Created
April 22, 2013 23:18
-
-
Save felipeochoa/5439424 to your computer and use it in GitHub Desktop.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#!/usr/bin/env python3 | |
""" | |
Used to fetch cover art. Based heavily on obeythepenguin's | |
`Cover Fetcher' (http://coverfetcher.sourceforge.net/) | |
obeythepenguin AT users.sourceforge.net, but attempting to | |
provide a CLI interface. | |
""" | |
import argparse | |
import urllib.request | |
import urllib.parse | |
import xml.etree.ElementTree as etree | |
import pdb | |
BASE_URL = ("http://ws.audioscrobbler.com/2.0/?" | |
"method=album.getinfo" | |
"&api_key=XXXXXX") # Need to input key! | |
class CoverError(Exception): | |
"""Base class for the errors in this module.""" | |
pass | |
class CommunicationError(CoverError): | |
""" | |
Raised when there's a communication failure with LastFM. | |
""" | |
def __init__(self, reason): | |
self.reason = reason | |
class ResourceError(CoverError): | |
""" | |
Raised when the artwork is not on the server. | |
""" | |
def __init__(self, album, artist): | |
self.album = album | |
self.artist = artist | |
class AlbumError(ResourceError): | |
"""Raised when the album is not found on the server.""" | |
class ArtError(ResourceError): | |
"""Raised when art is not on the server, but the album is.""" | |
def get_xml(album, artist): | |
"""Get the album xml data (as a file-like object).""" | |
target = BASE_URL | |
target += "&album=" +urllib.parse.quote(album) | |
target += "&artist=" +urllib.parse.quote(artist) | |
# URLError can be raised by following line | |
return urllib.request.urlopen(target) | |
def get_url(xml, size): | |
"""Get the url with the location of the artwork.""" | |
# Based on Sam Wirch's post | |
# www.samwirch.com/blog/parsing-xml-data-lists-python-3 | |
tree = etree.parse(xml) | |
album_node = tree.getroot().find("album") | |
sizes = ['extralarge', 'large', 'medium', 'small'] | |
sizes.remove(size) | |
sizes = [size] + sizes | |
for s in sizes: | |
for child in album_node.findall('image'): | |
if s == child.get('size'): | |
if child.text is not None: | |
return child.text | |
return None | |
def get_picture(album, artist, size): | |
""" | |
Retrieve the cover art. | |
Size is one of 'small', 'medium', 'large', or 'extralarge', | |
determined by LastFM. | |
Returns the picture as a readable file-like object. | |
""" | |
try: | |
xml = get_xml(album, artist) | |
except urllib.request.HTTPError as e: | |
if e.code == 400: | |
raise AlbumError(album, artist) | |
else: | |
raise CommunicationError(e.code) | |
except urllib.request.URLError as e: | |
raise CommunicationError(e.reason) | |
location = get_url(xml, size) | |
if location is None: | |
raise ArtError(album, artist) | |
try: | |
return urllib.request.urlopen(location) | |
except urllib.request.HTTPError as e: | |
raise CommunicationError(e.code) | |
except urllib.request.URLError as e: | |
raise CommunicationError(e.reason) | |
def parse_args(): | |
"""Parse the command line args.""" | |
usage = """ | |
This is the CLI-Cover-Fetcher. Use it like this: | |
python coverfetcher.py [options] <artist> <album> | |
The result will be saved as <artist>_<album>.jpg (with spaces | |
replaced by dashes. | |
""" | |
parser = argparse.ArgumentParser(usage) | |
help = "The name of the artist." | |
parser.add_argument("artist", help=help) | |
help = "The name of the album." | |
parser.add_argument("album", help=help) | |
help = "Override the default file location." | |
parser.add_argument("-t", "--target", help=help, | |
metavar='f') | |
help = ("One of 'small', 'medium', 'large', or 'extralarge'." | |
"(Default 'extralarge')") | |
parser.add_argument("-s", "--size", help=help, | |
default='extralarge') | |
args = parser.parse_args() | |
return args | |
def main(): | |
args = parse_args() | |
if args.target is None: | |
args.target = args.artist + '_' + args.album | |
args.target = args.target.replace(' ','-') | |
args.target += '.png' | |
try: | |
picture = get_picture(args.album, args.artist, args.size) | |
picture = picture.read() | |
except ArtError as e: | |
from sys import stderr | |
stderr.write("LastFM has no artwork for {0.album} by " | |
"{0.artist}! (The album is there though)\n".format( | |
args)) | |
return False | |
except AlbumError as e: | |
from sys import stderr | |
stderr.write("{0.album} by {0.artist} is not " | |
"on the LastFM server!\n".format(args)) | |
return False | |
except CommunicationError: | |
from sys import stderr | |
stderr.write("I couldn't communicate with the LastFM " | |
"server!\n") | |
return False | |
with open(args.target, 'wb') as f: | |
f.write(picture) | |
return True | |
if __name__ == "__main__": | |
main() |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment