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.

@@ -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
- 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
+ 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. [Change Log](#change-log)
77
- 7. [License](#license)
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, truncate_chars, tabsize=8):
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=tabsize)
570
- truncated_line = expanded_line[:truncate_chars]
571
- truncated_lines.append(truncated_line)
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
- secret_cipher_dict = {
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,,