Merge pull request #698 from naughtyGitCat/master
typo transalte to translate,and some blank lines
This commit is contained in:
@@ -3,18 +3,19 @@ import json
|
|||||||
import os
|
import os
|
||||||
import re
|
import re
|
||||||
import sys
|
import sys
|
||||||
|
import time
|
||||||
import shutil
|
import shutil
|
||||||
import typing
|
import typing
|
||||||
import urllib3
|
import urllib3
|
||||||
import signal
|
import signal
|
||||||
import platform
|
import platform
|
||||||
|
import multiprocessing
|
||||||
|
from datetime import datetime, timedelta
|
||||||
|
from pathlib import Path
|
||||||
|
|
||||||
from opencc import OpenCC
|
from opencc import OpenCC
|
||||||
|
|
||||||
import ADC_function
|
|
||||||
import config
|
import config
|
||||||
from datetime import datetime, timedelta
|
|
||||||
import time
|
|
||||||
from pathlib import Path
|
|
||||||
from ADC_function import file_modification_days, get_html, parallel_download_files
|
from ADC_function import file_modification_days, get_html, parallel_download_files
|
||||||
from number_parser import get_number
|
from number_parser import get_number
|
||||||
from core import core_main, moveFailedFolder
|
from core import core_main, moveFailedFolder
|
||||||
@@ -44,7 +45,8 @@ def argparse_function(ver: str) -> typing.Tuple[str, str, str, str, bool]:
|
|||||||
parser = argparse.ArgumentParser(epilog=f"Load Config file '{conf.ini_path}'.")
|
parser = argparse.ArgumentParser(epilog=f"Load Config file '{conf.ini_path}'.")
|
||||||
parser.add_argument("file", default='', nargs='?', help="Single Movie file path.")
|
parser.add_argument("file", default='', nargs='?', help="Single Movie file path.")
|
||||||
parser.add_argument("-p", "--path", default='', nargs='?', help="Analysis folder path.")
|
parser.add_argument("-p", "--path", default='', nargs='?', help="Analysis folder path.")
|
||||||
parser.add_argument("-m","--main-mode",default='',nargs='?',help="Main mode. 1:Scraping 2:Organizing 3:Scraping in analysis folder")
|
parser.add_argument("-m", "--main-mode", default='', nargs='?',
|
||||||
|
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("-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("-C", "--config", default='config.ini', nargs='?', help="The config file Path.")
|
||||||
default_logdir = str(Path.home() / '.mlogs')
|
default_logdir = str(Path.home() / '.mlogs')
|
||||||
@@ -52,9 +54,12 @@ def argparse_function(ver: str) -> typing.Tuple[str, str, str, str, bool]:
|
|||||||
help=f"""Duplicate stdout and stderr to logfiles in logging folder, default on.
|
help=f"""Duplicate stdout and stderr to logfiles in logging folder, default on.
|
||||||
default folder for current user: '{default_logdir}'. Change default folder to an empty file,
|
default folder for current user: '{default_logdir}'. Change default folder to an empty file,
|
||||||
or use --log-dir= to turn log off.""")
|
or use --log-dir= to turn log off.""")
|
||||||
parser.add_argument("-q","--regex-query",dest='regexstr',default='',nargs='?',help="python re module regex filepath filtering.")
|
parser.add_argument("-q", "--regex-query", dest='regexstr', default='', nargs='?',
|
||||||
parser.add_argument("-d","--nfo-skip-days",dest='days',default='',nargs='?', help="Override nfo_skip_days value in config.")
|
help="python re module regex filepath filtering.")
|
||||||
parser.add_argument("-c","--stop-counter",dest='cnt',default='',nargs='?', help="Override stop_counter value in config.")
|
parser.add_argument("-d", "--nfo-skip-days", dest='days', default='', nargs='?',
|
||||||
|
help="Override nfo_skip_days value in config.")
|
||||||
|
parser.add_argument("-c", "--stop-counter", dest='cnt', default='', nargs='?',
|
||||||
|
help="Override stop_counter value in config.")
|
||||||
parser.add_argument("-i", "--ignore-failed-list", action="store_true", help="Ignore failed list '{}'".format(
|
parser.add_argument("-i", "--ignore-failed-list", action="store_true", help="Ignore failed list '{}'".format(
|
||||||
os.path.join(os.path.abspath(conf.failed_folder()), 'failed_list.txt')))
|
os.path.join(os.path.abspath(conf.failed_folder()), 'failed_list.txt')))
|
||||||
parser.add_argument("-a", "--auto-exit", action="store_true",
|
parser.add_argument("-a", "--auto-exit", action="store_true",
|
||||||
@@ -67,12 +72,16 @@ is performed. It may help you correct wrong numbers before real job.""")
|
|||||||
parser.add_argument("-v", "--version", action="version", version=ver)
|
parser.add_argument("-v", "--version", action="version", version=ver)
|
||||||
|
|
||||||
args = parser.parse_args()
|
args = parser.parse_args()
|
||||||
|
|
||||||
def get_natural_number_or_none(value):
|
def get_natural_number_or_none(value):
|
||||||
return int(value) if isinstance(value, str) and value.isnumeric() and int(value) >= 0 else None
|
return int(value) if isinstance(value, str) and value.isnumeric() and int(value) >= 0 else None
|
||||||
|
|
||||||
def get_str_or_none(value):
|
def get_str_or_none(value):
|
||||||
return value if isinstance(value, str) and len(value) else None
|
return value if isinstance(value, str) and len(value) else None
|
||||||
|
|
||||||
def get_bool_or_none(value):
|
def get_bool_or_none(value):
|
||||||
return True if isinstance(value, bool) and value else None
|
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:main_mode"] = get_natural_number_or_none(args.main_mode)
|
||||||
config.G_conf_override["common:source_folder"] = get_str_or_none(args.path)
|
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:auto_exit"] = get_bool_or_none(args.auto_exit)
|
||||||
@@ -83,43 +92,53 @@ is performed. It may help you correct wrong numbers before real job.""")
|
|||||||
|
|
||||||
return args.file, args.number, args.logdir, args.regexstr, args.zero_op
|
return args.file, args.number, args.logdir, args.regexstr, args.zero_op
|
||||||
|
|
||||||
|
|
||||||
class OutLogger(object):
|
class OutLogger(object):
|
||||||
def __init__(self, logfile) -> None:
|
def __init__(self, logfile) -> None:
|
||||||
self.term = sys.stdout
|
self.term = sys.stdout
|
||||||
self.log = open(logfile, "w", encoding='utf-8', buffering=1)
|
self.log = open(logfile, "w", encoding='utf-8', buffering=1)
|
||||||
self.filepath = logfile
|
self.filepath = logfile
|
||||||
|
|
||||||
def __del__(self):
|
def __del__(self):
|
||||||
self.close()
|
self.close()
|
||||||
|
|
||||||
def __enter__(self):
|
def __enter__(self):
|
||||||
pass
|
pass
|
||||||
|
|
||||||
def __exit__(self, *args):
|
def __exit__(self, *args):
|
||||||
self.close()
|
self.close()
|
||||||
|
|
||||||
def write(self, msg):
|
def write(self, msg):
|
||||||
self.term.write(msg)
|
self.term.write(msg)
|
||||||
self.log.write(msg)
|
self.log.write(msg)
|
||||||
|
|
||||||
def flush(self):
|
def flush(self):
|
||||||
self.term.flush()
|
self.term.flush()
|
||||||
self.log.flush()
|
self.log.flush()
|
||||||
os.fsync(self.log.fileno())
|
os.fsync(self.log.fileno())
|
||||||
|
|
||||||
def close(self):
|
def close(self):
|
||||||
if self.term != None:
|
if self.term is not None:
|
||||||
sys.stdout = self.term
|
sys.stdout = self.term
|
||||||
self.term = None
|
self.term = None
|
||||||
if self.log != None:
|
if self.log is not None:
|
||||||
self.log.close()
|
self.log.close()
|
||||||
self.log = None
|
self.log = None
|
||||||
|
|
||||||
|
|
||||||
class ErrLogger(OutLogger):
|
class ErrLogger(OutLogger):
|
||||||
|
|
||||||
def __init__(self, logfile) -> None:
|
def __init__(self, logfile) -> None:
|
||||||
self.term = sys.stderr
|
self.term = sys.stderr
|
||||||
self.log = open(logfile, "w", encoding='utf-8', buffering=1)
|
self.log = open(logfile, "w", encoding='utf-8', buffering=1)
|
||||||
self.filepath = logfile
|
self.filepath = logfile
|
||||||
|
|
||||||
def close(self):
|
def close(self):
|
||||||
if self.term != None:
|
if self.term is not None:
|
||||||
sys.stderr = self.term
|
sys.stderr = self.term
|
||||||
self.term = None
|
self.term = None
|
||||||
if self.log != None:
|
|
||||||
|
if self.log is not None:
|
||||||
self.log.close()
|
self.log.close()
|
||||||
self.log = None
|
self.log = None
|
||||||
|
|
||||||
@@ -254,13 +273,14 @@ def signal_handler(*args):
|
|||||||
print('[!]Ctrl+C detected, Exit.')
|
print('[!]Ctrl+C detected, Exit.')
|
||||||
sys.exit(9)
|
sys.exit(9)
|
||||||
|
|
||||||
|
|
||||||
def sigdebug_handler(*args):
|
def sigdebug_handler(*args):
|
||||||
config.G_conf_override["debug_mode:switch"] = not config.G_conf_override["debug_mode:switch"]
|
config.G_conf_override["debug_mode:switch"] = not config.G_conf_override["debug_mode:switch"]
|
||||||
print('[!]Debug {}'.format('On' if config.getInstance().debug() else 'oFF'))
|
print('[!]Debug {}'.format('On' if config.getInstance().debug() else 'oFF'))
|
||||||
|
|
||||||
|
|
||||||
# 新增失败文件列表跳过处理,及.nfo修改天数跳过处理,提示跳过视频总数,调试模式(-g)下详细被跳过文件,跳过小广告
|
# 新增失败文件列表跳过处理,及.nfo修改天数跳过处理,提示跳过视频总数,调试模式(-g)下详细被跳过文件,跳过小广告
|
||||||
def movie_lists(source_folder, regexstr):
|
def movie_lists(source_folder, regexstr: str) -> list[str]:
|
||||||
conf = config.getInstance()
|
conf = config.getInstance()
|
||||||
main_mode = conf.main_mode()
|
main_mode = conf.main_mode()
|
||||||
debug = conf.debug()
|
debug = conf.debug()
|
||||||
@@ -311,11 +331,12 @@ def movie_lists(source_folder, regexstr):
|
|||||||
continue # file is symlink or hardlink(Linux/NTFS/Darwin)
|
continue # file is symlink or hardlink(Linux/NTFS/Darwin)
|
||||||
# 调试用0字节样本允许通过,去除小于120MB的广告'苍老师强力推荐.mp4'(102.2MB)'黑道总裁.mp4'(98.4MB)'有趣的妹子激情表演.MP4'(95MB)'有趣的臺灣妹妹直播.mp4'(15.1MB)
|
# 调试用0字节样本允许通过,去除小于120MB的广告'苍老师强力推荐.mp4'(102.2MB)'黑道总裁.mp4'(98.4MB)'有趣的妹子激情表演.MP4'(95MB)'有趣的臺灣妹妹直播.mp4'(15.1MB)
|
||||||
movie_size = 0 if is_sym else full_name.stat().st_size # 同上 符号链接不取stat()及st_size,直接赋0跳过小视频检测
|
movie_size = 0 if is_sym else full_name.stat().st_size # 同上 符号链接不取stat()及st_size,直接赋0跳过小视频检测
|
||||||
if movie_size > 0 and movie_size < 125829120: # 1024*1024*120=125829120
|
if 0 < movie_size < 125829120: # 1024*1024*120=125829120
|
||||||
continue
|
continue
|
||||||
if cliRE and not cliRE.search(absf) or trailerRE.search(full_name.name):
|
if cliRE and not cliRE.search(absf) or trailerRE.search(full_name.name):
|
||||||
continue
|
continue
|
||||||
if main_mode == 3 and nfo_skip_days > 0 and file_modification_days(full_name.with_suffix('.nfo')) <= nfo_skip_days:
|
if main_mode == 3 and nfo_skip_days > 0 and file_modification_days(
|
||||||
|
full_name.with_suffix('.nfo')) <= nfo_skip_days:
|
||||||
skip_nfo_days_cnt += 1
|
skip_nfo_days_cnt += 1
|
||||||
if debug:
|
if debug:
|
||||||
print(f"[!]Skip movie by it's .nfo which modified within {nfo_skip_days} days: '{absf}'")
|
print(f"[!]Skip movie by it's .nfo which modified within {nfo_skip_days} days: '{absf}'")
|
||||||
@@ -325,7 +346,8 @@ def movie_lists(source_folder, regexstr):
|
|||||||
if skip_failed_cnt:
|
if skip_failed_cnt:
|
||||||
print(f"[!]Skip {skip_failed_cnt} movies in failed list '{failed_list_txt_path}'.")
|
print(f"[!]Skip {skip_failed_cnt} movies in failed list '{failed_list_txt_path}'.")
|
||||||
if skip_nfo_days_cnt:
|
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.")
|
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 soft_link or main_mode == 3:
|
||||||
return total
|
return total
|
||||||
# 软连接方式,已经成功削刮的也需要从成功目录中检查.nfo更新天数,跳过N天内更新过的
|
# 软连接方式,已经成功削刮的也需要从成功目录中检查.nfo更新天数,跳过N天内更新过的
|
||||||
@@ -351,13 +373,17 @@ def movie_lists(source_folder, regexstr):
|
|||||||
if debug:
|
if debug:
|
||||||
print(f"[!]Skip file successfully processed within {nfo_skip_days} days: '{f}'")
|
print(f"[!]Skip file successfully processed within {nfo_skip_days} days: '{f}'")
|
||||||
if len(rm_list):
|
if len(rm_list):
|
||||||
print(f"[!]Skip {len(rm_list)} movies in success folder '{success_folder}' who's .nfo modified within {nfo_skip_days} days.")
|
print(
|
||||||
|
f"[!]Skip {len(rm_list)} movies in success folder '{success_folder}' who's .nfo modified within {nfo_skip_days} days.")
|
||||||
|
|
||||||
return total
|
return total
|
||||||
|
|
||||||
|
|
||||||
def create_failed_folder(failed_folder):
|
def create_failed_folder(failed_folder: str):
|
||||||
if not os.path.exists(failed_folder): # 新建failed文件夹
|
"""
|
||||||
|
新建failed文件夹
|
||||||
|
"""
|
||||||
|
if not os.path.exists(failed_folder):
|
||||||
try:
|
try:
|
||||||
os.makedirs(failed_folder)
|
os.makedirs(failed_folder)
|
||||||
except:
|
except:
|
||||||
@@ -370,9 +396,7 @@ def rm_empty_folder(path):
|
|||||||
deleted = set()
|
deleted = set()
|
||||||
for current_dir, subdirs, files in os.walk(abspath, topdown=False):
|
for current_dir, subdirs, files in os.walk(abspath, topdown=False):
|
||||||
try:
|
try:
|
||||||
still_has_subdirs = any(
|
still_has_subdirs = any(_ for subdir in subdirs if os.path.join(current_dir, subdir) not in deleted)
|
||||||
_ for subdir in subdirs if os.path.join(current_dir, subdir) not in deleted
|
|
||||||
)
|
|
||||||
if not any(files) and not still_has_subdirs and not os.path.samefile(path, current_dir):
|
if not any(files) and not still_has_subdirs and not os.path.samefile(path, current_dir):
|
||||||
os.rmdir(current_dir)
|
os.rmdir(current_dir)
|
||||||
deleted.add(current_dir)
|
deleted.add(current_dir)
|
||||||
@@ -387,7 +411,7 @@ def create_data_and_move(file_path: str, zero_op, oCC):
|
|||||||
n_number = get_number(debug, os.path.basename(file_path))
|
n_number = get_number(debug, os.path.basename(file_path))
|
||||||
file_path = os.path.abspath(file_path)
|
file_path = os.path.abspath(file_path)
|
||||||
|
|
||||||
if debug == True:
|
if debug is True:
|
||||||
print(f"[!] [{n_number}] As Number making data for '{file_path}'")
|
print(f"[!] [{n_number}] As Number making data for '{file_path}'")
|
||||||
if zero_op:
|
if zero_op:
|
||||||
return
|
return
|
||||||
@@ -456,7 +480,7 @@ def main():
|
|||||||
|
|
||||||
main_mode = conf.main_mode()
|
main_mode = conf.main_mode()
|
||||||
folder_path = ""
|
folder_path = ""
|
||||||
if not main_mode in (1, 2, 3):
|
if main_mode not in (1, 2, 3):
|
||||||
print(f"[-]Main mode must be 1 or 2 or 3! You can run '{os.path.basename(sys.argv[0])} --help' for more help.")
|
print(f"[-]Main mode must be 1 or 2 or 3! You can run '{os.path.basename(sys.argv[0])} --help' for more help.")
|
||||||
sys.exit(4)
|
sys.exit(4)
|
||||||
|
|
||||||
@@ -467,7 +491,8 @@ def main():
|
|||||||
signal.signal(signal.SIGWINCH, sigdebug_handler)
|
signal.signal(signal.SIGWINCH, sigdebug_handler)
|
||||||
dupe_stdout_to_logfile(logdir)
|
dupe_stdout_to_logfile(logdir)
|
||||||
|
|
||||||
platform_total = str(' - ' + platform.platform() + ' \n[*] - ' + platform.machine() + ' - Python-' + platform.python_version())
|
platform_total = str(
|
||||||
|
' - ' + platform.platform() + ' \n[*] - ' + platform.machine() + ' - Python-' + platform.python_version())
|
||||||
|
|
||||||
print('[*]================= Movie Data Capture =================')
|
print('[*]================= Movie Data Capture =================')
|
||||||
print('[*]' + version.center(54))
|
print('[*]' + version.center(54))
|
||||||
@@ -504,6 +529,7 @@ def main():
|
|||||||
def fmd(f):
|
def fmd(f):
|
||||||
return ('https://raw.githubusercontent.com/yoshiko2/Movie_Data_Capture/master/MappingTable/' + f,
|
return ('https://raw.githubusercontent.com/yoshiko2/Movie_Data_Capture/master/MappingTable/' + f,
|
||||||
Path.home() / '.local' / 'share' / 'mdc' / f)
|
Path.home() / '.local' / 'share' / 'mdc' / f)
|
||||||
|
|
||||||
map_tab = (fmd('mapping_actor.xml'), fmd('mapping_info.xml'), fmd('c_number.json'))
|
map_tab = (fmd('mapping_actor.xml'), fmd('mapping_info.xml'), fmd('c_number.json'))
|
||||||
for k, v in map_tab:
|
for k, v in map_tab:
|
||||||
if v.exists():
|
if v.exists():
|
||||||
@@ -525,14 +551,15 @@ def main():
|
|||||||
try:
|
try:
|
||||||
oCC = None if ccm == 0 else OpenCC('t2s.json' if ccm == 1 else 's2t.json')
|
oCC = None if ccm == 0 else OpenCC('t2s.json' if ccm == 1 else 's2t.json')
|
||||||
except:
|
except:
|
||||||
# some OS no OpennCC cpython, try opencc-python-reimplemented.
|
# some OS no OpenCC cpython, try opencc-python-reimplemented.
|
||||||
# pip uninstall opencc && pip install opencc-python-reimplemented
|
# pip uninstall opencc && pip install opencc-python-reimplemented
|
||||||
oCC = None if ccm == 0 else OpenCC('t2s' if ccm == 1 else 's2t')
|
oCC = None if ccm == 0 else OpenCC('t2s' if ccm == 1 else 's2t')
|
||||||
|
|
||||||
if not single_file_path == '': # Single File
|
if not single_file_path == '': # Single File
|
||||||
print('[+]==================== Single File =====================')
|
print('[+]==================== Single File =====================')
|
||||||
if custom_number == '':
|
if custom_number == '':
|
||||||
create_data_and_move_with_custom_number(single_file_path, get_number(conf.debug(), os.path.basename(single_file_path)), oCC)
|
create_data_and_move_with_custom_number(single_file_path,
|
||||||
|
get_number(conf.debug(), os.path.basename(single_file_path)), oCC)
|
||||||
else:
|
else:
|
||||||
create_data_and_move_with_custom_number(single_file_path, custom_number, oCC)
|
create_data_and_move_with_custom_number(single_file_path, custom_number, oCC)
|
||||||
else:
|
else:
|
||||||
@@ -555,7 +582,8 @@ def main():
|
|||||||
for movie_path in movie_list: # 遍历电影列表 交给core处理
|
for movie_path in movie_list: # 遍历电影列表 交给core处理
|
||||||
count = count + 1
|
count = count + 1
|
||||||
percentage = str(count / int(count_all) * 100)[:4] + '%'
|
percentage = str(count / int(count_all) * 100)[:4] + '%'
|
||||||
print('[!] {:>30}{:>21}'.format('- ' + percentage + ' [' + str(count) + '/' + count_all + '] -', time.strftime("%H:%M:%S")))
|
print('[!] {:>30}{:>21}'.format('- ' + percentage + ' [' + str(count) + '/' + count_all + '] -',
|
||||||
|
time.strftime("%H:%M:%S")))
|
||||||
create_data_and_move(movie_path, zero_op, oCC)
|
create_data_and_move(movie_path, zero_op, oCC)
|
||||||
if count >= stop_count:
|
if count >= stop_count:
|
||||||
print("[!]Stop counter triggered!")
|
print("[!]Stop counter triggered!")
|
||||||
@@ -581,7 +609,7 @@ def main():
|
|||||||
|
|
||||||
sys.exit(0)
|
sys.exit(0)
|
||||||
|
|
||||||
import multiprocessing
|
|
||||||
if __name__ == '__main__':
|
if __name__ == '__main__':
|
||||||
multiprocessing.freeze_support()
|
multiprocessing.freeze_support()
|
||||||
main()
|
main()
|
||||||
|
|||||||
@@ -235,8 +235,8 @@ def get_data_from_json(file_number, oCC): # 从JSON返回元数据
|
|||||||
json_data['studio'] = studio
|
json_data['studio'] = studio
|
||||||
json_data['director'] = director
|
json_data['director'] = director
|
||||||
|
|
||||||
if conf.is_transalte():
|
if conf.is_translate():
|
||||||
translate_values = conf.transalte_values().split(",")
|
translate_values = conf.translate_values().split(",")
|
||||||
for translate_value in translate_values:
|
for translate_value in translate_values:
|
||||||
if json_data[translate_value] == "":
|
if json_data[translate_value] == "":
|
||||||
continue
|
continue
|
||||||
@@ -248,12 +248,12 @@ def get_data_from_json(file_number, oCC): # 从JSON返回元数据
|
|||||||
continue
|
continue
|
||||||
except:
|
except:
|
||||||
pass
|
pass
|
||||||
if conf.get_transalte_engine() == "azure":
|
if conf.get_translate_engine() == "azure":
|
||||||
t = translate(
|
t = translate(
|
||||||
json_data[translate_value],
|
json_data[translate_value],
|
||||||
target_language="zh-Hans",
|
target_language="zh-Hans",
|
||||||
engine=conf.get_transalte_engine(),
|
engine=conf.get_translate_engine(),
|
||||||
key=conf.get_transalte_key(),
|
key=conf.get_translate_key(),
|
||||||
)
|
)
|
||||||
else:
|
else:
|
||||||
t = translate(json_data[translate_value])
|
t = translate(json_data[translate_value])
|
||||||
|
|||||||
@@ -8,7 +8,7 @@ success_output_folder=JAV_output
|
|||||||
soft_link=0
|
soft_link=0
|
||||||
failed_move=1
|
failed_move=1
|
||||||
auto_exit=0
|
auto_exit=0
|
||||||
transalte_to_sc=0
|
translate_to_sc=0
|
||||||
multi_threading=0
|
multi_threading=0
|
||||||
;actor_gender value: female(♀) or male(♂) or both(♀ ♂) or all(♂ ♀ ⚧)
|
;actor_gender value: female(♀) or male(♂) or both(♀ ♂) or all(♂ ♀ ⚧)
|
||||||
actor_gender=female
|
actor_gender=female
|
||||||
@@ -51,7 +51,7 @@ folders=failed,JAV_output
|
|||||||
switch=0
|
switch=0
|
||||||
|
|
||||||
; 机器翻译
|
; 机器翻译
|
||||||
[transalte]
|
[translate]
|
||||||
switch=0
|
switch=0
|
||||||
;可选项 google-free,azure
|
;可选项 google-free,azure
|
||||||
engine=google-free
|
engine=google-free
|
||||||
|
|||||||
80
config.py
80
config.py
@@ -5,7 +5,6 @@ import configparser
|
|||||||
import time
|
import time
|
||||||
from pathlib import Path
|
from pathlib import Path
|
||||||
|
|
||||||
|
|
||||||
G_conf_override = {
|
G_conf_override = {
|
||||||
# index 0 save Config() first instance for quick access by using getInstance()
|
# index 0 save Config() first instance for quick access by using getInstance()
|
||||||
0: None,
|
0: None,
|
||||||
@@ -98,14 +97,18 @@ class Config:
|
|||||||
# print("[-]",e)
|
# print("[-]",e)
|
||||||
# sys.exit(3)
|
# sys.exit(3)
|
||||||
# #self.conf = self._default_config()
|
# #self.conf = self._default_config()
|
||||||
|
|
||||||
def getboolean_override(self, section, item) -> bool:
|
def getboolean_override(self, section, item) -> bool:
|
||||||
return self.conf.getboolean(section, item) if G_conf_override[f"{section}:{item}"] is None else bool(G_conf_override[f"{section}:{item}"])
|
return self.conf.getboolean(section, item) if G_conf_override[f"{section}:{item}"] is None else bool(
|
||||||
|
G_conf_override[f"{section}:{item}"])
|
||||||
|
|
||||||
def getint_override(self, section, item) -> int:
|
def getint_override(self, section, item) -> int:
|
||||||
return self.conf.getint(section, item) if G_conf_override[f"{section}:{item}"] is None else int(G_conf_override[f"{section}:{item}"])
|
return self.conf.getint(section, item) if G_conf_override[f"{section}:{item}"] is None else int(
|
||||||
|
G_conf_override[f"{section}:{item}"])
|
||||||
|
|
||||||
def get_override(self, section, item) -> str:
|
def get_override(self, section, item) -> str:
|
||||||
return self.conf.get(section, item) if G_conf_override[f"{section}:{item}"] is None else str(G_conf_override[f"{section}:{item}"])
|
return self.conf.get(section, item) if G_conf_override[f"{section}:{item}"] is None else str(
|
||||||
|
G_conf_override[f"{section}:{item}"])
|
||||||
|
|
||||||
def main_mode(self) -> int:
|
def main_mode(self) -> int:
|
||||||
try:
|
try:
|
||||||
@@ -127,34 +130,46 @@ class Config:
|
|||||||
|
|
||||||
def soft_link(self) -> bool:
|
def soft_link(self) -> bool:
|
||||||
return self.conf.getboolean("common", "soft_link")
|
return self.conf.getboolean("common", "soft_link")
|
||||||
|
|
||||||
def failed_move(self) -> bool:
|
def failed_move(self) -> bool:
|
||||||
return self.conf.getboolean("common", "failed_move")
|
return self.conf.getboolean("common", "failed_move")
|
||||||
|
|
||||||
def auto_exit(self) -> bool:
|
def auto_exit(self) -> bool:
|
||||||
return self.getboolean_override("common", "auto_exit")
|
return self.getboolean_override("common", "auto_exit")
|
||||||
def transalte_to_sc(self) -> bool:
|
|
||||||
return self.conf.getboolean("common", "transalte_to_sc")
|
def translate_to_sc(self) -> bool:
|
||||||
|
return self.conf.getboolean("common", "translate_to_sc")
|
||||||
|
|
||||||
def multi_threading(self) -> bool:
|
def multi_threading(self) -> bool:
|
||||||
return self.conf.getboolean("common", "multi_threading")
|
return self.conf.getboolean("common", "multi_threading")
|
||||||
|
|
||||||
def del_empty_folder(self) -> bool:
|
def del_empty_folder(self) -> bool:
|
||||||
return self.conf.getboolean("common", "del_empty_folder")
|
return self.conf.getboolean("common", "del_empty_folder")
|
||||||
|
|
||||||
def nfo_skip_days(self) -> int:
|
def nfo_skip_days(self) -> int:
|
||||||
try:
|
try:
|
||||||
return self.getint_override("common", "nfo_skip_days")
|
return self.getint_override("common", "nfo_skip_days")
|
||||||
except:
|
except:
|
||||||
return 30
|
return 30
|
||||||
|
|
||||||
def stop_counter(self) -> int:
|
def stop_counter(self) -> int:
|
||||||
try:
|
try:
|
||||||
return self.getint_override("common", "stop_counter")
|
return self.getint_override("common", "stop_counter")
|
||||||
except:
|
except:
|
||||||
return 0
|
return 0
|
||||||
|
|
||||||
def ignore_failed_list(self) -> bool:
|
def ignore_failed_list(self) -> bool:
|
||||||
return self.getboolean_override("common", "ignore_failed_list")
|
return self.getboolean_override("common", "ignore_failed_list")
|
||||||
|
|
||||||
def download_only_missing_images(self) -> bool:
|
def download_only_missing_images(self) -> bool:
|
||||||
return self.conf.getboolean("common", "download_only_missing_images")
|
return self.conf.getboolean("common", "download_only_missing_images")
|
||||||
|
|
||||||
def mapping_table_validity(self) -> int:
|
def mapping_table_validity(self) -> int:
|
||||||
return self.conf.getint("common", "mapping_table_validity")
|
return self.conf.getint("common", "mapping_table_validity")
|
||||||
def is_transalte(self) -> bool:
|
|
||||||
return self.conf.getboolean("transalte", "switch")
|
def is_translate(self) -> bool:
|
||||||
|
return self.conf.getboolean("translate", "switch")
|
||||||
|
|
||||||
def is_trailer(self) -> bool:
|
def is_trailer(self) -> bool:
|
||||||
return self.conf.getboolean("trailer", "switch")
|
return self.conf.getboolean("trailer", "switch")
|
||||||
|
|
||||||
@@ -190,18 +205,25 @@ class Config:
|
|||||||
return extrafanart_download
|
return extrafanart_download
|
||||||
except ValueError:
|
except ValueError:
|
||||||
self._exit("extrafanart_folder")
|
self._exit("extrafanart_folder")
|
||||||
def get_transalte_engine(self) -> str:
|
|
||||||
return self.conf.get("transalte","engine")
|
def get_translate_engine(self) -> str:
|
||||||
# def get_transalte_appId(self) ->str:
|
return self.conf.get("translate", "engine")
|
||||||
# return self.conf.get("transalte","appid")
|
|
||||||
def get_transalte_key(self) -> str:
|
# def get_translate_appId(self) ->str:
|
||||||
return self.conf.get("transalte","key")
|
# return self.conf.get("translate","appid")
|
||||||
def get_transalte_delay(self) -> int:
|
|
||||||
return self.conf.getint("transalte","delay")
|
def get_translate_key(self) -> str:
|
||||||
def transalte_values(self) -> str:
|
return self.conf.get("translate", "key")
|
||||||
return self.conf.get("transalte", "values")
|
|
||||||
|
def get_translate_delay(self) -> int:
|
||||||
|
return self.conf.getint("translate", "delay")
|
||||||
|
|
||||||
|
def translate_values(self) -> str:
|
||||||
|
return self.conf.get("translate", "values")
|
||||||
|
|
||||||
def get_translate_service_site(self) -> str:
|
def get_translate_service_site(self) -> str:
|
||||||
return self.conf.get("transalte", "service_site")
|
return self.conf.get("translate", "service_site")
|
||||||
|
|
||||||
def proxy(self):
|
def proxy(self):
|
||||||
try:
|
try:
|
||||||
sec = "proxy"
|
sec = "proxy"
|
||||||
@@ -320,7 +342,6 @@ class Config:
|
|||||||
except:
|
except:
|
||||||
return "hog"
|
return "hog"
|
||||||
|
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
def _exit(sec: str) -> None:
|
def _exit(sec: str) -> None:
|
||||||
print("[-] Read config error! Please check the {} section in config.ini", sec)
|
print("[-] Read config error! Please check the {} section in config.ini", sec)
|
||||||
@@ -340,7 +361,7 @@ class Config:
|
|||||||
conf.set(sec1, "soft_link", "0")
|
conf.set(sec1, "soft_link", "0")
|
||||||
conf.set(sec1, "failed_move", "1")
|
conf.set(sec1, "failed_move", "1")
|
||||||
conf.set(sec1, "auto_exit", "0")
|
conf.set(sec1, "auto_exit", "0")
|
||||||
conf.set(sec1, "transalte_to_sc", "1")
|
conf.set(sec1, "translate_to_sc", "1")
|
||||||
# actor_gender value: female or male or both or all(含人妖)
|
# actor_gender value: female or male or both or all(含人妖)
|
||||||
conf.set(sec1, "actor_gender", "female")
|
conf.set(sec1, "actor_gender", "female")
|
||||||
conf.set(sec1, "del_empty_folder", "1")
|
conf.set(sec1, "del_empty_folder", "1")
|
||||||
@@ -358,7 +379,6 @@ class Config:
|
|||||||
conf.set(sec2, "type", "socks5")
|
conf.set(sec2, "type", "socks5")
|
||||||
conf.set(sec2, "cacert_file", "")
|
conf.set(sec2, "cacert_file", "")
|
||||||
|
|
||||||
|
|
||||||
sec3 = "Name_Rule"
|
sec3 = "Name_Rule"
|
||||||
conf.add_section(sec3)
|
conf.add_section(sec3)
|
||||||
conf.set(sec3, "location_rule", "actor + '/' + number")
|
conf.set(sec3, "location_rule", "actor + '/' + number")
|
||||||
@@ -382,7 +402,7 @@ class Config:
|
|||||||
conf.add_section(sec7)
|
conf.add_section(sec7)
|
||||||
conf.set(sec7, "switch", "0")
|
conf.set(sec7, "switch", "0")
|
||||||
|
|
||||||
sec8 = "transalte"
|
sec8 = "translate"
|
||||||
conf.add_section(sec8)
|
conf.add_section(sec8)
|
||||||
conf.set(sec8, "switch", "0")
|
conf.set(sec8, "switch", "0")
|
||||||
conf.set(sec8, "engine", "google-free")
|
conf.set(sec8, "engine", "google-free")
|
||||||
@@ -402,8 +422,10 @@ class Config:
|
|||||||
|
|
||||||
sec11 = "media"
|
sec11 = "media"
|
||||||
conf.add_section(sec11)
|
conf.add_section(sec11)
|
||||||
conf.set(sec11, "media_type", ".mp4,.avi,.rmvb,.wmv,.mov,.mkv,.flv,.ts,.webm,.MP4,.AVI,.RMVB,.WMV,.MOV,.MKV,.FLV,.TS,.WEBM,iso,ISO")
|
conf.set(sec11, "media_type",
|
||||||
conf.set(sec11, "sub_type", ".smi,.srt,.idx,.sub,.sup,.psb,.ssa,.ass,.txt,.usf,.xss,.ssf,.rt,.lrc,.sbv,.vtt,.ttml")
|
".mp4,.avi,.rmvb,.wmv,.mov,.mkv,.flv,.ts,.webm,.MP4,.AVI,.RMVB,.WMV,.MOV,.MKV,.FLV,.TS,.WEBM,iso,ISO")
|
||||||
|
conf.set(sec11, "sub_type",
|
||||||
|
".smi,.srt,.idx,.sub,.sup,.psb,.ssa,.ass,.txt,.usf,.xss,.ssf,.rt,.lrc,.sbv,.vtt,.ttml")
|
||||||
|
|
||||||
sec12 = "watermark"
|
sec12 = "watermark"
|
||||||
conf.add_section(sec12)
|
conf.add_section(sec12)
|
||||||
@@ -464,7 +486,8 @@ class IniProxy():
|
|||||||
'''
|
'''
|
||||||
if self.address:
|
if self.address:
|
||||||
if self.proxytype in self.SUPPORT_PROXY_TYPE:
|
if self.proxytype in self.SUPPORT_PROXY_TYPE:
|
||||||
proxies = {"http": self.proxytype + "://" + self.address, "https": self.proxytype + "://" + self.address}
|
proxies = {"http": self.proxytype + "://" + self.address,
|
||||||
|
"https": self.proxytype + "://" + self.address}
|
||||||
else:
|
else:
|
||||||
proxies = {"http": "http://" + self.address, "https": "https://" + self.address}
|
proxies = {"http": "http://" + self.address, "https": "https://" + self.address}
|
||||||
else:
|
else:
|
||||||
@@ -477,8 +500,11 @@ if __name__ == "__main__":
|
|||||||
def evprint(evstr):
|
def evprint(evstr):
|
||||||
code = compile(evstr, "<string>", "eval")
|
code = compile(evstr, "<string>", "eval")
|
||||||
print('{}: "{}"'.format(evstr, eval(code)))
|
print('{}: "{}"'.format(evstr, eval(code)))
|
||||||
|
|
||||||
|
|
||||||
config = Config()
|
config = Config()
|
||||||
mfilter = {'conf', 'proxy', '_exit', '_default_config', 'getboolean_override', 'getint_override', 'get_override', 'ini_path'}
|
mfilter = {'conf', 'proxy', '_exit', '_default_config', 'getboolean_override', 'getint_override', 'get_override',
|
||||||
|
'ini_path'}
|
||||||
for _m in [m for m in dir(config) if not m.startswith('__') and m not in mfilter]:
|
for _m in [m for m in dir(config) if not m.startswith('__') and m not in mfilter]:
|
||||||
evprint(f'config.{_m}()')
|
evprint(f'config.{_m}()')
|
||||||
pfilter = {'proxies', 'SUPPORT_PROXY_TYPE'}
|
pfilter = {'proxies', 'SUPPORT_PROXY_TYPE'}
|
||||||
|
|||||||
@@ -2,6 +2,7 @@ import os
|
|||||||
import re
|
import re
|
||||||
import sys
|
import sys
|
||||||
import config
|
import config
|
||||||
|
import typing
|
||||||
|
|
||||||
G_spat = re.compile(
|
G_spat = re.compile(
|
||||||
"^22-sht\.me|-fhd|_fhd|^fhd_|^fhd-|-hd|_hd|^hd_|^hd-|-sd|_sd|-1080p|_1080p|-720p|_720p|"
|
"^22-sht\.me|-fhd|_fhd|^fhd_|^fhd-|-hd|_hd|^hd_|^hd-|-sd|_sd|-1080p|_1080p|-720p|_720p|"
|
||||||
@@ -9,30 +10,30 @@ G_spat = re.compile(
|
|||||||
re.IGNORECASE)
|
re.IGNORECASE)
|
||||||
|
|
||||||
|
|
||||||
def get_number(debug,file_path: str) -> str:
|
def get_number(debug: bool, file_path: str) -> str:
|
||||||
# """
|
"""
|
||||||
# >>> from number_parser import get_number
|
从文件路径中提取番号 from number_parser import get_number
|
||||||
# >>> get_number("/Users/Guest/AV_Data_Capture/snis-829.mp4")
|
>>> get_number(False, "/Users/Guest/AV_Data_Capture/snis-829.mp4")
|
||||||
# 'snis-829'
|
'snis-829'
|
||||||
# >>> get_number("/Users/Guest/AV_Data_Capture/snis-829-C.mp4")
|
>>> get_number(False, "/Users/Guest/AV_Data_Capture/snis-829-C.mp4")
|
||||||
# 'snis-829'
|
'snis-829'
|
||||||
# >>> get_number("C:¥Users¥Guest¥snis-829.mp4")
|
>>> get_number(False, "C:¥Users¥Guest¥snis-829.mp4")
|
||||||
# 'snis-829'
|
'snis-829'
|
||||||
# >>> get_number("C:¥Users¥Guest¥snis-829-C.mp4")
|
>>> get_number(False, "C:¥Users¥Guest¥snis-829-C.mp4")
|
||||||
# 'snis-829'
|
'snis-829'
|
||||||
# >>> get_number("./snis-829.mp4")
|
>>> get_number(False, "./snis-829.mp4")
|
||||||
# 'snis-829'
|
'snis-829'
|
||||||
# >>> get_number("./snis-829-C.mp4")
|
>>> get_number(False, "./snis-829-C.mp4")
|
||||||
# 'snis-829'
|
'snis-829'
|
||||||
# >>> get_number(".¥snis-829.mp4")
|
>>> get_number(False, ".¥snis-829.mp4")
|
||||||
# 'snis-829'
|
'snis-829'
|
||||||
# >>> get_number(".¥snis-829-C.mp4")
|
>>> get_number(False, ".¥snis-829-C.mp4")
|
||||||
# 'snis-829'
|
'snis-829'
|
||||||
# >>> get_number("snis-829.mp4")
|
>>> get_number(False, "snis-829.mp4")
|
||||||
# 'snis-829'
|
'snis-829'
|
||||||
# >>> get_number("snis-829-C.mp4")
|
>>> get_number(False, "snis-829-C.mp4")
|
||||||
# 'snis-829'
|
'snis-829'
|
||||||
# """
|
"""
|
||||||
filepath = os.path.basename(file_path)
|
filepath = os.path.basename(file_path)
|
||||||
# debug True 和 False 两块代码块合并,原因是此模块及函数只涉及字符串计算,没有IO操作,debug on时输出导致异常信息即可
|
# debug True 和 False 两块代码块合并,原因是此模块及函数只涉及字符串计算,没有IO操作,debug on时输出导致异常信息即可
|
||||||
try:
|
try:
|
||||||
@@ -79,7 +80,8 @@ G_TAKE_NUM_RULES = {
|
|||||||
'heyzo': lambda x: 'HEYZO-' + re.findall(r'heyzo[^\d]*(\d{4})', x, re.I)[0]
|
'heyzo': lambda x: 'HEYZO-' + re.findall(r'heyzo[^\d]*(\d{4})', x, re.I)[0]
|
||||||
}
|
}
|
||||||
|
|
||||||
def get_number_by_dict(filename: str) -> str:
|
|
||||||
|
def get_number_by_dict(filename: str) -> typing.Optional[str]:
|
||||||
try:
|
try:
|
||||||
for k, v in G_TAKE_NUM_RULES.items():
|
for k, v in G_TAKE_NUM_RULES.items():
|
||||||
if re.search(k, filename, re.I):
|
if re.search(k, filename, re.I):
|
||||||
@@ -88,10 +90,13 @@ def get_number_by_dict(filename: str) -> str:
|
|||||||
pass
|
pass
|
||||||
return None
|
return None
|
||||||
|
|
||||||
|
|
||||||
class Cache_uncensored_conf:
|
class Cache_uncensored_conf:
|
||||||
prefix = None
|
prefix = None
|
||||||
|
|
||||||
def is_empty(self):
|
def is_empty(self):
|
||||||
return bool(self.prefix is None)
|
return bool(self.prefix is None)
|
||||||
|
|
||||||
def set(self, v: list):
|
def set(self, v: list):
|
||||||
if not v or not len(v) or not len(v[0]):
|
if not v or not len(v) or not len(v[0]):
|
||||||
raise ValueError('input prefix list empty or None')
|
raise ValueError('input prefix list empty or None')
|
||||||
@@ -100,13 +105,16 @@ class Cache_uncensored_conf:
|
|||||||
for i in v[1:]:
|
for i in v[1:]:
|
||||||
s += f"|{i}.+"
|
s += f"|{i}.+"
|
||||||
self.prefix = re.compile(s, re.I)
|
self.prefix = re.compile(s, re.I)
|
||||||
|
|
||||||
def check(self, number):
|
def check(self, number):
|
||||||
if self.prefix is None:
|
if self.prefix is None:
|
||||||
raise ValueError('No init re compile')
|
raise ValueError('No init re compile')
|
||||||
return self.prefix.match(number)
|
return self.prefix.match(number)
|
||||||
|
|
||||||
|
|
||||||
G_cache_uncensored_conf = Cache_uncensored_conf()
|
G_cache_uncensored_conf = Cache_uncensored_conf()
|
||||||
|
|
||||||
|
|
||||||
# ========================================================================是否为无码
|
# ========================================================================是否为无码
|
||||||
def is_uncensored(number):
|
def is_uncensored(number):
|
||||||
if re.match(
|
if re.match(
|
||||||
@@ -119,6 +127,7 @@ r'[\d-]{4,}|\d{6}_\d{2,3}|(cz|gedo|k|n|red-|se)\d{2,4}|heyzo.+|xxx-av-.+|heydoug
|
|||||||
G_cache_uncensored_conf.set(config.getInstance().get_uncensored().split(','))
|
G_cache_uncensored_conf.set(config.getInstance().get_uncensored().split(','))
|
||||||
return G_cache_uncensored_conf.check(number)
|
return G_cache_uncensored_conf.check(number)
|
||||||
|
|
||||||
|
|
||||||
if __name__ == "__main__":
|
if __name__ == "__main__":
|
||||||
# import doctest
|
# import doctest
|
||||||
# doctest.testmod(raise_on_error=True)
|
# doctest.testmod(raise_on_error=True)
|
||||||
@@ -145,9 +154,13 @@ if __name__ == "__main__":
|
|||||||
"pacopacomama-093021_539-FHD.mkv", # 新支持片商格式 093021_539 命名规则来自javdb数据源
|
"pacopacomama-093021_539-FHD.mkv", # 新支持片商格式 093021_539 命名规则来自javdb数据源
|
||||||
"sbw99.cc@heyzo_hd_2636_full.mp4"
|
"sbw99.cc@heyzo_hd_2636_full.mp4"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
def evprint(evstr):
|
def evprint(evstr):
|
||||||
code = compile(evstr, "<string>", "eval")
|
code = compile(evstr, "<string>", "eval")
|
||||||
print("{1:>20} # '{0}'".format(evstr[18:-2], eval(code)))
|
print("{1:>20} # '{0}'".format(evstr[18:-2], eval(code)))
|
||||||
|
|
||||||
|
|
||||||
for t in test_use_cases:
|
for t in test_use_cases:
|
||||||
evprint(f'get_number(True, "{t}")')
|
evprint(f'get_number(True, "{t}")')
|
||||||
|
|
||||||
@@ -170,6 +183,7 @@ if __name__ == "__main__":
|
|||||||
# 示例:
|
# 示例:
|
||||||
# python3 ./number_parser.py ALL
|
# python3 ./number_parser.py ALL
|
||||||
import subprocess
|
import subprocess
|
||||||
|
|
||||||
ES_search_path = "ALL disks"
|
ES_search_path = "ALL disks"
|
||||||
if sys.argv[1] == "ALL":
|
if sys.argv[1] == "ALL":
|
||||||
if sys.platform == "win32":
|
if sys.platform == "win32":
|
||||||
@@ -181,7 +195,8 @@ if __name__ == "__main__":
|
|||||||
out_list = out_text.splitlines()
|
out_list = out_text.splitlines()
|
||||||
elif sys.platform in ("linux", "darwin"):
|
elif sys.platform in ("linux", "darwin"):
|
||||||
ES_prog_path = 'locate' if sys.platform == 'linux' else 'glocate'
|
ES_prog_path = 'locate' if sys.platform == 'linux' else 'glocate'
|
||||||
ES_cmdline = r"{} -b -i --regex '\.mp4$|\.avi$|\.rmvb$|\.wmv$|\.mov$|\.mkv$|\.webm$|\.iso$|\.mpg$|\.m4v$'".format(ES_prog_path)
|
ES_cmdline = r"{} -b -i --regex '\.mp4$|\.avi$|\.rmvb$|\.wmv$|\.mov$|\.mkv$|\.webm$|\.iso$|\.mpg$|\.m4v$'".format(
|
||||||
|
ES_prog_path)
|
||||||
out_bytes = subprocess.check_output(ES_cmdline.split(' '))
|
out_bytes = subprocess.check_output(ES_cmdline.split(' '))
|
||||||
out_text = out_bytes.decode('utf-8')
|
out_text = out_bytes.decode('utf-8')
|
||||||
out_list = [os.path.basename(line) for line in out_text.splitlines()]
|
out_list = [os.path.basename(line) for line in out_text.splitlines()]
|
||||||
|
|||||||
Reference in New Issue
Block a user