diff --git a/Movie_Data_Capture.py b/Movie_Data_Capture.py index f15e746..2298bd0 100644 --- a/Movie_Data_Capture.py +++ b/Movie_Data_Capture.py @@ -49,6 +49,8 @@ def argparse_function(ver: str) -> typing.Tuple[str, str, str, str, bool]: help="Main mode. 1:Scraping 2:Organizing 3:Scraping in analysis folder") parser.add_argument("-n", "--number", default='', nargs='?', help="Custom file number of single movie file.") # parser.add_argument("-C", "--config", default='config.ini', nargs='?', help="The config file Path.") + parser.add_argument("-L", "--link-mode", default='', nargs='?', + help="Create movie file link. 0:moving movie file, do not create link 1:soft link 2:try hard link first") default_logdir = str(Path.home() / '.mlogs') parser.add_argument("-o", "--log-dir", dest='logdir', default=default_logdir, nargs='?', help=f"""Duplicate stdout and stderr to logfiles in logging folder, default on. @@ -83,6 +85,7 @@ is performed. It may help you correct wrong numbers before real job.""") return True if isinstance(value, bool) and value else None config.G_conf_override["common:main_mode"] = get_natural_number_or_none(args.main_mode) + config.G_conf_override["common:link_mode"] = get_natural_number_or_none(args.link_mode) config.G_conf_override["common:source_folder"] = get_str_or_none(args.path) config.G_conf_override["common:auto_exit"] = get_bool_or_none(args.auto_exit) config.G_conf_override["common:nfo_skip_days"] = get_natural_number_or_none(args.days) @@ -288,7 +291,7 @@ def movie_lists(source_folder, regexstr: str) -> typing.List[str]: main_mode = conf.main_mode() debug = conf.debug() nfo_skip_days = conf.nfo_skip_days() - soft_link = conf.soft_link() + link_mode = conf.link_mode() file_type = conf.media_type().lower().split(",") trailerRE = re.compile(r'-trailer\.', re.IGNORECASE) cliRE = None @@ -299,7 +302,7 @@ def movie_lists(source_folder, regexstr: str) -> typing.List[str]: pass failed_list_txt_path = Path(conf.failed_folder()).resolve() / 'failed_list.txt' failed_set = set() - if (main_mode == 3 or soft_link) and not conf.ignore_failed_list(): + if (main_mode == 3 or link_mode) and not conf.ignore_failed_list(): try: flist = failed_list_txt_path.read_text(encoding='utf-8').splitlines() failed_set = set(flist) @@ -351,7 +354,7 @@ def movie_lists(source_folder, regexstr: str) -> typing.List[str]: if skip_nfo_days_cnt: print( f"[!]Skip {skip_nfo_days_cnt} movies in source folder '{source}' who's .nfo modified within {nfo_skip_days} days.") - if nfo_skip_days <= 0 or not soft_link or main_mode == 3: + if nfo_skip_days <= 0 or not link_mode or main_mode == 3: return total # 软连接方式,已经成功削刮的也需要从成功目录中检查.nfo更新天数,跳过N天内更新过的 skip_numbers = set() @@ -458,7 +461,7 @@ def create_data_and_move_with_custom_number(file_path: str, custom_number, oCC): print("[-] [{}] ERROR:".format(file_path)) print('[-]', err) - if conf.soft_link(): + if conf.link_mode(): print("[-]Link {} to failed folder".format(file_path)) os.symlink(file_path, os.path.join(conf.failed_folder(), file_name)) else: @@ -511,7 +514,7 @@ def main(): print(f"[+]Load Config file '{conf.ini_path}'.") if conf.debug(): print('[+]Enable debug') - if conf.soft_link(): + if conf.link_mode(): print('[!]Enable soft link') if len(sys.argv) > 1: print('[!]CmdLine:', " ".join(sys.argv[1:])) diff --git a/config.ini b/config.ini index 3f87668..b5de17f 100755 --- a/config.ini +++ b/config.ini @@ -5,7 +5,7 @@ main_mode=1 source_folder=./ failed_output_folder=failed success_output_folder=JAV_output -soft_link=0 +link_mode=0 ; 0: 不刮削硬链接文件 1: 刮削硬链接文件 scan_hardlink=0 failed_move=1 diff --git a/config.py b/config.py index 1197fd7..637989a 100644 --- a/config.py +++ b/config.py @@ -10,6 +10,7 @@ G_conf_override = { 0: None, # register override config items "common:main_mode": None, + "common:link_mode": None, "common:source_folder": None, "common:auto_exit": None, "common:nfo_skip_days": None, @@ -128,8 +129,8 @@ class Config: def actor_gender(self) -> str: return self.conf.get("common", "actor_gender") - def soft_link(self) -> bool: - return self.conf.getboolean("common", "soft_link") + def link_mode(self) -> bool: + return self.getint_override("common", "link_mode") def scan_hardlink(self) -> bool: return self.conf.getboolean("common", "scan_hardlink", fallback=False)#未找到配置选项,默认不刮削 @@ -361,7 +362,7 @@ class Config: conf.set(sec1, "source_folder", "./") conf.set(sec1, "failed_output_folder", "failed") conf.set(sec1, "success_output_folder", "JAV_output") - conf.set(sec1, "soft_link", "0") + conf.set(sec1, "link_mode", "0") conf.set(sec1, "scan_hardlink", "0") conf.set(sec1, "failed_move", "1") conf.set(sec1, "auto_exit", "0") diff --git a/core.py b/core.py index 15eadb4..a54968f 100644 --- a/core.py +++ b/core.py @@ -27,15 +27,15 @@ def escape_path(path, escape_literals: str): # Remove escape literals def moveFailedFolder(filepath): conf = config.getInstance() failed_folder = conf.failed_folder() - soft_link = conf.soft_link() + link_mode = conf.link_mode() # 模式3或软连接,改为维护一个失败列表,启动扫描时加载用于排除该路径,以免反复处理 # 原先的创建软连接到失败目录,并不直观,不方便找到失败文件位置,不如直接记录该文件路径 - if conf.main_mode() == 3 or soft_link: + if conf.main_mode() == 3 or link_mode: ftxt = os.path.abspath(os.path.join(failed_folder, 'failed_list.txt')) print("[-]Add to Failed List file, see '%s'" % ftxt) with open(ftxt, 'a', encoding='utf-8') as flt: flt.write(f'{filepath}\n') - elif conf.failed_move() and not soft_link: + elif conf.failed_move() and not link_mode: failed_name = os.path.join(failed_folder, os.path.basename(filepath)) mtxt = os.path.abspath(os.path.join(failed_folder, 'where_was_i_before_being_moved.txt')) print("'[-]Move to Failed output folder, see '%s'" % mtxt) @@ -472,11 +472,19 @@ def paste_file_to_folder(filepath, path, number, leak_word, c_word, hack_word): # 同名覆盖致使全部文件损失且不可追回的最坏情况 if os.path.exists(targetpath): raise FileExistsError('File Exists on destination path, we will never overwriting.') - soft_link = config.getInstance().soft_link() - # 如果soft_link=1 使用软链接 - if soft_link == 0: + link_mode = config.getInstance().link_mode() + # 如果link_mode 1: 建立软链接 2: 硬链接优先、无法建立硬链接再尝试软链接。 + # 移除原先soft_link=2的功能代码,因默认记录日志,已经可追溯文件来源 + create_softlink = False + if link_mode not in (1, 2): shutil.move(filepath, targetpath) - elif soft_link == 1: + elif link_mode == 2: + # 跨卷或跨盘符无法建立硬链接导致异常,回落到建立软链接 + try: + os.link(filepath, targetpath, follow_symlinks=False) + except: + create_softlink = True + if link_mode == 1 or create_softlink: # 先尝试采用相对路径,以便网络访问时能正确打开视频,失败则可能是因为跨盘符等原因无法支持 # 相对路径径,改用绝对路径方式尝试建立软链接 try: @@ -484,15 +492,6 @@ def paste_file_to_folder(filepath, path, number, leak_word, c_word, hack_word): os.symlink(filerelpath, targetpath) except: os.symlink(filepath_obj.resolve(), targetpath) - elif soft_link == 2: - shutil.move(filepath, targetpath) - # 移走文件后,在原来位置增加一个可追溯的软链接,指向文件新位置 - # 以便追查文件从原先位置被移动到哪里了,避免因为得到错误番号后改名移动导致的文件失踪 - # 便于手工找回文件。由于目前软链接已经不会被刮削,文件名后缀无需再修改。 - targetabspath = os.path.abspath(targetpath) - if targetabspath != os.path.abspath(filepath): - targetrelpath = os.path.relpath(targetabspath, file_parent_origin_path) - os.symlink(targetrelpath, filepath) sub_res = config.getInstance().sub_rule() for subname in sub_res: @@ -530,7 +529,7 @@ def paste_file_to_folder_mode2(filepath, path, multi_part, number, part, leak_wo if os.path.exists(targetpath): raise FileExistsError('File Exists on destination path, we will never overwriting.') try: - if config.getInstance().soft_link(): + if config.getInstance().link_mode(): os.symlink(filepath, targetpath) else: shutil.move(filepath, targetpath) @@ -686,7 +685,7 @@ def core_main(file_path, number_th, oCC): except: pass - + # 裁剪图 cutImage(imagecut, path , fanart_path, poster_path)