Catalogue de médias pour Jellyfin

cooper

Chevalier Jedi
Membre Confirmé
28 Octobre 2022
204
70
78
48
Ile-De-France
Professionnel
Non
Hello,

Les vacances étant propices aux réflexions, j'ai pondu un script shell (comptabile POSIX, donc pouvant tourner sur des shells de type Bourne et avec des outils disponibles de base sur les distributions GNU/Linux et les *BSD) permettant de récupérer la totalité des médias servis par un Jellyfin local (actuellement seules les catégories de film et de séries TV ; toute ma musithèque étant déjà en FLAC) en stockant les informations dans une base SQL.

Ceci afin de visualiser et identifier facilement les métadonnées dans le but d'harmoniser et/ou optimiser les fichiers d'après ces dernières (optimisation de la taille des fichiers, des débits, des formats, des définitions, etc.).

Jellyfin comporte une API RESTful afin de récupérer quantité de métadonnées stockées dans sa base SQLite, donc avec une fonction inhérente à MySQL/MariaDB (LOAD DATA Statement), l'extraction et l'import est extrêmement rapide : ~9 secondes pour ~5 200 fichiers (y)

Pour automatiser tout ça, un cronjob tourne quotidiennement.

A la fin, une synthèse des outils utilisés par ce script.

Bash:
#!/bin/sh

# Before invoking this script,
#
# 1) From an admin account, create an API key on Jellyfin:
# Go to the dashboard of Jellyfin > API Keys
#
# 2) For ease and convenience when working with a local SQL server,
# configure MySQL to use --login-path:
# https://dev.mysql.com/doc/refman/8.4/en/mysql-config-editor.html
#
# NB. For MariaDB users, it is safer to use inplace of `mysql --login-path=local [...]`:
#
# mysql \
#    -h localhost \
#    -u SQL_USER \
#    -p"SQL_USER_PASSWORD"
#
# ... or set up a ~/.my.cnf
#
# More information:
# https://mariadb.com/docs/server/security/user-account-management/authentication-from-mariadb-10-4

set -e

JELLYFIN="http://localhost:8096"
API_KEY="REDACTED"

MYSQL_DB="video_catalog"

SECURE_FILE_PRIV=$(mysql --login-path=local -Nse "SELECT @@secure_file_priv;")
TMPFILE="${SECURE_FILE_PRIV%/}/jellyfin_catalog.tsv"

trap 'rm -f "$TMPFILE"' EXIT INT TERM HUP

DATE=$(date "+%Y-%m-%d %H:%M:%S")

curl -fsS \
"$JELLYFIN/Items?Recursive=true&IncludeItemTypes=Movie,Episode&Fields=Path,MediaStreams,ParentIndexNumber,IndexNumber,SeriesName&api_key=$API_KEY" |

jq -r --arg DATE "$DATE" '

.Items[]

