2022-12-08 15:45:37 +00:00
|
|
|
"""
|
|
|
|
Spotify
|
|
|
|
"""
|
|
|
|
from django.conf import settings
|
|
|
|
from catalog.common import *
|
|
|
|
from catalog.models import *
|
2023-02-03 16:33:58 -05:00
|
|
|
from catalog.music.utils import upc_to_gtin_13
|
2022-12-08 15:45:37 +00:00
|
|
|
from .douban import *
|
|
|
|
import time
|
|
|
|
import datetime
|
|
|
|
import requests
|
|
|
|
import dateparser
|
|
|
|
import logging
|
|
|
|
|
|
|
|
|
|
|
|
_logger = logging.getLogger(__name__)
|
|
|
|
|
|
|
|
|
|
|
|
spotify_token = None
|
|
|
|
spotify_token_expire_time = time.time()
|
|
|
|
|
|
|
|
|
2022-12-15 17:29:35 -05:00
|
|
|
@SiteManager.register
|
2022-12-08 15:45:37 +00:00
|
|
|
class Spotify(AbstractSite):
|
2022-12-16 01:08:10 -05:00
|
|
|
SITE_NAME = SiteName.Spotify
|
2022-12-08 15:45:37 +00:00
|
|
|
ID_TYPE = IdType.Spotify_Album
|
2022-12-29 23:57:02 -05:00
|
|
|
URL_PATTERNS = [r"\w+://open\.spotify\.com/album/([a-zA-Z0-9]+)"]
|
|
|
|
WIKI_PROPERTY_ID = "?"
|
2022-12-08 15:45:37 +00:00
|
|
|
DEFAULT_MODEL = Album
|
|
|
|
|
|
|
|
@classmethod
|
2023-02-03 16:33:58 -05:00
|
|
|
def id_to_url(cls, id_value):
|
2022-12-08 15:45:37 +00:00
|
|
|
return f"https://open.spotify.com/album/{id_value}"
|
|
|
|
|
|
|
|
def scrape(self):
|
2023-02-03 16:33:58 -05:00
|
|
|
api_url = f"https://api.spotify.com/v1/albums/{self.id_value}"
|
2022-12-29 23:57:02 -05:00
|
|
|
headers = {"Authorization": f"Bearer {get_spotify_token()}"}
|
2022-12-08 15:45:37 +00:00
|
|
|
res_data = BasicDownloader(api_url, headers=headers).download().json()
|
|
|
|
artist = []
|
2022-12-29 23:57:02 -05:00
|
|
|
for artist_dict in res_data["artists"]:
|
|
|
|
artist.append(artist_dict["name"])
|
2022-12-08 15:45:37 +00:00
|
|
|
|
2022-12-29 23:57:02 -05:00
|
|
|
title = res_data["name"]
|
2022-12-08 15:45:37 +00:00
|
|
|
|
2023-04-17 21:43:20 -04:00
|
|
|
genre = res_data.get("genres", [])
|
2022-12-08 15:45:37 +00:00
|
|
|
|
|
|
|
company = []
|
2022-12-29 23:57:02 -05:00
|
|
|
for com in res_data["copyrights"]:
|
|
|
|
company.append(com["text"])
|
2022-12-08 15:45:37 +00:00
|
|
|
|
|
|
|
duration = 0
|
|
|
|
track_list = []
|
|
|
|
track_urls = []
|
2022-12-29 23:57:02 -05:00
|
|
|
for track in res_data["tracks"]["items"]:
|
|
|
|
track_urls.append(track["external_urls"]["spotify"])
|
|
|
|
duration += track["duration_ms"]
|
|
|
|
if res_data["tracks"]["items"][-1]["disc_number"] > 1:
|
2022-12-08 15:45:37 +00:00
|
|
|
# more than one disc
|
2022-12-29 23:57:02 -05:00
|
|
|
track_list.append(
|
|
|
|
str(track["disc_number"])
|
|
|
|
+ "-"
|
|
|
|
+ str(track["track_number"])
|
|
|
|
+ ". "
|
|
|
|
+ track["name"]
|
|
|
|
)
|
2022-12-08 15:45:37 +00:00
|
|
|
else:
|
2022-12-29 23:57:02 -05:00
|
|
|
track_list.append(str(track["track_number"]) + ". " + track["name"])
|
|
|
|
track_list = "\n".join(track_list)
|
2022-12-08 15:45:37 +00:00
|
|
|
|
2022-12-29 23:57:02 -05:00
|
|
|
release_date = dateparser.parse(res_data["release_date"]).strftime("%Y-%m-%d")
|
2022-12-08 15:45:37 +00:00
|
|
|
|
|
|
|
gtin = None
|
2022-12-29 23:57:02 -05:00
|
|
|
if res_data["external_ids"].get("upc"):
|
2023-02-03 16:33:58 -05:00
|
|
|
gtin = upc_to_gtin_13(res_data["external_ids"].get("upc"))
|
2022-12-29 23:57:02 -05:00
|
|
|
if res_data["external_ids"].get("ean"):
|
2023-02-03 16:33:58 -05:00
|
|
|
gtin = upc_to_gtin_13(res_data["external_ids"].get("ean"))
|
2022-12-08 18:08:05 +00:00
|
|
|
isrc = None
|
2022-12-29 23:57:02 -05:00
|
|
|
if res_data["external_ids"].get("isrc"):
|
|
|
|
isrc = res_data["external_ids"].get("isrc")
|
|
|
|
|
|
|
|
pd = ResourceContent(
|
|
|
|
metadata={
|
|
|
|
"title": title,
|
|
|
|
"artist": artist,
|
|
|
|
"genre": genre,
|
|
|
|
"track_list": track_list,
|
|
|
|
"release_date": release_date,
|
|
|
|
"duration": duration,
|
|
|
|
"company": company,
|
|
|
|
"brief": None,
|
|
|
|
"cover_image_url": res_data["images"][0]["url"],
|
|
|
|
}
|
|
|
|
)
|
2022-12-08 15:45:37 +00:00
|
|
|
if gtin:
|
|
|
|
pd.lookup_ids[IdType.GTIN] = gtin
|
2022-12-08 18:08:05 +00:00
|
|
|
if isrc:
|
|
|
|
pd.lookup_ids[IdType.ISRC] = isrc
|
2022-12-08 15:45:37 +00:00
|
|
|
if pd.metadata["cover_image_url"]:
|
|
|
|
imgdl = BasicImageDownloader(pd.metadata["cover_image_url"], self.url)
|
|
|
|
try:
|
|
|
|
pd.cover_image = imgdl.download().content
|
|
|
|
pd.cover_image_extention = imgdl.extention
|
|
|
|
except Exception:
|
2022-12-29 23:57:02 -05:00
|
|
|
_logger.debug(
|
|
|
|
f'failed to download cover for {self.url} from {pd.metadata["cover_image_url"]}'
|
|
|
|
)
|
2022-12-08 15:45:37 +00:00
|
|
|
return pd
|
|
|
|
|
|
|
|
|
|
|
|
def get_spotify_token():
|
|
|
|
global spotify_token, spotify_token_expire_time
|
2022-12-08 16:59:03 +00:00
|
|
|
if get_mock_mode():
|
2022-12-29 23:57:02 -05:00
|
|
|
return "mocked"
|
2022-12-08 15:45:37 +00:00
|
|
|
if spotify_token is None or is_spotify_token_expired():
|
|
|
|
invoke_spotify_token()
|
|
|
|
return spotify_token
|
|
|
|
|
2022-12-16 01:08:10 -05:00
|
|
|
|
2022-12-08 15:45:37 +00:00
|
|
|
def is_spotify_token_expired():
|
|
|
|
global spotify_token_expire_time
|
|
|
|
return True if spotify_token_expire_time <= time.time() else False
|
|
|
|
|
|
|
|
|
|
|
|
def invoke_spotify_token():
|
|
|
|
global spotify_token, spotify_token_expire_time
|
|
|
|
r = requests.post(
|
|
|
|
"https://accounts.spotify.com/api/token",
|
2022-12-29 23:57:02 -05:00
|
|
|
data={"grant_type": "client_credentials"},
|
|
|
|
headers={"Authorization": f"Basic {settings.SPOTIFY_CREDENTIAL}"},
|
2022-12-08 15:45:37 +00:00
|
|
|
)
|
|
|
|
data = r.json()
|
|
|
|
if r.status_code == 401:
|
|
|
|
# token expired, try one more time
|
|
|
|
# this maybe caused by external operations,
|
|
|
|
# for example debugging using a http client
|
|
|
|
r = requests.post(
|
|
|
|
"https://accounts.spotify.com/api/token",
|
2022-12-29 23:57:02 -05:00
|
|
|
data={"grant_type": "client_credentials"},
|
|
|
|
headers={"Authorization": f"Basic {settings.SPOTIFY_CREDENTIAL}"},
|
2022-12-08 15:45:37 +00:00
|
|
|
)
|
|
|
|
data = r.json()
|
|
|
|
elif r.status_code != 200:
|
|
|
|
raise Exception(f"Request to spotify API fails. Reason: {r.reason}")
|
|
|
|
# minus 2 for execution time error
|
2022-12-29 23:57:02 -05:00
|
|
|
spotify_token_expire_time = int(data["expires_in"]) + time.time() - 2
|
|
|
|
spotify_token = data["access_token"]
|