detect unreadable files that seem to be of the correct type

In the case that Mutagen throws an exception while trying to read a file, we
throw an UnreadableFileError, which is a new superclass for FileTypeError.
This commit is contained in:
Adrian Sampson 2010-07-03 23:44:28 -07:00
parent 37da0f4d49
commit 40a965ea18
5 changed files with 58 additions and 5 deletions

View file

@ -111,6 +111,9 @@ def albums_in_dir(path):
i = library.Item.from_path(os.path.join(root, filename))
except mediafile.FileTypeError:
pass
except mediafile.UnreadableFileError:
#FIXME log an error
pass
else:
items.append(i)

View file

@ -20,7 +20,7 @@ import shutil
import sys
from string import Template
import logging
from beets.mediafile import MediaFile, FileTypeError
from beets.mediafile import MediaFile, UnreadableFileError, FileTypeError
MAX_FILENAME_LENGTH = 200
@ -634,6 +634,8 @@ class BaseLibrary(object):
item = Item.from_path(_normpath(f))
except FileTypeError:
log.warn(f + ' of unknown type, skipping')
except UnreadableFileError:
log.error(f + ' is unreadable, skipping')
self.add(item, copy)

View file

@ -30,16 +30,26 @@ or the empty string).
"""
import mutagen
import mutagen.mp3
import mutagen.flac
import mutagen.monkeysaudio
import datetime
import re
__all__ = ['FileTypeError', 'MediaFile']
# Currently allowed values for type:
# mp3, mp4
class FileTypeError(IOError):
# mp3, mp4, flac, ogg, ape
# Raised for any file MediaFile can't read.
class UnreadableFileError(IOError):
pass
# Raised for files that don't seem to have a type MediaFile supports.
class FileTypeError(UnreadableFileError):
pass
@ -417,10 +427,18 @@ class MediaFile(object):
"""
def __init__(self, path):
"""Constructs a new MediaFile reflecting the file at path. May
throw UnreadableFileError.
"""
unreadable_exc = (
mutagen.mp3.HeaderNotFoundError,
mutagen.flac.FLACNoHeaderError,
mutagen.monkeysaudio.MonkeysAudioHeaderError,
)
try:
self.mgfile = mutagen.File(path)
except mutagen.mp3.HeaderNotFoundError:
raise FileTypeError('Mutagen could not read file')
except unreadable_exc:
raise UnreadableFileError('Mutagen could not read file')
if self.mgfile is None: # Mutagen couldn't guess the type
raise FileTypeError('file type unsupported by Mutagen')

View file

@ -356,6 +356,9 @@ def import_files(lib, paths, copy=True, write=True, autot=True, logpath=None):
item = library.Item.from_path(filepath)
except FileTypeError:
continue
except mediafile.UnreadableFileError:
#FIXME log an error
pass
# Add the item to the library, copying if requested.
if copy:

View file

@ -61,6 +61,33 @@ class EdgeTest(unittest.TestCase):
self.assertEqual(f.disc, 4)
self.assertEqual(f.disctotal, 5)
class SafetyTest(unittest.TestCase):
def _exccheck(self, fn, exc):
fn = os.path.join('rsrc', fn)
open(fn, 'a').close() # create an empty file (a la touch)
self.assertRaises(exc, beets.mediafile.MediaFile, fn)
os.unlink(fn) # delete the temporary file
def test_corrupt_mp3_raises_unreadablefileerror(self):
# Make sure we catch Mutagen reading errors appropriately.
self._exccheck('corrupt.mp3', beets.mediafile.UnreadableFileError)
def test_corrupt_mp4_raises_unreadablefileerror(self):
self._exccheck('corrupt.m4a', beets.mediafile.UnreadableFileError)
def test_corrupt_flac_raises_unreadablefileerror(self):
self._exccheck('corrupt.flac', beets.mediafile.UnreadableFileError)
def test_corrupt_ogg_raises_unreadablefileerror(self):
self._exccheck('corrupt.ogg', beets.mediafile.UnreadableFileError)
def test_corrupt_monkeys_raises_unreadablefileerror(self):
self._exccheck('corrupt.ape', beets.mediafile.UnreadableFileError)
def test_invalid_extension_raises_filetypeerror(self):
self._exccheck('something.unknown', beets.mediafile.FileTypeError)
def suite():
return unittest.TestLoader().loadTestsFromName(__name__)