From 87ccb7e8a6a7f97b911762ecdd611a24a42513a1 Mon Sep 17 00:00:00 2001 From: Maveno Date: Sun, 29 Sep 2024 21:42:42 +0200 Subject: [PATCH] fix pattern edit --- bin/check.py | 32 +++++++++++ bin/ffx/pattern_controller.py | 96 ++++++++++++++++++++++++++----- bin/ffx/pattern_delete_screen.py | 11 ++-- bin/ffx/pattern_details_screen.py | 55 +++++++++++------- bin/ffx/show_details_screen.py | 75 ++++++++++++++---------- 5 files changed, 200 insertions(+), 69 deletions(-) create mode 100644 bin/check.py diff --git a/bin/check.py b/bin/check.py new file mode 100644 index 0000000..9759724 --- /dev/null +++ b/bin/check.py @@ -0,0 +1,32 @@ +import os + +from ffx.pattern_controller import PatternController + +from ffx.model.show import Base +from sqlalchemy import create_engine, Column, Integer, String, ForeignKey +from sqlalchemy.orm import relationship, sessionmaker, Mapped, backref + +filename = 'Boruto.Naruto.Next.Generations.S01E256.GerEngSub.AAC.1080p.WebDL.x264-Tanuki.mkv' + + + +# Data 'input' variable +context = {} + +# Initialize DB +homeDir = os.path.expanduser("~") +ffxVarDir = os.path.join(homeDir, '.local', 'var', 'ffx') +if not os.path.exists(ffxVarDir): + os.makedirs(ffxVarDir) + +context['database_url'] = f"sqlite:///{os.path.join(ffxVarDir, 'ffx.db')}" +context['database_engine'] = create_engine(context['database_url']) +context['database_session'] = sessionmaker(bind=context['database_engine']) + +Base.metadata.create_all(context['database_engine']) + + +pc = PatternController(context) + + +print(pc.matchFilename(filename)) diff --git a/bin/ffx/pattern_controller.py b/bin/ffx/pattern_controller.py index 6d2c901..8beb345 100644 --- a/bin/ffx/pattern_controller.py +++ b/bin/ffx/pattern_controller.py @@ -1,4 +1,4 @@ -import click +import click, re from ffx.model.pattern import Pattern @@ -11,18 +11,47 @@ class PatternController(): self.Session = self.context['database_session'] # convenience - def updatePattern(self, show_id, pattern): + def addPattern(self, patternDescriptor): try: + s = self.Session() - q = s.query(Pattern).filter(Pattern.show_id == int(show_id), Pattern.pattern == str(pattern)) + q = s.query(Pattern).filter(Pattern.show_id == int(patternDescriptor['show_id']), Pattern.pattern == str(patternDescriptor['pattern'])) if not q.count(): - pattern = Pattern(show_id = int(show_id), pattern = str(pattern)) + pattern = Pattern(show_id = int(patternDescriptor['show_id']), + pattern = str(patternDescriptor['pattern'])) s.add(pattern) + s.commit() + return patternDescriptor + else: + return {} + + except Exception as ex: + raise click.ClickException(f"PatternController.addPattern(): {repr(ex)}") + finally: + s.close() + + + def updatePattern(self, patternId, patternDescriptor): + + try: + s = self.Session() + q = s.query(Pattern).filter(Pattern.id == int(patternId)) + + if q.count(): + + pattern = q.first() + + pattern.show_id = int(patternDescriptor['show_id']) + pattern.pattern = str(patternDescriptor['pattern']) + s.commit() return True + else: + return False + except Exception as ex: raise click.ClickException(f"PatternController.updatePattern(): {repr(ex)}") finally: @@ -30,11 +59,11 @@ class PatternController(): - def findPattern(self, showId, pattern): + def findPattern(self, patternDescriptor): try: s = self.Session() - q = s.query(Pattern).filter(Pattern.show_id == int(showId), Pattern.pattern == str(pattern)) + q = s.query(Pattern).filter(Pattern.show_id == int(patternDescriptor['show_id']), Pattern.pattern == str(patternDescriptor['pattern'])) if q.count(): pattern = q.first() @@ -48,21 +77,22 @@ class PatternController(): s.close() + def getPatternDict(self, pattern): + patternDescriptor = {} + patternDescriptor['pattern'] = str(pattern.pattern) + patternDescriptor['show_id'] = int(pattern.show_id) + return patternDescriptor + + def getPatternDescriptor(self, patternId): try: s = self.Session() q = s.query(Pattern).filter(Pattern.id == int(patternId)) - patternDescriptor = {} if q.count(): pattern = q.first() - - patternDescriptor['id'] = pattern.id - patternDescriptor['pattern'] = pattern.pattern - patternDescriptor['show_id'] = pattern.show_id - - return patternDescriptor + return self.getPatternDict(pattern) except Exception as ex: raise click.ClickException(f"PatternController.getPatternDescriptor(): {repr(ex)}") @@ -90,3 +120,43 @@ class PatternController(): raise click.ClickException(f"PatternController.deletePattern(): {repr(ex)}") finally: s.close() + + + def matchFilename(self, filename): + + SEASON_PATTERN = '[sS]([0-9]+)' + EPISODE_PATTERN = '[eE]([0-9]+)' + + result = {} + + try: + s = self.Session() + q = s.query(Pattern) + + for pattern in q.all(): + + match = re.search(pattern.pattern, filename) + + if match: + + result['pattern_id'] = pattern.id + result['show_id'] = pattern.show_id + + result['indicator'] = match.group(1) + + seasonMatch = re.search(SEASON_PATTERN, result['indicator']) + if seasonMatch: + result['season'] = int(seasonMatch.group(1)) + + episodeMatch = re.search(EPISODE_PATTERN, result['indicator']) + if episodeMatch: + result['episode'] = int(episodeMatch.group(1)) + + + except Exception as ex: + raise click.ClickException(f"PatternController.matchFilename(): {repr(ex)}") + finally: + s.close() + + return result + \ No newline at end of file diff --git a/bin/ffx/pattern_delete_screen.py b/bin/ffx/pattern_delete_screen.py index 3cccb50..8b47aa1 100644 --- a/bin/ffx/pattern_delete_screen.py +++ b/bin/ffx/pattern_delete_screen.py @@ -55,6 +55,7 @@ class PatternDeleteScreen(Screen): self.__pc = PatternController(context = self.context) self.__sc = ShowController(context = self.context) + self.pattern_id = patternId self.pattern_obj = self.__pc.getPatternDescriptor(patternId) if patternId is not None else {} self.show_obj = self.__sc.getShowDesciptor(showId) if showId is not None else {} @@ -97,13 +98,11 @@ class PatternDeleteScreen(Screen): if event.button.id == "delete_button": - if self.__pc.deletePattern(self.pattern_obj['id']): + if self.pattern_id is None: + raise click.ClickException('PatternDeleteScreen.on_button_pressed(): pattern id is undefined') - screenResult = {} - screenResult['show_id'] = self.show_obj['id'] - screenResult['pattern'] = self.pattern_obj['pattern'] - - self.dismiss(screenResult) + if self.__pc.deletePattern(self.pattern_id): + self.dismiss(self.pattern_obj) else: #TODO: Meldung diff --git a/bin/ffx/pattern_details_screen.py b/bin/ffx/pattern_details_screen.py index 1f3289a..62a2978 100644 --- a/bin/ffx/pattern_details_screen.py +++ b/bin/ffx/pattern_details_screen.py @@ -78,8 +78,10 @@ class PatternDetailsScreen(Screen): self.__pc = PatternController(context = self.context) self.__sc = ShowController(context = self.context) self.__tc = TrackController(context = self.context) - + + self.pattern_id = patternId self.pattern_obj = self.__pc.getPatternDescriptor(patternId) if patternId is not None else {} + self.show_obj = self.__sc.getShowDesciptor(showId) if showId is not None else {} @@ -106,7 +108,7 @@ class PatternDetailsScreen(Screen): self.audioStreamsTable.clear() - trackIds = self.__tc.findAllTracks(self.pattern_obj['id']) + trackIds = self.__tc.findAllTracks(self.pattern_id) #! id missing for audioTrackId in trackIds['audio']: @@ -126,7 +128,7 @@ class PatternDetailsScreen(Screen): self.audioStreamsTable.clear() - trackIds = self.__tc.findAllTracks(self.pattern_obj['id']) + trackIds = self.__tc.findAllTracks(self.pattern_id) for audioTrackId in trackIds['audio']: @@ -157,6 +159,7 @@ class PatternDetailsScreen(Screen): self.updateAudioTracks() self.updateSubtitleTracks() + def compose(self): self.audioStreamsTable = DataTable(classes="five") @@ -306,18 +309,30 @@ class PatternDetailsScreen(Screen): # Check if the button pressed is the one we are interested in if event.button.id == "save_button": - pattern = self.getPatternFromInput() + patternDescriptor = {} + patternDescriptor['show_id'] = self.show_obj['id'] + patternDescriptor['pattern'] = self.getPatternFromInput() - if self.__pc.updatePattern(self.show_obj['id'], pattern): + if self.pattern_obj: - screenResult = {} - screenResult['show_id'] = self.show_obj['id'] - screenResult['pattern'] = pattern + if self.pattern_id is None: + #TODO: Meldung + self.app.pop_screen() + else: + if self.__pc.updatePattern(self.pattern_id, patternDescriptor): + self.dismiss(patternDescriptor) + else: + #TODO: Meldung + self.app.pop_screen() - self.dismiss(screenResult) else: - #TODO: Meldung - self.app.pop_screen() + if self.__pc.addPattern(patternDescriptor): + self.dismiss(patternDescriptor) + else: + #TODO: Meldung + self.app.pop_screen() + + if event.button.id == "cancel_button": self.app.pop_screen() @@ -329,27 +344,27 @@ class PatternDetailsScreen(Screen): #self.pattern_obj if event.button.id == "button_add_audio_stream": - self.app.push_screen(TrackDetailsScreen(trackType = TrackType.AUDIO, patternId = self.pattern_obj['id'], subIndex = len(self.audioStreamsTable.rows)), self.handle_add_stream) + self.app.push_screen(TrackDetailsScreen(trackType = TrackType.AUDIO, patternId = self.pattern_obj['id'], subIndex = len(self.audioStreamsTable.rows)), self.handle_add_track) if event.button.id == "button_edit_audio_stream": - self.app.push_screen(TrackDetailsScreen(trackId = self.getSelectedAudioTrackId()), self.handle_edit_stream) + self.app.push_screen(TrackDetailsScreen(trackId = self.getSelectedAudioTrackId()), self.handle_edit_track) selectedAudioTrackId = self.getSelectedAudioTrackId() if selectedAudioTrackId is not None: if event.button.id == "button_delete_audio_stream": - self.app.push_screen(TrackDeleteScreen(trackId = selectedAudioTrackId), self.handle_delete_stream) + self.app.push_screen(TrackDeleteScreen(trackId = selectedAudioTrackId), self.handle_delete_track) if event.button.id == "button_add_subtitle_stream": - self.app.push_screen(TrackDetailsScreen(trackType = TrackType.SUBTITLE, patternId = self.pattern_obj['id'], subIndex = len(self.subtitleStreamsTable.rows)), self.handle_add_stream) + self.app.push_screen(TrackDetailsScreen(trackType = TrackType.SUBTITLE, patternId = self.pattern_obj['id'], subIndex = len(self.subtitleStreamsTable.rows)), self.handle_add_track) if event.button.id == "button_edit_subtitle_stream": - self.app.push_screen(TrackDetailsScreen(trackId = self.getSelectedSubtitleTrackId()), self.handle_edit_stream) + self.app.push_screen(TrackDetailsScreen(trackId = self.getSelectedSubtitleTrackId()), self.handle_edit_track) selectedSubtitleTrackId = self.getSelectedSubtitleTrackId() if selectedSubtitleTrackId is not None: if event.button.id == "button_delete_subtitle_stream": - self.app.push_screen(TrackDeleteScreen(trackId = selectedSubtitleTrackId), self.handle_delete_stream) + self.app.push_screen(TrackDeleteScreen(trackId = selectedSubtitleTrackId), self.handle_delete_track) - def handle_add_stream(self, trackDescriptor): + def handle_add_track(self, trackDescriptor): dispoList = trackDescriptor['disposition_list'] @@ -376,7 +391,7 @@ class PatternDetailsScreen(Screen): self.subtitleStreamsTable.add_row(*map(str, row)) - def handle_edit_stream(self, trackDescriptor): + def handle_edit_track(self, trackDescriptor): try: if trackDescriptor['type'] == TrackType.AUDIO: @@ -401,7 +416,7 @@ class PatternDetailsScreen(Screen): pass - def handle_delete_stream(self, trackDescriptor): + def handle_delete_track(self, trackDescriptor): try: if trackDescriptor['type'] == TrackType.AUDIO: diff --git a/bin/ffx/show_details_screen.py b/bin/ffx/show_details_screen.py index 194e17b..6afd855 100644 --- a/bin/ffx/show_details_screen.py +++ b/bin/ffx/show_details_screen.py @@ -23,9 +23,9 @@ class ShowDetailsScreen(Screen): CSS = """ Grid { - grid-size: 2 14; + grid-size: 5 14; grid-rows: 2 2 2 2 2 2 2 2 2 2 2 6 2 2; - grid-columns: 30 90; + grid-columns: 30 30 30 30 30; height: 100%; width: 100%; padding: 1; @@ -50,6 +50,15 @@ class ShowDetailsScreen(Screen): .two { column-span: 2; } + .three { + column-span: 3; + } + .four { + column-span: 4; + } + .five { + column-span: 5; + } .box { height: 100%; @@ -114,7 +123,7 @@ class ShowDetailsScreen(Screen): self.query_one("#indicator_episode_digits_input", Input).value = "2" - def getSelectedPattern(self): + def getSelectedPatternDescriptor(self): selectedPattern = {} @@ -127,6 +136,7 @@ class ShowDetailsScreen(Screen): if row_key is not None: selected_row_data = self.patternTable.get_row(row_key) + selectedPattern['show_id'] = self.show_obj['id'] selectedPattern['pattern'] = str(selected_row_data[0]) except CellDoesNotExist: @@ -140,7 +150,7 @@ class ShowDetailsScreen(Screen): def action_add_pattern(self): if self.show_obj: - self.app.push_screen(PatternDetailsScreen(showId = self.show_obj['id']), self.handle_add_pattern) + self.app.push_screen(PatternDetailsScreen(showId = self.show_obj['id']), self.handle_add_pattern) # <- def handle_add_pattern(self, screenResult): @@ -151,31 +161,36 @@ class ShowDetailsScreen(Screen): def action_edit_pattern(self): - selectedPattern = self.getSelectedPattern() + selectedPatternDescriptor = self.getSelectedPatternDescriptor() - if selectedPattern: - - selectedPatternId = self.__pc.findPattern(self.show_obj['id'], selectedPattern['pattern']) + if selectedPatternDescriptor: + + selectedPatternId = self.__pc.findPattern(selectedPatternDescriptor) if selectedPatternId is None: raise click.ClickException(f"ShowDetailsScreen.action_edit_pattern(): Pattern to remove has no id") - self.app.push_screen(PatternDetailsScreen(patternId = selectedPatternId, showId = self.show_obj['id']), self.handle_edit_pattern) + self.app.push_screen(PatternDetailsScreen(patternId = selectedPatternId, showId = self.show_obj['id']), self.handle_edit_pattern) # <- def handle_edit_pattern(self, screenResult): - pass - #pattern = (screenResult['pattern'],) - #self.patternTable.add_row(*map(str, pattern)) + + try: + + row_key, col_key = self.patternTable.coordinate_to_cell_key(self.patternTable.cursor_coordinate) + self.patternTable.update_cell(row_key, self.column_key_pattern, screenResult['pattern']) + + except CellDoesNotExist: + pass def action_remove_pattern(self): - selectedPattern = self.getSelectedPattern() + selectedPatternDescriptor = self.getSelectedPatternDescriptor() - if selectedPattern: + if selectedPatternDescriptor: - selectedPatternId = self.__pc.findPattern(self.show_obj['id'], selectedPattern['pattern']) + selectedPatternId = self.__pc.findPattern(selectedPatternDescriptor) if selectedPatternId is None: raise click.ClickException(f"ShowDetailsScreen.action_remove_pattern(): Pattern to remove has no id") @@ -196,10 +211,10 @@ class ShowDetailsScreen(Screen): def compose(self): # Create the DataTable widget - self.patternTable = DataTable(classes="two") + self.patternTable = DataTable(classes="five") # Define the columns with headers - self.column_key_id = self.patternTable.add_column("Pattern", width=90) + self.column_key_pattern = self.patternTable.add_column("Pattern", width=150) #self.column_key_name = self.patternTable.add_column("Name", width=50) #self.column_key_year = self.patternTable.add_column("Year", width=10) @@ -211,52 +226,52 @@ class ShowDetailsScreen(Screen): with Grid(): # 1 - yield Static("Show" if self.show_obj else "New Show", id="toplabel", classes="two") + yield Static("Show" if self.show_obj else "New Show", id="toplabel", classes="five") # 2 yield Static("ID") if self.show_obj: - yield Static("", id="id_wdg") + yield Static("", id="id_wdg", classes="four") else: - yield Input(type="integer", id="id_wdg") + yield Input(type="integer", id="id_wdg", classes="four") # 3 yield Static("Name") - yield Input(type="text", id="name_input") + yield Input(type="text", id="name_input", classes="four") # 4 yield Static("Year") - yield Input(type="integer", id="year_input") + yield Input(type="integer", id="year_input", classes="four") #5 - yield Static(" ", classes="two") + yield Static(" ", classes="five") #6 yield Static("Index Season Digits") - yield Input(type="integer", id="index_season_digits_input") + yield Input(type="integer", id="index_season_digits_input", classes="four") #7 yield Static("Index Episode Digits") - yield Input(type="integer", id="index_episode_digits_input") + yield Input(type="integer", id="index_episode_digits_input", classes="four") #8 yield Static("Indicator Season Digits") - yield Input(type="integer", id="indicator_season_digits_input") + yield Input(type="integer", id="indicator_season_digits_input", classes="four") #9 yield Static("Indicator Edisode Digits") - yield Input(type="integer", id="indicator_episode_digits_input") + yield Input(type="integer", id="indicator_episode_digits_input", classes="four") # 10 - yield Static(" ", classes="two") + yield Static(" ", classes="five") # 11 - yield Static("File patterns", classes="two") + yield Static("File patterns", classes="five") # 12 yield self.patternTable # 13 - yield Static(" ", classes="two") + yield Static(" ", classes="five") # 14 yield Button("Save", id="save_button")