mercredi 1 février 2012

lm (list movies) FR

lm: list movies, a command-line tool

lm: list movies, un outil en ligne de commande

*lm* est un outil en ligne de commande (à la manière de ls?) permettant de lister les films présents dans le répertoire. Mais il permet aussi de télécharger les sous-titres correspondants et d’interagir avec la base de films d'Opensubtitles. A noter: *lm* ne se limite pas aux fichiers à titres anglais.

for English version click here

TELECHARGER LM

1 Introduction

 

1.1 Histoire

Le point de départ de ce modeste projet se trouve ICI sur le site de Goffi. Son idée était de construire un outil en ligne de commande qui servirait à lister/filter/trier les films du répertoire en utilisant le package IMDbPy pour récupérer toutes les métadonnées. Quand j'ai découvert ce script, il y a quelques mois, j'y ai juste apporté quelques modifications qui semblaient utiles, comme l'affichage du résultat dans une page html avec des liens vers les bandes annonces, etc... Et petit à petit, j'ai réalisé que *lm* était un outil fort pratique pour garder la trace de ses films.

 

1.2 Petit tour rapide des fonctionnalités

Voici une liste des utilisations principales de *lm*:
  • lister les films d'un répertoire (recherche récursive) dans son terminal
    • filtrer par genre, acteurs, pays, taille de fichier
    • trier par nom ou par note IMDb
  • exporter ces résultat dans une page html avec:
    • les affiches des films
    • des liens vers les bandes annonces et les pages imdb
  • télécharger les sous-titres dans n'importe quelle langue (source Opensubtitles.org)

 

1.3 Les outils utilisés

*lm* utilise l'API d'Opensubtitles via le protocole XMLRPC (module python de la librairie standard: xmlrpclib) pour déterminer l'id IMDb du film à partir du hash du fichier. Si le film n'y est pas connu, *lm* pourra par la suite envoyer ces informations à Opensubtitles et ainsi participer à étoffer cette base de films.
IMDb fournit toutes les métadonnées des films. La base est interrogée grâce au module imdbpy.

 

2 Installation

 

IMDbPy (requis)

Faites un tour sur la page de téléchargement très complete. Vous y verrez sûrement que ce package est disponible sur le repo de votre distribution. Sinon, quelques installeurs (non)officiels sont disponibles pour  Mac Os X et Windows.
IMDbPY requiert le module *lxml* module pour accélérer le parsing. Si vous ne pouvez pas l'installer, assurez vous d'avoir BeautifulSoup à la place.
Note: Si vous souhaitez installer le package depuis les sources, vous pouvez vous contentez de la configuration minimale.

colorama (optionnel, pour les utilisateurs windows seulement)

*lm* est principalement déstiné à afficher ses résultats dans le terminal. Pour colorer le "terminal" windows , installez ce package.

 

3 lm en détails

Supposons l'arborescence de répertoires/fichiers suivante:

/films/
    Cinema Paradiso/
        1988.Cinema.Paradiso.mkv
    ATB/
        Attack.the.Block.avi
    dogville/
        DOGVILLE-2003.mkv
        trailer.avi

 

3.1 Options

 

Appel simple

xx@xx/films$ ./lm.py  
Attack the Block (Attack.the.Block.avi) 
Dogville (DOGVILLE-2003.mkv) 
Nuovo Cinema Paradiso (1988.Cinema.Paradiso.mkv)

Liste tous les films des répertoires et sous répertoires, triés par noms, avec un minimum d'informations affichées.

 

Description plus longue (-l)

xx@xx/films$ ./lm.py -l 
Attack the Block (2011,6.8,4475Mo) [Comedy, Horror, Sci-Fi] 
from Joe Cornish: Attack.the.Block.avi 
Dogville (2003,8.0,3640Mo) [Drama, Mystery, Thriller] from 
Lars von Trier: DOGVILLE-2003.mkv 
Nuovo Cinema Paradiso (1988,8.5,8137Mo) [Drama] from 
Giuseppe Tornatore: 1988.Cinema.Paradiso.mkv

Affiche l'année, la note, la taille du fichier, le genre du film ainsi que le réalisateur. 

 

Outline (-o)

[+/-] afficher/cacher le résultat

