def test_add_tracks_without_index(self, track_lib_mock, lib_mock): lib_mock.sp_playlist_add_tracks.return_value = int(spotify.ErrorType.OK) lib_mock.sp_playlist_num_tracks.return_value = 10 sp_track1 = spotify.ffi.new('int * ') track1 = spotify.Track(self.session, sp_track=sp_track1) sp_track2 = spotify.ffi.new('int * ') track2 = spotify.Track(self.session, sp_track=sp_track2) sp_playlist = spotify.ffi.cast('sp_playlist *', 42) playlist = spotify.Playlist(self.session, sp_playlist=sp_playlist) playlist.add_tracks([track1, track2]) lib_mock.sp_playlist_add_tracks.assert_called_with( sp_playlist, [sp_track1, sp_track2], 2, 10, self.session._sp_session )
def test_subscribers(self, lib_mock): sp_subscribers = spotify.ffi.new('sp_subscribers *') sp_subscribers.count = 1 user_alice = spotify.ffi.new('char[]', b'alice') sp_subscribers.subscribers = [user_alice] lib_mock.sp_playlist_subscribers.return_value = sp_subscribers sp_playlist = spotify.ffi.cast('sp_playlist *', 42) playlist = spotify.Playlist(self.session, sp_playlist=sp_playlist) result = playlist.subscribers lib_mock.sp_playlist_subscribers.assert_called_with(sp_playlist) tests.gc_collect() lib_mock.sp_playlist_subscribers_free.assert_called_with(sp_subscribers) self.assertEqual(result, ['alice'])
def test_life_cycle(self, lib_mock): sp_playlist = spotify.ffi.cast('sp_playlist *', 42) playlist = spotify.Playlist(self.session, sp_playlist=sp_playlist) sp_playlist = playlist._sp_playlist lib_mock.sp_playlist_add_ref.assert_called_with(sp_playlist) lib_mock.sp_playlist_add_callbacks.assert_called_with( sp_playlist, mock.ANY, mock.ANY) playlist = None # noqa tests.gc_collect() lib_mock.sp_playlist_remove_callbacks.assert_called_with( sp_playlist, mock.ANY, mock.ANY)
def test_tracks_delitem_with_slice(self, lib_mock): lib_mock.sp_playlist_remove_tracks.return_value = int( spotify.ErrorType.OK ) sp_playlist = spotify.ffi.cast('sp_playlist *', 42) playlist = spotify.Playlist(self.session, sp_playlist=sp_playlist) tracks = playlist.tracks tracks.__len__ = mock.Mock(return_value=3) del tracks[0:2] # Delete items in reverse order, so the indexes doesn't change lib_mock.sp_playlist_remove_tracks.assert_has_calls( [mock.call(sp_playlist, [1], 1), mock.call(sp_playlist, [0], 1)], any_order=False, )
def test_reorder_tracks(self, track_lib_mock, lib_mock): lib_mock.sp_playlist_reorder_tracks.return_value = int( spotify.ErrorType.OK) sp_playlist = spotify.ffi.cast('sp_playlist *', 42) playlist = spotify.Playlist(self.session, sp_playlist=sp_playlist) position1 = 13 position2 = 17 playlist.reorder_tracks([position1, position2], 17) lib_mock.sp_playlist_reorder_tracks.assert_called_with( sp_playlist, mock.ANY, 2, 17) self.assertIn(position1, lib_mock.sp_playlist_reorder_tracks.call_args[0][1]) self.assertIn(position2, lib_mock.sp_playlist_reorder_tracks.call_args[0][1])
def test_remove_tracks(self, track_lib_mock, lib_mock): lib_mock.sp_playlist_remove_tracks.return_value = int( spotify.ErrorType.OK) sp_playlist = spotify.ffi.cast('sp_playlist *', 42) playlist = spotify.Playlist(self.session, sp_playlist=sp_playlist) index1 = 13 index2 = 17 playlist.remove_tracks([index1, index2]) lib_mock.sp_playlist_remove_tracks.assert_called_with( sp_playlist, mock.ANY, 2) self.assertIn(index1, lib_mock.sp_playlist_remove_tracks.call_args[0][1]) self.assertIn(index2, lib_mock.sp_playlist_remove_tracks.call_args[0][1])
def test_link_may_fail_if_playlist_has_not_been_in_ram( self, link_mock, lib_mock ): lib_mock.sp_playlist_is_loaded.return_value = 1 lib_mock.sp_link_create_from_playlist.return_value = spotify.ffi.NULL sp_playlist = spotify.ffi.cast('sp_playlist *', 42) playlist = spotify.Playlist(self.session, sp_playlist=sp_playlist) with self.assertRaises(spotify.Error): playlist.link # Condition is checked only if link creation returns NULL lib_mock.sp_link_create_from_playlist.assert_called_with(sp_playlist) lib_mock.sp_playlist_is_in_ram.assert_called_with( self.session._sp_session, sp_playlist )
def test_tracks(self, track_lib_mock, lib_mock): sp_track = spotify.ffi.cast('sp_track *', 43) lib_mock.sp_playlist_num_tracks.return_value = 1 lib_mock.sp_playlist_track.return_value = sp_track sp_playlist = spotify.ffi.cast('sp_playlist *', 42) playlist = spotify.Playlist(self.session, sp_playlist=sp_playlist) self.assertEqual(lib_mock.sp_playlist_add_ref.call_count, 1) result = playlist.tracks self.assertEqual(lib_mock.sp_playlist_add_ref.call_count, 2) self.assertEqual(len(result), 1) lib_mock.sp_playlist_num_tracks.assert_called_with(sp_playlist) item = result[0] self.assertIsInstance(item, spotify.Track) self.assertEqual(item._sp_track, sp_track) self.assertEqual(lib_mock.sp_playlist_track.call_count, 1) lib_mock.sp_playlist_track.assert_called_with(sp_playlist, 0) track_lib_mock.sp_track_add_ref.assert_called_with(sp_track)
def test_tracks_setitem_with_slice(self, lib_mock): sp_playlist = spotify.ffi.cast('sp_playlist *', 42) playlist = spotify.Playlist(self.session, sp_playlist=sp_playlist) tracks = playlist.tracks tracks.__len__ = mock.Mock(return_value=5) playlist.remove_tracks = mock.Mock() playlist.add_tracks = mock.Mock() tracks[0:2] = [mock.sentinel.track1, mock.sentinel.track2] playlist.add_tracks.assert_has_calls( [ mock.call(mock.sentinel.track1, index=0), mock.call(mock.sentinel.track2, index=1), ], any_order=False, ) playlist.remove_tracks.assert_has_calls( [mock.call(3), mock.call(2)], any_order=False )
def test_life_cycle(self, lib_mock): sp_playlist = spotify.ffi.cast('sp_playlist *', 42) playlist = spotify.Playlist(self.session, sp_playlist=sp_playlist) sp_playlist = playlist._sp_playlist lib_mock.sp_playlist_add_ref.assert_called_with(sp_playlist) # Callbacks are only added when someone registers a Python event # handler on the playlist: lib_mock.sp_playlist_add_callbacks.assert_not_called() playlist.on(spotify.PlaylistEvent.TRACKS_ADDED, lambda *args: None) lib_mock.sp_playlist_add_callbacks.assert_called_with( sp_playlist, mock.ANY, mock.ANY ) playlist = None # noqa tests.gc_collect() # Callbacks are removed when the playlist is GC-ed: lib_mock.sp_playlist_remove_callbacks.assert_called_with( sp_playlist, mock.ANY, mock.ANY )
async def get_spotify_tracks( ctx, search_type: str, spotify_id: str, spotify_client, spotify_http ) -> t.Tuple[str, list]: name = None search_tracks = None try: if search_type == "album": search_result = await spotify_client.get_album(spotify_id=spotify_id) name = search_result.name search_tracks = await search_result.get_all_tracks() if len(search_tracks) > 500: search_tracks = search_tracks[:500] elif search_type == "playlist": search_result = spotify.Playlist( client=spotify_client, data=await spotify_http.get_playlist(spotify_id) ) name = search_result.name search_tracks = list(await search_result.get_all_tracks()) if len(search_tracks) > 500: search_tracks = search_tracks[:500] elif search_type == "track": search_result = await spotify_client.get_track(spotify_id=spotify_id) name = search_result.name search_tracks = [search_result] except (spotify.NotFound, discord.HTTPException): return await ctx.send( "No results were found for your spotify link.", delete_after=15 ) return name, search_tracks
def get_playlist(self, uri): """ Get :class:`Playlist` from a Spotify playlist URI. .. warning:: The playlists API was broken at 2018-05-24 by a server-side change made by Spotify. The functionality was never restored. Please use the Spotify Web API to work with playlists. Example:: >>> session = spotify.Session() # ... >>> playlist = session.get_playlist( ... 'spotify:user:fiat500c:playlist:54k50VZdvtnIPt4d8RBCmZ') >>> playlist.load().name u'500C feelgood playlist' """ warnings.warn("Spotify broke the libspotify playlists API 2018-05-24 " "and never restored it. " "Please use the Spotify Web API to work with playlists.") return spotify.Playlist(self, uri=uri)
def test_create_without_uri_or_sp_playlist_fails(self, lib_mock): with self.assertRaises(AssertionError): spotify.Playlist(self.session)
async def search(self, query: str, ctx: context.Context) -> objects.SearchResult: search_result = None search_tracks = None spotify_url_check = self.spotify_url_regex.match(query) if spotify_url_check is not None: source = 'spotify' spotify_client: spotify.Client = self.bot.cogs["Music"].spotify spotify_http_client: spotify.HTTPClient = self.bot.cogs[ "Music"].spotify_http search_type = spotify_url_check.group('type') spotify_id = spotify_url_check.group('id') try: if search_type == 'album': search_result = await spotify_client.get_album( spotify_id=spotify_id) search_tracks = await search_result.get_all_tracks() elif search_type == 'playlist': search_result = spotify.Playlist( client=spotify_client, data=await spotify_http_client.get_playlist(spotify_id)) search_tracks = await search_result.get_all_tracks() elif search_type == 'track': search_result = await spotify_client.get_track( spotify_id=spotify_id) search_tracks = [search_result] except spotify.NotFound or HTTPException: raise exceptions.VoiceError( f'No results were found for your Spotify link.') if not search_tracks: raise exceptions.VoiceError( f'No results were found for your Spotify link.') tracks = [ slate.Track( track_id='', ctx=ctx, track_info={ 'title': track.name or 'Unknown', 'author': ', '.join(artist.name for artist in track.artists) or 'Unknown', 'length': track.duration or 0, 'identifier': track.id or 'Unknown', 'uri': track.url or 'spotify', 'isStream': False, 'isSeekable': False, 'position': 0, 'thumbnail': track.images[0].url if track.images else None }, ) for track in search_tracks ] else: url = yarl.URL(query) if not url.host or not url.scheme: if query.startswith('soundcloud'): query = f'scsearch:{query[11:]}' else: query = f'ytsearch:{query}' try: search_result = await self.node.search(query=query, ctx=ctx) except slate.TrackLoadError as error: raise exceptions.VoiceError( f'`{error.status_code}` error code while searching for results. For support use `{self.bot.config.prefix}support`.' ) except slate.TrackLoadFailed as error: raise exceptions.VoiceError( f'`{error.severity}` error while searching for results. For support use `{self.bot.config.prefix}support`.\nReason: `{error.message}`' ) if not search_result: raise exceptions.VoiceError( f'No results were found for your search.') if isinstance(search_result, slate.Playlist): source = 'youtube' search_type = 'playlist' tracks = search_result.tracks else: source = search_result[0].source search_type = 'track' tracks = search_result return objects.SearchResult(source=source, search_type=search_type, search_result=search_result, tracks=tracks)
def test_ne(self, lib_mock): sp_playlist = spotify.ffi.cast('sp_playlist *', 42) playlist1 = spotify.Playlist(self.session, sp_playlist=sp_playlist) playlist2 = spotify.Playlist(self.session, sp_playlist=sp_playlist) self.assertFalse(playlist1 != playlist2)
def test_tracks_is_a_mutable_sequence(self, lib_mock): sp_playlist = spotify.ffi.cast('sp_playlist *', 42) playlist = spotify.Playlist(self.session, sp_playlist=sp_playlist) self.assertIsInstance(playlist.tracks, compat.MutableSequence)
def test_hash(self, lib_mock): sp_playlist = spotify.ffi.cast('sp_playlist *', 42) playlist1 = spotify.Playlist(self.session, sp_playlist=sp_playlist) playlist2 = spotify.Playlist(self.session, sp_playlist=sp_playlist) self.assertEqual(hash(playlist1), hash(playlist2))
def playlist_tracks(self, playlisturi): playlist = spotify.Playlist(self.session, uri=playlisturi) if not playlist.is_loaded: playlist.load() return [str(track.link) for track in playlist.tracks]
def playlist(self): """The :class:`~spotify.Playlist` object for this :class:`SearchPlaylist`.""" return spotify.Playlist(self.uri)