1
import xbmcgui
2
import xbmc
3
import xbmcaddon
4
import os, sys
5
6
__title__ = "Pandora"
7
__script_id__ = "script.xbmc.pandora"
8
__settings__ = xbmcaddon.Addon(id=__script_id__)
9
__version__ = "1.2.10-git"
10
11
print "PANDORA: Initializing v%s" %__version__
12
print "PANDORA: sys.platform = %s" %sys.platform
13
14
dlg = xbmcgui.DialogProgress()
15
dlg.create( "PANDORA", "Loading Script..." )
16
dlg.update( 0 )
17
18
from libpandora.pandora import Pandora, PandoraError
19
20
from pandagui import PandaGUI
21
from pandaplayer import PandaPlayer
22
23
24
scriptPath = __settings__.getAddonInfo('path')
25
26
dataDir = os.path.join( "special://profile/addon_data/%s/" %__script_id__ )
27
28
#Workaround: open() doesn't translate path correctly on some versions
29
dataDir = xbmc.translatePath( dataDir )
30
31
32
if __settings__.getSetting( "firstrun" ) == "true":
33
	print  "PANDORA: First run, showing settings dialog"
34
	__settings__.openSettings()
35
	__settings__.setSetting( "firstrun", "false" )
36
37
BTN_THUMB_DN = 330
38
BTN_THUMB_UP = 331
39
BTN_THUMBED_DN = 337
40
BTN_THUMBED_UP = 338
41
42
class PandaException( Exception ):
43
	pass
44
45
class Panda:
46
47
	def __init__( self ):
48
		self.gui = None
49
		self.pandora = None
50
		self.playlist = []
51
		self.curStation = ""
52
		self.curSong = None
53
		self.playing = False
54
		self.skip = False
55
		self.die = False
56
		self.settings = __settings__
57
		self.player = None
58
		self.skinName = "Default"
59
		
60
		fmt = int(self.settings.getSetting( "format" ))
61
		fmt = ( "aacplus", "mp3", "mp3-hifi" )[fmt]
62
		try:
63
			self.pandora = Pandora( dataDir, fmt )
64
		except PandoraError, e:
65
			xbmcgui.Dialog().ok( "Pandora", "Error: %s" %e )
66
			self.die = True
67
			return
68
69
		#Proxy settings
70
		if self.settings.getSetting( "proxy_enable" ) == "true":
71
			print "PANDORA: Proxy Enabled"
72
			proxy_info = {
73
				"host" : self.settings.getSetting( "proxy_server" ),
74
				"port" : self.settings.getSetting( "proxy_port" ),
75
				"user" : self.settings.getSetting( "proxy_user" ),
76
				"pass" : self.settings.getSetting( "proxy_pass" )
77
			}
78
			self.pandora.setProxy( proxy_info )
79
80
		self.pandora.sync()
81
		
82
		while not self.auth():
83
			resp = xbmcgui.Dialog().yesno( "Pandora", \
84
					"Failed to authenticate listener.", \
85
					"Check username/password and try again.", \
86
					"Show Settings?" )
87
			if resp:
88
				self.settings.openSettings()
89
			else:
90
				self.quit()
91
				return
92
93
		# Get skin from settings.
94
		# Check if a value is set in the settings. If not then use Default.
95
		if self.settings.getSetting ( "skin" ) != "":
96
			self.skinName = self.settings.getSetting( "skin" )
97
		
98
		self.player = PandaPlayer( panda = self )
99
100
		self.gui = PandaGUI( "script-pandora.xml", scriptPath, self.skinName)
101
		
102
		self.gui.setPanda( self )
103
104
	def auth( self ):
105
		user = self.settings.getSetting( "username" )
106
		pwd = self.settings.getSetting( "password" )
107
		if user == "" or pwd == "":
108
			return False
109
		dlg = xbmcgui.DialogProgress()
110
		dlg.create( "PANDORA", "Logging In..." )
111
		dlg.update( 0 )
112
		ret = self.pandora.authListener( user, pwd )
113
		dlg.close()
114
		return ret
115
116
	def playStation( self, stationId ):
117
		self.curStation = stationId
118
		self.curSong = None
119
		self.playlist = []
120
		self.getMoreSongs()
121
		self.playing = True
122
		self.playNextSong()
123
124
	def getStations( self ):
125
		return self.pandora.getStations()
126
	
127
	def getMoreSongs( self ):
128
		if self.curStation == "":
129
			raise PandaException()
130
		items = []
131
		fragment = self.pandora.getFragment( self.curStation )
132
		for s in fragment:
133
134
			thumbnailArtwork = self.settings.getSetting( "thumbnailArtwork" )
135
			thumbnail = s["artRadio"]
136
			#if thumbnailArtwork == "0":			# Album (lo-res)
137
				# default
138
			if thumbnailArtwork == "1":			# Artist (hi-res)
139
				thumbnail = s["artistArtUrl"]
140
141
			item = xbmcgui.ListItem( s["songTitle"] )
142
			item.setIconImage( thumbnail )
143
			item.setThumbnailImage( thumbnail )
144
			item.setProperty( "Cover", thumbnail )
145
			item.setProperty( "Rating", str(s["rating"] ))
146
			item.setProperty( "MusicId", s["musicId"] )
147
148
			info = { "title"	:	s["songTitle"], \
149
					 "artist"	:	s["artistSummary"], \
150
					 "album"	:	s["albumTitle"], \
151
					 "genre"	:	"".join(s["genre"]), \
152
					 "duration"	:	s["trackLength"], \
153
					}
154
			print "PANDORA: item info = %s" % info
155
			item.setInfo( "music", info )
156
			items.append( ( s["audioURL"], item ) )
157
158
		self.playlist.extend( items )
159
160
	def playNextSong( self ):
161
		if not self.playing:
162
			raise PandaException()
163
		try:
164
			next = self.playlist.pop( 0 )
165
			self.player.playSong( next )
166
			art = next[1].getProperty( "Cover" )
167
			self.gui.setProperty( "AlbumArt", art )
168
			self.curSong = next
169
170
			# FIXIT - This should move elsewhere:
171
			rating = int(next[1].getProperty( "Rating" ))
172
			if rating == 0:			# No rating
173
				self.gui.getControl(BTN_THUMB_DN).setVisible(True)
174
				self.gui.getControl(BTN_THUMBED_DN).setVisible(False)
175
				self.gui.getControl(BTN_THUMB_UP).setVisible(True)
176
				self.gui.getControl(BTN_THUMBED_UP).setVisible(False)
177
			elif rating == -1:		# Hate
178
				self.gui.getControl(BTN_THUMB_DN).setVisible(False)
179
				self.gui.getControl(BTN_THUMBED_DN).setVisible(True)
180
				self.gui.getControl(BTN_THUMB_UP).setVisible(True)
181
				self.gui.getControl(BTN_THUMBED_UP).setVisible(False)
182
			elif rating == 1:			# Love
183
				self.gui.getControl(BTN_THUMB_DN).setVisible(True)
184
				self.gui.getControl(BTN_THUMBED_DN).setVisible(False)
185
				self.gui.getControl(BTN_THUMB_UP).setVisible(False)
186
				self.gui.getControl(BTN_THUMBED_UP).setVisible(True)
187
			else:
188
				print "PANDORA: !!!! Unrecognised rating"
189
190
		except IndexError:
191
			self.curSong = None
192
			self.getMoreSongs()
193
194
		if len( self.playlist ) == 0:
195
			#Out of songs, grab some more while playing
196
			self.getMoreSongs()
197
198
	def skipSong( self ):
199
		self.skip = True
200
		self.player.stop()
201
202
	def addFeedback( self, likeFlag ):
203
		if not self.playing:
204
			raise PandaException()
205
		musicId = self.curSong[1].getProperty( "MusicId" )
206
		self.pandora.addFeedback( self.curStation, musicId, likeFlag )
207
208
	def addTiredSong( self ):
209
		if not self.playing:
210
			raise PandaException()
211
		musicId = self.curSong[1].getProperty( "MusicId" )
212
		self.pandora.addTiredSong( musicId )
213
214
	def main( self ):
215
		if self.die:
216
			return
217
		self.gui.doModal()
218
		self.cleanup()
219
		xbmc.sleep( 500 ) #Wait to make sure everything finishes
220
221
	def stop( self ):
222
		self.playing = False
223
		if self.player and self.player.timer\
224
				and self.player.timer.isAlive():
225
			self.player.timer.stop()
226
227
	def cleanup( self ):
228
		self.skip = False
229
		if self.playing:
230
			self.playing = False
231
			self.player.stop()
232
		del self.gui
233
		del self.player
234
235
	def quit( self ):
236
		if self.player and self.player.timer\
237
				and self.player.timer.isAlive():
238
			self.player.timer.stop()
239
		if self.gui != None:
240
			self.gui.close()
241
		self.die = True
242
243
if __name__ == '__main__':
244
	if __settings__.getSetting( "username" ) == "" or \
245
		__settings__.getSetting( "password" ) == "":
246
		xbmcgui.Dialog().ok( "Pandora", \
247
			"Username and/or password not specified" )
248
		__settings__.setSetting( "firstrun", "true" )
249
	else:
250
		panda = Panda()
251
		dlg.close()
252
		panda.main()