Example #1
0
    def previous_track(self, tl_track):
        """
        Returns the track that will be played if calling
        :meth:`mopidy.core.PlaybackController.previous()`.

        For normal playback this is the previous track in the tracklist. If
        random and/or consume is enabled it should return the current track
        instead.

        :param tl_track: the reference track
        :type tl_track: :class:`mopidy.models.TlTrack` or :class:`None`
        :rtype: :class:`mopidy.models.TlTrack` or :class:`None`
        """
        deprecation.warn('core.tracklist.previous_track', pending=True)
        tl_track is None or validation.check_instance(tl_track, TlTrack)

        if self.get_repeat() or self.get_consume() or self.get_random():
            return tl_track

        position = self.index(tl_track)

        if position in (None, 0):
            return None

        # Since we know we are not at zero we have to be somewhere in the range
        # 1 - len(tracks) Thus 'position - 1' will always be within the list.
        return self._tl_tracks[position - 1]
Example #2
0
    def get_playlists(self, include_tracks=True):
        """
        Get the available playlists.

        :rtype: list of :class:`mopidy.models.Playlist`

        .. versionchanged:: 1.0
            If you call the method with ``include_tracks=False``, the
            :attr:`~mopidy.models.Playlist.last_modified` field of the returned
            playlists is no longer set.

        .. deprecated:: 1.0
            Use :meth:`as_list` and :meth:`get_items` instead.
        """
        deprecation.warn('core.playlists.get_playlists')

        playlist_refs = self.as_list()

        if include_tracks:
            playlists = {r.uri: self.lookup(r.uri) for r in playlist_refs}
            # Use the playlist name from as_list() because it knows about any
            # playlist folder hierarchy, which lookup() does not.
            return [
                playlists[r.uri].replace(name=r.name) for r in playlist_refs
                if playlists[r.uri] is not None
            ]
        else:
            return [Playlist(uri=r.uri, name=r.name) for r in playlist_refs]
Example #3
0
 def copy(self, **values):
     """
     .. deprecated:: 1.1
         Use :meth:`replace` instead.
     """
     deprecation.warn('model.immutable.copy')
     return self.replace(**values)
Example #4
0
    def get_playlists(self, include_tracks=True):
        """
        Get the available playlists.

        :rtype: list of :class:`mopidy.models.Playlist`

        .. versionchanged:: 1.0
            If you call the method with ``include_tracks=False``, the
            :attr:`~mopidy.models.Playlist.last_modified` field of the returned
            playlists is no longer set.

        .. deprecated:: 1.0
            Use :meth:`as_list` and :meth:`get_items` instead.
        """
        deprecation.warn('core.playlists.get_playlists')

        playlist_refs = self.as_list()

        if include_tracks:
            playlists = {r.uri: self.lookup(r.uri) for r in playlist_refs}
            # Use the playlist name from as_list() because it knows about any
            # playlist folder hierarchy, which lookup() does not.
            return [
                playlists[r.uri].replace(name=r.name)
                for r in playlist_refs if playlists[r.uri] is not None]
        else:
            return [
                Playlist(uri=r.uri, name=r.name) for r in playlist_refs]
Example #5
0
    def filter(self, criteria=None, **kwargs):
        """
        Filter playlists by the given criterias.

        Examples::

            # Returns track with name 'a'
            filter({'name': 'a'})

            # Returns track with URI 'xyz'
            filter({'uri': 'xyz'})

            # Returns track with name 'a' and URI 'xyz'
            filter({'name': 'a', 'uri': 'xyz'})

        :param criteria: one or more criteria to match by
        :type criteria: dict
        :rtype: list of :class:`mopidy.models.Playlist`

        .. deprecated:: 1.0
            Use :meth:`as_list` and filter yourself.
        """
        deprecation.warn('core.playlists.filter')

        criteria = criteria or kwargs
        validation.check_query(
            criteria, validation.PLAYLIST_FIELDS, list_values=False)

        matches = self.playlists  # TODO: stop using self playlists
        for (key, value) in criteria.iteritems():
            matches = filter(lambda p: getattr(p, key) == value, matches)
        return matches
Example #6
0
    def previous_track(self, tl_track):
        """
        Returns the track that will be played if calling
        :meth:`mopidy.core.PlaybackController.previous()`.

        For normal playback this is the previous track in the tracklist. If
        random and/or consume is enabled it should return the current track
        instead.

        :param tl_track: the reference track
        :type tl_track: :class:`mopidy.models.TlTrack` or :class:`None`
        :rtype: :class:`mopidy.models.TlTrack` or :class:`None`
        """
        deprecation.warn('core.tracklist.previous_track', pending=True)
        tl_track is None or validation.check_instance(tl_track, TlTrack)

        if self.get_repeat() or self.get_consume() or self.get_random():
            return tl_track

        position = self.index(tl_track)

        if position in (None, 0):
            return None

        # Since we know we are not at zero we have to be somewhere in the range
        # 1 - len(tracks) Thus 'position - 1' will always be within the list.
        return self._tl_tracks[position - 1]
Example #7
0
 def copy(self, **values):
     """
     .. deprecated:: 1.1
         Use :meth:`replace` instead.
     """
     deprecation.warn('model.immutable.copy')
     return self.replace(**values)
