def __init__(self, util, bgr=None, bounding_box=None, font_size=None): """ Initializer :param util: utility object :param bgr: menu background :param bounding_box: bounding box """ self.util = util self.factory = Factory(util) self.config = util.config self.cdutil = CdUtil(util) self.bb = bounding_box self.horizontal_layout = True self.rows = None self.cols = None items = self.get_menu_items() cell_bb = items[2] m = self.create_home_menu_button label_area = (cell_bb.h / 100) * (100 - ICON_AREA) font_size = int((label_area / 100) * FONT_HEIGHT) Menu.__init__(self, util, bgr, bounding_box, None, None, create_item_method=m, font_size=font_size) self.set_modes(*items)
class CdDrivesScreen(Screen): """ File Browser Screen """ def __init__(self, util, listeners, voice_assistant): """ Initializer :param util: utility object :param listeners: file browser listeners """ self.util = util self.config = util.config self.cdutil = CdUtil(util) self.factory = Factory(util) self.bounding_box = util.screen_rect layout = BorderLayout(self.bounding_box) layout.set_percent_constraints(PERCENT_TOP_HEIGHT, PERCENT_BOTTOM_HEIGHT, 0, 0) Screen.__init__(self, util, "", PERCENT_TOP_HEIGHT, voice_assistant, "cd_drives_screen_title", True, layout.TOP) self.cd_drive_id = self.config[CD_PLAYBACK][CD_DRIVE_ID] self.cd_track = self.config[CD_PLAYBACK][CD_TRACK] self.cd_track_time = self.config[CD_PLAYBACK][CD_TRACK_TIME] self.screen_title.set_text(self.config[LABELS][KEY_CD_DRIVES]) self.cd_drives_menu = CdDrivesMenu(util, layout.CENTER, listeners[KEY_CD_TRACKS]) drives_info = self.cdutil.get_cd_drives_info() l = self.cd_drives_menu.get_layout(drives_info) bb = l.get_next_constraints() drives = self.cdutil.get_cd_drives(self.font_size, (bb.w, bb.h)) self.cd_drives_menu.set_items(drives, 0, listeners[KEY_CD_TRACKS]) for b in self.cd_drives_menu.buttons.values(): b.parent_screen = self Container.add_component(self, self.cd_drives_menu) factory = Factory(util) self.menu_buttons = factory.create_home_player_buttons( self, self.layout.BOTTOM, listeners) self.home_button = self.menu_buttons[0] self.player_button = self.menu_buttons[1] 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 """ Screen.add_screen_observers(self, update_observer, redraw_observer) self.cd_drives_menu.add_menu_observers(update_observer, redraw_observer) for b in self.menu_buttons: self.add_button_observers(b, update_observer, redraw_observer)
def __init__(self, util, listeners, voice_assistant, state): """ Initializer :param util: utility object :param listeners: file browser listeners """ self.util = util self.config = util.config self.cdutil = CdUtil(util) self.factory = Factory(util) self.bounding_box = util.screen_rect self.layout = BorderLayout(self.bounding_box) self.layout.set_percent_constraints(PERCENT_TOP_HEIGHT, PERCENT_BOTTOM_HEIGHT, 0, 0) Screen.__init__(self, util, "", PERCENT_TOP_HEIGHT, voice_assistant, "cd_tracks_screen_title", True, self.layout.TOP) color_dark_light = self.config[COLORS][COLOR_DARK_LIGHT] self.current_cd_drive_name = self.config[CD_PLAYBACK][CD_DRIVE_NAME] self.current_cd_drive_id = self.config[CD_PLAYBACK][CD_DRIVE_ID] self.filelist = self.get_filelist() self.file_menu = FileMenu(self.filelist, util, None, (0, 0, 0), self.layout.CENTER, align=ALIGN_LEFT) self.go_cd_player = listeners[KEY_PLAYER] self.file_menu.add_play_file_listener(self.play_track) Container.add_component(self, self.file_menu) listeners[GO_LEFT_PAGE] = self.file_menu.page_down listeners[GO_RIGHT_PAGE] = self.file_menu.page_up listeners[KEY_EJECT] = self.eject_cd listeners[KEY_REFRESH] = self.refresh_tracks connected_cd_drives = self.cdutil.get_cd_drives_number() self.navigator = CdTracksNavigator(util, connected_cd_drives, self.layout.BOTTOM, listeners, color_dark_light) Container.add_component(self, self.navigator) self.file_menu.add_left_number_listener( self.navigator.left_button.change_label) self.file_menu.add_right_number_listener( self.navigator.right_button.change_label) self.file_menu.update_buttons() self.page_turned = False self.animated_title = True
def __init__(self, util, bgr=None, bounding_box=None, font_size=None): """ Initializer :param util: utility object :param bgr: menu background :param bounding_box: bounding box """ self.util = util self.factory = Factory(util) self.config = util.config m = self.factory.create_home_menu_button Menu.__init__(self, util, bgr, bounding_box, None, None, create_item_method=m, font_size=font_size) self.cdutil = CdUtil(util) self.set_modes()
def __init__(self, util, listeners, voice_assistant): """ Initializer :param util: utility object :param listeners: file browser listeners """ self.util = util self.config = util.config self.cdutil = CdUtil(util) self.factory = Factory(util) self.bounding_box = util.screen_rect layout = BorderLayout(self.bounding_box) layout.set_percent_constraints(PERCENT_TOP_HEIGHT, PERCENT_BOTTOM_HEIGHT, 0, 0) Screen.__init__(self, util, "", PERCENT_TOP_HEIGHT, voice_assistant, "cd_drives_screen_title", True, layout.TOP) self.cd_drive_id = self.config[CD_PLAYBACK][CD_DRIVE_ID] self.cd_track = self.config[CD_PLAYBACK][CD_TRACK] self.cd_track_time = self.config[CD_PLAYBACK][CD_TRACK_TIME] self.screen_title.set_text(self.config[LABELS][KEY_CD_DRIVES]) self.cd_drives_menu = CdDrivesMenu(util, layout.CENTER, listeners[KEY_CD_TRACKS]) drives_info = self.cdutil.get_cd_drives_info() l = self.cd_drives_menu.get_layout(drives_info) bb = l.get_next_constraints() drives = self.cdutil.get_cd_drives(self.font_size, (bb.w, bb.h)) self.cd_drives_menu.set_items(drives, 0, listeners[KEY_CD_TRACKS]) for b in self.cd_drives_menu.buttons.values(): b.parent_screen = self self.add_menu(self.cd_drives_menu) self.navigator = CdDrivesNavigator(util, self.layout.BOTTOM, listeners) self.navigator.get_button_by_name(KEY_HOME).set_selected(True) self.add_navigator(self.navigator) self.link_borders()
def __init__(self, util, listeners, voice_assistant): """ Initializer :param util: utility object :param listeners: file browser listeners """ self.util = util self.config = util.config self.cdutil = CdUtil(util) self.factory = Factory(util) self.bounding_box = self.config[SCREEN_RECT] layout = BorderLayout(self.bounding_box) layout.set_percent_constraints(PERCENT_TOP_HEIGHT, PERCENT_BOTTOM_HEIGHT, 0, 0) Screen.__init__(self, util, "", PERCENT_TOP_HEIGHT, voice_assistant, "file_browser_screen_title", True, layout.TOP) color_dark_light = self.config[COLORS][COLOR_DARK_LIGHT] self.cd_drive_id = self.config[CD_PLAYBACK][CD_DRIVE_ID] self.cd_track = self.config[CD_PLAYBACK][CD_TRACK] self.cd_track_time = self.config[CD_PLAYBACK][CD_TRACK_TIME] self.screen_title.set_text(self.config[LABELS][KEY_CD_DRIVES]) self.cd_drives_menu = CdDrivesMenu(None, util, (0, 0, 0), layout.CENTER, listeners[KEY_CD_TRACKS]) drives_info = self.cdutil.get_cd_drives_info() l = self.cd_drives_menu.get_layout(drives_info) bb = l.get_next_constraints() drives = self.cdutil.get_cd_drives(self.font_size, (bb.w, bb.h)) self.cd_drives_menu.set_items(drives, 0, listeners[KEY_CD_TRACKS]) Container.add_component(self, self.cd_drives_menu) factory = Factory(util) self.menu_buttons = factory.create_home_player_buttons( self, self.layout.BOTTOM, listeners) self.home_button = self.menu_buttons[0] self.player_button = self.menu_buttons[1]
class HomeMenu(Menu): """ Home Menu class. Extends base Menu class """ def __init__(self, util, bgr=None, bounding_box=None, font_size=None): """ Initializer :param util: utility object :param bgr: menu background :param bounding_box: bounding box """ self.util = util self.factory = Factory(util) self.config = util.config self.cdutil = CdUtil(util) self.bb = bounding_box self.horizontal_layout = True self.rows = None self.cols = None items = self.get_menu_items() cell_bb = items[2] m = self.create_home_menu_button label_area = (cell_bb.h / 100) * (100 - ICON_AREA) font_size = int((label_area / 100) * FONT_HEIGHT) Menu.__init__(self, util, bgr, bounding_box, None, None, create_item_method=m, font_size=font_size) self.set_modes(*items) def get_menu_items(self): """ Prepare menu items :return: array containing menu items, disabled items, cell bounding box snf icon box """ items = [] disabled_items = [] player = self.config[AUDIO][PLAYER_NAME] if self.config[HOME_MENU][RADIO]: items.append(RADIO) if not self.util.is_radio_enabled( ) or not self.util.connected_to_internet: disabled_items.append(RADIO) if self.config[HOME_MENU][AUDIO_FILES]: items.append(AUDIO_FILES) if self.config[HOME_MENU][AUDIOBOOKS]: items.append(AUDIOBOOKS) if not self.util.is_audiobooks_enabled( ) or not self.util.connected_to_internet: disabled_items.append(AUDIOBOOKS) if self.config[HOME_MENU][STREAM]: items.append(STREAM) if not self.util.connected_to_internet: disabled_items.append(STREAM) if self.config[HOME_MENU][CD_PLAYER]: cd_drives_info = self.cdutil.get_cd_drives_info() if len(cd_drives_info) == 0 or player == MPV_NAME: disabled_items.append(CD_PLAYER) items.append(CD_PLAYER) if self.config[HOME_MENU][PODCASTS]: podcasts_util = self.util.get_podcasts_util() podcasts = podcasts_util.get_podcasts_links() downloads = podcasts_util.are_there_any_downloads() connected = self.util.connected_to_internet valid_players = [VLC_NAME, MPV_NAME] if (connected and len(podcasts) == 0 and not downloads) or ( not connected and not downloads) or player not in valid_players: disabled_items.append(PODCASTS) items.append(PODCASTS) if self.config[HOME_MENU][AIRPLAY]: items.append(AIRPLAY) if not self.util.config[LINUX_PLATFORM]: disabled_items.append(AIRPLAY) if self.config[HOME_MENU][SPOTIFY_CONNECT]: items.append(SPOTIFY_CONNECT) if not self.util.config[LINUX_PLATFORM]: disabled_items.append(SPOTIFY_CONNECT) if self.config[HOME_MENU][COLLECTION]: items.append(COLLECTION) db_util = self.util.get_db_util() if db_util.conn == None: disabled_items.append(COLLECTION) l = self.get_layout(items) bounding_box = l.get_next_constraints() box = self.factory.get_icon_bounding_box(bounding_box, ICON_LOCATION, ICON_AREA, ICON_SIZE, BUTTON_PADDING) return (items, disabled_items, bounding_box, box) def set_current_modes(self): """ Set current player modes """ items = self.get_menu_items() self.set_modes(*items) def set_modes(self, items, disabled_items, bounding_box, box): """ Set menu items :param items: menu items :param disabled_items: disabled menu items :param bounding_box: cell bounding box :param box: image boundng box """ self.modes = self.util.load_menu(items, NAME, disabled_items, V_ALIGN_TOP, bb=box) va_commands = self.util.get_voice_commands() if self.config[USAGE][USE_VOICE_ASSISTANT]: self.add_voice_command(RADIO, ["VA_RADIO", "VA_GO_RADIO"], va_commands) self.add_voice_command(AUDIO_FILES, ["VA_FILES", "VA_GO_FILES"], va_commands) self.add_voice_command( AUDIOBOOKS, ["VA_AUDIOBOOKS", "VA_BOOKS", "VA_GO_BOOKS"], va_commands) self.add_voice_command(STREAM, ["VA_STREAM", "VA_GO_STREAM"], va_commands) self.add_voice_command(CD_PLAYER, ["VA_CD_PLAYER"], va_commands) self.add_voice_command(PODCASTS, ["VA_PODCAST", "VA_PODCASTS"], va_commands) if not items: return if not self.config[CURRENT][MODE]: for i in items: if i not in disabled_items: mode = i break else: mode = self.config[CURRENT][MODE] self.set_items(self.modes, 0, self.change_mode, False) self.current_mode = self.modes[mode.lower()] self.item_selected(self.current_mode) def create_home_menu_button(self, s, constr, action, scale, font_size): """ Create Home 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 :param font_size: label font height in pixels :return: home menu button """ s.padding = BUTTON_PADDING s.image_area_percent = ICON_AREA return self.factory.create_menu_button(s, constr, action, scale, font_size=font_size) def add_voice_command(self, name, commands, va_commands): """ Add voice command :param name: item name :param commands: item commands :param va_commands: voice commands """ if not self.config[HOME_MENU][name]: return c = [] for m in commands: c.append(va_commands[m].strip()) self.modes[name].voice_commands = c def change_mode(self, state): """ Change mode event listener :param state: button state """ if not self.visible: return state.previous_mode = self.current_mode.name self.current_mode = state self.config[CURRENT][MODE] = state.name self.notify_listeners(state)
class FilePlayerScreen(Screen): """ File Player Screen """ def __init__(self, listeners, util, get_current_playlist, voice_assistant, player_stop=None): """ 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.stop_player = player_stop self.get_current_playlist = get_current_playlist self.bounding_box = util.screen_rect self.layout = BorderLayout(self.bounding_box) k = self.bounding_box.w / self.bounding_box.h percent_menu_width = (100.0 - PERCENT_TOP_HEIGHT - PERCENT_BOTTOM_HEIGHT) / k panel_width = (100.0 - percent_menu_width) / 2.0 self.layout.set_percent_constraints(PERCENT_TOP_HEIGHT, PERCENT_BOTTOM_HEIGHT, panel_width, panel_width) self.voice_assistant = voice_assistant Screen.__init__(self, util, "", PERCENT_TOP_HEIGHT, voice_assistant, "file_player_screen_title", True, self.layout.TOP) self.layout = BorderLayout(self.bounding_box) self.layout.set_percent_constraints(PERCENT_TOP_HEIGHT, PERCENT_BOTTOM_HEIGHT, panel_width, panel_width) self.create_left_panel(self.layout, listeners) self.create_right_panel(self.layout, listeners) self.file_button = self.factory.create_file_button( self.layout.CENTER, listeners[AUDIO_FILES]) Container.add_component(self, 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.volume = self.factory.create_volume_control(self.layout.BOTTOM) 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.volume_visible = False self.volume.set_visible(self.volume_visible) Container.add_component(self, self.volume) self.time_control = self.factory.create_time_control( self.layout.BOTTOM) 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) self.left_button.add_release_listener( self.play_button.draw_default_state) self.right_button.add_release_listener( self.play_button.draw_default_state) if self.config[PLAYER_SETTINGS][PAUSE]: self.time_control.pause() Container.add_component(self, self.time_control) self.play_listeners = [] self.add_play_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 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() 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() 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 self.set_current(True, s) def stop_timer(self): """ Stop time control timer """ 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): """ Create left side buttons panel :param layout: panel layout :param listeners: button listeners """ panel_layout = BorderLayout(layout.LEFT) panel_layout.set_percent_constraints(PERCENT_SIDE_BOTTOM_HEIGHT, PERCENT_SIDE_BOTTOM_HEIGHT, 0, 0) self.left_button = self.factory.create_left_button( panel_layout.CENTER, '', 40, 100) self.shutdown_button = self.factory.create_shutdown_button( panel_layout.TOP) 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) Container.add_component(self, panel) def create_right_panel(self, layout, listeners): """ Create right side buttons panel :param layout: panel layout :param listeners: button listeners """ panel_layout = BorderLayout(layout.RIGHT) panel_layout.set_percent_constraints(PERCENT_SIDE_BOTTOM_HEIGHT, PERCENT_SIDE_BOTTOM_HEIGHT, 0, 0) self.play_button = self.factory.create_play_pause_button( panel_layout.TOP, listeners[KEY_PLAY_PAUSE]) self.right_button = self.factory.create_right_button( panel_layout.CENTER, '', 40, 100) 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) Container.add_component(self, panel) def toggle_time_volume(self): """ Switch between time and volume controls """ if self.volume_visible: self.volume.set_visible(False) 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) self.time_control.set_visible(False) self.volume_visible = True self.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) 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() 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: state.volume = config_volume_level 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): """ Set audio file image """ f = self.config[FILE_PLAYBACK][CURRENT_FOLDER] if not f: return None img_tuple = self.util.get_audio_file_icon(f, self.bounding_box) self.set_file_button(img_tuple) return img_tuple[1] def set_cd_album_art_image(self): """ Set CD album art image """ img_tuple = self.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.util.get_scale_ratio( (self.layout.CENTER.w, self.layout.CENTER.h), full_screen_image) img = self.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 + "\"" state.music_folder = self.config[AUDIO][MUSIC_FOLDER] elif self.config[CURRENT][MODE] == CD_PLAYER: state.file_name = s.file_name state.url = getattr(s, "url", s.file_name) parts = s.file_name.split() self.config[CD_PLAYBACK][CD_DRIVE_NAME] = parts[0][len("cdda:///" ):] id = self.cdutil.get_cd_drive_id_by_name( self.config[CD_PLAYBACK][CD_DRIVE_NAME]) self.config[CD_PLAYBACK][CD_DRIVE_ID] = int(id) self.config[CD_PLAYBACK][CD_TRACK] = int(parts[1].split("=")[1]) self.config[PLAYER_SETTINGS][PAUSE] = False state.mute = self.config[PLAYER_SETTINGS][MUTE] state.pause = self.config[PLAYER_SETTINGS][PAUSE] state.file_type = FILE_AUDIO state.dont_notify = True state.source = FILE_AUDIO if self.config[FILE_PLAYBACK][ CURRENT_FILE_PLAYBACK_MODE] == FILE_AUDIO or self.config[ CURRENT][MODE] == CD_PLAYER: self.audio_files = self.get_audio_files() elif self.config[FILE_PLAYBACK][ CURRENT_FILE_PLAYBACK_MODE] == FILE_PLAYLIST: state.file_name = self.config[FILE_PLAYBACK][CURRENT_FILE_PLAYLIST] self.load_playlist(state) state.file_name = self.config[FILE_PLAYBACK][CURRENT_FILE] self.audio_files = self.get_audio_files_from_playlist() state.playback_mode = FILE_PLAYLIST n = getattr(s, "file_name", None) if n: state.file_name = n try: state.playlist_track_number = int(state.file_name) - 1 except: state.playlist_track_number = self.get_current_track_index( state) source = None if s: source = getattr(s, "source", None) if new_track: tt = 0.0 else: if self.config[CURRENT][MODE] == CD_PLAYER: tt = self.config[CD_PLAYBACK][CD_TRACK_TIME] else: tt = self.config[FILE_PLAYBACK][CURRENT_TRACK_TIME] if (isinstance(tt, str) and len(tt) != 0) or ( isinstance(tt, float) or (source and source == RESUME)) or isinstance(tt, int): state.track_time = tt self.time_control.slider.set_position(0) if self.file_button and self.file_button.components[ 1] and self.file_button.components[1].content: state.icon_base = self.file_button.components[1].content if s and s.volume: state.volume = s.volume if self.config[CURRENT][MODE] == CD_PLAYER and s and getattr( s, "source", None) == INIT: try: self.cd_album = self.util.cd_titles[self.config[CD_PLAYBACK] [CD_DRIVE_NAME]] self.set_cd_album_art_image() state.image_base = self.file_button.components[1].content except: self.cd_album = None if getattr(s, "full_screen_image", None) != None: state.full_screen_image = s.full_screen_image song_name = self.get_song_name(s) if song_name != None: state.album = song_name self.notify_play_listeners(state) def 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 """ if self.config[CURRENT][MODE] == CD_PLAYER: return img_tuple = self.util.get_audio_file_icon(self.current_folder, self.layout.CENTER) img = img_tuple[1] self.file_button.components[1].content = img self.file_button.state.icon_base = img_tuple self.file_button.components[1].content_x = self.layout.CENTER.x 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) else: self.file_button.components[1].content_y = self.layout.CENTER.y 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 self.time_control.stop_thread() if self.config[AUTO_PLAY_NEXT_TRACK]: if self.current_track_index == len(self.audio_files) - 1: if self.config[FILE_PLAYBACK][ CURRENT_FILE_PLAYBACK_MODE] == FILE_RECURSIVE: if not self.recursive_change_folder(): self.stop_recursive_playback() return elif self.config[CYCLIC_PLAYBACK]: self.current_track_index = 0 elif not self.config[CYCLIC_PLAYBACK]: return else: self.current_track_index += 1 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(self.current_track_index) if self.config[FILE_PLAYBACK][ CURRENT_FILE_PLAYBACK_MODE] == FILE_RECURSIVE: self.file_button.clean_draw_update() 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) self.time_control.set_visible(False) else: self.volume.set_visible(False) 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 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: """ 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) 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.time_volume_button, update_observer, redraw_observer, release=False) self.add_button_observers(self.file_button, update_observer, redraw_observer, press=False, release=False) self.time_control.web_seek_listener = update_observer self.time_control.add_start_timer_listener(start_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)
class FileMenu(Menu): """ File Menu class. Extends base Menu class """ def __init__(self, filelist, util, playlist_provider, bgr=None, bounding_box=None, align=ALIGN_CENTER): """ Initializer :param filelist: file list :param util: utility object :param bgr: menu background :param bounding_box: bounding box """ self.factory = Factory(util) self.util = util self.cdutil = CdUtil(self.util) self.playlist_provider = playlist_provider self.config = self.util.config self.filelist = filelist m = self.factory.create_file_menu_button self.bounding_box = bounding_box r = c = 3 if filelist: r = filelist.rows c = filelist.columns Menu.__init__(self, util, bgr, self.bounding_box, r, c, create_item_method=m, align=align, button_padding_x=5) self.browsing_history = {} self.left_number_listeners = [] self.right_number_listeners = [] self.change_folder_listeners = [] self.play_file_listeners = [] self.playlist_size_listeners = [] self.menu_navigation_listeners = [] self.page_turned = False self.separator = os.sep self.empty_state = State() url = selection = None self.current_folder = self.config[FILE_PLAYBACK][CURRENT_FOLDER] folder = self.current_folder playback_mode = self.config[FILE_PLAYBACK][CURRENT_FILE_PLAYBACK_MODE] if playback_mode == FILE_AUDIO or playback_mode == FILE_RECURSIVE: if not self.current_folder.endswith(os.sep): self.current_folder += os.sep if self.config[CURRENT][MODE] == CD_PLAYER: cd_drive_name = self.config[CD_PLAYBACK][CD_DRIVE_NAME] track = self.config[CD_PLAYBACK][CD_TRACK] url = self.cdutil.get_cd_track_url(cd_drive_name, track) else: url = self.current_folder + self.config[FILE_PLAYBACK][ CURRENT_FILE] elif playback_mode == FILE_PLAYLIST: url = self.config[FILE_PLAYBACK][CURRENT_FILE] self.browsing_history[self.current_folder] = 0 p = self.current_folder + self.separator + self.config[ FILE_PLAYBACK][CURRENT_FILE_PLAYLIST] self.browsing_history[p] = 0 folder = p self.current_folder = folder selection = url if url and self.filelist: self.filelist.set_current_item_by_url(url) p_index = self.filelist.current_page_index pl = self.filelist.items self.change_folder(folder, page_index=p_index, playlist=pl, selected=selection) if not self.config[FILE_PLAYBACK][CURRENT_FOLDER] and not self.config[ FILE_PLAYBACK][CURRENT_FILE]: self.select_first_item() def recursive_change_folder(self, state): """ Change recursive folder :param state: state object """ f = self.util.file_util.get_first_folder_with_audio_files(state.url) if f == None: self.change_folder(state.url) self.select_item_on_page(0) return self.config[FILE_PLAYBACK][CURRENT_FILE_PLAYBACK_MODE] = FILE_RECURSIVE self.config[FILE_PLAYBACK][CURRENT_FOLDER] = f[0] state.folder = f[0] state.file_name = f[1] state.file_type = FILE_AUDIO state.url = f[1] self.change_folder(f[0]) self.handle_file(state) def select_item(self, state): """ Select menu item :param state: state object defining selected object """ if self.visible and (state.file_type == FILE_AUDIO or state.file_type == FILE_PLAYLIST): self.config[FILE_PLAYBACK][ CURRENT_FOLDER] = self.util.file_util.current_folder if state.file_type == FOLDER or state.file_type == FOLDER_WITH_ICON: if getattr(state, "long_press", False): if self.config[FILE_PLAYBACK][ CURRENT_FILE_PLAYBACK_MODE] == FILE_RECURSIVE: self.config[FILE_PLAYBACK][ CURRENT_FILE_PLAYBACK_MODE] = FILE_AUDIO self.change_folder(state.url) self.select_item_on_page(0) else: self.config[FILE_PLAYBACK][ CURRENT_FILE_PLAYLIST] = state.url self.recursive_change_folder(state) else: self.config[FILE_PLAYBACK][ CURRENT_FILE_PLAYBACK_MODE] = FILE_AUDIO self.change_folder(state.url) self.select_item_on_page(0) elif state.file_type == FILE_AUDIO: if getattr(state, "long_press", False) and self.config[FILE_PLAYBACK][ CURRENT_FILE_PLAYBACK_MODE] == FILE_RECURSIVE: self.config[FILE_PLAYBACK][ CURRENT_FILE_PLAYBACK_MODE] = FILE_AUDIO m = getattr(state, "playback_mode", FILE_AUDIO) mode = self.config[FILE_PLAYBACK][ CURRENT_FILE_PLAYBACK_MODE] or FILE_AUDIO if m == FILE_AUDIO and mode == FILE_AUDIO: self.handle_file(state) else: self.config[FILE_PLAYBACK][CURRENT_FILE] = state.file_name self.config[FILE_PLAYBACK][CURRENT_TRACK_TIME] = None if not getattr(state, "dont_notify", None): self.notify_play_file_listeners(state) else: n = self.config[AUDIO][CLIENT_NAME] if n == MPLAYER or n == VLC: self.handle_file(state) elif state.file_type == FILE_PLAYLIST: self.config[FILE_PLAYBACK][ CURRENT_FILE_PLAYBACK_MODE] = FILE_PLAYLIST i = state.url.rfind(self.separator) url = state.url[i + 1:] self.config[FILE_PLAYBACK][CURRENT_FILE_PLAYLIST] = url state.music_folder = self.config[AUDIO][MUSIC_FOLDER] pl = self.util.load_playlist(state, self.playlist_provider, self.filelist.rows, self.filelist.columns) url = state.url if pl: self.notify_playlist_size_listener(len(pl)) else: url = state.url[0:i] u = getattr(state, "url", None) if u == None: state.url = state.folder + os.sep + state.file_name url = state.url self.change_folder(url, playlist=pl) if self.visible: self.draw() def handle_event(self, event): """ File menu event handler :param event: event to handle """ if not self.visible: return if event.type == USER_EVENT_TYPE and event.sub_type == SUB_TYPE_KEYBOARD and event.action == pygame.KEYUP: if event.keyboard_key == kbd_keys[KEY_LEFT]: if (self.filelist.current_item_index_in_page == 0 and self.filelist.current_item_index != 0 ) or self.filelist.current_item_index == 0: if self.filelist.length <= self.filelist.items_per_page: self.select_item_on_page(self.filelist.length - 1) else: self.turn_page_left() else: self.select_item_on_page(self.filelist.current_item_index - 1) elif event.keyboard_key == kbd_keys[KEY_RIGHT]: if self.filelist.current_item_index == self.filelist.length - 1 or self.filelist.current_item_index_in_page == self.filelist.items_per_page - 1: if self.filelist.length <= self.filelist.items_per_page: self.select_item_on_page(0) else: self.turn_page_right() else: self.select_item_on_page(self.filelist.current_item_index + 1) elif event.keyboard_key == kbd_keys[ KEY_UP] or event.keyboard_key == kbd_keys[KEY_DOWN]: Menu.handle_event(self, event) self.filelist.set_current_item(self.selected_index) self.notify_menu_navigation_listeners(self.empty_state) elif event.keyboard_key == kbd_keys[KEY_SELECT]: Menu.handle_event(self, event) else: Menu.handle_event(self, event) def page_up(self, state=None): """ Called by page up button :param state: not used """ if self.filelist.length <= self.filelist.items_per_page: return self.switch_to_next_page(None) self.select_item_on_page(self.filelist.current_page_index * self.filelist.items_per_page) def page_down(self, state=None): """ Called by page down button :param state: not used """ if self.filelist.length <= self.filelist.items_per_page: return self.switch_to_previous_page(None) self.select_item_on_page(self.filelist.current_page_index * self.filelist.items_per_page) def turn_page_left(self, state=None): """ Turn page left :param state: not used """ if self.filelist.length <= self.filelist.items_per_page: return self.switch_to_previous_page(None) if self.filelist.current_item_index == 0: self.select_item_on_page(self.filelist.length - 1) elif self.filelist.current_item_index_in_page == 0 and self.filelist.current_item_index != 0: self.select_item_on_page(self.filelist.current_item_index - 1) else: self.select_item_on_page(self.filelist.current_page_index * self.filelist.items_per_page) def turn_page_right(self, state=None): """ Turn page right :param state: not used """ if self.filelist.length <= self.filelist.items_per_page: return self.switch_to_next_page(None) if self.filelist.current_item_index == self.filelist.length - 1: self.select_item_on_page(0) elif self.filelist.current_item_index_in_page == self.filelist.items_per_page - 1: self.select_item_on_page(self.filelist.current_item_index + 1) else: self.select_item_on_page(self.filelist.current_page_index * self.filelist.items_per_page) def select_item_on_page(self, selected_index): """ Select item on page :param selected_index: index of the selected item """ if self.filelist.length == 0: return self.filelist.set_current_item(selected_index) self.unselect() self.select_by_index(selected_index) self.notify_menu_navigation_listeners(self.empty_state) def handle_file(self, state): """ Handle audio file :param state: state object defining audio file """ state.track_time = '0' if not state.file_name.startswith("cdda:"): self.config[FILE_PLAYBACK][CURRENT_FILE] = state.file_name self.config[FILE_PLAYBACK][CURRENT_TRACK_TIME] = state.track_time if self.is_in_filelist(state.file_name): b = self.get_button_by_filename(state.file_name) if not b: self.switch_to_next_page(state) else: state.comparator_item = b.state.comparator_item if not self.config[FILE_PLAYBACK][CURRENT_FILE].startswith("cdda:"): url = self.config[FILE_PLAYBACK][ CURRENT_FOLDER] + os.sep + self.config[FILE_PLAYBACK][ CURRENT_FILE] self.filelist.set_current_item_by_url(url) mode = getattr(state, "playback_mode", None) if mode == None: if state.file_type == FILE_AUDIO: state.playback_mode = FILE_AUDIO else: state.playback_mode = FILE_PLAYLIST self.item_selected(state) if not getattr(state, "dont_notify", None): self.notify_play_file_listeners(state) def update_playlist_menu(self, state): """ Update playlist menu This is initiated by player :param state: state object from player defining current playlist file """ if self.config[FILE_PLAYBACK][ CURRENT_FILE_PLAYBACK_MODE] != FILE_PLAYLIST: return s = State() s.dont_notify = True i = self.util.get_dictionary_value(state, "current_track_id") s.track_time = self.util.get_dictionary_value(state, "seek_time", "0") self.config[FILE_PLAYBACK][CURRENT_TRACK_TIME] = s.track_time if i != None: b = self.get_button_by_index_in_page(int(i) - 1) if not b: self.switch_to_next_page(s) s.comparator_item = int(i) name = self.util.get_dictionary_value(state, "Track") if not name: name = self.util.get_dictionary_value(state, "file_name") if name != None: self.config[FILE_PLAYBACK][CURRENT_FILE] = name self.item_selected(state) def get_comparator(self, state): """ Return comparator object from state :param state: state object containing comparator item """ try: p = state["Pos"] return int(p) except: pass try: s_comp = getattr(state, "comparator_item", None) if s_comp != None: return s_comp except: pass s_name = None if isinstance(state, dict): try: s_name = state["file_name"] except: pass elif isinstance(state, State): s_name = getattr(state, "file_name", None) for button in self.buttons.values(): b_name = getattr(button.state, "file_name", None) if s_name and b_name and s_name == button.state.file_name: return button.state.comparator_item return None def set_current_folder(self, folder): """ Current folder setter :param folder: new current folder """ self.current_folder = folder def set_filelist(self, filelist): """ Set filelist :param filelist: the filelist to set """ self.filelist = filelist def init_page(self, index): """ Page initializer :param index: new current page index """ url = self.config[FILE_PLAYBACK][CURRENT_FILE] if self.config[FILE_PLAYBACK][ CURRENT_FILE_PLAYBACK_MODE] == FILE_AUDIO: url = self.config[FILE_PLAYBACK][ CURRENT_FOLDER] + os.sep + self.config[FILE_PLAYBACK][ CURRENT_FILE] if url: self.filelist.set_current_item_by_url(url) self.filelist.current_page_index = index page = self.filelist.get_current_page() self.set_page(self.filelist.current_item_index_in_page, page) if not self.filelist.current_item: self.select_first_item() else: self.item_selected(self.filelist.current_item) def set_page(self, index_on_page, page, align=ALIGN_CENTER): """ Page setter :param index_on_page: current item index on page :param page: current page content """ if page == None: return self.set_items(self.make_dict(page), index_on_page, self.select_item) self.draw() def switch_to_next_page(self, state): """ Switch to the next page :param state: button state """ if len(self.filelist.items) == 0: return self.turn_page(state, self.filelist.next_page()) def switch_to_previous_page(self, state): """ Switch to the previous page :param state: button state """ if len(self.filelist.items) == 0: return self.turn_page(state, self.filelist.previous_page()) def turn_page(self, state, page): """ Change current page :param state: state object defining current item on page :param page: new page content """ self.set_page(self.filelist.current_item_index, page) if getattr(state, "url", None): self.filelist.set_current_item_by_url(state.url) if self.visible: self.item_selected(self.filelist.current_item) self.update_buttons() if not getattr(state, "dont_notify", None): self.draw() self.page_turned = True f = self.current_folder if f[-1] == self.separator: f = f[:-1] self.browsing_history[f] = self.filelist.current_page_index def switch_to_root(self, state): """ Switch to the root folder :param state: not used state object """ self.switch_folder(self.util.file_util.ROOT) def switch_to_user_home(self, state): """ Switch to the user home folder :param state: not used state object """ self.switch_folder(self.util.file_util.USER_HOME) def switch_folder(self, folder): """ Switch to folder :param folder: folder to switch to """ self.switch_file_playback_mode() self.change_folder(folder) self.select_first_item() def switch_file_playback_mode(self): if self.config[FILE_PLAYBACK][ CURRENT_FILE_PLAYBACK_MODE] == FILE_PLAYLIST: self.config[FILE_PLAYBACK][CURRENT_FILE_PLAYBACK_MODE] = FILE_AUDIO def switch_to_parent_folder(self, state): """ Switch to the parent folder :param state: not used state object """ if self.current_folder == self.separator: return self.switch_file_playback_mode() if self.current_folder and self.current_folder[-1] == self.separator: self.current_folder = self.current_folder[:-1] tmp = self.current_folder sep_index = self.current_folder.rfind(self.separator) self.browsing_history.pop(self.current_folder, None) folder = self.current_folder page_index = 0 selected_item = None if sep_index == -1: return if sep_index != 0: folder = self.current_folder[0:sep_index] if len(self.browsing_history) == 0: page_index = -1 selected_item = tmp else: page_index = self.browsing_history.get(folder, 0) elif sep_index == 0: folder = self.separator try: page_index = self.browsing_history[folder] except: pass try: self.change_folder(folder, page_index, selected=selected_item) except: pass if self.filelist.length != 0 and tmp != None: self.filelist.set_current_item_by_url(tmp) self.unselect() i = self.filelist.current_item_index self.select_by_index(i) def change_folder(self, folder, page_index=0, playlist=None, selected=None): """ Change folder :param folder: new folder name :param page_index: new page index :param playlist: playlist content """ if not folder: if self.config[AUDIO][MUSIC_FOLDER]: folder = self.config[AUDIO][MUSIC_FOLDER] else: folder = self.util.file_util.current_folder self.current_folder = folder self.selected_index = None folder_content = playlist if not folder_content and self.config[CURRENT][MODE] != CD_PLAYER: folder_content = self.util.load_folder_content( folder, self.filelist.rows, self.filelist.columns, self.bounding_box) if not folder_content: self.buttons = {} self.components = [] self.filelist = Page(folder_content, self.filelist.rows, self.filelist.columns) if selected: self.filelist.set_current_item_by_url(selected) page_index = self.filelist.current_page_index self.browsing_history[folder] = page_index self.init_page(page_index) self.notify_change_folder_listeners(folder) self.update_buttons() self.draw() self.page_turned = True def select_first_item(self, state=None): """ Select the first item in menu """ if self.filelist.length == 0: return self.filelist.set_current_item(0) self.unselect() self.select_by_index(0) def update_buttons(self): """ Update left/right buttons """ left = str(self.filelist.get_left_items_number()) right = str(self.filelist.get_right_items_number()) self.notify_left_number_listeners(left) self.notify_right_number_listeners(right) 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.comparator_item == index: return button return None def get_button_by_filename(self, file_name): """ Return the button by its file name :param file_name: file name :return: the button """ for button in self.buttons.values(): if button.state.file_name == file_name: return button return None def is_in_filelist(self, file_name): """ Check that file is in the current file list :param file_name: file name :return: True - in file list, False- not in file list """ for item in self.filelist.items: if item.file_name == file_name: return True return False def get_button_by_index(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 == index: return button return None def draw(self): """ Draw menu """ self.clean() self.select_by_index(self.selected_index) super(FileMenu, self).draw() self.update() def add_left_number_listener(self, listener): """ Add left button event listener :param listener: event listener """ if listener not in self.left_number_listeners: self.left_number_listeners.append(listener) def notify_left_number_listeners(self, index): """ Notify left number button listeners :param index: file index """ for listener in self.left_number_listeners: listener(index) def add_right_number_listener(self, listener): """ Add right button event listener :param listener: event listener """ if listener not in self.right_number_listeners: self.right_number_listeners.append(listener) def notify_right_number_listeners(self, index): """ Notify right number button listeners :param index: file index """ for listener in self.right_number_listeners: listener(index) def add_change_folder_listener(self, listener): """ Add change folder event listener :param listener: event listener """ if listener not in self.change_folder_listeners: self.change_folder_listeners.append(listener) def notify_change_folder_listeners(self, state): """ Notify change folder listeners :param state: state object defining new folder """ for listener in self.change_folder_listeners: listener(state) def add_play_file_listener(self, listener): """ Add play file event listener :param listener: event listener """ if listener not in self.play_file_listeners: self.play_file_listeners.append(listener) def notify_play_file_listeners(self, state): """ Notify play file listeners :param state: state object defining file """ for listener in self.play_file_listeners: listener(state) def add_playlist_size_listener(self, listener): """ Add playlist size event listener :param listener: event listener """ if listener not in self.playlist_size_listeners: self.playlist_size_listeners.append(listener) def notify_playlist_size_listener(self, size): """ Notify playlist size listeners :param size: playlist size """ for listener in self.playlist_size_listeners: listener(size) def add_menu_navigation_listeners(self, listener): """ Add menu navigation event listener :param listener: event listener """ if listener not in self.menu_navigation_listeners: self.menu_navigation_listeners.append(listener) def notify_menu_navigation_listeners(self, state): """ Notify menu navigation listeners """ for listener in self.menu_navigation_listeners: listener(state)
def __init__(self, filelist, util, playlist_provider, bgr=None, bounding_box=None, align=ALIGN_CENTER): """ Initializer :param filelist: file list :param util: utility object :param bgr: menu background :param bounding_box: bounding box """ self.factory = Factory(util) self.util = util self.cdutil = CdUtil(self.util) self.playlist_provider = playlist_provider self.config = self.util.config self.filelist = filelist m = self.factory.create_file_menu_button self.bounding_box = bounding_box r = c = 3 if filelist: r = filelist.rows c = filelist.columns Menu.__init__(self, util, bgr, self.bounding_box, r, c, create_item_method=m, align=align, button_padding_x=5) self.browsing_history = {} self.left_number_listeners = [] self.right_number_listeners = [] self.change_folder_listeners = [] self.play_file_listeners = [] self.playlist_size_listeners = [] self.menu_navigation_listeners = [] self.page_turned = False self.separator = os.sep self.empty_state = State() url = selection = None self.current_folder = self.config[FILE_PLAYBACK][CURRENT_FOLDER] folder = self.current_folder playback_mode = self.config[FILE_PLAYBACK][CURRENT_FILE_PLAYBACK_MODE] if playback_mode == FILE_AUDIO or playback_mode == FILE_RECURSIVE: if not self.current_folder.endswith(os.sep): self.current_folder += os.sep if self.config[CURRENT][MODE] == CD_PLAYER: cd_drive_name = self.config[CD_PLAYBACK][CD_DRIVE_NAME] track = self.config[CD_PLAYBACK][CD_TRACK] url = self.cdutil.get_cd_track_url(cd_drive_name, track) else: url = self.current_folder + self.config[FILE_PLAYBACK][ CURRENT_FILE] elif playback_mode == FILE_PLAYLIST: url = self.config[FILE_PLAYBACK][CURRENT_FILE] self.browsing_history[self.current_folder] = 0 p = self.current_folder + self.separator + self.config[ FILE_PLAYBACK][CURRENT_FILE_PLAYLIST] self.browsing_history[p] = 0 folder = p self.current_folder = folder selection = url if url and self.filelist: self.filelist.set_current_item_by_url(url) p_index = self.filelist.current_page_index pl = self.filelist.items self.change_folder(folder, page_index=p_index, playlist=pl, selected=selection) if not self.config[FILE_PLAYBACK][CURRENT_FOLDER] and not self.config[ FILE_PLAYBACK][CURRENT_FILE]: self.select_first_item()
class HomeMenu(Menu): """ Home Menu class. Extends base Menu class """ def __init__(self, util, bgr=None, bounding_box=None, font_size=None): """ Initializer :param util: utility object :param bgr: menu background :param bounding_box: bounding box """ self.util = util self.factory = Factory(util) self.config = util.config m = self.factory.create_home_menu_button Menu.__init__(self, util, bgr, bounding_box, None, None, create_item_method=m, font_size=font_size) self.cdutil = CdUtil(util) self.set_modes() def set_modes(self): items = [] disabled_items = [] player = self.config[AUDIO][PLAYER_NAME] if self.config[HOME_MENU][RADIO]: items.append(RADIO) if not self.util.is_radio_enabled( ) or not self.util.connected_to_internet: disabled_items.append(RADIO) if self.config[HOME_MENU][AUDIO_FILES]: items.append(AUDIO_FILES) if self.config[HOME_MENU][AUDIOBOOKS]: items.append(AUDIOBOOKS) if not self.util.is_audiobooks_enabled( ) or not self.util.connected_to_internet: disabled_items.append(AUDIOBOOKS) if self.config[HOME_MENU][STREAM]: items.append(STREAM) if not self.util.connected_to_internet: disabled_items.append(STREAM) if self.config[HOME_MENU][CD_PLAYER]: cd_drives_info = self.cdutil.get_cd_drives_info() if len(cd_drives_info) == 0 or player == MPV_NAME: disabled_items.append(CD_PLAYER) items.append(CD_PLAYER) if self.config[HOME_MENU][PODCASTS]: podcasts_util = self.util.get_podcasts_util() podcasts = podcasts_util.get_podcasts_links() downloads = podcasts_util.are_there_any_downloads() connected = self.util.connected_to_internet valid_players = [VLC_NAME, MPV_NAME] if (connected and len(podcasts) == 0 and not downloads) or ( not connected and not downloads) or player not in valid_players: disabled_items.append(PODCASTS) items.append(PODCASTS) if self.config[HOME_MENU][AIRPLAY]: items.append(AIRPLAY) if not self.util.config[LINUX_PLATFORM]: disabled_items.append(AIRPLAY) if self.config[HOME_MENU][SPOTIFY_CONNECT]: items.append(SPOTIFY_CONNECT) if not self.util.config[LINUX_PLATFORM]: disabled_items.append(SPOTIFY_CONNECT) if self.config[HOME_MENU][COLLECTION]: items.append(COLLECTION) db_util = self.util.get_db_util() if db_util.conn == None: disabled_items.append(COLLECTION) l = self.get_layout(items) bounding_box = l.get_next_constraints() self.modes = self.util.load_menu(items, NAME, disabled_items, V_ALIGN_TOP, bb=bounding_box, scale=0.5) va_commands = self.util.get_voice_commands() if self.config[USAGE][USE_VOICE_ASSISTANT]: self.add_voice_command(RADIO, ["VA_RADIO", "VA_GO_RADIO"], va_commands) self.add_voice_command(AUDIO_FILES, ["VA_FILES", "VA_GO_FILES"], va_commands) self.add_voice_command( AUDIOBOOKS, ["VA_AUDIOBOOKS", "VA_BOOKS", "VA_GO_BOOKS"], va_commands) self.add_voice_command(STREAM, ["VA_STREAM", "VA_GO_STREAM"], va_commands) self.add_voice_command(CD_PLAYER, ["VA_CD_PLAYER"], va_commands) self.add_voice_command(PODCASTS, ["VA_PODCAST", "VA_PODCASTS"], va_commands) if not items: return if not self.config[CURRENT][MODE]: for i in items: if i not in disabled_items: mode = i break else: mode = self.config[CURRENT][MODE] self.set_items(self.modes, 0, self.change_mode, False) self.current_mode = self.modes[mode.lower()] self.item_selected(self.current_mode) def add_voice_command(self, name, commands, va_commands): """ Add voice command :param name: item name :param commands: item commands :param va_commands: voice commands """ if not self.config[HOME_MENU][name]: return c = [] for m in commands: c.append(va_commands[m].strip()) self.modes[name].voice_commands = c def change_mode(self, state): """ Change mode event listener :param state: button state """ if not self.visible: return state.previous_mode = self.current_mode.name self.current_mode = state self.config[CURRENT][MODE] = state.name self.notify_listeners(state)
def __init__(self, filelist, util, playlist_provider, bounding_box=None, align=ALIGN_CENTER, icon_box=None, icon_box_without_label=None): """ Initializer :param filelist: file list :param util: utility object :param bgr: menu background :param bounding_box: bounding box """ self.factory = Factory(util) self.util = util self.cdutil = CdUtil(self.util) self.playlist_provider = playlist_provider self.config = self.util.config self.filelist = filelist self.icon_box = icon_box self.icon_box_without_label = icon_box_without_label m = self.create_file_menu_button self.bounding_box = bounding_box bgr = util.config[BACKGROUND][MENU_BGR_COLOR] r = c = 3 if filelist: r = filelist.rows c = filelist.columns h = self.config[HORIZONTAL_LAYOUT] button_height = (self.bounding_box.h / r) - (self.config[PADDING] * 2) if self.config[ALIGN_BUTTON_CONTENT_X] == 'center': font_size = int(((100 - self.config[IMAGE_AREA]) / 100) * self.config[FONT_HEIGHT_PERCENT]) else: font_size = int((button_height / 100) * self.config[FONT_HEIGHT_PERCENT]) Menu.__init__(self, util, bgr, self.bounding_box, r, c, create_item_method=m, align=align, horizontal_layout=h, font_size=font_size) self.browsing_history = {} self.left_number_listeners = [] self.right_number_listeners = [] self.change_folder_listeners = [] self.play_file_listeners = [] self.playlist_size_listeners = [] self.menu_navigation_listeners = [] self.page_turned = False self.separator = os.sep self.empty_state = State() url = selection = None self.current_folder = self.config[FILE_PLAYBACK][CURRENT_FOLDER] folder = self.current_folder playback_mode = self.config[FILE_PLAYBACK][CURRENT_FILE_PLAYBACK_MODE] if playback_mode == FILE_AUDIO or playback_mode == FILE_RECURSIVE: if not self.current_folder.endswith(os.sep): self.current_folder += os.sep if self.config[CURRENT][MODE] == CD_PLAYER: cd_drive_name = self.config[CD_PLAYBACK][CD_DRIVE_NAME] track = self.config[CD_PLAYBACK][CD_TRACK] url = self.cdutil.get_cd_track_url(cd_drive_name, track) else: url = self.current_folder + self.config[FILE_PLAYBACK][CURRENT_FILE] elif playback_mode == FILE_PLAYLIST: url = self.config[FILE_PLAYBACK][CURRENT_FILE] self.browsing_history[self.current_folder] = 0 p = self.current_folder + self.separator + self.config[FILE_PLAYBACK][CURRENT_FILE_PLAYLIST] self.browsing_history[p] = 0 folder = p self.current_folder = folder selection = url if url and self.filelist: self.filelist.set_current_item_by_url(url) p_index = self.filelist.current_page_index pl = self.filelist.items self.change_folder(folder, page_index=p_index, playlist=pl, selected=selection)
def __init__(self, listeners, util, get_current_playlist, voice_assistant, player_stop=None): """ 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.stop_player = player_stop self.get_current_playlist = get_current_playlist self.bounding_box = util.screen_rect self.layout = BorderLayout(self.bounding_box) k = self.bounding_box.w / self.bounding_box.h percent_menu_width = (100.0 - PERCENT_TOP_HEIGHT - PERCENT_BOTTOM_HEIGHT) / k panel_width = (100.0 - percent_menu_width) / 2.0 self.layout.set_percent_constraints(PERCENT_TOP_HEIGHT, PERCENT_BOTTOM_HEIGHT, panel_width, panel_width) self.voice_assistant = voice_assistant Screen.__init__(self, util, "", PERCENT_TOP_HEIGHT, voice_assistant, "file_player_screen_title", True, self.layout.TOP) self.layout = BorderLayout(self.bounding_box) self.layout.set_percent_constraints(PERCENT_TOP_HEIGHT, PERCENT_BOTTOM_HEIGHT, panel_width, panel_width) self.create_left_panel(self.layout, listeners) self.create_right_panel(self.layout, listeners) self.file_button = self.factory.create_file_button( self.layout.CENTER, listeners[AUDIO_FILES]) Container.add_component(self, 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.volume = self.factory.create_volume_control(self.layout.BOTTOM) 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.volume_visible = False self.volume.set_visible(self.volume_visible) Container.add_component(self, self.volume) self.time_control = self.factory.create_time_control( self.layout.BOTTOM) 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) self.left_button.add_release_listener( self.play_button.draw_default_state) self.right_button.add_release_listener( self.play_button.draw_default_state) if self.config[PLAYER_SETTINGS][PAUSE]: self.time_control.pause() Container.add_component(self, self.time_control) self.play_listeners = [] self.add_play_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
class HomeMenu(Menu): """ Home Menu class. Extends base Menu class """ def __init__(self, util, bgr=None, bounding_box=None, font_size=None): """ Initializer :param util: utility object :param bgr: menu background :param bounding_box: bounding box """ self.util = util self.factory = Factory(util) self.config = util.config m = self.factory.create_home_menu_button Menu.__init__(self, util, bgr, bounding_box, None, None, create_item_method=m, font_size=font_size) self.cdutil = CdUtil(util) self.set_modes() def set_modes(self): items = [] disabled_items = [] if self.config[HOME_MENU][RADIO]: items.append(RADIO) if not self.util.is_radio_enabled( ) or not self.util.connected_to_internet: disabled_items.append(RADIO) if self.config[HOME_MENU][AUDIO_FILES]: items.append(AUDIO_FILES) if self.config[HOME_MENU][AUDIOBOOKS]: items.append(AUDIOBOOKS) if not self.util.is_audiobooks_enabled( ) or not self.util.connected_to_internet: disabled_items.append(AUDIOBOOKS) if self.config[HOME_MENU][STREAM]: items.append(STREAM) if not self.util.connected_to_internet: disabled_items.append(STREAM) if self.config[HOME_MENU][CD_PLAYER]: cd_drives_info = self.cdutil.get_cd_drives_info() if len(cd_drives_info) == 0: disabled_items.append(CD_PLAYER) items.append(CD_PLAYER) if self.config[HOME_MENU][PODCASTS]: podcasts_util = self.util.get_podcasts_util() podcasts = podcasts_util.get_podcasts_links() downloads = podcasts_util.are_there_any_downloads() connected = self.util.connected_to_internet player = self.config[AUDIO][PLAYER_NAME] if (connected and len(podcasts) == 0 and not downloads) or (not connected and not downloads) or player != VLC: disabled_items.append(PODCASTS) items.append(PODCASTS) l = self.get_layout(items) bounding_box = l.get_next_constraints() self.modes = self.util.load_menu(items, NAME, disabled_items, V_ALIGN_TOP, bb=bounding_box, scale=0.5) va_commands = self.util.get_voice_commands() if self.config[USAGE][USE_VOICE_ASSISTANT]: if self.config[HOME_MENU][RADIO]: r = [ va_commands["VA_RADIO"].strip(), va_commands["VA_GO_RADIO"].strip() ] self.modes[RADIO].voice_commands = r if self.config[HOME_MENU][AUDIO_FILES]: f = [ va_commands["VA_FILES"].strip(), va_commands["VA_GO_FILES"].strip(), va_commands["VA_AUDIO_FILES"].strip() ] self.modes[AUDIO_FILES].voice_commands = f if self.config[HOME_MENU][AUDIOBOOKS]: a = [ va_commands["VA_AUDIOBOOKS"].strip(), va_commands["VA_BOOKS"].strip(), va_commands["VA_GO_BOOKS"].strip() ] self.modes[AUDIOBOOKS].voice_commands = a if self.config[HOME_MENU][STREAM]: s = [ va_commands["VA_STREAM"].strip(), va_commands["VA_GO_STREAM"].strip() ] self.modes[STREAM].voice_commands = s if self.config[HOME_MENU][CD_PLAYER]: s = [va_commands["VA_CD_PLAYER"].strip()] self.modes[STREAM].voice_commands = s if not items: return if not self.config[CURRENT][MODE]: for i in items: if i not in disabled_items: mode = i break else: mode = self.config[CURRENT][MODE] self.set_items(self.modes, 0, self.change_mode, False) self.current_mode = self.modes[mode.lower()] self.item_selected(self.current_mode) def change_mode(self, state): """ Change mode event listener :param state: button state """ if not self.visible: return state.previous_mode = self.current_mode.name self.current_mode = state self.config[CURRENT][MODE] = state.name self.notify_listeners(state)
class FileMenu(Menu): """ File Menu class. Extends base Menu class """ def __init__(self, filelist, util, playlist_provider, bounding_box=None, align=ALIGN_CENTER, icon_box=None, icon_box_without_label=None): """ Initializer :param filelist: file list :param util: utility object :param bgr: menu background :param bounding_box: bounding box """ self.factory = Factory(util) self.util = util self.cdutil = CdUtil(self.util) self.playlist_provider = playlist_provider self.config = self.util.config self.filelist = filelist self.icon_box = icon_box self.icon_box_without_label = icon_box_without_label m = self.create_file_menu_button self.bounding_box = bounding_box bgr = util.config[BACKGROUND][MENU_BGR_COLOR] r = c = 3 if filelist: r = filelist.rows c = filelist.columns h = self.config[HORIZONTAL_LAYOUT] button_height = (self.bounding_box.h / r) - (self.config[PADDING] * 2) if self.config[ALIGN_BUTTON_CONTENT_X] == 'center': font_size = int(((100 - self.config[IMAGE_AREA]) / 100) * self.config[FONT_HEIGHT_PERCENT]) else: font_size = int((button_height / 100) * self.config[FONT_HEIGHT_PERCENT]) Menu.__init__(self, util, bgr, self.bounding_box, r, c, create_item_method=m, align=align, horizontal_layout=h, font_size=font_size) self.browsing_history = {} self.left_number_listeners = [] self.right_number_listeners = [] self.change_folder_listeners = [] self.play_file_listeners = [] self.playlist_size_listeners = [] self.menu_navigation_listeners = [] self.page_turned = False self.separator = os.sep self.empty_state = State() url = selection = None self.current_folder = self.config[FILE_PLAYBACK][CURRENT_FOLDER] folder = self.current_folder playback_mode = self.config[FILE_PLAYBACK][CURRENT_FILE_PLAYBACK_MODE] if playback_mode == FILE_AUDIO or playback_mode == FILE_RECURSIVE: if not self.current_folder.endswith(os.sep): self.current_folder += os.sep if self.config[CURRENT][MODE] == CD_PLAYER: cd_drive_name = self.config[CD_PLAYBACK][CD_DRIVE_NAME] track = self.config[CD_PLAYBACK][CD_TRACK] url = self.cdutil.get_cd_track_url(cd_drive_name, track) else: url = self.current_folder + self.config[FILE_PLAYBACK][CURRENT_FILE] elif playback_mode == FILE_PLAYLIST: url = self.config[FILE_PLAYBACK][CURRENT_FILE] self.browsing_history[self.current_folder] = 0 p = self.current_folder + self.separator + self.config[FILE_PLAYBACK][CURRENT_FILE_PLAYLIST] self.browsing_history[p] = 0 folder = p self.current_folder = folder selection = url if url and self.filelist: self.filelist.set_current_item_by_url(url) p_index = self.filelist.current_page_index pl = self.filelist.items self.change_folder(folder, page_index=p_index, playlist=pl, selected=selection) def create_file_menu_button(self, s, constr, action, scale, font_size): """ Create File 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: file menu button """ scale = False s.padding = self.config[PADDING] s.image_area_percent = self.config[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 if s.file_type == FOLDER_WITH_ICON or (s.file_type == FILE_AUDIO and getattr(s, "has_embedded_image", None)): scale = True if hasattr(s, "show_label"): return 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: return self.factory.create_menu_button(s, constr, action, scale, label_area_percent=label_area_percent, font_size=font_size) def recursive_change_folder(self, state): """ Change recursive folder :param state: state object """ f = self.util.file_util.get_first_folder_with_audio_files(state.url) if f == None: self.change_folder(state.url) return self.config[FILE_PLAYBACK][CURRENT_FILE_PLAYBACK_MODE] = FILE_RECURSIVE self.config[FILE_PLAYBACK][CURRENT_FOLDER] = f[0] state.folder = f[0] state.file_name = f[1] state.file_type = FILE_AUDIO state.url = os.path.join(f[0], f[1]) self.change_folder(f[0]) self.handle_file(state) def select_item(self, state): """ Select menu item :param state: state object defining selected object """ if self.visible: if state.file_type == FILE_AUDIO or state.file_type == FILE_PLAYLIST: self.config[FILE_PLAYBACK][CURRENT_FOLDER] = self.util.file_util.current_folder if self.config[FILE_PLAYBACK][CURRENT_FILE_PLAYBACK_MODE] == FILE_PLAYLIST: if hasattr(state, "file_name") and hasattr(state, "name"): file_name = state.file_name name = state.name index = file_name.rfind(name) if index != -1: folder = file_name[0 : index] if len(folder.strip()) > 0: self.config[FILE_PLAYBACK][CURRENT_FOLDER] = folder if state.file_type == FOLDER or state.file_type == FOLDER_WITH_ICON: if getattr(state, "long_press", False): if self.config[FILE_PLAYBACK][CURRENT_FILE_PLAYBACK_MODE] == FILE_RECURSIVE: self.config[FILE_PLAYBACK][CURRENT_FILE_PLAYBACK_MODE] = FILE_AUDIO self.change_folder(state.url) else: self.config[FILE_PLAYBACK][CURRENT_FILE_PLAYLIST] = state.url self.recursive_change_folder(state) else: self.config[FILE_PLAYBACK][CURRENT_FILE_PLAYBACK_MODE] = FILE_AUDIO self.change_folder(state.url) elif state.file_type == FILE_AUDIO: if getattr(state, "long_press", False) and self.config[FILE_PLAYBACK][CURRENT_FILE_PLAYBACK_MODE] == FILE_RECURSIVE: self.config[FILE_PLAYBACK][CURRENT_FILE_PLAYBACK_MODE] = FILE_AUDIO m = getattr(state, "playback_mode", FILE_AUDIO) mode = self.config[FILE_PLAYBACK][CURRENT_FILE_PLAYBACK_MODE] or FILE_AUDIO if m == FILE_AUDIO and mode == FILE_AUDIO: self.handle_file(state) else: self.config[FILE_PLAYBACK][CURRENT_FILE] = state.file_name self.config[FILE_PLAYBACK][CURRENT_TRACK_TIME] = None if not getattr(state, "dont_notify", None): self.notify_play_file_listeners(state) else: n = self.config[AUDIO][CLIENT_NAME] if n == VLC or n == MPV: self.handle_file(state) self.handle_border_links() elif state.file_type == FILE_PLAYLIST: self.config[FILE_PLAYBACK][CURRENT_FILE_PLAYBACK_MODE] = FILE_PLAYLIST i = state.url.rfind(self.separator) url = state.url[i + 1:] self.config[FILE_PLAYBACK][CURRENT_FILE_PLAYLIST] = url state.music_folder = self.config[AUDIO][MUSIC_FOLDER] pl = self.util.load_playlist(state, self.playlist_provider, self.filelist.rows, self.filelist.columns, (self.icon_box.w, self.icon_box.h)) url = state.url if pl: self.notify_playlist_size_listener(len(pl)) else: url = state.url[0 : i] u = getattr(state, "url", None) if u == None: state.url = state.folder + os.sep + state.file_name url = state.url self.change_folder(url, playlist=pl) if self.visible: self.draw() def page_up(self, state=None): """ Called by page up button :param state: not used """ if self.filelist.length <= self.filelist.items_per_page: return self.switch_to_next_page(None) def page_down(self, state=None): """ Called by page down button :param state: not used """ if self.filelist.length <= self.filelist.items_per_page: return self.switch_to_previous_page(None) def handle_file(self, state): """ Handle audio file :param state: state object defining audio file """ state.track_time = '0' if not state.file_name.startswith("cdda:"): self.config[FILE_PLAYBACK][CURRENT_FILE] = state.file_name self.config[FILE_PLAYBACK][CURRENT_TRACK_TIME] = state.track_time if self.is_in_filelist(state.file_name): b = self.get_button_by_filename(state.file_name) if not b: self.switch_to_next_page(state) else: state.comparator_item = b.state.comparator_item if not self.config[FILE_PLAYBACK][CURRENT_FILE].startswith("cdda:"): if not self.config[FILE_PLAYBACK][CURRENT_FOLDER].endswith(os.sep): url = self.config[FILE_PLAYBACK][CURRENT_FOLDER] + os.sep + self.config[FILE_PLAYBACK][CURRENT_FILE] else: url = self.config[FILE_PLAYBACK][CURRENT_FOLDER] + self.config[FILE_PLAYBACK][CURRENT_FILE] self.filelist.set_current_item_by_url(url) mode = getattr(state, "playback_mode", None) if mode == None: if state.file_type == FILE_AUDIO: state.playback_mode = FILE_AUDIO else: state.playback_mode = FILE_PLAYLIST self.item_selected(state) if not getattr(state, "dont_notify", None): self.notify_play_file_listeners(state) def update_playlist_menu(self, state): """ Update playlist menu This is initiated by player :param state: state object from player defining current playlist file """ if self.config[FILE_PLAYBACK][CURRENT_FILE_PLAYBACK_MODE] != FILE_PLAYLIST: return s = State() s.dont_notify = True i = self.util.get_dictionary_value(state, "current_track_id") s.track_time = self.util.get_dictionary_value(state, "seek_time", "0") self.config[FILE_PLAYBACK][CURRENT_TRACK_TIME] = s.track_time if i != None: b = self.get_button_by_index_in_page(int(i) - 1) if not b: self.switch_to_next_page(s) s.comparator_item = int(i) name = self.util.get_dictionary_value(state, "Track") if not name: name = self.util.get_dictionary_value(state, "file_name") if name != None: self.config[FILE_PLAYBACK][CURRENT_FILE] = name self.item_selected(state) def get_comparator(self, state): """ Return comparator object from state :param state: state object containing comparator item """ try: p = state["Pos"] return int(p) except: pass try: s_comp = getattr(state, "comparator_item", None) if s_comp != None: return s_comp except: pass s_name = None if isinstance(state, dict): try: s_name = state["file_name"] except: pass elif isinstance(state, State): s_name = getattr(state, "file_name", None) for button in self.buttons.values(): b_name = getattr(button.state, "file_name", None) if s_name and b_name and s_name == button.state.file_name: return button.state.comparator_item return None def set_current_folder(self, folder): """ Current folder setter :param folder: new current folder """ self.current_folder = folder def set_filelist(self, filelist): """ Set filelist :param filelist: the filelist to set """ self.filelist = filelist def init_page(self, index): """ Page initializer :param index: new current page index """ url = self.config[FILE_PLAYBACK][CURRENT_FILE] if self.config[FILE_PLAYBACK][CURRENT_FILE_PLAYBACK_MODE] == FILE_AUDIO: url = self.config[FILE_PLAYBACK][CURRENT_FOLDER] + os.sep + self.config[FILE_PLAYBACK][CURRENT_FILE] if url: self.filelist.set_current_item_by_url(url) self.filelist.current_page_index = index page = self.filelist.get_current_page() self.set_page(self.filelist.current_item_index_in_page, page) if not self.filelist.current_item: self.filelist.current_page_index = index def set_page(self, index_on_page, page, align=ALIGN_CENTER): """ Page setter :param index_on_page: current item index on page :param page: current page content """ if page == None: return self.set_items(self.make_dict(page), index_on_page, self.select_item) for b in self.buttons.values(): b.parent_screen = self.parent_screen self.draw() def switch_to_next_page(self, state): """ Switch to the next page :param state: button state """ if len(self.filelist.items) == 0: return self.turn_page(state, self.filelist.next_page()) def switch_to_previous_page(self, state): """ Switch to the previous page :param state: button state """ if len(self.filelist.items) == 0: return self.turn_page(state, self.filelist.previous_page()) def turn_page(self, state, page): """ Change current page :param state: state object defining current item on page :param page: new page content """ self.set_page(self.filelist.current_item_index, page) if getattr(state, "url", None): self.filelist.set_current_item_by_url(state.url) if self.visible: self.item_selected(self.filelist.current_item) self.update_buttons() if not getattr(state, "dont_notify", None): self.draw() self.page_turned = True f = self.current_folder if f[-1] == self.separator: f = f[:-1] self.browsing_history[f] = self.filelist.current_page_index self.handle_border_links() def handle_border_links(self): """ Handle border links and menu/navigator selection """ if hasattr(self, "link_borders"): self.link_borders() if hasattr(self, "navigator"): if self.get_selected_item() != None: self.navigator.unselect() else: if not self.navigator.is_selected(): b = self.navigator.get_button_by_name(KEY_HOME) b.set_selected(True) b.clean_draw_update() def switch_to_root(self, state): """ Switch to the root folder :param state: not used state object """ self.switch_folder(self.util.file_util.ROOT) def switch_to_user_home(self, state): """ Switch to the user home folder :param state: not used state object """ self.switch_folder(self.util.file_util.USER_HOME) def switch_folder(self, folder): """ Switch to folder :param folder: folder to switch to """ self.switch_file_playback_mode() self.change_folder(folder) def switch_file_playback_mode(self): if self.config[FILE_PLAYBACK][CURRENT_FILE_PLAYBACK_MODE] == FILE_PLAYLIST: self.config[FILE_PLAYBACK][CURRENT_FILE_PLAYBACK_MODE] = FILE_AUDIO def switch_to_parent_folder(self, state): """ Switch to the parent folder :param state: not used state object """ if self.current_folder == self.separator: return self.switch_file_playback_mode() if self.current_folder and self.current_folder[-1] == self.separator: self.current_folder = self.current_folder[:-1] tmp = self.current_folder sep_index = self.current_folder.rfind(self.separator) self.browsing_history.pop(self.current_folder, None) folder = self.current_folder page_index = 0 selected_item = tmp if sep_index == -1: return if sep_index != 0: folder = self.current_folder[0:sep_index] if len(self.browsing_history) == 0: page_index = -1 else: page_index = self.browsing_history.get(folder, 0) elif sep_index == 0: folder = self.separator try: page_index = self.browsing_history[folder] except: pass try: self.change_folder(folder, page_index, selected=selected_item) except: pass if self.filelist.length != 0 and tmp != None: self.filelist.set_current_item_by_url(tmp) self.unselect() i = self.filelist.current_item_index self.select_by_index(i) if hasattr(self, "navigator") and self.get_selected_item() != None: self.navigator.unselect() def change_folder(self, folder, page_index=0, playlist=None, selected=None): """ Change folder :param folder: new folder name :param page_index: new page index :param playlist: playlist content """ if not folder: if self.config[AUDIO][MUSIC_FOLDER]: folder = self.config[AUDIO][MUSIC_FOLDER] else: folder = self.util.file_util.current_folder self.current_folder = folder self.selected_index = None folder_content = playlist if not folder_content and self.config[CURRENT][MODE] != CD_PLAYER: folder_content = self.util.load_folder_content(folder, self.filelist.rows, self.filelist.columns, self.icon_box, self.icon_box_without_label) if not folder_content: self.buttons = {} self.components = [] self.filelist = Page(folder_content, self.filelist.rows, self.filelist.columns) if selected: self.filelist.set_current_item_by_url(selected) page_index = self.filelist.current_item_page_index self.browsing_history[folder] = page_index self.init_page(page_index) self.notify_change_folder_listeners(folder) self.update_buttons() self.page_turned = True self.handle_border_links() def update_buttons(self): """ Update left/right buttons """ left = str(self.filelist.get_left_items_number()) right = str(self.filelist.get_right_items_number()) self.notify_left_number_listeners(left) self.notify_right_number_listeners(right) 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.comparator_item == index: return button return None def get_button_by_filename(self, file_name): """ Return the button by its file name :param file_name: file name :return: the button """ for button in self.buttons.values(): if button.state.file_name == file_name: return button return None def is_in_filelist(self, file_name): """ Check that file is in the current file list :param file_name: file name :return: True - in file list, False- not in file list """ if not self.filelist.items: return False for item in self.filelist.items: if item.file_name == file_name: return True return False def get_button_by_index(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 == index: return button return None def draw(self): """ Draw menu """ self.clean() super(FileMenu, self).draw() self.update() def add_left_number_listener(self, listener): """ Add left button event listener :param listener: event listener """ if listener not in self.left_number_listeners: self.left_number_listeners.append(listener) def notify_left_number_listeners(self, index): """ Notify left number button listeners :param index: file index """ for listener in self.left_number_listeners: listener(index) def add_right_number_listener(self, listener): """ Add right button event listener :param listener: event listener """ if listener not in self.right_number_listeners: self.right_number_listeners.append(listener) def notify_right_number_listeners(self, index): """ Notify right number button listeners :param index: file index """ for listener in self.right_number_listeners: listener(index) def add_change_folder_listener(self, listener): """ Add change folder event listener :param listener: event listener """ if listener not in self.change_folder_listeners: self.change_folder_listeners.append(listener) def notify_change_folder_listeners(self, state): """ Notify change folder listeners :param state: state object defining new folder """ for listener in self.change_folder_listeners: listener(state) def add_play_file_listener(self, listener): """ Add play file event listener :param listener: event listener """ if listener not in self.play_file_listeners: self.play_file_listeners.append(listener) def notify_play_file_listeners(self, state): """ Notify play file listeners :param state: state object defining file """ for listener in self.play_file_listeners: listener(state) def add_playlist_size_listener(self, listener): """ Add playlist size event listener :param listener: event listener """ if listener not in self.playlist_size_listeners: self.playlist_size_listeners.append(listener) def notify_playlist_size_listener(self, size): """ Notify playlist size listeners :param size: playlist size """ for listener in self.playlist_size_listeners: listener(size) def add_menu_navigation_listeners(self, listener): """ Add menu navigation event listener :param listener: event listener """ if listener not in self.menu_navigation_listeners: self.menu_navigation_listeners.append(listener) def notify_menu_navigation_listeners(self, state): """ Notify menu navigation listeners """ for listener in self.menu_navigation_listeners: listener(state)
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)
class CdTracksScreen(Screen): """ File Browser Screen """ def __init__(self, util, listeners, voice_assistant, state): """ Initializer :param util: utility object :param listeners: file browser listeners """ self.util = util self.config = util.config self.cdutil = CdUtil(util) self.factory = Factory(util) self.bounding_box = util.screen_rect self.layout = BorderLayout(self.bounding_box) self.layout.set_percent_constraints(PERCENT_TOP_HEIGHT, PERCENT_BOTTOM_HEIGHT, 0, 0) Screen.__init__(self, util, "", PERCENT_TOP_HEIGHT, voice_assistant, "cd_tracks_screen_title", True, self.layout.TOP) self.current_cd_drive_name = self.config[CD_PLAYBACK][CD_DRIVE_NAME] self.current_cd_drive_id = self.config[CD_PLAYBACK][CD_DRIVE_ID] self.filelist = self.get_filelist() self.file_menu = FileMenu(self.filelist, util, None, self.layout.CENTER, align=ALIGN_LEFT) self.go_cd_player = listeners[KEY_PLAYER] self.file_menu.add_play_file_listener(self.play_track) self.add_component(self.file_menu) listeners[GO_LEFT_PAGE] = self.file_menu.page_down listeners[GO_RIGHT_PAGE] = self.file_menu.page_up listeners[KEY_EJECT] = self.eject_cd listeners[KEY_REFRESH] = self.refresh_tracks connected_cd_drives = self.cdutil.get_cd_drives_number() self.navigator = CdTracksNavigator(util, connected_cd_drives, self.layout.BOTTOM, listeners) self.add_component(self.navigator) self.file_menu.add_left_number_listener( self.navigator.left_button.change_label) self.file_menu.add_right_number_listener( self.navigator.right_button.change_label) self.file_menu.update_buttons() self.page_turned = False self.animated_title = True def play_track(self, state): """ Set config and go to player :param state: state object with track info """ self.config[CD_PLAYBACK][CD_DRIVE_ID] = self.current_cd_drive_id self.config[CD_PLAYBACK][CD_DRIVE_NAME] = self.current_cd_drive_name self.config[CD_PLAYBACK][CD_TRACK_TIME] = "0" if self.current_cd_drive_name != self.screen_title.text: state.album = self.screen_title.text self.go_cd_player(state) def get_filelist(self): """ Return CD tracks :return: page with CD tracks """ rows = 5 columns = 2 layout = GridLayout(self.layout.CENTER) layout.set_pixel_constraints(rows, columns, 1, 1) constr = layout.get_next_constraints() fixed_height = int((constr.h * 35) / 100.0) tracks = self.cdutil.get_cd_tracks(rows, columns, fixed_height, self.current_cd_drive_name) if tracks == None: tracks = [] return Page(tracks, rows, columns) def set_current(self, state): """ Set current CD drive :param state: state object with drive info """ if not self.current_cd_drive_name or ( getattr(state, "name", None) and self.current_cd_drive_name != state.name): change_menu = False if not self.current_cd_drive_name: self.current_cd_drive_name = self.cdutil.get_default_cd_drive( )[1] change_menu = True elif state.name != "cd": self.current_cd_drive_name = state.name change_menu = True name = self.current_cd_drive_name tracks = len(self.file_menu.filelist.items) empty = self.cdutil.is_drive_empty(name) if name and empty != 1 and tracks == 0: change_menu = True if change_menu: id = self.cdutil.get_cd_drive_id_by_name( self.current_cd_drive_name) self.current_cd_drive_id = id self.file_menu.selected_index = 0 self.set_file_menu() self.set_screen_title() def set_screen_title(self): """ Set screen title """ title = drive_name = self.current_cd_drive_name try: title = self.util.cd_titles[drive_name] except: pass self.screen_title.set_text(title) def eject_cd(self, state): """ Eject CD :param state: state object with drive info """ if len(str(self.current_cd_drive_id)) == 0: return del self.util.cd_track_names_cache[self.current_cd_drive_id] if state == None or getattr(state, "no_physical_eject", None) == None: self.cdutil.eject_cd(int(self.current_cd_drive_id)) self.util.cd_titles[ self.current_cd_drive_name] = self.current_cd_drive_name self.file_menu.selected_index = 0 self.set_file_menu() self.set_screen_title() def refresh_tracks(self, state): """ Refresh tracks menu :param state: not used """ name = self.current_cd_drive_name if name and self.cdutil.is_drive_empty(name): s = State() s.no_physical_eject = True self.eject_cd(s) self.set_file_menu() self.set_screen_title() def set_file_menu(self): """ Set file menu """ filelist = self.get_filelist() self.file_menu.filelist = filelist self.file_menu.update_buttons() page = filelist.get_current_page() self.file_menu.set_page(filelist.current_item_index_in_page, page) for b in self.file_menu.buttons.values(): b.parent_screen = self def get_filelist_items(self, get_current_playlist): """ Call player for files in the playlist :return: list of files from playlist """ playlist = 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 = st.url = playlist[n] files.append(st) return files 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 """ Screen.add_screen_observers(self, update_observer, redraw_observer) self.file_menu.add_menu_observers(update_observer, redraw_observer=None, release=False) self.file_menu.add_change_folder_listener(redraw_observer) self.file_menu.add_menu_navigation_listeners(redraw_observer) self.file_menu.add_left_number_listener(redraw_observer) self.file_menu.add_right_number_listener(redraw_observer) self.navigator.add_observers(update_observer, redraw_observer)
def __init__(self, util, bgr=None, bounding_box=None, font_size=None): """ Initializer :param util: utility object :param bgr: menu background :param bounding_box: bounding box """ self.factory = Factory(util) self.config = util.config m = self.factory.create_home_menu_button Menu.__init__(self, util, bgr, bounding_box, None, None, create_item_method=m, font_size=font_size) cdutil = CdUtil(util) items = [] disabled_items = [] if self.config[HOME_MENU][RADIO]: items.append(RADIO) if not util.is_radio_enabled() or not util.connected_to_internet: disabled_items.append(RADIO) if self.config[HOME_MENU][AUDIO_FILES]: items.append(AUDIO_FILES) if self.config[HOME_MENU][AUDIOBOOKS]: items.append(AUDIOBOOKS) if not util.is_audiobooks_enabled() or not util.connected_to_internet: disabled_items.append(AUDIOBOOKS) if self.config[HOME_MENU][STREAM]: items.append(STREAM) if not util.connected_to_internet: disabled_items.append(STREAM) if self.config[HOME_MENU][CD_PLAYER]: cd_drives_info = cdutil.get_cd_drives_info() player = self.config[AUDIO][PLAYER_NAME] if len(cd_drives_info) == 0: disabled_items.append(CD_PLAYER) items.append(CD_PLAYER) l = self.get_layout(items) bounding_box = l.get_next_constraints() self.modes = util.load_menu(items, NAME, disabled_items, V_ALIGN_TOP, bb=bounding_box, scale=0.5) va_commands = self.util.get_voice_commands() if self.config[USAGE][USE_VOICE_ASSISTANT]: if self.config[HOME_MENU][RADIO]: r = [va_commands["VA_RADIO"].strip(), va_commands["VA_GO_RADIO"].strip()] self.modes[RADIO].voice_commands = r if self.config[HOME_MENU][AUDIO_FILES]: f = [va_commands["VA_FILES"].strip(), va_commands["VA_GO_FILES"].strip(), va_commands["VA_AUDIO_FILES"].strip()] self.modes[AUDIO_FILES].voice_commands = f if self.config[HOME_MENU][AUDIOBOOKS]: a = [va_commands["VA_AUDIOBOOKS"].strip(), va_commands["VA_BOOKS"].strip(), va_commands["VA_GO_BOOKS"].strip()] self.modes[AUDIOBOOKS].voice_commands = a if self.config[HOME_MENU][STREAM]: s = [va_commands["VA_STREAM"].strip(), va_commands["VA_GO_STREAM"].strip()] self.modes[STREAM].voice_commands = s if self.config[HOME_MENU][CD_PLAYER]: s = [va_commands["VA_CD_PLAYER"].strip()] self.modes[STREAM].voice_commands = s if not items: return if not self.config[CURRENT][MODE]: for i in items: if i not in disabled_items: mode = i break else: mode = self.config[CURRENT][MODE] self.set_items(self.modes, 0, self.change_mode, False) self.current_mode = self.modes[mode.lower()] self.item_selected(self.current_mode)
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)