15 __title__ =
"youtubeXSL_api - XPath and XSLT functions for the mashup grabbers"
16 __author__=
"R.D. Vaughan"
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
29 __xpathClassList__ = [
'xpathFunctions', ]
33 __xsltExtentionList__ = []
35 import os, sys, re, time, datetime, shutil, urllib.request, urllib.parse, urllib.error, string
36 from copy
import deepcopy
41 """Wraps a stream with an encoder"""
50 """Wraps the output stream, encoding Unicode strings with the specified encoding"""
51 if isinstance(obj, str):
54 self.
out.buffer.write(obj)
59 """Delegate everything but write to the stream"""
60 return getattr(self.
out, attr)
62 if isinstance(sys.stdout, io.TextIOWrapper):
67 from io
import StringIO
68 from lxml
import etree
69 except Exception
as e:
70 sys.stderr.write(
'\n! Error - Importing the "lxml" and "StringIO" python libraries failed on error(%s)\n' % e)
78 for digit
in etree.LIBXML_VERSION:
79 version+=str(digit)+
'.'
80 version = version[:-1]
83 ! Error - The installed version of the "lxml" python library "libxml" version is too old.
84 At least "libxml" version 2.7.2 must be installed. Your version is (%s).
90 """Functions specific extending XPath
93 self.
functList = [
'youtubeTrailerFilter',
'youtubePaging', ]
96 re.compile(
'''^.+?trailer\\ (?P<trailerNum>[0-9]+).*$''', re.UNICODE),
98 re.compile(
'''^.+?trailer\\ \\#(?P<trailerNum>[0-9]+).*$''', re.UNICODE),
109 '''Generate a list of entry elements that are relevant to the requested search term. Basically
110 remove duplicate and non-relevant search results and order them to provide the best results
112 Also set the paging variables.
113 Call example: 'mnvXpath:youtubeTrailerFilter(//atm:entry)'
114 return the list of relevant "entry" elements
116 searchTerm = common.removePunc(
'dummy', common.searchterm.lower())
117 titleFilter = etree.XPath(
'.//atm:title', namespaces=common.namespaces)
120 if searchTerm.startswith(
'the '):
121 searchTerm = searchTerm[4:].strip()
124 for entry
in args[0]:
125 titleDict[titleFilter(entry)[0].text] = entry
129 for key
in list(titleDict.keys()):
130 title = common.removePunc(
'dummy', key.lower())
131 if title.startswith(
'the '):
132 title = title[4:].strip()
133 if searchTerm.find(
'new ') == -1:
134 title = title.replace(
'new ',
'')
135 if searchTerm.find(
'official ') == -1:
136 title = title.replace(
'official ',
'')
137 if title.find(searchTerm) != -1:
140 if searchTerm.find(
'game ') == -1:
141 if title.find(
'game') != -1:
143 if title.find(
'hd') != -1
or title.find(
'1080p') != -1
or title.find(
'720p') != -1:
145 if title.startswith(searchTerm):
148 match = regexPattern.match(title)
151 trailerNum = match.groups()
152 if int(trailerNum[0]) < 20:
153 addOns+=
'Trailer #%s' % trailerNum[0]
154 title = title.replace((
'trailer %s' % trailerNum[0]),
'')
159 if title.find(
'trailer') != -1:
161 if HD
and not addOns.startswith(
'ZZ-Game'):
166 for text
in [
'hd',
'trailer',
'game',
'1080p',
'720p']:
167 title = title.replace(text,
'').replace(
' ',
' ').strip()
168 filteredDict[(
'%s %s' % (addOns, title)).strip()] = titleDict[key]
172 sortedList = sorted(filteredDict.keys())
173 for index
in range(len(sortedList)):
175 filtered2Dict[sortedList[index]] = deepcopy(filteredDict[sortedList[index]])
177 if sortedList[index] != sortedList[index-1]:
178 filtered2Dict[sortedList[index]] = deepcopy(filteredDict[sortedList[index]])
182 sortedList = sorted(filtered2Dict.keys())
183 for index
in range(len(sortedList)):
184 titleFilter(filtered2Dict[sortedList[index]])[0].text =
'%02d. %s' % (index+1, titleFilter(filtered2Dict[sortedList[index]])[0].text)
185 finalElements.append(filtered2Dict[sortedList[index]])
188 common.numresults = str(len(finalElements))
189 common.returned = common.numresults
190 common.startindex = common.numresults
196 '''Generate a page value specific to the mashup search for YouTube searches
197 Call example: 'mnvXpath:youtubePaging('dummy')'
198 The page value is some times a page # and sometimes an item position number
199 return the page value that will be used in the search as a string
201 return str((int(common.pagenumber) -1) * common.page_limit + 1)