riplex 0.7.1__tar.gz → 0.7.3__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.
Files changed (138) hide show
  1. {riplex-0.7.1 → riplex-0.7.3}/.github/agents/riplex.agent.md +10 -2
  2. riplex-0.7.3/PKG-INFO +96 -0
  3. riplex-0.7.3/README.md +77 -0
  4. {riplex-0.7.1 → riplex-0.7.3}/docs/changelog.md +25 -2
  5. {riplex-0.7.1/docs/guide → riplex-0.7.3/docs/cli-guide}/workflow.md +5 -2
  6. {riplex-0.7.1 → riplex-0.7.3}/docs/getting-started/installation.md +12 -3
  7. riplex-0.7.3/docs/gui-guide/gui-walkthrough.md +90 -0
  8. {riplex-0.7.1 → riplex-0.7.3}/docs/index.md +6 -3
  9. {riplex-0.7.1 → riplex-0.7.3}/mkdocs.yml +7 -5
  10. riplex-0.7.3/screenshots/0_Rip_Flow_BTTF.gif +0 -0
  11. riplex-0.7.3/screenshots/1_Welcome_Screen.png +0 -0
  12. riplex-0.7.3/screenshots/2_Disc_Detection_BTTF.png +0 -0
  13. riplex-0.7.3/screenshots/3_Metadata_Lookup_BTTF.png +0 -0
  14. riplex-0.7.3/screenshots/4_Disc_Release_BTTF.png +0 -0
  15. riplex-0.7.3/screenshots/5_Multi_Disc_Overview_BTTF.png +0 -0
  16. riplex-0.7.3/screenshots/5_Select_Title_to_RIP_BTTF.png +0 -0
  17. {riplex-0.7.1 → riplex-0.7.3}/src/riplex/detect.py +41 -5
  18. {riplex-0.7.1 → riplex-0.7.3}/src/riplex/disc/makemkv.py +59 -2
  19. {riplex-0.7.1 → riplex-0.7.3}/src/riplex/lookup.py +4 -1
  20. {riplex-0.7.1 → riplex-0.7.3}/src/riplex/metadata/planner.py +2 -0
  21. {riplex-0.7.1 → riplex-0.7.3}/src/riplex/models.py +1 -0
  22. {riplex-0.7.1 → riplex-0.7.3}/src/riplex/title.py +40 -2
  23. riplex-0.7.3/src/riplex.egg-info/PKG-INFO +96 -0
  24. {riplex-0.7.1 → riplex-0.7.3}/src/riplex.egg-info/SOURCES.txt +13 -4
  25. {riplex-0.7.1 → riplex-0.7.3}/src/riplex_app/screens/disc_detection.py +37 -3
  26. {riplex-0.7.1 → riplex-0.7.3}/src/riplex_app/screens/folder_picker.py +114 -2
  27. {riplex-0.7.1 → riplex-0.7.3}/src/riplex_app/screens/organize_preview.py +1 -0
  28. {riplex-0.7.1 → riplex-0.7.3}/src/riplex_app/screens/release.py +3 -0
  29. {riplex-0.7.1 → riplex-0.7.3}/src/riplex_cli/commands/orchestrate.py +5 -2
  30. {riplex-0.7.1 → riplex-0.7.3}/src/riplex_cli/commands/organize.py +28 -7
  31. {riplex-0.7.1 → riplex-0.7.3}/src/riplex_cli/commands/rip.py +5 -2
  32. {riplex-0.7.1 → riplex-0.7.3}/src/riplex_cli/main.py +18 -0
  33. {riplex-0.7.1 → riplex-0.7.3}/tests/test_cli_utils.py +35 -1
  34. {riplex-0.7.1 → riplex-0.7.3}/tests/test_detect.py +51 -0
  35. riplex-0.7.3/tests/test_lookup.py +48 -0
  36. {riplex-0.7.1 → riplex-0.7.3}/tests/test_makemkv.py +77 -0
  37. {riplex-0.7.1 → riplex-0.7.3}/tests/test_planner.py +53 -0
  38. riplex-0.7.1/PKG-INFO +0 -128
  39. riplex-0.7.1/README.md +0 -109
  40. riplex-0.7.1/src/riplex.egg-info/PKG-INFO +0 -128
  41. {riplex-0.7.1 → riplex-0.7.3}/.github/ISSUE_TEMPLATE/bug_report.yml +0 -0
  42. {riplex-0.7.1 → riplex-0.7.3}/.github/ISSUE_TEMPLATE/crash_report.yml +0 -0
  43. {riplex-0.7.1 → riplex-0.7.3}/.github/copilot-instructions.md +0 -0
  44. {riplex-0.7.1 → riplex-0.7.3}/.github/workflows/publish.yml +0 -0
  45. {riplex-0.7.1 → riplex-0.7.3}/.github/workflows/release.yml +0 -0
  46. {riplex-0.7.1 → riplex-0.7.3}/.gitignore +0 -0
  47. {riplex-0.7.1 → riplex-0.7.3}/.vscode/settings.json +0 -0
  48. {riplex-0.7.1 → riplex-0.7.3}/CONTRIBUTORS.md +0 -0
  49. {riplex-0.7.1 → riplex-0.7.3}/LICENSE +0 -0
  50. {riplex-0.7.1 → riplex-0.7.3}/docs/architecture.md +0 -0
  51. {riplex-0.7.1/docs/guide → riplex-0.7.3/docs/cli-guide}/lookup.md +0 -0
  52. {riplex-0.7.1/docs/guide → riplex-0.7.3/docs/cli-guide}/orchestrate.md +0 -0
  53. {riplex-0.7.1/docs/guide → riplex-0.7.3/docs/cli-guide}/organize.md +0 -0
  54. {riplex-0.7.1 → riplex-0.7.3}/docs/getting-started/configuration.md +0 -0
  55. {riplex-0.7.1 → riplex-0.7.3}/docs/naming-rules.md +0 -0
  56. {riplex-0.7.1 → riplex-0.7.3}/docs/reference/cli.md +0 -0
  57. {riplex-0.7.1 → riplex-0.7.3}/docs/troubleshooting.md +0 -0
  58. {riplex-0.7.1 → riplex-0.7.3}/issues/debug-artifacts-consolidation.md +0 -0
  59. {riplex-0.7.1 → riplex-0.7.3}/issues/orchestrate-dvdcompare-fallback.md +0 -0
  60. {riplex-0.7.1 → riplex-0.7.3}/issues/planned-features.md +0 -0
  61. {riplex-0.7.1 → riplex-0.7.3}/pyproject.toml +0 -0
  62. {riplex-0.7.1 → riplex-0.7.3}/setup.cfg +0 -0
  63. {riplex-0.7.1 → riplex-0.7.3}/src/riplex/__init__.py +0 -0
  64. {riplex-0.7.1 → riplex-0.7.3}/src/riplex/cache.py +0 -0
  65. {riplex-0.7.1 → riplex-0.7.3}/src/riplex/config.py +0 -0
  66. {riplex-0.7.1 → riplex-0.7.3}/src/riplex/dedup.py +0 -0
  67. {riplex-0.7.1 → riplex-0.7.3}/src/riplex/disc/__init__.py +0 -0
  68. {riplex-0.7.1 → riplex-0.7.3}/src/riplex/disc/analysis.py +0 -0
  69. {riplex-0.7.1 → riplex-0.7.3}/src/riplex/disc/provider.py +0 -0
  70. {riplex-0.7.1 → riplex-0.7.3}/src/riplex/formatter.py +0 -0
  71. {riplex-0.7.1 → riplex-0.7.3}/src/riplex/manifest.py +0 -0
  72. {riplex-0.7.1 → riplex-0.7.3}/src/riplex/matcher.py +0 -0
  73. {riplex-0.7.1 → riplex-0.7.3}/src/riplex/metadata/__init__.py +0 -0
  74. {riplex-0.7.1 → riplex-0.7.3}/src/riplex/metadata/provider.py +0 -0
  75. {riplex-0.7.1 → riplex-0.7.3}/src/riplex/metadata/sources/__init__.py +0 -0
  76. {riplex-0.7.1 → riplex-0.7.3}/src/riplex/metadata/sources/tmdb.py +0 -0
  77. {riplex-0.7.1 → riplex-0.7.3}/src/riplex/normalize.py +0 -0
  78. {riplex-0.7.1 → riplex-0.7.3}/src/riplex/organizer.py +0 -0
  79. {riplex-0.7.1 → riplex-0.7.3}/src/riplex/scanner.py +0 -0
  80. {riplex-0.7.1 → riplex-0.7.3}/src/riplex/snapshot.py +0 -0
  81. {riplex-0.7.1 → riplex-0.7.3}/src/riplex/splitter.py +0 -0
  82. {riplex-0.7.1 → riplex-0.7.3}/src/riplex/tagger.py +0 -0
  83. {riplex-0.7.1 → riplex-0.7.3}/src/riplex/ui.py +0 -0
  84. {riplex-0.7.1 → riplex-0.7.3}/src/riplex/updater.py +0 -0
  85. {riplex-0.7.1 → riplex-0.7.3}/src/riplex.egg-info/dependency_links.txt +0 -0
  86. {riplex-0.7.1 → riplex-0.7.3}/src/riplex.egg-info/entry_points.txt +0 -0
  87. {riplex-0.7.1 → riplex-0.7.3}/src/riplex.egg-info/requires.txt +0 -0
  88. {riplex-0.7.1 → riplex-0.7.3}/src/riplex.egg-info/top_level.txt +0 -0
  89. {riplex-0.7.1 → riplex-0.7.3}/src/riplex_app/__init__.py +0 -0
  90. {riplex-0.7.1 → riplex-0.7.3}/src/riplex_app/bug_report.py +0 -0
  91. {riplex-0.7.1 → riplex-0.7.3}/src/riplex_app/crash_dump.py +0 -0
  92. {riplex-0.7.1 → riplex-0.7.3}/src/riplex_app/keep_awake.py +0 -0
  93. {riplex-0.7.1 → riplex-0.7.3}/src/riplex_app/main.py +0 -0
  94. {riplex-0.7.1 → riplex-0.7.3}/src/riplex_app/screens/__init__.py +0 -0
  95. {riplex-0.7.1 → riplex-0.7.3}/src/riplex_app/screens/disc_overview.py +0 -0
  96. {riplex-0.7.1 → riplex-0.7.3}/src/riplex_app/screens/disc_swap.py +0 -0
  97. {riplex-0.7.1 → riplex-0.7.3}/src/riplex_app/screens/done.py +0 -0
  98. {riplex-0.7.1 → riplex-0.7.3}/src/riplex_app/screens/metadata.py +0 -0
  99. {riplex-0.7.1 → riplex-0.7.3}/src/riplex_app/screens/orchestrate_done.py +0 -0
  100. {riplex-0.7.1 → riplex-0.7.3}/src/riplex_app/screens/organize_done.py +0 -0
  101. {riplex-0.7.1 → riplex-0.7.3}/src/riplex_app/screens/progress.py +0 -0
  102. {riplex-0.7.1 → riplex-0.7.3}/src/riplex_app/screens/selection.py +0 -0
  103. {riplex-0.7.1 → riplex-0.7.3}/src/riplex_app/screens/update.py +0 -0
  104. {riplex-0.7.1 → riplex-0.7.3}/src/riplex_app/screens/welcome.py +0 -0
  105. {riplex-0.7.1 → riplex-0.7.3}/src/riplex_cli/__init__.py +0 -0
  106. {riplex-0.7.1 → riplex-0.7.3}/src/riplex_cli/commands/__init__.py +0 -0
  107. {riplex-0.7.1 → riplex-0.7.3}/src/riplex_cli/commands/lookup.py +0 -0
  108. {riplex-0.7.1 → riplex-0.7.3}/src/riplex_cli/commands/setup.py +0 -0
  109. {riplex-0.7.1 → riplex-0.7.3}/src/riplex_cli/formatting.py +0 -0
  110. {riplex-0.7.1 → riplex-0.7.3}/tests/__init__.py +0 -0
  111. {riplex-0.7.1 → riplex-0.7.3}/tests/fixtures/chernobyl_disc1.json +0 -0
  112. {riplex-0.7.1 → riplex-0.7.3}/tests/fixtures/makemkvcon_frozen_planet_ii_d2.txt +0 -0
  113. {riplex-0.7.1 → riplex-0.7.3}/tests/fixtures/makemkvcon_list.txt +0 -0
  114. {riplex-0.7.1 → riplex-0.7.3}/tests/snapshots/Batman Begins.snapshot.json +0 -0
  115. {riplex-0.7.1 → riplex-0.7.3}/tests/snapshots/Blade Runner (Blu-ray 4k).snapshot.json +0 -0
  116. {riplex-0.7.1 → riplex-0.7.3}/tests/snapshots/Blade Runner The Final Cut.snapshot.json +0 -0
  117. {riplex-0.7.1 → riplex-0.7.3}/tests/snapshots/Seven Worlds One Planet.snapshot.json +0 -0
  118. {riplex-0.7.1 → riplex-0.7.3}/tests/snapshots/The Dark Knight Rises.snapshot.json +0 -0
  119. {riplex-0.7.1 → riplex-0.7.3}/tests/snapshots/The Dark Knight.snapshot.json +0 -0
  120. {riplex-0.7.1 → riplex-0.7.3}/tests/snapshots/Waterworld.snapshot.json +0 -0
  121. {riplex-0.7.1 → riplex-0.7.3}/tests/test_cache.py +0 -0
  122. {riplex-0.7.1 → riplex-0.7.3}/tests/test_config.py +0 -0
  123. {riplex-0.7.1 → riplex-0.7.3}/tests/test_dedup.py +0 -0
  124. {riplex-0.7.1 → riplex-0.7.3}/tests/test_disc_analysis.py +0 -0
  125. {riplex-0.7.1 → riplex-0.7.3}/tests/test_disc_detection_screen.py +0 -0
  126. {riplex-0.7.1 → riplex-0.7.3}/tests/test_disc_fixtures.py +0 -0
  127. {riplex-0.7.1 → riplex-0.7.3}/tests/test_disc_provider.py +0 -0
  128. {riplex-0.7.1 → riplex-0.7.3}/tests/test_formatter.py +0 -0
  129. {riplex-0.7.1 → riplex-0.7.3}/tests/test_matcher.py +0 -0
  130. {riplex-0.7.1 → riplex-0.7.3}/tests/test_normalize.py +0 -0
  131. {riplex-0.7.1 → riplex-0.7.3}/tests/test_organizer.py +0 -0
  132. {riplex-0.7.1 → riplex-0.7.3}/tests/test_rip_guide.py +0 -0
  133. {riplex-0.7.1 → riplex-0.7.3}/tests/test_scanner.py +0 -0
  134. {riplex-0.7.1 → riplex-0.7.3}/tests/test_snapshot.py +0 -0
  135. {riplex-0.7.1 → riplex-0.7.3}/tests/test_splitter.py +0 -0
  136. {riplex-0.7.1 → riplex-0.7.3}/tests/test_tagger.py +0 -0
  137. {riplex-0.7.1 → riplex-0.7.3}/tests/test_ui.py +0 -0
  138. {riplex-0.7.1 → riplex-0.7.3}/tests/test_updater.py +0 -0
