diff --git a/mopidy/commands.py b/mopidy/commands.py index fecabe98..d9b4ce0e 100644 --- a/mopidy/commands.py +++ b/mopidy/commands.py @@ -279,7 +279,7 @@ class RootCommand(Command): mixer = self.start_mixer(config, mixer_class) audio = self.start_audio(config, mixer) backends = self.start_backends(config, backend_classes, audio) - core = self.start_core(mixer, backends) + core = self.start_core(mixer, backends, audio) self.start_frontends(config, frontend_classes, core) loop.run() except (exceptions.BackendError, @@ -360,9 +360,9 @@ class RootCommand(Command): return backends - def start_core(self, mixer, backends): + def start_core(self, mixer, backends, audio): logger.info('Starting Mopidy core') - return Core.start(mixer=mixer, backends=backends).proxy() + return Core.start(mixer=mixer, backends=backends, audio=audio).proxy() def start_frontends(self, config, frontend_classes, core): logger.info( diff --git a/mopidy/core/actor.py b/mopidy/core/actor.py index 75c06f69..ff60f190 100644 --- a/mopidy/core/actor.py +++ b/mopidy/core/actor.py @@ -7,12 +7,14 @@ import pykka from mopidy import audio, backend, mixer from mopidy.audio import PlaybackState +from mopidy.audio.utils import convert_tags_to_track from mopidy.core.history import HistoryController from mopidy.core.library import LibraryController from mopidy.core.listener import CoreListener from mopidy.core.playback import PlaybackController from mopidy.core.playlists import PlaylistsController from mopidy.core.tracklist import TracklistController +from mopidy.models import TlTrack, Track from mopidy.utils import versioning @@ -40,7 +42,7 @@ class Core( """The tracklist controller. An instance of :class:`mopidy.core.TracklistController`.""" - def __init__(self, mixer=None, backends=None): + def __init__(self, mixer=None, backends=None, audio=None): super(Core, self).__init__() self.backends = Backends(backends) @@ -57,6 +59,8 @@ class Core( self.tracklist = TracklistController(core=self) + self.audio = audio + def get_uri_schemes(self): futures = [b.uri_schemes for b in self.backends] results = pykka.get_all(futures) @@ -102,6 +106,34 @@ class Core( # Forward event from mixer to frontends CoreListener.send('mute_changed', mute=mute) + def tags_changed(self, tags): + # Validity checks + if not self.audio: + return + if self.playback.current_tl_track is None: + return + + tags = self.audio.get_current_tags().get() + if not tags: + return + + # Request available metadata and set a track + mt_track = convert_tags_to_track(tags) + + # Merge current_tl_track with metadata in current_metadata_track + c_track = self.playback.current_tl_track.track + track_kwargs = {k: v for k, v in c_track.__dict__.items() if v} + for k, v in mt_track.__dict__.items(): + if v: + track_kwargs[k] = v + + self.playback.current_metadata_track = TlTrack(**{ + 'tlid': self.playback.current_tl_track.tlid, + 'track': Track(**track_kwargs)}) + + # Send event to frontends + CoreListener.send('current_metadata_changed') + class Backends(list): def __init__(self, backends): diff --git a/mopidy/core/listener.py b/mopidy/core/listener.py index 2c027e1b..9d952473 100644 --- a/mopidy/core/listener.py +++ b/mopidy/core/listener.py @@ -163,3 +163,11 @@ class CoreListener(listener.Listener): :type time_position: int """ pass + + def current_metadata_changed(self): + """ + Called whenever current track's metadata changed + + *MAY* be implemented by actor. + """ + pass diff --git a/mopidy/core/playback.py b/mopidy/core/playback.py index ef3cc4b2..2bc2fbe6 100644 --- a/mopidy/core/playback.py +++ b/mopidy/core/playback.py @@ -126,6 +126,15 @@ class PlaybackController(object): mute = property(get_mute, set_mute) """Mute state as a :class:`True` if muted, :class:`False` otherwise""" + def get_current_metadata_track(self): + return self.current_metadata_track + + current_metadata_track = None + """ + The currently playing metadata :class:`mopidy.models.Track`, + or :class:`None`. + """ + # Methods # TODO: remove this. diff --git a/mopidy/mpd/actor.py b/mopidy/mpd/actor.py index c9ffff02..b56e507d 100644 --- a/mopidy/mpd/actor.py +++ b/mopidy/mpd/actor.py @@ -73,3 +73,6 @@ class MpdFrontend(pykka.ThreadingActor, CoreListener): def mute_changed(self, mute): self.send_idle('output') + + def current_metadata_changed(self): + self.send_idle('playlist') diff --git a/mopidy/mpd/protocol/current_playlist.py b/mopidy/mpd/protocol/current_playlist.py index 33c090e3..e083ea7c 100644 --- a/mopidy/mpd/protocol/current_playlist.py +++ b/mopidy/mpd/protocol/current_playlist.py @@ -275,9 +275,26 @@ def plchanges(context, version): - Calls ``plchanges "-1"`` two times per second to get the entire playlist. """ # XXX Naive implementation that returns all tracks as changed - if int(version) < context.core.tracklist.version.get(): + tracklist_version = context.core.tracklist.version.get() + iversion = int(version) + if iversion < tracklist_version: return translator.tracks_to_mpd_format( context.core.tracklist.tl_tracks.get()) + elif iversion == tracklist_version: + # If version are equals, it is just a metadata update + # So we replace the updated track in playlist + current_md_track = context.core.playback.current_metadata_track.get() + if current_md_track is None: + return None + + ntl_tracks = [] + tl_tracks = context.core.tracklist.tl_tracks.get() + for tl_track in tl_tracks: + if tl_track.tlid == current_md_track.tlid: + ntl_tracks.append(current_md_track) + else: + ntl_tracks.append(tl_track) + return translator.tracks_to_mpd_format(ntl_tracks) @protocol.commands.add('plchangesposid', version=protocol.INT) diff --git a/mopidy/mpd/protocol/status.py b/mopidy/mpd/protocol/status.py index 9dae635e..eabb9317 100644 --- a/mopidy/mpd/protocol/status.py +++ b/mopidy/mpd/protocol/status.py @@ -34,7 +34,9 @@ def currentsong(context): Displays the song info of the current song (same song that is identified in status). """ - tl_track = context.core.playback.current_tl_track.get() + tl_track = context.core.playback.current_metadata_track.get() + if tl_track is None: + 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)