|
| 1 | +import os |
| 2 | +import sys |
| 3 | +import json |
| 4 | +import threading |
| 5 | +import time |
| 6 | + |
| 7 | +from NotionDump import NotionBackupLogger |
| 8 | +from api.configuration import CONFIG_FILE_PATH, Configuration |
| 9 | +from api.notion_dump import NotionBackup |
| 10 | + |
| 11 | +from flask import Flask, render_template, send_from_directory, request |
| 12 | +from flask_bootstrap import Bootstrap |
| 13 | + |
| 14 | +app = Flask(__name__, template_folder='templates', static_folder='static//') |
| 15 | +app.config['SECRET_KEY'] = 'delta1037@qq.com' |
| 16 | +app.config['BOOTSTRAP_SERVE_LOCAL'] = True |
| 17 | +bootstrap = Bootstrap(app) |
| 18 | + |
| 19 | +SEVER_ABS_PATH = os.path.dirname(sys.argv[0]) |
| 20 | +LOG_FILE = SEVER_ABS_PATH + "/dump.log" |
| 21 | + |
| 22 | + |
| 23 | +class NotionBackupGUI(NotionBackupLogger): |
| 24 | + def __init__(self): |
| 25 | + super().__init__() |
| 26 | + self.__notion_backup = None |
| 27 | + # 日志文件句柄 |
| 28 | + self.__log = open(LOG_FILE, "a+", encoding='utf-8') |
| 29 | + # 输出备份的时间 |
| 30 | + self.backup_time = time.strftime('backup_time: %Y-%m-%d %H:%M:%S\n', time.localtime(time.time())) |
| 31 | + self.__log.write("\n###################################################\n") |
| 32 | + self.__log.write(self.backup_time + "\n") |
| 33 | + self.__log.flush() |
| 34 | + # 增量输出内容,给前端用的 |
| 35 | + self.__mutex = threading.Lock() |
| 36 | + self.__append_buffer = "" |
| 37 | + |
| 38 | + def log_debug(self, log_str): |
| 39 | + self.log_info(log_str) |
| 40 | + |
| 41 | + def log_info(self, message): |
| 42 | + self.log("[EXPORT KERNEL] " + str(message)) |
| 43 | + |
| 44 | + def log(self, msg): |
| 45 | + # 文件输出 |
| 46 | + self.__log.write(msg + "\n") |
| 47 | + self.__log.flush() |
| 48 | + |
| 49 | + # 窗口输出 |
| 50 | + self.__mutex.acquire() |
| 51 | + self.__append_buffer += (str(msg) + "\n") |
| 52 | + self.__mutex.release() |
| 53 | + |
| 54 | + def init_process(self, config_handle): |
| 55 | + # dump api |
| 56 | + self.__notion_backup = NotionBackup(logger=self, config=config_handle) |
| 57 | + |
| 58 | + def start_process(self): |
| 59 | + # 转入后台执行 |
| 60 | + self.log(self.backup_time) |
| 61 | + self.__notion_backup.start_dump(force_auto=True) |
| 62 | + |
| 63 | + def get_append_log(self): |
| 64 | + self.__mutex.acquire() |
| 65 | + ret_str = self.__append_buffer |
| 66 | + self.__append_buffer = "" |
| 67 | + self.__mutex.release() |
| 68 | + # print("//trans", ret_str, "##trans", len(ret_str)) |
| 69 | + return ret_str |
| 70 | + |
| 71 | + |
| 72 | +# 初始化控制程序 |
| 73 | +gui = NotionBackupGUI() |
| 74 | +config = Configuration(CONFIG_FILE_PATH, gui) |
| 75 | +gui.init_process(config) |
| 76 | + |
| 77 | + |
| 78 | +@app.route('/', methods=['GET', 'POST']) |
| 79 | +def index(): |
| 80 | + # 默认返回主界面渲染 |
| 81 | + return render_main() |
| 82 | + |
| 83 | + |
| 84 | +# 基本设置界面 |
| 85 | +@app.route('/setting_base', methods=['GET', 'POST']) |
| 86 | +def render_setting_base(): |
| 87 | + backup_type = config.get_key("*backup_type") |
| 88 | + return render_template( |
| 89 | + 'index.html', |
| 90 | + main_content=render_template( |
| 91 | + 'setting_base.html', |
| 92 | + backup_root_path=config.get_key("backup_root_path", default=""), |
| 93 | + display_rowss=["单页面备份", "多页面备份"], |
| 94 | + # 单页面配置 |
| 95 | + display_rows_choose=("单页面备份" if backup_type == "single" else "多页面备份"), |
| 96 | + single_readonly_token=config.get_key("*backup_token", prefix="single"), |
| 97 | + single_page_id=config.get_key("*page_id", prefix="single"), |
| 98 | + single_page_types=["Page-ID是页面类型的", "Database-ID是数据库页面类型的"], |
| 99 | + single_page_type_choose=("Page-ID是页面类型的" if config.get_key("-page_type", prefix="single") == "page" else "Database-ID是数据库页面类型的"), |
| 100 | + single_dump_path=config.get_key("-dump_path", prefix="single"), |
| 101 | + database_insert_types=["Content-内容嵌入", "Link-链接嵌入"], |
| 102 | + database_insert_type_choose=("Content-内容嵌入" if config.get_key("db_insert_type", prefix="single") == "content" else "Link-链接嵌入"), |
| 103 | + # 多页面配置 |
| 104 | + multi_readonly_token=config.get_key("*backup_token", prefix="multi"), |
| 105 | + multi_rw_token=config.get_key("*backup_info_token", prefix="multi"), |
| 106 | + multi_page_id=config.get_key("*backup_list_id", prefix="multi"), |
| 107 | + multi_log_id=config.get_key("*backup_log_id", prefix="multi"), |
| 108 | + ) |
| 109 | + ) |
| 110 | + |
| 111 | + |
| 112 | +# 基本设置 确认请求 |
| 113 | +@app.route('/setting_base_ack', methods=['GET', 'POST']) |
| 114 | +def setting_base_ack(): |
| 115 | + setting_base_json = json.loads(request.data) |
| 116 | + # print(setting_base_json) |
| 117 | + config.alt_key("backup_root_path", setting_base_json["backup_root_path"]) |
| 118 | + if setting_base_json["display_type"] != "多页面备份": |
| 119 | + config.alt_key("*backup_type", "single") |
| 120 | + config.alt_key("*backup_token", setting_base_json["single_readonly_token"], prefix="single") |
| 121 | + config.alt_key("*page_id", setting_base_json["single_page_id"], prefix="single") |
| 122 | + if "Page-" in setting_base_json["single_page_type"]: |
| 123 | + config.alt_key("-page_type", "page", prefix="single") |
| 124 | + else: |
| 125 | + config.alt_key("-page_type", "database", prefix="single") |
| 126 | + config.alt_key("-dump_path", setting_base_json["single_dump_path"], prefix="single") |
| 127 | + if "Content-" in setting_base_json["database_insert_type"]: |
| 128 | + config.alt_key("db_insert_type", "content", prefix="single") |
| 129 | + else: |
| 130 | + config.alt_key("db_insert_type", "link", prefix="single") |
| 131 | + else: |
| 132 | + config.alt_key("*backup_type", "multi") |
| 133 | + config.alt_key("*backup_token", setting_base_json["multi_readonly_token"], prefix="multi") |
| 134 | + config.alt_key("*backup_info_token", setting_base_json["multi_rw_token"], prefix="multi") |
| 135 | + config.alt_key("*backup_list_id", setting_base_json["multi_page_id"], prefix="multi") |
| 136 | + config.alt_key("*backup_log_id", setting_base_json["multi_log_id"], prefix="multi") |
| 137 | + return "" |
| 138 | + |
| 139 | + |
| 140 | +# 基本设置 取消请求 |
| 141 | +@app.route('/setting_base_cancel', methods=['GET', 'POST']) |
| 142 | +def setting_base_cancel(): |
| 143 | + ret_map = { |
| 144 | + "display_type": ("单页面备份" if config.get_key("*backup_type") == "single" else "多页面备份") |
| 145 | + } |
| 146 | + if ret_map["display_type"] != "多页面备份": |
| 147 | + ret_map["single_readonly_token"] = config.get_key("*backup_token", prefix="single") |
| 148 | + ret_map["single_page_id"] = config.get_key("*page_id", prefix="single") |
| 149 | + ret_map["single_page_type_choose"] = ("Page-ID是页面类型的" if config.get_key("-page_type", prefix="single") == "page" else "Database-ID是数据库页面类型的") |
| 150 | + ret_map["single_dump_path"] = config.get_key("-dump_path", prefix="single") |
| 151 | + ret_map["database_insert_type_choose"] = ("Content-内容嵌入" if config.get_key("db_insert_type", prefix="single") == "content" else "Link-链接嵌入") |
| 152 | + else: |
| 153 | + ret_map["multi_readonly_token"] = config.get_key("*backup_token", prefix="multi") |
| 154 | + ret_map["multi_rw_token"] = config.get_key("*backup_info_token", prefix="multi") |
| 155 | + ret_map["multi_page_id"] = config.get_key("*backup_list_id", prefix="multi") |
| 156 | + ret_map["multi_log_id"] = config.get_key("*backup_log_id", prefix="multi") |
| 157 | + return ret_map |
| 158 | + |
| 159 | + |
| 160 | +# 开发设置界面 |
| 161 | +@app.route('/setting_dev', methods=['GET', 'POST']) |
| 162 | +def render_setting_dev(): |
| 163 | + backup_list_map = config.get_key("backup_list_map", prefix="multi") |
| 164 | + backup_log_map = config.get_key("backup_log_map", prefix="multi") |
| 165 | + # 主题名称转换 |
| 166 | + color_theme_type_choose = "自定义" |
| 167 | + if config.get_key("color_theme") == "dark": |
| 168 | + color_theme_type_choose = "暗黑" |
| 169 | + elif config.get_key("color_theme") == "light": |
| 170 | + color_theme_type_choose = "明亮" |
| 171 | + # 主题文字背景属性 |
| 172 | + color_map = config.get_key("your_color_theme") |
| 173 | + b_types = [] |
| 174 | + f_types = [] |
| 175 | + d_types = [] |
| 176 | + for color_name in color_map: |
| 177 | + if color_name.startswith("b_"): |
| 178 | + b_types.append({ |
| 179 | + "name": color_name[color_name.find("_")+1:], |
| 180 | + "id_name": color_name, |
| 181 | + "color": color_map[color_name] |
| 182 | + }) |
| 183 | + elif color_name.startswith("f_"): |
| 184 | + f_types.append({ |
| 185 | + "name": color_name[color_name.find("_")+1:], |
| 186 | + "id_name": color_name, |
| 187 | + "color": color_map[color_name] |
| 188 | + }) |
| 189 | + elif color_name.startswith("d_"): |
| 190 | + d_types.append({ |
| 191 | + "name": color_name[color_name.find("_")+1:], |
| 192 | + "id_name": color_name, |
| 193 | + "color": color_map[color_name] |
| 194 | + }) |
| 195 | + |
| 196 | + return render_template( |
| 197 | + 'index.html', |
| 198 | + main_content=render_template( |
| 199 | + 'setting_dev.html', |
| 200 | + # checkbox信息 |
| 201 | + debug=("true" if config.get_key("debug") else "false"), |
| 202 | + page_properties=("true" if config.get_key("page_properties") else "false"), |
| 203 | + use_buffer=("true" if config.get_key("use_buffer") else "false"), |
| 204 | + file_with_link=("true" if config.get_key("file_with_link") else "false"), |
| 205 | + # 日期信息 |
| 206 | + date_formate=config.get_key("date_formate"), |
| 207 | + datetime_formate=config.get_key("datetime_formate"), |
| 208 | + # 主题选择 |
| 209 | + color_theme_types=["明亮", "暗黑", "自定义"], |
| 210 | + color_theme_type_choose=color_theme_type_choose, |
| 211 | + b_types=b_types, |
| 212 | + f_types=f_types, |
| 213 | + d_types=d_types, |
| 214 | + # 多页面配置页面列名映射表 |
| 215 | + page_id=backup_list_map["page_id"], |
| 216 | + page_type=backup_list_map["page_type"], |
| 217 | + dump_path=backup_list_map["dump_path"], |
| 218 | + db_insert_type=backup_list_map["db_insert_type"], |
| 219 | + dump_status=backup_list_map["dump_status"], |
| 220 | + title=backup_log_map["title"], |
| 221 | + date=backup_log_map["date"], |
| 222 | + status=backup_log_map["status"], |
| 223 | + log=backup_log_map["log"], |
| 224 | + ) |
| 225 | + ) |
| 226 | + |
| 227 | + |
| 228 | +# 开发设置 确认请求 |
| 229 | +@app.route('/setting_dev_ack', methods=['GET', 'POST']) |
| 230 | +def setting_dev_ack(): |
| 231 | + setting_dev_json = json.loads(request.data) |
| 232 | + # print(setting_dev_json) |
| 233 | + |
| 234 | + # checkbox信息 |
| 235 | + config.alt_key("debug", setting_dev_json["debug"]) |
| 236 | + config.alt_key("use_buffer", setting_dev_json["use_buffer"]) |
| 237 | + config.alt_key("page_properties", setting_dev_json["page_properties"]) |
| 238 | + config.alt_key("file_with_link", setting_dev_json["file_with_link"]) |
| 239 | + # 日期格式 |
| 240 | + config.alt_key("date_formate", setting_dev_json["date_formate"]) |
| 241 | + config.alt_key("datetime_formate", setting_dev_json["datetime_formate"]) |
| 242 | + # 主题 |
| 243 | + if setting_dev_json["theme_type"] == "明亮": |
| 244 | + config.alt_key("color_theme", "light") |
| 245 | + elif setting_dev_json["theme_type"] == "暗黑": |
| 246 | + config.alt_key("color_theme", "dark") |
| 247 | + else: |
| 248 | + config.alt_key("color_theme", "your_color_theme") |
| 249 | + for key in setting_dev_json: |
| 250 | + if key.startswith("b_") or key.startswith("f_") or key.startswith("d_"): |
| 251 | + config.alt_key(key, setting_dev_json[key], prefix="your_color_theme") |
| 252 | + |
| 253 | + # 备份映射表 |
| 254 | + backup_list_map = { |
| 255 | + "page_id": setting_dev_json["page_id"], |
| 256 | + "page_type": setting_dev_json["page_type"], |
| 257 | + "dump_path": setting_dev_json["dump_path"], |
| 258 | + "dump_status": setting_dev_json["dump_status"], |
| 259 | + "db_insert_type": setting_dev_json["db_insert_type"], |
| 260 | + } |
| 261 | + backup_log_map = { |
| 262 | + "title": setting_dev_json["title"], |
| 263 | + "date": setting_dev_json["date"], |
| 264 | + "status": setting_dev_json["status"], |
| 265 | + "log": setting_dev_json["log"], |
| 266 | + } |
| 267 | + config.alt_key("backup_list_map", backup_list_map, prefix="multi") |
| 268 | + config.alt_key("backup_log_map", backup_log_map, prefix="multi") |
| 269 | + return "" |
| 270 | + |
| 271 | + |
| 272 | +@app.route('/donate', methods=['GET', 'POST']) |
| 273 | +def render_donate(): |
| 274 | + return render_template( |
| 275 | + 'index.html', |
| 276 | + main_content=render_template( |
| 277 | + 'donate.html', |
| 278 | + ) |
| 279 | + ) |
| 280 | + |
| 281 | + |
| 282 | +@app.route('/tutorial', methods=['GET', 'POST']) |
| 283 | +def render_tutorial(): |
| 284 | + return render_template( |
| 285 | + 'index.html', |
| 286 | + main_content=render_template( |
| 287 | + 'tutorial.html', |
| 288 | + ) |
| 289 | + ) |
| 290 | + |
| 291 | + |
| 292 | +# 主界面 |
| 293 | +@app.route('/main', methods=['GET', 'POST']) |
| 294 | +def render_main(): |
| 295 | + return render_template( |
| 296 | + 'index.html', |
| 297 | + main_content=render_template( |
| 298 | + 'backup.html' |
| 299 | + ) |
| 300 | + ) |
| 301 | + |
| 302 | + |
| 303 | +@app.route('/start_export', methods=['GET', 'POST']) |
| 304 | +def start_export(): |
| 305 | + gui.start_process() |
| 306 | + return "" |
| 307 | + |
| 308 | + |
| 309 | +@app.route('/get_msg', methods=['GET', 'POST']) |
| 310 | +def get_msg(): |
| 311 | + return gui.get_append_log() |
| 312 | + # return "msg test" |
| 313 | + |
| 314 | + |
| 315 | +@app.errorhandler(404) |
| 316 | +def page_not_found(e): |
| 317 | + return render_template("index.html", main_content=render_template("error_404.html")), 404 |
| 318 | + |
| 319 | + |
| 320 | +@app.errorhandler(500) |
| 321 | +def page_not_found(e): |
| 322 | + return render_template("index.html", main_content=render_template("error_500.html")), 500 |
| 323 | + |
| 324 | + |
| 325 | +@app.route('/favicon.ico') |
| 326 | +def favicon(): |
| 327 | + return send_from_directory(os.path.join(app.root_path, 'static'), 'favicon.ico') |
| 328 | + |
| 329 | + |
| 330 | +@app.route('/local_static/<path:filename>') |
| 331 | +def local_static(filename): |
| 332 | + return send_from_directory(os.path.join(app.root_path, 'static'), filename) |
0 commit comments