kryten-webqueue 0.35.3__tar.gz → 0.35.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.
- {kryten_webqueue-0.35.3 → kryten_webqueue-0.35.4}/CHANGELOG.md +12 -0
- {kryten_webqueue-0.35.3 → kryten_webqueue-0.35.4}/PKG-INFO +1 -1
- {kryten_webqueue-0.35.3 → kryten_webqueue-0.35.4}/kryten_webqueue/catalog/db/_enrichment.py +8 -1
- {kryten_webqueue-0.35.3 → kryten_webqueue-0.35.4}/kryten_webqueue/catalog/enrichment/providers.py +7 -6
- {kryten_webqueue-0.35.3 → kryten_webqueue-0.35.4}/kryten_webqueue/catalog/enrichment/steps/meta.py +31 -15
- {kryten_webqueue-0.35.3 → kryten_webqueue-0.35.4}/kryten_webqueue/catalog/enrichment/steps/tags.py +34 -27
- {kryten_webqueue-0.35.3 → kryten_webqueue-0.35.4}/kryten_webqueue/catalog/enrichment/steps/title.py +2 -1
- {kryten_webqueue-0.35.3 → kryten_webqueue-0.35.4}/pyproject.toml +1 -1
- {kryten_webqueue-0.35.3 → kryten_webqueue-0.35.4}/.github/workflows/gitleaks.yml +0 -0
- {kryten_webqueue-0.35.3 → kryten_webqueue-0.35.4}/.github/workflows/python-publish.yml +0 -0
- {kryten_webqueue-0.35.3 → kryten_webqueue-0.35.4}/.github/workflows/release.yml +0 -0
- {kryten_webqueue-0.35.3 → kryten_webqueue-0.35.4}/.gitignore +0 -0
- {kryten_webqueue-0.35.3 → kryten_webqueue-0.35.4}/.gitleaks.toml +0 -0
- {kryten_webqueue-0.35.3 → kryten_webqueue-0.35.4}/.pre-commit-config.yaml +0 -0
- {kryten_webqueue-0.35.3 → kryten_webqueue-0.35.4}/AGENT-WORKFLOW-GUIDE.md +0 -0
- {kryten_webqueue-0.35.3 → kryten_webqueue-0.35.4}/README.md +0 -0
- {kryten_webqueue-0.35.3 → kryten_webqueue-0.35.4}/config.example.json +0 -0
- {kryten_webqueue-0.35.3 → kryten_webqueue-0.35.4}/deploy/kryten-webqueue.service +0 -0
- {kryten_webqueue-0.35.3 → kryten_webqueue-0.35.4}/deploy/nginx-queue.conf +0 -0
- {kryten_webqueue-0.35.3 → kryten_webqueue-0.35.4}/docs/IMPLEMENTATION_SPEC.md +0 -0
- {kryten_webqueue-0.35.3 → kryten_webqueue-0.35.4}/docs/IMPL_API_GATE.md +0 -0
- {kryten_webqueue-0.35.3 → kryten_webqueue-0.35.4}/docs/IMPL_ECONOMY.md +0 -0
- {kryten_webqueue-0.35.3 → kryten_webqueue-0.35.4}/docs/IMPL_KRYTEN_PY.md +0 -0
- {kryten_webqueue-0.35.3 → kryten_webqueue-0.35.4}/docs/IMPL_ROBOT.md +0 -0
- {kryten_webqueue-0.35.3 → kryten_webqueue-0.35.4}/docs/Kryten-Economy Service Quality Survey Report at v0.13.0.md +0 -0
- {kryten_webqueue-0.35.3 → kryten_webqueue-0.35.4}/docs/Kryten-Webqueue Service Quality Survey Report at v0.27.1.md +0 -0
- {kryten_webqueue-0.35.3 → kryten_webqueue-0.35.4}/docs/Log for incorrect promo insertion problem.txt +0 -0
- {kryten_webqueue-0.35.3 → kryten_webqueue-0.35.4}/docs/PLAN_PRESENCE_AND_PROMOS.md +0 -0
- {kryten_webqueue-0.35.3 → kryten_webqueue-0.35.4}/docs/PRE_PLAN_GAPS.md +0 -0
- {kryten_webqueue-0.35.3 → kryten_webqueue-0.35.4}/docs/PRODUCT_PLAN.md +0 -0
- {kryten_webqueue-0.35.3 → kryten_webqueue-0.35.4}/docs/SPEC_CATALOG_ENRICHMENT_PIPELINE.md +0 -0
- {kryten_webqueue-0.35.3 → kryten_webqueue-0.35.4}/docs/SPEC_EMOTE_REHOST.md +0 -0
- {kryten_webqueue-0.35.3 → kryten_webqueue-0.35.4}/docs/SPEC_JOBS_AND_BROWSE.md +0 -0
- {kryten_webqueue-0.35.3 → kryten_webqueue-0.35.4}/docs/UX_POLISH_PLAN.md +0 -0
- {kryten_webqueue-0.35.3 → kryten_webqueue-0.35.4}/kryten_webqueue/__init__.py +0 -0
- {kryten_webqueue-0.35.3 → kryten_webqueue-0.35.4}/kryten_webqueue/__main__.py +0 -0
- {kryten_webqueue-0.35.3 → kryten_webqueue-0.35.4}/kryten_webqueue/api_gate/__init__.py +0 -0
- {kryten_webqueue-0.35.3 → kryten_webqueue-0.35.4}/kryten_webqueue/api_gate/client.py +0 -0
- {kryten_webqueue-0.35.3 → kryten_webqueue-0.35.4}/kryten_webqueue/app.py +0 -0
- {kryten_webqueue-0.35.3 → kryten_webqueue-0.35.4}/kryten_webqueue/auth/__init__.py +0 -0
- {kryten_webqueue-0.35.3 → kryten_webqueue-0.35.4}/kryten_webqueue/auth/otp.py +0 -0
- {kryten_webqueue-0.35.3 → kryten_webqueue-0.35.4}/kryten_webqueue/auth/rate_limit.py +0 -0
- {kryten_webqueue-0.35.3 → kryten_webqueue-0.35.4}/kryten_webqueue/auth/session.py +0 -0
- {kryten_webqueue-0.35.3 → kryten_webqueue-0.35.4}/kryten_webqueue/catalog/__init__.py +0 -0
- {kryten_webqueue-0.35.3 → kryten_webqueue-0.35.4}/kryten_webqueue/catalog/db/__init__.py +0 -0
- {kryten_webqueue-0.35.3 → kryten_webqueue-0.35.4}/kryten_webqueue/catalog/db/_catalog.py +0 -0
- {kryten_webqueue-0.35.3 → kryten_webqueue-0.35.4}/kryten_webqueue/catalog/db/_connection.py +0 -0
- {kryten_webqueue-0.35.3 → kryten_webqueue-0.35.4}/kryten_webqueue/catalog/db/_feedback.py +0 -0
- {kryten_webqueue-0.35.3 → kryten_webqueue-0.35.4}/kryten_webqueue/catalog/db/_people.py +0 -0
- {kryten_webqueue-0.35.3 → kryten_webqueue-0.35.4}/kryten_webqueue/catalog/db/_playlists.py +0 -0
- {kryten_webqueue-0.35.3 → kryten_webqueue-0.35.4}/kryten_webqueue/catalog/db/_queue.py +0 -0
- {kryten_webqueue-0.35.3 → kryten_webqueue-0.35.4}/kryten_webqueue/catalog/db/_watchlist.py +0 -0
- {kryten_webqueue-0.35.3 → kryten_webqueue-0.35.4}/kryten_webqueue/catalog/enrichment/__init__.py +0 -0
- {kryten_webqueue-0.35.3 → kryten_webqueue-0.35.4}/kryten_webqueue/catalog/enrichment/classify.py +0 -0
- {kryten_webqueue-0.35.3 → kryten_webqueue-0.35.4}/kryten_webqueue/catalog/enrichment/normalise.py +0 -0
- {kryten_webqueue-0.35.3 → kryten_webqueue-0.35.4}/kryten_webqueue/catalog/enrichment/pipeline.py +0 -0
- {kryten_webqueue-0.35.3 → kryten_webqueue-0.35.4}/kryten_webqueue/catalog/enrichment/report.py +0 -0
- {kryten_webqueue-0.35.3 → kryten_webqueue-0.35.4}/kryten_webqueue/catalog/enrichment/steps/__init__.py +0 -0
- {kryten_webqueue-0.35.3 → kryten_webqueue-0.35.4}/kryten_webqueue/catalog/enrichment/steps/art.py +0 -0
- {kryten_webqueue-0.35.3 → kryten_webqueue-0.35.4}/kryten_webqueue/catalog/enrichment/steps/categories.py +0 -0
- {kryten_webqueue-0.35.3 → kryten_webqueue-0.35.4}/kryten_webqueue/catalog/enrichment/steps/sync.py +0 -0
- {kryten_webqueue-0.35.3 → kryten_webqueue-0.35.4}/kryten_webqueue/catalog/images.py +0 -0
- {kryten_webqueue-0.35.3 → kryten_webqueue-0.35.4}/kryten_webqueue/catalog/mediacms.py +0 -0
- {kryten_webqueue-0.35.3 → kryten_webqueue-0.35.4}/kryten_webqueue/catalog/sync.py +0 -0
- {kryten_webqueue-0.35.3 → kryten_webqueue-0.35.4}/kryten_webqueue/config.py +0 -0
- {kryten_webqueue-0.35.3 → kryten_webqueue-0.35.4}/kryten_webqueue/integrations/__init__.py +0 -0
- {kryten_webqueue-0.35.3 → kryten_webqueue-0.35.4}/kryten_webqueue/integrations/cmsutils/__init__.py +0 -0
- {kryten_webqueue-0.35.3 → kryten_webqueue-0.35.4}/kryten_webqueue/integrations/cmsutils/_common.py +0 -0
- {kryten_webqueue-0.35.3 → kryten_webqueue-0.35.4}/kryten_webqueue/integrations/cmsutils/enrichmeta.py +0 -0
- {kryten_webqueue-0.35.3 → kryten_webqueue-0.35.4}/kryten_webqueue/integrations/cmsutils/enrichtitles.py +0 -0
- {kryten_webqueue-0.35.3 → kryten_webqueue-0.35.4}/kryten_webqueue/integrations/cmsutils/enrichtv.py +0 -0
- {kryten_webqueue-0.35.3 → kryten_webqueue-0.35.4}/kryten_webqueue/integrations/cmsutils/fetchurls.py +0 -0
- {kryten_webqueue-0.35.3 → kryten_webqueue-0.35.4}/kryten_webqueue/integrations/cmsutils/motdposters.py +0 -0
- {kryten_webqueue-0.35.3 → kryten_webqueue-0.35.4}/kryten_webqueue/integrations/cmsutils/playedmovies.py +0 -0
- {kryten_webqueue-0.35.3 → kryten_webqueue-0.35.4}/kryten_webqueue/integrations/ytpipe/__init__.py +0 -0
- {kryten_webqueue-0.35.3 → kryten_webqueue-0.35.4}/kryten_webqueue/integrations/ytpipe/downloader.py +0 -0
- {kryten_webqueue-0.35.3 → kryten_webqueue-0.35.4}/kryten_webqueue/jobs/__init__.py +0 -0
- {kryten_webqueue-0.35.3 → kryten_webqueue-0.35.4}/kryten_webqueue/jobs/fetchurls_auth.py +0 -0
- {kryten_webqueue-0.35.3 → kryten_webqueue-0.35.4}/kryten_webqueue/jobs/job_scheduler.py +0 -0
- {kryten_webqueue-0.35.3 → kryten_webqueue-0.35.4}/kryten_webqueue/jobs/manager.py +0 -0
- {kryten_webqueue-0.35.3 → kryten_webqueue-0.35.4}/kryten_webqueue/jobs/rehost_emotes.py +0 -0
- {kryten_webqueue-0.35.3 → kryten_webqueue-0.35.4}/kryten_webqueue/jobs/tasks.py +0 -0
- {kryten_webqueue-0.35.3 → kryten_webqueue-0.35.4}/kryten_webqueue/logging_config.py +0 -0
- {kryten_webqueue-0.35.3 → kryten_webqueue-0.35.4}/kryten_webqueue/playlists/__init__.py +0 -0
- {kryten_webqueue-0.35.3 → kryten_webqueue-0.35.4}/kryten_webqueue/playlists/bulk_add.py +0 -0
- {kryten_webqueue-0.35.3 → kryten_webqueue-0.35.4}/kryten_webqueue/playlists/fire.py +0 -0
- {kryten_webqueue-0.35.3 → kryten_webqueue-0.35.4}/kryten_webqueue/playlists/importer.py +0 -0
- {kryten_webqueue-0.35.3 → kryten_webqueue-0.35.4}/kryten_webqueue/playlists/ordering.py +0 -0
- {kryten_webqueue-0.35.3 → kryten_webqueue-0.35.4}/kryten_webqueue/playlists/scheduler.py +0 -0
- {kryten_webqueue-0.35.3 → kryten_webqueue-0.35.4}/kryten_webqueue/promos/__init__.py +0 -0
- {kryten_webqueue-0.35.3 → kryten_webqueue-0.35.4}/kryten_webqueue/promos/director.py +0 -0
- {kryten_webqueue-0.35.3 → kryten_webqueue-0.35.4}/kryten_webqueue/queue/__init__.py +0 -0
- {kryten_webqueue-0.35.3 → kryten_webqueue-0.35.4}/kryten_webqueue/queue/completion.py +0 -0
- {kryten_webqueue-0.35.3 → kryten_webqueue-0.35.4}/kryten_webqueue/queue/ordering.py +0 -0
- {kryten_webqueue-0.35.3 → kryten_webqueue-0.35.4}/kryten_webqueue/queue/poller.py +0 -0
- {kryten_webqueue-0.35.3 → kryten_webqueue-0.35.4}/kryten_webqueue/queue/presence.py +0 -0
- {kryten_webqueue-0.35.3 → kryten_webqueue-0.35.4}/kryten_webqueue/queue/race_poller.py +0 -0
- {kryten_webqueue-0.35.3 → kryten_webqueue-0.35.4}/kryten_webqueue/queue/shadow.py +0 -0
- {kryten_webqueue-0.35.3 → kryten_webqueue-0.35.4}/kryten_webqueue/routes/__init__.py +0 -0
- {kryten_webqueue-0.35.3 → kryten_webqueue-0.35.4}/kryten_webqueue/routes/admin_catalog.py +0 -0
- {kryten_webqueue-0.35.3 → kryten_webqueue-0.35.4}/kryten_webqueue/routes/admin_feedback.py +0 -0
- {kryten_webqueue-0.35.3 → kryten_webqueue-0.35.4}/kryten_webqueue/routes/admin_job_schedules.py +0 -0
- {kryten_webqueue-0.35.3 → kryten_webqueue-0.35.4}/kryten_webqueue/routes/admin_jobs.py +0 -0
- {kryten_webqueue-0.35.3 → kryten_webqueue-0.35.4}/kryten_webqueue/routes/admin_moderation.py +0 -0
- {kryten_webqueue-0.35.3 → kryten_webqueue-0.35.4}/kryten_webqueue/routes/admin_playlists.py +0 -0
- {kryten_webqueue-0.35.3 → kryten_webqueue-0.35.4}/kryten_webqueue/routes/admin_promos.py +0 -0
- {kryten_webqueue-0.35.3 → kryten_webqueue-0.35.4}/kryten_webqueue/routes/admin_queue.py +0 -0
- {kryten_webqueue-0.35.3 → kryten_webqueue-0.35.4}/kryten_webqueue/routes/admin_schedules.py +0 -0
- {kryten_webqueue-0.35.3 → kryten_webqueue-0.35.4}/kryten_webqueue/routes/auth.py +0 -0
- {kryten_webqueue-0.35.3 → kryten_webqueue-0.35.4}/kryten_webqueue/routes/catalog.py +0 -0
- {kryten_webqueue-0.35.3 → kryten_webqueue-0.35.4}/kryten_webqueue/routes/feedback.py +0 -0
- {kryten_webqueue-0.35.3 → kryten_webqueue-0.35.4}/kryten_webqueue/routes/pages.py +0 -0
- {kryten_webqueue-0.35.3 → kryten_webqueue-0.35.4}/kryten_webqueue/routes/queue.py +0 -0
- {kryten_webqueue-0.35.3 → kryten_webqueue-0.35.4}/kryten_webqueue/routes/user.py +0 -0
- {kryten_webqueue-0.35.3 → kryten_webqueue-0.35.4}/kryten_webqueue/static/css/main.css +0 -0
- {kryten_webqueue-0.35.3 → kryten_webqueue-0.35.4}/kryten_webqueue/static/js/admin-playlists.js +0 -0
- {kryten_webqueue-0.35.3 → kryten_webqueue-0.35.4}/kryten_webqueue/static/js/admin-promos.js +0 -0
- {kryten_webqueue-0.35.3 → kryten_webqueue-0.35.4}/kryten_webqueue/static/js/admin-queue-mgmt.js +0 -0
- {kryten_webqueue-0.35.3 → kryten_webqueue-0.35.4}/kryten_webqueue/static/js/admin-schedules.js +0 -0
- {kryten_webqueue-0.35.3 → kryten_webqueue-0.35.4}/kryten_webqueue/static/js/admin.js +0 -0
- {kryten_webqueue-0.35.3 → kryten_webqueue-0.35.4}/kryten_webqueue/static/js/main.js +0 -0
- {kryten_webqueue-0.35.3 → kryten_webqueue-0.35.4}/kryten_webqueue/templates/admin/index.html +0 -0
- {kryten_webqueue-0.35.3 → kryten_webqueue-0.35.4}/kryten_webqueue/templates/admin/playlists.html +0 -0
- {kryten_webqueue-0.35.3 → kryten_webqueue-0.35.4}/kryten_webqueue/templates/admin/promos.html +0 -0
- {kryten_webqueue-0.35.3 → kryten_webqueue-0.35.4}/kryten_webqueue/templates/admin/queue_mgmt.html +0 -0
- {kryten_webqueue-0.35.3 → kryten_webqueue-0.35.4}/kryten_webqueue/templates/admin/schedules.html +0 -0
- {kryten_webqueue-0.35.3 → kryten_webqueue-0.35.4}/kryten_webqueue/templates/auth/login.html +0 -0
- {kryten_webqueue-0.35.3 → kryten_webqueue-0.35.4}/kryten_webqueue/templates/base.html +0 -0
- {kryten_webqueue-0.35.3 → kryten_webqueue-0.35.4}/kryten_webqueue/templates/catalog/browse.html +0 -0
- {kryten_webqueue-0.35.3 → kryten_webqueue-0.35.4}/kryten_webqueue/templates/catalog/item_detail.html +0 -0
- {kryten_webqueue-0.35.3 → kryten_webqueue-0.35.4}/kryten_webqueue/templates/catalog/item_not_found.html +0 -0
- {kryten_webqueue-0.35.3 → kryten_webqueue-0.35.4}/kryten_webqueue/templates/feedback/index.html +0 -0
- {kryten_webqueue-0.35.3 → kryten_webqueue-0.35.4}/kryten_webqueue/templates/queue/index.html +0 -0
- {kryten_webqueue-0.35.3 → kryten_webqueue-0.35.4}/kryten_webqueue/templates/race.html +0 -0
- {kryten_webqueue-0.35.3 → kryten_webqueue-0.35.4}/kryten_webqueue/templates/user/dashboard.html +0 -0
- {kryten_webqueue-0.35.3 → kryten_webqueue-0.35.4}/kryten_webqueue/templates/user/my_list.html +0 -0
- {kryten_webqueue-0.35.3 → kryten_webqueue-0.35.4}/kryten_webqueue/ws/__init__.py +0 -0
- {kryten_webqueue-0.35.3 → kryten_webqueue-0.35.4}/kryten_webqueue/ws/handler.py +0 -0
- {kryten_webqueue-0.35.3 → kryten_webqueue-0.35.4}/kryten_webqueue/ws/manager.py +0 -0
- {kryten_webqueue-0.35.3 → kryten_webqueue-0.35.4}/tests/__init__.py +0 -0
- {kryten_webqueue-0.35.3 → kryten_webqueue-0.35.4}/tests/test_classify.py +0 -0
- {kryten_webqueue-0.35.3 → kryten_webqueue-0.35.4}/tests/test_config_persistence.py +0 -0
- {kryten_webqueue-0.35.3 → kryten_webqueue-0.35.4}/tests/test_feedback.py +0 -0
- {kryten_webqueue-0.35.3 → kryten_webqueue-0.35.4}/tests/test_fetchurls_sharepoint.py +0 -0
- {kryten_webqueue-0.35.3 → kryten_webqueue-0.35.4}/tests/test_people_facets.py +0 -0
- {kryten_webqueue-0.35.3 → kryten_webqueue-0.35.4}/tests/test_phase1.py +0 -0
- {kryten_webqueue-0.35.3 → kryten_webqueue-0.35.4}/tests/test_phase2_jobs.py +0 -0
- {kryten_webqueue-0.35.3 → kryten_webqueue-0.35.4}/tests/test_phase3_jobs.py +0 -0
- {kryten_webqueue-0.35.3 → kryten_webqueue-0.35.4}/tests/test_phase4_live_fixes.py +0 -0
- {kryten_webqueue-0.35.3 → kryten_webqueue-0.35.4}/tests/test_playlist_import.py +0 -0
- {kryten_webqueue-0.35.3 → kryten_webqueue-0.35.4}/tests/test_presence_refund.py +0 -0
- {kryten_webqueue-0.35.3 → kryten_webqueue-0.35.4}/tests/test_promo_director.py +0 -0
- {kryten_webqueue-0.35.3 → kryten_webqueue-0.35.4}/tests/test_promo_pool_exclusion.py +0 -0
- {kryten_webqueue-0.35.3 → kryten_webqueue-0.35.4}/tests/test_providers.py +0 -0
- {kryten_webqueue-0.35.3 → kryten_webqueue-0.35.4}/tests/test_queue_announce.py +0 -0
- {kryten_webqueue-0.35.3 → kryten_webqueue-0.35.4}/tests/test_race_poller.py +0 -0
- {kryten_webqueue-0.35.3 → kryten_webqueue-0.35.4}/tests/test_recently_played_hide.py +0 -0
- {kryten_webqueue-0.35.3 → kryten_webqueue-0.35.4}/tests/test_save_results_to_playlist.py +0 -0
- {kryten_webqueue-0.35.3 → kryten_webqueue-0.35.4}/tests/test_schedule_lock.py +0 -0
- {kryten_webqueue-0.35.3 → kryten_webqueue-0.35.4}/tests/test_search_facets.py +0 -0
- {kryten_webqueue-0.35.3 → kryten_webqueue-0.35.4}/tests/test_title_normalization.py +0 -0
- {kryten_webqueue-0.35.3 → kryten_webqueue-0.35.4}/tests/test_watchlist.py +0 -0
|
@@ -2,6 +2,18 @@
|
|
|
2
2
|
|
|
3
3
|
## [Unreleased]
|
|
4
4
|
|
|
5
|
+
## [0.35.4] - 2026-08-13
|
|
6
|
+
|
|
7
|
+
### Fixed
|
|
8
|
+
|
|
9
|
+
- **JSON decode error handling in enrichment pipeline.** All API calls to TMDB,
|
|
10
|
+
OMDB, and MediaCMS now catch `json.JSONDecodeError` in addition to HTTP errors,
|
|
11
|
+
preventing malformed responses from crashing enrichment jobs.
|
|
12
|
+
- Added error handling to `TMDBProvider` search methods
|
|
13
|
+
- Added error handling to `OMDBProvider` search methods
|
|
14
|
+
- Added error handling to CMS API calls in meta, title, and tags steps
|
|
15
|
+
- Enhanced `parse_meta_json` logging to capture malformed JSON for debugging
|
|
16
|
+
|
|
5
17
|
## [0.35.3] - 2026-08-13
|
|
6
18
|
|
|
7
19
|
### Added
|
|
@@ -110,5 +110,12 @@ class _EnrichmentMixin:
|
|
|
110
110
|
return None
|
|
111
111
|
try:
|
|
112
112
|
return json.loads(raw)
|
|
113
|
-
except (ValueError, TypeError):
|
|
113
|
+
except (ValueError, TypeError) as exc:
|
|
114
|
+
import logging
|
|
115
|
+
logger = logging.getLogger(__name__)
|
|
116
|
+
token = (row or {}).get("friendly_token", "?")
|
|
117
|
+
logger.warning(
|
|
118
|
+
"Failed to parse meta_json for %s: %s. Raw value (first 200 chars): %r",
|
|
119
|
+
token, exc, raw[:200] if isinstance(raw, str) else raw
|
|
120
|
+
)
|
|
114
121
|
return None
|
{kryten_webqueue-0.35.3 → kryten_webqueue-0.35.4}/kryten_webqueue/catalog/enrichment/providers.py
RENAMED
|
@@ -8,6 +8,7 @@ includes poster_url so art and meta steps can share a single provider call.
|
|
|
8
8
|
from __future__ import annotations
|
|
9
9
|
|
|
10
10
|
import difflib
|
|
11
|
+
import json
|
|
11
12
|
import logging
|
|
12
13
|
import re
|
|
13
14
|
from dataclasses import dataclass, field
|
|
@@ -144,7 +145,7 @@ class TMDBProvider:
|
|
|
144
145
|
movie = self._pick(resp2.json().get("results", []), title, None)
|
|
145
146
|
if movie:
|
|
146
147
|
return await self._fetch_details(movie, headers, auth)
|
|
147
|
-
except httpx.HTTPError as exc:
|
|
148
|
+
except (httpx.HTTPError, json.JSONDecodeError, ValueError) as exc:
|
|
148
149
|
logger.debug("TMDB search error for %r: %s", title, exc)
|
|
149
150
|
return MovieMetadata()
|
|
150
151
|
|
|
@@ -180,7 +181,7 @@ class TMDBProvider:
|
|
|
180
181
|
meta.year = air_date[:4] if air_date else None
|
|
181
182
|
meta.cast = [c["name"] for c in data.get("guest_stars", [])[:8]]
|
|
182
183
|
return meta
|
|
183
|
-
except httpx.HTTPError as exc:
|
|
184
|
+
except (httpx.HTTPError, json.JSONDecodeError, ValueError) as exc:
|
|
184
185
|
logger.debug(
|
|
185
186
|
"TMDB TV search error for %r S%02dE%02d: %s", show, season, episode, exc
|
|
186
187
|
)
|
|
@@ -226,7 +227,7 @@ class TMDBProvider:
|
|
|
226
227
|
meta.tmdb_rating = f"{vote:.1f}/10"
|
|
227
228
|
meta.imdb_id = d.get("imdb_id", "")
|
|
228
229
|
meta.studio = [c["name"] for c in d.get("production_companies", [])[:3]]
|
|
229
|
-
except httpx.HTTPError:
|
|
230
|
+
except (httpx.HTTPError, json.JSONDecodeError, ValueError):
|
|
230
231
|
pass
|
|
231
232
|
|
|
232
233
|
try:
|
|
@@ -253,7 +254,7 @@ class TMDBProvider:
|
|
|
253
254
|
x["name"] for x in crew if x.get("job") == "Original Music Composer"
|
|
254
255
|
][:3]
|
|
255
256
|
meta.editor = [x["name"] for x in crew if x.get("job") == "Editor"][:3]
|
|
256
|
-
except httpx.HTTPError:
|
|
257
|
+
except (httpx.HTTPError, json.JSONDecodeError, ValueError):
|
|
257
258
|
pass
|
|
258
259
|
|
|
259
260
|
return meta
|
|
@@ -306,7 +307,7 @@ class OMDBProvider:
|
|
|
306
307
|
):
|
|
307
308
|
return MovieMetadata()
|
|
308
309
|
return self._parse(data)
|
|
309
|
-
except httpx.HTTPError as exc:
|
|
310
|
+
except (httpx.HTTPError, json.JSONDecodeError, ValueError) as exc:
|
|
310
311
|
logger.debug("OMDB error for %r: %s", title, exc)
|
|
311
312
|
return MovieMetadata()
|
|
312
313
|
|
|
@@ -327,7 +328,7 @@ class OMDBProvider:
|
|
|
327
328
|
)
|
|
328
329
|
if resp.status_code == 200 and resp.json().get("Response") == "True":
|
|
329
330
|
return self._parse(resp.json())
|
|
330
|
-
except httpx.HTTPError:
|
|
331
|
+
except (httpx.HTTPError, json.JSONDecodeError, ValueError):
|
|
331
332
|
pass
|
|
332
333
|
return MovieMetadata()
|
|
333
334
|
|
{kryten_webqueue-0.35.3 → kryten_webqueue-0.35.4}/kryten_webqueue/catalog/enrichment/steps/meta.py
RENAMED
|
@@ -154,6 +154,19 @@ class MetaStep:
|
|
|
154
154
|
new_score = score_description(desc)
|
|
155
155
|
meta_json = json.dumps(self._meta_to_dict(meta))
|
|
156
156
|
|
|
157
|
+
# Validate round-trip before saving
|
|
158
|
+
try:
|
|
159
|
+
json.loads(meta_json)
|
|
160
|
+
except (ValueError, TypeError) as e:
|
|
161
|
+
logger.error(
|
|
162
|
+
"[meta] %s: generated malformed meta_json: %s. First 300 chars: %r",
|
|
163
|
+
cls.friendly_token,
|
|
164
|
+
e,
|
|
165
|
+
meta_json[:300],
|
|
166
|
+
)
|
|
167
|
+
result.record_error(f"{cls.friendly_token}: malformed meta_json ({e})")
|
|
168
|
+
continue
|
|
169
|
+
|
|
157
170
|
logger.info(
|
|
158
171
|
"[meta] %s: %r → score %d",
|
|
159
172
|
cls.friendly_token,
|
|
@@ -206,21 +219,24 @@ class MetaStep:
|
|
|
206
219
|
|
|
207
220
|
async def _push_description(self, token: str, desc: str) -> None:
|
|
208
221
|
url = f"{self._base}/api/v1/media/{token}"
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
222
|
+
try:
|
|
223
|
+
async with httpx.AsyncClient(
|
|
224
|
+
headers=self._cms_headers, timeout=_TIMEOUT
|
|
225
|
+
) as client:
|
|
226
|
+
resp = await client.get(url)
|
|
227
|
+
owner = resp.json().get("user") if resp.status_code == 200 else None
|
|
228
|
+
await client.put(url, data={"description": desc})
|
|
229
|
+
if owner:
|
|
230
|
+
await client.post(
|
|
231
|
+
f"{self._base}/api/v1/media/user/bulk_actions",
|
|
232
|
+
json={
|
|
233
|
+
"action": "change_owner",
|
|
234
|
+
"media_ids": [token],
|
|
235
|
+
"owner": owner,
|
|
236
|
+
},
|
|
237
|
+
)
|
|
238
|
+
except (httpx.HTTPError, json.JSONDecodeError, ValueError) as exc:
|
|
239
|
+
logger.warning("[meta] Failed to push description for %s: %s", token, exc)
|
|
224
240
|
|
|
225
241
|
async def _write_people(self, token: str, meta: MovieMetadata) -> None:
|
|
226
242
|
people: list[dict] = []
|
{kryten_webqueue-0.35.3 → kryten_webqueue-0.35.4}/kryten_webqueue/catalog/enrichment/steps/tags.py
RENAMED
|
@@ -2,6 +2,7 @@
|
|
|
2
2
|
|
|
3
3
|
from __future__ import annotations
|
|
4
4
|
|
|
5
|
+
import json
|
|
5
6
|
import logging
|
|
6
7
|
import re
|
|
7
8
|
from datetime import datetime, UTC
|
|
@@ -108,35 +109,41 @@ class TagsStep:
|
|
|
108
109
|
self, client: httpx.AsyncClient, token: str, new_tags: list[str]
|
|
109
110
|
) -> bool:
|
|
110
111
|
url = f"{self._base}/api/v1/media/{token}"
|
|
111
|
-
|
|
112
|
-
|
|
112
|
+
try:
|
|
113
|
+
resp = await client.get(url)
|
|
114
|
+
if resp.status_code != 200:
|
|
115
|
+
return False
|
|
116
|
+
data = resp.json()
|
|
117
|
+
owner = data.get("user")
|
|
118
|
+
current = {
|
|
119
|
+
(t.get("title") if isinstance(t, dict) else t)
|
|
120
|
+
for t in (data.get("tags_info") or [])
|
|
121
|
+
}
|
|
122
|
+
to_add = [t for t in new_tags if t not in current]
|
|
123
|
+
if not to_add:
|
|
124
|
+
return False
|
|
125
|
+
merged = list(current | set(to_add))
|
|
126
|
+
put = await client.put(url, data={"tags": ",".join(merged)})
|
|
127
|
+
if put.status_code in (200, 201) and owner:
|
|
128
|
+
await client.post(
|
|
129
|
+
f"{self._base}/api/v1/media/user/bulk_actions",
|
|
130
|
+
json={"action": "change_owner", "media_ids": [token], "owner": owner},
|
|
131
|
+
)
|
|
132
|
+
return put.status_code in (200, 201)
|
|
133
|
+
except (httpx.HTTPError, json.JSONDecodeError, ValueError):
|
|
113
134
|
return False
|
|
114
|
-
data = resp.json()
|
|
115
|
-
owner = data.get("user")
|
|
116
|
-
current = {
|
|
117
|
-
(t.get("title") if isinstance(t, dict) else t)
|
|
118
|
-
for t in (data.get("tags_info") or [])
|
|
119
|
-
}
|
|
120
|
-
to_add = [t for t in new_tags if t not in current]
|
|
121
|
-
if not to_add:
|
|
122
|
-
return False
|
|
123
|
-
merged = list(current | set(to_add))
|
|
124
|
-
put = await client.put(url, data={"tags": ",".join(merged)})
|
|
125
|
-
if put.status_code in (200, 201) and owner:
|
|
126
|
-
await client.post(
|
|
127
|
-
f"{self._base}/api/v1/media/user/bulk_actions",
|
|
128
|
-
json={"action": "change_owner", "media_ids": [token], "owner": owner},
|
|
129
|
-
)
|
|
130
|
-
return put.status_code in (200, 201)
|
|
131
135
|
|
|
132
136
|
async def _reverse_sync(self, client: httpx.AsyncClient, token: str) -> None:
|
|
133
137
|
"""Insert any CMS-only tags into the local catalog_tags table."""
|
|
134
138
|
url = f"{self._base}/api/v1/media/{token}"
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
139
|
+
try:
|
|
140
|
+
resp = await client.get(url)
|
|
141
|
+
if resp.status_code != 200:
|
|
142
|
+
return
|
|
143
|
+
data = resp.json()
|
|
144
|
+
for t in data.get("tags_info") or []:
|
|
145
|
+
name = t.get("title") if isinstance(t, dict) else t
|
|
146
|
+
if name:
|
|
147
|
+
await self._db.add_catalog_tag(token, str(name))
|
|
148
|
+
except (httpx.HTTPError, json.JSONDecodeError, ValueError) as exc:
|
|
149
|
+
logger.warning("[tags] Failed reverse-sync for %s: %s", token, exc)
|
{kryten_webqueue-0.35.3 → kryten_webqueue-0.35.4}/kryten_webqueue/catalog/enrichment/steps/title.py
RENAMED
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
"""Step: title — normalise and reformat CMS titles per content type."""
|
|
2
2
|
|
|
3
|
+
import json
|
|
3
4
|
import logging
|
|
4
5
|
from datetime import datetime, UTC
|
|
5
6
|
|
|
@@ -122,5 +123,5 @@ class TitleStep:
|
|
|
122
123
|
},
|
|
123
124
|
)
|
|
124
125
|
return ok
|
|
125
|
-
except httpx.HTTPError:
|
|
126
|
+
except (httpx.HTTPError, json.JSONDecodeError, ValueError):
|
|
126
127
|
return False
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
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.3 → kryten_webqueue-0.35.4}/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.3 → kryten_webqueue-0.35.4}/kryten_webqueue/catalog/enrichment/__init__.py
RENAMED
|
File without changes
|
{kryten_webqueue-0.35.3 → kryten_webqueue-0.35.4}/kryten_webqueue/catalog/enrichment/classify.py
RENAMED
|
File without changes
|
{kryten_webqueue-0.35.3 → kryten_webqueue-0.35.4}/kryten_webqueue/catalog/enrichment/normalise.py
RENAMED
|
File without changes
|
{kryten_webqueue-0.35.3 → kryten_webqueue-0.35.4}/kryten_webqueue/catalog/enrichment/pipeline.py
RENAMED
|
File without changes
|
{kryten_webqueue-0.35.3 → kryten_webqueue-0.35.4}/kryten_webqueue/catalog/enrichment/report.py
RENAMED
|
File without changes
|
|
File without changes
|
{kryten_webqueue-0.35.3 → kryten_webqueue-0.35.4}/kryten_webqueue/catalog/enrichment/steps/art.py
RENAMED
|
File without changes
|
|
File without changes
|
{kryten_webqueue-0.35.3 → kryten_webqueue-0.35.4}/kryten_webqueue/catalog/enrichment/steps/sync.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{kryten_webqueue-0.35.3 → kryten_webqueue-0.35.4}/kryten_webqueue/integrations/cmsutils/__init__.py
RENAMED
|
File without changes
|
{kryten_webqueue-0.35.3 → kryten_webqueue-0.35.4}/kryten_webqueue/integrations/cmsutils/_common.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
{kryten_webqueue-0.35.3 → kryten_webqueue-0.35.4}/kryten_webqueue/integrations/cmsutils/enrichtv.py
RENAMED
|
File without changes
|
{kryten_webqueue-0.35.3 → kryten_webqueue-0.35.4}/kryten_webqueue/integrations/cmsutils/fetchurls.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
{kryten_webqueue-0.35.3 → kryten_webqueue-0.35.4}/kryten_webqueue/integrations/ytpipe/__init__.py
RENAMED
|
File without changes
|
{kryten_webqueue-0.35.3 → kryten_webqueue-0.35.4}/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.3 → kryten_webqueue-0.35.4}/kryten_webqueue/routes/admin_job_schedules.py
RENAMED
|
File without changes
|
|
File without changes
|
{kryten_webqueue-0.35.3 → kryten_webqueue-0.35.4}/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.3 → kryten_webqueue-0.35.4}/kryten_webqueue/static/js/admin-playlists.js
RENAMED
|
File without changes
|
|
File without changes
|
{kryten_webqueue-0.35.3 → kryten_webqueue-0.35.4}/kryten_webqueue/static/js/admin-queue-mgmt.js
RENAMED
|
File without changes
|
{kryten_webqueue-0.35.3 → kryten_webqueue-0.35.4}/kryten_webqueue/static/js/admin-schedules.js
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
{kryten_webqueue-0.35.3 → kryten_webqueue-0.35.4}/kryten_webqueue/templates/admin/index.html
RENAMED
|
File without changes
|
{kryten_webqueue-0.35.3 → kryten_webqueue-0.35.4}/kryten_webqueue/templates/admin/playlists.html
RENAMED
|
File without changes
|
{kryten_webqueue-0.35.3 → kryten_webqueue-0.35.4}/kryten_webqueue/templates/admin/promos.html
RENAMED
|
File without changes
|
{kryten_webqueue-0.35.3 → kryten_webqueue-0.35.4}/kryten_webqueue/templates/admin/queue_mgmt.html
RENAMED
|
File without changes
|
{kryten_webqueue-0.35.3 → kryten_webqueue-0.35.4}/kryten_webqueue/templates/admin/schedules.html
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
{kryten_webqueue-0.35.3 → kryten_webqueue-0.35.4}/kryten_webqueue/templates/catalog/browse.html
RENAMED
|
File without changes
|
{kryten_webqueue-0.35.3 → kryten_webqueue-0.35.4}/kryten_webqueue/templates/catalog/item_detail.html
RENAMED
|
File without changes
|
|
File without changes
|
{kryten_webqueue-0.35.3 → kryten_webqueue-0.35.4}/kryten_webqueue/templates/feedback/index.html
RENAMED
|
File without changes
|
{kryten_webqueue-0.35.3 → kryten_webqueue-0.35.4}/kryten_webqueue/templates/queue/index.html
RENAMED
|
File without changes
|
|
File without changes
|
{kryten_webqueue-0.35.3 → kryten_webqueue-0.35.4}/kryten_webqueue/templates/user/dashboard.html
RENAMED
|
File without changes
|
{kryten_webqueue-0.35.3 → kryten_webqueue-0.35.4}/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
|