Implement exclude argument

This commit is contained in:
DevilXD committed 2022-02-16 13:15:53 +01:00
1 parent fdc9dabd49
commit 83b8de11a1
4 files changed
+81 -32

No files matched your search

+1 -1
View File
@@ -51,7 +51,7 @@
"type": "python", "type": "python",
"request": "launch", "request": "launch",
"program": "main.py", "program": "main.py",
"args": ["--wrong"], "args": ["--excludes", "1", "2", "3"],
"console": "integratedTerminal", "console": "integratedTerminal",
"justMyCode": false "justMyCode": false
}, },
+46 -27
View File
@@ -262,6 +262,7 @@ class GameSelector:
self._list.pack(fill="both", expand=True) self._list.pack(fill="both", expand=True)
self._selection: Optional[str] = self._manager._twitch.options.game self._selection: Optional[str] = self._manager._twitch.options.game
self._games: OrderedDict[str, Game] = OrderedDict() self._games: OrderedDict[str, Game] = OrderedDict()
self._excluded: Set[int] = set()
self._list.bind("<<ListboxSelect>>", self._on_select) self._list.bind("<<ListboxSelect>>", self._on_select)
def set_games(self, games: Iterable[Game]): def set_games(self, games: Iterable[Game]):
@@ -270,30 +271,42 @@ class GameSelector:
self._list.delete(0, "end") self._list.delete(0, "end")
self._list.insert("end", *self._games.keys()) self._list.insert("end", *self._games.keys())
self._list.config(width=0) # autoadjust listbox width self._list.config(width=0) # autoadjust listbox width
if self._selection is not None: # process excluded games and relink the selection
selected_index: Optional[int] = next( self._excluded.clear()
( selected_index: Optional[int] = None
i exclude = self._manager._twitch.options.exclude
for i, str_game in enumerate(self._games.keys()) for i, game_name in enumerate(self._list.get(0, "end")):
if str_game == self._selection if game_name in exclude:
), self._excluded.add(i)
None, self._list.itemconfig(i, foreground="gray60")
) elif game_name == self._selection:
selected_index = i
self._list.selection_clear(0, "end")
if selected_index is not None: if selected_index is not None:
# reselect the currently selected item # reselect the currently selected item
self._list.selection_clear(0, "end")
self._list.selection_set(selected_index) self._list.selection_set(selected_index)
else: elif self._selection is not None:
# the game we've had selected isn't there anymore - clear selection # the game we've had selected isn't there anymore - clear selection
self._selection = None self._selection = None
def _on_select(self, event): def _on_select(self, event):
current = self._list.curselection() current: Tuple[int, ...] = self._list.curselection()
if not current: if not current:
# can happen when the user clicks on an empty list # can happen when the user clicks on an empty list
new_selection = None return
idx: int = current[0]
if idx in self._excluded:
# user clicked on an excluded game - reselect the previous one if possible
self._list.selection_clear(0, "end")
if self._selection is not None:
for i, game_name in enumerate(self._list.get(0, "end")):
if game_name == self._selection:
self._list.selection_set(i)
break
else: else:
new_selection = self._list.get(current[0]) self._selection = None
return
new_selection: str = self._list.get(idx)
if new_selection != self._selection: if new_selection != self._selection:
self._selection = new_selection self._selection = new_selection
self._manager._twitch.change_state(State.GAME_SELECT) self._manager._twitch.change_state(State.GAME_SELECT)
@@ -303,15 +316,15 @@ class GameSelector:
return None return None
return self._games[self._selection] return self._games[self._selection]
def set_first(self) -> Game: def set_first(self) -> Optional[Game]:
# select and return the first game from the list # select and return the first non-excluded game from the list
self._list.selection_clear(0, "end") self._list.selection_clear(0, "end")
self._list.selection_set(0) for i, game_name in enumerate(self._list.get(0, "end")):
for game_name, first_game in self._games.items(): if i not in self._excluded:
# just one iteration to get, set and return the first game
self._selection = game_name self._selection = game_name
return first_game self._list.selection_set(i)
raise RuntimeError("No games to select from") return self._games[game_name]
return None
class _BaseVars(TypedDict): class _BaseVars(TypedDict):
@@ -1028,7 +1041,9 @@ if __name__ == "__main__":
async def main(exit_event: asyncio.Event): async def main(exit_event: asyncio.Event):
# Initialize GUI debug # Initialize GUI debug
mock = SimpleNamespace(options=SimpleNamespace(game=None, tray=False), channels={}) mock = SimpleNamespace(
options=SimpleNamespace(game=None, tray=False, exclude={"Lit Game"}), channels={}
)
mock.change_state = lambda state: mock.gui.print(f"State change: {state.value}") mock.change_state = lambda state: mock.gui.print(f"State change: {state.value}")
mock.state_change = lambda state: partial(mock.change_state, state) mock.state_change = lambda state: partial(mock.change_state, state)
gui = GUIManager(mock) # type: ignore gui = GUIManager(mock) # type: ignore
@@ -1041,19 +1056,21 @@ if __name__ == "__main__":
gui.login.update("Login required", None) gui.login.update("Login required", None)
# Game selector # Game selector
gui.games.set_games([ gui.games.set_games([
create_game(420690, "Lit Game"),
create_game(123456, "Best Game"), create_game(123456, "Best Game"),
# create_game(654321, "My Game Very Long Name"), create_game(654321, "My Game Very Long Name"),
]) ])
# Channel list # Channel list
gui.channels.display( gui.channels.display(
create_channel( create_channel(
name="Thomus", status=0, game=None, drops=False, viewers=0, points=0, priority=True name="Thomus", status=0, game=None, drops=False, viewers=0, points=0, priority=True
) ),
add=True,
) )
channel = create_channel( channel = create_channel(
name="Traitus", status=1, game=None, drops=False, viewers=0, points=0, priority=True name="Traitus", status=1, game=None, drops=False, viewers=0, points=0, priority=True
) )
gui.channels.display(channel) gui.channels.display(channel, add=True,)
gui.channels.set_watching(channel) gui.channels.set_watching(channel)
gui.channels.display( gui.channels.display(
create_channel( create_channel(
@@ -1064,7 +1081,8 @@ if __name__ == "__main__":
viewers=42, viewers=42,
points=1234567, points=1234567,
priority=False, priority=False,
) ),
add=True,
) )
gui.channels.display( gui.channels.display(
create_channel( create_channel(
@@ -1075,7 +1093,8 @@ if __name__ == "__main__":
viewers=69, viewers=69,
points=1234567, points=1234567,
priority=False, priority=False,
) ),
add=True,
) )
gui._root.update() gui._root.update()
gui.channels.get_selection() gui.channels.get_selection()
+33 -2
View File
@@ -9,10 +9,12 @@ import logging
import argparse import argparse
import traceback import traceback
import tkinter as tk import tkinter as tk
from copy import copy
from pathlib import Path from pathlib import Path
from tkinter import messagebox from tkinter import messagebox
from typing import Optional, NoReturn from typing import Optional, Union, Set, NoReturn, Generic
from utils import _T
from twitch import Twitch from twitch import Twitch
from version import __version__ from version import __version__
from exceptions import CaptchaRequired from exceptions import CaptchaRequired
@@ -41,12 +43,40 @@ class Parser(argparse.ArgumentParser):
messagebox.showerror("Argument Parser Error", self._message.getvalue()) messagebox.showerror("Argument Parser Error", self._message.getvalue())
class SetCollectAction(argparse.Action, Generic[_T]):
def __init__(
self,
option_strings,
dest,
*,
nargs: Optional[Union[int, str]] = None,
const: Optional[_T] = None,
default: Optional[Set[_T]] = None,
**kwargs,
) -> None:
if nargs is not None and nargs in ('?', '*') or isinstance(nargs, int) and nargs <= 0:
raise ValueError("'nargs' has to be '+' or an integer greater than zero")
if default is None:
default = set()
elif not isinstance(default, set):
raise TypeError("'default' has to be of 'set' type")
super().__init__(option_strings, dest, nargs, const, default, **kwargs)
def __call__(self, parser, namespace, values, option_string=None):
items: Set[_T] = getattr(namespace, self.dest, self.default)
items = copy(items)
for value in values:
items.add(value)
setattr(namespace, self.dest, items)
class ParsedArgs(argparse.Namespace): class ParsedArgs(argparse.Namespace):
_verbose: int _verbose: int
_debug_ws: bool _debug_ws: bool
_debug_gql: bool _debug_gql: bool
log: bool log: bool
tray: bool tray: bool
exclude: Set[str]
no_run_check: bool no_run_check: bool
game: Optional[str] game: Optional[str]
@@ -90,9 +120,10 @@ parser = Parser(
) )
parser.add_argument("--version", action="version", version=f"v{__version__}") parser.add_argument("--version", action="version", version=f"v{__version__}")
parser.add_argument("-v", dest="_verbose", action="count", default=0) parser.add_argument("-v", dest="_verbose", action="count", default=0)
parser.add_argument("-g", "--game", default=None)
parser.add_argument("--tray", action="store_true") parser.add_argument("--tray", action="store_true")
parser.add_argument("--log", action="store_true") parser.add_argument("--log", action="store_true")
parser.add_argument("-g", "--game", default=None)
parser.add_argument("--exclude", action=SetCollectAction, nargs='+', metavar="GAME")
# undocumented debug args # undocumented debug args
parser.add_argument( parser.add_argument(
"--no-run-check", dest="no_run_check", action="store_true", help=argparse.SUPPRESS "--no-run-check", dest="no_run_check", action="store_true", help=argparse.SUPPRESS
+1 -2
View File
@@ -180,7 +180,6 @@ class Twitch:
WebsocketTopic("User", "CommunityPoints", self._user_id, self.process_points), WebsocketTopic("User", "CommunityPoints", self._user_id, self.process_points),
]) ])
first_select: bool = True first_select: bool = True
games: List[Game] = []
full_cleanup: bool = False full_cleanup: bool = False
channels: Final[OrderedDict[int, Channel]] = self.channels channels: Final[OrderedDict[int, Channel]] = self.channels
self.change_state(State.INVENTORY_FETCH) self.change_state(State.INVENTORY_FETCH)
@@ -193,7 +192,7 @@ class Twitch:
self.change_state(State.GAMES_UPDATE) self.change_state(State.GAMES_UPDATE)
elif self._state is State.GAMES_UPDATE: elif self._state is State.GAMES_UPDATE:
# Figure out which games to watch, and claim the drops we can # Figure out which games to watch, and claim the drops we can
games.clear() games: List[Game] = []
for game, campaigns in self.inventory.items(): for game, campaigns in self.inventory.items():
add_game = False add_game = False
for campaign in campaigns: for campaign in campaigns: