A Spotify lebányászásának ötlete az Adatkezelés és -vizualizáció R nyelven / történelmi projektmunka címet viselő órámon merült fel. Az egyik hallgatóm ugyanis a magyarországi diszkók és lemezlovasok társadalomtörténetét kutatja, így ehhez a témához kapcsolódva kellett egy olyan feladatot találni, ami R nyelven megvalósítható. Mivel már régebb óta tudtam erről a lehetőségről, de még sohasem próbáltam ki a gyakorlatban, ezért egy jó lehetőségnek éreztem mindezt arra, hogy én is tanuljak valami újat. Vágjunk is bele!

A Spotify API és a spotifyr csomag beüzemelése

Az API az angol Application Programming Interface rövidítése, ami lényegében egy szabványosított felületet kínál ahhoz, hogy kívülről, programozott módon hozzáférhessünk egy rendszer bizonyos szolgáltatásaihoz. Szerencsére a Spotify rendelkezik ilyen API-val, így erről az oldalról nincs akadálya a minket érdeklő metaadatok lekérdezésének. A Spotify API-val való R nyelvű kapcsolatot pedig a spotifyr nevű csomag biztosítja majd.

Az API beüzemelésének lépései a következők:

  1. Először – ha még nem rendelkezünk vele – regisztrálni kell egy Spotify felhasználói fiókot. Ez lehet ingyenes is, az API használatához nem kell előfizetés.

  2. Ezt követően a Spotify for Developers oldalon be kell jelentkeznünk a felhasználói adatainkkal.

  3. A Dashboard felületre jutva a CREATE AN APP feliratú gombra kell kattintani. Egy rövid párbeszédablakot kapunk, amit értelemszerűen kitöltünk és megnyomjuk a CREATE gombot.

  4. Ekkor a létrehozott app vezérlőpultjára jutunk, amelynek bal felső részén találjuk meg a számunkra szükséges adatokat: a Client ID-t és – a SHOW CLIENT SECRET linkre való kattintás után – a Client Secret-et. Ez két alfanumerikus karakterlánc. Ne zárjuk be az ablakot, mert szükségünk lesz ezekre! (És természetesen tartsuk titokban őket!)

A fentieket csak egyszer, a legelső használat előtt kell megtenni. Ha ezzel megvagyunk, akkor indítsuk el az RStudio-t és kövessük a további utasításokat.

Az alábbiakban R nyelven (v4.1.2) írt kódot használok a feladat végrehajtásához. A magyarázó szövegek közé ékelt fekete kódblokkok tartalmát az RStudio-ban egymás alá illesztve elvileg bárki által reprodukálható az itt bemutatott műveletsor. A kódblokkok # kezdetű sorai pusztán magyarázó funkcióval bírnak, ezekre a program futtatásakor nincs szükség.

Magát a spotifyr csomagot is elő kell készíteni a használatra. Természetesen – mint minden R csomag esetében – be kell töltenünk azt. Emellett, ugyancsak az aktuális munkamenet első futtatásakor, két környezeti változót is szükséges definiálnunk. Ezek a Spotify API-hoz tartozó Client ID-t és Client Secret-et fogják tartalmazni. Ha ezt nem tesszük meg, akkor a spotifyr csomag függvényei nem tudják lekérdezni a Spotify-ból az adatokat.

Az alábbi kódrészletben a Client ID-t és a Client Secret-et x karakterekkel helyettesítettem. Ide mindenkinek a korábban megszerzett saját azonosítóit kell bemásolnia. Érdemes mindezt egy szkript fájlban elmenteni, hogy ne kelljen minden alkalommal újra beírogatni.

1
2
3
4
5
6
7
# A szükséges csomag betöltése.
# Ezt legelső használat előtt az install.packages("spotifyr") utasítással telepíteni kell.
library(spotifyr)

# Környezeti változók létrehozása a Spotify API-hoz.
Sys.setenv(SPOTIFY_CLIENT_ID = "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx")
Sys.setenv(SPOTIFY_CLIENT_SECRET = "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx")

A spotifyr csomag függvényei

A spotifyr csomag számos függvényt tartalmaz, többek között olyanokat is, amelyekkel a saját felhasználói tartalmainkat tudjuk lekérdezni és manipulálni. Én azonban most csak azokkal a függvényekkel kívánok foglalkozni, amelyekkel a konkrét felhasználói profiltól függetlenül, általában véve is hozzá tudunk férni az előadók, albumok és dalok metaadataihoz.

Az előadók, albumok, dalok pontos beazonosítása nem a nevükkel történik, hanem egy egyedi ID-vel. Ehhez a Spotify felhasználói felületén úgy tudunk hozzájutni, hogy a kérdéses elem nevére jobb gombbal kattintva a Megosztás ➽ Hivatkozás másolása előadóhoz / Album hivatkozásának másolása / Dal hivatkozásának másolása opciók egyikét választjuk.

Ekkor az alábbi URL-eket kapjuk, például:

  • https://open.spotify.com/artist/7oPftvlwr6VrsViSDV7fJY?si=fcf5326dc7f64653

  • https://open.spotify.com/album/4uG8q3GPuWHQlRbswMIRS6?si=2B7LihHVSOWP25Ocl-aEqw

  • https://open.spotify.com/track/6L89mwZXSOwYl76YXfX13s?si=5df860e3dc2d432c

Ezekből a szürkével kijelölt – az utolsó perjel és a kérdőjel közötti – karakterláncokra van szükségünk, amelyek az előadók, albumok és dalok egyedi ID-jei. Rakjuk be ezeket egy-egy változóba, hogy később hivatkozni tudjunk rájuk.

1
2
3
eloadoID = "7oPftvlwr6VrsViSDV7fJY"
albumID = "4uG8q3GPuWHQlRbswMIRS6"
dalID = "6L89mwZXSOwYl76YXfX13s"

Az alábbiakban ismertetett függvényekben a következő paraméterek fordulhatnak elő:

Paraméter Magyarázat
id Kötelező paraméter. Az előadó / album / dal egyedi ID-je. Lásd fentebb. Ahol több ID is megadható, ott egy vektorrá összefűzve kell ezt megtenni.
limit Bizonyos függvények alapértelmezetten csak 20 találatot jelenítenek meg egyszerre. Ez a limit sokszor elegendő, de nem mindig. Itt maximum 50-re növelhetjük a kívánt mennyiséget.
offset Ezzel a paraméterrel azt adhatjuk meg, hogy az adott függvény hányadik elemtől kezdje el kilistázni a limit szerinti mennyiséget. A találatok számozása 0-val kezdődik, vagyis az 50. elem a 49-es sorszámot viseli. Ha például az offset = 50 és a limit = 50 paramétereket egyszerre használjuk, akkor az 51-100. találatokat fogjuk megkapni. Ezzel tehát több részletben, de akárhányszor 50 elemhez hozzájuthatunk.

A bemutatott függvényekkel adatkeretekben kapjuk vissza a találatokat, amelyeket egy korábbi posztomban részletesen leírt módon tudunk tovább manipulálni.

Az adatkeretünknek mindig annyi sora lesz, ahány találatot eredményez az adott függvény futtatása. Az oszlopok száma a bemutatott példák esetében 11 és 29 között van. A könnyebb áttekinthetőség kedvéért ezek nevét alább, a függvények bemutatása során kilistázom.

Az oszlopok tartalmát az elnevezésük alapján, illetve az eredményül kapott táblázatokat szemrevételezve az esetek döntő többségében nem nehéz beazonosítani. Egyébként barátunk a Google!

Előadókkal kapcsolatos függvények

A get_artists(id) függvénnyel adatokat kapunk az ID-vel azonosított előadóról vagy előadókról. Maximum 50 ID-t adhatunk meg egyszerre.

1
2
#Az eredményül kapott adatkeret oszlopainak kilistázása.
colnames(get_artists(eloadoID))
##  [1] "genres"                "href"                  "id"                   
##  [4] "images"                "name"                  "popularity"           
##  [7] "type"                  "uri"                   "external_urls.spotify"
## [10] "followers.href"        "followers.total"

A get_related_artists(id) függvénnyel a megadott előadóhoz hasonló 20 másik előadót kapunk vissza. Az eredmény mennyisége nem változtatható meg. A hasonlóság a Spotify közösség hallgatási előzményei alapján kerül megállapításra.

1
2
#Az eredményül kapott adatkeret oszlopainak kilistázása.
colnames(get_related_artists(eloadoID))
##  [1] "genres"                "href"                  "id"                   
##  [4] "images"                "name"                  "popularity"           
##  [7] "type"                  "uri"                   "external_urls.spotify"
## [10] "followers.href"        "followers.total"

A get_artist_top_track(id) függvénnyel egy adott előadó 10 legnépszerűbb dalát kaphatjuk meg. Az eredmény mennyisége nem változtatható meg.

1
2
#Az eredményül kapott adatkeret oszlopainak kilistázása.
colnames(get_artist_top_tracks(eloadoID))
##  [1] "artists"                      "disc_number"                 
##  [3] "duration_ms"                  "explicit"                    
##  [5] "href"                         "id"                          
##  [7] "is_local"                     "is_playable"                 
##  [9] "name"                         "popularity"                  
## [11] "preview_url"                  "track_number"                
## [13] "type"                         "uri"                         
## [15] "album.album_type"             "album.artists"               
## [17] "album.href"                   "album.id"                    
## [19] "album.images"                 "album.is_playable"           
## [21] "album.name"                   "album.release_date"          
## [23] "album.release_date_precision" "album.total_tracks"          
## [25] "album.type"                   "album.uri"                   
## [27] "album.external_urls.spotify"  "external_ids.isrc"           
## [29] "external_urls.spotify"

A get_artist_albums(id, limit, offset) függvénnyel az előadó albumait tudjuk kilistázni. Alapértelmezetten 20 albumot, de ez a limit és offset paraméterekkel megváltoztatható. Lásd fentebb.

1
2
#Az eredményül kapott adatkeret oszlopainak kilistázása.
colnames(get_artist_albums(eloadoID))
##  [1] "album_group"            "album_type"             "artists"               
##  [4] "available_markets"      "href"                   "id"                    
##  [7] "images"                 "name"                   "release_date"          
## [10] "release_date_precision" "total_tracks"           "type"                  
## [13] "uri"                    "external_urls.spotify"

Albumokkal kapcsolatos függvények

A get_albums(id) függvénnyel adatokat kapunk az ID-vel azonosított albumról vagy albumokról. Maximum 20 ID-t adhatunk meg egyszerre.

1
2
#Az eredményül kapott adatkeret oszlopainak kilistázása.
colnames(get_albums(albumID))
##  [1] "album_type"             "artists"                "available_markets"     
##  [4] "copyrights"             "genres"                 "href"                  
##  [7] "id"                     "images"                 "label"                 
## [10] "name"                   "popularity"             "release_date"          
## [13] "release_date_precision" "total_tracks"           "type"                  
## [16] "uri"                    "external_ids.upc"       "external_urls.spotify" 
## [19] "tracks.href"            "tracks.items"           "tracks.limit"          
## [22] "tracks.next"            "tracks.offset"          "tracks.previous"       
## [25] "tracks.total"

A get_album_tracks(id, limit, offset) függvénnyel egy adott albumon lévő dalokról kapunk adatokat. Alapértelmezetten 20 dalról, de ez a limit és offset paraméterekkel megváltoztatható. Lásd fentebb.

1
2
#Az eredményül kapott adatkeret oszlopainak kilistázása.
colnames(get_album_tracks(albumID))
##  [1] "artists"               "available_markets"     "disc_number"          
##  [4] "duration_ms"           "explicit"              "href"                 
##  [7] "id"                    "is_local"              "name"                 
## [10] "preview_url"           "track_number"          "type"                 
## [13] "uri"                   "external_urls.spotify"

Dalokkal kapcsolatos függvények

A get_tracks(id) függvénnyel adatokat kapunk az ID-vel azonosított dalról vagy dalokról. (Arról nem találtam információt, hogy itt mennyi ID-t lehet egyszerre megadni.)

1
2
#Az eredményül kapott adatkeret oszlopainak kilistázása.
colnames(get_tracks(dalID))
##  [1] "artists"                      "available_markets"           
##  [3] "disc_number"                  "duration_ms"                 
##  [5] "explicit"                     "href"                        
##  [7] "id"                           "is_local"                    
##  [9] "name"                         "popularity"                  
## [11] "preview_url"                  "track_number"                
## [13] "type"                         "uri"                         
## [15] "album.album_type"             "album.artists"               
## [17] "album.available_markets"      "album.href"                  
## [19] "album.id"                     "album.images"                
## [21] "album.name"                   "album.release_date"          
## [23] "album.release_date_precision" "album.total_tracks"          
## [25] "album.type"                   "album.uri"                   
## [27] "album.external_urls.spotify"  "external_ids.isrc"           
## [29] "external_urls.spotify"

