From 95a7d9a0330395ef87d9dcc0cf116f2e51870e26 Mon Sep 17 00:00:00 2001 From: javara999 Date: Fri, 29 May 2026 08:30:08 +0900 Subject: [PATCH] Align scheduler with FlaskFarm module flow --- logic.py | 67 ++++++++++--------------- templates/ff_freegame_main_setting.html | 13 ++--- 2 files changed, 34 insertions(+), 46 deletions(-) diff --git a/logic.py b/logic.py index 71d8d5f..a91b805 100644 --- a/logic.py +++ b/logic.py @@ -6,7 +6,7 @@ from datetime import datetime import requests from flask import jsonify, render_template from plugin import PluginModuleBase -from framework import F, Job, scheduler +from framework import F from .model import ModelFetchLog, ModelFreeGameItem, ModelSetting from . import scraper @@ -15,7 +15,6 @@ from .setup import P logger = P.logger package_name = P.package_name -job_id = f"{package_name}_fetch" _fetch_lock = threading.Lock() SOURCE_LABELS = { @@ -99,6 +98,8 @@ def _telegram_send(bot_token, chat_id, games): class Logic(PluginModuleBase): db_default = { + "main_auto_start": "False", + "main_interval": "0 */2 * * *", "auto_start": "False", "auto_interval": "0 */2 * * *", "notify_discord_webhook": "", @@ -116,18 +117,24 @@ class Logic(PluginModuleBase): } def __init__(self, PM): - super().__init__(PM, name="main", first_menu="setting") + super().__init__(PM, name="main", first_menu="setting", scheduler_desc="FreeGame fetch") def plugin_load(self): + self._migrate_scheduler_settings() ModelFreeGameItem.ensure_schema() - if _truthy(ModelSetting.get("auto_start")): - self.scheduler_start() + + def _migrate_scheduler_settings(self): + legacy_interval = str(ModelSetting.get("auto_interval") or "").strip() + if legacy_interval and str(ModelSetting.get("main_interval") or "").strip() in ["", "0 */2 * * *"]: + ModelSetting.set("main_interval", legacy_interval) + if _truthy(ModelSetting.get("auto_start")) and not _truthy(ModelSetting.get("main_auto_start")): + ModelSetting.set("main_auto_start", "True") def process_menu(self, sub, req): arg = ModelSetting.to_dict() arg["package_name"] = package_name - arg["scheduler"] = str(F.scheduler.is_include(job_id)) - arg["is_running"] = str(F.scheduler.is_running(job_id)) + arg["scheduler"] = str(F.scheduler.is_include(self.get_scheduler_name())) + arg["is_running"] = str(F.scheduler.is_running(self.get_scheduler_name())) arg["source_labels"] = SOURCE_LABELS arg["platform_counts"] = ModelFreeGameItem.get_platform_counts() if sub == "list": @@ -140,21 +147,17 @@ class Logic(PluginModuleBase): try: if sub == "setting_save": ret, _ = ModelSetting.setting_save(req) - if F.scheduler.is_include(job_id): - Logic.scheduler_stop() - Logic.scheduler_start() - elif _truthy(ModelSetting.get("auto_start")): - Logic.scheduler_start() + self.setting_save_after(None) ret["ret"] = "success" return jsonify(ret) if sub == "scheduler_toggle": if req.form["scheduler"] == "true": - Logic.scheduler_start() + self.P.logic.scheduler_start(self.name) else: - Logic.scheduler_stop() + self.P.logic.scheduler_stop(self.name) return jsonify({"ret": "success"}) if sub == "execute_once": - threading.Thread(target=Logic.scheduler_function, daemon=True).start() + threading.Thread(target=self.scheduler_function, daemon=True).start() return jsonify({"ret": "success"}) if sub == "web_list": ModelFreeGameItem.ensure_schema() @@ -167,29 +170,14 @@ class Logic(PluginModuleBase): logger.error(traceback.format_exc()) return jsonify({"ret": "error", "log": str(e)}) - @staticmethod - def scheduler_start(): - try: - interval = ModelSetting.get("auto_interval") or "0 */2 * * *" - if F.scheduler.is_include(job_id): - scheduler.remove_job(job_id) - job = Job(package_name, job_id, interval, Logic.scheduler_function, "FreeGame fetch", True) - scheduler.add_job_instance(job) - logger.info("FreeGame scheduler registered: id=%s interval=%s", job_id, interval) - except Exception as e: - logger.error("Exception:%s", e) - logger.error(traceback.format_exc()) + def setting_save_after(self, change_list): + if F.scheduler.is_include(self.get_scheduler_name()): + self.P.logic.scheduler_stop(self.name) + self.P.logic.scheduler_start(self.name) + elif _truthy(ModelSetting.get("main_auto_start")): + self.P.logic.scheduler_start(self.name) - @staticmethod - def scheduler_stop(): - try: - scheduler.remove_job(job_id) - except Exception as e: - logger.error("Exception:%s", e) - logger.error(traceback.format_exc()) - - @staticmethod - def scheduler_function(): + def scheduler_function(self): if not _fetch_lock.acquire(blocking=False): logger.info("FreeGame fetch skipped: already running") return @@ -221,7 +209,7 @@ class Logic(PluginModuleBase): logger.info("FreeGame fetch completed: free_candidates=%d enabled_sources=%d", len(fresh_free_games), len(enabled_sources)) ModelFetchLog("all", "ok", f"free_candidates={len(fresh_free_games)} enabled_sources={len(enabled_sources)}", len(fresh_free_games)).save() ModelSetting.set("last_fetch_finished", datetime.now().strftime("%Y-%m-%d %H:%M:%S")) - Logic._notify(fresh_free_games) + self._notify(fresh_free_games) except Exception as e: logger.error("Exception:%s", e) logger.error(traceback.format_exc()) @@ -229,8 +217,7 @@ class Logic(PluginModuleBase): finally: _fetch_lock.release() - @staticmethod - def _notify(games): + def _notify(self, games): if _truthy(ModelSetting.get("notify_enabled")) is False: return targets = list(games or []) diff --git a/templates/ff_freegame_main_setting.html b/templates/ff_freegame_main_setting.html index 0adb5c0..cd9aaa6 100644 --- a/templates/ff_freegame_main_setting.html +++ b/templates/ff_freegame_main_setting.html @@ -3,8 +3,8 @@
{{ macros.m_button_group([['globalSettingSaveBtn', '설정 저장']]) }}
- {{ macros.setting_input_text('auto_interval', '수집 주기', value=arg.get('auto_interval', '0 */2 * * *'), desc=['기본값: 2시간마다', '크론 표현식 사용']) }} - {{ macros.setting_checkbox('auto_start', '시작 시 자동 스케줄 등록', value=arg.get('auto_start', 'False')) }} + {{ macros.setting_input_text('main_interval', '수집 주기', value=arg.get('main_interval', '0 */2 * * *'), desc=['기본값: 2시간마다', '크론 표현식 사용']) }} + {{ macros.setting_checkbox('main_auto_start', '시작 시 자동 스케줄 등록', value=arg.get('main_auto_start', 'False')) }} {{ macros.global_setting_scheduler_button(arg['scheduler'], arg['is_running']) }} {{ macros.setting_buttons([['ff_freegame_execute_btn', '1회 실행']], left='수동 실행') }} {{ macros.info_text('last_fetch_started', '최근 수집 시작', value=arg.get('last_fetch_started', '')) }} @@ -15,7 +15,7 @@ {{ macros.setting_input_text('notify_telegram_bot_token', 'Telegram Bot Token', value=arg.get('notify_telegram_bot_token', '')) }} {{ macros.setting_input_text('notify_telegram_chat_id', 'Telegram Chat ID', value=arg.get('notify_telegram_chat_id', '')) }} {{ macros.m_hr() }} - {{ macros.info_text('source_help', '활성 소스', value='체크된 무료 소스만 저장/표시됩니다.') }} + {{ macros.info_text('source_help', '활성 소스', value='체크한 무료 소스만 저장/표시합니다.') }} {{ macros.setting_checkbox('source_epic_enabled', 'Epic', value=arg.get('source_epic_enabled', 'True')) }} {{ macros.setting_checkbox('source_steam_enabled', 'Steam', value=arg.get('source_steam_enabled', 'True')) }} {{ macros.setting_checkbox('source_gog_enabled', 'GOG', value=arg.get('source_gog_enabled', 'True')) }} @@ -30,9 +30,9 @@ const package_name = "{{ arg['package_name'] }}"; $("body").on("change", "#globalSchedulerSwitchBtn", function () { $.ajax({ - url: `/${package_name}/ajax/scheduler_toggle`, + url: `/${package_name}/ajax/scheduler`, type: "POST", - data: { scheduler: $(this).prop("checked") }, + data: { sub: "main", scheduler: $(this).prop("checked") }, dataType: "json", }); }); @@ -40,8 +40,9 @@ $("body").on("change", "#globalSchedulerSwitchBtn", function () { $("body").on("click", "#ff_freegame_execute_btn", function (e) { e.preventDefault(); $.ajax({ - url: `/${package_name}/ajax/execute_once`, + url: `/${package_name}/ajax/one_execute`, type: "POST", + data: { sub: "main" }, dataType: "json", success: function (ret) { if (ret.ret === "success") {