Beispiel #1
0
class Gusic(object):
	def __init__(self):
		self.logBuilder = GoogleMusic_log.Build(self,None)
		self.logBuilder.get_object('window_log').connect('delete-event', lambda w, e: w.hide() or True)
		self.log_scroll = True
		logging._handlers.ListStoreLoggingHandler = ListStoreLoggingHandler
		log.addHandler(logging._handlers.ListStoreLoggingHandler(self.logBuilder.get_object('liststore_log')))
		utils.log = log
		log.debug("loading main window builder")
		self.mainBuilder = GoogleMusic_main.Build(self,None)
		self.main = self.mainBuilder.get_object('window1')
		self.main.set_wmclass ("Gusic", "Gusic")
		self.main.set_title('Gusic')
		self.aboutBuilder = GoogleMusic_about.Build(self,None)
		self.aboutBuilder.get_object('aboutdialog1').set_version(__version__)
		self.keyring = keyring()
		self.api = gMusicApi()
		self.song = {
			"duration": [],
			"GtkSource": []
		}
		self.playmode = []
		self.Library = {}
		log.debug('loading GStreamer')
		self.gst = GStreamer()
		self.gst.set_playback()
		self.obj_song_progress = self.mainBuilder.get_object('song_progress')
		self.label_song_time = self.mainBuilder.get_object('label_song_time')
		self.toolbutton_play = self.mainBuilder.get_object('toolbutton_play')
		self.image_playpause = self.mainBuilder.get_object('image_playpause')

		self.notifier = Notifier()
		self.Playlists = Playlists()
		log.debug('Registering Bus events')
		self.Bus = Bus()
		self.Bus.registerEvent("on-start-playing")
		self.Bus.registerEvent("on-pause")
		self.Bus.registerEvent("on-login")
		self.Bus.registerEvent("on-update-library")
		self.Bus.registerEvent("on-song-ended")
		log.debug('connecting self._playNext to bus event "on-song-ended"')
		self.Bus.connect("on-song-ended",self._playNext)
		self.Cache = Cache()
		self.treeview_media_view = self.mainBuilder.get_object('treeview_media_view')
		self.treeview_media_view.set_cursor(0)
		self.liststore_media = self.mainBuilder.get_object('liststore_media')
		self.treestore_media = self.mainBuilder.get_object('treestore_media')
		#TODO: set Style properties (DONE)
		self.mainBuilder.get_object('treeview_media_view').set_name('treeview_media_view')
		self.GtkScreen = Gdk.Screen.get_default()
		self.style_context = Gtk.StyleContext()
		self.css_provider = Gtk.CssProvider()
		self.css_provider.load_from_path('lib/core/styles.css')
		self.style_context.add_provider_for_screen(self.GtkScreen,self.css_provider,Gtk.STYLE_PROVIDER_PRIORITY_APPLICATION)


		if self.keyring.haveLoginDetails():
			log.info("Got login details in keyring. Loading Gusic")
			self.startGusic()
		else:

			log.info("Haven't got any login details. Asking nicely for some")
			self.loginBuilder = GoogleMusic_dialog_login.Build(self,None)
			self.loginDialog = self.loginBuilder.get_object('window_login')
			self.loginDialog.set_wmclass ("Gusic", "Gusic")
			self.loginDialog.set_title('Gusic')
			self.image_logo = self.loginBuilder.get_object('image_logo')
			self.image_logo.set_from_file('imgs/Gusic_logo-256.png')
			self.loginDialog.show_all()

	def startGusic(self,fromLogin=False):
		self.main.show_all()
		if fromLogin:
			self.loginDialog.hide()
	def isLoggedIn(self):
		while self.loggedIn == False:
			time.sleep(0.2)
		return True
	def fetchMusicLibrary(self,status,other):
		log.info("loading fist api call: self.api.get_all_songs()")
		get_all_songs = self.api.get_all_songs(True)
		self.Library['songs'] = []
		for chunk in get_all_songs:
		 	for song in chunk:
		 		self.Library['songs'].append(song)
		 	status.set_text('Downloading music information ... (' + str(len(self.Library['songs'])) + ' songs)')
		
		self.liststore_all_songs = self.mainBuilder.get_object('liststore_all_songs')
		self.treeview_main_song_view = self.mainBuilder.get_object('treeview_main_song_view')
		log.info('removing model from treeview_main_song_view')
		self.treeview_main_song_view.set_model(None)
		songAdd = 0
		albumArtUrls = []
		log.info('storing song info into self.liststore_all_songs')
		status.set_text('Saving music information into database ... (1/2)')
		for song in self.Library['songs']:
			if not 'albumArtUrl' in song:
				song['albumArtUrl'] = 'null'
			else:
				albumArtUrls.append('http:' + song['albumArtUrl'])
			if not 'disc' in song:
				song['disc'] = 0
			if not 'track' in song:
				song['track'] = 0
			if not 'totalTracks' in song:
				song['totalTracks'] = 0
			self.liststore_all_songs.append([song['type'],song['title'],str(song['lastPlayed']),song['album'],song['artist'],song['id'],song['disc'],song['track'],song['totalTracks'],song['genre'],song['url'],song['albumArtUrl'],song['durationMillis']])
		log.info('setting treeview_main_song_view model to self.liststore_all_songs')
		self.treeview_main_song_view.set_model(self.liststore_all_songs)
		self.mainBuilder.get_object('treeviewcolumn_title').set_sort_column_id(1)
		self.mainBuilder.get_object('treeviewcolumn_artist').set_sort_column_id(4)
		self.mainBuilder.get_object('treeviewcolumn_album').set_sort_column_id(3)
		self.treeview_main_song_view.set_cursor(0)
		status.set_text('Saving music information into database ... (2/2)')
		self.searchCompletion = SearchCompletion(self.liststore_all_songs)
		self.searchField = self.mainBuilder.get_object('entry_search_field')
		Completion = Gtk.EntryCompletion()
		Completion.set_model(self.searchCompletion.get_matchStore())
		#TODO: Multi column completion (songs, albums and artists) [DONE]
		
		cell = Gtk.CellRendererPixbuf()
		Completion.pack_end(cell,True)
		Completion.add_attribute(cell,'pixbuf',3)
		self.searchField.set_completion(Completion)
		Completion.set_text_column(1)
		Completion.connect('match-selected',self.completion_action_match_selected)
	def fetchPlaylistLibrary(self):
		log.info('fetching all playlists')
		self.Library['playlists'] = self.api.get_all_playlist_ids(auto=True,user=True)
		log.info('setting main tree items')
		parent_media = self.treestore_media.append(None,['sys-all','All Media','sys-all',900])
		parent_searches = self.treestore_media.append(parent_media,['self-gen-pl','Searches','self-gen-pl',700])
		self.search_playlists = parent_searches
		parent_playlists = self.treestore_media.append(parent_media,['sys-pl','Playlists','sys',700])
		parent_auto_pl = self.treestore_media.append(parent_playlists,['sys-pl-auto','Auto playlists','sys-pl-auto',500])
		parent_user_pl = self.treestore_media.append(parent_playlists,['sys-pl-user','Your playlists','sys-pl-user',500])
		log.info('setting dynamic fetched playlists')
		for pl in self.Library['playlists']['auto'].keys():
			if type(self.Library['playlists']['auto'][pl]) is list:
				for pl_ in self.Library['playlists']['auto'][pl]:
					log.debug('appending auto-playlist:%s id: %s',pl,pl_)
					self.treestore_media.append(parent_auto_pl,[pl,pl_,'gen'])
			else:
				log.debug('appending auto-playlist:%s id: %s',pl,self.Library['playlists']['auto'][pl])
				self.treestore_media.append(parent_auto_pl,[self.Library['playlists']['auto'][pl],pl,'sys-pl-auto-gen',400])
		for pl in self.Library['playlists']['user'].keys():
			if type(self.Library['playlists']['user'][pl]) is list:
				for pl_ in self.Library['playlists']['user'][pl]:
					log.debug('appending user-playlist:%s id: %s',pl,pl_)
					self.treestore_media.append(parent_user_pl,[pl_,pl,'gen',400])
			else:
				log.debug('appending auto-playlist:%s id: %s',pl,self.Library['playlists']['user'][pl])
				self.treestore_media.append(parent_user_pl,[self.Library['playlists']['user'][pl],pl,'sys-pl-user-gen',400])
		log.info('setting treeview_media_view model to self.treestore_media')
		self.treeview_media_view.set_model(self.treestore_media)
		self.treeview_media_view.expand_all()
		self.treeview_media_view.set_cursor(0)
		return True
	def viewPlaylist(self,Plid,name,Local=False):
		log.info('request for %s with id %s',name,Plid)
		if Local:
			log.info('Local Playlist')
			self.treeview_main_song_view.set_model(self.Playlists.getPlaylist(Plid).getModel())
		else:
			if self.Playlists.playlistExists(Plid):
				log.info('%s exists, setting treeview_main_song_view to playlist model',Plid)
				self.treeview_main_song_view.set_model(self.Playlists.getPlaylist(Plid).getModel())
			else:		
				log.info("%s doesn't exists. Fetching playlist and store in self.Playlists as a Playlist class",Plid)
				playlist = Playlist(self.api.get_playlist_songs(Plid),Plid,name)
				self.Playlists.addPlaylist(playlist)
				log.info('setting treeview_main_song_view model to playlist %s model',Plid)
				self.treeview_main_song_view.set_model(self.Playlists.getPlaylist(Plid).getModel())
		return True
	def completion_action_match_selected(self,completion,model,tree_iter):

		log.info('selected %s (%s,id=%s) from completion',model[tree_iter][1],model[tree_iter][0],model[tree_iter][2])

		if model[tree_iter][0] == 'song':
			self.select_playlist_from_id('sys-all')
			self.load_playlist_into_main_view('sys-all')
			songIter = self.get_song_from_id(model[tree_iter][2],playIt=True)
			#self.treeview_main_song_view.set_cursor(model[tree_iter][3])
		elif model[tree_iter][0] == 'album':
			#Creating a new playlist of al songs that has the album name
			song_list = []		
			item = self.liststore_all_songs.get_iter_first()
			while (item != None):
				if model[tree_iter][1] == self.liststore_all_songs.get_value(item,3):
					for song in self.Library['songs']:
						if song['id'] == self.liststore_all_songs.get_value(item,5):
							song_list.append(song)
				item = self.liststore_all_songs.iter_next(item)
			playlist = Playlist(song_list,"search-" + model[tree_iter][1],model[tree_iter][1])
			self.Playlists.addPlaylist(playlist)
			media_iter = self.treestore_media.append(self.search_playlists,["search-" + model[tree_iter][1],model[tree_iter][1],'search',400])
			self.treeview_media_view.expand_all()
			media_selection = self.treeview_media_view.get_selection()
			media_selection.select_iter(media_iter)
			self.load_playlist_into_main_view(self.treeview_media_view)

		elif model[tree_iter][0] == 'artist':
			#Creating a new playlist of al songs that has the album name
			song_list = []		
			item = self.liststore_all_songs.get_iter_first()
			while (item != None):
				if model[tree_iter][1] == self.liststore_all_songs.get_value(item,4):
					for song in self.Library['songs']:
						if song['id'] == self.liststore_all_songs.get_value(item,5):
							song_list.append(song)
				item = self.liststore_all_songs.iter_next(item)
			playlist = Playlist(song_list,"search-" + model[tree_iter][1],model[tree_iter][1])
			self.Playlists.addPlaylist(playlist)
			media_iter = self.treestore_media.append(self.search_playlists,["search-" + model[tree_iter][1],model[tree_iter][1],'search',400])
			self.treeview_media_view.expand_all()
			media_selection = self.treeview_media_view.get_selection()
			media_selection.select_iter(media_iter)
			self.load_playlist_into_main_view(self.treeview_media_view)
	def search_all(self,text):
			song_list = []
			id_list = []
			item = self.liststore_all_songs.get_iter_first()
			while (item != None):
				# Title
				if text.lower() in self.liststore_all_songs.get_value(item,1).lower():
					for song in self.Library['songs']:
						if song['id'] == self.liststore_all_songs.get_value(item,5) and song['id'] not in id_list:
							song_list.append(song)
							id_list.append(song['id'])

				# Album
				if text.lower() in self.liststore_all_songs.get_value(item,3).lower():
					for song in self.Library['songs']:
						if song['id'] == self.liststore_all_songs.get_value(item,5) and song['id'] not in id_list:
							song_list.append(song)
							id_list.append(song['id'])

				# Artist
				if text.lower() in self.liststore_all_songs.get_value(item,4).lower():
					for song in self.Library['songs']:
						if song['id'] == self.liststore_all_songs.get_value(item,5) and song['id'] not in id_list:
							song_list.append(song)
							id_list.append(song['id'])

				item = self.liststore_all_songs.iter_next(item)
			playlist = Playlist(song_list,"search-" + text,text)
			self.Playlists.addPlaylist(playlist)
			media_iter = self.treestore_media.append(self.search_playlists,["search-" + text,text,'search',400])
			self.treeview_media_view.expand_all()
			media_selection = self.treeview_media_view.get_selection()
			media_selection.select_iter(media_iter)
			self.load_playlist_into_main_view(self.treeview_media_view)
	def get_song_from_id(self,songId,playIt):
		item = self.liststore_all_songs.get_iter_first()
		while (item != None):
			
			if self.liststore_all_songs.get_value(item,5) == songId:

				print item
				tree_selection = self.treeview_main_song_view.get_selection()
				tree_selection.select_iter(item)
				(model,pathlist) = tree_selection.get_selected_rows()
				self.treeview_main_song_view.scroll_to_cell(pathlist[0])

				if playIt:
					self._playIter(model,item)
				return item

			item = self.liststore_all_songs.iter_next(item)
	def select_playlist_from_id(self,playlistId):
		item = self.liststore_media.get_iter_first()
		while (item != None):
			if self.liststore_media.get_value(item,2) == playlistId:
				tree_selection = self.treeview_media_view.get_selection()
				tree_selection.select_iter(item)
				item = None
			item = self.liststore_media.iter_next(item)
	def load_playlist_into_main_view(self,treeview):
		log.info("Treeview type is %s",str(type(treeview)))
		if type(treeview) is None:
			return False
		elif type(treeview) is str:
			rowType = treeview
		else:
			tree_selection = treeview.get_selection()
			(model,pathlist) = tree_selection.get_selected_rows()
			if len(pathlist) == 0:
				log.info("Nothing selected")
				return False

			tree_iter = model.get_iter(pathlist[0])
			log.debug("treeview pathlist: %s", str(pathlist))
			rowType = model.get_value(tree_iter,2)
		log.debug("rowType: %s",rowType)
		if rowType == 'sys-all':
			self.treeview_main_song_view.set_model(self.liststore_all_songs)
		elif rowType == "sys-pl-auto-gen" or rowType == "sys-pl-user-gen" or rowType == "gen" or rowType == "search":
			ShowPl = threading.Thread(target=self.viewPlaylist,args=(model.get_value(tree_iter,0),model.get_value(tree_iter,1)))
			ShowPl.start()
			while ShowPl.isAlive():
			 	while Gtk.events_pending():
			 		Gtk.main_iteration()
	def toggle_playmode(self,mode):
		if mode in self.playmode:
			self.playmode.remove(mode)
			log.info('disabled playmode %s',mode)
		else:
			self.playmode.append(mode)
			log.info('enabled playmode %s',mode)

	def set_song_title(self,title):
		label = self.mainBuilder.get_object("label_song_title")
		label.set_text(title)
	def set_song_artist(self,artist):
		label = self.mainBuilder.get_object("label_song_details")
		label.set_text(artist)
	def start_checkProgress(self,model,tree_iter):
		duration = model.get_value(tree_iter,12) / 1000
		pretty_duration = str(duration / 60) + ":" + "%.2d" % (duration % 60)
		self.obj_song_progress.set_range(0,duration)
		self.song["duration"] = [duration,pretty_duration]
		self.song['GtkSource'] = [model,tree_iter]
		gobject.timeout_add(250,self._checkProgress)
	def _checkProgress(self):
		if self.gst.nowplaying is not None and self.gst.status is self.gst.PLAYING:
			if self.image_playpause.get_stock() != ("gtk-media-pause",6):
				self.Bus.emit('on-start-playing')
				self.image_playpause.set_from_stock("gtk-media-pause",6)
			position = self.gst.getposition() / gst.SECOND
			self.obj_song_progress.set_value(position)
			pretty_position = str(position / 60) + ":" + "%.2d" % (position % 60)
			self.label_song_time.set_text(pretty_position)
			return True
		elif self.gst.nowplaying is not None and self.gst.status is self.gst.PAUSED:
			if self.image_playpause.get_stock() != ("gtk-media-play",6):
				self.Bus.emit('on-pause')
				self.image_playpause.set_from_stock("gtk-media-play",6)
		elif self.gst.status is self.gst.NULL:
			self.image_playpause.set_from_stock("gtk-media-play",6)
			self.Bus.emit("on-song-ended")
			self.obj_song_progress.set_value(0)
			self.label_song_time.set_text("00:00")
			return False
	def _playIter(self,model,tree_iter):
			songId = model.get_value(tree_iter,5)
			songTitle = model.get_value(tree_iter,1)
			songArtist = model.get_value(tree_iter,4)
			songAlbum = model.get_value(tree_iter,3)
			log.info('playrequest for %s(%s)',songTitle,songId)
			try:
			 	songUrl = self.api.get_stream_url(songId)
			 	log.info('streaming url: <%s>',songUrl)
			except urllib2.HTTPError:
				log.exception("Exception while retreaving stream url")
				self.Error(title="Error retrieving stream",body="Gusic was unable to retrieve the streaming url. This likely means that you've exceeded your streaming limit. (Ouch!)")
				return False
			self.set_song_title(songTitle)
			self.set_song_artist(songArtist)
			self.treeview_main_song_view.set_cursor(model.get_path(tree_iter))
			log.info('starting play thread')
			play = threading.Thread(target=self.gst.playpause,args=(songUrl,None))
			play.start()
			self.obj_song_progress.set_sensitive(True)
			imgUrl = 'http:' + model.get_value(tree_iter,11)
			log.debug('album art url: <%s>',imgUrl)
			if imgUrl != 'http:null':
				# Setting size of album art to 400
				imgUrl = imgUrl.replace('s130','s400')
				threading.Thread(target=tools.setImageFromCache,args=(self.mainBuilder.get_object("image_toolbar_art"),imgUrl,self.Cache,[50,50])).start()
				threading.Thread(target=tools.setImageFromCache,args=(self.mainBuilder.get_object("image_art"),imgUrl,self.Cache,[200,200])).start()
			else:
				imgUrl = None
				self.mainBuilder.get_object("image_toolbar_art").set_from_file("imgs/Gusic_logo-32.png")
				self.mainBuilder.get_object("image_art").set_from_file("imgs/Gusic_logo-128.png")
			self.start_checkProgress(model,tree_iter)
			self.notifier._new_notif(songTitle + ' - ' + songArtist, songAlbum, self.Cache.getImageFromCache(imgUrl))
	def _playPrev(self):
		if self.gst.nowplaying is not None and self.gst.status is not self.gst.NULL:
			if self.gst.status is self.gst.PAUSED or self.gst.status is self.gst.PLAYING:
				if int(self.obj_song_progress.get_value()) < 3:
					tree_selection = self.treeview_main_song_view.get_selection()
					(model, pathlist) = tree_selection.get_selected_rows()
					tree_iter = model.get_iter(pathlist[0])
					prev_iter = tools.iter_prev(tree_iter,model)
					self._playIter(model,prev_iter)
				else:
					self.gst.seek(0)
	def _playNext(self):
		self.gst.playpause(None)
		tree_selection = self.treeview_main_song_view.get_selection()
		(model, pathlist) = tree_selection.get_selected_rows()
		tree_iter = model.get_iter(pathlist[0])
		next_iter = model.iter_next(tree_iter)
		if next_iter != None:
			if 'loop' in self.playmode:
				next_iter = model.get_iter_first()
			elif 'loop-one' in self.playmode:
				next_iter = tree_iter
			elif 'shuffle' in self.playmode:
				total_songs = model.iter_n_children( None )
				total_songs = total_songs - 1
				next_iter = model.iter_nth_child(None,randrange(0,total_songs))
			self._playIter(model,next_iter)
	def Error(self,title,body):
		dialog = Gtk.MessageDialog(parent=self.main,flags=Gtk.DialogFlags.MODAL,type=Gtk.MessageType.ERROR,buttons=Gtk.ButtonsType.CANCEL,message_format=title)
		dialog.format_secondary_text(body)
		dialog.run()
		dialog.destroy()