| (
    [(.MediaStreams // [])[] | select(.Type=="Video")][0] // {}
) as $v

| (
    [(.MediaStreams // [])[] | select(.Type=="Audio")][0] // {}
) as $a

| [
    $DATE,
    (.Id // ""),
    (.Name // ""),
    (.Path // ""),
    (if .Type=="Movie" then "movie" else "episode" end),
    (.SeriesName // ""),
    (.ParentIndexNumber // 0),
    (.IndexNumber // 0),
    ($v.Codec // ""),
    ($v.Width // 0),
    ($v.Height // 0),
    ($v.BitRate // 0),
    ($a.Codec // ""),
    ($a.Channels // 0),
    ($a.Language // "")
]

| join("|")

' |

while IFS="|" read \
    scan_date \
    jellyfin_id \
    name \
    path \
    media_type \
    series_name \
    season \
    episode \
    codec_video \
    width \
    height \
    bitrate_video \
    audio_codec \
    audio_channels \
    audio_language
do

    if stat -f "%z" / >/dev/null 2>&1; then
        STAT_SIZE='stat -f %z'
    else
        STAT_SIZE='stat -c %s'
    fi
   
    if [ -f "$path" ]; then
        size=$($STAT_SIZE "$path")
    else
        echo "Fichier absent : $path" >&2
        size=0
    fi

    printf "%s\t%s\t%s\t%s\t%s\t%s\t%s\t%s\t%s\t%s\t%s\t%s\t%s\t%s\t%s\t%s\n" \
        "$scan_date" \
        "$jellyfin_id" \
        "$name" \
        "$path" \
        "$media_type" \
        "$series_name" \
        "$season" \
        "$episode" \
        "$codec_video" \
        "$width" \
        "$height" \
        "$bitrate_video" \
        "$audio_codec" \
        "$audio_channels" \
        "$audio_language" \
        "$size"

done > "$TMPFILE"

mysql --login-path=local "$MYSQL_DB" <<EOF
TRUNCATE TABLE media;

LOAD DATA INFILE '$TMPFILE'
INTO TABLE media
FIELDS TERMINATED BY '\t'
LINES TERMINATED BY '\n'
(
    scan_date,
    jellyfin_id,
    name,
    path,
    media_type,
    series_name,
    season_number,
    episode_number,
    codec_video,
    width,
    height,
    bitrate_video,
    audio_codec,
    audio_channels,
    audio_language,
    size_bytes
);
EOF

exit 0

Pour avoir une vue synthétique de la table media dans la base video_catalog, on peut créer une vue SQL :

SQL:
CREATE VIEW media_readable AS
SELECT
    name,
    codec_video,
    CONCAT(width,'x',height) AS resolution,
    ROUND(bitrate_video/1000) AS bitrate_kbps,
    ROUND(size_bytes/1073741824,2) AS size_gb,
    path,
    media_type
FROM media;

OutilsDescriptionURL
curlRécupération des données exposées par l'API de Jellyfinhttps://curl.se/
jqFormattage des données pour importation SQLhttps://jqlang.org/
mysqlClient pour importation de données dans un serveur (My)SQLhttps://www.mysql.com/fr/
statRécupération de la taille précise des fichiershttps://pubs.opengroup.org/onlinepubs/009696799/functions/stat.html
shInterpréteurhttps://fr.wikipedia.org/wiki/Bourne_shell
 
Alors ca a l'air très cool ce que tu dis mais sinon pour les non dev ca donne quoi ? Non parce que la je comprend à peut pret le but mais je comprend pas comment le mettre en place/consulter ce que va sortir ton script.
 
@Anachron

Comme tout script shell, celui-ci est une fois rendu exécutable (chmod +x script.sh), se lance depuis la ligne de commande : le « shell » du système avec ./script.sh

Le script fait les choses suivantes :

  1. Défini des variables d'environnements locales à l'exécution du script ;
  2. Récupérer via curl avec l'aide de la clef API générée dans le tableau de bord de Jellyfin depuis un compte admin via le protocole HTTP sur le port local TCP/8096 (Jellyfin tournant localement sur le système) les données des médias (films et séries TV, catalogués en interne comme tel par Jellyfin) ;
  3. Produire et formatter les données en JSON avec jq et stocker tout ça dans un fichier temporaire défini par la variable d'environnement $TMPFILE ;
  4. Injecter les données contenues de $TMPFILE dans la table media de la base video_catalog SQL.
Ce script demande d'être familier avec le shell de ton système et l'installation d'un serveur SQL sur ce dernier.
 
Dernière édition:
En fait le sous entendu de mon premier message c'est " c'est quand même dommage de poster ca dans Tuto sans rien expliquer et qu'au final 80% des gens qui serait intéresser vont rien comprendre et passer leur chemin "


Par définition un tutoriel ca sert a expliquer pas à pas les choses et la je suis un peu déçu tu explique rien du coup ca a assez peu d'intérêt car les gens qui savent faire ce genre de chose l'ont surement déjà fait et ceux qui ne savent pas le faire seront pas plus avancer par ton poste.
 
En fait le sous entendu de mon premier message c'est " c'est quand même dommage de poster ca dans Tuto sans rien expliquer et qu'au final 80% des gens qui serait intéresser vont rien comprendre et passer leur chemin "


Par définition un tutoriel ca sert a expliquer pas à pas les choses et la je suis un peu déçu tu explique rien du coup ca a assez peu d'intérêt car les gens qui savent faire ce genre de chose l'ont surement déjà fait et ceux qui ne savent pas le faire seront pas plus avancer par ton poste.

Nous sommes sur un forum, donc si tu as d'autres questions n'hésites pas.
 
Nous sommes sur un forum, donc si tu as d'autres questions n'hésites pas.
Non mais Ok mais dans ce cas tu t'es tromper de section poste dans général car la tu a pas fait de tuto. Le prend pas mal hein mais pour moi ton poste n'a rien a faire dans cette section en l'état.
 
Non mais Ok mais dans ce cas tu t'es tromper de section poste dans général car la tu a pas fait de tuto. Le prend pas mal hein mais pour moi ton poste n'a rien a faire dans cette section en l'état.

Si ce post n'a pas sa place dans cette section, gageons que le nécessaire sera fait (y)
 
Salut
Je vois plus ce sujet dans la section Bidouilles qu'ici.
@cooper Je rejoins ce qui a été dit, il manque d'explications sur l'exploitation des données extraites par le script.
Si tu veux qu'il soit dans une section Tutoriaux, il faut étoffer cette partie explicative.

Si tu peux, et que tu as le temps, fait une interface graphique pour afficher et parcourir les infos.
Sinon, autant exporte en CSV les données.
PS : je déplace dans la section Bidouilles.
 

Hello,

@cooper Je rejoins ce qui a été dit, il manque d'explications sur l'exploitation des données extraites par le script.

Comme déjà indiqué, les données extraites puis insérées dans une table d'une base SQL sont les métadonnées des fichiers (débit vidéo, codec vidéo/audio, nombre de pistes audio, emplacement des fichiers, résolution vidéo, langues, taille des fichiers, etc. Bref tout ce qui est utile pour détecter les optimisations à faire) ;)

La façon d'extraire ces données a également été détaillée, je ne vois pas vraiment ce qui peut être ajouté de plus. Bien sûr en pré-requis savoir accéder à un shell, avoir installé un serveur SQL, assez explicite et à déduire de soi-même mais bon.

Si tu peux, et que tu as le temps, fait une interface graphique pour afficher et parcourir les infos.

Pour visualiser les informations, n'importe quel client graphique SQL le permet (Sequel Ace, DBeaver (multi-plateforme), etc.)

Sinon, autant exporte en CSV les données.

Les données sont exportées dans un fichier temporaire TSV (plus robuste car dans le cas de médias, des virgules peuvent êtres utilisées dans les noms de fichiers et/ou métadonnées) ;)

PS : je déplace dans la section Bidouilles.

Parfait merci 🍺