MythTV master
mevio_api.py
Go to the documentation of this file.
1# -*- coding: UTF-8 -*-
2
3# ----------------------
4# Name: mevio_api - XPath and XSLT functions for the Mevio 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__ ="mevio_api - XPath and XSLT functions for the www.mevio.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# 0.1.1 Fixed a bug when an autoplay link cannot be created
27# Added MP4 as an acceptable downloadable video file type
28# Added checking to see if the item is already in the data base
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 def __getattr__(self, attr):
60 """Delegate everything but write to the stream"""
61 return getattr(self.out, attr)
62
63if isinstance(sys.stdout, io.TextIOWrapper):
64 sys.stdout = OutStreamEncoder(sys.stdout, 'utf8')
65 sys.stderr = OutStreamEncoder(sys.stderr, 'utf8')
66
67try:
68 from io import StringIO
69 from lxml import etree
70except Exception as e:
71 sys.stderr.write('\n! Error - Importing the "lxml" and "StringIO" python libraries failed on error(%s)\n' % e)
72 sys.exit(1)
73
74
75class xpathFunctions(object):
76 """Functions specific extending XPath
77 """
78 def __init__(self):
79 self.functList = ['mevioLinkGeneration', 'mevioTitle', 'mevioEpisode', 'mevioCheckIfDBItem', ]
80 self.episodeRegex = [
81 # Episode 224
82 re.compile('''^.+?Episode\\ (?P<episodeno>[0-9]+).*$''', re.UNICODE),
83 # CrankyGeeks 136:
84 re.compile('''^.+?(?P<episodeno>[0-9]+)\\:.*$''', re.UNICODE),
85 ]
86 self.namespaces = {
87 'atom10': "http://www.w3.org/2005/Atom",
88 'media': "http://search.yahoo.com/mrss/",
89 'itunes':"http://www.itunes.com/dtds/podcast-1.0.dtd",
90 'xhtml': "http://www.w3.org/1999/xhtml",
91 'feedburner': "http://rssnamespace.org/feedburner/ext/1.0",
92 'mythtv': "http://www.mythtv.org/wiki/MythNetvision_Grabber_Script_Format",
93 'dc': "http://purl.org/dc/elements/1.1/",
94 'fb': "http://www.facebook.com/2008/fbml/",
95 }
97 [etree.XPath(".//embed/@flashvars", namespaces=self.namespaces), re.compile('''^.+?MediaId=(?P<videocode>[0-9]+).*$''', re.UNICODE)],
98 [etree.XPath(".//div[@class='player_wrapper']/a/@href", namespaces=self.namespaces), re.compile('''^.+?\\'(?P<videocode>[0-9]+)\\'\\)\\;.*$''', re.UNICODE)]
99 ]
100 # end __init__()
101
102
107
108 def mevioLinkGeneration(self, context, *arg):
109 '''Generate a link for the video.
110 Call example: 'mnvXpath:mevioLinkGeneration(string(link))'
111 return the url link
112 '''
113 webURL = arg[0]
114 try:
115 tmpHTML = etree.parse(webURL, etree.HTMLParser())
116 except Exception as errmsg:
117 sys.stderr.write("Error reading url(%s) error(%s)\n" % (webURL, errmsg))
118 return webURL
119
120 for index in range(len(self.mediaIdFilters)):
121 mediaId = self.mediaIdFilters[index][0](tmpHTML)
122 if not len(mediaId):
123 continue
124 match = self.mediaIdFilters[index][1].match(mediaId[0])
125 if match:
126 videocode = match.groups()
127 return 'file://%s/nv_python_libs/configs/HTML/mevio.html?videocode=%s' % (common.baseProcessingDir, videocode[0])
128 else:
129 return webURL
130 # end mevioLinkGeneration()
131
132 def mevioTitle(self, context, arg):
133 '''Parse the title string extract only the title text removing the redundant show name
134 Call example: 'mnvXpath:mevioTitle(./title/text())'
135 return the title text
136 '''
137 epText = self.mevioEpisode('dummy', arg).text
138 if epText:
139 epText = 'Ep %s: ' % epText
140 else:
141 epText = ''
142 seperatorStrs = [[' | ', 'before'], [': ', 'after'], [' - ', 'before']]
143 for sepStr in seperatorStrs:
144 if sepStr[1] == 'after':
145 index = arg[0].find(sepStr[0])
146 else:
147 index = arg[0].rfind(sepStr[0])
148 if index != -1:
149 if sepStr[1] == 'after':
150 return '%s%s' % (epText, arg[0][index+len(sepStr[0]):].strip())
151 else:
152 return '%s%s' % (epText, arg[0][:index].strip())
153 else:
154 if epText:
155 return epText
156 else:
157 return arg[0].strip()
158 # end mevioTitle()
159
160 def mevioEpisode(self, context, arg):
161 '''Parse the title string and extract an episode number
162 Call example: 'mnvXpath:mevioEpisode(./title/text())'
163 return an episode element
164 '''
165 episodeNumber = ''
166 for index in range(len(self.episodeRegex)):
167 match = self.episodeRegex[index].match(arg[0])
168 if match:
169 episodeNumber = match.groups()
170 break
171 return etree.XML('<episode>%s</episode>' % episodeNumber)
172 # end mevioEpisode()
173
174 def mevioCheckIfDBItem(self, context, *arg):
175 '''Use a unique key value pairing to find out if the 'internetcontentarticles' table already
176 has a matching item. This is done to save accessing the Internet when not required.
177 Call example: 'mnvXpath:mevioCheckIfDBItem(title, description)'
178 return True if a match was found
179 return False if a match was not found
180 '''
181 return common.checkIfDBItem('dummy', {'feedtitle': 'Technology', 'title': arg[0], 'description': arg[1]})
182 # end mevioCheckIfDBItem()
183
184
189
190
195
196
def __init__(self, outstream, encoding=None)
Definition: mevio_api.py:43
def mevioLinkGeneration(self, context, *arg)
Start of XPath extension functions.
Definition: mevio_api.py:108
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)