kryten-webqueue 0.36.4__tar.gz → 0.36.5__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 (165) hide show
  1. {kryten_webqueue-0.36.4 → kryten_webqueue-0.36.5}/CHANGELOG.md +11 -0
  2. {kryten_webqueue-0.36.4 → kryten_webqueue-0.36.5}/PKG-INFO +1 -1
  3. {kryten_webqueue-0.36.4 → kryten_webqueue-0.36.5}/kryten_webqueue/catalog/enrichment/steps/tags.py +22 -37
  4. {kryten_webqueue-0.36.4 → kryten_webqueue-0.36.5}/pyproject.toml +1 -1
  5. {kryten_webqueue-0.36.4 → kryten_webqueue-0.36.5}/.github/workflows/gitleaks.yml +0 -0
  6. {kryten_webqueue-0.36.4 → kryten_webqueue-0.36.5}/.github/workflows/python-publish.yml +0 -0
  7. {kryten_webqueue-0.36.4 → kryten_webqueue-0.36.5}/.github/workflows/release.yml +0 -0
  8. {kryten_webqueue-0.36.4 → kryten_webqueue-0.36.5}/.gitignore +0 -0
  9. {kryten_webqueue-0.36.4 → kryten_webqueue-0.36.5}/.gitleaks.toml +0 -0
  10. {kryten_webqueue-0.36.4 → kryten_webqueue-0.36.5}/.pre-commit-config.yaml +0 -0
  11. {kryten_webqueue-0.36.4 → kryten_webqueue-0.36.5}/AGENT-WORKFLOW-GUIDE.md +0 -0
  12. {kryten_webqueue-0.36.4 → kryten_webqueue-0.36.5}/README.md +0 -0
  13. {kryten_webqueue-0.36.4 → kryten_webqueue-0.36.5}/config.example.json +0 -0
  14. {kryten_webqueue-0.36.4 → kryten_webqueue-0.36.5}/deploy/kryten-webqueue.service +0 -0
  15. {kryten_webqueue-0.36.4 → kryten_webqueue-0.36.5}/deploy/nginx-queue.conf +0 -0
  16. {kryten_webqueue-0.36.4 → kryten_webqueue-0.36.5}/docs/IMPLEMENTATION_SPEC.md +0 -0
  17. {kryten_webqueue-0.36.4 → kryten_webqueue-0.36.5}/docs/IMPL_API_GATE.md +0 -0
  18. {kryten_webqueue-0.36.4 → kryten_webqueue-0.36.5}/docs/IMPL_ECONOMY.md +0 -0
  19. {kryten_webqueue-0.36.4 → kryten_webqueue-0.36.5}/docs/IMPL_KRYTEN_PY.md +0 -0
  20. {kryten_webqueue-0.36.4 → kryten_webqueue-0.36.5}/docs/IMPL_ROBOT.md +0 -0
  21. {kryten_webqueue-0.36.4 → kryten_webqueue-0.36.5}/docs/Kryten-Economy Service Quality Survey Report at v0.13.0.md +0 -0
  22. {kryten_webqueue-0.36.4 → kryten_webqueue-0.36.5}/docs/Kryten-Webqueue Service Quality Survey Report at v0.27.1.md +0 -0
  23. {kryten_webqueue-0.36.4 → kryten_webqueue-0.36.5}/docs/Log for incorrect promo insertion problem.txt +0 -0
  24. {kryten_webqueue-0.36.4 → kryten_webqueue-0.36.5}/docs/PLAN_PRESENCE_AND_PROMOS.md +0 -0
  25. {kryten_webqueue-0.36.4 → kryten_webqueue-0.36.5}/docs/PRE_PLAN_GAPS.md +0 -0
  26. {kryten_webqueue-0.36.4 → kryten_webqueue-0.36.5}/docs/PRODUCT_PLAN.md +0 -0
  27. {kryten_webqueue-0.36.4 → kryten_webqueue-0.36.5}/docs/SPEC_CATALOG_ENRICHMENT_PIPELINE.md +0 -0
  28. {kryten_webqueue-0.36.4 → kryten_webqueue-0.36.5}/docs/SPEC_EMOTE_REHOST.md +0 -0
  29. {kryten_webqueue-0.36.4 → kryten_webqueue-0.36.5}/docs/SPEC_JOBS_AND_BROWSE.md +0 -0
  30. {kryten_webqueue-0.36.4 → kryten_webqueue-0.36.5}/docs/UX_POLISH_PLAN.md +0 -0
  31. {kryten_webqueue-0.36.4 → kryten_webqueue-0.36.5}/kryten_webqueue/__init__.py +0 -0
  32. {kryten_webqueue-0.36.4 → kryten_webqueue-0.36.5}/kryten_webqueue/__main__.py +0 -0
  33. {kryten_webqueue-0.36.4 → kryten_webqueue-0.36.5}/kryten_webqueue/api_gate/__init__.py +0 -0
  34. {kryten_webqueue-0.36.4 → kryten_webqueue-0.36.5}/kryten_webqueue/api_gate/client.py +0 -0
  35. {kryten_webqueue-0.36.4 → kryten_webqueue-0.36.5}/kryten_webqueue/app.py +0 -0
  36. {kryten_webqueue-0.36.4 → kryten_webqueue-0.36.5}/kryten_webqueue/auth/__init__.py +0 -0
  37. {kryten_webqueue-0.36.4 → kryten_webqueue-0.36.5}/kryten_webqueue/auth/otp.py +0 -0
  38. {kryten_webqueue-0.36.4 → kryten_webqueue-0.36.5}/kryten_webqueue/auth/rate_limit.py +0 -0
  39. {kryten_webqueue-0.36.4 → kryten_webqueue-0.36.5}/kryten_webqueue/auth/session.py +0 -0
  40. {kryten_webqueue-0.36.4 → kryten_webqueue-0.36.5}/kryten_webqueue/catalog/__init__.py +0 -0
  41. {kryten_webqueue-0.36.4 → kryten_webqueue-0.36.5}/kryten_webqueue/catalog/db/__init__.py +0 -0
  42. {kryten_webqueue-0.36.4 → kryten_webqueue-0.36.5}/kryten_webqueue/catalog/db/_catalog.py +0 -0
  43. {kryten_webqueue-0.36.4 → kryten_webqueue-0.36.5}/kryten_webqueue/catalog/db/_connection.py +0 -0
  44. {kryten_webqueue-0.36.4 → kryten_webqueue-0.36.5}/kryten_webqueue/catalog/db/_enrichment.py +0 -0
  45. {kryten_webqueue-0.36.4 → kryten_webqueue-0.36.5}/kryten_webqueue/catalog/db/_feedback.py +0 -0
  46. {kryten_webqueue-0.36.4 → kryten_webqueue-0.36.5}/kryten_webqueue/catalog/db/_people.py +0 -0
  47. {kryten_webqueue-0.36.4 → kryten_webqueue-0.36.5}/kryten_webqueue/catalog/db/_playlists.py +0 -0
  48. {kryten_webqueue-0.36.4 → kryten_webqueue-0.36.5}/kryten_webqueue/catalog/db/_queue.py +0 -0
  49. {kryten_webqueue-0.36.4 → kryten_webqueue-0.36.5}/kryten_webqueue/catalog/db/_watchlist.py +0 -0
  50. {kryten_webqueue-0.36.4 → kryten_webqueue-0.36.5}/kryten_webqueue/catalog/enrichment/__init__.py +0 -0
  51. {kryten_webqueue-0.36.4 → kryten_webqueue-0.36.5}/kryten_webqueue/catalog/enrichment/classify.py +0 -0
  52. {kryten_webqueue-0.36.4 → kryten_webqueue-0.36.5}/kryten_webqueue/catalog/enrichment/normalise.py +0 -0
  53. {kryten_webqueue-0.36.4 → kryten_webqueue-0.36.5}/kryten_webqueue/catalog/enrichment/pipeline.py +0 -0
  54. {kryten_webqueue-0.36.4 → kryten_webqueue-0.36.5}/kryten_webqueue/catalog/enrichment/providers.py +0 -0
  55. {kryten_webqueue-0.36.4 → kryten_webqueue-0.36.5}/kryten_webqueue/catalog/enrichment/report.py +0 -0
  56. {kryten_webqueue-0.36.4 → kryten_webqueue-0.36.5}/kryten_webqueue/catalog/enrichment/steps/__init__.py +0 -0
  57. {kryten_webqueue-0.36.4 → kryten_webqueue-0.36.5}/kryten_webqueue/catalog/enrichment/steps/art.py +0 -0
  58. {kryten_webqueue-0.36.4 → kryten_webqueue-0.36.5}/kryten_webqueue/catalog/enrichment/steps/categories.py +0 -0
  59. {kryten_webqueue-0.36.4 → kryten_webqueue-0.36.5}/kryten_webqueue/catalog/enrichment/steps/meta.py +0 -0
  60. {kryten_webqueue-0.36.4 → kryten_webqueue-0.36.5}/kryten_webqueue/catalog/enrichment/steps/sync.py +0 -0
  61. {kryten_webqueue-0.36.4 → kryten_webqueue-0.36.5}/kryten_webqueue/catalog/enrichment/steps/title.py +0 -0
  62. {kryten_webqueue-0.36.4 → kryten_webqueue-0.36.5}/kryten_webqueue/catalog/images.py +0 -0
  63. {kryten_webqueue-0.36.4 → kryten_webqueue-0.36.5}/kryten_webqueue/catalog/mediacms.py +0 -0
  64. {kryten_webqueue-0.36.4 → kryten_webqueue-0.36.5}/kryten_webqueue/catalog/sync.py +0 -0
  65. {kryten_webqueue-0.36.4 → kryten_webqueue-0.36.5}/kryten_webqueue/config.py +0 -0
  66. {kryten_webqueue-0.36.4 → kryten_webqueue-0.36.5}/kryten_webqueue/integrations/__init__.py +0 -0
  67. {kryten_webqueue-0.36.4 → kryten_webqueue-0.36.5}/kryten_webqueue/integrations/cmsutils/__init__.py +0 -0
  68. {kryten_webqueue-0.36.4 → kryten_webqueue-0.36.5}/kryten_webqueue/integrations/cmsutils/_common.py +0 -0
  69. {kryten_webqueue-0.36.4 → kryten_webqueue-0.36.5}/kryten_webqueue/integrations/cmsutils/enrichmeta.py +0 -0
  70. {kryten_webqueue-0.36.4 → kryten_webqueue-0.36.5}/kryten_webqueue/integrations/cmsutils/enrichtitles.py +0 -0
  71. {kryten_webqueue-0.36.4 → kryten_webqueue-0.36.5}/kryten_webqueue/integrations/cmsutils/enrichtv.py +0 -0
  72. {kryten_webqueue-0.36.4 → kryten_webqueue-0.36.5}/kryten_webqueue/integrations/cmsutils/fetchurls.py +0 -0
  73. {kryten_webqueue-0.36.4 → kryten_webqueue-0.36.5}/kryten_webqueue/integrations/cmsutils/motdposters.py +0 -0
  74. {kryten_webqueue-0.36.4 → kryten_webqueue-0.36.5}/kryten_webqueue/integrations/cmsutils/playedmovies.py +0 -0
  75. {kryten_webqueue-0.36.4 → kryten_webqueue-0.36.5}/kryten_webqueue/integrations/ytpipe/__init__.py +0 -0
  76. {kryten_webqueue-0.36.4 → kryten_webqueue-0.36.5}/kryten_webqueue/integrations/ytpipe/downloader.py +0 -0
  77. {kryten_webqueue-0.36.4 → kryten_webqueue-0.36.5}/kryten_webqueue/jobs/__init__.py +0 -0
  78. {kryten_webqueue-0.36.4 → kryten_webqueue-0.36.5}/kryten_webqueue/jobs/fetchurls_auth.py +0 -0
  79. {kryten_webqueue-0.36.4 → kryten_webqueue-0.36.5}/kryten_webqueue/jobs/job_scheduler.py +0 -0
  80. {kryten_webqueue-0.36.4 → kryten_webqueue-0.36.5}/kryten_webqueue/jobs/manager.py +0 -0
  81. {kryten_webqueue-0.36.4 → kryten_webqueue-0.36.5}/kryten_webqueue/jobs/rehost_emotes.py +0 -0
  82. {kryten_webqueue-0.36.4 → kryten_webqueue-0.36.5}/kryten_webqueue/jobs/tasks.py +0 -0
  83. {kryten_webqueue-0.36.4 → kryten_webqueue-0.36.5}/kryten_webqueue/logging_config.py +0 -0
  84. {kryten_webqueue-0.36.4 → kryten_webqueue-0.36.5}/kryten_webqueue/playlists/__init__.py +0 -0
  85. {kryten_webqueue-0.36.4 → kryten_webqueue-0.36.5}/kryten_webqueue/playlists/bulk_add.py +0 -0
  86. {kryten_webqueue-0.36.4 → kryten_webqueue-0.36.5}/kryten_webqueue/playlists/fire.py +0 -0
  87. {kryten_webqueue-0.36.4 → kryten_webqueue-0.36.5}/kryten_webqueue/playlists/importer.py +0 -0
  88. {kryten_webqueue-0.36.4 → kryten_webqueue-0.36.5}/kryten_webqueue/playlists/ordering.py +0 -0
  89. {kryten_webqueue-0.36.4 → kryten_webqueue-0.36.5}/kryten_webqueue/playlists/scheduler.py +0 -0
  90. {kryten_webqueue-0.36.4 → kryten_webqueue-0.36.5}/kryten_webqueue/promos/__init__.py +0 -0
  91. {kryten_webqueue-0.36.4 → kryten_webqueue-0.36.5}/kryten_webqueue/promos/director.py +0 -0
  92. {kryten_webqueue-0.36.4 → kryten_webqueue-0.36.5}/kryten_webqueue/queue/__init__.py +0 -0
  93. {kryten_webqueue-0.36.4 → kryten_webqueue-0.36.5}/kryten_webqueue/queue/completion.py +0 -0
  94. {kryten_webqueue-0.36.4 → kryten_webqueue-0.36.5}/kryten_webqueue/queue/ordering.py +0 -0
  95. {kryten_webqueue-0.36.4 → kryten_webqueue-0.36.5}/kryten_webqueue/queue/poller.py +0 -0
  96. {kryten_webqueue-0.36.4 → kryten_webqueue-0.36.5}/kryten_webqueue/queue/presence.py +0 -0
  97. {kryten_webqueue-0.36.4 → kryten_webqueue-0.36.5}/kryten_webqueue/queue/race_poller.py +0 -0
  98. {kryten_webqueue-0.36.4 → kryten_webqueue-0.36.5}/kryten_webqueue/queue/shadow.py +0 -0
  99. {kryten_webqueue-0.36.4 → kryten_webqueue-0.36.5}/kryten_webqueue/routes/__init__.py +0 -0
  100. {kryten_webqueue-0.36.4 → kryten_webqueue-0.36.5}/kryten_webqueue/routes/admin_catalog.py +0 -0
  101. {kryten_webqueue-0.36.4 → kryten_webqueue-0.36.5}/kryten_webqueue/routes/admin_feedback.py +0 -0
  102. {kryten_webqueue-0.36.4 → kryten_webqueue-0.36.5}/kryten_webqueue/routes/admin_job_schedules.py +0 -0
  103. {kryten_webqueue-0.36.4 → kryten_webqueue-0.36.5}/kryten_webqueue/routes/admin_jobs.py +0 -0
  104. {kryten_webqueue-0.36.4 → kryten_webqueue-0.36.5}/kryten_webqueue/routes/admin_moderation.py +0 -0
  105. {kryten_webqueue-0.36.4 → kryten_webqueue-0.36.5}/kryten_webqueue/routes/admin_playlists.py +0 -0
  106. {kryten_webqueue-0.36.4 → kryten_webqueue-0.36.5}/kryten_webqueue/routes/admin_promos.py +0 -0
  107. {kryten_webqueue-0.36.4 → kryten_webqueue-0.36.5}/kryten_webqueue/routes/admin_queue.py +0 -0
  108. {kryten_webqueue-0.36.4 → kryten_webqueue-0.36.5}/kryten_webqueue/routes/admin_schedules.py +0 -0
  109. {kryten_webqueue-0.36.4 → kryten_webqueue-0.36.5}/kryten_webqueue/routes/auth.py +0 -0
  110. {kryten_webqueue-0.36.4 → kryten_webqueue-0.36.5}/kryten_webqueue/routes/catalog.py +0 -0
  111. {kryten_webqueue-0.36.4 → kryten_webqueue-0.36.5}/kryten_webqueue/routes/feedback.py +0 -0
  112. {kryten_webqueue-0.36.4 → kryten_webqueue-0.36.5}/kryten_webqueue/routes/pages.py +0 -0
  113. {kryten_webqueue-0.36.4 → kryten_webqueue-0.36.5}/kryten_webqueue/routes/queue.py +0 -0
  114. {kryten_webqueue-0.36.4 → kryten_webqueue-0.36.5}/kryten_webqueue/routes/user.py +0 -0
  115. {kryten_webqueue-0.36.4 → kryten_webqueue-0.36.5}/kryten_webqueue/static/css/main.css +0 -0
  116. {kryten_webqueue-0.36.4 → kryten_webqueue-0.36.5}/kryten_webqueue/static/js/admin-playlists.js +0 -0
  117. {kryten_webqueue-0.36.4 → kryten_webqueue-0.36.5}/kryten_webqueue/static/js/admin-promos.js +0 -0
  118. {kryten_webqueue-0.36.4 → kryten_webqueue-0.36.5}/kryten_webqueue/static/js/admin-queue-mgmt.js +0 -0
  119. {kryten_webqueue-0.36.4 → kryten_webqueue-0.36.5}/kryten_webqueue/static/js/admin-schedules.js +0 -0
  120. {kryten_webqueue-0.36.4 → kryten_webqueue-0.36.5}/kryten_webqueue/static/js/admin.js +0 -0
  121. {kryten_webqueue-0.36.4 → kryten_webqueue-0.36.5}/kryten_webqueue/static/js/main.js +0 -0
  122. {kryten_webqueue-0.36.4 → kryten_webqueue-0.36.5}/kryten_webqueue/templates/admin/index.html +0 -0
  123. {kryten_webqueue-0.36.4 → kryten_webqueue-0.36.5}/kryten_webqueue/templates/admin/playlists.html +0 -0
  124. {kryten_webqueue-0.36.4 → kryten_webqueue-0.36.5}/kryten_webqueue/templates/admin/promos.html +0 -0
  125. {kryten_webqueue-0.36.4 → kryten_webqueue-0.36.5}/kryten_webqueue/templates/admin/queue_mgmt.html +0 -0
  126. {kryten_webqueue-0.36.4 → kryten_webqueue-0.36.5}/kryten_webqueue/templates/admin/schedules.html +0 -0
  127. {kryten_webqueue-0.36.4 → kryten_webqueue-0.36.5}/kryten_webqueue/templates/auth/login.html +0 -0
  128. {kryten_webqueue-0.36.4 → kryten_webqueue-0.36.5}/kryten_webqueue/templates/base.html +0 -0
  129. {kryten_webqueue-0.36.4 → kryten_webqueue-0.36.5}/kryten_webqueue/templates/catalog/browse.html +0 -0
  130. {kryten_webqueue-0.36.4 → kryten_webqueue-0.36.5}/kryten_webqueue/templates/catalog/item_detail.html +0 -0
  131. {kryten_webqueue-0.36.4 → kryten_webqueue-0.36.5}/kryten_webqueue/templates/catalog/item_not_found.html +0 -0
  132. {kryten_webqueue-0.36.4 → kryten_webqueue-0.36.5}/kryten_webqueue/templates/feedback/index.html +0 -0
  133. {kryten_webqueue-0.36.4 → kryten_webqueue-0.36.5}/kryten_webqueue/templates/queue/index.html +0 -0
  134. {kryten_webqueue-0.36.4 → kryten_webqueue-0.36.5}/kryten_webqueue/templates/race.html +0 -0
  135. {kryten_webqueue-0.36.4 → kryten_webqueue-0.36.5}/kryten_webqueue/templates/user/dashboard.html +0 -0
  136. {kryten_webqueue-0.36.4 → kryten_webqueue-0.36.5}/kryten_webqueue/templates/user/my_list.html +0 -0
  137. {kryten_webqueue-0.36.4 → kryten_webqueue-0.36.5}/kryten_webqueue/ws/__init__.py +0 -0
  138. {kryten_webqueue-0.36.4 → kryten_webqueue-0.36.5}/kryten_webqueue/ws/handler.py +0 -0
  139. {kryten_webqueue-0.36.4 → kryten_webqueue-0.36.5}/kryten_webqueue/ws/manager.py +0 -0
  140. {kryten_webqueue-0.36.4 → kryten_webqueue-0.36.5}/scripts/patch_mediacms_bulk_facets.py +0 -0
  141. {kryten_webqueue-0.36.4 → kryten_webqueue-0.36.5}/scripts/patch_mediacms_tags.py +0 -0
  142. {kryten_webqueue-0.36.4 → kryten_webqueue-0.36.5}/scripts/trigger_enrich.py +0 -0
  143. {kryten_webqueue-0.36.4 → kryten_webqueue-0.36.5}/tests/__init__.py +0 -0
  144. {kryten_webqueue-0.36.4 → kryten_webqueue-0.36.5}/tests/test_classify.py +0 -0
  145. {kryten_webqueue-0.36.4 → kryten_webqueue-0.36.5}/tests/test_config_persistence.py +0 -0
  146. {kryten_webqueue-0.36.4 → kryten_webqueue-0.36.5}/tests/test_feedback.py +0 -0
  147. {kryten_webqueue-0.36.4 → kryten_webqueue-0.36.5}/tests/test_fetchurls_sharepoint.py +0 -0
  148. {kryten_webqueue-0.36.4 → kryten_webqueue-0.36.5}/tests/test_people_facets.py +0 -0
  149. {kryten_webqueue-0.36.4 → kryten_webqueue-0.36.5}/tests/test_phase1.py +0 -0
  150. {kryten_webqueue-0.36.4 → kryten_webqueue-0.36.5}/tests/test_phase2_jobs.py +0 -0
  151. {kryten_webqueue-0.36.4 → kryten_webqueue-0.36.5}/tests/test_phase3_jobs.py +0 -0
  152. {kryten_webqueue-0.36.4 → kryten_webqueue-0.36.5}/tests/test_phase4_live_fixes.py +0 -0
  153. {kryten_webqueue-0.36.4 → kryten_webqueue-0.36.5}/tests/test_playlist_import.py +0 -0
  154. {kryten_webqueue-0.36.4 → kryten_webqueue-0.36.5}/tests/test_presence_refund.py +0 -0
  155. {kryten_webqueue-0.36.4 → kryten_webqueue-0.36.5}/tests/test_promo_director.py +0 -0
  156. {kryten_webqueue-0.36.4 → kryten_webqueue-0.36.5}/tests/test_promo_pool_exclusion.py +0 -0
  157. {kryten_webqueue-0.36.4 → kryten_webqueue-0.36.5}/tests/test_providers.py +0 -0
  158. {kryten_webqueue-0.36.4 → kryten_webqueue-0.36.5}/tests/test_queue_announce.py +0 -0
  159. {kryten_webqueue-0.36.4 → kryten_webqueue-0.36.5}/tests/test_race_poller.py +0 -0
  160. {kryten_webqueue-0.36.4 → kryten_webqueue-0.36.5}/tests/test_recently_played_hide.py +0 -0
  161. {kryten_webqueue-0.36.4 → kryten_webqueue-0.36.5}/tests/test_save_results_to_playlist.py +0 -0
  162. {kryten_webqueue-0.36.4 → kryten_webqueue-0.36.5}/tests/test_schedule_lock.py +0 -0
  163. {kryten_webqueue-0.36.4 → kryten_webqueue-0.36.5}/tests/test_search_facets.py +0 -0
  164. {kryten_webqueue-0.36.4 → kryten_webqueue-0.36.5}/tests/test_title_normalization.py +0 -0
  165. {kryten_webqueue-0.36.4 → kryten_webqueue-0.36.5}/tests/test_watchlist.py +0 -0
