00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015 __title__ ="pbsXSL_api - XPath and XSLT functions for the PBS RSS/HTML"
00016 __author__="R.D. Vaughan"
00017 __purpose__='''
00018 This python script is intended to perform a variety of utility functions
00019 for the conversion of data to the MNV standard RSS output format.
00020 See this link for the specifications:
00021 http://www.mythtv.org/wiki/MythNetvision_Grabber_Script_Format
00022 '''
00023
00024 __version__="v0.1.0"
00025
00026
00027
00028
00029 __xpathClassList__ = ['xpathFunctions', ]
00030
00031
00032
00033 __xsltExtentionList__ = []
00034
00035 import os, sys, re, time, datetime, shutil, urllib, string
00036 from copy import deepcopy
00037
00038
00039 class OutStreamEncoder(object):
00040 """Wraps a stream with an encoder"""
00041 def __init__(self, outstream, encoding=None):
00042 self.out = outstream
00043 if not encoding:
00044 self.encoding = sys.getfilesystemencoding()
00045 else:
00046 self.encoding = encoding
00047
00048 def write(self, obj):
00049 """Wraps the output stream, encoding Unicode strings with the specified encoding"""
00050 if isinstance(obj, unicode):
00051 try:
00052 self.out.write(obj.encode(self.encoding))
00053 except IOError:
00054 pass
00055 else:
00056 try:
00057 self.out.write(obj)
00058 except IOError:
00059 pass
00060
00061 def __getattr__(self, attr):
00062 """Delegate everything but write to the stream"""
00063 return getattr(self.out, attr)
00064 sys.stdout = OutStreamEncoder(sys.stdout, 'utf8')
00065 sys.stderr = OutStreamEncoder(sys.stderr, 'utf8')
00066
00067 try:
00068 from StringIO import StringIO
00069 from lxml import etree
00070 except Exception, e:
00071 sys.stderr.write(u'\n! Error - Importing the "lxml" and "StringIO" python libraries failed on error(%s)\n' % e)
00072 sys.exit(1)
00073
00074
00075
00076
00077
00078 version = ''
00079 for digit in etree.LIBXML_VERSION:
00080 version+=str(digit)+'.'
00081 version = version[:-1]
00082 if version < '2.7.2':
00083 sys.stderr.write(u'''
00084 ! Error - The installed version of the "lxml" python library "libxml" version is too old.
00085 At least "libxml" version 2.7.2 must be installed. Your version is (%s).
00086 ''' % version)
00087 sys.exit(1)
00088
00089
00090 class xpathFunctions(object):
00091 """Functions specific extending XPath
00092 """
00093 def __init__(self):
00094 self.functList = ['pbsTitleSeriesEpisodeLink', 'pbsDuration', 'pbsDownloadlink']
00095 self.seriesEpisodeRegex = [
00096
00097 re.compile(u'''^.+?Season\\ (?P<seasno>[0-9]+)\\:\\ Episode\\ (?P<epno>[0-9]+).*$''', re.UNICODE),
00098
00099 re.compile(u'''^.+?Season\\ (?P<seasno>[0-9]+)\\,\\ Episode\\ (?P<epno>[0-9]+).*$''', re.UNICODE),
00100
00101 re.compile(u'''^.+?Episode\\ (?P<epno>[0-9]+).*$''', re.UNICODE),
00102 ]
00103 self.namespaces = {
00104 'media': u"http://search.yahoo.com/mrss/",
00105 'xhtml': u"http://www.w3.org/1999/xhtml",
00106 'mythtv': "http://www.mythtv.org/wiki/MythNetvision_Grabber_Script_Format",
00107 'mediaad': "http://PBS/dtd/mediaad/1.0",
00108 }
00109 self.persistence = {}
00110
00111
00112
00113
00114
00115
00116
00117
00118 def pbsTitleSeriesEpisodeLink(self, context, *arg):
00119 '''Generate a link for the PBS site.
00120 Call example: 'mnvXpath:pbsTitleSeriesEpisodeLink(normalize-space(./title),normalize-space(./link))/*'
00121 return the title, link and season and episode number elements if any were in the title
00122 '''
00123 tmpTitle = arg[0]
00124 tmpLink = arg[1]
00125
00126
00127 tmpVideoCode = tmpLink.replace(u'http://video.pbs.org/video/', u'')[:-1]
00128 self.persistence[tmpLink] = common.linkWebPage('dummy', 'pbs')
00129
00130
00131 seasonNumber = None
00132 episodeNumber = None
00133 for index in range(len(self.seriesEpisodeRegex)):
00134 match = self.seriesEpisodeRegex[index].match(tmpTitle)
00135 if match:
00136 if index < 2:
00137 (seasonNumber, episodeNumber) = match.groups()
00138 break
00139 else:
00140 episodeNumber = match.groups()[0]
00141 break
00142
00143
00144 index = tmpTitle.rfind('|')
00145 if index != -1:
00146 tmpTitle = tmpTitle[index+1:].strip()
00147 if seasonNumber and episodeNumber:
00148 tmpTitle = u'S%02dE%02d: %s' % (int(seasonNumber), int(episodeNumber), tmpTitle)
00149 elif episodeNumber:
00150 index = tmpTitle.find(':')
00151 if index != -1:
00152 tmpTitle = tmpTitle[index+1:].strip()
00153 tmpTitle = u'Ep%02d: %s' % (int(episodeNumber), tmpTitle)
00154 self.persistence[tmpLink] = common.linkWebPage('dummy', 'pbs').replace(u'TITLE', urllib.quote(tmpTitle)).replace(u'VIDEOCODE', tmpVideoCode)
00155
00156
00157 elementTmp = etree.XML('<xml></xml>')
00158 etree.SubElement(elementTmp, "title").text = tmpTitle
00159 if seasonNumber:
00160 etree.SubElement(elementTmp, "season").text = u"%s" % int(seasonNumber)
00161 if episodeNumber:
00162 etree.SubElement(elementTmp, "episode").text = u"%s" % int(episodeNumber)
00163 etree.SubElement(elementTmp, "link").text = self.persistence[tmpLink]
00164 return elementTmp
00165
00166
00167 def pbsDuration(self, context, *arg):
00168 '''Return the video duration in seconds
00169 Call example: 'mnvXpath:pbsDuration(normalize-string(./dd/p[@class="info"]/span[@class="time"]))'
00170 return the video duration
00171 '''
00172 if not arg[0]:
00173 return u''
00174 return arg[0][:-3]
00175
00176
00177 def pbsDownloadlink(self, context, *arg):
00178 '''Return a previously created download link
00179 Call example: 'mnvXpath:pbsDownloadlink(normalize-space(./link))'
00180 return the url link
00181 '''
00182 downloadLink = self.persistence[arg[0]]
00183 del self.persistence[arg[0]]
00184 return downloadLink
00185
00186
00187
00188
00189
00190
00191
00192
00193
00194
00195
00196
00197
00198
00199
00200
00201
00202
00203