kryten-webqueue 0.40.1__tar.gz → 0.40.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.
Files changed (184) hide show
  1. {kryten_webqueue-0.40.1 → kryten_webqueue-0.40.3}/CHANGELOG.md +22 -0
  2. {kryten_webqueue-0.40.1 → kryten_webqueue-0.40.3}/PKG-INFO +1 -1
  3. {kryten_webqueue-0.40.1 → kryten_webqueue-0.40.3}/kryten_webqueue/routes/admin_catalog.py +24 -18
  4. {kryten_webqueue-0.40.1 → kryten_webqueue-0.40.3}/kryten_webqueue/templates/catalog/browse.html +9 -5
  5. {kryten_webqueue-0.40.1 → kryten_webqueue-0.40.3}/pyproject.toml +1 -1
  6. {kryten_webqueue-0.40.1 → kryten_webqueue-0.40.3}/.github/workflows/gitleaks.yml +0 -0
  7. {kryten_webqueue-0.40.1 → kryten_webqueue-0.40.3}/.github/workflows/python-publish.yml +0 -0
  8. {kryten_webqueue-0.40.1 → kryten_webqueue-0.40.3}/.github/workflows/release.yml +0 -0
  9. {kryten_webqueue-0.40.1 → kryten_webqueue-0.40.3}/.gitignore +0 -0
  10. {kryten_webqueue-0.40.1 → kryten_webqueue-0.40.3}/.gitleaks.toml +0 -0
  11. {kryten_webqueue-0.40.1 → kryten_webqueue-0.40.3}/.pre-commit-config.yaml +0 -0
  12. {kryten_webqueue-0.40.1 → kryten_webqueue-0.40.3}/AGENT-WORKFLOW-GUIDE.md +0 -0
  13. {kryten_webqueue-0.40.1 → kryten_webqueue-0.40.3}/AGENTS.md +0 -0
  14. {kryten_webqueue-0.40.1 → kryten_webqueue-0.40.3}/README.md +0 -0
  15. {kryten_webqueue-0.40.1 → kryten_webqueue-0.40.3}/config.example.json +0 -0
  16. {kryten_webqueue-0.40.1 → kryten_webqueue-0.40.3}/deploy/kryten-webqueue.service +0 -0
  17. {kryten_webqueue-0.40.1 → kryten_webqueue-0.40.3}/deploy/nginx-queue.conf +0 -0
  18. {kryten_webqueue-0.40.1 → kryten_webqueue-0.40.3}/docs/IMPLEMENTATION_SPEC.md +0 -0
  19. {kryten_webqueue-0.40.1 → kryten_webqueue-0.40.3}/docs/IMPL_API_GATE.md +0 -0
  20. {kryten_webqueue-0.40.1 → kryten_webqueue-0.40.3}/docs/IMPL_ECONOMY.md +0 -0
  21. {kryten_webqueue-0.40.1 → kryten_webqueue-0.40.3}/docs/IMPL_KRYTEN_PY.md +0 -0
  22. {kryten_webqueue-0.40.1 → kryten_webqueue-0.40.3}/docs/IMPL_ROBOT.md +0 -0
  23. {kryten_webqueue-0.40.1 → kryten_webqueue-0.40.3}/docs/Kryten-Economy Service Quality Survey Report at v0.13.0.md +0 -0
  24. {kryten_webqueue-0.40.1 → kryten_webqueue-0.40.3}/docs/Kryten-Webqueue Service Quality Survey Report at v0.27.1.md +0 -0
  25. {kryten_webqueue-0.40.1 → kryten_webqueue-0.40.3}/docs/Log for incorrect promo insertion problem.txt +0 -0
  26. {kryten_webqueue-0.40.1 → kryten_webqueue-0.40.3}/docs/PLAN_PRESENCE_AND_PROMOS.md +0 -0
  27. {kryten_webqueue-0.40.1 → kryten_webqueue-0.40.3}/docs/PRD_TMDB_LOCAL_INDEX.md +0 -0
  28. {kryten_webqueue-0.40.1 → kryten_webqueue-0.40.3}/docs/PRE_PLAN_GAPS.md +0 -0
  29. {kryten_webqueue-0.40.1 → kryten_webqueue-0.40.3}/docs/PRODUCT_PLAN.md +0 -0
  30. {kryten_webqueue-0.40.1 → kryten_webqueue-0.40.3}/docs/SPEC-Visual-UX-Sprint-August-2026.md +0 -0
  31. {kryten_webqueue-0.40.1 → kryten_webqueue-0.40.3}/docs/SPEC_ADMIN_ITEM_EDITOR.md +0 -0
  32. {kryten_webqueue-0.40.1 → kryten_webqueue-0.40.3}/docs/SPEC_CATALOG_ENRICHMENT_PIPELINE.md +0 -0
  33. {kryten_webqueue-0.40.1 → kryten_webqueue-0.40.3}/docs/SPEC_EMOTE_REHOST.md +0 -0
  34. {kryten_webqueue-0.40.1 → kryten_webqueue-0.40.3}/docs/SPEC_JOBS_AND_BROWSE.md +0 -0
  35. {kryten_webqueue-0.40.1 → kryten_webqueue-0.40.3}/docs/SPEC_TMDB_LOCAL_INDEX.md +0 -0
  36. {kryten_webqueue-0.40.1 → kryten_webqueue-0.40.3}/docs/UX_POLISH_PLAN.md +0 -0
  37. {kryten_webqueue-0.40.1 → kryten_webqueue-0.40.3}/kryten_webqueue/__init__.py +0 -0
  38. {kryten_webqueue-0.40.1 → kryten_webqueue-0.40.3}/kryten_webqueue/__main__.py +0 -0
  39. {kryten_webqueue-0.40.1 → kryten_webqueue-0.40.3}/kryten_webqueue/api_gate/__init__.py +0 -0
  40. {kryten_webqueue-0.40.1 → kryten_webqueue-0.40.3}/kryten_webqueue/api_gate/client.py +0 -0
  41. {kryten_webqueue-0.40.1 → kryten_webqueue-0.40.3}/kryten_webqueue/app.py +0 -0
  42. {kryten_webqueue-0.40.1 → kryten_webqueue-0.40.3}/kryten_webqueue/auth/__init__.py +0 -0
  43. {kryten_webqueue-0.40.1 → kryten_webqueue-0.40.3}/kryten_webqueue/auth/otp.py +0 -0
  44. {kryten_webqueue-0.40.1 → kryten_webqueue-0.40.3}/kryten_webqueue/auth/rate_limit.py +0 -0
  45. {kryten_webqueue-0.40.1 → kryten_webqueue-0.40.3}/kryten_webqueue/auth/session.py +0 -0
  46. {kryten_webqueue-0.40.1 → kryten_webqueue-0.40.3}/kryten_webqueue/catalog/__init__.py +0 -0
  47. {kryten_webqueue-0.40.1 → kryten_webqueue-0.40.3}/kryten_webqueue/catalog/db/__init__.py +0 -0
  48. {kryten_webqueue-0.40.1 → kryten_webqueue-0.40.3}/kryten_webqueue/catalog/db/_catalog.py +0 -0
  49. {kryten_webqueue-0.40.1 → kryten_webqueue-0.40.3}/kryten_webqueue/catalog/db/_connection.py +0 -0
  50. {kryten_webqueue-0.40.1 → kryten_webqueue-0.40.3}/kryten_webqueue/catalog/db/_enrichment.py +0 -0
  51. {kryten_webqueue-0.40.1 → kryten_webqueue-0.40.3}/kryten_webqueue/catalog/db/_feedback.py +0 -0
  52. {kryten_webqueue-0.40.1 → kryten_webqueue-0.40.3}/kryten_webqueue/catalog/db/_fetch_queue.py +0 -0
  53. {kryten_webqueue-0.40.1 → kryten_webqueue-0.40.3}/kryten_webqueue/catalog/db/_people.py +0 -0
  54. {kryten_webqueue-0.40.1 → kryten_webqueue-0.40.3}/kryten_webqueue/catalog/db/_playlists.py +0 -0
  55. {kryten_webqueue-0.40.1 → kryten_webqueue-0.40.3}/kryten_webqueue/catalog/db/_queue.py +0 -0
  56. {kryten_webqueue-0.40.1 → kryten_webqueue-0.40.3}/kryten_webqueue/catalog/db/_watchlist.py +0 -0
  57. {kryten_webqueue-0.40.1 → kryten_webqueue-0.40.3}/kryten_webqueue/catalog/enrichment/__init__.py +0 -0
  58. {kryten_webqueue-0.40.1 → kryten_webqueue-0.40.3}/kryten_webqueue/catalog/enrichment/classify.py +0 -0
  59. {kryten_webqueue-0.40.1 → kryten_webqueue-0.40.3}/kryten_webqueue/catalog/enrichment/normalise.py +0 -0
  60. {kryten_webqueue-0.40.1 → kryten_webqueue-0.40.3}/kryten_webqueue/catalog/enrichment/pipeline.py +0 -0
  61. {kryten_webqueue-0.40.1 → kryten_webqueue-0.40.3}/kryten_webqueue/catalog/enrichment/providers.py +0 -0
  62. {kryten_webqueue-0.40.1 → kryten_webqueue-0.40.3}/kryten_webqueue/catalog/enrichment/report.py +0 -0
  63. {kryten_webqueue-0.40.1 → kryten_webqueue-0.40.3}/kryten_webqueue/catalog/enrichment/steps/__init__.py +0 -0
  64. {kryten_webqueue-0.40.1 → kryten_webqueue-0.40.3}/kryten_webqueue/catalog/enrichment/steps/art.py +0 -0
  65. {kryten_webqueue-0.40.1 → kryten_webqueue-0.40.3}/kryten_webqueue/catalog/enrichment/steps/categories.py +0 -0
  66. {kryten_webqueue-0.40.1 → kryten_webqueue-0.40.3}/kryten_webqueue/catalog/enrichment/steps/identify.py +0 -0
  67. {kryten_webqueue-0.40.1 → kryten_webqueue-0.40.3}/kryten_webqueue/catalog/enrichment/steps/meta.py +0 -0
  68. {kryten_webqueue-0.40.1 → kryten_webqueue-0.40.3}/kryten_webqueue/catalog/enrichment/steps/sync.py +0 -0
  69. {kryten_webqueue-0.40.1 → kryten_webqueue-0.40.3}/kryten_webqueue/catalog/enrichment/steps/tags.py +0 -0
  70. {kryten_webqueue-0.40.1 → kryten_webqueue-0.40.3}/kryten_webqueue/catalog/enrichment/steps/title.py +0 -0
  71. {kryten_webqueue-0.40.1 → kryten_webqueue-0.40.3}/kryten_webqueue/catalog/images.py +0 -0
  72. {kryten_webqueue-0.40.1 → kryten_webqueue-0.40.3}/kryten_webqueue/catalog/mediacms.py +0 -0
  73. {kryten_webqueue-0.40.1 → kryten_webqueue-0.40.3}/kryten_webqueue/catalog/sync.py +0 -0
  74. {kryten_webqueue-0.40.1 → kryten_webqueue-0.40.3}/kryten_webqueue/catalog/tmdb_index/__init__.py +0 -0
  75. {kryten_webqueue-0.40.1 → kryten_webqueue-0.40.3}/kryten_webqueue/catalog/tmdb_index/_schema.py +0 -0
  76. {kryten_webqueue-0.40.1 → kryten_webqueue-0.40.3}/kryten_webqueue/catalog/tmdb_index/_textmatch.py +0 -0
  77. {kryten_webqueue-0.40.1 → kryten_webqueue-0.40.3}/kryten_webqueue/catalog/tmdb_index/_ttscrape.py +0 -0
  78. {kryten_webqueue-0.40.1 → kryten_webqueue-0.40.3}/kryten_webqueue/catalog/tmdb_index/builder.py +0 -0
  79. {kryten_webqueue-0.40.1 → kryten_webqueue-0.40.3}/kryten_webqueue/catalog/tmdb_index/coverage.py +0 -0
  80. {kryten_webqueue-0.40.1 → kryten_webqueue-0.40.3}/kryten_webqueue/catalog/tmdb_index/index.py +0 -0
  81. {kryten_webqueue-0.40.1 → kryten_webqueue-0.40.3}/kryten_webqueue/config.py +0 -0
  82. {kryten_webqueue-0.40.1 → kryten_webqueue-0.40.3}/kryten_webqueue/integrations/__init__.py +0 -0
  83. {kryten_webqueue-0.40.1 → kryten_webqueue-0.40.3}/kryten_webqueue/integrations/cmsutils/__init__.py +0 -0
  84. {kryten_webqueue-0.40.1 → kryten_webqueue-0.40.3}/kryten_webqueue/integrations/cmsutils/_common.py +0 -0
  85. {kryten_webqueue-0.40.1 → kryten_webqueue-0.40.3}/kryten_webqueue/integrations/cmsutils/enrichmeta.py +0 -0
  86. {kryten_webqueue-0.40.1 → kryten_webqueue-0.40.3}/kryten_webqueue/integrations/cmsutils/enrichtitles.py +0 -0
  87. {kryten_webqueue-0.40.1 → kryten_webqueue-0.40.3}/kryten_webqueue/integrations/cmsutils/enrichtv.py +0 -0
  88. {kryten_webqueue-0.40.1 → kryten_webqueue-0.40.3}/kryten_webqueue/integrations/cmsutils/fetchurls.py +0 -0
  89. {kryten_webqueue-0.40.1 → kryten_webqueue-0.40.3}/kryten_webqueue/integrations/cmsutils/motdposters.py +0 -0
  90. {kryten_webqueue-0.40.1 → kryten_webqueue-0.40.3}/kryten_webqueue/integrations/cmsutils/playedmovies.py +0 -0
  91. {kryten_webqueue-0.40.1 → kryten_webqueue-0.40.3}/kryten_webqueue/integrations/ytpipe/__init__.py +0 -0
  92. {kryten_webqueue-0.40.1 → kryten_webqueue-0.40.3}/kryten_webqueue/integrations/ytpipe/downloader.py +0 -0
  93. {kryten_webqueue-0.40.1 → kryten_webqueue-0.40.3}/kryten_webqueue/jobs/__init__.py +0 -0
  94. {kryten_webqueue-0.40.1 → kryten_webqueue-0.40.3}/kryten_webqueue/jobs/fetchurls_auth.py +0 -0
  95. {kryten_webqueue-0.40.1 → kryten_webqueue-0.40.3}/kryten_webqueue/jobs/job_scheduler.py +0 -0
  96. {kryten_webqueue-0.40.1 → kryten_webqueue-0.40.3}/kryten_webqueue/jobs/manager.py +0 -0
  97. {kryten_webqueue-0.40.1 → kryten_webqueue-0.40.3}/kryten_webqueue/jobs/rehost_emotes.py +0 -0
  98. {kryten_webqueue-0.40.1 → kryten_webqueue-0.40.3}/kryten_webqueue/jobs/tasks.py +0 -0
  99. {kryten_webqueue-0.40.1 → kryten_webqueue-0.40.3}/kryten_webqueue/logging_config.py +0 -0
  100. {kryten_webqueue-0.40.1 → kryten_webqueue-0.40.3}/kryten_webqueue/playlists/__init__.py +0 -0
  101. {kryten_webqueue-0.40.1 → kryten_webqueue-0.40.3}/kryten_webqueue/playlists/bulk_add.py +0 -0
  102. {kryten_webqueue-0.40.1 → kryten_webqueue-0.40.3}/kryten_webqueue/playlists/fire.py +0 -0
  103. {kryten_webqueue-0.40.1 → kryten_webqueue-0.40.3}/kryten_webqueue/playlists/importer.py +0 -0
  104. {kryten_webqueue-0.40.1 → kryten_webqueue-0.40.3}/kryten_webqueue/playlists/ordering.py +0 -0
  105. {kryten_webqueue-0.40.1 → kryten_webqueue-0.40.3}/kryten_webqueue/playlists/scheduler.py +0 -0
  106. {kryten_webqueue-0.40.1 → kryten_webqueue-0.40.3}/kryten_webqueue/promos/__init__.py +0 -0
  107. {kryten_webqueue-0.40.1 → kryten_webqueue-0.40.3}/kryten_webqueue/promos/director.py +0 -0
  108. {kryten_webqueue-0.40.1 → kryten_webqueue-0.40.3}/kryten_webqueue/queue/__init__.py +0 -0
  109. {kryten_webqueue-0.40.1 → kryten_webqueue-0.40.3}/kryten_webqueue/queue/completion.py +0 -0
  110. {kryten_webqueue-0.40.1 → kryten_webqueue-0.40.3}/kryten_webqueue/queue/ordering.py +0 -0
  111. {kryten_webqueue-0.40.1 → kryten_webqueue-0.40.3}/kryten_webqueue/queue/poller.py +0 -0
  112. {kryten_webqueue-0.40.1 → kryten_webqueue-0.40.3}/kryten_webqueue/queue/presence.py +0 -0
  113. {kryten_webqueue-0.40.1 → kryten_webqueue-0.40.3}/kryten_webqueue/queue/race_poller.py +0 -0
  114. {kryten_webqueue-0.40.1 → kryten_webqueue-0.40.3}/kryten_webqueue/queue/shadow.py +0 -0
  115. {kryten_webqueue-0.40.1 → kryten_webqueue-0.40.3}/kryten_webqueue/routes/__init__.py +0 -0
  116. {kryten_webqueue-0.40.1 → kryten_webqueue-0.40.3}/kryten_webqueue/routes/admin_feedback.py +0 -0
  117. {kryten_webqueue-0.40.1 → kryten_webqueue-0.40.3}/kryten_webqueue/routes/admin_job_schedules.py +0 -0
  118. {kryten_webqueue-0.40.1 → kryten_webqueue-0.40.3}/kryten_webqueue/routes/admin_jobs.py +0 -0
  119. {kryten_webqueue-0.40.1 → kryten_webqueue-0.40.3}/kryten_webqueue/routes/admin_moderation.py +0 -0
  120. {kryten_webqueue-0.40.1 → kryten_webqueue-0.40.3}/kryten_webqueue/routes/admin_playlists.py +0 -0
  121. {kryten_webqueue-0.40.1 → kryten_webqueue-0.40.3}/kryten_webqueue/routes/admin_promos.py +0 -0
  122. {kryten_webqueue-0.40.1 → kryten_webqueue-0.40.3}/kryten_webqueue/routes/admin_queue.py +0 -0
  123. {kryten_webqueue-0.40.1 → kryten_webqueue-0.40.3}/kryten_webqueue/routes/admin_schedules.py +0 -0
  124. {kryten_webqueue-0.40.1 → kryten_webqueue-0.40.3}/kryten_webqueue/routes/auth.py +0 -0
  125. {kryten_webqueue-0.40.1 → kryten_webqueue-0.40.3}/kryten_webqueue/routes/catalog.py +0 -0
  126. {kryten_webqueue-0.40.1 → kryten_webqueue-0.40.3}/kryten_webqueue/routes/feedback.py +0 -0
  127. {kryten_webqueue-0.40.1 → kryten_webqueue-0.40.3}/kryten_webqueue/routes/pages.py +0 -0
  128. {kryten_webqueue-0.40.1 → kryten_webqueue-0.40.3}/kryten_webqueue/routes/queue.py +0 -0
  129. {kryten_webqueue-0.40.1 → kryten_webqueue-0.40.3}/kryten_webqueue/routes/user.py +0 -0
  130. {kryten_webqueue-0.40.1 → kryten_webqueue-0.40.3}/kryten_webqueue/static/css/main.css +0 -0
  131. {kryten_webqueue-0.40.1 → kryten_webqueue-0.40.3}/kryten_webqueue/static/js/admin-playlists.js +0 -0
  132. {kryten_webqueue-0.40.1 → kryten_webqueue-0.40.3}/kryten_webqueue/static/js/admin-promos.js +0 -0
  133. {kryten_webqueue-0.40.1 → kryten_webqueue-0.40.3}/kryten_webqueue/static/js/admin-queue-mgmt.js +0 -0
  134. {kryten_webqueue-0.40.1 → kryten_webqueue-0.40.3}/kryten_webqueue/static/js/admin-schedules.js +0 -0
  135. {kryten_webqueue-0.40.1 → kryten_webqueue-0.40.3}/kryten_webqueue/static/js/admin.js +0 -0
  136. {kryten_webqueue-0.40.1 → kryten_webqueue-0.40.3}/kryten_webqueue/static/js/main.js +0 -0
  137. {kryten_webqueue-0.40.1 → kryten_webqueue-0.40.3}/kryten_webqueue/templates/admin/index.html +0 -0
  138. {kryten_webqueue-0.40.1 → kryten_webqueue-0.40.3}/kryten_webqueue/templates/admin/playlists.html +0 -0
  139. {kryten_webqueue-0.40.1 → kryten_webqueue-0.40.3}/kryten_webqueue/templates/admin/promos.html +0 -0
  140. {kryten_webqueue-0.40.1 → kryten_webqueue-0.40.3}/kryten_webqueue/templates/admin/queue_mgmt.html +0 -0
  141. {kryten_webqueue-0.40.1 → kryten_webqueue-0.40.3}/kryten_webqueue/templates/admin/schedules.html +0 -0
  142. {kryten_webqueue-0.40.1 → kryten_webqueue-0.40.3}/kryten_webqueue/templates/auth/login.html +0 -0
  143. {kryten_webqueue-0.40.1 → kryten_webqueue-0.40.3}/kryten_webqueue/templates/base.html +0 -0
  144. {kryten_webqueue-0.40.1 → kryten_webqueue-0.40.3}/kryten_webqueue/templates/catalog/edit_item_modal.html +0 -0
  145. {kryten_webqueue-0.40.1 → kryten_webqueue-0.40.3}/kryten_webqueue/templates/catalog/item_detail.html +0 -0
  146. {kryten_webqueue-0.40.1 → kryten_webqueue-0.40.3}/kryten_webqueue/templates/catalog/item_not_found.html +0 -0
  147. {kryten_webqueue-0.40.1 → kryten_webqueue-0.40.3}/kryten_webqueue/templates/feedback/index.html +0 -0
  148. {kryten_webqueue-0.40.1 → kryten_webqueue-0.40.3}/kryten_webqueue/templates/queue/index.html +0 -0
  149. {kryten_webqueue-0.40.1 → kryten_webqueue-0.40.3}/kryten_webqueue/templates/race.html +0 -0
  150. {kryten_webqueue-0.40.1 → kryten_webqueue-0.40.3}/kryten_webqueue/templates/user/dashboard.html +0 -0
  151. {kryten_webqueue-0.40.1 → kryten_webqueue-0.40.3}/kryten_webqueue/templates/user/my_list.html +0 -0
  152. {kryten_webqueue-0.40.1 → kryten_webqueue-0.40.3}/kryten_webqueue/ws/__init__.py +0 -0
  153. {kryten_webqueue-0.40.1 → kryten_webqueue-0.40.3}/kryten_webqueue/ws/handler.py +0 -0
  154. {kryten_webqueue-0.40.1 → kryten_webqueue-0.40.3}/kryten_webqueue/ws/manager.py +0 -0
  155. {kryten_webqueue-0.40.1 → kryten_webqueue-0.40.3}/scripts/AGENTS.md +0 -0
  156. {kryten_webqueue-0.40.1 → kryten_webqueue-0.40.3}/scripts/patch_mediacms_bulk_facets.py +0 -0
  157. {kryten_webqueue-0.40.1 → kryten_webqueue-0.40.3}/scripts/patch_mediacms_tags.py +0 -0
  158. {kryten_webqueue-0.40.1 → kryten_webqueue-0.40.3}/scripts/trigger_enrich.py +0 -0
  159. {kryten_webqueue-0.40.1 → kryten_webqueue-0.40.3}/tests/__init__.py +0 -0
  160. {kryten_webqueue-0.40.1 → kryten_webqueue-0.40.3}/tests/test_catalog_delete.py +0 -0
  161. {kryten_webqueue-0.40.1 → kryten_webqueue-0.40.3}/tests/test_classify.py +0 -0
  162. {kryten_webqueue-0.40.1 → kryten_webqueue-0.40.3}/tests/test_config_persistence.py +0 -0
  163. {kryten_webqueue-0.40.1 → kryten_webqueue-0.40.3}/tests/test_feedback.py +0 -0
  164. {kryten_webqueue-0.40.1 → kryten_webqueue-0.40.3}/tests/test_fetchurls_sharepoint.py +0 -0
  165. {kryten_webqueue-0.40.1 → kryten_webqueue-0.40.3}/tests/test_identify_step.py +0 -0
  166. {kryten_webqueue-0.40.1 → kryten_webqueue-0.40.3}/tests/test_people_facets.py +0 -0
  167. {kryten_webqueue-0.40.1 → kryten_webqueue-0.40.3}/tests/test_phase1.py +0 -0
  168. {kryten_webqueue-0.40.1 → kryten_webqueue-0.40.3}/tests/test_phase2_jobs.py +0 -0
  169. {kryten_webqueue-0.40.1 → kryten_webqueue-0.40.3}/tests/test_phase3_jobs.py +0 -0
  170. {kryten_webqueue-0.40.1 → kryten_webqueue-0.40.3}/tests/test_phase4_live_fixes.py +0 -0
  171. {kryten_webqueue-0.40.1 → kryten_webqueue-0.40.3}/tests/test_playlist_import.py +0 -0
  172. {kryten_webqueue-0.40.1 → kryten_webqueue-0.40.3}/tests/test_presence_refund.py +0 -0
  173. {kryten_webqueue-0.40.1 → kryten_webqueue-0.40.3}/tests/test_promo_director.py +0 -0
  174. {kryten_webqueue-0.40.1 → kryten_webqueue-0.40.3}/tests/test_promo_pool_exclusion.py +0 -0
  175. {kryten_webqueue-0.40.1 → kryten_webqueue-0.40.3}/tests/test_providers.py +0 -0
  176. {kryten_webqueue-0.40.1 → kryten_webqueue-0.40.3}/tests/test_queue_announce.py +0 -0
  177. {kryten_webqueue-0.40.1 → kryten_webqueue-0.40.3}/tests/test_race_poller.py +0 -0
  178. {kryten_webqueue-0.40.1 → kryten_webqueue-0.40.3}/tests/test_recently_played_hide.py +0 -0
  179. {kryten_webqueue-0.40.1 → kryten_webqueue-0.40.3}/tests/test_save_results_to_playlist.py +0 -0
  180. {kryten_webqueue-0.40.1 → kryten_webqueue-0.40.3}/tests/test_schedule_lock.py +0 -0
  181. {kryten_webqueue-0.40.1 → kryten_webqueue-0.40.3}/tests/test_search_facets.py +0 -0
  182. {kryten_webqueue-0.40.1 → kryten_webqueue-0.40.3}/tests/test_title_normalization.py +0 -0
  183. {kryten_webqueue-0.40.1 → kryten_webqueue-0.40.3}/tests/test_tmdb_index.py +0 -0
  184. {kryten_webqueue-0.40.1 → kryten_webqueue-0.40.3}/tests/test_watchlist.py +0 -0
