kryten-webqueue 0.1.1__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 (58) hide show
  1. kryten_webqueue-0.1.1/.github/workflows/python-publish.yml +75 -0
  2. kryten_webqueue-0.1.1/.github/workflows/release.yml +125 -0
  3. kryten_webqueue-0.1.1/.gitignore +79 -0
  4. kryten_webqueue-0.1.1/PKG-INFO +127 -0
  5. kryten_webqueue-0.1.1/README.md +101 -0
  6. kryten_webqueue-0.1.1/config.example.json +27 -0
  7. kryten_webqueue-0.1.1/deploy/kryten-webqueue.service +23 -0
  8. kryten_webqueue-0.1.1/deploy/nginx-queue.conf +49 -0
  9. kryten_webqueue-0.1.1/docs/IMPLEMENTATION_SPEC.md +1847 -0
  10. kryten_webqueue-0.1.1/docs/IMPL_API_GATE.md +341 -0
  11. kryten_webqueue-0.1.1/docs/IMPL_ECONOMY.md +489 -0
  12. kryten_webqueue-0.1.1/docs/IMPL_KRYTEN_PY.md +335 -0
  13. kryten_webqueue-0.1.1/docs/IMPL_ROBOT.md +193 -0
  14. kryten_webqueue-0.1.1/docs/PRE_PLAN_GAPS.md +793 -0
  15. kryten_webqueue-0.1.1/docs/PRODUCT_PLAN.md +1110 -0
  16. kryten_webqueue-0.1.1/kryten_webqueue/__init__.py +0 -0
  17. kryten_webqueue-0.1.1/kryten_webqueue/__main__.py +10 -0
  18. kryten_webqueue-0.1.1/kryten_webqueue/api_gate/__init__.py +0 -0
  19. kryten_webqueue-0.1.1/kryten_webqueue/api_gate/client.py +113 -0
  20. kryten_webqueue-0.1.1/kryten_webqueue/app.py +184 -0
  21. kryten_webqueue-0.1.1/kryten_webqueue/auth/__init__.py +0 -0
  22. kryten_webqueue-0.1.1/kryten_webqueue/auth/otp.py +10 -0
  23. kryten_webqueue-0.1.1/kryten_webqueue/auth/rate_limit.py +29 -0
  24. kryten_webqueue-0.1.1/kryten_webqueue/auth/session.py +40 -0
  25. kryten_webqueue-0.1.1/kryten_webqueue/catalog/__init__.py +0 -0
  26. kryten_webqueue-0.1.1/kryten_webqueue/catalog/db.py +562 -0
  27. kryten_webqueue-0.1.1/kryten_webqueue/catalog/images.py +114 -0
  28. kryten_webqueue-0.1.1/kryten_webqueue/catalog/sync.py +96 -0
  29. kryten_webqueue-0.1.1/kryten_webqueue/config.py +46 -0
  30. kryten_webqueue-0.1.1/kryten_webqueue/playlists/__init__.py +0 -0
  31. kryten_webqueue-0.1.1/kryten_webqueue/playlists/fire.py +71 -0
  32. kryten_webqueue-0.1.1/kryten_webqueue/playlists/importer.py +92 -0
  33. kryten_webqueue-0.1.1/kryten_webqueue/playlists/scheduler.py +72 -0
  34. kryten_webqueue-0.1.1/kryten_webqueue/queue/__init__.py +0 -0
  35. kryten_webqueue-0.1.1/kryten_webqueue/queue/ordering.py +186 -0
  36. kryten_webqueue-0.1.1/kryten_webqueue/queue/poller.py +43 -0
  37. kryten_webqueue-0.1.1/kryten_webqueue/queue/shadow.py +116 -0
  38. kryten_webqueue-0.1.1/kryten_webqueue/routes/__init__.py +0 -0
  39. kryten_webqueue-0.1.1/kryten_webqueue/routes/admin_playlists.py +98 -0
  40. kryten_webqueue-0.1.1/kryten_webqueue/routes/admin_queue.py +64 -0
  41. kryten_webqueue-0.1.1/kryten_webqueue/routes/admin_schedules.py +129 -0
  42. kryten_webqueue-0.1.1/kryten_webqueue/routes/auth.py +83 -0
  43. kryten_webqueue-0.1.1/kryten_webqueue/routes/catalog.py +44 -0
  44. kryten_webqueue-0.1.1/kryten_webqueue/routes/pages.py +82 -0
  45. kryten_webqueue-0.1.1/kryten_webqueue/routes/queue.py +144 -0
  46. kryten_webqueue-0.1.1/kryten_webqueue/routes/user.py +35 -0
  47. kryten_webqueue-0.1.1/kryten_webqueue/static/css/main.css +470 -0
  48. kryten_webqueue-0.1.1/kryten_webqueue/static/js/main.js +26 -0
  49. kryten_webqueue-0.1.1/kryten_webqueue/templates/admin/index.html +98 -0
  50. kryten_webqueue-0.1.1/kryten_webqueue/templates/auth/login.html +69 -0
  51. kryten_webqueue-0.1.1/kryten_webqueue/templates/base.html +41 -0
  52. kryten_webqueue-0.1.1/kryten_webqueue/templates/catalog/browse.html +105 -0
  53. kryten_webqueue-0.1.1/kryten_webqueue/templates/queue/index.html +126 -0
  54. kryten_webqueue-0.1.1/kryten_webqueue/templates/user/dashboard.html +87 -0
  55. kryten_webqueue-0.1.1/kryten_webqueue/ws/__init__.py +0 -0
  56. kryten_webqueue-0.1.1/kryten_webqueue/ws/handler.py +59 -0
  57. kryten_webqueue-0.1.1/kryten_webqueue/ws/manager.py +57 -0
  58. kryten_webqueue-0.1.1/pyproject.toml +45 -0