Example #8
0
 def set_volume(self, volume):
     """
     .. deprecated:: 1.0
         Use :meth:`core.mixer.set_volume()
         <mopidy.core.MixerController.set_volume>` instead.
     """
     deprecation.warn("core.playback.set_volume")
     return self.core.mixer.set_volume(volume)
Example #9
0
 def get_volume(self):
     """
     .. deprecated:: 1.0
         Use :meth:`core.mixer.get_volume()
         <mopidy.core.MixerController.get_volume>` instead.
     """
     deprecation.warn('core.playback.get_volume')
     return self.core.mixer.get_volume()
Example #10
0
    def find_exact(self, query=None, uris=None, **kwargs):
        """Search the library for tracks where ``field`` is ``values``.

        .. deprecated:: 1.0
            Use :meth:`search` with ``exact`` set.
        """
        deprecation.warn("core.library.find_exact")
        return self.search(query=query, uris=uris, exact=True, **kwargs)
Example #11
0
 def set_mute(self, mute):
     """
     .. deprecated:: 1.0
         Use :meth:`core.mixer.set_mute()
         <mopidy.core.MixerController.set_mute>` instead.
     """
     deprecation.warn('core.playback.set_mute')
     return self.core.mixer.set_mute(mute)
Example #12
0
 def set_mute(self, mute):
     """
     .. deprecated:: 1.0
         Use :meth:`core.mixer.set_mute()
         <mopidy.core.MixerController.set_mute>` instead.
     """
     deprecation.warn('core.playback.set_mute')
     return self.core.mixer.set_mute(mute)
Example #13
0
 def get_volume(self):
     """
     .. deprecated:: 1.0
         Use :meth:`core.mixer.get_volume()
         <mopidy.core.MixerController.get_volume>` instead.
     """
     deprecation.warn('core.playback.get_volume')
     return self.core.mixer.get_volume()
Example #14
0
    def find_exact(self, query=None, uris=None, **kwargs):
        """Search the library for tracks where ``field`` is ``values``.

        .. deprecated:: 1.0
            Use :meth:`search` with ``exact`` set.
        """
        deprecation.warn('core.library.find_exact')
        return self.search(query=query, uris=uris, exact=True, **kwargs)
Example #15
0
    def play(self, tl_track=None, tlid=None):
        """
        Play the given track, or if the given tl_track and tlid is
        :class:`None`, play the currently active track.

        Note that the track **must** already be in the tracklist.

        .. deprecated:: 3.0
            The ``tl_track`` argument. Use ``tlid`` instead.

        :param tl_track: track to play
        :type tl_track: :class:`mopidy.models.TlTrack` or :class:`None`
        :param tlid: TLID of the track to play
        :type tlid: :class:`int` or :class:`None`
        """
        if sum(o is not None for o in [tl_track, tlid]) > 1:
            raise ValueError('At most one of "tl_track" and "tlid" may be set')

        tl_track is None or validation.check_instance(tl_track, models.TlTrack)
        tlid is None or validation.check_integer(tlid, min=1)

        if tl_track:
            deprecation.warn("core.playback.play:tl_track_kwarg")

        if tl_track is None and tlid is not None:
            for tl_track in self.core.tracklist.get_tl_tracks():
                if tl_track.tlid == tlid:
                    break
            else:
                tl_track = None

        if tl_track is not None:
            # TODO: allow from outside tracklist, would make sense given refs?
            assert tl_track in self.core.tracklist.get_tl_tracks()
        elif tl_track is None and self.get_state() == PlaybackState.PAUSED:
            self.resume()
            return

        current = self._pending_tl_track or self._current_tl_track
        pending = tl_track or current or self.core.tracklist.next_track(None)
        # avoid endless loop if 'repeat' is 'true' and no track is playable
        # * 2 -> second run to get all playable track in a shuffled playlist
        count = self.core.tracklist.get_length() * 2

        while pending:
            if self._change(pending, PlaybackState.PLAYING):
                break
            else:
                self.core.tracklist._mark_unplayable(pending)
            current = pending
            pending = self.core.tracklist.next_track(current)
            count -= 1
            if not count:
                logger.info("No playable track in the list.")
                break
Example #16
0
    def lookup(self, uri=None, uris=None):
        """
        Lookup the given URIs.

        If the URI expands to multiple tracks, the returned list will contain
        them all.

        :param uri: track URI
        :type uri: string or :class:`None`
        :param uris: track URIs
        :type uris: list of string or :class:`None`
        :rtype: list of :class:`mopidy.models.Track` if uri was set or
            {uri: list of :class:`mopidy.models.Track`} if uris was set.

        .. versionadded:: 1.0
            The ``uris`` argument.

        .. deprecated:: 1.0
            The ``uri`` argument. Use ``uris`` instead.
        """
        if sum(o is not None for o in [uri, uris]) != 1:
            raise ValueError('Exactly one of "uri" or "uris" must be set')

        uris is None or validation.check_uris(uris)
        uri is None or validation.check_uri(uri)

        if uri:
            deprecation.warn('core.library.lookup:uri_arg')

        if uri is not None:
            uris = [uri]

        futures = {}
        results = {u: [] for u in uris}

        # TODO: lookup(uris) to backend APIs
        for backend, backend_uris in self._get_backends_to_uris(uris).items():
            if backend_uris:
                for u in backend_uris:
                    futures[(backend, u)] = backend.library.lookup(u)

        for (backend, u), future in futures.items():
            with _backend_error_handling(backend):
                result = future.get()
                if result is not None:
                    validation.check_instances(result, models.Track)
                    # TODO Consider making Track.uri field mandatory, and
                    # then remove this filtering of tracks without URIs.
                    results[u] = [r for r in result if r.uri]

        if uri:
            return results[uri]
        return results
