audio: Add support for checking seekable state in scanner
Return type of scanner changed to a named tuple with (uri, tags, duration, seekable). This should help with #872 and the related "live" issues. Tests, local scan and stream metadata lookup have been updated to account for the changes.
This commit is contained in:
parent
f4e6956bb7
commit
cee73b5501
@ -1,5 +1,6 @@
|
||||
from __future__ import absolute_import, division, unicode_literals
|
||||
|
||||
import collections
|
||||
import time
|
||||
|
||||
import pygst
|
||||
@ -13,6 +14,9 @@ from mopidy.utils import encoding
|
||||
|
||||
_missing_plugin_desc = gst.pbutils.missing_plugin_message_get_description
|
||||
|
||||
Result = collections.namedtuple(
|
||||
'Result', ('uri', 'tags', 'duration', 'seekable'))
|
||||
|
||||
|
||||
class Scanner(object):
|
||||
"""
|
||||
@ -54,19 +58,22 @@ class Scanner(object):
|
||||
|
||||
:param uri: URI of the resource to scan.
|
||||
:type event: string
|
||||
:return: (tags, duration) pair. tags is a dictionary of lists for all
|
||||
the tags we found and duration is the length of the URI in
|
||||
milliseconds, or :class:`None` if the URI has no duration.
|
||||
:return: A named tuple containing ``(uri, tags, duration, seekable)``.
|
||||
``tags`` is a dictionary of lists for all the tags we found.
|
||||
``duration`` is the length of the URI in milliseconds, or
|
||||
:class:`None` if the URI has no duration. ``seekable`` is boolean
|
||||
indicating if a seek would succeed.
|
||||
"""
|
||||
tags, duration = None, None
|
||||
tags, duration, seekable = None, None, None
|
||||
try:
|
||||
self._setup(uri)
|
||||
tags = self._collect()
|
||||
duration = self._query_duration()
|
||||
seekable = self._query_seekable()
|
||||
finally:
|
||||
self._reset()
|
||||
|
||||
return tags, duration
|
||||
return Result(uri, tags, duration, seekable)
|
||||
|
||||
def _setup(self, uri):
|
||||
"""Primes the pipeline for collection."""
|
||||
@ -123,3 +130,8 @@ class Scanner(object):
|
||||
return None
|
||||
else:
|
||||
return duration // gst.MSECOND
|
||||
|
||||
def _query_seekable(self):
|
||||
query = gst.query_new_seeking(gst.FORMAT_TIME)
|
||||
self._pipe.query(query)
|
||||
return query.parse_seeking()[1]
|
||||
|
||||
@ -133,7 +133,8 @@ class ScanCommand(commands.Command):
|
||||
try:
|
||||
relpath = translator.local_track_uri_to_path(uri, media_dir)
|
||||
file_uri = path.path_to_uri(os.path.join(media_dir, relpath))
|
||||
tags, duration = scanner.scan(file_uri)
|
||||
result = scanner.scan(file_uri)
|
||||
tags, duration = result.tags, result.duration
|
||||
if duration < MIN_DURATION_MS:
|
||||
logger.warning('Failed %s: Track shorter than %dms',
|
||||
uri, MIN_DURATION_MS)
|
||||
|
||||
@ -45,9 +45,9 @@ class StreamLibraryProvider(backend.LibraryProvider):
|
||||
return [Track(uri=uri)]
|
||||
|
||||
try:
|
||||
tags, duration = self._scanner.scan(uri)
|
||||
track = utils.convert_tags_to_track(tags).copy(
|
||||
uri=uri, length=duration)
|
||||
result = self._scanner.scan(uri)
|
||||
track = utils.convert_tags_to_track(result.tags).copy(
|
||||
uri=uri, length=result.duration)
|
||||
except exceptions.ScannerError as e:
|
||||
logger.warning('Problem looking up %s: %s', uri, e)
|
||||
track = Track(uri=uri)
|
||||
|
||||
@ -31,9 +31,9 @@ class ScannerTest(unittest.TestCase):
|
||||
uri = path_lib.path_to_uri(path)
|
||||
key = uri[len('file://'):]
|
||||
try:
|
||||
tags, duration = scanner.scan(uri)
|
||||
self.tags[key] = tags
|
||||
self.durations[key] = duration
|
||||
result = scanner.scan(uri)
|
||||
self.tags[key] = result.tags
|
||||
self.durations[key] = result.duration
|
||||
except exceptions.ScannerError as error:
|
||||
self.errors[key] = error
|
||||
|
||||
|
||||
Loading…
Reference in New Issue
Block a user