def create_station_button(self, s, bb, action=None): """ Create station button :param s: button state :param bb: bounding box :param action: event listener :return: station logo button """ state = State() state.icon_base = s.icon_base state.index_in_page = s.index_in_page state.index = s.index state.scaled = getattr(s, "scaled", False) state.icon_base_scaled = s.icon_base_scaled state.name = "station_menu." + s.name state.l_name = s.l_name state.url = s.url state.keyboard_key = kbd_keys[KEY_SELECT] state.bounding_box = bb state.img_x = bb.x state.img_y = bb.y state.auto_update = False state.show_bgr = True state.show_img = True state.image_align_v = V_ALIGN_BOTTOM button = Button(self.util, state) button.add_release_listener(action) return button
def get_favorites_button_state(self, button_bounding_box): """ Get Favorites button state :param button_bounding_box: bounding box :return: favorites button state """ state = State() state.bounding_box = button_bounding_box scale_factor = 0.45 state.icon_base = self.image_util.load_icon_main( KEY_FAVORITES, button_bounding_box, scale_factor) state.icon_selected = self.image_util.load_icon_on( KEY_FAVORITES, button_bounding_box, scale_factor) state.name = state.l_name = state.genre = KEY_FAVORITES state.bgr = self.config[COLORS][COLOR_DARK] state.img_x = None state.img_y = None state.auto_update = True state.show_bgr = False state.show_img = True state.show_label = False state.comparator_item = state.name state.index = 0 state.v_align = V_ALIGN_TOP state.v_offset = 0 state.voice_commands = state.name return state
def get_cd_drives(self, font_size, bb): """ Return the list of object representing CD drives :font_size: font size :return: list of CD drives info """ content = self.get_cd_drives_info() if not content: return None items = {} for cd in content: s = State() s.index = cd[0] s.name = cd[1] s.l_name = cd[1] s.file_type = FILE_CD_DRIVE s.icon_base = self.image_util.get_file_icon(s.file_type, "", icon_bb=bb, scale_factor=0.25) s.comparator_item = s.index s.bgr = self.config[COLORS][COLOR_DARK] s.show_bgr = True s.fixed_height = int(font_size * 0.8) items[s.name] = s return items
def create_file_button(self, bb, action=None): """ Create default audio file button :param bb: bounding box :param action: button event listener :return: default audio file button """ state = State() state.icon_base = self.image_util.get_audio_file_icon("", bb) state.scaled = False state.name = "cd" state.keyboard_key = kbd_keys[KEY_SELECT] state.bounding_box = bb state.img_x = bb.x state.img_y = bb.y state.auto_update = False state.show_bgr = False state.show_img = True state.image_align_v = V_ALIGN_CENTER state.source = FILE_BUTTON button = Button(self.util, state) button.add_release_listener(action) return button
def get_podcast_info_from_disk(self, index, podcast): """ Get the info of loaded podcast as State object :param index: podcast index :param podcast: podcast dictionary :return: podcast info as State object """ s = State() s.index = index s.name = podcast["name"] s.l_name = s.name s.url = podcast["url"] s.online = False s.description = podcast["summary"] s.fixed_height = int(self.podcast_button_font_size * 0.8) s.file_type = PODCASTS s.comparator_item = s.index s.bgr = self.config[COLORS][COLOR_DARK] s.show_bgr = True try: img = os.path.join(self.config[PODCASTS_FOLDER], podcast["image"]) except: img = '' s.image_name = img s.icon_base = self.get_podcast_image(img, 0.5, 0.8, self.podcast_button_bb, False) self.summary_cache[s.url] = s return s
def create_station_button(self, s, bb, action=None): """ Create station button :param s: button state :param bb: bounding box :param action: event listener :return: station logo button """ state = State() state.icon_base = s.icon_base state.index_in_page = s.index_in_page state.index = s.index state.genre = s.genre state.scaled = getattr(s, "scaled", False) state.icon_base_scaled = s.icon_base_scaled state.name = "station_menu." + s.name state.l_name = s.l_name state.url = s.url state.keyboard_key = kbd_keys[KEY_SELECT] state.bounding_box = bb state.img_x = bb.x state.img_y = bb.y state.auto_update = False state.show_bgr = True state.show_img = True state.image_align_v = V_ALIGN_BOTTOM button = Button(self.util, state) button.add_release_listener(action) return button
def get_network_info(self, index, name, strength, bb): """ Prepare state object for network button :param index: network index :param name: network name :param strength: signal strength :param bb: bounding box :return: state object with network info """ s = State() s.index = index s.name = name s.l_name = name s.strength = strength s.comparator_item = s.index s.bgr = self.config[COLORS][COLOR_DARK] s.show_bgr = True if strength <= 25: n = "s-1" elif strength > 25 and strength <= 50: n = "s-2" elif strength > 50 and strength <= 75: n = "s-3" elif strength > 75: n = "s-4" s.icon_base = self.util.load_mono_svg_icon(n, self.util.COLOR_MAIN, bb, 0.5) return s
def load_m3u(self, path, folder, top_folder, items_per_page, default_icon_path): """ Load m3u playlist :param path: base path :param folder: main folder :param top_folder: top folder :param items_per_page: items per page :param default_icon_path: path to the default icon :return: list of State objects representing playlist """ items = [] lines = [] item_name = None index = 0 for encoding in ["utf8", "utf-8-sig", "utf-16"]: try: lines = codecs.open(path, "r", encoding).read().split("\n") break except Exception as e: logging.error(e) for line in lines: if len(line.rstrip()) == 0: continue if line.startswith("#") and not item_name: item_name = line[1:].rstrip() continue name = item_name.rstrip() path = os.path.join(folder, name + EXT_PNG) icon = self.image_util.load_image(path) if not icon: path = os.path.join(folder, name + EXT_JPG) icon = self.image_util.load_image(path) if not icon: icon = self.image_util.load_image(default_icon_path) state = State() state.index = index state.genre = top_folder state.url = line.rstrip() state.name = str(index) state.l_name = name state.icon_base = icon state.comparator_item = NAME state.index_in_page = index % items_per_page items.append(state) index += 1 item_name = None return items
def set_audio_file(self, new_track, s=None): """ Set new audio file :param new_track: True - new file "param s" button state """ state = State() state.folder = PODCASTS_FOLDER if s.status == STATUS_LOADED: state.url = s.file_name state.original_url = s.url else: state.url = s.url self.config[PLAYER_SETTINGS][PAUSE] = False state.mute = self.config[PLAYER_SETTINGS][MUTE] state.pause = self.config[PLAYER_SETTINGS][PAUSE] state.file_type = FILE_AUDIO state.dont_notify = True state.source = FILE_AUDIO state.playback_mode = FILE_AUDIO state.status = s.status if hasattr(s, "file_name"): state.file_name = s.file_name source = None if s: source = getattr(s, "source", None) if new_track: tt = 0.0 else: tt = self.config[PODCASTS][PODCAST_EPISODE_TIME] if (isinstance(tt, str) and len(tt) != 0) or ( isinstance(tt, float) or (source and source == RESUME)) or isinstance(tt, int): state.track_time = tt self.time_control.slider.set_position(0) if self.file_button and self.file_button.components[ 1] and self.file_button.components[1].content: state.icon_base = self.file_button.components[1].content if s: if self.config[VOLUME_CONTROL][ VOLUME_CONTROL_TYPE] == VOLUME_CONTROL_TYPE_PLAYER: state.volume = s.volume else: state.volume = None if getattr(s, "full_screen_image", None) != None: state.full_screen_image = s.full_screen_image self.notify_play_listeners(state)
def load_stations_folders(self, button_bounding_box): """ Load languages menu items :param button_bounding_box: bounding box :return: dictionary with menu items """ items = collections.OrderedDict() i = 0 current_language = self.config[CURRENT][LANGUAGE] folders = self.get_stations_folders() top_folder = self.get_stations_top_folder() for folder in folders: name = folder path = os.path.join(os.getcwd(), FOLDER_LANGUAGES, current_language, FOLDER_RADIO_STATIONS, top_folder, folder, FILE_FOLDER) folder_image = self.image_util.load_image(path) path_on = os.path.join(os.getcwd(), FOLDER_LANGUAGES, current_language, FOLDER_RADIO_STATIONS, top_folder, folder, FILE_FOLDER_ON) folder_image_on = self.image_util.load_image(path_on) state = State() state.name = state.l_name = state.genre = name if folder_image: scale_ratio = self.image_util.get_scale_ratio( (button_bounding_box.w, button_bounding_box.h), folder_image[1]) scaled_image = self.image_util.scale_image( folder_image, scale_ratio) state.icon_base = (path, scaled_image) if folder_image_on: scaled_image_on = self.image_util.scale_image( folder_image_on, scale_ratio) state.icon_selected = (path_on, scaled_image_on) state.bgr = self.config[COLORS][COLOR_DARK] state.img_x = None state.img_y = None state.auto_update = True state.show_bgr = True state.show_img = True state.show_label = True state.comparator_item = state.name state.index = i state.v_align = V_ALIGN_TOP state.v_offset = 35 state.voice_commands = name items[state.name] = state i += 1 return items
def load_menu(self, names, comparator, disabled_items=None): """ Load menu items :param names: list of menu item names (should have corresponding filename) :param comparator: string used to sort items :param disabled_items: list of items which should be disabled :return: dictionary with menu items """ items = {} f = self.config[ICON_SIZE_FOLDER] for name in names: filename = name + EXT_PNG path = os.path.join(FOLDER_ICONS, f, filename) icon = self.load_image(path) filename = name + IMAGE_SELECTED_SUFFIX + EXT_PNG path_on = os.path.join(FOLDER_ICONS, f, filename) icon_on = self.load_image(path_on) filename = name + IMAGE_DISABLED_SUFFIX + EXT_PNG path_off = os.path.join(FOLDER_ICONS, f, filename) icon_off = self.load_image(path_off) state = State() state.name = name state.genre = name state.l_genre = self.config[LABELS][name] state.l_name = self.config[LABELS][name] state.icon_base = icon if icon_on: state.icon_selected = icon_on else: state.icon_selected = icon if not icon_off: state.icon_disabled = icon_on state.bgr = self.config[COLORS][COLOR_DARK] state.img_x = None state.img_y = None state.auto_update = True state.show_bgr = True state.show_img = True state.show_label = True if comparator == NAME: state.comparator_item = state.name elif comparator == GENRE: state.comparator_item = state.genre if disabled_items and name in disabled_items: state.enabled = False items[state.name] = state return items
def load_favorites(self, p, items_per_page, default_icon_path): """ Load m3u playlist :param p: base path :param items_per_page: items per page :param items_per_page: items per page :param default_icon_path: path to the default icon :return: list of State objects representing playlist """ favorites = [] lines = [] state = None index = 0 if p == None: return favorites try: path = os.path.join(p, FILE_FAVORITES) lines = codecs.open(path, "r", UTF8).read().split("\n") except Exception as e: pass for line in lines: if len(line.rstrip()) == 0: continue if line.startswith("#") and state == None: state = State() state.favorite = True state.index = index state.name = str(index) state.index_in_page = index % items_per_page state.genre = line[1:].rstrip() elif line.startswith("#") and state != None: state.l_name = line[1:].rstrip() path = os.path.join(p, state.genre, state.l_name + EXT_PNG) icon = self.image_util.load_image(path) if not icon: icon = self.image_util.load_image(default_icon_path) state.icon_base = icon state.comparator_item = NAME elif line.startswith("http"): state.url = line.rstrip() favorites.append(state) state = None index += 1 return favorites
def get_podcast_info(self, index, podcast_url): """ Get podcast info as state object :param index: podcast index :param podcast_url: podcast url :return: podcast info as State object """ try: response = requests.get(podcast_url) if response.status_code == 404: return None rss = feedparser.parse(response.content) if rss and getattr(rss, "bozo_exception", None): return None except: return None s = State() s.index = index s.name = rss.feed.title s.l_name = s.name s.description = rss.feed.subtitle s.url = podcast_url s.online = True s.fixed_height = int(self.podcast_button_font_size * 0.8) s.file_type = PODCASTS s.comparator_item = s.index s.bgr = self.config[COLORS][COLOR_DARK] s.show_bgr = True if 'image' in rss.feed and 'href' in rss.feed.image: img = rss.feed.image.href.strip() else: img = '' s.image_name = img s.icon_base = self.get_podcast_image(img, 0.48, 0.8, self.podcast_button_bb) self.summary_cache[s.url] = s return s
def get_center_button(self, s): """ Create the center button :param s: button state :return: station logo button """ bb = Rect(self.layout.CENTER.x + 1, self.layout.CENTER.y + 1, self.layout.CENTER.w - 1, self.layout.CENTER.h - 1) if not hasattr(s, "icon_base"): self.util.add_icon(s) state = State() state.icon_base = s.icon_base self.factory.set_state_scaled_icons(s, bb) state.index = s.index state.genre = s.genre state.scaled = getattr(s, "scaled", False) state.icon_base_scaled = s.icon_base_scaled state.name = "station." + s.name state.l_name = s.l_name state.url = s.url state.keyboard_key = kbd_keys[KEY_SELECT] state.bounding_box = bb state.img_x = bb.x state.img_y = bb.y state.auto_update = False state.show_bgr = True state.show_img = True state.logo_image_path = s.image_path state.image_align_v = V_ALIGN_BOTTOM state.comparator_item = self.current_state.comparator_item button = Button(self.util, state) img = button.components[1] self.logo_button_content = (img.image_filename, img.content, img.content_x, img.content_y) return button
def create_disabled_button(self, bb, name, scale): """ Create disabled button :param bb: bounding box :param name: image name :param scale: image scale :return: disabled button """ state = State() state.name = name state.icon_base = self.util.load_mono_svg_icon(state.name, self.util.COLOR_OFF, bb, scale) state.icon_selected = state.icon_base state.bgr = (0, 0, 0) state.bounding_box = bb state.img_x = None state.img_y = None state.auto_update = True state.image_align_v = V_ALIGN_CENTER state.show_bgr = True state.show_img = True state.show_label = False return Button(self.util, state)
def create_disabled_button(self, bb, name, scale): """ Create disabled button :param bb: bounding box :param name: image name :param scale: image scale :return: disabled button """ state = State() state.name = name state.icon_base = self.image_util.load_icon_off(state.name, bb, scale) state.icon_selected = state.icon_base state.bgr = self.config[BACKGROUND][MENU_BGR_COLOR] state.bounding_box = bb state.img_x = None state.img_y = None state.auto_update = True state.image_align_v = V_ALIGN_CENTER state.show_bgr = True state.show_img = True state.show_label = False return Button(self.util, state)
def load_languages_menu(self, button_bounding_box): """ Load languages menu items :param button_bounding_box: menu button bounding box :return: dictionary with menu items """ items = {} i = 0 current_language = self.get_current_language() labels = current_language[TRANSLATIONS] va_commands = self.get_va_language_commands() for language in self.config[KEY_LANGUAGES]: name = language[NAME] state = State() state.name = name state.l_name = labels[name] path = os.path.join(os.getcwd(), FOLDER_LANGUAGES, name, FILE_FLAG) img = self.prepare_flag_image(path, button_bounding_box) state.icon_base = (path, img) state.bgr = self.config[COLORS][COLOR_DARK] state.img_x = None state.img_y = None state.auto_update = True state.show_bgr = True state.show_img = True state.show_label = True state.comparator_item = state.name state.index = i state.voice_commands = va_commands[name] state.v_align = V_ALIGN_TOP items[state.name] = state i += 1 return items
def create_stream_button(self, bb): """ Create Stream button :param bb: bounding box :return: genre button """ state = State() state.name = "stream" state.icon_base = self.util.load_mono_svg_icon(state.name, self.util.COLOR_OFF, bb, 0.4) state.icon_selected = state.icon_base state.bgr = (0, 0, 0) state.bounding_box = bb state.img_x = None state.img_y = None state.auto_update = True state.image_align_v = V_ALIGN_CENTER state.show_bgr = True state.show_img = True state.show_label = False return Button(self.util, state)
def handle_metadata(self, state=None): """ Handle metadata UI callback :param state: metadata object """ if not state: return if "picture" in state.keys(): img = ("current_shairport_image", state["picture"]) self.set_file_button(img) self.file_button.clean_draw_update() state = State() state.icon_base = img state.full_screen_image = img self.change_screensaver_image(state) elif "current_title" in state.keys(): title = state["current_title"] self.screen_title.set_text(title) elif "volume" in state.keys(): volume = state["volume"] self.volume.set_position(volume) self.volume.update_position() self.volume.notify_slide_listeners() elif "stream" in state.keys(): type = state["stream"] if type == "end": self.play_button.draw_state(1) elif type == "begin": self.play_button.draw_state(0) elif "Time" in state.keys() and "seek_time" in state.keys(): state["state"] = "running" if self.visible: if self.update_web_observer: self.update_web_observer()
def load_stations(self, language, genre, stations_per_page): """ Load stations for specified language and genre :param language: the language :param genre: the genre :param stations_per_page: stations per page used to assign indexes :return: list of button state objects. State contains station icons, index, genre, name etc. """ stations = [] folder = os.path.join(FOLDER_STATIONS, language, genre) path = os.path.join(folder, genre + EXT_M3U) lines = [] try: lines = codecs.open(path, "r", UTF_8).read().split("\n") except Exception as e: logging.error(str(e)) pass for i in range(0, len(lines), 3): if len(lines[i].rstrip()) == 0: continue index = int(lines[i].rstrip()[1:]) localized_name = lines[i + 1][1:] url = lines[i + 2] icon = self.load_station_icon(folder, index) state = State() state.index = index state.genre = genre state.url = url.rstrip() state.name = str(index) state.l_name = localized_name.rstrip() state.icon_base = icon state.comparator_item = INDEX state.index_in_page = index % stations_per_page stations.append(state) return stations
def set_audio_file(self, new_track, s=None): """ Set new audio file :param new_track: True - new audio file "param s" button state object """ state = State() if s: state.playback_mode = getattr(s, "playback_mode", FILE_AUDIO) state.playlist_track_number = getattr(s, "playlist_track_number", None) if self.config[CURRENT][MODE] == CD_PLAYER and getattr( s, "source", None) != INIT: image_base = getattr(s, "image_base", None) if image_base != None: state.image_base = image_base else: m = self.config[FILE_PLAYBACK][CURRENT_FILE_PLAYBACK_MODE] if m: state.playback_mode = m else: state.playback_mode = FILE_AUDIO if self.config[CURRENT][MODE] == AUDIO_FILES: self.current_folder = self.config[FILE_PLAYBACK][CURRENT_FOLDER] if not self.current_folder: return state.folder = self.current_folder state.file_name = self.config[FILE_PLAYBACK][CURRENT_FILE] if state.folder[-1] == os.sep: state.folder = state.folder[:-1] if os.sep in state.file_name: state.url = "\"" + state.file_name + "\"" else: state.url = "\"" + state.folder + os.sep + state.file_name + "\"" state.music_folder = self.config[AUDIO][MUSIC_FOLDER] elif self.config[CURRENT][MODE] == CD_PLAYER: state.file_name = s.file_name state.url = getattr(s, "url", s.file_name) parts = s.file_name.split() self.config[CD_PLAYBACK][CD_DRIVE_NAME] = parts[0][len("cdda:///" ):] id = self.cdutil.get_cd_drive_id_by_name( self.config[CD_PLAYBACK][CD_DRIVE_NAME]) self.config[CD_PLAYBACK][CD_DRIVE_ID] = int(id) self.config[CD_PLAYBACK][CD_TRACK] = int(parts[1].split("=")[1]) self.config[PLAYER_SETTINGS][PAUSE] = False state.mute = self.config[PLAYER_SETTINGS][MUTE] state.pause = self.config[PLAYER_SETTINGS][PAUSE] state.file_type = FILE_AUDIO state.dont_notify = True state.source = FILE_AUDIO if self.config[FILE_PLAYBACK][ CURRENT_FILE_PLAYBACK_MODE] == FILE_AUDIO or self.config[ CURRENT][MODE] == CD_PLAYER: self.audio_files = self.get_audio_files() elif self.config[FILE_PLAYBACK][ CURRENT_FILE_PLAYBACK_MODE] == FILE_PLAYLIST: state.file_name = self.config[FILE_PLAYBACK][CURRENT_FILE_PLAYLIST] self.load_playlist(state) state.file_name = self.config[FILE_PLAYBACK][CURRENT_FILE] self.audio_files = self.get_audio_files_from_playlist() state.playback_mode = FILE_PLAYLIST n = getattr(s, "file_name", None) if n: state.file_name = n try: state.playlist_track_number = int(state.file_name) - 1 except: state.playlist_track_number = self.get_current_track_index( state) source = None if s: source = getattr(s, "source", None) if new_track: tt = 0.0 else: if self.config[CURRENT][MODE] == CD_PLAYER: tt = self.config[CD_PLAYBACK][CD_TRACK_TIME] else: tt = self.config[FILE_PLAYBACK][CURRENT_TRACK_TIME] if (isinstance(tt, str) and len(tt) != 0) or ( isinstance(tt, float) or (source and source == RESUME)) or isinstance(tt, int): state.track_time = tt self.time_control.slider.set_position(0) if self.file_button and self.file_button.components[ 1] and self.file_button.components[1].content: state.icon_base = self.file_button.components[1].content if s and s.volume: state.volume = s.volume if self.config[CURRENT][MODE] == CD_PLAYER and s and getattr( s, "source", None) == INIT: try: self.cd_album = self.util.cd_titles[self.config[CD_PLAYBACK] [CD_DRIVE_NAME]] self.set_cd_album_art_image() state.image_base = self.file_button.components[1].content except: self.cd_album = None if getattr(s, "full_screen_image", None) != None: state.full_screen_image = s.full_screen_image song_name = self.get_song_name(s) if song_name != None: state.album = song_name self.notify_play_listeners(state)
def load_menu(self, names, comparator, disabled_items=None, v_align=None, bb=None, scale=1): """ Load menu items :param names: list of menu item names (should have corresponding filename) :param comparator: string used to sort items :param disabled_items: list of items which should be disabled :param v_align: vertical alignment :param bb: bounding box :param scale: image scale factor :return: dictionary with menu items """ items = {} i = 0 for name in names: icon = self.load_mono_svg_icon(name, self.COLOR_MAIN, bb, scale) icon_on = self.load_mono_svg_icon(name, self.COLOR_ON, bb, scale) if disabled_items and name in disabled_items: icon_off = self.load_mono_svg_icon(name, self.COLOR_OFF, bb, scale) else: icon_off = None state = State() state.name = name state.genre = name try: state.l_genre = self.config[LABELS][name] state.l_name = self.config[LABELS][name] except: state.l_genre = name state.l_name = name state.icon_base = icon if icon_on: state.icon_selected = icon_on else: state.icon_selected = icon if not icon_off: state.icon_disabled = icon_on else: state.icon_disabled = icon_off state.bgr = self.config[COLORS][COLOR_DARK] state.img_x = None state.img_y = None state.auto_update = True state.show_bgr = True state.show_img = True state.show_label = True state.v_align = v_align if comparator == NAME: state.comparator_item = state.name elif comparator == GENRE: state.comparator_item = state.genre if disabled_items and name in disabled_items: state.enabled = False state.index = i items[state.name] = state i += 1 return items
def set_audio_file(self, new_track, s=None): """ Set new audio file :param new_track: True - new audio file "param s" button state object """ state = State() state.playback_mode = FILE_AUDIO self.current_folder = s.folder state.folder = self.current_folder state.file_name = s.file_name state.url = s.url if state.folder[-1] == os.sep: state.folder = state.folder[:-1] state.full_screen_image = self.set_audio_file_image( state.url.replace('\"', ""), state.folder) self.config[PLAYER_SETTINGS][PAUSE] = False state.mute = self.config[PLAYER_SETTINGS][MUTE] state.pause = self.config[PLAYER_SETTINGS][PAUSE] self.play_button.draw_default_state(None) state.file_type = FILE_AUDIO state.dont_notify = True folder = self.config[COLLECTION_PLAYBACK][COLLECTION_FOLDER] self.audio_files = self.util.get_audio_files_in_folder(folder, False) source = None if s: source = getattr(s, "source", None) tt = 0.0 if new_track and hasattr(s, "source") and s.source != INIT: tt = 0.0 else: tt = self.config[COLLECTION_PLAYBACK][COLLECTION_TRACK_TIME] if (isinstance(tt, str) and len(tt) != 0) or ( isinstance(tt, float) or (source and source == RESUME)) or isinstance(tt, int): state.track_time = tt if self.show_time_control: self.time_control.slider.set_position(0) if self.file_button and self.file_button.components[ 1] and self.file_button.components[1].content: state.icon_base = self.file_button.components[1].content if self.file_button and hasattr(s, "index"): self.file_button.state.index = s.index else: self.file_button.state.index = 0 if s: if self.config[VOLUME_CONTROL][ VOLUME_CONTROL_TYPE] == VOLUME_CONTROL_TYPE_PLAYER: state.volume = s.volume else: state.volume = None if getattr(s, "full_screen_image", None) != None: state.full_screen_image = s.full_screen_image song_name = self.get_song_name(s) if song_name != None: state.album = song_name self.notify_play_listeners(state)