MythTV master
revision3XSL_api.py
Go to the documentation of this file.
1# -*- coding: UTF-8 -*-
2
3# ----------------------
4# Name: revision3XSL_api - XPath and XSLT functions for the Revision3 RSS/HTML items
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__ ="revision3XSL_api - XPath and XSLT functions for the www.revision3L.com 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
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
35import os, sys, re, time, datetime, shutil, urllib.request, urllib.parse, urllib.error, string
36from copy import deepcopy
37import io
38
39class 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
61if isinstance(sys.stdout, io.TextIOWrapper):
62 sys.stdout = OutStreamEncoder(sys.stdout, 'utf8')
63 sys.stderr = OutStreamEncoder(sys.stderr, 'utf8')
64
65try:
66 from io import StringIO
67 from lxml import etree
68except 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
73class xpathFunctions(object):
74 """Functions specific extending XPath
75 """
76 def __init__(self):
77 self.functList = ['revision3LinkGeneration', 'revision3Episode', 'revision3checkIfDBItem', ]
78 self.episodeRegex = [
79 re.compile('''^.+?\\-\\-(?P<episodeno>[0-9]+)\\-\\-.*$''', re.UNICODE),
80 ]
81 self.namespaces = {
82 'atom': "http://www.w3.org/2005/Atom",
83 'media': "http://search.yahoo.com/mrss/",
84 'itunes':"http://www.itunes.com/dtds/podcast-1.0.dtd",
85 'xhtml': "http://www.w3.org/1999/xhtml",
86 'mythtv': "http://www.mythtv.org/wiki/MythNetvision_Grabber_Script_Format",
87 'cnettv': "http://cnettv.com/mrss/",
88 'creativeCommons': "http://backend.userland.com/creativeCommonsRssModule",
89 'amp': "http://www.adobe.com/amp/1.0",
90 'content': "http://purl.org/rss/1.0/modules/content/",
91 }
93 [etree.XPath('//object/@id', namespaces=self.namespaces ), None],
94 ]
95 self.FullScreen = 'http://revision3.com/show/popupPlayer?video_id=%s&quality=high&offset=0'
96 self.FullScreenParser = common.parsers['html'].copy()
97 # end __init__()
98
99
104
105 def revision3LinkGeneration(self, context, *arg):
106 '''Generate a link for the video.
107 Call example: 'mnvXpath:revision3LinkGeneration(string(link))'
108 return the url link
109 '''
110 webURL = arg[0]
111 try:
112 tmpHTML = etree.parse(webURL, self.FullScreenParser)
113 except Exception as errmsg:
114 sys.stderr.write("Error reading url(%s) error(%s)\n" % (webURL, errmsg))
115 return webURL
116
117 for index in range(len(self.mediaIdFilters)):
118 mediaId = self.mediaIdFilters[index][0](tmpHTML)
119 if not len(mediaId):
120 continue
121 if self.mediaIdFilters[index][1]:
122 match = self.mediaIdFilters[index][1].match(mediaId[0])
123 if match:
124 videocode = match.groups()
125 return self.FullScreen % (videocode[0])
126 else:
127 return self.FullScreen % (mediaId[0].strip().replace('player-', ''))
128 else:
129 return webURL
130 # end revision3LinkGeneration()
131
132 def revision3Episode(self, context, *arg):
133 '''Parse the download link and extract an episode number
134 Call example: 'mnvXpath:revision3Episode(.)'
135 return the a massaged title element and an episode element in an array
136 '''
137 title = arg[0][0].find('title').text
138 link = arg[0][0].find('enclosure').attrib['url']
139
140 episodeNumber = ''
141 for index in range(len(self.episodeRegex)):
142 match = self.episodeRegex[index].match(link)
143 if match:
144 episodeNumber = int(match.groups()[0])
145 break
146 titleElement = etree.XML("<xml></xml>")
147 etree.SubElement(titleElement, "title").text = 'Ep%03d: %s' % (episodeNumber, title)
148 if episodeNumber:
149 etree.SubElement(titleElement, "episode").text = '%s' % episodeNumber
150 return [titleElement]
151 # end revision3Episode()
152
153 def revision3checkIfDBItem(self, context, arg):
154 '''Use a unique key value pairing to find out if the 'internetcontentarticles' table already
155 has a matching item. This is done to save accessing the Internet when not required.
156 Call example: 'mnvXpath:revision3checkIfDBItem(.)'
157 return True if a match was found
158 return False if a match was not found
159 '''
160 return common.checkIfDBItem('dummy', {'title': self.revision3Episode(context, arg)[0].find('title').text, })
161 # end revision3checkIfDBItem()
162
163
168
169
174
175
def revision3LinkGeneration(self, context, *arg)
Start of XPath extension functions.
static pid_list_t::iterator find(const PIDInfoMap &map, pid_list_t &list, pid_list_t::iterator begin, pid_list_t::iterator end, bool find_open)
MBASE_PUBLIC long long copy(QFile &dst, QFile &src, uint block_size=0)
Copies src file to dst file.