Git Product home page Git Product logo

pyspotify's Introduction

pyspotify

WARNING: This library no longer works

pyspotify is a Python wrapper around the libspotify C library, and thus depends on libspotify for everything it does.

In May 2015, libspotify was deprecated by Spotify and active maintenance stopped. At this point, libspotify had been the main way to integrate with Spotify for six years, and was part of numerous open source projects and commercial applications, including many receivers and even cars. It remained the only API for playback outside Android and iOS.

In February 2016, server side changes to the Spotify API caused the search functionality to stop working, without Spotify ever acknowledging it. Users of pyspotify could work around this by using the Spotify web API for searches and pyspotify for playback.

In April 2022, Spotify announced that they would sunset the libspotify API one month later.

In May 2022, new libspotify connections to Spotify started failing. With libspotify dead, pyspotify was dead too.

After two years in development from May 2013 to May 2015, and seven years of loyal service this project has reached its end.

There will be no further updates to pyspotify.

Hopefully, the pyspotify source code can still serve as a complete example of how to successfully wrap a large C library in Python using CFFI.

Introduction

pyspotify provides a Python interface to Spotify's online music streaming service.

With pyspotify you can access music metadata, search in Spotify's library of 20+ million tracks, manage your Spotify playlists, and play music from Spotify. All from your own Python applications.

pyspotify uses CFFI to make a pure Python wrapper around the official libspotify library. It works on CPython 2.7 and 3.5+, as well as PyPy 2.7 and 3.5+. It is known to work on Linux and macOS. Windows support should be possible, but is awaiting a contributor with the interest and knowledge to maintain it.

Project resources

Latest PyPI version CI build status Read the Docs build status Test coverage

pyspotify's People

Contributors

adamcik avatar edwardbetts avatar jodal avatar kingosticks avatar tarikd avatar thomasvs avatar trygveaa avatar vrs01 avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

pyspotify's Issues

num_subscribers() always returning 0

Just started using Pyspotify so apologies if i am missing something which I havent done, however I am just running a few tests and it appears that the Playlist.num_subscribers() is always returning 0, i also tried using Playlist.subscribers(), this also seems to return an empty array.

Please see my code below which i have been using for the tests

Is this a bug or am i just being stupid.

#!/usr/bin/env python
# -*- coding: utf8 -*-

import cmd
import logging
import os
import sys
import threading
import time

from spotify import ArtistBrowser, Link, ToplistBrowser, SpotifyError, AlbumBrowser, Playlist
from spotify.manager import (SpotifySessionManager, SpotifyPlaylistManager, SpotifyContainerManager)

container_loaded = threading.Event()

spotify_playlist = [
    'spotify:user:littleb1983:playlist:5qVbhgZxhEom7W4ZV6xG5P',
    'spotify:user:littleb1983:playlist:2hdIbJ7UuYxgu0FTVK83f3',
    'spotify:user:scoopy27:playlist:4pvL7XHfNmCzAjqDDpF3dV',
    'spotify:user:littleb1983:playlist:1b8hpJZcQuDFZfRLOV3rVW',
    'spotify:user:digsterdeutschland:playlist:0WgKHUksjYUrIuUTYXgbfQ',
    'spotify:user:matt.schofield.102:playlist:6Wq5autgVknMUiO80Ol2th',
    'spotify:user:marza69:playlist:5Ca0ExY1tMfoq9cr8NuJMd',
    'spotify:user:ayshafanny:playlist:53z42J2ByB0bPdK8XxQg5O',
    'spotify:user:digster.se:playlist:7LRqIcQTHUL4TBedADnYy2'
]


class sessionManager(SpotifySessionManager):
    appkey_file =  os.path.join(os.path.dirname(__file__), 'spotify_appkey.key')

    def __init__(self, *a, **kw):
        SpotifySessionManager.__init__(self, *a, **kw)

    def logged_in(self, session, error):

        for list in spotify_playlist:

            link = Link.from_string(list)
            playlist = link.as_playlist()

            print playlist.name()
            print playlist.owner()
            print playlist.num_subscribers()

            for track in playlist:
                print Link.from_track(track)
                print track.name()

if __name__ == '__main__':
    import optparse
    op = optparse.OptionParser(version="%prog 0.1")
    op.add_option("-u", "--username", help="Spotify username")
    op.add_option("-p", "--password", help="Spotify password")
    op.add_option("-v", "--verbose", help="Show debug information", dest="verbose", action="store_true")
    (options, args) = op.parse_args()
    if options.verbose:
        logging.basicConfig(level=logging.DEBUG)
    session_m = sessionManager(options.username, options.password, True)
    session_m.connect()

Unicode passwords crashes pyspotify

I first tried using a Unicode password in mopidy and filed mopidy/mopidy#466 for that, but it seems like the problem is in pyspotify as the jukebox example code also gets a crash when I try:

zenith@zenith-VirtualBox:~$ python jukebox.py -u 123123123123 -p some£password
Logging in, please wait...
Traceback (most recent call last):
  File "jukebox.py", line 504, in <module>
    session_m.connect()
  File "/usr/lib/pymodules/python2.7/spotify/manager/session.py", line 80, in connect
    self.remember_me)
UnicodeDecodeError: 'ascii' codec can't decode byte 0xc2 in position 6: ordinal not in range(128)

GstreamerAudioSink is asynchronous, and thus doesn't play nicely with the jukebox queue

If you use the gstreamer sink, playing a full playlist in jukebox has unforeseen consequences - the song plays until spotify has loaded the entire song, at which point the text track ended is printed out (as jukebox expects the sink to block until frames have played), and then the next song is loaded into the appsrc.

Possible temporary fixes are change the appsrc flags to use sync=true.

Decode all bytestrings to unicode

It would be nice if pyspotify decoded all bytestrings to unicode objects before they were returned to the Python program using pyspotify.

This way the client program would get rid of a lot of foo.decode('utf-8') calls, and pyspotify would also handle decoding errors like #10 for you.

Support for friends

Would be awesome if pyspotify could support the friends fetching already implemented in the libspotify:

int sp_session_num_friends (sp_session *session)
sp_user * sp_session_friend (sp_session *session, int index)

Thanks!! (Amazing work by the way)

Segmentation fault after running for a while

I have not yet been able to trace down the exact issue, but every time I play a couple of songs (~15 minutes) my app crashes with a segmentation fault.

Little information about my environment:

  • Ubuntu 11.10
  • pyspotify 1.6.1
  • libspotify 10.1.16 x86_64
  • Python 2.7.2

Here's a small part of the strace output:

access("tmp/Users/wolph-user/playlist-c3a5cea4027d5705c2ee69b02fc3c13002.bnk.tmp", F_OK) = -1 ENOENT (No such file or directory)                                                                                                                                                                                            
open("tmp/Users/wolph-user/playlist-c3a5cea4027d5705c2ee69b02fc3c13002.bnk.tmp", O_WRONLY|O_CREAT|O_TRUNC, 0664) = 28                                                                                                                                                                                                       
fcntl(28, F_SETFD, FD_CLOEXEC)          = 0                                                                                                                                                                                                                                                                                 
write(28, "SPCO\26\0\0\0\1\24PlaylistWithMetadata\334\37"..., 8192) = 8192                                                                                                                                                                                                                                                  
write(28, "\372\37[\250B\2024\225\0@\t\20\306\27\t\377}NC(\256g\366\251\360>5?\10\330\17x"..., 8192) = 8192                                                                                                                                                                                                                 
write(28, "\372\37Xx@0\17\10\17x\4\1\20[!\227{s\303O\377\277\244~\224\350\345\311\276\t\27E"..., 8192) = 8192                                                                                                                                                                                                               
write(28, "\372\37\22\330\223\2110\236\10\200\304\23x\10\0\10\1\200\2\17\10\17x\4\1\20#\324s\356\222'"..., 8192) = 8192                                                                                                                                                                                                     
write(28, "\372\37\245~\352\n\377\3\v\357\2244\35\10\277\366\355\367\4\10\207\200\372\367\4\10)\25\24\1\24\320"..., 8192) = 8192                                                                                                                                                                                            
write(28, "\372\37\24a\357\310 Esper, Rebecca Naomi Jone"..., 8192) = 8192                                                                                                                                                                                                                                                  
write(28, "\372\37\275\231\247?ne/She's A Rebel\t\20\363'\243\21\214\311D="..., 8192) = 8192                                                                                                                                                                                                                                
write(28, "\372\37\250\310\312\356I>\247+JjN\357vd\10\277\366\355\367\4\10\210\200\372\367\4\10\16\25\24"..., 8192) = 8192                                                                                                                                                                                                  
write(28, "\372\37v\361k\264\10\5\t\20\22\7\1S\323\271G\322\225i\375\252\16]\1\267\10\277\366\355\367\4"..., 8192) = 8192                                                                                                                                                                                                   
write(28, "\372\37\335\0\262\343\274<\222\3\32\217\220\23\t\nLonely Day\t\20\254\4\364\346"..., 8192) = 8192                                                                                                                                                                                                                
write(28, "\372\37\330\231Bo\327\207\10\200\342\tx\1\24\353\307\272\337\206\32\r\245\24\35}\262\377\203\34\351\226"..., 8192) = 8192                                                                                                                                                                                        
write(28, "Y\25\375F\307^\20\25\267\276g\361WFh\243\237\254\326\265\256\370\305\20\317\t\343\273\361OE\311"..., 5473) = 5473                                                                                                                                                                                                
close(28)                               = 0                                                                                                                                                                                                                                                                                 
rename("tmp/Users/wolph-user/playlist-c3a5cea4027d5705c2ee69b02fc3c13002.bnk.tmp", "tmp/Users/wolph-user/playlist-c3a5cea4027d5705c2ee69b02fc3c13002.bnk") = 0                                                                                                                                                              
write(27, "SPCO\17\0\0\0\1\rPlaylistCache\177\v`\3235\276\0\220\301"..., 2974) = 2974                                                                                                                                                                                                                                       
close(27)                               = 0                                                                                                                                                                                                                                                                                 
rename("tmp/Users/wolph-user/playlist.bnk.tmp", "tmp/Users/wolph-user/playlist.bnk") = 0                                                                                                                                                                                                                                    
unlink("tmp/Users/wolph-user/playlist") = -1 ENOENT (No such file or directory)                                                                                                                                                                                                                                             
clone(child_stack=0x7f4ade7fbfd0, flags=CLONE_VM|CLONE_FS|CLONE_FILES|CLONE_SIGHAND|CLONE_THREAD|CLONE_SYSVSEM|CLONE_SETTLS|CLONE_PARENT_SETTID|CLONE_CHILD_CLEARTID, parent_tidptr=0x7f4ade7fc9d0, tls=0x7f4ade7fc700, child_tidptr=0x7f4ade7fc9d0) = 12079                                                                
futex(0x7f4ae0000950, FUTEX_WAIT_PRIVATE, 0, NULL) = 0                                                                                                                                                                                                                                                                      
futex(0x7f4ae0000950, FUTEX_WAIT_PRIVATE, 0, NULL) = 0                                                                                                                                                                                                                                                                      
clone(child_stack=0x7f4ade7fbfd0, flags=CLONE_VM|CLONE_FS|CLONE_FILES|CLONE_SIGHAND|CLONE_THREAD|CLONE_SYSVSEM|CLONE_SETTLS|CLONE_PARENT_SETTID|CLONE_CHILD_CLEARTID, parent_tidptr=0x7f4ade7fc9d0, tls=0x7f4ade7fc700, child_tidptr=0x7f4ade7fc9d0) = 12081                                                                
futex(0x16a7850, FUTEX_WAKE_PRIVATE, 1) = 1                                                                                                                                                                                                                                                                                 
futex(0x16a7850, FUTEX_WAKE_PRIVATE, 1) = 0                                                                                                                                                                                                                                                                                 
futex(0x16a7850, FUTEX_WAKE_PRIVATE, 1) = 0                                                                                                                                                                                                                                                                                 
futex(0x16a7850, FUTEX_WAIT_PRIVATE, 0, NULL) = -1 EAGAIN (Resource temporarily unavailable)                                                                                                                                                                                                                                
futex(0x7f4ae0000950, FUTEX_WAKE_PRIVATE, 1) = 1                                                                                                                                                                                                                                                                            
futex(0x7f4ae0012f20, FUTEX_WAIT_PRIVATE, 0, NULL) = 0                                                                                                                                                                                                                                                                      
futex(0x16a7850, FUTEX_WAIT_PRIVATE, 0, NULL) = 0                                                                                                                                                                                                                                                                           
futex(0x7f4ae0012f20, FUTEX_WAIT_PRIVATE, 0, NULL) = 0                                                                                                                                                                                                                                                                      
clone(child_stack=0x7f4ade7fbfd0, flags=CLONE_VM|CLONE_FS|CLONE_FILES|CLONE_SIGHAND|CLONE_THREAD|CLONE_SYSVSEM|CLONE_SETTLS|CLONE_PARENT_SETTID|CLONE_CHILD_CLEARTID, parent_tidptr=0x7f4ade7fc9d0, tls=0x7f4ade7fc700, child_tidptr=0x7f4ade7fc9d0) = 12086                                                                
futex(0x7f4ae0000950, FUTEX_WAIT_PRIVATE, 0, NULL) = 0                                                                                                                                                                                                                                                                      
futex(0x7f4ae0000950, FUTEX_WAIT_PRIVATE, 0, NULL) = 0                                                                                                                                                                                                                                                                      
clone(child_stack=0x7f4ade7fbfd0, flags=CLONE_VM|CLONE_FS|CLONE_FILES|CLONE_SIGHAND|CLONE_THREAD|CLONE_SYSVSEM|CLONE_SETTLS|CLONE_PARENT_SETTID|CLONE_CHILD_CLEARTID, parent_tidptr=0x7f4ade7fc9d0, tls=0x7f4ade7fc700, child_tidptr=0x7f4ade7fc9d0) = 12088                                                                
futex(0x7f4ae0012f20, FUTEX_WAIT_PRIVATE, 0, NULL) = 0                                                                                                                                                                                                                                                                      
futex(0x7f4ae0012f20, FUTEX_WAIT_PRIVATE, 0, NULL) = 0                                                                                                                                                                                                                                                                      
futex(0x16a7850, FUTEX_WAKE_PRIVATE, 1) = 1                                                                                                                                                                                                                                                                                 
futex(0x16a7850, FUTEX_WAKE_PRIVATE, 1) = 0                                                                                                                                                                                                                                                                                 
+++ killed by SIGSEGV +++

Fix outstanding TODOs from cleanups

Summary of the most relevant cleanup TODOs that are outstanding:

  • Remove casts in *_SP_* macros so compiler can type check "everything"
  • Make code py_size_t clean
  • Switch to a generic linked list for callback handling and/or switch to returning a callback id used for removing callbacks. Last known place we are leaking memory.
  • Fix NULL deference cases and other places like malloc where we should be checking for errors.
  • Add region country code sanity checks
  • Handle NULLs inside the loops that convert artists, tracks etc to python lists.

jukebox freezes/hangs after playing one track of a playlist

Hello,

I'm using the pyspotify source from github compiled with the latest libspotify: 12.1.51.

When I'm running the jukebox example and using a play X command to play a playlist, the jukebox plays one track then shows "Stopping" and then hangs indefinitely...

While the first song is played, I can use the 'next' command without problems, but once one track has ended, the jukebox app will freeze.

Thanks for your help.

Sporadic crash during iterative search queries

Seeing the following crash in the python wrapper from an application I have written that is performing a number of iterative search queries:

From callback <function _search_complete_callback at 0x103ad70>:
Traceback (most recent call last):
  File "/usr/local/lib/python2.7/dist-packages/spotify/search.py", line 308, in _search_complete_callback
    search_result._callback_handles.remove(handle)
AttributeError: '_cffi_backend.CData' object has no attribute '_callback_handles'

I took a look at the code and couldn't see an obvious way by which the class could be initialized without the _callback_handles attribute being assigned i.e., it gets assigned to an empty set on line 52.

However, I do wonder if there is a possibility that an invalid handle could be returned by the C library in the following code fragment:

   (callback, search_result) = ffi.from_handle(handle)

Any thoughts on this would be appreciated.

Support autolinking

It would be nice to be able to turn on autolinking on playlist, so that tracks that are no longer available may be replaced by other versions of the same track.

I've seen users be surprised that a track isn't playable in Mopidy while it is playable in Spotify, simply because it has been replaced with an equivalent track.

libspotify exposes sp_playlist_set_autolink_tracks for this purpose.

ChannelError from libspotify

I started a python script from scratch to see if I can isolate the issue.

You can reproduce the issue using this repo. My logs.txt are there as well.
https://github.com/thesmart/pyspotify-playlist-generator (EDITED, LINK FIXED)

The python stack is like this:

python script -> pyspotify -> libspotify

  • python script - python 2.7.3 - this is LiveNation code that is trying to download all the Playlists that the user has. It logs in, makes the call to download our 200+ playlists. The load callback never fires.
  • pyspotify - version 1.10 - this is the python wrapper for libspotify. It has an error message capability to see what libspotify is saying. libspotify is telling pyspotify that it encountered a ChannelError.
  • libspotify - version 12.1.51 for Mac OS X/Darwin - this is a C library provided by Spotify that does magic with their servers. See logs.txt in the repo.
    See logs.txt in the repo.

The logs show that on our end, we're connected and then all the playlist responses fail in libspotify. I'm not sure if this is a known issue, I have tried searching.

pyspotify 2 -- a rewrite based on cffi

From seeing pyspotify issues being debugged and answered by lovely people that isn't me (hi @bok and @kingosticks) I understand that I'm not working alone wrt. pyspotify maintenance and should share a bit more.

I'm working on a pyspotify rewrite named pyspotify 2 using the cffi library. The main advantages over pyspotify 1 is that the pyspotify 2 code is pure Python, and works on CPython 2.7, CPython 3.3, and PyPy 2.

I've previously started pyspotify rewrites using Cython and ctypes. Though, this time I've come a lot further, and I'm basically past any expected hurdles. The remaining work is mostly doing a lot more of what I've already done. In other words, I am quite confident that I'll complete this rewrite with time. I don't have a target date, but I want this to be ready before Ubuntu 14.04 ships without Python 2 installed by default. That leaves us nearly a year.

I'm working on mapping the full libspotify API to Python classes, with proper memory and error handling, but otherwise staying close to the libspotify API.

I'm also maintaining a pyspotify shell as an example app and a driver for what APIs to add first. I want to keep the shell app simple and straight forward, and not end up in the feature creep our existing jukebox example is in, making it useless as an example to learn from. Thus, most actions in the shell maps almost directly to libspotify functions.

All code has unit tests, but only against mocks of the C functions (written in Python using the mock library), so some manual testing is also needed to make sure the tests are correct. This means that with the release of pyspotify 2, we'll have no further interest in the development of libmockspotify.

The work happens in my fork of the pyspotify repo, but in a new empty branch. So far I haven't copied anything at all from pyspotify 1.x. I may bring over the various manager and audiosink classes from pyspotify 1.x to ease migration, but I haven't decided yet. Since pyspotify 1 and 2 won't be API compatible, I'll let 1.x continue living in its own branch so we can do bugfix releases of it for a while after 2.x is released.

For further status updates, have a look at the README in the pyspotify2 branch, which is regularly updated with the state of the project. It also contains instructions on how to set up the development environment.

Support other user's "starred" playlists

If I have subscribed to another user's "starred" playlist, it shows up in the playlist container, but I can't get the name of it. I don't know if I can get the tracks from it. You can subscribing to spotify:user:jodal:starred to reproduce the issue.

Probably sp_session_starred_for_user_create() needs to be involved in fixing this.

Segmentation fault when reconnecting

Hi,

On my project i have create a RPC Server wich is a thread which is running a spotify Session

RpcServer(threading.Thread) -------> Session(SpotifySessionManager,threading.Thread)

I can, connect play pause stop and disconnect, but if i want disconnect and reconnect i have a segmentation fault.

Here is my debug :

RPC Server is running ...
try to connect
Logging in, please wait...

In the SpotifySessionManager loop
we are logged in !
In the SpotifySessionManager loop
In the SpotifySessionManager loop
In the SpotifySessionManager loop
In the SpotifySessionManager loop

is alive : False / Here i try to kill the Thread

In the SpotifySessionManager loop
Got message; disconnecting

*_Reconnection_

try to connect
Logging in, please wait...
Segmentation fault

Handle new configuration options

Spotify API 7 introduces 3 new session configuration options:

in sp_session_config:

+  /**
+   * Compress local copy of playlists, reduces disk space usage
+   */
+  bool compress_playlists;
+
+  /**
+   * Don't save metadata for local copies of playlists
+   * Reduces disk space usage at the expence of needing
+   * to request metadata from Spotify backend when loading list
+   */
+  bool dont_save_metadata_for_playlists;
+
+  /**
+   * Avoid loading playlists into RAM on startup. 
+   * See sp_playlist_is_in_ram() for more details.
+   */
+  bool initially_unload_playlists;

It would be nice if they were accessible through pyspotify.

Link.from_playlist(p) in examples/jukebox.py errors out when facing playlistfolders

I've got playlist folders and not only playlists. When I run "ls" after having logged in, I'm greeted with:

$ python jukebox.py -u <user> -p <pw>
Logging in, please wait...
Logged in!
jukebox> ls
Stopping
Goodbye!
Exception in thread Thread-1:
Traceback (most recent call last):
  File "/System/Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7/threading.py", line 530, in __bootstrap_inner
    self.run()
  File "jukebox.py", line 35, in run
    self.cmdloop()
  File "/System/Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7/cmd.py", line 142, in cmdloop
    stop = self.onecmd(line)
  File "/System/Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7/cmd.py", line 219, in onecmd
    return func(arg)
  File "jukebox.py", line 54, in do_list
    if Link.from_playlist(p).type() == Link.LINK_STARRED:
TypeError: must be spotify.Playlist, not spotify.PlaylistFolder

Compiling pyspotify 1 on Windows

Hi!

I tried compiling on WinXP and ran into several problems I thought you'd like to know.
First, compilation does not work for me with the latest version of gcc (the option '-mno-cygwin' is no longer supported).
Then I tried to downgrade to gcc 3.4.5 but I got compilation errors (log below).
Apparently PyObject_HEAD is not recognized, although we do have #include <Python.h> at the beginning of module.c
Do you have any idea on how to fix this or is there something stupid I'm missing?

Thanks in advance!

Compilation log:

~\mopidy-pyspotify-3d62577>python setup.py build
running build
running build_py
creating build
creating build\lib.win32-2.7
creating build\lib.win32-2.7\spotify
copying spotify\__init__.py -> build\lib.win32-2.7\spotify
creating build\lib.win32-2.7\spotify\audiosink
copying spotify\audiosink\alsa.py -> build\lib.win32-2.7\spotify\audiosink
copying spotify\audiosink\gstreamer.py -> build\lib.win32-2.7\spotify\audiosink
copying spotify\audiosink\oss.py -> build\lib.win32-2.7\spotify\audiosink
copying spotify\audiosink\portaudio.py -> build\lib.win32-2.7\spotify\audiosink
copying spotify\audiosink\__init__.py -> build\lib.win32-2.7\spotify\audiosink
creating build\lib.win32-2.7\spotify\manager
copying spotify\manager\container.py -> build\lib.win32-2.7\spotify\manager
copying spotify\manager\playlist.py -> build\lib.win32-2.7\spotify\manager
copying spotify\manager\session.py -> build\lib.win32-2.7\spotify\manager
copying spotify\manager\__init__.py -> build\lib.win32-2.7\spotify\manager
running build_ext
building 'spotify._spotify' extension
creating build\temp.win32-2.7
creating build\temp.win32-2.7\Release
creating build\temp.win32-2.7\Release\src
C:\MinGW\bin\gcc.exe -mno-cygwin -mdll -O -Wall -Isrc -IC:\Python27\include -IC:\Python27\PC -c src/module.c -o build\temp.win32-2.7\Release\src\module.o
src/module.c:3:28: libspotify/api.h: No such file or directory
In file included from src/module.c:5:
src/artist.h:2: error: syntax error before "sp_artist"
src/artist.h:2: warning: no semicolon at end of struct or union
src/artist.h:3: warning: type defaults to `int' in declaration of `Artist'
src/artist.h:3: warning: data definition has no type or storage class
src/artist.h:9: error: syntax error before '*' token
In file included from src/module.c:6:
src/artistbrowser.h:5: error: syntax error before "sp_artistbrowse"
src/artistbrowser.h:5: warning: no semicolon at end of struct or union
src/artistbrowser.h:6: warning: type defaults to `int' in declaration of `ArtistBrowser'
src/artistbrowser.h:6: warning: data definition has no type or storage class
src/artistbrowser.h:13: error: syntax error before '*' token
In file included from src/module.c:7:
src/album.h:2: error: syntax error before "sp_album"
src/album.h:2: warning: no semicolon at end of struct or union
src/album.h:3: warning: type defaults to `int' in declaration of `Album'
src/album.h:3: warning: data definition has no type or storage class
src/album.h:9: error: syntax error before '*' token
In file included from src/module.c:8:
src/albumbrowser.h:4: error: syntax error before "sp_albumbrowse"
src/albumbrowser.h:4: warning: no semicolon at end of struct or union
src/albumbrowser.h:6: error: syntax error before '}' token
src/albumbrowser.h:6: warning: type defaults to `int' in declaration of `AlbumBrowser'
src/albumbrowser.h:6: warning: data definition has no type or storage class
src/albumbrowser.h:13: error: syntax error before '*' token
In file included from src/module.c:9:
src/link.h:2: error: syntax error before "sp_link"
src/link.h:2: warning: no semicolon at end of struct or union
src/link.h:3: warning: type defaults to `int' in declaration of `Link'
src/link.h:3: warning: data definition has no type or storage class
In file included from src/module.c:10:
src/playlist.h:5: error: syntax error before "sp_playlist"
src/playlist.h:5: warning: no semicolon at end of struct or union
src/playlist.h:6: warning: type defaults to `int' in declaration of `Playlist'
src/playlist.h:6: warning: data definition has no type or storage class
src/playlist.h:14: error: syntax error before "sp_playlist_callbacks"
src/playlist.h:14: warning: no semicolon at end of struct or union
src/playlist.h:17: error: syntax error before '}' token
src/playlist.h:17: warning: type defaults to `int' in declaration of `playlist_callback'
src/playlist.h:17: warning: data definition has no type or storage class
src/playlist.h:21: error: syntax error before "sp_playlist"
src/playlist.h:21: warning: no semicolon at end of struct or union
src/playlist.h:22: warning: type defaults to `int' in declaration of `callbacks'
src/playlist.h:22: warning: data definition has no type or storage class
src/playlist.h:23: error: conflicting types for 'next'
src/playlist.h:16: error: previous declaration of 'next' was here
src/playlist.h:24: error: syntax error before '}' token
src/playlist.h:24: warning: type defaults to `int' in declaration of `pl_cb_entry'
src/playlist.h:24: warning: data definition has no type or storage class
src/playlist.h:26: error: syntax error before '*' token
In file included from src/module.c:11:
src/playlistcontainer.h:5: error: syntax error before "sp_playlistcontainer"
src/playlistcontainer.h:5: warning: no semicolon at end of struct or union
src/playlistcontainer.h:6: warning: type defaults to `int' in declaration of `PlaylistContainer'
src/playlistcontainer.h:6: warning: data definition has no type or storage class
src/playlistcontainer.h:12: error: syntax error before '*' token
src/playlistcontainer.h:16: error: syntax error before "sp_playlistcontainer_callbacks"
src/playlistcontainer.h:16: warning: no semicolon at end of struct or union
src/playlistcontainer.h:18: error: conflicting types for 'next'
src/playlist.h:23: error: previous declaration of 'next' was here
src/playlistcontainer.h:18: error: conflicting types for 'next'
src/playlist.h:23: error: previous declaration of 'next' was here
src/playlistcontainer.h:19: error: syntax error before '}' token
src/playlistcontainer.h:19: warning: type defaults to `int' in declaration of `playlistcontainer_callback'
src/playlistcontainer.h:19: warning: data definition has no type or storage class
src/playlistcontainer.h:23: error: syntax error before "sp_playlistcontainer"
src/playlistcontainer.h:23: warning: no semicolon at end of struct or union
src/playlistcontainer.h:24: warning: type defaults to `int' in declaration of `callbacks'
src/playlistcontainer.h:24: warning: data definition has no type or storage class
src/playlistcontainer.h:25: error: conflicting types for 'next'
src/playlistcontainer.h:18: error: previous declaration of 'next' was here
src/playlistcontainer.h:25: error: conflicting types for 'next'
src/playlist.h:23: error: previous declaration of 'next' was here
src/playlistcontainer.h:26: error: syntax error before '}' token
src/playlistcontainer.h:26: warning: type defaults to `int' in declaration of `plc_cb_entry'
src/playlistcontainer.h:26: warning: data definition has no type or storage class
In file included from src/module.c:12:
src/playlistfolder.h:7: error: syntax error before "sp_uint64"
src/playlistfolder.h:7: warning: no semicolon at end of struct or union
src/playlistfolder.h:8: warning: type defaults to `int' in declaration of `_type'
src/playlistfolder.h:8: warning: data definition has no type or storage class
src/playlistfolder.h:9: warning: type defaults to `int' in declaration of `PlaylistFolder'
src/playlistfolder.h:9: warning: data definition has no type or storage class
src/playlistfolder.h:15: error: syntax error before '*' token
In file included from src/module.c:13:
src/search.h:2: error: syntax error before "sp_search"
src/search.h:2: warning: no semicolon at end of struct or union
src/search.h:3: warning: type defaults to `int' in declaration of `Results'
src/search.h:3: warning: data definition has no type or storage class
src/search.h:9: error: syntax error before '*' token
In file included from src/module.c:14:
src/session.h:3: error: syntax error before "sp_session"
src/session.h:3: warning: no semicolon at end of struct or union
src/session.h:5: error: syntax error before '}' token
src/session.h:5: warning: type defaults to `int' in declaration of `Session'
src/session.h:5: warning: data definition has no type or storage class
src/session.h:7: error: syntax error before '*' token
src/session.h:7: warning: type defaults to `int' in declaration of `g_session'
src/session.h:7: warning: data definition has no type or storage class
src/session.h:16: error: syntax error before '*' token
In file included from src/module.c:15:
src/toplistbrowser.h:3: error: syntax error before "sp_toplistbrowse"
src/toplistbrowser.h:3: warning: no semicolon at end of struct or union
src/toplistbrowser.h:4: warning: type defaults to `int' in declaration of `ToplistBrowser'
src/toplistbrowser.h:4: warning: data definition has no type or storage class
src/toplistbrowser.h:10: error: syntax error before '*' token
In file included from src/module.c:16:
src/track.h:2: error: syntax error before "sp_track"
src/track.h:2: warning: no semicolon at end of struct or union
src/track.h:3: warning: type defaults to `int' in declaration of `Track'
src/track.h:3: warning: data definition has no type or storage class
src/track.h:9: error: syntax error before '*' token
In file included from src/module.c:17:
src/image.h:2: error: syntax error before "sp_image"
src/image.h:2: warning: no semicolon at end of struct or union
src/image.h:3: warning: type defaults to `int' in declaration of `Image'
src/image.h:3: warning: data definition has no type or storage class
src/image.h:9: error: syntax error before '*' token
In file included from src/module.c:18:
src/user.h:3: error: syntax error before "sp_user"
src/user.h:3: warning: no semicolon at end of struct or union
src/user.h:4: warning: type defaults to `int' in declaration of `User'
src/user.h:4: warning: data definition has no type or storage class
src/user.h:10: error: syntax error before '*' token
src/module.c: In function `init_spotify':
src/module.c:70: error: `SPOTIFY_API_VERSION' undeclared (first use in this function)
src/module.c:70: error: (Each undeclared identifier is reported only once
src/module.c:70: error: for each function it appears in.)
error: command 'gcc' failed with exit status 1

Random deadlocks during notify_main_thread() callback

I didn't really know what to name this issue because the problem is actually potentially in other places but this is the one place I know it exists. Take a look at the following backtraces:

 Thread 13

 (gdb) bt 10
 #0  0x9302191a in __psynch_mutexwait ()
 #1  0x98e4c13b in pthread_mutex_lock ()
 #2  0x012bc769 in g_session ()
 #3  0x012bc8bd in g_session ()
 #4  0x0132a9f7 in g_session ()
 #5  0x01331dfa in g_session ()
 #6  0x012f658f in g_session ()
 #7  0x013a6ff0 in sp_albumbrowse_create ()
 #8  0x0125d802 in AlbumBrowser_new ()
 #9  0x0008f76a in type_call (type=0x1264a98, args=0x14a6328, kwds=0x0) at Objects/typeobject.c:422

 Thread 12

 (gdb) bt
 #0  0x930218e2 in __psynch_cvwait ()
 #1  0x98e4b220 in _pthread_cond_wait ()
 #2  0x98ed10a1 in pthread_cond_wait$UNIX2003 ()
 #3  0x0012ef20 in PyThread_acquire_lock (lock=0x7a97f0e0, waitflag=1) at thread_pthread.h:452
 #4  0x000df971 in PyEval_RestoreThread (tstate=0x7c267f30) at Python/ceval.c:364
 #5  0x0011901d in PyGILState_Ensure () at Python/pystate.c:592
 #6  0x0125bb22 in notify_main_thread ()
 #7  0x012bc5eb in g_session ()
 #8  0x012dd6f7 in g_session ()
 #9  0x012d0ceb in g_session ()
 #10 0x012d47a1 in g_session ()
 #11 0x012d2dd9 in g_session ()
 #12 0x012cccf3 in g_session ()
 #13 0x012ce6c9 in g_session ()
 #14 0x0137be72 in g_session ()
 #15 0x0137be10 in g_session ()
 #16 0x0137daa9 in g_session ()
 #17 0x0137d8bf in g_session ()
 #18 0x012a1228 in g_session ()
 #19 0x98e46557 in _pthread_start ()
 #20 0x98e30cee in thread_start ()

The problem is that the Spofify notify callback is being invoked whilst the GIL is held by another thread: that thread in turn is blocking on something in g_session, which I can only assume is being held by the notify thread.

Now you could easily argue that libspotify should guarantee that this will never happen, but alas, that doesn't seem to be the case.

One possible fix for this would be to release the GIL before making a Spotify API call and re-aquire it when the call finishes. It's not the prettiest of things but it's probably the only safe thing to do.

For what it's worth I have spent hours and hours trying to track this down - it happens extremely regularly in my application (I'm the maintainer of the Plex Spotify plugin) - I'm pretty sure this isn't the only case where this is possible.

If you agree that this is a good solution to the issue I'm happy to run up a pull-request.

Support libspotify 12

The develop branch of pyspotify already works with libspotify 12, but libmockspotify and the pyspotify test suite needs to be updated to work with libspotify 12 before pyspotify 1.8 can be released.

@bok Do you have time to have a look at it?

Skip / Scrub to timecode?

Is there an api hook available to skip or scrub to a certain time within a track? Happy to contribute code.

Offline login / Offline playlists

Hi,

Discussed this on IRC a few days back and was asked to request it here;

Libspotify now features offline logins and offline synchronization of playlists, allowing libspotify to play selected tracks/playlist without requiring immediate internet connection. This is useful for everything from mobile devices to rigs with poor internet connections or; in my case; a carputer system.

I'm no expert in either libspotify or pyspotify but seeing as how libspotfy essentially handles all offline synchronization stuff internally, I believe all that would be required to implement this in pyspotify is binding sp_playlist_set_offline_mode() and related callbacks and status get* functions. If interest is dull I could try to implement this myself after some self tutoring around the pyspotify code.

/ bjorn

Handle local files without segfaulting

One of my Spotify playlists was "infected" by a local file. This resulted in following problem in handling of artist in pyspotify. Exact details of problem are a bit fuzzy, but problem seems to be with the artist object when calling name. There is also a related mopidy issue here which I will take care of.

http://open.spotify.com/user/adamcik/playlist/0ii9t5LUsjgTL7XY0s6mqM can be used to reproduce.

ERROR    2011-04-25 00:38:11,361 [4297:SpotifySMThread] mopidy.utils.process
  'utf8' codec can't decode bytes in position 1-4: invalid data
Traceback (most recent call last):
  File "/home/adamcik/dev/mopidy/mopidy/utils/process.py", line 21, in run
    self.run_inside_try()
  File "/home/adamcik/dev/mopidy/mopidy/backends/spotify/session_manager.py", line 40, in run_inside_try
    self.connect()
  File "/usr/local/lib/python2.6/dist-packages/pyspotify-1.1-py2.6-linux-i686.egg/spotify/manager.py", line 44, in connect
    self.loop(sess) # returns on disconnect
  File "/usr/local/lib/python2.6/dist-packages/pyspotify-1.1-py2.6-linux-i686.egg/spotify/manager.py", line 54, in loop
    self.timer = threading.Timer(timeout/1000.0, self.awoken.set)
  File "/usr/lib/python2.6/threading.py", line 711, in Timer
    return _Timer(*args, **kwargs)
  File "/usr/lib/python2.6/threading.py", line 722, in __init__
    Thread.__init__(self)
  File "/usr/lib/python2.6/threading.py", line 436, in __init__
    self.__daemonic = self._set_daemon()
  File "/usr/lib/python2.6/threading.py", line 448, in _set_daemon
    return current_thread().daemon
  File "/usr/lib/python2.6/threading.py", line 810, in currentThread
    return _active[_get_ident()]
  File "/home/adamcik/dev/mopidy/mopidy/backends/spotify/session_manager.py", line 73, in metadata_updated
    self.refresh_stored_playlists()
  File "/home/adamcik/dev/mopidy/mopidy/backends/spotify/session_manager.py", line 127, in refresh_stored_playlists
    SpotifyTranslator.to_mopidy_playlist(spotify_playlist))
  File "/home/adamcik/dev/mopidy/mopidy/backends/spotify/translator.py", line 60, in to_mopidy_playlist
    tracks=[cls.to_mopidy_track(t) for t in spotify_playlist],
  File "/home/adamcik/dev/mopidy/mopidy/backends/spotify/translator.py", line 41, in to_mopidy_track
    artists=[cls.to_mopidy_artist(a) for a in spotify_track.artists()],
  File "/home/adamcik/dev/mopidy/mopidy/backends/spotify/translator.py", line 19, in to_mopidy_artist
    name=spotify_artist.name().decode(ENCODING),
  File "/home/adamcik/dev/mopidy/lib/python2.6/encodings/utf_8.py", line 16, in decode
    return codecs.utf_8_decode(input, errors, True)
UnicodeDecodeError: 'utf8' codec can't decode bytes in position 1-4: invalid data
zsh: segmentation fault  GST_DEBUG=2 python mopidy --verbose

Expose playlist type

It would be nice with support for checking the type of a playlist. E.g. whether it is a regular playlist or a playlist folder start/end boundary.

This information is exposed by libspotify through sp_playlistcontainer_playlist_type.

Implement sp_playlist_has_pending_changes

I'm adding (and removing) tracks from a playlist and want to quit as soon as this is synced. This can be done by using Playlist. add_playlist_state_changed_callback() together with Playlist.has_pending_changes().

However the latter is not implemented but I think it would be simple given how simple the other accessor methods are.

How to save changes on playlists?

I'm using the latest alpha release which is available over pip (2.0.0.a1)

I followed the instructions on the documentation but I don't know how to save my changes.
I try to create a new playlist, but it seems to have no impact on my playlists...

import spotify
import threading

config = spotify.Config()
config.user_agent = 'My awesome Spotify client'
config.tracefile = b'/tmp/libspotify-trace.log'
session = spotify.Session(config=config)

session.login('username', 'password')

logged_in_event = threading.Event()

def logged_in_listener(session, error_type):
    logged_in_event.set()

def get_playlists(session):
    playlists = session.playlist_container
    if not playlists.is_loaded:
        playlists.load()
    return playlists

session.on(spotify.SessionEvent.LOGGED_IN, logged_in_listener)

while not logged_in_event.wait(0.1):
    session.process_events()

playlists = get_playlists(session)
print len(playlists)

search = session.search('mas').load()
track = search.tracks[0].load()

playlist = session.playlist_container.add_new_playlist('My Test Playlist')
tracks = [track]
playlist.add_tracks(tracks)

ALSAAudioError: File descriptor in bad state

Hi, I getting the following on a RaspberryPI with version 1.10 using the jukebox.py sample app when it switching track. The next command works but not when it automatically switches.

jukebox> play 0
Loading playlist theshopbox
Loading Sad-Eyed Lady Of The Lowlands from theshopbox
Playing
jukebox> next
Stopping
Loading Bleecker Street from theshopbox
Playing
jukebox> next
Stopping
Loading Son Of A Preacher Man from theshopbox
Playing
jukebox> Traceback (most recent call last):
  File "jukebox.py", line 461, in <module>
    session_m.connect()
  File "/usr/local/lib/python2.7/dist-packages/spotify/manager/session.py", line 81, in connect
    self.loop(self.session) # returns on logged out
  File "/usr/local/lib/python2.7/dist-packages/spotify/manager/session.py", line 97, in loop
    session, *message['args'])
  File "jukebox.py", line 397, in music_delivery_safe
    return self.audio.music_delivery(*args, **kwargs)
  File "/usr/local/lib/python2.7/dist-packages/spotify/audiosink/alsa.py", line 23, in music_delivery
    self._call_if_needed(self._device.setperiodsize, num_frames)
  File "/usr/local/lib/python2.7/dist-packages/spotify/audiosink/__init__.py", line 127, in _call_if_needed
    func(*args, **kwargs)
alsaaudio.ALSAAudioError: File descriptor in bad state

Error when compiling on Arch on the Raspberry Pi

I am getting an error when trying to install the development branch of pyspotify with libspotify 12

running install
running build
running build_py
creating build
creating build/lib.linux-armv6l-3.3
creating build/lib.linux-armv6l-3.3/spotify
copying spotify/__init__.py -> build/lib.linux-armv6l-3.3/spotify
creating build/lib.linux-armv6l-3.3/spotify/manager
copying spotify/manager/container.py -> build/lib.linux-armv6l-3.3/spotify/manager
copying spotify/manager/playlist.py -> build/lib.linux-armv6l-3.3/spotify/manager
copying spotify/manager/session.py -> build/lib.linux-armv6l-3.3/spotify/manager
copying spotify/manager/__init__.py -> build/lib.linux-armv6l-3.3/spotify/manager
creating build/lib.linux-armv6l-3.3/spotify/audiosink
copying spotify/audiosink/alsa.py -> build/lib.linux-armv6l-3.3/spotify/audiosink
copying spotify/audiosink/portaudio.py -> build/lib.linux-armv6l-3.3/spotify/audiosink
copying spotify/audiosink/oss.py -> build/lib.linux-armv6l-3.3/spotify/audiosink
copying spotify/audiosink/gstreamer.py -> build/lib.linux-armv6l-3.3/spotify/audiosink
copying spotify/audiosink/__init__.py -> build/lib.linux-armv6l-3.3/spotify/audiosink
running build_ext
building 'spotify._spotify' extension
creating build/temp.linux-armv6l-3.3
creating build/temp.linux-armv6l-3.3/src
gcc -pthread -Wno-unused-result -DNDEBUG -g -fwrapv -O3 -Wall -Wstrict-prototypes -march=armv6 -mfloat-abi=hard -mfpu=vfp -O2 -pipe -fstack-protector --param=ssp-buffer-size=4 -D_FORTIFY_SOURCE=2 -fPIC -Isrc -I/usr/include/python3.3m -c src/module.c -o build/temp.linux-armv6l-3.3/src/module.o
src/module.c: In function 'init_spotify':
src/module.c:35:9: warning: 'return' with no value, in function returning non-void [-Wreturn-type]
src/module.c:37:9: warning: 'return' with no value, in function returning non-void [-Wreturn-type]
src/module.c:39:9: warning: 'return' with no value, in function returning non-void [-Wreturn-type]
src/module.c:41:9: warning: 'return' with no value, in function returning non-void [-Wreturn-type]
src/module.c:43:9: warning: 'return' with no value, in function returning non-void [-Wreturn-type]
src/module.c:45:9: warning: 'return' with no value, in function returning non-void [-Wreturn-type]
src/module.c:47:9: warning: 'return' with no value, in function returning non-void [-Wreturn-type]
src/module.c:49:9: warning: 'return' with no value, in function returning non-void [-Wreturn-type]
src/module.c:51:9: warning: 'return' with no value, in function returning non-void [-Wreturn-type]
src/module.c:53:9: warning: 'return' with no value, in function returning non-void [-Wreturn-type]
src/module.c:55:9: warning: 'return' with no value, in function returning non-void [-Wreturn-type]
src/module.c:57:9: warning: 'return' with no value, in function returning non-void [-Wreturn-type]
src/module.c:59:5: warning: implicit declaration of function 'Py_InitModule' [-Wimplicit-function-declaration]
src/module.c:59:7: warning: assignment makes pointer from integer without a cast [enabled by default]
src/module.c:61:9: warning: 'return' with no value, in function returning non-void [-Wreturn-type]
gcc -pthread -Wno-unused-result -DNDEBUG -g -fwrapv -O3 -Wall -Wstrict-prototypes -march=armv6 -mfloat-abi=hard -mfpu=vfp -O2 -pipe -fstack-protector --param=ssp-buffer-size=4 -D_FORTIFY_SOURCE=2 -fPIC -Isrc -I/usr/include/python3.3m -c src/session.c -o build/temp.linux-armv6l-3.3/src/session.o
src/session.c:395:5: warning: missing braces around initializer [-Wmissing-braces]
src/session.c:395:5: warning: (near initialization for 'SessionType.ob_base.ob_base') [-Wmissing-braces]
src/session.c:396:5: warning: initialization makes integer from pointer without a cast [enabled by default]
src/session.c:396:5: warning: (near initialization for 'SessionType.tp_basicsize') [enabled by default]
src/session.c:414:5: warning: initialization makes pointer from integer without a cast [enabled by default]
src/session.c:414:5: warning: (near initialization for 'SessionType.tp_doc') [enabled by default]
src/session.c:415:5: warning: initialization from incompatible pointer type [enabled by default]
src/session.c:415:5: warning: (near initialization for 'SessionType.tp_traverse') [enabled by default]
src/session.c:422:5: warning: initialization from incompatible pointer type [enabled by default]
src/session.c:422:5: warning: (near initialization for 'SessionType.tp_members') [enabled by default]
src/session.c:423:5: warning: initialization from incompatible pointer type [enabled by default]
src/session.c:423:5: warning: (near initialization for 'SessionType.tp_getset') [enabled by default]
src/session.c:433:1: warning: initialization from incompatible pointer type [enabled by default]
src/session.c:433:1: warning: (near initialization for 'SessionType.tp_free') [enabled by default]
src/session.c: In function 'music_delivery':
src/session.c:623:5: warning: implicit declaration of function 'PyBuffer_FromMemory' [-Wimplicit-function-declaration]
src/session.c:623:26: warning: initialization makes pointer from integer without a cast [enabled by default]
src/session.c:636:5: warning: implicit declaration of function 'PyInt_Check' [-Wimplicit-function-declaration]
src/session.c:637:9: warning: implicit declaration of function 'PyInt_AsLong' [-Wimplicit-function-declaration]
src/session.c: In function 'session_connect':
src/session.c:910:9: warning: implicit declaration of function 'PyString_AS_STRING' [-Wimplicit-function-declaration]
src/session.c:910:14: warning: assignment makes pointer from integer without a cast [enabled by default]
gcc -pthread -Wno-unused-result -DNDEBUG -g -fwrapv -O3 -Wall -Wstrict-prototypes -march=armv6 -mfloat-abi=hard -mfpu=vfp -O2 -pipe -fstack-protector --param=ssp-buffer-size=4 -D_FORTIFY_SOURCE=2 -fPIC -Isrc -I/usr/include/python3.3m -c src/link.c -o build/temp.linux-armv6l-3.3/src/link.o
src/link.c: In function 'Link_dealloc':
src/link.c:41:9: error: 'Link' has no member named 'ob_type'
src/link.c: At top level:
src/link.c:267:5: warning: missing braces around initializer [-Wmissing-braces]
src/link.c:267:5: warning: (near initialization for 'LinkType.ob_base.ob_base') [-Wmissing-braces]
src/link.c:268:5: warning: initialization makes integer from pointer without a cast [enabled by default]
src/link.c:268:5: warning: (near initialization for 'LinkType.tp_basicsize') [enabled by default]
src/link.c:271:5: warning: initialization from incompatible pointer type [enabled by default]
src/link.c:271:5: warning: (near initialization for 'LinkType.tp_print') [enabled by default]
src/link.c:282:5: warning: initialization from incompatible pointer type [enabled by default]
src/link.c:282:5: warning: (near initialization for 'LinkType.tp_getattro') [enabled by default]
src/link.c:286:5: warning: initialization makes pointer from integer without a cast [enabled by default]
src/link.c:286:5: warning: (near initialization for 'LinkType.tp_doc') [enabled by default]
src/link.c:287:5: warning: initialization from incompatible pointer type [enabled by default]
src/link.c:287:5: warning: (near initialization for 'LinkType.tp_traverse') [enabled by default]
src/link.c:294:5: warning: initialization from incompatible pointer type [enabled by default]
src/link.c:294:5: warning: (near initialization for 'LinkType.tp_members') [enabled by default]
src/link.c:295:5: warning: initialization from incompatible pointer type [enabled by default]
src/link.c:295:5: warning: (near initialization for 'LinkType.tp_getset') [enabled by default]
src/link.c:304:5: warning: initialization from incompatible pointer type [enabled by default]
src/link.c:304:5: warning: (near initialization for 'LinkType.tp_free') [enabled by default]
error: command 'gcc' failed with exit status 1

Segfault on Ubuntu 10.4 with libspotify7

Quickfix/workaround: downgrade to libspotify6.

Problem can be provoked simply by doing a search or adding a track via telnet on a clean 10.4 machine that just got mopidy etc via apt. See strace excerpt below:

...
stat64("/usr/lib/python2.6/encodings/string_escape", 0xbfd60f88) = -1 ENOENT (No such file or directory)
open("/usr/lib/python2.6/encodings/string_escape.so", O_RDONLY|O_LARGEFILE) = -1 ENOENT (No such file or directory)
open("/usr/lib/python2.6/encodings/string_escapemodule.so", O_RDONLY|O_LARGEFILE) = -1 ENOENT (No such file or directory)
open("/usr/lib/python2.6/encodings/string_escape.py", O_RDONLY|O_LARGEFILE) = 24
fstat64(24, {st_mode=S_IFREG|0644, st_size=953, ...}) = 0
open("/usr/lib/python2.6/encodings/string_escape.pyc", O_RDONLY|O_LARGEFILE) = 25
fstat64(25, {st_mode=S_IFREG|0644, st_size=2069, ...}) = 0
mmap2(NULL, 4096, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0xb774e000
read(25, "\321\362\r\n\24m\310Kc\0\0\0\0\0\0\0\0\4\0\0\0@\0\0\0s\242\0\0\0d\0"..., 4096) = 2069
fstat64(25, {st_mode=S_IFREG|0644, st_size=2069, ...}) = 0
read(25, "", 4096)                      = 0
close(25)                               = 0
munmap(0xb774e000, 4096)                = 0
close(24)                               = 0
socket(PF_FILE, SOCK_STREAM, 0)         = 24
gettimeofday({1299451244, 870612}, NULL) = 0
connect(24, {sa_family=AF_FILE, path="/tmp/pymp-RpQEtu/listener-qkcoen"}, 34) = 0
dup(24)                                 = 23
close(24)                               = 0
read(23, "\0\0\0\37", 4)                = 4
read(23, "#CHALLENGE#\231 :\237a\202\327\260i*\360\t\7\375\353:\312}\t\263", 31) = 31
write(23, "\0\0\0\20\16\2031@dZH\207
+++ killed by SIGSEGV +++
zsh: segmentation fault  strace mopidy -v

Can't login to Spotify after upgrade to Ubuntu 12.04

After upgrading ubuntu to 12.04 mopidy will no longer start.

using mopidy 0.7.2, pyspotify 1.7.

$ python -c "import spotify; print (spotify.__version__, spotify.__file__)"
('1.7', '/usr/lib/python2.7/dist-packages/spotify/__init__.pyc')

Mopidy log:

INFO     Starting Mopidy 0.7.2 on Linux-3.2.0-24-generic-i686-with-Ubuntu-12.04-precise CPython 2.7.3
INFO     Mopidy uses SPOTIFY(R) CORE
ERROR    No credentials stored
Traceback (most recent call last):
  File "/usr/local/lib/python2.7/dist-packages/mopidy/utils/process.py", line 53, in run
    self.run_inside_try()
  File "/usr/local/lib/python2.7/dist-packages/mopidy/backends/spotify/session_manager.py", line 47, in run_inside_try
    self.connect()
  File "/usr/lib/python2.7/dist-packages/spotify/manager/session.py", line 53, in connect
    session = spotify.connect(self)
SpotifyError: No credentials stored
INFO     MPD server running at [::ffff:0.0.0.0]:6600
INFO     Last.fm scrobbler not started
ImportError: could not import gtk.gdk
INFO     Connected to D-Bus
ERROR    MPRIS frontend setup failed ('module' object has no attribute 'Server')

Segfault in music_delivery()

Since I upgraded from pyspotify cd827fd (v1.1+mopidy20110405) to c6e2a02 I've experienced segfaults more times than not when pressing CTRL+C to exit Mopidy (which uses pyspotify) while it plays music.

gdb on the core dump shows that a NULL pointer is passed to PyObject_TypeCheck:

Core was generated by `python mopidy'.
Program terminated with signal 11, Segmentation fault.
#0  0x00007fd6c88056d2 in music_delivery (session=0x1eb21a0, format=0x7fd6c8190a20, frames=0x2fec568, num_frames=2048) at src/session.c:486
486     if(PyObject_TypeCheck(c, &PyInt_Type)) {
(gdb) print c
$1 = 0x0

I guess this is caused by the program exiting in the middle of the execution of the Python callback music_delivery, which thus doesn't return an int/long to the calling C thread.

Possible fix, as far as I can tell:

diff --git a/src/session.c b/src/session.c
index 85066a9..c44b05d 100644
--- a/src/session.c
+++ b/src/session.c
@@ -483,7 +483,7 @@ static int music_delivery(sp_session *session, const sp_audi
     PyObject *client = (PyObject *)sp_session_userdata(session);
     PyObject *c= PyObject_CallMethod(client, "music_delivery", "OOiiiii", psess
     int consumed = num_frames; // assume all consumed
-    if(PyObject_TypeCheck(c, &PyInt_Type)) {
+    if(c != NULL && PyObject_TypeCheck(c, &PyInt_Type)) {
        consumed = (int)PyInt_AsLong(c);
     }
     Py_DECREF(pyframes);

Link#as_playlist

There is no support for loading any playlist, i.e. sp_playlist_create(g_session, link).

I'm quite the moron when it comes to both Python and C but still tried to add the feature in src/link.c like this:

10a11
> #include "session.h"
205a207,225
> Link_as_playlist(Link * self)
> {
>     if (!g_session) {
>         PyErr_SetString(SpotifyError, "Not logged in.");
>         return NULL;
>     }
> 
>     sp_playlist *p = sp_playlist_create(g_session, self->_link);
> 
>     if (!p) {
>         PyErr_SetString(SpotifyError, "Not a playlist link");
>         return NULL;
>     }
>     PyObject *playlist = Playlist_FromSpotify(p);
> 
>     return playlist;
> }
> 
> static PyObject *
249a270,273
>     {"as_playlist",
>      (PyCFunction)Link_as_playlist,
>      METH_NOARGS,
>      "Return this link as a Playlist object"},

But I'm getting errors that I believe are coming from pyspotify and not libspotify. I suppose sp_playlist_create does not return the sort of data I'm expecting it to.

It would be awesome if someone could add this feature.

segfault on invoking session methods

I am getting segfaults after invoking any session methods that use callbacks after I have logged in. My code is as below, I am getting a segfault right when I invoke the method "self.session.search(artist, search_finished, userdata=number)"

import logging
import os
import sys
import time
import pprint
import threading
from spotify import Playlist, PlaylistContainer
from spotify.audiosink import import_audio_sink
from threading import *
from spotify.manager import (SpotifySessionManager, SpotifyPlaylistManager, SpotifyContainerManager)

AudioSink = import_audio_sink()

class SpotifyListenerThread(SpotifySessionManager, threading.Thread):

    def __init__(self, *a, **kw):
        threading.Thread.__init__(self)
        self.pp = pprint.PrettyPrinter(indent=4)
        SpotifySessionManager.__init__(self, *a, **kw)
        self.audio = AudioSink(backend=self)
        self.playing = False
        self.connected = Event()
        self.track_playing = None
        self.jukebox_empty = True
        self.jukebox_queue = []
        self.pp.pprint("Logging in, please wait...")

    def run(self):
        self.connect()

    def logged_in(self, session, error):
        if error:
            self.pp.pprint(error)
            return
        self.session = session
        self.pp.pprint("Logged in")
        #TODO Notify spot that we are ready
        self.connected.set()

    def play_artist_toplist(self, artist, number):

        def search_finished(results, userdata):
            self.pp.pprint("Search finished")
            self.results = results
            artists = self.results.artists()
            tracks = self.results.tracks() 

            # First artist and top number songs
            # TODO do something with the artist
            i = 0
            for track in tracks:
                print "Added track %s to jukebox " % track.name()
                self.jukebox_queue.append(track)
                if i >= userdata:
                    break
                i += 1
            self.play_jukebox()

        self.session.search(artist, search_finished, userdata=number)

    def test_and_set_jukebox_empty(self):
        if len(self.jukebox_queue) == 0:
            self.jukebox_empty = True
            return True
        self.jukebox_empty = False
        return False

    def play_jukebox(self):
        if self.test_and_set_jukebox_empty():
            return

        # Load track if jukebox is not playing
        if not self.playing == True:
            track = self.jukebox_queue.pop(0)
            self.session.load(track)

            print "Loading %s " % track.name()
            self.track_playing = track        
            self.audio.start()
            self.session.play(1)
            print "Playing"
            self.playing = True

    def music_delivery_safe(self, *args, **kwargs):
        return self.audio.music_delivery(*args, **kwargs)

    def end_of_track(self, session):
        print "end of track called"
        self.audio.end_of_track()
        #self.audio.stop()
        #self.session.play(0)
        self.playing = False
        self.play_jukebox()

    def thread_process_event(self, subject, message):
        self.connected.wait()
        self.pp.pprint("Recieved event %s %s" % (subject, message) )
        self.play_artist_toplist(message, 5)

class SpotifyListener:

    def trace(self, frame, event, arg):
        print "%s, %s:%d" % (event, frame.f_code.co_filename, frame.f_lineno)

    def __init__(self):
        # Stupid segfaults
        #sys.settrace(self.trace)
        username = "username"
        password = "password"
        self.listenerthread = SpotifyListenerThread(username, password, False)
        self.listenerthread.start()


    def process_event(self, spot_subject, spot_data):
        self.listenerthread.thread_process_event(spot_subject, spot_data)
        # Adding join here since we are called from main
        self.listenerthread.join()

if __name__ == '__main__':

    #logging.basicConfig(level=logging.DEBUG)
    session_m = SpotifyListener()
    print "will process event spot: Zero 7"
    session_m.process_event("spot:", "Zero 7")

Move `Session.is_local(track)` to `Track.is_local()`

Since we have the Spotify session as a global variable, and we moved Session.is_available(track) to Track.availability(), we should change Session.is_local(track) to Track.is_local() for consistency.

Would be nice to have this done before the release of 1.6, so both changes happen in the same release.

Upgrade to libspotify 0.0.8

Should be done before the v1.2 release of pyspotify, even though we probably won't support the new features of 0.0.8 yet.

Skipping incompatible /usr/local/lib/libspotify.so error when installing

I get this error when trying to install on Ubuntu 12.04 with Python 2.7.3 I have libspotify 12.1.51 installed. I have python-dev installed as well. Am I missing something by chance?

/usr/bin/ld: skipping incompatible /usr/local/lib/libspotify.so when searching for -lspotify
/usr/bin/ld: cannot find -lspotify
collect2: error: ld returned 1 exit status
error: command 'gcc' failed with exit status 1

pyspotify does not work with libspotify 12

Subject was: Error compiling (ArchLinux with Pythonbrew)

I keep on getting this error on attempt to install with sudo pip install -U pyspotify

/home/humza/.pythonbrew/pythons/Python-2.7.2/bin/pip run on Sun Jun  3 19:30:42 2012
Downloading/unpacking pyspotify

  Getting page http://pypi.python.org/simple/pyspotify
  URLs to search for versions for pyspotify:
  * http://pypi.python.org/simple/pyspotify/
  Getting page http://pyspotify.mopidy.com/
  Analyzing links from page http://pypi.python.org/simple/pyspotify/
    Found link http://pypi.python.org/packages/source/p/pyspotify/pyspotify-1.3.tar.gz#md5=1df2037ee31651a6113f1c646c6c83a1 (from http://pypi.python.org/simple/pyspotify/), version: 1.3
    Found link http://pypi.python.org/packages/source/p/pyspotify/pyspotify-1.6.1.tar.gz#md5=88b3bb16a061d4c3868d5ffdee0d61fd (from http://pypi.python.org/simple/pyspotify/), version: 1.6.1
    Found link http://pypi.python.org/packages/source/p/pyspotify/pyspotify-1.2.tar.gz#md5=17d5d27c7582785fb8e0fb9f963e0d3a (from http://pypi.python.org/simple/pyspotify/), version: 1.2
    Found link http://pypi.python.org/packages/source/p/pyspotify/pyspotify-1.6.tar.gz#md5=1c4ff2791fdd6579d27b626c0331ff5a (from http://pypi.python.org/simple/pyspotify/), version: 1.6
    Found link http://pypi.python.org/packages/source/p/pyspotify/pyspotify-1.5.tar.gz#md5=2e93ae359c3f16e64794c2b18a1b99bc (from http://pypi.python.org/simple/pyspotify/), version: 1.5
    Found link http://pypi.python.org/packages/source/p/pyspotify/pyspotify-1.1.tar.gz#md5=ea894bf2ed866618d8c11f067f0a00fb (from http://pypi.python.org/simple/pyspotify/), version: 1.1
    Found link http://pypi.python.org/packages/source/p/pyspotify/pyspotify-1.4.tar.gz#md5=40679703afab49667f03cc77fa39fbfb (from http://pypi.python.org/simple/pyspotify/), version: 1.4
    Found link http://pypi.python.org/packages/source/p/pyspotify/pyspotify-1.7.tar.gz#md5=4f6aabc319172b4bd369c47ab164830e (from http://pypi.python.org/simple/pyspotify/), version: 1.7
    Skipping link http://pyspotify.mopidy.com/ (from http://pypi.python.org/simple/pyspotify/); not a file
    Skipping link http://freenode.net/ (from http://pypi.python.org/simple/pyspotify/); not a file
    Skipping link http://pyspotify.mopidy.com/docs/master/ (from http://pypi.python.org/simple/pyspotify/); not a file
    Skipping link http://www.spotify.com/ (from http://pypi.python.org/simple/pyspotify/); not a file
    Skipping link http://developer.spotify.com/en/libspotify/overview/ (from http://pypi.python.org/simple/pyspotify/); not a file
    Skipping link http://pyspotify.mopidy.com/docs/develop/ (from http://pypi.python.org/simple/pyspotify/); not a file
    Skipping link http://github.com/mopidy/pyspotify (from http://pypi.python.org/simple/pyspotify/); not a file
    Skipping link http://github.com/mopidy/pyspotify/issues (from http://pypi.python.org/simple/pyspotify/); not a file
    Found link http://github.com/mopidy/pyspotify/tarball/develop#egg=pyspotify-dev (from http://pypi.python.org/simple/pyspotify/), version: dev
  Analyzing links from page http://pyspotify.mopidy.com/en/latest/index.html
    Skipping link http://pyspotify.mopidy.com/en/latest/_static/rtd.css (from http://pyspotify.mopidy.com/en/latest/index.html); unknown archive format: .css
    Skipping link http://pyspotify.mopidy.com/en/latest/_static/pygments.css (from http://pyspotify.mopidy.com/en/latest/index.html); unknown archive format: .css
    Skipping link http://pyspotify.mopidy.com/en/latest/index.html (from http://pyspotify.mopidy.com/en/latest/index.html); unknown archive format: .html
    Skipping link http://pyspotify.mopidy.com/en/latest/introduction/ (from http://pyspotify.mopidy.com/en/latest/index.html); not a file
    Skipping link http://pyspotify.mopidy.com/en/latest/genindex/ (from http://pyspotify.mopidy.com/en/latest/index.html); not a file
    Skipping link http://pyspotify.mopidy.com/en/latest/py-modindex/ (from http://pyspotify.mopidy.com/en/latest/index.html); not a file
    Skipping link http://pyspotify.mopidy.com/en/latest/index.html#pyspotify (from http://pyspotify.mopidy.com/en/latest/index.html); unknown archive format: .html
    Skipping link http://pyspotify.mopidy.com/en/latest/index.html#project-resources (from http://pyspotify.mopidy.com/en/latest/index.html); unknown archive format: .html
    Skipping link http://pyspotify.mopidy.com/en/latest/index.html#table-of-contents (from http://pyspotify.mopidy.com/en/latest/index.html); unknown archive format: .html
    Skipping link http://pyspotify.mopidy.com/en/latest/introduction/#completion-status (from http://pyspotify.mopidy.com/en/latest/index.html); not a file
    Skipping link http://pyspotify.mopidy.com/en/latest/introduction/#requirements (from http://pyspotify.mopidy.com/en/latest/index.html); not a file
    Skipping link http://pyspotify.mopidy.com/en/latest/introduction/#installation (from http://pyspotify.mopidy.com/en/latest/index.html); not a file
    Skipping link http://pyspotify.mopidy.com/en/latest/introduction/#trying-it-out (from http://pyspotify.mopidy.com/en/latest/index.html); not a file
    Skipping link http://pyspotify.mopidy.com/en/latest/managers/ (from http://pyspotify.mopidy.com/en/latest/index.html); not a file
    Skipping link http://pyspotify.mopidy.com/en/latest/managers/session/ (from http://pyspotify.mopidy.com/en/latest/index.html); not a file
    Skipping link http://pyspotify.mopidy.com/en/latest/managers/playlist/ (from http://pyspotify.mopidy.com/en/latest/index.html); not a file
    Skipping link http://pyspotify.mopidy.com/en/latest/managers/container/ (from http://pyspotify.mopidy.com/en/latest/index.html); not a file
    Skipping link http://pyspotify.mopidy.com/en/latest/audiosink/ (from http://pyspotify.mopidy.com/en/latest/index.html); not a file
    Skipping link http://pyspotify.mopidy.com/en/latest/audiosink/#implementations (from http://pyspotify.mopidy.com/en/latest/index.html); not a file
    Skipping link http://pyspotify.mopidy.com/en/latest/api/ (from http://pyspotify.mopidy.com/en/latest/index.html); not a file
    Skipping link http://pyspotify.mopidy.com/en/latest/api/error/ (from http://pyspotify.mopidy.com/en/latest/index.html); not a file
    Skipping link http://pyspotify.mopidy.com/en/latest/api/session/ (from http://pyspotify.mopidy.com/en/latest/index.html); not a file
    Skipping link http://pyspotify.mopidy.com/en/latest/api/link/ (from http://pyspotify.mopidy.com/en/latest/index.html); not a file
    Skipping link http://pyspotify.mopidy.com/en/latest/api/track/ (from http://pyspotify.mopidy.com/en/latest/index.html); not a file
    Skipping link http://pyspotify.mopidy.com/en/latest/api/album/ (from http://pyspotify.mopidy.com/en/latest/index.html); not a file
    Skipping link http://pyspotify.mopidy.com/en/latest/api/artist/ (from http://pyspotify.mopidy.com/en/latest/index.html); not a file
    Skipping link http://pyspotify.mopidy.com/en/latest/api/albumbrowse/ (from http://pyspotify.mopidy.com/en/latest/index.html); not a file
    Skipping link http://pyspotify.mopidy.com/en/latest/api/artistbrowse/ (from http://pyspotify.mopidy.com/en/latest/index.html); not a file
    Skipping link http://pyspotify.mopidy.com/en/latest/api/image/ (from http://pyspotify.mopidy.com/en/latest/index.html); not a file
    Skipping link http://pyspotify.mopidy.com/en/latest/api/search/ (from http://pyspotify.mopidy.com/en/latest/index.html); not a file
    Skipping link http://pyspotify.mopidy.com/en/latest/api/playlist/ (from http://pyspotify.mopidy.com/en/latest/index.html); not a file
    Skipping link http://pyspotify.mopidy.com/en/latest/api/container/ (from http://pyspotify.mopidy.com/en/latest/index.html); not a file
    Skipping link http://pyspotify.mopidy.com/en/latest/api/user/ (from http://pyspotify.mopidy.com/en/latest/index.html); not a file
    Skipping link http://pyspotify.mopidy.com/en/latest/api/toplist/ (from http://pyspotify.mopidy.com/en/latest/index.html); not a file
    Skipping link http://pyspotify.mopidy.com/en/latest/api/inbox/ (from http://pyspotify.mopidy.com/en/latest/index.html); not a file
    Skipping link http://pyspotify.mopidy.com/en/latest/api/constants/ (from http://pyspotify.mopidy.com/en/latest/index.html); not a file
    Skipping link http://pyspotify.mopidy.com/en/latest/changes/ (from http://pyspotify.mopidy.com/en/latest/index.html); not a file
    Skipping link http://pyspotify.mopidy.com/en/latest/changes/#v1-7-2012-04-22 (from http://pyspotify.mopidy.com/en/latest/index.html); not a file
    Skipping link http://pyspotify.mopidy.com/en/latest/changes/#v1-6-1-2011-12-29 (from http://pyspotify.mopidy.com/en/latest/index.html); not a file
    Skipping link http://pyspotify.mopidy.com/en/latest/changes/#v1-6-2011-11-29 (from http://pyspotify.mopidy.com/en/latest/index.html); not a file
    Skipping link http://pyspotify.mopidy.com/en/latest/changes/#v1-5-2011-10-30 (from http://pyspotify.mopidy.com/en/latest/index.html); not a file
    Skipping link http://pyspotify.mopidy.com/en/latest/changes/#v1-4-2011-09-24 (from http://pyspotify.mopidy.com/en/latest/index.html); not a file
    Skipping link http://pyspotify.mopidy.com/en/latest/changes/#v1-3-2011-06-11 (from http://pyspotify.mopidy.com/en/latest/index.html); not a file
    Skipping link http://pyspotify.mopidy.com/en/latest/changes/#v1-2-2011-06-07 (from http://pyspotify.mopidy.com/en/latest/index.html); not a file
    Skipping link http://pyspotify.mopidy.com/en/latest/changes/#v1-1-mopidy20110405-2011-04-05 (from http://pyspotify.mopidy.com/en/latest/index.html); not a file
    Skipping link http://pyspotify.mopidy.com/en/latest/changes/#v1-1-mopidy20110331-2011-03-31 (from http://pyspotify.mopidy.com/en/latest/index.html); not a file
    Skipping link http://pyspotify.mopidy.com/en/latest/changes/#v1-1-mopidy20110330-2011-03-30 (from http://pyspotify.mopidy.com/en/latest/index.html); not a file
    Skipping link http://pyspotify.mopidy.com/en/latest/changes/#v1-1-mopidy20110223-2011-02-23 (from http://pyspotify.mopidy.com/en/latest/index.html); not a file
    Skipping link http://pyspotify.mopidy.com/en/latest/changes/#v1-1-mopidy20110106-2011-01-06 (from http://pyspotify.mopidy.com/en/latest/index.html); not a file
    Skipping link http://pyspotify.mopidy.com/en/latest/changes/#v1-1-2010-04-25 (from http://pyspotify.mopidy.com/en/latest/index.html); not a file
    Skipping link http://pyspotify.mopidy.com/en/latest/development/ (from http://pyspotify.mopidy.com/en/latest/index.html); not a file
    Skipping link http://pyspotify.mopidy.com/en/latest/development/#code-style (from http://pyspotify.mopidy.com/en/latest/index.html); not a file
    Skipping link http://pyspotify.mopidy.com/en/latest/development/#commit-guidelines (from http://pyspotify.mopidy.com/en/latest/index.html); not a file
    Skipping link http://pyspotify.mopidy.com/en/latest/development/#running-tests (from http://pyspotify.mopidy.com/en/latest/index.html); not a file
    Skipping link http://pyspotify.mopidy.com/en/latest/development/#continuous-integration-server (from http://pyspotify.mopidy.com/en/latest/index.html); not a file
    Skipping link http://pyspotify.mopidy.com/en/latest/development/#writing-documentation (from http://pyspotify.mopidy.com/en/latest/index.html); not a file
    Skipping link http://pyspotify.mopidy.com/en/latest/development/#creating-releases (from http://pyspotify.mopidy.com/en/latest/index.html); not a file
    Skipping link http://pyspotify.mopidy.com/en/latest/authors/ (from http://pyspotify.mopidy.com/en/latest/index.html); not a file
    Skipping link http://pyspotify.mopidy.com/en/latest/licenses/ (from http://pyspotify.mopidy.com/en/latest/index.html); not a file
    Skipping link http://pyspotify.mopidy.com/en/latest/licenses/#source-code-license (from http://pyspotify.mopidy.com/en/latest/index.html); not a file
    Skipping link http://pyspotify.mopidy.com/en/latest/licenses/#documentation-license (from http://pyspotify.mopidy.com/en/latest/index.html); not a file
    Skipping link http://pyspotify.mopidy.com/en/latest/licenses/#libspotify-disclaimer (from http://pyspotify.mopidy.com/en/latest/index.html); not a file
    Skipping link http://readthedocs.org (from http://pyspotify.mopidy.com/en/latest/index.html); not a file
    Skipping link http://pyspotify.mopidy.com/en/latest/_sources/index.txt (from http://pyspotify.mopidy.com/en/latest/index.html); unknown archive format: .txt
    Skipping link http://sphinx.pocoo.org/ (from http://pyspotify.mopidy.com/en/latest/index.html); not a file
    Skipping link http://readthedocs.org/projects/pyspotify/?fromdocs=pyspotify (from http://pyspotify.mopidy.com/en/latest/index.html); not a file
    Found link http://github.com/mopidy/pyspotify/tarball/develop#egg=pyspotify-dev (from http://pyspotify.mopidy.com/en/latest/index.html), version: dev
  Using version 1.7 (newest of versions: 1.7, 1.6.1, 1.6, 1.5, 1.4, 1.3, 1.2, 1.1, dev, dev)
  Downloading from URL http://pypi.python.org/packages/source/p/pyspotify/pyspotify-1.7.tar.gz#md5=4f6aabc319172b4bd369c47ab164830e (from http://pypi.python.org/simple/pyspotify/)
  Running setup.py egg_info for package pyspotify

    running egg_info
    creating pip-egg-info/pyspotify.egg-info
    writing pip-egg-info/pyspotify.egg-info/PKG-INFO
    writing top-level names to pip-egg-info/pyspotify.egg-info/top_level.txt
    writing dependency_links to pip-egg-info/pyspotify.egg-info/dependency_links.txt
    writing manifest file 'pip-egg-info/pyspotify.egg-info/SOURCES.txt'
    warning: manifest_maker: standard file '-c' not found


    reading manifest file 'pip-egg-info/pyspotify.egg-info/SOURCES.txt'
    reading manifest template 'MANIFEST.in'
    no previously-included directories found matching 'docs/_build'

    writing manifest file 'pip-egg-info/pyspotify.egg-info/SOURCES.txt'
Installing collected packages: pyspotify

  Running setup.py install for pyspotify

    Running command /home/humza/.pythonbrew/pythons/Python-2.7.2/bin/python -c "import setuptools;__file__='/home/humza/build/pyspotify/setup.py';exec(compile(open(__file__).read().replace('\r\n', '\n'), __file__, 'exec'))" install --single-version-externally-managed --record /tmp/pip-ELN8iz-record/install-record.txt
    running install
    running build
    running build_py
    creating build
    creating build/lib.linux-i686-2.7
    creating build/lib.linux-i686-2.7/spotify
    copying spotify/__init__.py -> build/lib.linux-i686-2.7/spotify
    creating build/lib.linux-i686-2.7/spotify/audiosink
    copying spotify/audiosink/__init__.py -> build/lib.linux-i686-2.7/spotify/audiosink
    copying spotify/audiosink/alsa.py -> build/lib.linux-i686-2.7/spotify/audiosink
    copying spotify/audiosink/portaudio.py -> build/lib.linux-i686-2.7/spotify/audiosink
    copying spotify/audiosink/gstreamer.py -> build/lib.linux-i686-2.7/spotify/audiosink
    copying spotify/audiosink/oss.py -> build/lib.linux-i686-2.7/spotify/audiosink
    creating build/lib.linux-i686-2.7/spotify/manager
    copying spotify/manager/__init__.py -> build/lib.linux-i686-2.7/spotify/manager
    copying spotify/manager/container.py -> build/lib.linux-i686-2.7/spotify/manager
    copying spotify/manager/playlist.py -> build/lib.linux-i686-2.7/spotify/manager
    copying spotify/manager/session.py -> build/lib.linux-i686-2.7/spotify/manager
    running build_ext
    building 'spotify._spotify' extension

    creating build/temp.linux-i686-2.7
    creating build/temp.linux-i686-2.7/src
    gcc -pthread -fno-strict-aliasing -g -O2 -DNDEBUG -g -fwrapv -O3 -Wall -Wstrict-prototypes -fPIC -Isrc -I/home/humza/.pythonbrew/pythons/Python-2.7.2/include/python2.7 -c src/module.c -o build/temp.linux-i686-2.7/src/module.o

    gcc -pthread -fno-strict-aliasing -g -O2 -DNDEBUG -g -fwrapv -O3 -Wall -Wstrict-prototypes -fPIC -Isrc -I/home/humza/.pythonbrew/pythons/Python-2.7.2/include/python2.7 -c src/session.c -o build/temp.linux-i686-2.7/src/session.o

    gcc -pthread -fno-strict-aliasing -g -O2 -DNDEBUG -g -fwrapv -O3 -Wall -Wstrict-prototypes -fPIC -Isrc -I/home/humza/.pythonbrew/pythons/Python-2.7.2/include/python2.7 -c src/link.c -o build/temp.linux-i686-2.7/src/link.o

    gcc -pthread -fno-strict-aliasing -g -O2 -DNDEBUG -g -fwrapv -O3 -Wall -Wstrict-prototypes -fPIC -Isrc -I/home/humza/.pythonbrew/pythons/Python-2.7.2/include/python2.7 -c src/track.c -o build/temp.linux-i686-2.7/src/track.o

    gcc -pthread -fno-strict-aliasing -g -O2 -DNDEBUG -g -fwrapv -O3 -Wall -Wstrict-prototypes -fPIC -Isrc -I/home/humza/.pythonbrew/pythons/Python-2.7.2/include/python2.7 -c src/album.c -o build/temp.linux-i686-2.7/src/album.o

    src/album.c: In function 'Album_cover':

    src/album.c:68:5: error: too few arguments to function 'sp_album_cover'

    In file included from src/album.c:3:0:

    /usr/include/libspotify/api.h:1830:28: note: declared here

    error: command 'gcc' failed with exit status 1

    Complete output from command /home/humza/.pythonbrew/pythons/Python-2.7.2/bin/python -c "import setuptools;__file__='/home/humza/build/pyspotify/setup.py';exec(compile(open(__file__).read().replace('\r\n', '\n'), __file__, 'exec'))" install --single-version-externally-managed --record /tmp/pip-ELN8iz-record/install-record.txt:

    running install

running build

running build_py

creating build

creating build/lib.linux-i686-2.7

creating build/lib.linux-i686-2.7/spotify

copying spotify/__init__.py -> build/lib.linux-i686-2.7/spotify

creating build/lib.linux-i686-2.7/spotify/audiosink

copying spotify/audiosink/__init__.py -> build/lib.linux-i686-2.7/spotify/audiosink

copying spotify/audiosink/alsa.py -> build/lib.linux-i686-2.7/spotify/audiosink

copying spotify/audiosink/portaudio.py -> build/lib.linux-i686-2.7/spotify/audiosink

copying spotify/audiosink/gstreamer.py -> build/lib.linux-i686-2.7/spotify/audiosink

copying spotify/audiosink/oss.py -> build/lib.linux-i686-2.7/spotify/audiosink

creating build/lib.linux-i686-2.7/spotify/manager

copying spotify/manager/__init__.py -> build/lib.linux-i686-2.7/spotify/manager

copying spotify/manager/container.py -> build/lib.linux-i686-2.7/spotify/manager

copying spotify/manager/playlist.py -> build/lib.linux-i686-2.7/spotify/manager

copying spotify/manager/session.py -> build/lib.linux-i686-2.7/spotify/manager

running build_ext

building 'spotify._spotify' extension

creating build/temp.linux-i686-2.7

creating build/temp.linux-i686-2.7/src

gcc -pthread -fno-strict-aliasing -g -O2 -DNDEBUG -g -fwrapv -O3 -Wall -Wstrict-prototypes -fPIC -Isrc -I/home/humza/.pythonbrew/pythons/Python-2.7.2/include/python2.7 -c src/module.c -o build/temp.linux-i686-2.7/src/module.o

gcc -pthread -fno-strict-aliasing -g -O2 -DNDEBUG -g -fwrapv -O3 -Wall -Wstrict-prototypes -fPIC -Isrc -I/home/humza/.pythonbrew/pythons/Python-2.7.2/include/python2.7 -c src/session.c -o build/temp.linux-i686-2.7/src/session.o

gcc -pthread -fno-strict-aliasing -g -O2 -DNDEBUG -g -fwrapv -O3 -Wall -Wstrict-prototypes -fPIC -Isrc -I/home/humza/.pythonbrew/pythons/Python-2.7.2/include/python2.7 -c src/link.c -o build/temp.linux-i686-2.7/src/link.o

gcc -pthread -fno-strict-aliasing -g -O2 -DNDEBUG -g -fwrapv -O3 -Wall -Wstrict-prototypes -fPIC -Isrc -I/home/humza/.pythonbrew/pythons/Python-2.7.2/include/python2.7 -c src/track.c -o build/temp.linux-i686-2.7/src/track.o

gcc -pthread -fno-strict-aliasing -g -O2 -DNDEBUG -g -fwrapv -O3 -Wall -Wstrict-prototypes -fPIC -Isrc -I/home/humza/.pythonbrew/pythons/Python-2.7.2/include/python2.7 -c src/album.c -o build/temp.linux-i686-2.7/src/album.o

src/album.c: In function 'Album_cover':

src/album.c:68:5: error: too few arguments to function 'sp_album_cover'

In file included from src/album.c:3:0:

/usr/include/libspotify/api.h:1830:28: note: declared here

error: command 'gcc' failed with exit status 1

Command /home/humza/.pythonbrew/pythons/Python-2.7.2/bin/python -c "import setuptools;__file__='/home/humza/build/pyspotify/setup.py';exec(compile(open(__file__).read().replace('\r\n', '\n'), __file__, 'exec'))" install --single-version-externally-managed --record /tmp/pip-ELN8iz-record/install-record.txt failed with error code 1 in /home/humza/build/pyspotify

Exception information:
Traceback (most recent call last):
  File "/home/humza/.pythonbrew/pythons/Python-2.7.2/lib/python2.7/site-packages/pip-1.1-py2.7.egg/pip/basecommand.py", line 104, in main
    status = self.run(options, args)
  File "/home/humza/.pythonbrew/pythons/Python-2.7.2/lib/python2.7/site-packages/pip-1.1-py2.7.egg/pip/commands/install.py", line 250, in run
    requirement_set.install(install_options, global_options)
  File "/home/humza/.pythonbrew/pythons/Python-2.7.2/lib/python2.7/site-packages/pip-1.1-py2.7.egg/pip/req.py", line 1133, in install
    requirement.install(install_options, global_options)
  File "/home/humza/.pythonbrew/pythons/Python-2.7.2/lib/python2.7/site-packages/pip-1.1-py2.7.egg/pip/req.py", line 577, in install
    cwd=self.source_dir, filter_stdout=self._filter_install, show_stdout=False)
  File "/home/humza/.pythonbrew/pythons/Python-2.7.2/lib/python2.7/site-packages/pip-1.1-py2.7.egg/pip/__init__.py", line 256, in call_subprocess
    % (command_desc, proc.returncode, cwd))
InstallationError: Command /home/humza/.pythonbrew/pythons/Python-2.7.2/bin/python -c "import setuptools;__file__='/home/humza/build/pyspotify/setup.py';exec(compile(open(__file__).read().replace('\r\n', '\n'), __file__, 'exec'))" install --single-version-externally-managed --record /tmp/pip-ELN8iz-record/install-record.txt failed with error code 1 in /home/humza/build/pyspotify

Jukebox hangs after certain sequences

Provided that you have a the appkey in the dir with the jukebox.py application and a playlist with at least 2 tracks on it, I can make the jukebox hang using the following examples:

play 0 1
queue 0 2
next
stop
quit -> hang

queue 0 1
queue 0 2
next -> playing!
next
quit -> hang

queue 0 1
stop
queue 0 2
next
quit -> hang

play 0 1
play 0 2
stop
quit -> hang

Segfault due to null pointer dereference at src/track.c:72

I have consistently reproduced a segfault using revision c6e2a02 due to a null pointer dereference at src/track.c:72.

A possible fix is:

diff --git a/src/track.c b/src/track.c
index f0d5956..82897de 100644
--- a/src/track.c
+++ b/src/track.c
@@ -68,6 +68,8 @@ static PyObject *Track_album(Track *self) {
     sp_album *album;

     album = sp_track_album(self->_track);
+    if (!album)
+        Py_RETURN_NONE;
     Album *a = (Album *)PyObject_CallObject((PyObject *)&AlbumType, NULL);
     sp_album_add_ref(album);
     a->_album = album;

Though, I think we should look for similar cases and handle them all in the same way. A quick look around the source code reveals that:

  • Track_album does not check for null pointers from sp_track_album, does call sp_album_add_ref, does not call Py_INCREF.
  • Track_artists does not check for null pointers from sp_track_artist, does not call sp_artist_add_ref, does not call Py_INCREF.
  • Album_artist does not check for null pointers from sp_album_artist, does not call sp_artist_add_ref, does call Py_INCREF.

That's three variants in three places.

Support for sp_playlist_add_tracks

Is it possible to add support for the sp_playlist_add_tracks function? I noticed there is support for removing tracks from a playlist. I may be able to go after this in a few days, but I have no experience integrating C libraries with Python.

Stuttery Playback

Hi

When trying the jutebox example all works well accept for playback. It stutters every now and then for less than a second and is intermittent. I am on:

Ubuntu 12.04 LTS Server 64bit
Alsa AudioSink (I can play audio fine with no stuttering from the the disk)

The server's not at a high load. I'm wondering if this is down to buffering?

Sorry this is quite vague. :p

pyspotify on windows?

Hi!
I'm working on a small project involving controlling, amongst others, spotify, with a python program. This module just looks so awesome, but is it any way to make it work on windows?

guitareirik

Support for connecting multiple times using the same session

When connecting to spotify everything works fine the first time but when trying to reconnect, i.e. disconnect and connect again, I always get the error "Initialization of library failed". I want to do this when switching username/password.

load() method times out on random albums

When trying to load albums, some fail due to timeout, but there doesn't seem to be any consistency. 1/2 of the albums for one artists will work and the other 1/2 wont.

richard@raspberrypi-> python
Python 2.7.3 (default, Jan 13 2013, 11:20:46) 
[GCC 4.6.3] on linux2
Type "help", "copyright", "credits" or "license" for more information.
>>> import spotify
>>> sess = spotify.Session()
>>> sess.login('xxxxx','xxxxxxxx')
>>> sess.get_album('spotify:album:02Zb13fM8k04tRwTfMUhe9')
Album(u'spotify:album:02Zb13fM8k04tRwTfMUhe9')
>>> sess.get_album('spotify:album:02Zb13fM8k04tRwTfMUhe9').load(5)
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "/usr/local/lib/python2.7/dist-packages/pyspotify-2.0.0a1-py2.7-linux-armv6l.egg/spotify/album.py", line 63, in load
    return utils.load(self, timeout=timeout)
  File "/usr/local/lib/python2.7/dist-packages/pyspotify-2.0.0a1-py2.7-linux-armv6l.egg/spotify/utils.py", line 217, in load
    raise RuntimeError('Session must be logged in to load objects')
RuntimeError: Session must be logged in to load objects
>>> sess.process_events()
1059
>>> sess.get_album('spotify:album:02Zb13fM8k04tRwTfMUhe9').load(5)
Album(u'spotify:album:02Zb13fM8k04tRwTfMUhe9')
>>> sess.get_album('spotify:album:02Zb13fM8k04tRwTfMUhe9').load(5).name
u'Welcome Reality'
>>> sess.get_album('spotify:album:3ph1ceuYuayuzoIJzPQji2').load(5).name
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "/usr/local/lib/python2.7/dist-packages/pyspotify-2.0.0a1-py2.7-linux-armv6l.egg/spotify/album.py", line 63, in load
    return utils.load(self, timeout=timeout)
  File "/usr/local/lib/python2.7/dist-packages/pyspotify-2.0.0a1-py2.7-linux-armv6l.egg/spotify/utils.py", line 228, in load
    raise spotify.Timeout(timeout)
spotify.error.Timeout: Operation did not complete in 5.000s
>>> sess.get_album('spotify:album:4IBQvwIbtDluogvDe2qpaB').load(5).name
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "/usr/local/lib/python2.7/dist-packages/pyspotify-2.0.0a1-py2.7-linux-armv6l.egg/spotify/album.py", line 63, in load
    return utils.load(self, timeout=timeout)
  File "/usr/local/lib/python2.7/dist-packages/pyspotify-2.0.0a1-py2.7-linux-armv6l.egg/spotify/utils.py", line 228, in load
    raise spotify.Timeout(timeout)
spotify.error.Timeout: Operation did not complete in 5.000s
>>> sess.get_album('spotify:album:5VppVyy751PTQWrfJbrJ4H').load(5).name
u'Between The Devil & The Deep Blue Sea (Special Edition)'
>>> sess.get_album('spotify:album:2cRMVS71c49Pf5SnIlJX3U').load(5).name
u'Coexist'
>>> sess.get_album('spotify:album:6mulYcpWRDAiv7KIouWvyP').load(5).name
u'ONE BY ONE'
>>> sess.get_album('spotify:album:6mulYcpWRDAiv7KIouWvyP').load(5).name
u'ONE BY ONE'
>>> sess.get_album('spotify:album:02jqf49ws9bcTvXLPGtjbT').load(5).name
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "/usr/local/lib/python2.7/dist-packages/pyspotify-2.0.0a1-py2.7-linux-armv6l.egg/spotify/album.py", line 63, in load
    return utils.load(self, timeout=timeout)
  File "/usr/local/lib/python2.7/dist-packages/pyspotify-2.0.0a1-py2.7-linux-armv6l.egg/spotify/utils.py", line 228, in load
    raise spotify.Timeout(timeout)
spotify.error.Timeout: Operation did not complete in 5.000s
>>> sess.get_album('spotify:album:17orrZznh0gmxYtpNP47nK').load(5).name
u'Another Home'
>>> sess.connection_state
<ConnectionState.LOGGED_IN: 1>
>>> sess.connection_state
<ConnectionState.LOGGED_IN: 1>
>>> sess.process_events()
60000
>>> sess.connection_state
<ConnectionState.LOGGED_IN: 1>
>>> sess.connection_state
<ConnectionState.LOGGED_IN: 1>
>>> sess.process_events()
28873
>>> sess.connection_state
<ConnectionState.LOGGED_IN: 1>
>>> sess.get_album('spotify:album:5lnQLEUiVDkLbFJHXHQu9m').load(5).name
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "/usr/local/lib/python2.7/dist-packages/pyspotify-2.0.0a1-py2.7-linux-armv6l.egg/spotify/album.py", line 63, in load
    return utils.load(self, timeout=timeout)
  File "/usr/local/lib/python2.7/dist-packages/pyspotify-2.0.0a1-py2.7-linux-armv6l.egg/spotify/utils.py", line 228, in load
    raise spotify.Timeout(timeout)
spotify.error.Timeout: Operation did not complete in 5.000s
>>> sess.process_events()
9489
>>> sess.connection_state
<ConnectionState.LOGGED_IN: 1>

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.