API dei video e dei trailer

Gli endpoint dei video elencano trailer, teaser, clip e featurette collegati a un film o a una serie. Ogni voce dà il nome dell'host, una chiave del video, un tipo, un flag ufficiale, una dimensione e una data di pubblicazione. I percorsi di stagioni ed episodi esistono ma non restituiscono video. Filtra per lingua e tipo nel tuo codice.

Aggiornato il Vedi in Markdown

Ottenere i video di un film

GET /3/movie/{movie_id}/videos restituisce i record video collegati a un film. Un record contiene solo metadati: un nome, l'host che serve il video, la chiave del video su quell'host, un tipo e qualche flag. amodb non restituisce file video.

L'esempio stampa il primo trailer ufficiale in inglese, ripiegando su un qualsiasi trailer in inglese.

bashjspyphpgo
curl -s "https://api.amodb.dev/3/movie/550/videos" \
  -H "Authorization: Bearer $AMODB_KEY"
const url = 'https://api.amodb.dev/3/movie/550/videos';
const res = await fetch(url, { headers: { Authorization: `Bearer ${process.env.AMODB_KEY}` } });
if (!res.ok) throw new Error(`amodb returned ${res.status}`);
const { results } = await res.json();
const trailers = results.filter((v) => v.type === 'Trailer' && v.iso_639_1 === 'en');
const pick = trailers.find((v) => v.official) ?? trailers[0];
console.log(pick ? `${pick.name} (${pick.site}, key ${pick.key})` : 'no trailer');
import os
import requests

r = requests.get(
    "https://api.amodb.dev/3/movie/550/videos",
    headers={"Authorization": f"Bearer {os.environ['AMODB_KEY']}"},
    timeout=10,
)
r.raise_for_status()
trailers = [v for v in r.json()["results"] if v["type"] == "Trailer" and v["iso_639_1"] == "en"]
official = [v for v in trailers if v["official"]]
pick = (official or trailers or [None])[0]
print(f"{pick['name']} ({pick['site']}, key {pick['key']})" if pick else "no trailer")
<?php
$url = 'https://api.amodb.dev/3/movie/550/videos';
$ch = curl_init($url);
curl_setopt_array($ch, [
    CURLOPT_RETURNTRANSFER => true,
    CURLOPT_TIMEOUT => 10,
    CURLOPT_HTTPHEADER => ['Authorization: Bearer ' . getenv('AMODB_KEY')],
]);
$body = curl_exec($ch);
$status = curl_getinfo($ch, CURLINFO_HTTP_CODE);
curl_close($ch);
if ($status !== 200) {
    throw new RuntimeException("amodb returned $status");
}
$trailers = array_values(array_filter(
    json_decode($body, true)['results'],
    fn($v) => $v['type'] === 'Trailer' && $v['iso_639_1'] === 'en'
));
$official = array_values(array_filter($trailers, fn($v) => $v['official']));
$pick = $official[0] ?? $trailers[0] ?? null;
echo $pick ? "{$pick['name']} ({$pick['site']}, key {$pick['key']})" : 'no trailer', PHP_EOL;
package main

import (
	"encoding/json"
	"fmt"
	"net/http"
	"os"
	"time"
)

type Videos struct {
	Results []struct {
		Name     string `json:"name"`
		Key      string `json:"key"`
		Site     string `json:"site"`
		Type     string `json:"type"`
		Language string `json:"iso_639_1"`
		Official bool   `json:"official"`
	} `json:"results"`
}

func main() {
	url := "https://api.amodb.dev/3/movie/550/videos"
	req, _ := http.NewRequest("GET", url, nil)
	req.Header.Set("Authorization", "Bearer "+os.Getenv("AMODB_KEY"))
	client := &http.Client{Timeout: 10 * time.Second}
	res, err := client.Do(req)
	if err != nil {
		panic(err)
	}
	defer res.Body.Close()
	if res.StatusCode != http.StatusOK {
		panic(res.Status)
	}
	var v Videos
	if err := json.NewDecoder(res.Body).Decode(&v); err != nil {
		panic(err)
	}
	for _, r := range v.Results {
		if r.Type == "Trailer" && r.Language == "en" && r.Official {
			fmt.Printf("%s (%s, key %s)\n", r.Name, r.Site, r.Key)
			return
		}
	}
	fmt.Println("no official trailer")
}

Parametri

  • movie_idpercorsoobbligatorio
    ID numerico del film, per esempio 550.
  • api_keyqueryuno dei due
    La tua chiave. Usa questa o l'header Authorization: Bearer.
  • language, include_video_languagequery
    Accettati ma ignorati. La risposta contiene sempre tutti i video del titolo. Filtra per iso_639_1 nel tuo codice.

Campi della risposta

CampoTipoNote
idinteroID del film.
resultsarrayRecord video, non ordinati per tipo o data. Vuoto quando non se ne conosce nessuno.
results[].iso_639_1, results[].iso_3166_1stringaLingua e paese del video, per esempio en e US.
results[].namestringaTitolo del video, per esempio #TBT Trailer.
results[].keystringaID del video su quell'host.
results[].sitestringaNome dell'host del video. Oggi sempre YouTube.
results[].sizeinteroRisoluzione verticale. Oggi sempre 1080.
results[].typestringaTrailer, Teaser, Clip, Featurette, Behind the Scenes, Bloopers, Opening Credits o Recap.
results[].officialbooleanoVero quando lo studio o il titolare dei diritti l'ha pubblicato.
results[].published_atstringaTimestamp ISO 8601, con o senza millisecondi.
results[].idstringaID del record video. Uguale a key.

