kryten-webqueue 0.44.5__tar.gz → 0.44.7__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 (199) hide show
  1. {kryten_webqueue-0.44.5 → kryten_webqueue-0.44.7}/CHANGELOG.md +28 -0
  2. {kryten_webqueue-0.44.5 → kryten_webqueue-0.44.7}/PKG-INFO +1 -1
  3. {kryten_webqueue-0.44.5 → kryten_webqueue-0.44.7}/kryten_webqueue/catalog/db/_catalog.py +10 -18
  4. {kryten_webqueue-0.44.5 → kryten_webqueue-0.44.7}/kryten_webqueue/catalog/db/_connection.py +4 -0
  5. {kryten_webqueue-0.44.5 → kryten_webqueue-0.44.7}/kryten_webqueue/integrations/ytpipe/downloader.py +14 -3
  6. {kryten_webqueue-0.44.5 → kryten_webqueue-0.44.7}/pyproject.toml +1 -1
  7. {kryten_webqueue-0.44.5 → kryten_webqueue-0.44.7}/.github/workflows/gitleaks.yml +0 -0
  8. {kryten_webqueue-0.44.5 → kryten_webqueue-0.44.7}/.github/workflows/python-publish.yml +0 -0
  9. {kryten_webqueue-0.44.5 → kryten_webqueue-0.44.7}/.github/workflows/release.yml +0 -0
  10. {kryten_webqueue-0.44.5 → kryten_webqueue-0.44.7}/.gitignore +0 -0
  11. {kryten_webqueue-0.44.5 → kryten_webqueue-0.44.7}/.gitleaks.toml +0 -0
  12. {kryten_webqueue-0.44.5 → kryten_webqueue-0.44.7}/.pre-commit-config.yaml +0 -0
  13. {kryten_webqueue-0.44.5 → kryten_webqueue-0.44.7}/AGENT-WORKFLOW-GUIDE.md +0 -0
  14. {kryten_webqueue-0.44.5 → kryten_webqueue-0.44.7}/AGENTS.md +0 -0
  15. {kryten_webqueue-0.44.5 → kryten_webqueue-0.44.7}/README.md +0 -0
  16. {kryten_webqueue-0.44.5 → kryten_webqueue-0.44.7}/config.example.json +0 -0
  17. {kryten_webqueue-0.44.5 → kryten_webqueue-0.44.7}/deploy/kryten-webqueue.service +0 -0
  18. {kryten_webqueue-0.44.5 → kryten_webqueue-0.44.7}/deploy/nginx-queue.conf +0 -0
  19. {kryten_webqueue-0.44.5 → kryten_webqueue-0.44.7}/docs/IMPLEMENTATION_SPEC.md +0 -0
  20. {kryten_webqueue-0.44.5 → kryten_webqueue-0.44.7}/docs/IMPL_API_GATE.md +0 -0
  21. {kryten_webqueue-0.44.5 → kryten_webqueue-0.44.7}/docs/IMPL_ECONOMY.md +0 -0
  22. {kryten_webqueue-0.44.5 → kryten_webqueue-0.44.7}/docs/IMPL_KRYTEN_PY.md +0 -0
  23. {kryten_webqueue-0.44.5 → kryten_webqueue-0.44.7}/docs/IMPL_ROBOT.md +0 -0
  24. {kryten_webqueue-0.44.5 → kryten_webqueue-0.44.7}/docs/Kryten-Economy Service Quality Survey Report at v0.13.0.md +0 -0
  25. {kryten_webqueue-0.44.5 → kryten_webqueue-0.44.7}/docs/Kryten-Webqueue Service Quality Survey Report at v0.27.1.md +0 -0
  26. {kryten_webqueue-0.44.5 → kryten_webqueue-0.44.7}/docs/Log for incorrect promo insertion problem.txt +0 -0
  27. {kryten_webqueue-0.44.5 → kryten_webqueue-0.44.7}/docs/PLAN_PRESENCE_AND_PROMOS.md +0 -0
  28. {kryten_webqueue-0.44.5 → kryten_webqueue-0.44.7}/docs/PRD_TMDB_LOCAL_INDEX.md +0 -0
  29. {kryten_webqueue-0.44.5 → kryten_webqueue-0.44.7}/docs/PRE_PLAN_GAPS.md +0 -0
  30. {kryten_webqueue-0.44.5 → kryten_webqueue-0.44.7}/docs/PRODUCT_PLAN.md +0 -0
  31. {kryten_webqueue-0.44.5 → kryten_webqueue-0.44.7}/docs/PUBLIC_API.md +0 -0
  32. {kryten_webqueue-0.44.5 → kryten_webqueue-0.44.7}/docs/SPEC-Visual-UX-Sprint-August-2026.md +0 -0
  33. {kryten_webqueue-0.44.5 → kryten_webqueue-0.44.7}/docs/SPEC_ADMIN_ITEM_EDITOR.md +0 -0
  34. {kryten_webqueue-0.44.5 → kryten_webqueue-0.44.7}/docs/SPEC_CATALOG_ENRICHMENT_PIPELINE.md +0 -0
  35. {kryten_webqueue-0.44.5 → kryten_webqueue-0.44.7}/docs/SPEC_EMOTE_REHOST.md +0 -0
  36. {kryten_webqueue-0.44.5 → kryten_webqueue-0.44.7}/docs/SPEC_JOBS_AND_BROWSE.md +0 -0
  37. {kryten_webqueue-0.44.5 → kryten_webqueue-0.44.7}/docs/SPEC_TMDB_LOCAL_INDEX.md +0 -0
  38. {kryten_webqueue-0.44.5 → kryten_webqueue-0.44.7}/docs/UX_POLISH_PLAN.md +0 -0
  39. {kryten_webqueue-0.44.5 → kryten_webqueue-0.44.7}/kryten_webqueue/__init__.py +0 -0
  40. {kryten_webqueue-0.44.5 → kryten_webqueue-0.44.7}/kryten_webqueue/__main__.py +0 -0
  41. {kryten_webqueue-0.44.5 → kryten_webqueue-0.44.7}/kryten_webqueue/api_gate/__init__.py +0 -0
  42. {kryten_webqueue-0.44.5 → kryten_webqueue-0.44.7}/kryten_webqueue/api_gate/client.py +0 -0
  43. {kryten_webqueue-0.44.5 → kryten_webqueue-0.44.7}/kryten_webqueue/app.py +0 -0
  44. {kryten_webqueue-0.44.5 → kryten_webqueue-0.44.7}/kryten_webqueue/auth/__init__.py +0 -0
  45. {kryten_webqueue-0.44.5 → kryten_webqueue-0.44.7}/kryten_webqueue/auth/device_keys.py +0 -0
  46. {kryten_webqueue-0.44.5 → kryten_webqueue-0.44.7}/kryten_webqueue/auth/otp.py +0 -0
  47. {kryten_webqueue-0.44.5 → kryten_webqueue-0.44.7}/kryten_webqueue/auth/rate_limit.py +0 -0
  48. {kryten_webqueue-0.44.5 → kryten_webqueue-0.44.7}/kryten_webqueue/auth/session.py +0 -0
  49. {kryten_webqueue-0.44.5 → kryten_webqueue-0.44.7}/kryten_webqueue/catalog/__init__.py +0 -0
  50. {kryten_webqueue-0.44.5 → kryten_webqueue-0.44.7}/kryten_webqueue/catalog/db/__init__.py +0 -0
  51. {kryten_webqueue-0.44.5 → kryten_webqueue-0.44.7}/kryten_webqueue/catalog/db/_blackouts.py +0 -0
  52. {kryten_webqueue-0.44.5 → kryten_webqueue-0.44.7}/kryten_webqueue/catalog/db/_devices.py +0 -0
  53. {kryten_webqueue-0.44.5 → kryten_webqueue-0.44.7}/kryten_webqueue/catalog/db/_enrichment.py +0 -0
  54. {kryten_webqueue-0.44.5 → kryten_webqueue-0.44.7}/kryten_webqueue/catalog/db/_feedback.py +0 -0
  55. {kryten_webqueue-0.44.5 → kryten_webqueue-0.44.7}/kryten_webqueue/catalog/db/_fetch_queue.py +0 -0
  56. {kryten_webqueue-0.44.5 → kryten_webqueue-0.44.7}/kryten_webqueue/catalog/db/_people.py +0 -0
  57. {kryten_webqueue-0.44.5 → kryten_webqueue-0.44.7}/kryten_webqueue/catalog/db/_playlists.py +0 -0
  58. {kryten_webqueue-0.44.5 → kryten_webqueue-0.44.7}/kryten_webqueue/catalog/db/_queue.py +0 -0
  59. {kryten_webqueue-0.44.5 → kryten_webqueue-0.44.7}/kryten_webqueue/catalog/db/_watchlist.py +0 -0
  60. {kryten_webqueue-0.44.5 → kryten_webqueue-0.44.7}/kryten_webqueue/catalog/enrichment/__init__.py +0 -0
  61. {kryten_webqueue-0.44.5 → kryten_webqueue-0.44.7}/kryten_webqueue/catalog/enrichment/classify.py +0 -0
  62. {kryten_webqueue-0.44.5 → kryten_webqueue-0.44.7}/kryten_webqueue/catalog/enrichment/normalise.py +0 -0
  63. {kryten_webqueue-0.44.5 → kryten_webqueue-0.44.7}/kryten_webqueue/catalog/enrichment/pipeline.py +0 -0
  64. {kryten_webqueue-0.44.5 → kryten_webqueue-0.44.7}/kryten_webqueue/catalog/enrichment/providers.py +0 -0
  65. {kryten_webqueue-0.44.5 → kryten_webqueue-0.44.7}/kryten_webqueue/catalog/enrichment/report.py +0 -0
  66. {kryten_webqueue-0.44.5 → kryten_webqueue-0.44.7}/kryten_webqueue/catalog/enrichment/steps/__init__.py +0 -0
  67. {kryten_webqueue-0.44.5 → kryten_webqueue-0.44.7}/kryten_webqueue/catalog/enrichment/steps/art.py +0 -0
  68. {kryten_webqueue-0.44.5 → kryten_webqueue-0.44.7}/kryten_webqueue/catalog/enrichment/steps/categories.py +0 -0
  69. {kryten_webqueue-0.44.5 → kryten_webqueue-0.44.7}/kryten_webqueue/catalog/enrichment/steps/identify.py +0 -0
  70. {kryten_webqueue-0.44.5 → kryten_webqueue-0.44.7}/kryten_webqueue/catalog/enrichment/steps/meta.py +0 -0
  71. {kryten_webqueue-0.44.5 → kryten_webqueue-0.44.7}/kryten_webqueue/catalog/enrichment/steps/sync.py +0 -0
  72. {kryten_webqueue-0.44.5 → kryten_webqueue-0.44.7}/kryten_webqueue/catalog/enrichment/steps/tags.py +0 -0
  73. {kryten_webqueue-0.44.5 → kryten_webqueue-0.44.7}/kryten_webqueue/catalog/enrichment/steps/title.py +0 -0
  74. {kryten_webqueue-0.44.5 → kryten_webqueue-0.44.7}/kryten_webqueue/catalog/images.py +0 -0
  75. {kryten_webqueue-0.44.5 → kryten_webqueue-0.44.7}/kryten_webqueue/catalog/mediacms.py +0 -0
  76. {kryten_webqueue-0.44.5 → kryten_webqueue-0.44.7}/kryten_webqueue/catalog/sync.py +0 -0
  77. {kryten_webqueue-0.44.5 → kryten_webqueue-0.44.7}/kryten_webqueue/catalog/tmdb_index/__init__.py +0 -0
  78. {kryten_webqueue-0.44.5 → kryten_webqueue-0.44.7}/kryten_webqueue/catalog/tmdb_index/_schema.py +0 -0
  79. {kryten_webqueue-0.44.5 → kryten_webqueue-0.44.7}/kryten_webqueue/catalog/tmdb_index/_textmatch.py +0 -0
  80. {kryten_webqueue-0.44.5 → kryten_webqueue-0.44.7}/kryten_webqueue/catalog/tmdb_index/_ttscrape.py +0 -0
  81. {kryten_webqueue-0.44.5 → kryten_webqueue-0.44.7}/kryten_webqueue/catalog/tmdb_index/builder.py +0 -0
  82. {kryten_webqueue-0.44.5 → kryten_webqueue-0.44.7}/kryten_webqueue/catalog/tmdb_index/coverage.py +0 -0
  83. {kryten_webqueue-0.44.5 → kryten_webqueue-0.44.7}/kryten_webqueue/catalog/tmdb_index/index.py +0 -0
  84. {kryten_webqueue-0.44.5 → kryten_webqueue-0.44.7}/kryten_webqueue/config.py +0 -0
  85. {kryten_webqueue-0.44.5 → kryten_webqueue-0.44.7}/kryten_webqueue/integrations/__init__.py +0 -0
  86. {kryten_webqueue-0.44.5 → kryten_webqueue-0.44.7}/kryten_webqueue/integrations/cmsutils/__init__.py +0 -0
  87. {kryten_webqueue-0.44.5 → kryten_webqueue-0.44.7}/kryten_webqueue/integrations/cmsutils/_common.py +0 -0
  88. {kryten_webqueue-0.44.5 → kryten_webqueue-0.44.7}/kryten_webqueue/integrations/cmsutils/blackout_scan.py +0 -0
  89. {kryten_webqueue-0.44.5 → kryten_webqueue-0.44.7}/kryten_webqueue/integrations/cmsutils/enrichmeta.py +0 -0
  90. {kryten_webqueue-0.44.5 → kryten_webqueue-0.44.7}/kryten_webqueue/integrations/cmsutils/enrichtitles.py +0 -0
  91. {kryten_webqueue-0.44.5 → kryten_webqueue-0.44.7}/kryten_webqueue/integrations/cmsutils/enrichtv.py +0 -0
  92. {kryten_webqueue-0.44.5 → kryten_webqueue-0.44.7}/kryten_webqueue/integrations/cmsutils/fetchurls.py +0 -0
  93. {kryten_webqueue-0.44.5 → kryten_webqueue-0.44.7}/kryten_webqueue/integrations/cmsutils/motdposters.py +0 -0
  94. {kryten_webqueue-0.44.5 → kryten_webqueue-0.44.7}/kryten_webqueue/integrations/cmsutils/playedmovies.py +0 -0
  95. {kryten_webqueue-0.44.5 → kryten_webqueue-0.44.7}/kryten_webqueue/integrations/ytpipe/__init__.py +0 -0
  96. {kryten_webqueue-0.44.5 → kryten_webqueue-0.44.7}/kryten_webqueue/jobs/__init__.py +0 -0
  97. {kryten_webqueue-0.44.5 → kryten_webqueue-0.44.7}/kryten_webqueue/jobs/fetchurls_auth.py +0 -0
  98. {kryten_webqueue-0.44.5 → kryten_webqueue-0.44.7}/kryten_webqueue/jobs/job_scheduler.py +0 -0
  99. {kryten_webqueue-0.44.5 → kryten_webqueue-0.44.7}/kryten_webqueue/jobs/log_capture.py +0 -0
  100. {kryten_webqueue-0.44.5 → kryten_webqueue-0.44.7}/kryten_webqueue/jobs/manager.py +0 -0
  101. {kryten_webqueue-0.44.5 → kryten_webqueue-0.44.7}/kryten_webqueue/jobs/rehost_emotes.py +0 -0
  102. {kryten_webqueue-0.44.5 → kryten_webqueue-0.44.7}/kryten_webqueue/jobs/tasks.py +0 -0
  103. {kryten_webqueue-0.44.5 → kryten_webqueue-0.44.7}/kryten_webqueue/logging_config.py +0 -0
  104. {kryten_webqueue-0.44.5 → kryten_webqueue-0.44.7}/kryten_webqueue/playlists/__init__.py +0 -0
  105. {kryten_webqueue-0.44.5 → kryten_webqueue-0.44.7}/kryten_webqueue/playlists/bulk_add.py +0 -0
  106. {kryten_webqueue-0.44.5 → kryten_webqueue-0.44.7}/kryten_webqueue/playlists/fire.py +0 -0
  107. {kryten_webqueue-0.44.5 → kryten_webqueue-0.44.7}/kryten_webqueue/playlists/importer.py +0 -0
  108. {kryten_webqueue-0.44.5 → kryten_webqueue-0.44.7}/kryten_webqueue/playlists/ordering.py +0 -0
  109. {kryten_webqueue-0.44.5 → kryten_webqueue-0.44.7}/kryten_webqueue/playlists/scheduler.py +0 -0
  110. {kryten_webqueue-0.44.5 → kryten_webqueue-0.44.7}/kryten_webqueue/promos/__init__.py +0 -0
  111. {kryten_webqueue-0.44.5 → kryten_webqueue-0.44.7}/kryten_webqueue/promos/director.py +0 -0
  112. {kryten_webqueue-0.44.5 → kryten_webqueue-0.44.7}/kryten_webqueue/queue/__init__.py +0 -0
  113. {kryten_webqueue-0.44.5 → kryten_webqueue-0.44.7}/kryten_webqueue/queue/completion.py +0 -0
  114. {kryten_webqueue-0.44.5 → kryten_webqueue-0.44.7}/kryten_webqueue/queue/ordering.py +0 -0
  115. {kryten_webqueue-0.44.5 → kryten_webqueue-0.44.7}/kryten_webqueue/queue/poller.py +0 -0
  116. {kryten_webqueue-0.44.5 → kryten_webqueue-0.44.7}/kryten_webqueue/queue/presence.py +0 -0
  117. {kryten_webqueue-0.44.5 → kryten_webqueue-0.44.7}/kryten_webqueue/queue/race_poller.py +0 -0
  118. {kryten_webqueue-0.44.5 → kryten_webqueue-0.44.7}/kryten_webqueue/queue/shadow.py +0 -0
  119. {kryten_webqueue-0.44.5 → kryten_webqueue-0.44.7}/kryten_webqueue/routes/__init__.py +0 -0
  120. {kryten_webqueue-0.44.5 → kryten_webqueue-0.44.7}/kryten_webqueue/routes/admin_catalog.py +0 -0
  121. {kryten_webqueue-0.44.5 → kryten_webqueue-0.44.7}/kryten_webqueue/routes/admin_feedback.py +0 -0
  122. {kryten_webqueue-0.44.5 → kryten_webqueue-0.44.7}/kryten_webqueue/routes/admin_job_schedules.py +0 -0
  123. {kryten_webqueue-0.44.5 → kryten_webqueue-0.44.7}/kryten_webqueue/routes/admin_jobs.py +0 -0
  124. {kryten_webqueue-0.44.5 → kryten_webqueue-0.44.7}/kryten_webqueue/routes/admin_moderation.py +0 -0
  125. {kryten_webqueue-0.44.5 → kryten_webqueue-0.44.7}/kryten_webqueue/routes/admin_playlists.py +0 -0
  126. {kryten_webqueue-0.44.5 → kryten_webqueue-0.44.7}/kryten_webqueue/routes/admin_promos.py +0 -0
  127. {kryten_webqueue-0.44.5 → kryten_webqueue-0.44.7}/kryten_webqueue/routes/admin_queue.py +0 -0
  128. {kryten_webqueue-0.44.5 → kryten_webqueue-0.44.7}/kryten_webqueue/routes/admin_schedules.py +0 -0
  129. {kryten_webqueue-0.44.5 → kryten_webqueue-0.44.7}/kryten_webqueue/routes/auth.py +0 -0
  130. {kryten_webqueue-0.44.5 → kryten_webqueue-0.44.7}/kryten_webqueue/routes/catalog.py +0 -0
  131. {kryten_webqueue-0.44.5 → kryten_webqueue-0.44.7}/kryten_webqueue/routes/devices.py +0 -0
  132. {kryten_webqueue-0.44.5 → kryten_webqueue-0.44.7}/kryten_webqueue/routes/feedback.py +0 -0
  133. {kryten_webqueue-0.44.5 → kryten_webqueue-0.44.7}/kryten_webqueue/routes/pages.py +0 -0
  134. {kryten_webqueue-0.44.5 → kryten_webqueue-0.44.7}/kryten_webqueue/routes/public_api.py +0 -0
  135. {kryten_webqueue-0.44.5 → kryten_webqueue-0.44.7}/kryten_webqueue/routes/queue.py +0 -0
  136. {kryten_webqueue-0.44.5 → kryten_webqueue-0.44.7}/kryten_webqueue/routes/user.py +0 -0
  137. {kryten_webqueue-0.44.5 → kryten_webqueue-0.44.7}/kryten_webqueue/static/css/main.css +0 -0
  138. {kryten_webqueue-0.44.5 → kryten_webqueue-0.44.7}/kryten_webqueue/static/js/admin-playlists.js +0 -0
  139. {kryten_webqueue-0.44.5 → kryten_webqueue-0.44.7}/kryten_webqueue/static/js/admin-promos.js +0 -0
  140. {kryten_webqueue-0.44.5 → kryten_webqueue-0.44.7}/kryten_webqueue/static/js/admin-queue-mgmt.js +0 -0
  141. {kryten_webqueue-0.44.5 → kryten_webqueue-0.44.7}/kryten_webqueue/static/js/admin-schedules.js +0 -0
  142. {kryten_webqueue-0.44.5 → kryten_webqueue-0.44.7}/kryten_webqueue/static/js/admin.js +0 -0
  143. {kryten_webqueue-0.44.5 → kryten_webqueue-0.44.7}/kryten_webqueue/static/js/keybindings.js +0 -0
  144. {kryten_webqueue-0.44.5 → kryten_webqueue-0.44.7}/kryten_webqueue/static/js/main.js +0 -0
  145. {kryten_webqueue-0.44.5 → kryten_webqueue-0.44.7}/kryten_webqueue/templates/admin/index.html +0 -0
  146. {kryten_webqueue-0.44.5 → kryten_webqueue-0.44.7}/kryten_webqueue/templates/admin/playlists.html +0 -0
  147. {kryten_webqueue-0.44.5 → kryten_webqueue-0.44.7}/kryten_webqueue/templates/admin/promos.html +0 -0
  148. {kryten_webqueue-0.44.5 → kryten_webqueue-0.44.7}/kryten_webqueue/templates/admin/queue_mgmt.html +0 -0
  149. {kryten_webqueue-0.44.5 → kryten_webqueue-0.44.7}/kryten_webqueue/templates/admin/schedules.html +0 -0
  150. {kryten_webqueue-0.44.5 → kryten_webqueue-0.44.7}/kryten_webqueue/templates/auth/login.html +0 -0
  151. {kryten_webqueue-0.44.5 → kryten_webqueue-0.44.7}/kryten_webqueue/templates/base.html +0 -0
  152. {kryten_webqueue-0.44.5 → kryten_webqueue-0.44.7}/kryten_webqueue/templates/catalog/browse.html +0 -0
  153. {kryten_webqueue-0.44.5 → kryten_webqueue-0.44.7}/kryten_webqueue/templates/catalog/edit_item_modal.html +0 -0
  154. {kryten_webqueue-0.44.5 → kryten_webqueue-0.44.7}/kryten_webqueue/templates/catalog/item_detail.html +0 -0
  155. {kryten_webqueue-0.44.5 → kryten_webqueue-0.44.7}/kryten_webqueue/templates/catalog/item_not_found.html +0 -0
  156. {kryten_webqueue-0.44.5 → kryten_webqueue-0.44.7}/kryten_webqueue/templates/feedback/index.html +0 -0
  157. {kryten_webqueue-0.44.5 → kryten_webqueue-0.44.7}/kryten_webqueue/templates/queue/index.html +0 -0
  158. {kryten_webqueue-0.44.5 → kryten_webqueue-0.44.7}/kryten_webqueue/templates/race.html +0 -0
  159. {kryten_webqueue-0.44.5 → kryten_webqueue-0.44.7}/kryten_webqueue/templates/user/dashboard.html +0 -0
  160. {kryten_webqueue-0.44.5 → kryten_webqueue-0.44.7}/kryten_webqueue/templates/user/link_device.html +0 -0
  161. {kryten_webqueue-0.44.5 → kryten_webqueue-0.44.7}/kryten_webqueue/templates/user/my_list.html +0 -0
  162. {kryten_webqueue-0.44.5 → kryten_webqueue-0.44.7}/kryten_webqueue/ws/__init__.py +0 -0
  163. {kryten_webqueue-0.44.5 → kryten_webqueue-0.44.7}/kryten_webqueue/ws/handler.py +0 -0
  164. {kryten_webqueue-0.44.5 → kryten_webqueue-0.44.7}/kryten_webqueue/ws/manager.py +0 -0
  165. {kryten_webqueue-0.44.5 → kryten_webqueue-0.44.7}/scripts/AGENTS.md +0 -0
  166. {kryten_webqueue-0.44.5 → kryten_webqueue-0.44.7}/scripts/patch_mediacms_bulk_facets.py +0 -0
  167. {kryten_webqueue-0.44.5 → kryten_webqueue-0.44.7}/scripts/patch_mediacms_tags.py +0 -0
  168. {kryten_webqueue-0.44.5 → kryten_webqueue-0.44.7}/scripts/trigger_enrich.py +0 -0
  169. {kryten_webqueue-0.44.5 → kryten_webqueue-0.44.7}/tests/__init__.py +0 -0
  170. {kryten_webqueue-0.44.5 → kryten_webqueue-0.44.7}/tests/test_catalog_blackout.py +0 -0
  171. {kryten_webqueue-0.44.5 → kryten_webqueue-0.44.7}/tests/test_catalog_delete.py +0 -0
  172. {kryten_webqueue-0.44.5 → kryten_webqueue-0.44.7}/tests/test_classify.py +0 -0
  173. {kryten_webqueue-0.44.5 → kryten_webqueue-0.44.7}/tests/test_config_persistence.py +0 -0
  174. {kryten_webqueue-0.44.5 → kryten_webqueue-0.44.7}/tests/test_device_linking.py +0 -0
  175. {kryten_webqueue-0.44.5 → kryten_webqueue-0.44.7}/tests/test_feedback.py +0 -0
  176. {kryten_webqueue-0.44.5 → kryten_webqueue-0.44.7}/tests/test_fetch_queue_pacing.py +0 -0
  177. {kryten_webqueue-0.44.5 → kryten_webqueue-0.44.7}/tests/test_fetchurls_sharepoint.py +0 -0
  178. {kryten_webqueue-0.44.5 → kryten_webqueue-0.44.7}/tests/test_identify_step.py +0 -0
  179. {kryten_webqueue-0.44.5 → kryten_webqueue-0.44.7}/tests/test_job_logs_and_queue_visibility.py +0 -0
  180. {kryten_webqueue-0.44.5 → kryten_webqueue-0.44.7}/tests/test_people_facets.py +0 -0
  181. {kryten_webqueue-0.44.5 → kryten_webqueue-0.44.7}/tests/test_phase1.py +0 -0
  182. {kryten_webqueue-0.44.5 → kryten_webqueue-0.44.7}/tests/test_phase2_jobs.py +0 -0
  183. {kryten_webqueue-0.44.5 → kryten_webqueue-0.44.7}/tests/test_phase3_jobs.py +0 -0
  184. {kryten_webqueue-0.44.5 → kryten_webqueue-0.44.7}/tests/test_phase4_live_fixes.py +0 -0
  185. {kryten_webqueue-0.44.5 → kryten_webqueue-0.44.7}/tests/test_playlist_import.py +0 -0
  186. {kryten_webqueue-0.44.5 → kryten_webqueue-0.44.7}/tests/test_presence_refund.py +0 -0
  187. {kryten_webqueue-0.44.5 → kryten_webqueue-0.44.7}/tests/test_promo_director.py +0 -0
  188. {kryten_webqueue-0.44.5 → kryten_webqueue-0.44.7}/tests/test_promo_pool_exclusion.py +0 -0
  189. {kryten_webqueue-0.44.5 → kryten_webqueue-0.44.7}/tests/test_providers.py +0 -0
  190. {kryten_webqueue-0.44.5 → kryten_webqueue-0.44.7}/tests/test_queue_announce.py +0 -0
  191. {kryten_webqueue-0.44.5 → kryten_webqueue-0.44.7}/tests/test_queue_preview_fallback.py +0 -0
  192. {kryten_webqueue-0.44.5 → kryten_webqueue-0.44.7}/tests/test_race_poller.py +0 -0
  193. {kryten_webqueue-0.44.5 → kryten_webqueue-0.44.7}/tests/test_recently_played_hide.py +0 -0
  194. {kryten_webqueue-0.44.5 → kryten_webqueue-0.44.7}/tests/test_save_results_to_playlist.py +0 -0
  195. {kryten_webqueue-0.44.5 → kryten_webqueue-0.44.7}/tests/test_schedule_lock.py +0 -0
  196. {kryten_webqueue-0.44.5 → kryten_webqueue-0.44.7}/tests/test_search_facets.py +0 -0
  197. {kryten_webqueue-0.44.5 → kryten_webqueue-0.44.7}/tests/test_title_normalization.py +0 -0
  198. {kryten_webqueue-0.44.5 → kryten_webqueue-0.44.7}/tests/test_tmdb_index.py +0 -0
  199. {kryten_webqueue-0.44.5 → kryten_webqueue-0.44.7}/tests/test_watchlist.py +0 -0
