├── README.md ├── faq.md ├── libspotify-12.1.103-Linux-armv6-bcm2708hardfp-release.tar.gz ├── libspotify-12.1.51-Android-arm-release.tar.gz ├── libspotify-12.1.51-Darwin-universal.zip ├── libspotify-12.1.51-Linux-armv5-release.tar.gz ├── libspotify-12.1.51-Linux-armv6-release.tar.gz ├── libspotify-12.1.51-Linux-armv7-release.tar.gz ├── libspotify-12.1.51-Linux-i686-release.tar.gz ├── libspotify-12.1.51-Linux-x86_64-release.tar.gz ├── libspotify-12.1.51-win32-release.zip └── libspotify-12.1.64-iOS-universal.zip /README.md: -------------------------------------------------------------------------------- 1 | # libspotify archive 2 | 3 | This is an unofficial archive of the latest libspotify releases from Spotify, 4 | as Spotify as of May 2018 no longer hosts these files themselves. 5 | 6 | 7 | ## WARNING: This library no longer works 8 | 9 | In May 2015, libspotify was deprecated by Spotify and active maintenance 10 | stopped. At this point, libspotify had been the main way to integrate with 11 | Spotify for six years, and was part of numerous open source projects and 12 | commercial applications, including many receivers and even cars. It remained 13 | the only API for playback outside Android and iOS. 14 | 15 | In February 2016, server side changes to the Spotify API caused the search 16 | functionality to stop working, without Spotify ever acknowledging it. Users 17 | could work around this by using the Spotify web API for searches and 18 | libspotify for playback. 19 | 20 | In April 2022, 21 | [Spotify announced](https://developer.spotify.com/community/news/2022/04/12/libspotify-sunset/) 22 | that they would sunset the libspotify API one month later. 23 | 24 | In May 2022, new libspotify connections to Spotify started failing. 25 | 26 | 27 | ## Downloads 28 | 29 | These are the latest available releases for each CPU architecture, all released 30 | around 2012. 31 | 32 | | OS | Architecture | Version | SHA256 checksum | 33 | | ------- | ------------ | --------------------------------------------------------: | ------------------------------------------------------------------ | 34 | | iOS | ARM/i386 | [12.1.64](libspotify-12.1.64-iOS-universal.zip) | `b32e9183e552c99bb4149e71181fadb26694553cab37a92311be16c286e0736a` | 35 | | Android | ARM | [12.1.51](libspotify-12.1.51-Android-arm-release.tar.gz) | `754957de2648e7235e6ead323c22c111282adfc889535a2684c13067d2099505` | 36 | | Win32 | x86 | [12.1.51](libspotify-12.1.51-win32-release.zip) | `7c08475997461c077f79130d3cd1002111448c0ad321025748ffade7a37dda30` | 37 | | macOS | Universal | [12.1.51](libspotify-12.1.51-Darwin-universal.zip) | `80053f0779f6192a8052732904d88b91acc62a350831f6b585a3c6ac10cb8fbd` | 38 | | Linux | amd64 | [12.1.51](libspotify-12.1.51-Linux-x86_64-release.tar.gz) | `43a14e0732ba6ae30078fac105d0e2998d04d5f5c396a4968386bc4e22491058` | 39 | | Linux | armv5t | [12.1.51](libspotify-12.1.51-Linux-armv5-release.tar.gz) | `4d96efcb1423864683917f40fb4df481491250a76cb29be3a235b3732a64fefc` | 40 | | Linux | armv6t | [12.1.51](libspotify-12.1.51-Linux-armv6-release.tar.gz) | `4fb888eeb486578fa3a08e15f5aa2101632e60b56a068553d05d5d4ee0a080cc` | 41 | | Linux | armv6hf | [12.1.103](libspotify-12.1.103-Linux-armv6-bcm2708hardfp-release.tar.gz) | `d658e6c1978fb46cf33376eb8367a51d024f4014f21beac1dd264532bcc54b24` | 42 | | Linux | armv7 | [12.1.51](libspotify-12.1.51-Linux-armv7-release.tar.gz) | `ad27b6c5aee5382b66b39bfea3b1752076b7abcc445979ce25c1ec9d7ff3aeda` | 43 | | Linux | i686 | [12.1.51](libspotify-12.1.51-Linux-i686-release.tar.gz) | `941ab4ba10bcd6ec4e96127afd095a39e11bc955de0882734c97e4f588b155ae` | 44 | 45 | 46 | ## Documentation 47 | 48 | - API reference: See `share/doc/libspotify/html/index.html` in the Linux 49 | releases above. 50 | - Examples: See `share/doc/libspotify/examples/` in the Linux releases above. 51 | - [libspotify FAQ](faq.md) 52 | -------------------------------------------------------------------------------- /faq.md: -------------------------------------------------------------------------------- 1 | # libspotify FAQ 2 | 3 | This content was retrieved from 4 | https://web.archive.org/web/20170913122345/https://developer.spotify.com/technologies/libspotify/faq/ 5 | on 2018-05-27. 6 | 7 | --- 8 | 9 | Here we answer some common questions about the Libspotify SDK. 10 | 11 | **Important!** If you are building applications for iOS or Android, please use 12 | the iOS SDK or Android SDK. LibSpotify and CocoaLibSpotify is considered 13 | deprecated for these platforms. 14 | 15 | 16 | ## libspotify objects 17 | 18 | ### Why are functions named like `sp_session_inbox_create()`? 19 | 20 | Functions ending in `_create()` create a new object inside libspotify rather 21 | than creating some entity on the Spotify servers. These `_create()` functions 22 | leave a reference for the API user to release when the user has no more 23 | interest in the object. *It is important to note that failing to release the 24 | entity will result in memory leaks.* 25 | 26 | ### I don't get any metadata callback when I create an album or artist link but I do get a callback if I do the same for a track 27 | 28 | Creating an `sp_album` or `sp_artist` object will not automatically populate 29 | the object with data. To get information about an artist or album you need to 30 | perform a browse request for libspotify to populate its internal datamodel. 31 | Once the browse request has succeded all `sp_album` and `sp_artist` object that 32 | can be derived from the response will be filled with data. 33 | 34 | The `sp_album` and `sp_artist` objects behave more like placeholder objects 35 | that contain minimal information about the artist and album. For example, it's 36 | not possible to get a list of all tracks on an album from just the `sp_album` 37 | object itself. 38 | 39 | This diagram describes the internal relationship between the metadata objects: 40 | 41 | ``` 42 | +----------------+ 43 | | sp_albumbrowse |-----------+ (List of tracks) 44 | +----------------+ | 45 | | | 46 | V V 47 | +----------+ +----------+ 48 | +--------------->| sp_album |<---------| sp_track |<-----------------+ 49 | | +----------+ +----------+ | 50 | | | | | 51 | | V | (Additional artists) | 52 | | +-----------+ | | 53 | | | sp_artist |<--------------+ | 54 | | +-----------+ | 55 | | (List of all ^ | 56 | | albums for | | 57 | | artist) +-----------------+ (List of all tracks for artist) | 58 | +--------------| sp_artistbrowse |-----------------------------------+ 59 | +-----------------+ 60 | ``` 61 | 62 | 63 | ## Threading and concurrency 64 | 65 | ### According to documentation, libspotify is not thread safe. What does this mean? 66 | 67 | It means that you can not invoke any libspotify API function while another API 68 | is invoked in a different thread. This includes *all* of the functions, even 69 | `sp_session_process_events()`. In other words, having a thread that just spins 70 | and invokes `sp_session_process_events()` when needed (either due to that the 71 | notification callback fires or a timeout happens), while another thread invokes 72 | API functions, is *not* supported. If you look in our examples you will see 73 | that we never do this ourselves. 74 | 75 | ### But libspotify creates threads itself! 76 | 77 | Yes, but only for serving requests internally and for those requests libspotify 78 | provides adequate locking by itself. In particular it spawns a network thread 79 | that handles all of the communication with Spotify's servers and is also 80 | responsible for decoding music, etc. 81 | 82 | ### Why is it like this? 83 | 84 | libspotify is comprised of two things. The Spotify Core ("Core") which has the 85 | libspotify API layer "on-top" of it. Core is used in all Spotify's native 86 | applications (Desktop client, Mobile clients, etc) and for those GUI centric 87 | applications the `sp_session_process_events()` handing is part of the normal GUI 88 | main thread. 89 | 90 | ### According to documentation, some callbacks are called from “internal session thread”. What does that mean? 91 | 92 | It means that those are not called from inside `sp_session_process_events()` 93 | but rather the network thread as described above. 94 | 95 | As of this writing those callbacks are: 96 | 97 | - `session.notify_main_thread` 98 | - `session.end_of_track` 99 | - `session.music_delivery` 100 | - `session.start_playback` 101 | - `session.stop_playback` 102 | - `session.get_audio_buffer_stats` 103 | 104 | There might be more in the future and the API documentation is the 105 | authoritative information about what callbacks are invoked from what threads. 106 | 107 | It's *very* important that these functions *NEVER* block for an extended period 108 | of time. Doing so may cause the API to be unresponsive because you would in 109 | fact block and stop all communication with the Spotify servers. Worst case the 110 | session could be disconnected. 111 | 112 | You should not call any other libspotify API methods from within these 113 | callbacks. Even if you use a global lock around all API calls as acquiring this 114 | global lock can take an extended amount of time this would effectively mean 115 | that you block this thread and risk audio dropouts or network disconnects, etc 116 | 117 | The most common error is to block in the `music_delivery` callback and wait for 118 | the audio output FIFO/queue/device/etc to have enough available samples to 119 | satisfy the request. This is *not* how it should be done, instead if there are 120 | not enough available buffers the function should just return 0 and libspotify 121 | will retry in a short while again with the same samples. 122 | 123 | ### What is the the `notify_main_thread` callback? Why is it needed? 124 | 125 | This callback is invoked from any thread when the main thread need to awaken to 126 | process events and in turn deliver callbacks to your application. 127 | 128 | It's important to remember that the main thread can also invoke this callback. 129 | The reason for this is that it simplifies the internal design. In particular 130 | this happens when cached browse results are loaded. Therefore, the notification 131 | mechanism must be prepared for this. This means that if you plan to take a 132 | lock, it must not already be held when calling `sp_session_process_events()`. 133 | 134 | ### So how should I write my integration to libspotify? 135 | 136 | There are basically two options. 137 | 138 | Staying on one thread or adding locking. Which one is better or preferred is 139 | mostly up to the implementer but here is a general sketch: 140 | 141 | #### Staying on one thread 142 | 143 | This means that you would encode your requests (browse, search, play track, 144 | etc) using some kind of message and post this for processing onto the same main 145 | thread that keeps doing `sp_session_process_events()` 146 | 147 | One example of this method is the spshell example. See `spshell_posix.c` and 148 | `spshell_win32.c` in particular. It's very simplistic as it just posts the 149 | command line as typed from the prompt into the main loop and let the main loop 150 | parse the line. But it should be enough to illustrate the general idea. 151 | 152 | This approach is probably the best if you already have a design where the 153 | libspotify integration receives messages from an external process or a 154 | different thread. In case you receive the messages from an external process 155 | (via a socket or similar) you probably would need to rewrite the 156 | `notify_main_thread` to use a `pipe(2)` or similar and use `poll(2)` or 157 | `select(2)` to control the main loop. To process messages from a different 158 | thread, you can stick to pthread condition variables much like the spshell 159 | example. 160 | 161 | #### Add your own locks 162 | 163 | You can add a global lock around all function calls to libspotify. This would 164 | also include `sp_session_process_events()`. 165 | 166 | For code inside callbacks that are called indirectly by 167 | `sp_session_process_events()` there is no need to worry about this global lock 168 | as the global lock is already acquired by the current thread outside of 169 | `sp_session_process_events()`. See the question about "callbacks are called from 170 | 'internal session thread'" to see what callbacks that are not invoked from 171 | within `sp_session_process_events()` and thus, where you would need additional 172 | locking. 173 | 174 | Also beware that during `sp_session_process_events()` data which is owned by 175 | libspotify may change. An example: 176 | 177 | Thread A (normal main loop): 178 | 179 | ``` c 180 | pthread_mutex_lock(&global_lock); 181 | do { 182 | sp_session_process_events(g_session, &next_timeout); 183 | } while (next_timeout == 0); 184 | pthread_mutex_unlock(&global_lock); 185 | ``` 186 | 187 | Thread B: 188 | 189 | ``` c 190 | const char *name; 191 | 192 | pthread_mutex_lock(&global_lock); 193 | name = sp_playlist_name(playlist); 194 | pthread_mutex_unlock(&global_lock); 195 | printf("The playlist is called: %sn", name); // <- might crash! 196 | ``` 197 | 198 | After thread B releases `global_lock` thread A might execute and process events 199 | from server that renames the playlist and then the memory holding the name 200 | might be freed resulting in a use of freed memory. 201 | 202 | Instead, the proper implementation is: 203 | 204 | Thread B: 205 | 206 | ``` c 207 | const char *name; 208 | 209 | pthread_mutex_lock(&global_lock); 210 | name = sp_playlist_name(playlist); 211 | printf("The playlist is called: %sn", name); 212 | pthread_mutex_unlock(&global_lock); 213 | ``` 214 | 215 | 216 | ## Playlists 217 | 218 | ### What is an `sp_playlistcontainer`? 219 | 220 | A playlistcontainer is a list of playlist. Those are currently obtained from 221 | two sources: 222 | 223 | `sp_session_playlistcontainer()` to get the currently logged in users rootlist 224 | and `sp_session_publishedcontainer_for_user_create()` 225 | 226 | The latter leaves a reference for the API user to release. 227 | 228 | ### How/When is a playlist loaded? 229 | 230 | Playlist start to load data from Spotify servers as soon as the object 231 | (`sp_playlist`) representing the playlist is created in libspotify. Playlist 232 | objects can be created as a direct result of an API call or implicitly created 233 | because they are part of a playlistcontainer. 234 | 235 | To get notifications about changes to the playlist, register callbacks using 236 | `sp_playlist_add_callbacks()`. Before registering the callbacks the API user 237 | should query the current playlist status (enumerate tracks already added, get 238 | playlist name, etc) Once the attributes changes or tracks are added, removed, 239 | moved the relevant callbacks will fire. 240 | 241 | When the playlist is loaded it only means that the track objects `sp_track` 242 | representing the tracks has been loaded into memory. You might still need to 243 | wait for metadata about the tracks. Although, if everything was in on disk 244 | cache and nothing have changed all metadata would have been loaded by now. For 245 | more info, see "How/When do I get metadata for tracks on playlists?" 246 | 247 | The application should continue and listen to the playlist callbacks as long as 248 | the playlist is displayed and update the view presented to the user so it 249 | reflects changes in the playlist. 250 | 251 | Playlist processing and resulting callbacks will only take place during 252 | `sp_session_process_events()` so it's safe to extract the list of tracks and 253 | then register the callbacks (or vice verse) without risking a race condition. 254 | 255 | ### Why isn't the track working even though `sp_track_is_loaded()` returns true? 256 | 257 | Even though `sp_track_is_loaded()` returns true, that doesn't necessarily mean 258 | that the track is ok. One must really check with `sp_track_error()` that the 259 | status is `SP_ERROR_OK`, before calling any other `sp_track_*()` functions. 260 | 261 | ### How/When do I get metadata for tracks on playlists? 262 | 263 | Contrary to browse and search results the playlist load metadata 264 | asynchronously. When metadata for one or more track in a playlist is loaded the 265 | `playlist_metadata_changed` callback will fire. This callback only fires when a 266 | track that is in the playlist transition from non-loaded to loaded state. 267 | 268 | In other words, if metadata for all tracks is already loaded the callback will 269 | not fire. The API user is expected to try to extract the metadata (or at least 270 | keep track of which tracks have metadata) when the track is added to the list 271 | (either via the `tracks_added` callback or via the `sp_playlist_track()` 272 | enumeration) 273 | 274 | Note that the `playlist_metadata_callback` may also fire spuriously. The reason 275 | for this is that track metadata is loaded in batch requests from Spotify's 276 | servers and if a lot of tracks was requested in one batch it's cheaper for the 277 | libspotify to invoke the callback on all playlists than having to sort out (an 278 | O(n^2) operation) which tracks are in which playlist. 279 | 280 | If the same track appears in multiple playlists (in this case the `sp_track` 281 | object would be the same as it's reference counted) the callback would fire for 282 | both playlists. 283 | 284 | ### What's the correct way to handle folders in the rootlist? 285 | 286 | Folders are represented using begin / end markers. One options is to just 287 | ignore those markers. This will present the user will a flattered list (without 288 | any folder). This is certainly not the recommended way and might serve as a 289 | stop gap during development. 290 | -------------------------------------------------------------------------------- /libspotify-12.1.103-Linux-armv6-bcm2708hardfp-release.tar.gz: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mopidy/libspotify-archive/d709c16cd3048b48b6f7fc1c52df161cdf7b2fc5/libspotify-12.1.103-Linux-armv6-bcm2708hardfp-release.tar.gz -------------------------------------------------------------------------------- /libspotify-12.1.51-Android-arm-release.tar.gz: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mopidy/libspotify-archive/d709c16cd3048b48b6f7fc1c52df161cdf7b2fc5/libspotify-12.1.51-Android-arm-release.tar.gz -------------------------------------------------------------------------------- /libspotify-12.1.51-Darwin-universal.zip: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mopidy/libspotify-archive/d709c16cd3048b48b6f7fc1c52df161cdf7b2fc5/libspotify-12.1.51-Darwin-universal.zip -------------------------------------------------------------------------------- /libspotify-12.1.51-Linux-armv5-release.tar.gz: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mopidy/libspotify-archive/d709c16cd3048b48b6f7fc1c52df161cdf7b2fc5/libspotify-12.1.51-Linux-armv5-release.tar.gz -------------------------------------------------------------------------------- /libspotify-12.1.51-Linux-armv6-release.tar.gz: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mopidy/libspotify-archive/d709c16cd3048b48b6f7fc1c52df161cdf7b2fc5/libspotify-12.1.51-Linux-armv6-release.tar.gz -------------------------------------------------------------------------------- /libspotify-12.1.51-Linux-armv7-release.tar.gz: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mopidy/libspotify-archive/d709c16cd3048b48b6f7fc1c52df161cdf7b2fc5/libspotify-12.1.51-Linux-armv7-release.tar.gz -------------------------------------------------------------------------------- /libspotify-12.1.51-Linux-i686-release.tar.gz: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mopidy/libspotify-archive/d709c16cd3048b48b6f7fc1c52df161cdf7b2fc5/libspotify-12.1.51-Linux-i686-release.tar.gz -------------------------------------------------------------------------------- /libspotify-12.1.51-Linux-x86_64-release.tar.gz: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mopidy/libspotify-archive/d709c16cd3048b48b6f7fc1c52df161cdf7b2fc5/libspotify-12.1.51-Linux-x86_64-release.tar.gz -------------------------------------------------------------------------------- /libspotify-12.1.51-win32-release.zip: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mopidy/libspotify-archive/d709c16cd3048b48b6f7fc1c52df161cdf7b2fc5/libspotify-12.1.51-win32-release.zip -------------------------------------------------------------------------------- /libspotify-12.1.64-iOS-universal.zip: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mopidy/libspotify-archive/d709c16cd3048b48b6f7fc1c52df161cdf7b2fc5/libspotify-12.1.64-iOS-universal.zip --------------------------------------------------------------------------------