riplex 0.3.6__tar.gz → 0.4.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.4.0/.github/copilot-instructions.md +69 -0
- {riplex-0.3.6 → riplex-0.4.0}/.github/workflows/release.yml +20 -8
- riplex-0.4.0/.vscode/settings.json +4 -0
- {riplex-0.3.6/src/riplex.egg-info → riplex-0.4.0}/PKG-INFO +2 -2
- {riplex-0.3.6 → riplex-0.4.0}/README.md +1 -1
- {riplex-0.3.6 → riplex-0.4.0}/docs/changelog.md +14 -0
- {riplex-0.3.6 → riplex-0.4.0}/docs/getting-started/installation.md +41 -10
- {riplex-0.3.6 → riplex-0.4.0}/pyproject.toml +6 -0
- {riplex-0.3.6 → riplex-0.4.0}/src/riplex/disc/makemkv.py +6 -3
- {riplex-0.3.6 → riplex-0.4.0}/src/riplex/scanner.py +30 -9
- {riplex-0.3.6 → riplex-0.4.0}/src/riplex/splitter.py +8 -1
- {riplex-0.3.6 → riplex-0.4.0}/src/riplex/tagger.py +2 -0
- {riplex-0.3.6 → riplex-0.4.0/src/riplex.egg-info}/PKG-INFO +2 -2
- {riplex-0.3.6 → riplex-0.4.0}/src/riplex.egg-info/SOURCES.txt +1 -0
- {riplex-0.3.6 → riplex-0.4.0}/src/riplex_app/screens/folder_picker.py +8 -2
- {riplex-0.3.6 → riplex-0.4.0}/src/riplex_app/screens/welcome.py +212 -8
- {riplex-0.3.6 → riplex-0.4.0}/src/riplex_app/updater.py +6 -0
- {riplex-0.3.6 → riplex-0.4.0}/src/riplex_cli/commands/setup.py +12 -6
- {riplex-0.3.6 → riplex-0.4.0}/tests/test_scanner.py +8 -4
- {riplex-0.3.6 → riplex-0.4.0}/tests/test_splitter.py +6 -3
- {riplex-0.3.6 → riplex-0.4.0}/tests/test_tagger.py +4 -2
- {riplex-0.3.6 → riplex-0.4.0}/tests/test_updater.py +21 -3
- riplex-0.3.6/.github/copilot-instructions.md +0 -38
- {riplex-0.3.6 → riplex-0.4.0}/.github/ISSUE_TEMPLATE/bug_report.yml +0 -0
- {riplex-0.3.6 → riplex-0.4.0}/.github/agents/riplex.agent.md +0 -0
- {riplex-0.3.6 → riplex-0.4.0}/.github/workflows/publish.yml +0 -0
- {riplex-0.3.6 → riplex-0.4.0}/.gitignore +0 -0
- {riplex-0.3.6 → riplex-0.4.0}/LICENSE +0 -0
- {riplex-0.3.6 → riplex-0.4.0}/REFACTOR_PLAN.md +0 -0
- {riplex-0.3.6 → riplex-0.4.0}/docs/architecture.md +0 -0
- {riplex-0.3.6 → riplex-0.4.0}/docs/getting-started/configuration.md +0 -0
- {riplex-0.3.6 → riplex-0.4.0}/docs/guide/lookup.md +0 -0
- {riplex-0.3.6 → riplex-0.4.0}/docs/guide/orchestrate.md +0 -0
- {riplex-0.3.6 → riplex-0.4.0}/docs/guide/organize.md +0 -0
- {riplex-0.3.6 → riplex-0.4.0}/docs/guide/workflow.md +0 -0
- {riplex-0.3.6 → riplex-0.4.0}/docs/index.md +0 -0
- {riplex-0.3.6 → riplex-0.4.0}/docs/naming-rules.md +0 -0
- {riplex-0.3.6 → riplex-0.4.0}/docs/reference/cli.md +0 -0
- {riplex-0.3.6 → riplex-0.4.0}/docs/troubleshooting.md +0 -0
- {riplex-0.3.6 → riplex-0.4.0}/issues/cross-disc-dvdcompare-matching.md +0 -0
- {riplex-0.3.6 → riplex-0.4.0}/issues/orchestrate-dvdcompare-fallback.md +0 -0
- {riplex-0.3.6 → riplex-0.4.0}/issues/planned-features.md +0 -0
- {riplex-0.3.6 → riplex-0.4.0}/mkdocs.yml +0 -0
- {riplex-0.3.6 → riplex-0.4.0}/setup.cfg +0 -0
- {riplex-0.3.6 → riplex-0.4.0}/src/riplex/__init__.py +0 -0
- {riplex-0.3.6 → riplex-0.4.0}/src/riplex/cache.py +0 -0
- {riplex-0.3.6 → riplex-0.4.0}/src/riplex/config.py +0 -0
- {riplex-0.3.6 → riplex-0.4.0}/src/riplex/dedup.py +0 -0
- {riplex-0.3.6 → riplex-0.4.0}/src/riplex/detect.py +0 -0
- {riplex-0.3.6 → riplex-0.4.0}/src/riplex/disc/__init__.py +0 -0
- {riplex-0.3.6 → riplex-0.4.0}/src/riplex/disc/analysis.py +0 -0
- {riplex-0.3.6 → riplex-0.4.0}/src/riplex/disc/provider.py +0 -0
- {riplex-0.3.6 → riplex-0.4.0}/src/riplex/formatter.py +0 -0
- {riplex-0.3.6 → riplex-0.4.0}/src/riplex/lookup.py +0 -0
- {riplex-0.3.6 → riplex-0.4.0}/src/riplex/manifest.py +0 -0
- {riplex-0.3.6 → riplex-0.4.0}/src/riplex/matcher.py +0 -0
- {riplex-0.3.6 → riplex-0.4.0}/src/riplex/metadata/__init__.py +0 -0
- {riplex-0.3.6 → riplex-0.4.0}/src/riplex/metadata/planner.py +0 -0
- {riplex-0.3.6 → riplex-0.4.0}/src/riplex/metadata/provider.py +0 -0
- {riplex-0.3.6 → riplex-0.4.0}/src/riplex/metadata/sources/__init__.py +0 -0
- {riplex-0.3.6 → riplex-0.4.0}/src/riplex/metadata/sources/tmdb.py +0 -0
- {riplex-0.3.6 → riplex-0.4.0}/src/riplex/models.py +0 -0
- {riplex-0.3.6 → riplex-0.4.0}/src/riplex/normalize.py +0 -0
- {riplex-0.3.6 → riplex-0.4.0}/src/riplex/organizer.py +0 -0
- {riplex-0.3.6 → riplex-0.4.0}/src/riplex/snapshot.py +0 -0
- {riplex-0.3.6 → riplex-0.4.0}/src/riplex/title.py +0 -0
- {riplex-0.3.6 → riplex-0.4.0}/src/riplex/ui.py +0 -0
- {riplex-0.3.6 → riplex-0.4.0}/src/riplex.egg-info/dependency_links.txt +0 -0
- {riplex-0.3.6 → riplex-0.4.0}/src/riplex.egg-info/entry_points.txt +0 -0
- {riplex-0.3.6 → riplex-0.4.0}/src/riplex.egg-info/requires.txt +0 -0
- {riplex-0.3.6 → riplex-0.4.0}/src/riplex.egg-info/top_level.txt +0 -0
- {riplex-0.3.6 → riplex-0.4.0}/src/riplex_app/__init__.py +0 -0
- {riplex-0.3.6 → riplex-0.4.0}/src/riplex_app/main.py +0 -0
- {riplex-0.3.6 → riplex-0.4.0}/src/riplex_app/screens/__init__.py +0 -0
- {riplex-0.3.6 → riplex-0.4.0}/src/riplex_app/screens/disc_detection.py +0 -0
- {riplex-0.3.6 → riplex-0.4.0}/src/riplex_app/screens/done.py +0 -0
- {riplex-0.3.6 → riplex-0.4.0}/src/riplex_app/screens/metadata.py +0 -0
- {riplex-0.3.6 → riplex-0.4.0}/src/riplex_app/screens/organize_done.py +0 -0
- {riplex-0.3.6 → riplex-0.4.0}/src/riplex_app/screens/organize_preview.py +0 -0
- {riplex-0.3.6 → riplex-0.4.0}/src/riplex_app/screens/progress.py +0 -0
- {riplex-0.3.6 → riplex-0.4.0}/src/riplex_app/screens/release.py +0 -0
- {riplex-0.3.6 → riplex-0.4.0}/src/riplex_app/screens/selection.py +0 -0
- {riplex-0.3.6 → riplex-0.4.0}/src/riplex_cli/__init__.py +0 -0
- {riplex-0.3.6 → riplex-0.4.0}/src/riplex_cli/commands/__init__.py +0 -0
- {riplex-0.3.6 → riplex-0.4.0}/src/riplex_cli/commands/lookup.py +0 -0
- {riplex-0.3.6 → riplex-0.4.0}/src/riplex_cli/commands/orchestrate.py +0 -0
- {riplex-0.3.6 → riplex-0.4.0}/src/riplex_cli/commands/organize.py +0 -0
- {riplex-0.3.6 → riplex-0.4.0}/src/riplex_cli/commands/rip.py +0 -0
- {riplex-0.3.6 → riplex-0.4.0}/src/riplex_cli/formatting.py +0 -0
- {riplex-0.3.6 → riplex-0.4.0}/src/riplex_cli/main.py +0 -0
- {riplex-0.3.6 → riplex-0.4.0}/tests/__init__.py +0 -0
- {riplex-0.3.6 → riplex-0.4.0}/tests/fixtures/makemkvcon_frozen_planet_ii_d2.txt +0 -0
- {riplex-0.3.6 → riplex-0.4.0}/tests/fixtures/makemkvcon_list.txt +0 -0
- {riplex-0.3.6 → riplex-0.4.0}/tests/snapshots/Batman Begins.snapshot.json +0 -0
- {riplex-0.3.6 → riplex-0.4.0}/tests/snapshots/Blade Runner (Blu-ray 4k).snapshot.json +0 -0
- {riplex-0.3.6 → riplex-0.4.0}/tests/snapshots/Blade Runner The Final Cut.snapshot.json +0 -0
- {riplex-0.3.6 → riplex-0.4.0}/tests/snapshots/Seven Worlds One Planet.snapshot.json +0 -0
- {riplex-0.3.6 → riplex-0.4.0}/tests/snapshots/The Dark Knight Rises.snapshot.json +0 -0
- {riplex-0.3.6 → riplex-0.4.0}/tests/snapshots/The Dark Knight.snapshot.json +0 -0
- {riplex-0.3.6 → riplex-0.4.0}/tests/snapshots/Waterworld.snapshot.json +0 -0
- {riplex-0.3.6 → riplex-0.4.0}/tests/test_cache.py +0 -0
- {riplex-0.3.6 → riplex-0.4.0}/tests/test_cli_utils.py +0 -0
- {riplex-0.3.6 → riplex-0.4.0}/tests/test_config.py +0 -0
- {riplex-0.3.6 → riplex-0.4.0}/tests/test_dedup.py +0 -0
- {riplex-0.3.6 → riplex-0.4.0}/tests/test_detect.py +0 -0
- {riplex-0.3.6 → riplex-0.4.0}/tests/test_disc_analysis.py +0 -0
- {riplex-0.3.6 → riplex-0.4.0}/tests/test_disc_provider.py +0 -0
- {riplex-0.3.6 → riplex-0.4.0}/tests/test_formatter.py +0 -0
- {riplex-0.3.6 → riplex-0.4.0}/tests/test_makemkv.py +0 -0
- {riplex-0.3.6 → riplex-0.4.0}/tests/test_matcher.py +0 -0
- {riplex-0.3.6 → riplex-0.4.0}/tests/test_normalize.py +0 -0
- {riplex-0.3.6 → riplex-0.4.0}/tests/test_organizer.py +0 -0
- {riplex-0.3.6 → riplex-0.4.0}/tests/test_planner.py +0 -0
- {riplex-0.3.6 → riplex-0.4.0}/tests/test_rip_guide.py +0 -0
- {riplex-0.3.6 → riplex-0.4.0}/tests/test_snapshot.py +0 -0
- {riplex-0.3.6 → riplex-0.4.0}/tests/test_ui.py +0 -0
|
@@ -0,0 +1,69 @@
|
|
|
1
|
+
# Copilot Instructions for riplex
|
|
2
|
+
|
|
3
|
+
## Documentation changelog
|
|
4
|
+
|
|
5
|
+
When any file under `docs/` is added, modified, or removed, update `docs/changelog.md` with a dated entry describing the change. Follow the [Keep a Changelog](https://keepachangelog.com/) format with sections like Added, Changed, Removed, or Fixed under a date heading.
|
|
6
|
+
|
|
7
|
+
## Installing from source
|
|
8
|
+
|
|
9
|
+
First-time setup — create a virtualenv and install in editable mode:
|
|
10
|
+
```
|
|
11
|
+
python3.12 -m venv .venv
|
|
12
|
+
source .venv/bin/activate # macOS/Linux
|
|
13
|
+
.venv\Scripts\activate # Windows
|
|
14
|
+
pip install -e ".[dev,gui]"
|
|
15
|
+
```
|
|
16
|
+
|
|
17
|
+
The `.vscode/settings.json` in this repo points VS Code at `.venv` automatically,
|
|
18
|
+
so the integrated terminal activates it on open. In any external terminal, run
|
|
19
|
+
`source .venv/bin/activate` first.
|
|
20
|
+
|
|
21
|
+
If you already have a venv active, just install:
|
|
22
|
+
```
|
|
23
|
+
pip install -e ".[dev]"
|
|
24
|
+
```
|
|
25
|
+
|
|
26
|
+
For the GUI, also include the gui extra:
|
|
27
|
+
```
|
|
28
|
+
pip install -e ".[dev,gui]"
|
|
29
|
+
```
|
|
30
|
+
|
|
31
|
+
### macOS extras (Homebrew Python only)
|
|
32
|
+
|
|
33
|
+
If you installed Python via Homebrew, two additional one-time steps are needed:
|
|
34
|
+
|
|
35
|
+
**1. SSL certificates** — Flet downloads its desktop runtime on first launch and will
|
|
36
|
+
fail with an SSL error without this fix:
|
|
37
|
+
```
|
|
38
|
+
CERT=$(python3.12 -c "import certifi; print(certifi.where())")
|
|
39
|
+
echo "export SSL_CERT_FILE=\"$CERT\"" >> .venv/bin/activate
|
|
40
|
+
echo "export REQUESTS_CA_BUNDLE=\"$CERT\"" >> .venv/bin/activate
|
|
41
|
+
source .venv/bin/activate
|
|
42
|
+
```
|
|
43
|
+
|
|
44
|
+
**2. Folder picker (tkinter)** — the browse buttons in the GUI require tkinter,
|
|
45
|
+
which Homebrew ships as a separate package:
|
|
46
|
+
```
|
|
47
|
+
brew install python-tk@3.12
|
|
48
|
+
```
|
|
49
|
+
Without this, the browse buttons show a hint telling the user to type the path
|
|
50
|
+
manually instead of crashing silently.
|
|
51
|
+
|
|
52
|
+
## Running
|
|
53
|
+
|
|
54
|
+
After installing from source, use the installed entry points:
|
|
55
|
+
```
|
|
56
|
+
riplex rip # CLI dry-run
|
|
57
|
+
riplex rip --execute # CLI actual rip
|
|
58
|
+
riplex-ui # Launch the Flet GUI
|
|
59
|
+
```
|
|
60
|
+
|
|
61
|
+
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
|
+
|
|
63
|
+
## Dry-run default
|
|
64
|
+
|
|
65
|
+
All destructive commands (`rip`, `organize`, `orchestrate`) are dry-run by default. There is no `--dry-run` flag. Use `--execute` to actually perform the operation.
|
|
66
|
+
|
|
67
|
+
## Testing
|
|
68
|
+
|
|
69
|
+
Run tests with `pytest` (or `python -m pytest`) from the project root with the venv active. All tests must pass before committing.
|
|
@@ -69,7 +69,15 @@ jobs:
|
|
|
69
69
|
path: release/
|
|
70
70
|
|
|
71
71
|
build-macos:
|
|
72
|
-
|
|
72
|
+
strategy:
|
|
73
|
+
fail-fast: false
|
|
74
|
+
matrix:
|
|
75
|
+
include:
|
|
76
|
+
- runner: macos-13
|
|
77
|
+
arch: x86_64
|
|
78
|
+
- runner: macos-14
|
|
79
|
+
arch: arm64
|
|
80
|
+
runs-on: ${{ matrix.runner }}
|
|
73
81
|
steps:
|
|
74
82
|
- uses: actions/checkout@v4
|
|
75
83
|
with:
|
|
@@ -116,12 +124,12 @@ jobs:
|
|
|
116
124
|
- name: Package macOS artifacts
|
|
117
125
|
run: |
|
|
118
126
|
mkdir -p release
|
|
119
|
-
cp dist/riplex release/
|
|
120
|
-
cd dist && zip -r ../release/riplex-ui-macos.zip riplex-ui.app
|
|
127
|
+
cp dist/riplex release/riplex-${{ matrix.arch }}
|
|
128
|
+
cd dist && zip -r ../release/riplex-ui-macos-${{ matrix.arch }}.zip riplex-ui.app
|
|
121
129
|
|
|
122
130
|
- uses: actions/upload-artifact@v4
|
|
123
131
|
with:
|
|
124
|
-
name: riplex-macos
|
|
132
|
+
name: riplex-macos-${{ matrix.arch }}
|
|
125
133
|
path: release/
|
|
126
134
|
|
|
127
135
|
release:
|
|
@@ -138,8 +146,10 @@ jobs:
|
|
|
138
146
|
mkdir release
|
|
139
147
|
cp artifacts/riplex-windows/riplex.exe release/riplex-windows.exe
|
|
140
148
|
cp artifacts/riplex-windows/riplex-ui.exe release/riplex-ui-windows.exe
|
|
141
|
-
cp artifacts/riplex-macos/riplex release/riplex-macos
|
|
142
|
-
cp artifacts/riplex-macos/riplex-ui-macos.zip release/
|
|
149
|
+
cp artifacts/riplex-macos-x86_64/riplex-x86_64 release/riplex-macos-x86_64
|
|
150
|
+
cp artifacts/riplex-macos-x86_64/riplex-ui-macos-x86_64.zip release/
|
|
151
|
+
cp artifacts/riplex-macos-arm64/riplex-arm64 release/riplex-macos-arm64
|
|
152
|
+
cp artifacts/riplex-macos-arm64/riplex-ui-macos-arm64.zip release/
|
|
143
153
|
|
|
144
154
|
- name: Create GitHub Release
|
|
145
155
|
uses: softprops/action-gh-release@v2
|
|
@@ -148,5 +158,7 @@ jobs:
|
|
|
148
158
|
files: |
|
|
149
159
|
release/riplex-windows.exe
|
|
150
160
|
release/riplex-ui-windows.exe
|
|
151
|
-
release/riplex-macos
|
|
152
|
-
release/riplex-ui-macos.zip
|
|
161
|
+
release/riplex-macos-x86_64
|
|
162
|
+
release/riplex-ui-macos-x86_64.zip
|
|
163
|
+
release/riplex-macos-arm64
|
|
164
|
+
release/riplex-ui-macos-arm64.zip
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: riplex
|
|
3
|
-
Version: 0.
|
|
3
|
+
Version: 0.4.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
|
|
@@ -26,7 +26,7 @@ Automates the tedious manual work around MakeMKV: figuring out what to rip, whic
|
|
|
26
26
|
If you'd rather use a simple graphical interface instead of the command line, download the pre-built app from the [Releases page](https://github.com/AnyCredit5518/riplex/releases/latest):
|
|
27
27
|
|
|
28
28
|
- **Windows**: Download `riplex-ui-windows.exe` and double-click to run
|
|
29
|
-
- **macOS**: Download `riplex-ui-macos.zip
|
|
29
|
+
- **macOS**: Download `riplex-ui-macos-arm64.zip` (Apple Silicon) or `riplex-ui-macos-x86_64.zip` (Intel), unzip, and open `riplex-ui.app`
|
|
30
30
|
|
|
31
31
|
No Python install required. The app walks you through setup and provides buttons for all workflows.
|
|
32
32
|
|
|
@@ -7,7 +7,7 @@ Automates the tedious manual work around MakeMKV: figuring out what to rip, whic
|
|
|
7
7
|
If you'd rather use a simple graphical interface instead of the command line, download the pre-built app from the [Releases page](https://github.com/AnyCredit5518/riplex/releases/latest):
|
|
8
8
|
|
|
9
9
|
- **Windows**: Download `riplex-ui-windows.exe` and double-click to run
|
|
10
|
-
- **macOS**: Download `riplex-ui-macos.zip
|
|
10
|
+
- **macOS**: Download `riplex-ui-macos-arm64.zip` (Apple Silicon) or `riplex-ui-macos-x86_64.zip` (Intel), unzip, and open `riplex-ui.app`
|
|
11
11
|
|
|
12
12
|
No Python install required. The app walks you through setup and provides buttons for all workflows.
|
|
13
13
|
|
|
@@ -6,9 +6,23 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/).
|
|
|
6
6
|
|
|
7
7
|
## 2026-05-03
|
|
8
8
|
|
|
9
|
+
### Changed
|
|
10
|
+
|
|
11
|
+
- Installation guide: macOS pre-built executables now ship as separate `arm64` (Apple Silicon) and `x86_64` (Intel) builds; added instructions to pick the right one and remove the Gatekeeper quarantine flag.
|
|
12
|
+
- Installation guide: "Installing from source" section now includes venv setup steps and a macOS SSL fix for Homebrew Python users (`SSL_CERT_FILE` via certifi).
|
|
13
|
+
- Installation guide: added macOS tkinter section for folder picker support.
|
|
14
|
+
|
|
9
15
|
### Added
|
|
10
16
|
|
|
11
17
|
- New troubleshooting guide (`docs/troubleshooting.md`) covering: makemkvcon not on PATH (Flatpak issue), drive not detected, invalid config file, TMDb API key signup, and dvdcompare lookup failures
|
|
18
|
+
- `find_ffprobe()` helper: all ffprobe consumers now check `~/.riplex/bin/`, `/usr/local/bin/`, and `/opt/homebrew/bin/` in addition to PATH.
|
|
19
|
+
- macOS auto-download: "Install Missing Tools" on macOS < 14 auto-downloads ffprobe from evermeet.cx to `~/.riplex/bin/`; opens download pages for MakeMKV and MKVToolNix.
|
|
20
|
+
- macOS .app bundle detection: `find_makemkvcon()` checks `/Applications/MakeMKV.app/`; `find_mkvmerge()` and `find_mkvpropedit()` check `/Applications/MKVToolNix.app/`.
|
|
21
|
+
- Dual-arch macOS CI builds (`macos-13`/x86_64 and `macos-14`/arm64) in release workflow.
|
|
22
|
+
- Arch-aware macOS update checker in GUI updater.
|
|
23
|
+
- Install progress bar and streaming output for Homebrew installs on macOS 14+.
|
|
24
|
+
- Graceful tkinter fallback in folder picker and welcome screen browse buttons.
|
|
25
|
+
- Linux apt support in GUI tool installer.
|
|
12
26
|
|
|
13
27
|
## 2026-05-02
|
|
14
28
|
|
|
@@ -14,7 +14,8 @@ Download the latest release for your platform from the [GitHub Releases page](ht
|
|
|
14
14
|
| Platform | CLI | GUI |
|
|
15
15
|
|---|---|---|
|
|
16
16
|
| Windows | `riplex-windows.exe` | `riplex-ui-windows.exe` |
|
|
17
|
-
| macOS | `riplex-macos` | `riplex-ui-macos.zip` |
|
|
17
|
+
| macOS (Apple Silicon) | `riplex-macos-arm64` | `riplex-ui-macos-arm64.zip` |
|
|
18
|
+
| macOS (Intel) | `riplex-macos-x86_64` | `riplex-ui-macos-x86_64.zip` |
|
|
18
19
|
|
|
19
20
|
### Windows
|
|
20
21
|
|
|
@@ -24,10 +25,18 @@ Download the latest release for your platform from the [GitHub Releases page](ht
|
|
|
24
25
|
|
|
25
26
|
### macOS
|
|
26
27
|
|
|
27
|
-
1.
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
28
|
+
1. Pick the build matching your Mac:
|
|
29
|
+
- Apple Silicon (M1/M2/M3/...): `riplex-macos-arm64` and `riplex-ui-macos-arm64.zip`
|
|
30
|
+
- Intel: `riplex-macos-x86_64` and `riplex-ui-macos-x86_64.zip`
|
|
31
|
+
|
|
32
|
+
Not sure which you have? Run `sysctl -n machdep.cpu.brand_string` in Terminal.
|
|
33
|
+
"Apple ..." means Apple Silicon; "Intel ..." means Intel.
|
|
34
|
+
2. Make the CLI executable: `chmod +x riplex-macos-*`
|
|
35
|
+
3. For the GUI, unzip the `.zip` and move `riplex-ui.app` to `/Applications/`.
|
|
36
|
+
The first time you launch it, macOS may block the unsigned app — remove the
|
|
37
|
+
quarantine flag with `xattr -dr com.apple.quarantine /Applications/riplex-ui.app`
|
|
38
|
+
and try again.
|
|
39
|
+
4. Run `./riplex-macos-arm64 setup` (or the `x86_64` variant) to configure.
|
|
31
40
|
|
|
32
41
|
## Option B: Install via pip
|
|
33
42
|
|
|
@@ -103,21 +112,43 @@ If you want to contribute or run the latest unreleased code:
|
|
|
103
112
|
```bash
|
|
104
113
|
git clone https://github.com/AnyCredit5518/riplex.git
|
|
105
114
|
cd riplex
|
|
106
|
-
|
|
115
|
+
python3.12 -m venv .venv
|
|
116
|
+
source .venv/bin/activate # macOS/Linux
|
|
117
|
+
pip install -e ".[dev,gui]"
|
|
107
118
|
```
|
|
108
119
|
|
|
109
|
-
|
|
120
|
+
The repo's `.vscode/settings.json` points VS Code at `.venv` automatically, so
|
|
121
|
+
the integrated terminal activates it on open. In any external terminal, run
|
|
122
|
+
`source .venv/bin/activate` first.
|
|
123
|
+
|
|
124
|
+
Then launch the GUI with:
|
|
110
125
|
|
|
111
126
|
```bash
|
|
112
|
-
|
|
127
|
+
riplex-ui
|
|
113
128
|
```
|
|
114
129
|
|
|
115
|
-
|
|
130
|
+
### macOS SSL fix (Homebrew Python only)
|
|
131
|
+
|
|
132
|
+
If you installed Python via Homebrew and `riplex-ui` crashes on first launch with
|
|
133
|
+
an SSL certificate error, run this one-time fix:
|
|
116
134
|
|
|
117
135
|
```bash
|
|
118
|
-
|
|
136
|
+
CERT=$(python3.12 -c "import certifi; print(certifi.where())")
|
|
137
|
+
echo "export SSL_CERT_FILE=\"$CERT\"" >> .venv/bin/activate
|
|
138
|
+
echo "export REQUESTS_CA_BUNDLE=\"$CERT\"" >> .venv/bin/activate
|
|
139
|
+
source .venv/bin/activate
|
|
119
140
|
```
|
|
120
141
|
|
|
142
|
+
### macOS folder picker (Homebrew Python only)
|
|
143
|
+
|
|
144
|
+
The browse buttons in the GUI use tkinter, which Homebrew ships separately:
|
|
145
|
+
|
|
146
|
+
```bash
|
|
147
|
+
brew install python-tk@3.12
|
|
148
|
+
```
|
|
149
|
+
|
|
150
|
+
Without this, clicking a browse button shows a hint to type the path manually instead.
|
|
151
|
+
|
|
121
152
|
## External tools
|
|
122
153
|
|
|
123
154
|
riplex uses these tools under the hood. The setup wizard handles installation, but if you prefer to install manually:
|
|
@@ -23,6 +23,12 @@ dev = [
|
|
|
23
23
|
]
|
|
24
24
|
gui = [
|
|
25
25
|
"flet>=0.84",
|
|
26
|
+
# tkinter is also required for the folder picker buttons but cannot be
|
|
27
|
+
# installed via pip — it is part of Python's standard library and must be
|
|
28
|
+
# installed at the OS level:
|
|
29
|
+
# macOS (Homebrew Python): brew install python-tk@3.12
|
|
30
|
+
# Linux (Debian/Ubuntu): sudo apt install python3-tk
|
|
31
|
+
# Windows: included in the standard python.org installer
|
|
26
32
|
]
|
|
27
33
|
|
|
28
34
|
[project.scripts]
|
|
@@ -19,8 +19,11 @@ _SUBPROCESS_FLAGS: dict = (
|
|
|
19
19
|
|
|
20
20
|
log = logging.getLogger(__name__)
|
|
21
21
|
|
|
22
|
-
#
|
|
22
|
+
# Common install paths where makemkvcon lives outside of PATH
|
|
23
23
|
_MAKEMKVCON_SEARCH_PATHS = [
|
|
24
|
+
# macOS .app bundle
|
|
25
|
+
Path("/Applications/MakeMKV.app/Contents/MacOS/makemkvcon"),
|
|
26
|
+
# Windows
|
|
24
27
|
Path(r"C:\Program Files\MakeMKV\makemkvcon64.exe"),
|
|
25
28
|
Path(r"C:\Program Files (x86)\MakeMKV\makemkvcon64.exe"),
|
|
26
29
|
Path(r"C:\Program Files\MakeMKV\makemkvcon.exe"),
|
|
@@ -649,9 +652,9 @@ def probe_chapter_durations(mkv_path: str | Path) -> list[int]:
|
|
|
649
652
|
Returns a list of chapter durations in seconds. Returns empty list
|
|
650
653
|
if ffprobe is unavailable or the file has no chapters.
|
|
651
654
|
"""
|
|
652
|
-
import
|
|
655
|
+
from riplex.scanner import find_ffprobe
|
|
653
656
|
|
|
654
|
-
ffprobe =
|
|
657
|
+
ffprobe = find_ffprobe()
|
|
655
658
|
if not ffprobe:
|
|
656
659
|
log.debug("ffprobe not found, skipping chapter duration extraction")
|
|
657
660
|
return []
|
|
@@ -5,6 +5,7 @@ from __future__ import annotations
|
|
|
5
5
|
import json
|
|
6
6
|
import logging
|
|
7
7
|
import platform
|
|
8
|
+
import shutil
|
|
8
9
|
import subprocess
|
|
9
10
|
from pathlib import Path
|
|
10
11
|
from typing import Callable
|
|
@@ -21,6 +22,28 @@ _SUBPROCESS_FLAGS: dict = (
|
|
|
21
22
|
else {}
|
|
22
23
|
)
|
|
23
24
|
|
|
25
|
+
# Common install locations for ffprobe outside of PATH
|
|
26
|
+
_FFPROBE_SEARCH_PATHS = [
|
|
27
|
+
Path.home() / ".riplex" / "bin" / "ffprobe",
|
|
28
|
+
Path("/usr/local/bin/ffprobe"),
|
|
29
|
+
Path("/opt/homebrew/bin/ffprobe"),
|
|
30
|
+
]
|
|
31
|
+
|
|
32
|
+
|
|
33
|
+
def find_ffprobe() -> str | None:
|
|
34
|
+
"""Locate the ffprobe executable.
|
|
35
|
+
|
|
36
|
+
Checks PATH first, then ``~/.riplex/bin/``, ``/usr/local/bin/``,
|
|
37
|
+
and ``/opt/homebrew/bin/``. Returns the path string or *None*.
|
|
38
|
+
"""
|
|
39
|
+
path = shutil.which("ffprobe")
|
|
40
|
+
if path:
|
|
41
|
+
return path
|
|
42
|
+
for candidate in _FFPROBE_SEARCH_PATHS:
|
|
43
|
+
if candidate.is_file():
|
|
44
|
+
return str(candidate)
|
|
45
|
+
return None
|
|
46
|
+
|
|
24
47
|
|
|
25
48
|
def _probe_file(path: Path) -> ScannedFile:
|
|
26
49
|
"""Extract metadata from a single MKV file using ffprobe.
|
|
@@ -37,10 +60,14 @@ def _probe_file(path: Path) -> ScannedFile:
|
|
|
37
60
|
except OSError:
|
|
38
61
|
size_bytes = 0
|
|
39
62
|
|
|
63
|
+
ffprobe = find_ffprobe()
|
|
64
|
+
if not ffprobe:
|
|
65
|
+
return ScannedFile(name=name, path=abs_path, size_bytes=size_bytes)
|
|
66
|
+
|
|
40
67
|
try:
|
|
41
68
|
result = subprocess.run(
|
|
42
69
|
[
|
|
43
|
-
|
|
70
|
+
ffprobe,
|
|
44
71
|
"-v", "quiet",
|
|
45
72
|
"-print_format", "json",
|
|
46
73
|
"-show_entries",
|
|
@@ -163,14 +190,8 @@ def scan_folder(
|
|
|
163
190
|
raise FileNotFoundError(f"Not a directory: {folder}")
|
|
164
191
|
|
|
165
192
|
# Check for ffprobe availability
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
["ffprobe", "-version"],
|
|
169
|
-
capture_output=True,
|
|
170
|
-
timeout=5,
|
|
171
|
-
**_SUBPROCESS_FLAGS,
|
|
172
|
-
)
|
|
173
|
-
except FileNotFoundError:
|
|
193
|
+
ffprobe = find_ffprobe()
|
|
194
|
+
if not ffprobe:
|
|
174
195
|
raise RuntimeError(
|
|
175
196
|
"ffprobe not found. Install FFmpeg to enable MKV duration scanning."
|
|
176
197
|
)
|
|
@@ -41,6 +41,7 @@ def find_mkvmerge() -> str | None:
|
|
|
41
41
|
if path:
|
|
42
42
|
return path
|
|
43
43
|
for candidate in [
|
|
44
|
+
"/Applications/MKVToolNix.app/Contents/MacOS/mkvmerge",
|
|
44
45
|
r"C:\Program Files\MKVToolNix\mkvmerge.exe",
|
|
45
46
|
r"C:\Program Files (x86)\MKVToolNix\mkvmerge.exe",
|
|
46
47
|
]:
|
|
@@ -51,9 +52,15 @@ def find_mkvmerge() -> str | None:
|
|
|
51
52
|
|
|
52
53
|
def get_chapters(file_path: str) -> list[Chapter]:
|
|
53
54
|
"""Extract chapter information from an MKV file using ffprobe."""
|
|
55
|
+
from riplex.scanner import find_ffprobe
|
|
56
|
+
|
|
57
|
+
ffprobe = find_ffprobe()
|
|
58
|
+
if not ffprobe:
|
|
59
|
+
return []
|
|
60
|
+
|
|
54
61
|
result = subprocess.run(
|
|
55
62
|
[
|
|
56
|
-
|
|
63
|
+
ffprobe, "-v", "quiet",
|
|
57
64
|
"-print_format", "json",
|
|
58
65
|
"-show_chapters",
|
|
59
66
|
file_path,
|
|
@@ -36,6 +36,7 @@ def find_mkvpropedit() -> str | None:
|
|
|
36
36
|
if path:
|
|
37
37
|
return path
|
|
38
38
|
for candidate in [
|
|
39
|
+
"/Applications/MKVToolNix.app/Contents/MacOS/mkvpropedit",
|
|
39
40
|
r"C:\Program Files\MKVToolNix\mkvpropedit.exe",
|
|
40
41
|
r"C:\Program Files (x86)\MKVToolNix\mkvpropedit.exe",
|
|
41
42
|
]:
|
|
@@ -113,6 +114,7 @@ def read_organized_tag(file_path: str) -> str | None:
|
|
|
113
114
|
mkvmerge = shutil.which("mkvmerge")
|
|
114
115
|
if mkvmerge is None:
|
|
115
116
|
for candidate in [
|
|
117
|
+
"/Applications/MKVToolNix.app/Contents/MacOS/mkvmerge",
|
|
116
118
|
r"C:\Program Files\MKVToolNix\mkvmerge.exe",
|
|
117
119
|
r"C:\Program Files (x86)\MKVToolNix\mkvmerge.exe",
|
|
118
120
|
]:
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: riplex
|
|
3
|
-
Version: 0.
|
|
3
|
+
Version: 0.4.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
|
|
@@ -26,7 +26,7 @@ Automates the tedious manual work around MakeMKV: figuring out what to rip, whic
|
|
|
26
26
|
If you'd rather use a simple graphical interface instead of the command line, download the pre-built app from the [Releases page](https://github.com/AnyCredit5518/riplex/releases/latest):
|
|
27
27
|
|
|
28
28
|
- **Windows**: Download `riplex-ui-windows.exe` and double-click to run
|
|
29
|
-
- **macOS**: Download `riplex-ui-macos.zip
|
|
29
|
+
- **macOS**: Download `riplex-ui-macos-arm64.zip` (Apple Silicon) or `riplex-ui-macos-x86_64.zip` (Intel), unzip, and open `riplex-ui.app`
|
|
30
30
|
|
|
31
31
|
No Python install required. The app walks you through setup and provides buttons for all workflows.
|
|
32
32
|
|
|
@@ -85,8 +85,14 @@ class FolderPickerScreen:
|
|
|
85
85
|
log.debug("_browse clicked")
|
|
86
86
|
|
|
87
87
|
def _pick():
|
|
88
|
-
|
|
89
|
-
|
|
88
|
+
try:
|
|
89
|
+
import tkinter as tk
|
|
90
|
+
from tkinter import filedialog
|
|
91
|
+
except ModuleNotFoundError:
|
|
92
|
+
log.warning("tkinter not available; user must type path manually")
|
|
93
|
+
self.folder_field.hint_text = "Type the path manually (brew install python-tk@3.12 to enable folder picker)"
|
|
94
|
+
self.app.page.update()
|
|
95
|
+
return
|
|
90
96
|
|
|
91
97
|
try:
|
|
92
98
|
root = tk.Tk()
|