v1.6.4 FFmpeg 경로 설정 추가

FFmpeg 경로 설정 추가
API에서 GET 요청 지원
This commit is contained in:
joyfuI
2020-07-25 03:06:03 +09:00
parent f78fde9d19
commit 33b70e3ec7
9 changed files with 208 additions and 142 deletions

View File

@@ -20,7 +20,7 @@ API에선 직접 비트레이트를 설정할 수 있습니다.
## API ## API
### 공통사항 ### 공통사항
모든 요청은 `POST`만 받습니다. 그리고 응답은 `JSON` 형식입니다. 모든 요청은 `POST` 또는 `GET`만 받습니다. 그리고 응답은 `JSON` 형식입니다.
모든 요청엔 *플러그인 이름* 정보가 있어야 합니다. `plugin` 키에 담아서 보내면 됩니다. 만약 *플러그인 이름* 정보가 없으면 **403 에러**를 반환합니다. 모든 요청엔 *플러그인 이름* 정보가 있어야 합니다. `plugin` 키에 담아서 보내면 됩니다. 만약 *플러그인 이름* 정보가 없으면 **403 에러**를 반환합니다.
요청을 처리하는 과정에서 예외가 발생하면 **500 에러**를 반환합니다. 이건 저한테 로그와 함께 알려주시면 됩니다. 요청을 처리하는 과정에서 예외가 발생하면 **500 에러**를 반환합니다. 이건 저한테 로그와 함께 알려주시면 됩니다.
모든 응답에는 `errorCode` 키가 있습니다. 코드의 의미는 아래 문단 참고 모든 응답에는 `errorCode` 키가 있습니다. 코드의 의미는 아래 문단 참고
@@ -131,6 +131,12 @@ API에선 직접 비트레이트를 설정할 수 있습니다.
물론 해당 정보가 없으면 null입니다. 물론 해당 정보가 없으면 null입니다.
## Changelog ## Changelog
v1.6.4
* FFmpeg 경로 설정 추가
SJVA에 내장된 버전 말고 원하는 버전을 사용할 수 있습니다.
* API에서 GET 요청 지원
이제 GET 요청으로도 API를 사용할 수 있습니다.
v1.6.3 v1.6.3
* 프록시 기능을 사용해도 국가차단 우회가 안 되는 문제 수정 * 프록시 기능을 사용해도 국가차단 우회가 안 되는 문제 수정

View File

@@ -1 +1 @@
{"description": "\uc720\ud29c\ube0c, \ub124\uc774\ubc84TV \ub4f1 \ub3d9\uc601\uc0c1 \uc0ac\uc774\ud2b8\uc5d0\uc11c \ub3d9\uc601\uc0c1 \ub2e4\uc6b4\ub85c\ub4dc", "name": "youtube-dl", "more": "", "version": "1.6.3", "home": "https://github.com/joyfuI/youtube-dl", "category_name": "vod", "developer": "joyfuI"} {"description": "\uc720\ud29c\ube0c, \ub124\uc774\ubc84TV \ub4f1 \ub3d9\uc601\uc0c1 \uc0ac\uc774\ud2b8\uc5d0\uc11c \ub3d9\uc601\uc0c1 \ub2e4\uc6b4\ub85c\ub4dc", "name": "youtube-dl", "more": "", "version": "1.6.4", "home": "https://github.com/joyfuI/youtube-dl", "category_name": "vod", "developer": "joyfuI"}

View File

