diff --git a/write_metadata.py b/write_metadata.py new file mode 100755 index 0000000..d4650b4 --- /dev/null +++ b/write_metadata.py @@ -0,0 +1,159 @@ +#!/usr/bin/env python3 +import argparse +import json +import os +import subprocess +import sys + +def read_metadata_json(json_file): + """ + Read metadata from a JSON file. + + Args: + json_file (str): Path to the JSON file + + Returns: + dict: Metadata information + """ + try: + with open(json_file, 'r', encoding='utf-8') as f: + metadata = json.load(f) + return metadata + except Exception as e: + print(f"❌ Error reading JSON file: {str(e)}") + return None + +def write_metadata_to_video(metadata, input_file, output_file=None): + """ + Write metadata to a video file using mkvmerge. + + Args: + metadata (dict): Metadata information + input_file (str): Path to the input video file + output_file (str, optional): Path to the output video file + + Returns: + bool: True if successful, False otherwise + """ + if not os.path.isfile(input_file): + print(f"❌ Input file not found: {input_file}") + return False + + if not output_file: + # Create a temporary output file + base_name, ext = os.path.splitext(input_file) + output_file = f"{base_name}_modified{ext}" + + # Start building the mkvmerge command + cmd = ["mkvmerge", "-o", output_file] + + # Add global metadata (title) + if "title" in metadata: + cmd.extend(["--title", metadata["title"]]) + + # Process audio tracks + for i, track in enumerate(metadata.get("audio_tracks", [])): + track_id = i + 1 # mkvmerge track IDs start from 0 for video, 1 for first audio + + # Set language + if "language" in track: + cmd.extend([f"--language", f"{track_id}:{track['language']}"]) + + # Set title/name + if "name" in track and track["name"]: + cmd.extend([f"--track-name", f"{track_id}:{track['name']}"]) + + # Set disposition flags + flags = track.get("flags", {}) + + if flags.get("default", False): + cmd.extend([f"--default-track", f"{track_id}:yes"]) + else: + cmd.extend([f"--default-track", f"{track_id}:no"]) + + if flags.get("forced", False): + cmd.extend([f"--forced-track", f"{track_id}:yes"]) + else: + cmd.extend([f"--forced-track", f"{track_id}:no"]) + + if flags.get("original", False): + cmd.extend([f"--original-flag", f"{track_id}:yes"]) + else: + cmd.extend([f"--original-flag", f"{track_id}:no"]) + + # Process subtitle tracks + for i, track in enumerate(metadata.get("subtitle_tracks", [])): + # Calculate track ID (assuming all audio tracks come before subtitle tracks) + track_id = len(metadata.get("audio_tracks", [])) + i + 1 + + # Set language + if "language" in track: + cmd.extend([f"--language", f"{track_id}:{track['language']}"]) + + # Set title/name + if "name" in track and track["name"]: + cmd.extend([f"--track-name", f"{track_id}:{track['name']}"]) + + # Set disposition flags + flags = track.get("flags", {}) + + if flags.get("default", False): + cmd.extend([f"--default-track", f"{track_id}:yes"]) + else: + cmd.extend([f"--default-track", f"{track_id}:no"]) + + if flags.get("forced", False): + cmd.extend([f"--forced-track", f"{track_id}:yes"]) + else: + cmd.extend([f"--forced-track", f"{track_id}:no"]) + + # Add input file + cmd.append(input_file) + + # Execute the mkvmerge command + print(f"🔄 Writing metadata to {os.path.basename(output_file)}") + print(f"Command: {' '.join(cmd)}") + + try: + result = subprocess.run(cmd, stdout=subprocess.PIPE, stderr=subprocess.PIPE, text=True) + if result.returncode != 0: + print(f"❌ Error writing metadata: {result.stderr}") + return False + + print(f"✅ Metadata written to {output_file}") + return True + except Exception as e: + print(f"❌ Error executing mkvmerge: {str(e)}") + return False + +def main(): + parser = argparse.ArgumentParser(description="Write metadata from JSON to video file.") + parser.add_argument("json_file", help="Path to input JSON metadata file") + parser.add_argument("video_file", help="Path to input video file") + parser.add_argument("-o", "--output", help="Path to output video file") + args = parser.parse_args() + + json_file = args.json_file + video_file = args.video_file + output_file = args.output + + if not os.path.isfile(json_file): + print(f"❌ JSON file not found: {json_file}") + sys.exit(1) + + if not os.path.isfile(video_file): + print(f"❌ Video file not found: {video_file}") + sys.exit(1) + + # Read metadata from JSON + metadata = read_metadata_json(json_file) + if not metadata: + sys.exit(1) + + # Write metadata to video + success = write_metadata_to_video(metadata, video_file, output_file) + if not success: + sys.exit(1) + +if __name__ == "__main__": + main()