Skip to content

Commit 69da07f

Browse files
authored
merge: provider API
feat: provider platform with multiple accounts and a provider store
2 parents 79e1634 + afd3303 commit 69da07f

650 files changed

Lines changed: 66222 additions & 21251 deletions

File tree

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

‎.github/ISSUE_TEMPLATE/bug.yml‎

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
name: Bug report
2-
description: Report a reproducible Spool for Jellyfin defect
2+
description: Report a reproducible Spool defect
33
title: "[Bug]: "
44
labels: [bug]
55
body:

‎.github/workflows/build-artifacts.yml‎

Lines changed: 225 additions & 60 deletions
Large diffs are not rendered by default.

‎.github/workflows/release.yml‎

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -37,7 +37,7 @@ jobs:
3737
- name: Upload corresponding source
3838
uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.0
3939
with:
40-
name: spool-for-jellyfin-corresponding-source
40+
name: spool-corresponding-source
4141
path: release-source/*
4242
retention-days: 1
4343

@@ -137,6 +137,7 @@ jobs:
137137
}
138138
add_row 'macOS — Apple Silicon' '*-macOS-arm64.dmg'
139139
add_row 'macOS — Intel' '*-macOS-x86_64.dmg'
140+
add_row 'Apple TV — unsigned (re-sign required)' '*-tvOS-arm64.ipa'
140141
add_row 'Windows — installer' '*-Windows-x64-Setup.exe'
141142
add_row 'Windows — portable' '*-Windows-x64-Portable.exe'
142143
add_row 'Linux — AppImage' '*-x86_64.AppImage'
@@ -167,6 +168,11 @@ jobs:
167168
if [[ "$MACOS_SIGNED" != true ]]; then
168169
echo 'The macOS DMG is **not Developer ID signed or notarized**.'
169170
fi
171+
echo
172+
echo 'Release CI requires the complete Linux traditional and real OpenGL/Vulkan GUI suites, Windows OpenGL tests, and the Android phone journey. Full macOS, tvOS simulator, and Android TV native suites remain available manually but do not gate this release; their platform builds and package audits are retained.'
173+
echo
174+
echo 'The Apple TV IPA is **unsigned**: it has no Apple signing identity or provisioning profile, and tvOS will not install it as downloaded. It is not distributed through the App Store or TestFlight and has not been reviewed by Apple.'
175+
echo "Build and sign from source with your own Apple Account, or use your own tvOS re-signing setup. See [Apple TV build and signing directions](https://github.com/$REPO/tree/$TAG#apple-tv)."
170176
} >release-notes.md
171177
- name: Publish GitHub prerelease
172178
env:
@@ -280,7 +286,7 @@ jobs:
280286
fi
281287
gh release download "$TAG" --repo "$GITHUB_REPOSITORY" \
282288
--pattern SHA256SUMS.txt --dir "$RUNNER_TEMP"
283-
bundle="Spool-for-Jellyfin-$version-linux-x86_64.tar.zst"
289+
bundle="Spool-$version-linux-x86_64.tar.zst"
284290
checksum="$(awk -v want="$bundle" \
285291
'{ sub(/^\*/, "", $2); if ($2 == want) print $1 }' \
286292
"$RUNNER_TEMP/SHA256SUMS.txt")"

