From c84496910f88394b6706ec63f05b6448b697a704 Mon Sep 17 00:00:00 2001 From: Jesse Bannon Date: Tue, 10 Jan 2023 14:19:45 -0800 Subject: [PATCH] [BUGFIX] Cross-device patch for ffmpeg file writes (#407) --- src/ytdl_sub/utils/ffmpeg.py | 33 +++++++++++++++++++++++++-------- src/ytdl_sub/utils/thumbnail.py | 10 +++++++++- 2 files changed, 34 insertions(+), 9 deletions(-) diff --git a/src/ytdl_sub/utils/ffmpeg.py b/src/ytdl_sub/utils/ffmpeg.py index f8ccdbfa..2d63de8e 100644 --- a/src/ytdl_sub/utils/ffmpeg.py +++ b/src/ytdl_sub/utils/ffmpeg.py @@ -32,6 +32,25 @@ class FFMPEG: "Trying to use a feature which requires ffmpeg, but it cannot be found" ) from subprocess_error + @classmethod + def tmp_file_path(cls, relative_file_path: str, extension: Optional[str] = None) -> str: + """ + Parameters + ---------- + relative_file_path + Path of input file that is going to be modified + extension + Desired output extension. Defaults to input file's extension + + Returns + ------- + Temporary file path for ffmpeg output + """ + if extension is None: + extension = relative_file_path.split(".")[-1] + + return f"{relative_file_path}.out.{extension}" + @classmethod def run(cls, ffmpeg_args: List[str]) -> None: """ @@ -110,8 +129,7 @@ def set_ffmpeg_metadata_chapters( if chapters: lines += _create_metadata_chapters(chapters=chapters, file_duration_sec=file_duration_sec) - file_path_ext = file_path.split(".")[-1] - output_file_path = f"{file_path}.out.{file_path_ext}" + tmp_file_path = FFMPEG.tmp_file_path(relative_file_path=file_path) with tempfile.NamedTemporaryFile(mode="w", suffix=".txt", encoding="utf-8") as metadata_file: metadata_file.write("\n".join(lines)) metadata_file.flush() @@ -129,10 +147,10 @@ def set_ffmpeg_metadata_chapters( "-bitexact", # for reproducibility "-codec", "copy", - output_file_path, + tmp_file_path, ] ) - FileHandler.move(output_file_path, file_path) + FileHandler.move(tmp_file_path, file_path) def add_ffmpeg_metadata_key_values(file_path: str, key_values: Dict[str, str]) -> None: @@ -144,13 +162,12 @@ def add_ffmpeg_metadata_key_values(file_path: str, key_values: Dict[str, str]) - key_values The key/values to add """ - file_path_ext = file_path.split(".")[-1] - output_file_path = f"{file_path}.out.{file_path_ext}" + tmp_file_path = FFMPEG.tmp_file_path(file_path) ffmpeg_args = ["-i", file_path, "-map", "0"] for key, value in key_values.items(): ffmpeg_args.extend(["-metadata", f"{key}={value}"]) - ffmpeg_args.extend(["-codec", "copy", output_file_path]) + ffmpeg_args.extend(["-codec", "copy", tmp_file_path]) FFMPEG.run(ffmpeg_args) - FileHandler.move(output_file_path, file_path) + FileHandler.move(tmp_file_path, file_path) diff --git a/src/ytdl_sub/utils/thumbnail.py b/src/ytdl_sub/utils/thumbnail.py index 549853d5..9ba26244 100644 --- a/src/ytdl_sub/utils/thumbnail.py +++ b/src/ytdl_sub/utils/thumbnail.py @@ -68,6 +68,14 @@ def convert_url_thumbnail(thumbnail_url: str, output_thumbnail_path: str) -> Opt thumbnail.write(file.read()) os.makedirs(os.path.dirname(output_thumbnail_path), exist_ok=True) - FFMPEG.run(["-bitexact", "-i", thumbnail.name, output_thumbnail_path]) + + tmp_output_path = FFMPEG.tmp_file_path( + relative_file_path=thumbnail.name, extension="jpg" + ) + FFMPEG.run(["-bitexact", "-i", thumbnail.name, tmp_output_path]) + + # Have FileHandler handle the move to a potential cross-device + FileHandler.move(tmp_output_path, output_thumbnail_path) + FileHandler.delete(tmp_output_path) return True