Exemplo n.º 1
0
def _execute_ffmpeg(
    content: bytes,
    cli: List[str],
    program: str = "ffmpeg",
    ignore_error_if_data: bool = False,
    get_logs: bool = False,
) -> bytes:
    mime_type = mime.get_mime_type(content)
    if mime.is_heif(mime_type):
        # FFmpeg does not support HEIF.
        # https://trac.ffmpeg.org/ticket/6521
        content = convert_heif_to_png(content)

    cli = [program, "-loglevel", "32" if get_logs else "24"] + cli

    proc = Popen(cli, stdout=PIPE, stdin=PIPE, stderr=PIPE)
    out, err = proc.communicate(input=content)

    if proc.returncode != 0:
        args = " ".join(shlex.quote(arg) for arg in cli)
        logger.warning(
            f"Failed to execute {program} command (cli={args}, err={err})")
        if (len(out) > 0 and not ignore_error_if_data) or len(out) == 0:
            raise errors.ProcessingError("Error while processing media.\n" +
                                         err.decode("utf-8"))
    return err if get_logs else out
Exemplo n.º 2
0
    def to_thumbnail(self, width: int, height: int) -> bytes:
        width_greater = self.width > self.height
        width, height = (-1, height) if width_greater else (width, -1)

        cli = []

        if float(self.duration) > 3.0:
            cli += ["-ss", math.floor(self.duration * 0.3)]

        cli += [
            "-i",
            "-",
            "-f",
            "image2",
            "-vf",
            f"scale={width}:{height}",
            "-vframes",
            "1",
            "-vcodec",
            "mjpeg",
            "-",
        ]

        content = _execute_ffmpeg(self.content, cli, ignore_error_if_data=True)

        if not content:
            raise errors.ProcessingError(
                "Error while creating thumbnail from video.")

        return content
Exemplo n.º 3
0
    def resize_fill(self, width: int, height: int) -> None:
        width_greater = self.width > self.height
        width, height = (-1, height) if width_greater else (width, -1)

        cli = [
            "-i",
            "{path}",
            "-f",
            "image2",
            "-filter:v",
            "scale='{width}:{height}'".format(width=width, height=height),
            "-map",
            "0:v:0",
            "-vframes",
            "1",
            "-vcodec",
            "png",
            "-",
        ]
        if ("duration" in self.info["format"]
                and self.info["format"]["format_name"] != "swf"):
            duration = float(self.info["format"]["duration"])
            if duration > 3:
                cli = [
                    "-ss",
                    "%d" % math.floor(duration * 0.3),
                ] + cli
        content = self._execute(cli, ignore_error_if_data=True)
        if not content:
            raise errors.ProcessingError("Error while resizing image.")
        self.content = content
        self._reload_info()
Exemplo n.º 4
0
 def resize_fill(self, width: int, height: int) -> None:
     cli = [
         '-i',
         '{path}',
         '-f',
         'image2',
         '-vf',
         _SCALE_FIT_FMT.format(width=width, height=height),
         '-map',
         '0:v:0',
         '-vframes',
         '1',
         '-vcodec',
         'png',
         '-',
     ]
     if 'duration' in self.info['format'] \
             and self.info['format']['format_name'] != 'swf':
         duration = float(self.info['format']['duration'])
         if duration > 3:
             cli = [
                 '-ss',
                 '%d' % math.floor(duration * 0.3),
             ] + cli
     content = self._execute(cli)
     if not content:
         raise errors.ProcessingError('Error while resizing image.')
     self.content = content
     self._reload_info()
Exemplo n.º 5
0
def _preprocess_image(content: bytes) -> NpMatrix:
    try:
        img = Image.open(BytesIO(content))
        return np.asarray(img.convert("L"), dtype=np.uint8)
    except IOError:
        raise errors.ProcessingError("Unable to generate a signature hash "
                                     "for this image.")