‎.github/workflows/rescan-release-sboms.yml‎

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -24,11 +24,11 @@ jobs:
2424
mkdir sboms
2525
tag="$(gh release list --exclude-drafts --limit 1 --json tagName --jq '.[0].tagName')"
2626
test -n "$tag"
27-
gh release download "$tag" --pattern '*.cdx.json' --dir sboms
28-
test -n "$(find sboms -type f -name '*.cdx.json' -print -quit)"
27+
gh release download "$tag" --pattern '*.syft.json' --pattern 'ffmpeg-vex.json' --dir sboms
28+
test -n "$(find sboms -type f -name '*.syft.json' -print -quit)"
2929
- name: Enforce vulnerability policy
3030
run: |
3131
set -euo pipefail
32-
for sbom in sboms/*.cdx.json; do
33-
"$RUNNER_TEMP/release-tools/grype" "sbom:$sbom" --fail-on high --only-fixed
32+
for sbom in sboms/*.syft.json; do
33+
"$RUNNER_TEMP/release-tools/grype" "sbom:$sbom" --vex sboms/ffmpeg-vex.json --fail-on high --only-fixed
3434
done

‎.github/workflows/tvos.yml‎

Lines changed: 69 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,69 @@
1+
name: tvOS source build
2+
3+
on:
4+
workflow_dispatch:
5+
push:
6+
branches: [feature/tvos]
7+
8+
permissions:
9+
contents: read
10+
11+
concurrency:
12+
group: tvos-${{ github.ref }}
13+
cancel-in-progress: true
14+
15+
jobs:
16+
simulator:
17+
name: Qt mpv tvOS ${{ matrix.sdk }} build (simulator tests; device artifact audit only)
18+
runs-on: macos-15
19+
timeout-minutes: 180
20+
strategy:
21+
fail-fast: false
22+
matrix:
23+
sdk: [appletvsimulator, appletvos]
24+
steps:
25+
- uses: actions/checkout@d23441a48e516b6c34aea4fa41551a30e30af803
26+
with:
27+
submodules: recursive
28+
persist-credentials: false
29+
- name: Install native build tools
30+
run: brew install cmake ninja meson pkg-config bash python imagemagick gpatch
31+
- name: Install pinned macOS Qt host tools
32+
run: |
33+
python3 -m venv "$RUNNER_TEMP/aqt"
34+
"$RUNNER_TEMP/aqt/bin/pip" install aqtinstall
35+
version="$(python3 -c 'import json;print(json.load(open("tools/manifests/toolchain.json"))["qt"]["version"])')"
36+
"$RUNNER_TEMP/aqt/bin/aqt" install-qt mac desktop "$version" clang_64 \
37+
-O "$RUNNER_TEMP/Qt" -m qtshadertools qtwebsockets qtimageformats qttasktree
38+
echo "QT_HOST_PATH=$RUNNER_TEMP/Qt/$version/macos" >> "$GITHUB_ENV"
39+
- name: Build Qt and media libraries for Apple TV
40+
env:
41+
APPLE_SDK: ${{ matrix.sdk }}
42+
APPLE_ARCH: arm64
43+
JOBS: 3
44+
BUILD_JOBS: 3
45+
run: bash tools/build-tvos.sh
46+
- uses: ./.github/actions/install-nix
47+
if: matrix.sdk == 'appletvsimulator'
48+
with:
49+
nix_conf: |
50+
experimental-features = nix-command flakes
51+
- uses: cachix/cachix-action@3ba601ff5bbb07c7220846facfa2cd81eeee15a1
52+
if: matrix.sdk == 'appletvsimulator'
53+
with:
54+
name: spool
55+
skipPush: true
56+
- name: Build same-binary host controller for the actual mobile app journey
57+
if: matrix.sdk == 'appletvsimulator'
58+
run: nix develop .#native -c env DEPLOY_APP=0 bash tools/build-macos.sh
59+
- name: Run traditional then real GPU GUI tests in isolated Apple TV simulator
60+
if: matrix.sdk == 'appletvsimulator'
61+
run: bash tools/apple/smoke-tvos.sh build/tvos/appletvsimulator-arm64/install/Spool.app
62+
- uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a
63+
if: always()
64+
with:
65+
name: internal-tvos-${{ matrix.sdk }}-arm64
66+
path: |
67+
build/tvos/${{ matrix.sdk }}-arm64/install
68+
build/tvos/smoke/*.png
69+
build/tvos/smoke/*.json

‎.gitignore‎

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
/build/
22
/build-linux-dev/
3+
/test-artifacts/
34
/build-arm/
45
/app/bin/
56
/app/lib/

‎.qmlls.ini‎

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
11
[General]
2-
; QML files live at qml/ and qml/*/, so include both relative depths.
3-
buildDir=../build/linux-dev/app:../../build/linux-dev/app
2+
; QML files live at qml/, qml/*/ and qml/providers/*/, so include every relative depth.
3+
buildDir=../build/linux-dev/app:../../build/linux-dev/app:../../../build/linux-dev/app
44
no-cmake-calls=true

