MythTV master
bliptvXSL_api.py
Go to the documentation of this file.
1# -*- coding: UTF-8 -*-
2
3# ----------------------
4# Name: bliptvXSL_api - XPath and XSLT functions for the Blip.tv 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__ ="bliptvXSL_api - XPath and XSLT functions for the Blip.tv RSS/HTML"
16__author__="R.D. Vaughan"
17__purpose__='''
18This python script is intended to perform a variety of utility functions
19for the conversion of data to the MNV standard RSS output format.
20See this link for the specifications:
21http://www.mythtv.org/wiki/MythNetvision_Grabber_Script_Format
22'''
23
24__version__="v0.1.1"
25# 0.1.0 Initial development
26# 0.1.1 Fixed a bug when an autoplay link cannot be created
27# Added MP4 as an acceptable downloadable video file type
28
29
30# Specify the class names that have XPath extention functions
31__xpathClassList__ = ['xpathFunctions', ]
32
33# Specify the XSLT extention class names. Each class is a stand lone extention function
34#__xsltExtentionList__ = ['xsltExtExample', ]
35__xsltExtentionList__ = []
36
37import os, sys, re, time, datetime, shutil, urllib.request, urllib.parse, urllib.error, string
38from copy import deepcopy
39import io
40
41class OutStreamEncoder(object):
42 """Wraps a stream with an encoder"""
43 def __init__(self, outstream, encoding=None):
44 self.out = outstream
45 if not encoding:
46 self.encoding = sys.getfilesystemencoding()
47 else:
48 self.encoding = encoding
49
50 def write(self, obj):
51 """Wraps the output stream, encoding Unicode strings with the specified encoding"""
52 if isinstance(obj, str):
53 obj = obj.encode(self.encoding)
54 try:
55 self.out.buffer.write(obj)
56 except OSError:
57 pass
58
59
60 def __getattr__(self, attr):
61 """Delegate everything but write to the stream"""
62 return getattr(self.out, attr)
63
64if isinstance(sys.stdout, io.TextIOWrapper):
65 sys.stdout = OutStreamEncoder(sys.stdout, 'utf8')
66 sys.stderr = OutStreamEncoder(sys.stderr, 'utf8')
67
68try:
69 from io import StringIO
70 from lxml import etree
71except Exception as e:
72 sys.stderr.write('\n! Error - Importing the "lxml" and "StringIO" python libraries failed on error(%s)\n' % e)
73 sys.exit(1)
74
75
76class xpathFunctions(object):
77 """Functions specific extending XPath
78 """
79 def __init__(self):
80 self.functList = ['bliptvFlvLinkGeneration', 'bliptvDownloadLinkGeneration', 'bliptvEpisode', 'bliptvIsCustomHTML', ]
81 self.episodeRegex = [
82 re.compile('''TERRA\\ (?P<episodeno>[0-9]+).*$''', re.UNICODE),
83 ]
84 self.namespaces = {
85 'xsi': "http://www.w3.org/2001/XMLSchema-instance",
86 'media': "http://search.yahoo.com/mrss/",
87 'xhtml': "http://www.w3.org/1999/xhtml",
88 'atm': "http://www.w3.org/2005/Atom",
89 'mythtv': "http://www.mythtv.org/wiki/MythNetvision_Grabber_Script_Format",
90 'itunes':"http://www.itunes.com/dtds/podcast-1.0.dtd",
91 'creativeCommons': "http://backend.userland.com/creativeCommonsRssModule",
92 'geo': "http://www.w3.org/2003/01/geo/wgs84_pos#",
93 'blip': "http://blip.tv/dtd/blip/1.0",
94 'wfw': "http://wellformedweb.org/CommentAPI/",
95 'amp': "http://www.adobe.com/amp/1.0",
96 'dcterms': "http://purl.org/dc/terms",
97 'gm': "http://www.google.com/schemas/gm/1.1",
98 'mediaad': "http://blip.tv/dtd/mediaad/1.0",
99 }
100 self.flvFilter = etree.XPath(".//media:content[@type='video/x-flv']", namespaces=self.namespaces)
101 self.m4vFilter = etree.XPath(".//media:content[@type='video/mp4' or @type='video/quicktime' or @type='video/x-m4v']", namespaces=self.namespaces)
102 self.durationFilter = etree.XPath(".//blip:runtime/text()", namespaces=self.namespaces)
103 self.linkFilter = etree.XPath("./link/text()", namespaces=self.namespaces)
104 self.languageFilter = etree.XPath("../language/text()", namespaces=self.namespaces)
105 # end __init__()
106
107
112
113 def bliptvFlvLinkGeneration(self, context, arg):
114 '''Generate a link for the Blip.tv site.
115 Call example: 'mnvXpath:bliptvFlvLinkGeneration(.)'
116 return the url link
117 '''
118 flvFile = self.flvFilter(arg[0])
119 if len(flvFile):
120 flvFileLink = flvFile[0].attrib['url']
121 return '%s%s' % (common.linkWebPage('dummy', 'bliptv'), flvFileLink.replace('.flv', '').replace('http://blip.tv/file/get/', ''))
122 else:
123 return self.linkFilter(arg[0])[0]
124 # end bliptvXSLLinkGeneration()
125
126 def bliptvDownloadLinkGeneration(self, context, arg):
127 '''Generate a download link for the Blip.tv site.
128 Call example: 'mnvXpath:bliptvDownloadLinkGeneration(.)'
129 return an array of one download link element
130 '''
131 downloadLink = etree.XML('<link></link>')
132 flvFile = self.flvFilter(arg[0])
133 m4vFile = self.m4vFilter(arg[0])
134 if len(m4vFile):
135 downloadLink.attrib['url'] = m4vFile[0].attrib['url']
136 if m4vFile[0].attrib.get('width'):
137 downloadLink.attrib['width'] = m4vFile[0].attrib['width']
138 if m4vFile[0].attrib.get('height'):
139 downloadLink.attrib['height'] = m4vFile[0].attrib['height']
140 if m4vFile[0].attrib.get('fileSize'):
141 downloadLink.attrib['length'] = m4vFile[0].attrib['fileSize']
142 if len(self.durationFilter(arg[0])):
143 downloadLink.attrib['duration'] = self.durationFilter(arg[0])[0]
144 downloadLink.attrib['lang'] = self.languageFilter(arg[0])[0]
145 return [downloadLink]
146 elif len(flvFile):
147 downloadLink.attrib['url'] = flvFile[0].attrib['url']
148 if flvFile[0].attrib.get('width'):
149 downloadLink.attrib['width'] = flvFile[0].attrib['width']
150 if flvFile[0].attrib.get('height'):
151 downloadLink.attrib['height'] = flvFile[0].attrib['height']
152 if flvFile[0].attrib.get('fileSize'):
153 downloadLink.attrib['length'] = flvFile[0].attrib['fileSize']
154 if len(self.durationFilter(arg[0])):
155 downloadLink.attrib['duration'] = self.durationFilter(arg[0])[0]
156 downloadLink.attrib['lang'] = self.languageFilter(arg[0])[0]
157 return [downloadLink]
158 else:
159 downloadLink.attrib['url'] = self.linkFilter(arg[0])[0]
160 if len(self.durationFilter(arg[0])):
161 downloadLink.attrib['duration'] = self.durationFilter(arg[0])[0]
162 downloadLink.attrib['lang'] = self.languageFilter(arg[0])[0]
163 return [downloadLink]
164 # end bliptvDownloadLinkGeneration()
165
166 def bliptvEpisode(self, context, arg):
167 '''Parse the title string and extract an episode number
168 Call example: 'mnvXpath:bliptvEpisode(./title/text())'
169 return the url link
170 '''
171 episodeNumber = ''
172 for index in range(len(self.episodeRegex)):
173 match = self.episodeRegex[index].match(arg[0])
174 if match:
175 episodeNumber = match.groups()
176 break
177 return etree.XML('<episode>%s</episode>' % episodeNumber)
178 # end bliptvEpisode()
179
180 def bliptvIsCustomHTML(self, context, arg):
181 '''Parse the item element and deternmine if there is a flv file
182 Call example: 'mnvXpath:bliptvIsCustomHTML(.)'
183 return True is there is a '.flv' file
184 return False if there is no .flv' file
185 '''
186 if len(self.flvFilter(arg[0])):
187 return True
188 return False
189 # end bliptvIsCustomHTML()
190
191
196
197
202
203
def bliptvFlvLinkGeneration(self, context, arg)
Start of XPath extension functions.