summaryrefslogtreecommitdiff
path: root/plugins/AlbumCover.py
blob: 512302e3b4ce233debb0d5f95526d08e805161d7 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
from clPlugin import *
from amazon_cover_fetcher import *
from traceback import print_exc
from thread import start_new_thread

# FETCH MODES
AC_NO_FETCH='0'
AC_FETCH_LOCAL_DIR='1'
AC_FETCH_ALBUM_DIR='2'
AC_FETCH_INTERNET='3'

# DOWNLOAD TO MODES
AC_DL_LOCAL_DIR='0'
AC_DL_ALBUM_DIR='1'

AC_DEFAULT_GFX_EXTS='jpg,jpeg,bmp,gif,png'
AC_DEFAULT_FILES='cover,album'

class wgAlbumCover(QtGui.QWidget):
	" container for the image"
	img=None
	imgLoaded=False
	def __init__(self,parent=None):
		QtGui.QWidget.__init__(self,parent)
		self.img=QtGui.QImage()
		
		monty.addListener('onSongChange', self.onSongChange)
		monty.addListener('onReady', self.onReady)
		monty.addListener('onDisconnect', self.onDisconnect)
		monty.addListener('onStateChange', self.onSongChange)
		
		self.setMinimumSize(64,64)
	
	def mousePressEvent(self, event):
		self.onSongChange(None)
	
	def getIMG(self):
		if self.imgLoaded:
			return self.img
		return None

	def paintEvent(self, event):
		l=min(self.width(),self.height())
		p=QtGui.QPainter(self)
		rect=QtCore.QRectF((self.width()-l)/2,0,l,l)
		p.drawImage(rect,self.img)

	def onSongChange(self, params):
		song=monty.getCurrentSong()
		try:
			song._data['file']
		except:
			self.img.load('')
			self.update()
			return
		start_new_thread(self.fetchCover, (song,))
	
	def fetchCover(self, song):
		# set default cover, in case all else fails!
		self.imgLoaded=False
		self.img.load('gfx/no-cd-cover.png')
		for i in xrange(3):
			src=settings.get('albumcover.fetch%i'%(i), str(i))
			if src==AC_NO_FETCH:
				# if we see a NO_FETCH, we don't do any further actions!
				break
			# (download and) load in self.img from a source!
			if self.fetchCoverSrc(song, src):
				# ACK!
				self.imgLoaded=True
				break
		self.update()
	
	def fetchCoverSrc(self, song, src):
		"""Fetch the album cover for $song from $src."""
		if not src in [AC_FETCH_INTERNET, AC_FETCH_LOCAL_DIR, AC_FETCH_ALBUM_DIR]:
			print "wgAlbumCover::fetchCover - invalid source "+str(src)
			return False
		
		# fetch gfx extensions
		exts=settings.get('albumcover.gfx.ext', AC_DEFAULT_GFX_EXTS).split(',')
		exts=map(lambda ext: ext.strip(), exts)
		
		# fetch cover album titles
		coverTitles=settings.get('albumcover.files', AC_DEFAULT_FILES).split(',')
		coverTitles=map(lambda title: title.strip(), coverTitles)
		
		# song absolute path
		fInfo=QtCore.QFileInfo(song.getFilepath())
		songAbsDir='%s/%s/'%(mpdSettings.get('music_directory'), str(fInfo.path()))
		
		if src==AC_FETCH_INTERNET:
			# look on the internetz!
			try:
				if not song.getArtist() or not song.getAlbum():
					return False
				# get the url from amazon WS
				coverURL=AmazonAlbumImage(song.getArtist(), song.getAlbum()).fetch()
				if not coverURL:
					return False
				# read the url, i.e. retrieve image data
				img=urllib.urlopen(coverURL)
				# where do we save to?
				if settings.get('albumcover.downloadto', AC_DL_LOCAL_DIR)==AC_DL_LOCAL_DIR:
					file='%s/%s.jpg'%(songAbsDir,coverTitles[0])
				elif settings.get('albumcover.downloadto', AC_DL_LOCAL_DIR)==AC_DL_ALBUM_DIR:
					file='%s/%s - %s.jpg'%(settings.get('albumcover.dir'),song.getArtist(),song.getAlbum())
				# open file, and write the read of img!
				f=open(file,'wb')
				f.write(img.read())
				f.close()

				# load image; should work now!
				self.img.load(file)
				return True
			except:
				print_exc()
				return False
		if src==AC_FETCH_LOCAL_DIR:
			# look in local directory
			# create all possible album cover filenames ...
			coverFiles=[]
			for title in coverTitles:
				for ext in exts:
					coverFiles.append('%s.%s'%(title,ext))
			path=songAbsDir
			
			
		elif src==AC_FETCH_ALBUM_DIR:
			# look in album directory
			path=settings.get('albumcover.dir')
			fInfo=QtCore.QFileInfo(path)
			if not fInfo.isDir():
				return False
			coverFiles=[]
			for ext in exts:
				coverFiles.append('%s - %s.%s'%(song.getArtist(),song.getAlbum(),ext))
			# set path

		# now we have to look in $path for the files in $coverFiles!
		for coverFile in coverFiles:
			file='%s/%s'%(path, coverFile)
			if QtCore.QFileInfo(file).exists():
				try:
					self.img.load(file)
					return True
				except:
					print "wgAlbumCover::fetchCover - Failed to load %s"%(file)
		return False

	def onReady(self, params):
		self.onSongChange(None)
		self.update()

	def onDisconnect(self, params):
		self.img.load('')
		self.update()


