├── .gitignore ├── rename_episodes.cmd ├── rename_episodes.sh ├── run_after_done.cmd ├── README.md └── reg_match.py /.gitignore: -------------------------------------------------------------------------------- 1 | /backup/ 2 | *log.txt -------------------------------------------------------------------------------- /rename_episodes.cmd: -------------------------------------------------------------------------------- 1 | for %%i in (%*) do python C:\Users\miracleyoo\Documents\Program\utorrent\reg_match.py --path=%%i -------------------------------------------------------------------------------- /rename_episodes.sh: -------------------------------------------------------------------------------- 1 | for path in "$@" 2 | do 3 | python //anime_renamer-master/reg_match.py --path="$path"; 4 | done -------------------------------------------------------------------------------- /run_after_done.cmd: -------------------------------------------------------------------------------- 1 | set file_name=%1% 2 | set directory=%2% 3 | 4 | python C:\Users\miracleyoo\Documents\Program\utorrent\reg_match.py --name=%file_name% --root=%directory% 5 | 6 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Anime Renamer 2 | 3 | 本项目用于与utorrent联动,在下载动漫剧集后自动正则匹配并重命名为串流软件(如Plex)支持的格式。 4 | 5 | ## 使用方法: 6 | 7 | 1. 与utorrent联动,在`高级-运行程序`中使用命令 `\run_after_done.cmd "%F" "%D"` 实现自动重命名。 8 | 2. **For Windows:** 直接将整个存放动漫的根文件夹拖放到`rename_episodes.cmd`文件上即可。该文件会调用前面提到的Python脚本,并对整个文件夹中的所有有问题的文件名进行重命名。你也可以将有问题的子目录或特定文件拖放上去,或是同时拖放多个文件/文件夹。Python脚本中有着相应的适配。 9 | 3. **For Mac/Linux:** 使用`rename_episodes.sh`,最好将其添加到你的`~/.zshrc`或`~/.bashrc`中,作为一个函数。如`rename-e`,之后只需要在terminal中输入 `rename-e ` 即可。 -------------------------------------------------------------------------------- /reg_match.py: -------------------------------------------------------------------------------- 1 | import re 2 | import os 3 | import io 4 | import sys 5 | import os.path as op 6 | import argparse 7 | import codecs 8 | from glob import glob 9 | from pathlib2 import Path 10 | 11 | log_name=op.join(op.dirname(op.realpath(__file__)), 'log.txt') 12 | 13 | # Episode Regular Expression Matching Rules 14 | episode_rules = [r'(.*)\[(\d{1,3}|\d{1,3}\.\d{1,2})(?:v\d{1,2})?(?:END)?\](.*)', 15 | r'(.*)\[E(\d{1,3}|\d{1,3}\.\d{1,2})(?:v\d{1,2})?(?:END)?\](.*)', 16 | r'(.*)\[第(\d*\.*\d*)话(?:END)?\](.*)', 17 | r'(.*)\[第(\d*\.*\d*)話(?:END)?\](.*)', 18 | r'(.*)第(\d*\.*\d*)话(?:END)?(.*)', 19 | r'(.*)第(\d*\.*\d*)話(?:END)?(.*)', 20 | r'(.*)- (\d{1,3}|\d{1,3}\.\d{1,2})(?:v\d{1,2})?(?:END)? (.*)'] 21 | # Suffixs of files we are going to rename 22 | suffixs = ['mp4', 'mkv', 'avi', 'mov', 'flv', 'rmvb', 'ass', 'idx'] 23 | sys.stdout = io.TextIOWrapper(buffer=sys.stdout.buffer,encoding='utf8') 24 | 25 | # Parse the input arguments. You can whether input only root, or only path, or both root and name. 26 | parser = argparse.ArgumentParser(description='Regular Expression Match') 27 | parser.add_argument('--root', default='', 28 | help='The root directory of the input file.') 29 | parser.add_argument('--name', default='', 30 | help='The file name of the input file.') 31 | parser.add_argument('--path', default='', 32 | help='The file full path of the input file.') 33 | 34 | 35 | def rename(root, name): 36 | root = Path(root) 37 | 38 | for rule in episode_rules: 39 | matchObj = re.match(rule, name, re.I) 40 | if matchObj is not None: 41 | new_name = f'{matchObj.group(1)} E{matchObj.group(2)} {matchObj.group(3)}' 42 | # print(matchObj.group()) 43 | # print(new_name) 44 | print(f'{name} -> {new_name}') 45 | with codecs.open(log_name, 'a+', 'utf-8') as f: 46 | # f.writelines(f'{name} -> {new_name}') 47 | print(f'{name} -> {new_name}', file=f) 48 | 49 | os.rename(str(root/name), str(root/new_name)) 50 | general_check(root, new_name) 51 | return 52 | general_check(root, name) 53 | 54 | 55 | def general_check(root, name): 56 | new_name = ' '.join(name.split()) 57 | if new_name != name: 58 | print(f'{name} -> {new_name}') 59 | with codecs.open(log_name, 'a+', 'utf-8') as f: 60 | print(f'{name} -> {new_name}', file=f) 61 | os.rename(str(root/name), str(root/new_name)) 62 | 63 | 64 | if __name__ == "__main__": 65 | args = parser.parse_args() 66 | if op.isdir(args.path): 67 | args.root = args.path 68 | args.path = '' 69 | 70 | if args.name != '' and args.root != '': 71 | temp = str(args.root/args.name) 72 | if op.isdir(temp): 73 | args.root = temp 74 | args.name = '' 75 | 76 | if args.path != '': 77 | root, name = op.split(args.path) 78 | rename(root, name) 79 | elif args.name != '' and args.root != '': 80 | rename(args.root, args.name) 81 | elif args.root != '': 82 | files = [] 83 | for suffix in suffixs: 84 | files.extend(Path(args.root).rglob('*.'+suffix)) 85 | files.extend(Path(args.root).rglob('*.'+suffix.upper())) 86 | print(f'Total Files Number: {len(files)}') 87 | for path in files: 88 | root, name = op.split(path) 89 | rename(root, name) 90 | else: 91 | print('Please input whether only root, or only path, or both root and name') 92 | # os.system('PAUSE') 93 | # for rule in episode_rules: 94 | # matchObj = re.match(rule, name, re.I) 95 | # if matchObj is not None: 96 | # new_name = f'{matchObj.group(1)} E{matchObj.group(2)} {matchObj.group(3)}' 97 | # # print(matchObj.group()) 98 | # # print(new_name) 99 | # print(f'{name} -> {new_name}') 100 | # with open(r'C:\Users\miracleyoo\Documents\Program\utorrent\log.txt', 'a+') as f: 101 | # print(f'{name} -> {new_name}', file=f) 102 | 103 | # os.rename(str(root/name), str(root/new_name)) 104 | # break 105 | --------------------------------------------------------------------------------