diff --git a/VERSION b/VERSION index b0f3d96..66c4c22 100644 --- a/VERSION +++ b/VERSION @@ -1 +1 @@ -1.0.8 +1.0.9 diff --git a/engine/episode_match.py b/engine/episode_match.py index 65c7fb2..f3cc3ed 100644 --- a/engine/episode_match.py +++ b/engine/episode_match.py @@ -13,7 +13,7 @@ from .tvdb_client import TvdbEpisode # S01E05 - Title or S01E05-E06 - Title PATTERN_SXXEXX = re.compile( - r"^(.*?[Ss])(\d+)([Ee])(\d+)(-[Ee](\d+))?(.*)$", + r"^(.*?)([Ss])(\d+)([Ee])(\d+)(-[Ee](\d+))?(.*)$", ) # Show Name 04x01 Title, 4x01 - Title, etc. PATTERN_NXNN = re.compile( @@ -60,7 +60,7 @@ def parse_episode_stem(stem: str, pattern: str = DEFAULT_EPISODE_PATTERN) -> Opt m = PATTERN_SXXEXX.match(stem) if m: - prefix_before_s, season_s, _e, ep_s, _dash, ep2_s, rest = m.groups() + prefix, s_letter, season_s, e_letter, ep_s, _range_block, ep2_s, rest = m.groups() try: season = int(season_s) old_first = int(ep_s) @@ -78,7 +78,9 @@ def parse_episode_stem(stem: str, pattern: str = DEFAULT_EPISODE_PATTERN) -> Opt title = _clean_title(rest) return { "format": "sxxexx", - "prefix_before_s": prefix_before_s, + "prefix": prefix, + "s_letter": s_letter, + "e_letter": e_letter, "season": season, "season_pad": len(season_s), "episode_pad": len(ep_s), @@ -143,11 +145,14 @@ def rewrite_episode_stem( s_pad = max(parsed["season_pad"], len(str(new_season))) e_pad = max(parsed["episode_pad"], pad, len(str(new_ep))) e1 = str(new_ep).zfill(e_pad) - prefix = f"{parsed['prefix_before_s']}S{new_season:0{s_pad}d}E" + head = ( + f"{parsed['prefix']}{parsed['s_letter']}{new_season:0{s_pad}d}{parsed['e_letter']}" + ) if span <= 1: - return f"{prefix}{e1}{parsed['suffix']}" + return f"{head}{e1}{parsed['suffix']}" e2 = str(new_ep + span - 1).zfill(e_pad) - return f"{prefix}{e1}-E{e2}{parsed['suffix']}" + range_prefix = f"-{parsed['e_letter']}" + return f"{head}{e1}{range_prefix}{e2}{parsed['suffix']}" def rewrite_episode_number( diff --git a/gui/main_window.py b/gui/main_window.py index 79058b6..be70d4b 100644 --- a/gui/main_window.py +++ b/gui/main_window.py @@ -25,7 +25,7 @@ from PyQt6.QtWidgets import ( QCheckBox, QComboBox, ) -from PyQt6.QtCore import Qt, QDir, QItemSelectionModel +from PyQt6.QtCore import Qt, QDir, QItemSelectionModel, QSettings from PyQt6.QtGui import QFont, QColor from engine.pipeline import compute_preview, perform_renames, save_undo_log, load_undo_log, perform_undo @@ -53,7 +53,9 @@ class MainWindow(QMainWindow): self._base_dir = "" self._file_names: list[str] = [] self._preview_by_orig: dict[str, str] = {} # original name -> new name for selection preview + self._split: QSplitter | None = None self._setup_ui() + self._restore_layout() self._refresh_preview() def _setup_ui(self): @@ -172,8 +174,40 @@ class MainWindow(QMainWindow): split.addWidget(right) split.setSizes([320, 680]) + self._split = split layout.addWidget(split, 1) + def _settings(self) -> QSettings: + return QSettings() + + def _restore_layout(self) -> None: + settings = self._settings() + geometry = settings.value("window/geometry") + if geometry is not None: + self.restoreGeometry(geometry) + if self._split is not None: + split_state = settings.value("splitter/state") + if split_state is not None: + self._split.restoreState(split_state) + header = self.preview_table.horizontalHeader() + header_state = settings.value("preview_table/header") + if header_state is not None: + header.restoreState(header_state) + + def _save_layout(self) -> None: + settings = self._settings() + settings.setValue("window/geometry", self.saveGeometry()) + if self._split is not None: + settings.setValue("splitter/state", self._split.saveState()) + settings.setValue( + "preview_table/header", + self.preview_table.horizontalHeader().saveState(), + ) + + def closeEvent(self, event) -> None: + self._save_layout() + super().closeEvent(event) + def _browse(self): path = QFileDialog.getExistingDirectory(self, "Select folder") if path: diff --git a/main.py b/main.py index b51f422..e2e89e5 100644 --- a/main.py +++ b/main.py @@ -21,7 +21,11 @@ def main(): Qt.HighDpiScaleFactorRoundingPolicy.PassThrough ) app = QApplication(sys.argv) + app.setOrganizationName("HSRename") + app.setOrganizationDomain("hisora.dev") app.setApplicationName("HSRename") + version_file = _root / "VERSION" + app.setApplicationVersion(version_file.read_text().strip() if version_file.is_file() else "") win = MainWindow() win.show() sys.exit(app.exec()) diff --git a/packaging/release-stamp-1.0.9.txt b/packaging/release-stamp-1.0.9.txt new file mode 100644 index 0000000..95ddf54 --- /dev/null +++ b/packaging/release-stamp-1.0.9.txt @@ -0,0 +1,3 @@ +HSRename 1.0.9 +- Remember window size, splitter position, and preview column widths between sessions +- Fix double S in SxxExx renames (SS02E33) when show name ends before the episode code