Updated fese module to latest version to fix embedded subtitles provider. #2423

pull/2427/head v1.4.3-beta.8
morpheus65535 4 months ago
parent afa529c4b3
commit 1428edfb8b

@ -1,13 +0,0 @@
fese-0.2.7.dist-info/INSTALLER,sha256=zuuue4knoyJ-UwPPXg8fezS7VCrXJQrAP7zeNuwvFQg,4
fese-0.2.7.dist-info/LICENSE,sha256=OXLcl0T2SZ8Pmy2_dmlvKuetivmyPd5m1q-Gyd-zaYY,35149
fese-0.2.7.dist-info/METADATA,sha256=ZhkaLWdzqGU8X7sO3kLkpI5YsoeEoMtrbbqkxO4Tnvo,655
fese-0.2.7.dist-info/RECORD,,
fese-0.2.7.dist-info/REQUESTED,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
fese-0.2.7.dist-info/WHEEL,sha256=oiQVh_5PnQM0E3gPdiz09WCNmwiHDMaGer_elqB3coM,92
fese-0.2.7.dist-info/top_level.txt,sha256=ra2BuARVEUZpk76YpHnjVoqjR2FxvzhCdmW2OyBWGzE,5
fese/__init__.py,sha256=3glaq0hsVZWG-ADCl2tW5z3T0NQJYsyHBIG-uscr70M,150
fese/container.py,sha256=ztQxukjMOjEVQFqTQG9IVLYXkBhn8KhUZ_37E3W1PS4,8140
fese/disposition.py,sha256=mtYjMCm1uwudWbjVo-8CEMp5UkVb75jEoCXEfqqWBMk,2116
fese/exceptions.py,sha256=VZaubpq8SPpkUGp28Ryebsf9YzqbKK62nni6YZgDPYI,372
fese/stream.py,sha256=Hgf6-amksHpuhSoY6SL6C3q4YtGCuRHl4fusBWE9nBE,4866
fese/tags.py,sha256=qKkcjJmCKgnXIbZ9x-nngCNYAfv5cbJZ4A6EP0ckZME,5454

@ -1,6 +1,6 @@
Metadata-Version: 2.1 Metadata-Version: 2.1
Name: fese Name: fese
Version: 0.2.7 Version: 0.2.9
Summary: A library to extract FFmpeg subtitle streams Summary: A library to extract FFmpeg subtitle streams
Author-email: Vitiko Nogales <averroista@protonmail.com> Author-email: Vitiko Nogales <averroista@protonmail.com>
Requires-Python: >=3.7 Requires-Python: >=3.7

@ -0,0 +1,13 @@
fese-0.2.9.dist-info/INSTALLER,sha256=zuuue4knoyJ-UwPPXg8fezS7VCrXJQrAP7zeNuwvFQg,4
fese-0.2.9.dist-info/LICENSE,sha256=OXLcl0T2SZ8Pmy2_dmlvKuetivmyPd5m1q-Gyd-zaYY,35149
fese-0.2.9.dist-info/METADATA,sha256=nJz9q6FwX7fqmsO3jgM0ZgV0gsCeILWoxVRUqCbJkFI,655
fese-0.2.9.dist-info/RECORD,,
fese-0.2.9.dist-info/REQUESTED,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
fese-0.2.9.dist-info/WHEEL,sha256=oiQVh_5PnQM0E3gPdiz09WCNmwiHDMaGer_elqB3coM,92
fese-0.2.9.dist-info/top_level.txt,sha256=ra2BuARVEUZpk76YpHnjVoqjR2FxvzhCdmW2OyBWGzE,5
fese/__init__.py,sha256=_YUpx7sq26ioEp5LZOEKa-0MrRHQUuRuDCs0EQ6Amv4,150
fese/container.py,sha256=sLuxP0vlba4iGVohGfYtd-QcjQ-YxMU6lqMOM-Wtqlc,10340
fese/disposition.py,sha256=hv4YmXpsvKmUdpeWvSrZkhKgtZLZ8t56dmwMddsqxus,2156
fese/exceptions.py,sha256=VZaubpq8SPpkUGp28Ryebsf9YzqbKK62nni6YZgDPYI,372
fese/stream.py,sha256=Hgf6-amksHpuhSoY6SL6C3q4YtGCuRHl4fusBWE9nBE,4866
fese/tags.py,sha256=qKkcjJmCKgnXIbZ9x-nngCNYAfv5cbJZ4A6EP0ckZME,5454

