spotify-monitor 2.2__py3-none-any.whl → 2.2.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.2.dist-info → spotify_monitor-2.2.1.dist-info}/METADATA +4 -2
- spotify_monitor-2.2.1.dist-info/RECORD +7 -0
- spotify_monitor.py +32 -17
- spotify_monitor-2.2.dist-info/RECORD +0 -7
- {spotify_monitor-2.2.dist-info → spotify_monitor-2.2.1.dist-info}/WHEEL +0 -0
- {spotify_monitor-2.2.dist-info → spotify_monitor-2.2.1.dist-info}/entry_points.txt +0 -0
- {spotify_monitor-2.2.dist-info → spotify_monitor-2.2.1.dist-info}/licenses/LICENSE +0 -0
- {spotify_monitor-2.2.dist-info → spotify_monitor-2.2.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.2
|
|
3
|
+
Version: 2.2.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
|
|
@@ -25,7 +25,7 @@ Dynamic: license-file
|
|
|
25
25
|
|
|
26
26
|
# spotify_monitor
|
|
27
27
|
|
|
28
|
-
|
|
28
|
+
Tool for real-time monitoring of Spotify friends' music activity feed.
|
|
29
29
|
|
|
30
30
|
NOTE: 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).
|
|
31
31
|
|
|
@@ -200,6 +200,8 @@ If you store the `SP_DC_COOKIE` in a dotenv file you can update its value and se
|
|
|
200
200
|
|
|
201
201
|
This is the alternative method used to obtain a Spotify access token which simulates a login from the real Spotify desktop app using credentials intercepted from a real session.
|
|
202
202
|
|
|
203
|
+
**NOTE**: Spotify appears to have changed something in client versions released after June 2025 (likely a switch to HTTP/3 and/or certificate pinning). You may need to use an older version of the Spotify desktop client for this method to work.
|
|
204
|
+
|
|
203
205
|
- Run an intercepting proxy of your choice (like [Proxyman](https://proxyman.com)).
|
|
204
206
|
|
|
205
207
|
- Launch the Spotify desktop client and look for POST requests to `https://login{n}.spotify.com/v3/login`
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
spotify_monitor.py,sha256=-uJet8WI668Ihnqs3uArowPfrYa4MUzB1QPYEL_1EGg,153671
|
|
2
|
+
spotify_monitor-2.2.1.dist-info/licenses/LICENSE,sha256=OXLcl0T2SZ8Pmy2_dmlvKuetivmyPd5m1q-Gyd-zaYY,35149
|
|
3
|
+
spotify_monitor-2.2.1.dist-info/METADATA,sha256=q0IT4d33nTghRZ4boNvp0KxUgmD17-URY6bQMTgPAI8,22613
|
|
4
|
+
spotify_monitor-2.2.1.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
|
|
5
|
+
spotify_monitor-2.2.1.dist-info/entry_points.txt,sha256=8HzePfUcCSXrYaXOwLbNNYO8GJcnhgCSl4wcDNECht8,57
|
|
6
|
+
spotify_monitor-2.2.1.dist-info/top_level.txt,sha256=EP6IPD4vHT12rLM5b_jo2i3nrfOuwk3ehhr2gWdQx9Y,16
|
|
7
|
+
spotify_monitor-2.2.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.2
|
|
4
|
+
v2.2.1
|
|
5
5
|
|
|
6
6
|
Tool implementing real-time tracking of Spotify friends music activity:
|
|
7
7
|
https://github.com/misiektoja/spotify_monitor/
|
|
@@ -15,7 +15,7 @@ pyotp (optional, needed when the token source is set to cookie)
|
|
|
15
15
|
python-dotenv (optional)
|
|
16
16
|
"""
|
|
17
17
|
|
|
18
|
-
VERSION = "2.2"
|
|
18
|
+
VERSION = "2.2.1"
|
|
19
19
|
|
|
20
20
|
# ---------------------------
|
|
21
21
|
# CONFIGURATION SECTION START
|
|
@@ -149,6 +149,10 @@ SP_USER_GOT_OFFLINE_TRACK_ID = ""
|
|
|
149
149
|
# Set to 0 to keep playing indefinitely until manually paused
|
|
150
150
|
SP_USER_GOT_OFFLINE_DELAY_BEFORE_PAUSE = 5 # 5 seconds
|
|
151
151
|
|
|
152
|
+
# Occasionally, the Spotify API glitches and reports that the user has disappeared from the list of friends
|
|
153
|
+
# To avoid false alarms, we delay alerts until this happens REMOVED_DISAPPEARED_COUNTER times in a row
|
|
154
|
+
REMOVED_DISAPPEARED_COUNTER = 4
|
|
155
|
+
|
|
152
156
|
# Optional: specify user agent manually
|
|
153
157
|
#
|
|
154
158
|
# When the token source is 'cookie' - set it to web browser user agent, some examples:
|
|
@@ -409,6 +413,7 @@ SONG_ON_LOOP_VALUE = 0
|
|
|
409
413
|
SKIPPED_SONG_THRESHOLD = 0
|
|
410
414
|
SP_USER_GOT_OFFLINE_TRACK_ID = ""
|
|
411
415
|
SP_USER_GOT_OFFLINE_DELAY_BEFORE_PAUSE = 0
|
|
416
|
+
REMOVED_DISAPPEARED_COUNTER = 0
|
|
412
417
|
USER_AGENT = ""
|
|
413
418
|
LIVENESS_CHECK_INTERVAL = 0
|
|
414
419
|
CHECK_INTERNET_URL = ""
|
|
@@ -1179,10 +1184,13 @@ def fetch_server_time(session: req.Session, ua: str) -> int:
|
|
|
1179
1184
|
def generate_totp():
|
|
1180
1185
|
import pyotp
|
|
1181
1186
|
|
|
1182
|
-
|
|
1183
|
-
|
|
1184
|
-
|
|
1185
|
-
|
|
1187
|
+
secret_cipher_dict = {
|
|
1188
|
+
"8": [37, 84, 32, 76, 87, 90, 87, 47, 13, 75, 48, 54, 44, 28, 19, 21, 22],
|
|
1189
|
+
"7": [59, 91, 66, 74, 30, 66, 74, 38, 46, 50, 72, 61, 44, 71, 86, 39, 89],
|
|
1190
|
+
"6": [21, 24, 85, 46, 48, 35, 33, 8, 11, 63, 76, 12, 55, 77, 14, 7, 54],
|
|
1191
|
+
"5": [12, 56, 76, 33, 88, 44, 88, 33, 78, 78, 11, 66, 22, 22, 55, 69, 54]
|
|
1192
|
+
}
|
|
1193
|
+
secret_cipher_bytes = secret_cipher_dict["8"]
|
|
1186
1194
|
|
|
1187
1195
|
transformed = [e ^ ((t % 33) + 9) for t, e in enumerate(secret_cipher_bytes)]
|
|
1188
1196
|
joined = "".join(str(num) for num in transformed)
|
|
@@ -1211,7 +1219,7 @@ def refresh_access_token_from_sp_dc(sp_dc: str) -> dict:
|
|
|
1211
1219
|
"productType": "web-player",
|
|
1212
1220
|
"totp": otp_value,
|
|
1213
1221
|
"totpServer": otp_value,
|
|
1214
|
-
"totpVer":
|
|
1222
|
+
"totpVer": 8,
|
|
1215
1223
|
"sTime": server_time,
|
|
1216
1224
|
"cTime": client_time,
|
|
1217
1225
|
"buildDate": time.strftime("%Y-%m-%d", time.gmtime(server_time)),
|
|
@@ -2251,7 +2259,7 @@ def spotify_monitor_friend_uri(user_uri_id, tracks, csv_file_name):
|
|
|
2251
2259
|
SP_CACHED_ACCESS_TOKEN = None
|
|
2252
2260
|
|
|
2253
2261
|
client_errs = ['access token', 'invalid client token', 'expired client token', 'refresh token has been revoked', 'refresh token has expired', 'refresh token is invalid', 'invalid grant during refresh']
|
|
2254
|
-
cookie_errs = ['access token', 'unauthorized']
|
|
2262
|
+
cookie_errs = ['access token', 'unauthorized', 'unsuccessful token request']
|
|
2255
2263
|
|
|
2256
2264
|
if TOKEN_SOURCE == 'client' and any(k in err for k in client_errs):
|
|
2257
2265
|
print(f"* Error: client or refresh token may be invalid or expired!")
|
|
@@ -2264,11 +2272,11 @@ def spotify_monitor_friend_uri(user_uri_id, tracks, csv_file_name):
|
|
|
2264
2272
|
email_sent = True
|
|
2265
2273
|
|
|
2266
2274
|
elif TOKEN_SOURCE == 'cookie' and any(k in err for k in cookie_errs):
|
|
2267
|
-
print(f"* Error: sp_dc may be invalid or
|
|
2275
|
+
print(f"* Error: sp_dc may be invalid/expired or Spotify has broken sth again!")
|
|
2268
2276
|
if ERROR_NOTIFICATION and not email_sent:
|
|
2269
|
-
m_subject = f"spotify_monitor: sp_dc may be invalid or
|
|
2270
|
-
m_body = f"sp_dc may be invalid or
|
|
2271
|
-
m_body_html = f"<html><head></head><body>sp_dc may be invalid or
|
|
2277
|
+
m_subject = f"spotify_monitor: sp_dc may be invalid/expired or Spotify has broken sth again! (uri: {user_uri_id})"
|
|
2278
|
+
m_body = f"sp_dc may be invalid/expired or Spotify has broken sth again!\n{e}{get_cur_ts(nl_ch + nl_ch + 'Timestamp: ')}"
|
|
2279
|
+
m_body_html = f"<html><head></head><body>sp_dc may be invalid/expired or Spotify has broken sth again!<br>{escape(str(e))}{get_cur_ts('<br><br>Timestamp: ')}</body></html>"
|
|
2272
2280
|
print(f"Sending email notification to {RECEIVER_EMAIL}")
|
|
2273
2281
|
send_email(m_subject, m_body, m_body_html, SMTP_SSL)
|
|
2274
2282
|
email_sent = True
|
|
@@ -2431,6 +2439,8 @@ def spotify_monitor_friend_uri(user_uri_id, tracks, csv_file_name):
|
|
|
2431
2439
|
|
|
2432
2440
|
email_sent = False
|
|
2433
2441
|
|
|
2442
|
+
disappeared_counter = 0
|
|
2443
|
+
|
|
2434
2444
|
# Primary loop
|
|
2435
2445
|
while True:
|
|
2436
2446
|
|
|
@@ -2498,7 +2508,7 @@ def spotify_monitor_friend_uri(user_uri_id, tracks, csv_file_name):
|
|
|
2498
2508
|
print(f"* Error, retrying in {display_time(SPOTIFY_ERROR_INTERVAL)}: '{e}'")
|
|
2499
2509
|
|
|
2500
2510
|
client_errs = ['access token', 'invalid client token', 'expired client token', 'refresh token has been revoked', 'refresh token has expired', 'refresh token is invalid', 'invalid grant during refresh']
|
|
2501
|
-
cookie_errs = ['access token', 'unauthorized']
|
|
2511
|
+
cookie_errs = ['access token', 'unauthorized', 'unsuccessful token request']
|
|
2502
2512
|
|
|
2503
2513
|
if TOKEN_SOURCE == 'client' and any(k in err for k in client_errs):
|
|
2504
2514
|
print(f"* Error: client or refresh token may be invalid or expired!")
|
|
@@ -2511,11 +2521,11 @@ def spotify_monitor_friend_uri(user_uri_id, tracks, csv_file_name):
|
|
|
2511
2521
|
email_sent = True
|
|
2512
2522
|
|
|
2513
2523
|
elif TOKEN_SOURCE == 'cookie' and any(k in err for k in cookie_errs):
|
|
2514
|
-
print(f"* Error: sp_dc may be invalid or
|
|
2524
|
+
print(f"* Error: sp_dc may be invalid/expired or Spotify has broken sth again!")
|
|
2515
2525
|
if ERROR_NOTIFICATION and not email_sent:
|
|
2516
|
-
m_subject = f"spotify_monitor: sp_dc may be invalid or
|
|
2517
|
-
m_body = f"sp_dc may be invalid or
|
|
2518
|
-
m_body_html = f"<html><head></head><body>sp_dc may be invalid or
|
|
2526
|
+
m_subject = f"spotify_monitor: sp_dc may be invalid/expired or Spotify has broken sth again! (uri: {user_uri_id})"
|
|
2527
|
+
m_body = f"sp_dc may be invalid/expired or Spotify has broken sth again!\n{e}{get_cur_ts(nl_ch + nl_ch + 'Timestamp: ')}"
|
|
2528
|
+
m_body_html = f"<html><head></head><body>sp_dc may be invalid/expired or Spotify has broken sth again!<br>{escape(str(e))}{get_cur_ts('<br><br>Timestamp: ')}</body></html>"
|
|
2519
2529
|
print(f"Sending email notification to {RECEIVER_EMAIL}")
|
|
2520
2530
|
send_email(m_subject, m_body, m_body_html, SMTP_SSL)
|
|
2521
2531
|
email_sent = True
|
|
@@ -2525,6 +2535,10 @@ def spotify_monitor_friend_uri(user_uri_id, tracks, csv_file_name):
|
|
|
2525
2535
|
|
|
2526
2536
|
if sp_found is False:
|
|
2527
2537
|
# User has disappeared from the Spotify's friend list or account has been removed
|
|
2538
|
+
disappeared_counter += 1
|
|
2539
|
+
if disappeared_counter < REMOVED_DISAPPEARED_COUNTER:
|
|
2540
|
+
time.sleep(SPOTIFY_CHECK_INTERVAL)
|
|
2541
|
+
continue
|
|
2528
2542
|
if user_not_found is False:
|
|
2529
2543
|
if is_user_removed(sp_accessToken, user_uri_id):
|
|
2530
2544
|
print(f"Spotify user '{user_uri_id}' ({sp_username}) was probably removed! Retrying in {display_time(SPOTIFY_DISAPPEARED_CHECK_INTERVAL)} intervals")
|
|
@@ -2548,6 +2562,7 @@ def spotify_monitor_friend_uri(user_uri_id, tracks, csv_file_name):
|
|
|
2548
2562
|
continue
|
|
2549
2563
|
else:
|
|
2550
2564
|
# User reappeared in the Spotify's friend list
|
|
2565
|
+
disappeared_counter = 0
|
|
2551
2566
|
if user_not_found is True:
|
|
2552
2567
|
print(f"Spotify user {user_uri_id} ({sp_username}) has reappeared!")
|
|
2553
2568
|
if ERROR_NOTIFICATION:
|
|
@@ -1,7 +0,0 @@
|
|
|
1
|
-
spotify_monitor.py,sha256=OGM62kDeXOa8SO0RZK1Lhuagbw_Ltchy_oWtWW3xkIA,152513
|
|
2
|
-
spotify_monitor-2.2.dist-info/licenses/LICENSE,sha256=OXLcl0T2SZ8Pmy2_dmlvKuetivmyPd5m1q-Gyd-zaYY,35149
|
|
3
|
-
spotify_monitor-2.2.dist-info/METADATA,sha256=yXfwE_3vT7INKsIWxyBX9EgC2i3SL7-chl9gFNmH1lY,22382
|
|
4
|
-
spotify_monitor-2.2.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
|
|
5
|
-
spotify_monitor-2.2.dist-info/entry_points.txt,sha256=8HzePfUcCSXrYaXOwLbNNYO8GJcnhgCSl4wcDNECht8,57
|
|
6
|
-
spotify_monitor-2.2.dist-info/top_level.txt,sha256=EP6IPD4vHT12rLM5b_jo2i3nrfOuwk3ehhr2gWdQx9Y,16
|
|
7
|
-
spotify_monitor-2.2.dist-info/RECORD,,
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|