From 846b85556df9e172dce211836976949fdb1736b1 Mon Sep 17 00:00:00 2001 From: Adrian Sampson Date: Fri, 24 Jun 2011 21:24:15 -0700 Subject: [PATCH] algorithm for identifying filesystem album art --- beets/autotag/art.py | 34 +++++++++++++++++++++++++++++++++- test/_common.py | 5 +++++ test/test_art.py | 27 ++++++++++++++++++++++++++- test/test_files.py | 7 ++----- 4 files changed, 66 insertions(+), 7 deletions(-) diff --git a/beets/autotag/art.py b/beets/autotag/art.py index c2f96300d..eaefeeda4 100644 --- a/beets/autotag/art.py +++ b/beets/autotag/art.py @@ -1,5 +1,5 @@ # This file is part of beets. -# Copyright 2010, Adrian Sampson. +# Copyright 2011, Adrian Sampson. # # Permission is hereby granted, free of charge, to any person obtaining # a copy of this software and associated documentation files (the @@ -17,9 +17,13 @@ import urllib import sys import logging +import os from beets.autotag.mb import album_for_id +IMAGE_EXTENSIONS = ['png', 'jpg', 'jpeg'] +COVER_NAMES = ['cover', 'front', 'art', 'album', 'folder'] + # The common logger. log = logging.getLogger('beets') @@ -47,6 +51,34 @@ def art_for_asin(asin): return fn +# Art from the filesystem. + +def art_in_path(path): + """Look for album art files in a specified directory.""" + if not os.path.isdir(path): + return + + # Find all files that look like images in the directory. + images = [] + print path, os.listdir(path) + for fn in os.listdir(path): + for ext in IMAGE_EXTENSIONS: + if fn.lower().endswith('.' + ext): + images.append(fn) + + # Look for "preferred" filenames. + for fn in images: + for name in COVER_NAMES: + if fn.lower().startswith(name): + log.debug('Using well-named art file %s' % fn) + return os.path.join(path, fn) + + # Fall back to any image in the folder. + if images: + log.debug('Using fallback art file %s' % images[0]) + return os.path.join(path, images[0]) + + # Main interface. def art_for_album(album): diff --git a/test/_common.py b/test/_common.py index d7bafdf1b..4905ebc04 100644 --- a/test/_common.py +++ b/test/_common.py @@ -187,3 +187,8 @@ class ExtraAsserts(object): def assertNotExists(self, path): self.assertFalse(os.path.exists(path), 'file exists: %s' % path) + +# Utility. + +def touch(path): + open(path, 'a').close() diff --git a/test/test_art.py b/test/test_art.py index f9c13fffd..bcf0ee297 100644 --- a/test/test_art.py +++ b/test/test_art.py @@ -1,5 +1,5 @@ # This file is part of beets. -# Copyright 2010, Adrian Sampson. +# Copyright 2011, Adrian Sampson. # # Permission is hereby granted, free of charge, to any person obtaining # a copy of this software and associated documentation files (the @@ -18,6 +18,8 @@ import unittest import _common from beets.autotag import art +import os +import shutil class MockHeaders(object): def __init__(self, typeval): @@ -53,6 +55,29 @@ class AmazonArtTest(unittest.TestCase): artpath = art.art_for_album(album) self.assertEqual(artpath, None) +class FSArtTest(unittest.TestCase): + def setUp(self): + self.dpath = os.path.join(_common.RSRC, 'arttest') + os.mkdir(self.dpath) + def tearDown(self): + shutil.rmtree(self.dpath) + + def test_finds_jpg_in_directory(self): + _common.touch(os.path.join(self.dpath, 'a.jpg')) + fn = art.art_in_path(self.dpath) + self.assertEqual(fn, os.path.join(self.dpath, 'a.jpg')) + + def test_appropriately_named_file_takes_precedence(self): + _common.touch(os.path.join(self.dpath, 'a.jpg')) + _common.touch(os.path.join(self.dpath, 'cover.jpg')) + fn = art.art_in_path(self.dpath) + self.assertEqual(fn, os.path.join(self.dpath, 'cover.jpg')) + + def test_non_image_file_not_identified(self): + _common.touch(os.path.join(self.dpath, 'a.txt')) + fn = art.art_in_path(self.dpath) + self.assertEqual(fn, None) + def suite(): return unittest.TestLoader().loadTestsFromName(__name__) diff --git a/test/test_files.py b/test/test_files.py index 9b75f9d6f..b534721aa 100644 --- a/test/test_files.py +++ b/test/test_files.py @@ -1,5 +1,5 @@ # This file is part of beets. -# Copyright 2010, Adrian Sampson. +# Copyright 2011, Adrian Sampson. # # Permission is hereby granted, free of charge, to any person obtaining # a copy of this software and associated documentation files (the @@ -22,13 +22,10 @@ import stat from os.path import join import _common -from _common import item +from _common import item, touch import beets.library from beets import util -def touch(path): - open(path, 'a').close() - class MoveTest(unittest.TestCase): def setUp(self): # make a temporary file