riplex 0.9.2__tar.gz → 0.9.4__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.9.2 → riplex-0.9.4}/.github/workflows/release.yml +19 -7
- {riplex-0.9.2/src/riplex.egg-info → riplex-0.9.4}/PKG-INFO +2 -2
- {riplex-0.9.2 → riplex-0.9.4}/pyproject.toml +11 -5
- {riplex-0.9.2 → riplex-0.9.4}/src/riplex/scanner.py +31 -2
- {riplex-0.9.2 → riplex-0.9.4/src/riplex.egg-info}/PKG-INFO +2 -2
- {riplex-0.9.2 → riplex-0.9.4}/src/riplex.egg-info/requires.txt +1 -1
- riplex-0.9.4/src/riplex.egg-info/scm_version.json +8 -0
- {riplex-0.9.2 → riplex-0.9.4}/tests/test_scanner.py +60 -1
- riplex-0.9.2/src/riplex.egg-info/scm_version.json +0 -8
- {riplex-0.9.2 → riplex-0.9.4}/.github/ISSUE_TEMPLATE/bug_report.yml +0 -0
- {riplex-0.9.2 → riplex-0.9.4}/.github/ISSUE_TEMPLATE/crash_report.yml +0 -0
- {riplex-0.9.2 → riplex-0.9.4}/.github/agents/riplex.agent.md +0 -0
- {riplex-0.9.2 → riplex-0.9.4}/.github/copilot-instructions.md +0 -0
- {riplex-0.9.2 → riplex-0.9.4}/.github/workflows/publish.yml +0 -0
- {riplex-0.9.2 → riplex-0.9.4}/.gitignore +0 -0
- {riplex-0.9.2 → riplex-0.9.4}/.vscode/settings.json +0 -0
- {riplex-0.9.2 → riplex-0.9.4}/CONTRIBUTORS.md +0 -0
- {riplex-0.9.2 → riplex-0.9.4}/LICENSE +0 -0
- {riplex-0.9.2 → riplex-0.9.4}/README.md +0 -0
- {riplex-0.9.2 → riplex-0.9.4}/docs/architecture.md +0 -0
- {riplex-0.9.2 → riplex-0.9.4}/docs/changelog.md +0 -0
- {riplex-0.9.2 → riplex-0.9.4}/docs/cli-guide/lookup.md +0 -0
- {riplex-0.9.2 → riplex-0.9.4}/docs/cli-guide/orchestrate.md +0 -0
- {riplex-0.9.2 → riplex-0.9.4}/docs/cli-guide/organize.md +0 -0
- {riplex-0.9.2 → riplex-0.9.4}/docs/cli-guide/workflow.md +0 -0
- {riplex-0.9.2 → riplex-0.9.4}/docs/getting-started/configuration.md +0 -0
- {riplex-0.9.2 → riplex-0.9.4}/docs/getting-started/installation.md +0 -0
- {riplex-0.9.2 → riplex-0.9.4}/docs/gui-guide/gui-walkthrough.md +0 -0
- {riplex-0.9.2 → riplex-0.9.4}/docs/index.md +0 -0
- {riplex-0.9.2 → riplex-0.9.4}/docs/naming-rules.md +0 -0
- {riplex-0.9.2 → riplex-0.9.4}/docs/reference/cli.md +0 -0
- {riplex-0.9.2 → riplex-0.9.4}/docs/troubleshooting.md +0 -0
- {riplex-0.9.2 → riplex-0.9.4}/issues/debug-artifacts-consolidation.md +0 -0
- {riplex-0.9.2 → riplex-0.9.4}/issues/manual-rip-and-organize-escape-hatch.md +0 -0
- {riplex-0.9.2 → riplex-0.9.4}/issues/orchestrate-dvdcompare-fallback.md +0 -0
- {riplex-0.9.2 → riplex-0.9.4}/issues/planned-features.md +0 -0
- {riplex-0.9.2 → riplex-0.9.4}/mkdocs.yml +0 -0
- {riplex-0.9.2 → riplex-0.9.4}/screenshots/0_Rip_Flow_BTTF.gif +0 -0
- {riplex-0.9.2 → riplex-0.9.4}/screenshots/1_Welcome_Screen.png +0 -0
- {riplex-0.9.2 → riplex-0.9.4}/screenshots/2_Disc_Detection_BTTF.png +0 -0
- {riplex-0.9.2 → riplex-0.9.4}/screenshots/3_Metadata_Lookup_BTTF.png +0 -0
- {riplex-0.9.2 → riplex-0.9.4}/screenshots/4_Disc_Release_BTTF.png +0 -0
- {riplex-0.9.2 → riplex-0.9.4}/screenshots/5_Multi_Disc_Overview_BTTF.png +0 -0
- {riplex-0.9.2 → riplex-0.9.4}/screenshots/5_Select_Title_to_RIP_BTTF.png +0 -0
- {riplex-0.9.2 → riplex-0.9.4}/setup.cfg +0 -0
- {riplex-0.9.2 → riplex-0.9.4}/src/riplex/__init__.py +0 -0
- {riplex-0.9.2 → riplex-0.9.4}/src/riplex/cache.py +0 -0
- {riplex-0.9.2 → riplex-0.9.4}/src/riplex/config.py +0 -0
- {riplex-0.9.2 → riplex-0.9.4}/src/riplex/dedup.py +0 -0
- {riplex-0.9.2 → riplex-0.9.4}/src/riplex/detect.py +0 -0
- {riplex-0.9.2 → riplex-0.9.4}/src/riplex/disc/__init__.py +0 -0
- {riplex-0.9.2 → riplex-0.9.4}/src/riplex/disc/analysis.py +0 -0
- {riplex-0.9.2 → riplex-0.9.4}/src/riplex/disc/makemkv.py +0 -0
- {riplex-0.9.2 → riplex-0.9.4}/src/riplex/disc/provider.py +0 -0
- {riplex-0.9.2 → riplex-0.9.4}/src/riplex/formatter.py +0 -0
- {riplex-0.9.2 → riplex-0.9.4}/src/riplex/lookup.py +0 -0
- {riplex-0.9.2 → riplex-0.9.4}/src/riplex/manifest.py +0 -0
- {riplex-0.9.2 → riplex-0.9.4}/src/riplex/matcher.py +0 -0
- {riplex-0.9.2 → riplex-0.9.4}/src/riplex/metadata/__init__.py +0 -0
- {riplex-0.9.2 → riplex-0.9.4}/src/riplex/metadata/planner.py +0 -0
- {riplex-0.9.2 → riplex-0.9.4}/src/riplex/metadata/provider.py +0 -0
- {riplex-0.9.2 → riplex-0.9.4}/src/riplex/metadata/sources/__init__.py +0 -0
- {riplex-0.9.2 → riplex-0.9.4}/src/riplex/metadata/sources/tmdb.py +0 -0
- {riplex-0.9.2 → riplex-0.9.4}/src/riplex/models.py +0 -0
- {riplex-0.9.2 → riplex-0.9.4}/src/riplex/normalize.py +0 -0
- {riplex-0.9.2 → riplex-0.9.4}/src/riplex/organizer.py +0 -0
- {riplex-0.9.2 → riplex-0.9.4}/src/riplex/snapshot.py +0 -0
- {riplex-0.9.2 → riplex-0.9.4}/src/riplex/splitter.py +0 -0
- {riplex-0.9.2 → riplex-0.9.4}/src/riplex/tagger.py +0 -0
- {riplex-0.9.2 → riplex-0.9.4}/src/riplex/title.py +0 -0
- {riplex-0.9.2 → riplex-0.9.4}/src/riplex/ui.py +0 -0
- {riplex-0.9.2 → riplex-0.9.4}/src/riplex/updater.py +0 -0
- {riplex-0.9.2 → riplex-0.9.4}/src/riplex.egg-info/SOURCES.txt +0 -0
- {riplex-0.9.2 → riplex-0.9.4}/src/riplex.egg-info/dependency_links.txt +0 -0
- {riplex-0.9.2 → riplex-0.9.4}/src/riplex.egg-info/entry_points.txt +0 -0
- {riplex-0.9.2 → riplex-0.9.4}/src/riplex.egg-info/scm_file_list.json +0 -0
- {riplex-0.9.2 → riplex-0.9.4}/src/riplex.egg-info/top_level.txt +0 -0
- {riplex-0.9.2 → riplex-0.9.4}/src/riplex_app/__init__.py +0 -0
- {riplex-0.9.2 → riplex-0.9.4}/src/riplex_app/bug_report.py +0 -0
- {riplex-0.9.2 → riplex-0.9.4}/src/riplex_app/crash_dump.py +0 -0
- {riplex-0.9.2 → riplex-0.9.4}/src/riplex_app/keep_awake.py +0 -0
- {riplex-0.9.2 → riplex-0.9.4}/src/riplex_app/main.py +0 -0
- {riplex-0.9.2 → riplex-0.9.4}/src/riplex_app/screens/__init__.py +0 -0
- {riplex-0.9.2 → riplex-0.9.4}/src/riplex_app/screens/disc_detection.py +0 -0
- {riplex-0.9.2 → riplex-0.9.4}/src/riplex_app/screens/disc_overview.py +0 -0
- {riplex-0.9.2 → riplex-0.9.4}/src/riplex_app/screens/disc_swap.py +0 -0
- {riplex-0.9.2 → riplex-0.9.4}/src/riplex_app/screens/done.py +0 -0
- {riplex-0.9.2 → riplex-0.9.4}/src/riplex_app/screens/folder_picker.py +0 -0
- {riplex-0.9.2 → riplex-0.9.4}/src/riplex_app/screens/metadata.py +0 -0
- {riplex-0.9.2 → riplex-0.9.4}/src/riplex_app/screens/orchestrate_done.py +0 -0
- {riplex-0.9.2 → riplex-0.9.4}/src/riplex_app/screens/organize_done.py +0 -0
- {riplex-0.9.2 → riplex-0.9.4}/src/riplex_app/screens/organize_preview.py +0 -0
- {riplex-0.9.2 → riplex-0.9.4}/src/riplex_app/screens/progress.py +0 -0
- {riplex-0.9.2 → riplex-0.9.4}/src/riplex_app/screens/release.py +0 -0
- {riplex-0.9.2 → riplex-0.9.4}/src/riplex_app/screens/selection.py +0 -0
- {riplex-0.9.2 → riplex-0.9.4}/src/riplex_app/screens/update.py +0 -0
- {riplex-0.9.2 → riplex-0.9.4}/src/riplex_app/screens/welcome.py +0 -0
- {riplex-0.9.2 → riplex-0.9.4}/src/riplex_cli/__init__.py +0 -0
- {riplex-0.9.2 → riplex-0.9.4}/src/riplex_cli/commands/__init__.py +0 -0
- {riplex-0.9.2 → riplex-0.9.4}/src/riplex_cli/commands/lookup.py +0 -0
- {riplex-0.9.2 → riplex-0.9.4}/src/riplex_cli/commands/orchestrate.py +0 -0
- {riplex-0.9.2 → riplex-0.9.4}/src/riplex_cli/commands/organize.py +0 -0
- {riplex-0.9.2 → riplex-0.9.4}/src/riplex_cli/commands/rip.py +0 -0
- {riplex-0.9.2 → riplex-0.9.4}/src/riplex_cli/commands/setup.py +0 -0
- {riplex-0.9.2 → riplex-0.9.4}/src/riplex_cli/formatting.py +0 -0
- {riplex-0.9.2 → riplex-0.9.4}/src/riplex_cli/main.py +0 -0
- {riplex-0.9.2 → riplex-0.9.4}/tests/__init__.py +0 -0
- {riplex-0.9.2 → riplex-0.9.4}/tests/fixtures/chernobyl_disc1.json +0 -0
- {riplex-0.9.2 → riplex-0.9.4}/tests/fixtures/makemkvcon_frozen_planet_ii_d2.txt +0 -0
- {riplex-0.9.2 → riplex-0.9.4}/tests/fixtures/makemkvcon_list.txt +0 -0
- {riplex-0.9.2 → riplex-0.9.4}/tests/snapshots/Batman Begins.snapshot.json +0 -0
- {riplex-0.9.2 → riplex-0.9.4}/tests/snapshots/Blade Runner (Blu-ray 4k).snapshot.json +0 -0
- {riplex-0.9.2 → riplex-0.9.4}/tests/snapshots/Blade Runner The Final Cut.snapshot.json +0 -0
- {riplex-0.9.2 → riplex-0.9.4}/tests/snapshots/Seven Worlds One Planet.snapshot.json +0 -0
- {riplex-0.9.2 → riplex-0.9.4}/tests/snapshots/The Dark Knight Rises.snapshot.json +0 -0
- {riplex-0.9.2 → riplex-0.9.4}/tests/snapshots/The Dark Knight.snapshot.json +0 -0
- {riplex-0.9.2 → riplex-0.9.4}/tests/snapshots/Waterworld.snapshot.json +0 -0
- {riplex-0.9.2 → riplex-0.9.4}/tests/test_app_main.py +0 -0
- {riplex-0.9.2 → riplex-0.9.4}/tests/test_cache.py +0 -0
- {riplex-0.9.2 → riplex-0.9.4}/tests/test_cli_utils.py +0 -0
- {riplex-0.9.2 → riplex-0.9.4}/tests/test_config.py +0 -0
- {riplex-0.9.2 → riplex-0.9.4}/tests/test_dedup.py +0 -0
- {riplex-0.9.2 → riplex-0.9.4}/tests/test_detect.py +0 -0
- {riplex-0.9.2 → riplex-0.9.4}/tests/test_disc_analysis.py +0 -0
- {riplex-0.9.2 → riplex-0.9.4}/tests/test_disc_detection_screen.py +0 -0
- {riplex-0.9.2 → riplex-0.9.4}/tests/test_disc_fixtures.py +0 -0
- {riplex-0.9.2 → riplex-0.9.4}/tests/test_disc_provider.py +0 -0
- {riplex-0.9.2 → riplex-0.9.4}/tests/test_formatter.py +0 -0
- {riplex-0.9.2 → riplex-0.9.4}/tests/test_lookup.py +0 -0
- {riplex-0.9.2 → riplex-0.9.4}/tests/test_makemkv.py +0 -0
- {riplex-0.9.2 → riplex-0.9.4}/tests/test_matcher.py +0 -0
- {riplex-0.9.2 → riplex-0.9.4}/tests/test_normalize.py +0 -0
- {riplex-0.9.2 → riplex-0.9.4}/tests/test_organizer.py +0 -0
- {riplex-0.9.2 → riplex-0.9.4}/tests/test_planner.py +0 -0
- {riplex-0.9.2 → riplex-0.9.4}/tests/test_release_screen.py +0 -0
- {riplex-0.9.2 → riplex-0.9.4}/tests/test_rip_guide.py +0 -0
- {riplex-0.9.2 → riplex-0.9.4}/tests/test_snapshot.py +0 -0
- {riplex-0.9.2 → riplex-0.9.4}/tests/test_splitter.py +0 -0
- {riplex-0.9.2 → riplex-0.9.4}/tests/test_tagger.py +0 -0
- {riplex-0.9.2 → riplex-0.9.4}/tests/test_tmdb_provider.py +0 -0
- {riplex-0.9.2 → riplex-0.9.4}/tests/test_ui.py +0 -0
- {riplex-0.9.2 → riplex-0.9.4}/tests/test_updater.py +0 -0
- {riplex-0.9.2 → riplex-0.9.4}/tests/test_welcome_screen.py +0 -0
|
@@ -23,7 +23,10 @@ jobs:
|
|
|
23
23
|
- name: Install dependencies
|
|
24
24
|
run: |
|
|
25
25
|
pip install -e ".[gui]"
|
|
26
|
-
|
|
26
|
+
# Keep flet-desktop in lockstep with the flet pin in pyproject
|
|
27
|
+
# (==0.85.1). The 0.85.3 macOS runtime ships a malformed
|
|
28
|
+
# objective_c.framework that breaks codesign (see issue #21).
|
|
29
|
+
pip install "flet-desktop==0.85.1" pyinstaller
|
|
27
30
|
|
|
28
31
|
- name: Cache Flet desktop runtime
|
|
29
32
|
run: |
|
|
@@ -96,11 +99,18 @@ jobs:
|
|
|
96
99
|
- name: Install dependencies
|
|
97
100
|
run: |
|
|
98
101
|
pip install -e ".[gui]"
|
|
99
|
-
|
|
102
|
+
# Keep flet-desktop in lockstep with the flet pin in pyproject
|
|
103
|
+
# (==0.85.1). The 0.85.3 macOS runtime ships a malformed
|
|
104
|
+
# objective_c.framework that breaks codesign (see issue #21).
|
|
105
|
+
pip install "flet-desktop==0.85.1" pyinstaller
|
|
100
106
|
|
|
101
|
-
- name:
|
|
107
|
+
- name: Download Flet desktop runtime archive
|
|
102
108
|
run: |
|
|
103
|
-
|
|
109
|
+
set -e
|
|
110
|
+
FLET_VERSION="$(python -c 'import flet_desktop.version; print(flet_desktop.version.version)')"
|
|
111
|
+
FLET_CLIENT_ARCHIVE="$RUNNER_TEMP/flet-macos.tar.gz"
|
|
112
|
+
curl -L "https://github.com/flet-dev/flet/releases/download/v${FLET_VERSION}/flet-macos.tar.gz" -o "$FLET_CLIENT_ARCHIVE"
|
|
113
|
+
echo "FLET_CLIENT_ARCHIVE=$FLET_CLIENT_ARCHIVE" >> "$GITHUB_ENV"
|
|
104
114
|
|
|
105
115
|
- name: Build CLI executable
|
|
106
116
|
run: |
|
|
@@ -117,7 +127,6 @@ jobs:
|
|
|
117
127
|
|
|
118
128
|
- name: Build GUI app bundle
|
|
119
129
|
run: |
|
|
120
|
-
FLET_CLIENT_CACHE="$(python -c 'import flet_desktop; print(flet_desktop.ensure_client_cached())')"
|
|
121
130
|
pyinstaller --name riplex-ui --onedir --windowed \
|
|
122
131
|
--hidden-import riplex_app.screens.welcome \
|
|
123
132
|
--hidden-import riplex_app.screens.disc_detection \
|
|
@@ -138,14 +147,17 @@ jobs:
|
|
|
138
147
|
--collect-all flet_desktop \
|
|
139
148
|
--collect-data certifi \
|
|
140
149
|
--collect-data dvdcompare_scraper \
|
|
141
|
-
--add-data "$
|
|
150
|
+
--add-data "$FLET_CLIENT_ARCHIVE:flet_desktop/app" \
|
|
142
151
|
src/riplex_app/main.py
|
|
143
152
|
|
|
144
153
|
- name: Package macOS artifacts
|
|
145
154
|
run: |
|
|
146
155
|
mkdir -p release
|
|
147
156
|
cp dist/riplex release/riplex-macos
|
|
148
|
-
|
|
157
|
+
# -y preserves symlinks (including the .framework Versions/Current
|
|
158
|
+
# links). Without it, zip flattens those symlinks into duplicate
|
|
159
|
+
# files and the unpacked .app crashes on launch (issue #21).
|
|
160
|
+
cd dist && zip -r -y ../release/riplex-ui-macos.zip riplex-ui.app
|
|
149
161
|
|
|
150
162
|
- uses: actions/upload-artifact@v4
|
|
151
163
|
with:
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: riplex
|
|
3
|
-
Version: 0.9.
|
|
3
|
+
Version: 0.9.4
|
|
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
|
|
@@ -15,7 +15,7 @@ Requires-Dist: pytest>=8.0; extra == "dev"
|
|
|
15
15
|
Requires-Dist: pytest-asyncio>=0.23; extra == "dev"
|
|
16
16
|
Requires-Dist: respx>=0.21; extra == "dev"
|
|
17
17
|
Provides-Extra: gui
|
|
18
|
-
Requires-Dist: flet
|
|
18
|
+
Requires-Dist: flet==0.85.1; extra == "gui"
|
|
19
19
|
Dynamic: license-file
|
|
20
20
|
|
|
21
21
|
# riplex
|
|
@@ -23,13 +23,19 @@ dev = [
|
|
|
23
23
|
"respx>=0.21",
|
|
24
24
|
]
|
|
25
25
|
gui = [
|
|
26
|
-
# Pin to
|
|
26
|
+
# Pin Flet to an exact version. We've verified 0.84 and 0.85 both work
|
|
27
27
|
# with the GUI's current API usage (``ft.Border.all``,
|
|
28
28
|
# ``page.show_dialog``). An open upper bound risked picking up
|
|
29
|
-
# breaking renames silently (see issue #12)
|
|
30
|
-
#
|
|
31
|
-
#
|
|
32
|
-
|
|
29
|
+
# breaking renames silently (see issue #12).
|
|
30
|
+
#
|
|
31
|
+
# We pin to ``==0.85.1`` specifically because the prebuilt macOS desktop
|
|
32
|
+
# runtime that ships with 0.85.3 (``flet-desktop-full-0.85.3``, downloaded
|
|
33
|
+
# from Flet's CDN at build time) has a malformed nested
|
|
34
|
+
# ``objective_c.framework`` whose code signature newer macOS ``codesign``
|
|
35
|
+
# rejects. That broke the PyInstaller macOS build (release workflow) and
|
|
36
|
+
# produced a GUI bundle that crashes on launch (issue #21). Keep
|
|
37
|
+
# ``flet`` and ``flet-desktop`` in lockstep at this version.
|
|
38
|
+
"flet==0.85.1",
|
|
33
39
|
# tkinter is also required for the folder picker buttons but cannot be
|
|
34
40
|
# installed via pip — it is part of Python's standard library and must be
|
|
35
41
|
# installed at the OS level:
|
|
@@ -4,6 +4,7 @@ from __future__ import annotations
|
|
|
4
4
|
|
|
5
5
|
import json
|
|
6
6
|
import logging
|
|
7
|
+
import os
|
|
7
8
|
import platform
|
|
8
9
|
import shutil
|
|
9
10
|
import subprocess
|
|
@@ -30,16 +31,44 @@ _FFPROBE_SEARCH_PATHS = [
|
|
|
30
31
|
]
|
|
31
32
|
|
|
32
33
|
|
|
34
|
+
def _windows_ffprobe_candidates() -> list[Path]:
|
|
35
|
+
"""Return likely ``ffprobe.exe`` locations from winget and manual installs.
|
|
36
|
+
|
|
37
|
+
riplex installs FFmpeg via ``winget install Gyan.FFmpeg``, which is a
|
|
38
|
+
portable package: winget drops a shim under ``WinGet\\Links`` and unpacks
|
|
39
|
+
the payload under ``WinGet\\Packages\\Gyan.FFmpeg*\\...\\bin``. Neither is on
|
|
40
|
+
PATH in the current process right after install, so check them directly.
|
|
41
|
+
"""
|
|
42
|
+
candidates: list[Path] = []
|
|
43
|
+
local_appdata = os.environ.get("LOCALAPPDATA")
|
|
44
|
+
if local_appdata:
|
|
45
|
+
winget = Path(local_appdata) / "Microsoft" / "WinGet"
|
|
46
|
+
candidates.append(winget / "Links" / "ffprobe.exe")
|
|
47
|
+
packages = winget / "Packages"
|
|
48
|
+
if packages.is_dir():
|
|
49
|
+
candidates.extend(packages.glob("Gyan.FFmpeg*/**/bin/ffprobe.exe"))
|
|
50
|
+
# Common manual install spots
|
|
51
|
+
candidates.append(Path(r"C:\ffmpeg\bin\ffprobe.exe"))
|
|
52
|
+
candidates.append(Path(r"C:\Program Files\ffmpeg\bin\ffprobe.exe"))
|
|
53
|
+
return candidates
|
|
54
|
+
|
|
55
|
+
|
|
33
56
|
def find_ffprobe() -> str | None:
|
|
34
57
|
"""Locate the ffprobe executable.
|
|
35
58
|
|
|
36
59
|
Checks PATH first, then ``~/.riplex/bin/``, ``/usr/local/bin/``,
|
|
37
|
-
and ``/opt/homebrew/bin/``.
|
|
60
|
+
and ``/opt/homebrew/bin/``. On Windows, also checks the winget
|
|
61
|
+
portable install locations (the ``WinGet\\Links`` shim and the
|
|
62
|
+
``WinGet\\Packages\\Gyan.FFmpeg*`` payload) and common manual install
|
|
63
|
+
folders. Returns the path string or *None*.
|
|
38
64
|
"""
|
|
39
65
|
path = shutil.which("ffprobe")
|
|
40
66
|
if path:
|
|
41
67
|
return path
|
|
42
|
-
|
|
68
|
+
candidates = list(_FFPROBE_SEARCH_PATHS)
|
|
69
|
+
if platform.system() == "Windows":
|
|
70
|
+
candidates.extend(_windows_ffprobe_candidates())
|
|
71
|
+
for candidate in candidates:
|
|
43
72
|
if candidate.is_file():
|
|
44
73
|
return str(candidate)
|
|
45
74
|
return None
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: riplex
|
|
3
|
-
Version: 0.9.
|
|
3
|
+
Version: 0.9.4
|
|
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
|
|
@@ -15,7 +15,7 @@ Requires-Dist: pytest>=8.0; extra == "dev"
|
|
|
15
15
|
Requires-Dist: pytest-asyncio>=0.23; extra == "dev"
|
|
16
16
|
Requires-Dist: respx>=0.21; extra == "dev"
|
|
17
17
|
Provides-Extra: gui
|
|
18
|
-
Requires-Dist: flet
|
|
18
|
+
Requires-Dist: flet==0.85.1; extra == "gui"
|
|
19
19
|
Dynamic: license-file
|
|
20
20
|
|
|
21
21
|
# riplex
|
|
@@ -6,7 +6,7 @@ from unittest.mock import patch
|
|
|
6
6
|
import pytest
|
|
7
7
|
|
|
8
8
|
from riplex.models import ScannedFile
|
|
9
|
-
from riplex.scanner import _probe_file, scan_folder
|
|
9
|
+
from riplex.scanner import _probe_file, find_ffprobe, scan_folder
|
|
10
10
|
|
|
11
11
|
|
|
12
12
|
@pytest.fixture
|
|
@@ -103,3 +103,62 @@ class TestScanFolder:
|
|
|
103
103
|
for disc in discs:
|
|
104
104
|
for f in disc.files:
|
|
105
105
|
assert Path(f.path).is_absolute()
|
|
106
|
+
|
|
107
|
+
|
|
108
|
+
class TestFindFfprobe:
|
|
109
|
+
def test_returns_path_when_on_path(self):
|
|
110
|
+
with patch("riplex.scanner.shutil.which", return_value="/usr/bin/ffprobe"):
|
|
111
|
+
assert find_ffprobe() == "/usr/bin/ffprobe"
|
|
112
|
+
|
|
113
|
+
def test_returns_none_when_not_found(self, monkeypatch):
|
|
114
|
+
monkeypatch.setattr("riplex.scanner.shutil.which", lambda _: None)
|
|
115
|
+
monkeypatch.setattr("riplex.scanner.platform.system", lambda: "Linux")
|
|
116
|
+
monkeypatch.setattr("riplex.scanner._FFPROBE_SEARCH_PATHS", [])
|
|
117
|
+
assert find_ffprobe() is None
|
|
118
|
+
|
|
119
|
+
def test_finds_winget_links_shim_on_windows(self, tmp_path, monkeypatch):
|
|
120
|
+
local_appdata = tmp_path / "AppData" / "Local"
|
|
121
|
+
links = local_appdata / "Microsoft" / "WinGet" / "Links"
|
|
122
|
+
links.mkdir(parents=True)
|
|
123
|
+
shim = links / "ffprobe.exe"
|
|
124
|
+
shim.write_text("", encoding="utf-8")
|
|
125
|
+
|
|
126
|
+
monkeypatch.setattr("riplex.scanner.shutil.which", lambda _: None)
|
|
127
|
+
monkeypatch.setattr("riplex.scanner.platform.system", lambda: "Windows")
|
|
128
|
+
monkeypatch.setattr("riplex.scanner._FFPROBE_SEARCH_PATHS", [])
|
|
129
|
+
monkeypatch.setenv("LOCALAPPDATA", str(local_appdata))
|
|
130
|
+
|
|
131
|
+
assert find_ffprobe() == str(shim)
|
|
132
|
+
|
|
133
|
+
def test_finds_winget_package_payload_on_windows(self, tmp_path, monkeypatch):
|
|
134
|
+
local_appdata = tmp_path / "AppData" / "Local"
|
|
135
|
+
bin_dir = (
|
|
136
|
+
local_appdata / "Microsoft" / "WinGet" / "Packages"
|
|
137
|
+
/ "Gyan.FFmpeg_Microsoft.Winget.Source_abc"
|
|
138
|
+
/ "ffmpeg-7.0-full_build" / "bin"
|
|
139
|
+
)
|
|
140
|
+
bin_dir.mkdir(parents=True)
|
|
141
|
+
exe = bin_dir / "ffprobe.exe"
|
|
142
|
+
exe.write_text("", encoding="utf-8")
|
|
143
|
+
|
|
144
|
+
monkeypatch.setattr("riplex.scanner.shutil.which", lambda _: None)
|
|
145
|
+
monkeypatch.setattr("riplex.scanner.platform.system", lambda: "Windows")
|
|
146
|
+
monkeypatch.setattr("riplex.scanner._FFPROBE_SEARCH_PATHS", [])
|
|
147
|
+
monkeypatch.setenv("LOCALAPPDATA", str(local_appdata))
|
|
148
|
+
|
|
149
|
+
assert find_ffprobe() == str(exe)
|
|
150
|
+
|
|
151
|
+
def test_windows_candidates_skipped_on_non_windows(self, monkeypatch):
|
|
152
|
+
monkeypatch.setattr("riplex.scanner.shutil.which", lambda _: None)
|
|
153
|
+
monkeypatch.setattr("riplex.scanner.platform.system", lambda: "Linux")
|
|
154
|
+
monkeypatch.setattr("riplex.scanner._FFPROBE_SEARCH_PATHS", [])
|
|
155
|
+
called = {"hit": False}
|
|
156
|
+
|
|
157
|
+
def _should_not_run():
|
|
158
|
+
called["hit"] = True
|
|
159
|
+
return []
|
|
160
|
+
|
|
161
|
+
monkeypatch.setattr("riplex.scanner._windows_ffprobe_candidates", _should_not_run)
|
|
162
|
+
assert find_ffprobe() is None
|
|
163
|
+
assert called["hit"] is False
|
|
164
|
+
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|