diff --git a/.cache b/.cache new file mode 100644 index 0000000..978d1ff --- /dev/null +++ b/.cache @@ -0,0 +1 @@ +{"access_token": "BQBLkrI_DtWbBB-Y_yvCzKZqDFrro73r1UEmQcSJDmbzxDIn-CVAzTVlZBnnE_Viwvxf8Mw0abtUG2-Ar_DX_0_ZYiREupYyPmQntkT_wZ1qh36s1o0050wBr5m3wo8zPPLRzbC4CayXveBNK1b7xXSVA6cWHyV7tiTVHFcGzCkZqR4VyY2xMzkGt601Y4KXFD5t3kaXKDn0UbnCljZ4rLTnkTnEns6_zl-tZw", "token_type": "Bearer", "expires_in": 3600, "refresh_token": "AQCcf3etBqf_21tv8xeX2CbMcYOc7poEEg8gHhUwMp6fwedvDH2qsOP8wOQyHw4gliFB7H81v4QEj_r3e5-_7ywA5Hf4K5QhET3vdUj2MoKkSxZBObPNJwOBQc7dta72h88", "scope": "user-read-recently-played user-top-read", "expires_at": 1762104750} \ No newline at end of file diff --git a/.env b/.env new file mode 100644 index 0000000..0c96372 --- /dev/null +++ b/.env @@ -0,0 +1,3 @@ +SPOTIFY_CLIENT_ID=67ad3c02297a4dfd9a41f462068e8bf5 +SPOTIFY_CLIENT_SECRET=e19beb8eff4d453d986172aeb588e499 +SPOTIFY_REDIRECT_URI=http://127.0.0.1:8080/callback diff --git a/main.py b/main.py new file mode 100644 index 0000000..e69de29 diff --git a/spotify.ipynb b/spotify.ipynb new file mode 100644 index 0000000..98b108f --- /dev/null +++ b/spotify.ipynb @@ -0,0 +1,543 @@ +{ + "cells": [ + { + "cell_type": "code", + "execution_count": 1, + "id": "09cfd095", + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Collecting spotipy\n", + " Downloading spotipy-2.25.1-py3-none-any.whl.metadata (5.1 kB)\n", + "Collecting python-dotenv\n", + " Downloading python_dotenv-1.2.1-py3-none-any.whl.metadata (25 kB)\n", + "Collecting redis>=3.5.3 (from spotipy)\n", + " Downloading redis-7.0.1-py3-none-any.whl.metadata (12 kB)\n", + "Requirement already satisfied: requests>=2.25.0 in c:\\users\\cex-laguna\\appdata\\local\\programs\\python\\python313\\lib\\site-packages (from spotipy) (2.32.5)\n", + "Requirement already satisfied: urllib3>=1.26.0 in c:\\users\\cex-laguna\\appdata\\local\\programs\\python\\python313\\lib\\site-packages (from spotipy) (2.5.0)\n", + "Requirement already satisfied: charset_normalizer<4,>=2 in c:\\users\\cex-laguna\\appdata\\local\\programs\\python\\python313\\lib\\site-packages (from requests>=2.25.0->spotipy) (3.4.3)\n", + "Requirement already satisfied: idna<4,>=2.5 in c:\\users\\cex-laguna\\appdata\\local\\programs\\python\\python313\\lib\\site-packages (from requests>=2.25.0->spotipy) (3.11)\n", + "Requirement already satisfied: certifi>=2017.4.17 in c:\\users\\cex-laguna\\appdata\\local\\programs\\python\\python313\\lib\\site-packages (from requests>=2.25.0->spotipy) (2025.10.5)\n", + "Downloading spotipy-2.25.1-py3-none-any.whl (31 kB)\n", + "Downloading python_dotenv-1.2.1-py3-none-any.whl (21 kB)\n", + "Downloading redis-7.0.1-py3-none-any.whl (339 kB)\n", + "Installing collected packages: redis, python-dotenv, spotipy\n", + "\n", + " ---------------------------------------- 0/3 [redis]\n", + " ---------------------------------------- 0/3 [redis]\n", + " ---------------------------------------- 0/3 [redis]\n", + " ---------------------------------------- 0/3 [redis]\n", + " ---------------------------------------- 0/3 [redis]\n", + " ---------------------------------------- 0/3 [redis]\n", + " ---------------------------------------- 0/3 [redis]\n", + " ---------------------------------------- 0/3 [redis]\n", + " ---------------------------------------- 0/3 [redis]\n", + " ---------------------------------------- 0/3 [redis]\n", + " ---------------------------------------- 0/3 [redis]\n", + " ---------------------------------------- 0/3 [redis]\n", + " ---------------------------------------- 0/3 [redis]\n", + " ---------------------------------------- 0/3 [redis]\n", + " ---------------------------------------- 0/3 [redis]\n", + " ---------------------------------------- 0/3 [redis]\n", + " ---------------------------------------- 0/3 [redis]\n", + " ------------- -------------------------- 1/3 [python-dotenv]\n", + " ------------- -------------------------- 1/3 [python-dotenv]\n", + " -------------------------- ------------- 2/3 [spotipy]\n", + " ---------------------------------------- 3/3 [spotipy]\n", + "\n", + "Successfully installed python-dotenv-1.2.1 redis-7.0.1 spotipy-2.25.1\n", + "Note: you may need to restart the kernel to use updated packages.\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + "\n", + "[notice] A new release of pip is available: 25.2 -> 25.3\n", + "[notice] To update, run: python.exe -m pip install --upgrade pip\n" + ] + } + ], + "source": [ + "pip install spotipy python-dotenv\n" + ] + }, + { + "cell_type": "code", + "execution_count": 2, + "id": "af26030b", + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "'neereafufi9'" + ] + }, + "execution_count": 2, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "import spotipy\n", + "from spotipy.oauth2 import SpotifyOAuth\n", + "from dotenv import load_dotenv\n", + "import os\n", + "\n", + "# Cargar variables del archivo .env\n", + "load_dotenv()\n", + "\n", + "sp = spotipy.Spotify(auth_manager=SpotifyOAuth(\n", + " client_id=os.getenv(\"SPOTIFY_CLIENT_ID\"),\n", + " client_secret=os.getenv(\"SPOTIFY_CLIENT_SECRET\"),\n", + " redirect_uri=os.getenv(\"SPOTIFY_REDIRECT_URI\"),\n", + " scope=\"user-read-recently-played user-top-read\"\n", + "))\n", + "\n", + "user = sp.current_user()\n", + "user[\"display_name\"]\n" + ] + }, + { + "cell_type": "markdown", + "id": "3f41d70b", + "metadata": {}, + "source": [ + "EXPLORAR ARTISTAS FAVORITOS Y DESCUBRIR MÚSICA NUEVA\n", + "1. Pedir artistas favoritos." + ] + }, + { + "cell_type": "code", + "execution_count": 6, + "id": "15ba33a0", + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "['Galvan Real', 'Blake', 'Lola Índigo']" + ] + }, + "execution_count": 6, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "favorite_artists = ['Galvan Real', 'Blake', 'Lola Índigo']\n", + "\n", + "favorite_artists" + ] + }, + { + "cell_type": "markdown", + "id": "6efd8a73", + "metadata": {}, + "source": [ + "2. Buscar esos artistas en Spotify y obtener sus IDs" + ] + }, + { + "cell_type": "code", + "execution_count": 7, + "id": "f72cde94", + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "{'Galvan Real': '2iA56rE7fZUnD4GdsSUj3G',\n", + " 'Blake': '2FwMmxiCWQhEyO9k0nOyNF',\n", + " 'Lola Índigo': '3bvfu2KAve4lPHrhEFDZna'}" + ] + }, + "execution_count": 7, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "artist_ids = {}\n", + "\n", + "for artist in favorite_artists:\n", + " result = sp.search(q=artist, type=\"artist\", limit=1)\n", + " if result[\"artists\"][\"items\"]:\n", + " artist_id = result[\"artists\"][\"items\"][0][\"id\"]\n", + " artist_ids[artist] = artist_id\n", + "\n", + "artist_ids\n" + ] + }, + { + "cell_type": "markdown", + "id": "5021ad4e", + "metadata": {}, + "source": [ + "3. Obtener top 5 canciones de cada artista." + ] + }, + { + "cell_type": "code", + "execution_count": 8, + "id": "8960b44b", + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "{'Galvan Real': ['La Magia',\n", + " 'La Luna',\n", + " 'Amigos',\n", + " 'Volverte A Ver',\n", + " 'Deseo - Remix'],\n", + " 'Blake': ['Lengua de Serpiente',\n", + " 'El Diario del Loco',\n", + " 'Me Tiene Mal',\n", + " 'Ideales',\n", + " 'En Bucle'],\n", + " 'Lola Índigo': ['MOJA1TA',\n", + " 'EL TONTO',\n", + " 'LA REINA',\n", + " '1000COSAS',\n", + " 'La Niña de la Escuela']}" + ] + }, + "execution_count": 8, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "top_tracks = {}\n", + "\n", + "for artist, artist_id in artist_ids.items():\n", + " results = sp.artist_top_tracks(artist_id)\n", + " tracks = [track[\"name\"] for track in results[\"tracks\"][:5]]\n", + " top_tracks[artist] = tracks\n", + "\n", + "top_tracks\n" + ] + }, + { + "cell_type": "code", + "execution_count": 13, + "id": "29f0a512", + "metadata": {}, + "outputs": [ + { + "name": "stderr", + "output_type": "stream", + "text": [ + "HTTP Error for GET to https://api.spotify.com/v1/artists/2iA56rE7fZUnD4GdsSUj3G/related-artists with Params: {} returned 404 due to Not Found\n", + "HTTP Error for GET to https://api.spotify.com/v1/artists/2FwMmxiCWQhEyO9k0nOyNF/related-artists with Params: {} returned 404 due to Not Found\n" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + "⚠ Error con Galvan Real: http status: 404, code: -1 - https://api.spotify.com/v1/artists/2iA56rE7fZUnD4GdsSUj3G/related-artists:\n", + " Not Found, reason: None\n", + "⚠ Error con Blake: http status: 404, code: -1 - https://api.spotify.com/v1/artists/2FwMmxiCWQhEyO9k0nOyNF/related-artists:\n", + " Not Found, reason: None\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + "HTTP Error for GET to https://api.spotify.com/v1/artists/3bvfu2KAve4lPHrhEFDZna/related-artists with Params: {} returned 404 due to Not Found\n" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + "⚠ Error con Lola Indigo: http status: 404, code: -1 - https://api.spotify.com/v1/artists/3bvfu2KAve4lPHrhEFDZna/related-artists:\n", + " Not Found, reason: None\n" + ] + }, + { + "data": { + "text/plain": [ + "{'Galvan Real': [], 'Blake': [], 'Lola Indigo': []}" + ] + }, + "execution_count": 13, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "artist_ids = {\n", + " \"Galvan Real\": \"2iA56rE7fZUnD4GdsSUj3G\",\n", + " \"Blake\": '2FwMmxiCWQhEyO9k0nOyNF',\n", + " \"Lola Indigo\": '3bvfu2KAve4lPHrhEFDZna'\n", + "}\n", + "\n", + "similar_artists = {}\n", + "\n", + "for artist, artist_id in artist_ids.items():\n", + " try:\n", + " results = sp.artist_related_artists(artist_id)\n", + " if results[\"artists\"]:\n", + " related = [a[\"name\"] for a in results[\"artists\"][:5]]\n", + " similar_artists[artist] = related\n", + " else:\n", + " similar_artists[artist] = []\n", + " print(f\"⚠ No hay artistas relacionados para {artist}\")\n", + " except Exception as e:\n", + " similar_artists[artist] = []\n", + " print(f\"⚠ Error con {artist}: {e}\")\n", + "\n", + "similar_artists\n" + ] + }, + { + "cell_type": "markdown", + "id": "fb8ba3f3", + "metadata": {}, + "source": [ + "4. Encontrar artistas similares (recomendaciones)" + ] + }, + { + "cell_type": "code", + "execution_count": 11, + "id": "5cd3304e", + "metadata": {}, + "outputs": [ + { + "name": "stderr", + "output_type": "stream", + "text": [ + "HTTP Error for GET to https://api.spotify.com/v1/artists/2iA56rE7fZUnD4GdsSUj3G/related-artists with Params: {} returned 404 due to Not Found\n" + ] + }, + { + "ename": "SpotifyException", + "evalue": "http status: 404, code: -1 - https://api.spotify.com/v1/artists/2iA56rE7fZUnD4GdsSUj3G/related-artists:\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[32mc:\\Users\\CeX-Laguna\\AppData\\Local\\Programs\\Python\\Python313\\Lib\\site-packages\\spotipy\\client.py:274\u001b[39m, in \u001b[36mSpotify._internal_call\u001b[39m\u001b[34m(self, method, url, payload, params)\u001b[39m\n\u001b[32m 269\u001b[39m response = \u001b[38;5;28mself\u001b[39m._session.request(\n\u001b[32m 270\u001b[39m method, url, headers=headers, proxies=\u001b[38;5;28mself\u001b[39m.proxies,\n\u001b[32m 271\u001b[39m timeout=\u001b[38;5;28mself\u001b[39m.requests_timeout, **args\n\u001b[32m 272\u001b[39m )\n\u001b[32m--> \u001b[39m\u001b[32m274\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 275\u001b[39m results = response.json()\n", + "\u001b[36mFile \u001b[39m\u001b[32mc:\\Users\\CeX-Laguna\\AppData\\Local\\Programs\\Python\\Python313\\Lib\\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/artists/2iA56rE7fZUnD4GdsSUj3G/related-artists", + "\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[11]\u001b[39m\u001b[32m, line 4\u001b[39m\n\u001b[32m 1\u001b[39m similar_artists = {}\n\u001b[32m 3\u001b[39m \u001b[38;5;28;01mfor\u001b[39;00m artist, artist_id \u001b[38;5;129;01min\u001b[39;00m artist_ids.items():\n\u001b[32m----> \u001b[39m\u001b[32m4\u001b[39m results = \u001b[43msp\u001b[49m\u001b[43m.\u001b[49m\u001b[43martist_related_artists\u001b[49m\u001b[43m(\u001b[49m\u001b[43martist_id\u001b[49m\u001b[43m)\u001b[49m\n\u001b[32m 5\u001b[39m related = [a[\u001b[33m\"\u001b[39m\u001b[33mname\u001b[39m\u001b[33m\"\u001b[39m] \u001b[38;5;28;01mfor\u001b[39;00m a \u001b[38;5;129;01min\u001b[39;00m results[\u001b[33m\"\u001b[39m\u001b[33martists\u001b[39m\u001b[33m\"\u001b[39m][:\u001b[32m5\u001b[39m]]\n\u001b[32m 6\u001b[39m similar_artists[artist] = related\n", + "\u001b[36mFile \u001b[39m\u001b[32mc:\\Users\\CeX-Laguna\\AppData\\Local\\Programs\\Python\\Python313\\Lib\\site-packages\\spotipy\\client.py:464\u001b[39m, in \u001b[36mSpotify.artist_related_artists\u001b[39m\u001b[34m(self, artist_id)\u001b[39m\n\u001b[32m 458\u001b[39m warnings.warn(\n\u001b[32m 459\u001b[39m \u001b[33m\"\u001b[39m\u001b[33mYou\u001b[39m\u001b[33m'\u001b[39m\u001b[33mre using `artist_related_artists(...)`, \u001b[39m\u001b[33m\"\u001b[39m\n\u001b[32m 460\u001b[39m \u001b[33m\"\u001b[39m\u001b[33mwhich is marked as deprecated by Spotify.\u001b[39m\u001b[33m\"\u001b[39m,\n\u001b[32m 461\u001b[39m \u001b[38;5;167;01mDeprecationWarning\u001b[39;00m\n\u001b[32m 462\u001b[39m )\n\u001b[32m 463\u001b[39m trid = \u001b[38;5;28mself\u001b[39m._get_id(\u001b[33m\"\u001b[39m\u001b[33martist\u001b[39m\u001b[33m\"\u001b[39m, artist_id)\n\u001b[32m--> \u001b[39m\u001b[32m464\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\u001b[33;43m\"\u001b[39;49m\u001b[33;43martists/\u001b[39;49m\u001b[33;43m\"\u001b[39;49m\u001b[43m \u001b[49m\u001b[43m+\u001b[49m\u001b[43m \u001b[49m\u001b[43mtrid\u001b[49m\u001b[43m \u001b[49m\u001b[43m+\u001b[49m\u001b[43m \u001b[49m\u001b[33;43m\"\u001b[39;49m\u001b[33;43m/related-artists\u001b[39;49m\u001b[33;43m\"\u001b[39;49m\u001b[43m)\u001b[49m\n", + "\u001b[36mFile \u001b[39m\u001b[32mc:\\Users\\CeX-Laguna\\AppData\\Local\\Programs\\Python\\Python313\\Lib\\site-packages\\spotipy\\client.py:324\u001b[39m, in \u001b[36mSpotify._get\u001b[39m\u001b[34m(self, url, args, payload, **kwargs)\u001b[39m\n\u001b[32m 321\u001b[39m \u001b[38;5;28;01mif\u001b[39;00m args:\n\u001b[32m 322\u001b[39m kwargs.update(args)\n\u001b[32m--> \u001b[39m\u001b[32m324\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[32mc:\\Users\\CeX-Laguna\\AppData\\Local\\Programs\\Python\\Python313\\Lib\\site-packages\\spotipy\\client.py:294\u001b[39m, in \u001b[36mSpotify._internal_call\u001b[39m\u001b[34m(self, method, url, payload, params)\u001b[39m\n\u001b[32m 289\u001b[39m reason = \u001b[38;5;28;01mNone\u001b[39;00m\n\u001b[32m 291\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 292\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[32m294\u001b[39m \u001b[38;5;28;01mraise\u001b[39;00m SpotifyException(\n\u001b[32m 295\u001b[39m response.status_code,\n\u001b[32m 296\u001b[39m -\u001b[32m1\u001b[39m,\n\u001b[32m 297\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 298\u001b[39m reason=reason,\n\u001b[32m 299\u001b[39m headers=response.headers,\n\u001b[32m 300\u001b[39m )\n\u001b[32m 301\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 302\u001b[39m request = retry_error.request\n", + "\u001b[31mSpotifyException\u001b[39m: http status: 404, code: -1 - https://api.spotify.com/v1/artists/2iA56rE7fZUnD4GdsSUj3G/related-artists:\n Not Found, reason: None" + ] + } + ], + "source": [ + "similar_artists = {}\n", + "\n", + "for artist, artist_id in artist_ids.items():\n", + " results = sp.artist_related_artists(artist_id)\n", + " related = [a[\"name\"] for a in results[\"artists\"][:5]]\n", + " similar_artists[artist] = related\n", + "\n", + "similar_artists\n" + ] + }, + { + "cell_type": "markdown", + "id": "fab72cfe", + "metadata": {}, + "source": [ + "Prepara la lista de URIs para la playlist." + ] + }, + { + "cell_type": "code", + "execution_count": 15, + "id": "c18f2835", + "metadata": {}, + "outputs": [], + "source": [ + "track_uris = []\n", + "\n", + "for artist, tracks in top_tracks.items():\n", + " for track_name in tracks:\n", + " result = sp.search(q=f\"{track_name} {artist}\", type=\"track\", limit=1)\n", + " items = result['tracks']['items']\n", + " if items:\n", + " track_uris.append(items[0]['uri'])\n" + ] + }, + { + "cell_type": "markdown", + "id": "55833ab7", + "metadata": {}, + "source": [ + "Crear una lista de canciones recomendadas para la playlist." + ] + }, + { + "cell_type": "code", + "execution_count": 18, + "id": "bf2feacf", + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "['spotify:track:1uw6eHdMtRlX6MtiZVJYB9',\n", + " 'spotify:track:06Ke9F6uDCPCRlryHzBegD',\n", + " 'spotify:track:1btXIMqhheMHFTSYRfYd7j',\n", + " 'spotify:track:0UO81pdmWKfhFi8F1VJfCl',\n", + " 'spotify:track:63rH77IJhmuQsNIxpCxaJ5',\n", + " 'spotify:track:4rKQ8daoK0aklVptea8A9E']" + ] + }, + "execution_count": 18, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "recommendation_tracks = []\n", + "\n", + "for artist, artist_id in artist_ids.items():\n", + " results = sp.artist_top_tracks(artist_id)\n", + " for track in results[\"tracks\"][:2]:\n", + " recommendation_tracks.append(track[\"uri\"])\n", + "\n", + "recommendation_tracks\n" + ] + }, + { + "cell_type": "markdown", + "id": "70c68f58", + "metadata": {}, + "source": [ + "EXPLORAR PLAYLIST DESTACADAS\n", + "Obtener playlists destacadas de Spotify." + ] + }, + { + "cell_type": "code", + "execution_count": 19, + "id": "26240335", + "metadata": {}, + "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': 5, '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=5&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[32mc:\\Users\\CeX-Laguna\\AppData\\Local\\Programs\\Python\\Python313\\Lib\\site-packages\\spotipy\\client.py:274\u001b[39m, in \u001b[36mSpotify._internal_call\u001b[39m\u001b[34m(self, method, url, payload, params)\u001b[39m\n\u001b[32m 269\u001b[39m response = \u001b[38;5;28mself\u001b[39m._session.request(\n\u001b[32m 270\u001b[39m method, url, headers=headers, proxies=\u001b[38;5;28mself\u001b[39m.proxies,\n\u001b[32m 271\u001b[39m timeout=\u001b[38;5;28mself\u001b[39m.requests_timeout, **args\n\u001b[32m 272\u001b[39m )\n\u001b[32m--> \u001b[39m\u001b[32m274\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 275\u001b[39m results = response.json()\n", + "\u001b[36mFile \u001b[39m\u001b[32mc:\\Users\\CeX-Laguna\\AppData\\Local\\Programs\\Python\\Python313\\Lib\\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=5&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[19]\u001b[39m\u001b[32m, line 1\u001b[39m\n\u001b[32m----> \u001b[39m\u001b[32m1\u001b[39m featured = \u001b[43msp\u001b[49m\u001b[43m.\u001b[49m\u001b[43mfeatured_playlists\u001b[49m\u001b[43m(\u001b[49m\u001b[43mlimit\u001b[49m\u001b[43m=\u001b[49m\u001b[32;43m5\u001b[39;49m\u001b[43m)\u001b[49m\n\u001b[32m 2\u001b[39m featured_list = [(item[\u001b[33m\"\u001b[39m\u001b[33mname\u001b[39m\u001b[33m\"\u001b[39m], item[\u001b[33m\"\u001b[39m\u001b[33mid\u001b[39m\u001b[33m\"\u001b[39m]) \u001b[38;5;28;01mfor\u001b[39;00m item \u001b[38;5;129;01min\u001b[39;00m featured[\u001b[33m\"\u001b[39m\u001b[33mplaylists\u001b[39m\u001b[33m\"\u001b[39m][\u001b[33m\"\u001b[39m\u001b[33mitems\u001b[39m\u001b[33m\"\u001b[39m]]\n\u001b[32m 4\u001b[39m featured_list\n", + "\u001b[36mFile \u001b[39m\u001b[32mc:\\Users\\CeX-Laguna\\AppData\\Local\\Programs\\Python\\Python313\\Lib\\site-packages\\spotipy\\client.py:1595\u001b[39m, in \u001b[36mSpotify.featured_playlists\u001b[39m\u001b[34m(self, locale, country, timestamp, limit, offset)\u001b[39m\n\u001b[32m 1569\u001b[39m \u001b[38;5;250m\u001b[39m\u001b[33;03m\"\"\" Get a list of Spotify featured playlists\u001b[39;00m\n\u001b[32m 1570\u001b[39m \n\u001b[32m 1571\u001b[39m \u001b[33;03m Parameters:\u001b[39;00m\n\u001b[32m (...)\u001b[39m\u001b[32m 1588\u001b[39m \u001b[33;03m items.\u001b[39;00m\n\u001b[32m 1589\u001b[39m \u001b[33;03m\"\"\"\u001b[39;00m\n\u001b[32m 1590\u001b[39m warnings.warn(\n\u001b[32m 1591\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 1592\u001b[39m \u001b[33m\"\u001b[39m\u001b[33mwhich is marked as deprecated by Spotify.\u001b[39m\u001b[33m\"\u001b[39m,\n\u001b[32m 1593\u001b[39m \u001b[38;5;167;01mDeprecationWarning\u001b[39;00m,\n\u001b[32m 1594\u001b[39m )\n\u001b[32m-> \u001b[39m\u001b[32m1595\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 1596\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 1597\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 1598\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 1599\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 1600\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 1601\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 1602\u001b[39m \u001b[43m\u001b[49m\u001b[43m)\u001b[49m\n", + "\u001b[36mFile \u001b[39m\u001b[32mc:\\Users\\CeX-Laguna\\AppData\\Local\\Programs\\Python\\Python313\\Lib\\site-packages\\spotipy\\client.py:324\u001b[39m, in \u001b[36mSpotify._get\u001b[39m\u001b[34m(self, url, args, payload, **kwargs)\u001b[39m\n\u001b[32m 321\u001b[39m \u001b[38;5;28;01mif\u001b[39;00m args:\n\u001b[32m 322\u001b[39m kwargs.update(args)\n\u001b[32m--> \u001b[39m\u001b[32m324\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[32mc:\\Users\\CeX-Laguna\\AppData\\Local\\Programs\\Python\\Python313\\Lib\\site-packages\\spotipy\\client.py:294\u001b[39m, in \u001b[36mSpotify._internal_call\u001b[39m\u001b[34m(self, method, url, payload, params)\u001b[39m\n\u001b[32m 289\u001b[39m reason = \u001b[38;5;28;01mNone\u001b[39;00m\n\u001b[32m 291\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 292\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[32m294\u001b[39m \u001b[38;5;28;01mraise\u001b[39;00m SpotifyException(\n\u001b[32m 295\u001b[39m response.status_code,\n\u001b[32m 296\u001b[39m -\u001b[32m1\u001b[39m,\n\u001b[32m 297\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 298\u001b[39m reason=reason,\n\u001b[32m 299\u001b[39m headers=response.headers,\n\u001b[32m 300\u001b[39m )\n\u001b[32m 301\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 302\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=5&offset=0:\n Not Found, reason: None" + ] + } + ], + "source": [ + "featured = sp.featured_playlists(limit=5)\n", + "featured_list = [(item[\"name\"], item[\"id\"]) for item in featured[\"playlists\"][\"items\"]]\n", + "\n", + "featured_list\n" + ] + }, + { + "cell_type": "markdown", + "id": "62ad5101", + "metadata": {}, + "source": [ + "Elegir una playlist y ver sus canciones." + ] + }, + { + "cell_type": "code", + "execution_count": 20, + "id": "64d3a97c", + "metadata": {}, + "outputs": [ + { + "ename": "NameError", + "evalue": "name 'featured_list' is not defined", + "output_type": "error", + "traceback": [ + "\u001b[31m---------------------------------------------------------------------------\u001b[39m", + "\u001b[31mNameError\u001b[39m Traceback (most recent call last)", + "\u001b[36mCell\u001b[39m\u001b[36m \u001b[39m\u001b[32mIn[20]\u001b[39m\u001b[32m, line 1\u001b[39m\n\u001b[32m----> \u001b[39m\u001b[32m1\u001b[39m playlist_id = \u001b[43mfeatured_list\u001b[49m[\u001b[32m0\u001b[39m][\u001b[32m1\u001b[39m] \u001b[38;5;66;03m# Primera playlist destacada\u001b[39;00m\n\u001b[32m 3\u001b[39m playlist_tracks = sp.playlist_tracks(playlist_id)\n\u001b[32m 5\u001b[39m songs = [(t[\u001b[33m\"\u001b[39m\u001b[33mtrack\u001b[39m\u001b[33m\"\u001b[39m][\u001b[33m\"\u001b[39m\u001b[33mname\u001b[39m\u001b[33m\"\u001b[39m], t[\u001b[33m\"\u001b[39m\u001b[33mtrack\u001b[39m\u001b[33m\"\u001b[39m][\u001b[33m\"\u001b[39m\u001b[33martists\u001b[39m\u001b[33m\"\u001b[39m][\u001b[32m0\u001b[39m][\u001b[33m\"\u001b[39m\u001b[33mname\u001b[39m\u001b[33m\"\u001b[39m]) \n\u001b[32m 6\u001b[39m \u001b[38;5;28;01mfor\u001b[39;00m t \u001b[38;5;129;01min\u001b[39;00m playlist_tracks[\u001b[33m\"\u001b[39m\u001b[33mitems\u001b[39m\u001b[33m\"\u001b[39m]]\n", + "\u001b[31mNameError\u001b[39m: name 'featured_list' is not defined" + ] + } + ], + "source": [ + "playlist_id = featured_list[0][1] # Primera playlist destacada\n", + "\n", + "playlist_tracks = sp.playlist_tracks(playlist_id)\n", + "\n", + "songs = [(t[\"track\"][\"name\"], t[\"track\"][\"artists\"][0][\"name\"]) \n", + " for t in playlist_tracks[\"items\"]]\n", + "\n", + "songs[:10] # ver primeros 10\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "06dbbc29", + "metadata": {}, + "outputs": [], + "source": [ + "user_id = sp.current_user()[\"id\"]\n", + "\n", + "playlist = sp.user_playlist_create(user=user_id, name=\"Mi Playlist Descubierta\", public=False)\n", + "sp.playlist_add_items(playlist[\"id\"], recommendation_tracks)\n", + "\n", + "print(\"✅ Playlist creada con tus descubrimientos!\")\n" + ] + } + ], + "metadata": { + "kernelspec": { + "display_name": "Python 3", + "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.13.7" + } + }, + "nbformat": 4, + "nbformat_minor": 5 +}