Esempio n. 1
0
def _list_build_query(field, mpd_query):
    """Converts a ``list`` query to a Mopidy query."""
    if mpd_query is None:
        return {}
    # shlex does not seem to be friends with unicode objects
    tokens = shlex.split(mpd_query.encode('utf-8'))
    tokens = [t.decode('utf-8') for t in tokens]
    if len(tokens) == 1:
        if field == u'album':
            return {'artist': [tokens[0]]}
        else:
            raise MpdArgError(
                u'should be "Album" for 3 arguments', command=u'list')
    elif len(tokens) % 2 == 0:
        query = {}
        while tokens:
            key = tokens[0].lower()
            key = str(key) # Needed for kwargs keys on OS X and Windows
            value = tokens[1]
            tokens = tokens[2:]
            if key not in (u'artist', u'album', u'date', u'genre'):
                raise MpdArgError(u'not able to parse args', command=u'list')
            if key in query:
                query[key].append(value)
            else:
                query[key] = [value]
        return query
    else:
        raise MpdArgError(u'not able to parse args', command=u'list')
Esempio n. 2
0
def playpos(context, songpos):
    """
    *musicpd.org, playback section:*

        ``play [SONGPOS]``

        Begins playing the playlist at song number ``SONGPOS``.

    *Clarifications:*

    - ``play "-1"`` when playing is ignored.
    - ``play "-1"`` when paused resumes playback.
    - ``play "-1"`` when stopped with a current track starts playback at the
      current track.
    - ``play "-1"`` when stopped without a current track, e.g. after playlist
      replacement, starts playback at the first track.

    *BitMPC:*

    - issues ``play 6`` without quotes around the argument.
    """
    songpos = int(songpos)
    if songpos == -1:
        return _play_minus_one(context)
    try:
        tl_track = context.core.tracklist.slice(songpos, songpos + 1).get()[0]
        return context.core.playback.play(tl_track).get()
    except IndexError:
        raise MpdArgError('Bad song index', command='play')
Esempio n. 3
0
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(u'No such song', command=u'addid')
    if songpos is not None:
        songpos = int(songpos)
    track = context.backend.library.lookup(uri).get()
    if track is None:
        raise MpdNoExistError(u'No such song', command=u'addid')
    if songpos and songpos > len(
            context.backend.current_playlist.tracks.get()):
        raise MpdArgError(u'Bad song index', command=u'addid')
    cp_track = context.backend.current_playlist.add(track,
                                                    at_position=songpos).get()
    return ('Id', cp_track.cpid)
Esempio n. 4
0
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', command='addid')
    if songpos is not None:
        songpos = int(songpos)
    if songpos and songpos > context.core.tracklist.length.get():
        raise MpdArgError('Bad song index', command='addid')
    tl_tracks = context.core.tracklist.add(uri=uri, at_position=songpos).get()
    if not tl_tracks:
        raise MpdNoExistError('No such song', command='addid')
    return ('Id', tl_tracks[0].tlid)
Esempio n. 5
0
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', command='playlistinfo')
        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)
Esempio n. 6
0
def delete_songpos(context, songpos):
    """See :meth:`delete_range`"""
    try:
        songpos = int(songpos)
        (cpid, _) = context.backend.current_playlist.cp_tracks.get()[songpos]
        context.backend.current_playlist.remove(cpid=cpid)
    except IndexError:
        raise MpdArgError(u'Bad song index', command=u'delete')
Esempio n. 7
0
def delete_songpos(context, songpos):
    """See :meth:`delete_range`"""
    try:
        songpos = int(songpos)
        (tlid, _) = context.core.tracklist.slice(songpos, songpos + 1).get()[0]
        context.core.tracklist.remove(tlid=[tlid])
    except IndexError:
        raise MpdArgError('Bad song index', command='delete')
Esempio n. 8
0
def query_from_mpd_list_format(field, mpd_query):
    """
    Converts an MPD ``list`` query to a Mopidy query.
    """
    # NOTE kwargs dict keys must be bytestrings to work on Python < 2.6.5
    # See https://github.com/mopidy/mopidy/issues/302 for details
    if mpd_query is None:
        return {}
    try:
        # shlex does not seem to be friends with unicode objects
        tokens = shlex.split(mpd_query.encode('utf-8'))
    except ValueError as error:
        if str(error) == 'No closing quotation':
            raise MpdArgError('Invalid unquoted character', command='list')
        else:
            raise
    tokens = [t.decode('utf-8') for t in tokens]
    if len(tokens) == 1:
        if field == 'album':
            if not tokens[0]:
                raise ValueError
            return {b'artist': [tokens[0]]}  # See above NOTE
        else:
            raise MpdArgError('should be "Album" for 3 arguments',
                              command='list')
    elif len(tokens) % 2 == 0:
        query = {}
        while tokens:
            key = str(tokens[0].lower())  # See above NOTE
            value = tokens[1]
            tokens = tokens[2:]
            if key not in ('artist', 'album', 'date', 'genre'):
                raise MpdArgError('not able to parse args', command='list')
            if not value:
                raise ValueError
            if key in query:
                query[key].append(value)
            else:
                query[key] = [value]
        return query
    else:
        raise MpdArgError('not able to parse args', command='list')
