riplex 0.6.2__tar.gz → 0.6.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 (131) hide show
  1. {riplex-0.6.2 → riplex-0.6.3}/.github/ISSUE_TEMPLATE/bug_report.yml +1 -1
  2. riplex-0.6.3/.github/ISSUE_TEMPLATE/crash_report.yml +82 -0
  3. {riplex-0.6.2 → riplex-0.6.3}/.github/copilot-instructions.md +38 -0
  4. {riplex-0.6.2/src/riplex.egg-info → riplex-0.6.3}/PKG-INFO +2 -2
  5. {riplex-0.6.2 → riplex-0.6.3}/docs/changelog.md +12 -0
  6. {riplex-0.6.2 → riplex-0.6.3}/docs/troubleshooting.md +19 -0
  7. riplex-0.6.3/issues/debug-artifacts-consolidation.md +146 -0
  8. riplex-0.6.3/issues/planned-features.md +509 -0
  9. {riplex-0.6.2 → riplex-0.6.3}/pyproject.toml +1 -1
  10. riplex-0.6.3/src/riplex/__init__.py +8 -0
  11. {riplex-0.6.2 → riplex-0.6.3}/src/riplex/disc/makemkv.py +130 -6
  12. {riplex-0.6.2 → riplex-0.6.3}/src/riplex/disc/provider.py +220 -14
  13. {riplex-0.6.2/src/riplex_app → riplex-0.6.3/src/riplex}/updater.py +56 -5
  14. {riplex-0.6.2 → riplex-0.6.3/src/riplex.egg-info}/PKG-INFO +2 -2
  15. {riplex-0.6.2 → riplex-0.6.3}/src/riplex.egg-info/SOURCES.txt +6 -1
  16. {riplex-0.6.2 → riplex-0.6.3}/src/riplex.egg-info/requires.txt +1 -1
  17. riplex-0.6.3/src/riplex_app/bug_report.py +145 -0
  18. riplex-0.6.3/src/riplex_app/crash_dump.py +116 -0
  19. riplex-0.6.3/src/riplex_app/keep_awake.py +88 -0
  20. riplex-0.6.3/src/riplex_app/main.py +331 -0
  21. riplex-0.6.3/src/riplex_app/screens/disc_detection.py +677 -0
  22. {riplex-0.6.2 → riplex-0.6.3}/src/riplex_app/screens/metadata.py +44 -1
  23. {riplex-0.6.2 → riplex-0.6.3}/src/riplex_app/screens/organize_done.py +26 -9
  24. {riplex-0.6.2 → riplex-0.6.3}/src/riplex_app/screens/organize_preview.py +30 -1
  25. {riplex-0.6.2 → riplex-0.6.3}/src/riplex_app/screens/progress.py +5 -0
  26. {riplex-0.6.2 → riplex-0.6.3}/src/riplex_app/screens/release.py +124 -9
  27. {riplex-0.6.2 → riplex-0.6.3}/src/riplex_app/screens/update.py +1 -1
  28. {riplex-0.6.2 → riplex-0.6.3}/src/riplex_app/screens/welcome.py +47 -15
  29. {riplex-0.6.2 → riplex-0.6.3}/src/riplex_cli/main.py +25 -1
  30. riplex-0.6.3/tests/test_disc_detection_screen.py +46 -0
  31. {riplex-0.6.2 → riplex-0.6.3}/tests/test_disc_provider.py +49 -0
  32. {riplex-0.6.2 → riplex-0.6.3}/tests/test_makemkv.py +46 -0
  33. {riplex-0.6.2 → riplex-0.6.3}/tests/test_updater.py +100 -8
  34. riplex-0.6.2/issues/planned-features.md +0 -48
  35. riplex-0.6.2/src/riplex/__init__.py +0 -3
  36. riplex-0.6.2/src/riplex_app/bug_report.py +0 -76
  37. riplex-0.6.2/src/riplex_app/main.py +0 -130
  38. riplex-0.6.2/src/riplex_app/screens/disc_detection.py +0 -312
  39. {riplex-0.6.2 → riplex-0.6.3}/.github/agents/riplex.agent.md +0 -0
  40. {riplex-0.6.2 → riplex-0.6.3}/.github/workflows/publish.yml +0 -0
  41. {riplex-0.6.2 → riplex-0.6.3}/.github/workflows/release.yml +0 -0
  42. {riplex-0.6.2 → riplex-0.6.3}/.gitignore +0 -0
  43. {riplex-0.6.2 → riplex-0.6.3}/.vscode/settings.json +0 -0
  44. {riplex-0.6.2 → riplex-0.6.3}/CONTRIBUTORS.md +0 -0
  45. {riplex-0.6.2 → riplex-0.6.3}/LICENSE +0 -0
  46. {riplex-0.6.2 → riplex-0.6.3}/README.md +0 -0
  47. {riplex-0.6.2 → riplex-0.6.3}/docs/architecture.md +0 -0
  48. {riplex-0.6.2 → riplex-0.6.3}/docs/getting-started/configuration.md +0 -0
  49. {riplex-0.6.2 → riplex-0.6.3}/docs/getting-started/installation.md +0 -0
  50. {riplex-0.6.2 → riplex-0.6.3}/docs/guide/lookup.md +0 -0
  51. {riplex-0.6.2 → riplex-0.6.3}/docs/guide/orchestrate.md +0 -0
  52. {riplex-0.6.2 → riplex-0.6.3}/docs/guide/organize.md +0 -0
  53. {riplex-0.6.2 → riplex-0.6.3}/docs/guide/workflow.md +0 -0
  54. {riplex-0.6.2 → riplex-0.6.3}/docs/index.md +0 -0
  55. {riplex-0.6.2 → riplex-0.6.3}/docs/naming-rules.md +0 -0
  56. {riplex-0.6.2 → riplex-0.6.3}/docs/reference/cli.md +0 -0
  57. {riplex-0.6.2 → riplex-0.6.3}/issues/orchestrate-dvdcompare-fallback.md +0 -0
  58. {riplex-0.6.2 → riplex-0.6.3}/mkdocs.yml +0 -0
  59. {riplex-0.6.2 → riplex-0.6.3}/setup.cfg +0 -0
  60. {riplex-0.6.2 → riplex-0.6.3}/src/riplex/cache.py +0 -0
  61. {riplex-0.6.2 → riplex-0.6.3}/src/riplex/config.py +0 -0
  62. {riplex-0.6.2 → riplex-0.6.3}/src/riplex/dedup.py +0 -0
  63. {riplex-0.6.2 → riplex-0.6.3}/src/riplex/detect.py +0 -0
  64. {riplex-0.6.2 → riplex-0.6.3}/src/riplex/disc/__init__.py +0 -0
  65. {riplex-0.6.2 → riplex-0.6.3}/src/riplex/disc/analysis.py +0 -0
  66. {riplex-0.6.2 → riplex-0.6.3}/src/riplex/formatter.py +0 -0
  67. {riplex-0.6.2 → riplex-0.6.3}/src/riplex/lookup.py +0 -0
  68. {riplex-0.6.2 → riplex-0.6.3}/src/riplex/manifest.py +0 -0
  69. {riplex-0.6.2 → riplex-0.6.3}/src/riplex/matcher.py +0 -0
  70. {riplex-0.6.2 → riplex-0.6.3}/src/riplex/metadata/__init__.py +0 -0
  71. {riplex-0.6.2 → riplex-0.6.3}/src/riplex/metadata/planner.py +0 -0
  72. {riplex-0.6.2 → riplex-0.6.3}/src/riplex/metadata/provider.py +0 -0
  73. {riplex-0.6.2 → riplex-0.6.3}/src/riplex/metadata/sources/__init__.py +0 -0
  74. {riplex-0.6.2 → riplex-0.6.3}/src/riplex/metadata/sources/tmdb.py +0 -0
  75. {riplex-0.6.2 → riplex-0.6.3}/src/riplex/models.py +0 -0
  76. {riplex-0.6.2 → riplex-0.6.3}/src/riplex/normalize.py +0 -0
  77. {riplex-0.6.2 → riplex-0.6.3}/src/riplex/organizer.py +0 -0
  78. {riplex-0.6.2 → riplex-0.6.3}/src/riplex/scanner.py +0 -0
  79. {riplex-0.6.2 → riplex-0.6.3}/src/riplex/snapshot.py +0 -0
  80. {riplex-0.6.2 → riplex-0.6.3}/src/riplex/splitter.py +0 -0
  81. {riplex-0.6.2 → riplex-0.6.3}/src/riplex/tagger.py +0 -0
  82. {riplex-0.6.2 → riplex-0.6.3}/src/riplex/title.py +0 -0
  83. {riplex-0.6.2 → riplex-0.6.3}/src/riplex/ui.py +0 -0
  84. {riplex-0.6.2 → riplex-0.6.3}/src/riplex.egg-info/dependency_links.txt +0 -0
  85. {riplex-0.6.2 → riplex-0.6.3}/src/riplex.egg-info/entry_points.txt +0 -0
  86. {riplex-0.6.2 → riplex-0.6.3}/src/riplex.egg-info/top_level.txt +0 -0
  87. {riplex-0.6.2 → riplex-0.6.3}/src/riplex_app/__init__.py +0 -0
  88. {riplex-0.6.2 → riplex-0.6.3}/src/riplex_app/screens/__init__.py +0 -0
  89. {riplex-0.6.2 → riplex-0.6.3}/src/riplex_app/screens/disc_overview.py +0 -0
  90. {riplex-0.6.2 → riplex-0.6.3}/src/riplex_app/screens/disc_swap.py +0 -0
  91. {riplex-0.6.2 → riplex-0.6.3}/src/riplex_app/screens/done.py +0 -0
  92. {riplex-0.6.2 → riplex-0.6.3}/src/riplex_app/screens/folder_picker.py +0 -0
  93. {riplex-0.6.2 → riplex-0.6.3}/src/riplex_app/screens/orchestrate_done.py +0 -0
  94. {riplex-0.6.2 → riplex-0.6.3}/src/riplex_app/screens/selection.py +0 -0
  95. {riplex-0.6.2 → riplex-0.6.3}/src/riplex_cli/__init__.py +0 -0
  96. {riplex-0.6.2 → riplex-0.6.3}/src/riplex_cli/commands/__init__.py +0 -0
  97. {riplex-0.6.2 → riplex-0.6.3}/src/riplex_cli/commands/lookup.py +0 -0
  98. {riplex-0.6.2 → riplex-0.6.3}/src/riplex_cli/commands/orchestrate.py +0 -0
  99. {riplex-0.6.2 → riplex-0.6.3}/src/riplex_cli/commands/organize.py +0 -0
  100. {riplex-0.6.2 → riplex-0.6.3}/src/riplex_cli/commands/rip.py +0 -0
  101. {riplex-0.6.2 → riplex-0.6.3}/src/riplex_cli/commands/setup.py +0 -0
  102. {riplex-0.6.2 → riplex-0.6.3}/src/riplex_cli/formatting.py +0 -0
  103. {riplex-0.6.2 → riplex-0.6.3}/tests/__init__.py +0 -0
  104. {riplex-0.6.2 → riplex-0.6.3}/tests/fixtures/chernobyl_disc1.json +0 -0
  105. {riplex-0.6.2 → riplex-0.6.3}/tests/fixtures/makemkvcon_frozen_planet_ii_d2.txt +0 -0
  106. {riplex-0.6.2 → riplex-0.6.3}/tests/fixtures/makemkvcon_list.txt +0 -0
  107. {riplex-0.6.2 → riplex-0.6.3}/tests/snapshots/Batman Begins.snapshot.json +0 -0
  108. {riplex-0.6.2 → riplex-0.6.3}/tests/snapshots/Blade Runner (Blu-ray 4k).snapshot.json +0 -0
  109. {riplex-0.6.2 → riplex-0.6.3}/tests/snapshots/Blade Runner The Final Cut.snapshot.json +0 -0
  110. {riplex-0.6.2 → riplex-0.6.3}/tests/snapshots/Seven Worlds One Planet.snapshot.json +0 -0
  111. {riplex-0.6.2 → riplex-0.6.3}/tests/snapshots/The Dark Knight Rises.snapshot.json +0 -0
  112. {riplex-0.6.2 → riplex-0.6.3}/tests/snapshots/The Dark Knight.snapshot.json +0 -0
  113. {riplex-0.6.2 → riplex-0.6.3}/tests/snapshots/Waterworld.snapshot.json +0 -0
  114. {riplex-0.6.2 → riplex-0.6.3}/tests/test_cache.py +0 -0
  115. {riplex-0.6.2 → riplex-0.6.3}/tests/test_cli_utils.py +0 -0
  116. {riplex-0.6.2 → riplex-0.6.3}/tests/test_config.py +0 -0
  117. {riplex-0.6.2 → riplex-0.6.3}/tests/test_dedup.py +0 -0
  118. {riplex-0.6.2 → riplex-0.6.3}/tests/test_detect.py +0 -0
  119. {riplex-0.6.2 → riplex-0.6.3}/tests/test_disc_analysis.py +0 -0
  120. {riplex-0.6.2 → riplex-0.6.3}/tests/test_disc_fixtures.py +0 -0
  121. {riplex-0.6.2 → riplex-0.6.3}/tests/test_formatter.py +0 -0
  122. {riplex-0.6.2 → riplex-0.6.3}/tests/test_matcher.py +0 -0
  123. {riplex-0.6.2 → riplex-0.6.3}/tests/test_normalize.py +0 -0
  124. {riplex-0.6.2 → riplex-0.6.3}/tests/test_organizer.py +0 -0
  125. {riplex-0.6.2 → riplex-0.6.3}/tests/test_planner.py +0 -0
  126. {riplex-0.6.2 → riplex-0.6.3}/tests/test_rip_guide.py +0 -0
  127. {riplex-0.6.2 → riplex-0.6.3}/tests/test_scanner.py +0 -0
  128. {riplex-0.6.2 → riplex-0.6.3}/tests/test_snapshot.py +0 -0
  129. {riplex-0.6.2 → riplex-0.6.3}/tests/test_splitter.py +0 -0
  130. {riplex-0.6.2 → riplex-0.6.3}/tests/test_tagger.py +0 -0
  131. {riplex-0.6.2 → riplex-0.6.3}/tests/test_ui.py +0 -0
