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 _readChunk(self, file): try: (length, type) = struct.unpack('>I4s', file.read(8)) except (OSError, IOError, struct.error): return 0 key = None if type == 'IEND': return 0 elif type == 'IHDR': data = file.read(length + 4) self.width, self.height, self.depth = struct.unpack( ">IIb", data[:9]) elif type == 'tEXt': log.debug('latin-1 Text found.') (data, crc) = struct.unpack('>%isI' % length, file.read(length + 4)) (key, value) = data.split('\0') self.meta[key] = kaa.str_to_unicode(value) elif type == 'zTXt': log.debug('Compressed Text found.') (data, crc) = struct.unpack('>%isI' % length, file.read(length + 4)) split = data.split('\0') key = split[0] value = "".join(split[1:]) compression = ord(value[0]) value = value[1:] if compression == 0: decompressed = zlib.decompress(value) log.debug("%s (Compressed %i) -> %s" % \ (key,compression,decompressed)) else: log.debug("%s has unknown Compression %c" % (key, compression)) self.meta[key] = kaa.str_to_unicode(value) elif type == 'iTXt': log.debug('International Text found.') (data, crc) = struct.unpack('>%isI' % length, file.read(length + 4)) (key, value) = data.split('\0') self.meta[key] = kaa.str_to_unicode(value) else: file.seek(length + 4, 1) log.debug("%s of length %d ignored." % (type, length)) if key is not None and key.lower() == "comment": self.comment = self.meta[key] return 1
def _readChunk(self,file): try: (length, type) = struct.unpack('>I4s', file.read(8)) except (OSError, IOError, struct.error): return 0 key = None if type == 'IEND': return 0 elif type == 'IHDR': data = file.read(length+4) self.width, self.height, self.depth = struct.unpack(">IIb", data[:9]) elif type == 'tEXt': log.debug('latin-1 Text found.') (data, crc) = struct.unpack('>%isI' % length,file.read(length+4)) (key, value) = data.split('\0') self.meta[key] = kaa.str_to_unicode(value) elif type == 'zTXt': log.debug('Compressed Text found.') (data,crc) = struct.unpack('>%isI' % length,file.read(length+4)) split = data.split('\0') key = split[0] value = "".join(split[1:]) compression = ord(value[0]) value = value[1:] if compression == 0: decompressed = zlib.decompress(value) log.debug("%s (Compressed %i) -> %s" % \ (key,compression,decompressed)) else: log.debug("%s has unknown Compression %c" % (key,compression)) self.meta[key] = kaa.str_to_unicode(value) elif type == 'iTXt': log.debug('International Text found.') (data,crc) = struct.unpack('>%isI' % length,file.read(length+4)) (key, value) = data.split('\0') self.meta[key] = kaa.str_to_unicode(value) else: file.seek(length+4,1) log.debug("%s of length %d ignored." % (type, length)) if key is not None and key.lower() == "comment": self.comment = self.meta[key] return 1
def browse(self): """ Show all items from that artist. """ title = kaa.str_to_unicode(self.artist) if self.album: query = dict(artist=self.artist, album=self.album, type='audio') title = '%s - %s' % (title, kaa.str_to_unicode(self.album)) else: query = dict(artist=self.artist, type='audio') # FIXME: monitor query for live update async = kaa.beacon.query(**query) self.pl = freevo.Playlist(title, async, self, type='audio') self.pl.browse()
def __init__(self, artist, parent): super(ArtistItem, self).__init__(parent) self.artist = artist # Work around a beacon bug for part in artist.split(' '): self.name += ' ' + kaa.str_to_unicode(part.capitalize()) self.name = self.name.strip()
def __init__(self, name='', playlist=[], parent=None, type=None, random=False, autoplay=False, repeat=REPEAT_OFF): """ Init the playlist @param playlist: - a filename to a playlist file (e.g. m3u) - a list of Items, beacon Items or filenames - a beacon query - an inprogress object pointing to something from the above @param type: either a media (video,audio,image) or None for all """ freevo.MediaItem.__init__(self, parent) freevo.ItemList.__init__(self) self.name = kaa.str_to_unicode(name) if self.type == 'tv': type = 'video' # variables only for Playlist self._playlist = playlist self.autoplay = autoplay self.repeat = repeat self.media_type = type self.next = None self._playlist_valid = playlist == [] self._random = random # create a basic info object self.info = {}
def match(self, metadata, id): """ Match the metadata to the given id. Metadata can either be a string with the name to match or a kaa.metadata object. """ if isinstance(metadata, (str, unicode)): alias = kaa.str_to_unicode(metadata) else: alias = metadata.get('series') if not alias: log.error('no alias given') yield False if not self._db.query(type='metadata'): attr, data = (yield parse(self.hostname + '/api/Updates.php?type=none')) data = dict(data) self._db.add('metadata', servertime=int(data['Time']), localtime=int(time.time())) data = self._db.query(type='series', tvdb=id) if not data: log.info('query thetvdb for %s' % id) for i in range(3): # try to get results three times before giving up yield self._update_series(id) data = self._db.query(type='series', tvdb=id) if data: break self.force_resync() if not data: log.error('no result from server') yield False self._update_db('alias', alias, parent=('series', data[0]['id'])) self._update_db('alias', data[0]['name'], parent=('series', data[0]['id'])) self._db.commit() series = Series(self, data[0]) self.force_resync() yield True
def to_list(self): """ Return a long list with every information about the recording. """ info = copy.copy(self.info) if self.subtitle: info['subtitle'] = self.subtitle if self.episode: info['episode'] = self.episode if self.__url: info['url'] = kaa.str_to_unicode(self.__url) if self.description: info['description'] = kaa.str_to_unicode(self.description) return self.id, self.name, self.channel, self.priority, self.start, \ self.stop, self.status, int(self.start_padding), \ int(self.stop_padding), info
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 get(self, key, default=None): """ Access attributes of the item. If the attribute is not found the default value (None) will be returned. """ if key.startswith('tmp:'): return self._beacon_tmpdata.get(key[4:], default) if key == 'parent': return self._beacon_parent if key == 'media': return self._beacon_media if key == 'read_only': # FIXME: this is not correct, a directory can also be # read only on a rw filesystem. return self._beacon_media.get('volume.read_only', default) if key in ('image', 'thumbnail'): image = self._beacon_data.get('image') if not image: if self._beacon_parent and self._beacon_id: # This is not a good solution, maybe the parent is # not up to date. Well, we have to live with that # for now. Only get image from parent if the item # is scanned because it is a very bad idea that # unscanned images (we do not know that they are # images yet) inherit the image from a directory. image = self._beacon_parent.get('image') if not image: return default if image.startswith('http://'): fname = self._beacon_controller._db.md5url(image, 'images') if key == 'image': if not os.path.isfile(fname): # FIXME: We need to fetch the image. Right now this will not happen # until beacon restarts or a thumbnail is requested return default return fname if key == 'thumbnail': # the thumbnail code will take care of downloading return Thumbnail(image, self._beacon_media) if key == 'image': return image if key == 'thumbnail': return Thumbnail(image, self._beacon_media) if key == 'title': t = self._beacon_data.get('title') if t: return t # generate some title and save local it for future use t = kaa.str_to_unicode( get_title(self._beacon_data['name'], self.isfile)) self._beacon_data['title'] = t return t result = self._beacon_data.get(key, default) if result is None: return default return result
def get(self, key, default=None): """ Access attributes of the item. If the attribute is not found the default value (None) will be returned. """ if key.startswith('tmp:'): return self._beacon_tmpdata.get(key[4:], default) if key == 'parent': return self._beacon_parent if key == 'media': return self._beacon_media if key == 'read_only': # FIXME: this is not correct, a directory can also be # read only on a rw filesystem. return self._beacon_media.get('volume.read_only', default) if key in ('image', 'thumbnail'): image = self._beacon_data.get('image') if not image: if self._beacon_parent and self._beacon_id: # This is not a good solution, maybe the parent is # not up to date. Well, we have to live with that # for now. Only get image from parent if the item # is scanned because it is a very bad idea that # unscanned images (we do not know that they are # images yet) inherit the image from a directory. image = self._beacon_parent.get('image') if not image: return default if image.startswith('http://'): fname = self._beacon_controller._db.md5url(image, 'images') if key == 'image': if not os.path.isfile(fname): # FIXME: We need to fetch the image. Right now this will not happen # until beacon restarts or a thumbnail is requested return default return fname if key == 'thumbnail': # the thumbnail code will take care of downloading return Thumbnail(image, self._beacon_media) if key == 'image': return image if key == 'thumbnail': return Thumbnail(image, self._beacon_media) if key == 'title': t = self._beacon_data.get('title') if t: return t # generate some title and save local it for future use t = kaa.str_to_unicode(get_title(self._beacon_data['name'], self.isfile)) self._beacon_data['title'] = t return t result = self._beacon_data.get(key, default) if result is None: return default return result
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 _set(self, key, value): """ Set key to value and add the key to the internal keys list if missing. """ if value is None and getattr(self, key, None) is None: return if isinstance(value, str): value = kaa.str_to_unicode(value) setattr(self, key, value) if not key in self._keys: self._keys.append(key)
def parseiptc(app): iptc = {} if app[:14] == "Photoshop 3.0\x00": app = app[14:] # parse the image resource block offset = 0 data = None while app[offset:offset+4] == "8BIM": offset = offset + 4 # resource code code = unpack("<H", app[offset:offset+2])[0] offset = offset + 2 # resource name (usually empty) name_len = ord(app[offset]) name = app[offset+1:offset+1+name_len] offset = 1 + offset + name_len if offset & 1: offset = offset + 1 # resource data block size = unpack("<L", app[offset:offset+4])[0] offset = offset + 4 if code == 0x0404: # 0x0404 contains IPTC/NAA data data = app[offset:offset+size] break offset = offset + size if offset & 1: offset = offset + 1 if not data: return None offset = 0 iptc = {} while 1: try: intro = ord(data[offset]) except (ValueError, KeyError, IndexError): return flatten(iptc) if intro != 0x1c: return flatten(iptc) (tag, record, dataset, length) = unpack("!BBBH", data[offset:offset+5]) val = kaa.str_to_unicode(data[offset+5:offset+length+5]) offset += length + 5 name = c_datasets.get(dataset) if not name: continue if iptc.has_key(name): iptc[name].append(val) else: iptc[name] = [val] return flatten(iptc)
def __xml__(self, root): """ Convert Recording into kaa.xmlutils.Element """ node = root.add_child('recording', id=self.id) for var in ('name', 'channel', 'priority', 'status', 'subtitle', 'fxdname', 'episode', 'description'): if getattr(self, var): node.add_child(var, getattr(self, var)) if self.__url: node.add_child('url', kaa.str_to_unicode(self.__url)) node.add_child('timer', start=_time_int2str(self.start), stop=_time_int2str(self.stop)) node.add_child('padding', start=self.start_padding, stop=self.stop_padding) info = node.add_child('info') for key, value in self.info.items(): info.add_child(key, value) return node
def __init__(self, directory, parent, name = '', type = None): # store type as menu_type and go on handling it as media_type # with tv replaced by video. Only Directory has a difference between # media_type and menu_type with the extra tv value. This is needed # to show a tv based skin when browsing a dir from the tv plugin. self.menu_type = type if type == 'tv': type = 'video' super(Directory, self).__init__(parent=parent, type=type) self.item_menu = None self.set_url(directory) if name: self.name = kaa.str_to_unicode(name) if self['show_all_items']: # FIXME: no way to set this self.media_type = None self._beacon_query = None
def __init__(self, directory, parent, name='', type=None): # store type as menu_type and go on handling it as media_type # with tv replaced by video. Only Directory has a difference between # media_type and menu_type with the extra tv value. This is needed # to show a tv based skin when browsing a dir from the tv plugin. self.menu_type = type if type == 'tv': type = 'video' super(Directory, self).__init__(parent=parent, type=type) self.item_menu = None self.set_url(directory) if name: self.name = kaa.str_to_unicode(name) if self['show_all_items']: # FIXME: no way to set this self.media_type = None self._beacon_query = None self.__description = ''
def set_url(self, url): """ Set a new url to the item and adjust all attributes depending on the url. Each MediaItem has to call this function. """ if not isinstance(url, kaa.beacon.Item): raise RuntimeError('MediaItem.set_url needs a beacon item') self.info = url self.url = url.url if self.url.startswith('file://'): # The url is based on a file. We can search for images # and extra attributes here self.filename = self.url[7:] else: # Mode is not file, it has to be a network url. Other # types like dvd are handled inside the derivated class self.filename = '' if not self.name: self.name = kaa.str_to_unicode(self.url)
def _writexml(self, node): """ Write XML node with feed configuration and cache. """ node.setAttribute('url', self.url) doc = node.ownerDocument d = doc.createElement('directory') for attr in ('download', 'keep'): if getattr(self, '_' + attr): d.setAttribute(attr, 'true') else: d.setAttribute(attr, 'false') d.setAttribute('num', str(self._num)) d.appendChild(doc.createTextNode(self.dirname)) node.appendChild(d) for url, fname in self._entries: e = doc.createElement('entry') e.setAttribute('url', url) if fname: e.setAttribute('filename', kaa.str_to_unicode(fname)) d.appendChild(e)
def match(self, name, channel, start): """ Return True if name, channel and start match this favorite. """ if kaa.str_to_unicode(name.lower()) != self.name.lower() and not self.substring: return False if name.lower().find(self.name.lower()) == -1: return False if not channel in self.channels: return False # convert start time into struct in localtime timetuple = datetime.fromtimestamp(start, kaa.dateutils.local).timetuple() if not int(time.strftime('%w', timetuple)) in self.days: return False stime = int(timetuple[3]) * 100 + int(timetuple[4]) for t in self.times: m = _time_re.match(t).groups() start = int(m[0])*100 + int(m[1]) stop = int(m[2])*100 + int(m[3]) if stime >= start and stime <= stop: return True return False
def set_url(self, url): """ Set a new url to the item and adjust all attributes depending on the url. Each MediaItem has to call this function. """ if not isinstance(url, kaa.beacon.Item): if not url.startswith('http:'): raise RuntimeError('MediaItem.set_url needs a beacon item') self.info = {} self.url = url else: self.info = url self.url = url.url if self.url.startswith('file://'): # The url is based on a file. We can search for images # and extra attributes here self.filename = self.url[7:] else: # Mode is not file, it has to be a network url. Other # types like dvd are handled inside the derivated class self.filename = '' if not self.name: self.name = kaa.str_to_unicode(self.url)
def match(self, name, channel, start): """ Return True if name, channel and start match this favorite. """ if kaa.str_to_unicode( name.lower()) != self.name.lower() and not self.substring: return False if name.lower().find(self.name.lower()) == -1: return False if not channel in self.channels: return False # convert start time into struct in localtime timetuple = datetime.fromtimestamp(start, kaa.dateutils.local).timetuple() if not int(time.strftime('%w', timetuple)) in self.days: return False stime = int(timetuple[3]) * 100 + int(timetuple[4]) for t in self.times: m = _time_re.match(t).groups() start = int(m[0]) * 100 + int(m[1]) stop = int(m[2]) * 100 + int(m[3]) if stime >= start and stime <= stop: return True return False