strava-cz-api 2.1.2__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- strava_cz_api-2.1.2/LICENSE +21 -0
- strava_cz_api-2.1.2/PKG-INFO +98 -0
- strava_cz_api-2.1.2/README.md +88 -0
- strava_cz_api-2.1.2/examples/login.py +26 -0
- strava_cz_api-2.1.2/examples/public_jidelnicek.py +10 -0
- strava_cz_api-2.1.2/examples/user_info.py +18 -0
- strava_cz_api-2.1.2/pyproject.toml +16 -0
- strava_cz_api-2.1.2/setup.cfg +4 -0
- strava_cz_api-2.1.2/strava_cz_api/action.py +78 -0
- strava_cz_api-2.1.2/strava_cz_api/strava.py +362 -0
- strava_cz_api-2.1.2/strava_cz_api.egg-info/PKG-INFO +98 -0
- strava_cz_api-2.1.2/strava_cz_api.egg-info/SOURCES.txt +12 -0
- strava_cz_api-2.1.2/strava_cz_api.egg-info/dependency_links.txt +1 -0
- strava_cz_api-2.1.2/strava_cz_api.egg-info/top_level.txt +3 -0
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2025 Matěj Adamec
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
|
@@ -0,0 +1,98 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: strava_cz_api
|
|
3
|
+
Version: 2.1.2
|
|
4
|
+
Summary: Rest API for strava.cz.
|
|
5
|
+
Author-email: Matěj Adamec <kralyk@kralyk.dev>
|
|
6
|
+
Requires-Python: >=3.8
|
|
7
|
+
Description-Content-Type: text/markdown
|
|
8
|
+
License-File: LICENSE
|
|
9
|
+
Dynamic: license-file
|
|
10
|
+
|
|
11
|
+
# Strava.cz rest API
|
|
12
|
+
> ⚠️ **UPOZORNĚNÍ:** Strava.cz má vysoce proměnlivé prostředí (každá jídelna má jiný počet obědů, jiné názvy chodů apod.) z toho důvodu toto API **není plně univerzální**. I když jsem se snažil ho napsat univerzálně, nějaké metody nemusí plně fungovat a bude to vyžadovat vaší opravu.
|
|
13
|
+
|
|
14
|
+
Toto je **neoficiální** REST api pro stravu.cz. V tomto dokumentu je popsáno vše co potřebuješ vědet o tomto API. Je zde také vysvětleno dopodrobna jak to celé funguje.
|
|
15
|
+
|
|
16
|
+
## Instalace
|
|
17
|
+
```bash
|
|
18
|
+
pip install strava_cz_api.cz_api
|
|
19
|
+
```
|
|
20
|
+
|
|
21
|
+
## Autentizace
|
|
22
|
+
K API endpointům potřebuješ **SID** a **s5url**. Můžeš si je získat sám z dev tools v prohlížeči, ale nejlepší cesta je pomocí metod: `Auth.login()` a `Auth.getCredentials()`:
|
|
23
|
+
|
|
24
|
+
```py
|
|
25
|
+
from strava_cz_api import Auth
|
|
26
|
+
|
|
27
|
+
cookie, data = Auth.login("demo", "demo", "0000")
|
|
28
|
+
sid, s5url = Auth.getCredentials(data)
|
|
29
|
+
```
|
|
30
|
+
|
|
31
|
+
**Poznámky:**
|
|
32
|
+
- Podporované jazyky: `CZ`, `EN`, `SK`.
|
|
33
|
+
- `Auth.login()` vrací `cookie` a JSON data; `Auth.getCredentials()` z nich vytáhne `sid` a `s5url`.
|
|
34
|
+
|
|
35
|
+
## Inicializace API
|
|
36
|
+
```py
|
|
37
|
+
from strava_cz_api import Api
|
|
38
|
+
|
|
39
|
+
api = Api(
|
|
40
|
+
sid="00000000000000000000000000000000",
|
|
41
|
+
s5url="",
|
|
42
|
+
cislo_jidelny="0000"
|
|
43
|
+
)
|
|
44
|
+
```
|
|
45
|
+
|
|
46
|
+
**Poznámky:**
|
|
47
|
+
- `s5url=""` může být hash, url či prázdné. Někdy se stane, že musí být spravný input, někdy může být prázné.
|
|
48
|
+
|
|
49
|
+
## Veřejné endpointy (bez přihlášení)
|
|
50
|
+
|
|
51
|
+
| Metoda | Popis | Poznámka |
|
|
52
|
+
| --- | --- | --- |
|
|
53
|
+
| `getJidelny()` | Seznam jídelen
|
|
54
|
+
| `getJidelna()` | Informace o jídělne
|
|
55
|
+
| `getS5url()` | URL jídelny
|
|
56
|
+
| `getJidelnicek()` | Get veřejného jídelníčku
|
|
57
|
+
|
|
58
|
+
## Autentizované endpointy (Api)
|
|
59
|
+
| Metoda | Popis | Poznámka |
|
|
60
|
+
| --- | --- | --- |
|
|
61
|
+
| `getJidelnicekToday()` | Dnešní jídelníček | Vrací list (`table0`) |
|
|
62
|
+
| `getJidelnicekAll()` | Kompletní jídelníček
|
|
63
|
+
| `getInfo()` | Informace o uživateli
|
|
64
|
+
| `getUsername()` | Uživatelské jméno | Vytahuje z `getInfo()` |
|
|
65
|
+
| `getJidelna()` | Informace o jídelně
|
|
66
|
+
| `getHistorieKlienta(date)` | Historie objednávek za měsíc | `date` = první den měsíce (např. `2025-01-01`) |
|
|
67
|
+
| `getPlaby()` | Pohyby na účtu
|
|
68
|
+
| `getMessages()` | Zprávy pro uživatele
|
|
69
|
+
| `getProtokol()` | Vrátí protokol
|
|
70
|
+
| `getVydej()` | Vrátí list vydaných jídel.
|
|
71
|
+
| `postJidlo(veta, stav)` | Přihlásit/odhlásit jídlo | `stav`: 1 přihlásit, 0 odhlásit |
|
|
72
|
+
| `postDen(datum, stav)` | Přihlásit/odhlásit celý den | `datum` ve formátu `YYYY-MM-DD` |
|
|
73
|
+
| `postOrders()` | Uložit změny objednávek | Nutné po `postJidlo`/`postDen` |
|
|
74
|
+
|
|
75
|
+
## Objednávky – správný postup
|
|
76
|
+
Změny objednávek se ukládají ve dvou krocích:
|
|
77
|
+
1. Provedení změn (`postJidlo` nebo `postDen`)
|
|
78
|
+
2. Uložení (`postOrders`)
|
|
79
|
+
|
|
80
|
+
```py
|
|
81
|
+
cookie_data = api.postJidlo(5, 1)
|
|
82
|
+
cookie_data = api.postOrders()
|
|
83
|
+
```
|
|
84
|
+
|
|
85
|
+
## Návratové hodnoty
|
|
86
|
+
Většina metod vrací JSON string. Metody `postJidlo`, `postDen` a `postOrders` vrací dvojici `(cookie, data)` z POST odpovědi.
|
|
87
|
+
|
|
88
|
+
## Chyby a omezení
|
|
89
|
+
- Error handling je dostupný přes výjimky, které lze importovat: `from strava_cz_api import StravaError`.
|
|
90
|
+
- Při neúspěšném požadavku se vyhazuje `ConnectionError`.
|
|
91
|
+
- Některé jídelny mohou vyžadovat úpravy payloadů nebo cookie.
|
|
92
|
+
|
|
93
|
+
## Příklady
|
|
94
|
+
Ukázkové skripty najdeš ve složce `./examples`.
|
|
95
|
+
|
|
96
|
+
## Demo
|
|
97
|
+
- Demo uživatele si lze vytvořit na https://www.strava.cz/strava/Stravnik/Demo
|
|
98
|
+
- Poté se lze přihlásit na https://app.strava.cz/ na jídelně `0000`
|
|
@@ -0,0 +1,88 @@
|
|
|
1
|
+
# Strava.cz rest API
|
|
2
|
+
> ⚠️ **UPOZORNĚNÍ:** Strava.cz má vysoce proměnlivé prostředí (každá jídelna má jiný počet obědů, jiné názvy chodů apod.) z toho důvodu toto API **není plně univerzální**. I když jsem se snažil ho napsat univerzálně, nějaké metody nemusí plně fungovat a bude to vyžadovat vaší opravu.
|
|
3
|
+
|
|
4
|
+
Toto je **neoficiální** REST api pro stravu.cz. V tomto dokumentu je popsáno vše co potřebuješ vědet o tomto API. Je zde také vysvětleno dopodrobna jak to celé funguje.
|
|
5
|
+
|
|
6
|
+
## Instalace
|
|
7
|
+
```bash
|
|
8
|
+
pip install strava_cz_api.cz_api
|
|
9
|
+
```
|
|
10
|
+
|
|
11
|
+
## Autentizace
|
|
12
|
+
K API endpointům potřebuješ **SID** a **s5url**. Můžeš si je získat sám z dev tools v prohlížeči, ale nejlepší cesta je pomocí metod: `Auth.login()` a `Auth.getCredentials()`:
|
|
13
|
+
|
|
14
|
+
```py
|
|
15
|
+
from strava_cz_api import Auth
|
|
16
|
+
|
|
17
|
+
cookie, data = Auth.login("demo", "demo", "0000")
|
|
18
|
+
sid, s5url = Auth.getCredentials(data)
|
|
19
|
+
```
|
|
20
|
+
|
|
21
|
+
**Poznámky:**
|
|
22
|
+
- Podporované jazyky: `CZ`, `EN`, `SK`.
|
|
23
|
+
- `Auth.login()` vrací `cookie` a JSON data; `Auth.getCredentials()` z nich vytáhne `sid` a `s5url`.
|
|
24
|
+
|
|
25
|
+
## Inicializace API
|
|
26
|
+
```py
|
|
27
|
+
from strava_cz_api import Api
|
|
28
|
+
|
|
29
|
+
api = Api(
|
|
30
|
+
sid="00000000000000000000000000000000",
|
|
31
|
+
s5url="",
|
|
32
|
+
cislo_jidelny="0000"
|
|
33
|
+
)
|
|
34
|
+
```
|
|
35
|
+
|
|
36
|
+
**Poznámky:**
|
|
37
|
+
- `s5url=""` může být hash, url či prázdné. Někdy se stane, že musí být spravný input, někdy může být prázné.
|
|
38
|
+
|
|
39
|
+
## Veřejné endpointy (bez přihlášení)
|
|
40
|
+
|
|
41
|
+
| Metoda | Popis | Poznámka |
|
|
42
|
+
| --- | --- | --- |
|
|
43
|
+
| `getJidelny()` | Seznam jídelen
|
|
44
|
+
| `getJidelna()` | Informace o jídělne
|
|
45
|
+
| `getS5url()` | URL jídelny
|
|
46
|
+
| `getJidelnicek()` | Get veřejného jídelníčku
|
|
47
|
+
|
|
48
|
+
## Autentizované endpointy (Api)
|
|
49
|
+
| Metoda | Popis | Poznámka |
|
|
50
|
+
| --- | --- | --- |
|
|
51
|
+
| `getJidelnicekToday()` | Dnešní jídelníček | Vrací list (`table0`) |
|
|
52
|
+
| `getJidelnicekAll()` | Kompletní jídelníček
|
|
53
|
+
| `getInfo()` | Informace o uživateli
|
|
54
|
+
| `getUsername()` | Uživatelské jméno | Vytahuje z `getInfo()` |
|
|
55
|
+
| `getJidelna()` | Informace o jídelně
|
|
56
|
+
| `getHistorieKlienta(date)` | Historie objednávek za měsíc | `date` = první den měsíce (např. `2025-01-01`) |
|
|
57
|
+
| `getPlaby()` | Pohyby na účtu
|
|
58
|
+
| `getMessages()` | Zprávy pro uživatele
|
|
59
|
+
| `getProtokol()` | Vrátí protokol
|
|
60
|
+
| `getVydej()` | Vrátí list vydaných jídel.
|
|
61
|
+
| `postJidlo(veta, stav)` | Přihlásit/odhlásit jídlo | `stav`: 1 přihlásit, 0 odhlásit |
|
|
62
|
+
| `postDen(datum, stav)` | Přihlásit/odhlásit celý den | `datum` ve formátu `YYYY-MM-DD` |
|
|
63
|
+
| `postOrders()` | Uložit změny objednávek | Nutné po `postJidlo`/`postDen` |
|
|
64
|
+
|
|
65
|
+
## Objednávky – správný postup
|
|
66
|
+
Změny objednávek se ukládají ve dvou krocích:
|
|
67
|
+
1. Provedení změn (`postJidlo` nebo `postDen`)
|
|
68
|
+
2. Uložení (`postOrders`)
|
|
69
|
+
|
|
70
|
+
```py
|
|
71
|
+
cookie_data = api.postJidlo(5, 1)
|
|
72
|
+
cookie_data = api.postOrders()
|
|
73
|
+
```
|
|
74
|
+
|
|
75
|
+
## Návratové hodnoty
|
|
76
|
+
Většina metod vrací JSON string. Metody `postJidlo`, `postDen` a `postOrders` vrací dvojici `(cookie, data)` z POST odpovědi.
|
|
77
|
+
|
|
78
|
+
## Chyby a omezení
|
|
79
|
+
- Error handling je dostupný přes výjimky, které lze importovat: `from strava_cz_api import StravaError`.
|
|
80
|
+
- Při neúspěšném požadavku se vyhazuje `ConnectionError`.
|
|
81
|
+
- Některé jídelny mohou vyžadovat úpravy payloadů nebo cookie.
|
|
82
|
+
|
|
83
|
+
## Příklady
|
|
84
|
+
Ukázkové skripty najdeš ve složce `./examples`.
|
|
85
|
+
|
|
86
|
+
## Demo
|
|
87
|
+
- Demo uživatele si lze vytvořit na https://www.strava.cz/strava/Stravnik/Demo
|
|
88
|
+
- Poté se lze přihlásit na https://app.strava.cz/ na jídelně `0000`
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
# made by OpiKula
|
|
2
|
+
|
|
3
|
+
from strava_cz_api import Api, Auth, StravaError
|
|
4
|
+
import getpass
|
|
5
|
+
|
|
6
|
+
# Ziskame od uzivatele credentials
|
|
7
|
+
username = input("Zadej zde svoje uživatelské jméno: ")
|
|
8
|
+
password = getpass.getpass("Zadej zde svoje heslo: ")
|
|
9
|
+
jidelna = input("Zadej zde číslo jídelny: ")
|
|
10
|
+
|
|
11
|
+
# Poslani post requestu a getnuti SID a s5url
|
|
12
|
+
try:
|
|
13
|
+
cookie, data = Auth.login(username, password, jidelna)
|
|
14
|
+
|
|
15
|
+
except StravaError:
|
|
16
|
+
print("Chybné heslo")
|
|
17
|
+
exit()
|
|
18
|
+
|
|
19
|
+
# ziskame sid a s5url
|
|
20
|
+
sid, s5url = Auth.getCredentials(data)
|
|
21
|
+
|
|
22
|
+
# Inicializujeme spojeni a vytiskneme jidelnicek
|
|
23
|
+
example = Api(sid, s5url, jidelna)
|
|
24
|
+
|
|
25
|
+
|
|
26
|
+
print(example.getJidelnicekToday())
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
from strava import Public
|
|
2
|
+
import json
|
|
3
|
+
|
|
4
|
+
cislo_jidelny = input("Zadej cislo jidelny: ").strip()
|
|
5
|
+
lang = (input("Jazyk (CZ/EN/SK) [CZ]: ").strip() or "CZ").upper()
|
|
6
|
+
|
|
7
|
+
data = Public.getJidelnicek(cislo_jidelny, lang)
|
|
8
|
+
jidelnicek = json.loads(data)
|
|
9
|
+
|
|
10
|
+
print(json.dumps(jidelnicek, indent=2, ensure_ascii=False))
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
from strava import Api, Auth
|
|
2
|
+
import getpass
|
|
3
|
+
import json
|
|
4
|
+
|
|
5
|
+
username = input("Zadej uzivatelske jmeno: ").strip()
|
|
6
|
+
password = getpass.getpass("Zadej heslo: ")
|
|
7
|
+
cislo_jidelny = input("Zadej cislo jidelny: ").strip()
|
|
8
|
+
|
|
9
|
+
_cookie, data = Auth.login(username, password, cislo_jidelny)
|
|
10
|
+
sid, s5url = Auth.getCredentials(data)
|
|
11
|
+
|
|
12
|
+
api = Api(sid, s5url, cislo_jidelny)
|
|
13
|
+
|
|
14
|
+
print("Uzivatel:", api.getUsername())
|
|
15
|
+
print("Info:")
|
|
16
|
+
print(json.dumps(json.loads(api.getInfo()), indent=2, ensure_ascii=False))
|
|
17
|
+
print("Jidelna:")
|
|
18
|
+
print(json.dumps(json.loads(api.getJidelna()), indent=2, ensure_ascii=False))
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
[build-system]
|
|
2
|
+
requires = ["setuptools>=61.0"]
|
|
3
|
+
build-backend = "setuptools.build_meta"
|
|
4
|
+
|
|
5
|
+
[tool.setuptools.packages.find]
|
|
6
|
+
where = ["."]
|
|
7
|
+
|
|
8
|
+
[project]
|
|
9
|
+
name = "strava_cz_api"
|
|
10
|
+
version = "2.1.2"
|
|
11
|
+
description = "Rest API for strava.cz."
|
|
12
|
+
readme = "README.md"
|
|
13
|
+
requires-python = ">=3.8"
|
|
14
|
+
authors = [
|
|
15
|
+
{ name="Matěj Adamec", email="kralyk@kralyk.dev" }
|
|
16
|
+
]
|
|
@@ -0,0 +1,78 @@
|
|
|
1
|
+
import requests
|
|
2
|
+
import json
|
|
3
|
+
|
|
4
|
+
class StravaError(Exception):
|
|
5
|
+
pass
|
|
6
|
+
|
|
7
|
+
class JidelnaNenalezenaError(StravaError):
|
|
8
|
+
pass
|
|
9
|
+
|
|
10
|
+
class ChybneHesloError(StravaError):
|
|
11
|
+
pass
|
|
12
|
+
|
|
13
|
+
class BackendError(StravaError):
|
|
14
|
+
pass
|
|
15
|
+
|
|
16
|
+
class ChybneSID(StravaError):
|
|
17
|
+
pass
|
|
18
|
+
|
|
19
|
+
def raise_api_error(data):
|
|
20
|
+
if data.get("state") != "error":
|
|
21
|
+
return
|
|
22
|
+
|
|
23
|
+
number = data.get("number")
|
|
24
|
+
message = data.get("message", "Neznámá chyba")
|
|
25
|
+
|
|
26
|
+
exc = ERROR_MAP.get(number, StravaError)
|
|
27
|
+
raise exc(message)
|
|
28
|
+
|
|
29
|
+
|
|
30
|
+
ERROR_MAP = {
|
|
31
|
+
6: JidelnaNenalezenaError,
|
|
32
|
+
15: ChybneSID,
|
|
33
|
+
13405: ChybneHesloError,
|
|
34
|
+
3002: BackendError,
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
class Get:
|
|
38
|
+
@staticmethod
|
|
39
|
+
def call(url, payload, headers=
|
|
40
|
+
{
|
|
41
|
+
"Content-Type": "text/plain;charset=UTF-8",
|
|
42
|
+
"Cookie": "NEXT_LOCALE=cs; multiContextSession=%7B%22printOpen%22%3A%7B%22value%22%3Afalse%2C%22expiration%22%3A-1%7D%7D",
|
|
43
|
+
"Referer": "https://app.strava.cz/"
|
|
44
|
+
}):
|
|
45
|
+
|
|
46
|
+
response = requests.post(url, headers=headers, json=payload)
|
|
47
|
+
|
|
48
|
+
data = response.json()
|
|
49
|
+
|
|
50
|
+
raise_api_error(data)
|
|
51
|
+
|
|
52
|
+
return json.dumps(data, indent=2, ensure_ascii=False)
|
|
53
|
+
|
|
54
|
+
|
|
55
|
+
|
|
56
|
+
class Post:
|
|
57
|
+
@staticmethod
|
|
58
|
+
def call(url, payload, cookie, headers=None):
|
|
59
|
+
if headers is None:
|
|
60
|
+
headers = {
|
|
61
|
+
"Content-Type": "text/plain;charset=UTF-8",
|
|
62
|
+
"Cookie": cookie,
|
|
63
|
+
"Referer": "https://app.strava.cz/"
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
|
|
67
|
+
response = requests.post(url, headers=headers, json=payload)
|
|
68
|
+
|
|
69
|
+
data = response.json()
|
|
70
|
+
|
|
71
|
+
raise_api_error(data)
|
|
72
|
+
|
|
73
|
+
new_cookie = "; ".join([f"{k}={v}" for k, v in response.cookies.items()])
|
|
74
|
+
|
|
75
|
+
return new_cookie, data
|
|
76
|
+
|
|
77
|
+
|
|
78
|
+
|
|
@@ -0,0 +1,362 @@
|
|
|
1
|
+
import requests
|
|
2
|
+
import json
|
|
3
|
+
from action import Get, Post
|
|
4
|
+
|
|
5
|
+
from action import (
|
|
6
|
+
StravaError,
|
|
7
|
+
JidelnaNenalezenaError,
|
|
8
|
+
ChybneHesloError,
|
|
9
|
+
BackendError,
|
|
10
|
+
ChybneSID
|
|
11
|
+
)
|
|
12
|
+
|
|
13
|
+
__all__ = [
|
|
14
|
+
"Api",
|
|
15
|
+
"Auth",
|
|
16
|
+
"StravaError",
|
|
17
|
+
"JidelnaNenalezenaError",
|
|
18
|
+
"ChybneHesloError",
|
|
19
|
+
"BackendError",
|
|
20
|
+
"ChybneSID"
|
|
21
|
+
]
|
|
22
|
+
|
|
23
|
+
|
|
24
|
+
class Api:
|
|
25
|
+
def __init__(self, sid, s5url, cislo_jidelny, cookie="NEXT_LOCALE=cs; multiContextSession=%7B%22printOpen%22%3A%7B%22value%22%3Afalse%2C%22expiration%22%3A-1%7D%7D", lang="CZ"):
|
|
26
|
+
if lang not in ("CZ", "EN", "SK"):
|
|
27
|
+
raise ValueError("Podporované jazyky: EN, CZ, SK")
|
|
28
|
+
|
|
29
|
+
self.sid = sid
|
|
30
|
+
self.lang = lang
|
|
31
|
+
self.cislo_jidelny = cislo_jidelny
|
|
32
|
+
self.cookie = cookie
|
|
33
|
+
self.s5url = s5url
|
|
34
|
+
|
|
35
|
+
self.base = "https://app.strava.cz/api"
|
|
36
|
+
|
|
37
|
+
|
|
38
|
+
def getJidelnicekToday(self):
|
|
39
|
+
"""
|
|
40
|
+
Vrátí dnešní jídelníček
|
|
41
|
+
"""
|
|
42
|
+
return json.loads(self.getJidelnicekAll()).get("table0", [])
|
|
43
|
+
|
|
44
|
+
|
|
45
|
+
def getJidelnicekAll(self):
|
|
46
|
+
"""
|
|
47
|
+
Vrátí celý jídelníček
|
|
48
|
+
"""
|
|
49
|
+
url = f"{self.base}/objednavky"
|
|
50
|
+
|
|
51
|
+
payload = {
|
|
52
|
+
"cislo": self.cislo_jidelny,
|
|
53
|
+
"sid": self.sid,
|
|
54
|
+
"s5url": self.s5url,
|
|
55
|
+
"lang": self.lang,
|
|
56
|
+
"konto": 0,
|
|
57
|
+
"podminka": "",
|
|
58
|
+
"ignoreCert": "false"
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
return Get.call(url, payload)
|
|
62
|
+
|
|
63
|
+
|
|
64
|
+
def getInfo(self):
|
|
65
|
+
"""
|
|
66
|
+
Vrátí info o uživateli
|
|
67
|
+
"""
|
|
68
|
+
url = f"{self.base}/nactiVlastnostiPA"
|
|
69
|
+
|
|
70
|
+
payload = {
|
|
71
|
+
"sid": self.sid,
|
|
72
|
+
"url": self.s5url,
|
|
73
|
+
"cislo": self.cislo_jidelny,
|
|
74
|
+
"ignoreCert": "false",
|
|
75
|
+
"lang": self.lang,
|
|
76
|
+
"getText": True,
|
|
77
|
+
"checkVersion": True,
|
|
78
|
+
"resetTables" :True,
|
|
79
|
+
"frontendFunction": "refreshInformations"
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
|
|
83
|
+
return Get.call(url, payload)
|
|
84
|
+
|
|
85
|
+
|
|
86
|
+
def getUsername(self):
|
|
87
|
+
"""
|
|
88
|
+
Vrátí uživatelské jméno
|
|
89
|
+
"""
|
|
90
|
+
|
|
91
|
+
return json.loads(self.getInfo()).get("id")
|
|
92
|
+
|
|
93
|
+
|
|
94
|
+
def getJidelna(self):
|
|
95
|
+
"""
|
|
96
|
+
Získá informaci o jídělně
|
|
97
|
+
"""
|
|
98
|
+
|
|
99
|
+
url = f"{self.base}/jidelnaS5"
|
|
100
|
+
|
|
101
|
+
payload = {
|
|
102
|
+
"cislo": self.cislo_jidelny,
|
|
103
|
+
"url": self.s5url,
|
|
104
|
+
"lang": self.lang,
|
|
105
|
+
"ignoreCert": "false"
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
|
|
109
|
+
return Get.call(url, payload)
|
|
110
|
+
|
|
111
|
+
|
|
112
|
+
def getHistorieKlienta(self, date):
|
|
113
|
+
"""
|
|
114
|
+
Získá info o historii objednávek.
|
|
115
|
+
|
|
116
|
+
date = počáteční datum měsíce.
|
|
117
|
+
2025-01-01 - leden
|
|
118
|
+
2025-12-01 - prosinec
|
|
119
|
+
"""
|
|
120
|
+
|
|
121
|
+
url = f"{self.base}/historieKlienta"
|
|
122
|
+
|
|
123
|
+
payload = {
|
|
124
|
+
"sid": self.sid,
|
|
125
|
+
"url": self.s5url,
|
|
126
|
+
"cislo": self.cislo_jidelny,
|
|
127
|
+
"datum": date,
|
|
128
|
+
"lang": self.lang,
|
|
129
|
+
"ignoreCert": "false"
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
|
|
133
|
+
return Get.call(url, payload)
|
|
134
|
+
|
|
135
|
+
|
|
136
|
+
def getPlaby(self):
|
|
137
|
+
"""
|
|
138
|
+
Vrátí platby na účtu.
|
|
139
|
+
"""
|
|
140
|
+
|
|
141
|
+
url = f"{self.base}/platby"
|
|
142
|
+
|
|
143
|
+
payload = {
|
|
144
|
+
"sid": self.sid,
|
|
145
|
+
"url": self.s5url,
|
|
146
|
+
"cislo": self.cislo_jidelny,
|
|
147
|
+
"lang": self.lang,
|
|
148
|
+
"ignoreCert": "false"
|
|
149
|
+
}
|
|
150
|
+
|
|
151
|
+
|
|
152
|
+
return Get.call(url, payload)
|
|
153
|
+
|
|
154
|
+
|
|
155
|
+
def getMessages(self):
|
|
156
|
+
"""
|
|
157
|
+
Vratí zprávy poslané uživatelovi.
|
|
158
|
+
"""
|
|
159
|
+
|
|
160
|
+
url = f"{self.base}/messagesGetList"
|
|
161
|
+
|
|
162
|
+
payload = {
|
|
163
|
+
"sid": "",
|
|
164
|
+
"idO":"",
|
|
165
|
+
"idJ": self.cislo_jidelny,
|
|
166
|
+
"idU": self.getUsername(),
|
|
167
|
+
"typZpravy": ""
|
|
168
|
+
}
|
|
169
|
+
|
|
170
|
+
return Get.call(url, payload)
|
|
171
|
+
|
|
172
|
+
|
|
173
|
+
def getProtokol(self):
|
|
174
|
+
"""
|
|
175
|
+
Vrátí protokol.
|
|
176
|
+
"""
|
|
177
|
+
|
|
178
|
+
url = f"{self.base}/getProtokol"
|
|
179
|
+
|
|
180
|
+
payload = {
|
|
181
|
+
"cislo": self.cislo_jidelny,
|
|
182
|
+
"s5url": self.s5url,
|
|
183
|
+
"sid": self.sid,
|
|
184
|
+
"ignoreCert": "false",
|
|
185
|
+
"lang": self.lang,
|
|
186
|
+
"uroven": "KP",
|
|
187
|
+
"evCislo": 0
|
|
188
|
+
}
|
|
189
|
+
|
|
190
|
+
|
|
191
|
+
return Get.call(url, payload)
|
|
192
|
+
|
|
193
|
+
def getVydej(self):
|
|
194
|
+
"""
|
|
195
|
+
Vrátí list vydaných jídel.
|
|
196
|
+
"""
|
|
197
|
+
|
|
198
|
+
url = f"{self.base}/vydej"
|
|
199
|
+
|
|
200
|
+
payload = {
|
|
201
|
+
"cislo": self.cislo_jidelny,
|
|
202
|
+
"s5url": self.s5url,
|
|
203
|
+
"sid": self.sid,
|
|
204
|
+
"ignoreCert": "false",
|
|
205
|
+
"lang": self.lang,
|
|
206
|
+
}
|
|
207
|
+
|
|
208
|
+
|
|
209
|
+
return Get.call(url, payload)
|
|
210
|
+
|
|
211
|
+
|
|
212
|
+
def postJidlo(self, veta, stav):
|
|
213
|
+
"""
|
|
214
|
+
Příhlásí nebo odhlásí jídlo.
|
|
215
|
+
|
|
216
|
+
veta = číslo políčka/jídla - jde získat např. z getJidelnicek()
|
|
217
|
+
stav = 0 odhlásit - 1 přihlásit
|
|
218
|
+
"""
|
|
219
|
+
url = f"{self.base}/pridejJidloS5"
|
|
220
|
+
|
|
221
|
+
payload = {
|
|
222
|
+
"cislo": self.cislo_jidelny,
|
|
223
|
+
"sid": self.sid,
|
|
224
|
+
"url": self.s5url,
|
|
225
|
+
"veta": veta,
|
|
226
|
+
"pocet": stav, # 0 ohlasit - 1 prihlasit
|
|
227
|
+
"lang": self.lang,
|
|
228
|
+
"ignoreCert": "false"
|
|
229
|
+
}
|
|
230
|
+
|
|
231
|
+
self.cookie = Post.call(url, payload, self.cookie)
|
|
232
|
+
|
|
233
|
+
return self.cookie
|
|
234
|
+
|
|
235
|
+
|
|
236
|
+
def postOrders(self):
|
|
237
|
+
"""
|
|
238
|
+
Uloží objednávky
|
|
239
|
+
"""
|
|
240
|
+
url = f"{self.base}/saveOrders"
|
|
241
|
+
|
|
242
|
+
|
|
243
|
+
payload = {
|
|
244
|
+
"cislo": self.cislo_jidelny,
|
|
245
|
+
"sid": self.sid,
|
|
246
|
+
"url": self.s5url,
|
|
247
|
+
"xml": None,
|
|
248
|
+
"lang": self.lang,
|
|
249
|
+
"ignoreCert": "false"
|
|
250
|
+
}
|
|
251
|
+
|
|
252
|
+
self.cookie = Post.call(url, payload, self.cookie)
|
|
253
|
+
|
|
254
|
+
return self.cookie
|
|
255
|
+
|
|
256
|
+
|
|
257
|
+
def postDen(self, datum, stav):
|
|
258
|
+
"""
|
|
259
|
+
Přihlásí nebo ohlásí celý den.
|
|
260
|
+
|
|
261
|
+
datum = datum dne jaký chceme odhlásit. 2025-12-30
|
|
262
|
+
stav = 0 ohlasit - 1 prihlasit
|
|
263
|
+
"""
|
|
264
|
+
|
|
265
|
+
url = f"{self.base}/objednejDenS5"
|
|
266
|
+
|
|
267
|
+
payload = {
|
|
268
|
+
"cislo": self.cislo_jidelny,
|
|
269
|
+
"sid": self.sid,
|
|
270
|
+
"url": self.s5url,
|
|
271
|
+
"datum": datum,
|
|
272
|
+
"pocet": stav,
|
|
273
|
+
"lang": self.lang,
|
|
274
|
+
"ignoreCert": "false"
|
|
275
|
+
}
|
|
276
|
+
|
|
277
|
+
self.cookie = Post.call(url, payload, self.cookie)
|
|
278
|
+
|
|
279
|
+
return self.cookie
|
|
280
|
+
|
|
281
|
+
|
|
282
|
+
class Public:
|
|
283
|
+
def getJidelnicek(cislo_jidelny, lang):
|
|
284
|
+
"""
|
|
285
|
+
Získání public jídelníčků.
|
|
286
|
+
"""
|
|
287
|
+
if lang not in ("CZ", "EN", "SK"):
|
|
288
|
+
raise ValueError("Podporované jazyky: EN, CZ, SK")
|
|
289
|
+
|
|
290
|
+
url = "https://app.strava.cz/api/jidelnicky"
|
|
291
|
+
|
|
292
|
+
payload = {
|
|
293
|
+
"cislo": cislo_jidelny,
|
|
294
|
+
"s5url": Public.getS5url(cislo_jidelny),
|
|
295
|
+
"lang": lang,
|
|
296
|
+
"ignoreCert": False
|
|
297
|
+
}
|
|
298
|
+
|
|
299
|
+
return Get.call(url, payload)
|
|
300
|
+
|
|
301
|
+
def getJidelna(cislo_jidelny):
|
|
302
|
+
"""
|
|
303
|
+
Vrátí informaci o jídelně.
|
|
304
|
+
"""
|
|
305
|
+
url = "https://app.strava.cz/api/s4Polozky"
|
|
306
|
+
|
|
307
|
+
payload = {
|
|
308
|
+
"cislo": cislo_jidelny,
|
|
309
|
+
"lang": "CZ",
|
|
310
|
+
"polozky": "V_NAZEV,V_ULICE,V_MESTO,V_PSC,V_TELEFON,V_UCET,V_EMAIL,V_URL,DATCAS_AKT,VERZE,URLWSDL_S-URL,GPSDELKA,GPSSIRKA,IGN_CERT,TEXT_ANON,LOGO"}
|
|
311
|
+
|
|
312
|
+
return Get.call(url, payload)
|
|
313
|
+
|
|
314
|
+
def getS5url(cislo_jidelny):
|
|
315
|
+
"""
|
|
316
|
+
Pomocná metoda co vratí url jídelny.
|
|
317
|
+
"""
|
|
318
|
+
return json.loads(Public.getJidelna(cislo_jidelny)).get("urlwsdl_s")[0]
|
|
319
|
+
|
|
320
|
+
|
|
321
|
+
def getJidelny():
|
|
322
|
+
"""
|
|
323
|
+
Vrátí seznam všech jídelen a jejich čísel.
|
|
324
|
+
"""
|
|
325
|
+
url = "https://app.strava.cz/api/zarAMesta"
|
|
326
|
+
|
|
327
|
+
payload = {
|
|
328
|
+
"lang":"CZ"
|
|
329
|
+
}
|
|
330
|
+
|
|
331
|
+
return Get.call(url, payload)
|
|
332
|
+
|
|
333
|
+
|
|
334
|
+
class Auth:
|
|
335
|
+
def login(username, password, cislo_jidelny, lang="CZ", zustat_prihlasen=True, cookie="NEXT_LOCALE=cs"):
|
|
336
|
+
"""
|
|
337
|
+
Vrátí data nutná pro další komunikaci.
|
|
338
|
+
"""
|
|
339
|
+
if lang not in ("CZ", "EN", "SK"):
|
|
340
|
+
raise ValueError("Podporované jazyky: EN, CZ, SK")
|
|
341
|
+
|
|
342
|
+
url = "https://app.strava.cz/api/login"
|
|
343
|
+
|
|
344
|
+
payload = {
|
|
345
|
+
"cislo": cislo_jidelny,
|
|
346
|
+
"jmeno": username,
|
|
347
|
+
"heslo": password,
|
|
348
|
+
"zustatPrihlasen": zustat_prihlasen,
|
|
349
|
+
"environment": "W",
|
|
350
|
+
"lang": lang
|
|
351
|
+
}
|
|
352
|
+
|
|
353
|
+
return Post.call(url, payload, cookie)
|
|
354
|
+
|
|
355
|
+
def getCredentials(data):
|
|
356
|
+
"""
|
|
357
|
+
Vyfiltruje SID a s5url z funkce login
|
|
358
|
+
"""
|
|
359
|
+
|
|
360
|
+
sid = data.get("sid")
|
|
361
|
+
s5url = data.get("s5url")
|
|
362
|
+
return sid, s5url
|
|
@@ -0,0 +1,98 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: strava_cz_api
|
|
3
|
+
Version: 2.1.2
|
|
4
|
+
Summary: Rest API for strava.cz.
|
|
5
|
+
Author-email: Matěj Adamec <kralyk@kralyk.dev>
|
|
6
|
+
Requires-Python: >=3.8
|
|
7
|
+
Description-Content-Type: text/markdown
|
|
8
|
+
License-File: LICENSE
|
|
9
|
+
Dynamic: license-file
|
|
10
|
+
|
|
11
|
+
# Strava.cz rest API
|
|
12
|
+
> ⚠️ **UPOZORNĚNÍ:** Strava.cz má vysoce proměnlivé prostředí (každá jídelna má jiný počet obědů, jiné názvy chodů apod.) z toho důvodu toto API **není plně univerzální**. I když jsem se snažil ho napsat univerzálně, nějaké metody nemusí plně fungovat a bude to vyžadovat vaší opravu.
|
|
13
|
+
|
|
14
|
+
Toto je **neoficiální** REST api pro stravu.cz. V tomto dokumentu je popsáno vše co potřebuješ vědet o tomto API. Je zde také vysvětleno dopodrobna jak to celé funguje.
|
|
15
|
+
|
|
16
|
+
## Instalace
|
|
17
|
+
```bash
|
|
18
|
+
pip install strava_cz_api.cz_api
|
|
19
|
+
```
|
|
20
|
+
|
|
21
|
+
## Autentizace
|
|
22
|
+
K API endpointům potřebuješ **SID** a **s5url**. Můžeš si je získat sám z dev tools v prohlížeči, ale nejlepší cesta je pomocí metod: `Auth.login()` a `Auth.getCredentials()`:
|
|
23
|
+
|
|
24
|
+
```py
|
|
25
|
+
from strava_cz_api import Auth
|
|
26
|
+
|
|
27
|
+
cookie, data = Auth.login("demo", "demo", "0000")
|
|
28
|
+
sid, s5url = Auth.getCredentials(data)
|
|
29
|
+
```
|
|
30
|
+
|
|
31
|
+
**Poznámky:**
|
|
32
|
+
- Podporované jazyky: `CZ`, `EN`, `SK`.
|
|
33
|
+
- `Auth.login()` vrací `cookie` a JSON data; `Auth.getCredentials()` z nich vytáhne `sid` a `s5url`.
|
|
34
|
+
|
|
35
|
+
## Inicializace API
|
|
36
|
+
```py
|
|
37
|
+
from strava_cz_api import Api
|
|
38
|
+
|
|
39
|
+
api = Api(
|
|
40
|
+
sid="00000000000000000000000000000000",
|
|
41
|
+
s5url="",
|
|
42
|
+
cislo_jidelny="0000"
|
|
43
|
+
)
|
|
44
|
+
```
|
|
45
|
+
|
|
46
|
+
**Poznámky:**
|
|
47
|
+
- `s5url=""` může být hash, url či prázdné. Někdy se stane, že musí být spravný input, někdy může být prázné.
|
|
48
|
+
|
|
49
|
+
## Veřejné endpointy (bez přihlášení)
|
|
50
|
+
|
|
51
|
+
| Metoda | Popis | Poznámka |
|
|
52
|
+
| --- | --- | --- |
|
|
53
|
+
| `getJidelny()` | Seznam jídelen
|
|
54
|
+
| `getJidelna()` | Informace o jídělne
|
|
55
|
+
| `getS5url()` | URL jídelny
|
|
56
|
+
| `getJidelnicek()` | Get veřejného jídelníčku
|
|
57
|
+
|
|
58
|
+
## Autentizované endpointy (Api)
|
|
59
|
+
| Metoda | Popis | Poznámka |
|
|
60
|
+
| --- | --- | --- |
|
|
61
|
+
| `getJidelnicekToday()` | Dnešní jídelníček | Vrací list (`table0`) |
|
|
62
|
+
| `getJidelnicekAll()` | Kompletní jídelníček
|
|
63
|
+
| `getInfo()` | Informace o uživateli
|
|
64
|
+
| `getUsername()` | Uživatelské jméno | Vytahuje z `getInfo()` |
|
|
65
|
+
| `getJidelna()` | Informace o jídelně
|
|
66
|
+
| `getHistorieKlienta(date)` | Historie objednávek za měsíc | `date` = první den měsíce (např. `2025-01-01`) |
|
|
67
|
+
| `getPlaby()` | Pohyby na účtu
|
|
68
|
+
| `getMessages()` | Zprávy pro uživatele
|
|
69
|
+
| `getProtokol()` | Vrátí protokol
|
|
70
|
+
| `getVydej()` | Vrátí list vydaných jídel.
|
|
71
|
+
| `postJidlo(veta, stav)` | Přihlásit/odhlásit jídlo | `stav`: 1 přihlásit, 0 odhlásit |
|
|
72
|
+
| `postDen(datum, stav)` | Přihlásit/odhlásit celý den | `datum` ve formátu `YYYY-MM-DD` |
|
|
73
|
+
| `postOrders()` | Uložit změny objednávek | Nutné po `postJidlo`/`postDen` |
|
|
74
|
+
|
|
75
|
+
## Objednávky – správný postup
|
|
76
|
+
Změny objednávek se ukládají ve dvou krocích:
|
|
77
|
+
1. Provedení změn (`postJidlo` nebo `postDen`)
|
|
78
|
+
2. Uložení (`postOrders`)
|
|
79
|
+
|
|
80
|
+
```py
|
|
81
|
+
cookie_data = api.postJidlo(5, 1)
|
|
82
|
+
cookie_data = api.postOrders()
|
|
83
|
+
```
|
|
84
|
+
|
|
85
|
+
## Návratové hodnoty
|
|
86
|
+
Většina metod vrací JSON string. Metody `postJidlo`, `postDen` a `postOrders` vrací dvojici `(cookie, data)` z POST odpovědi.
|
|
87
|
+
|
|
88
|
+
## Chyby a omezení
|
|
89
|
+
- Error handling je dostupný přes výjimky, které lze importovat: `from strava_cz_api import StravaError`.
|
|
90
|
+
- Při neúspěšném požadavku se vyhazuje `ConnectionError`.
|
|
91
|
+
- Některé jídelny mohou vyžadovat úpravy payloadů nebo cookie.
|
|
92
|
+
|
|
93
|
+
## Příklady
|
|
94
|
+
Ukázkové skripty najdeš ve složce `./examples`.
|
|
95
|
+
|
|
96
|
+
## Demo
|
|
97
|
+
- Demo uživatele si lze vytvořit na https://www.strava.cz/strava/Stravnik/Demo
|
|
98
|
+
- Poté se lze přihlásit na https://app.strava.cz/ na jídelně `0000`
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
LICENSE
|
|
2
|
+
README.md
|
|
3
|
+
pyproject.toml
|
|
4
|
+
examples/login.py
|
|
5
|
+
examples/public_jidelnicek.py
|
|
6
|
+
examples/user_info.py
|
|
7
|
+
strava_cz_api/action.py
|
|
8
|
+
strava_cz_api/strava.py
|
|
9
|
+
strava_cz_api.egg-info/PKG-INFO
|
|
10
|
+
strava_cz_api.egg-info/SOURCES.txt
|
|
11
|
+
strava_cz_api.egg-info/dependency_links.txt
|
|
12
|
+
strava_cz_api.egg-info/top_level.txt
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
|