--[[
RSS READER Plugin
Copyright (C) 2014-2021, Jacek Jendrzej 'satbaby'
License: GPL
This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public
License as published by the Free Software Foundation; either
version 2 of the License, or (at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
General Public License for more details.
You should have received a copy of the GNU General Public
License along with this program; if not, write to the
Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
Boston, MA 02110-1301, USA.
]]
--dependencies: feedparser http://feedparser.luaforge.net/ ,libexpat, lua-expat
rssReaderVersion="Lua RSS READER v1.09 by satbaby"
local CONF_PATH = "/var/tuxbox/config/"
if DIR and DIR.CONFIGDIR then
CONF_PATH = DIR.CONFIGDIR .. '/'
end
revision = 0
youtube_dev_id = nil
feedentries = {}
local n = neutrino()
local fh = filehelpers.new()
local FontMenu = FONT.MENU
local FontTitle = FONT.MENU_TITLE
local glob = {}
local conf = {}
local S_Key = {fav_setup=1,fav=2,setup=3}
local P_Key = {btnOk=1,btnRed=2,btnPlay=3}
local addon = nil
local nothing,hva,hvb,hvc,hve,hvf="nichts",nil,nil,nil,nil,"reader"
local picdir = "/tmp/rssPics"
local vPlay = nil
local epgtext = nil
local epgtitle = nil
local LinksBrowser = "/links.so"
locale = {}
locale["english"] = {
picdir = "Picture directory: ",
picdirhint = "In which directory should images be saved ?",
bindirhint = "In which directory are HTML viewer ?",
addonsdir = "Addons directory: ",
addonsdirhint = "In which directory are rss addons ?",
linksbrowserdir = "Links Browser directory: ",
linksbrowserdirhint = "In which directory are links browser ?",
htmlviewer = "Browser selection",
htmlviewerhint = "Browser or HTML viewer selection",
set_key = "Select Settings Key",
set_key_hint = "Set key for Settings",
fav_and_setup_key = "Fav and Setup",
fav_key = "Fav",
setup_key = "Setup",
curlTimeout= "Connect Timeout",
curlTimeouthint = "Internet connect timeout (min/max) 1...99 seconds",
maxRes = "Max. Resolution",
maxReshint = "Max. Video Resolution",
mt_ard = "Generate ARD Media Library List",
mt_zdf = "Generate ZDF Media Library List",
mt_hint = "The list is only loaded after rss restart",
dldir = "Path for Downloads:",
dlhint = "In which directory should videos be saved ?",
set_keyp = "Select Settings Play",
set_keyp_hint = "Set key for Play",
set_keyp_ok = "OK",
set_keyp_red = "Red",
set_keyp_play = "Play"
}
locale["deutsch"] = {
picdir = "Bildverzeichnis: ",
picdirhint = "In welchem Verzeichnis sollen die Bilder gespeichert werden ?",
bindirhint = "In welchem Verzeichnis befinden sich HTML viewer ?",
addonsdir = "Addons Verzeichnis: ",
addonsdirhint = "In welchem Verzeichnis befinden sich rss addons ?",
linksbrowserdir = "Links Browser Verzeichnis: ",
linksbrowserdirhint = "In welchem Verzeichnis befindet sich Links Browser ?",
htmlviewer = "Browser Auswahl",
htmlviewerhint = "Browser oder HTML viewer Auswahl",
set_key = "Einstellungen Taste",
set_key_hint = "Taste für Einstellungen",
fav_and_setup_key = "Fav und Setup",
fav_key = "Fav",
setup_key ="Setup",
curlTimeout="Zeitüberschreitung der Internetverbindung nach",
curlTimeouthint="Zeitüberschreitung der Internetverbindung (min/max) 1...99 sekunden",
maxRes = "Max. Auflösung",
maxReshint = "Max. Auflösung für Video",
mt_ard = "Generiere ARD Mediathek Liste",
mt_zdf = "Generiere ZDF Mediathek Liste",
mt_hint = "Die Liste wird erst nach rss neustart geladen",
dldir= "Pfad für Downloads:",
dlhint = "In welchem Verzeichnis sollen die Videos gespeichert werden ?",
set_keyp = "Play Taste",
set_keyp_hint = "Taste für Play",
set_keyp_ok = "OK",
set_keyp_red = "Rot",
set_keyp_play = "Play"
}
locale["polski"] = {
picdir = "folder dla zdjęć: ",
picdirhint = "W którym folderze zdjęcia (pics) mają być zapisane ?",
bindirhint = "W którym folderze znajduje się przeglądarka HTML?",
addonsdir = "Addons folder: ",
addonsdirhint = "W którym folderze znajdują się rss addons ?",
linksbrowserdir = "Links Browser folder: ",
linksbrowserdirhint = "W którym folderze znajduje się Links Browser ?",
htmlviewer = "Browser wybór",
htmlviewerhint = "Browser albo HTML viewer wybór",
set_key = "Wybierz Klawisz dla ustawień",
set_key_hint = "Wybór klawisza dla tego menu",
fav_and_setup_key = "Fav i Setup",
fav_key = "Fav",
setup_key ="Setup",
curlTimeout="Limit czasu połączenia z Internetem",
curlTimeouthint="Limit czasu połączenia z Internetem (min/max) 1...99 sekund",
maxRes = "Max. rozdzielczość",
maxReshint = "Maksymalna rozdzielczość dla Video",
mt_ard = "Generowanie listy bibliotek ARD Media",
mt_zdf = "Generowanie listy bibliotek ZDF Media",
mt_hint = "Lista jest ładowana dopiero po restarcie rss",
dldir = "folder dla downloads:",
dlhint = "W którym folderze downloads mają być zapisane ?",
set_keyp = "Wybierz Klawisz dla Play",
set_keyp_hint = "Wybór klawisza dla Play",
set_keyp_ok = "OK",
set_keyp_red = "Czerwony",
set_keyp_play = "Play"
}
function get_confFile()
return CONF_PATH .. "rss.conf"
end
function __LINE__() return debug.getinfo(2, 'l').currentline end
function toUcode(s)
s=s:gsub("&","&")
s=s:gsub("'","'")
s=s:gsub("<","<")
s=s:gsub(">",">")
s=s:gsub('"',""")
s=s:gsub("\x0a","
")
s=s:gsub("\x0d","
")
return s
end
function writeXML(ch, title, info1, info2, filename)
ch = ch or ""
title = title or ""
info1 = info1 or ""
info2 = info2 or ""
local xml='\
\
\
\
' .. ch .. '\
' .. toUcode(title) .. '\
0\
' .. toUcode(info1) .. '\
' .. info2 .. '\
0\
1\
0\
1\
\
\
\
0\
0\
0\
\
0\
\
0\
0\
0\
0\
0\
\
0\
0\
0\
\
\
\
\n'
local file = io.open(filename,'w')
file:write(xml)
file:close()
end
function dl_stream(dl)
local Format = nil
if dl and dl.streamUrl then
if dl.streamUrl:sub(-4) == ".mp4" then
Format = 'mp4'
elseif dl.streamUrl:find("m3u8") then
Format = 'ts'
elseif dl.streamUrl:find("googlevideo.com/videoplaybac") then
Format = 'mkv'
local itag = dl.streamUrl:match('itag=(%d+)') or dl.streamUrl:match('itag%%3D(%d+)')
if itag then
local inr = tonumber(itag)
if inr == 315 or inr == 308 or inr == 303 or inr == 302 or inr == 313
or inr == 271 or inr == 248 or inr == 247 or inr == 244 then
Format = 'mkv'
else
Format = 'ts'
end
end
end
local dlname = nil
if dl.ch and dl.name and dl.date and dl.info1 then
dlname = dl.ch .. "_" .. dl.name .. "_" .. dl.info1 .. "_" .. dl.date
dlname = dlname:gsub("[%p%s/]", "_")
end
if dlname and Format then
local dls = "/tmp/.rss_dl.sh"
local filenamexml = "/tmp/.rss_dl_xml"
writeXML(dl.ch, dl.name, dl.info1, dl.info2, filenamexml)
dlname = conf.dlPath .. "/" .. dlname
local script=io.open(dls,"w")
script:write('echo "download start" ;\n')
if Format == 'mp4' then
script:write('wget -q --continue ' .. dl.streamUrl .. ' -O ' .. dlname .. '.mp4 ;\n')
elseif Format == 'ts' or Format == 'mkv' then
if dl.streamUrl2 then
script:write("ffmpeg -y -nostdin -loglevel 30 -i '" .. dl.streamUrl .. "' -i '" .. dl.streamUrl2 .. "' -c copy " .. dlname .. "." .. Format .. "\n")
else
script:write("ffmpeg -y -nostdin -loglevel 30 -i '" .. dl.streamUrl .. "' -c copy " .. dlname .. "." .. Format .. "\n")
end
end
script:write('if [ $? -eq 0 ]; then \n')
script:write('wget -q http://127.0.0.1/control/message?popup="Video ' .. dl.name .. ' wurde heruntergeladen." -O /dev/null ; \n')
script:write('mv ' .. filenamexml .. ' ' .. dlname .. '.xml ; \n')
script:write('else \n')
script:write('wget -q http://127.0.0.1/control/message?popup="Download ' .. dl.name .. ' FEHLGESCHLAGEN" -O /dev/null ; \n')
script:write('rm ' .. filenamexml .. ' ; \n')
script:write('fi \n')
script:write('rm ' .. dls .. '; \n')
script:close()
os.execute('sh ' .. dls .. ' &')
return true
end
end
return false
end
function dl_check(streamUrl)
local check = false
local dl_not_possible = conf.dlPath == '/tmp' or conf.dlPath == '/'
if dl_not_possible then return check end
if fh:exist('/tmp/.rss_dl.sh', 'f') then return check end
if streamUrl:sub(-4) == ".mp4" then
check = true
elseif glob.have_ffmpeg and (streamUrl:find('m3u8') or streamUrl:find("googlevideo.com/videoplaybac")) then
check = true
end
return check
end
function gen_dl(streamUrl,streamUrl2,title,info1,idNr)
local dl = {}
dl.name = title
dl.streamUrl = streamUrl
dl.streamUrl2 = streamUrl2
dl.info1 = ''
dl.ch = ''
dl.date = ''
if info1 then
dl.info2 = toUcode(info1)
end
if fp.entries[idNr].author_detail and fp.entries[idNr].author_detail.name then
dl.ch = fp.entries[idNr].author_detail.name
end
if fp.entries[idNr].updated_parsed then
dl.date = os.date("%Y%m%d_%H%M%S",fp.entries[idNr].updated_parsed)
end
return dl
end
function which(bin_name)
local path = os.getenv("PATH") or "/bin"
for v in path:gmatch("([^:]+):?") do
local file = v .. "/" .. bin_name
if fh:exist(file , "f") then
return true
end
end
return false
end
function getMaxVideoRes()
local maxRes = 1280
if conf.maxRes then
local maxResStr = conf.maxRes:match("(%d+)x")
maxRes = tonumber(maxResStr)
end
return maxRes
end
function getVideoUrlM3U8(m3u8_url,tmpMaxRes)
if m3u8_url == nil then return nil end
if not m3u8_url:find('m3u8') then return m3u8_url end
local videoUrl = nil
local res = 0
local data = getdata(m3u8_url)
if data then
local host = m3u8_url:match('([%a]+[:]?//[_%w%-%.]+)/')
if m3u8_url:find('/master.m3u8') or m3u8_url:find('/manifest.m3u8') then
local lastpos = (m3u8_url:reverse()):find("/")
local hosttmp = m3u8_url:sub(1,#m3u8_url-lastpos)
if hosttmp then
host = hosttmp .."/"
end
end
local maxRes = getMaxVideoRes()
if tmpMaxRes and maxRes > tmpMaxRes then maxRes = tmpMaxRes end
for band, res1, res2, url in data:gmatch('BANDWIDTH=(%d+).-RESOLUTION=(%d+)x(%d+).-\n(.-)\n') do
if url and res1 then
local nr = tonumber(res1)
if nr <= maxRes and nr > res then
res=nr
if host and url:sub(1,4) ~= "http" then
url = host .. url
end
url = url:gsub("\x0d","")
videoUrl = url
end
end
end
end
if videoUrl == nil then
videoUrl = m3u8_url
end
return videoUrl,res
end
function pop(cmd)
local f = assert(io.popen(cmd, 'r'))
local s = assert(f:read('*a'))
f:close()
return s
end
function getdata(Url,outputfile,Postfields,pass_headers,httpheaders)
if Url == nil then return nil end
if Curl == nil then
Curl = curl.new()
end
if Url:sub(1, 2) == '//' then
Url = 'https:' .. Url
end
if 1 > conf.ctimeout then conf.ctimeout=1 end
local ret, data = Curl:download{ url=Url, A="Mozilla/5.0",connectTimeout=conf.ctimeout,maxRedirs=5,
followRedir=true,postfields=Postfields,header=pass_headers,o=outputfile,httpheader=httpheaders }
if ret == CURL.OK then
if outputfile then
return 1
end
return data
else
return nil
end
end
function getFeedDataFromUrl(url)
local h = hintbox.new{caption="Please Wait ...", text="I'm Thinking."}
if h then
h:paint()
end
local httpheaders = { 'Accept: application/xml' }
local data = getdata(url,nil,nil,nil,httpheaders)
if h then
h:hide()
end
if data then
-- fix for >>> couldn't parse xml. lxp says: junk after document element
local nB, nE = data:find("")
if nE and #data > nE then
data = string.sub(data,0,nE)
end
else
return nil
end
local error = nil
local feedparser = require "feedparser"
fp,error = feedparser.parse(data)
if error then
print("DEBUG ".. __LINE__())
print(data) -- DEBUG
print ("ERROR >> ".. error .. "\n###")
local window,x,y,w,h = showWindow("DEBUG Output", data)
window:hide()
window = nil
end
data = nil
return fp
end
function godirectkey(d)
if d == nil then return d end
local _dkey = ""
if d == 1 then
_dkey = RC.red
elseif d == 2 then
_dkey = RC.green
elseif d == 3 then
_dkey = RC.yellow
elseif d == 4 then
_dkey = RC.blue
elseif d < 14 then
_dkey = RC[""..d - 4 ..""]
elseif d == 14 then
_dkey = RC["0"]
else
-- rest
_dkey = ""
end
return _dkey
end
function check_if_double(tab,name)
for index,value in ipairs(tab) do
if value == name then
return false
end
end
return true
end
function info(infotxt,cap)
if cap == nil then
cap = "Information"
end
local h = hintbox.new{caption=cap, text=infotxt}
if h then
h:paint()
get_input()
h:hide()
end
h = nil
end
function get_input(ct,B)
local stop = false
local ret = nil
local msg, data = nil,nil
if B == nil then B = {btnOk=''} end
repeat
msg, data = n:GetInput(500)
if ct and (msg == RC.up or msg == RC.page_up) then
ct:scroll{dir="up"}
elseif ct and (msg == RC.down or msg == RC.page_down) then
ct:scroll{dir="down"}
elseif msg == RC.left then
stop = true
elseif msg == RC.right then
stop = true
end
for k,v in pairs(B) do
if k and ((msg == RC[k:sub(4):lower()]) or
(k and conf.mpkey > 0 and msg == conf.mpkey and k:sub(4):lower() == 'play') ) then
stop = true
end
end
until msg == RC.home or msg == RC.setup or stop
if stop then
ret = msg
end
return ret
end
function tounicode(c)
if c > 8200 then
return " "
end
if c > 383 then
c=c-256
return "\xC6" .. string.format('%c', c)
elseif c > 319 then
c=c-192
return "\xC5" .. string.format('%c', c)
elseif c > 254 then
c=c-128
return "\xC4" .. string.format('%c', c)
elseif c > 191 then
c=c-64
return "\xC3" .. string.format('%c', c)
else
return string.format('%c', c)
end
end
function convHTMLentities(summary)
if summary ~= nil then
summary = summary:gsub("([0-9]+);",function(c) return tounicode(tonumber(c)) end)
summary = summary:gsub("([%x]+);",function(c) return tounicode(tonumber(c, 16)) end)
end
return summary
end
--------------------------- new
function removeElemetsbyTagName(document,ename)
local t = document:getElementsByTagName(ename)
for i, element in ipairs(t) do
element:remove()
end
end
function removeElemetsbyTagName2(document,tagName,atrName)
local t = document:getElementsByTagName(tagName)
for i, element in ipairs(t) do
local el = element:getAttribute(atrName)
if el then
element:remove()
end
end
end
function all_trim(s)
if s == nil then return "" end
return s:match("^%s*(.-)%s*$")
end
function xml_entities(s)
s = s:gsub('<' , '<' )
s = s:gsub('>' , '>' )
s = s:gsub('"', '"' )
s = s:gsub(''', "'" )
s = s:gsub('Ä', 'Ä' )
s = s:gsub('ä', 'ä' )
s = s:gsub('Ö', 'Ö' )
s = s:gsub('ö', 'ö' )
s = s:gsub('ü', 'ü' )
s = s:gsub('Ü', 'Ü' )
s = s:gsub('ß','ß' )
s = s:gsub('á','á' )
s = s:gsub('Á','Á' )
s = s:gsub('é','é' )
s = s:gsub('É','É' )
s = s:gsub('ú','ú' )
s = s:gsub('Ú','Ú' )
s = s:gsub('€','€' )
s = s:gsub('©','©' )
s = s:gsub('®','®' )
s = s:gsub(' ',' ' )
s = s:gsub('','' )
s = s:gsub('Ó','Ó' )
s = s:gsub('ó','ó' )
s = s:gsub('„','„' )
s = s:gsub('“','“' )
s = s:gsub('–','–' )
s = s:gsub('—','—' )
s = s:gsub('…','…' )
s = s:gsub('‘','‘' )
s = s:gsub('’','’' )
s = s:gsub('‹','‹' )
s = s:gsub('›','›' )
s = s:gsub('‰','‰' )
s = s:gsub('è','è' )
s = s:gsub('‚','‚' )
s = s:gsub('»','»' )
s = s:gsub('”','”' )
s = s:gsub('ç','ç' )
s = s:gsub('&' , '&' )
return s
end
function prepare_text(text)
if text == nil then return nil end
if #text < 1 then
return text
end
text = text:gsub('<.->', "") -- remove "<" alles zwischen ">"
text = text:gsub("\240[\144-\191][\128-\191][\128-\191]","")
text = convHTMLentities(text)
text = text:gsub("%s+\n", " \n")
text = all_trim(text)
text = xml_entities(text)
return text
end
function getMaxScreenWidth()
local max_w = SCREEN.END_X - SCREEN.OFF_X
return max_w
end
function getMaxScreenHeight()
local max_h = SCREEN.END_Y - SCREEN.OFF_Y
return max_h
end
function getSafeScreenSize(x,y,w,h)
local maxW = getMaxScreenWidth()
local maxH = getMaxScreenHeight()
if w > maxW or w < 1 then
w = maxW
end
if h > maxH or h < 1 then
if h > maxH then
w = maxW
end
h = maxH
end
if x < 0 or x+w > maxW then
x = 0
end
if y < 0 or y+h > maxH then
y = 0
end
return x,y,w,h
end
function paintPic(window,fpic,x,y,w,h)
local cp = cpicture.new{parent=window, x=x, y=y, dx=w, dy=h, image=fpic}
if window == nil then
cp:paint()
end
end
function paintText(x,y,w,h,picW,picH,CPos,text,window) --ALIGN_AUTO_WIDTH
if x == 0 then
x = 20
end
local pW,pH = 0,0
local ct = ctext.new{parent=window,x=x, y=y, dx=w, dy=h, text=text, mode = "ALIGN_SCROLL | DECODE_HTML", font_text=Font}
if window == nil then
ct:paint()
else
local ctLines = ct:getLines()
h = ctLines * n:FontHeight(FontMenu)
h = h + window:headerHeight() + window:footerHeight() + window:headerHeight()/2
h = math.floor(h)
if ctLines < 6 then
text = text:gsub("\n"," ")
ct:setText{text=text}
pW = 0
pH = picH
h = h + picH
else
w = w + picW + 4
pH = 0
pW = picW + 4
h = h + window:footerHeight()
end
x,y,w,h = getSafeScreenSize(x,y,w,h)
ct:setDimensionsAll(x+pW,y+pH,w,h)
window:setDimensionsAll(x,y,w,h)
if CPos and CPos > 0 and CPos < 4 then
window:setCenterPos{CPos}
end
if ctLines > 5 and picH < h - window:headerHeight() - window:footerHeight() then
y = y + (h - window:headerHeight() - window:footerHeight()- picH)/2
y = math.floor(y)
end
end
return ct,x,y,w,h
end
function paintWindow(x,y,w,h,CPos,Title,Icon,B)
if B == nil then B = {} end
local defaultW = math.floor(getMaxScreenWidth()- getMaxScreenWidth()/3)
local defaultH = n:FontHeight(FontMenu)
if w < 1 then
w = defaultW
end
if h < 1 then
h = defaultH
end
local opt = {x=x, y=y, dx=w, dy=h, title=Title, icon=Icon}
for k,v in pairs(B) do
opt[k]=v
end
local window = cwindow.new(opt)
h = h + window:footerHeight() + window:headerHeight()
if Title and #Title > 1 then
w = n:getRenderWidth(FontTitle,Title .. "wW")
w = w + window:headerHeight() + 10 --icon
if w < defaultW then
w = defaultW
end
if w > getMaxScreenWidth() then
w = getMaxScreenWidth()
end
end
x,y,w,h = getSafeScreenSize(x,y,w,h)
window:setDimensionsAll(x,y,w,h)
if CPos and CPos > 0 and CPos < 4 then
window:setCenterPos{CPos}
end
return window,x,y,w,h
end
function showWindow(title,text,fpic,icon,B)
local x,y,w,h = 0,0,0,0
local picW,picH = 0,0
local maxW = getMaxScreenWidth()
local maxH = getMaxScreenHeight()
text = prepare_text(text)
if fpic then
picW,picH = n:GetSize(fpic)
if picW and picW > 0 and picH and picH > 0 then
local maxPicSizeW,maxPicSizeH = math.floor(maxW/4),math.floor(maxH/2)
if #text < 100 then
if #text < 10 then
maxPicSizeH = maxH
else
maxPicSizeH = maxH-(5*n:FontHeight(FontMenu))
end
maxPicSizeW = maxW
end
if picH > maxPicSizeH or picW > maxW then
picW,picH = rescalePic(picW,picH,maxPicSizeW,maxPicSizeH)
end
if picH < 150 and picW < 150 then
picW,picH = rescalePic(picW,picH,picH*2,picW*2)
end
h = picH
end
end
local wPosition = 3
local cw,x,y,w,h = paintWindow(x,y,w,h,-1,title,icon,B)
local ct,x,y,w,h = paintText(x,y,w,h,picW,picH,wPosition,text,cw)
if fpic and picW > 1 and picH > 1 then
if x > 15 then
x = x-10
end
local cp = paintPic(cw,fpic,x,y,picW,picH)
end
cw:paint()
local selected = get_input(ct,B)
return cw , selected
end
function show_textWindow(tit_txt, txt)
glob.m:hide()
if txt == nil then return end
if txt and #txt < 1 then
return
end
txt = prepare_text(txt)
local window,x,y,w,h = showWindow(tit_txt, txt)
window:hide()
window = nil
end
function epgInfo(xres, yres, aspectRatio, framerate)
local window,x,y,w,h = showWindow(epgtitle, epgtext)
window:hide()
window = nil
end
function checkdomain(feed,url)
if not url then return url end
local a,b=url:find("src=.http:")
if a and b then
url=url:sub(b-4,#url)
end
if not url:find("//") then
local domain = nil
if fp.feed.link then
domain = fp.feed.link:match('^(%w+://[^/]+)')
end
if domain then
url = domain .. "/" .. url
end
end
return url
end
function getMediUrls(idNr)
local UrlVideo,UrlAudio, UrlExtra = nil,nil,nil
local picUrl = {}
local feed = fp.entries[idNr]
local rev = revision
for i, link in ipairs(feed.enclosures) do
local urlType =link.type
local mediaUrlFound = false
if link.url and urlType == "image/jpeg" then
picUrl[#picUrl+1] = link.url
mediaUrlFound = true
end
if urlType == 'video/mp4' or urlType == 'video/mpeg' or
urlType == 'video/x-m4v' or urlType == 'video/quicktime' then
UrlVideo = link.url
mediaUrlFound = true
end
if rev == 1 and urlType == 'video/webm' then
UrlVideo = link.url
mediaUrlFound = true
end
if urlType == 'audio/mp3' or urlType == 'audio/mpeg' then
if rev == 1 or rev == 0x09 or rev == 0x0B or rev == 0x0C or rev == 0x0D or rev == 0x0E then
UrlAudio = link.url
mediaUrlFound = true
end
end
if mediaUrlFound == false and link.url then
local purl = link.url:match ('(http.-%.[JjGgPp][PpIiNn][Ee]?[GgFf])')
if purl and #purl>4 then
purl = checkdomain(feed,url)
if purl ~= picUrl[#picUrl] then
picUrl[#picUrl+1] = purl
end
end
end
end
if not UrlVideo and feed.summary then
UrlVideo = feed.summary:match('