mirror of
https://github.com/beetbox/beets.git
synced 2025-12-16 05:34:47 +01:00
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:
parent
37da0f4d49
commit
40a965ea18
5 changed files with 58 additions and 5 deletions
|
|
@ -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)
|
||||
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -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')
|
||||
|
|
|
|||
|
|
@ -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:
|
||||
|
|
|
|||
|
|
@ -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__)
|
||||
|
||||
|
|
|
|||
Loading…
Reference in a new issue