@@ -3,13 +3,14 @@
# python # python
import os import os
import sys import sys
import platform
import subprocess import subprocess
import traceback import traceback
# third-party # third-party
# sjva 공용 # sjva 공용
from framework import db, path_data from framework import db, path_app_root, path_data
from framework.util import Util from framework.util import Util
# 패키지 # 패키지
@@ -20,6 +21,7 @@ from .model import ModelSetting
class Logic(object): class Logic(object):
db_default = { db_default = {
'db_version': '1', 'db_version': '1',
'ffmpeg_path': 'ffmpeg' if platform.system() != 'Windows' else os.path.join(path_app_root, 'bin', 'Windows', 'ffmpeg.exe'),
'temp_path': os.path.join(path_data, 'download_tmp'), 'temp_path': os.path.join(path_data, 'download_tmp'),
'save_path': os.path.join(path_data, 'download'), 'save_path': os.path.join(path_data, 'download'),
'default_filename': '%(title)s-%(id)s.%(ext)s', 'default_filename': '%(title)s-%(id)s.%(ext)s',
@@ -45,16 +47,15 @@ class Logic(object):
logger.debug('%s plugin_load', package_name) logger.debug('%s plugin_load', package_name)
Logic.db_init() Logic.db_init()
# 모듈 설치
try: try:
import glob2 import glob2
except ImportError: except ImportError:
# glob2 설치
logger.debug('glob2 install') logger.debug('glob2 install')
logger.debug(subprocess.check_output([sys.executable, '-m', 'pip', 'install', 'glob2'], universal_newlines=True)) logger.debug(subprocess.check_output([sys.executable, '-m', 'pip', 'install', 'glob2'], universal_newlines=True))
try: try:
import flask_cors import flask_cors
except ImportError: except ImportError:
# flask-cors 설치
logger.debug('flask-cors install') logger.debug('flask-cors install')
logger.debug(subprocess.check_output([sys.executable, '-m', 'pip', 'install', 'flask-cors'], universal_newlines=True)) logger.debug(subprocess.check_output([sys.executable, '-m', 'pip', 'install', 'flask-cors'], universal_newlines=True))

View File

@@ -9,15 +9,19 @@ from flask import jsonify
# 패키지 # 패키지
from .plugin import logger from .plugin import logger
from .my_youtube_dl import Status from .my_youtube_dl import MyYoutubeDL, Status
######################################################### #########################################################
class LogicNormal(object): class LogicNormal(object):
youtube_dl_list = [] youtube_dl_list = []
@staticmethod
def get_youtube_dl_version():
return MyYoutubeDL.get_version()
@staticmethod @staticmethod
def get_preset_list(): def get_preset_list():
preset_list = [ return [
['bestvideo+bestaudio/best', '최고 화질'], ['bestvideo+bestaudio/best', '최고 화질'],
['bestvideo[height<=1080]+bestaudio/best[height<=1080]', '1080p'], ['bestvideo[height<=1080]+bestaudio/best[height<=1080]', '1080p'],
['worstvideo+worstaudio/worst', '최저 화질'], ['worstvideo+worstaudio/worst', '최저 화질'],
@@ -27,11 +31,10 @@ class LogicNormal(object):
['bestaudio/best', '오디오만'], ['bestaudio/best', '오디오만'],
['_custom', '사용자 정의'] ['_custom', '사용자 정의']
] ]
return preset_list
@staticmethod @staticmethod
def get_postprocessor_list(): def get_postprocessor_list():
postprocessor_list = [ return [
['', '후처리 안함', None], ['', '후처리 안함', None],
['mp4', 'MP4', '비디오 변환'], ['mp4', 'MP4', '비디오 변환'],
['flv', 'FLV', '비디오 변환'], ['flv', 'FLV', '비디오 변환'],
@@ -51,7 +54,6 @@ class LogicNormal(object):
['vorbis', 'Vorbis', '오디오 추출'], ['vorbis', 'Vorbis', '오디오 추출'],
['wav', 'WAV', '오디오 추출'] ['wav', 'WAV', '오디오 추출']
] ]
return postprocessor_list
@staticmethod @staticmethod
def get_postprocessor(): def get_postprocessor():
@@ -64,6 +66,42 @@ class LogicNormal(object):
extract_audio.append(i[0]) extract_audio.append(i[0])
return video_convertor, extract_audio return video_convertor, extract_audio
@staticmethod
def download(**kwagrs):
logger.debug(kwagrs)
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']
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 postprocessor:
opts['postprocessors'] = postprocessor
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']
youtube_dl = MyYoutubeDL(plugin, url, filename, temp_path, save_path, opts)
youtube_dl.key = kwagrs.get('key')
LogicNormal.youtube_dl_list.append(youtube_dl) # 리스트 추가
return youtube_dl
@staticmethod @staticmethod
def get_data(youtube_dl): def get_data(youtube_dl):
try: try:
@@ -86,16 +124,16 @@ class LogicNormal(object):
data['percent'] = '0' data['percent'] = '0'
data['eta'] = youtube_dl.progress_hooks['eta'] if youtube_dl.progress_hooks['eta'] is not None else '' 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['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: # 다운로드 전 if youtube_dl.status == Status.READY: # 다운로드 전
data['start_time'] = '' data['start_time'] = ''
data['download_time'] = '' data['download_time'] = ''
else: else:
if youtube_dl.end_time is None: # 완료 전 if youtube_dl.end_time is None: # 완료 전
download_time = datetime.now() - youtube_dl.start_time download_time = datetime.now() - youtube_dl.start_time
else: else:
download_time = youtube_dl.end_time - youtube_dl.start_time download_time = youtube_dl.end_time - youtube_dl.start_time
data['end_time'] = youtube_dl.end_time.strftime('%m-%d %H:%M:%S') 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']): # 둘 다 값이 있으면 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['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['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['percent'] = '%.2f' % (float(youtube_dl.progress_hooks['downloaded_bytes']) / float(youtube_dl.progress_hooks['total_bytes']) * 100)
@@ -107,6 +145,10 @@ class LogicNormal(object):
logger.error(traceback.format_exc()) logger.error(traceback.format_exc())
return None return None
@staticmethod
def get_info_dict(url, proxy):
MyYoutubeDL.get_info_dict(url, proxy)
@staticmethod @staticmethod
def human_readable_size(size, suffix=''): def human_readable_size(size, suffix=''):
for unit in ('Bytes', 'KB', 'MB', 'GB', 'TB', 'PB', 'EB', 'ZB'): for unit in ('Bytes', 'KB', 'MB', 'GB', 'TB', 'PB', 'EB', 'ZB'):

View File

@@ -39,8 +39,8 @@ class Status(Enum):
return str_list[self.value] return str_list[self.value]
class Youtube_dl(object): class MyYoutubeDL(object):
_index = 0 __index = 0
_last_msg = '' _last_msg = ''
def __init__(self, plugin, url, filename, temp_path, save_path=None, opts=None): def __init__(self, plugin, url, filename, temp_path, save_path=None, opts=None):
@@ -58,10 +58,10 @@ class Youtube_dl(object):
os.makedirs(save_path) os.makedirs(save_path)
self.save_path = save_path self.save_path = save_path
self.opts = opts self.opts = opts
self.index = Youtube_dl._index self.index = MyYoutubeDL.__index
Youtube_dl._index += 1 MyYoutubeDL.__index += 1
self._status = Status.READY self.__status = Status.READY
self._thread = None self.__thread = None
self.key = None self.key = None
self.start_time = None # 시작 시간 self.start_time = None # 시작 시간
self.end_time = None # 종료 시간 self.end_time = None # 종료 시간
@@ -86,8 +86,8 @@ class Youtube_dl(object):
def start(self): def start(self):
if self.status != Status.READY: if self.status != Status.READY:
return False return False
self._thread = Thread(target=self.run) self.__thread = Thread(target=self.run)
self._thread.start() self.__thread.start()
return True return True
def run(self): def run(self):
@@ -96,7 +96,7 @@ class Youtube_dl(object):
try: try:
self.start_time = datetime.now() self.start_time = datetime.now()
self.status = Status.START self.status = Status.START
info_dict = Youtube_dl.get_info_dict(self.url, self.opts.get('proxy')) # 동영상 정보 가져오기 info_dict = MyYoutubeDL.get_info_dict(self.url, self.opts.get('proxy')) # 동영상 정보 가져오기
if info_dict is None: # 가져오기 실패 if info_dict is None: # 가져오기 실패
self.status = Status.ERROR self.status = Status.ERROR
return return
@@ -163,7 +163,7 @@ class Youtube_dl(object):
logger.error('Exception:%s', e) logger.error('Exception:%s', e)
logger.error(traceback.format_exc()) logger.error(traceback.format_exc())
return None return None
return json.loads(Youtube_dl._last_msg) return json.loads(MyYoutubeDL._last_msg)
def my_hook(self, d): def my_hook(self, d):
if self.status != Status.STOP: if self.status != Status.STOP:
@@ -188,18 +188,18 @@ class Youtube_dl(object):
@property @property
def status(self): def status(self):
return self._status return self.__status
@status.setter @status.setter
def status(self, value): def status(self, value):
from .plugin import socketio_emit from .plugin import socketio_emit
self._status = value self.__status = value
socketio_emit('status', self) socketio_emit('status', self)
class MyLogger(object): class MyLogger(object):
def debug(self, msg): def debug(self, msg):
Youtube_dl._last_msg = msg MyYoutubeDL._last_msg = msg
if msg.find('') != -1 or msg.find('{') != -1: if msg.find('') != -1 or msg.find('{') != -1:
return # 과도한 로그 방지 return # 과도한 로그 방지
logger.debug(msg) logger.debug(msg)

164
plugin.py
View File

@@ -3,6 +3,7 @@
# python # python
import os import os
import traceback import traceback
import subprocess
# third-party # third-party
from flask import Blueprint, request, render_template, redirect, jsonify, abort from flask import Blueprint, request, render_template, redirect, jsonify, abort
@@ -18,7 +19,6 @@ logger = get_logger(package_name)
from .logic import Logic from .logic import Logic
from .logic_normal import LogicNormal from .logic_normal import LogicNormal
from .model import ModelSetting from .model import ModelSetting
from .my_youtube_dl import Youtube_dl
######################################################### #########################################################
# 플러그인 공용 # 플러그인 공용
@@ -34,7 +34,7 @@ menu = {
} }
plugin_info = { plugin_info = {
'version': '1.6.3', 'version': '1.6.4',
'name': 'youtube-dl', 'name': 'youtube-dl',
'category_name': 'vod', 'category_name': 'vod',
'developer': 'joyfuI', 'developer': 'joyfuI',
@@ -67,7 +67,7 @@ def first_menu(sub):
if sub == 'setting': if sub == 'setting':
arg.update(ModelSetting.to_dict()) arg.update(ModelSetting.to_dict())
arg['youtube_dl_version'] = Youtube_dl.get_version() arg['youtube_dl_version'] = LogicNormal.get_youtube_dl_version()
return render_template('%s_%s.html' % (package_name, sub), arg=arg) return render_template('%s_%s.html' % (package_name, sub), arg=arg)
elif sub == 'download': elif sub == 'download':
@@ -100,33 +100,33 @@ def ajax(sub):
return jsonify(ret) return jsonify(ret)
# UI 요청 # UI 요청
elif sub == 'ffmpeg_version':
path = request.form['path']
ret = subprocess.check_output([path, '-version']).replace('\n', '<br>')
return jsonify(ret)
elif sub == 'download': elif sub == 'download':
url = request.form['url']
filename = request.form['filename']
temp_path = ModelSetting.get('temp_path')
save_path = ModelSetting.get('save_path')
format_code = request.form['format']
postprocessor = request.form['postprocessor'] postprocessor = request.form['postprocessor']
proxy = ModelSetting.get('proxy')
opts = {}
if format_code:
opts['format'] = format_code
video_convertor, extract_audio = LogicNormal.get_postprocessor() video_convertor, extract_audio = LogicNormal.get_postprocessor()
preferedformat = None
preferredcodec = None
preferredquality = None
if postprocessor in video_convertor: if postprocessor in video_convertor:
opts['postprocessors'] = [{ preferedformat = postprocessor
'key': 'FFmpegVideoConvertor',
'preferedformat': postprocessor
}]
elif postprocessor in extract_audio: elif postprocessor in extract_audio:
opts['postprocessors'] = [{ preferredcodec = postprocessor
'key': 'FFmpegExtractAudio', preferredquality = 192
'preferredcodec': postprocessor, youtube_dl = LogicNormal.download(plugin=package_name,
'preferredquality': '192' url=request.form['url'],
}] filename=request.form['filename'],
if proxy: temp_path=ModelSetting.get('temp_path'),
opts['proxy'] = proxy save_path=ModelSetting.get('save_path'),
youtube_dl = Youtube_dl(package_name, url, filename, temp_path, save_path, opts) format=request.form['format'],
LogicNormal.youtube_dl_list.append(youtube_dl) # 리스트 추가 preferedformat=preferedformat,
preferredcodec=preferredcodec,
preferredquality=preferredquality,
proxy=ModelSetting.get('proxy'),
ffmpeg_path=ModelSetting.get('ffmpeg_path'))
youtube_dl.start() youtube_dl.start()
socketio_emit('add', youtube_dl) socketio_emit('add', youtube_dl)
return jsonify([]) return jsonify([])
@@ -154,75 +154,63 @@ def ajax(sub):
@blueprint.route('/api/<sub>', methods=['GET', 'POST']) @blueprint.route('/api/<sub>', methods=['GET', 'POST'])
@check_api @check_api
def api(sub): def api(sub):
plugin = request.form.get('plugin') plugin = request.values.get('plugin')
logger.debug('API %s %s: %s', package_name, sub, plugin) logger.debug('API %s %s: %s', package_name, sub, plugin)
if not plugin: # 요청한 플러그인명이 빈문자열이거나 None면 if not plugin: # 요청한 플러그인명이 빈문자열이거나 None면
abort(403) # 403 에러(거부) abort(403) # 403 에러(거부)
try: try:
# 동영상 정보를 반환하는 API # 동영상 정보를 반환하는 API
if sub == 'info_dict': if sub == 'info_dict':
url = request.form.get('url') url = request.values.get('url')
ret = { ret = {
'errorCode': 0, 'errorCode': 0,
'info_dict': None 'info_dict': None
} }
if None in (url,): if None in (url,):
return LogicNormal.abort(ret, 1) # 필수 요청 변수가 없음 return LogicNormal.abort(ret, 1) # 필수 요청 변수가 없음
if not url.startswith('http'): if not url.startswith('http'):
return LogicNormal.abort(ret, 2) # 잘못된 동영상 주소 return LogicNormal.abort(ret, 2) # 잘못된 동영상 주소
info_dict = Youtube_dl.get_info_dict(url, ModelSetting.get('proxy')) info_dict = LogicNormal.get_info_dict(url, ModelSetting.get('proxy'))
if info_dict is None: if info_dict is None:
return LogicNormal.abort(ret, 10) # 실패 return LogicNormal.abort(ret, 10) # 실패
ret['info_dict'] = info_dict ret['info_dict'] = info_dict
return jsonify(ret) return jsonify(ret)
# 다운로드 준비를 요청하는 API # 다운로드 준비를 요청하는 API
elif sub == 'download': elif sub == 'download':
key = request.form.get('key') key = request.values.get('key')
url = request.form.get('url') url = request.values.get('url')
filename = request.form.get('filename', ModelSetting.get('default_filename')) filename = request.values.get('filename', ModelSetting.get('default_filename'))
save_path = request.form.get('save_path', ModelSetting.get('save_path')) save_path = request.values.get('save_path', ModelSetting.get('save_path'))
format_code = request.form.get('format', None) format_code = request.values.get('format', None)
preferedformat = request.form.get('preferedformat', None) preferedformat = request.values.get('preferedformat', None)
preferredcodec = request.form.get('preferredcodec', None) preferredcodec = request.values.get('preferredcodec', None)
preferredquality = request.form.get('preferredquality', 192) preferredquality = request.values.get('preferredquality', 192)
archive = request.form.get('archive', None) archive = request.values.get('archive', None)
start = request.form.get('start', False) start = request.values.get('start', False)
ret = { ret = {
'errorCode': 0, 'errorCode': 0,
'index': None 'index': None
} }
if None in (key, url): if None in (key, url):
return LogicNormal.abort(ret, 1) # 필수 요청 변수가 없음 return LogicNormal.abort(ret, 1) # 필수 요청 변수가 없음
if not url.startswith('http'): if not url.startswith('http'):
return LogicNormal.abort(ret, 2) # 잘못된 동영상 주소 return LogicNormal.abort(ret, 2) # 잘못된 동영상 주소
opts = {} if preferredcodec not in (None, 'best', 'mp3', 'aac', 'flac', 'm4a', 'opus', 'vorbis', 'wav'):
if format_code is not None: return LogicNormal.abort(ret, 5) # 허용되지 않은 값이 있음
opts['format'] = format_code youtube_dl = LogicNormal.download(plugin=plugin,
postprocessor = [] url=url,
if preferedformat is not None: filename=filename,
postprocessor.append({ temp_path=ModelSetting.get('temp_path'),
'key': 'FFmpegVideoConvertor', save_path=save_path,
'preferedformat': preferedformat format=format_code,
}) preferedformat=preferedformat,
if preferredcodec is not None: preferredcodec=preferredcodec,
if preferredcodec not in ('best', 'mp3', 'aac', 'flac', 'm4a', 'opus', 'vorbis', 'wav'): preferredquality=preferredquality,
return LogicNormal.abort(ret, 5) # 허용되지 않은 값이 있음 archive=archive,
postprocessor.append({ proxy=ModelSetting.get('proxy'),
'key': 'FFmpegExtractAudio', ffmpeg_path=ModelSetting.get('ffmpeg_path'),
'preferredcodec': preferredcodec, key=key)
'preferredquality': str(preferredquality)
})
if postprocessor:
opts['postprocessors'] = postprocessor
proxy = ModelSetting.get('proxy')
if proxy:
opts['proxy'] = proxy
if archive is not None:
opts['download_archive'] = archive
youtube_dl = Youtube_dl(plugin, url, filename, ModelSetting.get('temp_path'), save_path, opts)
youtube_dl.key = key
LogicNormal.youtube_dl_list.append(youtube_dl) # 리스트 추가
ret['index'] = youtube_dl.index ret['index'] = youtube_dl.index
if start: if start:
youtube_dl.start() youtube_dl.start()
@@ -231,50 +219,50 @@ def api(sub):
# 다운로드 시작을 요청하는 API # 다운로드 시작을 요청하는 API
elif sub == 'start': elif sub == 'start':
index = request.form.get('index') index = request.values.get('index')
key = request.form.get('key') key = request.values.get('key')
ret = { ret = {
'errorCode': 0, 'errorCode': 0,
'status': None 'status': None
} }
if None in (index, key): if None in (index, key):
return LogicNormal.abort(ret, 1) # 필수 요청 변수가 없음 return LogicNormal.abort(ret, 1) # 필수 요청 변수가 없음
index = int(index) 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) # 인덱스 범위를 벗어남 return LogicNormal.abort(ret, 3) # 인덱스 범위를 벗어남
youtube_dl = LogicNormal.youtube_dl_list[index] youtube_dl = LogicNormal.youtube_dl_list[index]
if youtube_dl.key != key: if youtube_dl.key != key:
return LogicNormal.abort(ret, 4) # 키가 일치하지 않음 return LogicNormal.abort(ret, 4) # 키가 일치하지 않음
ret['status'] = youtube_dl.status.name ret['status'] = youtube_dl.status.name
if not youtube_dl.start(): if not youtube_dl.start():
return LogicNormal.abort(ret, 10) # 실패 return LogicNormal.abort(ret, 10) # 실패
return jsonify(ret) return jsonify(ret)
# 다운로드 중지를 요청하는 API # 다운로드 중지를 요청하는 API
elif sub == 'stop': elif sub == 'stop':
index = request.form.get('index') index = request.values.get('index')
key = request.form.get('key') key = request.values.get('key')
ret = { ret = {
'errorCode': 0, 'errorCode': 0,
'status': None 'status': None
} }
if None in (index, key): if None in (index, key):
return LogicNormal.abort(ret, 1) # 필수 요청 변수가 없음 return LogicNormal.abort(ret, 1) # 필수 요청 변수가 없음
index = int(index) 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) # 인덱스 범위를 벗어남 return LogicNormal.abort(ret, 3) # 인덱스 범위를 벗어남
youtube_dl = LogicNormal.youtube_dl_list[index] youtube_dl = LogicNormal.youtube_dl_list[index]
if youtube_dl.key != key: if youtube_dl.key != key:
return LogicNormal.abort(ret, 4) # 키가 일치하지 않음 return LogicNormal.abort(ret, 4) # 키가 일치하지 않음
ret['status'] = youtube_dl.status.name ret['status'] = youtube_dl.status.name
if not youtube_dl.stop(): if not youtube_dl.stop():
return LogicNormal.abort(ret, 10) # 실패 return LogicNormal.abort(ret, 10) # 실패
return jsonify(ret) return jsonify(ret)
# 현재 상태를 반환하는 API # 현재 상태를 반환하는 API
elif sub == 'status': elif sub == 'status':
index = request.form.get('index') index = request.values.get('index')
key = request.form.get('key') key = request.values.get('key')
ret = { ret = {
'errorCode': 0, 'errorCode': 0,
'status': None, 'status': None,
@@ -284,13 +272,13 @@ def api(sub):
'save_path': None 'save_path': None
} }
if None in (index, key): if None in (index, key):
return LogicNormal.abort(ret, 1) # 필수 요청 변수가 없음 return LogicNormal.abort(ret, 1) # 필수 요청 변수가 없음
index = int(index) 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) # 인덱스 범위를 벗어남 return LogicNormal.abort(ret, 3) # 인덱스 범위를 벗어남
youtube_dl = LogicNormal.youtube_dl_list[index] youtube_dl = LogicNormal.youtube_dl_list[index]
if youtube_dl.key != key: if youtube_dl.key != key:
return LogicNormal.abort(ret, 4) # 키가 일치하지 않음 return LogicNormal.abort(ret, 4) # 키가 일치하지 않음
ret['status'] = youtube_dl.status.name ret['status'] = youtube_dl.status.name
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['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['end_time'] = youtube_dl.end_time.strftime('%Y-%m-%dT%H:%M:%S') if youtube_dl.end_time is not None else None
@@ -301,7 +289,7 @@ def api(sub):
logger.error('Exception:%s', e) logger.error('Exception:%s', e)
logger.error(traceback.format_exc()) logger.error(traceback.format_exc())
abort(500) # 500 에러(서버 오류) abort(500) # 500 에러(서버 오류)
abort(404) # 404 에러(페이지 없음) abort(404) # 404 에러(페이지 없음)
######################################################### #########################################################
# socketio # socketio

View File

@@ -57,7 +57,7 @@
// 후처리 변경 // 후처리 변경
$('#postprocessor').change(function () { $('#postprocessor').change(function () {
if ($(this).find($('option[value="' + $(this).val() + '"]')).parent().attr('label') === '오디오 추출') { if ($(this).find($(`option[value="${$(this).val()}"]`)).parent().attr('label') === '오디오 추출') {
$('#preset').val('bestaudio/best').change(); $('#preset').val('bestaudio/best').change();
} }
}); });
@@ -72,7 +72,7 @@
return; return;
} }
$.ajax({ $.ajax({
url: '/' + package_name + '/ajax/download', url: `/${package_name}/ajax/download`,
type: 'POST', type: 'POST',
cache: false, cache: false,
data: { data: {
@@ -81,12 +81,15 @@
format: $('#format').val(), format: $('#format').val(),
postprocessor: $('#postprocessor').val() postprocessor: $('#postprocessor').val()
}, },
dataType: 'json', dataType: 'json'
success: function () { }).done(function () {
$.notify('<strong>분석중..</strong>', { $.notify('<strong>분석중..</strong>', {
type: 'info' type: 'info'
}); });
} }).fail(function () {
$.notify('<strong>다운로드 요청 실패</strong>', {
type: 'danger'
});
}); });
return false; return false;
}); });

