class StationScreen(Screen): """ Station Screen """ def __init__(self, listeners, util, voice_assistant, screen_mode=STATION): """ Initializer :param util: utility object :param listener: screen menu event listener """ self.util = util self.config = util.config self.factory = Factory(util) self.screen_mode = screen_mode self.bounding_box = util.screen_rect self.favorites_util = FavoritesUtil(self.util) self.top_height = self.config[PLAYER_SCREEN][TOP_HEIGHT_PERCENT] self.bottom_height = self.config[PLAYER_SCREEN][BOTTOM_HEIGHT_PERCENT] self.button_height = self.config[PLAYER_SCREEN][BUTTON_HEIGHT_PERCENT] self.popup_width = self.config[PLAYER_SCREEN][POPUP_WIDTH_PERCENT] self.image_location = self.config[PLAYER_SCREEN][IMAGE_LOCATION] self.layout = self.get_layout() Screen.__init__(self, util, "", self.top_height, voice_assistant, "station_screen_title", True, self.layout.TOP) self.layout = self.get_layout() folders = self.util.get_stations_folders() if folders: panel_layout = self.get_panel_layout(self.layout, LOCATION_RIGHT) panel_layout.set_percent_constraints(self.button_height, self.button_height, 0, 0) self.genres = util.load_stations_folders(panel_layout.BOTTOM) self.genres[ KEY_FAVORITES] = self.favorites_util.get_favorites_button_state( panel_layout.BOTTOM) current_genre_name = list(self.genres.keys())[0] self.current_genre = self.genres[current_genre_name] self.items_per_line = self.items_per_line(self.layout.CENTER.w) items = [] if self.screen_mode == STATION: k = STATIONS + "." + self.config[CURRENT][LANGUAGE] try: self.config[k] self.current_genre = self.genres[self.config[k] [CURRENT_STATIONS]] except: self.config[k] = {} self.config[k][CURRENT_STATIONS] = self.current_genre.name items = self.load_stations( self.config[CURRENT][LANGUAGE], self.current_genre.name, self.items_per_line * self.items_per_line) elif self.screen_mode == STREAM: items = util.load_streams(self.items_per_line * self.items_per_line) self.playlist = Page(items, self.items_per_line, self.items_per_line) self.station_menu = StationMenu( self.playlist, util, screen_mode, self.config[BACKGROUND][SCREEN_BGR_COLOR], self.layout.CENTER) if self.station_menu.is_button_defined(): d = {"current_title": self.station_menu.button.state.l_name} self.screen_title.set_text(d) Container.add_component(self, self.station_menu) self.stop_player = listeners[KEY_STOP] self.create_left_panel(self.layout, listeners) self.create_right_panel(self.layout, listeners) self.home_button.add_release_listener(listeners[KEY_HOME]) if self.screen_mode == STATION: self.genres_button.add_release_listener(listeners[KEY_GENRES]) self.shutdown_button.add_release_listener( self.favorites_util.save_favorites) self.shutdown_button.add_release_listener(listeners[KEY_SHUTDOWN]) self.left_button.add_release_listener( self.station_menu.switch_to_previous_station) self.left_button.add_release_listener(self.update_arrow_button_labels) self.page_down_button.add_release_listener( self.station_menu.switch_to_previous_page) self.page_down_button.add_release_listener( self.update_arrow_button_labels) self.right_button.add_release_listener( self.station_menu.switch_to_next_station) self.right_button.add_release_listener(self.update_arrow_button_labels) self.page_up_button.add_release_listener( self.station_menu.switch_to_next_page) self.page_up_button.add_release_listener( self.update_arrow_button_labels) self.station_menu.add_listener(listeners[KEY_PLAY]) self.station_menu.add_listener(self.screen_title.set_state) self.station_menu.add_listener(self.update_arrow_button_labels) self.station_menu.add_mode_listener(self.mode_listener) self.info_button = None self.info_popup = None self.start_screensaver = listeners[SCREENSAVER] bottom_layout = BorderLayout(self.layout.BOTTOM) bottom_layout.set_percent_constraints(0, 0, 0, self.popup_width) volume_layout = bottom_layout.CENTER volume_layout.w -= 2 volume_layout.x += 1 self.volume = self.factory.create_volume_control(volume_layout) self.volume.add_slide_listener(listeners[KEY_SET_VOLUME]) self.volume.add_slide_listener(listeners[KEY_SET_CONFIG_VOLUME]) self.volume.add_slide_listener(listeners[KEY_SET_SAVER_VOLUME]) self.volume.add_knob_listener(listeners[KEY_MUTE]) self.add_component(self.volume) self.player_screen = True self.add_popup(bottom_layout.RIGHT) if self.current_genre.name == KEY_FAVORITES: self.favorites_mode = True else: self.favorites_mode = False self.favorites_util.set_favorites_in_config(self.items_per_line) self.animated_title = True def get_layout(self): """ Get the layout of the center area of the screen for image and buttons :return: layout rectangle """ layout = BorderLayout(self.bounding_box) k = self.bounding_box.w / self.bounding_box.h percent_menu_width = (100.0 - self.top_height - self.bottom_height) / k panel_width = (100.0 - percent_menu_width) / 2.0 if self.image_location == LOCATION_CENTER: layout.set_percent_constraints(self.top_height, self.bottom_height, panel_width, panel_width) elif self.image_location == LOCATION_LEFT: layout.set_percent_constraints(self.top_height, self.bottom_height, 0, panel_width * 2) elif self.image_location == LOCATION_RIGHT: layout.set_percent_constraints(self.top_height, self.bottom_height, panel_width * 2, 0) return layout def get_panel_layout(self, layout, panel_location): """ Get the layout of the panel for buttons :param layout: layout of the whole central area :param panel_location: panel location: left or right :return: panel layout rectangle """ if self.image_location == LOCATION_CENTER: if panel_location == LOCATION_LEFT: return BorderLayout(layout.LEFT) else: return BorderLayout(layout.RIGHT) elif self.image_location == LOCATION_LEFT: r = layout.RIGHT if panel_location == LOCATION_LEFT: return BorderLayout(Rect(r.x, r.y, r.w / 2, r.h)) else: return BorderLayout( Rect(r.x + r.w / 2 + 1, r.y, r.w / 2 - 1, r.h)) elif self.image_location == LOCATION_RIGHT: r = layout.LEFT if panel_location == LOCATION_LEFT: return BorderLayout(Rect(r.x, r.y, r.w / 2, r.h)) else: return BorderLayout( Rect(r.x + r.w / 2 + 1, r.y, r.w / 2 - 1, r.h)) def add_popup(self, bb): """ Add info popup menu :param bb: bounding box """ self.info_button = self.factory.create_info_button( bb, self.handle_info_button) self.info_popup = self.get_info_popup(self.bounding_box) self.add_component(self.info_button) self.add_component(self.info_popup) def handle_info_button(self, state): """ Handle info button :param state: button state """ self.info_popup.set_visible(True) self.clean_draw_update() def get_info_popup(self, bb): """ Create info popup menu :param bb: bounding box :return: popup menu """ items = [] items.append(CLOCK) items.append(WEATHER) items.append(LYRICS) layout = BorderLayout(bb) layout.set_percent_constraints(self.top_height, 0, 0, self.popup_width) popup = Popup(items, self.util, layout.RIGHT, self.clean_draw_update, self.handle_info_popup_selection) self.right_button.add_label_listener(popup.update_popup) return popup 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 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. """ if genre == KEY_FAVORITES: return self.favorites_util.get_favorites_playlist( language, stations_per_page) else: return self.util.get_stations_playlist(language, genre, stations_per_page) def mode_listener(self, mode): """ Station screen menu mode event listener :param mode: menu mode """ if mode == self.station_menu.STATION_MODE: self.left_button.set_visible(True) self.right_button.set_visible(True) self.page_down_button.set_visible(False) self.page_up_button.set_visible(False) self.left_button.clean_draw_update() self.right_button.clean_draw_update() else: self.left_button.set_visible(False) self.right_button.set_visible(False) self.page_down_button.set_visible(True) self.page_up_button.set_visible(True) if self.playlist.total_pages == 1: self.page_down_button.set_enabled(False) self.page_up_button.set_enabled(False) else: self.page_down_button.set_enabled(True) self.page_up_button.set_enabled(True) self.page_down_button.clean_draw_update() self.page_up_button.clean_draw_update() def update_arrow_button_labels(self, state): """ Update arrow buttons state :param state: button state used for update """ if self.playlist.length == 0: self.stop_player() left = right = "0" self.page_down_button.set_enabled(False) self.page_up_button.set_enabled(False) self.left_button.set_enabled(False) self.right_button.set_enabled(False) else: left = str(self.station_menu.button.state.index) right = str(self.playlist.length - self.station_menu.button.state.index - 1) self.page_down_button.set_enabled(True) self.page_up_button.set_enabled(True) self.left_button.set_enabled(True) self.right_button.set_enabled(True) self.left_button.change_label(left) self.right_button.change_label(right) self.page_down_button.change_label(left) self.page_up_button.change_label(right) def create_left_panel(self, layout, listeners): """ Create Station Screen left panel. Include Shutdown button, Left button and Home button. :param layout: left panel layout :param listeners: event listeners """ panel_layout = self.get_panel_layout(layout, LOCATION_LEFT) panel_layout.set_percent_constraints(self.button_height, self.button_height, 0, 0) left = 0 if self.station_menu.is_button_defined(): left = self.station_menu.button.state.index self.left_button = self.factory.create_left_button( panel_layout.CENTER, str(left), 40, 100) self.page_down_button = self.factory.create_page_down_button( panel_layout.CENTER, str(left), 40, 100) self.page_down_button.set_visible(False) panel_layout.TOP.y += 1 panel_layout.TOP.h -= 2 self.shutdown_button = self.factory.create_shutdown_button( panel_layout.TOP) panel_layout.BOTTOM.h += 1 self.home_button = self.factory.create_button(KEY_HOME, KEY_HOME, panel_layout.BOTTOM, image_size_percent=36) self.shutdown_button.parent_screen = self self.home_button.parent_screen = self self.left_button.parent_screen = self self.page_down_button.parent_screen = self panel = Container(self.util, layout.LEFT) panel.add_component(self.shutdown_button) panel.add_component(self.left_button) panel.add_component(self.page_down_button) panel.add_component(self.home_button) Container.add_component(self, panel) def create_right_panel(self, layout, listeners): """ Create Station Screen right panel. Include Genre button, right button and Play/Pause button :param layout: right panel layout :param listeners: event listeners """ panel_layout = self.get_panel_layout(layout, LOCATION_RIGHT) panel_layout.set_percent_constraints(self.button_height, self.button_height, 0, 0) panel_layout.BOTTOM.h += 1 if self.screen_mode == STATION: self.genres_button = self.factory.create_genre_button( panel_layout.BOTTOM, self.current_genre, PERCENT_GENRE_IMAGE_AREA) elif self.screen_mode == STREAM: self.genres_button = self.factory.create_stream_button( panel_layout.BOTTOM) right = 0 if self.station_menu.is_button_defined(): right = self.playlist.length - self.station_menu.button.state.index - 1 self.right_button = self.factory.create_right_button( panel_layout.CENTER, str(right), 40, 100) self.page_up_button = self.factory.create_page_up_button( panel_layout.CENTER, str(right), 40, 100) self.page_up_button.set_visible(False) panel_layout.TOP.y += 1 panel_layout.TOP.h -= 2 self.play_button = self.factory.create_play_pause_button( panel_layout.TOP, listeners[KEY_PLAY_PAUSE]) self.genres_button.parent_screen = self self.right_button.parent_screen = self self.page_up_button.parent_screen = self self.play_button.parent_screen = self panel = Container(self.util, layout.RIGHT) panel.add_component(self.genres_button) panel.add_component(self.right_button) panel.add_component(self.page_up_button) panel.add_component(self.play_button) Container.add_component(self, panel) def set_genre_button_image(self, genre): """ Set genre button image :param genre: genre button """ if self.favorites_mode: favorites_button_state = self.favorites_util.get_favorites_button_state( self.genres_button.state.bounding_box) self.genres_button.selected = False self.genres_button.set_state(favorites_button_state) else: s = State() s.__dict__ = genre.__dict__ s.bounding_box = self.genres_button.state.bounding_box s.bgr = self.genres_button.bgr s.show_label = False s.keyboard_key = kbd_keys[KEY_MENU] self.factory.scale_genre_button_image(s, PERCENT_GENRE_IMAGE_AREA) self.genres_button.set_state(s) def set_current(self, state=None): """ Set current station by index defined in current playlist :param state: button state (if any) """ items = [] current_language = self.config[CURRENT][LANGUAGE] selected_genre = None self.favorites_mode = False self.sync_state() if self.screen_mode == STATION: key = STATIONS + "." + current_language s1 = state != None and getattr(state, "source", None) == KEY_FAVORITES s2 = state == None and self.config[key][ CURRENT_STATIONS] == KEY_FAVORITES if s1 or s2: self.favorites_mode = True self.config[key][CURRENT_STATIONS] = KEY_FAVORITES try: k = self.config[key][CURRENT_STATIONS] selected_genre = self.genres[k] self.store_previous_station(current_language) except: self.config[key] = {} selected_genre = self.current_genre genre = selected_genre.name size = self.items_per_line * self.items_per_line items = self.load_stations(current_language, genre, size) elif self.screen_mode == STREAM: items = self.util.load_streams(self.items_per_line * self.items_per_line) self.playlist = Page(items, self.items_per_line, self.items_per_line) if self.playlist.length == 0: return self.station_menu.set_playlist(self.playlist) if self.screen_mode == STATION: self.station_menu.genre = selected_genre.name previous_station_index = 0 try: previous_station_index = self.config[ STATIONS + "." + current_language][selected_genre.name] except KeyError: pass src = getattr(state, "source", None) change_mode = getattr(state, "change_mode", False) n = change_mode or (src != KEY_HOME and src != GO_PLAYER and src != KEY_BACK) self.station_menu.set_station(previous_station_index, notify=n) self.station_menu.set_station_mode(None) self.set_genre_button_image(selected_genre) if self.favorites_mode: self.current_genre = self.favorites_util.get_favorites_button_state( self.genres_button.state.bounding_box) else: self.current_genre = selected_genre elif self.screen_mode == STREAM: previous_station_index = 0 try: previous_station_index = self.config[CURRENT][STREAM] except KeyError: pass self.station_menu.set_station(previous_station_index) self.station_menu.set_station_mode(None) self.config[CURRENT][STREAM] = previous_station_index n = self.station_menu.get_current_station_name() self.screen_title.set_text(n) config_volume_level = int(self.config[PLAYER_SETTINGS][VOLUME]) if self.volume.get_position() != config_volume_level: self.volume.set_position(config_volume_level) self.volume.update_position() def sync_state(self): # play-pause button if self.config[PLAYER_SETTINGS][PAUSE]: new_state = "play" else: new_state = "pause" states = self.play_button.states index = 0 for i, s in enumerate(states): if s.name == new_state: index = i break self.play_button.draw_state(index) # mute button if self.config[PLAYER_SETTINGS][MUTE]: self.volume.selected = False else: self.volume.selected = True self.volume.handle_knob_selection(False) def store_previous_station(self, lang): """ Store previous station for the current language :param lang: previous language """ k = STATIONS + "." + lang try: self.config[k] except: self.config[k] = {} try: i = self.station_menu.get_current_station_index() self.config[k][self.current_genre.name] = i except: pass def set_visible(self, flag): """ Set visibility flag :param flag: True - screen visible, False - screen invisible """ self.visible = flag self.screen_title.set_visible(flag) self.station_menu.set_visible(flag) def enable_player_screen(self, flag): """ Enable player screen :param flag: enable/disable flag """ self.screen_title.active = flag def add_screen_observers(self, update_observer, redraw_observer, title_to_json): """ Add screen observers :param update_observer: observer for updating the screen :param redraw_observer: observer to redraw the whole screen """ Screen.add_screen_observers(self, update_observer, redraw_observer, title_to_json) self.add_button_observers(self.shutdown_button, update_observer, redraw_observer=None) self.shutdown_button.add_cancel_listener(redraw_observer) self.screen_title.add_listener(title_to_json) self.add_button_observers(self.play_button, update_observer, redraw_observer=None) self.add_button_observers(self.home_button, update_observer, redraw_observer, release=False) self.add_button_observers(self.info_button, update_observer, redraw_observer) self.info_popup.add_menu_observers(update_observer, redraw_observer) self.add_button_observers(self.left_button, update_observer, redraw_observer, release=False) self.add_button_observers(self.right_button, update_observer, redraw_observer, release=False) self.add_button_observers(self.page_down_button, update_observer, redraw_observer) self.add_button_observers(self.page_up_button, update_observer, redraw_observer) self.volume.add_slide_listener(update_observer) self.volume.add_knob_listener(update_observer) self.volume.add_press_listener(update_observer) self.volume.add_motion_listener(update_observer) self.add_button_observers(self.genres_button, update_observer, redraw_observer, release=False) self.station_menu.add_listener(update_observer) self.station_menu.add_change_logo_listener(redraw_observer)
class PlayerScreen(Screen): """ The Parent for all player screens """ def __init__(self, util, listeners, screen_title, show_arrow_labels=True, show_order=True, show_info=True, show_time_control=True, voice_assistant=None): """ Initializer :param util: utility object :param listeners: screen event listeners :param screen_title: screen title/id :param show_arrow_labels: True - show arrow lables, False - don't show :param show_order: True - show the order button/popup, False - don't show :param show_info: True - show the info button/popup, False - don't show :param show_time_control: True - show the time control, False - don't show :param voice_assistant: the voice assistant """ self.util = util self.config = util.config self.factory = Factory(util) self.player = listeners[KEY_PLAY] self.bounding_box = util.screen_rect self.show_order = show_order self.show_info = show_info self.show_time_control = show_time_control self.order_button = None self.info_button = None self.order_popup = None self.info_popup = None self.top_height = self.config[PLAYER_SCREEN][TOP_HEIGHT_PERCENT] self.bottom_height = self.config[PLAYER_SCREEN][BOTTOM_HEIGHT_PERCENT] self.button_height = self.config[PLAYER_SCREEN][BUTTON_HEIGHT_PERCENT] self.popup_width = self.config[PLAYER_SCREEN][POPUP_WIDTH_PERCENT] self.image_location = self.config[PLAYER_SCREEN][IMAGE_LOCATION] self.layout = self.get_layout() Screen.__init__(self, util, "", self.top_height, voice_assistant, screen_title, True, self.layout.TOP) self.layout = self.get_layout() self.custom_button = None self.center_button = None self.create_left_panel(self.layout, show_arrow_labels) self.create_right_panel(self.layout, show_arrow_labels) self.create_bottom_panel(self.layout.BOTTOM) self.player_screen = True self.animated_title = True self.arrow_keys = [ kbd_keys[KEY_LEFT], kbd_keys[KEY_RIGHT], kbd_keys[KEY_UP], kbd_keys[KEY_DOWN] ] self.player_keys = [kbd_keys[KEY_PLAY_PAUSE], kbd_keys[KEY_MUTE]] self.volume_keys = [kbd_keys[KEY_VOLUME_UP], kbd_keys[KEY_VOLUME_DOWN]] self.previous_next_keys = [ kbd_keys[KEY_PAGE_DOWN], kbd_keys[KEY_PAGE_UP] ] self.playlist = [] self.current_index = 0 def set_listeners(self, listeners): """ Set event listeners :param listeners: the dictionary of the listeners """ self.shutdown_button.add_release_listener(listeners[KEY_SHUTDOWN]) self.home_button.add_release_listener(listeners[KEY_HOME]) self.stop_player = listeners[KEY_STOP] self.start_screensaver = listeners[SCREENSAVER] self.volume.add_slide_listener(listeners[KEY_SET_VOLUME]) self.volume.add_slide_listener(listeners[KEY_SET_CONFIG_VOLUME]) self.volume.add_slide_listener(listeners[KEY_SET_SAVER_VOLUME]) self.volume.add_knob_listener(listeners[KEY_MUTE]) def link_borders(self): """ Link components borders for the arrow keys navigation """ if self.show_order: order_x = self.order_button.bounding_box.x order_y = self.order_button.bounding_box.y home_bottom = self.order_button.bounding_box.y else: order_x = None order_y = None home_bottom = self.volume.bounding_box.y if self.show_info: info_x = self.info_button.bounding_box.x info_y = self.info_button.bounding_box.y else: info_x = None info_y = None self.center_button.ignore_enter_y = False shutdown_x = self.shutdown_button.bounding_box.x shutdown_y = self.shutdown_button.bounding_box.y left_x = self.left_button.bounding_box.x left_y = self.left_button.bounding_box.y home_x = self.home_button.bounding_box.x home_y = self.home_button.bounding_box.y play_x = self.play_button.bounding_box.x play_y = self.play_button.bounding_box.y right_x = self.right_button.bounding_box.x right_y = self.right_button.bounding_box.y custom_x = self.custom_button.bounding_box.x custom_y = self.custom_button.bounding_box.y if self.center_button: center_x = self.center_button.bounding_box.x center_y = self.center_button.bounding_box.y else: center_x = None volume_x = self.volume.bounding_box.x volume_y = self.volume.bounding_box.y if self.image_location == LOCATION_CENTER: if info_x == None: x = volume_x y = volume_y else: x = info_x y = info_y if self.show_order: x_top = order_x y_top = order_y else: x_top = volume_x y_top = volume_y self.set_button_borders(self.shutdown_button, (x, y), (x_top, y_top), (center_x, center_y), (left_x, left_y)) self.set_button_borders(self.left_button, (play_x, play_y), (shutdown_x, shutdown_y), (center_x, left_y), (home_x, home_y)) self.set_button_borders(self.home_button, (right_x, right_y), (left_x, left_y), (center_x, home_y), (x_top, y_top)) self.set_button_borders(self.play_button, (center_x, center_y), (info_x, info_y), (left_x, left_y), (right_x, right_y)) self.set_button_borders(self.right_button, (center_x, right_y), (play_x, play_y), (home_x, home_y), (custom_x, custom_y)) if order_x == None: x = volume_x y = volume_y else: x = order_x y = order_y self.set_button_borders(self.custom_button, (center_x, custom_y), (right_x, right_y), (x, y), (info_x, info_y)) if self.center_button: self.set_button_borders(self.center_button, (left_x, left_y), (volume_x, volume_y), (right_x, right_y), (volume_x, volume_y)) if order_x == None: x_left = custom_x y_left = custom_y else: x_left = order_x y_left = order_y if info_x == None: x_right = shutdown_x y_right = shutdown_y else: x_right = info_x y_right = info_y self.set_button_borders(self.volume, (x_left, y_left), (center_y, center_y), (x_right, y_right), (center_y, center_y)) if self.show_order: self.set_button_borders(self.order_button, (custom_x, custom_y), (home_x, home_y), (volume_x, volume_y), (shutdown_x, shutdown_y)) if self.show_time_control: self.set_button_borders(self.time_control.slider, (x_left, y_left), (center_y, center_y), (x_right, y_right), (center_y, center_y)) if self.show_info: self.set_button_borders(self.info_button, (volume_x, volume_y), (custom_x, custom_y), (shutdown_x, shutdown_y), (play_x, play_y)) elif self.image_location == LOCATION_LEFT: if self.center_button: self.center_button.ignore_enter_y = True self.set_button_borders(self.shutdown_button, (center_x, center_y), (volume_x, volume_y), (play_x, play_y), (left_x, left_y)) self.set_button_borders(self.left_button, (play_x, play_y), (shutdown_x, shutdown_y), (right_x, right_y), (home_x, home_y)) self.set_button_borders(self.home_button, (right_x, right_y), (left_x, left_y), (custom_x, custom_y), (volume_x, volume_y)) if self.show_info: x_top = info_x y_top = info_y else: x_top = volume_x y_top = volume_y self.set_button_borders(self.play_button, (shutdown_x, shutdown_y), (x_top, y_top), (left_x, left_y), (right_x, right_y)) self.set_button_borders(self.right_button, (left_x, left_y), (play_x, play_y), (home_x, home_y), (custom_x, custom_y)) if self.show_order: x_right = order_x y_right = order_y else: x_right = volume_x y_right = volume_y self.set_button_borders(self.custom_button, (home_x, home_y), (right_x, right_y), (x_right, y_right), (info_x, info_y)) if self.center_button: if self.show_info: x_left = info_x y_left = info_y else: x_left = volume_x y_left = volume_y self.set_button_borders(self.center_button, (x_left, y_left), (volume_x, volume_y), (shutdown_x, shutdown_y), (volume_x, volume_y)) if self.show_order and self.show_info: x_left = order_x y_left = order_y x_right = info_x y_right = info_y elif self.show_order and not self.show_info: x_left = order_x y_left = order_y x_right = center_x y_right = center_y elif not self.show_order and self.show_info: x_left = custom_x y_left = custom_y x_right = info_x y_right = info_y elif not self.show_order and not self.show_info: x_left = custom_x y_left = custom_y x_right = center_x y_right = center_y self.set_button_borders(self.volume, (x_left, y_left), (center_x, center_y), (x_right, y_right), (center_x, center_y)) if self.show_time_control: self.set_button_borders(self.time_control.slider, (x_left, y_left), (center_x, center_y), (x_right, y_right), (center_x, center_y)) if self.show_order: self.set_button_borders(self.order_button, (custom_x, custom_y), (center_x, center_y), (volume_x, volume_y), (center_x, center_y)) if self.show_info: self.set_button_borders(self.info_button, (volume_x, volume_y), (custom_x, custom_y), (center_x, center_y), (play_x, play_y)) elif self.image_location == LOCATION_RIGHT: if self.center_button: self.center_button.ignore_enter_y = True if self.show_info: x_left = info_x y_left = info_y else: x_left = volume_x y_left = volume_y if self.show_order: x_top = order_x y_top = order_y else: x_top = volume_x y_top = volume_y self.set_button_borders(self.shutdown_button, (x_left, y_left), (x_top, y_top), (play_x, play_y), (left_x, left_y)) self.set_button_borders(self.left_button, (center_x, center_y), (shutdown_x, shutdown_y), (right_x, right_y), (home_x, home_y)) self.set_button_borders(self.home_button, (right_x, right_y), (left_x, left_y), (custom_x, custom_y), (x_top, y_top)) self.set_button_borders(self.play_button, (shutdown_x, shutdown_y), (volume_x, volume_y), (center_x, center_y), (right_x, right_y)) self.set_button_borders(self.right_button, (left_x, left_y), (play_x, play_y), (home_x, home_y), (custom_x, custom_y)) if self.show_order: x_right = order_x y_right = order_y else: x_right = volume_x y_right = volume_y self.set_button_borders(self.custom_button, (home_x, home_y), (right_x, right_y), (x_right, y_right), (volume_x, volume_y)) if self.center_button: if self.show_info: x_left = info_x y_left = info_y else: x_left = volume_x y_left = volume_y self.set_button_borders(self.center_button, (play_x, play_y), (volume_x, volume_y), (left_x, left_y), (volume_x, volume_y)) if self.show_order and self.show_info: x_left = order_x y_left = order_y x_right = info_x y_right = info_y elif self.show_order and not self.show_info: x_left = order_x y_left = order_y x_right = center_x y_right = center_y elif not self.show_order and self.show_info: x_left = custom_x y_left = custom_y x_right = info_x y_right = info_y elif not self.show_order and not self.show_info: x_left = custom_x y_left = custom_y x_right = center_x y_right = center_y self.set_button_borders(self.volume, (x_left, y_left), (custom_x, custom_y), (x_right, y_right), (play_x, play_y)) if self.show_time_control: self.set_button_borders(self.time_control.slider, (x_left, y_left), (custom_x, custom_y), (x_right, y_right), (play_x, play_y)) if self.show_order: self.set_button_borders(self.order_button, (custom_x, custom_y), (home_x, home_y), (volume_x, volume_y), (shutdown_x, shutdown_y)) if self.show_info: self.set_button_borders(self.info_button, (volume_x, volume_y), (center_x, center_y), (shutdown_x, shutdown_y), (center_x, center_y)) def set_button_borders(self, button, left, top, right, bottom): """ Set button borders :param button: target button :param left: left border :param top: top border :param right: right border :param bottom: bottom border """ margin = 10 if left != None: button.exit_left_x = left[0] + margin button.exit_left_y = left[1] + margin if right != None: button.exit_right_x = right[0] + margin button.exit_right_y = right[1] + margin if top != None: button.exit_top_x = top[0] + margin button.exit_top_y = top[1] + margin if bottom != None: button.exit_bottom_x = bottom[0] + margin button.exit_bottom_y = bottom[1] + margin def get_layout(self): """ Get the layout of the center area of the screen for image and buttons :return: layout rectangle """ layout = BorderLayout(self.bounding_box) top = int(self.bounding_box.h * self.top_height / 100) bottom = int(self.bounding_box.h * self.bottom_height / 100) center = self.bounding_box.h - top - bottom if center % 2 != 0: top -= 1 center += 1 left = right = (self.bounding_box.w - center) / 2 if self.image_location == LOCATION_CENTER: layout.set_pixel_constraints(top, bottom, left, right) elif self.image_location == LOCATION_LEFT: layout.set_pixel_constraints(top, bottom, 0, right * 2) elif self.image_location == LOCATION_RIGHT: layout.set_pixel_constraints(top, bottom, right * 2, 0) return layout def get_panel_layout(self, layout, panel_location): """ Get the layout of the panel for buttons :param layout: layout of the whole central area :param panel_location: panel location - left or right :return: panel layout rectangle """ if self.image_location == LOCATION_CENTER: if panel_location == LOCATION_LEFT: return BorderLayout(layout.LEFT) else: return BorderLayout(layout.RIGHT) elif self.image_location == LOCATION_LEFT: r = layout.RIGHT if panel_location == LOCATION_LEFT: return BorderLayout(Rect(r.x, r.y, r.w / 2, r.h)) else: return BorderLayout( Rect(r.x + r.w / 2 + 1, r.y, r.w / 2 - 1, r.h)) elif self.image_location == LOCATION_RIGHT: r = layout.LEFT if panel_location == LOCATION_LEFT: return BorderLayout(Rect(r.x, r.y, r.w / 2, r.h)) else: return BorderLayout( Rect(r.x + r.w / 2 + 1, r.y, r.w / 2 - 1, r.h)) def create_left_panel(self, layout, arrow_labels): """ Create left side buttons panel :param layout: panel layout :param arrow_labels: show arrow label or not """ panel_layout = self.get_panel_layout(layout, LOCATION_LEFT) panel_layout.set_percent_constraints(self.button_height, self.button_height, 0, 0) self.left_button = self.factory.create_left_button( panel_layout.CENTER, '', 40, 100, arrow_labels) self.left_button.add_release_listener(self.go_left) panel_layout.TOP.y += 1 panel_layout.TOP.h -= 2 self.shutdown_button = self.factory.create_shutdown_button( panel_layout.TOP) panel_layout.BOTTOM.h += 1 self.home_button = self.factory.create_button(KEY_HOME, KEY_HOME, panel_layout.BOTTOM, image_size_percent=36) panel = Container(self.util, layout.LEFT) panel.add_component(self.shutdown_button) panel.add_component(self.left_button) panel.add_component(self.home_button) self.add_component(panel) def create_right_panel(self, layout, arrow_labels): """ Create right side buttons panel :param layout: panel layout :param arrow_labels: show arrow label or not """ panel_layout = self.get_panel_layout(layout, LOCATION_RIGHT) panel_layout.set_percent_constraints(self.button_height, self.button_height, 0, 0) panel_layout.TOP.y += 1 panel_layout.TOP.h -= 2 self.play_button = self.factory.create_play_pause_button( panel_layout.TOP, self.listeners[KEY_PLAY_PAUSE]) self.right_button = self.factory.create_right_button( panel_layout.CENTER, '', 40, 100, arrow_labels) self.right_button.add_release_listener(self.go_right) panel_layout.BOTTOM.h += 1 self.custom_button_layout = panel_layout.BOTTOM panel = Container(self.util, layout.RIGHT) panel.add_component(self.play_button) panel.add_component(self.right_button) self.right_panel = panel self.add_component(panel) def create_bottom_panel(self, layout): """ Create bottom panel :param layout: panel layout """ self.playback_order = self.config[PLAYER_SETTINGS][PLAYBACK_ORDER] if self.show_order or self.show_info: self.add_popups(layout) self.bottom_center_layout.x -= 1 self.bottom_center_layout.y += 1 self.bottom_center_layout.w += 1 self.bottom_center_layout.h -= 1 self.volume = self.factory.create_volume_control( self.bottom_center_layout) self.volume_visible = False self.volume.set_visible(self.volume_visible) self.add_component(self.volume) if self.show_time_control: self.time_control = self.factory.create_time_control(layout) if self.config[PLAYER_SETTINGS][PAUSE]: self.time_control.pause() self.time_control.slider.handle_knob_events = False self.add_component(self.time_control) else: self.time_control = None def add_popups(self, layout): """ Add popup menus - playback order & info :param layout: bottom panel layout """ self.bottom_layout = BorderLayout(layout) if self.show_order and not self.show_info: self.bottom_layout.set_percent_constraints(0, 0, self.popup_width, 0) self.order_button = self.factory.create_order_button( self.bottom_layout.LEFT, self.handle_order_button, self.playback_order) self.order_popup = self.get_order_popup(self.bounding_box) self.add_component(self.order_button) elif self.show_order and self.show_info: self.bottom_layout.set_percent_constraints(0, 0, self.popup_width, self.popup_width) self.order_button = self.factory.create_order_button( self.bottom_layout.LEFT, self.handle_order_button, self.playback_order) self.info_button = self.factory.create_info_button( self.bottom_layout.RIGHT, self.handle_info_button) self.order_popup = self.get_order_popup(self.bounding_box) self.info_popup = self.get_info_popup(self.bounding_box) self.add_component(self.order_button) self.add_component(self.info_button) elif not self.show_order and self.show_info: self.bottom_layout.set_percent_constraints(0, 0, 0, self.popup_width) self.bottom_layout.RIGHT.y += 1 self.bottom_layout.RIGHT.h -= 1 self.info_button = self.factory.create_info_button( self.bottom_layout.RIGHT, self.handle_info_button) self.info_popup = self.get_info_popup(self.bounding_box) self.add_component(self.info_button) self.bottom_layout.CENTER.w -= 2 self.bottom_layout.CENTER.x += 1 self.bottom_center_layout = self.bottom_layout.CENTER def handle_order_button(self, state): """ Handle playback order button :param state: button state """ self.order_popup.set_visible(True) self.clean_draw_update() def handle_info_button(self, state): """ Handle info button :param state: button state """ self.info_popup.set_visible(True) self.clean_draw_update() def get_order_popup(self, bb): """ Create playback order popup menu :param bb: bounding box :return: popup menu """ items = [] items.append(PLAYBACK_CYCLIC) items.append(PLAYBACK_REGULAR) items.append(PLAYBACK_SINGLE_TRACK) items.append(PLAYBACK_SHUFFLE) items.append(PLAYBACK_SINGLE_CYCLIC) layout = BorderLayout(bb) layout.set_percent_constraints(self.top_height, 0, self.popup_width, 0) popup = Popup(items, self.util, layout.LEFT, self.update_screen, self.handle_order_popup_selection, default_selection=self.playback_order) return popup def get_info_popup(self, bb): """ Create info popup menu :param bb: bounding box :return: popup menu """ items = [] mode = self.config[CURRENT][MODE] items.append(CLOCK) items.append(WEATHER) items.append(LYRICS) if mode == AUDIO_FILES or mode == COLLECTION: items.append(FILE_INFO) layout = BorderLayout(bb) layout.set_percent_constraints(self.top_height, 0, 0, self.popup_width) popup = Popup(items, self.util, layout.RIGHT, self.update_screen, self.handle_info_popup_selection) return popup def update_screen(self): """ Update the screen """ self.clean_draw_update() self.redraw_observer() def handle_order_popup_selection(self, state): """ Handle playback order menu selection :param state: button state """ b = self.factory.create_order_button(self.bottom_layout.LEFT, self.handle_order_button, state.name) i = self.components.index(self.order_button) self.components[i] = b self.order_button = b self.add_button_observers(self.order_button, self.update_observer, self.redraw_observer) self.order_button.set_selected(True) self.order_button.clean_draw_update() self.current_button = self.order_button self.link_borders() self.config[PLAYER_SETTINGS][PLAYBACK_ORDER] = state.name def get_listener(self, listeners, name): """ Return listener by name/key in the dictionary :param listeners: all listeners :param name: listener name :return: listener if avaialble, None - otherwise """ if name in listeners.keys(): return listeners[name] else: return None def set_current(self, state=None): """ Player specific function :param state: the source button state """ pass def set_visible(self, flag): """ Set visibility flag :param flag: True - screen visible, False - screen invisible """ Container.set_visible(self, flag) if self.time_control == None: return if flag: if self.volume_visible: self.volume.set_visible(True) if self.show_time_control: self.time_control.set_visible(False) else: self.volume.set_visible(False) if self.show_time_control: self.time_control.set_visible(True) def add_screen_observers(self, update_observer, redraw_observer, title_to_json, start_time_control=None, stop_time_control=None): """ Add screen observers :param update_observer: observer for updating the screen :param redraw_observer: observer to redraw the whole screen :param title_to_json: :param start_time_control: :param stop_time_control: """ self.update_observer = update_observer self.redraw_observer = redraw_observer Screen.add_screen_observers(self, update_observer, redraw_observer, title_to_json) self.add_button_observers(self.shutdown_button, update_observer, redraw_observer=None) self.shutdown_button.add_cancel_listener(redraw_observer) self.screen_title.add_listener(title_to_json) self.add_button_observers(self.play_button, update_observer, redraw_observer=None) self.add_button_observers(self.home_button, update_observer, redraw_observer) if self.order_button: self.add_button_observers(self.order_button, update_observer, redraw_observer) if self.info_button: self.add_button_observers(self.info_button, update_observer, redraw_observer) self.add_button_observers(self.left_button, update_observer, redraw_observer=None) self.left_button.add_label_listener(update_observer) self.add_button_observers(self.right_button, update_observer, redraw_observer=None) self.right_button.add_label_listener(update_observer) self.volume.add_slide_listener(update_observer) self.volume.add_knob_listener(update_observer) self.volume.add_press_listener(update_observer) self.volume.add_motion_listener(update_observer) if self.center_button: self.add_button_observers(self.center_button, update_observer, redraw_observer, press=False, release=False) if self.order_popup: self.order_popup.add_menu_observers(update_observer, redraw_observer) if self.info_popup: self.info_popup.add_menu_observers(update_observer, redraw_observer) if self.show_time_control: self.add_button_observers(self.time_volume_button, update_observer, redraw_observer, release=False) self.time_control.web_seek_listener = update_observer if start_time_control: self.time_control.add_start_timer_listener(start_time_control) if stop_time_control: self.time_control.add_stop_timer_listener(stop_time_control) self.time_control.slider.add_slide_listener(update_observer) self.time_control.slider.add_knob_listener(update_observer) self.time_control.slider.add_press_listener(update_observer) self.time_control.slider.add_motion_listener(update_observer) def handle_event(self, event): """ Handle screen event :param event: the event to handle """ if not self.visible: return mouse_events = [ pygame.MOUSEBUTTONUP, pygame.MOUSEBUTTONDOWN, pygame.MOUSEMOTION ] if event.type in mouse_events: self.handle_mouse(event) elif event.type == USER_EVENT_TYPE: self.handle_user_event(event) elif event.type == SELECT_EVENT_TYPE: self.handle_select_action(event) def handle_mouse(self, event): """ Mouse event dispatcher :param event: the event to handle """ button = self.get_collided_button(event) if button and event.type == pygame.MOUSEBUTTONDOWN: self.handle_mouse_down(event, button) elif button and event.type == pygame.MOUSEBUTTONUP: self.handle_mouse_up(event, button) elif event.type == pygame.MOUSEMOTION: self.handle_mouse_motion(event) return Container.handle_event(self, event) self.redraw_observer() def handle_mouse_down(self, event, button): """ Handle mouse button down event :param event: the event to handle :param button: the clicked button """ if not ((self.time_control and button == self.time_control.slider) or button == self.volume): if hasattr( self, "current_button" ) and self.time_control and self.current_button == self.time_control.slider: self.time_control.slider.set_knob_off() elif hasattr( self, "current_button") and self.current_button == self.volume: self.volume.set_knob_off() elif hasattr(self, "current_button" ) and self.current_button != self.center_button: self.current_button.set_selected(False) self.current_button.clean_draw_update() else: if hasattr(self, "current_button") and ( button != self.volume or (button == self.volume and not self.volume.knob_selected)): self.current_button.set_selected(False) self.current_button.clean_draw_update() if self.current_button != button: self.current_button.set_selected(False) self.current_button.clean_draw_update() self.current_button = button def handle_mouse_up(self, event, button): """ Handle mouse button up event :param event: the event to handle :param button: the clicked button """ if self.config[PLAYER_SETTINGS][MUTE] and button != self.volume: prev_pos = event.pos event.pos = self.volume.get_knob_center() self.volume.selected = True self.volume.handle_event(event) event.pos = prev_pos self.volume.selected = False self.volume.clicked = False self.volume.set_knob_off() if ( (self.time_control and button == self.time_control.slider) or button == self.volume ) and self.current_button != self.volume and self.time_control and self.current_button != self.time_control.slider: self.current_button.set_selected(False) self.current_button.clean_draw_update() self.current_button = button def handle_mouse_motion(self, event): """ Handle mouse button up event :param event: the event to handle """ if self.volume.clicked: self.volume.handle_event(event) elif self.time_control and self.time_control.slider.clicked: self.time_control.handle_event(event) def handle_user_event(self, event): """ User event dispatcher :param event: the event to handle """ k = event.keyboard_key if k in self.arrow_keys: self.handle_arrow_key(event) elif k == kbd_keys[KEY_PLAY_PAUSE]: self.handle_play_key(event) elif k == kbd_keys[KEY_MUTE]: self.handle_mute_key(event) elif k in self.volume_keys: self.handle_volume_key(event) elif k in self.previous_next_keys: self.handle_previous_next_key(event) elif k == kbd_keys[KEY_HOME]: self.handle_home_key(event) elif k == kbd_keys[KEY_SELECT]: self.handle_select_key(event) def handle_previous_next_key(self, event): """ Next/previous keys handler :param event: the event to handle """ k = event.keyboard_key button = None if k == kbd_keys[KEY_PAGE_DOWN]: button = self.left_button elif k == kbd_keys[KEY_PAGE_UP]: button = self.right_button if button: if self.current_button == self.volume: self.volume.set_knob_off() else: self.current_button.set_selected(False) self.current_button.clean_draw_update() button.handle_event(event) button.clean_draw_update() self.current_button = button def handle_arrow_key(self, event): """ Arrow keys handler :param event: the event to handle """ Container.handle_event(self, event) if self.config[PLAYER_SETTINGS][MUTE] and event.action == pygame.KEYUP: event.keyboard_key = kbd_keys[KEY_MUTE] self.volume.selected = True self.volume.handle_event(event) self.current_button = self.volume self.update_web_observer() def handle_play_key(self, event): """ Play/pause keys handler :param event: the event to handle """ if event.action == pygame.KEYDOWN: self.current_button.set_selected(False) self.current_button.clean_draw_update() self.update_web_observer() self.current_button = self.play_button Container.handle_event(self, event) def handle_mute_key(self, event): """ Mute key handler :param event: the event to handle """ if not self.volume.visible: return if event.action == pygame.KEYDOWN: self.current_button.set_selected(False) self.current_button.clean_draw_update() self.update_web_observer() self.volume.set_knob_on() self.current_button = self.volume Container.handle_event(self, event) def handle_volume_key(self, event): """ Volume Up/Down keys handler :param event: the event to handle """ if not self.volume.visible: return if self.order_button and self.order_popup.visible: self.order_popup.handle_outside_event(event) if self.info_button and self.info_popup.visible: self.info_popup.handle_outside_event(event) if not self.config[PLAYER_SETTINGS][ MUTE] and event.action == pygame.KEYDOWN: if self.current_button != self.volume: self.current_button.set_selected(False) self.current_button.clean_draw_update() self.volume.selected = True self.volume.handle_event(event) self.current_button = self.volume elif not self.config[PLAYER_SETTINGS][ MUTE] and event.action == pygame.KEYUP: self.volume.handle_event(event) self.update_web_observer() def handle_home_key(self, event): """ Home key handler :param event: the event to handle """ if self.current_button != self.home_button: self.current_button.set_selected(False) self.home_button.handle_event(event) self.current_button = self.home_button self.current_button.set_selected(True) def handle_select_key(self, event): """ Select key handler :param event: the event to handle """ if event.action == pygame.KEYUP: if self.order_button and self.order_button.selected and not self.order_popup.visible: self.order_button.handle_event(event) elif self.info_button and self.info_button.selected and not self.info_popup.visible: self.info_button.handle_event(event) else: if not ((self.order_button and self.order_popup.visible) or (self.info_button and self.info_popup.visible)): if hasattr(self, "current_button"): self.current_button.handle_event(event) else: Container.handle_event(self, event) self.update_web_observer() elif event.action == pygame.KEYDOWN: if hasattr(self, "current_button"): self.current_button.handle_event(event) def get_collided_button(self, event): """ Get clicked button by click point coordinates :param event: the event :return: the button clicked """ if (self.order_popup and self.order_popup.visible) or (self.info_popup and self.info_popup.visible): return None pos = getattr(event, "pos", None) if pos == None: pos = (event.x, event.y) button = None if self.shutdown_button.bounding_box.collidepoint(pos): button = self.shutdown_button elif self.left_button.bounding_box.collidepoint(pos): button = self.left_button elif self.home_button.bounding_box.collidepoint(pos): button = self.home_button elif self.order_button and self.order_button.bounding_box.collidepoint( pos): button = self.order_button elif self.play_button.bounding_box.collidepoint(pos): button = self.play_button elif self.right_button.bounding_box.collidepoint(pos): button = self.right_button elif self.custom_button and self.custom_button.bounding_box.collidepoint( pos): button = self.custom_button elif self.info_button and self.info_button.bounding_box.collidepoint( pos): button = self.info_button elif self.center_button and self.center_button.bounding_box.collidepoint( pos): button = self.center_button else: if self.time_control and self.time_control.visible and self.time_control.slider.bounding_box.collidepoint( pos): button = self.time_control.slider elif self.volume.visible and self.volume.bounding_box.collidepoint( pos): button = self.volume return button def handle_select_action(self, event): """ Handle select action :param event: the event """ button = self.get_collided_button(event) if button: if self.time_control and button == self.time_control.slider: self.time_control.slider.set_knob_on() elif button == self.volume: self.volume.set_knob_on() else: button.enter_y = event.y self.select_button(button) self.current_button = button self.update_web_observer() def select_button(self, button): """ Select button :param button: the button to select """ if hasattr(self.current_button, "set_selected"): self.current_button.set_selected(False) if hasattr(button, "set_selected"): button.set_selected(True) button.clean_draw_update() def update_arrow_button_labels(self): """ Update arrow buttons state """ if len(self.playlist) == 0: left = right = "0" else: left = str(self.current_index) right = str(len(self.playlist) - self.current_index - 1) self.left_button.change_label(left) self.right_button.change_label(right) def go_left(self, state): """ Switch to the previous item :param state: not used state object """ playlist_size = len(self.playlist) if playlist_size == 0: return if self.current_index == 0: self.current_index = playlist_size - 1 else: self.current_index -= 1 self.change_item() def go_right(self, state): """ Switch to the next item :param state: not used state object """ playlist_size = len(self.playlist) if playlist_size == 0: return if self.current_index == playlist_size - 1: self.current_index = 0 else: self.current_index += 1 self.change_item() def change_item(self): """ Update item """ self.play_button.draw_default_state(None) self.set_current_item(self.current_index) self.update_arrow_button_labels() self.update_center_button() self.update_web_observer() self.play() def set_current_item(self, index): """ Spsecific for each player. Sets config item """ pass def set_title(self, current_item): """ Set screen title :param current_item: the current button state object """ d = {"current_title": getattr(current_item, "comparator_item", "")} flag = self.screen_title.active self.enable_player_screen(True) self.screen_title.set_text(d) self.enable_player_screen(flag) def update_center_button(self): """ Update the center button """ current_state = self.playlist[self.current_index] current_state.bounding_box = self.layout.CENTER self.util.add_icon(current_state) button = self.get_center_button(current_state) self.center_button.state = button.state self.center_button.components = button.components self.center_button.clean_draw_update() self.set_title(current_state) def play(self): """ Start playback """ if hasattr(self, "center_button") and self.center_button != None and hasattr( self.center_button, "state"): self.center_button.state.volume = self.config[PLAYER_SETTINGS][ VOLUME] self.play_button.draw_default_state(None) self.config[PLAYER_SETTINGS][PAUSE] = False self.player(self.center_button.state) def enable_player_screen(self, flag): """ Enable player screen :param flag: enable/disable flag """ self.screen_title.active = flag
class FilePlayerScreen(Screen): """ File Player Screen """ def __init__(self, listeners, util, get_current_playlist, voice_assistant, player_stop=None, arrow_labels=True, active_file_button=True, show_time_control=True, show_order=True, show_info=True): """ Initializer :param listeners: screen listeners :param util: utility object :param get_current_playlist: current playlist getter :param voice_assistant: voice assistant :param player_stop: stop player function """ self.util = util self.config = util.config self.cdutil = CdUtil(util) self.factory = Factory(util) self.image_util = util.image_util self.top_height = self.config[PLAYER_SCREEN][TOP_HEIGHT_PERCENT] self.bottom_height = self.config[PLAYER_SCREEN][BOTTOM_HEIGHT_PERCENT] self.button_height = self.config[PLAYER_SCREEN][BUTTON_HEIGHT_PERCENT] self.popup_width = self.config[PLAYER_SCREEN][POPUP_WIDTH_PERCENT] self.image_location = self.config[PLAYER_SCREEN][IMAGE_LOCATION] self.stop_player = player_stop self.get_current_playlist = get_current_playlist self.show_time_control = show_time_control self.bounding_box = util.screen_rect self.layout = self.get_layout() self.voice_assistant = voice_assistant Screen.__init__(self, util, "", self.top_height, voice_assistant, "file_player_screen_title", True, self.layout.TOP) self.layout = self.get_layout() self.create_left_panel(self.layout, listeners, arrow_labels) self.create_right_panel(self.layout, listeners, arrow_labels) if not active_file_button: listeners[AUDIO_FILES] = None self.file_button = self.factory.create_file_button( self.layout.CENTER, listeners[AUDIO_FILES]) self.add_component(self.file_button) self.audio_files = self.get_audio_files() self.home_button.add_release_listener(listeners[KEY_HOME]) self.shutdown_button.add_release_listener(listeners[KEY_SHUTDOWN]) self.left_button.add_release_listener(self.go_left) self.right_button.add_release_listener(self.go_right) self.show_order = show_order self.show_info = show_info self.order_button = None self.info_button = None self.order_popup = None self.info_popup = None self.playback_order = self.config[PLAYER_SETTINGS][PLAYBACK_ORDER] self.bottom_center_layout = self.layout.BOTTOM if self.show_order or self.show_info: self.start_screensaver = listeners[SCREENSAVER] self.go_info_screen = listeners[KEY_INFO] self.add_popups() self.volume = self.factory.create_volume_control( self.bottom_center_layout) self.volume.add_slide_listener( self.get_listener(listeners, KEY_SET_VOLUME)) self.volume.add_slide_listener( self.get_listener(listeners, KEY_SET_CONFIG_VOLUME)) self.volume.add_slide_listener( self.get_listener(listeners, KEY_SET_SAVER_VOLUME)) self.volume.add_knob_listener(self.get_listener(listeners, KEY_MUTE)) self.volume_visible = False self.volume.set_visible(self.volume_visible) self.add_component(self.volume) if self.show_time_control: self.time_control = self.factory.create_time_control( self.bottom_center_layout) if KEY_SEEK in listeners.keys(): self.time_control.add_seek_listener(listeners[KEY_SEEK]) self.play_button.add_listener(PAUSE, self.time_control.pause) self.play_button.add_listener(KEY_PLAY, self.time_control.resume) if self.config[PLAYER_SETTINGS][PAUSE]: self.time_control.pause() self.add_component(self.time_control) self.left_button.add_release_listener( self.play_button.draw_default_state) self.right_button.add_release_listener( self.play_button.draw_default_state) self.play_listeners = [] self.add_play_listener(self.get_listener(listeners, KEY_PLAY)) self.current_folder = self.config[FILE_PLAYBACK][CURRENT_FOLDER] self.file_button.state.cover_art_folder = self.util.file_util.get_cover_art_folder( self.current_folder) self.playlist_size = 0 self.player_screen = True self.cd_album = None self.animated_title = True if self.order_popup: Container.add_component(self, self.order_popup) if self.info_popup: Container.add_component(self, self.info_popup) def get_layout(self): """ Get the layout of the center area of the screen for image and buttons :return: layout rectangle """ layout = BorderLayout(self.bounding_box) k = self.bounding_box.w / self.bounding_box.h percent_menu_width = (100.0 - self.top_height - self.bottom_height) / k panel_width = (100.0 - percent_menu_width) / 2.0 if self.image_location == LOCATION_CENTER: layout.set_percent_constraints(self.top_height, self.bottom_height, panel_width, panel_width) elif self.image_location == LOCATION_LEFT: layout.set_percent_constraints(self.top_height, self.bottom_height, 0, panel_width * 2) elif self.image_location == LOCATION_RIGHT: layout.set_percent_constraints(self.top_height, self.bottom_height, panel_width * 2, 0) return layout def get_panel_layout(self, layout, panel_location): """ Get the layout of the panel for buttons :param layout: layout of the whole central area :param panel_location: panel location: left or right :return: panel layout rectangle """ if self.image_location == LOCATION_CENTER: if panel_location == LOCATION_LEFT: return BorderLayout(layout.LEFT) else: return BorderLayout(layout.RIGHT) elif self.image_location == LOCATION_LEFT: r = layout.RIGHT if panel_location == LOCATION_LEFT: return BorderLayout(Rect(r.x, r.y, r.w / 2, r.h)) else: return BorderLayout( Rect(r.x + r.w / 2 + 1, r.y, r.w / 2 - 1, r.h)) elif self.image_location == LOCATION_RIGHT: r = layout.LEFT if panel_location == LOCATION_LEFT: return BorderLayout(Rect(r.x, r.y, r.w / 2, r.h)) else: return BorderLayout( Rect(r.x + r.w / 2 + 1, r.y, r.w / 2 - 1, r.h)) def add_popups(self): """ Add popup menus: playback order & info """ self.bottom_layout = BorderLayout(self.layout.BOTTOM) if self.show_order and not self.show_info: self.bottom_layout.set_percent_constraints(0, 0, self.popup_width, 0) self.order_button = self.factory.create_order_button( self.bottom_layout.LEFT, self.handle_order_button, self.playback_order) self.order_popup = self.get_order_popup(self.bounding_box) self.add_component(self.order_button) elif self.show_order and self.show_info: self.bottom_layout.set_percent_constraints(0, 0, self.popup_width, self.popup_width) self.order_button = self.factory.create_order_button( self.bottom_layout.LEFT, self.handle_order_button, self.playback_order) self.info_button = self.factory.create_info_button( self.bottom_layout.RIGHT, self.handle_info_button) self.order_popup = self.get_order_popup(self.bounding_box) self.info_popup = self.get_info_popup(self.bounding_box) self.add_component(self.order_button) self.add_component(self.info_button) elif not self.show_order and self.show_info: self.bottom_layout.set_percent_constraints(0, 0, 0, self.popup_width) self.info_button = self.factory.create_info_button( self.bottom_layout.RIGHT, self.handle_info_button) self.info_popup = self.get_info_popup(self.bounding_box) self.add_component(self.info_button) self.bottom_layout.CENTER.w -= 2 self.bottom_layout.CENTER.x += 1 self.bottom_center_layout = self.bottom_layout.CENTER def handle_order_button(self, state): """ Handle playback order button :param state: button state """ self.order_popup.set_visible(True) self.clean_draw_update() def handle_info_button(self, state): """ Handle info button :param state: button state """ self.info_popup.set_visible(True) self.clean_draw_update() def get_order_popup(self, bb): """ Create playback order popup menu :param bb: bounding box :return: popup menu """ items = [] items.append(PLAYBACK_CYCLIC) items.append(PLAYBACK_REGULAR) items.append(PLAYBACK_SINGLE_TRACK) items.append(PLAYBACK_SHUFFLE) items.append(PLAYBACK_SINGLE_CYCLIC) layout = BorderLayout(bb) layout.set_percent_constraints(self.top_height, 0, self.popup_width, 0) popup = Popup(items, self.util, layout.LEFT, self.clean_draw_update, self.handle_order_popup_selection, default_selection=self.playback_order) self.left_button.add_label_listener(popup.update_popup) return popup def get_info_popup(self, bb): """ Create info popup menu :param bb: bounding box :return: popup menu """ items = [] mode = self.config[CURRENT][MODE] items.append(CLOCK) items.append(WEATHER) items.append(LYRICS) if mode == AUDIO_FILES or mode == COLLECTION: items.append(FILE_INFO) layout = BorderLayout(bb) layout.set_percent_constraints(self.top_height, 0, 0, self.popup_width) popup = Popup(items, self.util, layout.RIGHT, self.clean_draw_update, self.handle_info_popup_selection) self.right_button.add_label_listener(popup.update_popup) return popup def handle_order_popup_selection(self, state): """ Handle playback order menu selection :param state: button state """ b = self.factory.create_order_button(self.bottom_layout.LEFT, self.handle_order_button, state.name) i = self.components.index(self.order_button) self.components[i] = b self.order_button = b self.add_button_observers(self.order_button, self.update_observer, self.redraw_observer) self.order_button.clean_draw_update() self.config[PLAYER_SETTINGS][PLAYBACK_ORDER] = state.name def handle_info_popup_selection(self, state): """ Handle info menu selection :param state: button state """ n = state.name if n == CLOCK or n == WEATHER: self.start_screensaver(n) elif n == LYRICS: a = None try: m = self.util.get_file_metadata() a = m["artist"] + " - " + m["title"] except: pass if a != None: s = State() s.album = a self.start_screensaver(n, s) else: self.start_screensaver(n) else: self.go_info_screen(state) def get_audio_files(self): """ Return the list of audio files in current folder :return: list of audio files """ files = [] if self.config[CURRENT][MODE] == CD_PLAYER: af = getattr(self, "audio_files", None) if af == None: cd_drive_name = self.config[CD_PLAYBACK][CD_DRIVE_NAME] files = self.cdutil.get_cd_tracks_summary(cd_drive_name) else: return self.audio_files else: folder = self.config[FILE_PLAYBACK][CURRENT_FOLDER] files = self.util.get_audio_files_in_folder(folder) return files def get_current_track_index(self, state=None): """ Return current track index. In case of files goes through the file list. In case of playlist takes track index from the state object. :param state: button state :return: current track index """ if self.config[CURRENT][MODE] == AUDIOBOOKS: t = None try: t = state["file_name"] except: pass if t == None: try: t = state["current_title"] except: pass if t == None: try: t = state except: pass for i, f in enumerate(self.audio_files): try: s = f["file_name"] except: pass if getattr(f, "file_name", None): s = getattr(f, "file_name", None) if s.endswith(t): return i return 0 mode = self.config[FILE_PLAYBACK][CURRENT_FILE_PLAYBACK_MODE] if state and mode == FILE_PLAYLIST: try: n = state["Track"] if n: return int(n) - 1 except: pass if self.config[CURRENT][MODE] == CD_PLAYER: cmp = int(self.config[CD_PLAYBACK][CD_TRACK]) - 1 else: cmp = self.config[FILE_PLAYBACK][CURRENT_FILE] if state and isinstance(state, State): cmp = state.file_name for f in self.audio_files: if self.config[CURRENT][MODE] == CD_PLAYER: if f.index == cmp: return f.index else: if f.file_name == cmp: return f.index return 0 def stop_recursive_playback(self): """ Stop recursive playback """ self.config[FILE_PLAYBACK][CURRENT_FILE_PLAYBACK_MODE] = FILE_AUDIO self.config[FILE_PLAYBACK][CURRENT_FILE_PLAYLIST] = None self.config[FILE_PLAYBACK][CURRENT_TRACK_TIME] = None self.stop_timer() if self.show_time_control: self.time_control.stop_thread() self.time_control.reset() if self.stop_player != None: self.stop_player() def go_left(self, state): """ Switch to the previous track :param state: not used state object """ if getattr(self, "current_track_index", None) == None: return filelist_size = self.get_filelist_size() if self.config[FILE_PLAYBACK][ CURRENT_FILE_PLAYBACK_MODE] == FILE_RECURSIVE: self.stop_recursive_playback() return if self.current_track_index == 0: self.current_track_index = filelist_size - 1 else: self.current_track_index -= 1 self.change_track(self.current_track_index) def go_right(self, state): """ Switch to the next track :param state: not used state object """ if getattr(self, "current_track_index", None) == None: return filelist_size = self.get_filelist_size() if self.config[FILE_PLAYBACK][ CURRENT_FILE_PLAYBACK_MODE] == FILE_RECURSIVE and self.current_track_index == filelist_size - 1: self.stop_timer() if self.show_time_control: self.time_control.stop_thread() self.recursive_change_folder() self.current_track_index = 0 self.change_track(self.current_track_index) self.file_button.clean_draw_update() return if self.current_track_index == filelist_size - 1: self.current_track_index = 0 else: self.current_track_index += 1 self.change_track(self.current_track_index) def get_filelist_size(self): """ Return the file list size :return: file list size """ if self.audio_files: return len(self.audio_files) else: return 0 def change_track(self, track_index): """ Change track :param track_index: index track """ a = [AUDIOBOOKS, CD_PLAYER] m = self.config[CURRENT][MODE] if not (m in a): self.config[FILE_PLAYBACK][CURRENT_FILE] = self.get_filename( track_index) self.stop_timer() time.sleep(0.3) s = State() if m == FILE_PLAYBACK: s.playback_mode = self.config[FILE_PLAYBACK][ CURRENT_FILE_PLAYBACK_MODE] s.playlist_track_number = track_index s.index = track_index s.source = ARROW_BUTTON s.file_name = self.get_filename(track_index) if self.cd_album != None: s.album = self.cd_album if self.config[CURRENT][MODE] == AUDIO_FILES: folder = self.current_folder if not folder.endswith(os.sep): folder += os.sep s.url = folder + s.file_name self.set_current(True, s) def stop_timer(self): """ Stop time control timer """ if self.show_time_control: self.time_control.stop_timer() def get_filename(self, index): """ Get filename by index :param index: file index :return: filename """ for b in self.audio_files: if b.index == index: return b.file_name return "" def is_valid_mode(self): current_mode = self.config[CURRENT][MODE] modes = [AUDIO_FILES, AUDIOBOOKS, CD_PLAYER] if current_mode in modes: return True else: return False def update_arrow_button_labels(self, state=None): """ Update left/right arrow button labels :param state: state object representing current track """ if (not self.is_valid_mode()) or (not self.screen_title.active): return self.set_current_track_index(state) left = self.current_track_index right = 0 if self.audio_files and len(self.audio_files) > 1: right = len(self.audio_files) - self.current_track_index - 1 self.left_button.change_label(str(left)) self.right_button.change_label(str(right)) def set_current_track_index(self, state): """ Set current track index :param state: state object representing current track """ if not self.is_valid_mode(): return if self.config[CURRENT][MODE] == CD_PLAYER and getattr( state, "cd_track_id", None): self.config[CD_PLAYBACK][CD_TRACK] = state["cd_track_id"] self.current_track_index = 0 if self.playlist_size == 1: return if not self.audio_files: self.audio_files = self.get_audio_files() if not self.audio_files: return i = self.get_current_track_index(state) self.current_track_index = i def create_left_panel(self, layout, listeners, arrow_labels): """ Create left side buttons panel :param layout: panel layout :param listeners: button listeners :param arrow_labels: show arrow label or not """ panel_layout = self.get_panel_layout(layout, LOCATION_LEFT) panel_layout.set_percent_constraints(self.button_height, self.button_height, 0, 0) self.left_button = self.factory.create_left_button( panel_layout.CENTER, '', 40, 100, arrow_labels) panel_layout.TOP.y += 1 panel_layout.TOP.h -= 2 self.shutdown_button = self.factory.create_shutdown_button( panel_layout.TOP) panel_layout.BOTTOM.h += 1 self.home_button = self.factory.create_button(KEY_HOME, KEY_HOME, panel_layout.BOTTOM, image_size_percent=36) panel = Container(self.util, layout.LEFT) panel.add_component(self.shutdown_button) panel.add_component(self.left_button) panel.add_component(self.home_button) self.add_component(panel) def create_right_panel(self, layout, listeners, arrow_labels): """ Create right side buttons panel :param layout: panel layout :param listeners: button listeners :param arrow_labels: show arrow label or not """ panel_layout = self.get_panel_layout(layout, LOCATION_RIGHT) panel_layout.set_percent_constraints(self.button_height, self.button_height, 0, 0) panel_layout.TOP.y += 1 panel_layout.TOP.h -= 2 self.play_button = self.factory.create_play_pause_button( panel_layout.TOP, self.get_listener(listeners, KEY_PLAY_PAUSE)) self.right_button = self.factory.create_right_button( panel_layout.CENTER, '', 40, 100, arrow_labels) panel_layout.BOTTOM.h += 1 self.time_volume_button = self.factory.create_time_volume_button( panel_layout.BOTTOM, self.toggle_time_volume) panel = Container(self.util, layout.RIGHT) panel.add_component(self.play_button) panel.add_component(self.right_button) panel.add_component(self.time_volume_button) self.add_component(panel) def get_listener(self, listeners, name): """ Return listener :param listeners: all listeners :param name: listener name :return: listener if avaialble, None - otherwise """ if name in listeners.keys(): return listeners[name] else: return None def toggle_time_volume(self): """ Switch between time and volume controls """ if self.volume_visible: self.volume.set_visible(False) if self.show_time_control: self.time_control.set_visible(True) self.volume_visible = False else: volume_level = int(self.config[PLAYER_SETTINGS][VOLUME]) self.volume.set_position(volume_level) self.volume.update_position() self.volume.set_visible(True) if self.show_time_control: self.time_control.set_visible(False) self.volume_visible = True self.clean_draw_update() if hasattr(self, "time_control"): self.time_control.slider.clean_draw_update() def eject_cd(self, state): """ Eject CD :param state: button state object """ self.audio_files = [] self.screen_title.set_text(" ") self.update_arrow_button_labels(state) if self.show_time_control: self.time_control.reset() self.cd_album = None self.set_cd_album_art_image() def set_current(self, new_track=False, state=None): """ Set current file or playlist :param new_track: True - new audio file :param state: button state """ self.cd_album = getattr(state, "album", None) if self.config[CURRENT][MODE] == AUDIO_FILES: if getattr(state, "url", None) is None: state.url = None state.full_screen_image = self.set_audio_file_image(state.url) elif self.config[CURRENT][MODE] == CD_PLAYER and getattr( state, "source", None) != INIT: state.full_screen_image = self.set_cd_album_art_image() state.image_base = self.file_button.components[1].content config_volume_level = int(self.config[PLAYER_SETTINGS][VOLUME]) if state: if self.config[VOLUME_CONTROL][ VOLUME_CONTROL_TYPE] == VOLUME_CONTROL_TYPE_PLAYER: state.volume = config_volume_level else: state.volume = None self.set_audio_file(new_track, state) if self.volume.get_position() != config_volume_level: self.volume.set_position(config_volume_level) self.volume.update_position() def set_audio_file_image(self, url=None, folder=None): """ Set audio file image :param url: audio file name :param folder: folder name :return: image """ if folder: f = folder else: f = self.config[FILE_PLAYBACK][CURRENT_FOLDER] if not f: return None img_tuple = self.image_util.get_audio_file_icon( f, self.bounding_box, url) self.set_file_button(img_tuple) self.file_button.clean_draw_update() return img_tuple[1] def set_cd_album_art_image(self): """ Set CD album art image """ img_tuple = self.image_util.get_cd_album_art(self.cd_album, self.bounding_box) if img_tuple == None: return None self.set_file_button(img_tuple) self.file_button.clean_draw_update() return img_tuple[1] def set_file_button(self, img_tuple): """ Set image in file button :param img_tuple: tuple where first element is image location, second element image itself """ full_screen_image = img_tuple[1] self.file_button.state.full_screen_image = full_screen_image scale_ratio = self.image_util.get_scale_ratio( (self.layout.CENTER.w, self.layout.CENTER.h), full_screen_image) img = self.image_util.scale_image(full_screen_image, scale_ratio) self.file_button.components[1].content = img self.file_button.state.icon_base = img self.file_button.components[ 1].image_filename = self.file_button.state.image_filename = img_tuple[ 0] self.file_button.components[1].content_x = self.layout.CENTER.x + ( self.layout.CENTER.w - img.get_size()[0]) / 2 if self.layout.CENTER.h > img.get_size()[1]: self.file_button.components[ 1].content_y = self.layout.CENTER.y + int( (self.layout.CENTER.h - img.get_size()[1]) / 2) + 1 else: self.file_button.components[1].content_y = self.layout.CENTER.y 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 + "\"" if s.url == None and state.url != None: state.full_screen_image = self.set_audio_file_image( state.url.replace('\"', "")) 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] self.play_button.draw_default_state(None) 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 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 s and hasattr(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 get_song_name(self, state): """ Get song name in the format: Artist - Song name :param state: state object """ album = getattr(state, "album", None) if album == None: return None artist = album if "/" in album: artist = album.split("/")[0].strip() if artist == None or len(artist) == 0: return None name = getattr(state, "l_name", None) file_name = getattr(state, "file_name", None) if name == None: if file_name == None: return None else: if file_name.startswith("cdda:"): id = int(file_name.split("=")[1].strip()) name = self.audio_files[id - 1].name else: name = file_name pos = name.find(".") if pos != -1: tokens = name.split(".") if tokens[0].strip().isdigit(): name = name[pos + 1:].strip() if name == None or len(name) == 0: return None else: return artist + " - " + name def get_audio_files_from_playlist(self): """ Call player for files in the playlist :return: list of files from playlist """ playlist = self.get_current_playlist() files = [] if playlist: for n in range(len(playlist)): st = State() st.index = st.comparator_item = n st.file_type = FILE_AUDIO st.file_name = playlist[n] files.append(st) return files def restore_current_folder(self, state=None): """ Set current folder in config object :param state: not used """ self.config[FILE_PLAYBACK][CURRENT_FOLDER] = self.current_folder def set_audio_file_playlist(self, index): """ Set file in playlist :param index: file index in playlist """ state = State() state.playback_mode = FILE_PLAYLIST state.playlist_track_number = index state.file_type = FILE_AUDIO self.current_folder = self.config[FILE_PLAYBACK][CURRENT_FOLDER] self.notify_play_listeners(state) def go_back(self): """ Go back """ pass def recursive_change_folder(self): start_folder = self.config[FILE_PLAYBACK][CURRENT_FILE_PLAYLIST] current_folder = self.config[FILE_PLAYBACK][CURRENT_FOLDER] f = self.util.file_util.get_next_folder_with_audio_files( start_folder, current_folder) if f == None or (f != None and f[0] == None): self.config[FILE_PLAYBACK][CURRENT_FILE_PLAYBACK_MODE] = FILE_AUDIO self.config[FILE_PLAYBACK][CURRENT_FILE_PLAYLIST] = None return False self.config[FILE_PLAYBACK][CURRENT_FOLDER] = f[0] self.config[FILE_PLAYBACK][CURRENT_FILE] = f[1] self.config[FILE_PLAYBACK][CURRENT_TRACK_TIME] = None state = State() state.file_type = FOLDER state.url = f[0] state.long_press = True state.playback_mode = FILE_RECURSIVE self.current_track_index = 0 state.dont_notify = True self.audio_files = self.get_audio_files() self.recursive_notifier(f[0]) return True def end_of_track(self): """ Handle end of track """ if not self.screen_title.active: return i = getattr(self, "current_track_index", None) if i == None: return self.stop_timer() mode = self.config[CURRENT][MODE] if mode == RADIO or mode == STREAM or not self.audio_files: return if self.show_time_control: self.time_control.stop_thread() playback_mode = self.config[FILE_PLAYBACK][CURRENT_FILE_PLAYBACK_MODE] if playback_mode == FILE_RECURSIVE: if self.current_track_index == (len(self.audio_files) - 1): if not self.recursive_change_folder(): self.stop_recursive_playback() return else: index = 0 else: index = self.current_track_index + 1 else: index = self.get_next_index() if index == None: self.time_control.stop_thread() self.time_control.reset() return else: self.current_track_index = index if mode == AUDIO_FILES: self.config[FILE_PLAYBACK][CURRENT_TRACK_TIME] = None elif mode == AUDIOBOOKS: self.config[AUDIOBOOKS][BROWSER_BOOK_TIME] = None self.change_track(index) if playback_mode == FILE_RECURSIVE: self.file_button.clean_draw_update() def get_next_index(self): """ Return next file index :return: file index or None """ order = self.config[PLAYER_SETTINGS][PLAYBACK_ORDER] n = self.current_track_index last = len(self.audio_files) - 1 if order == PLAYBACK_SINGLE_TRACK: return None if order == PLAYBACK_SINGLE_CYCLIC: return n if order == PLAYBACK_CYCLIC: if n == last: return 0 else: return n + 1 elif order == PLAYBACK_REGULAR: if n == last: return None else: return n + 1 elif order == PLAYBACK_SHUFFLE: if len(self.audio_files) == 1: return n else: return random.randint(0, last) def set_playlist_size(self, size): """ Set playlist size :param size: playlist size """ self.playlist_size = size self.stop_timer() def set_visible(self, flag): """ Set visibility flag :param flag: True - screen visible, False - screen invisible """ Container.set_visible(self, flag) if flag: if self.volume_visible: self.volume.set_visible(True) if self.show_time_control: self.time_control.set_visible(False) else: self.volume.set_visible(False) if self.show_time_control: self.time_control.set_visible(True) def add_play_listener(self, listener): """ Add play listener :param listener: event listener """ if listener not in self.play_listeners: self.play_listeners.append(listener) def notify_play_listeners(self, state): """ Notify all play listeners :param state: button state """ if not self.screen_title.active: return m = getattr(state, "playback_mode", None) if m != None and m != FILE_PLAYLIST: state.icon_base = self.file_button.state.icon_base folder = getattr(state, "folder", None) if folder: state.cover_art_folder = self.util.file_util.get_cover_art_folder( state.folder) for listener in self.play_listeners: listener(state) def enable_player_screen(self, flag): """ Enable player screen :param flag: enable/disable flag """ self.screen_title.active = flag if self.show_time_control: self.time_control.active = flag def add_screen_observers(self, update_observer, redraw_observer, start_time_control, stop_time_control, title_to_json): """ Add screen observers :param update_observer: observer for updating the screen :param redraw_observer: observer to redraw the whole screen :param start_time_control: :param stop_time_control: :param title_to_json: """ self.update_observer = update_observer self.redraw_observer = redraw_observer Screen.add_screen_observers(self, update_observer, redraw_observer, title_to_json) self.add_button_observers(self.shutdown_button, update_observer, redraw_observer=None) self.shutdown_button.add_cancel_listener(redraw_observer) self.screen_title.add_listener(redraw_observer) self.add_button_observers(self.play_button, update_observer, redraw_observer=None) self.add_button_observers(self.home_button, update_observer, redraw_observer) if self.order_button: self.add_button_observers(self.order_button, update_observer, redraw_observer) if self.info_button: self.add_button_observers(self.info_button, update_observer, redraw_observer) self.add_button_observers(self.left_button, update_observer, redraw_observer=None) self.left_button.add_label_listener(update_observer) self.add_button_observers(self.right_button, update_observer, redraw_observer=None) self.right_button.add_label_listener(update_observer) self.volume.add_slide_listener(update_observer) self.volume.add_knob_listener(update_observer) self.volume.add_press_listener(update_observer) self.volume.add_motion_listener(update_observer) self.add_button_observers(self.file_button, update_observer, redraw_observer, press=False, release=False) if self.order_popup: self.order_popup.add_menu_observers(update_observer, redraw_observer) if self.info_popup: self.info_popup.add_menu_observers(update_observer, redraw_observer) if self.show_time_control: self.add_button_observers(self.time_volume_button, update_observer, redraw_observer, release=False) self.time_control.web_seek_listener = update_observer if start_time_control: self.time_control.add_start_timer_listener(start_time_control) if stop_time_control: self.time_control.add_stop_timer_listener(stop_time_control) self.time_control.slider.add_slide_listener(update_observer) self.time_control.slider.add_knob_listener(update_observer) self.time_control.slider.add_press_listener(update_observer) self.time_control.slider.add_motion_listener(update_observer)