diff --git a/gui.py b/gui.py index ddc3be55..53ba7714 100644 --- a/gui.py +++ b/gui.py @@ -1456,7 +1456,9 @@ class _SettingsVars(TypedDict): proxy: StringVar autostart: IntVar priority_only: IntVar + priority_by_time: IntVar tray_notifications: IntVar + class SettingsPanel: @@ -1471,6 +1473,7 @@ def __init__(self, manager: GUIManager, master: ttk.Widget): "tray": IntVar(master, self._settings.autostart_tray), "autostart": IntVar(master, self._settings.autostart), "priority_only": IntVar(master, self._settings.priority_only), + "priority_by_time": IntVar(master, self._settings.priority_by_time), "tray_notifications": IntVar(master, self._settings.tray_notifications), } master.rowconfigure(0, weight=1) @@ -1528,6 +1531,12 @@ def __init__(self, manager: GUIManager, master: ttk.Widget): ttk.Checkbutton( checkboxes_frame, variable=self._vars["priority_only"], command=self.priority_only ).grid(column=1, row=irow, sticky="w") + ttk.Label( + checkboxes_frame, text=_("gui", "settings", "general", "priority_by_time") + ).grid(column=0, row=(irow := irow + 1), sticky="e") + ttk.Checkbutton( + checkboxes_frame, variable=self._vars["priority_by_time"], command=self.priority_by_time + ).grid(column=1, row=irow, sticky="w") # proxy frame proxy_frame = ttk.Frame(center_frame2) proxy_frame.grid(column=0, row=2) @@ -1740,6 +1749,9 @@ def priority_delete(self) -> None: def priority_only(self) -> None: self._settings.priority_only = bool(self._vars["priority_only"].get()) + def priority_by_time(self) -> None: + self._settings.priority_by_time = bool(self._vars["priority_by_time"].get()) + def exclude_add(self) -> None: game_name: str = self._exclude_entry.get() if not game_name: @@ -2257,6 +2269,7 @@ async def main(exit_event: asyncio.Event): autostart=False, language="English", priority_only=False, + priority_by_time=False, autostart_tray=False, exclude={"Lit Game"}, ) diff --git a/settings.py b/settings.py index 1e0ee1a7..f16f472a 100644 --- a/settings.py +++ b/settings.py @@ -18,6 +18,7 @@ class SettingsFile(TypedDict): exclude: set[str] priority: list[str] priority_only: bool + priority_by_time: bool autostart_tray: bool connection_quality: int tray_notifications: bool @@ -29,6 +30,7 @@ class SettingsFile(TypedDict): "exclude": set(), "autostart": False, "priority_only": True, + "priority_by_time": False, "autostart_tray": False, "connection_quality": 1, "language": DEFAULT_LANG, @@ -52,6 +54,7 @@ class Settings: exclude: set[str] priority: list[str] priority_only: bool + priority_by_time: bool autostart_tray: bool connection_quality: int tray_notifications: bool diff --git a/translate.py b/translate.py index 227c0e8c..4ed76a0b 100644 --- a/translate.py +++ b/translate.py @@ -166,6 +166,7 @@ class GUISettingsGeneral(TypedDict): tray: str tray_notifications: str priority_only: str + priority_by_time: str proxy: str @@ -363,6 +364,7 @@ class Translation(TypedDict): "tray": "Autostart into tray: ", "tray_notifications": "Tray notifications: ", "priority_only": "Priority Only: ", + "priority_by_time": "Prioritize campaigns by end date: ", "proxy": "Proxy (requires restart):", }, "game_name": "Game name", diff --git a/twitch.py b/twitch.py index bd899396..d3059e6c 100644 --- a/twitch.py +++ b/twitch.py @@ -824,19 +824,40 @@ async def _run(self): exclude = self.settings.exclude priority = self.settings.priority priority_only = self.settings.priority_only + priority_by_time = self.settings.priority_by_time next_hour = datetime.now(timezone.utc) + timedelta(hours=1) - for campaign in self.inventory: + campaigns = self.inventory + campaigns.sort(key=lambda c: c.ends_at, reverse=False) # lets us give priority to campaigns ending soonest later on + max_priority = len(campaigns) + max_wanted_priority = max_priority + len(priorities) + for campaign in campaigns: game = campaign.game if ( - game not in self.wanted_games # isn't already there - and game.name not in exclude # and isn't excluded + game not in self.wanted_games # isn't already there + and game.name not in exclude # and isn't excluded # and isn't excluded by priority_only and (not priority_only or game.name in priority) # and can be progressed within the next hour and campaign.can_earn_within(next_hour) ): - # non-excluded games with no priority are placed last, below priority ones - self.wanted_games[game] = priorities.get(game.name, 0) + # get users priority preference + game_priority = priorities.get(game.name, 0) + + if (game_priority): + if (not priority_by_time): + # keep games ordered by priority list + # max_wanted_priority does not change in this case, consider it "0" + self.wanted_games[game] = game_priority + max_wanted_priority + else: + # sort priority games by time ending soonest + # games are already sorted by ends_at, max_wanted_priority only goes down for each added to the wanted_games list + self.wanted_games[game] = max_wanted_priority + max_wanted_priority = max_wanted_priority - 1 + else: + # non-excluded games with no priority are placed last, below priority ones + # but sorted by end time to maximize amount of potential drops + self.wanted_games[game] = max_priority + max_priority = max_priority - 1 full_cleanup = True self.restart_watching() self.change_state(State.CHANNELS_CLEANUP)