diff --git a/bin/ffx.py b/bin/ffx.py index 4499560..d1d5f7b 100755 --- a/bin/ffx.py +++ b/bin/ffx.py @@ -6,9 +6,13 @@ from ffx.file_properties import FileProperties from ffx.ffx_app import FfxApp from ffx.ffx_controller import FfxController +from ffx.show_controller import ShowController +from ffx.tmdb_controller import TmdbController + from ffx.database import databaseContext from ffx.track_type import TrackType +from ffx.video_encoder import VideoEncoder VERSION='0.1.0' @@ -194,7 +198,9 @@ def convert(ctx, context = ctx.obj - context['dry_run'] = dry_run + context['dry_run'] = True # dry_run + + context['video_encoder'] = VideoEncoder.fromLabel(video_encoder) context['jellyfin'] = jellyfin context['tmdb'] = tmdb @@ -209,8 +215,8 @@ def convert(ctx, qualityTokens = quality.split(',') q_list = [q for q in qualityTokens if q.isnumeric()] -# click.echo(f"Qualities: {q_list}") -# + click.echo(f"Qualities: {q_list}") + context['bitrates'] = {} 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" @@ -236,7 +242,8 @@ def convert(ctx, # # Parse subtitle files # # availableFileSubtitleDescriptors = searchSubtitleFiles(subtitle_directory, subtitle_prefix) if context['import_subtitles'] else [] - +# sc = ShowController(context) + tc = TmdbController() 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") @@ -316,12 +323,32 @@ def convert(ctx, audioTokens = fc.generateAudioEncodingTokens() click.echo(f"Audio Tokens: {audioTokens}") + + tmdbFileBasename = '' else: # Case pattern matching - targetMediaDescriptor = currentPattern.getMediaDescriptor() if currentPattern is not None else None + targetMediaDescriptor = currentPattern.getMediaDescriptor() + currentShowDescriptor = currentPattern.getShowDescriptor() + + label = currentShowDescriptor.getFilenamePrefix() + + tmdbResult = tc.queryTmdb(currentShowDescriptor.getId(), mediaFileProperties.getSeason(), mediaFileProperties.getEpisode()) + + # click.echo(f"{tmdbResult}") + + tmdbFileBasename = tc.getEpisodeFileBasename(currentShowDescriptor.getFilenamePrefix(), + tmdbResult['name'], + mediaFileProperties.getSeason(), + mediaFileProperties.getEpisode(), + currentShowDescriptor.getIndexSeasonDigits(), + currentShowDescriptor.getIndexEpisodeDigits(), + currentShowDescriptor.getIndicatorSeasonDigits(), + currentShowDescriptor.getIndicatorEpisodeDigits()) + + click.echo(f"tmdbFileBasename={tmdbFileBasename}") if context['import_subtitles']: targetMediaDescriptor.importSubtitles(context['subtitle_directory'], context['subtitle_prefix']) @@ -349,7 +376,15 @@ def convert(ctx, click.echo(f"\nRunning job {jobIndex} file={sourcePath} q={q}") jobIndex += 1 - + targetFilename = tmdbFileBasename if tmdbFileBasename else mediaFileProperties.assembleTargetFilename(label, q if len(q_list) > 1 else -1) + targetPath = os.path.join(sourceDirectory, targetFilename) + + fc.runJob(sourcePath, + targetPath, + context['video_encoder'], + q) + + # #click.confirm('Warning! This file is not compliant to the defined source schema! Do you want to continue?', abort=True) endTime = time.perf_counter() diff --git a/bin/ffx/ffx_controller.py b/bin/ffx/ffx_controller.py index d5cf5e0..c093672 100644 --- a/bin/ffx/ffx_controller.py +++ b/bin/ffx/ffx_controller.py @@ -17,7 +17,7 @@ class FfxController(): TEMP_FILE_NAME = "ffmpeg2pass-0.log" - DEFAULT_VIDEO_ENCODER = 'vp9' + DEFAULT_VIDEO_ENCODER = VideoEncoder.VP9.label() DEFAULT_QUALITY = 23 DEFAULT_AV1_PRESET = 5 @@ -409,7 +409,7 @@ class FfxController(): + self.generateDispositionTokens()) if not self.__sourceMediaDescriptor is None: - commandSequence += self.generateMetadataTokens() + commandSequence2 += self.generateMetadataTokens() if denoise: commandSequence2 += self.generateDenoiseTokens() diff --git a/bin/ffx/file_properties.py b/bin/ffx/file_properties.py index 88ab9fa..a38ee1b 100644 --- a/bin/ffx/file_properties.py +++ b/bin/ffx/file_properties.py @@ -43,7 +43,7 @@ class FileProperties(): matchResult = self.__pc.matchFilename(self.__sourceFilename) - self.__pattern = matchResult['pattern'] if matchResult else None + self.__pattern: Pattern = matchResult['pattern'] if matchResult else None matchedGroups = matchResult['match'].groups() if matchResult else {} seIndicator = matchedGroups[0] if matchedGroups else self.__sourceFilename @@ -187,13 +187,13 @@ class FileProperties(): def assembleTargetFilename(self, - label = None, - quality : int = -1, - fileIndex : int = -1, - indexDigits : int = DEFAULT_INDEX_DIGITS, - extension : str = None): + label: str = "", + quality: int = -1, + fileIndex: int = -1, + indexDigits: int = DEFAULT_INDEX_DIGITS, + extension: str = None): - if 'show_descriptor' in self.context['show_descriptor'].keys(): + if 'show_descriptor' in self.context.keys(): season_digits = self.context['show_descriptor'][ShowDescriptor.INDICATOR_SEASON_DIGITS_KEY] episode_digits = self.context['show_descriptor'][ShowDescriptor.INDICATOR_EPISODE_DIGITS_KEY] else: @@ -204,29 +204,27 @@ class FileProperties(): targetFilenameExtension = FfxController.DEFAULT_FILE_EXTENSION if extension is None else str(extension) - if label is None: + if not label: targetFilenameTokens = [self.__sourceFileBasename] - else: targetFilenameTokens = [label] if fileIndex > -1: targetFilenameTokens += [f"{fileIndex:0{indexDigits}d}"] - elif self.__season > -1 and self.__episode > -1: targetFilenameTokens += [f"S{self.__season:0{season_digits}d}E{self.__episode:0{episode_digits}d}"] elif self.__episode > -1: targetFilenameTokens += [f"E{self.__episode:0{episode_digits}d}"] - if len(quality) != 1: - targetFilenameTokens += [f"q{quality}"] + if quality != -1: + targetFilenameTokens += [f"q{quality}"] - # In case source and target filenames are the same add an extension to distinct output from input - if label is None and self.__sourceFilenameExtension == targetFilenameExtension: - targetFilenameTokens += ['ffx'] + # In case source and target filenames are the same add an extension to distinct output from input + if not label and self.__sourceFilenameExtension == targetFilenameExtension: + targetFilenameTokens += ['ffx'] - targetFilename = '_'.join(targetFilenameTokens) + targetFilename = '_'.join(targetFilenameTokens) - click.echo(f"Target filename: {targetFilename}") + click.echo(f"Target filename: {targetFilename}") return targetFilename diff --git a/bin/ffx/model/pattern.py b/bin/ffx/model/pattern.py index e1dd08c..e1bdb0e 100644 --- a/bin/ffx/model/pattern.py +++ b/bin/ffx/model/pattern.py @@ -1,10 +1,13 @@ +import click + from sqlalchemy import create_engine, Column, Integer, String, ForeignKey from sqlalchemy.orm import relationship, sessionmaker, Mapped, backref -from .show import Base +from .show import Base, Show from .track import Track from ffx.media_descriptor import MediaDescriptor +from ffx.show_descriptor import ShowDescriptor class Pattern(Base): @@ -20,7 +23,7 @@ class Pattern(Base): # v1.x show_id = Column(Integer, ForeignKey('shows.id', ondelete="CASCADE")) - show = relationship('Show', back_populates='patterns', lazy='joined') + show = relationship(Show, back_populates='patterns', lazy='joined') # v2.0 # show_id: Mapped[int] = mapped_column(ForeignKey("shows.id", ondelete="CASCADE")) @@ -38,6 +41,10 @@ class Pattern(Base): def getShowId(self): return int(self.show_id) + def getShowDescriptor(self) -> ShowDescriptor: + click.echo(f"self.show {self.show} id={self.show_id}") + return self.show.getDescriptor() + def getId(self): return int(self.id) diff --git a/bin/ffx/model/show.py b/bin/ffx/model/show.py index 372b75e..14e5935 100644 --- a/bin/ffx/model/show.py +++ b/bin/ffx/model/show.py @@ -44,30 +44,16 @@ class Show(Base): indicator_episode_digits = Column(Integer, default=ShowDescriptor.DEFAULT_INDICATOR_EPISODE_DIGITS) - def getDesciptor(self): - - descriptor = {} - - descriptor['id'] = int(self.id) - descriptor['name'] = str(self.name) - descriptor['year'] = int(self.year) - - descriptor['index_season_digits'] = int(self.index_season_digits) - descriptor['index_episode_digits'] = int(self.index_episode_digits) - descriptor['indicator_season_digits'] = int(self.indicator_season_digits) - descriptor['indicator_episode_digits'] = int(self.indicator_episode_digits) - - return descriptor - -# def getDescriptor(self): -# -# kwargs = {} -# -# kwargs[] -# kwargs[] -# kwargs[] -# -# kwargs[] -# kwargs[] -# kwargs[] -# kwargs[] \ No newline at end of file + def getDescriptor(self): + + kwargs = {} + + kwargs[ShowDescriptor.ID_KEY] = int(self.id) + kwargs[ShowDescriptor.NAME_KEY] = str(self.name) + kwargs[ShowDescriptor.YEAR_KEY] = int(self.year) + kwargs[ShowDescriptor.INDEX_SEASON_DIGITS_KEY] = int(self.index_season_digits) + kwargs[ShowDescriptor.INDEX_EPISODE_DIGITS_KEY] = int(self.index_season_digits) + kwargs[ShowDescriptor.INDICATOR_SEASON_DIGITS_KEY] = int(self.indicator_season_digits) + kwargs[ShowDescriptor.INDICATOR_EPISODE_DIGITS_KEY] = int(self.indicator_episode_digits) + + return ShowDescriptor(**kwargs) diff --git a/bin/ffx/show_controller.py b/bin/ffx/show_controller.py index 9cdcedb..9e4dded 100644 --- a/bin/ffx/show_controller.py +++ b/bin/ffx/show_controller.py @@ -26,6 +26,18 @@ class ShowController(): finally: s.close() + def getShow(self, showId): + + try: + s = self.Session() + q = s.query(Show).filter(Show.id == showId) + + return q.first() if q.count() else None + + except Exception as ex: + raise click.ClickException(f"ShowController.getShow(): {repr(ex)}") + finally: + s.close() def getAllShows(self): diff --git a/bin/ffx/show_descriptor.py b/bin/ffx/show_descriptor.py index 1ab79ed..1573d55 100644 --- a/bin/ffx/show_descriptor.py +++ b/bin/ffx/show_descriptor.py @@ -13,7 +13,7 @@ from ffx.helper import dictDiff, DIFF_ADDED_KEY, DIFF_CHANGED_KEY, DIFF_REMOVED_ class ShowDescriptor(): """This class represents the structural content of a media file including streams and metadata""" - CONTEXT_KEY = 'context' + # CONTEXT_KEY = 'context' ID_KEY = 'id' NAME_KEY = 'name' @@ -29,306 +29,74 @@ class ShowDescriptor(): DEFAULT_INDICATOR_SEASON_DIGITS = 2 DEFAULT_INDICATOR_EPISODE_DIGITS = 2 - def getDesciptor(self): - - descriptor = {} - - descriptor['id'] = int(self.id) - descriptor['name'] = str(self.name) - descriptor['year'] = int(self.year) - - descriptor['index_season_digits'] = int(self.index_season_digits) - descriptor['index_episode_digits'] = int(self.index_episode_digits) - descriptor['indicator_season_digits'] = int(self.indicator_season_digits) - descriptor['indicator_episode_digits'] = int(self.indicator_episode_digits) - - return descriptor def __init__(self, **kwargs): if ShowDescriptor.ID_KEY in kwargs.keys(): - if type(kwargs[ShowDescriptor.ID_KEY]) is not dict: - raise TypeError(f"ShowDescriptor.__init__(): Argument {ShowDescriptor.ID_KEY} is required to be of type dict") + if type(kwargs[ShowDescriptor.ID_KEY]) is not int: + raise TypeError(f"ShowDescriptor.__init__(): Argument {ShowDescriptor.ID_KEY} is required to be of type int") self.__showId = kwargs[ShowDescriptor.ID_KEY] else: self.__showId = {} if ShowDescriptor.NAME_KEY in kwargs.keys(): - if type(kwargs[ShowDescriptor.NAME_KEY]) is not dict: - raise TypeError(f"ShowDescriptor.__init__(): Argument {ShowDescriptor.NAME_KEY} is required to be of type dict") + if type(kwargs[ShowDescriptor.NAME_KEY]) is not str: + raise TypeError(f"ShowDescriptor.__init__(): Argument {ShowDescriptor.NAME_KEY} is required to be of type str") self.__showName = kwargs[ShowDescriptor.NAME_KEY] else: self.__showName = {} if ShowDescriptor.YEAR_KEY in kwargs.keys(): - if type(kwargs[ShowDescriptor.YEAR_KEY]) is not dict: - raise TypeError(f"ShowDescriptor.__init__(): Argument {ShowDescriptor.YEAR_KEY} is required to be of type dict") + if type(kwargs[ShowDescriptor.YEAR_KEY]) is not int: + raise TypeError(f"ShowDescriptor.__init__(): Argument {ShowDescriptor.YEAR_KEY} is required to be of type int") self.__showYear = kwargs[ShowDescriptor.YEAR_KEY] else: self.__showYear = {} if ShowDescriptor.INDEX_SEASON_DIGITS_KEY in kwargs.keys(): - if type(kwargs[ShowDescriptor.INDEX_SEASON_DIGITS_KEY]) is not dict: - raise TypeError(f"ShowDescriptor.__init__(): Argument {ShowDescriptor.INDEX_SEASON_DIGITS_KEY} is required to be of type dict") + if type(kwargs[ShowDescriptor.INDEX_SEASON_DIGITS_KEY]) is not int: + raise TypeError(f"ShowDescriptor.__init__(): Argument {ShowDescriptor.INDEX_SEASON_DIGITS_KEY} is required to be of type int") self.__indexSeasonDigits = kwargs[ShowDescriptor.INDEX_SEASON_DIGITS_KEY] else: self.__indexSeasonDigits = {} if ShowDescriptor.INDEX_EPISODE_DIGITS_KEY in kwargs.keys(): - if type(kwargs[ShowDescriptor.INDEX_EPISODE_DIGITS_KEY]) is not dict: - raise TypeError(f"ShowDescriptor.__init__(): Argument {ShowDescriptor.INDEX_EPISODE_DIGITS_KEY} is required to be of type dict") + if type(kwargs[ShowDescriptor.INDEX_EPISODE_DIGITS_KEY]) is not int: + raise TypeError(f"ShowDescriptor.__init__(): Argument {ShowDescriptor.INDEX_EPISODE_DIGITS_KEY} is required to be of type int") self.__indexEpisodeDigits = kwargs[ShowDescriptor.INDEX_EPISODE_DIGITS_KEY] else: self.__indexEpisodeDigits = {} if ShowDescriptor.INDICATOR_SEASON_DIGITS_KEY in kwargs.keys(): - if type(kwargs[ShowDescriptor.INDICATOR_SEASON_DIGITS_KEY]) is not dict: - raise TypeError(f"ShowDescriptor.__init__(): Argument {ShowDescriptor.INDICATOR_SEASON_DIGITS_KEY} is required to be of type dict") + if type(kwargs[ShowDescriptor.INDICATOR_SEASON_DIGITS_KEY]) is not int: + raise TypeError(f"ShowDescriptor.__init__(): Argument {ShowDescriptor.INDICATOR_SEASON_DIGITS_KEY} is required to be of type int") self.__indicatorSeasonDigits = kwargs[ShowDescriptor.INDICATOR_SEASON_DIGITS_KEY] else: self.__indicatorSeasonDigits = {} if ShowDescriptor.INDICATOR_EPISODE_DIGITS_KEY in kwargs.keys(): - if type(kwargs[ShowDescriptor.INDICATOR_EPISODE_DIGITS_KEY]) is not dict: - raise TypeError(f"ShowDescriptor.__init__(): Argument {ShowDescriptor.INDICATOR_EPISODE_DIGITS_KEY} is required to be of type dict") + if type(kwargs[ShowDescriptor.INDICATOR_EPISODE_DIGITS_KEY]) is not int: + raise TypeError(f"ShowDescriptor.__init__(): Argument {ShowDescriptor.INDICATOR_EPISODE_DIGITS_KEY} is required to be of type int") self.__indicatorEpisodeDigits = kwargs[ShowDescriptor.INDICATOR_EPISODE_DIGITS_KEY] else: self.__indicatorEpisodeDigits = {} - - def getDefaultVideoTrack(self): - videoDefaultTracks = [v for v in self.getVideoTracks() if TrackDisposition.DEFAULT in v.getDispositionSet()] - if len(videoDefaultTracks) > 1: - raise ValueError('ShowDescriptor.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('ShowDescriptor.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('ShowDescriptor.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('ShowDescriptor.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('ShowDescriptor.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('ShowDescriptor.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(): - if t.getType() == trackType: - t.setDispositionFlag(TrackDisposition.DEFAULT, t.getSubIndex() == int(subIndex)) - - def setForcedSubTrack(self, trackType : TrackType, subIndex : int): - for t in self.getAllTrackDescriptors(): - if t.getType() == trackType: - t.setDispositionFlag(TrackDisposition.FORCED, t.getSubIndex() == int(subIndex)) - - - def getReorderedTrackDescriptors(self): - - videoTracks = self.sortSubIndices(self.getVideoTracks()) - audioTracks = self.sortSubIndices(self.getAudioTracks()) - subtitleTracks = self.sortSubIndices(self.getSubtitleTracks()) - - videoDefaultTrack = self.getDefaultVideoTrack() - self.getForcedVideoTrack() - audioDefaultTrack = self.getDefaultAudioTrack() - self.getForcedAudioTrack() - subtitleDefaultTrack = self.getDefaultSubtitleTrack() - self.getForcedSubtitleTrack() - - if self.__jellyfinOrder: - if not videoDefaultTrack is None: - videoTracks.append(videoTracks.pop(videoTracks.index(videoDefaultTrack))) - if not audioDefaultTrack is None: - audioTracks.append(audioTracks.pop(audioTracks.index(audioDefaultTrack))) - if not subtitleDefaultTrack is None: - subtitleTracks.append(subtitleTracks.pop(subtitleTracks.index(subtitleDefaultTrack))) - - 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 - - - @classmethod - def fromFfprobe(cls, formatData, streamData): - - kwargs = {} - - if ShowDescriptor.FFPROBE_TAGS_KEY in formatData.keys(): - kwargs[ShowDescriptor.TAGS_KEY] = formatData[ShowDescriptor.FFPROBE_TAGS_KEY] - - kwargs[ShowDescriptor.TRACK_DESCRIPTOR_LIST_KEY] = [] - - #TODO: Evtl obsolet - subIndexCounters = {} - - for streamObj in streamData: - - ffprobeCodecType = streamObj[ShowDescriptor.FFPROBE_CODEC_TYPE_KEY] - trackType = TrackType.fromLabel(ffprobeCodecType) - - if trackType != TrackType.UNKNOWN: - - if trackType not in subIndexCounters.keys(): - subIndexCounters[trackType] = 0 - - kwargs[ShowDescriptor.TRACK_DESCRIPTOR_LIST_KEY].append(TrackDescriptor.fromFfprobe(streamObj, - subIndex=subIndexCounters[trackType])) - subIndexCounters[trackType] += 1 - - - return cls(**kwargs) - - - def getTags(self): - return self.__mediaTags - - - def sortSubIndices(self, descriptors : List[TrackDescriptor]) -> List[TrackDescriptor]: - subIndex = 0 - for t in descriptors: - t.setSubIndex(subIndex) - subIndex += 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] - - - def getAudioTracks(self) -> List[TrackDescriptor]: - return [a for a in self.__trackDescriptors.copy() if a.getType() == TrackType.AUDIO] - - def getSubtitleTracks(self) -> List[TrackDescriptor]: - return [s for s in self.__trackDescriptors.copy() 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, vsShowDescriptor : Self): - - if not isinstance(vsShowDescriptor, self.__class__): - raise click.ClickException(f"ShowDescriptor.compare(): Argument is required to be of type {self.__class__}") - - vsTags = vsShowDescriptor.getTags() - tags = self.getTags() - - #HINT: Some tags differ per file, for example creation_time, so these are removed before diff - for emt in ShowDescriptor.EXCLUDED_MEDIA_TAGS: - if emt in tags.keys(): - del tags[emt] - if emt in vsTags.keys(): - del vsTags[emt] - - tagsDiff = dictDiff(vsTags, tags) - - compareResult = {} - - if tagsDiff: - compareResult[ShowDescriptor.TAGS_KEY] = tagsDiff - - - # Target track configuration (from DB) - #tracks = self.getAllTrackDescriptors() - tracks = self.getReorderedTrackDescriptors() - numTracks = len(tracks) - - # Current track configuration (of file) - vsTracks = vsShowDescriptor.getAllTrackDescriptors() - numVsTracks = len(vsTracks) - - maxNumOfTracks = max(numVsTracks, numTracks) - - - trackCompareResult = {} - - for tp in range(maxNumOfTracks): - - # inspect/update funktionier nur so - if self.__jellyfinOrder: - vsTrackIndex = tracks[tp].getSourceIndex() - else: - vsTrackIndex = tp - # vsTrackIndex = tracks[tp].getSourceIndex() - - # Will trigger if tracks are missing in file - if tp > (numVsTracks - 1): - if DIFF_ADDED_KEY not in trackCompareResult.keys(): - trackCompareResult[DIFF_ADDED_KEY] = set() - trackCompareResult[DIFF_ADDED_KEY].add(tracks[tp].getIndex()) - continue - - # Will trigger if tracks are missing in DB definition - # New tracks will be added per update via this way - if tp > (numTracks - 1): - if DIFF_REMOVED_KEY not in trackCompareResult.keys(): - trackCompareResult[DIFF_REMOVED_KEY] = {} - trackCompareResult[DIFF_REMOVED_KEY][vsTracks[vsTrackIndex].getIndex()] = vsTracks[vsTrackIndex] - continue - - # assumption is made here that the track order will not change for all files of a sequence - trackDiff = tracks[tp].compare(vsTracks[vsTrackIndex]) - - if trackDiff: - if DIFF_CHANGED_KEY not in trackCompareResult.keys(): - trackCompareResult[DIFF_CHANGED_KEY] = {} - trackCompareResult[DIFF_CHANGED_KEY][vsTracks[vsTrackIndex].getIndex()] = trackDiff - - if trackCompareResult: - compareResult[ShowDescriptor.TRACKS_KEY] = trackCompareResult - - return compareResult - - - - def getInputMappingTokens(self, use_sub_index : bool = True): - - reorderedTrackDescriptors = self.getReorderedTrackDescriptors() - inputMappingTokens = [] - - for rtd in reorderedTrackDescriptors: - trackType = rtd.getType() - if use_sub_index: - inputMappingTokens += ['-map', f"0:{trackType.indicator()}:{rtd.getSubIndex()}"] - else: - inputMappingTokens += ['-map', f"0:{rtd.getIndex()}"] - - return inputMappingTokens - + def getId(self): + return self.__showId + def getName(self): + return self.__showName + def getYear(self): + return self.__showYear + + def getIndexSeasonDigits(self): + return self.__indexSeasonDigits + def getIndexEpisodeDigits(self): + return self.__indexEpisodeDigits + def getIndicatorSeasonDigits(self): + return self.__indicatorSeasonDigits + def getIndicatorEpisodeDigits(self): + return self.__indicatorEpisodeDigits + + def getFilenamePrefix(self): + return f"{self.__showName} ({str(self.__showYear)})" diff --git a/bin/ffx/tmdb_controller.py b/bin/ffx/tmdb_controller.py index 7c6de2d..cea3e8a 100644 --- a/bin/ffx/tmdb_controller.py +++ b/bin/ffx/tmdb_controller.py @@ -40,12 +40,11 @@ class TmdbController(): return requests.get(tmdbUrl).json() - def getEpisodeFilename(self, + def getEpisodeFileBasename(self, showName, episodeName, season, episode, - extension, indexSeasonDigits = 2, indexEpisodeDigits = 2, indicatorSeasonDigits = 2, @@ -92,7 +91,5 @@ class TmdbController(): filenameTokens += ['S{num:{fill}{width}}'.format(num=season, fill='0', width=indicatorSeasonDigits)] if indicatorEpisodeDigits: filenameTokens += ['E{num:{fill}{width}}'.format(num=episode, fill='0', width=indicatorEpisodeDigits)] - - filenameTokens += ['.', extension] - + return ''.join(filenameTokens)