]> gitweb.pimeys.fr Git - scripts-20-100.git/blob - rename_series.py
4bc4c81769f131f5309124d85a42f0078bb3eb89
[scripts-20-100.git] / rename_series.py
1 #!/usr/bin/env python
2 # -*- encoding: utf-8 -*-
3
4 """ Pour renommer en masse les épisodes d'une série à partir d'un fichier
5 de titres. """
6
7 import re
8 import os
9 import os.path
10 import argparse
11 import pprint
12
13 FORMAT = "%%(series_name)s - [%%(season)0%(logmaxseason)sdx%%(episode)0%(logmaxepisode)sd] - %%(title)s.%%(extension)s"
14
15 SEASONEPISODE_REGEXP = ur"^(?P<series_name>([A-Za-z0-9_-]+(\.| ))+)(S|- \[)(?P<season>\d+)(E|x)(?P<episode>\d+).*\.(?P<extension>[a-z0-9]*)$"
16 sep_re = re.compile(SEASONEPISODE_REGEXP)
17
18 def get_titles(filename, debug=False, oneintwo=False):
19 """Récupère les titres des épisodes dans le fichier"""
20 text = open(filename).read()
21 if oneintwo:
22 # On enlève une ligne sur deux
23 text = re.sub("(.*\n).*\n", r'\1', text)
24 titles = re.findall('^[0-9\s]+"(.*?)"', text, flags=re.MULTILINE)
25 if debug:
26 print "Titres :"
27 pprint.pprint(titles)
28 return titles
29
30 def proper_name(name):
31 """Proprifie le nom de la série."""
32 return name.replace(".", " ").strip()
33
34 def get_files(titlesfilename, debug=False):
35 """Récupère les fichiers locaux, en enlevant le fichier de titres.
36 Les analyse à coup de regexp et les renvoie dans un dico. Clé = n° de l'épisode."""
37 files = os.listdir(".")
38 if titlesfilename in files:
39 files.remove(titlesfilename)
40 dir = {}
41 for filename in files:
42 o = sep_re.match(filename)
43 if o:
44 d = o.groupdict()
45 d["episode"] = int(d["episode"])
46 d["season"] = int(d["season"])
47 if dir.has_key(d["episode"]):
48 raise ValueError("Épisode %s trouvé deux fois." % d["episode"])
49
50 dir[d["episode"]] = (filename, d)
51 else:
52 raise ValueError("Unparsable file : %s" % filename)
53 if debug:
54 print "Fichiers :"
55 pprint.pprint(dir)
56 return dir
57
58 def process(dir, titles, maxseason, seriesname, args):
59 """Prépare tous les renommages.
60 Renvoie une map before -> after."""
61 series_names = set([proper_name(d["series_name"]) for (_, d) in dir.values()])
62 if seriesname:
63 series_name = seriesname
64 elif len(series_names) > 1:
65 print "Plusieurs titres trouvés :"
66 print list(series_names)
67 series_name = raw_input("Spécifier titre : ")
68 else:
69 series_name = list(series_names)[0]
70 l = range(1, len(dir) + 1)
71 eps = dir.keys()
72 eps.sort()
73 if eps != l:
74 raise ValueError("Il manque des épisodes : %s" % eps)
75 if len(titles) != len(eps):
76 print "Pas autant de titres que d'épisodes : on retente en lisant une ligne sur deux."
77 titles = get_titles(args.titles, oneintwo=True)
78 if len(titles) != len(eps):
79 raise ValueError("Pas autant de titres que d'épisodes !")
80 formatdir = {
81 "logmaxseason" : len(str(maxseason)),
82 "logmaxepisode" : len(str(max(eps))),
83 "series_name" : series_name
84 }
85 map = []
86 for k in eps:
87 (before, d) = dir[k]
88 d.update(formatdir)
89 d["title"] = titles[k-1]
90 newname = FORMAT % d
91 newname = newname % d
92 map.append((before, newname))
93 return map
94
95 def confirm(map):
96 """Affiche ce qui va être fait et demande confirmation."""
97 size = max([len(b) for (b, a) in map])
98 for (b, a) in map:
99 print "%s%s %s" % (b, " " * (size - len(b)), a)
100 ans = raw_input("Renommer ?")
101 return ans.lower() in ["y", "o", "yes", "oui"]
102
103
104 def do(map):
105 """Fait le renommage."""
106 for (before, after) in map:
107 os.rename(before, after)
108
109 if __name__ == "__main__":
110 parser = argparse.ArgumentParser(description="Renommage en batch d'épisodes de série.")
111 parser.add_argument('-v', '--verbose', help="Afficher du debug", action="store_true")
112 parser.add_argument('-q', '--quiet', help="Ne pas afficher les warnings", action="store_true")
113 parser.add_argument('-t', '--titles', help="Fichier contenant les titres des épisodes", action="store", type=str, default="titles")
114 parser.add_argument('-m', '--maxseason', help="Nombre total de saisons (pour le nombre de 0)", action="store", type=str, default=1)
115 parser.add_argument('-s', '--seriesname', help="Override le nom de la série", action="store", type=str)
116
117 args = parser.parse_args()
118
119 titles = get_titles(args.titles, args.verbose)
120 files = get_files(args.titles, args.verbose)
121 map = process(files, titles, args.maxseason, args.seriesname, args)
122 if confirm(map):
123 do(map)