refactor: add mkvpropedit as alternative for in-place modification
This commit is contained in:
parent
7a49849ee9
commit
4b6576ec53
@ -1,4 +1,4 @@
|
||||
FROM debian:bullseye-slim AS builder
|
||||
FROM debian:bookworm-slim AS builder
|
||||
|
||||
# Install ffmpeg and mkvtoolnix
|
||||
# but only keep the binaries and libs for ffprobe and mkvmerge
|
||||
@ -7,11 +7,13 @@ RUN apt-get update && apt-get install -y --no-install-recommends \
|
||||
&& mkdir -p /artifacts/bin /artifacts/lib \
|
||||
&& cp $(which ffprobe) /artifacts/bin/ \
|
||||
&& cp $(which mkvmerge) /artifacts/bin/ \
|
||||
&& cp $(which mkvpropedit) /artifacts/bin/ \
|
||||
&& ldd $(which ffprobe) | awk '{print $3}' | xargs -I '{}' cp -v '{}' /artifacts/lib/ || true \
|
||||
&& ldd $(which mkvmerge) | awk '{print $3}' | xargs -I '{}' cp -v '{}' /artifacts/lib/ || true
|
||||
&& ldd $(which mkvmerge) | awk '{print $3}' | xargs -I '{}' cp -v '{}' /artifacts/lib/ || true \
|
||||
&& ldd $(which mkvpropedit) | awk '{print $3}' | xargs -I '{}' cp -v '{}' /artifacts/lib/ || true
|
||||
|
||||
# Must be the same base as builder image for shared libraries compatibility
|
||||
FROM python:3.13.3-slim-bullseye
|
||||
FROM python:3.13.3-slim-bookworm
|
||||
|
||||
COPY --from=builder /artifacts/bin/* /usr/local/bin/
|
||||
COPY --from=builder /artifacts/lib/* /usr/local/lib/
|
||||
|
@ -81,6 +81,12 @@ class MetadataExtractor:
|
||||
}
|
||||
metadata["subtitle_tracks"].append(track)
|
||||
|
||||
elif codec_type == "video":
|
||||
pass
|
||||
|
||||
elif codec_type == "button":
|
||||
pass
|
||||
|
||||
else:
|
||||
self.logger.warning(f"Unknown track codec type '{codec_type}'")
|
||||
|
||||
|
@ -11,26 +11,7 @@ class MetadataWriter:
|
||||
def __init__(self):
|
||||
self.logger: logging.Logger = logging.getLogger("MetadataWriter")
|
||||
|
||||
def apply_metadata(self, metadata: dict, in_path: str, out_path: Optional[str] = None) -> bool:
|
||||
"""
|
||||
Writes metadata to a video file using mkvmerge
|
||||
|
||||
:param metadata: Metadata information
|
||||
:param in_path: Path of the input video file
|
||||
:param out_path: Path of the output video file. If None, ``"_modified"`` is appended to ``in_path`` instead
|
||||
:return: True if successful, False otherwise
|
||||
"""
|
||||
|
||||
if not os.path.isfile(in_path):
|
||||
self.logger.error(f"Input file not found: {in_path}")
|
||||
return False
|
||||
|
||||
if out_path is None:
|
||||
# Create a temporary output file
|
||||
base_name, ext = os.path.splitext(in_path)
|
||||
out_path: str = f"{base_name}_modified{ext}"
|
||||
|
||||
# Start building the mkvmerge command
|
||||
def get_mkvmerge_cmd(self, metadata: dict, in_path: str, out_path: str) -> list[str]:
|
||||
cmd: list[str] = [
|
||||
"mkvmerge",
|
||||
"-o", out_path
|
||||
@ -66,8 +47,76 @@ class MetadataWriter:
|
||||
|
||||
# Add input file
|
||||
cmd.append(in_path)
|
||||
return cmd
|
||||
|
||||
# Execute the mkvmerge command
|
||||
def get_mkvpropedit_cmd(self, metadata: dict, path: str) -> list[str]:
|
||||
cmd: list[str] = [
|
||||
"mkvpropedit",
|
||||
path
|
||||
]
|
||||
|
||||
# Add global metadata (title)
|
||||
if "title" in metadata:
|
||||
cmd.extend(["--edit", "info", "--set", f"title={metadata["title"]}"])
|
||||
|
||||
# Process audio + subtitle tracks
|
||||
tracks: list[dict] = metadata.get("audio_tracks", []) + metadata.get("subtitle_tracks", [])
|
||||
for track in tracks:
|
||||
# Use the actual track index from the metadata
|
||||
track_id = track.get("index", 0)
|
||||
|
||||
cmd.extend(["--edit", f"track:{track_id}"])
|
||||
|
||||
# Set language
|
||||
if "language" in track:
|
||||
cmd.extend(["--set", f"language={track["language"]}"])
|
||||
|
||||
# Set title/name
|
||||
if "name" in track and track["name"]:
|
||||
cmd.extend(["--set", f"name={track["name"]}"])
|
||||
|
||||
# Set disposition flags
|
||||
flags = track.get("flags", {})
|
||||
|
||||
def yes_no(flag: str):
|
||||
return f"{track_id}:{"yes" if flags.get(flag, False) else "no"}"
|
||||
|
||||
cmd.extend(["--set", f"flag-default={int(flags.get("default", False))}"])
|
||||
cmd.extend(["--set", f"flag-forced={int(flags.get("forced", False))}"])
|
||||
cmd.extend(["--set", f"flag-original={int(flags.get("original", False))}"])
|
||||
|
||||
return cmd
|
||||
|
||||
def apply_metadata(self, metadata: dict, in_path: str, out_path: Optional[str] = None) -> bool:
|
||||
"""
|
||||
Writes metadata to a video file using mkvmerge or mkvpropedit
|
||||
|
||||
:param metadata: Metadata information
|
||||
:param in_path: Path of the input video file
|
||||
:param out_path: Path of the output video file. If None, ``"_modified"`` is appended to ``in_path`` instead
|
||||
:return: True if successful, False otherwise
|
||||
"""
|
||||
|
||||
if not os.path.isfile(in_path):
|
||||
self.logger.error(f"Input file not found: {in_path}")
|
||||
return False
|
||||
|
||||
if out_path is None:
|
||||
# Create a temporary output file
|
||||
base_name, ext = os.path.splitext(in_path)
|
||||
out_path: str = f"{base_name}_modified{ext}"
|
||||
|
||||
# Build the command
|
||||
overwriting: bool = os.path.abspath(in_path) == os.path.abspath(out_path)
|
||||
cmd: list[str] = (
|
||||
self.get_mkvpropedit_cmd(metadata, in_path)
|
||||
if overwriting else
|
||||
self.get_mkvmerge_cmd(metadata, in_path, out_path)
|
||||
)
|
||||
|
||||
print(cmd)
|
||||
|
||||
# Execute the command
|
||||
self.logger.debug(f"Writing metadata to {os.path.basename(out_path)}")
|
||||
|
||||
try:
|
||||
@ -80,7 +129,7 @@ class MetadataWriter:
|
||||
return True
|
||||
|
||||
except Exception as e:
|
||||
self.logger.error(f"Error executing mkvmerge: {str(e)}")
|
||||
self.logger.error(f"Error executing {cmd[0]}: {str(e)}")
|
||||
return False
|
||||
|
||||
@staticmethod
|
||||
|
Loading…
x
Reference in New Issue
Block a user