From 5ca7d6d12c356ebca37eceb635f5a8dd2044d959 Mon Sep 17 00:00:00 2001 From: Maveno Date: Sun, 20 Oct 2024 17:58:07 +0200 Subject: [PATCH] unmux mwe --- bin/ffx.py | 129 +++++++++++++++++++++++++------------ bin/ffx/ffx_controller.py | 1 + bin/ffx/file_properties.py | 2 + 3 files changed, 90 insertions(+), 42 deletions(-) diff --git a/bin/ffx.py b/bin/ffx.py index ea7e436..d545693 100755 --- a/bin/ffx.py +++ b/bin/ffx.py @@ -11,10 +11,13 @@ from ffx.tmdb_controller import TmdbController from ffx.database import databaseContext +from ffx.track_descriptor import TrackDescriptor from ffx.track_type import TrackType from ffx.video_encoder import VideoEncoder from ffx.track_disposition import TrackDisposition +from ffx.process import executeProcess + VERSION='0.1.2' @@ -60,53 +63,95 @@ def inspect(ctx, filename): app = FfxApp(ctx.obj) app.run() +#TODO: TrackCodec Klasse +CODEC_LOOKUP_TABLE = { + 'h264': {'format': 'h264', 'extension': 'h264'}, + 'aac': { 'extension': 'aac'}, + 'ac3': {'format': 'ac3', 'extension': 'ac3'}, + 'ass': {'format': 'ass', 'extension': 'ass'}, + 'hdmv_pgs_subtitle': {'format': 'sup', 'extension': 'sup'} +} + +def getUnmuxSequence(trackDescriptor: TrackDescriptor, sourcePath, targetPrefix, targetDirectory = ''): + + trackCodec = trackDescriptor.getCodec() + + if not trackCodec in CODEC_LOOKUP_TABLE.keys(): + return [] + + commandTokens = FfxController.COMMAND_TOKENS + ['-i', sourcePath] + trackType = trackDescriptor.getType() + + targetPathBase = os.path.join(targetDirectory, targetPrefix) if targetDirectory else targetPrefix + + commandTokens += ['-map', + f"0:{trackType.indicator()}:{trackDescriptor.getSubIndex()}", + '-c', + 'copy'] + + if 'format' in CODEC_LOOKUP_TABLE[trackCodec].keys(): + commandTokens += ['-f', CODEC_LOOKUP_TABLE[trackCodec]['format']] + + commandTokens += [f"{targetPathBase}.{CODEC_LOOKUP_TABLE[trackCodec]['extension']}"] + return commandTokens -# @ffx.command() -# @click.pass_context -# -# @click.argument('paths', nargs=-1) -# @click.option('-l', '--label', type=str, default='', help='Label to be used as filename prefix') -# -# @click.option('-sd', '--subtitle-directory', type=str, default='', help='Load subtitles from here') -# @click.option('-sp', '--subtitle-prefix', type=str, default='', help='Subtitle filename prefix') -# -# @click.option("-o", "--output-directory", type=str, default='') -# -# @click.option("--dry-run", is_flag=True, default=False) -# -# -# def unmux(ctx, -# label, -# paths, -# subtitle_directory, -# subtitle_prefix, -# output_directory, -# dry_run): -# -# existingSourcePaths = [p for p in paths if os.path.isfile(p)] -# click.echo(f"\nUnmuxing {len(existingSourcePaths)} files") -# -# for sourcePath in existingSourcePaths: -# -# sd = getStreamDescriptor(sourcePath) -# -# print(f"\nFile {sourcePath}\n") -# -# for v in sd['video']: -# -# if v['codec_name'] == 'h264': -# -# commandSequence = ['ffmpeg', '-i', sourcePath, '-map', '0:v:0', '-c', 'copy', '-f', 'h264'] -# executeProcess() -# -# for a in sd['audio']: -# print(f"A: {a}\n") -# for s in sd['subtitle']: -# print(f"S: {s}\n") +@ffx.command() +@click.pass_context + +@click.argument('paths', nargs=-1) +@click.option('-l', '--label', type=str, default='', help='Label to be used as filename prefix') +@click.option("-o", "--output-directory", type=str, default='') +@click.option("-s", "--subtitles-only", is_flag=True, default=False) +@click.option("--dry-run", is_flag=True, default=False) +def unmux(ctx, + paths, + label, + output_directory, + subtitles_only, + dry_run): + + existingSourcePaths = [p for p in paths if os.path.isfile(p)] + click.echo(f"\nUnmuxing {len(existingSourcePaths)} files") + + for sourcePath in existingSourcePaths: + + fp = FileProperties(ctx.obj, sourcePath) + + print(f"\nFile {sourcePath}\n") + + try: + sourceMediaDescriptor = fp.getMediaDescriptor() + + for trackDescriptor in sourceMediaDescriptor.getAllTrackDescriptors(): + + if trackDescriptor.getType() == TrackType.SUBTITLE or not subtitles_only: + + season = fp.getSeason() + episode = fp.getEpisode() + + targetLabel = label if label else fp.getFileBasename() + targetIndicator = f"_S{season}E{episode}" if label and season != -1 and episode != -1 else '' + + # SEASON_EPISODE_STREAM_LANGUAGE_MATCH = '[sS]([0-9]+)[eE]([0-9]+)_([0-9]+)_([a-z]{3})' + targetPrefix = f"{targetLabel}{targetIndicator}_{trackDescriptor.getIndex()}_{trackDescriptor.getLanguage().threeLetter()}" + + unmuxSequence = getUnmuxSequence(trackDescriptor, sourcePath, targetPrefix, targetDirectory = output_directory) + + if unmuxSequence: + if not dry_run: + click.echo(f"Executing unmuxing sequence: {' '.join(unmuxSequence)}") + out, err, rc = executeProcess(unmuxSequence) + if rc: + click.echo(f"Unmuxing of stream {trackDescriptor.getIndex()} failed with error ({rc}) {err}") + else: + click.echo(f"Skipping stream with unknown codec {trackDescriptor.getCodec()}") + except Exception as ex: + click.echo(f"Skipping File {sourcePath} ({ex})") + @ffx.command() @click.pass_context diff --git a/bin/ffx/ffx_controller.py b/bin/ffx/ffx_controller.py index 3b4a56d..cf07443 100644 --- a/bin/ffx/ffx_controller.py +++ b/bin/ffx/ffx_controller.py @@ -455,3 +455,4 @@ class FfxController(): out, err, rc = executeProcess(commandSequence2) if rc: raise click.ClickException(f"Command resulted in error: rc={rc} error={err}") + diff --git a/bin/ffx/file_properties.py b/bin/ffx/file_properties.py index 7dc8b74..cd5965f 100644 --- a/bin/ffx/file_properties.py +++ b/bin/ffx/file_properties.py @@ -185,6 +185,8 @@ class FileProperties(): def getEpisode(self): return int(self.__episode) + def getFileBasename(self): + return self.__sourceFileBasename def assembleTargetFileBasename(self, label: str = "",