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()
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()