added model magic functions

This commit is contained in:
aj 2019-09-13 16:31:40 +01:00
parent 3879562e82
commit 92217ad3a4
9 changed files with 121 additions and 5 deletions

View File

@ -11,7 +11,7 @@ logger = logging.getLogger('spotframework')
log_format = '%(asctime)s %(levelname)s %(name)s - %(funcName)s - %(message)s'
file_handler = logging.FileHandler(".spot/resort_playlist.log")
file_handler = logging.FileHandler(".spot/sort_playlist.log")
formatter = logging.Formatter(log_format)
file_handler.setFormatter(formatter)

View File

@ -1,6 +1,7 @@
from __future__ import annotations
from typing import TYPE_CHECKING
from typing import List
from spotframework.util.console import Color
if TYPE_CHECKING:
from spotframework.model.artist import Artist
@ -23,6 +24,10 @@ class Album:
return f'{self.name} / {artists}'
def __repr__(self):
return Color.DARKCYAN + Color.BOLD + 'Album' + Color.END + \
f': {self.name}, [{self.artists}]'
class SpotifyAlbum(Album):
def __init__(self,
@ -56,3 +61,7 @@ class SpotifyAlbum(Album):
self.label = label
self.popularity = popularity
def __repr__(self):
return Color.DARKCYAN + Color.BOLD + 'SpotifyAlbum' + Color.END + \
f': {self.name}, {self.artists}, {self.uri}, {self.tracks}'

View File

@ -1,4 +1,5 @@
from typing import List
from spotframework.util.console import Color
class Artist:
@ -8,6 +9,10 @@ class Artist:
def __str__(self):
return f'{self.name}'
def __repr__(self):
return Color.PURPLE + Color.BOLD + 'Artist' + Color.END + \
f': {self.name}'
class SpotifyArtist(Artist):
def __init__(self,
@ -30,3 +35,7 @@ class SpotifyArtist(Artist):
self.genres = genres
self.popularity = popularity
def __repr__(self):
return Color.PURPLE + Color.BOLD + 'SpotifyArtist' + Color.END + \
f': {self.name}, {self.uri}'

View File

@ -1,5 +1,6 @@
from spotframework.model.user import User
from spotframework.model.track import Track, SpotifyTrack, PlaylistTrack
from spotframework.util.console import Color
from tabulate import tabulate
from typing import List
import logging
@ -50,9 +51,46 @@ class Playlist:
prefix = f'\n==={self.name}===\n\n' if self.name is not None else ''
table = prefix + self.get_tracks_string() + '\n' + f'total: {len(self)}'
return table
def __repr__(self):
return Color.GREEN + Color.BOLD + 'Playlist' + Color.END + \
f': {self.name}, ({len(self)})'
def __add__(self, other):
if isinstance(other, Track):
self.tracks.append(other)
return self
elif isinstance(other, list):
if all((isinstance(i, Track) for i in other)):
self.tracks += other
return self
else:
logger.error('list not full of tracks')
raise TypeError('list not full of tracks')
else:
logger.error('list of tracks needed to add')
raise TypeError('list of tracks needed to add')
def __sub__(self, other):
if isinstance(other, Track):
self.tracks.remove(other)
return self
elif isinstance(other, list):
if all((isinstance(i, Track) for i in other)):
self.tracks -= other
return self
else:
logger.error('list not full of tracks')
raise TypeError('list not full of tracks')
else:
logger.error('list of tracks needed to subtract')
raise TypeError('list of tracks needed to subtract')
def get_tracks_string(self):
rows = []
@ -109,3 +147,7 @@ class SpotifyPlaylist(Playlist):
table = prefix + self.get_tracks_string() + '\n' + f'total: {len(self)}'
return table
def __repr__(self):
return Color.GREEN + Color.BOLD + 'SpotifyPlaylist' + Color.END + \
f': {self.name} ({self.owner}), ({len(self)}), {self.uri}'

View File

@ -2,6 +2,7 @@ from __future__ import annotations
from typing import TYPE_CHECKING
from typing import List
from datetime import datetime
from spotframework.util.console import Color
if TYPE_CHECKING:
from spotframework.model.album import Album
from spotframework.model.artist import Artist
@ -44,6 +45,10 @@ class Track:
return f'{self.name} / {album} / {artists}'
def __repr__(self):
return Color.YELLOW + Color.BOLD + 'Track' + Color.END + \
f': {self.name}, ({self.album}), {self.artists}'
class SpotifyTrack(Track):
def __init__(self,
@ -74,6 +79,10 @@ class SpotifyTrack(Track):
self.popularity = popularity
def __repr__(self):
return Color.BOLD + Color.YELLOW + 'SpotifyTrack' + Color.END + \
f': {self.name}, ({self.album}), {self.artists}, {self.uri}'
class PlaylistTrack(SpotifyTrack):
def __init__(self,
@ -110,3 +119,7 @@ class PlaylistTrack(SpotifyTrack):
self.added_at = datetime.fromisoformat(added_at.replace('T', ' ').replace('Z', ''))
self.added_by = added_by
self.is_local = is_local
def __repr__(self):
return Color.BOLD + Color.YELLOW + 'PlaylistTrack' + Color.END + \
f': {self.name}, ({self.album}), {self.artists}, {self.uri}, {self.added_at}'

View File

@ -1,3 +1,4 @@
from spotframework.util.console import Color
class User:
@ -19,3 +20,7 @@ class User:
def __str__(self):
return f'{self.username}'
def __repr__(self):
return Color.RED + Color.BOLD + 'User' + Color.END + \
f': {self.username}, {self.display_name}, {self.uri}'

View File

@ -5,6 +5,7 @@ import time
from typing import List, Optional
from . import const
from spotframework.net.parse import parse
from spotframework.net.user import NetworkUser
from spotframework.model.playlist import SpotifyPlaylist
from spotframework.model.track import Track, PlaylistTrack
from requests.models import Response
@ -16,7 +17,7 @@ logger = logging.getLogger(__name__)
class Network:
def __init__(self, user):
def __init__(self, user: NetworkUser):
self.user = user
def _make_get_request(self, method, url, params=None, headers={}) -> Optional[dict]:
@ -40,6 +41,11 @@ class Network:
else:
logger.error(f'{method} rate limit reached: cannot find Retry-After header')
elif req.status_code == 401:
logger.warning(f'{method} access token expired, refreshing')
self.user.refresh_token()
return self._make_get_request(method, url, params, headers)
else:
error_text = req.json()['error']['message']
logger.error(f'{method} get {req.status_code} {error_text}')
@ -67,6 +73,11 @@ class Network:
else:
logger.error(f'{method} rate limit reached: cannot find Retry-After header')
elif req.status_code == 401:
logger.warning(f'{method} access token expired, refreshing')
self.user.refresh_token()
return self._make_post_request(method, url, params, json, headers)
else:
error_text = str(req.text)
logger.error(f'{method} post {req.status_code} {error_text}')
@ -94,6 +105,11 @@ class Network:
else:
logger.error(f'{method} rate limit reached: cannot find Retry-After header')
elif req.status_code == 401:
logger.warning(f'{method} access token expired, refreshing')
self.user.refresh_token()
return self._make_put_request(method, url, params, json, headers)
else:
error_text = str(req.text)
logger.error(f'{method} put {req.status_code} {error_text}')

View File

@ -1,5 +1,6 @@
import requests
from spotframework.model.user import User
from spotframework.util.console import Color
from base64 import b64encode
import logging
import time
@ -22,6 +23,10 @@ class NetworkUser(User):
self.refresh_token()
self.refresh_info()
def __repr__(self):
return Color.RED + Color.BOLD + 'NetworkUser' + Color.END + \
f': {self.username}, {self.display_name}, {self.uri}'
def refresh_token(self) -> None:
if self.refreshtoken is None:
@ -53,7 +58,7 @@ class NetworkUser(User):
time.sleep(int(retry_after) + 1)
return self.refresh_token()
else:
logger.error(f'refresh_token rate limit reached: cannot find Retry-After header')
logger.error('refresh_token rate limit reached: cannot find Retry-After header')
else:
error_text = req.json()['error']['message']
@ -97,7 +102,12 @@ class NetworkUser(User):
time.sleep(int(retry_after) + 1)
return self.get_info()
else:
logger.error(f'get_info rate limit reached: cannot find Retry-After header')
logger.error('get_info rate limit reached: cannot find Retry-After header')
elif req.status_code == 401:
logger.warning('access token expired, refreshing')
self.refresh_token()
return self.get_info()
else:
error_text = req.json()['error']['message']

View File

@ -0,0 +1,12 @@
class Color:
PURPLE = '\033[95m'
CYAN = '\033[96m'
DARKCYAN = '\033[36m'
BLUE = '\033[94m'
GREEN = '\033[92m'
YELLOW = '\033[93m'
RED = '\033[91m'
BOLD = '\033[1m'
UNDERLINE = '\033[4m'
END = '\033[0m'