diff --git a/bin/ffx/media_descriptor.py b/bin/ffx/media_descriptor.py index 634f388..403bfcc 100644 --- a/bin/ffx/media_descriptor.py +++ b/bin/ffx/media_descriptor.py @@ -1,11 +1,12 @@ -from typing import List +import click + +from typing import List, Self from ffx.track_type import TrackType from ffx.track_descriptor import TrackDescriptor from ffx.helper import dictDiff - class MediaDescriptor(): """This class represents the structural content of a media file including streams and metadata""" @@ -84,6 +85,9 @@ class MediaDescriptor(): def getAllTracks(self) -> List[TrackDescriptor]: return self.__trackDescriptors + def getVideoTracks(self) -> List[TrackDescriptor]: + return [d for d in self.__trackDescriptors if d.getType() == TrackType.VIDEO] + def getAudioTracks(self) -> List[TrackDescriptor]: return [d for d in self.__trackDescriptors if d.getType() == TrackType.AUDIO] @@ -92,8 +96,11 @@ class MediaDescriptor(): - def compare(self, vsMediaDescriptor): - + def compare(self, vsMediaDescriptor : Self): + + if not isinstance(vsMediaDescriptor, self.__class__): + raise click.ClickException(f"MediaDescriptor.compare(): Argument is required to be of type {self.__class__}") + mediaTagsResult = dictDiff(vsMediaDescriptor.getTags(), self.getTags()) compareResult = {} @@ -102,35 +109,43 @@ class MediaDescriptor(): compareResult['tags'] = mediaTagsResult - vsTracks = vsMediaDescriptor.getAllTracks() - tracks = self.getAllTracks() + # Target track configuration (from DB) + tracks = [t for t in self.getAllTracks() if t.getType() != TrackType.VIDEO] + numTracks = len(tracks) + # Current track configuration (of file) + vsTracks = [t for t in vsMediaDescriptor.getAllTracks() if t.getType() != TrackType.VIDEO] numVsTracks = len(vsTracks) - numTracks = len(tracks) + maxNumOfTracks = max(numVsTracks, numTracks) + # raise click.ClickException(f"numTracks={numTracks} numVsTracks={numVsTracks}") # 1 4 trackCompareResult = {} - for trackIndex in range(maxNumOfTracks): - - if trackIndex > numVsTracks - 1: + for tp in range(maxNumOfTracks): + + # Will trigger if tracks are missing in file + if tp > (numVsTracks - 1): if 'removed' not in trackCompareResult.keys(): trackCompareResult['removed'] = set() - trackCompareResult['removed'].add(trackIndex) + trackCompareResult['removed'].add(tracks[tp].getIndex()) continue - if trackIndex > numTracks - 1: + # Will trigger if tracks are missing in DB definition + if tp > (numTracks - 1): if 'added' not in trackCompareResult.keys(): trackCompareResult['added'] = {} - trackCompareResult['added'][trackIndex] = vsTracks[trackIndex] + trackCompareResult['added'][vsTracks[tp].getIndex()] = vsTracks[tp] continue - trackResult = tracks[trackIndex].compare(vsTracks[trackIndex]) - if trackResult: - if 'changed' not in trackCompareResult.keys(): - trackCompareResult['changed'] = {} - trackCompareResult['changed'][trackIndex] = trackResult + # assumption is made here that the track order will not change for all files of a sequence + tdiff = tracks[tp].compare(vsTracks[tp]) + + if tdiff: + if 'changed' not in trackCompareResult.keys(): + trackCompareResult['changed'] = {} + trackCompareResult['changed'][vsTracks[tp].getIndex()] = tdiff if trackCompareResult: compareResult['tracks'] = trackCompareResult diff --git a/bin/ffx/media_details_screen.py b/bin/ffx/media_details_screen.py index ae1db1c..0bd1ccf 100644 --- a/bin/ffx/media_details_screen.py +++ b/bin/ffx/media_details_screen.py @@ -91,6 +91,14 @@ class MediaDetailsScreen(Screen): }*/ """ + + BINDINGS = [ + ("n", "new_pattern", "New Pattern"), + ("u", "update_pattern", "Update Pattern"), + ("e", "edit_pattern", "Update Pattern"), + ] + + def __init__(self): super().__init__() @@ -119,8 +127,6 @@ class MediaDetailsScreen(Screen): self.__storedMediaFilenamePattern = self.__mediaFilenamePattern.getMediaDescriptor() if self.__mediaFilenamePattern is not None else None - # raise click.ClickException(f"diff {self.__mediaDescriptor.compare(self.__storedMediaFilenamePattern)}") - # def loadTracks(self, show_id): # @@ -202,8 +208,9 @@ class MediaDetailsScreen(Screen): def on_mount(self): - row = (' ', '', ' ') # Convert each element to a string before adding - self.showsTable.add_row(*map(str, row)) + if self.__mediaFilenamePattern is None: + row = (' ', '', ' ') # Convert each element to a string before adding + self.showsTable.add_row(*map(str, row)) for show in self.__sc.getAllShows(): row = (int(show.id), show.name, show.year) # Convert each element to a string before adding @@ -226,31 +233,61 @@ class MediaDetailsScreen(Screen): self.query_one("#pattern_input", Input).value = self.__mediaFilenamePattern.getPattern() - mediaDifferences = self.__mediaDescriptor.compare(self.__mediaFilenamePattern.getMediaDescriptor()) + # Enumerating differences between media descriptor from file vs from stored in database + targetMediaDescriptor = self.__mediaFilenamePattern.getMediaDescriptor() + mediaDifferences = targetMediaDescriptor.compare(self.__mediaDescriptor) if 'tags' in mediaDifferences.keys(): mediaTags = self.__mediaDescriptor.getTags() if 'added' in mediaDifferences['tags'].keys(): - for addedTagKey in mediaDifferences['tags']['added']: - row = (f"added media tag: key='{addedTagKey}' value='{mediaTags[addedTagKey]}'",) self.differencesTable.add_row(*map(str, row)) + if 'removed' in mediaDifferences['tags'].keys(): + for removedTagKey in mediaDifferences['tags']['removed']: + row = (f"removed media tag: key='{removedTagKey}' value='{mediaTags[removedTagKey]}'",) + self.differencesTable.add_row(*map(str, row)) + + if 'tracks' in mediaDifferences.keys(): - tracks = self.__mediaDescriptor.getAllTracks() + currentTracks = self.__mediaDescriptor.getAllTracks() # 0,1,2,3 + targetTracks = targetMediaDescriptor.getAllTracks() # 0 <- from DB - if 'removed' in mediaDifferences['tracks'].keys(): + if 'added' in mediaDifferences['tracks'].keys(): + for addedTrackIndex in mediaDifferences['tracks']['added'].keys(): + addedTrack : Track = currentTracks[addedTrackIndex] + row = (f"added {addedTrack.getType().label()} track: index={addedTrackIndex} subIndex={addedTrack.getSubIndex()} lang={addedTrack.getLanguage().threeLetter()}",) + self.differencesTable.add_row(*map(str, row)) + if 'removed' in mediaDifferences['tracks'].keys(): for removedTrackIndex in mediaDifferences['tracks']['removed']: - - removedTrack : Track = tracks[removedTrackIndex] - - row = (f"removed {removedTrack.getType().label()} track: index={removedTrackIndex} subIndex={removedTrack.getSubIndex()} lang={removedTrack.getLanguage().threeLetter()}",) + row = (f"removed track: index={removedTrackIndex}",) self.differencesTable.add_row(*map(str, row)) + + if 'changed' in mediaDifferences['tracks'].keys(): + for changedTrackIndex in mediaDifferences['tracks']['changed'].keys(): + + changedTrack : Track = targetTracks[changedTrackIndex] + changedTrackDiff : dict = mediaDifferences['tracks']['changed'][changedTrackIndex] + + if 'tags' in changedTrackDiff.keys(): + + if 'added' in changedTrackDiff['tags']: + for addedTagKey in changedTrackDiff['tags']['added']: + + addedTagValue = changedTrack.getTags()[addedTagKey] + row = (f"changed {changedTrack.getType().label()} track index={changedTrackIndex} added key={addedTagKey} value={addedTagValue}",) + self.differencesTable.add_row(*map(str, row)) + + if 'removed' in changedTrackDiff['tags']: + for removedTagKey in changedTrackDiff['tags']['removed']: + row = (f"changed {changedTrack.getType().label()} track index={changedTrackIndex} removed key={removedTagKey}",) + self.differencesTable.add_row(*map(str, row)) + else: self.query_one("#pattern_input", Input).value = self.__mediaFilename diff --git a/bin/ffx/model/pattern.py b/bin/ffx/model/pattern.py index 7742079..e1dd08c 100644 --- a/bin/ffx/model/pattern.py +++ b/bin/ffx/model/pattern.py @@ -55,13 +55,6 @@ class Pattern(Base): kwargs[MediaDescriptor.TRACK_DESCRIPTOR_LIST_KEY] = [] -# for track in self.tracks: -# -# if track.getType() not in kwargs[MediaDescriptor.TRACK_DESCRIPTORS_KEY].keys(): -# kwargs[MediaDescriptor.TRACK_DESCRIPTORS_KEY][track.getType().label()] = [] -# -# kwargs[MediaDescriptor.TRACK_DESCRIPTORS_KEY][track.getType().label()].append(track.getDescriptor()) - for track in self.tracks: kwargs[MediaDescriptor.TRACK_DESCRIPTOR_LIST_KEY].append(track.getDescriptor()) diff --git a/bin/ffx/model/track.py b/bin/ffx/model/track.py index d94f23b..caa7337 100644 --- a/bin/ffx/model/track.py +++ b/bin/ffx/model/track.py @@ -174,7 +174,7 @@ class Track(Base): kwargs[TrackDescriptor.ID_KEY] = self.getId() kwargs[TrackDescriptor.PATTERN_ID_KEY] = self.getPatternId() - kwargs[TrackDescriptor.SUB_INDEX_KEY] = self.getIndex() + kwargs[TrackDescriptor.INDEX_KEY] = self.getIndex() kwargs[TrackDescriptor.SUB_INDEX_KEY] = self.getSubIndex() kwargs[TrackDescriptor.TRACK_TYPE_KEY] = self.getType() diff --git a/bin/ffx/pattern_controller.py b/bin/ffx/pattern_controller.py index b3935de..3a7b17e 100644 --- a/bin/ffx/pattern_controller.py +++ b/bin/ffx/pattern_controller.py @@ -23,9 +23,9 @@ class PatternController(): pattern = str(patternDescriptor['pattern'])) s.add(pattern) s.commit() - return patternDescriptor + return pattern.getId() else: - return {} + return None except Exception as ex: raise click.ClickException(f"PatternController.addPattern(): {repr(ex)}") diff --git a/bin/ffx/pattern_details_screen.py b/bin/ffx/pattern_details_screen.py index 0544eec..03213c6 100644 --- a/bin/ffx/pattern_details_screen.py +++ b/bin/ffx/pattern_details_screen.py @@ -85,6 +85,7 @@ class PatternDetailsScreen(Screen): self.show_obj = self.__sc.getShowDesciptor(showId) if showId is not None else {} + #TODO: per controller def loadTracks(self, show_id): try: @@ -323,7 +324,17 @@ class PatternDetailsScreen(Screen): self.app.pop_screen() else: - if self.__pc.addPattern(patternDescriptor): + patternId = self.__pc.addPattern(patternDescriptor) + if patternId is not None: + + # Add dummy video track + kwargs = {} + kwargs[TrackDescriptor.INDEX_KEY] = 0 + kwargs[TrackDescriptor.SUB_INDEX_KEY] = 0 + kwargs[TrackDescriptor.PATTERN_ID_KEY] = patternId + kwargs[TrackDescriptor.TRACK_TYPE_KEY] = TrackType.VIDEO + self.__tc.addTrack(TrackDescriptor(**kwargs)) + self.dismiss(patternDescriptor) else: #TODO: Meldung @@ -338,8 +349,16 @@ class PatternDetailsScreen(Screen): # Save pattern when just created before adding streams if self.__pattern is not None: + numVideoStreams = len(self.__pattern.getMediaDescriptor().getVideoTracks()) + numAudioStreams = len(self.audioStreamsTable.rows) + numSubtitleStreams = len(self.subtitleStreamsTable.rows) + + addedTrackIndex = numVideoStreams + numAudioStreams + numSubtitleStreams + + #NOTE: Track index + if event.button.id == "button_add_audio_stream": - self.app.push_screen(TrackDetailsScreen(trackType = TrackType.AUDIO, patternId = self.__pattern.getId(), subIndex = len(self.audioStreamsTable.rows)), self.handle_add_track) + self.app.push_screen(TrackDetailsScreen(trackType = TrackType.AUDIO, patternId = self.__pattern.getId(), index = addedTrackIndex, subIndex = numAudioStreams), self.handle_add_track) selectedAudioTrack = self.getSelectedAudioTrackDescriptor() if selectedAudioTrack is not None: @@ -350,7 +369,7 @@ class PatternDetailsScreen(Screen): self.app.push_screen(TrackDeleteScreen(trackDescriptor = selectedAudioTrack), self.handle_delete_track) if event.button.id == "button_add_subtitle_stream": - self.app.push_screen(TrackDetailsScreen(trackType = TrackType.SUBTITLE, patternId = self.__pattern.getId(), subIndex = len(self.subtitleStreamsTable.rows)), self.handle_add_track) + self.app.push_screen(TrackDetailsScreen(trackType = TrackType.SUBTITLE, patternId = self.__pattern.getId(), index = addedTrackIndex, subIndex = numSubtitleStreams), self.handle_add_track) selectedSubtitleTrack = self.getSelectedSubtitleTrackDescriptor() if selectedSubtitleTrack is not None: diff --git a/bin/ffx/shows_screen.py b/bin/ffx/shows_screen.py index e8a8028..b28f3b7 100644 --- a/bin/ffx/shows_screen.py +++ b/bin/ffx/shows_screen.py @@ -132,9 +132,11 @@ class ShowsScreen(Screen): def on_mount(self) -> None: - for show in self.__sc.getAllShows(): - row = (int(show.id), show.name, show.year) # Convert each element to a string before adding - self.table.add_row(*map(str, row)) + allShows = self.__sc.getAllShows() + if allShows is not None: + for show in self.__sc.getAllShows(): + row = (int(show.id), show.name, show.year) # Convert each element to a string before adding + self.table.add_row(*map(str, row)) def compose(self): diff --git a/bin/ffx/track_controller.py b/bin/ffx/track_controller.py index 25531bb..30fbb14 100644 --- a/bin/ffx/track_controller.py +++ b/bin/ffx/track_controller.py @@ -27,6 +27,7 @@ class TrackController(): s = self.Session() track = Track(pattern_id = int(trackDescriptor.getPatternId()), track_type = int(trackDescriptor.getType().index()), + index = int(trackDescriptor.getIndex()), sub_index = int(trackDescriptor.getSubIndex()), disposition_flags = int(TrackDisposition.toFlags(trackDescriptor.getDispositionSet()))) diff --git a/bin/ffx/track_descriptor.py b/bin/ffx/track_descriptor.py index 3796957..52aeeb6 100644 --- a/bin/ffx/track_descriptor.py +++ b/bin/ffx/track_descriptor.py @@ -135,7 +135,7 @@ class TrackDescriptor(): kwargs = {} - kwargs[TrackDescriptor.INDEX_KEY] = streamObj[TrackDescriptor.FFPROBE_INDEX_KEY] if TrackDescriptor.FFPROBE_INDEX_KEY in streamObj.keys() else -1 + kwargs[TrackDescriptor.INDEX_KEY] = int(streamObj[TrackDescriptor.FFPROBE_INDEX_KEY]) if TrackDescriptor.FFPROBE_INDEX_KEY in streamObj.keys() else -1 kwargs[TrackDescriptor.SUB_INDEX_KEY] = subIndex kwargs[TrackDescriptor.TRACK_TYPE_KEY] = trackType @@ -205,3 +205,5 @@ class TrackDescriptor(): if dispositionDiffResult: compareResult['dispositions'] = dispositionDiffResult + + return compareResult \ No newline at end of file diff --git a/bin/ffx/track_details_screen.py b/bin/ffx/track_details_screen.py index 36f289e..6b41f42 100644 --- a/bin/ffx/track_details_screen.py +++ b/bin/ffx/track_details_screen.py @@ -81,7 +81,7 @@ class TrackDetailsScreen(Screen): } """ - def __init__(self, trackDescriptor = None, patternId = None, trackType : TrackType = None, subIndex = None): + def __init__(self, trackDescriptor : TrackDescriptor = None, patternId = None, trackType : TrackType = None, index = None, subIndex = None): super().__init__() self.context = self.app.getContext() @@ -94,11 +94,13 @@ class TrackDetailsScreen(Screen): self.__isNew = trackDescriptor is None if self.__isNew: self.__trackType = trackType + self.__index = index self.__subIndex = subIndex self.__trackDescriptor : TrackDescriptor = None self.__pattern : Pattern = self.__pc.getPattern(patternId) if patternId is not None else {} else: self.__trackType = trackDescriptor.getType() + self.__index = trackDescriptor.getIndex() self.__subIndex = trackDescriptor.getSubIndex() self.__trackDescriptor : TrackDescriptor = trackDescriptor self.__pattern : Pattern = self.__pc.getPattern(self.__trackDescriptor.getPatternId()) @@ -240,7 +242,7 @@ class TrackDetailsScreen(Screen): kwargs[TrackDescriptor.PATTERN_ID_KEY] = int(self.__pattern.getId()) - kwargs[TrackDescriptor.INDEX_KEY] = -1 + kwargs[TrackDescriptor.INDEX_KEY] = self.__index kwargs[TrackDescriptor.SUB_INDEX_KEY] = self.__subIndex kwargs[TrackDescriptor.TRACK_TYPE_KEY] = self.__trackType