From 15d98a96ec09acdae0293a7d3c32416f72348193 Mon Sep 17 00:00:00 2001 From: joyfuI <1342862+joyfuI@users.noreply.github.com> Date: Sat, 30 Apr 2022 18:57:23 +0900 Subject: [PATCH] =?UTF-8?q?pylint,=20black=20=EC=A0=81=EC=9A=A9?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .gitignore | 1 - .vscode/settings.json | 5 + logic.py | 68 ++-- logic_normal.py | 394 ++++++++++--------- model.py | 54 ++- my_youtube_dl.py | 137 +++---- plugin.py | 563 ++++++++++++++-------------- static/youtube-dl_download.js | 55 +-- static/youtube-dl_list.css | 18 +- static/youtube-dl_list.js | 207 +++++----- static/youtube-dl_setting.js | 79 ++-- static/youtube-dl_sub.js | 39 +- static/youtube-dl_thumbnail.js | 37 +- templates/youtube-dl_list.html | 57 +-- templates/youtube-dl_setting.html | 47 ++- templates/youtube-dl_sub.html | 38 +- templates/youtube-dl_thumbnail.html | 27 +- 17 files changed, 993 insertions(+), 833 deletions(-) create mode 100644 .vscode/settings.json diff --git a/.gitignore b/.gitignore index c129fdf..917251c 100644 --- a/.gitignore +++ b/.gitignore @@ -1,4 +1,3 @@ -.idea/ .venv/ __pycache__/ test/ diff --git a/.vscode/settings.json b/.vscode/settings.json new file mode 100644 index 0000000..c659b65 --- /dev/null +++ b/.vscode/settings.json @@ -0,0 +1,5 @@ +{ + "files.associations": { + "*.html": "jinja-html" + } +} diff --git a/logic.py b/logic.py index d02f701..fea54d3 100644 --- a/logic.py +++ b/logic.py @@ -12,20 +12,21 @@ from framework.util import Util from .logic_normal import LogicNormal from .model import ModelSetting -package_name = __name__.split('.')[0] +package_name = __name__.split(".", maxsplit=1)[0] logger = get_logger(package_name) class Logic(object): db_default = { - 'db_version': '2', - 'youtube_dl_package': '0', - 'ffmpeg_path': '' if platform.system() != 'Windows' else os.path.join(path_app_root, 'bin', 'Windows', - 'ffmpeg.exe'), - 'temp_path': os.path.join(path_data, 'download_tmp'), - 'save_path': os.path.join(path_data, 'download'), - 'default_filename': '', - 'proxy': '' + "db_version": "2", + "youtube_dl_package": "0", + "ffmpeg_path": "" + if platform.system() != "Windows" + else os.path.join(path_app_root, "bin", "Windows", "ffmpeg.exe"), + "temp_path": os.path.join(path_data, "download_tmp"), + "save_path": os.path.join(path_data, "download"), + "default_filename": "", + "proxy": "", } @staticmethod @@ -37,51 +38,66 @@ class Logic(object): db.session.commit() Logic.migration() except Exception as e: - logger.error('Exception:%s', e) + logger.error("Exception:%s", e) logger.error(traceback.format_exc()) @staticmethod def plugin_load(): try: - logger.debug('%s plugin_load', package_name) + logger.debug("%s plugin_load", package_name) Logic.db_init() # youtube-dl 업데이트 - youtube_dl = LogicNormal.get_youtube_dl_package(ModelSetting.get('youtube_dl_package')) - logger.debug('%s upgrade' % youtube_dl) - logger.debug(subprocess.check_output([sys.executable, '-m', 'pip', 'install', '--upgrade', youtube_dl], - universal_newlines=True)) + youtube_dl = LogicNormal.get_youtube_dl_package( + ModelSetting.get("youtube_dl_package") + ) + logger.debug(f"{youtube_dl} upgrade") + logger.debug( + subprocess.check_output( + [sys.executable, "-m", "pip", "install", "--upgrade", youtube_dl], + universal_newlines=True, + ) + ) # 편의를 위해 json 파일 생성 from .plugin import plugin_info - Util.save_from_dict_to_json(plugin_info, os.path.join(os.path.dirname(__file__), 'info.json')) + + Util.save_from_dict_to_json( + plugin_info, os.path.join(os.path.dirname(__file__), "info.json") + ) except Exception as e: - logger.error('Exception:%s', e) + logger.error("Exception:%s", e) logger.error(traceback.format_exc()) @staticmethod def plugin_unload(): try: - logger.debug('%s plugin_unload', package_name) + logger.debug("%s plugin_unload", package_name) except Exception as e: - logger.error('Exception:%s', e) + logger.error("Exception:%s", e) logger.error(traceback.format_exc()) @staticmethod def migration(): try: - db_version = ModelSetting.get_int('db_version') - connect = sqlite3.connect(os.path.join(path_data, 'db', '%s.db' % package_name)) + db_version = ModelSetting.get_int("db_version") + connect = sqlite3.connect( + os.path.join(path_data, "db", f"{package_name}.db") + ) if db_version < 2: - logger.debug('youtube-dlc uninstall') - logger.debug(subprocess.check_output([sys.executable, '-m', 'pip', 'uninstall', '-y', 'youtube-dlc'], - universal_newlines=True)) + logger.debug("youtube-dlc uninstall") + logger.debug( + subprocess.check_output( + [sys.executable, "-m", "pip", "uninstall", "-y", "youtube-dlc"], + universal_newlines=True, + ) + ) connect.commit() connect.close() - ModelSetting.set('db_version', Logic.db_default['db_version']) + ModelSetting.set("db_version", Logic.db_default["db_version"]) db.session.flush() except Exception as e: - logger.error('Exception:%s', e) + logger.error("Exception:%s", e) logger.error(traceback.format_exc()) diff --git a/logic_normal.py b/logic_normal.py index 4f997d1..7a8e41d 100644 --- a/logic_normal.py +++ b/logic_normal.py @@ -7,7 +7,7 @@ from framework.logger import get_logger from .my_youtube_dl import MyYoutubeDL, Status -package_name = __name__.split('.')[0] +package_name = __name__.split(".", maxsplit=1)[0] logger = get_logger(package_name) @@ -16,8 +16,8 @@ class LogicNormal(object): @staticmethod def get_youtube_dl_package(index=None, import_pkg=False): - packages = ['youtube-dl', 'yt-dlp'] - import_name = ['youtube_dl', 'yt_dlp'] + packages = ["youtube-dl", "yt-dlp"] + import_name = ["youtube_dl", "yt_dlp"] if import_pkg: return import_name if index is None else import_name[int(index)] else: @@ -28,9 +28,9 @@ class LogicNormal(object): try: return MyYoutubeDL.get_version() except Exception as e: - logger.error('Exception:%s', e) + logger.error("Exception:%s", e) logger.error(traceback.format_exc()) - return '패키지 임포트 실패' + return "패키지 임포트 실패" @staticmethod def get_default_filename(): @@ -39,37 +39,40 @@ class LogicNormal(object): @staticmethod def get_preset_list(): return [ - ['bestvideo+bestaudio/best', '최고 화질'], - ['bestvideo[height<=1080]+bestaudio/best[height<=1080]', '1080p'], - ['worstvideo+worstaudio/worst', '최저 화질'], - ['bestvideo[ext=mp4]+bestaudio[ext=m4a]/best[ext=mp4]', '최고 화질(mp4)'], - ['bestvideo[ext=mp4][height<=1080]+bestaudio[ext=m4a]/best[ext=mp4][height<=1080]', '1080p(mp4)'], - ['bestvideo[filesize<50M]+bestaudio/best[filesize<50M]', '50MB 미만'], - ['bestaudio/best', '오디오만'], - ['_custom', '사용자 정의'] + ["bestvideo+bestaudio/best", "최고 화질"], + ["bestvideo[height<=1080]+bestaudio/best[height<=1080]", "1080p"], + ["worstvideo+worstaudio/worst", "최저 화질"], + ["bestvideo[ext=mp4]+bestaudio[ext=m4a]/best[ext=mp4]", "최고 화질(mp4)"], + [ + "bestvideo[ext=mp4][height<=1080]+bestaudio[ext=m4a]/best[ext=mp4][height<=1080]", + "1080p(mp4)", + ], + ["bestvideo[filesize<50M]+bestaudio/best[filesize<50M]", "50MB 미만"], + ["bestaudio/best", "오디오만"], + ["_custom", "사용자 정의"], ] @staticmethod def get_postprocessor_list(): return [ - ['', '후처리 안함', None], - ['mp4', 'MP4', '비디오 변환'], - ['flv', 'FLV', '비디오 변환'], - ['webm', 'WebM', '비디오 변환'], - ['ogg', 'Ogg', '비디오 변환'], - ['mkv', 'MKV', '비디오 변환'], - ['ts', 'TS', '비디오 변환'], - ['avi', 'AVI', '비디오 변환'], - ['wmv', 'WMV', '비디오 변환'], - ['mov', 'MOV', '비디오 변환'], - ['gif', 'GIF', '비디오 변환'], - ['mp3', 'MP3', '오디오 추출'], - ['aac', 'AAC', '오디오 추출'], - ['flac', 'FLAC', '오디오 추출'], - ['m4a', 'M4A', '오디오 추출'], - ['opus', 'Opus', '오디오 추출'], - ['vorbis', 'Vorbis', '오디오 추출'], - ['wav', 'WAV', '오디오 추출'] + ["", "후처리 안함", None], + ["mp4", "MP4", "비디오 변환"], + ["flv", "FLV", "비디오 변환"], + ["webm", "WebM", "비디오 변환"], + ["ogg", "Ogg", "비디오 변환"], + ["mkv", "MKV", "비디오 변환"], + ["ts", "TS", "비디오 변환"], + ["avi", "AVI", "비디오 변환"], + ["wmv", "WMV", "비디오 변환"], + ["mov", "MOV", "비디오 변환"], + ["gif", "GIF", "비디오 변환"], + ["mp3", "MP3", "오디오 추출"], + ["aac", "AAC", "오디오 추출"], + ["flac", "FLAC", "오디오 추출"], + ["m4a", "M4A", "오디오 추출"], + ["opus", "Opus", "오디오 추출"], + ["vorbis", "Vorbis", "오디오 추출"], + ["wav", "WAV", "오디오 추출"], ] @staticmethod @@ -77,9 +80,9 @@ class LogicNormal(object): video_convertor = [] extract_audio = [] for i in LogicNormal.get_postprocessor_list(): - if i[2] == '비디오 변환': + if i[2] == "비디오 변환": video_convertor.append(i[0]) - elif i[2] == '오디오 추출': + elif i[2] == "오디오 추출": extract_audio.append(i[0]) return video_convertor, extract_audio @@ -87,50 +90,56 @@ class LogicNormal(object): def download(**kwagrs): try: logger.debug(kwagrs) - plugin = kwagrs['plugin'] - url = kwagrs['url'] - filename = kwagrs['filename'] - temp_path = kwagrs['temp_path'] - save_path = kwagrs['save_path'] + plugin = kwagrs["plugin"] + url = kwagrs["url"] + filename = kwagrs["filename"] + temp_path = kwagrs["temp_path"] + save_path = kwagrs["save_path"] opts = {} - if 'format' in kwagrs and kwagrs['format']: - opts['format'] = kwagrs['format'] + if "format" in kwagrs and kwagrs["format"]: + opts["format"] = kwagrs["format"] postprocessor = [] - if 'preferedformat' in kwagrs and kwagrs['preferedformat']: - postprocessor.append({ - 'key': 'FFmpegVideoConvertor', - 'preferedformat': kwagrs['preferedformat'] - }) - if 'preferredcodec' in kwagrs and kwagrs['preferredcodec']: - postprocessor.append({ - 'key': 'FFmpegExtractAudio', - 'preferredcodec': kwagrs['preferredcodec'], - 'preferredquality': str(kwagrs['preferredquality']) - }) + if "preferedformat" in kwagrs and kwagrs["preferedformat"]: + postprocessor.append( + { + "key": "FFmpegVideoConvertor", + "preferedformat": kwagrs["preferedformat"], + } + ) + if "preferredcodec" in kwagrs and kwagrs["preferredcodec"]: + postprocessor.append( + { + "key": "FFmpegExtractAudio", + "preferredcodec": kwagrs["preferredcodec"], + "preferredquality": str(kwagrs["preferredquality"]), + } + ) if postprocessor: - opts['postprocessors'] = postprocessor - if 'playlist' in kwagrs and kwagrs['playlist']: - if kwagrs['playlist'] == 'reverse': - opts['playlistreverse'] = True - elif kwagrs['playlist'] == 'random': - opts['playlistrandom'] = True + opts["postprocessors"] = postprocessor + if "playlist" in kwagrs and kwagrs["playlist"]: + if kwagrs["playlist"] == "reverse": + opts["playlistreverse"] = True + elif kwagrs["playlist"] == "random": + opts["playlistrandom"] = True else: - opts['playlist_items'] = kwagrs['playlist'] - if 'archive' in kwagrs and kwagrs['archive']: - opts['download_archive'] = kwagrs['archive'] - if 'proxy' in kwagrs and kwagrs['proxy']: - opts['proxy'] = kwagrs['proxy'] - if 'ffmpeg_path' in kwagrs and kwagrs['ffmpeg_path']: - opts['ffmpeg_location'] = kwagrs['ffmpeg_path'] - if 'cookiefile' in kwagrs and kwagrs['cookiefile']: - opts['cookiefile'] = kwagrs['cookiefile'] - dateafter = kwagrs.get('dateafter') - youtube_dl = MyYoutubeDL(plugin, 'video', url, filename, temp_path, save_path, opts, dateafter) - youtube_dl.key = kwagrs.get('key') + opts["playlist_items"] = kwagrs["playlist"] + if "archive" in kwagrs and kwagrs["archive"]: + opts["download_archive"] = kwagrs["archive"] + if "proxy" in kwagrs and kwagrs["proxy"]: + opts["proxy"] = kwagrs["proxy"] + if "ffmpeg_path" in kwagrs and kwagrs["ffmpeg_path"]: + opts["ffmpeg_location"] = kwagrs["ffmpeg_path"] + if "cookiefile" in kwagrs and kwagrs["cookiefile"]: + opts["cookiefile"] = kwagrs["cookiefile"] + dateafter = kwagrs.get("dateafter") + youtube_dl = MyYoutubeDL( + plugin, "video", url, filename, temp_path, save_path, opts, dateafter + ) + youtube_dl.key = kwagrs.get("key") LogicNormal.youtube_dl_list.append(youtube_dl) # 리스트 추가 return youtube_dl except Exception as e: - logger.error('Exception:%s', e) + logger.error("Exception:%s", e) logger.error(traceback.format_exc()) return None @@ -138,40 +147,50 @@ class LogicNormal(object): def thumbnail(**kwagrs): try: logger.debug(kwagrs) - plugin = kwagrs['plugin'] - url = kwagrs['url'] - filename = kwagrs['filename'] - temp_path = kwagrs['temp_path'] - save_path = kwagrs['save_path'] - opts = { - 'skip_download': True - } - if 'all_thumbnails' in kwagrs and str(kwagrs['all_thumbnails']).lower() != 'false': - opts['write_all_thumbnails'] = True + plugin = kwagrs["plugin"] + url = kwagrs["url"] + filename = kwagrs["filename"] + temp_path = kwagrs["temp_path"] + save_path = kwagrs["save_path"] + opts = {"skip_download": True} + if ( + "all_thumbnails" in kwagrs + and str(kwagrs["all_thumbnails"]).lower() != "false" + ): + opts["write_all_thumbnails"] = True else: - opts['writethumbnail'] = True - if 'playlist' in kwagrs and kwagrs['playlist']: - if kwagrs['playlist'] == 'reverse': - opts['playlistreverse'] = True - elif kwagrs['playlist'] == 'random': - opts['playlistrandom'] = True + opts["writethumbnail"] = True + if "playlist" in kwagrs and kwagrs["playlist"]: + if kwagrs["playlist"] == "reverse": + opts["playlistreverse"] = True + elif kwagrs["playlist"] == "random": + opts["playlistrandom"] = True else: - opts['playlist_items'] = kwagrs['playlist'] - if 'archive' in kwagrs and kwagrs['archive']: - opts['download_archive'] = kwagrs['archive'] - if 'proxy' in kwagrs and kwagrs['proxy']: - opts['proxy'] = kwagrs['proxy'] - if 'ffmpeg_path' in kwagrs and kwagrs['ffmpeg_path']: - opts['ffmpeg_location'] = kwagrs['ffmpeg_path'] - if 'cookiefile' in kwagrs and kwagrs['cookiefile']: - opts['cookiefile'] = kwagrs['cookiefile'] - dateafter = kwagrs.get('dateafter') - youtube_dl = MyYoutubeDL(plugin, 'thumbnail', url, filename, temp_path, save_path, opts, dateafter) - youtube_dl.key = kwagrs.get('key') + opts["playlist_items"] = kwagrs["playlist"] + if "archive" in kwagrs and kwagrs["archive"]: + opts["download_archive"] = kwagrs["archive"] + if "proxy" in kwagrs and kwagrs["proxy"]: + opts["proxy"] = kwagrs["proxy"] + if "ffmpeg_path" in kwagrs and kwagrs["ffmpeg_path"]: + opts["ffmpeg_location"] = kwagrs["ffmpeg_path"] + if "cookiefile" in kwagrs and kwagrs["cookiefile"]: + opts["cookiefile"] = kwagrs["cookiefile"] + dateafter = kwagrs.get("dateafter") + youtube_dl = MyYoutubeDL( + plugin, + "thumbnail", + url, + filename, + temp_path, + save_path, + opts, + dateafter, + ) + youtube_dl.key = kwagrs.get("key") LogicNormal.youtube_dl_list.append(youtube_dl) # 리스트 추가 return youtube_dl except Exception as e: - logger.error('Exception:%s', e) + logger.error("Exception:%s", e) logger.error(traceback.format_exc()) return None @@ -179,45 +198,47 @@ class LogicNormal(object): def sub(**kwagrs): try: logger.debug(kwagrs) - plugin = kwagrs['plugin'] - url = kwagrs['url'] - filename = kwagrs['filename'] - temp_path = kwagrs['temp_path'] - save_path = kwagrs['save_path'] - opts = { - 'skip_download': True - } - sub_lang = map(lambda x: x.strip(), kwagrs['sub_lang'].split(',')) # 문자열을 리스트로 변환 - if 'all_subs' in kwagrs and str(kwagrs['all_subs']).lower() != 'false': - opts['allsubtitles'] = True + plugin = kwagrs["plugin"] + url = kwagrs["url"] + filename = kwagrs["filename"] + temp_path = kwagrs["temp_path"] + save_path = kwagrs["save_path"] + opts = {"skip_download": True} + sub_lang = map( + lambda x: x.strip(), kwagrs["sub_lang"].split(",") + ) # 문자열을 리스트로 변환 + if "all_subs" in kwagrs and str(kwagrs["all_subs"]).lower() != "false": + opts["allsubtitles"] = True else: - opts['subtitleslangs'] = sub_lang - if 'auto_sub' in kwagrs and str(kwagrs['auto_sub']).lower() != 'false': - opts['writeautomaticsub'] = True + opts["subtitleslangs"] = sub_lang + if "auto_sub" in kwagrs and str(kwagrs["auto_sub"]).lower() != "false": + opts["writeautomaticsub"] = True else: - opts['writesubtitles'] = True - if 'playlist' in kwagrs and kwagrs['playlist']: - if kwagrs['playlist'] == 'reverse': - opts['playlistreverse'] = True - elif kwagrs['playlist'] == 'random': - opts['playlistrandom'] = True + opts["writesubtitles"] = True + if "playlist" in kwagrs and kwagrs["playlist"]: + if kwagrs["playlist"] == "reverse": + opts["playlistreverse"] = True + elif kwagrs["playlist"] == "random": + opts["playlistrandom"] = True else: - opts['playlist_items'] = kwagrs['playlist'] - if 'archive' in kwagrs and kwagrs['archive']: - opts['download_archive'] = kwagrs['archive'] - if 'proxy' in kwagrs and kwagrs['proxy']: - opts['proxy'] = kwagrs['proxy'] - if 'ffmpeg_path' in kwagrs and kwagrs['ffmpeg_path']: - opts['ffmpeg_location'] = kwagrs['ffmpeg_path'] - if 'cookiefile' in kwagrs and kwagrs['cookiefile']: - opts['cookiefile'] = kwagrs['cookiefile'] - dateafter = kwagrs.get('dateafter') - youtube_dl = MyYoutubeDL(plugin, 'subtitle', url, filename, temp_path, save_path, opts, dateafter) - youtube_dl.key = kwagrs.get('key') + opts["playlist_items"] = kwagrs["playlist"] + if "archive" in kwagrs and kwagrs["archive"]: + opts["download_archive"] = kwagrs["archive"] + if "proxy" in kwagrs and kwagrs["proxy"]: + opts["proxy"] = kwagrs["proxy"] + if "ffmpeg_path" in kwagrs and kwagrs["ffmpeg_path"]: + opts["ffmpeg_location"] = kwagrs["ffmpeg_path"] + if "cookiefile" in kwagrs and kwagrs["cookiefile"]: + opts["cookiefile"] = kwagrs["cookiefile"] + dateafter = kwagrs.get("dateafter") + youtube_dl = MyYoutubeDL( + plugin, "subtitle", url, filename, temp_path, save_path, opts, dateafter + ) + youtube_dl.key = kwagrs.get("key") LogicNormal.youtube_dl_list.append(youtube_dl) # 리스트 추가 return youtube_dl except Exception as e: - logger.error('Exception:%s', e) + logger.error("Exception:%s", e) logger.error(traceback.format_exc()) return None @@ -225,50 +246,79 @@ class LogicNormal(object): def get_data(youtube_dl): try: data = {} - data['plugin'] = youtube_dl.plugin - data['url'] = youtube_dl.url - data['filename'] = youtube_dl.filename - data['temp_path'] = youtube_dl.temp_path - data['save_path'] = youtube_dl.save_path - data['index'] = youtube_dl.index - data['status_str'] = youtube_dl.status.name - data['status_ko'] = str(youtube_dl.status) - data['end_time'] = '' - data['extractor'] = youtube_dl.type + ( - ' - ' + youtube_dl.info_dict['extractor'] if youtube_dl.info_dict['extractor'] is not None else '') - data['title'] = youtube_dl.info_dict['title'] if \ - youtube_dl.info_dict['title'] is not None else youtube_dl.url - data['uploader'] = youtube_dl.info_dict['uploader'] if youtube_dl.info_dict['uploader'] is not None else '' - data['uploader_url'] = youtube_dl.info_dict['uploader_url'] if \ - youtube_dl.info_dict['uploader_url'] is not None else '' - data['downloaded_bytes_str'] = '' - data['total_bytes_str'] = '' - data['percent'] = '0' - data['eta'] = youtube_dl.progress_hooks['eta'] if youtube_dl.progress_hooks['eta'] is not None else '' - data['speed_str'] = LogicNormal.human_readable_size(youtube_dl.progress_hooks['speed'], '/s') if \ - youtube_dl.progress_hooks['speed'] is not None else '' + data["plugin"] = youtube_dl.plugin + data["url"] = youtube_dl.url + data["filename"] = youtube_dl.filename + data["temp_path"] = youtube_dl.temp_path + data["save_path"] = youtube_dl.save_path + data["index"] = youtube_dl.index + data["status_str"] = youtube_dl.status.name + data["status_ko"] = str(youtube_dl.status) + data["end_time"] = "" + data["extractor"] = youtube_dl.type + ( + " - " + youtube_dl.info_dict["extractor"] + if youtube_dl.info_dict["extractor"] is not None + else "" + ) + data["title"] = ( + youtube_dl.info_dict["title"] + if youtube_dl.info_dict["title"] is not None + else youtube_dl.url + ) + data["uploader"] = ( + youtube_dl.info_dict["uploader"] + if youtube_dl.info_dict["uploader"] is not None + else "" + ) + data["uploader_url"] = ( + youtube_dl.info_dict["uploader_url"] + if youtube_dl.info_dict["uploader_url"] is not None + else "" + ) + data["downloaded_bytes_str"] = "" + data["total_bytes_str"] = "" + data["percent"] = "0" + data["eta"] = ( + youtube_dl.progress_hooks["eta"] + if youtube_dl.progress_hooks["eta"] is not None + else "" + ) + data["speed_str"] = ( + LogicNormal.human_readable_size( + youtube_dl.progress_hooks["speed"], "/s" + ) + if youtube_dl.progress_hooks["speed"] is not None + else "" + ) if youtube_dl.status == Status.READY: # 다운로드 전 - data['start_time'] = '' - data['download_time'] = '' + data["start_time"] = "" + data["download_time"] = "" else: if youtube_dl.end_time is None: # 완료 전 download_time = datetime.now() - youtube_dl.start_time else: download_time = youtube_dl.end_time - youtube_dl.start_time - data['end_time'] = youtube_dl.end_time.strftime('%m-%d %H:%M:%S') - if None not in (youtube_dl.progress_hooks['downloaded_bytes'], - youtube_dl.progress_hooks['total_bytes']): # 둘 다 값이 있으면 - data['downloaded_bytes_str'] = LogicNormal.human_readable_size( - youtube_dl.progress_hooks['downloaded_bytes'] + data["end_time"] = youtube_dl.end_time.strftime("%m-%d %H:%M:%S") + if None not in ( + youtube_dl.progress_hooks["downloaded_bytes"], + youtube_dl.progress_hooks["total_bytes"], + ): # 둘 다 값이 있으면 + data["downloaded_bytes_str"] = LogicNormal.human_readable_size( + youtube_dl.progress_hooks["downloaded_bytes"] ) - data['total_bytes_str'] = LogicNormal.human_readable_size(youtube_dl.progress_hooks['total_bytes']) - data['percent'] = '%.2f' % (float(youtube_dl.progress_hooks['downloaded_bytes']) - / float(youtube_dl.progress_hooks['total_bytes']) * 100) - data['start_time'] = youtube_dl.start_time.strftime('%m-%d %H:%M:%S') - data['download_time'] = '%02d:%02d' % (download_time.seconds / 60, download_time.seconds % 60) + data["total_bytes_str"] = LogicNormal.human_readable_size( + youtube_dl.progress_hooks["total_bytes"] + ) + data[ + "percent" + ] = f"{float(youtube_dl.progress_hooks['downloaded_bytes']) / float(youtube_dl.progress_hooks['total_bytes']) * 100:.2f}" + data["start_time"] = youtube_dl.start_time.strftime("%m-%d %H:%M:%S") + data[ + "download_time" + ] = f"{download_time.seconds / 60:02d}:{download_time.seconds % 60:02d}" return data except Exception as e: - logger.error('Exception:%s', e) + logger.error("Exception:%s", e) logger.error(traceback.format_exc()) return None @@ -277,14 +327,14 @@ class LogicNormal(object): return MyYoutubeDL.get_info_dict(url, proxy) @staticmethod - def human_readable_size(size, suffix=''): - for unit in ('Bytes', 'KB', 'MB', 'GB', 'TB', 'PB', 'EB', 'ZB'): + def human_readable_size(size, suffix=""): + for unit in ("Bytes", "KB", "MB", "GB", "TB", "PB", "EB", "ZB"): if size < 1024.0: - return '%3.1f %s%s' % (size, unit, suffix) + return f"{size:3.1f} {unit}{suffix}" size /= 1024.0 - return '%.1f %s%s' % (size, 'YB', suffix) + return f"{size:.1f} YB{suffix}" @staticmethod def abort(base, code): - base['errorCode'] = code + base["errorCode"] = code return jsonify(base) diff --git a/model.py b/model.py index 022392f..6af0b0e 100644 --- a/model.py +++ b/model.py @@ -5,14 +5,16 @@ from framework import app, db, path_data from framework.logger import get_logger from framework.util import Util -package_name = __name__.split('.')[0] +package_name = __name__.split(".", maxsplit=1)[0] logger = get_logger(package_name) -app.config['SQLALCHEMY_BINDS'][package_name] = 'sqlite:///%s' % (os.path.join(path_data, 'db', '%s.db' % package_name)) +app.config["SQLALCHEMY_BINDS"][package_name] = "sqlite:///%s" % ( + os.path.join(path_data, "db", f"{package_name}.db") +) class ModelSetting(db.Model): - __tablename__ = '%s_setting' % package_name - __table_args__ = {'mysql_collate': 'utf8_general_ci'} + __tablename__ = f"{package_name}_setting" + __table_args__ = {"mysql_collate": "utf8_general_ci"} __bind_key__ = package_name id = db.Column(db.Integer, primary_key=True) @@ -32,9 +34,11 @@ class ModelSetting(db.Model): @staticmethod def get(key): try: - return db.session.query(ModelSetting).filter_by(key=key).first().value.strip() + return ( + db.session.query(ModelSetting).filter_by(key=key).first().value.strip() + ) except Exception as e: - logger.error('Exception:%s %s', e, key) + logger.error("Exception:%s %s", e, key) logger.error(traceback.format_exc()) @staticmethod @@ -42,54 +46,64 @@ class ModelSetting(db.Model): try: return int(ModelSetting.get(key)) except Exception as e: - logger.error('Exception:%s %s', e, key) + logger.error("Exception:%s %s", e, key) logger.error(traceback.format_exc()) @staticmethod def get_bool(key): try: - return ModelSetting.get(key) == 'True' + return ModelSetting.get(key) == "True" except Exception as e: - logger.error('Exception:%s %s', e, key) + logger.error("Exception:%s %s", e, key) logger.error(traceback.format_exc()) @staticmethod def set(key, value): try: - item = db.session.query(ModelSetting).filter_by(key=key).with_for_update().first() + item = ( + db.session.query(ModelSetting) + .filter_by(key=key) + .with_for_update() + .first() + ) if item is not None: item.value = value.strip() db.session.commit() else: db.session.add(ModelSetting(key, value.strip())) except Exception as e: - logger.error('Exception:%s', e) + logger.error("Exception:%s", e) logger.error(traceback.format_exc()) - logger.error('Error Key:%s Value:%s', key, value) + logger.error("Error Key:%s Value:%s", key, value) @staticmethod def to_dict(): try: return Util.db_list_to_dict(db.session.query(ModelSetting).all()) except Exception as e: - logger.error('Exception:%s', e) + logger.error("Exception:%s", e) logger.error(traceback.format_exc()) @staticmethod def setting_save(req): try: for key, value in req.form.items(): - if key in ['scheduler', 'is_running']: + if key in ["scheduler", "is_running"]: continue - if key.startswith('tmp_'): + if key.startswith("tmp_"): continue - logger.debug('Key:%s Value:%s', key, value) - entity = db.session.query(ModelSetting).filter_by(key=key).with_for_update().first() + logger.debug("Key:%s Value:%s", key, value) + entity = ( + db.session.query(ModelSetting) + .filter_by(key=key) + .with_for_update() + .first() + ) entity.value = value db.session.commit() return True except Exception as e: - logger.error('Exception:%s', e) + logger.error("Exception:%s", e) logger.error(traceback.format_exc()) return False @@ -97,9 +111,9 @@ class ModelSetting(db.Model): def get_list(key): try: value = ModelSetting.get(key) - values = [x.strip().strip() for x in value.replace('\n', '|').split('|')] + values = [x.strip().strip() for x in value.replace("\n", "|").split("|")] values = Util.get_list_except_empty(values) return values except Exception as e: - logger.error('Exception:%s %s', e, key) + logger.error("Exception:%s %s", e, key) logger.error(traceback.format_exc()) diff --git a/my_youtube_dl.py b/my_youtube_dl.py index 2ef22ec..f4d0ed3 100644 --- a/my_youtube_dl.py +++ b/my_youtube_dl.py @@ -3,7 +3,6 @@ from __future__ import unicode_literals import os import traceback import tempfile -import json from glob import glob from datetime import datetime from threading import Thread @@ -12,7 +11,7 @@ from enum import Enum from framework.logger import get_logger import framework.common.celery as celery_shutil -package_name = __name__.split('.')[0] +package_name = __name__.split(".", maxsplit=1)[0] logger = get_logger(package_name) @@ -26,30 +25,33 @@ class Status(Enum): COMPLETED = 6 def __str__(self): - str_list = [ - '준비', - '분석중', - '다운로드중', - '실패', - '변환중', - '중지', - '완료' - ] + str_list = ["??", "???", "?????", "??", "???", "??", "??"] return str_list[self.value] class MyYoutubeDL(object): - DEFAULT_FILENAME = '%(title)s-%(id)s.%(ext)s' + DEFAULT_FILENAME = "%(title)s-%(id)s.%(ext)s" _index = 0 - _last_msg = '' - def __init__(self, plugin, type_name, url, filename, temp_path, save_path=None, opts=None, dateafter=None, - datebefore=None): + def __init__( + self, + plugin, + type_name, + url, + filename, + temp_path, + save_path=None, + opts=None, + dateafter=None, + datebefore=None, + ): # from youtube_dl.utils import DateRange from .plugin import youtube_dl_package - DateRange = __import__('%s.utils' % youtube_dl_package, fromlist=[ - 'DateRange']).DateRange + + DateRange = __import__( + f"{youtube_dl_package}.utils", fromlist=["DateRange"] + ).DateRange if save_path is None: save_path = temp_path @@ -61,13 +63,13 @@ class MyYoutubeDL(object): self.filename = filename if not os.path.isdir(temp_path): os.makedirs(temp_path) - self.temp_path = tempfile.mkdtemp(prefix='youtube-dl_', dir=temp_path) + self.temp_path = tempfile.mkdtemp(prefix="youtube-dl_", dir=temp_path) if not os.path.isdir(save_path): os.makedirs(save_path) self.save_path = save_path self.opts = opts if dateafter or datebefore: - self.opts['daterange'] = DateRange(start=dateafter, end=datebefore) + self.opts["daterange"] = DateRange(start=dateafter, end=datebefore) self.index = MyYoutubeDL._index MyYoutubeDL._index += 1 self._status = Status.READY @@ -77,10 +79,10 @@ class MyYoutubeDL(object): self.end_time = None # 종료 시간 # info_dict에서 얻는 정보 self.info_dict = { - 'extractor': None, # 타입 - 'title': None, # 제목 - 'uploader': None, # 업로더 - 'uploader_url': None # 업로더 주소 + "extractor": None, # ?? + "title": None, # ?? + "uploader": None, # ??? + "uploader_url": None, # ??? ?? } # info_dict에서 얻는 정보(entries) # self.info_dict['playlist_index'] = None @@ -89,10 +91,10 @@ class MyYoutubeDL(object): # self.info_dict['thumbnail'] = None # 썸네일 # progress_hooks에서 얻는 정보 self.progress_hooks = { - 'downloaded_bytes': None, # 다운로드한 크기 - 'total_bytes': None, # 전체 크기 - 'eta': None, # 예상 시간(s) - 'speed': None # 다운로드 속도(bytes/s) + "downloaded_bytes": None, # ????? ?? + "total_bytes": None, # ?? ?? + "eta": None, # ?? ??(s) + "speed": None, # ???? ??(bytes/s) } def start(self): @@ -105,34 +107,36 @@ class MyYoutubeDL(object): def run(self): # import youtube_dl from .plugin import youtube_dl_package - youtube_dl = __import__('%s' % youtube_dl_package) + + youtube_dl = __import__(youtube_dl_package) try: self.start_time = datetime.now() self.status = Status.START # 동영상 정보 가져오기 info_dict = MyYoutubeDL.get_info_dict( - self.url, self.opts.get('proxy'), self.opts.get('cookiefile')) + self.url, self.opts.get("proxy"), self.opts.get("cookiefile") + ) if info_dict is None: self.status = Status.ERROR return - self.info_dict['extractor'] = info_dict['extractor'] - self.info_dict['title'] = info_dict.get('title', info_dict['id']) - self.info_dict['uploader'] = info_dict.get('uploader', '') - self.info_dict['uploader_url'] = info_dict.get('uploader_url', '') + self.info_dict["extractor"] = info_dict["extractor"] + self.info_dict["title"] = info_dict.get("title", info_dict["id"]) + self.info_dict["uploader"] = info_dict.get("uploader", "") + self.info_dict["uploader_url"] = info_dict.get("uploader_url", "") ydl_opts = { - 'logger': MyLogger(), - 'progress_hooks': [self.my_hook], + "logger": MyLogger(), + "progress_hooks": [self.my_hook], # 'match_filter': self.match_filter_func, - 'outtmpl': os.path.join(self.temp_path, self.filename), - 'ignoreerrors': True, - 'cachedir': False + "outtmpl": os.path.join(self.temp_path, self.filename), + "ignoreerrors": True, + "cachedir": False, } ydl_opts.update(self.opts) with youtube_dl.YoutubeDL(ydl_opts) as ydl: ydl.download([self.url]) if self.status in (Status.START, Status.FINISHED): # 다운로드 성공 - for i in glob(self.temp_path + '/**/*', recursive=True): + for i in glob(self.temp_path + "/**/*", recursive=True): path = i.replace(self.temp_path, self.save_path, 1) if os.path.isdir(i): if not os.path.isdir(path): @@ -142,7 +146,7 @@ class MyYoutubeDL(object): self.status = Status.COMPLETED except Exception as e: self.status = Status.ERROR - logger.error('Exception:%s', e) + logger.error("Exception:%s", e) logger.error(traceback.format_exc()) finally: # 임시폴더 삭제 @@ -161,8 +165,10 @@ class MyYoutubeDL(object): def get_version(): # from youtube_dl.version import __version__ from .plugin import youtube_dl_package - __version__ = __import__('%s.version' % youtube_dl_package, fromlist=[ - '__version__']).__version__ + + __version__ = __import__( + f"{youtube_dl_package}.version", fromlist=["__version__"] + ).__version__ return __version__ @@ -170,21 +176,19 @@ class MyYoutubeDL(object): def get_info_dict(url, proxy=None, cookiefile=None): # import youtube_dl from .plugin import youtube_dl_package - youtube_dl = __import__('%s' % youtube_dl_package) + + youtube_dl = __import__(youtube_dl_package) try: - ydl_opts = { - 'extract_flat': 'in_playlist', - 'logger': MyLogger() - } + ydl_opts = {"extract_flat": "in_playlist", "logger": MyLogger()} if proxy: - ydl_opts['proxy'] = proxy + ydl_opts["proxy"] = proxy if cookiefile: - ydl_opts['cookiefile'] = cookiefile + ydl_opts["cookiefile"] = cookiefile with youtube_dl.YoutubeDL(ydl_opts) as ydl: info = ydl.extract_info(url, download=False) except Exception as e: - logger.error('Exception:%s', e) + logger.error("Exception:%s", e) logger.error(traceback.format_exc()) return None return info @@ -192,22 +196,22 @@ class MyYoutubeDL(object): def my_hook(self, d): if self.status != Status.STOP: self.status = { - 'downloading': Status.DOWNLOADING, - 'error': Status.ERROR, - 'finished': Status.FINISHED # 다운로드 완료. 변환 시작 - }[d['status']] - if d['status'] != 'error': - self.filename = os.path.basename(d.get('filename')) - self.progress_hooks['downloaded_bytes'] = d.get('downloaded_bytes') - self.progress_hooks['total_bytes'] = d.get('total_bytes') - self.progress_hooks['eta'] = d.get('eta') - self.progress_hooks['speed'] = d.get('speed') + "downloading": Status.DOWNLOADING, + "error": Status.ERROR, + "finished": Status.FINISHED, # ???? ??. ?? ?? + }[d["status"]] + if d["status"] != "error": + self.filename = os.path.basename(d.get("filename")) + self.progress_hooks["downloaded_bytes"] = d.get("downloaded_bytes") + self.progress_hooks["total_bytes"] = d.get("total_bytes") + self.progress_hooks["eta"] = d.get("eta") + self.progress_hooks["speed"] = d.get("speed") def match_filter_func(self, info_dict): - self.info_dict['playlist_index'] = info_dict['playlist_index'] - self.info_dict['duration'] = info_dict['duration'] - self.info_dict['format'] = info_dict['format'] - self.info_dict['thumbnail'] = info_dict['thumbnail'] + self.info_dict["playlist_index"] = info_dict["playlist_index"] + self.info_dict["duration"] = info_dict["duration"] + self.info_dict["format"] = info_dict["format"] + self.info_dict["thumbnail"] = info_dict["thumbnail"] return None @property @@ -219,13 +223,12 @@ class MyYoutubeDL(object): from .plugin import socketio_emit self._status = value - socketio_emit('status', self) + socketio_emit("status", self) class MyLogger(object): def debug(self, msg): - MyYoutubeDL._last_msg = msg - if msg.find('') != -1 or msg.find('{') != -1: + if msg.find("\x1B") != -1 or msg.find("{") != -1: # 과도한 로그 방지 return logger.debug(msg) diff --git a/plugin.py b/plugin.py index d700056..7f6c4e6 100644 --- a/plugin.py +++ b/plugin.py @@ -13,38 +13,47 @@ from .logic import Logic from .logic_normal import LogicNormal from .model import ModelSetting -package_name = __name__.split('.')[0] +package_name = __name__.split(".", maxsplit=1)[0] logger = get_logger(package_name) youtube_dl_package = LogicNormal.get_youtube_dl_package( - ModelSetting.get('youtube_dl_package') if ModelSetting.get('youtube_dl_package') else Logic.db_default[ - 'youtube_dl_package'], import_pkg=True) + ModelSetting.get("youtube_dl_package") + if ModelSetting.get("youtube_dl_package") + else Logic.db_default["youtube_dl_package"], + import_pkg=True, +) ######################################################### # 플러그인 공용 ######################################################### -blueprint = Blueprint(package_name, package_name, url_prefix='/%s' % package_name, - template_folder=os.path.join( - os.path.dirname(__file__), 'templates'), - static_folder=os.path.join(os.path.dirname(__file__), 'static')) +blueprint = Blueprint( + package_name, + package_name, + url_prefix=f"/{package_name}", + template_folder=os.path.join(os.path.dirname(__file__), "templates"), + static_folder=os.path.join(os.path.dirname(__file__), "static"), +) menu = { - 'main': [package_name, 'youtube-dl'], - 'sub': [ - ['setting', '설정'], ['download', '다운로드'], ['thumbnail', - '썸네일 다운로드'], ['sub', '자막 다운로드'], ['list', '목록'], - ['log', '로그'] + "main": [package_name, "youtube-dl"], + "sub": [ + ["setting", "설정"], + ["download", "다운로드"], + ["thumbnail", "썸네일 다운로드"], + ["sub", "자막 다운로드"], + ["list", "목록"], + ["log", "로그"], ], - 'category': 'vod' + "category": "vod", } plugin_info = { - 'version': '3.1.0', - 'name': 'youtube-dl', - 'category_name': 'vod', - 'developer': 'joyfuI', - 'description': '유튜브, 네이버TV 등 동영상 사이트에서 동영상 다운로드', - 'home': 'https://github.com/joyfuI/youtube-dl', - 'more': '' + "version": "3.1.0", + "name": "youtube-dl", + "category_name": "vod", + "developer": "joyfuI", + "description": "유튜브, 네이버TV 등 동영상 사이트에서 동영상 다운로드", + "home": "https://github.com/joyfuI/youtube-dl", + "more": "", } @@ -59,79 +68,91 @@ def plugin_unload(): ######################################################### # WEB Menu ######################################################### -@blueprint.route('/') +@blueprint.route("/") def home(): - return redirect('/%s/list' % package_name) + return redirect(f"/{package_name}/list") -@blueprint.route('/') +@blueprint.route("/") @login_required def first_menu(sub): try: arg = { - 'package_name': package_name, - 'template_name': '%s_%s' % (package_name, sub) + "package_name": package_name, + "template_name": f"{package_name}_{sub}", } - if sub == 'setting': + if sub == "setting": arg.update(ModelSetting.to_dict()) - arg['package_list'] = LogicNormal.get_youtube_dl_package() - arg['youtube_dl_version'] = LogicNormal.get_youtube_dl_version() - arg['DEFAULT_FILENAME'] = LogicNormal.get_default_filename() - return render_template('%s_%s.html' % (package_name, sub), arg=arg) + arg["package_list"] = LogicNormal.get_youtube_dl_package() + arg["youtube_dl_version"] = LogicNormal.get_youtube_dl_version() + arg["DEFAULT_FILENAME"] = LogicNormal.get_default_filename() + return render_template(f"{package_name}_{sub}.html", arg=arg) - elif sub == 'download': - default_filename = ModelSetting.get('default_filename') - arg['filename'] = default_filename if default_filename else LogicNormal.get_default_filename() - arg['preset_list'] = LogicNormal.get_preset_list() - arg['postprocessor_list'] = LogicNormal.get_postprocessor_list() - return render_template('%s_%s.html' % (package_name, sub), arg=arg) + elif sub == "download": + default_filename = ModelSetting.get("default_filename") + arg["filename"] = ( + default_filename + if default_filename + else LogicNormal.get_default_filename() + ) + arg["preset_list"] = LogicNormal.get_preset_list() + arg["postprocessor_list"] = LogicNormal.get_postprocessor_list() + return render_template(f"{package_name}_{sub}.html", arg=arg) - elif sub == 'thumbnail': - default_filename = ModelSetting.get('default_filename') - arg['filename'] = default_filename if default_filename else LogicNormal.get_default_filename() - return render_template('%s_%s.html' % (package_name, sub), arg=arg) + elif sub == "thumbnail": + default_filename = ModelSetting.get("default_filename") + arg["filename"] = ( + default_filename + if default_filename + else LogicNormal.get_default_filename() + ) + return render_template(f"{package_name}_{sub}.html", arg=arg) - elif sub == 'sub': - default_filename = ModelSetting.get('default_filename') - arg['filename'] = default_filename if default_filename else LogicNormal.get_default_filename() - return render_template('%s_%s.html' % (package_name, sub), arg=arg) + elif sub == "sub": + default_filename = ModelSetting.get("default_filename") + arg["filename"] = ( + default_filename + if default_filename + else LogicNormal.get_default_filename() + ) + return render_template(f"{package_name}_{sub}.html", arg=arg) - elif sub == 'list': - return render_template('%s_%s.html' % (package_name, sub), arg=arg) + elif sub == "list": + return render_template(f"{package_name}_{sub}.html", arg=arg) - elif sub == 'log': - return render_template('log.html', package=package_name) + elif sub == "log": + return render_template("log.html", package=package_name) except Exception as e: - logger.error('Exception:%s', e) + logger.error("Exception:%s", e) logger.error(traceback.format_exc()) - return render_template('sample.html', title='%s - %s' % (package_name, sub)) + return render_template("sample.html", title=f"{package_name} - {sub}") ######################################################### # For UI ######################################################### -@blueprint.route('/ajax/', methods=['POST']) +@blueprint.route("/ajax/", methods=["POST"]) @login_required def ajax(sub): - logger.debug('AJAX %s %s', package_name, sub) + logger.debug("AJAX %s %s", package_name, sub) try: # 공통 요청 - if sub == 'setting_save': + if sub == "setting_save": ret = ModelSetting.setting_save(request) - if request.form['ffmpeg_path'] == 'ffmpeg': - ModelSetting.set('ffmpeg_path', '') + if request.form["ffmpeg_path"] == "ffmpeg": + ModelSetting.set("ffmpeg_path", "") return jsonify(ret) # UI 요청 - elif sub == 'ffmpeg_version': - path = request.form['path'] - ret = subprocess.check_output([path, '-version']) - ret = ret.decode().replace('\n', '
') + elif sub == "ffmpeg_version": + path = request.form["path"] + ret = subprocess.check_output([path, "-version"]) + ret = ret.decode().replace("\n", "
") return jsonify(ret) - elif sub == 'download': - postprocessor = request.form['postprocessor'] + elif sub == "download": + postprocessor = request.form["postprocessor"] video_convertor, extract_audio = LogicNormal.get_postprocessor() preferedformat = None preferredcodec = None @@ -141,56 +162,56 @@ def ajax(sub): elif postprocessor in extract_audio: preferredcodec = postprocessor preferredquality = 192 - youtube_dl = LogicNormal.download(plugin=package_name, - url=request.form['url'], - filename=request.form['filename'], - temp_path=ModelSetting.get( - 'temp_path'), - save_path=ModelSetting.get( - 'save_path'), - format=request.form['format'], - preferedformat=preferedformat, - preferredcodec=preferredcodec, - preferredquality=preferredquality, - proxy=ModelSetting.get('proxy'), - ffmpeg_path=ModelSetting.get('ffmpeg_path')) + youtube_dl = LogicNormal.download( + plugin=package_name, + url=request.form["url"], + filename=request.form["filename"], + temp_path=ModelSetting.get("temp_path"), + save_path=ModelSetting.get("save_path"), + format=request.form["format"], + preferedformat=preferedformat, + preferredcodec=preferredcodec, + preferredquality=preferredquality, + proxy=ModelSetting.get("proxy"), + ffmpeg_path=ModelSetting.get("ffmpeg_path"), + ) youtube_dl.start() - socketio_emit('add', youtube_dl) + socketio_emit("add", youtube_dl) return jsonify([]) - elif sub == 'thumbnail': - youtube_dl = LogicNormal.thumbnail(plugin=package_name, - url=request.form['url'], - filename=request.form['filename'], - temp_path=ModelSetting.get( - 'temp_path'), - save_path=ModelSetting.get( - 'save_path'), - all_thumbnails=request.form['all_thumbnails'], - proxy=ModelSetting.get('proxy'), - ffmpeg_path=ModelSetting.get('ffmpeg_path')) + elif sub == "thumbnail": + youtube_dl = LogicNormal.thumbnail( + plugin=package_name, + url=request.form["url"], + filename=request.form["filename"], + temp_path=ModelSetting.get("temp_path"), + save_path=ModelSetting.get("save_path"), + all_thumbnails=request.form["all_thumbnails"], + proxy=ModelSetting.get("proxy"), + ffmpeg_path=ModelSetting.get("ffmpeg_path"), + ) youtube_dl.start() - socketio_emit('add', youtube_dl) + socketio_emit("add", youtube_dl) return jsonify([]) - elif sub == 'sub': - youtube_dl = LogicNormal.sub(plugin=package_name, - url=request.form['url'], - filename=request.form['filename'], - temp_path=ModelSetting.get( - 'temp_path'), - save_path=ModelSetting.get( - 'save_path'), - all_subs=request.form['all_subs'], - sub_lang=request.form['sub_lang'], - auto_sub=request.form['auto_sub'], - proxy=ModelSetting.get('proxy'), - ffmpeg_path=ModelSetting.get('ffmpeg_path')) + elif sub == "sub": + youtube_dl = LogicNormal.sub( + plugin=package_name, + url=request.form["url"], + filename=request.form["filename"], + temp_path=ModelSetting.get("temp_path"), + save_path=ModelSetting.get("save_path"), + all_subs=request.form["all_subs"], + sub_lang=request.form["sub_lang"], + auto_sub=request.form["auto_sub"], + proxy=ModelSetting.get("proxy"), + ffmpeg_path=ModelSetting.get("ffmpeg_path"), + ) youtube_dl.start() - socketio_emit('add', youtube_dl) + socketio_emit("add", youtube_dl) return jsonify([]) - elif sub == 'list': + elif sub == "list": ret = [] for i in LogicNormal.youtube_dl_list: data = LogicNormal.get_data(i) @@ -198,17 +219,17 @@ def ajax(sub): ret.append(data) return jsonify(ret) - elif sub == 'all_stop': + elif sub == "all_stop": for i in LogicNormal.youtube_dl_list: i.stop() return jsonify([]) - elif sub == 'stop': - index = int(request.form['index']) + elif sub == "stop": + index = int(request.form["index"]) LogicNormal.youtube_dl_list[index].stop() return jsonify([]) except Exception as e: - logger.error('Exception:%s', e) + logger.error("Exception:%s", e) logger.error(traceback.format_exc()) @@ -216,260 +237,257 @@ def ajax(sub): # API ######################################################### # API 명세는 https://github.com/joyfuI/youtube-dl#api -@blueprint.route('/api/', methods=['GET', 'POST']) +@blueprint.route("/api/", methods=["GET", "POST"]) @cross_origin() @check_api def api(sub): - plugin = request.values.get('plugin') - logger.debug('API %s %s: %s', package_name, sub, plugin) + plugin = request.values.get("plugin") + logger.debug("API %s %s: %s", package_name, sub, plugin) if not plugin: # 요청한 플러그인명이 빈문자열이거나 None면 abort(403) # 403 에러(거부) try: # 동영상 정보를 반환하는 API - if sub == 'info_dict': - url = request.values.get('url') - ret = { - 'errorCode': 0, - 'info_dict': None - } + if sub == "info_dict": + url = request.values.get("url") + ret = {"errorCode": 0, "info_dict": None} if None in (url,): return LogicNormal.abort(ret, 1) # 필수 요청 변수가 없음 - if not url.startswith('http'): + if not url.startswith("http"): return LogicNormal.abort(ret, 2) # 잘못된 동영상 주소 - info_dict = LogicNormal.get_info_dict( - url, ModelSetting.get('proxy')) + info_dict = LogicNormal.get_info_dict(url, ModelSetting.get("proxy")) if info_dict is None: return LogicNormal.abort(ret, 10) # 실패 - ret['info_dict'] = info_dict + ret["info_dict"] = info_dict return jsonify(ret) # 비디오 다운로드 준비를 요청하는 API - elif sub == 'download': - key = request.values.get('key') - url = request.values.get('url') + elif sub == "download": + key = request.values.get("key") + url = request.values.get("url") filename = request.values.get( - 'filename', ModelSetting.get('default_filename')) - save_path = request.values.get( - 'save_path', ModelSetting.get('save_path')) - format_code = request.values.get('format', None) - preferedformat = request.values.get('preferedformat', None) - preferredcodec = request.values.get('preferredcodec', None) - preferredquality = request.values.get('preferredquality', 192) - dateafter = request.values.get('dateafter', None) - playlist = request.values.get('playlist', None) - archive = request.values.get('archive', None) - start = request.values.get('start', False) - cookiefile = request.values.get('cookiefile', None) - ret = { - 'errorCode': 0, - 'index': None - } + "filename", ModelSetting.get("default_filename") + ) + save_path = request.values.get("save_path", ModelSetting.get("save_path")) + format_code = request.values.get("format", None) + preferedformat = request.values.get("preferedformat", None) + preferredcodec = request.values.get("preferredcodec", None) + preferredquality = request.values.get("preferredquality", 192) + dateafter = request.values.get("dateafter", None) + playlist = request.values.get("playlist", None) + archive = request.values.get("archive", None) + start = request.values.get("start", False) + cookiefile = request.values.get("cookiefile", None) + ret = {"errorCode": 0, "index": None} if None in (key, url): return LogicNormal.abort(ret, 1) # 필수 요청 변수가 없음 - if not url.startswith('http'): + if not url.startswith("http"): return LogicNormal.abort(ret, 2) # 잘못된 동영상 주소 - if preferredcodec not in (None, 'best', 'mp3', 'aac', 'flac', 'm4a', 'opus', 'vorbis', 'wav'): + if preferredcodec not in ( + None, + "best", + "mp3", + "aac", + "flac", + "m4a", + "opus", + "vorbis", + "wav", + ): return LogicNormal.abort(ret, 5) # 허용되지 않은 값이 있음 if not filename: filename = LogicNormal.get_default_filename() - youtube_dl = LogicNormal.download(plugin=plugin, - url=url, - filename=filename, - temp_path=ModelSetting.get( - 'temp_path'), - save_path=save_path, - format=format_code, - preferedformat=preferedformat, - preferredcodec=preferredcodec, - preferredquality=preferredquality, - dateafter=dateafter, - playlist=playlist, - archive=archive, - proxy=ModelSetting.get('proxy'), - ffmpeg_path=ModelSetting.get( - 'ffmpeg_path'), - key=key, - cookiefile=cookiefile) + youtube_dl = LogicNormal.download( + plugin=plugin, + url=url, + filename=filename, + temp_path=ModelSetting.get("temp_path"), + save_path=save_path, + format=format_code, + preferedformat=preferedformat, + preferredcodec=preferredcodec, + preferredquality=preferredquality, + dateafter=dateafter, + playlist=playlist, + archive=archive, + proxy=ModelSetting.get("proxy"), + ffmpeg_path=ModelSetting.get("ffmpeg_path"), + key=key, + cookiefile=cookiefile, + ) if youtube_dl is None: return LogicNormal.abort(ret, 10) # 실패 - ret['index'] = youtube_dl.index + ret["index"] = youtube_dl.index if start: youtube_dl.start() - socketio_emit('add', youtube_dl) + socketio_emit("add", youtube_dl) return jsonify(ret) # 썸네일 다운로드 준비를 요청하는 API - elif sub == 'thumbnail': - key = request.values.get('key') - url = request.values.get('url') + elif sub == "thumbnail": + key = request.values.get("key") + url = request.values.get("url") filename = request.values.get( - 'filename', ModelSetting.get('default_filename')) - save_path = request.values.get( - 'save_path', ModelSetting.get('save_path')) - all_thumbnails = request.values.get('all_thumbnails', False) - dateafter = request.values.get('dateafter', None) - playlist = request.values.get('playlist', None) - archive = request.values.get('archive', None) - start = request.values.get('start', False) - cookiefile = request.values.get('cookiefile', None) - ret = { - 'errorCode': 0, - 'index': None - } + "filename", ModelSetting.get("default_filename") + ) + save_path = request.values.get("save_path", ModelSetting.get("save_path")) + all_thumbnails = request.values.get("all_thumbnails", False) + dateafter = request.values.get("dateafter", None) + playlist = request.values.get("playlist", None) + archive = request.values.get("archive", None) + start = request.values.get("start", False) + cookiefile = request.values.get("cookiefile", None) + ret = {"errorCode": 0, "index": None} if None in (key, url): return LogicNormal.abort(ret, 1) # 필수 요청 변수가 없음 - if not url.startswith('http'): + if not url.startswith("http"): return LogicNormal.abort(ret, 2) # 잘못된 동영상 주소 if not filename: filename = LogicNormal.get_default_filename() - youtube_dl = LogicNormal.thumbnail(plugin=plugin, - url=url, - filename=filename, - temp_path=ModelSetting.get( - 'temp_path'), - save_path=save_path, - all_thumbnails=all_thumbnails, - dateafter=dateafter, - playlist=playlist, - archive=archive, - proxy=ModelSetting.get('proxy'), - ffmpeg_path=ModelSetting.get( - 'ffmpeg_path'), - key=key, - cookiefile=cookiefile) + youtube_dl = LogicNormal.thumbnail( + plugin=plugin, + url=url, + filename=filename, + temp_path=ModelSetting.get("temp_path"), + save_path=save_path, + all_thumbnails=all_thumbnails, + dateafter=dateafter, + playlist=playlist, + archive=archive, + proxy=ModelSetting.get("proxy"), + ffmpeg_path=ModelSetting.get("ffmpeg_path"), + key=key, + cookiefile=cookiefile, + ) if youtube_dl is None: return LogicNormal.abort(ret, 10) # 실패 - ret['index'] = youtube_dl.index + ret["index"] = youtube_dl.index if start: youtube_dl.start() - socketio_emit('add', youtube_dl) + socketio_emit("add", youtube_dl) return jsonify(ret) # 자막 다운로드 준비를 요청하는 API - elif sub == 'sub': - key = request.values.get('key') - url = request.values.get('url') + elif sub == "sub": + key = request.values.get("key") + url = request.values.get("url") filename = request.values.get( - 'filename', ModelSetting.get('default_filename')) - save_path = request.values.get( - 'save_path', ModelSetting.get('save_path')) - all_subs = request.values.get('all_subs', False) - sub_lang = request.values.get('sub_lang', 'ko') - auto_sub = request.values.get('all_subs', False) - dateafter = request.values.get('dateafter', None) - playlist = request.values.get('playlist', None) - archive = request.values.get('archive', None) - start = request.values.get('start', False) - cookiefile = request.values.get('cookiefile', None) - ret = { - 'errorCode': 0, - 'index': None - } + "filename", ModelSetting.get("default_filename") + ) + save_path = request.values.get("save_path", ModelSetting.get("save_path")) + all_subs = request.values.get("all_subs", False) + sub_lang = request.values.get("sub_lang", "ko") + auto_sub = request.values.get("all_subs", False) + dateafter = request.values.get("dateafter", None) + playlist = request.values.get("playlist", None) + archive = request.values.get("archive", None) + start = request.values.get("start", False) + cookiefile = request.values.get("cookiefile", None) + ret = {"errorCode": 0, "index": None} if None in (key, url): return LogicNormal.abort(ret, 1) # 필수 요청 변수가 없음 - if not url.startswith('http'): + if not url.startswith("http"): return LogicNormal.abort(ret, 2) # 잘못된 동영상 주소 if not filename: filename = LogicNormal.get_default_filename() - youtube_dl = LogicNormal.sub(plugin=plugin, - url=url, - filename=filename, - temp_path=ModelSetting.get( - 'temp_path'), - save_path=save_path, - all_subs=all_subs, - sub_lang=sub_lang, - auto_sub=auto_sub, - dateafter=dateafter, - playlist=playlist, - archive=archive, - proxy=ModelSetting.get('proxy'), - ffmpeg_path=ModelSetting.get( - 'ffmpeg_path'), - key=key, - cookiefile=cookiefile) + youtube_dl = LogicNormal.sub( + plugin=plugin, + url=url, + filename=filename, + temp_path=ModelSetting.get("temp_path"), + save_path=save_path, + all_subs=all_subs, + sub_lang=sub_lang, + auto_sub=auto_sub, + dateafter=dateafter, + playlist=playlist, + archive=archive, + proxy=ModelSetting.get("proxy"), + ffmpeg_path=ModelSetting.get("ffmpeg_path"), + key=key, + cookiefile=cookiefile, + ) if youtube_dl is None: return LogicNormal.abort(ret, 10) # 실패 - ret['index'] = youtube_dl.index + ret["index"] = youtube_dl.index if start: youtube_dl.start() - socketio_emit('add', youtube_dl) + socketio_emit("add", youtube_dl) return jsonify(ret) # 다운로드 시작을 요청하는 API - elif sub == 'start': - index = request.values.get('index') - key = request.values.get('key') - ret = { - 'errorCode': 0, - 'status': None - } + elif sub == "start": + index = request.values.get("index") + key = request.values.get("key") + ret = {"errorCode": 0, "status": None} if None in (index, key): return LogicNormal.abort(ret, 1) # 필수 요청 변수가 없음 index = int(index) - if not (0 <= index < len(LogicNormal.youtube_dl_list)): + if not 0 <= index < len(LogicNormal.youtube_dl_list): return LogicNormal.abort(ret, 3) # 인덱스 범위를 벗어남 youtube_dl = LogicNormal.youtube_dl_list[index] if youtube_dl.key != key: return LogicNormal.abort(ret, 4) # 키가 일치하지 않음 - ret['status'] = youtube_dl.status.name + ret["status"] = youtube_dl.status.name if not youtube_dl.start(): return LogicNormal.abort(ret, 10) # 실패 return jsonify(ret) # 다운로드 중지를 요청하는 API - elif sub == 'stop': - index = request.values.get('index') - key = request.values.get('key') - ret = { - 'errorCode': 0, - 'status': None - } + elif sub == "stop": + index = request.values.get("index") + key = request.values.get("key") + ret = {"errorCode": 0, "status": None} if None in (index, key): return LogicNormal.abort(ret, 1) # 필수 요청 변수가 없음 index = int(index) - if not (0 <= index < len(LogicNormal.youtube_dl_list)): + if not 0 <= index < len(LogicNormal.youtube_dl_list): return LogicNormal.abort(ret, 3) # 인덱스 범위를 벗어남 youtube_dl = LogicNormal.youtube_dl_list[index] if youtube_dl.key != key: return LogicNormal.abort(ret, 4) # 키가 일치하지 않음 - ret['status'] = youtube_dl.status.name + ret["status"] = youtube_dl.status.name if not youtube_dl.stop(): return LogicNormal.abort(ret, 10) # 실패 return jsonify(ret) # 현재 상태를 반환하는 API - elif sub == 'status': - index = request.values.get('index') - key = request.values.get('key') + elif sub == "status": + index = request.values.get("index") + key = request.values.get("key") ret = { - 'errorCode': 0, - 'status': None, - 'type': None, - 'start_time': None, - 'end_time': None, - 'temp_path': None, - 'save_path': None + "errorCode": 0, + "status": None, + "type": None, + "start_time": None, + "end_time": None, + "temp_path": None, + "save_path": None, } if None in (index, key): return LogicNormal.abort(ret, 1) # 필수 요청 변수가 없음 index = int(index) - if not (0 <= index < len(LogicNormal.youtube_dl_list)): + if not 0 <= index < len(LogicNormal.youtube_dl_list): return LogicNormal.abort(ret, 3) # 인덱스 범위를 벗어남 youtube_dl = LogicNormal.youtube_dl_list[index] if youtube_dl.key != key: return LogicNormal.abort(ret, 4) # 키가 일치하지 않음 - ret['status'] = youtube_dl.status.name - ret['type'] = youtube_dl.type - ret['start_time'] = youtube_dl.start_time.strftime('%Y-%m-%dT%H:%M:%S') if \ - youtube_dl.start_time is not None else None - ret['end_time'] = youtube_dl.end_time.strftime('%Y-%m-%dT%H:%M:%S') if \ - youtube_dl.end_time is not None else None - ret['temp_path'] = youtube_dl.temp_path - ret['save_path'] = youtube_dl.save_path + ret["status"] = youtube_dl.status.name + ret["type"] = youtube_dl.type + ret["start_time"] = ( + youtube_dl.start_time.strftime("%Y-%m-%dT%H:%M:%S") + if youtube_dl.start_time is not None + else None + ) + ret["end_time"] = ( + youtube_dl.end_time.strftime("%Y-%m-%dT%H:%M:%S") + if youtube_dl.end_time is not None + else None + ) + ret["temp_path"] = youtube_dl.temp_path + ret["save_path"] = youtube_dl.save_path return jsonify(ret) except Exception as e: - logger.error('Exception:%s', e) + logger.error("Exception:%s", e) logger.error(traceback.format_exc()) abort(500) # 500 에러(서버 오류) abort(404) # 404 에러(페이지 없음) @@ -479,5 +497,6 @@ def api(sub): # socketio ######################################################### def socketio_emit(cmd, data): - socketio.emit(cmd, LogicNormal.get_data(data), namespace='/%s' % - package_name, broadcast=True) + socketio.emit( + cmd, LogicNormal.get_data(data), namespace=f"/{package_name}", broadcast=True + ) diff --git a/static/youtube-dl_download.js b/static/youtube-dl_download.js index 1ff644b..0bae84b 100644 --- a/static/youtube-dl_download.js +++ b/static/youtube-dl_download.js @@ -1,4 +1,4 @@ -"use strict"; +'use strict'; const url = document.getElementById('url'); const preset = document.getElementById('preset'); @@ -8,41 +8,44 @@ const download_btn = document.getElementById('download_btn'); // 프리셋 변경 preset.addEventListener('change', () => { - if (preset.value !== '_custom') { - format.value = preset.value; - } + if (preset.value !== '_custom') { + format.value = preset.value; + } }); format.addEventListener('input', () => { - preset.value = '_custom'; + preset.value = '_custom'; }); // 후처리 변경 postprocessor.addEventListener('change', () => { - const select = postprocessor.selectedOptions[0]; - if (select.parentElement.label === '오디오 추출') { - preset.value = 'bestaudio/best'; - format.value = preset.value; - } + const select = postprocessor.selectedOptions[0]; + if (select.parentElement.label === '오디오 추출') { + preset.value = 'bestaudio/best'; + format.value = preset.value; + } }); // 다운로드 download_btn.addEventListener('click', (event) => { - event.preventDefault(); - if (!url.value.startsWith('http')) { - notify('URL을 입력하세요.', 'warning'); - return; - } + event.preventDefault(); + if (!url.value.startsWith('http')) { + notify('URL을 입력하세요.', 'warning'); + return; + } - fetch(`/${package_name}/ajax/download`, { - method: 'POST', - cache: 'no-cache', - headers: { - 'Content-Type': 'application/x-www-form-urlencoded; charset=UTF-8' - }, - body: get_formdata('#download') - }).then(response => response.json()).then(() => { - notify('분석중..', 'info'); - }).catch(() => { - notify('다운로드 요청 실패', 'danger'); + fetch(`/${package_name}/ajax/download`, { + method: 'POST', + cache: 'no-cache', + headers: { + 'Content-Type': 'application/x-www-form-urlencoded; charset=UTF-8', + }, + body: get_formdata('#download'), + }) + .then((response) => response.json()) + .then(() => { + notify('분석중..', 'info'); + }) + .catch(() => { + notify('다운로드 요청 실패', 'danger'); }); }); diff --git a/static/youtube-dl_list.css b/static/youtube-dl_list.css index 47216be..1e940ba 100644 --- a/static/youtube-dl_list.css +++ b/static/youtube-dl_list.css @@ -1,26 +1,26 @@ .row > div { - padding-top: 3px; - padding-bottom: 3px; + padding-top: 3px; + padding-bottom: 3px; } .row { - align-items: center; - word-break: break-all; + align-items: center; + word-break: break-all; } .row > div:nth-child(odd) { - text-align: right; + text-align: right; } .row > div:nth-child(even) { - text-align: left; + text-align: left; } .cursor-pointer { - cursor: pointer; + cursor: pointer; } .info-padding { - padding-left: 10px; - padding-top: 3px; + padding-left: 10px; + padding-top: 3px; } diff --git a/static/youtube-dl_list.js b/static/youtube-dl_list.js index 5eb0b7f..116275b 100644 --- a/static/youtube-dl_list.js +++ b/static/youtube-dl_list.js @@ -1,4 +1,4 @@ -"use strict"; +'use strict'; const all_stop_btn = document.getElementById('all_stop_btn'); const list_tbody = document.getElementById('list_tbody'); @@ -6,134 +6,147 @@ const list_tbody = document.getElementById('list_tbody'); // 소켓 const socket = io.connect(`${location.origin}/${package_name}`); socket.on('add', (data) => { - list_tbody.innerHTML += make_item(data); + list_tbody.innerHTML += make_item(data); }); socket.on('status', (data) => { - status_html(data); + status_html(data); }); // 목록 불러오기 fetch(`/${package_name}/ajax/list`, { - method: 'POST', - cache: 'no-cache', - headers: { - 'Content-Type': 'application/x-www-form-urlencoded; charset=UTF-8' - } -}).then(response => response.json()).then((data) => { + method: 'POST', + cache: 'no-cache', + headers: { + 'Content-Type': 'application/x-www-form-urlencoded; charset=UTF-8', + }, +}) + .then((response) => response.json()) + .then((data) => { let str = ''; for (const item of data) { - str += make_item(item); + str += make_item(item); } list_tbody.innerHTML = str; -}); + }); // 전체 중지 all_stop_btn.addEventListener('click', (event) => { - event.preventDefault(); - fetch(`/${package_name}/ajax/all_stop`, { - method: 'POST', - cache: 'no-cache', - headers: { - 'Content-Type': 'application/x-www-form-urlencoded; charset=UTF-8' - } - }).then(response => response.json()).then(() => { - location.reload(); + event.preventDefault(); + fetch(`/${package_name}/ajax/all_stop`, { + method: 'POST', + cache: 'no-cache', + headers: { + 'Content-Type': 'application/x-www-form-urlencoded; charset=UTF-8', + }, + }) + .then((response) => response.json()) + .then(() => { + location.reload(); }); }); // 중지 list_tbody.addEventListener('click', (event) => { - event.preventDefault(); - const target = event.target; - if (!target.classList.contains('youtubeDl-stop')) { - return; - } - fetch(`/${package_name}/ajax/stop`, { - method: 'POST', - cache: 'no-cache', - headers: { - 'Content-Type': 'application/x-www-form-urlencoded; charset=UTF-8' - }, - body: new URLSearchParams({ - index: target.dataset.index - }) - }).then(response => response.json()).then(() => { - location.reload(); + event.preventDefault(); + const target = event.target; + if (!target.classList.contains('youtubeDl-stop')) { + return; + } + fetch(`/${package_name}/ajax/stop`, { + method: 'POST', + cache: 'no-cache', + headers: { + 'Content-Type': 'application/x-www-form-urlencoded; charset=UTF-8', + }, + body: new URLSearchParams({ + index: target.dataset.index, + }), + }) + .then((response) => response.json()) + .then(() => { + location.reload(); }); }); function make_item(data) { - let str = ``; - str += get_item(data); - str += ''; - str += ``; - str += ''; - str += `
`; - str += get_detail(data); - str += '
'; - str += ''; - str += ''; - return str; + let str = ``; + str += get_item(data); + str += ''; + str += ``; + str += ''; + str += `
`; + str += get_detail(data); + str += '
'; + str += ''; + str += ''; + return str; } function get_item(data) { - let str = `${data.index + 1}`; - str += `${data.plugin}`; - str += `${data.start_time}`; - str += `${data.extractor}`; - str += `${data.title}`; - str += `${data.status_ko}`; - let visi = 'hidden'; - if (parseInt(data.percent) > 0 && data.status_str !== 'STOP') { - visi = 'visible'; - } - str += `
${data.percent}%
`; - str += `${data.download_time}`; - str += ''; - if (data.status_str === 'START' || data.status_str === 'DOWNLOADING' || data.status_str === 'FINISHED') { - str += ``; - } - str += ''; - return str; + let str = `${data.index + 1}`; + str += `${data.plugin}`; + str += `${data.start_time}`; + str += `${data.extractor}`; + str += `${data.title}`; + str += `${data.status_ko}`; + let visi = 'hidden'; + if (parseInt(data.percent) > 0 && data.status_str !== 'STOP') { + visi = 'visible'; + } + str += `
${data.percent}%
`; + str += `${data.download_time}`; + str += ''; + if ( + data.status_str === 'START' || + data.status_str === 'DOWNLOADING' || + data.status_str === 'FINISHED' + ) { + str += ``; + } + str += ''; + return str; } function get_detail(data) { - let str = info_html('URL', data.url, data.url); - str += info_html('업로더', data.uploader, data.uploader_url); - str += info_html('임시폴더', data.temp_path); - str += info_html('저장폴더', data.save_path); - str += info_html('종료시간', data.end_time); - if (data.status_str === 'DOWNLOADING') { - str += info_html('', '현재 다운로드 중인 파일에 대한 정보'); - str += info_html('파일명', data.filename); - str += info_html('진행률(current/total)', `${data.percent}% (${data.downloaded_bytes_str} / ${data.total_bytes_str})`); - str += info_html('남은 시간', `${data.eta}초`); - str += info_html('다운 속도', data.speed_str); - } - return str; + let str = info_html('URL', data.url, data.url); + str += info_html('업로더', data.uploader, data.uploader_url); + str += info_html('임시폴더', data.temp_path); + str += info_html('저장폴더', data.save_path); + str += info_html('종료시간', data.end_time); + if (data.status_str === 'DOWNLOADING') { + str += info_html('', '현재 다운로드 중인 파일에 대한 정보'); + str += info_html('파일명', data.filename); + str += info_html( + '진행률(current/total)', + `${data.percent}% (${data.downloaded_bytes_str} / ${data.total_bytes_str})` + ); + str += info_html('남은 시간', `${data.eta}초`); + str += info_html('다운 속도', data.speed_str); + } + return str; } function info_html(left, right, option) { - let str = '
'; - const link = (left === 'URL' || left === '업로더'); - str += '
'; - str += `${left}`; - str += '
'; - str += '
'; - str += '
'; - str += ''; - if (link) { - str += ``; - } - str += right; - if (link) { - str += ''; - } - str += '
'; - return str; + let str = '
'; + const link = left === 'URL' || left === '업로더'; + str += '
'; + str += `${left}`; + str += '
'; + str += '
'; + str += '
'; + str += ''; + if (link) { + str += ``; + } + str += right; + if (link) { + str += ''; + } + str += '
'; + return str; } function status_html(data) { - document.getElementById(`item_${data.index}`).innerHTML = get_item(data); - document.getElementById(`detail_${data.index}`).innerHTML = get_detail(data); + document.getElementById(`item_${data.index}`).innerHTML = get_item(data); + document.getElementById(`detail_${data.index}`).innerHTML = get_detail(data); } diff --git a/static/youtube-dl_setting.js b/static/youtube-dl_setting.js index b97b65c..247592c 100644 --- a/static/youtube-dl_setting.js +++ b/static/youtube-dl_setting.js @@ -1,4 +1,4 @@ -"use strict"; +'use strict'; const ffmpeg_path = document.getElementById('ffmpeg_path'); const ffmpeg_version_btn = document.getElementById('ffmpeg_version_btn'); @@ -12,50 +12,63 @@ const modal_body = document.getElementById('modal_body'); // FFmpeg 버전확인 ffmpeg_version_btn.addEventListener('click', (event) => { - event.preventDefault(); - let ffmpeg = ffmpeg_path.value; - if (ffmpeg.length === 0) { - ffmpeg = 'ffmpeg'; - } + event.preventDefault(); + let ffmpeg = ffmpeg_path.value; + if (ffmpeg.length === 0) { + ffmpeg = 'ffmpeg'; + } - fetch(`/${package_name}/ajax/ffmpeg_version`, { - method: 'POST', - cache: 'no-cache', - headers: { - 'Content-Type': 'application/x-www-form-urlencoded; charset=UTF-8' - }, - body: new URLSearchParams({ - path: ffmpeg - }) - }).then(response => response.json()).then((data) => { - modal_title.innerHTML = `${ffmpeg} -version`; - modal_body.innerHTML = data; - $('#large_modal').modal(); - }).catch(() => { - notify('버전확인 실패', 'danger'); + fetch(`/${package_name}/ajax/ffmpeg_version`, { + method: 'POST', + cache: 'no-cache', + headers: { + 'Content-Type': 'application/x-www-form-urlencoded; charset=UTF-8', + }, + body: new URLSearchParams({ + path: ffmpeg, + }), + }) + .then((response) => response.json()) + .then((data) => { + modal_title.innerHTML = `${ffmpeg} -version`; + modal_body.innerHTML = data; + $('#large_modal').modal(); + }) + .catch(() => { + notify('버전확인 실패', 'danger'); }); }); // FFmpeg 파일 선택 ffmpeg_path_btn.addEventListener('click', (event) => { - event.preventDefault(); - m_select_local_file_modal('실행 파일 선택', '/', false, (result) => { - ffmpeg_path.value = result; - }); + event.preventDefault(); + m_select_local_file_modal('실행 파일 선택', '/', false, (result) => { + ffmpeg_path.value = result; + }); }); // 임시 폴더 경로 선택 temp_path_btn.addEventListener('click', (event) => { - event.preventDefault(); - m_select_local_file_modal("저장 경로 선택", temp_path.value, true, (result) => { - temp_path.value = result; - }); + event.preventDefault(); + m_select_local_file_modal( + '저장 경로 선택', + temp_path.value, + true, + (result) => { + temp_path.value = result; + } + ); }); // 저장 폴더 경로 선택 save_path_btn.addEventListener('click', (event) => { - event.preventDefault(); - m_select_local_file_modal("저장 경로 선택", save_path.value, true, (result) => { - save_path.value = result; - }); + event.preventDefault(); + m_select_local_file_modal( + '저장 경로 선택', + save_path.value, + true, + (result) => { + save_path.value = result; + } + ); }); diff --git a/static/youtube-dl_sub.js b/static/youtube-dl_sub.js index f5a166d..dc8d437 100644 --- a/static/youtube-dl_sub.js +++ b/static/youtube-dl_sub.js @@ -1,31 +1,34 @@ -"use strict"; +'use strict'; const url = document.getElementById('url'); const download_btn = document.getElementById('download_btn'); // 모든 자막 다운로드 $('#all_subs').change(() => { - use_collapse('all_subs', true); + use_collapse('all_subs', true); }); // 다운로드 download_btn.addEventListener('click', (event) => { - event.preventDefault(); - if (!url.value.startsWith('http')) { - notify('URL을 입력하세요.', 'warning'); - return; - } + event.preventDefault(); + if (!url.value.startsWith('http')) { + notify('URL을 입력하세요.', 'warning'); + return; + } - fetch(`/${package_name}/ajax/sub`, { - method: 'POST', - cache: 'no-cache', - headers: { - 'Content-Type': 'application/x-www-form-urlencoded; charset=UTF-8' - }, - body: get_formdata('#download') - }).then(response => response.json()).then(() => { - notify('분석중..', 'info'); - }).catch(() => { - notify('다운로드 요청 실패', 'danger'); + fetch(`/${package_name}/ajax/sub`, { + method: 'POST', + cache: 'no-cache', + headers: { + 'Content-Type': 'application/x-www-form-urlencoded; charset=UTF-8', + }, + body: get_formdata('#download'), + }) + .then((response) => response.json()) + .then(() => { + notify('분석중..', 'info'); + }) + .catch(() => { + notify('다운로드 요청 실패', 'danger'); }); }); diff --git a/static/youtube-dl_thumbnail.js b/static/youtube-dl_thumbnail.js index 0867ebb..0098cff 100644 --- a/static/youtube-dl_thumbnail.js +++ b/static/youtube-dl_thumbnail.js @@ -1,26 +1,29 @@ -"use strict"; +'use strict'; const url = document.getElementById('url'); const download_btn = document.getElementById('download_btn'); // 다운로드 download_btn.addEventListener('click', (event) => { - event.preventDefault(); - if (!url.value.startsWith('http')) { - notify('URL을 입력하세요.', 'warning'); - return; - } + event.preventDefault(); + if (!url.value.startsWith('http')) { + notify('URL을 입력하세요.', 'warning'); + return; + } - fetch(`/${package_name}/ajax/thumbnail`, { - method: 'POST', - cache: 'no-cache', - headers: { - 'Content-Type': 'application/x-www-form-urlencoded; charset=UTF-8' - }, - body: get_formdata('#download') - }).then(response => response.json()).then(() => { - notify('분석중..', 'info'); - }).catch(() => { - notify('다운로드 요청 실패', 'danger'); + fetch(`/${package_name}/ajax/thumbnail`, { + method: 'POST', + cache: 'no-cache', + headers: { + 'Content-Type': 'application/x-www-form-urlencoded; charset=UTF-8', + }, + body: get_formdata('#download'), + }) + .then((response) => response.json()) + .then(() => { + notify('분석중..', 'info'); + }) + .catch(() => { + notify('다운로드 요청 실패', 'danger'); }); }); diff --git a/templates/youtube-dl_list.html b/templates/youtube-dl_list.html index 472849d..9f48e03 100644 --- a/templates/youtube-dl_list.html +++ b/templates/youtube-dl_list.html @@ -1,34 +1,35 @@ -{% extends "base.html" %} -{% block content %} +{% extends "base.html" %} {% block content %} - + - {{ macros.m_row_start() }} - {{ macros.m_button('all_stop_btn', '전체 중지') }} - {{ macros.m_row_end() }} -
+{{ macros.m_row_start() }} {{ macros.m_button('all_stop_btn', '전체 중지') }} {{ +macros.m_row_end() }} +
- - - - - - - - - - - - - - - -
IDXPlugin시작시간타입제목상태진행률진행시간Action
+ + + + + + + + + + + + + + + +
IDXPlugin시작시간타입제목상태진행률진행시간Action
- - + + {% endblock %} diff --git a/templates/youtube-dl_setting.html b/templates/youtube-dl_setting.html index f25f5d5..ae6ed7c 100644 --- a/templates/youtube-dl_setting.html +++ b/templates/youtube-dl_setting.html @@ -1,21 +1,34 @@ -{% extends "base.html" %} -{% block content %} +{% extends "base.html" %} {% block content %} -
- {{ macros.setting_radio('youtube_dl_package', 'youtube-dl', arg['package_list'], value=arg['youtube_dl_package'], desc='사용할 youtube-dl 패키지를 선택합니다. 설정 저장 후 재시작이 필요합니다.') }} - {{ macros.setting_input_text('youtube_dl_version', 'youtube-dl 버전', value=arg['youtube_dl_version'], disabled=True) }} - {{ macros.setting_input_text_and_buttons('ffmpeg_path', 'FFmpeg 경로', [['ffmpeg_version_btn', '버전확인'], ['ffmpeg_path_btn', '파일 선택']], value=arg['ffmpeg_path'], placeholder='ffmpeg', desc='SJVA에 내장된 버전 말고 원하는 버전을 사용할 수 있습니다.') }} - {{ macros.setting_input_text_and_buttons('temp_path', '임시 폴더', [['temp_path_btn', '경로 선택']], value=arg['temp_path'], desc='다운로드 파일이 임시로 저장될 폴더입니다.') }} - {{ macros.setting_input_text_and_buttons('save_path', '저장 폴더', [['save_path_btn', '경로 선택']], value=arg['save_path'], desc='정상적으로 완료된 파일이 이동할 폴더입니다.') }} - {{ macros.setting_input_text('default_filename', '기본 파일명', value=arg['default_filename'], placeholder=arg['DEFAULT_FILENAME'], desc='템플릿 규칙은 https://github.com/ytdl-org/youtube-dl/#output-template 참고') }} - {{ macros.setting_input_text('proxy', '프록시', value=arg['proxy'], desc=['HTTP/HTTPS/SOCKS를 지원합니다. 예) socks5://127.0.0.1:1080/', '빈칸으로 두면 프록시를 사용하지 않습니다.']) }} - {{ macros.setting_button([['global_setting_save_btn', '저장']]) }} -
+
+ {{ macros.setting_radio('youtube_dl_package', 'youtube-dl', + arg['package_list'], value=arg['youtube_dl_package'], desc='사용할 youtube-dl + 패키지를 선택합니다. 설정 저장 후 재시작이 필요합니다.') }} {{ + macros.setting_input_text('youtube_dl_version', 'youtube-dl 버전', + value=arg['youtube_dl_version'], disabled=True) }} {{ + macros.setting_input_text_and_buttons('ffmpeg_path', 'FFmpeg 경로', + [['ffmpeg_version_btn', '버전확인'], ['ffmpeg_path_btn', '파일 선택']], + value=arg['ffmpeg_path'], placeholder='ffmpeg', desc='SJVA에 내장된 버전 말고 + 원하는 버전을 사용할 수 있습니다.') }} {{ + macros.setting_input_text_and_buttons('temp_path', '임시 폴더', + [['temp_path_btn', '경로 선택']], value=arg['temp_path'], desc='다운로드 + 파일이 임시로 저장될 폴더입니다.') }} {{ + macros.setting_input_text_and_buttons('save_path', '저장 폴더', + [['save_path_btn', '경로 선택']], value=arg['save_path'], desc='정상적으로 + 완료된 파일이 이동할 폴더입니다.') }} {{ + macros.setting_input_text('default_filename', '기본 파일명', + value=arg['default_filename'], placeholder=arg['DEFAULT_FILENAME'], + desc='템플릿 규칙은 https://github.com/ytdl-org/youtube-dl/#output-template + 참고') }} {{ macros.setting_input_text('proxy', '프록시', value=arg['proxy'], + desc=['HTTP/HTTPS/SOCKS를 지원합니다. 예) socks5://127.0.0.1:1080/', '빈칸으로 + 두면 프록시를 사용하지 않습니다.']) }} {{ + macros.setting_button([['global_setting_save_btn', '저장']]) }} +
- - + + {% endblock %} diff --git a/templates/youtube-dl_sub.html b/templates/youtube-dl_sub.html index 8dfb1a4..a53e0c7 100644 --- a/templates/youtube-dl_sub.html +++ b/templates/youtube-dl_sub.html @@ -1,21 +1,25 @@ -{% extends "base.html" %} -{% block content %} +{% extends "base.html" %} {% block content %} -
- {{ macros.setting_input_text('url', 'URL', placeholder='http:// 주소', desc='유튜브, 네이버TV 등 동영상 주소') }} - {{ macros.setting_input_text('filename', '파일명', value=arg['filename'], desc='템플릿 규칙은 https://github.com/ytdl-org/youtube-dl/#output-template 참고') }} - {{ macros.setting_checkbox('all_subs', '모든 자막 다운로드', value='False') }} -
- {{ macros.setting_input_text('sub_lang', '자막 언어', value='ko', desc=['두 자리 국가 코드', '콤마(,)를 구분자로 여러 개 지정 가능']) }} -
- {{ macros.setting_checkbox('auto_sub', '자동생성 자막 다운로드', value='False', desc='유튜브 전용') }} - {{ macros.setting_button([['download_btn', '다운로드']]) }} -
+
+ {{ macros.setting_input_text('url', 'URL', placeholder='http:// 주소', + desc='유튜브, 네이버TV 등 동영상 주소') }} {{ + macros.setting_input_text('filename', '파일명', value=arg['filename'], + desc='템플릿 규칙은 https://github.com/ytdl-org/youtube-dl/#output-template + 참고') }} {{ macros.setting_checkbox('all_subs', '모든 자막 다운로드', + value='False') }} +
+ {{ macros.setting_input_text('sub_lang', '자막 언어', value='ko', desc=['두 + 자리 국가 코드', '콤마(,)를 구분자로 여러 개 지정 가능']) }} +
+ {{ macros.setting_checkbox('auto_sub', '자동생성 자막 다운로드', + value='False', desc='유튜브 전용') }} {{ + macros.setting_button([['download_btn', '다운로드']]) }} +
- - + + {% endblock %} diff --git a/templates/youtube-dl_thumbnail.html b/templates/youtube-dl_thumbnail.html index 1beb49f..f48c6a7 100644 --- a/templates/youtube-dl_thumbnail.html +++ b/templates/youtube-dl_thumbnail.html @@ -1,17 +1,18 @@ -{% extends "base.html" %} -{% block content %} +{% extends "base.html" %} {% block content %} -
- {{ macros.setting_input_text('url', 'URL', placeholder='http:// 주소', desc='유튜브, 네이버TV 등 동영상 주소') }} - {{ macros.setting_input_text('filename', '파일명', value=arg['filename'], desc='템플릿 규칙은 https://github.com/ytdl-org/youtube-dl/#output-template 참고') }} - {{ macros.setting_checkbox('all_thumbnails', '모든 썸네일 다운로드', value='False') }} - {{ macros.setting_button([['download_btn', '다운로드']]) }} -
+
+ {{ macros.setting_input_text('url', 'URL', placeholder='http:// 주소', + desc='유튜브, 네이버TV 등 동영상 주소') }} {{ + macros.setting_input_text('filename', '파일명', value=arg['filename'], + desc='템플릿 규칙은 https://github.com/ytdl-org/youtube-dl/#output-template + 참고') }} {{ macros.setting_checkbox('all_thumbnails', '모든 썸네일 다운로드', + value='False') }} {{ macros.setting_button([['download_btn', '다운로드']]) }} +
- - + + {% endblock %}