>xx@xx/films$ ./lm.py -o
Attack the Block (Attack.the.Block.avi) 
*** A teen gang in South London defend their block from an 
alien invasion. 
Dogville (DOGVILLE-2003.mkv) 
*** A woman on the run from the mob is reluctantly accepted in a small Colorado town. In exchange, 
she agrees to work for them. As a search visits town, she 
finds out that their support has a price. Yet her dangerous
secret is never far away... 
Nuovo Cinema Paradiso (1988.Cinema.Paradiso.mkv) 
*** A filmmaker recalls his childhood, when he fell in love 
with the movies at his village’s theater and formed a deep 
friendship with the theater’s projectionist.

 

La plus longue description (-L)

xx@xx/films$ ./lm.py -L
Essayez! Les acteurs, ainsi qu'un résumé détaillé sont affichés.

 

Afficher les résultats dans une page html (-S)

xx@xx/films$ ./lm.py -S
Attack the Block
Comedy, Horror
note: 6.8, votes: 26.0K
size: 4475Mo

ATB-ATTACK-THE-BLOCK
Dogville
Drama, Mystery
note: 8.0, votes: 59.0K
size: 3640Mo

DOGVILLE-2003.mkv
Nuovo Cinema Paradiso
Drama
note: 8.5, votes: 62.0K
size: 8137Mo

1988.Cinema.Paradiso.mkv