Exemplo n.º 6
0
 def _execute(
         self,
         cli: List[str],
         program: str = 'ffmpeg',
         ignore_error_if_data: bool = False) -> bytes:
     extension = mime.get_extension(mime.get_mime_type(self.content))
     assert extension
     with util.create_temp_file(suffix='.' + extension) as handle:
         handle.write(self.content)
         handle.flush()
         cli = [program, '-loglevel', '24'] + cli
         cli = [part.format(path=handle.name) for part in cli]
         proc = subprocess.Popen(
             cli,
             stdout=subprocess.PIPE,
             stdin=subprocess.PIPE,
             stderr=subprocess.PIPE)
         out, err = proc.communicate(input=self.content)
         if proc.returncode != 0:
             logger.warning(
                 'ffmpeg 명령어 실행 실패 (cli=%r, err=%r)',
                 ' '.join(shlex.quote(arg) for arg in cli),
                 err)
             if ((len(out) > 0 and not ignore_error_if_data)
                     or len(out) == 0):
                 raise errors.ProcessingError(
                     '이미지 처리 중 오류.\n'
                     + err.decode('utf-8'))
         return out
Exemplo n.º 7
0
 def _execute(
     self,
     cli: List[str],
     program: str = "ffmpeg",
     ignore_error_if_data: bool = False,
     get_logs: bool = False,
 ) -> bytes:
     extension = mime.get_extension(mime.get_mime_type(self.content))
     assert extension
     with util.create_temp_file(suffix="." + extension) as handle:
         handle.write(self.content)
         handle.flush()
         cli = [program, "-loglevel", "32" if get_logs else "24"] + cli
         cli = [part.format(path=handle.name) for part in cli]
         proc = subprocess.Popen(
             cli,
             stdout=subprocess.PIPE,
             stdin=subprocess.PIPE,
             stderr=subprocess.PIPE,
         )
         out, err = proc.communicate(input=self.content)
         if proc.returncode != 0:
             logger.warning(
                 "Failed to execute ffmpeg command (cli=%r, err=%r)",
                 " ".join(shlex.quote(arg) for arg in cli),
                 err,
             )
             if (len(out) > 0
                     and not ignore_error_if_data) or len(out) == 0:
                 raise errors.ProcessingError(
                     "Error while processing image.\n" +
                     err.decode("utf-8"))
         return err if get_logs else out
Exemplo n.º 8
0
    def resize_fill(self, width: int, height: int) -> None:
        width_greater = self.width > self.height
        width, height = (-1, height) if width_greater else (width, -1)

        cli = [
            '-i', '{path}',
            '-f', 'image2',
            '-filter:v', "scale='{width}:{height}'".format(
                width=width, height=height),
            '-map', '0:v:0',
            '-vframes', '1',
            '-vcodec', 'png',
            '-',
        ]
        if 'duration' in self.info['format'] \
                and self.info['format']['format_name'] != 'swf':
            duration = float(self.info['format']['duration'])
            if duration > 3:
                cli = [
                    '-ss',
                    '%d' % math.floor(duration * 0.3),
                ] + cli
        content = self._execute(cli, ignore_error_if_data=True)
        if not content:
            raise errors.ProcessingError('이미지 리사이징 오류.')
        self.content = content
        self._reload_info()
Exemplo n.º 9
0
def download(url: str) -> bytes:
    assert url
    request = urllib.request.Request(url)
    request.add_header('Referer', url)
    try:
        with urllib.request.urlopen(request) as handle:
            return handle.read()
    except Exception as ex:
        raise errors.ProcessingError('Error downloading %s (%s)' % (url, ex))
Exemplo n.º 10
0
    def _reload_info(self) -> None:
        try:
            self._extract_from_exif()
        except Exception:
            self._extract_using_ffmpeg()

        assert self.width > 0
        assert self.height > 0
        if (not self.width) or (not self.height):
            logger.warning("Error processing this image.")
            raise errors.ProcessingError("Error processing this image.")
Exemplo n.º 11
0
def download(url: str) -> bytes:
    assert url
    request = urllib.request.Request(url)
    if config.config['user_agent']:
        request.add_header('User-Agent', config.config['user_agent'])
    request.add_header('Referer', url)
    try:
        with urllib.request.urlopen(request) as handle:
            return handle.read()
    except Exception as ex:
        raise errors.ProcessingError('%s 다운로드 중 오류 (%s)' % (url, ex))
