@todo Restructure so there is a windows/ folder with a file per source
@todo Add additional sources
@todo Track recent
-@todo Sequential playback
+@todo Presenter browsing when not active
@todo Audio seek bar
@todo Persisted Pause
@todo Favorites
import util.misc as misc_utils
import stream
+import stream_index
import call_monitor
gobject.GObject.__init__(self)
self._index = index
self._node = None
+ self._nextSearch = None
self._calls = call_monitor.CallMonitor()
self._calls.connect("call_start", self._on_call_start)
self._stream.connect("error", self._on_stream_error)
def set_piece_by_node(self, node):
- assert node is None or node.is_leaf(), node
- if self._node is node:
- return
- self._node = node
- if self._node is not None:
- self._stream.set_file(self._node.uri)
- _moduleLogger.info("New node %r" % self._node)
- self.emit("title_change", self._node)
+ self._set_piece_by_node(node)
@property
def node(self):
def back(self):
_moduleLogger.info("back")
+ assert self._nextSearch is None
+ self._nextSearch = stream_index.AsyncWalker(stream_index.get_previous)
+ self._nextSearch.start(self.node, self._on_next_node, self._on_node_search_error)
def next(self):
_moduleLogger.info("next")
+ assert self._nextSearch is None
+ self._nextSearch = stream_index.AsyncWalker(stream_index.get_next)
+ self._nextSearch.start(self.node, self._on_next_node, self._on_node_search_error)
+
+ def _set_piece_by_node(self, node):
+ assert node is None or node.is_leaf(), node
+ if self._node is node:
+ _moduleLogger.info("Already set to %r" % node)
+ return
+ self._node = node
+ if self._node is not None:
+ self._stream.set_file(self._node.uri)
+ _moduleLogger.info("New node %r" % self._node)
+ self.emit("title_change", self._node)
+
+ @misc_utils.log_exception(_moduleLogger)
+ def _on_next_node(self, node):
+ self._nextSearch = None
+
+ restart = self.state == self.STATE_PLAY
+ self._set_piece_by_node(node)
+ if restart:
+ self.play()
+
+ @misc_utils.log_exception(_moduleLogger)
+ def _on_node_search_error(self, e):
+ self._nextSearch = None
+ self.emit("error", e, "")
@misc_utils.log_exception(_moduleLogger)
def _on_stream_state(self, s, state):
)
return ancestors, currentNode, descendants
+
+
+class AsyncWalker(object):
+
+ def __init__(self, func):
+ self._func = func
+ self._run = None
+
+ def start(self, *args, **kwds):
+ assert self._run is None
+ self._run = self._func(*args, **kwds)
+ node = self._run.send(None) # priming the function
+ node.get_children(self.on_success, self.on_error)
+
+ @misc_utils.log_exception(_moduleLogger)
+ def on_success(self, children):
+ _moduleLogger.debug("Processing success for: %r", self._func)
+ try:
+ node = self._run.send(children)
+ except StopIteration, e:
+ pass
+ else:
+ node.get_children(self.on_success, self.on_error)
+
+ @misc_utils.log_exception(_moduleLogger)
+ def on_error(self, error):
+ _moduleLogger.debug("Processing error for: %r", self._func)
+ try:
+ node = self._run.throw(error)
+ except StopIteration, e:
+ pass
+ else:
+ node.get_children(self.on_success, self.on_error)
+
+
+def get_next(node, on_success, on_error):
+ try:
+ assert node.is_leaf(), node
+
+ # Find next branch
+ childNode = node
+ while True:
+ parent = childNode.get_parent()
+ siblings = yield parent
+ for i, sibling in enumerate(siblings):
+ if sibling is childNode:
+ break
+ i += 1
+ if i < len(siblings):
+ sibling = siblings[i]
+ break
+ else:
+ childNode = parent
+
+ # dig into that branch to find the first leaf
+ nodes = [sibling]
+ while nodes:
+ child = nodes.pop(0)
+ if child.is_leaf():
+ on_success(child)
+ return
+ children = yield child
+ nodes[0:0] = children
+ raise RuntimeError("Ran out of nodes when hunting for first leaf of %s" % node)
+ except Exception, e:
+ on_error(e)
+
+
+def get_previous(node, on_success, on_error):
+ try:
+ assert node.is_leaf(), node
+
+ # Find next branch
+ childNode = node
+ while True:
+ parent = childNode.get_parent()
+ siblings = yield parent
+ for i, sibling in enumerate(siblings):
+ if sibling is childNode:
+ break
+ i -= 1
+ if 0 <= i:
+ sibling = siblings[i]
+ break
+ else:
+ childNode = parent
+
+ # dig into that branch to find the first leaf
+ nodes = [sibling]
+ while nodes:
+ child = nodes.pop(-1)
+ if child.is_leaf():
+ on_success(child)
+ return
+ children = yield child
+ nodes[0:0] = children
+ raise RuntimeError("Ran out of nodes when hunting for first leaf of %s" % node)
+ except Exception, e:
+ on_error(e)