Files
JRay-public-server/src/api/mod.rs
T
dtourolleandClaude Opus 5 0ff1018bcc
CI / static musl binary (push) Has been skipped
CI / fmt, clippy, test (push) Failing after 2m0s
CI / advisories and licences (push) Successful in 27s
Withdraw the file-hash tier; document the legal posture
Removes `cut.video_hash` and the `exact` match tier on legal grounds. The
OpenSubtitles hash was the strongest technical signal available — it identifies
a specific file, so it cannot produce a false positive — and that is exactly
the problem.

Every tier must be a claim about a *cut*, never about a copy. A TMDB id
discloses "some copy of this film", which is what a library catalogue
discloses. A file hash discloses "this exact release": it made a read endpoint
into a release-level oracle, and made an instance's database a mapping from
file fingerprints to the instances holding them. That is a far more specific
disclosure than PR-005 permits, and a dataset no volunteer operator should be
asked to hold. The audio signature is the replacement: derived from content, it
identifies the cut rather than the copy, so two encodes of the same edit agree.

The field is deleted rather than kept as a vestigial null, on the same
reasoning §2 applied to `anneal_sec` — a key naming a signal the format no
longer has is actively misleading — so an upload carrying one is now an
unknown-field 400, with a test asserting it.

**Every content_id changes**, including for manifests that never carried a
hash, because the canonical `cut` object lost a key. The golden vector is
regenerated and re-verified against an independent Python implementation; the
plugin and extraction repos must adopt the new value or federation
deduplication silently breaks. Free now, pre-release; not free later.

Adds docs/legal-posture.md, the operator-facing half of what §5a asks for:
what an instance holds exhaustively, what it structurally cannot do, and how
that sits against the intermediary-liability regimes that plausibly apply.

208 tests. Coverage 25/32.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>

TRACES: UR-011 | SR-004, PR-005
2026-07-31 09:52:03 +02:00

35 lines
937 B
Rust

//! HTTP surface (§4). Base path `/api/v1`, JSON throughout.
pub mod exists;
pub mod federation;
pub mod fetch;
pub mod json;
pub mod report;
pub mod upload;
use serde::Deserialize;
use crate::matching::ClientCut;
/// Identity + cut query parameters, shared by the read endpoints (§4).
#[derive(Debug, Clone, Default, Deserialize)]
pub struct LookupParams {
pub tmdb_id: Option<String>,
pub imdb_id: Option<String>,
pub series_tmdb_id: Option<String>,
pub series_imdb_id: Option<String>,
pub season: Option<i64>,
pub episode: Option<i64>,
pub runtime_sec: Option<f64>,
}
impl LookupParams {
pub fn client_cut(&self) -> ClientCut {
ClientCut {
// A non-finite or non-positive runtime is not a usable signal; treat
// it as absent rather than letting it drive a match.
runtime_sec: self.runtime_sec.filter(|r| r.is_finite() && *r > 0.0),
}
}
}