local: Split out library reading and writting
- Create $XDG_DATA_DIR/mopidy/local in the local extension's validate env.
- Make sure we handle bad data causing ValueError in JSON decoding
- Initializing empty file causes more harm than good as it just leads to a
ValueError. Switched to doing write_library(json_file, {})
- Helpers have been updated to be library oriented, not track. This paves the
way for having {tracks: {uri: ...}, artist: {uri: ...}, ...} type
denormalized data.
This commit is contained in:
parent
9c2d38e989
commit
ad53a067ae
@ -1,9 +1,13 @@
|
||||
from __future__ import unicode_literals
|
||||
|
||||
import logging
|
||||
import os
|
||||
|
||||
import mopidy
|
||||
from mopidy import config, ext
|
||||
from mopidy.utils import encoding, path
|
||||
|
||||
logger = logging.getLogger('mopidy.backends.local')
|
||||
|
||||
|
||||
class Extension(ext.Extension):
|
||||
@ -27,7 +31,11 @@ class Extension(ext.Extension):
|
||||
return schema
|
||||
|
||||
def validate_environment(self):
|
||||
pass
|
||||
try:
|
||||
path.get_or_create_dir(b'$XDG_DATA_DIR/mopidy/local')
|
||||
except EnvironmentError as error:
|
||||
error = encoding.locale_decode(error)
|
||||
logger.warning('Could not create local data dir: %s', error)
|
||||
|
||||
def get_backend_classes(self):
|
||||
from .actor import LocalBackend
|
||||
|
||||
@ -1,13 +1,14 @@
|
||||
from __future__ import unicode_literals
|
||||
|
||||
import logging
|
||||
import os
|
||||
|
||||
import pykka
|
||||
|
||||
from mopidy.backends import base
|
||||
from mopidy.utils import encoding, path
|
||||
from mopidy.utils import encoding
|
||||
|
||||
from .library import LocalJsonLibraryProvider
|
||||
from . import library
|
||||
|
||||
logger = logging.getLogger('mopidy.backends.local.json')
|
||||
|
||||
@ -17,14 +18,13 @@ class LocalJsonBackend(pykka.ThreadingActor, base.Backend):
|
||||
super(LocalJsonBackend, self).__init__()
|
||||
|
||||
self.config = config
|
||||
self.check_dirs_and_files()
|
||||
self.library = LocalJsonLibraryProvider(backend=self)
|
||||
self.library = library.LocalJsonLibraryProvider(backend=self)
|
||||
self.uri_schemes = ['local']
|
||||
|
||||
def check_dirs_and_files(self):
|
||||
try:
|
||||
path.get_or_create_file(self.config['local-json']['json_file'])
|
||||
except EnvironmentError as error:
|
||||
logger.warning(
|
||||
'Could not create empty json file: %s',
|
||||
encoding.locale_decode(error))
|
||||
if not os.path.exists(config['local-json']['json_file']):
|
||||
try:
|
||||
library.write_library(config['local-json']['json_file'], {})
|
||||
logger.info('Created empty local JSON library.')
|
||||
except EnvironmentError as error:
|
||||
error = encoding.locale_decode(error)
|
||||
logger.warning('Could not create local library: %s', error)
|
||||
|
||||
@ -14,13 +14,31 @@ from mopidy.backends.local import search
|
||||
logger = logging.getLogger('mopidy.backends.local.json')
|
||||
|
||||
|
||||
def _load_tracks(json_file):
|
||||
def load_library(json_file):
|
||||
try:
|
||||
with gzip.open(json_file, 'rb') as fp:
|
||||
result = json.load(fp, object_hook=models.model_json_decoder)
|
||||
except IOError:
|
||||
return []
|
||||
return result.get('tracks', [])
|
||||
return json.load(fp, object_hook=models.model_json_decoder)
|
||||
except (IOError, ValueError) as e:
|
||||
logger.warning('Loading JSON local library failed: %s', e)
|
||||
return {}
|
||||
|
||||
|
||||
def write_library(json_file, data):
|
||||
data['version'] = mopidy.__version__
|
||||
directory, basename = os.path.split(json_file)
|
||||
|
||||
# TODO: cleanup directory/basename.* files.
|
||||
tmp = tempfile.NamedTemporaryFile(
|
||||
prefix=basename + '.', dir=directory, delete=False)
|
||||
|
||||
try:
|
||||
with gzip.GzipFile(fileobj=tmp, mode='wb') as fp:
|
||||
json.dump(data, fp, cls=models.ModelJSONEncoder,
|
||||
indent=2, separators=(',', ': '))
|
||||
os.rename(tmp.name, json_file)
|
||||
finally:
|
||||
if os.path.exists(tmp.name):
|
||||
os.remove(tmp.name)
|
||||
|
||||
|
||||
class LocalJsonLibraryProvider(base.BaseLibraryProvider):
|
||||
@ -36,7 +54,7 @@ class LocalJsonLibraryProvider(base.BaseLibraryProvider):
|
||||
'Loading local tracks from %s using %s',
|
||||
self._media_dir, self._json_file)
|
||||
|
||||
tracks = _load_tracks(self._json_file)
|
||||
tracks = load_library(self._json_file).get('tracks', [])
|
||||
uris_to_remove = set(self._uri_mapping)
|
||||
|
||||
for track in tracks:
|
||||
@ -75,7 +93,7 @@ class LocalJsonLibraryUpdateProvider(base.BaseLibraryProvider):
|
||||
self._json_file = config['local-json']['json_file']
|
||||
|
||||
def load(self):
|
||||
for track in _load_tracks(self._json_file):
|
||||
for track in load_library(self._json_file).get('tracks', []):
|
||||
self._tracks[track.uri] = track
|
||||
return self._tracks.values()
|
||||
|
||||
@ -87,19 +105,4 @@ class LocalJsonLibraryUpdateProvider(base.BaseLibraryProvider):
|
||||
del self._tracks[uri]
|
||||
|
||||
def commit(self):
|
||||
directory, basename = os.path.split(self._json_file)
|
||||
|
||||
# TODO: cleanup directory/basename.* files.
|
||||
tmp = tempfile.NamedTemporaryFile(
|
||||
prefix=basename + '.', dir=directory, delete=False)
|
||||
|
||||
try:
|
||||
with gzip.GzipFile(fileobj=tmp, mode='wb') as fp:
|
||||
data = {'version': mopidy.__version__,
|
||||
'tracks': self._tracks.values()}
|
||||
json.dump(data, fp, cls=models.ModelJSONEncoder,
|
||||
indent=2, separators=(',', ': '))
|
||||
os.rename(tmp.name, self._json_file)
|
||||
finally:
|
||||
if os.path.exists(tmp.name):
|
||||
os.remove(tmp.name)
|
||||
write_library(self._json_file, {'tracks': self._tracks.values()})
|
||||
|
||||
Loading…
Reference in New Issue
Block a user