Exemplo n.º 12
0
 def wrapper_inner(*args: Any, **kwargs: Any) -> Any:
     try:
         return target_function(*args, **kwargs)
     except elasticsearch.exceptions.NotFoundError:
         # index not yet created, will be created dynamically by
         # add_image()
         return default_param_factory()
     except elasticsearch.exceptions.ElasticsearchException as ex:
         logger.warning('Problem with elastic search: %s', ex)
         raise errors.ThirdPartyError('Elastic search 연결 오류.')
     except IOError:
         raise errors.ProcessingError('이미지가 아닙니다.')
     except Exception as ex:
         raise errors.ThirdPartyError('알 수 없는 에러 (%s).' % ex)
Exemplo n.º 13
0
 def _reload_info(self) -> None:
     self.info = json.loads(self._execute([
         '-i', '{path}',
         '-of', 'json',
         '-select_streams', 'v',
         '-show_format',
         '-show_streams',
     ], program='ffprobe').decode('utf-8'))
     assert 'format' in self.info
     assert 'streams' in self.info
     if len(self.info['streams']) < 1:
         logger.warning('The video contains no video streams.')
         raise errors.ProcessingError(
             '동영상에 동영상 스트림이 없습니다.')
Exemplo n.º 14
0
    def check_for_sound(self) -> bool:
        audioinfo = json.loads(
            _execute_ffmpeg(
                self.content,
                [
                    "-i",
                    "-",
                    "-of",
                    "json",
                    "-select_streams",
                    "a",
                    "-show_streams",
                ],
                program="ffprobe",
            ).decode("utf-8"))

        assert "streams" in audioinfo
        if len(audioinfo["streams"]) < 1:
            return False

        log = _execute_ffmpeg(
            self.content,
            [
                "-hide_banner",
                "-progress",
                "-",
                "-i",
                "-",
                "-af",
                "volumedetect",
                "-max_muxing_queue_size",
                "99999",
                "-vn",
                "-sn",
                "-f",
                "null",
                "-y",
                "/dev/null",
            ],
            get_logs=True,
        ).decode("utf-8", errors="replace")
        log_match = re.search(r".*volumedetect.*mean_volume: (.*) dB", log)
        if not log_match or not log_match.groups():
            raise errors.ProcessingError(
                "A problem occured when trying to check for audio")
        meanvol = float(log_match.groups()[0])

        # -91.0 dB is the minimum for 16-bit audio, assume sound if > -80.0 dB
        return meanvol > -80.0
Exemplo n.º 15
0
 def _execute(self, cli, program='ffmpeg'):
     with util.create_temp_file() as handle:
         handle.write(self.content)
         handle.flush()
         cli = [program, '-loglevel', '24'] + cli
         cli = [part.format(path=handle.name) for part in cli]
         proc = subprocess.Popen(cli,
                                 stdout=subprocess.PIPE,
                                 stdin=subprocess.PIPE,
                                 stderr=subprocess.PIPE)
         out, err = proc.communicate(input=self.content)
         if proc.returncode != 0:
             raise errors.ProcessingError(
                 'Error while processing image.\n' + err.decode('utf-8'))
         return out
Exemplo n.º 16
0
def download(url: str, use_video_downloader: bool = False) -> bytes:
    assert url
    request = urllib.request.Request(url)
    if config.config['user_agent']:
        request.add_header('User-Agent', config.config['user_agent'])
    request.add_header('Referer', url)
    try:
        with urllib.request.urlopen(request) as handle:
            content = handle.read()
    except Exception as ex:
        raise errors.ProcessingError('Error downloading %s (%s)' % (url, ex))
    if (use_video_downloader
            and mime.get_mime_type(content) == 'application/octet-stream'):
        return _youtube_dl_wrapper(url)
    return content
Exemplo n.º 17
0
    def to_thumbnail(self, width: int, height: int) -> bytes:
        width_greater = self.width > self.height
        width, height = (-1, height) if width_greater else (width, -1)

        cli = ["-i", "-"]
        self._add_orientation_filters(cli, f"scale='{width}:{height}'")
        cli += ["-f", "image2", "-vframes", "1", "-vcodec", "png", "-"]

        content = _execute_ffmpeg(self.content, cli, ignore_error_if_data=True)

        if not content:
            raise errors.ProcessingError(
                "Error while creating thumbnail from image.")

        return content
