kryten-webqueue 0.35.1__tar.gz → 0.35.3__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.1 → kryten_webqueue-0.35.3}/CHANGELOG.md +33 -0
- {kryten_webqueue-0.35.1 → kryten_webqueue-0.35.3}/PKG-INFO +1 -1
- {kryten_webqueue-0.35.1 → kryten_webqueue-0.35.3}/kryten_webqueue/static/css/main.css +14 -1
- {kryten_webqueue-0.35.1 → kryten_webqueue-0.35.3}/kryten_webqueue/static/js/admin.js +117 -11
- {kryten_webqueue-0.35.1 → kryten_webqueue-0.35.3}/pyproject.toml +1 -1
- {kryten_webqueue-0.35.1 → kryten_webqueue-0.35.3}/.github/workflows/gitleaks.yml +0 -0
- {kryten_webqueue-0.35.1 → kryten_webqueue-0.35.3}/.github/workflows/python-publish.yml +0 -0
- {kryten_webqueue-0.35.1 → kryten_webqueue-0.35.3}/.github/workflows/release.yml +0 -0
- {kryten_webqueue-0.35.1 → kryten_webqueue-0.35.3}/.gitignore +0 -0
- {kryten_webqueue-0.35.1 → kryten_webqueue-0.35.3}/.gitleaks.toml +0 -0
- {kryten_webqueue-0.35.1 → kryten_webqueue-0.35.3}/.pre-commit-config.yaml +0 -0
- {kryten_webqueue-0.35.1 → kryten_webqueue-0.35.3}/AGENT-WORKFLOW-GUIDE.md +0 -0
- {kryten_webqueue-0.35.1 → kryten_webqueue-0.35.3}/README.md +0 -0
- {kryten_webqueue-0.35.1 → kryten_webqueue-0.35.3}/config.example.json +0 -0
- {kryten_webqueue-0.35.1 → kryten_webqueue-0.35.3}/deploy/kryten-webqueue.service +0 -0
- {kryten_webqueue-0.35.1 → kryten_webqueue-0.35.3}/deploy/nginx-queue.conf +0 -0
- {kryten_webqueue-0.35.1 → kryten_webqueue-0.35.3}/docs/IMPLEMENTATION_SPEC.md +0 -0
- {kryten_webqueue-0.35.1 → kryten_webqueue-0.35.3}/docs/IMPL_API_GATE.md +0 -0
- {kryten_webqueue-0.35.1 → kryten_webqueue-0.35.3}/docs/IMPL_ECONOMY.md +0 -0
- {kryten_webqueue-0.35.1 → kryten_webqueue-0.35.3}/docs/IMPL_KRYTEN_PY.md +0 -0
- {kryten_webqueue-0.35.1 → kryten_webqueue-0.35.3}/docs/IMPL_ROBOT.md +0 -0
- {kryten_webqueue-0.35.1 → kryten_webqueue-0.35.3}/docs/Kryten-Economy Service Quality Survey Report at v0.13.0.md +0 -0
- {kryten_webqueue-0.35.1 → kryten_webqueue-0.35.3}/docs/Kryten-Webqueue Service Quality Survey Report at v0.27.1.md +0 -0
- {kryten_webqueue-0.35.1 → kryten_webqueue-0.35.3}/docs/Log for incorrect promo insertion problem.txt +0 -0
- {kryten_webqueue-0.35.1 → kryten_webqueue-0.35.3}/docs/PLAN_PRESENCE_AND_PROMOS.md +0 -0
- {kryten_webqueue-0.35.1 → kryten_webqueue-0.35.3}/docs/PRE_PLAN_GAPS.md +0 -0
- {kryten_webqueue-0.35.1 → kryten_webqueue-0.35.3}/docs/PRODUCT_PLAN.md +0 -0
- {kryten_webqueue-0.35.1 → kryten_webqueue-0.35.3}/docs/SPEC_CATALOG_ENRICHMENT_PIPELINE.md +0 -0
- {kryten_webqueue-0.35.1 → kryten_webqueue-0.35.3}/docs/SPEC_EMOTE_REHOST.md +0 -0
- {kryten_webqueue-0.35.1 → kryten_webqueue-0.35.3}/docs/SPEC_JOBS_AND_BROWSE.md +0 -0
- {kryten_webqueue-0.35.1 → kryten_webqueue-0.35.3}/docs/UX_POLISH_PLAN.md +0 -0
- {kryten_webqueue-0.35.1 → kryten_webqueue-0.35.3}/kryten_webqueue/__init__.py +0 -0
- {kryten_webqueue-0.35.1 → kryten_webqueue-0.35.3}/kryten_webqueue/__main__.py +0 -0
- {kryten_webqueue-0.35.1 → kryten_webqueue-0.35.3}/kryten_webqueue/api_gate/__init__.py +0 -0
- {kryten_webqueue-0.35.1 → kryten_webqueue-0.35.3}/kryten_webqueue/api_gate/client.py +0 -0
- {kryten_webqueue-0.35.1 → kryten_webqueue-0.35.3}/kryten_webqueue/app.py +0 -0
- {kryten_webqueue-0.35.1 → kryten_webqueue-0.35.3}/kryten_webqueue/auth/__init__.py +0 -0
- {kryten_webqueue-0.35.1 → kryten_webqueue-0.35.3}/kryten_webqueue/auth/otp.py +0 -0
- {kryten_webqueue-0.35.1 → kryten_webqueue-0.35.3}/kryten_webqueue/auth/rate_limit.py +0 -0
- {kryten_webqueue-0.35.1 → kryten_webqueue-0.35.3}/kryten_webqueue/auth/session.py +0 -0
- {kryten_webqueue-0.35.1 → kryten_webqueue-0.35.3}/kryten_webqueue/catalog/__init__.py +0 -0
- {kryten_webqueue-0.35.1 → kryten_webqueue-0.35.3}/kryten_webqueue/catalog/db/__init__.py +0 -0
- {kryten_webqueue-0.35.1 → kryten_webqueue-0.35.3}/kryten_webqueue/catalog/db/_catalog.py +0 -0
- {kryten_webqueue-0.35.1 → kryten_webqueue-0.35.3}/kryten_webqueue/catalog/db/_connection.py +0 -0
- {kryten_webqueue-0.35.1 → kryten_webqueue-0.35.3}/kryten_webqueue/catalog/db/_enrichment.py +0 -0
- {kryten_webqueue-0.35.1 → kryten_webqueue-0.35.3}/kryten_webqueue/catalog/db/_feedback.py +0 -0
- {kryten_webqueue-0.35.1 → kryten_webqueue-0.35.3}/kryten_webqueue/catalog/db/_people.py +0 -0
- {kryten_webqueue-0.35.1 → kryten_webqueue-0.35.3}/kryten_webqueue/catalog/db/_playlists.py +0 -0
- {kryten_webqueue-0.35.1 → kryten_webqueue-0.35.3}/kryten_webqueue/catalog/db/_queue.py +0 -0
- {kryten_webqueue-0.35.1 → kryten_webqueue-0.35.3}/kryten_webqueue/catalog/db/_watchlist.py +0 -0
- {kryten_webqueue-0.35.1 → kryten_webqueue-0.35.3}/kryten_webqueue/catalog/enrichment/__init__.py +0 -0
- {kryten_webqueue-0.35.1 → kryten_webqueue-0.35.3}/kryten_webqueue/catalog/enrichment/classify.py +0 -0
- {kryten_webqueue-0.35.1 → kryten_webqueue-0.35.3}/kryten_webqueue/catalog/enrichment/normalise.py +0 -0
- {kryten_webqueue-0.35.1 → kryten_webqueue-0.35.3}/kryten_webqueue/catalog/enrichment/pipeline.py +0 -0
- {kryten_webqueue-0.35.1 → kryten_webqueue-0.35.3}/kryten_webqueue/catalog/enrichment/providers.py +0 -0
- {kryten_webqueue-0.35.1 → kryten_webqueue-0.35.3}/kryten_webqueue/catalog/enrichment/report.py +0 -0
- {kryten_webqueue-0.35.1 → kryten_webqueue-0.35.3}/kryten_webqueue/catalog/enrichment/steps/__init__.py +0 -0
- {kryten_webqueue-0.35.1 → kryten_webqueue-0.35.3}/kryten_webqueue/catalog/enrichment/steps/art.py +0 -0
- {kryten_webqueue-0.35.1 → kryten_webqueue-0.35.3}/kryten_webqueue/catalog/enrichment/steps/categories.py +0 -0
- {kryten_webqueue-0.35.1 → kryten_webqueue-0.35.3}/kryten_webqueue/catalog/enrichment/steps/meta.py +0 -0
- {kryten_webqueue-0.35.1 → kryten_webqueue-0.35.3}/kryten_webqueue/catalog/enrichment/steps/sync.py +0 -0
- {kryten_webqueue-0.35.1 → kryten_webqueue-0.35.3}/kryten_webqueue/catalog/enrichment/steps/tags.py +0 -0
- {kryten_webqueue-0.35.1 → kryten_webqueue-0.35.3}/kryten_webqueue/catalog/enrichment/steps/title.py +0 -0
- {kryten_webqueue-0.35.1 → kryten_webqueue-0.35.3}/kryten_webqueue/catalog/images.py +0 -0
- {kryten_webqueue-0.35.1 → kryten_webqueue-0.35.3}/kryten_webqueue/catalog/mediacms.py +0 -0
- {kryten_webqueue-0.35.1 → kryten_webqueue-0.35.3}/kryten_webqueue/catalog/sync.py +0 -0
- {kryten_webqueue-0.35.1 → kryten_webqueue-0.35.3}/kryten_webqueue/config.py +0 -0
- {kryten_webqueue-0.35.1 → kryten_webqueue-0.35.3}/kryten_webqueue/integrations/__init__.py +0 -0
- {kryten_webqueue-0.35.1 → kryten_webqueue-0.35.3}/kryten_webqueue/integrations/cmsutils/__init__.py +0 -0
- {kryten_webqueue-0.35.1 → kryten_webqueue-0.35.3}/kryten_webqueue/integrations/cmsutils/_common.py +0 -0
- {kryten_webqueue-0.35.1 → kryten_webqueue-0.35.3}/kryten_webqueue/integrations/cmsutils/enrichmeta.py +0 -0
- {kryten_webqueue-0.35.1 → kryten_webqueue-0.35.3}/kryten_webqueue/integrations/cmsutils/enrichtitles.py +0 -0
- {kryten_webqueue-0.35.1 → kryten_webqueue-0.35.3}/kryten_webqueue/integrations/cmsutils/enrichtv.py +0 -0
- {kryten_webqueue-0.35.1 → kryten_webqueue-0.35.3}/kryten_webqueue/integrations/cmsutils/fetchurls.py +0 -0
- {kryten_webqueue-0.35.1 → kryten_webqueue-0.35.3}/kryten_webqueue/integrations/cmsutils/motdposters.py +0 -0
- {kryten_webqueue-0.35.1 → kryten_webqueue-0.35.3}/kryten_webqueue/integrations/cmsutils/playedmovies.py +0 -0
- {kryten_webqueue-0.35.1 → kryten_webqueue-0.35.3}/kryten_webqueue/integrations/ytpipe/__init__.py +0 -0
- {kryten_webqueue-0.35.1 → kryten_webqueue-0.35.3}/kryten_webqueue/integrations/ytpipe/downloader.py +0 -0
- {kryten_webqueue-0.35.1 → kryten_webqueue-0.35.3}/kryten_webqueue/jobs/__init__.py +0 -0
- {kryten_webqueue-0.35.1 → kryten_webqueue-0.35.3}/kryten_webqueue/jobs/fetchurls_auth.py +0 -0
- {kryten_webqueue-0.35.1 → kryten_webqueue-0.35.3}/kryten_webqueue/jobs/job_scheduler.py +0 -0
- {kryten_webqueue-0.35.1 → kryten_webqueue-0.35.3}/kryten_webqueue/jobs/manager.py +0 -0
- {kryten_webqueue-0.35.1 → kryten_webqueue-0.35.3}/kryten_webqueue/jobs/rehost_emotes.py +0 -0
- {kryten_webqueue-0.35.1 → kryten_webqueue-0.35.3}/kryten_webqueue/jobs/tasks.py +0 -0
- {kryten_webqueue-0.35.1 → kryten_webqueue-0.35.3}/kryten_webqueue/logging_config.py +0 -0
- {kryten_webqueue-0.35.1 → kryten_webqueue-0.35.3}/kryten_webqueue/playlists/__init__.py +0 -0
- {kryten_webqueue-0.35.1 → kryten_webqueue-0.35.3}/kryten_webqueue/playlists/bulk_add.py +0 -0
- {kryten_webqueue-0.35.1 → kryten_webqueue-0.35.3}/kryten_webqueue/playlists/fire.py +0 -0
- {kryten_webqueue-0.35.1 → kryten_webqueue-0.35.3}/kryten_webqueue/playlists/importer.py +0 -0
- {kryten_webqueue-0.35.1 → kryten_webqueue-0.35.3}/kryten_webqueue/playlists/ordering.py +0 -0
- {kryten_webqueue-0.35.1 → kryten_webqueue-0.35.3}/kryten_webqueue/playlists/scheduler.py +0 -0
- {kryten_webqueue-0.35.1 → kryten_webqueue-0.35.3}/kryten_webqueue/promos/__init__.py +0 -0
- {kryten_webqueue-0.35.1 → kryten_webqueue-0.35.3}/kryten_webqueue/promos/director.py +0 -0
- {kryten_webqueue-0.35.1 → kryten_webqueue-0.35.3}/kryten_webqueue/queue/__init__.py +0 -0
- {kryten_webqueue-0.35.1 → kryten_webqueue-0.35.3}/kryten_webqueue/queue/completion.py +0 -0
- {kryten_webqueue-0.35.1 → kryten_webqueue-0.35.3}/kryten_webqueue/queue/ordering.py +0 -0
- {kryten_webqueue-0.35.1 → kryten_webqueue-0.35.3}/kryten_webqueue/queue/poller.py +0 -0
- {kryten_webqueue-0.35.1 → kryten_webqueue-0.35.3}/kryten_webqueue/queue/presence.py +0 -0
- {kryten_webqueue-0.35.1 → kryten_webqueue-0.35.3}/kryten_webqueue/queue/race_poller.py +0 -0
- {kryten_webqueue-0.35.1 → kryten_webqueue-0.35.3}/kryten_webqueue/queue/shadow.py +0 -0
- {kryten_webqueue-0.35.1 → kryten_webqueue-0.35.3}/kryten_webqueue/routes/__init__.py +0 -0
- {kryten_webqueue-0.35.1 → kryten_webqueue-0.35.3}/kryten_webqueue/routes/admin_catalog.py +0 -0
- {kryten_webqueue-0.35.1 → kryten_webqueue-0.35.3}/kryten_webqueue/routes/admin_feedback.py +0 -0
- {kryten_webqueue-0.35.1 → kryten_webqueue-0.35.3}/kryten_webqueue/routes/admin_job_schedules.py +0 -0
- {kryten_webqueue-0.35.1 → kryten_webqueue-0.35.3}/kryten_webqueue/routes/admin_jobs.py +0 -0
- {kryten_webqueue-0.35.1 → kryten_webqueue-0.35.3}/kryten_webqueue/routes/admin_moderation.py +0 -0
- {kryten_webqueue-0.35.1 → kryten_webqueue-0.35.3}/kryten_webqueue/routes/admin_playlists.py +0 -0
- {kryten_webqueue-0.35.1 → kryten_webqueue-0.35.3}/kryten_webqueue/routes/admin_promos.py +0 -0
- {kryten_webqueue-0.35.1 → kryten_webqueue-0.35.3}/kryten_webqueue/routes/admin_queue.py +0 -0
- {kryten_webqueue-0.35.1 → kryten_webqueue-0.35.3}/kryten_webqueue/routes/admin_schedules.py +0 -0
- {kryten_webqueue-0.35.1 → kryten_webqueue-0.35.3}/kryten_webqueue/routes/auth.py +0 -0
- {kryten_webqueue-0.35.1 → kryten_webqueue-0.35.3}/kryten_webqueue/routes/catalog.py +0 -0
- {kryten_webqueue-0.35.1 → kryten_webqueue-0.35.3}/kryten_webqueue/routes/feedback.py +0 -0
- {kryten_webqueue-0.35.1 → kryten_webqueue-0.35.3}/kryten_webqueue/routes/pages.py +0 -0
- {kryten_webqueue-0.35.1 → kryten_webqueue-0.35.3}/kryten_webqueue/routes/queue.py +0 -0
- {kryten_webqueue-0.35.1 → kryten_webqueue-0.35.3}/kryten_webqueue/routes/user.py +0 -0
- {kryten_webqueue-0.35.1 → kryten_webqueue-0.35.3}/kryten_webqueue/static/js/admin-playlists.js +0 -0
- {kryten_webqueue-0.35.1 → kryten_webqueue-0.35.3}/kryten_webqueue/static/js/admin-promos.js +0 -0
- {kryten_webqueue-0.35.1 → kryten_webqueue-0.35.3}/kryten_webqueue/static/js/admin-queue-mgmt.js +0 -0
- {kryten_webqueue-0.35.1 → kryten_webqueue-0.35.3}/kryten_webqueue/static/js/admin-schedules.js +0 -0
- {kryten_webqueue-0.35.1 → kryten_webqueue-0.35.3}/kryten_webqueue/static/js/main.js +0 -0
- {kryten_webqueue-0.35.1 → kryten_webqueue-0.35.3}/kryten_webqueue/templates/admin/index.html +0 -0
- {kryten_webqueue-0.35.1 → kryten_webqueue-0.35.3}/kryten_webqueue/templates/admin/playlists.html +0 -0
- {kryten_webqueue-0.35.1 → kryten_webqueue-0.35.3}/kryten_webqueue/templates/admin/promos.html +0 -0
- {kryten_webqueue-0.35.1 → kryten_webqueue-0.35.3}/kryten_webqueue/templates/admin/queue_mgmt.html +0 -0
- {kryten_webqueue-0.35.1 → kryten_webqueue-0.35.3}/kryten_webqueue/templates/admin/schedules.html +0 -0
- {kryten_webqueue-0.35.1 → kryten_webqueue-0.35.3}/kryten_webqueue/templates/auth/login.html +0 -0
- {kryten_webqueue-0.35.1 → kryten_webqueue-0.35.3}/kryten_webqueue/templates/base.html +0 -0
- {kryten_webqueue-0.35.1 → kryten_webqueue-0.35.3}/kryten_webqueue/templates/catalog/browse.html +0 -0
- {kryten_webqueue-0.35.1 → kryten_webqueue-0.35.3}/kryten_webqueue/templates/catalog/item_detail.html +0 -0
- {kryten_webqueue-0.35.1 → kryten_webqueue-0.35.3}/kryten_webqueue/templates/catalog/item_not_found.html +0 -0
- {kryten_webqueue-0.35.1 → kryten_webqueue-0.35.3}/kryten_webqueue/templates/feedback/index.html +0 -0
- {kryten_webqueue-0.35.1 → kryten_webqueue-0.35.3}/kryten_webqueue/templates/queue/index.html +0 -0
- {kryten_webqueue-0.35.1 → kryten_webqueue-0.35.3}/kryten_webqueue/templates/race.html +0 -0
- {kryten_webqueue-0.35.1 → kryten_webqueue-0.35.3}/kryten_webqueue/templates/user/dashboard.html +0 -0
- {kryten_webqueue-0.35.1 → kryten_webqueue-0.35.3}/kryten_webqueue/templates/user/my_list.html +0 -0
- {kryten_webqueue-0.35.1 → kryten_webqueue-0.35.3}/kryten_webqueue/ws/__init__.py +0 -0
- {kryten_webqueue-0.35.1 → kryten_webqueue-0.35.3}/kryten_webqueue/ws/handler.py +0 -0
- {kryten_webqueue-0.35.1 → kryten_webqueue-0.35.3}/kryten_webqueue/ws/manager.py +0 -0
- {kryten_webqueue-0.35.1 → kryten_webqueue-0.35.3}/tests/__init__.py +0 -0
- {kryten_webqueue-0.35.1 → kryten_webqueue-0.35.3}/tests/test_classify.py +0 -0
- {kryten_webqueue-0.35.1 → kryten_webqueue-0.35.3}/tests/test_config_persistence.py +0 -0
- {kryten_webqueue-0.35.1 → kryten_webqueue-0.35.3}/tests/test_feedback.py +0 -0
- {kryten_webqueue-0.35.1 → kryten_webqueue-0.35.3}/tests/test_fetchurls_sharepoint.py +0 -0
- {kryten_webqueue-0.35.1 → kryten_webqueue-0.35.3}/tests/test_people_facets.py +0 -0
- {kryten_webqueue-0.35.1 → kryten_webqueue-0.35.3}/tests/test_phase1.py +0 -0
- {kryten_webqueue-0.35.1 → kryten_webqueue-0.35.3}/tests/test_phase2_jobs.py +0 -0
- {kryten_webqueue-0.35.1 → kryten_webqueue-0.35.3}/tests/test_phase3_jobs.py +0 -0
- {kryten_webqueue-0.35.1 → kryten_webqueue-0.35.3}/tests/test_phase4_live_fixes.py +0 -0
- {kryten_webqueue-0.35.1 → kryten_webqueue-0.35.3}/tests/test_playlist_import.py +0 -0
- {kryten_webqueue-0.35.1 → kryten_webqueue-0.35.3}/tests/test_presence_refund.py +0 -0
- {kryten_webqueue-0.35.1 → kryten_webqueue-0.35.3}/tests/test_promo_director.py +0 -0
- {kryten_webqueue-0.35.1 → kryten_webqueue-0.35.3}/tests/test_promo_pool_exclusion.py +0 -0
- {kryten_webqueue-0.35.1 → kryten_webqueue-0.35.3}/tests/test_providers.py +0 -0
- {kryten_webqueue-0.35.1 → kryten_webqueue-0.35.3}/tests/test_queue_announce.py +0 -0
- {kryten_webqueue-0.35.1 → kryten_webqueue-0.35.3}/tests/test_race_poller.py +0 -0
- {kryten_webqueue-0.35.1 → kryten_webqueue-0.35.3}/tests/test_recently_played_hide.py +0 -0
- {kryten_webqueue-0.35.1 → kryten_webqueue-0.35.3}/tests/test_save_results_to_playlist.py +0 -0
- {kryten_webqueue-0.35.1 → kryten_webqueue-0.35.3}/tests/test_schedule_lock.py +0 -0
- {kryten_webqueue-0.35.1 → kryten_webqueue-0.35.3}/tests/test_search_facets.py +0 -0
- {kryten_webqueue-0.35.1 → kryten_webqueue-0.35.3}/tests/test_title_normalization.py +0 -0
- {kryten_webqueue-0.35.1 → kryten_webqueue-0.35.3}/tests/test_watchlist.py +0 -0
|
@@ -2,6 +2,39 @@
|
|
|
2
2
|
|
|
3
3
|
## [Unreleased]
|
|
4
4
|
|
|
5
|
+
## [0.35.3] - 2026-08-13
|
|
6
|
+
|
|
7
|
+
### Added
|
|
8
|
+
|
|
9
|
+
- **Job run detail view.** Every row in the "Recent Job Runs" table now has an
|
|
10
|
+
ℹ button that opens a modal with the full output for that run.
|
|
11
|
+
- **Pipeline enrichment reports** are rendered as a per-step table
|
|
12
|
+
(Processed / Changed / Skipped / Failed) with any per-step error messages
|
|
13
|
+
shown inline beneath their row.
|
|
14
|
+
- **In-progress snapshots** are clearly labelled as such with a ⏳ indicator
|
|
15
|
+
and show the last heartbeat values while the job is still running.
|
|
16
|
+
- **Legacy / other job results** fall back to pretty-printed JSON.
|
|
17
|
+
- **Summary column** now understands the `catalog_enrich` report format and
|
|
18
|
+
shows a compact per-step summary (e.g. `classify: 5200✓ · meta: 1500✓ (42s)`).
|
|
19
|
+
An ⏳ prefix marks an in-progress heartbeat.
|
|
20
|
+
- Runs table shows 15 rows (up from 10) and marks still-running rows with an
|
|
21
|
+
amber "running…" indicator instead of a blank ended-at cell.
|
|
22
|
+
|
|
23
|
+
## [0.35.2] - 2026-08-13
|
|
24
|
+
|
|
25
|
+
### Fixed
|
|
26
|
+
|
|
27
|
+
- **Job / schedule modals no longer clip off-screen.** The job-runner and
|
|
28
|
+
schedule parameter dialogs could grow taller than the viewport, pushing
|
|
29
|
+
the Cancel/Save/Run buttons below the fold where they were unreachable.
|
|
30
|
+
|
|
31
|
+
- `.modal-box` is now a flex column capped at `90vh` with `max-width`
|
|
32
|
+
widened from 420 px to 540 px.
|
|
33
|
+
- All scrollable content is wrapped in a `.modal-body` div that absorbs
|
|
34
|
+
the overflow; the action buttons are pinned at the bottom with a
|
|
35
|
+
separator line and `flex-shrink: 0`, so they are always reachable
|
|
36
|
+
regardless of how many parameters a job defines.
|
|
37
|
+
|
|
5
38
|
## [0.35.1] - 2026-08-13
|
|
6
39
|
|
|
7
40
|
### Fixed
|
|
@@ -1357,10 +1357,20 @@ a.np-chip {
|
|
|
1357
1357
|
box-shadow: var(--shadow);
|
|
1358
1358
|
padding: 1.5rem;
|
|
1359
1359
|
width: 100%;
|
|
1360
|
-
max-width:
|
|
1360
|
+
max-width: 540px;
|
|
1361
|
+
max-height: 90vh;
|
|
1362
|
+
display: flex;
|
|
1363
|
+
flex-direction: column;
|
|
1364
|
+
}
|
|
1365
|
+
.modal-body {
|
|
1366
|
+
overflow-y: auto;
|
|
1367
|
+
flex: 1;
|
|
1368
|
+
min-height: 0;
|
|
1369
|
+
padding-right: 0.25rem; /* breathing room beside scrollbar */
|
|
1361
1370
|
}
|
|
1362
1371
|
.modal-box h3 {
|
|
1363
1372
|
margin-bottom: 1rem;
|
|
1373
|
+
flex-shrink: 0;
|
|
1364
1374
|
}
|
|
1365
1375
|
.modal-actions {
|
|
1366
1376
|
display: flex;
|
|
@@ -1368,6 +1378,9 @@ a.np-chip {
|
|
|
1368
1378
|
justify-content: flex-end;
|
|
1369
1379
|
flex-wrap: wrap;
|
|
1370
1380
|
margin-top: 1.25rem;
|
|
1381
|
+
padding-top: 0.75rem;
|
|
1382
|
+
border-top: 1px solid var(--border);
|
|
1383
|
+
flex-shrink: 0;
|
|
1371
1384
|
}
|
|
1372
1385
|
.btn-secondary {
|
|
1373
1386
|
background: var(--bg-card);
|
|
@@ -86,7 +86,7 @@ async function openJobRunnerModal(job) {
|
|
|
86
86
|
overlay.innerHTML = `
|
|
87
87
|
<div class="modal-box" role="dialog" aria-modal="true">
|
|
88
88
|
<h3>Run: ${escapeHtml(job.label)}</h3>
|
|
89
|
-
<div class="job-params">${job.schema.map(f => _jobFieldHtml(f)).join('')}</div>
|
|
89
|
+
<div class="modal-body"><div class="job-params">${job.schema.map(f => _jobFieldHtml(f)).join('')}</div></div>
|
|
90
90
|
<div class="modal-actions">
|
|
91
91
|
<button class="btn btn-secondary" data-action="cancel">Cancel</button>
|
|
92
92
|
<button class="btn btn-primary" data-action="run">Run</button>
|
|
@@ -159,6 +159,7 @@ async function openScheduleModal(jobName) {
|
|
|
159
159
|
overlay.innerHTML = `
|
|
160
160
|
<div class="modal-box" role="dialog" aria-modal="true">
|
|
161
161
|
<h3>${existing ? 'Edit' : 'Create'} Schedule: ${escapeHtml(job.label)}</h3>
|
|
162
|
+
<div class="modal-body">
|
|
162
163
|
<label class="field">
|
|
163
164
|
<span>Cron expression <small style="font-weight:normal;opacity:.7">(min hour dom mon dow, UTC)</small></span>
|
|
164
165
|
<input type="text" id="sched-cron" placeholder="0 21 * * 4" value="${cronVal}" autocomplete="off">
|
|
@@ -168,6 +169,7 @@ async function openScheduleModal(jobName) {
|
|
|
168
169
|
<span>Active</span>
|
|
169
170
|
</label>
|
|
170
171
|
${paramFields ? `<details ${existing ? 'open' : ''}><summary style="cursor:pointer;margin:.5rem 0">Job parameters</summary><div class="job-params">${paramFields}</div></details>` : ''}
|
|
172
|
+
</div>
|
|
171
173
|
<div class="modal-actions">
|
|
172
174
|
<button class="btn btn-secondary" data-action="cancel">Cancel</button>
|
|
173
175
|
<button class="btn btn-primary" data-action="save">Save</button>
|
|
@@ -279,23 +281,33 @@ async function loadJobs() {
|
|
|
279
281
|
: '<p>No jobs registered</p>';
|
|
280
282
|
}
|
|
281
283
|
|
|
282
|
-
// Recent job-run history
|
|
283
|
-
const rResp = await fetch('/admin/jobs/runs?limit=
|
|
284
|
+
// Recent job-run history — table includes an expand button for full output
|
|
285
|
+
const rResp = await fetch('/admin/jobs/runs?limit=15');
|
|
284
286
|
if (rResp.ok) {
|
|
285
287
|
const runs = await rResp.json();
|
|
286
288
|
const el = document.getElementById('job-runs');
|
|
287
289
|
if (runs.length > 0) {
|
|
288
290
|
el.innerHTML = `<table class="admin-table">
|
|
289
|
-
<tr><th>Job</th><th>Started</th><th>Ended</th><th>Status</th><th>Detail</th></tr>
|
|
290
|
-
${runs.map(r =>
|
|
291
|
+
<tr><th>Job</th><th>Started</th><th>Ended</th><th>Status</th><th>Detail</th><th></th></tr>
|
|
292
|
+
${runs.map(r => {
|
|
293
|
+
const summary = escapeHtml(summarizeRunDetail(r.detail));
|
|
294
|
+
const hasDetail = r.detail && r.detail.length > 2;
|
|
295
|
+
const expandBtn = hasDetail
|
|
296
|
+
? `<button class="btn btn-sm" onclick="showRunDetail(${r.id})" title="View full output">\u2139</button>`
|
|
297
|
+
: '';
|
|
298
|
+
const endedCell = r.ended_at
|
|
299
|
+
? formatLocalDateTime(r.ended_at)
|
|
300
|
+
: `<span style="color:var(--warning)">running\u2026</span>`;
|
|
301
|
+
return `
|
|
291
302
|
<tr>
|
|
292
303
|
<td>${escapeHtml(r.job_name || '')}</td>
|
|
293
304
|
<td>${formatLocalDateTime(r.started_at)}</td>
|
|
294
|
-
<td>${
|
|
305
|
+
<td>${endedCell}</td>
|
|
295
306
|
<td><span class="job-status job-status-${escapeHtml(r.status || '')}">${escapeHtml(r.status || '')}</span></td>
|
|
296
|
-
<td class="job-detail">${
|
|
297
|
-
|
|
298
|
-
|
|
307
|
+
<td class="job-detail">${summary}</td>
|
|
308
|
+
<td>${expandBtn}</td>
|
|
309
|
+
</tr>`;
|
|
310
|
+
}).join('')}
|
|
299
311
|
</table>`;
|
|
300
312
|
} else {
|
|
301
313
|
el.innerHTML = '<p>No job runs yet</p>';
|
|
@@ -303,6 +315,81 @@ async function loadJobs() {
|
|
|
303
315
|
}
|
|
304
316
|
}
|
|
305
317
|
|
|
318
|
+
// Run-detail cache so we don't re-fetch on re-open.
|
|
319
|
+
const RUN_DETAIL_CACHE = {};
|
|
320
|
+
|
|
321
|
+
async function showRunDetail(runId) {
|
|
322
|
+
if (!RUN_DETAIL_CACHE[runId]) {
|
|
323
|
+
const resp = await fetch('/admin/jobs/runs?limit=50');
|
|
324
|
+
if (resp.ok) { (await resp.json()).forEach(r => { RUN_DETAIL_CACHE[r.id] = r; }); }
|
|
325
|
+
}
|
|
326
|
+
const run = RUN_DETAIL_CACHE[runId];
|
|
327
|
+
if (!run) { showToast('Run not found', 'error'); return; }
|
|
328
|
+
|
|
329
|
+
const existingModal = document.getElementById('run-detail-modal');
|
|
330
|
+
if (existingModal) existingModal.remove();
|
|
331
|
+
|
|
332
|
+
let d = null;
|
|
333
|
+
try { d = run.detail ? JSON.parse(run.detail) : null; } catch (e) {}
|
|
334
|
+
|
|
335
|
+
let bodyHtml;
|
|
336
|
+
if (d && d.steps_run && d.steps) {
|
|
337
|
+
// Pipeline enrichment final report — render as a table
|
|
338
|
+
const dryBadge = d.dry_run
|
|
339
|
+
? ' <span style="color:var(--warning);font-size:.8rem">(dry run \u2014 no writes)</span>' : '';
|
|
340
|
+
const elapsed = d.elapsed_sec ? ` \u00b7 ${d.elapsed_sec}s elapsed` : '';
|
|
341
|
+
const rowsHtml = d.steps_run.map(s => {
|
|
342
|
+
const r = d.steps[s];
|
|
343
|
+
if (!r) return '';
|
|
344
|
+
const errs = (r.errors || []).map(e =>
|
|
345
|
+
`<div style="font-size:.78rem;color:var(--danger);padding:.15rem 0">${escapeHtml(e)}</div>`
|
|
346
|
+
).join('');
|
|
347
|
+
return `<tr>
|
|
348
|
+
<td><strong>${escapeHtml(s)}</strong></td>
|
|
349
|
+
<td>${r.processed}</td>
|
|
350
|
+
<td>${r.changed}</td>
|
|
351
|
+
<td>${r.skipped}</td>
|
|
352
|
+
<td style="${r.failed ? 'color:var(--danger)' : ''}">${r.failed || 0}</td>
|
|
353
|
+
</tr>${errs ? `<tr><td colspan="5" style="padding:0 0 .5rem 1.5rem">${errs}</td></tr>` : ''}`;
|
|
354
|
+
}).join('');
|
|
355
|
+
bodyHtml = `
|
|
356
|
+
<p style="margin-bottom:.75rem">
|
|
357
|
+
Steps: <strong>${escapeHtml(d.steps_run.join(' \u2192 '))}</strong>${dryBadge}<br>
|
|
358
|
+
Total items: <strong>${(d.total_items || 0).toLocaleString()}</strong>${elapsed}
|
|
359
|
+
</p>
|
|
360
|
+
<table class="admin-table">
|
|
361
|
+
<tr><th>Step</th><th>Processed</th><th>Changed</th><th>Skipped</th><th>Failed</th></tr>
|
|
362
|
+
${rowsHtml}
|
|
363
|
+
</table>`;
|
|
364
|
+
} else if (d && d.step && typeof d.processed === 'number') {
|
|
365
|
+
// In-progress heartbeat snapshot
|
|
366
|
+
bodyHtml = `<p style="color:var(--warning)">\u23f3 Job still running — last progress snapshot:</p>
|
|
367
|
+
<pre style="white-space:pre-wrap;font-size:.82rem">${escapeHtml(JSON.stringify(d, null, 2))}</pre>`;
|
|
368
|
+
} else {
|
|
369
|
+
// Generic / legacy format
|
|
370
|
+
const raw = typeof run.detail === 'string' ? run.detail : JSON.stringify(run.detail, null, 2);
|
|
371
|
+
bodyHtml = `<pre style="white-space:pre-wrap;font-size:.82rem">${escapeHtml(raw)}</pre>`;
|
|
372
|
+
}
|
|
373
|
+
|
|
374
|
+
const overlay = document.createElement('div');
|
|
375
|
+
overlay.id = 'run-detail-modal';
|
|
376
|
+
overlay.className = 'modal-overlay';
|
|
377
|
+
overlay.innerHTML = `
|
|
378
|
+
<div class="modal-box" role="dialog" aria-modal="true">
|
|
379
|
+
<h3>${escapeHtml(run.job_name || 'Run')} \u2014 ${escapeHtml(run.status || '')}
|
|
380
|
+
<span style="font-size:.75rem;font-weight:400;opacity:.7">#${run.id}</span></h3>
|
|
381
|
+
<div class="modal-body">${bodyHtml}</div>
|
|
382
|
+
<div class="modal-actions">
|
|
383
|
+
<button class="btn btn-secondary" data-action="close">Close</button>
|
|
384
|
+
</div>
|
|
385
|
+
</div>`;
|
|
386
|
+
overlay.addEventListener('click', e => {
|
|
387
|
+
if (e.target === overlay || e.target.getAttribute('data-action') === 'close')
|
|
388
|
+
overlay.remove();
|
|
389
|
+
});
|
|
390
|
+
document.body.appendChild(overlay);
|
|
391
|
+
}
|
|
392
|
+
|
|
306
393
|
async function loadAdminData() {
|
|
307
394
|
// Queue status
|
|
308
395
|
const qResp = await fetch('/queue/state');
|
|
@@ -374,8 +461,7 @@ function connectAdminWebSocket() {
|
|
|
374
461
|
}, 30000);
|
|
375
462
|
}
|
|
376
463
|
|
|
377
|
-
// Summarize a job_runs.detail JSON blob for the history table.
|
|
378
|
-
// failure message, otherwise a compact success summary.
|
|
464
|
+
// Summarize a job_runs.detail JSON blob for the history table.
|
|
379
465
|
function summarizeRunDetail(detail) {
|
|
380
466
|
if (!detail) return '';
|
|
381
467
|
let d;
|
|
@@ -383,6 +469,26 @@ function summarizeRunDetail(detail) {
|
|
|
383
469
|
catch { return String(detail).slice(0, 160); }
|
|
384
470
|
if (d && d.error) return d.error;
|
|
385
471
|
if (d && typeof d === 'object') {
|
|
472
|
+
// Pipeline in-progress heartbeat
|
|
473
|
+
if (d.step && typeof d.processed === 'number') {
|
|
474
|
+
const bits = [`${d.step}: ${d.processed} processed`];
|
|
475
|
+
if (d.changed) bits.push(`${d.changed} changed`);
|
|
476
|
+
if (d.failed) bits.push(`${d.failed} failed`);
|
|
477
|
+
return '\u23f3 ' + bits.join(', ');
|
|
478
|
+
}
|
|
479
|
+
// Pipeline final report
|
|
480
|
+
if (d.steps_run && d.steps) {
|
|
481
|
+
const tag = d.dry_run ? ' [dry run]' : '';
|
|
482
|
+
const elapsed = d.elapsed_sec ? ` (${d.elapsed_sec}s)` : '';
|
|
483
|
+
const parts = d.steps_run.filter(s => d.steps[s] && d.steps[s].processed).map(s => {
|
|
484
|
+
const r = d.steps[s];
|
|
485
|
+
const bits = [];
|
|
486
|
+
if (r.changed) bits.push(`${r.changed}\u2713`);
|
|
487
|
+
if (r.failed) bits.push(`${r.failed}\u2717`);
|
|
488
|
+
return `${s}: ${bits.join(' ') || r.processed}`;
|
|
489
|
+
});
|
|
490
|
+
return parts.join(' \u00b7 ') + elapsed + tag;
|
|
491
|
+
}
|
|
386
492
|
const parts = [];
|
|
387
493
|
if (d.sheet) parts.push(d.sheet);
|
|
388
494
|
if (d.imported_playlists && d.imported_playlists.length) parts.push(`imported: ${d.imported_playlists.join(', ')}`);
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
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.1 → kryten_webqueue-0.35.3}/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
|
|
File without changes
|
{kryten_webqueue-0.35.1 → kryten_webqueue-0.35.3}/kryten_webqueue/catalog/enrichment/__init__.py
RENAMED
|
File without changes
|
{kryten_webqueue-0.35.1 → kryten_webqueue-0.35.3}/kryten_webqueue/catalog/enrichment/classify.py
RENAMED
|
File without changes
|
{kryten_webqueue-0.35.1 → kryten_webqueue-0.35.3}/kryten_webqueue/catalog/enrichment/normalise.py
RENAMED
|
File without changes
|
{kryten_webqueue-0.35.1 → kryten_webqueue-0.35.3}/kryten_webqueue/catalog/enrichment/pipeline.py
RENAMED
|
File without changes
|
{kryten_webqueue-0.35.1 → kryten_webqueue-0.35.3}/kryten_webqueue/catalog/enrichment/providers.py
RENAMED
|
File without changes
|
{kryten_webqueue-0.35.1 → kryten_webqueue-0.35.3}/kryten_webqueue/catalog/enrichment/report.py
RENAMED
|
File without changes
|
|
File without changes
|
{kryten_webqueue-0.35.1 → kryten_webqueue-0.35.3}/kryten_webqueue/catalog/enrichment/steps/art.py
RENAMED
|
File without changes
|
|
File without changes
|
{kryten_webqueue-0.35.1 → kryten_webqueue-0.35.3}/kryten_webqueue/catalog/enrichment/steps/meta.py
RENAMED
|
File without changes
|
{kryten_webqueue-0.35.1 → kryten_webqueue-0.35.3}/kryten_webqueue/catalog/enrichment/steps/sync.py
RENAMED
|
File without changes
|
{kryten_webqueue-0.35.1 → kryten_webqueue-0.35.3}/kryten_webqueue/catalog/enrichment/steps/tags.py
RENAMED
|
File without changes
|
{kryten_webqueue-0.35.1 → kryten_webqueue-0.35.3}/kryten_webqueue/catalog/enrichment/steps/title.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{kryten_webqueue-0.35.1 → kryten_webqueue-0.35.3}/kryten_webqueue/integrations/cmsutils/__init__.py
RENAMED
|
File without changes
|
{kryten_webqueue-0.35.1 → kryten_webqueue-0.35.3}/kryten_webqueue/integrations/cmsutils/_common.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
{kryten_webqueue-0.35.1 → kryten_webqueue-0.35.3}/kryten_webqueue/integrations/cmsutils/enrichtv.py
RENAMED
|
File without changes
|
{kryten_webqueue-0.35.1 → kryten_webqueue-0.35.3}/kryten_webqueue/integrations/cmsutils/fetchurls.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
{kryten_webqueue-0.35.1 → kryten_webqueue-0.35.3}/kryten_webqueue/integrations/ytpipe/__init__.py
RENAMED
|
File without changes
|
{kryten_webqueue-0.35.1 → kryten_webqueue-0.35.3}/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.1 → kryten_webqueue-0.35.3}/kryten_webqueue/routes/admin_job_schedules.py
RENAMED
|
File without changes
|
|
File without changes
|
{kryten_webqueue-0.35.1 → kryten_webqueue-0.35.3}/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
|
{kryten_webqueue-0.35.1 → kryten_webqueue-0.35.3}/kryten_webqueue/static/js/admin-playlists.js
RENAMED
|
File without changes
|
|
File without changes
|
{kryten_webqueue-0.35.1 → kryten_webqueue-0.35.3}/kryten_webqueue/static/js/admin-queue-mgmt.js
RENAMED
|
File without changes
|
{kryten_webqueue-0.35.1 → kryten_webqueue-0.35.3}/kryten_webqueue/static/js/admin-schedules.js
RENAMED
|
File without changes
|
|
File without changes
|
{kryten_webqueue-0.35.1 → kryten_webqueue-0.35.3}/kryten_webqueue/templates/admin/index.html
RENAMED
|
File without changes
|
{kryten_webqueue-0.35.1 → kryten_webqueue-0.35.3}/kryten_webqueue/templates/admin/playlists.html
RENAMED
|
File without changes
|
{kryten_webqueue-0.35.1 → kryten_webqueue-0.35.3}/kryten_webqueue/templates/admin/promos.html
RENAMED
|
File without changes
|
{kryten_webqueue-0.35.1 → kryten_webqueue-0.35.3}/kryten_webqueue/templates/admin/queue_mgmt.html
RENAMED
|
File without changes
|
{kryten_webqueue-0.35.1 → kryten_webqueue-0.35.3}/kryten_webqueue/templates/admin/schedules.html
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
{kryten_webqueue-0.35.1 → kryten_webqueue-0.35.3}/kryten_webqueue/templates/catalog/browse.html
RENAMED
|
File without changes
|
{kryten_webqueue-0.35.1 → kryten_webqueue-0.35.3}/kryten_webqueue/templates/catalog/item_detail.html
RENAMED
|
File without changes
|
|
File without changes
|
{kryten_webqueue-0.35.1 → kryten_webqueue-0.35.3}/kryten_webqueue/templates/feedback/index.html
RENAMED
|
File without changes
|
{kryten_webqueue-0.35.1 → kryten_webqueue-0.35.3}/kryten_webqueue/templates/queue/index.html
RENAMED
|
File without changes
|
|
File without changes
|
{kryten_webqueue-0.35.1 → kryten_webqueue-0.35.3}/kryten_webqueue/templates/user/dashboard.html
RENAMED
|
File without changes
|
{kryten_webqueue-0.35.1 → kryten_webqueue-0.35.3}/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
|