Example #17
0
    def lookup(self, uri=None, uris=None):
        """
        Lookup the given URIs.

        If the URI expands to multiple tracks, the returned list will contain
        them all.

        :param uri: track URI
        :type uri: string or :class:`None`
        :param uris: track URIs
        :type uris: list of string or :class:`None`
        :rtype: list of :class:`mopidy.models.Track` if uri was set or
            {uri: list of :class:`mopidy.models.Track`} if uris was set.

        .. versionadded:: 1.0
            The ``uris`` argument.

        .. deprecated:: 1.0
            The ``uri`` argument. Use ``uris`` instead.
        """
        if sum(o is not None for o in [uri, uris]) != 1:
            raise ValueError('Exactly one of "uri" or "uris" must be set')

        uris is None or validation.check_uris(uris)
        uri is None or validation.check_uri(uri)

        if uri:
            deprecation.warn('core.library.lookup:uri_arg')

        if uri is not None:
            uris = [uri]

        futures = {}
        results = {u: [] for u in uris}

        # TODO: lookup(uris) to backend APIs
        for backend, backend_uris in self._get_backends_to_uris(uris).items():
            if backend_uris:
                for u in backend_uris:
                    futures[(backend, u)] = backend.library.lookup(u)

        for (backend, u), future in futures.items():
            with _backend_error_handling(backend):
                result = future.get()
                if result is not None:
                    validation.check_instances(result, models.Track)
                    # TODO Consider making Track.uri field mandatory, and
                    # then remove this filtering of tracks without URIs.
                    results[u] = [r for r in result if r.uri]

        if uri:
            return results[uri]
        return results
Example #18
0
    def play(self, tl_track=None, tlid=None):
        """
        Play the given track, or if the given tl_track and tlid is
        :class:`None`, play the currently active track.

        Note that the track **must** already be in the tracklist.

        :param tl_track: track to play
        :type tl_track: :class:`mopidy.models.TlTrack` or :class:`None`
        :param tlid: TLID of the track to play
        :type tlid: :class:`int` or :class:`None`
        """
        if sum(o is not None for o in [tl_track, tlid]) > 1:
            raise ValueError('At most one of "tl_track" and "tlid" may be set')

        tl_track is None or validation.check_instance(tl_track, models.TlTrack)
        tlid is None or validation.check_integer(tlid, min=1)

        if tl_track:
            deprecation.warn('core.playback.play:tl_track_kwarg', pending=True)

        if tl_track is None and tlid is not None:
            for tl_track in self.core.tracklist.get_tl_tracks():
                if tl_track.tlid == tlid:
                    break
            else:
                tl_track = None

        if tl_track is not None:
            # TODO: allow from outside tracklist, would make sense given refs?
            assert tl_track in self.core.tracklist.get_tl_tracks()
        elif tl_track is None and self.get_state() == PlaybackState.PAUSED:
            self.resume()
            return

        current = self._pending_tl_track or self._current_tl_track
        pending = tl_track or current or self.core.tracklist.next_track(None)
        # avoid endless loop if 'repeat' is 'true' and no track is playable
        # * 2 -> second run to get all playable track in a shuffled playlist
        count = self.core.tracklist.get_length() * 2

        while pending:
            if self._change(pending, PlaybackState.PLAYING):
                break
            else:
                self.core.tracklist._mark_unplayable(pending)
            current = pending
            pending = self.core.tracklist.next_track(current)
            count -= 1
            if not count:
                logger.info('No playable track in the list.')
                break
Example #19
0
    def emit_end_of_stream(self):
        """
        Put an end-of-stream token on the playbin. This is typically used in
        combination with :meth:`emit_data`.

        We will get a GStreamer message when the stream playback reaches the
        token, and can then do any end-of-stream related tasks.

        .. deprecated:: 1.0
            Use :meth:`emit_data` with a :class:`None` buffer instead.
        """
        deprecation.warn('audio.emit_end_of_stream')
        self._appsrc.push(None)
Example #20
0
    def emit_end_of_stream(self):
        """
        Put an end-of-stream token on the playbin. This is typically used in
        combination with :meth:`emit_data`.

        We will get a GStreamer message when the stream playback reaches the
        token, and can then do any end-of-stream related tasks.

        .. deprecated:: 1.0
            Use :meth:`emit_data` with a :class:`None` buffer instead.
        """
        deprecation.warn('audio.emit_end_of_stream')
        self._appsrc.push(None)
Example #21
0
def playlist(context):
    """
    *musicpd.org, current playlist section:*

        ``playlist``

        Displays the current playlist.

        .. note::

            Do not use this, instead use ``playlistinfo``.
    """
    deprecation.warn('mpd.protocol.current_playlist.playlist')
    return playlistinfo(context)
Example #22
0
    def next_track(self, tl_track):
        """
        The track that will be played if calling
        :meth:`mopidy.core.PlaybackController.next()`.

        For normal playback this is the next track in the tracklist. If repeat
        is enabled the next track can loop around the tracklist. When random is
        enabled this should be a random track, all tracks should be played once
        before the tracklist repeats.

        .. deprecated:: 3.0
            Use :meth:`get_next_tlid` instead.

        :param tl_track: the reference track
        :type tl_track: :class:`mopidy.models.TlTrack` or :class:`None`
        :rtype: :class:`mopidy.models.TlTrack` or :class:`None`
        """
        deprecation.warn("core.tracklist.next_track")
        tl_track is None or validation.check_instance(tl_track, TlTrack)

        if not self._tl_tracks:
            return None

        if self.get_random() and not self._shuffled:
            if self.get_repeat() or not tl_track:
                logger.debug("Shuffling tracks")
                self._shuffled = self._tl_tracks[:]
                random.shuffle(self._shuffled)

        if self.get_random():
            if self._shuffled:
                return self._shuffled[0]
            return None

        next_index = self.index(tl_track)
        if next_index is None:
            next_index = 0
        else:
            next_index += 1

        if self.get_repeat():
            if self.get_consume() and len(self._tl_tracks) == 1:
                return None
            else:
                next_index %= len(self._tl_tracks)
        elif next_index >= len(self._tl_tracks):
            return None

        return self._tl_tracks[next_index]
Example #23
0
    def next_track(self, tl_track):
        """
        The track that will be played if calling
        :meth:`mopidy.core.PlaybackController.next()`.

        For normal playback this is the next track in the tracklist. If repeat
        is enabled the next track can loop around the tracklist. When random is
        enabled this should be a random track, all tracks should be played once
        before the tracklist repeats.

        :param tl_track: the reference track
        :type tl_track: :class:`mopidy.models.TlTrack` or :class:`None`
        :rtype: :class:`mopidy.models.TlTrack` or :class:`None`
        """
        deprecation.warn('core.tracklist.next_track', pending=True)
        tl_track is None or validation.check_instance(tl_track, TlTrack)

        if not self._tl_tracks:
            return None

        if self.get_random() and not self._shuffled:
            if self.get_repeat() or not tl_track:
                logger.debug('Shuffling tracks')
                self._shuffled = self._tl_tracks[:]
                random.shuffle(self._shuffled)

        if self.get_random():
            if self._shuffled:
                return self._shuffled[0]
            return None

        next_index = self.index(tl_track)
        if next_index is None:
            next_index = 0
        else:
            next_index += 1

        if self.get_repeat():
            if self.get_consume() and len(self._tl_tracks) == 1:
                return None
            else:
                next_index %= len(self._tl_tracks)
        elif next_index >= len(self._tl_tracks):
            return None

        return self._tl_tracks[next_index]
Example #24
0
    def play(self, tl_track=None, tlid=None):
        """
        Play the given track, or if the given tl_track and tlid is
        :class:`None`, play the currently active track.

        Note that the track **must** already be in the tracklist.

        :param tl_track: track to play
        :type tl_track: :class:`mopidy.models.TlTrack` or :class:`None`
        :param tlid: TLID of the track to play
        :type tlid: :class:`int` or :class:`None`
        """
        if sum(o is not None for o in [tl_track, tlid]) > 1:
            raise ValueError('At most one of "tl_track" and "tlid" may be set')

        tl_track is None or validation.check_instance(tl_track, models.TlTrack)
        tlid is None or validation.check_integer(tlid, min=1)

        if tl_track:
            deprecation.warn("core.playback.play:tl_track_kwarg", pending=True)

        if tl_track is None and tlid is not None:
            for tl_track in self.core.tracklist.get_tl_tracks():
                if tl_track.tlid == tlid:
                    break
            else:
                tl_track = None

        if tl_track is not None:
            # TODO: allow from outside tracklist, would make sense given refs?
            assert tl_track in self.core.tracklist.get_tl_tracks()
        elif tl_track is None and self.get_state() == PlaybackState.PAUSED:
            self.resume()
            return

        current = self._pending_tl_track or self._current_tl_track
        pending = tl_track or current or self.core.tracklist.next_track(None)

        while pending:
            # TODO: should we consume unplayable tracks in this loop?
            if self._change(pending, PlaybackState.PLAYING):
                break
            else:
                self.core.tracklist._mark_unplayable(pending)
            current = pending
            pending = self.core.tracklist.next_track(current)
