Fix TUI widgets color bleedthru
This commit is contained in:
@@ -8,10 +8,9 @@ from ffx.audio_layout import AudioLayout
|
|||||||
|
|
||||||
from .show_details_screen import ShowDetailsScreen
|
from .show_details_screen import ShowDetailsScreen
|
||||||
from .pattern_details_screen import PatternDetailsScreen
|
from .pattern_details_screen import PatternDetailsScreen
|
||||||
from .screen_support import build_screen_bootstrap, build_screen_controllers
|
from .screen_support import build_screen_bootstrap, build_screen_controllers, populate_tag_table
|
||||||
|
|
||||||
from ffx.track_type import TrackType
|
from ffx.track_type import TrackType
|
||||||
from ffx.track_codec import TrackCodec
|
|
||||||
from ffx.model.track import Track
|
from ffx.model.track import Track
|
||||||
|
|
||||||
from ffx.track_disposition import TrackDisposition
|
from ffx.track_disposition import TrackDisposition
|
||||||
@@ -25,7 +24,7 @@ from ffx.file_properties import FileProperties
|
|||||||
|
|
||||||
from ffx.media_descriptor_change_set import MediaDescriptorChangeSet
|
from ffx.media_descriptor_change_set import MediaDescriptorChangeSet
|
||||||
|
|
||||||
from ffx.helper import formatRichColor, DIFF_ADDED_KEY, DIFF_CHANGED_KEY, DIFF_REMOVED_KEY, DIFF_UNCHANGED_KEY
|
from ffx.helper import DIFF_ADDED_KEY, DIFF_CHANGED_KEY, DIFF_REMOVED_KEY, DIFF_UNCHANGED_KEY
|
||||||
|
|
||||||
|
|
||||||
# Screen[dict[int, str, int]]
|
# Screen[dict[int, str, int]]
|
||||||
@@ -156,6 +155,9 @@ class MediaDetailsScreen(Screen):
|
|||||||
raise click.ClickException(f"MediaDetailsScreen.__init__(): Argument 'filename' is required to be provided for command 'inspect'")
|
raise click.ClickException(f"MediaDetailsScreen.__init__(): Argument 'filename' is required to be provided for command 'inspect'")
|
||||||
|
|
||||||
self.__mediaFilename = self.context['arguments']['filename']
|
self.__mediaFilename = self.context['arguments']['filename']
|
||||||
|
self.__showRowData: dict[object, ShowDescriptor | None] = {}
|
||||||
|
self.__trackRowData: dict[object, TrackDescriptor] = {}
|
||||||
|
self.__sourceMediaTagRowData: dict[object, tuple[str, str]] = {}
|
||||||
|
|
||||||
if not os.path.isfile(self.__mediaFilename):
|
if not os.path.isfile(self.__mediaFilename):
|
||||||
raise click.ClickException(f"MediaDetailsScreen.__init__(): Media file {self.__mediaFilename} does not exist")
|
raise click.ClickException(f"MediaDetailsScreen.__init__(): Media file {self.__mediaFilename} does not exist")
|
||||||
@@ -167,37 +169,49 @@ class MediaDetailsScreen(Screen):
|
|||||||
"""Remove show entry from DataTable.
|
"""Remove show entry from DataTable.
|
||||||
Removes the <New show> entry if showId is not set"""
|
Removes the <New show> entry if showId is not set"""
|
||||||
|
|
||||||
for rowKey, row in self.showsTable.rows.items(): # dict[RowKey, Row]
|
for row_key, show_descriptor in list(self.__showRowData.items()):
|
||||||
|
if (
|
||||||
rowData = self.showsTable.get_row(rowKey)
|
(showId == -1 and show_descriptor is None)
|
||||||
|
or (
|
||||||
try:
|
show_descriptor is not None
|
||||||
if (showId == -1 and rowData[0] == ' '
|
and show_descriptor.getId() == showId
|
||||||
or showId == int(rowData[0])):
|
)
|
||||||
self.showsTable.remove_row(rowKey)
|
):
|
||||||
return
|
self.showsTable.remove_row(row_key)
|
||||||
except:
|
self.__showRowData.pop(row_key, None)
|
||||||
continue
|
return
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
def getRowIndexFromShowId(self, showId : int = -1) -> int:
|
def getRowIndexFromShowId(self, showId : int = -1) -> int:
|
||||||
"""Find the index of the row where the value in the specified column matches the target_value."""
|
"""Find the index of the row where the value in the specified column matches the target_value."""
|
||||||
|
|
||||||
for rowKey, row in self.showsTable.rows.items(): # dict[RowKey, Row]
|
for row_key, show_descriptor in self.__showRowData.items():
|
||||||
|
if (
|
||||||
rowData = self.showsTable.get_row(rowKey)
|
(showId == -1 and show_descriptor is None)
|
||||||
|
or (
|
||||||
try:
|
show_descriptor is not None
|
||||||
if ((showId == -1 and rowData[0] == ' ')
|
and show_descriptor.getId() == showId
|
||||||
or showId == int(rowData[0])):
|
)
|
||||||
return int(self.showsTable.get_row_index(rowKey))
|
):
|
||||||
except:
|
return int(self.showsTable.get_row_index(row_key))
|
||||||
continue
|
|
||||||
|
|
||||||
return None
|
return None
|
||||||
|
|
||||||
|
|
||||||
|
def _add_show_row(self, show_descriptor: ShowDescriptor | None):
|
||||||
|
if show_descriptor is None:
|
||||||
|
row_key = self.showsTable.add_row(' ', '<New show>', ' ')
|
||||||
|
else:
|
||||||
|
row_key = self.showsTable.add_row(
|
||||||
|
str(show_descriptor.getId()),
|
||||||
|
str(show_descriptor.getName()),
|
||||||
|
str(show_descriptor.getYear()),
|
||||||
|
)
|
||||||
|
self.__showRowData[row_key] = show_descriptor
|
||||||
|
return row_key
|
||||||
|
|
||||||
|
|
||||||
def loadProperties(self):
|
def loadProperties(self):
|
||||||
|
|
||||||
self.__mediaFileProperties = FileProperties(self.context, self.__mediaFilename)
|
self.__mediaFileProperties = FileProperties(self.context, self.__mediaFilename)
|
||||||
@@ -314,23 +328,17 @@ class MediaDetailsScreen(Screen):
|
|||||||
def on_mount(self):
|
def on_mount(self):
|
||||||
|
|
||||||
if self.__currentPattern is None:
|
if self.__currentPattern is None:
|
||||||
row = (' ', '<New show>', ' ') # Convert each element to a string before adding
|
self._add_show_row(None)
|
||||||
self.showsTable.add_row(*map(str, row))
|
|
||||||
|
|
||||||
for show in self.__sc.getAllShows():
|
for show in self.__sc.getAllShows():
|
||||||
row = (int(show.id), show.name, show.year) # Convert each element to a string before adding
|
self._add_show_row(show.getDescriptor(self.context))
|
||||||
self.showsTable.add_row(*map(str, row))
|
|
||||||
|
|
||||||
for mediaTagKey, mediaTagValue in self.__sourceMediaDescriptor.getTags().items():
|
self.__sourceMediaTagRowData = populate_tag_table(
|
||||||
|
self.mediaTagsTable,
|
||||||
textColor = None
|
self.__sourceMediaDescriptor.getTags(),
|
||||||
if mediaTagKey in self.__ignoreGlobalKeys:
|
ignore_keys=self.__ignoreGlobalKeys,
|
||||||
textColor = 'blue'
|
remove_keys=self.__removeGlobalKeys,
|
||||||
if mediaTagKey in self.__removeGlobalKeys:
|
)
|
||||||
textColor = 'red'
|
|
||||||
|
|
||||||
row = (formatRichColor(mediaTagKey, textColor), formatRichColor(mediaTagValue, textColor)) # Convert each element to a string before adding
|
|
||||||
self.mediaTagsTable.add_row(*map(str, row))
|
|
||||||
|
|
||||||
self.updateTracks()
|
self.updateTracks()
|
||||||
|
|
||||||
@@ -362,6 +370,7 @@ class MediaDetailsScreen(Screen):
|
|||||||
def updateTracks(self):
|
def updateTracks(self):
|
||||||
|
|
||||||
self.tracksTable.clear()
|
self.tracksTable.clear()
|
||||||
|
self.__trackRowData = {}
|
||||||
|
|
||||||
# trackDescriptorList = self.__sourceMediaDescriptor.getAllTrackDescriptors()
|
# trackDescriptorList = self.__sourceMediaDescriptor.getAllTrackDescriptors()
|
||||||
trackDescriptorList = self.__sourceMediaDescriptor.getTrackDescriptors()
|
trackDescriptorList = self.__sourceMediaDescriptor.getTrackDescriptors()
|
||||||
@@ -387,7 +396,8 @@ class MediaDetailsScreen(Screen):
|
|||||||
'Yes' if TrackDisposition.DEFAULT in dispoSet else 'No',
|
'Yes' if TrackDisposition.DEFAULT in dispoSet else 'No',
|
||||||
'Yes' if TrackDisposition.FORCED in dispoSet else 'No')
|
'Yes' if TrackDisposition.FORCED in dispoSet else 'No')
|
||||||
|
|
||||||
self.tracksTable.add_row(*map(str, row))
|
row_key = self.tracksTable.add_row(*map(str, row))
|
||||||
|
self.__trackRowData[row_key] = td
|
||||||
|
|
||||||
typeCounter[trackType] += 1
|
typeCounter[trackType] += 1
|
||||||
|
|
||||||
@@ -529,17 +539,7 @@ class MediaDetailsScreen(Screen):
|
|||||||
row_key, col_key = self.tracksTable.coordinate_to_cell_key(self.tracksTable.cursor_coordinate)
|
row_key, col_key = self.tracksTable.coordinate_to_cell_key(self.tracksTable.cursor_coordinate)
|
||||||
|
|
||||||
if row_key is not None:
|
if row_key is not None:
|
||||||
selected_track_data = self.tracksTable.get_row(row_key)
|
return self.__trackRowData.get(row_key)
|
||||||
|
|
||||||
kwargs = {}
|
|
||||||
kwargs[TrackDescriptor.CONTEXT_KEY] = self.context
|
|
||||||
kwargs[TrackDescriptor.INDEX_KEY] = int(selected_track_data[0])
|
|
||||||
kwargs[TrackDescriptor.TRACK_TYPE_KEY] = TrackType.fromLabel(selected_track_data[1])
|
|
||||||
kwargs[TrackDescriptor.SUB_INDEX_KEY] = int(selected_track_data[2])
|
|
||||||
kwargs[TrackDescriptor.CODEC_KEY] = TrackCodec.fromLabel(selected_track_data[3])
|
|
||||||
kwargs[TrackDescriptor.AUDIO_LAYOUT_KEY] = AudioLayout.fromLabel(selected_track_data[4])
|
|
||||||
|
|
||||||
return TrackDescriptor(**kwargs)
|
|
||||||
else:
|
else:
|
||||||
return None
|
return None
|
||||||
|
|
||||||
@@ -554,20 +554,7 @@ class MediaDetailsScreen(Screen):
|
|||||||
row_key, col_key = self.showsTable.coordinate_to_cell_key(self.showsTable.cursor_coordinate)
|
row_key, col_key = self.showsTable.coordinate_to_cell_key(self.showsTable.cursor_coordinate)
|
||||||
|
|
||||||
if row_key is not None:
|
if row_key is not None:
|
||||||
selected_row_data = self.showsTable.get_row(row_key)
|
return self.__showRowData.get(row_key)
|
||||||
|
|
||||||
try:
|
|
||||||
kwargs = {}
|
|
||||||
|
|
||||||
kwargs[ShowDescriptor.CONTEXT_KEY] = self.context
|
|
||||||
kwargs[ShowDescriptor.ID_KEY] = int(selected_row_data[0])
|
|
||||||
kwargs[ShowDescriptor.NAME_KEY] = str(selected_row_data[1])
|
|
||||||
kwargs[ShowDescriptor.YEAR_KEY] = int(selected_row_data[2])
|
|
||||||
|
|
||||||
return ShowDescriptor(**kwargs)
|
|
||||||
|
|
||||||
except ValueError:
|
|
||||||
return None
|
|
||||||
|
|
||||||
except CellDoesNotExist:
|
except CellDoesNotExist:
|
||||||
return None
|
return None
|
||||||
@@ -583,8 +570,7 @@ class MediaDetailsScreen(Screen):
|
|||||||
|
|
||||||
showRowIndex = self.getRowIndexFromShowId(showDescriptor.getId())
|
showRowIndex = self.getRowIndexFromShowId(showDescriptor.getId())
|
||||||
if showRowIndex is None:
|
if showRowIndex is None:
|
||||||
show = (showDescriptor.getId(), showDescriptor.getName(), showDescriptor.getYear())
|
self._add_show_row(showDescriptor)
|
||||||
self.showsTable.add_row(*map(str, show))
|
|
||||||
|
|
||||||
showRowIndex = self.getRowIndexFromShowId(showDescriptor.getId())
|
showRowIndex = self.getRowIndexFromShowId(showDescriptor.getId())
|
||||||
if showRowIndex is not None:
|
if showRowIndex is not None:
|
||||||
|
|||||||
@@ -14,7 +14,11 @@ from .shifted_season_details_screen import ShiftedSeasonDetailsScreen
|
|||||||
|
|
||||||
from .tag_details_screen import TagDetailsScreen
|
from .tag_details_screen import TagDetailsScreen
|
||||||
from .tag_delete_screen import TagDeleteScreen
|
from .tag_delete_screen import TagDeleteScreen
|
||||||
from .screen_support import build_screen_bootstrap, build_screen_controllers
|
from .screen_support import (
|
||||||
|
build_screen_bootstrap,
|
||||||
|
build_screen_controllers,
|
||||||
|
populate_tag_table,
|
||||||
|
)
|
||||||
|
|
||||||
from ffx.track_type import TrackType
|
from ffx.track_type import TrackType
|
||||||
|
|
||||||
@@ -28,8 +32,6 @@ from ffx.iso_language import IsoLanguage
|
|||||||
from ffx.audio_layout import AudioLayout
|
from ffx.audio_layout import AudioLayout
|
||||||
from ffx.model.shifted_season import ShiftedSeason
|
from ffx.model.shifted_season import ShiftedSeason
|
||||||
|
|
||||||
from ffx.helper import formatRichColor, removeRichColor
|
|
||||||
|
|
||||||
|
|
||||||
# Screen[dict[int, str, int]]
|
# Screen[dict[int, str, int]]
|
||||||
class PatternDetailsScreen(Screen):
|
class PatternDetailsScreen(Screen):
|
||||||
@@ -130,11 +132,15 @@ class PatternDetailsScreen(Screen):
|
|||||||
self.__showDescriptor = self.__sc.getShowDescriptor(showId) if showId is not None else None
|
self.__showDescriptor = self.__sc.getShowDescriptor(showId) if showId is not None else None
|
||||||
self.__draftTracks : List[TrackDescriptor] = []
|
self.__draftTracks : List[TrackDescriptor] = []
|
||||||
self.__draftTags : dict[str, str] = {}
|
self.__draftTags : dict[str, str] = {}
|
||||||
|
self.__trackRowData: dict[object, TrackDescriptor] = {}
|
||||||
|
self.__tagRowData: dict[object, tuple[str, str]] = {}
|
||||||
|
self.__shiftedSeasonRowData: dict[object, dict[str, int | None]] = {}
|
||||||
|
|
||||||
|
|
||||||
def updateTracks(self):
|
def updateTracks(self):
|
||||||
|
|
||||||
self.tracksTable.clear()
|
self.tracksTable.clear()
|
||||||
|
self.__trackRowData = {}
|
||||||
|
|
||||||
tracks = self.getCurrentTrackDescriptors()
|
tracks = self.getCurrentTrackDescriptors()
|
||||||
|
|
||||||
@@ -165,7 +171,8 @@ class PatternDetailsScreen(Screen):
|
|||||||
'Yes' if TrackDisposition.FORCED in dispoSet else 'No',
|
'Yes' if TrackDisposition.FORCED in dispoSet else 'No',
|
||||||
td.getSourceIndex())
|
td.getSourceIndex())
|
||||||
|
|
||||||
self.tracksTable.add_row(*map(str, row))
|
row_key = self.tracksTable.add_row(*map(str, row))
|
||||||
|
self.__trackRowData[row_key] = td
|
||||||
|
|
||||||
typeCounter[trackType] += 1
|
typeCounter[trackType] += 1
|
||||||
|
|
||||||
@@ -243,29 +250,23 @@ class PatternDetailsScreen(Screen):
|
|||||||
|
|
||||||
|
|
||||||
def updateTags(self):
|
def updateTags(self):
|
||||||
|
|
||||||
self.tagsTable.clear()
|
|
||||||
|
|
||||||
tags = (
|
tags = (
|
||||||
self.__tac.findAllMediaTags(self.__pattern.getId())
|
self.__tac.findAllMediaTags(self.__pattern.getId())
|
||||||
if self.__pattern is not None
|
if self.__pattern is not None
|
||||||
else self.__draftTags
|
else self.__draftTags
|
||||||
)
|
)
|
||||||
|
|
||||||
for tagKey, tagValue in tags.items():
|
self.__tagRowData = populate_tag_table(
|
||||||
|
self.tagsTable,
|
||||||
textColor = None
|
tags,
|
||||||
if tagKey in self.__ignoreGlobalKeys:
|
ignore_keys=self.__ignoreGlobalKeys,
|
||||||
textColor = 'blue'
|
remove_keys=self.__removeGlobalKeys,
|
||||||
if tagKey in self.__removeGlobalKeys:
|
)
|
||||||
textColor = 'red'
|
|
||||||
|
|
||||||
row = (formatRichColor(tagKey, textColor), formatRichColor(tagValue, textColor))
|
|
||||||
self.tagsTable.add_row(*map(str, row))
|
|
||||||
|
|
||||||
def updateShiftedSeasons(self):
|
def updateShiftedSeasons(self):
|
||||||
|
|
||||||
self.shiftedSeasonsTable.clear()
|
self.shiftedSeasonsTable.clear()
|
||||||
|
self.__shiftedSeasonRowData = {}
|
||||||
|
|
||||||
if self.__pattern is None:
|
if self.__pattern is None:
|
||||||
return
|
return
|
||||||
@@ -273,6 +274,7 @@ class PatternDetailsScreen(Screen):
|
|||||||
shiftedSeason: ShiftedSeason
|
shiftedSeason: ShiftedSeason
|
||||||
for shiftedSeason in self.__ssc.getShiftedSeasonSiblings(patternId=self.__pattern.getId()):
|
for shiftedSeason in self.__ssc.getShiftedSeasonSiblings(patternId=self.__pattern.getId()):
|
||||||
shiftedSeasonObj = shiftedSeason.getObj()
|
shiftedSeasonObj = shiftedSeason.getObj()
|
||||||
|
shiftedSeasonObj['id'] = shiftedSeason.getId()
|
||||||
|
|
||||||
firstEpisode = shiftedSeasonObj['first_episode']
|
firstEpisode = shiftedSeasonObj['first_episode']
|
||||||
firstEpisodeStr = str(firstEpisode) if firstEpisode != -1 else ''
|
firstEpisodeStr = str(firstEpisode) if firstEpisode != -1 else ''
|
||||||
@@ -288,7 +290,8 @@ class PatternDetailsScreen(Screen):
|
|||||||
shiftedSeasonObj['episode_offset'],
|
shiftedSeasonObj['episode_offset'],
|
||||||
)
|
)
|
||||||
|
|
||||||
self.shiftedSeasonsTable.add_row(*map(str, row))
|
row_key = self.shiftedSeasonsTable.add_row(*map(str, row))
|
||||||
|
self.__shiftedSeasonRowData[row_key] = shiftedSeasonObj
|
||||||
|
|
||||||
def getSelectedShiftedSeasonObjFromInput(self):
|
def getSelectedShiftedSeasonObjFromInput(self):
|
||||||
|
|
||||||
@@ -300,29 +303,7 @@ class PatternDetailsScreen(Screen):
|
|||||||
)
|
)
|
||||||
|
|
||||||
if row_key is not None:
|
if row_key is not None:
|
||||||
selected_row_data = self.shiftedSeasonsTable.get_row(row_key)
|
shiftedSeasonObj = dict(self.__shiftedSeasonRowData.get(row_key, {}))
|
||||||
|
|
||||||
def parse_int_or_default(value: str, default: int) -> int:
|
|
||||||
try:
|
|
||||||
return int(value)
|
|
||||||
except (TypeError, ValueError):
|
|
||||||
return default
|
|
||||||
|
|
||||||
shiftedSeasonObj['original_season'] = int(selected_row_data[0])
|
|
||||||
shiftedSeasonObj['first_episode'] = parse_int_or_default(selected_row_data[1], -1)
|
|
||||||
shiftedSeasonObj['last_episode'] = parse_int_or_default(selected_row_data[2], -1)
|
|
||||||
shiftedSeasonObj['season_offset'] = parse_int_or_default(selected_row_data[3], 0)
|
|
||||||
shiftedSeasonObj['episode_offset'] = parse_int_or_default(selected_row_data[4], 0)
|
|
||||||
|
|
||||||
if self.__pattern is not None:
|
|
||||||
shiftedSeasonId = self.__ssc.findShiftedSeason(
|
|
||||||
patternId=self.__pattern.getId(),
|
|
||||||
originalSeason=shiftedSeasonObj['original_season'],
|
|
||||||
firstEpisode=shiftedSeasonObj['first_episode'],
|
|
||||||
lastEpisode=shiftedSeasonObj['last_episode'],
|
|
||||||
)
|
|
||||||
if shiftedSeasonId is not None:
|
|
||||||
shiftedSeasonObj['id'] = shiftedSeasonId
|
|
||||||
|
|
||||||
except CellDoesNotExist:
|
except CellDoesNotExist:
|
||||||
pass
|
pass
|
||||||
@@ -513,15 +494,7 @@ class PatternDetailsScreen(Screen):
|
|||||||
row_key, col_key = self.tracksTable.coordinate_to_cell_key(self.tracksTable.cursor_coordinate)
|
row_key, col_key = self.tracksTable.coordinate_to_cell_key(self.tracksTable.cursor_coordinate)
|
||||||
|
|
||||||
if row_key is not None:
|
if row_key is not None:
|
||||||
selected_track_data = self.tracksTable.get_row(row_key)
|
return self.__trackRowData.get(row_key)
|
||||||
|
|
||||||
trackIndex = int(selected_track_data[0])
|
|
||||||
trackSubIndex = int(selected_track_data[2])
|
|
||||||
|
|
||||||
for trackDescriptor in self.getCurrentTrackDescriptors():
|
|
||||||
if (trackDescriptor.getIndex() == trackIndex
|
|
||||||
and trackDescriptor.getSubIndex() == trackSubIndex):
|
|
||||||
return trackDescriptor
|
|
||||||
|
|
||||||
return None
|
return None
|
||||||
|
|
||||||
@@ -539,12 +512,7 @@ class PatternDetailsScreen(Screen):
|
|||||||
row_key, col_key = self.tagsTable.coordinate_to_cell_key(self.tagsTable.cursor_coordinate)
|
row_key, col_key = self.tagsTable.coordinate_to_cell_key(self.tagsTable.cursor_coordinate)
|
||||||
|
|
||||||
if row_key is not None:
|
if row_key is not None:
|
||||||
selected_tag_data = self.tagsTable.get_row(row_key)
|
return self.__tagRowData.get(row_key)
|
||||||
|
|
||||||
tagKey = removeRichColor(selected_tag_data[0])
|
|
||||||
tagValue = removeRichColor(selected_tag_data[1])
|
|
||||||
|
|
||||||
return tagKey, tagValue
|
|
||||||
|
|
||||||
else:
|
else:
|
||||||
return None
|
return None
|
||||||
|
|||||||
@@ -1,7 +1,9 @@
|
|||||||
from __future__ import annotations
|
from __future__ import annotations
|
||||||
|
|
||||||
|
from collections.abc import Mapping
|
||||||
from dataclasses import dataclass
|
from dataclasses import dataclass
|
||||||
|
|
||||||
|
from .helper import formatRichColor
|
||||||
from .pattern_controller import PatternController
|
from .pattern_controller import PatternController
|
||||||
from .show_controller import ShowController
|
from .show_controller import ShowController
|
||||||
from .shifted_season_controller import ShiftedSeasonController
|
from .shifted_season_controller import ShiftedSeasonController
|
||||||
@@ -63,3 +65,34 @@ def build_screen_controllers(
|
|||||||
controllers['shifted_season'] = ShiftedSeasonController(context=context)
|
controllers['shifted_season'] = ShiftedSeasonController(context=context)
|
||||||
|
|
||||||
return controllers
|
return controllers
|
||||||
|
|
||||||
|
|
||||||
|
def populate_tag_table(
|
||||||
|
table,
|
||||||
|
tags: Mapping[str, object],
|
||||||
|
*,
|
||||||
|
ignore_keys: list[str],
|
||||||
|
remove_keys: list[str],
|
||||||
|
) -> dict[object, tuple[str, str]]:
|
||||||
|
"""Render display rows while keeping raw tag data addressable by row key."""
|
||||||
|
|
||||||
|
table.clear()
|
||||||
|
|
||||||
|
row_data: dict[object, tuple[str, str]] = {}
|
||||||
|
for tag_key, tag_value in tags.items():
|
||||||
|
raw_key = str(tag_key)
|
||||||
|
raw_value = str(tag_value)
|
||||||
|
|
||||||
|
text_color = None
|
||||||
|
if raw_key in ignore_keys:
|
||||||
|
text_color = "blue"
|
||||||
|
if raw_key in remove_keys:
|
||||||
|
text_color = "red"
|
||||||
|
|
||||||
|
row_key = table.add_row(
|
||||||
|
str(formatRichColor(raw_key, text_color)),
|
||||||
|
str(formatRichColor(raw_value, text_color)),
|
||||||
|
)
|
||||||
|
row_data[row_key] = (raw_key, raw_value)
|
||||||
|
|
||||||
|
return row_data
|
||||||
|
|||||||
@@ -108,12 +108,45 @@ class ShowDetailsScreen(Screen):
|
|||||||
self.__ssc = controllers['shifted_season']
|
self.__ssc = controllers['shifted_season']
|
||||||
|
|
||||||
self.__showDescriptor = self.__sc.getShowDescriptor(showId) if showId is not None else None
|
self.__showDescriptor = self.__sc.getShowDescriptor(showId) if showId is not None else None
|
||||||
|
self.__patternRowData: dict[object, dict[str, object]] = {}
|
||||||
|
self.__shiftedSeasonRowData: dict[object, dict[str, int | None]] = {}
|
||||||
|
|
||||||
|
|
||||||
|
def _add_pattern_row(self, *, pattern_id: int | None, pattern_text: str):
|
||||||
|
row_key = self.patternTable.add_row(str(pattern_text))
|
||||||
|
self.__patternRowData[row_key] = {
|
||||||
|
'id': pattern_id,
|
||||||
|
'show_id': self.__showDescriptor.getId() if self.__showDescriptor is not None else None,
|
||||||
|
'pattern': str(pattern_text),
|
||||||
|
}
|
||||||
|
return row_key
|
||||||
|
|
||||||
|
|
||||||
|
def _add_shifted_season_row(self, shifted_season_obj: dict[str, int | None]):
|
||||||
|
firstEpisode = shifted_season_obj['first_episode']
|
||||||
|
firstEpisodeStr = str(firstEpisode) if firstEpisode != -1 else ''
|
||||||
|
|
||||||
|
lastEpisode = shifted_season_obj['last_episode']
|
||||||
|
lastEpisodeStr = str(lastEpisode) if lastEpisode != -1 else ''
|
||||||
|
|
||||||
|
row = (
|
||||||
|
shifted_season_obj['original_season'],
|
||||||
|
firstEpisodeStr,
|
||||||
|
lastEpisodeStr,
|
||||||
|
shifted_season_obj['season_offset'],
|
||||||
|
shifted_season_obj['episode_offset'],
|
||||||
|
)
|
||||||
|
|
||||||
|
row_key = self.shiftedSeasonsTable.add_row(*map(str, row))
|
||||||
|
self.__shiftedSeasonRowData[row_key] = dict(shifted_season_obj)
|
||||||
|
return row_key
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
def updateShiftedSeasons(self):
|
def updateShiftedSeasons(self):
|
||||||
|
|
||||||
self.shiftedSeasonsTable.clear()
|
self.shiftedSeasonsTable.clear()
|
||||||
|
self.__shiftedSeasonRowData = {}
|
||||||
|
|
||||||
if not self.__showDescriptor is None:
|
if not self.__showDescriptor is None:
|
||||||
|
|
||||||
@@ -123,20 +156,8 @@ class ShowDetailsScreen(Screen):
|
|||||||
for shiftedSeason in self.__ssc.getShiftedSeasonSiblings(showId=showId):
|
for shiftedSeason in self.__ssc.getShiftedSeasonSiblings(showId=showId):
|
||||||
|
|
||||||
shiftedSeasonObj = shiftedSeason.getObj()
|
shiftedSeasonObj = shiftedSeason.getObj()
|
||||||
|
shiftedSeasonObj['id'] = shiftedSeason.getId()
|
||||||
firstEpisode = shiftedSeasonObj['first_episode']
|
self._add_shifted_season_row(shiftedSeasonObj)
|
||||||
firstEpisodeStr = str(firstEpisode) if firstEpisode != -1 else ''
|
|
||||||
|
|
||||||
lastEpisode = shiftedSeasonObj['last_episode']
|
|
||||||
lastEpisodeStr = str(lastEpisode) if lastEpisode != -1 else ''
|
|
||||||
|
|
||||||
row = (shiftedSeasonObj['original_season'],
|
|
||||||
firstEpisodeStr,
|
|
||||||
lastEpisodeStr,
|
|
||||||
shiftedSeasonObj['season_offset'],
|
|
||||||
shiftedSeasonObj['episode_offset'])
|
|
||||||
|
|
||||||
self.shiftedSeasonsTable.add_row(*map(str, row))
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
@@ -162,8 +183,10 @@ class ShowDetailsScreen(Screen):
|
|||||||
|
|
||||||
#raise click.ClickException(f"show_id {showId}")
|
#raise click.ClickException(f"show_id {showId}")
|
||||||
for pattern in self.__pc.getPatternsForShow(showId):
|
for pattern in self.__pc.getPatternsForShow(showId):
|
||||||
row = (pattern.getPattern(),)
|
self._add_pattern_row(
|
||||||
self.patternTable.add_row(*map(str, row))
|
pattern_id=pattern.getId(),
|
||||||
|
pattern_text=pattern.getPattern(),
|
||||||
|
)
|
||||||
|
|
||||||
self.updateShiftedSeasons()
|
self.updateShiftedSeasons()
|
||||||
|
|
||||||
@@ -195,10 +218,7 @@ class ShowDetailsScreen(Screen):
|
|||||||
row_key, col_key = self.patternTable.coordinate_to_cell_key(self.patternTable.cursor_coordinate)
|
row_key, col_key = self.patternTable.coordinate_to_cell_key(self.patternTable.cursor_coordinate)
|
||||||
|
|
||||||
if row_key is not None:
|
if row_key is not None:
|
||||||
selected_row_data = self.patternTable.get_row(row_key)
|
selectedPattern = dict(self.__patternRowData.get(row_key, {}))
|
||||||
|
|
||||||
selectedPattern['show_id'] = self.__showDescriptor.getId()
|
|
||||||
selectedPattern['pattern'] = str(selected_row_data[0])
|
|
||||||
|
|
||||||
except CellDoesNotExist:
|
except CellDoesNotExist:
|
||||||
pass
|
pass
|
||||||
@@ -217,31 +237,7 @@ class ShowDetailsScreen(Screen):
|
|||||||
row_key, col_key = self.shiftedSeasonsTable.coordinate_to_cell_key(self.shiftedSeasonsTable.cursor_coordinate)
|
row_key, col_key = self.shiftedSeasonsTable.coordinate_to_cell_key(self.shiftedSeasonsTable.cursor_coordinate)
|
||||||
|
|
||||||
if row_key is not None:
|
if row_key is not None:
|
||||||
selected_row_data = self.shiftedSeasonsTable.get_row(row_key)
|
shiftedSeasonObj = dict(self.__shiftedSeasonRowData.get(row_key, {}))
|
||||||
|
|
||||||
def parse_int_or_default(value: str, default: int) -> int:
|
|
||||||
try:
|
|
||||||
return int(value)
|
|
||||||
except (TypeError, ValueError):
|
|
||||||
return default
|
|
||||||
|
|
||||||
shiftedSeasonObj['original_season'] = int(selected_row_data[0])
|
|
||||||
shiftedSeasonObj['first_episode'] = parse_int_or_default(selected_row_data[1], -1)
|
|
||||||
shiftedSeasonObj['last_episode'] = parse_int_or_default(selected_row_data[2], -1)
|
|
||||||
shiftedSeasonObj['season_offset'] = parse_int_or_default(selected_row_data[3], 0)
|
|
||||||
shiftedSeasonObj['episode_offset'] = parse_int_or_default(selected_row_data[4], 0)
|
|
||||||
|
|
||||||
|
|
||||||
if self.__showDescriptor is not None:
|
|
||||||
|
|
||||||
showId = int(self.__showDescriptor.getId())
|
|
||||||
|
|
||||||
shiftedSeasonId = self.__ssc.findShiftedSeason(showId,
|
|
||||||
originalSeason=shiftedSeasonObj['original_season'],
|
|
||||||
firstEpisode=shiftedSeasonObj['first_episode'],
|
|
||||||
lastEpisode=shiftedSeasonObj['last_episode'])
|
|
||||||
if shiftedSeasonId is not None:
|
|
||||||
shiftedSeasonObj['id'] = shiftedSeasonId
|
|
||||||
|
|
||||||
except CellDoesNotExist:
|
except CellDoesNotExist:
|
||||||
pass
|
pass
|
||||||
@@ -255,9 +251,14 @@ class ShowDetailsScreen(Screen):
|
|||||||
|
|
||||||
|
|
||||||
def handle_add_pattern(self, screenResult):
|
def handle_add_pattern(self, screenResult):
|
||||||
|
if screenResult is None:
|
||||||
|
return
|
||||||
|
|
||||||
pattern = (screenResult['pattern'],)
|
pattern_id = self.__pc.findPattern(screenResult)
|
||||||
self.patternTable.add_row(*map(str, pattern))
|
self._add_pattern_row(
|
||||||
|
pattern_id=pattern_id,
|
||||||
|
pattern_text=screenResult['pattern'],
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
def action_edit_pattern(self):
|
def action_edit_pattern(self):
|
||||||
@@ -265,8 +266,7 @@ class ShowDetailsScreen(Screen):
|
|||||||
selectedPatternDescriptor = self.getSelectedPatternDescriptor()
|
selectedPatternDescriptor = self.getSelectedPatternDescriptor()
|
||||||
|
|
||||||
if selectedPatternDescriptor:
|
if selectedPatternDescriptor:
|
||||||
|
selectedPatternId = selectedPatternDescriptor.get('id')
|
||||||
selectedPatternId = self.__pc.findPattern(selectedPatternDescriptor)
|
|
||||||
|
|
||||||
if selectedPatternId is None:
|
if selectedPatternId is None:
|
||||||
raise click.ClickException(f"ShowDetailsScreen.action_edit_pattern(): Pattern to edit has no id")
|
raise click.ClickException(f"ShowDetailsScreen.action_edit_pattern(): Pattern to edit has no id")
|
||||||
@@ -280,6 +280,8 @@ class ShowDetailsScreen(Screen):
|
|||||||
|
|
||||||
row_key, col_key = self.patternTable.coordinate_to_cell_key(self.patternTable.cursor_coordinate)
|
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'])
|
self.patternTable.update_cell(row_key, self.column_key_pattern, screenResult['pattern'])
|
||||||
|
if row_key in self.__patternRowData:
|
||||||
|
self.__patternRowData[row_key]['pattern'] = str(screenResult['pattern'])
|
||||||
|
|
||||||
except CellDoesNotExist:
|
except CellDoesNotExist:
|
||||||
pass
|
pass
|
||||||
@@ -291,7 +293,7 @@ class ShowDetailsScreen(Screen):
|
|||||||
|
|
||||||
if selectedPatternDescriptor:
|
if selectedPatternDescriptor:
|
||||||
|
|
||||||
selectedPatternId = self.__pc.findPattern(selectedPatternDescriptor)
|
selectedPatternId = selectedPatternDescriptor.get('id')
|
||||||
|
|
||||||
if selectedPatternId is None:
|
if selectedPatternId is None:
|
||||||
raise click.ClickException(f"ShowDetailsScreen.action_remove_pattern(): Pattern to remove has no id")
|
raise click.ClickException(f"ShowDetailsScreen.action_remove_pattern(): Pattern to remove has no id")
|
||||||
@@ -304,6 +306,7 @@ class ShowDetailsScreen(Screen):
|
|||||||
try:
|
try:
|
||||||
row_key, col_key = self.patternTable.coordinate_to_cell_key(self.patternTable.cursor_coordinate)
|
row_key, col_key = self.patternTable.coordinate_to_cell_key(self.patternTable.cursor_coordinate)
|
||||||
self.patternTable.remove_row(row_key)
|
self.patternTable.remove_row(row_key)
|
||||||
|
self.__patternRowData.pop(row_key, None)
|
||||||
|
|
||||||
except CellDoesNotExist:
|
except CellDoesNotExist:
|
||||||
pass
|
pass
|
||||||
|
|||||||
@@ -66,6 +66,17 @@ class ShowsScreen(Screen):
|
|||||||
self.Session = self.context['database']['session'] # convenience
|
self.Session = self.context['database']['session'] # convenience
|
||||||
|
|
||||||
self.__sc = ShowController(context = self.context)
|
self.__sc = ShowController(context = self.context)
|
||||||
|
self.__showRowData: dict[object, ShowDescriptor] = {}
|
||||||
|
|
||||||
|
|
||||||
|
def _add_show_row(self, show_descriptor: ShowDescriptor):
|
||||||
|
row_key = self.table.add_row(
|
||||||
|
str(show_descriptor.getId()),
|
||||||
|
str(show_descriptor.getName()),
|
||||||
|
str(show_descriptor.getYear()),
|
||||||
|
)
|
||||||
|
self.__showRowData[row_key] = show_descriptor
|
||||||
|
return row_key
|
||||||
|
|
||||||
|
|
||||||
def getSelectedShowId(self):
|
def getSelectedShowId(self):
|
||||||
@@ -76,9 +87,8 @@ class ShowsScreen(Screen):
|
|||||||
row_key, col_key = self.table.coordinate_to_cell_key(self.table.cursor_coordinate)
|
row_key, col_key = self.table.coordinate_to_cell_key(self.table.cursor_coordinate)
|
||||||
|
|
||||||
if row_key is not None:
|
if row_key is not None:
|
||||||
selected_row_data = self.table.get_row(row_key)
|
selected_show = self.__showRowData.get(row_key)
|
||||||
|
return selected_show.getId() if selected_show is not None else None
|
||||||
return selected_row_data[0]
|
|
||||||
|
|
||||||
except CellDoesNotExist:
|
except CellDoesNotExist:
|
||||||
return None
|
return None
|
||||||
@@ -90,9 +100,8 @@ class ShowsScreen(Screen):
|
|||||||
self.app.push_screen(ShowDetailsScreen(), self.handle_new_screen)
|
self.app.push_screen(ShowDetailsScreen(), self.handle_new_screen)
|
||||||
|
|
||||||
def handle_new_screen(self, screenResult):
|
def handle_new_screen(self, screenResult):
|
||||||
|
if isinstance(screenResult, ShowDescriptor):
|
||||||
show = (screenResult['id'], screenResult['name'], screenResult['year'])
|
self._add_show_row(screenResult)
|
||||||
self.table.add_row(*map(str, show))
|
|
||||||
|
|
||||||
|
|
||||||
def action_edit_show(self):
|
def action_edit_show(self):
|
||||||
@@ -111,6 +120,7 @@ class ShowsScreen(Screen):
|
|||||||
|
|
||||||
self.table.update_cell(row_key, self.column_key_name, showDescriptor.getName())
|
self.table.update_cell(row_key, self.column_key_name, showDescriptor.getName())
|
||||||
self.table.update_cell(row_key, self.column_key_year, showDescriptor.getYear())
|
self.table.update_cell(row_key, self.column_key_year, showDescriptor.getYear())
|
||||||
|
self.__showRowData[row_key] = showDescriptor
|
||||||
|
|
||||||
except CellDoesNotExist:
|
except CellDoesNotExist:
|
||||||
pass
|
pass
|
||||||
@@ -131,6 +141,7 @@ class ShowsScreen(Screen):
|
|||||||
try:
|
try:
|
||||||
row_key, col_key = self.table.coordinate_to_cell_key(self.table.cursor_coordinate)
|
row_key, col_key = self.table.coordinate_to_cell_key(self.table.cursor_coordinate)
|
||||||
self.table.remove_row(row_key)
|
self.table.remove_row(row_key)
|
||||||
|
self.__showRowData.pop(row_key, None)
|
||||||
|
|
||||||
except CellDoesNotExist:
|
except CellDoesNotExist:
|
||||||
pass
|
pass
|
||||||
@@ -138,8 +149,7 @@ class ShowsScreen(Screen):
|
|||||||
|
|
||||||
def on_mount(self) -> None:
|
def on_mount(self) -> None:
|
||||||
for show in self.__sc.getAllShows():
|
for show in self.__sc.getAllShows():
|
||||||
row = (int(show.id), show.name, show.year) # Convert each element to a string before adding
|
self._add_show_row(show.getDescriptor(self.context))
|
||||||
self.table.add_row(*map(str, row))
|
|
||||||
|
|
||||||
|
|
||||||
def compose(self):
|
def compose(self):
|
||||||
|
|||||||
@@ -13,8 +13,7 @@ from .track_codec import TrackCodec
|
|||||||
from .track_descriptor import TrackDescriptor
|
from .track_descriptor import TrackDescriptor
|
||||||
from .track_disposition import TrackDisposition
|
from .track_disposition import TrackDisposition
|
||||||
from .track_type import TrackType
|
from .track_type import TrackType
|
||||||
|
from .screen_support import build_screen_bootstrap, populate_tag_table
|
||||||
from ffx.helper import formatRichColor, removeRichColor
|
|
||||||
|
|
||||||
|
|
||||||
class TrackDetailsScreen(Screen):
|
class TrackDetailsScreen(Screen):
|
||||||
@@ -98,28 +97,12 @@ class TrackDetailsScreen(Screen):
|
|||||||
):
|
):
|
||||||
super().__init__()
|
super().__init__()
|
||||||
|
|
||||||
self.context = self.app.getContext()
|
bootstrap = build_screen_bootstrap(self.app.getContext())
|
||||||
|
self.context = bootstrap.context
|
||||||
|
|
||||||
self.__configurationData = self.context["config"].getData()
|
self.__removeTrackKeys = bootstrap.remove_track_keys
|
||||||
|
self.__ignoreTrackKeys = bootstrap.ignore_track_keys
|
||||||
metadataConfiguration = (
|
self.__tagRowData: dict[object, tuple[str, str]] = {}
|
||||||
self.__configurationData["metadata"]
|
|
||||||
if "metadata" in self.__configurationData.keys()
|
|
||||||
else {}
|
|
||||||
)
|
|
||||||
|
|
||||||
self.__removeTrackKeys = (
|
|
||||||
metadataConfiguration["streams"]["remove"]
|
|
||||||
if "streams" in metadataConfiguration.keys()
|
|
||||||
and "remove" in metadataConfiguration["streams"].keys()
|
|
||||||
else []
|
|
||||||
)
|
|
||||||
self.__ignoreTrackKeys = (
|
|
||||||
metadataConfiguration["streams"]["ignore"]
|
|
||||||
if "streams" in metadataConfiguration.keys()
|
|
||||||
and "ignore" in metadataConfiguration["streams"].keys()
|
|
||||||
else []
|
|
||||||
)
|
|
||||||
|
|
||||||
self.__isNew = trackDescriptor is None
|
self.__isNew = trackDescriptor is None
|
||||||
self.__trackDescriptor = trackDescriptor
|
self.__trackDescriptor = trackDescriptor
|
||||||
@@ -166,18 +149,12 @@ class TrackDetailsScreen(Screen):
|
|||||||
)
|
)
|
||||||
|
|
||||||
def updateTags(self):
|
def updateTags(self):
|
||||||
|
self.__tagRowData = populate_tag_table(
|
||||||
self.trackTagsTable.clear()
|
self.trackTagsTable,
|
||||||
|
self.__draftTrackTags,
|
||||||
for key, value in self.__draftTrackTags.items():
|
ignore_keys=self.__ignoreTrackKeys,
|
||||||
textColor = None
|
remove_keys=self.__removeTrackKeys,
|
||||||
if key in self.__ignoreTrackKeys:
|
)
|
||||||
textColor = "blue"
|
|
||||||
if key in self.__removeTrackKeys:
|
|
||||||
textColor = "red"
|
|
||||||
|
|
||||||
row = (formatRichColor(key, textColor), formatRichColor(value, textColor))
|
|
||||||
self.trackTagsTable.add_row(*map(str, row))
|
|
||||||
|
|
||||||
def on_mount(self):
|
def on_mount(self):
|
||||||
|
|
||||||
@@ -190,9 +167,9 @@ class TrackDetailsScreen(Screen):
|
|||||||
self.query_one("#pattern_label", Static).update(self.__patternLabel)
|
self.query_one("#pattern_label", Static).update(self.__patternLabel)
|
||||||
|
|
||||||
if self.__trackType is not None:
|
if self.__trackType is not None:
|
||||||
self.query_one("#type_select", Select).value = self.__trackType.label()
|
self.query_one("#type_select", Select).value = self.__trackType
|
||||||
|
|
||||||
self.query_one("#audio_layout_select", Select).value = self.__audioLayout.label()
|
self.query_one("#audio_layout_select", Select).value = self.__audioLayout
|
||||||
|
|
||||||
for disposition in TrackDisposition:
|
for disposition in TrackDisposition:
|
||||||
|
|
||||||
@@ -211,9 +188,7 @@ class TrackDetailsScreen(Screen):
|
|||||||
)
|
)
|
||||||
|
|
||||||
if self.__trackDescriptor is not None:
|
if self.__trackDescriptor is not None:
|
||||||
self.query_one("#language_select", Select).value = (
|
self.query_one("#language_select", Select).value = self.__trackDescriptor.getLanguage()
|
||||||
self.__trackDescriptor.getLanguage().label()
|
|
||||||
)
|
|
||||||
self.query_one("#title_input", Input).value = self.__trackDescriptor.getTitle()
|
self.query_one("#title_input", Input).value = self.__trackDescriptor.getTitle()
|
||||||
self.updateTags()
|
self.updateTags()
|
||||||
|
|
||||||
@@ -226,8 +201,6 @@ class TrackDetailsScreen(Screen):
|
|||||||
|
|
||||||
self.trackTagsTable.cursor_type = "row"
|
self.trackTagsTable.cursor_type = "row"
|
||||||
|
|
||||||
languages = [language.label() for language in IsoLanguage]
|
|
||||||
|
|
||||||
yield Header()
|
yield Header()
|
||||||
|
|
||||||
with Grid():
|
with Grid():
|
||||||
@@ -250,15 +223,15 @@ class TrackDetailsScreen(Screen):
|
|||||||
yield Static(" ", classes="five")
|
yield Static(" ", classes="five")
|
||||||
|
|
||||||
yield Static("Type")
|
yield Static("Type")
|
||||||
yield Select.from_values(
|
yield Select(
|
||||||
[trackType.label() for trackType in TrackType],
|
[(trackType.label(), trackType) for trackType in TrackType],
|
||||||
classes="four",
|
classes="four",
|
||||||
id="type_select",
|
id="type_select",
|
||||||
)
|
)
|
||||||
|
|
||||||
yield Static("Audio Layout")
|
yield Static("Audio Layout")
|
||||||
yield Select.from_values(
|
yield Select(
|
||||||
[layout.label() for layout in AudioLayout],
|
[(layout.label(), layout) for layout in AudioLayout],
|
||||||
classes="four",
|
classes="four",
|
||||||
id="audio_layout_select",
|
id="audio_layout_select",
|
||||||
)
|
)
|
||||||
@@ -268,7 +241,11 @@ class TrackDetailsScreen(Screen):
|
|||||||
yield Static(" ", classes="five")
|
yield Static(" ", classes="five")
|
||||||
|
|
||||||
yield Static("Language")
|
yield Static("Language")
|
||||||
yield Select.from_values(languages, classes="four", id="language_select")
|
yield Select(
|
||||||
|
[(language.label(), language) for language in IsoLanguage],
|
||||||
|
classes="four",
|
||||||
|
id="language_select",
|
||||||
|
)
|
||||||
|
|
||||||
yield Static(" ", classes="five")
|
yield Static(" ", classes="five")
|
||||||
|
|
||||||
@@ -328,15 +305,18 @@ class TrackDetailsScreen(Screen):
|
|||||||
if self.__subIndex is not None and int(self.__subIndex) >= 0:
|
if self.__subIndex is not None and int(self.__subIndex) >= 0:
|
||||||
kwargs[TrackDescriptor.SUB_INDEX_KEY] = int(self.__subIndex)
|
kwargs[TrackDescriptor.SUB_INDEX_KEY] = int(self.__subIndex)
|
||||||
|
|
||||||
selectedTrackType = TrackType.fromLabel(
|
selectedTrackType = self.query_one("#type_select", Select).value
|
||||||
self.query_one("#type_select", Select).value
|
if not isinstance(selectedTrackType, TrackType):
|
||||||
)
|
selectedTrackType = TrackType.UNKNOWN
|
||||||
kwargs[TrackDescriptor.TRACK_TYPE_KEY] = selectedTrackType
|
kwargs[TrackDescriptor.TRACK_TYPE_KEY] = selectedTrackType
|
||||||
kwargs[TrackDescriptor.CODEC_KEY] = self.__trackCodec
|
kwargs[TrackDescriptor.CODEC_KEY] = self.__trackCodec
|
||||||
|
|
||||||
if selectedTrackType == TrackType.AUDIO:
|
if selectedTrackType == TrackType.AUDIO:
|
||||||
kwargs[TrackDescriptor.AUDIO_LAYOUT_KEY] = AudioLayout.fromLabel(
|
selectedAudioLayout = self.query_one("#audio_layout_select", Select).value
|
||||||
self.query_one("#audio_layout_select", Select).value
|
kwargs[TrackDescriptor.AUDIO_LAYOUT_KEY] = (
|
||||||
|
selectedAudioLayout
|
||||||
|
if isinstance(selectedAudioLayout, AudioLayout)
|
||||||
|
else AudioLayout.LAYOUT_UNDEFINED
|
||||||
)
|
)
|
||||||
else:
|
else:
|
||||||
kwargs[TrackDescriptor.AUDIO_LAYOUT_KEY] = AudioLayout.LAYOUT_UNDEFINED
|
kwargs[TrackDescriptor.AUDIO_LAYOUT_KEY] = AudioLayout.LAYOUT_UNDEFINED
|
||||||
@@ -344,8 +324,8 @@ class TrackDetailsScreen(Screen):
|
|||||||
trackTags = dict(self.__draftTrackTags)
|
trackTags = dict(self.__draftTrackTags)
|
||||||
|
|
||||||
language = self.query_one("#language_select", Select).value
|
language = self.query_one("#language_select", Select).value
|
||||||
if language:
|
if isinstance(language, IsoLanguage):
|
||||||
trackTags["language"] = IsoLanguage.find(language).threeLetter()
|
trackTags["language"] = language.threeLetter()
|
||||||
|
|
||||||
title = self.query_one("#title_input", Input).value
|
title = self.query_one("#title_input", Input).value
|
||||||
if title:
|
if title:
|
||||||
@@ -370,12 +350,7 @@ class TrackDetailsScreen(Screen):
|
|||||||
)
|
)
|
||||||
|
|
||||||
if row_key is not None:
|
if row_key is not None:
|
||||||
selected_tag_data = self.trackTagsTable.get_row(row_key)
|
return self.__tagRowData.get(row_key)
|
||||||
|
|
||||||
tagKey = removeRichColor(selected_tag_data[0])
|
|
||||||
tagValue = removeRichColor(selected_tag_data[1])
|
|
||||||
|
|
||||||
return tagKey, tagValue
|
|
||||||
|
|
||||||
return None
|
return None
|
||||||
|
|
||||||
|
|||||||
@@ -23,6 +23,21 @@ class StaticConfig:
|
|||||||
return self._data
|
return self._data
|
||||||
|
|
||||||
|
|
||||||
|
class FakeTagTable:
|
||||||
|
def __init__(self):
|
||||||
|
self.rows = {}
|
||||||
|
self._next_index = 0
|
||||||
|
|
||||||
|
def clear(self):
|
||||||
|
self.rows.clear()
|
||||||
|
|
||||||
|
def add_row(self, *values):
|
||||||
|
row_key = f"row-{self._next_index}"
|
||||||
|
self._next_index += 1
|
||||||
|
self.rows[row_key] = tuple(values)
|
||||||
|
return row_key
|
||||||
|
|
||||||
|
|
||||||
class ScreenSupportTests(unittest.TestCase):
|
class ScreenSupportTests(unittest.TestCase):
|
||||||
def make_context(self):
|
def make_context(self):
|
||||||
return {
|
return {
|
||||||
@@ -81,6 +96,32 @@ class ScreenSupportTests(unittest.TestCase):
|
|||||||
controllers,
|
controllers,
|
||||||
)
|
)
|
||||||
|
|
||||||
|
def test_populate_tag_table_keeps_raw_values_outside_display_labels(self):
|
||||||
|
table = FakeTagTable()
|
||||||
|
|
||||||
|
row_data = screen_support.populate_tag_table(
|
||||||
|
table,
|
||||||
|
{"BPS": 4835, "KEEP": "plain"},
|
||||||
|
ignore_keys=["KEEP"],
|
||||||
|
remove_keys=["BPS"],
|
||||||
|
)
|
||||||
|
|
||||||
|
self.assertEqual(
|
||||||
|
{
|
||||||
|
"row-0": ("BPS", "4835"),
|
||||||
|
"row-1": ("KEEP", "plain"),
|
||||||
|
},
|
||||||
|
row_data,
|
||||||
|
)
|
||||||
|
self.assertEqual(
|
||||||
|
("[red]BPS[/red]", "[red]4835[/red]"),
|
||||||
|
table.rows["row-0"],
|
||||||
|
)
|
||||||
|
self.assertEqual(
|
||||||
|
("[blue]KEEP[/blue]", "[blue]plain[/blue]"),
|
||||||
|
table.rows["row-1"],
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
if __name__ == "__main__":
|
if __name__ == "__main__":
|
||||||
unittest.main()
|
unittest.main()
|
||||||
|
|||||||
325
tests/unit/test_tag_table_screen_state.py
Normal file
325
tests/unit/test_tag_table_screen_state.py
Normal file
@@ -0,0 +1,325 @@
|
|||||||
|
from __future__ import annotations
|
||||||
|
|
||||||
|
from pathlib import Path
|
||||||
|
import sys
|
||||||
|
import unittest
|
||||||
|
|
||||||
|
|
||||||
|
SRC_ROOT = Path(__file__).resolve().parents[2] / "src"
|
||||||
|
|
||||||
|
if str(SRC_ROOT) not in sys.path:
|
||||||
|
sys.path.insert(0, str(SRC_ROOT))
|
||||||
|
|
||||||
|
|
||||||
|
from ffx.audio_layout import AudioLayout # noqa: E402
|
||||||
|
from ffx.iso_language import IsoLanguage # noqa: E402
|
||||||
|
from ffx.logging_utils import get_ffx_logger # noqa: E402
|
||||||
|
from ffx.media_details_screen import MediaDetailsScreen # noqa: E402
|
||||||
|
from ffx.pattern_details_screen import PatternDetailsScreen # noqa: E402
|
||||||
|
from ffx.show_descriptor import ShowDescriptor # noqa: E402
|
||||||
|
from ffx.show_details_screen import ShowDetailsScreen # noqa: E402
|
||||||
|
from ffx.shows_screen import ShowsScreen # noqa: E402
|
||||||
|
from ffx.track_codec import TrackCodec # noqa: E402
|
||||||
|
from ffx.track_descriptor import TrackDescriptor # noqa: E402
|
||||||
|
from ffx.track_details_screen import TrackDetailsScreen # noqa: E402
|
||||||
|
from ffx.track_type import TrackType # noqa: E402
|
||||||
|
|
||||||
|
|
||||||
|
class FakeTagTable:
|
||||||
|
def __init__(self):
|
||||||
|
self.rows = {}
|
||||||
|
self.cursor_coordinate = (0, 0)
|
||||||
|
self._selected_row_key = None
|
||||||
|
self._next_index = 0
|
||||||
|
self._row_order = []
|
||||||
|
|
||||||
|
def clear(self):
|
||||||
|
self.rows.clear()
|
||||||
|
self._selected_row_key = None
|
||||||
|
self._row_order.clear()
|
||||||
|
|
||||||
|
def add_row(self, *values):
|
||||||
|
row_key = f"row-{self._next_index}"
|
||||||
|
self._next_index += 1
|
||||||
|
self.rows[row_key] = tuple(values)
|
||||||
|
self._row_order.append(row_key)
|
||||||
|
if self._selected_row_key is None:
|
||||||
|
self._selected_row_key = row_key
|
||||||
|
return row_key
|
||||||
|
|
||||||
|
def coordinate_to_cell_key(self, _coordinate):
|
||||||
|
return self._selected_row_key, None
|
||||||
|
|
||||||
|
def select_row(self, row_key):
|
||||||
|
self._selected_row_key = row_key
|
||||||
|
|
||||||
|
def get_row_index(self, row_key):
|
||||||
|
return self._row_order.index(row_key)
|
||||||
|
|
||||||
|
def remove_row(self, row_key):
|
||||||
|
self.rows.pop(row_key, None)
|
||||||
|
if row_key in self._row_order:
|
||||||
|
self._row_order.remove(row_key)
|
||||||
|
if self._selected_row_key == row_key:
|
||||||
|
self._selected_row_key = self._row_order[0] if self._row_order else None
|
||||||
|
|
||||||
|
def update_cell(self, row_key, column_key, value):
|
||||||
|
row = list(self.rows[row_key])
|
||||||
|
row[int(column_key)] = value
|
||||||
|
self.rows[row_key] = tuple(row)
|
||||||
|
|
||||||
|
|
||||||
|
class FakeMediaDescriptor:
|
||||||
|
def __init__(self, track_descriptors):
|
||||||
|
self._track_descriptors = list(track_descriptors)
|
||||||
|
|
||||||
|
def getTrackDescriptors(self):
|
||||||
|
return list(self._track_descriptors)
|
||||||
|
|
||||||
|
|
||||||
|
class FakeValueWidget:
|
||||||
|
def __init__(self, value):
|
||||||
|
self.value = value
|
||||||
|
|
||||||
|
|
||||||
|
class FakeInputWidget:
|
||||||
|
def __init__(self, value):
|
||||||
|
self.value = value
|
||||||
|
|
||||||
|
|
||||||
|
class FakeSelectionListWidget:
|
||||||
|
def __init__(self, selected):
|
||||||
|
self.selected = selected
|
||||||
|
|
||||||
|
|
||||||
|
def make_track_descriptor(index, sub_index, track_type):
|
||||||
|
return TrackDescriptor(
|
||||||
|
index=index,
|
||||||
|
sub_index=sub_index,
|
||||||
|
track_type=track_type,
|
||||||
|
codec_name=TrackCodec.UNKNOWN,
|
||||||
|
audio_layout=AudioLayout.LAYOUT_UNDEFINED,
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
def make_show_descriptor(show_id, name="Show", year=2000):
|
||||||
|
return ShowDescriptor(
|
||||||
|
id=show_id,
|
||||||
|
name=name,
|
||||||
|
year=year,
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
class TagTableScreenStateTests(unittest.TestCase):
|
||||||
|
def test_track_details_screen_reads_selected_tag_from_raw_row_mapping(self):
|
||||||
|
screen = object.__new__(TrackDetailsScreen)
|
||||||
|
screen.trackTagsTable = FakeTagTable()
|
||||||
|
screen._TrackDetailsScreen__draftTrackTags = {
|
||||||
|
"BPS": "4835",
|
||||||
|
"KEEP_ME": "plain",
|
||||||
|
}
|
||||||
|
screen._TrackDetailsScreen__ignoreTrackKeys = ["KEEP_ME"]
|
||||||
|
screen._TrackDetailsScreen__removeTrackKeys = ["BPS"]
|
||||||
|
screen._TrackDetailsScreen__tagRowData = {}
|
||||||
|
|
||||||
|
screen.updateTags()
|
||||||
|
|
||||||
|
self.assertEqual(
|
||||||
|
("[red]BPS[/red]", "[red]4835[/red]"),
|
||||||
|
screen.trackTagsTable.rows["row-0"],
|
||||||
|
)
|
||||||
|
self.assertEqual(
|
||||||
|
("BPS", "4835"),
|
||||||
|
screen.getSelectedTag(),
|
||||||
|
)
|
||||||
|
|
||||||
|
def test_track_details_screen_reads_select_values_from_widget_state(self):
|
||||||
|
screen = object.__new__(TrackDetailsScreen)
|
||||||
|
screen.context = {"logger": get_ffx_logger()}
|
||||||
|
screen._TrackDetailsScreen__trackDescriptor = None
|
||||||
|
screen._TrackDetailsScreen__patternId = 5
|
||||||
|
screen._TrackDetailsScreen__index = 2
|
||||||
|
screen._TrackDetailsScreen__subIndex = 0
|
||||||
|
screen._TrackDetailsScreen__trackCodec = TrackCodec.UNKNOWN
|
||||||
|
screen._TrackDetailsScreen__draftTrackTags = {"KEEP": "value"}
|
||||||
|
|
||||||
|
widgets = {
|
||||||
|
"#type_select": FakeValueWidget(TrackType.AUDIO),
|
||||||
|
"#audio_layout_select": FakeValueWidget(AudioLayout.LAYOUT_STEREO),
|
||||||
|
"#language_select": FakeValueWidget(IsoLanguage.GERMAN),
|
||||||
|
"#title_input": FakeInputWidget("German Audio"),
|
||||||
|
"#dispositions_selection_list": FakeSelectionListWidget({0, 6}),
|
||||||
|
}
|
||||||
|
screen.query_one = lambda selector, _widget_type=None: widgets[selector]
|
||||||
|
|
||||||
|
descriptor = screen.getTrackDescriptorFromInput()
|
||||||
|
|
||||||
|
self.assertEqual(TrackType.AUDIO, descriptor.getType())
|
||||||
|
self.assertEqual(AudioLayout.LAYOUT_STEREO, descriptor.getAudioLayout())
|
||||||
|
self.assertEqual("deu", descriptor.getTags()["language"])
|
||||||
|
self.assertEqual("German Audio", descriptor.getTitle())
|
||||||
|
self.assertEqual("value", descriptor.getTags()["KEEP"])
|
||||||
|
|
||||||
|
def test_pattern_details_screen_reads_selected_track_from_row_mapping(self):
|
||||||
|
first_track = make_track_descriptor(0, 0, TrackType.VIDEO)
|
||||||
|
second_track = make_track_descriptor(1, 0, TrackType.SUBTITLE)
|
||||||
|
|
||||||
|
screen = object.__new__(PatternDetailsScreen)
|
||||||
|
screen.tracksTable = FakeTagTable()
|
||||||
|
screen._PatternDetailsScreen__draftTracks = [first_track, second_track]
|
||||||
|
screen._PatternDetailsScreen__pattern = None
|
||||||
|
screen._PatternDetailsScreen__trackRowData = {}
|
||||||
|
|
||||||
|
screen.updateTracks()
|
||||||
|
screen.tracksTable.select_row("row-1")
|
||||||
|
|
||||||
|
self.assertIs(second_track, screen.getSelectedTrackDescriptor())
|
||||||
|
|
||||||
|
def test_pattern_details_screen_reads_selected_tag_from_raw_row_mapping(self):
|
||||||
|
screen = object.__new__(PatternDetailsScreen)
|
||||||
|
screen.tagsTable = FakeTagTable()
|
||||||
|
screen._PatternDetailsScreen__pattern = None
|
||||||
|
screen._PatternDetailsScreen__draftTags = {
|
||||||
|
"BPS": "4835",
|
||||||
|
"TITLE": "Deutsch [FN]",
|
||||||
|
}
|
||||||
|
screen._PatternDetailsScreen__ignoreGlobalKeys = ["TITLE"]
|
||||||
|
screen._PatternDetailsScreen__removeGlobalKeys = ["BPS"]
|
||||||
|
screen._PatternDetailsScreen__tagRowData = {}
|
||||||
|
|
||||||
|
screen.updateTags()
|
||||||
|
|
||||||
|
self.assertEqual(
|
||||||
|
("[red]BPS[/red]", "[red]4835[/red]"),
|
||||||
|
screen.tagsTable.rows["row-0"],
|
||||||
|
)
|
||||||
|
self.assertEqual(
|
||||||
|
("BPS", "4835"),
|
||||||
|
screen.getSelectedTag(),
|
||||||
|
)
|
||||||
|
|
||||||
|
def test_media_details_screen_reads_selected_track_from_row_mapping(self):
|
||||||
|
first_track = make_track_descriptor(0, 0, TrackType.VIDEO)
|
||||||
|
second_track = make_track_descriptor(1, 0, TrackType.SUBTITLE)
|
||||||
|
|
||||||
|
screen = object.__new__(MediaDetailsScreen)
|
||||||
|
screen.tracksTable = FakeTagTable()
|
||||||
|
screen._MediaDetailsScreen__sourceMediaDescriptor = FakeMediaDescriptor(
|
||||||
|
[first_track, second_track]
|
||||||
|
)
|
||||||
|
screen._MediaDetailsScreen__trackRowData = {}
|
||||||
|
|
||||||
|
screen.updateTracks()
|
||||||
|
screen.tracksTable.select_row("row-1")
|
||||||
|
|
||||||
|
self.assertIs(second_track, screen.getSelectedTrackDescriptor())
|
||||||
|
|
||||||
|
def test_pattern_details_screen_reads_selected_shifted_season_from_row_mapping(self):
|
||||||
|
screen = object.__new__(PatternDetailsScreen)
|
||||||
|
screen.shiftedSeasonsTable = FakeTagTable()
|
||||||
|
screen._PatternDetailsScreen__pattern = object()
|
||||||
|
screen._PatternDetailsScreen__shiftedSeasonRowData = {}
|
||||||
|
|
||||||
|
row_key = screen.shiftedSeasonsTable.add_row("9", "1", "3", "1", "0")
|
||||||
|
screen._PatternDetailsScreen__shiftedSeasonRowData[row_key] = {
|
||||||
|
"id": 44,
|
||||||
|
"original_season": 9,
|
||||||
|
"first_episode": 1,
|
||||||
|
"last_episode": 3,
|
||||||
|
"season_offset": 1,
|
||||||
|
"episode_offset": 0,
|
||||||
|
}
|
||||||
|
screen.shiftedSeasonsTable.rows[row_key] = ("broken", "ui", "values", "!", "?")
|
||||||
|
|
||||||
|
self.assertEqual(
|
||||||
|
{
|
||||||
|
"id": 44,
|
||||||
|
"original_season": 9,
|
||||||
|
"first_episode": 1,
|
||||||
|
"last_episode": 3,
|
||||||
|
"season_offset": 1,
|
||||||
|
"episode_offset": 0,
|
||||||
|
},
|
||||||
|
screen.getSelectedShiftedSeasonObjFromInput(),
|
||||||
|
)
|
||||||
|
|
||||||
|
def test_show_details_screen_reads_selected_pattern_from_row_mapping(self):
|
||||||
|
screen = object.__new__(ShowDetailsScreen)
|
||||||
|
screen.patternTable = FakeTagTable()
|
||||||
|
screen._ShowDetailsScreen__showDescriptor = make_show_descriptor(7, "Demo", 1999)
|
||||||
|
screen._ShowDetailsScreen__patternRowData = {}
|
||||||
|
|
||||||
|
row_key = screen._add_pattern_row(pattern_id=11, pattern_text=r"^demo_(s[0-9]+e[0-9]+)\.mkv$")
|
||||||
|
screen.patternTable.rows[row_key] = ("display text changed",)
|
||||||
|
|
||||||
|
self.assertEqual(
|
||||||
|
{
|
||||||
|
"id": 11,
|
||||||
|
"show_id": 7,
|
||||||
|
"pattern": r"^demo_(s[0-9]+e[0-9]+)\.mkv$",
|
||||||
|
},
|
||||||
|
screen.getSelectedPatternDescriptor(),
|
||||||
|
)
|
||||||
|
|
||||||
|
def test_show_details_screen_reads_selected_shifted_season_from_row_mapping(self):
|
||||||
|
screen = object.__new__(ShowDetailsScreen)
|
||||||
|
screen.shiftedSeasonsTable = FakeTagTable()
|
||||||
|
screen._ShowDetailsScreen__shiftedSeasonRowData = {}
|
||||||
|
|
||||||
|
row_key = screen.shiftedSeasonsTable.add_row("1", "", "", "0", "0")
|
||||||
|
screen._ShowDetailsScreen__shiftedSeasonRowData[row_key] = {
|
||||||
|
"id": 3,
|
||||||
|
"original_season": 1,
|
||||||
|
"first_episode": -1,
|
||||||
|
"last_episode": -1,
|
||||||
|
"season_offset": 0,
|
||||||
|
"episode_offset": 0,
|
||||||
|
}
|
||||||
|
screen.shiftedSeasonsTable.rows[row_key] = ("bad", "visible", "data", "x", "y")
|
||||||
|
|
||||||
|
self.assertEqual(
|
||||||
|
{
|
||||||
|
"id": 3,
|
||||||
|
"original_season": 1,
|
||||||
|
"first_episode": -1,
|
||||||
|
"last_episode": -1,
|
||||||
|
"season_offset": 0,
|
||||||
|
"episode_offset": 0,
|
||||||
|
},
|
||||||
|
screen.getSelectedShiftedSeasonObjFromInput(),
|
||||||
|
)
|
||||||
|
|
||||||
|
def test_shows_screen_reads_selected_show_id_from_row_mapping(self):
|
||||||
|
screen = object.__new__(ShowsScreen)
|
||||||
|
screen.table = FakeTagTable()
|
||||||
|
screen._ShowsScreen__showRowData = {}
|
||||||
|
|
||||||
|
row_key = screen._add_show_row(make_show_descriptor(4, "Mapped", 2011))
|
||||||
|
screen.table.rows[row_key] = ("999", "Visible", "2099")
|
||||||
|
|
||||||
|
self.assertEqual(4, screen.getSelectedShowId())
|
||||||
|
|
||||||
|
def test_media_details_screen_reads_selected_show_from_row_mapping(self):
|
||||||
|
screen = object.__new__(MediaDetailsScreen)
|
||||||
|
screen.showsTable = FakeTagTable()
|
||||||
|
screen._MediaDetailsScreen__showRowData = {}
|
||||||
|
|
||||||
|
placeholder_key = screen._add_show_row(None)
|
||||||
|
show_key = screen._add_show_row(make_show_descriptor(8, "Real Show", 2020))
|
||||||
|
screen.showsTable.select_row(show_key)
|
||||||
|
screen.showsTable.rows[show_key] = ("oops", "display", "changed")
|
||||||
|
|
||||||
|
selected_show = screen.getSelectedShowDescriptor()
|
||||||
|
|
||||||
|
self.assertIsInstance(selected_show, ShowDescriptor)
|
||||||
|
self.assertEqual(8, selected_show.getId())
|
||||||
|
self.assertEqual(0, screen.getRowIndexFromShowId(-1))
|
||||||
|
self.assertEqual(1, screen.getRowIndexFromShowId(8))
|
||||||
|
|
||||||
|
screen.removeShow(-1)
|
||||||
|
self.assertNotIn(placeholder_key, screen._MediaDetailsScreen__showRowData)
|
||||||
|
self.assertEqual(0, screen.getRowIndexFromShowId(8))
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
unittest.main()
|
||||||
Reference in New Issue
Block a user