renamer.py 7.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206
  1. #!/usr/bin/env python3
  2. # coding: utf-8
  3. """
  4. Created on Wed Jul 13 10:52:12 2024
  5. @author: ajco7475
  6. """
  7. import sys
  8. import os
  9. import re
  10. import getopt
  11. from colorama import init, Fore, Style
  12. import random
  13. import logging
  14. import platform
  15. logger = logging.getLogger("RENAMER")
  16. logging.basicConfig()
  17. init(autoreset=True)
  18. def color_text(text, color):
  19. return f"{color}{text}{Fore.RESET}"
  20. # =============================================================================
  21. # usage
  22. #
  23. # - afficher le message d'aide
  24. # =============================================================================
  25. def set_log_level(log_level):
  26. if log_level == "CRITICAL":
  27. logger.setLevel(logging.CRITICAL)
  28. elif log_level == "ERROR":
  29. logger.setLevel(logging.ERROR)
  30. elif log_level == "WARNING":
  31. logger.setLevel(logging.WARNING)
  32. elif log_level == "INFO":
  33. logger.setLevel(logging.INFO)
  34. else:
  35. if log_level is None:
  36. print("INFO: log level is set to 'DEBUG' by default")
  37. elif log_level != "DEBUG":
  38. print(
  39. "INFO: specified log_level value ({}) is incorrect, use CRITICAL, ERROR, WARNING, INFO or DEBUG. log "
  40. "level is set to 'DEBUG' by default".format(log_level))
  41. logger.setLevel(logging.DEBUG)
  42. # =============================================================================
  43. # clean_file_name
  44. #
  45. # - afficher le message d'aide
  46. # =============================================================================
  47. def clean_file_name(old_filename):
  48. new_filename = None
  49. parts = old_filename.rsplit('.', 1) # Divise à partir du dernier point
  50. if len(parts) == 2:
  51. # Remplace tous les points dans la première partie
  52. parts[0] = re.sub(r'\.', ' ', parts[0])
  53. new_filename = parts[0] + '.' + parts[1]
  54. else:
  55. # S'il n'y a pas de point, ou juste un à la fin, retourne la chaîne inchangée
  56. new_filename = old_filename
  57. # remplacement de DVDRip et marques suivantes
  58. new_filename = re.sub(r'(.*)\s+DVDRip\b.*\.(\w+)$', r'\1.\2', new_filename)
  59. # nettoyage de 1080p ... et 720p ...
  60. new_filename = re.sub(r'(.*)(\d\d\d+p).*\.(\w+)$', r'\1\2.\3', new_filename)
  61. # ntettoyage de x264 ... x265 ...
  62. new_filename = re.sub(r'(.*)(\s+x26\d).*\.(\w+)$', r'\1.\3', new_filename)
  63. # ntettoyage de ... - ...
  64. new_filename = re.sub(r'\s+-\s+', ' ', new_filename)
  65. # mise en parenthéses de l'année
  66. new_filename = re.sub(r'\b(\d\d\d\d)\b', r'(\1)', new_filename)
  67. # suppression des blancs au debut
  68. new_filename = re.sub(r'^\s+', '', new_filename)
  69. # suppression des blancs à la fin
  70. new_filename = re.sub(r'\s+$', '', new_filename)
  71. # remplacement d'un planc par un seul underscore
  72. new_filename = re.sub(r'\s+', '_', new_filename)
  73. # remplacement de plusieures parentheses ouvrantes
  74. new_filename = re.sub(r'\(\(+', '(', new_filename)
  75. # remplacement de plusieures parentheses fermantes
  76. new_filename = re.sub(r'\)\)+', ')', new_filename)
  77. logger.debug(f"old_filename=<{old_filename}> new_filename=<{new_filename}>")
  78. return new_filename
  79. # =============================================================================
  80. # rename_files_in_directory
  81. #
  82. # - afficher le message d'aide
  83. # =============================================================================
  84. def rename_files_in_directory(
  85. directory_path,
  86. pattern=None,
  87. new_prefix=None,
  88. no_underscore=False,
  89. test=False):
  90. """
  91. Renomme les fichiers dans le répertoire spécifié selon un certain motif.
  92. :param directory_path: Chemin du répertoire à parcourir.
  93. :param pattern: Motif regex pour correspondre les noms de fichiers actuels.
  94. :param new_pattern: Motif pour renommer les fichiers.
  95. """
  96. # Vérifier si le répertoire existe
  97. if not os.path.isdir(directory_path):
  98. print(f"Le répertoire {directory_path} n'existe pas.")
  99. return
  100. if pattern is None:
  101. pattern = r".*"
  102. logger.debug(f"pattern=<{pattern}> new_prefix=<{new_prefix}> no_underscore=<{no_underscore}>")
  103. # Parcourir tous les fichiers dans le répertoire
  104. for filename in os.listdir(directory_path):
  105. # Chemin complet du fichier
  106. file_path = os.path.join(directory_path, filename)
  107. # Vérifier si c'est un fichier
  108. if os.path.isfile(file_path):
  109. logger.debug(f"file_path=<{file_path}>")
  110. # Utiliser l'expression régulière pour correspondre le nom de fichier
  111. match = re.match(pattern, filename)
  112. if match:
  113. # Construire le nouveau nom de fichier
  114. new_filename = clean_file_name(filename)
  115. if new_prefix is not None:
  116. pattern = re.compile(r'(?i)^(.*?)(S(\d+)E(\d+))')
  117. match = re.search(pattern, new_filename)
  118. logger.debug(f"<<{match.group()}>> {match.lastindex} ---> {new_prefix}")
  119. saison = "{:02}".format(int(match.group(3)))
  120. episode = "{:02}".format(int(match.group(4)))
  121. logger.debug(
  122. "saison : " + color_text(saison, Fore.BLUE) + " episode : " + color_text(episode, Fore.RED))
  123. new_filename = pattern.sub(f'{new_prefix}_S{saison}E{episode}', new_filename)
  124. # si demandé enlever les underscores
  125. if no_underscore:
  126. new_filename = new_filename.replace('_',' ')
  127. # Renommer le fichier
  128. new_file_path = os.path.join(directory_path, new_filename)
  129. if not test:
  130. os.rename(file_path, new_file_path)
  131. print("<<< " + color_text(file_path, Fore.BLUE) + "\n>>> " + color_text(new_file_path, Fore.RED))
  132. # =============================================================================
  133. # usage
  134. #
  135. # - afficher le message d'aide
  136. # =============================================================================
  137. def usage():
  138. script_name = os.path.basename(__file__)
  139. print(f"{script_name} : () facultative item, <> : mandatory item\n"
  140. " (--prefix=<prefix string>) : prefixe a placer devant SxxExx\n"
  141. " (--rd=<prefix string>) : repertoire à parcourir\n"
  142. " (--nu) : supprimer le 'underscore' du nom final du fichier cible\n"
  143. " (--test) : afficher les transformations sans effectuer le rennomage\n"
  144. " (--ll=<log level:CRITICAL|ERROR|WARNING|INFO|DEBUG>)\n"
  145. " (-h) : this help\n")
  146. # =============================================================================
  147. # MAIN
  148. # =============================================================================
  149. if __name__ == '__main__':
  150. # nouveau prefix
  151. prefix = None
  152. # niveau de logs par défaut
  153. ll = 'INFO'
  154. # repertoire à addresser
  155. ren_dir = None
  156. # supprimer le 'underscore' du nom final du fichier cible
  157. no_underscore = False
  158. # afficher les transformations sans effectuer le rennomage
  159. do_test = False
  160. try:
  161. opts, args = getopt.getopt(sys.argv[1:], "h",
  162. ["prefix=", "rd=", "nu", "test", "ll="])
  163. except getopt.GetoptError as err:
  164. logger.error(err)
  165. usage()
  166. sys.exit(2)
  167. for opt, arg in opts:
  168. if opt == '-h':
  169. usage()
  170. sys.exit()
  171. elif opt in "--prefix":
  172. prefix = arg
  173. elif opt in "--rd":
  174. ren_dir = arg
  175. elif opt in "--nu":
  176. no_underscore = True
  177. elif opt in "--test":
  178. do_test = True
  179. elif opt in "--ll":
  180. if arg in ["CRITICAL", "ERROR", "WARNING", "INFO", "DEBUG"]:
  181. ll = arg
  182. # log level
  183. set_log_level(ll)
  184. if ren_dir is None:
  185. ren_dir = os.getcwd()
  186. rename_files_in_directory(ren_dir, new_prefix=prefix, no_underscore=no_underscore,test=do_test)