# # xmltv.py - Python interface to XMLTV format, based on XMLTV.pm # # Copyright (C) 2001 James Oakley # # This library is free software; you can redistribute it and/or # modify it under the terms of the GNU Lesser General Public # License as published by the Free Software Foundation; either # version 2.1 of the License, or (at your option) any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU # Lesser General Public License for more details. # # You should have received a copy of the GNU Lesser General Public # License along with this program; if not, write to the Free Software # Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA # # Notes: # - Uses qp_xml instead of DOM. It's way faster # - Read and write functions use file objects instead of filenames # - Unicode is removed on dictionary keys because the xmlrpclib marshaller # chokes on it. It'll always be Latin-1 anyway... (famous last words) # # Yes, A lot of this is quite different than the Perl module, mainly to keep # it Pythonic # # If you have any trouble: jfunk@funktronics.ca # # Changes for Freevo: # o change data_format to '%Y%m%d%H%M%S %Z' # o change encode to use 'ignore' as error: # string.encode(locale) -> string.encode(locale, 'ignore') # o add except AttributeError: for unhandled elements (line 250ff) # o import config and change locale = config.LOCALE from locale import getdefaultlocale from xml.utils import qp_xml from xml.sax import saxutils import string, types, re # The Python-XMLTV version VERSION = "0.5.15" # The date format used in XMLTV date_format = '%Y%m%d%H%M%S %Z' # Note: Upstream xmltv.py uses %z so remember to change that when syncing date_format_notz = '%Y%m%d%H%M%S' # These characters are illegal in XML XML_BADCHARS = re.compile(u'[^\x09\x0A\x0D\x20-\uD7FF\uE000-\uFFFD\u10000-\u10FFFF]') # # Options. They may be overridden after this module is imported # # The locale for dictionary keys. Leaving them in Unicode screws up the # XMLRPC marshaller _, locale = getdefaultlocale() # The extraction process could be simpler, building a tree recursively # without caring about the element names, but it's done this way to allow # special handling for certain elements. If 'desc' changed one day then # ProgrammeHandler.desc() can be modified to reflect it class _ProgrammeHandler: """ Handles XMLTV programme elements """ # # sub-tags # def title(self, node): return _readwithlang(node) def sub_title(self, node): return _readwithlang(node) def desc(self, node): return _readwithlang(node) def credits(self, node): return _extractNodes(node, self) def date(self, node): return node.textof() def category(self, node): return _readwithlang(node) def language(self, node): return _readwithlang(node) def orig_language(self, node): return _readwithlang(node) def length(self, node): data = {} data['units'] = _getxmlattr(node, u'units') try: length = int(node.textof()) except ValueError: pass data['length'] = length return data def icon(self, node): data = {} for attr in (u'src', u'width', u'height'): if node.attrs.has_key(('', attr)): data[attr.encode(locale, 'ignore')] = _getxmlattr(node, attr) return data def url(self, node): return node.textof() def country(self, node): return _readwithlang(node) def episode_num(self, node): system = _getxmlattr(node, u'system') if system == '': system = 'onscreen' return (node.textof(), system) def video(self, node): result = {} for child in node.children: result[child.name.encode(locale, 'ignore')] = self._call(child) return result def audio(self, node): result = {} for child in node.children: result[child.name.encode(locale, 'ignore')] = self._call(child) return result def previously_shown(self, node): data = {} for attr in (u'start', u'channel'): if node.attrs.has_key(('', attr)): data[attr.encode(locale, 'ignore')] = node.attrs[('', attr)] return data def premiere(self, node): return _readwithlang(node) def last_chance(self, node): return _readwithlang(node) def new(self, node): return 1 def subtitles(self, node): data = {} if node.attrs.has_key(('', u'type')): data['type'] = _getxmlattr(node, u'type') for child in node.children: if child.name == u'language': data['language'] = _readwithlang(child) return data def rating(self, node): data = {} data['icon'] = [] if node.attrs.has_key(('', u'system')): data['system'] = node.attrs[('', u'system')] for child in node.children: if child.name == u'value': data['value'] = child.textof() elif child.name == u'icon': data['icon'].append(self.icon(child)) if len(data['icon']) == 0: del data['icon'] return data def star_rating(self, node): data = {} data['icon'] = [] for child in node.children: if child.name == u'value': data['value'] = child.textof() elif child.name == u'icon': data['icon'].append(self.icon(child)) if len(data['icon']) == 0: del data['icon'] return data # # sub-tags # def actor(self, node): return node.textof() def director(self, node): return node.textof() def writer(self, node): return node.textof() def adapter(self, node): return node.textof() def producer(self, node): return node.textof() def presenter(self, node): return node.textof() def commentator(self, node): return node.textof() def guest(self, node): return node.textof() # #