inc stream management
This commit is contained in:
272
bin/ffx.py
272
bin/ffx.py
@@ -618,16 +618,6 @@ def convert(ctx,
|
|||||||
targetFilenameTokens = [sourceFileBasename]
|
targetFilenameTokens = [sourceFileBasename]
|
||||||
|
|
||||||
|
|
||||||
# SSD -> TSD -> MSO
|
|
||||||
#
|
|
||||||
# src file [vtt files] -> SSD
|
|
||||||
#
|
|
||||||
# in opts, checks -> TSD
|
|
||||||
#
|
|
||||||
# jellyfin -> MSO
|
|
||||||
#
|
|
||||||
# TSD - SSD, MSO -> out opts
|
|
||||||
|
|
||||||
# Load source stream descriptor
|
# Load source stream descriptor
|
||||||
try:
|
try:
|
||||||
###
|
###
|
||||||
@@ -638,28 +628,6 @@ def convert(ctx,
|
|||||||
click.echo(f"File with path {sourcePath} does not contain any audiovisual data, skipping ...")
|
click.echo(f"File with path {sourcePath} does not contain any audiovisual data, skipping ...")
|
||||||
continue
|
continue
|
||||||
|
|
||||||
# # Ensure disposition and tags keys for every stream
|
|
||||||
# for substreamIndex in range(len(sourceStreamDescriptor[STREAM_TYPE_AUDIO])):
|
|
||||||
# if not 'disposition' in sourceStreamDescriptor[STREAM_TYPE_AUDIO][substreamIndex].keys():
|
|
||||||
# sourceStreamDescriptor[STREAM_TYPE_AUDIO][substreamIndex]['disposition'] = {}
|
|
||||||
# if not 'default' in sourceStreamDescriptor[STREAM_TYPE_AUDIO][substreamIndex]['disposition'].keys():
|
|
||||||
# sourceStreamDescriptor[STREAM_TYPE_AUDIO][substreamIndex]['disposition']['default'] = 0
|
|
||||||
# if not 'forced' in sourceStreamDescriptor[STREAM_TYPE_AUDIO][substreamIndex]['disposition'].keys():
|
|
||||||
# sourceStreamDescriptor[STREAM_TYPE_AUDIO][substreamIndex]['disposition']['forced'] = 0
|
|
||||||
# for substreamIndex in range(len(sourceStreamDescriptor[STREAM_TYPE_AUDIO])):
|
|
||||||
# if not 'tags' in sourceStreamDescriptor[STREAM_TYPE_AUDIO][substreamIndex].keys():
|
|
||||||
# sourceStreamDescriptor[STREAM_TYPE_AUDIO][substreamIndex]['tags'] = {}
|
|
||||||
# for substreamIndex in range(len(sourceStreamDescriptor[STREAM_TYPE_SUBTITLE])):
|
|
||||||
# if not 'disposition' in sourceStreamDescriptor[STREAM_TYPE_SUBTITLE][substreamIndex].keys():
|
|
||||||
# sourceStreamDescriptor[STREAM_TYPE_SUBTITLE][substreamIndex]['disposition'] = {}
|
|
||||||
# if not 'default' in sourceStreamDescriptor[STREAM_TYPE_SUBTITLE][substreamIndex]['disposition'].keys():
|
|
||||||
# sourceStreamDescriptor[STREAM_TYPE_SUBTITLE][substreamIndex]['disposition']['default'] = 0
|
|
||||||
# if not 'forced' in sourceStreamDescriptor[STREAM_TYPE_SUBTITLE][substreamIndex]['disposition'].keys():
|
|
||||||
# sourceStreamDescriptor[STREAM_TYPE_SUBTITLE][substreamIndex]['disposition']['forced'] = 0
|
|
||||||
# for substreamIndex in range(len(sourceStreamDescriptor[STREAM_TYPE_SUBTITLE])):
|
|
||||||
# if not 'tags' in sourceStreamDescriptor[STREAM_TYPE_SUBTITLE][substreamIndex].keys():
|
|
||||||
# sourceStreamDescriptor[STREAM_TYPE_SUBTITLE][substreamIndex]['tags'] = {}
|
|
||||||
|
|
||||||
###
|
###
|
||||||
targetStreamDescriptor = sourceStreamDescriptor.copy()
|
targetStreamDescriptor = sourceStreamDescriptor.copy()
|
||||||
###
|
###
|
||||||
@@ -705,27 +673,6 @@ def convert(ctx,
|
|||||||
targetStreamDescriptor[STREAM_TYPE_SUBTITLE][substreamIndex]['disposition']['forded'] = 1 if substreamIndex == forcedSubtitle else 0
|
targetStreamDescriptor[STREAM_TYPE_SUBTITLE][substreamIndex]['disposition']['forded'] = 1 if substreamIndex == forcedSubtitle else 0
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
## Process input opts
|
|
||||||
|
|
||||||
# # Source stream descriptors
|
|
||||||
# audioStreams = targetStreamDescriptor[STREAM_TYPE_AUDIO]
|
|
||||||
# subtitleStreams = targetStreamDescriptor[STREAM_TYPE_SUBTITLE]
|
|
||||||
#
|
|
||||||
# # Set language and title in source stream descriptors if given per command line option
|
|
||||||
# for streamIndex in range(len(audioStreams)):
|
|
||||||
# if streamIndex <= len(audioLanguages) - 1:
|
|
||||||
# audioStreams[streamIndex]['tags']['language'] = audioLanguages[streamIndex]
|
|
||||||
# if streamIndex <= len(audioTitles) - 1:
|
|
||||||
# audioStreams[streamIndex]['tags']['title'] = audioTitles[streamIndex]
|
|
||||||
#
|
|
||||||
# for streamIndex in range(len(subtitleStreams)):
|
|
||||||
# if streamIndex <= len(subtitleLanguages) - 1:
|
|
||||||
# subtitleStreams[streamIndex]['tags']['language'] = subtitleLanguages[streamIndex]
|
|
||||||
# if streamIndex <= len(subtitleTitles) - 1:
|
|
||||||
# subtitleStreams[streamIndex]['tags']['title'] = subtitleTitles[streamIndex]
|
|
||||||
|
|
||||||
|
|
||||||
# Set language and title in source stream descriptors if given per command line option
|
# Set language and title in source stream descriptors if given per command line option
|
||||||
for streamIndex in range(len(targetStreamDescriptor[STREAM_TYPE_AUDIO])):
|
for streamIndex in range(len(targetStreamDescriptor[STREAM_TYPE_AUDIO])):
|
||||||
if streamIndex <= len(audioLanguages) - 1:
|
if streamIndex <= len(audioLanguages) - 1:
|
||||||
@@ -740,6 +687,7 @@ def convert(ctx,
|
|||||||
targetStreamDescriptor[STREAM_TYPE_SUBTITLE][streamIndex]['tags']['title'] = subtitleTitles[streamIndex]
|
targetStreamDescriptor[STREAM_TYPE_SUBTITLE][streamIndex]['tags']['title'] = subtitleTitles[streamIndex]
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
click.echo('\nTarget streams:')
|
click.echo('\nTarget streams:')
|
||||||
for aStream in targetStreamDescriptor[STREAM_TYPE_AUDIO]:
|
for aStream in targetStreamDescriptor[STREAM_TYPE_AUDIO]:
|
||||||
click.echo(f"audio stream {aStream['sub_index']} lang={aStream['tags']['language']} title={aStream['tags']['title']} default={aStream['disposition']['default']} forced={aStream['disposition']['forced']}")
|
click.echo(f"audio stream {aStream['sub_index']} lang={aStream['tags']['language']} title={aStream['tags']['title']} default={aStream['disposition']['default']} forced={aStream['disposition']['forced']}")
|
||||||
@@ -747,6 +695,7 @@ def convert(ctx,
|
|||||||
click.echo(f"subtitle stream {sStream['sub_index']} lang={sStream['tags']['language']} title={sStream['tags']['title']} default={sStream['disposition']['default']} forced={sStream['disposition']['forced']}")
|
click.echo(f"subtitle stream {sStream['sub_index']} lang={sStream['tags']['language']} title={sStream['tags']['title']} default={sStream['disposition']['default']} forced={sStream['disposition']['forced']}")
|
||||||
|
|
||||||
|
|
||||||
|
# Find source stream order
|
||||||
audioStreamSourceOrder = list(range(len(sourceStreamDescriptor[STREAM_TYPE_AUDIO])))
|
audioStreamSourceOrder = list(range(len(sourceStreamDescriptor[STREAM_TYPE_AUDIO])))
|
||||||
subtitleStreamSourceOrder = list(range(len(sourceStreamDescriptor[STREAM_TYPE_SUBTITLE])))
|
subtitleStreamSourceOrder = list(range(len(sourceStreamDescriptor[STREAM_TYPE_SUBTITLE])))
|
||||||
|
|
||||||
@@ -761,35 +710,66 @@ def convert(ctx,
|
|||||||
subtitleStreamSourceOrder = getModifiedStreamOrder(len(sourceStreamDescriptor[STREAM_TYPE_SUBTITLE]), defaultTargetSubtitleStreams[0]['sub_index'])
|
subtitleStreamSourceOrder = getModifiedStreamOrder(len(sourceStreamDescriptor[STREAM_TYPE_SUBTITLE]), defaultTargetSubtitleStreams[0]['sub_index'])
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
mappingVideoTokens = ['-map', '0:v:0']
|
||||||
|
|
||||||
|
mappingTokens = mappingVideoTokens.copy()
|
||||||
|
dispositionTokens = []
|
||||||
|
|
||||||
|
audioTokens = []
|
||||||
|
|
||||||
|
|
||||||
|
audioMetadataTokens = []
|
||||||
|
for audioStreamIndex in range(len(sourceStreamDescriptor[STREAM_TYPE_AUDIO])):
|
||||||
|
|
||||||
|
sourceAudioStreamIndex = audioStreamSourceOrder[audioStreamIndex]
|
||||||
|
sourceAudioStream = sourceStreamDescriptor[STREAM_TYPE_AUDIO][sourceAudioStreamIndex]
|
||||||
|
|
||||||
|
# Create mapping and ffmpeg options for audio streams
|
||||||
|
# mappingTokens += ['-map', f"0:a:{sourceAudioStreamIndex['src_sub_index']}"]
|
||||||
|
mappingTokens += ['-map', f"0:a:{sourceAudioStreamIndex}"]
|
||||||
|
|
||||||
|
# audioTokens += generateAudioTokens(context, sourceAudioStream['src_sub_index'], sourceAudioStream['layout'])
|
||||||
|
audioTokens += generateAudioTokens(context, sourceAudioStreamIndex, sourceAudioStream['audio_layout'])
|
||||||
|
|
||||||
|
if sourceStreamDescriptor[STREAM_TYPE_AUDIO][audioStreamIndex]['tags']['language'] != targetStreamDescriptor[STREAM_TYPE_AUDIO][audioStreamIndex]['tags']['language']:
|
||||||
|
audioMetadataTokens += [f"-metadata:s:a:{audioStreamIndex}", f"language={targetStreamDescriptor[STREAM_TYPE_AUDIO][audioStreamIndex]['tags']['language']}"]
|
||||||
|
|
||||||
|
if sourceStreamDescriptor[STREAM_TYPE_AUDIO][audioStreamIndex]['tags']['title'] != targetStreamDescriptor[STREAM_TYPE_AUDIO][audioStreamIndex]['tags']['title']:
|
||||||
|
audioMetadataTokens += [f"-metadata:s:a:{audioStreamIndex}", f"title={targetStreamDescriptor[STREAM_TYPE_AUDIO][audioStreamIndex]['tags']['title']}"]
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
click.echo(f"Audio stream source order {audioStreamSourceOrder}")
|
click.echo(f"Audio stream source order {audioStreamSourceOrder}")
|
||||||
click.echo(f"Subtitle stream source order {subtitleStreamSourceOrder}")
|
click.echo(f"Subtitle stream source order {subtitleStreamSourceOrder}")
|
||||||
|
|
||||||
continue
|
|
||||||
|
|
||||||
|
|
||||||
commandTokens = COMMAND_TOKENS + ['-i', sourcePath]
|
commandTokens = COMMAND_TOKENS + ['-i', sourcePath]
|
||||||
|
|
||||||
subtitleFileTokens = []
|
subtitleFileTokens = []
|
||||||
matchingSubtitles = []
|
subtitleMetadataTokens = []
|
||||||
if context['import_subtitles']:
|
|
||||||
|
|
||||||
subtitles = [a for a in availableFileSubtitleDescriptors if a['season'] == season and a['episode'] == episode]
|
# matchingSubtitles = []
|
||||||
mSubtitles = sorted(subtitles, key=lambda d: d['stream'])
|
# if context['import_subtitles']:
|
||||||
|
#
|
||||||
for sfd in mSubtitles:
|
# subtitles = [a for a in availableFileSubtitleDescriptors if a['season'] == season and a['episode'] == episode]
|
||||||
subtitleFileTokens += ['-i', sfd['path']]
|
# mSubtitles = sorted(subtitles, key=lambda d: d['stream'])
|
||||||
|
#
|
||||||
for streamIndex in range(len(mSubtitles)):
|
# for sfd in mSubtitles:
|
||||||
mSubtitles[streamIndex]['forced'] = 1 if forcedSubtitle != -1 and streamIndex == forcedSubtitle else 0
|
# subtitleFileTokens += ['-i', sfd['path']]
|
||||||
mSubtitles[streamIndex]['default'] = 1 if defaultSubtitle != -1 and streamIndex == defaultSubtitle else 0
|
#
|
||||||
|
# for streamIndex in range(len(mSubtitles)):
|
||||||
if streamIndex <= len(subtitleTitles) -1:
|
# mSubtitles[streamIndex]['forced'] = 1 if forcedSubtitle != -1 and streamIndex == forcedSubtitle else 0
|
||||||
mSubtitles[streamIndex]['title'] = subtitleTitles[streamIndex]
|
# mSubtitles[streamIndex]['default'] = 1 if defaultSubtitle != -1 and streamIndex == defaultSubtitle else 0
|
||||||
|
#
|
||||||
if defaultSubtitle != -1 and jellyfin:
|
# if streamIndex <= len(subtitleTitles) -1:
|
||||||
matchingSubtitles = getReorderedSubstreams(mSubtitles, defaultSubtitle)
|
# mSubtitles[streamIndex]['title'] = subtitleTitles[streamIndex]
|
||||||
else:
|
#
|
||||||
matchingSubtitles = mSubtitles
|
# if defaultSubtitle != -1 and jellyfin:
|
||||||
|
# matchingSubtitles = getReorderedSubstreams(mSubtitles, defaultSubtitle)
|
||||||
|
# else:
|
||||||
|
# matchingSubtitles = mSubtitles
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
@@ -798,93 +778,71 @@ def convert(ctx,
|
|||||||
click.echo(f"\nRunning job {job_index} file={sourcePath} q={q}")
|
click.echo(f"\nRunning job {job_index} file={sourcePath} q={q}")
|
||||||
job_index += 1
|
job_index += 1
|
||||||
|
|
||||||
mappingVideoTokens = ['-map', '0:v:0']
|
|
||||||
|
|
||||||
mappingTokens = mappingVideoTokens.copy()
|
# # Reorder audio stream descriptors and create disposition options if default is given per command line option
|
||||||
dispositionTokens = []
|
# if defaultAudio == -1:
|
||||||
|
# sourceAudioStreams = audioStreams
|
||||||
|
# else:
|
||||||
|
# for streamIndex in range(len(audioStreams)):
|
||||||
|
# audioStreams[streamIndex]['disposition']['default'] = 1 if streamIndex == defaultAudio else 0
|
||||||
|
#
|
||||||
|
# sourceAudioStreams = getReorderedSubstreams(audioStreams, defaultAudio) if jellyfin else audioStreams
|
||||||
|
#
|
||||||
|
# dispositionTokens += generateDispositionTokens(sourceAudioStreams)
|
||||||
|
#
|
||||||
|
# # Set forced tag in subtitle descriptor if given per command line option
|
||||||
|
# if forcedSubtitle != -1:
|
||||||
|
# for streamIndex in range(len(subtitleStreams)):
|
||||||
|
# subtitleStreams[streamIndex]['disposition']['forced'] = 1 if streamIndex == forcedSubtitle else 0
|
||||||
|
#
|
||||||
|
# # Reorder subtitle stream descriptors and create disposition options if default is given per command line option
|
||||||
|
# if defaultSubtitle == -1:
|
||||||
|
# sourceSubtitleStreams = subtitleStreams
|
||||||
|
# else:
|
||||||
|
# for streamIndex in range(len(subtitleStreams)):
|
||||||
|
# subtitleStreams[streamIndex]['disposition']['default'] = 1 if streamIndex == defaultSubtitle else 0
|
||||||
|
#
|
||||||
|
# sourceSubtitleStreams = getReorderedSubstreams(subtitleStreams, defaultSubtitle) if jellyfin else subtitleStreams
|
||||||
|
#
|
||||||
|
# dispositionTokens += generateDispositionTokens(sourceSubtitleStreams)
|
||||||
|
#
|
||||||
|
|
||||||
audioTokens = []
|
|
||||||
|
|
||||||
|
|
||||||
# Reorder audio stream descriptors and create disposition options if default is given per command line option
|
|
||||||
if defaultAudio == -1:
|
|
||||||
sourceAudioStreams = audioStreams
|
|
||||||
else:
|
|
||||||
for streamIndex in range(len(audioStreams)):
|
|
||||||
audioStreams[streamIndex]['disposition']['default'] = 1 if streamIndex == defaultAudio else 0
|
|
||||||
|
|
||||||
sourceAudioStreams = getReorderedSubstreams(audioStreams, defaultAudio) if jellyfin else audioStreams
|
# # Create mapping and ffmpeg options for subtitle streams
|
||||||
|
|
||||||
dispositionTokens += generateDispositionTokens(sourceAudioStreams)
|
# if context['import_subtitles']:
|
||||||
|
#
|
||||||
# Set forced tag in subtitle descriptor if given per command line option
|
# numMatchingSubtitles = len(matchingSubtitles)
|
||||||
if forcedSubtitle != -1:
|
#
|
||||||
for streamIndex in range(len(subtitleStreams)):
|
# if jellyfin and defaultSubtitle != -1:
|
||||||
subtitleStreams[streamIndex]['disposition']['forced'] = 1 if streamIndex == forcedSubtitle else 0
|
# subtitleSequence = getModifiedStreamOrder(numMatchingSubtitles, default_subtitle) #!
|
||||||
|
# else:
|
||||||
# Reorder subtitle stream descriptors and create disposition options if default is given per command line option
|
# subtitleSequence = range(numMatchingSubtitles)
|
||||||
if defaultSubtitle == -1:
|
#
|
||||||
sourceSubtitleStreams = subtitleStreams
|
# for fileIndex in range(numMatchingSubtitles):
|
||||||
else:
|
#
|
||||||
for streamIndex in range(len(subtitleStreams)):
|
# # Create mapping for subtitle streams when imported from files
|
||||||
subtitleStreams[streamIndex]['disposition']['default'] = 1 if streamIndex == defaultSubtitle else 0
|
# mappingTokens += ['-map', f"{subtitleSequence[fileIndex]+1}:s:0"]
|
||||||
|
#
|
||||||
sourceSubtitleStreams = getReorderedSubstreams(subtitleStreams, defaultSubtitle) if jellyfin else subtitleStreams
|
# msg = matchingSubtitles[fileIndex]
|
||||||
|
# subtitleMetadataTokens += [f"-metadata:s:s:{fileIndex}", f"language={msg['language']}"]
|
||||||
dispositionTokens += generateDispositionTokens(sourceSubtitleStreams)
|
# if 'title' in matchingSubtitles[fileIndex].keys():
|
||||||
|
# subtitleMetadataTokens += [f"-metadata:s:s:{fileIndex}", f"title={matchingSubtitles[fileIndex]['title']}"]
|
||||||
|
#
|
||||||
audioMetadataTokens = []
|
# else:
|
||||||
for audioStreamIndex in range(len(sourceAudioStreams)):
|
#
|
||||||
|
# for subtitleStreamIndex in range(len(sourceSubtitleStreams)):
|
||||||
audioStream = sourceAudioStreams[audioStreamIndex]
|
#
|
||||||
|
# subtitleStream = sourceSubtitleStreams[subtitleStreamIndex]
|
||||||
# Create mapping and ffmpeg options for audio streams
|
#
|
||||||
mappingTokens += ['-map', f"0:a:{audioStream['src_sub_index']}"]
|
# # Create mapping for subtitle streams
|
||||||
audioTokens += generateAudioTokens(context, audioStream['src_sub_index'], audioStream['layout'])
|
# mappingTokens += ['-map', f"s:{subtitleStream['src_sub_index']}"]
|
||||||
|
#
|
||||||
if 'tags' in audioStream.keys():
|
# if 'tags' in subtitleStream.keys():
|
||||||
if 'language' in audioStream['tags'].keys():
|
# if 'language' in subtitleStream['tags'].keys():
|
||||||
audioMetadataTokens += [f"-metadata:s:a:{audioStreamIndex}", f"language={audioStream['tags']['language']}"]
|
# subtitleMetadataTokens += [f"-metadata:s:s:{subtitleStreamIndex}", f"language={subtitleStream['tags']['language']}"]
|
||||||
if 'title' in audioStream['tags'].keys():
|
# if 'title' in subtitleStream['tags'].keys():
|
||||||
audioMetadataTokens += [f"-metadata:s:a:{audioStreamIndex}", f"title={audioStream['tags']['title']}"]
|
# subtitleMetadataTokens += [f"-metadata:s:s:{subtitleStreamIndex}", f"title={subtitleStream['tags']['title']}"]
|
||||||
|
|
||||||
|
|
||||||
# Create mapping and ffmpeg options for subtitle streams
|
|
||||||
subtitleMetadataTokens = []
|
|
||||||
if context['import_subtitles']:
|
|
||||||
|
|
||||||
numMatchingSubtitles = len(matchingSubtitles)
|
|
||||||
|
|
||||||
if jellyfin and defaultSubtitle != -1:
|
|
||||||
subtitleSequence = getModifiedStreamOrder(numMatchingSubtitles, default_subtitle) #!
|
|
||||||
else:
|
|
||||||
subtitleSequence = range(numMatchingSubtitles)
|
|
||||||
|
|
||||||
for fileIndex in range(numMatchingSubtitles):
|
|
||||||
|
|
||||||
# Create mapping for subtitle streams when imported from files
|
|
||||||
mappingTokens += ['-map', f"{subtitleSequence[fileIndex]+1}:s:0"]
|
|
||||||
|
|
||||||
msg = matchingSubtitles[fileIndex]
|
|
||||||
subtitleMetadataTokens += [f"-metadata:s:s:{fileIndex}", f"language={msg['language']}"]
|
|
||||||
if 'title' in matchingSubtitles[fileIndex].keys():
|
|
||||||
subtitleMetadataTokens += [f"-metadata:s:s:{fileIndex}", f"title={matchingSubtitles[fileIndex]['title']}"]
|
|
||||||
|
|
||||||
else:
|
|
||||||
|
|
||||||
for subtitleStreamIndex in range(len(sourceSubtitleStreams)):
|
|
||||||
|
|
||||||
subtitleStream = sourceSubtitleStreams[subtitleStreamIndex]
|
|
||||||
|
|
||||||
# Create mapping for subtitle streams
|
|
||||||
mappingTokens += ['-map', f"s:{subtitleStream['src_sub_index']}"]
|
|
||||||
|
|
||||||
if 'tags' in subtitleStream.keys():
|
|
||||||
if 'language' in subtitleStream['tags'].keys():
|
|
||||||
subtitleMetadataTokens += [f"-metadata:s:s:{subtitleStreamIndex}", f"language={subtitleStream['tags']['language']}"]
|
|
||||||
if 'title' in subtitleStream['tags'].keys():
|
|
||||||
subtitleMetadataTokens += [f"-metadata:s:s:{subtitleStreamIndex}", f"title={subtitleStream['tags']['title']}"]
|
|
||||||
|
|
||||||
|
|
||||||
# Job specific tokens
|
# Job specific tokens
|
||||||
|
|||||||
Reference in New Issue
Block a user