kryten-webqueue 0.18.0__tar.gz → 0.19.0__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 (105) hide show
  1. {kryten_webqueue-0.18.0 → kryten_webqueue-0.19.0}/CHANGELOG.md +8 -0
  2. {kryten_webqueue-0.18.0 → kryten_webqueue-0.19.0}/PKG-INFO +1 -1
  3. {kryten_webqueue-0.18.0 → kryten_webqueue-0.19.0}/kryten_webqueue/static/css/main.css +33 -13
  4. {kryten_webqueue-0.18.0 → kryten_webqueue-0.19.0}/kryten_webqueue/templates/user/dashboard.html +56 -28
  5. {kryten_webqueue-0.18.0 → kryten_webqueue-0.19.0}/pyproject.toml +1 -1
  6. {kryten_webqueue-0.18.0 → kryten_webqueue-0.19.0}/.github/workflows/python-publish.yml +0 -0
  7. {kryten_webqueue-0.18.0 → kryten_webqueue-0.19.0}/.github/workflows/release.yml +0 -0
  8. {kryten_webqueue-0.18.0 → kryten_webqueue-0.19.0}/.gitignore +0 -0
  9. {kryten_webqueue-0.18.0 → kryten_webqueue-0.19.0}/README.md +0 -0
  10. {kryten_webqueue-0.18.0 → kryten_webqueue-0.19.0}/config.example.json +0 -0
  11. {kryten_webqueue-0.18.0 → kryten_webqueue-0.19.0}/deploy/kryten-webqueue.service +0 -0
  12. {kryten_webqueue-0.18.0 → kryten_webqueue-0.19.0}/deploy/nginx-queue.conf +0 -0
  13. {kryten_webqueue-0.18.0 → kryten_webqueue-0.19.0}/docs/IMPLEMENTATION_SPEC.md +0 -0
  14. {kryten_webqueue-0.18.0 → kryten_webqueue-0.19.0}/docs/IMPL_API_GATE.md +0 -0
  15. {kryten_webqueue-0.18.0 → kryten_webqueue-0.19.0}/docs/IMPL_ECONOMY.md +0 -0
  16. {kryten_webqueue-0.18.0 → kryten_webqueue-0.19.0}/docs/IMPL_KRYTEN_PY.md +0 -0
  17. {kryten_webqueue-0.18.0 → kryten_webqueue-0.19.0}/docs/IMPL_ROBOT.md +0 -0
  18. {kryten_webqueue-0.18.0 → kryten_webqueue-0.19.0}/docs/PLAN_PRESENCE_AND_PROMOS.md +0 -0
  19. {kryten_webqueue-0.18.0 → kryten_webqueue-0.19.0}/docs/PRE_PLAN_GAPS.md +0 -0
  20. {kryten_webqueue-0.18.0 → kryten_webqueue-0.19.0}/docs/PRODUCT_PLAN.md +0 -0
  21. {kryten_webqueue-0.18.0 → kryten_webqueue-0.19.0}/docs/SPEC_JOBS_AND_BROWSE.md +0 -0
  22. {kryten_webqueue-0.18.0 → kryten_webqueue-0.19.0}/docs/UX_POLISH_PLAN.md +0 -0
  23. {kryten_webqueue-0.18.0 → kryten_webqueue-0.19.0}/kryten_webqueue/__init__.py +0 -0
  24. {kryten_webqueue-0.18.0 → kryten_webqueue-0.19.0}/kryten_webqueue/__main__.py +0 -0
  25. {kryten_webqueue-0.18.0 → kryten_webqueue-0.19.0}/kryten_webqueue/api_gate/__init__.py +0 -0
  26. {kryten_webqueue-0.18.0 → kryten_webqueue-0.19.0}/kryten_webqueue/api_gate/client.py +0 -0
  27. {kryten_webqueue-0.18.0 → kryten_webqueue-0.19.0}/kryten_webqueue/app.py +0 -0
  28. {kryten_webqueue-0.18.0 → kryten_webqueue-0.19.0}/kryten_webqueue/auth/__init__.py +0 -0
  29. {kryten_webqueue-0.18.0 → kryten_webqueue-0.19.0}/kryten_webqueue/auth/otp.py +0 -0
  30. {kryten_webqueue-0.18.0 → kryten_webqueue-0.19.0}/kryten_webqueue/auth/rate_limit.py +0 -0
  31. {kryten_webqueue-0.18.0 → kryten_webqueue-0.19.0}/kryten_webqueue/auth/session.py +0 -0
  32. {kryten_webqueue-0.18.0 → kryten_webqueue-0.19.0}/kryten_webqueue/catalog/__init__.py +0 -0
  33. {kryten_webqueue-0.18.0 → kryten_webqueue-0.19.0}/kryten_webqueue/catalog/db.py +0 -0
  34. {kryten_webqueue-0.18.0 → kryten_webqueue-0.19.0}/kryten_webqueue/catalog/images.py +0 -0
  35. {kryten_webqueue-0.18.0 → kryten_webqueue-0.19.0}/kryten_webqueue/catalog/mediacms.py +0 -0
  36. {kryten_webqueue-0.18.0 → kryten_webqueue-0.19.0}/kryten_webqueue/catalog/sync.py +0 -0
  37. {kryten_webqueue-0.18.0 → kryten_webqueue-0.19.0}/kryten_webqueue/config.py +0 -0
  38. {kryten_webqueue-0.18.0 → kryten_webqueue-0.19.0}/kryten_webqueue/integrations/__init__.py +0 -0
  39. {kryten_webqueue-0.18.0 → kryten_webqueue-0.19.0}/kryten_webqueue/integrations/cmsutils/__init__.py +0 -0
  40. {kryten_webqueue-0.18.0 → kryten_webqueue-0.19.0}/kryten_webqueue/integrations/cmsutils/_common.py +0 -0
  41. {kryten_webqueue-0.18.0 → kryten_webqueue-0.19.0}/kryten_webqueue/integrations/cmsutils/enrichmeta.py +0 -0
  42. {kryten_webqueue-0.18.0 → kryten_webqueue-0.19.0}/kryten_webqueue/integrations/cmsutils/enrichtitles.py +0 -0
  43. {kryten_webqueue-0.18.0 → kryten_webqueue-0.19.0}/kryten_webqueue/integrations/cmsutils/enrichtv.py +0 -0
  44. {kryten_webqueue-0.18.0 → kryten_webqueue-0.19.0}/kryten_webqueue/integrations/cmsutils/fetchurls.py +0 -0
  45. {kryten_webqueue-0.18.0 → kryten_webqueue-0.19.0}/kryten_webqueue/integrations/ytpipe/__init__.py +0 -0
  46. {kryten_webqueue-0.18.0 → kryten_webqueue-0.19.0}/kryten_webqueue/integrations/ytpipe/downloader.py +0 -0
  47. {kryten_webqueue-0.18.0 → kryten_webqueue-0.19.0}/kryten_webqueue/jobs/__init__.py +0 -0
  48. {kryten_webqueue-0.18.0 → kryten_webqueue-0.19.0}/kryten_webqueue/jobs/fetchurls_auth.py +0 -0
  49. {kryten_webqueue-0.18.0 → kryten_webqueue-0.19.0}/kryten_webqueue/jobs/manager.py +0 -0
  50. {kryten_webqueue-0.18.0 → kryten_webqueue-0.19.0}/kryten_webqueue/jobs/tasks.py +0 -0
  51. {kryten_webqueue-0.18.0 → kryten_webqueue-0.19.0}/kryten_webqueue/logging_config.py +0 -0
  52. {kryten_webqueue-0.18.0 → kryten_webqueue-0.19.0}/kryten_webqueue/playlists/__init__.py +0 -0
  53. {kryten_webqueue-0.18.0 → kryten_webqueue-0.19.0}/kryten_webqueue/playlists/bulk_add.py +0 -0
  54. {kryten_webqueue-0.18.0 → kryten_webqueue-0.19.0}/kryten_webqueue/playlists/fire.py +0 -0
  55. {kryten_webqueue-0.18.0 → kryten_webqueue-0.19.0}/kryten_webqueue/playlists/importer.py +0 -0
  56. {kryten_webqueue-0.18.0 → kryten_webqueue-0.19.0}/kryten_webqueue/playlists/ordering.py +0 -0
  57. {kryten_webqueue-0.18.0 → kryten_webqueue-0.19.0}/kryten_webqueue/playlists/scheduler.py +0 -0
  58. {kryten_webqueue-0.18.0 → kryten_webqueue-0.19.0}/kryten_webqueue/promos/__init__.py +0 -0
  59. {kryten_webqueue-0.18.0 → kryten_webqueue-0.19.0}/kryten_webqueue/promos/director.py +0 -0
  60. {kryten_webqueue-0.18.0 → kryten_webqueue-0.19.0}/kryten_webqueue/queue/__init__.py +0 -0
  61. {kryten_webqueue-0.18.0 → kryten_webqueue-0.19.0}/kryten_webqueue/queue/ordering.py +0 -0
  62. {kryten_webqueue-0.18.0 → kryten_webqueue-0.19.0}/kryten_webqueue/queue/poller.py +0 -0
  63. {kryten_webqueue-0.18.0 → kryten_webqueue-0.19.0}/kryten_webqueue/queue/presence.py +0 -0
  64. {kryten_webqueue-0.18.0 → kryten_webqueue-0.19.0}/kryten_webqueue/queue/shadow.py +0 -0
  65. {kryten_webqueue-0.18.0 → kryten_webqueue-0.19.0}/kryten_webqueue/routes/__init__.py +0 -0
  66. {kryten_webqueue-0.18.0 → kryten_webqueue-0.19.0}/kryten_webqueue/routes/admin_catalog.py +0 -0
  67. {kryten_webqueue-0.18.0 → kryten_webqueue-0.19.0}/kryten_webqueue/routes/admin_jobs.py +0 -0
  68. {kryten_webqueue-0.18.0 → kryten_webqueue-0.19.0}/kryten_webqueue/routes/admin_playlists.py +0 -0
  69. {kryten_webqueue-0.18.0 → kryten_webqueue-0.19.0}/kryten_webqueue/routes/admin_promos.py +0 -0
  70. {kryten_webqueue-0.18.0 → kryten_webqueue-0.19.0}/kryten_webqueue/routes/admin_queue.py +0 -0
  71. {kryten_webqueue-0.18.0 → kryten_webqueue-0.19.0}/kryten_webqueue/routes/admin_schedules.py +0 -0
  72. {kryten_webqueue-0.18.0 → kryten_webqueue-0.19.0}/kryten_webqueue/routes/auth.py +0 -0
  73. {kryten_webqueue-0.18.0 → kryten_webqueue-0.19.0}/kryten_webqueue/routes/catalog.py +0 -0
  74. {kryten_webqueue-0.18.0 → kryten_webqueue-0.19.0}/kryten_webqueue/routes/pages.py +0 -0
  75. {kryten_webqueue-0.18.0 → kryten_webqueue-0.19.0}/kryten_webqueue/routes/queue.py +0 -0
  76. {kryten_webqueue-0.18.0 → kryten_webqueue-0.19.0}/kryten_webqueue/routes/user.py +0 -0
  77. {kryten_webqueue-0.18.0 → kryten_webqueue-0.19.0}/kryten_webqueue/static/js/main.js +0 -0
  78. {kryten_webqueue-0.18.0 → kryten_webqueue-0.19.0}/kryten_webqueue/templates/admin/index.html +0 -0
  79. {kryten_webqueue-0.18.0 → kryten_webqueue-0.19.0}/kryten_webqueue/templates/admin/playlists.html +0 -0
  80. {kryten_webqueue-0.18.0 → kryten_webqueue-0.19.0}/kryten_webqueue/templates/admin/promos.html +0 -0
  81. {kryten_webqueue-0.18.0 → kryten_webqueue-0.19.0}/kryten_webqueue/templates/admin/queue_mgmt.html +0 -0
  82. {kryten_webqueue-0.18.0 → kryten_webqueue-0.19.0}/kryten_webqueue/templates/admin/schedules.html +0 -0
  83. {kryten_webqueue-0.18.0 → kryten_webqueue-0.19.0}/kryten_webqueue/templates/auth/login.html +0 -0
  84. {kryten_webqueue-0.18.0 → kryten_webqueue-0.19.0}/kryten_webqueue/templates/base.html +0 -0
  85. {kryten_webqueue-0.18.0 → kryten_webqueue-0.19.0}/kryten_webqueue/templates/catalog/browse.html +0 -0
  86. {kryten_webqueue-0.18.0 → kryten_webqueue-0.19.0}/kryten_webqueue/templates/catalog/item_detail.html +0 -0
  87. {kryten_webqueue-0.18.0 → kryten_webqueue-0.19.0}/kryten_webqueue/templates/catalog/item_not_found.html +0 -0
  88. {kryten_webqueue-0.18.0 → kryten_webqueue-0.19.0}/kryten_webqueue/templates/queue/index.html +0 -0
  89. {kryten_webqueue-0.18.0 → kryten_webqueue-0.19.0}/kryten_webqueue/ws/__init__.py +0 -0
  90. {kryten_webqueue-0.18.0 → kryten_webqueue-0.19.0}/kryten_webqueue/ws/handler.py +0 -0
  91. {kryten_webqueue-0.18.0 → kryten_webqueue-0.19.0}/kryten_webqueue/ws/manager.py +0 -0
  92. {kryten_webqueue-0.18.0 → kryten_webqueue-0.19.0}/tests/__init__.py +0 -0
  93. {kryten_webqueue-0.18.0 → kryten_webqueue-0.19.0}/tests/test_config_persistence.py +0 -0
  94. {kryten_webqueue-0.18.0 → kryten_webqueue-0.19.0}/tests/test_fetchurls_sharepoint.py +0 -0
  95. {kryten_webqueue-0.18.0 → kryten_webqueue-0.19.0}/tests/test_phase1.py +0 -0
  96. {kryten_webqueue-0.18.0 → kryten_webqueue-0.19.0}/tests/test_phase2_jobs.py +0 -0
  97. {kryten_webqueue-0.18.0 → kryten_webqueue-0.19.0}/tests/test_phase3_jobs.py +0 -0
  98. {kryten_webqueue-0.18.0 → kryten_webqueue-0.19.0}/tests/test_phase4_live_fixes.py +0 -0
  99. {kryten_webqueue-0.18.0 → kryten_webqueue-0.19.0}/tests/test_playlist_import.py +0 -0
  100. {kryten_webqueue-0.18.0 → kryten_webqueue-0.19.0}/tests/test_presence_refund.py +0 -0
  101. {kryten_webqueue-0.18.0 → kryten_webqueue-0.19.0}/tests/test_promo_director.py +0 -0
  102. {kryten_webqueue-0.18.0 → kryten_webqueue-0.19.0}/tests/test_promo_pool_exclusion.py +0 -0
  103. {kryten_webqueue-0.18.0 → kryten_webqueue-0.19.0}/tests/test_queue_announce.py +0 -0
  104. {kryten_webqueue-0.18.0 → kryten_webqueue-0.19.0}/tests/test_save_results_to_playlist.py +0 -0
  105. {kryten_webqueue-0.18.0 → kryten_webqueue-0.19.0}/tests/test_search_facets.py +0 -0
