## Dependency updates (exact pins) - **http-acl 0.13.1 → 0.14.0**: security hardening — IPv4-embedded IPv6 ranges (IPv4-compatible `::/96`, translated `::ffff:0:0:0/96`, NAT64 `64:ff9b::/96`, 6to4 `2002::/16`) are now denied by default; previously `::7f00:1` or `64:ff9b::7f00:1` could reach loopback through the SSRF guard. Also fixes the reqwest resolver dropping every getaddrinfo answer carrying port 0 - lru 0.19.0 (iterator Send/Sync bounds), ammonia 4.2.4, opendal 0.59.5, oxc 0.155.0, rustls 0.23.46, rusty_aac 1.1.1, rusty_h264 0.16.1, webpki-roots 1.0.10, zstd 0.14.3, tokio-util 0.7.20 and other transitives ## http-acl 0.14 adaptation (synctv-common SSRF guard) 0.14 refuses adding non-global ranges via `add_denied_ip_range` at build time. Our `DEFAULT_EXTRA_DENIED_RANGES` contained `2002::/16`, so `try_build` failed and the guard silently degraded to the **deny-all fallback** (every IP and hostname blocked). Fix: - `2002::/16` moved to `DEFAULT_NON_GLOBAL_DENIED_RANGES` (the SsrfPolicy-side list used by `is_ip_blocked`), together with the other embedded ranges: `::/96`, `::ffff:0:0:0/96`, `64:ff9b:1::/48` - new `test_ipv4_embedded_ipv6_blocked` covers all embedded probe forms (including the NAT64 metadata address) and a global IPv6 control ## tokio 1.53.2 → 1.54.0 1.54.0 starts accepted sockets as readable and writable, so the raw-TCP mocks in `error_handling_tests` could flush the response before the client had written its request; hyper rejects such a connection with `UnexpectedMessage` inside `reqwest::get`. The mocks now drain the request head before answering (normal HTTP ordering, matches a real server) and the suite passes on 1.54.0. ## Kept on purpose - bincode 2.0.1 (3.0.0 placeholder), dashmap 7.0.0-rc2, opaque-ke 4.1.0-pre.2, webauthn-rs 0.6.1-dev, serde_yaml, testcontainers 0.27 (modules 0.15 still requires ^0.27) ## Toolchain / CI - nightly-2026-10-13 → **nightly-2026-10-20** (rust-toolchain.toml + all workflows) - actions already float on latest major tags (checkout v7, cache v6, …) — no changes needed ## Validation - `make check`, `make check-all-targets`, `make clippy-check -D warnings`, `make fmt-check` clean - `cargo nextest run --workspace --run-ignored all`: **6970/6970 passed** (incl. docker-backed e2e) - `cargo deny check`: advisories/bans/licenses/sources all ok |
7 days ago | |
|---|---|---|
| .. | ||
| proto | 2 months ago | |
| src | 2 weeks ago | |
| tests | 7 days ago | |
| Cargo.toml | 2 weeks ago | |
| README.md | 3 months ago | |
| build.rs | 3 months ago | |
README.md
SyncTV Media Providers
synctv-media-providers contains the upstream protocol implementations used by
SyncTV. Each provider owns its HTTP/WebSocket protocol, request signing, DTOs,
pagination, authentication details, playback extraction, and protocol tests.
The complete integration guide is available in Chinese and English:
Modules
| Category | Modules | Upstream capabilities represented here |
|---|---|---|
| Video and live platforms | bilibili, youtube, twitch, douyin, tiktok, huya, douyu, acfun, cctv |
URL/ID parsing, metadata, native playback variants, platform feeds, subtitles, danmaku/chat, chapters, storyboard, and live protocols where available |
| Media servers and file services | emby, alist, cloudreve |
Authentication, browsing, search, metadata, thumbnails, subtitles, direct streams, transcode/remux, and playback reporting where available |
| NAS and private cloud | fnos, qnap, synology, nextcloud, seafile, truenas |
File browsing, search, preview/thumbnail, media libraries, native transcode, favorites, history, and playback reporting according to each server API |
Provider modules remain independent. A provider-specific source enum, cursor, signature, media-library model, or playback response stays inside that provider. Shared code is reserved for stable transport concerns such as HTTP safety, bounded response reads, retries, credentials, circuit breakers, and errors.
Architecture
Provider support crosses three API boundaries:
| Boundary | Location | Purpose |
|---|---|---|
| Upstream client | synctv-media-providers/src/<provider>/ |
Calls the provider's native HTTP, WebSocket, XML, or binary protocol |
| Internal remote-provider transport | synctv-media-providers/proto/, src/grpc/, src/remote_transport/ |
Runs selected provider clients in a separate SyncTV provider process |
| Public SyncTV API | synctv-proto/proto/providers/, synctv-proto/proto/playback_provider/, synctv-api/ |
Exposes typed parse, preview, list, binding, and playback operations to App and CLI clients |
The Core adapters live in synctv-core/src/provider/. They connect upstream
clients to credentials, persistent source configs and targets, dynamic playlists,
autoplay, PlaybackResult, and proxy resource resolution.
Current standalone remote gRPC services cover Alist, Bilibili, and Emby. Other providers run through their local clients and public SyncTV APIs. Extending the remote transport requires a provider-specific internal proto, server, client, registration, configuration, and local/remote parity tests.
Library Usage
Clients create or accept SyncTV's guarded HTTP configuration so redirects and resolved addresses remain inside the configured SSRF policy:
use synctv_media_providers::{
build_provider_http_client, BilibiliClient, CloudreveClient,
};
use synctv_common::ssrf::SsrfGuard;
let http = build_provider_http_client(SsrfGuard::strict_policy())?;
let bilibili = BilibiliClient::new()?;
let cloudreve = CloudreveClient::with_http_client(
"https://cloud.example.com",
http,
)?;
Consult each module's client.rs and tests for its constructors and typed
requests. Core and API code should consume typed provider methods rather than
constructing upstream URLs or decoding provider JSON themselves.
Standalone Provider Service
The provider server currently publishes Alist, Bilibili, and Emby internal gRPC
services. Every request carries x-provider-secret; each service also applies
message limits, compression policy, and an independent circuit breaker.
cargo +nightly build --release \
-p synctv-media-providers \
--bin media-provider-server
PROVIDER_AUTH_SECRET="$(openssl rand -hex 32)" \
PROVIDER_LISTEN_ADDR="0.0.0.0:50051" \
./target/release/media-provider-server
TLS features are tls-aws-lc, tls-ring, tls-webpki-roots, and
tls-native-roots. Select one crypto provider and the root source required by
the deployment.
Adding or Extending a Provider
- Define the provider's real product flows: login, parse, preview, browse, dynamic sources, playback variants, auxiliary media, and status reporting.
- Implement a dedicated module under
src/<provider>/with its own DTOs, pagination, signing, and protocol tests. - Add typed source configs and targets, then implement the Core provider and dynamic playlist behavior.
- Add public protobuf messages, HTTP/gRPC handlers, OpenAPI schemas, CLI paths, and every generated playback-resource resolver.
- Add internal remote transport when that provider needs separate deployment.
- Sync public protobuf into the Flutter App and implement codec, binding, parse/preview, selection, and creation UI.
- Test upstream contracts, Core behavior, public transports, CLI, database integration, and Flutter flows.
Typed parse, resolve, list, search, and preview results carry a media or playlist source config. Page, cursor, offset, and continuation models follow each provider's upstream contract and map to the explicit public pagination type.
Development
Use the repository nightly toolchain for builds and checks:
cargo +nightly fmt --all
cargo +nightly check -p synctv-media-providers --all-targets
cargo +nightly nextest run -p synctv-media-providers --run-ignored all --nff
Run the complete workspace suite from the repository root after changing Core, protobuf, API, management, CLI, or persistence behavior:
cargo +nightly check --workspace --all-targets
make nextest
Tests that call upstream services use deterministic protocol fixtures or
WireMock. Database and service integration scenarios use the workspace
Testcontainers setup and run through make nextest.