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.

@@ -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
- spotify_monitor is a tool for real-time monitoring of Spotify friends' music activity.
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
- secret_cipher_bytes = [
1183
- 12, 56, 76, 33, 88, 44, 88, 33,
1184
- 78, 78, 11, 66, 22, 22, 55, 69, 54,
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": 5,
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 expired!")
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 expired! (uri: {user_uri_id})"
2270
- m_body = f"sp_dc may be invalid or expired!\n{e}{get_cur_ts(nl_ch + nl_ch + 'Timestamp: ')}"
2271
- m_body_html = f"<html><head></head><body>sp_dc may be invalid or expired!<br>{escape(str(e))}{get_cur_ts('<br><br>Timestamp: ')}</body></html>"
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 expired!")
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 expired! (uri: {user_uri_id})"
2517
- m_body = f"sp_dc may be invalid or expired!\n{e}{get_cur_ts(nl_ch + nl_ch + 'Timestamp: ')}"
2518
- m_body_html = f"<html><head></head><body>sp_dc may be invalid or expired!<br>{escape(str(e))}{get_cur_ts('<br><br>Timestamp: ')}</body></html>"
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,,