diff --git a/__init__.py b/__init__.py index 2149051..e69de29 100644 --- a/__init__.py +++ b/__init__.py @@ -1,7 +0,0 @@ -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/info.json b/info.json deleted file mode 100644 index 8d1ac41..0000000 --- a/info.json +++ /dev/null @@ -1,9 +0,0 @@ -{ - "version": "4.0.1", - "name": "youtube-dl", - "category_name": "vod", - "developer": "joyfuI", - "description": "유튜브, 네이버TV 등 동영상 사이트에서 동영상 다운로드", - "home": "https://github.com/joyfuI/youtube-dl", - "more": "" -} \ No newline at end of file diff --git a/info.yaml b/info.yaml new file mode 100644 index 0000000..5a56061 --- /dev/null +++ b/info.yaml @@ -0,0 +1,7 @@ +title: "유튜브 다운로더" +version: "0.1.0" +package_name: "youtube-dl" +developer: "flaskfarm" +description: "유튜브 다운로드" +home: "https://gitea.yommi.duckdns.org/ff_plugins/youtube-dl" +more: "https://gitea.yommi.duckdns.org/ff_plugins/youtube-dl/raw/branch/main/README.md" \ No newline at end of file diff --git a/main.py b/main.py index 61aa1bd..ee2c906 100644 --- a/main.py +++ b/main.py @@ -8,15 +8,11 @@ from datetime import datetime from flask import render_template, jsonify -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 -logger = Plugin.logger -package_name = Plugin.package_name -ModelSetting = Plugin.ModelSetting +logger = P.logger +package_name = P.package_name +ModelSetting = P.ModelSetting class LogicMain(LogicModuleBase): diff --git a/mod_basic.py b/mod_basic.py new file mode 100644 index 0000000..8569398 --- /dev/null +++ b/mod_basic.py @@ -0,0 +1,118 @@ +# -*- coding: utf-8 -*- +# @Time : 2023/02/25 7:29 PM +# @Author : yommi +# @Site : +# @File : mod_basic +# @Software: PyCharm +# @Path : youtube-dl/mod_basic.py +from support import SupportYaml +from tool import ToolUtil + +from .setup import * + +# from .main import LogicMain +from .my_youtube_dl import MyYoutubeDL, Status +import platform +import os +from .model import ModelYoutubeDlItem +from loguru import logger + + +class ModuleBasic(PluginModuleBase): + def __init__(self, P): + super(ModuleBasic, self).__init__( + P, name="basic", first_menu="setting", scheduler_desc="유튜브 다운로더" + ) + self.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": "", + } + self.web_list_model = ModelYoutubeDlItem + + def process_menu(self, sub, req): + logger.debug(f"sub: {sub}") + arg = P.ModelSetting.to_dict() + logger.debug(f"arg:: {arg}") + if sub == "setting": + arg["is_include"] = F.scheduler.is_include(self.get_scheduler_name()) + arg["is_running"] = F.scheduler.is_running(self.get_scheduler_name()) + + elif sub == "download": + default_filename = P.ModelSetting.get("default_filename") + arg["filename"] = ( + default_filename + if default_filename + else ModuleBasic.get_default_filename() + ) + arg["preset_list"] = ModuleBasic.get_preset_list() + arg["postprocessor_list"] = ModuleBasic.get_postprocessor_list() + + return render_template(f"{P.package_name}_{self.name}_{sub}.html", arg=arg) + + def process_command(self, command, arg1, arg2, arg3, req): + ret = {"ret": "success"} + return jsonify(ret) + + # def plugin_load(self): + # if ( + # os.path.exists( + # ToolUtil.make_path(P.ModelSetting.get(f"{self.name}_path_config")) + # ) + # is False + # ): + # shutil.copyfile( + # os.path.join( + # os.path.dirname(__file__), "files", f"config_{self.name}.yaml" + # ), + # ToolUtil.make_path(P.ModelSetting.get(f"{self.name}_path_config")), + # ) + + @staticmethod + def get_default_filename(): + return MyYoutubeDL.DEFAULT_FILENAME + + @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", "사용자 정의"], + ] + + @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", "오디오 추출"], + ] diff --git a/model.py b/model.py new file mode 100644 index 0000000..186ced4 --- /dev/null +++ b/model.py @@ -0,0 +1,18 @@ +# -*- coding: utf-8 -*- +# @Time : 2023/02/25 7:55 PM +# @Author : yommi +# @Site : +# @File : model +# @Software: PyCharm +# @Path : youtube-dl/model.py + +from .setup import * + + +class ModelYoutubeDlItem(ModelBase): + P = P + __tablename__ = "youtube_dl_item" + __table_args__ = {"mysql_collate": "utf8_general_ci"} + __bind_key__ = P.package_name + + id = db.Column(db.Integer, primary_key=True) diff --git a/my_youtube_dl.py b/my_youtube_dl.py index c30eb9b..2544422 100644 --- a/my_youtube_dl.py +++ b/my_youtube_dl.py @@ -8,14 +8,16 @@ from datetime import datetime from threading import Thread from enum import Enum -import framework.common.celery as celery_shutil +from framework import celery as celery_shutil -from .plugin import Plugin +# from .plugin import Plugin -logger = Plugin.logger -ModelSetting = Plugin.ModelSetting +from .setup import P -youtube_dl_package = Plugin.youtube_dl_packages[ +logger = P.logger +ModelSetting = P.ModelSetting + +youtube_dl_package = P.youtube_dl_packages[ int(ModelSetting.get("youtube_dl_package")) if ModelSetting.get("youtube_dl_package") else 1 # LogicMain.db_default["youtube_dl_package"] @@ -140,7 +142,9 @@ class MyYoutubeDL: } ydl_opts.update(self.opts) with youtube_dl.YoutubeDL(ydl_opts) as ydl: - ydl.download([self.url]) + logger.debug(self.url) + error_code = ydl.download([self.url]) + logger.debug(error_code) if self.status in (Status.START, Status.FINISHED): # 다운로드 성공 for i in glob(self.temp_path + "/**/*", recursive=True): path = i.replace(self.temp_path, self.save_path, 1) @@ -190,12 +194,13 @@ class MyYoutubeDL: if http_headers: ydl_opts["http_headers"] = http_headers with youtube_dl.YoutubeDL(ydl_opts) as ydl: + # info = ydl.extract_info(url, download=False) info = ydl.extract_info(url, download=False) except Exception as error: logger.error("Exception:%s", error) logger.error(traceback.format_exc()) return None - return info + return ydl.sanitize_info(info) def my_hook(self, data): if self.status != Status.STOP: diff --git a/plugin.py b/plugin.py deleted file mode 100644 index 0414741..0000000 --- a/plugin.py +++ /dev/null @@ -1,346 +0,0 @@ -import os -import traceback -import json - -from flask import Blueprint, request, jsonify, abort - -from framework import app, path_data -from framework.logger import get_logger -from framework.util import Util -from framework.common.plugin import ( - get_model_setting, - Logic, - default_route_single_module, -) - - -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"), - ) - - # 메뉴 정의 - menu = { - "main": [package_name, "youtube-dl"], - "sub": [ - ["setting", "설정"], - ["download", "다운로드"], - ["thumbnail", "썸네일 다운로드"], - ["sub", "자막 다운로드"], - ["list", "목록"], - ["log", "로그"], - ], - "category": "vod", - } - - plugin_info = { - "version": "4.0.1", - "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 initialize(): - try: - 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") - ) - - # 로드할 모듈 정의 - from .main import LogicMain - - Plugin.module_list = [LogicMain(Plugin)] - - Plugin.logic = Logic(Plugin) - default_route_single_module(Plugin) - except Exception as error: - Plugin.logger.error("Exception:%s", error) - Plugin.logger.error(traceback.format_exc()) - - -# API 명세는 https://github.com/joyfuI/youtube-dl#api -@Plugin.blueprint.route("/api/", methods=["GET", "POST"]) -def api(sub): - 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 LogicAbort.abort(ret, 1) # 필수 요청 변수가 없음 - if not url.startswith("http"): - return LogicAbort.abort(ret, 2) # 잘못된 동영상 주소 - info_dict = LogicMain.get_info_dict(url, Plugin.ModelSetting.get("proxy")) - if info_dict is None: - return LogicAbort.abort(ret, 10) # 실패 - ret["info_dict"] = info_dict - - # 비디오 다운로드 준비를 요청하는 API - elif sub == "download": - key = request.values.get("key") - url = request.values.get("url") - filename = request.values.get( - "filename", Plugin.ModelSetting.get("default_filename") - ) - save_path = request.values.get( - "save_path", Plugin.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) - headers = request.values.get("headers", "null") - ret = {"errorCode": 0, "index": None} - if None in (key, url): - return LogicAbort.abort(ret, 1) # 필수 요청 변수가 없음 - if not url.startswith("http"): - return LogicAbort.abort(ret, 2) # 잘못된 동영상 주소 - if preferredcodec not in ( - None, - "best", - "mp3", - "aac", - "flac", - "m4a", - "opus", - "vorbis", - "wav", - ): - return LogicAbort.abort(ret, 5) # 허용되지 않은 값이 있음 - if not filename: - filename = LogicMain.get_default_filename() - youtube_dl = LogicMain.download( - plugin=plugin, - url=url, - filename=filename, - temp_path=Plugin.ModelSetting.get("temp_path"), - save_path=save_path, - format=format_code, - preferedformat=preferedformat, - preferredcodec=preferredcodec, - preferredquality=preferredquality, - dateafter=dateafter, - playlist=playlist, - archive=archive, - proxy=Plugin.ModelSetting.get("proxy"), - ffmpeg_path=Plugin.ModelSetting.get("ffmpeg_path"), - key=key, - cookiefile=cookiefile, - headers=json.loads(headers), - ) - if youtube_dl is None: - return LogicAbort.abort(ret, 10) # 실패 - ret["index"] = youtube_dl.index - if start: - youtube_dl.start() - 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", Plugin.ModelSetting.get("default_filename") - ) - save_path = request.values.get( - "save_path", Plugin.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) - headers = request.values.get("headers", "null") - ret = {"errorCode": 0, "index": None} - if None in (key, url): - return LogicAbort.abort(ret, 1) # 필수 요청 변수가 없음 - if not url.startswith("http"): - return LogicAbort.abort(ret, 2) # 잘못된 동영상 주소 - if not filename: - filename = LogicMain.get_default_filename() - youtube_dl = LogicMain.thumbnail( - plugin=plugin, - url=url, - filename=filename, - temp_path=Plugin.ModelSetting.get("temp_path"), - save_path=save_path, - all_thumbnails=all_thumbnails, - dateafter=dateafter, - playlist=playlist, - archive=archive, - proxy=Plugin.ModelSetting.get("proxy"), - ffmpeg_path=Plugin.ModelSetting.get("ffmpeg_path"), - key=key, - cookiefile=cookiefile, - headers=json.loads(headers), - ) - if youtube_dl is None: - return LogicAbort.abort(ret, 10) # 실패 - ret["index"] = youtube_dl.index - if start: - youtube_dl.start() - 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", Plugin.ModelSetting.get("default_filename") - ) - save_path = request.values.get( - "save_path", Plugin.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) - headers = request.values.get("headers", "null") - ret = {"errorCode": 0, "index": None} - if None in (key, url): - return LogicAbort.abort(ret, 1) # 필수 요청 변수가 없음 - if not url.startswith("http"): - return LogicAbort.abort(ret, 2) # 잘못된 동영상 주소 - if not filename: - filename = LogicMain.get_default_filename() - youtube_dl = LogicMain.sub( - plugin=plugin, - url=url, - filename=filename, - temp_path=Plugin.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=Plugin.ModelSetting.get("proxy"), - ffmpeg_path=Plugin.ModelSetting.get("ffmpeg_path"), - key=key, - cookiefile=cookiefile, - headers=json.loads(headers), - ) - if youtube_dl is None: - return LogicAbort.abort(ret, 10) # 실패 - ret["index"] = youtube_dl.index - if start: - youtube_dl.start() - LogicMain.socketio_emit("add", youtube_dl) - - # 다운로드 시작을 요청하는 API - elif sub == "start": - index = request.values.get("index") - key = request.values.get("key") - ret = {"errorCode": 0, "status": None} - if None in (index, key): - return LogicAbort.abort(ret, 1) # 필수 요청 변수가 없음 - index = int(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 LogicAbort.abort(ret, 4) # 키가 일치하지 않음 - ret["status"] = youtube_dl.status.name - if not youtube_dl.start(): - return LogicAbort.abort(ret, 10) # 실패 - - # 다운로드 중지를 요청하는 API - elif sub == "stop": - index = request.values.get("index") - key = request.values.get("key") - ret = {"errorCode": 0, "status": None} - if None in (index, key): - return LogicAbort.abort(ret, 1) # 필수 요청 변수가 없음 - index = int(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 LogicAbort.abort(ret, 4) # 키가 일치하지 않음 - ret["status"] = youtube_dl.status.name - if not youtube_dl.stop(): - return LogicAbort.abort(ret, 10) # 실패 - - # 현재 상태를 반환하는 API - 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, - } - if None in (index, key): - return LogicAbort.abort(ret, 1) # 필수 요청 변수가 없음 - index = int(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 LogicAbort.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 - - return jsonify(ret) - except Exception as error: - Plugin.logger.error("Exception:%s", error) - Plugin.logger.error(traceback.format_exc()) - - -logger = Plugin.logger -initialize() diff --git a/setup.py b/setup.py new file mode 100644 index 0000000..0a99a2a --- /dev/null +++ b/setup.py @@ -0,0 +1,77 @@ +# -*- coding: utf-8 -*- +# @Time : 2023/02/25 7:20 PM +# @Author : yommi +# @Site : +# @File : setup.py +# @Software: PyCharm +# @Path : youtube-dl/setup.py + +__menu = { + "uri": __package__, + "name": "유튜브 다운로더", + "list": [ + { + "uri": "basic", + "name": "기본 처리", + "list": [ + { + "uri": "setting", + "name": "설정", + }, + ], + }, + { + "uri": "basic/download", + "name": "다운로드", + }, + { + "uri": "download", + "name": "다운로드", + "list": [ + { + "uri": "basic", + "name": "다운로드", + }, + ], + }, + {"uri": "thumbnail", "name": "썸네일 다운로드"}, + {"uri": "sub", "name": "자막 다운로드"}, + { + "uri": "manual", + "name": "매뉴얼", + "list": [ + {"uri": "README.md", "name": "README.md"}, + ], + }, + { + "uri": "log", + "name": "로그", + }, + ], +} + +setting = { + "filepath": __file__, + "use_db": True, + "use_default_setting": True, + "home_module": None, + "menu": __menu, + "setting_menu": None, + "default_route": "normal", +} + + +from plugin import * + +P = create_plugin_instance(setting) +P.youtube_dl_packages = ["youtube-dl", "yt-dlp", "youtube-dlc"] + +try: + from .mod_basic import ModuleBasic + + P.set_module_list([ModuleBasic]) +except Exception as e: + P.logger.error(f"Exception:{str(e)}") + P.logger.error(traceback.format_exc()) + +logger = P.logger diff --git a/templates/youtube-dl_basic_download.html b/templates/youtube-dl_basic_download.html new file mode 100644 index 0000000..465fa6b --- /dev/null +++ b/templates/youtube-dl_basic_download.html @@ -0,0 +1,49 @@ +{% extends "base.html" %} + +{% macro my_setting_select(id, title, options, col='9', desc=None, value=None) %} + {{ macros.setting_top(title) }} +
+ +
+ {{ macros.setting_bottom(desc) }} +{% endmacro %} + +{% 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_select('preset', '동영상 포맷 프리셋', arg['preset_list'], col='3') }} + {{ macros.setting_input_text('format', '동영상 포맷', desc=['포맷 지정은 https://github.com/ytdl-org/youtube-dl/#format-selection 참고', '빈칸으로 두면 최고 화질로 다운로드합니다.']) }} + {{ my_setting_select('postprocessor', '후처리', arg['postprocessor_list'], col='3', desc='다운로드 후 FFmpeg로 후처리합니다.') }} + {{ macros.setting_buttons([['download_btn', '다운로드']]) }} +
+ + + + +{% endblock %} diff --git a/templates/youtube-dl_basic_setting.html b/templates/youtube-dl_basic_setting.html new file mode 100644 index 0000000..9157293 --- /dev/null +++ b/templates/youtube-dl_basic_setting.html @@ -0,0 +1,34 @@ +{% extends "base.html" %} {% block content %} +{{ macros.m_button_group([['globalSettingSaveBtn', '설정 저장'], ['globalOneExecuteBtn', '1회 실행'], ['globalImmediatelyExecuteBtn', '즉시 실행']])}} +{{ macros.m_row_start('5') }} +{{ macros.m_row_end() }} + +
+ {{ macros.setting_radio_with_value('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_download.html b/templates/youtube-dl_download_basic.html similarity index 100% rename from templates/youtube-dl_download.html rename to templates/youtube-dl_download_basic.html