import settings
if hildonize.IS_FREMANTLE_SUPPORTED:
- # I don't normally do this but I want to error as loudly as possibly when an issue arises
- import hildon
+ # I don't normally do this but I want to error as loudly as possibly when an issue arises
+ import hildon
_moduleLogger = logging.getLogger(__name__)
class Gui(object):
- # @todo Jump straight to book selection on first launch?
- # @todo Absolute increments (+/-5 seconds)
- # @todo Show elapsed time / time lef
- # @todo Volume control when screen is off
- # @todo Variable speed
- # http://scaletempo.sourceforge.net/0/task-list.html
- # http://www.gstreamer.net/data/doc/gstreamer/head/gst-plugins-bad-plugins/html/gst-plugins-bad-plugins-scaletempo.html
-
- def __init__(self):
- _moduleLogger.info("Starting GUI")
- self._clipboard = gtk.clipboard_get()
- self._callMonitor = CallMonitor.CallMonitor()
- self.__settingsWindow = None
- self.__settingsManager = None
- self._bookSelection = []
- self._bookSelectionIndex = -1
- self._chapterSelection = []
- self._chapterSelectionIndex = -1
- self._sleepSelection = ["0", "1", "10", "20", "30", "60"]
- self._sleepSelectionIndex = 0
-
- self.__window_in_fullscreen = False #The window isn't in full screen mode initially.
- self.__isPortrait = False
-
- self.controller = None
- self.sleep_timer = None
-
- # set up gui
- self.setup()
- self._callMonitor.connect("call_start", self.__on_call_started)
- self._callMonitor.start()
-
- def setup(self):
- self._app = hildonize.get_app_class()()
- self.win = gtk.Window()
- self.win = hildonize.hildonize_window(self._app, self.win)
- self.win.set_title(constants.__pretty_app_name__)
-
- # Cover image
- self.cover = gtk.Image()
-
- # Controls:
-
- # Label that hold the title of the book,and maybe the chapter
- self.title = gtk.Label()
- self.title.set_justify(gtk.JUSTIFY_CENTER)
- self._set_display_title("Select a book to start listening")
-
- self.chapter = gtk.Label()
- self.chapter.set_justify(gtk.JUSTIFY_CENTER)
-
- # Seekbar
- if hildonize.IS_FREMANTLE_SUPPORTED:
- self.seek = hildon.Seekbar()
- self.seek.set_range(0.0, 100)
- self.seek.set_draw_value(False)
- self.seek.set_update_policy(gtk.UPDATE_DISCONTINUOUS)
- self.seek.connect('change-value', self.seek_changed) # event
- # self.seek.connect('value-changed',self.seek_changed) # event
- else:
- adjustment = gtk.Adjustment(0, 0, 101, 1, 5, 1)
- self.seek = gtk.HScale(adjustment)
- self.seek.set_draw_value(False)
- self.seek.connect('change-value', self.seek_changed) # event
-
- # Pause button
- if hildonize.IS_FREMANTLE_SUPPORTED:
- self.backButton = hildon.Button(gtk.HILDON_SIZE_AUTO_WIDTH | gtk.HILDON_SIZE_FINGER_HEIGHT, hildon.BUTTON_ARRANGEMENT_VERTICAL)
- image = gtk.image_new_from_stock(gtk.STOCK_MEDIA_PREVIOUS, gtk.HILDON_SIZE_FINGER_HEIGHT)
- self.backButton.set_image(image)
-
- self.button = hildon.Button(gtk.HILDON_SIZE_AUTO_WIDTH | gtk.HILDON_SIZE_FINGER_HEIGHT, hildon.BUTTON_ARRANGEMENT_VERTICAL)
-
- self.forwardButton = hildon.Button(gtk.HILDON_SIZE_AUTO_WIDTH | gtk.HILDON_SIZE_FINGER_HEIGHT, hildon.BUTTON_ARRANGEMENT_VERTICAL)
- image = gtk.image_new_from_stock(gtk.STOCK_MEDIA_NEXT, gtk.HILDON_SIZE_FINGER_HEIGHT)
- self.forwardButton.set_image(image)
- else:
- self.backButton = gtk.Button(stock=gtk.STOCK_MEDIA_PREVIOUS)
- self.button = gtk.Button()
- self.forwardButton = gtk.Button(stock=gtk.STOCK_MEDIA_NEXT)
- self.set_button_text("Play", "Start playing the audiobook")
- self.backButton.connect('clicked', self._on_previous_chapter)
- self.button.connect('clicked', self.play_pressed) # event
- self.forwardButton.connect('clicked', self._on_next_chapter)
-
- self._toolbar = gtk.HBox()
- self._toolbar.pack_start(self.backButton, False, False, 0)
- self._toolbar.pack_start(self.button, True, True, 0)
- self._toolbar.pack_start(self.forwardButton, False, False, 0)
-
- # Box to hold the controls:
- self._controlLayout = gtk.VBox()
- self._controlLayout.pack_start(gtk.Label(), True, True, 0)
- self._controlLayout.pack_start(self.title, False, True, 0)
- self._controlLayout.pack_start(self.chapter, False, True, 0)
- self._controlLayout.pack_start(gtk.Label(), True, True, 0)
- self._controlLayout.pack_start(self.seek, False, True, 0)
- self._controlLayout.pack_start(self._toolbar, False, True, 0)
-
- #Box that divides the layout in two: cover on the lefta
- #and controls on the right
- self._viewLayout = gtk.HBox()
- self._viewLayout.pack_start(self.cover, True, True, 0)
- self._viewLayout.add(self._controlLayout)
-
- self._menuBar = gtk.MenuBar()
- self._menuBar.show()
-
- self._mainLayout = gtk.VBox()
- self._mainLayout.pack_start(self._menuBar, False, False, 0)
- self._mainLayout.pack_start(self._viewLayout)
-
- # Add hbox to the window
- self.win.add(self._mainLayout)
-
- #Menu:
- # Create menu
- self._populate_menu()
-
- self.win.connect("delete_event", self.quit) # Add shutdown event
- self.win.connect("key-press-event", self.on_key_press)
- self.win.connect("window-state-event", self._on_window_state_change)
-
- self.win.show_all()
-
- # Run update timer
- self.setup_timers()
-
- def _populate_menu(self):
- self._menuBar = hildonize.hildonize_menu(
- self.win,
- self._menuBar,
- )
- if hildonize.IS_FREMANTLE_SUPPORTED:
- # Create a picker button
- self.book_button = hildon.Button(gtk.HILDON_SIZE_AUTO,
- hildon.BUTTON_ARRANGEMENT_VERTICAL)
- self.book_button.set_title("Audiobook") # Set a title to the button
- self.book_button.connect("clicked", self._on_select_audiobook)
-
- # Create a picker button
- self.chapter_button = hildon.Button(gtk.HILDON_SIZE_AUTO,
- hildon.BUTTON_ARRANGEMENT_VERTICAL)
- self.chapter_button.set_title("Chapter") # Set a title to the button
- self.chapter_button.connect("clicked", self._on_select_chapter)
-
- # Create a picker button
- self.sleeptime_button = hildon.Button(gtk.HILDON_SIZE_AUTO,
- hildon.BUTTON_ARRANGEMENT_VERTICAL)
- self.sleeptime_button.set_title("Sleeptimer") # Set a title to the button
- self.sleeptime_button.connect("clicked", self._on_select_sleep)
-
- settings_button = hildon.Button(gtk.HILDON_SIZE_AUTO, hildon.BUTTON_ARRANGEMENT_VERTICAL)
- settings_button.set_label("Settings")
- settings_button.connect("clicked", self._on_settings)
-
- about_button = hildon.Button(gtk.HILDON_SIZE_AUTO, hildon.BUTTON_ARRANGEMENT_VERTICAL)
- about_button.set_label("About")
- about_button.connect("clicked", self._on_about_activate)
-
- help_button = hildon.Button(gtk.HILDON_SIZE_AUTO, hildon.BUTTON_ARRANGEMENT_VERTICAL)
- help_button.set_label("Help")
- help_button.connect("clicked", self.get_help)
-
- self._menuBar.append(self.book_button) # Add the button to menu
- self._menuBar.append(self.chapter_button) # Add the button to menu
- self._menuBar.append(self.sleeptime_button) # Add the button to menu
- self._menuBar.append(settings_button)
- self._menuBar.append(help_button)
- self._menuBar.append(about_button)
- self._menuBar.show_all()
- else:
- self._audiobookMenuItem = gtk.MenuItem("Audiobook: ")
- self._audiobookMenuItem.connect("activate", self._on_select_audiobook)
-
- self._chapterMenuItem = gtk.MenuItem("Chapter: ")
- self._chapterMenuItem.connect("activate", self._on_select_chapter)
-
- self._sleepMenuItem = gtk.MenuItem("Sleeptimer: 0")
- self._sleepMenuItem.connect("activate", self._on_select_sleep)
-
- settingsMenuItem = gtk.MenuItem("Settings")
- settingsMenuItem.connect("activate", self._on_settings)
-
- aboutMenuItem = gtk.MenuItem("About")
- aboutMenuItem.connect("activate", self._on_about_activate)
-
- helpMenuItem = gtk.MenuItem("Help")
- helpMenuItem.connect("activate", self.get_help)
-
- booksMenu = gtk.Menu()
- booksMenu.append(self._audiobookMenuItem)
- booksMenu.append(self._chapterMenuItem)
- booksMenu.append(self._sleepMenuItem)
- booksMenu.append(settingsMenuItem)
- booksMenu.append(helpMenuItem)
- booksMenu.append(aboutMenuItem)
-
- booksMenuItem = gtk.MenuItem("Books")
- booksMenuItem.show()
- booksMenuItem.set_submenu(booksMenu)
- self._menuBar.append(booksMenuItem)
- self._menuBar.show_all()
-
- def setup_timers(self):
- self.seek_timer = timeout_add_seconds(3, self.update_seek)
-
- def save_settings(self):
- config = ConfigParser.SafeConfigParser()
- self._save_settings(config)
- with open(constants._user_settings_, "wb") as configFile:
- config.write(configFile)
- self.controller.save()
-
- def _save_settings(self, config):
- config.add_section(constants.__pretty_app_name__)
- config.set(constants.__pretty_app_name__, "portrait", str(self.__isPortrait))
- config.set(constants.__pretty_app_name__, "fullscreen", str(self.__window_in_fullscreen))
- config.set(constants.__pretty_app_name__, "audiopath", self.controller.get_books_path())
-
- def load_settings(self):
- config = ConfigParser.SafeConfigParser()
- config.read(constants._user_settings_)
- self._load_settings(config)
-
- def _load_settings(self, config):
- isPortrait = False
- window_in_fullscreen = False
- booksPath = constants._default_book_path_
- try:
- isPortrait = config.getboolean(constants.__pretty_app_name__, "portrait")
- window_in_fullscreen = config.getboolean(constants.__pretty_app_name__, "fullscreen")
- booksPath = config.get(constants.__pretty_app_name__, "audiopath")
- except ConfigParser.NoSectionError, e:
- _moduleLogger.info(
- "Settings file %s is missing section %s" % (
- constants._user_settings_,
- e.section,
- )
- )
-
- if isPortrait ^ self.__isPortrait:
- if isPortrait:
- orientation = gtk.ORIENTATION_VERTICAL
- else:
- orientation = gtk.ORIENTATION_HORIZONTAL
- self.set_orientation(orientation)
-
- self.__window_in_fullscreen = window_in_fullscreen
- if self.__window_in_fullscreen:
- self.win.fullscreen()
- else:
- self.win.unfullscreen()
-
- self.controller.load(booksPath)
-
- @staticmethod
- def __format_name(path):
- if os.path.isfile(path):
- return os.path.basename(path).rsplit(".", 1)[0]
- else:
- return os.path.basename(path)
-
- @gtk_toolbox.log_exception(_moduleLogger)
- def _on_select_audiobook(self, *args):
- if not self._bookSelection:
- return
- index = hildonize.touch_selector(
- self.win,
- "Audiobook",
- (self.__format_name(bookPath) for bookPath in self._bookSelection),
- self._bookSelectionIndex if 0 <= self._bookSelectionIndex else 0,
- )
- self._bookSelectionIndex = index
- bookName = self._bookSelection[index]
- self.controller.set_book(bookName)
- self.set_button_text("Play", "Start playing the audiobook") # reset button
-
- @gtk_toolbox.log_exception(_moduleLogger)
- def _on_select_chapter(self, *args):
- if not self._chapterSelection:
- return
- index = hildonize.touch_selector(
- self.win,
- "Chapter",
- (self.__format_name(chapterPath) for chapterPath in self._chapterSelection),
- self._chapterSelectionIndex if 0 <= self._chapterSelectionIndex else 0,
- )
- self._chapterSelectionIndex = index
- chapterName = self._chapterSelection[index]
- self.controller.set_chapter(chapterName)
- self.set_button_text("Play", "Start playing the audiobook") # reset button
-
- @gtk_toolbox.log_exception(_moduleLogger)
- def _on_select_sleep(self, *args):
- if self.sleep_timer is not None:
- gobject.source_remove(self.sleep_timer)
-
- try:
- index = hildonize.touch_selector(
- self.win,
- "Sleeptimer",
- self._sleepSelection,
- self._sleepSelectionIndex if 0 <= self._sleepSelectionIndex else 0,
- )
- except RuntimeError:
- _moduleLogger.exception("Handling as if user cancelled")
- hildonize.show_information_banner(self.win, "Sleep timer canceled")
- index = 0
-
- self._sleepSelectionIndex = index
- sleepName = self._sleepSelection[index]
-
- time_out = int(sleepName)
- if 0 < time_out:
- timeout_add_seconds(time_out * 60, self.sleep)
-
- if hildonize.IS_FREMANTLE_SUPPORTED:
- self.sleeptime_button.set_text("Sleeptimer", sleepName)
- else:
- self._sleepMenuItem.get_child().set_text("Sleeptimer: %s" % (sleepName, ))
-
- @gtk_toolbox.log_exception(_moduleLogger)
- def __on_call_started(self, callMonitor):
- self.pause()
-
- @gtk_toolbox.log_exception(_moduleLogger)
- def _on_settings(self, *args):
- if self.__settingsWindow is None:
- vbox = gtk.VBox()
- self.__settingsManager = settings.SettingsDialog(vbox)
-
- self.__settingsWindow = gtk.Window()
- self.__settingsWindow.add(vbox)
- self.__settingsWindow = hildonize.hildonize_window(self._app, self.__settingsWindow)
- self.__settingsManager.window = self.__settingsWindow
-
- self.__settingsWindow.set_title("Settings")
- self.__settingsWindow.set_transient_for(self.win)
- self.__settingsWindow.set_default_size(*self.win.get_size())
- self.__settingsWindow.connect("delete-event", self._on_settings_delete)
- self.__settingsManager.set_portrait_state(self.__isPortrait)
- self.__settingsManager.set_audiobook_path(self.controller.get_books_path())
- self.__settingsWindow.set_modal(True)
- self.__settingsWindow.show_all()
-
- @gtk_toolbox.log_exception(_moduleLogger)
- def _on_settings_delete(self, *args):
- self.__settingsWindow.emit_stop_by_name("delete-event")
- self.__settingsWindow.hide()
- self.__settingsWindow.set_modal(False)
-
- isPortrait = self.__settingsManager.is_portrait()
- if isPortrait ^ self.__isPortrait:
- if isPortrait:
- orientation = gtk.ORIENTATION_VERTICAL
- else:
- orientation = gtk.ORIENTATION_HORIZONTAL
- self.set_orientation(orientation)
- if self.__settingsManager.get_audiobook_path() != self.controller.get_books_path():
- self.controller.reload(self.__settingsManager.get_audiobook_path())
-
- return True
-
- @gtk_toolbox.log_exception(_moduleLogger)
- def update_seek(self):
- #print self.controller.get_percentage()
- if self.controller.is_playing():
- gtk.gdk.threads_enter()
- self.seek.set_value(self.controller.get_percentage() * 100)
- gtk.gdk.threads_leave()
- #self.controller.get_percentage()
- return True # run again
-
- @gtk_toolbox.log_exception(_moduleLogger)
- def sleep(self):
- _moduleLogger.info("sleep time timeout")
- hildonize.show_information_banner(self.win, "Sleep timer")
- self.controller.stop()
- self.set_button_text("Resume", "Resume playing the audiobook")
- return False # do not repeat
-
- @gtk_toolbox.log_exception(_moduleLogger)
- def get_help(self, button):
- Browser.open("file:///opt/Nqa-Audiobook-player/Help/nqaap.html")
-
- @gtk_toolbox.log_exception(_moduleLogger)
- def seek_changed(self, seek, scroll , value):
- # print "sok", scroll
- self.controller.seek_percent(seek.get_value() / 100.0)
-
- @gtk_toolbox.log_exception(_moduleLogger)
- def _on_next_chapter(self, *args):
- self.controller.next_chapter()
-
- @gtk_toolbox.log_exception(_moduleLogger)
- def _on_previous_chapter(self, *args):
- self.controller.previous_chapter()
-
- @gtk_toolbox.log_exception(_moduleLogger)
- def play_pressed(self, button):
- if self.controller.is_playing():
- self.pause()
- else:
- self.play()
-
- @gtk_toolbox.log_exception(_moduleLogger)
- def on_key_press(self, widget, event, *args):
- RETURN_TYPES = (gtk.keysyms.Return, gtk.keysyms.ISO_Enter, gtk.keysyms.KP_Enter)
- isCtrl = bool(event.get_state() & gtk.gdk.CONTROL_MASK)
- if (
- event.keyval == gtk.keysyms.F6 or
- event.keyval in RETURN_TYPES and isCtrl
- ):
- # The "Full screen" hardware key has been pressed
- if self.__window_in_fullscreen:
- self.win.unfullscreen ()
- else:
- self.win.fullscreen ()
- return True
- elif event.keyval == gtk.keysyms.o and isCtrl:
- self._toggle_rotate()
- return True
- elif (
- event.keyval in (gtk.keysyms.w, gtk.keysyms.q) and
- event.get_state() & gtk.gdk.CONTROL_MASK
- ):
- self.quit()
- elif event.keyval == gtk.keysyms.l and event.get_state() & gtk.gdk.CONTROL_MASK:
- with open(constants._user_logpath_, "r") as f:
- logLines = f.xreadlines()
- log = "".join(logLines)
- self._clipboard.set_text(str(log))
- return True
- elif event.keyval in RETURN_TYPES:
- if self.controller.is_playing():
- self.pause()
- else:
- self.play()
- return True
- elif event.keyval == gtk.keysyms.Left:
- self.controller.previous_chapter()
- return True
- elif event.keyval == gtk.keysyms.Right:
- self.controller.next_chapter()
- return True
-
- @gtk_toolbox.log_exception(_moduleLogger)
- def _on_window_state_change(self, widget, event, *args):
- if event.new_window_state & gtk.gdk.WINDOW_STATE_FULLSCREEN:
- self.__window_in_fullscreen = True
- else:
- self.__window_in_fullscreen = False
-
- @gtk_toolbox.log_exception(_moduleLogger)
- def quit(self, *args): # what are the arguments?
- _moduleLogger.info("Shutting down")
- try:
- self.save_settings()
- self.controller.stop() # to save the state
- finally:
- gtk.main_quit()
-
- @gtk_toolbox.log_exception(_moduleLogger)
- def _on_about_activate(self, *args):
- dlg = gtk.AboutDialog()
- dlg.set_name(constants.__pretty_app_name__)
- dlg.set_version("%s-%d" % (constants.__version__, constants.__build__))
- dlg.set_copyright("Copyright 2010")
- dlg.set_comments("")
- dlg.set_website("http://nqaap.garage.maemo.org/")
- dlg.set_authors(["Pengman <pengmeister@gmail.com>", "Ed Page <eopage@byu.net>"])
- dlg.run()
- dlg.destroy()
-
- # Actions:
-
- def play(self):
- self.set_button_text("Stop", "Stop playing the audiobook")
- self.controller.play()
-
- def pause(self):
- self.set_button_text("Resume", "Resume playing the audiobook")
- self.controller.stop()
-
- def set_orientation(self, orientation):
- if orientation == gtk.ORIENTATION_VERTICAL:
- if self.__isPortrait:
- return
- hildonize.window_to_portrait(self.win)
- self.__isPortrait = True
-
- self._viewLayout.remove(self._controlLayout)
- self._mainLayout.add(self._controlLayout)
- elif orientation == gtk.ORIENTATION_HORIZONTAL:
- if not self.__isPortrait:
- return
- hildonize.window_to_landscape(self.win)
- self.__isPortrait = False
-
- self._mainLayout.remove(self._controlLayout)
- self._viewLayout.add(self._controlLayout)
- else:
- raise NotImplementedError(orientation)
-
- def get_orientation(self):
- return gtk.ORIENTATION_VERTICAL if self.__isPortrait else gtk.ORIENTATION_HORIZONTAL
-
- def _toggle_rotate(self):
- if self.__isPortrait:
- self.set_orientation(gtk.ORIENTATION_HORIZONTAL)
- else:
- self.set_orientation(gtk.ORIENTATION_VERTICAL)
-
- def change_chapter(self, chapterName):
- if chapterName is None:
- _moduleLogger.debug("chapter selection canceled.")
- return True # this should end the function and indicate it has been handled
-
- _moduleLogger.debug("chapter changed (by controller) to: %s" % chapterName)
-
- def set_button_text(self, title, text):
- if hildonize.IS_FREMANTLE_SUPPORTED:
- self.button.set_text(title, text)
- else:
- self.button.set_label("%s" % (title, ))
-
- def set_books(self, books):
- _moduleLogger.debug("new books")
- del self._bookSelection[:]
- self._bookSelection.extend(books)
- if len(books) == 0 and self.controller is not None:
- hildonize.show_information_banner(self.win, "No audiobooks found. \nPlease place your audiobooks in the directory %s" % self.controller.get_books_path())
-
- def set_book(self, bookPath, cover):
- bookName = self.__format_name(bookPath)
-
- self.set_button_text("Play", "Start playing the audiobook") # reset button
- self._set_display_title(bookName)
- if hildonize.IS_FREMANTLE_SUPPORTED:
- self.book_button.set_text("Audiobook", bookName)
- else:
- self._audiobookMenuItem.get_child().set_text("Audiobook: %s" % (bookName, ))
- if cover != "":
- self.cover.set_from_file(cover)
-
- def set_chapter(self, chapterIndex):
- '''
- Called from controller whenever a new chapter is started
-
- chapter parameter is supposed to be the index for the chapter, not the name
- '''
- self.auto_chapter_selected = True
- self._set_display_chapter(str(chapterIndex + 1))
- if hildonize.IS_FREMANTLE_SUPPORTED:
- self.chapter_button.set_text("Chapter", str(chapterIndex))
- else:
- self._chapterMenuItem.get_child().set_text("Chapter: %s" % (chapterIndex+1, ))
-
- def set_chapters(self, chapters):
- _moduleLogger.debug("setting chapters" )
- del self._chapterSelection[:]
- self._chapterSelection.extend(chapters)
-
- def set_sleep_timer(self, mins):
- pass
-
- # Utils
- def set_selected_value(self, button, value):
- i = button.get_selector().get_model(0).index[value] # get index of value from list
- button.set_active(i) # set active index to that index
-
- def _set_display_title(self, title):
- self.title.set_markup("<b><big>%s</big></b>" % title)
-
- def _set_display_chapter(self, chapter):
- self.chapter.set_markup("<b><big>Chapter %s</big></b>" % chapter)
+ # @todo Jump straight to book selection on first launch?
+ # @todo Absolute increments (+/-5 seconds)
+ # @todo Show elapsed time / time lef
+ # @todo Volume control when screen is off
+ # @todo Variable speed
+ # http://scaletempo.sourceforge.net/0/task-list.html
+ # http://www.gstreamer.net/data/doc/gstreamer/head/gst-plugins-bad-plugins/html/gst-plugins-bad-plugins-scaletempo.html
+
+ def __init__(self):
+ _moduleLogger.info("Starting GUI")
+ self._clipboard = gtk.clipboard_get()
+ self._callMonitor = CallMonitor.CallMonitor()
+ self.__settingsWindow = None
+ self.__settingsManager = None
+ self._bookSelection = []
+ self._bookSelectionIndex = -1
+ self._chapterSelection = []
+ self._chapterSelectionIndex = -1
+ self._sleepSelection = ["0", "1", "10", "20", "30", "60"]
+ self._sleepSelectionIndex = 0
+
+ self.__window_in_fullscreen = False #The window isn't in full screen mode initially.
+ self.__isPortrait = False
+
+ self.controller = None
+ self.sleep_timer = None
+
+ # set up gui
+ self.setup()
+ self._callMonitor.connect("call_start", self.__on_call_started)
+ self._callMonitor.start()
+
+ def setup(self):
+ self._app = hildonize.get_app_class()()
+ self.win = gtk.Window()
+ self.win = hildonize.hildonize_window(self._app, self.win)
+ self.win.set_title(constants.__pretty_app_name__)
+
+ # Cover image
+ self.cover = gtk.Image()
+
+ # Controls:
+
+ # Label that hold the title of the book,and maybe the chapter
+ self.title = gtk.Label()
+ self.title.set_justify(gtk.JUSTIFY_CENTER)
+ self._set_display_title("Select a book to start listening")
+
+ self.chapter = gtk.Label()
+ self.chapter.set_justify(gtk.JUSTIFY_CENTER)
+
+ # Seekbar
+ if hildonize.IS_FREMANTLE_SUPPORTED:
+ self.seek = hildon.Seekbar()
+ self.seek.set_range(0.0, 100)
+ self.seek.set_draw_value(False)
+ self.seek.set_update_policy(gtk.UPDATE_DISCONTINUOUS)
+ self.seek.connect('change-value', self.seek_changed) # event
+ # self.seek.connect('value-changed',self.seek_changed) # event
+ else:
+ adjustment = gtk.Adjustment(0, 0, 101, 1, 5, 1)
+ self.seek = gtk.HScale(adjustment)
+ self.seek.set_draw_value(False)
+ self.seek.connect('change-value', self.seek_changed) # event
+
+ # Pause button
+ if hildonize.IS_FREMANTLE_SUPPORTED:
+ self.backButton = hildon.Button(gtk.HILDON_SIZE_AUTO_WIDTH | gtk.HILDON_SIZE_FINGER_HEIGHT, hildon.BUTTON_ARRANGEMENT_VERTICAL)
+ image = gtk.image_new_from_stock(gtk.STOCK_MEDIA_PREVIOUS, gtk.HILDON_SIZE_FINGER_HEIGHT)
+ self.backButton.set_image(image)
+
+ self.button = hildon.Button(gtk.HILDON_SIZE_AUTO_WIDTH | gtk.HILDON_SIZE_FINGER_HEIGHT, hildon.BUTTON_ARRANGEMENT_VERTICAL)
+
+ self.forwardButton = hildon.Button(gtk.HILDON_SIZE_AUTO_WIDTH | gtk.HILDON_SIZE_FINGER_HEIGHT, hildon.BUTTON_ARRANGEMENT_VERTICAL)
+ image = gtk.image_new_from_stock(gtk.STOCK_MEDIA_NEXT, gtk.HILDON_SIZE_FINGER_HEIGHT)
+ self.forwardButton.set_image(image)
+ else:
+ self.backButton = gtk.Button(stock=gtk.STOCK_MEDIA_PREVIOUS)
+ self.button = gtk.Button()
+ self.forwardButton = gtk.Button(stock=gtk.STOCK_MEDIA_NEXT)
+ self.set_button_text("Play", "Start playing the audiobook")
+ self.backButton.connect('clicked', self._on_previous_chapter)
+ self.button.connect('clicked', self.play_pressed) # event
+ self.forwardButton.connect('clicked', self._on_next_chapter)
+
+ self._toolbar = gtk.HBox()
+ self._toolbar.pack_start(self.backButton, False, False, 0)
+ self._toolbar.pack_start(self.button, True, True, 0)
+ self._toolbar.pack_start(self.forwardButton, False, False, 0)
+
+ # Box to hold the controls:
+ self._controlLayout = gtk.VBox()
+ self._controlLayout.pack_start(gtk.Label(), True, True, 0)
+ self._controlLayout.pack_start(self.title, False, True, 0)
+ self._controlLayout.pack_start(self.chapter, False, True, 0)
+ self._controlLayout.pack_start(gtk.Label(), True, True, 0)
+ self._controlLayout.pack_start(self.seek, False, True, 0)
+ self._controlLayout.pack_start(self._toolbar, False, True, 0)
+
+ #Box that divides the layout in two: cover on the lefta
+ #and controls on the right
+ self._viewLayout = gtk.HBox()
+ self._viewLayout.pack_start(self.cover, True, True, 0)
+ self._viewLayout.add(self._controlLayout)
+
+ self._menuBar = gtk.MenuBar()
+ self._menuBar.show()
+
+ self._mainLayout = gtk.VBox()
+ self._mainLayout.pack_start(self._menuBar, False, False, 0)
+ self._mainLayout.pack_start(self._viewLayout)
+
+ # Add hbox to the window
+ self.win.add(self._mainLayout)
+
+ #Menu:
+ # Create menu
+ self._populate_menu()
+
+ self.win.connect("delete_event", self.quit) # Add shutdown event
+ self.win.connect("key-press-event", self.on_key_press)
+ self.win.connect("window-state-event", self._on_window_state_change)
+
+ self.win.show_all()
+
+ # Run update timer
+ self.setup_timers()
+
+ def _populate_menu(self):
+ self._menuBar = hildonize.hildonize_menu(
+ self.win,
+ self._menuBar,
+ )
+ if hildonize.IS_FREMANTLE_SUPPORTED:
+ # Create a picker button
+ self.book_button = hildon.Button(gtk.HILDON_SIZE_AUTO,
+ hildon.BUTTON_ARRANGEMENT_VERTICAL)
+ self.book_button.set_title("Audiobook") # Set a title to the button
+ self.book_button.connect("clicked", self._on_select_audiobook)
+
+ # Create a picker button
+ self.chapter_button = hildon.Button(gtk.HILDON_SIZE_AUTO,
+ hildon.BUTTON_ARRANGEMENT_VERTICAL)
+ self.chapter_button.set_title("Chapter") # Set a title to the button
+ self.chapter_button.connect("clicked", self._on_select_chapter)
+
+ # Create a picker button
+ self.sleeptime_button = hildon.Button(gtk.HILDON_SIZE_AUTO,
+ hildon.BUTTON_ARRANGEMENT_VERTICAL)
+ self.sleeptime_button.set_title("Sleeptimer") # Set a title to the button
+ self.sleeptime_button.connect("clicked", self._on_select_sleep)
+
+ settings_button = hildon.Button(gtk.HILDON_SIZE_AUTO, hildon.BUTTON_ARRANGEMENT_VERTICAL)
+ settings_button.set_label("Settings")
+ settings_button.connect("clicked", self._on_settings)
+
+ about_button = hildon.Button(gtk.HILDON_SIZE_AUTO, hildon.BUTTON_ARRANGEMENT_VERTICAL)
+ about_button.set_label("About")
+ about_button.connect("clicked", self._on_about_activate)
+
+ help_button = hildon.Button(gtk.HILDON_SIZE_AUTO, hildon.BUTTON_ARRANGEMENT_VERTICAL)
+ help_button.set_label("Help")
+ help_button.connect("clicked", self.get_help)
+
+ self._menuBar.append(self.book_button) # Add the button to menu
+ self._menuBar.append(self.chapter_button) # Add the button to menu
+ self._menuBar.append(self.sleeptime_button) # Add the button to menu
+ self._menuBar.append(settings_button)
+ self._menuBar.append(help_button)
+ self._menuBar.append(about_button)
+ self._menuBar.show_all()
+ else:
+ self._audiobookMenuItem = gtk.MenuItem("Audiobook: ")
+ self._audiobookMenuItem.connect("activate", self._on_select_audiobook)
+
+ self._chapterMenuItem = gtk.MenuItem("Chapter: ")
+ self._chapterMenuItem.connect("activate", self._on_select_chapter)
+
+ self._sleepMenuItem = gtk.MenuItem("Sleeptimer: 0")
+ self._sleepMenuItem.connect("activate", self._on_select_sleep)
+
+ settingsMenuItem = gtk.MenuItem("Settings")
+ settingsMenuItem.connect("activate", self._on_settings)
+
+ aboutMenuItem = gtk.MenuItem("About")
+ aboutMenuItem.connect("activate", self._on_about_activate)
+
+ helpMenuItem = gtk.MenuItem("Help")
+ helpMenuItem.connect("activate", self.get_help)
+
+ booksMenu = gtk.Menu()
+ booksMenu.append(self._audiobookMenuItem)
+ booksMenu.append(self._chapterMenuItem)
+ booksMenu.append(self._sleepMenuItem)
+ booksMenu.append(settingsMenuItem)
+ booksMenu.append(helpMenuItem)
+ booksMenu.append(aboutMenuItem)
+
+ booksMenuItem = gtk.MenuItem("Books")
+ booksMenuItem.show()
+ booksMenuItem.set_submenu(booksMenu)
+ self._menuBar.append(booksMenuItem)
+ self._menuBar.show_all()
+
+ def setup_timers(self):
+ self.seek_timer = timeout_add_seconds(3, self.update_seek)
+
+ def save_settings(self):
+ config = ConfigParser.SafeConfigParser()
+ self._save_settings(config)
+ with open(constants._user_settings_, "wb") as configFile:
+ config.write(configFile)
+ self.controller.save()
+
+ def _save_settings(self, config):
+ config.add_section(constants.__pretty_app_name__)
+ config.set(constants.__pretty_app_name__, "portrait", str(self.__isPortrait))
+ config.set(constants.__pretty_app_name__, "fullscreen", str(self.__window_in_fullscreen))
+ config.set(constants.__pretty_app_name__, "audiopath", self.controller.get_books_path())
+
+ def load_settings(self):
+ config = ConfigParser.SafeConfigParser()
+ config.read(constants._user_settings_)
+ self._load_settings(config)
+
+ def _load_settings(self, config):
+ isPortrait = False
+ window_in_fullscreen = False
+ booksPath = constants._default_book_path_
+ try:
+ isPortrait = config.getboolean(constants.__pretty_app_name__, "portrait")
+ window_in_fullscreen = config.getboolean(constants.__pretty_app_name__, "fullscreen")
+ booksPath = config.get(constants.__pretty_app_name__, "audiopath")
+ except ConfigParser.NoSectionError, e:
+ _moduleLogger.info(
+ "Settings file %s is missing section %s" % (
+ constants._user_settings_,
+ e.section,
+ )
+ )
+
+ if isPortrait ^ self.__isPortrait:
+ if isPortrait:
+ orientation = gtk.ORIENTATION_VERTICAL
+ else:
+ orientation = gtk.ORIENTATION_HORIZONTAL
+ self.set_orientation(orientation)
+
+ self.__window_in_fullscreen = window_in_fullscreen
+ if self.__window_in_fullscreen:
+ self.win.fullscreen()
+ else:
+ self.win.unfullscreen()
+
+ self.controller.load(booksPath)
+
+ @staticmethod
+ def __format_name(path):
+ if os.path.isfile(path):
+ return os.path.basename(path).rsplit(".", 1)[0]
+ else:
+ return os.path.basename(path)
+
+ @gtk_toolbox.log_exception(_moduleLogger)
+ def _on_select_audiobook(self, *args):
+ if not self._bookSelection:
+ return
+ index = hildonize.touch_selector(
+ self.win,
+ "Audiobook",
+ (self.__format_name(bookPath) for bookPath in self._bookSelection),
+ self._bookSelectionIndex if 0 <= self._bookSelectionIndex else 0,
+ )
+ self._bookSelectionIndex = index
+ bookName = self._bookSelection[index]
+ self.controller.set_book(bookName)
+ self.set_button_text("Play", "Start playing the audiobook") # reset button
+
+ @gtk_toolbox.log_exception(_moduleLogger)
+ def _on_select_chapter(self, *args):
+ if not self._chapterSelection:
+ return
+ index = hildonize.touch_selector(
+ self.win,
+ "Chapter",
+ (self.__format_name(chapterPath) for chapterPath in self._chapterSelection),
+ self._chapterSelectionIndex if 0 <= self._chapterSelectionIndex else 0,
+ )
+ self._chapterSelectionIndex = index
+ chapterName = self._chapterSelection[index]
+ self.controller.set_chapter(chapterName)
+ self.set_button_text("Play", "Start playing the audiobook") # reset button
+
+ @gtk_toolbox.log_exception(_moduleLogger)
+ def _on_select_sleep(self, *args):
+ if self.sleep_timer is not None:
+ gobject.source_remove(self.sleep_timer)
+
+ try:
+ index = hildonize.touch_selector(
+ self.win,
+ "Sleeptimer",
+ self._sleepSelection,
+ self._sleepSelectionIndex if 0 <= self._sleepSelectionIndex else 0,
+ )
+ except RuntimeError:
+ _moduleLogger.exception("Handling as if user cancelled")
+ hildonize.show_information_banner(self.win, "Sleep timer canceled")
+ index = 0
+
+ self._sleepSelectionIndex = index
+ sleepName = self._sleepSelection[index]
+
+ time_out = int(sleepName)
+ if 0 < time_out:
+ timeout_add_seconds(time_out * 60, self.sleep)
+
+ if hildonize.IS_FREMANTLE_SUPPORTED:
+ self.sleeptime_button.set_text("Sleeptimer", sleepName)
+ else:
+ self._sleepMenuItem.get_child().set_text("Sleeptimer: %s" % (sleepName, ))
+
+ @gtk_toolbox.log_exception(_moduleLogger)
+ def __on_call_started(self, callMonitor):
+ self.pause()
+
+ @gtk_toolbox.log_exception(_moduleLogger)
+ def _on_settings(self, *args):
+ if self.__settingsWindow is None:
+ vbox = gtk.VBox()
+ self.__settingsManager = settings.SettingsDialog(vbox)
+
+ self.__settingsWindow = gtk.Window()
+ self.__settingsWindow.add(vbox)
+ self.__settingsWindow = hildonize.hildonize_window(self._app, self.__settingsWindow)
+ self.__settingsManager.window = self.__settingsWindow
+
+ self.__settingsWindow.set_title("Settings")
+ self.__settingsWindow.set_transient_for(self.win)
+ self.__settingsWindow.set_default_size(*self.win.get_size())
+ self.__settingsWindow.connect("delete-event", self._on_settings_delete)
+ self.__settingsManager.set_portrait_state(self.__isPortrait)
+ self.__settingsManager.set_audiobook_path(self.controller.get_books_path())
+ self.__settingsWindow.set_modal(True)
+ self.__settingsWindow.show_all()
+
+ @gtk_toolbox.log_exception(_moduleLogger)
+ def _on_settings_delete(self, *args):
+ self.__settingsWindow.emit_stop_by_name("delete-event")
+ self.__settingsWindow.hide()
+ self.__settingsWindow.set_modal(False)
+
+ isPortrait = self.__settingsManager.is_portrait()
+ if isPortrait ^ self.__isPortrait:
+ if isPortrait:
+ orientation = gtk.ORIENTATION_VERTICAL
+ else:
+ orientation = gtk.ORIENTATION_HORIZONTAL
+ self.set_orientation(orientation)
+ if self.__settingsManager.get_audiobook_path() != self.controller.get_books_path():
+ self.controller.reload(self.__settingsManager.get_audiobook_path())
+
+ return True
+
+ @gtk_toolbox.log_exception(_moduleLogger)
+ def update_seek(self):
+ #print self.controller.get_percentage()
+ if self.controller.is_playing():
+ gtk.gdk.threads_enter()
+ self.seek.set_value(self.controller.get_percentage() * 100)
+ gtk.gdk.threads_leave()
+ #self.controller.get_percentage()
+ return True # run again
+
+ @gtk_toolbox.log_exception(_moduleLogger)
+ def sleep(self):
+ _moduleLogger.info("sleep time timeout")
+ hildonize.show_information_banner(self.win, "Sleep timer")
+ self.controller.stop()
+ self.set_button_text("Resume", "Resume playing the audiobook")
+ return False # do not repeat
+
+ @gtk_toolbox.log_exception(_moduleLogger)
+ def get_help(self, button):
+ Browser.open("file:///opt/Nqa-Audiobook-player/Help/nqaap.html")
+
+ @gtk_toolbox.log_exception(_moduleLogger)
+ def seek_changed(self, seek, scroll , value):
+ # print "sok", scroll
+ self.controller.seek_percent(seek.get_value() / 100.0)
+
+ @gtk_toolbox.log_exception(_moduleLogger)
+ def _on_next_chapter(self, *args):
+ self.controller.next_chapter()
+
+ @gtk_toolbox.log_exception(_moduleLogger)
+ def _on_previous_chapter(self, *args):
+ self.controller.previous_chapter()
+
+ @gtk_toolbox.log_exception(_moduleLogger)
+ def play_pressed(self, button):
+ if self.controller.is_playing():
+ self.pause()
+ else:
+ self.play()
+
+ @gtk_toolbox.log_exception(_moduleLogger)
+ def on_key_press(self, widget, event, *args):
+ RETURN_TYPES = (gtk.keysyms.Return, gtk.keysyms.ISO_Enter, gtk.keysyms.KP_Enter)
+ isCtrl = bool(event.get_state() & gtk.gdk.CONTROL_MASK)
+ if (
+ event.keyval == gtk.keysyms.F6 or
+ event.keyval in RETURN_TYPES and isCtrl
+ ):
+ # The "Full screen" hardware key has been pressed
+ if self.__window_in_fullscreen:
+ self.win.unfullscreen ()
+ else:
+ self.win.fullscreen ()
+ return True
+ elif event.keyval == gtk.keysyms.o and isCtrl:
+ self._toggle_rotate()
+ return True
+ elif (
+ event.keyval in (gtk.keysyms.w, gtk.keysyms.q) and
+ event.get_state() & gtk.gdk.CONTROL_MASK
+ ):
+ self.quit()
+ elif event.keyval == gtk.keysyms.l and event.get_state() & gtk.gdk.CONTROL_MASK:
+ with open(constants._user_logpath_, "r") as f:
+ logLines = f.xreadlines()
+ log = "".join(logLines)
+ self._clipboard.set_text(str(log))
+ return True
+ elif event.keyval in RETURN_TYPES:
+ if self.controller.is_playing():
+ self.pause()
+ else:
+ self.play()
+ return True
+ elif event.keyval == gtk.keysyms.Left:
+ self.controller.previous_chapter()
+ return True
+ elif event.keyval == gtk.keysyms.Right:
+ self.controller.next_chapter()
+ return True
+
+ @gtk_toolbox.log_exception(_moduleLogger)
+ def _on_window_state_change(self, widget, event, *args):
+ if event.new_window_state & gtk.gdk.WINDOW_STATE_FULLSCREEN:
+ self.__window_in_fullscreen = True
+ else:
+ self.__window_in_fullscreen = False
+
+ @gtk_toolbox.log_exception(_moduleLogger)
+ def quit(self, *args): # what are the arguments?
+ _moduleLogger.info("Shutting down")
+ try:
+ self.save_settings()
+ self.controller.stop() # to save the state
+ finally:
+ gtk.main_quit()
+
+ @gtk_toolbox.log_exception(_moduleLogger)
+ def _on_about_activate(self, *args):
+ dlg = gtk.AboutDialog()
+ dlg.set_name(constants.__pretty_app_name__)
+ dlg.set_version("%s-%d" % (constants.__version__, constants.__build__))
+ dlg.set_copyright("Copyright 2010")
+ dlg.set_comments("")
+ dlg.set_website("http://nqaap.garage.maemo.org/")
+ dlg.set_authors(["Pengman <pengmeister@gmail.com>", "Ed Page <eopage@byu.net>"])
+ dlg.run()
+ dlg.destroy()
+
+ # Actions:
+
+ def play(self):
+ self.set_button_text("Stop", "Stop playing the audiobook")
+ self.controller.play()
+
+ def pause(self):
+ self.set_button_text("Resume", "Resume playing the audiobook")
+ self.controller.stop()
+
+ def set_orientation(self, orientation):
+ if orientation == gtk.ORIENTATION_VERTICAL:
+ if self.__isPortrait:
+ return
+ hildonize.window_to_portrait(self.win)
+ self.__isPortrait = True
+
+ self._viewLayout.remove(self._controlLayout)
+ self._mainLayout.add(self._controlLayout)
+ elif orientation == gtk.ORIENTATION_HORIZONTAL:
+ if not self.__isPortrait:
+ return
+ hildonize.window_to_landscape(self.win)
+ self.__isPortrait = False
+
+ self._mainLayout.remove(self._controlLayout)
+ self._viewLayout.add(self._controlLayout)
+ else:
+ raise NotImplementedError(orientation)
+
+ def get_orientation(self):
+ return gtk.ORIENTATION_VERTICAL if self.__isPortrait else gtk.ORIENTATION_HORIZONTAL
+
+ def _toggle_rotate(self):
+ if self.__isPortrait:
+ self.set_orientation(gtk.ORIENTATION_HORIZONTAL)
+ else:
+ self.set_orientation(gtk.ORIENTATION_VERTICAL)
+
+ def change_chapter(self, chapterName):
+ if chapterName is None:
+ _moduleLogger.debug("chapter selection canceled.")
+ return True # this should end the function and indicate it has been handled
+
+ _moduleLogger.debug("chapter changed (by controller) to: %s" % chapterName)
+
+ def set_button_text(self, title, text):
+ if hildonize.IS_FREMANTLE_SUPPORTED:
+ self.button.set_text(title, text)
+ else:
+ self.button.set_label("%s" % (title, ))
+
+ def set_books(self, books):
+ _moduleLogger.debug("new books")
+ del self._bookSelection[:]
+ self._bookSelection.extend(books)
+ if len(books) == 0 and self.controller is not None:
+ hildonize.show_information_banner(self.win, "No audiobooks found. \nPlease place your audiobooks in the directory %s" % self.controller.get_books_path())
+
+ def set_book(self, bookPath, cover):
+ bookName = self.__format_name(bookPath)
+
+ self.set_button_text("Play", "Start playing the audiobook") # reset button
+ self._set_display_title(bookName)
+ if hildonize.IS_FREMANTLE_SUPPORTED:
+ self.book_button.set_text("Audiobook", bookName)
+ else:
+ self._audiobookMenuItem.get_child().set_text("Audiobook: %s" % (bookName, ))
+ if cover != "":
+ self.cover.set_from_file(cover)
+
+ def set_chapter(self, chapterIndex):
+ '''
+ Called from controller whenever a new chapter is started
+
+ chapter parameter is supposed to be the index for the chapter, not the name
+ '''
+ self.auto_chapter_selected = True
+ self._set_display_chapter(str(chapterIndex + 1))
+ if hildonize.IS_FREMANTLE_SUPPORTED:
+ self.chapter_button.set_text("Chapter", str(chapterIndex))
+ else:
+ self._chapterMenuItem.get_child().set_text("Chapter: %s" % (chapterIndex+1, ))
+
+ def set_chapters(self, chapters):
+ _moduleLogger.debug("setting chapters" )
+ del self._chapterSelection[:]
+ self._chapterSelection.extend(chapters)
+
+ def set_sleep_timer(self, mins):
+ pass
+
+ # Utils
+ def set_selected_value(self, button, value):
+ i = button.get_selector().get_model(0).index[value] # get index of value from list
+ button.set_active(i) # set active index to that index
+
+ def _set_display_title(self, title):
+ self.title.set_markup("<b><big>%s</big></b>" % title)
+
+ def _set_display_chapter(self, chapter):
+ self.chapter.set_markup("<b><big>Chapter %s</big></b>" % chapter)
def _old_timeout_add_seconds(timeout, callback):
- return gobject.timeout_add(timeout * 1000, callback)
+ return gobject.timeout_add(timeout * 1000, callback)
def _timeout_add_seconds(timeout, callback):
- return gobject.timeout_add_seconds(timeout, callback)
+ return gobject.timeout_add_seconds(timeout, callback)
try:
- gobject.timeout_add_seconds
- timeout_add_seconds = _timeout_add_seconds
+ gobject.timeout_add_seconds
+ timeout_add_seconds = _timeout_add_seconds
except AttributeError:
- timeout_add_seconds = _old_timeout_add_seconds
+ timeout_add_seconds = _old_timeout_add_seconds
if __name__ == "__main__":
- g = Gui(None)
+ g = Gui(None)
class Player(object):
- def __init__(self, ui):
- self.storage = FileStorage.FileStorage(path = constants._data_path_)
- if hildonize.IS_HILDON_SUPPORTED and not hildonize.IS_FREMANTLE_SUPPORTED:
- import SimpleOSSOPlayer as _SimplePlayer
- SimplePlayer = _SimplePlayer # silence PyFlakes
- else:
- import SimpleGStreamer as SimplePlayer
- self.player = SimplePlayer.SimplePlayer(self.next_chapter)
- self.ui = ui
- self.audiobook = None
- self._bookDir = None
- self._bookPaths = {}
-
- def get_books_path(self):
- return self._bookDir
-
- def reload(self, booksPath):
- if self.audiobook is not None:
- position = self.player.elapsed()
- self.storage.set_time(self.audiobook.current_chapter, position)
- self.save()
- self.load(booksPath)
-
- def load(self, booksPath):
- _moduleLogger.info("Loading books from %s" % booksPath)
- self.storage.load()
- self._bookDir = booksPath
-
- self._bookPaths = dict(
- (self.__format_name(bookPath), bookPath)
- for bookPath in self._find_books()
- )
- if self.ui is not None:
- bookPaths = self._bookPaths.values()
- bookPaths.sort()
- self.ui.set_books(bookPaths)
-
- lastBookName = self.storage.get_selected()
- if lastBookName is not None:
- _moduleLogger.info("continuing book: %s" % lastBookName)
- try:
- bookPath = self._bookPaths[lastBookName]
- self.set_book(bookPath)
- except KeyError:
- _moduleLogger.exception("Audiobook was not found")
- except IndexError:
- _moduleLogger.exception("Chapter was not found")
- except IOError:
- _moduleLogger.exception("Audiobook could not be loaded")
- except Exception:
- _moduleLogger.exception("Can you say 'confusion'?")
-
- def save(self):
- position = self.player.elapsed()
- self.storage.set_time(self.audiobook.current_chapter, position)
- self.storage.save()
-
- @staticmethod
- def __format_name(path):
- if os.path.isfile(path):
- return os.path.basename(path).rsplit(".", 1)[0]
- else:
- return os.path.basename(path)
-
- def set_book(self, bookPath):
- oldBookName = self.storage.get_selected()
- try:
- bookName = self.__format_name(bookPath)
- self.storage.select_book(bookName)
- chapter_num, _ = self.storage.get_time()
- self.audiobook = Audiobook.Audiobook(
- bookPath,
- chapter_num
- )
- except:
- self.storage.select_book(oldBookName)
- raise
-
- # self.player.set_file(self.audiobook.get_current_chapter())
- # self.player.seek_time(time)
-
- if self.ui is not None:
- self.ui.set_book(bookPath, self.audiobook.get_cover_img())
- self.ui.set_chapters(self.audiobook.chapters)
-
- chapter_title = self.audiobook.chapters[self.audiobook.current_chapter]
- self.set_chapter(chapter_title, True)
-
- def set_chapter(self, chapter, continuing = False):
- _moduleLogger.info("set chapter:" + chapter + " : Continuing: " + str(continuing))
- self.audiobook.set_chapter(chapter)
- self.player.set_file(self.audiobook.get_current_chapter())
- if not continuing:
- self.storage.set_time(self.audiobook.current_chapter, 0)
-
- if self.ui is not None:
- self.ui.set_chapter(self.audiobook.current_chapter)
-
- def previous_chapter(self, *args):
- _moduleLogger.info("Going back a chapter")
- self.player.stop()
- next_file = self.audiobook.get_previous_chapter()
- if next_file is not False:
- self.set_chapter(next_file)
- self.player.play()
- else: # the book is over
- self.storage.set_time(0, 0)
-
- def next_chapter(self, *args):
- _moduleLogger.info("Advancing a chapter")
- self.player.stop()
- next_file = self.audiobook.get_next_chapter()
- if next_file is not False:
- self.set_chapter(next_file)
- self.player.play()
- else: # the book is over
- self.storage.set_time(0, 0)
-
- def play(self):
- if self.audiobook is not None:
- self.player.play()
- _, target_time = self.storage.get_time()
- if 0 < target_time:
- time.sleep(1)
- self.player.seek_time(target_time)
- #print self.player.elapsed()
- else:
- print "No book selected, find one in ", self._bookDir
-
- def stop(self):
- position = self.player.elapsed()
- self.player.stop()
-
- if self.audiobook is not None:
- self.storage.set_time(self.audiobook.current_chapter, position)
-
- def is_playing(self):
- return self.player.playing
-
- def sleeptimer(self, secs):
- #print "sleeper", secs
- time.sleep(secs)
- #print "now its time to sleep"
- self.stop()
-
- def start_sleeptimer(self, secs):
- #print "startin sleep"
- sleep_thread = threading.Thread(target=self.sleeptimer, args=(secs, ))
- sleep_thread.start()
- #print "started sleep"
-
- def get_percentage(self):
- try:
- return float(self.player.elapsed()) / float(self.player.duration())
- except ZeroDivisionError:
- return 0.0
-
- def seek_percent(self, ratio):
- try:
- target = int(self.player.duration() * ratio) # Calculate where to seek
- self.player.seek_time(target) # seek
-
- position = self.player.elapsed()
- self.storage.set_time(self.audiobook.current_chapter, target) # save position
- return True
- except:
- _moduleLogger.exception("Seek failed")
- return False
-
- def _find_books(self):
- try:
- paths = (
- os.path.join(self._bookDir, f)
- for f in os.listdir(self._bookDir)
- )
- return (
- path
- for path in paths
- if Audiobook.is_book(path)
- )
- except OSError:
- return ()
+ def __init__(self, ui):
+ self.storage = FileStorage.FileStorage(path = constants._data_path_)
+ if hildonize.IS_HILDON_SUPPORTED and not hildonize.IS_FREMANTLE_SUPPORTED:
+ import SimpleOSSOPlayer as _SimplePlayer
+ SimplePlayer = _SimplePlayer # silence PyFlakes
+ else:
+ import SimpleGStreamer as SimplePlayer
+ self.player = SimplePlayer.SimplePlayer(self.next_chapter)
+ self.ui = ui
+ self.audiobook = None
+ self._bookDir = None
+ self._bookPaths = {}
+
+ def get_books_path(self):
+ return self._bookDir
+
+ def reload(self, booksPath):
+ if self.audiobook is not None:
+ position = self.player.elapsed()
+ self.storage.set_time(self.audiobook.current_chapter, position)
+ self.save()
+ self.load(booksPath)
+
+ def load(self, booksPath):
+ _moduleLogger.info("Loading books from %s" % booksPath)
+ self.storage.load()
+ self._bookDir = booksPath
+
+ self._bookPaths = dict(
+ (self.__format_name(bookPath), bookPath)
+ for bookPath in self._find_books()
+ )
+ if self.ui is not None:
+ bookPaths = self._bookPaths.values()
+ bookPaths.sort()
+ self.ui.set_books(bookPaths)
+
+ lastBookName = self.storage.get_selected()
+ if lastBookName is not None:
+ _moduleLogger.info("continuing book: %s" % lastBookName)
+ try:
+ bookPath = self._bookPaths[lastBookName]
+ self.set_book(bookPath)
+ except KeyError:
+ _moduleLogger.exception("Audiobook was not found")
+ except IndexError:
+ _moduleLogger.exception("Chapter was not found")
+ except IOError:
+ _moduleLogger.exception("Audiobook could not be loaded")
+ except Exception:
+ _moduleLogger.exception("Can you say 'confusion'?")
+
+ def save(self):
+ position = self.player.elapsed()
+ if self.audiobook is not None:
+ self.storage.set_time(self.audiobook.current_chapter, position)
+ self.storage.save()
+
+ @staticmethod
+ def __format_name(path):
+ if os.path.isfile(path):
+ return os.path.basename(path).rsplit(".", 1)[0]
+ else:
+ return os.path.basename(path)
+
+ def set_book(self, bookPath):
+ oldBookName = self.storage.get_selected()
+ try:
+ bookName = self.__format_name(bookPath)
+ self.storage.select_book(bookName)
+ chapter_num, _ = self.storage.get_time()
+ self.audiobook = Audiobook.Audiobook(
+ bookPath,
+ chapter_num
+ )
+ except:
+ self.storage.select_book(oldBookName)
+ raise
+
+ # self.player.set_file(self.audiobook.get_current_chapter())
+ # self.player.seek_time(time)
+
+ if self.ui is not None:
+ self.ui.set_book(bookPath, self.audiobook.get_cover_img())
+ self.ui.set_chapters(self.audiobook.chapters)
+
+ chapter_title = self.audiobook.chapters[self.audiobook.current_chapter]
+ self.set_chapter(chapter_title, True)
+
+ def set_chapter(self, chapter, continuing = False):
+ _moduleLogger.info("set chapter:" + chapter + " : Continuing: " + str(continuing))
+ self.audiobook.set_chapter(chapter)
+ self.player.set_file(self.audiobook.get_current_chapter())
+ if not continuing:
+ self.storage.set_time(self.audiobook.current_chapter, 0)
+
+ if self.ui is not None:
+ self.ui.set_chapter(self.audiobook.current_chapter)
+
+ def previous_chapter(self, *args):
+ _moduleLogger.info("Going back a chapter")
+ self.player.stop()
+ next_file = self.audiobook.get_previous_chapter()
+ if next_file is not False:
+ self.set_chapter(next_file)
+ self.player.play()
+ else: # the book is over
+ self.storage.set_time(0, 0)
+
+ def next_chapter(self, *args):
+ _moduleLogger.info("Advancing a chapter")
+ self.player.stop()
+ next_file = self.audiobook.get_next_chapter()
+ if next_file is not False:
+ self.set_chapter(next_file)
+ self.player.play()
+ else: # the book is over
+ self.storage.set_time(0, 0)
+
+ def play(self):
+ if self.audiobook is not None:
+ self.player.play()
+ _, target_time = self.storage.get_time()
+ if 0 < target_time:
+ time.sleep(1)
+ self.player.seek_time(target_time)
+ #print self.player.elapsed()
+ else:
+ print "No book selected, find one in ", self._bookDir
+
+ def stop(self):
+ position = self.player.elapsed()
+ self.player.stop()
+
+ if self.audiobook is not None:
+ self.storage.set_time(self.audiobook.current_chapter, position)
+
+ def is_playing(self):
+ return self.player.playing
+
+ def sleeptimer(self, secs):
+ #print "sleeper", secs
+ time.sleep(secs)
+ #print "now its time to sleep"
+ self.stop()
+
+ def start_sleeptimer(self, secs):
+ #print "startin sleep"
+ sleep_thread = threading.Thread(target=self.sleeptimer, args=(secs, ))
+ sleep_thread.start()
+ #print "started sleep"
+
+ def get_percentage(self):
+ try:
+ return float(self.player.elapsed()) / float(self.player.duration())
+ except ZeroDivisionError:
+ return 0.0
+
+ def seek_percent(self, ratio):
+ try:
+ target = int(self.player.duration() * ratio) # Calculate where to seek
+ self.player.seek_time(target) # seek
+
+ position = self.player.elapsed()
+ self.storage.set_time(self.audiobook.current_chapter, target) # save position
+ return True
+ except:
+ _moduleLogger.exception("Seek failed")
+ return False
+
+ def _find_books(self):
+ try:
+ paths = (
+ os.path.join(self._bookDir, f)
+ for f in os.listdir(self._bookDir)
+ )
+ return (
+ path
+ for path in paths
+ if Audiobook.is_book(path)
+ )
+ except OSError:
+ return ()