@@ -65,7 +65,8 @@ docs/
65
65
  naming-rules.md # Plex naming conventions
66
66
  changelog.md # Documentation changelog (Keep a Changelog format)
67
67
  getting-started/ # Installation, configuration
68
- guide/ # Per-command workflow guides
68
+ gui-guide/ # Desktop app walkthroughs
69
+ cli-guide/ # Command-by-command workflow guides
69
70
  reference/ # CLI reference
70
71
  ```
71
72
 
@@ -162,9 +163,16 @@ Docs live in `docs/` and are referenced from README.md.
162
163
  - `docs/naming-rules.md`: Plex naming conventions and folder layout rules
163
164
  - `docs/changelog.md`: Documentation changelog (update when docs change)
164
165
  - `docs/getting-started/`: Installation and configuration guides
165
- - `docs/guide/`: Per-command workflow walkthroughs
166
+ - `docs/gui-guide/`: Desktop app walkthroughs
167
+ - `docs/cli-guide/`: Command-by-command workflow walkthroughs
166
168
  - `docs/reference/cli.md`: Complete CLI option reference
167
169
 
170
+ *** Delete File: c:\Users\asher\Projects\anycredit5518\riplex\docs\guide\gui-walkthrough.md
171
+ *** Delete File: c:\Users\asher\Projects\anycredit5518\riplex\docs\guide\workflow.md
172
+ *** Delete File: c:\Users\asher\Projects\anycredit5518\riplex\docs\guide\orchestrate.md
173
+ *** Delete File: c:\Users\asher\Projects\anycredit5518\riplex\docs\guide\lookup.md
174
+ *** Delete File: c:\Users\asher\Projects\anycredit5518\riplex\docs\guide\organize.md
175
+
168
176
  ### Documentation rules
169
177
 
170
178
  - When making significant changes (new features, renamed modules, changed behavior), update the relevant docs
riplex-0.7.3/PKG-INFO ADDED
@@ -0,0 +1,96 @@
1
+ Metadata-Version: 2.4
2
+ Name: riplex
3
+ Version: 0.7.3
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
+ License: MIT
6
+ Requires-Python: >=3.11
7
+ Description-Content-Type: text/markdown
8
+ License-File: LICENSE
9
+ Requires-Dist: httpx>=0.27
10
+ Requires-Dist: dvdcompare-scraper>=0.1.15
11
+ Requires-Dist: platformdirs>=4.0
12
+ Provides-Extra: dev
13
+ Requires-Dist: pytest>=8.0; extra == "dev"
14
+ Requires-Dist: pytest-asyncio>=0.23; extra == "dev"
15
+ Requires-Dist: respx>=0.21; extra == "dev"
16
+ Provides-Extra: gui
17
+ Requires-Dist: flet<0.86,>=0.84; extra == "gui"
18
+ Dynamic: license-file
19
+
20
+ # riplex
21
+
22
+ Automatically organizes MKV files from physical disc collections into Plex-compatible folder structures with the right names, the right folders, and no manual work.
23
+
24
+ riplex includes both a desktop app for guided ripping and a full CLI for terminal-first and automated workflows.
25
+
26
+ <p align="center">
27
+ <img src="screenshots/0_Rip_Flow_BTTF.gif" alt="Rip flow demo" width="800">
28
+ </p>
29
+
30
+ ## Why?
31
+
32
+ After using MakeMKV to back up a disc, you're left with a pile of generically-named files (`title_t00.mkv`, `title_t01.mkv`, ...) and no idea which is the main film, which are featurettes, which are duplicates, and which is the play-all compilation you didn't need. For a multi-disc TV series, you're looking at hours of manual effort: reading disc cases, Googling runtimes, renaming files one by one, and building the exact folder hierarchy Plex demands.
33
+
34
+ riplex solves this by pulling metadata from TMDb (canonical titles, years, episode info) and [dvdcompare.net](https://www.dvdcompare.net) (per-disc content breakdowns including featurettes, deleted scenes, runtimes), then automatically classifying, deduplicating, matching, renaming, and organizing everything into the correct Plex structure.
35
+
36
+ ## Get started
37
+
38
+ Start with the [Getting Started guide](docs/getting-started/installation.md). It covers all three install paths:
39
+
40
+ - **Pre-built app**: fastest way to try riplex. Download links and platform-specific notes are in the [installation guide](docs/getting-started/installation.md#option-a-pre-built-executables).
41
+ - **pipx**: recommended if you have Python or do not mind installing it. See [Option B](docs/getting-started/installation.md#option-b-install-with-pipx-recommended).
42
+ - **From source**: for developers and unsupported binary platforms. See [Option C](docs/getting-started/installation.md#option-c-install-from-source).
43
+
44
+ If you just want the desktop app right now, the latest binaries are on the [Releases page](https://github.com/AnyCredit5518/riplex/releases/latest). For the guided desktop flow after install, see the [GUI Walkthrough](docs/gui-guide/gui-walkthrough.md).
45
+
46
+ If you prefer the command line, riplex also ships a full CLI with `lookup`, `rip`, `organize`, and `orchestrate` workflows. For the end-to-end terminal flow, see the [CLI Workflow guide](docs/cli-guide/workflow.md).
47
+
48
+ After installing:
49
+
50
+ 1. Run setup. The GUI walks you through it on first launch, or you can use [`riplex setup`](docs/getting-started/installation.md#setup).
51
+ 2. If you want to see the GUI step by step, read the [GUI Walkthrough](docs/gui-guide/gui-walkthrough.md).
52
+ 3. Follow the [CLI Workflow guide](docs/cli-guide/workflow.md) for the end-to-end flow.
53
+ 4. If you prefer the terminal, use the [CLI reference](docs/reference/cli.md) for command details.
54
+
55
+ ## What it looks like
56
+
57
+ Instead of leaving you to sort through a wall of raw MakeMKV titles, riplex helps you understand what is actually on the disc and choose the titles worth ripping. It surfaces likely matches, highlights junk and duplicates, and helps you avoid play-all traps.
58
+
59
+ ![Title selection](screenshots/5_Select_Title_to_RIP_BTTF.png)
60
+
61
+ More screenshots:
62
+ [welcome](screenshots/1_Welcome_Screen.png),
63
+ [disc detection](screenshots/2_Disc_Detection_BTTF.png),
64
+ [metadata lookup](screenshots/3_Metadata_Lookup_BTTF.png),
65
+ [release picker](screenshots/4_Disc_Release_BTTF.png),
66
+ [disc overview](screenshots/5_Multi_Disc_Overview_BTTF.png).
67
+
68
+ > [!NOTE]
69
+ > riplex currently handles one film (or one TV show) per session. Multi-film box sets that bundle separate films onto separate discs (e.g. a trilogy in one box) need to be ripped one film at a time.
70
+
71
+ ## Requirements
72
+
73
+ riplex uses MakeMKV, ffmpeg, and MKVToolNix under the hood. The setup wizard installs them for you on Windows (winget), macOS (Homebrew), and Debian/Ubuntu Linux (apt). On other platforms see [the installation guide](docs/getting-started/installation.md).
74
+
75
+ You'll also need a free [TMDb API key](https://www.themoviedb.org/settings/api). The wizard prompts you for it.
76
+
77
+ ## Data sources
78
+
79
+ - **[TMDb](https://www.themoviedb.org/)**: canonical movie and TV metadata (titles, years, episodes, runtimes)
80
+ - **[dvdcompare.net](https://www.dvdcompare.net)**: per-disc content breakdowns (featurettes, deleted scenes, play-all groupings, runtimes). An invaluable community resource.
81
+
82
+ ## Related projects
83
+
84
+ - **[dvdcompare-scraper](https://github.com/AnyCredit5518/dvdcompare-scraper)**: Python client for dvdcompare.net. Powers riplex's disc lookup. Contributions welcome.
85
+
86
+ ## Documentation
87
+
88
+ - [Getting started](docs/getting-started/installation.md): installation, configuration
89
+ - [GUI walkthrough](docs/gui-guide/gui-walkthrough.md): the main desktop flow, screen by screen
90
+ - [CLI workflow](docs/cli-guide/workflow.md): end-to-end terminal workflows
91
+ - [CLI reference](docs/reference/cli.md): every command and flag
92
+ - [Architecture](docs/architecture.md): design, data flow, project structure
93
+
94
+ ## License
95
+
96
+ MIT
riplex-0.7.3/README.md ADDED
@@ -0,0 +1,77 @@
1
+ # riplex
2
+
3
+ Automatically organizes MKV files from physical disc collections into Plex-compatible folder structures with the right names, the right folders, and no manual work.
4
+
5
+ riplex includes both a desktop app for guided ripping and a full CLI for terminal-first and automated workflows.
6
+
7
+ <p align="center">
8
+ <img src="screenshots/0_Rip_Flow_BTTF.gif" alt="Rip flow demo" width="800">
9
+ </p>
10
+
11
+ ## Why?
12
+
13
+ After using MakeMKV to back up a disc, you're left with a pile of generically-named files (`title_t00.mkv`, `title_t01.mkv`, ...) and no idea which is the main film, which are featurettes, which are duplicates, and which is the play-all compilation you didn't need. For a multi-disc TV series, you're looking at hours of manual effort: reading disc cases, Googling runtimes, renaming files one by one, and building the exact folder hierarchy Plex demands.
14
+
15
+ riplex solves this by pulling metadata from TMDb (canonical titles, years, episode info) and [dvdcompare.net](https://www.dvdcompare.net) (per-disc content breakdowns including featurettes, deleted scenes, runtimes), then automatically classifying, deduplicating, matching, renaming, and organizing everything into the correct Plex structure.
16
+
17
+ ## Get started
18
+
19
+ Start with the [Getting Started guide](docs/getting-started/installation.md). It covers all three install paths:
20
+
21
+ - **Pre-built app**: fastest way to try riplex. Download links and platform-specific notes are in the [installation guide](docs/getting-started/installation.md#option-a-pre-built-executables).
22
+ - **pipx**: recommended if you have Python or do not mind installing it. See [Option B](docs/getting-started/installation.md#option-b-install-with-pipx-recommended).
23
+ - **From source**: for developers and unsupported binary platforms. See [Option C](docs/getting-started/installation.md#option-c-install-from-source).
24
+
25
+ If you just want the desktop app right now, the latest binaries are on the [Releases page](https://github.com/AnyCredit5518/riplex/releases/latest). For the guided desktop flow after install, see the [GUI Walkthrough](docs/gui-guide/gui-walkthrough.md).
26
+
27
+ If you prefer the command line, riplex also ships a full CLI with `lookup`, `rip`, `organize`, and `orchestrate` workflows. For the end-to-end terminal flow, see the [CLI Workflow guide](docs/cli-guide/workflow.md).
28
+
29
+ After installing:
30
+
31
+ 1. Run setup. The GUI walks you through it on first launch, or you can use [`riplex setup`](docs/getting-started/installation.md#setup).
32
+ 2. If you want to see the GUI step by step, read the [GUI Walkthrough](docs/gui-guide/gui-walkthrough.md).
33
+ 3. Follow the [CLI Workflow guide](docs/cli-guide/workflow.md) for the end-to-end flow.
34
+ 4. If you prefer the terminal, use the [CLI reference](docs/reference/cli.md) for command details.
35
+
36
+ ## What it looks like
37
+
38
+ Instead of leaving you to sort through a wall of raw MakeMKV titles, riplex helps you understand what is actually on the disc and choose the titles worth ripping. It surfaces likely matches, highlights junk and duplicates, and helps you avoid play-all traps.
39
+
40
+ ![Title selection](screenshots/5_Select_Title_to_RIP_BTTF.png)
41
+
42
+ More screenshots:
43
+ [welcome](screenshots/1_Welcome_Screen.png),
44
+ [disc detection](screenshots/2_Disc_Detection_BTTF.png),
45
+ [metadata lookup](screenshots/3_Metadata_Lookup_BTTF.png),
46
+ [release picker](screenshots/4_Disc_Release_BTTF.png),
47
+ [disc overview](screenshots/5_Multi_Disc_Overview_BTTF.png).
48
+
49
+ > [!NOTE]
50
+ > riplex currently handles one film (or one TV show) per session. Multi-film box sets that bundle separate films onto separate discs (e.g. a trilogy in one box) need to be ripped one film at a time.
51
+
52
+ ## Requirements
53
+
54
+ riplex uses MakeMKV, ffmpeg, and MKVToolNix under the hood. The setup wizard installs them for you on Windows (winget), macOS (Homebrew), and Debian/Ubuntu Linux (apt). On other platforms see [the installation guide](docs/getting-started/installation.md).
55
+
56
+ You'll also need a free [TMDb API key](https://www.themoviedb.org/settings/api). The wizard prompts you for it.
57
+
58
+ ## Data sources
59
+
60
+ - **[TMDb](https://www.themoviedb.org/)**: canonical movie and TV metadata (titles, years, episodes, runtimes)
61
+ - **[dvdcompare.net](https://www.dvdcompare.net)**: per-disc content breakdowns (featurettes, deleted scenes, play-all groupings, runtimes). An invaluable community resource.
62
+
63
+ ## Related projects
64
+
65
+ - **[dvdcompare-scraper](https://github.com/AnyCredit5518/dvdcompare-scraper)**: Python client for dvdcompare.net. Powers riplex's disc lookup. Contributions welcome.
66
+
67
+ ## Documentation
68
+
69
+ - [Getting started](docs/getting-started/installation.md): installation, configuration
70
+ - [GUI walkthrough](docs/gui-guide/gui-walkthrough.md): the main desktop flow, screen by screen
71
+ - [CLI workflow](docs/cli-guide/workflow.md): end-to-end terminal workflows
72
+ - [CLI reference](docs/reference/cli.md): every command and flag
73
+ - [Architecture](docs/architecture.md): design, data flow, project structure
74
+
75
+ ## License
76
+
77
+ MIT
@@ -4,6 +4,29 @@ 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.7.3 — 2026-06-10
8
+
9
+ ### Fixed
10
+
11
+ - **GUI: silent "No optical drives detected" when MakeMKV is expired or unregistered.** When `makemkvcon` rejects requests with a fatal MSG (codes `5021` too-old, `5022` key-expired, `5023` key-invalid) it exits cleanly with zero `DRV:` lines, so riplex previously rendered an empty drive list. The shared library now parses these fatal MSGs and raises `MakeMKVError`; the Disc Detection screen surfaces the verbatim `makemkvcon` message along with **Download MakeMKV ↗** and **Get beta key ↗** buttons so users can resolve the lockout in one click.
12
+
13
+ ## v0.7.2 — 2026-05-17
14
+
15
+ ### Fixed
16
+
17
+ - **Auto-detected disc labels with compact season/disc suffixes.** Volume labels such as `Hannibal St01bd1` and `HANNIBAL_S1_BD1` now strip the trailing season/disc marker before TMDb and dvdcompare lookup, so both the GUI and CLI start from the correct base title instead of searching for the raw disc label.
18
+
19
+ ## 2026-05-16
20
+
21
+ ### Added
22
+
23
+ - New GUI walkthrough guide with screenshots for the main desktop flow: welcome, disc detection, metadata lookup, release picker, title selection, and multi-disc overview.
24
+
25
+ ### Changed
26
+
27
+ - Split the user guides into `docs/gui-guide/` and `docs/cli-guide/` so the desktop flow and terminal flow are documented separately.
28
+ - Linked the new GUI walkthrough from the README, installation guide, CLI workflow guide, and docs index so beginners can discover the desktop flow more easily.
29
+
7
30
  ## v0.7.1 — 2026-05-16
8
31
 
9
32
  ### Fixed
@@ -141,7 +164,7 @@ Summary: organize-time match quality fixes, faster post-rip organize, and a rele
141
164
 
142
165
  ### Added
143
166
 
144
- - Orchestrate guide (`docs/guide/orchestrate.md`): full documentation for the new primary workflow command
167
+ - Orchestrate guide (`docs/cli-guide/orchestrate.md`): full documentation for the new primary workflow command
145
168
  - `orchestrate` subcommand in CLI Reference with complete options table
146
169
  - `rip` subcommand added to README (features block, usage examples, CLI reference table)
147
170
  - `orchestrate` subcommand added to README (features block, usage examples, CLI reference table)
@@ -159,7 +182,7 @@ Summary: organize-time match quality fixes, faster post-rip organize, and a rele
159
182
  - Rip-guide output examples updated to use configurable rip output path instead of hardcoded `_MakeMKV`
160
183
  - Architecture section updated from 4 modes to 6 modes (added orchestrate, rip)
161
184
  - Project structure listings updated to include all current source and test files
162
- - `docs/guide/workflow.md` updated to recommend orchestrate as the primary workflow
185
+ - `docs/cli-guide/workflow.md` updated to recommend orchestrate as the primary workflow
163
186
  - `docs/architecture.md` updated with orchestrate and rip modes and data flows
164
187
  - `PLANNED_FEATURES.md` orchestrate section moved to "Recently Implemented"
165
188
  - CLI reference tables for organize (added `--snapshot`, `--auto`) and rip-guide (added `--drive`) updated
@@ -1,6 +1,9 @@
1
- # Typical Workflow
1
+ # CLI Workflow
2
2
 
3
- This page walks through the recommended end-to-end workflow for ripping a disc set and organizing it into Plex.
3
+ This page walks through the recommended end-to-end command-line workflow for ripping a disc set and organizing it into Plex.
4
+
5
+ If you want to see the desktop app screen by screen first, start with the
6
+ [GUI Walkthrough](../gui-guide/gui-walkthrough.md).
4
7
 
5
8
  ## Recommended: Use `orchestrate`
6
9
 
@@ -4,9 +4,12 @@
4
4
 
5
5
  There are three ways to install riplex:
6
6
 
7
- - **[Pre-built executables](#option-a-pre-built-executables)** - easiest, no Python needed
8
- - **[pipx](#option-b-install-with-pipx-recommended)** - recommended for Python users
9
- - **[From source](#option-c-install-from-source)** - for developers
7
+ - **[Pre-built executables](#option-a-pre-built-executables)** fastest
8
+ way to try riplex. No Python required, but upgrades mean re-downloading.
9
+ - **[pipx](#option-b-install-with-pipx-recommended)** recommended.
10
+ Requires Python, but `pipx upgrade riplex` makes staying current effortless.
11
+ - **[From source](#option-c-install-from-source)** — for developers and
12
+ platforms without a pre-built binary (Intel Mac, Linux).
10
13
 
11
14
  ### Option A: Pre-built executables
12
15
 
@@ -225,6 +228,12 @@ riplex setup
225
228
  Or just launch the GUI -- it checks for missing tools on startup and walks you
226
229
  through setup automatically.
227
230
 
231
+ If you want to preview the desktop flow before ripping a disc, see the
232
+ [GUI Walkthrough](../gui-guide/gui-walkthrough.md).
233
+
234
+ If you prefer the terminal workflow after setup, see the
235
+ [CLI Workflow guide](../cli-guide/workflow.md).
236
+
228
237
  The setup wizard will:
229
238
 
230
239
  1. Ask for your TMDb API key (free at https://www.themoviedb.org/settings/api)
@@ -0,0 +1,90 @@
1
+ # GUI Walkthrough
2
+
3
+ This page walks through the main riplex GUI flow using the screenshots in this repo. It is not a screen-by-screen reference manual. The goal is to show what each step is for, what decision you make there, and what happens next.
4
+
5
+ ## 1. Welcome
6
+
7
+ ![Welcome screen](../../screenshots/1_Welcome_Screen.png)
8
+
9
+ The Welcome screen checks your setup before you start. If riplex is missing a required tool or configuration value, this is where it tells you.
10
+
11
+ What you do here:
12
+ - confirm that your TMDb key and output paths are configured
13
+ - let riplex install or point to missing tools if needed
14
+ - continue once the environment is ready
15
+
16
+ ## 2. Disc detection
17
+
18
+ ![Disc detection](../../screenshots/2_Disc_Detection_BTTF.png)
19
+
20
+ Once a disc is in the drive, riplex detects it and reads the volume label.
21
+
22
+ What you do here:
23
+ - verify that the detected disc is the one you intended to rip
24
+ - if multiple drives are present, choose the correct drive
25
+ - continue once the disc has been read successfully
26
+
27
+ Troubleshooting:
28
+ - if no drive appears, verify that MakeMKV can see the drive and that `makemkvcon` is installed correctly
29
+ - if the detected title is wrong, you can correct it on the next step
30
+
31
+ ## 3. Metadata lookup
32
+
33
+ ![Metadata lookup](../../screenshots/3_Metadata_Lookup_BTTF.png)
34
+
35
+ riplex uses the disc label as a starting point, then looks up the title on TMDb.
36
+
37
+ What you do here:
38
+ - confirm the detected title if it is already correct
39
+ - edit the search text if the disc label is abbreviated or noisy
40
+ - choose the correct TMDb match if there is more than one possible result
41
+
42
+ ## 4. Release picker
43
+
44
+ ![Release picker](../../screenshots/4_Disc_Release_BTTF.png)
45
+
46
+ After the TMDb title is confirmed, riplex looks up the corresponding physical-media release on dvdcompare.net.
47
+
48
+ What you do here:
49
+ - pick the release that matches the disc in your drive
50
+ - pay attention to format and region when several similar releases exist
51
+ - use the dvdcompare link to verify the page if needed
52
+
53
+ Troubleshooting:
54
+ - if riplex picks the wrong dvdcompare page, use the manual override on this screen to paste a dvdcompare film id or URL
55
+
56
+ ## 5. Title selection
57
+
58
+ ![Title selection](../../screenshots/5_Select_Title_to_RIP_BTTF.png)
59
+
60
+ This is the most important decision point in the GUI. riplex analyzes the disc, classifies the titles, and shows you what is likely worth ripping.
61
+
62
+ What you do here:
63
+ - review the recommended titles before starting the rip
64
+ - keep the main feature, episodes, or useful extras selected
65
+ - deselect obvious junk, duplicates, or play-all titles if needed
66
+
67
+ Why this screen matters:
68
+ - MakeMKV exposes raw titles and durations, but not what those titles actually are
69
+ - riplex uses metadata, disc context, and runtime matching to turn that pile of titles into something understandable
70
+
71
+ ## 6. Disc overview for multi-disc releases
72
+
73
+ ![Disc overview](../../screenshots/5_Multi_Disc_Overview_BTTF.png)
74
+
75
+ When a single film release spans multiple discs, riplex keeps them together as one project and shows you where the current disc fits into the full release.
76
+
77
+ What you do here:
78
+ - confirm that you are ripping the expected disc in the set
79
+ - move through the discs in order as riplex prompts you
80
+ - let riplex merge the results into one organized output when the project is complete
81
+
82
+ Important note:
83
+ - riplex currently handles one film or one TV show per session
84
+ - multi-film box sets still need to be ripped one film at a time
85
+
86
+ ## What comes next
87
+
88
+ After title selection, riplex starts the rip, shows progress, and then summarizes the results when it finishes.
89
+
90
+ If you want the full end-to-end terminal flow after setup, see the [CLI Workflow](../cli-guide/workflow.md).
@@ -10,10 +10,10 @@ riplex has four commands, each targeting a different stage of the disc ripping w
10
10
 
11
11
  | Command | Stage | What it does |
12
12
  |---|---|---|
13
- | [`orchestrate`](guide/orchestrate.md) | Full pipeline | Multi-disc rip-then-organize in one session |
13
+ | [`orchestrate`](cli-guide/orchestrate.md) | Full pipeline | Multi-disc rip-then-organize in one session |
14
14
  | [`rip`](reference/cli.md#rip) | Ripping | Single-disc rip via makemkvcon with auto title selection |
15
- | [`organize`](guide/organize.md) | After ripping | Scans MKV files, deduplicates, matches by runtime, moves into Plex layout |
16
- | [`lookup`](guide/lookup.md) | Before ripping | Shows disc contents from dvdcompare, recommends which titles to rip, creates folder structure |
15
+ | [`organize`](cli-guide/organize.md) | After ripping | Scans MKV files, deduplicates, matches by runtime, moves into Plex layout |
16
+ | [`lookup`](cli-guide/lookup.md) | Before ripping | Shows disc contents from dvdcompare, recommends which titles to rip, creates folder structure |
17
17
 
18
18
  ## Quick start
19
19
 
@@ -33,6 +33,9 @@ riplex organize path/to/rips/Oppenheimer --execute
33
33
 
34
34
  See [Installation](getting-started/installation.md) for full setup instructions.
35
35
 
36
+ If you prefer the desktop app, see the [GUI Walkthrough](gui-guide/gui-walkthrough.md)
37
+ for the main flow with screenshots.
38
+
36
39
  ## Features
37
40
 
38
41
  - **TMDb integration**: Identifies movies vs TV shows, gets canonical titles, episode lists, and runtimes
@@ -48,11 +48,13 @@ nav:
48
48
  - Getting Started:
49
49
  - Installation: getting-started/installation.md
50
50
  - Configuration: getting-started/configuration.md
51
- - User Guide:
52
- - Typical Workflow: guide/workflow.md
53
- - Orchestrate: guide/orchestrate.md
54
- - Lookup: guide/lookup.md
55
- - Organizing Files: guide/organize.md
51
+ - GUI Guide:
52
+ - Walkthrough: gui-guide/gui-walkthrough.md
53
+ - CLI Guide:
54
+ - Workflow: cli-guide/workflow.md
55
+ - Orchestrate: cli-guide/orchestrate.md
56
+ - Lookup: cli-guide/lookup.md
57
+ - Organizing Files: cli-guide/organize.md
56
58
  - CLI Reference: reference/cli.md
57
59
  - Architecture: architecture.md
58
60
  - Plex Naming Rules: naming-rules.md
@@ -10,7 +10,9 @@ import logging
10
10
  import re
11
11
  from dataclasses import dataclass, field
12
12
  from pathlib import Path
13
- from typing import TYPE_CHECKING
13
+ from typing import TYPE_CHECKING, Literal
14
+
15
+ from riplex.title import parse_season_number, parse_title_and_season, strip_year_from_title
14
16
 
15
17
  if TYPE_CHECKING:
16
18
  from riplex.models import ScannedDisc, ScannedFile
@@ -34,9 +36,18 @@ class TitleGroup:
34
36
 
35
37
  title: str
36
38
  folders: list[Path] = field(default_factory=list)
39
+ season_number: int | None = None
37
40
  detected_format: str | None = None
38
41
 
39
42
 
43
+ @dataclass
44
+ class OrganizeLayout:
45
+ """How an organize root should be processed."""
46
+
47
+ mode: Literal["single", "batch", "empty"]
48
+ groups: list[TitleGroup] = field(default_factory=list)
49
+
50
+
40
51
  def detect_format(discs: list[ScannedDisc]) -> str | None:
41
52
  """Infer disc format from the maximum video resolution across all files.
42
53
 
@@ -124,7 +135,8 @@ def group_title_folders(root: Path) -> list[TitleGroup]:
124
135
  Ignores folders starting with ``_`` (e.g. ``_archive``).
125
136
  Returns groups sorted by title, each containing the original folder paths.
126
137
  """
127
- groups: dict[str, list[Path]] = {}
138
+ groups: dict[tuple[str, int | None], list[Path]] = {}
139
+ root_title, _ = strip_year_from_title(root.name)
128
140
 
129
141
  for sub in sorted(root.iterdir()):
130
142
  if not sub.is_dir():
@@ -142,14 +154,38 @@ def group_title_folders(root: Path) -> list[TitleGroup]:
142
154
  continue
143
155
 
144
156
  base = _normalize_title(sub.name)
145
- groups.setdefault(base, []).append(sub)
157
+ title, season_number = parse_title_and_season(base)
158
+ if title is None and season_number is not None:
159
+ title = root_title
160
+ if title is None:
161
+ title = base
162
+ season_number = parse_season_number(base)
163
+ groups.setdefault((title, season_number), []).append(sub)
146
164
 
147
165
  result: list[TitleGroup] = []
148
- for title in sorted(groups):
149
- result.append(TitleGroup(title=title, folders=groups[title]))
166
+ for title, season_number in sorted(groups):
167
+ result.append(TitleGroup(title=title, folders=groups[(title, season_number)], season_number=season_number))
150
168
  return result
151
169
 
152
170
 
171
+ def detect_organize_layout(root: Path) -> OrganizeLayout:
172
+ """Classify an organize root as single-title, batch, or empty.
173
+
174
+ Single mode covers a flat folder of MKVs or a folder whose immediate
175
+ subfolders are disc folders. Batch mode covers roots that contain nested
176
+ season/title folders such as ``Show/Season 6/Disc 1``.
177
+ """
178
+ has_root_mkvs = any(root.glob("*.mkv"))
179
+ has_sub_mkvs = any(root.glob("*/*.mkv"))
180
+ has_nested_mkvs = any(root.glob("*/*/*.mkv"))
181
+
182
+ if has_root_mkvs or (has_sub_mkvs and not has_nested_mkvs):
183
+ return OrganizeLayout(mode="single")
184
+ if has_sub_mkvs or has_nested_mkvs:
185
+ return OrganizeLayout(mode="batch", groups=group_title_folders(root))
186
+ return OrganizeLayout(mode="empty")
187
+
188
+
153
189
  def infer_media_type(disc_info) -> str:
154
190
  """Infer 'movie' or 'tv' from disc title structure.
155
191
 
@@ -114,6 +114,15 @@ class MakeMKVPreflight:
114
114
  error: str = "" # short human-readable failure reason
115
115
 
116
116
 
117
+ class MakeMKVError(RuntimeError):
118
+ """makemkvcon ran but refused to do useful work (e.g. expired beta key)."""
119
+
120
+ def __init__(self, message: str, *, code: int | None = None, raw: str = ""):
121
+ super().__init__(message)
122
+ self.code = code
123
+ self.raw = raw
124
+
125
+
117
126
  @dataclass
118
127
  class DiscInfo:
119
128
  """Parsed disc information from makemkvcon -r info."""
@@ -276,6 +285,43 @@ def parse_drive_list(output: str) -> list[DriveInfo]:
276
285
  return drives
277
286
 
278
287
 
288
+ # MSG codes makemkvcon emits when it refuses to do real work. The user-facing
289
+ # message is the first quoted field. Anything in this set should be surfaced
290
+ # verbatim to the user with an actionable hint, since the rest of the run
291
+ # will silently produce empty results otherwise (no DRV lines, no titles).
292
+ _MAKEMKV_FATAL_MSG_CODES: frozenset[int] = frozenset({
293
+ 5021, # "This application version is too old..." (expired beta key)
294
+ 5022, # registration key expired
295
+ 5023, # registration key invalid
296
+ })
297
+
298
+
299
+ def parse_fatal_message(output: str) -> tuple[int, str] | None:
300
+ """Return ``(code, message)`` for the first known fatal MSG line, else None.
301
+
302
+ makemkvcon emits ``MSG:<code>,<flags>,<count>,"<text>",...`` lines.
303
+ When it refuses to scan (expired beta, invalid key, etc.) it prints
304
+ one of those and then exits without any ``DRV:`` lines, which makes
305
+ ``parse_drive_list`` legitimately return ``[]``. Callers can use
306
+ this helper to distinguish "no drives" from "makemkvcon won't run".
307
+ """
308
+ for line in output.splitlines():
309
+ if not line.startswith("MSG:"):
310
+ continue
311
+ parts = _split_robot_line(line[4:])
312
+ if len(parts) < 4:
313
+ continue
314
+ try:
315
+ code = int(parts[0])
316
+ except ValueError:
317
+ continue
318
+ if code not in _MAKEMKV_FATAL_MSG_CODES:
319
+ continue
320
+ # parts[3] is the rendered, human-readable message text.
321
+ return code, parts[3]
322
+ return None
323
+
324
+
279
325
  def _split_robot_line(text: str) -> list[str]:
280
326
  """Split a makemkvcon robot-mode CSV line, respecting quoted strings."""
281
327
  parts: list[str] = []
@@ -415,7 +461,12 @@ class MakeMKV:
415
461
  return parse_disc_info(output)
416
462
 
417
463
  def drive_list(self) -> list[DriveInfo]:
418
- """List available optical drives."""
464
+ """List available optical drives.
465
+
466
+ Raises :class:`MakeMKVError` if makemkvcon ran but returned no
467
+ drive lines because of a known fatal condition (most commonly
468
+ an expired beta version that refuses to scan until updated).
469
+ """
419
470
  exe = self._require_exe()
420
471
 
421
472
  cmd = [str(exe), "-r", "info", "list"]
@@ -429,7 +480,13 @@ class MakeMKV:
429
480
  **_SUBPROCESS_FLAGS,
430
481
  )
431
482
  output = result.stdout + result.stderr
432
- return parse_drive_list(output)
483
+ drives = parse_drive_list(output)
484
+ if not drives:
485
+ fatal = parse_fatal_message(output)
486
+ if fatal is not None:
487
+ code, message = fatal
488
+ raise MakeMKVError(message, code=code, raw=output)
489
+ return drives
433
490
 
434
491
  def resolve_drive(self, drive_arg: str = "auto") -> DriveInfo:
435
492
  """Resolve a drive argument to a :class:`DriveInfo`.
@@ -63,8 +63,11 @@ async def lookup_metadata(
63
63
 
64
64
  if not skip_dvdcompare:
65
65
  try:
66
+ dvdcompare_title = canonical
67
+ if not is_movie and request.season_number is not None:
68
+ dvdcompare_title = f"{canonical}: Season {request.season_number}"
66
69
  discs, release_name = await fetch_and_select_release(
67
- canonical,
70
+ dvdcompare_title,
68
71
  disc_format=disc_format,
69
72
  disc_info=disc_info,
70
73
  preferred=preferred_release,
@@ -139,6 +139,8 @@ async def _plan_show(
139
139
 
140
140
  seasons: list[PlannedSeason] = []
141
141
  for sm in detail.seasons:
142
+ if request.season_number is not None and sm.season_number != request.season_number:
143
+ continue
142
144
  episodes: list[PlannedEpisode] = []
143
145
  for em in sm.episodes:
144
146
  fname = episode_file_name(
@@ -12,6 +12,7 @@ class SearchRequest:
12
12
 
13
13
  title: str
14
14
  year: int | None = None
15
+ season_number: int | None = None
15
16
  media_type: Literal["movie", "tv", "auto"] = "auto"
16
17
  include_specials: bool = True
17
18
  include_extras_skeleton: bool = True