"""Apple Music API wrapper.""" from datetime import datetime from datetime import timedelta import time from typing import Dict import jwt import requests from src.common.types import BaseStoreAPI class AppleMusicAPI(BaseStoreAPI): """Apple Music API wrapper class.""" def __init__(self, client_id: str, team_id: str, private_key: str): """Initialize. Args: client_id: Apple 10-character key identifier. team_id: Apple 10-character Team ID. private_key: MusicKit private key. """ self._client_id = client_id self._team_id = team_id self._private_key = private_key self._alg = 'ES256' self._sleep_time = 0.0 self._recreate_access_token_for_creds() def _obtain_access_token(self) -> str: """Generate access token.""" token_expiration_time = datetime.now() + timedelta(seconds=900) payload = { 'iss': self._team_id, 'iat': int(datetime.now().timestamp()), 'exp': int(token_expiration_time.timestamp())} token = jwt.encode( payload, self._private_key, algorithm=self._alg, headers={'alg': self._alg, 'kid': self._client_id}) return token def _auth_headers(self) -> Dict: """Auth headers.""" return { 'Authorization': f'Bearer {self._access_token}', 'Content-Type': 'application/json'} def _recreate_access_token_for_creds(self): """Recreate access token.""" self._access_token = self._obtain_access_token() def call(self, endpoint: str, params: Dict) -> requests.Response: """Call Apple Music API with a GET method. Args: endpoint: An endpoint from here https://developer.apple.com/documentation/applemusicapi params: API request params according to the documentation. returns: HTTP response from the API. """ headers = self._auth_headers() attempt_number = 0 while attempt_number < 5: attempt_number += 1 response = requests.get( f'https://api.music.apple.com/v1{endpoint}', params=params, headers=headers) if response.status_code == 401: self._recreate_access_token_for_creds() elif response.status_code == 429: self._sleep_time += 0.5 time.sleep(self._sleep_time) else: self._sleep_time = 0.0 return response return response