View File

@@ -43,7 +43,7 @@
const package_name = '{{ arg["package_name"] }}'; const package_name = '{{ arg["package_name"] }}';
$(function () { $(function () {
let socket = io.connect(location.origin + '/' + package_name); let socket = io.connect(`${location.origin}/${package_name}`);
socket.on('add', function (data) { socket.on('add', function (data) {
$('#list').append(make_item(data)); $('#list').append(make_item(data));
@@ -54,33 +54,31 @@
}); });
$.ajax({ $.ajax({
url: '/' + package_name + '/ajax/list', url: `/${package_name}/ajax/list`,
type: 'POST', type: 'POST',
cache: false, cache: false,
data: {}, data: {},
dataType: 'json', dataType: 'json'
success: function (data) { }).done(function (data) {
let str = ''; let str = '';
for (let i of data) { for (let item of data) {
str += make_item(i); str += make_item(item);
}
$('#list').html(str);
} }
$('#list').html(str);
}); });
$('#list').on('click', '.youtube-dl_stop', function () { $('#list').on('click', '.youtube-dl_stop', function () {
let index = $(this).data('index'); let index = $(this).data('index');
$.ajax({ $.ajax({
url: '/' + package_name + '/ajax/stop', url: `/${package_name}/ajax/stop`,
type: 'POST', type: 'POST',
cache: false, cache: false,
data: { data: {
index: index index: index
}, },
dataType: 'json', dataType: 'json'
success: function () { }).done(function () {
location.reload(); // 새로고침 location.reload();
}
}); });
return false; return false;
}); });
@@ -158,8 +156,8 @@
} }
function status_html(data) { function status_html(data) {
$('#item_' + data.index).html(get_item(data)); $(`#item_${data.index}`).html(get_item(data));
$('#detail_' + data.index).html(get_detail(data)); $(`#detail_${data.index}`).html(get_detail(data));
} }
</script> </script>

View File

@@ -4,10 +4,11 @@
<div> <div>
{{ macros.setting_input_text('youtube_dl_version', 'youtube-dl 버전', value=arg['youtube_dl_version']) }} {{ macros.setting_input_text('youtube_dl_version', 'youtube-dl 버전', value=arg['youtube_dl_version']) }}
<form id="setting"> <form id="setting">
{{ macros.setting_input_text('temp_path', '임시 폴더', value=arg['temp_path'], placeholder='임시 폴더 경로', desc='다운로드 파일이 임시로 저장될 폴더 입니다.') }} {{ macros.setting_input_text_and_buttons('ffmpeg_path', 'FFmpeg 경로', [['ffmpeg_version', '버전확인']], value=arg['ffmpeg_path'], placeholder='ffmpeg', desc='SJVA에 내장된 버전 말고 원하는 버전을 사용할 수 있습니다.') }}
{{ macros.setting_input_text('save_path', '저장 폴더', value=arg['save_path'], placeholder='저장 폴더 경로', desc='정상적으로 완료된 파일이 이동할 폴더 입니다.') }} {{ macros.setting_input_text('temp_path', '임시 폴더', value=arg['temp_path'], desc='다운로드 파일이 임시로 저장될 폴더입니다.') }}
{{ macros.setting_input_text('default_filename', '기본 파일명', value=arg['default_filename'], placeholder='저장 폴더 경로', desc=['템플릿 규칙은 https://github.com/ytdl-org/youtube-dl/blob/master/README.md#output-template 참고', '기본값은 "%(title)s-%(id)s.%(ext)s"입니다.']) }} {{ macros.setting_input_text('save_path', '저장 폴더', value=arg['save_path'], desc='정상적으로 완료된 파일이 이동할 폴더입니다.') }}
{{ macros.setting_input_text('proxy', '프록시', value=arg['proxy'], placeholder='프록시 주소', desc=['HTTP/HTTPS/SOCKS를 지원합니다. 예) socks5://127.0.0.1:1080/', '빈칸으로 두면 프록시를 사용하지 않습니다.']) }} {{ macros.setting_input_text('default_filename', '기본 파일명', value=arg['default_filename'], desc=['템플릿 규칙은 https://github.com/ytdl-org/youtube-dl/blob/master/README.md#output-template 참고', '기본값은 "%(title)s-%(id)s.%(ext)s"입니다.']) }}
{{ macros.setting_input_text('proxy', '프록시', value=arg['proxy'], desc=['HTTP/HTTPS/SOCKS를 지원합니다. 예) socks5://127.0.0.1:1080/', '빈칸으로 두면 프록시를 사용하지 않습니다.']) }}
{{ macros.setting_checkbox('activate_cors', 'CORS 허용', value=arg['activate_cors'], desc='API로의 크로스 도메인 요청을 허용합니다. 설정 저장 후 재시작이 필요합니다.') }} {{ macros.setting_checkbox('activate_cors', 'CORS 허용', value=arg['activate_cors'], desc='API로의 크로스 도메인 요청을 허용합니다. 설정 저장 후 재시작이 필요합니다.') }}
{{ macros.setting_button([['global_setting_save_btn', '저장']]) }} {{ macros.setting_button([['global_setting_save_btn', '저장']]) }}
</form> </form>
@@ -16,6 +17,33 @@
<script> <script>
"use strict"; "use strict";
const package_name = '{{ arg["package_name"] }}'; const package_name = '{{ arg["package_name"] }}';
$(function () {
$('#youtube_dl_version').prop('readonly', true);
// FFmpeg 버전확인
$('#ffmpeg_version').click(function () {
let ffmpeg_path = $('#ffmpeg_path').val()
$.ajax({
url: `/${package_name}/ajax/ffmpeg_version`,
type: 'POST',
cache: false,
data: {
path: ffmpeg_path.length === 0 ? 'ffmpeg' : ffmpeg_path
},
dataType: 'json'
}).done(function (data) {
$('#modal_title').html(`${ffmpeg_path} -version`);
$('#modal_body').html(data);
$('#large_modal').modal();
}).fail(function () {
$.notify('<strong>버전확인 실패</strong>', {
type: 'danger'
});
});
return false;
});
});
</script> </script>
{% endblock %} {% endblock %}