class MusicPlayingPage(PageBase): class zoneListener(ZoneListener): def __init__(self, owner): super().__init__(owner) def on_selected_zone_changed(self): if self.owner.pageInView == True: self.owner.on_Page_Entered_View(None) def on_zone_transport_change_event(self, event): if self.owner.pageInView == True: self.owner.on_zone_transport_change_event(event) def on_zone_render_change_event(self, event): pass def on_zone_queue_update_begin(self): pass def on_zone_queue_update_end(self): pass def on_current_track_update_state(self, trackInfo): self.owner.on_current_track_update_state(trackInfo) def close_play_mode_dialog(self): self.playModeDialog.destroy() self.playModeDialog = None def handlePlayModeResponse(self): response = self.playModeDialog.get_response() self.close_play_mode_dialog() zone = self.topLevel.get_selected_zone() if zone is not None: if response == PlayModeDialog.Choice.PLAY_NORMAL: zone.play_mode('NORMAL') elif response == PlayModeDialog.Choice.PLAY_SHUFFLE: zone.play_mode('SHUFFLE') elif response == PlayModeDialog.Choice.PLAY_REPEAT: zone.play_mode('REPEAT_ALL') elif response == PlayModeDialog.Choice.PLAY_SHUFFLE_REPEAT: zone.play_mode('SHUFFLE_NOREPEAT') elif response == PlayModeDialog.Choice.CROSSFADE: zone.cross_fade(True if self.crossFadeMode == '0' else False) def on_zoneButton_Clicked(self): # Close all open dialogs. if self.playModeDialog is not None: self.close_play_mode_dialog() super().on_zoneButton_Clicked() def on_Page_Entered_View(self, SelectedZone): super().on_Page_Entered_View(SelectedZone) # Update the page when it shows up with # the latest information. if self.selectedZone is not None: self.on_zone_transport_change_event( self.selectedZone.get_current_transport_info()) trackInfo = self.selectedZone.get_current_track_info() self.set_current_track_details(trackInfo) self.set_album_art(trackInfo) print("Music playing view") # get uri and metadata of what's playing media_info = self.selectedZone.sonos.avTransport.GetMediaInfo( [('InstanceID', 0)] ) #this uses SoCo to access the underlying UPNP calls which gets AV data which s different to s.get_current_track_info() #uri = media_info['CurrentURI'] metadata = media_info['CurrentURIMetaData'] # ## later you can play this station by: #s.play_uri(uri=uri, meta=metadata) def on_Page_Exit_View(self): super().on_Page_Exit_View() # Stop all timeouts for label in self.scrollLabels: label.stop() def on_Button_A_Clicked(self): if self.playModeDialog is None: self.playModeDialog = PlayModeDialog(self) self.playModeDialog.set_decorated(False) else: self.handlePlayModeResponse() def on_Button_B_Clicked(self): pass def on_Button_C_Clicked(self): if self.playModeDialog is not None: self.close_play_mode_dialog() self.topLevel.show_queue_page() def on_Return_Button_Clicked(self): if self.playModeDialog is None: self.topLevel.show_page("MusicPage") else: self.close_play_mode_dialog() # The scroll wheel def on_Scroll_Up(self): if self.playModeDialog is not None: self.playModeDialog.on_Scroll_Up() def on_Scroll_Down(self): if self.playModeDialog is not None: self.playModeDialog.on_Scroll_Down() def on_Button_Ok_Clicked(self): if self.playModeDialog is None: self.topLevel.show_page("MusicAlbumArtPage") else: self.handlePlayModeResponse() def set_album_art(self, data): artUri = "" if 'album_art_uri' in data: artUri = data['album_art_uri'] elif 'album_art' in data: artUri = data['album_art'] if artUri != "": self.albumArtUri = self.topLevel.get_selected_zone( ).sonos.music_library.build_album_art_full_uri(artUri) response = requests.get(self.albumArtUri) if response.status_code == 200: im = Image(None) im.SetFromStream(response.content) self.albumArtImage.set_from_pixbuf(im.Scale(128, 128)) else: self.albumArtImage.set_from_pixbuf( imageManager.get_pixbuf('noArt')) def set_current_track_details(self, data): string = "" #GLib.markup_escape_text(data['title']) self.trackNameLabel.set_markup(data['title']) if 'creator' in data: string = data[ 'creator'] # GLib.markup_escape_text(data['creator']) elif 'artist' in data: string = data['artist'] #string = GLib.markup_escape_text(data['artist']) #self.artistsNameLabel.set_markup("<b>" + string + "</b>") self.artistsNameLabel.set_markup(string) #string = GLib.markup_escape_text(data['album']) #self.albumNameLabel.set_markup("<b>" + string + "</b>") self.albumNameLabel.set_markup(data['album']) if 'duration' in data and 'position' in data: self.on_current_track_update_state(data) def on_zone_transport_change_event(self, event): mutex.acquire() try: if hasattr(event, 'variables'): varDict = event.variables else: varDict = event if 'current_play_mode' in varDict: currentPlayMode = varDict['current_play_mode'] if currentPlayMode == 'SHUFFLE_NOREPEAT': self.playModeRepeatImage.clear() self.playModeShuffleImage.set_from_pixbuf( imageManager.get_pixbuf('shuffle')) elif currentPlayMode == 'REPEAT_ALL': self.playModeRepeatImage.set_from_pixbuf( imageManager.get_pixbuf('repeat')) self.playModeShuffleImage.clear() elif currentPlayMode == 'NORMAL': self.playModeRepeatImage.clear() self.playModeShuffleImage.clear() elif currentPlayMode == 'SHUFFLE': # shuffle and repeat self.playModeRepeatImage.set_from_pixbuf( imageManager.get_pixbuf('repeat')) self.playModeShuffleImage.set_from_pixbuf( imageManager.get_pixbuf('suffle')) if 'transport_state' in varDict: xportState = varDict['transport_state'] if xportState == 'PAUSED_PLAYBACK': self.xportStateImage.set_from_pixbuf( imageManager.get_pixbuf('pause')) elif xportState == 'TRANSITIONING': self.xportStateImage.set_from_pixbuf( imageManager.get_pixbuf('transition')) elif xportState == 'PLAYING': self.xportStateImage.set_from_pixbuf( imageManager.get_pixbuf('play')) elif xportState == 'STOPPED': self.xportStateImage.set_from_pixbuf( imageManager.get_pixbuf('stop')) self.trackProgressBar.set_fraction(0.0) self.trackProgressTimeLabel.set_text("--:--/--:--") else: self.xportStateImage.set_from_pixbuf( imageManager.get_pixbuf('shrug')) if 'current_crossfade_mode' in varDict: self.crossFadeMode = varDict['current_crossfade_mode'] if self.crossFadeMode == '1': self.crossFadeImage.set_from_pixbuf( imageManager.get_pixbuf('crossFade')) else: self.crossFadeImage.clear() if 'next_track_meta_data' in varDict: nextTrackMetaData = varDict['next_track_meta_data'] if nextTrackMetaData is not '': nextTrackMetaData = nextTrackMetaData.to_dict() nextTrackTitle = GLib.markup_escape_text( nextTrackMetaData['title']) nextTrackArtist = GLib.markup_escape_text( nextTrackMetaData['creator']) #string = "<b>{0} - {1}</b>" string = "{0} - {1}" self.nextTrackLabel.set_text("Next: ") string = string.format(nextTrackTitle, nextTrackArtist) self.nextTrackNameLabel.set_markup(string) else: self.nextTrackLabel.set_text("") self.nextTrackNameLabel.set_text("") if 'current_track' in varDict and 'number_of_tracks' in varDict: currentTrack = varDict['current_track'] numberOfTracks = varDict['number_of_tracks'] string = "Track [{0}/{1}]" self.trackNumberLabel.set_text( string.format(currentTrack, numberOfTracks)) self.inQueueLabel.set_text("In Queue: ") string = "<b>{0}</b>" self.inQueueCountLabel.set_markup( string.format(numberOfTracks)) else: self.trackNumberLabel.set_text("Track") self.inQueueLabel.set_text("") self.inQueueCountLabel.set_text("") if 'current_track_meta_data' in varDict: currentTrackMetaData = varDict['current_track_meta_data'] if currentTrackMetaData is not '': currentTrackMetaData = currentTrackMetaData.to_dict() self.set_current_track_details(currentTrackMetaData) self.trackProgressBar.show() self.trackProgressTimeLabel.show() if self.topLevel.get_selected_zone() is not None: self.set_album_art(currentTrackMetaData) else: #Display the blank album art image self.albumArtImage.set_from_pixbuf( imageManager.get_pixbuf('noArt')) else: self.trackNameLabel.set_markup("<b>[no music]</b>") self.artistsNameLabel.set_text("") self.albumNameLabel.set_text("") self.albumArtImage.set_from_pixbuf( imageManager.get_pixbuf('noArt')) self.trackProgressBar.hide() self.trackProgressTimeLabel.hide() finally: mutex.release() def on_current_track_update_state(self, trackInfo): mutex.acquire() try: # grab the values from the current track # state and update the gui if isinstance(trackInfo, dict): trackPos = trackInfo['position'].split(':') trackLen = trackInfo['duration'].split(':') try: tpH = int(trackPos[0]) tpM = int(trackPos[1]) tpS = int(trackPos[2]) tlH = int(trackLen[0]) tlM = int(trackLen[1]) tlS = int(trackLen[2]) trackProg = float((tpH * 24) + (tpM * 60) + tpS) trackDur = float((tlH * 24) + (tlM * 60) + tlS) tpos = ((trackPos[0] + ":") if tpH > 0 else "") + trackPos[1] + ":" + trackPos[2] tdur = ((trackLen[0] + ":") if tlH > 0 else "") + trackLen[1] + ":" + trackLen[2] if trackDur > 0.0: self.trackProgressBar.set_fraction(trackProg / trackDur) self.trackProgressTimeLabel.set_text(tpos + "/" + tdur) else: self.trackProgressTimeLabel.set_text("") except ValueError: self.trackProgressTimeLabel.set_text("") finally: mutex.release() def title(self): self.titleLabel = Gtk.Label("Now Playing") return (self.titleLabel) def scrolledWindow(self): topVbox = Gtk.VBox() stateHBox = Gtk.HBox() self.xportStateImage = Gtk.Image() self.xportStateImage.set_from_pixbuf( imageManager.get_image('stop').Scale(16, 16)) stateHBox.pack_start(self.xportStateImage, False, False, 5) xportStateLabel = Gtk.Label() xportStateLabel.set_markup("<span size=\"15000\">Now Playing</span>") xportStateLabel.set_alignment(0.0, 0.5) stateHBox.pack_start(xportStateLabel, True, True, 5) self.crossFadeImage = Gtk.Image() self.crossFadeImage.set_from_pixbuf( imageManager.get_pixbuf('crossFade')) stateHBox.pack_start(self.crossFadeImage, False, False, 5) self.playModeShuffleImage = Gtk.Image() self.playModeShuffleImage.set_from_pixbuf( imageManager.get_pixbuf('shuffle')) stateHBox.pack_start(self.playModeShuffleImage, False, False, 5) self.playModeRepeatImage = Gtk.Image() self.playModeRepeatImage.set_from_pixbuf( imageManager.get_pixbuf('repeat')) stateHBox.pack_start(self.playModeRepeatImage, False, False, 5) topVbox.pack_start(stateHBox, False, False, 0) detailHBox = Gtk.HBox() self.albumArtImage = Gtk.Image() self.albumArtImage.set_from_pixbuf(imageManager.get_pixbuf('noArt')) detailHBox.pack_start(self.albumArtImage, False, False, 5) detailVBox = Gtk.VBox() self.trackNumberLabel = Gtk.Label("Track [x/y]") self.trackNumberLabel.set_alignment(0.0, 0.5) detailVBox.pack_start(self.trackNumberLabel, True, False, 0) mf = "<b>{0}</b>" self.trackNameLabel = ScrollLabel(1) #Gtk.Label() #self.trackNameLabel.set_markup("<span weight=\"bold\">Track Name Goes Here In Bold</span>") self.trackNameLabel.set_markup("Track Name Goes Here In Bold") self.trackNameLabel.set_ellipsize(Pango.EllipsizeMode.END) self.trackNameLabel.set_alignment(0.0, 0.5) self.trackNameLabel.assign_markup(mf) self.scrollLabels.append(self.trackNameLabel) detailVBox.pack_start(self.trackNameLabel, True, False, 0) self.trackProgressBar = Gtk.ProgressBar() detailVBox.pack_start(self.trackProgressBar, True, False, 0) self.trackProgressTimeLabel = Gtk.Label("--:--/--:--") self.trackProgressTimeLabel.set_alignment(1.0, 0.5) detailVBox.pack_start(self.trackProgressTimeLabel, True, False, 0) artistsLabel = Gtk.Label("Artists") artistsLabel.set_alignment(0.0, 0.5) detailVBox.pack_start(artistsLabel, True, False, 0) self.artistsNameLabel = ScrollLabel(1) #Gtk.Label() self.artistsNameLabel.set_markup("Artist Name Goes Here") self.artistsNameLabel.set_ellipsize(Pango.EllipsizeMode.END) self.artistsNameLabel.set_alignment(0.0, 0.5) self.artistsNameLabel.assign_markup(mf) self.scrollLabels.append(self.artistsNameLabel) detailVBox.pack_start(self.artistsNameLabel, True, False, 0) separatorLine = Gtk.Image() separatorLine.set_from_pixbuf(imageManager.get_pixbuf('separator')) detailVBox.pack_start(separatorLine, True, False, 0) albumsLabel = Gtk.Label("Albums") albumsLabel.set_alignment(0.0, 0.5) detailVBox.pack_start(albumsLabel, True, False, 0) self.albumNameLabel = ScrollLabel(1) #Gtk.Label() self.albumNameLabel.set_markup("Album Name Goes Here") self.albumNameLabel.set_ellipsize(Pango.EllipsizeMode.END) self.albumNameLabel.set_alignment(0.0, 0.5) self.albumNameLabel.assign_markup(mf) self.scrollLabels.append(self.albumNameLabel) detailVBox.pack_start(self.albumNameLabel, True, False, 0) detailHBox.pack_start(detailVBox, True, True, 5) topVbox.pack_start(detailHBox, True, True, 2) return (topVbox) def status(self): bottomHBox = Gtk.HBox() self.nextTrackLabel = Gtk.Label("Next: ") bottomHBox.pack_start(self.nextTrackLabel, False, False, 0) self.nextTrackNameLabel = ScrollLabel(1) #Gtk.Label() self.nextTrackNameLabel.set_markup("Track Name - Artist Name") self.nextTrackNameLabel.assign_markup("<b>{0}</b>") self.nextTrackNameLabel.set_max_width_chars(21) self.nextTrackNameLabel.set_ellipsize(Pango.EllipsizeMode.END) self.scrollLabels.append(self.nextTrackNameLabel) bottomHBox.pack_start(self.nextTrackNameLabel, True, True, 0) queueImage = Gtk.Image() queueImage.set_from_pixbuf( imageManager.get_image('queue').Scale(16, 16)) bottomHBox.pack_start(queueImage, False, False, 2) self.inQueueLabel = Gtk.Label("In Queue: ") bottomHBox.pack_start(self.inQueueLabel, False, False, 0) self.inQueueCountLabel = Gtk.Label() self.inQueueCountLabel.set_markup("<b>##</b>") self.inQueueCountLabel.set_ellipsize(Pango.EllipsizeMode.END) bottomHBox.pack_start(self.inQueueCountLabel, False, False, 0) return bottomHBox def footer(self): grid = Gtk.Grid() l = Gtk.Label("Play Mode") l.set_hexpand(True) l.set_size_request(100, -1) grid.add(l) l = Gtk.Label(" ") l.set_hexpand(True) l.set_size_request(100, -1) grid.attach(l, 1, 0, 1, 1) l = Gtk.Label("View Queue") l.set_hexpand(True) l.set_size_request(100, -1) grid.attach(l, 2, 0, 1, 1) return grid def __init__(self, topLevel): self.scrollLabels = [] super().__init__(topLevel) self.crossFadeMode = '0' self.playModeDialog = None self.zlistener = self.zoneListener(self) self.topLevel.add_zone_listener(self.__class__.__name__, self.zlistener)
class MusicAlbumArtPage(PageBase): class zoneListener(ZoneListener): def __init__(self, owner): super().__init__(owner) def on_selected_zone_changed(self): if self.owner.pageInView == True: self.owner.on_Page_Entered_View(None) def on_zone_transport_change_event(self, event): if self.owner.pageInView == True: self.owner.on_zone_transport_change_event(event) def on_zone_render_change_event(self, event): pass def on_zone_queue_update_begin(self): pass def on_zone_queue_update_end(self): pass def on_current_track_update_state(self, trackInfo): pass def on_Page_Entered_View(self, SelectedZone): super().on_Page_Entered_View(SelectedZone) if self.selectedZone is not None: self.on_zone_transport_change_event( self.selectedZone.get_current_transport_info()) self.on_current_track_update_state( self.selectedZone.get_current_track_info()) print("Album art in view") def on_current_track_update_state(self, trackInfo): mutex.acquire() try: if isinstance(trackInfo, dict): self.set_album_art(trackInfo) if trackInfo['artist'] == "" or trackInfo["title"] == "": self.musicLabel.set_markup("[no music]") #self.musicLabel.set_markup("<span size=\"12000\"><b>[no music]</b></span>") else: #music = GLib.markup_escape_text(trackInfo['title'] + " - " + trackInfo['artist']) #self.musicLabel.set_markup("<span size=\"12000\"><b>" + music + "</b></span>") music = (trackInfo['title'] + " - " + trackInfo['artist']) self.musicLabel.set_markup(music) finally: mutex.release() def set_album_art(self, data): artUri = "" if 'album_art_uri' in data: artUri = data['album_art_uri'] elif 'album_art' in data: artUri = data['album_art'] if artUri != "": self.albumArtUri = self.topLevel.get_selected_zone( ).sonos.music_library.build_album_art_full_uri(artUri) response = requests.get(self.albumArtUri) if response.status_code == 200: im = Image(None) im.SetFromStream(response.content) self.albumArtImage.set_from_pixbuf(im.Scale(250, 250)) else: self.albumArtImage.set_from_pixbuf( imageManager.get_image('noArt').Scale(250, 250)) def on_zone_transport_change_event(self, event): mutex.acquire() try: if hasattr(event, 'variables'): varDict = event.variables else: varDict = event if 'current_track_meta_data' in varDict: currentTrackMetaData = varDict['current_track_meta_data'] if currentTrackMetaData is not '': currentTrackMetaData = currentTrackMetaData.to_dict() #music = GLib.markup_escape_text(currentTrackMetaData['title'] + " - " + currentTrackMetaData['creator']) #self.musicLabel.set_markup("<span size=\"12000\"><b>" + music + "</b></span>") music = (currentTrackMetaData['title'] + " - " + currentTrackMetaData['creator']) self.musicLabel.set_markup(music) #if self.topLevel.get_selected_zone() is not None and 'album_art_uri' in currentTrackMetaData: if self.topLevel.get_selected_zone() is not None: self.set_album_art(currentTrackMetaData) else: #self.albumArtImage.set_from_file('./images/NoAlbumArt.jpg') self.albumArtImage.set_from_file( './images/AlbumArtEmpty.jpg') pixbuf = self.albumArtImage.get_pixbuf().scale_simple( 250, 250, GdkPixbuf.InterpType.BILINEAR) self.albumArtImage.set_from_pixbuf(pixbuf) else: #self.musicLabel.set_markup("<span size=\"12000\"><b>[no music]</b></span>") self.musicLabel.set_markup("[no music]") self.albumArtImage.set_from_file( './images/AlbumArtEmpty.jpg') pixbuf = self.albumArtImage.get_pixbuf().scale_simple( 250, 250, GdkPixbuf.InterpType.BILINEAR) self.albumArtImage.set_from_pixbuf(pixbuf) finally: mutex.release() def on_Button_A_Clicked(self): pass def on_Button_B_Clicked(self): pass def on_Button_C_Clicked(self): pass def on_Return_Button_Clicked(self): self.topLevel.show_page("MusicPlayingPage") # The scroll wheel def on_Scroll_Up(self): pass def on_Scroll_Down(self): pass def on_Button_Ok_Clicked(self): self.topLevel.show_page("MusicPlayingPage") def title(self): #self.titleLabel = Gtk.Label("Now Playing (Album Art)") return (Gtk.VBox()) def scrolledWindow(self): vbox = Gtk.VBox() self.albumArtImage = Gtk.Image() self.albumArtImage.set_from_file('./images/AlbumArtEmpty.jpg') pixbuf = self.albumArtImage.get_pixbuf().scale_simple( 250, 250, GdkPixbuf.InterpType.BILINEAR) self.albumArtImage.set_from_pixbuf(pixbuf) self.albumArtImage.show() vbox.pack_start(self.albumArtImage, True, True, 5) self.musicLabel = ScrollLabel(1) #Gtk.Label() music = "[no music]" #self.musicLabel.set_markup("<span size=\"12000\"><b>" + music + "</b></span>") self.musicLabel.assign_markup( "<span size=\"12000\"><b> {0} </b></span>") self.musicLabel.set_markup(music) self.musicLabel.set_max_width_chars(25) self.musicLabel.set_ellipsize(Pango.EllipsizeMode.END) vbox.pack_start(self.musicLabel, False, False, 0) return (vbox) def status(self): pass def footer(self): return Gtk.VBox() def __init__(self, topLevel): super().__init__(topLevel) self.zlistener = self.zoneListener(self) self.topLevel.add_zone_listener(self.__class__.__name__, self.zlistener)