From 3c6a0543f51138119daf27e8674f24b2fd28b4c9 Mon Sep 17 00:00:00 2001 From: Tobias Sauerwein Date: Wed, 31 Jul 2013 23:52:24 +0200 Subject: [PATCH] Scanner: Fix deadlock on incorrectly identified files --- mopidy/backends/local/__init__.py | 1 + mopidy/backends/local/ext.conf | 1 + mopidy/scanner.py | 22 ++++++++++++++++++++-- tests/data/scanner/example.log | Bin 0 -> 206 bytes tests/scanner_test.py | 4 ++++ 5 files changed, 26 insertions(+), 2 deletions(-) create mode 100644 tests/data/scanner/example.log diff --git a/mopidy/backends/local/__init__.py b/mopidy/backends/local/__init__.py index f718eeb5..cf982220 100644 --- a/mopidy/backends/local/__init__.py +++ b/mopidy/backends/local/__init__.py @@ -18,6 +18,7 @@ class Extension(ext.Extension): def get_config_schema(self): schema = super(Extension, self).get_config_schema() + schema['scan_timeout'] = config.Integer(minimum=0) schema['media_dir'] = config.Path() schema['playlists_dir'] = config.Path() schema['tag_cache_file'] = config.Path() diff --git a/mopidy/backends/local/ext.conf b/mopidy/backends/local/ext.conf index 54c3ab78..ae30438f 100644 --- a/mopidy/backends/local/ext.conf +++ b/mopidy/backends/local/ext.conf @@ -1,5 +1,6 @@ [local] enabled = true +scan_timeout = 1000 media_dir = $XDG_MUSIC_DIR playlists_dir = $XDG_DATA_DIR/mopidy/local/playlists tag_cache_file = $XDG_DATA_DIR/mopidy/local/tag_cache diff --git a/mopidy/scanner.py b/mopidy/scanner.py index 9f13d454..cdfdad96 100644 --- a/mopidy/scanner.py +++ b/mopidy/scanner.py @@ -97,9 +97,14 @@ def main(): logging.warning('Failed %s: %s', uri, error) logging.debug('Debug info for %s: %s', uri, debug) + if not config['local']['scan_timeout']: + scan_timeout = 1000 + else: + scan_timeout = config['local']['scan_timeout'] + logging.info('Scanning new and modified tracks.') # TODO: just pass the library in instead? - scanner = Scanner(uris_update, store, debug) + scanner = Scanner(uris_update, store, debug, scan_timeout) try: scanner.start() except KeyboardInterrupt: @@ -176,12 +181,14 @@ def translator(data): class Scanner(object): - def __init__(self, uris, data_callback, error_callback=None): + def __init__(self, uris, data_callback, error_callback=None, scan_timeout=1000): self.data = {} self.uris = iter(uris) self.data_callback = data_callback self.error_callback = error_callback + self.scan_timeout = scan_timeout self.loop = gobject.MainLoop() + self.timeout_id = None self.fakesink = gst.element_factory_make('fakesink') self.fakesink.set_property('signal-handoffs', True) @@ -252,6 +259,13 @@ class Scanner(object): self.error_callback(uri, error, debug) self.next_uri() + def process_timeout(self): + if self.error_callback: + uri = self.uribin.get_property('uri') + self.error_callback(uri, 'Processing timeout after %i seconds' % self.timeout, 'debug') + self.next_uri() + return True + def get_duration(self): self.pipe.get_state() # Block until state change is done. try: @@ -262,6 +276,9 @@ class Scanner(object): def next_uri(self): self.data = {} + if self.timeout_id: + gobject.source_remove(self.timeout_id) + self.timeout_id = None try: uri = next(self.uris) except StopIteration: @@ -269,6 +286,7 @@ class Scanner(object): return False self.pipe.set_state(gst.STATE_NULL) self.uribin.set_property('uri', uri) + self.timeout_id = gobject.timeout_add(self.scan_timeout, self.process_timeout) self.pipe.set_state(gst.STATE_PLAYING) return True diff --git a/tests/data/scanner/example.log b/tests/data/scanner/example.log new file mode 100644 index 0000000000000000000000000000000000000000..c49a044d01813d3ce57031f8fc41fe7e7abb2974 GIT binary patch literal 206 zcmYL@%L>9U5Jk^g@E`mD5z~sGJ1Jedbze1>f{&sV^yk&nbRl7qn_=#`^Zk^(s5sCu zVZ)On4L5b+-SSrL2+WwP_C)6@Rc@WQJ9ANGtehD9wTwriWqN{V%qUeUzi=v=*y$Zo j`?Rawvu`c4QAPiMdSH?0TOIvA12<=?4sNoxvrGv;5;`AM literal 0 HcmV?d00001 diff --git a/tests/scanner_test.py b/tests/scanner_test.py index dcf891c0..903d6510 100644 --- a/tests/scanner_test.py +++ b/tests/scanner_test.py @@ -210,6 +210,10 @@ class ScannerTest(unittest.TestCase): self.scan('scanner/image') self.assert_(self.errors) + def test_log_file_is_ignored(self): + self.scan('scanner/example.log') + self.assert_(self.errors) + @unittest.SkipTest def test_song_without_time_is_handeled(self): pass