def __init__(self, name='unknown', channel='unknown', priority=0, start=0, stop=0, node=None, info={} ): self.id = Recording.NEXT_ID Recording.NEXT_ID += 1 self.name = name self.channel = channel self.priority = priority self.start = start self.stop = stop # optional information self.subtitle = '' self.episode = '' self.description = '' self.url = '' self.fxdname = '' self.info = {} self.status = CONFLICT self.start_padding = config.recording.start_padding self.stop_padding = config.recording.stop_padding self.respect_start_padding = True self.respect_stop_padding = True for key, value in info.items(): if key in ('subtitle', 'description') and value: setattr(self, key, kaa.str_to_unicode(value)) elif key == 'url' and value: self.url = kaa.unicode_to_str(value) elif key in ('start_padding', 'stop_padding'): setattr(self, key, int(value)) elif value: self.info[key] = kaa.str_to_unicode(value) # device where the tvserver wants to schedule the recording self.device = None # device where the recording is currently scheduled self._scheduled_device = None if node: self._add_xml_data(node)
def __str__(self): """ A simple string representation for a recording for debugging in the tvserver. """ channel = self.channel if len(channel) > 10: channel = channel[:10] diff = (self.stop - self.start) / 60 name = self.name if len(name) > 17: name = name[:14] + u'...' name = u'"' + name + u'"' status = self.status if status == 'scheduled' and self.device: status = self.device.name if self.respect_start_padding: start_padding = int(self.start_padding / 60) else: start_padding = 0 if self.respect_stop_padding: stop_padding = int(self.stop_padding / 60) else: stop_padding = 0 return '%3d %10s %-19s %4d %s/%s-%s %2s %2s %s' % \ (self.id, kaa.unicode_to_str(channel), kaa.unicode_to_str(name), self.priority, _time_int2str(self.start)[4:8], _time_int2str(self.start)[8:-6], _time_int2str(self.stop)[8:], start_padding, stop_padding, kaa.unicode_to_str(status))
def __str__(self): """ A simple string representation for a recording for debugging in the tvserver. """ channel = self.channel if len(channel) > 10: channel = channel[:10] diff = (self.stop - self.start) / 60 name = self.name if len(name) > 17: name = name[:14] + u'...' name = u'"' + name + u'"' status = self.status if status == 'scheduled' and self.device: status = self.device.name if self.respect_start_padding: start_padding = int(self.start_padding/60) else: start_padding = 0 if self.respect_stop_padding: stop_padding = int(self.stop_padding/60) else: stop_padding = 0 return '%3d %10s %-19s %4d %s/%s-%s %2s %2s %s' % \ (self.id, kaa.unicode_to_str(channel), kaa.unicode_to_str(name), self.priority, _time_int2str(self.start)[4:8], _time_int2str(self.start)[8:-6], _time_int2str(self.stop)[8:], start_padding, stop_padding, kaa.unicode_to_str(status))
def parse_feed(c): for d in c.childNodes: if not d.nodeName == 'directory': continue dirname = kaa.unicode_to_str(d.childNodes[0].data.strip()) url = kaa.unicode_to_str(c.getAttribute('url')) feed = _get_feed(url, dirname) feed._readxml(c) _feeds.append(feed) return
def _add_xml_data(self, node): """ Parse informations from a fxd node and set the internal variables. """ for child in node: for var in ('name', 'fxdname'): if child.nodename == var: setattr(self, var, child.content) if child.nodename == 'url': self.url = kaa.unicode_to_str(child.content) if child.nodename == 'once': self.once = True if child.nodename == 'substring': self.substring = True if child.nodename == 'channels': self.channels = [] for c in child: self.channels.append(c.content) if child.nodename == 'days': self.days = [] for v in child.content.split(' '): self.days.append(int(v)) if child.nodename == 'times': self.times = [] for t in child: self.times.append(t.content) if child.nodename == 'padding': self.start_padding = int(child.start) self.stop_padding = int(child.stop) if child.nodename == 'priority': setattr(self, 'priority', int(child.content))
def scan(files, progress): global num_deleted for thumbnail in files: progress.update() metadata = kaa.metadata.parse(thumbnail) if not metadata: if FORCE: os.unlink(thumbnail) num_deleted += 1 continue uri = metadata['Thumb::URI'] if not uri: if FORCE: os.unlink(thumbnail) num_deleted += 1 continue uri = kaa.unicode_to_str(uri) if not uri.startswith('file://'): if FORCE: os.unlink(thumbnail) num_deleted += 1 continue if not os.path.isfile(uri[7:]): os.unlink(thumbnail) num_deleted += 1
def _fill_template(self, rec, text, is_url): """ Fill template like url and fxdname from the favorite to something specific for the recording. """ t = time.strftime('%Y %m %d %H:%M', time.localtime(rec.start)) year, month, day, hour_min = t.split(' ') options = { 'title': rec.name, 'year': year, 'month': month, 'day': day, 'time': hour_min, 'episode': rec.episode, 'subtitle': rec.subtitle } if is_url: # url is string and an extra '/' is not allowed. Replace '/' # with '_' and also convert all args to string. for o in options: options[o] = kaa.unicode_to_str(options[o]).replace('/', '_') for pattern in re.findall('%\([a-z]*\)', text): if not str(pattern[2:-1]) in options: options[pattern[2:-1]] = pattern text = re.sub('%\([a-z]*\)', lambda x: x.group(0) + 's', text) text = text % options return text.rstrip(' -_:')
def _fill_template(self, rec, text, is_url): """ Fill template like url and fxdname from the favorite to something specific for the recording. """ t = time.strftime('%Y %m %d %H:%M', time.localtime(rec.start)) year, month, day, hour_min = t.split(' ') options = { 'title' : rec.name, 'year' : year, 'month' : month, 'day' : day, 'time' : hour_min, 'episode' : rec.episode, 'subtitle' : rec.subtitle } if is_url: # url is string and an extra '/' is not allowed. Replace '/' # with '_' and also convert all args to string. for o in options: options[o] = kaa.unicode_to_str(options[o]).replace('/', '_') for pattern in re.findall('%\([a-z]*\)', text): if not str(pattern[2:-1]) in options: options[pattern[2:-1]] = pattern text = re.sub('%\([a-z]*\)', lambda x: x.group(0)+'s', text) text = text % options return text.rstrip(' -_:')
def url(self): """ URL, absolute or relative filename """ if self.__url: # something is set, return it return self.__url filename_array = { 'progname': kaa.unicode_to_str(self.name), 'title' : kaa.unicode_to_str(self.subtitle) } filemask = config.recording.filemask % filename_array filename = '' for letter in datetime.fromtimestamp(self.start, kaa.dateutils.local).strftime(filemask): if letter in string.ascii_letters + string.digits: filename += letter elif filename and filename[-1] != '_': filename += '_' return filename.rstrip(' -_:')
def __getattr__(self, attr): if attr == 'basename' and not 'basename' in self.keys(): basename = os.path.basename(self['url']) if self.url.endswith('/'): ext = os.path.splitext(self['url'])[1] basename = self['title'].replace('/', '') + ext self['basename'] = kaa.unicode_to_str(basename) return self.get(attr)
def __str__(self): if self.description.has_key('title') and self.description['title']: s = self.description['title'] else: s = self.name if self.description.has_key('episode') and self.description['episode']: s += u' %s' % self.description['episode'] if self.description.has_key('subtitle') and \ self.description['subtitle']: s += u' - %s' % self.description['subtitle'] return kaa.unicode_to_str(s)
def url(self): """ URL, absolute or relative filename """ if self.__url: # something is set, return it return self.__url filename_array = { 'progname': kaa.unicode_to_str(self.name), 'title': kaa.unicode_to_str(self.subtitle) } filemask = config.recording.filemask % filename_array filename = '' for letter in datetime.fromtimestamp( self.start, kaa.dateutils.local).strftime(filemask): if letter in string.ascii_letters + string.digits: filename += letter elif filename and filename[-1] != '_': filename += '_' return filename.rstrip(' -_:')
def replace(obj, l): try: r = eval(obj.group()[2:-2], l) if r == None: return '' if isinstance(r, unicode): return kaa.unicode_to_str(r) return str(r) except (SystemExit, KeyboardInterrupt): raise SystemExit except Exception, e: return ''
def _get_image(self, url): """ Download image and store it to the image dir. Returns image filename. """ url = kaa.unicode_to_str(url) fname = hashlib.md5(url).hexdigest() + os.path.splitext(url)[1] fname = os.path.join(self.IMAGEDIR, fname) if os.path.isfile(fname): yield fname yield kaa.net.url.fetch(url, fname) yield fname
def __str__(self): """ A simple string representation for a favorite for debugging in the tvserver. """ name = self.name if len(name) > 30: name = name[:30] + u'...' name = kaa.unicode_to_str(u'"' + name + u'"') if self.once: once = '(schedule once)' else: once = '' if self.substring: substring = '(substring matching)' else: substring = '(exact matching)' return '%3d %-35s %4d %s %s' % (self.id, name, self.priority, once, substring)
def _readxml(self, node): """ Read XML node with feed configuration and cache. """ for d in node.childNodes: if not d.nodeName == 'directory': continue self._download = d.getAttribute('download').lower() == 'true' self._num = int(d.getAttribute('num')) self._keep = d.getAttribute('keep').lower() == 'true' for node in d.childNodes: if not node.nodeName == 'entry': continue fname = kaa.unicode_to_str(node.getAttribute('filename')) or None self._entries.append((node.getAttribute('url'), fname))
def update_recording(self, rec): """ Update recording based on data from the favorite """ rec.favorite = True rec.start_padding = self.start_padding rec.stop_padding = self.stop_padding rec.fxdname = self.fxdname if self.url: # add url template to recording try: url = self._fill_template(rec, self.url, True) rec.url = kaa.unicode_to_str(url) except Exception, e: log.exception('Error setting recording url')
def add_item(self, url, type, parent, **kwargs): """ Add non-file item item. """ if self.status == DISCONNECTED: raise RuntimeError('client not connected') if isinstance(url, unicode): url = kaa.unicode_to_str(url) if url.find('://') > 0: kwargs['scheme'] = url[:url.find('://')] kwargs['name'] = url i = Item(None, url, kwargs, parent, parent._beacon_media) rpc = self.rpc('item_create', type=type, parent=parent._beacon_id, **kwargs) rpc.connect(i._beacon_database_update) return i
def widget_set(self, type, id, *args): """ Changes attributes of a widget. See widget_add for details. """ args = list(args) if type == 'scroller' and len(args[-1]) > self.width and \ not args[-1][-1] in ' -_': # looks better args[-1] += ' ' if type in ('string', 'title', 'scroller'): if isinstance(args[-1], unicode): a = kaa.unicode_to_str(args[-1]) args[-1] = '"%s"' % args[-1].replace('"', '\\"').replace('\n', '') self._send('widget_set %s %s %s' % \ (self.name, id, ' '.join([str(i) for i in args ])))
def _finalize(self): """ Correct same data based on specific rules """ # make sure all strings are unicode for key in self._keys: if key in UNPRINTABLE_KEYS: continue value = getattr(self, key) if value is None: continue if key == 'image': if isinstance(value, unicode): setattr(self, key, kaa.unicode_to_str(value)) continue if isinstance(value, str): setattr(self, key, kaa.str_to_unicode(value)) if isinstance(value, unicode): setattr(self, key, value.strip().rstrip().replace(u'\0', u'')) if isinstance(value, list) and value and isinstance( value[0], Media): for submenu in value: submenu._finalize() # copy needed tags from tables for name, table in self.tables.items(): mapping = self.table_mapping.get(name, {}) for tag, attr in mapping.items(): if self.get(attr): continue value = table.get(tag, None) if value is not None: if not isinstance(value, (str, unicode)): value = kaa.str_to_unicode(str(value)) elif isinstance(value, str): value = kaa.str_to_unicode(value) value = value.strip().rstrip().replace(u'\0', u'') setattr(self, attr, value) if 'fourcc' in self._keys and 'codec' in self._keys and self.codec is not None: # Codec may be a fourcc, in which case we resolve it to its actual # name and set the fourcc attribute. self.fourcc, self.codec = fourcc.resolve(self.codec) if 'language' in self._keys: self.langcode, self.language = language.resolve(self.language)
def _finalize(self): """ Correct same data based on specific rules """ # make sure all strings are unicode for key in self._keys: if key in UNPRINTABLE_KEYS: continue value = getattr(self, key) if value is None: continue if key == 'image': if isinstance(value, unicode): setattr(self, key, kaa.unicode_to_str(value)) continue if isinstance(value, str): setattr(self, key, kaa.str_to_unicode(value)) if isinstance(value, unicode): setattr(self, key, value.strip().rstrip().replace(u'\0', u'')) if isinstance(value, list) and value and isinstance(value[0], Media): for submenu in value: submenu._finalize() # copy needed tags from tables for name, table in self.tables.items(): mapping = self.table_mapping.get(name, {}) for tag, attr in mapping.items(): if self.get(attr): continue value = table.get(tag, None) if value is not None: if not isinstance(value, (str, unicode)): value = kaa.str_to_unicode(str(value)) elif isinstance(value, str): value = kaa.str_to_unicode(value) value = value.strip().rstrip().replace(u'\0', u'') setattr(self, attr, value) if 'fourcc' in self._keys and 'codec' in self._keys and self.codec is not None: # Codec may be a fourcc, in which case we resolve it to its actual # name and set the fourcc attribute. self.fourcc, self.codec = fourcc.resolve(self.codec) if 'language' in self._keys: self.langcode, self.language = language.resolve(self.language)
def __init__(self, name='unknown', channel='unknown', priority=0, start=0, stop=0, node=None, info={}): self.id = Recording.NEXT_ID Recording.NEXT_ID += 1 self.name = name self.channel = channel self.priority = priority self.start = start self.stop = stop # optional information self.subtitle = '' self.episode = '' self.description = '' self.url = '' self.fxdname = '' self.info = {} self.status = CONFLICT self.start_padding = config.recording.start_padding self.stop_padding = config.recording.stop_padding self.respect_start_padding = True self.respect_stop_padding = True for key, value in info.items(): if key in ('subtitle', 'description') and value: setattr(self, key, kaa.str_to_unicode(value)) elif key == 'url' and value: self.url = kaa.unicode_to_str(value) elif key in ('start_padding', 'stop_padding'): setattr(self, key, int(value)) elif value: self.info[key] = kaa.str_to_unicode(value) # device where the tvserver wants to schedule the recording self.device = None # device where the recording is currently scheduled self._scheduled_device = None if node: self._add_xml_data(node)
def __init__(self, directory): core.Media.__init__(self) # search .directory info = os.path.join(directory, '.directory') if os.path.isfile(info): f = open(info) for l in f.readlines(): if l.startswith('Icon='): image = l[5:].strip() if not image.startswith('/'): image = os.path.join(directory, image) if os.path.isfile(image): self._set('image', image) if l.startswith('Name='): self.title = l[5:].strip() if l.startswith('Comment='): self.comment = l[8:].strip() f.close() # search album.xml (bins) binsxml = os.path.join(directory, 'album.xml') if os.path.isfile(binsxml): bins = BinsParser(binsxml) for key, value in bins.items(): if key == 'sampleimage': image = os.path.join(directory, kaa.unicode_to_str(value)) if os.path.isfile(image): self._set('image', image) continue self._set(key, value) # find (folder|cover).(jpg|jpeg|png) for basename in ('folder', 'cover'): for ext in ('png', 'jpg', 'jpeg'): folder = os.path.join(directory, basename + '.' + ext) if os.path.isfile(folder): self._set('image', folder) self.mime = 'text/directory'
def __init__(self, directory): core.Media.__init__(self) # search .directory info = os.path.join(directory, '.directory') if os.path.isfile(info): f = open(info) for l in f.readlines(): if l.startswith('Icon='): image = l[5:].strip() if not image.startswith('/'): image = os.path.join(directory, image) if os.path.isfile(image): self._set('image', image) if l.startswith('Name='): self.title = l[5:].strip() if l.startswith('Comment='): self.comment = l[8:].strip() f.close() # search album.xml (bins) binsxml = os.path.join(directory, 'album.xml') if os.path.isfile(binsxml): bins = BinsParser(binsxml) for key, value in list(bins.items()): if key == 'sampleimage': image = os.path.join(directory, kaa.unicode_to_str(value)) if os.path.isfile(image): self._set('image', image) continue self._set(key, value) # find folder.jpg (windows style cover) folderjpg = os.path.join(directory, 'folder.jpg') if os.path.isfile(folderjpg): self._set('image', folderjpg) self.mime = 'text/directory'
def _add_xml_data(self, node): """ Parse informations from a fxd node and set the internal variables. """ # Parse informations from a fxd node and set the internal variables. for child in node: for var in ('name', 'channel', 'status', 'subtitle', 'fxdname', 'episode', 'description'): if child.nodename == var: setattr(self, var, child.content) if child.nodename == 'url': self.url = kaa.unicode_to_str(child.content) if child.nodename == 'priority': self.priority = int(child.content) if child.nodename == 'padding': self.start_padding = int(child.start) self.stop_padding = int(child.stop) if child.nodename == 'timer': self.start = _time_str2int(child.start) self.stop = _time_str2int(child.stop) if child.nodename == 'info': for info in child: self.info[info.nodename] = info.content
def update(self, verbose=False): """ Update feed. """ def print_status(s): sys.stdout.write("%s\r" % s.get_progressbar()) sys.stdout.flush() if self._updating: log.error('feed %s is already updating', self.url) yield False self._updating = True log.info('update feed %s', self.url) # get directory information beacondir = yield kaa.beacon.get(self.dirname) listing = yield beacondir.list() allurls = [ f.url for f in listing ] num = self._num allfiles = [ e[1] for e in self._entries ] entries = self._entries new_entries = [] iter = self.iterate() for entry in iter: while isinstance(entry, kaa.InProgress): # dummy entry to signal waiting result = yield entry # send result back to the iterator entry = iter.send(result) log.info('process %s', entry.url) filename = None if not self._download and entry.url in allurls: # already in beacon list pass elif not self._download: # use url as name entry['name'] = kaa.unicode_to_str(entry.url) i = yield kaa.beacon.add_item(parent=beacondir, **entry) else: # download filename = os.path.join(self.dirname, entry.basename) if not os.path.isfile(filename) and filename in allfiles: # file not found, check if it was downloaded before. If # so, the user deleted it and we do not fetch it again pass elif os.path.isfile(filename): # File already downloaded. # FIXME: make sure the file is up-to-date pass else: async = entry.fetch(filename) if verbose: async.progress.connect(print_status) yield async if not os.path.isfile(filename): log.error('error fetching', entry.url) continue if os.path.isfile(filename): item = yield kaa.beacon.get(filename) if not item.scanned: yield item.scan() if 'date' in entry: item['timestamp'] = entry['date'] for key in ('title', 'description'): if key in entry: item[key] = entry[key] new_entries.append((entry['url'], filename)) num -= 1 if num == 0: break log.info('*** finished with %s ***', self.url) manager.save() # delete old files or remove old entries from beacon for url, filename in entries: if (self._keep and self._download) or (url, filename) in new_entries: continue if not filename: # delete old entries from beacon for f in (yield beacondir.list()): if f.url == url: f.delete() elif os.path.isfile(filename): # delete file on disc os.unlink(filename) self._updating = False self._entries = new_entries yield True
def __repr__(self): return '<kaa.epg.Program %s>' % unicode_to_str(self.title)
class PluginInterface(freevo.Plugin): """ Display context info in LCD using lcdproc daemon. """ def __init__(self): """ init the lcd """ super(PluginInterface, self).__init__() self.lcd = kaa.display.LCD() self.lcd.signals['connected'].connect(self._connected) self.running = False self.current = [] self.timer = kaa.Timer(self.update) def _connected(self, width, height): if self.running: del self.current self.set_application(freevo.taskmanager.current) return True self.running = True self.height = height self.width = width self.playitem = None self.screens = None l = self.height while not self.screens: try: layouts[l] c = self.width while True: try: self.screens = layouts[l][c] break except KeyError: c -= 1 if c < 1: raise KeyError except KeyError: l -= 1 if l < 1: return False self.lines = l self.columns = c kaa.EventHandler(self.eventhandler).register() freevo.signals['application-change'].connect(self.set_application) self.set_application(freevo.taskmanager.current) def set_application(self, app): name = app.name widgets = self.screens.get(name) if not widgets: log.error('no lcd screen for %s %s' % (name, self.screens.keys())) self.current = [] return self.current = [app, self.lcd.create_screen(name)] for widget in widgets: w = self.current[1].widget_add(widget[0]) self.current.append([w, widget[1:], []]) self.update() def update(self): def replace(obj, l): try: r = eval(obj.group()[2:-2], l) if r == None: return '' if isinstance(r, unicode): return kaa.unicode_to_str(r) return str(r) except (SystemExit, KeyboardInterrupt): raise SystemExit except Exception, e: return '' if not self.current: return menu = None if hasattr(self.current[0], 'current'): menu = self.current[0].current item = self.playitem cb = kaa.Callable(replace, locals()) for w in self.current[2:]: args = [] for a in w[1]: if isinstance(a, unicode): a = kaa.unicode_to_str(a) if isinstance(a, str) and a.find('%%') >= 0: a = varreg.subn(cb, a)[0] args.append(a) if w[2] != args: w[0].set(*args) w[2] = args
def __repr__(self): return '<kaa.epg.Channel %s>' % unicode_to_str(self.name)
def __str__(self): return kaa.unicode_to_str(unicode(self))
def _normalize_name(self, name): return kaa.unicode_to_str(name.replace('.', '').replace(' ', '')).upper().strip()
def _normalize_name(self, name): return kaa.unicode_to_str(name.replace('.', '').replace( ' ', '')).upper().strip()