diff --git a/bin/ffx.py b/bin/ffx.py index f31a954..ea7e436 100755 --- a/bin/ffx.py +++ b/bin/ffx.py @@ -13,6 +13,7 @@ from ffx.database import databaseContext from ffx.track_type import TrackType from ffx.video_encoder import VideoEncoder +from ffx.track_disposition import TrackDisposition VERSION='0.1.2' @@ -160,6 +161,7 @@ def shows(ctx): @click.option("-t", "--no-tmdb", 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) @@ -191,6 +193,7 @@ def convert(ctx, denoise, no_tmdb, no_jellyfin, + no_pattern, dry_run): """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['jellyfin'] = not no_jellyfin - context['tmdb'] = not no_tmdb + context['use_jellyfin'] = not no_jellyfin + context['use_tmdb'] = not no_tmdb + context['use_pattern'] = not no_pattern context['import_subtitles'] = (subtitle_directory and subtitle_prefix) if context['import_subtitles']: @@ -242,7 +246,7 @@ def convert(ctx, 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] click.echo(f"\nRunning {len(existingSourcePaths) * len(q_list)} jobs") @@ -265,7 +269,7 @@ def convert(ctx, sourceMediaDescriptor = mediaFileProperties.getMediaDescriptor() #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'}") @@ -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. # The correct tokens should then be created by - try: - sourceMediaDescriptor.getDefaultVideoTrack() - except ValueError: + if len([v for v in sourceMediaDescriptor.getVideoTracks() if v.getDispositionFlag(TrackDisposition.DEFAULT)]) > 1: 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: + + if len([v for v in sourceMediaDescriptor.getVideoTracks() if v.getDispositionFlag(TrackDisposition.FORCED)]) > 1: 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: + + if len([a for a in sourceMediaDescriptor.getAudioTracks() if a.getDispositionFlag(TrackDisposition.DEFAULT)]) > 1: 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: + + if len([a for a in sourceMediaDescriptor.getAudioTracks() if a.getDispositionFlag(TrackDisposition.FORCED)]) > 1: 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: + + if len([s for s in sourceMediaDescriptor.getSubtitleTracks() if s.getDispositionFlag(TrackDisposition.DEFAULT)]) > 1: 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: + + if len([s for s in sourceMediaDescriptor.getSubtitleTracks() if s.getDispositionFlag(TrackDisposition.FORCED)]) > 1: forcedSubtitleTrackSubIndex = click.prompt("More than one forced subtitle stream detected! Please select stream", type=int) sourceMediaDescriptor.setForcedSubTrack(TrackType.SUBTITLE, forcedSubtitleTrackSubIndex) + if context['import_subtitles']: sourceMediaDescriptor.importSubtitles(context['subtitle_directory'], context['subtitle_prefix']) fc = FfxController(context, sourceMediaDescriptor) - - # mappingTokens = fc.generateMetadataTokens() - # click.echo(f"Metadata Tokens: {mappingTokens}") - + dispositionTokens = fc.generateDispositionTokens() click.echo(f"Disposition Tokens: {dispositionTokens}") @@ -329,18 +324,14 @@ def convert(ctx, # Case pattern matching targetMediaDescriptor = currentPattern.getMediaDescriptor() + currentShowDescriptor = currentPattern.getShowDescriptor() - if context['tmdb']: + if context['use_tmdb']: tmdbEpisodeResult = tc.queryEpisode(currentShowDescriptor.getId(), mediaFileProperties.getSeason(), mediaFileProperties.getEpisode()) - # click.echo(f"{tmdbEpisodeResult}") - - #print(type(tmdbEpisodeResult['name'])) - #quit() - if tmdbEpisodeResult: fileBasename = tc.getEpisodeFileBasename(currentShowDescriptor.getFilenamePrefix(), tmdbEpisodeResult['name'], @@ -349,9 +340,7 @@ def convert(ctx, currentShowDescriptor.getIndexSeasonDigits(), currentShowDescriptor.getIndexEpisodeDigits(), currentShowDescriptor.getIndicatorSeasonDigits(), - currentShowDescriptor.getIndicatorEpisodeDigits()) - - + currentShowDescriptor.getIndicatorEpisodeDigits()) else: fileBasename = currentShowDescriptor.getFilenamePrefix() @@ -359,8 +348,16 @@ def convert(ctx, if context['import_subtitles']: targetMediaDescriptor.importSubtitles(context['subtitle_directory'], context['subtitle_prefix']) + + # 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() - targetMediaDescriptor.setJellyfinOrder(context['jellyfin']) + # 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()}") @@ -385,9 +382,10 @@ def convert(ctx, extra = ['ffx'] if sourceFilenameExtension == FfxController.DEFAULT_FILE_EXTENSION else [] - targetFilename = fileBasename if context['tmdb'] else mediaFileProperties.assembleTargetFileBasename(label if label else fileBasename, - q if len(q_list) > 1 else -1, - extraTokens = extra) + targetFilename = (fileBasename if context['use_tmdb'] + else mediaFileProperties.assembleTargetFileBasename(label if label else fileBasename, + q if len(q_list) > 1 else -1, + extraTokens = extra)) targetPath = os.path.join(output_directory if output_directory else sourceDirectory, targetFilename) @@ -398,7 +396,7 @@ def convert(ctx, preset, 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() click.echo(f"\nDONE\nTime elapsed {endTime - startTime}") diff --git a/bin/ffx/ffx_controller.py b/bin/ffx/ffx_controller.py index 6db1b2e..3b4a56d 100644 --- a/bin/ffx/ffx_controller.py +++ b/bin/ffx/ffx_controller.py @@ -117,7 +117,8 @@ class FfxController(): audioTokens = [] #sourceAudioTrackDescriptors = [smd for smd in self.__sourceMediaDescriptor.getAllTrackDescriptors() if smd.getType() == TrackType.AUDIO] - targetAudioTrackDescriptors = [rtd for rtd in self.__targetMediaDescriptor.getReorderedTrackDescriptors() if rtd.getType() == TrackType.AUDIO] + # targetAudioTrackDescriptors = [rtd for rtd in self.__targetMediaDescriptor.getReorderedTrackDescriptors() if rtd.getType() == TrackType.AUDIO] + targetAudioTrackDescriptors = [td for td in self.__targetMediaDescriptor.getAllTrackDescriptors() if td.getType() == TrackType.AUDIO] trackSubIndex = 0 for trackDescriptor in targetAudioTrackDescriptors: @@ -166,29 +167,25 @@ class FfxController(): return audioTokens + # -disposition:s:0 default -disposition:s:1 0 def generateDispositionTokens(self): - """Source media descriptor is optional""" - - sourceTrackDescriptors = [] if self.__sourceMediaDescriptor is None else self.__sourceMediaDescriptor.getAllTrackDescriptors() - targetTrackDescriptors = self.__targetMediaDescriptor.getReorderedTrackDescriptors() + + # sourceTrackDescriptors = [] if self.__sourceMediaDescriptor is None else self.__sourceMediaDescriptor.getAllTrackDescriptors() + targetTrackDescriptors = self.__targetMediaDescriptor.getAllTrackDescriptors() dispositionTokens = [] + + # raise click.ClickException(f"ttd subindices: {[t.getSubIndex() for t in targetTrackDescriptors]}") - # for subStreamIndex in range(len(subDescriptor)): + #TODO: Sorting here is for the sole purpose to let the tokens appear with ascending subindices. Why necessary? Jellyfin order? + # for trackDescriptor in sorted(targetTrackDescriptors.copy(), key=lambda d: d.getSubIndex()): for trackDescriptor in targetTrackDescriptors: #HINT: No dispositions for pgs subtitle tracks that have no external file source if (trackDescriptor.getExternalSourceFilePath() or trackDescriptor.getCodec() != TrackDescriptor.CODEC_PGS): - # Calculate source sub index. This applies only if a source media descriptor is defined. - if sourceTrackDescriptors: - changedTargetTrackDescriptor : TrackDescriptor = targetTrackDescriptors[trackDescriptor.getIndex()] - changedTargetTrackSourceIndex = changedTargetTrackDescriptor.getSourceIndex() - subIndex = sourceTrackDescriptors[changedTargetTrackSourceIndex].getSubIndex() - else: - subIndex = trackDescriptor.getSubIndex() - + subIndex = trackDescriptor.getSubIndex() streamIndicator = trackDescriptor.getType().indicator() dispositionSet = trackDescriptor.getDispositionSet() @@ -358,37 +355,20 @@ class FfxController(): metadataTokens = [] for tagKey, tagValue in self.__targetMediaDescriptor.getTags().items(): - metadataTokens += [f"-metadata:g", f"{tagKey}={tagValue}"] + #HINT: With current ffmpeg version track metadata tags are not passed to the outfile + for td in self.__targetMediaDescriptor.getAllTrackDescriptors(): - #NOTE: With current version track metadata tags are not passed to the outfile - targetTrackDescriptors = self.__targetMediaDescriptor.getReorderedTrackDescriptors() - - - for d in targetTrackDescriptors: - - # changedTagValue = targetTrackDescriptors[changedTargetTrackSourceIndex].getTags()[changedTagKey] - # sourceSubIndex = sourceTrackDescriptors[changedTargetTrackSourceIndex].getSubIndex() - # addedTagValue = changedTrackDiff[MediaDescriptor.TAGS_KEY][DIFF_ADDED_KEY][addedTagKey] - - # click.echo(f"addedTagValue={addedTagValue}") - # click.echo(f"sourceTrackDescriptors: subindex={[s.getSubIndex() for s in sourceTrackDescriptors]} sourceindex={[s.getSourceIndex() for s in sourceTrackDescriptors]} tags={[s.getTags() for s in sourceTrackDescriptors]}") - # click.echo(f"targetTrackDescriptors: subindex={[t.getSubIndex() for t in targetTrackDescriptors]} sourceindex={[t.getSourceIndex() for t in targetTrackDescriptors]} tags={[t.getTags() for t in targetTrackDescriptors]}") - # click.echo(f"changed track_index={changedTrackIndex} indicator={changedTargetTrackDescriptor.getType().indicator()} key={addedTagKey} value={addedTagValue} source_index={changedSourceTrackIndex}") - for tagKey, tagValue in d.getTags().items(): + for tagKey, tagValue in td.getTags().items(): - metadataTokens += [f"-metadata:s:{d.getType().indicator()}:{d.getSubIndex()}", + metadataTokens += [f"-metadata:s:{td.getType().indicator()}:{td.getSubIndex()}", f"{tagKey}={tagValue}"] return metadataTokens - - - - def runJob(self, sourcePath, targetPath, diff --git a/bin/ffx/media_descriptor.py b/bin/ffx/media_descriptor.py index 747a813..ecc2962 100644 --- a/bin/ffx/media_descriptor.py +++ b/bin/ffx/media_descriptor.py @@ -61,15 +61,6 @@ class MediaDescriptor: else: self.__trackDescriptors = [] - if MediaDescriptor.CLEAR_TAGS_FLAG_KEY in kwargs.keys(): - if type(kwargs[MediaDescriptor.CLEAR_TAGS_FLAG_KEY]) is not bool: - raise TypeError( - f"MediaDescriptor.__init__(): Argument {MediaDescriptor.CLEAR_TAGS_FLAG_KEY} is required to be of type bool" - ) - self.__clearTags = kwargs[MediaDescriptor.CLEAR_TAGS_FLAG_KEY] - else: - self.__clearTags = False - if MediaDescriptor.JELLYFIN_ORDER_FLAG_KEY in kwargs.keys(): if type(kwargs[MediaDescriptor.JELLYFIN_ORDER_FLAG_KEY]) is not bool: raise TypeError( @@ -79,77 +70,6 @@ class MediaDescriptor: else: self.__jellyfinOrder = False - def getDefaultVideoTrack(self): - videoDefaultTracks = [ - v - for v in self.getVideoTracks() - if TrackDisposition.DEFAULT in v.getDispositionSet() - ] - if len(videoDefaultTracks) > 1: - raise ValueError( - "MediaDescriptor.getDefaultVideoTrack(): More than one default video track is not supported" - ) - return videoDefaultTracks[0] if videoDefaultTracks else None - - def getForcedVideoTrack(self): - videoForcedTracks = [ - v - for v in self.getVideoTracks() - if TrackDisposition.FORCED in v.getDispositionSet() - ] - if len(videoForcedTracks) > 1: - raise ValueError( - "MediaDescriptor.getForcedVideoTrack(): More than one forced video track is not supported" - ) - return videoForcedTracks[0] if videoForcedTracks else None - - def getDefaultAudioTrack(self): - audioDefaultTracks = [ - a - for a in self.getAudioTracks() - if TrackDisposition.DEFAULT in a.getDispositionSet() - ] - if len(audioDefaultTracks) > 1: - raise ValueError( - "MediaDescriptor.getDefaultAudioTrack(): More than one default audio track is not supported" - ) - return audioDefaultTracks[0] if audioDefaultTracks else None - - def getForcedAudioTrack(self): - audioForcedTracks = [ - a - for a in self.getAudioTracks() - if TrackDisposition.FORCED in a.getDispositionSet() - ] - if len(audioForcedTracks) > 1: - raise ValueError( - "MediaDescriptor.getForcedAudioTrack(): More than one forced audio track is not supported" - ) - return audioForcedTracks[0] if audioForcedTracks else None - - def getDefaultSubtitleTrack(self): - subtitleDefaultTracks = [ - s - for s in self.getSubtitleTracks() - if TrackDisposition.DEFAULT in s.getDispositionSet() - ] - if len(subtitleDefaultTracks) > 1: - raise ValueError( - "MediaDescriptor.getDefaultSubtitleTrack(): More than one default subtitle track is not supported" - ) - return subtitleDefaultTracks[0] if subtitleDefaultTracks else None - - def getForcedSubtitleTrack(self): - subtitleForcedTracks = [ - s - for s in self.getSubtitleTracks() - if TrackDisposition.FORCED in s.getDispositionSet() - ] - if len(subtitleForcedTracks) > 1: - raise ValueError( - "MediaDescriptor.getForcedSubtitleTrack(): More than one forced subtitle track is not supported" - ) - return subtitleForcedTracks[0] if subtitleForcedTracks else None def setDefaultSubTrack(self, trackType: TrackType, subIndex: int): for t in self.getAllTrackDescriptors(): @@ -166,7 +86,7 @@ class MediaDescriptor: ) - def checkDefaultAndForcedDispositions(self): + def checkConfiguration(self): videoTracks = self.getVideoTracks() audioTracks = self.getAudioTracks() @@ -193,42 +113,37 @@ class MediaDescriptor: if len(set(sourceIndices)) < len(trackDescriptors): raise ValueError('Multiple streams originating from the same source stream') - def getReorderedTrackDescriptors(self): - - - - reorderedTrackDescriptors = videoTracks + audioTracks + subtitleTracks - orderedSourceTrackSequence = [ - t.getSourceIndex() for t in reorderedTrackDescriptors - ] - - if len(set(orderedSourceTrackSequence)) < len(orderedSourceTrackSequence): - raise ValueError( - f"Multiple streams originating from the same source stream not supported" - ) - - return reorderedTrackDescriptors def applyJellyfinOrder(self): + """Reorder subtracks in types with default the last, then make subindices flat again""" # videoTracks = self.sortSubIndices(self.getVideoTracks()) # audioTracks = self.sortSubIndices(self.getAudioTracks()) # subtitleTracks = self.sortSubIndices(self.getSubtitleTracks()) + self.checkConfiguration() + + # from self.__trackDescriptors videoTracks = self.getVideoTracks() audioTracks = self.getAudioTracks() subtitleTracks = self.getSubtitleTracks() - - if len([v for v in videoTracks if v.getDispositionFlag(TrackDisposition.DEFAULT)]) > 1: - pass - if len([a for a in audioTracks if a.getDispositionFlag(TrackDisposition.DEFAULT)]) > 1: - pass - if len([s for s in subtitleTracks if s.getDispositionFlag(TrackDisposition.DEFAULT)]): - pass - videoTracks.append(videoTracks.pop(videoTracks.index(videoTracks))) - audioTracks.append(audioTracks.pop(audioTracks.index(audioTracks))) - subtitleTracks.append(subtitleTracks.pop(subtitleTracks.index(subtitleTracks))) + defaultVideoTracks = [v for v in videoTracks if v.getDispositionFlag(TrackDisposition.DEFAULT)] + defaultAudioTracks = [a for a in audioTracks if a.getDispositionFlag(TrackDisposition.DEFAULT)] + defaultSubtitleTracks = [s for s in subtitleTracks if s.getDispositionFlag(TrackDisposition.DEFAULT)] + + if defaultVideoTracks: + videoTracks.append(videoTracks.pop(videoTracks.index(defaultVideoTracks[0]))) + self.sortSubIndices(videoTracks) + if defaultAudioTracks: + audioTracks.append(audioTracks.pop(audioTracks.index(defaultAudioTracks[0]))) + self.sortSubIndices(audioTracks) + if defaultSubtitleTracks: + subtitleTracks.append(subtitleTracks.pop(subtitleTracks.index(defaultSubtitleTracks[0]))) + self.sortSubIndices(subtitleTracks) + + self.__trackDescriptors = videoTracks + audioTracks + subtitleTracks + self.sortIndices(self.__trackDescriptors) @classmethod @@ -268,43 +183,46 @@ class MediaDescriptor: def getTags(self): return self.__mediaTags + def sortSubIndices( self, descriptors: List[TrackDescriptor] ) -> List[TrackDescriptor]: subIndex = 0 - for t in descriptors: - t.setSubIndex(subIndex) + for d in descriptors: + d.setSubIndex(subIndex) subIndex += 1 return descriptors + def sortIndices( + self, descriptors: List[TrackDescriptor] + ) -> List[TrackDescriptor]: + index = 0 + for d in descriptors: + d.setIndex(index) + index += 1 + return descriptors + + def getAllTrackDescriptors(self) -> List[TrackDescriptor]: return self.getVideoTracks() + self.getAudioTracks() + self.getSubtitleTracks() def getVideoTracks(self) -> List[TrackDescriptor]: return [ - v for v in self.__trackDescriptors.copy() if v.getType() == TrackType.VIDEO + v for v in self.__trackDescriptors if v.getType() == TrackType.VIDEO ] def getAudioTracks(self) -> List[TrackDescriptor]: return [ - a for a in self.__trackDescriptors.copy() if a.getType() == TrackType.AUDIO + a for a in self.__trackDescriptors if a.getType() == TrackType.AUDIO ] def getSubtitleTracks(self) -> List[TrackDescriptor]: return [ s - for s in self.__trackDescriptors.copy() + for s in self.__trackDescriptors if s.getType() == TrackType.SUBTITLE ] - # def getJellyfin(self): - # return self.__jellyfinOrder -# - # def setJellyfinOrder(self, state): - # self.__jellyfinOrder = state - - def getClearTags(self): - return self.__clearTags def compare(self, vsMediaDescriptor: Self): @@ -315,6 +233,10 @@ class MediaDescriptor: vsTags = vsMediaDescriptor.getTags() tags = self.getTags() + + # tags ist leer + # click.echo(f"tags={tags} vsTags={vsTags}") + # raise click.Abort # HINT: Some tags differ per file, for example creation_time, so these are removed before diff for emt in MediaDescriptor.EXCLUDED_MEDIA_TAGS: @@ -332,7 +254,7 @@ class MediaDescriptor: # Target track configuration (from DB) # tracks = self.getAllTrackDescriptors() - tracks = self.getReorderedTrackDescriptors() + tracks = self.getAllTrackDescriptors() # filtern numTracks = len(tracks) # Current track configuration (of file) @@ -386,12 +308,13 @@ class MediaDescriptor: def getImportFileTokens(self, use_sub_index: bool = True): - reorderedTrackDescriptors = self.getReorderedTrackDescriptors() + # reorderedTrackDescriptors = self.getReorderedTrackDescriptors() importFileTokens = [] - for rtd in reorderedTrackDescriptors: + #for rtd in reorderedTrackDescriptors: + for td in self.__trackDescriptors: - importedFilePath = rtd.getExternalSourceFilePath() + importedFilePath = td.getExternalSourceFilePath() if importedFilePath: importFileTokens += [ @@ -403,17 +326,18 @@ class MediaDescriptor: def getInputMappingTokens(self, use_sub_index: bool = True, only_video: bool = False): - reorderedTrackDescriptors = self.getReorderedTrackDescriptors() + # reorderedTrackDescriptors = self.getReorderedTrackDescriptors() inputMappingTokens = [] filePointer = 1 - for rtd in reorderedTrackDescriptors: + #for rtd in reorderedTrackDescriptors: + for td in self.__trackDescriptors: - trackType = rtd.getType() + trackType = td.getType() if (trackType == TrackType.VIDEO or not only_video): - importedFilePath = rtd.getExternalSourceFilePath() + importedFilePath = td.getExternalSourceFilePath() if use_sub_index: @@ -427,15 +351,15 @@ class MediaDescriptor: else: - if rtd.getCodec() != TrackDescriptor.CODEC_PGS: + if td.getCodec() != TrackDescriptor.CODEC_PGS: inputMappingTokens += [ "-map", - f"0:{trackType.indicator()}:{rtd.getSubIndex()}", + f"0:{trackType.indicator()}:{td.getSubIndex()}", ] else: - if rtd.getCodec() != TrackDescriptor.CODEC_PGS: - inputMappingTokens += ["-map", f"0:{rtd.getIndex()}"] + if td.getCodec() != TrackDescriptor.CODEC_PGS: + inputMappingTokens += ["-map", f"0:{td.getIndex()}"] return inputMappingTokens diff --git a/bin/ffx/media_details_screen.py b/bin/ffx/media_details_screen.py index 4b47a91..3858c54 100644 --- a/bin/ffx/media_details_screen.py +++ b/bin/ffx/media_details_screen.py @@ -156,6 +156,7 @@ class MediaDetailsScreen(Screen): #HINT: This is None if the filename did not match anything in database self.__currentPattern = self.__mediaFileProperties.getPattern() + # keine tags vorhanden self.__targetMediaDescriptor = self.__currentPattern.getMediaDescriptor() if self.__currentPattern is not None else None # Enumerating differences between media descriptors @@ -506,13 +507,18 @@ class MediaDetailsScreen(Screen): self.highlightPattern(False) + for tagKey, tagValue in self.__currentMediaDescriptor.getTags().items(): + self.__tac.updateMediaTag(patternId, tagKey, tagValue) + for trackDescriptor in self.__currentMediaDescriptor.getAllTrackDescriptors(): self.__tc.addTrack(trackDescriptor, patternId = patternId) def action_new_pattern(self): - if not self.__currentMediaDescriptor.checkDefaultAndForcedDispositions(): + try: + self.__currentMediaDescriptor.checkConfiguration() + except ValueError: return selectedShowDescriptor = self.getSelectedShowDescriptor() diff --git a/bin/ffx/model/pattern.py b/bin/ffx/model/pattern.py index e1bdb0e..2d1adbc 100644 --- a/bin/ffx/model/pattern.py +++ b/bin/ffx/model/pattern.py @@ -62,7 +62,13 @@ class Pattern(Base): kwargs[MediaDescriptor.TRACK_DESCRIPTOR_LIST_KEY] = [] + # Set ordered subindices + subIndexCounter = {} for track in self.tracks: - kwargs[MediaDescriptor.TRACK_DESCRIPTOR_LIST_KEY].append(track.getDescriptor()) + trackType = track.getType() + if not trackType in subIndexCounter.keys(): + subIndexCounter[trackType] = 0 + kwargs[MediaDescriptor.TRACK_DESCRIPTOR_LIST_KEY].append(track.getDescriptor(subIndex = subIndexCounter[trackType])) + subIndexCounter[trackType] += 1 return MediaDescriptor(**kwargs) diff --git a/bin/ffx/track_descriptor.py b/bin/ffx/track_descriptor.py index fda5c4a..4d83f12 100644 --- a/bin/ffx/track_descriptor.py +++ b/bin/ffx/track_descriptor.py @@ -241,6 +241,9 @@ class TrackDescriptor: def getIndex(self): return self.__index + def setIndex(self, index): + self.__index = index + def getSourceIndex(self): return self.__sourceIndex