@@ -1,5 +1,33 @@
1
1
  # Changelog
2
2
 
3
+ ## [0.44.7] - 2026-08-31
4
+
5
+ ### Fixed
6
+
7
+ - **SQLite WAL corruption mitigation.** The catalog DB connection now sets
8
+ `synchronous=NORMAL` (safe in WAL mode), `busy_timeout=5000` (retry on
9
+ lock contention instead of failing immediately), `wal_autocheckpoint=100`
10
+ (checkpoint every 100 pages instead of the 1000-page default, keeping the
11
+ WAL small), and runs a passive checkpoint on every connect to drain any
12
+ stale frames left by an unclean previous run.
13
+ - **`delete_stale_catalog_items` rewritten to use subqueries.** Previously
14
+ built a potentially huge `IN (?, ?, …)` parameter list (one bind for every
15
+ stale token) before issuing two separate bulk DELETEs. Now uses correlated
16
+ subqueries instead, eliminating the SELECT round-trip and the large
17
+ parameter list, reducing per-sync WAL pressure.
18
+
19
+ ## [0.44.6] - 2026-08-30
20
+
21
+ ### Fixed
22
+
23
+ - **Tubi (AES-128 HLS) downloads no longer fail ffprobe validation.** When
24
+ `ffprobe` exits non-zero but writes nothing to stderr — the common outcome
25
+ for TS/HLS-merged containers like Tubi movies — the pre-upload check now
26
+ treats it as a soft skip (same behaviour as when `ffprobe` is absent) rather
27
+ than a hard failure. A real error (non-empty stderr) still fails fast. All
28
+ error messages now include the filename so the admin job history is
29
+ actionable.
30
+
3
31
  ## [0.44.5] - 2026-08-30
