From 9c2d38e989dea2d0bc669ebd129aacc9e7f263a0 Mon Sep 17 00:00:00 2001 From: Thomas Adamcik Date: Wed, 4 Dec 2013 21:12:28 +0100 Subject: [PATCH] local: Remove tag cache support - Updates doc references to tag cache - Removes tag cache from config and marks it deprecated - Removes tag cache from setup.py - Removes tag cache from config converter - Removes tag cache from tests - Converts local library tests to use JSON. --- docs/devtools.rst | 7 +- docs/ext/local.rst | 4 - mopidy/backends/local/__init__.py | 2 +- mopidy/backends/local/ext.conf | 1 - mopidy/backends/local/tagcache/__init__.py | 28 -- mopidy/backends/local/tagcache/actor.py | 30 -- mopidy/backends/local/tagcache/ext.conf | 2 - mopidy/backends/local/tagcache/library.py | 101 ------ mopidy/backends/local/tagcache/translator.py | 246 ------------- mopidy/config/convert.py | 1 - setup.py | 1 - tests/backends/local/events_test.py | 1 - tests/backends/local/library_test.py | 46 +-- tests/backends/local/playback_test.py | 1 - tests/backends/local/playlists_test.py | 1 - tests/backends/local/tagcache_test.py | 346 ------------------- tests/backends/local/tracklist_test.py | 1 - tests/data/advanced_tag_cache | 107 ------ tests/data/albumartist_tag_cache | 16 - tests/data/blank_tag_cache | 10 - tests/data/empty_tag_cache | 6 - tests/data/library.json.gz | Bin 0 -> 394 bytes tests/data/library_tag_cache | 56 --- tests/data/musicbrainz_tag_cache | 20 -- tests/data/scanner/advanced_cache | 81 ----- tests/data/scanner/empty_cache | 6 - tests/data/scanner/simple_cache | 15 - tests/data/simple_tag_cache | 16 - tests/data/utf8_tag_cache | 18 - 29 files changed, 28 insertions(+), 1142 deletions(-) delete mode 100644 mopidy/backends/local/tagcache/__init__.py delete mode 100644 mopidy/backends/local/tagcache/actor.py delete mode 100644 mopidy/backends/local/tagcache/ext.conf delete mode 100644 mopidy/backends/local/tagcache/library.py delete mode 100644 mopidy/backends/local/tagcache/translator.py delete mode 100644 tests/backends/local/tagcache_test.py delete mode 100644 tests/data/advanced_tag_cache delete mode 100644 tests/data/albumartist_tag_cache delete mode 100644 tests/data/blank_tag_cache delete mode 100644 tests/data/empty_tag_cache create mode 100644 tests/data/library.json.gz delete mode 100644 tests/data/library_tag_cache delete mode 100644 tests/data/musicbrainz_tag_cache delete mode 100644 tests/data/scanner/advanced_cache delete mode 100644 tests/data/scanner/empty_cache delete mode 100644 tests/data/scanner/simple_cache delete mode 100644 tests/data/simple_tag_cache delete mode 100644 tests/data/utf8_tag_cache diff --git a/docs/devtools.rst b/docs/devtools.rst index ecae6c86..858cc7f8 100644 --- a/docs/devtools.rst +++ b/docs/devtools.rst @@ -66,11 +66,8 @@ Sample session:: -OK +ACK [2@0] {listallinfo} incorrect arguments -To ensure that Mopidy and MPD have comparable state it is suggested you setup -both to use ``tests/data/advanced_tag_cache`` for their tag cache and -``tests/data/scanner/advanced/`` for the music folder and ``tests/data`` for -playlists. - +To ensure that Mopidy and MPD have comparable state it is suggested you scan +the same media directory with both servers. Documentation writing ===================== diff --git a/docs/ext/local.rst b/docs/ext/local.rst index 583a7427..51268c51 100644 --- a/docs/ext/local.rst +++ b/docs/ext/local.rst @@ -43,10 +43,6 @@ Configuration values Path to playlists directory with m3u files for local media. -.. confval:: local/tag_cache_file - - Path to tag cache for local media. - .. confval:: local/scan_timeout Number of milliseconds before giving up scanning a file and moving on to diff --git a/mopidy/backends/local/__init__.py b/mopidy/backends/local/__init__.py index 723eb056..d24ab010 100644 --- a/mopidy/backends/local/__init__.py +++ b/mopidy/backends/local/__init__.py @@ -20,7 +20,7 @@ class Extension(ext.Extension): schema = super(Extension, self).get_config_schema() schema['media_dir'] = config.Path() schema['playlists_dir'] = config.Path() - schema['tag_cache_file'] = config.Path() + schema['tag_cache_file'] = config.Deprecated() schema['scan_timeout'] = config.Integer( minimum=1000, maximum=1000*60*60) schema['excluded_file_extensions'] = config.List(optional=True) diff --git a/mopidy/backends/local/ext.conf b/mopidy/backends/local/ext.conf index afc13c7d..f906a04f 100644 --- a/mopidy/backends/local/ext.conf +++ b/mopidy/backends/local/ext.conf @@ -2,7 +2,6 @@ enabled = true media_dir = $XDG_MUSIC_DIR playlists_dir = $XDG_DATA_DIR/mopidy/local/playlists -tag_cache_file = $XDG_DATA_DIR/mopidy/local/tag_cache scan_timeout = 1000 excluded_file_extensions = .html diff --git a/mopidy/backends/local/tagcache/__init__.py b/mopidy/backends/local/tagcache/__init__.py deleted file mode 100644 index b51b88bf..00000000 --- a/mopidy/backends/local/tagcache/__init__.py +++ /dev/null @@ -1,28 +0,0 @@ -from __future__ import unicode_literals - -import os - -import mopidy -from mopidy import config, ext - - -class Extension(ext.Extension): - - dist_name = 'Mopidy-Local-Tagcache' - ext_name = 'local-tagcache' - version = mopidy.__version__ - - def get_default_config(self): - conf_file = os.path.join(os.path.dirname(__file__), 'ext.conf') - return config.read(conf_file) - - # Config only contains local-tagcache/enabled since we are not setting our - # own schema. - - def get_backend_classes(self): - from .actor import LocalTagcacheBackend - return [LocalTagcacheBackend] - - def get_library_updaters(self): - from .library import LocalTagcacheLibraryUpdateProvider - return [LocalTagcacheLibraryUpdateProvider] diff --git a/mopidy/backends/local/tagcache/actor.py b/mopidy/backends/local/tagcache/actor.py deleted file mode 100644 index f052debb..00000000 --- a/mopidy/backends/local/tagcache/actor.py +++ /dev/null @@ -1,30 +0,0 @@ -from __future__ import unicode_literals - -import logging - -import pykka - -from mopidy.backends import base -from mopidy.utils import encoding, path - -from .library import LocalTagcacheLibraryProvider - -logger = logging.getLogger('mopidy.backends.local.tagcache') - - -class LocalTagcacheBackend(pykka.ThreadingActor, base.Backend): - def __init__(self, config, audio): - super(LocalTagcacheBackend, self).__init__() - - self.config = config - self.check_dirs_and_files() - self.library = LocalTagcacheLibraryProvider(backend=self) - self.uri_schemes = ['local'] - - def check_dirs_and_files(self): - try: - path.get_or_create_file(self.config['local']['tag_cache_file']) - except EnvironmentError as error: - logger.warning( - 'Could not create empty tag cache file: %s', - encoding.locale_decode(error)) diff --git a/mopidy/backends/local/tagcache/ext.conf b/mopidy/backends/local/tagcache/ext.conf deleted file mode 100644 index 749959e8..00000000 --- a/mopidy/backends/local/tagcache/ext.conf +++ /dev/null @@ -1,2 +0,0 @@ -[local-tagcache] -enabled = false diff --git a/mopidy/backends/local/tagcache/library.py b/mopidy/backends/local/tagcache/library.py deleted file mode 100644 index 5b541d19..00000000 --- a/mopidy/backends/local/tagcache/library.py +++ /dev/null @@ -1,101 +0,0 @@ -from __future__ import unicode_literals - -import logging -import os -import tempfile - -from mopidy.backends import base -from mopidy.backends.local import search -from mopidy.backends.local.translator import local_to_file_uri - -from .translator import parse_mpd_tag_cache, tracks_to_tag_cache_format - -logger = logging.getLogger('mopidy.backends.local.tagcache') - - -class LocalTagcacheLibraryProvider(base.BaseLibraryProvider): - def __init__(self, *args, **kwargs): - super(LocalTagcacheLibraryProvider, self).__init__(*args, **kwargs) - self._uri_mapping = {} - self._media_dir = self.backend.config['local']['media_dir'] - self._tag_cache_file = self.backend.config['local']['tag_cache_file'] - self.refresh() - - def refresh(self, uri=None): - logger.debug( - 'Loading local tracks from %s using %s', - self._media_dir, self._tag_cache_file) - - tracks = parse_mpd_tag_cache(self._tag_cache_file, self._media_dir) - uris_to_remove = set(self._uri_mapping) - - for track in tracks: - self._uri_mapping[track.uri] = track - uris_to_remove.discard(track.uri) - - for uri in uris_to_remove: - del self._uri_mapping[uri] - - logger.info( - 'Loaded %d local tracks from %s using %s', - len(tracks), self._media_dir, self._tag_cache_file) - - def lookup(self, uri): - try: - return [self._uri_mapping[uri]] - except KeyError: - logger.debug('Failed to lookup %r', uri) - return [] - - def find_exact(self, query=None, uris=None): - tracks = self._uri_mapping.values() - return search.find_exact(tracks, query=query, uris=uris) - - def search(self, query=None, uris=None): - tracks = self._uri_mapping.values() - return search.search(tracks, query=query, uris=uris) - - -class LocalTagcacheLibraryUpdateProvider(base.BaseLibraryProvider): - uri_schemes = ['local'] - - def __init__(self, config): - self._tracks = {} - self._media_dir = config['local']['media_dir'] - self._tag_cache_file = config['local']['tag_cache_file'] - - def load(self): - tracks = parse_mpd_tag_cache(self._tag_cache_file, self._media_dir) - for track in tracks: - # TODO: this should use uris as is, i.e. hack that should go away - # with tag caches. - uri = local_to_file_uri(track.uri, self._media_dir) - self._tracks[uri] = track.copy(uri=uri) - return tracks - - def add(self, track): - self._tracks[track.uri] = track - - def remove(self, uri): - if uri in self._tracks: - del self._tracks[uri] - - def commit(self): - directory, basename = os.path.split(self._tag_cache_file) - - # TODO: cleanup directory/basename.* files. - tmp = tempfile.NamedTemporaryFile( - prefix=basename + '.', dir=directory, delete=False) - - try: - for row in tracks_to_tag_cache_format( - self._tracks.values(), self._media_dir): - if len(row) == 1: - tmp.write(('%s\n' % row).encode('utf-8')) - else: - tmp.write(('%s: %s\n' % row).encode('utf-8')) - - os.rename(tmp.name, self._tag_cache_file) - finally: - if os.path.exists(tmp.name): - os.remove(tmp.name) diff --git a/mopidy/backends/local/tagcache/translator.py b/mopidy/backends/local/tagcache/translator.py deleted file mode 100644 index be54cd1d..00000000 --- a/mopidy/backends/local/tagcache/translator.py +++ /dev/null @@ -1,246 +0,0 @@ -from __future__ import unicode_literals - -import logging -import os -import re -import urllib - -from mopidy.frontends.mpd import translator as mpd, protocol -from mopidy.models import Track, Artist, Album -from mopidy.utils.encoding import locale_decode -from mopidy.utils.path import mtime as get_mtime, split_path, uri_to_path - -logger = logging.getLogger('mopidy.backends.local.tagcache') - - -# TODO: remove music_dir from API -def parse_mpd_tag_cache(tag_cache, music_dir=''): - """ - Converts a MPD tag_cache into a lists of tracks, artists and albums. - """ - tracks = set() - - try: - with open(tag_cache) as library: - contents = library.read() - except IOError as error: - logger.warning('Could not open tag cache: %s', locale_decode(error)) - return tracks - - current = {} - state = None - - # TODO: uris as bytes - for line in contents.split(b'\n'): - if line == b'songList begin': - state = 'songs' - continue - elif line == b'songList end': - state = None - continue - elif not state: - continue - - key, value = line.split(b': ', 1) - - if key == b'key': - _convert_mpd_data(current, tracks) - current.clear() - - current[key.lower()] = value.decode('utf-8') - - _convert_mpd_data(current, tracks) - - return tracks - - -def _convert_mpd_data(data, tracks): - if not data: - return - - track_kwargs = {} - album_kwargs = {} - artist_kwargs = {} - albumartist_kwargs = {} - - if 'track' in data: - if '/' in data['track']: - album_kwargs['num_tracks'] = int(data['track'].split('/')[1]) - track_kwargs['track_no'] = int(data['track'].split('/')[0]) - else: - track_kwargs['track_no'] = int(data['track']) - - if 'mtime' in data: - track_kwargs['last_modified'] = int(data['mtime']) - - if 'artist' in data: - artist_kwargs['name'] = data['artist'] - - if 'albumartist' in data: - albumartist_kwargs['name'] = data['albumartist'] - - if 'composer' in data: - track_kwargs['composers'] = [Artist(name=data['composer'])] - - if 'performer' in data: - track_kwargs['performers'] = [Artist(name=data['performer'])] - - if 'album' in data: - album_kwargs['name'] = data['album'] - - if 'title' in data: - track_kwargs['name'] = data['title'] - - if 'genre' in data: - track_kwargs['genre'] = data['genre'] - - if 'date' in data: - track_kwargs['date'] = data['date'] - - if 'comment' in data: - track_kwargs['comment'] = data['comment'] - - if 'musicbrainz_trackid' in data: - track_kwargs['musicbrainz_id'] = data['musicbrainz_trackid'] - - if 'musicbrainz_albumid' in data: - album_kwargs['musicbrainz_id'] = data['musicbrainz_albumid'] - - if 'musicbrainz_artistid' in data: - artist_kwargs['musicbrainz_id'] = data['musicbrainz_artistid'] - - if 'musicbrainz_albumartistid' in data: - albumartist_kwargs['musicbrainz_id'] = ( - data['musicbrainz_albumartistid']) - - if artist_kwargs: - artist = Artist(**artist_kwargs) - track_kwargs['artists'] = [artist] - - if albumartist_kwargs: - albumartist = Artist(**albumartist_kwargs) - album_kwargs['artists'] = [albumartist] - - if album_kwargs: - album = Album(**album_kwargs) - track_kwargs['album'] = album - - if data['file'][0] == '/': - path = data['file'][1:] - else: - path = data['file'] - - track_kwargs['uri'] = 'local:track:%s' % path - track_kwargs['length'] = int(data.get('time', 0)) * 1000 - - track = Track(**track_kwargs) - tracks.add(track) - - -def tracks_to_tag_cache_format(tracks, media_dir): - """ - Format list of tracks for output to MPD tag cache - - :param tracks: the tracks - :type tracks: list of :class:`mopidy.models.Track` - :param media_dir: the path to the music dir - :type media_dir: string - :rtype: list of lists of two-tuples - """ - result = [ - ('info_begin',), - ('mpd_version', protocol.VERSION), - ('fs_charset', protocol.ENCODING), - ('info_end',) - ] - tracks.sort(key=lambda t: t.uri) - dirs, files = tracks_to_directory_tree(tracks, media_dir) - _add_to_tag_cache(result, dirs, files, media_dir) - return result - - -# TODO: bytes only -def _add_to_tag_cache(result, dirs, files, media_dir): - base_path = media_dir.encode('utf-8') - - for path, (entry_dirs, entry_files) in dirs.items(): - try: - text_path = path.decode('utf-8') - except UnicodeDecodeError: - text_path = urllib.quote(path).decode('utf-8') - name = os.path.split(text_path)[1] - result.append(('directory', text_path)) - result.append(('mtime', get_mtime(os.path.join(base_path, path)))) - result.append(('begin', name)) - _add_to_tag_cache(result, entry_dirs, entry_files, media_dir) - result.append(('end', name)) - - result.append(('songList begin',)) - - for track in files: - track_result = dict(mpd.track_to_mpd_format(track)) - - # XXX Don't save comments to the tag cache as they may span multiple - # lines. We'll start saving track comments when we move from tag_cache - # to a JSON file. See #579 for details. - if 'Comment' in track_result: - del track_result['Comment'] - - path = uri_to_path(track_result['file']) - try: - text_path = path.decode('utf-8') - except UnicodeDecodeError: - text_path = urllib.quote(path).decode('utf-8') - relative_path = os.path.relpath(path, base_path) - relative_uri = urllib.quote(relative_path) - - # TODO: use track.last_modified - track_result['file'] = relative_uri - track_result['mtime'] = get_mtime(path) - track_result['key'] = os.path.basename(text_path) - track_result = order_mpd_track_info(track_result.items()) - - result.extend(track_result) - - result.append(('songList end',)) - - -def tracks_to_directory_tree(tracks, media_dir): - directories = ({}, []) - - for track in tracks: - path = b'' - current = directories - - absolute_track_dir_path = os.path.dirname(uri_to_path(track.uri)) - relative_track_dir_path = re.sub( - '^' + re.escape(media_dir), b'', absolute_track_dir_path) - - for part in split_path(relative_track_dir_path): - path = os.path.join(path, part) - if path not in current[0]: - current[0][path] = ({}, []) - current = current[0][path] - current[1].append(track) - return directories - - -MPD_KEY_ORDER = ''' - key file Time Artist Album AlbumArtist Title Track Genre Date Composer - Performer Comment Disc MUSICBRAINZ_ALBUMID MUSICBRAINZ_ALBUMARTISTID - MUSICBRAINZ_ARTISTID MUSICBRAINZ_TRACKID mtime -'''.split() - - -def order_mpd_track_info(result): - """ - Order results from - :func:`mopidy.frontends.mpd.translator.track_to_mpd_format` so that it - matches MPD's ordering. Simply a cosmetic fix for easier diffing of - tag_caches. - - :param result: the track info - :type result: list of tuples - :rtype: list of tuples - """ - return sorted(result, key=lambda i: MPD_KEY_ORDER.index(i[0])) diff --git a/mopidy/config/convert.py b/mopidy/config/convert.py index 3c3edb85..87bf4ed5 100644 --- a/mopidy/config/convert.py +++ b/mopidy/config/convert.py @@ -45,7 +45,6 @@ def convert(settings): helper('local/media_dir', 'LOCAL_MUSIC_PATH') helper('local/playlists_dir', 'LOCAL_PLAYLIST_PATH') - helper('local/tag_cache_file', 'LOCAL_TAG_CACHE_FILE') helper('spotify/username', 'SPOTIFY_USERNAME') helper('spotify/password', 'SPOTIFY_PASSWORD') diff --git a/setup.py b/setup.py index 11855553..bc2fe222 100644 --- a/setup.py +++ b/setup.py @@ -43,7 +43,6 @@ setup( 'mopidy.ext': [ 'http = mopidy.frontends.http:Extension [http]', 'local = mopidy.backends.local:Extension', - 'local-tagcache = mopidy.backends.local.tagcache:Extension', 'local-json = mopidy.backends.local.json:Extension', 'mpd = mopidy.frontends.mpd:Extension', 'stream = mopidy.backends.stream:Extension', diff --git a/tests/backends/local/events_test.py b/tests/backends/local/events_test.py index 725c580f..1e26a68c 100644 --- a/tests/backends/local/events_test.py +++ b/tests/backends/local/events_test.py @@ -18,7 +18,6 @@ class LocalBackendEventsTest(unittest.TestCase): 'local': { 'media_dir': path_to_data_dir(''), 'playlists_dir': b'', - 'tag_cache_file': path_to_data_dir('empty_tag_cache'), } } diff --git a/tests/backends/local/library_test.py b/tests/backends/local/library_test.py index c04b81f5..e4c00570 100644 --- a/tests/backends/local/library_test.py +++ b/tests/backends/local/library_test.py @@ -1,12 +1,13 @@ from __future__ import unicode_literals +import copy import tempfile import unittest import pykka from mopidy import core -from mopidy.backends.local.tagcache import actor +from mopidy.backends.local.json import actor from mopidy.models import Track, Album, Artist from tests import path_to_data_dir @@ -61,12 +62,14 @@ class LocalLibraryProviderTest(unittest.TestCase): 'local': { 'media_dir': path_to_data_dir(''), 'playlists_dir': b'', - 'tag_cache_file': path_to_data_dir('library_tag_cache'), - } + }, + 'local-json': { + 'json_file': path_to_data_dir('library.json.gz'), + }, } def setUp(self): - self.backend = actor.LocalTagcacheBackend.start( + self.backend = actor.LocalJsonBackend.start( config=self.config, audio=None).proxy() self.core = core.Core(backends=[self.backend]) self.library = self.core.library @@ -85,27 +88,27 @@ class LocalLibraryProviderTest(unittest.TestCase): # Verifies that https://github.com/mopidy/mopidy/issues/500 # has been fixed. - tag_cache = tempfile.NamedTemporaryFile() - with open(self.config['local']['tag_cache_file']) as fh: - tag_cache.write(fh.read()) - tag_cache.flush() + with tempfile.NamedTemporaryFile() as library: + with open(self.config['local-json']['json_file']) as fh: + library.write(fh.read()) + library.flush() - config = {'local': self.config['local'].copy()} - config['local']['tag_cache_file'] = tag_cache.name - backend = actor.LocalTagcacheBackend(config=config, audio=None) + config = copy.deepcopy(self.config) + config['local-json']['json_file'] = library.name + backend = actor.LocalJsonBackend(config=config, audio=None) - # Sanity check that value is in tag cache - result = backend.library.lookup(self.tracks[0].uri) - self.assertEqual(result, self.tracks[0:1]) + # Sanity check that value is in the library + result = backend.library.lookup(self.tracks[0].uri) + self.assertEqual(result, self.tracks[0:1]) - # Clear tag cache and refresh - tag_cache.seek(0) - tag_cache.truncate() - backend.library.refresh() + # Clear library and refresh + library.seek(0) + library.truncate() + backend.library.refresh() - # Now it should be gone. - result = backend.library.lookup(self.tracks[0].uri) - self.assertEqual(result, []) + # Now it should be gone. + result = backend.library.lookup(self.tracks[0].uri) + self.assertEqual(result, []) def test_lookup(self): tracks = self.library.lookup(self.tracks[0].uri) @@ -115,6 +118,7 @@ class LocalLibraryProviderTest(unittest.TestCase): tracks = self.library.lookup('fake uri') self.assertEqual(tracks, []) + # TODO: move to search_test module def test_find_exact_no_hits(self): result = self.library.find_exact(track_name=['unknown track']) self.assertEqual(list(result[0].tracks), []) diff --git a/tests/backends/local/playback_test.py b/tests/backends/local/playback_test.py index 8fbc4415..4c3dd70d 100644 --- a/tests/backends/local/playback_test.py +++ b/tests/backends/local/playback_test.py @@ -23,7 +23,6 @@ class LocalPlaybackProviderTest(unittest.TestCase): 'local': { 'media_dir': path_to_data_dir(''), 'playlists_dir': b'', - 'tag_cache_file': path_to_data_dir('empty_tag_cache'), } } diff --git a/tests/backends/local/playlists_test.py b/tests/backends/local/playlists_test.py index c8fedd62..c02e1d23 100644 --- a/tests/backends/local/playlists_test.py +++ b/tests/backends/local/playlists_test.py @@ -20,7 +20,6 @@ class LocalPlaylistsProviderTest(unittest.TestCase): config = { 'local': { 'media_dir': path_to_data_dir(''), - 'tag_cache_file': path_to_data_dir('library_tag_cache'), } } diff --git a/tests/backends/local/tagcache_test.py b/tests/backends/local/tagcache_test.py deleted file mode 100644 index b40b3346..00000000 --- a/tests/backends/local/tagcache_test.py +++ /dev/null @@ -1,346 +0,0 @@ -# encoding: utf-8 - -from __future__ import unicode_literals - -import os -import unittest - -from mopidy.backends.local.tagcache import translator -from mopidy.frontends.mpd import translator as mpd, protocol -from mopidy.models import Album, Artist, Track -from mopidy.utils.path import mtime, uri_to_path - -from tests import path_to_data_dir - - -class TracksToTagCacheFormatTest(unittest.TestCase): - def setUp(self): - self.media_dir = '/dir/subdir' - mtime.set_fake_time(1234567) - - def tearDown(self): - mtime.undo_fake() - - def translate(self, track): - base_path = self.media_dir.encode('utf-8') - result = dict(mpd.track_to_mpd_format(track)) - result['file'] = uri_to_path(result['file'])[len(base_path) + 1:] - result['key'] = os.path.basename(result['file']) - result['mtime'] = mtime('') - return translator.order_mpd_track_info(result.items()) - - def consume_headers(self, result): - self.assertEqual(('info_begin',), result[0]) - self.assertEqual(('mpd_version', protocol.VERSION), result[1]) - self.assertEqual(('fs_charset', protocol.ENCODING), result[2]) - self.assertEqual(('info_end',), result[3]) - return result[4:] - - def consume_song_list(self, result): - self.assertEqual(('songList begin',), result[0]) - for i, row in enumerate(result): - if row == ('songList end',): - return result[1:i], result[i + 1:] - self.fail("Couldn't find songList end in result") - - def consume_directory(self, result): - self.assertEqual('directory', result[0][0]) - self.assertEqual(('mtime', mtime('.')), result[1]) - self.assertEqual(('begin', os.path.split(result[0][1])[1]), result[2]) - directory = result[2][1] - for i, row in enumerate(result): - if row == ('end', directory): - return result[3:i], result[i + 1:] - self.fail("Couldn't find end %s in result" % directory) - - def test_empty_tag_cache_has_header(self): - result = translator.tracks_to_tag_cache_format([], self.media_dir) - result = self.consume_headers(result) - - def test_empty_tag_cache_has_song_list(self): - result = translator.tracks_to_tag_cache_format([], self.media_dir) - result = self.consume_headers(result) - song_list, result = self.consume_song_list(result) - - self.assertEqual(len(song_list), 0) - self.assertEqual(len(result), 0) - - def test_tag_cache_has_header(self): - track = Track(uri='file:///dir/subdir/song.mp3') - result = translator.tracks_to_tag_cache_format([track], self.media_dir) - result = self.consume_headers(result) - - def test_tag_cache_has_song_list(self): - track = Track(uri='file:///dir/subdir/song.mp3') - result = translator.tracks_to_tag_cache_format([track], self.media_dir) - result = self.consume_headers(result) - song_list, result = self.consume_song_list(result) - - self.assert_(song_list) - self.assertEqual(len(result), 0) - - def test_tag_cache_has_formated_track(self): - track = Track(uri='file:///dir/subdir/song.mp3') - formated = self.translate(track) - result = translator.tracks_to_tag_cache_format([track], self.media_dir) - - result = self.consume_headers(result) - song_list, result = self.consume_song_list(result) - - self.assertEqual(formated, song_list) - self.assertEqual(len(result), 0) - - def test_tag_cache_has_formated_track_with_key_and_mtime(self): - track = Track(uri='file:///dir/subdir/song.mp3') - formated = self.translate(track) - result = translator.tracks_to_tag_cache_format([track], self.media_dir) - - result = self.consume_headers(result) - song_list, result = self.consume_song_list(result) - - self.assertEqual(formated, song_list) - self.assertEqual(len(result), 0) - - def test_tag_cache_supports_directories(self): - track = Track(uri='file:///dir/subdir/folder/song.mp3') - formated = self.translate(track) - result = translator.tracks_to_tag_cache_format([track], self.media_dir) - - result = self.consume_headers(result) - dir_data, result = self.consume_directory(result) - song_list, result = self.consume_song_list(result) - self.assertEqual(len(song_list), 0) - self.assertEqual(len(result), 0) - - song_list, result = self.consume_song_list(dir_data) - self.assertEqual(len(result), 0) - self.assertEqual(formated, song_list) - - def test_tag_cache_diretory_header_is_right(self): - track = Track(uri='file:///dir/subdir/folder/sub/song.mp3') - result = translator.tracks_to_tag_cache_format([track], self.media_dir) - - result = self.consume_headers(result) - dir_data, result = self.consume_directory(result) - - self.assertEqual(('directory', 'folder/sub'), dir_data[0]) - self.assertEqual(('mtime', mtime('.')), dir_data[1]) - self.assertEqual(('begin', 'sub'), dir_data[2]) - - def test_tag_cache_suports_sub_directories(self): - track = Track(uri='file:///dir/subdir/folder/sub/song.mp3') - formated = self.translate(track) - result = translator.tracks_to_tag_cache_format([track], self.media_dir) - - result = self.consume_headers(result) - - dir_data, result = self.consume_directory(result) - song_list, result = self.consume_song_list(result) - self.assertEqual(len(song_list), 0) - self.assertEqual(len(result), 0) - - dir_data, result = self.consume_directory(dir_data) - song_list, result = self.consume_song_list(result) - self.assertEqual(len(result), 0) - self.assertEqual(len(song_list), 0) - - song_list, result = self.consume_song_list(dir_data) - self.assertEqual(len(result), 0) - self.assertEqual(formated, song_list) - - def test_tag_cache_supports_multiple_tracks(self): - tracks = [ - Track(uri='file:///dir/subdir/song1.mp3'), - Track(uri='file:///dir/subdir/song2.mp3'), - ] - - formated = [] - formated.extend(self.translate(tracks[0])) - formated.extend(self.translate(tracks[1])) - - result = translator.tracks_to_tag_cache_format(tracks, self.media_dir) - - result = self.consume_headers(result) - song_list, result = self.consume_song_list(result) - - self.assertEqual(formated, song_list) - self.assertEqual(len(result), 0) - - def test_tag_cache_supports_multiple_tracks_in_dirs(self): - tracks = [ - Track(uri='file:///dir/subdir/song1.mp3'), - Track(uri='file:///dir/subdir/folder/song2.mp3'), - ] - - formated = [] - formated.append(self.translate(tracks[0])) - formated.append(self.translate(tracks[1])) - - result = translator.tracks_to_tag_cache_format(tracks, self.media_dir) - - result = self.consume_headers(result) - dir_data, result = self.consume_directory(result) - song_list, song_result = self.consume_song_list(dir_data) - - self.assertEqual(formated[1], song_list) - self.assertEqual(len(song_result), 0) - - song_list, result = self.consume_song_list(result) - self.assertEqual(len(result), 0) - self.assertEqual(formated[0], song_list) - - -class TracksToDirectoryTreeTest(unittest.TestCase): - def setUp(self): - self.media_dir = '/root' - - def test_no_tracks_gives_emtpy_tree(self): - tree = translator.tracks_to_directory_tree([], self.media_dir) - self.assertEqual(tree, ({}, [])) - - def test_top_level_files(self): - tracks = [ - Track(uri='file:///root/file1.mp3'), - Track(uri='file:///root/file2.mp3'), - Track(uri='file:///root/file3.mp3'), - ] - tree = translator.tracks_to_directory_tree(tracks, self.media_dir) - self.assertEqual(tree, ({}, tracks)) - - def test_single_file_in_subdir(self): - tracks = [Track(uri='file:///root/dir/file1.mp3')] - tree = translator.tracks_to_directory_tree(tracks, self.media_dir) - expected = ({'dir': ({}, tracks)}, []) - self.assertEqual(tree, expected) - - def test_single_file_in_sub_subdir(self): - tracks = [Track(uri='file:///root/dir1/dir2/file1.mp3')] - tree = translator.tracks_to_directory_tree(tracks, self.media_dir) - expected = ({'dir1': ({'dir1/dir2': ({}, tracks)}, [])}, []) - self.assertEqual(tree, expected) - - def test_complex_file_structure(self): - tracks = [ - Track(uri='file:///root/file1.mp3'), - Track(uri='file:///root/dir1/file2.mp3'), - Track(uri='file:///root/dir1/file3.mp3'), - Track(uri='file:///root/dir2/file4.mp3'), - Track(uri='file:///root/dir2/sub/file5.mp3'), - ] - tree = translator.tracks_to_directory_tree(tracks, self.media_dir) - expected = ( - { - 'dir1': ({}, [tracks[1], tracks[2]]), - 'dir2': ( - { - 'dir2/sub': ({}, [tracks[4]]) - }, - [tracks[3]] - ), - }, - [tracks[0]] - ) - self.assertEqual(tree, expected) - - -expected_artists = [Artist(name='name')] -expected_albums = [ - Album(name='albumname', artists=expected_artists, num_tracks=2), - Album(name='albumname', num_tracks=2), -] -expected_tracks = [] - - -def generate_track(path, ident, album_id): - uri = 'local:track:%s' % path - track = Track( - uri=uri, name='trackname', artists=expected_artists, - album=expected_albums[album_id], track_no=1, date='2006', length=4000, - last_modified=1272319626) - expected_tracks.append(track) - - -generate_track('song1.mp3', 6, 0) -generate_track('song2.mp3', 7, 0) -generate_track('song3.mp3', 8, 1) -generate_track('subdir1/song4.mp3', 2, 0) -generate_track('subdir1/song5.mp3', 3, 0) -generate_track('subdir2/song6.mp3', 4, 1) -generate_track('subdir2/song7.mp3', 5, 1) -generate_track('subdir1/subsubdir/song8.mp3', 0, 0) -generate_track('subdir1/subsubdir/song9.mp3', 1, 1) - - -class MPDTagCacheToTracksTest(unittest.TestCase): - def test_emtpy_cache(self): - tracks = translator.parse_mpd_tag_cache( - path_to_data_dir('empty_tag_cache'), path_to_data_dir('')) - self.assertEqual(set(), tracks) - - def test_simple_cache(self): - tracks = translator.parse_mpd_tag_cache( - path_to_data_dir('simple_tag_cache'), path_to_data_dir('')) - track = Track( - uri='local:track:song1.mp3', name='trackname', - artists=expected_artists, track_no=1, album=expected_albums[0], - date='2006', length=4000, last_modified=1272319626) - self.assertEqual(set([track]), tracks) - - def test_advanced_cache(self): - tracks = translator.parse_mpd_tag_cache( - path_to_data_dir('advanced_tag_cache'), path_to_data_dir('')) - self.assertEqual(set(expected_tracks), tracks) - - def test_unicode_cache(self): - tracks = translator.parse_mpd_tag_cache( - path_to_data_dir('utf8_tag_cache'), path_to_data_dir('')) - - artists = [Artist(name='æøå')] - album = Album(name='æøå', artists=artists) - track = Track( - uri='local:track:song1.mp3', name='æøå', artists=artists, - composers=artists, performers=artists, genre='æøå', - album=album, length=4000, last_modified=1272319626, - comment='æøå&^`ൂ㔶') - - self.assertEqual(track, list(tracks)[0]) - - @unittest.SkipTest - def test_misencoded_cache(self): - # FIXME not sure if this can happen - pass - - def test_cache_with_blank_track_info(self): - tracks = translator.parse_mpd_tag_cache( - path_to_data_dir('blank_tag_cache'), path_to_data_dir('')) - expected = Track( - uri='local:track:song1.mp3', length=4000, last_modified=1272319626) - self.assertEqual(set([expected]), tracks) - - def test_musicbrainz_tagcache(self): - tracks = translator.parse_mpd_tag_cache( - path_to_data_dir('musicbrainz_tag_cache'), path_to_data_dir('')) - artist = list(expected_tracks[0].artists)[0].copy( - musicbrainz_id='7364dea6-ca9a-48e3-be01-b44ad0d19897') - albumartist = list(expected_tracks[0].artists)[0].copy( - name='albumartistname', - musicbrainz_id='7364dea6-ca9a-48e3-be01-b44ad0d19897') - album = expected_tracks[0].album.copy( - artists=[albumartist], - musicbrainz_id='cb5f1603-d314-4c9c-91e5-e295cfb125d2') - track = expected_tracks[0].copy( - artists=[artist], album=album, - musicbrainz_id='90488461-8c1f-4a4e-826b-4c6dc70801f0') - - self.assertEqual(track, list(tracks)[0]) - - def test_albumartist_tag_cache(self): - tracks = translator.parse_mpd_tag_cache( - path_to_data_dir('albumartist_tag_cache'), path_to_data_dir('')) - artist = Artist(name='albumartistname') - album = expected_albums[0].copy(artists=[artist]) - track = Track( - uri='local:track:song1.mp3', name='trackname', - artists=expected_artists, track_no=1, album=album, date='2006', - length=4000, last_modified=1272319626) - self.assertEqual(track, list(tracks)[0]) diff --git a/tests/backends/local/tracklist_test.py b/tests/backends/local/tracklist_test.py index ac135a25..c7cfe51f 100644 --- a/tests/backends/local/tracklist_test.py +++ b/tests/backends/local/tracklist_test.py @@ -19,7 +19,6 @@ class LocalTracklistProviderTest(unittest.TestCase): 'local': { 'media_dir': path_to_data_dir(''), 'playlists_dir': b'', - 'tag_cache_file': path_to_data_dir('empty_tag_cache'), } } tracks = [ diff --git a/tests/data/advanced_tag_cache b/tests/data/advanced_tag_cache deleted file mode 100644 index be299fb6..00000000 --- a/tests/data/advanced_tag_cache +++ /dev/null @@ -1,107 +0,0 @@ -info_begin -mpd_version: 0.14.2 -fs_charset: UTF-8 -info_end -directory: subdir1 -begin: subdir1 -directory: subsubdir -begin: subdir1/subsubdir -songList begin -key: song8.mp3 -file: subdir1/subsubdir/song8.mp3 -Time: 4 -Artist: name -AlbumArtist: name -Title: trackname -Album: albumname -Track: 1/2 -Date: 2006 -mtime: 1272319626 -key: song9.mp3 -file: subdir1/subsubdir/song9.mp3 -Time: 4 -Artist: name -Title: trackname -Album: albumname -Track: 1/2 -Date: 2006 -mtime: 1272319626 -songList end -end: subdir1/subsubdir -songList begin -key: song4.mp3 -file: subdir1/song4.mp3 -Time: 4 -Artist: name -AlbumArtist: name -Title: trackname -Album: albumname -Track: 1/2 -Date: 2006 -mtime: 1272319626 -key: song5.mp3 -file: subdir1/song5.mp3 -Time: 4 -Artist: name -AlbumArtist: name -Title: trackname -Album: albumname -Track: 1/2 -Date: 2006 -mtime: 1272319626 -songList end -end: subdir1 -directory: subdir2 -begin: subdir2 -songList begin -key: song6.mp3 -file: subdir2/song6.mp3 -Time: 4 -Artist: name -Title: trackname -Album: albumname -Track: 1/2 -Date: 2006 -mtime: 1272319626 -key: song7.mp3 -file: subdir2/song7.mp3 -Time: 4 -Artist: name -Title: trackname -Album: albumname -Track: 1/2 -Date: 2006 -mtime: 1272319626 -songList end -end: subdir2 -songList begin -key: song1.mp3 -file: /song1.mp3 -Time: 4 -Artist: name -AlbumArtist: name -Title: trackname -Album: albumname -Track: 1/2 -Date: 2006 -mtime: 1272319626 -key: song2.mp3 -file: /song2.mp3 -Time: 4 -Artist: name -AlbumArtist: name -Title: trackname -Album: albumname -Track: 1/2 -Date: 2006 -mtime: 1272319626 -key: song3.mp3 -file: /song3.mp3 -Time: 4 -Artist: name -Title: trackname -Album: albumname -Track: 1/2 -Date: 2006 -mtime: 1272319626 -songList end diff --git a/tests/data/albumartist_tag_cache b/tests/data/albumartist_tag_cache deleted file mode 100644 index 29942a75..00000000 --- a/tests/data/albumartist_tag_cache +++ /dev/null @@ -1,16 +0,0 @@ -info_begin -mpd_version: 0.14.2 -fs_charset: UTF-8 -info_end -songList begin -key: song1.mp3 -file: /song1.mp3 -Time: 4 -Artist: name -Title: trackname -Album: albumname -AlbumArtist: albumartistname -Track: 1/2 -Date: 2006 -mtime: 1272319626 -songList end diff --git a/tests/data/blank_tag_cache b/tests/data/blank_tag_cache deleted file mode 100644 index a6d33386..00000000 --- a/tests/data/blank_tag_cache +++ /dev/null @@ -1,10 +0,0 @@ -info_begin -mpd_version: 0.14.2 -fs_charset: UTF-8 -info_end -songList begin -key: song1.mp3 -file: /song1.mp3 -Time: 4 -mtime: 1272319626 -songList end diff --git a/tests/data/empty_tag_cache b/tests/data/empty_tag_cache deleted file mode 100644 index 84053d90..00000000 --- a/tests/data/empty_tag_cache +++ /dev/null @@ -1,6 +0,0 @@ -info_begin -mpd_version: 0.14.2 -fs_charset: UTF-8 -info_end -songList begin -songList end diff --git a/tests/data/library.json.gz b/tests/data/library.json.gz new file mode 100644 index 0000000000000000000000000000000000000000..07cd48d128bb4cffcdf379a74ce7bf66469830d7 GIT binary patch literal 394 zcmV;50d@W#iwFoGcb`%M|7>Yua$$0LE^2dcZUDuVOKyWO5Qg`h!t%O_{2)}yu6O9J zijYg3fC@G;PB$obuW^DQY6#F^6(KbIGak>($DA zPL__6r8CG2`X+D;?QDqv0q4oqlP=_~>Ic0$iR2d>mV;0Q-?gm-X6 zXn;rPjR&2`BOK&W%8IMy3fep>=>LFjMuBd|-mfDU$|kf1_VMX@ro*VyORf%56-#1` o9$_7rXf$u4?av^%riS09flP`f0Il)s8o}WF0}y$t#qtRN0Om2m9{>OV literal 0 HcmV?d00001 diff --git a/tests/data/library_tag_cache b/tests/data/library_tag_cache deleted file mode 100644 index 6d00cf97..00000000 --- a/tests/data/library_tag_cache +++ /dev/null @@ -1,56 +0,0 @@ -info_begin -mpd_version: 0.14.2 -fs_charset: UTF-8 -info_end -songList begin -key: key1 -file: /path1 -Artist: artist1 -AlbumArtist: artist1 -Title: track1 -Album: album1 -Date: 2001-02-03 -Track: 1 -Time: 4 -key: key2 -file: /path2 -Artist: artist2 -AlbumArtist: artist2 -Title: track2 -Album: album2 -Date: 2002 -Track: 2 -Time: 4 -key: key3 -file: /path3 -Artist: artist4 -AlbumArtist: artist3 -Title: track3 -Album: album3 -Date: 2003 -Track: 3 -Time: 4 -key: key4 -file: /path4 -Artist: artist3 -Title: track4 -Album: album4 -Date: 2004 -Track: 4 -Comment: This is a fantastic track -Time: 60 -key: key5 -file: /path5 -Composer: artist5 -Title: track5 -Album: album4 -Genre: genre1 -Time: 4 -key: key6 -file: /path6 -Performer: artist6 -Title: track6 -Album: album4 -Genre: genre2 -Time: 4 -songList end diff --git a/tests/data/musicbrainz_tag_cache b/tests/data/musicbrainz_tag_cache deleted file mode 100644 index 0e9dca46..00000000 --- a/tests/data/musicbrainz_tag_cache +++ /dev/null @@ -1,20 +0,0 @@ -info_begin -mpd_version: 0.16.0 -fs_charset: UTF-8 -info_end -songList begin -key: song1.mp3 -file: /song1.mp3 -Time: 4 -Artist: name -Title: trackname -Album: albumname -AlbumArtist: albumartistname -Track: 1/2 -Date: 2006 -MUSICBRAINZ_ALBUMID: cb5f1603-d314-4c9c-91e5-e295cfb125d2 -MUSICBRAINZ_ALBUMARTISTID: 7364dea6-ca9a-48e3-be01-b44ad0d19897 -MUSICBRAINZ_ARTISTID: 7364dea6-ca9a-48e3-be01-b44ad0d19897 -MUSICBRAINZ_TRACKID: 90488461-8c1f-4a4e-826b-4c6dc70801f0 -mtime: 1272319626 -songList end diff --git a/tests/data/scanner/advanced_cache b/tests/data/scanner/advanced_cache deleted file mode 100644 index 60f7fca6..00000000 --- a/tests/data/scanner/advanced_cache +++ /dev/null @@ -1,81 +0,0 @@ -info_begin -mpd_version: 0.15.4 -fs_charset: UTF-8 -info_end -directory: subdir1 -mtime: 1288121499 -begin: subdir1 -songList begin -key: song4.mp3 -file: subdir1/song4.mp3 -Time: 5 -Artist: name -Title: trackname -Album: albumname -Track: 01/02 -Date: 2006 -mtime: 1288121370 -key: song5.mp3 -file: subdir1/song5.mp3 -Time: 5 -Artist: name -Title: trackname -Album: albumname -Track: 01/02 -Date: 2006 -mtime: 1288121370 -songList end -end: subdir1 -directory: subdir2 -mtime: 1288121499 -begin: subdir2 -songList begin -key: song6.mp3 -file: subdir2/song6.mp3 -Time: 5 -Artist: name -Title: trackname -Album: albumname -Track: 01/02 -Date: 2006 -mtime: 1288121370 -key: song7.mp3 -file: subdir2/song7.mp3 -Time: 5 -Artist: name -Title: trackname -Album: albumname -Track: 01/02 -Date: 2006 -mtime: 1288121370 -songList end -end: subdir2 -songList begin -key: song1.mp3 -file: /song1.mp3 -Time: 5 -Artist: name -Title: trackname -Album: albumname -Track: 01/02 -Date: 2006 -mtime: 1288121370 -key: song2.mp3 -file: /song2.mp3 -Time: 5 -Artist: name -Title: trackname -Album: albumname -Track: 01/02 -Date: 2006 -mtime: 1288121370 -key: song3.mp3 -file: /song3.mp3 -Time: 5 -Artist: name -Title: trackname -Album: albumname -Track: 01/02 -Date: 2006 -mtime: 1288121370 -songList end diff --git a/tests/data/scanner/empty_cache b/tests/data/scanner/empty_cache deleted file mode 100644 index 3c466a32..00000000 --- a/tests/data/scanner/empty_cache +++ /dev/null @@ -1,6 +0,0 @@ -info_begin -mpd_version: 0.15.4 -fs_charset: UTF-8 -info_end -songList begin -songList end diff --git a/tests/data/scanner/simple_cache b/tests/data/scanner/simple_cache deleted file mode 100644 index db11c324..00000000 --- a/tests/data/scanner/simple_cache +++ /dev/null @@ -1,15 +0,0 @@ -info_begin -mpd_version: 0.15.4 -fs_charset: UTF-8 -info_end -songList begin -key: song1.mp3 -file: /song1.mp3 -Time: 5 -Artist: name -Title: trackname -Album: albumname -Track: 01/02 -Date: 2006 -mtime: 1288121370 -songList end diff --git a/tests/data/simple_tag_cache b/tests/data/simple_tag_cache deleted file mode 100644 index 07a474b3..00000000 --- a/tests/data/simple_tag_cache +++ /dev/null @@ -1,16 +0,0 @@ -info_begin -mpd_version: 0.14.2 -fs_charset: UTF-8 -info_end -songList begin -key: song1.mp3 -file: /song1.mp3 -Time: 4 -Artist: name -AlbumArtist: name -Title: trackname -Album: albumname -Track: 1/2 -Date: 2006 -mtime: 1272319626 -songList end diff --git a/tests/data/utf8_tag_cache b/tests/data/utf8_tag_cache deleted file mode 100644 index 83fbcad4..00000000 --- a/tests/data/utf8_tag_cache +++ /dev/null @@ -1,18 +0,0 @@ -info_begin -mpd_version: 0.14.2 -fs_charset: UTF-8 -info_end -songList begin -key: song1.mp3 -file: /song1.mp3 -Time: 4 -Artist: æøå -AlbumArtist: æøå -Composer: æøå -Performer: æøå -Title: æøå -Album: æøå -Genre: æøå -Comment: æøå&^`ൂ㔶 -mtime: 1272319626 -songList end