Exemplo n.º 18
0
    def _reload_info(self):
        cmd = [
            "-i",
            "-",
            "-print_format",
            "json",
            "-show_streams",
            "-show_format",
        ]

        info = json.loads(
            _execute_ffmpeg(
                self.content,
                cmd,
                program="ffprobe",
            ).decode("utf-8"))

        assert "streams" in info
        if len(info["streams"]) < 1:
            logger.warning("This video contains no video streams.")
            raise errors.ProcessingError(
                "The video contains no video streams.")

        self.width = info["streams"][0]["width"]
        self.height = info["streams"][0]["height"]

        assert "format" in info
        assert "tags" in info["format"]

        if "creation_time" in info["format"]["tags"]:
            self.date_taken = info["format"]["tags"]["creation_time"]

        # List of tuples where only one value can be valid
        option_tuples = (
            ("manufacturer", "com.android.manufacturer"),
            ("model", "com.android.model"),
        )

        camera_string = []

        for option_tuple in option_tuples:
            for option in option_tuple:
                if option in info["format"]["tags"]:
                    camera_string.append(info["format"]["tags"][option])
                    break

        if camera_string:
            self.camera = " ".join(camera_string)
Exemplo n.º 19
0
 def _reload_info(self):
     self.info = json.loads(
         self._execute([
             '-of',
             'json',
             '-select_streams',
             'v',
             '-show_streams',
             '-count_frames',
             '-i',
             '-',
         ],
                       program='ffprobe').decode('utf-8'))
     assert 'streams' in self.info
     if len(self.info['streams']) != 1:
         raise errors.ProcessingError('Multiple video streams detected.')
Exemplo n.º 20
0
    def check_for_sound(self) -> bool:
        audioinfo = json.loads(
            self._execute([
                '-i',
                '{path}',
                '-of',
                'json',
                '-select_streams',
                'a',
                '-show_streams',
            ],
                          program='ffprobe').decode('utf-8'))
        assert 'streams' in audioinfo
        if len(audioinfo['streams']) < 1:
            return False

        log = self._execute([
            '-hide_banner',
            '-progress',
            '-',
            '-i',
            '{path}',
            '-af',
            'volumedetect',
            '-max_muxing_queue_size',
            '99999',
            '-vn',
            '-sn',
            '-f',
            'null',
            '-y',
            '/dev/null',
        ],
                            get_logs=True).decode('utf-8', errors='replace')
        log_match = re.search(r'.*volumedetect.*mean_volume: (.*) dB', log)
        if not log_match or not log_match.groups():
            raise errors.ProcessingError(
                'A problem occured when trying to check for audio')
        meanvol = float(log_match.groups()[0])

        # -91.0 dB is the minimum for 16-bit audio, assume sound if > -80.0 dB
        return meanvol > -80.0
Exemplo n.º 21
0
 def _execute(self, cli: List[str], program: str = 'ffmpeg') -> bytes:
     extension = mime.get_extension(mime.get_mime_type(self.content))
     assert extension
     with util.create_temp_file(suffix='.' + extension) as handle:
         handle.write(self.content)
         handle.flush()
         cli = [program, '-loglevel', '24'] + cli
         cli = [part.format(path=handle.name) for part in cli]
         proc = subprocess.Popen(cli,
                                 stdout=subprocess.PIPE,
                                 stdin=subprocess.PIPE,
                                 stderr=subprocess.PIPE)
         out, err = proc.communicate(input=self.content)
         if proc.returncode != 0:
             logger.warning(
                 'Failed to execute ffmpeg command (cli=%r, err=%r)',
                 ' '.join(shlex.quote(arg) for arg in cli), err)
             raise errors.ProcessingError(
                 'Error while processing image.\n' + err.decode('utf-8'))
         return out
Exemplo n.º 22
0
 def _reload_info(self) -> None:
     self.info = json.loads(
         self._execute(
             [
                 "-i",
                 "{path}",
                 "-of",
                 "json",
                 "-select_streams",
                 "v",
                 "-show_format",
                 "-show_streams",
             ],
             program="ffprobe",
         ).decode("utf-8"))
     assert "format" in self.info
     assert "streams" in self.info
     if len(self.info["streams"]) < 1:
         logger.warning("The video contains no video streams.")
         raise errors.ProcessingError(
             "The video contains no video streams.")