4
32
 
5
33
  ### Fixed
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.5
2
2
  Name: kryten-webqueue
3
- Version: 0.44.5
3
+ Version: 0.44.7
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
@@ -1042,30 +1042,22 @@ class _CatalogMixin:
1042
1042
  - catalog_people
1043
1043
  - catalog_studios
1044
1044
  """
1045
- cursor = await self._db.execute(
1046
- "SELECT friendly_token FROM catalog WHERE synced_at < ? OR synced_at IS NULL",
1047
- [sync_started_at],
1048
- )
1049
- tokens = [row[0] for row in await cursor.fetchall()]
1050
-
1051
- if not tokens:
1052
- return 0
1053
-
1054
- # Delete from FTS first (not automatically cascaded)
1055
- placeholders = ",".join("?" * len(tokens))
1045
+ # Delete from FTS first (not automatically cascaded); use subquery to avoid
1046
+ # building a potentially huge IN-list parameter list for large syncs.
1056
1047
  await self._db.execute(
1057
- f"DELETE FROM catalog_fts WHERE friendly_token IN ({placeholders})",
1058
- tokens,
1048
+ "DELETE FROM catalog_fts WHERE friendly_token IN "
1049
+ "(SELECT friendly_token FROM catalog WHERE synced_at < ? OR synced_at IS NULL)",
1050
+ [sync_started_at],
1059
1051
  )
1060
1052
 
1061
1053
  # Delete from catalog (cascades to join tables via ON DELETE CASCADE)
1062
- await self._db.execute(
1063
- f"DELETE FROM catalog WHERE friendly_token IN ({placeholders})",
1064
- tokens,
1054
+ cursor = await self._db.execute(
1055
+ "DELETE FROM catalog WHERE synced_at < ? OR synced_at IS NULL",
1056
+ [sync_started_at],
1065
1057
  )
1066
-
1058
+ count = cursor.rowcount
1067
1059
  await self._db.commit()
1068
- return len(tokens)
1060
+ return count or 0
1069
1061
 
1070
1062
  async def find_catalog_by_title(self, title: str) -> dict | None:
1071
1063
  """Best-effort lookup of a catalog item whose title matches ``title``.