A get_track_audio_features(id) függvénnyel az adott dal finomabb jellemzőiről kaphatunk adatokat.

1
2
#Az eredményül kapott adatkeret oszlopainak kilistázása.
colnames(get_track_audio_features(dalID))
##  [1] "danceability"     "energy"           "key"              "loudness"        
##  [5] "mode"             "speechiness"      "acousticness"     "instrumentalness"
##  [9] "liveness"         "valence"          "tempo"            "type"            
## [13] "id"               "uri"              "track_href"       "analysis_url"    
## [17] "duration_ms"      "time_signature"

Egy 40 évvel ezelőtti slágerlista dalainak mai népszerűsége

Végezetül nézzünk meg egy konkrét példát is a spotifyr csomag használatára! A feladat lényege az, hogy egy régi slágerlista dalairól megállapítjuk, mennyire állták ki azok az idők próbáját. Vagyis népszerűek-e manapság is, vagy esetleg időközben teljesen a feledésbe merültek.

A vizsgálathoz a Spotify Popularity Index nevű mutatót fogom felhasználni, amelyet a fentebb ismertetett függvények futtatása után, ahol releváns, popularity néven találhatunk meg az eredményül kapott adatkeretek oszlopai között. Az SPI kiszámításának pontos algoritmusa nem ismert, ezt – mivel gyakorlati jelentősége van a rendszer működtetésében – a Spotify titkolja és valószínűleg időről-időre változtatja, finomítgatja is. De mindenesetre itt egy 0 és 100 közötti számról van szó, ami különböző adatok összegzése után, egyetlen értékkel jellemzi az adott előadó, album vagy dal pillanatnyi népszerűségét. Minél magasabb ez a szám, annál nagyobb a népszerűség. Az SPI alapján tehát össze lehet hasonlítani egymással a vizsgált entitásokat.

A kiválasztott slágerlista pontosan 40 évvel ezelőtt, 1982 októberében jelent meg az Ifjúsági Magazin hasábjain.

A 20 dalból álló válogatásban vannak ma is méltán ismert és időközben méltán elfeledett alkotások is. Ugyanakkor a dalok időtállóságát nem az én szubjektív zenei ízlésem alapján fogjuk megítélni, hanem a Spotify hallgatóinak kollektív bölcsességére bízzuk a döntést.

A slágerlista szereplői közül Eszményi Viktória dalát nem találtam meg a Spotify katalógusában. Ezt a továbbiakban úgy tekintem, hogy manapság már egyáltalán nincs rá igény, vagyis 0 az SPI értéke. A Hobo Blues Band dala pedig, bár szerepel a katalógusban, de valami miatt Magyarországon nem elérhető. Így ezt sem tudtam figyelembe venni.

Először is összegyűjtöttem a rendelkezésre álló 18 dal ID-jét, majd a get_tracks() függvénnyel megszereztem az ezekhez tartozó SPI értékeket. Mivel egy-egy dal az idők során több albumon is megjelenhetett, ezért az adatgyűjtés során érdemes erre a szempontra is figyelemmel lennünk! Én minden esetben azt a verziót vettem fel a listánkra, amelyiknek a legmagasabb volt az SPI értéke. Továbbá csakis a slágerlistán megnevezett előadó példányai közül válogattam, a más általi feldolgozásokra tehát nem voltam tekintettel.

