diff --git a/.cache b/.cache new file mode 100644 index 0000000..522eb45 --- /dev/null +++ b/.cache @@ -0,0 +1 @@ +{"access_token": "BQAE8y-04ZMat5J6ksMMiGewJ7nS8T2kHGl-2GpkY-DlwG1a5itfltf76ZQBj5XnsAzZ0zsAeN16ydiFo7tG1QVHpofbCZH6WswopSGBowFtvaFGaNNotO4yFviTVZWsI9YHd8TFTPA", "token_type": "Bearer", "expires_in": 3600, "expires_at": 1764362109} \ No newline at end of file diff --git a/lab-apis.ipynb b/lab-apis.ipynb index e923554..67162c5 100644 --- a/lab-apis.ipynb +++ b/lab-apis.ipynb @@ -45,7 +45,7 @@ }, { "cell_type": "code", - "execution_count": null, + "execution_count": 2, "id": "319cfd4e-f6fb-4419-80e0-e3983cd25e43", "metadata": {}, "outputs": [], @@ -56,10 +56,41 @@ }, { "cell_type": "code", - "execution_count": null, + "execution_count": 1, "id": "04e12954-fd70-4311-88a5-fb7e2c29799c", "metadata": {}, - "outputs": [], + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Collecting spotipy\n", + " Downloading spotipy-2.25.2-py3-none-any.whl.metadata (5.1 kB)\n", + "Collecting redis>=3.5.3 (from spotipy)\n", + " Downloading redis-7.1.0-py3-none-any.whl.metadata (12 kB)\n", + "Collecting requests>=2.25.0 (from spotipy)\n", + " Using cached requests-2.32.5-py3-none-any.whl.metadata (4.9 kB)\n", + "Collecting urllib3>=1.26.0 (from spotipy)\n", + " Using cached urllib3-2.5.0-py3-none-any.whl.metadata (6.5 kB)\n", + "Collecting charset_normalizer<4,>=2 (from requests>=2.25.0->spotipy)\n", + " Using cached charset_normalizer-3.4.4-cp313-cp313-macosx_10_13_universal2.whl.metadata (37 kB)\n", + "Collecting idna<4,>=2.5 (from requests>=2.25.0->spotipy)\n", + " Using cached idna-3.11-py3-none-any.whl.metadata (8.4 kB)\n", + "Collecting certifi>=2017.4.17 (from requests>=2.25.0->spotipy)\n", + " Using cached certifi-2025.11.12-py3-none-any.whl.metadata (2.5 kB)\n", + "Downloading spotipy-2.25.2-py3-none-any.whl (31 kB)\n", + "Downloading redis-7.1.0-py3-none-any.whl (354 kB)\n", + "Using cached requests-2.32.5-py3-none-any.whl (64 kB)\n", + "Using cached charset_normalizer-3.4.4-cp313-cp313-macosx_10_13_universal2.whl (208 kB)\n", + "Using cached idna-3.11-py3-none-any.whl (71 kB)\n", + "Using cached urllib3-2.5.0-py3-none-any.whl (129 kB)\n", + "Using cached certifi-2025.11.12-py3-none-any.whl (159 kB)\n", + "Installing collected packages: urllib3, redis, idna, charset_normalizer, certifi, requests, spotipy\n", + "\u001b[2K \u001b[90m━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\u001b[0m \u001b[32m7/7\u001b[0m [spotipy]m6/7\u001b[0m [spotipy]]ormalizer]\n", + "\u001b[1A\u001b[2KSuccessfully installed certifi-2025.11.12 charset_normalizer-3.4.4 idna-3.11 redis-7.1.0 requests-2.32.5 spotipy-2.25.2 urllib3-2.5.0\n" + ] + } + ], "source": [ "# If you havent done so, install the spotipy wrapper\n", "!pip install spotipy" @@ -75,7 +106,7 @@ }, { "cell_type": "code", - "execution_count": null, + "execution_count": 3, "id": "03034bc6-9858-412a-83b7-18abdc345d7e", "metadata": {}, "outputs": [], @@ -382,12 +413,301 @@ }, { "cell_type": "code", - "execution_count": null, + "execution_count": 6, "id": "29694252-f217-454d-8881-681b2b6eeb1e", "metadata": {}, - "outputs": [], + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Top tracks for Billie Eilish: ['BIRDS OF A FEATHER', 'WILDFLOWER', 'ocean eyes', 'lovely (with Khalid)', 'CHIHIRO']\n", + "Top tracks for The Weeknd: ['One Of The Girls (with JENNIE, Lily Rose Depp)', 'Timeless (feat Playboi Carti)', 'Blinding Lights', 'Starboy', 'Die For You']\n", + "Top tracks for The Weeknd: ['One Of The Girls (with JENNIE, Lily Rose Depp)', 'Timeless (feat Playboi Carti)', 'Blinding Lights', 'Starboy', 'Die For You']\n", + "Top tracks for Dua Lipa: ['Cold Heart - PNAU Remix', \"Don't Start Now\", 'Training Season', 'Levitating (feat. DaBaby)', 'New Rules']\n", + "\n", + "Top tracks list: [{'Billie Eilish': ['BIRDS OF A FEATHER', 'WILDFLOWER', 'ocean eyes', 'lovely (with Khalid)', 'CHIHIRO']}, {'The Weeknd': ['One Of The Girls (with JENNIE, Lily Rose Depp)', 'Timeless (feat Playboi Carti)', 'Blinding Lights', 'Starboy', 'Die For You']}, {'Dua Lipa': ['Cold Heart - PNAU Remix', \"Don't Start Now\", 'Training Season', 'Levitating (feat. DaBaby)', 'New Rules']}]\n", + "Top tracks for Dua Lipa: ['Cold Heart - PNAU Remix', \"Don't Start Now\", 'Training Season', 'Levitating (feat. DaBaby)', 'New Rules']\n", + "\n", + "Top tracks list: [{'Billie Eilish': ['BIRDS OF A FEATHER', 'WILDFLOWER', 'ocean eyes', 'lovely (with Khalid)', 'CHIHIRO']}, {'The Weeknd': ['One Of The Girls (with JENNIE, Lily Rose Depp)', 'Timeless (feat Playboi Carti)', 'Blinding Lights', 'Starboy', 'Die For You']}, {'Dua Lipa': ['Cold Heart - PNAU Remix', \"Don't Start Now\", 'Training Season', 'Levitating (feat. DaBaby)', 'New Rules']}]\n", + "Related artists for Billie Eilish: ['Poppy', 'Pop Smoke', 'Popcaan', 'Pop Mage', 'Popy Jr.']\n", + "Related artists for Billie Eilish: ['Poppy', 'Pop Smoke', 'Popcaan', 'Pop Mage', 'Popy Jr.']\n", + "Related artists for The Weeknd: ['Poppy', 'Pop Smoke', 'Popcaan', 'Pop Mage', 'Popy Jr.']\n", + "Related artists for The Weeknd: ['Poppy', 'Pop Smoke', 'Popcaan', 'Pop Mage', 'Popy Jr.']\n", + "Related artists for Dua Lipa: ['Taylor Swift', 'Fuerza Regida', 'Ariana Grande', 'Billie Eilish', 'Rihanna']\n", + "\n", + "Related artists list: [{'Billie Eilish': ['Poppy', 'Pop Smoke', 'Popcaan', 'Pop Mage', 'Popy Jr.']}, {'The Weeknd': ['Poppy', 'Pop Smoke', 'Popcaan', 'Pop Mage', 'Popy Jr.']}, {'Dua Lipa': ['Taylor Swift', 'Fuerza Regida', 'Ariana Grande', 'Billie Eilish', 'Rihanna']}]\n", + "\n", + "=== CHALLENGE: Combined Playlist ===\n", + "Related artists for Dua Lipa: ['Taylor Swift', 'Fuerza Regida', 'Ariana Grande', 'Billie Eilish', 'Rihanna']\n", + "\n", + "Related artists list: [{'Billie Eilish': ['Poppy', 'Pop Smoke', 'Popcaan', 'Pop Mage', 'Popy Jr.']}, {'The Weeknd': ['Poppy', 'Pop Smoke', 'Popcaan', 'Pop Mage', 'Popy Jr.']}, {'Dua Lipa': ['Taylor Swift', 'Fuerza Regida', 'Ariana Grande', 'Billie Eilish', 'Rihanna']}]\n", + "\n", + "=== CHALLENGE: Combined Playlist ===\n", + "Combined Playlist:\n", + "\n", + "Billie Eilish - Top Tracks:\n", + " 1. BIRDS OF A FEATHER\n", + " 2. WILDFLOWER\n", + " 3. ocean eyes\n", + " 4. lovely (with Khalid)\n", + " 5. CHIHIRO\n", + "\n", + "The Weeknd - Top Tracks:\n", + " 1. One Of The Girls (with JENNIE, Lily Rose Depp)\n", + " 2. Timeless (feat Playboi Carti)\n", + " 3. Blinding Lights\n", + " 4. Starboy\n", + " 5. Die For You\n", + "\n", + "Dua Lipa - Top Tracks:\n", + " 1. Cold Heart - PNAU Remix\n", + " 2. Don't Start Now\n", + " 3. Training Season\n", + " 4. Levitating (feat. DaBaby)\n", + " 5. New Rules\n", + "\n", + "Poppy - Top Tracks (Related to Billie Eilish):\n", + " 1. End of You\n", + " 2. V.A.N\n", + " 3. new way out\n", + " 4. from me to u (feat. Poppy)\n", + " 5. Unravel\n", + "\n", + "Pop Smoke - Top Tracks (Related to Billie Eilish):\n", + " 1. What You Know Bout Love\n", + " 2. Dior\n", + " 3. Mood Swings (feat. Lil Tjay)\n", + " 4. For The Night (feat. Lil Baby & DaBaby)\n", + " 5. Invincible\n", + "\n", + "Poppy - Top Tracks (Related to The Weeknd):\n", + " 1. End of You\n", + " 2. V.A.N\n", + " 3. new way out\n", + " 4. from me to u (feat. Poppy)\n", + " 5. Unravel\n", + "\n", + "Pop Smoke - Top Tracks (Related to The Weeknd):\n", + " 1. What You Know Bout Love\n", + " 2. Dior\n", + " 3. Mood Swings (feat. Lil Tjay)\n", + " 4. For The Night (feat. Lil Baby & DaBaby)\n", + " 5. Invincible\n", + "\n", + "Taylor Swift - Top Tracks (Related to Dua Lipa):\n", + " 1. The Fate of Ophelia\n", + " 2. Opalite\n", + " 3. Elizabeth Taylor\n", + " 4. Father Figure\n", + " 5. The Life of a Showgirl (feat. Sabrina Carpenter)\n", + "\n", + "Fuerza Regida - Top Tracks (Related to Dua Lipa):\n", + " 1. Marlboro Rojo\n", + " 2. TU SANCHO\n", + " 3. COQUETA\n", + " 4. Tu Boda\n", + " 5. ANSIEDAD\n", + "\n", + "Total sections in playlist: 9\n", + "Total tracks in combined playlist: 45\n", + "Combined Playlist:\n", + "\n", + "Billie Eilish - Top Tracks:\n", + " 1. BIRDS OF A FEATHER\n", + " 2. WILDFLOWER\n", + " 3. ocean eyes\n", + " 4. lovely (with Khalid)\n", + " 5. CHIHIRO\n", + "\n", + "The Weeknd - Top Tracks:\n", + " 1. One Of The Girls (with JENNIE, Lily Rose Depp)\n", + " 2. Timeless (feat Playboi Carti)\n", + " 3. Blinding Lights\n", + " 4. Starboy\n", + " 5. Die For You\n", + "\n", + "Dua Lipa - Top Tracks:\n", + " 1. Cold Heart - PNAU Remix\n", + " 2. Don't Start Now\n", + " 3. Training Season\n", + " 4. Levitating (feat. DaBaby)\n", + " 5. New Rules\n", + "\n", + "Poppy - Top Tracks (Related to Billie Eilish):\n", + " 1. End of You\n", + " 2. V.A.N\n", + " 3. new way out\n", + " 4. from me to u (feat. Poppy)\n", + " 5. Unravel\n", + "\n", + "Pop Smoke - Top Tracks (Related to Billie Eilish):\n", + " 1. What You Know Bout Love\n", + " 2. Dior\n", + " 3. Mood Swings (feat. Lil Tjay)\n", + " 4. For The Night (feat. Lil Baby & DaBaby)\n", + " 5. Invincible\n", + "\n", + "Poppy - Top Tracks (Related to The Weeknd):\n", + " 1. End of You\n", + " 2. V.A.N\n", + " 3. new way out\n", + " 4. from me to u (feat. Poppy)\n", + " 5. Unravel\n", + "\n", + "Pop Smoke - Top Tracks (Related to The Weeknd):\n", + " 1. What You Know Bout Love\n", + " 2. Dior\n", + " 3. Mood Swings (feat. Lil Tjay)\n", + " 4. For The Night (feat. Lil Baby & DaBaby)\n", + " 5. Invincible\n", + "\n", + "Taylor Swift - Top Tracks (Related to Dua Lipa):\n", + " 1. The Fate of Ophelia\n", + " 2. Opalite\n", + " 3. Elizabeth Taylor\n", + " 4. Father Figure\n", + " 5. The Life of a Showgirl (feat. Sabrina Carpenter)\n", + "\n", + "Fuerza Regida - Top Tracks (Related to Dua Lipa):\n", + " 1. Marlboro Rojo\n", + " 2. TU SANCHO\n", + " 3. COQUETA\n", + " 4. Tu Boda\n", + " 5. ANSIEDAD\n", + "\n", + "Total sections in playlist: 9\n", + "Total tracks in combined playlist: 45\n" + ] + } + ], "source": [ - "# Your answer here" + "# Exercise 1: Discovering New Music through Your Favorite Artists\n", + "\n", + "# 1. List of favorite artists\n", + "artists = [\"Billie Eilish\", \"The Weeknd\", \"Dua Lipa\"]\n", + "\n", + "# 2. Function to get top tracks\n", + "def get_top_tracks(artist_name):\n", + " \"\"\"\n", + " Get the top 5 tracks for a given artist.\n", + " Returns a list of track names.\n", + " \"\"\"\n", + " try:\n", + " # Search for the artist\n", + " results = sp.search(q=artist_name, type='artist', limit=1)\n", + " \n", + " if results['artists']['items']:\n", + " artist_id = results['artists']['items'][0]['id']\n", + " # Get top tracks for the artist\n", + " top_tracks = sp.artist_top_tracks(artist_id)\n", + " # Extract the first 5 track names\n", + " track_names = [track['name'] for track in top_tracks['tracks'][:5]]\n", + " return track_names\n", + " else:\n", + " print(f\"Artist '{artist_name}' not found\")\n", + " return []\n", + " except Exception as e:\n", + " print(f\"Error getting top tracks for {artist_name}: {e}\")\n", + " return []\n", + "\n", + "# Get top tracks for each artist\n", + "top_tracks_list = []\n", + "for artist in artists:\n", + " tracks = get_top_tracks(artist)\n", + " top_tracks_list.append({artist: tracks})\n", + " print(f\"Top tracks for {artist}: {tracks}\")\n", + "\n", + "print(\"\\nTop tracks list:\", top_tracks_list)\n", + "\n", + "# 3. Function to find related artists (using genre-based search as alternative)\n", + "def find_related_artists(artist_name):\n", + " \"\"\"\n", + " Find related artists by searching for artists in similar genres.\n", + " Returns a list of related artist names.\n", + " \"\"\"\n", + " try:\n", + " # Search for the artist to get their info\n", + " results = sp.search(q=artist_name, type='artist', limit=1)\n", + " \n", + " if results['artists']['items']:\n", + " artist_info = results['artists']['items'][0]\n", + " genres = artist_info.get('genres', [])\n", + " \n", + " # If the artist has genres, search for other artists in those genres\n", + " if genres:\n", + " # Use the first genre to search for similar artists\n", + " genre = genres[0]\n", + " search_results = sp.search(q=f'genre:\"{genre}\"', type='artist', limit=10)\n", + " \n", + " related_names = []\n", + " for artist in search_results['artists']['items']:\n", + " if artist['name'] != artist_name and artist['name'] not in related_names:\n", + " related_names.append(artist['name'])\n", + " if len(related_names) >= 5:\n", + " break\n", + " \n", + " return related_names[:5]\n", + " else:\n", + " # If no genres, search for artists with similar names or keywords\n", + " search_terms = [\"pop\", \"indie\", \"electronic\", \"alternative\", \"rock\"]\n", + " related_names = []\n", + " \n", + " for term in search_terms:\n", + " search_results = sp.search(q=term, type='artist', limit=5)\n", + " for artist in search_results['artists']['items']:\n", + " if artist['name'] != artist_name and artist['name'] not in related_names:\n", + " related_names.append(artist['name'])\n", + " if len(related_names) >= 5:\n", + " break\n", + " if len(related_names) >= 5:\n", + " break\n", + " \n", + " return related_names[:5]\n", + " else:\n", + " print(f\"Artist '{artist_name}' not found\")\n", + " return []\n", + " except Exception as e:\n", + " print(f\"Error finding related artists for {artist_name}: {e}\")\n", + " # Return some popular artists as fallback\n", + " return [\"Taylor Swift\", \"Ed Sheeran\", \"Ariana Grande\", \"Bruno Mars\", \"Adele\"][:5]\n", + "\n", + "# Get related artists for each favorite artist\n", + "related_artists_list = []\n", + "for artist in artists:\n", + " related = find_related_artists(artist)\n", + " related_artists_list.append({artist: related})\n", + " print(f\"Related artists for {artist}: {related}\")\n", + "\n", + "print(\"\\nRelated artists list:\", related_artists_list)\n", + "\n", + "# Challenge: Create a combined playlist\n", + "print(\"\\n=== CHALLENGE: Combined Playlist ===\")\n", + "\n", + "combined_playlist = {}\n", + "\n", + "# Add top tracks from favorite artists\n", + "for artist in artists:\n", + " top_tracks = get_top_tracks(artist)\n", + " combined_playlist[f\"{artist} - Top Tracks\"] = top_tracks\n", + "\n", + "# Add top tracks from related artists\n", + "for artist in artists:\n", + " related = find_related_artists(artist)\n", + " for related_artist in related[:2]: # Limit to first 2 related artists to keep it manageable\n", + " related_top_tracks = get_top_tracks(related_artist)\n", + " if related_top_tracks: # Only add if we found tracks\n", + " combined_playlist[f\"{related_artist} - Top Tracks (Related to {artist})\"] = related_top_tracks\n", + "\n", + "print(\"Combined Playlist:\")\n", + "for section, tracks in combined_playlist.items():\n", + " print(f\"\\n{section}:\")\n", + " for i, track in enumerate(tracks, 1):\n", + " print(f\" {i}. {track}\")\n", + "\n", + "print(f\"\\nTotal sections in playlist: {len(combined_playlist)}\")\n", + "total_tracks = sum(len(tracks) for tracks in combined_playlist.values())\n", + "print(f\"Total tracks in combined playlist: {total_tracks}\")" ] }, { @@ -404,10 +724,37 @@ }, { "cell_type": "code", - "execution_count": null, + "execution_count": 7, "id": "25fb0cf8-c13a-41b0-b8f8-7e0700fd1e41", "metadata": {}, - "outputs": [], + "outputs": [ + { + "name": "stderr", + "output_type": "stream", + "text": [ + "HTTP Error for GET to https://api.spotify.com/v1/browse/featured-playlists with Params: {'locale': None, 'country': None, 'timestamp': None, 'limit': 20, 'offset': 0} returned 404 due to Not Found\n" + ] + }, + { + "ename": "SpotifyException", + "evalue": "http status: 404, code: -1 - https://api.spotify.com/v1/browse/featured-playlists?limit=20&offset=0:\n Not Found, reason: None", + "output_type": "error", + "traceback": [ + "\u001b[31m---------------------------------------------------------------------------\u001b[39m", + "\u001b[31mHTTPError\u001b[39m Traceback (most recent call last)", + "\u001b[36mFile \u001b[39m\u001b[32m~/Desktop/data_analytics/labs/10lab-apis/.venv/lib/python3.13/site-packages/spotipy/client.py:271\u001b[39m, in \u001b[36mSpotify._internal_call\u001b[39m\u001b[34m(self, method, url, payload, params)\u001b[39m\n\u001b[32m 266\u001b[39m response = \u001b[38;5;28mself\u001b[39m._session.request(\n\u001b[32m 267\u001b[39m method, url, headers=headers, proxies=\u001b[38;5;28mself\u001b[39m.proxies,\n\u001b[32m 268\u001b[39m timeout=\u001b[38;5;28mself\u001b[39m.requests_timeout, **args\n\u001b[32m 269\u001b[39m )\n\u001b[32m--> \u001b[39m\u001b[32m271\u001b[39m \u001b[43mresponse\u001b[49m\u001b[43m.\u001b[49m\u001b[43mraise_for_status\u001b[49m\u001b[43m(\u001b[49m\u001b[43m)\u001b[49m\n\u001b[32m 272\u001b[39m results = response.json()\n", + "\u001b[36mFile \u001b[39m\u001b[32m~/Desktop/data_analytics/labs/10lab-apis/.venv/lib/python3.13/site-packages/requests/models.py:1026\u001b[39m, in \u001b[36mResponse.raise_for_status\u001b[39m\u001b[34m(self)\u001b[39m\n\u001b[32m 1025\u001b[39m \u001b[38;5;28;01mif\u001b[39;00m http_error_msg:\n\u001b[32m-> \u001b[39m\u001b[32m1026\u001b[39m \u001b[38;5;28;01mraise\u001b[39;00m HTTPError(http_error_msg, response=\u001b[38;5;28mself\u001b[39m)\n", + "\u001b[31mHTTPError\u001b[39m: 404 Client Error: Not Found for url: https://api.spotify.com/v1/browse/featured-playlists?limit=20&offset=0", + "\nDuring handling of the above exception, another exception occurred:\n", + "\u001b[31mSpotifyException\u001b[39m Traceback (most recent call last)", + "\u001b[36mCell\u001b[39m\u001b[36m \u001b[39m\u001b[32mIn[7]\u001b[39m\u001b[32m, line 1\u001b[39m\n\u001b[32m----> \u001b[39m\u001b[32m1\u001b[39m \u001b[43msp\u001b[49m\u001b[43m.\u001b[49m\u001b[43mfeatured_playlists\u001b[49m\u001b[43m(\u001b[49m\u001b[43m)\u001b[49m \u001b[38;5;66;03m# We get a playlist id of a playlist we like\u001b[39;00m\n", + "\u001b[36mFile \u001b[39m\u001b[32m~/Desktop/data_analytics/labs/10lab-apis/.venv/lib/python3.13/site-packages/spotipy/client.py:1662\u001b[39m, in \u001b[36mSpotify.featured_playlists\u001b[39m\u001b[34m(self, locale, country, timestamp, limit, offset)\u001b[39m\n\u001b[32m 1633\u001b[39m \u001b[38;5;250m\u001b[39m\u001b[33;03m\"\"\" Get a list of Spotify featured playlists\u001b[39;00m\n\u001b[32m 1634\u001b[39m \n\u001b[32m 1635\u001b[39m \u001b[33;03m .. deprecated::\u001b[39;00m\n\u001b[32m (...)\u001b[39m\u001b[32m 1655\u001b[39m \u001b[33;03m items.\u001b[39;00m\n\u001b[32m 1656\u001b[39m \u001b[33;03m\"\"\"\u001b[39;00m\n\u001b[32m 1657\u001b[39m warnings.warn(\n\u001b[32m 1658\u001b[39m \u001b[33m\"\u001b[39m\u001b[33mYou\u001b[39m\u001b[33m'\u001b[39m\u001b[33mre using `featured_playlists(...)`, \u001b[39m\u001b[33m\"\u001b[39m\n\u001b[32m 1659\u001b[39m \u001b[33m\"\u001b[39m\u001b[33mwhich is marked as deprecated by Spotify.\u001b[39m\u001b[33m\"\u001b[39m,\n\u001b[32m 1660\u001b[39m \u001b[38;5;167;01mDeprecationWarning\u001b[39;00m,\n\u001b[32m 1661\u001b[39m )\n\u001b[32m-> \u001b[39m\u001b[32m1662\u001b[39m \u001b[38;5;28;01mreturn\u001b[39;00m \u001b[38;5;28;43mself\u001b[39;49m\u001b[43m.\u001b[49m\u001b[43m_get\u001b[49m\u001b[43m(\u001b[49m\n\u001b[32m 1663\u001b[39m \u001b[43m \u001b[49m\u001b[33;43m\"\u001b[39;49m\u001b[33;43mbrowse/featured-playlists\u001b[39;49m\u001b[33;43m\"\u001b[39;49m\u001b[43m,\u001b[49m\n\u001b[32m 1664\u001b[39m \u001b[43m \u001b[49m\u001b[43mlocale\u001b[49m\u001b[43m=\u001b[49m\u001b[43mlocale\u001b[49m\u001b[43m,\u001b[49m\n\u001b[32m 1665\u001b[39m \u001b[43m \u001b[49m\u001b[43mcountry\u001b[49m\u001b[43m=\u001b[49m\u001b[43mcountry\u001b[49m\u001b[43m,\u001b[49m\n\u001b[32m 1666\u001b[39m \u001b[43m \u001b[49m\u001b[43mtimestamp\u001b[49m\u001b[43m=\u001b[49m\u001b[43mtimestamp\u001b[49m\u001b[43m,\u001b[49m\n\u001b[32m 1667\u001b[39m \u001b[43m \u001b[49m\u001b[43mlimit\u001b[49m\u001b[43m=\u001b[49m\u001b[43mlimit\u001b[49m\u001b[43m,\u001b[49m\n\u001b[32m 1668\u001b[39m \u001b[43m \u001b[49m\u001b[43moffset\u001b[49m\u001b[43m=\u001b[49m\u001b[43moffset\u001b[49m\u001b[43m,\u001b[49m\n\u001b[32m 1669\u001b[39m \u001b[43m\u001b[49m\u001b[43m)\u001b[49m\n", + "\u001b[36mFile \u001b[39m\u001b[32m~/Desktop/data_analytics/labs/10lab-apis/.venv/lib/python3.13/site-packages/spotipy/client.py:321\u001b[39m, in \u001b[36mSpotify._get\u001b[39m\u001b[34m(self, url, args, payload, **kwargs)\u001b[39m\n\u001b[32m 318\u001b[39m \u001b[38;5;28;01mif\u001b[39;00m args:\n\u001b[32m 319\u001b[39m kwargs.update(args)\n\u001b[32m--> \u001b[39m\u001b[32m321\u001b[39m \u001b[38;5;28;01mreturn\u001b[39;00m \u001b[38;5;28;43mself\u001b[39;49m\u001b[43m.\u001b[49m\u001b[43m_internal_call\u001b[49m\u001b[43m(\u001b[49m\u001b[33;43m\"\u001b[39;49m\u001b[33;43mGET\u001b[39;49m\u001b[33;43m\"\u001b[39;49m\u001b[43m,\u001b[49m\u001b[43m \u001b[49m\u001b[43murl\u001b[49m\u001b[43m,\u001b[49m\u001b[43m \u001b[49m\u001b[43mpayload\u001b[49m\u001b[43m,\u001b[49m\u001b[43m \u001b[49m\u001b[43mkwargs\u001b[49m\u001b[43m)\u001b[49m\n", + "\u001b[36mFile \u001b[39m\u001b[32m~/Desktop/data_analytics/labs/10lab-apis/.venv/lib/python3.13/site-packages/spotipy/client.py:291\u001b[39m, in \u001b[36mSpotify._internal_call\u001b[39m\u001b[34m(self, method, url, payload, params)\u001b[39m\n\u001b[32m 286\u001b[39m reason = \u001b[38;5;28;01mNone\u001b[39;00m\n\u001b[32m 288\u001b[39m logger.error(\u001b[33mf\u001b[39m\u001b[33m\"\u001b[39m\u001b[33mHTTP Error for \u001b[39m\u001b[38;5;132;01m{\u001b[39;00mmethod\u001b[38;5;132;01m}\u001b[39;00m\u001b[33m to \u001b[39m\u001b[38;5;132;01m{\u001b[39;00murl\u001b[38;5;132;01m}\u001b[39;00m\u001b[33m with Params: \u001b[39m\u001b[33m\"\u001b[39m\n\u001b[32m 289\u001b[39m \u001b[33mf\u001b[39m\u001b[33m\"\u001b[39m\u001b[38;5;132;01m{\u001b[39;00margs.get(\u001b[33m'\u001b[39m\u001b[33mparams\u001b[39m\u001b[33m'\u001b[39m)\u001b[38;5;132;01m}\u001b[39;00m\u001b[33m returned \u001b[39m\u001b[38;5;132;01m{\u001b[39;00mresponse.status_code\u001b[38;5;132;01m}\u001b[39;00m\u001b[33m due to \u001b[39m\u001b[38;5;132;01m{\u001b[39;00mmsg\u001b[38;5;132;01m}\u001b[39;00m\u001b[33m\"\u001b[39m)\n\u001b[32m--> \u001b[39m\u001b[32m291\u001b[39m \u001b[38;5;28;01mraise\u001b[39;00m SpotifyException(\n\u001b[32m 292\u001b[39m response.status_code,\n\u001b[32m 293\u001b[39m -\u001b[32m1\u001b[39m,\n\u001b[32m 294\u001b[39m \u001b[33mf\u001b[39m\u001b[33m\"\u001b[39m\u001b[38;5;132;01m{\u001b[39;00mresponse.url\u001b[38;5;132;01m}\u001b[39;00m\u001b[33m:\u001b[39m\u001b[38;5;130;01m\\n\u001b[39;00m\u001b[33m \u001b[39m\u001b[38;5;132;01m{\u001b[39;00mmsg\u001b[38;5;132;01m}\u001b[39;00m\u001b[33m\"\u001b[39m,\n\u001b[32m 295\u001b[39m reason=reason,\n\u001b[32m 296\u001b[39m headers=response.headers,\n\u001b[32m 297\u001b[39m )\n\u001b[32m 298\u001b[39m \u001b[38;5;28;01mexcept\u001b[39;00m requests.exceptions.RetryError \u001b[38;5;28;01mas\u001b[39;00m retry_error:\n\u001b[32m 299\u001b[39m request = retry_error.request\n", + "\u001b[31mSpotifyException\u001b[39m: http status: 404, code: -1 - https://api.spotify.com/v1/browse/featured-playlists?limit=20&offset=0:\n Not Found, reason: None" + ] + } + ], "source": [ "sp.featured_playlists() # We get a playlist id of a playlist we like" ] @@ -533,18 +880,238 @@ }, { "cell_type": "code", - "execution_count": null, + "execution_count": 8, "id": "ed92d961-9646-4375-a386-ccc320a958f5", "metadata": {}, - "outputs": [], + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "=== Exercise 2: Unraveling the World of Playlists ===\n", + "1. Finding Popular Playlists:\n", + "Top 5 Popular Playlists found:\n", + "1. Name: COUNTRY HITS 2025 🔥 New Country Songs + Top Hits\n", + " ID: 4Jb4PDWREzNnbZcOHPcZPy\n", + " Description: best country music of 2025 most popular trending today modern mix viral top 100 hottest contemporary...\n", + "\n", + "2. Name: 🇵🇦 Plenas Nuevas Panamá || 2025 🔥\n", + " ID: 2SvbiQjJFx0cevXCP5Gcrg\n", + " Description: Lo mas nuevo de dancehall, afrobeat, reggaetón panameño e internacional 24/7 Artistas: Boza, Do...\n", + "\n", + "2. Deep Dive into a Selected Playlist:\n", + "Top 5 Popular Playlists found:\n", + "1. Name: COUNTRY HITS 2025 🔥 New Country Songs + Top Hits\n", + " ID: 4Jb4PDWREzNnbZcOHPcZPy\n", + " Description: best country music of 2025 most popular trending today modern mix viral top 100 hottest contemporary...\n", + "\n", + "2. Name: 🇵🇦 Plenas Nuevas Panamá || 2025 🔥\n", + " ID: 2SvbiQjJFx0cevXCP5Gcrg\n", + " Description: Lo mas nuevo de dancehall, afrobeat, reggaetón panameño e internacional 24/7 Artistas: Boza, Do...\n", + "\n", + "2. Deep Dive into a Selected Playlist:\n", + "Chosen Playlist: COUNTRY HITS 2025 🔥 New Country Songs + Top Hits\n", + "Description: best country music of 2025 most popular trending today modern mix viral top 100 hottest contemporary country pop rock latest americana ⚠️ NO SOCIAL MEDIA ACCOUNTS ASSOCIATED WITH THIS PROFILE. BEWARE OF SCAMS!\n", + "Total Track Count: 111\n", + "\n", + "3. First 10 Tracks in the Chosen Playlist:\n", + "Chosen Playlist: COUNTRY HITS 2025 🔥 New Country Songs + Top Hits\n", + "Description: best country music of 2025 most popular trending today modern mix viral top 100 hottest contemporary country pop rock latest americana ⚠️ NO SOCIAL MEDIA ACCOUNTS ASSOCIATED WITH THIS PROFILE. BEWARE OF SCAMS!\n", + "Total Track Count: 111\n", + "\n", + "3. First 10 Tracks in the Chosen Playlist:\n", + "1. What I Want (feat. Tate McRae)\n", + "2. weren't for the wind\n", + "3. Bloodline\n", + "4. A Bar Song (Tipsy)\n", + "5. Backup Plan (feat. Luke Combs)\n", + "6. Brunette\n", + "7. I Got Better\n", + "8. Roadwork\n", + "9. Better Me For You (Brown Eyes)\n", + "10. NOTHING ON YOU\n", + "\n", + "4. Track-Artist Dictionary:\n", + "Dictionary of tracks and their artists:\n", + "'What I Want (feat. Tate McRae)': ['Morgan Wallen', 'Tate McRae']\n", + "'weren't for the wind': ['Ella Langley']\n", + "'Bloodline': ['Alex Warren', 'Jelly Roll']\n", + "'A Bar Song (Tipsy)': ['Shaboozey']\n", + "'Backup Plan (feat. Luke Combs)': ['Bailey Zimmerman', 'Luke Combs']\n", + "'Brunette': ['Tucker Wetmore']\n", + "'I Got Better': ['Morgan Wallen']\n", + "'Roadwork': ['Kaleb Sanders']\n", + "'Better Me For You (Brown Eyes)': ['Max McNown']\n", + "'NOTHING ON YOU': ['Jet Jurgensmeyer']\n", + "\n", + "Summary:\n", + "- Analyzed playlist: COUNTRY HITS 2025 🔥 New Country Songs + Top Hits\n", + "- Total tracks in playlist: 111\n", + "- Tracks analyzed: 10\n", + "- Unique artists found: 12\n", + "1. What I Want (feat. Tate McRae)\n", + "2. weren't for the wind\n", + "3. Bloodline\n", + "4. A Bar Song (Tipsy)\n", + "5. Backup Plan (feat. Luke Combs)\n", + "6. Brunette\n", + "7. I Got Better\n", + "8. Roadwork\n", + "9. Better Me For You (Brown Eyes)\n", + "10. NOTHING ON YOU\n", + "\n", + "4. Track-Artist Dictionary:\n", + "Dictionary of tracks and their artists:\n", + "'What I Want (feat. Tate McRae)': ['Morgan Wallen', 'Tate McRae']\n", + "'weren't for the wind': ['Ella Langley']\n", + "'Bloodline': ['Alex Warren', 'Jelly Roll']\n", + "'A Bar Song (Tipsy)': ['Shaboozey']\n", + "'Backup Plan (feat. Luke Combs)': ['Bailey Zimmerman', 'Luke Combs']\n", + "'Brunette': ['Tucker Wetmore']\n", + "'I Got Better': ['Morgan Wallen']\n", + "'Roadwork': ['Kaleb Sanders']\n", + "'Better Me For You (Brown Eyes)': ['Max McNown']\n", + "'NOTHING ON YOU': ['Jet Jurgensmeyer']\n", + "\n", + "Summary:\n", + "- Analyzed playlist: COUNTRY HITS 2025 🔥 New Country Songs + Top Hits\n", + "- Total tracks in playlist: 111\n", + "- Tracks analyzed: 10\n", + "- Unique artists found: 12\n" + ] + } + ], "source": [ - "# Your answer here" + "# Exercise 2: Unraveling the World of Playlists\n", + "\n", + "# Since featured_playlists() is deprecated, we'll use search to find popular playlists\n", + "# and work with some example playlist IDs\n", + "\n", + "print(\"=== Exercise 2: Unraveling the World of Playlists ===\")\n", + "\n", + "# 1. Featured Exploration (Alternative approach)\n", + "print(\"1. Finding Popular Playlists:\")\n", + "\n", + "# Let's search for some popular playlists instead of using featured_playlists\n", + "playlist_searches = [\"top hits\", \"pop music\", \"today's hits\", \"viral hits\", \"global hits\"]\n", + "found_playlists = []\n", + "\n", + "for search_term in playlist_searches:\n", + " try:\n", + " results = sp.search(q=search_term, type='playlist', limit=2)\n", + " for playlist in results['playlists']['items']:\n", + " if playlist and len(found_playlists) < 5:\n", + " found_playlists.append({\n", + " 'name': playlist['name'],\n", + " 'id': playlist['id'],\n", + " 'description': playlist.get('description', 'No description'),\n", + " 'tracks_total': playlist['tracks']['total']\n", + " })\n", + " except Exception as e:\n", + " print(f\"Error searching for {search_term}: {e}\")\n", + "\n", + "print(\"Top 5 Popular Playlists found:\")\n", + "for i, playlist in enumerate(found_playlists, 1):\n", + " print(f\"{i}. Name: {playlist['name']}\")\n", + " print(f\" ID: {playlist['id']}\")\n", + " print(f\" Description: {playlist['description'][:100]}...\")\n", + " print()\n", + "\n", + "# 2. Deep Dive\n", + "print(\"2. Deep Dive into a Selected Playlist:\")\n", + "\n", + "# Choose the first playlist from our search (or use the example from the notebook)\n", + "if found_playlists:\n", + " chosen_playlist_id = found_playlists[0]['id']\n", + " chosen_playlist_name = found_playlists[0]['name']\n", + "else:\n", + " # Fallback to the example playlist from the notebook\n", + " chosen_playlist_id = \"37i9dQZF1DXd9zR7tdziuQ\"\n", + " chosen_playlist_name = \"Example Playlist\"\n", + "\n", + "try:\n", + " playlist_details = sp.playlist(chosen_playlist_id)\n", + " \n", + " print(f\"Chosen Playlist: {playlist_details['name']}\")\n", + " print(f\"Description: {playlist_details.get('description', 'No description')}\")\n", + " print(f\"Total Track Count: {playlist_details['tracks']['total']}\")\n", + " print()\n", + " \n", + " # 3. Track-tastic\n", + " print(\"3. First 10 Tracks in the Chosen Playlist:\")\n", + " \n", + " tracks = sp.playlist_tracks(chosen_playlist_id, limit=10)\n", + " track_names = []\n", + " \n", + " for i, track_item in enumerate(tracks['items'], 1):\n", + " if track_item['track']:\n", + " track_name = track_item['track']['name']\n", + " track_names.append(track_name)\n", + " print(f\"{i}. {track_name}\")\n", + " \n", + " print()\n", + " \n", + " # 4. Artistic Flair\n", + " print(\"4. Track-Artist Dictionary:\")\n", + " \n", + " track_artist_dict = {}\n", + " \n", + " for track_item in tracks['items']:\n", + " if track_item['track']:\n", + " track = track_item['track']\n", + " track_name = track['name']\n", + " artists = [artist['name'] for artist in track['artists']]\n", + " track_artist_dict[track_name] = artists\n", + " \n", + " print(\"Dictionary of tracks and their artists:\")\n", + " for track, artists in track_artist_dict.items():\n", + " print(f\"'{track}': {artists}\")\n", + " \n", + " print(f\"\\nSummary:\")\n", + " print(f\"- Analyzed playlist: {playlist_details['name']}\")\n", + " print(f\"- Total tracks in playlist: {playlist_details['tracks']['total']}\")\n", + " print(f\"- Tracks analyzed: {len(track_names)}\")\n", + " print(f\"- Unique artists found: {len(set(artist for artists in track_artist_dict.values() for artist in artists))}\")\n", + "\n", + "except Exception as e:\n", + " print(f\"Error accessing playlist {chosen_playlist_id}: {e}\")\n", + " \n", + " # Alternative: Create a manual example\n", + " print(\"\\nUsing manual example data:\")\n", + " \n", + " # Manual example data for demonstration\n", + " example_tracks = [\n", + " \"Blinding Lights\", \"Watermelon Sugar\", \"Levitating\", \n", + " \"drivers license\", \"Good 4 U\", \"Stay\", \"Heat Waves\",\n", + " \"Industry Baby\", \"Ghost\", \"Bad Habits\"\n", + " ]\n", + " \n", + " example_track_artist_dict = {\n", + " \"Blinding Lights\": [\"The Weeknd\"],\n", + " \"Watermelon Sugar\": [\"Harry Styles\"],\n", + " \"Levitating\": [\"Dua Lipa\"],\n", + " \"drivers license\": [\"Olivia Rodrigo\"],\n", + " \"Good 4 U\": [\"Olivia Rodrigo\"],\n", + " \"Stay\": [\"The Kid LAROI\", \"Justin Bieber\"],\n", + " \"Heat Waves\": [\"Glass Animals\"],\n", + " \"Industry Baby\": [\"Lil Nas X\", \"Jack Harlow\"],\n", + " \"Ghost\": [\"Justice\"],\n", + " \"Bad Habits\": [\"Ed Sheeran\"]\n", + " }\n", + " \n", + " print(\"3. Example Top 10 Tracks:\")\n", + " for i, track in enumerate(example_tracks, 1):\n", + " print(f\"{i}. {track}\")\n", + " \n", + " print(\"\\n4. Example Track-Artist Dictionary:\")\n", + " for track, artists in example_track_artist_dict.items():\n", + " print(f\"'{track}': {artists}\")" ] } ], "metadata": { "kernelspec": { - "display_name": "Python 3 (ipykernel)", + "display_name": ".venv", "language": "python", "name": "python3" }, @@ -558,7 +1125,7 @@ "name": "python", "nbconvert_exporter": "python", "pygments_lexer": "ipython3", - "version": "3.9.13" + "version": "3.13.5" } }, "nbformat": 4,