Esempio n. 9
0
def query_from_mpd_list_format(field, mpd_query):
    """
    Converts an MPD ``list`` query to a Mopidy query.
    """
    if mpd_query is None:
        return {}
    try:
        # shlex does not seem to be friends with unicode objects
        tokens = shlex.split(mpd_query.encode('utf-8'))
    except ValueError as error:
        if str(error) == 'No closing quotation':
            raise MpdArgError('Invalid unquoted character', command='list')
        else:
            raise
    tokens = [t.decode('utf-8') for t in tokens]
    if len(tokens) == 1:
        if field == 'album':
            if not tokens[0]:
                raise ValueError
            return {'artist': [tokens[0]]}
        else:
            raise MpdArgError('should be "Album" for 3 arguments',
                              command='list')
    elif len(tokens) % 2 == 0:
        query = {}
        while tokens:
            key = tokens[0].lower()
            value = tokens[1]
            tokens = tokens[2:]
            if key not in ('artist', 'album', 'albumartist', 'composer',
                           'date', 'genre', 'performer'):
                raise MpdArgError('not able to parse args', command='list')
            if not value:
                raise ValueError
            if key in query:
                query[key].append(value)
            else:
                query[key] = [value]
        return query
    else:
        raise MpdArgError('not able to parse args', command='list')
Esempio n. 10
0
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)
        start = songpos
        end = songpos + 1
        if start == -1:
            end = None
        cpids = [
            ct[0] for ct in context.backend.current_playlist.cp_tracks.get()
        ]
        return tracks_to_mpd_format(
            context.backend.current_playlist.tracks.get(),
            start,
            end,
            cpids=cpids)
    else:
        if start is None:
            start = 0
        start = int(start)
        if not (0 <= start <= len(
                context.backend.current_playlist.tracks.get())):
            raise MpdArgError(u'Bad song index', command=u'playlistinfo')
        if end is not None:
            end = int(end)
            if end > len(context.backend.current_playlist.tracks.get()):
                end = None
        cpids = [
            ct[0] for ct in context.backend.current_playlist.cp_tracks.get()
        ]
        return tracks_to_mpd_format(
            context.backend.current_playlist.tracks.get(),
            start,
            end,
            cpids=cpids)
Esempio n. 11
0
def delete_range(context, start, end=None):
    """
    *musicpd.org, current playlist section:*

        ``delete [{POS} | {START:END}]``

        Deletes a song from the playlist.
    """
    start = int(start)
    if end is not None:
        end = int(end)
    else:
        end = len(context.backend.current_playlist.tracks.get())
    cp_tracks = context.backend.current_playlist.cp_tracks.get()[start:end]
    if not cp_tracks:
        raise MpdArgError(u'Bad song index', command=u'delete')
    for (cpid, _) in cp_tracks:
        context.backend.current_playlist.remove(cpid=cpid)
Esempio n. 12
0
def delete_range(context, start, end=None):
    """
    *musicpd.org, current playlist section:*

        ``delete [{POS} | {START:END}]``

        Deletes a song from the playlist.
    """
    start = int(start)
    if end is not None:
        end = int(end)
    else:
        end = context.core.tracklist.length.get()
    tl_tracks = context.core.tracklist.slice(start, end).get()
    if not tl_tracks:
        raise MpdArgError('Bad song index', command='delete')
    for (tlid, _) in tl_tracks:
        context.core.tracklist.remove(tlid=[tlid])
Esempio n. 13
0
def count(context, mpd_query):
    """
    *musicpd.org, music database section:*

        ``count {TAG} {NEEDLE}``

        Counts the number of songs and their total playtime in the db
        matching ``TAG`` exactly.

    *GMPC:*

    - does not add quotes around the tag argument.
    - use multiple tag-needle pairs to make more specific searches.
    """
    try:
        query = translator.query_from_mpd_search_format(mpd_query)
    except ValueError:
        raise MpdArgError('incorrect arguments', command='count')
    results = context.core.library.find_exact(**query).get()
    result_tracks = _get_tracks(results)
    return [
        ('songs', len(result_tracks)),
        ('playtime', sum(track.length for track in result_tracks) / 1000),
    ]