def playlistinfo(context, songpos=None, start=None, end=None): """ *musicpd.org, current playlist section:* ``playlistinfo [[SONGPOS] | [START:END]]`` Displays a list of all songs in the playlist, or if the optional argument is given, displays information only for the song ``SONGPOS`` or the range of songs ``START:END``. *ncmpc and mpc:* - uses negative indexes, like ``playlistinfo "-1"``, to request the entire playlist """ if songpos == '-1': songpos = None if songpos is not None: songpos = int(songpos) tl_track = context.core.tracklist.tl_tracks.get()[songpos] return translator.track_to_mpd_format(tl_track, position=songpos) else: if start is None: start = 0 start = int(start) if not (0 <= start <= context.core.tracklist.length.get()): raise MpdArgError('Bad song index') if end is not None: end = int(end) if end > context.core.tracklist.length.get(): end = None tl_tracks = context.core.tracklist.tl_tracks.get() return translator.tracks_to_mpd_format(tl_tracks, start, end)
def listallinfo(context, uri=None): """ *musicpd.org, music database section:* ``listallinfo [URI]`` Same as ``listall``, except it also returns metadata info in the same format as ``lsinfo``. Do not use this command. Do not manage a client-side copy of MPD's database. That is fragile and adds huge overhead. It will break with large databases. Instead, query MPD whenever you need something. .. warning:: This command is disabled by default in Mopidy installs. """ result = [] for path, lookup_future in context.browse(uri): if not lookup_future: result.append(('directory', path)) else: for tracks in lookup_future.get().values(): for track in tracks: result.extend(translator.track_to_mpd_format(track)) return result
def lsinfo(context, uri=None): """ *musicpd.org, music database section:* ``lsinfo [URI]`` Lists the contents of the directory ``URI``. When listing the root directory, this currently returns the list of stored playlists. This behavior is deprecated; use ``listplaylists`` instead. MPD returns the same result, including both playlists and the files and directories located at the root level, for both ``lsinfo``, ``lsinfo ""``, and ``lsinfo "/"``. """ result = [] for path, lookup_future in context.browse(uri, recursive=False): if not lookup_future: result.append(('directory', path.lstrip('/'))) else: tracks = lookup_future.get() if tracks: result.extend(translator.track_to_mpd_format(tracks[0])) if uri in (None, '', '/'): result.extend(protocol.stored_playlists.listplaylists(context)) if not result: raise exceptions.MpdNoExistError('Not found') return result
def lsinfo(context, uri=None): """ *musicpd.org, music database section:* ``lsinfo [URI]`` Lists the contents of the directory ``URI``. When listing the root directory, this currently returns the list of stored playlists. This behavior is deprecated; use ``listplaylists`` instead. MPD returns the same result, including both playlists and the files and directories located at the root level, for both ``lsinfo``, ``lsinfo ""``, and ``lsinfo "/"``. """ result = [] for path, lookup_future in context.browse(uri, recursive=False): if not lookup_future: result.append(('directory', path.lstrip('/'))) else: tracks = lookup_future.get() if tracks: result.extend(translator.track_to_mpd_format(tracks[0])) if uri in (None, '', '/'): result.extend(protocol.stored_playlists.listplaylists(context)) return result
def plchanges(context, version): """ *musicpd.org, current playlist section:* ``plchanges {VERSION}`` Displays changed songs currently in the playlist since ``VERSION``. To detect songs that were deleted at the end of the playlist, use ``playlistlength`` returned by status command. *MPDroid:* - Calls ``plchanges "-1"`` two times per second to get the entire playlist. """ # XXX Naive implementation that returns all tracks as changed tracklist_version = context.core.tracklist.get_version().get() if version < tracklist_version: return translator.tracks_to_mpd_format( context.core.tracklist.get_tl_tracks().get()) elif version == tracklist_version: # A version match could indicate this is just a metadata update, so # check for a stream ref and let the client know about the change. stream_title = context.core.playback.get_stream_title().get() if stream_title is None: return None tl_track = context.core.playback.get_current_tl_track().get() position = context.core.tracklist.index(tl_track).get() return translator.track_to_mpd_format( tl_track, position=position, stream_title=stream_title)
def test_track_to_mpd_format_for_empty_track(self): result = translator.track_to_mpd_format(Track(uri="a uri", length=137000)) self.assertIn(("file", "a uri"), result) self.assertIn(("Time", 137), result) self.assertNotIn(("Artist", ""), result) self.assertNotIn(("Title", ""), result) self.assertNotIn(("Album", ""), result) self.assertNotIn(("Track", 0), result) self.assertNotIn(("Date", ""), result) self.assertEqual(len(result), 2)
def test_track_to_mpd_format_for_empty_track(self): result = translator.track_to_mpd_format(Track()) self.assertIn(('file', ''), result) self.assertIn(('Time', 0), result) self.assertIn(('Artist', ''), result) self.assertIn(('Title', ''), result) self.assertIn(('Album', ''), result) self.assertIn(('Track', 0), result) self.assertNotIn(('Date', ''), result) self.assertEqual(len(result), 6)
def test_track_to_mpd_format_for_empty_track(self): result = translator.track_to_mpd_format( Track(uri='a uri', length=137000)) self.assertIn(('file', 'a uri'), result) self.assertIn(('Time', 137), result) self.assertNotIn(('Artist', ''), result) self.assertNotIn(('Title', ''), result) self.assertNotIn(('Album', ''), result) self.assertNotIn(('Track', 0), result) self.assertNotIn(('Date', ''), result) self.assertEqual(len(result), 2)
def test_track_to_mpd_format_for_empty_track(self): result = translator.track_to_mpd_format( Track(uri='a uri', length=137000) ) self.assertIn(('file', 'a uri'), result) self.assertIn(('Time', 137), result) self.assertNotIn(('Artist', ''), result) self.assertNotIn(('Title', ''), result) self.assertNotIn(('Album', ''), result) self.assertNotIn(('Track', 0), result) self.assertNotIn(('Date', ''), result) self.assertEqual(len(result), 2)
def test_track_to_mpd_format_for_empty_track(self): # TODO: this is likely wrong, see: # https://github.com/mopidy/mopidy/issues/923#issuecomment-79584110 result = translator.track_to_mpd_format(Track()) self.assertIn(('file', ''), result) self.assertIn(('Time', 0), result) self.assertIn(('Artist', ''), result) self.assertIn(('Title', ''), result) self.assertIn(('Album', ''), result) self.assertIn(('Track', 0), result) self.assertNotIn(('Date', ''), result) self.assertEqual(len(result), 6)
def currentsong(context): """ *musicpd.org, status section:* ``currentsong`` Displays the song info of the current song (same song that is identified in status). """ tl_track = context.core.playback.current_tl_track.get() if tl_track is not None: position = context.core.tracklist.index(tl_track).get() return track_to_mpd_format(tl_track, position=position)
def currentsong(context): """ *musicpd.org, status section:* ``currentsong`` Displays the song info of the current song (same song that is identified in status). """ tl_track = context.core.playback.current_tl_track.get() if tl_track is not None: position = context.core.tracklist.index(tl_track).get() return translator.track_to_mpd_format(tl_track, position=position)
def playlistfind(context, tag, needle): """ *musicpd.org, current playlist section:* ``playlistfind {TAG} {NEEDLE}`` Finds songs in the current playlist with strict matching. """ if tag == 'filename': tl_tracks = context.core.tracklist.filter({'uri': [needle]}).get() if not tl_tracks: return None position = context.core.tracklist.index(tl_tracks[0]).get() return translator.track_to_mpd_format(tl_tracks[0], position=position) raise exceptions.MpdNotImplemented # TODO
def listallinfo(context, uri=None): """ *musicpd.org, music database section:* ``listallinfo [URI]`` Same as ``listall``, except it also returns metadata info in the same format as ``lsinfo``. """ result = [] for path, lookup_future in context.browse(uri): if not lookup_future: result.append(('directory', path)) else: for track in lookup_future.get(): result.extend(translator.track_to_mpd_format(track)) return result
def playlistid(context, tlid=None): """ *musicpd.org, current playlist section:* ``playlistid {SONGID}`` Displays a list of songs in the playlist. ``SONGID`` is optional and specifies a single song to display info for. """ if tlid is not None: tl_tracks = context.core.tracklist.filter(tlid=[tlid]).get() if not tl_tracks: raise exceptions.MpdNoExistError('No such song') position = context.core.tracklist.index(tl_tracks[0]).get() return translator.track_to_mpd_format(tl_tracks[0], position=position) else: return translator.tracks_to_mpd_format( context.core.tracklist.tl_tracks.get())
def listallinfo(context, uri=None): """ *musicpd.org, music database section:* ``listallinfo [URI]`` Same as ``listall``, except it also returns metadata info in the same format as ``lsinfo``. """ dirs_and_futures = [] result = [] root_path = translator.normalize_path(uri) try: uri = context.directory_path_to_uri(root_path) except MpdNoExistError as e: e.command = 'listallinfo' e.message = 'Not found' raise browse_futures = [(root_path, context.core.library.browse(uri))] while browse_futures: base_path, future = browse_futures.pop() for ref in future.get(): if ref.type == Ref.DIRECTORY: path = '/'.join([base_path, ref.name.replace('/', '')]) future = context.core.library.browse(ref.uri) browse_futures.append((path, future)) dirs_and_futures.append(('directory', path)) elif ref.type == Ref.TRACK: # TODO Lookup tracks in batch for better performance dirs_and_futures.append(context.core.library.lookup(ref.uri)) result = [] for obj in dirs_and_futures: if hasattr(obj, 'get'): for track in obj.get(): result.extend(translator.track_to_mpd_format(track)) else: result.append(obj) if not result: raise MpdNoExistError('Not found') return [('directory', root_path)] + result
def test_track_to_mpd_format_for_nonempty_track(self): result = translator.track_to_mpd_format( TlTrack(122, self.track), position=9) self.assertIn(('file', 'a uri'), result) self.assertIn(('Time', 137), result) self.assertIn(('Artist', 'an artist'), result) self.assertIn(('Title', 'a name'), result) self.assertIn(('Album', 'an album'), result) self.assertIn(('AlbumArtist', 'an other artist'), result) self.assertIn(('Composer', 'a composer'), result) self.assertIn(('Performer', 'a performer'), result) self.assertIn(('Genre', 'a genre'), result) self.assertIn(('Track', '7/13'), result) self.assertIn(('Date', datetime.date(1977, 1, 1)), result) self.assertIn(('Disc', '1'), result) self.assertIn(('Pos', 9), result) self.assertIn(('Id', 122), result) self.assertNotIn(('Comment', 'a comment'), result) self.assertEqual(len(result), 14)
def test_track_to_mpd_format_for_nonempty_track(self): result = translator.track_to_mpd_format(TlTrack(122, self.track), position=9) self.assertIn(("file", "a uri"), result) self.assertIn(("Time", 137), result) self.assertIn(("Artist", "an artist"), result) self.assertIn(("Title", "a name"), result) self.assertIn(("Album", "an album"), result) self.assertIn(("AlbumArtist", "an other artist"), result) self.assertIn(("Composer", "a composer"), result) self.assertIn(("Performer", "a performer"), result) self.assertIn(("Genre", "a genre"), result) self.assertIn(("Track", "7/13"), result) self.assertIn(("Date", "1977-01-01"), result) self.assertIn(("Disc", 1), result) self.assertIn(("Pos", 9), result) self.assertIn(("Id", 122), result) self.assertIn(("X-AlbumUri", "urischeme:album:12345"), result) self.assertIn(("X-AlbumImage", "image1"), result) self.assertNotIn(("Comment", "a comment"), result) self.assertEqual(len(result), 16)
def test_track_to_mpd_format_for_nonempty_track(self): result = translator.track_to_mpd_format(TlTrack(122, self.track), position=9) self.assertIn(('file', 'à uri'), result) self.assertIn(('Time', 137), result) self.assertIn(('Artist', 'an artist'), result) self.assertIn(('Title', 'a nàme'), result) self.assertIn(('Album', 'an album'), result) self.assertIn(('AlbumArtist', 'an other artist'), result) self.assertIn(('Composer', 'a composer'), result) self.assertIn(('Performer', 'a performer'), result) self.assertIn(('Genre', 'a genre'), result) self.assertIn(('Track', '7/13'), result) self.assertIn(('Date', '1977-01-01'), result) self.assertIn(('Disc', 1), result) self.assertIn(('Pos', 9), result) self.assertIn(('Id', 122), result) self.assertIn(('X-AlbumUri', 'urischeme:àlbum:12345'), result) self.assertIn(('X-AlbumImage', 'image1'), result) self.assertNotIn(('Comment', 'a comment'), result) self.assertEqual(len(result), 16)
def test_track_to_mpd_format_for_nonempty_track(self): result = translator.track_to_mpd_format( TlTrack(122, self.track), position=9) self.assertIn(('file', 'a uri'), result) self.assertIn(('Time', 137), result) self.assertIn(('Artist', 'an artist'), result) self.assertIn(('Title', 'a name'), result) self.assertIn(('Album', 'an album'), result) self.assertIn(('AlbumArtist', 'an other artist'), result) self.assertIn(('Composer', 'a composer'), result) self.assertIn(('Performer', 'a performer'), result) self.assertIn(('Genre', 'a genre'), result) self.assertIn(('Track', '7/13'), result) self.assertIn(('Date', '1977-01-01'), result) self.assertIn(('Disc', 1), result) self.assertIn(('Pos', 9), result) self.assertIn(('Id', 122), result) self.assertIn(('X-AlbumUri', 'urischeme:album:12345'), result) self.assertIn(('X-AlbumImage', 'image1'), result) self.assertNotIn(('Comment', 'a comment'), result) self.assertEqual(len(result), 16)
def lsinfo(context, uri=None): """ *musicpd.org, music database section:* ``lsinfo [URI]`` Lists the contents of the directory ``URI``. When listing the root directory, this currently returns the list of stored playlists. This behavior is deprecated; use ``listplaylists`` instead. MPD returns the same result, including both playlists and the files and directories located at the root level, for both ``lsinfo``, ``lsinfo ""``, and ``lsinfo "/"``. """ result = [] root_path = translator.normalize_path(uri, relative=True) try: uri = context.directory_path_to_uri(root_path) except MpdNoExistError as e: e.command = 'lsinfo' e.message = 'Not found' raise if uri is None: result.extend(stored_playlists.listplaylists(context)) for ref in context.core.library.browse(uri).get(): if ref.type == Ref.DIRECTORY: path = '/'.join([root_path, ref.name.replace('/', '')]) result.append(('directory', path.lstrip('/'))) elif ref.type == Ref.TRACK: # TODO Lookup tracks in batch for better performance tracks = context.core.library.lookup(ref.uri).get() if tracks: result.extend(translator.track_to_mpd_format(tracks[0])) return result
def test_track_to_mpd_format_with_last_modified(self): track = self.track.replace(last_modified=995303899000) result = translator.track_to_mpd_format(track) self.assertIn(('Last-Modified', '2001-07-16T17:18:19Z'), result)
def test_track_to_mpd_format_with_stream_and_no_track_name(self): track = self.track.replace(name=None) result = translator.track_to_mpd_format(track, stream_title="foo") self.assertNotIn(("Name", ""), result) self.assertIn(("Title", "foo"), result)
def test_track_to_mpd_format_with_empty_stream_title(self): result = translator.track_to_mpd_format(self.track, stream_title="") self.assertIn(("Name", "a name"), result) self.assertNotIn(("Title", ""), result)
def test_track_to_mpd_format_musicbrainz_artistid(self): artist = list(self.track.artists)[0].replace(musicbrainz_id="foo") track = self.track.replace(artists=[artist]) result = translator.track_to_mpd_format(track) self.assertIn(("MUSICBRAINZ_ARTISTID", "foo"), result)
def test_track_to_mpd_format_musicbrainz_trackid(self): track = self.track.copy(musicbrainz_id='foo') result = translator.track_to_mpd_format(track) self.assertIn(('MUSICBRAINZ_TRACKID', 'foo'), result)
def test_track_to_mpd_format_musicbrainz_albumid(self): album = self.track.album.copy(musicbrainz_id='foo') track = self.track.copy(album=album) result = translator.track_to_mpd_format(track) self.assertIn(('MUSICBRAINZ_ALBUMID', 'foo'), result)
def test_track_to_mpd_format_musicbrainz_albumartistid(self): artist = list(self.track.artists)[0].copy(musicbrainz_id='foo') album = self.track.album.copy(artists=[artist]) track = self.track.copy(album=album) result = translator.track_to_mpd_format(track) self.assertIn(('MUSICBRAINZ_ALBUMARTISTID', 'foo'), result)
def test_track_to_mpd_format_with_last_modified(self): track = self.track.replace(last_modified=995303899000) result = translator.track_to_mpd_format(track) self.assertIn(("Last-Modified", "2001-07-16T17:18:19Z"), result)
def test_track_to_mpd_format_with_position_and_tlid(self): result = translator.track_to_mpd_format(TlTrack(2, Track(uri="a uri")), position=1) self.assertIn(("Pos", 1), result) self.assertIn(("Id", 2), result)
def test_track_to_mpd_format_with_position(self): result = translator.track_to_mpd_format(Track(), position=1) self.assertNotIn(("Pos", 1), result)
def test_track_to_mpd_format_with_empty_stream_title(self): result = translator.track_to_mpd_format(self.track, stream_title='') self.assertIn(('Name', 'a nàme'), result) self.assertNotIn(('Title', ''), result)
def test_track_to_mpd_format_with_position_and_tlid(self): result = translator.track_to_mpd_format(TlTrack(2, Track(uri='a uri')), position=1) self.assertIn(('Pos', 1), result) self.assertIn(('Id', 2), result)
def test_track_to_mpd_format_with_tlid(self): result = translator.track_to_mpd_format(TlTrack(1, Track())) self.assertNotIn(('Id', 1), result)
def test_track_to_mpd_format_with_position(self): result = translator.track_to_mpd_format(Track(), position=1) self.assertNotIn(('Pos', 1), result)
def test_track_to_mpd_format_with_stream_and_no_track_name(self): track = self.track.replace(name=None) result = translator.track_to_mpd_format(track, stream_title='foo') self.assertNotIn(('Name', ''), result) self.assertIn(('Title', 'foo'), result)
def test_track_to_mpd_format_with_tlid(self): result = translator.track_to_mpd_format(TlTrack(1, Track())) self.assertNotIn(("Id", 1), result)
def test_track_to_mpd_format_with_last_modified_of_zero(self): track = self.track.replace(last_modified=0) result = translator.track_to_mpd_format(track) keys = [k for k, v in result] self.assertNotIn('Last-Modified', keys)
def test_track_to_mpd_format_musicbrainz_trackid(self): track = self.track.replace(musicbrainz_id="foo") result = translator.track_to_mpd_format(track) self.assertIn(("MUSICBRAINZ_TRACKID", "foo"), result)
def test_track_to_mpd_format_musicbrainz_trackid(self): track = self.track.replace(musicbrainz_id='foo') result = translator.track_to_mpd_format(track) self.assertIn(('MUSICBRAINZ_TRACKID', 'foo'), result)
def test_track_to_mpd_format_with_last_modified_of_zero(self): track = self.track.replace(last_modified=0) result = translator.track_to_mpd_format(track) keys = [k for k, v in result] self.assertNotIn("Last-Modified", keys)
def test_track_to_mpd_format_musicbrainz_albumid(self): album = self.track.album.replace(musicbrainz_id='foo') track = self.track.replace(album=album) result = translator.track_to_mpd_format(track) self.assertIn(('MUSICBRAINZ_ALBUMID', 'foo'), result)
def test_track_to_mpd_format_musicbrainz_albumid(self): album = self.track.album.replace(musicbrainz_id="foo") track = self.track.replace(album=album) result = translator.track_to_mpd_format(track) self.assertIn(("MUSICBRAINZ_ALBUMID", "foo"), result)
def test_track_to_mpd_format_musicbrainz_artistid(self): artist = list(self.track.artists)[0].replace(musicbrainz_id='foo') track = self.track.replace(artists=[artist]) result = translator.track_to_mpd_format(track) self.assertIn(('MUSICBRAINZ_ARTISTID', 'foo'), result)