class RadioPlayerScreen(PlayerScreen): """ The Radio Player Screen """ def __init__(self, util, listeners, voice_assistant=None): """ Initializer :param util: utility object :param listeners: screen event listeners :param voice_assistant: the voice assistant """ self.util = util self.config = util.config self.bounding_box = util.screen_rect self.favorites_util = FavoritesUtil(self.util) self.image_util = util.image_util show_arrow_labels = True self.show_order = False self.show_info = True self.show_time_slider = False self.listeners = listeners self.change_logo_listeners = [] self.favorites_util.set_favorites_in_config() PlayerScreen.__init__(self, util, listeners, "station_screen_title", show_arrow_labels, self.show_order, self.show_info, self.show_time_slider, voice_assistant) self.set_custom_button() self.set_center_button() self.favorites_util.mark_favorites({"b": self.center_button}) self.add_component(self.info_popup) self.set_listeners(listeners) self.shutdown_button.release_listeners.insert( 0, self.favorites_util.save_favorites) # self.link_borders() if self.center_button == None: self.custom_button.set_selected(True) self.current_button = self.custom_button self.custom_button.clean_draw_update() def set_custom_button(self): """ Set the custom buttom """ self.genres = self.util.get_genres() self.genres[ KEY_FAVORITES] = self.favorites_util.get_favorites_button_state( self.custom_button_layout) self.current_genre = self.util.get_current_genre() self.current_genre.bounding_box = self.custom_button_layout self.custom_button = self.get_custom_button(self.current_genre, self.listeners[KEY_GENRES]) self.right_panel.add_component(self.custom_button) def stop(self): """ Stop playback """ if self.center_button: self.center_button.components[1] = None self.set_title("") if hasattr(self, "stop_player"): self.stop_player() def set_center_button(self): """ Set the center button """ if self.current_genre.name == KEY_FAVORITES: self.playlist = self.favorites_util.get_favorites_playlist() else: self.playlist = self.util.get_radio_player_playlist( self.current_genre.name) if self.playlist == None or len(self.playlist) == 0: self.clean_center_button() self.update_arrow_button_labels() self.set_title("") self.stop() return self.current_index = self.util.get_current_radio_station_index() if self.current_index >= len(self.playlist): self.current_index = len(self.playlist) - 1 self.current_state = self.playlist[self.current_index] self.current_state.bounding_box = self.layout.CENTER if not hasattr(self.current_state, "icon_base"): self.util.add_icon(self.current_state) if self.center_button == None: self.center_button = self.get_center_button(self.current_state) self.current_button = self.center_button self.add_component(self.center_button) else: button = self.get_center_button(self.current_state) self.center_button.state = button.state self.center_button.components = button.components self.center_button.selected = True self.center_button.add_release_listener(self.handle_favorite) self.center_button.add_release_listener( self.listeners[KEY_RADIO_BROWSER]) self.center_button.clean_draw_update() img = self.center_button.components[1] self.logo_button_content = (img.image_filename, img.content, img.content_x, img.content_y) self.update_arrow_button_labels() self.set_title(self.current_state) self.link_borders() def get_custom_button(self, genre_button_state, listener): """ Get the custom button :param genre_button_state: the genre button state :param listener: the button listener """ self.util.add_icons(genre_button_state) bb = genre_button_state.bounding_box button = self.factory.get_genre_button(bb, genre_button_state, PERCENT_GENRE_IMAGE_AREA) button.add_release_listener(listener) return button 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 add_change_logo_listener(self, listener): """ Add change logo listener :param listener: event listener """ if listener not in self.change_logo_listeners: self.change_logo_listeners.append(listener) def notify_change_logo_listeners(self, state): """ Notify change logo event listeners :param state: state object with new image in 'icon_base' """ for listener in self.change_logo_listeners: listener(state) def change_genre(self, state=None): """ Change genre :para, state: the button state with new genre """ self.genres = self.util.get_genres() self.genres[ KEY_FAVORITES] = self.favorites_util.get_favorites_button_state( self.custom_button_layout) self.current_genre = self.genres[state.name] self.current_genre.bounding_box = self.custom_button_layout button = self.get_custom_button(self.current_genre, self.listeners[KEY_GENRES]) self.custom_button.state = button.state self.custom_button.set_selected(True) self.set_center_button() def set_current(self, state=None): """ Set the current screen state :param state: the state object """ if state == None: self.clean_center_button() self.update_arrow_button_labels() self.set_title("") self.stop_player() self.current_button = self.home_button self.home_button.clean_draw_update() return if not hasattr(state, "source"): return src = getattr(state, "source", None) if src == KEY_HOME: if not hasattr(self, "current_button"): # after changing language self.home_button.set_selected(True) self.home_button.clean_draw_update() self.current_button = self.home_button if state.change_mode: self.start_playback() if src == GENRE: if state.comparator_item != self.current_genre.comparator_item: self.change_genre(state) if self.current_genre.name != KEY_FAVORITES: self.favorites_util.mark_favorites( {"b": self.center_button}) self.play() self.center_button.set_selected(False) elif src == KEY_FAVORITES: current_language = self.config[CURRENT][LANGUAGE] key = STATIONS + "." + current_language self.config[key][CURRENT_STATIONS] = KEY_FAVORITES self.change_genre(state) self.center_button.set_selected(False) if self.favorites_util.get_current_favorites_station() != None: self.play() elif src == KEY_RADIO_BROWSER: if self.center_button and self.center_button.state.url != state.url: self.start_playback() favorites, lang_dict = self.favorites_util.get_favorites_from_config( ) if self.center_button and len(self.center_button.components) == 4: if not self.favorites_util.is_favorite( favorites, self.center_button.state ): # remove star icon if not favorite anymore del self.center_button.components[3] elif self.center_button and len( self.center_button.components) == 3: if self.current_genre.name == KEY_FAVORITES: if not self.favorites_util.is_favorite( favorites, self.center_button.state): self.start_playback() else: if self.favorites_util.is_favorite( favorites, self.center_button.state ): # add star icon if favorite self.favorites_util.mark_favorites( {"b": self.center_button}) def start_playback(self): """ Start playback """ self.set_center_button() self.set_title(self.current_state) self.play() def set_current_item(self, index): """ Specific for each player. Sets config item """ self.util.set_radio_station_index(index) def clean_center_button(self): """ Clean the center button """ if self.center_button == None or self.center_button.components[ 1] == None: return self.center_button.components[1].content = None self.center_button.components[1].image_filename = None self.center_button.state.icon_base = None self.center_button.state.icon_base_scaled = None self.center_button.state.comparator_item = None if len(self.center_button.components) == 4: del self.center_button.components[3] if self.visible: self.center_button.clean_draw_update() def show_logo(self): """ Show station logo image """ self.center_button.components[ 1].image_filename = self.logo_button_content[0] self.center_button.components[1].content = self.logo_button_content[1] self.center_button.components[1].content_x = self.logo_button_content[ 2] self.center_button.components[1].content_y = self.logo_button_content[ 3] self.center_button.state.icon_base = (self.logo_button_content[0], self.logo_button_content[1]) self.center_button.state.comparator_item = self.current_state.comparator_item if self.visible: self.center_button.clean_draw_update() self.notify_change_logo_listeners(self.center_button.state) self.redraw_observer() def show_album_art(self, status): """ Show album art from discogs.com :param status: object having artist & track names """ self.current_album_image = None if self.config[CURRENT][MODE] != RADIO or status == None: return album = status['current_title'] if len(album) < 10 or "jingle" in album.lower(): self.show_logo() self.redraw_observer() return r = Rect(0, 0, self.config[SCREEN_INFO][WIDTH], self.config[SCREEN_INFO][HEIGHT]) full_screen_image = self.image_util.get_cd_album_art(album, r) bb = self.center_button.bounding_box scale_ratio = self.image_util.get_scale_ratio((bb.w, bb.h), full_screen_image[1]) album_art = (full_screen_image[0], self.image_util.scale_image(full_screen_image, scale_ratio)) if album_art and album_art[0] != None and album_art[0].endswith( DEFAULT_CD_IMAGE) or album_art[1] == None: self.show_logo() self.redraw_observer() return size = album_art[1].get_size() if self.center_button.components[1] == None: button = self.get_center_button(self.current_state) self.center_button.state = button.state self.center_button.components = button.components name = GENERATED_IMAGE + "album.art" self.center_button.components[1].image_filename = name self.center_button.components[1].content = album_art[1] self.center_button.components[1].content_x = int(bb.x + (bb.w - size[0]) / 2) self.center_button.components[1].content_y = int(bb.y + (bb.h - size[1]) / 2) album_art = (name, album_art[1]) self.center_button.state.icon_base = self.center_button.state.icon_base_scaled = album_art self.center_button.state.comparator_item = self.current_state.comparator_item if full_screen_image: self.center_button.state.full_screen_image = full_screen_image[1] self.center_button.state.album = album if self.visible: self.center_button.clean_draw_update() self.notify_change_logo_listeners(self.center_button.state) self.redraw_observer() def handle_info_popup_selection(self, state): """ Handle info menu selection :param state: button state """ if state.name == LYRICS: a = None try: a = self.screen_title.text except: pass if a != None: s = State() s.album = a self.start_screensaver(state.name, s) else: self.start_screensaver(state.name) else: self.start_screensaver(state.name) def handle_favorite(self, state): """ Add/Remove station to/from the favorites :param state: button state """ if state == None or not getattr(state, "long_press", False): return favorites, lang_dict = self.favorites_util.get_favorites_from_config() if self.favorites_util.is_favorite(favorites, state): self.favorites_util.remove_favorite(favorites, state) if self.current_genre.name == KEY_FAVORITES: if len(self.playlist) > 0: if state.index == 0: self.current_index = 0 else: self.current_index = state.index - 1 self.util.set_radio_station_index(self.current_index) self.set_center_button() self.play() else: self.util.set_radio_station_index(None) self.stop() else: if isinstance(state.icon_base, tuple): state.image_path = state.icon_base[0] self.favorites_util.add_favorite(favorites, state) if self.center_button and len(self.center_button.components) == 3: self.favorites_util.mark_favorites({"b": self.center_button})
class StationMenu(Menu): """ Station Menu class. Extends base Menu class """ PAGE_MODE = 0 STATION_MODE = 1 STATION = "station" LOGO_SCALE_FACTOR = 200 / 228 def __init__(self, playlist, util, mode=STATION, bgr=None, bounding_box=None): """ Initializer :param playlist: playlist object :param util: utility object :param bgr: menu background :param bounding_box: bounding box """ self.factory = Factory(util) self.util = util self.config = self.util.config self.image_util = util.image_util self.favorites_util = FavoritesUtil(self.util) m = self.create_station_menu_button bb = bounding_box self.menu_mode = mode Menu.__init__(self, util, bgr, bb, playlist.rows, playlist.columns, create_item_method=m) self.bounding_box = bb self.playlist = playlist self.current_mode = self.STATION_MODE path = os.path.join(FOLDER_ICONS, IMAGE_SHADOW + EXT_PNG) self.original_shadow = self.image_util.load_image(path, bounding_box=(bb.w, bb.h)) h = self.bounding_box.h self.shadow = (self.original_shadow[0], self.image_util.scale_image(self.original_shadow[1], (h, h))) self.shadow_component = None path = os.path.join(FOLDER_ICONS, IMAGE_SELECTION + EXT_PNG) self.selection = self.image_util.load_image(path) self.station_button = None self.menu_click_listeners = [] self.mode_listeners = [] self.change_logo_listeners = [] self.page_turned = False self.genre = None self.current_logo_image = None self.current_logo_filename = None self.current_album_image = None def create_station_menu_button(self, s, constr, action, scale): """ Create Station Menu button :param s: button state :param constr: scaling constraints :param action: button event listener :param scale: True - scale images, False - don't scale images :return: station menu button """ if scale: self.factory.set_state_scaled_icons(s, constr) s.scaled = scale button = self.create_station_button(s, constr, action) button.bgr = (0, 0, 0) return button 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 set_playlist(self, playlist): """ Set playlist :param playlist: the playlist to set """ self.playlist = playlist def init_station(self, index): """ Initialize the station specified by its index :param index: station index """ self.current_album_image = None self.playlist.set_current_item(index) index = self.playlist.current_item_index index_on_page = self.playlist.current_item_index_in_page page = self.playlist.get_current_page() self.set_page(index, index_on_page, page) def set_page(self, index, index_on_page, page): """ Set new page of stations :param index: current station index in playlist :param index_on_page: station index on page :param page: list of stations """ self.set_items(self.make_dict(page), index_on_page, self.switch_mode) if not self.favorites_util.is_favorite_mode(): self.favorites_util.mark_favorites(self.buttons) for b in self.buttons.values(): b.add_release_listener(self.handle_favorite) self.shadow_component = self.get_shadow() self.add_component(self.shadow_component) self.station_button = self.get_logo_button(index) if self.current_album_image == None: self.large_station_button = self.get_logo_button(index) self.add_component(self.large_station_button) if not self.is_button_defined(): return self.add_component(self.get_selection_frame(self.button)) def is_button_defined(self): """ Check if ''button' object was defined :return: true - button object defined, false - not defined """ return getattr(self, "button", None) != None def get_shadow(self): """ Return the button shadow component :return: shadow component """ c = Component(self.util, self.shadow[1]) c.name = "station_menu.shadow" c.image_filename = self.shadow[0] c.content_x = self.bounding_box.x c.content_y = self.bounding_box.y return c def get_logo_button(self, index): """ Return the button of the station specified by its index :param index: button index in the playlist :return: current station button """ try: self.button = self.buttons[str(index)] except: pass if not self.is_button_defined(): return b = self.create_station_button(self.button.state, self.bounding_box, self.switch_mode) b.components[1].content = self.button.state.icon_base img = b.components[1].content if isinstance(img, tuple): self.current_logo_filename = img[0] img = img[1] bb = self.bounding_box logo_height = int(bb.h * self.LOGO_SCALE_FACTOR) self.current_logo_image = self.image_util.scale_image( img, (logo_height, logo_height)) b.components[1].content = self.current_logo_image b.components[ 1].content_x = bb.x + bb.w / 2 - self.current_logo_image.get_size( )[0] / 2 b.components[ 1].content_y = bb.y + bb.h / 2 - self.current_logo_image.get_size( )[1] / 2 b.add_release_listener(self.handle_favorite) self.favorites_util.mark_favorites({"b": b}) return b def handle_favorite(self, state): """ Add/Remove station to/from the favorites :param state: button state """ if self.config[CURRENT][MODE] != RADIO or state == None or not getattr( state, "long_press", False): return favorites, lang_dict = self.favorites_util.get_favorites_from_config() if self.favorites_util.is_favorite(favorites, state): self.favorites_util.remove_favorite(favorites, state, self.playlist.rows, self.playlist.columns) size = self.playlist.rows * self.playlist.columns length = len(favorites) if self.favorites_util.is_favorite_mode(): del self.buttons[str(state.index)] if len(self.buttons) == 0: self.components = [] if length > 0: self.switch_to_previous_station(state) else: for i, comp in enumerate(self.components): if type( comp ) is Button and comp.state.genre == state.genre and comp.state.l_name == state.l_name: del self.components[state.index_in_page] break if state.index_in_page == 0 and len(favorites) <= size: self.set_station(0) else: self.switch_to_previous_station(state) self.playlist.items = favorites self.playlist.length = length self.playlist.total_pages = int(length / size) if len(favorites) > 0: state = favorites[self.playlist.current_item_index] else: state.l_name = " " self.notify_listeners(state) if len(self.station_button.components) == 4: del self.station_button.components[3] if self.large_station_button and len( self.large_station_button.components) == 4: del self.large_station_button.components[3] else: items_per_page = self.playlist.rows * self.playlist.columns self.favorites_util.add_favorite(favorites, state, items_per_page) self.favorites_util.mark_favorites({"b": self.station_button}) self.favorites_util.mark_favorites( {"b": self.large_station_button}) self.favorites_util.mark_favorites(self.buttons) self.clean_draw_update() def get_selection_frame(self, button): """ Create the selection frame used in Page mode :param button: button for which the selection frame should be created :return: selection frame component """ x = button.components[0].content.x y = button.components[0].content.y w = button.components[0].content.w h = button.components[0].content.h i = self.image_util.scale_image(self.selection[1], (w, h)) c = Component(self.util, i) c.content_x = x c.content_y = y c.name = "station_menu.selection" c.image_filename = self.selection[0] c.visible = False c.selection_index = button.state.index_in_page return c def set_station(self, index, save=True, notify=True): """ Set new station specified by its index :param index: the index of new station :param save: flag defining if index should be saved in configuration object, True - save, False - don't save """ try: self.config[PLAYER_SETTINGS][PAUSE] = False self.init_station(index) self.draw() if self.config[VOLUME_CONTROL][ VOLUME_CONTROL_TYPE] == VOLUME_CONTROL_TYPE_PLAYER: self.button.state.volume = self.config[PLAYER_SETTINGS][VOLUME] else: self.button.state.volume = None self.button.state.mute = self.config[PLAYER_SETTINGS][MUTE] self.button.state.pause = self.config[PLAYER_SETTINGS][PAUSE] if notify: self.notify_listeners(self.button.state) if save: self.save_station_index(self.button.state.index) except KeyError: pass def save_station_index(self, index): """ Save station/stream index in configuration object :param index: the index """ lang = self.config[CURRENT][LANGUAGE] mode = self.config[CURRENT][MODE] if mode == RADIO: k = STATIONS + "." + lang try: self.config[k] except: self.config[k] = {} self.config[k][CURRENT_STATIONS] = self.genre self.config[k][self.genre] = index elif mode == STREAM: try: self.config[CURRENT][STREAM] = index except: pass def get_current_station_name(self): """ Return the current station name :return: localized name of the current station """ index = self.playlist.current_item_index button = self.buttons[str(index)] return button.state.l_name def get_current_station_index(self): """ Return the index of the current station :return: the index """ return self.playlist.current_item.index def switch_to_next_station(self, state): """ Switch to the next station :param state: button state """ if len(self.playlist.get_current_page()) == ( self.playlist.current_item_index_in_page + 1): self.switch_to_next_page(state) if self.playlist.current_item_index == self.playlist.length - 1: self.playlist.current_item_index = 0 else: self.playlist.current_item_index += 1 else: self.playlist.current_item_index += 1 self.set_station(self.playlist.current_item_index) def switch_to_previous_station(self, state): """ Switch to the previous station :param state: button state """ if self.playlist.current_item_index == 0: self.switch_to_previous_page(state) l = len(self.components) self.playlist.current_item_index = self.get_button_by_index_in_page( l - 4).state.index else: self.playlist.current_item_index -= 1 self.set_station(self.playlist.current_item_index) def switch_to_next_page(self, state): """ Switch to the next page :param state: button state """ next_page = self.playlist.next_page() self.set_page(self.playlist.current_item_index, self.playlist.current_page_index, next_page) if state != None: l = len(self.components) next_selected_button = self.get_button_by_index_in_page(0) self.components[l - 1] = self.get_selection_frame(next_selected_button) self.draw() self.page_turned = True def switch_to_previous_page(self, state): """ Switch to the previous page :param state: button state """ next_page = self.playlist.previous_page() self.set_page(self.playlist.current_item_index, self.playlist.current_page_index, next_page) if state != None: l = len(self.components) next_selected_button = self.get_button_by_index_in_page(0) self.components[l - 1] = self.get_selection_frame(next_selected_button) self.draw() self.page_turned = True def switch_mode(self, state): """ Switch menu mode. There are two modes - Station and Page :param state: button state """ if self.current_mode == self.STATION_MODE: self.set_page_mode() else: self.set_station_mode(state) def set_page_mode(self): """ Set Page mode """ self.current_mode = self.PAGE_MODE self.draw() self.notify_mode_listeners(self.current_mode) def set_station_mode(self, state): """ Set Station mode :param state: button state """ self.current_mode = self.STATION_MODE if self.page_turned: l = len(self.components) self.components[l - 1] = self.get_selection_frame(self.button) self.page_turned = False if state and state.index != self.playlist.current_item_index: self.set_station(state.index) else: self.draw() self.notify_mode_listeners(self.current_mode) def get_button_by_index_in_page(self, index): """ Return the button by its index on page :param index: button index :return: the button """ for button in self.buttons.values(): if button.state.index_in_page == index: return button return None def handle_event(self, event): """ Station menu event handler :param event: event to handle """ if not self.visible: return if self.current_mode == self.STATION_MODE: self.station_button.handle_event(event) else: if event.type == USER_EVENT_TYPE and event.sub_type == SUB_TYPE_KEYBOARD and event.action == pygame.KEYUP: l = len(self.components) selection = self.components[l - 1] key_event = False col = int(selection.selection_index % self.cols) row = int(selection.selection_index / self.cols) if event.keyboard_key == kbd_keys[KEY_LEFT]: if col == 0 and row == 0: self.switch_to_previous_page(None) l = len(self.components) selection.selection_index = l - 4 else: selection.selection_index = selection.selection_index - 1 key_event = True elif event.keyboard_key == kbd_keys[KEY_RIGHT]: if col == self.cols - 1 and row == self.rows - 1: self.switch_to_next_page(None) selection.selection_index = 0 l = len(self.components) else: m = selection.selection_index + 1 if self.get_button_by_index_in_page(m): selection.selection_index = m else: self.switch_to_next_page(None) selection.selection_index = 0 l = len(self.components) key_event = True elif event.keyboard_key == kbd_keys[KEY_UP]: if row == 0: for n in range(self.rows): m = selection.selection_index + (self.rows - 1 - n) * self.cols if self.get_button_by_index_in_page(m): selection.selection_index = m else: selection.selection_index = selection.selection_index - self.cols key_event = True elif event.keyboard_key == kbd_keys[KEY_DOWN]: if row == self.rows - 1: selection.selection_index = int( selection.selection_index % self.cols) else: m = selection.selection_index + self.cols if self.get_button_by_index_in_page(m): selection.selection_index = m else: selection.selection_index = int( selection.selection_index % self.cols) key_event = True elif event.keyboard_key == kbd_keys[KEY_BACK]: self.init_station(self.station_button.state.index) self.switch_mode(self.station_button.state) self.draw() key_event = False if key_event: next_selected_button = self.get_button_by_index_in_page( selection.selection_index) self.components[l - 1] = self.get_selection_frame( next_selected_button) self.draw() if event.keyboard_key == kbd_keys[KEY_SELECT]: selected_button = self.get_button_by_index_in_page( selection.selection_index) self.item_selected(selected_button.state) self.switch_mode(selected_button.state) self.notify_menu_click_listeners(event) else: Menu.handle_event(self, event) if self.visible and event.type == pygame.MOUSEBUTTONUP and self.bounding_box.collidepoint( event.pos): self.notify_menu_click_listeners(event) def draw(self): """ Draw Station Menu """ self.clean() l = len(self.components) if l > 2 and self.current_mode == self.STATION_MODE: self.components[l - 3].set_visible(True) self.components[l - 2].set_visible(True) self.components[l - 2].components[0].set_visible(False) self.components[l - 1].set_visible(False) elif l > 2: self.components[l - 3].set_visible(False) self.components[l - 2].set_visible(False) self.components[l - 1].set_visible(True) super(StationMenu, self).draw() self.update() def add_menu_click_listener(self, listener): """ Add menu button click listener :param listener: event listener """ if listener not in self.menu_click_listeners: self.menu_click_listeners.append(listener) def notify_menu_click_listeners(self, event): """ Notify all menu button click event listeners :param event: event to handle """ for listener in self.menu_click_listeners: listener(event) def add_mode_listener(self, listener): """ Add change mode listener :param listener: event listener """ if listener not in self.mode_listeners: self.mode_listeners.append(listener) def notify_mode_listeners(self, mode): """ Notify all menu change mode event listeners :param mode: the mode """ for listener in self.mode_listeners: listener(mode) def add_change_logo_listener(self, listener): """ Add change logo listener :param listener: event listener """ if listener not in self.change_logo_listeners: self.change_logo_listeners.append(listener) def notify_change_logo_listeners(self, state): """ Notify change logo event listeners :param state: state object with new image in 'icon_base' """ for listener in self.change_logo_listeners: listener(state) def show_logo(self): """ Show station logo image """ b = self.large_station_button bb = self.bounding_box logo_height = int(bb.h * self.LOGO_SCALE_FACTOR) b.components[1].image_filename = self.current_logo_filename b.components[1].content = self.current_logo_image b.components[ 1].content_x = bb.x + bb.w / 2 - self.current_logo_image.get_size( )[0] / 2 b.components[ 1].content_y = bb.y + bb.h / 2 - self.current_logo_image.get_size( )[1] / 2 if self.visible: self.draw() self.notify_change_logo_listeners(b.state) def show_album_art(self, status): """ Show album art from discogs.com :param status: object having artist & track names """ self.current_album_image = None if self.config[CURRENT][ MODE] != RADIO or status == None or self.current_mode == self.PAGE_MODE: return album = status['current_title'] if len(album) < 10 or "jingle" in album.lower(): self.show_logo() return bb_w = self.bounding_box.w * self.LOGO_SCALE_FACTOR bb_h = bb_w bb_x = self.bounding_box.x + (self.bounding_box.w - bb_w) / 2 bb_y = self.bounding_box.y + (self.bounding_box.h - bb_h) / 2 bb = pygame.Rect(bb_x, bb_y, bb_w, bb_w) r = pygame.Rect(0, 0, self.config[SCREEN_INFO][WIDTH], self.config[SCREEN_INFO][HEIGHT]) full_screen_image = self.image_util.get_cd_album_art(album, r) scale_ratio = self.image_util.get_scale_ratio((bb.w, bb.h), full_screen_image[1]) album_art = (full_screen_image[0], self.image_util.scale_image(full_screen_image, scale_ratio)) if album_art and album_art[0] != None and album_art[0].endswith( DEFAULT_CD_IMAGE) or album_art[1] == None: self.show_logo() return if album_art and album_art[0] != None and album_art[0].endswith( DEFAULT_CD_IMAGE) or album_art[1] == None: self.show_logo() return size = album_art[1].get_size() self.current_album_image = album_art[1] b = self.large_station_button img = b.components[1] img.content = album_art[1] img.content_x = int(bb_x + (bb_w - size[0]) / 2) img.content_y = int(bb_y + (bb_h - size[1]) / 2) url = self.util.encode_url(album_art[0]) img.image_filename = url b.state.icon_base = album_art if full_screen_image: b.state.full_screen_image = full_screen_image[1] k = 17 / 15 w = int(size[0] * k) h = int(size[1] * k) shadow = self.image_util.scale_image(self.original_shadow[1], (w, h)) self.shadow_component.content = shadow size = shadow.get_size() x = int(self.bounding_box.x + (self.bounding_box.w - w) / 2) y = int(self.bounding_box.y + (self.bounding_box.h - h) / 2) w = size[0] h = size[1] self.shadow_component.content_x = x self.shadow_component.content_y = y self.shadow_component.bounding_box = pygame.Rect(0, 0, w, h) if self.visible: self.draw() b.state.album = album self.notify_change_logo_listeners(b.state)
class RadioBrowserScreen(MenuScreen): """ Radio Browser Screen """ def __init__(self, util, listeners, voice_assistant): """ Initializer :param util: utility object :param listeners: screen event listeners :param voice_assistant: the voice assistant """ self.util = util self.config = util.config self.groups_list = self.util.get_stations_folders() self.factory = Factory(util) self.favorites_util = FavoritesUtil(self.util) rows = self.config[FILE_BROWSER_ROWS] columns = self.config[FILE_BROWSER_COLUMNS] d = [rows, columns] self.page_size = rows * columns MenuScreen.__init__(self, util, listeners, rows, columns, voice_assistant, d, self.turn_page, page_in_title=False) self.total_pages = 0 self.title = "" m = self.create_radio_browser_menu_button button_height = (self.menu_layout.h / rows) - (self.config[PADDING] * 2) bgr = self.config[BACKGROUND][MENU_BGR_COLOR] if self.config[ALIGN_BUTTON_CONTENT_X] == 'center': font_size = int(((100 - STATION_IMAGE_AREA) / 100) * self.config[FONT_HEIGHT_PERCENT]) else: font_size = int( (button_height / 100) * self.config[FONT_HEIGHT_PERCENT]) self.navigator = RadioNavigator(self.util, self.layout.BOTTOM, listeners) self.add_navigator(self.navigator) self.left_button = self.navigator.get_button_by_name(KEY_PAGE_DOWN) self.right_button = self.navigator.get_button_by_name(KEY_PAGE_UP) self.player_button = self.navigator.get_button_by_name(KEY_PLAYER) h = self.config[HORIZONTAL_LAYOUT] self.stations_menu = Menu(util, bgr, self.menu_layout, rows, columns, create_item_method=m, align=ALIGN_CENTER, horizontal_layout=h, font_size=font_size) self.set_menu(self.stations_menu) self.current_page = None self.current_language = self.config[CURRENT][LANGUAGE] self.current_genre = self.util.get_current_genre() self.turn_page() self.animated_title = True def create_radio_browser_menu_button(self, state, constr, action, scale, font_size): """ Factory function for menu button :param state: button state :param constr: bounding box :param action: action listener :param scale: True - sacle, False - don't scale :param font_size: the label font size :return: menu button """ s = copy(state) s.bounding_box = constr s.padding = self.config[PADDING] s.image_area_percent = STATION_IMAGE_AREA label_area_percent = 100 - s.image_area_percent if self.config[ALIGN_BUTTON_CONTENT_X] == 'left': s.image_location = LEFT s.label_location = LEFT s.h_align = H_ALIGN_LEFT elif self.config[ALIGN_BUTTON_CONTENT_X] == 'right': s.image_location = RIGHT s.label_location = RIGHT s.h_align = H_ALIGN_RIGHT elif self.config[ALIGN_BUTTON_CONTENT_X] == 'center': s.image_location = TOP s.label_location = BOTTOM s.h_align = H_ALIGN_CENTER s.v_align = CENTER s.wrap_labels = self.config[WRAP_LABELS] s.fixed_height = font_size s.scaled = True self.util.add_icon(s, self.get_scale_factor(s)) scale = True if hasattr(s, "show_label"): b = self.factory.create_menu_button( s, constr, action, scale, label_area_percent=label_area_percent, show_label=s.show_label, font_size=font_size) else: b = self.factory.create_menu_button( s, constr, action, scale, label_area_percent=label_area_percent, font_size=font_size) b.state.icon_selected_scaled = b.state.icon_base_scaled b.state.icon_selected = s.icon_base return b def get_scale_factor(self, s): """ Calculate scale factor :param s: button state object :return: scale width and height tuple """ bb = s.bounding_box if self.config[ALIGN_BUTTON_CONTENT_X] == 'center': location = TOP else: location = self.config[ALIGN_BUTTON_CONTENT_X] icon_box = self.factory.get_icon_bounding_box(bb, location, self.config[IMAGE_AREA], self.config[IMAGE_SIZE], self.config[PADDING]) icon_box_without_label = self.factory.get_icon_bounding_box( bb, location, 100, 100, self.config[PADDING], False) if self.config[HIDE_FOLDER_NAME]: s.show_label = False w = icon_box_without_label.w h = icon_box_without_label.h else: s.show_label = True w = icon_box.w h = icon_box.h return (w, h) def get_playlist(self, genre=None): """ Get playlist :param genre: the genre :return: the playlist """ if self.current_genre.name == KEY_FAVORITES: return self.favorites_util.get_favorites_playlist() else: return self.util.get_radio_browser_playlist(genre) def get_page(self): """ Get the current page from the playlist :return: the page """ language = self.config[CURRENT][LANGUAGE] genre = self.util.get_current_genre() playlist = self.get_playlist(genre.l_name) playlist_length = len(playlist) self.total_pages = math.ceil(playlist_length / self.page_size) if self.current_page == None or language != self.current_language or self.current_genre != genre: self.current_language = language self.current_genre = genre playlist = self.get_playlist(genre.l_name) playlist_length = len(playlist) self.total_pages = math.ceil(playlist_length / self.page_size) if self.total_pages == 0: self.left_button.change_label("0") self.right_button.change_label("0") self.set_title() return [] self.current_page = self.get_page_by_index() self.set_title() start = (self.current_page - 1) * self.page_size end = self.current_page * self.page_size return playlist[start:end] def get_page_by_index(self): """ Get the page by index :return: the page """ page = None index = self.util.get_current_radio_station_index() if index < self.page_size: page = 1 else: page = math.ceil(index / self.page_size) return page def set_title(self): """ Set the screen title """ genre = self.util.get_current_genre() if genre.name == KEY_FAVORITES: station = self.favorites_util.get_current_favorites_station() else: station = self.util.get_current_radio_station() if station: title = station.comparator_item else: title = "" d = {"current_title": title} self.screen_title.set_text(d) def turn_page(self): """ Turn page """ page = self.get_page() d = self.stations_menu.make_dict(page) self.stations_menu.set_items(d, 0, self.change_station, False) self.favorites_util.mark_favorites(self.stations_menu.buttons) index = self.util.get_current_radio_station_index() menu_selected = self.stations_menu.select_by_index(index) if self.navigator and self.total_pages > 1: self.left_button.change_label(str(self.current_page - 1)) self.right_button.change_label( str(self.total_pages - self.current_page)) else: self.left_button.change_label("0") self.right_button.change_label("0") for b in self.stations_menu.buttons.values(): b.parent_screen = self b.release_listeners.insert(0, self.handle_favorite) self.stations_menu.clean_draw_update() if menu_selected: self.navigator.unselect() self.link_borders() navigator_selected = self.navigator.is_selected() if (len(page) == 0 or (not menu_selected and not navigator_selected)) and self.navigator: self.navigator.unselect() self.player_button.set_selected(True) self.player_button.clean_draw_update() def change_station(self, state): """ Change station :param state: state object """ found = False for b in self.stations_menu.buttons.values(): if b.state == state: found = True break if not found: # after deleting favorite playlist = self.get_playlist(self.current_genre.l_name) index = self.util.get_current_radio_station_index() if playlist and len(playlist) > 0: state = playlist[index] else: state = None if state: state.source = KEY_RADIO_BROWSER state.name = self.util.get_current_genre().name self.util.set_radio_station_index(state.index) else: self.util.set_radio_station_index(None) self.go_player(state) self.set_title() def add_screen_observers(self, update_observer, redraw_observer): """ Add screen observers :param update_observer: observer for updating the screen :param redraw_observer: observer to redraw the whole screen """ self.navigator.add_observers(update_observer, redraw_observer) self.stations_menu.add_menu_observers(update_observer, redraw_observer, release=False) def set_current(self, state=None): """ Set current screen :param state: the source button state object """ self.turn_page() def handle_event(self, event): """ Handle screen event :param event: the event to handle """ self.handle_event_common(event) def handle_favorite(self, state): """ Add/Remove station to/from the favorites :param state: button state """ if state == None or not getattr(state, "long_press", False): return favorites, lang_dict = self.favorites_util.get_favorites_from_config() if self.favorites_util.is_favorite(favorites, state): self.favorites_util.remove_favorite(favorites, state) if self.current_genre.name == KEY_FAVORITES: current_index = state.index if len(favorites) == 0: self.util.set_radio_station_index(None) else: if current_index == 0: self.util.set_radio_station_index(0) else: self.util.set_radio_station_index(current_index - 1) self.turn_page() else: selected_button = self.stations_menu.get_selected_item() if selected_button and len(selected_button.components) == 4: del selected_button.components[3] selected_button.clean_draw_update() else: self.favorites_util.add_favorite(favorites, state) self.favorites_util.mark_favorites(self.stations_menu.buttons)