Ezt követően az rbind() függvénnyel beraktam a két hiányzó dalt is az adatkeret megfelelő helyére, hogy teljes legyen a korabeli slágerlista.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
# A Slágerlista dalainak Spotify ID-jei.
dalokID <- c("6bKy3DSrYisAovpESmemI9",
             "7BjhPdha55imGiHva13bCY",
             "7aDEV98V3nDJjcEKCvEf0m",
             "0nvHpUcKA3Lux2jPHJ1zox",
             "0VRpZPbGLQGWE1C2QCKJ0Q",
             "0FgMEfOtcPaOYVRxw5bRDC",
             "18iPfEwdVYxTKgisdNxkQ6",
             "6GfpkCvyXQquSLOKw85FZD",
             "1n6nAyze063gCMUUA6A6pN",
             "3L8eJMy1ybbYBJ2bWqSUHt",
             "7CwyI66hD5HcKklrUiPHby",
             "16ht0CxihTVLlGwV6UesgN",
             "2KEFEZAfJPbeFu3SyzplYa",
             "5ZQClajENs4ucJYePlFtFw",
             "26QHaT5OEEtHEsqDO8cuXJ",
             "3GovkUYxLDyvzl3Ls0nrn0",
             "1FxuEfZjPoHMIw3zoa8pwN",
             "4Y5jMm1c67wY8mOuFqmIf7")
# Az SPI értékek legenerálása egy adatkeretbe
popTop1982Oktober <- get_tracks(dalokID)[,c("name","popularity")]
# A két hiányzó dal elhelyezése az adatkeretben.
popTop1982Oktober <- rbind(popTop1982Oktober[1:2,],
                           data.frame("name" = "Mata Hari", "popularity" = 0),
                           popTop1982Oktober[3:12,],
                           data.frame("name" = "Egy lány mondja el", "popularity" = 0),
                           popTop1982Oktober[13:18,])
# Az adatkeret sorainak beszámozása.
rownames(popTop1982Oktober) <- 1:20
# Az adatkeret kinyomtatása a konzolra.
popTop1982Oktober
##                     name popularity
## 1            Játssz még!          9
## 2             Angyallány         27
## 3              Mata Hari          0
## 4             Féltelek …         23
## 5     Kevés voltam neked         26
## 6                Requiem         31
## 7          Fekete élmény          8
## 8            Másnak szól          4
## 9       La Baletta No. 1         11
## 10          Kemény játék          5
## 11          Ciao, Marina         31
## 12               Jégszív         23
## 13             Lakótelep          2
## 14    Egy lány mondja el          0
## 15           A nikkelpók          0
## 16             Isztambul         34
## 17      Oh Yeah - Remake          0
## 18 Mitől megy a villamos          5
## 19        Macska az úton         12
## 20          Gömbölyű dal         17

Az SPI értékeket tekintve a fenti lista elemeinek relatív pozíciója nagyjából megfelelt az előzetes várakozásaimnak. Jó lenne viszont valami külső támpont, amihez abszolút értelemben is viszonyítani tudnánk. Valami, aminek alapján meg lehetne ítélni, hogy valójában mennyire népszerűek manapság a slágerlista relatíve népszerűbbnek tűnő tételei.

Ehhez szinte önként kínálja magát Korda Györgynek az eredetileg 1981-ben – vagyis szerencsés módon közel egykorúan – megjelent Reptér című dala, amely 2022 nyarának egyik vitathatatlanul népszerű slágere volt.

1
get_tracks("7kpbpRnTHMwuSORe4iyG07")[,c("name","popularity")]
##     name popularity
## 1 Reptér         45

Látható tehát, hogy a Reptérhez képest az 1982-es slágerlistának még a legnépszerűbb dala is jelentős lemaradásban van. Kérdés persze, amit majd a jövő dönt el, hogy Korda György slágere vajon tényleg időtálló-e, vagy csak pillanatnyilag felkapott? Én inkább az utóbbira tippelnék. A slágerlista magasabbra pozícionált tételei ugyanis minden különösebb hájpolás nélkül hozzák a feltüntetett – bár kétségkívül jóval alacsonyabb – SPI értékeket. Emellett Korda dala a maga idejében nemhogy az Ifjúsági Magazin slágerlistájára nem került fel, hanem az olvasók kifejezetten cikinek érezték az előadót.

Megjegyzendő még, hogy a 0 és 100 közötti skálán a Reptér is “csak” 45 pontot kapott. (Update: Ez a 2023 októberi állapotot tükrözi. Amikor 2022 októberében közzétettem ezt a posztot, akkor a Reptér SPI értéke 52 volt.) A Spotify katalógusában ugyanis globális szinten versenyeznek egymással az egyes tételek. Egy igen népszerű magyar sláger, úgy látszik, nagyságrendileg ennyit tud manapság elérni. Az 1982. októberi slágerlista tételeinek pontszámát ehhez képest kell soknak vagy kevésnek tartanunk.