ffmpeg + ffprobe paths
This commit is contained in:
parent
c2fab59b3e
commit
8a3d92b04b
7 changed files with 73 additions and 12 deletions
3
.gitignore
vendored
3
.gitignore
vendored
|
|
@ -144,4 +144,5 @@ docker/root/defaults/examples
|
|||
|
||||
.local/
|
||||
|
||||
ffmpeg.exe
|
||||
ffmpeg.exe
|
||||
ffprobe.exe
|
||||
|
|
@ -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"}
|
||||
|
|
|
|||
|
|
@ -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():
|
||||
|
|
|
|||
|
|
@ -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()
|
||||
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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",
|
||||
|
|
|
|||
|
|
@ -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"):
|
||||
|
|
|
|||
Loading…
Reference in a new issue