Example #25
0
    def play(self, tl_track=None, tlid=None):
        """
        Play the given track, or if the given tl_track and tlid is
        :class:`None`, play the currently active track.

        Note that the track **must** already be in the tracklist.

        :param tl_track: track to play
        :type tl_track: :class:`mopidy.models.TlTrack` or :class:`None`
        :param tlid: TLID of the track to play
        :type tlid: :class:`int` or :class:`None`
        """
        if sum(o is not None for o in [tl_track, tlid]) > 1:
            raise ValueError('At most one of "tl_track" and "tlid" may be set')

        tl_track is None or validation.check_instance(tl_track, models.TlTrack)
        tlid is None or validation.check_integer(tlid, min=1)

        if tl_track:
            deprecation.warn('core.playback.play:tl_track_kwarg', pending=True)

        if tl_track is None and tlid is not None:
            for tl_track in self.core.tracklist.get_tl_tracks():
                if tl_track.tlid == tlid:
                    break
            else:
                tl_track = None

        if tl_track is not None:
            # TODO: allow from outside tracklist, would make sense given refs?
            assert tl_track in self.core.tracklist.get_tl_tracks()
        elif tl_track is None and self.get_state() == PlaybackState.PAUSED:
            self.resume()
            return

        current = self._pending_tl_track or self._current_tl_track
        pending = tl_track or current or self.core.tracklist.next_track(None)

        while pending:
            if self._change(pending, PlaybackState.PLAYING):
                break
            else:
                self.core.tracklist._mark_unplayable(pending)
            current = pending
            pending = self.core.tracklist.next_track(current)
Example #26
0
    def filter(self, criteria=None, **kwargs):
        """
        Filter the tracklist by the given criterias.

        A criteria consists of a model field to check and a list of values to
        compare it against. If the model field matches one of the values, it
        may be returned.

        Only tracks that matches all the given criterias are returned.

        Examples::

            # Returns tracks with TLIDs 1, 2, 3, or 4 (tracklist ID)
            filter({'tlid': [1, 2, 3, 4]})

            # Returns track with URIs 'xyz' or 'abc'
            filter({'uri': ['xyz', 'abc']})

            # Returns track with a matching TLIDs (1, 3 or 6) and a
            # matching URI ('xyz' or 'abc')
            filter({'tlid': [1, 3, 6], 'uri': ['xyz', 'abc']})

        :param criteria: on or more criteria to match by
        :type criteria: dict, of (string, list) pairs
        :rtype: list of :class:`mopidy.models.TlTrack`

        .. deprecated:: 1.1
            Providing the criteria via ``kwargs``.
        """
        if kwargs:
            deprecation.warn('core.tracklist.filter:kwargs_criteria')

        criteria = criteria or kwargs
        tlids = criteria.pop('tlid', [])
        validation.check_query(criteria, validation.TRACKLIST_FIELDS)
        validation.check_instances(tlids, int)

        matches = self._tl_tracks
        for (key, values) in criteria.items():
            matches = [
                ct for ct in matches if getattr(ct.track, key) in values
            ]
        if tlids:
            matches = [ct for ct in matches if ct.tlid in tlids]
        return matches
Example #27
0
    def filter(self, criteria=None, **kwargs):
        """
        Filter the tracklist by the given criterias.

        A criteria consists of a model field to check and a list of values to
        compare it against. If the model field matches one of the values, it
        may be returned.

        Only tracks that matches all the given criterias are returned.

        Examples::

            # Returns tracks with TLIDs 1, 2, 3, or 4 (tracklist ID)
            filter({'tlid': [1, 2, 3, 4]})

            # Returns track with URIs 'xyz' or 'abc'
            filter({'uri': ['xyz', 'abc']})

            # Returns track with a matching TLIDs (1, 3 or 6) and a
            # matching URI ('xyz' or 'abc')
            filter({'tlid': [1, 3, 6], 'uri': ['xyz', 'abc']})

        :param criteria: on or more criteria to match by
        :type criteria: dict, of (string, list) pairs
        :rtype: list of :class:`mopidy.models.TlTrack`

        .. deprecated:: 1.1
            Providing the criteria via ``kwargs``.
        """
        if kwargs:
            deprecation.warn('core.tracklist.filter:kwargs_criteria')

        criteria = criteria or kwargs
        tlids = criteria.pop('tlid', [])
        validation.check_query(criteria, validation.TRACKLIST_FIELDS)
        validation.check_instances(tlids, int)

        matches = self._tl_tracks
        for (key, values) in criteria.items():
            matches = [
                ct for ct in matches if getattr(ct.track, key) in values]
        if tlids:
            matches = [ct for ct in matches if ct.tlid in tlids]
        return matches
Example #28
0
    def eot_track(self, tl_track):
        """
        The track that will be played after the given track.

        Not necessarily the same track as :meth:`next_track`.

        :param tl_track: the reference track
        :type tl_track: :class:`mopidy.models.TlTrack` or :class:`None`
        :rtype: :class:`mopidy.models.TlTrack` or :class:`None`
        """
        deprecation.warn('core.tracklist.eot_track', pending=True)
        tl_track is None or validation.check_instance(tl_track, TlTrack)
        if self.get_single() and self.get_repeat():
            return tl_track
        elif self.get_single():
            return None

        # Current difference between next and EOT handling is that EOT needs to
        # handle "single", with that out of the way the rest of the logic is
        # shared.
        return self.next_track(tl_track)