class pluginAlbumCover(Plugin):
	o=None
	def __init__(self, winMain):
		Plugin.__init__(self, winMain, 'AlbumCover')
	def _load(self):
		self.o=wgAlbumCover(None)
	def getInfo(self):
		return "Display the album cover of the currently playing album."
	def getExtInfo(self):
		return "Displays the album cover of the currently playing album in a widget.\n" \
				"This album cover can be fetched from various locations:\n" \
				"  local dir: the directory in which the album is located;\n" \
				"  albums dir: a directory containing all album covers. The album covers are named $artist - $album;\n" \
				"  internet: fetch from amazon.com\n\n" \
				"Settings:\n" \
				"  albumcover.fetch$i: what source to fetch from on step $i. If step $i fails, move on to step $i+1. If step0==no fetching, then no cover will be looked for;\n" \
				"  albumcover.dir: location of the directory containing the album cover;\n" \
				"  albumcover.downloadTo: where to download album covers from internet to. The filename will be $artist - $album. If this directory doesn't exist, showing the album cover will fail.\n" \
				"  albumcover.files: comma separated list of filenames (without extension)to be considered an album cover. The extensions from albumcover.gfx.ext are used.\n" \
				"  albumcover.gfx.ext: comma separated list of gfx-file extensions.\n"

	def getWidget(self):
		return self.o

	def _getDockWidget(self):
		return self._createDock(self.o)

	def _getSettings(self):
		ret=[]
		nums=['first', 'second', 'third']
		actions=[QtGui.QComboBox(), QtGui.QComboBox(), QtGui.QComboBox()]
		for i,action in enumerate(actions):
			setting='albumcover.fetch%i'%(i)
			action.addItem("On the %s action, Monty rested."%(nums[i]))
			action.addItem("Local dir")
			action.addItem("Albums dir")
			action.addItem("Internet")
			action.setCurrentIndex(int(settings.get(setting, str(i+1))))
			ret.append([setting, 'Action %i'%(i+1), 'What to do on the %s step.'%(nums[i]), action])

		downloadTo=QtGui.QComboBox()
		downloadTo.addItem("Local dir")
		downloadTo.addItem("Albums dir")
		ret.append(['albumcover.downloadto', 'Download album covers to', 'Specifies where to save album covers fetched from internet to.\nIf Albums dir is selected, and the albums dir is not set properly, album covers are not downloaded, nor shown.', downloadTo])
		ret.append(['albumcover.files', 'Album cover files', 'Comma separated list of titles that are to be considered album covers. E.g. cover,album.', QtGui.QLineEdit(settings.get('albumcover.files', AC_DEFAULT_FILES))])
		ret.append(['albumcover.dir', 'Album directory', 'Directory containing the album covers.\nIf empty, or not existing, album covers won\'t be downloaded or retrieved from this directory.', QtGui.QLineEdit(settings.get('albumcover.dir'))])
		
		return ret			
	
	def afterSaveSettings(self):
		self.o.onSongChange(None)