initial import

This commit is contained in:
2024-11-01 09:59:45 +01:00
commit e102cfa9c8
7 changed files with 1414 additions and 0 deletions
+5
View File
@@ -0,0 +1,5 @@
myice.ini
*.pdf
schedule.json
.envrc
cookies.txt
+63
View File
@@ -0,0 +1,63 @@
# See https://pre-commit.com for more information
# See https://pre-commit.com/hooks.html for more hooks
---
repos:
- repo: https://github.com/pre-commit/pre-commit-hooks
rev: v3.2.0
hooks:
- id: trailing-whitespace
- id: check-case-conflict
- id: end-of-file-fixer
- id: check-executables-have-shebangs
- id: check-merge-conflict
- id: check-yaml
- id: check-added-large-files
- id: detect-private-key
- repo: https://github.com/astral-sh/ruff-pre-commit
# Ruff version.
rev: v0.6.8
hooks:
# Run the linter.
- id: ruff
args: [--fix]
# Run the formatter.
- id: ruff-format
args: [--diff, --target-version, py312]
- repo: https://github.com/pre-commit/mirrors-mypy
rev: v1.11.2
hooks:
- id: mypy
exclude: ^(docs/|example-plugin/)
args: [--ignore-missing-imports]
additional_dependencies: [types-requests]
- repo: https://github.com/adrienverge/yamllint.git
rev: v1.35.1
hooks:
- id: yamllint
args: [--strict]
- repo: https://github.com/markdownlint/markdownlint
rev: v0.12.0
hooks:
- id: markdownlint
exclude: "^.github|(^docs/_sidebar\\.md$)"
- repo: https://github.com/shellcheck-py/shellcheck-py
rev: v0.10.0.1
hooks:
- id: shellcheck
args: ["--severity=error"]
exclude: "^.git"
files: "\\.sh$"
- repo: https://github.com/golangci/misspell
rev: v0.6.0
hooks:
- id: misspell
args: ["-i", "charactor"]
- repo: https://github.com/python-poetry/poetry
rev: "1.8.0"
hooks:
- id: poetry-check
- id: poetry-lock
- id: poetry-install
+59
View File
@@ -0,0 +1,59 @@
# myice
## récupérer le schedule
```shell
./myice.py schedule -o schedule.json
```
## data
Pour récupérer les event des U13 Elite par exemple:
```shell
jq -r '.[] | select(.agegroup == "U13 (Elite)") | [.date, .id_event, .event, .title] | join(" - ")' schedule.json
2024-11-01 - 561896 - - U13 (Elite)
Spécial
Shooting Box Groupe #3
2024-11-01 - 561904 - - U13 (Elite)
Off-Ice
Patinoire des Vernets - Patinoire Extérieure
2024-11-01 - 561855 - - U13 (Elite)
On-Ice
Patinoire des Vernets - Patinoire Extérieure
2024-11-04 - 576653 - - U13 (Elite)
Off-Ice
Patinoire des Vernets - Patinoire Extérieure
2024-11-04 - 572066 - - U13 (Elite)
On-Ice
Patinoire des Vernets - Patinoire Extérieure
2024-11-05 - 576652 - - U13 (Elite)
Off-Ice
Patinoire des Vernets - Patinoire Extérieure
2024-11-05 - 572068 - - U13 (Elite)
On-Ice
Patinoire des Vernets - Patinoire Extérieure
2024-11-02 - 117015 - Jeu - U13 (Elite)
Saison
HC Ajoie
```
### match
alors pour avoir la convocation du match contre Ajoie, l'id c'est 117015:
```shell
./get_schedule.py game 117015
Opening file game_117015.pdf
```
### entraînement
et pour la convoc d'un entraînement:
```shell
./myice.py practice 561855
Opening file practice_561855.pdf
```
View File
Executable
+237
View File
@@ -0,0 +1,237 @@
#!/usr/bin/env python3
"""
Tool to work with My Ice Hockey schedules
"""
import configparser
import datetime
import json
import os
import re
import sys
from pathlib import Path
from typing import Annotated
import requests
import typer
user_agent = "Mozilla/5.0 (Macintosh; Intel Mac OS X 10.15; rv:131.0) Gecko/20100101 Firefox/131.0"
app = typer.Typer(no_args_is_help=True)
session: requests.Session
userid: int
def load_cookies(file: str = "cookies.txt") -> requests.cookies.RequestsCookieJar:
cookie_jar_file = Path(file)
cj_dict = {}
if cookie_jar_file.exists():
with cookie_jar_file.open("rb") as f:
cj_dict = json.load(f)
return requests.cookies.cookiejar_from_dict(cj_dict)
def save_cookies():
with open("cookies.txt", "w") as f:
f.write(json.dumps(requests.utils.dict_from_cookiejar(session.cookies)))
def get_login(local_file: str = "myice.ini") -> tuple[str, str, int]:
config = configparser.ConfigParser()
config.read(
[
Path("~/.config/myice.ini").expanduser(),
"myice.ini",
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")
if not username or not password:
print("Error: please configure username/password in ini file")
sys.exit(1)
else:
print("Error: please configure username/password in ini file")
sys.exit(1)
return username, password, userid
def do_login():
global session
global userid
username, password, userid = get_login()
r = session.get("https://app.myice.hockey/", headers={"User-Agent": user_agent})
r.raise_for_status()
form_data = {
"login_email": username,
"login_password": password,
"sublogin": 1,
"login_submit": "",
}
r = session.post(
"https://app.myice.hockey/classes/process.php",
data=form_data,
headers={
"Referer": "https://app.myice.hockey/",
"Origin": "https://app.myice.hockey",
"User-Agent": user_agent,
},
)
r.raise_for_status()
def get_userid():
global session
r = session.get(
"https://app.myice.hockey/players/clubschedule/",
headers={
"User-Agent": user_agent,
"Referer": "https://app.myice.hockey/classes/process.php",
},
)
r.raise_for_status()
for line in r.text.splitlines():
m = re.search(r"^\s+userid: '(?P<userid>[0-9]+)'", line)
if m:
userid = m.group("userid")
break
return userid
def wrapper_session(func):
def wrapper(*args, **kwargs):
global session, userid
session = requests.Session()
session.cookies = load_cookies()
session.cookies.clear_expired_cookies()
if not session.cookies.get("mih_v3_cookname"):
print("login...")
do_login()
save_cookies()
_, _, userid = get_login()
if not userid:
print("get userid...")
userid = get_userid()
return func(*args, **kwargs)
return wrapper
@wrapper_session
def get_schedule() -> str:
global session
global userid
assert session and userid
now = datetime.datetime.now()
date_start = now + datetime.timedelta(days=1)
date_end = date_start + datetime.timedelta(days=7)
r = session.post(
"https://app.myice.hockey/inc/processclubplanning.php",
data={
"type": "fetchmy",
"userid": userid,
"type_location": ["*"],
"start": date_start.strftime("%Y-%m-%d"),
"end": date_end.strftime("%Y-%m-%d"),
},
headers={
"User-Agent": user_agent,
"Referer": "https://app.myice.hockey/players/clubschedule/",
},
)
r.raise_for_status()
return r.text
@wrapper_session
def game_pdf(gameid: int, outfile: Path):
global session, userid
assert session and userid
r = session.get(
f"https://app.myice.hockey/pdfexports/playerplatgamepdfgenerator.php?id={gameid}",
headers={
"User-Agent": user_agent,
"Referer": "https://app.myice.hockey/inc/processclubplanning.php",
},
)
r.raise_for_status()
with outfile.open("wb") as fd:
for chunk in r.iter_content(chunk_size=1024 * 1024 * 4):
fd.write(chunk)
@wrapper_session
def practice_pdf(gameid: int, outfile: Path):
global session, userid
assert session and userid
r = session.get(
f"https://app.myice.hockey/pdfexports/playerplatpracticepdf.php?practice={gameid}",
headers={
"User-Agent": user_agent,
"Referer": "https://app.myice.hockey/inc/processclubplanning.php",
},
)
r.raise_for_status()
with outfile.open("wb") as fd:
for chunk in r.iter_content(chunk_size=1024 * 1024 * 4):
fd.write(chunk)
@app.command()
def schedule(
outfile: Annotated[
Path | None,
typer.Option(
"--outfile", "-o", help="file to write result to, or stdout if none"
),
] = None,
):
"""
Fetch schedule as json
"""
schedule = get_schedule()
if outfile:
with outfile.open("w") as f:
f.write(schedule)
else:
print("Schedule:", file=sys.stderr)
print(schedule)
def open(file: str) -> None:
if os.uname().sysname == "Linux":
os.system(f"xdg-open {file}")
else:
print(f"Opening file {file}", file=sys.stderr)
os.system(f"open {file}")
@app.command("game")
def get_game_pdf(
game_id: Annotated[int, typer.Argument(help="ID of game to gen pdf for")],
):
"""
Genate the pdf for the game invitation
"""
output_filename = f"game_{game_id}.pdf"
game_pdf(game_id, Path(output_filename))
open(output_filename)
@app.command("practice")
def get_practice_pdf(
game_id: Annotated[int, typer.Argument(help="ID of practice to gen pdf for")],
):
"""
Genate the pdf for the practice invitation
"""
output_filename = f"practice_{game_id}.pdf"
practice_pdf(game_id, Path(output_filename))
open(output_filename)
if __name__ == "__main__":
app()
Generated
+1028
View File
File diff suppressed because it is too large Load Diff
+22
View File
@@ -0,0 +1,22 @@
[tool.poetry]
name = "myice"
version = "0.1.0"
description = ""
authors = ["Rene Luria <rene.luria@infomaniak.com>"]
readme = "README.md"
[tool.poetry.dependencies]
python = "^3.12"
requests = "^2.32.3"
typer = {extras = ["all"], version = "^0.12.5"}
[tool.poetry.group.dev.dependencies]
ipykernel = "^6.29.5"
[build-system]
requires = ["poetry-core"]
build-backend = "poetry.core.masonry.api"
[tool.poetry.scripts]
myice = 'myice.myice:app'