diff --git a/docs/api/js.rst b/docs/api/js.rst index 6a8e0fcd..856f2db4 100644 --- a/docs/api/js.rst +++ b/docs/api/js.rst @@ -256,7 +256,7 @@ chain. The function will be called with the error object as the only argument: .. code-block:: js mopidy.playback.getCurrentTrack() - .catch(console.error.bind(console)); + .catch(console.error.bind(console)) .done(printCurrentTrack); You can also register the error handler at the end of the promise chain by diff --git a/docs/changelog.rst b/docs/changelog.rst index 75fdc538..741956b9 100644 --- a/docs/changelog.rst +++ b/docs/changelog.rst @@ -4,6 +4,65 @@ Changelog This changelog is used to track all major changes to Mopidy. + +v1.1.1 (UNRELEASED) +=================== + +Bug fix release. + +- Core: Make :meth:`mopidy.core.LibraryController.refresh` work for all + backends with a library provider. Previously, it wrongly worked for all + backends with a playlists provider. (Fixes: :issue:`1257`) + +- Core: Respect :confval:`core/cache_dir` and :confval:`core/data_dir` config + values added in 1.1.0 when creating the dirs Mopidy need to store data. This + should not change the behavior for desktop users running Mopidy. When running + Mopidy as a system service installed from a package which sets the core dir + configs properly (e.g. Debian and Arch packages), this fix avoids the + creation of a couple of directories that should not be used, typically + :file:`/var/lib/mopidy/.local` and :file:`/var/lib/mopidy/.cache`. (Fixes: + :issue:`1259`, PR: :issue:`1266`) + +- Local: Deprecate :confval:`local/data_dir` and respect + :confval:`core/data_dir` instead. This does not change the defaults for + desktop users, only system services installed from packages that properly set + :confval:`core/data_dir`, like the Debian and Arch packages. (Fixes: + :issue:`1259`, PR: :issue:`1266`) + +- M3U: Changed default for the :confval:`m3u/playlists_dir` from + ``$XDG_DATA_DIR/mopidy/m3u`` to unset, which now means the extension's data + dir. This does not change the defaults for desktop users, only system + services installed from packages that properly set :confval:`core/data_dir`, + like the Debian and Arch pakages. (Fixes: :issue:`1259`, PR: :issue:`1266`) + +- Stream: If "file" is present in the :confval:`stream/protocols` config value + and the :ref:`ext-file` extension is enabled, we exited with an error because + two extensions claimed the same URI scheme. We now log a warning recommending + to remove "file" from the :confval:`stream/protocols` config, and then + proceed startup. (Fixes: :issue:`1248`, PR: :issue:`1254`) + +- Stream: Fix bug in new playlist parser. A non-ASCII char in an urilist + comment would cause a crash while parsing due to comparision of a non-ASCII + bytestring with a Unicode string. (Fixes: :issue:`1265`) + +- File: Adjust log levels when failing to expand ``$XDG_MUSIC_DIR`` into a real + path. This usually happens when running Mopidy as a system service, and thus + with a limited set of environment variables. (Fixes: :issue:`1249`, PR: + :issue:`1255`) + +- File: When browsing files, we no longer scan the files to check if they're + playable. This makes browsing of the file hierarchy instant for HTTP clients, + which do no scanning of the files' metadata, and a bit faster for MPD + clients, which no longer scan the files twice. (Fixes: :issue:`1260`, PR: + :issue:`1261`) + +- Audio: Fix timeout handling in scanner. This regression caused timeouts to + expire before it should, causing scans to fail. + +- Audio: Update scanner to emit MIME type instead of an error when missing a + plugin. + + v1.1.0 (2015-08-09) =================== diff --git a/docs/config.rst b/docs/config.rst index 26304176..7f0bda31 100644 --- a/docs/config.rst +++ b/docs/config.rst @@ -65,6 +65,13 @@ Core configuration Path to base directory for storing cached data. + Mopidy and extensions will use this path to cache data that can safely be + thrown away. + + If your system is running from an SD card, it can help avoid wear and + corruption of your SD card by pointing this config to another location. If + you have enough RAM, a tmpfs might be a good choice. + When running Mopidy as a regular user, this should usually be ``$XDG_CACHE_DIR/mopidy``, i.e. :file:`~/.cache/mopidy`. @@ -85,6 +92,11 @@ Core configuration Path to base directory for persistent data files. + Mopidy and extensions will use this path to store data that cannot be + be thrown away and reproduced without some effort. Examples include + Mopidy-Local's index of your media library and Mopidy-M3U's stored + playlists. + When running Mopidy as a regular user, this should usually be ``$XDG_DATA_DIR/mopidy``, i.e. :file:`~/.local/share/mopidy`. diff --git a/docs/debian.rst b/docs/debian.rst index f939d9af..f761c4b0 100644 --- a/docs/debian.rst +++ b/docs/debian.rst @@ -113,12 +113,17 @@ from a regular Mopidy setup you'll want to know about. sudo service mopidy status -- Mopidy installed from a Debian package can use both Mopidy extensions - installed both from Debian packages and extensions installed with pip. +- Mopidy installed from a Debian package can use Mopidy extensions installed + both from Debian packages and with pip. This has always been the case. - The other way around does not work: Mopidy installed with pip can use - extensions installed with pip, but not extensions installed from a Debian - package. This is because the Debian packages install extensions into + Mopidy installed with pip can use extensions installed with pip, but + not extensions installed from a Debian package released before August 2015. + This is because the Debian packages used to install extensions into :file:`/usr/share/mopidy` which is normally not on your ``PYTHONPATH``. - Thus, your pip-installed Mopidy will not find the Debian package-installed + Thus, your pip-installed Mopidy would not find the Debian package-installed extensions. + + In August 2015, all Mopidy extension Debian packages was modified to install + into :file:`/usr/lib/python2.7/dist-packages`, like any other Python Debian + package. Thus, Mopidy installed with pip can now use extensions installed + from Debian. diff --git a/docs/ext/local.rst b/docs/ext/local.rst index 18f66adc..d6e3b56a 100644 --- a/docs/ext/local.rst +++ b/docs/ext/local.rst @@ -47,8 +47,8 @@ active at a time. To create a new library provider you must create class that implements the :class:`mopidy.local.Library` interface and install it in the extension registry under ``local:library``. Any data that the library needs to store on -disc should be stored in :confval:`local/data_dir` using the library name as -part of the filename or directory to avoid any conflicts. +disc should be stored in the extension's data dir, as returned by +:meth:`~mopidy.ext.Extension.get_data_dir`. Configuration diff --git a/docs/ext/m3u.rst b/docs/ext/m3u.rst index d05f88f1..2b86b73a 100644 --- a/docs/ext/m3u.rst +++ b/docs/ext/m3u.rst @@ -52,4 +52,5 @@ See :ref:`config` for general help on configuring Mopidy. .. confval:: m3u/playlists_dir - Path to directory with M3U files. + Path to directory with M3U files. Unset by default, in which case the + extension's data dir is used to store playlists. diff --git a/mopidy/__main__.py b/mopidy/__main__.py index ee359268..208d2ff1 100644 --- a/mopidy/__main__.py +++ b/mopidy/__main__.py @@ -75,15 +75,16 @@ def main(): args = root_cmd.parse(mopidy_args) - create_file_structures_and_config(args, extensions_data) - check_old_locations() - config, config_errors = config_lib.load( args.config_files, [d.config_schema for d in extensions_data], [d.config_defaults for d in extensions_data], args.config_overrides) + create_core_dirs(config) + create_initial_config_file(args, extensions_data) + check_old_locations() + verbosity_level = args.base_verbosity_level if args.verbosity_level: verbosity_level += args.verbosity_level @@ -166,12 +167,17 @@ def main(): raise -def create_file_structures_and_config(args, extensions_data): - path.get_or_create_dir(b'$XDG_DATA_DIR/mopidy') - path.get_or_create_dir(b'$XDG_CONFIG_DIR/mopidy') +def create_core_dirs(config): + path.get_or_create_dir(config['core']['cache_dir']) + path.get_or_create_dir(config['core']['config_dir']) + path.get_or_create_dir(config['core']['data_dir']) + + +def create_initial_config_file(args, extensions_data): + """Initialize whatever the last config file is with defaults""" - # Initialize whatever the last config file is with defaults config_file = args.config_files[-1] + if os.path.exists(path.expand_path(config_file)): return diff --git a/mopidy/audio/scan.py b/mopidy/audio/scan.py index cf370052..d1081788 100644 --- a/mopidy/audio/scan.py +++ b/mopidy/audio/scan.py @@ -12,8 +12,6 @@ from mopidy import exceptions from mopidy.audio import utils from mopidy.internal import encoding -_missing_plugin_desc = gst.pbutils.missing_plugin_message_get_description - _Result = collections.namedtuple( 'Result', ('uri', 'tags', 'duration', 'seekable', 'mime', 'playable')) @@ -134,12 +132,12 @@ def _process(pipeline, timeout_ms): clock = pipeline.get_clock() bus = pipeline.get_bus() timeout = timeout_ms * gst.MSECOND - tags, mime, have_audio, missing_description = {}, None, False, None + tags, mime, have_audio, missing_message = {}, None, False, None types = (gst.MESSAGE_ELEMENT | gst.MESSAGE_APPLICATION | gst.MESSAGE_ERROR | gst.MESSAGE_EOS | gst.MESSAGE_ASYNC_DONE | gst.MESSAGE_TAG) - start = clock.get_time() + previous = clock.get_time() while timeout > 0: message = bus.timed_pop_filtered(timeout, types) @@ -147,8 +145,7 @@ def _process(pipeline, timeout_ms): break elif message.type == gst.MESSAGE_ELEMENT: if gst.pbutils.is_missing_plugin_message(message): - missing_description = encoding.locale_decode( - _missing_plugin_desc(message)) + missing_message = message elif message.type == gst.MESSAGE_APPLICATION: if message.structure.get_name() == 'have-type': mime = message.structure['caps'].get_name() @@ -158,8 +155,10 @@ def _process(pipeline, timeout_ms): have_audio = True elif message.type == gst.MESSAGE_ERROR: error = encoding.locale_decode(message.parse_error()[0]) - if missing_description: - error = '%s (%s)' % (missing_description, error) + if missing_message and not mime: + caps = missing_message.structure['detail'] + mime = caps.get_structure(0).get_name() + return tags, mime, have_audio raise exceptions.ScannerError(error) elif message.type == gst.MESSAGE_EOS: return tags, mime, have_audio @@ -171,7 +170,9 @@ def _process(pipeline, timeout_ms): # Note that this will only keep the last tag. tags.update(utils.convert_taglist(taglist)) - timeout -= clock.get_time() - start + now = clock.get_time() + timeout -= now - previous + previous = now raise exceptions.ScannerError('Timeout after %dms' % timeout_ms) diff --git a/mopidy/core/actor.py b/mopidy/core/actor.py index f20b0ba2..6d10a593 100644 --- a/mopidy/core/actor.py +++ b/mopidy/core/actor.py @@ -161,7 +161,7 @@ class Backends(list): for scheme in b.uri_schemes.get(): assert scheme not in backends_by_scheme, ( - 'Cannot add URI scheme %s for %s, ' + 'Cannot add URI scheme "%s" for %s, ' 'it is already handled by %s' ) % (scheme, name(b), name(backends_by_scheme[scheme])) backends_by_scheme[scheme] = b diff --git a/mopidy/core/library.py b/mopidy/core/library.py index c300fbb9..ce420812 100644 --- a/mopidy/core/library.py +++ b/mopidy/core/library.py @@ -255,7 +255,7 @@ class LibraryController(object): backends = {} uri_scheme = urlparse.urlparse(uri).scheme if uri else None - for backend_scheme, backend in self.backends.with_playlists.items(): + for backend_scheme, backend in self.backends.with_library.items(): backends.setdefault(backend, set()).add(backend_scheme) for backend, backend_schemes in backends.items(): diff --git a/mopidy/ext.py b/mopidy/ext.py index 908b6d5d..199d7ab6 100644 --- a/mopidy/ext.py +++ b/mopidy/ext.py @@ -63,6 +63,8 @@ class Extension(object): def get_cache_dir(self, config): """Get or create cache directory for the extension. + Use this directory to cache data that can safely be thrown away. + :param config: the Mopidy config object :return: string """ @@ -87,6 +89,8 @@ class Extension(object): def get_data_dir(self, config): """Get or create data directory for the extension. + Use this directory to store data that should be persistent. + :param config: the Mopidy config object :returns: string """ diff --git a/mopidy/file/library.py b/mopidy/file/library.py index 10586561..b8531a6e 100644 --- a/mopidy/file/library.py +++ b/mopidy/file/library.py @@ -71,7 +71,7 @@ class FileLibraryProvider(backend.LibraryProvider): name = dir_entry.decode(FS_ENCODING, 'replace') if os.path.isdir(child_path): result.append(models.Ref.directory(name=name, uri=uri)) - elif os.path.isfile(child_path) and self._is_audio_file(uri): + elif os.path.isfile(child_path): result.append(models.Ref.track(name=name, uri=uri)) result.sort(key=operator.attrgetter('name')) @@ -108,12 +108,15 @@ class FileLibraryProvider(backend.LibraryProvider): media_dir_split[0].encode(FS_ENCODING)) if not local_path: - logger.warning('Failed expanding path (%s) from' - 'file/media_dirs config value.', - media_dir_split[0]) + logger.debug( + 'Failed expanding path (%s) from file/media_dirs config ' + 'value.', + media_dir_split[0]) continue elif not os.path.isdir(local_path): - logger.warning('%s is not a directory', local_path) + logger.warning( + '%s is not a directory. Please create the directory or ' + 'update the file/media_dirs config value.', local_path) continue media_dir['path'] = local_path @@ -131,18 +134,6 @@ class FileLibraryProvider(backend.LibraryProvider): name=media_dir['name'], uri=path.path_to_uri(media_dir['path'])) - def _is_audio_file(self, uri): - try: - result = self._scanner.scan(uri) - if result.playable: - logger.debug('Playable file: %s', result.uri) - else: - logger.debug('Unplayable file: %s (not audio)', result.uri) - return result.playable - except exceptions.ScannerError as e: - logger.debug('Unplayable file: %s (%s)', uri, e) - return False - def _is_in_basedir(self, local_path): return any( path.is_path_inside_base_dir(local_path, media_dir['path']) diff --git a/mopidy/internal/playlists.py b/mopidy/internal/playlists.py index 219d3ec6..f8e654af 100644 --- a/mopidy/internal/playlists.py +++ b/mopidy/internal/playlists.py @@ -122,7 +122,7 @@ def parse_asx(data): def parse_urilist(data): result = [] for line in data.splitlines(): - if not line.strip() or line.startswith('#'): + if not line.strip() or line.startswith(b'#'): continue try: validation.check_uri(line) diff --git a/mopidy/local/__init__.py b/mopidy/local/__init__.py index ff61c17c..3ee2703e 100644 --- a/mopidy/local/__init__.py +++ b/mopidy/local/__init__.py @@ -23,7 +23,7 @@ class Extension(ext.Extension): schema = super(Extension, self).get_config_schema() schema['library'] = config.String() schema['media_dir'] = config.Path() - schema['data_dir'] = config.Path() + schema['data_dir'] = config.Deprecated() schema['playlists_dir'] = config.Deprecated() schema['tag_cache_file'] = config.Deprecated() schema['scan_timeout'] = config.Integer( diff --git a/mopidy/local/ext.conf b/mopidy/local/ext.conf index ebd7962f..6dd29147 100644 --- a/mopidy/local/ext.conf +++ b/mopidy/local/ext.conf @@ -2,7 +2,6 @@ enabled = true library = json media_dir = $XDG_MUSIC_DIR -data_dir = $XDG_DATA_DIR/mopidy/local scan_timeout = 1000 scan_flush_threshold = 1000 scan_follow_symlinks = false diff --git a/mopidy/local/json.py b/mopidy/local/json.py index 0be5e99e..501990ee 100644 --- a/mopidy/local/json.py +++ b/mopidy/local/json.py @@ -12,7 +12,7 @@ import tempfile import mopidy from mopidy import compat, local, models from mopidy.internal import encoding, timer -from mopidy.local import search, storage, translator +from mopidy.local import Extension, search, storage, translator logger = logging.getLogger(__name__) @@ -116,7 +116,7 @@ class JsonLibrary(local.Library): self._browse_cache = None self._media_dir = config['local']['media_dir'] self._json_file = os.path.join( - config['local']['data_dir'], b'library.json.gz') + Extension().get_data_dir(config), b'library.json.gz') storage.check_dirs_and_files(config) diff --git a/mopidy/local/storage.py b/mopidy/local/storage.py index 1808c4a2..aaa74fba 100644 --- a/mopidy/local/storage.py +++ b/mopidy/local/storage.py @@ -3,8 +3,6 @@ from __future__ import absolute_import, unicode_literals import logging import os -from mopidy.internal import encoding, path - logger = logging.getLogger(__name__) @@ -13,10 +11,3 @@ def check_dirs_and_files(config): logger.warning( 'Local media dir %s does not exist.' % config['local']['media_dir']) - - try: - path.get_or_create_dir(config['local']['data_dir']) - except EnvironmentError as error: - logger.warning( - 'Could not create local data dir: %s', - encoding.locale_decode(error)) diff --git a/mopidy/m3u/__init__.py b/mopidy/m3u/__init__.py index e0fcf305..06825932 100644 --- a/mopidy/m3u/__init__.py +++ b/mopidy/m3u/__init__.py @@ -21,7 +21,7 @@ class Extension(ext.Extension): def get_config_schema(self): schema = super(Extension, self).get_config_schema() - schema['playlists_dir'] = config.Path() + schema['playlists_dir'] = config.Path(optional=True) return schema def setup(self, registry): diff --git a/mopidy/m3u/actor.py b/mopidy/m3u/actor.py index fe959d86..fc4734a2 100644 --- a/mopidy/m3u/actor.py +++ b/mopidy/m3u/actor.py @@ -4,7 +4,7 @@ import logging import pykka -from mopidy import backend +from mopidy import backend, m3u from mopidy.internal import encoding, path from mopidy.m3u.library import M3ULibraryProvider from mopidy.m3u.playlists import M3UPlaylistsProvider @@ -21,12 +21,16 @@ class M3UBackend(pykka.ThreadingActor, backend.Backend): self._config = config - try: - path.get_or_create_dir(config['m3u']['playlists_dir']) - except EnvironmentError as error: - logger.warning( - 'Could not create M3U playlists dir: %s', - encoding.locale_decode(error)) + if config['m3u']['playlists_dir'] is not None: + self._playlists_dir = config['m3u']['playlists_dir'] + try: + path.get_or_create_dir(self._playlists_dir) + except EnvironmentError as error: + logger.warning( + 'Could not create M3U playlists dir: %s', + encoding.locale_decode(error)) + else: + self._playlists_dir = m3u.Extension().get_data_dir(config) self.playlists = M3UPlaylistsProvider(backend=self) self.library = M3ULibraryProvider(backend=self) diff --git a/mopidy/m3u/ext.conf b/mopidy/m3u/ext.conf index 0e828b1b..adc0d00a 100644 --- a/mopidy/m3u/ext.conf +++ b/mopidy/m3u/ext.conf @@ -1,3 +1,3 @@ [m3u] enabled = true -playlists_dir = $XDG_DATA_DIR/mopidy/m3u +playlists_dir = diff --git a/mopidy/m3u/playlists.py b/mopidy/m3u/playlists.py index af92e062..3567f8aa 100644 --- a/mopidy/m3u/playlists.py +++ b/mopidy/m3u/playlists.py @@ -23,7 +23,7 @@ class M3UPlaylistsProvider(backend.PlaylistsProvider): def __init__(self, *args, **kwargs): super(M3UPlaylistsProvider, self).__init__(*args, **kwargs) - self._playlists_dir = self.backend._config['m3u']['playlists_dir'] + self._playlists_dir = self.backend._playlists_dir self._playlists = {} self.refresh() diff --git a/mopidy/mpd/dispatcher.py b/mopidy/mpd/dispatcher.py index a8e2c05c..099a2f18 100644 --- a/mopidy/mpd/dispatcher.py +++ b/mopidy/mpd/dispatcher.py @@ -271,9 +271,9 @@ class MpdContext(object): If ``lookup`` is true and the ``path`` is to a track, the returned ``data`` is a future which will contain the results from looking up - the URI with :meth:`mopidy.core.LibraryController.lookup` If ``lookup`` - is false and the ``path`` is to a track, the returned ``data`` will be - a :class:`mopidy.models.Ref` for the track. + the URI with :meth:`mopidy.core.LibraryController.lookup`. If + ``lookup`` is false and the ``path`` is to a track, the returned + ``data`` will be a :class:`mopidy.models.Ref` for the track. For all entries that are not tracks, the returned ``data`` will be :class:`None`. diff --git a/mopidy/stream/actor.py b/mopidy/stream/actor.py index ae5be8e0..cc9632d5 100644 --- a/mopidy/stream/actor.py +++ b/mopidy/stream/actor.py @@ -36,6 +36,13 @@ class StreamBackend(pykka.ThreadingActor, backend.Backend): self.uri_schemes = audio_lib.supported_uri_schemes( config['stream']['protocols']) + if 'file' in self.uri_schemes and config['file']['enabled']: + logger.warning( + 'The stream/protocols config value includes the "file" ' + 'protocol. "file" playback is now handled by Mopidy-File. ' + 'Please remove it from the stream/protocols config.') + self.uri_schemes -= {'file'} + class StreamLibraryProvider(backend.LibraryProvider): diff --git a/tests/audio/test_scan.py b/tests/audio/test_scan.py index c558835e..8c2b9af3 100644 --- a/tests/audio/test_scan.py +++ b/tests/audio/test_scan.py @@ -40,8 +40,11 @@ class ScannerTest(unittest.TestCase): self.assertEqual(self.result[name].tags[key], value) def check_if_missing_plugin(self): - if any(['missing a plug-in' in str(e) for e in self.errors.values()]): - raise unittest.SkipTest('Missing MP3 support?') + for path, result in self.result.items(): + if not path.endswith('.mp3'): + continue + if not result.playable and result.mime == 'audio/mpeg': + raise unittest.SkipTest('Missing MP3 support?') def test_tags_is_set(self): self.scan(self.find('scanner/simple')) @@ -109,6 +112,17 @@ class ScannerTest(unittest.TestCase): wav = path_to_data_dir('scanner/empty.wav') self.assertEqual(self.result[wav].duration, 0) + def test_uri_list(self): + path = path_to_data_dir('scanner/playlist.m3u') + self.scan([path]) + self.assertEqual(self.result[path].mime, 'text/uri-list') + + def test_text_plain(self): + # GStreamer decode bin hardcodes bad handling of text plain :/ + path = path_to_data_dir('scanner/plain.txt') + self.scan([path]) + self.assertIn(path, self.errors) + @unittest.SkipTest def test_song_without_time_is_handeled(self): pass diff --git a/tests/core/test_actor.py b/tests/core/test_actor.py index 410933d2..8f062fa2 100644 --- a/tests/core/test_actor.py +++ b/tests/core/test_actor.py @@ -37,7 +37,8 @@ class CoreActorTest(unittest.TestCase): self.assertRaisesRegexp( AssertionError, - 'Cannot add URI scheme dummy1 for B2, it is already handled by B1', + 'Cannot add URI scheme "dummy1" for B2, ' + 'it is already handled by B1', Core, mixer=None, backends=[self.backend1, self.backend2]) def test_version(self): diff --git a/tests/core/test_library.py b/tests/core/test_library.py index 941f1831..92b22bfb 100644 --- a/tests/core/test_library.py +++ b/tests/core/test_library.py @@ -20,6 +20,7 @@ class BaseCoreLibraryTest(unittest.TestCase): self.library1.get_images.return_value.get.return_value = {} self.library1.root_directory.get.return_value = dummy1_root self.backend1.library = self.library1 + self.backend1.has_playlists.return_value.get.return_value = False dummy2_root = Ref.directory(uri='dummy2:directory', name='dummy2') self.backend2 = mock.Mock() @@ -29,13 +30,14 @@ class BaseCoreLibraryTest(unittest.TestCase): self.library2.get_images.return_value.get.return_value = {} self.library2.root_directory.get.return_value = dummy2_root self.backend2.library = self.library2 + self.backend2.has_playlists.return_value.get.return_value = False # A backend without the optional library provider self.backend3 = mock.Mock() self.backend3.uri_schemes.get.return_value = ['dummy3'] self.backend3.actor_ref.actor_class.__name__ = 'DummyBackend3' - self.backend3.has_library().get.return_value = False - self.backend3.has_library_browse().get.return_value = False + self.backend3.has_library.return_value.get.return_value = False + self.backend3.has_library_browse.return_value.get.return_value = False self.core = core.Core(mixer=None, backends=[ self.backend1, self.backend2, self.backend3]) diff --git a/tests/data/library.json.gz b/tests/data/local/library.json.gz similarity index 100% rename from tests/data/library.json.gz rename to tests/data/local/library.json.gz diff --git a/tests/data/scanner/plain.txt b/tests/data/scanner/plain.txt new file mode 100644 index 00000000..3180d4a9 --- /dev/null +++ b/tests/data/scanner/plain.txt @@ -0,0 +1 @@ +Some plain text file with nothing special in it. diff --git a/tests/data/scanner/playlist.m3u b/tests/data/scanner/playlist.m3u new file mode 100644 index 00000000..df0f0142 --- /dev/null +++ b/tests/data/scanner/playlist.m3u @@ -0,0 +1 @@ +http://example.com/ diff --git a/tests/internal/test_playlists.py b/tests/internal/test_playlists.py index 21537813..9a1c49d5 100644 --- a/tests/internal/test_playlists.py +++ b/tests/internal/test_playlists.py @@ -23,7 +23,7 @@ file:///tmp/baz URILIST = b""" file:///tmp/foo -# a comment +# a comment \xc5\xa7\xc5\x95 file:///tmp/bar file:///tmp/baz diff --git a/tests/local/test_json.py b/tests/local/test_json.py index 520287ad..169ba743 100644 --- a/tests/local/test_json.py +++ b/tests/local/test_json.py @@ -45,10 +45,11 @@ class BrowseCacheTest(unittest.TestCase): class JsonLibraryTest(unittest.TestCase): config = { + 'core': { + 'data_dir': path_to_data_dir(''), + }, 'local': { 'media_dir': path_to_data_dir(''), - 'data_dir': path_to_data_dir(''), - 'playlists_dir': b'', 'library': 'json', }, } diff --git a/tests/local/test_library.py b/tests/local/test_library.py index 7763057f..4142d6c3 100644 --- a/tests/local/test_library.py +++ b/tests/local/test_library.py @@ -65,10 +65,11 @@ class LocalLibraryProviderTest(unittest.TestCase): ] config = { + 'core': { + 'data_dir': path_to_data_dir(''), + }, 'local': { 'media_dir': path_to_data_dir(''), - 'data_dir': path_to_data_dir(''), - 'playlists_dir': b'', 'library': 'json', }, } @@ -105,11 +106,15 @@ class LocalLibraryProviderTest(unittest.TestCase): tmpdir = tempfile.mkdtemp() try: - tmplib = os.path.join(tmpdir, 'library.json.gz') - shutil.copy(path_to_data_dir('library.json.gz'), tmplib) + tmpdir_local = os.path.join(tmpdir, 'local') + shutil.copytree(path_to_data_dir('local'), tmpdir_local) - config = {'local': self.config['local'].copy()} - config['local']['data_dir'] = tmpdir + config = { + 'core': { + 'data_dir': tmpdir, + }, + 'local': self.config['local'], + } backend = actor.LocalBackend(config=config, audio=None) # Sanity check that value is in the library @@ -117,6 +122,7 @@ class LocalLibraryProviderTest(unittest.TestCase): self.assertEqual(result, self.tracks[0:1]) # Clear and refresh. + tmplib = os.path.join(tmpdir_local, 'library.json.gz') open(tmplib, 'w').close() backend.library.refresh() diff --git a/tests/local/test_playback.py b/tests/local/test_playback.py index bab70847..b99f8508 100644 --- a/tests/local/test_playback.py +++ b/tests/local/test_playback.py @@ -23,12 +23,11 @@ from tests.local import generate_song, populate_tracklist class LocalPlaybackProviderTest(unittest.TestCase): config = { 'core': { + 'data_dir': path_to_data_dir(''), 'max_tracklist_length': 10000, }, 'local': { 'media_dir': path_to_data_dir(''), - 'data_dir': path_to_data_dir(''), - 'playlists_dir': b'', 'library': 'json', } } diff --git a/tests/local/test_tracklist.py b/tests/local/test_tracklist.py index 72da3f13..b7ed7dcb 100644 --- a/tests/local/test_tracklist.py +++ b/tests/local/test_tracklist.py @@ -18,11 +18,11 @@ from tests.local import generate_song, populate_tracklist class LocalTracklistProviderTest(unittest.TestCase): config = { 'core': { + 'data_dir': path_to_data_dir(''), 'max_tracklist_length': 10000 }, 'local': { 'media_dir': path_to_data_dir(''), - 'data_dir': path_to_data_dir(''), 'playlists_dir': b'', 'library': 'json', }