Cette vue à des liens vers les bandes annonces (cliquez sur l'affiche) et les pages imdb (cliquez sur les titres des films).

 

Ouvrir la page imdb (-s)



Ouvre directement les pages IMDb des films sélectionnés. Soyez prudents, et n'utilisez pas ce paramètre si trop d'éléments risquent d'être affichés.

 

Filtrer les films (-f @xx:yy)

Syntaxe: “@keyword:filter,filter,filter@keyword2:filter,filter” (n'est pas sensible à la casse).
xx@xx/films$ ./lm.py -f @genre:drama
...
xx@xx/films$ ./lm.py -f @genre:drama@size:+2000
...
Vous pouvez filtrer par genre, acteurs, parys, taille de fichier (ex: @size:+900 ou @size:-400), mais aussi par pertinence de la reconnaissance du titre (@unsure). Lisez la partie suivante sur les couleurs utilisées pour en savoir plus sur les erreurs d'identification.

 

3.2 Interprétation des couleurs affichées

Quand les films s'affichent dans le terminal, les titres peuvent prendre plusieurs couleurs.

 

MAGENTA

Le top! Le hash du film a été trouvé dans la base Opensubtitles. 95% de chances de pointer le bon titre.

 

ORANGE

Pas si mal. *lm* n'a pas trouvé le hash du fichier, mais la recherche directe sur IMDb a donné un bon résultat, *lm* est assez confiant. 80% de chance d'afficher le bon titre.

 

ORANGE avec des symboles /|\ :

Aïe! Le hash n'a rien donné sur Opensubtitles, et la recherche directe par IMDb n'a pas donné de résultat satisfaisant non plus. Il y a des chances que le titre indiqué ne soit pas bon. Il est conseillé de lancer une confirmation manuelle de l'ensemble de ces titres avec la commande "lm.py YOUR_DIR -f @unsure --confirm".

 

3.3 Actions

 

Télécharger les sous-titres (--donwload language)

xx@xx/films$ ./lm.py --download eng
Recherche les sous-titres sur la base Opensubtitles. Par ordre de préférence seront téléchargés, les sous-titres pointant vers les hashs exacts des fichiers détenus, puis les sous-titres les plus téléchargés parmi ceux associés aux bons id IMDb. Les sous-titres sont téléchargés dans les répertoires de chaque film avec la syntaxe “MOVIEFILENAME_ENG_LM1.srt” (replacer ENG par la langue choisie). Au plus 3 sous-titres seront téléchargés par film.
limite: Opensubtitles limite à 200 téléchargements par jour. Merci de prendre cette limite en considération et d'éviter de saturer leur serveur!
langue: Fournir un code ISO639 comme décrit ICI. eng/fre/ger en sont des exemples.
503 Service Unavailable: Il arrive parfois que le serveur Opensubtitles soit saturé. Ré-essayez quelques minutes/heures plus tard.

 

Recherche/confirmation manuelle (--confirm)

Cette commande lance une procédure qui vous accompagne dans la recherche ou confirmation des films sélectionnés. Si le titre associé ne vous correspond pas, vous pourrez fournir des information supplémentaires pour l'identifier (titre, année, IMDb id).
[+/-] afficher/cacher cette procédure

>xx@xx/films$ ./lm.py--confirm

*************** File to confirm *************** 
absolute path : ~/films/dogville/DOGVILLE-2003.mkv 
basename : DOGVILLE-2003.mkv

Dogville (2003,8.0,3640Mo) [Drama, Mystery, Thriller] 
from Lars von Trier: DOGVILLE-2003.mkv 

Do you confirm stored info? (y/n):n 
Will you provide an IMDb id? (y/n):n 
please enter movie title: dogville 
please enter year, leave blank if unknown: 2003 

ratio <0.7 & year, we retry on base results 
ratio ==> dogville (for [dogville]) 1.000000 
--> movie found title: Dogville 
--> movie found year: 2003 
Confirm this result? (y/n):y 
movie saved

 

Uploader la paire (hash, id) à Opensubtitles (--upload)

Sélectionne les films dont les hashs n'ont pas été trouvés sur Opensubtitles pour lesquels la recherche sur IMDb à fourni de bons résultats, et envoie la correspondance hash -> imdb_id à la base Opensubtitles. Une confirmation vous sera demandée avant tout effet.

 

Supprimer des fichiers du cache (-d)

Supprime du cache les fichiers sélectionnés. Une confirmation vous sera demandée avant tout effet. Pour supprimer tous les fichiers du cache "./lm.py cache -d"

 

Remettre le cache à zéro (--reset)

Supprime directement tous les fichiers de cache stockés dans le répertoire ~/.lm.  Une confirmation vous sera demandée avant tout effet.

 

Divers

 

Les appels à IMDb sont longs

Conseil: quand *lm* est appelé sur des fichiers qu'il ne connaît pas, il requête IMDb pour tous les fichiers inconnus, et c'est ... lent. Pour tester le script, assurez vous de pointer un répertoire ne contenant que quelques films.

 

Fichiers cachés

Tout est stocké dans le répertoire ~/.lm/.

 

Recherche de l'id IMDb

Voici les principales étapes:
  1. Construire le hash du film 
  2. Questionner Opensubtitles via leur api XMLRPC.
  3. Reconnaît-il ce hash? Si oui => parfait, travail terminé, exit!
  4. Sinon, on essaye de deviner le titre et l'année de sortie du film à partir du nom du fichier (mots interdit, regexp, ...)
  5. On questionne IMDb pour le titre deviné. On récupère les résultats
  6. Si nous pensions avoir détecter une année de sortie, les résultats sont filtrés pour ne conserver que les films de l'année en question.
  7. Recherche de la meilleure correspondance entre les titres (devinés et résultats), sur les titres du films dans tous les pays disponibles
  8. Si le meilleur résultat n'est pas satisfaisant, et si nous avions deviné une année à l'étape 6, on repasse à 7 avec les résultats initiaux (non filtrés) d'IMDb.

12 commentaires:

  1. Un grand merci de la part d'un futur utilisateur :)

    hybris

    RépondreSupprimer
  2. Super idée !
    Malheureusement je viens de tester et j'obtiens :
    {'url': 'http://akas.imdb.com/find?s=tt;mx=20;q=asterix+et+cleopatre', 'error type': 'http_error_default', 'errcode': 403, 'headers': , 'proxy': '', 'errmsg': 'Forbidden'}
    IMDb filtrerait-il selon le user-agent ? La même url depuis FF fonctionne bien...

    RépondreSupprimer
    Réponses
    1. Etait-ce le seul fichier du répertoire? Ou bien cette erreur survient-elle après au milieu de nombreuses recherches?

      Supprimer
    2. Il y avait 6 fichiers, et celà survient dès le 1er. Il me met le titrre suivi de [1/6] puis ce message.

      Supprimer
    3. Eventuellement teste un appel direct à l'API IMDb.

      >> import imdb
      >> i = imdb.IMDb()
      >> i.search_movie("asterix et cleopatre")
      []

      Supprimer
    4. même résultat, voici la stack

      >>> import imdb
      >>> i = imdb.IMDb()
      >>> i.search_movie("asterix et cleopatre")
      Traceback (most recent call last):
      File "", line 1, in
      File "/usr/lib/python2.7/site-packages/imdb/__init__.py", line 360, in search_movie
      res = self._search_movie(title, results)
      File "/usr/lib/python2.7/site-packages/imdb/parser/http/__init__.py", line 416, in _search_movie
      cont = self._get_search_content('tt', title, results)
      File "/usr/lib/python2.7/site-packages/imdb/parser/http/__init__.py", line 399, in _get_search_content
      cont = self._retrieve(imdbURL_find % params)
      File "/usr/lib/python2.7/site-packages/imdb/parser/http/__init__.py", line 385, in _retrieve
      return self.urlOpener.retrieve_unicode(url, size=size)
      File "/usr/lib/python2.7/site-packages/imdb/parser/http/__init__.py", line 165, in retrieve_unicode
      uopener = self.open(url)
      File "/usr/lib/python2.7/urllib.py", line 205, in open
      return getattr(self, name)(url)
      File "/usr/lib/python2.7/urllib.py", line 356, in open_http
      return self.http_error(url, fp, errcode, errmsg, headers)
      File "/usr/lib/python2.7/urllib.py", line 373, in http_error
      return self.http_error_default(url, fp, errcode, errmsg, headers)
      File "/usr/lib/python2.7/site-packages/imdb/parser/http/__init__.py", line 214, in http_error_default
      'proxy': self.get_proxy()}
      imdb._exceptions.IMDbDataAccessError: {'url': 'http://akas.imdb.com/find?s=tt;mx=20;q=asterix+et+cleopatre', 'error type': 'http_error_default', 'errcode': 403, 'headers': , 'proxy': '', 'errmsg': 'Forbidden'}

      Supprimer
    5. by the way... en testant les examples donnés dans les readme de python-imdb :
      $ search_movie.py "the passion"
      Probably you're not connected to Internet. Complete error report:
      {'url': 'http://akas.imdb.com/find?s=tt;mx=20;q=the+passion', 'error type': 'http_error_default', 'errcode': 403, 'headers': , 'proxy': '', 'errmsg': 'Forbidden'}
      $ get_movie.py 0133093
      Probably you're not connected to Internet. Complete error report:
      {'url': 'http://akas.imdb.com/title/tt0133093/combined', 'error type': 'http_error_default', 'errcode': 403, 'headers': , 'proxy': '', 'errmsg': 'Forbidden'}
      donc le pbm ne vient pas de lm...
      (bien sûr je suis connecté à Internet, pas de proxy, rien de spécial)

      Supprimer
    6. 1/ Quelle version d'IMDbpy utilises tu?
      2/ Arrives tu à charger la page d'accueil de google?
      >> import urllib
      >> uo = urllib.FancyURLopener()
      >> url = uo.open('http://www.google.com')
      >> url.read()
      3/ D'autres ont signalé ce genre de soucis, http://groups.google.com/group/imdbpy-users/browse_thread/thread/df785dc52ccdd3c5, qui auraient du être reglés après la version 4.5

      Supprimer
    7. 1/ 3.9
      2/ oui, je récupère bien la page
      3/ ceci explique celà ;)
      ps : Mandriva 2011 (ils ne sont pas très à jour sur python on dirait)

      Supprimer
    8. pps : merci pour le support :)

      Supprimer
    9. Bonjour!

      Voilà le truc à faire pour régler rapidement le problème… et savoir quoi faire au prochain ;-)

      Trouver où est installé imdbpy; chez moi par exemple:
      /usr/lib/python2.7/dist-packages/imdb

      Dedans, le fichier dans lequel l'adresse de la recherche sur IMDB est écrite:
      parser/http/__init__.py

      Il faut changer l'ordre de la requête pour mettre le "s=" en dernier. Trouver la ligne:
      params = 's=%s;mx=%s;q=%s'

      Et changer en:
      params = 'mx=%s;q=%s;s=%s'

      Héhé…

      Supprimer
  3. Nice post thank you Rodney

    RépondreSupprimer