def test_search_any(library, client_mock): client_mock.search.return_value = client_mock.SearchResult({ "responseHeader": { "params": { "query": "album" } }, "response": { "docs": [ { "identifier": "album1", "title": "Album #1", "mediatype": "audio", }, { "identifier": "album2", "title": "Album #2", "mediatype": "etree", }, ], "numFound": 2, }, }) result = library.search(dict(any=["album"])) assert client_mock.search.called_once() assert result == models.SearchResult( uri="internetarchive:?q=album", albums=[ models.Album(name="Album #1", uri="internetarchive:album1"), models.Album(name="Album #2", uri="internetarchive:album2"), ], )
def search(self, query): """Search Emby for a term. :param query: Search query :type query: dict :returns: Search results :rtype: mopidy.models.SearchResult """ logger.debug('Searching in Emby for {}'.format(query)) # something to store the results in data = [] tracks = [] albums = [] artists = [] for itemtype, term in query.items(): for item in term: data.extend(self._get_search(itemtype, item)) # walk through all items and create stuff for item in data: if item['Type'] == 'Audio': track_artists = [ models.Artist(name=artist) for artist in item['Artists'] ] tracks.append( models.Track(uri='emby:track:{}'.format(item['ItemId']), track_no=item.get('IndexNumber'), name=item.get('Name'), artists=track_artists, album=models.Album(name=item.get('Album'), artists=track_artists))) elif item['Type'] == 'MusicAlbum': album_artists = [ models.Artist(name=artist) for artist in item['Artists'] ] albums.append( models.Album(uri='emby:album:{}'.format(item['ItemId']), name=item.get('Name'), artists=album_artists)) elif item['Type'] == 'MusicArtist': artists.append( models.Artist(uri='emby:artist:{}'.format(item['ItemId']), name=item.get('Name'))) return models.SearchResult(uri='emby:search', tracks=tracks, artists=artists, albums=albums)
def get_search_tracks(self, artist_ref, album_id): tracks = [] url = self.api_url( '/Items?IncludeItemTypes=Audio&Recursive=true&' 'AlbumIds={}&UserId={}&'.format( album_id, self.user_id ) ) result = self.http.get(url) if result: raw_tracks = result.get('Items') if artist_ref: # If the artist was in the query, # ensure all tracks belong to that artist tracks = [ models.Track( uri='jellyfin:track:{}'.format(item.get('Id')), track_no=item.get('IndexNumber'), disc_no=track.get('ParentIndexNumber'), name=item.get('Name'), artists=artist_ref, album=models.Album( name=item.get('Album'), artists=artist_ref ) ) for item in raw_tracks if unidecode(artist_ref[0].name.lower()) in ( artist.lower() for artist in item.get('Artists')) ] else: # If the query doesn't contain an artist, return all tracks tracks = [ models.Track( uri='jellyfin:track:{}'.format(item.get('Id')), track_no=item.get('IndexNumber'), name=item.get('Name'), artists=artist_ref, album=models.Album( name=item.get('Album'), artists=artist_ref ) ) for item in raw_tracks ] return tracks
def test_track_playback_ended_scrobbles_played_track(pylast_mock, frontend): frontend.last_start_time = 123 frontend.lastfm = mock.Mock(spec=pylast.LastFMNetwork) artists = [models.Artist(name="ABC"), models.Artist(name="XYZ")] album = models.Album(name="The Collection") track = models.Track( name="One Two Three", artists=artists, album=album, track_no=3, length=180432, musicbrainz_id="123-456", ) tl_track = models.TlTrack(track=track, tlid=17) frontend.track_playback_ended(tl_track, 150000) frontend.lastfm.scrobble.assert_called_with( "ABC, XYZ", "One Two Three", "123", duration="180", album="The Collection", track_number="3", mbid="123-456", )
def _album(obj): try: name = obj["Album"] except KeyError: return None else: return models.Album(name=name, uri=None)
def album(): return models.Album( uri='podcast+http://www.example.com/everything.xml', name='All About Everything', artists=[models.Artist(name='John Doe')], num_tracks=3 )
def mopidy_album_mock(mopidy_artist_mock): return models.Album( artists=[mopidy_artist_mock], date="2001", name="DEF 456", uri="spotify:album:def", )
def album(obj): return models.Album( uri=obj["URI"], name=obj["DisplayName"], artists=list(_artists(obj)), num_tracks=obj.get("ItemCount", obj.get("ChildCount")), )
def album(obj): return models.Album( uri=obj['URI'], name=obj['DisplayName'], artists=list(_artists(obj)), num_tracks=obj.get('ItemCount', obj.get('ChildCount')), )
def lookup(self, uri): pandora_uri = PandoraUri.factory(uri) logger.info("Looking up Pandora {} {}...".format( pandora_uri.uri_type, pandora_uri.uri)) if isinstance(pandora_uri, SearchUri): # Create the station first so that it can be browsed. station_uri = self._create_station_for_token(pandora_uri.token) track = self._browse_tracks(station_uri.uri)[0] # Recursive call to look up first track in station that was searched for. return self.lookup(track.uri) track_kwargs = {"uri": uri} (album_kwargs, artist_kwargs) = {}, {} if isinstance(pandora_uri, TrackUri): try: track = self.lookup_pandora_track(uri) except KeyError: logger.exception(f"Failed to lookup Pandora URI '{uri}'.") return [] else: if isinstance(pandora_uri, AdItemUri): track_kwargs["name"] = "Advertisement" if not track.title: track.title = "(Title not specified)" artist_kwargs["name"] = track.title if not track.company_name: track.company_name = "(Company name not specified)" album_kwargs["name"] = track.company_name else: track_kwargs["name"] = track.song_name track_kwargs["length"] = track.track_length * 1000 try: track_kwargs["bitrate"] = int(track.bitrate) except TypeError: # Bitrate not specified for this stream, ignore. pass artist_kwargs["name"] = track.artist_name album_kwargs["name"] = track.album_name elif isinstance(pandora_uri, StationUri): station = self.backend.api.get_station(pandora_uri.station_id) track_kwargs["name"] = station.name artist_kwargs["name"] = "Pandora Station" album_kwargs["name"] = ", ".join(station.genre) else: raise ValueError( "Unexpected type to perform Pandora track lookup: {}.".format( pandora_uri.uri_type)) artist_kwargs[ "uri"] = uri # Artist lookups should just point back to the track itself. track_kwargs["artists"] = [models.Artist(**artist_kwargs)] album_kwargs[ "uri"] = uri # Album lookups should just point back to the track itself. track_kwargs["album"] = models.Album(**album_kwargs) return [models.Track(**track_kwargs)]
def create_album(self, item): """Create album object from Jellyfin item. :param track: item :type track: dict :returns: Album :rtype: mopidy.models.Album """ item_type = item.get('Type') if item_type == 'Audio': return models.Album(name=item.get('Album'), artists=self.create_artists(item), uri=f'jellyfin:album:{item.get("AlbumId")}') elif item_type == 'MusicAlbum': return models.Album(name=item.get('Name'), artists=self.create_artists(item), uri=f'jellyfin:album:{item.get("Id")}')
def test_search(config, library, results): responses.add(responses.GET, re.compile(r'.*/search\b.*'), json=results) assert library.search({'any': ['foo']}) == models.SearchResult( albums=[ models.Album(name='Foo', uri='podcast+http://example.com/feed1234') ], tracks=[ models.Track( name='Bar', uri='podcast+http://example.com/feed1234#5678', album=models.Album( name='Foo', uri='podcast+http://example.com/feed1234' ) ) ] )
def web_to_album(web_album): artists = [ web_to_artist(web_artist) for web_artist in web_album['artists']] return models.Album( uri=web_album['uri'], name=web_album['name'], artists=artists)
def lookup(self, uri): pandora_uri = PandoraUri.factory(uri) if isinstance(pandora_uri, SearchUri): # Create the station first so that it can be browsed. station_uri = self._create_station_for_token(pandora_uri.token) track = self._browse_tracks(station_uri.uri)[0] # Recursive call to look up first track in station that was searched for. return self.lookup(track.uri) if isinstance(pandora_uri, TrackUri): try: track = self.lookup_pandora_track(uri) except KeyError: logger.exception( "Failed to lookup Pandora URI '{}'.".format(uri)) return [] else: track_kwargs = {'uri': uri} (album_kwargs, artist_kwargs) = {}, {} # TODO: Album.images has been deprecated in Mopidy 1.2. Remove this code when all frontends have been # updated to make use of the newer LibraryController.get_images() images = self.get_images([uri])[uri] if len(images) > 0: album_kwargs = {'images': [image.uri for image in images]} if isinstance(pandora_uri, AdItemUri): track_kwargs['name'] = 'Advertisement' if not track.title: track.title = '(Title not specified)' artist_kwargs['name'] = track.title if not track.company_name: track.company_name = '(Company name not specified)' album_kwargs['name'] = track.company_name else: track_kwargs['name'] = track.song_name track_kwargs['length'] = track.track_length * 1000 try: track_kwargs['bitrate'] = int(track.bitrate) except TypeError: # Bitrate not specified for this stream, ignore. pass artist_kwargs['name'] = track.artist_name album_kwargs['name'] = track.album_name else: raise ValueError( 'Unexpected type to perform Pandora track lookup: {}.'.format( pandora_uri.uri_type)) artist_kwargs[ 'uri'] = uri # Artist lookups should just point back to the track itself. track_kwargs['artists'] = [models.Artist(**artist_kwargs)] album_kwargs[ 'uri'] = uri # Album lookups should just point back to the track itself. track_kwargs['album'] = models.Album(**album_kwargs) return [models.Track(**track_kwargs)]
def test_default_get_images_impl_falls_back_to_album_image(self): album = models.Album(images=['imageuri']) track = models.Track(uri='trackuri', album=album) library = dummy_backend.DummyLibraryProvider(backend=None) library.dummy_library.append(track) expected = {'trackuri': [models.Image(uri='imageuri')]} self.assertEqual(library.get_images(['trackuri']), expected)
def create_album(self, track): """Create album object from track. :param track: Track :type track: dict :returns: Album :rtype: mopidy.models.Album """ return models.Album(name=track.get('Album'), artists=self.create_artists(track))
def get_albums(self, query): raw_artist = [""] raw_albums = [] # Check query for artist name if 'artist' in query: raw_artist = query.get('artist') elif 'albumartist' in query: raw_artist = query.get('albumartist') else: return [] # URL encode artist string artist = quote(raw_artist[0].encode('utf8')).replace('/', '-') artist_ref = [models.Artist(name=raw_artist[0])] url = self.api_url( '/Artists/{}?UserId={}'.format( artist, self.user_id) ) # Pull out artist_id artist_data = self.http.get(url) artist_id = artist_data.get('Id') # Get album list if self.albumartistsort: url = self.api_url( '/Items?AlbumArtistIds={}&UserId={}&' 'IncludeItemTypes=MusicAlbum&Recursive=true'.format( artist_id, self.user_id ) ) else: url = self.api_url( '/Items?ArtistIds={}&UserId={}&' 'IncludeItemTypes=MusicAlbum&Recursive=true'.format( artist_id, self.user_id ) ) result = self.http.get(url) if result: raw_albums = result.get('Items') albums = [ models.Album( uri='jellyfin:album:{}'.format(item.get('Id')), name=item.get('Name'), artists=artist_ref ) for item in raw_albums ] return albums
def to_album(qobuz_album): if qobuz_album is None: return artist = to_artist(qobuz_album.artist) return models.Album( uri="qobuz:album:" + str(qobuz_album.id), name=qobuz_album.title, artists=[artist], )
def compose_bt_track(self, uri=BTPlayerUri.BT_SONG): # Old behaviour -> Use real track data on lookup # Since track data are immutable, it is hacky to change the data on track changes # New behaviour -> Use track structure with the device name and info if not self.bt_player.is_connected(): return None dev_name = unicode(self.bt_player.get_device_name()) bt_info = {'name': dev_name, 'artists': [models.Artist(name='Bluetooth Player')], 'album': models.Album(name=dev_name, uri=BTPlayerUri.BT_DEVICE), 'uri': uri} return models.Track(**bt_info)
def web_to_album(web_album): ref = web_to_album_ref(web_album) if ref is None: return artists = [ web_to_artist(web_artist) for web_artist in web_album.get("artists", []) ] artists = [a for a in artists if a] return models.Album(uri=ref.uri, name=ref.name, artists=artists)
def translate_track_data(bt_track_data, uri): if bt_track_data: mp_track_data = { 'uri': uri, 'name': unicode(bt_track_data.get('Title', '')), 'artists': [models.Artist(name=unicode(bt_track_data.get('Artist')))], 'album': models.Album(name=unicode(bt_track_data.get('Album'))), 'length': int(bt_track_data.get('Duration')) if bt_track_data.get('Duration') != 0xFFFFFFFF else None, 'genre': unicode(bt_track_data.get('Genre'))} return models.Track(**mp_track_data) else: return {}
def lookup(self, uri): if not uri.startswith("transistor:"): return [] if uri == "transistor:noise": return [models.Track(name="Random Noise", uri=uri)] split_uri = uri.split(":") if len(split_uri) == 4: if split_uri[1] == "radios": bank_radios = self.lib.data["radio_banks"][split_uri[2]] for rad in bank_radios: if rad["position"] == int(split_uri[3]): return [ models.Track( name=rad["name"], uri=uri, artists=[models.Artist(name=rad["name"])], album=models.Album(name=split_uri[2]), ) ] if split_uri[1] == "podcasts": for podcast in self.lib.data["podcasts"]: if podcast["position"] == int(split_uri[2]): for ep in podcast["episodes"]: if split_uri[3] == ep["title"]: return [ models.Track( name=ep["title"], uri=uri, artists=[ models.Artist(name=podcast["name"]) ], album=models.Album(name=""), ) ] return []
def test_successful_translation(self, web_track_mock): track = translator.web_to_track(web_track_mock) assert track.uri == 'spotify:track:abc' assert track.name == 'ABC 123' assert list(track.artists) == [ models.Artist(uri='spotify:artist:abba', name='ABBA') ] assert track.album == models.Album(uri='spotify:album:def', name='DEF 456') assert track.track_no == 7 assert track.disc_no == 1 assert track.length == 174300
def test_successful_translation(self, web_track_mock): track = translator.web_to_track(web_track_mock) artists = [models.Artist(uri="spotify:artist:abba", name="ABBA")] assert track.uri == "spotify:track:abc" assert track.name == "ABC 123" assert list(track.artists) == artists assert track.album == models.Album(uri="spotify:album:def", name="DEF 456", artists=artists) assert track.track_no == 7 assert track.disc_no == 1 assert track.length == 174300
def _build_user_albums(self, user): return [ models.Album( uri='lastfm:user-album:{0}'.format( self._generate_uri_tail(user.name, limit=self.limit, period=period) ), name=self._generate_name(user.name, limit=self.limit, period=period), ) for period in self.ALL_PERIODS ]
def web_to_album(web_album): ref = web_to_album_ref(web_album) if ref is None: return artists = [ web_to_artist(web_artist) for web_artist in web_album.get("artists", []) ] artists = [a for a in artists if a] # Note: date can by YYYY-MM-DD, YYYY-MM or YYYY. date = web_album.get("release_date", "").split("-")[0] or None return models.Album(uri=ref.uri, name=ref.name, artists=artists, date=date)
def tracks(self, newest_first=False): album = models.Album(uri=self.uri, name=self.__channel.findtext('title'), artists=self.__artists(self.__channel), num_tracks=len(self.__items)) genre = self.__genre(self.__channel) items = enumerate(self.__items, start=1) for index, item in (reversed(list(items)) if newest_first else items): yield models.Track(uri=self.getitemuri(self.__guid(item)), name=item.findtext('title'), album=album, artists=(self.__artists(item) or album.artists), genre=genre, date=self.__date(item), length=self.__length(item), comment=item.findtext('description'), track_no=index)
def test_album(album=translator.album): model = models.Album(name="foo", uri="internetarchive:foo") assert model == album({"identifier": "foo"}) assert model.replace(name="Foo") == album({ "identifier": "foo", "title": "Foo" }) assert model.replace(artists=[models.Artist(name="bar")]) == album({ "identifier": "foo", "creator": "bar" }) assert model.replace(date="1970-01-01") == album({ "identifier": "foo", "date": "1970-01-01" })
def to_album(sp_album): if not sp_album.is_loaded: return if sp_album.artist is not None and sp_album.artist.is_loaded: artists = [to_artist(sp_album.artist)] else: artists = [] if sp_album.year is not None and sp_album.year != 0: date = f"{sp_album.year}" else: date = None return models.Album( uri=sp_album.link.uri, name=sp_album.name, artists=artists, date=date )
def test_successful_translation(self, sp_track_mock): track = translator.to_track(sp_track_mock, bitrate=320) assert track.uri == 'spotify:track:abc' assert track.name == 'ABC 123' assert list(track.artists) == [ models.Artist(uri='spotify:artist:abba', name='ABBA') ] assert track.album == models.Album( uri='spotify:album:def', name='DEF 456', artists=[models.Artist(uri='spotify:artist:abba', name='ABBA')], date='2001') assert track.track_no == 7 assert track.disc_no == 1 assert track.date == '2001' assert track.length == 174300 assert track.bitrate == 320