@ -4,4 +4,4 @@
from .container import FFprobeVideoContainer from .container import FFprobeVideoContainer
from .stream import FFprobeSubtitleStream from .stream import FFprobeSubtitleStream
__version__ = "0.2.7" __version__ = "0.2.9"

@ -6,7 +6,9 @@ from __future__ import annotations
import json import json
import logging import logging
import os import os
import re
import subprocess import subprocess
import time
from .exceptions import ExtractionError from .exceptions import ExtractionError
from .exceptions import InvalidSource from .exceptions import InvalidSource
@ -23,6 +25,45 @@ FFMPEG_PATH = os.environ.get("FFMPEG_PATH", "ffmpeg")
FFMPEG_STATS = True FFMPEG_STATS = True
FF_LOG_LEVEL = "quiet" FF_LOG_LEVEL = "quiet"
_PROGRESS_RE = re.compile(
r"size=\s*(\d+\w*B|N/A)\s+time=(\d+:\d+:\d+\.\d+)\s+bitrate=\s*([\d\.]+(?:e[\+\-]?\d+)?\w*bits/s|N/A)\s+speed=([\d\.]+(?:e[\+\-]?\d+)?x|N/A)"
)
def _ffmpeg_call(command, log_callback=None, progress_callback=None, timeout=10000):
proc = subprocess.Popen(
command,
stdout=subprocess.PIPE,
stderr=subprocess.PIPE,
universal_newlines=True,
)
log_callback = log_callback or logger.debug
start = time.time()
while True:
line = proc.stderr.readline()
if not line:
break
if line:
log_callback("ffmpeg: %s", line.strip())
if progress_callback is not None:
match = _PROGRESS_RE.search(line)
if match:
size, time_, bitrate, speed = match.groups()
info = {"size": size, "time": time_, "bitrate": bitrate, "speed": speed}
progress_callback(info)
if timeout is not None and time.time() - start > timeout:
proc.kill()
raise subprocess.TimeoutExpired(command, timeout)
return_code = proc.wait()
if return_code != 0:
raise subprocess.CalledProcessError(return_code, command)
class FFprobeVideoContainer: class FFprobeVideoContainer:
def __init__(self, path: str): def __init__(self, path: str):
@ -81,6 +122,8 @@ class FFprobeVideoContainer:
overwrite=True, overwrite=True,
timeout=600, timeout=600,
convert_format=None, convert_format=None,
basename_callback=None,
progress_callback=None,
): ):
"""Extracts a list of subtitles converting them. Returns a dictionary of the """Extracts a list of subtitles converting them. Returns a dictionary of the
extracted filenames by index. extracted filenames by index.
@ -95,6 +138,9 @@ class FFprobeVideoContainer:
:param timeout: subprocess timeout in seconds (default: 600) :param timeout: subprocess timeout in seconds (default: 600)
:param convert_format: format to convert selected subtitles. Defaults to :param convert_format: format to convert selected subtitles. Defaults to
srt srt
:param basename_callback: a callback that takes the filename path. Only used if
custom_dir is set. Defaults to `os.path.basename`
:progress_callback: a callback that takes a dict
:raises: ExtractionError, UnsupportedCodec, OSError :raises: ExtractionError, UnsupportedCodec, OSError
""" """
extract_command = [FFMPEG_PATH, "-v", FF_LOG_LEVEL] extract_command = [FFMPEG_PATH, "-v", FF_LOG_LEVEL]
@ -116,7 +162,8 @@ class FFprobeVideoContainer:
f"{os.path.splitext(self.path)[0]}.{subtitle.suffix}.{extension_to_use}" f"{os.path.splitext(self.path)[0]}.{subtitle.suffix}.{extension_to_use}"
) )
if custom_dir is not None: if custom_dir is not None:
sub_path = os.path.join(custom_dir, os.path.basename(sub_path)) basename_callback = basename_callback or os.path.basename
sub_path = os.path.join(custom_dir, basename_callback(sub_path))
if not overwrite and sub_path in collected_paths: if not overwrite and sub_path in collected_paths:
sub_path = f"{os.path.splitext(sub_path)[0]}.{len(collected_paths):02}.{extension_to_use}" sub_path = f"{os.path.splitext(sub_path)[0]}.{len(collected_paths):02}.{extension_to_use}"
@ -139,7 +186,10 @@ class FFprobeVideoContainer:
logger.debug("Extracting subtitle with command %s", " ".join(extract_command)) logger.debug("Extracting subtitle with command %s", " ".join(extract_command))
try: try:
subprocess.run(extract_command, timeout=timeout, check=True) # subprocess.run(extract_command, timeout=timeout, check=True)
_ffmpeg_call(
extract_command, timeout=timeout, progress_callback=progress_callback
)
except (subprocess.SubprocessError, FileNotFoundError) as error: except (subprocess.SubprocessError, FileNotFoundError) as error:
raise ExtractionError(f"Error calling ffmpeg: {error}") from error raise ExtractionError(f"Error calling ffmpeg: {error}") from error
@ -156,6 +206,8 @@ class FFprobeVideoContainer:
overwrite=True, overwrite=True,
timeout=600, timeout=600,
fallback_to_convert=True, fallback_to_convert=True,
basename_callback=None,
progress_callback=None,
): ):
"""Extracts a list of subtitles with ffmpeg's copy method. Returns a dictionary """Extracts a list of subtitles with ffmpeg's copy method. Returns a dictionary
of the extracted filenames by index. of the extracted filenames by index.
@ -167,6 +219,9 @@ class FFprobeVideoContainer:
:param timeout: subprocess timeout in seconds (default: 600) :param timeout: subprocess timeout in seconds (default: 600)
:param fallback_to_convert: fallback to stream's default convert format if it is :param fallback_to_convert: fallback to stream's default convert format if it is
incompatible with copy incompatible with copy
:param basename_callback: a callback that takes the filename path. Only used if
custom_dir is set. Defaults to `os.path.basename`
:progress_callback: a callback that takes a dict
:raises: ExtractionError, UnsupportedCodec, OSError :raises: ExtractionError, UnsupportedCodec, OSError
""" """
extract_command = [FFMPEG_PATH, "-v", FF_LOG_LEVEL] extract_command = [FFMPEG_PATH, "-v", FF_LOG_LEVEL]
@ -184,7 +239,8 @@ class FFprobeVideoContainer:
for subtitle in subtitles: for subtitle in subtitles:
sub_path = f"{os.path.splitext(self.path)[0]}.{subtitle.suffix}.{subtitle.extension}" sub_path = f"{os.path.splitext(self.path)[0]}.{subtitle.suffix}.{subtitle.extension}"
if custom_dir is not None: if custom_dir is not None:
sub_path = os.path.join(custom_dir, os.path.basename(sub_path)) basename_callback = basename_callback or os.path.basename
sub_path = os.path.join(custom_dir, basename_callback(sub_path))
if not overwrite and sub_path in collected_paths: if not overwrite and sub_path in collected_paths:
sub_path = f"{os.path.splitext(sub_path)[0]}.{len(collected_paths):02}.{subtitle.extension}" sub_path = f"{os.path.splitext(sub_path)[0]}.{len(collected_paths):02}.{subtitle.extension}"
@ -216,7 +272,10 @@ class FFprobeVideoContainer:
logger.debug("Extracting subtitle with command %s", " ".join(extract_command)) logger.debug("Extracting subtitle with command %s", " ".join(extract_command))
try: try:
subprocess.run(extract_command, timeout=timeout, check=True) # subprocess.run(extract_command, timeout=timeout, check=True)
_ffmpeg_call(
extract_command, timeout=timeout, progress_callback=progress_callback
)
except (subprocess.SubprocessError, FileNotFoundError) as error: except (subprocess.SubprocessError, FileNotFoundError) as error:
raise ExtractionError(f"Error calling ffmpeg: {error}") from error raise ExtractionError(f"Error calling ffmpeg: {error}") from error

@ -57,8 +57,8 @@ class FFprobeSubtitleDisposition:
def language_kwargs(self): def language_kwargs(self):
return { return {
"hi": self._content_type == "hearing_impaired", "hi": self._content_type == "hearing_impaired" or self.hearing_impaired,
"forced": self._content_type == "forced", "forced": self._content_type == "forced" or self.forced,
} }
def __str__(self): def __str__(self):

@ -10,7 +10,7 @@ charset-normalizer==3.3.2
deep-translator==1.11.4 deep-translator==1.11.4
dogpile.cache==1.3.2 dogpile.cache==1.3.2
dynaconf==3.2.4 dynaconf==3.2.4
fese==0.2.7 fese==0.2.9
ffsubsync==0.4.25 ffsubsync==0.4.25
flask-cors==4.0.0 flask-cors==4.0.0
flask-migrate==4.0.5 flask-migrate==4.0.5

Loading…
Cancel
Save