spotapi 2.0.0b1__tar.gz → 2.0.0b2__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.
- {spotapi-2.0.0b1 → spotapi-2.0.0b2}/.gitignore +165 -165
- {spotapi-2.0.0b1 → spotapi-2.0.0b2}/CHANGELOG.md +89 -89
- {spotapi-2.0.0b1 → spotapi-2.0.0b2}/CODE_OF_CONDUCT.md +128 -128
- {spotapi-2.0.0b1 → spotapi-2.0.0b2}/CONTRIBUTING.md +246 -246
- {spotapi-2.0.0b1 → spotapi-2.0.0b2}/LEGAL_NOTICE.md +45 -45
- {spotapi-2.0.0b1 → spotapi-2.0.0b2}/LICENSE +674 -674
- {spotapi-2.0.0b1 → spotapi-2.0.0b2}/MIGRATION.md +181 -181
- {spotapi-2.0.0b1 → spotapi-2.0.0b2}/PKG-INFO +7 -7
- {spotapi-2.0.0b1 → spotapi-2.0.0b2}/README.md +239 -239
- {spotapi-2.0.0b1 → spotapi-2.0.0b2}/docs/album.md +58 -58
- {spotapi-2.0.0b1 → spotapi-2.0.0b2}/docs/artist.md +107 -107
- {spotapi-2.0.0b1 → spotapi-2.0.0b2}/docs/creator.md +55 -55
- {spotapi-2.0.0b1 → spotapi-2.0.0b2}/docs/family.md +61 -61
- {spotapi-2.0.0b1 → spotapi-2.0.0b2}/docs/language.md +89 -89
- {spotapi-2.0.0b1 → spotapi-2.0.0b2}/docs/login.md +102 -102
- {spotapi-2.0.0b1 → spotapi-2.0.0b2}/docs/password.md +37 -37
- {spotapi-2.0.0b1 → spotapi-2.0.0b2}/docs/player.md +183 -183
- {spotapi-2.0.0b1 → spotapi-2.0.0b2}/docs/playlist.md +178 -178
- {spotapi-2.0.0b1 → spotapi-2.0.0b2}/docs/public.md +142 -142
- {spotapi-2.0.0b1 → spotapi-2.0.0b2}/docs/song.md +125 -125
- {spotapi-2.0.0b1 → spotapi-2.0.0b2}/docs/status.md +147 -147
- {spotapi-2.0.0b1 → spotapi-2.0.0b2}/docs/user.md +67 -67
- {spotapi-2.0.0b1 → spotapi-2.0.0b2}/docs/websocket.md +28 -28
- {spotapi-2.0.0b1 → spotapi-2.0.0b2}/example.py +9 -6
- {spotapi-2.0.0b1 → spotapi-2.0.0b2}/pyproject.toml +85 -85
- {spotapi-2.0.0b1 → spotapi-2.0.0b2}/requirements.txt +2 -2
- {spotapi-2.0.0b1 → spotapi-2.0.0b2}/setup.py +61 -61
- {spotapi-2.0.0b1 → spotapi-2.0.0b2}/spotapi/sync/__init__.py +25 -25
- spotapi-2.0.0b2/spotapi/sync/_tests/.env.sample +3 -0
- {spotapi-2.0.0b1 → spotapi-2.0.0b2}/spotapi/sync/_tests/__init__.py +1 -1
- {spotapi-2.0.0b1 → spotapi-2.0.0b2}/spotapi/sync/_tests/annotations_test.py +222 -222
- {spotapi-2.0.0b1 → spotapi-2.0.0b2}/spotapi/sync/_tests/client_refresh_test.py +224 -224
- {spotapi-2.0.0b1 → spotapi-2.0.0b2}/spotapi/sync/_tests/features/artist_test.py +196 -196
- {spotapi-2.0.0b1 → spotapi-2.0.0b2}/spotapi/sync/_tests/features/event_test.py +53 -53
- {spotapi-2.0.0b1 → spotapi-2.0.0b2}/spotapi/sync/_tests/features/player_test.py +112 -112
- {spotapi-2.0.0b1 → spotapi-2.0.0b2}/spotapi/sync/_tests/features/private_playlist_test.py +70 -70
- {spotapi-2.0.0b1 → spotapi-2.0.0b2}/spotapi/sync/_tests/features/public_playlist_test.py +32 -32
- {spotapi-2.0.0b1 → spotapi-2.0.0b2}/spotapi/sync/_tests/features/session.py +36 -36
- {spotapi-2.0.0b1 → spotapi-2.0.0b2}/spotapi/sync/_tests/features/song_test.py +67 -67
- {spotapi-2.0.0b1 → spotapi-2.0.0b2}/spotapi/sync/_tests/features/status_test.py +126 -126
- {spotapi-2.0.0b1 → spotapi-2.0.0b2}/spotapi/sync/_tests/features/user_test.py +63 -63
- {spotapi-2.0.0b1 → spotapi-2.0.0b2}/spotapi/sync/album.py +96 -96
- {spotapi-2.0.0b1 → spotapi-2.0.0b2}/spotapi/sync/artist.py +287 -287
- {spotapi-2.0.0b1 → spotapi-2.0.0b2}/spotapi/sync/client.py +314 -314
- {spotapi-2.0.0b1 → spotapi-2.0.0b2}/spotapi/sync/creator.py +203 -203
- {spotapi-2.0.0b1 → spotapi-2.0.0b2}/spotapi/sync/exceptions/__init__.py +1 -1
- {spotapi-2.0.0b1 → spotapi-2.0.0b2}/spotapi/sync/exceptions/errors.py +111 -111
- {spotapi-2.0.0b1 → spotapi-2.0.0b2}/spotapi/sync/family.py +162 -162
- {spotapi-2.0.0b1 → spotapi-2.0.0b2}/spotapi/sync/http/__init__.py +2 -2
- {spotapi-2.0.0b1 → spotapi-2.0.0b2}/spotapi/sync/http/data.py +43 -43
- {spotapi-2.0.0b1 → spotapi-2.0.0b2}/spotapi/sync/http/request.py +248 -248
- {spotapi-2.0.0b1 → spotapi-2.0.0b2}/spotapi/sync/login.py +356 -356
- {spotapi-2.0.0b1 → spotapi-2.0.0b2}/spotapi/sync/password.py +97 -97
- {spotapi-2.0.0b1 → spotapi-2.0.0b2}/spotapi/sync/player.py +348 -348
- {spotapi-2.0.0b1 → spotapi-2.0.0b2}/spotapi/sync/playlist.py +417 -417
- {spotapi-2.0.0b1 → spotapi-2.0.0b2}/spotapi/sync/podcast.py +129 -129
- {spotapi-2.0.0b1 → spotapi-2.0.0b2}/spotapi/sync/public.py +117 -117
- {spotapi-2.0.0b1 → spotapi-2.0.0b2}/spotapi/sync/solvers/__init__.py +15 -15
- {spotapi-2.0.0b1 → spotapi-2.0.0b2}/spotapi/sync/solvers/capmonster.py +145 -145
- {spotapi-2.0.0b1 → spotapi-2.0.0b2}/spotapi/sync/solvers/capsolver.py +144 -144
- {spotapi-2.0.0b1 → spotapi-2.0.0b2}/spotapi/sync/song.py +288 -288
- {spotapi-2.0.0b1 → spotapi-2.0.0b2}/spotapi/sync/status.py +226 -226
- {spotapi-2.0.0b1 → spotapi-2.0.0b2}/spotapi/sync/types/__init__.py +2 -2
- {spotapi-2.0.0b1 → spotapi-2.0.0b2}/spotapi/sync/types/alias.py +29 -29
- {spotapi-2.0.0b1 → spotapi-2.0.0b2}/spotapi/sync/types/annotations.py +201 -201
- {spotapi-2.0.0b1 → spotapi-2.0.0b2}/spotapi/sync/types/data.py +413 -413
- {spotapi-2.0.0b1 → spotapi-2.0.0b2}/spotapi/sync/types/interfaces.py +57 -57
- {spotapi-2.0.0b1 → spotapi-2.0.0b2}/spotapi/sync/user.py +128 -128
- {spotapi-2.0.0b1 → spotapi-2.0.0b2}/spotapi/sync/utils/__init__.py +3 -3
- {spotapi-2.0.0b1 → spotapi-2.0.0b2}/spotapi/sync/utils/logger.py +91 -91
- {spotapi-2.0.0b1 → spotapi-2.0.0b2}/spotapi/sync/utils/saver.py +357 -357
- {spotapi-2.0.0b1 → spotapi-2.0.0b2}/spotapi/sync/utils/strings.py +130 -130
- {spotapi-2.0.0b1 → spotapi-2.0.0b2}/spotapi/sync/websocket.py +167 -167
- spotapi-2.0.0b2/spotapi/v2/__init__.py +11 -0
- {spotapi-2.0.0b1 → spotapi-2.0.0b2}/spotapi/v2/client.py +101 -101
- {spotapi-2.0.0b1 → spotapi-2.0.0b2}/spotapi/v2/connection/http.py +26 -1
- {spotapi-2.0.0b1 → spotapi-2.0.0b2}/spotapi/v2/connection/types.py +76 -76
- {spotapi-2.0.0b1 → spotapi-2.0.0b2}/spotapi/v2/connection/websocket.py +199 -199
- {spotapi-2.0.0b1 → spotapi-2.0.0b2}/spotapi/v2/datastruct/__init__.py +9 -9
- {spotapi-2.0.0b1 → spotapi-2.0.0b2}/spotapi/v2/datastruct/event_handler.py +62 -62
- {spotapi-2.0.0b1 → spotapi-2.0.0b2}/spotapi/v2/datastruct/object_dict.py +52 -5
- {spotapi-2.0.0b1 → spotapi-2.0.0b2}/spotapi/v2/datastruct/pool.py +155 -156
- spotapi-2.0.0b2/spotapi/v2/playlist.py +225 -0
- spotapi-2.0.0b2/spotapi/v2/public.py +370 -0
- spotapi-2.0.0b1/spotapi/v2/base.py → spotapi-2.0.0b2/spotapi/v2/query.py +117 -100
- {spotapi-2.0.0b1 → spotapi-2.0.0b2}/spotapi/v2/session.py +32 -1
- {spotapi-2.0.0b1 → spotapi-2.0.0b2}/spotapi/v2/specialized/__init__.py +3 -3
- {spotapi-2.0.0b1 → spotapi-2.0.0b2}/spotapi/v2/specialized/data_wrappers/__init__.py +2 -0
- {spotapi-2.0.0b1 → spotapi-2.0.0b2}/spotapi/v2/specialized/data_wrappers/album.py +93 -93
- {spotapi-2.0.0b1 → spotapi-2.0.0b2}/spotapi/v2/specialized/data_wrappers/artist.py +66 -66
- {spotapi-2.0.0b1 → spotapi-2.0.0b2}/spotapi/v2/specialized/data_wrappers/common.py +139 -139
- {spotapi-2.0.0b1 → spotapi-2.0.0b2}/spotapi/v2/specialized/data_wrappers/playlist.py +81 -81
- {spotapi-2.0.0b1 → spotapi-2.0.0b2}/spotapi/v2/specialized/data_wrappers/podcast.py +75 -75
- spotapi-2.0.0b2/spotapi/v2/specialized/data_wrappers/profile_attributes.py +29 -0
- {spotapi-2.0.0b1 → spotapi-2.0.0b2}/spotapi/v2/specialized/data_wrappers/track.py +113 -113
- {spotapi-2.0.0b1 → spotapi-2.0.0b2}/spotapi/v2/specialized/totp.py +66 -66
- {spotapi-2.0.0b1 → spotapi-2.0.0b2}/spotapi/v2/types/__init__.py +1 -4
- {spotapi-2.0.0b1 → spotapi-2.0.0b2}/spotapi/v2/types/exceptions.py +5 -0
- {spotapi-2.0.0b1 → spotapi-2.0.0b2}/spotapi/v2/types/logger.py +724 -724
- {spotapi-2.0.0b1 → spotapi-2.0.0b2}/spotapi/v2/utils/__init__.py +1 -4
- {spotapi-2.0.0b1 → spotapi-2.0.0b2}/spotapi/v2/utils/cache.py +62 -62
- {spotapi-2.0.0b1 → spotapi-2.0.0b2}/spotapi/v2/utils/random.py +22 -22
- {spotapi-2.0.0b1 → spotapi-2.0.0b2}/spotapi/v2/utils/strings.py +2 -3
- spotapi-2.0.0b1/spotapi/sync/_tests/.env.sample +0 -3
- spotapi-2.0.0b1/spotapi/v2/__init__.py +0 -5
- spotapi-2.0.0b1/spotapi/v2/public.py +0 -151
- {spotapi-2.0.0b1 → spotapi-2.0.0b2}/image.png +0 -0
- {spotapi-2.0.0b1 → spotapi-2.0.0b2}/spotapi/v2/connection/__init__.py +0 -0
- {spotapi-2.0.0b1 → spotapi-2.0.0b2}/spotapi/v2/py.typed +0 -0
|
@@ -1,166 +1,166 @@
|
|
|
1
|
-
# Byte-compiled / optimized / DLL files
|
|
2
|
-
__pycache__/
|
|
3
|
-
*.py[cod]
|
|
4
|
-
*$py.class
|
|
5
|
-
|
|
6
|
-
# C extensions
|
|
7
|
-
*.so
|
|
8
|
-
|
|
9
|
-
# Distribution / packaging
|
|
10
|
-
.vscode/
|
|
11
|
-
.Python
|
|
12
|
-
build/
|
|
13
|
-
develop-eggs/
|
|
14
|
-
dist/
|
|
15
|
-
downloads/
|
|
16
|
-
eggs/
|
|
17
|
-
.eggs/
|
|
18
|
-
lib/
|
|
19
|
-
lib64/
|
|
20
|
-
parts/
|
|
21
|
-
sdist/
|
|
22
|
-
var/
|
|
23
|
-
wheels/
|
|
24
|
-
share/python-wheels/
|
|
25
|
-
*.egg-info/
|
|
26
|
-
.installed.cfg
|
|
27
|
-
*.egg
|
|
28
|
-
MANIFEST
|
|
29
|
-
|
|
30
|
-
# PyInstaller
|
|
31
|
-
# Usually these files are written by a python script from a template
|
|
32
|
-
# before PyInstaller builds the exe, so as to inject date/other infos into it.
|
|
33
|
-
*.manifest
|
|
34
|
-
*.spec
|
|
35
|
-
|
|
36
|
-
# Installer logs
|
|
37
|
-
pip-log.txt
|
|
38
|
-
pip-delete-this-directory.txt
|
|
39
|
-
|
|
40
|
-
# Unit test / coverage reports
|
|
41
|
-
htmlcov/
|
|
42
|
-
.tox/
|
|
43
|
-
.nox/
|
|
44
|
-
.coverage
|
|
45
|
-
.coverage.*
|
|
46
|
-
.cache
|
|
47
|
-
nosetests.xml
|
|
48
|
-
coverage.xml
|
|
49
|
-
*.cover
|
|
50
|
-
*.py,cover
|
|
51
|
-
.hypothesis/
|
|
52
|
-
.pytest_cache/
|
|
53
|
-
cover/
|
|
54
|
-
|
|
55
|
-
# Translations
|
|
56
|
-
*.mo
|
|
57
|
-
*.pot
|
|
58
|
-
|
|
59
|
-
# Django stuff:
|
|
60
|
-
*.log
|
|
61
|
-
local_settings.py
|
|
62
|
-
db.sqlite3
|
|
63
|
-
db.sqlite3-journal
|
|
64
|
-
|
|
65
|
-
# Flask stuff:
|
|
66
|
-
instance/
|
|
67
|
-
.webassets-cache
|
|
68
|
-
|
|
69
|
-
# Scrapy stuff:
|
|
70
|
-
.scrapy
|
|
71
|
-
|
|
72
|
-
# Sphinx documentation
|
|
73
|
-
docs/_build/
|
|
74
|
-
|
|
75
|
-
# PyBuilder
|
|
76
|
-
.pybuilder/
|
|
77
|
-
target/
|
|
78
|
-
|
|
79
|
-
# Jupyter Notebook
|
|
80
|
-
.ipynb_checkpoints
|
|
81
|
-
|
|
82
|
-
# IPython
|
|
83
|
-
profile_default/
|
|
84
|
-
ipython_config.py
|
|
85
|
-
|
|
86
|
-
# pyenv
|
|
87
|
-
# For a library or package, you might want to ignore these files since the code is
|
|
88
|
-
# intended to run in multiple environments; otherwise, check them in:
|
|
89
|
-
# .python-version
|
|
90
|
-
|
|
91
|
-
# pipenv
|
|
92
|
-
# According to pypa/pipenv#598, it is recommended to include Pipfile.lock in version control.
|
|
93
|
-
# However, in case of collaboration, if having platform-specific dependencies or dependencies
|
|
94
|
-
# having no cross-platform support, pipenv may install dependencies that don't work, or not
|
|
95
|
-
# install all needed dependencies.
|
|
96
|
-
#Pipfile.lock
|
|
97
|
-
|
|
98
|
-
# poetry
|
|
99
|
-
# Similar to Pipfile.lock, it is generally recommended to include poetry.lock in version control.
|
|
100
|
-
# This is especially recommended for binary packages to ensure reproducibility, and is more
|
|
101
|
-
# commonly ignored for libraries.
|
|
102
|
-
# https://python-poetry.org/docs/basic-usage/#commit-your-poetrylock-file-to-version-control
|
|
103
|
-
#poetry.lock
|
|
104
|
-
|
|
105
|
-
# pdm
|
|
106
|
-
# Similar to Pipfile.lock, it is generally recommended to include pdm.lock in version control.
|
|
107
|
-
#pdm.lock
|
|
108
|
-
# pdm stores project-wide configurations in .pdm.toml, but it is recommended to not include it
|
|
109
|
-
# in version control.
|
|
110
|
-
# https://pdm.fming.dev/latest/usage/project/#working-with-version-control
|
|
111
|
-
.pdm.toml
|
|
112
|
-
.pdm-python
|
|
113
|
-
.pdm-build/
|
|
114
|
-
|
|
115
|
-
# PEP 582; used by e.g. github.com/David-OConnor/pyflow and github.com/pdm-project/pdm
|
|
116
|
-
__pypackages__/
|
|
117
|
-
|
|
118
|
-
# Celery stuff
|
|
119
|
-
celerybeat-schedule
|
|
120
|
-
celerybeat.pid
|
|
121
|
-
|
|
122
|
-
# SageMath parsed files
|
|
123
|
-
*.sage.py
|
|
124
|
-
|
|
125
|
-
# Environments
|
|
126
|
-
.env
|
|
127
|
-
.venv
|
|
128
|
-
env/
|
|
129
|
-
venv/
|
|
130
|
-
ENV/
|
|
131
|
-
env.bak/
|
|
132
|
-
venv.bak/
|
|
133
|
-
|
|
134
|
-
# Spyder project settings
|
|
135
|
-
.spyderproject
|
|
136
|
-
.spyproject
|
|
137
|
-
|
|
138
|
-
# Rope project settings
|
|
139
|
-
.ropeproject
|
|
140
|
-
|
|
141
|
-
# mkdocs documentation
|
|
142
|
-
/site
|
|
143
|
-
|
|
144
|
-
# mypy
|
|
145
|
-
.mypy_cache/
|
|
146
|
-
.dmypy.json
|
|
147
|
-
dmypy.json
|
|
148
|
-
|
|
149
|
-
# Pyre type checker
|
|
150
|
-
.pyre/
|
|
151
|
-
|
|
152
|
-
# pytype static type analyzer
|
|
153
|
-
.pytype/
|
|
154
|
-
|
|
155
|
-
# Cython debug symbols
|
|
156
|
-
cython_debug/
|
|
157
|
-
|
|
158
|
-
# PyCharm
|
|
159
|
-
# JetBrains specific template is maintained in a separate JetBrains.gitignore that can
|
|
160
|
-
# be found at https://github.com/github/gitignore/blob/main/Global/JetBrains.gitignore
|
|
161
|
-
# and can be added to the global gitignore or merged into this file. For a more nuclear
|
|
162
|
-
# option (not recommended) you can uncomment the following to ignore the entire idea folder.
|
|
163
|
-
#.idea/
|
|
164
|
-
main.py
|
|
165
|
-
build.bat
|
|
1
|
+
# Byte-compiled / optimized / DLL files
|
|
2
|
+
__pycache__/
|
|
3
|
+
*.py[cod]
|
|
4
|
+
*$py.class
|
|
5
|
+
|
|
6
|
+
# C extensions
|
|
7
|
+
*.so
|
|
8
|
+
|
|
9
|
+
# Distribution / packaging
|
|
10
|
+
.vscode/
|
|
11
|
+
.Python
|
|
12
|
+
build/
|
|
13
|
+
develop-eggs/
|
|
14
|
+
dist/
|
|
15
|
+
downloads/
|
|
16
|
+
eggs/
|
|
17
|
+
.eggs/
|
|
18
|
+
lib/
|
|
19
|
+
lib64/
|
|
20
|
+
parts/
|
|
21
|
+
sdist/
|
|
22
|
+
var/
|
|
23
|
+
wheels/
|
|
24
|
+
share/python-wheels/
|
|
25
|
+
*.egg-info/
|
|
26
|
+
.installed.cfg
|
|
27
|
+
*.egg
|
|
28
|
+
MANIFEST
|
|
29
|
+
|
|
30
|
+
# PyInstaller
|
|
31
|
+
# Usually these files are written by a python script from a template
|
|
32
|
+
# before PyInstaller builds the exe, so as to inject date/other infos into it.
|
|
33
|
+
*.manifest
|
|
34
|
+
*.spec
|
|
35
|
+
|
|
36
|
+
# Installer logs
|
|
37
|
+
pip-log.txt
|
|
38
|
+
pip-delete-this-directory.txt
|
|
39
|
+
|
|
40
|
+
# Unit test / coverage reports
|
|
41
|
+
htmlcov/
|
|
42
|
+
.tox/
|
|
43
|
+
.nox/
|
|
44
|
+
.coverage
|
|
45
|
+
.coverage.*
|
|
46
|
+
.cache
|
|
47
|
+
nosetests.xml
|
|
48
|
+
coverage.xml
|
|
49
|
+
*.cover
|
|
50
|
+
*.py,cover
|
|
51
|
+
.hypothesis/
|
|
52
|
+
.pytest_cache/
|
|
53
|
+
cover/
|
|
54
|
+
|
|
55
|
+
# Translations
|
|
56
|
+
*.mo
|
|
57
|
+
*.pot
|
|
58
|
+
|
|
59
|
+
# Django stuff:
|
|
60
|
+
*.log
|
|
61
|
+
local_settings.py
|
|
62
|
+
db.sqlite3
|
|
63
|
+
db.sqlite3-journal
|
|
64
|
+
|
|
65
|
+
# Flask stuff:
|
|
66
|
+
instance/
|
|
67
|
+
.webassets-cache
|
|
68
|
+
|
|
69
|
+
# Scrapy stuff:
|
|
70
|
+
.scrapy
|
|
71
|
+
|
|
72
|
+
# Sphinx documentation
|
|
73
|
+
docs/_build/
|
|
74
|
+
|
|
75
|
+
# PyBuilder
|
|
76
|
+
.pybuilder/
|
|
77
|
+
target/
|
|
78
|
+
|
|
79
|
+
# Jupyter Notebook
|
|
80
|
+
.ipynb_checkpoints
|
|
81
|
+
|
|
82
|
+
# IPython
|
|
83
|
+
profile_default/
|
|
84
|
+
ipython_config.py
|
|
85
|
+
|
|
86
|
+
# pyenv
|
|
87
|
+
# For a library or package, you might want to ignore these files since the code is
|
|
88
|
+
# intended to run in multiple environments; otherwise, check them in:
|
|
89
|
+
# .python-version
|
|
90
|
+
|
|
91
|
+
# pipenv
|
|
92
|
+
# According to pypa/pipenv#598, it is recommended to include Pipfile.lock in version control.
|
|
93
|
+
# However, in case of collaboration, if having platform-specific dependencies or dependencies
|
|
94
|
+
# having no cross-platform support, pipenv may install dependencies that don't work, or not
|
|
95
|
+
# install all needed dependencies.
|
|
96
|
+
#Pipfile.lock
|
|
97
|
+
|
|
98
|
+
# poetry
|
|
99
|
+
# Similar to Pipfile.lock, it is generally recommended to include poetry.lock in version control.
|
|
100
|
+
# This is especially recommended for binary packages to ensure reproducibility, and is more
|
|
101
|
+
# commonly ignored for libraries.
|
|
102
|
+
# https://python-poetry.org/docs/basic-usage/#commit-your-poetrylock-file-to-version-control
|
|
103
|
+
#poetry.lock
|
|
104
|
+
|
|
105
|
+
# pdm
|
|
106
|
+
# Similar to Pipfile.lock, it is generally recommended to include pdm.lock in version control.
|
|
107
|
+
#pdm.lock
|
|
108
|
+
# pdm stores project-wide configurations in .pdm.toml, but it is recommended to not include it
|
|
109
|
+
# in version control.
|
|
110
|
+
# https://pdm.fming.dev/latest/usage/project/#working-with-version-control
|
|
111
|
+
.pdm.toml
|
|
112
|
+
.pdm-python
|
|
113
|
+
.pdm-build/
|
|
114
|
+
|
|
115
|
+
# PEP 582; used by e.g. github.com/David-OConnor/pyflow and github.com/pdm-project/pdm
|
|
116
|
+
__pypackages__/
|
|
117
|
+
|
|
118
|
+
# Celery stuff
|
|
119
|
+
celerybeat-schedule
|
|
120
|
+
celerybeat.pid
|
|
121
|
+
|
|
122
|
+
# SageMath parsed files
|
|
123
|
+
*.sage.py
|
|
124
|
+
|
|
125
|
+
# Environments
|
|
126
|
+
.env
|
|
127
|
+
.venv
|
|
128
|
+
env/
|
|
129
|
+
venv/
|
|
130
|
+
ENV/
|
|
131
|
+
env.bak/
|
|
132
|
+
venv.bak/
|
|
133
|
+
|
|
134
|
+
# Spyder project settings
|
|
135
|
+
.spyderproject
|
|
136
|
+
.spyproject
|
|
137
|
+
|
|
138
|
+
# Rope project settings
|
|
139
|
+
.ropeproject
|
|
140
|
+
|
|
141
|
+
# mkdocs documentation
|
|
142
|
+
/site
|
|
143
|
+
|
|
144
|
+
# mypy
|
|
145
|
+
.mypy_cache/
|
|
146
|
+
.dmypy.json
|
|
147
|
+
dmypy.json
|
|
148
|
+
|
|
149
|
+
# Pyre type checker
|
|
150
|
+
.pyre/
|
|
151
|
+
|
|
152
|
+
# pytype static type analyzer
|
|
153
|
+
.pytype/
|
|
154
|
+
|
|
155
|
+
# Cython debug symbols
|
|
156
|
+
cython_debug/
|
|
157
|
+
|
|
158
|
+
# PyCharm
|
|
159
|
+
# JetBrains specific template is maintained in a separate JetBrains.gitignore that can
|
|
160
|
+
# be found at https://github.com/github/gitignore/blob/main/Global/JetBrains.gitignore
|
|
161
|
+
# and can be added to the global gitignore or merged into this file. For a more nuclear
|
|
162
|
+
# option (not recommended) you can uncomment the following to ignore the entire idea folder.
|
|
163
|
+
#.idea/
|
|
164
|
+
main.py
|
|
165
|
+
build.bat
|
|
166
166
|
sessions.json
|
|
@@ -1,90 +1,90 @@
|
|
|
1
|
-
# Changelog
|
|
2
|
-
|
|
3
|
-
All notable changes to SpotAPI are documented here.
|
|
4
|
-
|
|
5
|
-
The format follows [Keep a Changelog](https://keepachangelog.com/en/1.1.0/).
|
|
6
|
-
SpotAPI adheres to [Semantic Versioning](https://semver.org/).
|
|
7
|
-
|
|
8
|
-
---
|
|
9
|
-
|
|
10
|
-
## [Unreleased] — `async-v2` beta
|
|
11
|
-
|
|
12
|
-
### Added
|
|
13
|
-
|
|
14
|
-
- **Full async rewrite** — every public method is now a coroutine or
|
|
15
|
-
`AsyncGenerator`. No sync wrappers, no `asyncio.run()` hidden inside the
|
|
16
|
-
library.
|
|
17
|
-
- **`Public` search generators** — `search_tracks`, `search_artists`,
|
|
18
|
-
`search_albums`, `search_playlists`, `search_podcasts` all return
|
|
19
|
-
`AsyncGenerator[Sequence[T]]` and paginate automatically.
|
|
20
|
-
- **Typed data wrappers** — `Track`, `Artist`, `Album`, `Playlist`, `Podcast`
|
|
21
|
-
are fully typed `@dataclass(slots=True)` classes with `__repr__`.
|
|
22
|
-
- **Shared visual types** — `_common.py` extracts the repeated color/theme
|
|
23
|
-
structs that Spotify returns on every entity, eliminating ~300 lines of
|
|
24
|
-
duplication across the data wrapper modules.
|
|
25
|
-
- **`from_dict` deserializer** — recursive, camelCase-aware dataclass factory
|
|
26
|
-
with `lru_cache`-backed annotation resolution.
|
|
27
|
-
- **`ObjectDict`** — attribute-access `dict` subclass for ergonomic raw JSON
|
|
28
|
-
traversal, with optional thread-safe write locking.
|
|
29
|
-
- **`Pool[T]`** — generic async object pool with factory, pre-warm, capped
|
|
30
|
-
eviction, and teardown callbacks.
|
|
31
|
-
- **`EventDispatcher`** — async event system used by `WebSocketClient`.
|
|
32
|
-
- **`WebSocketClient`** — async WebSocket wrapper with heartbeat manager,
|
|
33
|
-
`@event` decorator, and `asynccontextmanager`-based connection lifecycle.
|
|
34
|
-
- **`HTTPClient`** — `wreq`-backed HTTP client with:
|
|
35
|
-
- Exponential backoff + jitter retry strategy.
|
|
36
|
-
- Randomised browser profile emulation (Chrome, Edge, Firefox, Opera).
|
|
37
|
-
- Randomised OS emulation (Windows 30×, macOS 6×, Linux 2×).
|
|
38
|
-
- Shared `ClientPool` for connection reuse.
|
|
39
|
-
- **`BundleSession`** — parses Spotify's HTML to extract JS bundle URLs,
|
|
40
|
-
fetches and caches them, and derives persisted query hashes.
|
|
41
|
-
- **`AuthSession`** — TOTP-based access token + client token acquisition with
|
|
42
|
-
a background auto-refresh task. No CAPTCHA solver required.
|
|
43
|
-
- **`timed_cache`** — TTL-aware async/sync cache decorator used for the
|
|
44
|
-
expensive bundle-fetch step.
|
|
45
|
-
- **Five loggers**: `LoggerColour`, `StandardLogger`, `NoopLogger`,
|
|
46
|
-
`InbuiltLogger`, `JsonLogger`, and `MultiLogger` fan-out — all implementing
|
|
47
|
-
`LoggerProtocol`.
|
|
48
|
-
- **`py.typed` marker** — signals full PEP 561 type-checker support.
|
|
49
|
-
- `pyproject.toml` replaces `setup.py`.
|
|
50
|
-
|
|
51
|
-
### Fixed
|
|
52
|
-
|
|
53
|
-
- `types/__init__.py` had duplicate star imports causing symbols to be
|
|
54
|
-
registered twice; replaced with explicit named imports.
|
|
55
|
-
- `utils/__init__.py` used a broken double-import pattern that shadowed the
|
|
56
|
-
module-level `__all__`; replaced with explicit named imports.
|
|
57
|
-
- `Pool.put()` called the deprecated `asyncio.get_event_loop()` (deprecated
|
|
58
|
-
in Python 3.11); replaced with `asyncio.get_running_loop()`.
|
|
59
|
-
- `_BaseLogger.log()` acquired the threading lock then returned early without
|
|
60
|
-
releasing it when `is_enabled()` was `False`; replaced the manual
|
|
61
|
-
acquire/release with a `with` statement via `contextlib.nullcontext`.
|
|
62
|
-
- `totp.py` had an unreachable `return FALLBACK` statement after a
|
|
63
|
-
`raise RuntimeError`; removed the dead code.
|
|
64
|
-
- Data wrappers (`track.py`, `artist.py`, `album.py`, `playlist.py`,
|
|
65
|
-
`podcast.py`) each redefined identical color/theme dataclasses; extracted
|
|
66
|
-
to `_common.py` and imported from there.
|
|
67
|
-
|
|
68
|
-
### Changed
|
|
69
|
-
|
|
70
|
-
- Package layout reorganised into `connection/`, `datastruct/`,
|
|
71
|
-
`specialized/`, `types/`, `utils/` sub-packages.
|
|
72
|
-
- `setup.py` replaced by `pyproject.toml` (Hatchling build backend).
|
|
73
|
-
- Minimum Python version raised from 3.11 to **3.11**.
|
|
74
|
-
|
|
75
|
-
### Removed
|
|
76
|
-
|
|
77
|
-
- `annotations.py` runtime type-enforcement decorator (`@enforce_types`,
|
|
78
|
-
`@enforce`) — moved to a dev-only tool; it has no callers in v2 and
|
|
79
|
-
imposes overhead on every method call.
|
|
80
|
-
- `parse_json_string` from `utils/strings.py` — v1 leftover with no callers
|
|
81
|
-
in v2 (Spotify's `correlationId` is now parsed via the `appServerConfig`
|
|
82
|
-
base64 blob).
|
|
83
|
-
- `setup.py`, `requirements.txt` — superseded by `pyproject.toml`.
|
|
84
|
-
|
|
85
|
-
---
|
|
86
|
-
|
|
87
|
-
## [1.2.8] — 2026-06-14 *(latest stable)*
|
|
88
|
-
|
|
89
|
-
> See the [main branch](https://github.com/Aran404/SpotAPI/tree/main) for the
|
|
1
|
+
# Changelog
|
|
2
|
+
|
|
3
|
+
All notable changes to SpotAPI are documented here.
|
|
4
|
+
|
|
5
|
+
The format follows [Keep a Changelog](https://keepachangelog.com/en/1.1.0/).
|
|
6
|
+
SpotAPI adheres to [Semantic Versioning](https://semver.org/).
|
|
7
|
+
|
|
8
|
+
---
|
|
9
|
+
|
|
10
|
+
## [Unreleased] — `async-v2` beta
|
|
11
|
+
|
|
12
|
+
### Added
|
|
13
|
+
|
|
14
|
+
- **Full async rewrite** — every public method is now a coroutine or
|
|
15
|
+
`AsyncGenerator`. No sync wrappers, no `asyncio.run()` hidden inside the
|
|
16
|
+
library.
|
|
17
|
+
- **`Public` search generators** — `search_tracks`, `search_artists`,
|
|
18
|
+
`search_albums`, `search_playlists`, `search_podcasts` all return
|
|
19
|
+
`AsyncGenerator[Sequence[T]]` and paginate automatically.
|
|
20
|
+
- **Typed data wrappers** — `Track`, `Artist`, `Album`, `Playlist`, `Podcast`
|
|
21
|
+
are fully typed `@dataclass(slots=True)` classes with `__repr__`.
|
|
22
|
+
- **Shared visual types** — `_common.py` extracts the repeated color/theme
|
|
23
|
+
structs that Spotify returns on every entity, eliminating ~300 lines of
|
|
24
|
+
duplication across the data wrapper modules.
|
|
25
|
+
- **`from_dict` deserializer** — recursive, camelCase-aware dataclass factory
|
|
26
|
+
with `lru_cache`-backed annotation resolution.
|
|
27
|
+
- **`ObjectDict`** — attribute-access `dict` subclass for ergonomic raw JSON
|
|
28
|
+
traversal, with optional thread-safe write locking.
|
|
29
|
+
- **`Pool[T]`** — generic async object pool with factory, pre-warm, capped
|
|
30
|
+
eviction, and teardown callbacks.
|
|
31
|
+
- **`EventDispatcher`** — async event system used by `WebSocketClient`.
|
|
32
|
+
- **`WebSocketClient`** — async WebSocket wrapper with heartbeat manager,
|
|
33
|
+
`@event` decorator, and `asynccontextmanager`-based connection lifecycle.
|
|
34
|
+
- **`HTTPClient`** — `wreq`-backed HTTP client with:
|
|
35
|
+
- Exponential backoff + jitter retry strategy.
|
|
36
|
+
- Randomised browser profile emulation (Chrome, Edge, Firefox, Opera).
|
|
37
|
+
- Randomised OS emulation (Windows 30×, macOS 6×, Linux 2×).
|
|
38
|
+
- Shared `ClientPool` for connection reuse.
|
|
39
|
+
- **`BundleSession`** — parses Spotify's HTML to extract JS bundle URLs,
|
|
40
|
+
fetches and caches them, and derives persisted query hashes.
|
|
41
|
+
- **`AuthSession`** — TOTP-based access token + client token acquisition with
|
|
42
|
+
a background auto-refresh task. No CAPTCHA solver required.
|
|
43
|
+
- **`timed_cache`** — TTL-aware async/sync cache decorator used for the
|
|
44
|
+
expensive bundle-fetch step.
|
|
45
|
+
- **Five loggers**: `LoggerColour`, `StandardLogger`, `NoopLogger`,
|
|
46
|
+
`InbuiltLogger`, `JsonLogger`, and `MultiLogger` fan-out — all implementing
|
|
47
|
+
`LoggerProtocol`.
|
|
48
|
+
- **`py.typed` marker** — signals full PEP 561 type-checker support.
|
|
49
|
+
- `pyproject.toml` replaces `setup.py`.
|
|
50
|
+
|
|
51
|
+
### Fixed
|
|
52
|
+
|
|
53
|
+
- `types/__init__.py` had duplicate star imports causing symbols to be
|
|
54
|
+
registered twice; replaced with explicit named imports.
|
|
55
|
+
- `utils/__init__.py` used a broken double-import pattern that shadowed the
|
|
56
|
+
module-level `__all__`; replaced with explicit named imports.
|
|
57
|
+
- `Pool.put()` called the deprecated `asyncio.get_event_loop()` (deprecated
|
|
58
|
+
in Python 3.11); replaced with `asyncio.get_running_loop()`.
|
|
59
|
+
- `_BaseLogger.log()` acquired the threading lock then returned early without
|
|
60
|
+
releasing it when `is_enabled()` was `False`; replaced the manual
|
|
61
|
+
acquire/release with a `with` statement via `contextlib.nullcontext`.
|
|
62
|
+
- `totp.py` had an unreachable `return FALLBACK` statement after a
|
|
63
|
+
`raise RuntimeError`; removed the dead code.
|
|
64
|
+
- Data wrappers (`track.py`, `artist.py`, `album.py`, `playlist.py`,
|
|
65
|
+
`podcast.py`) each redefined identical color/theme dataclasses; extracted
|
|
66
|
+
to `_common.py` and imported from there.
|
|
67
|
+
|
|
68
|
+
### Changed
|
|
69
|
+
|
|
70
|
+
- Package layout reorganised into `connection/`, `datastruct/`,
|
|
71
|
+
`specialized/`, `types/`, `utils/` sub-packages.
|
|
72
|
+
- `setup.py` replaced by `pyproject.toml` (Hatchling build backend).
|
|
73
|
+
- Minimum Python version raised from 3.11 to **3.11**.
|
|
74
|
+
|
|
75
|
+
### Removed
|
|
76
|
+
|
|
77
|
+
- `annotations.py` runtime type-enforcement decorator (`@enforce_types`,
|
|
78
|
+
`@enforce`) — moved to a dev-only tool; it has no callers in v2 and
|
|
79
|
+
imposes overhead on every method call.
|
|
80
|
+
- `parse_json_string` from `utils/strings.py` — v1 leftover with no callers
|
|
81
|
+
in v2 (Spotify's `correlationId` is now parsed via the `appServerConfig`
|
|
82
|
+
base64 blob).
|
|
83
|
+
- `setup.py`, `requirements.txt` — superseded by `pyproject.toml`.
|
|
84
|
+
|
|
85
|
+
---
|
|
86
|
+
|
|
87
|
+
## [1.2.8] — 2026-06-14 *(latest stable)*
|
|
88
|
+
|
|
89
|
+
> See the [main branch](https://github.com/Aran404/SpotAPI/tree/main) for the
|
|
90
90
|
> v1 changelog.
|