spotify-monitor 2.3.1__tar.gz → 2.5__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.
Potentially problematic release.
This version of spotify-monitor might be problematic. Click here for more details.
- {spotify_monitor-2.3.1 → spotify_monitor-2.5}/PKG-INFO +146 -10
- {spotify_monitor-2.3.1 → spotify_monitor-2.5}/README.md +145 -9
- {spotify_monitor-2.3.1 → spotify_monitor-2.5}/pyproject.toml +1 -1
- {spotify_monitor-2.3.1 → spotify_monitor-2.5}/spotify_monitor.egg-info/PKG-INFO +146 -10
- {spotify_monitor-2.3.1 → spotify_monitor-2.5}/spotify_monitor.py +124 -33
- {spotify_monitor-2.3.1 → spotify_monitor-2.5}/LICENSE +0 -0
- {spotify_monitor-2.3.1 → spotify_monitor-2.5}/setup.cfg +0 -0
- {spotify_monitor-2.3.1 → spotify_monitor-2.5}/spotify_monitor.egg-info/SOURCES.txt +0 -0
- {spotify_monitor-2.3.1 → spotify_monitor-2.5}/spotify_monitor.egg-info/dependency_links.txt +0 -0
- {spotify_monitor-2.3.1 → spotify_monitor-2.5}/spotify_monitor.egg-info/entry_points.txt +0 -0
- {spotify_monitor-2.3.1 → spotify_monitor-2.5}/spotify_monitor.egg-info/requires.txt +0 -0
- {spotify_monitor-2.3.1 → spotify_monitor-2.5}/spotify_monitor.egg-info/top_level.txt +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: spotify_monitor
|
|
3
|
-
Version: 2.
|
|
3
|
+
Version: 2.5
|
|
4
4
|
Summary: Tool implementing real-time tracking of Spotify friends music activity
|
|
5
5
|
Author-email: Michal Szymanski <misiektoja-pypi@rm-rf.ninja>
|
|
6
6
|
License-Expression: GPL-3.0-or-later
|
|
@@ -26,7 +26,7 @@ Dynamic: license-file
|
|
|
26
26
|
|
|
27
27
|
# spotify_monitor
|
|
28
28
|
|
|
29
|
-
Tool for real-time monitoring of Spotify friends' music activity feed
|
|
29
|
+
Tool for real-time monitoring of **Spotify friends' music activity feed**.
|
|
30
30
|
|
|
31
31
|
✨ If you're interested in tracking changes to Spotify users' profiles including their playlists, take a look at another tool I've developed: [spotify_profile_monitor](https://github.com/misiektoja/spotify_profile_monitor).
|
|
32
32
|
|
|
@@ -77,8 +77,11 @@ Tool for real-time monitoring of Spotify friends' music activity feed.
|
|
|
77
77
|
* [Signal Controls (macOS/Linux/Unix)](#signal-controls-macoslinuxunix)
|
|
78
78
|
* [Coloring Log Output with GRC](#coloring-log-output-with-grc)
|
|
79
79
|
6. [Debugging Tools](#debugging-tools)
|
|
80
|
+
* [Access Token Retrieval via sp_dc Cookie and TOTP](#access-token-retrieval-via-sp_dc-cookie-and-totp)
|
|
81
|
+
* [Secret Key Extraction from Spotify Web Player Bundles](#secret-key-extraction-from-spotify-web-player-bundles)
|
|
80
82
|
7. [Change Log](#change-log)
|
|
81
|
-
8. [
|
|
83
|
+
8. [Maintainers](#maintainers)
|
|
84
|
+
9. [License](#license)
|
|
82
85
|
|
|
83
86
|
<a id="requirements"></a>
|
|
84
87
|
## Requirements
|
|
@@ -88,8 +91,8 @@ Tool for real-time monitoring of Spotify friends' music activity feed.
|
|
|
88
91
|
|
|
89
92
|
Tested on:
|
|
90
93
|
|
|
91
|
-
* **macOS**: Ventura, Sonoma, Sequoia
|
|
92
|
-
* **Linux**: Raspberry Pi OS (Bullseye, Bookworm), Ubuntu 24, Rocky Linux 8.x/9.x, Kali Linux 2024/2025
|
|
94
|
+
* **macOS**: Ventura, Sonoma, Sequoia, Tahoe
|
|
95
|
+
* **Linux**: Raspberry Pi OS (Bullseye, Bookworm, Trixie), Ubuntu 24/25, Rocky Linux 8.x/9.x, Kali Linux 2024/2025
|
|
93
96
|
* **Windows**: 10, 11
|
|
94
97
|
|
|
95
98
|
It should work on other versions of macOS, Linux, Unix and Windows as well.
|
|
@@ -112,7 +115,7 @@ Download the *[spotify_monitor.py](https://raw.githubusercontent.com/misiektoja/
|
|
|
112
115
|
Install dependencies via pip:
|
|
113
116
|
|
|
114
117
|
```sh
|
|
115
|
-
pip install requests python-dateutil urllib3 pyotp python-dotenv
|
|
118
|
+
pip install requests python-dateutil urllib3 pyotp python-dotenv wcwidth
|
|
116
119
|
```
|
|
117
120
|
|
|
118
121
|
Alternatively, from the downloaded *[requirements.txt](https://raw.githubusercontent.com/misiektoja/spotify_monitor/refs/heads/main/requirements.txt)*:
|
|
@@ -199,7 +202,7 @@ If your `sp_dc` cookie expires, the tool will notify you via the console and ema
|
|
|
199
202
|
|
|
200
203
|
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).
|
|
201
204
|
|
|
202
|
-
|
|
205
|
+
> **NOTE:** secrets used for TOTP generation (`SECRET_CIPHER_DICT`) expire every two days, that's why since v2.4 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).
|
|
203
206
|
|
|
204
207
|
<a id="spotify-desktop-client"></a>
|
|
205
208
|
#### Spotify Desktop Client
|
|
@@ -572,32 +575,165 @@ grc tail -F -n 100 spotify_monitor_<user_uri_id/file_suffix>.log
|
|
|
572
575
|
<a id="debugging-tools"></a>
|
|
573
576
|
## Debugging Tools
|
|
574
577
|
|
|
575
|
-
To help with troubleshooting and development, two debug utilities are available in the
|
|
578
|
+
To help with troubleshooting and development, two debug utilities are available in the [debug](https://github.com/misiektoja/spotify_monitor/tree/dev/debug) directory.
|
|
576
579
|
|
|
577
|
-
|
|
580
|
+
<a id="access-token-retrieval-via-sp_dc-cookie-and-totp"></a>
|
|
581
|
+
### Access Token Retrieval via sp_dc Cookie and TOTP
|
|
582
|
+
|
|
583
|
+
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.
|
|
584
|
+
|
|
585
|
+
Download from [here](https://github.com/misiektoja/spotify_monitor/blob/dev/debug/spotify_monitor_totp_test.py) or:
|
|
586
|
+
|
|
587
|
+
```sh
|
|
588
|
+
wget https://raw.githubusercontent.com/misiektoja/spotify_monitor/refs/heads/dev/debug/spotify_monitor_totp_test.py
|
|
589
|
+
```
|
|
590
|
+
|
|
591
|
+
Install requirements:
|
|
578
592
|
|
|
579
593
|
```sh
|
|
580
594
|
pip install requests python-dateutil pyotp
|
|
595
|
+
```
|
|
596
|
+
|
|
597
|
+
Run:
|
|
598
|
+
|
|
599
|
+
```sh
|
|
581
600
|
python3 spotify_monitor_totp_test.py --sp-dc "your_sp_dc_cookie_value"
|
|
582
601
|
```
|
|
583
602
|
|
|
584
|
-
|
|
603
|
+
You should get a valid Spotify access token, example output:
|
|
604
|
+
|
|
605
|
+
<p align="center">
|
|
606
|
+
<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%"/>
|
|
607
|
+
</p>
|
|
608
|
+
|
|
609
|
+
> **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` (available since v1.6). There is also a [xyloflake/spot-secrets-go/](https://github.com/xyloflake/spot-secrets-go/) repo which offers JSON files that are automatically updated with current secrets (you can pass `--download-secrets` flag in `spotify_monitor_totp_test` to get it automatically from remote URL, available since v1.8).
|
|
610
|
+
|
|
611
|
+
<a id="secret-key-extraction-from-spotify-web-player-bundles"></a>
|
|
612
|
+
### Secret Key Extraction from Spotify Web Player Bundles
|
|
613
|
+
|
|
614
|
+
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.
|
|
615
|
+
|
|
616
|
+
> 💡 **Quick tip:** The easiest and recommended way to run this tool is via Docker. Jump directly to the [Docker usage section below](#-secret-key-extraction-via-docker-recommended-easiest-way).
|
|
617
|
+
|
|
618
|
+
Download from [here](https://github.com/misiektoja/spotify_monitor/blob/dev/debug/spotify_monitor_secret_grabber.py) or:
|
|
619
|
+
|
|
620
|
+
```sh
|
|
621
|
+
wget https://raw.githubusercontent.com/misiektoja/spotify_monitor/refs/heads/dev/debug/spotify_monitor_secret_grabber.py
|
|
622
|
+
```
|
|
623
|
+
|
|
624
|
+
Install requirements:
|
|
585
625
|
|
|
586
626
|
```sh
|
|
587
627
|
pip install playwright
|
|
588
628
|
playwright install
|
|
629
|
+
```
|
|
630
|
+
|
|
631
|
+
Run interactively (default output mode):
|
|
632
|
+
|
|
633
|
+
```sh
|
|
589
634
|
python3 spotify_monitor_secret_grabber.py
|
|
590
635
|
```
|
|
591
636
|
|
|
637
|
+
You should get output similar to below:
|
|
638
|
+
|
|
592
639
|
<p align="center">
|
|
593
640
|
<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%"/>
|
|
594
641
|
</p>
|
|
595
642
|
|
|
643
|
+
Show help:
|
|
644
|
+
```sh
|
|
645
|
+
python3 spotify_monitor_secret_grabber.py -h
|
|
646
|
+
```
|
|
647
|
+
|
|
648
|
+
---
|
|
649
|
+
|
|
650
|
+
<a id="cli-output-modes"></a>
|
|
651
|
+
### CLI Output Modes
|
|
652
|
+
|
|
653
|
+
The script supports several output modes for different use cases:
|
|
654
|
+
|
|
655
|
+
| Flag | Description | Output |
|
|
656
|
+
|------|--------------|--------|
|
|
657
|
+
| `--secret` | Prints plain JSON array of extracted secrets | `[{"version": X, "secret": "..."}, ...]` |
|
|
658
|
+
| `--secretbytes` | Prints JSON array with ASCII byte values | `[{"version": X, "secret": [..]}, ...]` |
|
|
659
|
+
| `--secretdict` | Prints JSON object/dict mapping version → byte list | `{"X": [..], "Y": [..]}` |
|
|
660
|
+
| `--all` | Extracts secrets and **writes all three outputs** to local files | `secrets.json`, `secretBytes.json`, `secretDict.json` |
|
|
661
|
+
|
|
662
|
+
Print extracted secrets in specific format, for example Python-friendly secret bytes (JSON object/dict) and save to indicated file:
|
|
663
|
+
|
|
664
|
+
```sh
|
|
665
|
+
python3 spotify_monitor_secret_grabber.py --secretdict > secretDict.json
|
|
666
|
+
```
|
|
667
|
+
|
|
668
|
+
Or, to generate and save all secret formats to files (`secrets.json`, `secretBytes.json`, `secretDict.json`) at once:
|
|
669
|
+
|
|
670
|
+
```sh
|
|
671
|
+
python3 spotify_monitor_secret_grabber.py --all
|
|
672
|
+
```
|
|
673
|
+
|
|
674
|
+
Default file paths and names can be configured directly in the `OUTPUT_FILES` dictionary at the top of the script.
|
|
675
|
+
|
|
676
|
+
---
|
|
677
|
+
|
|
678
|
+
<a id="-secret-key-extraction-via-docker-recommended-easiest-way"></a>
|
|
679
|
+
### 🐳 Secret Key Extraction via Docker (Recommended Easiest Way)
|
|
680
|
+
|
|
681
|
+
A prebuilt multi-architecture image is available on Docker Hub: [`misiektoja/spotify-secrets-grabber`](https://hub.docker.com/r/misiektoja/spotify-secrets-grabber)
|
|
682
|
+
|
|
683
|
+
This image works on:
|
|
684
|
+
- macOS (Intel & Apple Silicon)
|
|
685
|
+
- Linux (x86_64 and ARM64)
|
|
686
|
+
- Windows (Docker Desktop / WSL2)
|
|
687
|
+
- Raspberry Pi 4/5 (64-bit OS)
|
|
688
|
+
|
|
689
|
+
Run interactively (default output mode):
|
|
690
|
+
|
|
691
|
+
```sh
|
|
692
|
+
docker run --rm misiektoja/spotify-secrets-grabber
|
|
693
|
+
```
|
|
694
|
+
|
|
695
|
+
Show help:
|
|
696
|
+
```sh
|
|
697
|
+
docker run --rm misiektoja/spotify-secrets-grabber -h
|
|
698
|
+
```
|
|
699
|
+
|
|
700
|
+
Print extracted secrets in specific format, for example Python-friendly secret bytes (JSON object/dict) and save to indicated file:
|
|
701
|
+
```sh
|
|
702
|
+
docker run --rm misiektoja/spotify-secrets-grabber --secretdict > secretDict.json
|
|
703
|
+
```
|
|
704
|
+
|
|
705
|
+
Or, to generate and save all secret formats to files (`secrets.json`, `secretBytes.json`, `secretDict.json`) at once:
|
|
706
|
+
|
|
707
|
+
```sh
|
|
708
|
+
docker run --rm -v .:/work -w /work misiektoja/spotify-secrets-grabber --all
|
|
709
|
+
```
|
|
710
|
+
|
|
711
|
+
*For SELinux hosts (Fedora/RHEL), use `-v .:/work:Z`.*
|
|
712
|
+
|
|
713
|
+
<a id="optional-use-docker-compose-one-command-for-all-oss"></a>
|
|
714
|
+
Or optionally use Docker Compose (a preconfigured [compose.yaml](https://github.com/misiektoja/spotify_monitor/blob/dev/debug/spotify_monitor_secret_grabber_docker/compose.yaml) file is included in the repo):
|
|
715
|
+
|
|
716
|
+
```sh
|
|
717
|
+
docker compose run --rm spotify-secrets-grabber --all
|
|
718
|
+
```
|
|
719
|
+
|
|
720
|
+
This will save all files into your current directory on any system (macOS, Linux or Windows).
|
|
721
|
+
|
|
722
|
+
---
|
|
723
|
+
|
|
724
|
+
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`) either manually or by referencing an external `secretDict.json` file, which can be hosted in another repo or stored locally. See the description of `SECRET_CIPHER_DICT_URL` in those files for details.
|
|
725
|
+
|
|
596
726
|
<a id="change-log"></a>
|
|
597
727
|
## Change Log
|
|
598
728
|
|
|
599
729
|
See [RELEASE_NOTES.md](https://github.com/misiektoja/spotify_monitor/blob/main/RELEASE_NOTES.md) for details.
|
|
600
730
|
|
|
731
|
+
<a id="maintainers"></a>
|
|
732
|
+
## Maintainers
|
|
733
|
+
|
|
734
|
+
[](https://github.com/misiektoja)
|
|
735
|
+
[](https://github.com/tomballgithub)
|
|
736
|
+
|
|
601
737
|
<a id="license"></a>
|
|
602
738
|
## License
|
|
603
739
|
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
# spotify_monitor
|
|
2
2
|
|
|
3
|
-
Tool for real-time monitoring of Spotify friends' music activity feed
|
|
3
|
+
Tool for real-time monitoring of **Spotify friends' music activity feed**.
|
|
4
4
|
|
|
5
5
|
✨ If you're interested in tracking changes to Spotify users' profiles including their playlists, take a look at another tool I've developed: [spotify_profile_monitor](https://github.com/misiektoja/spotify_profile_monitor).
|
|
6
6
|
|
|
@@ -51,8 +51,11 @@ Tool for real-time monitoring of Spotify friends' music activity feed.
|
|
|
51
51
|
* [Signal Controls (macOS/Linux/Unix)](#signal-controls-macoslinuxunix)
|
|
52
52
|
* [Coloring Log Output with GRC](#coloring-log-output-with-grc)
|
|
53
53
|
6. [Debugging Tools](#debugging-tools)
|
|
54
|
+
* [Access Token Retrieval via sp_dc Cookie and TOTP](#access-token-retrieval-via-sp_dc-cookie-and-totp)
|
|
55
|
+
* [Secret Key Extraction from Spotify Web Player Bundles](#secret-key-extraction-from-spotify-web-player-bundles)
|
|
54
56
|
7. [Change Log](#change-log)
|
|
55
|
-
8. [
|
|
57
|
+
8. [Maintainers](#maintainers)
|
|
58
|
+
9. [License](#license)
|
|
56
59
|
|
|
57
60
|
<a id="requirements"></a>
|
|
58
61
|
## Requirements
|
|
@@ -62,8 +65,8 @@ Tool for real-time monitoring of Spotify friends' music activity feed.
|
|
|
62
65
|
|
|
63
66
|
Tested on:
|
|
64
67
|
|
|
65
|
-
* **macOS**: Ventura, Sonoma, Sequoia
|
|
66
|
-
* **Linux**: Raspberry Pi OS (Bullseye, Bookworm), Ubuntu 24, Rocky Linux 8.x/9.x, Kali Linux 2024/2025
|
|
68
|
+
* **macOS**: Ventura, Sonoma, Sequoia, Tahoe
|
|
69
|
+
* **Linux**: Raspberry Pi OS (Bullseye, Bookworm, Trixie), Ubuntu 24/25, Rocky Linux 8.x/9.x, Kali Linux 2024/2025
|
|
67
70
|
* **Windows**: 10, 11
|
|
68
71
|
|
|
69
72
|
It should work on other versions of macOS, Linux, Unix and Windows as well.
|
|
@@ -86,7 +89,7 @@ Download the *[spotify_monitor.py](https://raw.githubusercontent.com/misiektoja/
|
|
|
86
89
|
Install dependencies via pip:
|
|
87
90
|
|
|
88
91
|
```sh
|
|
89
|
-
pip install requests python-dateutil urllib3 pyotp python-dotenv
|
|
92
|
+
pip install requests python-dateutil urllib3 pyotp python-dotenv wcwidth
|
|
90
93
|
```
|
|
91
94
|
|
|
92
95
|
Alternatively, from the downloaded *[requirements.txt](https://raw.githubusercontent.com/misiektoja/spotify_monitor/refs/heads/main/requirements.txt)*:
|
|
@@ -173,7 +176,7 @@ If your `sp_dc` cookie expires, the tool will notify you via the console and ema
|
|
|
173
176
|
|
|
174
177
|
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).
|
|
175
178
|
|
|
176
|
-
|
|
179
|
+
> **NOTE:** secrets used for TOTP generation (`SECRET_CIPHER_DICT`) expire every two days, that's why since v2.4 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).
|
|
177
180
|
|
|
178
181
|
<a id="spotify-desktop-client"></a>
|
|
179
182
|
#### Spotify Desktop Client
|
|
@@ -546,32 +549,165 @@ grc tail -F -n 100 spotify_monitor_<user_uri_id/file_suffix>.log
|
|
|
546
549
|
<a id="debugging-tools"></a>
|
|
547
550
|
## Debugging Tools
|
|
548
551
|
|
|
549
|
-
To help with troubleshooting and development, two debug utilities are available in the
|
|
552
|
+
To help with troubleshooting and development, two debug utilities are available in the [debug](https://github.com/misiektoja/spotify_monitor/tree/dev/debug) directory.
|
|
550
553
|
|
|
551
|
-
|
|
554
|
+
<a id="access-token-retrieval-via-sp_dc-cookie-and-totp"></a>
|
|
555
|
+
### Access Token Retrieval via sp_dc Cookie and TOTP
|
|
556
|
+
|
|
557
|
+
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.
|
|
558
|
+
|
|
559
|
+
Download from [here](https://github.com/misiektoja/spotify_monitor/blob/dev/debug/spotify_monitor_totp_test.py) or:
|
|
560
|
+
|
|
561
|
+
```sh
|
|
562
|
+
wget https://raw.githubusercontent.com/misiektoja/spotify_monitor/refs/heads/dev/debug/spotify_monitor_totp_test.py
|
|
563
|
+
```
|
|
564
|
+
|
|
565
|
+
Install requirements:
|
|
552
566
|
|
|
553
567
|
```sh
|
|
554
568
|
pip install requests python-dateutil pyotp
|
|
569
|
+
```
|
|
570
|
+
|
|
571
|
+
Run:
|
|
572
|
+
|
|
573
|
+
```sh
|
|
555
574
|
python3 spotify_monitor_totp_test.py --sp-dc "your_sp_dc_cookie_value"
|
|
556
575
|
```
|
|
557
576
|
|
|
558
|
-
|
|
577
|
+
You should get a valid Spotify access token, example output:
|
|
578
|
+
|
|
579
|
+
<p align="center">
|
|
580
|
+
<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%"/>
|
|
581
|
+
</p>
|
|
582
|
+
|
|
583
|
+
> **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` (available since v1.6). There is also a [xyloflake/spot-secrets-go/](https://github.com/xyloflake/spot-secrets-go/) repo which offers JSON files that are automatically updated with current secrets (you can pass `--download-secrets` flag in `spotify_monitor_totp_test` to get it automatically from remote URL, available since v1.8).
|
|
584
|
+
|
|
585
|
+
<a id="secret-key-extraction-from-spotify-web-player-bundles"></a>
|
|
586
|
+
### Secret Key Extraction from Spotify Web Player Bundles
|
|
587
|
+
|
|
588
|
+
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.
|
|
589
|
+
|
|
590
|
+
> 💡 **Quick tip:** The easiest and recommended way to run this tool is via Docker. Jump directly to the [Docker usage section below](#-secret-key-extraction-via-docker-recommended-easiest-way).
|
|
591
|
+
|
|
592
|
+
Download from [here](https://github.com/misiektoja/spotify_monitor/blob/dev/debug/spotify_monitor_secret_grabber.py) or:
|
|
593
|
+
|
|
594
|
+
```sh
|
|
595
|
+
wget https://raw.githubusercontent.com/misiektoja/spotify_monitor/refs/heads/dev/debug/spotify_monitor_secret_grabber.py
|
|
596
|
+
```
|
|
597
|
+
|
|
598
|
+
Install requirements:
|
|
559
599
|
|
|
560
600
|
```sh
|
|
561
601
|
pip install playwright
|
|
562
602
|
playwright install
|
|
603
|
+
```
|
|
604
|
+
|
|
605
|
+
Run interactively (default output mode):
|
|
606
|
+
|
|
607
|
+
```sh
|
|
563
608
|
python3 spotify_monitor_secret_grabber.py
|
|
564
609
|
```
|
|
565
610
|
|
|
611
|
+
You should get output similar to below:
|
|
612
|
+
|
|
566
613
|
<p align="center">
|
|
567
614
|
<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%"/>
|
|
568
615
|
</p>
|
|
569
616
|
|
|
617
|
+
Show help:
|
|
618
|
+
```sh
|
|
619
|
+
python3 spotify_monitor_secret_grabber.py -h
|
|
620
|
+
```
|
|
621
|
+
|
|
622
|
+
---
|
|
623
|
+
|
|
624
|
+
<a id="cli-output-modes"></a>
|
|
625
|
+
### CLI Output Modes
|
|
626
|
+
|
|
627
|
+
The script supports several output modes for different use cases:
|
|
628
|
+
|
|
629
|
+
| Flag | Description | Output |
|
|
630
|
+
|------|--------------|--------|
|
|
631
|
+
| `--secret` | Prints plain JSON array of extracted secrets | `[{"version": X, "secret": "..."}, ...]` |
|
|
632
|
+
| `--secretbytes` | Prints JSON array with ASCII byte values | `[{"version": X, "secret": [..]}, ...]` |
|
|
633
|
+
| `--secretdict` | Prints JSON object/dict mapping version → byte list | `{"X": [..], "Y": [..]}` |
|
|
634
|
+
| `--all` | Extracts secrets and **writes all three outputs** to local files | `secrets.json`, `secretBytes.json`, `secretDict.json` |
|
|
635
|
+
|
|
636
|
+
Print extracted secrets in specific format, for example Python-friendly secret bytes (JSON object/dict) and save to indicated file:
|
|
637
|
+
|
|
638
|
+
```sh
|
|
639
|
+
python3 spotify_monitor_secret_grabber.py --secretdict > secretDict.json
|
|
640
|
+
```
|
|
641
|
+
|
|
642
|
+
Or, to generate and save all secret formats to files (`secrets.json`, `secretBytes.json`, `secretDict.json`) at once:
|
|
643
|
+
|
|
644
|
+
```sh
|
|
645
|
+
python3 spotify_monitor_secret_grabber.py --all
|
|
646
|
+
```
|
|
647
|
+
|
|
648
|
+
Default file paths and names can be configured directly in the `OUTPUT_FILES` dictionary at the top of the script.
|
|
649
|
+
|
|
650
|
+
---
|
|
651
|
+
|
|
652
|
+
<a id="-secret-key-extraction-via-docker-recommended-easiest-way"></a>
|
|
653
|
+
### 🐳 Secret Key Extraction via Docker (Recommended Easiest Way)
|
|
654
|
+
|
|
655
|
+
A prebuilt multi-architecture image is available on Docker Hub: [`misiektoja/spotify-secrets-grabber`](https://hub.docker.com/r/misiektoja/spotify-secrets-grabber)
|
|
656
|
+
|
|
657
|
+
This image works on:
|
|
658
|
+
- macOS (Intel & Apple Silicon)
|
|
659
|
+
- Linux (x86_64 and ARM64)
|
|
660
|
+
- Windows (Docker Desktop / WSL2)
|
|
661
|
+
- Raspberry Pi 4/5 (64-bit OS)
|
|
662
|
+
|
|
663
|
+
Run interactively (default output mode):
|
|
664
|
+
|
|
665
|
+
```sh
|
|
666
|
+
docker run --rm misiektoja/spotify-secrets-grabber
|
|
667
|
+
```
|
|
668
|
+
|
|
669
|
+
Show help:
|
|
670
|
+
```sh
|
|
671
|
+
docker run --rm misiektoja/spotify-secrets-grabber -h
|
|
672
|
+
```
|
|
673
|
+
|
|
674
|
+
Print extracted secrets in specific format, for example Python-friendly secret bytes (JSON object/dict) and save to indicated file:
|
|
675
|
+
```sh
|
|
676
|
+
docker run --rm misiektoja/spotify-secrets-grabber --secretdict > secretDict.json
|
|
677
|
+
```
|
|
678
|
+
|
|
679
|
+
Or, to generate and save all secret formats to files (`secrets.json`, `secretBytes.json`, `secretDict.json`) at once:
|
|
680
|
+
|
|
681
|
+
```sh
|
|
682
|
+
docker run --rm -v .:/work -w /work misiektoja/spotify-secrets-grabber --all
|
|
683
|
+
```
|
|
684
|
+
|
|
685
|
+
*For SELinux hosts (Fedora/RHEL), use `-v .:/work:Z`.*
|
|
686
|
+
|
|
687
|
+
<a id="optional-use-docker-compose-one-command-for-all-oss"></a>
|
|
688
|
+
Or optionally use Docker Compose (a preconfigured [compose.yaml](https://github.com/misiektoja/spotify_monitor/blob/dev/debug/spotify_monitor_secret_grabber_docker/compose.yaml) file is included in the repo):
|
|
689
|
+
|
|
690
|
+
```sh
|
|
691
|
+
docker compose run --rm spotify-secrets-grabber --all
|
|
692
|
+
```
|
|
693
|
+
|
|
694
|
+
This will save all files into your current directory on any system (macOS, Linux or Windows).
|
|
695
|
+
|
|
696
|
+
---
|
|
697
|
+
|
|
698
|
+
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`) either manually or by referencing an external `secretDict.json` file, which can be hosted in another repo or stored locally. See the description of `SECRET_CIPHER_DICT_URL` in those files for details.
|
|
699
|
+
|
|
570
700
|
<a id="change-log"></a>
|
|
571
701
|
## Change Log
|
|
572
702
|
|
|
573
703
|
See [RELEASE_NOTES.md](https://github.com/misiektoja/spotify_monitor/blob/main/RELEASE_NOTES.md) for details.
|
|
574
704
|
|
|
705
|
+
<a id="maintainers"></a>
|
|
706
|
+
## Maintainers
|
|
707
|
+
|
|
708
|
+
[](https://github.com/misiektoja)
|
|
709
|
+
[](https://github.com/tomballgithub)
|
|
710
|
+
|
|
575
711
|
<a id="license"></a>
|
|
576
712
|
## License
|
|
577
713
|
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: spotify_monitor
|
|
3
|
-
Version: 2.
|
|
3
|
+
Version: 2.5
|
|
4
4
|
Summary: Tool implementing real-time tracking of Spotify friends music activity
|
|
5
5
|
Author-email: Michal Szymanski <misiektoja-pypi@rm-rf.ninja>
|
|
6
6
|
License-Expression: GPL-3.0-or-later
|
|
@@ -26,7 +26,7 @@ Dynamic: license-file
|
|
|
26
26
|
|
|
27
27
|
# spotify_monitor
|
|
28
28
|
|
|
29
|
-
Tool for real-time monitoring of Spotify friends' music activity feed
|
|
29
|
+
Tool for real-time monitoring of **Spotify friends' music activity feed**.
|
|
30
30
|
|
|
31
31
|
✨ If you're interested in tracking changes to Spotify users' profiles including their playlists, take a look at another tool I've developed: [spotify_profile_monitor](https://github.com/misiektoja/spotify_profile_monitor).
|
|
32
32
|
|
|
@@ -77,8 +77,11 @@ Tool for real-time monitoring of Spotify friends' music activity feed.
|
|
|
77
77
|
* [Signal Controls (macOS/Linux/Unix)](#signal-controls-macoslinuxunix)
|
|
78
78
|
* [Coloring Log Output with GRC](#coloring-log-output-with-grc)
|
|
79
79
|
6. [Debugging Tools](#debugging-tools)
|
|
80
|
+
* [Access Token Retrieval via sp_dc Cookie and TOTP](#access-token-retrieval-via-sp_dc-cookie-and-totp)
|
|
81
|
+
* [Secret Key Extraction from Spotify Web Player Bundles](#secret-key-extraction-from-spotify-web-player-bundles)
|
|
80
82
|
7. [Change Log](#change-log)
|
|
81
|
-
8. [
|
|
83
|
+
8. [Maintainers](#maintainers)
|
|
84
|
+
9. [License](#license)
|
|
82
85
|
|
|
83
86
|
<a id="requirements"></a>
|
|
84
87
|
## Requirements
|
|
@@ -88,8 +91,8 @@ Tool for real-time monitoring of Spotify friends' music activity feed.
|
|
|
88
91
|
|
|
89
92
|
Tested on:
|
|
90
93
|
|
|
91
|
-
* **macOS**: Ventura, Sonoma, Sequoia
|
|
92
|
-
* **Linux**: Raspberry Pi OS (Bullseye, Bookworm), Ubuntu 24, Rocky Linux 8.x/9.x, Kali Linux 2024/2025
|
|
94
|
+
* **macOS**: Ventura, Sonoma, Sequoia, Tahoe
|
|
95
|
+
* **Linux**: Raspberry Pi OS (Bullseye, Bookworm, Trixie), Ubuntu 24/25, Rocky Linux 8.x/9.x, Kali Linux 2024/2025
|
|
93
96
|
* **Windows**: 10, 11
|
|
94
97
|
|
|
95
98
|
It should work on other versions of macOS, Linux, Unix and Windows as well.
|
|
@@ -112,7 +115,7 @@ Download the *[spotify_monitor.py](https://raw.githubusercontent.com/misiektoja/
|
|
|
112
115
|
Install dependencies via pip:
|
|
113
116
|
|
|
114
117
|
```sh
|
|
115
|
-
pip install requests python-dateutil urllib3 pyotp python-dotenv
|
|
118
|
+
pip install requests python-dateutil urllib3 pyotp python-dotenv wcwidth
|
|
116
119
|
```
|
|
117
120
|
|
|
118
121
|
Alternatively, from the downloaded *[requirements.txt](https://raw.githubusercontent.com/misiektoja/spotify_monitor/refs/heads/main/requirements.txt)*:
|
|
@@ -199,7 +202,7 @@ If your `sp_dc` cookie expires, the tool will notify you via the console and ema
|
|
|
199
202
|
|
|
200
203
|
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).
|
|
201
204
|
|
|
202
|
-
|
|
205
|
+
> **NOTE:** secrets used for TOTP generation (`SECRET_CIPHER_DICT`) expire every two days, that's why since v2.4 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).
|
|
203
206
|
|
|
204
207
|
<a id="spotify-desktop-client"></a>
|
|
205
208
|
#### Spotify Desktop Client
|
|
@@ -572,32 +575,165 @@ grc tail -F -n 100 spotify_monitor_<user_uri_id/file_suffix>.log
|
|
|
572
575
|
<a id="debugging-tools"></a>
|
|
573
576
|
## Debugging Tools
|
|
574
577
|
|
|
575
|
-
To help with troubleshooting and development, two debug utilities are available in the
|
|
578
|
+
To help with troubleshooting and development, two debug utilities are available in the [debug](https://github.com/misiektoja/spotify_monitor/tree/dev/debug) directory.
|
|
576
579
|
|
|
577
|
-
|
|
580
|
+
<a id="access-token-retrieval-via-sp_dc-cookie-and-totp"></a>
|
|
581
|
+
### Access Token Retrieval via sp_dc Cookie and TOTP
|
|
582
|
+
|
|
583
|
+
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.
|
|
584
|
+
|
|
585
|
+
Download from [here](https://github.com/misiektoja/spotify_monitor/blob/dev/debug/spotify_monitor_totp_test.py) or:
|
|
586
|
+
|
|
587
|
+
```sh
|
|
588
|
+
wget https://raw.githubusercontent.com/misiektoja/spotify_monitor/refs/heads/dev/debug/spotify_monitor_totp_test.py
|
|
589
|
+
```
|
|
590
|
+
|
|
591
|
+
Install requirements:
|
|
578
592
|
|
|
579
593
|
```sh
|
|
580
594
|
pip install requests python-dateutil pyotp
|
|
595
|
+
```
|
|
596
|
+
|
|
597
|
+
Run:
|
|
598
|
+
|
|
599
|
+
```sh
|
|
581
600
|
python3 spotify_monitor_totp_test.py --sp-dc "your_sp_dc_cookie_value"
|
|
582
601
|
```
|
|
583
602
|
|
|
584
|
-
|
|
603
|
+
You should get a valid Spotify access token, example output:
|
|
604
|
+
|
|
605
|
+
<p align="center">
|
|
606
|
+
<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%"/>
|
|
607
|
+
</p>
|
|
608
|
+
|
|
609
|
+
> **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` (available since v1.6). There is also a [xyloflake/spot-secrets-go/](https://github.com/xyloflake/spot-secrets-go/) repo which offers JSON files that are automatically updated with current secrets (you can pass `--download-secrets` flag in `spotify_monitor_totp_test` to get it automatically from remote URL, available since v1.8).
|
|
610
|
+
|
|
611
|
+
<a id="secret-key-extraction-from-spotify-web-player-bundles"></a>
|
|
612
|
+
### Secret Key Extraction from Spotify Web Player Bundles
|
|
613
|
+
|
|
614
|
+
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.
|
|
615
|
+
|
|
616
|
+
> 💡 **Quick tip:** The easiest and recommended way to run this tool is via Docker. Jump directly to the [Docker usage section below](#-secret-key-extraction-via-docker-recommended-easiest-way).
|
|
617
|
+
|
|
618
|
+
Download from [here](https://github.com/misiektoja/spotify_monitor/blob/dev/debug/spotify_monitor_secret_grabber.py) or:
|
|
619
|
+
|
|
620
|
+
```sh
|
|
621
|
+
wget https://raw.githubusercontent.com/misiektoja/spotify_monitor/refs/heads/dev/debug/spotify_monitor_secret_grabber.py
|
|
622
|
+
```
|
|
623
|
+
|
|
624
|
+
Install requirements:
|
|
585
625
|
|
|
586
626
|
```sh
|
|
587
627
|
pip install playwright
|
|
588
628
|
playwright install
|
|
629
|
+
```
|
|
630
|
+
|
|
631
|
+
Run interactively (default output mode):
|
|
632
|
+
|
|
633
|
+
```sh
|
|
589
634
|
python3 spotify_monitor_secret_grabber.py
|
|
590
635
|
```
|
|
591
636
|
|
|
637
|
+
You should get output similar to below:
|
|
638
|
+
|
|
592
639
|
<p align="center">
|
|
593
640
|
<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%"/>
|
|
594
641
|
</p>
|
|
595
642
|
|
|
643
|
+
Show help:
|
|
644
|
+
```sh
|
|
645
|
+
python3 spotify_monitor_secret_grabber.py -h
|
|
646
|
+
```
|
|
647
|
+
|
|
648
|
+
---
|
|
649
|
+
|
|
650
|
+
<a id="cli-output-modes"></a>
|
|
651
|
+
### CLI Output Modes
|
|
652
|
+
|
|
653
|
+
The script supports several output modes for different use cases:
|
|
654
|
+
|
|
655
|
+
| Flag | Description | Output |
|
|
656
|
+
|------|--------------|--------|
|
|
657
|
+
| `--secret` | Prints plain JSON array of extracted secrets | `[{"version": X, "secret": "..."}, ...]` |
|
|
658
|
+
| `--secretbytes` | Prints JSON array with ASCII byte values | `[{"version": X, "secret": [..]}, ...]` |
|
|
659
|
+
| `--secretdict` | Prints JSON object/dict mapping version → byte list | `{"X": [..], "Y": [..]}` |
|
|
660
|
+
| `--all` | Extracts secrets and **writes all three outputs** to local files | `secrets.json`, `secretBytes.json`, `secretDict.json` |
|
|
661
|
+
|
|
662
|
+
Print extracted secrets in specific format, for example Python-friendly secret bytes (JSON object/dict) and save to indicated file:
|
|
663
|
+
|
|
664
|
+
```sh
|
|
665
|
+
python3 spotify_monitor_secret_grabber.py --secretdict > secretDict.json
|
|
666
|
+
```
|
|
667
|
+
|
|
668
|
+
Or, to generate and save all secret formats to files (`secrets.json`, `secretBytes.json`, `secretDict.json`) at once:
|
|
669
|
+
|
|
670
|
+
```sh
|
|
671
|
+
python3 spotify_monitor_secret_grabber.py --all
|
|
672
|
+
```
|
|
673
|
+
|
|
674
|
+
Default file paths and names can be configured directly in the `OUTPUT_FILES` dictionary at the top of the script.
|
|
675
|
+
|
|
676
|
+
---
|
|
677
|
+
|
|
678
|
+
<a id="-secret-key-extraction-via-docker-recommended-easiest-way"></a>
|
|
679
|
+
### 🐳 Secret Key Extraction via Docker (Recommended Easiest Way)
|
|
680
|
+
|
|
681
|
+
A prebuilt multi-architecture image is available on Docker Hub: [`misiektoja/spotify-secrets-grabber`](https://hub.docker.com/r/misiektoja/spotify-secrets-grabber)
|
|
682
|
+
|
|
683
|
+
This image works on:
|
|
684
|
+
- macOS (Intel & Apple Silicon)
|
|
685
|
+
- Linux (x86_64 and ARM64)
|
|
686
|
+
- Windows (Docker Desktop / WSL2)
|
|
687
|
+
- Raspberry Pi 4/5 (64-bit OS)
|
|
688
|
+
|
|
689
|
+
Run interactively (default output mode):
|
|
690
|
+
|
|
691
|
+
```sh
|
|
692
|
+
docker run --rm misiektoja/spotify-secrets-grabber
|
|
693
|
+
```
|
|
694
|
+
|
|
695
|
+
Show help:
|
|
696
|
+
```sh
|
|
697
|
+
docker run --rm misiektoja/spotify-secrets-grabber -h
|
|
698
|
+
```
|
|
699
|
+
|
|
700
|
+
Print extracted secrets in specific format, for example Python-friendly secret bytes (JSON object/dict) and save to indicated file:
|
|
701
|
+
```sh
|
|
702
|
+
docker run --rm misiektoja/spotify-secrets-grabber --secretdict > secretDict.json
|
|
703
|
+
```
|
|
704
|
+
|
|
705
|
+
Or, to generate and save all secret formats to files (`secrets.json`, `secretBytes.json`, `secretDict.json`) at once:
|
|
706
|
+
|
|
707
|
+
```sh
|
|
708
|
+
docker run --rm -v .:/work -w /work misiektoja/spotify-secrets-grabber --all
|
|
709
|
+
```
|
|
710
|
+
|
|
711
|
+
*For SELinux hosts (Fedora/RHEL), use `-v .:/work:Z`.*
|
|
712
|
+
|
|
713
|
+
<a id="optional-use-docker-compose-one-command-for-all-oss"></a>
|
|
714
|
+
Or optionally use Docker Compose (a preconfigured [compose.yaml](https://github.com/misiektoja/spotify_monitor/blob/dev/debug/spotify_monitor_secret_grabber_docker/compose.yaml) file is included in the repo):
|
|
715
|
+
|
|
716
|
+
```sh
|
|
717
|
+
docker compose run --rm spotify-secrets-grabber --all
|
|
718
|
+
```
|
|
719
|
+
|
|
720
|
+
This will save all files into your current directory on any system (macOS, Linux or Windows).
|
|
721
|
+
|
|
722
|
+
---
|
|
723
|
+
|
|
724
|
+
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`) either manually or by referencing an external `secretDict.json` file, which can be hosted in another repo or stored locally. See the description of `SECRET_CIPHER_DICT_URL` in those files for details.
|
|
725
|
+
|
|
596
726
|
<a id="change-log"></a>
|
|
597
727
|
## Change Log
|
|
598
728
|
|
|
599
729
|
See [RELEASE_NOTES.md](https://github.com/misiektoja/spotify_monitor/blob/main/RELEASE_NOTES.md) for details.
|
|
600
730
|
|
|
731
|
+
<a id="maintainers"></a>
|
|
732
|
+
## Maintainers
|
|
733
|
+
|
|
734
|
+
[](https://github.com/misiektoja)
|
|
735
|
+
[](https://github.com/tomballgithub)
|
|
736
|
+
|
|
601
737
|
<a id="license"></a>
|
|
602
738
|
## License
|
|
603
739
|
|
|
@@ -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.5
|
|
5
5
|
|
|
6
6
|
Tool implementing real-time tracking of Spotify friends music activity:
|
|
7
7
|
https://github.com/misiektoja/spotify_monitor/
|
|
@@ -16,7 +16,7 @@ python-dotenv (optional)
|
|
|
16
16
|
wcwidth (optional, needed by TRUNCATE_CHARS feature)
|
|
17
17
|
"""
|
|
18
18
|
|
|
19
|
-
VERSION = "2.
|
|
19
|
+
VERSION = "2.5"
|
|
20
20
|
|
|
21
21
|
# ---------------------------
|
|
22
22
|
# CONFIGURATION SECTION START
|
|
@@ -244,25 +244,28 @@ SPOTIFY_INACTIVITY_CHECK_SIGNAL_VALUE = 30 # 30 seconds
|
|
|
244
244
|
# The section below is used when the token source is set to 'cookie'
|
|
245
245
|
|
|
246
246
|
# Maximum number of attempts to get a valid access token in a single run of the spotify_get_access_token_from_sp_dc() function
|
|
247
|
-
TOKEN_MAX_RETRIES =
|
|
247
|
+
TOKEN_MAX_RETRIES = 3
|
|
248
248
|
|
|
249
249
|
# Interval between access token retry attempts; in seconds
|
|
250
250
|
TOKEN_RETRY_TIMEOUT = 0.5 # 0.5 second
|
|
251
251
|
|
|
252
|
-
# Mapping of TOTP version identifiers to the
|
|
253
|
-
# Newest
|
|
252
|
+
# Mapping of TOTP version identifiers to the secrets needed for TOTP generation
|
|
253
|
+
# Newest secrets are downloaded automatically from SECRET_CIPHER_DICT_URL (see below)
|
|
254
|
+
# Can also be fetched via spotify_monitor_secret_grabber.py utility - see debug dir
|
|
254
255
|
SECRET_CIPHER_DICT = {
|
|
255
|
-
"12": [107, 81, 49, 57, 67, 93, 87, 81, 69, 67, 40, 93, 48, 50, 46, 91, 94, 113, 41, 108, 77, 107, 34],
|
|
256
|
-
"11": [111, 45, 40, 73, 95, 74, 35, 85, 105, 107, 60, 110, 55, 72, 69, 70, 114, 83, 63, 88, 91],
|
|
257
|
-
"10": [61, 110, 58, 98, 35, 79, 117, 69, 102, 72, 92, 102, 69, 93, 41, 101, 42, 75],
|
|
258
|
-
"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],
|
|
259
|
-
"8": [37, 84, 32, 76, 87, 90, 87, 47, 13, 75, 48, 54, 44, 28, 19, 21, 22],
|
|
260
|
-
"7": [59, 91, 66, 74, 30, 66, 74, 38, 46, 50, 72, 61, 44, 71, 86, 39, 89],
|
|
261
256
|
"6": [21, 24, 85, 46, 48, 35, 33, 8, 11, 63, 76, 12, 55, 77, 14, 7, 54],
|
|
262
257
|
"5": [12, 56, 76, 33, 88, 44, 88, 33, 78, 78, 11, 66, 22, 22, 55, 69, 54],
|
|
263
258
|
}
|
|
264
259
|
|
|
265
|
-
#
|
|
260
|
+
# Remote or local URL used to fetch updated secrets needed for TOTP generation
|
|
261
|
+
# Set to empty string to disable
|
|
262
|
+
# If you used "spotify_monitor_secret_grabber.py --secretdict > secretDict.json" specify the file location below
|
|
263
|
+
# SECRET_CIPHER_DICT_URL = "https://github.com/Thereallo1026/spotify-secrets/blob/main/secrets/secretDict.json?raw=true"
|
|
264
|
+
SECRET_CIPHER_DICT_URL = "https://github.com/xyloflake/spot-secrets-go/blob/main/secrets/secretDict.json?raw=true"
|
|
265
|
+
# SECRET_CIPHER_DICT_URL = file:///C:/your_path/secretDict.json
|
|
266
|
+
# SECRET_CIPHER_DICT_URL = "file:///your_path/secretDict.json"
|
|
267
|
+
|
|
268
|
+
# Identifier used to select the appropriate secret from SECRET_CIPHER_DICT when generating a TOTP token
|
|
266
269
|
# Set to 0 to auto-select the highest available version
|
|
267
270
|
TOTP_VER = 0
|
|
268
271
|
|
|
@@ -467,6 +470,7 @@ SPOTIFY_INACTIVITY_CHECK_SIGNAL_VALUE = 0
|
|
|
467
470
|
TOKEN_MAX_RETRIES = 0
|
|
468
471
|
TOKEN_RETRY_TIMEOUT = 0.0
|
|
469
472
|
SECRET_CIPHER_DICT = {}
|
|
473
|
+
SECRET_CIPHER_DICT_URL = ""
|
|
470
474
|
TOTP_VER = 0
|
|
471
475
|
FLAG_FILE = ""
|
|
472
476
|
TRUNCATE_CHARS = 0
|
|
@@ -1276,7 +1280,11 @@ def fetch_server_time(session: req.Session, ua: str) -> int:
|
|
|
1276
1280
|
def generate_totp():
|
|
1277
1281
|
import pyotp
|
|
1278
1282
|
|
|
1279
|
-
|
|
1283
|
+
ver = TOTP_VER or max(map(int, SECRET_CIPHER_DICT))
|
|
1284
|
+
if str(ver) not in SECRET_CIPHER_DICT:
|
|
1285
|
+
raise Exception(f"generate_totp(): Defined TOTP_VER ({ver}) is missing in SECRET_CIPHER_DICT")
|
|
1286
|
+
|
|
1287
|
+
secret_cipher_bytes = SECRET_CIPHER_DICT[str(ver)]
|
|
1280
1288
|
|
|
1281
1289
|
transformed = [e ^ ((t % 33) + 9) for t, e in enumerate(secret_cipher_bytes)]
|
|
1282
1290
|
joined = "".join(str(num) for num in transformed)
|
|
@@ -1286,6 +1294,65 @@ def generate_totp():
|
|
|
1286
1294
|
return pyotp.TOTP(secret, digits=6, interval=30)
|
|
1287
1295
|
|
|
1288
1296
|
|
|
1297
|
+
def fetch_and_update_secrets():
|
|
1298
|
+
global SECRET_CIPHER_DICT
|
|
1299
|
+
|
|
1300
|
+
if not SECRET_CIPHER_DICT_URL:
|
|
1301
|
+
return False
|
|
1302
|
+
|
|
1303
|
+
try:
|
|
1304
|
+
if SECRET_CIPHER_DICT_URL.startswith("file:"):
|
|
1305
|
+
import os
|
|
1306
|
+
from urllib.parse import urlparse, unquote
|
|
1307
|
+
|
|
1308
|
+
parsed = urlparse(SECRET_CIPHER_DICT_URL)
|
|
1309
|
+
|
|
1310
|
+
if parsed.netloc:
|
|
1311
|
+
raw_path = f"/{parsed.netloc}{parsed.path or ''}"
|
|
1312
|
+
else:
|
|
1313
|
+
if SECRET_CIPHER_DICT_URL.startswith("file://"):
|
|
1314
|
+
raw_path = parsed.path or SECRET_CIPHER_DICT_URL[len("file://"):]
|
|
1315
|
+
else:
|
|
1316
|
+
raw_path = parsed.path or SECRET_CIPHER_DICT_URL[len("file:"):]
|
|
1317
|
+
|
|
1318
|
+
raw_path = unquote(raw_path)
|
|
1319
|
+
|
|
1320
|
+
if raw_path.startswith("/~"):
|
|
1321
|
+
raw_path = raw_path[1:]
|
|
1322
|
+
|
|
1323
|
+
if not raw_path.startswith("/") and not raw_path.startswith("~"):
|
|
1324
|
+
raw_path = "/" + raw_path
|
|
1325
|
+
|
|
1326
|
+
path = os.path.expanduser(os.path.expandvars(raw_path))
|
|
1327
|
+
|
|
1328
|
+
print(f"Loading Spotify web-player TOTP secrets from file: {path}")
|
|
1329
|
+
with open(path, "r", encoding="utf-8") as f:
|
|
1330
|
+
secrets = json.load(f)
|
|
1331
|
+
print("─" * HORIZONTAL_LINE)
|
|
1332
|
+
else:
|
|
1333
|
+
print(f"Fetching Spotify web-player TOTP secrets from URL: {SECRET_CIPHER_DICT_URL}")
|
|
1334
|
+
response = req.get(SECRET_CIPHER_DICT_URL, timeout=FUNCTION_TIMEOUT, verify=VERIFY_SSL)
|
|
1335
|
+
response.raise_for_status()
|
|
1336
|
+
secrets = response.json()
|
|
1337
|
+
print("─" * HORIZONTAL_LINE)
|
|
1338
|
+
|
|
1339
|
+
if not isinstance(secrets, dict) or not secrets:
|
|
1340
|
+
raise ValueError("fetch_and_update_secrets(): Fetched payload not a non-empty dict")
|
|
1341
|
+
|
|
1342
|
+
for key, value in secrets.items():
|
|
1343
|
+
if not isinstance(key, str) or not key.isdigit():
|
|
1344
|
+
raise ValueError(f"fetch_and_update_secrets(): Invalid key format: {key}")
|
|
1345
|
+
if not isinstance(value, list) or not all(isinstance(x, int) for x in value):
|
|
1346
|
+
raise ValueError(f"fetch_and_update_secrets(): Invalid value format for key {key}")
|
|
1347
|
+
|
|
1348
|
+
SECRET_CIPHER_DICT = secrets
|
|
1349
|
+
return True
|
|
1350
|
+
|
|
1351
|
+
except Exception as e:
|
|
1352
|
+
print(f"fetch_and_update_secrets(): Failed to get new secrets: {e}")
|
|
1353
|
+
return False
|
|
1354
|
+
|
|
1355
|
+
|
|
1289
1356
|
# Refreshes the Spotify access token using the sp_dc cookie, tries first with mode "transport" and if needed with "init"
|
|
1290
1357
|
def refresh_access_token_from_sp_dc(sp_dc: str) -> dict:
|
|
1291
1358
|
transport = True
|
|
@@ -1385,29 +1452,52 @@ def spotify_get_access_token_from_sp_dc(sp_dc: str):
|
|
|
1385
1452
|
max_retries = TOKEN_MAX_RETRIES
|
|
1386
1453
|
retry = 0
|
|
1387
1454
|
|
|
1388
|
-
|
|
1389
|
-
token_data = refresh_access_token_from_sp_dc(sp_dc)
|
|
1390
|
-
token = token_data["access_token"]
|
|
1391
|
-
client_id = token_data.get("client_id", "")
|
|
1392
|
-
length = token_data["length"]
|
|
1455
|
+
last_error = ""
|
|
1393
1456
|
|
|
1394
|
-
|
|
1395
|
-
|
|
1396
|
-
|
|
1397
|
-
|
|
1398
|
-
|
|
1457
|
+
while retry < max_retries:
|
|
1458
|
+
try:
|
|
1459
|
+
token_data = refresh_access_token_from_sp_dc(sp_dc)
|
|
1460
|
+
token = token_data["access_token"]
|
|
1461
|
+
client_id = token_data.get("client_id", "")
|
|
1462
|
+
length = token_data["length"]
|
|
1463
|
+
|
|
1464
|
+
SP_CACHED_ACCESS_TOKEN = token
|
|
1465
|
+
SP_ACCESS_TOKEN_EXPIRES_AT = token_data["expires_at"]
|
|
1466
|
+
SP_CACHED_CLIENT_ID = client_id
|
|
1467
|
+
|
|
1468
|
+
if SP_CACHED_ACCESS_TOKEN is None or not check_token_validity(SP_CACHED_ACCESS_TOKEN, SP_CACHED_CLIENT_ID, USER_AGENT):
|
|
1469
|
+
retry += 1
|
|
1470
|
+
time.sleep(TOKEN_RETRY_TIMEOUT)
|
|
1471
|
+
else:
|
|
1472
|
+
break
|
|
1473
|
+
except Exception as e:
|
|
1474
|
+
last_error = str(e)
|
|
1399
1475
|
retry += 1
|
|
1400
|
-
|
|
1401
|
-
|
|
1402
|
-
break
|
|
1476
|
+
if retry < max_retries:
|
|
1477
|
+
time.sleep(TOKEN_RETRY_TIMEOUT)
|
|
1403
1478
|
|
|
1404
1479
|
if retry == max_retries:
|
|
1405
|
-
|
|
1406
|
-
|
|
1407
|
-
|
|
1408
|
-
|
|
1409
|
-
|
|
1410
|
-
|
|
1480
|
+
|
|
1481
|
+
if fetch_and_update_secrets():
|
|
1482
|
+
try:
|
|
1483
|
+
token_data = refresh_access_token_from_sp_dc(sp_dc)
|
|
1484
|
+
token = token_data["access_token"]
|
|
1485
|
+
client_id = token_data.get("client_id", "")
|
|
1486
|
+
length = token_data["length"]
|
|
1487
|
+
|
|
1488
|
+
SP_CACHED_ACCESS_TOKEN = token
|
|
1489
|
+
SP_ACCESS_TOKEN_EXPIRES_AT = token_data["expires_at"]
|
|
1490
|
+
SP_CACHED_CLIENT_ID = client_id
|
|
1491
|
+
|
|
1492
|
+
if SP_CACHED_ACCESS_TOKEN and check_token_validity(SP_CACHED_ACCESS_TOKEN, SP_CACHED_CLIENT_ID, USER_AGENT):
|
|
1493
|
+
return SP_CACHED_ACCESS_TOKEN
|
|
1494
|
+
except Exception as e:
|
|
1495
|
+
last_error = str(e)
|
|
1496
|
+
|
|
1497
|
+
error_msg = f"Failed to obtain a valid Spotify access token after {max_retries} attempts"
|
|
1498
|
+
if last_error:
|
|
1499
|
+
error_msg += f": {last_error}"
|
|
1500
|
+
raise RuntimeError(error_msg)
|
|
1411
1501
|
|
|
1412
1502
|
return SP_CACHED_ACCESS_TOKEN
|
|
1413
1503
|
|
|
@@ -1985,7 +2075,7 @@ def spotify_convert_uri_to_url(uri):
|
|
|
1985
2075
|
return url
|
|
1986
2076
|
|
|
1987
2077
|
|
|
1988
|
-
#
|
|
2078
|
+
# Returns list of Spotify friends
|
|
1989
2079
|
def spotify_list_friends(friend_activity):
|
|
1990
2080
|
|
|
1991
2081
|
print(f"Number of friends:\t\t{len(friend_activity['friends'])}\n")
|
|
@@ -3314,6 +3404,7 @@ def main():
|
|
|
3314
3404
|
else:
|
|
3315
3405
|
if FLAG_FILE:
|
|
3316
3406
|
FLAG_FILE = os.path.expanduser(FLAG_FILE)
|
|
3407
|
+
flag_file_delete()
|
|
3317
3408
|
|
|
3318
3409
|
if args.send_test_email:
|
|
3319
3410
|
print("* Sending test email notification ...\n")
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|