‎AGENTS.md‎

Lines changed: 53 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22

33
## Project
44

5-
- Spool for Jellyfin client for webOS and desktop.
5+
- Spool: a media player for webOS, desktop and Android.
66
- Prefer a smaller, faster, easier-to-extend codebase over compatibility scaffolding or speculative abstractions.
77
- The app is prerelease software: bump/reset caches on schema changes instead of adding migrations or fallback readers.
88
- `mpv/` is a submodule. Commit mpv changes inside `mpv/`, then commit its pointer here.
@@ -29,18 +29,33 @@
2929

3030
## Module Seam
3131

32-
The goal is one core that several backends can sit on (spool-jellyfin,
33-
spool-plex, spool-stremio). `CMakeLists.txt` groups sources into
34-
`SPOOL_PLATFORM_SOURCES`, `SPOOL_PLAYER_SOURCES`, `SPOOL_SHELL_SOURCES` and
35-
`SPOOL_JELLYFIN_SOURCES` to mark where that cut goes. They still build as one
36-
library; the grouping exists so the split stays mechanical.
32+
The app knows no media backend. Every source is a provider package (JS logic
33+
and QML screens) run by `src/provider/`; `docs/providers.md` describes the
34+
pieces and `sdk/` is the current format-3 provider contract. Jellyfin, Emby, Plex and
35+
Stremio live in their `spool-player/spool-*` repositories; Open Movies lives in
36+
`spool-player/spool-provider-example`. All five are bundled from digest-pinned
37+
archives in `providers/lock.json`. Providers and host cut over together; do not add
38+
compatibility shims for older provider/host builds.
3739

