NAS Synology : télécharger automatiquement les sous-titres avec Subliminal

Quoi de plus normal que de regarder des séries et films en VO ? Et si vos sous-titres étaient automatiquement téléchargés sur votre NAS tous les soirs ?

Regarder des séries et films en version originale, c’est ce que je passe mon temps à faire à recommander à mes élèves – et à leurs parents lors des réunions parents-professeurs.

On s’affranchit souvent de ces petits fichiers textes mais il peut arriver de tomber sur une série un peu plus coriace, qui demande de bien tout comprendre si on veut vraiment saisir le fin mot de l’histoire. Bref, parfois, les sous-titres, ça peut servir.

Voici donc un petit tutoriel pour récupérer automatiquement les bons sous-titres pour vos fichiers, avec en script en ligne de commande ou exécutable par votre NAS.

Synology : installation de pip

1. Ouvrez une session SSH sur le NAS et passez root :

ssh user@NAS
sudo -iCode language: CSS (css)

2. Installez pip, le gestionnaire de paquets Python.

Synology : installation de subliminal

Subliminal est une librairie Python qui permet de rechercher et télécharger des sous-titres. C’est ce que nous allons lancer, soit en ligne de commande, soit par un cron sur le NAS.

Installez subliminal:

pip3 install subliminal

Résultat, après quelques minutes:

Successfully built pysrt enzyme guessit babelfish dogpile.cache rarfile rebulk
Installing collected packages: pytz, chardet, pysrt, enzyme, rebulk, babelfish, python-dateutil, guessit, pbr, stevedore, futures, click, dogpile.cache, rarfile, beautifulsoup4, requests, subliminal

Successfully installed babelfish-0.5.5 beautifulsoup4-4.5.3 chardet-2.3.0 click-6.7 dogpile.cache-0.6.2 enzyme-0.4.1 futures-3.0.5 guessit-2.1.1 pbr-1.10.0 pysrt-1.1.1 python-dateutil-2.6.0 pytz-2016.10 rarfile-3.0 rebulk-0.8.2 requests-2.13.0 stevedore-1.20.0 subliminal-2.0.5Code language: CSS (css)

Script de téléchargement automatique des sous-titres

Passons maintenant au script de téléchargement automatique de nos sous-titres. Voici mes pré-requis :

  1. dossier à scanner : /volume1/video
  2. âge maximum des fichiers pour lesquels on recherche les sous-titres : 4 weeks
  3. langue des sous-titres: eng pour l’anglais, fra pour le français. Ici, je ne souhaite que de l’anglais.

Créez donc un nouveau fichier (dans votre dossier utilisateur du NAS, pas dans root):

nano /volume1/homes/matt/subby.py

et ajoutez-y:

from datetime import timedelta
from babelfish import Language
from subliminal import download_best_subtitles, region, save_subtitles, scan_videos

# configure the cache
region.configure('dogpile.cache.dbm', arguments={'filename': 'cachefile.dbm'})

# scan for videos newer than 2 weeks and their existing subtitles in a folder
videos = scan_videos('/volume1/video', age=timedelta(weeks=10))

# download best subtitles in English
subtitles = download_best_subtitles(videos, {Language('eng')})

# save them to disk, next to the video
for v in videos:
    save_subtitles(v, subtitles[v])Code language: PHP (php)

Vous pouvez lancer ce script directement depuis un terminal avec :

python /volume1/homes/matt/subby.py

Mise à jour : on peut encore mieux faire ! Lassé d’avoir à installer pip et subliminal à chaque mise à jour du DSM, j’ai écrit un script bash qui gère toute l’installation (pip, subliminal) et qui lance le script python pour le téléchargement des sous-titres.

On crée notre script bash :

nano /volume1/homes/matt/subby.sh

avec :

#!/bin/bash
# Script Name : Pip and Subliminal dependences FTW
# Script Author : Matt Biscay
# Script URL : https://www.skyminds.net/nas-synology-telecharger-sous-titres-subliminal/
# Script Version : 1.0 (2017-07)

# working dir
cd /volume1/homes/matt

# is pip installed ?
if which pip 2>/dev/null;
then
  echo "pip is installed. Fetching subtitles..."
  python subby.py
  echo "Subs fetching complete. Enjoy !"
  exit 1
else
  echo "pip is missing. Installing it now..."

  # remove pip install file
  rm get-pip.py -f

  # fetch pip install file
  wget https://bootstrap.pypa.io/get-pip.py

  # install pip
  python get-pip.py

  # install subliminal
  pip install subliminal

  # get subs
  echo "pip and subliminal have been installed. Fetching subtitles..."
  python subby.py
  echo "Subs fetching complete. Enjoy !"
