diff --git a/README.md b/README.md index cd0bd55..fb4e2e3 100644 --- a/README.md +++ b/README.md @@ -19,12 +19,49 @@ with [pipx](https://pipx.pypa.io/stable/installation/): pipx install --extra-index-url https://gitea.parano.ch/api/packages/herel/pypi/simple/ myice ``` +## configuration + +Create a `myice.ini` file with your credentials: + +```ini +[default] +username = your_email@example.com +password = your_password +userid = 12345 +token = your_api_token +club_id = 172 +``` + +You can also create multiple sections for different users: + +```ini +[default] +username = user1@example.com +password = password1 +userid = 12345 +token = token1 +club_id = 172 + +[isaac] +username = isaac@example.com +password = password2 +userid = 67890 +token = token2 +club_id = 186 +``` + ## récupérer le schedule ```shell myice schedule -o schedule.json ``` +To use a specific configuration section: + +```shell +myice schedule -o schedule.json --config-section isaac +``` + ## data ### listing @@ -67,6 +104,12 @@ Opening file game_117015.pdf ``` +To use a specific configuration section: + +```shell +❯ myice game 117015 --config-section isaac +``` + ### entraînement et pour la convoc d'un entraînement: @@ -77,6 +120,12 @@ Opening file practice_561855.pdf ``` +To use a specific configuration section: + +```shell +❯ myice practice 561855 --config-section isaac +``` + ### AI ```text @@ -86,3 +135,9 @@ Opening file practice_561855.pdf > et les u13 a ? < Le prochain match de l'équipe U13 A se déroulera le samedi 9 novembre 2024 contre HC Vallorbe à P. du Frézillon, 1337 Vallorbe VD. Le match débutera à 13h00 et se terminera à 15h00. Le prochain match à domicile de l'équipe U13 A se déroulera le dimanche 10 novembre 2024 contre CP Meyrin à Les Vernets, Glace extérieure, 1227 Les Acacias GE. Le match débutera à 13h00 et se terminera à 15h00. ``` + +To use a specific configuration section: + +```shell +❯ myice ai --config-section isaac +``` diff --git a/myice/myice.py b/myice/myice.py index 6bd50fc..8c64989 100755 --- a/myice/myice.py +++ b/myice/myice.py @@ -165,6 +165,7 @@ def save_cookies(file: str = "cookies.txt"): def get_login( local_file: str = "myice.ini", + config_section: str = "default", ) -> tuple[str, str, int | None, str | None, int | None]: config = configparser.ConfigParser() config.read( @@ -174,22 +175,29 @@ def get_login( local_file, ] ) - if "default" in config.sections(): - default_config = config["default"] - - username = default_config.get("username") - password = default_config.get("password") - userid = default_config.getint("userid") - token = default_config.get("token") - club_id = default_config.getint("club_id") - if not username or not password: - print( - "Error: please configure username/password in ini file", file=sys.stderr - ) - sys.exit(1) + if config_section in config.sections(): + selected_config = config[config_section] + elif "default" in config.sections(): + # Fallback to default section if specified section doesn't exist + selected_config = config["default"] + print( + f"Warning: Section '{config_section}' not found, using 'default' section", + file=sys.stderr, + ) else: print("Error: please configure username/password in ini file", file=sys.stderr) sys.exit(1) + + username = selected_config.get("username") + password = selected_config.get("password") + userid = selected_config.getint("userid", fallback=None) + token = selected_config.get("token", fallback=None) + club_id = selected_config.getint("club_id", fallback=None) + + if not username or not password: + print("Error: please configure username/password in ini file", file=sys.stderr) + sys.exit(1) + return username, password, userid, token, club_id @@ -202,10 +210,14 @@ def select_club(club_id: int = 172): r.raise_for_status() -def do_login(): +def do_login(config_section: str = "default"): global session global userid - username, password, userid, token, club_id = get_login() + username, password, userid_tmp, token, club_id = get_login( + config_section=config_section + ) + if userid_tmp is not None: + userid = userid_tmp r = session.get("https://app.myice.hockey/", headers={"User-Agent": user_agent}) r.raise_for_status() form_data = { @@ -225,7 +237,8 @@ def do_login(): ) r.raise_for_status() # select the club we want - select_club(club_id) + if club_id: + select_club(club_id) def get_userid(): @@ -249,15 +262,18 @@ def get_userid(): def wrapper_session(func): def wrapper(*args, **kwargs): global session, userid + # Extract config_section from kwargs if present + config_section = kwargs.get("config_section", "default") + session = requests.Session() # session.verify = False session.cookies = load_cookies() session.cookies.clear_expired_cookies() if not session.cookies.get("mih_v3_cookname"): print("login...", file=sys.stderr) - do_login() + do_login(config_section=config_section) save_cookies() - _, _, userid, _, _ = get_login() + _, _, userid, _, _ = get_login(config_section=config_section) if not userid: print("get userid...", file=sys.stderr) userid = get_userid() @@ -267,7 +283,7 @@ def wrapper_session(func): @wrapper_session -def get_schedule(num_days: int) -> str: +def get_schedule(num_days: int, config_section: str = "default") -> str: global session global userid assert session and userid @@ -298,7 +314,7 @@ def get_schedule(num_days: int) -> str: @wrapper_session -def game_pdf(gameid: int, outfile: Path): +def game_pdf(gameid: int, outfile: Path, config_section: str = "default"): global session, userid assert session and userid r = session.get( @@ -315,7 +331,7 @@ def game_pdf(gameid: int, outfile: Path): @wrapper_session -def practice_pdf(gameid: int, outfile: Path): +def practice_pdf(gameid: int, outfile: Path, config_section: str = "default"): global session, userid assert session and userid r = session.get( @@ -340,11 +356,17 @@ def schedule( ), ] = None, num_days: Annotated[int, typer.Option("--days")] = 7, + config_section: Annotated[ + str, + typer.Option( + "--config-section", "-c", help="Configuration section to use from INI file" + ), + ] = "default", ): """ Fetch schedule as json """ - schedule = get_schedule(num_days) + schedule = get_schedule(num_days, config_section=config_section) # Sanitize the JSON response using our proven approach sanitized_schedule = sanitize_json_response(schedule) if outfile: @@ -383,6 +405,12 @@ def extract_players(pdf_file: Path) -> List[str]: def get_game_pdf( game_id: Annotated[int, typer.Argument(help="ID of game to gen pdf for")], open_file: Annotated[bool, typer.Option("--open", "-o")] = False, + config_section: Annotated[ + str, + typer.Option( + "--config-section", "-c", help="Configuration section to use from INI file" + ), + ] = "default", ): """ Genate the pdf for the game invitation @@ -391,7 +419,7 @@ def get_game_pdf( output_filename = f"game_{game_id}.pdf" else: output_filename = tempfile.NamedTemporaryFile().name - game_pdf(game_id, Path(output_filename)) + game_pdf(game_id, Path(output_filename), config_section=config_section) if open_file: os_open(output_filename) else: @@ -403,12 +431,18 @@ def get_game_pdf( @app.command("practice") def get_practice_pdf( game_id: Annotated[int, typer.Argument(help="ID of practice to gen pdf for")], + config_section: Annotated[ + str, + typer.Option( + "--config-section", "-c", help="Configuration section to use from INI file" + ), + ] = "default", ): """ Genate the pdf for the practice invitation """ output_filename = f"practice_{game_id}.pdf" - practice_pdf(game_id, Path(output_filename)) + practice_pdf(game_id, Path(output_filename), config_section=config_section) os_open(output_filename) @@ -422,6 +456,12 @@ def parse_schedule( schedule_file: Annotated[ Path, typer.Option(help="schedule json file to parse") ] = Path("schedule.json"), + config_section: Annotated[ + str, + typer.Option( + "--config-section", "-c", help="Configuration section to use from INI file" + ), + ] = "default", ): """ Parse schedule.json to look for specific games or practices @@ -471,6 +511,12 @@ def check_with_ai( schedule_file: Annotated[ Path, typer.Option(help="schedule json file to parse") ] = Path("schedule.json"), + config_section: Annotated[ + str, + typer.Option( + "--config-section", "-c", help="Configuration section to use from INI file" + ), + ] = "default", ): """ Search through the schedule with natural language using Infomaniak LLM API @@ -523,10 +569,10 @@ mobile_headers = { } -def mobile_login(): +def mobile_login(config_section: str = "default"): import base64 - username, password, _, token, club_id = get_login() + username, password, _, token, club_id = get_login(config_section=config_section) if token and club_id: return {"id": 0, "token": token, "id_club": club_id} @@ -565,16 +611,30 @@ def refresh_data(): @app.command("mobile-login") -def do_mobile_login(): +def do_mobile_login( + config_section: Annotated[ + str, + typer.Option( + "--config-section", "-c", help="Configuration section to use from INI file" + ), + ] = "default", +): global userdata - userdata = mobile_login() + userdata = mobile_login(config_section=config_section) print(json.dumps(userdata, indent=2)) @app.command("mobile") -def mobile(): +def mobile( + config_section: Annotated[ + str, + typer.Option( + "--config-section", "-c", help="Configuration section to use from INI file" + ), + ] = "default", +): global userdata - userdata = mobile_login() + userdata = mobile_login(config_section=config_section) games = [x for x in refresh_data().get("club_games")] print(json.dumps(games, indent=2)) @@ -583,9 +643,15 @@ def mobile(): def mobile_game( game_id: Annotated[int, typer.Argument(help="game id")], raw: Annotated[bool, typer.Option(help="display raw output")] = False, + config_section: Annotated[ + str, + typer.Option( + "--config-section", "-c", help="Configuration section to use from INI file" + ), + ] = "default", ): global userdata - userdata = mobile_login() + userdata = mobile_login(config_section=config_section) # data = refresh_data() with requests.post( diff --git a/myice/webapi.py b/myice/webapi.py index cbeeafb..50ef7ba 100644 --- a/myice/webapi.py +++ b/myice/webapi.py @@ -77,7 +77,7 @@ async def schedule( ): if not headers.authorized(): raise HTTPException(401, detail="get out") - username, password, userid, existing_token = myice.get_login() + username, password, userid, existing_token, club_id = myice.get_login() if existing_token: myice.userdata = { "id": userid, @@ -94,7 +94,7 @@ async def game( headers: Annotated[AuthHeaders, Header()], game_id: int, ): - username, password, userid, existing_token = myice.get_login() + username, password, userid, existing_token, club_id = myice.get_login() if existing_token: myice.userdata = { "id": userid,