38-
- Do not add a `src/api/` or `src/discovery/` include to the platform, player
39-
or shell groups. Four such dependencies already exist and are the work a
40-
split has to undo first: `PlayerController`, `PlaybackReporter`,
41-
`PlayQueueController` and `SettingsController` each take a
42-
`JellyfinApiFacade`, and `configurePlatformPlaybackCapabilities()` is
43-
handed one.
40+
- Core is everything under `src/` except `src/providers/` (native providers;
41+
only `LocalProvider` today) and `src/main.cpp`, the composition root. Core
42+
never includes `src/providers/`; `tools/check-module-seam.sh` is the
43+
`module-seam` ctest.
44+
- The app sees one `Provider`, `SourceHub`, which routes to every enabled
45+
account. IDs leaving it are scoped (`<8 hex>:<id>`) and stay opaque to
46+
routes, caches and QML. Pages reach media through `Catalog`,
47+
`SearchSource`, `UserItemStateSink`, `ArtworkSource`, `PlaybackSource` and
48+
`StreamQualityControl`, never a provider type.
49+
- Shared QML gates optional controls on the `ProviderCapabilities` singleton
50+
(search, userItemState, playbackReporting, segments, groupPlayback,
51+
remoteControl, streamQuality, trickplay): what the enabled accounts can do
52+
between them. Provider-specific UI is the provider's own QML, mounted by
53+
`shell/ProviderSurface` with a `ProviderUiContext`; item-menu entries come
54+
from the manifest's `actions`.
55+
- Group playback and remote control are generic (`GroupPlaybackController`,
56+
`AppControllerRemote.cpp`); providers translate their protocol into
57+
`group` and `remote` events. Do not touch `src/player` or
58+
`qml/pages/Player*` for provider work beyond renames.
4459
- `qml/primitives` and `qml/theme` reach exactly two singletons, `Art.url` and
4560
`Settings.uiScalePercent`. Keep it that way; page- and shell-level QML is
4661
where backend-shaped data belongs.
@@ -52,6 +67,12 @@ library; the grouping exists so the split stays mechanical.
5267
- `tools/manifests/toolchain.json` sets the Qt and FFmpeg versions for every
5368
platform. Nothing else may name one; `tools/toolchain-versions.sh --check`
5469
is what CI runs to keep the Qt module manifests honest.
70+
- Qt source manifests use the official-listed FAU archive mirror rather than a
71+
geo-selected redirect. Mirror changes must preserve version/module SHA-256 pins;
72+
verify the full archive digest before changing a source URL.
73+
- webOS GCC coroutine calls use named argument maps before `co_await`; nesting
74+
a member expression inside a temporary argument aggregate triggered a compiler
75+
internal error. Keep the wire arguments unchanged when restructuring such calls.
5576
- The launch screen carries the version, so it is rendered per build by
5677
`tools/generate-splash.sh` from `tools/manifests/splash.json` and is not
5778
committed. Configuring the app is enough to get it on every platform.
@@ -61,12 +82,30 @@ library; the grouping exists so the split stays mechanical.
6182
- Launch the native release app with `nix run`. Clean Git revisions substitute the immutable package from Cachix; dirty tracked changes use the incremental checkout build.
6283
- Launch the already-built native release app without rebuilding with `nix run .#run`. It fails with a build-command hint when the binary is missing.
6384
- Build without launching with `nix run .#build`.
64-
- Run the test suite the way CI does with `nix run .#tests` (release build, then the same ctest invocation and exclusions as the workflow).
85+
- Run the test suite the way CI does with `nix run .#tests` (release build, then `python tools/run-tests.py --build-dir <dir> --workers N`: traditional selectors finish before real GUI e2e; failures aggregate without GPU exclusions).
6586
- Leave interactive UI testing to the user. Do not drive their desktop with xdotool/xdgtool or similar input automation, or launch visible smoke tests unless explicitly requested. Use builds and isolated/offscreen checks for verification.
66-
- Use `nix develop .#native -c ...` for targeted development commands (e.g. `cmake --preset linux-dev`, then `cmake --build build/linux-dev/app --target jellyfin-native`).
87+
- Use `nix develop .#native -c ...` for targeted development commands (e.g. `cmake --preset linux-dev`, then `cmake --build build/linux-dev/app --target spool`).
6788
- The image-diagnostics equivalents remain `nix run .#image-debug-build` followed by `nix run .#image-debug`.
6889
- Batch coherent edits, then run one build and one `qmlformat`/`clang-format` invocation over all touched files; don't build or format file-by-file.
6990

91+
### Filtered preview diagnostics
92+
93+
- Trace is opt-in: `QT_LOGGING_RULES='spool.provider.trace.debug=true'`.
94+
Enable it only for the shortest necessary inspection, then unset it.
95+
- Never print or share unfiltered app logs, diagnostics JSON, provider responses,
96+
credential stores, URLs, request headers, or account configuration. Restoration
97+
must use the real app's existing credential path, never pasted tokens.
98+
- Always filter trace output before displaying it: select only `preview metadata`,
99+
`preview session`, `preview fetch failed`, and `preview load failed` messages
100+
from `spool.provider.trace`. Prefer an explicit field allowlist (item ID,
101+
enabled, availability, format, dimensions/count, numeric network/status codes,
102+
frame/speculative). Redact authentication, URL/query, user/account and path
103+
values even if upstream logging is already sanitized.
104+
- `spoolet` may inspect restored-account library rows and drive an explicitly
105+
requested offscreen preview smoke. Filter JSON to the required titles, IDs,
106+
player/preview state and dimensions. Never dump raw provider payloads or
107+
support reports to discover preview availability.
108+
70109
## webOS
71110

72111
- Do not build, install, launch, deploy, or test on a TV unless the user explicitly requests it. "Deploy" means install-only; never launch unless separately asked.

0 commit comments

Comments
 (0)