@@ -6,6 +6,14 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/),
6
6
  and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
7
7
  ## [Unreleased]
8
8
 
9
+ ## [0.19.0] — 2026-06-17
10
+
11
+ ### Changed
12
+
13
+ - **Z-Coin dashboard reorganized into tabs.** The account page was overcrowded with three side-by-side columns. It's now a widened account card (balance, rank, progress, perks) beside a tabbed container with **Queue History**, **Recent Transactions**, and a new **Vanity Items** tab. Each tab lazy-loads its data on first view; the vanity greeting/color editors moved out of the cramped left column into their own roomier tab. Collapses to a single column on narrow screens.
14
+
15
+ [0.19.0]: https://github.com/grobertson/kryten-webqueue/releases/tag/v0.19.0
16
+
9
17
  ## [0.18.0] — 2026-06-17
10
18
 
11
19
  ### Fixed
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: kryten-webqueue
3
- Version: 0.18.0
3
+ Version: 0.19.0
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
@@ -797,20 +797,50 @@ a.np-chip {
797
797
  }
798
798
  .dashboard-grid {
799
799
  display: grid;
800
- grid-template-columns: 1fr 1fr 1fr;
800
+ grid-template-columns: minmax(280px, 360px) 1fr;
801
801
  gap: 1.5rem;
802
802
  margin-top: 1.5rem;
803
+ align-items: start;
803
804
  }
