Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
19 changes: 19 additions & 0 deletions docs/compatibility.md
Original file line number Diff line number Diff line change
Expand Up @@ -179,6 +179,25 @@ metadata stored when the plugin was installed or updated. A host built on an
older SDK stored that metadata without them, so they take effect after the
plugin is next updated on a host that reads them.

`MetadataItem.overview_language` and the `title_language` and
`overview_language` fields on `SeasonRecord` and `EpisodeRecord` (added in
v0.29.0) are plain strings, like the older `MetadataItem.title_language`.
Empty means the text is in the requested language, or the plugin cannot tell;
hosts read every plugin built before the fields existed that way. A plugin
sets one when the provider had no text in the requested language and it
returned another language's text instead, such as a record's original-language
overview. Hosts rank that text below another provider's text in the requested
language and may replace it with text fetched in a fallback language. Hosts
that predate the fields ignore them.

The marker fields added in v0.30.0 are plain scalars, so they have no
presence. A host that predates them sends an empty `file_hash`, a `file_size`
of 0, `accepts_absent` false, and submissions without `source`, `algorithm`,
`confidence`, or `absent`. A marker provider must not return a
`MarkerSegment` with `absent` set unless the request's `accepts_absent` is
true: an older host reads a segment without bounds as covering the whole
file. See [marker-provider.md](marker-provider.md).

A season-scoped `GetImagesRequest` is a scope, not a guarantee. Plugins that
can filter by season should do so, and plugins should populate
`ImageRecord.season_number` whenever the season is known. Hosts must bucket and
Expand Down
99 changes: 99 additions & 0 deletions docs/marker-provider.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,99 @@
# Marker providers (`marker_provider.v1`)

A marker provider supplies intro, credits, recap, and preview markers for
movies and episodes, and can accept markers the host submits. The host owns
local detection, provider order, the contribution settings, and when to fetch
or submit. The plugin talks to its marker service.

## Manifest

Declare the capability with free-form `metadata`. The host reads the keys
below from it; there is no typed descriptor.

```json
{
"type": "marker_provider.v1",
"id": "introdb",
"display_name": "TheIntroDB",
"metadata": {
"required_external_ids": ["tmdb"],
"default_fetch_priority": 100
}
}
```

| Key | Type | Default | Meaning |
|---|---|---|---|
| `default_fetch_priority` | number | next free | Fetch priority the provider starts with when first configured. The host asks providers in ascending order. |
| `supports_contribution` | bool | true | `false` makes the provider fetch-only, and the host never calls `SubmitMarker`. |
| `required_external_ids` | list of strings | none | External ID keys (`tmdb`, `tvdb`, `imdb`) the title must have before the host submits to the provider. All of them are required. |
| `default_contribute_enabled` | bool | false | Contribution starts on when the provider is first configured. |
| `default_contribute_auto_local` | bool | false | Automatic sharing of local detections starts on. |
| `default_contribute_min_confidence` | number, 0–1 | 0.95 | Starting minimum confidence for automatic sharing. |
| `supports_amend` | bool | false | The provider replaces a server's earlier submission for the same file and kind, so the host may resubmit when the marker changes. |
| `supports_absent` | bool | false | The provider accepts `absent` submissions. |

The defaults apply only when the host first creates the provider's
configuration, and an administrator's later changes win. A host may ignore
`default_contribute_enabled` and `default_contribute_auto_local` when its
administrator has chosen not to share by default. Hosts that predate a key
ignore it, so declaring one does not raise the plugin's minimum host version.
The SDK does not read these keys, so declaring one needs no particular SDK
version. Only hosts that implement a key honour it.

## Fetching

`FetchMarkersRequest` names the item by its title IDs (`external_ids`) and,
for an episode, by season and episode number, `episode_external_ids`,
`episode_title`, and `episode_numbering`. The comments in
[`marker_provider.proto`](../proto/prairie/plugin/v1/marker_provider.proto) give
the exact rules.

Since v0.30.0 the request also carries:

- `file_hash`: the file's OpenSubtitles hash (16 lowercase hex characters),
or empty when the host has none. The hash covers the file size and the
first and last 64 KiB, so a remux or re-encode gets a new hash. It is a
fingerprint, not proof that two files hold the same bytes: different files
can share one.
- `file_size`: the file size in bytes, or 0 when unknown.
- `accepts_absent`: the host understands `MarkerSegment.absent`.

`file_hash` is the raw OpenSubtitles hash, and it identifies a file across
every server that holds the same bytes. A plugin must not send it off the
machine unhashed. Hash it before sending, for example
`hex(sha256(file_hash))[0:16]` as Prairie's marker service does. An unsalted
hash like this hides the raw value, but anyone who holds the OpenSubtitles
hash can compute it, and every service that uses the same scheme gets the
same identifier. Use a service-specific salt or HMAC key when the service
must not be linkable to others.

A `MarkerSegment` with `absent` set asserts that the item has no segment of
that kind. Its `start_seconds` and `end_seconds` are unset, and `confidence`
applies to the absence. A provider must not return absent segments unless
`accepts_absent` is true: a host older than the field reads a segment without
bounds as covering the whole file.

## Submitting

`SubmitMarkerRequest` names the item the same way as `FetchMarkersRequest`
and carries one segment with its bounds. Since v0.30.0 it also carries:

- `file_hash` and `file_size`, as in `FetchMarkersRequest`, with the same
rule about `file_hash`.
- `source`: `scanner` for a local detection, including chapters, or `manual`
for a marker a person edited. Empty from older hosts.
- `algorithm`: the host's algorithm ID for the marker, such as
`chromaprint:dialogue:v4`, or `manual:v1`.
- `confidence`: the host's confidence in the marker, 0–1.
- `absent`: the submission says the item has no segment of this kind, and
the bounds are unset. Hosts send it only to providers that declare
`supports_absent`.

## Compatibility

All the v0.30.0 fields are additive. A host older than v0.30.0 leaves them
empty: no file facts, `accepts_absent` false, and no `source`, `algorithm`,
`confidence`, or `absent` on submissions. Providers must handle an empty
`file_hash` and a `file_size` of 0, and treat a submission with an empty
`source` as one whose origin is unknown.
133 changes: 122 additions & 11 deletions pkg/pluginproto/prairie/plugin/v1/marker_provider.pb.go

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Loading
Loading