Repository: beetbox/beets

Issue:
keyfinder: Output parsing error
### Problem

Running this command in verbose (`-vv`) mode:

``` sh
$ beet -vv keyfinder anything
```

Led to this problem:

```
user configuration: /home/diomekes/.config/beets/config.yaml
data directory: /home/diomekes/.config/beets
plugin paths:
Sending event: pluginload
inline: adding item field disc_and_track
library database: /home/diomekes/.config/beets/library.db
library directory: /home/diomekes/media/music
Sending event: library_opened
Traceback (most recent call last):
  File "/usr/bin/beet", line 9, in <module>
    load_entry_point('beets==1.3.19', 'console_scripts', 'beet')()
  File "/usr/lib/python2.7/site-packages/beets/ui/__init__.py", line 1266, in main
    _raw_main(args)
  File "/usr/lib/python2.7/site-packages/beets/ui/__init__.py", line 1253, in _raw_main
    subcommand.func(lib, suboptions, subargs)
  File "/usr/lib/python2.7/site-packages/beetsplug/keyfinder.py", line 48, in command
    self.find_key(lib.items(ui.decargs(args)), write=ui.should_write())
  File "/usr/lib/python2.7/site-packages/beetsplug/keyfinder.py", line 74, in find_key
    key_raw = output.rsplit(None, 1)[-1]
IndexError: list index out of range
```

keyfinder-cli works if run directly
### Setup
- OS:  archlinux
- Python version: 2.7.12
- beets version: 1.3.19
- Turning off plugins made problem go away (yes/no): problem is with keyfinder plugin only
- libkeyfinder-git 239.0a5ec7f-1
- keyfinder-cli-git 49.40a41ab-1

My configuration (output of `beet config`) is:

``` yaml
...
keyfinder:
    bin: keyfinder-cli
    auto: yes
    overwrite: no

plugins: badfiles chroma convert duplicates fetchart fromfilename fuzzy info inline keyfinder lastgenre lyrics mbcollection mbsync missing play random scrub smartplaylist zero
...
```


Comments:

Patch:
diff --git a/beetsplug/keyfinder.py b/beetsplug/keyfinder.py
index a75b8d97..702003f0 100644
--- a/beetsplug/keyfinder.py
+++ b/beetsplug/keyfinder.py
@@ -76,7 +76,14 @@ class KeyFinderPlugin(BeetsPlugin):
                                 item.path)
                 continue
 
-            key_raw = output.rsplit(None, 1)[-1]
+            try:
+                key_raw = output.rsplit(None, 1)[-1]
+            except IndexError:
+                # Sometimes keyfinder-cli returns 0 but with no key, usually
+                # when the file is silent or corrupt, so we log and skip.
+                self._log.error(u'no key returned for path: {0}', item.path)
+                continue
+
             try:
                 key = util.text_string(key_raw)
             except UnicodeDecodeError:
diff --git a/docs/changelog.rst b/docs/changelog.rst
index 0de3b15a..41221b1f 100644
--- a/docs/changelog.rst
+++ b/docs/changelog.rst
@@ -282,6 +282,8 @@ Fixes:
   :bug:`3773` :bug:`3774`
 * Fix a bug causing PIL to generate poor quality JPEGs when resizing artwork.
   :bug:`3743`
+* :doc:`plugins/keyfinder`: Catch output from ``keyfinder-cli`` that is missing key.
+  :bug:`2242`
 
 For plugin developers:
 


Test patch:
diff --git a/test/test_keyfinder.py b/test/test_keyfinder.py
index a9ac43a2..c8735e47 100644
--- a/test/test_keyfinder.py
+++ b/test/test_keyfinder.py
@@ -76,6 +76,16 @@ class KeyFinderTest(unittest.TestCase, TestHelper):
         item.load()
         self.assertEqual(item['initial_key'], 'F')
 
+    def test_no_key(self, command_output):
+        item = Item(path='/file')
+        item.add(self.lib)
+
+        command_output.return_value = util.CommandOutput(b"", b"")
+        self.run_command('keyfinder')
+
+        item.load()
+        self.assertEqual(item['initial_key'], None)
+
 
 def suite():
     return unittest.TestLoader().loadTestsFromName(__name__)