diff --git a/.cache b/.cache new file mode 100644 index 0000000..c7ccca4 --- /dev/null +++ b/.cache @@ -0,0 +1 @@ +{"access_token": "BQBmb5Ypjo8kw2hS6Oev86JR6CY0C2uNEbzrJtAyQGdB4P9HJo8Ci4FE1eNzC7VXIqzu644i1x_5V4Lp4WEvX8b_XDE5tNC4XhYBoOdQTAtziCMddNMXw-3IV5eJfP1dou0vJiQAbYQ", "token_type": "Bearer", "expires_in": 3600, "expires_at": 1758907684} \ No newline at end of file diff --git a/.env b/.env new file mode 100644 index 0000000..9cf48af --- /dev/null +++ b/.env @@ -0,0 +1,2 @@ +CLIENT_ID="7820bedb1f404b66a95b2b2d9eef1ac9" +CLIENT_SECRET="7719c9312a8145d2a58928f8ea0cfe62" \ No newline at end of file diff --git a/.ipynb_checkpoints/README-checkpoint.md b/.ipynb_checkpoints/README-checkpoint.md new file mode 100644 index 0000000..936335c --- /dev/null +++ b/.ipynb_checkpoints/README-checkpoint.md @@ -0,0 +1,118 @@ +![logo_ironhack_blue 7](https://user-images.githubusercontent.com/23629340/40541063-a07a0a8a-601a-11e8-91b5-2f13e4e6b441.png) + +# LAB | APIs +
+ +

Learning Goals

+
+ + This lab allows you to practice and apply the concepts and techniques taught in class. + + Upon completion of this lab, you will be able to: + +- Use Python libraries such as requests to extract data from APIs, and convert extracted data into a suitable data structure. + +
+
+ +
+ +
+ +
+ + +## Introduction + +Welcome to the world of music data exploration! In this lab, you will venture into the realm of the Spotify API using SpotiPy, a Python library that allows you to interact with Spotify's vast music catalog and playlist data. + +### **Objective** + +The objective of this lab is to acquaint you with the fundamental operations of the Spotify API using SpotiPy. You will learn how to authenticate with the API, perform searches for tracks and artists, and retrieve information about playlists, among other things. + +### **Lab Sections** + +This lab comprises two main sections: + +#### **Section 1: Discovering New Music through Your Favorite Artists** + +In this section, you will use the Spotify API to explore the top tracks of your favorite artists and discover related artists. By the end, you'll have the opportunity to create a playlist featuring your favorite tracks and those of related artists. + +#### **Section 2: Unraveling the World of Playlists** + +In the second section, you will delve into Spotify's featured playlists. You'll learn how to fetch information about these playlists, explore their details, and extract track and artist data from them. + +
+ +Let's embark on this musical journey into the world of Spotify API exploration! + +
+ +**Happy coding!** :heart: + + +## Requirements + +- Fork this repo +- Clone it to your machine + +## Getting Started + +Complete the challenges in the `Jupyter Notebook` file. Follow the instructions and add your code and explanations as necessary. + +## Submission + +- Upon completion, run the following commands: + +```bash +git add . +git commit -m "Solved lab" +git push origin master +``` + +- Paste the link of your lab in Student Portal. + + +## FAQs +
+ I am stuck in the exercise and don't know how to solve the problem or where to start. +
+ + If you are stuck in your code and don't know how to solve the problem or where to start, you should take a step back and try to form a clear question about the specific issue you are facing. This will help you narrow down the problem and come up with potential solutions. + + + For example, is it a concept that you don't understand, or are you receiving an error message that you don't know how to fix? It is usually helpful to try to state the problem as clearly as possible, including any error messages you are receiving. This can help you communicate the issue to others and potentially get help from classmates or online resources. + + + Once you have a clear understanding of the problem, you will be able to start working toward the solution. + + [Back to top](#faqs) + +
+ + +
+ I am unable to push changes to the repository. What should I do? +
+ +There are a couple of possible reasons why you may be unable to *push* changes to a Git repository: + +1. **You have not committed your changes:** Before you can push your changes to the repository, you need to commit them using the `git commit` command. Make sure you have committed your changes and try pushing again. To do this, run the following terminal commands from the project folder: + ```bash + git add . + git commit -m "Your commit message" + git push + ``` +2. **You do not have permission to push to the repository:** If you have cloned the repository directly from the main Ironhack repository without making a *Fork* first, you do not have write access to the repository. +To check which remote repository you have cloned, run the following terminal command from the project folder: + ```bash + git remote -v + ``` +If the link shown is the same as the main Ironhack repository, you will need to fork the repository to your GitHub account first and then clone your fork to your local machine to be able to push the changes. + +**Note**: You should make a copy of your local code to avoid losing it in the process. + + [Back to top](#faqs) + +
+ diff --git a/.ipynb_checkpoints/lab-apis-checkpoint.ipynb b/.ipynb_checkpoints/lab-apis-checkpoint.ipynb new file mode 100644 index 0000000..e923554 --- /dev/null +++ b/.ipynb_checkpoints/lab-apis-checkpoint.ipynb @@ -0,0 +1,566 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "id": "27422808-8a16-4be1-897f-57b379af8991", + "metadata": {}, + "source": [ + "# Lab | APIs" + ] + }, + { + "cell_type": "markdown", + "id": "50f30950-3e31-499a-92ea-1535422c570b", + "metadata": {}, + "source": [ + "In order to use the `Spotify` API (`SpotiPy`), create an account in `Spotify` and follow [these](https://developer.spotify.com/documentation/general/guides/app-settings/) steps. " + ] + }, + { + "cell_type": "markdown", + "id": "a0479b95-6ca5-415e-b894-1f5cb17b055b", + "metadata": {}, + "source": [ + "## Authentication and initializing the API" + ] + }, + { + "cell_type": "markdown", + "id": "47d71611-c617-4972-a0c3-7090c24b399c", + "metadata": {}, + "source": [ + "Save your client ID and your client secret in your preferred way, and read it or load it into the following variables:" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "ea44c82a-5c07-4dbc-beb2-bba2601bb75e", + "metadata": {}, + "outputs": [], + "source": [ + "CLIENT_ID = \"\"\n", + "CLIENT_SECRET = \"\"" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "319cfd4e-f6fb-4419-80e0-e3983cd25e43", + "metadata": {}, + "outputs": [], + "source": [ + "CLIENT_ID = \"4109b2d9f5014671863bb2df1d1fbdd3\"\n", + "CLIENT_SECRET = \"5cb719fae80c4191a9c0b288f51bfe50\"" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "04e12954-fd70-4311-88a5-fb7e2c29799c", + "metadata": {}, + "outputs": [], + "source": [ + "# If you havent done so, install the spotipy wrapper\n", + "!pip install spotipy" + ] + }, + { + "cell_type": "markdown", + "id": "dc0e86da-8846-4207-84c3-cd20b9e01d0e", + "metadata": {}, + "source": [ + "Once you have done it, we will start initializing the API." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "03034bc6-9858-412a-83b7-18abdc345d7e", + "metadata": {}, + "outputs": [], + "source": [ + "import spotipy\n", + "from spotipy.oauth2 import SpotifyClientCredentials\n", + "\n", + "#Initialize SpotiPy with user credentials\n", + "sp = spotipy.Spotify(auth_manager=SpotifyClientCredentials(client_id=CLIENT_ID,\n", + " client_secret=CLIENT_SECRET))\n" + ] + }, + { + "cell_type": "markdown", + "id": "8fed9628-08d7-4290-a4be-5527696b01c5", + "metadata": {}, + "source": [ + "## Using the search method" + ] + }, + { + "cell_type": "markdown", + "id": "6575a3c6-f25a-4905-b1f3-c0efd50dcc1e", + "metadata": {}, + "source": [ + "Now, let's use the search method by introducing a \"query\". For example, let's try searching for \"Lady Gaga\":" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "7772a1e0-9692-4d04-a590-76111a272d8d", + "metadata": { + "tags": [] + }, + "outputs": [], + "source": [ + "results = sp.search(q='Lady Gaga', limit=50)\n", + "results" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "edc14c95-474b-4e2a-aea3-bdfd0a205546", + "metadata": {}, + "outputs": [], + "source": [ + "results.keys() # We can see that we only have tracks" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "ad8ef934-1dbb-4008-ac8e-f5c29823fe6a", + "metadata": {}, + "outputs": [], + "source": [ + "results[\"tracks\"].keys() # Let's check the values" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "004b7814-4dd5-408e-b7ba-1da87f9250cb", + "metadata": {}, + "outputs": [], + "source": [ + "results[\"tracks\"][\"href\"] # Query we have searched " + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "7285cedd-fbe1-47cf-98d5-a7fdc3e5c8b8", + "metadata": { + "scrolled": true, + "tags": [] + }, + "outputs": [], + "source": [ + "results[\"tracks\"][\"items\"] #items (actual tracks)" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "529fff56-47d3-4d78-8ff5-9530fe290d1d", + "metadata": {}, + "outputs": [], + "source": [ + "results[\"tracks\"][\"limit\"]#Limit we have chosen" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "92c64c57-3bd2-4d42-bbd1-84a040f1e02a", + "metadata": {}, + "outputs": [], + "source": [ + "results[\"tracks\"][\"next\"] #link to the next page (next 50 tracks)" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "f5ccdf79-5d9e-40de-adb9-2cc1e5b7c74a", + "metadata": { + "tags": [] + }, + "outputs": [], + "source": [ + "results[\"tracks\"][\"offset\"] # Actual offset (starting point)" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "356730c1-60a2-4ea8-bd2c-e0522bab8a4d", + "metadata": {}, + "outputs": [], + "source": [ + "results[\"tracks\"][\"previous\"] #Previous search" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "7c44c8fd-63ea-45ba-94bd-5c5e8e1458b3", + "metadata": {}, + "outputs": [], + "source": [ + "results[\"tracks\"][\"total\"] # Number of matches" + ] + }, + { + "cell_type": "markdown", + "id": "7a127c64-3274-4ecc-aa0f-83ae34af4655", + "metadata": {}, + "source": [ + "## Exploring the tracks" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "6c3541a2-0fd2-41e0-9b27-60a7dc36c4cb", + "metadata": { + "scrolled": true, + "tags": [] + }, + "outputs": [], + "source": [ + "results[\"tracks\"][\"items\"][0] # Explore the first song" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "f2c35eb2-3ea6-4329-9f29-7c062f466638", + "metadata": {}, + "outputs": [], + "source": [ + "results[\"tracks\"][\"items\"][0].keys() # We will focus on album, artists, id, name, popularity, type and uri" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "889ca3c3-b0c8-4037-96fb-6add847f537f", + "metadata": {}, + "outputs": [], + "source": [ + "# Track artists\n", + "results[\"tracks\"][\"items\"][0][\"artists\"] " + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "a9c6a0b2-cea7-48ff-8c51-179d15388aa2", + "metadata": {}, + "outputs": [], + "source": [ + "# Track artists names\n", + "for artist in results[\"tracks\"][\"items\"][0][\"artists\"]:\n", + " print(artist[\"name\"])" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "6a826e9c-d2e7-4537-a82c-3dc3a2b80b9f", + "metadata": {}, + "outputs": [], + "source": [ + "# Track ID\n", + "results[\"tracks\"][\"items\"][0][\"id\"] " + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "a5bd871b-6087-4680-819c-1a1d8ba879bc", + "metadata": {}, + "outputs": [], + "source": [ + "# Track name\n", + "results[\"tracks\"][\"items\"][0][\"name\"] " + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "812661f1-29db-452f-a719-cdfbe95ba9f6", + "metadata": {}, + "outputs": [], + "source": [ + "# Popularity index\n", + "results[\"tracks\"][\"items\"][0][\"popularity\"] " + ] + }, + { + "cell_type": "markdown", + "id": "0e81c762-e6c5-424e-a4eb-12ab45dffb9f", + "metadata": {}, + "source": [ + "Spotify songs are identified by either a \"url\", a \"uri\", or an \"id\". \n", + "\n", + "- The `id` is an alphanumeric code, and it's the nuclear part of the identifier.\n", + "\n", + "- The `uri` contains \"spotify:track\" before the id. An uri is useful because it can be searched manually in the Spotify app.\n", + "\n", + "- The `url` is a link to the song on the Spotify web player.\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "8bcdccfc-dde9-4f4b-8af5-3caa335b89b5", + "metadata": {}, + "outputs": [], + "source": [ + "results[\"tracks\"][\"items\"][0][\"uri\"]" + ] + }, + { + "cell_type": "markdown", + "id": "71c3c9c1-4ec2-42bf-a243-b21105ae1699", + "metadata": {}, + "source": [ + "## Exercise 1: Discovering New Music through Your Favorite Artists\n", + "\n", + "**Objective:** \n", + "Uncover new music by exploring the top tracks of your favorite artists and their related artists.\n", + "\n", + "**Instructions:**\n", + "\n", + "1. **List Your Favorite Artists**:\n", + " - Make a list of your three favorite artists and store it in a variable named `artists`.\n", + " - Example: `artists = [\"Los Fabulosos Cadillacs\", \"Manu Chao\", \"Muchachito Bombo Infierno\"]`.\n", + "\n", + "2. **Fetch Top Tracks**:\n", + " - Write a function named `get_top_tracks`.\n", + " - This function should accept an artist's name and return the name of the first 5 top tracks by that artist.\n", + " - Use the function `get_top_tracks` to get the first 5 top tracks for each artist in your `artists` list and store the results in a new list named `top_tracks_list`.\n", + "\n", + "3. **Discover Related Artists**:\n", + " - Write a function named `find_related_artists`.\n", + " - This function should accept an artist's name and return the names of the first 5 artists related to the provided artist.\n", + " - Store the results in a list named `related_artists_list`.\n", + "\n", + "**Challenge:** \n", + "Combine the above steps to create a playlist that includes the top tracks of your favorite artists and the top tracks of the artists related to them." + ] + }, + { + "cell_type": "markdown", + "id": "0c442378-e26f-47c8-b4f1-b4fa07089935", + "metadata": {}, + "source": [ + "**Hint Section for 3. **Discover Related Artists**:**\n", + "\n", + "1. **Getting Artist ID**:\n", + " - Remember that every artist on Spotify has a unique identifier: their `id`. To get the related artists, you first need to fetch the ID of the given artist.\n", + " - Consider using the `sp.search` method to query the artist's name. The method requires a `q` parameter, which is your query (in this case, the artist's name). It also has a `limit` parameter, which specifies the number of tracks it returns. In this case, 1 track is enough, since we just want the artist ID. \n", + " - Each track in the results has an associated 'artists' field. This field is a list containing details about all artists involved in that track.\n", + " - For most tracks, especially those by a single artist, this list will contain one artist. From this artist's details, you can extract the 'id' field, which is the unique identifier for that artist on Spotify.\n", + "\n", + "\n", + "3. **Fetching Related Artists**:\n", + " - Once you have the artist's ID, you can use another SpotiPy method to fetch related artists. Think about which SpotiPy method allows you to get related artists using an artist's ID. Here is the documentation link: https://spotipy.readthedocs.io/en/2.22.1/. \n", + " - This method will return a list of related artists. You'll need to extract the relevant details (artist names) from this list.\n", + "\n", + "4. **Iterating for Multiple Artists**:\n", + " - Once you have a function that returns related artists names for one artist, you can use a list comprehension to apply this function to a list of artist names.\n", + "\n", + "5. **Testing**:\n", + " - Always test your function with one artist name first. Once you're confident it works, then apply it to the entire list.\n", + "\n", + "Remember, the key is to break the problem down into manageable steps. Use the SpotiPy documentation as a resource to understand available methods and their return structures." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "29694252-f217-454d-8881-681b2b6eeb1e", + "metadata": {}, + "outputs": [], + "source": [ + "# Your answer here" + ] + }, + { + "cell_type": "markdown", + "id": "94ad5fdc-22e5-4521-8aa1-c6833eb7e949", + "metadata": {}, + "source": [ + "## Playlists\n", + "\n", + "The `sp.featured_playlists()` method in `spotipy` fetches a list of Spotify's featured playlists at a given moment. These are curated playlists that Spotify often highlights on the platform's homepage. The method provides a snapshot of the playlists that are being promoted or featured by Spotify at the time of the request.\n", + "\n", + "Once you've fetched the featured playlists, you can extract their IDs (and other details)." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "25fb0cf8-c13a-41b0-b8f8-7e0700fd1e41", + "metadata": {}, + "outputs": [], + "source": [ + "sp.featured_playlists() # We get a playlist id of a playlist we like" + ] + }, + { + "cell_type": "markdown", + "id": "90f558f3-c638-4df4-b5a4-e24f7847d52a", + "metadata": {}, + "source": [ + "### Getting a Playlist's Details\n", + "To fetch details about a specific playlist, you can use the playlist method. You'll need the playlist's Spotify ID." + ] + }, + { + "cell_type": "markdown", + "id": "0eef529f-617f-4ea3-8156-07472ac8e6d5", + "metadata": {}, + "source": [ + "In this example, we will use the following playlist id: *37i9dQZF1DXd9zR7tdziuQ*" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "46d35121-9256-4cf4-81f5-118b87f7af32", + "metadata": {}, + "outputs": [], + "source": [ + "playlist_id = \"37i9dQZF1DXd9zR7tdziuQ\"\n", + "playlist = sp.playlist(playlist_id)" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "5260f67f-6024-4fee-8449-30904f03bf76", + "metadata": {}, + "outputs": [], + "source": [ + "print(playlist['name']) # Print the playlist's name\n", + "print(playlist['description']) # Print the playlist's description" + ] + }, + { + "cell_type": "markdown", + "id": "13bc8631-69f0-4b98-9cc9-5baecbaea9ba", + "metadata": {}, + "source": [ + "### Getting Tracks from a Playlist\n", + "If you want to get the tracks from a specific playlist, you can use the playlist_tracks method." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "69c78f8d-7e6a-4d15-bcbb-fc93edb82433", + "metadata": {}, + "outputs": [], + "source": [ + "tracks = sp.playlist_tracks(playlist_id)\n", + "for track in tracks['items']:\n", + " print(track['track']['name']) # Print each track's name" + ] + }, + { + "cell_type": "markdown", + "id": "2775714d-acc7-4555-96bd-2c541ab0855e", + "metadata": {}, + "source": [ + "### Getting Artists from a Playlist\n", + "\n", + "To extract all the artists from the tracks in a playlist, you'd typically follow these steps:\n", + "\n", + "1. Fetch the playlist's tracks.\n", + "2. Iterate through each track.\n", + "3. For each track, extract the associated artists." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "65c5e5c4-f186-42c6-b136-4ef02b0b01ff", + "metadata": {}, + "outputs": [], + "source": [ + "# List to store unique artist names\n", + "artists_list = []\n", + "\n", + "for track_item in tracks['items']:\n", + " track = track_item['track']\n", + " for artist in track['artists']:\n", + " artist_name = artist['name']\n", + " if artist_name not in artists_list: # This ensures each artist is added only once\n", + " artists_list.append(artist_name)\n", + "\n", + "print(artists_list)" + ] + }, + { + "cell_type": "markdown", + "id": "7b52207e-a4f0-4f90-9f4e-3170d7f0f3fe", + "metadata": {}, + "source": [ + "## Exercise 2: Unraveling the World of Playlists\n", + "\n", + "\n", + "1. **Featured Exploration**: \n", + " - Fetch the list of Spotify's current featured playlists. \n", + " - Extract and display the names and IDs of the top 5 featured playlists.\n", + " \n", + "2. **Deep Dive**:\n", + " - Choose any one of the top 5 featured playlists (you can choose the one you personally find most interesting or simply pick one randomly).\n", + " - Fetch and display its name, description, and total track count.\n", + "\n", + "3. **Track-tastic**:\n", + " - Extract and display the names of the first 10 tracks in the chosen playlist.\n", + "\n", + "4. **Artistic Flair**:\n", + " - Create a dictionary where the keys are the names of the first 10 tracks, and the values are lists containing the names of the artists associated with each track.\n", + " - For example: `{\"TrackName1\": [\"Artist1\", \"Artist2\"], \"TrackName2\": [\"Artist3\"]}`\n", + " " + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "ed92d961-9646-4375-a386-ccc320a958f5", + "metadata": {}, + "outputs": [], + "source": [ + "# Your answer here" + ] + } + ], + "metadata": { + "kernelspec": { + "display_name": "Python 3 (ipykernel)", + "language": "python", + "name": "python3" + }, + "language_info": { + "codemirror_mode": { + "name": "ipython", + "version": 3 + }, + "file_extension": ".py", + "mimetype": "text/x-python", + "name": "python", + "nbconvert_exporter": "python", + "pygments_lexer": "ipython3", + "version": "3.9.13" + } + }, + "nbformat": 4, + "nbformat_minor": 5 +} diff --git a/lab-apis.ipynb b/lab-apis.ipynb index e923554..f1805d5 100644 --- a/lab-apis.ipynb +++ b/lab-apis.ipynb @@ -34,35 +34,37 @@ }, { "cell_type": "code", - "execution_count": null, + "execution_count": 121, "id": "ea44c82a-5c07-4dbc-beb2-bba2601bb75e", "metadata": {}, "outputs": [], "source": [ - "CLIENT_ID = \"\"\n", - "CLIENT_SECRET = \"\"" + "import os\n", + "from dotenv import load_dotenv" ] }, { "cell_type": "code", - "execution_count": null, + "execution_count": 122, "id": "319cfd4e-f6fb-4419-80e0-e3983cd25e43", "metadata": {}, "outputs": [], "source": [ - "CLIENT_ID = \"4109b2d9f5014671863bb2df1d1fbdd3\"\n", - "CLIENT_SECRET = \"5cb719fae80c4191a9c0b288f51bfe50\"" + "load_dotenv()\n", + "\n", + "CLIENT_ID = os.getenv(\"CLIENT_ID\")\n", + "CLIENT_SECRET = os.getenv(\"CLIENT_SECRET\")" ] }, { "cell_type": "code", - "execution_count": null, + "execution_count": 123, "id": "04e12954-fd70-4311-88a5-fb7e2c29799c", "metadata": {}, "outputs": [], "source": [ "# If you havent done so, install the spotipy wrapper\n", - "!pip install spotipy" + "# !pip install spotipy" ] }, { @@ -75,7 +77,7 @@ }, { "cell_type": "code", - "execution_count": null, + "execution_count": 124, "id": "03034bc6-9858-412a-83b7-18abdc345d7e", "metadata": {}, "outputs": [], @@ -106,50 +108,50 @@ }, { "cell_type": "code", - "execution_count": null, + "execution_count": 125, "id": "7772a1e0-9692-4d04-a590-76111a272d8d", "metadata": { "tags": [] }, "outputs": [], "source": [ - "results = sp.search(q='Lady Gaga', limit=50)\n", - "results" + "#results = sp.search(q='Lady Gaga', limit=50)\n", + "#results" ] }, { "cell_type": "code", - "execution_count": null, + "execution_count": 126, "id": "edc14c95-474b-4e2a-aea3-bdfd0a205546", "metadata": {}, "outputs": [], "source": [ - "results.keys() # We can see that we only have tracks" + "#results.keys() # We can see that we only have tracks" ] }, { "cell_type": "code", - "execution_count": null, + "execution_count": 127, "id": "ad8ef934-1dbb-4008-ac8e-f5c29823fe6a", "metadata": {}, "outputs": [], "source": [ - "results[\"tracks\"].keys() # Let's check the values" + "#results[\"tracks\"].keys() # Let's check the values" ] }, { "cell_type": "code", - "execution_count": null, + "execution_count": 128, "id": "004b7814-4dd5-408e-b7ba-1da87f9250cb", "metadata": {}, "outputs": [], "source": [ - "results[\"tracks\"][\"href\"] # Query we have searched " + "#results[\"tracks\"][\"href\"] # Query we have searched " ] }, { "cell_type": "code", - "execution_count": null, + "execution_count": 129, "id": "7285cedd-fbe1-47cf-98d5-a7fdc3e5c8b8", "metadata": { "scrolled": true, @@ -157,59 +159,59 @@ }, "outputs": [], "source": [ - "results[\"tracks\"][\"items\"] #items (actual tracks)" + "#results[\"tracks\"][\"items\"] #items (actual tracks)" ] }, { "cell_type": "code", - "execution_count": null, + "execution_count": 130, "id": "529fff56-47d3-4d78-8ff5-9530fe290d1d", "metadata": {}, "outputs": [], "source": [ - "results[\"tracks\"][\"limit\"]#Limit we have chosen" + "#results[\"tracks\"][\"limit\"]#Limit we have chosen" ] }, { "cell_type": "code", - "execution_count": null, + "execution_count": 131, "id": "92c64c57-3bd2-4d42-bbd1-84a040f1e02a", "metadata": {}, "outputs": [], "source": [ - "results[\"tracks\"][\"next\"] #link to the next page (next 50 tracks)" + "#results[\"tracks\"][\"next\"] #link to the next page (next 50 tracks)" ] }, { "cell_type": "code", - "execution_count": null, + "execution_count": 132, "id": "f5ccdf79-5d9e-40de-adb9-2cc1e5b7c74a", "metadata": { "tags": [] }, "outputs": [], "source": [ - "results[\"tracks\"][\"offset\"] # Actual offset (starting point)" + "#results[\"tracks\"][\"offset\"] # Actual offset (starting point)" ] }, { "cell_type": "code", - "execution_count": null, + "execution_count": 133, "id": "356730c1-60a2-4ea8-bd2c-e0522bab8a4d", "metadata": {}, "outputs": [], "source": [ - "results[\"tracks\"][\"previous\"] #Previous search" + "#results[\"tracks\"][\"previous\"] #Previous search" ] }, { "cell_type": "code", - "execution_count": null, + "execution_count": 134, "id": "7c44c8fd-63ea-45ba-94bd-5c5e8e1458b3", "metadata": {}, "outputs": [], "source": [ - "results[\"tracks\"][\"total\"] # Number of matches" + "#results[\"tracks\"][\"total\"] # Number of matches" ] }, { @@ -222,7 +224,7 @@ }, { "cell_type": "code", - "execution_count": null, + "execution_count": 135, "id": "6c3541a2-0fd2-41e0-9b27-60a7dc36c4cb", "metadata": { "scrolled": true, @@ -230,73 +232,73 @@ }, "outputs": [], "source": [ - "results[\"tracks\"][\"items\"][0] # Explore the first song" + "#results[\"tracks\"][\"items\"][0] # Explore the first song" ] }, { "cell_type": "code", - "execution_count": null, + "execution_count": 136, "id": "f2c35eb2-3ea6-4329-9f29-7c062f466638", "metadata": {}, "outputs": [], "source": [ - "results[\"tracks\"][\"items\"][0].keys() # We will focus on album, artists, id, name, popularity, type and uri" + "#results[\"tracks\"][\"items\"][0].keys() # We will focus on album, artists, id, name, popularity, type and uri" ] }, { "cell_type": "code", - "execution_count": null, + "execution_count": 137, "id": "889ca3c3-b0c8-4037-96fb-6add847f537f", "metadata": {}, "outputs": [], "source": [ "# Track artists\n", - "results[\"tracks\"][\"items\"][0][\"artists\"] " + "#results[\"tracks\"][\"items\"][0][\"artists\"] " ] }, { "cell_type": "code", - "execution_count": null, + "execution_count": 138, "id": "a9c6a0b2-cea7-48ff-8c51-179d15388aa2", "metadata": {}, "outputs": [], "source": [ "# Track artists names\n", - "for artist in results[\"tracks\"][\"items\"][0][\"artists\"]:\n", - " print(artist[\"name\"])" + "#for artist in results[\"tracks\"][\"items\"][0][\"artists\"]:\n", + "# print(artist[\"name\"])" ] }, { "cell_type": "code", - "execution_count": null, + "execution_count": 139, "id": "6a826e9c-d2e7-4537-a82c-3dc3a2b80b9f", "metadata": {}, "outputs": [], "source": [ "# Track ID\n", - "results[\"tracks\"][\"items\"][0][\"id\"] " + "#results[\"tracks\"][\"items\"][0][\"id\"] " ] }, { "cell_type": "code", - "execution_count": null, + "execution_count": 140, "id": "a5bd871b-6087-4680-819c-1a1d8ba879bc", "metadata": {}, "outputs": [], "source": [ "# Track name\n", - "results[\"tracks\"][\"items\"][0][\"name\"] " + "#results[\"tracks\"][\"items\"][0][\"name\"] " ] }, { "cell_type": "code", - "execution_count": null, + "execution_count": 141, "id": "812661f1-29db-452f-a719-cdfbe95ba9f6", "metadata": {}, "outputs": [], "source": [ "# Popularity index\n", - "results[\"tracks\"][\"items\"][0][\"popularity\"] " + "#results[\"tracks\"][\"items\"][0][\"popularity\"] " ] }, { @@ -315,12 +317,12 @@ }, { "cell_type": "code", - "execution_count": null, + "execution_count": 142, "id": "8bcdccfc-dde9-4f4b-8af5-3caa335b89b5", "metadata": {}, "outputs": [], "source": [ - "results[\"tracks\"][\"items\"][0][\"uri\"]" + "#results[\"tracks\"][\"items\"][0][\"uri\"]" ] }, { @@ -328,7 +330,7 @@ "id": "71c3c9c1-4ec2-42bf-a243-b21105ae1699", "metadata": {}, "source": [ - "## Exercise 1: Discovering New Music through Your Favorite Artists\n", + "### Exercise 1: Discovering New Music through Your Favorite Artists\n", "\n", "**Objective:** \n", "Uncover new music by exploring the top tracks of your favorite artists and their related artists.\n", @@ -382,12 +384,218 @@ }, { "cell_type": "code", - "execution_count": null, + "execution_count": 143, "id": "29694252-f217-454d-8881-681b2b6eeb1e", "metadata": {}, "outputs": [], "source": [ - "# Your answer here" + "#1 List Your Favorite Artists:\n", + "\n", + "artists = [\"Meshuggah\", \"Animals As Leaders\", \"Periphery\"]" + ] + }, + { + "cell_type": "code", + "execution_count": 144, + "id": "c824dfe4-6754-4ade-bf71-66050b359224", + "metadata": {}, + "outputs": [], + "source": [ + "#2 Fetch Top Tracks:\n", + "\n", + "def get_top_tracks(artist_name):\n", + " results = sp.search(q=artist_name, limit=5)\n", + "\n", + " track_names = [item['name'] for item in results['tracks']['items']]\n", + "\n", + " return track_names" + ] + }, + { + "cell_type": "code", + "execution_count": 145, + "id": "bc4cc9ce-4002-4890-b880-cbd8e333f214", + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "['Meshuggah', 'Bleed', 'Combustion', 'Demiurge', 'Lethargica']" + ] + }, + "execution_count": 145, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "get_top_tracks(\"Meshuggah\")" + ] + }, + { + "cell_type": "code", + "execution_count": 146, + "id": "66e876ed-239a-45b6-a1a0-aa91c06f716e", + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "['Cafo',\n", + " 'Physical Education',\n", + " 'The Woven Web',\n", + " 'High School Trouble Maker',\n", + " 'A Song About the End of the World']" + ] + }, + "execution_count": 146, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "get_top_tracks(\"Animals As Leaders\")" + ] + }, + { + "cell_type": "code", + "execution_count": 147, + "id": "17168427-2961-4a02-8ac8-78755295672e", + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "['Periphery', 'Marigold', 'Periphery', 'Atropos', 'Garden In The Bones']" + ] + }, + "execution_count": 147, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "get_top_tracks(\"Periphery\")" + ] + }, + { + "cell_type": "code", + "execution_count": 148, + "id": "6eacd5a1-96d1-45eb-acdb-0001872296ed", + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "[['Meshuggah', 'Bleed', 'Combustion', 'Demiurge', 'Lethargica'], ['Cafo', 'Physical Education', 'The Woven Web', 'High School Trouble Maker', 'A Song About the End of the World'], ['Periphery', 'Marigold', 'Periphery', 'Atropos', 'Garden In The Bones']]\n" + ] + } + ], + "source": [ + "top_tracks_list = []\n", + "\n", + "top_tracks_list = [get_top_tracks(artist) for artist in artists]\n", + "\n", + "print(top_tracks_list)" + ] + }, + { + "cell_type": "code", + "execution_count": 149, + "id": "104e045b-31ef-44ea-a818-3678ed7b56f6", + "metadata": {}, + "outputs": [], + "source": [ + "#3 Discover Related Artists:\n", + "\n", + "def find_related_artists(artist_name):\n", + " \"\"\"\n", + " Finds artists related to a given artist and returns their names\n", + " \"\"\"\n", + " results = sp.search(q=artist_name, limit=1, type='artist')\n", + "\n", + " if not results['artists']['items']:\n", + " return f\"No tracks found for {artist_name}\"\n", + " \n", + " artist_id = results['artists']['items'][0]['id']\n", + "\n", + " related_artists_results = sp.artist_related_artists(artist_id)\n", + "\n", + " related_artists_list = [artist['name'] for artist in related_artists_results['artists'][:5]]\n", + "\n", + " return related_artists_list" + ] + }, + { + "cell_type": "code", + "execution_count": 150, + "id": "8e587bf8-8089-4592-b746-ddee07515383", + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "--- Finding related artists for: Meshuggah ---\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + "HTTP Error for GET to https://api.spotify.com/v1/artists/3ggwAqZD3lyT2sbovlmfQY/related-artists with Params: {} returned 404 due to Not Found\n" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + "An error occurred for Meshuggah. It's likely the Spotify endpoint is no longer active.\n", + "--- Finding related artists for: Animals As Leaders ---\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + "HTTP Error for GET to https://api.spotify.com/v1/artists/65C6Unk7nhg2aCnVuAPMo8/related-artists with Params: {} returned 404 due to Not Found\n" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + "An error occurred for Animals As Leaders. It's likely the Spotify endpoint is no longer active.\n", + "--- Finding related artists for: Periphery ---\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + "HTTP Error for GET to https://api.spotify.com/v1/artists/6d24kC5fxHFOSEAmjQPPhc/related-artists with Params: {} returned 404 due to Not Found\n" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + "An error occurred for Periphery. It's likely the Spotify endpoint is no longer active.\n" + ] + } + ], + "source": [ + "related_artists_list = []\n", + "\n", + "for artist_name in artists:\n", + " print(f\"--- Finding related artists for: {artist_name} ---\")\n", + " try:\n", + " related = find_related_artists(artist_name)\n", + " print(f\"Found: {related}\")\n", + " related_artists_list.append(related)\n", + " except Exception as e:\n", + " print(f\"An error occurred for {artist_name}. It's likely the Spotify endpoint is no longer active.\")" ] }, { @@ -404,10 +612,37 @@ }, { "cell_type": "code", - "execution_count": null, + "execution_count": 151, "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[0;31m---------------------------------------------------------------------------\u001b[0m", + "\u001b[0;31mHTTPError\u001b[0m Traceback (most recent call last)", + "File \u001b[0;32m/opt/anaconda3/lib/python3.13/site-packages/spotipy/client.py:274\u001b[0m, in \u001b[0;36mSpotify._internal_call\u001b[0;34m(self, method, url, payload, params)\u001b[0m\n\u001b[1;32m 269\u001b[0m response \u001b[38;5;241m=\u001b[39m \u001b[38;5;28mself\u001b[39m\u001b[38;5;241m.\u001b[39m_session\u001b[38;5;241m.\u001b[39mrequest(\n\u001b[1;32m 270\u001b[0m method, url, headers\u001b[38;5;241m=\u001b[39mheaders, proxies\u001b[38;5;241m=\u001b[39m\u001b[38;5;28mself\u001b[39m\u001b[38;5;241m.\u001b[39mproxies,\n\u001b[1;32m 271\u001b[0m timeout\u001b[38;5;241m=\u001b[39m\u001b[38;5;28mself\u001b[39m\u001b[38;5;241m.\u001b[39mrequests_timeout, \u001b[38;5;241m*\u001b[39m\u001b[38;5;241m*\u001b[39margs\n\u001b[1;32m 272\u001b[0m )\n\u001b[0;32m--> 274\u001b[0m response\u001b[38;5;241m.\u001b[39mraise_for_status()\n\u001b[1;32m 275\u001b[0m results \u001b[38;5;241m=\u001b[39m response\u001b[38;5;241m.\u001b[39mjson()\n", + "File \u001b[0;32m/opt/anaconda3/lib/python3.13/site-packages/requests/models.py:1024\u001b[0m, in \u001b[0;36mResponse.raise_for_status\u001b[0;34m(self)\u001b[0m\n\u001b[1;32m 1023\u001b[0m \u001b[38;5;28;01mif\u001b[39;00m http_error_msg:\n\u001b[0;32m-> 1024\u001b[0m \u001b[38;5;28;01mraise\u001b[39;00m HTTPError(http_error_msg, response\u001b[38;5;241m=\u001b[39m\u001b[38;5;28mself\u001b[39m)\n", + "\u001b[0;31mHTTPError\u001b[0m: 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[0;31mSpotifyException\u001b[0m Traceback (most recent call last)", + "Cell \u001b[0;32mIn[151], line 1\u001b[0m\n\u001b[0;32m----> 1\u001b[0m sp\u001b[38;5;241m.\u001b[39mfeatured_playlists()\n", + "File \u001b[0;32m/opt/anaconda3/lib/python3.13/site-packages/spotipy/client.py:1595\u001b[0m, in \u001b[0;36mSpotify.featured_playlists\u001b[0;34m(self, locale, country, timestamp, limit, offset)\u001b[0m\n\u001b[1;32m 1569\u001b[0m \u001b[38;5;250m\u001b[39m\u001b[38;5;124;03m\"\"\" Get a list of Spotify featured playlists\u001b[39;00m\n\u001b[1;32m 1570\u001b[0m \n\u001b[1;32m 1571\u001b[0m \u001b[38;5;124;03m Parameters:\u001b[39;00m\n\u001b[0;32m (...)\u001b[0m\n\u001b[1;32m 1588\u001b[0m \u001b[38;5;124;03m items.\u001b[39;00m\n\u001b[1;32m 1589\u001b[0m \u001b[38;5;124;03m\"\"\"\u001b[39;00m\n\u001b[1;32m 1590\u001b[0m warnings\u001b[38;5;241m.\u001b[39mwarn(\n\u001b[1;32m 1591\u001b[0m \u001b[38;5;124m\"\u001b[39m\u001b[38;5;124mYou\u001b[39m\u001b[38;5;124m'\u001b[39m\u001b[38;5;124mre using `featured_playlists(...)`, \u001b[39m\u001b[38;5;124m\"\u001b[39m\n\u001b[1;32m 1592\u001b[0m \u001b[38;5;124m\"\u001b[39m\u001b[38;5;124mwhich is marked as deprecated by Spotify.\u001b[39m\u001b[38;5;124m\"\u001b[39m,\n\u001b[1;32m 1593\u001b[0m \u001b[38;5;167;01mDeprecationWarning\u001b[39;00m,\n\u001b[1;32m 1594\u001b[0m )\n\u001b[0;32m-> 1595\u001b[0m \u001b[38;5;28;01mreturn\u001b[39;00m \u001b[38;5;28mself\u001b[39m\u001b[38;5;241m.\u001b[39m_get(\n\u001b[1;32m 1596\u001b[0m \u001b[38;5;124m\"\u001b[39m\u001b[38;5;124mbrowse/featured-playlists\u001b[39m\u001b[38;5;124m\"\u001b[39m,\n\u001b[1;32m 1597\u001b[0m locale\u001b[38;5;241m=\u001b[39mlocale,\n\u001b[1;32m 1598\u001b[0m country\u001b[38;5;241m=\u001b[39mcountry,\n\u001b[1;32m 1599\u001b[0m timestamp\u001b[38;5;241m=\u001b[39mtimestamp,\n\u001b[1;32m 1600\u001b[0m limit\u001b[38;5;241m=\u001b[39mlimit,\n\u001b[1;32m 1601\u001b[0m offset\u001b[38;5;241m=\u001b[39moffset,\n\u001b[1;32m 1602\u001b[0m )\n", + "File \u001b[0;32m/opt/anaconda3/lib/python3.13/site-packages/spotipy/client.py:324\u001b[0m, in \u001b[0;36mSpotify._get\u001b[0;34m(self, url, args, payload, **kwargs)\u001b[0m\n\u001b[1;32m 321\u001b[0m \u001b[38;5;28;01mif\u001b[39;00m args:\n\u001b[1;32m 322\u001b[0m kwargs\u001b[38;5;241m.\u001b[39mupdate(args)\n\u001b[0;32m--> 324\u001b[0m \u001b[38;5;28;01mreturn\u001b[39;00m \u001b[38;5;28mself\u001b[39m\u001b[38;5;241m.\u001b[39m_internal_call(\u001b[38;5;124m\"\u001b[39m\u001b[38;5;124mGET\u001b[39m\u001b[38;5;124m\"\u001b[39m, url, payload, kwargs)\n", + "File \u001b[0;32m/opt/anaconda3/lib/python3.13/site-packages/spotipy/client.py:294\u001b[0m, in \u001b[0;36mSpotify._internal_call\u001b[0;34m(self, method, url, payload, params)\u001b[0m\n\u001b[1;32m 289\u001b[0m reason \u001b[38;5;241m=\u001b[39m \u001b[38;5;28;01mNone\u001b[39;00m\n\u001b[1;32m 291\u001b[0m logger\u001b[38;5;241m.\u001b[39merror(\u001b[38;5;124mf\u001b[39m\u001b[38;5;124m\"\u001b[39m\u001b[38;5;124mHTTP Error for \u001b[39m\u001b[38;5;132;01m{\u001b[39;00mmethod\u001b[38;5;132;01m}\u001b[39;00m\u001b[38;5;124m to \u001b[39m\u001b[38;5;132;01m{\u001b[39;00murl\u001b[38;5;132;01m}\u001b[39;00m\u001b[38;5;124m with Params: \u001b[39m\u001b[38;5;124m\"\u001b[39m\n\u001b[1;32m 292\u001b[0m \u001b[38;5;124mf\u001b[39m\u001b[38;5;124m\"\u001b[39m\u001b[38;5;132;01m{\u001b[39;00margs\u001b[38;5;241m.\u001b[39mget(\u001b[38;5;124m'\u001b[39m\u001b[38;5;124mparams\u001b[39m\u001b[38;5;124m'\u001b[39m)\u001b[38;5;132;01m}\u001b[39;00m\u001b[38;5;124m returned \u001b[39m\u001b[38;5;132;01m{\u001b[39;00mresponse\u001b[38;5;241m.\u001b[39mstatus_code\u001b[38;5;132;01m}\u001b[39;00m\u001b[38;5;124m due to \u001b[39m\u001b[38;5;132;01m{\u001b[39;00mmsg\u001b[38;5;132;01m}\u001b[39;00m\u001b[38;5;124m\"\u001b[39m)\n\u001b[0;32m--> 294\u001b[0m \u001b[38;5;28;01mraise\u001b[39;00m SpotifyException(\n\u001b[1;32m 295\u001b[0m response\u001b[38;5;241m.\u001b[39mstatus_code,\n\u001b[1;32m 296\u001b[0m \u001b[38;5;241m-\u001b[39m\u001b[38;5;241m1\u001b[39m,\n\u001b[1;32m 297\u001b[0m \u001b[38;5;124mf\u001b[39m\u001b[38;5;124m\"\u001b[39m\u001b[38;5;132;01m{\u001b[39;00mresponse\u001b[38;5;241m.\u001b[39murl\u001b[38;5;132;01m}\u001b[39;00m\u001b[38;5;124m:\u001b[39m\u001b[38;5;130;01m\\n\u001b[39;00m\u001b[38;5;124m \u001b[39m\u001b[38;5;132;01m{\u001b[39;00mmsg\u001b[38;5;132;01m}\u001b[39;00m\u001b[38;5;124m\"\u001b[39m,\n\u001b[1;32m 298\u001b[0m reason\u001b[38;5;241m=\u001b[39mreason,\n\u001b[1;32m 299\u001b[0m headers\u001b[38;5;241m=\u001b[39mresponse\u001b[38;5;241m.\u001b[39mheaders,\n\u001b[1;32m 300\u001b[0m )\n\u001b[1;32m 301\u001b[0m \u001b[38;5;28;01mexcept\u001b[39;00m requests\u001b[38;5;241m.\u001b[39mexceptions\u001b[38;5;241m.\u001b[39mRetryError \u001b[38;5;28;01mas\u001b[39;00m retry_error:\n\u001b[1;32m 302\u001b[0m request \u001b[38;5;241m=\u001b[39m retry_error\u001b[38;5;241m.\u001b[39mrequest\n", + "\u001b[0;31mSpotifyException\u001b[0m: 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" ] @@ -488,10 +723,22 @@ }, { "cell_type": "code", - "execution_count": null, + "execution_count": 152, "id": "65c5e5c4-f186-42c6-b136-4ef02b0b01ff", "metadata": {}, - "outputs": [], + "outputs": [ + { + "ename": "TypeError", + "evalue": "list indices must be integers or slices, not str", + "output_type": "error", + "traceback": [ + "\u001b[0;31m---------------------------------------------------------------------------\u001b[0m", + "\u001b[0;31mTypeError\u001b[0m Traceback (most recent call last)", + "Cell \u001b[0;32mIn[152], line 4\u001b[0m\n\u001b[1;32m 1\u001b[0m \u001b[38;5;66;03m# List to store unique artist names\u001b[39;00m\n\u001b[1;32m 2\u001b[0m artists_list \u001b[38;5;241m=\u001b[39m []\n\u001b[0;32m----> 4\u001b[0m \u001b[38;5;28;01mfor\u001b[39;00m track_item \u001b[38;5;129;01min\u001b[39;00m tracks[\u001b[38;5;124m'\u001b[39m\u001b[38;5;124mitems\u001b[39m\u001b[38;5;124m'\u001b[39m]:\n\u001b[1;32m 5\u001b[0m track \u001b[38;5;241m=\u001b[39m track_item[\u001b[38;5;124m'\u001b[39m\u001b[38;5;124mtrack\u001b[39m\u001b[38;5;124m'\u001b[39m]\n\u001b[1;32m 6\u001b[0m \u001b[38;5;28;01mfor\u001b[39;00m artist \u001b[38;5;129;01min\u001b[39;00m track[\u001b[38;5;124m'\u001b[39m\u001b[38;5;124martists\u001b[39m\u001b[38;5;124m'\u001b[39m]:\n", + "\u001b[0;31mTypeError\u001b[0m: list indices must be integers or slices, not str" + ] + } + ], "source": [ "# List to store unique artist names\n", "artists_list = []\n", @@ -533,20 +780,107 @@ }, { "cell_type": "code", - "execution_count": null, + "execution_count": 153, "id": "ed92d961-9646-4375-a386-ccc320a958f5", "metadata": {}, - "outputs": [], - "source": [ - "# Your answer here" + "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[0;31m---------------------------------------------------------------------------\u001b[0m", + "\u001b[0;31mHTTPError\u001b[0m Traceback (most recent call last)", + "File \u001b[0;32m/opt/anaconda3/lib/python3.13/site-packages/spotipy/client.py:274\u001b[0m, in \u001b[0;36mSpotify._internal_call\u001b[0;34m(self, method, url, payload, params)\u001b[0m\n\u001b[1;32m 269\u001b[0m response \u001b[38;5;241m=\u001b[39m \u001b[38;5;28mself\u001b[39m\u001b[38;5;241m.\u001b[39m_session\u001b[38;5;241m.\u001b[39mrequest(\n\u001b[1;32m 270\u001b[0m method, url, headers\u001b[38;5;241m=\u001b[39mheaders, proxies\u001b[38;5;241m=\u001b[39m\u001b[38;5;28mself\u001b[39m\u001b[38;5;241m.\u001b[39mproxies,\n\u001b[1;32m 271\u001b[0m timeout\u001b[38;5;241m=\u001b[39m\u001b[38;5;28mself\u001b[39m\u001b[38;5;241m.\u001b[39mrequests_timeout, \u001b[38;5;241m*\u001b[39m\u001b[38;5;241m*\u001b[39margs\n\u001b[1;32m 272\u001b[0m )\n\u001b[0;32m--> 274\u001b[0m response\u001b[38;5;241m.\u001b[39mraise_for_status()\n\u001b[1;32m 275\u001b[0m results \u001b[38;5;241m=\u001b[39m response\u001b[38;5;241m.\u001b[39mjson()\n", + "File \u001b[0;32m/opt/anaconda3/lib/python3.13/site-packages/requests/models.py:1024\u001b[0m, in \u001b[0;36mResponse.raise_for_status\u001b[0;34m(self)\u001b[0m\n\u001b[1;32m 1023\u001b[0m \u001b[38;5;28;01mif\u001b[39;00m http_error_msg:\n\u001b[0;32m-> 1024\u001b[0m \u001b[38;5;28;01mraise\u001b[39;00m HTTPError(http_error_msg, response\u001b[38;5;241m=\u001b[39m\u001b[38;5;28mself\u001b[39m)\n", + "\u001b[0;31mHTTPError\u001b[0m: 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[0;31mSpotifyException\u001b[0m Traceback (most recent call last)", + "Cell \u001b[0;32mIn[153], line 4\u001b[0m\n\u001b[1;32m 1\u001b[0m \u001b[38;5;66;03m# Featured Exploration\u001b[39;00m\n\u001b[1;32m 2\u001b[0m \n\u001b[1;32m 3\u001b[0m \u001b[38;5;66;03m# Fetches a dictionary containing featured playlists\u001b[39;00m\n\u001b[0;32m----> 4\u001b[0m featured_playlists \u001b[38;5;241m=\u001b[39m sp\u001b[38;5;241m.\u001b[39mfeatured_playlists()\n\u001b[1;32m 6\u001b[0m \u001b[38;5;28mprint\u001b[39m(featured_playlists\u001b[38;5;241m.\u001b[39mkeys())\n", + "File \u001b[0;32m/opt/anaconda3/lib/python3.13/site-packages/spotipy/client.py:1595\u001b[0m, in \u001b[0;36mSpotify.featured_playlists\u001b[0;34m(self, locale, country, timestamp, limit, offset)\u001b[0m\n\u001b[1;32m 1569\u001b[0m \u001b[38;5;250m\u001b[39m\u001b[38;5;124;03m\"\"\" Get a list of Spotify featured playlists\u001b[39;00m\n\u001b[1;32m 1570\u001b[0m \n\u001b[1;32m 1571\u001b[0m \u001b[38;5;124;03m Parameters:\u001b[39;00m\n\u001b[0;32m (...)\u001b[0m\n\u001b[1;32m 1588\u001b[0m \u001b[38;5;124;03m items.\u001b[39;00m\n\u001b[1;32m 1589\u001b[0m \u001b[38;5;124;03m\"\"\"\u001b[39;00m\n\u001b[1;32m 1590\u001b[0m warnings\u001b[38;5;241m.\u001b[39mwarn(\n\u001b[1;32m 1591\u001b[0m \u001b[38;5;124m\"\u001b[39m\u001b[38;5;124mYou\u001b[39m\u001b[38;5;124m'\u001b[39m\u001b[38;5;124mre using `featured_playlists(...)`, \u001b[39m\u001b[38;5;124m\"\u001b[39m\n\u001b[1;32m 1592\u001b[0m \u001b[38;5;124m\"\u001b[39m\u001b[38;5;124mwhich is marked as deprecated by Spotify.\u001b[39m\u001b[38;5;124m\"\u001b[39m,\n\u001b[1;32m 1593\u001b[0m \u001b[38;5;167;01mDeprecationWarning\u001b[39;00m,\n\u001b[1;32m 1594\u001b[0m )\n\u001b[0;32m-> 1595\u001b[0m \u001b[38;5;28;01mreturn\u001b[39;00m \u001b[38;5;28mself\u001b[39m\u001b[38;5;241m.\u001b[39m_get(\n\u001b[1;32m 1596\u001b[0m \u001b[38;5;124m\"\u001b[39m\u001b[38;5;124mbrowse/featured-playlists\u001b[39m\u001b[38;5;124m\"\u001b[39m,\n\u001b[1;32m 1597\u001b[0m locale\u001b[38;5;241m=\u001b[39mlocale,\n\u001b[1;32m 1598\u001b[0m country\u001b[38;5;241m=\u001b[39mcountry,\n\u001b[1;32m 1599\u001b[0m timestamp\u001b[38;5;241m=\u001b[39mtimestamp,\n\u001b[1;32m 1600\u001b[0m limit\u001b[38;5;241m=\u001b[39mlimit,\n\u001b[1;32m 1601\u001b[0m offset\u001b[38;5;241m=\u001b[39moffset,\n\u001b[1;32m 1602\u001b[0m )\n", + "File \u001b[0;32m/opt/anaconda3/lib/python3.13/site-packages/spotipy/client.py:324\u001b[0m, in \u001b[0;36mSpotify._get\u001b[0;34m(self, url, args, payload, **kwargs)\u001b[0m\n\u001b[1;32m 321\u001b[0m \u001b[38;5;28;01mif\u001b[39;00m args:\n\u001b[1;32m 322\u001b[0m kwargs\u001b[38;5;241m.\u001b[39mupdate(args)\n\u001b[0;32m--> 324\u001b[0m \u001b[38;5;28;01mreturn\u001b[39;00m \u001b[38;5;28mself\u001b[39m\u001b[38;5;241m.\u001b[39m_internal_call(\u001b[38;5;124m\"\u001b[39m\u001b[38;5;124mGET\u001b[39m\u001b[38;5;124m\"\u001b[39m, url, payload, kwargs)\n", + "File \u001b[0;32m/opt/anaconda3/lib/python3.13/site-packages/spotipy/client.py:294\u001b[0m, in \u001b[0;36mSpotify._internal_call\u001b[0;34m(self, method, url, payload, params)\u001b[0m\n\u001b[1;32m 289\u001b[0m reason \u001b[38;5;241m=\u001b[39m \u001b[38;5;28;01mNone\u001b[39;00m\n\u001b[1;32m 291\u001b[0m logger\u001b[38;5;241m.\u001b[39merror(\u001b[38;5;124mf\u001b[39m\u001b[38;5;124m\"\u001b[39m\u001b[38;5;124mHTTP Error for \u001b[39m\u001b[38;5;132;01m{\u001b[39;00mmethod\u001b[38;5;132;01m}\u001b[39;00m\u001b[38;5;124m to \u001b[39m\u001b[38;5;132;01m{\u001b[39;00murl\u001b[38;5;132;01m}\u001b[39;00m\u001b[38;5;124m with Params: \u001b[39m\u001b[38;5;124m\"\u001b[39m\n\u001b[1;32m 292\u001b[0m \u001b[38;5;124mf\u001b[39m\u001b[38;5;124m\"\u001b[39m\u001b[38;5;132;01m{\u001b[39;00margs\u001b[38;5;241m.\u001b[39mget(\u001b[38;5;124m'\u001b[39m\u001b[38;5;124mparams\u001b[39m\u001b[38;5;124m'\u001b[39m)\u001b[38;5;132;01m}\u001b[39;00m\u001b[38;5;124m returned \u001b[39m\u001b[38;5;132;01m{\u001b[39;00mresponse\u001b[38;5;241m.\u001b[39mstatus_code\u001b[38;5;132;01m}\u001b[39;00m\u001b[38;5;124m due to \u001b[39m\u001b[38;5;132;01m{\u001b[39;00mmsg\u001b[38;5;132;01m}\u001b[39;00m\u001b[38;5;124m\"\u001b[39m)\n\u001b[0;32m--> 294\u001b[0m \u001b[38;5;28;01mraise\u001b[39;00m SpotifyException(\n\u001b[1;32m 295\u001b[0m response\u001b[38;5;241m.\u001b[39mstatus_code,\n\u001b[1;32m 296\u001b[0m \u001b[38;5;241m-\u001b[39m\u001b[38;5;241m1\u001b[39m,\n\u001b[1;32m 297\u001b[0m \u001b[38;5;124mf\u001b[39m\u001b[38;5;124m\"\u001b[39m\u001b[38;5;132;01m{\u001b[39;00mresponse\u001b[38;5;241m.\u001b[39murl\u001b[38;5;132;01m}\u001b[39;00m\u001b[38;5;124m:\u001b[39m\u001b[38;5;130;01m\\n\u001b[39;00m\u001b[38;5;124m \u001b[39m\u001b[38;5;132;01m{\u001b[39;00mmsg\u001b[38;5;132;01m}\u001b[39;00m\u001b[38;5;124m\"\u001b[39m,\n\u001b[1;32m 298\u001b[0m reason\u001b[38;5;241m=\u001b[39mreason,\n\u001b[1;32m 299\u001b[0m headers\u001b[38;5;241m=\u001b[39mresponse\u001b[38;5;241m.\u001b[39mheaders,\n\u001b[1;32m 300\u001b[0m )\n\u001b[1;32m 301\u001b[0m \u001b[38;5;28;01mexcept\u001b[39;00m requests\u001b[38;5;241m.\u001b[39mexceptions\u001b[38;5;241m.\u001b[39mRetryError \u001b[38;5;28;01mas\u001b[39;00m retry_error:\n\u001b[1;32m 302\u001b[0m request \u001b[38;5;241m=\u001b[39m retry_error\u001b[38;5;241m.\u001b[39mrequest\n", + "\u001b[0;31mSpotifyException\u001b[0m: http status: 404, code: -1 - https://api.spotify.com/v1/browse/featured-playlists?limit=20&offset=0:\n Not Found, reason: None" + ] + } + ], + "source": [ + "# Featured Exploration\n", + "\n", + "# Fetches a dictionary containing featured playlists\n", + "featured_playlists = sp.featured_playlists()\n", + "\n", + "print(featured_playlists.keys())" + ] + }, + { + "cell_type": "code", + "execution_count": 154, + "id": "6cdb54dc-5b21-4139-8904-7e3df64e5445", + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Found an empty playlist item... skipping.\n", + "\n", + "Found an empty playlist item... skipping.\n", + "\n", + "Found an empty playlist item... skipping.\n", + "\n", + "Found an empty playlist item... skipping.\n", + "\n", + "Found an empty playlist item... skipping.\n", + "\n" + ] + } + ], + "source": [ + "# Search for playlists with \"Top Hits\" in the title\n", + "playlist_results = sp.search(q=\"Top Hits\", type=\"playlist\", limit=5)\n", + "\n", + "# The playlist data is found under the 'playlists' key\n", + "playlists = playlist_results['playlists']['items']\n", + "\n", + "# Print out the name and ID of each playlist we found\n", + "for p in playlists:\n", + " if p:\n", + " print(f\"Playlist Name: {p['name']}\")\n", + " print(f\"Playlist ID: {p['id']}\\n\")\n", + " else:\n", + " print(\"Found an empty playlist item... skipping.\\n\")" ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "da0865ef-8e06-4785-a30e-36aa1c00b9cd", + "metadata": {}, + "outputs": [], + "source": [] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "a4490f33-289d-4450-bda9-022f237310a9", + "metadata": {}, + "outputs": [], + "source": [] } ], "metadata": { "kernelspec": { - "display_name": "Python 3 (ipykernel)", + "display_name": "Python [conda env:base] *", "language": "python", - "name": "python3" + "name": "conda-base-py" }, "language_info": { "codemirror_mode": { @@ -558,7 +892,7 @@ "name": "python", "nbconvert_exporter": "python", "pygments_lexer": "ipython3", - "version": "3.9.13" + "version": "3.13.5" } }, "nbformat": 4,