Moving files to new locations
[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                 if os.path.isfile(path):
78                         return os.path.basename(path).rsplit(".", 1)[0]
79                 else:
80                         return os.path.basename(path)
81
82         def set_book(self, bookPath):
83                 oldBookName = self.storage.get_selected()
84                 try:
85                         bookName = self.__format_name(bookPath)
86                         self.storage.select_book(bookName)
87                         chapter_num, _ = self.storage.get_time()
88                         self.audiobook = Audiobook.Audiobook(
89                                 bookPath,
90                                 chapter_num
91                         )
92                 except:
93                         self.storage.select_book(oldBookName)
94                         raise
95
96                 # self.player.set_file(self.audiobook.get_current_chapter())
97                 # self.player.seek_time(time) 
98
99                 if self.ui is not None:
100                         self.ui.set_book(bookPath, self.audiobook.get_cover_img())
101                         self.ui.set_chapters(self.audiobook.chapters)
102
103                 chapter_title = self.audiobook.chapters[self.audiobook.current_chapter]
104                 self.set_chapter(chapter_title, True)
105
106         def set_chapter(self, chapter, continuing = False):
107                 _moduleLogger.info("set chapter:" + chapter + " : Continuing: " + str(continuing))
108                 self.audiobook.set_chapter(chapter)
109                 self.player.set_file(self.audiobook.get_current_chapter())
110                 if not continuing:
111                         self.storage.set_time(self.audiobook.current_chapter, 0)
112
113                 if self.ui is not None:
114                         self.ui.set_chapter(self.audiobook.current_chapter)
115
116         def previous_chapter(self, *args):
117                 _moduleLogger.info("Going back a chapter")
118                 self.player.stop()
119                 next_file = self.audiobook.get_previous_chapter()
120                 if next_file is not False:
121                         self.set_chapter(next_file)
122                         self.player.play()
123                 else:                                              # the book is over
124                         self.storage.set_time(0, 0)
125
126         def next_chapter(self, *args):
127                 _moduleLogger.info("Advancing a chapter")
128                 self.player.stop()
129                 next_file = self.audiobook.get_next_chapter()
130                 if next_file is not False:
131                         self.set_chapter(next_file)
132                         self.player.play()
133                 else:                                              # the book is over
134                         self.storage.set_time(0, 0)
135
136         def play(self):
137                 if self.audiobook is not None:
138                         self.player.play()
139                         _, target_time = self.storage.get_time()
140                         if 0 < target_time:
141                                 time.sleep(1)
142                                 self.player.seek_time(target_time)
143                         #print self.player.elapsed()
144                 else:
145                         print "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                 #print "sleeper", secs
159                 time.sleep(secs)
160                 #print "now its time to sleep"
161                 self.stop()
162
163         def start_sleeptimer(self, secs):
164                 #print "startin sleep"
165                 sleep_thread = threading.Thread(target=self.sleeptimer, args=(secs, ))
166                 sleep_thread.start()
167                 #print "started sleep"
168
169         def get_percentage(self):
170                 try:
171                         return float(self.player.elapsed()) / float(self.player.duration())
172                 except ZeroDivisionError:
173                         return 0.0
174
175         def seek_percent(self, ratio):
176                 try:
177                         target = int(self.player.duration() * ratio) # Calculate where to seek
178                         self.player.seek_time(target)     # seek
179
180                         position = self.player.elapsed()
181                         self.storage.set_time(self.audiobook.current_chapter, target) # save position
182                         return True
183                 except:
184                         _moduleLogger.exception("Seek failed")
185                         return False
186
187         def _find_books(self):
188                 try:
189                         paths = (
190                                 os.path.join(self._bookDir, f)
191                                 for f in os.listdir(self._bookDir)
192                         )
193                         return (
194                                 path
195                                 for path in paths
196                                 if Audiobook.is_book(path)
197                         )
198                 except OSError:
199                         return ()