From: Vincent Le Gallic Date: Thu, 11 Jun 2015 02:16:37 +0000 (+0200) Subject: Script pour batch-rename des épisodes de séries selon mon format de noms préféré X-Git-Url: http://gitweb.pimeys.fr/?p=scripts-20-100.git;a=commitdiff_plain;h=d706a2361f5ddebb688e73abc6c65cd2fcfe882c Script pour batch-rename des épisodes de séries selon mon format de noms préféré --- diff --git a/rename_series.py b/rename_series.py new file mode 100755 index 0000000..dd4e0fe --- /dev/null +++ b/rename_series.py @@ -0,0 +1,123 @@ +#!/usr/bin/env python +# -*- encoding: utf-8 -*- + +""" Pour renommer en masse les épisodes d'une série à partir d'un fichier + de titres. """ + +import re +import os +import os.path +import argparse +import pprint + +FORMAT = "%%(series_name)s - [%%(season)0%(logmaxseason)sdx%%(episode)0%(logmaxepisode)sd] - %%(title)s.%%(extension)s" + +SEASONEPISODE_REGEXP = ur"^(?P([A-Za-z0-9_-]+(\.| ))+)(S|\[)(?P\d+)(E|x)(?P\d+).*\.(?P[a-z0-9]*)$" +sep_re = re.compile(SEASONEPISODE_REGEXP) + +def get_titles(filename, debug=False, oneintwo=False): + """Récupère les titres des épisodes dans le fichier""" + text = open(filename).read() + if oneintwo: + # On enlève une ligne sur deux + text = re.sub("(.*\n).*\n", r'\1', text) + titles = re.findall('"(.*)"', text) + if debug: + print "Titres :" + pprint.pprint(titles) + return titles + +def proper_name(name): + """Proprifie le nom de la série.""" + return name.replace(".", " ").strip() + +def get_files(titlesfilename, debug=False): + """Récupère les fichiers locaux, en enlevant le fichier de titres. + Les analyse à coup de regexp et les renvoie dans un dico. Clé = n° de l'épisode.""" + files = os.listdir(".") + if titlesfilename in files: + files.remove(titlesfilename) + dir = {} + for filename in files: + o = sep_re.match(filename) + if o: + d = o.groupdict() + d["episode"] = int(d["episode"]) + d["season"] = int(d["season"]) + if dir.has_key(d["episode"]): + raise ValueError("Épisode %s trouvé deux fois." % d["episode"]) + + dir[d["episode"]] = (filename, d) + else: + raise ValueError("Unparsable file : %s" % filename) + if debug: + print "Fichiers :" + pprint.pprint(dir) + return dir + +def process(dir, titles, maxseason, seriesname, args): + """Prépare tous les renommages. + Renvoie une map before -> after.""" + series_names = set([proper_name(d["series_name"]) for (_, d) in dir.values()]) + if seriesname: + series_name = seriesname + elif len(series_names) > 1: + print "Plusieurs titres trouvés :" + print list(series_names) + series_name = raw_input("Spécifier titre : ") + else: + series_name = list(series_names)[0] + l = range(1, len(dir) + 1) + eps = dir.keys() + eps.sort() + if eps != l: + raise ValueError("Il manque des épisodes : %s" % eps) + if len(titles) != len(eps): + print "Pas autant de titres que d'épisodes : on retente en lisant une ligne sur deux." + titles = get_titles(args.titles, oneintwo=True) + if len(titles) != len(eps): + raise ValueError("Pas autant de titres que d'épisodes !") + formatdir = { + "logmaxseason" : len(str(maxseason)), + "logmaxepisode" : len(str(max(eps))), + "series_name" : series_name + } + map = [] + for k in eps: + (before, d) = dir[k] + d.update(formatdir) + d["title"] = titles[k-1] + newname = FORMAT % d + newname = newname % d + map.append((before, newname)) + return map + +def confirm(map): + """Affiche ce qui va être fait et demande confirmation.""" + size = max([len(b) for (b, a) in map]) + for (b, a) in map: + print "%s%s → %s" % (b, " " * (size - len(b)), a) + ans = raw_input("Renommer ?") + return ans.lower() in ["y", "o", "yes", "oui"] + + +def do(map): + """Fait le renommage.""" + for (before, after) in map: + os.rename(before, after) + +if __name__ == "__main__": + parser = argparse.ArgumentParser(description="Renommage en batch d'épisodes de série.") + parser.add_argument('-v', '--verbose', help="Afficher du debug", action="store_true") + parser.add_argument('-q', '--quiet', help="Ne pas afficher les warnings", action="store_true") + parser.add_argument('-t', '--titles', help="Fichier contenant les titres des épisodes", action="store", type=str, default="titles") + parser.add_argument('-m', '--maxseason', help="Nombre total de saisons (pour le nombre de 0)", action="store", type=str, default=1) + parser.add_argument('-s', '--seriesname', help="Override le nom de la série", action="store", type=str) + + args = parser.parse_args() + + titles = get_titles(args.titles, args.verbose) + files = get_files(args.titles, args.verbose) + map = process(files, titles, args.maxseason, args.seriesname, args) + if confirm(map): + do(map)