diff --git a/README.md b/README.md index 9f2102c..c7ab747 100644 --- a/README.md +++ b/README.md @@ -133,6 +133,9 @@ API를 제공합니다. 다른 플러그인에서 동영상 정보나 다운로 물론 해당 정보가 없으면 null입니다. ## Changelog +v2.3.1 +* yt-dlp 패키지명 변경 대응 + v2.3.0 * youtube-dlc를 yt-dlp로 변경 youtube-dlc가 2개월 넘게 커밋이 없어서 youtube-dlc의 포크 프로젝트인 yt-dlp로 변경했습니다. diff --git a/info.json b/info.json index 96e1b2b..dd5eb8e 100644 --- a/info.json +++ b/info.json @@ -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": "2.3.0", "home": "https://github.com/joyfuI/youtube-dl", "category_name": "vod", "developer": "joyfuI"} \ No newline at end of file +{"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": "2.3.1", "home": "https://github.com/joyfuI/youtube-dl", "category_name": "vod", "developer": "joyfuI"} \ No newline at end of file diff --git a/logic.py b/logic.py index 7f808c7..98fff17 100644 --- a/logic.py +++ b/logic.py @@ -1,5 +1,4 @@ # -*- coding: utf-8 -*- -######################################################### # python import os import sys @@ -18,13 +17,14 @@ from framework.util import Util from .plugin import logger, package_name from .logic_normal import LogicNormal from .model import ModelSetting -######################################################### + class Logic(object): db_default = { 'db_version': '2', 'youtube_dl_package': '0', - 'ffmpeg_path': '' if platform.system() != 'Windows' else os.path.join(path_app_root, 'bin', 'Windows', 'ffmpeg.exe'), + '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': '', @@ -55,12 +55,14 @@ class Logic(object): import glob2 except ImportError: 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)) # youtube-dl 업데이트 youtube_dl = LogicNormal.get_youtube_dl_package(ModelSetting.get('youtube_dl_package')) logger.debug('%s upgrade' % youtube_dl) - logger.debug(subprocess.check_output([sys.executable, '-m', 'pip', 'install', '--upgrade', youtube_dl], universal_newlines=True)) + logger.debug(subprocess.check_output([sys.executable, '-m', 'pip', 'install', '--upgrade', youtube_dl], + universal_newlines=True)) # 편의를 위해 json 파일 생성 from .plugin import plugin_info @@ -85,7 +87,8 @@ class Logic(object): if db_version < 2: logger.debug('youtube-dlc uninstall') - logger.debug(subprocess.check_output([sys.executable, '-m', 'pip', 'uninstall', '-y', 'youtube-dlc'], universal_newlines=True)) + logger.debug(subprocess.check_output([sys.executable, '-m', 'pip', 'uninstall', '-y', 'youtube-dlc'], + universal_newlines=True)) connect.commit() connect.close() diff --git a/logic_normal.py b/logic_normal.py index bbcc605..77dd234 100644 --- a/logic_normal.py +++ b/logic_normal.py @@ -1,5 +1,4 @@ # -*- coding: utf-8 -*- -######################################################### # python import traceback from datetime import datetime @@ -10,7 +9,7 @@ from flask import jsonify # 패키지 from .plugin import logger from .my_youtube_dl import MyYoutubeDL, Status -######################################################### + class LogicNormal(object): youtube_dl_list = [] @@ -18,7 +17,7 @@ class LogicNormal(object): @staticmethod def get_youtube_dl_package(index=None, import_pkg=False): packages = ['youtube-dl', 'yt-dlp'] - import_name = ['youtube_dl', 'youtube_dlc'] + import_name = ['youtube_dl', 'yt_dlp'] if import_pkg: return import_name if index is None else import_name[int(index)] else: @@ -26,7 +25,12 @@ class LogicNormal(object): @staticmethod def get_youtube_dl_version(): - return MyYoutubeDL.get_version() + try: + return MyYoutubeDL.get_version() + except Exception as e: + logger.error('Exception:%s', e) + logger.error(traceback.format_exc()) + return '패키지 임포트 실패' @staticmethod def get_default_filename(): @@ -136,28 +140,36 @@ class LogicNormal(object): data['status_str'] = youtube_dl.status.name data['status_ko'] = str(youtube_dl.status) data['end_time'] = '' - data['extractor'] = youtube_dl.info_dict['extractor'] if youtube_dl.info_dict['extractor'] is not None else '' - data['title'] = youtube_dl.info_dict['title'] if youtube_dl.info_dict['title'] is not None else youtube_dl.url + data['extractor'] = youtube_dl.info_dict['extractor'] if \ + youtube_dl.info_dict['extractor'] is not None else '' + data['title'] = youtube_dl.info_dict['title'] if \ + youtube_dl.info_dict['title'] is not None else youtube_dl.url data['uploader'] = youtube_dl.info_dict['uploader'] if youtube_dl.info_dict['uploader'] is not None else '' - data['uploader_url'] = youtube_dl.info_dict['uploader_url'] if youtube_dl.info_dict['uploader_url'] is not None else '' + data['uploader_url'] = youtube_dl.info_dict['uploader_url'] if \ + youtube_dl.info_dict['uploader_url'] is not None else '' data['downloaded_bytes_str'] = '' data['total_bytes_str'] = '' data['percent'] = '0' data['eta'] = youtube_dl.progress_hooks['eta'] if youtube_dl.progress_hooks['eta'] is not None else '' - data['speed_str'] = LogicNormal.human_readable_size(youtube_dl.progress_hooks['speed'], '/s') if youtube_dl.progress_hooks['speed'] is not None else '' - if youtube_dl.status == Status.READY: # 다운로드 전 + data['speed_str'] = LogicNormal.human_readable_size(youtube_dl.progress_hooks['speed'], '/s') if \ + youtube_dl.progress_hooks['speed'] is not None else '' + if youtube_dl.status == Status.READY: # 다운로드 전 data['start_time'] = '' data['download_time'] = '' else: - if youtube_dl.end_time is None: # 완료 전 + if youtube_dl.end_time is None: # 완료 전 download_time = datetime.now() - youtube_dl.start_time else: download_time = youtube_dl.end_time - youtube_dl.start_time data['end_time'] = youtube_dl.end_time.strftime('%m-%d %H:%M:%S') - if None not in (youtube_dl.progress_hooks['downloaded_bytes'], youtube_dl.progress_hooks['total_bytes']): # 둘 다 값이 있으면 - data['downloaded_bytes_str'] = LogicNormal.human_readable_size(youtube_dl.progress_hooks['downloaded_bytes']) + if None not in (youtube_dl.progress_hooks['downloaded_bytes'], + youtube_dl.progress_hooks['total_bytes']): # 둘 다 값이 있으면 + data['downloaded_bytes_str'] = LogicNormal.human_readable_size( + youtube_dl.progress_hooks['downloaded_bytes'] + ) data['total_bytes_str'] = LogicNormal.human_readable_size(youtube_dl.progress_hooks['total_bytes']) - data['percent'] = '%.2f' % (float(youtube_dl.progress_hooks['downloaded_bytes']) / float(youtube_dl.progress_hooks['total_bytes']) * 100) + data['percent'] = '%.2f' % (float(youtube_dl.progress_hooks['downloaded_bytes']) + / float(youtube_dl.progress_hooks['total_bytes']) * 100) data['start_time'] = youtube_dl.start_time.strftime('%m-%d %H:%M:%S') data['download_time'] = '%02d:%02d' % (download_time.seconds / 60, download_time.seconds % 60) return data diff --git a/model.py b/model.py index 57b29f4..6abc713 100644 --- a/model.py +++ b/model.py @@ -1,5 +1,4 @@ # -*- coding: utf-8 -*- -######################################################### # python import traceback import os @@ -14,7 +13,7 @@ from framework.util import Util from .plugin import logger, package_name app.config['SQLALCHEMY_BINDS'][package_name] = 'sqlite:///%s' % (os.path.join(path_data, 'db', '%s.db' % package_name)) -######################################################### + class ModelSetting(db.Model): __tablename__ = '%s_setting' % package_name diff --git a/my_youtube_dl.py b/my_youtube_dl.py index 381e913..dbf8964 100644 --- a/my_youtube_dl.py +++ b/my_youtube_dl.py @@ -10,8 +10,6 @@ import json from datetime import datetime from enum import Enum -# third-party - # sjva 공용, 패키지 import framework.common.celery as celery_shutil from .plugin import logger @@ -71,26 +69,26 @@ class MyYoutubeDL(object): self.__status = Status.READY self.__thread = None self.key = None - self.start_time = None # 시작 시간 - self.end_time = None # 종료 시간 + self.start_time = None # 시작 시간 + self.end_time = None # 종료 시간 # info_dict에서 얻는 정보 self.info_dict = { - 'extractor': None, # 타입 - 'title': None, # 제목 - 'uploader': None, # 업로더 - 'uploader_url': None # 업로더 주소 + 'extractor': None, # 타입 + 'title': None, # 제목 + 'uploader': None, # 업로더 + 'uploader_url': None # 업로더 주소 } # info_dict에서 얻는 정보(entries) # self.info_dict['playlist_index'] = None - # self.info_dict['duration'] = None # 길이 - # self.info_dict['format'] = None # 포맷 - # self.info_dict['thumbnail'] = None # 썸네일 + # self.info_dict['duration'] = None # 길이 + # self.info_dict['format'] = None # 포맷 + # self.info_dict['thumbnail'] = None # 썸네일 # progress_hooks에서 얻는 정보 self.progress_hooks = { - 'downloaded_bytes': None, # 다운로드한 크기 - 'total_bytes': None, # 전체 크기 - 'eta': None, # 예상 시간(s) - 'speed': None # 다운로드 속도(bytes/s) + 'downloaded_bytes': None, # 다운로드한 크기 + 'total_bytes': None, # 전체 크기 + 'eta': None, # 예상 시간(s) + 'speed': None # 다운로드 속도(bytes/s) } def start(self): diff --git a/plugin.py b/plugin.py index 2f7b17d..6752c25 100644 --- a/plugin.py +++ b/plugin.py @@ -1,11 +1,9 @@ # -*- coding: utf-8 -*- -######################################################### # python import os import sys import traceback import subprocess -import json # third-party from flask import Blueprint, request, render_template, redirect, jsonify, abort @@ -20,19 +18,23 @@ package_name = __name__.split('.')[0] logger = get_logger(package_name) from .logic import Logic from .logic_normal import LogicNormal -YOUTUBE_DL_PACKAGE = LogicNormal.get_youtube_dl_package(Logic.db_default['youtube_dl_package'], import_pkg=True) from .model import ModelSetting +YOUTUBE_DL_PACKAGE = LogicNormal.get_youtube_dl_package(Logic.db_default['youtube_dl_package'], import_pkg=True) + ######################################################### # 플러그인 공용 ######################################################### -blueprint = Blueprint(package_name, package_name, url_prefix='/%s' % package_name, template_folder=os.path.join(os.path.dirname(__file__), 'templates')) +blueprint = Blueprint(package_name, package_name, url_prefix='/%s' % package_name, + template_folder=os.path.join(os.path.dirname(__file__), 'templates'), + static_folder=os.path.join(os.path.dirname(__file__), 'static')) if ModelSetting.get_bool('activate_cors'): try: from flask_cors import CORS except ImportError: 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)) from flask_cors import CORS CORS(blueprint, resources={r"/youtube-dl/api/*": {"origins": "*"}}) @@ -45,7 +47,7 @@ menu = { } plugin_info = { - 'version': '2.3.0', + 'version': '2.3.1', 'name': 'youtube-dl', 'category_name': 'vod', 'developer': 'joyfuI', @@ -54,14 +56,17 @@ plugin_info = { 'more': '' } + def plugin_load(): Logic.plugin_load() global YOUTUBE_DL_PACKAGE YOUTUBE_DL_PACKAGE = LogicNormal.get_youtube_dl_package(ModelSetting.get('youtube_dl_package'), import_pkg=True) + def plugin_unload(): Logic.plugin_unload() + ######################################################### # WEB Menu ######################################################### @@ -69,11 +74,15 @@ def plugin_unload(): def home(): return redirect('/%s/list' % package_name) + @blueprint.route('/') @login_required def first_menu(sub): try: - arg = {'package_name': package_name} + arg = { + 'package_name': package_name, + 'template_name': '%s_%s' % (package_name, sub) + } if sub == 'setting': arg.update(ModelSetting.to_dict()) @@ -99,6 +108,7 @@ def first_menu(sub): logger.error(traceback.format_exc()) return render_template('sample.html', title='%s - %s' % (package_name, sub)) + ######################################################### # For UI ######################################################### @@ -168,6 +178,7 @@ def ajax(sub): logger.error('Exception:%s', e) logger.error(traceback.format_exc()) + ######################################################### # API ######################################################### @@ -188,12 +199,12 @@ def api(sub): 'info_dict': None } if None in (url,): - return LogicNormal.abort(ret, 1) # 필수 요청 변수가 없음 + return LogicNormal.abort(ret, 1) # 필수 요청 변수가 없음 if not url.startswith('http'): - return LogicNormal.abort(ret, 2) # 잘못된 동영상 주소 + return LogicNormal.abort(ret, 2) # 잘못된 동영상 주소 info_dict = LogicNormal.get_info_dict(url, ModelSetting.get('proxy')) if info_dict is None: - return LogicNormal.abort(ret, 10) # 실패 + return LogicNormal.abort(ret, 10) # 실패 ret['info_dict'] = info_dict return jsonify(ret) @@ -216,11 +227,11 @@ def api(sub): 'index': None } if None in (key, url): - return LogicNormal.abort(ret, 1) # 필수 요청 변수가 없음 + return LogicNormal.abort(ret, 1) # 필수 요청 변수가 없음 if not url.startswith('http'): - return LogicNormal.abort(ret, 2) # 잘못된 동영상 주소 + return LogicNormal.abort(ret, 2) # 잘못된 동영상 주소 if preferredcodec not in (None, 'best', 'mp3', 'aac', 'flac', 'm4a', 'opus', 'vorbis', 'wav'): - return LogicNormal.abort(ret, 5) # 허용되지 않은 값이 있음 + return LogicNormal.abort(ret, 5) # 허용되지 않은 값이 있음 if not filename: filename = LogicNormal.get_default_filename() youtube_dl = LogicNormal.download(plugin=plugin, @@ -239,7 +250,7 @@ def api(sub): key=key, cookiefile=cookiefile) if youtube_dl is None: - return LogicNormal.abort(ret, 10) # 실패 + return LogicNormal.abort(ret, 10) # 실패 ret['index'] = youtube_dl.index if start: youtube_dl.start() @@ -255,16 +266,16 @@ def api(sub): 'status': None } if None in (index, key): - return LogicNormal.abort(ret, 1) # 필수 요청 변수가 없음 + return LogicNormal.abort(ret, 1) # 필수 요청 변수가 없음 index = int(index) 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] if youtube_dl.key != key: - return LogicNormal.abort(ret, 4) # 키가 일치하지 않음 + return LogicNormal.abort(ret, 4) # 키가 일치하지 않음 ret['status'] = youtube_dl.status.name if not youtube_dl.start(): - return LogicNormal.abort(ret, 10) # 실패 + return LogicNormal.abort(ret, 10) # 실패 return jsonify(ret) # 다운로드 중지를 요청하는 API @@ -276,16 +287,16 @@ def api(sub): 'status': None } if None in (index, key): - return LogicNormal.abort(ret, 1) # 필수 요청 변수가 없음 + return LogicNormal.abort(ret, 1) # 필수 요청 변수가 없음 index = int(index) 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] if youtube_dl.key != key: - return LogicNormal.abort(ret, 4) # 키가 일치하지 않음 + return LogicNormal.abort(ret, 4) # 키가 일치하지 않음 ret['status'] = youtube_dl.status.name if not youtube_dl.stop(): - return LogicNormal.abort(ret, 10) # 실패 + return LogicNormal.abort(ret, 10) # 실패 return jsonify(ret) # 현재 상태를 반환하는 API @@ -301,16 +312,18 @@ def api(sub): 'save_path': None } if None in (index, key): - return LogicNormal.abort(ret, 1) # 필수 요청 변수가 없음 + return LogicNormal.abort(ret, 1) # 필수 요청 변수가 없음 index = int(index) 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] if youtube_dl.key != key: - return LogicNormal.abort(ret, 4) # 키가 일치하지 않음 + return LogicNormal.abort(ret, 4) # 키가 일치하지 않음 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['end_time'] = youtube_dl.end_time.strftime('%Y-%m-%dT%H:%M:%S') if youtube_dl.end_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['temp_path'] = youtube_dl.temp_path ret['save_path'] = youtube_dl.save_path return jsonify(ret) @@ -318,7 +331,8 @@ def api(sub): logger.error('Exception:%s', e) logger.error(traceback.format_exc()) abort(500) # 500 에러(서버 오류) - abort(404) # 404 에러(페이지 없음) + abort(404) # 404 에러(페이지 없음) + ######################################################### # socketio diff --git a/static/youtube-dl_download.js b/static/youtube-dl_download.js new file mode 100644 index 0000000..1ff644b --- /dev/null +++ b/static/youtube-dl_download.js @@ -0,0 +1,48 @@ +"use strict"; + +const url = document.getElementById('url'); +const preset = document.getElementById('preset'); +const format = document.getElementById('format'); +const postprocessor = document.getElementById('postprocessor'); +const download_btn = document.getElementById('download_btn'); + +// 프리셋 변경 +preset.addEventListener('change', () => { + if (preset.value !== '_custom') { + format.value = preset.value; + } +}); +format.addEventListener('input', () => { + preset.value = '_custom'; +}); + +// 후처리 변경 +postprocessor.addEventListener('change', () => { + const select = postprocessor.selectedOptions[0]; + if (select.parentElement.label === '오디오 추출') { + preset.value = 'bestaudio/best'; + format.value = preset.value; + } +}); + +// 다운로드 +download_btn.addEventListener('click', (event) => { + event.preventDefault(); + if (!url.value.startsWith('http')) { + notify('URL을 입력하세요.', 'warning'); + return; + } + + fetch(`/${package_name}/ajax/download`, { + method: 'POST', + cache: 'no-cache', + headers: { + 'Content-Type': 'application/x-www-form-urlencoded; charset=UTF-8' + }, + body: get_formdata('#download') + }).then(response => response.json()).then(() => { + notify('분석중..', 'info'); + }).catch(() => { + notify('다운로드 요청 실패', 'danger'); + }); +}); diff --git a/static/youtube-dl_list.css b/static/youtube-dl_list.css new file mode 100644 index 0000000..47216be --- /dev/null +++ b/static/youtube-dl_list.css @@ -0,0 +1,26 @@ +.row > div { + padding-top: 3px; + padding-bottom: 3px; +} + +.row { + align-items: center; + word-break: break-all; +} + +.row > div:nth-child(odd) { + text-align: right; +} + +.row > div:nth-child(even) { + text-align: left; +} + +.cursor-pointer { + cursor: pointer; +} + +.info-padding { + padding-left: 10px; + padding-top: 3px; +} diff --git a/static/youtube-dl_list.js b/static/youtube-dl_list.js new file mode 100644 index 0000000..5eb0b7f --- /dev/null +++ b/static/youtube-dl_list.js @@ -0,0 +1,139 @@ +"use strict"; + +const all_stop_btn = document.getElementById('all_stop_btn'); +const list_tbody = document.getElementById('list_tbody'); + +// 소켓 +const socket = io.connect(`${location.origin}/${package_name}`); +socket.on('add', (data) => { + list_tbody.innerHTML += make_item(data); +}); +socket.on('status', (data) => { + status_html(data); +}); + +// 목록 불러오기 +fetch(`/${package_name}/ajax/list`, { + method: 'POST', + cache: 'no-cache', + headers: { + 'Content-Type': 'application/x-www-form-urlencoded; charset=UTF-8' + } +}).then(response => response.json()).then((data) => { + let str = ''; + for (const item of data) { + str += make_item(item); + } + list_tbody.innerHTML = str; +}); + +// 전체 중지 +all_stop_btn.addEventListener('click', (event) => { + event.preventDefault(); + fetch(`/${package_name}/ajax/all_stop`, { + method: 'POST', + cache: 'no-cache', + headers: { + 'Content-Type': 'application/x-www-form-urlencoded; charset=UTF-8' + } + }).then(response => response.json()).then(() => { + location.reload(); + }); +}); + +// 중지 +list_tbody.addEventListener('click', (event) => { + event.preventDefault(); + const target = event.target; + if (!target.classList.contains('youtubeDl-stop')) { + return; + } + fetch(`/${package_name}/ajax/stop`, { + method: 'POST', + cache: 'no-cache', + headers: { + 'Content-Type': 'application/x-www-form-urlencoded; charset=UTF-8' + }, + body: new URLSearchParams({ + index: target.dataset.index + }) + }).then(response => response.json()).then(() => { + location.reload(); + }); +}); + +function make_item(data) { + let str = ``; + str += get_item(data); + str += ''; + str += ``; + str += ''; + str += `
`; + str += get_detail(data); + str += '
'; + str += ''; + str += ''; + return str; +} + +function get_item(data) { + let str = `${data.index + 1}`; + str += `${data.plugin}`; + str += `${data.start_time}`; + str += `${data.extractor}`; + str += `${data.title}`; + str += `${data.status_ko}`; + let visi = 'hidden'; + if (parseInt(data.percent) > 0 && data.status_str !== 'STOP') { + visi = 'visible'; + } + str += `
${data.percent}%
`; + str += `${data.download_time}`; + str += ''; + if (data.status_str === 'START' || data.status_str === 'DOWNLOADING' || data.status_str === 'FINISHED') { + str += ``; + } + str += ''; + return str; +} + +function get_detail(data) { + let str = info_html('URL', data.url, data.url); + str += info_html('업로더', data.uploader, data.uploader_url); + str += info_html('임시폴더', data.temp_path); + str += info_html('저장폴더', data.save_path); + str += info_html('종료시간', data.end_time); + if (data.status_str === 'DOWNLOADING') { + str += info_html('', '현재 다운로드 중인 파일에 대한 정보'); + str += info_html('파일명', data.filename); + str += info_html('진행률(current/total)', `${data.percent}% (${data.downloaded_bytes_str} / ${data.total_bytes_str})`); + str += info_html('남은 시간', `${data.eta}초`); + str += info_html('다운 속도', data.speed_str); + } + return str; +} + +function info_html(left, right, option) { + let str = '
'; + const link = (left === 'URL' || left === '업로더'); + str += '
'; + str += `${left}`; + str += '
'; + str += '
'; + str += '
'; + str += ''; + if (link) { + str += ``; + } + str += right; + if (link) { + str += ''; + } + str += '
'; + return str; +} + +function status_html(data) { + document.getElementById(`item_${data.index}`).innerHTML = get_item(data); + document.getElementById(`detail_${data.index}`).innerHTML = get_detail(data); +} diff --git a/static/youtube-dl_setting.js b/static/youtube-dl_setting.js new file mode 100644 index 0000000..2234a50 --- /dev/null +++ b/static/youtube-dl_setting.js @@ -0,0 +1,32 @@ +"use strict"; + +const ffmpeg_version_btn = document.getElementById('ffmpeg_version_btn'); +const ffmpeg_path = document.getElementById('ffmpeg_path'); +const modal_title = document.getElementById('modal_title'); +const modal_body = document.getElementById('modal_body'); + +// FFmpeg 버전확인 +ffmpeg_version_btn.addEventListener('click', (event) => { + event.preventDefault(); + let ffmpeg = ffmpeg_path.value; + if (ffmpeg.length === 0) { + ffmpeg = 'ffmpeg'; + } + + fetch(`/${package_name}/ajax/ffmpeg_version`, { + method: 'POST', + cache: 'no-cache', + headers: { + 'Content-Type': 'application/x-www-form-urlencoded; charset=UTF-8' + }, + body: new URLSearchParams({ + path: ffmpeg + }) + }).then(response => response.json()).then((data) => { + modal_title.innerHTML = `${ffmpeg} -version`; + modal_body.innerHTML = data; + $('#large_modal').modal(); + }).catch(() => { + notify('버전확인 실패', 'danger'); + }); +}); diff --git a/templates/youtube-dl_download.html b/templates/youtube-dl_download.html index c192cfd..092c075 100644 --- a/templates/youtube-dl_download.html +++ b/templates/youtube-dl_download.html @@ -1,6 +1,6 @@ {% extends "base.html" %} -{% macro setting_select2(id, title, options, col='9', desc=None, value=None) %} +{% macro my_setting_select(id, title, options, col='9', desc=None, value=None) %} {{ macros.setting_top(title) }}