diff --git a/logic.py b/logic.py index c5a8d1a..ffd9f65 100644 --- a/logic.py +++ b/logic.py @@ -18,61 +18,61 @@ from .model import ModelSetting ######################################################### class Logic(object): - db_default = { - 'db_version': '1', - 'temp_path': os.path.join(path_data, 'download_tmp'), - 'save_path': os.path.join(path_data, 'download'), - 'default_filename': '%(title)s-%(id)s.%(ext)s', - 'proxy': '', - 'activate_cors': False - } + db_default = { + 'db_version': '1', + 'temp_path': os.path.join(path_data, 'download_tmp'), + 'save_path': os.path.join(path_data, 'download'), + 'default_filename': '%(title)s-%(id)s.%(ext)s', + 'proxy': '', + 'activate_cors': False + } - @staticmethod - def db_init(): - try: - for key, value in Logic.db_default.items(): - if db.session.query(ModelSetting).filter_by(key=key).count() == 0: - db.session.add(ModelSetting(key, value)) - db.session.commit() - # Logic.migration() - except Exception as e: - logger.error('Exception:%s', e) - logger.error(traceback.format_exc()) + @staticmethod + def db_init(): + try: + for key, value in Logic.db_default.items(): + if db.session.query(ModelSetting).filter_by(key=key).count() == 0: + db.session.add(ModelSetting(key, value)) + db.session.commit() + # Logic.migration() + except Exception as e: + logger.error('Exception:%s', e) + logger.error(traceback.format_exc()) - @staticmethod - def plugin_load(): - try: - logger.debug('%s plugin_load', package_name) - Logic.db_init() # DB 초기화 + @staticmethod + def plugin_load(): + try: + logger.debug('%s plugin_load', package_name) + Logic.db_init() - try: - import glob2 - except ImportError: - # glob2 설치 - logger.debug('glob2 install') - logger.debug(subprocess.check_output([sys.executable, '-m', 'pip', 'install', 'glob2'], universal_newlines=True)) - try: - import flask_cors - except ImportError: - # flask-cors 설치 - logger.debug('flask-cors install') - logger.debug(subprocess.check_output([sys.executable, '-m', 'pip', 'install', 'flask-cors'], universal_newlines=True)) + try: + import glob2 + except ImportError: + # glob2 설치 + logger.debug('glob2 install') + logger.debug(subprocess.check_output([sys.executable, '-m', 'pip', 'install', 'glob2'], universal_newlines=True)) + try: + import flask_cors + except ImportError: + # flask-cors 설치 + logger.debug('flask-cors install') + logger.debug(subprocess.check_output([sys.executable, '-m', 'pip', 'install', 'flask-cors'], universal_newlines=True)) - # youtube-dl 업데이트 - logger.debug('youtube-dl upgrade') - logger.debug(subprocess.check_output([sys.executable, '-m', 'pip', 'install', '--upgrade', 'youtube-dl'], universal_newlines=True)) + # youtube-dl 업데이트 + logger.debug('youtube-dl upgrade') + logger.debug(subprocess.check_output([sys.executable, '-m', 'pip', 'install', '--upgrade', 'youtube-dl'], universal_newlines=True)) - # 편의를 위해 json 파일 생성 - from plugin import plugin_info - Util.save_from_dict_to_json(plugin_info, os.path.join(os.path.dirname(__file__), 'info.json')) - except Exception as e: - logger.error('Exception:%s', e) - logger.error(traceback.format_exc()) + # 편의를 위해 json 파일 생성 + from plugin import plugin_info + Util.save_from_dict_to_json(plugin_info, os.path.join(os.path.dirname(__file__), 'info.json')) + except Exception as e: + logger.error('Exception:%s', e) + logger.error(traceback.format_exc()) - @staticmethod - def plugin_unload(): - try: - logger.debug('%s plugin_unload', package_name) - except Exception as e: - logger.error('Exception:%s', e) - logger.error(traceback.format_exc()) + @staticmethod + def plugin_unload(): + try: + logger.debug('%s plugin_unload', package_name) + except Exception as e: + logger.error('Exception:%s', e) + logger.error(traceback.format_exc()) diff --git a/logic_normal.py b/logic_normal.py index bf200df..b8853ea 100644 --- a/logic_normal.py +++ b/logic_normal.py @@ -13,109 +13,109 @@ from .my_youtube_dl import Status ######################################################### class LogicNormal(object): - youtube_dl_list = [] + youtube_dl_list = [] - @staticmethod - def get_preset_list(): - preset_list = [ - ['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', '사용자 정의'] - ] - return preset_list + @staticmethod + def get_preset_list(): + preset_list = [ + ['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', '사용자 정의'] + ] + return preset_list - @staticmethod - def get_postprocessor_list(): - postprocessor_list = [ - ['', '후처리 안함', 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', '오디오 추출'] - ] - return postprocessor_list + @staticmethod + def get_postprocessor_list(): + postprocessor_list = [ + ['', '후처리 안함', 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', '오디오 추출'] + ] + return postprocessor_list - @staticmethod - def get_postprocessor(): - video_convertor = [] - extract_audio = [] - for i in LogicNormal.get_postprocessor_list(): - if i[2] == '비디오 변환': - video_convertor.append(i[0]) - elif i[2] == '오디오 추출': - extract_audio.append(i[0]) - return video_convertor, extract_audio + @staticmethod + def get_postprocessor(): + video_convertor = [] + extract_audio = [] + for i in LogicNormal.get_postprocessor_list(): + if i[2] == '비디오 변환': + video_convertor.append(i[0]) + elif i[2] == '오디오 추출': + extract_audio.append(i[0]) + return video_convertor, extract_audio - @staticmethod - def get_data(youtube_dl): - try: - data = {} - data['plugin'] = youtube_dl.plugin - data['url'] = youtube_dl.url - data['filename'] = youtube_dl.filename - data['temp_path'] = youtube_dl.temp_path - data['save_path'] = youtube_dl.save_path - data['index'] = youtube_dl.index - 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['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['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['start_time'] = '' - data['download_time'] = '' - else: - 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']) - 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['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 - except Exception as e: - logger.error('Exception:%s', e) - logger.error(traceback.format_exc()) - return None + @staticmethod + def get_data(youtube_dl): + try: + data = {} + data['plugin'] = youtube_dl.plugin + data['url'] = youtube_dl.url + data['filename'] = youtube_dl.filename + data['temp_path'] = youtube_dl.temp_path + data['save_path'] = youtube_dl.save_path + data['index'] = youtube_dl.index + 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['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['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['start_time'] = '' + data['download_time'] = '' + else: + 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']) + 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['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 + except Exception as e: + logger.error('Exception:%s', e) + logger.error(traceback.format_exc()) + return None - @staticmethod - def human_readable_size(size, suffix=''): - for unit in ('Bytes', 'KB', 'MB', 'GB', 'TB', 'PB', 'EB', 'ZB'): - if size < 1024.0: - return '%3.1f %s%s' % (size, unit, suffix) - size /= 1024.0 - return '%.1f %s%s' % (size, 'YB', suffix) + @staticmethod + def human_readable_size(size, suffix=''): + for unit in ('Bytes', 'KB', 'MB', 'GB', 'TB', 'PB', 'EB', 'ZB'): + if size < 1024.0: + return '%3.1f %s%s' % (size, unit, suffix) + size /= 1024.0 + return '%.1f %s%s' % (size, 'YB', suffix) - @staticmethod - def abort(base, code): - base['errorCode'] = code - return jsonify(base) + @staticmethod + def abort(base, code): + base['errorCode'] = code + return jsonify(base) diff --git a/model.py b/model.py index 87d9daf..23666cc 100644 --- a/model.py +++ b/model.py @@ -17,95 +17,95 @@ app.config['SQLALCHEMY_BINDS'][package_name] = 'sqlite:///%s' % (os.path.join(pa ######################################################### class ModelSetting(db.Model): - __tablename__ = '%s_setting' % package_name - __table_args__ = {'mysql_collate': 'utf8_general_ci'} - __bind_key__ = package_name + __tablename__ = '%s_setting' % package_name + __table_args__ = {'mysql_collate': 'utf8_general_ci'} + __bind_key__ = package_name - id = db.Column(db.Integer, primary_key=True) - key = db.Column(db.String(100), unique=True, nullable=False) - value = db.Column(db.String, nullable=False) + id = db.Column(db.Integer, primary_key=True) + key = db.Column(db.String(100), unique=True, nullable=False) + value = db.Column(db.String, nullable=False) - def __init__(self, key, value): - self.key = key - self.value = value + def __init__(self, key, value): + self.key = key + self.value = value - def __repr__(self): - return repr(self.as_dict()) + def __repr__(self): + return repr(self.as_dict()) - def as_dict(self): - return {x.name: getattr(self, x.name) for x in self.__table__.columns} + def as_dict(self): + return {x.name: getattr(self, x.name) for x in self.__table__.columns} - @staticmethod - def get(key): - try: - return db.session.query(ModelSetting).filter_by(key=key).first().value.strip() - except Exception as e: - logger.error('Exception:%s %s', e, key) - logger.error(traceback.format_exc()) + @staticmethod + def get(key): + try: + return db.session.query(ModelSetting).filter_by(key=key).first().value.strip() + except Exception as e: + logger.error('Exception:%s %s', e, key) + logger.error(traceback.format_exc()) - @staticmethod - def get_int(key): - try: - return int(ModelSetting.get(key)) - except Exception as e: - logger.error('Exception:%s %s', e, key) - logger.error(traceback.format_exc()) + @staticmethod + def get_int(key): + try: + return int(ModelSetting.get(key)) + except Exception as e: + logger.error('Exception:%s %s', e, key) + logger.error(traceback.format_exc()) - @staticmethod - def get_bool(key): - try: - return ModelSetting.get(key) == 'True' - except Exception as e: - logger.error('Exception:%s %s', e, key) - logger.error(traceback.format_exc()) + @staticmethod + def get_bool(key): + try: + return ModelSetting.get(key) == 'True' + except Exception as e: + logger.error('Exception:%s %s', e, key) + logger.error(traceback.format_exc()) - @staticmethod - def set(key, value): - try: - item = db.session.query(ModelSetting).filter_by(key=key).with_for_update().first() - if item is not None: - item.value = value.strip() - db.session.commit() - else: - db.session.add(ModelSetting(key, value.strip())) - except Exception as e: - logger.error('Exception:%s', e) - logger.error(traceback.format_exc()) - logger.error('Error Key:%s Value:%s', key, value) + @staticmethod + def set(key, value): + try: + item = db.session.query(ModelSetting).filter_by(key=key).with_for_update().first() + if item is not None: + item.value = value.strip() + db.session.commit() + else: + db.session.add(ModelSetting(key, value.strip())) + except Exception as e: + logger.error('Exception:%s', e) + logger.error(traceback.format_exc()) + logger.error('Error Key:%s Value:%s', key, value) - @staticmethod - def to_dict(): - try: - return Util.db_list_to_dict(db.session.query(ModelSetting).all()) - except Exception as e: - logger.error('Exception:%s', e) - logger.error(traceback.format_exc()) + @staticmethod + def to_dict(): + try: + return Util.db_list_to_dict(db.session.query(ModelSetting).all()) + except Exception as e: + logger.error('Exception:%s', e) + logger.error(traceback.format_exc()) - @staticmethod - def setting_save(req): - try: - for key, value in req.form.items(): - if key in ['scheduler', 'is_running']: - continue - if key.startswith('tmp_'): - continue - logger.debug('Key:%s Value:%s', key, value) - entity = db.session.query(ModelSetting).filter_by(key=key).with_for_update().first() - entity.value = value - db.session.commit() - return True - except Exception as e: - logger.error('Exception:%s', e) - logger.error(traceback.format_exc()) - return False + @staticmethod + def setting_save(req): + try: + for key, value in req.form.items(): + if key in ['scheduler', 'is_running']: + continue + if key.startswith('tmp_'): + continue + logger.debug('Key:%s Value:%s', key, value) + entity = db.session.query(ModelSetting).filter_by(key=key).with_for_update().first() + entity.value = value + db.session.commit() + return True + except Exception as e: + logger.error('Exception:%s', e) + logger.error(traceback.format_exc()) + return False - @staticmethod - def get_list(key): - try: - value = ModelSetting.get(key) - values = [x.strip().strip() for x in value.replace('\n', '|').split('|')] - values = Util.get_list_except_empty(values) - return values - except Exception as e: - logger.error('Exception:%s %s', e, key) - logger.error(traceback.format_exc()) + @staticmethod + def get_list(key): + try: + value = ModelSetting.get(key) + values = [x.strip().strip() for x in value.replace('\n', '|').split('|')] + values = Util.get_list_except_empty(values) + return values + except Exception as e: + logger.error('Exception:%s %s', e, key) + logger.error(traceback.format_exc()) diff --git a/my_youtube_dl.py b/my_youtube_dl.py index 5389754..d0bc88d 100644 --- a/my_youtube_dl.py +++ b/my_youtube_dl.py @@ -18,194 +18,194 @@ from .plugin import logger class Status(Enum): - READY = 0 - START = 1 - DOWNLOADING = 2 - ERROR = 3 - FINISHED = 4 - STOP = 5 - COMPLETED = 6 + READY = 0 + START = 1 + DOWNLOADING = 2 + ERROR = 3 + FINISHED = 4 + STOP = 5 + COMPLETED = 6 - def __str__(self): - str_list = [ - '준비', - '분석중', - '다운로드중', - '실패', - '변환중', - '중지', - '완료' - ] - return str_list[self.value] + def __str__(self): + str_list = [ + '준비', + '분석중', + '다운로드중', + '실패', + '변환중', + '중지', + '완료' + ] + return str_list[self.value] class Youtube_dl(object): - _index = 0 - _last_msg = '' + _index = 0 + _last_msg = '' - def __init__(self, plugin, url, filename, temp_path, save_path=None, opts=None): - if save_path is None: - save_path = temp_path - if opts is None: - opts = {} - self.plugin = plugin - self.url = url - self.filename = filename - if not os.path.isdir(temp_path): - os.makedirs(temp_path) - self.temp_path = tempfile.mkdtemp(prefix='youtube-dl_', dir=temp_path) - if not os.path.isdir(save_path): - os.makedirs(save_path) - self.save_path = save_path - self.opts = opts - self.index = Youtube_dl._index - Youtube_dl._index += 1 - self._status = Status.READY - self._thread = None - self.key = None - self.start_time = None # 시작 시간 - self.end_time = None # 종료 시간 - self.info_dict = { # info_dict에서 얻는 정보 - '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.progress_hooks = { # progress_hooks에서 얻는 정보 - 'downloaded_bytes': None, # 다운로드한 크기 - 'total_bytes': None, # 전체 크기 - 'eta': None, # 예상 시간(s) - 'speed': None # 다운로드 속도(bytes/s) - } + def __init__(self, plugin, url, filename, temp_path, save_path=None, opts=None): + if save_path is None: + save_path = temp_path + if opts is None: + opts = {} + self.plugin = plugin + self.url = url + self.filename = filename + if not os.path.isdir(temp_path): + os.makedirs(temp_path) + self.temp_path = tempfile.mkdtemp(prefix='youtube-dl_', dir=temp_path) + if not os.path.isdir(save_path): + os.makedirs(save_path) + self.save_path = save_path + self.opts = opts + self.index = Youtube_dl._index + Youtube_dl._index += 1 + self._status = Status.READY + self._thread = None + self.key = None + self.start_time = None # 시작 시간 + self.end_time = None # 종료 시간 + self.info_dict = { # info_dict에서 얻는 정보 + '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.progress_hooks = { # progress_hooks에서 얻는 정보 + 'downloaded_bytes': None, # 다운로드한 크기 + 'total_bytes': None, # 전체 크기 + 'eta': None, # 예상 시간(s) + 'speed': None # 다운로드 속도(bytes/s) + } - def start(self): - if self.status != Status.READY: - return False - self._thread = Thread(target=self.run) - self._thread.start() - return True + def start(self): + if self.status != Status.READY: + return False + self._thread = Thread(target=self.run) + self._thread.start() + return True - def run(self): - import youtube_dl - import glob2 - try: - self.start_time = datetime.now() - self.status = Status.START - info_dict = Youtube_dl.get_info_dict(self.url, self.opts.get('proxy')) # 동영상 정보 가져오기 - if info_dict is None: # 가져오기 실패 - self.status = Status.ERROR - return - self.info_dict['extractor'] = info_dict['extractor'] - self.info_dict['title'] = info_dict['title'] - self.info_dict['uploader'] = info_dict['uploader'] - self.info_dict['uploader_url'] = info_dict['uploader_url'] - ydl_opts = { - 'logger': MyLogger(), - 'progress_hooks': [self.my_hook], - # 'match_filter': self.match_filter_func, - 'outtmpl': os.path.join(self.temp_path, self.filename), - 'ignoreerrors': True, - 'cachedir': False - } - ydl_opts.update(self.opts) - with youtube_dl.YoutubeDL(ydl_opts) as ydl: - ydl.download([self.url]) - if self.status == Status.FINISHED: # 다운로드 성공 - for i in glob2.glob(self.temp_path + '/**/*'): - path = i.replace(self.temp_path, self.save_path, 1) - if os.path.isdir(i): - if not os.path.isdir(path): - os.mkdir(path) - continue - celery_shutil.move(i, path) # 파일 이동 - self.status = Status.COMPLETED - except Exception as e: - self.status = Status.ERROR - logger.error('Exception:%s', e) - logger.error(traceback.format_exc()) - finally: - celery_shutil.rmtree(self.temp_path) # 임시폴더 삭제 - if self.status != Status.STOP: - self.end_time = datetime.now() + def run(self): + import youtube_dl + import glob2 + try: + self.start_time = datetime.now() + self.status = Status.START + info_dict = Youtube_dl.get_info_dict(self.url, self.opts.get('proxy')) # 동영상 정보 가져오기 + if info_dict is None: # 가져오기 실패 + self.status = Status.ERROR + return + self.info_dict['extractor'] = info_dict['extractor'] + self.info_dict['title'] = info_dict['title'] + self.info_dict['uploader'] = info_dict['uploader'] + self.info_dict['uploader_url'] = info_dict['uploader_url'] + ydl_opts = { + 'logger': MyLogger(), + 'progress_hooks': [self.my_hook], + # 'match_filter': self.match_filter_func, + 'outtmpl': os.path.join(self.temp_path, self.filename), + 'ignoreerrors': True, + 'cachedir': False + } + ydl_opts.update(self.opts) + with youtube_dl.YoutubeDL(ydl_opts) as ydl: + ydl.download([self.url]) + if self.status == Status.FINISHED: # 다운로드 성공 + for i in glob2.glob(self.temp_path + '/**/*'): + path = i.replace(self.temp_path, self.save_path, 1) + if os.path.isdir(i): + if not os.path.isdir(path): + os.mkdir(path) + continue + celery_shutil.move(i, path) # 파일 이동 + self.status = Status.COMPLETED + except Exception as e: + self.status = Status.ERROR + logger.error('Exception:%s', e) + logger.error(traceback.format_exc()) + finally: + celery_shutil.rmtree(self.temp_path) # 임시폴더 삭제 + if self.status != Status.STOP: + self.end_time = datetime.now() - def stop(self): - if self.status in (Status.ERROR, Status.STOP, Status.COMPLETED): - return False - self.status = Status.STOP - self.end_time = datetime.now() - return True + def stop(self): + if self.status in (Status.ERROR, Status.STOP, Status.COMPLETED): + return False + self.status = Status.STOP + self.end_time = datetime.now() + return True - @staticmethod - def get_version(): - import youtube_dl - return youtube_dl.version.__version__ + @staticmethod + def get_version(): + import youtube_dl + return youtube_dl.version.__version__ - @staticmethod - def get_info_dict(url, proxy=None): - import youtube_dl - try: - ydl_opts = { - 'simulate': True, - 'dump_single_json': True, - 'extract_flat': 'in_playlist', - 'logger': MyLogger() - } - if proxy: - ydl_opts['proxy'] = proxy - with youtube_dl.YoutubeDL(ydl_opts) as ydl: - ydl.download([url]) - except Exception as e: - logger.error('Exception:%s', e) - logger.error(traceback.format_exc()) - return None - return json.loads(Youtube_dl._last_msg) + @staticmethod + def get_info_dict(url, proxy=None): + import youtube_dl + try: + ydl_opts = { + 'simulate': True, + 'dump_single_json': True, + 'extract_flat': 'in_playlist', + 'logger': MyLogger() + } + if proxy: + ydl_opts['proxy'] = proxy + with youtube_dl.YoutubeDL(ydl_opts) as ydl: + ydl.download([url]) + except Exception as e: + logger.error('Exception:%s', e) + logger.error(traceback.format_exc()) + return None + return json.loads(Youtube_dl._last_msg) - def my_hook(self, d): - if self.status != Status.STOP: - self.status = { - 'downloading': Status.DOWNLOADING, - 'error': Status.ERROR, - 'finished': Status.FINISHED # 다운로드 완료. 변환 시작 - }[d['status']] - if d['status'] != 'error': - self.filename = os.path.basename(d.get('filename')) - self.progress_hooks['downloaded_bytes'] = d.get('downloaded_bytes') - self.progress_hooks['total_bytes'] = d.get('total_bytes') - self.progress_hooks['eta'] = d.get('eta') - self.progress_hooks['speed'] = d.get('speed') + def my_hook(self, d): + if self.status != Status.STOP: + self.status = { + 'downloading': Status.DOWNLOADING, + 'error': Status.ERROR, + 'finished': Status.FINISHED # 다운로드 완료. 변환 시작 + }[d['status']] + if d['status'] != 'error': + self.filename = os.path.basename(d.get('filename')) + self.progress_hooks['downloaded_bytes'] = d.get('downloaded_bytes') + self.progress_hooks['total_bytes'] = d.get('total_bytes') + self.progress_hooks['eta'] = d.get('eta') + self.progress_hooks['speed'] = d.get('speed') - def match_filter_func(self, info_dict): - self.info_dict['playlist_index'] = info_dict['playlist_index'] - self.info_dict['duration'] = info_dict['duration'] - self.info_dict['format'] = info_dict['format'] - self.info_dict['thumbnail'] = info_dict['thumbnail'] - return None + def match_filter_func(self, info_dict): + self.info_dict['playlist_index'] = info_dict['playlist_index'] + self.info_dict['duration'] = info_dict['duration'] + self.info_dict['format'] = info_dict['format'] + self.info_dict['thumbnail'] = info_dict['thumbnail'] + return None - @property - def status(self): - return self._status + @property + def status(self): + return self._status - @status.setter - def status(self, value): - from .plugin import socketio_emit - self._status = value - socketio_emit('status', self) + @status.setter + def status(self, value): + from .plugin import socketio_emit + self._status = value + socketio_emit('status', self) class MyLogger(object): - def debug(self, msg): - Youtube_dl._last_msg = msg - if msg.find('') != -1 or msg.find('{') != -1: - return # 과도한 로그 방지 - logger.debug(msg) + def debug(self, msg): + Youtube_dl._last_msg = msg + if msg.find('') != -1 or msg.find('{') != -1: + return # 과도한 로그 방지 + logger.debug(msg) - def warning(self, msg): - logger.warning(msg) + def warning(self, msg): + logger.warning(msg) - def error(self, msg): - logger.error(msg) + def error(self, msg): + logger.error(msg) diff --git a/plugin.py b/plugin.py index 1dcda60..c3caee1 100644 --- a/plugin.py +++ b/plugin.py @@ -26,65 +26,65 @@ from .my_youtube_dl import Youtube_dl blueprint = Blueprint(package_name, package_name, url_prefix='/%s' % package_name, template_folder=os.path.join(os.path.dirname(__file__), 'templates')) menu = { - 'main': [package_name, 'youtube-dl'], - 'sub': [ - ['setting', '설정'], ['download', '다운로드'], ['list', '목록'], ['log', '로그'] - ], - 'category': 'vod' + 'main': [package_name, 'youtube-dl'], + 'sub': [ + ['setting', '설정'], ['download', '다운로드'], ['list', '목록'], ['log', '로그'] + ], + 'category': 'vod' } plugin_info = { - 'version': '1.6.3', - 'name': 'youtube-dl', - 'category_name': 'vod', - 'developer': 'joyfuI', - 'description': '유튜브, 네이버TV 등 동영상 사이트에서 동영상 다운로드', - 'home': 'https://github.com/joyfuI/youtube-dl', - 'more': '' + 'version': '1.6.3', + 'name': 'youtube-dl', + 'category_name': 'vod', + 'developer': 'joyfuI', + 'description': '유튜브, 네이버TV 등 동영상 사이트에서 동영상 다운로드', + 'home': 'https://github.com/joyfuI/youtube-dl', + 'more': '' } def plugin_load(): - Logic.plugin_load() - if ModelSetting.get_bool('activate_cors'): - import flask_cors - flask_cors.CORS(blueprint) + Logic.plugin_load() + if ModelSetting.get_bool('activate_cors'): + import flask_cors + flask_cors.CORS(blueprint) def plugin_unload(): - Logic.plugin_unload() + Logic.plugin_unload() ######################################################### # WEB Menu ######################################################### @blueprint.route('/') def home(): - return redirect('/%s/list' % package_name) + return redirect('/%s/list' % package_name) @blueprint.route('/') @login_required def first_menu(sub): - try: - arg = {'package_name': package_name} + try: + arg = {'package_name': package_name} - if sub == 'setting': - arg.update(ModelSetting.to_dict()) - arg['youtube_dl_version'] = Youtube_dl.get_version() - return render_template('%s_%s.html' % (package_name, sub), arg=arg) + if sub == 'setting': + arg.update(ModelSetting.to_dict()) + arg['youtube_dl_version'] = Youtube_dl.get_version() + return render_template('%s_%s.html' % (package_name, sub), arg=arg) - elif sub == 'download': - arg['file_name'] = ModelSetting.get('default_filename') - arg['preset_list'] = LogicNormal.get_preset_list() - arg['postprocessor_list'] = LogicNormal.get_postprocessor_list() - return render_template('%s_%s.html' % (package_name, sub), arg=arg) + elif sub == 'download': + arg['file_name'] = ModelSetting.get('default_filename') + arg['preset_list'] = LogicNormal.get_preset_list() + arg['postprocessor_list'] = LogicNormal.get_postprocessor_list() + return render_template('%s_%s.html' % (package_name, sub), arg=arg) - elif sub == 'list': - return render_template('%s_%s.html' % (package_name, sub), arg=arg) + elif sub == 'list': + return render_template('%s_%s.html' % (package_name, sub), arg=arg) - elif sub == 'log': - return render_template('log.html', package=package_name) - except Exception as e: - logger.error('Exception:%s', e) - logger.error(traceback.format_exc()) - return render_template('sample.html', title='%s - %s' % (package_name, sub)) + elif sub == 'log': + return render_template('log.html', package=package_name) + except Exception as e: + logger.error('Exception:%s', e) + logger.error(traceback.format_exc()) + return render_template('sample.html', title='%s - %s' % (package_name, sub)) ######################################################### # For UI @@ -92,60 +92,60 @@ def first_menu(sub): @blueprint.route('/ajax/', methods=['POST']) @login_required def ajax(sub): - logger.debug('AJAX %s %s', package_name, sub) - try: - # 공통 요청 - if sub == 'setting_save': - ret = ModelSetting.setting_save(request) - return jsonify(ret) + logger.debug('AJAX %s %s', package_name, sub) + try: + # 공통 요청 + if sub == 'setting_save': + ret = ModelSetting.setting_save(request) + return jsonify(ret) - # UI 요청 - 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'] - proxy = ModelSetting.get('proxy') - opts = {} - if format_code: - opts['format'] = format_code - video_convertor, extract_audio = LogicNormal.get_postprocessor() - if postprocessor in video_convertor: - opts['postprocessors'] = [{ - 'key': 'FFmpegVideoConvertor', - 'preferedformat': postprocessor - }] - elif postprocessor in extract_audio: - opts['postprocessors'] = [{ - 'key': 'FFmpegExtractAudio', - 'preferredcodec': postprocessor, - 'preferredquality': '192' - }] - if proxy: - opts['proxy'] = proxy - youtube_dl = Youtube_dl(package_name, url, filename, temp_path, save_path, opts) - LogicNormal.youtube_dl_list.append(youtube_dl) # 리스트 추가 - youtube_dl.start() - socketio_emit('add', youtube_dl) - return jsonify([]) + # UI 요청 + 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'] + proxy = ModelSetting.get('proxy') + opts = {} + if format_code: + opts['format'] = format_code + video_convertor, extract_audio = LogicNormal.get_postprocessor() + if postprocessor in video_convertor: + opts['postprocessors'] = [{ + 'key': 'FFmpegVideoConvertor', + 'preferedformat': postprocessor + }] + elif postprocessor in extract_audio: + opts['postprocessors'] = [{ + 'key': 'FFmpegExtractAudio', + 'preferredcodec': postprocessor, + 'preferredquality': '192' + }] + if proxy: + opts['proxy'] = proxy + youtube_dl = Youtube_dl(package_name, url, filename, temp_path, save_path, opts) + LogicNormal.youtube_dl_list.append(youtube_dl) # 리스트 추가 + youtube_dl.start() + socketio_emit('add', youtube_dl) + return jsonify([]) - elif sub == 'list': - ret = [] - for i in LogicNormal.youtube_dl_list: - data = LogicNormal.get_data(i) - if data is not None: - ret.append(data) - return jsonify(ret) + elif sub == 'list': + ret = [] + for i in LogicNormal.youtube_dl_list: + data = LogicNormal.get_data(i) + if data is not None: + ret.append(data) + return jsonify(ret) - elif sub == 'stop': - index = int(request.form['index']) - LogicNormal.youtube_dl_list[index].stop() - return jsonify([]) - except Exception as e: - logger.error('Exception:%s', e) - logger.error(traceback.format_exc()) + elif sub == 'stop': + index = int(request.form['index']) + LogicNormal.youtube_dl_list[index].stop() + return jsonify([]) + except Exception as e: + logger.error('Exception:%s', e) + logger.error(traceback.format_exc()) ######################################################### # API @@ -154,157 +154,157 @@ def ajax(sub): @blueprint.route('/api/', methods=['GET', 'POST']) @check_api def api(sub): - plugin = request.form.get('plugin') - logger.debug('API %s %s: %s', package_name, sub, plugin) - if not plugin: # 요청한 플러그인명이 빈문자열이거나 None면 - abort(403) # 403 에러(거부) - try: - # 동영상 정보를 반환하는 API - if sub == 'info_dict': - url = request.form.get('url') - ret = { - 'errorCode': 0, - 'info_dict': None - } - if None in (url,): - return LogicNormal.abort(ret, 1) # 필수 요청 변수가 없음 - if not url.startswith('http'): - return LogicNormal.abort(ret, 2) # 잘못된 동영상 주소 - info_dict = Youtube_dl.get_info_dict(url, ModelSetting.get('proxy')) - if info_dict is None: - return LogicNormal.abort(ret, 10) # 실패 - ret['info_dict'] = info_dict - return jsonify(ret) + plugin = request.form.get('plugin') + logger.debug('API %s %s: %s', package_name, sub, plugin) + if not plugin: # 요청한 플러그인명이 빈문자열이거나 None면 + abort(403) # 403 에러(거부) + try: + # 동영상 정보를 반환하는 API + if sub == 'info_dict': + url = request.form.get('url') + ret = { + 'errorCode': 0, + 'info_dict': None + } + if None in (url,): + return LogicNormal.abort(ret, 1) # 필수 요청 변수가 없음 + if not url.startswith('http'): + return LogicNormal.abort(ret, 2) # 잘못된 동영상 주소 + info_dict = Youtube_dl.get_info_dict(url, ModelSetting.get('proxy')) + if info_dict is None: + return LogicNormal.abort(ret, 10) # 실패 + ret['info_dict'] = info_dict + return jsonify(ret) - # 다운로드 준비를 요청하는 API - elif sub == 'download': - key = request.form.get('key') - url = request.form.get('url') - filename = request.form.get('filename', ModelSetting.get('default_filename')) - save_path = request.form.get('save_path', ModelSetting.get('save_path')) - format_code = request.form.get('format', None) - preferedformat = request.form.get('preferedformat', None) - preferredcodec = request.form.get('preferredcodec', None) - preferredquality = request.form.get('preferredquality', 192) - archive = request.form.get('archive', None) - start = request.form.get('start', False) - ret = { - 'errorCode': 0, - 'index': None - } - if None in (key, url): - return LogicNormal.abort(ret, 1) # 필수 요청 변수가 없음 - if not url.startswith('http'): - return LogicNormal.abort(ret, 2) # 잘못된 동영상 주소 - opts = {} - if format_code is not None: - opts['format'] = format_code - postprocessor = [] - if preferedformat is not None: - postprocessor.append({ - 'key': 'FFmpegVideoConvertor', - 'preferedformat': preferedformat - }) - if preferredcodec is not None: - if preferredcodec not in ('best', 'mp3', 'aac', 'flac', 'm4a', 'opus', 'vorbis', 'wav'): - return LogicNormal.abort(ret, 5) # 허용되지 않은 값이 있음 - postprocessor.append({ - 'key': 'FFmpegExtractAudio', - 'preferredcodec': preferredcodec, - '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 - if start: - youtube_dl.start() - socketio_emit('add', youtube_dl) - return jsonify(ret) + # 다운로드 준비를 요청하는 API + elif sub == 'download': + key = request.form.get('key') + url = request.form.get('url') + filename = request.form.get('filename', ModelSetting.get('default_filename')) + save_path = request.form.get('save_path', ModelSetting.get('save_path')) + format_code = request.form.get('format', None) + preferedformat = request.form.get('preferedformat', None) + preferredcodec = request.form.get('preferredcodec', None) + preferredquality = request.form.get('preferredquality', 192) + archive = request.form.get('archive', None) + start = request.form.get('start', False) + ret = { + 'errorCode': 0, + 'index': None + } + if None in (key, url): + return LogicNormal.abort(ret, 1) # 필수 요청 변수가 없음 + if not url.startswith('http'): + return LogicNormal.abort(ret, 2) # 잘못된 동영상 주소 + opts = {} + if format_code is not None: + opts['format'] = format_code + postprocessor = [] + if preferedformat is not None: + postprocessor.append({ + 'key': 'FFmpegVideoConvertor', + 'preferedformat': preferedformat + }) + if preferredcodec is not None: + if preferredcodec not in ('best', 'mp3', 'aac', 'flac', 'm4a', 'opus', 'vorbis', 'wav'): + return LogicNormal.abort(ret, 5) # 허용되지 않은 값이 있음 + postprocessor.append({ + 'key': 'FFmpegExtractAudio', + 'preferredcodec': preferredcodec, + '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 + if start: + youtube_dl.start() + socketio_emit('add', youtube_dl) + return jsonify(ret) - # 다운로드 시작을 요청하는 API - elif sub == 'start': - index = request.form.get('index') - key = request.form.get('key') - ret = { - 'errorCode': 0, - 'status': None - } - if None in (index, key): - return LogicNormal.abort(ret, 1) # 필수 요청 변수가 없음 - index = int(index) - if not (0 <= index < len(LogicNormal.youtube_dl_list)): - return LogicNormal.abort(ret, 3) # 인덱스 범위를 벗어남 - youtube_dl = LogicNormal.youtube_dl_list[index] - if youtube_dl.key != key: - return LogicNormal.abort(ret, 4) # 키가 일치하지 않음 - ret['status'] = youtube_dl.status.name - if not youtube_dl.start(): - return LogicNormal.abort(ret, 10) # 실패 - return jsonify(ret) + # 다운로드 시작을 요청하는 API + elif sub == 'start': + index = request.form.get('index') + key = request.form.get('key') + ret = { + 'errorCode': 0, + 'status': None + } + if None in (index, key): + return LogicNormal.abort(ret, 1) # 필수 요청 변수가 없음 + index = int(index) + if not (0 <= index < len(LogicNormal.youtube_dl_list)): + return LogicNormal.abort(ret, 3) # 인덱스 범위를 벗어남 + youtube_dl = LogicNormal.youtube_dl_list[index] + if youtube_dl.key != key: + return LogicNormal.abort(ret, 4) # 키가 일치하지 않음 + ret['status'] = youtube_dl.status.name + if not youtube_dl.start(): + return LogicNormal.abort(ret, 10) # 실패 + return jsonify(ret) - # 다운로드 중지를 요청하는 API - elif sub == 'stop': - index = request.form.get('index') - key = request.form.get('key') - ret = { - 'errorCode': 0, - 'status': None - } - if None in (index, key): - return LogicNormal.abort(ret, 1) # 필수 요청 변수가 없음 - index = int(index) - if not (0 <= index < len(LogicNormal.youtube_dl_list)): - return LogicNormal.abort(ret, 3) # 인덱스 범위를 벗어남 - youtube_dl = LogicNormal.youtube_dl_list[index] - if youtube_dl.key != key: - return LogicNormal.abort(ret, 4) # 키가 일치하지 않음 - ret['status'] = youtube_dl.status.name - if not youtube_dl.stop(): - return LogicNormal.abort(ret, 10) # 실패 - return jsonify(ret) + # 다운로드 중지를 요청하는 API + elif sub == 'stop': + index = request.form.get('index') + key = request.form.get('key') + ret = { + 'errorCode': 0, + 'status': None + } + if None in (index, key): + return LogicNormal.abort(ret, 1) # 필수 요청 변수가 없음 + index = int(index) + if not (0 <= index < len(LogicNormal.youtube_dl_list)): + return LogicNormal.abort(ret, 3) # 인덱스 범위를 벗어남 + youtube_dl = LogicNormal.youtube_dl_list[index] + if youtube_dl.key != key: + return LogicNormal.abort(ret, 4) # 키가 일치하지 않음 + ret['status'] = youtube_dl.status.name + if not youtube_dl.stop(): + return LogicNormal.abort(ret, 10) # 실패 + return jsonify(ret) - # 현재 상태를 반환하는 API - elif sub == 'status': - index = request.form.get('index') - key = request.form.get('key') - ret = { - 'errorCode': 0, - 'status': None, - 'start_time': None, - 'end_time': None, - 'temp_path': None, - 'save_path': None - } - if None in (index, key): - return LogicNormal.abort(ret, 1) # 필수 요청 변수가 없음 - index = int(index) - if not (0 <= index < len(LogicNormal.youtube_dl_list)): - return LogicNormal.abort(ret, 3) # 인덱스 범위를 벗어남 - youtube_dl = LogicNormal.youtube_dl_list[index] - if youtube_dl.key != key: - 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['temp_path'] = youtube_dl.temp_path - ret['save_path'] = youtube_dl.save_path - return jsonify(ret) - except Exception as e: - logger.error('Exception:%s', e) - logger.error(traceback.format_exc()) - abort(500) # 500 에러(서버 오류) - abort(404) # 404 에러(페이지 없음) + # 현재 상태를 반환하는 API + elif sub == 'status': + index = request.form.get('index') + key = request.form.get('key') + ret = { + 'errorCode': 0, + 'status': None, + 'start_time': None, + 'end_time': None, + 'temp_path': None, + 'save_path': None + } + if None in (index, key): + return LogicNormal.abort(ret, 1) # 필수 요청 변수가 없음 + index = int(index) + if not (0 <= index < len(LogicNormal.youtube_dl_list)): + return LogicNormal.abort(ret, 3) # 인덱스 범위를 벗어남 + youtube_dl = LogicNormal.youtube_dl_list[index] + if youtube_dl.key != key: + 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['temp_path'] = youtube_dl.temp_path + ret['save_path'] = youtube_dl.save_path + return jsonify(ret) + except Exception as e: + logger.error('Exception:%s', e) + logger.error(traceback.format_exc()) + abort(500) # 500 에러(서버 오류) + abort(404) # 404 에러(페이지 없음) ######################################################### # socketio ######################################################### def socketio_emit(cmd, data): - socketio.emit(cmd, LogicNormal.get_data(data), namespace='/%s' % package_name, broadcast=True) + socketio.emit(cmd, LogicNormal.get_data(data), namespace='/%s' % package_name, broadcast=True) diff --git a/templates/youtube-dl_download.html b/templates/youtube-dl_download.html index 6012cbd..d0b366b 100644 --- a/templates/youtube-dl_download.html +++ b/templates/youtube-dl_download.html @@ -1,96 +1,96 @@ {% macro setting_select2(id, title, options, col='9', desc=None, value=None) %} - {{ macros.setting_top(title) }} -
- -
- {{ macros.setting_bottom(desc) }} + {{ macros.setting_top(title) }} +
+ +
+ {{ macros.setting_bottom(desc) }} {% endmacro %} {% extends "base.html" %} {% block content %}
- {{ macros.setting_input_text('url', 'URL', placeholder='http:// 주소', desc='유튜브, 네이버TV 등 동영상 주소') }} - {{ macros.setting_input_text('filename', '파일명', value=arg['file_name'], desc='템플릿 규칙은 https://github.com/ytdl-org/youtube-dl/blob/master/README.md#output-template 참고') }} - {{ macros.setting_select('preset', '동영상 포맷 프리셋', arg['preset_list'], col='3') }} - {{ macros.setting_input_text('format', '동영상 포맷', desc=['포맷 지정은 https://github.com/ytdl-org/youtube-dl/blob/master/README.md#format-selection 참고', '빈칸으로 두면 최고 화질로 다운로드합니다.']) }} - {{ setting_select2('postprocessor', '후처리', arg['postprocessor_list'], col='3', desc='다운로드 후 FFmpeg로 후처리합니다.') }} - {{ macros.setting_button([['download_start', '다운로드']]) }} + {{ macros.setting_input_text('url', 'URL', placeholder='http:// 주소', desc='유튜브, 네이버TV 등 동영상 주소') }} + {{ macros.setting_input_text('filename', '파일명', value=arg['file_name'], desc='템플릿 규칙은 https://github.com/ytdl-org/youtube-dl/blob/master/README.md#output-template 참고') }} + {{ macros.setting_select('preset', '동영상 포맷 프리셋', arg['preset_list'], col='3') }} + {{ macros.setting_input_text('format', '동영상 포맷', desc=['포맷 지정은 https://github.com/ytdl-org/youtube-dl/blob/master/README.md#format-selection 참고', '빈칸으로 두면 최고 화질로 다운로드합니다.']) }} + {{ setting_select2('postprocessor', '후처리', arg['postprocessor_list'], col='3', desc='다운로드 후 FFmpeg로 후처리합니다.') }} + {{ macros.setting_button([['download_start', '다운로드']]) }}
-{% endblock %} \ No newline at end of file +{% endblock %} diff --git a/templates/youtube-dl_list.html b/templates/youtube-dl_list.html index 67c8c08..bf5a7d3 100644 --- a/templates/youtube-dl_list.html +++ b/templates/youtube-dl_list.html @@ -2,162 +2,165 @@ {% block content %} - - - - - - - - - - - - - - + + + + + + + + + + + + + +
IDXPlugin시작시간타입제목상태진행률진행시간Action
IDXPlugin시작시간타입제목상태진행률진행시간Action
-{% endblock %} \ No newline at end of file +{% endblock %} diff --git a/templates/youtube-dl_setting.html b/templates/youtube-dl_setting.html index 78f95d6..b1b744e 100644 --- a/templates/youtube-dl_setting.html +++ b/templates/youtube-dl_setting.html @@ -2,20 +2,20 @@ {% block content %}
- {{ macros.setting_input_text('youtube_dl_version', 'youtube-dl 버전', value=arg['youtube_dl_version']) }} -
- {{ macros.setting_input_text('temp_path', '임시 폴더', value=arg['temp_path'], placeholder='임시 폴더 경로', desc='다운로드 파일이 임시로 저장될 폴더 입니다.') }} - {{ macros.setting_input_text('save_path', '저장 폴더', value=arg['save_path'], placeholder='저장 폴더 경로', 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('proxy', '프록시', value=arg['proxy'], placeholder='프록시 주소', desc=['HTTP/HTTPS/SOCKS를 지원합니다. 예) socks5://127.0.0.1:1080/', '빈칸으로 두면 프록시를 사용하지 않습니다.']) }} - {{ macros.setting_checkbox('activate_cors', 'CORS 허용', value=arg['activate_cors'], desc='API로의 크로스 도메인 요청을 허용합니다. 설정 저장 후 재시작이 필요합니다.') }} - {{ macros.setting_button([['global_setting_save_btn', '저장']]) }} -
+ {{ macros.setting_input_text('youtube_dl_version', 'youtube-dl 버전', value=arg['youtube_dl_version']) }} +
+ {{ macros.setting_input_text('temp_path', '임시 폴더', value=arg['temp_path'], placeholder='임시 폴더 경로', desc='다운로드 파일이 임시로 저장될 폴더 입니다.') }} + {{ macros.setting_input_text('save_path', '저장 폴더', value=arg['save_path'], placeholder='저장 폴더 경로', 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('proxy', '프록시', value=arg['proxy'], placeholder='프록시 주소', desc=['HTTP/HTTPS/SOCKS를 지원합니다. 예) socks5://127.0.0.1:1080/', '빈칸으로 두면 프록시를 사용하지 않습니다.']) }} + {{ macros.setting_checkbox('activate_cors', 'CORS 허용', value=arg['activate_cors'], desc='API로의 크로스 도메인 요청을 허용합니다. 설정 저장 후 재시작이 필요합니다.') }} + {{ macros.setting_button([['global_setting_save_btn', '저장']]) }} +
-{% endblock %} \ No newline at end of file +{% endblock %}