Example #29
0
    def eot_track(self, tl_track):
        """
        The track that will be played after the given track.

        Not necessarily the same track as :meth:`next_track`.

        :param tl_track: the reference track
        :type tl_track: :class:`mopidy.models.TlTrack` or :class:`None`
        :rtype: :class:`mopidy.models.TlTrack` or :class:`None`
        """
        deprecation.warn('core.tracklist.eot_track', pending=True)
        tl_track is None or validation.check_instance(tl_track, TlTrack)
        if self.get_single() and self.get_repeat():
            return tl_track
        elif self.get_single():
            return None

        # Current difference between next and EOT handling is that EOT needs to
        # handle "single", with that out of the way the rest of the logic is
        # shared.
        return self.next_track(tl_track)
Example #30
0
    def play(self, tl_track=None, tlid=None):
        """
        Play the given track, or if the given tl_track and tlid is
        :class:`None`, play the currently active track.

        Note that the track **must** already be in the tracklist.

        :param tl_track: track to play
        :type tl_track: :class:`mopidy.models.TlTrack` or :class:`None`
        :param tlid: TLID of the track to play
        :type tlid: :class:`int` or :class:`None`
        """
        if sum(o is not None for o in [tl_track, tlid]) > 1:
            raise ValueError('At most one of "tl_track" and "tlid" may be set')

        tl_track is None or validation.check_instance(tl_track, models.TlTrack)
        tlid is None or validation.check_integer(tlid, min=0)

        if tl_track:
            deprecation.warn('core.playback.play:tl_track_kwarg', pending=True)

        self._play(tl_track=tl_track, tlid=tlid, on_error_step=1)
Example #31
0
    def play(self, tl_track=None, tlid=None):
        """
        Play the given track, or if the given tl_track and tlid is
        :class:`None`, play the currently active track.

        Note that the track **must** already be in the tracklist.

        :param tl_track: track to play
        :type tl_track: :class:`mopidy.models.TlTrack` or :class:`None`
        :param tlid: TLID of the track to play
        :type tlid: :class:`int` or :class:`None`
        """
        if sum(o is not None for o in [tl_track, tlid]) > 1:
            raise ValueError('At most one of "tl_track" and "tlid" may be set')

        tl_track is None or validation.check_instance(tl_track, models.TlTrack)
        tlid is None or validation.check_integer(tlid, min=0)

        if tl_track:
            deprecation.warn('core.playback.play:tl_track_kwarg', pending=True)

        self._play(tl_track=tl_track, tlid=tlid, on_error_step=1)
Example #32
0
    def remove(self, criteria=None, **kwargs):
        """
        Remove the matching tracks from the tracklist.

        Uses :meth:`filter()` to lookup the tracks to remove.

        Triggers the :meth:`mopidy.core.CoreListener.tracklist_changed` event.

        :param criteria: on or more criteria to match by
        :type criteria: dict
        :rtype: list of :class:`mopidy.models.TlTrack` that was removed

        .. deprecated:: 1.1
            Providing the criteria  via ``kwargs``.
        """
        if kwargs:
            deprecation.warn('core.tracklist.remove:kwargs_criteria')

        tl_tracks = self.filter(criteria or kwargs)
        for tl_track in tl_tracks:
            position = self._tl_tracks.index(tl_track)
            del self._tl_tracks[position]
        self._increase_version()
        return tl_tracks
Example #33
0
def pause(context, state=None):
    """
    *musicpd.org, playback section:*

        ``pause {PAUSE}``

        Toggles pause/resumes playing, ``PAUSE`` is 0 or 1.

    *MPDroid:*

    - Calls ``pause`` without any arguments to toogle pause.
    """
    if state is None:
        deprecation.warn('mpd.protocol.playback.pause:state_arg')

        playback_state = context.core.playback.get_state().get()
        if (playback_state == PlaybackState.PLAYING):
            context.core.playback.pause().get()
        elif (playback_state == PlaybackState.PAUSED):
            context.core.playback.resume().get()
    elif state:
        context.core.playback.pause().get()
    else:
        context.core.playback.resume().get()
Example #34
0
def pause(context, state=None):
    """
    *musicpd.org, playback section:*

        ``pause {PAUSE}``

        Toggles pause/resumes playing, ``PAUSE`` is 0 or 1.

    *MPDroid:*

    - Calls ``pause`` without any arguments to toogle pause.
    """
    if state is None:
        deprecation.warn('mpd.protocol.playback.pause:state_arg')

        playback_state = context.core.playback.get_state().get()
        if (playback_state == PlaybackState.PLAYING):
            context.core.playback.pause().get()
        elif (playback_state == PlaybackState.PAUSED):
            context.core.playback.resume().get()
    elif state:
        context.core.playback.pause().get()
    else:
        context.core.playback.resume().get()
Example #35
0
    def remove(self, criteria=None, **kwargs):
        """
        Remove the matching tracks from the tracklist.

        Uses :meth:`filter()` to lookup the tracks to remove.

        Triggers the :meth:`mopidy.core.CoreListener.tracklist_changed` event.

        :param criteria: on or more criteria to match by
        :type criteria: dict
        :rtype: list of :class:`mopidy.models.TlTrack` that was removed

        .. deprecated:: 1.1
            Providing the criteria  via ``kwargs``.
        """
        if kwargs:
            deprecation.warn('core.tracklist.remove:kwargs_criteria')

        tl_tracks = self.filter(criteria or kwargs)
        for tl_track in tl_tracks:
            position = self._tl_tracks.index(tl_track)
            del self._tl_tracks[position]
        self._increase_version()
        return tl_tracks
