Merge pull request #864 from jodal/feature/history
Add history controller to core API
This commit is contained in:
commit
339221089d
@ -37,6 +37,15 @@ Manages everything related to the tracks we are currently playing.
|
||||
:members:
|
||||
|
||||
|
||||
History controller
|
||||
==================
|
||||
|
||||
Keeps record of what tracks have been played.
|
||||
|
||||
.. autoclass:: mopidy.core.HistoryController
|
||||
:members:
|
||||
|
||||
|
||||
Playlists controller
|
||||
====================
|
||||
|
||||
|
||||
@ -10,6 +10,9 @@ v0.20.0 (UNRELEASED)
|
||||
|
||||
**Core API**
|
||||
|
||||
- Added :class:`mopidy.core.HistoryController` which keeps track of what
|
||||
tracks have been played. (Fixes: :issue:`423`, PR: :issue:`803`)
|
||||
|
||||
- Removed ``clear_current_track`` keyword argument to
|
||||
:meth:`mopidy.core.Playback.stop`. It was a leaky internal abstraction,
|
||||
which was never intended to be used externally.
|
||||
|
||||
@ -2,6 +2,7 @@ from __future__ import unicode_literals
|
||||
|
||||
# flake8: noqa
|
||||
from .actor import Core
|
||||
from .history import HistoryController
|
||||
from .library import LibraryController
|
||||
from .listener import CoreListener
|
||||
from .playback import PlaybackController, PlaybackState
|
||||
|
||||
@ -7,6 +7,7 @@ import pykka
|
||||
|
||||
from mopidy import audio, backend, mixer
|
||||
from mopidy.audio import PlaybackState
|
||||
from mopidy.core.history import HistoryController
|
||||
from mopidy.core.library import LibraryController
|
||||
from mopidy.core.listener import CoreListener
|
||||
from mopidy.core.playback import PlaybackController
|
||||
@ -23,6 +24,10 @@ class Core(
|
||||
"""The library controller. An instance of
|
||||
:class:`mopidy.core.LibraryController`."""
|
||||
|
||||
history = None
|
||||
"""The playback history controller. An instance of
|
||||
:class:`mopidy.core.HistoryController`."""
|
||||
|
||||
playback = None
|
||||
"""The playback controller. An instance of
|
||||
:class:`mopidy.core.PlaybackController`."""
|
||||
@ -42,6 +47,8 @@ class Core(
|
||||
|
||||
self.library = LibraryController(backends=self.backends, core=self)
|
||||
|
||||
self.history = HistoryController()
|
||||
|
||||
self.playback = PlaybackController(
|
||||
mixer=mixer, backends=self.backends, core=self)
|
||||
|
||||
|
||||
54
mopidy/core/history.py
Normal file
54
mopidy/core/history.py
Normal file
@ -0,0 +1,54 @@
|
||||
from __future__ import unicode_literals
|
||||
|
||||
import copy
|
||||
import logging
|
||||
import time
|
||||
|
||||
from mopidy import models
|
||||
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
|
||||
class HistoryController(object):
|
||||
|
||||
def __init__(self):
|
||||
self._history = []
|
||||
|
||||
def add(self, track):
|
||||
"""Add track to the playback history.
|
||||
|
||||
:param track: track to add
|
||||
:type track: :class:`mopidy.models.Track`
|
||||
"""
|
||||
if not isinstance(track, models.Track):
|
||||
raise TypeError('Only Track objects can be added to the history')
|
||||
|
||||
timestamp = int(time.time() * 1000)
|
||||
|
||||
name_parts = []
|
||||
if track.artists:
|
||||
name_parts.append(
|
||||
', '.join([artist.name for artist in track.artists]))
|
||||
if track.name is not None:
|
||||
name_parts.append(track.name)
|
||||
name = ' - '.join(name_parts)
|
||||
ref = models.Ref.track(uri=track.uri, name=name)
|
||||
|
||||
self._history.insert(0, (timestamp, ref))
|
||||
|
||||
def get_length(self):
|
||||
"""Get the number of tracks in the history.
|
||||
|
||||
:returns: the history length
|
||||
:rtype: int
|
||||
"""
|
||||
return len(self._history)
|
||||
|
||||
def get_history(self):
|
||||
"""Get the track history.
|
||||
|
||||
:returns: the track history
|
||||
:rtype: list of (timestamp, mopidy.models.Ref) tuples
|
||||
"""
|
||||
return copy.copy(self._history)
|
||||
@ -250,6 +250,7 @@ class PlaybackController(object):
|
||||
|
||||
if success:
|
||||
self.core.tracklist.mark_playing(tl_track)
|
||||
self.core.history.add(tl_track.track)
|
||||
# TODO: replace with stream-changed
|
||||
self._trigger_track_playback_started()
|
||||
else:
|
||||
|
||||
@ -41,6 +41,7 @@ def make_jsonrpc_wrapper(core_actor):
|
||||
objects={
|
||||
'core.get_uri_schemes': core.Core.get_uri_schemes,
|
||||
'core.get_version': core.Core.get_version,
|
||||
'core.history': core.HistoryController,
|
||||
'core.library': core.LibraryController,
|
||||
'core.playback': core.PlaybackController,
|
||||
'core.playlists': core.PlaylistsController,
|
||||
@ -51,6 +52,7 @@ def make_jsonrpc_wrapper(core_actor):
|
||||
'core.describe': inspector.describe,
|
||||
'core.get_uri_schemes': core_actor.get_uri_schemes,
|
||||
'core.get_version': core_actor.get_version,
|
||||
'core.history': core_actor.history,
|
||||
'core.library': core_actor.library,
|
||||
'core.playback': core_actor.playback,
|
||||
'core.playlists': core_actor.playlists,
|
||||
|
||||
47
tests/core/test_history.py
Normal file
47
tests/core/test_history.py
Normal file
@ -0,0 +1,47 @@
|
||||
from __future__ import unicode_literals
|
||||
|
||||
import unittest
|
||||
|
||||
from mopidy.core import HistoryController
|
||||
from mopidy.models import Artist, Track
|
||||
|
||||
|
||||
class PlaybackHistoryTest(unittest.TestCase):
|
||||
|
||||
def setUp(self):
|
||||
self.tracks = [
|
||||
Track(uri='dummy1:a', name='foo',
|
||||
artists=[Artist(name='foober'), Artist(name='barber')]),
|
||||
Track(uri='dummy2:a', name='foo'),
|
||||
Track(uri='dummy3:a', name='bar')
|
||||
]
|
||||
self.history = HistoryController()
|
||||
|
||||
def test_add_track(self):
|
||||
self.history.add(self.tracks[0])
|
||||
self.assertEqual(self.history.get_length(), 1)
|
||||
|
||||
self.history.add(self.tracks[1])
|
||||
self.assertEqual(self.history.get_length(), 2)
|
||||
|
||||
self.history.add(self.tracks[2])
|
||||
self.assertEqual(self.history.get_length(), 3)
|
||||
|
||||
def test_non_tracks_are_rejected(self):
|
||||
with self.assertRaises(TypeError):
|
||||
self.history.add(object())
|
||||
|
||||
self.assertEqual(self.history.get_length(), 0)
|
||||
|
||||
def test_history_entry_contents(self):
|
||||
track = self.tracks[0]
|
||||
self.history.add(track)
|
||||
|
||||
result = self.history.get_history()
|
||||
(timestamp, ref) = result[0]
|
||||
|
||||
self.assertIsInstance(timestamp, int)
|
||||
self.assertEqual(track.uri, ref.uri)
|
||||
self.assertIn(track.name, ref.name)
|
||||
for artist in track.artists:
|
||||
self.assertIn(artist.name, ref.name)
|
||||
Loading…
Reference in New Issue
Block a user