4 import util.misc as misc_utils
5 from util import go_utils
9 _moduleLogger = logging.getLogger(__name__)
12 SOURCE_RADIO = "radio"
13 SOURCE_CONFERENCES = "conferences"
14 SOURCE_MAGAZINES = "magazines"
15 SOURCE_SCRIPTURES = "scriptures"
18 class Connection(object):
21 self._backend = backend.Backend()
22 self._indexing = go_utils.AsyncPool()
25 self._indexing.start()
30 def download(self, func, on_success, on_error, args = None, kwds = None):
36 self._indexing.clear_tasks()
37 self._indexing.add_task(
38 getattr(self._backend, func),
46 class AudioIndex(object):
49 self._connection = Connection()
50 self._languages = None
51 self._languagesRequest = None
55 self._connection.start()
58 self._connection.stop()
60 def get_languages(self, on_success, on_error):
61 if self._languages is None:
62 assert self._languagesRequest is None
63 self._languagesRequest = on_success, on_error
64 self._connection.download(
66 self._on_get_languages,
67 self._on_languages_error
70 on_success(self._languages)
72 def get_source(self, source, langId = None):
73 key = (source, langId)
74 if key in self._sources:
75 node = self._sources[key]
77 if source == SOURCE_RADIO:
78 node = RadioNode(self._connection)
79 elif source == SOURCE_CONFERENCES:
80 assert langId is not None
81 node = ConferencesNode(self._connection, langId)
83 raise NotImplementedError(source)
84 self._sources[key] = node
88 @misc_utils.log_exception(_moduleLogger)
89 def _on_get_languages(self, languages):
90 assert self._languages is None
91 assert self._languagesRequest is not None
92 r = self._languagesRequest
93 self._languagesRequest = None
94 self._languages = languages
97 @misc_utils.log_exception(_moduleLogger)
98 def _on_languages_error(self, e):
99 assert self._languages is None
100 assert self._languagesRequest is not None
101 r = self._languagesRequest
102 self._languagesRequest = None
103 r[1](self._languages)
108 def __init__(self, connection, parent, data, id):
109 self._connection = connection
110 self._parent = weakref.ref(parent) if parent is not None else None
112 self._children = None
115 def get_children(self, on_success, on_error):
116 if self._children is None:
117 self._get_children(on_success, on_error)
119 on_success(self._children)
121 def get_parent(self):
122 if self._parent is None:
123 raise RuntimeError("")
124 parent = self._parent()
127 def get_properties(self):
132 raise NotImplementedError("On %s" % type(self))
139 raise NotImplementedError("")
141 def _get_children(self, on_success, on_error):
142 raise NotImplementedError("")
145 class ParentNode(Node):
147 def __init__(self, connection, parent, data, id):
148 Node.__init__(self, connection, parent, data, id)
154 def _get_children(self, on_success, on_error):
155 assert self._request is None
156 assert self._children is None
157 self._request = on_success, on_error
159 func, args, kwds = self._get_func()
161 self._connection.download(
170 raise NotImplementedError()
172 def _create_child(self, data, id):
173 raise NotImplementedError()
175 @misc_utils.log_exception(_moduleLogger)
176 def _on_success(self, data):
181 self._create_child(child, i)
182 for i, child in enumerate(data)
185 _moduleLogger.exception("Translating error")
186 self._children = None
191 @misc_utils.log_exception(_moduleLogger)
192 def _on_error(self, error):
198 class LeafNode(Node):
200 def __init__(self, connection, parent, data, id):
201 Node.__init__(self, connection, parent, data, id)
207 def can_navigate(self):
208 raise NotImplementedError("On %s" % type(self))
212 raise NotImplementedError("On %s" % type(self))
216 raise NotImplementedError("On %s" % type(self))
218 def _get_children(self, on_success, on_error):
219 raise RuntimeError("Not is a leaf")
222 class RadioNode(ParentNode):
224 def __init__(self, connection):
225 ParentNode.__init__(self, connection, None, {}, SOURCE_RADIO)
232 return "get_radio_channels", (), {}
234 def _create_child(self, data, id):
235 return RadioChannelNode(self._connection, self, data, id)
238 class RadioChannelNode(LeafNode):
240 def __init__(self, connection, parent, data, id):
241 LeafNode.__init__(self, connection, parent, data, id)
242 self._extendedData = {}
246 def can_navigate(self):
259 return self._data["url"]
261 def get_programming(self, date, on_success, on_error):
262 date = date.strftime("%Y-%m-%d")
264 programming = self._extendedData[date]
266 self._get_programming(date, on_success, on_error)
268 on_success(programming)
270 def _get_programming(self, date, on_success, on_error):
271 assert self._request is None
272 assert date not in self._extendedData
273 self._request = on_success, on_error, date
275 self._connection.download(
276 "get_radio_channel_programming",
279 (self._data["id"], date),
283 @misc_utils.log_exception(_moduleLogger)
284 def _on_success(self, data):
289 self._extendedData[date] = [
294 _moduleLogger.exception("Translating error")
295 del self._extendedData[date]
298 r[0](self._extendedData[date])
300 @misc_utils.log_exception(_moduleLogger)
301 def _on_error(self, error):
307 class ConferencesNode(ParentNode):
309 def __init__(self, connection, langId):
310 ParentNode.__init__(self, connection, None, {}, SOURCE_CONFERENCES)
311 self._langId = langId
318 return "get_conferences", (self._langId, ), {}
320 def _create_child(self, data, id):
321 return ConferenceNode(self._connection, self, data, id)
324 class ConferenceNode(ParentNode):
326 def __init__(self, connection, parent, data, id):
327 ParentNode.__init__(self, connection, parent, data, id)
331 return self._data["title"]
334 return "get_conference_sessions", (self._data["id"], ), {}
336 def _create_child(self, data, id):
337 return SessionNode(self._connection, self, data, id)
340 class SessionNode(ParentNode):
342 def __init__(self, connection, parent, data, id):
343 ParentNode.__init__(self, connection, parent, data, id)
347 return self._data["title"]
350 return "get_conference_talks", (self._data["id"], ), {}
352 def _create_child(self, data, id):
353 return TalkNode(self._connection, self, data, id)
356 class TalkNode(LeafNode):
358 def __init__(self, connection, parent, data, id):
359 LeafNode.__init__(self, connection, parent, data, id)
362 def can_navigate(self):
367 return self._data["title"]
371 return self._data["speaker"]
375 return self._data["url"]
378 def walk_ancestors(node):
382 node = node.get_parent()
387 def common_paths(targetNode, currentNode):
388 targetNodePath = list(walk_ancestors(targetNode))
389 targetNodePath.reverse()
390 currentNodePath = list(walk_ancestors(currentNode))
391 currentNodePath.reverse()
396 for i, (t, c) in enumerate(zip(targetNodePath, currentNodePath)):
398 return ancestors, None, descendants
403 for child in targetNodePath[i+1:]
406 return ancestors, currentNode, descendants