spotify-monitor 2.3__py3-none-any.whl → 2.4__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.4
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
- Tool for real-time monitoring of Spotify friends' music activity feed.
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,17 @@ 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
+ * [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)
82
+ 7. [Change Log](#change-log)
83
+ 8. [License](#license)
78
84
 
79
85
  <a id="requirements"></a>
80
86
  ## Requirements
81
87
 
82
88
  * Python 3.6 or higher
83
- * Libraries: `requests`, `python-dateutil`, `urllib3`, `pyotp`, `python-dotenv`
89
+ * Libraries: `requests`, `python-dateutil`, `urllib3`, `pyotp`, `python-dotenv`, `wcwidth`
84
90
 
85
91
  Tested on:
86
92
 
@@ -108,7 +114,7 @@ Download the *[spotify_monitor.py](https://raw.githubusercontent.com/misiektoja/
108
114
  Install dependencies via pip:
109
115
 
110
116
  ```sh
111
- pip install requests python-dateutil urllib3 pyotp python-dotenv
117
+ pip install requests python-dateutil urllib3 pyotp python-dotenv wcwidth
112
118
  ```
113
119
 
114
120
  Alternatively, from the downloaded *[requirements.txt](https://raw.githubusercontent.com/misiektoja/spotify_monitor/refs/heads/main/requirements.txt)*:
@@ -195,6 +201,8 @@ If your `sp_dc` cookie expires, the tool will notify you via the console and ema
195
201
 
196
202
  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
203
 
204
+ > **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).
205
+
198
206
  <a id="spotify-desktop-client"></a>
199
207
  #### Spotify Desktop Client
200
208
 
@@ -563,6 +571,76 @@ Example:
563
571
  grc tail -F -n 100 spotify_monitor_<user_uri_id/file_suffix>.log
564
572
  ```
565
573
 
574
+ <a id="debugging-tools"></a>
575
+ ## Debugging Tools
576
+
577
+ To help with troubleshooting and development, two debug utilities are available in the [debug](https://github.com/misiektoja/spotify_monitor/tree/dev/debug) directory.
578
+
579
+ <a id="access-token-retrieval-via-sp_dc-cookie-and-totp"></a>
580
+ ### Access Token Retrieval via sp_dc Cookie and TOTP
581
+
582
+ 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.
583
+
584
+ Download from [here](https://github.com/misiektoja/spotify_monitor/blob/dev/debug/spotify_monitor_totp_test.py) or:
585
+
586
+ ```sh
587
+ wget https://raw.githubusercontent.com/misiektoja/spotify_monitor/refs/heads/dev/debug/spotify_monitor_totp_test.py
588
+ ```
589
+
590
+ Install requirements:
591
+
592
+ ```sh
593
+ pip install requests python-dateutil pyotp
594
+ ```
595
+
596
+ Run:
597
+
598
+ ```sh
599
+ python3 spotify_monitor_totp_test.py --sp-dc "your_sp_dc_cookie_value"
600
+ ```
601
+
602
+ You should get a valid Spotify access token, example output:
603
+
604
+ <p align="center">
605
+ <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%"/>
606
+ </p>
607
+
608
+ > **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](https://github.com/misiektoja/spotify_monitor/blob/dev/debug/spotify_monitor_totp_test.py) (available since v1.6). There is also a [Thereallo1026/spotify-secrets](https://github.com/Thereallo1026/spotify-secrets) repo which offers JSON files that are automatically updated with current secrets.
609
+
610
+ <a id="secret-key-extraction-from-spotify-web-player-bundles"></a>
611
+ ### Secret Key Extraction from Spotify Web Player Bundles
612
+
613
+ 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.
614
+
615
+ Download from [here](https://github.com/misiektoja/spotify_monitor/blob/dev/debug/spotify_monitor_secret_grabber.py) or:
616
+
617
+ ```sh
618
+ wget https://raw.githubusercontent.com/misiektoja/spotify_monitor/refs/heads/dev/debug/spotify_monitor_secret_grabber.py
619
+ ```
620
+
621
+ Install requirements:
622
+
623
+ ```sh
624
+ pip install playwright
625
+ playwright install
626
+ ```
627
+
628
+ Run:
629
+
630
+ ```sh
631
+ python3 spotify_monitor_secret_grabber.py
632
+ ```
633
+
634
+ You should get output similar to below:
635
+
636
+ <p align="center">
637
+ <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%"/>
638
+ </p>
639
+
640
+ 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`).
641
+
642
+ > **NOTE:** you can also use [Thereallo1026/spotify-secrets](https://github.com/Thereallo1026/spotify-secrets) repo which offers JSON files that are automatically updated with current secrets (its secret extraction code is based on `spotify_monitor_secret_grabber`).
643
+
566
644
  <a id="change-log"></a>
567
645
  ## Change Log
568
646
 
@@ -0,0 +1,7 @@
1
+ spotify_monitor.py,sha256=TtB0dWvl5Yn1ti4y8VFk61V8rqXEZfnLY2PJZ26hVsw,161638
2
+ spotify_monitor-2.4.dist-info/licenses/LICENSE,sha256=OXLcl0T2SZ8Pmy2_dmlvKuetivmyPd5m1q-Gyd-zaYY,35149
3
+ spotify_monitor-2.4.dist-info/METADATA,sha256=rcnYf1XgMu4k55OO0m1yfP61TXRA_CkZLLDXUzDLHLM,27747
4
+ spotify_monitor-2.4.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
5
+ spotify_monitor-2.4.dist-info/entry_points.txt,sha256=8HzePfUcCSXrYaXOwLbNNYO8GJcnhgCSl4wcDNECht8,57
6
+ spotify_monitor-2.4.dist-info/top_level.txt,sha256=EP6IPD4vHT12rLM5b_jo2i3nrfOuwk3ehhr2gWdQx9Y,16
7
+ spotify_monitor-2.4.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.4
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.4"
19
20
 
20
21
  # ---------------------------
21
22
  # CONFIGURATION SECTION START
@@ -238,14 +239,38 @@ 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
- TOKEN_MAX_RETRIES = 10
247
+ TOKEN_MAX_RETRIES = 3
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 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
255
+ SECRET_CIPHER_DICT = {
256
+ "12": [107, 81, 49, 57, 67, 93, 87, 81, 69, 67, 40, 93, 48, 50, 46, 91, 94, 113, 41, 108, 77, 107, 34],
257
+ "11": [111, 45, 40, 73, 95, 74, 35, 85, 105, 107, 60, 110, 55, 72, 69, 70, 114, 83, 63, 88, 91],
258
+ "10": [61, 110, 58, 98, 35, 79, 117, 69, 102, 72, 92, 102, 69, 93, 41, 101, 42, 75],
259
+ "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],
260
+ "8": [37, 84, 32, 76, 87, 90, 87, 47, 13, 75, 48, 54, 44, 28, 19, 21, 22],
261
+ "7": [59, 91, 66, 74, 30, 66, 74, 38, 46, 50, 72, 61, 44, 71, 86, 39, 89],
262
+ "6": [21, 24, 85, 46, 48, 35, 33, 8, 11, 63, 76, 12, 55, 77, 14, 7, 54],
263
+ "5": [12, 56, 76, 33, 88, 44, 88, 33, 78, 78, 11, 66, 22, 22, 55, 69, 54],
264
+ }
265
+
266
+ # Remote URL used to fetch updated secrets needed for TOTP generation
267
+ # Set to empty string to disable
268
+ SECRET_CIPHER_DICT_URL = "https://github.com/Thereallo1026/spotify-secrets/blob/main/secrets/secretDict.json?raw=true"
269
+
270
+ # Identifier used to select the appropriate secret from SECRET_CIPHER_DICT when generating a TOTP token
271
+ # Set to 0 to auto-select the highest available version
272
+ TOTP_VER = 0
273
+
249
274
  # ---------------------------------------------------------------------
250
275
 
251
276
  # The section below is used when the token source is set to 'client'
@@ -446,6 +471,9 @@ CLEAR_SCREEN = False
446
471
  SPOTIFY_INACTIVITY_CHECK_SIGNAL_VALUE = 0
447
472
  TOKEN_MAX_RETRIES = 0
448
473
  TOKEN_RETRY_TIMEOUT = 0.0
474
+ SECRET_CIPHER_DICT = {}
475
+ SECRET_CIPHER_DICT_URL = ""
476
+ TOTP_VER = 0
449
477
  FLAG_FILE = ""
450
478
  TRUNCATE_CHARS = 0
451
479
 
@@ -480,9 +508,6 @@ TOKEN_URL = "https://open.spotify.com/api/token"
480
508
  # URL of the endpoint to get server time needed to create TOTP object
481
509
  SERVER_TIME_URL = "https://open.spotify.com/"
482
510
 
483
- # Identifier used to select the appropriate encrypted secret from secret_cipher_dict when generating a TOTP token
484
- TOTP_VER = 10
485
-
486
511
  # Variables for caching functionality of the Spotify client token to avoid unnecessary refreshing
487
512
  SP_CACHED_CLIENT_TOKEN = None
488
513
  SP_CLIENT_TOKEN_EXPIRES_AT = 0
@@ -561,14 +586,30 @@ SESSION.mount("http://", adapter)
561
586
 
562
587
 
563
588
  # 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):
589
+ def truncate_string_per_line(message, truncate_width, tabsize=8):
590
+ try:
591
+ from wcwidth import wcwidth
592
+ except ImportError:
593
+ return message
594
+
565
595
  lines = message.split('\n')
566
596
  truncated_lines = []
567
597
 
568
598
  for line in lines:
569
- expanded_line = line.expandtabs(tabsize=tabsize)
570
- truncated_line = expanded_line[:truncate_chars]
571
- truncated_lines.append(truncated_line)
599
+ expanded_line = line.expandtabs(tabsize)
600
+ current_width = 0
601
+ truncated = ''
602
+
603
+ for char in expanded_line:
604
+ char_width = wcwidth(char)
605
+ if char_width < 0:
606
+ char_width = 0 # Non-printable or unknown width
607
+ if current_width + char_width > truncate_width:
608
+ break
609
+ truncated += char
610
+ current_width += char_width
611
+
612
+ truncated_lines.append(truncated)
572
613
 
573
614
  return '\n'.join(truncated_lines)
574
615
 
@@ -1241,15 +1282,10 @@ def fetch_server_time(session: req.Session, ua: str) -> int:
1241
1282
  def generate_totp():
1242
1283
  import pyotp
1243
1284
 
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)]
1285
+ if str((ver := TOTP_VER or max(map(int, SECRET_CIPHER_DICT)))) not in SECRET_CIPHER_DICT:
1286
+ raise Exception(f"generate_totp(): Defined TOTP_VER ({ver}) is missing in SECRET_CIPHER_DICT")
1287
+
1288
+ secret_cipher_bytes = SECRET_CIPHER_DICT[str(ver)]
1253
1289
 
1254
1290
  transformed = [e ^ ((t % 33) + 9) for t, e in enumerate(secret_cipher_bytes)]
1255
1291
  joined = "".join(str(num) for num in transformed)
@@ -1259,6 +1295,34 @@ def generate_totp():
1259
1295
  return pyotp.TOTP(secret, digits=6, interval=30)
1260
1296
 
1261
1297
 
1298
+ def fetch_and_update_secrets():
1299
+ global SECRET_CIPHER_DICT
1300
+
1301
+ if not SECRET_CIPHER_DICT_URL:
1302
+ return False
1303
+
1304
+ try:
1305
+ response = req.get(SECRET_CIPHER_DICT_URL, timeout=FUNCTION_TIMEOUT, verify=VERIFY_SSL)
1306
+ response.raise_for_status()
1307
+ secrets = response.json()
1308
+
1309
+ if not isinstance(secrets, dict) or not secrets:
1310
+ raise ValueError("fetch_and_update_secrets(): Fetched payload not a non‑empty dict")
1311
+
1312
+ for key, value in secrets.items():
1313
+ if not isinstance(key, str) or not key.isdigit():
1314
+ raise ValueError(f"fetch_and_update_secrets(): Invalid key format: {key}")
1315
+ if not isinstance(value, list) or not all(isinstance(x, int) for x in value):
1316
+ raise ValueError(f"fetch_and_update_secrets(): Invalid value format for key {key}")
1317
+
1318
+ SECRET_CIPHER_DICT = secrets
1319
+ return True
1320
+
1321
+ except Exception as e:
1322
+ print(f"fetch_and_update_secrets(): Failed to get new secrets: {e}")
1323
+ return False
1324
+
1325
+
1262
1326
  # Refreshes the Spotify access token using the sp_dc cookie, tries first with mode "transport" and if needed with "init"
1263
1327
  def refresh_access_token_from_sp_dc(sp_dc: str) -> dict:
1264
1328
  transport = True
@@ -1358,29 +1422,52 @@ def spotify_get_access_token_from_sp_dc(sp_dc: str):
1358
1422
  max_retries = TOKEN_MAX_RETRIES
1359
1423
  retry = 0
1360
1424
 
1361
- while retry < max_retries:
1362
- token_data = refresh_access_token_from_sp_dc(sp_dc)
1363
- token = token_data["access_token"]
1364
- client_id = token_data.get("client_id", "")
1365
- length = token_data["length"]
1425
+ last_error = ""
1366
1426
 
1367
- SP_CACHED_ACCESS_TOKEN = token
1368
- SP_ACCESS_TOKEN_EXPIRES_AT = token_data["expires_at"]
1369
- SP_CACHED_CLIENT_ID = client_id
1370
-
1371
- if SP_CACHED_ACCESS_TOKEN is None or not check_token_validity(SP_CACHED_ACCESS_TOKEN, SP_CACHED_CLIENT_ID, USER_AGENT):
1427
+ while retry < max_retries:
1428
+ try:
1429
+ token_data = refresh_access_token_from_sp_dc(sp_dc)
1430
+ token = token_data["access_token"]
1431
+ client_id = token_data.get("client_id", "")
1432
+ length = token_data["length"]
1433
+
1434
+ SP_CACHED_ACCESS_TOKEN = token
1435
+ SP_ACCESS_TOKEN_EXPIRES_AT = token_data["expires_at"]
1436
+ SP_CACHED_CLIENT_ID = client_id
1437
+
1438
+ if SP_CACHED_ACCESS_TOKEN is None or not check_token_validity(SP_CACHED_ACCESS_TOKEN, SP_CACHED_CLIENT_ID, USER_AGENT):
1439
+ retry += 1
1440
+ time.sleep(TOKEN_RETRY_TIMEOUT)
1441
+ else:
1442
+ break
1443
+ except Exception as e:
1444
+ last_error = str(e)
1372
1445
  retry += 1
1373
- time.sleep(TOKEN_RETRY_TIMEOUT)
1374
- else:
1375
- break
1446
+ if retry < max_retries:
1447
+ time.sleep(TOKEN_RETRY_TIMEOUT)
1376
1448
 
1377
1449
  if retry == max_retries:
1378
- if SP_CACHED_ACCESS_TOKEN is not None:
1379
- print(f"* Token appears to be still invalid after {max_retries} attempts, returning token anyway")
1380
- print_cur_ts("Timestamp:\t\t\t")
1381
- return SP_CACHED_ACCESS_TOKEN
1382
- else:
1383
- raise RuntimeError(f"Failed to obtain a valid Spotify access token after {max_retries} attempts")
1450
+
1451
+ if fetch_and_update_secrets():
1452
+ try:
1453
+ token_data = refresh_access_token_from_sp_dc(sp_dc)
1454
+ token = token_data["access_token"]
1455
+ client_id = token_data.get("client_id", "")
1456
+ length = token_data["length"]
1457
+
1458
+ SP_CACHED_ACCESS_TOKEN = token
1459
+ SP_ACCESS_TOKEN_EXPIRES_AT = token_data["expires_at"]
1460
+ SP_CACHED_CLIENT_ID = client_id
1461
+
1462
+ if SP_CACHED_ACCESS_TOKEN and check_token_validity(SP_CACHED_ACCESS_TOKEN, SP_CACHED_CLIENT_ID, USER_AGENT):
1463
+ return SP_CACHED_ACCESS_TOKEN
1464
+ except Exception as e:
1465
+ last_error = str(e)
1466
+
1467
+ error_msg = f"Failed to obtain a valid Spotify access token after {max_retries} attempts"
1468
+ if last_error:
1469
+ error_msg += f": {last_error}"
1470
+ raise RuntimeError(error_msg)
1384
1471
 
1385
1472
  return SP_CACHED_ACCESS_TOKEN
1386
1473
 
@@ -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,,