diff --git a/backend/.gitignore b/frontend/backend/.gitignore similarity index 100% rename from backend/.gitignore rename to frontend/backend/.gitignore diff --git a/backend/.pre-commit-config.yaml b/frontend/backend/.pre-commit-config.yaml similarity index 100% rename from backend/.pre-commit-config.yaml rename to frontend/backend/.pre-commit-config.yaml diff --git a/backend/MD_Attractor/__init__.py b/frontend/backend/MD_Attractor/__init__.py similarity index 100% rename from backend/MD_Attractor/__init__.py rename to frontend/backend/MD_Attractor/__init__.py diff --git a/backend/MD_Attractor/__pycache__/__init__.cpython-310.pyc b/frontend/backend/MD_Attractor/__pycache__/__init__.cpython-310.pyc similarity index 100% rename from backend/MD_Attractor/__pycache__/__init__.cpython-310.pyc rename to frontend/backend/MD_Attractor/__pycache__/__init__.cpython-310.pyc diff --git a/backend/MD_Attractor/__pycache__/settings.cpython-310.pyc b/frontend/backend/MD_Attractor/__pycache__/settings.cpython-310.pyc similarity index 100% rename from backend/MD_Attractor/__pycache__/settings.cpython-310.pyc rename to frontend/backend/MD_Attractor/__pycache__/settings.cpython-310.pyc diff --git a/backend/MD_Attractor/__pycache__/urls.cpython-310.pyc b/frontend/backend/MD_Attractor/__pycache__/urls.cpython-310.pyc similarity index 100% rename from backend/MD_Attractor/__pycache__/urls.cpython-310.pyc rename to frontend/backend/MD_Attractor/__pycache__/urls.cpython-310.pyc diff --git a/backend/MD_Attractor/__pycache__/wsgi.cpython-310.pyc b/frontend/backend/MD_Attractor/__pycache__/wsgi.cpython-310.pyc similarity index 100% rename from backend/MD_Attractor/__pycache__/wsgi.cpython-310.pyc rename to frontend/backend/MD_Attractor/__pycache__/wsgi.cpython-310.pyc diff --git a/backend/MD_Attractor/asgi.py b/frontend/backend/MD_Attractor/asgi.py similarity index 100% rename from backend/MD_Attractor/asgi.py rename to frontend/backend/MD_Attractor/asgi.py diff --git a/backend/MD_Attractor/settings.py b/frontend/backend/MD_Attractor/settings.py similarity index 100% rename from backend/MD_Attractor/settings.py rename to frontend/backend/MD_Attractor/settings.py diff --git a/backend/MD_Attractor/urls.py b/frontend/backend/MD_Attractor/urls.py similarity index 100% rename from backend/MD_Attractor/urls.py rename to frontend/backend/MD_Attractor/urls.py diff --git a/backend/MD_Attractor/wsgi.py b/frontend/backend/MD_Attractor/wsgi.py similarity index 100% rename from backend/MD_Attractor/wsgi.py rename to frontend/backend/MD_Attractor/wsgi.py diff --git a/backend/Procfile b/frontend/backend/Procfile similarity index 100% rename from backend/Procfile rename to frontend/backend/Procfile diff --git a/backend/README.md b/frontend/backend/README.md similarity index 100% rename from backend/README.md rename to frontend/backend/README.md diff --git a/backend/db.sqlite3 b/frontend/backend/db.sqlite3 similarity index 100% rename from backend/db.sqlite3 rename to frontend/backend/db.sqlite3 diff --git a/backend/manage.py b/frontend/backend/manage.py old mode 100755 new mode 100644 similarity index 100% rename from backend/manage.py rename to frontend/backend/manage.py diff --git a/backend/requirements.txt b/frontend/backend/requirements.txt similarity index 100% rename from backend/requirements.txt rename to frontend/backend/requirements.txt diff --git a/frontend/backend/song_api/AppleMusicAPI.py b/frontend/backend/song_api/AppleMusicAPI.py new file mode 100644 index 0000000..0e73f36 --- /dev/null +++ b/frontend/backend/song_api/AppleMusicAPI.py @@ -0,0 +1,119 @@ +import os +from dotenv import load_dotenv +from typing import Dict, List, Optional, Tuple +import requests + +load_dotenv() + +class AppleMusicAPI(): + """ + A class that interacts with the Apple Music API to retrieve song details and related information. + + Attributes: + developer_token (str): The Apple Music Developer Token. + base_url (str): The base URL for Apple Music API. + data (Dict[str, str]): A dictionary containing data for the song search. + + Methods: + getSongDetails: Retrieves the details of a song based on the search query. + collectGenres: Collects the genres of an artist. + relatedArtists: Retrieves the related artists. + getTopTracks: Retrieves the top tracks of collaborated artists. + """ + + def __init__(self, data: Dict[str, str]): + self.developer_token: str = os.getenv('APPLE_MUSIC_DEVELOPER_TOKEN') + self.base_url: str = "https://api.music.apple.com/v1/" + self.data: Dict[str, str] = data + + def getSongDetails(self) -> Tuple[Optional[str], Optional[str], Optional[List[str]], Optional[str]]: + """ + Retrieves the details of a song based on the search query. + + Returns: + Tuple[Optional[str], Optional[str], Optional[List[str]], Optional[str]]: A tuple containing the song ID, song name, genres, and an error message if applicable. + """ + track_name: str = self.data['search'] + url: str = f"{self.base_url}catalog/us/search" + params = { + "term": track_name, + "types": "songs", + "limit": 1 + } + headers = {"Authorization": f"Bearer {self.developer_token}"} + response = requests.get(url, headers=headers, params=params) + + if response.status_code != 200: + return None, None, None, "Error: Failed to fetch data from Apple Music API." + + results = response.json() + if "results" not in results or "songs" not in results["results"]: + return None, None, None, "Error: No song found with the given name." + + song_data = results["results"]["songs"]["data"][0] + song_id: str = song_data["id"] + song_name: str = song_data["attributes"]["name"] + artist_id: str = song_data["relationships"]["artists"]["data"][0]["id"] + + genres = self.collectGenres(artist_id) + return song_id, song_name, genres, None + + def collectGenres(self, artist_id: str) -> List[str]: + """ + Collects the genres of an artist. + + Args: + artist_id (str): The ID of the artist. + + Returns: + List[str]: A list of genres associated with the artist. + """ + url: str = f"{self.base_url}catalog/us/artists/{artist_id}" + headers = {"Authorization": f"Bearer {self.developer_token}"} + response = requests.get(url, headers=headers) + + if response.status_code != 200: + return [] + + artist_data = response.json() + if "data" not in artist_data or len(artist_data["data"]) == 0: + return [] + + return artist_data["data"][0]["attributes"].get("genreNames", []) + + def relatedArtists(self, artist_id: str) -> List[Dict[str, str]]: + """ + Retrieves the related artists. + + Args: + artist_id (str): The ID of the artist. + + Returns: + List[Dict[str, str]]: A list of related artists and their genres. + """ + # Apple Music API may not provide "related artists" as directly as Spotify. + # Implement a placeholder method or use a workaround if needed. + return [{"id": artist_id, "name": "Related Artist Example"}] + + def getTopTracks(self, artist_id: str) -> List[Dict[str, str]]: + """ + Retrieves the top tracks of an artist. + + Args: + artist_id (str): The ID of the artist. + + Returns: + List[Dict[str, str]]: A list of the artist's top tracks. + """ + url: str = f"{self.base_url}catalog/us/artists/{artist_id}/top-songs" + headers = {"Authorization": f"Bearer {self.developer_token}"} + response = requests.get(url, headers=headers) + + if response.status_code != 200: + return [] + + top_songs = response.json() + if "data" not in top_songs: + return [] + + return [{"name": song["attributes"]["name"], "id": song["id"]} for song in top_songs["data"]] diff --git a/backend/song_api/__init__.py b/frontend/backend/song_api/__init__.py similarity index 100% rename from backend/song_api/__init__.py rename to frontend/backend/song_api/__init__.py diff --git a/backend/song_api/__pycache__/__init__.cpython-310.pyc b/frontend/backend/song_api/__pycache__/__init__.cpython-310.pyc similarity index 100% rename from backend/song_api/__pycache__/__init__.cpython-310.pyc rename to frontend/backend/song_api/__pycache__/__init__.cpython-310.pyc diff --git a/backend/song_api/__pycache__/admin.cpython-310.pyc b/frontend/backend/song_api/__pycache__/admin.cpython-310.pyc similarity index 100% rename from backend/song_api/__pycache__/admin.cpython-310.pyc rename to frontend/backend/song_api/__pycache__/admin.cpython-310.pyc diff --git a/backend/song_api/__pycache__/apps.cpython-310.pyc b/frontend/backend/song_api/__pycache__/apps.cpython-310.pyc similarity index 100% rename from backend/song_api/__pycache__/apps.cpython-310.pyc rename to frontend/backend/song_api/__pycache__/apps.cpython-310.pyc diff --git a/backend/song_api/__pycache__/egoNetwork.cpython-310.pyc b/frontend/backend/song_api/__pycache__/egoNetwork.cpython-310.pyc similarity index 100% rename from backend/song_api/__pycache__/egoNetwork.cpython-310.pyc rename to frontend/backend/song_api/__pycache__/egoNetwork.cpython-310.pyc diff --git a/backend/song_api/__pycache__/models.cpython-310.pyc b/frontend/backend/song_api/__pycache__/models.cpython-310.pyc similarity index 100% rename from backend/song_api/__pycache__/models.cpython-310.pyc rename to frontend/backend/song_api/__pycache__/models.cpython-310.pyc diff --git a/backend/song_api/__pycache__/serializers.cpython-310.pyc b/frontend/backend/song_api/__pycache__/serializers.cpython-310.pyc similarity index 100% rename from backend/song_api/__pycache__/serializers.cpython-310.pyc rename to frontend/backend/song_api/__pycache__/serializers.cpython-310.pyc diff --git a/backend/song_api/__pycache__/spotifyAPI.cpython-310.pyc b/frontend/backend/song_api/__pycache__/spotifyAPI.cpython-310.pyc similarity index 100% rename from backend/song_api/__pycache__/spotifyAPI.cpython-310.pyc rename to frontend/backend/song_api/__pycache__/spotifyAPI.cpython-310.pyc diff --git a/backend/song_api/__pycache__/urls.cpython-310.pyc b/frontend/backend/song_api/__pycache__/urls.cpython-310.pyc similarity index 100% rename from backend/song_api/__pycache__/urls.cpython-310.pyc rename to frontend/backend/song_api/__pycache__/urls.cpython-310.pyc diff --git a/backend/song_api/__pycache__/views.cpython-310.pyc b/frontend/backend/song_api/__pycache__/views.cpython-310.pyc similarity index 100% rename from backend/song_api/__pycache__/views.cpython-310.pyc rename to frontend/backend/song_api/__pycache__/views.cpython-310.pyc diff --git a/backend/song_api/admin.py b/frontend/backend/song_api/admin.py similarity index 100% rename from backend/song_api/admin.py rename to frontend/backend/song_api/admin.py diff --git a/backend/song_api/apps.py b/frontend/backend/song_api/apps.py similarity index 100% rename from backend/song_api/apps.py rename to frontend/backend/song_api/apps.py diff --git a/backend/song_api/egoNetwork.py b/frontend/backend/song_api/egoNetwork.py similarity index 100% rename from backend/song_api/egoNetwork.py rename to frontend/backend/song_api/egoNetwork.py diff --git a/backend/song_api/models.py b/frontend/backend/song_api/models.py similarity index 100% rename from backend/song_api/models.py rename to frontend/backend/song_api/models.py diff --git a/backend/song_api/serializers.py b/frontend/backend/song_api/serializers.py similarity index 100% rename from backend/song_api/serializers.py rename to frontend/backend/song_api/serializers.py diff --git a/backend/song_api/spotifyAPI.py b/frontend/backend/song_api/spotifyAPI.py similarity index 100% rename from backend/song_api/spotifyAPI.py rename to frontend/backend/song_api/spotifyAPI.py diff --git a/backend/song_api/tests.py b/frontend/backend/song_api/tests.py similarity index 100% rename from backend/song_api/tests.py rename to frontend/backend/song_api/tests.py diff --git a/backend/song_api/urls.py b/frontend/backend/song_api/urls.py similarity index 100% rename from backend/song_api/urls.py rename to frontend/backend/song_api/urls.py diff --git a/backend/song_api/views.py b/frontend/backend/song_api/views.py similarity index 100% rename from backend/song_api/views.py rename to frontend/backend/song_api/views.py