@@ -549,6 +549,10 @@ class _DBBase:
549
549
  self._db.row_factory = aiosqlite.Row
550
550
  await self._db.execute("PRAGMA journal_mode=WAL")
551
551
  await self._db.execute("PRAGMA foreign_keys=ON")
552
+ await self._db.execute("PRAGMA synchronous=NORMAL") # safe in WAL; faster than FULL
553
+ await self._db.execute("PRAGMA busy_timeout=5000") # retry up to 5 s on lock
554
+ await self._db.execute("PRAGMA wal_autocheckpoint=100") # checkpoint every 100 pages
555
+ await self._db.execute("PRAGMA wal_checkpoint(PASSIVE)") # drain any stale WAL on open
552
556
 
553
557
  async def close(self):
554
558
  if self._db:
@@ -3101,14 +3101,25 @@ class MediaDownloaderToMediaCMS:
3101
3101
  # ffprobe missing/errored: don't block the upload on our own check.
3102
3102
  print(f"[WARN] skipping pre-upload validation (ffprobe unavailable): {e}")
3103
3103
  return
3104
+ fname = os.path.basename(file_path)
3104
3105
  if proc.returncode != 0:
3106
+ stderr = proc.stderr.strip()
3107
+ if not stderr:
3108
+ # ffprobe exited non-zero but printed nothing to stderr — common
3109
+ # with certain TS/HLS-merged containers (e.g. Tubi AES-128).
3110
+ # Let MediaCMS be the final arbiter rather than blocking the upload.
3111
+ print(
3112
+ f"[WARN] ffprobe exited {proc.returncode} with no error output for"
3113
+ f" {fname}; skipping pre-upload validation"
3114
+ )
3115
+ return
3105
3116
  raise ValueError(
3106
- f"ffprobe could not read the file: {proc.stderr.strip()[:200]}"
3117
+ f"ffprobe could not read the file {fname}: {stderr[:200]}"
3107
3118
  )
3108
3119
  try:
3109
3120
  meta = json.loads(proc.stdout or "{}")
3110
3121
  except ValueError:
3111
- raise ValueError("ffprobe returned unparseable output")
3122
+ raise ValueError(f"ffprobe returned unparseable output for {fname}")
3112
3123
  has_video = any(
3113
3124
  s.get("codec_type") == "video" for s in meta.get("streams") or []
3114
3125
  )
@@ -3118,7 +3129,7 @@ class MediaDownloaderToMediaCMS:
3118
3129
  duration = 0.0
3119
3130
  if not has_video or duration <= 0:
3120
3131
  raise ValueError(
3121
- f"downloaded file is not a valid video (video_stream={has_video}, duration={duration})"
3132
+ f"{fname} is not a valid video (video_stream={has_video}, duration={duration})"
3122
3133
  )
3123
3134
 
3124
3135
  def process_video(
@@ -1,6 +1,6 @@
1
1
  [project]
2
2
  name = "kryten-webqueue"
3
- version = "0.44.5"
3
+ version = "0.44.7"
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"