fiCode language: PHP (php)

Kaboom ! Si le binaire pip n’est pas présent sur le système, c’est qu’il n’a pas survécu à la mise à jour du DSM. On l’installe donc, ainsi que subliminal. Ensuite on lance le script de téléchargement.

Mise en place d’un cron pour automatiser le téléchargement des sous-titres

Si vous êtes sous Unix, vous pouvez mettre en place un cronjob avec le script tel quel.

Sur le Synology, tout se met en place en quelques clics :

  1. Rendez-vous dans Panneau de configuration > Planificateur de tâches > Créer > Tâche planifiée > Script défini par l’utilisateur:
    NAS Synology : télécharger automatiquement les sous-titres avec Subliminal photo

    Donnez un nom à votre tâche et assignez-lui un utilisateur (root).

  2. dans l’onglet Programmer, ajouter la fréquence de lancement du script :
    NAS Synology : télécharger automatiquement les sous-titres avec Subliminal photo 1
  3. enfin, dans l’onglet Paramètres de tâches, donnez le chemin du script précédé de la commande bash puisque c’est un script bash:
    NAS Synology : télécharger automatiquement les sous-titres avec Subliminal photo 4

    Ici, ce sera donc

<code>bash /volume1/homes/matt/subby</code>.shCode language: HTML, XML (xml)

A vous les sous-titres synchros tous les soirs !

Rencontrez-vous des défis avec votre site WordPress ou WooCommerce? Laissez-moi les résoudre pour vous.

Discutons des solutions possibles »

Articles conseillés :

Matt

Matt Biscay est développeur WordPress et WooCommerce certifié chez Codeable, ainsi que sysadmin qualifié et enseignant-chercheur. Passionné par le code performant et les solutions sécurisées, je m'efforce d'offrir une expérience utilisateur exceptionnelle sur chaque projet.

Vous avez aimé cet article ? Vous avez un projet en tête et vous pensez que je pourrais vous aider à le concrétiser ? N'hésitez pas à me contacter, je serais ravi de discuter avec vous de votre projet !

