@ -8,6 +8,8 @@ from ffx.ffx_app import FfxApp
from ffx . ffx_controller import FfxController
from ffx . ffx_controller import FfxController
from ffx . database import databaseContext
from ffx . database import databaseContext
from ffx . track_type import TrackType
VERSION = ' 0.1.0 '
VERSION = ' 0.1.0 '
@ -207,53 +209,35 @@ def convert(ctx,
context [ ' bitrates ' ] [ ' stereo ' ] = str ( stereo_bitrate ) if str ( stereo_bitrate ) . endswith ( ' k ' ) else f " { stereo_bitrate } k "
context [ ' bitrates ' ] [ ' stereo ' ] = str ( stereo_bitrate ) if str ( stereo_bitrate ) . endswith ( ' k ' ) else f " { stereo_bitrate } k "
context [ ' bitrates ' ] [ ' ac3 ' ] = str ( ac3_bitrate ) if str ( ac3_bitrate ) . endswith ( ' k ' ) else f " { ac3_bitrate } k "
context [ ' bitrates ' ] [ ' ac3 ' ] = str ( ac3_bitrate ) if str ( ac3_bitrate ) . endswith ( ' k ' ) else f " { ac3_bitrate } k "
context [ ' bitrates ' ] [ ' dts ' ] = str ( dts_bitrate ) if str ( dts_bitrate ) . endswith ( ' k ' ) else f " { dts_bitrate } k "
context [ ' bitrates ' ] [ ' dts ' ] = str ( dts_bitrate ) if str ( dts_bitrate ) . endswith ( ' k ' ) else f " { dts_bitrate } k "
#
# click.echo(f"Stereo bitrate: {context['bitrates']['stereo']}")
click . echo ( f " Stereo bitrate: { context [ ' bitrates ' ] [ ' stereo ' ] } " )
# click.echo(f"AC3 bitrate: {context['bitrates']['ac3']}")
click . echo ( f " AC3 bitrate: { context [ ' bitrates ' ] [ ' ac3 ' ] } " )
# click.echo(f"DTS bitrate: {context['bitrates']['dts']}")
click . echo ( f " DTS bitrate: { context [ ' bitrates ' ] [ ' dts ' ] } " )
#
#
#
# Process crop parameters
context [ ' perform_crop ' ] = ( crop != ' none ' )
if context [ ' perform_crop ' ] :
cTokens = crop . split ( ' , ' )
if cTokens and len ( cTokens ) == 2 :
cropStart = int ( cTokens [ 0 ] )
cropLength = int ( cTokens [ 1 ] )
cropTokens = FfxController . generateCropTokens ( cropStart , cropLength )
else :
cropTokens = FfxController . generateCropTokens ( )
else :
cropTokens = [ ]
click . echo ( f " Crop tokens= { cropTokens } " )
# ## Conversion parameters
# ## Conversion parameters
#
#
# # Parse subtitle files
# # Parse subtitle files
# context['import_subtitles'] = (subtitle_directory and subtitle_prefix)
# context['import_subtitles'] = (subtitle_directory and subtitle_prefix)
# availableFileSubtitleDescriptors = searchSubtitleFiles(subtitle_directory, subtitle_prefix) if context['import_subtitles'] else []
# availableFileSubtitleDescriptors = searchSubtitleFiles(subtitle_directory, subtitle_prefix) if context['import_subtitles'] else []
#
#
# # Overwrite audio tags if set
# audioLanguages = audio_language
# audioTitles = audio_title
#
# # Overwrite subtitle tags if set
# subtitleLanguages = subtitle_language
# subtitleTitles = subtitle_title
#
# defaultAudio = default_audio
# defaultSubtitle = default_subtitle
# forcedAudio = forced_audio
# forcedSubtitle = forced_subtitle
#
#
# # Process crop parameters
# context['perform_crop'] = (crop != 'none')
# if context['perform_crop']:
# cTokens = crop.split(',')
# if cTokens and len(cTokens) == 2:
# cropStart, cropLength = crop.split(',')
# else:
# cropStart = FfxController.DEFAULT_CROP_START
# cropLength = FfxController.DEFAULT_CROP_LENGTH
#
# click.echo(f"crop start={cropStart} length={cropLength}")
#
# cropTokens = generateCropTokens(int(cropStart), int(cropLength))
# else:
# cropTokens = []
#
#
# job_index = 0
#
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 " )
@ -267,27 +251,74 @@ def convert(ctx,
sourceFileBasename = ' . ' . join ( sourcePathTokens [ : - 1 ] )
sourceFileBasename = ' . ' . join ( sourcePathTokens [ : - 1 ] )
sourceFilenameExtension = sourcePathTokens [ - 1 ]
sourceFilenameExtension = sourcePathTokens [ - 1 ]
click . echo ( f " \n Processing file { sourcePath } " )
click . echo ( f " \n Processing file { sourcePath } " )
mediaFileProperties = FileProperties ( context , sourceFilename )
mediaFileProperties = FileProperties ( context , sourceFilename )
current MediaDescriptor = mediaFileProperties . getMediaDescriptor ( )
source MediaDescriptor = 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 ( )
targetMediaDescriptor = currentPattern . getMediaDescriptor ( ) if currentPattern is not None 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 ' } " )
if not currentPattern is None :
if currentPattern is None :
# Case no pattern matching
# Check for multiple default or forced dispositions if not set by user input or database requirements
#
# 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
try :
sourceMediaDescriptor . getDefaultVideoTrack ( )
except ValueError :
defaultVideoTrackSubIndex = click . prompt ( " More than one default video stream detected! Please select stream " , type = int )
sourceMediaDescriptor . setDefaultSubTrack ( TrackType . VIDEO , defaultVideoTrackSubIndex )
try :
sourceMediaDescriptor . getForcedVideoTrack ( )
except ValueError :
forcedVideoTrackSubIndex = click . prompt ( " More than one forced video stream detected! Please select stream " , type = int )
sourceMediaDescriptor . setForcedSubTrack ( TrackType . VIDEO , forcedVideoTrackSubIndex )
try :
sourceMediaDescriptor . getDefaultAudioTrack ( )
except ValueError :
defaultAudioTrackSubIndex = click . prompt ( " More than one default audio stream detected! Please select stream " , type = int )
sourceMediaDescriptor . setDefaultSubTrack ( TrackType . AUDIO , defaultAudioTrackSubIndex )
try :
sourceMediaDescriptor . getForcedAudioTrack ( )
except ValueError :
forcedAudioTrackSubIndex = click . prompt ( " More than one forced audio stream detected! Please select stream " , type = int )
sourceMediaDescriptor . setForcedSubTrack ( TrackType . AUDIO , forcedAudioTrackSubIndex )
try :
sourceMediaDescriptor . getDefaultSubtitleTrack ( )
except ValueError :
defaultSubtitleTrackSubIndex = click . prompt ( " More than one default subtitle stream detected! Please select stream " , type = int )
sourceMediaDescriptor . setDefaultSubTrack ( TrackType . SUBTITLE , defaultSubtitleTrackSubIndex )
try :
sourceMediaDescriptor . getForcedSubtitleTrack ( )
except ValueError :
forcedSubtitleTrackSubIndex = click . prompt ( " More than one forced subtitle stream detected! Please select stream " , type = int )
sourceMediaDescriptor . setForcedSubTrack ( TrackType . SUBTITLE , forcedSubtitleTrackSubIndex )
fc = FfxController ( context , sourceMediaDescriptor )
dispositionTokens = fc . generateDispositionTokens ( )
click . echo ( f " Disposition Tokens: { dispositionTokens } " )
else :
# Case pattern matching
targetMediaDescriptor = currentPattern . getMediaDescriptor ( ) if currentPattern is not None else None
targetMediaDescriptor . setJellyfinOrder ( context [ ' jellyfin ' ] )
targetMediaDescriptor . setJellyfinOrder ( context [ ' jellyfin ' ] )
click . echo ( f " Input mapping tokens: { targetMediaDescriptor . getInputMappingTokens ( ) } " )
click . echo ( f " Input mapping tokens: { targetMediaDescriptor . getInputMappingTokens ( ) } " )
fc = FfxController ( context , currentMediaDescriptor , targetMediaDescriptor )
fc = FfxController ( context , targetMediaDescriptor, source MediaDescriptor)
mappingTokens = fc . generateMetadataTokens ( )
mappingTokens = fc . generateMetadataTokens ( )
click . echo ( f " Metadata Tokens: { mappingTokens } " )
click . echo ( f " Metadata Tokens: { mappingTokens } " )
@ -300,26 +331,7 @@ def convert(ctx,
click . echo ( f " Season= { mediaFileProperties . getSeason ( ) } Episode= { mediaFileProperties . getEpisode ( ) } " )
click . echo ( f " Season= { mediaFileProperties . getSeason ( ) } Episode= { mediaFileProperties . getEpisode ( ) } " )
# # Determine season and episode if present in current filename
# season_digits = 2
# episode_digits = 2
# index_digits = 3
#
# se_result = se_match.search(sourceFilename)
# e_result = e_match.search(sourceFilename)
#
# season = -1
# episode = -1
# file_index = 0
#
# if se_result is not None:
# season = int(se_result.group(1))
# episode = int(se_result.group(2))
# elif e_result is not None:
# episode = int(e_result.group(1))
# else:
# file_index += 1
#
# matchingFileSubtitleDescriptors = sorted([d for d in availableFileSubtitleDescriptors if d['season'] == season and d['episode'] == episode], key=lambda d: d['stream']) if availableFileSubtitleDescriptors else []
# matchingFileSubtitleDescriptors = sorted([d for d in availableFileSubtitleDescriptors if d['season'] == season and d['episode'] == episode], key=lambda d: d['stream']) if availableFileSubtitleDescriptors else []
#
#
# print(f"season={season} episode={episode} file={file_index}")
# print(f"season={season} episode={episode} file={file_index}")
@ -359,212 +371,9 @@ def convert(ctx,
# ## ## ##
# ## ## ##
# targetStreamDescriptor = sourceStreamDescriptor.copy()
# targetStreamDescriptor = sourceStreamDescriptor.copy()
# ## ## ##
# ## ## ##
#
#
# click.echo('\nSource streams:')
# for aStream in sourceStreamDescriptor[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']}")
# for sStream in sourceStreamDescriptor[STREAM_TYPE_SUBTITLE]:
# click.echo(f"subtitle stream {sStream['sub_index']} lang={sStream['tags']['language']} title={sStream['tags']['title']} default={sStream['disposition']['default']} forced={sStream['disposition']['forced']}")
#
#
# # Check for multiple default or forced dispositions if not set by user input or database requirements
# #NOTE: It is currently expected that all source file have the same substream pattern, e.g. coming from the same encoder
# numDefaultAudioStreams = len([a for a in sourceStreamDescriptor[STREAM_TYPE_AUDIO] if a['disposition']['default'] == 1])
# if defaultAudio == -1 and numDefaultAudioStreams > 1:
# defaultAudio = click.prompt("More than one default audio stream detected! Please select stream", type=int)
#
# numForcedAudioStreams = len([a for a in sourceStreamDescriptor[STREAM_TYPE_AUDIO] if a['disposition']['forced'] == 1])
# if forcedAudio == -1 and numForcedAudioStreams > 1:
# forcedAudio = click.prompt("More than one forced audio stream detected! Please select stream", type=int)
#
# numDefaultSubtitleStreams = len([s for s in sourceStreamDescriptor[STREAM_TYPE_SUBTITLE] if s['disposition']['default'] == 1])
# if defaultSubtitle == -1 and numDefaultSubtitleStreams > 1:
# defaultSubtitle = click.prompt("More than one default subtitle stream detected! Please select stream", type=int)
#
# numForcedSubtitleStreams = len([s for s in sourceStreamDescriptor[STREAM_TYPE_SUBTITLE] if s['disposition']['forced'] == 1])
# if forcedSubtitle == -1 and numForcedSubtitleStreams > 1:
# forcedSubtitle = click.prompt("More than one forced subtitle stream detected! Please select stream", type=int)
#
# #Define default/forced tags
# if defaultAudio != -1:
# for substreamIndex in range(len(targetStreamDescriptor[STREAM_TYPE_AUDIO])):
# targetStreamDescriptor[STREAM_TYPE_AUDIO][substreamIndex]['disposition']['default'] = 1 if substreamIndex == defaultAudio else 0
# if forcedAudio != -1:
# for substreamIndex in range(len(targetStreamDescriptor[STREAM_TYPE_AUDIO])):
# targetStreamDescriptor[STREAM_TYPE_AUDIO][substreamIndex]['disposition']['forced'] = 1 if substreamIndex == forcedAudio else 0
# if defaultSubtitle != -1:
# for substreamIndex in range(len(targetStreamDescriptor[STREAM_TYPE_SUBTITLE])):
# targetStreamDescriptor[STREAM_TYPE_SUBTITLE][substreamIndex]['disposition']['default'] = 1 if substreamIndex == defaultSubtitle else 0
# if forcedSubtitle != -1:
# for substreamIndex in range(len(targetStreamDescriptor[STREAM_TYPE_SUBTITLE])):
# targetStreamDescriptor[STREAM_TYPE_SUBTITLE][substreamIndex]['disposition']['forced'] = 1 if substreamIndex == forcedSubtitle else 0
#
#
# # Set language and title in source stream descriptors if given per command line option
# for streamIndex in range(len(targetStreamDescriptor[STREAM_TYPE_AUDIO])):
# if streamIndex <= len(audioLanguages) - 1:
# targetStreamDescriptor[STREAM_TYPE_AUDIO][streamIndex]['tags']['language'] = audioLanguages[streamIndex]
# if streamIndex <= len(audioTitles) - 1:
# targetStreamDescriptor[STREAM_TYPE_AUDIO][streamIndex]['tags']['title'] = audioTitles[streamIndex]
#
# for streamIndex in range(len(targetStreamDescriptor[STREAM_TYPE_SUBTITLE])):
# if streamIndex <= len(subtitleLanguages) - 1:
# targetStreamDescriptor[STREAM_TYPE_SUBTITLE][streamIndex]['tags']['language'] = subtitleLanguages[streamIndex]
# if streamIndex <= len(subtitleTitles) - 1:
# targetStreamDescriptor[STREAM_TYPE_SUBTITLE][streamIndex]['tags']['title'] = subtitleTitles[streamIndex]
#
#
# click.echo('\nTarget streams:')
# 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']}")
# for sStream in targetStreamDescriptor[STREAM_TYPE_SUBTITLE]:
# click.echo(f"subtitle stream {sStream['sub_index']} lang={sStream['tags']['language']} title={sStream['tags']['title']} default={sStream['disposition']['default']} forced={sStream['disposition']['forced']}")
#
#
# numSourceAudioSubStreams = len(sourceStreamDescriptor[STREAM_TYPE_AUDIO])
# numSourceSubtitleSubStreams = len(sourceStreamDescriptor[STREAM_TYPE_SUBTITLE])
#
# # Stream order is just a list of integer
# audioStreamSourceOrder = list(range(numSourceAudioSubStreams))
# subtitleStreamSourceOrder = list(range(numSourceSubtitleSubStreams))
#
#
# # In order for the jellyfin media web UI to work properly the default/forced stream has to be the last in the sequence
# if jellyfin:
#
# defaultTargetAudioStreams = [a for a in targetStreamDescriptor[STREAM_TYPE_AUDIO] if a['disposition']['default'] == 1]
# if defaultTargetAudioStreams:
# audioStreamSourceOrder = getModifiedStreamOrder(len(sourceStreamDescriptor[STREAM_TYPE_AUDIO]), defaultTargetAudioStreams[0]['sub_index'])
#
# defaultTargetSubtitleStreams = [a for a in targetStreamDescriptor[STREAM_TYPE_SUBTITLE] if a['disposition']['default'] == 1]
# if defaultTargetSubtitleStreams:
# subtitleStreamSourceOrder = getModifiedStreamOrder(len(sourceStreamDescriptor[STREAM_TYPE_SUBTITLE]), defaultTargetSubtitleStreams[0]['sub_index'])
#
#
# # audioDispositionTokens = generateDispositionTokens(targetStreamDescriptor[STREAM_TYPE_AUDIO])
# # subtitleDispositionTokens = generateDispositionTokens(targetStreamDescriptor[STREAM_TYPE_SUBTITLE])
#
# audioDispositionTokens = generateDispositionTokens(targetStreamDescriptor[STREAM_TYPE_AUDIO], modifyOrder = audioStreamSourceOrder)
# subtitleDispositionTokens = generateDispositionTokens(targetStreamDescriptor[STREAM_TYPE_SUBTITLE], modifyOrder = subtitleStreamSourceOrder)
#
#
#
# mappingVideoTokens = ['-map', '0:v:0']
# mappingTokens = mappingVideoTokens.copy()
#
# dispositionTokens = []
#
# audioEncodingTokens = []
#
#
# audioMetadataTokens = []
# for audioStreamIndex in range(len(targetStreamDescriptor[STREAM_TYPE_AUDIO])):
#
# # Modify selected source audio stream for jellyfin if required
# sourceAudioStreamIndex = audioStreamSourceOrder[audioStreamIndex]
#
# # Add audio mapping tokens to list of general mapping tokens
# mappingTokens += ['-map', f"0:a:{sourceAudioStreamIndex}"]
#
#
# targetAudioStream = targetStreamDescriptor[STREAM_TYPE_AUDIO][audioStreamIndex]
#
# # audioEncodingTokens += generateAudioEncodingTokens(context, sourceAudioStream['src_sub_index'], sourceAudioStream['layout'])
# audioEncodingTokens += generateAudioEncodingTokens(context, audioStreamIndex, targetAudioStream['audio_layout'])
#
# if sourceStreamDescriptor[STREAM_TYPE_AUDIO][sourceAudioStreamIndex]['tags']['language'] != targetStreamDescriptor[STREAM_TYPE_AUDIO][audioStreamIndex]['tags']['language']:
# audioMetadataTokens += [f"-metadata:s:a:{audioStreamIndex}", f"language={targetStreamDescriptor[STREAM_TYPE_AUDIO][sourceAudioStreamIndex]['tags']['language']}"]
#
# if sourceStreamDescriptor[STREAM_TYPE_AUDIO][sourceAudioStreamIndex]['tags']['title'] != targetStreamDescriptor[STREAM_TYPE_AUDIO][audioStreamIndex]['tags']['title']:
# audioMetadataTokens += [f"-metadata:s:a:{audioStreamIndex}", f"title={targetStreamDescriptor[STREAM_TYPE_AUDIO][sourceAudioStreamIndex]['tags']['title']}"]
#
# # targetStreamDescriptor[STREAM_TYPE_AUDIO][audioStreamIndex]['disposition']['default'] = 1 if streamIndex == defaultAudio else 0
#
#
# subtitleImportFileTokens = []
# subtitleMetadataTokens = []
#
# if context['import_subtitles'] and numSourceSubtitleSubStreams != len(matchingFileSubtitleDescriptors):
# click.echo(f"The number of subtitle streams found in file with path {sourcePath} is different from the number of subtitle streams provided by matching imported files, skipping ...")
# continue
#
# # 0: Quelle f1 = forced
# # 1: QUelle f2 = full
#
# for subtitleStreamIndex in range(len(targetStreamDescriptor[STREAM_TYPE_SUBTITLE])):
#
# # Modify selected source subtitle stream for jellyfin if required
# sourceSubtitleStreamIndex = subtitleStreamSourceOrder[subtitleStreamIndex]
#
#
# if context['import_subtitles']:
#
# fileSubtitleDescriptor = matchingFileSubtitleDescriptors[subtitleStreamIndex] # original order
#
# subtitleImportFileTokens += ['-i', fileSubtitleDescriptor['path']] # original order
#
# # Create mapping for subtitle streams when imported from files
# mappingTokens += ['-map', f"{sourceSubtitleStreamIndex+1}:s:0"] # modified order
#
#
# if fileSubtitleDescriptor['language'] != targetStreamDescriptor[STREAM_TYPE_SUBTITLE][subtitleStreamIndex]['tags']['language']:
# subtitleMetadataTokens += [f"-metadata:s:s:{sourceSubtitleStreamIndex}", f"language={targetStreamDescriptor[STREAM_TYPE_SUBTITLE][subtitleStreamIndex]['tags']['language']}"]
#
# subtitleMetadataTokens += [f"-metadata:s:s:{sourceSubtitleStreamIndex}", f"title={targetStreamDescriptor[STREAM_TYPE_SUBTITLE][subtitleStreamIndex]['tags']['title']}"]
#
# else:
#
# # Add subtitle mapping tokens to list of general mapping tokens
# mappingTokens += ['-map', f"0:s:{sourceSubtitleStreamIndex}"]
#
# if sourceStreamDescriptor[STREAM_TYPE_SUBTITLE][sourceSubtitleStreamIndex]['tags']['language'] != targetStreamDescriptor[STREAM_TYPE_SUBTITLE][subtitleStreamIndex]['tags']['language']:
# subtitleMetadataTokens += [f"-metadata:s:s:{subtitleStreamIndex}", f"language={targetStreamDescriptor[STREAM_TYPE_SUBTITLE][subtitleStreamIndex]['tags']['language']}"]
#
# if sourceStreamDescriptor[STREAM_TYPE_SUBTITLE][sourceSubtitleStreamIndex]['tags']['title'] != targetStreamDescriptor[STREAM_TYPE_SUBTITLE][subtitleStreamIndex]['tags']['title']:
# subtitleMetadataTokens += [f"-metadata:s:s:{subtitleStreamIndex}", f"title={targetStreamDescriptor[STREAM_TYPE_SUBTITLE][subtitleStreamIndex]['tags']['title']}"]
#
#
#
#
#
#
# # # 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
# #
# # 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)
# #
#
#
#
#
#
# click.echo(f"Audio stream source order {audioStreamSourceOrder}")
# click.echo(f"Subtitle stream source order {subtitleStreamSourceOrder}")
#
#
# commandTokens = COMMAND_TOKENS + ['-i', sourcePath]
# commandTokens = COMMAND_TOKENS + ['-i', sourcePath]
#
#
#
#
@ -755,9 +564,5 @@ def convert(ctx,
click . echo ( f " Time elapsed { endTime - startTime } " )
click . echo ( f " Time elapsed { endTime - startTime } " )
# click.echo(f"app result: {app.getContext()}")
if __name__ == ' __main__ ' :
if __name__ == ' __main__ ' :
ffx ( )
ffx ( )