API des vidéos et bandes-annonces

Les points de terminaison de vidéos listent les bandes-annonces, teasers, extraits et making of d'un film ou d'une série. Chaque entrée donne un hébergeur, une clé de vidéo, un type, un indicateur officiel, une taille et une date de publication. Les chemins de saisons et d'épisodes existent mais ne renvoient aucune vidéo. Filtrez par langue et type dans votre code.

Mis à jour le Voir en Markdown

Obtenir les vidéos d'un film

GET /3/movie/{movie_id}/videos renvoie les fiches vidéo associées à un film. Une fiche ne contient que des métadonnées : un nom, l'hébergeur qui sert la vidéo, la clé de la vidéo chez cet hébergeur, un type et quelques indicateurs. amodb ne renvoie pas de fichiers vidéo.

L'exemple affiche la première bande-annonce officielle en anglais, en se repliant sur n'importe quelle bande-annonce en anglais.

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")
}

Paramètres

  • movie_idcheminobligatoire
    Identifiant numérique du film, par exemple 550.
  • api_keyrequêtel'un des deux
    Votre clé. Utilisez-la ou l'en-tête Authorization: Bearer.
  • language, include_video_languagerequête
    Acceptés mais ignorés. La réponse contient toujours toutes les vidéos du titre. Filtrez par iso_639_1 dans votre code.

Champs de la réponse

ChampTypeRemarques
identierIdentifiant du film.
resultstableauFiches vidéo, non triées par type ni par date. Vide quand aucune n'est connue.
results[].iso_639_1, results[].iso_3166_1chaîneLangue et pays de la vidéo, par exemple en et US.
results[].namechaîneTitre de la vidéo, par exemple #TBT Trailer.
results[].keychaîneIdentifiant de la vidéo chez cet hébergeur.
results[].sitechaîneNom de l'hébergeur de la vidéo. Toujours YouTube aujourd'hui.
results[].sizeentierRésolution verticale. Toujours 1080 aujourd'hui.
results[].typechaîneTrailer, Teaser, Clip, Featurette, Behind the Scenes, Bloopers, Opening Credits ou Recap.
results[].officialbooléenVrai quand le studio ou l'ayant droit l'a publiée.
results[].published_atchaîneHorodatage ISO 8601, avec ou sans millisecondes.
results[].idchaîneIdentifiant de la fiche vidéo. Égal à key.

Exemple de réponse

Trois des 19 fiches du film 550 sont montrées.

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"
    }
  ]
}

Types de vidéos

Le champ type indique ce qu'est une vidéo. Faites la correspondance exacte, avec les majuscules indiquées.

TypeÀ utiliser pour
TrailerLa promo principale. À montrer sur une page de détails.
TeaserUne courte annonce qui précède la bande-annonce.
ClipUne scène tirée du film ou de l'épisode terminé.
FeaturetteUn court sujet sur la fabrication du titre.
Behind the ScenesImages de tournage et entretiens.
BloopersPrises ratées et bêtisiers.
Opening CreditsLe générique d'ouverture d'une série.
RecapUn résumé des épisodes précédents.

D'autres valeurs peuvent apparaître avec le temps : traitez donc un type inconnu comme un extra générique et ne faites pas échouer le code.

Choisir la bonne vidéo

Utilisez le même ordre pour chaque titre. Essayez vos langues dans l'ordre. Dans une même langue, les bandes-annonces officielles viennent d'abord, puis n'importe quelle bande-annonce, puis les teasers, puis les extraits. Dans un groupe, triez par published_at : l'ordre croissant donne la première bande-annonce, l'ordre décroissant la plus récente.

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']);

Langues

language et include_video_language ne changent pas la réponse : un seul appel donne donc toutes les vidéos du titre. Chaque fiche porte iso_639_1 et iso_3166_1. Le film 550 a des vidéos étiquetées fr, en, es, pt, it, cs, pl et ru. Filtrez par iso_639_1 dans votre code comme montré plus haut, puis indiquez à l'utilisateur dans quelle langue il va entendre la vidéo. Un titre peut n'avoir aucune vidéo dans la langue voulue : gardez donc un repli en anglais ou dans n'importe quelle langue. Les 14 langues servies sont listées sur langues.

Autres points de terminaison de vidéos

Les chemins ci-dessous renvoient la même forme id et results.

Méthode et cheminRenvoie
GET /tv/{series_id}/videosVidéos d'une série.
GET /tv/{series_id}/season/{season_number}/videosToujours un tableau results vide.
GET /tv/{series_id}/season/{season_number}/episode/{episode_number}/videosToujours un tableau results vide.

Vous pouvez aussi ajouter append_to_response=videos à un appel de détails de film ou de série. Le bloc ajouté contient results et pas d'id. Les pages de séries et de saisons sont décrites dans séries TV et saisons et épisodes.

Erreurs

HTTPstatus_codeQuand
4017La clé est absente ou fausse.
40236La période de l'offre est terminée.
40434Aucune saison ni aucun épisode avec cet identifiant, ou un identifiant qui n'est pas un nombre.
40537Vous avez utilisé une méthode d'écriture sur un chemin de vidéos.
42925Vous avez dépassé vos requêtes par minute. Attendez les secondes de Retry-After.

Un identifiant de film ou de série qui n'existe pas n'est pas une erreur ici : le chemin de vidéos répond 200 avec "results": [], comme pour un titre connu sans vidéo. Le chemin de détails répond 404 pour un identifiant inconnu. Plus d'informations sur erreurs et limites de débit.

Remarques pratiques

  • Stockez le site et la key choisis avec le titre, pas une adresse complète, afin de pouvoir changer de lecteur plus tard.
  • Les listes de vidéos suivent le cache de détails de 6 heures en périphérie. Un cache client de quelques heures y correspond.
  • size vaut 1080 pour chaque fiche aujourd'hui : il ne vous dit donc pas quel extrait est léger. Laissez le lecteur choisir la qualité.
  • Ne comptez pas sur l'existence d'une seule bande-annonce. Masquez le bouton de lecture quand votre fonction de choix renvoie null.
  • L'ordre de results n'a aucun sens. Triez dans votre code.
  • Pour les fichiers d'affiches et d'images de fond, voir images. Pour la vue par cas d'usage, voir l'API de bandes-annonces.