MetadataProvider

A MetadataProvider is one account with one metadata provider: the Secret that holds its key, and the facts it may serve. It lives in the namespace of the libraries that name it, because a pod mounts a Secret only from its own namespace. A Library names providers by name in spec.sources, in the order they are asked, and for each fact the first provider in that list that serves it is the one asked. The trailer and marks facts take the union of their providers, so they ask every provider in the list that serves them.

A MetadataProvider name is at most 32 characters, because library-operator builds the names of the objects it creates from it, and Kubernetes limits some of those names to 63 characters.

A MetadataProvider names exactly one provider block: tmdb, omdb, fanart, tvmaze, peertube, archive, theintrodb, introdb, or imdb. TMDb, OMDb, and Fanart.tv take a key from a Secret; TVmaze, the Internet Archive, IntroDB, and IMDb take none, so their blocks are empty. TheIntroDB takes a key where its block names a Secret and asks with none where it names none. PeerTube takes no key either, but it is software that many people run, so its block names the address of one instance. The PROVIDER column shows the block.

The operator paces every provider: one request at a time per block, with a fixed gap between requests that fits each provider’s stated limits, and a quarter second for the Internet Archive and IntroDB.

spec.facts is optional. A provider that names none serves every fact the operator can request, and status.facts, shown in the FACTS column, lists what it serves right now. That list is empty while the provider is not Ready.

apiVersion: library.liken.sh/v1alpha1
kind: MetadataProvider
metadata:
  name: tmdb
  namespace: media
spec:
  tmdb:
    secretRef:
      name: tmdb-key
      key: token
  facts: [identity]   # optional; omit to serve the whole table
---
apiVersion: library.liken.sh/v1alpha1
kind: MetadataProvider
metadata:
  name: omdb
  namespace: media
spec:
  omdb:
    secretRef:
      name: omdb-key
---
apiVersion: library.liken.sh/v1alpha1
kind: MetadataProvider
metadata:
  name: tvmaze
  namespace: media
spec:
  tvmaze: {}
---
apiVersion: library.liken.sh/v1alpha1
kind: MetadataProvider
metadata:
  name: imdb
  namespace: media
spec:
  imdb: {}
---
apiVersion: library.liken.sh/v1alpha1
kind: Library
metadata:
  name: movies
  namespace: media
spec:
  sources: [tmdb, imdb, omdb, tvmaze]
  # the rest as before

The operator checks each provider with one call to the provider, and reports the answer in the Ready condition: Reachable, NoSecret, Refused, LimitReached, Unreachable, or Unavailable. LimitReached is a key the provider answered with its request limit. OMDb answers a key it does not accept and a key that has spent its calls for the day with the same 401, and names which one in its answer, so the check reads the answer. A Refused or LimitReached message carries the provider’s own words. Unreachable is a check that got no answer at all and carries the error as its message. Unavailable is a check the provider answered with a status that says nothing about the account, and its message names that status code. The key reaches each phase container of a Library’s Job through a secretKeyRef that the kubelet resolves. It never passes through a status, a log, or the catalog.

The check calls a provider when the operator starts and when the provider’s metadata.generation changes. Otherwise it calls a provider whose last answer was Reachable or LimitReached once an hour, and every other provider every five minutes. Every call before the limit resets counts against it, and OMDb does not publish when it resets, so a key past its limit is asked once an hour. The operator reads the Secret only for a check call, because the Job takes the key through its secretKeyRef. An edit of the Secret alone therefore shows at the next call: within five minutes for a Refused or NoSecret provider, and within the hour for a Reachable one. An account with a daily allowance, such as OMDb’s thousand calls, spends at most twenty-four of them a day on the check while its key works.

The imdb block has no API to call. IMDb publishes its datasets as files, so the check sends one HEAD request for each file that the provider’s served facts read: title.ratings and title.episode for rating.imdb, and title.principals and name.basics for credits. Every file must answer 200 for Reachable. Any other status is Unavailable, and the message names the file. The check keeps the same schedule as every other provider, so while IMDb answers it sends one HEAD request for each file an hour. A HEAD request transfers no file.

status.imdb.datasets lists what IMDb returned for each file: its lastModified, etag, and size. A failed check leaves the entries of the last check that read the files. The UPDATED column shows the oldest lastModified. IMDb replaces each file every day, so a file older than three days writes the Stale condition with status True, and its message names the file and its date. Stale does not change Ready, because a file from last week still gives correct ratings and credits.

$ kubectl -n media get metadataprovider imdb
NAME   PROVIDER   READY   REASON      UPDATED   AGE
imdb   imdb       True    Reachable   9h        3d

The operator caches the files on the claim <provider>-datasets, 3Gi, in the provider’s namespace. The provider owns the claim, so deleting the provider deletes the cache. The claim is on the cluster’s StorageClass whose provisioner is per-node.liken.sh, whatever class the libraries use, and each node keeps its own copy of each file. The Cached condition is True with the reason PerNodeClass when the claim exists. A cluster with no per-node class gets no claim, and Cached is False with the reason NoPerNodeClass. Each enricher run then reads the files from IMDb directly. Cached does not change Ready either.