Example #36
0
    def search(self, query=None, uris=None, exact=False, **kwargs):
        """
        Search the library for tracks where ``field`` contains ``values``.

        If ``uris`` is given, the search is limited to results from within the
        URI roots. For example passing ``uris=['file:']`` will limit the search
        to the local backend.

        Examples::

            # Returns results matching 'a' in any backend
            search({'any': ['a']})

            # Returns results matching artist 'xyz' in any backend
            search({'artist': ['xyz']})

            # Returns results matching 'a' and 'b' and artist 'xyz' in any
            # backend
            search({'any': ['a', 'b'], 'artist': ['xyz']})

            # Returns results matching 'a' if within the given URI roots
            # "file:///media/music" and "spotify:"
            search({'any': ['a']}, uris=['file:///media/music', 'spotify:'])

            # Returns results matching artist 'xyz' and 'abc' in any backend
            search({'artist': ['xyz', 'abc']})

        :param query: one or more queries to search for
        :type query: dict
        :param uris: zero or more URI roots to limit the search to
        :type uris: list of string or :class:`None`
        :param exact: if the search should use exact matching
        :type exact: :class:`bool`
        :rtype: list of :class:`mopidy.models.SearchResult`

        .. versionadded:: 1.0
            The ``exact`` keyword argument, which replaces :meth:`find_exact`.

        .. deprecated:: 1.0
            Previously, if the query was empty, and the backend could support
            it, all available tracks were returned. This has not changed, but
            it is strongly discouraged. No new code should rely on this
            behavior.

        .. deprecated:: 1.1
            Providing the search query via ``kwargs`` is no longer supported.
        """
        query = _normalize_query(query or kwargs)

        uris is None or validation.check_uris(uris)
        query is None or validation.check_query(query)
        validation.check_boolean(exact)

        if kwargs:
            deprecation.warn('core.library.search:kwargs_query')

        if not query:
            deprecation.warn('core.library.search:empty_query')

        futures = {}
        for backend, backend_uris in self._get_backends_to_uris(uris).items():
            futures[backend] = backend.library.search(query=query,
                                                      uris=backend_uris,
                                                      exact=exact)

        # Some of our tests check for LookupError to catch bad queries. This is
        # silly and should be replaced with query validation before passing it
        # to the backends.
        reraise = (TypeError, LookupError)

        results = []
        for backend, future in futures.items():
            try:
                with _backend_error_handling(backend, reraise=reraise):
                    result = future.get()
                    if result is not None:
                        validation.check_instance(result, models.SearchResult)
                        results.append(result)
            except TypeError:
                backend_name = backend.actor_ref.actor_class.__name__
                logger.warning(
                    '%s does not implement library.search() with "exact" '
                    'support. Please upgrade it.', backend_name)

        return results
Example #37
0
    def search(self, query=None, uris=None, exact=False, **kwargs):
        """
        Search the library for tracks where ``field`` contains ``values``.

        If ``uris`` is given, the search is limited to results from within the
        URI roots. For example passing ``uris=['file:']`` will limit the search
        to the local backend.

        Examples::

            # Returns results matching 'a' in any backend
            search({'any': ['a']})

            # Returns results matching artist 'xyz' in any backend
            search({'artist': ['xyz']})

            # Returns results matching 'a' and 'b' and artist 'xyz' in any
            # backend
            search({'any': ['a', 'b'], 'artist': ['xyz']})

            # Returns results matching 'a' if within the given URI roots
            # "file:///media/music" and "spotify:"
            search({'any': ['a']}, uris=['file:///media/music', 'spotify:'])

            # Returns results matching artist 'xyz' and 'abc' in any backend
            search({'artist': ['xyz', 'abc']})

        :param query: one or more queries to search for
        :type query: dict
        :param uris: zero or more URI roots to limit the search to
        :type uris: list of string or :class:`None`
        :param exact: if the search should use exact matching
        :type exact: :class:`bool`
        :rtype: list of :class:`mopidy.models.SearchResult`

        .. versionadded:: 1.0
            The ``exact`` keyword argument, which replaces :meth:`find_exact`.

        .. deprecated:: 1.0
            Previously, if the query was empty, and the backend could support
            it, all available tracks were returned. This has not changed, but
            it is strongly discouraged. No new code should rely on this
            behavior.

        .. deprecated:: 1.1
            Providing the search query via ``kwargs`` is no longer supported.
        """
        query = _normalize_query(query or kwargs)

        uris is None or validation.check_uris(uris)
        query is None or validation.check_query(query)
        validation.check_boolean(exact)

        if kwargs:
            deprecation.warn("core.library.search:kwargs_query")

        if not query:
            deprecation.warn("core.library.search:empty_query")

        futures = {}
        for backend, backend_uris in self._get_backends_to_uris(uris).items():
            futures[backend] = backend.library.search(query=query, uris=backend_uris, exact=exact)

        # Some of our tests check for LookupError to catch bad queries. This is
        # silly and should be replaced with query validation before passing it
        # to the backends.
        reraise = (TypeError, LookupError)

        results = []
        for backend, future in futures.items():
            try:
                with _backend_error_handling(backend, reraise=reraise):
                    result = future.get()
                    if result is not None:
                        validation.check_instance(result, models.SearchResult)
                        results.append(result)
            except TypeError:
                backend_name = backend.actor_ref.actor_class.__name__
                logger.warning(
                    '%s does not implement library.search() with "exact" ' "support. Please upgrade it.", backend_name
                )

        return results
