Repository: beetbox/beets

Issue:
Improved the method to get the path of the current song. 
Improves the performance issue described in issue #2752. Before, the complete playlist was fetched from the server. Now, the command "currentsong" is used for this purpose. This improves performance when a huge playlist is active.
mpdstats: using playlist to get current song may be a performance issue
### Problem

MPDStats fails to update stats for all songs on a low performance system when a large playlist is active. In this case, getting the playlist in _on_play_ may take longer than the current song is playing and stats are not updated for the next song because _status['songid']_ is still pointing to the previous song when the playlist is finally received.

The playlist is just used to get the url of the current song. It would be more efficient do this with the _currentsong_ command which is faster and does create less load on the server.


### Setup

* HW: Raspberry Pi B+
* OS: Raspbian Stretch 
* Python version: 2.7.13
* beets version: 1.4.5
* Turning off plugins made problem go away (yes/no): n/a

My configuration (output of `beet config`) is:

```yaml
mpd:
    host: 127.0.0.1
    port: 6600
    rating: yes
    rating_mix: 0.75
    music_directory: /media/Medien/Musik
    password: REDACTED
smartplaylist:
    auto: no
    relative_to: /media/Medien/Musik/
    playlist_dir: /var/lib/mpd/playlists
    playlists: [{name: rating.m3u, query: 'rating:0.4..1.0'}, {name: not_played.m3u, query: '-play_count: artist:'}, {name: dylan.m3u, query: 'artist:Dylan'}]
mpdstats:
    host: 127.0.0.1
    port: 6600
    music_directory: /media/Medien/Musik
    rating: yes
    rating_mix: 0.75
library: ~/beets/musiclibrary.db

plugins: mpdstats smartplaylist lastgenre random
directory: /media/Medien/Musik/

import:
    copy: no
    write: no

```



Discussion:

Good point! If a `currentsong` command will work, let's try switching to that. Would you be willing to try making a PR and testing out the change?

Resolving patch:
diff --git a/beetsplug/mpdstats.py b/beetsplug/mpdstats.py
--- a/beetsplug/mpdstats.py
+++ b/beetsplug/mpdstats.py
@@ -107,17 +107,17 @@ def get(self, command, retries=RETRIES):
         self.connect()
         return self.get(command, retries=retries - 1)
 
-    def playlist(self):
-        """Return the currently active playlist.  Prefixes paths with the
+    def currentsong(self):
+        """Return the path to the currently playing song.  Prefixes paths with the
         music_directory, to get the absolute path.
         """
-        result = {}
-        for entry in self.get('playlistinfo'):
+        result = None
+        entry = self.get('currentsong')
+        if 'file' in entry:
             if not is_url(entry['file']):
-                result[entry['id']] = os.path.join(
-                    self.music_directory, entry['file'])
+                result = os.path.join(self.music_directory, entry['file'])
             else:
-                result[entry['id']] = entry['file']
+                result = entry['file']
         return result
 
     def status(self):
@@ -250,12 +250,16 @@ def on_pause(self, status):
         self.now_playing = None
 
     def on_play(self, status):
-        playlist = self.mpd.playlist()
-        path = playlist.get(status['songid'])
+
+        path = self.mpd.currentsong()
 
         if not path:
             return
 
+        if is_url(path):
+            self._log.info(u'playing stream {0}', displayable_path(path))
+            return
+
         played, duration = map(int, status['time'].split(':', 1))
         remaining = duration - played
 
@@ -272,14 +276,6 @@ def on_play(self, status):
                 if diff <= self.time_threshold:
                     return
 
-                if self.now_playing['path'] == path and played == 0:
-                    self.handle_song_change(self.now_playing)
-
-        if is_url(path):
-            self._log.info(u'playing stream {0}', displayable_path(path))
-            self.now_playing = None
-            return
-
         self._log.info(u'playing {0}', displayable_path(path))
 
         self.now_playing = {


Test patch:
diff --git a/test/test_mpdstats.py b/test/test_mpdstats.py
--- a/test/test_mpdstats.py
+++ b/test/test_mpdstats.py
@@ -65,7 +65,7 @@ def test_get_item(self):
 
     @patch("beetsplug.mpdstats.MPDClientWrapper", return_value=Mock(**{
         "events.side_effect": EVENTS, "status.side_effect": STATUSES,
-        "playlist.return_value": {1: item_path}}))
+        "currentsong.return_value": item_path}))
     def test_run_mpdstats(self, mpd_mock):
         item = Item(title=u'title', path=self.item_path, id=1)
         item.add(self.lib)