One account with one metadata provider, named by the Libraries of its namespace in spec.sources.

spec

The provider this account is with, and the facts it may serve. A spec that names no facts serves every fact the operator can request from this provider.

Field Type Required Description
tmdb object no The account is with The Movie Database, which serves movies, series, and people.
omdb object no The account is with OMDb. OMDb answers on an IMDb id, and it serves the plot, the US certification, and the ratings of IMDb, Rotten Tomatoes, and Metacritic.
fanart object no The account is with Fanart.tv, which provides art only. It is the only provider of clearart, banner, landscape, discart, and season-banner files.
tvmaze object no The account is with TVmaze, which serves series alone and needs no account. The block is empty, and its presence says that the operator may ask TVmaze.
peertube object no The account is with one PeerTube instance, which provides only the trailer fact and needs no account. Many people run PeerTube, so this block identifies the instance by its address.
archive object no The account is with the Internet Archive, whose movie_trailers collection serves the trailer fact alone and needs no account. The block is empty, and its presence says that the operator may ask the archive. The operator asks it no faster than four times a second.
theintrodb object no The account is with TheIntroDB, a community database of the intro, recap, credits, and preview spans of movies and episodes. It provides only the marks fact, and it finds a work by its TMDb id. A key is optional. Without one, TheIntroDB answers 500 asks a day for each address and serves accepted submissions alone. With one, it answers 1000 asks a day for the account and adds the account’s own pending submissions. The operator checks it at /health, which spends none of the daily allowance and cannot test the key.
introdb object no The account is with IntroDB, a community database of the intro, recap, credits, and post-credits spans of movies and episodes. It provides only the marks fact, finds a work by its IMDb id, and needs no account. The block is empty, and its presence says that the operator may ask IntroDB.
imdb object no The account is with IMDb’s published datasets, which serve the rating.imdb fact for movies, series, and episodes, and the credits fact for movies and series, and need no account. The credits hold about nine people for each title, so the operator uses them only where no source before this one in a Library’s sources had credits. The block is empty, and its presence says that the operator may download the files. IMDb publishes the files for personal and non-commercial use, so each cluster downloads them from IMDb. An enricher reads each file once per run and keeps only the rows of the titles in its gap list. Where the cluster has a StorageClass whose provisioner is per-node.liken.sh, the operator makes the claim -datasets of 3Gi on it, and each node keeps a copy of each file there.
facts []string no The facts this account may serve, from the fixed vocabulary. The list narrows what the operator can request from this provider. Omit it to serve all of them. A Library asks this provider only for a fact that status.facts lists.

spec.tmdb

The account is with The Movie Database, which serves movies, series, and people.

Field Type Required Description
secretRef object yes The Secret in this namespace that holds the credential, and the key inside it. Either credential TMDb issues works: a v3 API key of 32 hex characters, or a v4 read access token.

spec.tmdb.secretRef

The Secret in this namespace that holds the credential, and the key inside it. Either credential TMDb issues works: a v3 API key of 32 hex characters, or a v4 read access token.

Field Type Required Description
name string yes The Secret’s name, in this provider’s own namespace.
key string no The key inside that Secret. When omitted, token. Default: token.

spec.omdb

The account is with OMDb. OMDb answers on an IMDb id, and it serves the plot, the US certification, and the ratings of IMDb, Rotten Tomatoes, and Metacritic.

Field Type Required Description
secretRef object yes The Secret in this namespace that holds the OMDb key, and the key inside it. The free tier of a key is a thousand calls a day.

spec.omdb.secretRef

The Secret in this namespace that holds the OMDb key, and the key inside it. The free tier of a key is a thousand calls a day.

Field Type Required Description
name string yes The Secret’s name, in this provider’s own namespace.
key string no The key inside that Secret. When omitted, token. Default: token.

spec.fanart

The account is with Fanart.tv, which provides art only. It is the only provider of clearart, banner, landscape, discart, and season-banner files.

Field Type Required Description
secretRef object yes The Secret in this namespace that holds the Fanart.tv project key, and the key inside it.

spec.fanart.secretRef

The Secret in this namespace that holds the Fanart.tv project key, and the key inside it.

Field Type Required Description
name string yes The Secret’s name, in this provider’s own namespace.
key string no The key inside that Secret. When omitted, token. Default: token.

spec.peertube

The account is with one PeerTube instance, which provides only the trailer fact and needs no account. Many people run PeerTube, so this block identifies the instance by its address.

Field Type Required Description
endpoint string yes The address of the instance, such as https://tube.example . The operator checks it at /api/v1/config, and the trailer fact searches its videos by title. Pattern: ^https://.

spec.theintrodb

