def _new_connection(self, client_sock): """ Callback when a new client connects. """ log.debug("New connection %s", client_sock) client_sock.buffer_size = self._socket.buffer_size client = Channel(sock=client_sock, auth_secret=self._auth_secret) for obj in self.objects: client.register(obj) client._send_auth_challenge() kaa.inprogress(client).connect(self.signals['client-connected'].emit)
def _new_connection(self, client_sock): """ Callback when a new client connects. """ log.debug("New connection %s", client_sock) client_sock.buffer_size = self._socket.buffer_size client = Channel(sock = client_sock, auth_secret = self._auth_secret) for obj in self.objects: client.register(obj) client._send_auth_challenge() kaa.inprogress(client).connect(self.signals['client-connected'].emit)
def _monitor(self, address, buffer_size, retry): while True: try: self.status = CONNECTING yield kaa.inprogress(self) # Python 2.4 code # TODO: remove all python 2.4 supporting code self._connect_inprogress.result self.status = CONNECTED # wait until the socket is closed yield self.signals.subset('closed').any() except Exception, e: # connection failed pass self._connect_inprogress = kaa.InProgress() self.status = DISCONNECTED # wait some time until we retry yield kaa.delay(retry) # reset variables self._authenticated = False self._pending_challenge = None self._read_buffer = [] self.status = CONNECTING self._socket = kaa.Socket(buffer_size) self._socket.chunk_size = 1024 self._socket.signals['read'].connect(self._handle_read) self._socket.signals['closed'].connect(self._handle_close) self._socket.connect(address).exception.connect(self._handle_refused)
def provide_image(self, path, **attributes): """ HTTP callback for images """ filename = '' path = urllib.unquote(path) if path.startswith('beacon'): filename = os.path.join(utils.imagedir, path[7:]) if path.startswith('cache'): filename = os.path.join(utils.cachedir, path[6:]) if path.startswith('thumbnail'): item = yield kaa.beacon.query(id=int(path.split('/')[2]), type=path.split('/')[1]) if len(item) != 1: log.error('beacon returned wrong results') yield None thumbnail = item[0].get('thumbnail') if thumbnail.needs_update or 1: yield kaa.inprogress(thumbnail.create(priority=kaa.beacon.Thumbnail.PRIORITY_HIGH)) filename = thumbnail.large if filename: if os.path.isfile(filename): yield open(filename).read(), None, None log.error('no file: %s' % filename) yield None else: yield None
def delete_item(self, item): """ Delete an item. Called by Item objects """ yield kaa.inprogress(self._db.read_lock) self._db.delete_object(item._beacon_id)
def _monitor(self, address, buffer_size, retry): while True: try: self.status = CONNECTING yield kaa.inprogress(self) # Python 2.4 code # TODO: remove all python 2.4 supporting code self._connect_inprogress.result self.status = CONNECTED # wait until the socket is closed yield self.signals.subset('closed').any() except Exception, e: # connection failed pass self._connect_inprogress = kaa.InProgress() self.status = DISCONNECTED # wait some time until we retry yield kaa.delay(retry) # reset variables self._authenticated = False self._pending_challenge = None self._read_buffer = [] self.status = CONNECTING self._socket = kaa.Socket(buffer_size) self._socket.chunk_size = 1024 self._socket.signals['read'].connect(self._handle_read) self._socket.signals['closed'].connect(self._handle_close) self._socket.connect(address).exception.connect( self._handle_refused)
def newfunc(*args, **kwargs): global _client global signals if not _client: _client = Client() signals = _client.signals if not _client.connected: try: # wait for next connect if _client.channel.status != kaa.rpc.CONNECTED: # this may raise an exception yield kaa.inprogress(_client.channel) if not _client.connected: yield kaa.inprogress(signals['connect']) log.info('beacon connected') except Exception, e: raise ConnectError(e)
def query(self, **query): """ Query the database. """ result = Query(self, **query) self._queries.append(weakref(result)) yield kaa.inprogress(result) yield result
def query(self, **kwargs): """ Query the database. """ query = Query(self, **kwargs) # _queries is a WeakValueDictionary, so query will be weakly referenced. self._queries[query.id] = query yield kaa.inprogress(query) yield query
def newfunc(*args, **kwargs): global _client global signals if not _client: _client = Client() signals = _client.signals if not _client.connected: try: # wait for next connect if _client.channel.status != kaa.rpc.CONNECTED: # this may raise an exception yield kaa.inprogress(_client.channel) if not _client.connected: yield kaa.inprogress(signals['connect']) log.info('beacon connected') for name, interface in plugins.load(_client).items(): globals()[name] = interface except Exception, e: raise ConnectError(e)
def newfunc(*args, **kwargs): global _client global signals if not _client: _client = Client() signals = _client.signals if not _client.connected: try: # wait for next connect if _client.channel.status != kaa.rpc.CONNECTED: # this may raise an exception yield kaa.inprogress(_client.channel) if not _client.connected: yield kaa.inprogress(signals["connect"]) log.info("beacon connected") for name, interface in plugins.load(_client).items(): globals()[name] = interface except Exception, e: raise ConnectError(e)
def get(self, filename): """ Return an object for the given filename. """ filename = os.path.realpath(filename) if not os.path.exists(filename): raise OSError('no such file or directory %s' % filename) q = Query(self, filename=filename) yield kaa.inprogress(q) yield q.get()
def _beacon_update_all(self): """ Timed callback to write all changes to the db. Called by Item objects """ yield kaa.inprogress(self._db.read_lock) changes = self._changed self._changed = [] for item in changes: self._db.update_object(item._beacon_id, item._beacon_changes) item._beacon_changes = {} # commit to update monitors self._db.commit()
def images(self, path, **attributes): if path in self.image_cache_hashes: image = self.image_cache_hashes[path] if isinstance(image, kaa.beacon.Thumbnail): if image.needs_update or 1: yield kaa.inprogress(image.create(priority=kaa.beacon.Thumbnail.PRIORITY_HIGH)) if attributes.get('size', '') == 'small': image = image.normal elif attributes.get('size', '') == 'normal': image = image.large else: image = image.name if image: yield open(image).read(), None, None
def __call__(self, widget, context): if self.condition: if not eval(self.condition, context): return kaa.InProgressAll() async = [] for animation in self.animations: if animation.behaviour == 'move': x1 = x2 = widget.x if animation.x1 is not None: x1 = animation.get_scaled('x1', 0, int) if animation.x2 is not None: x2 = animation.get_scaled('x2', 0, int) y1 = y2 = widget.y if animation.y1 is not None: y1 = animation.get_scaled('y1', 1, int) if animation.y2 is not None: y2 = animation.get_scaled('y2', 1, int) start = x1, y1 end = x2, y2 widget.x = x1 widget.y = y1 elif animation.behaviour in ('xrotation', 'yrotation', 'zrotation'): start = end = getattr(widget, animation.behaviour) if animation.start is not None: start = int(animation.start) setattr(widget, animation.behaviour, start) if animation.end is not None: end = int(animation.end) widget.rotation = start elif animation.behaviour == 'opacity': start = end = widget.opacity if animation.start is not None: start = int(animation.start) if animation.end is not None: end = int(animation.end) widget.opacity = start else: log.error('unsupported behaviour %s', animation.behaviour) continue a = widget.animate(float(animation.secs or 1), delay=float(animation.delay or 0)) a.behave(animation.behaviour, start, end) async.append(kaa.inprogress(a)) if self.process_children: for child in widget.children: eventhandler = child.eventhandler.get(self.event) if eventhandler is not None: async.extend([ x(child, context) for x in eventhandler]) return kaa.InProgressAll(*async)
def _call(self, cmd): self._busy = True log.debug('cmd %s', cmd) if self.dvbstreamer.stopping: log.info('waiting for dvbstreamer to be stopped') yield kaa.inprogress(self.dvbstreamer) if not self.dvbstreamer.running: # FIXME: this only works up to dvb9 but that should be enough log.info('starting dvbstreamer') self.dvbstreamer.start(['-a', self.config.adapter[-1]]) async = kaa.InProgress() if self._ready: self._ready = False self._callback = async self.dvbstreamer.write(cmd + '\n')
def images(self, path, **attributes): if path in self.image_cache_hashes: image = self.image_cache_hashes[path] if isinstance(image, kaa.beacon.Thumbnail): if image.needs_update or 1: yield kaa.inprogress( image.create( priority=kaa.beacon.Thumbnail.PRIORITY_HIGH)) if attributes.get('size', '') == 'small': image = image.normal elif attributes.get('size', '') == 'normal': image = image.large else: image = image.name if image: yield open(image).read(), None, None
def view(self, path, known=None, **attributes): result = self.application.get_json(self) result['type'] = self.application.name if str(result) != self.last_view[1]: self.last_view = self.last_view[0] + 1, str(result) while True: if not known or known != str(self.last_view[0]): result = self.application.get_json(self) result['type'] = self.application.name result['status'] = self.last_view[0] yield result # we need to wait for an update yield kaa.inprogress(self.signals['update']) result = self.application.get_json(self) result['type'] = self.application.name if str(result) != self.last_view[1]: self.last_view = self.last_view[0] + 1, str(result)
def __init__(self, mountpoint, query, *args, **kw): self._query = query self._filename_map = {} self._query_update_time = 0 query.signals["changed"].connect_weak(self._query_changed) query.monitor() if kaa.inprogress(query).finished: # Query is already finished, so explicitly call _query_changed() # now to update the filename map. self._query_changed() fuse.Fuse.__init__(self, *args, **kw) self.multithreaded = 1 # make it a real path because we will chdir to / self.mountpoint = os.path.realpath(mountpoint) self.parse(args=[self.mountpoint, "-f"])
def _create(self, sid, blocksize, stream): """ Create the FIFO and return the kaa.Socket and the IBBSocket object. """ # Make a kaa.Socket to kaa.Socket connection. One socket will be # given to the outside, the other one will be used to communicate # with the IBBSocket. filename = kaa.tempfile('ibb', unique=True) socket1 = kaa.net.tls.TLSSocket() wait = kaa.inprogress(socket1.signals['new-client']) socket2 = kaa.Socket() socket1.listen(filename) yield socket2.connect(filename) socket1 = yield wait socket1.sid = sid socket2.signals['closed'].connect(self._app_close, sid) yield socket1, IBBSocket(socket2, self.remote.iqset, sid, blocksize, stream)
def animate(self, secs, alpha='inc', delay=0, callback=None, unparent=False): """ Animate the object with the given animation. This returns an Animation object to add the behaviours. The animation is already started when this function returns. :param secs: number of seconds to run :param alpha: alpha function for this animation :param unparent: if set to True the widget will be unparented after the animation is finished. """ a = animation.Animation(secs, alpha, callback) a.apply(self) a.start(delay) if unparent: kaa.inprogress(a).connect(self.unparent).ignore_caller_args = True return a
def _start_backend(self): # spawn the backend process args = [ 'python', os.path.dirname(__file__) + '/backend/main.py', self.name, self.logfile ] self._candy_dirty = True self.server = subprocess.Popen(args, stdout=sys.stdout, stderr=sys.stderr) retry = 50 if os.path.exists(kaa.tempfile(self.name)): os.unlink(kaa.tempfile(self.name)) while True: try: self.ipc = kaa.rpc.connect(self.name) yield kaa.inprogress(self.ipc) break except Exception, e: retry -= 1 if retry == 0: raise e time.sleep(0.1)
def connect(self): start = time.time() while True: try: channel = kaa.rpc.connect('thumb/socket') channel.register(self) self.rpc = channel.rpc yield kaa.inprogress(channel) yield None except Exception, e: # FIXME: rather than this kludge, catch only the exceptions likely to happen # if connection to thumbnail server fails. if isinstance(e, GeneratorExit): raise if start + 3 < time.time(): # start time is up, something is wrong here raise RuntimeError('unable to connect to thumbnail server') yield kaa.delay(0.01)
def _beacon_start_query(self, query): """ Start the database query. """ if not self._client.connected: # wait until the client is connected # FIXME: maybe the server is not running yield kaa.inprogress(self._client.signals['connect']) if 'parent' in query and isinstance(query['parent'], Item) and \ not query['parent']._beacon_id: # The parent we want to use has no database id. This can happen for # new items while the scanning is still in progress. We need to # request the real database id and do the query when done. parent = query['parent'] log.info('force data for %s', parent) async = parent.scan() if isinstance(async, kaa.InProgress): # Not an InProgress object if it is not file. yield async
def connect(self): """ Connect to the thumbnail server """ start = time.time() while True: try: channel = kaa.rpc.connect('thumb/socket') channel.register(self) self.rpc = channel.rpc yield kaa.inprogress(channel) yield None except Exception, e: # FIXME: rather than this kludge, catch only the exceptions likely to happen # if connection to thumbnail server fails. if isinstance(e, GeneratorExit): raise if start + 3 < time.time(): # start time is up, something is wrong here raise RuntimeError('unable to connect to thumbnail server') yield kaa.delay(0.01)
def _device_add_to_database(self, metadata, devdict): """ Add the device to the database """ yield kaa.inprogress(self._db.read_lock) id = devdict.get('beacon.id') if devdict.get('volume.is_disc') == True and metadata and \ metadata.get('mime') in ('video/vcd', 'video/dvd'): # pass rom drive type = metadata['mime'][6:] log.info('detect %s as %s' % (devdict.get('beacon.id'), type)) mid = self._db.add_object("media", name=devdict.get('beacon.id'), content=type)['id'] vid = self._db.add_object("video", name="", parent=('media', mid), title=unicode(get_title(metadata['label'])), media = mid)['id'] for track in metadata.tracks: self._db.add_object('track_%s' % type, name='%02d' % track.trackno, parent=('video', vid), media=mid, chapters=track.chapters, length=track.length, audio=[ x.convert() for x in track.audio ], subtitles=[ x.convert() for x in track.subtitles ]) yield True if devdict.get('volume.disc.has_audio') and metadata: # Audio CD log.info('detect %s as audio cd' % devdict.get('beacon.id')) mid = self._db.add_object("media", name=devdict.get('beacon.id'), content='cdda')['id'] aid = self._db.add_object("audio", name='', title = metadata.get('title'), artist = metadata.get('artist'), parent=('media', mid), media = mid)['id'] for track in metadata.tracks: self._db.add_object('track_cdda', name=str(track.trackno), title=track.get('title'), artist=track.get('artist'), parent=('audio', aid), media=mid) yield True # filesystem log.info('detect %s as filesystem' % devdict.get('beacon.id')) mid = self._db.add_object("media", name=devdict.get('beacon.id'), content='file')['id'] mtime = 0 if devdict.get('block.device'): mtime = os.stat(devdict.get('block.device'))[stat.ST_MTIME] self._db.add_object("dir", name="", parent=('media', mid), media=mid, mtime=mtime) yield True
def play(self, item, resources): """ play an item """ if not self.status in (freevo.STATUS_IDLE, freevo.STATUS_STOPPED): # Already running, stop the current player by sending a STOP # event. The event will also get to the playlist behind the # current item and the whole list will be stopped. freevo.Event(freevo.STOP, handler=self.eventhandler).post() # Now connect to our own 'stop' signal once to repeat this current # function call without the player playing yield kaa.inprogress(self.signals['stop']) if not self.status in (freevo.STATUS_IDLE, freevo.STATUS_STOPPED): log.error('unable to stop current audio playback') yield False if not kaa.main.is_running(): # Freevo is in shutdown mode, do not start a new player, the old # only stopped because of the shutdown. yield False if (yield self.get_resources(*resources, force=True)) == False: log.error("Can't get resource %s", str(resources)) yield False # Store item and playlist. We need to keep the playlist object # here to make sure it is not deleted when player is running in # the background. self.item = item self.playlist = self.item.playlist if self.playlist: self.playlist.select(self.item) # Set the current item to the gui engine self.context.item = self.item.properties self.context.playlist = self.playlist self.item.elapsed_secs = 0 self.status = freevo.STATUS_RUNNING # update GUI yield kaa.NotFinished yield True
def _add_device_to_db(self, metadata, dev): """ Add the device to the database """ yield kaa.inprogress(self._db.read_lock) # FIXME: check if the device is still valid # FIXME: handle failed dvd detection id = dev.get('beacon.id') if dev.get('volume.is_disc') == True and metadata and \ metadata.get('mime') in ('video/vcd', 'video/dvd'): # pass rom drive type = metadata['mime'][6:] log.info('detect %s as %s' % (id, type)) mid = self._db.add_object("media", name=id, content=type)['id'] vid = self._db.add_object("video", name="", parent=('media', mid), title=unicode(get_title(metadata['label'])), media = mid)['id'] for track in metadata.tracks: self._db.add_object('track_%s' % type, name='%02d' % track.trackno, parent=('video', vid), media=mid, chapters=track.chapters, length=track.length, audio=[ x.convert() for x in track.audio ], subtitles=[ x.convert() for x in track.subtitles ]) return if dev.get('volume.disc.has_audio') and metadata: # Audio CD log.info('detect %s as audio cd' % id) mid = self._db.add_object("media", name=id, content='cdda')['id'] aid = self._db.add_object("audio", name='', title = metadata.get('title'), artist = metadata.get('artist'), parent=('media', mid), media = mid)['id'] for track in metadata.tracks: self._db.add_object('track_cdda', name=str(track.trackno), title=track.get('title'), artist=track.get('artist'), parent=('audio', aid), media=mid) return # filesystem log.info('detect %s as %s' % (id, dev.get('volume.fstype', '<unknown filesystem>'))) mid = self._db.add_object("media", name=id, content='file')['id'] mtime = 0 # FIXME: wrong for / if dev.get('block.device'): mtime = os.stat(dev.get('block.device'))[stat.ST_MTIME] self._db.add_object("dir", name="", parent=('media', mid), media=mid, mtime=mtime)
def foo(): pid = os.fork() if not pid: s = Server() kaa.main.run() print 'server down' sys.exit(0) print 1 for f in ('fast', 'subyield'): x = eval(f)() if isinstance(x, kaa.InProgress): # this should happen when calling subyield print f, 'needs more time' yield x # waiting... # subyield is now done x = x.result else: # this should happen for fast print f, 'was a yield function but did not stop' print x print 6 # just break here and return again in the next mainloop iteration yield kaa.NotFinished # call some async function with different types of # results (given as parameter) callback = kaa.InProgressCallable() async (callback, 7, 8) yield callback print callback.result # (7, 8) callback = kaa.InProgressCallable() async (callback) yield callback print callback.result # None callback = kaa.InProgressCallable() async (callback, 9) yield callback print callback.result # 9 callback = kaa.InProgressCallable() async (callback, foo=10) yield callback print callback.result # 10 callback = kaa.InProgressCallable() async (callback, foo=11, bar=12) yield callback print callback.result # {'foo': 11, 'bar': 12} x = thread(13) # this is also an InProgress object yield x print x.result # 13 x = thread('crash') try: # the thread raised an exception, so x() will # raise it here yield x print x.result print 'crash test failed' except: print 'crash test ok' print 14 print 'connect to server' c = kaa.rpc.connect('test') print 'server tests' yield kaa.inprogress(c) # normal rpc result = c.rpc('test1', 15) yield result print result.result # rpc in a thread result = c.rpc('test2', 16) yield result print result.result # rpc with yield direct result = c.rpc('test3', 17) yield result print result.result # rpc with yield indirect result = c.rpc('test4', 18) yield result print result.result # rpc with yield error result = c.rpc('crash') try: yield result result.result print 'bad rpc test failed' except: print 'bad rpc test ok' # rpc with remote exception result = c.rpc('test6', 18) try: yield result result.result print 'remote rpc exception test failed' except ValueError, e: print 'remote rpc exception test ok' print "========= A traceback (for rpc) is expected below:" print e
def acquire_read_lock(self): return kaa.inprogress(self.read_lock)
# 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA # # ----------------------------------------------------------------------- import config import kaa from tv.record_client import RecordClient def handler(result): if result: print _('Updated recording schedule') else: print _('Not updated recording schedule') raise SystemExit rc = RecordClient() try: kaa.inprogress(rc.channel).wait() except Exception, why: print 'Cannot connect to record server' raise SystemExit print _('Updating recording schedule') if not rc.updateFavoritesSchedule(handler): print rc.recordserverdown raise SystemExit kaa.main.run()
def remote(): g = kaa.epg.connect(('localhost', 10000)) yield kaa.inprogress(g.signals['connected'])
def _device_add_to_database(self, metadata, devdict): """ Add the device to the database """ yield kaa.inprogress(self._db.read_lock) id = devdict.get('beacon.id') if devdict.get('volume.is_disc') == True and metadata and \ metadata.get('mime') in ('video/vcd', 'video/dvd'): # pass rom drive type = metadata['mime'][6:] log.info('detect %s as %s' % (devdict.get('beacon.id'), type)) mid = self._db.add_object("media", name=devdict.get('beacon.id'), content=type)['id'] vid = self._db.add_object("video", name="", parent=('media', mid), title=unicode( get_title(metadata['label'])), media=mid)['id'] for track in metadata.tracks: self._db.add_object( 'track_%s' % type, name='%02d' % track.trackno, parent=('video', vid), media=mid, chapters=track.chapters, length=track.length, audio=[x.convert() for x in track.audio], subtitles=[x.convert() for x in track.subtitles]) yield True if devdict.get('volume.disc.has_audio') and metadata: # Audio CD log.info('detect %s as audio cd' % devdict.get('beacon.id')) mid = self._db.add_object("media", name=devdict.get('beacon.id'), content='cdda')['id'] aid = self._db.add_object("audio", name='', title=metadata.get('title'), artist=metadata.get('artist'), parent=('media', mid), media=mid)['id'] for track in metadata.tracks: self._db.add_object('track_cdda', name=str(track.trackno), title=track.get('title'), artist=track.get('artist'), parent=('audio', aid), media=mid) yield True # filesystem log.info('detect %s as filesystem' % devdict.get('beacon.id')) mid = self._db.add_object("media", name=devdict.get('beacon.id'), content='file')['id'] mtime = 0 if devdict.get('block.device'): mtime = os.stat(devdict.get('block.device'))[stat.ST_MTIME] self._db.add_object("dir", name="", parent=('media', mid), media=mid, mtime=mtime) yield True
try: yield result result.result print 'remote rpc exception test failed' except ValueError, e: print 'remote rpc exception test ok' print "========= A traceback (for rpc) is expected below:" print e # call rpc in thread x = thread2(c, 19) yield x # print 19 print x.result # 20 # Test InProgressCallable destruction cleans up signal connection. ip = kaa.inprogress(sig['one']) assert (len(sig['one']) == 1) del ip gc.collect() assert (len(sig['one']) == 0) print 'InProgressCallable cleanup ok' # Test InProgressAny via Signals.any() kaa.OneShotTimer(sig['three'].emit, 'worked').start(0.5) print 'Testing InProgressAny, should return in 0.5s' n, args = yield sig.subset('one', 'three').any() print 'InProgressAny returned:', n, args # Force InProgressCallables implicitly created by any() to be deleted. gc.collect() # Verify that they _are_ deleted and detached from the signal. print sig['one']._callbacks
def _parse(db, item, mtime): """ Parse the item, this can take a while. """ produced_load = 0 try: # # Parent checking # parent = item._beacon_parent if not parent._beacon_id: # There is a parent without id, update the parent now. r = parse(db, parent) if isinstance(r, kaa.InProgress): yield r if not parent._beacon_id: # This should never happen raise AttributeError('parent for %s has no dbid' % item) # we had no parent id which we have now. Restart the whole # parsing process. maye this item was in the db already r = parse(db, parent) if isinstance(r, kaa.InProgress): r = yield r yield r # # Metadata parsing # t1 = time.time() # FIXME: add force parameter from config file: # - always force (slow but best result) # - never force (faster but maybe wrong) # - only force on media 1 (good default) # Parse metadata in an extra named thread metadata = yield parse_thread(item.filename) if not metadata: metadata = {} attributes = { 'mtime': mtime, 'image': metadata.get('image') } if metadata.get('media') == kaa.metadata.MEDIA_DISC and \ metadata.get('subtype') in db.list_object_types(): type = metadata['subtype'] if metadata.get('type'): attributes['scheme'] = metadata.get('type').lower() item._beacon_isdir = False elif media_types.get(metadata.get('media')) in db.list_object_types(): type = media_types.get(metadata['media']) elif item._beacon_isdir: type = 'dir' else: type = 'file' if item._beacon_id and type != item._beacon_id[0]: # The item changed its type. Adjust the db yield kaa.inprogress(db.read_lock) data = db.update_object_type(item._beacon_id, type) if not data: log.error('item to change not in the db anymore') log.info('change item %s to %s' % (item._beacon_id, type)) item._beacon_database_update(data) # # Thumbnail / Cover / Image stuff. # produced_load = 1 if type == 'dir': attributes['image_from_items'] = False if not attributes.get('image'): for cover in ('cover.jpg', 'cover.png'): if os.path.isfile(item.filename + cover): attributes['image'] = item.filename + cover break # TODO: do some more stuff here: # Audio directories may have a different cover if there is only # one jpg in a dir of mp3 files or a files with 'front' in the name. # They need to be added here as special kind of cover elif type == 'image': attributes['image'] = item.filename if metadata.get('thumbnail'): t = thumbnail.Thumbnail(item.filename, item._beacon_media) if t.needs_update: # only store the normal version try: produced_load = 2 t.normal = kaa.imlib2.open_from_memory(metadata.get('thumbnail')) except (ValueError, IOError): log.exception('image thumbnail') else: base = os.path.splitext(item.filename)[0] if type == 'video' and not attributes.get('image') and thumbnail.SUPPORT_VIDEO: attributes['image'] = item.filename if metadata.get('thumbnail') and not attributes.get('image'): attributes['image'] = item.filename t = thumbnail.Thumbnail(item.filename, item._beacon_media) try: produced_load = 2 t.image = kaa.imlib2.open_from_memory(metadata['thumbnail']) except (ValueError, IOError): log.exception('raw thumbnail') for ext in ('.jpg', '.png'): if os.path.isfile(base + ext): attributes['image'] = base + ext break if os.path.isfile(item.filename + ext): attributes['image'] = item.filename + ext break # # Type specific attributes # if type == 'video': # Normally db.add_object() will take care of assigning type # attributes from metadata, but some attributes for videos # aren't at the top-level attribute object. For video # dimensions, take the dimensions of the first video track # (of the longest title, if applicable). video = None if metadata.get('video'): video = metadata.video[0] elif metadata.get('tracks'): # Find the longest title with a video track. for title in sorted(metadata.tracks, key=lambda t: -t.length): if title.get('video'): video = title.video[0] break if video: attributes['width'] = video.get('width') attributes['height'] = video.get('height') attributes['series'] = metadata.series attributes['season'] = metadata.season attributes['episode'] = metadata.episode attributes['metadata'] = metadata # now call extention plugins ext = os.path.splitext(item.filename)[1] for function in extention_plugins.get(ext, []) + extention_plugins.get(None, []): function(item, attributes, type) yield kaa.inprogress(db.read_lock) if attributes.get('image'): # create thumbnail t = thumbnail.Thumbnail(attributes.get('image'), item._beacon_media) if t.needs_update and (not type == 'video' or not hasattr(item, 'filename') or utils.do_thumbnail(item.filename)): t.create(t.PRIORITY_LOW) # # Database code # # add kaa.metadata results, the db module will add everything known # to the db. After that add or update the database. # if item._beacon_id: # Update old db entry db.update_object(item._beacon_id, **attributes) item._beacon_data.update(attributes) else: # Create new entry obj = db.add_object(type, name=item._beacon_data['name'], parent=parent, overlay=item._beacon_overlay, **attributes) item._beacon_database_update(obj) # # Additional track handling # if hasattr(metadata, 'tracks'): # The item has tracks, e.g. a dvd image on hd. if not metadata.get('type'): log.error('%s metadata has no type', item) yield produced_load # delete all known tracks before adding new result = yield db.query(parent=item) for track in result: db.delete_object(track) if not 'track_%s' % metadata.get('type').lower() in \ db.list_object_types(): key = metadata.get('type').lower() log.error('track_%s not in database keys', key) yield produced_load type = 'track_%s' % metadata.get('type').lower() for track in metadata.tracks: db.add_object(type, name=str(track.trackno), parent=item, metadata=track) # parsing done log.info('scan %s (%0.3f)' % (item, time.time() - t1)) except GeneratorExit: # Don't catch this, otherwise if the coroutine is aborted you get # "_parse() ignored GeneratorExit" raise except Exception, e: log.exception('parser error: %s', item)
def _generate(self, job): """ Generates the thumbnail by spawning MPlayer. Yields True if generation was successful, and False otherwise. """ mpargs = [job.filename] pos = 0 try: length = job.metadata.length if job.metadata.type == u'DVD': # Find longest title. longest = sorted(job.metadata.tracks, key = lambda t: t.length)[-1] # Small heuristic: favor lowest title that's at least 80% of the longest title. track = min([t for t in job.metadata.tracks if t.length > longest.length * 0.8]) length = track.length mpargs[0] = 'dvd://%d' % track.trackno mpargs.extend(['-dvd-device', job.filename]) elif job.metadata.video[0].length: length = job.metadata.video[0].length # Pick a random position between 30-70%. By randomizing, we give # the user the option to delete the original thumbnail and regenerate # a (likely) new one, in case the previous one wasn't very representative. pos = length * random.randrange(30, 70) / 100.0 if hasattr(job.metadata, 'type'): # FIXME: dischi, this logic needs a comment. if job.metadata.type in ('MPEG-TS', 'MPEG-PES'): pos = length / 20.0 except (AttributeError, IndexError, TypeError): # else arbitrary consider that file is 1Mbps and grab position at 10% try: pos = os.stat(job.filename)[stat.ST_SIZE]/1024/1024/10.0 except (OSError, IOError): yield False if pos < 10: # FIXME: needs another comment; is this because keyframes tend to be # every 10 seconds? But if length < 10, won't we risk seeking to EOF and # not getting any thumbnail at all?" pos = 10 try: # Give MPlayer 10 seconds to generate the thumbnail before we give # up and kill it. Some video files cause mplayer to runaway. yield self.mplayer.start([str(pos)] + mpargs).timeout(10, abort=True) except kaa.TimeoutException: log.error('Thumbnailer timed out while trying to process %s', job.filename) if self.mplayer.stopping: # MPlayer was aborted due to timeout and is now stopping. We # want to wait until it's fully terminated before proceeding, # so we yield again on its 'finished' signal which will be # emitted once the abort is complete. yield kaa.inprogress(self.mplayer.signals['finished']) # MPlayer is done, look for the screenshots it created. captures = glob.glob('000000??.png') if not captures: # No images, Mplayer crashed on this file? log.error('no images found') yield False # find the largest image (making assumption it's the best) current_capture = sorted(captures, key=lambda x: os.stat(x)[stat.ST_SIZE])[-1] try: # scale thumbnail for size, width, height in (('large', 256, 256), ('normal', 128, 128)): image = kaa.imlib2.open_without_cache(current_capture) try: # FIXME: Thumb::Mimetype ends up being wrong. libthumb.png(job.filename, job.imagefile % size, (width, height), image._image) except (IOError, ValueError): self.create_failed(job) break # remove old stuff os.rename(current_capture, os.path.basename(job.filename) + '.png') # remove old files. [ os.remove(fname) for fname in captures if os.path.isfile(fname) ] except Exception, e: log.exception('Thumbnailing of MPlayer screenshots failed') yield False
def add_directory_attributes(db, directory): """ Add some extra attributes for a directory recursive. This function checkes album, artist, image and length. When there are changes, go up to the parent and check it, too. """ data = { 'length': 0, 'artist': u'', 'album': u'', 'image': '', 'series': '', 'season': '' } check_attr = data.keys()[:] check_attr.remove('length') if directory._beacon_data['image_from_parser'] and \ directory._beacon_data['image']: # The directory had an image defined and found by the parser. # Delete image from data, we don't want to override it. del data['image'] items = { 'video': [], 'audio': [], 'image': [], 'dir': [], 'other': [] } for item in (yield db.query(parent=directory)): t = item._beacon_data.get('type') if t in items: items[t].append(item) else: items['other'].append(item) relevant = [] if (not items['video'] and not items['other'] and not items['dir']) and \ ((len(items['audio']) > 2, len(items['image']) <= 1) or \ (len(items['audio']) > 8, len(items['image']) <= 3)): # Could be music files. Only music files plus maybe # folder/cover images relevant = items['audio'] if (not items['audio'] and not items['other'] and not items['dir']) and \ (len(items['video']) > 2, len(items['image']) <= 1): # Could be video files. Only video files plus maybe one # folder/cover image relevant = items['video'] if not items['audio'] and not items['video'] and not items['other'] and \ items['dir'] and len(items['image']) <= 1: # only directories with maybe one folder/cover image relevant = items['dir'] for item in relevant: data['length'] += item._beacon_data.get('length', 0) or 0 for attr in check_attr: value = item._beacon_data.get(attr, data[attr]) if data[attr] == '': data[attr] = value if data[attr] != value: data[attr] = None check_attr.remove(attr) if data['image'] and not (data['artist'] or data['album']): # We have neither artist nor album. So this seems to be a video # or an image directory and we don't want to set the image from # maybe one item in that directory as our directory image. data['image'] = None data = dict([ x for x in data.items() if x[1] is not None ]) for attr in data.keys(): if data[attr] != directory._beacon_data[attr]: break else: # no changes. yield True yield kaa.inprogress(db.read_lock) # update directory in database db.update_object(directory._beacon_id, **data) directory._beacon_data.update(data) # check parent if directory._beacon_parent: yield add_directory_attributes(db, directory._beacon_parent)
def add_directory_attributes(db, directory): """ Add some extra attributes for a directory recursive. This function checkes album, artist, image and length. When there are changes, go up to the parent and check it, too. """ data = { 'length': 0, 'artist': u'', 'album': u'', 'image': '', 'series': '', 'season': '' } check_attr = data.keys()[:] check_attr.remove('length') if directory._beacon_data['image_from_parser'] and \ directory._beacon_data['image']: # The directory had an image defined and found by the parser. # Delete image from data, we don't want to override it. del data['image'] items = {'video': [], 'audio': [], 'image': [], 'dir': [], 'other': []} for item in (yield db.query(parent=directory)): t = item._beacon_data.get('type') if t in items: items[t].append(item) else: items['other'].append(item) relevant = [] if (not items['video'] and not items['other'] and not items['dir']) and \ ((len(items['audio']) > 2, len(items['image']) <= 1) or \ (len(items['audio']) > 8, len(items['image']) <= 3)): # Could be music files. Only music files plus maybe # folder/cover images relevant = items['audio'] if (not items['audio'] and not items['other'] and not items['dir']) and \ (len(items['video']) > 2, len(items['image']) <= 1): # Could be video files. Only video files plus maybe one # folder/cover image relevant = items['video'] if not items['audio'] and not items['video'] and not items['other'] and \ items['dir'] and len(items['image']) <= 1: # only directories with maybe one folder/cover image relevant = items['dir'] for item in relevant: data['length'] += item._beacon_data.get('length', 0) or 0 for attr in check_attr: value = item._beacon_data.get(attr, data[attr]) if data[attr] == '': data[attr] = value if data[attr] != value: data[attr] = None check_attr.remove(attr) if data['image'] and not (data['artist'] or data['album']): # We have neither artist nor album. So this seems to be a video # or an image directory and we don't want to set the image from # maybe one item in that directory as our directory image. data['image'] = None data = dict([x for x in data.items() if x[1] is not None]) for attr in data.keys(): if data[attr] != directory._beacon_data[attr]: break else: # no changes. yield True yield kaa.inprogress(db.read_lock) # update directory in database db.update_object(directory._beacon_id, **data) directory._beacon_data.update(data) # check parent if directory._beacon_parent: yield add_directory_attributes(db, directory._beacon_parent)
if opts.update: tv.epg.update(config.XMLTV_FILE) else: grab() import kaa from tv.record_client import RecordClient def handler(result): if result: print _('Updated recording schedule') else: print _('Not updated recording schedule') raise SystemExit rc = RecordClient() try: kaa.inprogress(rc.channel).wait() except Exception, why: print 'Cannot connect to record server' raise SystemExit print 'Scheduling favorites for recording: ' if not rc.updateFavoritesSchedule(handler): print rc.recordserverdown raise SystemExit kaa.main.run()
def _parse(db, item, mtime): """ Parse the item, this can take a while. """ produced_load = 0 try: # # Parent checking # parent = item._beacon_parent if not parent._beacon_id: # There is a parent without id, update the parent now. r = parse(db, parent) if isinstance(r, kaa.InProgress): yield r if not parent._beacon_id: # This should never happen raise AttributeError('parent for %s has no dbid' % item) # we had no parent id which we have now. Restart the whole # parsing process. maye this item was in the db already r = parse(db, parent) if isinstance(r, kaa.InProgress): r = yield r yield r # # Metadata parsing # t1 = time.time() # FIXME: add force parameter from config file: # - always force (slow but best result) # - never force (faster but maybe wrong) # - only force on media 1 (good default) # Parse metadata in an extra named thread metadata = yield parse_thread(item.filename) if not metadata: metadata = {} attributes = {'mtime': mtime, 'image': metadata.get('image')} if metadata.get('media') == kaa.metadata.MEDIA_DISC and \ metadata.get('subtype') in db.list_object_types(): type = metadata['subtype'] if metadata.get('type'): attributes['scheme'] = metadata.get('type').lower() item._beacon_isdir = False elif media_types.get(metadata.get('media')) in db.list_object_types(): type = media_types.get(metadata['media']) elif item._beacon_isdir: type = 'dir' else: type = 'file' if item._beacon_id and type != item._beacon_id[0]: # The item changed its type. Adjust the db yield kaa.inprogress(db.read_lock) data = db.update_object_type(item._beacon_id, type) if not data: log.info('item to change not in the db anymore') log.info('change item %s to %s' % (item._beacon_id, type)) item._beacon_database_update(data) # # Thumbnail / Cover / Image stuff. # produced_load = 1 if type == 'dir': # If the image was detected by the parser, do not override # it in add_directory_attributes attributes['image_from_parser'] = bool(attributes.get('image')) elif type == 'image': attributes['image'] = item.filename if metadata.get('thumbnail'): t = thumbnail.Thumbnail(item.filename, item._beacon_media) if t.needs_update: # only store the normal version try: produced_load = 2 t.normal = kaa.imlib2.open_from_memory( metadata.get('thumbnail')) except (ValueError, IOError): log.exception('image thumbnail') else: base = os.path.splitext(item.filename)[0] if type == 'video' and not attributes.get( 'image') and thumbnail.SUPPORT_VIDEO: attributes['image'] = item.filename if metadata.get('thumbnail') and not attributes.get('image'): attributes['image'] = item.filename t = thumbnail.Thumbnail(item.filename, item._beacon_media) try: produced_load = 2 t.image = kaa.imlib2.open_from_memory( metadata['thumbnail']) except (ValueError, IOError): log.exception('raw thumbnail') for ext in ('.jpg', '.png'): if os.path.isfile(base + ext): if type == 'video': attributes['poster'] = base + ext else: attributes['image'] = base + ext break if os.path.isfile(item.filename + ext): if type == 'video': attributes['poster'] = item.filename + ext else: attributes['image'] = item.filename + ext break # # Type specific attributes # if type == 'video': # Normally db.add_object() will take care of assigning type # attributes from metadata, but some attributes for videos # aren't at the top-level attribute object. For video # dimensions, take the dimensions of the first video track # (of the longest title, if applicable). video = None if metadata.get('video'): video = metadata.video[0] elif metadata.get('tracks'): # Find the longest title with a video track. for title in sorted(metadata.tracks, key=lambda t: -t.length): if title.get('video'): video = title.video[0] break if video: attributes['width'] = video.get('width') attributes['height'] = video.get('height') attributes['series'] = metadata.series attributes['season'] = metadata.season attributes['episode'] = metadata.episode attributes['metadata'] = metadata # now call extention plugins ext = os.path.splitext(item.filename)[1] for function in extention_plugins.get(ext, []) + extention_plugins.get( None, []): function(item, attributes, type) yield kaa.inprogress(db.read_lock) if attributes.get('image'): # create thumbnail t = thumbnail.Thumbnail(attributes.get('image'), item._beacon_media) if t.needs_update and (not type == 'video' or not hasattr(item, 'filename') or utils.do_thumbnail(item.filename)): t.create(t.PRIORITY_LOW) # # Database code # # add kaa.metadata results, the db module will add everything known # to the db. After that add or update the database. # if item._beacon_id: # Update old db entry db.update_object(item._beacon_id, **attributes) item._beacon_data.update(attributes) else: # check if for some reasons the same item was parsed # parallel. If so, do not add it again and reuse the id entry = db._db.query(parent=parent._beacon_id, name=item._beacon_data['name']) if entry: # Update old db entry log.error('item already in db, re-use beacon_id') db.update_object((entry[0]['type'], entry[0]['id']), **attributes) obj = db._db.query(parent=parent._beacon_id, name=item._beacon_data['name'])[0] else: # Create new entry obj = db.add_object(type, name=item._beacon_data['name'], parent=parent, **attributes) item._beacon_database_update(obj) # # Additional track handling # if hasattr(metadata, 'tracks'): # The item has tracks, e.g. a dvd image on hd. if not metadata.get('type'): log.error('%s metadata has no type', item) yield produced_load # delete all known tracks before adding new result = yield db.query(parent=item) for track in result: db.delete_object(track) if not 'track_%s' % metadata.get('type').lower() in \ db.list_object_types(): key = metadata.get('type').lower() log.error('track_%s not in database keys', key) yield produced_load type = 'track_%s' % metadata.get('type').lower() for track in metadata.tracks: db.add_object(type, name=str(track.trackno), parent=item, metadata=track) # parsing done log.info('scan %s (%0.3f)' % (item, time.time() - t1)) except GeneratorExit: # Don't catch this, otherwise if the coroutine is aborted you get # "_parse() ignored GeneratorExit" raise except Exception, e: log.exception('parser error: %s', item)
class LCD(object): """ LCD interface """ def __init__(self, server='127.0.0.1', port=13666): self.signals = { 'connected': kaa.Signal() } self._server = server self._port = port self._connected = False self._connect() self._screenno = 0 def create_screen(self, name = None, priority='foreground', duration=0): """ Create a new screen with the given name. """ if not name: name = 'lcd%d' % self._screenno self._screenno += 1 return Screen(self, name, priority, duration) def _send(self, line): """ Send a command to the server. """ if not self._connected: return self.socket.write(line + '\n') def _disconnect(self, expected): self._connected = False self._connect() @kaa.coroutine() def _connect(self): """ Connect to the server and init the connection. """ if self._connected: yield False self.socket = kaa.Socket() try: yield self.socket.connect((self._server, self._port)) except Exception, e: # try again later log.error('LCDproc connection error; will try again later') kaa.OneShotTimer(self._connect).start(10) yield False self.socket.signals['closed'].connect_once(self._disconnect) self._connected = True self._send('hello') wait = kaa.inprogress(self.socket.signals['read']) line = (yield wait).strip().split() self._send('client_set name kaa') self.size = int(line[7]), int(line[9]) self.width, self.height = self.size log.info('LCDproc connected') self.signals['connected'].emit(self.width, self.height) yield False
if __name__ == '__main__': if len(sys.argv) >= 2: function = sys.argv[1] else: function = 'none' from time import sleep idnr = None startclock = time.clock() es = EncodingClientActions() print time.clock() - startclock kaa.inprogress(es.channel).wait() print time.clock() - startclock if function == 'test2': result = es.ping() print 'ping:', result if not result: raise EncodingClientActions.encodingserverdown result = es.getContainerCAP() print 'getContainerCAP:', result container = result[1][1] result = es.getVideoCodecCAP() print 'getVideoCodecCAP:', result video_codec = result[1][3] result = es.getAudioCodecCAP() print 'getAudioCodecCAP:', result audio_codec = result[1][3]