Example #38
0
    def add(self, tracks=None, at_position=None, uri=None, uris=None):
        """
        Add tracks to the tracklist.

        If ``uri`` is given instead of ``tracks``, the URI is looked up in the
        library and the resulting tracks are added to the tracklist.

        If ``uris`` is given instead of ``uri`` or ``tracks``, the URIs are
        looked up in the library and the resulting tracks are added to the
        tracklist.

        If ``at_position`` is given, the tracks are inserted at the given
        position in the tracklist. If ``at_position`` is not given, the tracks
        are appended to the end of the tracklist.

        Triggers the :meth:`mopidy.core.CoreListener.tracklist_changed` event.

        :param tracks: tracks to add
        :type tracks: list of :class:`mopidy.models.Track` or :class:`None`
        :param at_position: position in tracklist to add tracks
        :type at_position: int or :class:`None`
        :param uri: URI for tracks to add
        :type uri: string or :class:`None`
        :param uris: list of URIs for tracks to add
        :type uris: list of string or :class:`None`
        :rtype: list of :class:`mopidy.models.TlTrack`

        .. versionadded:: 1.0
            The ``uris`` argument.

        .. deprecated:: 1.0
            The ``tracks`` and ``uri`` arguments. Use ``uris``.
        """
        if sum(o is not None for o in [tracks, uri, uris]) != 1:
            raise ValueError(
                'Exactly one of "tracks", "uri" or "uris" must be set')

        tracks is None or validation.check_instances(tracks, Track)
        uri is None or validation.check_uri(uri)
        uris is None or validation.check_uris(uris)
        validation.check_integer(at_position or 0)

        if tracks:
            deprecation.warn('core.tracklist.add:tracks_arg')

        if uri:
            deprecation.warn('core.tracklist.add:uri_arg')

        if tracks is None:
            if uri is not None:
                uris = [uri]

            tracks = []
            track_map = self.core.library.lookup(uris=uris)
            for uri in uris:
                tracks.extend(track_map[uri])

        tl_tracks = []
        max_length = self.core._config['core']['max_tracklist_length']

        for track in tracks:
            if self.get_length() >= max_length:
                raise exceptions.TracklistFull(
                    'Tracklist may contain at most %d tracks.' % max_length)

            tl_track = TlTrack(self._next_tlid, track)
            self._next_tlid += 1
            if at_position is not None:
                self._tl_tracks.insert(at_position, tl_track)
                at_position += 1
            else:
                self._tl_tracks.append(tl_track)
            tl_tracks.append(tl_track)

        if tl_tracks:
            self._increase_version()

        return tl_tracks
Example #39
0
    def add(self, tracks=None, at_position=None, uris=None):
        """
        Add tracks to the tracklist.

        If ``uris`` is given instead of ``tracks``, the URIs are
        looked up in the library and the resulting tracks are added to the
        tracklist.

        If ``at_position`` is given, the tracks are inserted at the given
        position in the tracklist. If ``at_position`` is not given, the tracks
        are appended to the end of the tracklist.

        Triggers the :meth:`mopidy.core.CoreListener.tracklist_changed` event.

        :param tracks: tracks to add
        :type tracks: list of :class:`mopidy.models.Track` or :class:`None`
        :param at_position: position in tracklist to add tracks
        :type at_position: int or :class:`None`
        :param uris: list of URIs for tracks to add
        :type uris: list of string or :class:`None`
        :rtype: list of :class:`mopidy.models.TlTrack`

        .. versionadded:: 1.0
            The ``uris`` argument.

        .. deprecated:: 1.0
            The ``tracks`` argument. Use ``uris``.
        """
        if sum(o is not None for o in [tracks, uris]) != 1:
            raise ValueError('Exactly one of "tracks" or "uris" must be set')

        tracks is None or validation.check_instances(tracks, Track)
        uris is None or validation.check_uris(uris)
        validation.check_integer(at_position or 0)

        if tracks:
            deprecation.warn("core.tracklist.add:tracks_arg")

        if tracks is None:
            tracks = []
            track_map = self.core.library.lookup(uris=uris)
            for uri in uris:
                tracks.extend(track_map[uri])

        tl_tracks = []
        max_length = self.core._config["core"]["max_tracklist_length"]

        for track in tracks:
            if self.get_length() >= max_length:
                raise exceptions.TracklistFull(
                    f"Tracklist may contain at most {max_length:d} tracks."
                )

            tl_track = TlTrack(self._next_tlid, track)
            self._next_tlid += 1
            if at_position is not None:
                self._tl_tracks.insert(at_position, tl_track)
                at_position += 1
            else:
                self._tl_tracks.append(tl_track)
            tl_tracks.append(tl_track)

        if tl_tracks:
            self._increase_version()

        return tl_tracks