def addid(context, uri, songpos=None): """ *musicpd.org, current playlist section:* ``addid {URI} [POSITION]`` Adds a song to the playlist (non-recursive) and returns the song id. ``URI`` is always a single file or URL. For example:: addid "foo.mp3" Id: 999 OK *Clarifications:* - ``addid ""`` should return an error. """ if not uri: raise MpdNoExistError('No such song') if songpos is not None: songpos = int(songpos) if songpos and songpos > context.core.tracklist.length.get(): raise MpdArgError('Bad song index') tl_tracks = context.core.tracklist.add(uri=uri, at_position=songpos).get() if not tl_tracks: raise MpdNoExistError('No such song') return ('Id', tl_tracks[0].tlid)
def test_mpd_noexist_error(self): try: raise MpdNoExistError(command='foo') except MpdNoExistError as e: self.assertEqual( e.get_mpd_ack(), 'ACK [50@0] {foo} ')
def listall(context, uri=None): """ *musicpd.org, music database section:* ``listall [URI]`` Lists all songs and directories in ``URI``. """ result = [] root_path = translator.normalize_path(uri) # TODO: doesn't the dispatcher._call_handler have enough info to catch # the error this can produce, set the command and then 'raise'? try: uri = context.directory_path_to_uri(root_path) except MpdNoExistError as e: e.command = 'listall' 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('/', '')]) result.append(('directory', path)) browse_futures.append( (path, context.core.library.browse(ref.uri))) elif ref.type == Ref.TRACK: result.append(('file', ref.uri)) if not result: raise MpdNoExistError('Not found') return [('directory', root_path)] + result
def load(context, name, start=None, end=None): """ *musicpd.org, stored playlists section:* ``load {NAME} [START:END]`` Loads the playlist into the current queue. Playlist plugins are supported. A range may be specified to load only a part of the playlist. *Clarifications:* - ``load`` appends the given playlist to the current playlist. - MPD 0.17.1 does not support open-ended ranges, i.e. without end specified, for the ``load`` command, even though MPD's general range docs allows open-ended ranges. - MPD 0.17.1 does not fail if the specified range is outside the playlist, in either or both ends. """ playlist = context.lookup_playlist_from_name(name) if not playlist: raise MpdNoExistError('No such playlist') if start is not None: start = int(start) if end is not None: end = int(end) context.core.tracklist.add(playlist.tracks[start:end])
def deleteid(context, tlid): """ *musicpd.org, current playlist section:* ``deleteid {SONGID}`` Deletes the song ``SONGID`` from the playlist """ tlid = int(tlid) tl_tracks = context.core.tracklist.remove(tlid=[tlid]).get() if not tl_tracks: raise MpdNoExistError('No such song')
def disableoutput(context, outputid): """ *musicpd.org, audio output section:* ``disableoutput`` Turns an output off. """ if int(outputid) == 0: context.core.playback.set_mute(False) else: raise MpdNoExistError('No such audio output')
def swapid(context, tlid1, tlid2): """ *musicpd.org, current playlist section:* ``swapid {SONG1} {SONG2}`` Swaps the positions of ``SONG1`` and ``SONG2`` (both song ids). """ tlid1 = int(tlid1) tlid2 = int(tlid2) tl_tracks1 = context.core.tracklist.filter(tlid=[tlid1]).get() tl_tracks2 = context.core.tracklist.filter(tlid=[tlid2]).get() if not tl_tracks1 or not tl_tracks2: raise MpdNoExistError('No such song') position1 = context.core.tracklist.index(tl_tracks1[0]).get() position2 = context.core.tracklist.index(tl_tracks2[0]).get() swap(context, position1, position2)
def moveid(context, tlid, to): """ *musicpd.org, current playlist section:* ``moveid {FROM} {TO}`` Moves the song with ``FROM`` (songid) to ``TO`` (playlist index) in the playlist. If ``TO`` is negative, it is relative to the current song in the playlist (if there is one). """ tlid = int(tlid) to = int(to) tl_tracks = context.core.tracklist.filter(tlid=[tlid]).get() if not tl_tracks: raise MpdNoExistError('No such song') position = context.core.tracklist.index(tl_tracks[0]).get() context.core.tracklist.move(position, position + 1, to)
def listplaylistinfo(context, name): """ *musicpd.org, stored playlists section:* ``listplaylistinfo {NAME}`` Lists songs in the playlist ``NAME.m3u``. Output format: Standard track listing, with fields: file, Time, Title, Date, Album, Artist, Track """ playlist = context.lookup_playlist_from_name(name) if not playlist: raise MpdNoExistError('No such playlist') return playlist_to_mpd_format(playlist)
def listplaylist(context, name): """ *musicpd.org, stored playlists section:* ``listplaylist {NAME}`` Lists the files in the playlist ``NAME.m3u``. Output format:: file: relative/path/to/file1.flac file: relative/path/to/file2.ogg file: relative/path/to/file3.mp3 """ playlist = context.lookup_playlist_from_name(name) if not playlist: raise MpdNoExistError('No such playlist') return ['file: %s' % t.uri for t in playlist.tracks]
def add(context, uri): """ *musicpd.org, current playlist section:* ``add {URI}`` Adds the file ``URI`` to the playlist (directories add recursively). ``URI`` can also be a single file. *Clarifications:* - ``add ""`` should add all tracks in the library to the current playlist. """ if not uri.strip('/'): return tl_tracks = context.core.tracklist.add(uri=uri).get() if tl_tracks: return try: uri = context.directory_path_to_uri(translator.normalize_path(uri)) except MpdNoExistError as e: e.command = 'add' e.message = 'directory or file not found' raise browse_futures = [context.core.library.browse(uri)] lookup_futures = [] while browse_futures: for ref in browse_futures.pop().get(): if ref.type == ref.DIRECTORY: browse_futures.append(context.core.library.browse(ref.uri)) else: lookup_futures.append(context.core.library.lookup(ref.uri)) tracks = [] for future in lookup_futures: tracks.extend(future.get()) if not tracks: raise MpdNoExistError('directory or file not found') context.core.tracklist.add(tracks=tracks)
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 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: tlid = int(tlid) tl_tracks = context.core.tracklist.filter(tlid=[tlid]).get() if not tl_tracks: raise 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 playid(context, tlid): """ *musicpd.org, playback section:* ``playid [SONGID]`` Begins playing the playlist at song ``SONGID``. *Clarifications:* - ``playid "-1"`` when playing is ignored. - ``playid "-1"`` when paused resumes playback. - ``playid "-1"`` when stopped with a current track starts playback at the current track. - ``playid "-1"`` when stopped without a current track, e.g. after playlist replacement, starts playback at the first track. """ tlid = int(tlid) if tlid == -1: return _play_minus_one(context) tl_tracks = context.core.tracklist.filter(tlid=[tlid]).get() if not tl_tracks: raise MpdNoExistError('No such song') return context.core.playback.play(tl_tracks[0]).get()