Created
March 3, 2021 19:38
-
-
Save Romern/b47f749213910366684b056d7140a1e9 to your computer and use it in GitHub Desktop.
Napster stream API used in android app (no drm)
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import requests | |
from requests.auth import HTTPBasicAuth | |
import json | |
from pathlib import Path | |
apikey = 'ZTJlOWNhZGUtNzlmZS00ZGU2LTkwYjMtZDk1ODRlMDkwODM5' #from the APK | |
secret = 'MTRjZTVjM2EtOGVlZi00OTU3LWFmNjktNTllODFhNmYyNzI5' #from the APK | |
def download_file(url, filename): | |
with requests.get(url, stream=True) as r: | |
r.raise_for_status() | |
with open(filename, 'wb') as f: | |
for chunk in r.iter_content(chunk_size=8192): | |
# If you have chunk encoded response uncomment if | |
# and set chunk_size parameter to None. | |
#if chunk: | |
f.write(chunk) | |
def search(query): | |
headers = { | |
'apikey': apikey, | |
'User-Agent': 'okhttp/3.12.1', | |
} | |
params = ( | |
('catalog', 'DE'), | |
('lang', 'de_DE'), | |
('offset', '0'), | |
('per_type_limit', '5'), | |
('query', query), | |
('rights', '2'), | |
('type', 'album,artist,track'), | |
) | |
response = requests.get('http://api.rhapsody.com/v2.2/search', headers=headers, params=params) | |
return response.json() | |
#album_id e.g. alb.XXXXXXXXXXX | |
def get_album_tracks_info(album_id): | |
if "alb." != album_id[:len("alb.")]: | |
raise Exception("not an album id") | |
headers = { | |
'apikey': apikey, | |
'User-Agent': 'okhttp/3.12.1', | |
} | |
params = ( | |
('catalog', 'DE'), | |
('lang', 'de_DE'), | |
('rights', '2'), | |
) | |
response = requests.get(f'http://api.rhapsody.com/v2.2/albums/{album_id}/tracks', headers=headers, params=params) | |
return response.json() | |
def auth_user(username, password): | |
headers = { | |
'User-Agent': 'okhttp/3.12.1', | |
} | |
data = { | |
'username': username, | |
'password': password, | |
'grant_type': 'password' | |
} | |
response = requests.post('https://api.rhapsody.com/oauth/token', headers=headers, data=data, auth=HTTPBasicAuth(apikey, secret)) | |
return response.json()["access_token"] # also contains other stuff | |
def get_audio_stream_info(track_id, access_token, bitrate=44100, format="FLAC"): | |
if "tra." != track_id[:len("tra.")]: | |
raise Exception("not an track id") | |
headers = { | |
'Accept': 'application/json', | |
'Authorization': f'Bearer {access_token}', | |
'Host': 'api.rhapsody.com', | |
'User-Agent': 'okhttp/3.12.1', | |
} | |
params = ( | |
('bitrate', str(bitrate)), | |
('format', format), | |
('protocol', ''), | |
('track', track_id), | |
) | |
response = requests.get('https://api.rhapsody.com/v2.2/streams', headers=headers, params=params) | |
return response.json() | |
def download_album(album_id, access_token): | |
album_info = get_album_tracks_info(album_id) | |
for track in album_info["tracks"]: | |
stream_info = get_audio_stream_info(track["id"], access_token) | |
stream_url = stream_info["streams"][0]["url"] | |
directory = Path("./") / f'{track["artistName"]} - {track["albumName"]}' | |
directory.mkdir(exist_ok=True, parents=True) | |
download_file(stream_url, directory / f'{track["index"]}. {track["name"]}.flac') |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment