Ejemplo n.º 1
0
 def link(self):
     """A :class:`Link` to the playlist."""
     if not self.is_loaded:
         raise spotify.Error('The playlist must be loaded to create a link')
     sp_link = lib.sp_link_create_from_playlist(self._sp_playlist)
     if sp_link == ffi.NULL:
         if not self.is_in_ram:
             raise spotify.Error(
                 'The playlist must have been in RAM to create a link')
         # XXX Figure out why we can still get NULL here even if
         # the playlist is both loaded and in RAM.
         raise spotify.Error('Failed to get link from Spotify playlist')
     return spotify.Link(self._session, sp_link=sp_link, add_ref=False)
Ejemplo n.º 2
0
    def __init__(self, session, uri=None, sp_playlist=None, add_ref=True):
        super(Playlist, self).__init__()

        assert uri or sp_playlist, 'uri or sp_playlist is required'

        self._session = session

        if uri is not None:
            playlist = spotify.Link(self._session, uri).as_playlist()
            if playlist is None:
                raise spotify.Error(
                    'Failed to get playlist from Spotify URI: %r' % uri)
            sp_playlist = playlist._sp_playlist
            session._cache[sp_playlist] = self
            add_ref = True

        if add_ref:
            lib.sp_playlist_add_ref(sp_playlist)
        self._sp_playlist = ffi.gc(sp_playlist, lib.sp_playlist_release)

        self._sp_playlist_callbacks = None

        # Make sure we remove callbacks in __del__() using the same lib as we
        # added callbacks with.
        self._lib = lib
Ejemplo n.º 3
0
    def __getitem__(self, key):
        # Required by collections.Sequence

        if isinstance(key, slice):
            return list(self).__getitem__(key)
        if not isinstance(key, int):
            raise TypeError('list indices must be int or slice, not %s' %
                            key.__class__.__name__)
        if key < 0:
            key += self.__len__()
        if not 0 <= key < self.__len__():
            raise IndexError('list index out of range')

        playlist_type = PlaylistType(
            lib.sp_playlistcontainer_playlist_type(self._sp_playlistcontainer,
                                                   key))

        if playlist_type is PlaylistType.PLAYLIST:
            sp_playlist = lib.sp_playlistcontainer_playlist(
                self._sp_playlistcontainer, key)
            return spotify.Playlist._cached(self._session,
                                            sp_playlist,
                                            add_ref=True)
        elif playlist_type in (PlaylistType.START_FOLDER,
                               PlaylistType.END_FOLDER):
            return PlaylistFolder(
                id=lib.sp_playlistcontainer_playlist_folder_id(
                    self._sp_playlistcontainer, key),
                name=utils.get_with_fixed_buffer(
                    100, lib.sp_playlistcontainer_playlist_folder_name,
                    self._sp_playlistcontainer, key),
                type=playlist_type)
        else:
            raise spotify.Error('Unknown playlist type: %r' % playlist_type)
Ejemplo n.º 4
0
 def clear_unseen_tracks(self, playlist):
     """Clears unseen tracks from the given ``playlist``."""
     result = lib.sp_playlistcontainer_clear_unseen_tracks(
         self._sp_playlistcontainer, playlist._sp_playlist
     )
     if result == -1:
         raise spotify.Error('Failed clearing unseen tracks')
Ejemplo n.º 5
0
    def test_repr_if_link_creation_fails(self, link_mock, lib_mock):
        lib_mock.sp_playlist_is_loaded.return_value = 1
        link_mock.side_effect = spotify.Error('error message')
        sp_playlist = spotify.ffi.cast('sp_playlist *', 42)
        playlist = spotify.Playlist(self.session, sp_playlist=sp_playlist)

        result = repr(playlist)

        self.assertEqual(result, 'Playlist(<error: error message>)')
    def _get_more_tracks(self):
        self._sp_tracks_len = min(self._num_tracks,
                                  self._sp_tracks_len + self._BATCH_SIZE)
        self._sp_tracks = ffi.new('sp_track *[]', self._sp_tracks_len)
        self._num_tracks = lib.sp_playlistcontainer_get_unseen_tracks(
            self._sp_playlistcontainer, self._sp_playlist, self._sp_tracks,
            self._sp_tracks_len)

        if self._num_tracks < 0:
            raise spotify.Error('Failed to get unseen tracks for playlist')
Ejemplo n.º 7
0
def test_lookup_when_offline(session_mock, sp_track_mock, provider, caplog):
    session_mock.get_link.return_value = sp_track_mock.link
    sp_track_mock.link.as_track.return_value.load.side_effect = spotify.Error(
        'Must be online to load objects')

    results = provider.lookup('spotify:track:abc')

    assert len(results) == 0
    assert (
        'Failed to lookup "spotify:track:abc": Must be online to load objects'
        in caplog.text())
Ejemplo n.º 8
0
def load(session, obj, timeout=None):
    """Block until the object's data is loaded.

    If the session isn't logged in, a :exc:`spotify.Error` is raised as Spotify
    objects cannot be loaded without being online and logged in.

    The ``obj`` must at least have the :attr:`is_loaded` attribute. If it also
    has an :meth:`error` method, it will be checked for errors to raise.

    After ``timeout`` seconds with no results :exc:`~spotify.Timeout` is
    raised.

    If unspecified, the ``timeout`` defaults to 10s. Any timeout is better than
    no timeout, since no timeout would cause programs to potentially hang
    forever without any information to help debug the issue.

    The method returns ``self`` to allow for chaining of calls.
    """
    _check_error(obj)
    if obj.is_loaded:
        return obj

    if session.connection.state is not spotify.ConnectionState.LOGGED_IN:
        raise spotify.Error(
            'Session must be logged in and online to load objects: %r'
            % session.connection.state)

    if timeout is None:
        timeout = 10
    deadline = time.time() + timeout

    while not obj.is_loaded:
        session.process_events()
        _check_error(obj)
        if obj.is_loaded:
            return obj
        if time.time() > deadline:
            raise spotify.Timeout(timeout)

        # Instead of sleeping for a very short time and making a tight loop
        # here, one might be tempted to sleep for the time returned by the
        # session.process_events() call above. If no event loop is running,
        # that could lead to very long waits (up to a minute or so) since no
        # one is doing anything on "notify_main_thread" session callbacks,
        # which is intended to interrupt the sleep interval prescribed by
        # session.process_events(). Thus, it is better to make this loop tight.
        time.sleep(0.001)

    _check_error(obj)
    return obj
Ejemplo n.º 9
0
    def __init__(
        self,
        session,
        canonical_username=None,
        tracks=None,
        message='',
        callback=None,
        sp_inbox=None,
        add_ref=True,
    ):

        assert (
            canonical_username and tracks or sp_inbox
        ), 'canonical_username and tracks, or sp_inbox, is required'

        self._session = session
        self.loaded_event = threading.Event()

        if sp_inbox is None:
            canonical_username = utils.to_char(canonical_username)

            if isinstance(tracks, spotify.Track):
                tracks = [tracks]

            message = utils.to_char(message)

            handle = ffi.new_handle((self._session, self, callback))
            self._session._callback_handles.add(handle)

            sp_inbox = lib.sp_inbox_post_tracks(
                self._session._sp_session,
                canonical_username,
                [t._sp_track for t in tracks],
                len(tracks),
                message,
                _inboxpost_complete_callback,
                handle,
            )
            add_ref = True

            if sp_inbox == ffi.NULL:
                raise spotify.Error('Inbox post request failed to initialize')

        if add_ref:
            lib.sp_inbox_add_ref(sp_inbox)
        self._sp_inbox = ffi.gc(sp_inbox, lib.sp_inbox_release)
Ejemplo n.º 10
0
    def add_new_playlist(self, name, index=None):
        """Add an empty playlist with ``name`` at the given ``index``.

        The playlist name must not be space-only or longer than 255 chars.

        If the ``index`` isn't specified, the new playlist is added at the end
        of the container.

        Returns the new playlist.
        """
        self._validate_name(name)
        sp_playlist = lib.sp_playlistcontainer_add_new_playlist(
            self._sp_playlistcontainer, utils.to_char(name))
        if sp_playlist == ffi.NULL:
            raise spotify.Error('Playlist creation failed')
        playlist = spotify.Playlist._cached(self._session,
                                            sp_playlist,
                                            add_ref=True)
        if index is not None:
            self.move_playlist(self.__len__() - 1, index)
        return playlist
Ejemplo n.º 11
0
    def __init__(self,
                 canonical_username=None,
                 tracks=None,
                 message='',
                 callback=None,
                 sp_inbox=None,
                 add_ref=True):

        assert canonical_username and tracks or sp_inbox, \
            'canonical_username and tracks, or sp_inbox, is required'

        self.complete_event = threading.Event()
        self._callback_handles = set()

        if sp_inbox is None:
            canonical_username = utils.to_char(canonical_username)

            if isinstance(tracks, spotify.Track):
                tracks = [tracks]

            message = utils.to_char(message)

            handle = ffi.new_handle((callback, self))
            # TODO Think through the life cycle of the handle object. Can it
            # happen that we GC the search and handle object, and then later
            # the callback is called?
            self._callback_handles.add(handle)

            sp_inbox = lib.sp_inbox_post_tracks(
                spotify.session_instance._sp_session, canonical_username,
                [t._sp_track for t in tracks], len(tracks), message,
                _inboxpost_complete_callback, handle)
            add_ref = True

            if sp_inbox == ffi.NULL:
                raise spotify.Error('Inbox post request failed to initialize')

        if add_ref:
            lib.sp_inbox_add_ref(sp_inbox)
        self._sp_inbox = ffi.gc(sp_inbox, lib.sp_inbox_release)
Ejemplo n.º 12
0
    def setup(self):
        while not self._end.is_set():
            try:
                self.current = self.playlist.get(timeout=10)

                if not self.current.is_loaded:
                    self.current.load()
                    self.current.artists.load()

                self.session.player.load(self.current)
                self.update_playing(track=self.current)

                timeout_count = 0
                maxrate = "4000k"
                bufsize = "8000k"

                # cmd = "ffmpeg -f s16le -codec:a pcm_s16le -ac 2 -ar 44100 -i - " \
                #       "-f s16le -ar {} -ac {} -maxrate {} -bufsize {}  -loglevel warning pipe:1".format(
                #         self.voice.encoder.sampling_rate,
                #         self.voice.encoder.channels,
                #         maxrate,
                #         bufsize
                # )
                # args = shlex.split(cmd)
                # self.proc = Popen(args, stdin=PIPE, stdout=PIPE)
                # self.player = ProcessPlayer(self.proc, self.voice, None)

                #TODO: Test this
                before = "-f s16le -codec:a pcm_s16le -ac 2 -ar 44100"
                options = "-maxrate {} -bufsize {}".format(maxrate, bufsize)
                self.player = self.voice.create_ffmpeg_player(PIPE, pipe=True, before_options=before, options=options)
                self.proc = self.player.process

                self._ready.set()
                self.session.player.play()
                time.sleep(1)
                self.player.start()

                while not self.frame_queue.empty():
                    try:
                        while self._pause.is_set():
                            if self._end.is_set():
                                self._pause.clear()
                                break
                            else:
                                time.sleep(1)

                        if self._end.is_set() or self._skip.is_set():
                            self.frame_queue.clear()
                            self._skip.clear()
                            break

                        play_item = self.frame_queue.get(timeout=1)

                        if self._ready.is_set():
                            self.proc.stdin.write(play_item[1])

                    except queue.Empty:
                        print("Timeout ", timeout_count)
                        timeout_count += 1
                        if timeout_count > 30:
                            raise spotify.Error("Timeout while playing track.")

            except queue.Empty:
                continue
            except (spotify.Error, Exception) as e:
                if isinstance(e, spotify.Error):
                    print("Spotify error!")
                print(repr(e))
                self.session.player.unload()
                self.cleanup()
                return

        self.cleanup()
Ejemplo n.º 13
0
    def run(self):
        args = self.args

        # start event loop
        self.event_loop.start()

        # wait for main thread to login
        self.ripper_continue.wait()
        if self.abort.is_set():
            return

        # check if we were passed a file name or search
        if len(args.uri) == 1 and path_exists(args.uri[0]):
            uris = [line.strip() for line in open(args.uri[0])]
        elif len(args.uri) == 1 and not args.uri[0].startswith("spotify:"):
            uris = [list(self.search_query(args.uri[0]))]
        else:
            uris = args.uri

        def get_tracks_from_uri(uri):
            current_playlist = None
            current_album = None
            current_chart = None

            if isinstance(uri, list):
                return uri
            else:
                if (args.exclude_appears_on
                        and uri.startswith("spotify:artist:")):
                    album_uris = self.web.get_non_appears_on_albums(uri)
                    return itertools.chain(*[
                        self.load_link(album_uri) for album_uri in album_uris
                    ])
                elif uri.startswith("spotify:charts:"):
                    charts = self.web.get_charts(uri)
                    if charts is not None:
                        self.current_chart = charts
                        chart_uris = [
                            t["track"]["uri"]
                            for t in charts["entries"]["items"]
                        ]
                        return itertools.chain(*[
                            self.load_link(chart_uri)
                            for chart_uri in chart_uris
                        ])
                    else:
                        return iter([])
                else:
                    return self.load_link(uri)

        # calculate total size and time
        all_tracks = []
        for uri in uris:
            tracks = get_tracks_from_uri(uri)
            all_tracks += list(tracks)

        self.progress.calc_total(all_tracks)

        if self.progress.total_size > 0:
            print("Total Download Size: " +
                  format_size(self.progress.total_size))

        # create track iterator
        for uri in uris:
            if self.abort.is_set():
                break

            tracks = list(get_tracks_from_uri(uri))

            if args.playlist_sync and self.current_playlist:
                self.sync = Sync(args, self)
                self.sync.sync_playlist(self.current_playlist)

            # ripping loop
            for idx, track in enumerate(tracks):
                try:
                    self.check_stop_time()
                    self.skip.clear()

                    if self.abort.is_set():
                        break

                    print('Loading track...')
                    track.load()
                    if track.availability != 1:
                        print(Fore.RED + 'Track is not available, '
                              'skipping...' + Fore.RESET)
                        self.post.log_failure(track)
                        continue

                    self.audio_file = self.format_track_path(idx, track)

                    if not args.overwrite and path_exists(self.audio_file):
                        print(Fore.YELLOW + "Skipping " + track.link.uri +
                              Fore.RESET)
                        print(Fore.CYAN + self.audio_file + Fore.RESET)
                        self.post.queue_remove_from_playlist(idx)
                        continue

                    self.session.player.load(track)
                    self.prepare_rip(idx, track)
                    self.session.player.play()

                    timeout_count = 0
                    while not self.end_of_track.is_set() or \
                            not self.rip_queue.empty():
                        try:
                            if self.abort.is_set() or self.skip.is_set():
                                break

                            rip_item = self.rip_queue.get(timeout=1)

                            if self.abort.is_set() or self.skip.is_set():
                                break

                            self.rip(self.session, rip_item[0], rip_item[1],
                                     rip_item[2])
                        except queue.Empty:
                            timeout_count += 1
                            if timeout_count > 60:
                                raise spotify.Error("Timeout while "
                                                    "ripping track")

                    if self.skip.is_set():
                        print("\n" + Fore.YELLOW + "User skipped track... " +
                              Fore.RESET)
                        self.session.player.play(False)
                        self.post.clean_up_partial()
                        self.post.log_failure(track)
                        self.end_of_track.clear()
                        self.progress.end_track(show_end=False)
                        self.ripping.clear()
                        continue

                    if self.abort.is_set():
                        self.session.player.play(False)
                        self.end_of_track.set()
                        self.post.clean_up_partial()
                        self.post.log_failure(track)
                        break

                    self.end_of_track.clear()

                    self.finish_rip(track)

                    # update id3v2 with metadata and embed front cover image
                    set_metadata_tags(args, self.audio_file, idx, track, self)

                    # make a note of the index and remove all the
                    # tracks from the playlist when everything is done
                    self.post.queue_remove_from_playlist(idx)

                except (spotify.Error, Exception) as e:
                    if isinstance(e, Exception):
                        print(Fore.RED + "Spotify error detected" + Fore.RESET)
                    print(str(e))
                    print("Skipping to next track...")
                    self.session.player.play(False)
                    self.post.clean_up_partial()
                    self.post.log_failure(track)
                    continue

            # create playlist m3u file if needed
            self.post.create_playlist_m3u(tracks)

            # create playlist wpl file if needed
            self.post.create_playlist_wpl(tracks)

            # actually removing the tracks from playlist
            self.post.remove_tracks_from_playlist()

        # logout, we are done
        self.post.end_failure_log()
        self.post.print_summary()
        self.logout()
        self.stop_event_loop()
        self.finished.set()
Ejemplo n.º 14
0
    def run(self):
        args = self.args

        # start event loop
        self.event_loop.start()

        # wait for main thread to login
        self.ripper_continue.wait()
        if self.abort.is_set():
            return
        #set session to private
        self.session.social.private_session = True

        # list of spotify URIs
        uris = args.uri

        # calculate total size and time
        all_tracks = []
        uri_tracks = {}
        for uri in uris:
            tracks = list(self.get_tracks_from_uri(uri))
            uri_tracks[uri] = tracks
            for idx, track in enumerate(tracks):

                # ignore local tracks
                if track.is_local:
                    continue

                audio_file = self.format_track_path(idx, track)
                all_tracks.append((track, audio_file))

        self.progress.calc_total(all_tracks)

        if self.progress.total_size > 0:
            print(
                "Total Download Size: " +
                format_size(self.progress.total_size))

        # create track iterator
        for uri in uris:
            if self.abort.is_set():
                break

            tracks = uri_tracks[uri]

            """acepta una playlist album para sincronizar, aunque es al pedo"""

            if args.playlist_sync and self.current_playlist:
                self.sync = Sync(args, self)
                self.sync.sync_playlist(self.current_playlist)

            # ripping loop
            for idx, track in enumerate(tracks):
                try:
                    self.check_stop_time()
                    self.skip.clear()

                    if self.abort.is_set():
                        break

                    print('Loading track...')
                    track.load(args.timeout)
                    if track.availability != 1 or track.is_local:
                        print(
                            Fore.RED + 'Track is not available, '
                                       'skipping...' + Fore.RESET)
                        self.post.log_failure(track)
                        self.progress.track_idx += 1
                        continue

                    self.audio_file = self.format_track_path(idx, track)

                    if not args.overwrite and path_exists(self.audio_file):
                        if is_partial(self.audio_file, track):
                            print("Overwriting partial file")
                        else:
                            print(
                                Fore.YELLOW + "Skipping " +
                                track.link.uri + Fore.RESET)
                            print(Fore.CYAN + self.audio_file + Fore.RESET)
                            self.post.queue_remove_from_playlist(track.link.uri)
                            self.progress.track_idx += 1
                            continue

                    self.session.player.load(track)
                    self.prepare_rip(track)
                    self.session.player.play()

                    timeout_count = 0
                    while not self.end_of_track.is_set() or \
                            not self.rip_queue.empty():
                        try:
                            if self.abort.is_set() or self.skip.is_set():
                                break

                            rip_item = self.rip_queue.get(timeout=1)

                            if self.abort.is_set() or self.skip.is_set():
                                break

                            self.rip(self.session, rip_item[0],
                                     rip_item[1], rip_item[2])
                        except queue.Empty:
                            timeout_count += 1
                            if timeout_count > 60:
                                raise spotify.Error("Timeout while "
                                                    "ripping track")

                    if self.skip.is_set():
                        extra_line = "" if self.play_token_resume.is_set() \
                                        else "\n"
                        print(extra_line + Fore.YELLOW +
                            "User skipped track... " + Fore.RESET)
                        self.session.player.play(False)
                        self.post.clean_up_partial()
                        self.post.log_failure(track)
                        self.end_of_track.clear()
                        self.progress.end_track(show_end=False)
                        self.ripping.clear()
                        continue

                    if self.abort.is_set():
                        self.session.player.play(False)
                        self.end_of_track.set()
                        self.post.clean_up_partial()
                        self.post.log_failure(track)
                        break

                    self.end_of_track.clear()

                    self.finish_rip(track)

                    # update id3v2 with metadata and embed front cover image
                    set_metadata_tags(args, self.audio_file, idx, track, self)

                    # make a note of the index and remove all the
                    # tracks from the playlist when everything is done
                    self.post.queue_remove_from_playlist(track.link.uri)

                    # finally log success
                    self.post.log_success(track)

                except (spotify.Error, Exception) as e:
                    if isinstance(e, Exception):
                        print(Fore.RED + "Spotify error detected" + Fore.RESET)
                    print(str(e))
                    traceback.print_exc()
                    print("Skipping to next track...")
                    self.session.player.play(False)
                    self.post.clean_up_partial()
                    self.post.log_failure(track)
                    continue

            # create playlist m3u file if needed
            self.post.create_playlist_m3u(tracks)

            # create playlist wpl file if needed
            self.post.create_playlist_wpl(tracks)

            # actually removing the tracks from playlist
            self.post.remove_tracks_from_playlist()

            # remove libspotify's offline storage cache
            self.post.remove_offline_cache()

        # logout, we are done
        self.post.end_failure_log()
        self.post.print_summary()
        self.logout()
        self.stop_event_loop()
        self.finished.set()
        sys.exit()
Ejemplo n.º 15
0
def _lookup_playlist(config, session, web_client, uri):
    playlist = playlists.playlist_lookup(session, web_client, uri,
                                         config["bitrate"])
    if playlist is None:
        raise spotify.Error("Playlist Web API lookup failed")
    return playlist.tracks
Ejemplo n.º 16
0
    def run(self):
        args = self.args

        # start event loop
        self.event_loop.start()

        # wait for main thread to login
        self.ripper_continue.wait()
        if self.abort.is_set():
            return
        #set session to provate
        self.session.social.private_session = True

        # list of spotify URIs
        uris = args.uri

        def get_tracks_from_uri(uri):
            self.current_playlist = None
            self.current_album = None
            self.current_chart = None

            if isinstance(uri, list):
                return uri
            else:
                if (uri.startswith("spotify:artist:")
                        and (args.artist_album_type is not None
                             or args.artist_album_market is not None)):
                    album_uris = self.web.get_albums_with_filter(uri)
                    return itertools.chain(*[
                        self.load_link(album_uri) for album_uri in album_uris
                    ])
                elif uri.startswith("spotify:charts:"):
                    charts = self.web.get_charts(uri)
                    if charts is not None:
                        self.current_chart = charts
                        chart_uris = charts["tracks"]
                        return itertools.chain(*[
                            self.load_link(chart_uri)
                            for chart_uri in chart_uris
                        ])
                    else:
                        return iter([])
                else:
                    return self.load_link(uri)

        # calculate total size and time
        all_tracks = []
        for uri in uris:
            tracks = list(get_tracks_from_uri(uri))

            # TODO: remove dependency on current_album, ...
            for idx, track in enumerate(tracks):

                # ignore local tracks
                if track.is_local:
                    continue

                audio_file = self.format_track_path(idx, track)
                all_tracks.append((track, audio_file))

        self.progress.calc_total(all_tracks)

        if self.progress.total_size > 0:
            print("Total Download Size: " +
                  format_size(self.progress.total_size))

        # create track iterator
        for uri in uris:
            if self.abort.is_set():
                break

            tracks = list(get_tracks_from_uri(uri))

            if args.playlist_sync and self.current_playlist:
                self.sync = Sync(args, self)
                self.sync.sync_playlist(self.current_playlist)

            # ripping loop
            for idx, track in enumerate(tracks):
                try:
                    self.check_stop_time()
                    self.skip.clear()

                    if self.abort.is_set():
                        break

                    print('Loading track...')
                    track.load(args.timeout)
                    if track.availability != 1 or track.is_local:
                        print(Fore.RED + 'Track is not available, '
                              'skipping...' + Fore.RESET)
                        self.post.log_failure(track)
                        continue

                    self.audio_file = self.format_track_path(idx, track)

                    if not args.overwrite and path_exists(self.audio_file):
                        if is_partial(self.audio_file, track):
                            print("Overwriting partial file")
                        else:
                            print(Fore.YELLOW + "Skipping " + track.link.uri +
                                  Fore.RESET)
                            print(Fore.CYAN + self.audio_file + Fore.RESET)
                            continue

                    self.session.player.load(track)
                    self.prepare_rip(idx, track)
                    self.session.player.play()

                    timeout_count = 0
                    while not self.end_of_track.is_set() or \
                            not self.rip_queue.empty():
                        try:
                            if self.abort.is_set() or self.skip.is_set():
                                break

                            rip_item = self.rip_queue.get(timeout=1)

                            if self.abort.is_set() or self.skip.is_set():
                                break

                            self.rip(self.session, rip_item[0], rip_item[1],
                                     rip_item[2])
                        except queue.Empty:
                            timeout_count += 1
                            if timeout_count > 60:
                                raise spotify.Error("Timeout while "
                                                    "ripping track")

                    if self.skip.is_set():
                        extra_line = "" if self.play_token_resume.is_set() \
                                        else "\n"
                        print(extra_line + Fore.YELLOW +
                              "User skipped track... " + Fore.RESET)
                        self.session.player.play(False)
                        self.post.clean_up_partial()
                        self.post.log_failure(track)
                        self.end_of_track.clear()
                        self.progress.end_track(show_end=False)
                        self.ripping.clear()
                        continue

                    if self.abort.is_set():
                        self.session.player.play(False)
                        self.end_of_track.set()
                        self.post.clean_up_partial()
                        self.post.log_failure(track)
                        break

                    self.end_of_track.clear()

                    self.finish_rip(track)

                    # update id3v2 with metadata and embed front cover image
                    set_metadata_tags(args, self.audio_file, idx, track, self)

                    # finally log success
                    self.post.log_success(track)

                except (spotify.Error, Exception) as e:
                    if isinstance(e, Exception):
                        print(Fore.RED + "Spotify error detected" + Fore.RESET)
                    print(str(e))
                    traceback.print_exc()
                    print("Skipping to next track...")
                    self.session.player.play(False)
                    self.post.clean_up_partial()
                    self.post.log_failure(track)
                    continue

            # create playlist m3u file if needed
            self.post.create_playlist_m3u(tracks)

            # create playlist wpl file if needed
            self.post.create_playlist_wpl(tracks)

            # remove libspotify's offline storage cache
            self.post.remove_offline_cache()

        # logout, we are done
        self.post.end_failure_log()
        self.post.print_summary()
        self.logout()
        self.stop_event_loop()
        self.finished.set()
        sys.exit()
Ejemplo n.º 17
0
 def error(self):
     return spotify.Error(spotify.Error.OK)
Ejemplo n.º 18
0
 def test_error_is_an_exception(self):
     error = spotify.Error(0)
     self.assertIsInstance(error, Exception)