@@ -2,6 +2,17 @@
2
2
 
3
3
  ## [Unreleased]
4
4
 
5
+ ## [0.36.5] - 2026-08-14
6
+
7
+ ### Changed
8
+
9
+ - **Tags step no longer reads every item.** With `mediacms_manage_all_media` set,
10
+ the tags step now issues a single idempotent `add_tags` POST per item (the
11
+ server skips tags already present) instead of a per-item `GET` to read current
12
+ tags/owner. The redundant per-item reverse-sync `GET` was also removed — catalog
13
+ sync already mirrors CMS tags in bulk via `/api/v1/media_facets`. Stock-CMS
14
+ (owner-scoped) deployments still do the ownership `GET` on the fallback path.
15
+
5
16
  ## [0.36.4] - 2026-08-14
6
17
 
7
18
  ### Changed
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.5
2
2
  Name: kryten-webqueue
3
- Version: 0.36.4
3
+ Version: 0.36.5
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
@@ -117,8 +117,6 @@ class TagsStep:
117
117
  desired,
118
118
  api_user=api_user,
119
119
  )
120
- # Reverse sync: pull any CMS-only tags back to local DB
121
- await self._reverse_sync(client, cls.friendly_token)
122
120
  if changed:
123
121
  result.changed += 1
124
122
  else:
