Bump to 0.8.12
[nqaap] / src / Player.py
1 import os
2 import threading
3 import time
4 import logging
5
6 import constants
7 import hildonize
8 import Audiobook
9 import FileStorage
10
11
12 _moduleLogger = logging.getLogger(__name__)
13
14
15 class Player(object):
16
17         def __init__(self, ui):
18                 self.storage = FileStorage.FileStorage(path = constants._data_path_)
19                 if hildonize.IS_HILDON_SUPPORTED and not hildonize.IS_FREMANTLE_SUPPORTED:
20                         import SimpleOSSOPlayer as _SimplePlayer
21                         SimplePlayer = _SimplePlayer # silence PyFlakes
22                 else:
23                         import SimpleGStreamer as SimplePlayer
24                 self.player = SimplePlayer.SimplePlayer(self.next_chapter)
25                 self.ui = ui
26                 self.audiobook = None
27                 self._bookDir = None
28                 self._bookPaths = {}
29
30         def get_books_path(self):
31                 return self._bookDir
32
33         def reload(self, booksPath):
34                 if self.audiobook is not None:
35                         position = self.player.elapsed()
36                         self.storage.set_time(self.audiobook.current_chapter, position)
37                 self.save()
38                 self.load(booksPath)
39
40         def load(self, booksPath):
41                 _moduleLogger.info("Loading books from %s" % booksPath)
42                 self.storage.load()
43                 self._bookDir = booksPath
44
45                 self._bookPaths = dict(
46                         (self.__format_name(bookPath), bookPath)
47                         for bookPath in self._find_books()
48                 )
49                 if self.ui is not None:
50                         bookPaths = self._bookPaths.values()
51                         bookPaths.sort()
52                         self.ui.set_books(bookPaths)
53
54                 lastBookName = self.storage.get_selected()
55                 if lastBookName is not None:
56                         _moduleLogger.info("continuing book: %s" % lastBookName)
57                         try:
58                                 bookPath = self._bookPaths[lastBookName]
59                                 self.set_book(bookPath)
60                         except KeyError:
61                                 _moduleLogger.exception("Audiobook was not found")
62                         except IndexError:
63                                 _moduleLogger.exception("Chapter was not found")
64                         except IOError:
65                                 _moduleLogger.exception("Audiobook could not be loaded")
66                         except Exception:
67                                 _moduleLogger.exception("Can you say 'confusion'?")
68
69         def save(self):
70                 position = self.player.elapsed()
71                 if self.audiobook is not None:
72                         self.storage.set_time(self.audiobook.current_chapter, position)
73                 self.storage.save()
74
75         @staticmethod
76         def __format_name(path):
77                 name = os.path.basename(path).decode("utf-8")
78                 if os.path.isfile(path):
79                         # remove the extension
80                         name.rsplit(".", 1)[0]
81                 return name
82
83         def set_book(self, bookPath):
84                 oldBookName = self.storage.get_selected()
85                 try:
86                         bookName = self.__format_name(bookPath)
87                         self.storage.select_book(bookName)
88                         chapter_num, _ = self.storage.get_time()
89                         self.audiobook = Audiobook.Audiobook(
90                                 bookPath,
91                                 chapter_num
92                         )
93                 except:
94                         self.storage.select_book(oldBookName)
95                         raise
96
97                 # self.player.set_file(self.audiobook.get_current_chapter())
98                 # self.player.seek_time(time) 
99
100                 if self.ui is not None:
101                         self.ui.set_book(bookPath, self.audiobook.get_cover_img())
102                         self.ui.set_chapters(self.audiobook.chapters)
103
104                 chapter_title = self.audiobook.chapters[self.audiobook.current_chapter]
105                 self.set_chapter(chapter_title, True)
106
107         def set_chapter(self, chapter, continuing = False):
108                 _moduleLogger.info("set chapter:" + chapter + " : Continuing: " + str(continuing))
109                 self.audiobook.set_chapter(chapter)
110                 self.player.set_file(self.audiobook.get_current_chapter())
111                 if not continuing:
112                         self.storage.set_time(self.audiobook.current_chapter, 0)
113
114                 if self.ui is not None:
115                         self.ui.set_chapter(self.audiobook.current_chapter)
116
117         def previous_chapter(self, *args):
118                 _moduleLogger.info("Going back a chapter")
119                 self.player.stop()
120                 next_file = self.audiobook.get_previous_chapter()
121                 if next_file is not False:
122                         self.set_chapter(next_file)
123                         self.player.play()
124                 else:                                              # the book is over
125                         self.storage.set_time(0, 0)
126
127         def next_chapter(self, *args):
128                 _moduleLogger.info("Advancing a chapter")
129                 self.player.stop()
130                 next_file = self.audiobook.get_next_chapter()
131                 if next_file is not False:
132                         self.set_chapter(next_file)
133                         self.player.play()
134                 else:                                              # the book is over
135                         self.storage.set_time(0, 0)
136
137         def play(self):
138                 if self.audiobook is not None:
139                         self.player.play()
140                         _, target_time = self.storage.get_time()
141                         if 0 < target_time:
142                                 time.sleep(1)
143                                 self.player.seek_time(target_time)
144                 else:
145                         _moduleLogger.info("No book selected, find one in ", self._bookDir)
146
147         def stop(self):
148                 position = self.player.elapsed()
149                 self.player.stop()
150
151                 if self.audiobook is not None:
152                         self.storage.set_time(self.audiobook.current_chapter, position)
153
154         def is_playing(self):
155                 return self.player.playing
156
157         def sleeptimer(self, secs):
158                 time.sleep(secs)
159                 self.stop()
160
161         def start_sleeptimer(self, secs):
162                 sleep_thread = threading.Thread(target=self.sleeptimer, args=(secs, ))
163                 sleep_thread.start()
164
165         def get_percentage(self):
166                 try:
167                         return float(self.player.elapsed()) / float(self.player.duration())
168                 except ZeroDivisionError:
169                         return 0.0
170
171         def seek_percent(self, ratio):
172                 try:
173                         target = int(self.player.duration() * ratio) # Calculate where to seek
174                         self.player.seek_time(target)     # seek
175
176                         position = self.player.elapsed()
177                         self.storage.set_time(self.audiobook.current_chapter, target) # save position
178                         return True
179                 except:
180                         _moduleLogger.exception("Seek failed")
181                         return False
182
183         def _find_books(self):
184                 try:
185                         paths = (
186                                 os.path.join(self._bookDir, f)
187                                 for f in os.listdir(self._bookDir)
188                         )
189                         return (
190                                 path
191                                 for path in paths
192                                 if Audiobook.is_book(path)
193                         )
194                 except OSError:
195                         return ()