ffmpeg + ffprobe paths

This commit is contained in:
Jesse Bannon 2023-02-28 14:44:31 -08:00
parent c2fab59b3e
commit 8a3d92b04b
7 changed files with 73 additions and 12 deletions

1
.gitignore vendored
View file

@ -145,3 +145,4 @@ docker/root/defaults/examples
.local/
ffmpeg.exe
ffprobe.exe

View file

@ -1,3 +1,4 @@
import tempfile
from typing import Any
from typing import Dict
from typing import Optional
@ -5,14 +6,24 @@ from typing import Optional
from mergedeep import mergedeep
from ytdl_sub.prebuilt_presets import PREBUILT_PRESETS
from ytdl_sub.utils.system import IS_WINDOWS
from ytdl_sub.validators.strict_dict_validator import StrictDictValidator
from ytdl_sub.validators.validators import LiteralDictValidator
from ytdl_sub.validators.validators import StringValidator
if IS_WINDOWS:
_DEFAULT_LOCK_DIRECTORY = tempfile.TemporaryDirectory().name
_DEFAULT_FFMPEG_PATH = ".\\ffmpeg.exe"
_DEFAULT_FFPROBE_PATH = ".\\ffprobe.exe"
else:
_DEFAULT_LOCK_DIRECTORY = "/tmp"
_DEFAULT_FFMPEG_PATH = "/usr/bin/ffmpeg"
_DEFAULT_FFPROBE_PATH = "/usr/bin/ffprobe"
class ConfigOptions(StrictDictValidator):
_required_keys = {"working_directory"}
_optional_keys = {"umask", "dl_aliases", "lock_directory"}
_optional_keys = {"umask", "dl_aliases", "lock_directory", "ffmpeg_path", "ffprobe_path"}
def __init__(self, name: str, value: Any):
super().__init__(name, value)
@ -27,7 +38,14 @@ class ConfigOptions(StrictDictValidator):
key="dl_aliases", validator=LiteralDictValidator
)
self._lock_directory = self._validate_key(
key="lock_directory", validator=StringValidator, default="/tmp"
key="lock_directory", validator=StringValidator, default=_DEFAULT_LOCK_DIRECTORY
)
# TODO: Validate these exist
self._ffmpeg_path = self._validate_key(
key="ffmpeg_path", validator=StringValidator, default=_DEFAULT_FFMPEG_PATH
)
self._ffprobe_path = self._validate_key(
key="ffprobe_path", validator=StringValidator, default=_DEFAULT_FFPROBE_PATH
)
@property
@ -82,6 +100,20 @@ class ConfigOptions(StrictDictValidator):
"""
return self._lock_directory.value
@property
def ffmpeg_path(self) -> str:
"""
TODO: Fill out!
"""
return self._ffmpeg_path.value
@property
def ffprobe_path(self) -> str:
"""
TODO: Fill out!
"""
return self._ffprobe_path.value
class ConfigValidator(StrictDictValidator):
_required_keys = {"configuration", "presets"}

View file

@ -168,7 +168,10 @@ class SplitByChaptersPlugin(Plugin[SplitByChaptersOptions]):
if self.is_dry_run:
chapters = Chapters.from_entry_chapters(entry=entry)
else:
chapters = Chapters.from_embedded_chapters(file_path=entry.get_download_file_path())
chapters = Chapters.from_embedded_chapters(
ffprobe_path=FFMPEG.ffprobe_path(),
file_path=entry.get_download_file_path(),
)
# If no chapters, do not split anything
if not chapters.contains_any_chapters():

View file

@ -11,6 +11,7 @@ from ytdl_sub.subscriptions.base_subscription import BaseSubscription
from ytdl_sub.subscriptions.subscription_ytdl_options import SubscriptionYTDLOptions
from ytdl_sub.utils.datetime import to_date_range
from ytdl_sub.utils.exceptions import ValidationException
from ytdl_sub.utils.ffmpeg import FFMPEG
from ytdl_sub.utils.file_handler import FileHandler
from ytdl_sub.utils.file_handler import FileHandlerTransactionLog
from ytdl_sub.utils.file_handler import FileMetadata
@ -265,6 +266,12 @@ class SubscriptionDownload(BaseSubscription, ABC):
If true, do not download any video/audio files or move anything to the output
directory.
"""
# Set ffmpeg paths
FFMPEG.set_paths(
ffmpeg_path=self._config_options.ffmpeg_path,
ffprobe_path=self._config_options.ffprobe_path,
)
self._enhanced_download_archive.reinitialize(dry_run=dry_run)
plugins = self._initialize_plugins()

