kryten-webqueue 0.2.8__tar.gz → 0.3.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.
- {kryten_webqueue-0.2.8 → kryten_webqueue-0.3.0}/PKG-INFO +1 -1
- {kryten_webqueue-0.2.8 → kryten_webqueue-0.3.0}/kryten_webqueue/app.py +10 -9
- {kryten_webqueue-0.2.8 → kryten_webqueue-0.3.0}/kryten_webqueue/catalog/db.py +2 -2
- {kryten_webqueue-0.2.8 → kryten_webqueue-0.3.0}/kryten_webqueue/catalog/sync.py +9 -1
- {kryten_webqueue-0.2.8 → kryten_webqueue-0.3.0}/kryten_webqueue/templates/catalog/browse.html +3 -0
- {kryten_webqueue-0.2.8 → kryten_webqueue-0.3.0}/pyproject.toml +1 -1
- {kryten_webqueue-0.2.8 → kryten_webqueue-0.3.0}/.github/workflows/python-publish.yml +0 -0
- {kryten_webqueue-0.2.8 → kryten_webqueue-0.3.0}/.github/workflows/release.yml +0 -0
- {kryten_webqueue-0.2.8 → kryten_webqueue-0.3.0}/.gitignore +0 -0
- {kryten_webqueue-0.2.8 → kryten_webqueue-0.3.0}/README.md +0 -0
- {kryten_webqueue-0.2.8 → kryten_webqueue-0.3.0}/config.example.json +0 -0
- {kryten_webqueue-0.2.8 → kryten_webqueue-0.3.0}/deploy/kryten-webqueue.service +0 -0
- {kryten_webqueue-0.2.8 → kryten_webqueue-0.3.0}/deploy/nginx-queue.conf +0 -0
- {kryten_webqueue-0.2.8 → kryten_webqueue-0.3.0}/docs/IMPLEMENTATION_SPEC.md +0 -0
- {kryten_webqueue-0.2.8 → kryten_webqueue-0.3.0}/docs/IMPL_API_GATE.md +0 -0
- {kryten_webqueue-0.2.8 → kryten_webqueue-0.3.0}/docs/IMPL_ECONOMY.md +0 -0
- {kryten_webqueue-0.2.8 → kryten_webqueue-0.3.0}/docs/IMPL_KRYTEN_PY.md +0 -0
- {kryten_webqueue-0.2.8 → kryten_webqueue-0.3.0}/docs/IMPL_ROBOT.md +0 -0
- {kryten_webqueue-0.2.8 → kryten_webqueue-0.3.0}/docs/PRE_PLAN_GAPS.md +0 -0
- {kryten_webqueue-0.2.8 → kryten_webqueue-0.3.0}/docs/PRODUCT_PLAN.md +0 -0
- {kryten_webqueue-0.2.8 → kryten_webqueue-0.3.0}/kryten_webqueue/__init__.py +0 -0
- {kryten_webqueue-0.2.8 → kryten_webqueue-0.3.0}/kryten_webqueue/__main__.py +0 -0
- {kryten_webqueue-0.2.8 → kryten_webqueue-0.3.0}/kryten_webqueue/api_gate/__init__.py +0 -0
- {kryten_webqueue-0.2.8 → kryten_webqueue-0.3.0}/kryten_webqueue/api_gate/client.py +0 -0
- {kryten_webqueue-0.2.8 → kryten_webqueue-0.3.0}/kryten_webqueue/auth/__init__.py +0 -0
- {kryten_webqueue-0.2.8 → kryten_webqueue-0.3.0}/kryten_webqueue/auth/otp.py +0 -0
- {kryten_webqueue-0.2.8 → kryten_webqueue-0.3.0}/kryten_webqueue/auth/rate_limit.py +0 -0
- {kryten_webqueue-0.2.8 → kryten_webqueue-0.3.0}/kryten_webqueue/auth/session.py +0 -0
- {kryten_webqueue-0.2.8 → kryten_webqueue-0.3.0}/kryten_webqueue/catalog/__init__.py +0 -0
- {kryten_webqueue-0.2.8 → kryten_webqueue-0.3.0}/kryten_webqueue/catalog/images.py +0 -0
- {kryten_webqueue-0.2.8 → kryten_webqueue-0.3.0}/kryten_webqueue/config.py +0 -0
- {kryten_webqueue-0.2.8 → kryten_webqueue-0.3.0}/kryten_webqueue/playlists/__init__.py +0 -0
- {kryten_webqueue-0.2.8 → kryten_webqueue-0.3.0}/kryten_webqueue/playlists/fire.py +0 -0
- {kryten_webqueue-0.2.8 → kryten_webqueue-0.3.0}/kryten_webqueue/playlists/importer.py +0 -0
- {kryten_webqueue-0.2.8 → kryten_webqueue-0.3.0}/kryten_webqueue/playlists/scheduler.py +0 -0
- {kryten_webqueue-0.2.8 → kryten_webqueue-0.3.0}/kryten_webqueue/queue/__init__.py +0 -0
- {kryten_webqueue-0.2.8 → kryten_webqueue-0.3.0}/kryten_webqueue/queue/ordering.py +0 -0
- {kryten_webqueue-0.2.8 → kryten_webqueue-0.3.0}/kryten_webqueue/queue/poller.py +0 -0
- {kryten_webqueue-0.2.8 → kryten_webqueue-0.3.0}/kryten_webqueue/queue/shadow.py +0 -0
- {kryten_webqueue-0.2.8 → kryten_webqueue-0.3.0}/kryten_webqueue/routes/__init__.py +0 -0
- {kryten_webqueue-0.2.8 → kryten_webqueue-0.3.0}/kryten_webqueue/routes/admin_playlists.py +0 -0
- {kryten_webqueue-0.2.8 → kryten_webqueue-0.3.0}/kryten_webqueue/routes/admin_queue.py +0 -0
- {kryten_webqueue-0.2.8 → kryten_webqueue-0.3.0}/kryten_webqueue/routes/admin_schedules.py +0 -0
- {kryten_webqueue-0.2.8 → kryten_webqueue-0.3.0}/kryten_webqueue/routes/auth.py +0 -0
- {kryten_webqueue-0.2.8 → kryten_webqueue-0.3.0}/kryten_webqueue/routes/catalog.py +0 -0
- {kryten_webqueue-0.2.8 → kryten_webqueue-0.3.0}/kryten_webqueue/routes/pages.py +0 -0
- {kryten_webqueue-0.2.8 → kryten_webqueue-0.3.0}/kryten_webqueue/routes/queue.py +0 -0
- {kryten_webqueue-0.2.8 → kryten_webqueue-0.3.0}/kryten_webqueue/routes/user.py +0 -0
- {kryten_webqueue-0.2.8 → kryten_webqueue-0.3.0}/kryten_webqueue/static/css/main.css +0 -0
- {kryten_webqueue-0.2.8 → kryten_webqueue-0.3.0}/kryten_webqueue/static/js/main.js +0 -0
- {kryten_webqueue-0.2.8 → kryten_webqueue-0.3.0}/kryten_webqueue/templates/admin/index.html +0 -0
- {kryten_webqueue-0.2.8 → kryten_webqueue-0.3.0}/kryten_webqueue/templates/auth/login.html +0 -0
- {kryten_webqueue-0.2.8 → kryten_webqueue-0.3.0}/kryten_webqueue/templates/base.html +0 -0
- {kryten_webqueue-0.2.8 → kryten_webqueue-0.3.0}/kryten_webqueue/templates/queue/index.html +0 -0
- {kryten_webqueue-0.2.8 → kryten_webqueue-0.3.0}/kryten_webqueue/templates/user/dashboard.html +0 -0
- {kryten_webqueue-0.2.8 → kryten_webqueue-0.3.0}/kryten_webqueue/ws/__init__.py +0 -0
- {kryten_webqueue-0.2.8 → kryten_webqueue-0.3.0}/kryten_webqueue/ws/handler.py +0 -0
- {kryten_webqueue-0.2.8 → kryten_webqueue-0.3.0}/kryten_webqueue/ws/manager.py +0 -0
|
@@ -45,15 +45,7 @@ async def lifespan(app: FastAPI):
|
|
|
45
45
|
api_gate = ApiGateClient(config.api_gate_url, config.api_gate_token)
|
|
46
46
|
app.state.api_gate = api_gate
|
|
47
47
|
|
|
48
|
-
#
|
|
49
|
-
catalog_sync = CatalogSync(
|
|
50
|
-
mediacms_url=config.mediacms_url,
|
|
51
|
-
mediacms_token=config.mediacms_token,
|
|
52
|
-
db=db,
|
|
53
|
-
)
|
|
54
|
-
app.state.catalog_sync = catalog_sync
|
|
55
|
-
|
|
56
|
-
# Cover art resolver
|
|
48
|
+
# Cover art resolver (created before sync so it can be passed in)
|
|
57
49
|
cover_art = CoverArtResolver(
|
|
58
50
|
image_dir=config.image_dir,
|
|
59
51
|
placeholder_dir=config.placeholder_dir,
|
|
@@ -62,6 +54,15 @@ async def lifespan(app: FastAPI):
|
|
|
62
54
|
)
|
|
63
55
|
app.state.cover_art = cover_art
|
|
64
56
|
|
|
57
|
+
# Catalog sync
|
|
58
|
+
catalog_sync = CatalogSync(
|
|
59
|
+
mediacms_url=config.mediacms_url,
|
|
60
|
+
mediacms_token=config.mediacms_token,
|
|
61
|
+
db=db,
|
|
62
|
+
cover_art=cover_art,
|
|
63
|
+
)
|
|
64
|
+
app.state.catalog_sync = catalog_sync
|
|
65
|
+
|
|
65
66
|
# WebSocket manager
|
|
66
67
|
ws_manager = WebSocketManager()
|
|
67
68
|
app.state.ws_manager = ws_manager
|
|
@@ -220,7 +220,7 @@ class Database:
|
|
|
220
220
|
|
|
221
221
|
async def browse(self, *, category: str | None = None, page: int = 1, per_page: int = 24) -> list[dict]:
|
|
222
222
|
query = """
|
|
223
|
-
SELECT c.friendly_token, c.title, c.duration_sec, c.cover_art_path, c.manifest_url
|
|
223
|
+
SELECT c.friendly_token, c.title, c.duration_sec, c.cover_art_path, c.thumbnail_url, c.manifest_url
|
|
224
224
|
FROM catalog c
|
|
225
225
|
WHERE c.friendly_token NOT IN (
|
|
226
226
|
SELECT spi.media_id FROM saved_playlist_items spi
|
|
@@ -244,7 +244,7 @@ class Database:
|
|
|
244
244
|
|
|
245
245
|
async def search(self, query_text: str, *, page: int = 1, per_page: int = 24) -> list[dict]:
|
|
246
246
|
sql = """
|
|
247
|
-
SELECT c.friendly_token, c.title, c.duration_sec, c.cover_art_path, c.manifest_url,
|
|
247
|
+
SELECT c.friendly_token, c.title, c.duration_sec, c.cover_art_path, c.thumbnail_url, c.manifest_url,
|
|
248
248
|
rank AS relevance
|
|
249
249
|
FROM catalog_fts fts
|
|
250
250
|
JOIN catalog c ON c.rowid = fts.rowid
|
|
@@ -28,7 +28,7 @@ def _describe_httpx_error(exc: Exception, url: str) -> str:
|
|
|
28
28
|
class CatalogSync:
|
|
29
29
|
"""Synchronizes catalog data from MediaCMS."""
|
|
30
30
|
|
|
31
|
-
def __init__(self, *, mediacms_url: str, mediacms_token: str, db):
|
|
31
|
+
def __init__(self, *, mediacms_url: str, mediacms_token: str, db, cover_art=None):
|
|
32
32
|
# Strip any accidental /api/v1 suffix — the sync code appends it itself
|
|
33
33
|
url = mediacms_url.rstrip("/")
|
|
34
34
|
for suffix in ("/api/v1", "/api"):
|
|
@@ -38,6 +38,7 @@ class CatalogSync:
|
|
|
38
38
|
self._url = url
|
|
39
39
|
self._token = mediacms_token
|
|
40
40
|
self._db = db
|
|
41
|
+
self._cover_art = cover_art
|
|
41
42
|
self._client = httpx.AsyncClient(
|
|
42
43
|
headers={"Authorization": f"Token {mediacms_token}"},
|
|
43
44
|
timeout=30.0,
|
|
@@ -127,6 +128,13 @@ class CatalogSync:
|
|
|
127
128
|
await self._db.insert_catalog(row)
|
|
128
129
|
stats["new"] += 1
|
|
129
130
|
|
|
131
|
+
# Fetch TMDB/OMDB cover art if not already cached
|
|
132
|
+
if self._cover_art and not (existing and existing.get("cover_art_path")):
|
|
133
|
+
try:
|
|
134
|
+
await self._cover_art.resolve(token, row["title"], self._db)
|
|
135
|
+
except Exception as e:
|
|
136
|
+
logger.debug(f"Cover art resolve failed for {token}: {e}")
|
|
137
|
+
|
|
130
138
|
def _build_manifest_url(self, media: dict) -> str:
|
|
131
139
|
# Use the MediaCMS watch page URL (e.g. https://www.dropsugar.co/view?m=TOKEN)
|
|
132
140
|
url = media.get("url", "")
|
{kryten_webqueue-0.2.8 → kryten_webqueue-0.3.0}/kryten_webqueue/templates/catalog/browse.html
RENAMED
|
@@ -32,6 +32,9 @@
|
|
|
32
32
|
/static/images/{{ item.cover_art_path }}/800.webp 800w"
|
|
33
33
|
sizes="(max-width: 600px) 200px, 400px"
|
|
34
34
|
alt="{{ item.title }}" loading="lazy">
|
|
35
|
+
{% elif item.thumbnail_url %}
|
|
36
|
+
<img src="{{ item.thumbnail_url }}"
|
|
37
|
+
alt="{{ item.title }}" loading="lazy">
|
|
35
38
|
{% else %}
|
|
36
39
|
<div class="card-poster-placeholder">
|
|
37
40
|
<span>{{ item.title[:1] }}</span>
|
|
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
|
{kryten_webqueue-0.2.8 → kryten_webqueue-0.3.0}/kryten_webqueue/templates/user/dashboard.html
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|