diff --git a/README.md b/README.md index 10a2af0..100f8c6 100644 --- a/README.md +++ b/README.md @@ -245,6 +245,10 @@ API를 제공합니다. 다른 플러그인에서 동영상 정보나 다운로 ## Changelog +v4.0.0 + +- 최신 플러그인 구조로 변경 + v3.1.1 - 디폴트 youtube_dl 패키지를 yt-dlp로 변경 diff --git a/__init__.py b/__init__.py index e962124..2149051 100644 --- a/__init__.py +++ b/__init__.py @@ -1 +1,7 @@ -from .plugin import blueprint, menu, plugin_info, plugin_load, plugin_unload +from .plugin import Plugin + +blueprint = Plugin.blueprint +menu = Plugin.menu +plugin_load = Plugin.logic.plugin_load +plugin_unload = Plugin.logic.plugin_unload +plugin_info = Plugin.plugin_info diff --git a/abort.py b/abort.py new file mode 100644 index 0000000..623250e --- /dev/null +++ b/abort.py @@ -0,0 +1,8 @@ +from flask import jsonify + + +class LogicAbort: + @staticmethod + def abort(base, code): + base["errorCode"] = code + return jsonify(base) diff --git a/info.json b/info.json index db8a0f3..374edde 100644 --- a/info.json +++ b/info.json @@ -1,10 +1,9 @@ { - "version": "3.1.1", + "version": "4.0.0", "name": "youtube-dl", "category_name": "vod", "developer": "joyfuI", "description": "유튜브, 네이버TV 등 동영상 사이트에서 동영상 다운로드", "home": "https://github.com/joyfuI/youtube-dl", - "more": "", - "category": "vod" + "more": "" } \ No newline at end of file diff --git a/logic.py b/logic.py deleted file mode 100644 index dcc3235..0000000 --- a/logic.py +++ /dev/null @@ -1,103 +0,0 @@ -import os -import sys -import platform -import traceback -import subprocess -import sqlite3 - -from framework import db, path_app_root, path_data -from framework.logger import get_logger -from framework.util import Util - -from .logic_normal import LogicNormal -from .model import ModelSetting - -package_name = __name__.split(".", maxsplit=1)[0] -logger = get_logger(package_name) - - -class Logic(object): - db_default = { - "db_version": "2", - "youtube_dl_package": "1", - "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 - def db_init(): - try: - for key, value in Logic.db_default.items(): - if db.session.query(ModelSetting).filter_by(key=key).count() == 0: - db.session.add(ModelSetting(key, value)) - db.session.commit() - Logic.migration() - except Exception as error: - logger.error("Exception:%s", error) - logger.error(traceback.format_exc()) - - @staticmethod - def plugin_load(): - try: - 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(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") - ) - except Exception as error: - logger.error("Exception:%s", error) - logger.error(traceback.format_exc()) - - @staticmethod - def plugin_unload(): - try: - logger.debug("%s plugin_unload", package_name) - except Exception as error: - logger.error("Exception:%s", error) - 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", 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, - ) - ) - - connect.commit() - connect.close() - ModelSetting.set("db_version", Logic.db_default["db_version"]) - db.session.flush() - except Exception as error: - logger.error("Exception:%s", error) - logger.error(traceback.format_exc()) diff --git a/logic_normal.py b/main.py similarity index 58% rename from logic_normal.py rename to main.py index 3648921..8b41c54 100644 --- a/logic_normal.py +++ b/main.py @@ -1,28 +1,230 @@ +import os +import sys +import platform import traceback +import subprocess +import sqlite3 from datetime import datetime -from flask import jsonify +from flask import render_template, jsonify -from framework.logger import get_logger +from framework import db, path_app_root, path_data, socketio +from framework.common.plugin import LogicModuleBase, default_route_socketio +from .plugin import Plugin from .my_youtube_dl import MyYoutubeDL, Status -package_name = __name__.split(".", maxsplit=1)[0] -logger = get_logger(package_name) +logger = Plugin.logger +package_name = Plugin.package_name +ModelSetting = Plugin.ModelSetting -class LogicNormal(object): +class LogicMain(LogicModuleBase): + db_default = { + "db_version": "2", + "youtube_dl_package": "1", + "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": "", + } + + def __init__(self, plugin): + super(LogicMain, self).__init__(plugin, None) + self.name = package_name # 모듈명 + default_route_socketio(plugin, self) + + def plugin_load(self): + try: + # youtube-dl 업데이트 + youtube_dl = Plugin.youtube_dl_packages[ + int(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, + ) + ) + except Exception as error: + logger.error("Exception:%s", error) + logger.error(traceback.format_exc()) + + def process_menu(self, sub, req): + try: + arg = { + "package_name": package_name, + "sub": sub, + "template_name": f"{package_name}_{sub}", + "package_version": Plugin.plugin_info["version"], + } + + if sub == "setting": + arg.update(ModelSetting.to_dict()) + arg["package_list"] = Plugin.youtube_dl_packages + arg["youtube_dl_version"] = LogicMain.get_youtube_dl_version() + arg["DEFAULT_FILENAME"] = LogicMain.get_default_filename() + + elif sub == "download": + default_filename = ModelSetting.get("default_filename") + arg["filename"] = ( + default_filename + if default_filename + else LogicMain.get_default_filename() + ) + arg["preset_list"] = LogicMain.get_preset_list() + arg["postprocessor_list"] = LogicMain.get_postprocessor_list() + + elif sub == "thumbnail": + default_filename = ModelSetting.get("default_filename") + arg["filename"] = ( + default_filename + if default_filename + else LogicMain.get_default_filename() + ) + + elif sub == "sub": + default_filename = ModelSetting.get("default_filename") + arg["filename"] = ( + default_filename + if default_filename + else LogicMain.get_default_filename() + ) + + elif sub == "list": + pass + + return render_template(f"{package_name}_{sub}.html", arg=arg) + except Exception as error: + logger.error("Exception:%s", error) + logger.error(traceback.format_exc()) + return render_template("sample.html", title=f"{package_name} - {sub}") + + def process_ajax(self, sub, req): + try: + logger.debug("AJAX: %s, %s", sub, req.values) + ret = {"ret": "success"} + + if sub == "ffmpeg_version": + path = req.form["path"] + output = subprocess.check_output([path, "-version"]) + output = output.decode().replace("\n", "
") + ret["data"] = output + + elif sub == "download": + postprocessor = req.form["postprocessor"] + video_convertor, extract_audio = LogicMain.get_postprocessor() + preferedformat = None + preferredcodec = None + preferredquality = None + if postprocessor in video_convertor: + preferedformat = postprocessor + elif postprocessor in extract_audio: + preferredcodec = postprocessor + preferredquality = 192 + youtube_dl = LogicMain.download( + plugin=package_name, + url=req.form["url"], + filename=req.form["filename"], + temp_path=ModelSetting.get("temp_path"), + save_path=ModelSetting.get("save_path"), + format=req.form["format"], + preferedformat=preferedformat, + preferredcodec=preferredcodec, + preferredquality=preferredquality, + proxy=ModelSetting.get("proxy"), + ffmpeg_path=ModelSetting.get("ffmpeg_path") + if req.form["ffmpeg_path"] != "ffmpeg" + else None, + ) + youtube_dl.start() + LogicMain.socketio_emit("add", youtube_dl) + + elif sub == "thumbnail": + youtube_dl = LogicMain.thumbnail( + plugin=package_name, + url=req.form["url"], + filename=req.form["filename"], + temp_path=ModelSetting.get("temp_path"), + save_path=ModelSetting.get("save_path"), + all_thumbnails=req.form["all_thumbnails"], + proxy=ModelSetting.get("proxy"), + ffmpeg_path=ModelSetting.get("ffmpeg_path") + if req.form["ffmpeg_path"] != "ffmpeg" + else None, + ) + youtube_dl.start() + LogicMain.socketio_emit("add", youtube_dl) + + elif sub == "sub": + youtube_dl = LogicMain.sub( + plugin=package_name, + url=req.form["url"], + filename=req.form["filename"], + temp_path=ModelSetting.get("temp_path"), + save_path=ModelSetting.get("save_path"), + all_subs=req.form["all_subs"], + sub_lang=req.form["sub_lang"], + auto_sub=req.form["auto_sub"], + proxy=ModelSetting.get("proxy"), + ffmpeg_path=ModelSetting.get("ffmpeg_path") + if req.form["ffmpeg_path"] != "ffmpeg" + else None, + ) + youtube_dl.start() + LogicMain.socketio_emit("add", youtube_dl) + + elif sub == "list": + ret["data"] = [] + for i in LogicMain.youtube_dl_list: + data = LogicMain.get_data(i) + if data is not None: + ret["data"].append(data) + + elif sub == "all_stop": + for i in LogicMain.youtube_dl_list: + i.stop() + + elif sub == "stop": + index = int(req.form["index"]) + LogicMain.youtube_dl_list[index].stop() + + return jsonify(ret) + except Exception as error: + logger.error("Exception:%s", error) + logger.error(traceback.format_exc()) + return jsonify({"ret": "danger", "msg": str(error)}) + + def migration(self): + try: + 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, + ) + ) + + connect.commit() + connect.close() + ModelSetting.set("db_version", LogicMain.db_default["db_version"]) + db.session.flush() + except Exception as error: + logger.error("Exception:%s", error) + logger.error(traceback.format_exc()) + youtube_dl_list = [] - @staticmethod - def get_youtube_dl_package(index=None, import_pkg=False): - 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: - return packages if index is None else packages[int(index)] - @staticmethod def get_youtube_dl_version(): try: @@ -79,7 +281,7 @@ class LogicNormal(object): def get_postprocessor(): video_convertor = [] extract_audio = [] - for i in LogicNormal.get_postprocessor_list(): + for i in LogicMain.get_postprocessor_list(): if i[2] == "비디오 변환": video_convertor.append(i[0]) elif i[2] == "오디오 추출": @@ -136,7 +338,7 @@ class LogicNormal(object): plugin, "video", url, filename, temp_path, save_path, opts, dateafter ) youtube_dl.key = kwagrs.get("key") - LogicNormal.youtube_dl_list.append(youtube_dl) # 리스트 추가 + LogicMain.youtube_dl_list.append(youtube_dl) # 리스트 추가 return youtube_dl except Exception as error: logger.error("Exception:%s", error) @@ -187,7 +389,7 @@ class LogicNormal(object): dateafter, ) youtube_dl.key = kwagrs.get("key") - LogicNormal.youtube_dl_list.append(youtube_dl) # 리스트 추가 + LogicMain.youtube_dl_list.append(youtube_dl) # 리스트 추가 return youtube_dl except Exception as error: logger.error("Exception:%s", error) @@ -235,7 +437,7 @@ class LogicNormal(object): plugin, "subtitle", url, filename, temp_path, save_path, opts, dateafter ) youtube_dl.key = kwagrs.get("key") - LogicNormal.youtube_dl_list.append(youtube_dl) # 리스트 추가 + LogicMain.youtube_dl_list.append(youtube_dl) # 리스트 추가 return youtube_dl except Exception as error: logger.error("Exception:%s", error) @@ -284,9 +486,7 @@ class LogicNormal(object): else "" ) data["speed_str"] = ( - LogicNormal.human_readable_size( - youtube_dl.progress_hooks["speed"], "/s" - ) + LogicMain.human_readable_size(youtube_dl.progress_hooks["speed"], "/s") if youtube_dl.progress_hooks["speed"] is not None else "" ) @@ -303,10 +503,10 @@ class LogicNormal(object): youtube_dl.progress_hooks["downloaded_bytes"], youtube_dl.progress_hooks["total_bytes"], ): # 둘 다 값이 있으면 - data["downloaded_bytes_str"] = LogicNormal.human_readable_size( + data["downloaded_bytes_str"] = LogicMain.human_readable_size( youtube_dl.progress_hooks["downloaded_bytes"] ) - data["total_bytes_str"] = LogicNormal.human_readable_size( + data["total_bytes_str"] = LogicMain.human_readable_size( youtube_dl.progress_hooks["total_bytes"] ) data[ @@ -335,6 +535,7 @@ class LogicNormal(object): return f"{size:.1f} YB{suffix}" @staticmethod - def abort(base, code): - base["errorCode"] = code - return jsonify(base) + def socketio_emit(cmd, data): + socketio.emit( + cmd, LogicMain.get_data(data), namespace=f"/{package_name}", broadcast=True + ) diff --git a/model.py b/model.py deleted file mode 100644 index 7f9a8f1..0000000 --- a/model.py +++ /dev/null @@ -1,119 +0,0 @@ -import os -import traceback - -from framework import app, db, path_data -from framework.logger import get_logger -from framework.util import Util - -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", f"{package_name}.db") -) - - -class ModelSetting(db.Model): - __tablename__ = f"{package_name}_setting" - __table_args__ = {"mysql_collate": "utf8_general_ci"} - __bind_key__ = package_name - - id = db.Column(db.Integer, primary_key=True) - key = db.Column(db.String(100), unique=True, nullable=False) - value = db.Column(db.String, nullable=False) - - def __init__(self, key, value): - self.key = key - self.value = value - - def __repr__(self): - return repr(self.as_dict()) - - def as_dict(self): - return {x.name: getattr(self, x.name) for x in self.__table__.columns} - - @staticmethod - def get(key): - try: - return ( - db.session.query(ModelSetting).filter_by(key=key).first().value.strip() - ) - except Exception as error: - logger.error("Exception:%s %s", error, key) - logger.error(traceback.format_exc()) - - @staticmethod - def get_int(key): - try: - return int(ModelSetting.get(key)) - except Exception as error: - logger.error("Exception:%s %s", error, key) - logger.error(traceback.format_exc()) - - @staticmethod - def get_bool(key): - try: - return ModelSetting.get(key) == "True" - except Exception as error: - logger.error("Exception:%s %s", error, 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() - ) - if item is not None: - item.value = value.strip() - db.session.commit() - else: - db.session.add(ModelSetting(key, value.strip())) - except Exception as error: - logger.error("Exception:%s", error) - logger.error(traceback.format_exc()) - 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 error: - logger.error("Exception:%s", error) - logger.error(traceback.format_exc()) - - @staticmethod - def setting_save(req): - try: - for key, value in req.form.items(): - if key in ["scheduler", "is_running"]: - continue - 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() - ) - entity.value = value - db.session.commit() - return True - except Exception as error: - logger.error("Exception:%s", error) - logger.error(traceback.format_exc()) - return False - - @staticmethod - def get_list(key): - try: - value = ModelSetting.get(key) - values = [x.strip().strip() for x in value.replace("\n", "|").split("|")] - values = Util.get_list_except_empty(values) - return values - except Exception as error: - logger.error("Exception:%s %s", error, key) - logger.error(traceback.format_exc()) diff --git a/my_youtube_dl.py b/my_youtube_dl.py index 48f9684..94196b1 100644 --- a/my_youtube_dl.py +++ b/my_youtube_dl.py @@ -8,11 +8,18 @@ from datetime import datetime from threading import Thread from enum import Enum -from framework.logger import get_logger import framework.common.celery as celery_shutil -package_name = __name__.split(".", maxsplit=1)[0] -logger = get_logger(package_name) +from .plugin import Plugin + +logger = Plugin.logger +ModelSetting = Plugin.ModelSetting + +youtube_dl_package = Plugin.youtube_dl_packages[ + int(ModelSetting.get("youtube_dl_package")) + if ModelSetting.get("youtube_dl_package") + else 1 # LogicMain.db_default["youtube_dl_package"] +].replace("-", "_") class Status(Enum): @@ -29,7 +36,7 @@ class Status(Enum): return str_list[self.value] -class MyYoutubeDL(object): +class MyYoutubeDL: DEFAULT_FILENAME = "%(title)s-%(id)s.%(ext)s" _index = 0 @@ -47,8 +54,6 @@ class MyYoutubeDL(object): datebefore=None, ): # from youtube_dl.utils import DateRange - from .plugin import youtube_dl_package - DateRange = __import__( f"{youtube_dl_package}.utils", fromlist=["DateRange"] ).DateRange @@ -106,8 +111,6 @@ class MyYoutubeDL(object): def run(self): # import youtube_dl - from .plugin import youtube_dl_package - youtube_dl = __import__(youtube_dl_package) try: @@ -164,8 +167,6 @@ class MyYoutubeDL(object): @staticmethod def get_version(): # from youtube_dl.version import __version__ - from .plugin import youtube_dl_package - __version__ = __import__( f"{youtube_dl_package}.version", fromlist=["__version__"] ).__version__ @@ -175,8 +176,6 @@ class MyYoutubeDL(object): @staticmethod def get_info_dict(url, proxy=None, cookiefile=None): # import youtube_dl - from .plugin import youtube_dl_package - youtube_dl = __import__(youtube_dl_package) try: @@ -220,13 +219,13 @@ class MyYoutubeDL(object): @status.setter def status(self, value): - from .plugin import socketio_emit + from .main import LogicMain self._status = value - socketio_emit("status", self) + LogicMain.socketio_emit("status", self) -class MyLogger(object): +class MyLogger: def debug(self, msg): if msg.find(" ETA ") != -1: # 과도한 로그 방지 diff --git a/plugin.py b/plugin.py index 777d18a..bbf3d8a 100644 --- a/plugin.py +++ b/plugin.py @@ -1,274 +1,117 @@ import os import traceback -import subprocess -from flask import Blueprint, request, render_template, redirect, jsonify, abort -from flask_login import login_required -from flask_cors import cross_origin +from flask import Blueprint, request, jsonify, abort -from framework import check_api, socketio +from framework import app, path_data from framework.logger import get_logger - -from .logic import Logic -from .logic_normal import LogicNormal -from .model import ModelSetting - -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, +from framework.util import Util +from framework.common.plugin import ( + get_model_setting, + Logic, + default_route_single_module, ) -######################################################### -# 플러그인 공용 -######################################################### -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", "로그"], - ], - "category": "vod", -} +class Plugin: + package_name = __name__.split(".", maxsplit=1)[0] + logger = get_logger(package_name) + 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"), + ) -plugin_info = { - "version": "3.1.1", - "name": "youtube-dl", - "category_name": "vod", - "developer": "joyfuI", - "description": "유튜브, 네이버TV 등 동영상 사이트에서 동영상 다운로드", - "home": "https://github.com/joyfuI/youtube-dl", - "more": "", -} + # 메뉴 정의 + menu = { + "main": [package_name, "youtube-dl"], + "sub": [ + ["setting", "설정"], + ["download", "다운로드"], + ["thumbnail", "썸네일 다운로드"], + ["sub", "자막 다운로드"], + ["list", "목록"], + ["log", "로그"], + ], + "category": "vod", + } + + plugin_info = { + "version": "4.0.0", + "name": package_name, + "category_name": "vod", + "developer": "joyfuI", + "description": "유튜브, 네이버TV 등 동영상 사이트에서 동영상 다운로드", + "home": f"https://github.com/joyfuI/{package_name}", + "more": "", + } + + ModelSetting = get_model_setting(package_name, logger) + logic = None + module_list = None + home_module = "list" # 기본모듈 + + youtube_dl_packages = ["youtube-dl", "yt-dlp"] -def plugin_load(): - Logic.plugin_load() - - -def plugin_unload(): - Logic.plugin_unload() - - -######################################################### -# WEB Menu -######################################################### -@blueprint.route("/") -def home(): - return redirect(f"/{package_name}/list") - - -@blueprint.route("/") -@login_required -def first_menu(sub): +def initialize(): try: - arg = { - "package_name": package_name, - "template_name": f"{package_name}_{sub}", - "package_version": plugin_info["version"], - } + app.config["SQLALCHEMY_BINDS"][ + Plugin.package_name + ] = f"sqlite:///{os.path.join(path_data, 'db', f'{Plugin.package_name}.db')}" + Util.save_from_dict_to_json( + Plugin.plugin_info, os.path.join(os.path.dirname(__file__), "info.json") + ) - 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(f"{package_name}_{sub}.html", arg=arg) + # 로드할 모듈 정의 + from .main import LogicMain - 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) + Plugin.module_list = [LogicMain(Plugin)] - 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(f"{package_name}_{sub}.html", 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) + Plugin.logic = Logic(Plugin) + default_route_single_module(Plugin) except Exception as error: - logger.error("Exception:%s", error) - logger.error(traceback.format_exc()) - return render_template("sample.html", title=f"{package_name} - {sub}") + Plugin.logger.error("Exception:%s", error) + Plugin.logger.error(traceback.format_exc()) -######################################################### -# For UI -######################################################### -@blueprint.route("/ajax/", methods=["POST"]) -@login_required -def ajax(sub): - logger.debug("AJAX %s %s", package_name, sub) - try: - # 공통 요청 - if sub == "setting_save": - ret = ModelSetting.setting_save(request) - 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", "
") - return jsonify(ret) - - elif sub == "download": - postprocessor = request.form["postprocessor"] - video_convertor, extract_audio = LogicNormal.get_postprocessor() - preferedformat = None - preferredcodec = None - preferredquality = None - if postprocessor in video_convertor: - preferedformat = postprocessor - 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.start() - 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"), - ) - youtube_dl.start() - 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"), - ) - youtube_dl.start() - socketio_emit("add", youtube_dl) - return jsonify([]) - - elif sub == "list": - ret = [] - for i in LogicNormal.youtube_dl_list: - data = LogicNormal.get_data(i) - if data is not None: - ret.append(data) - return jsonify(ret) - - elif sub == "all_stop": - for i in LogicNormal.youtube_dl_list: - i.stop() - return jsonify([]) - - elif sub == "stop": - index = int(request.form["index"]) - LogicNormal.youtube_dl_list[index].stop() - return jsonify([]) - except Exception as error: - logger.error("Exception:%s", error) - logger.error(traceback.format_exc()) - - -######################################################### -# API -######################################################### # API 명세는 https://github.com/joyfuI/youtube-dl#api -@blueprint.route("/api/", methods=["GET", "POST"]) -@cross_origin() -@check_api +@Plugin.blueprint.route("/api/", methods=["GET", "POST"]) def api(sub): - plugin = request.values.get("plugin") - logger.debug("API %s %s: %s", package_name, sub, plugin) - if not plugin: # 요청한 플러그인명이 빈문자열이거나 None면 - abort(403) # 403 에러(거부) + from .main import LogicMain + from .abort import LogicAbort + try: + Plugin.logger.debug("API: %s, %s", sub, request.values) + plugin = request.values.get("plugin") + if not plugin: # 요청한 플러그인명이 빈문자열이거나 None면 + abort(403) # 403 에러(거부) + # 동영상 정보를 반환하는 API if sub == "info_dict": url = request.values.get("url") ret = {"errorCode": 0, "info_dict": None} if None in (url,): - return LogicNormal.abort(ret, 1) # 필수 요청 변수가 없음 + return LogicAbort.abort(ret, 1) # 필수 요청 변수가 없음 if not url.startswith("http"): - return LogicNormal.abort(ret, 2) # 잘못된 동영상 주소 - info_dict = LogicNormal.get_info_dict(url, ModelSetting.get("proxy")) + return LogicAbort.abort(ret, 2) # 잘못된 동영상 주소 + info_dict = LogicMain.get_info_dict(url, Plugin.ModelSetting.get("proxy")) if info_dict is None: - return LogicNormal.abort(ret, 10) # 실패 + return LogicAbort.abort(ret, 10) # 실패 ret["info_dict"] = info_dict - return jsonify(ret) # 비디오 다운로드 준비를 요청하는 API elif sub == "download": key = request.values.get("key") url = request.values.get("url") filename = request.values.get( - "filename", ModelSetting.get("default_filename") + "filename", Plugin.ModelSetting.get("default_filename") + ) + save_path = request.values.get( + "save_path", Plugin.ModelSetting.get("save_path") ) - 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) @@ -280,9 +123,9 @@ def api(sub): cookiefile = request.values.get("cookiefile", None) ret = {"errorCode": 0, "index": None} if None in (key, url): - return LogicNormal.abort(ret, 1) # 필수 요청 변수가 없음 + return LogicAbort.abort(ret, 1) # 필수 요청 변수가 없음 if not url.startswith("http"): - return LogicNormal.abort(ret, 2) # 잘못된 동영상 주소 + return LogicAbort.abort(ret, 2) # 잘못된 동영상 주소 if preferredcodec not in ( None, "best", @@ -294,14 +137,14 @@ def api(sub): "vorbis", "wav", ): - return LogicNormal.abort(ret, 5) # 허용되지 않은 값이 있음 + return LogicAbort.abort(ret, 5) # 허용되지 않은 값이 있음 if not filename: - filename = LogicNormal.get_default_filename() - youtube_dl = LogicNormal.download( + filename = LogicMain.get_default_filename() + youtube_dl = LogicMain.download( plugin=plugin, url=url, filename=filename, - temp_path=ModelSetting.get("temp_path"), + temp_path=Plugin.ModelSetting.get("temp_path"), save_path=save_path, format=format_code, preferedformat=preferedformat, @@ -310,27 +153,28 @@ def api(sub): dateafter=dateafter, playlist=playlist, archive=archive, - proxy=ModelSetting.get("proxy"), - ffmpeg_path=ModelSetting.get("ffmpeg_path"), + proxy=Plugin.ModelSetting.get("proxy"), + ffmpeg_path=Plugin.ModelSetting.get("ffmpeg_path"), key=key, cookiefile=cookiefile, ) if youtube_dl is None: - return LogicNormal.abort(ret, 10) # 실패 + return LogicAbort.abort(ret, 10) # 실패 ret["index"] = youtube_dl.index if start: youtube_dl.start() - socketio_emit("add", youtube_dl) - return jsonify(ret) + LogicMain.socketio_emit("add", youtube_dl) # 썸네일 다운로드 준비를 요청하는 API elif sub == "thumbnail": key = request.values.get("key") url = request.values.get("url") filename = request.values.get( - "filename", ModelSetting.get("default_filename") + "filename", Plugin.ModelSetting.get("default_filename") + ) + save_path = request.values.get( + "save_path", Plugin.ModelSetting.get("save_path") ) - 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) @@ -339,42 +183,43 @@ def api(sub): cookiefile = request.values.get("cookiefile", None) ret = {"errorCode": 0, "index": None} if None in (key, url): - return LogicNormal.abort(ret, 1) # 필수 요청 변수가 없음 + return LogicAbort.abort(ret, 1) # 필수 요청 변수가 없음 if not url.startswith("http"): - return LogicNormal.abort(ret, 2) # 잘못된 동영상 주소 + return LogicAbort.abort(ret, 2) # 잘못된 동영상 주소 if not filename: - filename = LogicNormal.get_default_filename() - youtube_dl = LogicNormal.thumbnail( + filename = LogicMain.get_default_filename() + youtube_dl = LogicMain.thumbnail( plugin=plugin, url=url, filename=filename, - temp_path=ModelSetting.get("temp_path"), + temp_path=Plugin.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"), + proxy=Plugin.ModelSetting.get("proxy"), + ffmpeg_path=Plugin.ModelSetting.get("ffmpeg_path"), key=key, cookiefile=cookiefile, ) if youtube_dl is None: - return LogicNormal.abort(ret, 10) # 실패 + return LogicAbort.abort(ret, 10) # 실패 ret["index"] = youtube_dl.index if start: youtube_dl.start() - socketio_emit("add", youtube_dl) - return jsonify(ret) + LogicMain.socketio_emit("add", youtube_dl) # 자막 다운로드 준비를 요청하는 API elif sub == "sub": key = request.values.get("key") url = request.values.get("url") filename = request.values.get( - "filename", ModelSetting.get("default_filename") + "filename", Plugin.ModelSetting.get("default_filename") + ) + save_path = request.values.get( + "save_path", Plugin.ModelSetting.get("save_path") ) - 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) @@ -385,16 +230,16 @@ def api(sub): cookiefile = request.values.get("cookiefile", None) ret = {"errorCode": 0, "index": None} if None in (key, url): - return LogicNormal.abort(ret, 1) # 필수 요청 변수가 없음 + return LogicAbort.abort(ret, 1) # 필수 요청 변수가 없음 if not url.startswith("http"): - return LogicNormal.abort(ret, 2) # 잘못된 동영상 주소 + return LogicAbort.abort(ret, 2) # 잘못된 동영상 주소 if not filename: - filename = LogicNormal.get_default_filename() - youtube_dl = LogicNormal.sub( + filename = LogicMain.get_default_filename() + youtube_dl = LogicMain.sub( plugin=plugin, url=url, filename=filename, - temp_path=ModelSetting.get("temp_path"), + temp_path=Plugin.ModelSetting.get("temp_path"), save_path=save_path, all_subs=all_subs, sub_lang=sub_lang, @@ -402,18 +247,17 @@ def api(sub): dateafter=dateafter, playlist=playlist, archive=archive, - proxy=ModelSetting.get("proxy"), - ffmpeg_path=ModelSetting.get("ffmpeg_path"), + proxy=Plugin.ModelSetting.get("proxy"), + ffmpeg_path=Plugin.ModelSetting.get("ffmpeg_path"), key=key, cookiefile=cookiefile, ) if youtube_dl is None: - return LogicNormal.abort(ret, 10) # 실패 + return LogicAbort.abort(ret, 10) # 실패 ret["index"] = youtube_dl.index if start: youtube_dl.start() - socketio_emit("add", youtube_dl) - return jsonify(ret) + LogicMain.socketio_emit("add", youtube_dl) # 다운로드 시작을 요청하는 API elif sub == "start": @@ -421,17 +265,16 @@ def api(sub): key = request.values.get("key") ret = {"errorCode": 0, "status": None} if None in (index, key): - return LogicNormal.abort(ret, 1) # 필수 요청 변수가 없음 + return LogicAbort.abort(ret, 1) # 필수 요청 변수가 없음 index = int(index) - if not 0 <= index < len(LogicNormal.youtube_dl_list): - return LogicNormal.abort(ret, 3) # 인덱스 범위를 벗어남 - youtube_dl = LogicNormal.youtube_dl_list[index] + if not 0 <= index < len(LogicMain.youtube_dl_list): + return LogicAbort.abort(ret, 3) # 인덱스 범위를 벗어남 + youtube_dl = LogicMain.youtube_dl_list[index] if youtube_dl.key != key: - return LogicNormal.abort(ret, 4) # 키가 일치하지 않음 + return LogicAbort.abort(ret, 4) # 키가 일치하지 않음 ret["status"] = youtube_dl.status.name if not youtube_dl.start(): - return LogicNormal.abort(ret, 10) # 실패 - return jsonify(ret) + return LogicAbort.abort(ret, 10) # 실패 # 다운로드 중지를 요청하는 API elif sub == "stop": @@ -439,17 +282,16 @@ def api(sub): key = request.values.get("key") ret = {"errorCode": 0, "status": None} if None in (index, key): - return LogicNormal.abort(ret, 1) # 필수 요청 변수가 없음 + return LogicAbort.abort(ret, 1) # 필수 요청 변수가 없음 index = int(index) - if not 0 <= index < len(LogicNormal.youtube_dl_list): - return LogicNormal.abort(ret, 3) # 인덱스 범위를 벗어남 - youtube_dl = LogicNormal.youtube_dl_list[index] + if not 0 <= index < len(LogicMain.youtube_dl_list): + return LogicAbort.abort(ret, 3) # 인덱스 범위를 벗어남 + youtube_dl = LogicMain.youtube_dl_list[index] if youtube_dl.key != key: - return LogicNormal.abort(ret, 4) # 키가 일치하지 않음 + return LogicAbort.abort(ret, 4) # 키가 일치하지 않음 ret["status"] = youtube_dl.status.name if not youtube_dl.stop(): - return LogicNormal.abort(ret, 10) # 실패 - return jsonify(ret) + return LogicAbort.abort(ret, 10) # 실패 # 현재 상태를 반환하는 API elif sub == "status": @@ -465,13 +307,13 @@ def api(sub): "save_path": None, } if None in (index, key): - return LogicNormal.abort(ret, 1) # 필수 요청 변수가 없음 + return LogicAbort.abort(ret, 1) # 필수 요청 변수가 없음 index = int(index) - if not 0 <= index < len(LogicNormal.youtube_dl_list): - return LogicNormal.abort(ret, 3) # 인덱스 범위를 벗어남 - youtube_dl = LogicNormal.youtube_dl_list[index] + if not 0 <= index < len(LogicMain.youtube_dl_list): + return LogicAbort.abort(ret, 3) # 인덱스 범위를 벗어남 + youtube_dl = LogicMain.youtube_dl_list[index] if youtube_dl.key != key: - return LogicNormal.abort(ret, 4) # 키가 일치하지 않음 + return LogicAbort.abort(ret, 4) # 키가 일치하지 않음 ret["status"] = youtube_dl.status.name ret["type"] = youtube_dl.type ret["start_time"] = ( @@ -486,18 +328,12 @@ def api(sub): ) ret["temp_path"] = youtube_dl.temp_path ret["save_path"] = youtube_dl.save_path - return jsonify(ret) + + return jsonify(ret) except Exception as error: - logger.error("Exception:%s", error) - logger.error(traceback.format_exc()) - abort(500) # 500 에러(서버 오류) - abort(404) # 404 에러(페이지 없음) + Plugin.logger.error("Exception:%s", error) + Plugin.logger.error(traceback.format_exc()) -######################################################### -# socketio -######################################################### -def socketio_emit(cmd, data): - socketio.emit( - cmd, LogicNormal.get_data(data), namespace=f"/{package_name}", broadcast=True - ) +logger = Plugin.logger +initialize()