def _aa_to_mopidy_album(self, song): uri = 'gmusic:album:' + song['albumId'] name = song['album'] artist = self._aa_to_mopidy_album_artist(song) date = unicode(song.get('year', 0)) images = self._get_images(song) return Album(uri=uri, name=name, artists=[artist], date=date, images=images)
def to_mopidy_album(track): if track is None: return artist = track['albumArtist'] if artist.strip() == '': artist = track['artist'] return Album(name=track['album'], artists=[Artist(name=artist)], num_tracks=track.get('totalTracks', 1), num_discs=track.get('totalDiscs', track.get('disc', 1)), date=track.get('year', 1970))
def test_serialize_with_artists(self): artist = Artist(name="foo") self.assertDictEqual( { "__model__": "Album", "uri": "uri", "name": "name", "artists": [artist.serialize()], }, Album(uri="uri", name="name", artists=[artist]).serialize(), )
def _convert_album(self, album): """ Transforms a beets album into a mopidy Track """ if not album: return album_kwargs = {} artist_kwargs = {} if 'album' in album: album_kwargs['name'] = album['album'] if 'disctotal' in album: album_kwargs['num_discs'] = album['disctotal'] if 'tracktotal' in album: album_kwargs['num_tracks'] = album['tracktotal'] if 'mb_albumid' in album: album_kwargs['musicbrainz_id'] = album['mb_albumid'] album_kwargs['date'] = None if self.backend.use_original_release_date: if 'original_year' in album: album_kwargs['date'] = self._build_date( album['original_year'], album['original_month'], album['original_day']) else: if 'year' in album: album_kwargs['date'] = self._build_date( album['year'], album['month'], album['day']) # if 'added' in item: # album_kwargs['last_modified'] = album['added'] # if 'artpath' in album: # album_kwargs['images'] = [album['artpath']] if 'albumartist' in album: artist_kwargs['name'] = album['albumartist'] if 'mb_albumartistid' in album: artist_kwargs['musicbrainz_id'] = album['mb_albumartistid'] if artist_kwargs: artist = Artist(**artist_kwargs) album_kwargs['artists'] = [artist] if 'id' in album: album_kwargs['uri'] = uricompose('beetslocal', None, 'album:%s:' % album['id']) album = Album(**album_kwargs) return album
def convert_tags_to_track(tags): """Convert our normalized tags to a track. :param tags: dictionary of tag keys with a list of values :type tags: :class:`dict` :rtype: :class:`mopidy.models.Track` """ album_kwargs = {} track_kwargs = {} track_kwargs['composers'] = _artists(tags, Gst.TAG_COMPOSER) track_kwargs['performers'] = _artists(tags, Gst.TAG_PERFORMER) track_kwargs['artists'] = _artists(tags, Gst.TAG_ARTIST, 'musicbrainz-artistid', 'musicbrainz-sortname') album_kwargs['artists'] = _artists(tags, Gst.TAG_ALBUM_ARTIST, 'musicbrainz-albumartistid') track_kwargs['genre'] = '; '.join(tags.get(Gst.TAG_GENRE, [])) track_kwargs['name'] = '; '.join(tags.get(Gst.TAG_TITLE, [])) if not track_kwargs['name']: track_kwargs['name'] = '; '.join(tags.get(Gst.TAG_ORGANIZATION, [])) track_kwargs['comment'] = '; '.join(tags.get('comment', [])) if not track_kwargs['comment']: track_kwargs['comment'] = '; '.join(tags.get(Gst.TAG_LOCATION, [])) if not track_kwargs['comment']: track_kwargs['comment'] = '; '.join(tags.get(Gst.TAG_COPYRIGHT, [])) track_kwargs['track_no'] = tags.get(Gst.TAG_TRACK_NUMBER, [None])[0] track_kwargs['disc_no'] = tags.get(Gst.TAG_ALBUM_VOLUME_NUMBER, [None])[0] track_kwargs['bitrate'] = tags.get(Gst.TAG_BITRATE, [None])[0] track_kwargs['musicbrainz_id'] = tags.get('musicbrainz-trackid', [None])[0] album_kwargs['name'] = tags.get(Gst.TAG_ALBUM, [None])[0] album_kwargs['num_tracks'] = tags.get(Gst.TAG_TRACK_COUNT, [None])[0] album_kwargs['num_discs'] = tags.get(Gst.TAG_ALBUM_VOLUME_COUNT, [None])[0] album_kwargs['musicbrainz_id'] = tags.get('musicbrainz-albumid', [None])[0] album_kwargs['date'] = tags.get(Gst.TAG_DATE, [None])[0] if not album_kwargs['date']: datetime = tags.get(Gst.TAG_DATE_TIME, [None])[0] if datetime is not None: album_kwargs['date'] = datetime.split('T')[0] # Clear out any empty values we found track_kwargs = {k: v for k, v in track_kwargs.items() if v} album_kwargs = {k: v for k, v in album_kwargs.items() if v} # Only bother with album if we have a name to show. if album_kwargs.get('name'): track_kwargs['album'] = Album(**album_kwargs) return Track(**track_kwargs)
def test_list_albumartist_should_not_return_artists_without_names(self): self.backend.library.dummy_find_exact_result = SearchResult( tracks=[Track(album=Album(artists=[Artist(name="")]))] ) self.send_request('list "albumartist"') self.assertNotInResponse("Artist: ") self.assertNotInResponse("Albumartist: ") self.assertNotInResponse("Composer: ") self.assertNotInResponse("Performer: ") self.assertInResponse("OK")
def resolve_url(url, stream=False): video = pafy.new(url) if not stream: uri = 'youtube:video/%s.%s' % ( safe_url(video.title), video.videoid ) else: uri = video.getbestaudio() if not uri: # get video url uri = video.getbest() logger.debug('%s - %s %s %s' % ( video.title, uri.bitrate, uri.mediatype, uri.extension)) uri = uri.url if not uri: return if '-' in video.title: title = video.title.split('-') track = Track( name=title[1].strip(), comment=video.videoid, length=video.length*1000, artists=[Artist(name=title[0].strip())], album=Album( name='Youtube', images=[video.bigthumb, video.bigthumbhd] ), uri=uri ) else: track = Track( name=video.title, comment=video.videoid, length=video.length*1000, album=Album( name='Youtube', images=[video.bigthumb, video.bigthumbhd] ), uri=uri ) return track
def wrap_album(plexalbum, plex_uri_method, resolve_uri_method): '''Wrap a plex search result in mopidy.model.album''' return Album(uri=plex_uri_method(plexalbum.ratingKey, 'plex:album'), name=plexalbum.title, artists=[Artist(uri=plex_uri_method(plexalbum.parentKey, 'plex:artist'), name=plexalbum.parentTitle)], num_tracks=plexalbum.leafCount, num_discs=None, date=str(plexalbum.year), images=[resolve_uri_method(plexalbum.thumb), resolve_uri_method(plexalbum.art)] )
def test_ne(self): track1 = Track(uri='uri1', name='name1', artists=[Artist(name='name1')], album=Album(name='name1'), track_no=1, date='1977-01-01', length=100, bitrate=100, musicbrainz_id='id1') track2 = Track(uri='uri2', name='name2', artists=[Artist(name='name2')], album=Album(name='name2'), track_no=2, date='1977-01-02', length=200, bitrate=200, musicbrainz_id='id2') self.assertNotEqual(track1, track2) self.assertNotEqual(hash(track1), hash(track2))
def _make_album(album_id: str, album: AlbumIndex): kwargs = { "uri": str(AlbumUri(album_id)), "name": album.title, "num_tracks": len(album.tracks), "num_discs": album.tracks[-1].disc_no if len(album.tracks) else 1, } if album.artists: kwargs["artists"] = [_make_artist(artist) for artist in album.artists] if album.musicbrainz_id: kwargs["musicbrainz_id"] = album.musicbrainz_id return Album(**kwargs)
def test_get_metadata_has_track_album_artists(self): self.backend.current_playlist.append([ Track(album=Album(artists=[ Artist(name='a'), Artist(name='b'), Artist(name=None) ])) ]) self.backend.playback.play() result = self.mpris.Get(objects.PLAYER_IFACE, 'Metadata') self.assertIn('xesam:albumArtist', result.keys()) self.assertEquals(result['xesam:albumArtist'], ['a', 'b'])
def test_ne(self): track1 = Track(uri=u'uri1', name=u'name1', artists=[Artist(name=u'name1')], album=Album(name=u'name1'), track_no=1, date=datetime.date.today(), length=100, bitrate=100, musicbrainz_id='id1') track2 = Track(uri=u'uri2', name=u'name2', artists=[Artist(name=u'name2')], album=Album(name=u'name2'), track_no=2, date=datetime.date.today() - datetime.timedelta(days=1), length=200, bitrate=200, musicbrainz_id='id2') self.assertNotEqual(track1, track2) self.assertNotEqual(hash(track1), hash(track2))
def test_currentsong_unicode(self): track = Track(uri='dummy:/à', name='a nàme', album=Album(uri='something:àlbum:12345')) self.backend.library.dummy_library = [track] self.core.tracklist.add(uris=[track.uri]).get() self.core.playback.play().get() self.send_request('currentsong') self.assertInResponse('file: dummy:/à') self.assertInResponse('Title: a nàme') self.assertInResponse('X-AlbumUri: something:àlbum:12345')
def _aa_to_mopidy_album(self, song): album_info = self.backend.session.get_album_info(song['albumId'], include_tracks=False) if album_info is None: return None name = album_info['name'] artist = self._aa_to_mopidy_album_artist(album_info) date = unicode(album_info.get('year', 0)) return Album( name=name, artists=[artist], date=date)
def test_eq(self): date = '1977-01-01' artists = [Artist()] album = Album() track1 = Track( uri='uri', name='name', artists=artists, album=album, track_no=1, date=date, length=100, bitrate=100, musicbrainz_id='id') track2 = Track( uri='uri', name='name', artists=artists, album=album, track_no=1, date=date, length=100, bitrate=100, musicbrainz_id='id') self.assertEqual(track1, track2) self.assertEqual(hash(track1), hash(track2))
def search(self, query=None, uris=None, exact=False): # TODO Support exact search logger.info('youtube LibraryProvider.search "%s"', query) # handle only searching (queries with 'any') not browsing! if not (query and "any" in query): return None search_query = " ".join(query["any"]) logger.info('Searching YouTube for query "%s"', search_query) try: entries = youtube.Entry.search(search_query) except Exception as e: logger.error('search error "%s"', e) return None # load playlist info (to get video_count) of all playlists together playlists = [entry for entry in entries if not entry.is_video] youtube.Playlist.load_info(playlists) tracks = [] for entry in entries: if entry.is_video: uri_base = "youtube:video" album = "YouTube Video" length = int(entry.length.get()) * 1000 else: uri_base = "youtube:playlist" album = "YouTube Playlist (%s videos)" % entry.video_count.get() length = 0 name = entry.title.get() tracks.append( Track( name=name.replace(";", ""), comment=entry.id, length=length, artists=[Artist(name=entry.channel.get())], album=Album(name=album), uri="%s/%s.%s" % (uri_base, safe_url(name), entry.id), ) ) # load video info and playlist videos in the background. they should be # ready by the time the user adds search results to the playing queue for pl in playlists: pl.videos # start loading return SearchResult(uri="youtube:search", tracks=tracks)
def find_exact(self, query=None, uris=None): # TODO Only return results within URI roots given by ``uris`` if query is None: query = {} self._validate_query(query) result_tracks = self._uri_mapping.values() for (field, values) in query.iteritems(): if not hasattr(values, '__iter__'): values = [values] # FIXME this is bound to be slow for large libraries for value in values: if field == 'track_no': q = value else: q = value.strip() uri_filter = lambda t: q == t.uri track_filter = lambda t: q == t.name album_filter = lambda t: q == getattr(t, 'album', Album()).name artist_filter = lambda t: filter(lambda a: q == a.name, t. artists) albumartist_filter = lambda t: any( [q == a.name for a in getattr(t.album, 'artists', [])]) track_no_filter = lambda t: q == t.track_no date_filter = lambda t: q == t.date any_filter = lambda t: (uri_filter(t) or track_filter( t) or album_filter(t) or artist_filter( t) or albumartist_filter(t) or track_no_filter(t) or date_filter(t)) if field == 'uri': result_tracks = filter(uri_filter, result_tracks) elif field == 'track': result_tracks = filter(track_filter, result_tracks) elif field == 'album': result_tracks = filter(album_filter, result_tracks) elif field == 'artist': result_tracks = filter(artist_filter, result_tracks) elif field == 'albumartist': result_tracks = filter(albumartist_filter, result_tracks) elif field == 'track_no': result_tracks = filter(track_no_filter, result_tracks) elif field == 'date': result_tracks = filter(date_filter, result_tracks) elif field == 'any': result_tracks = filter(any_filter, result_tracks) else: raise LookupError('Invalid lookup field: %s' % field) # TODO: add local:search:<query> return SearchResult(uri='local:search', tracks=result_tracks)
def wrap_track(plextrack, plex_uri_method): '''Wrap a plex search result in mopidy.model.track''' return Track(uri=plex_uri_method(plextrack.ratingKey, 'plex:track'), name=plextrack.title, artists=[Artist(uri=plex_uri_method(plextrack.grandparentKey, 'plex:artist'), name=plextrack.grandparentTitle)], album=Album(uri=plex_uri_method(plextrack.parentKey, 'plex:album'), name=plextrack.parentTitle), track_no=None, #plextrack.index, length=plextrack.duration, # TODO: bitrate=plextrack.media.bitrate, comment=plextrack.summary )
def setUp(self): # noqa: N802 self.tags = { 'album': ['album'], 'track-number': [1], 'artist': ['artist'], 'composer': ['composer'], 'performer': ['performer'], 'album-artist': ['albumartist'], 'title': ['track'], 'track-count': [2], 'album-disc-number': [2], 'album-disc-count': [3], 'date': [datetime.date( 2006, 1, 1, )], 'container-format': ['ID3 tag'], 'genre': ['genre'], 'comment': ['comment'], 'musicbrainz-trackid': ['trackid'], 'musicbrainz-albumid': ['albumid'], 'musicbrainz-artistid': ['artistid'], 'musicbrainz-albumartistid': ['albumartistid'], 'bitrate': [1000], } artist = Artist(name='artist', musicbrainz_id='artistid') composer = Artist(name='composer') performer = Artist(name='performer') albumartist = Artist(name='albumartist', musicbrainz_id='albumartistid') album = Album(name='album', num_tracks=2, num_discs=3, musicbrainz_id='albumid', artists=[albumartist]) self.track = Track(name='track', date='2006-01-01', genre='genre', track_no=1, disc_no=2, comment='comment', musicbrainz_id='trackid', album=album, bitrate=1000, artists=[artist], composers=[composer], performers=[performer])
def get_items(self, uri): id_, upload = parse_uri(uri) logger.info("YTMusic getting playlist items for \"%s\"", id_) try: pls = API.get_playlist(id_, limit=100) except Exception: logger.exception("YTMusic failed getting playlist items") pls = None if pls: refs = [] if "tracks" in pls: for track in pls["tracks"]: refs.append(Ref.track(uri=f"ytm:video?id={track['videoId']}", name=track["title"])) duration = track["duration"].split(":") artists = [Artist( uri=f"ytm:artist?id={a['id']}&upload=false", name=a["name"], sortname=a["name"], musicbrainz_id="", ) for a in track["artists"]] if track["album"]: album = Album( uri=f"ytm:album?id={track['album']['id']}&upload=false", name=track["album"]["name"], artists=artists, num_tracks=None, num_discs=None, date="1999", musicbrainz_id="", ) else: album = None TRACKS[track["videoId"]] = Track( uri=f"ytm:video?id={track['videoId']}", name=track["title"], artists=artists, album=album, composers=[], performers=[], genre="", track_no=None, disc_no=None, date="1999", length=(int(duration[0]) * 60 * 1000) + (int(duration[1]) * 1000), bitrate=0, comment="", musicbrainz_id="", last_modified=None, ) return refs return None
def _track(row): kwargs = { 'uri': row.uri, 'name': row.name, 'genre': row.genre, 'track_no': row.track_no, 'disc_no': row.disc_no, 'date': row.date, 'length': row.length, 'bitrate': row.bitrate, 'comment': row.comment, 'musicbrainz_id': row.musicbrainz_id, 'last_modified': row.last_modified } if row.album_uri is not None: if row.albumartist_uri is not None: albumartists = [ Artist(uri=row.albumartist_uri, name=row.albumartist_name, musicbrainz_id=row.albumartist_musicbrainz_id) ] else: albumartists = None kwargs['album'] = Album( uri=row.album_uri, name=row.album_name, artists=albumartists, num_tracks=row.album_num_tracks, num_discs=row.album_num_discs, date=row.album_date, musicbrainz_id=row.album_musicbrainz_id, images=row.album_images.split() if row.album_images else None) if row.artist_uri is not None: kwargs['artists'] = [ Artist(uri=row.artist_uri, name=row.artist_name, musicbrainz_id=row.artist_musicbrainz_id) ] if row.composer_uri is not None: kwargs['composers'] = [ Artist(uri=row.composer_uri, name=row.composer_name, musicbrainz_id=row.composer_musicbrainz_id) ] if row.performer_uri is not None: kwargs['performers'] = [ Artist(uri=row.performer_uri, name=row.performer_name, musicbrainz_id=row.performer_musicbrainz_id) ] return Track(**kwargs)
def test_unicode_cache(self): tracks = parse_mpd_tag_cache(path_to_data_dir('utf8_tag_cache'), path_to_data_dir('')) uri = path_to_uri(path_to_data_dir('song1.mp3')) artists = [Artist(name='æøå')] album = Album(name='æøå', artists=artists) track = Track(uri=uri, name='æøå', artists=artists, album=album, length=4000) self.assertEqual(track, list(tracks)[0])
def raw_album_to_album(self, album): if album is None: return None return Album( name=album.get("title") or album.get("name") or UNKNOWN_ALBUM, num_tracks=album.get("songCount"), uri=uri.get_album_uri(album.get("id")), artists=[ Artist( name=album.get("artist"), uri=uri.get_artist_uri(album.get("artistId")), ) ], )
def _create_track(self, row): art_id = row[b'ArtworkID'] images = [os.path.join(self.art_dir, art_id + '.jpg')] if art_id else [] artist = Artist(name=row[b'ArtistName'], ) album = Album(name=row[b'AlbumName'], artists=[artist], images=images) track = Track(name=row[b'TrackName'], track_no=row[b'TrackNumber'], artists=[artist], album=album, uri=row[b'Uri'], date=unicode(row[b'Year']), length=row[b'Duration']) return track
def _to_mopidy_album(self, song): name = song.get('album', '') artist = self._to_mopidy_album_artist(song) date = unicode(song.get('year', 0)) uri = 'gmusic:album:' + self._create_id(artist.name + name + date) album = Album( uri=uri, name=name, artists=[artist], num_tracks=song.get('totalTrackCount', 1), num_discs=song.get('totalDiscCount', song.get('discNumber', 1)), date=date) self.albums[uri] = album return album
def test_currentsong_unicode(self): track = Track( uri="dummy:/à", name="a nàme", album=Album(uri="something:àlbum:12345"), ) self.backend.library.dummy_library = [track] self.core.tracklist.add(uris=[track.uri]).get() self.core.playback.play().get() self.send_request("currentsong") self.assertInResponse("file: dummy:/à") self.assertInResponse("Title: a nàme") self.assertInResponse("X-AlbumUri: something:àlbum:12345")
def test_get_metadata_use_first_album_image_as_art_url(self): # XXX Currently, the album image order isn't preserved because they # are stored as a frozenset(). We pick the first in the set, which is # sorted alphabetically, thus we get 'bar.jpg', not 'foo.jpg', which # would probably make more sense. self.core.tracklist.add([ Track(album=Album(images=[ 'http://example.com/foo.jpg', 'http://example.com/bar.jpg' ])) ]) self.core.playback.play() result = self.mpris.Get(objects.PLAYER_IFACE, 'Metadata') self.assertIn('mpris:artUrl', result.keys()) self.assertEqual(result['mpris:artUrl'], 'http://example.com/bar.jpg')
def parse_track(self, data, remote_url=False): if not data: return None if not data.get("streamable"): logger.info( f"{data.get('title')!r} can't be streamed from SoundCloud") return None if not data.get("kind") == "track": logger.debug(f"{data.get('title')} is not a track") return None track_kwargs = {} artist_kwargs = {} album_kwargs = {} if "title" in data: label_name = data.get("label_name") if not label_name: label_name = data.get("user", {}).get("username", "Unknown label") track_kwargs["name"] = data["title"] artist_kwargs["name"] = label_name album_kwargs["name"] = "SoundCloud" if "date" in data: track_kwargs["date"] = data["date"] if remote_url: args = (data["sharing"], data["permalink_url"], data["stream_url"]) track_kwargs["uri"] = self.get_streamable_url(*args) if track_kwargs["uri"] is None: logger.info( f"{data.get('title')} can't be streamed from SoundCloud") return None else: track_kwargs[ "uri"] = f"soundcloud:song/{readable_url(data.get('title'))}.{data.get('id')}" track_kwargs["length"] = int(data.get("duration", 0)) track_kwargs["comment"] = data.get("permalink_url", "") if artist_kwargs: track_kwargs["artists"] = [Artist(**artist_kwargs)] if album_kwargs: track_kwargs["album"] = Album(**album_kwargs) return Track(**track_kwargs)
def lookup(self, uri): logger.debug('Cdrom: track selected') i = int(uri.lstrip("cd:/")) - 1 logger.debug('Cdrom: track %s selected', i) (number, name, duration, albumtitle, genre, year) = self.backend.cdrom.tracks[i] album = Album(name=albumtitle) return [ Track(uri=uri, name=name, length=int(duration) * 1000, genre=genre, date=year, album=album) ]
def test_search(self): self.backend.library.dummy_search_result = SearchResult( albums=[Album(uri='dummy:album:a', name='A')], artists=[Artist(uri='dummy:artist:b', name='B')], tracks=[Track(uri='dummy:track:c', name='C')]) self.send_request('search "any" "foo"') self.assertInResponse('file: dummy:album:a') self.assertInResponse('Title: Album: A') self.assertInResponse('file: dummy:artist:b') self.assertInResponse('Title: Artist: B') self.assertInResponse('file: dummy:track:c') self.assertInResponse('Title: C') self.assertInResponse('OK')