diff --git a/data/interfaces/default/config.html b/data/interfaces/default/config.html
index 6db6bf86..f5f9ea78 100644
--- a/data/interfaces/default/config.html
+++ b/data/interfaces/default/config.html
@@ -980,8 +980,8 @@
diff --git a/headphones/albumart.py b/headphones/albumart.py
index 4c2f716b..c35658da 100644
--- a/headphones/albumart.py
+++ b/headphones/albumart.py
@@ -13,11 +13,9 @@
# You should have received a copy of the GNU General Public License
# along with Headphones. If not, see .
-import StringIO
import struct
-from contextlib import closing
from six.moves.urllib.parse import urlencode
-import requests as requests
+from io import BytesIO
import headphones
from headphones import db, request, logger
@@ -39,10 +37,11 @@ def getAlbumArt(albumid):
# Amazon
logger.info("Searching for artwork at Amazon")
myDB = db.DBConnection()
- asin = myDB.action(
- 'SELECT AlbumASIN from albums WHERE AlbumID=?', [albumid]).fetchone()[0]
- if asin:
- artwork_path = 'http://ec1.images-amazon.com/images/P/%s.01.LZZZZZZZ.jpg' % asin
+ dbalbum = myDB.action(
+ 'SELECT ArtistName, AlbumTitle, ReleaseID, AlbumASIN FROM albums WHERE AlbumID=?',
+ [albumid]).fetchone()
+ if dbalbum['AlbumASIN']:
+ artwork_path = 'http://ec1.images-amazon.com/images/P/%s.01.LZZZZZZZ.jpg' % dbalbum['AlbumASIN']
artwork = getartwork(artwork_path)
if artwork:
logger.info("Artwork found at Amazon")
@@ -50,12 +49,7 @@ def getAlbumArt(albumid):
# last.fm
from headphones import lastfm
-
logger.info("Searching for artwork at last.fm")
- myDB = db.DBConnection()
- dbalbum = myDB.action(
- 'SELECT ArtistName, AlbumTitle, ReleaseID FROM albums WHERE AlbumID=?',
- [albumid]).fetchone()
if dbalbum['ReleaseID'] != albumid:
data = lastfm.request_lastfm("album.getinfo", mbid=dbalbum['ReleaseID'])
if not data:
@@ -87,6 +81,94 @@ def getAlbumArt(albumid):
return None, None
+def jpeg(bites):
+ fhandle = BytesIO(bites)
+ try:
+ fhandle.seek(0)
+ size = 2
+ ftype = 0
+ while not 0xc0 <= ftype <= 0xcf:
+ fhandle.seek(size, 1)
+ byte = fhandle.read(1)
+ while ord(byte) == 0xff:
+ byte = fhandle.read(1)
+ ftype = ord(byte)
+ size = struct.unpack('>H', fhandle.read(2))[0] - 2
+ fhandle.seek(1, 1)
+ height, width = struct.unpack('>HH', fhandle.read(4))
+ return width, height
+ except struct.error:
+ return None, None
+ except TypeError:
+ return None, None
+
+
+def png(bites):
+ try:
+ check = struct.unpack('>i', bites[4:8])[0]
+ if check != 0x0d0a1a0a:
+ return None, None
+ return struct.unpack('>ii', bites[16:24])
+ except struct.error:
+ return None, None
+
+
+def get_image_data(bites):
+ type = None
+ width = None
+ height = None
+ if len(bites) < 24:
+ return None, None, None
+
+ peek = bites[0:2]
+ if peek == b'\xff\xd8':
+ width, height = jpeg(bites)
+ type = 'jpg'
+ elif peek == b'\x89P':
+ width, height = png(bites)
+ type = 'png'
+ return type, width, height
+
+
+def getartwork(artwork_path):
+ artwork = bytes()
+ minwidth = int(headphones.CONFIG.ALBUM_ART_MIN_WIDTH)
+ maxwidth = int(headphones.CONFIG.ALBUM_ART_MAX_WIDTH)
+
+ resp = request.request_response(artwork_path, timeout=20, stream=True, whitelist_status_code=404)
+
+ if resp:
+ img_width = None
+ for chunk in resp.iter_content(chunk_size=1024):
+ artwork += chunk
+ if not img_width and (minwidth or maxwidth):
+ img_type, img_width, img_height = get_image_data(artwork)
+ # Check min/max
+ if img_width and (minwidth or maxwidth):
+ if minwidth and img_width < minwidth:
+ logger.info("Artwork is too small. Type: %s. Width: %s. Height: %s",
+ img_type, img_width, img_height)
+ artwork = None
+ break
+ elif maxwidth and img_width > maxwidth:
+ # Downsize using proxy service to max width
+ logger.info("Artwork is greater than the maximum width, downsizing using proxy service")
+ artwork_path = '{0}?{1}'.format('http://images.weserv.nl/', urlencode({
+ 'url': artwork_path.replace('http://', ''),
+ 'w': maxwidth,
+ }))
+ artwork = bytes()
+ r = request.request_response(artwork_path, timeout=20, stream=True, whitelist_status_code=404)
+ if r:
+ for chunk in r.iter_content(chunk_size=1024):
+ artwork += chunk
+ r.close()
+ break
+ resp.close()
+
+ return artwork
+
+
def getCachedArt(albumid):
from headphones import cache
@@ -104,114 +186,4 @@ def getCachedArt(albumid):
return
else:
with open(artwork_path, "r") as fp:
- return fp.read()
-
-
-def getartwork(artwork_path):
-
- artwork = None
- minwidth = headphones.CONFIG.ALBUM_ART_MIN_WIDTH
- maxwidth = headphones.CONFIG.ALBUM_ART_MAX_WIDTH
- useproxy = False
-
- with closing(requests.get(artwork_path, stream=True)) as resp:
-
- # Get 1st block of artwork
- data = resp.iter_content(chunk_size=1024)
- artwork = b''
- for chunk in data:
- artwork += chunk
- if len(artwork) >= 32:
- break
- else:
- artwork = None
-
- # Check image and size
- if artwork:
-
-
- #TODO not working well
- #img_type, img_width, img_height = getImageInfo(artwork)
-
- #if not img_type or minwidth and img_width < minwidth:
- # logger.info("Artwork is not suitable or too small. Type: %s. Width: %s. Height: %s",
- # img_type, img_width, img_height)
- # artwork = None
- #elif maxwidth and img_width > maxwidth:
- # useproxy = True
- #else:
- # Get rest of artwork
- for chunk in data:
- artwork += chunk
-
- # Downsize using proxy service to max width
- # if useproxy:
- # logger.info("Artwork is greater than the maximum width, downsizing using proxy service")
- # artwork_path = '{0}?{1}'.format('http://images.weserv.nl/', urlencode({
- # 'url': artwork_path.replace('http://', ''),
- # 'w': maxwidth,
- # }))
- # artwork = request.request_content(artwork_path, timeout=20)
-
- return artwork
-
-
-def getImageInfo(data):
- data = str(data)
- size = len(data)
- height = -1
- width = -1
- content_type = None
-
- # handle GIFs
- if size >= 10 and data[:6] in ('GIF87a', 'GIF89a'):
- # Check to see if content_type is correct
- content_type = 'image/gif'
- w, h = struct.unpack("= 24 and data.startswith('\211PNG\r\n\032\n') and data[12:16] == 'IHDR':
- content_type = 'image/png'
- w, h = struct.unpack(">LL", data[16:24])
- width = int(w)
- height = int(h)
-
- # Maybe this is for an older PNG version.
- elif size >= 16 and data.startswith('\211PNG\r\n\032\n'):
- # Check to see if we have the right content type
- content_type = 'image/png'
- w, h = struct.unpack(">LL", data[8:16])
- width = int(w)
- height = int(h)
-
- # handle JPEGs
- elif size >= 2 and data.startswith('\377\330'):
- content_type = 'image/jpeg'
- jpeg = StringIO.StringIO(data)
- jpeg.read(2)
- b = jpeg.read(1)
- try:
- while b and ord(b) != 0xDA:
- while ord(b) != 0xFF:
- b = jpeg.read(1)
- while ord(b) == 0xFF:
- b = jpeg.read(1)
- if ord(b) >= 0xC0 and ord(b) <= 0xC3:
- jpeg.read(3)
- h, w = struct.unpack(">HH", jpeg.read(4))
- break
- else:
- jpeg.read(int(struct.unpack(">H", jpeg.read(2))[0]) - 2)
- b = jpeg.read(1)
- width = int(w)
- height = int(h)
- except struct.error:
- pass
- except ValueError:
- pass
-
- return content_type, width, height
+ return fp.read()
\ No newline at end of file
diff --git a/headphones/config.py b/headphones/config.py
index 69f33b58..07b6678f 100644
--- a/headphones/config.py
+++ b/headphones/config.py
@@ -34,8 +34,8 @@ _CONFIG_DEFINITIONS = {
'ADD_ALBUM_ART': (int, 'General', 0),
'ADVANCEDENCODER': (str, 'General', ''),
'ALBUM_ART_FORMAT': (str, 'General', 'folder'),
- 'ALBUM_ART_MIN_WIDTH': (int, 'General', 0),
- 'ALBUM_ART_MAX_WIDTH': (int, 'General', 0),
+ 'ALBUM_ART_MIN_WIDTH': (str, 'General', ''),
+ 'ALBUM_ART_MAX_WIDTH': (str, 'General', ''),
# This is used in importer.py to determine how complete an album needs to
# be - to be considered "downloaded". Percentage from 0-100
'ALBUM_COMPLETION_PCT': (int, 'Advanced', 80),