update
This commit is contained in:
46
lib/cli/code_encode.py
Normal file
46
lib/cli/code_encode.py
Normal file
@@ -0,0 +1,46 @@
|
||||
|
||||
import argparse
|
||||
import os
|
||||
import sys
|
||||
|
||||
sys.path.append(os.path.dirname(os.path.dirname(__file__)))
|
||||
|
||||
from support import SupportFile, SupportSC, logger
|
||||
|
||||
|
||||
class CodeEncode:
|
||||
def start_folder(self, folderpath):
|
||||
for name in os.listdir(folderpath):
|
||||
filepath = os.path.join(folderpath, name)
|
||||
if os.path.isfile(filepath) and name not in ['setup.py', '__init__.py'] and name.endswith('.py'):
|
||||
self.encode_file(filepath)
|
||||
|
||||
def encode_file(self, filepath):
|
||||
if filepath.endswith(".py") == False:
|
||||
logger.info("is not .py file")
|
||||
return
|
||||
text = SupportFile.read_file(filepath)
|
||||
data = SupportSC.encode(text, 1)
|
||||
SupportFile.write_file(filepath + 'f', data)
|
||||
logger.info(f"Create {os.path.basename(filepath + 'f')}")
|
||||
|
||||
|
||||
def process_args(self):
|
||||
parser = argparse.ArgumentParser()
|
||||
parser.add_argument('--mode', default='encode')
|
||||
parser.add_argument('--source', required=True, help=u'absolute path. folder or file')
|
||||
args = parser.parse_args()
|
||||
if SupportSC.LIBRARY_LOADING == False:
|
||||
logger.error("sc import fail")
|
||||
return
|
||||
if os.path.exists(args.source):
|
||||
if os.path.isdir(args.source):
|
||||
self.start_folder(args.source)
|
||||
elif os.path.isfile(args.source):
|
||||
self.encode_file(args.source)
|
||||
|
||||
|
||||
if __name__== "__main__":
|
||||
CodeEncode().process_args()
|
||||
|
||||
# python C:\work\FlaskFarm\flaskfarm\lib\cli\code_encode.py --source=C:\work\FlaskFarm\data\LOADING\klive_plus\source_spotv.py
|
||||
@@ -204,7 +204,7 @@ class Framework:
|
||||
|
||||
from .init_web import jinja_initialize
|
||||
jinja_initialize(self.app)
|
||||
|
||||
|
||||
from .init_plugin import PluginManager
|
||||
self.PluginManager = PluginManager
|
||||
PluginManager.plugin_update()
|
||||
|
||||
@@ -21,19 +21,8 @@ class PluginManager:
|
||||
|
||||
@classmethod
|
||||
def get_plugin_name_list(cls):
|
||||
#if not app.config['config']['auth_status']:
|
||||
# return
|
||||
"""
|
||||
plugin_path = os.path.join(frame.config['path_app'], 'plugins')
|
||||
sys.path.insert(0, plugin_path)
|
||||
from system import SystemModelSetting
|
||||
plugins = os.listdir(plugin_path)
|
||||
"""
|
||||
plugins = []
|
||||
|
||||
|
||||
#2019-07-17
|
||||
|
||||
try:
|
||||
plugin_path = os.path.join(F.config['path_data'], 'plugins')
|
||||
if os.path.exists(plugin_path) == True and os.path.isdir(plugin_path) == True:
|
||||
@@ -115,51 +104,18 @@ class PluginManager:
|
||||
|
||||
F.logger.debug(plugins)
|
||||
for plugin_name in plugins:
|
||||
|
||||
#logger.debug(len(system.LogicPlugin.current_loading_plugin_list))
|
||||
#if plugin_name.startswith('_'):
|
||||
# continue
|
||||
#if plugin_name == 'terminal' and platform.system() == 'Windows':
|
||||
# continue
|
||||
#if plugin_name in except_plugin_list:
|
||||
# F.logger.debug('Except plugin : %s' % frame.plugin_menu)
|
||||
# continue
|
||||
F.logger.debug(f'[+] PLUGIN LOADING Start.. [{plugin_name}]')
|
||||
entity = cls.all_package_list[plugin_name]
|
||||
entity['version'] = '3'
|
||||
try:
|
||||
mod = __import__('%s' % (plugin_name), fromlist=[])
|
||||
mod_plugin_info = None
|
||||
# 2021-12-31
|
||||
#import system
|
||||
#if plugin_name not in system.LogicPlugin.current_loading_plugin_list:
|
||||
# system.LogicPlugin.current_loading_plugin_list[plugin_name] = {'status':'loading'}
|
||||
|
||||
try:
|
||||
mod_plugin_info = getattr(mod, 'plugin_info')
|
||||
entity['module'] = mod
|
||||
"""
|
||||
if 'category' not in mod_plugin_info and 'category_name' in mod_plugin_info:
|
||||
mod_plugin_info['category'] = mod_plugin_info['category_name']
|
||||
if 'policy_point' in mod_plugin_info:
|
||||
if mod_plugin_info['policy_point'] > app.config['config']['point']:
|
||||
system.LogicPlugin.current_loading_plugin_list[plugin_name]['status'] = 'violation_policy_point'
|
||||
continue
|
||||
if 'policy_level' in mod_plugin_info:
|
||||
if mod_plugin_info['policy_level'] > app.config['config']['level']:
|
||||
system.LogicPlugin.current_loading_plugin_list[plugin_name]['status'] = 'violation_policy_level'
|
||||
continue
|
||||
if 'category' in mod_plugin_info and mod_plugin_info['category'] == 'beta':
|
||||
if SystemModelSetting.get_bool('use_beta') == False:
|
||||
system.LogicPlugin.current_loading_plugin_list[plugin_name]['status'] = 'violation_beta'
|
||||
continue
|
||||
"""
|
||||
except Exception as exception:
|
||||
#logger.error('Exception:%s', exception)
|
||||
#logger.error(traceback.format_exc())
|
||||
|
||||
#mod_plugin_info = getattr(mod, 'setup')
|
||||
F.logger.info(f'[!] PLUGIN_INFO not exist : [{plugin_name}] - is FF')
|
||||
|
||||
if mod_plugin_info == None:
|
||||
try:
|
||||
mod = __import__(f'{plugin_name}.setup', fromlist=['setup'])
|
||||
@@ -168,13 +124,10 @@ class PluginManager:
|
||||
F.logger.error(f'Exception:{str(e)}')
|
||||
F.logger.error(traceback.format_exc())
|
||||
F.logger.warning(f'[!] NOT normal plugin : [{plugin_name}]')
|
||||
#entity['version'] = 'not_plugin'
|
||||
|
||||
|
||||
try:
|
||||
if entity['version'] != '4':
|
||||
mod_blue_print = getattr(mod, 'blueprint')
|
||||
|
||||
else:
|
||||
entity['setup_mod'] = mod
|
||||
entity['P'] = getattr(mod, 'P')
|
||||
@@ -196,24 +149,7 @@ class PluginManager:
|
||||
cls.all_package_list[plugin_name]['status'] = 'import fail'
|
||||
cls.all_package_list[plugin_name]['log'] = traceback.format_exc()
|
||||
|
||||
#from tool_base import d
|
||||
#logger.error(d(system.LogicPlugin.current_loading_plugin_list))
|
||||
# 2021-07-01 모듈에 있는 DB 테이블 생성이 안되는 문제
|
||||
# 기존 구조 : db.create_all() => 모듈 plugin_load => celery task 등록 후 리턴
|
||||
# 변경 구조 : 모듈 plugin_load => db.create_all() => celery인 경우 리턴
|
||||
|
||||
# plugin_load 를 해야 하위 로직에 있는 DB가 로딩된다.
|
||||
# plugin_load 에 db는 사용하는 코드가 있으면 안된다. (테이블도 없을 때 에러발생)
|
||||
try:
|
||||
#logger.warning('module plugin_load in celery ')
|
||||
cls.plugin_list['mod']['module'].plugin_load()
|
||||
except Exception as exception:
|
||||
F.logger.debug(f'mod plugin_load error!!')
|
||||
#logger.error('Exception:%s', exception)
|
||||
#logger.error(traceback.format_exc())
|
||||
|
||||
# import가 끝나면 DB를 만든다.
|
||||
# 플러그인 로드시 DB 초기화를 할 수 있다.
|
||||
|
||||
|
||||
if not F.config['run_celery']:
|
||||
try:
|
||||
@@ -225,17 +161,6 @@ class PluginManager:
|
||||
F.logger.debug('db.create_all error')
|
||||
|
||||
if not F.config['run_flask']:
|
||||
# 2021-06-03
|
||||
# 모듈의 로직에 있는 celery 함수는 등록해주어야한다.
|
||||
#try:
|
||||
# logger.warning('module plugin_load in celery ')
|
||||
# plugin_instance_list['mod'].plugin_load()
|
||||
#except Exception as exception:
|
||||
# logger.error('module plugin_load error')
|
||||
# logger.error('Exception:%s', exception)
|
||||
# logger.error(traceback.format_exc())
|
||||
# 2021-07-01
|
||||
# db때문에 위에서 로딩함.
|
||||
return
|
||||
|
||||
for key, entity in cls.plugin_list.items():
|
||||
@@ -259,6 +184,13 @@ class PluginManager:
|
||||
cls.all_package_list[key]['loading'] = False
|
||||
cls.all_package_list[key]['status'] = 'plugin_load error'
|
||||
cls.all_package_list[key]['log'] = traceback.format_exc()
|
||||
|
||||
if key in cls.plugin_menus:
|
||||
del cls.plugin_menus[key]
|
||||
from framework.init_menu import MenuManager
|
||||
MenuManager.init_menu()
|
||||
|
||||
|
||||
# mod는 위에서 로딩
|
||||
if key != 'mod':
|
||||
t = threading.Thread(target=func, args=(mod_plugin_load, key))
|
||||
|
||||
@@ -16,34 +16,30 @@ class Logic(object):
|
||||
self.P = P
|
||||
|
||||
def plugin_load(self):
|
||||
try:
|
||||
self.P.logger.debug('%s plugin_load', self.P.package_name)
|
||||
self.db_init()
|
||||
self.P.logger.debug('%s plugin_load', self.P.package_name)
|
||||
self.db_init()
|
||||
for module in self.P.module_list:
|
||||
module.migration()
|
||||
if module.page_list is not None:
|
||||
for page_instance in module.page_list:
|
||||
page_instance.migration()
|
||||
|
||||
for module in self.P.module_list:
|
||||
module.plugin_load()
|
||||
if module.page_list is not None:
|
||||
for page_instance in module.page_list:
|
||||
page_instance.plugin_load()
|
||||
if self.P.ModelSetting is not None:
|
||||
for module in self.P.module_list:
|
||||
module.migration()
|
||||
key = f'{module.name}_auto_start'
|
||||
if self.P.ModelSetting.has_key(key) and self.P.ModelSetting.get_bool(key):
|
||||
self.scheduler_start(module.name)
|
||||
if module.page_list is not None:
|
||||
for page_instance in module.page_list:
|
||||
page_instance.migration()
|
||||
key = f'{module.name}_{page_instance.name}_auto_start'
|
||||
if self.P.ModelSetting.has_key(key) and self.P.ModelSetting.get_bool(key):
|
||||
self.scheduler_start_sub(module.name, page_instance.name)
|
||||
|
||||
for module in self.P.module_list:
|
||||
module.plugin_load()
|
||||
if module.page_list is not None:
|
||||
for page_instance in module.page_list:
|
||||
page_instance.plugin_load()
|
||||
if self.P.ModelSetting is not None:
|
||||
for module in self.P.module_list:
|
||||
key = f'{module.name}_auto_start'
|
||||
if self.P.ModelSetting.has_key(key) and self.P.ModelSetting.get_bool(key):
|
||||
self.scheduler_start(module.name)
|
||||
if module.page_list is not None:
|
||||
for page_instance in module.page_list:
|
||||
key = f'{module.name}_{page_instance.name}_auto_start'
|
||||
if self.P.ModelSetting.has_key(key) and self.P.ModelSetting.get_bool(key):
|
||||
self.scheduler_start_sub(module.name, page_instance.name)
|
||||
|
||||
except Exception as e:
|
||||
self.P.logger.error(f'Exception:{str(e)}')
|
||||
self.P.logger.error(traceback.format_exc())
|
||||
|
||||
def db_init(self):
|
||||
try:
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
import traceback
|
||||
from datetime import datetime
|
||||
|
||||
from framework import F
|
||||
|
||||
@@ -32,8 +33,8 @@ def get_model_setting(package_name, logger, table_name=None):
|
||||
if ret is not None:
|
||||
return ret.value.strip()
|
||||
return None
|
||||
except Exception as exception:
|
||||
logger.error('Exception:%s %s', exception, key)
|
||||
except Exception as e:
|
||||
logger.error(f"Exception:{str(e)} [{key}]")
|
||||
logger.error(traceback.format_exc())
|
||||
|
||||
@staticmethod
|
||||
@@ -45,16 +46,24 @@ def get_model_setting(package_name, logger, table_name=None):
|
||||
def get_int(key):
|
||||
try:
|
||||
return int(ModelSetting.get(key))
|
||||
except Exception as exception:
|
||||
logger.error('Exception:%s %s', exception, key)
|
||||
except Exception as e:
|
||||
logger.error(f"Exception:{str(e)} [{key}]")
|
||||
logger.error(traceback.format_exc())
|
||||
|
||||
@staticmethod
|
||||
def get_bool(key):
|
||||
try:
|
||||
return (ModelSetting.get(key) == 'True')
|
||||
except Exception as exception:
|
||||
logger.error('Exception:%s %s', exception, key)
|
||||
except Exception as e:
|
||||
logger.error(f"Exception:{str(e)} [{key}]")
|
||||
logger.error(traceback.format_exc())
|
||||
|
||||
@staticmethod
|
||||
def get_datetime(key):
|
||||
try:
|
||||
return datetime.strptime(ModelSetting.get(key), '%Y-%m-%d %H:%M:%S.%f')
|
||||
except Exception as e:
|
||||
logger.error(f"Exception:{str(e)} [{key}]")
|
||||
logger.error(traceback.format_exc())
|
||||
|
||||
@staticmethod
|
||||
@@ -68,8 +77,8 @@ def get_model_setting(package_name, logger, table_name=None):
|
||||
else:
|
||||
F.db.session.add(ModelSetting(key, value.strip()))
|
||||
F.db.session.commit()
|
||||
except Exception as exception:
|
||||
logger.error('Exception:%s %s', exception, key)
|
||||
except Exception as e:
|
||||
logger.error(f"Exception:{str(e)} [{key}]")
|
||||
logger.error(traceback.format_exc())
|
||||
|
||||
@staticmethod
|
||||
@@ -78,8 +87,8 @@ def get_model_setting(package_name, logger, table_name=None):
|
||||
ret = ModelSetting.db_list_to_dict(F.db.session.query(ModelSetting).all())
|
||||
ret['package_name'] = package_name
|
||||
return ret
|
||||
except Exception as exception:
|
||||
logger.error('Exception:%s', exception)
|
||||
except Exception as e:
|
||||
logger.error(f"Exception:{str(e)}")
|
||||
logger.error(traceback.format_exc())
|
||||
|
||||
|
||||
@@ -99,8 +108,8 @@ def get_model_setting(package_name, logger, table_name=None):
|
||||
entity.value = value
|
||||
F.db.session.commit()
|
||||
return True, change_list
|
||||
except Exception as exception:
|
||||
logger.error('Exception:%s', exception)
|
||||
except Exception as e:
|
||||
logger.error(f"Exception:{str(e)}")
|
||||
logger.error(traceback.format_exc())
|
||||
logger.debug('Error Key:%s Value:%s', key, value)
|
||||
return False, []
|
||||
@@ -115,8 +124,8 @@ def get_model_setting(package_name, logger, table_name=None):
|
||||
values = [x.split(comment)[0].strip() for x in value.split(delimeter)]
|
||||
values = ModelSetting.get_list_except_empty(values)
|
||||
return values
|
||||
except Exception as exception:
|
||||
logger.error('Exception:%s', exception)
|
||||
except Exception as e:
|
||||
logger.error(f"Exception:{str(e)}")
|
||||
logger.error(traceback.format_exc())
|
||||
logger.error('Error Key:%s Value:%s', key, value)
|
||||
|
||||
|
||||
@@ -15,8 +15,9 @@ logger = get_logger()
|
||||
from .base.aes import SupportAES
|
||||
from .base.discord import SupportDiscord
|
||||
from .base.file import SupportFile
|
||||
from .base.sc import SupportSC
|
||||
from .base.string import SupportString
|
||||
from .base.subprocess import SupportSubprocess
|
||||
from .base.sub_process import SupportSubprocess
|
||||
from .base.telegram import SupportTelegram
|
||||
from .base.util import (AlchemyEncoder, SingletonClass, SupportUtil,
|
||||
default_headers, pt)
|
||||
|
||||
@@ -1,10 +1,16 @@
|
||||
import os, base64, traceback
|
||||
from Crypto.Cipher import AES
|
||||
import base64
|
||||
import os
|
||||
import traceback
|
||||
|
||||
from Crypto import Random
|
||||
from Crypto.Cipher import AES
|
||||
|
||||
from . import logger
|
||||
|
||||
BS = 16
|
||||
pad = lambda s: s + (BS - len(s) % BS) * chr(BS - len(s) % BS)
|
||||
unpad = lambda s : s[0:-s[-1]]
|
||||
pad = lambda s: s + (BS - len(s.encode('utf-8')) % BS) * chr(BS - len(s.encode('utf-8')) % BS)
|
||||
#unpad = lambda s : s[0:-s[-1]]
|
||||
unpad = lambda s : s[:-ord(s[len(s)-1:])]
|
||||
key = b'140b41b22a29beb4061bda66b6747e14'
|
||||
|
||||
class SupportAES(object):
|
||||
@@ -39,5 +45,56 @@ class SupportAES(object):
|
||||
iv = enc[:16]
|
||||
if len(iv) != 16:
|
||||
iv = os.urandom(16)
|
||||
if mykey is not None and type(mykey) == type(''):
|
||||
mykey = mykey.encode()
|
||||
cipher = AES.new(key if mykey is None else mykey, AES.MODE_CBC, iv )
|
||||
return unpad(cipher.decrypt( enc[16:] )).decode()
|
||||
|
||||
@classmethod
|
||||
def md5(cls, text):
|
||||
import hashlib
|
||||
enc = hashlib.md5()
|
||||
enc.update(text.encode())
|
||||
return enc.hexdigest()
|
||||
|
||||
|
||||
|
||||
|
||||
@classmethod
|
||||
def encrypt_(cls, raw, mykey=None, iv=None):
|
||||
try:
|
||||
Random.atfork()
|
||||
except Exception as exception:
|
||||
logger.error('Exception:%s', exception)
|
||||
logger.error(traceback.format_exc())
|
||||
raw = pad(raw)
|
||||
if type(raw) == type(''):
|
||||
raw = raw.encode()
|
||||
if mykey is not None and type(mykey) == type(''):
|
||||
mykey = mykey.encode()
|
||||
if iv == None:
|
||||
iv = Random.new().read( AES.block_size )
|
||||
elif iv is not None and type(iv) == type(''):
|
||||
iv = iv.encode()
|
||||
cipher = AES.new(key if mykey is None else mykey, AES.MODE_CBC, iv )
|
||||
try:
|
||||
tmp = cipher.encrypt( raw )
|
||||
except Exception as exception:
|
||||
logger.error('Exception:%s', exception)
|
||||
logger.error(traceback.format_exc())
|
||||
tmp = cipher.encrypt( raw.encode() )
|
||||
ret = base64.b64encode( tmp )
|
||||
ret = ret.decode()
|
||||
return ret
|
||||
|
||||
@classmethod
|
||||
def decrypt_(cls, enc, mykey=None, iv=None):
|
||||
enc = base64.b64decode(enc)
|
||||
if iv == None:
|
||||
iv = os.urandom(16)
|
||||
elif iv is not None and type(iv) == type(''):
|
||||
iv = iv.encode()
|
||||
if mykey is not None and type(mykey) == type(''):
|
||||
mykey = mykey.encode()
|
||||
cipher = AES.new(key if mykey is None else mykey, AES.MODE_CBC, iv )
|
||||
return unpad(cipher.decrypt( enc )).decode()
|
||||
|
||||
@@ -94,23 +94,6 @@ class SupportFile(object):
|
||||
|
||||
|
||||
|
||||
@classmethod
|
||||
def write(cls, data, filepath, mode='w'):
|
||||
try:
|
||||
import codecs
|
||||
ofp = codecs.open(filepath, mode, encoding='utf8')
|
||||
if isinstance(data, bytes) and mode == 'w':
|
||||
data = data.decode('utf-8')
|
||||
ofp.write(data)
|
||||
ofp.close()
|
||||
return True
|
||||
except Exception as exception:
|
||||
logger.debug('Exception:%s', exception)
|
||||
logger.debug(traceback.format_exc())
|
||||
return False
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
@classmethod
|
||||
|
||||
79
lib/support/base/sc.py
Normal file
79
lib/support/base/sc.py
Normal file
@@ -0,0 +1,79 @@
|
||||
import argparse
|
||||
import os
|
||||
import platform
|
||||
import re
|
||||
import sys
|
||||
import traceback
|
||||
|
||||
from . import logger
|
||||
|
||||
|
||||
class SupportSC:
|
||||
LIBRARY_LOADING = False
|
||||
try:
|
||||
if platform.system() == 'Linux':
|
||||
if (platform.platform().find('86') == -1 and platform.platform().find('64') == -1) or platform.platform().find('arch') != -1 or platform.platform().find('arm') != -1:
|
||||
sys.path.insert(2, os.path.join(os.path.dirname(os.path.abspath(__file__)), 'lib', 'sc', 'LinuxArm'))
|
||||
else:
|
||||
sys.path.insert(2, os.path.join(os.path.dirname(os.path.abspath(__file__)), 'lib', 'sc', 'Linux'))
|
||||
if platform.system() == 'Windows':
|
||||
sys.path.append(os.path.join(os.path.dirname(os.path.dirname(os.path.abspath(__file__))), 'sc', 'Windows'))
|
||||
import sc
|
||||
LIBRARY_LOADING = True
|
||||
except:
|
||||
pass
|
||||
|
||||
|
||||
@classmethod
|
||||
def encode(cls, text, mode=0):
|
||||
try:
|
||||
import sc
|
||||
return sc.encode(text, mode)
|
||||
except Exception as e:
|
||||
logger.error(f'Exception:{str(e)}')
|
||||
logger.error(traceback.format_exc())
|
||||
return None
|
||||
|
||||
|
||||
@classmethod
|
||||
def decode(cls, text):
|
||||
try:
|
||||
import sc
|
||||
return sc.decode(text)
|
||||
except:
|
||||
return None
|
||||
|
||||
@classmethod
|
||||
def load_module(cls, module_name, module_code):
|
||||
try:
|
||||
import sc
|
||||
mod = sc.load_module(module_name, module_code)
|
||||
sys.modules[mod] = mod
|
||||
logger.warning(f"C-LOADING : {module_name}")
|
||||
return mod
|
||||
except Exception as e:
|
||||
logger.error(f'Exception:{str(e)}')
|
||||
logger.error(traceback.format_exc())
|
||||
|
||||
@classmethod
|
||||
def load_module_P(cls, plugin_ins, filename):
|
||||
return cls.load_module_f(plugin_ins.setting['filepath'], filename)
|
||||
|
||||
@classmethod
|
||||
def load_module_f(cls, package_filepath, filename):
|
||||
dirname = os.path.dirname(package_filepath)
|
||||
filepath = os.path.join(dirname, filename + '.pyf')
|
||||
if os.path.exists(filepath) and os.path.exists(filepath):
|
||||
from support import SupportFile
|
||||
code = SupportFile.read_file(filepath)
|
||||
return cls.load_module(f"{os.path.basename(dirname)}.{filename}", code)
|
||||
|
||||
@classmethod
|
||||
def td(self, mediacode, ts, url):
|
||||
try:
|
||||
import sc
|
||||
ret = sc.td1(mediacode, str(ts), url).strip()
|
||||
ret = re.sub('[^ -~]+', '', ret).strip()
|
||||
return ret
|
||||
except:
|
||||
return None
|
||||
BIN
lib/support/sc/Windows/sc.cp310-win_amd64.pyd
Normal file
BIN
lib/support/sc/Windows/sc.cp310-win_amd64.pyd
Normal file
Binary file not shown.
@@ -21,6 +21,7 @@ class ModuleSetting(PluginModuleBase):
|
||||
'web_title': 'Home',
|
||||
'use_apikey': 'False',
|
||||
'apikey': ''.join(random.choice(string.ascii_uppercase + string.digits) for _ in range(10)),
|
||||
'app_id': ''.join(random.choice(string.ascii_uppercase + string.digits) for _ in range(10)),
|
||||
f'restart_interval': f'{random.randint(0,59)} {random.randint(1,23)} * * *',
|
||||
'restart_notify': 'False',
|
||||
'theme' : 'Cerulean',
|
||||
|
||||
Reference in New Issue
Block a user