riplex 0.2.1__tar.gz → 0.2.2__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.2.1/src/riplex.egg-info → riplex-0.2.2}/PKG-INFO +1 -1
- {riplex-0.2.1 → riplex-0.2.2/src/riplex.egg-info}/PKG-INFO +1 -1
- {riplex-0.2.1 → riplex-0.2.2}/src/riplex.egg-info/SOURCES.txt +1 -0
- {riplex-0.2.1 → riplex-0.2.2}/src/riplex_app/main.py +4 -0
- {riplex-0.2.1 → riplex-0.2.2}/src/riplex_app/screens/welcome.py +52 -0
- riplex-0.2.2/src/riplex_app/updater.py +83 -0
- {riplex-0.2.1 → riplex-0.2.2}/.github/ISSUE_TEMPLATE/bug_report.yml +0 -0
- {riplex-0.2.1 → riplex-0.2.2}/.github/agents/riplex.agent.md +0 -0
- {riplex-0.2.1 → riplex-0.2.2}/.github/copilot-instructions.md +0 -0
- {riplex-0.2.1 → riplex-0.2.2}/.github/workflows/publish.yml +0 -0
- {riplex-0.2.1 → riplex-0.2.2}/.github/workflows/release.yml +0 -0
- {riplex-0.2.1 → riplex-0.2.2}/.gitignore +0 -0
- {riplex-0.2.1 → riplex-0.2.2}/MONOREPO_PLAN.md +0 -0
- {riplex-0.2.1 → riplex-0.2.2}/PLANNED_FEATURES.md +0 -0
- {riplex-0.2.1 → riplex-0.2.2}/README.md +0 -0
- {riplex-0.2.1 → riplex-0.2.2}/REFACTOR_PLAN.md +0 -0
- {riplex-0.2.1 → riplex-0.2.2}/docs/architecture.md +0 -0
- {riplex-0.2.1 → riplex-0.2.2}/docs/changelog.md +0 -0
- {riplex-0.2.1 → riplex-0.2.2}/docs/getting-started/configuration.md +0 -0
- {riplex-0.2.1 → riplex-0.2.2}/docs/getting-started/installation.md +0 -0
- {riplex-0.2.1 → riplex-0.2.2}/docs/guide/lookup.md +0 -0
- {riplex-0.2.1 → riplex-0.2.2}/docs/guide/orchestrate.md +0 -0
- {riplex-0.2.1 → riplex-0.2.2}/docs/guide/organize.md +0 -0
- {riplex-0.2.1 → riplex-0.2.2}/docs/guide/workflow.md +0 -0
- {riplex-0.2.1 → riplex-0.2.2}/docs/index.md +0 -0
- {riplex-0.2.1 → riplex-0.2.2}/docs/naming-rules.md +0 -0
- {riplex-0.2.1 → riplex-0.2.2}/docs/reference/cli.md +0 -0
- {riplex-0.2.1 → riplex-0.2.2}/issues/cross-disc-dvdcompare-matching.md +0 -0
- {riplex-0.2.1 → riplex-0.2.2}/mkdocs.yml +0 -0
- {riplex-0.2.1 → riplex-0.2.2}/plex_naming_rules.md +0 -0
- {riplex-0.2.1 → riplex-0.2.2}/pyproject.toml +0 -0
- {riplex-0.2.1 → riplex-0.2.2}/setup.cfg +0 -0
- {riplex-0.2.1 → riplex-0.2.2}/src/riplex/__init__.py +0 -0
- {riplex-0.2.1 → riplex-0.2.2}/src/riplex/cache.py +0 -0
- {riplex-0.2.1 → riplex-0.2.2}/src/riplex/config.py +0 -0
- {riplex-0.2.1 → riplex-0.2.2}/src/riplex/dedup.py +0 -0
- {riplex-0.2.1 → riplex-0.2.2}/src/riplex/detect.py +0 -0
- {riplex-0.2.1 → riplex-0.2.2}/src/riplex/disc/__init__.py +0 -0
- {riplex-0.2.1 → riplex-0.2.2}/src/riplex/disc/analysis.py +0 -0
- {riplex-0.2.1 → riplex-0.2.2}/src/riplex/disc/makemkv.py +0 -0
- {riplex-0.2.1 → riplex-0.2.2}/src/riplex/disc/provider.py +0 -0
- {riplex-0.2.1 → riplex-0.2.2}/src/riplex/formatter.py +0 -0
- {riplex-0.2.1 → riplex-0.2.2}/src/riplex/lookup.py +0 -0
- {riplex-0.2.1 → riplex-0.2.2}/src/riplex/manifest.py +0 -0
- {riplex-0.2.1 → riplex-0.2.2}/src/riplex/matcher.py +0 -0
- {riplex-0.2.1 → riplex-0.2.2}/src/riplex/metadata/__init__.py +0 -0
- {riplex-0.2.1 → riplex-0.2.2}/src/riplex/metadata/planner.py +0 -0
- {riplex-0.2.1 → riplex-0.2.2}/src/riplex/metadata/provider.py +0 -0
- {riplex-0.2.1 → riplex-0.2.2}/src/riplex/metadata/sources/__init__.py +0 -0
- {riplex-0.2.1 → riplex-0.2.2}/src/riplex/metadata/sources/tmdb.py +0 -0
- {riplex-0.2.1 → riplex-0.2.2}/src/riplex/models.py +0 -0
- {riplex-0.2.1 → riplex-0.2.2}/src/riplex/normalize.py +0 -0
- {riplex-0.2.1 → riplex-0.2.2}/src/riplex/organizer.py +0 -0
- {riplex-0.2.1 → riplex-0.2.2}/src/riplex/scanner.py +0 -0
- {riplex-0.2.1 → riplex-0.2.2}/src/riplex/snapshot.py +0 -0
- {riplex-0.2.1 → riplex-0.2.2}/src/riplex/splitter.py +0 -0
- {riplex-0.2.1 → riplex-0.2.2}/src/riplex/tagger.py +0 -0
- {riplex-0.2.1 → riplex-0.2.2}/src/riplex/title.py +0 -0
- {riplex-0.2.1 → riplex-0.2.2}/src/riplex/ui.py +0 -0
- {riplex-0.2.1 → riplex-0.2.2}/src/riplex.egg-info/dependency_links.txt +0 -0
- {riplex-0.2.1 → riplex-0.2.2}/src/riplex.egg-info/entry_points.txt +0 -0
- {riplex-0.2.1 → riplex-0.2.2}/src/riplex.egg-info/requires.txt +0 -0
- {riplex-0.2.1 → riplex-0.2.2}/src/riplex.egg-info/top_level.txt +0 -0
- {riplex-0.2.1 → riplex-0.2.2}/src/riplex_app/__init__.py +0 -0
- {riplex-0.2.1 → riplex-0.2.2}/src/riplex_app/screens/__init__.py +0 -0
- {riplex-0.2.1 → riplex-0.2.2}/src/riplex_app/screens/disc_detection.py +0 -0
- {riplex-0.2.1 → riplex-0.2.2}/src/riplex_app/screens/done.py +0 -0
- {riplex-0.2.1 → riplex-0.2.2}/src/riplex_app/screens/folder_picker.py +0 -0
- {riplex-0.2.1 → riplex-0.2.2}/src/riplex_app/screens/metadata.py +0 -0
- {riplex-0.2.1 → riplex-0.2.2}/src/riplex_app/screens/organize_done.py +0 -0
- {riplex-0.2.1 → riplex-0.2.2}/src/riplex_app/screens/organize_preview.py +0 -0
- {riplex-0.2.1 → riplex-0.2.2}/src/riplex_app/screens/progress.py +0 -0
- {riplex-0.2.1 → riplex-0.2.2}/src/riplex_app/screens/release.py +0 -0
- {riplex-0.2.1 → riplex-0.2.2}/src/riplex_app/screens/selection.py +0 -0
- {riplex-0.2.1 → riplex-0.2.2}/src/riplex_cli/__init__.py +0 -0
- {riplex-0.2.1 → riplex-0.2.2}/src/riplex_cli/commands/__init__.py +0 -0
- {riplex-0.2.1 → riplex-0.2.2}/src/riplex_cli/commands/lookup.py +0 -0
- {riplex-0.2.1 → riplex-0.2.2}/src/riplex_cli/commands/orchestrate.py +0 -0
- {riplex-0.2.1 → riplex-0.2.2}/src/riplex_cli/commands/organize.py +0 -0
- {riplex-0.2.1 → riplex-0.2.2}/src/riplex_cli/commands/rip.py +0 -0
- {riplex-0.2.1 → riplex-0.2.2}/src/riplex_cli/commands/setup.py +0 -0
- {riplex-0.2.1 → riplex-0.2.2}/src/riplex_cli/formatting.py +0 -0
- {riplex-0.2.1 → riplex-0.2.2}/src/riplex_cli/main.py +0 -0
- {riplex-0.2.1 → riplex-0.2.2}/tests/__init__.py +0 -0
- {riplex-0.2.1 → riplex-0.2.2}/tests/fixtures/makemkvcon_frozen_planet_ii_d2.txt +0 -0
- {riplex-0.2.1 → riplex-0.2.2}/tests/fixtures/makemkvcon_list.txt +0 -0
- {riplex-0.2.1 → riplex-0.2.2}/tests/snapshots/Batman Begins.snapshot.json +0 -0
- {riplex-0.2.1 → riplex-0.2.2}/tests/snapshots/Blade Runner (Blu-ray 4k).snapshot.json +0 -0
- {riplex-0.2.1 → riplex-0.2.2}/tests/snapshots/Blade Runner The Final Cut.snapshot.json +0 -0
- {riplex-0.2.1 → riplex-0.2.2}/tests/snapshots/Seven Worlds One Planet.snapshot.json +0 -0
- {riplex-0.2.1 → riplex-0.2.2}/tests/snapshots/The Dark Knight Rises.snapshot.json +0 -0
- {riplex-0.2.1 → riplex-0.2.2}/tests/snapshots/The Dark Knight.snapshot.json +0 -0
- {riplex-0.2.1 → riplex-0.2.2}/tests/snapshots/Waterworld.snapshot.json +0 -0
- {riplex-0.2.1 → riplex-0.2.2}/tests/test_cache.py +0 -0
- {riplex-0.2.1 → riplex-0.2.2}/tests/test_cli_utils.py +0 -0
- {riplex-0.2.1 → riplex-0.2.2}/tests/test_config.py +0 -0
- {riplex-0.2.1 → riplex-0.2.2}/tests/test_dedup.py +0 -0
- {riplex-0.2.1 → riplex-0.2.2}/tests/test_detect.py +0 -0
- {riplex-0.2.1 → riplex-0.2.2}/tests/test_disc_analysis.py +0 -0
- {riplex-0.2.1 → riplex-0.2.2}/tests/test_disc_provider.py +0 -0
- {riplex-0.2.1 → riplex-0.2.2}/tests/test_formatter.py +0 -0
- {riplex-0.2.1 → riplex-0.2.2}/tests/test_makemkv.py +0 -0
- {riplex-0.2.1 → riplex-0.2.2}/tests/test_matcher.py +0 -0
- {riplex-0.2.1 → riplex-0.2.2}/tests/test_normalize.py +0 -0
- {riplex-0.2.1 → riplex-0.2.2}/tests/test_organizer.py +0 -0
- {riplex-0.2.1 → riplex-0.2.2}/tests/test_planner.py +0 -0
- {riplex-0.2.1 → riplex-0.2.2}/tests/test_rip_guide.py +0 -0
- {riplex-0.2.1 → riplex-0.2.2}/tests/test_scanner.py +0 -0
- {riplex-0.2.1 → riplex-0.2.2}/tests/test_snapshot.py +0 -0
- {riplex-0.2.1 → riplex-0.2.2}/tests/test_splitter.py +0 -0
- {riplex-0.2.1 → riplex-0.2.2}/tests/test_tagger.py +0 -0
- {riplex-0.2.1 → riplex-0.2.2}/tests/test_ui.py +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: riplex
|
|
3
|
-
Version: 0.2.
|
|
3
|
+
Version: 0.2.2
|
|
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
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: riplex
|
|
3
|
-
Version: 0.2.
|
|
3
|
+
Version: 0.2.2
|
|
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
|
|
@@ -58,6 +58,7 @@ src/riplex/metadata/sources/__init__.py
|
|
|
58
58
|
src/riplex/metadata/sources/tmdb.py
|
|
59
59
|
src/riplex_app/__init__.py
|
|
60
60
|
src/riplex_app/main.py
|
|
61
|
+
src/riplex_app/updater.py
|
|
61
62
|
src/riplex_app/screens/__init__.py
|
|
62
63
|
src/riplex_app/screens/disc_detection.py
|
|
63
64
|
src/riplex_app/screens/done.py
|
|
@@ -2,11 +2,13 @@
|
|
|
2
2
|
|
|
3
3
|
import shutil
|
|
4
4
|
import threading
|
|
5
|
+
import webbrowser
|
|
5
6
|
|
|
6
7
|
import flet as ft
|
|
7
8
|
|
|
8
9
|
from riplex.config import load_config, get_api_key
|
|
9
10
|
from riplex.disc.makemkv import find_makemkvcon
|
|
11
|
+
from riplex_app.updater import check_for_update, get_current_version, get_download_url
|
|
10
12
|
|
|
11
13
|
|
|
12
14
|
class WelcomeScreen:
|
|
@@ -148,9 +150,32 @@ class WelcomeScreen:
|
|
|
148
150
|
tooltip="Organize existing MKV rips into Plex-compatible folder structure.",
|
|
149
151
|
)
|
|
150
152
|
|
|
153
|
+
# Update banner (hidden until check completes)
|
|
154
|
+
self.update_banner = ft.Container(
|
|
155
|
+
ft.Row(
|
|
156
|
+
[
|
|
157
|
+
ft.Icon(ft.Icons.SYSTEM_UPDATE, color=ft.Colors.BLUE),
|
|
158
|
+
ft.Text("", size=13, ref=None),
|
|
159
|
+
ft.TextButton("Download", on_click=self._open_update),
|
|
160
|
+
],
|
|
161
|
+
spacing=8,
|
|
162
|
+
),
|
|
163
|
+
bgcolor=ft.Colors.BLUE_50,
|
|
164
|
+
border_radius=8,
|
|
165
|
+
padding=ft.padding.symmetric(horizontal=12, vertical=8),
|
|
166
|
+
visible=False,
|
|
167
|
+
)
|
|
168
|
+
self._update_info = None
|
|
169
|
+
|
|
151
170
|
return ft.Column(
|
|
152
171
|
[
|
|
153
172
|
ft.Text("riplex", size=32, weight=ft.FontWeight.BOLD),
|
|
173
|
+
ft.Text(
|
|
174
|
+
f"v{get_current_version()}",
|
|
175
|
+
size=12,
|
|
176
|
+
color=ft.Colors.GREY_500,
|
|
177
|
+
),
|
|
178
|
+
self.update_banner,
|
|
154
179
|
ft.Text(
|
|
155
180
|
"Rip physical discs and organize into Plex-compatible libraries.",
|
|
156
181
|
size=14,
|
|
@@ -198,6 +223,33 @@ class WelcomeScreen:
|
|
|
198
223
|
|
|
199
224
|
threading.Thread(target=_pick, daemon=True).start()
|
|
200
225
|
|
|
226
|
+
def check_for_updates(self):
|
|
227
|
+
"""Run update check in background thread (call after page is available)."""
|
|
228
|
+
def _check():
|
|
229
|
+
info = check_for_update()
|
|
230
|
+
if info:
|
|
231
|
+
self._update_info = info
|
|
232
|
+
# Update UI from main thread
|
|
233
|
+
import asyncio
|
|
234
|
+
|
|
235
|
+
async def _show():
|
|
236
|
+
banner_row = self.update_banner.content
|
|
237
|
+
banner_row.controls[1] = ft.Text(
|
|
238
|
+
f"Update available: {info['tag']}", size=13
|
|
239
|
+
)
|
|
240
|
+
self.update_banner.visible = True
|
|
241
|
+
self.app.page.update()
|
|
242
|
+
|
|
243
|
+
self.app.page.run_task(_show)
|
|
244
|
+
|
|
245
|
+
threading.Thread(target=_check, daemon=True).start()
|
|
246
|
+
|
|
247
|
+
def _open_update(self, e):
|
|
248
|
+
"""Open the download URL in the user's browser."""
|
|
249
|
+
if self._update_info:
|
|
250
|
+
url = get_download_url(self._update_info)
|
|
251
|
+
webbrowser.open(url)
|
|
252
|
+
|
|
201
253
|
def _save_config(self, e):
|
|
202
254
|
"""Write config from the setup fields."""
|
|
203
255
|
from riplex.config import save_config
|
|
@@ -0,0 +1,83 @@
|
|
|
1
|
+
"""Check for newer releases on GitHub."""
|
|
2
|
+
|
|
3
|
+
import urllib.request
|
|
4
|
+
import json
|
|
5
|
+
import sys
|
|
6
|
+
from importlib.metadata import version, PackageNotFoundError
|
|
7
|
+
|
|
8
|
+
GITHUB_REPO = "AnyCredit5518/riplex"
|
|
9
|
+
RELEASES_URL = f"https://api.github.com/repos/{GITHUB_REPO}/releases/latest"
|
|
10
|
+
|
|
11
|
+
|
|
12
|
+
def get_current_version() -> str:
|
|
13
|
+
"""Return the installed package version, or 'dev' if not installed."""
|
|
14
|
+
try:
|
|
15
|
+
return version("riplex")
|
|
16
|
+
except PackageNotFoundError:
|
|
17
|
+
return "dev"
|
|
18
|
+
|
|
19
|
+
|
|
20
|
+
def _parse_version(tag: str) -> tuple:
|
|
21
|
+
"""Parse 'v1.2.3' into (1, 2, 3) for comparison."""
|
|
22
|
+
tag = tag.lstrip("v")
|
|
23
|
+
parts = []
|
|
24
|
+
for p in tag.split("."):
|
|
25
|
+
try:
|
|
26
|
+
parts.append(int(p))
|
|
27
|
+
except ValueError:
|
|
28
|
+
break
|
|
29
|
+
return tuple(parts)
|
|
30
|
+
|
|
31
|
+
|
|
32
|
+
def check_for_update() -> dict | None:
|
|
33
|
+
"""Check GitHub for a newer release.
|
|
34
|
+
|
|
35
|
+
Returns a dict with 'tag', 'url', and 'assets' if an update is available,
|
|
36
|
+
or None if already up to date (or on error).
|
|
37
|
+
"""
|
|
38
|
+
current = get_current_version()
|
|
39
|
+
if current == "dev":
|
|
40
|
+
return None
|
|
41
|
+
|
|
42
|
+
try:
|
|
43
|
+
req = urllib.request.Request(
|
|
44
|
+
RELEASES_URL,
|
|
45
|
+
headers={"Accept": "application/vnd.github+json", "User-Agent": "riplex"},
|
|
46
|
+
)
|
|
47
|
+
with urllib.request.urlopen(req, timeout=5) as resp:
|
|
48
|
+
data = json.loads(resp.read())
|
|
49
|
+
except Exception:
|
|
50
|
+
return None
|
|
51
|
+
|
|
52
|
+
latest_tag = data.get("tag_name", "")
|
|
53
|
+
if not latest_tag:
|
|
54
|
+
return None
|
|
55
|
+
|
|
56
|
+
if _parse_version(latest_tag) > _parse_version(current):
|
|
57
|
+
# Find the right asset for this platform
|
|
58
|
+
assets = {}
|
|
59
|
+
for asset in data.get("assets", []):
|
|
60
|
+
name = asset["name"].lower()
|
|
61
|
+
assets[name] = asset["browser_download_url"]
|
|
62
|
+
|
|
63
|
+
return {
|
|
64
|
+
"tag": latest_tag,
|
|
65
|
+
"url": data.get("html_url", ""),
|
|
66
|
+
"assets": assets,
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
return None
|
|
70
|
+
|
|
71
|
+
|
|
72
|
+
def get_download_url(update_info: dict) -> str:
|
|
73
|
+
"""Get the platform-appropriate download URL from update info."""
|
|
74
|
+
if sys.platform == "win32":
|
|
75
|
+
for name, url in update_info["assets"].items():
|
|
76
|
+
if "ui" in name and "windows" in name:
|
|
77
|
+
return url
|
|
78
|
+
elif sys.platform == "darwin":
|
|
79
|
+
for name, url in update_info["assets"].items():
|
|
80
|
+
if "ui" in name and "macos" in name:
|
|
81
|
+
return url
|
|
82
|
+
# Fallback to release page
|
|
83
|
+
return update_info["url"]
|
|
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
|