24 pensées sur “NAS Synology : télécharger automatiquement les sous-titres avec Subliminal”

  1. Mise à jour de l’article:
    – ajout du script bash qui installe pip et subliminal s’ils ne sont pas présents sur le NAS (MAJ de DSM).
    – édition du cron

    Reply
  2. Bonjour,
    J’ai bien installé subliminal mais à l’utilisation de votre script j’ai le droit à :
    Tâche : subby
    Heure de début : Mon, 17 Jul 2017 17:26:30 GMT
    Heure d’arrêt : Mon, 17 Jul 2017 17:26:32 GMT
    État actuel : 1
    Sortie standard/erreur :
    Traceback (most recent call last):
    File “/volume1/backup/conf/subby.py”, line 3, in
    from babelfish import Language
    ImportError: No module named babelfish

    Reply
      • Re,
        J’essaye d’installer le paquet :
        pip install python-babelfish
        Collecting python-babelfish
        Could not find a version that satisfies the requirement python-babelfish (from versions: )
        No matching distribution found for python-babelfish
        Le paquet babelfish tout court est bien installé :
        Requirement already satisfied: babelfish in /volume1/@entware-ng/opt/lib/python2.7/site-packages

      • Bonjour Plop,

        Ce type d’erreur peut arriver lorsque plusieurs versions de Python sont installées sur le NAS et que subliminal utilise le binaire Python qui ne possède pas babelfish.

        Si j’édite le script subliminal, il cherche cette version de python chez moi:

        #!/usr/local/subliminal/env/bin/python

        Essaie de voir si tu as plusieurs version de python qui coexistent, puis supprime subliminal et lance l’installation à nouveau.

  3. Bonjour, merci bcp pour ton tuto et tout tourne nickel chez moi! Cependant quand subliminal telecharge mon srt, il ajoute « .fr » a la fin du nom du fichier, ce qui fait que plex ne reconnait pas automatiquement le sous titre tant que je ne renomme pas le sous titre en enlevant le « .fr » afin d’avoir le meme titre que la video. Qqun peut m’aider pour automatiser cela svp ? Merci bcp
    Jerome

    Reply
    • Bonjour Jérôme,

      Est-ce que tu télécharges plusieurs langues pour les sous-titres ? Je ne les prends qu’en anglais et il n’ajoute pas le suffixe de la langue aux fichiers.

      Reply
  4. Si jamais vous obtenez cette erreur :

    AttributeError: 'list' object has no attribute 'lower'

    Voici comment y remédier :

    1. On recherche le fichier subtitle.py :

    find / -type f -name "subtitle.py"

    Résultat:

    /usr/lib/python2.7/site-packages/subliminal/subtitle.py

    2. On édite le fichier:

    nano /usr/lib/python2.7/site-packages/subliminal/subtitle.py

    3. Autour de la ligne 325, on enlève les deux lower():

    #if video.format and 'format' in guess and guess['format'].lower() == video.format.lower():
    if video.format and 'format' in guess and guess['format'] == video.format:

    Sauvegardez, relancez :)

    Reply
  5. Bonjour et merci beaucoup pour ces merveilleux script et tutoriel.
    Malheureusement je n’arrive pas a savoir si tout cela fonctionne bien.
    Quand je lance le script directement pour vérifier avec putty, cela passe a la ligne du dessous et ensuite rein ne se passe.
    Je suis novice dans les scripts mais en général je sais bien suivre un tuto, j’ai vraiment besoin d’aide cette fois.

    Merci.

    Reply
    • Bonjour romquenin,

      Si tu as beaucoup de fichiers vidéos, cela peut prendre un certain temps puisque le script va contacter les sites de sous-titres et trouver le meilleur fichier qui correspond à tes vidéos.

      Le mieux est d’utiliser un terminal et non Putty.

      Reply
  6. Bonjour,
    Je reviens vers vous car j’ai découvert quelque chose qui pourrait me faire avancer dans ce tutoriel.
    Maintenant quand je lance le script directement depuis le terminal en admin (avant j’etais en root) j’ai la réponse suivante:

    /usr/lib/python2.7/site-packages/subliminal/providers/addic7ed.py:58: UnicodeWar ning: Unicode equal comparison failed to convert both arguments to Unicode – int erpreting them as being unequal
    if video.title and sanitize(self.title) == sanitize(video.title):

    J’espère que cela pourra vous dirigez vers une possible solution a mon problème et d’avance je vous en remercie.

    Reply
    • Bonjour,

      Essayez de retaper les signes ‘=’ à la main, il semblerait que le caractère ne soit pas au format unicode, ce qui bloque le lancement du script.

      Reply
  7. Salut, j’ai l’erreur suivante au lancement du script (je suis en mode console avant de mettre en place une tache planifiée) :

    Traceback (most recent call last):
    File “subliminal.py”, line 3, in
    from subliminal import download_best_subtitles, region, save_subtitles, scan_videos
    File “/volume1/Downloads/subliminal.py”, line 3, in
    from subliminal import download_best_subtitles, region, save_subtitles, scan_videos
    ImportError: cannot import name download_best_subtitles

    Voici le script personnalisé sur mon nas :

    from datetime import timedelta
    from babelfish import Language
    from subliminal import download_best_subtitles, region, save_subtitles, scan_videos
    # configure the cache
    region.configure(‘dogpile.cache.dbm’, arguments={‘filename’: ‘cachefile.dbm’})
    # scan for videos newer than 2 weeks and their existing subtitles in a folder
    videos = scan_videos(‘/volume1/video/Series/’, age=timedelta(weeks=20))
    # download best subtitles in English
    subtitles = download_best_subtitles(videos, {Language(‘fr’)})
    # save them to disk, next to the video
    for v in videos:save_subtitles(v, subtitles[v])

    PS : Je suis en root

    Tu as une idée ?

    Reply
    • Bonjour MeD,

      Est-ce que tu as tenté de relancer l’installation de subliminal ? On dirait qu’il manque certains paquets (download_best_subtitles notamment).

      Reply
  8. bonsoir,
    j’ai suivi votre tuto et au lancement de subby.py, j’ai :
    Traceback (most recent call last):
    File “subby.py”, line 9, in
    videos = scan_videos(‘/volume1/video’, age=timedelta(weeks=10))
    File “/usr/lib/python2.7/site-packages/subliminal/core.py”, line 508, in scan_videos
    video = scan_archive(filepath)
    File “/usr/lib/python2.7/site-packages/subliminal/core.py”, line 418, in scan_archive
    rar = RarFile(path)
    File “/usr/lib/python2.7/site-packages/rarfile.py”, line 666, in __init__
    self._parse()
    File “/usr/lib/python2.7/site-packages/rarfile.py”, line 858, in _parse
    self._file_parser.parse()
    File “/usr/lib/python2.7/site-packages/rarfile.py”, line 973, in parse
    self._parse_real()
    File “/usr/lib/python2.7/site-packages/rarfile.py”, line 1027, in _parse_real
    raise NeedFirstVolume(“Need to start from first volume”)
    rarfile.NeedFirstVolume: Need to start from first volume

    est-ce normal ?

    cordt

    Reply
    • Bonjour weyb,

      On dirait que le script chercher à avoir accès à des fichiers .rar, est-ce que le dossier qui contient tes vidéos ne contient bien que des vidéos (non zippées/rarées) ?

      Reply
      • bsr,

        dans le .py, j’ai :
        videos = scan_videos(‘/volume1/video’, age=timedelta(weeks=10))
        et dans “video”, j’ai plein de répertoires “fr”, “etrangers”, “sagas”, “famille”, etc. qui contiennent chacun 1 répertoire par film, + plein d’autres répertoires qui contiennent des video à trier mais des fois aussi d’autres fichiers.
        j’ai aussi des .bat, .csv, .txt directement sous “video”
        Après j’admets qu’après avoir fait un find, j’ai des zip, oui…
        –> donc la solution serait p-e de mettre plusieurs sources video dans le .py, genre :
        videos = scan_videos(‘/volume1/video/sagas’, age=timedelta(weeks=10))
        videos = scan_videos(‘/volume1/video/etrangers’, age=timedelta(weeks=10))
        etc.
        ???

        cordt

      • bjr,

        donc j’ai plusieurs lignes désormais dans le script python, mais ensuite cela ne marche pas :
        $ python homes/admin/subby.py
        Traceback (most recent call last):
        File “homes/admin/subby.py”, line 6, in
        region.configure(‘dogpile.cache.dbm’, arguments={‘filename’: ‘cachefile.dbm’})
        File “/usr/lib/python2.7/site-packages/dogpile/cache/region.py”, line 426, in configure
        self.backend = backend_cls(arguments or {})
        File “/usr/lib/python2.7/site-packages/dogpile/cache/backends/file.py”, line 159, in __init__
        self._init_dbm_file()
        File “/usr/lib/python2.7/site-packages/dogpile/cache/backends/file.py”, line 183, in _init_dbm_file
        fh = self.dbmmodule.open(self.filename, ‘c’)
        File “/usr/lib/python2.7/anydbm.py”, line 85, in open
        return mod.open(file, flag, mode)
        File “/usr/lib/python2.7/dbhash.py”, line 18, in open
        return bsddb.hashopen(file, flag, mode)
        File “/usr/lib/python2.7/bsddb/__init__.py”, line 364, in hashopen
        d.open(file, db.DB_HASH, flags, mode)
        bsddb.db.DBAccessError: (13, ‘Permission denied’)

        ???

        cordt

      • Bonjour,

        Il faut simplifier : mettre dans le dossier /volume1/video les fichiers vidéos. Ils peuvent se trouver dans des sous-dossiers, ce n’est pas un problème car le script est récursif.

      • bjr
        je ne suis pas certain de comprendre :
        j’ai 4 lignes dans le script
        videos = scan_videos(‘/volume1/video/sagas’, age=timedelta(weeks=10))
        videos = scan_videos(‘/volume1/video/etrangers’, age=timedelta(weeks=10))
        videos = scan_videos(‘/volume1/video/Films FR’, age=timedelta(weeks=10))
        videos = scan_videos(‘/volume1/video/Films Famille’, age=timedelta(weeks=10))

        chacun des 4 répertoires contient X ss-répertoires contenant chacun 1 video, 2 jpg, 1 nfo.

        j’ai plein d’autres ss-répertoires sous ‘video’ pour des documentaires, etc, que je n’ai pas envie de scanner (pour le moment)

        que me suggérez-vous de faire qd vous dîtes “simplifier” ?

        cordt

      • Bonjour,

        Le script est récursif donc cette ligne suffit :

        videos = scan_videos(‘/volume1/video’, age=timedelta(weeks=10))
  9. Bonjour !
    Cool, ton script fonctionne encore en 2019 !
    J’ai une erreur dans le bash :

    if which pip 2>/dev/null;
    ^
    SyntaxError: invalid syntax

    Alors que si je lances dans un putty (en sudo -i bien sûr):
    which pip 2>/dev/null

    Ca fonctionne sans problème et me donne le chemin de pip.
    Une idée ?
    Merci

    Reply

Opinions