spotify-monitor 2.1__py3-none-any.whl → 2.1.2__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.
- {spotify_monitor-2.1.dist-info → spotify_monitor-2.1.2.dist-info}/METADATA +3 -3
- spotify_monitor-2.1.2.dist-info/RECORD +7 -0
- spotify_monitor.py +69 -61
- spotify_monitor-2.1.dist-info/RECORD +0 -7
- {spotify_monitor-2.1.dist-info → spotify_monitor-2.1.2.dist-info}/WHEEL +0 -0
- {spotify_monitor-2.1.dist-info → spotify_monitor-2.1.2.dist-info}/entry_points.txt +0 -0
- {spotify_monitor-2.1.dist-info → spotify_monitor-2.1.2.dist-info}/licenses/LICENSE +0 -0
- {spotify_monitor-2.1.dist-info → spotify_monitor-2.1.2.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.1
|
|
3
|
+
Version: 2.1.2
|
|
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
|
|
@@ -200,9 +200,9 @@ To use credentials captured from the Spotify desktop client to obtain an access
|
|
|
200
200
|
|
|
201
201
|
Run an intercepting proxy of your choice (like [Proxyman](https://proxyman.com)).
|
|
202
202
|
|
|
203
|
-
Launch the Spotify desktop client and look for requests to `https://login{n}.spotify.com/v3/login`
|
|
203
|
+
Launch the Spotify desktop client and look for POST requests to `https://login{n}.spotify.com/v3/login`
|
|
204
204
|
|
|
205
|
-
Note: The `login` part is suffixed with one or more digits (e.g. `login5
|
|
205
|
+
Note: The `login` part is suffixed with one or more digits (e.g. `login5`).
|
|
206
206
|
|
|
207
207
|
If you don't see this request, log out from the client and log back in.
|
|
208
208
|
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
spotify_monitor.py,sha256=jCI1-Bi4xYlxeGLWISAHuQq0FPn4f8dEkVDrh2Pk2FE,146164
|
|
2
|
+
spotify_monitor-2.1.2.dist-info/licenses/LICENSE,sha256=OXLcl0T2SZ8Pmy2_dmlvKuetivmyPd5m1q-Gyd-zaYY,35149
|
|
3
|
+
spotify_monitor-2.1.2.dist-info/METADATA,sha256=DVyBABHOKULe8lZ5lHPT62ak3n1jMzObpUns_Y-nW0o,21524
|
|
4
|
+
spotify_monitor-2.1.2.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
|
|
5
|
+
spotify_monitor-2.1.2.dist-info/entry_points.txt,sha256=8HzePfUcCSXrYaXOwLbNNYO8GJcnhgCSl4wcDNECht8,57
|
|
6
|
+
spotify_monitor-2.1.2.dist-info/top_level.txt,sha256=EP6IPD4vHT12rLM5b_jo2i3nrfOuwk3ehhr2gWdQx9Y,16
|
|
7
|
+
spotify_monitor-2.1.2.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.1
|
|
4
|
+
v2.1.2
|
|
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 (needed when the token source is set to cookie)
|
|
|
15
15
|
python-dotenv (optional)
|
|
16
16
|
"""
|
|
17
17
|
|
|
18
|
-
VERSION = "2.1"
|
|
18
|
+
VERSION = "2.1.2"
|
|
19
19
|
|
|
20
20
|
# ---------------------------
|
|
21
21
|
# CONFIGURATION SECTION START
|
|
@@ -109,7 +109,7 @@ SPOTIFY_INACTIVITY_CHECK = 660 # 11 mins
|
|
|
109
109
|
# Can also be set using the -m flag
|
|
110
110
|
SPOTIFY_DISAPPEARED_CHECK_INTERVAL = 180 # 3 mins
|
|
111
111
|
|
|
112
|
-
# Whether to auto
|
|
112
|
+
# Whether to auto-play each listened song in your Spotify client
|
|
113
113
|
# Can also be set using the -g flag
|
|
114
114
|
TRACK_SONGS = False
|
|
115
115
|
|
|
@@ -202,7 +202,7 @@ SP_LOGFILE = "spotify_monitor"
|
|
|
202
202
|
# Can also be disabled via the -d flag
|
|
203
203
|
DISABLE_LOGGING = False
|
|
204
204
|
|
|
205
|
-
# Width of horizontal line
|
|
205
|
+
# Width of horizontal line
|
|
206
206
|
HORIZONTAL_LINE = 113
|
|
207
207
|
|
|
208
208
|
# Whether to clear the terminal screen after starting the tool
|
|
@@ -396,10 +396,7 @@ SP_CACHED_CLIENT_ID = ""
|
|
|
396
396
|
SP_CACHED_USER_AGENT = ""
|
|
397
397
|
|
|
398
398
|
# URL of the Spotify Web Player endpoint to get access token
|
|
399
|
-
TOKEN_URL = "https://open.spotify.com/
|
|
400
|
-
|
|
401
|
-
# URL of the endpoint to get server time needed to create TOTP object
|
|
402
|
-
SERVER_TIME_URL = "https://open.spotify.com/server-time"
|
|
399
|
+
TOKEN_URL = "https://open.spotify.com/api/token"
|
|
403
400
|
|
|
404
401
|
# Variables for caching functionality of the Spotify client token to avoid unnecessary refreshing
|
|
405
402
|
SP_CACHED_CLIENT_TOKEN = None
|
|
@@ -451,6 +448,7 @@ import shutil
|
|
|
451
448
|
from pathlib import Path
|
|
452
449
|
import secrets
|
|
453
450
|
from typing import Optional
|
|
451
|
+
from email.utils import parsedate_to_datetime
|
|
454
452
|
|
|
455
453
|
import urllib3
|
|
456
454
|
if not VERIFY_SSL:
|
|
@@ -512,7 +510,7 @@ def signal_handler(sig, frame):
|
|
|
512
510
|
# Checks internet connectivity
|
|
513
511
|
def check_internet(url=CHECK_INTERNET_URL, timeout=CHECK_INTERNET_TIMEOUT, verify=VERIFY_SSL):
|
|
514
512
|
try:
|
|
515
|
-
_ = req.get(url, timeout=timeout, verify=verify)
|
|
513
|
+
_ = req.get(url, headers={'User-Agent': get_random_user_agent() if TOKEN_SOURCE == 'cookie' else get_random_spotify_user_agent()}, timeout=timeout, verify=verify)
|
|
516
514
|
return True
|
|
517
515
|
except req.RequestException as e:
|
|
518
516
|
print(f"* No connectivity, please check your network:\n\n{e}")
|
|
@@ -982,10 +980,14 @@ def check_token_validity(access_token: str, client_id: Optional[str] = None, use
|
|
|
982
980
|
url = "https://api.spotify.com/v1/me"
|
|
983
981
|
headers = {"Authorization": f"Bearer {access_token}"}
|
|
984
982
|
|
|
985
|
-
if
|
|
983
|
+
if user_agent is not None:
|
|
986
984
|
headers.update({
|
|
987
|
-
"
|
|
988
|
-
|
|
985
|
+
"User-Agent": user_agent
|
|
986
|
+
})
|
|
987
|
+
|
|
988
|
+
if TOKEN_SOURCE == "cookie" and client_id is not None:
|
|
989
|
+
headers.update({
|
|
990
|
+
"Client-Id": client_id
|
|
989
991
|
})
|
|
990
992
|
|
|
991
993
|
if platform.system() != 'Windows':
|
|
@@ -1087,30 +1089,10 @@ def get_random_user_agent() -> str:
|
|
|
1087
1089
|
return ""
|
|
1088
1090
|
|
|
1089
1091
|
|
|
1090
|
-
#
|
|
1091
|
-
def
|
|
1092
|
-
data = data.replace(" ", "")
|
|
1093
|
-
return bytes.fromhex(data)
|
|
1094
|
-
|
|
1095
|
-
|
|
1096
|
-
# Creates a TOTP object using a secret derived from transformed cipher bytes
|
|
1097
|
-
def generate_totp(ua: str):
|
|
1098
|
-
import pyotp
|
|
1099
|
-
|
|
1100
|
-
secret_cipher_bytes = [
|
|
1101
|
-
12, 56, 76, 33, 88, 44, 88, 33,
|
|
1102
|
-
78, 78, 11, 66, 22, 22, 55, 69, 54,
|
|
1103
|
-
]
|
|
1104
|
-
|
|
1105
|
-
transformed = [e ^ ((t % 33) + 9) for t, e in enumerate(secret_cipher_bytes)]
|
|
1106
|
-
joined = "".join(str(num) for num in transformed)
|
|
1107
|
-
utf8_bytes = joined.encode("utf-8")
|
|
1108
|
-
hex_str = "".join(format(b, 'x') for b in utf8_bytes)
|
|
1109
|
-
secret_bytes = hex_to_bytes(hex_str)
|
|
1110
|
-
secret = base64.b32encode(secret_bytes).decode().rstrip('=')
|
|
1092
|
+
# Returns Spotify edge-server Unix time
|
|
1093
|
+
def fetch_server_time(session: req.Session, ua: str) -> int:
|
|
1111
1094
|
|
|
1112
1095
|
headers = {
|
|
1113
|
-
"Host": "open.spotify.com",
|
|
1114
1096
|
"User-Agent": ua,
|
|
1115
1097
|
"Accept": "*/*",
|
|
1116
1098
|
}
|
|
@@ -1119,24 +1101,34 @@ def generate_totp(ua: str):
|
|
|
1119
1101
|
if platform.system() != 'Windows':
|
|
1120
1102
|
signal.signal(signal.SIGALRM, timeout_handler)
|
|
1121
1103
|
signal.alarm(FUNCTION_TIMEOUT + 2)
|
|
1122
|
-
|
|
1123
|
-
|
|
1124
|
-
|
|
1104
|
+
response = session.head("https://open.spotify.com/", headers=headers, timeout=FUNCTION_TIMEOUT, verify=VERIFY_SSL)
|
|
1105
|
+
response.raise_for_status()
|
|
1106
|
+
except TimeoutException as e:
|
|
1107
|
+
raise Exception(f"fetch_server_time() head network request timeout after {display_time(FUNCTION_TIMEOUT + 2)}: {e}")
|
|
1108
|
+
except Exception as e:
|
|
1109
|
+
raise Exception(f"fetch_server_time() head network request error: {e}")
|
|
1125
1110
|
finally:
|
|
1126
1111
|
if platform.system() != 'Windows':
|
|
1127
1112
|
signal.alarm(0)
|
|
1128
1113
|
|
|
1129
|
-
|
|
1114
|
+
return int(parsedate_to_datetime(response.headers["Date"]).timestamp())
|
|
1130
1115
|
|
|
1131
|
-
json_data = resp.json()
|
|
1132
|
-
server_time = json_data.get("serverTime")
|
|
1133
1116
|
|
|
1134
|
-
|
|
1135
|
-
|
|
1117
|
+
# Creates a TOTP object using a secret derived from transformed cipher bytes
|
|
1118
|
+
def generate_totp():
|
|
1119
|
+
import pyotp
|
|
1120
|
+
|
|
1121
|
+
secret_cipher_bytes = [
|
|
1122
|
+
12, 56, 76, 33, 88, 44, 88, 33,
|
|
1123
|
+
78, 78, 11, 66, 22, 22, 55, 69, 54,
|
|
1124
|
+
]
|
|
1136
1125
|
|
|
1137
|
-
|
|
1126
|
+
transformed = [e ^ ((t % 33) + 9) for t, e in enumerate(secret_cipher_bytes)]
|
|
1127
|
+
joined = "".join(str(num) for num in transformed)
|
|
1128
|
+
hex_str = joined.encode().hex()
|
|
1129
|
+
secret = base64.b32encode(bytes.fromhex(hex_str)).decode().rstrip("=")
|
|
1138
1130
|
|
|
1139
|
-
return
|
|
1131
|
+
return pyotp.TOTP(secret, digits=6, interval=30)
|
|
1140
1132
|
|
|
1141
1133
|
|
|
1142
1134
|
# Retrieves a new Spotify access token using the sp_dc cookie, tries first with mode "transport" and if needed with "init"
|
|
@@ -1149,7 +1141,8 @@ def refresh_token(sp_dc: str) -> dict:
|
|
|
1149
1141
|
token = ""
|
|
1150
1142
|
|
|
1151
1143
|
ua = get_random_user_agent()
|
|
1152
|
-
|
|
1144
|
+
server_time = fetch_server_time(session, ua)
|
|
1145
|
+
totp_obj = generate_totp()
|
|
1153
1146
|
client_time = int(time_ns() / 1000 / 1000)
|
|
1154
1147
|
otp_value = totp_obj.at(server_time)
|
|
1155
1148
|
|
|
@@ -1161,11 +1154,15 @@ def refresh_token(sp_dc: str) -> dict:
|
|
|
1161
1154
|
"totpVer": 5,
|
|
1162
1155
|
"sTime": server_time,
|
|
1163
1156
|
"cTime": client_time,
|
|
1157
|
+
"buildDate": time.strftime("%Y-%m-%d", time.gmtime(server_time)),
|
|
1158
|
+
"buildVer": f"web-player_{time.strftime('%Y-%m-%d', time.gmtime(server_time))}_{server_time * 1000}_{secrets.token_hex(4)}",
|
|
1164
1159
|
}
|
|
1165
1160
|
|
|
1166
1161
|
headers = {
|
|
1167
1162
|
"User-Agent": ua,
|
|
1168
1163
|
"Accept": "application/json",
|
|
1164
|
+
"Referer": "https://open.spotify.com/",
|
|
1165
|
+
"App-Platform": "WebPlayer",
|
|
1169
1166
|
"Cookie": f"sp_dc={sp_dc}",
|
|
1170
1167
|
}
|
|
1171
1168
|
|
|
@@ -1358,12 +1355,6 @@ def read_varint(data, index):
|
|
|
1358
1355
|
|
|
1359
1356
|
# Parses Spotify Protobuf login response
|
|
1360
1357
|
def parse_protobuf_message(data):
|
|
1361
|
-
"""
|
|
1362
|
-
Recursively parses a Protobuf message, returns a dictionary mapping tags to values
|
|
1363
|
-
|
|
1364
|
-
If a length-delimited field's first byte is a control character (i.e. < 0x20), we assume it is a nested message
|
|
1365
|
-
and parse it recursively, otherwise we decode it as UTF-8
|
|
1366
|
-
"""
|
|
1367
1358
|
index = 0
|
|
1368
1359
|
result = {}
|
|
1369
1360
|
while index < len(data):
|
|
@@ -1401,7 +1392,6 @@ def parse_protobuf_message(data):
|
|
|
1401
1392
|
# (device_id, system_id, user_uri_id, refresh_token)
|
|
1402
1393
|
def parse_request_body_file(file_path):
|
|
1403
1394
|
"""
|
|
1404
|
-
Expected structure:
|
|
1405
1395
|
{
|
|
1406
1396
|
1: {
|
|
1407
1397
|
1: "device_id",
|
|
@@ -1566,7 +1556,7 @@ def build_clienttoken_request_protobuf(app_version, device_id, system_id, cpu_ar
|
|
|
1566
1556
|
def spotify_get_access_token_from_client(device_id, system_id, user_uri_id, refresh_token, client_token):
|
|
1567
1557
|
global SP_CACHED_ACCESS_TOKEN, SP_CACHED_REFRESH_TOKEN, SP_ACCESS_TOKEN_EXPIRES_AT
|
|
1568
1558
|
|
|
1569
|
-
if SP_CACHED_ACCESS_TOKEN and time.time() < SP_ACCESS_TOKEN_EXPIRES_AT and check_token_validity(SP_CACHED_ACCESS_TOKEN):
|
|
1559
|
+
if SP_CACHED_ACCESS_TOKEN and time.time() < SP_ACCESS_TOKEN_EXPIRES_AT and check_token_validity(SP_CACHED_ACCESS_TOKEN, user_agent=USER_AGENT):
|
|
1570
1560
|
return SP_CACHED_ACCESS_TOKEN
|
|
1571
1561
|
|
|
1572
1562
|
if not client_token:
|
|
@@ -1578,8 +1568,8 @@ def spotify_get_access_token_from_client(device_id, system_id, user_uri_id, refr
|
|
|
1578
1568
|
protobuf_body = build_spotify_auth_protobuf(device_id, system_id, user_uri_id, refresh_token)
|
|
1579
1569
|
|
|
1580
1570
|
parsed_url = urlparse(LOGIN_URL)
|
|
1581
|
-
host = parsed_url.netloc
|
|
1582
|
-
origin = f"{parsed_url.scheme}://{parsed_url.netloc}"
|
|
1571
|
+
host = parsed_url.netloc
|
|
1572
|
+
origin = f"{parsed_url.scheme}://{parsed_url.netloc}"
|
|
1583
1573
|
|
|
1584
1574
|
headers = {
|
|
1585
1575
|
"Host": host,
|
|
@@ -1601,8 +1591,10 @@ def spotify_get_access_token_from_client(device_id, system_id, user_uri_id, refr
|
|
|
1601
1591
|
signal.signal(signal.SIGALRM, timeout_handler)
|
|
1602
1592
|
signal.alarm(FUNCTION_TIMEOUT + 2)
|
|
1603
1593
|
response = req.post(LOGIN_URL, headers=headers, data=protobuf_body, timeout=FUNCTION_TIMEOUT, verify=VERIFY_SSL)
|
|
1604
|
-
except
|
|
1594
|
+
except TimeoutException as e:
|
|
1605
1595
|
raise Exception(f"spotify_get_access_token_from_client() network request timeout after {display_time(FUNCTION_TIMEOUT + 2)}: {e}")
|
|
1596
|
+
except Exception as e:
|
|
1597
|
+
raise Exception(f"spotify_get_access_token_from_client() network request error: {e}")
|
|
1606
1598
|
finally:
|
|
1607
1599
|
if platform.system() != 'Windows':
|
|
1608
1600
|
signal.alarm(0)
|
|
@@ -1673,8 +1665,10 @@ def spotify_get_client_token(app_version, device_id, system_id, **device_overrid
|
|
|
1673
1665
|
signal.signal(signal.SIGALRM, timeout_handler)
|
|
1674
1666
|
signal.alarm(FUNCTION_TIMEOUT + 2)
|
|
1675
1667
|
response = req.post(CLIENTTOKEN_URL, headers=headers, data=body, timeout=FUNCTION_TIMEOUT, verify=VERIFY_SSL)
|
|
1676
|
-
except
|
|
1668
|
+
except TimeoutException as e:
|
|
1677
1669
|
raise Exception(f"spotify_get_client_token() network request timeout after {display_time(FUNCTION_TIMEOUT + 2)}: {e}")
|
|
1670
|
+
except Exception as e:
|
|
1671
|
+
raise Exception(f"spotify_get_client_token() network request error: {e}")
|
|
1678
1672
|
finally:
|
|
1679
1673
|
if platform.system() != 'Windows':
|
|
1680
1674
|
signal.alarm(0)
|
|
@@ -1685,7 +1679,7 @@ def spotify_get_client_token(app_version, device_id, system_id, **device_overrid
|
|
|
1685
1679
|
parsed = parse_protobuf_message(response.content)
|
|
1686
1680
|
inner = parsed.get(2, {})
|
|
1687
1681
|
client_token = deep_flatten(inner.get(1)) if inner.get(1) else None
|
|
1688
|
-
ttl = int(inner.get(3, 0)) or 1209600
|
|
1682
|
+
ttl = int(inner.get(3, 0)) or 1209600
|
|
1689
1683
|
|
|
1690
1684
|
if not client_token:
|
|
1691
1685
|
raise Exception("clienttoken response did not contain a token")
|
|
@@ -1748,6 +1742,10 @@ def spotify_get_friends_json(access_token):
|
|
|
1748
1742
|
"Client-Id": SP_CACHED_CLIENT_ID,
|
|
1749
1743
|
"User-Agent": SP_CACHED_USER_AGENT,
|
|
1750
1744
|
})
|
|
1745
|
+
elif TOKEN_SOURCE == "client":
|
|
1746
|
+
headers.update({
|
|
1747
|
+
"User-Agent": USER_AGENT
|
|
1748
|
+
})
|
|
1751
1749
|
|
|
1752
1750
|
response = SESSION.get(url, headers=headers, timeout=FUNCTION_TIMEOUT, verify=VERIFY_SSL)
|
|
1753
1751
|
if response.status_code == 401:
|
|
@@ -1807,8 +1805,6 @@ def spotify_list_friends(friend_activity):
|
|
|
1807
1805
|
sp_playlist_uri = friend["track"]["context"].get("uri")
|
|
1808
1806
|
sp_track_uri = friend["track"].get("uri")
|
|
1809
1807
|
|
|
1810
|
-
# if index > 0:
|
|
1811
|
-
# print("─" * HORIZONTAL_LINE)
|
|
1812
1808
|
print("─" * HORIZONTAL_LINE)
|
|
1813
1809
|
print(f"Username:\t\t\t{sp_username}")
|
|
1814
1810
|
print(f"User URI ID:\t\t\t{sp_uri}")
|
|
@@ -1877,6 +1873,10 @@ def spotify_get_track_info(access_token, track_uri):
|
|
|
1877
1873
|
"Client-Id": SP_CACHED_CLIENT_ID,
|
|
1878
1874
|
"User-Agent": SP_CACHED_USER_AGENT,
|
|
1879
1875
|
})
|
|
1876
|
+
elif TOKEN_SOURCE == "client":
|
|
1877
|
+
headers.update({
|
|
1878
|
+
"User-Agent": USER_AGENT
|
|
1879
|
+
})
|
|
1880
1880
|
# add si parameter so link opens in native Spotify app after clicking
|
|
1881
1881
|
si = "?si=1"
|
|
1882
1882
|
|
|
@@ -1907,6 +1907,10 @@ def spotify_get_playlist_info(access_token, playlist_uri):
|
|
|
1907
1907
|
"Client-Id": SP_CACHED_CLIENT_ID,
|
|
1908
1908
|
"User-Agent": SP_CACHED_USER_AGENT,
|
|
1909
1909
|
})
|
|
1910
|
+
elif TOKEN_SOURCE == "client":
|
|
1911
|
+
headers.update({
|
|
1912
|
+
"User-Agent": USER_AGENT
|
|
1913
|
+
})
|
|
1910
1914
|
# add si parameter so link opens in native Spotify app after clicking
|
|
1911
1915
|
si = "?si=1"
|
|
1912
1916
|
|
|
@@ -1934,6 +1938,10 @@ def spotify_get_current_user(access_token) -> dict | None:
|
|
|
1934
1938
|
"Client-Id": SP_CACHED_CLIENT_ID,
|
|
1935
1939
|
"User-Agent": SP_CACHED_USER_AGENT,
|
|
1936
1940
|
})
|
|
1941
|
+
elif TOKEN_SOURCE == "client":
|
|
1942
|
+
headers.update({
|
|
1943
|
+
"User-Agent": USER_AGENT
|
|
1944
|
+
})
|
|
1937
1945
|
|
|
1938
1946
|
if platform.system() != 'Windows':
|
|
1939
1947
|
signal.signal(signal.SIGALRM, timeout_handler)
|
|
@@ -2916,7 +2924,7 @@ def main():
|
|
|
2916
2924
|
dest="track_in_spotify",
|
|
2917
2925
|
action="store_true",
|
|
2918
2926
|
default=None,
|
|
2919
|
-
help="Auto
|
|
2927
|
+
help="Auto-play each listened song in your Spotify client"
|
|
2920
2928
|
)
|
|
2921
2929
|
opts.add_argument(
|
|
2922
2930
|
"-b", "--csv-file",
|
|
@@ -1,7 +0,0 @@
|
|
|
1
|
-
spotify_monitor.py,sha256=g_kitqHOJr-708PeGjrosvMG3Om6AzH6d0xE8VdPbDc,145830
|
|
2
|
-
spotify_monitor-2.1.dist-info/licenses/LICENSE,sha256=OXLcl0T2SZ8Pmy2_dmlvKuetivmyPd5m1q-Gyd-zaYY,35149
|
|
3
|
-
spotify_monitor-2.1.dist-info/METADATA,sha256=4OdX74oC29gletoUAq0amLvMkKcq-GqOxXVt1E_ATTQ,21529
|
|
4
|
-
spotify_monitor-2.1.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
|
|
5
|
-
spotify_monitor-2.1.dist-info/entry_points.txt,sha256=8HzePfUcCSXrYaXOwLbNNYO8GJcnhgCSl4wcDNECht8,57
|
|
6
|
-
spotify_monitor-2.1.dist-info/top_level.txt,sha256=EP6IPD4vHT12rLM5b_jo2i3nrfOuwk3ehhr2gWdQx9Y,16
|
|
7
|
-
spotify_monitor-2.1.dist-info/RECORD,,
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|