-
Notifications
You must be signed in to change notification settings - Fork 0
/
spotify.py
86 lines (74 loc) · 2.67 KB
/
spotify.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
import logging
import os
from pathlib import Path
from typing import Any, Callable, Dict, Iterable
from spotipy import Spotify
from spotipy.cache_handler import CacheFileHandler
from spotipy.oauth2 import SpotifyOAuth
CLIENT_ID = os.getenv("SPOTIPY_CLIENT_ID", "aba916bbd6214fdc8bc993344439c58e")
REDIRECT_URI = "http://localhost/"
# SPOTIPY_CLIENT_SECRET must be provided via env variable
SCOPES = (
"playlist-read-private",
"playlist-read-collaborative",
"user-library-read", # Needed to read saved tracks
"user-top-read",
"user-follow-read",
"user-read-recently-played",
)
logger = logging.getLogger(__name__)
class SpotifyClient(Spotify):
def __init__(self):
self._auth_manager = SpotifyOAuth(
client_id=CLIENT_ID,
redirect_uri=REDIRECT_URI,
open_browser=False,
scope=",".join(SCOPES),
cache_handler=CacheFileHandler(cache_path=self.cache_path()),
)
status_forcelist = list(Spotify.default_retry_codes)
status_forcelist.append(401)
super().__init__(auth_manager=self._auth_manager, status_forcelist=status_forcelist)
self.user_id = self.me()["id"]
@staticmethod
def cache_path() -> Path:
fallback_path = Path(os.environ["HOME"], ".config")
return Path(
os.environ.get("XDG_CONFIG_HOME", fallback_path),
"spotify-backup",
)
def get_all_items(self, func: Callable, **kwargs) -> Dict:
"""Return all items for a paginated result set of Spotify"""
result = func(**kwargs)
items = result["items"]
while result["next"]:
result = self.next(result)
items.extend(result["items"])
return items
@staticmethod
def chunks(lst: Iterable, n: int) -> Iterable[Any]:
"""Yield successive n-sized chunks from lst."""
for i in range(0, len(lst), n):
yield lst[i : i + n]
def create_playlist(self, name: str, uris: Iterable[str]) -> Dict:
"""Create a copy of the playlist in json_path"""
uris_count = len(uris)
logger.info("Copying playlist as %s (%d tracks)", name, uris_count)
dst = self.user_playlist_create(
self.user_id,
name,
public=False,
collaborative=False,
)
dst_id = dst["id"]
logger.debug("Destination playlist ID: %s", dst_id)
count = 0
for chunk in self.chunks(uris, 100):
count += len(chunk)
self.playlist_add_items(dst_id, chunk)
logger.info(
"Copied %s of %s tracks",
count,
uris_count,
)
return dst