riplex 0.7.4__tar.gz → 0.8.0__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- {riplex-0.7.4/src/riplex.egg-info → riplex-0.8.0}/PKG-INFO +1 -1
- {riplex-0.7.4 → riplex-0.8.0}/docs/changelog.md +10 -0
- {riplex-0.7.4 → riplex-0.8.0/src/riplex.egg-info}/PKG-INFO +1 -1
- {riplex-0.7.4 → riplex-0.8.0}/src/riplex.egg-info/SOURCES.txt +1 -0
- {riplex-0.7.4 → riplex-0.8.0}/src/riplex_app/screens/done.py +1 -1
- {riplex-0.7.4 → riplex-0.8.0}/src/riplex_app/screens/metadata.py +1 -1
- {riplex-0.7.4 → riplex-0.8.0}/src/riplex_app/screens/orchestrate_done.py +5 -5
- {riplex-0.7.4 → riplex-0.8.0}/src/riplex_app/screens/welcome.py +59 -10
- riplex-0.8.0/tests/test_welcome_screen.py +42 -0
- {riplex-0.7.4 → riplex-0.8.0}/.github/ISSUE_TEMPLATE/bug_report.yml +0 -0
- {riplex-0.7.4 → riplex-0.8.0}/.github/ISSUE_TEMPLATE/crash_report.yml +0 -0
- {riplex-0.7.4 → riplex-0.8.0}/.github/agents/riplex.agent.md +0 -0
- {riplex-0.7.4 → riplex-0.8.0}/.github/copilot-instructions.md +0 -0
- {riplex-0.7.4 → riplex-0.8.0}/.github/workflows/publish.yml +0 -0
- {riplex-0.7.4 → riplex-0.8.0}/.github/workflows/release.yml +0 -0
- {riplex-0.7.4 → riplex-0.8.0}/.gitignore +0 -0
- {riplex-0.7.4 → riplex-0.8.0}/.vscode/settings.json +0 -0
- {riplex-0.7.4 → riplex-0.8.0}/CONTRIBUTORS.md +0 -0
- {riplex-0.7.4 → riplex-0.8.0}/LICENSE +0 -0
- {riplex-0.7.4 → riplex-0.8.0}/README.md +0 -0
- {riplex-0.7.4 → riplex-0.8.0}/docs/architecture.md +0 -0
- {riplex-0.7.4 → riplex-0.8.0}/docs/cli-guide/lookup.md +0 -0
- {riplex-0.7.4 → riplex-0.8.0}/docs/cli-guide/orchestrate.md +0 -0
- {riplex-0.7.4 → riplex-0.8.0}/docs/cli-guide/organize.md +0 -0
- {riplex-0.7.4 → riplex-0.8.0}/docs/cli-guide/workflow.md +0 -0
- {riplex-0.7.4 → riplex-0.8.0}/docs/getting-started/configuration.md +0 -0
- {riplex-0.7.4 → riplex-0.8.0}/docs/getting-started/installation.md +0 -0
- {riplex-0.7.4 → riplex-0.8.0}/docs/gui-guide/gui-walkthrough.md +0 -0
- {riplex-0.7.4 → riplex-0.8.0}/docs/index.md +0 -0
- {riplex-0.7.4 → riplex-0.8.0}/docs/naming-rules.md +0 -0
- {riplex-0.7.4 → riplex-0.8.0}/docs/reference/cli.md +0 -0
- {riplex-0.7.4 → riplex-0.8.0}/docs/troubleshooting.md +0 -0
- {riplex-0.7.4 → riplex-0.8.0}/issues/debug-artifacts-consolidation.md +0 -0
- {riplex-0.7.4 → riplex-0.8.0}/issues/manual-rip-and-organize-escape-hatch.md +0 -0
- {riplex-0.7.4 → riplex-0.8.0}/issues/orchestrate-dvdcompare-fallback.md +0 -0
- {riplex-0.7.4 → riplex-0.8.0}/issues/planned-features.md +0 -0
- {riplex-0.7.4 → riplex-0.8.0}/mkdocs.yml +0 -0
- {riplex-0.7.4 → riplex-0.8.0}/pyproject.toml +0 -0
- {riplex-0.7.4 → riplex-0.8.0}/screenshots/0_Rip_Flow_BTTF.gif +0 -0
- {riplex-0.7.4 → riplex-0.8.0}/screenshots/1_Welcome_Screen.png +0 -0
- {riplex-0.7.4 → riplex-0.8.0}/screenshots/2_Disc_Detection_BTTF.png +0 -0
- {riplex-0.7.4 → riplex-0.8.0}/screenshots/3_Metadata_Lookup_BTTF.png +0 -0
- {riplex-0.7.4 → riplex-0.8.0}/screenshots/4_Disc_Release_BTTF.png +0 -0
- {riplex-0.7.4 → riplex-0.8.0}/screenshots/5_Multi_Disc_Overview_BTTF.png +0 -0
- {riplex-0.7.4 → riplex-0.8.0}/screenshots/5_Select_Title_to_RIP_BTTF.png +0 -0
- {riplex-0.7.4 → riplex-0.8.0}/setup.cfg +0 -0
- {riplex-0.7.4 → riplex-0.8.0}/src/riplex/__init__.py +0 -0
- {riplex-0.7.4 → riplex-0.8.0}/src/riplex/cache.py +0 -0
- {riplex-0.7.4 → riplex-0.8.0}/src/riplex/config.py +0 -0
- {riplex-0.7.4 → riplex-0.8.0}/src/riplex/dedup.py +0 -0
- {riplex-0.7.4 → riplex-0.8.0}/src/riplex/detect.py +0 -0
- {riplex-0.7.4 → riplex-0.8.0}/src/riplex/disc/__init__.py +0 -0
- {riplex-0.7.4 → riplex-0.8.0}/src/riplex/disc/analysis.py +0 -0
- {riplex-0.7.4 → riplex-0.8.0}/src/riplex/disc/makemkv.py +0 -0
- {riplex-0.7.4 → riplex-0.8.0}/src/riplex/disc/provider.py +0 -0
- {riplex-0.7.4 → riplex-0.8.0}/src/riplex/formatter.py +0 -0
- {riplex-0.7.4 → riplex-0.8.0}/src/riplex/lookup.py +0 -0
- {riplex-0.7.4 → riplex-0.8.0}/src/riplex/manifest.py +0 -0
- {riplex-0.7.4 → riplex-0.8.0}/src/riplex/matcher.py +0 -0
- {riplex-0.7.4 → riplex-0.8.0}/src/riplex/metadata/__init__.py +0 -0
- {riplex-0.7.4 → riplex-0.8.0}/src/riplex/metadata/planner.py +0 -0
- {riplex-0.7.4 → riplex-0.8.0}/src/riplex/metadata/provider.py +0 -0
- {riplex-0.7.4 → riplex-0.8.0}/src/riplex/metadata/sources/__init__.py +0 -0
- {riplex-0.7.4 → riplex-0.8.0}/src/riplex/metadata/sources/tmdb.py +0 -0
- {riplex-0.7.4 → riplex-0.8.0}/src/riplex/models.py +0 -0
- {riplex-0.7.4 → riplex-0.8.0}/src/riplex/normalize.py +0 -0
- {riplex-0.7.4 → riplex-0.8.0}/src/riplex/organizer.py +0 -0
- {riplex-0.7.4 → riplex-0.8.0}/src/riplex/scanner.py +0 -0
- {riplex-0.7.4 → riplex-0.8.0}/src/riplex/snapshot.py +0 -0
- {riplex-0.7.4 → riplex-0.8.0}/src/riplex/splitter.py +0 -0
- {riplex-0.7.4 → riplex-0.8.0}/src/riplex/tagger.py +0 -0
- {riplex-0.7.4 → riplex-0.8.0}/src/riplex/title.py +0 -0
- {riplex-0.7.4 → riplex-0.8.0}/src/riplex/ui.py +0 -0
- {riplex-0.7.4 → riplex-0.8.0}/src/riplex/updater.py +0 -0
- {riplex-0.7.4 → riplex-0.8.0}/src/riplex.egg-info/dependency_links.txt +0 -0
- {riplex-0.7.4 → riplex-0.8.0}/src/riplex.egg-info/entry_points.txt +0 -0
- {riplex-0.7.4 → riplex-0.8.0}/src/riplex.egg-info/requires.txt +0 -0
- {riplex-0.7.4 → riplex-0.8.0}/src/riplex.egg-info/top_level.txt +0 -0
- {riplex-0.7.4 → riplex-0.8.0}/src/riplex_app/__init__.py +0 -0
- {riplex-0.7.4 → riplex-0.8.0}/src/riplex_app/bug_report.py +0 -0
- {riplex-0.7.4 → riplex-0.8.0}/src/riplex_app/crash_dump.py +0 -0
- {riplex-0.7.4 → riplex-0.8.0}/src/riplex_app/keep_awake.py +0 -0
- {riplex-0.7.4 → riplex-0.8.0}/src/riplex_app/main.py +0 -0
- {riplex-0.7.4 → riplex-0.8.0}/src/riplex_app/screens/__init__.py +0 -0
- {riplex-0.7.4 → riplex-0.8.0}/src/riplex_app/screens/disc_detection.py +0 -0
- {riplex-0.7.4 → riplex-0.8.0}/src/riplex_app/screens/disc_overview.py +0 -0
- {riplex-0.7.4 → riplex-0.8.0}/src/riplex_app/screens/disc_swap.py +0 -0
- {riplex-0.7.4 → riplex-0.8.0}/src/riplex_app/screens/folder_picker.py +0 -0
- {riplex-0.7.4 → riplex-0.8.0}/src/riplex_app/screens/organize_done.py +0 -0
- {riplex-0.7.4 → riplex-0.8.0}/src/riplex_app/screens/organize_preview.py +0 -0
- {riplex-0.7.4 → riplex-0.8.0}/src/riplex_app/screens/progress.py +0 -0
- {riplex-0.7.4 → riplex-0.8.0}/src/riplex_app/screens/release.py +0 -0
- {riplex-0.7.4 → riplex-0.8.0}/src/riplex_app/screens/selection.py +0 -0
- {riplex-0.7.4 → riplex-0.8.0}/src/riplex_app/screens/update.py +0 -0
- {riplex-0.7.4 → riplex-0.8.0}/src/riplex_cli/__init__.py +0 -0
- {riplex-0.7.4 → riplex-0.8.0}/src/riplex_cli/commands/__init__.py +0 -0
- {riplex-0.7.4 → riplex-0.8.0}/src/riplex_cli/commands/lookup.py +0 -0
- {riplex-0.7.4 → riplex-0.8.0}/src/riplex_cli/commands/orchestrate.py +0 -0
- {riplex-0.7.4 → riplex-0.8.0}/src/riplex_cli/commands/organize.py +0 -0
- {riplex-0.7.4 → riplex-0.8.0}/src/riplex_cli/commands/rip.py +0 -0
- {riplex-0.7.4 → riplex-0.8.0}/src/riplex_cli/commands/setup.py +0 -0
- {riplex-0.7.4 → riplex-0.8.0}/src/riplex_cli/formatting.py +0 -0
- {riplex-0.7.4 → riplex-0.8.0}/src/riplex_cli/main.py +0 -0
- {riplex-0.7.4 → riplex-0.8.0}/tests/__init__.py +0 -0
- {riplex-0.7.4 → riplex-0.8.0}/tests/fixtures/chernobyl_disc1.json +0 -0
- {riplex-0.7.4 → riplex-0.8.0}/tests/fixtures/makemkvcon_frozen_planet_ii_d2.txt +0 -0
- {riplex-0.7.4 → riplex-0.8.0}/tests/fixtures/makemkvcon_list.txt +0 -0
- {riplex-0.7.4 → riplex-0.8.0}/tests/snapshots/Batman Begins.snapshot.json +0 -0
- {riplex-0.7.4 → riplex-0.8.0}/tests/snapshots/Blade Runner (Blu-ray 4k).snapshot.json +0 -0
- {riplex-0.7.4 → riplex-0.8.0}/tests/snapshots/Blade Runner The Final Cut.snapshot.json +0 -0
- {riplex-0.7.4 → riplex-0.8.0}/tests/snapshots/Seven Worlds One Planet.snapshot.json +0 -0
- {riplex-0.7.4 → riplex-0.8.0}/tests/snapshots/The Dark Knight Rises.snapshot.json +0 -0
- {riplex-0.7.4 → riplex-0.8.0}/tests/snapshots/The Dark Knight.snapshot.json +0 -0
- {riplex-0.7.4 → riplex-0.8.0}/tests/snapshots/Waterworld.snapshot.json +0 -0
- {riplex-0.7.4 → riplex-0.8.0}/tests/test_cache.py +0 -0
- {riplex-0.7.4 → riplex-0.8.0}/tests/test_cli_utils.py +0 -0
- {riplex-0.7.4 → riplex-0.8.0}/tests/test_config.py +0 -0
- {riplex-0.7.4 → riplex-0.8.0}/tests/test_dedup.py +0 -0
- {riplex-0.7.4 → riplex-0.8.0}/tests/test_detect.py +0 -0
- {riplex-0.7.4 → riplex-0.8.0}/tests/test_disc_analysis.py +0 -0
- {riplex-0.7.4 → riplex-0.8.0}/tests/test_disc_detection_screen.py +0 -0
- {riplex-0.7.4 → riplex-0.8.0}/tests/test_disc_fixtures.py +0 -0
- {riplex-0.7.4 → riplex-0.8.0}/tests/test_disc_provider.py +0 -0
- {riplex-0.7.4 → riplex-0.8.0}/tests/test_formatter.py +0 -0
- {riplex-0.7.4 → riplex-0.8.0}/tests/test_lookup.py +0 -0
- {riplex-0.7.4 → riplex-0.8.0}/tests/test_makemkv.py +0 -0
- {riplex-0.7.4 → riplex-0.8.0}/tests/test_matcher.py +0 -0
- {riplex-0.7.4 → riplex-0.8.0}/tests/test_normalize.py +0 -0
- {riplex-0.7.4 → riplex-0.8.0}/tests/test_organizer.py +0 -0
- {riplex-0.7.4 → riplex-0.8.0}/tests/test_planner.py +0 -0
- {riplex-0.7.4 → riplex-0.8.0}/tests/test_release_screen.py +0 -0
- {riplex-0.7.4 → riplex-0.8.0}/tests/test_rip_guide.py +0 -0
- {riplex-0.7.4 → riplex-0.8.0}/tests/test_scanner.py +0 -0
- {riplex-0.7.4 → riplex-0.8.0}/tests/test_snapshot.py +0 -0
- {riplex-0.7.4 → riplex-0.8.0}/tests/test_splitter.py +0 -0
- {riplex-0.7.4 → riplex-0.8.0}/tests/test_tagger.py +0 -0
- {riplex-0.7.4 → riplex-0.8.0}/tests/test_ui.py +0 -0
- {riplex-0.7.4 → riplex-0.8.0}/tests/test_updater.py +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: riplex
|
|
3
|
-
Version: 0.
|
|
3
|
+
Version: 0.8.0
|
|
4
4
|
Summary: Automates the tedious manual work around MakeMKV: figuring out what to rip, which MKV files are actually what, and organizing everything into Plex-compatible folder structures.
|
|
5
5
|
License: MIT
|
|
6
6
|
Requires-Python: >=3.11
|
|
@@ -4,6 +4,16 @@ All notable changes to the riplex documentation are recorded here.
|
|
|
4
4
|
|
|
5
5
|
The format is based on [Keep a Changelog](https://keepachangelog.com/).
|
|
6
6
|
|
|
7
|
+
## v0.8.0 — 2026-06-12
|
|
8
|
+
|
|
9
|
+
### Added
|
|
10
|
+
|
|
11
|
+
- **GUI: editable settings after first-run setup.** The welcome screen now exposes an **Edit Settings** button after configuration is complete, so users can update the TMDb API key, media library root, MakeMKV rip output folder, and optional archive folder without re-running setup from the command line.
|
|
12
|
+
|
|
13
|
+
### Changed
|
|
14
|
+
|
|
15
|
+
- **GUI: less Plex-specific library wording.** User-facing destination copy now refers to a general media library while retaining **Plex-compatible naming** where the current folder/file convention is being described.
|
|
16
|
+
|
|
7
17
|
## v0.7.4 — 2026-06-10
|
|
8
18
|
|
|
9
19
|
### Fixed
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: riplex
|
|
3
|
-
Version: 0.
|
|
3
|
+
Version: 0.8.0
|
|
4
4
|
Summary: Automates the tedious manual work around MakeMKV: figuring out what to rip, which MKV files are actually what, and organizing everything into Plex-compatible folder structures.
|
|
5
5
|
License: MIT
|
|
6
6
|
Requires-Python: >=3.11
|
|
@@ -123,6 +123,7 @@ tests/test_splitter.py
|
|
|
123
123
|
tests/test_tagger.py
|
|
124
124
|
tests/test_ui.py
|
|
125
125
|
tests/test_updater.py
|
|
126
|
+
tests/test_welcome_screen.py
|
|
126
127
|
tests/fixtures/chernobyl_disc1.json
|
|
127
128
|
tests/fixtures/makemkvcon_frozen_planet_ii_d2.txt
|
|
128
129
|
tests/fixtures/makemkvcon_list.txt
|
|
@@ -87,7 +87,7 @@ class DoneScreen:
|
|
|
87
87
|
|
|
88
88
|
no_metadata_hint = ft.Text(
|
|
89
89
|
"Ripped without metadata — use 'Organize Rips' from the home screen "
|
|
90
|
-
"when TMDb is available to move these files into your
|
|
90
|
+
"when TMDb is available to move these files into your media library.",
|
|
91
91
|
size=12,
|
|
92
92
|
color=ft.Colors.ORANGE,
|
|
93
93
|
) if tmdb_match is None and len(successful) > 0 else ft.Container()
|
|
@@ -149,7 +149,7 @@ class MetadataScreen:
|
|
|
149
149
|
[
|
|
150
150
|
ft.Text("Metadata Lookup", size=24, weight=ft.FontWeight.BOLD),
|
|
151
151
|
ft.Text(
|
|
152
|
-
"TMDb is needed for canonical titles, years, and
|
|
152
|
+
"TMDb is needed for canonical titles, years, and media-library folder "
|
|
153
153
|
"structure. Without it, you can still rip the disc and organize later.",
|
|
154
154
|
size=13,
|
|
155
155
|
color=ft.Colors.GREY_500,
|
|
@@ -17,7 +17,7 @@ class OrchestrateDoneScreen:
|
|
|
17
17
|
"""Shown after all discs in the orchestrate queue have been ripped.
|
|
18
18
|
|
|
19
19
|
Displays a summary of all disc rips and offers to organize the
|
|
20
|
-
ripped files into Plex-compatible folder structure.
|
|
20
|
+
ripped files into a Plex-compatible folder structure.
|
|
21
21
|
"""
|
|
22
22
|
|
|
23
23
|
def __init__(self, app):
|
|
@@ -108,7 +108,7 @@ class OrchestrateDoneScreen:
|
|
|
108
108
|
on_click=self._open_folder,
|
|
109
109
|
)
|
|
110
110
|
organize_btn = ft.ElevatedButton(
|
|
111
|
-
"Organize into
|
|
111
|
+
"Organize into Library",
|
|
112
112
|
icon=ft.Icons.DRIVE_FILE_MOVE,
|
|
113
113
|
on_click=self._organize,
|
|
114
114
|
style=ft.ButtonStyle(
|
|
@@ -136,8 +136,8 @@ class OrchestrateDoneScreen:
|
|
|
136
136
|
ft.Column(disc_rows, spacing=6),
|
|
137
137
|
ft.Container(height=10),
|
|
138
138
|
ft.Text(
|
|
139
|
-
"All selected discs have been ripped. Click 'Organize into
|
|
140
|
-
"to match files to metadata and move them into your
|
|
139
|
+
"All selected discs have been ripped. Click 'Organize into Library' "
|
|
140
|
+
"to match files to metadata and move them into your media library.",
|
|
141
141
|
size=13,
|
|
142
142
|
color=ft.Colors.GREY_500,
|
|
143
143
|
),
|
|
@@ -202,7 +202,7 @@ class OrchestrateDoneScreen:
|
|
|
202
202
|
self._organize_status.value = f"Error: {exc}"
|
|
203
203
|
self._organize_status.color = ft.Colors.RED
|
|
204
204
|
e.control.disabled = False
|
|
205
|
-
e.control.text = "Organize into
|
|
205
|
+
e.control.text = "Organize into Library"
|
|
206
206
|
self.app.page.update()
|
|
207
207
|
|
|
208
208
|
threading.Thread(target=_do_organize, daemon=True).start()
|
|
@@ -16,13 +16,30 @@ from riplex.updater import check_for_update, get_current_version
|
|
|
16
16
|
log = logging.getLogger(__name__)
|
|
17
17
|
|
|
18
18
|
|
|
19
|
+
def has_complete_config(config: dict) -> bool:
|
|
20
|
+
"""Return True when required GUI setup values are present."""
|
|
21
|
+
return bool(
|
|
22
|
+
config
|
|
23
|
+
and config.get("tmdb_api_key")
|
|
24
|
+
and config.get("output_root")
|
|
25
|
+
and config.get("rip_output")
|
|
26
|
+
)
|
|
27
|
+
|
|
28
|
+
|
|
29
|
+
def should_show_setup(config: dict, state: dict) -> bool:
|
|
30
|
+
"""Return True when the welcome screen should show setup fields."""
|
|
31
|
+
return not has_complete_config(config) or bool(state.get("_show_setup"))
|
|
32
|
+
|
|
33
|
+
|
|
19
34
|
class WelcomeScreen:
|
|
20
35
|
def __init__(self, app):
|
|
21
36
|
self.app = app
|
|
22
37
|
|
|
23
38
|
def build(self) -> ft.Control:
|
|
24
39
|
config = load_config()
|
|
25
|
-
|
|
40
|
+
has_api_key = bool(config and config.get("tmdb_api_key"))
|
|
41
|
+
has_config = has_complete_config(config)
|
|
42
|
+
show_setup = should_show_setup(config, self.app.state)
|
|
26
43
|
has_makemkv = find_makemkvcon() is not None
|
|
27
44
|
has_ffprobe = find_ffprobe() is not None
|
|
28
45
|
from riplex.splitter import find_mkvmerge
|
|
@@ -31,7 +48,7 @@ class WelcomeScreen:
|
|
|
31
48
|
# Status indicators
|
|
32
49
|
checks = [
|
|
33
50
|
("Config file", has_config),
|
|
34
|
-
("TMDb API key",
|
|
51
|
+
("TMDb API key", has_api_key),
|
|
35
52
|
("makemkvcon", has_makemkv),
|
|
36
53
|
("ffprobe", has_ffprobe),
|
|
37
54
|
("mkvmerge", has_mkvmerge),
|
|
@@ -102,7 +119,7 @@ class WelcomeScreen:
|
|
|
102
119
|
can_rip = all(ok for _, ok in checks)
|
|
103
120
|
can_organize = has_config and has_ffprobe
|
|
104
121
|
|
|
105
|
-
# Setup fields (shown if config missing)
|
|
122
|
+
# Setup fields (shown if config missing or user chooses to edit)
|
|
106
123
|
self.api_key_field = ft.TextField(
|
|
107
124
|
label="TMDb API key",
|
|
108
125
|
value=config.get("tmdb_api_key", ""),
|
|
@@ -111,7 +128,7 @@ class WelcomeScreen:
|
|
|
111
128
|
expand=True,
|
|
112
129
|
)
|
|
113
130
|
self.output_root_field = ft.TextField(
|
|
114
|
-
label="
|
|
131
|
+
label="Media library root",
|
|
115
132
|
value=config.get("output_root", ""),
|
|
116
133
|
expand=True,
|
|
117
134
|
)
|
|
@@ -155,8 +172,9 @@ class WelcomeScreen:
|
|
|
155
172
|
ft.Container(height=8),
|
|
156
173
|
_make_browse_row(self.output_root_field),
|
|
157
174
|
ft.Text(
|
|
158
|
-
"Your
|
|
159
|
-
"into Movies/ and TV Shows/ subfolders here
|
|
175
|
+
"Your media library root. Organized files will be placed "
|
|
176
|
+
"into Movies/ and TV Shows/ subfolders here using "
|
|
177
|
+
"Plex-compatible naming.",
|
|
160
178
|
size=11,
|
|
161
179
|
color=ft.Colors.GREY_600,
|
|
162
180
|
),
|
|
@@ -177,10 +195,20 @@ class WelcomeScreen:
|
|
|
177
195
|
color=ft.Colors.GREY_600,
|
|
178
196
|
),
|
|
179
197
|
ft.Container(height=8),
|
|
180
|
-
ft.
|
|
198
|
+
ft.Row(
|
|
199
|
+
[
|
|
200
|
+
ft.ElevatedButton("Save Config", on_click=self._save_config),
|
|
201
|
+
ft.TextButton(
|
|
202
|
+
"Cancel",
|
|
203
|
+
on_click=self._hide_setup,
|
|
204
|
+
visible=has_config,
|
|
205
|
+
),
|
|
206
|
+
],
|
|
207
|
+
spacing=8,
|
|
208
|
+
),
|
|
181
209
|
],
|
|
182
210
|
spacing=4,
|
|
183
|
-
visible=
|
|
211
|
+
visible=show_setup,
|
|
184
212
|
)
|
|
185
213
|
|
|
186
214
|
# Workflow buttons
|
|
@@ -190,7 +218,7 @@ class WelcomeScreen:
|
|
|
190
218
|
on_click=self._start_rip,
|
|
191
219
|
disabled=not can_rip,
|
|
192
220
|
style=ft.ButtonStyle(padding=ft.Padding(left=30, top=15, right=30, bottom=15)),
|
|
193
|
-
tooltip="Detect a disc, look up metadata, rip selected titles, and organize into
|
|
221
|
+
tooltip="Detect a disc, look up metadata, rip selected titles, and organize into your media library.",
|
|
194
222
|
)
|
|
195
223
|
organize_button = ft.ElevatedButton(
|
|
196
224
|
"Organize Rips",
|
|
@@ -228,7 +256,7 @@ class WelcomeScreen:
|
|
|
228
256
|
),
|
|
229
257
|
self.update_banner,
|
|
230
258
|
ft.Text(
|
|
231
|
-
"Rip physical discs and organize into Plex-compatible
|
|
259
|
+
"Rip physical discs and organize them into a media library with Plex-compatible naming.",
|
|
232
260
|
size=14,
|
|
233
261
|
color=ft.Colors.GREY_400,
|
|
234
262
|
),
|
|
@@ -244,6 +272,16 @@ class WelcomeScreen:
|
|
|
244
272
|
ft.Column(status_rows, spacing=4),
|
|
245
273
|
install_section,
|
|
246
274
|
ft.Container(height=10),
|
|
275
|
+
ft.Row(
|
|
276
|
+
[
|
|
277
|
+
ft.OutlinedButton(
|
|
278
|
+
"Edit Settings",
|
|
279
|
+
icon=ft.Icons.SETTINGS,
|
|
280
|
+
on_click=self._show_setup,
|
|
281
|
+
visible=has_config and not show_setup,
|
|
282
|
+
),
|
|
283
|
+
],
|
|
284
|
+
),
|
|
247
285
|
setup_section,
|
|
248
286
|
ft.Container(expand=True),
|
|
249
287
|
ft.Text("What would you like to do?", size=16, weight=ft.FontWeight.BOLD),
|
|
@@ -645,6 +683,17 @@ class WelcomeScreen:
|
|
|
645
683
|
)
|
|
646
684
|
|
|
647
685
|
# Refresh the screen
|
|
686
|
+
self.app.state.pop("_show_setup", None)
|
|
687
|
+
self.app.navigate("welcome")
|
|
688
|
+
|
|
689
|
+
def _show_setup(self, e):
|
|
690
|
+
"""Reveal config fields for editing after first-run setup."""
|
|
691
|
+
self.app.state["_show_setup"] = True
|
|
692
|
+
self.app.navigate("welcome")
|
|
693
|
+
|
|
694
|
+
def _hide_setup(self, e):
|
|
695
|
+
"""Hide config fields without saving changes."""
|
|
696
|
+
self.app.state.pop("_show_setup", None)
|
|
648
697
|
self.app.navigate("welcome")
|
|
649
698
|
|
|
650
699
|
def _start_rip(self, e):
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
from riplex_app.screens.welcome import has_complete_config, should_show_setup
|
|
2
|
+
|
|
3
|
+
|
|
4
|
+
class TestHasCompleteConfig:
|
|
5
|
+
def test_requires_api_key_output_root_and_rip_output(self):
|
|
6
|
+
assert has_complete_config({}) is False
|
|
7
|
+
assert has_complete_config({"tmdb_api_key": "key"}) is False
|
|
8
|
+
assert has_complete_config({"tmdb_api_key": "key", "output_root": "E:/Media"}) is False
|
|
9
|
+
assert has_complete_config({
|
|
10
|
+
"tmdb_api_key": "key",
|
|
11
|
+
"output_root": "E:/Media",
|
|
12
|
+
"rip_output": "E:/Media/_MakeMKV",
|
|
13
|
+
}) is True
|
|
14
|
+
|
|
15
|
+
def test_archive_root_is_optional(self):
|
|
16
|
+
assert has_complete_config({
|
|
17
|
+
"tmdb_api_key": "key",
|
|
18
|
+
"output_root": "E:/Media",
|
|
19
|
+
"rip_output": "E:/Media/_MakeMKV",
|
|
20
|
+
"archive_root": "",
|
|
21
|
+
}) is True
|
|
22
|
+
|
|
23
|
+
|
|
24
|
+
class TestShouldShowSetup:
|
|
25
|
+
def test_shows_setup_for_incomplete_config(self):
|
|
26
|
+
assert should_show_setup({"tmdb_api_key": "key"}, {}) is True
|
|
27
|
+
|
|
28
|
+
def test_hides_setup_for_complete_config(self):
|
|
29
|
+
config = {
|
|
30
|
+
"tmdb_api_key": "key",
|
|
31
|
+
"output_root": "E:/Media",
|
|
32
|
+
"rip_output": "E:/Media/_MakeMKV",
|
|
33
|
+
}
|
|
34
|
+
assert should_show_setup(config, {}) is False
|
|
35
|
+
|
|
36
|
+
def test_can_force_show_setup_for_editing(self):
|
|
37
|
+
config = {
|
|
38
|
+
"tmdb_api_key": "key",
|
|
39
|
+
"output_root": "E:/Media",
|
|
40
|
+
"rip_output": "E:/Media/_MakeMKV",
|
|
41
|
+
}
|
|
42
|
+
assert should_show_setup(config, {"_show_setup": True}) is True
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|