iteration1
This commit is contained in:
@@ -1180,8 +1180,8 @@ def convert(ctx,
|
||||
|
||||
|
||||
ssc = ShiftedSeasonController(context)
|
||||
|
||||
showId = mediaFileProperties.getShowId()
|
||||
|
||||
matchedShowId = mediaFileProperties.getShowId()
|
||||
|
||||
#HINT: -1 if not set
|
||||
if 'tmdb' in cliOverrides.keys() and 'season' in cliOverrides['tmdb']:
|
||||
@@ -1286,19 +1286,43 @@ def convert(ctx,
|
||||
indicatorEpisodeDigits = currentShowDescriptor.getIndicatorEpisodeDigits() if not currentPattern is None else defaultDigitLengths[ShowDescriptor.INDICATOR_EPISODE_DIGITS_KEY]
|
||||
|
||||
|
||||
# Shift season and episode if defined for this show
|
||||
if ('tmdb' not in cliOverrides.keys() and showId != -1
|
||||
and showSeason != -1 and showEpisode != -1):
|
||||
shiftedShowSeason, shiftedShowEpisode = ssc.shiftSeason(showId,
|
||||
season=showSeason,
|
||||
episode=showEpisode)
|
||||
showIdForShift = (
|
||||
cliOverrides['tmdb']['show']
|
||||
if 'tmdb' in cliOverrides.keys() and 'show' in cliOverrides['tmdb']
|
||||
else matchedShowId
|
||||
)
|
||||
patternIdForShift = currentPattern.getId() if currentPattern is not None else None
|
||||
hasExplicitTargetSeasonOrEpisode = (
|
||||
'tmdb' in cliOverrides.keys()
|
||||
and (
|
||||
'season' in cliOverrides['tmdb']
|
||||
or 'episode' in cliOverrides['tmdb']
|
||||
)
|
||||
)
|
||||
|
||||
# Shift season and episode if defined for the matched pattern or show
|
||||
if (
|
||||
not hasExplicitTargetSeasonOrEpisode
|
||||
and showSeason != -1
|
||||
and showEpisode != -1
|
||||
):
|
||||
shiftedShowSeason, shiftedShowEpisode = ssc.shiftSeason(
|
||||
showIdForShift,
|
||||
season=showSeason,
|
||||
episode=showEpisode,
|
||||
patternId=patternIdForShift,
|
||||
)
|
||||
else:
|
||||
shiftedShowSeason = showSeason
|
||||
shiftedShowEpisode = showEpisode
|
||||
|
||||
# Assemble target filename accordingly depending on TMDB lookup is enabled
|
||||
#HINT: -1 if not set
|
||||
showId = cliOverrides['tmdb']['show'] if 'tmdb' in cliOverrides.keys() and 'show' in cliOverrides['tmdb'] else (-1 if currentShowDescriptor is None else currentShowDescriptor.getId())
|
||||
showId = (
|
||||
cliOverrides['tmdb']['show']
|
||||
if 'tmdb' in cliOverrides.keys() and 'show' in cliOverrides['tmdb']
|
||||
else (-1 if currentShowDescriptor is None else currentShowDescriptor.getId())
|
||||
)
|
||||
|
||||
if context['use_tmdb'] and showId != -1 and shiftedShowSeason != -1 and shiftedShowEpisode != -1:
|
||||
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
VERSION='0.2.4'
|
||||
DATABASE_VERSION = 2
|
||||
DATABASE_VERSION = 3
|
||||
|
||||
DEFAULT_QUALITY = 32
|
||||
DEFAULT_AV1_PRESET = 5
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import os, click
|
||||
|
||||
from sqlalchemy import create_engine, inspect
|
||||
from sqlalchemy import create_engine, inspect, text
|
||||
from sqlalchemy.orm import sessionmaker
|
||||
|
||||
# Import the full model package so SQLAlchemy registers every mapped class
|
||||
@@ -71,11 +71,110 @@ def bootstrapDatabaseIfNeeded(databaseContext):
|
||||
def ensureDatabaseVersion(databaseContext):
|
||||
|
||||
currentDatabaseVersion = getDatabaseVersion(databaseContext)
|
||||
if currentDatabaseVersion:
|
||||
if currentDatabaseVersion != DATABASE_VERSION:
|
||||
raise DatabaseVersionException(f"Current database version ({currentDatabaseVersion}) does not match required ({DATABASE_VERSION})")
|
||||
else:
|
||||
if not currentDatabaseVersion:
|
||||
setDatabaseVersion(databaseContext, DATABASE_VERSION)
|
||||
return
|
||||
|
||||
if currentDatabaseVersion > DATABASE_VERSION:
|
||||
raise DatabaseVersionException(
|
||||
f"Current database version ({currentDatabaseVersion}) does not match required ({DATABASE_VERSION})"
|
||||
)
|
||||
|
||||
if currentDatabaseVersion < DATABASE_VERSION:
|
||||
migrateDatabase(databaseContext, currentDatabaseVersion, DATABASE_VERSION)
|
||||
currentDatabaseVersion = getDatabaseVersion(databaseContext)
|
||||
|
||||
if currentDatabaseVersion != DATABASE_VERSION:
|
||||
raise DatabaseVersionException(
|
||||
f"Current database version ({currentDatabaseVersion}) does not match required ({DATABASE_VERSION})"
|
||||
)
|
||||
|
||||
|
||||
def migrateDatabase(databaseContext, currentVersion: int, targetVersion: int):
|
||||
version = int(currentVersion)
|
||||
|
||||
while version < int(targetVersion):
|
||||
if version == 2:
|
||||
migrateDatabaseV2ToV3(databaseContext)
|
||||
version = 3
|
||||
setDatabaseVersion(databaseContext, version)
|
||||
continue
|
||||
|
||||
raise DatabaseVersionException(
|
||||
f"No migration path from database version {version} to {targetVersion}"
|
||||
)
|
||||
|
||||
|
||||
def migrateDatabaseV2ToV3(databaseContext):
|
||||
engine = databaseContext['engine']
|
||||
inspector = inspect(engine)
|
||||
shiftedSeasonColumns = {
|
||||
column['name']
|
||||
for column in inspector.get_columns('shifted_seasons')
|
||||
}
|
||||
|
||||
if 'pattern_id' in shiftedSeasonColumns:
|
||||
return
|
||||
|
||||
with engine.begin() as connection:
|
||||
connection.execute(text("PRAGMA foreign_keys=OFF"))
|
||||
connection.execute(
|
||||
text(
|
||||
"""
|
||||
CREATE TABLE shifted_seasons_v3 (
|
||||
id INTEGER PRIMARY KEY,
|
||||
show_id INTEGER,
|
||||
pattern_id INTEGER,
|
||||
original_season INTEGER,
|
||||
first_episode INTEGER DEFAULT -1,
|
||||
last_episode INTEGER DEFAULT -1,
|
||||
season_offset INTEGER DEFAULT 0,
|
||||
episode_offset INTEGER DEFAULT 0,
|
||||
FOREIGN KEY(show_id) REFERENCES shows(id) ON DELETE CASCADE,
|
||||
FOREIGN KEY(pattern_id) REFERENCES patterns(id) ON DELETE CASCADE,
|
||||
CHECK (
|
||||
(show_id IS NOT NULL AND pattern_id IS NULL)
|
||||
OR (show_id IS NULL AND pattern_id IS NOT NULL)
|
||||
)
|
||||
)
|
||||
"""
|
||||
)
|
||||
)
|
||||
connection.execute(
|
||||
text(
|
||||
"""
|
||||
INSERT INTO shifted_seasons_v3 (
|
||||
id,
|
||||
show_id,
|
||||
pattern_id,
|
||||
original_season,
|
||||
first_episode,
|
||||
last_episode,
|
||||
season_offset,
|
||||
episode_offset
|
||||
)
|
||||
SELECT
|
||||
id,
|
||||
show_id,
|
||||
NULL,
|
||||
original_season,
|
||||
first_episode,
|
||||
last_episode,
|
||||
season_offset,
|
||||
episode_offset
|
||||
FROM shifted_seasons
|
||||
"""
|
||||
)
|
||||
)
|
||||
connection.execute(text("DROP TABLE shifted_seasons"))
|
||||
connection.execute(text("ALTER TABLE shifted_seasons_v3 RENAME TO shifted_seasons"))
|
||||
connection.execute(
|
||||
text("CREATE INDEX ix_shifted_seasons_show_id ON shifted_seasons(show_id)")
|
||||
)
|
||||
connection.execute(
|
||||
text("CREATE INDEX ix_shifted_seasons_pattern_id ON shifted_seasons(pattern_id)")
|
||||
)
|
||||
connection.execute(text("PRAGMA foreign_keys=ON"))
|
||||
|
||||
|
||||
def getDatabaseVersion(databaseContext):
|
||||
|
||||
@@ -35,6 +35,7 @@ class Pattern(Base):
|
||||
tracks = relationship('Track', back_populates='pattern', cascade="all, delete", lazy='joined')
|
||||
|
||||
media_tags = relationship('MediaTag', back_populates='pattern', cascade="all, delete", lazy='joined')
|
||||
shifted_seasons = relationship('ShiftedSeason', back_populates='pattern', cascade="all, delete", lazy='joined')
|
||||
|
||||
quality = Column(Integer, default=0)
|
||||
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import click
|
||||
|
||||
from sqlalchemy import Column, Integer, ForeignKey
|
||||
from sqlalchemy import CheckConstraint, Column, ForeignKey, Index, Integer
|
||||
from sqlalchemy.orm import relationship
|
||||
|
||||
from .show import Base, Show
|
||||
@@ -9,6 +9,14 @@ from .show import Base, Show
|
||||
class ShiftedSeason(Base):
|
||||
|
||||
__tablename__ = 'shifted_seasons'
|
||||
__table_args__ = (
|
||||
CheckConstraint(
|
||||
"(show_id IS NOT NULL AND pattern_id IS NULL) OR (show_id IS NULL AND pattern_id IS NOT NULL)",
|
||||
name="ck_shifted_seasons_single_owner",
|
||||
),
|
||||
Index("ix_shifted_seasons_show_id", "show_id"),
|
||||
Index("ix_shifted_seasons_pattern_id", "pattern_id"),
|
||||
)
|
||||
|
||||
# v1.x
|
||||
id = Column(Integer, primary_key=True)
|
||||
@@ -19,9 +27,12 @@ class ShiftedSeason(Base):
|
||||
# pattern: Mapped[str] = mapped_column(String, nullable=False)
|
||||
|
||||
# v1.x
|
||||
show_id = Column(Integer, ForeignKey('shows.id', ondelete="CASCADE"))
|
||||
show_id = Column(Integer, ForeignKey('shows.id', ondelete="CASCADE"), nullable=True)
|
||||
show = relationship(Show, back_populates='shifted_seasons', lazy='joined')
|
||||
|
||||
pattern_id = Column(Integer, ForeignKey('patterns.id', ondelete="CASCADE"), nullable=True)
|
||||
pattern = relationship('Pattern', back_populates='shifted_seasons', lazy='joined')
|
||||
|
||||
# v2.0
|
||||
# show_id: Mapped[int] = mapped_column(ForeignKey("shows.id", ondelete="CASCADE"))
|
||||
# show: Mapped["Show"] = relationship(back_populates="patterns")
|
||||
@@ -39,6 +50,12 @@ class ShiftedSeason(Base):
|
||||
def getId(self):
|
||||
return self.id
|
||||
|
||||
def getShowId(self):
|
||||
return self.show_id
|
||||
|
||||
def getPatternId(self):
|
||||
return self.pattern_id
|
||||
|
||||
|
||||
def getOriginalSeason(self):
|
||||
return self.original_season
|
||||
@@ -61,6 +78,8 @@ class ShiftedSeason(Base):
|
||||
|
||||
shiftedSeasonObj = {}
|
||||
|
||||
shiftedSeasonObj['show_id'] = self.getShowId()
|
||||
shiftedSeasonObj['pattern_id'] = self.getPatternId()
|
||||
shiftedSeasonObj['original_season'] = self.getOriginalSeason()
|
||||
shiftedSeasonObj['first_episode'] = self.getFirstEpisode()
|
||||
shiftedSeasonObj['last_episode'] = self.getLastEpisode()
|
||||
@@ -68,4 +87,3 @@ class ShiftedSeason(Base):
|
||||
shiftedSeasonObj['episode_offset'] = self.getEpisodeOffset()
|
||||
|
||||
return shiftedSeasonObj
|
||||
|
||||
|
||||
@@ -9,6 +9,8 @@ from ffx.model.pattern import Pattern
|
||||
|
||||
from .track_details_screen import TrackDetailsScreen
|
||||
from .track_delete_screen import TrackDeleteScreen
|
||||
from .shifted_season_delete_screen import ShiftedSeasonDeleteScreen
|
||||
from .shifted_season_details_screen import ShiftedSeasonDetailsScreen
|
||||
|
||||
from .tag_details_screen import TagDetailsScreen
|
||||
from .tag_delete_screen import TagDeleteScreen
|
||||
@@ -24,6 +26,7 @@ from textual.widgets._data_table import CellDoesNotExist
|
||||
from ffx.file_properties import FileProperties
|
||||
from ffx.iso_language import IsoLanguage
|
||||
from ffx.audio_layout import AudioLayout
|
||||
from ffx.model.shifted_season import ShiftedSeason
|
||||
|
||||
from ffx.helper import formatRichColor, removeRichColor
|
||||
|
||||
@@ -34,8 +37,8 @@ class PatternDetailsScreen(Screen):
|
||||
CSS = """
|
||||
|
||||
Grid {
|
||||
grid-size: 7 17;
|
||||
grid-rows: 2 2 2 2 2 2 6 2 2 8 2 2 8 2 2 2 2;
|
||||
grid-size: 7 20;
|
||||
grid-rows: 2 2 2 2 2 2 6 2 2 8 2 2 8 2 2 8 2 2 2 2;
|
||||
grid-columns: 25 25 25 25 25 25 25;
|
||||
height: 100%;
|
||||
width: 100%;
|
||||
@@ -115,11 +118,13 @@ class PatternDetailsScreen(Screen):
|
||||
show=True,
|
||||
track=True,
|
||||
tag=True,
|
||||
shifted_season=True,
|
||||
)
|
||||
self.__pc = controllers['pattern']
|
||||
self.__sc = controllers['show']
|
||||
self.__tc = controllers['track']
|
||||
self.__tac = controllers['tag']
|
||||
self.__ssc = controllers['shifted_season']
|
||||
|
||||
self.__pattern : Pattern = self.__pc.getPattern(patternId) if patternId is not None else None
|
||||
self.__showDescriptor = self.__sc.getShowDescriptor(showId) if showId is not None else None
|
||||
@@ -258,6 +263,72 @@ class PatternDetailsScreen(Screen):
|
||||
row = (formatRichColor(tagKey, textColor), formatRichColor(tagValue, textColor))
|
||||
self.tagsTable.add_row(*map(str, row))
|
||||
|
||||
def updateShiftedSeasons(self):
|
||||
|
||||
self.shiftedSeasonsTable.clear()
|
||||
|
||||
if self.__pattern is None:
|
||||
return
|
||||
|
||||
shiftedSeason: ShiftedSeason
|
||||
for shiftedSeason in self.__ssc.getShiftedSeasonSiblings(patternId=self.__pattern.getId()):
|
||||
shiftedSeasonObj = shiftedSeason.getObj()
|
||||
|
||||
firstEpisode = shiftedSeasonObj['first_episode']
|
||||
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))
|
||||
|
||||
def getSelectedShiftedSeasonObjFromInput(self):
|
||||
|
||||
shiftedSeasonObj = {}
|
||||
|
||||
try:
|
||||
row_key, col_key = self.shiftedSeasonsTable.coordinate_to_cell_key(
|
||||
self.shiftedSeasonsTable.cursor_coordinate
|
||||
)
|
||||
|
||||
if row_key is not None:
|
||||
selected_row_data = self.shiftedSeasonsTable.get_row(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:
|
||||
pass
|
||||
|
||||
return shiftedSeasonObj
|
||||
|
||||
|
||||
def on_mount(self):
|
||||
|
||||
@@ -276,6 +347,7 @@ class PatternDetailsScreen(Screen):
|
||||
|
||||
self.updateTags()
|
||||
self.updateTracks()
|
||||
self.updateShiftedSeasons()
|
||||
|
||||
def compose(self):
|
||||
|
||||
@@ -304,6 +376,16 @@ class PatternDetailsScreen(Screen):
|
||||
|
||||
self.tracksTable.cursor_type = 'row'
|
||||
|
||||
self.shiftedSeasonsTable = DataTable(classes="seven")
|
||||
|
||||
self.column_key_original_season = self.shiftedSeasonsTable.add_column("Original Season", width=18)
|
||||
self.column_key_first_episode = self.shiftedSeasonsTable.add_column("First Episode", width=18)
|
||||
self.column_key_last_episode = self.shiftedSeasonsTable.add_column("Last Episode", width=18)
|
||||
self.column_key_season_offset = self.shiftedSeasonsTable.add_column("Season Offset", width=18)
|
||||
self.column_key_episode_offset = self.shiftedSeasonsTable.add_column("Episode Offset", width=18)
|
||||
|
||||
self.shiftedSeasonsTable.cursor_type = 'row'
|
||||
|
||||
|
||||
yield Header()
|
||||
|
||||
@@ -345,6 +427,27 @@ class PatternDetailsScreen(Screen):
|
||||
yield Static(" ", classes="seven")
|
||||
|
||||
# 9
|
||||
yield Static("Shifted Seasons")
|
||||
if self.__pattern is not None:
|
||||
yield Button("Add", id="button_add_shifted_season")
|
||||
yield Button("Edit", id="button_edit_shifted_season")
|
||||
yield Button("Delete", id="button_delete_shifted_season")
|
||||
else:
|
||||
yield Static(" ")
|
||||
yield Static(" ")
|
||||
yield Static(" ")
|
||||
|
||||
yield Static(" ")
|
||||
yield Static(" ")
|
||||
yield Static(" ")
|
||||
|
||||
# 10
|
||||
yield self.shiftedSeasonsTable
|
||||
|
||||
# 11
|
||||
yield Static(" ", classes="seven")
|
||||
|
||||
# 12
|
||||
yield Static("Media Tags")
|
||||
yield Button("Add", id="button_add_tag")
|
||||
yield Button("Edit", id="button_edit_tag")
|
||||
@@ -354,13 +457,13 @@ class PatternDetailsScreen(Screen):
|
||||
yield Static(" ")
|
||||
yield Static(" ")
|
||||
|
||||
# 10
|
||||
# 13
|
||||
yield self.tagsTable
|
||||
|
||||
# 11
|
||||
# 14
|
||||
yield Static(" ", classes="seven")
|
||||
|
||||
# 12
|
||||
# 15
|
||||
yield Static("Streams")
|
||||
yield Button("Add", id="button_add_track")
|
||||
yield Button("Edit", id="button_edit_track")
|
||||
@@ -370,21 +473,21 @@ class PatternDetailsScreen(Screen):
|
||||
yield Button("Up", id="button_track_up")
|
||||
yield Button("Down", id="button_track_down")
|
||||
|
||||
# 13
|
||||
# 16
|
||||
yield self.tracksTable
|
||||
|
||||
# 14
|
||||
# 17
|
||||
yield Static(" ", classes="seven")
|
||||
|
||||
# 15
|
||||
# 18
|
||||
yield Static(" ", classes="seven")
|
||||
|
||||
# 16
|
||||
# 19
|
||||
yield Button("Save", id="save_button")
|
||||
yield Button("Cancel", id="cancel_button")
|
||||
yield Static(" ", classes="five")
|
||||
|
||||
# 17
|
||||
# 20
|
||||
yield Static(" ", classes="seven")
|
||||
|
||||
yield Footer()
|
||||
@@ -486,6 +589,35 @@ class PatternDetailsScreen(Screen):
|
||||
if event.button.id == "cancel_button":
|
||||
self.app.pop_screen()
|
||||
|
||||
if event.button.id == "button_add_shifted_season":
|
||||
if self.__pattern is not None:
|
||||
self.app.push_screen(
|
||||
ShiftedSeasonDetailsScreen(patternId=self.__pattern.getId()),
|
||||
self.handle_update_shifted_season,
|
||||
)
|
||||
|
||||
if event.button.id == "button_edit_shifted_season":
|
||||
selectedShiftedSeasonObj = self.getSelectedShiftedSeasonObjFromInput()
|
||||
if 'id' in selectedShiftedSeasonObj.keys():
|
||||
self.app.push_screen(
|
||||
ShiftedSeasonDetailsScreen(
|
||||
patternId=self.__pattern.getId(),
|
||||
shiftedSeasonId=selectedShiftedSeasonObj['id'],
|
||||
),
|
||||
self.handle_update_shifted_season,
|
||||
)
|
||||
|
||||
if event.button.id == "button_delete_shifted_season":
|
||||
selectedShiftedSeasonObj = self.getSelectedShiftedSeasonObjFromInput()
|
||||
if 'id' in selectedShiftedSeasonObj.keys():
|
||||
self.app.push_screen(
|
||||
ShiftedSeasonDeleteScreen(
|
||||
patternId=self.__pattern.getId(),
|
||||
shiftedSeasonId=selectedShiftedSeasonObj['id'],
|
||||
),
|
||||
self.handle_delete_shifted_season,
|
||||
)
|
||||
|
||||
|
||||
numTracks = len(self.getCurrentTrackDescriptors())
|
||||
|
||||
@@ -654,3 +786,9 @@ class PatternDetailsScreen(Screen):
|
||||
self.updateTags()
|
||||
else:
|
||||
raise click.ClickException('tag delete failed')
|
||||
|
||||
def handle_update_shifted_season(self, screenResult):
|
||||
self.updateShiftedSeasons()
|
||||
|
||||
def handle_delete_shifted_season(self, screenResult):
|
||||
self.updateShiftedSeasons()
|
||||
|
||||
@@ -6,225 +6,431 @@ from ffx.model.shifted_season import ShiftedSeason
|
||||
class EpisodeOrderException(Exception):
|
||||
pass
|
||||
|
||||
|
||||
class RangeOverlapException(Exception):
|
||||
pass
|
||||
|
||||
|
||||
class ShiftedSeasonController():
|
||||
|
||||
class ShiftedSeasonOwnerException(Exception):
|
||||
pass
|
||||
|
||||
|
||||
class ShiftedSeasonController:
|
||||
|
||||
def __init__(self, context):
|
||||
|
||||
|
||||
self.context = context
|
||||
self.Session = self.context['database']['session'] # convenience
|
||||
self.Session = self.context['database']['session'] # convenience
|
||||
|
||||
def checkShiftedSeason(self, showId: int, shiftedSeasonObj: dict, shiftedSeasonId: int = 0):
|
||||
def _resolve_owner(self, showId=None, patternId=None):
|
||||
hasShow = showId is not None
|
||||
hasPattern = patternId is not None
|
||||
|
||||
if hasShow == hasPattern:
|
||||
raise ShiftedSeasonOwnerException(
|
||||
"ShiftedSeason rules require exactly one owner: either showId or patternId."
|
||||
)
|
||||
|
||||
if hasShow:
|
||||
if type(showId) is not int:
|
||||
raise ValueError(
|
||||
"ShiftedSeasonController: Argument showId is required to be of type int"
|
||||
)
|
||||
return {
|
||||
'show_id': int(showId),
|
||||
'pattern_id': None,
|
||||
'label': f"show #{int(showId)}",
|
||||
}
|
||||
|
||||
if type(patternId) is not int:
|
||||
raise ValueError(
|
||||
"ShiftedSeasonController: Argument patternId is required to be of type int"
|
||||
)
|
||||
return {
|
||||
'show_id': None,
|
||||
'pattern_id': int(patternId),
|
||||
'label': f"pattern #{int(patternId)}",
|
||||
}
|
||||
|
||||
def _apply_owner_filter(self, query, owner):
|
||||
if owner['pattern_id'] is not None:
|
||||
return query.filter(ShiftedSeason.pattern_id == owner['pattern_id'])
|
||||
return query.filter(ShiftedSeason.show_id == owner['show_id'])
|
||||
|
||||
def _normalize_shifted_season_fields(self, shiftedSeasonObj: dict):
|
||||
if type(shiftedSeasonObj) is not dict:
|
||||
raise ValueError(
|
||||
"ShiftedSeasonController: Argument shiftedSeasonObj is required to be of type dict"
|
||||
)
|
||||
|
||||
fields = {
|
||||
'original_season': int(shiftedSeasonObj['original_season']),
|
||||
'first_episode': int(shiftedSeasonObj['first_episode']),
|
||||
'last_episode': int(shiftedSeasonObj['last_episode']),
|
||||
'season_offset': int(shiftedSeasonObj['season_offset']),
|
||||
'episode_offset': int(shiftedSeasonObj['episode_offset']),
|
||||
}
|
||||
|
||||
firstEpisode = fields['first_episode']
|
||||
lastEpisode = fields['last_episode']
|
||||
if firstEpisode != -1 and lastEpisode != -1 and lastEpisode < firstEpisode:
|
||||
raise EpisodeOrderException(
|
||||
"ShiftedSeason last_episode must be greater than or equal to first_episode."
|
||||
)
|
||||
|
||||
return fields
|
||||
|
||||
def _ranges_overlap(self, firstEpisodeA, lastEpisodeA, firstEpisodeB, lastEpisodeB):
|
||||
startA = float('-inf') if int(firstEpisodeA) == -1 else int(firstEpisodeA)
|
||||
endA = float('inf') if int(lastEpisodeA) == -1 else int(lastEpisodeA)
|
||||
startB = float('-inf') if int(firstEpisodeB) == -1 else int(firstEpisodeB)
|
||||
endB = float('inf') if int(lastEpisodeB) == -1 else int(lastEpisodeB)
|
||||
return startA <= endB and startB <= endA
|
||||
|
||||
def _ordered_query(self, session, owner):
|
||||
q = self._apply_owner_filter(session.query(ShiftedSeason), owner)
|
||||
return q.order_by(
|
||||
ShiftedSeason.original_season.asc(),
|
||||
ShiftedSeason.first_episode.asc(),
|
||||
ShiftedSeason.last_episode.asc(),
|
||||
ShiftedSeason.id.asc(),
|
||||
)
|
||||
|
||||
def _find_matching_rule(self, session, owner, season: int, episode: int):
|
||||
for shiftedSeasonEntry in self._ordered_query(session, owner).all():
|
||||
if (
|
||||
season == shiftedSeasonEntry.getOriginalSeason()
|
||||
and (
|
||||
shiftedSeasonEntry.getFirstEpisode() == -1
|
||||
or episode >= shiftedSeasonEntry.getFirstEpisode()
|
||||
)
|
||||
and (
|
||||
shiftedSeasonEntry.getLastEpisode() == -1
|
||||
or episode <= shiftedSeasonEntry.getLastEpisode()
|
||||
)
|
||||
):
|
||||
return shiftedSeasonEntry
|
||||
return None
|
||||
|
||||
def checkShiftedSeason(
|
||||
self,
|
||||
showId: int | None = None,
|
||||
shiftedSeasonObj: dict | None = None,
|
||||
shiftedSeasonId: int = 0,
|
||||
patternId: int | None = None,
|
||||
):
|
||||
"""
|
||||
Check if for a particula season
|
||||
|
||||
shiftedSeasonId
|
||||
Check whether a shifted-season rule is valid within one owner scope.
|
||||
"""
|
||||
|
||||
session = None
|
||||
try:
|
||||
s = self.Session()
|
||||
owner = self._resolve_owner(showId=showId, patternId=patternId)
|
||||
fields = self._normalize_shifted_season_fields(shiftedSeasonObj)
|
||||
session = self.Session()
|
||||
|
||||
originalSeason = shiftedSeasonObj['original_season']
|
||||
firstEpisode = int(shiftedSeasonObj['first_episode'])
|
||||
lastEpisode = int(shiftedSeasonObj['last_episode'])
|
||||
|
||||
q = s.query(ShiftedSeason).filter(ShiftedSeason.show_id == int(showId))
|
||||
q = self._ordered_query(session, owner)
|
||||
if shiftedSeasonId:
|
||||
q = q.filter(ShiftedSeason.id != int(shiftedSeasonId))
|
||||
|
||||
siblingShiftedSeason: ShiftedSeason
|
||||
for siblingShiftedSeason in q.all():
|
||||
|
||||
siblingOriginalSeason = siblingShiftedSeason.getOriginalSeason
|
||||
siblingFirstEpisode = siblingShiftedSeason.getFirstEpisode()
|
||||
siblingLastEpisode = siblingShiftedSeason.getLastEpisode()
|
||||
|
||||
if (originalSeason == siblingOriginalSeason
|
||||
and lastEpisode >= siblingFirstEpisode
|
||||
and siblingLastEpisode >= firstEpisode):
|
||||
if fields['original_season'] != siblingShiftedSeason.getOriginalSeason():
|
||||
continue
|
||||
|
||||
if self._ranges_overlap(
|
||||
fields['first_episode'],
|
||||
fields['last_episode'],
|
||||
siblingShiftedSeason.getFirstEpisode(),
|
||||
siblingShiftedSeason.getLastEpisode(),
|
||||
):
|
||||
return False
|
||||
|
||||
return True
|
||||
|
||||
except (EpisodeOrderException, ShiftedSeasonOwnerException) as ex:
|
||||
raise click.ClickException(str(ex))
|
||||
except Exception as ex:
|
||||
raise click.ClickException(f"ShiftedSeasonController.addShiftedSeason(): {repr(ex)}")
|
||||
raise click.ClickException(
|
||||
f"ShiftedSeasonController.checkShiftedSeason(): {repr(ex)}"
|
||||
)
|
||||
finally:
|
||||
s.close()
|
||||
if session is not None:
|
||||
session.close()
|
||||
|
||||
def addShiftedSeason(
|
||||
self,
|
||||
showId: int | None = None,
|
||||
shiftedSeasonObj: dict | None = None,
|
||||
patternId: int | None = None,
|
||||
):
|
||||
|
||||
def addShiftedSeason(self, showId: int, shiftedSeasonObj: dict):
|
||||
|
||||
if type(showId) is not int:
|
||||
raise ValueError(f"ShiftedSeasonController.addShiftedSeason(): Argument showId is required to be of type int")
|
||||
|
||||
if type(shiftedSeasonObj) is not dict:
|
||||
raise ValueError(f"ShiftedSeasonController.addShiftedSeason(): Argument shiftedSeasonObj is required to be of type dict")
|
||||
|
||||
session = None
|
||||
try:
|
||||
s = self.Session()
|
||||
owner = self._resolve_owner(showId=showId, patternId=patternId)
|
||||
fields = self._normalize_shifted_season_fields(shiftedSeasonObj)
|
||||
|
||||
firstEpisode = int(shiftedSeasonObj['first_episode'])
|
||||
lastEpisode = int(shiftedSeasonObj['last_episode'])
|
||||
if not self.checkShiftedSeason(
|
||||
showId=owner['show_id'],
|
||||
patternId=owner['pattern_id'],
|
||||
shiftedSeasonObj=fields,
|
||||
):
|
||||
raise RangeOverlapException(
|
||||
f"ShiftedSeason rule overlaps with an existing rule for {owner['label']}."
|
||||
)
|
||||
|
||||
if lastEpisode < firstEpisode:
|
||||
raise EpisodeOrderException()
|
||||
|
||||
q = s.query(ShiftedSeason).filter(ShiftedSeason.show_id == int(showId))
|
||||
|
||||
shiftedSeason = ShiftedSeason(show_id = int(showId),
|
||||
original_season = int(shiftedSeasonObj['original_season']),
|
||||
first_episode = firstEpisode,
|
||||
last_episode = lastEpisode,
|
||||
season_offset = int(shiftedSeasonObj['season_offset']),
|
||||
episode_offset = int(shiftedSeasonObj['episode_offset']))
|
||||
s.add(shiftedSeason)
|
||||
s.commit()
|
||||
session = self.Session()
|
||||
shiftedSeason = ShiftedSeason(
|
||||
show_id=owner['show_id'],
|
||||
pattern_id=owner['pattern_id'],
|
||||
original_season=fields['original_season'],
|
||||
first_episode=fields['first_episode'],
|
||||
last_episode=fields['last_episode'],
|
||||
season_offset=fields['season_offset'],
|
||||
episode_offset=fields['episode_offset'],
|
||||
)
|
||||
session.add(shiftedSeason)
|
||||
session.commit()
|
||||
return shiftedSeason.getId()
|
||||
|
||||
except (EpisodeOrderException, RangeOverlapException, ShiftedSeasonOwnerException) as ex:
|
||||
raise click.ClickException(str(ex))
|
||||
except Exception as ex:
|
||||
raise click.ClickException(f"ShiftedSeasonController.addShiftedSeason(): {repr(ex)}")
|
||||
raise click.ClickException(
|
||||
f"ShiftedSeasonController.addShiftedSeason(): {repr(ex)}"
|
||||
)
|
||||
finally:
|
||||
s.close()
|
||||
|
||||
if session is not None:
|
||||
session.close()
|
||||
|
||||
def updateShiftedSeason(self, shiftedSeasonId: int, shiftedSeasonObj: dict):
|
||||
|
||||
if type(shiftedSeasonId) is not int:
|
||||
raise ValueError(f"ShiftedSeasonController.updateShiftedSeason(): Argument shiftedSeasonId is required to be of type int")
|
||||
|
||||
if type(shiftedSeasonObj) is not dict:
|
||||
raise ValueError(f"ShiftedSeasonController.updateShiftedSeason(): Argument shiftedSeasonObj is required to be of type dict")
|
||||
raise ValueError(
|
||||
"ShiftedSeasonController.updateShiftedSeason(): Argument shiftedSeasonId is required to be of type int"
|
||||
)
|
||||
|
||||
session = None
|
||||
try:
|
||||
s = self.Session()
|
||||
fields = self._normalize_shifted_season_fields(shiftedSeasonObj)
|
||||
session = self.Session()
|
||||
|
||||
shiftedSeason = s.query(ShiftedSeason).filter(ShiftedSeason.id == int(shiftedSeasonId)).first()
|
||||
shiftedSeason = (
|
||||
session.query(ShiftedSeason)
|
||||
.filter(ShiftedSeason.id == int(shiftedSeasonId))
|
||||
.first()
|
||||
)
|
||||
|
||||
if shiftedSeason is not None:
|
||||
|
||||
shiftedSeason.original_season = int(shiftedSeasonObj['original_season'])
|
||||
shiftedSeason.first_episode = int(shiftedSeasonObj['first_episode'])
|
||||
shiftedSeason.last_episode = int(shiftedSeasonObj['last_episode'])
|
||||
shiftedSeason.season_offset = int(shiftedSeasonObj['season_offset'])
|
||||
shiftedSeason.episode_offset = int(shiftedSeasonObj['episode_offset'])
|
||||
|
||||
s.commit()
|
||||
return True
|
||||
|
||||
else:
|
||||
if shiftedSeason is None:
|
||||
return False
|
||||
|
||||
owner = self._resolve_owner(
|
||||
showId=shiftedSeason.getShowId(),
|
||||
patternId=shiftedSeason.getPatternId(),
|
||||
)
|
||||
if not self.checkShiftedSeason(
|
||||
showId=owner['show_id'],
|
||||
patternId=owner['pattern_id'],
|
||||
shiftedSeasonObj=fields,
|
||||
shiftedSeasonId=shiftedSeasonId,
|
||||
):
|
||||
raise RangeOverlapException(
|
||||
f"ShiftedSeason rule overlaps with an existing rule for {owner['label']}."
|
||||
)
|
||||
|
||||
shiftedSeason.original_season = fields['original_season']
|
||||
shiftedSeason.first_episode = fields['first_episode']
|
||||
shiftedSeason.last_episode = fields['last_episode']
|
||||
shiftedSeason.season_offset = fields['season_offset']
|
||||
shiftedSeason.episode_offset = fields['episode_offset']
|
||||
|
||||
session.commit()
|
||||
return True
|
||||
|
||||
except (EpisodeOrderException, RangeOverlapException, ShiftedSeasonOwnerException) as ex:
|
||||
raise click.ClickException(str(ex))
|
||||
except Exception as ex:
|
||||
raise click.ClickException(f"ShiftedSeasonController.updateShiftedSeason(): {repr(ex)}")
|
||||
raise click.ClickException(
|
||||
f"ShiftedSeasonController.updateShiftedSeason(): {repr(ex)}"
|
||||
)
|
||||
finally:
|
||||
s.close()
|
||||
if session is not None:
|
||||
session.close()
|
||||
|
||||
|
||||
def findShiftedSeason(self, showId: int, originalSeason: int, firstEpisode: int, lastEpisode: int):
|
||||
|
||||
if type(showId) is not int:
|
||||
raise ValueError(f"ShiftedSeasonController.findShiftedSeason(): Argument shiftedSeasonId is required to be of type int")
|
||||
def findShiftedSeason(
|
||||
self,
|
||||
showId: int | None = None,
|
||||
originalSeason: int | None = None,
|
||||
firstEpisode: int | None = None,
|
||||
lastEpisode: int | None = None,
|
||||
patternId: int | None = None,
|
||||
):
|
||||
|
||||
if type(originalSeason) is not int:
|
||||
raise ValueError(f"ShiftedSeasonController.findShiftedSeason(): Argument originalSeason is required to be of type int")
|
||||
raise ValueError(
|
||||
"ShiftedSeasonController.findShiftedSeason(): Argument originalSeason is required to be of type int"
|
||||
)
|
||||
|
||||
if type(firstEpisode) is not int:
|
||||
raise ValueError(f"ShiftedSeasonController.findShiftedSeason(): Argument firstEpisode is required to be of type int")
|
||||
raise ValueError(
|
||||
"ShiftedSeasonController.findShiftedSeason(): Argument firstEpisode is required to be of type int"
|
||||
)
|
||||
|
||||
if type(lastEpisode) is not int:
|
||||
raise ValueError(f"ShiftedSeasonController.findShiftedSeason(): Argument lastEpisode is required to be of type int")
|
||||
raise ValueError(
|
||||
"ShiftedSeasonController.findShiftedSeason(): Argument lastEpisode is required to be of type int"
|
||||
)
|
||||
|
||||
session = None
|
||||
try:
|
||||
s = self.Session()
|
||||
shiftedSeason = s.query(ShiftedSeason).filter(
|
||||
ShiftedSeason.show_id == int(showId),
|
||||
ShiftedSeason.original_season == int(originalSeason),
|
||||
ShiftedSeason.first_episode == int(firstEpisode),
|
||||
ShiftedSeason.last_episode == int(lastEpisode),
|
||||
).first()
|
||||
owner = self._resolve_owner(showId=showId, patternId=patternId)
|
||||
session = self.Session()
|
||||
shiftedSeason = (
|
||||
self._apply_owner_filter(session.query(ShiftedSeason), owner)
|
||||
.filter(
|
||||
ShiftedSeason.original_season == int(originalSeason),
|
||||
ShiftedSeason.first_episode == int(firstEpisode),
|
||||
ShiftedSeason.last_episode == int(lastEpisode),
|
||||
)
|
||||
.first()
|
||||
)
|
||||
|
||||
return shiftedSeason.getId() if shiftedSeason is not None else None
|
||||
|
||||
except ShiftedSeasonOwnerException as ex:
|
||||
raise click.ClickException(str(ex))
|
||||
except Exception as ex:
|
||||
raise click.ClickException(f"PatternController.findShiftedSeason(): {repr(ex)}")
|
||||
raise click.ClickException(
|
||||
f"ShiftedSeasonController.findShiftedSeason(): {repr(ex)}"
|
||||
)
|
||||
finally:
|
||||
s.close()
|
||||
if session is not None:
|
||||
session.close()
|
||||
|
||||
def getShiftedSeasonSiblings(self, showId: int):
|
||||
|
||||
if type(showId) is not int:
|
||||
raise ValueError(f"ShiftedSeasonController.getShiftedSeasonSiblings(): Argument shiftedSeasonId is required to be of type int")
|
||||
def getShiftedSeasonSiblings(
|
||||
self,
|
||||
showId: int | None = None,
|
||||
patternId: int | None = None,
|
||||
):
|
||||
session = None
|
||||
|
||||
try:
|
||||
s = self.Session()
|
||||
q = s.query(ShiftedSeason).filter(ShiftedSeason.show_id == int(showId))
|
||||
|
||||
return q.all()
|
||||
owner = self._resolve_owner(showId=showId, patternId=patternId)
|
||||
session = self.Session()
|
||||
return self._ordered_query(session, owner).all()
|
||||
|
||||
except ShiftedSeasonOwnerException as ex:
|
||||
raise click.ClickException(str(ex))
|
||||
except Exception as ex:
|
||||
raise click.ClickException(f"PatternController.getShiftedSeasonSiblings(): {repr(ex)}")
|
||||
raise click.ClickException(
|
||||
f"ShiftedSeasonController.getShiftedSeasonSiblings(): {repr(ex)}"
|
||||
)
|
||||
finally:
|
||||
s.close()
|
||||
|
||||
if session is not None:
|
||||
session.close()
|
||||
|
||||
def getShiftedSeason(self, shiftedSeasonId: int):
|
||||
|
||||
if type(shiftedSeasonId) is not int:
|
||||
raise ValueError(f"ShiftedSeasonController.getShiftedSeason(): Argument shiftedSeasonId is required to be of type int")
|
||||
raise ValueError(
|
||||
"ShiftedSeasonController.getShiftedSeason(): Argument shiftedSeasonId is required to be of type int"
|
||||
)
|
||||
|
||||
session = None
|
||||
try:
|
||||
s = self.Session()
|
||||
return s.query(ShiftedSeason).filter(ShiftedSeason.id == int(shiftedSeasonId)).first()
|
||||
session = self.Session()
|
||||
return (
|
||||
session.query(ShiftedSeason)
|
||||
.filter(ShiftedSeason.id == int(shiftedSeasonId))
|
||||
.first()
|
||||
)
|
||||
|
||||
except Exception as ex:
|
||||
raise click.ClickException(f"ShiftedSeasonController.getShiftedSeason(): {repr(ex)}")
|
||||
raise click.ClickException(
|
||||
f"ShiftedSeasonController.getShiftedSeason(): {repr(ex)}"
|
||||
)
|
||||
finally:
|
||||
s.close()
|
||||
|
||||
if session is not None:
|
||||
session.close()
|
||||
|
||||
def deleteShiftedSeason(self, shiftedSeasonId):
|
||||
|
||||
if type(shiftedSeasonId) is not int:
|
||||
raise ValueError(f"ShiftedSeasonController.deleteShiftedSeason(): Argument shiftedSeasonId is required to be of type int")
|
||||
raise ValueError(
|
||||
"ShiftedSeasonController.deleteShiftedSeason(): Argument shiftedSeasonId is required to be of type int"
|
||||
)
|
||||
|
||||
session = None
|
||||
try:
|
||||
s = self.Session()
|
||||
shiftedSeason = s.query(ShiftedSeason).filter(ShiftedSeason.id == int(shiftedSeasonId)).first()
|
||||
session = self.Session()
|
||||
shiftedSeason = (
|
||||
session.query(ShiftedSeason)
|
||||
.filter(ShiftedSeason.id == int(shiftedSeasonId))
|
||||
.first()
|
||||
)
|
||||
|
||||
if shiftedSeason is not None:
|
||||
|
||||
#DAFUQ: https://stackoverflow.com/a/19245058
|
||||
# q.delete()
|
||||
s.delete(shiftedSeason)
|
||||
|
||||
s.commit()
|
||||
session.delete(shiftedSeason)
|
||||
session.commit()
|
||||
return True
|
||||
return False
|
||||
|
||||
except Exception as ex:
|
||||
raise click.ClickException(f"ShiftedSeasonController.deleteShiftedSeason(): {repr(ex)}")
|
||||
raise click.ClickException(
|
||||
f"ShiftedSeasonController.deleteShiftedSeason(): {repr(ex)}"
|
||||
)
|
||||
finally:
|
||||
s.close()
|
||||
if session is not None:
|
||||
session.close()
|
||||
|
||||
def shiftSeason(self, showId, season, episode, patternId=None):
|
||||
|
||||
def shiftSeason(self, showId, season, episode):
|
||||
if season == -1 or episode == -1:
|
||||
return season, episode
|
||||
|
||||
shiftedSeasonEntry: ShiftedSeason
|
||||
for shiftedSeasonEntry in self.getShiftedSeasonSiblings(showId):
|
||||
session = None
|
||||
try:
|
||||
session = self.Session()
|
||||
activeShift = None
|
||||
|
||||
if (season == shiftedSeasonEntry.getOriginalSeason()
|
||||
and (shiftedSeasonEntry.getFirstEpisode() == -1 or episode >= shiftedSeasonEntry.getFirstEpisode())
|
||||
and (shiftedSeasonEntry.getLastEpisode() == -1 or episode <= shiftedSeasonEntry.getLastEpisode())):
|
||||
if patternId is not None:
|
||||
activeShift = self._find_matching_rule(
|
||||
session,
|
||||
self._resolve_owner(patternId=patternId),
|
||||
season=int(season),
|
||||
episode=int(episode),
|
||||
)
|
||||
|
||||
shiftedSeason = season + shiftedSeasonEntry.getSeasonOffset()
|
||||
shiftedEpisode = episode + shiftedSeasonEntry.getEpisodeOffset()
|
||||
if activeShift is None and showId is not None and showId != -1:
|
||||
activeShift = self._find_matching_rule(
|
||||
session,
|
||||
self._resolve_owner(showId=showId),
|
||||
season=int(season),
|
||||
episode=int(episode),
|
||||
)
|
||||
|
||||
self.context['logger'].info(f"Shifting season: {season} episode: {episode} "
|
||||
+f"-> season: {shiftedSeason} episode: {shiftedEpisode}")
|
||||
if activeShift is None:
|
||||
return season, episode
|
||||
|
||||
return shiftedSeason, shiftedEpisode
|
||||
|
||||
return season, episode
|
||||
shiftedSeason = season + activeShift.getSeasonOffset()
|
||||
shiftedEpisode = episode + activeShift.getEpisodeOffset()
|
||||
|
||||
ownerLabel = (
|
||||
f"pattern #{activeShift.getPatternId()}"
|
||||
if activeShift.getPatternId() is not None
|
||||
else f"show #{activeShift.getShowId()}"
|
||||
)
|
||||
self.context['logger'].info(
|
||||
f"Shifting season via {ownerLabel}: {season}/{episode} -> {shiftedSeason}/{shiftedEpisode}"
|
||||
)
|
||||
|
||||
return shiftedSeason, shiftedEpisode
|
||||
|
||||
except ShiftedSeasonOwnerException as ex:
|
||||
raise click.ClickException(str(ex))
|
||||
except Exception as ex:
|
||||
raise click.ClickException(
|
||||
f"ShiftedSeasonController.shiftSeason(): {repr(ex)}"
|
||||
)
|
||||
finally:
|
||||
if session is not None:
|
||||
session.close()
|
||||
|
||||
@@ -43,7 +43,7 @@ class ShiftedSeasonDeleteScreen(Screen):
|
||||
}
|
||||
"""
|
||||
|
||||
def __init__(self, showId = None, shiftedSeasonId = None):
|
||||
def __init__(self, showId = None, patternId = None, shiftedSeasonId = None):
|
||||
super().__init__()
|
||||
|
||||
self.context = self.app.getContext()
|
||||
@@ -52,6 +52,7 @@ class ShiftedSeasonDeleteScreen(Screen):
|
||||
self.__ssc = ShiftedSeasonController(context = self.context)
|
||||
|
||||
self._showId = showId
|
||||
self._patternId = patternId
|
||||
self.__shiftedSeasonId = shiftedSeasonId
|
||||
|
||||
|
||||
@@ -59,7 +60,12 @@ class ShiftedSeasonDeleteScreen(Screen):
|
||||
|
||||
shiftedSeason: ShiftedSeason = self.__ssc.getShiftedSeason(self.__shiftedSeasonId)
|
||||
|
||||
self.query_one("#static_show_id", Static).update(str(self._showId))
|
||||
ownerLabel = (
|
||||
f"pattern #{self._patternId}"
|
||||
if self._patternId is not None
|
||||
else f"show #{self._showId}"
|
||||
)
|
||||
self.query_one("#static_owner", Static).update(ownerLabel)
|
||||
self.query_one("#static_original_season", Static).update(str(shiftedSeason.getOriginalSeason()))
|
||||
self.query_one("#static_first_episode", Static).update(str(shiftedSeason.getFirstEpisode()))
|
||||
self.query_one("#static_last_episode", Static).update(str(shiftedSeason.getLastEpisode()))
|
||||
@@ -77,8 +83,8 @@ class ShiftedSeasonDeleteScreen(Screen):
|
||||
|
||||
yield Static(" ", classes="two")
|
||||
|
||||
yield Static("from show")
|
||||
yield Static(" ", id="static_show_id")
|
||||
yield Static("from")
|
||||
yield Static(" ", id="static_owner")
|
||||
|
||||
yield Static(" ", classes="two")
|
||||
|
||||
@@ -122,4 +128,3 @@ class ShiftedSeasonDeleteScreen(Screen):
|
||||
|
||||
if event.button.id == "cancel_button":
|
||||
self.app.pop_screen()
|
||||
|
||||
|
||||
@@ -81,7 +81,7 @@ class ShiftedSeasonDetailsScreen(Screen):
|
||||
}
|
||||
"""
|
||||
|
||||
def __init__(self, showId = None, shiftedSeasonId = None):
|
||||
def __init__(self, showId = None, patternId = None, shiftedSeasonId = None):
|
||||
super().__init__()
|
||||
|
||||
self.context = self.app.getContext()
|
||||
@@ -90,8 +90,14 @@ class ShiftedSeasonDetailsScreen(Screen):
|
||||
self.__ssc = ShiftedSeasonController(context = self.context)
|
||||
|
||||
self.__showId = showId
|
||||
self.__patternId = patternId
|
||||
self.__shiftedSeasonId = shiftedSeasonId
|
||||
|
||||
def _owner_kwargs(self):
|
||||
if self.__patternId is not None:
|
||||
return {'patternId': self.__patternId}
|
||||
return {'showId': self.__showId}
|
||||
|
||||
def on_mount(self):
|
||||
|
||||
if self.__shiftedSeasonId is not None:
|
||||
@@ -203,8 +209,11 @@ class ShiftedSeasonDetailsScreen(Screen):
|
||||
|
||||
if self.__shiftedSeasonId is not None:
|
||||
|
||||
if self.__ssc.checkShiftedSeason(self.__showId, shiftedSeasonObj,
|
||||
shiftedSeasonId = self.__shiftedSeasonId):
|
||||
if self.__ssc.checkShiftedSeason(
|
||||
shiftedSeasonObj=shiftedSeasonObj,
|
||||
shiftedSeasonId=self.__shiftedSeasonId,
|
||||
**self._owner_kwargs(),
|
||||
):
|
||||
if self.__ssc.updateShiftedSeason(self.__shiftedSeasonId, shiftedSeasonObj):
|
||||
self.dismiss((self.__shiftedSeasonId, shiftedSeasonObj))
|
||||
else:
|
||||
@@ -212,8 +221,14 @@ class ShiftedSeasonDetailsScreen(Screen):
|
||||
self.app.pop_screen()
|
||||
|
||||
else:
|
||||
if self.__ssc.checkShiftedSeason(self.__showId, shiftedSeasonObj):
|
||||
self.__shiftedSeasonId = self.__ssc.addShiftedSeason(self.__showId, shiftedSeasonObj)
|
||||
if self.__ssc.checkShiftedSeason(
|
||||
shiftedSeasonObj=shiftedSeasonObj,
|
||||
**self._owner_kwargs(),
|
||||
):
|
||||
self.__shiftedSeasonId = self.__ssc.addShiftedSeason(
|
||||
shiftedSeasonObj=shiftedSeasonObj,
|
||||
**self._owner_kwargs(),
|
||||
)
|
||||
self.dismiss((self.__shiftedSeasonId, shiftedSeasonObj))
|
||||
|
||||
|
||||
|
||||
@@ -211,11 +211,17 @@ class ShowDetailsScreen(Screen):
|
||||
if row_key is not None:
|
||||
selected_row_data = self.shiftedSeasonsTable.get_row(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'] = int(selected_row_data[1]) if selected_row_data[1].isnumeric() else -1
|
||||
shiftedSeasonObj['last_episode'] = int(selected_row_data[2]) if selected_row_data[2].isnumeric() else -1
|
||||
shiftedSeasonObj['season_offset'] = int(selected_row_data[3]) if selected_row_data[3].isnumeric() else 0
|
||||
shiftedSeasonObj['episode_offset'] = int(selected_row_data[4]) if selected_row_data[4].isnumeric() else 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:
|
||||
|
||||
Reference in New Issue
Block a user