zspotify/zspotify/zspotify.py

98 lines
3.5 KiB
Python
Raw Normal View History

import os
import os.path
from getpass import getpass
import time
import requests
from librespot.audio.decoders import VorbisOnlyAudioQuality
from librespot.core import Session
from const import TYPE, \
2021-11-30 09:03:45 +01:00
PREMIUM, USER_READ_EMAIL, OFFSET, LIMIT, \
2021-11-18 22:16:07 +01:00
PLAYLIST_READ_PRIVATE, USER_LIBRARY_READ
from config import Config
class ZSpotify:
SESSION: Session = None
DOWNLOAD_QUALITY = None
2021-11-18 22:39:17 +01:00
CONFIG: Config = Config()
2021-11-18 22:16:07 +01:00
def __init__(self, args):
ZSpotify.CONFIG.load(args)
ZSpotify.login()
@classmethod
def login(cls):
""" Authenticates with Spotify and saves credentials to a file """
2021-11-24 14:40:14 +01:00
cred_location = Config.get_credentials_location()
if os.path.isfile(cred_location):
try:
cls.SESSION = Session.Builder().stored_file(cred_location).create()
return
except RuntimeError:
pass
while True:
2021-10-24 01:17:04 +02:00
user_name = ''
while len(user_name) == 0:
user_name = input('Username: ')
password = getpass()
try:
conf = Session.Configuration.Builder().set_stored_credential_file(cred_location).build()
cls.SESSION = Session.Builder(conf).user_pass(user_name, password).create()
return
except RuntimeError:
pass
@classmethod
def get_content_stream(cls, content_id, quality):
return cls.SESSION.content_feeder().load(content_id, VorbisOnlyAudioQuality(quality), False, None)
@classmethod
def __get_auth_token(cls):
return cls.SESSION.tokens().get_token(USER_READ_EMAIL, PLAYLIST_READ_PRIVATE, USER_LIBRARY_READ).access_token
@classmethod
def get_auth_header(cls):
return {
2021-11-05 11:50:27 +01:00
'Authorization': f'Bearer {cls.__get_auth_token()}',
2021-11-18 22:39:17 +01:00
'Accept-Language': f'{cls.CONFIG.get_language()}'
2021-11-05 11:50:27 +01:00
}
@classmethod
def get_auth_header_and_params(cls, limit, offset):
2021-11-05 11:59:40 +01:00
return {
'Authorization': f'Bearer {cls.__get_auth_token()}',
2021-11-18 22:39:17 +01:00
'Accept-Language': f'{cls.CONFIG.get_language()}'
2021-11-05 11:59:40 +01:00
}, {LIMIT: limit, OFFSET: offset}
@classmethod
def invoke_url_with_params(cls, url, limit, offset, **kwargs):
headers, params = cls.get_auth_header_and_params(limit=limit, offset=offset)
params.update(kwargs)
return requests.get(url, headers=headers, params=params).json()
@classmethod
2021-12-18 10:11:43 +01:00
def invoke_url(cls, url, tryCount=0):
# we need to import that here, otherwise we will get circular imports!
2021-12-18 10:11:43 +01:00
from termoutput import Printer, PrintChannel
headers = cls.get_auth_header()
response = requests.get(url, headers=headers)
2021-12-15 14:49:12 +01:00
responsetext = response.text
responsejson = response.json()
2021-12-18 10:11:43 +01:00
2021-12-15 15:15:16 +01:00
if 'error' in responsejson:
if tryCount < (cls.CONFIG.get_retry_attempts() - 1):
2021-12-18 10:11:43 +01:00
Printer.print(PrintChannel.WARNINGS, f"Spotify API Error (try {tryCount + 1}) ({responsejson['error']['status']}): {responsejson['error']['message']}")
2021-12-15 15:15:16 +01:00
time.sleep(5)
return cls.invoke_url(url, tryCount + 1)
2021-12-15 14:49:12 +01:00
Printer.print(PrintChannel.API_ERRORS, f"Spotify API Error ({responsejson['error']['status']}): {responsejson['error']['message']}")
2021-12-15 15:15:16 +01:00
2021-12-15 14:49:12 +01:00
return responsetext, responsejson
@classmethod
def check_premium(cls) -> bool:
""" If user has spotify premium return true """
2021-11-18 22:39:17 +01:00
return (cls.SESSION.get_user_attribute(TYPE) == PREMIUM) or cls.CONFIG.get_force_premium()