@@ -2,6 +2,28 @@
2
2
 
3
3
  ## [Unreleased]
4
4
 
5
+ ## [0.40.3] - 2026-08-21
6
+
7
+ ### Fixed
8
+
9
+ - **Browse/search pagination no longer bounces back to page 1 when a non-default
10
+ duration or sort is active.** Pagination links omitted the `duration` filter
11
+ (and carried a stale `hide_short=0` param), so paging landed on a URL without
12
+ `duration`; the client-side preference-restore then re-applied the saved filter
13
+ via `applyFacets()`, which rebuilds the URL without `page` — sending the user
14
+ to page 1. Links now carry `duration`, and `restorePreferences()` skips any URL
15
+ that already has a `page` param so explicit pagination is never hijacked.
16
+
17
+ ## [0.40.2] - 2026-08-21
18
+
19
+ ### Changed
20
+
21
+ - **Admin re-enrich returns `400` instead of `500` on an invalid job request.**
22
+ Both the `/edit` and `/re-enrich` routes now catch `ValueError` from
23
+ `catalog_enrich` param validation and surface it as `400 Bad Request` rather
24
+ than letting it become an unhandled 500 (defense against future
25
+ steps-schema drift).
26
+
5
27
  ## [0.40.1] - 2026-08-21
6
28
 
7
29
  ### Fixed
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.5
2
2
  Name: kryten-webqueue
3
- Version: 0.40.1
3
+ Version: 0.40.3
4
4
  Summary: Netflix/Tubi-style catalog browser and pay-to-play queue management for CyTube
5
5
  Author: grobertson
6
6
  License-Expression: MIT
@@ -156,15 +156,18 @@ async def enrich_item(
156
156
  if not item:
157
157
  raise HTTPException(404, "Catalog item not found")
158
158
  job_manager = request.app.state.job_manager
159
- result = await job_manager.run(
160
- "catalog_enrich",
161
- params={
162
- "tokens": friendly_token,
163
- "force": "true",
164
- "steps": "classify,identify,meta,art,tags",
165
- },
166
- triggered_by=user.get("username"),
167
- )
159
+ try:
160
+ result = await job_manager.run(
161
+ "catalog_enrich",
162
+ params={
163
+ "tokens": friendly_token,
164
+ "force": "true",
165
+ "steps": "classify,identify,meta,art,tags",
166
+ },
167
+ triggered_by=user.get("username"),
168
+ )
169
+ except ValueError as exc:
170
+ raise HTTPException(400, f"Invalid enrichment request: {exc}") from exc
168
171
  return result
169
172
 
170
173
 
@@ -301,15 +304,18 @@ async def edit_item(
301
304
  # --- Optional re-enrichment trigger ---
302
305
  if body.get("re_enrich", False):
303
306
  job_manager = request.app.state.job_manager
304
- result = await job_manager.run(
305
- "catalog_enrich",
306
- params={
307
- "tokens": friendly_token,
308
- "force": "true",
309
- "steps": "classify,identify,meta,art,tags",
310
- },
311
- triggered_by=username,
312
- )
307
+ try:
308
+ result = await job_manager.run(
309
+ "catalog_enrich",
310
+ params={
311
+ "tokens": friendly_token,
312
+ "force": "true",
313
+ "steps": "classify,identify,meta,art,tags",
314
+ },
315
+ triggered_by=username,
316
+ )
317
+ except ValueError as exc:
318
+ raise HTTPException(400, f"Invalid enrichment request: {exc}") from exc
313
319
  enrich_job_id = result.get("run_id")
314
320
 
315
321
  return {
@@ -125,7 +125,7 @@
125
125
  </div>
126
126
 
127
127
  {% set sort_q = ('&sort=' ~ sort) if (sort and sort != 'default') else '' %}
128
- {% set hide_short_q = '' if hide_short else '&hide_short=0' %}
128
+ {% set duration_q = ('&duration=' ~ duration) if (duration and duration != '10+') else '' %}
129
129
  {% set person_q = ('&person=' ~ active_person | urlencode) if active_person else '' %}
130
130
  {% set studio_q = ('&studio=' ~ active_studio | urlencode) if active_studio else '' %}
131
131
  {% if not items %}
@@ -168,7 +168,7 @@
168
168
 
169
169
  <div class="pagination">
170
170
  {% if page > 1 %}
171
- <a href="?page={{ page - 1 }}{% if query %}&q={{ query }}{% endif %}{% if active_category %}&category={{ active_category }}{% endif %}{% if active_tag %}&tag={{ active_tag | urlencode }}{% endif %}{{ sort_q }}{{ hide_short_q }}{{ person_q }}{{ studio_q }}" class="btn btn-sm">&larr; Prev</a>
171
+ <a href="?page={{ page - 1 }}{% if query %}&q={{ query }}{% endif %}{% if active_category %}&category={{ active_category }}{% endif %}{% if active_tag %}&tag={{ active_tag | urlencode }}{% endif %}{{ sort_q }}{{ duration_q }}{{ person_q }}{{ studio_q }}" class="btn btn-sm">&larr; Prev</a>
172
172
  {% endif %}
173
173
 
174
174
  {% set start_page = [1, page - 2] | max %}
@@ -177,14 +177,14 @@
177
177
  {% if p == page %}
178
178
  <span class="page-num page-current">{{ p }}</span>
179
179
  {% else %}
180
- <a href="?page={{ p }}{% if query %}&q={{ query }}{% endif %}{% if active_category %}&category={{ active_category }}{% endif %}{% if active_tag %}&tag={{ active_tag | urlencode }}{% endif %}{{ sort_q }}{{ hide_short_q }}{{ person_q }}{{ studio_q }}" class="btn btn-sm btn-page">{{ p }}</a>
180
+ <a href="?page={{ p }}{% if query %}&q={{ query }}{% endif %}{% if active_category %}&category={{ active_category }}{% endif %}{% if active_tag %}&tag={{ active_tag | urlencode }}{% endif %}{{ sort_q }}{{ duration_q }}{{ person_q }}{{ studio_q }}" class="btn btn-sm btn-page">{{ p }}</a>
181
181
  {% endif %}
182
182
  {% endfor %}
183
183
 
184
184
  <span class="page-info">of {{ total_pages }}</span>
185
185
 
186
186
  {% if page < total_pages %}
187
- <a href="?page={{ page + 1 }}{% if query %}&q={{ query }}{% endif %}{% if active_category %}&category={{ active_category }}{% endif %}{% if active_tag %}&tag={{ active_tag | urlencode }}{% endif %}{{ sort_q }}{{ hide_short_q }}{{ person_q }}{{ studio_q }}" class="btn btn-sm">Next &rarr;</a>
187
+ <a href="?page={{ page + 1 }}{% if query %}&q={{ query }}{% endif %}{% if active_category %}&category={{ active_category }}{% endif %}{% if active_tag %}&tag={{ active_tag | urlencode }}{% endif %}{{ sort_q }}{{ duration_q }}{{ person_q }}{{ studio_q }}" class="btn btn-sm">Next &rarr;</a>
188
188
  {% endif %}
189
189
  </div>
190
190
  {% endblock %}
@@ -229,7 +229,11 @@ function applyFacets() {
229
229
  const sortSel = document.getElementById('sort-select');
230
230
  const durationSel = document.getElementById('duration-select');
231
231
  const url = new URL(window.location.href);
232
-
232
+
233
+ // Never hijack an explicit paginated navigation: applyFacets() drops the
234
+ // page, so restoring a saved pref here would bounce the user back to page 1.
235
+ if (url.searchParams.has('page')) return;
236
+
233
237
  // Restore sort preference
234
238
  if (sortSel && !url.searchParams.has('sort')) {
235
239
  let saved = null;
@@ -1,6 +1,6 @@
1
1
  [project]
2
2
  name = "kryten-webqueue"
3
- version = "0.40.1"
3
+ version = "0.40.3"
4
4
  description = "Netflix/Tubi-style catalog browser and pay-to-play queue management for CyTube"
5
5
  readme = "README.md"
6
6
  license = "MIT"