@@ -148,50 +146,37 @@ class TagsStep:
148
146
 
149
147
  The ``PUT /media/{token}`` endpoint only accepts title/description/media_file
150
148
  and silently ignores a ``tags`` field, so tag changes must go through
151
- ``POST /media/user/bulk_actions`` with ``action: add_tags``. On stock
152
- MediaCMS that endpoint is owner-scoped, so unless ``manage_all`` is set we
153
- skip the push for media the API user does not own rather than flooding
154
- CMS with 400s.
149
+ ``POST /media/user/bulk_actions`` with ``action: add_tags``.
150
+
151
+ When ``manage_all`` is set the server-side ``add_tags`` is idempotent
152
+ (it skips tags already present), so we POST directly with no per-item GET.
153
+ On stock MediaCMS the endpoint is owner-scoped, so we must first GET the
154
+ item to check ownership and skip the push for media we do not own.
155
155
  """
156
- detail_url = f"{self._base}/api/v1/media/{token}"
157
156
  try:
158
- resp = await client.get(detail_url)
159
- if resp.status_code != 200:
160
- return False
161
- data = resp.json()
162
- owner = data.get("user")
163
- if not self._manage_all and (api_user is None or owner != api_user):
164
- return False
165
- current = {
166
- (t.get("title") if isinstance(t, dict) else t)
167
- for t in (data.get("tags_info") or [])
168
- }
169
- to_add = [t for t in new_tags if t not in current]
170
- if not to_add:
171
- return False
157
+ if not self._manage_all:
158
+ resp = await client.get(f"{self._base}/api/v1/media/{token}")
159
+ if resp.status_code != 200:
160
+ return False
161
+ data = resp.json()
162
+ owner = data.get("user")
163
+ if api_user is None or owner != api_user:
164
+ return False
165
+ current = {
166
+ (t.get("title") if isinstance(t, dict) else t)
167
+ for t in (data.get("tags_info") or [])
168
+ }
169
+ new_tags = [t for t in new_tags if t not in current]
170
+ if not new_tags:
171
+ return False
172
172
  put = await client.post(
173
173
  f"{self._base}/api/v1/media/user/bulk_actions",
174
174
  json={
175
175
  "action": "add_tags",
176
176
  "media_ids": [token],
177
- "tag_titles": to_add,
177
+ "tag_titles": new_tags,
178
178
  },
179
179
  )
180
180
  return put.status_code in (200, 201)
181
181
  except (httpx.HTTPError, json.JSONDecodeError, ValueError):
182
182
  return False
183
-
184
- async def _reverse_sync(self, client: httpx.AsyncClient, token: str) -> None:
185
- """Insert any CMS-only tags into the local catalog_tags table."""
186
- url = f"{self._base}/api/v1/media/{token}"
187
- try:
188
- resp = await client.get(url)
189
- if resp.status_code != 200:
190
- return
191
- data = resp.json()
192
- for t in data.get("tags_info") or []:
193
- name = t.get("title") if isinstance(t, dict) else t
194
- if name:
195
- await self._db.add_catalog_tag(token, str(name))
196
- except (httpx.HTTPError, json.JSONDecodeError, ValueError) as exc:
197
- logger.warning("[tags] Failed reverse-sync for %s: %s", token, exc)
@@ -1,6 +1,6 @@
1
1
  [project]
2
2
  name = "kryten-webqueue"
3
- version = "0.36.4"
3
+ version = "0.36.5"
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"