mpd: Split browse and playlist name to uri caching

This commit is contained in:
Thomas Adamcik 2015-04-23 23:08:25 +02:00
parent 9bb278f00e
commit d4c695ac75
3 changed files with 48 additions and 7 deletions

View File

@ -27,6 +27,9 @@ Bug fix release.
- HTTP: Fix threading bug that would cause duplicate delivery of WS messages. - HTTP: Fix threading bug that would cause duplicate delivery of WS messages.
- MPD: Fix case where a playlist that is present in both browse and as a listed
playlist breaks the MPD frontend protocol output. (Fixes :issue:`1120`)
v1.0.0 (2015-03-25) v1.0.0 (2015-03-25)
=================== ===================

View File

@ -2,8 +2,12 @@ from __future__ import absolute_import, unicode_literals
import re import re
# TOOD: refactor this into a generic mapper that does not know about browse
# or playlists and then use one instance for each case?
class MpdUriMapper(object): class MpdUriMapper(object):
""" """
Maintains the mappings between uniquified MPD names and URIs. Maintains the mappings between uniquified MPD names and URIs.
""" """
@ -17,7 +21,8 @@ class MpdUriMapper(object):
def __init__(self, core=None): def __init__(self, core=None):
self.core = core self.core = core
self._uri_from_name = {} self._uri_from_name = {}
self._name_from_uri = {} self._browse_name_from_uri = {}
self._playlist_name_from_uri = {}
def _create_unique_name(self, name, uri): def _create_unique_name(self, name, uri):
stripped_name = self._invalid_browse_chars.sub(' ', name) stripped_name = self._invalid_browse_chars.sub(' ', name)
@ -30,13 +35,16 @@ class MpdUriMapper(object):
i += 1 i += 1
return name return name
def insert(self, name, uri): def insert(self, name, uri, playlist=False):
""" """
Create a unique and MPD compatible name that maps to the given URI. Create a unique and MPD compatible name that maps to the given URI.
""" """
name = self._create_unique_name(name, uri) name = self._create_unique_name(name, uri)
self._uri_from_name[name] = uri self._uri_from_name[name] = uri
self._name_from_uri[uri] = name if playlist:
self._playlist_name_from_uri[uri] = name
else:
self._browse_name_from_uri[uri] = name
return name return name
def uri_from_name(self, name): def uri_from_name(self, name):
@ -56,7 +64,7 @@ class MpdUriMapper(object):
if not playlist_ref.name: if not playlist_ref.name:
continue continue
name = self._invalid_playlist_chars.sub('|', playlist_ref.name) name = self._invalid_playlist_chars.sub('|', playlist_ref.name)
self.insert(name, playlist_ref.uri) self.insert(name, playlist_ref.uri, playlist=True)
def playlist_uri_from_name(self, name): def playlist_uri_from_name(self, name):
""" """
@ -70,6 +78,6 @@ class MpdUriMapper(object):
""" """
Helper function to retrieve the unique MPD playlist name from its URI. Helper function to retrieve the unique MPD playlist name from its URI.
""" """
if uri not in self._name_from_uri: if uri not in self._playlist_name_from_uri:
self.refresh_playlists_mapping() self.refresh_playlists_mapping()
return self._name_from_uri[uri] return self._playlist_name_from_uri[uri]

View File

@ -2,7 +2,7 @@ from __future__ import absolute_import, unicode_literals
import random import random
from mopidy.models import Track from mopidy.models import Playlist, Ref, Track
from tests.mpd import protocol from tests.mpd import protocol
@ -175,3 +175,33 @@ class IssueGH137RegressionTest(protocol.BaseTestCase):
u'Album "This Is Remixed Hits - Mashups & Rare 12" Mixes"') u'Album "This Is Remixed Hits - Mashups & Rare 12" Mixes"')
self.assertInResponse('ACK [2@0] {list} Invalid unquoted character') self.assertInResponse('ACK [2@0] {list} Invalid unquoted character')
class IssueGH1120RegressionTest(protocol.BaseTestCase):
"""
The issue: https://github.com/mopidy/mopidy/issues/1120
How to reproduce:
- A playlist must be in both browse results and playlists
- Call for instance ``lsinfo "/"`` to populate the cache with the
playlist name from the playlist backend.
- Call ``lsinfo "/dummy"`` to override the playlist name with the browse
name.
- Call ``lsinfo "/"`` and we now have an invalid name with ``/`` in it.
"""
def test(self):
self.backend.library.dummy_browse_result = {
'dummy:/': [Ref.playlist(name='Top 100 tracks', uri='dummy:/1')],
}
self.backend.playlists.set_dummy_playlists([
Playlist(name='Top 100 tracks', uri='dummy:/1'),
])
response1 = self.send_request('lsinfo "/"')
self.send_request('lsinfo "/dummy"')
response2 = self.send_request('lsinfo "/"')
self.assertEqual(response1, response2)