spotify-profile-monitor 2.6__tar.gz → 2.7__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.
- {spotify_profile_monitor-2.6 → spotify_profile_monitor-2.7}/PKG-INFO +85 -7
- {spotify_profile_monitor-2.6 → spotify_profile_monitor-2.7}/README.md +83 -6
- {spotify_profile_monitor-2.6 → spotify_profile_monitor-2.7}/pyproject.toml +2 -1
- {spotify_profile_monitor-2.6 → spotify_profile_monitor-2.7}/spotify_profile_monitor.egg-info/PKG-INFO +85 -7
- {spotify_profile_monitor-2.6 → spotify_profile_monitor-2.7}/spotify_profile_monitor.egg-info/requires.txt +1 -0
- {spotify_profile_monitor-2.6 → spotify_profile_monitor-2.7}/spotify_profile_monitor.py +127 -40
- {spotify_profile_monitor-2.6 → spotify_profile_monitor-2.7}/LICENSE +0 -0
- {spotify_profile_monitor-2.6 → spotify_profile_monitor-2.7}/setup.cfg +0 -0
- {spotify_profile_monitor-2.6 → spotify_profile_monitor-2.7}/spotify_profile_monitor.egg-info/SOURCES.txt +0 -0
- {spotify_profile_monitor-2.6 → spotify_profile_monitor-2.7}/spotify_profile_monitor.egg-info/dependency_links.txt +0 -0
- {spotify_profile_monitor-2.6 → spotify_profile_monitor-2.7}/spotify_profile_monitor.egg-info/entry_points.txt +0 -0
- {spotify_profile_monitor-2.6 → spotify_profile_monitor-2.7}/spotify_profile_monitor.egg-info/top_level.txt +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: spotify_profile_monitor
|
|
3
|
-
Version: 2.
|
|
3
|
+
Version: 2.7
|
|
4
4
|
Summary: Tool implementing real-time tracking of Spotify users activities and profile changes including playlists
|
|
5
5
|
Author-email: Michal Szymanski <misiektoja-pypi@rm-rf.ninja>
|
|
6
6
|
License-Expression: GPL-3.0-or-later
|
|
@@ -24,13 +24,16 @@ Requires-Dist: pytz>=2020.1
|
|
|
24
24
|
Requires-Dist: tzlocal>=4.0
|
|
25
25
|
Requires-Dist: python-dotenv>=0.19
|
|
26
26
|
Requires-Dist: spotipy>=2.24.0
|
|
27
|
+
Requires-Dist: wcwidth>=0.2.7
|
|
27
28
|
Dynamic: license-file
|
|
28
29
|
|
|
29
30
|
# spotify_profile_monitor
|
|
30
31
|
|
|
31
|
-
OSINT tool for real-time monitoring of Spotify users' activities and profile changes including playlists
|
|
32
|
+
OSINT tool for real-time monitoring of **Spotify users' activities and profile changes including playlists**.
|
|
32
33
|
|
|
33
|
-
|
|
34
|
+
✨ If you want to track Spotify friends' music activity, check out another tool I developed: [spotify_monitor](https://github.com/misiektoja/spotify_monitor).
|
|
35
|
+
|
|
36
|
+
🛠️ If you're looking for debug tools to get Spotify Web Player access tokens and extract secret keys: [click here](#debugging-tools)
|
|
34
37
|
|
|
35
38
|
<a id="features"></a>
|
|
36
39
|
## Features
|
|
@@ -89,14 +92,17 @@ NOTE: If you want to track Spotify friends' music activity, check out another to
|
|
|
89
92
|
* [Check Intervals](#check-intervals)
|
|
90
93
|
* [Signal Controls (macOS/Linux/Unix)](#signal-controls-macoslinuxunix)
|
|
91
94
|
* [Coloring Log Output with GRC](#coloring-log-output-with-grc)
|
|
92
|
-
6. [
|
|
93
|
-
|
|
95
|
+
6. [Debugging Tools](#debugging-tools)
|
|
96
|
+
* [Access Token Retrieval via sp_dc Cookie and TOTP](#access-token-retrieval-via-sp_dc-cookie-and-totp)
|
|
97
|
+
* [Secret Key Extraction from Spotify Web Player Bundles](#secret-key-extraction-from-spotify-web-player-bundles)
|
|
98
|
+
7. [Change Log](#change-log)
|
|
99
|
+
8. [License](#license)
|
|
94
100
|
|
|
95
101
|
<a id="requirements"></a>
|
|
96
102
|
## Requirements
|
|
97
103
|
|
|
98
104
|
* Python 3.6 or higher
|
|
99
|
-
* Libraries: `requests`, `python-dateutil`, `urllib3`, `pyotp`, `pytz`, `tzlocal`, `python-dotenv`, [Spotipy](https://github.com/spotipy-dev/spotipy)
|
|
105
|
+
* Libraries: `requests`, `python-dateutil`, `urllib3`, `pyotp`, `pytz`, `tzlocal`, `python-dotenv`, [Spotipy](https://github.com/spotipy-dev/spotipy), `wcwidth`
|
|
100
106
|
|
|
101
107
|
Tested on:
|
|
102
108
|
|
|
@@ -124,7 +130,7 @@ Download the *[spotify_profile_monitor.py](https://raw.githubusercontent.com/mis
|
|
|
124
130
|
Install dependencies via pip:
|
|
125
131
|
|
|
126
132
|
```sh
|
|
127
|
-
pip install requests python-dateutil urllib3 pyotp pytz tzlocal python-dotenv spotipy
|
|
133
|
+
pip install requests python-dateutil urllib3 pyotp pytz tzlocal python-dotenv spotipy wcwidth
|
|
128
134
|
```
|
|
129
135
|
|
|
130
136
|
Alternatively, from the downloaded *[requirements.txt](https://raw.githubusercontent.com/misiektoja/spotify_profile_monitor/refs/heads/main/requirements.txt)*:
|
|
@@ -241,6 +247,8 @@ If your `sp_dc` cookie expires, the tool will notify you via the console and ema
|
|
|
241
247
|
|
|
242
248
|
If you store the `SP_DC_COOKIE` in a dotenv file you can update its value and send a `SIGHUP` signal to reload the file with the new `sp_dc` cookie without restarting the tool. More info in [Storing Secrets](#storing-secrets) and [Signal Controls (macOS/Linux/Unix)](#signal-controls-macoslinuxunix).
|
|
243
249
|
|
|
250
|
+
> **NOTE:** secrets used for TOTP generation (`SECRET_CIPHER_DICT`) expire every two days, that's why since v2.7 the tool fetches it from remote URL (see `SECRET_CIPHER_DICT_URL`); you can also run the [spotify_monitor_secret_grabber](https://github.com/misiektoja/spotify_monitor/blob/dev/debug/spotify_monitor_secret_grabber.py) and extract it by yourself (see [Secret Key Extraction from Spotify Web Player Bundles](#secret-key-extraction-from-spotify-web-player-bundles) for more info).
|
|
251
|
+
|
|
244
252
|
<a id="spotify-desktop-client"></a>
|
|
245
253
|
#### Spotify Desktop Client
|
|
246
254
|
|
|
@@ -811,6 +819,76 @@ Example:
|
|
|
811
819
|
grc tail -F -n 100 spotify_profile_monitor_<user_uri_id/file_suffix>.log
|
|
812
820
|
```
|
|
813
821
|
|
|
822
|
+
<a id="debugging-tools"></a>
|
|
823
|
+
## Debugging Tools
|
|
824
|
+
|
|
825
|
+
To help with troubleshooting and development, two debug utilities are available in the [debug](https://github.com/misiektoja/spotify_monitor/tree/dev/debug) directory of the related [spotify_monitor](https://github.com/misiektoja/spotify_monitor) project.
|
|
826
|
+
|
|
827
|
+
<a id="access-token-retrieval-via-sp_dc-cookie-and-totp"></a>
|
|
828
|
+
### Access Token Retrieval via sp_dc Cookie and TOTP
|
|
829
|
+
|
|
830
|
+
The [spotify_monitor_totp_test](https://github.com/misiektoja/spotify_monitor/blob/dev/debug/spotify_monitor_totp_test.py) tool retrieves a Spotify access token using a Web Player `sp_dc` cookie and TOTP parameters.
|
|
831
|
+
|
|
832
|
+
Download from [here](https://github.com/misiektoja/spotify_monitor/blob/dev/debug/spotify_monitor_totp_test.py) or:
|
|
833
|
+
|
|
834
|
+
```sh
|
|
835
|
+
wget https://raw.githubusercontent.com/misiektoja/spotify_monitor/refs/heads/dev/debug/spotify_monitor_totp_test.py
|
|
836
|
+
```
|
|
837
|
+
|
|
838
|
+
Install requirements:
|
|
839
|
+
|
|
840
|
+
```sh
|
|
841
|
+
pip install requests python-dateutil pyotp
|
|
842
|
+
```
|
|
843
|
+
|
|
844
|
+
Run:
|
|
845
|
+
|
|
846
|
+
```sh
|
|
847
|
+
python3 spotify_monitor_totp_test.py --sp-dc "your_sp_dc_cookie_value"
|
|
848
|
+
```
|
|
849
|
+
|
|
850
|
+
You should get a valid Spotify access token, example output:
|
|
851
|
+
|
|
852
|
+
<p align="center">
|
|
853
|
+
<img src="https://raw.githubusercontent.com/misiektoja/spotify_monitor/refs/heads/main/assets/spotify_monitor_totp_test.png" alt="spotify_monitor_totp_test" width="100%"/>
|
|
854
|
+
</p>
|
|
855
|
+
|
|
856
|
+
> **NOTE:** secrets used for TOTP generation (`SECRET_CIPHER_DICT`) expire every two days; you can either run the [spotify_monitor_secret_grabber](https://github.com/misiektoja/spotify_monitor/blob/dev/debug/spotify_monitor_secret_grabber.py) and extract it by yourself (see [here](#secret-key-extraction-from-spotify-web-player-bundles) for more info) or you can pass `--fetch-secrets` flag in [spotify_monitor_totp_test](https://github.com/misiektoja/spotify_monitor/blob/dev/debug/spotify_monitor_totp_test.py) (available since v1.6). There is also a [Thereallo1026/spotify-secrets](https://github.com/Thereallo1026/spotify-secrets) repo which offers JSON files that are automatically updated with current secrets.
|
|
857
|
+
|
|
858
|
+
<a id="secret-key-extraction-from-spotify-web-player-bundles"></a>
|
|
859
|
+
### Secret Key Extraction from Spotify Web Player Bundles
|
|
860
|
+
|
|
861
|
+
The [spotify_monitor_secret_grabber](https://github.com/misiektoja/spotify_monitor/blob/dev/debug/spotify_monitor_secret_grabber.py) tool automatically extracts secret keys used for TOTP generation in Spotify Web Player JavaScript bundles.
|
|
862
|
+
|
|
863
|
+
Download from [here](https://github.com/misiektoja/spotify_monitor/blob/dev/debug/spotify_monitor_secret_grabber.py) or:
|
|
864
|
+
|
|
865
|
+
```sh
|
|
866
|
+
wget https://raw.githubusercontent.com/misiektoja/spotify_monitor/refs/heads/dev/debug/spotify_monitor_secret_grabber.py
|
|
867
|
+
```
|
|
868
|
+
|
|
869
|
+
Install requirements:
|
|
870
|
+
|
|
871
|
+
```sh
|
|
872
|
+
pip install playwright
|
|
873
|
+
playwright install
|
|
874
|
+
```
|
|
875
|
+
|
|
876
|
+
Run:
|
|
877
|
+
|
|
878
|
+
```sh
|
|
879
|
+
python3 spotify_monitor_secret_grabber.py
|
|
880
|
+
```
|
|
881
|
+
|
|
882
|
+
You should get output similar to below:
|
|
883
|
+
|
|
884
|
+
<p align="center">
|
|
885
|
+
<img src="https://raw.githubusercontent.com/misiektoja/spotify_monitor/refs/heads/main/assets/spotify_monitor_secret_grabber.png" alt="spotify_monitor_secret_grabber" width="100%"/>
|
|
886
|
+
</p>
|
|
887
|
+
|
|
888
|
+
You can now update the secrets used for TOTP generation (for example `SECRET_CIPHER_DICT` in `spotify_monitor_totp_test`, `spotify_monitor` and `spotify_profile_monitor`).
|
|
889
|
+
|
|
890
|
+
> **NOTE:** you can also use [Thereallo1026/spotify-secrets](https://github.com/Thereallo1026/spotify-secrets) repo which offers JSON files that are automatically updated with current secrets (its secret extraction code is based on `spotify_monitor_secret_grabber`).
|
|
891
|
+
|
|
814
892
|
<a id="change-log"></a>
|
|
815
893
|
## Change Log
|
|
816
894
|
|
|
@@ -1,8 +1,10 @@
|
|
|
1
1
|
# spotify_profile_monitor
|
|
2
2
|
|
|
3
|
-
OSINT tool for real-time monitoring of Spotify users' activities and profile changes including playlists
|
|
3
|
+
OSINT tool for real-time monitoring of **Spotify users' activities and profile changes including playlists**.
|
|
4
4
|
|
|
5
|
-
|
|
5
|
+
✨ If you want to track Spotify friends' music activity, check out another tool I developed: [spotify_monitor](https://github.com/misiektoja/spotify_monitor).
|
|
6
|
+
|
|
7
|
+
🛠️ If you're looking for debug tools to get Spotify Web Player access tokens and extract secret keys: [click here](#debugging-tools)
|
|
6
8
|
|
|
7
9
|
<a id="features"></a>
|
|
8
10
|
## Features
|
|
@@ -61,14 +63,17 @@ NOTE: If you want to track Spotify friends' music activity, check out another to
|
|
|
61
63
|
* [Check Intervals](#check-intervals)
|
|
62
64
|
* [Signal Controls (macOS/Linux/Unix)](#signal-controls-macoslinuxunix)
|
|
63
65
|
* [Coloring Log Output with GRC](#coloring-log-output-with-grc)
|
|
64
|
-
6. [
|
|
65
|
-
|
|
66
|
+
6. [Debugging Tools](#debugging-tools)
|
|
67
|
+
* [Access Token Retrieval via sp_dc Cookie and TOTP](#access-token-retrieval-via-sp_dc-cookie-and-totp)
|
|
68
|
+
* [Secret Key Extraction from Spotify Web Player Bundles](#secret-key-extraction-from-spotify-web-player-bundles)
|
|
69
|
+
7. [Change Log](#change-log)
|
|
70
|
+
8. [License](#license)
|
|
66
71
|
|
|
67
72
|
<a id="requirements"></a>
|
|
68
73
|
## Requirements
|
|
69
74
|
|
|
70
75
|
* Python 3.6 or higher
|
|
71
|
-
* Libraries: `requests`, `python-dateutil`, `urllib3`, `pyotp`, `pytz`, `tzlocal`, `python-dotenv`, [Spotipy](https://github.com/spotipy-dev/spotipy)
|
|
76
|
+
* Libraries: `requests`, `python-dateutil`, `urllib3`, `pyotp`, `pytz`, `tzlocal`, `python-dotenv`, [Spotipy](https://github.com/spotipy-dev/spotipy), `wcwidth`
|
|
72
77
|
|
|
73
78
|
Tested on:
|
|
74
79
|
|
|
@@ -96,7 +101,7 @@ Download the *[spotify_profile_monitor.py](https://raw.githubusercontent.com/mis
|
|
|
96
101
|
Install dependencies via pip:
|
|
97
102
|
|
|
98
103
|
```sh
|
|
99
|
-
pip install requests python-dateutil urllib3 pyotp pytz tzlocal python-dotenv spotipy
|
|
104
|
+
pip install requests python-dateutil urllib3 pyotp pytz tzlocal python-dotenv spotipy wcwidth
|
|
100
105
|
```
|
|
101
106
|
|
|
102
107
|
Alternatively, from the downloaded *[requirements.txt](https://raw.githubusercontent.com/misiektoja/spotify_profile_monitor/refs/heads/main/requirements.txt)*:
|
|
@@ -213,6 +218,8 @@ If your `sp_dc` cookie expires, the tool will notify you via the console and ema
|
|
|
213
218
|
|
|
214
219
|
If you store the `SP_DC_COOKIE` in a dotenv file you can update its value and send a `SIGHUP` signal to reload the file with the new `sp_dc` cookie without restarting the tool. More info in [Storing Secrets](#storing-secrets) and [Signal Controls (macOS/Linux/Unix)](#signal-controls-macoslinuxunix).
|
|
215
220
|
|
|
221
|
+
> **NOTE:** secrets used for TOTP generation (`SECRET_CIPHER_DICT`) expire every two days, that's why since v2.7 the tool fetches it from remote URL (see `SECRET_CIPHER_DICT_URL`); you can also run the [spotify_monitor_secret_grabber](https://github.com/misiektoja/spotify_monitor/blob/dev/debug/spotify_monitor_secret_grabber.py) and extract it by yourself (see [Secret Key Extraction from Spotify Web Player Bundles](#secret-key-extraction-from-spotify-web-player-bundles) for more info).
|
|
222
|
+
|
|
216
223
|
<a id="spotify-desktop-client"></a>
|
|
217
224
|
#### Spotify Desktop Client
|
|
218
225
|
|
|
@@ -783,6 +790,76 @@ Example:
|
|
|
783
790
|
grc tail -F -n 100 spotify_profile_monitor_<user_uri_id/file_suffix>.log
|
|
784
791
|
```
|
|
785
792
|
|
|
793
|
+
<a id="debugging-tools"></a>
|
|
794
|
+
## Debugging Tools
|
|
795
|
+
|
|
796
|
+
To help with troubleshooting and development, two debug utilities are available in the [debug](https://github.com/misiektoja/spotify_monitor/tree/dev/debug) directory of the related [spotify_monitor](https://github.com/misiektoja/spotify_monitor) project.
|
|
797
|
+
|
|
798
|
+
<a id="access-token-retrieval-via-sp_dc-cookie-and-totp"></a>
|
|
799
|
+
### Access Token Retrieval via sp_dc Cookie and TOTP
|
|
800
|
+
|
|
801
|
+
The [spotify_monitor_totp_test](https://github.com/misiektoja/spotify_monitor/blob/dev/debug/spotify_monitor_totp_test.py) tool retrieves a Spotify access token using a Web Player `sp_dc` cookie and TOTP parameters.
|
|
802
|
+
|
|
803
|
+
Download from [here](https://github.com/misiektoja/spotify_monitor/blob/dev/debug/spotify_monitor_totp_test.py) or:
|
|
804
|
+
|
|
805
|
+
```sh
|
|
806
|
+
wget https://raw.githubusercontent.com/misiektoja/spotify_monitor/refs/heads/dev/debug/spotify_monitor_totp_test.py
|
|
807
|
+
```
|
|
808
|
+
|
|
809
|
+
Install requirements:
|
|
810
|
+
|
|
811
|
+
```sh
|
|
812
|
+
pip install requests python-dateutil pyotp
|
|
813
|
+
```
|
|
814
|
+
|
|
815
|
+
Run:
|
|
816
|
+
|
|
817
|
+
```sh
|
|
818
|
+
python3 spotify_monitor_totp_test.py --sp-dc "your_sp_dc_cookie_value"
|
|
819
|
+
```
|
|
820
|
+
|
|
821
|
+
You should get a valid Spotify access token, example output:
|
|
822
|
+
|
|
823
|
+
<p align="center">
|
|
824
|
+
<img src="https://raw.githubusercontent.com/misiektoja/spotify_monitor/refs/heads/main/assets/spotify_monitor_totp_test.png" alt="spotify_monitor_totp_test" width="100%"/>
|
|
825
|
+
</p>
|
|
826
|
+
|
|
827
|
+
> **NOTE:** secrets used for TOTP generation (`SECRET_CIPHER_DICT`) expire every two days; you can either run the [spotify_monitor_secret_grabber](https://github.com/misiektoja/spotify_monitor/blob/dev/debug/spotify_monitor_secret_grabber.py) and extract it by yourself (see [here](#secret-key-extraction-from-spotify-web-player-bundles) for more info) or you can pass `--fetch-secrets` flag in [spotify_monitor_totp_test](https://github.com/misiektoja/spotify_monitor/blob/dev/debug/spotify_monitor_totp_test.py) (available since v1.6). There is also a [Thereallo1026/spotify-secrets](https://github.com/Thereallo1026/spotify-secrets) repo which offers JSON files that are automatically updated with current secrets.
|
|
828
|
+
|
|
829
|
+
<a id="secret-key-extraction-from-spotify-web-player-bundles"></a>
|
|
830
|
+
### Secret Key Extraction from Spotify Web Player Bundles
|
|
831
|
+
|
|
832
|
+
The [spotify_monitor_secret_grabber](https://github.com/misiektoja/spotify_monitor/blob/dev/debug/spotify_monitor_secret_grabber.py) tool automatically extracts secret keys used for TOTP generation in Spotify Web Player JavaScript bundles.
|
|
833
|
+
|
|
834
|
+
Download from [here](https://github.com/misiektoja/spotify_monitor/blob/dev/debug/spotify_monitor_secret_grabber.py) or:
|
|
835
|
+
|
|
836
|
+
```sh
|
|
837
|
+
wget https://raw.githubusercontent.com/misiektoja/spotify_monitor/refs/heads/dev/debug/spotify_monitor_secret_grabber.py
|
|
838
|
+
```
|
|
839
|
+
|
|
840
|
+
Install requirements:
|
|
841
|
+
|
|
842
|
+
```sh
|
|
843
|
+
pip install playwright
|
|
844
|
+
playwright install
|
|
845
|
+
```
|
|
846
|
+
|
|
847
|
+
Run:
|
|
848
|
+
|
|
849
|
+
```sh
|
|
850
|
+
python3 spotify_monitor_secret_grabber.py
|
|
851
|
+
```
|
|
852
|
+
|
|
853
|
+
You should get output similar to below:
|
|
854
|
+
|
|
855
|
+
<p align="center">
|
|
856
|
+
<img src="https://raw.githubusercontent.com/misiektoja/spotify_monitor/refs/heads/main/assets/spotify_monitor_secret_grabber.png" alt="spotify_monitor_secret_grabber" width="100%"/>
|
|
857
|
+
</p>
|
|
858
|
+
|
|
859
|
+
You can now update the secrets used for TOTP generation (for example `SECRET_CIPHER_DICT` in `spotify_monitor_totp_test`, `spotify_monitor` and `spotify_profile_monitor`).
|
|
860
|
+
|
|
861
|
+
> **NOTE:** you can also use [Thereallo1026/spotify-secrets](https://github.com/Thereallo1026/spotify-secrets) repo which offers JSON files that are automatically updated with current secrets (its secret extraction code is based on `spotify_monitor_secret_grabber`).
|
|
862
|
+
|
|
786
863
|
<a id="change-log"></a>
|
|
787
864
|
## Change Log
|
|
788
865
|
|
|
@@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"
|
|
|
4
4
|
|
|
5
5
|
[project]
|
|
6
6
|
name = "spotify_profile_monitor"
|
|
7
|
-
version = "2.
|
|
7
|
+
version = "2.7"
|
|
8
8
|
description = "Tool implementing real-time tracking of Spotify users activities and profile changes including playlists"
|
|
9
9
|
readme = "README.md"
|
|
10
10
|
license = "GPL-3.0-or-later"
|
|
@@ -20,6 +20,7 @@ dependencies = [
|
|
|
20
20
|
"tzlocal>=4.0",
|
|
21
21
|
"python-dotenv>=0.19",
|
|
22
22
|
"spotipy>=2.24.0",
|
|
23
|
+
"wcwidth>=0.2.7",
|
|
23
24
|
]
|
|
24
25
|
classifiers = [
|
|
25
26
|
"Programming Language :: Python :: 3",
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: spotify_profile_monitor
|
|
3
|
-
Version: 2.
|
|
3
|
+
Version: 2.7
|
|
4
4
|
Summary: Tool implementing real-time tracking of Spotify users activities and profile changes including playlists
|
|
5
5
|
Author-email: Michal Szymanski <misiektoja-pypi@rm-rf.ninja>
|
|
6
6
|
License-Expression: GPL-3.0-or-later
|
|
@@ -24,13 +24,16 @@ Requires-Dist: pytz>=2020.1
|
|
|
24
24
|
Requires-Dist: tzlocal>=4.0
|
|
25
25
|
Requires-Dist: python-dotenv>=0.19
|
|
26
26
|
Requires-Dist: spotipy>=2.24.0
|
|
27
|
+
Requires-Dist: wcwidth>=0.2.7
|
|
27
28
|
Dynamic: license-file
|
|
28
29
|
|
|
29
30
|
# spotify_profile_monitor
|
|
30
31
|
|
|
31
|
-
OSINT tool for real-time monitoring of Spotify users' activities and profile changes including playlists
|
|
32
|
+
OSINT tool for real-time monitoring of **Spotify users' activities and profile changes including playlists**.
|
|
32
33
|
|
|
33
|
-
|
|
34
|
+
✨ If you want to track Spotify friends' music activity, check out another tool I developed: [spotify_monitor](https://github.com/misiektoja/spotify_monitor).
|
|
35
|
+
|
|
36
|
+
🛠️ If you're looking for debug tools to get Spotify Web Player access tokens and extract secret keys: [click here](#debugging-tools)
|
|
34
37
|
|
|
35
38
|
<a id="features"></a>
|
|
36
39
|
## Features
|
|
@@ -89,14 +92,17 @@ NOTE: If you want to track Spotify friends' music activity, check out another to
|
|
|
89
92
|
* [Check Intervals](#check-intervals)
|
|
90
93
|
* [Signal Controls (macOS/Linux/Unix)](#signal-controls-macoslinuxunix)
|
|
91
94
|
* [Coloring Log Output with GRC](#coloring-log-output-with-grc)
|
|
92
|
-
6. [
|
|
93
|
-
|
|
95
|
+
6. [Debugging Tools](#debugging-tools)
|
|
96
|
+
* [Access Token Retrieval via sp_dc Cookie and TOTP](#access-token-retrieval-via-sp_dc-cookie-and-totp)
|
|
97
|
+
* [Secret Key Extraction from Spotify Web Player Bundles](#secret-key-extraction-from-spotify-web-player-bundles)
|
|
98
|
+
7. [Change Log](#change-log)
|
|
99
|
+
8. [License](#license)
|
|
94
100
|
|
|
95
101
|
<a id="requirements"></a>
|
|
96
102
|
## Requirements
|
|
97
103
|
|
|
98
104
|
* Python 3.6 or higher
|
|
99
|
-
* Libraries: `requests`, `python-dateutil`, `urllib3`, `pyotp`, `pytz`, `tzlocal`, `python-dotenv`, [Spotipy](https://github.com/spotipy-dev/spotipy)
|
|
105
|
+
* Libraries: `requests`, `python-dateutil`, `urllib3`, `pyotp`, `pytz`, `tzlocal`, `python-dotenv`, [Spotipy](https://github.com/spotipy-dev/spotipy), `wcwidth`
|
|
100
106
|
|
|
101
107
|
Tested on:
|
|
102
108
|
|
|
@@ -124,7 +130,7 @@ Download the *[spotify_profile_monitor.py](https://raw.githubusercontent.com/mis
|
|
|
124
130
|
Install dependencies via pip:
|
|
125
131
|
|
|
126
132
|
```sh
|
|
127
|
-
pip install requests python-dateutil urllib3 pyotp pytz tzlocal python-dotenv spotipy
|
|
133
|
+
pip install requests python-dateutil urllib3 pyotp pytz tzlocal python-dotenv spotipy wcwidth
|
|
128
134
|
```
|
|
129
135
|
|
|
130
136
|
Alternatively, from the downloaded *[requirements.txt](https://raw.githubusercontent.com/misiektoja/spotify_profile_monitor/refs/heads/main/requirements.txt)*:
|
|
@@ -241,6 +247,8 @@ If your `sp_dc` cookie expires, the tool will notify you via the console and ema
|
|
|
241
247
|
|
|
242
248
|
If you store the `SP_DC_COOKIE` in a dotenv file you can update its value and send a `SIGHUP` signal to reload the file with the new `sp_dc` cookie without restarting the tool. More info in [Storing Secrets](#storing-secrets) and [Signal Controls (macOS/Linux/Unix)](#signal-controls-macoslinuxunix).
|
|
243
249
|
|
|
250
|
+
> **NOTE:** secrets used for TOTP generation (`SECRET_CIPHER_DICT`) expire every two days, that's why since v2.7 the tool fetches it from remote URL (see `SECRET_CIPHER_DICT_URL`); you can also run the [spotify_monitor_secret_grabber](https://github.com/misiektoja/spotify_monitor/blob/dev/debug/spotify_monitor_secret_grabber.py) and extract it by yourself (see [Secret Key Extraction from Spotify Web Player Bundles](#secret-key-extraction-from-spotify-web-player-bundles) for more info).
|
|
251
|
+
|
|
244
252
|
<a id="spotify-desktop-client"></a>
|
|
245
253
|
#### Spotify Desktop Client
|
|
246
254
|
|
|
@@ -811,6 +819,76 @@ Example:
|
|
|
811
819
|
grc tail -F -n 100 spotify_profile_monitor_<user_uri_id/file_suffix>.log
|
|
812
820
|
```
|
|
813
821
|
|
|
822
|
+
<a id="debugging-tools"></a>
|
|
823
|
+
## Debugging Tools
|
|
824
|
+
|
|
825
|
+
To help with troubleshooting and development, two debug utilities are available in the [debug](https://github.com/misiektoja/spotify_monitor/tree/dev/debug) directory of the related [spotify_monitor](https://github.com/misiektoja/spotify_monitor) project.
|
|
826
|
+
|
|
827
|
+
<a id="access-token-retrieval-via-sp_dc-cookie-and-totp"></a>
|
|
828
|
+
### Access Token Retrieval via sp_dc Cookie and TOTP
|
|
829
|
+
|
|
830
|
+
The [spotify_monitor_totp_test](https://github.com/misiektoja/spotify_monitor/blob/dev/debug/spotify_monitor_totp_test.py) tool retrieves a Spotify access token using a Web Player `sp_dc` cookie and TOTP parameters.
|
|
831
|
+
|
|
832
|
+
Download from [here](https://github.com/misiektoja/spotify_monitor/blob/dev/debug/spotify_monitor_totp_test.py) or:
|
|
833
|
+
|
|
834
|
+
```sh
|
|
835
|
+
wget https://raw.githubusercontent.com/misiektoja/spotify_monitor/refs/heads/dev/debug/spotify_monitor_totp_test.py
|
|
836
|
+
```
|
|
837
|
+
|
|
838
|
+
Install requirements:
|
|
839
|
+
|
|
840
|
+
```sh
|
|
841
|
+
pip install requests python-dateutil pyotp
|
|
842
|
+
```
|
|
843
|
+
|
|
844
|
+
Run:
|
|
845
|
+
|
|
846
|
+
```sh
|
|
847
|
+
python3 spotify_monitor_totp_test.py --sp-dc "your_sp_dc_cookie_value"
|
|
848
|
+
```
|
|
849
|
+
|
|
850
|
+
You should get a valid Spotify access token, example output:
|
|
851
|
+
|
|
852
|
+
<p align="center">
|
|
853
|
+
<img src="https://raw.githubusercontent.com/misiektoja/spotify_monitor/refs/heads/main/assets/spotify_monitor_totp_test.png" alt="spotify_monitor_totp_test" width="100%"/>
|
|
854
|
+
</p>
|
|
855
|
+
|
|
856
|
+
> **NOTE:** secrets used for TOTP generation (`SECRET_CIPHER_DICT`) expire every two days; you can either run the [spotify_monitor_secret_grabber](https://github.com/misiektoja/spotify_monitor/blob/dev/debug/spotify_monitor_secret_grabber.py) and extract it by yourself (see [here](#secret-key-extraction-from-spotify-web-player-bundles) for more info) or you can pass `--fetch-secrets` flag in [spotify_monitor_totp_test](https://github.com/misiektoja/spotify_monitor/blob/dev/debug/spotify_monitor_totp_test.py) (available since v1.6). There is also a [Thereallo1026/spotify-secrets](https://github.com/Thereallo1026/spotify-secrets) repo which offers JSON files that are automatically updated with current secrets.
|
|
857
|
+
|
|
858
|
+
<a id="secret-key-extraction-from-spotify-web-player-bundles"></a>
|
|
859
|
+
### Secret Key Extraction from Spotify Web Player Bundles
|
|
860
|
+
|
|
861
|
+
The [spotify_monitor_secret_grabber](https://github.com/misiektoja/spotify_monitor/blob/dev/debug/spotify_monitor_secret_grabber.py) tool automatically extracts secret keys used for TOTP generation in Spotify Web Player JavaScript bundles.
|
|
862
|
+
|
|
863
|
+
Download from [here](https://github.com/misiektoja/spotify_monitor/blob/dev/debug/spotify_monitor_secret_grabber.py) or:
|
|
864
|
+
|
|
865
|
+
```sh
|
|
866
|
+
wget https://raw.githubusercontent.com/misiektoja/spotify_monitor/refs/heads/dev/debug/spotify_monitor_secret_grabber.py
|
|
867
|
+
```
|
|
868
|
+
|
|
869
|
+
Install requirements:
|
|
870
|
+
|
|
871
|
+
```sh
|
|
872
|
+
pip install playwright
|
|
873
|
+
playwright install
|
|
874
|
+
```
|
|
875
|
+
|
|
876
|
+
Run:
|
|
877
|
+
|
|
878
|
+
```sh
|
|
879
|
+
python3 spotify_monitor_secret_grabber.py
|
|
880
|
+
```
|
|
881
|
+
|
|
882
|
+
You should get output similar to below:
|
|
883
|
+
|
|
884
|
+
<p align="center">
|
|
885
|
+
<img src="https://raw.githubusercontent.com/misiektoja/spotify_monitor/refs/heads/main/assets/spotify_monitor_secret_grabber.png" alt="spotify_monitor_secret_grabber" width="100%"/>
|
|
886
|
+
</p>
|
|
887
|
+
|
|
888
|
+
You can now update the secrets used for TOTP generation (for example `SECRET_CIPHER_DICT` in `spotify_monitor_totp_test`, `spotify_monitor` and `spotify_profile_monitor`).
|
|
889
|
+
|
|
890
|
+
> **NOTE:** you can also use [Thereallo1026/spotify-secrets](https://github.com/Thereallo1026/spotify-secrets) repo which offers JSON files that are automatically updated with current secrets (its secret extraction code is based on `spotify_monitor_secret_grabber`).
|
|
891
|
+
|
|
814
892
|
<a id="change-log"></a>
|
|
815
893
|
## Change Log
|
|
816
894
|
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
#!/usr/bin/env python3
|
|
2
2
|
"""
|
|
3
3
|
Author: Michal Szymanski <misiektoja-github@rm-rf.ninja>
|
|
4
|
-
v2.
|
|
4
|
+
v2.7
|
|
5
5
|
|
|
6
6
|
OSINT tool implementing real-time tracking of Spotify users activities and profile changes including playlists:
|
|
7
7
|
https://github.com/misiektoja/spotify_profile_monitor/
|
|
@@ -16,9 +16,10 @@ pytz
|
|
|
16
16
|
tzlocal (optional)
|
|
17
17
|
python-dotenv (optional)
|
|
18
18
|
spotipy (optional, needed when the token source is set to oauth_app)
|
|
19
|
+
wcwidth (optional, needed by TRUNCATE_CHARS feature)
|
|
19
20
|
"""
|
|
20
21
|
|
|
21
|
-
VERSION = "2.
|
|
22
|
+
VERSION = "2.7"
|
|
22
23
|
|
|
23
24
|
# ---------------------------
|
|
24
25
|
# CONFIGURATION SECTION START
|
|
@@ -246,14 +247,38 @@ TRUNCATE_CHARS = 0
|
|
|
246
247
|
# Value used by signal handlers to increase or decrease profile check interval (SPOTIFY_CHECK_INTERVAL); in seconds
|
|
247
248
|
SPOTIFY_CHECK_SIGNAL_VALUE = 300 # 5 minutes
|
|
248
249
|
|
|
250
|
+
# ---------------------------------------------------------------------
|
|
251
|
+
|
|
252
|
+
# The section below is used when the token source is set to 'cookie'
|
|
253
|
+
|
|
249
254
|
# Maximum number of attempts to get a valid access token in a single run of the spotify_get_access_token_from_sp_dc() function
|
|
250
|
-
|
|
251
|
-
TOKEN_MAX_RETRIES = 10
|
|
255
|
+
TOKEN_MAX_RETRIES = 3
|
|
252
256
|
|
|
253
257
|
# Interval between access token retry attempts; in seconds
|
|
254
|
-
# Used only when the token source is set to 'cookie'
|
|
255
258
|
TOKEN_RETRY_TIMEOUT = 0.5 # 0.5 second
|
|
256
259
|
|
|
260
|
+
# Mapping of TOTP version identifiers to the secrets needed for TOTP generation
|
|
261
|
+
# Newest secrets are downloaded automatically from SECRET_CIPHER_DICT_URL (see below)
|
|
262
|
+
# Can also be fetched via spotify_monitor_secret_grabber.py utility - see debug dir
|
|
263
|
+
SECRET_CIPHER_DICT = {
|
|
264
|
+
"12": [107, 81, 49, 57, 67, 93, 87, 81, 69, 67, 40, 93, 48, 50, 46, 91, 94, 113, 41, 108, 77, 107, 34],
|
|
265
|
+
"11": [111, 45, 40, 73, 95, 74, 35, 85, 105, 107, 60, 110, 55, 72, 69, 70, 114, 83, 63, 88, 91],
|
|
266
|
+
"10": [61, 110, 58, 98, 35, 79, 117, 69, 102, 72, 92, 102, 69, 93, 41, 101, 42, 75],
|
|
267
|
+
"9": [109, 101, 90, 99, 66, 92, 116, 108, 85, 70, 86, 49, 68, 54, 87, 50, 72, 121, 52, 64, 57, 43, 36, 81, 97, 72, 53, 41, 78, 56],
|
|
268
|
+
"8": [37, 84, 32, 76, 87, 90, 87, 47, 13, 75, 48, 54, 44, 28, 19, 21, 22],
|
|
269
|
+
"7": [59, 91, 66, 74, 30, 66, 74, 38, 46, 50, 72, 61, 44, 71, 86, 39, 89],
|
|
270
|
+
"6": [21, 24, 85, 46, 48, 35, 33, 8, 11, 63, 76, 12, 55, 77, 14, 7, 54],
|
|
271
|
+
"5": [12, 56, 76, 33, 88, 44, 88, 33, 78, 78, 11, 66, 22, 22, 55, 69, 54],
|
|
272
|
+
}
|
|
273
|
+
|
|
274
|
+
# Remote URL used to fetch updated secrets needed for TOTP generation
|
|
275
|
+
# Set to empty string to disable
|
|
276
|
+
SECRET_CIPHER_DICT_URL = "https://github.com/Thereallo1026/spotify-secrets/blob/main/secrets/secretDict.json?raw=true"
|
|
277
|
+
|
|
278
|
+
# Identifier used to select the appropriate secret from SECRET_CIPHER_DICT when generating a TOTP token
|
|
279
|
+
# Set to 0 to auto-select the highest available version
|
|
280
|
+
TOTP_VER = 0
|
|
281
|
+
|
|
257
282
|
# ---------------------------------------------------------------------
|
|
258
283
|
|
|
259
284
|
# The section below is used when the token source is set to 'oauth_app'
|
|
@@ -521,6 +546,9 @@ CLEAR_SCREEN = False
|
|
|
521
546
|
SPOTIFY_CHECK_SIGNAL_VALUE = 0
|
|
522
547
|
TOKEN_MAX_RETRIES = 0
|
|
523
548
|
TOKEN_RETRY_TIMEOUT = 0.0
|
|
549
|
+
SECRET_CIPHER_DICT = {}
|
|
550
|
+
SECRET_CIPHER_DICT_URL = ""
|
|
551
|
+
TOTP_VER = 0
|
|
524
552
|
TRUNCATE_CHARS = 0
|
|
525
553
|
|
|
526
554
|
exec(CONFIG_BLOCK, globals())
|
|
@@ -554,9 +582,6 @@ TOKEN_URL = "https://open.spotify.com/api/token"
|
|
|
554
582
|
# URL of the endpoint to get server time needed to create TOTP object
|
|
555
583
|
SERVER_TIME_URL = "https://open.spotify.com/"
|
|
556
584
|
|
|
557
|
-
# Identifier used to select the appropriate encrypted secret from secret_cipher_dict when generating a TOTP token
|
|
558
|
-
TOTP_VER = 10
|
|
559
|
-
|
|
560
585
|
# Variables for caching functionality of the Spotify client token to avoid unnecessary refreshing
|
|
561
586
|
SP_CACHED_CLIENT_TOKEN = None
|
|
562
587
|
SP_CLIENT_TOKEN_EXPIRES_AT = 0
|
|
@@ -661,14 +686,30 @@ SESSION.mount("http://", adapter)
|
|
|
661
686
|
|
|
662
687
|
|
|
663
688
|
# Truncates each line of a string to a specified number of characters including tab expansion and multi-line support
|
|
664
|
-
def truncate_string_per_line(message,
|
|
689
|
+
def truncate_string_per_line(message, truncate_width, tabsize=8):
|
|
690
|
+
try:
|
|
691
|
+
from wcwidth import wcwidth
|
|
692
|
+
except ImportError:
|
|
693
|
+
return message
|
|
694
|
+
|
|
665
695
|
lines = message.split('\n')
|
|
666
696
|
truncated_lines = []
|
|
667
697
|
|
|
668
698
|
for line in lines:
|
|
669
|
-
expanded_line = line.expandtabs(tabsize
|
|
670
|
-
|
|
671
|
-
|
|
699
|
+
expanded_line = line.expandtabs(tabsize)
|
|
700
|
+
current_width = 0
|
|
701
|
+
truncated = ''
|
|
702
|
+
|
|
703
|
+
for char in expanded_line:
|
|
704
|
+
char_width = wcwidth(char)
|
|
705
|
+
if char_width < 0:
|
|
706
|
+
char_width = 0 # Non-printable or unknown width
|
|
707
|
+
if current_width + char_width > truncate_width:
|
|
708
|
+
break
|
|
709
|
+
truncated += char
|
|
710
|
+
current_width += char_width
|
|
711
|
+
|
|
712
|
+
truncated_lines.append(truncated)
|
|
672
713
|
|
|
673
714
|
return '\n'.join(truncated_lines)
|
|
674
715
|
|
|
@@ -1437,15 +1478,10 @@ def fetch_server_time(session: req.Session, ua: str) -> int:
|
|
|
1437
1478
|
def generate_totp():
|
|
1438
1479
|
import pyotp
|
|
1439
1480
|
|
|
1440
|
-
|
|
1441
|
-
"
|
|
1442
|
-
|
|
1443
|
-
|
|
1444
|
-
"7": [59, 91, 66, 74, 30, 66, 74, 38, 46, 50, 72, 61, 44, 71, 86, 39, 89],
|
|
1445
|
-
"6": [21, 24, 85, 46, 48, 35, 33, 8, 11, 63, 76, 12, 55, 77, 14, 7, 54],
|
|
1446
|
-
"5": [12, 56, 76, 33, 88, 44, 88, 33, 78, 78, 11, 66, 22, 22, 55, 69, 54],
|
|
1447
|
-
}
|
|
1448
|
-
secret_cipher_bytes = secret_cipher_dict[str(TOTP_VER)]
|
|
1481
|
+
if str((ver := TOTP_VER or max(map(int, SECRET_CIPHER_DICT)))) not in SECRET_CIPHER_DICT:
|
|
1482
|
+
raise Exception(f"generate_totp(): Defined TOTP_VER ({ver}) is missing in SECRET_CIPHER_DICT")
|
|
1483
|
+
|
|
1484
|
+
secret_cipher_bytes = SECRET_CIPHER_DICT[str(ver)]
|
|
1449
1485
|
|
|
1450
1486
|
transformed = [e ^ ((t % 33) + 9) for t, e in enumerate(secret_cipher_bytes)]
|
|
1451
1487
|
joined = "".join(str(num) for num in transformed)
|
|
@@ -1455,6 +1491,34 @@ def generate_totp():
|
|
|
1455
1491
|
return pyotp.TOTP(secret, digits=6, interval=30)
|
|
1456
1492
|
|
|
1457
1493
|
|
|
1494
|
+
def fetch_and_update_secrets():
|
|
1495
|
+
global SECRET_CIPHER_DICT
|
|
1496
|
+
|
|
1497
|
+
if not SECRET_CIPHER_DICT_URL:
|
|
1498
|
+
return False
|
|
1499
|
+
|
|
1500
|
+
try:
|
|
1501
|
+
response = req.get(SECRET_CIPHER_DICT_URL, timeout=FUNCTION_TIMEOUT, verify=VERIFY_SSL)
|
|
1502
|
+
response.raise_for_status()
|
|
1503
|
+
secrets = response.json()
|
|
1504
|
+
|
|
1505
|
+
if not isinstance(secrets, dict) or not secrets:
|
|
1506
|
+
raise ValueError("fetch_and_update_secrets(): Fetched payload not a non‑empty dict")
|
|
1507
|
+
|
|
1508
|
+
for key, value in secrets.items():
|
|
1509
|
+
if not isinstance(key, str) or not key.isdigit():
|
|
1510
|
+
raise ValueError(f"fetch_and_update_secrets(): Invalid key format: {key}")
|
|
1511
|
+
if not isinstance(value, list) or not all(isinstance(x, int) for x in value):
|
|
1512
|
+
raise ValueError(f"fetch_and_update_secrets(): Invalid value format for key {key}")
|
|
1513
|
+
|
|
1514
|
+
SECRET_CIPHER_DICT = secrets
|
|
1515
|
+
return True
|
|
1516
|
+
|
|
1517
|
+
except Exception as e:
|
|
1518
|
+
print(f"fetch_and_update_secrets(): Failed to get new secrets: {e}")
|
|
1519
|
+
return False
|
|
1520
|
+
|
|
1521
|
+
|
|
1458
1522
|
# Refreshes the Spotify access token using the sp_dc cookie, tries first with mode "transport" and if needed with "init"
|
|
1459
1523
|
def refresh_access_token_from_sp_dc(sp_dc: str) -> dict:
|
|
1460
1524
|
transport = True
|
|
@@ -1554,29 +1618,52 @@ def spotify_get_access_token_from_sp_dc(sp_dc: str):
|
|
|
1554
1618
|
max_retries = TOKEN_MAX_RETRIES
|
|
1555
1619
|
retry = 0
|
|
1556
1620
|
|
|
1557
|
-
|
|
1558
|
-
token_data = refresh_access_token_from_sp_dc(sp_dc)
|
|
1559
|
-
token = token_data["access_token"]
|
|
1560
|
-
client_id = token_data.get("client_id", "")
|
|
1561
|
-
length = token_data["length"]
|
|
1621
|
+
last_error = ""
|
|
1562
1622
|
|
|
1563
|
-
|
|
1564
|
-
|
|
1565
|
-
|
|
1566
|
-
|
|
1567
|
-
|
|
1623
|
+
while retry < max_retries:
|
|
1624
|
+
try:
|
|
1625
|
+
token_data = refresh_access_token_from_sp_dc(sp_dc)
|
|
1626
|
+
token = token_data["access_token"]
|
|
1627
|
+
client_id = token_data.get("client_id", "")
|
|
1628
|
+
length = token_data["length"]
|
|
1629
|
+
|
|
1630
|
+
SP_CACHED_ACCESS_TOKEN = token
|
|
1631
|
+
SP_ACCESS_TOKEN_EXPIRES_AT = token_data["expires_at"]
|
|
1632
|
+
SP_CACHED_CLIENT_ID = client_id
|
|
1633
|
+
|
|
1634
|
+
if SP_CACHED_ACCESS_TOKEN is None or not check_token_validity(SP_CACHED_ACCESS_TOKEN, SP_CACHED_CLIENT_ID, USER_AGENT):
|
|
1635
|
+
retry += 1
|
|
1636
|
+
time.sleep(TOKEN_RETRY_TIMEOUT)
|
|
1637
|
+
else:
|
|
1638
|
+
break
|
|
1639
|
+
except Exception as e:
|
|
1640
|
+
last_error = str(e)
|
|
1568
1641
|
retry += 1
|
|
1569
|
-
|
|
1570
|
-
|
|
1571
|
-
break
|
|
1642
|
+
if retry < max_retries:
|
|
1643
|
+
time.sleep(TOKEN_RETRY_TIMEOUT)
|
|
1572
1644
|
|
|
1573
1645
|
if retry == max_retries:
|
|
1574
|
-
|
|
1575
|
-
|
|
1576
|
-
|
|
1577
|
-
|
|
1578
|
-
|
|
1579
|
-
|
|
1646
|
+
|
|
1647
|
+
if fetch_and_update_secrets():
|
|
1648
|
+
try:
|
|
1649
|
+
token_data = refresh_access_token_from_sp_dc(sp_dc)
|
|
1650
|
+
token = token_data["access_token"]
|
|
1651
|
+
client_id = token_data.get("client_id", "")
|
|
1652
|
+
length = token_data["length"]
|
|
1653
|
+
|
|
1654
|
+
SP_CACHED_ACCESS_TOKEN = token
|
|
1655
|
+
SP_ACCESS_TOKEN_EXPIRES_AT = token_data["expires_at"]
|
|
1656
|
+
SP_CACHED_CLIENT_ID = client_id
|
|
1657
|
+
|
|
1658
|
+
if SP_CACHED_ACCESS_TOKEN and check_token_validity(SP_CACHED_ACCESS_TOKEN, SP_CACHED_CLIENT_ID, USER_AGENT):
|
|
1659
|
+
return SP_CACHED_ACCESS_TOKEN
|
|
1660
|
+
except Exception as e:
|
|
1661
|
+
last_error = str(e)
|
|
1662
|
+
|
|
1663
|
+
error_msg = f"Failed to obtain a valid Spotify access token after {max_retries} attempts"
|
|
1664
|
+
if last_error:
|
|
1665
|
+
error_msg += f": {last_error}"
|
|
1666
|
+
raise RuntimeError(error_msg)
|
|
1580
1667
|
|
|
1581
1668
|
return SP_CACHED_ACCESS_TOKEN
|
|
1582
1669
|
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|