@@ -0,0 +1,75 @@
1
+ name: Publish Python Package to PyPI
2
+
3
+ on:
4
+ workflow_call:
5
+ release:
6
+ types: [published]
7
+ push:
8
+ tags:
9
+ - 'kryten-webqueue-v*'
10
+ - 'v*'
11
+
12
+ permissions:
13
+ contents: read
14
+ id-token: write
15
+
16
+ jobs:
17
+ release-build:
18
+ name: Build distribution packages
19
+ runs-on: ubuntu-latest
20
+
21
+ steps:
22
+ - name: Checkout repository
23
+ uses: actions/checkout@v4
24
+
25
+ - name: Install uv
26
+ uses: astral-sh/setup-uv@v4
27
+ with:
28
+ version: "latest"
29
+
30
+ - name: Set up Python
31
+ uses: actions/setup-python@v5
32
+ with:
33
+ python-version: "3.12"
34
+
35
+ - name: Build release distributions
36
+ run: |
37
+ uv build
38
+ echo "📦 Built packages:"
39
+ ls -lh dist/
40
+
41
+ - name: Upload distributions
42
+ uses: actions/upload-artifact@v4
43
+ with:
44
+ name: release-dists
45
+ path: dist/
46
+
47
+ pypi-publish:
48
+ name: Publish to PyPI
49
+ runs-on: ubuntu-latest
50
+ needs:
51
+ - release-build
52
+ environment:
53
+ name: pypi
54
+ permissions:
55
+ id-token: write
56
+
57
+ steps:
58
+ - name: Retrieve release distributions
59
+ uses: actions/download-artifact@v4
60
+ with:
61
+ name: release-dists
62
+ path: dist/
63
+
64
+ - name: Publish release distributions to PyPI
65
+ uses: pypa/gh-action-pypi-publish@release/v1
66
+ with:
67
+ packages-dir: dist/
68
+ skip-existing: true
69
+ attestations: false
70
+
71
+ - name: Success notification
72
+ if: success()
73
+ run: |
74
+ echo "✅ Successfully published to PyPI!"
75
+ echo "🔗 Package URL: https://pypi.org/project/kryten-webqueue/"
@@ -0,0 +1,125 @@
1
+ name: Release Automation
2
+
3
+ # Automatically create GitHub releases when version in pyproject.toml changes
4
+ on:
5
+ push:
6
+ branches:
7
+ - main
8
+ paths:
9
+ - 'pyproject.toml'
10
+ workflow_dispatch:
11
+
12
+ permissions:
13
+ contents: write
14
+ pull-requests: read
15
+ id-token: write
16
+
17
+ jobs:
18
+ create-release:
19
+ name: Create Release
20
+ runs-on: ubuntu-latest
21
+
22
+ steps:
23
+ - uses: actions/checkout@v4
24
+ with:
25
+ fetch-depth: 0 # Full history for changelog
26
+
27
+ - name: Read version from pyproject.toml
28
+ id: version
29
+ run: |
30
+ VERSION=$(grep -m1 'version = "' pyproject.toml | cut -d '"' -f 2)
31
+ echo "version=$VERSION" >> $GITHUB_OUTPUT
32
+ echo "tag=v$VERSION" >> $GITHUB_OUTPUT
33
+ echo "📦 Version: $VERSION"
34
+
35
+ - name: Check if tag exists
36
+ id: check_tag
37
+ run: |
38
+ git fetch --tags
39
+ if git rev-parse "${{ steps.version.outputs.tag }}" >/dev/null 2>&1; then
40
+ echo "exists=true" >> $GITHUB_OUTPUT
41
+ echo "ℹ️ Tag ${{ steps.version.outputs.tag }} already exists"
42
+ else
43
+ echo "exists=false" >> $GITHUB_OUTPUT
44
+ echo "✨ Tag ${{ steps.version.outputs.tag }} will be created"
45
+ fi
46
+
47
+ - name: Generate changelog
48
+ id: changelog
49
+ if: steps.check_tag.outputs.exists == 'false'
50
+ run: |
51
+ echo "Generating changelog..."
52
+
53
+ # Get previous tag
54
+ PREV_TAG=$(git describe --tags --abbrev=0 HEAD^ 2>/dev/null || echo "")
55
+
56
+ if [ -z "$PREV_TAG" ]; then
57
+ echo "📝 First release - generating full changelog"
58
+ COMMITS=$(git log --pretty=format:"- %s (%h)" --no-merges)
59
+ else
60
+ echo "📝 Generating changelog since $PREV_TAG"
61
+ COMMITS=$(git log ${PREV_TAG}..HEAD --pretty=format:"- %s (%h)" --no-merges)
62
+ fi
63
+
64
+ # Save changelog to file
65
+ cat > changelog.md << EOF
66
+ ## What's Changed
67
+
68
+ ${COMMITS}
69
+
70
+ **Full Changelog**: https://github.com/${{ github.repository }}/compare/${PREV_TAG}...${{ steps.version.outputs.tag }}
71
+ EOF
72
+
73
+ cat changelog.md
74
+
75
+ - name: Create Git tag
76
+ if: steps.check_tag.outputs.exists == 'false'
77
+ run: |
78
+ git config user.name "github-actions[bot]"
79
+ git config user.email "github-actions[bot]@users.noreply.github.com"
80
+ git tag -a "${{ steps.version.outputs.tag }}" -m "Release ${{ steps.version.outputs.tag }}"
81
+ git push origin "${{ steps.version.outputs.tag }}"
82
+
83
+ - name: Create GitHub Release
84
+ if: steps.check_tag.outputs.exists == 'false'
85
+ env:
86
+ GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
87
+ run: |
88
+ gh release create "${{ steps.version.outputs.tag }}" \
89
+ --title "Release ${{ steps.version.outputs.tag }}" \
90
+ --notes-file changelog.md
91
+
92
+ - name: Skip release creation
93
+ if: steps.check_tag.outputs.exists == 'true'
94
+ run: |
95
+ echo "ℹ️ Release ${{ steps.version.outputs.tag }} already exists - skipping"
96
+
97
+ publish-to-pypi:
98
+ name: Publish to PyPI
99
+ needs: [create-release]
100
+ uses: ./.github/workflows/python-publish.yml
101
+ permissions:
102
+ id-token: write
103
+ contents: read
104
+
105
+ notify-release:
106
+ name: Notify Release Created
107
+ runs-on: ubuntu-latest
108
+ needs: [create-release, publish-to-pypi]
109
+
110
+ steps:
111
+ - uses: actions/checkout@v4
112
+
113
+ - name: Read version from pyproject.toml
114
+ id: version
115
+ run: |
116
+ VERSION=$(grep -m1 'version = "' pyproject.toml | cut -d '"' -f 2)
117
+ echo "version=$VERSION" >> $GITHUB_OUTPUT
118
+ echo "tag=v$VERSION" >> $GITHUB_OUTPUT
119
+
120
+ - name: Send notification
121
+ run: |
122
+ echo "📢 Release notification"
123
+ echo "Version: ${{ steps.version.outputs.tag }}"
124
+ echo "Repository: ${{ github.repository }}"
125
+ echo "Release URL: https://github.com/${{ github.repository }}/releases/tag/${{ steps.version.outputs.tag }}"
@@ -0,0 +1,79 @@
1
+ # Python
2
+ __pycache__/
3
+ *.py[cod]
4
+ *$py.class
5
+ *.so
6
+ .Python
7
+ build/
8
+ develop-eggs/
9
+ dist/
10
+ downloads/
11
+ eggs/
12
+ .eggs/
13
+ lib/
14
+ lib64/
15
+ parts/
16
+ sdist/
17
+ var/
18
+ wheels/
19
+ pip-wheel-metadata/
20
+ share/python-wheels/
21
+ *.egg-info/
22
+ .installed.cfg
23
+ *.egg
24
+ MANIFEST
25
+
26
+ # Virtual environments
27
+ .venv/
28
+ venv/
29
+ ENV/
30
+ env/
31
+
32
+ # PyCharm
33
+ .idea/
34
+
35
+ # VSCode
36
+ .vscode/
37
+
38
+ # pytest
39
+ .pytest_cache/
40
+ htmlcov/
41
+ .coverage
42
+ .coverage.*
43
+ coverage.xml
44
+ *.cover
45
+ .hypothesis/
46
+
47
+ # mypy
48
+ .mypy_cache/
49
+ .dmypy.json
50
+ dmypy.json
51
+
52
+ # Logs
53
+ *.log
54
+ logs/
55
+
56
+ # Configuration files (keep examples only)
57
+ config.json
58
+ config-*.json
59
+ !config.example.json
60
+
61
+ # Database files
62
+ *.db
63
+ *.db-wal
64
+ *.db-shm
65
+
66
+ # OS
67
+ .DS_Store
68
+ Thumbs.db
69
+
70
+ # Backup files
71
+ *~
72
+ *.bak
73
+ *.swp
74
+
75
+ # Test output
76
+ test-output/
77
+
78
+ # uv
79
+ uv.lock
@@ -0,0 +1,127 @@
1
+ Metadata-Version: 2.4
2
+ Name: kryten-webqueue
3
+ Version: 0.1.1
4
+ Summary: Netflix/Tubi-style catalog browser and pay-to-play queue management for CyTube
5
+ Author: grobertson
6
+ License-Expression: MIT
7
+ Requires-Python: >=3.12
8
+ Requires-Dist: aiosqlite>=0.20
9
+ Requires-Dist: apscheduler>=3.10
10
+ Requires-Dist: fastapi>=0.115
11
+ Requires-Dist: httpx>=0.27
12
+ Requires-Dist: jinja2>=3.1
13
+ Requires-Dist: pillow>=10.0
14
+ Requires-Dist: pydantic>=2.0
15
+ Requires-Dist: pyjwt>=2.8
16
+ Requires-Dist: uvicorn[standard]>=0.30
17
+ Requires-Dist: websockets>=12.0
18
+ Provides-Extra: dev
19
+ Requires-Dist: black>=24.0; extra == 'dev'
20
+ Requires-Dist: httpx; extra == 'dev'
21
+ Requires-Dist: mypy>=1.10; extra == 'dev'
22
+ Requires-Dist: pytest-asyncio>=0.23; extra == 'dev'
23
+ Requires-Dist: pytest>=8.0; extra == 'dev'
24
+ Requires-Dist: ruff>=0.4; extra == 'dev'
25
+ Description-Content-Type: text/markdown
26
+
27
+ # kryten-webqueue
28
+
29
+ Netflix/Tubi-style catalog browser and pay-to-play queue management for CyTube.
30
+
31
+ ## Architecture
32
+
33
+ ```
34
+ Browser → nginx (queue.dropsugar.co) → kryten-webqueue (:2010) → kryten-api-gate (:24444) → NATS services
35
+ ```
36
+
37
+ - **HTTP-only** — webqueue never touches NATS directly
38
+ - **SQLite** for all local state (catalog, OTPs, queue shadow, playlists, schedules)
39
+ - **WebSocket** for real-time queue updates
40
+ - **Polling** api-gate every 3 seconds for playlist state
41
+
42
+ ## Quick Start
43
+
44
+ ```bash
45
+ # Install
46
+ python -m venv .venv
47
+ .venv/bin/pip install -e .
48
+
49
+ # Configure
50
+ cp config.example.json /etc/kryten-webqueue/config.json
51
+ # Edit config.json with your secrets
52
+
53
+ # Run
54
+ WQ_CONFIG=/etc/kryten-webqueue/config.json python -m kryten_webqueue
55
+ ```
56
+
57
+ ## Configuration
58
+
59
+ See `config.example.json` for all options. Required secrets:
60
+
61
+ | Key | Description |
62
+ |-----|-------------|
63
+ | `secret_key` | Random string for JWT signing (≥32 chars) |
64
+ | `api_gate_token` | Bearer token for kryten-api-gate |
65
+ | `mediacms_token` | API token for MediaCMS catalog sync |
66
+
67
+ ## Deployment
68
+
69
+ ```bash
70
+ # Install service
71
+ sudo cp deploy/kryten-webqueue.service /etc/systemd/system/
72
+ sudo systemctl daemon-reload
73
+ sudo systemctl enable --now kryten-webqueue
74
+
75
+ # nginx
76
+ sudo cp deploy/nginx-queue.conf /etc/nginx/sites-available/queue.dropsugar.co
77
+ sudo ln -s /etc/nginx/sites-available/queue.dropsugar.co /etc/nginx/sites-enabled/
78
+ sudo nginx -t && sudo systemctl reload nginx
79
+ ```
80
+
81
+ ## API Endpoints
82
+
83
+ ### Auth
84
+ - `POST /auth/otp/request` — Request OTP (delivered via PM)
85
+ - `POST /auth/otp/verify` — Verify OTP, get session cookie
86
+ - `POST /auth/logout` — Clear session
87
+ - `GET /auth/me` — Current user info
88
+
89
+ ### Catalog
90
+ - `GET /catalog/browse` — Paginated browse (with category filter)
91
+ - `GET /catalog/search?q=...` — Full-text search
92
+ - `GET /catalog/item/{token}` — Item detail
93
+ - `GET /catalog/categories` — List categories
94
+
95
+ ### Queue
96
+ - `GET /queue/state` — Current queue state
97
+ - `POST /queue/add` — Add item (FIFO pay-queue)
98
+ - `POST /queue/playnext` — Add as play-next (premium)
99
+ - `GET /queue/preview?friendly_token=...&tier=...` — Cost preview
100
+ - `GET /queue/history` — User's queue history
101
+
102
+ ### User
103
+ - `GET /user/balance` — Economy balance
104
+ - `GET /user/transactions` — Transaction history
105
+ - `GET /user/profile` — Profile info
106
+
107
+ ### Admin (rank ≥ 3)
108
+ - `GET/POST/PUT/DELETE /admin/playlists/...` — Saved playlists CRUD
109
+ - `GET/POST/PUT/DELETE /admin/schedules/...` — Schedule CRUD
110
+ - `POST /admin/schedules/{id}/fire` — Manual fire
111
+ - `POST /admin/queue/clear` — Clear queue (refunds pay items)
112
+ - `DELETE /admin/queue/{uid}` — Remove item
113
+ - `POST /admin/queue/sync-now` — Trigger catalog sync
114
+
115
+ ### WebSocket
116
+ - `ws://host/ws` — Real-time queue updates (auth via session cookie)
117
+
118
+ ## Dependencies
119
+
120
+ - Python ≥ 3.12
121
+ - kryten-api-gate ≥ 0.3.6
122
+ - kryten-py ≥ 0.16.1 (upstream, not a direct dependency)
123
+ - kryten-economy ≥ 0.8.11 (upstream, not a direct dependency)
124
+
125
+ ## License
126
+
127
+ Proprietary — DropSugar / Q&A
@@ -0,0 +1,101 @@
1
+ # kryten-webqueue
2
+
3
+ Netflix/Tubi-style catalog browser and pay-to-play queue management for CyTube.
4
+
5
+ ## Architecture
6
+
7
+ ```
8
+ Browser → nginx (queue.dropsugar.co) → kryten-webqueue (:2010) → kryten-api-gate (:24444) → NATS services
9
+ ```
10
+
11
+ - **HTTP-only** — webqueue never touches NATS directly
12
+ - **SQLite** for all local state (catalog, OTPs, queue shadow, playlists, schedules)
13
+ - **WebSocket** for real-time queue updates
14
+ - **Polling** api-gate every 3 seconds for playlist state
15
+
16
+ ## Quick Start
17
+
18
+ ```bash
19
+ # Install
20
+ python -m venv .venv
21
+ .venv/bin/pip install -e .
22
+
23
+ # Configure
24
+ cp config.example.json /etc/kryten-webqueue/config.json
25
+ # Edit config.json with your secrets
26
+
27
+ # Run
28
+ WQ_CONFIG=/etc/kryten-webqueue/config.json python -m kryten_webqueue
29
+ ```
30
+
31
+ ## Configuration
32
+
33
+ See `config.example.json` for all options. Required secrets:
34
+
35
+ | Key | Description |
36
+ |-----|-------------|
37
+ | `secret_key` | Random string for JWT signing (≥32 chars) |
38
+ | `api_gate_token` | Bearer token for kryten-api-gate |
39
+ | `mediacms_token` | API token for MediaCMS catalog sync |
40
+
41
+ ## Deployment
42
+
43
+ ```bash
44
+ # Install service
45
+ sudo cp deploy/kryten-webqueue.service /etc/systemd/system/
46
+ sudo systemctl daemon-reload
47
+ sudo systemctl enable --now kryten-webqueue
48
+
49
+ # nginx
50
+ sudo cp deploy/nginx-queue.conf /etc/nginx/sites-available/queue.dropsugar.co
51
+ sudo ln -s /etc/nginx/sites-available/queue.dropsugar.co /etc/nginx/sites-enabled/
52
+ sudo nginx -t && sudo systemctl reload nginx
53
+ ```
54
+
55
+ ## API Endpoints
56
+
57
+ ### Auth
58
+ - `POST /auth/otp/request` — Request OTP (delivered via PM)
59
+ - `POST /auth/otp/verify` — Verify OTP, get session cookie
60
+ - `POST /auth/logout` — Clear session
61
+ - `GET /auth/me` — Current user info
62
+
63
+ ### Catalog
64
+ - `GET /catalog/browse` — Paginated browse (with category filter)
65
+ - `GET /catalog/search?q=...` — Full-text search
66
+ - `GET /catalog/item/{token}` — Item detail
67
+ - `GET /catalog/categories` — List categories
68
+
69
+ ### Queue
70
+ - `GET /queue/state` — Current queue state
71
+ - `POST /queue/add` — Add item (FIFO pay-queue)
72
+ - `POST /queue/playnext` — Add as play-next (premium)
73
+ - `GET /queue/preview?friendly_token=...&tier=...` — Cost preview
74
+ - `GET /queue/history` — User's queue history
75
+
76
+ ### User
77
+ - `GET /user/balance` — Economy balance
78
+ - `GET /user/transactions` — Transaction history
79
+ - `GET /user/profile` — Profile info
80
+
81
+ ### Admin (rank ≥ 3)
82
+ - `GET/POST/PUT/DELETE /admin/playlists/...` — Saved playlists CRUD
83
+ - `GET/POST/PUT/DELETE /admin/schedules/...` — Schedule CRUD
84
+ - `POST /admin/schedules/{id}/fire` — Manual fire
85
+ - `POST /admin/queue/clear` — Clear queue (refunds pay items)
86
+ - `DELETE /admin/queue/{uid}` — Remove item
87
+ - `POST /admin/queue/sync-now` — Trigger catalog sync
88
+
89
+ ### WebSocket
90
+ - `ws://host/ws` — Real-time queue updates (auth via session cookie)
91
+
92
+ ## Dependencies
93
+
94
+ - Python ≥ 3.12
95
+ - kryten-api-gate ≥ 0.3.6
96
+ - kryten-py ≥ 0.16.1 (upstream, not a direct dependency)
97
+ - kryten-economy ≥ 0.8.11 (upstream, not a direct dependency)
98
+
99
+ ## License
100
+
101
+ Proprietary — DropSugar / Q&A
@@ -0,0 +1,27 @@
1
+ {
2
+ "channel": "Q_A",
3
+ "host": "0.0.0.0",
4
+ "port": 2010,
5
+ "secret_key": "CHANGE_ME_long_random_string",
6
+ "session_ttl_hours": 24,
7
+
8
+ "api_gate_url": "http://127.0.0.1:24444",
9
+ "api_gate_token": "CHANGE_ME",
10
+
11
+ "mediacms_url": "https://www.dropsugar.com",
12
+ "mediacms_token": "CHANGE_ME",
13
+
14
+ "tmdb_api_key": "",
15
+ "omdb_api_key": "",
16
+
17
+ "db_path": "/var/lib/kryten-webqueue/webqueue.db",
18
+
19
+ "image_dir": "/var/lib/kryten-webqueue/images",
20
+ "placeholder_dir": "/var/lib/kryten-webqueue/images/placeholders",
21
+
22
+ "catalog_sync_interval_hours": 4,
23
+ "pre_fire_lock_minutes_default": 15,
24
+ "state_poll_interval_sec": 3.0,
25
+
26
+ "prometheus_port": 28292
27
+ }
@@ -0,0 +1,23 @@
1
+ [Unit]
2
+ Description=kryten-webqueue - CyTube Queue Management
3
+ After=network.target
4
+
5
+ [Service]
6
+ Type=simple
7
+ User=kryten
8
+ Group=kryten
9
+ WorkingDirectory=/opt/kryten-webqueue
10
+ Environment=WQ_CONFIG=/etc/kryten-webqueue/config.json
11
+ ExecStart=/opt/kryten-webqueue/.venv/bin/python -m kryten_webqueue
12
+ Restart=always
13
+ RestartSec=5
14
+
15
+ # Hardening
16
+ NoNewPrivileges=true
17
+ ProtectSystem=strict
18
+ ProtectHome=true
19
+ ReadWritePaths=/var/lib/kryten-webqueue
20
+ PrivateTmp=true
21
+
22
+ [Install]
23
+ WantedBy=multi-user.target
@@ -0,0 +1,49 @@
1
+ server {
2
+ listen 443 ssl http2;
3
+ server_name queue.dropsugar.co;
4
+
5
+ ssl_certificate /etc/letsencrypt/live/queue.dropsugar.co/fullchain.pem;
6
+ ssl_certificate_key /etc/letsencrypt/live/queue.dropsugar.co/privkey.pem;
7
+
8
+ # WebSocket upgrade
9
+ location /ws {
10
+ proxy_pass http://127.0.0.1:2010;
11
+ proxy_http_version 1.1;
12
+ proxy_set_header Upgrade $http_upgrade;
13
+ proxy_set_header Connection "upgrade";
14
+ proxy_set_header Host $host;
15
+ proxy_set_header X-Real-IP $remote_addr;
16
+ proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
17
+ proxy_set_header X-Forwarded-Proto $scheme;
18
+ proxy_read_timeout 86400;
19
+ }
20
+
21
+ # API + pages
22
+ location / {
23
+ proxy_pass http://127.0.0.1:2010;
24
+ proxy_set_header Host $host;
25
+ proxy_set_header X-Real-IP $remote_addr;
26
+ proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
27
+ proxy_set_header X-Forwarded-Proto $scheme;
28
+ }
29
+
30
+ # Static assets - serve directly for performance
31
+ location /static/ {
32
+ alias /opt/kryten-webqueue/kryten_webqueue/static/;
33
+ expires 7d;
34
+ add_header Cache-Control "public, immutable";
35
+ }
36
+
37
+ # Cover art images
38
+ location /images/ {
39
+ alias /var/lib/kryten-webqueue/images/;
40
+ expires 30d;
41
+ add_header Cache-Control "public, immutable";
42
+ }
43
+ }
44
+
45
+ server {
46
+ listen 80;
47
+ server_name queue.dropsugar.co;
48
+ return 301 https://$server_name$request_uri;
49
+ }