@ -13,6 +13,7 @@ from ffx.database import databaseContext
from ffx . track_type import TrackType
from ffx . track_type import TrackType
from ffx . video_encoder import VideoEncoder
from ffx . video_encoder import VideoEncoder
from ffx . track_disposition import TrackDisposition
VERSION = ' 0.1.2 '
VERSION = ' 0.1.2 '
@ -160,6 +161,7 @@ def shows(ctx):
@click.option ( " -t " , " --no-tmdb " , is_flag = True , default = False )
@click.option ( " -t " , " --no-tmdb " , is_flag = True , default = False )
@click.option ( " -j " , " --no-jellyfin " , is_flag = True , default = False )
@click.option ( " -j " , " --no-jellyfin " , is_flag = True , default = False )
@click.option ( " -np " , " --no-pattern " , is_flag = True , default = False )
@click.option ( " --dry-run " , is_flag = True , default = False )
@click.option ( " --dry-run " , is_flag = True , default = False )
@ -191,6 +193,7 @@ def convert(ctx,
denoise ,
denoise ,
no_tmdb ,
no_tmdb ,
no_jellyfin ,
no_jellyfin ,
no_pattern ,
dry_run ) :
dry_run ) :
""" Batch conversion of audiovideo files in format suitable for web playback, e.g. jellyfin
""" Batch conversion of audiovideo files in format suitable for web playback, e.g. jellyfin
@ -207,8 +210,9 @@ def convert(ctx,
context [ ' video_encoder ' ] = VideoEncoder . fromLabel ( video_encoder )
context [ ' video_encoder ' ] = VideoEncoder . fromLabel ( video_encoder )
context [ ' jellyfin ' ] = not no_jellyfin
context [ ' use_jellyfin ' ] = not no_jellyfin
context [ ' tmdb ' ] = not no_tmdb
context [ ' use_tmdb ' ] = not no_tmdb
context [ ' use_pattern ' ] = not no_pattern
context [ ' import_subtitles ' ] = ( subtitle_directory and subtitle_prefix )
context [ ' import_subtitles ' ] = ( subtitle_directory and subtitle_prefix )
if context [ ' import_subtitles ' ] :
if context [ ' import_subtitles ' ] :
@ -242,7 +246,7 @@ def convert(ctx,
click . echo ( f " Crop start= { context [ ' crop_start ' ] } length= { context [ ' crop_length ' ] } " )
click . echo ( f " Crop start= { context [ ' crop_start ' ] } length= { context [ ' crop_length ' ] } " )
tc = TmdbController ( )
tc = TmdbController ( ) if context [ ' use_tmdb ' ] else None
existingSourcePaths = [ p for p in paths if os . path . isfile ( p ) and p . split ( ' . ' ) [ - 1 ] in FfxController . INPUT_FILE_EXTENSIONS ]
existingSourcePaths = [ p for p in paths if os . path . isfile ( p ) and p . split ( ' . ' ) [ - 1 ] in FfxController . INPUT_FILE_EXTENSIONS ]
click . echo ( f " \n Running { len ( existingSourcePaths ) * len ( q_list ) } jobs " )
click . echo ( f " \n Running { len ( existingSourcePaths ) * len ( q_list ) } jobs " )
@ -265,7 +269,7 @@ def convert(ctx,
sourceMediaDescriptor = mediaFileProperties . getMediaDescriptor ( )
sourceMediaDescriptor = mediaFileProperties . getMediaDescriptor ( )
#HINT: This is None if the filename did not match anything in database
#HINT: This is None if the filename did not match anything in database
currentPattern = mediaFileProperties . getPattern ( )
currentPattern = mediaFileProperties . getPattern ( ) if context [ ' use_pattern ' ] else None
click . echo ( f " Pattern matching: { ' No ' if currentPattern is None else ' Yes ' } " )
click . echo ( f " Pattern matching: { ' No ' if currentPattern is None else ' Yes ' } " )
@ -279,45 +283,36 @@ def convert(ctx,
#
#
# Query user for the correct sub indices, then configure flags in track descriptors associated with media descriptor accordingly.
# Query user for the correct sub indices, then configure flags in track descriptors associated with media descriptor accordingly.
# The correct tokens should then be created by
# The correct tokens should then be created by
try :
if len ( [ v for v in sourceMediaDescriptor . getVideoTracks ( ) if v . getDispositionFlag ( TrackDisposition . DEFAULT ) ] ) > 1 :
sourceMediaDescriptor . getDefaultVideoTrack ( )
except ValueError :
defaultVideoTrackSubIndex = click . prompt ( " More than one default video stream detected! Please select stream " , type = int )
defaultVideoTrackSubIndex = click . prompt ( " More than one default video stream detected! Please select stream " , type = int )
sourceMediaDescriptor . setDefaultSubTrack ( TrackType . VIDEO , defaultVideoTrackSubIndex )
sourceMediaDescriptor . setDefaultSubTrack ( TrackType . VIDEO , defaultVideoTrackSubIndex )
try :
sourceMediaDescriptor . getForcedVideoTrack ( )
if len ( [ v for v in sourceMediaDescriptor . getVideoTracks ( ) if v . getDispositionFlag ( TrackDisposition . FORCED ) ] ) > 1 :
except ValueError :
forcedVideoTrackSubIndex = click . prompt ( " More than one forced video stream detected! Please select stream " , type = int )
forcedVideoTrackSubIndex = click . prompt ( " More than one forced video stream detected! Please select stream " , type = int )
sourceMediaDescriptor . setForcedSubTrack ( TrackType . VIDEO , forcedVideoTrackSubIndex )
sourceMediaDescriptor . setForcedSubTrack ( TrackType . VIDEO , forcedVideoTrackSubIndex )
try :
sourceMediaDescriptor . getDefaultAudioTrack ( )
if len ( [ a for a in sourceMediaDescriptor . getAudioTracks ( ) if a . getDispositionFlag ( TrackDisposition . DEFAULT ) ] ) > 1 :
except ValueError :
defaultAudioTrackSubIndex = click . prompt ( " More than one default audio stream detected! Please select stream " , type = int )
defaultAudioTrackSubIndex = click . prompt ( " More than one default audio stream detected! Please select stream " , type = int )
sourceMediaDescriptor . setDefaultSubTrack ( TrackType . AUDIO , defaultAudioTrackSubIndex )
sourceMediaDescriptor . setDefaultSubTrack ( TrackType . AUDIO , defaultAudioTrackSubIndex )
try :
sourceMediaDescriptor . getForcedAudioTrack ( )
if len ( [ a for a in sourceMediaDescriptor . getAudioTracks ( ) if a . getDispositionFlag ( TrackDisposition . FORCED ) ] ) > 1 :
except ValueError :
forcedAudioTrackSubIndex = click . prompt ( " More than one forced audio stream detected! Please select stream " , type = int )
forcedAudioTrackSubIndex = click . prompt ( " More than one forced audio stream detected! Please select stream " , type = int )
sourceMediaDescriptor . setForcedSubTrack ( TrackType . AUDIO , forcedAudioTrackSubIndex )
sourceMediaDescriptor . setForcedSubTrack ( TrackType . AUDIO , forcedAudioTrackSubIndex )
try :
sourceMediaDescriptor . getDefaultSubtitleTrack ( )
if len ( [ s for s in sourceMediaDescriptor . getSubtitleTracks ( ) if s . getDispositionFlag ( TrackDisposition . DEFAULT ) ] ) > 1 :
except ValueError :
defaultSubtitleTrackSubIndex = click . prompt ( " More than one default subtitle stream detected! Please select stream " , type = int )
defaultSubtitleTrackSubIndex = click . prompt ( " More than one default subtitle stream detected! Please select stream " , type = int )
sourceMediaDescriptor . setDefaultSubTrack ( TrackType . SUBTITLE , defaultSubtitleTrackSubIndex )
sourceMediaDescriptor . setDefaultSubTrack ( TrackType . SUBTITLE , defaultSubtitleTrackSubIndex )
try :
sourceMediaDescriptor . getForcedSubtitleTrack ( )
if len ( [ s for s in sourceMediaDescriptor . getSubtitleTracks ( ) if s . getDispositionFlag ( TrackDisposition . FORCED ) ] ) > 1 :
except ValueError :
forcedSubtitleTrackSubIndex = click . prompt ( " More than one forced subtitle stream detected! Please select stream " , type = int )
forcedSubtitleTrackSubIndex = click . prompt ( " More than one forced subtitle stream detected! Please select stream " , type = int )
sourceMediaDescriptor . setForcedSubTrack ( TrackType . SUBTITLE , forcedSubtitleTrackSubIndex )
sourceMediaDescriptor . setForcedSubTrack ( TrackType . SUBTITLE , forcedSubtitleTrackSubIndex )
if context [ ' import_subtitles ' ] :
if context [ ' import_subtitles ' ] :
sourceMediaDescriptor . importSubtitles ( context [ ' subtitle_directory ' ] , context [ ' subtitle_prefix ' ] )
sourceMediaDescriptor . importSubtitles ( context [ ' subtitle_directory ' ] , context [ ' subtitle_prefix ' ] )
fc = FfxController ( context , sourceMediaDescriptor )
fc = FfxController ( context , sourceMediaDescriptor )
# mappingTokens = fc.generateMetadataTokens()
# click.echo(f"Metadata Tokens: {mappingTokens}")
dispositionTokens = fc . generateDispositionTokens ( )
dispositionTokens = fc . generateDispositionTokens ( )
click . echo ( f " Disposition Tokens: { dispositionTokens } " )
click . echo ( f " Disposition Tokens: { dispositionTokens } " )
@ -329,18 +324,14 @@ def convert(ctx,
# Case pattern matching
# Case pattern matching
targetMediaDescriptor = currentPattern . getMediaDescriptor ( )
targetMediaDescriptor = currentPattern . getMediaDescriptor ( )
currentShowDescriptor = currentPattern . getShowDescriptor ( )
currentShowDescriptor = currentPattern . getShowDescriptor ( )
if context [ ' tmdb' ] :
if context [ ' use_ tmdb' ] :
tmdbEpisodeResult = tc . queryEpisode ( currentShowDescriptor . getId ( ) , mediaFileProperties . getSeason ( ) , mediaFileProperties . getEpisode ( ) )
tmdbEpisodeResult = tc . queryEpisode ( currentShowDescriptor . getId ( ) , mediaFileProperties . getSeason ( ) , mediaFileProperties . getEpisode ( ) )
# click.echo(f"{tmdbEpisodeResult}")
#print(type(tmdbEpisodeResult['name']))
#quit()
if tmdbEpisodeResult :
if tmdbEpisodeResult :
fileBasename = tc . getEpisodeFileBasename ( currentShowDescriptor . getFilenamePrefix ( ) ,
fileBasename = tc . getEpisodeFileBasename ( currentShowDescriptor . getFilenamePrefix ( ) ,
tmdbEpisodeResult [ ' name ' ] ,
tmdbEpisodeResult [ ' name ' ] ,
@ -350,8 +341,6 @@ def convert(ctx,
currentShowDescriptor . getIndexEpisodeDigits ( ) ,
currentShowDescriptor . getIndexEpisodeDigits ( ) ,
currentShowDescriptor . getIndicatorSeasonDigits ( ) ,
currentShowDescriptor . getIndicatorSeasonDigits ( ) ,
currentShowDescriptor . getIndicatorEpisodeDigits ( ) )
currentShowDescriptor . getIndicatorEpisodeDigits ( ) )
else :
else :
fileBasename = currentShowDescriptor . getFilenamePrefix ( )
fileBasename = currentShowDescriptor . getFilenamePrefix ( )
@ -360,7 +349,15 @@ def convert(ctx,
if context [ ' import_subtitles ' ] :
if context [ ' import_subtitles ' ] :
targetMediaDescriptor . importSubtitles ( context [ ' subtitle_directory ' ] , context [ ' subtitle_prefix ' ] )
targetMediaDescriptor . importSubtitles ( context [ ' subtitle_directory ' ] , context [ ' subtitle_prefix ' ] )
targetMediaDescriptor . setJellyfinOrder ( context [ ' jellyfin ' ] )
# raise click.ClickException(f"tmd subindices: {[t.getSubIndex() for t in targetMediaDescriptor.getAllTrackDescriptors()]}")
# click.echo(f"tmd subindices: {[t.getIndex() for t in targetMediaDescriptor.getAllTrackDescriptors()]} {[t.getSubIndex() for t in targetMediaDescriptor.getAllTrackDescriptors()]} {[t.getDispositionFlag(TrackDisposition.DEFAULT) for t in targetMediaDescriptor.getAllTrackDescriptors()]}")
if context [ ' use_jellyfin ' ] :
# Reorder subtracks in types with default the last, then make subindices flat again
targetMediaDescriptor . applyJellyfinOrder ( )
# click.echo(f"tmd subindices: {[t.getIndex() for t in targetMediaDescriptor.getAllTrackDescriptors()]} {[t.getSubIndex() for t in targetMediaDescriptor.getAllTrackDescriptors()]} {[t.getDispositionFlag(TrackDisposition.DEFAULT) for t in targetMediaDescriptor.getAllTrackDescriptors()]}")
# raise click.Abort
click . echo ( f " Input mapping tokens (2nd pass): { targetMediaDescriptor . getInputMappingTokens ( ) } " )
click . echo ( f " Input mapping tokens (2nd pass): { targetMediaDescriptor . getInputMappingTokens ( ) } " )
@ -385,9 +382,10 @@ def convert(ctx,
extra = [ ' ffx ' ] if sourceFilenameExtension == FfxController . DEFAULT_FILE_EXTENSION else [ ]
extra = [ ' ffx ' ] if sourceFilenameExtension == FfxController . DEFAULT_FILE_EXTENSION else [ ]
targetFilename = fileBasename if context [ ' tmdb ' ] else mediaFileProperties . assembleTargetFileBasename ( label if label else fileBasename ,
targetFilename = ( fileBasename if context [ ' use_tmdb ' ]
else mediaFileProperties . assembleTargetFileBasename ( label if label else fileBasename ,
q if len ( q_list ) > 1 else - 1 ,
q if len ( q_list ) > 1 else - 1 ,
extraTokens = extra )
extraTokens = extra ) )
targetPath = os . path . join ( output_directory if output_directory else sourceDirectory , targetFilename )
targetPath = os . path . join ( output_directory if output_directory else sourceDirectory , targetFilename )
@ -398,7 +396,7 @@ def convert(ctx,
preset ,
preset ,
denoise )
denoise )
# #click.confirm('Warning! This file is not compliant to the defined source schema! Do you want to continue?', abort=True)
#TODO: click.confirm('Warning! This file is not compliant to the defined source schema! Do you want to continue?', abort=True)
endTime = time . perf_counter ( )
endTime = time . perf_counter ( )
click . echo ( f " \n DONE \n Time elapsed { endTime - startTime } " )
click . echo ( f " \n DONE \n Time elapsed { endTime - startTime } " )