feat(web): add client-aware playback and reproducible UI (#433)
## Summary
- add a versioned playback client profile for browser/runtime protocol,
container, codec, header, proxy, insecure-media, and P2P-loader
capabilities
- generate compatible direct and proxy resources inside each provider
and return a structured incompatibility error when route policy leaves
no viable result
- force provider proxy delivery for browser-forbidden headers, including
affected Bilibili variants, while preserving explicit direct-only
failures
- keep legacy clients compatible and isolate capability-aware playback
cache entries
- serve `/oauth2/callback` through the same Flutter SPA entry point and
keep public discovery anonymous
## Reproducible Web UI
- move Flutter acquisition/build, source configuration, asset manifests,
Brotli/gzip compression, and compile-time embedding into the independent
`synctv-web-ui` crate
- support prebuilt distributions, local projects, and Git sources pinned
to an immutable full commit, with an ignored local override
- fingerprint source, Flutter version, build arguments, dart-defines,
builder generation, output, and compression settings
- validate cached Git repository/revision/commit identity, support
offline cache reuse, and rebuild only when relevant inputs change
- pin and checksum the Flutter SDK in the Docker Web asset stage;
backend-only builds require no Flutter, Git fetch, or network
- serve embedded assets with ETags, compression negotiation, CSP, cache
policy, Origin/CORS handling, and SPA fallback outside API/media routes
## Verification
- `cargo fmt --all -- --check`
- workspace `cargo check`, test/doc-test, and all-targets Clippy with
warnings denied
- provider tests: 200 passed, 1 ignored
- OAuth core/API tests: 72 + 16 passed
- `synctv-web-ui`: 10 passed
- `synctv-api-http --features web-ui`: 12 passed
- default Git source cold build from the pinned App commit, followed by
offline hot-cache reuse in about 1.1 seconds
- `cargo check -p synctv --features web-ui` and `docker buildx build
--check .`
- real Chrome playback, P2P, OAuth/Casdoor, multi-user sync, chat,
media, playlist, upload, settings, and playback-history flows
Companion frontend PR: https://github.com/synctv-org/synctv-app/pull/52
Release pin validation:
https://github.com/synctv-org/synctv-release/pull/9
1 month ago
|
|
|
# SyncTV Web UI assets
|
|
|
|
|
|
|
|
|
|
This crate owns acquisition, optional Flutter builds, compression, manifests,
|
|
|
|
|
and compile-time embedding of the SyncTV browser client. `synctv-api-http` can
|
|
|
|
|
also serve a distribution directly from disk during development.
|
feat(web): add client-aware playback and reproducible UI (#433)
## Summary
- add a versioned playback client profile for browser/runtime protocol,
container, codec, header, proxy, insecure-media, and P2P-loader
capabilities
- generate compatible direct and proxy resources inside each provider
and return a structured incompatibility error when route policy leaves
no viable result
- force provider proxy delivery for browser-forbidden headers, including
affected Bilibili variants, while preserving explicit direct-only
failures
- keep legacy clients compatible and isolate capability-aware playback
cache entries
- serve `/oauth2/callback` through the same Flutter SPA entry point and
keep public discovery anonymous
## Reproducible Web UI
- move Flutter acquisition/build, source configuration, asset manifests,
Brotli/gzip compression, and compile-time embedding into the independent
`synctv-web-ui` crate
- support prebuilt distributions, local projects, and Git sources pinned
to an immutable full commit, with an ignored local override
- fingerprint source, Flutter version, build arguments, dart-defines,
builder generation, output, and compression settings
- validate cached Git repository/revision/commit identity, support
offline cache reuse, and rebuild only when relevant inputs change
- pin and checksum the Flutter SDK in the Docker Web asset stage;
backend-only builds require no Flutter, Git fetch, or network
- serve embedded assets with ETags, compression negotiation, CSP, cache
policy, Origin/CORS handling, and SPA fallback outside API/media routes
## Verification
- `cargo fmt --all -- --check`
- workspace `cargo check`, test/doc-test, and all-targets Clippy with
warnings denied
- provider tests: 200 passed, 1 ignored
- OAuth core/API tests: 72 + 16 passed
- `synctv-web-ui`: 10 passed
- `synctv-api-http --features web-ui`: 12 passed
- default Git source cold build from the pinned App commit, followed by
offline hot-cache reuse in about 1.1 seconds
- `cargo check -p synctv --features web-ui` and `docker buildx build
--check .`
- real Chrome playback, P2P, OAuth/Casdoor, multi-user sync, chat,
media, playlist, upload, settings, and playback-history flows
Companion frontend PR: https://github.com/synctv-org/synctv-app/pull/52
Release pin validation:
https://github.com/synctv-org/synctv-release/pull/9
1 month ago
|
|
|
|
|
|
|
|
## Sources
|
|
|
|
|
|
|
|
|
|
`web-ui.toml` reads prebuilt files from `dist/`. The directory is empty in Git
|
|
|
|
|
apart from `.gitkeep`.
|
feat(web): add client-aware playback and reproducible UI (#433)
## Summary
- add a versioned playback client profile for browser/runtime protocol,
container, codec, header, proxy, insecure-media, and P2P-loader
capabilities
- generate compatible direct and proxy resources inside each provider
and return a structured incompatibility error when route policy leaves
no viable result
- force provider proxy delivery for browser-forbidden headers, including
affected Bilibili variants, while preserving explicit direct-only
failures
- keep legacy clients compatible and isolate capability-aware playback
cache entries
- serve `/oauth2/callback` through the same Flutter SPA entry point and
keep public discovery anonymous
## Reproducible Web UI
- move Flutter acquisition/build, source configuration, asset manifests,
Brotli/gzip compression, and compile-time embedding into the independent
`synctv-web-ui` crate
- support prebuilt distributions, local projects, and Git sources pinned
to an immutable full commit, with an ignored local override
- fingerprint source, Flutter version, build arguments, dart-defines,
builder generation, output, and compression settings
- validate cached Git repository/revision/commit identity, support
offline cache reuse, and rebuild only when relevant inputs change
- pin and checksum the Flutter SDK in the Docker Web asset stage;
backend-only builds require no Flutter, Git fetch, or network
- serve embedded assets with ETags, compression negotiation, CSP, cache
policy, Origin/CORS handling, and SPA fallback outside API/media routes
## Verification
- `cargo fmt --all -- --check`
- workspace `cargo check`, test/doc-test, and all-targets Clippy with
warnings denied
- provider tests: 200 passed, 1 ignored
- OAuth core/API tests: 72 + 16 passed
- `synctv-web-ui`: 10 passed
- `synctv-api-http --features web-ui`: 12 passed
- default Git source cold build from the pinned App commit, followed by
offline hot-cache reuse in about 1.1 seconds
- `cargo check -p synctv --features web-ui` and `docker buildx build
--check .`
- real Chrome playback, P2P, OAuth/Casdoor, multi-user sync, chat,
media, playlist, upload, settings, and playback-history flows
Companion frontend PR: https://github.com/synctv-org/synctv-app/pull/52
Release pin validation:
https://github.com/synctv-org/synctv-release/pull/9
1 month ago
|
|
|
|
|
|
|
|
`web-ui.production.toml` is the versioned production source used by CI. Its Git
|
|
|
|
|
source pins both the requested revision and its expected full lowercase commit
|
|
|
|
|
SHA. The build fails when the revision resolves to another commit.
|
|
|
|
|
|
|
|
|
|
For local development, create the ignored `web-ui.local.toml` beside the
|
|
|
|
|
default file. It takes precedence unless `SYNCTV_WEB_CONFIG` names another
|
|
|
|
|
configuration. Relative paths resolve from the selected configuration file.
|
|
|
|
|
|
|
|
|
|
Prebuilt distribution:
|
|
|
|
|
|
|
|
|
|
```toml
|
|
|
|
|
schema-version = 1
|
|
|
|
|
|
|
|
|
|
[source]
|
|
|
|
|
kind = "dist"
|
|
|
|
|
path = "../synctv-app/build/web"
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
Local Flutter project:
|
|
|
|
|
|
|
|
|
|
```toml
|
|
|
|
|
schema-version = 1
|
|
|
|
|
|
|
|
|
|
[source]
|
|
|
|
|
kind = "local-project"
|
|
|
|
|
path = "../../flutter/synctv-app"
|
|
|
|
|
allow-dirty = true
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
Immutable Git checkout:
|
|
|
|
|
|
|
|
|
|
```toml
|
|
|
|
|
schema-version = 1
|
|
|
|
|
|
|
|
|
|
[source]
|
|
|
|
|
kind = "git"
|
|
|
|
|
repository = "https://github.com/synctv-org/synctv-app.git"
|
|
|
|
|
revision = "refs/tags/v1.2.3"
|
|
|
|
|
commit = "0123456789abcdef0123456789abcdef01234567"
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
The optional `[build]` table accepts `flutter`, `arguments`, and a
|
|
|
|
|
`dart-defines` mapping. Arguments and defines participate in the build
|
|
|
|
|
fingerprint.
|
|
|
|
|
|
|
|
|
|
## Commands
|
|
|
|
|
|
|
|
|
|
Run the server against a mutable local distribution:
|
|
|
|
|
|
|
|
|
|
```bash
|
|
|
|
|
make dev-serve
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
`dev-serve` enables the `web-ui-dynamic` feature and sets
|
|
|
|
|
`SYNCTV_SERVER_WEB_UI_DIRECTORY` to `synctv-web-ui/dist`. Override the directory
|
|
|
|
|
with `DEV_WEB_UI_DIR=/path/to/dist`. Files are read for every request, use
|
|
|
|
|
`Cache-Control: no-store`, and can be replaced without rebuilding or restarting
|
|
|
|
|
the Rust server. A relative runtime directory is resolved from the server's
|
|
|
|
|
working directory.
|
|
|
|
|
|
feat(web): add client-aware playback and reproducible UI (#433)
## Summary
- add a versioned playback client profile for browser/runtime protocol,
container, codec, header, proxy, insecure-media, and P2P-loader
capabilities
- generate compatible direct and proxy resources inside each provider
and return a structured incompatibility error when route policy leaves
no viable result
- force provider proxy delivery for browser-forbidden headers, including
affected Bilibili variants, while preserving explicit direct-only
failures
- keep legacy clients compatible and isolate capability-aware playback
cache entries
- serve `/oauth2/callback` through the same Flutter SPA entry point and
keep public discovery anonymous
## Reproducible Web UI
- move Flutter acquisition/build, source configuration, asset manifests,
Brotli/gzip compression, and compile-time embedding into the independent
`synctv-web-ui` crate
- support prebuilt distributions, local projects, and Git sources pinned
to an immutable full commit, with an ignored local override
- fingerprint source, Flutter version, build arguments, dart-defines,
builder generation, output, and compression settings
- validate cached Git repository/revision/commit identity, support
offline cache reuse, and rebuild only when relevant inputs change
- pin and checksum the Flutter SDK in the Docker Web asset stage;
backend-only builds require no Flutter, Git fetch, or network
- serve embedded assets with ETags, compression negotiation, CSP, cache
policy, Origin/CORS handling, and SPA fallback outside API/media routes
## Verification
- `cargo fmt --all -- --check`
- workspace `cargo check`, test/doc-test, and all-targets Clippy with
warnings denied
- provider tests: 200 passed, 1 ignored
- OAuth core/API tests: 72 + 16 passed
- `synctv-web-ui`: 10 passed
- `synctv-api-http --features web-ui`: 12 passed
- default Git source cold build from the pinned App commit, followed by
offline hot-cache reuse in about 1.1 seconds
- `cargo check -p synctv --features web-ui` and `docker buildx build
--check .`
- real Chrome playback, P2P, OAuth/Casdoor, multi-user sync, chat,
media, playlist, upload, settings, and playback-history flows
Companion frontend PR: https://github.com/synctv-org/synctv-app/pull/52
Release pin validation:
https://github.com/synctv-org/synctv-release/pull/9
1 month ago
|
|
|
Build and export the Web distribution:
|
|
|
|
|
|
|
|
|
|
```bash
|
|
|
|
|
SYNCTV_WEB_CONFIG=synctv-web-ui/web-ui.production.toml \
|
|
|
|
|
make web-ui-build WEB_UI_EXPORT_DIR=synctv-web-ui/dist
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
Build the release server with the assets embedded:
|
|
|
|
|
|
|
|
|
|
```bash
|
|
|
|
|
make web-release-build
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
The existing `web-ui` feature embeds the distribution for release deployment.
|
|
|
|
|
Both features expose the same routes. When `server.web_ui_directory` is
|
|
|
|
|
configured, its disk contents are authoritative and take precedence over
|
|
|
|
|
embedded assets.
|
|
|
|
|
|
feat(web): add client-aware playback and reproducible UI (#433)
## Summary
- add a versioned playback client profile for browser/runtime protocol,
container, codec, header, proxy, insecure-media, and P2P-loader
capabilities
- generate compatible direct and proxy resources inside each provider
and return a structured incompatibility error when route policy leaves
no viable result
- force provider proxy delivery for browser-forbidden headers, including
affected Bilibili variants, while preserving explicit direct-only
failures
- keep legacy clients compatible and isolate capability-aware playback
cache entries
- serve `/oauth2/callback` through the same Flutter SPA entry point and
keep public discovery anonymous
## Reproducible Web UI
- move Flutter acquisition/build, source configuration, asset manifests,
Brotli/gzip compression, and compile-time embedding into the independent
`synctv-web-ui` crate
- support prebuilt distributions, local projects, and Git sources pinned
to an immutable full commit, with an ignored local override
- fingerprint source, Flutter version, build arguments, dart-defines,
builder generation, output, and compression settings
- validate cached Git repository/revision/commit identity, support
offline cache reuse, and rebuild only when relevant inputs change
- pin and checksum the Flutter SDK in the Docker Web asset stage;
backend-only builds require no Flutter, Git fetch, or network
- serve embedded assets with ETags, compression negotiation, CSP, cache
policy, Origin/CORS handling, and SPA fallback outside API/media routes
## Verification
- `cargo fmt --all -- --check`
- workspace `cargo check`, test/doc-test, and all-targets Clippy with
warnings denied
- provider tests: 200 passed, 1 ignored
- OAuth core/API tests: 72 + 16 passed
- `synctv-web-ui`: 10 passed
- `synctv-api-http --features web-ui`: 12 passed
- default Git source cold build from the pinned App commit, followed by
offline hot-cache reuse in about 1.1 seconds
- `cargo check -p synctv --features web-ui` and `docker buildx build
--check .`
- real Chrome playback, P2P, OAuth/Casdoor, multi-user sync, chat,
media, playlist, upload, settings, and playback-history flows
Companion frontend PR: https://github.com/synctv-org/synctv-app/pull/52
Release pin validation:
https://github.com/synctv-org/synctv-release/pull/9
1 month ago
|
|
|
The Web-only command exports to `target/web-ui-dist` by default. CI uploads the
|
|
|
|
|
exported distribution once, then passes its authenticated artifact URL and
|
|
|
|
|
SHA-256 digest to the existing multi-platform Docker build. Docker verifies and
|
|
|
|
|
embeds the archive; it never installs Flutter or builds the frontend.
|
|
|
|
|
|
|
|
|
|
## Build controls
|
|
|
|
|
|
|
|
|
|
| Variable | Behavior |
|
|
|
|
|
| --- | --- |
|
|
|
|
|
| `SYNCTV_WEB_CONFIG` | Select a configuration file explicitly. |
|
|
|
|
|
| `SYNCTV_WEB_DIST` | Use a prebuilt directory. This compatibility override takes precedence over configured sources. |
|
|
|
|
|
| `SYNCTV_WEB_CACHE_DIR` | Select the Git, Flutter output, and compression cache root. |
|
|
|
|
|
| `SYNCTV_WEB_EXPORT_DIR` | Copy the final uncompressed distribution to a disjoint directory. |
|
|
|
|
|
| `SYNCTV_WEB_OFFLINE` | Disable Git fetches and use `flutter pub get --offline`. Missing cache entries fail. |
|
|
|
|
|
| `SYNCTV_WEB_FORCE_REBUILD` | Fetch the pinned revision again and rebuild Flutter output. |
|
|
|
|
|
|
|
|
|
|
Relative paths in these controls resolve from the workspace root containing the
|
|
|
|
|
`synctv-web-ui` crate. Paths inside a selected configuration resolve from that
|
|
|
|
|
configuration file.
|
|
|
|
|
|
|
|
|
|
The fingerprint includes the source file hash or pinned commit, Flutter version,
|
|
|
|
|
build arguments, dart-defines, builder version, and final distribution hash.
|
|
|
|
|
Git checkout, Flutter output, and compression data use separate cache layers.
|
|
|
|
|
Ordinary workspace builds do not enable the `embed` feature and require no
|
|
|
|
|
Flutter installation, Git access, or network access.
|