Update repository URL to Gitea and sync structural changes

This commit is contained in:
2026-01-05 15:57:24 +09:00
parent 51ef1ee459
commit 1167e60c36
12 changed files with 318 additions and 376 deletions

View File

@@ -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

View File

@@ -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": ""
}

7
info.yaml Normal file
View File

@@ -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"

10
main.py
View File

@@ -8,15 +8,11 @@ from datetime import datetime
from flask import render_template, jsonify 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 from .my_youtube_dl import MyYoutubeDL, Status
logger = Plugin.logger logger = P.logger
package_name = Plugin.package_name package_name = P.package_name
ModelSetting = Plugin.ModelSetting ModelSetting = P.ModelSetting
class LogicMain(LogicModuleBase): class LogicMain(LogicModuleBase):

118
mod_basic.py Normal file
View File

@@ -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", "오디오 추출"],
]

18
model.py Normal file
View File

@@ -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)

View File

@@ -8,14 +8,16 @@ from datetime import datetime
from threading import Thread from threading import Thread
from enum import Enum 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 from .setup import P
ModelSetting = Plugin.ModelSetting
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")) int(ModelSetting.get("youtube_dl_package"))
if ModelSetting.get("youtube_dl_package") if ModelSetting.get("youtube_dl_package")
else 1 # LogicMain.db_default["youtube_dl_package"] else 1 # LogicMain.db_default["youtube_dl_package"]
@@ -140,7 +142,9 @@ class MyYoutubeDL:
} }
ydl_opts.update(self.opts) ydl_opts.update(self.opts)
with youtube_dl.YoutubeDL(ydl_opts) as ydl: 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): # 다운로드 성공 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) path = i.replace(self.temp_path, self.save_path, 1)
@@ -190,12 +194,13 @@ class MyYoutubeDL:
if http_headers: if http_headers:
ydl_opts["http_headers"] = http_headers ydl_opts["http_headers"] = http_headers
with youtube_dl.YoutubeDL(ydl_opts) as ydl: with youtube_dl.YoutubeDL(ydl_opts) as ydl:
# info = ydl.extract_info(url, download=False)
info = ydl.extract_info(url, download=False) info = ydl.extract_info(url, download=False)
except Exception as error: except Exception as error:
logger.error("Exception:%s", error) logger.error("Exception:%s", error)
logger.error(traceback.format_exc()) logger.error(traceback.format_exc())
return None return None
return info return ydl.sanitize_info(info)
def my_hook(self, data): def my_hook(self, data):
if self.status != Status.STOP: if self.status != Status.STOP:

346
plugin.py
View File

@@ -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/<sub>", 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()

77
setup.py Normal file
View File

@@ -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

View File

@@ -0,0 +1,49 @@
{% extends "base.html" %}
{% macro my_setting_select(id, title, options, col='9', desc=None, value=None) %}
{{ macros.setting_top(title) }}
<div class="input-group col-sm-{{ col }}">
<select id="{{ id }}" name="{{ id }}" class="form-control form-control-sm">
{% set ns = namespace(optgroup=none) %}
{% for item in options %}
{% if ns.optgroup != item[2] %}
{% if ns.optgroup is not none %}
</optgroup>
{% endif %}
{% if item[2] is not none %}
<optgroup label="{{ item[2] }}">
{% endif %}
{% set ns.optgroup = item[2] %}
{% endif %}
{% if value is not none and value == item[0] %}
<option value="{{ item[0] }}" selected>{{ item[1] }}</option>
{% else %}
<option value="{{ item[0] }}">{{ item[1] }}</option>
{% endif %}
{% endfor %}
{% if ns.optgroup is not none %}
</optgroup>
{% endif %}
</select>
</div>
{{ macros.setting_bottom(desc) }}
{% endmacro %}
{% block content %}
<form id="download">
{{ 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', '다운로드']]) }}
</form>
<script>
"use strict";
const package_name = '{{ arg["package_name"] }}';
</script>
<script src="{{ url_for('.static', filename='%s.js' % arg['template_name']) }}?ver={{ arg['package_version'] }}"></script>
{% endblock %}

View File

@@ -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() }}
<form id="setting">
{{ 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', '저장']]) }}#}
</form>
<script>
"use strict"
const package_name = '{{ arg["package_name"] }}'
</script>
<script src="{{ url_for('.static', filename='%s.js' % arg['template_name']) }}?ver={{ arg['package_version'] }}"></script>
{% endblock %}