# -*- coding: utf-8 -*- ######################################################### # python import json import logging import os import platform import threading import time import traceback # third-party import requests from flask import (Blueprint, Response, jsonify, redirect, render_template, request, send_file, stream_with_context) from flask_login import login_required # sjva 공용 from framework import (app, check_api, frame, get_logger, # , celery path_app_root, path_data, scheduler, socketio) from support import SingletonClass # 로그 package_name = __name__.split('.')[0] logger = get_logger(__package__) # 패키지 from .logic import SystemLogic from .logic_auth import SystemLogicAuth from .logic_command import SystemLogicCommand from .logic_command2 import SystemLogicCommand2 # celery 때문에 import from .logic_env import SystemLogicEnv from .logic_notify import SystemLogicNotify from .logic_plugin import LogicPlugin from .logic_selenium import SystemLogicSelenium from .logic_site import SystemLogicSite from .logic_telegram_bot import SystemLogicTelegramBot from .logic_terminal import SystemLogicTerminal from .logic_tool_crypt import SystemLogicToolDecrypt from .model import ModelSetting ######################################################### ######################################################### # 플러그인 공용 ######################################################### blueprint = Blueprint(package_name, package_name, url_prefix='/%s' % package_name, template_folder='templates') menu = { 'uri' : package_name, 'name': '설정', 'list': [ { 'uri': 'setting', 'name': '일반설정', 'list': [ {'uri': 'basic', 'name': '기본'}, {'uri': 'auth', 'name': '인증'}, {'uri': 'env', 'name': '시스템'}, {'uri': 'notify', 'name': '알림'}, {'uri': 'telegram_bot', 'name': '텔레그램 봇'}, {'uri': 'selenium', 'name': 'Selenium'}, {'uri': 'site', 'name': 'Site'}, {'uri': 'memo', 'name': '메모'}, {'uri': 'terminal', 'name': 'Terminal'}, ], }, { 'uri': 'plugin', 'name': '플러그인' }, { 'uri': 'tool', 'name': 'Tool', 'list': [{'uri': 'crypt', 'name': '암호화'}] }, { 'uri': 'log', 'name': '로그' } ] } #if platform.system() == 'Windows': # del menu['sub2']['setting'][-1] def plugin_load(): logger.debug('plugin_load:%s', package_name) SystemLogic.plugin_load() SystemLogicTelegramBot.plugin_load() SystemLogicSite.plugin_load() def plugin_unload(): logger.debug('plugin_load:%s', package_name) SystemLogicSelenium.plugin_unload() SystemLogicCommand.plugin_unload() SystemLogicCommand2.plugin_unload() ######################################################### # WEB Menu ######################################################### @blueprint.route('/') def normal(): return redirect('/%s/setting' % package_name) @login_required def home(): return render_template('info.html', arg=None) @blueprint.route('/', methods=['GET', 'POST']) @login_required def first_menu(sub): #logger.debug('System SUB:%s', sub) arg = None if sub == 'home': return render_template('%s_%s.html' % (package_name, sub), arg=None) elif sub == 'setting': return redirect('/%s/%s/basic' % (package_name, sub)) elif sub == 'tool': return redirect('/%s/%s/crypt' % (package_name, sub)) elif sub == 'plugin': arg = ModelSetting.to_dict() arg['install'] = request.args.get('install', '') if arg['install'] == 'flaskfilemanager': arg['install'] = 'https://github.com/soju6jan/' + arg['install'] try: import flaskfilemanager arg['install'] = '' except: pass elif arg['install'] == 'flaskcode': arg['install'] = 'https://github.com/soju6jan/' + arg['install'] try: import flaskcode arg['install'] = '' except: pass return render_template('system_plugin.html', arg=arg) elif sub == 'information': return render_template('manual.html', sub=sub, arg='system.json') elif sub == 'log': log_files=os.listdir(os.path.join(path_data, 'log')) log_files.sort() log_list = [] arg = {'package_name' : package_name, 'sub' : sub} for x in log_files: if x.endswith('.log'): log_list.append(x) arg['log_list'] = '|'.join(log_list) arg['all_list'] = '|'.join(log_files) arg['filename'] = '' if 'filename' in request.form: arg['filename'] = request.form['filename'] logger.debug(arg) return render_template('%s_%s.html' % (package_name, sub), arg=arg) elif sub == 'restart': restart() return render_template('system_restart.html', sub=sub, referer=request.headers.get("Referer")) elif sub == 'shutdown': shutdown() return render_template('system_restart.html', sub=sub, referer=request.headers.get("Referer")) elif sub == 'telegram': return redirect('/%s/%s/setting' % (package_name, sub)) return render_template('sample.html', title='%s - %s' % (package_name, sub)) @blueprint.route('//') @login_required def second_menu(sub, sub2): try: if sub == 'setting': arg = ModelSetting.to_dict() arg['sub'] = sub2 if sub2 == 'basic': arg['point'] = SystemLogic.point return render_template('%s_%s_%s.html' % (package_name, sub, sub2), arg=arg) elif sub2 in ['trans', 'selenium', 'notify']: return render_template('%s_%s_%s.html' % (package_name, sub, sub2), arg=arg) elif sub2 == 'auth': arg['auth_result'] = SystemLogicAuth.get_auth_status() return render_template('%s_%s_%s.html' % (package_name, sub, sub2), arg=arg) elif sub2 == 'telegram_bot': arg['scheduler'] = str(scheduler.is_include('%s_%s' % (package_name, sub2))) arg['is_running'] = str(scheduler.is_running('%s_%s' % (package_name, sub2))) return render_template('%s_%s_%s.html' % (package_name, sub, sub2), arg=arg) elif sub2 == 'env': arg['export'] = SystemLogicEnv.load_export() if arg['export'] is None: arg['export'] = u'export.sh 파일이 없습니다.' return render_template('%s_%s_%s.html' % (package_name, sub, sub2), arg=arg) elif sub2 == 'site': arg['scheduler'] = str(scheduler.is_include('%s_%s' % (package_name, sub2))) arg['is_running'] = str(scheduler.is_running('%s_%s' % (package_name, sub2))) from system.model import ModelSetting as SystemModelSetting arg['site_get_daum_cookie_url'] = '{ddns}/{package_name}/api/{sub2}/daum_cookie'.format(ddns=SystemModelSetting.get('ddns'), package_name=package_name, sub2=sub2) if SystemModelSetting.get_bool('auth_use_apikey'): arg['site_get_daum_cookie_url'] += '?apikey={apikey}'.format(apikey=SystemModelSetting.get('auth_apikey')) return render_template('%s_%s_%s.html' % (package_name, sub, sub2), arg=arg) elif sub2 == 'memo': return render_template('%s_%s_%s.html' % (package_name, sub, sub2), arg=arg) elif sub2 == 'terminal': arg['yaml_path'] = SystemLogicTerminal.yaml_path.replace(path_app_root, '') return render_template('%s_%s_%s.html' % (package_name, sub, sub2), arg=arg) elif sub == 'tool': arg = ModelSetting.to_dict() arg['sub'] = sub2 if sub2 == 'crypt': return render_template('%s_%s_%s.html' % (package_name, sub, sub2), arg=arg) except Exception as exception: logger.error('Exception:%s', exception) logger.error(traceback.format_exc()) ######################################################### # For UI ######################################################### @blueprint.route('/ajax//', methods=['GET', 'POST']) @login_required def second_ajax(sub, sub2): logger.debug('System AJAX sub:%s', sub) try: if sub == 'auth': from .logic_auth import SystemLogicAuth return SystemLogicAuth.process_ajax(sub2, request) elif sub == 'selenium': return SystemLogicSelenium.process_ajax(sub2, request) elif sub == 'notify': return SystemLogicNotify.process_ajax(sub2, request) elif sub == 'telegram_bot': return SystemLogicTelegramBot.process_ajax(sub2, request) elif sub == 'env': return SystemLogicEnv.process_ajax(sub2, request) elif sub == 'site': return SystemLogicSite.process_ajax(sub2, request) elif sub == 'crypt': return SystemLogicToolDecrypt.process_ajax(sub2, request) elif sub == 'terminal': return SystemLogicTerminal.process_ajax(sub2, request) except Exception as exception: logger.error('Exception:%s', exception) logger.error(traceback.format_exc()) @blueprint.route('/ajax/', methods=['GET', 'POST']) @login_required def ajax(sub): #logger.debug('System AJAX sub:%s', sub) try: if sub == 'info': try: ret = {} ret['system'] = SystemLogic.get_info() ret['scheduler'] = scheduler.get_job_list_info() #logger.debug(ret) return jsonify(ret) except Exception as exception: logger.error('Exception:%s', exception) logger.error(traceback.format_exc()) return jsonify() elif sub == 'setting_save_system': try: ret = SystemLogic.setting_save_system(request) return jsonify(ret) except Exception as exception: logger.error('Exception:%s', exception) logger.error(traceback.format_exc()) elif sub == 'setting_save': ret = ModelSetting.setting_save(request) SystemLogic.setting_save_after() return jsonify(ret) elif sub == 'ddns_test': try: url = request.form['ddns'] + '/version' res = requests.get(url) data = res.text #data = res.json() #logger.debug(data) return jsonify(data) except Exception as exception: logger.error('Exception:%s', exception) logger.error(traceback.format_exc()) return jsonify('fail') elif sub == 'celery_test': try: #result = add_together.delay(10, 20) #print(result.wait()) #return 'Welcome to my app!' try: import framework framework.exit_code = 1 socketio.stop() except Exception as exception: logger.error('Exception:%s', exception) logger.error(traceback.format_exc()) #os.environ['SJVA_REPEAT_TYPE'] = 'update' return jsonify() except Exception as exception: logger.error('Exception:%s', exception) logger.error(traceback.format_exc()) elif sub == 'command_run': try: command_text = request.form['command_text'] ret = SystemLogic.command_run(command_text) return jsonify(ret) except Exception as exception: logger.error('Exception:%s', exception) logger.error(traceback.format_exc()) elif sub == 'get_link_list': try: link_json = SystemLogic.get_setting_value('link_json') j = json.loads(link_json) return jsonify(j) except Exception as exception: logger.error('Exception:%s', exception) logger.error(traceback.format_exc()) elif sub == 'link_save': try: link_data_str = request.form['link_data'] #j = json.loads(link_data) ret = SystemLogic.link_save(link_data_str) return jsonify(ret) except Exception as exception: logger.error('Exception:%s', exception) logger.error(traceback.format_exc()) elif sub == 'plugin_list': try: return jsonify(LogicPlugin.get_plugin_list()) except Exception as exception: logger.error('Exception:%s', exception) logger.error(traceback.format_exc()) elif sub == 'plugin_install': try: #plugin_name = request.form['plugin_name'] plugin_git = request.form['plugin_git'] return jsonify(LogicPlugin.plugin_install_by_api(plugin_git, request.form.get('zip_url'), request.form.get('zip_filename'))) except Exception as exception: logger.error('Exception:%s', exception) logger.error(traceback.format_exc()) elif sub == 'plugin_uninstall': try: plugin_name = request.form['plugin_name'] return jsonify(LogicPlugin.plugin_uninstall(plugin_name)) except Exception as exception: logger.error('Exception:%s', exception) logger.error(traceback.format_exc()) elif sub == 'recent_version': ret = SystemLogic.get_recent_version() ret = {'ret':ret, 'version':SystemLogic.recent_version} return jsonify(ret) except Exception as exception: logger.error('Exception:%s', exception) logger.error(traceback.format_exc()) @socketio.on('connect', namespace='/%s' % package_name) def connect(): try: InfoProcess.instance().connect(request.sid) except Exception as exception: logger.error('Exception:%s', exception) logger.error(traceback.format_exc()) @socketio.on('disconnect', namespace='/%s' % package_name) def disconnect(): try: InfoProcess.instance().disconnect(request.sid) except Exception as exception: logger.error('Exception:%s', exception) logger.error(traceback.format_exc()) @socketio.on('connect', namespace='/system_restart') def connect_system_restart(): try: socketio.emit("on_connect", 'restart', namespace='/system_restart', broadcast=True) except Exception as exception: logger.error('Exception:%s', exception) logger.error(traceback.format_exc()) @socketio.on('disconnect', namespace='/system_restart') def disconnect_system_restart(): try: pass except Exception as exception: logger.error('Exception:%s', exception) logger.error(traceback.format_exc()) ######################################################### # API ######################################################### @blueprint.route('/api/', methods=['GET', 'POST']) @check_api def first_api(sub): try: if sub == 'plugin_add': plugin_git = request.form['plugin_git'] from system.logic_plugin import LogicPlugin ret = LogicPlugin.plugin_install_by_api(plugin_git, request.form.get('zip_url'), request.form.get('zip_filename')) return jsonify(ret) elif sub == 'restart': logger.debug('web restart') import system system.restart() return jsonify({'ret':'success'}) elif sub == 'gds': url = f"{app.config['DEFINE']['WEB_DIRECT_URL']}/sjva/gds2.php?type=file&id={request.args.get('id')}&user_id={ModelSetting.get('sjva_me_user_id')}&user_apikey={ModelSetting.get('auth_apikey')}" data = requests.get(url).json()['data'] logger.debug(data) req_headers = dict(request.headers) headers = {} if 'Range' not in req_headers or req_headers['Range'].startswith('bytes=0-'): headers['Range'] = "bytes=0-1048576" else: headers['Range'] = req_headers['Range'] headers['Authorization'] = f"Bearer {data['token']}" headers['Connection'] = 'keep-alive' r = requests.get(data['url'], headers=headers, stream=True) rv = Response(r.iter_content(chunk_size=1048576), r.status_code, content_type=r.headers['Content-Type'], direct_passthrough=True) rv.headers.add('Content-Range', r.headers.get('Content-Range')) return rv elif sub == 'gds2': url = f"{app.config['DEFINE']['WEB_DIRECT_URL']}/sjva/gds.php?type=file&id={request.args.get('id')}&user_id={ModelSetting.get('sjva_me_user_id')}&user_apikey={ModelSetting.get('auth_apikey')}" data = requests.get(url).json()['data'] logger.debug(data) req_headers = dict(request.headers) headers = {} headers['Range'] = f"bytes={request.args.get('range')}" headers['Authorization'] = f"Bearer {data['token']}" headers['Connection'] = 'keep-alive' logger.warning(headers) """ response = redirect(data['url']) headers = dict(response.headers) headers.update({'Authorization': f"Bearer {data['token']}"}) response.headers = headers return response response.headers.add('Authorization', headers['Authorization']) #response.headers['Location'] = data['url'] return response """ r = requests.get(data['url'], headers=headers, stream=True) logger.warning(r.history) #rv = Response(r.iter_content(chunk_size=10485760), r.status_code, content_type=r.headers['Content-Type'], direct_passthrough=True) #rv.headers.add('Content-Range', r.headers.get('Content-Range')) rv = Response(r.iter_content(chunk_size=1048576), r.status_code, content_type=r.headers['Content-Type'], direct_passthrough=True) rv.headers.add('Content-Range', r.headers.get('Content-Range')) logger.debug(rv.headers) return rv elif sub == 'gds_subtitle': url = f"{app.config['DEFINE']['WEB_DIRECT_URL']}/sjva/gds2.php?type=file&id={request.args.get('id')}&user_id={ModelSetting.get('sjva_me_user_id')}&user_apikey={ModelSetting.get('auth_apikey')}" data = requests.get(url).json()['data'] logger.debug(data) req_headers = dict(request.headers) headers = {} headers['Range'] = f"bytes={request.args.get('range')}" headers['Authorization'] = f"Bearer {data['token']}" headers['Connection'] = 'keep-alive' logger.warning(headers) r = requests.get(data['url'], headers=headers, stream=True) logger.warning(r.history) if r.encoding != None: if r.encoding == 'ISO-8859-1': # 한글자막 인코딩 예외처리 try: text = r.content.decode('utf-8', "strict") except Exception as e: logger.error('Exception:%s', e) logger.error(traceback.format_exc()) text = r.content.decode('utf-8', "ignore") else: text = r.content.decode(r.encoding, "ignore") else: text = r.text from framework.common.util import convert_srt_to_vtt as convSrt2Vtt vtt = convSrt2Vtt(text) r.headers['Content-Type'] = "text/vtt; charset=utf-8" rv = Response(vtt, r.status_code, content_type=r.headers['Content-Type']) rv.headers.add('Content-Disposition', 'inline; filename="subtitle.vtt"') rv.headers.add('Content-Transfer-Encoding', 'binary') logger.debug(rv.headers) return rv except Exception as exception: logger.error('Exception:%s', exception) logger.error(traceback.format_exc()) @blueprint.route('/api//', methods=['GET', 'POST']) @check_api def second_api(sub, sub2): try: if sub == 'trans': from .logic_trans import SystemLogicTrans return SystemLogicTrans.process_api(sub2, request) elif sub == 'site': from .logic_site import SystemLogicSite return SystemLogicSite.process_api(sub2, request) except Exception as exception: logger.error('Exception:%s', exception) logger.error(traceback.format_exc()) @blueprint.route("/videojs", methods=['GET', 'POST']) def videojs(): data = {} data['play_title'] = request.form['play_title'] data['play_source_src'] = request.form['play_source_src'] data['play_source_type'] = request.form['play_source_type'] if 'play_subtitle_src' in request.form: data['play_subtitle_src'] = request.form['play_subtitle_src'] #logger.warning(data) return render_template('videojs.html', data=data)