kryten-webqueue 0.35.7__tar.gz → 0.35.8__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.35.7 → kryten_webqueue-0.35.8}/CHANGELOG.md +20 -0
- {kryten_webqueue-0.35.7 → kryten_webqueue-0.35.8}/PKG-INFO +1 -1
- {kryten_webqueue-0.35.7 → kryten_webqueue-0.35.8}/kryten_webqueue/catalog/db/_catalog.py +38 -0
- {kryten_webqueue-0.35.7 → kryten_webqueue-0.35.8}/kryten_webqueue/catalog/enrichment/providers.py +49 -0
- {kryten_webqueue-0.35.7 → kryten_webqueue-0.35.8}/kryten_webqueue/catalog/enrichment/steps/art.py +14 -1
- {kryten_webqueue-0.35.7 → kryten_webqueue-0.35.8}/kryten_webqueue/catalog/sync.py +8 -1
- {kryten_webqueue-0.35.7 → kryten_webqueue-0.35.8}/pyproject.toml +1 -1
- {kryten_webqueue-0.35.7 → kryten_webqueue-0.35.8}/.github/workflows/gitleaks.yml +0 -0
- {kryten_webqueue-0.35.7 → kryten_webqueue-0.35.8}/.github/workflows/python-publish.yml +0 -0
- {kryten_webqueue-0.35.7 → kryten_webqueue-0.35.8}/.github/workflows/release.yml +0 -0
- {kryten_webqueue-0.35.7 → kryten_webqueue-0.35.8}/.gitignore +0 -0
- {kryten_webqueue-0.35.7 → kryten_webqueue-0.35.8}/.gitleaks.toml +0 -0
- {kryten_webqueue-0.35.7 → kryten_webqueue-0.35.8}/.pre-commit-config.yaml +0 -0
- {kryten_webqueue-0.35.7 → kryten_webqueue-0.35.8}/AGENT-WORKFLOW-GUIDE.md +0 -0
- {kryten_webqueue-0.35.7 → kryten_webqueue-0.35.8}/README.md +0 -0
- {kryten_webqueue-0.35.7 → kryten_webqueue-0.35.8}/config.example.json +0 -0
- {kryten_webqueue-0.35.7 → kryten_webqueue-0.35.8}/deploy/kryten-webqueue.service +0 -0
- {kryten_webqueue-0.35.7 → kryten_webqueue-0.35.8}/deploy/nginx-queue.conf +0 -0
- {kryten_webqueue-0.35.7 → kryten_webqueue-0.35.8}/docs/IMPLEMENTATION_SPEC.md +0 -0
- {kryten_webqueue-0.35.7 → kryten_webqueue-0.35.8}/docs/IMPL_API_GATE.md +0 -0
- {kryten_webqueue-0.35.7 → kryten_webqueue-0.35.8}/docs/IMPL_ECONOMY.md +0 -0
- {kryten_webqueue-0.35.7 → kryten_webqueue-0.35.8}/docs/IMPL_KRYTEN_PY.md +0 -0
- {kryten_webqueue-0.35.7 → kryten_webqueue-0.35.8}/docs/IMPL_ROBOT.md +0 -0
- {kryten_webqueue-0.35.7 → kryten_webqueue-0.35.8}/docs/Kryten-Economy Service Quality Survey Report at v0.13.0.md +0 -0
- {kryten_webqueue-0.35.7 → kryten_webqueue-0.35.8}/docs/Kryten-Webqueue Service Quality Survey Report at v0.27.1.md +0 -0
- {kryten_webqueue-0.35.7 → kryten_webqueue-0.35.8}/docs/Log for incorrect promo insertion problem.txt +0 -0
- {kryten_webqueue-0.35.7 → kryten_webqueue-0.35.8}/docs/PLAN_PRESENCE_AND_PROMOS.md +0 -0
- {kryten_webqueue-0.35.7 → kryten_webqueue-0.35.8}/docs/PRE_PLAN_GAPS.md +0 -0
- {kryten_webqueue-0.35.7 → kryten_webqueue-0.35.8}/docs/PRODUCT_PLAN.md +0 -0
- {kryten_webqueue-0.35.7 → kryten_webqueue-0.35.8}/docs/SPEC_CATALOG_ENRICHMENT_PIPELINE.md +0 -0
- {kryten_webqueue-0.35.7 → kryten_webqueue-0.35.8}/docs/SPEC_EMOTE_REHOST.md +0 -0
- {kryten_webqueue-0.35.7 → kryten_webqueue-0.35.8}/docs/SPEC_JOBS_AND_BROWSE.md +0 -0
- {kryten_webqueue-0.35.7 → kryten_webqueue-0.35.8}/docs/UX_POLISH_PLAN.md +0 -0
- {kryten_webqueue-0.35.7 → kryten_webqueue-0.35.8}/kryten_webqueue/__init__.py +0 -0
- {kryten_webqueue-0.35.7 → kryten_webqueue-0.35.8}/kryten_webqueue/__main__.py +0 -0
- {kryten_webqueue-0.35.7 → kryten_webqueue-0.35.8}/kryten_webqueue/api_gate/__init__.py +0 -0
- {kryten_webqueue-0.35.7 → kryten_webqueue-0.35.8}/kryten_webqueue/api_gate/client.py +0 -0
- {kryten_webqueue-0.35.7 → kryten_webqueue-0.35.8}/kryten_webqueue/app.py +0 -0
- {kryten_webqueue-0.35.7 → kryten_webqueue-0.35.8}/kryten_webqueue/auth/__init__.py +0 -0
- {kryten_webqueue-0.35.7 → kryten_webqueue-0.35.8}/kryten_webqueue/auth/otp.py +0 -0
- {kryten_webqueue-0.35.7 → kryten_webqueue-0.35.8}/kryten_webqueue/auth/rate_limit.py +0 -0
- {kryten_webqueue-0.35.7 → kryten_webqueue-0.35.8}/kryten_webqueue/auth/session.py +0 -0
- {kryten_webqueue-0.35.7 → kryten_webqueue-0.35.8}/kryten_webqueue/catalog/__init__.py +0 -0
- {kryten_webqueue-0.35.7 → kryten_webqueue-0.35.8}/kryten_webqueue/catalog/db/__init__.py +0 -0
- {kryten_webqueue-0.35.7 → kryten_webqueue-0.35.8}/kryten_webqueue/catalog/db/_connection.py +0 -0
- {kryten_webqueue-0.35.7 → kryten_webqueue-0.35.8}/kryten_webqueue/catalog/db/_enrichment.py +0 -0
- {kryten_webqueue-0.35.7 → kryten_webqueue-0.35.8}/kryten_webqueue/catalog/db/_feedback.py +0 -0
- {kryten_webqueue-0.35.7 → kryten_webqueue-0.35.8}/kryten_webqueue/catalog/db/_people.py +0 -0
- {kryten_webqueue-0.35.7 → kryten_webqueue-0.35.8}/kryten_webqueue/catalog/db/_playlists.py +0 -0
- {kryten_webqueue-0.35.7 → kryten_webqueue-0.35.8}/kryten_webqueue/catalog/db/_queue.py +0 -0
- {kryten_webqueue-0.35.7 → kryten_webqueue-0.35.8}/kryten_webqueue/catalog/db/_watchlist.py +0 -0
- {kryten_webqueue-0.35.7 → kryten_webqueue-0.35.8}/kryten_webqueue/catalog/enrichment/__init__.py +0 -0
- {kryten_webqueue-0.35.7 → kryten_webqueue-0.35.8}/kryten_webqueue/catalog/enrichment/classify.py +0 -0
- {kryten_webqueue-0.35.7 → kryten_webqueue-0.35.8}/kryten_webqueue/catalog/enrichment/normalise.py +0 -0
- {kryten_webqueue-0.35.7 → kryten_webqueue-0.35.8}/kryten_webqueue/catalog/enrichment/pipeline.py +0 -0
- {kryten_webqueue-0.35.7 → kryten_webqueue-0.35.8}/kryten_webqueue/catalog/enrichment/report.py +0 -0
- {kryten_webqueue-0.35.7 → kryten_webqueue-0.35.8}/kryten_webqueue/catalog/enrichment/steps/__init__.py +0 -0
- {kryten_webqueue-0.35.7 → kryten_webqueue-0.35.8}/kryten_webqueue/catalog/enrichment/steps/categories.py +0 -0
- {kryten_webqueue-0.35.7 → kryten_webqueue-0.35.8}/kryten_webqueue/catalog/enrichment/steps/meta.py +0 -0
- {kryten_webqueue-0.35.7 → kryten_webqueue-0.35.8}/kryten_webqueue/catalog/enrichment/steps/sync.py +0 -0
- {kryten_webqueue-0.35.7 → kryten_webqueue-0.35.8}/kryten_webqueue/catalog/enrichment/steps/tags.py +0 -0
- {kryten_webqueue-0.35.7 → kryten_webqueue-0.35.8}/kryten_webqueue/catalog/enrichment/steps/title.py +0 -0
- {kryten_webqueue-0.35.7 → kryten_webqueue-0.35.8}/kryten_webqueue/catalog/images.py +0 -0
- {kryten_webqueue-0.35.7 → kryten_webqueue-0.35.8}/kryten_webqueue/catalog/mediacms.py +0 -0
- {kryten_webqueue-0.35.7 → kryten_webqueue-0.35.8}/kryten_webqueue/config.py +0 -0
- {kryten_webqueue-0.35.7 → kryten_webqueue-0.35.8}/kryten_webqueue/integrations/__init__.py +0 -0
- {kryten_webqueue-0.35.7 → kryten_webqueue-0.35.8}/kryten_webqueue/integrations/cmsutils/__init__.py +0 -0
- {kryten_webqueue-0.35.7 → kryten_webqueue-0.35.8}/kryten_webqueue/integrations/cmsutils/_common.py +0 -0
- {kryten_webqueue-0.35.7 → kryten_webqueue-0.35.8}/kryten_webqueue/integrations/cmsutils/enrichmeta.py +0 -0
- {kryten_webqueue-0.35.7 → kryten_webqueue-0.35.8}/kryten_webqueue/integrations/cmsutils/enrichtitles.py +0 -0
- {kryten_webqueue-0.35.7 → kryten_webqueue-0.35.8}/kryten_webqueue/integrations/cmsutils/enrichtv.py +0 -0
- {kryten_webqueue-0.35.7 → kryten_webqueue-0.35.8}/kryten_webqueue/integrations/cmsutils/fetchurls.py +0 -0
- {kryten_webqueue-0.35.7 → kryten_webqueue-0.35.8}/kryten_webqueue/integrations/cmsutils/motdposters.py +0 -0
- {kryten_webqueue-0.35.7 → kryten_webqueue-0.35.8}/kryten_webqueue/integrations/cmsutils/playedmovies.py +0 -0
- {kryten_webqueue-0.35.7 → kryten_webqueue-0.35.8}/kryten_webqueue/integrations/ytpipe/__init__.py +0 -0
- {kryten_webqueue-0.35.7 → kryten_webqueue-0.35.8}/kryten_webqueue/integrations/ytpipe/downloader.py +0 -0
- {kryten_webqueue-0.35.7 → kryten_webqueue-0.35.8}/kryten_webqueue/jobs/__init__.py +0 -0
- {kryten_webqueue-0.35.7 → kryten_webqueue-0.35.8}/kryten_webqueue/jobs/fetchurls_auth.py +0 -0
- {kryten_webqueue-0.35.7 → kryten_webqueue-0.35.8}/kryten_webqueue/jobs/job_scheduler.py +0 -0
- {kryten_webqueue-0.35.7 → kryten_webqueue-0.35.8}/kryten_webqueue/jobs/manager.py +0 -0
- {kryten_webqueue-0.35.7 → kryten_webqueue-0.35.8}/kryten_webqueue/jobs/rehost_emotes.py +0 -0
- {kryten_webqueue-0.35.7 → kryten_webqueue-0.35.8}/kryten_webqueue/jobs/tasks.py +0 -0
- {kryten_webqueue-0.35.7 → kryten_webqueue-0.35.8}/kryten_webqueue/logging_config.py +0 -0
- {kryten_webqueue-0.35.7 → kryten_webqueue-0.35.8}/kryten_webqueue/playlists/__init__.py +0 -0
- {kryten_webqueue-0.35.7 → kryten_webqueue-0.35.8}/kryten_webqueue/playlists/bulk_add.py +0 -0
- {kryten_webqueue-0.35.7 → kryten_webqueue-0.35.8}/kryten_webqueue/playlists/fire.py +0 -0
- {kryten_webqueue-0.35.7 → kryten_webqueue-0.35.8}/kryten_webqueue/playlists/importer.py +0 -0
- {kryten_webqueue-0.35.7 → kryten_webqueue-0.35.8}/kryten_webqueue/playlists/ordering.py +0 -0
- {kryten_webqueue-0.35.7 → kryten_webqueue-0.35.8}/kryten_webqueue/playlists/scheduler.py +0 -0
- {kryten_webqueue-0.35.7 → kryten_webqueue-0.35.8}/kryten_webqueue/promos/__init__.py +0 -0
- {kryten_webqueue-0.35.7 → kryten_webqueue-0.35.8}/kryten_webqueue/promos/director.py +0 -0
- {kryten_webqueue-0.35.7 → kryten_webqueue-0.35.8}/kryten_webqueue/queue/__init__.py +0 -0
- {kryten_webqueue-0.35.7 → kryten_webqueue-0.35.8}/kryten_webqueue/queue/completion.py +0 -0
- {kryten_webqueue-0.35.7 → kryten_webqueue-0.35.8}/kryten_webqueue/queue/ordering.py +0 -0
- {kryten_webqueue-0.35.7 → kryten_webqueue-0.35.8}/kryten_webqueue/queue/poller.py +0 -0
- {kryten_webqueue-0.35.7 → kryten_webqueue-0.35.8}/kryten_webqueue/queue/presence.py +0 -0
- {kryten_webqueue-0.35.7 → kryten_webqueue-0.35.8}/kryten_webqueue/queue/race_poller.py +0 -0
- {kryten_webqueue-0.35.7 → kryten_webqueue-0.35.8}/kryten_webqueue/queue/shadow.py +0 -0
- {kryten_webqueue-0.35.7 → kryten_webqueue-0.35.8}/kryten_webqueue/routes/__init__.py +0 -0
- {kryten_webqueue-0.35.7 → kryten_webqueue-0.35.8}/kryten_webqueue/routes/admin_catalog.py +0 -0
- {kryten_webqueue-0.35.7 → kryten_webqueue-0.35.8}/kryten_webqueue/routes/admin_feedback.py +0 -0
- {kryten_webqueue-0.35.7 → kryten_webqueue-0.35.8}/kryten_webqueue/routes/admin_job_schedules.py +0 -0
- {kryten_webqueue-0.35.7 → kryten_webqueue-0.35.8}/kryten_webqueue/routes/admin_jobs.py +0 -0
- {kryten_webqueue-0.35.7 → kryten_webqueue-0.35.8}/kryten_webqueue/routes/admin_moderation.py +0 -0
- {kryten_webqueue-0.35.7 → kryten_webqueue-0.35.8}/kryten_webqueue/routes/admin_playlists.py +0 -0
- {kryten_webqueue-0.35.7 → kryten_webqueue-0.35.8}/kryten_webqueue/routes/admin_promos.py +0 -0
- {kryten_webqueue-0.35.7 → kryten_webqueue-0.35.8}/kryten_webqueue/routes/admin_queue.py +0 -0
- {kryten_webqueue-0.35.7 → kryten_webqueue-0.35.8}/kryten_webqueue/routes/admin_schedules.py +0 -0
- {kryten_webqueue-0.35.7 → kryten_webqueue-0.35.8}/kryten_webqueue/routes/auth.py +0 -0
- {kryten_webqueue-0.35.7 → kryten_webqueue-0.35.8}/kryten_webqueue/routes/catalog.py +0 -0
- {kryten_webqueue-0.35.7 → kryten_webqueue-0.35.8}/kryten_webqueue/routes/feedback.py +0 -0
- {kryten_webqueue-0.35.7 → kryten_webqueue-0.35.8}/kryten_webqueue/routes/pages.py +0 -0
- {kryten_webqueue-0.35.7 → kryten_webqueue-0.35.8}/kryten_webqueue/routes/queue.py +0 -0
- {kryten_webqueue-0.35.7 → kryten_webqueue-0.35.8}/kryten_webqueue/routes/user.py +0 -0
- {kryten_webqueue-0.35.7 → kryten_webqueue-0.35.8}/kryten_webqueue/static/css/main.css +0 -0
- {kryten_webqueue-0.35.7 → kryten_webqueue-0.35.8}/kryten_webqueue/static/js/admin-playlists.js +0 -0
- {kryten_webqueue-0.35.7 → kryten_webqueue-0.35.8}/kryten_webqueue/static/js/admin-promos.js +0 -0
- {kryten_webqueue-0.35.7 → kryten_webqueue-0.35.8}/kryten_webqueue/static/js/admin-queue-mgmt.js +0 -0
- {kryten_webqueue-0.35.7 → kryten_webqueue-0.35.8}/kryten_webqueue/static/js/admin-schedules.js +0 -0
- {kryten_webqueue-0.35.7 → kryten_webqueue-0.35.8}/kryten_webqueue/static/js/admin.js +0 -0
- {kryten_webqueue-0.35.7 → kryten_webqueue-0.35.8}/kryten_webqueue/static/js/main.js +0 -0
- {kryten_webqueue-0.35.7 → kryten_webqueue-0.35.8}/kryten_webqueue/templates/admin/index.html +0 -0
- {kryten_webqueue-0.35.7 → kryten_webqueue-0.35.8}/kryten_webqueue/templates/admin/playlists.html +0 -0
- {kryten_webqueue-0.35.7 → kryten_webqueue-0.35.8}/kryten_webqueue/templates/admin/promos.html +0 -0
- {kryten_webqueue-0.35.7 → kryten_webqueue-0.35.8}/kryten_webqueue/templates/admin/queue_mgmt.html +0 -0
- {kryten_webqueue-0.35.7 → kryten_webqueue-0.35.8}/kryten_webqueue/templates/admin/schedules.html +0 -0
- {kryten_webqueue-0.35.7 → kryten_webqueue-0.35.8}/kryten_webqueue/templates/auth/login.html +0 -0
- {kryten_webqueue-0.35.7 → kryten_webqueue-0.35.8}/kryten_webqueue/templates/base.html +0 -0
- {kryten_webqueue-0.35.7 → kryten_webqueue-0.35.8}/kryten_webqueue/templates/catalog/browse.html +0 -0
- {kryten_webqueue-0.35.7 → kryten_webqueue-0.35.8}/kryten_webqueue/templates/catalog/item_detail.html +0 -0
- {kryten_webqueue-0.35.7 → kryten_webqueue-0.35.8}/kryten_webqueue/templates/catalog/item_not_found.html +0 -0
- {kryten_webqueue-0.35.7 → kryten_webqueue-0.35.8}/kryten_webqueue/templates/feedback/index.html +0 -0
- {kryten_webqueue-0.35.7 → kryten_webqueue-0.35.8}/kryten_webqueue/templates/queue/index.html +0 -0
- {kryten_webqueue-0.35.7 → kryten_webqueue-0.35.8}/kryten_webqueue/templates/race.html +0 -0
- {kryten_webqueue-0.35.7 → kryten_webqueue-0.35.8}/kryten_webqueue/templates/user/dashboard.html +0 -0
- {kryten_webqueue-0.35.7 → kryten_webqueue-0.35.8}/kryten_webqueue/templates/user/my_list.html +0 -0
- {kryten_webqueue-0.35.7 → kryten_webqueue-0.35.8}/kryten_webqueue/ws/__init__.py +0 -0
- {kryten_webqueue-0.35.7 → kryten_webqueue-0.35.8}/kryten_webqueue/ws/handler.py +0 -0
- {kryten_webqueue-0.35.7 → kryten_webqueue-0.35.8}/kryten_webqueue/ws/manager.py +0 -0
- {kryten_webqueue-0.35.7 → kryten_webqueue-0.35.8}/tests/__init__.py +0 -0
- {kryten_webqueue-0.35.7 → kryten_webqueue-0.35.8}/tests/test_classify.py +0 -0
- {kryten_webqueue-0.35.7 → kryten_webqueue-0.35.8}/tests/test_config_persistence.py +0 -0
- {kryten_webqueue-0.35.7 → kryten_webqueue-0.35.8}/tests/test_feedback.py +0 -0
- {kryten_webqueue-0.35.7 → kryten_webqueue-0.35.8}/tests/test_fetchurls_sharepoint.py +0 -0
- {kryten_webqueue-0.35.7 → kryten_webqueue-0.35.8}/tests/test_people_facets.py +0 -0
- {kryten_webqueue-0.35.7 → kryten_webqueue-0.35.8}/tests/test_phase1.py +0 -0
- {kryten_webqueue-0.35.7 → kryten_webqueue-0.35.8}/tests/test_phase2_jobs.py +0 -0
- {kryten_webqueue-0.35.7 → kryten_webqueue-0.35.8}/tests/test_phase3_jobs.py +0 -0
- {kryten_webqueue-0.35.7 → kryten_webqueue-0.35.8}/tests/test_phase4_live_fixes.py +0 -0
- {kryten_webqueue-0.35.7 → kryten_webqueue-0.35.8}/tests/test_playlist_import.py +0 -0
- {kryten_webqueue-0.35.7 → kryten_webqueue-0.35.8}/tests/test_presence_refund.py +0 -0
- {kryten_webqueue-0.35.7 → kryten_webqueue-0.35.8}/tests/test_promo_director.py +0 -0
- {kryten_webqueue-0.35.7 → kryten_webqueue-0.35.8}/tests/test_promo_pool_exclusion.py +0 -0
- {kryten_webqueue-0.35.7 → kryten_webqueue-0.35.8}/tests/test_providers.py +0 -0
- {kryten_webqueue-0.35.7 → kryten_webqueue-0.35.8}/tests/test_queue_announce.py +0 -0
- {kryten_webqueue-0.35.7 → kryten_webqueue-0.35.8}/tests/test_race_poller.py +0 -0
- {kryten_webqueue-0.35.7 → kryten_webqueue-0.35.8}/tests/test_recently_played_hide.py +0 -0
- {kryten_webqueue-0.35.7 → kryten_webqueue-0.35.8}/tests/test_save_results_to_playlist.py +0 -0
- {kryten_webqueue-0.35.7 → kryten_webqueue-0.35.8}/tests/test_schedule_lock.py +0 -0
- {kryten_webqueue-0.35.7 → kryten_webqueue-0.35.8}/tests/test_search_facets.py +0 -0
- {kryten_webqueue-0.35.7 → kryten_webqueue-0.35.8}/tests/test_title_normalization.py +0 -0
- {kryten_webqueue-0.35.7 → kryten_webqueue-0.35.8}/tests/test_watchlist.py +0 -0
|
@@ -2,6 +2,26 @@
|
|
|
2
2
|
|
|
3
3
|
## [Unreleased]
|
|
4
4
|
|
|
5
|
+
## [0.35.8] - 2026-08-14
|
|
6
|
+
|
|
7
|
+
### Fixed
|
|
8
|
+
|
|
9
|
+
- **TV show poster art preservation.** Fixed art enrichment step to use TV show
|
|
10
|
+
searches instead of movie searches for TV episodes. Previously, searching for
|
|
11
|
+
"The X-Files" as a movie would find the 1998 X-Files movie poster instead of
|
|
12
|
+
the TV series poster, causing ~90% of TV show posters to be replaced with
|
|
13
|
+
incorrect movie posters or wiped out entirely. Now uses `search_tv_show()` for
|
|
14
|
+
TV content to get the correct series poster art.
|
|
15
|
+
- **Deleted items removed from catalog.** Catalog sync now tracks and removes
|
|
16
|
+
items that have been deleted from MediaCMS. Items with `synced_at` timestamps
|
|
17
|
+
older than the sync start time are identified as deleted and removed from the
|
|
18
|
+
catalog along with their category, tag, people, and studio associations.
|
|
19
|
+
|
|
20
|
+
### Added
|
|
21
|
+
|
|
22
|
+
- **TMDBProvider.search_tv_show() and OMDBProvider.search_tv_show().** New methods
|
|
23
|
+
to search for TV series and return show posters (for use with TV episode items).
|
|
24
|
+
|
|
5
25
|
## [0.35.7] - 2026-08-14
|
|
6
26
|
|
|
7
27
|
### Added
|
|
@@ -848,6 +848,44 @@ class _CatalogMixin:
|
|
|
848
848
|
[path, source, friendly_token],
|
|
849
849
|
)
|
|
850
850
|
|
|
851
|
+
async def delete_stale_catalog_items(self, sync_started_at: str) -> int:
|
|
852
|
+
"""Delete catalog items that weren't updated during the sync.
|
|
853
|
+
|
|
854
|
+
Items with synced_at older than sync_started_at are no longer present
|
|
855
|
+
in MediaCMS and should be removed. Returns count of deleted items.
|
|
856
|
+
|
|
857
|
+
Foreign key CASCADE will automatically remove related entries from:
|
|
858
|
+
- catalog_fts
|
|
859
|
+
- catalog_categories
|
|
860
|
+
- catalog_tags
|
|
861
|
+
- catalog_people
|
|
862
|
+
- catalog_studios
|
|
863
|
+
"""
|
|
864
|
+
cursor = await self._db.execute(
|
|
865
|
+
"SELECT friendly_token FROM catalog WHERE synced_at < ? OR synced_at IS NULL",
|
|
866
|
+
[sync_started_at],
|
|
867
|
+
)
|
|
868
|
+
tokens = [row[0] for row in await cursor.fetchall()]
|
|
869
|
+
|
|
870
|
+
if not tokens:
|
|
871
|
+
return 0
|
|
872
|
+
|
|
873
|
+
# Delete from FTS first (not automatically cascaded)
|
|
874
|
+
placeholders = ",".join("?" * len(tokens))
|
|
875
|
+
await self._db.execute(
|
|
876
|
+
f"DELETE FROM catalog_fts WHERE friendly_token IN ({placeholders})",
|
|
877
|
+
tokens,
|
|
878
|
+
)
|
|
879
|
+
|
|
880
|
+
# Delete from catalog (cascades to join tables via ON DELETE CASCADE)
|
|
881
|
+
await self._db.execute(
|
|
882
|
+
f"DELETE FROM catalog WHERE friendly_token IN ({placeholders})",
|
|
883
|
+
tokens,
|
|
884
|
+
)
|
|
885
|
+
|
|
886
|
+
await self._db.commit()
|
|
887
|
+
return len(tokens)
|
|
888
|
+
|
|
851
889
|
async def find_catalog_by_title(self, title: str) -> dict | None:
|
|
852
890
|
"""Best-effort lookup of a catalog item whose title matches ``title``.
|
|
853
891
|
|
{kryten_webqueue-0.35.7 → kryten_webqueue-0.35.8}/kryten_webqueue/catalog/enrichment/providers.py
RENAMED
|
@@ -149,6 +149,36 @@ class TMDBProvider:
|
|
|
149
149
|
logger.debug("TMDB search error for %r: %s", title, exc)
|
|
150
150
|
return MovieMetadata()
|
|
151
151
|
|
|
152
|
+
async def search_tv_show(self, show: str) -> MovieMetadata:
|
|
153
|
+
"""Search for a TV show and return its poster (for episode art)."""
|
|
154
|
+
if not self._key:
|
|
155
|
+
return MovieMetadata()
|
|
156
|
+
headers, auth = _tmdb_auth(self._key)
|
|
157
|
+
try:
|
|
158
|
+
resp = await self._client.get(
|
|
159
|
+
f"{TMDB_BASE}/search/tv",
|
|
160
|
+
headers=headers,
|
|
161
|
+
params={"query": show, **auth},
|
|
162
|
+
)
|
|
163
|
+
if resp.status_code != 200:
|
|
164
|
+
return MovieMetadata()
|
|
165
|
+
results = resp.json().get("results", [])
|
|
166
|
+
if not results:
|
|
167
|
+
return MovieMetadata()
|
|
168
|
+
# Pick the best match by popularity
|
|
169
|
+
tv_show = results[0]
|
|
170
|
+
meta = MovieMetadata()
|
|
171
|
+
meta.title = tv_show.get("name", "")
|
|
172
|
+
meta.synopsis = tv_show.get("overview", "")
|
|
173
|
+
first_air = tv_show.get("first_air_date", "")
|
|
174
|
+
meta.year = first_air[:4] if first_air else None
|
|
175
|
+
if tv_show.get("poster_path"):
|
|
176
|
+
meta.poster_url = f"https://image.tmdb.org/t/p/w780{tv_show['poster_path']}"
|
|
177
|
+
return meta
|
|
178
|
+
except (httpx.HTTPError, json.JSONDecodeError, ValueError) as exc:
|
|
179
|
+
logger.debug("TMDB TV show search error for %r: %s", show, exc)
|
|
180
|
+
return MovieMetadata()
|
|
181
|
+
|
|
152
182
|
async def search_tv_episode(
|
|
153
183
|
self, show: str, season: int, episode: int
|
|
154
184
|
) -> MovieMetadata:
|
|
@@ -311,6 +341,25 @@ class OMDBProvider:
|
|
|
311
341
|
logger.debug("OMDB error for %r: %s", title, exc)
|
|
312
342
|
return MovieMetadata()
|
|
313
343
|
|
|
344
|
+
async def search_tv_show(self, show: str) -> MovieMetadata:
|
|
345
|
+
"""Search for a TV show and return its poster (for episode art)."""
|
|
346
|
+
if not self._key:
|
|
347
|
+
return MovieMetadata()
|
|
348
|
+
try:
|
|
349
|
+
resp = await self._client.get(
|
|
350
|
+
OMDB_BASE,
|
|
351
|
+
params={
|
|
352
|
+
"apikey": self._key,
|
|
353
|
+
"t": show,
|
|
354
|
+
"type": "series",
|
|
355
|
+
},
|
|
356
|
+
)
|
|
357
|
+
if resp.status_code == 200 and resp.json().get("Response") == "True":
|
|
358
|
+
return self._parse(resp.json())
|
|
359
|
+
except (httpx.HTTPError, json.JSONDecodeError, ValueError):
|
|
360
|
+
pass
|
|
361
|
+
return MovieMetadata()
|
|
362
|
+
|
|
314
363
|
async def search_tv_episode(
|
|
315
364
|
self, show: str, season: int, episode: int
|
|
316
365
|
) -> MovieMetadata:
|
{kryten_webqueue-0.35.7 → kryten_webqueue-0.35.8}/kryten_webqueue/catalog/enrichment/steps/art.py
RENAMED
|
@@ -114,9 +114,22 @@ class ArtStep:
|
|
|
114
114
|
return (meta or {}).get("poster_url")
|
|
115
115
|
|
|
116
116
|
async def _resolve_poster(self, cls: ItemClassification) -> str | None:
|
|
117
|
-
"""Query TMDB then OMDB using lookup_title (the key fix for hosted movies).
|
|
117
|
+
"""Query TMDB then OMDB using lookup_title (the key fix for hosted movies).
|
|
118
|
+
|
|
119
|
+
For TV episodes, search for the show poster (not episode-specific art).
|
|
120
|
+
"""
|
|
118
121
|
if not cls.lookup_title:
|
|
119
122
|
return None
|
|
123
|
+
|
|
124
|
+
# TV episodes: get the show poster
|
|
125
|
+
if cls.content_type == "tv_episode":
|
|
126
|
+
meta = await self._tmdb.search_tv_show(cls.lookup_title)
|
|
127
|
+
if meta.poster_url:
|
|
128
|
+
return meta.poster_url
|
|
129
|
+
meta = await self._omdb.search_tv_show(cls.lookup_title)
|
|
130
|
+
return meta.poster_url
|
|
131
|
+
|
|
132
|
+
# Movies and other content: search as movie
|
|
120
133
|
meta = await self._tmdb.search_movie(cls.lookup_title, cls.lookup_year)
|
|
121
134
|
if meta.poster_url:
|
|
122
135
|
return meta.poster_url
|
|
@@ -57,7 +57,8 @@ class CatalogSync:
|
|
|
57
57
|
async def sync(self):
|
|
58
58
|
"""Full catalog sync from MediaCMS API."""
|
|
59
59
|
log_id = await self._db.start_sync_log()
|
|
60
|
-
stats = {"seen": 0, "new": 0, "updated": 0, "errors": 0}
|
|
60
|
+
stats = {"seen": 0, "new": 0, "updated": 0, "errors": 0, "deleted": 0}
|
|
61
|
+
sync_started_at = datetime.now(UTC).isoformat()
|
|
61
62
|
|
|
62
63
|
try:
|
|
63
64
|
# /manage_media returns all items (9k+); /media is capped at 1000
|
|
@@ -106,6 +107,12 @@ class CatalogSync:
|
|
|
106
107
|
f"Catalog sync page {page}: seen={stats['seen']} next={next_url!r}"
|
|
107
108
|
)
|
|
108
109
|
|
|
110
|
+
# Remove items deleted from MediaCMS (not seen during this sync)
|
|
111
|
+
deleted_count = await self._db.delete_stale_catalog_items(sync_started_at)
|
|
112
|
+
stats["deleted"] = deleted_count
|
|
113
|
+
if deleted_count > 0:
|
|
114
|
+
logger.info(f"Removed {deleted_count} items deleted from MediaCMS")
|
|
115
|
+
|
|
109
116
|
await self._db.finish_sync_log(log_id, stats, "completed")
|
|
110
117
|
logger.info(f"Catalog sync complete: {stats} ({page} pages)")
|
|
111
118
|
except asyncio.CancelledError:
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
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.35.7 → kryten_webqueue-0.35.8}/docs/Log for incorrect promo insertion problem.txt
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
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.35.7 → kryten_webqueue-0.35.8}/kryten_webqueue/catalog/enrichment/__init__.py
RENAMED
|
File without changes
|
{kryten_webqueue-0.35.7 → kryten_webqueue-0.35.8}/kryten_webqueue/catalog/enrichment/classify.py
RENAMED
|
File without changes
|
{kryten_webqueue-0.35.7 → kryten_webqueue-0.35.8}/kryten_webqueue/catalog/enrichment/normalise.py
RENAMED
|
File without changes
|
{kryten_webqueue-0.35.7 → kryten_webqueue-0.35.8}/kryten_webqueue/catalog/enrichment/pipeline.py
RENAMED
|
File without changes
|
{kryten_webqueue-0.35.7 → kryten_webqueue-0.35.8}/kryten_webqueue/catalog/enrichment/report.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
{kryten_webqueue-0.35.7 → kryten_webqueue-0.35.8}/kryten_webqueue/catalog/enrichment/steps/meta.py
RENAMED
|
File without changes
|
{kryten_webqueue-0.35.7 → kryten_webqueue-0.35.8}/kryten_webqueue/catalog/enrichment/steps/sync.py
RENAMED
|
File without changes
|
{kryten_webqueue-0.35.7 → kryten_webqueue-0.35.8}/kryten_webqueue/catalog/enrichment/steps/tags.py
RENAMED
|
File without changes
|
{kryten_webqueue-0.35.7 → kryten_webqueue-0.35.8}/kryten_webqueue/catalog/enrichment/steps/title.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{kryten_webqueue-0.35.7 → kryten_webqueue-0.35.8}/kryten_webqueue/integrations/cmsutils/__init__.py
RENAMED
|
File without changes
|
{kryten_webqueue-0.35.7 → kryten_webqueue-0.35.8}/kryten_webqueue/integrations/cmsutils/_common.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
{kryten_webqueue-0.35.7 → kryten_webqueue-0.35.8}/kryten_webqueue/integrations/cmsutils/enrichtv.py
RENAMED
|
File without changes
|
{kryten_webqueue-0.35.7 → kryten_webqueue-0.35.8}/kryten_webqueue/integrations/cmsutils/fetchurls.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
{kryten_webqueue-0.35.7 → kryten_webqueue-0.35.8}/kryten_webqueue/integrations/ytpipe/__init__.py
RENAMED
|
File without changes
|
{kryten_webqueue-0.35.7 → kryten_webqueue-0.35.8}/kryten_webqueue/integrations/ytpipe/downloader.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
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.35.7 → kryten_webqueue-0.35.8}/kryten_webqueue/routes/admin_job_schedules.py
RENAMED
|
File without changes
|
|
File without changes
|
{kryten_webqueue-0.35.7 → kryten_webqueue-0.35.8}/kryten_webqueue/routes/admin_moderation.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
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.35.7 → kryten_webqueue-0.35.8}/kryten_webqueue/static/js/admin-playlists.js
RENAMED
|
File without changes
|
|
File without changes
|
{kryten_webqueue-0.35.7 → kryten_webqueue-0.35.8}/kryten_webqueue/static/js/admin-queue-mgmt.js
RENAMED
|
File without changes
|
{kryten_webqueue-0.35.7 → kryten_webqueue-0.35.8}/kryten_webqueue/static/js/admin-schedules.js
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
{kryten_webqueue-0.35.7 → kryten_webqueue-0.35.8}/kryten_webqueue/templates/admin/index.html
RENAMED
|
File without changes
|
{kryten_webqueue-0.35.7 → kryten_webqueue-0.35.8}/kryten_webqueue/templates/admin/playlists.html
RENAMED
|
File without changes
|
{kryten_webqueue-0.35.7 → kryten_webqueue-0.35.8}/kryten_webqueue/templates/admin/promos.html
RENAMED
|
File without changes
|
{kryten_webqueue-0.35.7 → kryten_webqueue-0.35.8}/kryten_webqueue/templates/admin/queue_mgmt.html
RENAMED
|
File without changes
|
{kryten_webqueue-0.35.7 → kryten_webqueue-0.35.8}/kryten_webqueue/templates/admin/schedules.html
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
{kryten_webqueue-0.35.7 → kryten_webqueue-0.35.8}/kryten_webqueue/templates/catalog/browse.html
RENAMED
|
File without changes
|
{kryten_webqueue-0.35.7 → kryten_webqueue-0.35.8}/kryten_webqueue/templates/catalog/item_detail.html
RENAMED
|
File without changes
|
|
File without changes
|
{kryten_webqueue-0.35.7 → kryten_webqueue-0.35.8}/kryten_webqueue/templates/feedback/index.html
RENAMED
|
File without changes
|
{kryten_webqueue-0.35.7 → kryten_webqueue-0.35.8}/kryten_webqueue/templates/queue/index.html
RENAMED
|
File without changes
|
|
File without changes
|
{kryten_webqueue-0.35.7 → kryten_webqueue-0.35.8}/kryten_webqueue/templates/user/dashboard.html
RENAMED
|
File without changes
|
{kryten_webqueue-0.35.7 → kryten_webqueue-0.35.8}/kryten_webqueue/templates/user/my_list.html
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|