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:
Thomas Adamcik 2015-03-11 23:09:14 +01:00
parent f4e6956bb7
commit cee73b5501
4 changed files with 25 additions and 12 deletions

View File

@ -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]

View File

@ -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)

View File

@ -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)

View File

@ -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