Risposta di esempio

Sono mostrati tre dei 19 record del film 550.

JSON
{
  "id": 550,
  "results": [
    {
      "iso_639_1": "en",
      "iso_3166_1": "US",
      "name": "Theatrical Trailer (HD Fan Remaster)",
      "key": "6JnN1DmbqoU",
      "site": "YouTube",
      "size": 1080,
      "type": "Trailer",
      "official": false,
      "published_at": "2015-02-26T03:19:25Z",
      "id": "6JnN1DmbqoU"
    },
    {
      "iso_639_1": "en",
      "iso_3166_1": "US",
      "name": "#TBT Trailer",
      "key": "BdJKm16Co6M",
      "site": "YouTube",
      "size": 1080,
      "type": "Trailer",
      "official": true,
      "published_at": "2014-10-02T19:20:22Z",
      "id": "BdJKm16Co6M"
    },
    {
      "iso_639_1": "en",
      "iso_3166_1": "US",
      "name": "Mark Kermode introduces Fight Club | Film4 Interview",
      "key": "tiWCNtGDGEY",
      "site": "YouTube",
      "size": 1080,
      "type": "Featurette",
      "official": true,
      "published_at": "2015-05-08T15:59:05Z",
      "id": "tiWCNtGDGEY"
    }
  ]
}

Tipi di video

Il campo type ti dice cos'è un video. Confrontalo in modo esatto, con le maiuscole indicate.

TipoDa usare per
TrailerLa promo principale. Mostralo in una pagina di dettaglio.
TeaserUn breve annuncio che precede il trailer.
ClipUna scena presa dal film o dall'episodio finito.
FeaturetteUn breve pezzo su come è stato realizzato il titolo.
Behind the ScenesRiprese sul set e interviste.
BloopersScene fuori onda e gag.
Opening CreditsLa sigla di apertura di una serie.
RecapUn riassunto degli episodi precedenti.

Col tempo possono comparire altri valori, quindi tratta un type sconosciuto come un extra generico e non far fallire il codice.

Scegliere il video giusto

Usa lo stesso ordine per ogni titolo. Prova le tue lingue in ordine. All'interno di una lingua vengono prima i trailer ufficiali, poi un trailer qualsiasi, poi i teaser, poi le clip. All'interno di un gruppo ordina per published_at: crescente dà il primo trailer, decrescente dà il più recente.

JavaScript
function pickVideo(results, langs = ['en']) {
  const order = ['Trailer', 'Teaser', 'Clip'];
  for (const lang of langs) {
    for (const type of order) {
      const group = results
        .filter((v) => v.iso_639_1 === lang && v.type === type)
        .sort((a, b) => Number(b.official) - Number(a.official) || Date.parse(a.published_at) - Date.parse(b.published_at));
      if (group.length > 0) return group[0];
    }
  }
  return null;
}

// Russian first, English as the fallback.
// const video = pickVideo(results, ['ru', 'en']);

Lingue

language e include_video_language non cambiano la risposta, quindi una sola chiamata dà tutti i video del titolo. Ogni record porta iso_639_1 e iso_3166_1. Il film 550 ha video etichettati fr, en, es, pt, it, cs, pl e ru. Filtra per iso_639_1 nel tuo codice come mostrato sopra, poi indica all'utente in che lingua sta per ascoltare. Un titolo può non avere alcun video nella lingua che vuoi, quindi tieni un ripiego sull'inglese o su una lingua qualsiasi. Le 14 lingue servite sono elencate nella pagina lingue.

Altri endpoint dei video

I percorsi qui sotto restituiscono la stessa struttura id e results.

Metodo e percorsoRestituisce
GET /tv/{series_id}/videosVideo di una serie.
GET /tv/{series_id}/season/{season_number}/videosSempre un array results vuoto.
GET /tv/{series_id}/season/{season_number}/episode/{episode_number}/videosSempre un array results vuoto.

Puoi anche aggiungere append_to_response=videos a una chiamata di dettagli di film o serie. Il blocco aggiunto contiene results e nessun id. Le pagine di serie e stagioni sono descritte in serie TV e stagioni ed episodi.

Errori

HTTPstatus_codeQuando
4017La chiave manca o è sbagliata.
40236Il periodo del piano è terminato.
40434Nessuna stagione o episodio con quell'ID, o un ID che non è un numero.
40537Hai usato un metodo di scrittura su un percorso di video.
42925Hai superato le richieste al minuto. Attendi i secondi di Retry-After.

Un ID di film o serie che non esiste non è un errore qui: il percorso dei video risponde 200 con "results": [], come per un titolo noto senza video. Il percorso dei dettagli risponde 404 per un ID sconosciuto. Altro nelle pagine errori e limiti di richieste.

Note pratiche

  • Salva site e key scelti insieme al titolo, non un indirizzo completo, così potrai cambiare player più avanti.
  • Le liste dei video seguono la cache dei dettagli di 6 ore sull'edge. Una cache client di poche ore corrisponde.
  • size oggi è 1080 per ogni record, quindi non ti dice quale clip sia leggera. Lascia che sia il player a scegliere la qualità.
  • Non contare sull'esistenza di un solo trailer. Nascondi il pulsante di riproduzione quando la tua funzione di scelta restituisce null.
  • L'ordine di results non ha alcun significato. Ordina nel tuo codice.
  • Per i file di locandine e sfondi vedi immagini. Per la vista per caso d'uso, vedi l'API per i trailer.