# This file is part of beets.# Copyright 2013, Adrian Sampson.## Permission is hereby granted, free of charge, to any person obtaining# a copy of this software and associated documentation files (the# "Software"), to deal in the Software without restriction, including# without limitation the rights to use, copy, modify, merge, publish,# distribute, sublicense, and/or sell copies of the Software, and to# permit persons to whom the Software is furnished to do so, subject to# the following conditions:## The above copyright notice and this permission notice shall be# included in all copies or substantial portions of the Software."""Allows beets to embed album art into file metadata."""importloggingimportimghdrfrombeets.pluginsimportBeetsPluginfrombeetsimportmediafilefrombeetsimportuifrombeets.uiimportdecargsfrombeets.utilimportsyspath,normpathfrombeets.util.artresizerimportArtResizerfrombeetsimportconfiglog=logging.getLogger('beets')def_embed(path,items,maxwidth=0):"""Embed an image file, located at `path`, into each item. """ifmaxwidth:path=ArtResizer.shared.resize(maxwidth,syspath(path))data=open(syspath(path),'rb').read()kindstr=imghdr.what(None,data)ifkindstrnotin('jpeg','png'):log.error('A file of type %s is not allowed as coverart.'%kindstr)return# Add art to each file.log.debug('Embedding album art.')foriteminitems:try:f=mediafile.MediaFile(syspath(item.path))exceptmediafile.UnreadableFileErrorasexc:log.warn('Could not embed art in {0}: {1}'.format(repr(item.path),exc))continuef.art=dataf.save()classEmbedCoverArtPlugin(BeetsPlugin):"""Allows albumart to be embedded into the actual files. """def__init__(self):super(EmbedCoverArtPlugin,self).__init__()self.config.add({'maxwidth':0,'auto':True,})ifself.config['maxwidth'].get(int)and \
notArtResizer.shared.local:self.config['maxwidth']=0log.warn("embedart: ImageMagick or PIL not found; ""'maxwidth' option ignored")defcommands(self):# Embed command.embed_cmd=ui.Subcommand('embedart',help='embed an image file into file metadata')defembed_func(lib,opts,args):ifnotargs:raiseui.UserError('specify an image file')imagepath=normpath(args.pop(0))embed(lib,imagepath,decargs(args))embed_cmd.func=embed_func# Extract command.extract_cmd=ui.Subcommand('extractart',help='extract an image from file metadata')extract_cmd.parser.add_option('-o',dest='outpath',help='image output file')defextract_func(lib,opts,args):outpath=normpath(opts.outpathor'cover')extract(lib,outpath,decargs(args))extract_cmd.func=extract_func# Clear command.clear_cmd=ui.Subcommand('clearart',help='remove images from file metadata')defclear_func(lib,opts,args):clear(lib,decargs(args))clear_cmd.func=clear_funcreturn[embed_cmd,extract_cmd,clear_cmd]# "embedart" command.defembed(lib,imagepath,query):albums=lib.albums(query)fori_albuminalbums:album=i_albumbreakelse:log.error('No album matches query.')returnlog.info('Embedding album art into %s - %s.'% \
(album.albumartist,album.album))_embed(imagepath,album.items(),config['embedart']['maxwidth'].get(int))# "extractart" command.defextract(lib,outpath,query):items=lib.items(query)fori_iteminitems:item=i_itembreakelse:log.error('No item matches query.')return# Extract the art.mf=mediafile.MediaFile(syspath(item.path))art=mf.artifnotart:log.error('No album art present in %s - %s.'%(item.artist,item.title))return# Add an extension to the filename.ext=imghdr.what(None,h=art)ifnotext:log.error('Unknown image type.')returnoutpath+='.'+extlog.info('Extracting album art from: %s - %s\n''To: %s'% \
(item.artist,item.title,outpath))withopen(syspath(outpath),'wb')asf:f.write(art)# "clearart" command.defclear(lib,query):log.info('Clearing album art from items:')foriteminlib.items(query):log.info(u'%s - %s'%(item.artist,item.title))mf=mediafile.MediaFile(syspath(item.path))mf.art=Nonemf.save()# Automatically embed art into imported albums.@EmbedCoverArtPlugin.listen('album_imported')defalbum_imported(lib,album):ifalbum.artpathandconfig['embedart']['auto']:_embed(album.artpath,album.items(),config['embedart']['maxwidth'].get(int))