diff --git a/files/config.yaml.docker b/files/config.yaml.docker deleted file mode 100644 index 496b9a4..0000000 --- a/files/config.yaml.docker +++ /dev/null @@ -1,12 +0,0 @@ -path_data: "/data" - -#use_gevent: true -#use_celery: true -#debug: false -#redis_port: 46379 -#port: 9999 -#plugin_update: false -#running_type: "docker" -#plugin_loading_only_devpath: true -#plugin_loading_list: [] -#plugin_except_list: [] diff --git a/files/freeze.txt b/files/freeze.txt deleted file mode 100644 index 1e14ac3..0000000 --- a/files/freeze.txt +++ /dev/null @@ -1,71 +0,0 @@ -amqp==5.1.1 -APScheduler==3.9.1 -async-generator==1.10 -async-timeout==4.0.2 -attrs==22.1.0 -bidict==0.22.0 -billiard==3.6.4.0 -celery==5.2.7 -certifi==2022.9.24 -cffi==1.15.1 -charset-normalizer==2.1.1 -click==8.1.3 -click-didyoumean==0.3.0 -click-plugins==1.1.1 -click-repl==0.2.0 -colorama==0.4.5 -Deprecated==1.2.13 -discord-webhook==0.17.0 -exceptiongroup==1.0.0rc9 -Flask==2.2.2 -Flask-Cors==3.0.10 -Flask-Dropzone==1.6.0 -Flask-Login==0.6.2 -Flask-Markdown==0.3 -Flask-SocketIO==5.3.1 -Flask-SQLAlchemy==3.0.1 -gevent==22.8.0 -gevent-websocket==0.10.1 -greenlet==1.1.3.post0 -h11==0.14.0 -idna==3.4 -itsdangerous==2.1.2 -Jinja2==3.1.2 -kombu==5.2.4 -lxml==4.9.1 -Markdown==3.4.1 -MarkupSafe==2.1.1 -outcome==1.2.0 -packaging==21.3 -Pillow==9.2.0 -prompt-toolkit==3.0.31 -psutil==5.9.2 -pycparser==2.21 -pycryptodome==3.15.0 -pyparsing==3.0.9 -PySocks==1.7.1 -python-engineio==4.3.4 -python-socketio==5.7.1 -pytz==2022.4 -pytz-deprecation-shim==0.1.0.post0 -PyYAML==6.0 -redis==4.3.4 -requests==2.28.1 -selenium==4.5.0 -six==1.16.0 -sniffio==1.3.0 -sortedcontainers==2.4.0 -SQLAlchemy==1.4.41 -telepot-mod==0.0.1 -trio==0.22.0 -trio-websocket==0.9.2 -tzdata==2022.4 -tzlocal==4.2 -urllib3==1.26.12 -vine==5.0.0 -wcwidth==0.2.5 -Werkzeug==2.2.2 -wrapt==1.14.1 -wsproto==1.2.0 -zope.event==4.5.0 -zope.interface==5.5.0 diff --git a/files/requirements_mini.txt b/files/requirements_mini.txt index b75825d..ef50bde 100644 --- a/files/requirements_mini.txt +++ b/files/requirements_mini.txt @@ -18,7 +18,6 @@ discord-webhook pyyaml telepot-mod Flask-Dropzone -pycryptodome psutil # filemanager diff --git a/files/requirements_useful.txt b/files/requirements_useful.txt index 709299a..2b4f785 100644 --- a/files/requirements_useful.txt +++ b/files/requirements_useful.txt @@ -1,2 +1,3 @@ lxml selenium +pycryptodome \ No newline at end of file diff --git a/lib/framework/init_declare.py b/lib/framework/init_declare.py index 006903e..a37048f 100644 --- a/lib/framework/init_declare.py +++ b/lib/framework/init_declare.py @@ -63,13 +63,6 @@ class CustomFormatter(logging.Formatter): return formatter.format(record) -# Suuport를 logger 생성전에 쓰지 않기 위해 중복 선언 -def read_yaml(filepath): - import yaml - with open(filepath, encoding='utf8') as file: - data = yaml.load(file, Loader=yaml.FullLoader) - return data - class User: def __init__(self, user_id, email=None, passwd_hash=None, authenticated=False): @@ -88,9 +81,14 @@ class User: return str(r) def can_login(self, passwd_hash): - from support import SupportAES - tmp = SupportAES.decrypt(self.passwd_hash) - return passwd_hash == tmp + #from support import SupportAES + #tmp = SupportAES.decrypt(self.passwd_hash) + import hashlib + enc = hashlib.md5() + enc.update(passwd_hash.encode()) + hash = enc.hexdigest() + #return True + return self.passwd_hash == hash def is_active(self): return True diff --git a/lib/framework/init_main.py b/lib/framework/init_main.py index 1842963..417f830 100644 --- a/lib/framework/init_main.py +++ b/lib/framework/init_main.py @@ -8,6 +8,7 @@ import time import traceback from datetime import datetime +import yaml from flask import Flask from flask_cors import CORS from flask_login import LoginManager, login_required @@ -69,7 +70,6 @@ class Framework: self.__init_db() - if True or self.config['run_flask']: from .scheduler import Job, Scheduler self.scheduler = Scheduler(self) @@ -78,9 +78,6 @@ class Framework: if self.config['use_gevent']: self.socketio = SocketIO(self.app, cors_allowed_origins="*") else: - #if self.config['running_type'] == 'termux': - # self.socketio = SocketIO(self.app, cors_allowed_origins="*", async_mode='eventlet') - #else: self.socketio = SocketIO(self.app, cors_allowed_origins="*", async_mode='threading') CORS(self.app) @@ -208,18 +205,14 @@ class Framework: from .init_web import jinja_initialize jinja_initialize(self.app) - #system.LogicPlugin.custom_plugin_update() from .init_plugin import PluginManager self.PluginManager = PluginManager PluginManager.plugin_update() PluginManager.plugin_init() PluginManager.plugin_menus['system'] = {'menu':SP.menu, 'match':False} - - #from .init_menu import init_menu, get_menu_map + from .init_menu import MenuManager MenuManager.init_menu() - #init_menu(self.plugin_menu) - #system.SystemLogic.apply_menu_link() if self.config['run_flask']: if self.config.get('port') == None: @@ -232,6 +225,7 @@ class Framework: self.logger.info(f"### PORT: {self.config.get('port')}") self.logger.info('### Now you can access App by webbrowser!!') + def __prepare_starting(self): # 여기서 monkey.patch시 너무 늦다고 문제 발생 pass @@ -276,7 +270,9 @@ class Framework: def __init_define(self): self.config['DEFINE'] = {} # 이건 필요 없음 - self.config['DEFINE']['MAIN_SERVER_URL'] = 'https://server.sjva.me' + self.config['DEFINE']['GIT_VERSION_URL'] = 'https://raw.githubusercontent.com/flaskfarm/flaskfarm/main/lib/framework/version.py' + self.config['DEFINE']['CHANGELOG'] = 'https://flaskfarm.github.io/posts/changelog' + def __process_args(self): @@ -306,29 +302,23 @@ class Framework: #self.config['arg_config'] = def __load_config(self): - from .init_declare import read_yaml - #if self.config['run_flask']: if self.config['arg_config'] == '.': #self.config['config_filepath'] = os.path.join(self.path_app_root, 'config.yaml') self.config['config_filepath'] = os.path.join(self.config['path_working'], 'config.yaml') else: self.config['config_filepath'] = self.config['arg_config'] - if not os.path.exists(self.config['config_filepath']): - # celery는 환경변수 사용불가로 native 판단 - # 도커는 celery가 먼저 진입 - # 추후에 변경할 것!!!!!!!!!!!!!!!!! TODO - if self.config.get('running_type').startswith('docker'):# or os.path.exists('/data'): - shutil.copy( - os.path.join(self.path_app_root, 'files', 'config.yaml.docker'), - self.config['config_filepath'] - ) + if os.path.exists(self.config['config_filepath']) == False: + if self.config.get('running_type').startswith('docker'): + with open(self.config['config_filepath'], 'w', encoding='utf8') as f: + yaml.dump({'path_data':'/data'}, f, default_flow_style=False, allow_unicode=True) else: shutil.copy( os.path.join(self.path_app_root, 'files', 'config.yaml.template'), self.config['config_filepath'] ) - data = read_yaml(self.config['config_filepath']) + with open(self.config['config_filepath'], encoding='utf8') as file: + data = yaml.load(file, Loader=yaml.FullLoader) for key, value in data.items(): if key == 'running_type' and value not in ['termux', 'entware']: continue @@ -509,8 +499,8 @@ class Framework: def get_recent_version(self): try: import requests - url = f"{self.config['DEFINE']['MAIN_SERVER_URL']}/version" - self.config['recent_version'] = requests.get(url).text + text = requests.get(self.config['DEFINE']['GIT_VERSION_URL']).text + self.config['recent_version'] = text.split('=')[1].strip().strip('"') return True except Exception as e: self.logger.error(f'Exception:{str(e)}') diff --git a/lib/framework/init_route.py b/lib/framework/init_route.py index c00edb7..ee94855 100644 --- a/lib/framework/init_route.py +++ b/lib/framework/init_route.py @@ -1,7 +1,8 @@ import os import traceback -from flask import jsonify, redirect, request, send_from_directory +from flask import (jsonify, redirect, render_template, request, + send_from_directory) from flask_login import login_required from framework import F @@ -109,7 +110,26 @@ def upload(): return jsonify('fail') +@F.app.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'] + return render_template('videojs.html', data=data) + + + + + + + + # 3.10에서 이거 필수 @F.socketio.on('connect', namespace=f'/framework') def connect(): pass + + diff --git a/lib/framework/scheduler.py b/lib/framework/scheduler.py index faeb9ca..948fa62 100644 --- a/lib/framework/scheduler.py +++ b/lib/framework/scheduler.py @@ -231,7 +231,9 @@ class Job(object): self.thread = threading.Thread(target=self.target_function, args=(self.args,)) self.thread.daemon = True self.thread.start() + F.socketio.emit('notify', {'type':'success', 'msg':f"{self.description}
작업을 시작합니다." }, namespace='/framework', broadcast=True) self.thread.join() + F.socketio.emit('notify', {'type':'success', 'msg':f"{self.description}
작업이 종료되었습니다." }, namespace='/framework', broadcast=True) self.end_time = datetime.now(timezone('Asia/Seoul')) self.running_timedelta = self.end_time - self.start_time self.status = 'success' diff --git a/lib/framework/static/js/ff_common1.js b/lib/framework/static/js/ff_common1.js index e9a27bd..88c6ec3 100644 --- a/lib/framework/static/js/ff_common1.js +++ b/lib/framework/static/js/ff_common1.js @@ -116,10 +116,7 @@ function showModal(data='EMPTY', title='JSON', json=true) { } -/////////////////////////////////////// -// camel - -function get_formdata(form_id) { +function getFormdata(form_id) { // on, off 일수도 있으니 모두 True, False로 통일하고 // 밑에서는 False인 경우 값이 추가되지 않으니.. 수동으로 넣어줌 var checkboxs = $(form_id + ' input[type=checkbox]'); @@ -148,20 +145,23 @@ function get_formdata(form_id) { return formData; } +/////////////////////////////////////// +// camel + function use_collapse(div, reverse=false) { var ret = $('#' + div).prop('checked'); if (reverse) { if (ret) { - $('#' + div + '_div').collapse('hide') + $('#' + div + '_div').collapse('hide'); } else { - $('#' + div + '_div').collapse('show') + $('#' + div + '_div').collapse('show'); } } else { if (ret) { - $('#' + div + '_div').collapse('show') + $('#' + div + '_div').collapse('show'); } else { - $('#' + div + '_div').collapse('hide') + $('#' + div + '_div').collapse('hide'); } } } diff --git a/lib/framework/static/js/ff_global1.js b/lib/framework/static/js/ff_global1.js index 9e8e471..d4e766c 100644 --- a/lib/framework/static/js/ff_global1.js +++ b/lib/framework/static/js/ff_global1.js @@ -78,7 +78,7 @@ $("body").on('click', '#globalSettingSaveBtn', function(e){ }); function globalSettingSave() { - var formData = get_formdata('#setting'); + var formData = getFormdata('#setting'); $.ajax({ url: '/' + PACKAGE_NAME + '/ajax/setting_save', type: "POST", @@ -119,6 +119,11 @@ $("body").on('click', '#globalEditBtn', function(e) { }); }); +$("body").on('click', '#globalCliboardBtn', function(e) { + e.preventDefault(); + window.navigator.clipboard.writeText($(this).data('text')); + notify("클립보드에 복사하였습니다.", "success"); +}); /////////////////////////////////////// @@ -144,6 +149,25 @@ function globalSendCommand(command, arg1, arg2, arg3, modal_title, callback) { }); } +function globalSendCommandPage(command, arg1, arg2, arg3, modal_title, callback) { + console.log("globalSendCommandPage [" + command + '] [' + arg1 + '] [' + arg2 + '] [' + arg3 + '] [' + modal_title + '] [' + callback + ']'); + console.log('/' + PACKAGE_NAME + '/ajax/' + MODULE_NAME + '/command'); + + $.ajax({ + url: '/' + PACKAGE_NAME + '/ajax/' + MODULE_NAME + '/' + PAGE_NAME + '/command', + type: "POST", + cache: false, + data:{command:command, arg1:arg1, arg2:arg2, arg3}, + dataType: "json", + success: function (ret) { + if (ret.msg != null) notify(ret.msg, ret.ret); + if (ret.modal != null) m_modal(ret.modal, modal_title, false); + if (ret.json != null) m_modal(ret.json, modal_title, true); + if (callback != null) callback(ret); + } + }); +} + function shutdown_confirm() { $("#confirm_title").html("종료 확인"); $("#confirm_body").html("종료 하시겠습니까?"); diff --git a/lib/framework/static/js/ff_ui1.js b/lib/framework/static/js/ff_ui1.js index 32867af..ee43e42 100644 --- a/lib/framework/static/js/ff_ui1.js +++ b/lib/framework/static/js/ff_ui1.js @@ -1,3 +1,74 @@ +function m_button_group(h) { + var str = '
'; + str += h + str += '
'; + return str; +} + +// primary, secondary, success, danger, warning, info, light, dark, white +function m_button(id, text, data={}, color='success', outline=true, small=false) { + var str = '