MythTV  master
pbsXSL_api.py
Go to the documentation of this file.
1 # -*- coding: UTF-8 -*-
2 
3 # ----------------------
4 # Name: pbsXSL_api - XPath and XSLT functions for the PBS RSS/HTML itmes
5 # Python Script
6 # Author: R.D. Vaughan
7 # Purpose: This python script is intended to perform a variety of utility functions
8 # for the conversion of data to the MNV standard RSS output format.
9 # See this link for the specifications:
10 # http://www.mythtv.org/wiki/MythNetvision_Grabber_Script_Format
11 #
12 # License:Creative Commons GNU GPL v2
13 # (http://creativecommons.org/licenses/GPL/2.0/)
14 #-------------------------------------
15 __title__ ="pbsXSL_api - XPath and XSLT functions for the PBS RSS/HTML"
16 __author__="R.D. Vaughan"
17 __purpose__='''
18 This python script is intended to perform a variety of utility functions
19 for the conversion of data to the MNV standard RSS output format.
20 See this link for the specifications:
21 http://www.mythtv.org/wiki/MythNetvision_Grabber_Script_Format
22 '''
23 
24 __version__="v0.1.0"
25 # 0.1.0 Initial development
26 
27 
28 # Specify the class names that have XPath extention functions
29 __xpathClassList__ = ['xpathFunctions', ]
30 
31 # Specify the XSLT extention class names. Each class is a stand lone extention function
32 #__xsltExtentionList__ = ['xsltExtExample', ]
33 __xsltExtentionList__ = []
34 
35 import os, sys, re, time, datetime, shutil, urllib.request, urllib.parse, urllib.error, string
36 from copy import deepcopy
37 
38 
39 class OutStreamEncoder(object):
40  """Wraps a stream with an encoder"""
41  def __init__(self, outstream, encoding=None):
42  self.out = outstream
43  if not encoding:
44  self.encoding = sys.getfilesystemencoding()
45  else:
46  self.encoding = encoding
47 
48  def write(self, obj):
49  """Wraps the output stream, encoding Unicode strings with the specified encoding"""
50  if isinstance(obj, str):
51  obj = obj.encode(self.encoding)
52  try:
53  self.out.buffer.write(obj)
54  except OSError:
55  pass
56 
57  def __getattr__(self, attr):
58  """Delegate everything but write to the stream"""
59  return getattr(self.out, attr)
60 
61 if isinstance(sys.stdout, io.TextIOWrapper):
62  sys.stdout = OutStreamEncoder(sys.stdout, 'utf8')
63  sys.stderr = OutStreamEncoder(sys.stderr, 'utf8')
64 
65 try:
66  from io import StringIO
67  from lxml import etree
68 except Exception as e:
69  sys.stderr.write('\n! Error - Importing the "lxml" and "StringIO" python libraries failed on error(%s)\n' % e)
70  sys.exit(1)
71 
72 # Check that the lxml library is current enough
73 # From the lxml documents it states: (http://codespeak.net/lxml/installation.html)
74 # "If you want to use XPath, do not use libxml2 2.6.27. We recommend libxml2 2.7.2 or later"
75 # Testing was performed with the Ubuntu 9.10 "python-lxml" version "2.1.5-1ubuntu2" repository package
76 version = ''
77 for digit in etree.LIBXML_VERSION:
78  version+=str(digit)+'.'
79 version = version[:-1]
80 if version < '2.7.2':
81  sys.stderr.write('''
82 ! Error - The installed version of the "lxml" python library "libxml" version is too old.
83  At least "libxml" version 2.7.2 must be installed. Your version is (%s).
84 ''' % version)
85  sys.exit(1)
86 
87 
88 class xpathFunctions(object):
89  """Functions specific extending XPath
90  """
91  def __init__(self):
92  self.functList = ['pbsTitleSeriesEpisodeLink', 'pbsDuration', 'pbsDownloadlink']
94  # Season 8: Episode 1
95  re.compile('''^.+?Season\\ (?P<seasno>[0-9]+)\\:\\ Episode\\ (?P<epno>[0-9]+).*$''', re.UNICODE),
96  # Season 8, Episode 1
97  re.compile('''^.+?Season\\ (?P<seasno>[0-9]+)\\,\\ Episode\\ (?P<epno>[0-9]+).*$''', re.UNICODE),
98  # Episode 1:
99  re.compile('''^.+?Episode\\ (?P<epno>[0-9]+).*$''', re.UNICODE),
100  ]
101  self.namespaces = {
102  'media': "http://search.yahoo.com/mrss/",
103  'xhtml': "http://www.w3.org/1999/xhtml",
104  'mythtv': "http://www.mythtv.org/wiki/MythNetvision_Grabber_Script_Format",
105  'mediaad': "http://PBS/dtd/mediaad/1.0",
106  }
107  self.persistence = {}
108  # end __init__()
109 
110 
115 
116  def pbsTitleSeriesEpisodeLink(self, context, *arg):
117  '''Generate a link for the PBS site.
118  Call example: 'mnvXpath:pbsTitleSeriesEpisodeLink(normalize-space(./title),normalize-space(./link))/*'
119  return the title, link and season and episode number elements if any were in the title
120  '''
121  tmpTitle = arg[0]
122  tmpLink = arg[1]
123 
124  # Set the custom HTML PBS link
125  tmpVideoCode = tmpLink.replace('http://video.pbs.org/video/', '')[:-1]
126  self.persistence[tmpLink] = common.linkWebPage('dummy', 'pbs')
127 
128  # Parse out any Season
129  seasonNumber = None
130  episodeNumber = None
131  for index in range(len(self.seriesEpisodeRegex)):
132  match = self.seriesEpisodeRegex[index].match(tmpTitle)
133  if match:
134  if index < 2:
135  (seasonNumber, episodeNumber) = match.groups()
136  break
137  else:
138  episodeNumber = match.groups()[0]
139  break
140 
141  # Massage video title
142  index = tmpTitle.rfind('|')
143  if index != -1:
144  tmpTitle = tmpTitle[index+1:].strip()
145  if seasonNumber and episodeNumber:
146  tmpTitle = 'S%02dE%02d: %s' % (int(seasonNumber), int(episodeNumber), tmpTitle)
147  elif episodeNumber:
148  index = tmpTitle.find(':')
149  if index != -1:
150  tmpTitle = tmpTitle[index+1:].strip()
151  tmpTitle = 'Ep%02d: %s' % (int(episodeNumber), tmpTitle)
152  self.persistence[tmpLink] = common.linkWebPage('dummy', 'pbs').replace('TITLE', urllib.parse.quote(tmpTitle)).replace('VIDEOCODE', tmpVideoCode)
153 
154  # Make the elements to include in the item
155  elementTmp = etree.XML('<xml></xml>')
156  etree.SubElement(elementTmp, "title").text = tmpTitle
157  if seasonNumber:
158  etree.SubElement(elementTmp, "season").text = "%s" % int(seasonNumber)
159  if episodeNumber:
160  etree.SubElement(elementTmp, "episode").text = "%s" % int(episodeNumber)
161  etree.SubElement(elementTmp, "link").text = self.persistence[tmpLink]
162  return elementTmp
163  # end pbsTitleSeriesEpisodeLink()
164 
165  def pbsDuration(self, context, *arg):
166  '''Return the video duration in seconds
167  Call example: 'mnvXpath:pbsDuration(normalize-string(./dd/p[@class="info"]/span[@class="time"]))'
168  return the video duration
169  '''
170  if not arg[0]:
171  return ''
172  return arg[0][:-3]
173  # end pbsDuration()
174 
175  def pbsDownloadlink(self, context, *arg):
176  '''Return a previously created download link
177  Call example: 'mnvXpath:pbsDownloadlink(normalize-space(./link))'
178  return the url link
179  '''
180  downloadLink = self.persistence[arg[0]]
181  del self.persistence[arg[0]]
182  return downloadLink
183  # end pbsDownloadlink()
184 
185 
190 
191 
196 
197 
nv_python_libs.xsltfunctions.pbsXSL_api.OutStreamEncoder.out
out
Definition: pbsXSL_api.py:42
nv_python_libs.xsltfunctions.pbsXSL_api.xpathFunctions.pbsTitleSeriesEpisodeLink
def pbsTitleSeriesEpisodeLink(self, context, *arg)
Start of XPath extension functions.
Definition: pbsXSL_api.py:116
nv_python_libs.xsltfunctions.pbsXSL_api.xpathFunctions.seriesEpisodeRegex
seriesEpisodeRegex
Definition: pbsXSL_api.py:93
nv_python_libs.xsltfunctions.pbsXSL_api.xpathFunctions
Definition: pbsXSL_api.py:88
nv_python_libs.xsltfunctions.pbsXSL_api.OutStreamEncoder.__getattr__
def __getattr__(self, attr)
Definition: pbsXSL_api.py:57
nv_python_libs.xsltfunctions.pbsXSL_api.OutStreamEncoder
Definition: pbsXSL_api.py:39
nv_python_libs.xsltfunctions.pbsXSL_api.xpathFunctions.namespaces
namespaces
Definition: pbsXSL_api.py:101
nv_python_libs.xsltfunctions.pbsXSL_api.OutStreamEncoder.__init__
def __init__(self, outstream, encoding=None)
Definition: pbsXSL_api.py:41
nv_python_libs.xsltfunctions.pbsXSL_api.xpathFunctions.persistence
persistence
Definition: pbsXSL_api.py:107
nv_python_libs.xsltfunctions.pbsXSL_api.xpathFunctions.pbsDuration
def pbsDuration(self, context, *arg)
Definition: pbsXSL_api.py:165
nv_python_libs.xsltfunctions.pbsXSL_api.xpathFunctions.pbsDownloadlink
def pbsDownloadlink(self, context, *arg)
Definition: pbsXSL_api.py:175
nv_python_libs.xsltfunctions.pbsXSL_api.xpathFunctions.__init__
def __init__(self)
Definition: pbsXSL_api.py:91
nv_python_libs.xsltfunctions.pbsXSL_api.OutStreamEncoder.write
def write(self, obj)
Definition: pbsXSL_api.py:48
nv_python_libs.xsltfunctions.pbsXSL_api.xpathFunctions.functList
functList
Definition: pbsXSL_api.py:92
nv_python_libs.xsltfunctions.pbsXSL_api.OutStreamEncoder.encoding
encoding
Definition: pbsXSL_api.py:44