@@ -13,7 +13,7 @@ body:
13
13
  id: version
14
14
  attributes:
15
15
  label: riplex version
16
- placeholder: "e.g. 0.1.1.dev18"
16
+ placeholder: "e.g. 0.4.1"
17
17
  validations:
18
18
  required: true
19
19
 
@@ -0,0 +1,82 @@
1
+ name: Crash Report
2
+ description: Report an unhandled exception / crash in riplex (auto-filed from the GUI's "Report Crash" button)
3
+ title: "[Crash] "
4
+ labels: ["bug", "crash"]
5
+ body:
6
+ - type: markdown
7
+ attributes:
8
+ value: |
9
+ Thanks for reporting a crash! Most fields below are pre-filled by the
10
+ GUI. Please review and add anything else that might help reproduce.
11
+
12
+ - type: input
13
+ id: version
14
+ attributes:
15
+ label: riplex version
16
+ placeholder: "e.g. 0.4.1"
17
+ validations:
18
+ required: true
19
+
20
+ - type: input
21
+ id: platform
22
+ attributes:
23
+ label: Platform
24
+ placeholder: "e.g. Windows-11-10.0.26100-SP0"
25
+ validations:
26
+ required: true
27
+
28
+ - type: dropdown
29
+ id: frontend
30
+ attributes:
31
+ label: Frontend
32
+ options:
33
+ - CLI
34
+ - GUI
35
+ validations:
36
+ required: true
37
+
38
+ - type: input
39
+ id: exception-type
40
+ attributes:
41
+ label: Exception type
42
+ placeholder: "e.g. FileNotFoundError"
43
+ validations:
44
+ required: true
45
+
46
+ - type: input
47
+ id: exception-message
48
+ attributes:
49
+ label: Exception message
50
+ placeholder: "e.g. [WinError 2] The system cannot find the file specified"
51
+
52
+ - type: input
53
+ id: last-screen
54
+ attributes:
55
+ label: Last screen / action
56
+ description: Which screen were you on, or what did you click, when the crash happened?
57
+ placeholder: "e.g. organize_done — clicked Open Folder"
58
+
59
+ - type: textarea
60
+ id: traceback
61
+ attributes:
62
+ label: Traceback
63
+ description: Full Python traceback (auto-filled by the GUI).
64
+ render: text
65
+ validations:
66
+ required: true
67
+
68
+ - type: textarea
69
+ id: what-were-you-doing
70
+ attributes:
71
+ label: What were you doing?
72
+ description: Brief description of the steps leading up to the crash.
73
+
74
+ - type: textarea
75
+ id: debug-files
76
+ attributes:
77
+ label: Debug files
78
+ description: |
79
+ Please attach the crash dump file referenced above. It contains the
80
+ full traceback, app state, and recent logs needed to reproduce the
81
+ crash. If a `_riplex/` debug folder also exists at your output
82
+ directory, zip it and drag it here as well.
@@ -28,6 +28,20 @@ For the GUI, also include the gui extra:
28
28
  pip install -e ".[dev,gui]"
29
29
  ```
30
30
 
31
+ ### Editable-installing dvdcompare-scraper (optional)
32
+
33
+ By default `dvdcompare-scraper` is pulled from PyPI as a regular install, so
34
+ local edits to that sibling repo (typically at
35
+ `../dvdcompare-scraper/`) do not take effect until a new version is
36
+ published. To pick up scraper changes immediately without bumping the
37
+ version, editable-install it once:
38
+
39
+ ```
40
+ pip install -e ../dvdcompare-scraper
41
+ ```
42
+
43
+ After this, `riplex-ui` and the CLI will use the local checkout directly.
44
+
31
45
  ### macOS extras (Homebrew Python only)
32
46
 
33
47
  If you installed Python via Homebrew, two additional one-time steps are needed:
@@ -60,6 +74,30 @@ riplex-ui # Launch the Flet GUI
60
74
 
61
75
  Do NOT use `python -m riplex` (that errors — riplex is a library package, not runnable). Do NOT use `python -m riplex_cli.main` when the entry point works.
62
76
 
77
+ Because `riplex` is editable-installed (`pip install -e .`), any local edit
78
+ to source files under `src/riplex/`, `src/riplex_cli/`, or `src/riplex_app/`
79
+ is live the next time you launch `riplex-ui` or run a `riplex` CLI command.
80
+ No reinstall step is needed for normal development.
81
+
82
+ ## Upgrading dependencies
83
+
84
+ The only dependency that needs an explicit upgrade is `dvdcompare-scraper`,
85
+ since it's installed from PyPI (not editable). After a new version is
86
+ published (every push to its `main` branch auto-bumps the patch and
87
+ publishes), bump the pin in `pyproject.toml` and run:
88
+ ```
89
+ pip install -e ".[dev,gui]" --upgrade
90
+ ```
91
+
92
+ Close `riplex-ui` first if it's running — the `.exe` shim is locked while
93
+ the process is alive and pip will fail with `WinError 32`.
94
+
95
+ To verify the upgrade picked up the new version:
96
+ ```
97
+ py -m pip show dvdcompare-scraper | Select-String Version
98
+ ```
99
+
100
+
63
101
  ## Dry-run default
64
102
 
65
103
  All destructive commands (`rip`, `organize`, `orchestrate`) are dry-run by default. There is no `--dry-run` flag. Use `--execute` to actually perform the operation.
@@ -1,13 +1,13 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: riplex
3
- Version: 0.6.2
3
+ Version: 0.6.3
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
7
7
  Description-Content-Type: text/markdown
8
8
  License-File: LICENSE
9
9
  Requires-Dist: httpx>=0.27
10
- Requires-Dist: dvdcompare-scraper>=0.1.12
10
+ Requires-Dist: dvdcompare-scraper>=0.1.15
11
11
  Requires-Dist: platformdirs>=4.0
12
12
  Provides-Extra: dev
13
13
  Requires-Dist: pytest>=8.0; extra == "dev"
@@ -4,6 +4,18 @@ 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
+ ## 2026-05-13
8
+
9
+ ### Changed
10
+
11
+ - Bumped `dvdcompare-scraper` pin to `>=0.1.15`, which adds quoted-title disc-header parsing. Boxsets such as *Back to the Future 40th Anniversary Trilogy* that glue six physical discs into a single dvdcompare disc entry are now split correctly into one PlannedDisc per physical disc.
12
+
13
+ ## 2026-05-12
14
+
15
+ ### Added
16
+
17
+ - Troubleshooting guide: new "GUI: disc not being detected" section covering the redesigned drive-list panel, manual drive selection, the `makemkvcon` status line, and the bundled bug-report flow.
18
+
7
19
  ## 2026-05-09
8
20
 
9
21
  ### Changed
@@ -35,6 +35,25 @@ Common issues and solutions reported by users.
35
35
 
36
36
  ---
37
37
 
38
+ ## GUI: disc not being detected
39
+
40
+ **Symptom:** `riplex-ui` shows "No disc found" or sits on the disc detection screen even though a disc is inserted.
41
+
42
+ **What the GUI does:**
43
+
44
+ * On the **Disc Detection** screen, riplex now lists every optical drive your system reports, with a per-drive status badge (`Empty`, `Tray open`, `Disc loaded`, etc.).
45
+ * The list refreshes automatically every few seconds — inserting or ejecting a disc updates the screen without manual refresh. Click the circular ↻ button at the top right to force an immediate rescan.
46
+ * If exactly one drive has a loaded disc, riplex starts reading it automatically. With multiple drives or zero loaded drives, click `Read disc` next to the drive you want to use.
47
+
48
+ **If your drive is missing entirely:**
49
+
50
+ 1. Confirm MakeMKV sees the drive. Open the MakeMKV GUI or run `makemkvcon -r info list` and look for a `DRV:` line with your device path.
51
+ 2. If MakeMKV does not list it, the issue is at the OS/driver level — riplex only displays what MakeMKV reports.
52
+ 3. Check the `makemkvcon: …` line at the top of the screen. If it shows `unavailable`, click the bundled "Download MakeMKV" link or follow the [installation guide](getting-started/installation.md).
53
+ 4. Use the `Open bug report` button on the error panel — it pre-fills the GitHub issue with the captured MakeMKV diagnostics (executable path, version, last error) and points you at the log directory to attach.
54
+
55
+ ---
56
+
38
57
  ## Invalid config file (TOML parse error)
39
58
 
40
59
  **Symptom:** Running any riplex command crashes with a `TOMLDecodeError` traceback mentioning your config file.
@@ -0,0 +1,146 @@
1
+ # Consolidate riplex debug artifacts
2
+
3
+ ## Problem
4
+
5
+ riplex currently writes 11 distinct JSON/log artifacts across multiple
6
+ locations with overlapping naming. The word "manifest" is overloaded
7
+ (production `_rip_manifest.json` vs. debug `riplex-rip.manifest.json`),
8
+ two debug writers (`save_rip_manifest`, `save_scan_snapshot`) have no
9
+ production readers, and the organize snapshot lives at the title root
10
+ instead of in `_riplex/` like the other debug files. The `_riplex/README.txt`
11
+ template lists files that may not actually be present.
12
+
13
+ A related bug: failed rips silently produce a `_rip_manifest.json` with
14
+ `"filename": ""` because `run_rip` checks `proc.returncode == 0` to
15
+ determine success, but `makemkvcon` returns 0 even on HashCheck failures.
16
+ Surfaced by a real failure on Matrix Reloaded Disc 1 (corrupt
17
+ `/BDMV/STREAM/00002.m2ts`).
18
+
19
+ ## Affected users
20
+
21
+ Anyone filing bug reports (confused about which JSON to attach), anyone
22
+ inspecting their rip output (unclear what each file is for), anyone
23
+ re-running organize on a failed rip (manifest claims success).
24
+
25
+ ## Workaround
26
+
27
+ None — symptom is cosmetic confusion plus the failed-rip status bug,
28
+ which can be diagnosed by reading `_makemkvcon_tNN.log` directly.
29
+
30
+ ## Proposed fix
31
+
32
+ ### Target artifact layout
33
+
34
+ **Per-disc folder** (production + per-title logs):
35
+
36
+ - `Disc N/<canonical>_tNN.mkv` — actual rip
37
+ - `Disc N/_rip_manifest.json` — production; gains a per-title `status`
38
+ field (`"success"` | `"failed"` | `"cancelled"`) plus `error_message`
39
+ for failures, and top-level `success_count` / `failed_count`
40
+ - `Disc N/_makemkvcon_tNN.log` — stays here (per-title, too noisy for
41
+ the title-level debug folder)
42
+
43
+ **Title-root `_riplex/`** (single home for all debug):
44
+
45
+ - `riplex-rip.snapshot.json` — rip pipeline state (TMDb match,
46
+ dvdcompare, selected/ripped titles, phase)
47
+ - `riplex-organize.snapshot.json` — **renamed and moved** from
48
+ `<Title>.snapshot.json` at title root
49
+ - `organized.json` — already lives here, unchanged
50
+ - `riplex.log` — CLI session log, unchanged
51
+ - `README.txt` — rewritten to match what's actually written
52
+
53
+ **User-data folder** (`~/.../riplex/`) — unchanged:
54
+
55
+ - `riplex_app.log` — GUI runtime log
56
+ - `crashes/crash-*.txt` — GUI crash dumps
57
+
58
+ **Removed entirely**:
59
+
60
+ - `_riplex/riplex-rip.manifest.json` — duplicate of production manifest,
61
+ no readers
62
+ - `_riplex/riplex-scan.snapshot.json` — aborted parallel mechanism, no
63
+ production readers (only tests)
64
+
65
+ ### Implementation phases
66
+
67
+ 1. **Manifest status field.** Real success detection in `run_rip` (parse
68
+ `MSG:5004,...,"N titles saved, M failed"` summary line). Update
69
+ `build_rip_manifest` to include all attempted titles with `status` +
70
+ `error_message`. `build_scanned_from_manifests` skips non-success
71
+ entries. `load_manifest` defaults `status` to `"success"` when
72
+ missing for back-compat. Independent of other phases. (Partially
73
+ implemented: `_parse_rip_summary` already added in
74
+ `src/riplex/disc/makemkv.py`.)
75
+
76
+ 2. **Consolidate organize snapshot.** New path
77
+ `_riplex/riplex-organize.snapshot.json`. `snapshot.py::load()` falls
78
+ back to legacy `<Title>.snapshot.json` for old folders (no
79
+ migration). Updates callers in `organize.py` and
80
+ `organize_preview.py`. Independent of phase 1.
81
+
82
+ 3. **Remove dead writers.** Delete `snapshot.py::save_rip_manifest()`
83
+ and `snapshot.py::save_scan_snapshot()` plus their callers. Drop
84
+ corresponding tests. Depends on phase 2.
85
+
86
+ 4. **Docs + README template.** Rewrite `_README_TEXT` in `snapshot.py`
87
+ to match reality. New "Output Artifacts" section in
88
+ `docs/architecture.md` with the full table (production vs debug,
89
+ location, writer, reader, safe-to-delete). Dated entry in
90
+ `docs/changelog.md`. Same commit as phases 2-3 so docs match code.
91
+
92
+ 5. **Patch version bump** per repo convention.
93
+
94
+ ### Decisions locked
95
+
96
+ - Heavy scope: consolidate file locations + rename + remove dead code +
97
+ docs (not just docs)
98
+ - "manifest" reserved for production data; debug duplicate is deleted,
99
+ not renamed
100
+ - Both `save_rip_manifest` and `save_scan_snapshot` removed
101
+ - `_makemkvcon_tNN.log` stays in per-disc folder (too noisy/per-title to
102
+ belong alongside the higher-level pipeline snapshots)
103
+ - Failed rips DO get a `_rip_manifest.json` entry with `status: "failed"`
104
+ - No migration tool for old organize snapshots — `load()` just tries new
105
+ path first, falls back to legacy
106
+
107
+ ### Verification
108
+
109
+ 1. `pytest` — existing tests pass; new tests for status field +
110
+ legacy snapshot fallback
111
+ 2. Fresh GUI rip → output dirs contain only files in the north-star
112
+ list above
113
+ 3. Cancel a rip mid-way → manifest has `status: "cancelled"` entry
114
+ 4. Re-rip Matrix Reloaded Disc 1 (the damaged disc that prompted this)
115
+ → manifest has `status: "failed"` with `error_message` populated
116
+ 5. Run organize against a folder containing legacy
117
+ `<Title>.snapshot.json` → loads via fallback
118
+ 6. Open `_riplex/README.txt` in a finished session → matches files
119
+ actually present
120
+ 7. Visual: title folder structure matches `docs/architecture.md` table
121
+ exactly
122
+
123
+ ### Out of scope
124
+
125
+ - User-data log locations (`riplex_app.log`, crash dumps)
126
+ - Migration tool for old `<Title>.snapshot.json` (just fallback-read)
127
+ - v1/v2 snapshot envelope format (already supported by `load`)
128
+ - `_makemkvcon_tNN.log` location/format
129
+ - GUI changes beyond the manifest status fix already started
130
+
131
+ ## Relevant files
132
+
133
+ - `src/riplex/manifest.py` — `build_rip_manifest`,
134
+ `build_scanned_from_manifests`, `load_manifest`
135
+ - `src/riplex/snapshot.py` — `save_rip_snapshot`, `save_rip_manifest`
136
+ (DELETE), `save_scan_snapshot` (DELETE), `save_from_scanned`, `load`,
137
+ `_README_TEXT`, `get_debug_dir`
138
+ - `src/riplex/disc/makemkv.py` — `run_rip`, `_parse_rip_summary`
139
+ - `src/riplex_cli/commands/rip.py` — remove `save_rip_manifest` call
140
+ - `src/riplex_cli/commands/organize.py` — organize snapshot path
141
+ - `src/riplex_app/screens/organize_preview.py` — organize snapshot path
142
+ - `src/riplex_app/screens/progress.py` — `_write_manifest`
143
+ - `tests/test_snapshot.py`, `tests/test_manifest.py` — fixtures, drop
144
+ deleted-fn tests, add status-field tests
145
+ - `docs/architecture.md` — new Output Artifacts section
146
+ - `docs/changelog.md` — dated entry