cookidoo-api 0.1.0__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.
- cookidoo_api-0.1.0/CHANGELOG.md +5 -0
- cookidoo_api-0.1.0/LICENSE +21 -0
- cookidoo_api-0.1.0/PKG-INFO +178 -0
- cookidoo_api-0.1.0/README.md +148 -0
- cookidoo_api-0.1.0/cookidoo_api/__init__.py +51 -0
- cookidoo_api-0.1.0/cookidoo_api/const.py +107 -0
- cookidoo_api-0.1.0/cookidoo_api/cookidoo.py +783 -0
- cookidoo_api-0.1.0/cookidoo_api/exceptions.py +37 -0
- cookidoo_api-0.1.0/cookidoo_api/helpers.py +122 -0
- cookidoo_api-0.1.0/cookidoo_api/py.typed +0 -0
- cookidoo_api-0.1.0/cookidoo_api/types.py +94 -0
- cookidoo_api-0.1.0/cookidoo_api.egg-info/PKG-INFO +178 -0
- cookidoo_api-0.1.0/cookidoo_api.egg-info/SOURCES.txt +17 -0
- cookidoo_api-0.1.0/cookidoo_api.egg-info/dependency_links.txt +1 -0
- cookidoo_api-0.1.0/cookidoo_api.egg-info/requires.txt +3 -0
- cookidoo_api-0.1.0/cookidoo_api.egg-info/top_level.txt +1 -0
- cookidoo_api-0.1.0/pyproject.toml +248 -0
- cookidoo_api-0.1.0/setup.cfg +4 -0
- cookidoo_api-0.1.0/tests/test_helpers.py +163 -0
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2024 Cyrill Raccaud cyrill.raccaud+pypi@gmail.com
|
|
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,178 @@
|
|
|
1
|
+
Metadata-Version: 2.1
|
|
2
|
+
Name: cookidoo-api
|
|
3
|
+
Version: 0.1.0
|
|
4
|
+
Summary: Unofficial package to access Cookidoo.
|
|
5
|
+
Author-email: Cyrill Raccaud <cyrill.raccaud+pypi@gmail.com>
|
|
6
|
+
License: MIT License
|
|
7
|
+
Project-URL: Documentation, https://miaucl.github.io/cookidoo-api/
|
|
8
|
+
Project-URL: Source, https://github.com/miaucl/cookidoo-api
|
|
9
|
+
Project-URL: Issues, https://github.com/miaucl/cookidoo-api/issues
|
|
10
|
+
Keywords: cookidoo,todo,web,browser,scaping,home-assistant,iot
|
|
11
|
+
Classifier: Programming Language :: Python :: 3
|
|
12
|
+
Classifier: License :: OSI Approved :: MIT License
|
|
13
|
+
Classifier: Operating System :: OS Independent
|
|
14
|
+
Classifier: Intended Audience :: Information Technology
|
|
15
|
+
Classifier: Topic :: System :: Monitoring
|
|
16
|
+
Classifier: Topic :: System :: Logging
|
|
17
|
+
Classifier: Topic :: System :: Systems Administration
|
|
18
|
+
Requires-Python: >=3.12
|
|
19
|
+
Description-Content-Type: text/markdown
|
|
20
|
+
License-File: LICENSE
|
|
21
|
+
Requires-Dist: aiohttp
|
|
22
|
+
Requires-Dist: playwright
|
|
23
|
+
Requires-Dist: python-dotenv
|
|
24
|
+
|
|
25
|
+
# Cookidoo API
|
|
26
|
+
|
|
27
|
+
[](https://pypi.org/p/cookidoo-api)
|
|
28
|
+
|
|
29
|
+
An unofficial python package to access Cookidoo.
|
|
30
|
+
|
|
31
|
+
[](https://github.com/miaucl/cookidoo-api/actions/workflows/unit-tests.yaml)
|
|
32
|
+
[](https://github.com/miaucl/cookidoo-api/actions/workflows/smoke-test.yaml)
|
|
33
|
+
[](https://github.com/miaucl/cookidoo-api/actions/workflows/ruff.yml)
|
|
34
|
+
[](https://github.com/miaucl/cookidoo-api/actions/workflows/mypy.yaml)
|
|
35
|
+
[](https://github.com/miaucl/cookidoo-api/actions/workflows/markdownlint.yml)
|
|
36
|
+
|
|
37
|
+
[](https://github.com/sponsors/miaucl)
|
|
38
|
+
[](https://patreon.com/miaucl)
|
|
39
|
+
[](https://buymeacoffee.com/miaucl)
|
|
40
|
+
[](https://paypal.me/sponsormiaucl)
|
|
41
|
+
|
|
42
|
+
## Disclaimer
|
|
43
|
+
|
|
44
|
+
The developers of this module are in no way endorsed by or affiliated with Cookidoo or Vorwerk, or any associated subsidiaries, logos or trademarks.
|
|
45
|
+
|
|
46
|
+
## Installation
|
|
47
|
+
|
|
48
|
+
**Disclaimer: This library needs a runner (browser) to execute the calls through web automation. Make sure to have it correctly set up using one of the following options before proceeding.**
|
|
49
|
+
|
|
50
|
+
[Setup runner](https://github.com/cookidoo-api/blob/master/runners)
|
|
51
|
+
|
|
52
|
+
Once you have tested your runner, install the cookidoo library and use it with your preferred browser.
|
|
53
|
+
|
|
54
|
+
`pip install cookidoo-api`
|
|
55
|
+
|
|
56
|
+
## Documentation
|
|
57
|
+
|
|
58
|
+
See below for usage examples. See [Exceptions](#exceptions) for API-specific exceptions and mitigation strategies for common exceptions.
|
|
59
|
+
|
|
60
|
+
## Usage Example
|
|
61
|
+
|
|
62
|
+
The API is based on the async implementation of the library [`playwright`](https://playwright.dev/python/docs/api/class-playwright) in collaboration with a runner for browser emulation.
|
|
63
|
+
|
|
64
|
+
Make sure to have stored your credentials in the top-level file `.env` as such, to loaded by `dotenv`. Alternatively, provide the environment variables by any other `dotenv` compatible means.
|
|
65
|
+
|
|
66
|
+
```text
|
|
67
|
+
EMAIL=your@mail.com
|
|
68
|
+
PASSWORD=password
|
|
69
|
+
```
|
|
70
|
+
|
|
71
|
+
Run the [example script](https://github.com/miaucl/cookidoo-api/blob/master/example.py) and have a look at the inline comments for more explanation.
|
|
72
|
+
|
|
73
|
+
## Exceptions
|
|
74
|
+
|
|
75
|
+
In case something goes wrong during a request, several [exceptions](https://github.com/miaucl/cookidoo/blob/master/cookidoo_api/exceptions.py) can be thrown.
|
|
76
|
+
They will either be
|
|
77
|
+
|
|
78
|
+
- `CookidooActionException`
|
|
79
|
+
- `CookidooAuthBotDetectionException`
|
|
80
|
+
- `CookidooAuthException`
|
|
81
|
+
- `CookidooConfigException`
|
|
82
|
+
- `CookidooNavigationException`
|
|
83
|
+
- `CookidooSelectorException`
|
|
84
|
+
- `CookidooUnavailableException`
|
|
85
|
+
- `CookidooUnexpectedStateException`
|
|
86
|
+
|
|
87
|
+
depending on the context. All inherit from `CookidooException`.
|
|
88
|
+
|
|
89
|
+
### Another asyncio event loop is
|
|
90
|
+
|
|
91
|
+
With the async calls, you might encounter an error that another asyncio event loop is already running on the same thread. This is expected behavior according to the asyncio.run() [documentation](https://docs.python.org/3/library/asyncio-runner.html#asyncio.run). You cannot use more than one aiohttp session per thread, reuse the existing one!
|
|
92
|
+
|
|
93
|
+
### Exception ignored: RuntimeError: Event loop is closed
|
|
94
|
+
|
|
95
|
+
Due to a known issue in some versions of aiohttp when using Windows, you might encounter a similar error to this:
|
|
96
|
+
|
|
97
|
+
```python
|
|
98
|
+
Exception ignored in: <function _ProactorBasePipeTransport.__del__ at 0x00000000>
|
|
99
|
+
Traceback (most recent call last):
|
|
100
|
+
File "C:\...\py38\lib\asyncio\proactor_events.py", line 116, in __del__
|
|
101
|
+
self.close()
|
|
102
|
+
File "C:\...\py38\lib\asyncio\proactor_events.py", line 108, in close
|
|
103
|
+
self._loop.call_soon(self._call_connection_lost, None)
|
|
104
|
+
File "C:\...\py38\lib\asyncio\base_events.py", line 719, in call_soon
|
|
105
|
+
self._check_closed()
|
|
106
|
+
File "C:\...\py38\lib\asyncio\base_events.py", line 508, in _check_closed
|
|
107
|
+
raise RuntimeError('Event loop is closed')
|
|
108
|
+
RuntimeError: Event loop is closed
|
|
109
|
+
```
|
|
110
|
+
|
|
111
|
+
You can fix this according to [this](https://stackoverflow.com/questions/68123296/asyncio-throws-runtime-error-with-exception-ignored) StackOverflow answer by adding the following line of code before executing the library:
|
|
112
|
+
|
|
113
|
+
```python
|
|
114
|
+
asyncio.set_event_loop_policy(asyncio.WindowsSelectorEventLoopPolicy())
|
|
115
|
+
```
|
|
116
|
+
|
|
117
|
+
## Bot detection and captcha problems
|
|
118
|
+
|
|
119
|
+
There is an inbuilt bot detection on cookidoo which can block the login process. There is a clear error message, when that happens. The tokens are valid for a fixed duration and therefore the library tries to minimize the amount of logins required to avoid the captcha process. Unfortunately, this is not always possible when developing or debugging a setup, and you might run into it. To continue, either wait a day or switch to a runner with a gui and enable `captcha` mode to manually solve the captcha during the login or a service such as [`capsolver`](https://www.capsolver.com/).
|
|
120
|
+
|
|
121
|
+
It is generally advised, to first try the login in `fail` mode and only activate a recovery mode on a `CookidooAuthBotDetectionException` raised.
|
|
122
|
+
|
|
123
|
+
### Captcha recovery mode `user_input`
|
|
124
|
+
|
|
125
|
+
```python
|
|
126
|
+
cookidoo = Cookidoo(<your headful browser setup>)
|
|
127
|
+
await cookidoo.login(captcha_recovery_mode="user_input")
|
|
128
|
+
```
|
|
129
|
+
|
|
130
|
+
_Be aware, using this option with a headless browser will indefinitely block the process in login, as it is waiting for user action._
|
|
131
|
+
|
|
132
|
+
### Captcha recovery mode `capsolver`
|
|
133
|
+
|
|
134
|
+
This requires the `capsolver` to be installed.
|
|
135
|
+
|
|
136
|
+
```bash
|
|
137
|
+
pip install capsolver
|
|
138
|
+
```
|
|
139
|
+
|
|
140
|
+
```python
|
|
141
|
+
cookidoo = Cookidoo(<your browser setup>)
|
|
142
|
+
await cookidoo.login(captcha_recovery_mode="capsolver")
|
|
143
|
+
```
|
|
144
|
+
|
|
145
|
+
**This is not yet implemented.**
|
|
146
|
+
|
|
147
|
+
Alternatively, they also provide a [browser extension](https://docs.capsolver.com/en/guide/extension/introductions/), which might be a cleaner way.
|
|
148
|
+
|
|
149
|
+
## Dev
|
|
150
|
+
|
|
151
|
+
Setup the dev environment using VSCode, it is highly recommended.
|
|
152
|
+
|
|
153
|
+
```bash
|
|
154
|
+
python -m venv .venv
|
|
155
|
+
source .venv/bin/activate
|
|
156
|
+
pip install -r requirements_dev.txt
|
|
157
|
+
```
|
|
158
|
+
|
|
159
|
+
Install [pre-commit](https://pre-commit.com)
|
|
160
|
+
|
|
161
|
+
```bash
|
|
162
|
+
pre-commit install
|
|
163
|
+
|
|
164
|
+
# Run the commit hooks manually
|
|
165
|
+
pre-commit run --all-files
|
|
166
|
+
```
|
|
167
|
+
|
|
168
|
+
Following VSCode integrations may be helpful:
|
|
169
|
+
|
|
170
|
+
- [ruff](https://marketplace.visualstudio.com/items?itemName=charliermarsh.ruff)
|
|
171
|
+
- [mypy](https://marketplace.visualstudio.com/items?itemName=matangover.mypy)
|
|
172
|
+
- [markdownlint](https://marketplace.visualstudio.com/items?itemName=DavidAnson.vscode-markdownlint)
|
|
173
|
+
|
|
174
|
+
# CHANGELOG
|
|
175
|
+
|
|
176
|
+
## 0.1.0
|
|
177
|
+
|
|
178
|
+
Initial commit.
|
|
@@ -0,0 +1,148 @@
|
|
|
1
|
+
# Cookidoo API
|
|
2
|
+
|
|
3
|
+
[](https://pypi.org/p/cookidoo-api)
|
|
4
|
+
|
|
5
|
+
An unofficial python package to access Cookidoo.
|
|
6
|
+
|
|
7
|
+
[](https://github.com/miaucl/cookidoo-api/actions/workflows/unit-tests.yaml)
|
|
8
|
+
[](https://github.com/miaucl/cookidoo-api/actions/workflows/smoke-test.yaml)
|
|
9
|
+
[](https://github.com/miaucl/cookidoo-api/actions/workflows/ruff.yml)
|
|
10
|
+
[](https://github.com/miaucl/cookidoo-api/actions/workflows/mypy.yaml)
|
|
11
|
+
[](https://github.com/miaucl/cookidoo-api/actions/workflows/markdownlint.yml)
|
|
12
|
+
|
|
13
|
+
[](https://github.com/sponsors/miaucl)
|
|
14
|
+
[](https://patreon.com/miaucl)
|
|
15
|
+
[](https://buymeacoffee.com/miaucl)
|
|
16
|
+
[](https://paypal.me/sponsormiaucl)
|
|
17
|
+
|
|
18
|
+
## Disclaimer
|
|
19
|
+
|
|
20
|
+
The developers of this module are in no way endorsed by or affiliated with Cookidoo or Vorwerk, or any associated subsidiaries, logos or trademarks.
|
|
21
|
+
|
|
22
|
+
## Installation
|
|
23
|
+
|
|
24
|
+
**Disclaimer: This library needs a runner (browser) to execute the calls through web automation. Make sure to have it correctly set up using one of the following options before proceeding.**
|
|
25
|
+
|
|
26
|
+
[Setup runner](https://github.com/cookidoo-api/blob/master/runners)
|
|
27
|
+
|
|
28
|
+
Once you have tested your runner, install the cookidoo library and use it with your preferred browser.
|
|
29
|
+
|
|
30
|
+
`pip install cookidoo-api`
|
|
31
|
+
|
|
32
|
+
## Documentation
|
|
33
|
+
|
|
34
|
+
See below for usage examples. See [Exceptions](#exceptions) for API-specific exceptions and mitigation strategies for common exceptions.
|
|
35
|
+
|
|
36
|
+
## Usage Example
|
|
37
|
+
|
|
38
|
+
The API is based on the async implementation of the library [`playwright`](https://playwright.dev/python/docs/api/class-playwright) in collaboration with a runner for browser emulation.
|
|
39
|
+
|
|
40
|
+
Make sure to have stored your credentials in the top-level file `.env` as such, to loaded by `dotenv`. Alternatively, provide the environment variables by any other `dotenv` compatible means.
|
|
41
|
+
|
|
42
|
+
```text
|
|
43
|
+
EMAIL=your@mail.com
|
|
44
|
+
PASSWORD=password
|
|
45
|
+
```
|
|
46
|
+
|
|
47
|
+
Run the [example script](https://github.com/miaucl/cookidoo-api/blob/master/example.py) and have a look at the inline comments for more explanation.
|
|
48
|
+
|
|
49
|
+
## Exceptions
|
|
50
|
+
|
|
51
|
+
In case something goes wrong during a request, several [exceptions](https://github.com/miaucl/cookidoo/blob/master/cookidoo_api/exceptions.py) can be thrown.
|
|
52
|
+
They will either be
|
|
53
|
+
|
|
54
|
+
- `CookidooActionException`
|
|
55
|
+
- `CookidooAuthBotDetectionException`
|
|
56
|
+
- `CookidooAuthException`
|
|
57
|
+
- `CookidooConfigException`
|
|
58
|
+
- `CookidooNavigationException`
|
|
59
|
+
- `CookidooSelectorException`
|
|
60
|
+
- `CookidooUnavailableException`
|
|
61
|
+
- `CookidooUnexpectedStateException`
|
|
62
|
+
|
|
63
|
+
depending on the context. All inherit from `CookidooException`.
|
|
64
|
+
|
|
65
|
+
### Another asyncio event loop is
|
|
66
|
+
|
|
67
|
+
With the async calls, you might encounter an error that another asyncio event loop is already running on the same thread. This is expected behavior according to the asyncio.run() [documentation](https://docs.python.org/3/library/asyncio-runner.html#asyncio.run). You cannot use more than one aiohttp session per thread, reuse the existing one!
|
|
68
|
+
|
|
69
|
+
### Exception ignored: RuntimeError: Event loop is closed
|
|
70
|
+
|
|
71
|
+
Due to a known issue in some versions of aiohttp when using Windows, you might encounter a similar error to this:
|
|
72
|
+
|
|
73
|
+
```python
|
|
74
|
+
Exception ignored in: <function _ProactorBasePipeTransport.__del__ at 0x00000000>
|
|
75
|
+
Traceback (most recent call last):
|
|
76
|
+
File "C:\...\py38\lib\asyncio\proactor_events.py", line 116, in __del__
|
|
77
|
+
self.close()
|
|
78
|
+
File "C:\...\py38\lib\asyncio\proactor_events.py", line 108, in close
|
|
79
|
+
self._loop.call_soon(self._call_connection_lost, None)
|
|
80
|
+
File "C:\...\py38\lib\asyncio\base_events.py", line 719, in call_soon
|
|
81
|
+
self._check_closed()
|
|
82
|
+
File "C:\...\py38\lib\asyncio\base_events.py", line 508, in _check_closed
|
|
83
|
+
raise RuntimeError('Event loop is closed')
|
|
84
|
+
RuntimeError: Event loop is closed
|
|
85
|
+
```
|
|
86
|
+
|
|
87
|
+
You can fix this according to [this](https://stackoverflow.com/questions/68123296/asyncio-throws-runtime-error-with-exception-ignored) StackOverflow answer by adding the following line of code before executing the library:
|
|
88
|
+
|
|
89
|
+
```python
|
|
90
|
+
asyncio.set_event_loop_policy(asyncio.WindowsSelectorEventLoopPolicy())
|
|
91
|
+
```
|
|
92
|
+
|
|
93
|
+
## Bot detection and captcha problems
|
|
94
|
+
|
|
95
|
+
There is an inbuilt bot detection on cookidoo which can block the login process. There is a clear error message, when that happens. The tokens are valid for a fixed duration and therefore the library tries to minimize the amount of logins required to avoid the captcha process. Unfortunately, this is not always possible when developing or debugging a setup, and you might run into it. To continue, either wait a day or switch to a runner with a gui and enable `captcha` mode to manually solve the captcha during the login or a service such as [`capsolver`](https://www.capsolver.com/).
|
|
96
|
+
|
|
97
|
+
It is generally advised, to first try the login in `fail` mode and only activate a recovery mode on a `CookidooAuthBotDetectionException` raised.
|
|
98
|
+
|
|
99
|
+
### Captcha recovery mode `user_input`
|
|
100
|
+
|
|
101
|
+
```python
|
|
102
|
+
cookidoo = Cookidoo(<your headful browser setup>)
|
|
103
|
+
await cookidoo.login(captcha_recovery_mode="user_input")
|
|
104
|
+
```
|
|
105
|
+
|
|
106
|
+
_Be aware, using this option with a headless browser will indefinitely block the process in login, as it is waiting for user action._
|
|
107
|
+
|
|
108
|
+
### Captcha recovery mode `capsolver`
|
|
109
|
+
|
|
110
|
+
This requires the `capsolver` to be installed.
|
|
111
|
+
|
|
112
|
+
```bash
|
|
113
|
+
pip install capsolver
|
|
114
|
+
```
|
|
115
|
+
|
|
116
|
+
```python
|
|
117
|
+
cookidoo = Cookidoo(<your browser setup>)
|
|
118
|
+
await cookidoo.login(captcha_recovery_mode="capsolver")
|
|
119
|
+
```
|
|
120
|
+
|
|
121
|
+
**This is not yet implemented.**
|
|
122
|
+
|
|
123
|
+
Alternatively, they also provide a [browser extension](https://docs.capsolver.com/en/guide/extension/introductions/), which might be a cleaner way.
|
|
124
|
+
|
|
125
|
+
## Dev
|
|
126
|
+
|
|
127
|
+
Setup the dev environment using VSCode, it is highly recommended.
|
|
128
|
+
|
|
129
|
+
```bash
|
|
130
|
+
python -m venv .venv
|
|
131
|
+
source .venv/bin/activate
|
|
132
|
+
pip install -r requirements_dev.txt
|
|
133
|
+
```
|
|
134
|
+
|
|
135
|
+
Install [pre-commit](https://pre-commit.com)
|
|
136
|
+
|
|
137
|
+
```bash
|
|
138
|
+
pre-commit install
|
|
139
|
+
|
|
140
|
+
# Run the commit hooks manually
|
|
141
|
+
pre-commit run --all-files
|
|
142
|
+
```
|
|
143
|
+
|
|
144
|
+
Following VSCode integrations may be helpful:
|
|
145
|
+
|
|
146
|
+
- [ruff](https://marketplace.visualstudio.com/items?itemName=charliermarsh.ruff)
|
|
147
|
+
- [mypy](https://marketplace.visualstudio.com/items?itemName=matangover.mypy)
|
|
148
|
+
- [markdownlint](https://marketplace.visualstudio.com/items?itemName=DavidAnson.vscode-markdownlint)
|
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
"""Cookidoo API package."""
|
|
2
|
+
|
|
3
|
+
__version__ = "0.1.0"
|
|
4
|
+
|
|
5
|
+
from .const import (
|
|
6
|
+
DEFAULT_COOKIDOO_CONFIG,
|
|
7
|
+
DEFAULT_NETWORK_TIMEOUT,
|
|
8
|
+
DEFAULT_RETRIES,
|
|
9
|
+
DEFAULT_TIMEOUT,
|
|
10
|
+
)
|
|
11
|
+
from .cookidoo import Cookidoo
|
|
12
|
+
from .exceptions import (
|
|
13
|
+
CookidooActionException,
|
|
14
|
+
CookidooAuthBotDetectionException,
|
|
15
|
+
CookidooAuthException,
|
|
16
|
+
CookidooConfigException,
|
|
17
|
+
CookidooException,
|
|
18
|
+
CookidooNavigationException,
|
|
19
|
+
CookidooSelectorException,
|
|
20
|
+
CookidooUnavailableException,
|
|
21
|
+
CookidooUnexpectedStateException,
|
|
22
|
+
)
|
|
23
|
+
from .types import (
|
|
24
|
+
CookidooBrowserType,
|
|
25
|
+
CookidooCaptchaRecoveryType,
|
|
26
|
+
CookidooConfig,
|
|
27
|
+
CookidooItem,
|
|
28
|
+
CookidooItemStateType,
|
|
29
|
+
)
|
|
30
|
+
|
|
31
|
+
__all__ = [
|
|
32
|
+
"Cookidoo",
|
|
33
|
+
"CookidooBrowserType",
|
|
34
|
+
"CookidooCaptchaRecoveryType",
|
|
35
|
+
"CookidooItemStateType",
|
|
36
|
+
"CookidooConfig",
|
|
37
|
+
"CookidooItem",
|
|
38
|
+
"CookidooException",
|
|
39
|
+
"CookidooConfigException",
|
|
40
|
+
"CookidooAuthException",
|
|
41
|
+
"CookidooAuthBotDetectionException",
|
|
42
|
+
"CookidooSelectorException",
|
|
43
|
+
"CookidooActionException",
|
|
44
|
+
"CookidooUnavailableException",
|
|
45
|
+
"CookidooUnexpectedStateException",
|
|
46
|
+
"CookidooNavigationException",
|
|
47
|
+
"DEFAULT_COOKIDOO_CONFIG",
|
|
48
|
+
"DEFAULT_RETRIES",
|
|
49
|
+
"DEFAULT_NETWORK_TIMEOUT",
|
|
50
|
+
"DEFAULT_TIMEOUT",
|
|
51
|
+
]
|
|
@@ -0,0 +1,107 @@
|
|
|
1
|
+
"""Constants for Cookidoo API."""
|
|
2
|
+
|
|
3
|
+
from typing import Final
|
|
4
|
+
|
|
5
|
+
from cookidoo_api.types import CookidooConfig
|
|
6
|
+
|
|
7
|
+
LOGIN_START_URL: Final = "https://cookidoo.ch"
|
|
8
|
+
LOGIN_START_SELECTOR: Final = "#layout--default > header > div > core-nav > nav > div.core-nav__container > ul.core-nav__links.unauthenticated-only > li:nth-child(2) > a"
|
|
9
|
+
LOGIN_EMAIL_SELECTOR: Final = "#email"
|
|
10
|
+
LOGIN_PASSWORD_SELECTOR: Final = "#password"
|
|
11
|
+
LOGIN_SUBMIT_SELECTOR: Final = 'button[type="submit"]'
|
|
12
|
+
LOGIN_CAPTCHA_SELECTOR: Final = "#amzn-captcha-verify-button"
|
|
13
|
+
LOGIN_ERROR_NOTIFICATION_SELECTOR: Final = ".notification__unobtrusive-error"
|
|
14
|
+
COOKIE_VALIDATION_URL: Final = "https://cookidoo.ch/profile/account"
|
|
15
|
+
COOKIE_VALIDATION_SELECTOR: Final = (
|
|
16
|
+
"main > section > .profile-indent > .profile-main-headline"
|
|
17
|
+
)
|
|
18
|
+
SHOPPING_LIST_URL: Final = "https://cookidoo.ch/shopping"
|
|
19
|
+
SHOPPING_LIST_SELECTOR: Final = "pm-shopping-list"
|
|
20
|
+
|
|
21
|
+
SHOPPING_LIST_EMPTY_SELECTOR: Final = "core-error-page"
|
|
22
|
+
|
|
23
|
+
SHOPPING_LIST_OPTIONS_SELECTOR: Final = "#shopping-list-options"
|
|
24
|
+
SHOPPING_LIST_CLEAR_ALL_OPTION_SELECTOR: Final = "#clearAllRecipes"
|
|
25
|
+
SHOPPING_LIST_CLEAR_ALL_MODAL_CONFIRM_SELECTOR: Final = (
|
|
26
|
+
'core-modal [data-action="clear-all"] button[type="submit"]'
|
|
27
|
+
)
|
|
28
|
+
|
|
29
|
+
SHOPPING_LIST_ITEMS_SELECTOR: Final = "pm-ingredients-list #byCategory"
|
|
30
|
+
SHOPPING_LIST_CHECKED_ITEMS_SELECTOR: Final = "pm-checked-list-wrapper"
|
|
31
|
+
|
|
32
|
+
SHOPPING_LIST_ITEM_SUB_SELECTOR: Final = "li:not(.additional-items-list-item)"
|
|
33
|
+
SHOPPING_LIST_ITEM_LABEL_SUB_SELECTOR: Final = (
|
|
34
|
+
'label span[data-type="ingredientNotation"]'
|
|
35
|
+
)
|
|
36
|
+
SHOPPING_LIST_ITEM_QUANTITY_SUB_SELECTOR: Final = 'label span[data-type="value"]'
|
|
37
|
+
SHOPPING_LIST_ITEM_UNIT_SUB_SELECTOR: Final = 'label span[data-type="unitNotation"]'
|
|
38
|
+
SHOPPING_LIST_ITEM_ID_SUB_SELECTOR: Final = "input[data-value]"
|
|
39
|
+
SHOPPING_LIST_ITEM_ID_ATTR: Final = "data-value"
|
|
40
|
+
SHOPPING_LIST_CHECKBOX_SUB_SELECTOR: Final = "core-checkbox"
|
|
41
|
+
|
|
42
|
+
SHOPPING_LIST_ADDITIONAL_ITEMS_SELECTOR: Final = "pm-additional-items-list"
|
|
43
|
+
SHOPPING_LIST_ADDITIONAL_CHECKED_ITEMS_SELECTOR: Final = "pm-checked-list-wrapper"
|
|
44
|
+
SHOPPING_LIST_ADDITIONAL_ITEM_SUB_SELECTOR: Final = "li.additional-items-list-item"
|
|
45
|
+
SHOPPING_LIST_ADDITIONAL_ITEM_HOVER_SUB_SELECTOR: Final = "> div"
|
|
46
|
+
SHOPPING_LIST_ADDITIONAL_ITEM_LABEL_SUB_SELECTOR: Final = (
|
|
47
|
+
'label span[data-type="name"], label span[data-type="value"]'
|
|
48
|
+
)
|
|
49
|
+
SHOPPING_LIST_ADDITIONAL_ITEM_ID_SUB_SELECTOR: Final = "input[data-value]"
|
|
50
|
+
SHOPPING_LIST_ADDITIONAL_ITEM_ID_ATTR: Final = "data-value"
|
|
51
|
+
SHOPPING_LIST_ADDITIONAL_CHECKBOX_SUB_SELECTOR: Final = "core-checkbox"
|
|
52
|
+
SHOPPING_LIST_ADDITIONAL_ITEM_DELETE_SUB_SELECTOR: Final = 'span[data-type="delete"]'
|
|
53
|
+
SHOPPING_LIST_ADDITIONAL_ITEM_EDIT_SUB_SELECTOR: Final = 'span[data-type="edit"]'
|
|
54
|
+
|
|
55
|
+
SHOPPING_LIST_EDIT_ADDITIONAL_ITEM_SELECTOR: Final = "pm-edit-additional-item"
|
|
56
|
+
SHOPPING_LIST_EDIT_ADDITIONAL_ITEM_INPUT_SUB_SELECTOR: Final = 'input[type="text"]'
|
|
57
|
+
SHOPPING_LIST_EDIT_ADDITIONAL_ITEM_CONFIRM_SUB_SELECTOR: Final = (
|
|
58
|
+
'button:not([type="button"])'
|
|
59
|
+
)
|
|
60
|
+
|
|
61
|
+
SHOPPING_LIST_CREATE_ADDITIONAL_ITEM_SELECTOR: Final = "pm-add-additional-item"
|
|
62
|
+
SHOPPING_LIST_CREATE_ADDITIONAL_ITEM_INPUT_SUB_SELECTOR: Final = "input"
|
|
63
|
+
SHOPPING_LIST_CREATE_ADDITIONAL_ITEM_CONFIRM_SUB_SELECTOR: Final = "button"
|
|
64
|
+
|
|
65
|
+
SHOPPING_LIST_ITEMS_TAB_SELECTOR: Final = "core-content-navigation button:nth-child(1)"
|
|
66
|
+
SHOPPING_LIST_RECIPES_TAB_SELECTOR: Final = (
|
|
67
|
+
"core-content-navigation button:nth-child(2)"
|
|
68
|
+
)
|
|
69
|
+
SHOPPING_LIST_RECIPE_OPTIONS_SELECTOR_TEMPLATE: Final = (
|
|
70
|
+
'[id="shopping-list-trigger-{}"]'
|
|
71
|
+
)
|
|
72
|
+
SHOPPING_LIST_RECIPE_REMOVE_OPTION_SELECTOR_TEMPLATE: Final = 'core-context-menu[trigger-id="shopping-list-trigger-{}"] core-handle-form[data-action="remove-recipes"]'
|
|
73
|
+
|
|
74
|
+
RECIPE_URL_PREFIX: Final = "https://cookidoo.ch/recipes/recipe/"
|
|
75
|
+
RECIPE_COOK_TODAY_SELECTOR: Final = '[id="cook-today-handle-form"] button'
|
|
76
|
+
RECIPE_ADD_OPTIONS_SELECTOR_TEMPLATE: Final = '[id="add-trigger-{}"]'
|
|
77
|
+
RECIPE_ADD_OPTION_SHOPPING_LIST_SELECTOR: Final = (
|
|
78
|
+
'[id="add-to-shopping-list-button"] button'
|
|
79
|
+
)
|
|
80
|
+
RECIPE_ADD_TO_SHOPPING_LIST_CONFIRM_SELECTOR: Final = (
|
|
81
|
+
'core-conversion-teaser [href^="/shopping"]'
|
|
82
|
+
)
|
|
83
|
+
DOM_CHECK_ATTACHED: Final = "element => document.body.contains(element)"
|
|
84
|
+
|
|
85
|
+
DEFAULT_RETRIES = 3
|
|
86
|
+
DEFAULT_NETWORK_TIMEOUT = 5000
|
|
87
|
+
DEFAULT_TIMEOUT = 3000
|
|
88
|
+
|
|
89
|
+
|
|
90
|
+
DEFAULT_COOKIDOO_CONFIG = CookidooConfig(
|
|
91
|
+
{
|
|
92
|
+
"language_code": "de-CH",
|
|
93
|
+
"browser": "firefox",
|
|
94
|
+
"remote_addr": None,
|
|
95
|
+
"remote_port": "9222",
|
|
96
|
+
"headless": True,
|
|
97
|
+
"email": "your@email",
|
|
98
|
+
"password": "1234password!",
|
|
99
|
+
"network_timeout": DEFAULT_NETWORK_TIMEOUT,
|
|
100
|
+
"timeout": DEFAULT_TIMEOUT,
|
|
101
|
+
"retries": DEFAULT_RETRIES,
|
|
102
|
+
"load_media": True,
|
|
103
|
+
"tracing": False,
|
|
104
|
+
"screenshots": False,
|
|
105
|
+
"out_dir": "./out",
|
|
106
|
+
}
|
|
107
|
+
)
|