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
|
# Install ffmpeg and mkvtoolnix
|
||||||
# but only keep the binaries and libs for ffprobe and mkvmerge
|
# 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 \
|
&& mkdir -p /artifacts/bin /artifacts/lib \
|
||||||
&& cp $(which ffprobe) /artifacts/bin/ \
|
&& cp $(which ffprobe) /artifacts/bin/ \
|
||||||
&& cp $(which mkvmerge) /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 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
|
# 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/bin/* /usr/local/bin/
|
||||||
COPY --from=builder /artifacts/lib/* /usr/local/lib/
|
COPY --from=builder /artifacts/lib/* /usr/local/lib/
|
||||||
|
@ -81,6 +81,12 @@ class MetadataExtractor:
|
|||||||
}
|
}
|
||||||
metadata["subtitle_tracks"].append(track)
|
metadata["subtitle_tracks"].append(track)
|
||||||
|
|
||||||
|
elif codec_type == "video":
|
||||||
|
pass
|
||||||
|
|
||||||
|
elif codec_type == "button":
|
||||||
|
pass
|
||||||
|
|
||||||
else:
|
else:
|
||||||
self.logger.warning(f"Unknown track codec type '{codec_type}'")
|
self.logger.warning(f"Unknown track codec type '{codec_type}'")
|
||||||
|
|
||||||
|
@ -11,26 +11,7 @@ class MetadataWriter:
|
|||||||
def __init__(self):
|
def __init__(self):
|
||||||
self.logger: logging.Logger = logging.getLogger("MetadataWriter")
|
self.logger: logging.Logger = logging.getLogger("MetadataWriter")
|
||||||
|
|
||||||
def apply_metadata(self, metadata: dict, in_path: str, out_path: Optional[str] = None) -> bool:
|
def get_mkvmerge_cmd(self, metadata: dict, in_path: str, out_path: str) -> list[str]:
|
||||||
"""
|
|
||||||
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
|
|
||||||
cmd: list[str] = [
|
cmd: list[str] = [
|
||||||
"mkvmerge",
|
"mkvmerge",
|
||||||
"-o", out_path
|
"-o", out_path
|
||||||
@ -66,8 +47,76 @@ class MetadataWriter:
|
|||||||
|
|
||||||
# Add input file
|
# Add input file
|
||||||
cmd.append(in_path)
|
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)}")
|
self.logger.debug(f"Writing metadata to {os.path.basename(out_path)}")
|
||||||
|
|
||||||
try:
|
try:
|
||||||
@ -80,7 +129,7 @@ class MetadataWriter:
|
|||||||
return True
|
return True
|
||||||
|
|
||||||
except Exception as e:
|
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
|
return False
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
|
Loading…
x
Reference in New Issue
Block a user