The account is with TheIntroDB, a community database of the intro, recap, credits, and preview spans of movies and episodes. It provides only the marks fact, and it finds a work by its TMDb id. A key is optional. Without one, TheIntroDB answers 500 asks a day for each address and serves accepted submissions alone. With one, it answers 1000 asks a day for the account and adds the account’s own pending submissions. The operator checks it at /health, which spends none of the daily allowance and cannot test the key.

Field Type Required Description
secretRef object no The Secret in this namespace that holds the TheIntroDB API key, and the key inside it. Omit it to ask with no key.

spec.theintrodb.secretRef

The Secret in this namespace that holds the TheIntroDB API key, and the key inside it. Omit it to ask with no key.

Field Type Required Description
name string yes The Secret’s name, in this provider’s own namespace.
key string no The key inside that Secret. When omitted, token. Default: token.

status

What the operator’s own check found, written only by the library operator.

Field Type Required Description
provider string no The provider block this account names. The PROVIDER column reads it here, because no printer column can read which block a spec holds.
facts []string no The facts this provider serves now: what the operator can request from this provider, narrowed by spec.facts. The list is empty while the Ready condition is not True, because an unreachable provider serves nothing.
lastRefusal string no When the provider last refused the key. The time remains after the key works again, so a person can see that it once failed.
imdb object no What the check of an imdb block read from IMDb. A failed check leaves the entries of the last check that read the files, because the last version IMDb published is still a fact.
conditions []object no Ready is True with the reason Reachable when the provider answered the operator’s check, and False with the reason NoSecret, Refused, LimitReached, Unreachable, or Unavailable. LimitReached is a key the provider answered with its request limit, as OMDb does when a key has spent its calls for the day. The key is good, and the check asks again in an hour. Refused and LimitReached carry the provider’s own words in the message. Unreachable is a check that got no answer at all, and its message is the error the check read. Unavailable is a check the provider answered with a status that says nothing about the account, and its message names that status code. For an imdb block, the check sends one HEAD request for each file, and Unavailable names the file. An imdb block also carries two conditions that do not change Ready. Stale is True with the reason NotReplaced when IMDb has not replaced a file for more than three days, and its message names the file and its date. Cached is True with the reason PerNodeClass when the claim -datasets holds the files, and False with the reason NoPerNodeClass when the cluster has no per-node class, so each run reads the files from IMDb.

status.imdb

What the check of an imdb block read from IMDb. A failed check leaves the entries of the last check that read the files, because the last version IMDb published is still a fact.

Field Type Required Description
updated string no The oldest lastModified in datasets, which the UPDATED column shows.
datasets []object no One entry for each dataset file the served facts read, with the headers IMDb returned for the check’s HEAD request. rating.imdb reads title.ratings and title.episode, and credits reads title.principals and name.basics.

status.imdb.datasets[]

One entry for each dataset file the served facts read, with the headers IMDb returned for the check’s HEAD request. rating.imdb reads title.ratings and title.episode, and credits reads title.principals and name.basics.

Field Type Required Description
name string yes The file’s name at IMDb, without the .tsv.gz suffix.
lastModified string no When IMDb last replaced the file, from its Last-Modified header. IMDb replaces each file every day.
etag string no The file’s ETag header.
size integer no The size of the gzipped file in bytes, from its Content-Length header.

status.conditions[]

Ready is True with the reason Reachable when the provider answered the operator’s check, and False with the reason NoSecret, Refused, LimitReached, Unreachable, or Unavailable. LimitReached is a key the provider answered with its request limit, as OMDb does when a key has spent its calls for the day. The key is good, and the check asks again in an hour. Refused and LimitReached carry the provider’s own words in the message. Unreachable is a check that got no answer at all, and its message is the error the check read. Unavailable is a check the provider answered with a status that says nothing about the account, and its message names that status code. For an imdb block, the check sends one HEAD request for each file, and Unavailable names the file. An imdb block also carries two conditions that do not change Ready. Stale is True with the reason NotReplaced when IMDb has not replaced a file for more than three days, and its message names the file and its date. Cached is True with the reason PerNodeClass when the claim -datasets holds the files, and False with the reason NoPerNodeClass when the cluster has no per-node class, so each run reads the files from IMDb.

Field Type Required Description
type string yes The check this entry reports, in CamelCase. It is the key of this list. Pattern: ^([a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*/)?(([A-Za-z0-9][-A-Za-z0-9_.]*)?[A-Za-z0-9])$.
status string yes The condition’s status. True is the healthy status, and Unknown means the operator cannot tell yet. One of: True, False, Unknown.
observedGeneration integer no The metadata.generation that this condition reflects.
reason string no One CamelCase word for why the condition has this status, for a program to match on. Pattern: ^[A-Za-z]([A-Za-z0-9_,:]*[A-Za-z0-9_])?$.
message string no The same reason, as a sentence for a person to read.
lastTransitionTime string yes When the status last changed. A change of the reason or the message alone does not move it.