804
805
  @media (max-width: 900px) {
805
806
  .dashboard-grid {
806
807
  grid-template-columns: 1fr;
807
808
  }
808
809
  }
809
- .balance-card, .history-card, .transactions-card {
810
+ .balance-card, .history-card, .transactions-card, .dashboard-tabs-card {
810
811
  background: var(--bg-card);
811
812
  border-radius: var(--radius);
812
813
  padding: 1.5rem;
813
814
  }
815
+
816
+ /* Dashboard tabbed container */
817
+ .tabs {
818
+ display: flex;
819
+ gap: 0.25rem;
820
+ border-bottom: 1px solid var(--border);
821
+ margin-bottom: 1rem;
822
+ }
823
+ .tab-btn {
824
+ background: transparent;
825
+ border: none;
826
+ border-bottom: 2px solid transparent;
827
+ color: var(--text-secondary);
828
+ cursor: pointer;
829
+ font-size: 0.95rem;
830
+ font-weight: 600;
831
+ padding: 0.6rem 0.9rem;
832
+ margin-bottom: -1px;
833
+ }
834
+ .tab-btn:hover {
835
+ color: var(--text-primary);
836
+ }
837
+ .tab-btn.active {
838
+ color: var(--accent);
839
+ border-bottom-color: var(--accent);
840
+ }
841
+ .tab-panel[hidden] {
842
+ display: none;
843
+ }
814
844
  .balance-amount {
815
845
  font-size: 2rem;
816
846
  font-weight: 700;
@@ -911,17 +941,7 @@ a.np-chip {
911
941
  color: var(--success);
912
942
  }
913
943
 
914
- /* Vanity items (dashboard left column) */
915
- .vanity-section {
916
- margin-top: 1.25rem;
917
- padding-top: 1.25rem;
918
- border-top: 1px solid var(--border);
919
- }
920
- .vanity-section h3 {
921
- font-size: 0.85rem;
922
- color: var(--text-secondary);
923
- margin-bottom: 0.6rem;
924
- }
944
+ /* Vanity items (dashboard "Vanity Items" tab) */
925
945
  .vanity-item {
926
946
  margin-bottom: 0.85rem;
927
947
  }
@@ -10,7 +10,7 @@
10
10
  </div>
11
11
 
12
12
  <div class="dashboard-grid">
13
- <!-- LEFT: Account -->
13
+ <!-- LEFT: Account (widened) -->
14
14
  <div class="balance-card">
15
15
  <h2>Z Coin Balance</h2>
16
16
  <p class="balance-amount" id="balance-amount">Loading…</p>
@@ -18,9 +18,37 @@
18
18
 
19
19
  <div class="account-rank" id="account-rank"></div>
20
20
  <div class="account-perks" id="account-perks"></div>
21
+ </div>
22
+
23
+ <!-- RIGHT: Tabbed container -->
24
+ <div class="dashboard-tabs-card">
25
+ <div class="tabs" role="tablist">
26
+ <button class="tab-btn active" data-tab="queue" role="tab" aria-selected="true">Queue History</button>
27
+ <button class="tab-btn" data-tab="transactions" role="tab" aria-selected="false">Recent Transactions</button>
28
+ <button class="tab-btn" data-tab="vanity" role="tab" aria-selected="false">Vanity Items</button>
29
+ </div>
30
+
31
+ <div class="tab-panel" id="tab-queue" role="tabpanel">
32
+ <div id="queue-history">
33
+ <p class="empty-state">Loading…</p>
34
+ </div>
35
+ <div class="history-pager" id="queue-pager"></div>
36
+ </div>
21
37
 
22
- <div class="vanity-section" id="vanity-section">
23
- <h3>Vanity</h3>
38
+ <div class="tab-panel" id="tab-transactions" role="tabpanel" hidden>
39
+ <div class="tx-toggle" id="tx-toggle">
40
+ <button class="tx-toggle-btn active" data-filter="all">All</button>
41
+ <button class="tx-toggle-btn" data-filter="credit">Credits</button>
42
+ <button class="tx-toggle-btn" data-filter="debit">Debits</button>
43
+ </div>
44
+ <div id="transactions">
45
+ <p class="empty-state">Loading…</p>
46
+ </div>
47
+ <div class="tx-pager" id="tx-pager"></div>
48
+ </div>
49
+
50
+ <div class="tab-panel" id="tab-vanity" role="tabpanel" hidden>
51
+ <p class="muted">Personalize how the bot greets you and your chat color. Each update is a one-time purchase.</p>
24
52
  <div class="vanity-item">
25
53
  <div class="vanity-row">
26
54
  <span class="vanity-label">Greeting</span>
@@ -37,29 +65,6 @@
37
65
  </div>
38
66
  </div>
39
67
  </div>
40
-
41
- <!-- MIDDLE: Queue history -->
42
- <div class="history-card">
43
- <h2>Queue History</h2>
44
- <div id="queue-history">
45
- <p class="empty-state">Loading…</p>
46
- </div>
47
- <div class="history-pager" id="queue-pager"></div>
48
- </div>
49
-
50
- <!-- RIGHT: Transactions -->
51
- <div class="transactions-card">
52
- <h2>Recent Transactions</h2>
53
- <div class="tx-toggle" id="tx-toggle">
54
- <button class="tx-toggle-btn active" data-filter="all">All</button>
55
- <button class="tx-toggle-btn" data-filter="credit">Credits</button>
56
- <button class="tx-toggle-btn" data-filter="debit">Debits</button>
57
- </div>
58
- <div id="transactions">
59
- <p class="empty-state">Loading…</p>
60
- </div>
61
- <div class="tx-pager" id="tx-pager"></div>
62
- </div>
63
68
  </div>
64
69
  </div>
65
70
  {% endblock %}
@@ -442,8 +447,31 @@ document.querySelectorAll('.tx-toggle-btn').forEach(b => b.addEventListener('cli
442
447
  renderTransactions();
443
448
  }));
444
449
 
450
+ // Tabs: show one panel at a time; lazy-load each panel's data on first view.
451
+ const tabLoaded = { queue: false, transactions: false, vanity: false };
452
+ function loadTabOnce(tab) {
453
+ if (tabLoaded[tab]) return;
454
+ tabLoaded[tab] = true;
455
+ if (tab === 'queue') loadQueue(0);
456
+ else if (tab === 'transactions') loadTransactions(true);
457
+ // 'vanity' needs no fetch — populated by loadAccount().
458
+ }
459
+ function showTab(tab) {
460
+ document.querySelectorAll('.tab-btn').forEach(b => {
461
+ const on = b.dataset.tab === tab;
462
+ b.classList.toggle('active', on);
463
+ b.setAttribute('aria-selected', on ? 'true' : 'false');
464
+ });
465
+ document.querySelectorAll('.tab-panel').forEach(p => {
466
+ p.hidden = p.id !== `tab-${tab}`;
467
+ });
468
+ loadTabOnce(tab);
469
+ }
470
+ document.querySelectorAll('.tab-btn').forEach(b => {
471
+ b.addEventListener('click', () => showTab(b.dataset.tab));
472
+ });
473
+
445
474
  loadAccount();
446
- loadQueue(0);
447
- loadTransactions(true);
475
+ showTab('queue'); // default tab; lazy-loads queue history
448
476
  </script>
449
477
  {% endblock %}
@@ -1,6 +1,6 @@
1
1
  [project]
2
2
  name = "kryten-webqueue"
3
- version = "0.18.0"
3
+ version = "0.19.0"
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"