View file

@ -15,6 +15,7 @@ from ytdl_sub.plugins.file_convert import FileConvertPlugin
from ytdl_sub.plugins.match_filters import MatchFiltersPlugin
from ytdl_sub.plugins.plugin import Plugin
from ytdl_sub.plugins.subtitles import SubtitlesPlugin
from ytdl_sub.utils.ffmpeg import FFMPEG
from ytdl_sub.ytdl_additions.enhanced_download_archive import EnhancedDownloadArchive
PluginT = TypeVar("PluginT", bound=Plugin)
@ -57,6 +58,7 @@ class SubscriptionYTDLOptions:
"outtmpl": str(Path(self._working_directory) / "%(id)s.%(ext)s"),
# Always write thumbnails
"writethumbnail": True,
"ffmpeg_location": FFMPEG.ffmpeg_path(),
}
return ytdl_options

View file

@ -221,10 +221,12 @@ class Chapters:
return Chapters(timestamps=timestamps, titles=titles)
@classmethod
def from_embedded_chapters(cls, file_path: str) -> "Chapters":
def from_embedded_chapters(cls, ffprobe_path: str, file_path: str) -> "Chapters":
"""
Parameters
----------
ffprobe_path
Path to ffprobe executable
file_path
File to read ffmpeg chapter metadata from
@ -234,7 +236,7 @@ class Chapters:
"""
proc = subprocess.run(
[
"ffprobe",
ffprobe_path,
"-loglevel",
"quiet",
"-print_format",

View file

@ -10,7 +10,6 @@ from ytdl_sub.utils.chapters import Chapters
from ytdl_sub.utils.exceptions import ValidationException
from ytdl_sub.utils.file_handler import FileHandler
from ytdl_sub.utils.logger import Logger
from ytdl_sub.utils.system import IS_WINDOWS
logger = Logger.get(name="ffmpeg")
@ -26,13 +25,28 @@ def _ffmpeg_metadata_escape(str_to_escape: str) -> str:
class FFMPEG:
_FFMPEG_PATH: str = ""
_FFPROBE_PATH: str = ""
@classmethod
def set_paths(cls, ffmpeg_path: str, ffprobe_path: str) -> None:
cls._FFMPEG_PATH = ffmpeg_path
cls._FFPROBE_PATH = ffprobe_path
@classmethod
def ffmpeg_path(cls) -> str:
assert cls._FFMPEG_PATH, "ffmpeg has not been set"
return cls._FFMPEG_PATH
@classmethod
def ffprobe_path(cls) -> str:
assert cls._FFPROBE_PATH, "ffprobe has not been set"
return cls._FFPROBE_PATH
@classmethod
def _ensure_installed(cls):
try:
if IS_WINDOWS:
subprocess.check_output([".\\ffmpeg", "-version"])
else:
subprocess.check_output(["which", "ffmpeg"])
subprocess.check_output([cls.ffmpeg_path(), "-version"])
except subprocess.CalledProcessError as subprocess_error:
raise ValidationException(
"Trying to use a feature which requires ffmpeg, but it cannot be found"
@ -69,7 +83,7 @@ class FFMPEG:
"""
cls._ensure_installed()
cmd = [".\\ffmpeg.exe" if IS_WINDOWS else "ffmpeg"]
cmd = [cls.ffmpeg_path()]
cmd.extend(ffmpeg_args)
logger.debug("Running %s", " ".join(cmd))
with Logger.handle_external_logs(name="ffmpeg"):