spotify-monitor 2.3__py3-none-any.whl → 2.3.1__py3-none-any.whl
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.dist-info → spotify_monitor-2.3.1.dist-info}/METADATA +35 -5
- spotify_monitor-2.3.1.dist-info/RECORD +7 -0
- spotify_monitor.py +47 -20
- spotify_monitor-2.3.dist-info/RECORD +0 -7
- {spotify_monitor-2.3.dist-info → spotify_monitor-2.3.1.dist-info}/WHEEL +0 -0
- {spotify_monitor-2.3.dist-info → spotify_monitor-2.3.1.dist-info}/entry_points.txt +0 -0
- {spotify_monitor-2.3.dist-info → spotify_monitor-2.3.1.dist-info}/licenses/LICENSE +0 -0
- {spotify_monitor-2.3.dist-info → spotify_monitor-2.3.1.dist-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
|
|
3
|
+
Version: 2.3.1
|
|
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
|
|
@@ -21,13 +21,16 @@ Requires-Dist: python-dateutil>=2.8
|
|
|
21
21
|
Requires-Dist: urllib3>=2.0.7
|
|
22
22
|
Requires-Dist: pyotp>=2.9.0
|
|
23
23
|
Requires-Dist: python-dotenv>=0.19
|
|
24
|
+
Requires-Dist: wcwidth>=0.2.7
|
|
24
25
|
Dynamic: license-file
|
|
25
26
|
|
|
26
27
|
# spotify_monitor
|
|
27
28
|
|
|
28
29
|
Tool for real-time monitoring of Spotify friends' music activity feed.
|
|
29
30
|
|
|
30
|
-
|
|
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
|
+
|
|
33
|
+
🛠️ If you're looking for debug tools to get Spotify Web Player access tokens and extract secret keys: [click here](#debugging-tools)
|
|
31
34
|
|
|
32
35
|
<a id="features"></a>
|
|
33
36
|
## Features
|
|
@@ -73,14 +76,15 @@ NOTE: If you're interested in tracking changes to Spotify users' profiles includ
|
|
|
73
76
|
* [Check Intervals](#check-intervals)
|
|
74
77
|
* [Signal Controls (macOS/Linux/Unix)](#signal-controls-macoslinuxunix)
|
|
75
78
|
* [Coloring Log Output with GRC](#coloring-log-output-with-grc)
|
|
76
|
-
6. [
|
|
77
|
-
7. [
|
|
79
|
+
6. [Debugging Tools](#debugging-tools)
|
|
80
|
+
7. [Change Log](#change-log)
|
|
81
|
+
8. [License](#license)
|
|
78
82
|
|
|
79
83
|
<a id="requirements"></a>
|
|
80
84
|
## Requirements
|
|
81
85
|
|
|
82
86
|
* Python 3.6 or higher
|
|
83
|
-
* Libraries: `requests`, `python-dateutil`, `urllib3`, `pyotp`, `python-dotenv`
|
|
87
|
+
* Libraries: `requests`, `python-dateutil`, `urllib3`, `pyotp`, `python-dotenv`, `wcwidth`
|
|
84
88
|
|
|
85
89
|
Tested on:
|
|
86
90
|
|
|
@@ -195,6 +199,8 @@ If your `sp_dc` cookie expires, the tool will notify you via the console and ema
|
|
|
195
199
|
|
|
196
200
|
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).
|
|
197
201
|
|
|
202
|
+
`Note`: encrypted byte sequences used for TOTP secret generation tend to expire every now and then; you can either check the [issues](https://github.com/misiektoja/spotify_monitor/issues) section of the project to see if there are any new secrets published or you can run the [spotify_monitor_secret_grabber.py](https://github.com/misiektoja/spotify_monitor/blob/dev/debug/spotify_monitor_secret_grabber.py) and extract it by yourself (see [Debugging Tools](https://github.com/misiektoja/spotify_monitor#debugging-tools) for more info).
|
|
203
|
+
|
|
198
204
|
<a id="spotify-desktop-client"></a>
|
|
199
205
|
#### Spotify Desktop Client
|
|
200
206
|
|
|
@@ -563,6 +569,30 @@ Example:
|
|
|
563
569
|
grc tail -F -n 100 spotify_monitor_<user_uri_id/file_suffix>.log
|
|
564
570
|
```
|
|
565
571
|
|
|
572
|
+
<a id="debugging-tools"></a>
|
|
573
|
+
## Debugging Tools
|
|
574
|
+
|
|
575
|
+
To help with troubleshooting and development, two debug utilities are available in the `debug` directory:
|
|
576
|
+
|
|
577
|
+
- [spotify_monitor_totp_test.py](https://github.com/misiektoja/spotify_monitor/blob/dev/debug/spotify_monitor_totp_test.py): fetching of Spotify access token based on a Spotify Web Player `sp_dc` cookie value:
|
|
578
|
+
|
|
579
|
+
```sh
|
|
580
|
+
pip install requests python-dateutil pyotp
|
|
581
|
+
python3 spotify_monitor_totp_test.py --sp-dc "your_sp_dc_cookie_value"
|
|
582
|
+
```
|
|
583
|
+
|
|
584
|
+
- [spotify_monitor_secret_grabber.py](https://github.com/misiektoja/spotify_monitor/blob/dev/debug/spotify_monitor_secret_grabber.py): automatic extractor for secret keys used for TOTP generation in Spotify Web Player JavaScript bundles:
|
|
585
|
+
|
|
586
|
+
```sh
|
|
587
|
+
pip install playwright
|
|
588
|
+
playwright install
|
|
589
|
+
python3 spotify_monitor_secret_grabber.py
|
|
590
|
+
```
|
|
591
|
+
|
|
592
|
+
<p align="center">
|
|
593
|
+
<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
|
+
</p>
|
|
595
|
+
|
|
566
596
|
<a id="change-log"></a>
|
|
567
597
|
## Change Log
|
|
568
598
|
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
spotify_monitor.py,sha256=msF-xUpmB_dch3C1dtA31mvU0OgtRUgUeOtXh20xDLw,159386
|
|
2
|
+
spotify_monitor-2.3.1.dist-info/licenses/LICENSE,sha256=OXLcl0T2SZ8Pmy2_dmlvKuetivmyPd5m1q-Gyd-zaYY,35149
|
|
3
|
+
spotify_monitor-2.3.1.dist-info/METADATA,sha256=z37aFQ2NUa5jYzU5pF6ru5UXmu65Ctee8J_EDvjG1iI,25204
|
|
4
|
+
spotify_monitor-2.3.1.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
|
|
5
|
+
spotify_monitor-2.3.1.dist-info/entry_points.txt,sha256=8HzePfUcCSXrYaXOwLbNNYO8GJcnhgCSl4wcDNECht8,57
|
|
6
|
+
spotify_monitor-2.3.1.dist-info/top_level.txt,sha256=EP6IPD4vHT12rLM5b_jo2i3nrfOuwk3ehhr2gWdQx9Y,16
|
|
7
|
+
spotify_monitor-2.3.1.dist-info/RECORD,,
|
spotify_monitor.py
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
#!/usr/bin/env python3
|
|
2
2
|
"""
|
|
3
3
|
Author: Michal Szymanski <misiektoja-github@rm-rf.ninja>
|
|
4
|
-
v2.3
|
|
4
|
+
v2.3.1
|
|
5
5
|
|
|
6
6
|
Tool implementing real-time tracking of Spotify friends music activity:
|
|
7
7
|
https://github.com/misiektoja/spotify_monitor/
|
|
@@ -13,9 +13,10 @@ python-dateutil
|
|
|
13
13
|
urllib3
|
|
14
14
|
pyotp (optional, needed when the token source is set to cookie)
|
|
15
15
|
python-dotenv (optional)
|
|
16
|
+
wcwidth (optional, needed by TRUNCATE_CHARS feature)
|
|
16
17
|
"""
|
|
17
18
|
|
|
18
|
-
VERSION = "2.3"
|
|
19
|
+
VERSION = "2.3.1"
|
|
19
20
|
|
|
20
21
|
# ---------------------------
|
|
21
22
|
# CONFIGURATION SECTION START
|
|
@@ -238,14 +239,33 @@ TRUNCATE_CHARS = 0
|
|
|
238
239
|
# Value added/subtracted via signal handlers to adjust inactivity timeout (SPOTIFY_INACTIVITY_CHECK); in seconds
|
|
239
240
|
SPOTIFY_INACTIVITY_CHECK_SIGNAL_VALUE = 30 # 30 seconds
|
|
240
241
|
|
|
242
|
+
# ---------------------------------------------------------------------
|
|
243
|
+
|
|
244
|
+
# The section below is used when the token source is set to 'cookie'
|
|
245
|
+
|
|
241
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
|
|
242
|
-
# Used only when the token source is set to 'cookie'
|
|
243
247
|
TOKEN_MAX_RETRIES = 10
|
|
244
248
|
|
|
245
249
|
# Interval between access token retry attempts; in seconds
|
|
246
|
-
# Used only when the token source is set to 'cookie'
|
|
247
250
|
TOKEN_RETRY_TIMEOUT = 0.5 # 0.5 second
|
|
248
251
|
|
|
252
|
+
# Mapping of TOTP version identifiers to the encrypted byte sequence for TOTP secret generation
|
|
253
|
+
# Newest TOTP secrets can be fetched via spotify_monitor_secret_grabber.py (see debug dir)
|
|
254
|
+
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
|
+
"6": [21, 24, 85, 46, 48, 35, 33, 8, 11, 63, 76, 12, 55, 77, 14, 7, 54],
|
|
262
|
+
"5": [12, 56, 76, 33, 88, 44, 88, 33, 78, 78, 11, 66, 22, 22, 55, 69, 54],
|
|
263
|
+
}
|
|
264
|
+
|
|
265
|
+
# Identifier used to select the appropriate encrypted secret from SECRET_CIPHER_DICT when generating a TOTP token
|
|
266
|
+
# Set to 0 to auto-select the highest available version
|
|
267
|
+
TOTP_VER = 0
|
|
268
|
+
|
|
249
269
|
# ---------------------------------------------------------------------
|
|
250
270
|
|
|
251
271
|
# The section below is used when the token source is set to 'client'
|
|
@@ -446,6 +466,8 @@ CLEAR_SCREEN = False
|
|
|
446
466
|
SPOTIFY_INACTIVITY_CHECK_SIGNAL_VALUE = 0
|
|
447
467
|
TOKEN_MAX_RETRIES = 0
|
|
448
468
|
TOKEN_RETRY_TIMEOUT = 0.0
|
|
469
|
+
SECRET_CIPHER_DICT = {}
|
|
470
|
+
TOTP_VER = 0
|
|
449
471
|
FLAG_FILE = ""
|
|
450
472
|
TRUNCATE_CHARS = 0
|
|
451
473
|
|
|
@@ -480,9 +502,6 @@ TOKEN_URL = "https://open.spotify.com/api/token"
|
|
|
480
502
|
# URL of the endpoint to get server time needed to create TOTP object
|
|
481
503
|
SERVER_TIME_URL = "https://open.spotify.com/"
|
|
482
504
|
|
|
483
|
-
# Identifier used to select the appropriate encrypted secret from secret_cipher_dict when generating a TOTP token
|
|
484
|
-
TOTP_VER = 10
|
|
485
|
-
|
|
486
505
|
# Variables for caching functionality of the Spotify client token to avoid unnecessary refreshing
|
|
487
506
|
SP_CACHED_CLIENT_TOKEN = None
|
|
488
507
|
SP_CLIENT_TOKEN_EXPIRES_AT = 0
|
|
@@ -561,14 +580,30 @@ SESSION.mount("http://", adapter)
|
|
|
561
580
|
|
|
562
581
|
|
|
563
582
|
# Truncates each line of a string to a specified number of characters including tab expansion and multi-line support
|
|
564
|
-
def truncate_string_per_line(message,
|
|
583
|
+
def truncate_string_per_line(message, truncate_width, tabsize=8):
|
|
584
|
+
try:
|
|
585
|
+
from wcwidth import wcwidth
|
|
586
|
+
except ImportError:
|
|
587
|
+
return message
|
|
588
|
+
|
|
565
589
|
lines = message.split('\n')
|
|
566
590
|
truncated_lines = []
|
|
567
591
|
|
|
568
592
|
for line in lines:
|
|
569
|
-
expanded_line = line.expandtabs(tabsize
|
|
570
|
-
|
|
571
|
-
|
|
593
|
+
expanded_line = line.expandtabs(tabsize)
|
|
594
|
+
current_width = 0
|
|
595
|
+
truncated = ''
|
|
596
|
+
|
|
597
|
+
for char in expanded_line:
|
|
598
|
+
char_width = wcwidth(char)
|
|
599
|
+
if char_width < 0:
|
|
600
|
+
char_width = 0 # Non-printable or unknown width
|
|
601
|
+
if current_width + char_width > truncate_width:
|
|
602
|
+
break
|
|
603
|
+
truncated += char
|
|
604
|
+
current_width += char_width
|
|
605
|
+
|
|
606
|
+
truncated_lines.append(truncated)
|
|
572
607
|
|
|
573
608
|
return '\n'.join(truncated_lines)
|
|
574
609
|
|
|
@@ -1241,15 +1276,7 @@ def fetch_server_time(session: req.Session, ua: str) -> int:
|
|
|
1241
1276
|
def generate_totp():
|
|
1242
1277
|
import pyotp
|
|
1243
1278
|
|
|
1244
|
-
|
|
1245
|
-
"10": [61, 110, 58, 98, 35, 79, 117, 69, 102, 72, 92, 102, 69, 93, 41, 101, 42, 75],
|
|
1246
|
-
"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],
|
|
1247
|
-
"8": [37, 84, 32, 76, 87, 90, 87, 47, 13, 75, 48, 54, 44, 28, 19, 21, 22],
|
|
1248
|
-
"7": [59, 91, 66, 74, 30, 66, 74, 38, 46, 50, 72, 61, 44, 71, 86, 39, 89],
|
|
1249
|
-
"6": [21, 24, 85, 46, 48, 35, 33, 8, 11, 63, 76, 12, 55, 77, 14, 7, 54],
|
|
1250
|
-
"5": [12, 56, 76, 33, 88, 44, 88, 33, 78, 78, 11, 66, 22, 22, 55, 69, 54],
|
|
1251
|
-
}
|
|
1252
|
-
secret_cipher_bytes = secret_cipher_dict[str(TOTP_VER)]
|
|
1279
|
+
secret_cipher_bytes = SECRET_CIPHER_DICT[str((ver := TOTP_VER or max(map(int, SECRET_CIPHER_DICT))))]
|
|
1253
1280
|
|
|
1254
1281
|
transformed = [e ^ ((t % 33) + 9) for t, e in enumerate(secret_cipher_bytes)]
|
|
1255
1282
|
joined = "".join(str(num) for num in transformed)
|
|
@@ -1,7 +0,0 @@
|
|
|
1
|
-
spotify_monitor.py,sha256=Nq4RTsG9bHUeVpGJLOOCX8lr5xySEniNsu4aohrpU-o,158392
|
|
2
|
-
spotify_monitor-2.3.dist-info/licenses/LICENSE,sha256=OXLcl0T2SZ8Pmy2_dmlvKuetivmyPd5m1q-Gyd-zaYY,35149
|
|
3
|
-
spotify_monitor-2.3.dist-info/METADATA,sha256=MFBSxyNhzVr5ZCJHMWWenD4CH9EWGYvgA0UB2ZM-bgI,23411
|
|
4
|
-
spotify_monitor-2.3.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
|
|
5
|
-
spotify_monitor-2.3.dist-info/entry_points.txt,sha256=8HzePfUcCSXrYaXOwLbNNYO8GJcnhgCSl4wcDNECht8,57
|
|
6
|
-
spotify_monitor-2.3.dist-info/top_level.txt,sha256=EP6IPD4vHT12rLM5b_jo2i3nrfOuwk3ehhr2gWdQx9Y,16
|
|
7
|
-
spotify_monitor-2.3.dist-info/RECORD,,
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|