Repository: beetbox/beets

Issue:
Crash when doing bulk import in quiet singleton mode.
I have an _extremely_ large (~350 GB) music collection, that is fairly disorganized, so I'm trying to get as much of the tagging done without requiring user-input before I have to deal with manual tag intervention.

Anyways, I'm running `beet` like so: `beet -v import -sq /media/Storage/MusicTemp/ | tee musicImportLog2.txt`

After running for a while (about 12 hours), I get a crash that looks like:

```
/media/Storage/MusicTemp/Boards of Canada/Hi Scores/04 - Boards of Canada - June 9th (2).mp3
Tagging track: Boards of Canada - June 9th
(Similarity: 100.0%)
  File "/usr/local/bin/beet", line 9, in <module>
    load_entry_point('beets==1.3.3', 'console_scripts', 'beet')()
  File "/usr/local/lib/python2.7/dist-packages/beets/ui/__init__.py", line 946, in main
    _raw_main(args)
  File "/usr/local/lib/python2.7/dist-packages/beets/ui/__init__.py", line 937, in _raw_main
    subcommand.func(lib, suboptions, subargs)
  File "/usr/local/lib/python2.7/dist-packages/beets/ui/commands.py", line 843, in import_func
    import_files(lib, paths, query)
  File "/usr/local/lib/python2.7/dist-packages/beets/ui/commands.py", line 779, in import_files
    session.run()
  File "/usr/local/lib/python2.7/dist-packages/beets/importer.py", line 347, in run
    pl.run_parallel(QUEUE_SIZE)
  File "/usr/local/lib/python2.7/dist-packages/beets/util/pipeline.py", line 194, in run
    msg = self.coro.next()
  File "/usr/local/lib/python2.7/dist-packages/beets/importer.py", line 590, in read_tasks
    for path, items in autotag.albums_in_dir(toppath):
  File "/usr/local/lib/python2.7/dist-packages/beets/autotag/__init__.py", line 54, in albums_in_dir
    i = library.Item.from_path(os.path.join(root, filename))
  File "/usr/local/lib/python2.7/dist-packages/beets/library.py", line 303, in from_path
    i.read(path)
  File "/usr/local/lib/python2.7/dist-packages/beets/library.py", line 357, in read
    value = getattr(f, key)
  File "/usr/local/lib/python2.7/dist-packages/beets/mediafile.py", line 579, in __get__
    return _safe_cast(self.out_type, out)
  File "/usr/local/lib/python2.7/dist-packages/beets/mediafile.py", line 121, in _safe_cast
    return bool(int(val))
TypeError: int() argument must be a string or a number, not 'ASFUnicodeAttribute'

```

I've seen this crash happen several times, and if I re-run the import, it does get further before it crashes again.

A little detective work shows that `ASFUnicodeAttribute` is apparently [a class](http://www.sourcecodebrowser.com/mutagen/1.14/classmutagen_1_1asf_1_1_a_s_f_unicode_attribute.html) in [mutagen](https://code.google.com/p/mutagen/), but I'm not sure _what_ they're using it for.



Discussion:

Resolving patch:
diff --git a/beets/mediafile.py b/beets/mediafile.py
--- a/beets/mediafile.py
+++ b/beets/mediafile.py
@@ -94,6 +94,9 @@ def _safe_cast(out_type, val):
     returned. out_type should be bool, int, or unicode; otherwise, the
     value is just passed through.
     """
+    if isinstance(val, mutagen.asf.ASFBaseAttribute):
+        val = val.value
+
     if out_type == int:
         if val is None:
             return 0
@@ -116,11 +119,8 @@ def _safe_cast(out_type, val):
             return False
         else:
             try:
-                if isinstance(val, mutagen.asf.ASFBoolAttribute):
-                    return val.value
-                else:
-                    # Should work for strings, bools, ints:
-                    return bool(int(val))
+                # Should work for strings, bools, ints:
+                return bool(int(val))
             except ValueError:
                 return False
 


Test patch:
diff --git a/test/test_mediafile_edge.py b/test/test_mediafile_edge.py
--- a/test/test_mediafile_edge.py
+++ b/test/test_mediafile_edge.py
@@ -17,6 +17,8 @@
 import os
 import shutil
 
+import mutagen
+
 import _common
 from _common import unittest
 import beets.mediafile
@@ -81,6 +83,10 @@ def test_safe_cast_int_string_to_int(self):
     def test_safe_cast_string_to_bool(self):
         self.assertEqual(_sc(bool, 'whatever'), False)
 
+    def test_safe_cast_asfunicodeattribute_to_bool(self):
+        self.assertEqual(_sc(bool, mutagen.asf.ASFUnicodeAttribute('foo')),
+                         False)
+
     def test_safe_cast_intstring_to_bool(self):
         self.assertEqual(_sc(bool, '5'), True)