--[[ 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([%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('') end if #picUrl == 0 then local urls = {feed.summary, feed.content} for i,v in ipairs(urls) do if type(v) == "string" then v=v:gsub('src=""','') v=v:gsub("src=''",'') for url in v:gmatch ('[%-%s]?src%s?=%s?[%"\']?(.-%.[JjGgPp][PpIiNn][Ee]?[GgFf])[%"\'%s%?]') do if url and #url > 4 then local a,b = url:find("http[%w%p]+$") if a and b then local tmpurl = url:sub(a,b) if tmpurl then url = tmpurl end end url = checkdomain(feed,url) if url ~= picUrl[#picUrl] then if check_if_double(picUrl,url) then picUrl[#picUrl+1] = url end end end end for url in v:gmatch ('[%-%s]? 4 then local a,b = url:find("http[%w%p]+$") if a and b then local tmpurl = url:sub(a,b) if tmpurl then url = tmpurl end end url = checkdomain(feed,url) if url ~= picUrl[#picUrl] then if check_if_double(picUrl,url) then picUrl[#picUrl+1] = url end end end end if UrlExtra == nil then UrlExtra = v:match('%w+://[%w+%p]+%.json') end end end end if not UrlVideo and not UrlAudio and not UrlExtra and fp.entries[idNr].link:find("www.youtube.com")then UrlExtra = fp.entries[idNr].link end if fp.entries[idNr].links and not UrlExtra then for i,v in ipairs(fp.entries[idNr].links) do if v.websiteUrl and not UrlExtra then UrlExtra = v.websiteUrl end end end glob.urlPicUrls = picUrl return UrlVideo , UrlAudio , UrlExtra end function html2text(viewer,text) if text == nil then return nil end local tmp_filename = os.tmpname() local fileout = io.open(tmp_filename, 'w+') if fileout then text = text:gsub("<[sS][cC][rR][iI][pP][tT][^%w%-].-", "") fileout:write(text .. "\n") fileout:close() collectgarbage() end local cmd = viewer .. " " .. tmp_filename text = pop(cmd) os.remove(tmp_filename) return text end function htmlreader(text) if text == nil then return "" end local text_tmp = text:match("(.-)") local error = "RSS HTML READER ERROR\n" if text_tmp == nil then return error end text = text_tmp local patterns = { {'',""}, {'.-',""}, {'.-',""}, {'
  • .-
  • ',""}, {'',""}, {'',""}, {'',""}, {'',""}, {'',""}, {'',""}, {'',""}, {'
    ',""}, {'',""}, {'',""}, {'',""}, {'<.->', ""}, {'%-%->', ""}, {'[ ]+\n', ""}, {'\n[ ]+', "",20}, {'[\r]+', "\n"}, {'^\n*', ""}, {'[\n]+', "\n"}, {'\n*$', ""}, } if text == nil then return "" end for _,v in ipairs(patterns) do text = text:gsub( v[1], v[2],v[3] ) end if text == nil then return "" end return text end function checkHaveViewer() if hva == conf.htmlviewer then return true elseif hvb == conf.htmlviewer then return true elseif hvc == conf.htmlviewer then return true elseif hve == conf.htmlviewer then return true elseif hvf == conf.htmlviewer then return true elseif nothing == conf.htmlviewer then return false end return false end function showWithHtmlViewer(data) local txt = nil local viewer = nil if hve == conf.htmlviewer then viewer = conf.linksbrowserdir .. LinksBrowser .. " -dump" txt=html2text(viewer,data) elseif hvb == conf.htmlviewer then viewer= conf.bindir .. "/html2text -nobs -utf8" txt=html2text(viewer,data) elseif hvc == conf.htmlviewer then viewer= conf.bindir .. "/w3m -dump" txt=html2text(viewer,data) elseif hvf == conf.htmlviewer then txt = htmlreader(data) elseif nothing == conf.htmlviewer then return nil end return txt end ----------------------------------------------- function showMenuItem(id) local nr = tonumber(id) local stop = false local selected = paintMenuItem(nr) repeat if selected == RC.left then if nr > 1 then nr=nr-1 else nr = #glob.feedpersed.entries end selected = paintMenuItem(nr) elseif selected == RC.right then if nr < #glob.feedpersed.entries then nr=nr+1 else nr = 1 end selected = paintMenuItem(nr) elseif selected then selected = paintMenuItem(nr) else stop = true end until stop end function setBtnPlay(B, strPlay) if conf.playKey == P_Key.btnOk then B.btnOk = strPlay elseif conf.playKey == P_Key.btnRed then B.btnRed = strPlay elseif conf.playKey == P_Key.btnPlay then B.btnPlay = strPlay end end local tmpUrlLink,tmpUrlVideo,tmpUrlAudio,tmpUrlExtra,tmpUrlVideoAudio,tmpText = nil,nil,nil,nil,nil,nil function paintMenuItem(idNr) glob.m:hide() local title = fp.entries[idNr].title if title then title = title:gsub("\n", " ") end local text = fp.entries[idNr].summary local UrlLink = fp.entries[idNr].link local UrlVideo,UrlAudio,UrlExtra,UrlVideoAudio = nil,nil,nil,nil local cal = false if UrlLink ~= tmpUrlLink then glob.urlPicUrls = {} tmpUrlLink,tmpUrlVideo,tmpUrlAudio,tmpUrlExtra,tmpUrlVideoAudio,tmpText = nil,nil,nil,nil,nil,nil UrlVideo,UrlAudio,UrlExtra = getMediUrls(idNr) cal = true else UrlVideo,UrlAudio,UrlExtra,UrlVideoAudio,text = tmpUrlVideo,tmpUrlAudio,tmpUrlExtra,tmpUrlVideoAudio,tmpText end local fpic = nil if cal and addon and UrlLink then local hasaddon,a = pcall(require,addon) if hasaddon then a.VideoUrl = nil a.UrlVideoAudio = nil a.AudioUrl = nil a.getAddonMedia(UrlLink,UrlExtra) if a.VideoUrl then UrlVideo = a.VideoUrl a.VideoUrl = nil end if a.UrlVideoAudio then UrlVideoAudio = a.UrlVideoAudio a.UrlVideoAudio = nil end if a.AudioUrl then UrlAudio = a.AudioUrl a.AudioUrl = nil end if a.PicUrl then if type(a.PicUrl) == 'table' then for i=1,#a.PicUrl do if check_if_double(glob.urlPicUrls,a.PicUrl[i]) then glob.urlPicUrls[#glob.urlPicUrls+1] = a.PicUrl[i] end end else if check_if_double(glob.urlPicUrls,a.PicUrl) then glob.urlPicUrls[#glob.urlPicUrls+1] = a.PicUrl end end a.PicUrl = nil end if a.addText then if text == nil then text="" end text = text .. a.addText a.addText = nil end if a.newText then text = a.newText a.newText = nil end else local errMsg = ".lua not found in directory: " .. conf.addonsdir info( addon .. errMsg ,"ADDON: Error") end end if UrlLink then tmpUrlLink,tmpUrlVideo,tmpUrlAudio,tmpUrlExtra,tmpUrlVideoAudio,tmpText = UrlLink,UrlVideo,UrlAudio,UrlExtra,UrlVideoAudio,text end if not vPlay and (UrlVideo or UrlAudio) then vPlay = video.new() end if vPlay and text and #text > 1 then vPlay:setInfoFunc("epgInfo") epgtext = text epgtitle = title end if UrlVideo == UrlLink then UrlLink = nil end if UrlAudio == UrlLink then UrlLink = nil end if UrlLink and UrlLink:sub(1, 4) ~= 'http' then UrlLink = nil end if glob.urlPicUrls and #glob.urlPicUrls > 0 then fpic=downloadPic(idNr,1) end if text == nil and fp.entries[idNr].content then text = fp.entries[idNr].content end if UrlVideo and UrlVideo:sub(1, 2) == '//' then UrlVideo = 'https:' .. UrlVideo end if UrlAudio and UrlAudio:sub(1, 2) == '//' then UrlAudio = 'https:' .. UrlAudio end if text == nil then if vPlay and UrlVideo then if revision then vPlay:PlayFile(title,UrlVideo,UrlVideo,"",UrlVideoAudio or "") else vPlay:PlayFile(title,UrlVideo,UrlVideo) end elseif vPlay and UrlAudio then vPlay:PlayFile(title,UrlAudio,UrlAudio) end collectgarbage() return end local B = {btnRed = nil, btnGreen = nil, btnYellow = nil, btnBlue = nil, btn0 = nil, btn1 = nil, btnOk = nil, btnSetup = nil, btnPlay = nil} local dl_possible = false if UrlVideo then setBtnPlay(B,"Play Video") dl_possible = dl_check(UrlVideo) if dl_possible then B.btn0 = "Download Video" end end if UrlLink and checkHaveViewer() then B.btnGreen = "Read Seite" end if glob.urlPicUrls and #glob.urlPicUrls > 0 then B.btnYellow = "Show Pic" if #glob.urlPicUrls > 1 then B.btnYellow = B.btnYellow .. "s" end end if UrlAudio then local bnt = "Play Audio" if UrlVideo == nil then setBtnPlay(B,bnt) else B.btnBlue = bnt end end local cw,selected = showWindow(title, text, fpic, "hint_info", B) cw:hide() cw = nil local isPlayRC = selected == RC.ok or selected == RC.red or selected == RC.play or selected == conf.mpkey local info1 = '' if fp.entries[idNr].author_detail and fp.entries[idNr].author_detail.name then info1 = fp.entries[idNr].author_detail.name end if fp.entries[idNr].published then local pub = fp.entries[idNr].published:match('(%d+%-%d+%-%d+)') if pub then info1 = info1 .. ' ' .. pub end end if isPlayRC and vPlay and UrlVideo then if revision then vPlay:PlayFile(title, UrlVideo, info1, UrlVideo, UrlVideoAudio or "") else vPlay:PlayFile(title,UrlVideo,UrlVideo) end elseif checkHaveViewer() and selected == RC.green and UrlLink then if hva == conf.htmlviewer and UrlLink then os.execute(conf.linksbrowserdir .. LinksBrowser .. " -g " .. UrlLink) else local data = getdata(UrlLink) if data then local txt = showWithHtmlViewer(data) data = nil if txt then show_textWindow(title,txt) end end end elseif selected == RC.yellow and B.btnYellow then picviewer(idNr,1) elseif vPlay and UrlAudio then if selected == RC.blue or (UrlVideo == nil and isPlayRC) then vPlay:PlayFile(title, UrlAudio, info1, UrlAudio) end elseif dl_possible and selected == RC['0'] and B.btn0 then local dl = gen_dl(UrlVideo, UrlVideoAudio, title, text or "", idNr) if dl then dl_stream(dl) end end epgtext = nil epgtitle = nil if glob.urlPicUrls and #glob.urlPicUrls > 0 and conf.picdir == picdir then local fh = filehelpers.new() if fh then fh:rmdir(picdir) fh:mkdir(picdir) end end collectgarbage() return selected end function downloadPic(idNr,nr) local fpic = nil if not glob.urlPicUrls[nr] then return nil end local picname = string.find(glob.urlPicUrls[nr], "/[^/]*$") if picname then picname = string.sub(glob.urlPicUrls[nr],picname+1,#glob.urlPicUrls[nr]) local t = nil if fp.entries[idNr].updated_parsed then t = os.date("%d%m%H%M%S_",fp.entries[idNr].updated_parsed) end local id2 = nil if t then id2 = t else id2 = idNr end fpic = conf.picdir .. "/" .. id2 .. picname if fh:exist(fpic, "f") == false then if nr > 1 then n:PaintIcon("icon_red", 20 + SCREEN.OFF_X, 40 + SCREEN.OFF_Y, 30,30) end local UrlPic = glob.urlPicUrls[nr] local ok = getdata(UrlPic,fpic) if not ok then fpic = nil end end end return fpic end function rescalePic(picW,picH,maxW,maxH) if picW and picW > 0 and picH and picH > 0 then local aspect = picW / picH if not maxH then maxH = getMaxScreenHeight() end if not maxW then maxW = getMaxScreenWidth() end if picW / maxW > picH / maxH then picW = maxW picH = maxW/aspect else picH = maxH picW = maxH * aspect end picH = math.floor(picH) picW = math.floor(picW) end return picW,picH end function picviewer(id,nr) if #glob.urlPicUrls > 0 and nr > 0 then local V = nil local msg, data = nil,nil local lastnr = 0 local colBlack = COL.BLACK if not colBlack then colBlack = COL.COL_BLACK end local colRed = COL.RED if not colRed then colRed = COL.COL_RED end repeat msg, data = n:GetInput(500) if msg == RC.left then if nr > 1 then nr=nr-1 else nr = #glob.urlPicUrls end elseif msg == RC.right then if nr < #glob.urlPicUrls then nr=nr+1 else nr = 1 end end if lastnr ~= nr then lastnr = nr local image = downloadPic(id,nr) if image then local picW,picH = n:GetSize(image) if picW and picW > 0 and picH and picH > 0 then if picH < 250 and picW < 250 then picW,picH = rescalePic(picW,picH,picH*2,picW*2) else picW,picH = rescalePic(picW,picH) end local y,x=0,0 if getMaxScreenHeight() > picH then y = (getMaxScreenHeight()-picH)/2 y = math.floor(y) end if getMaxScreenWidth() > picW then x = (getMaxScreenWidth()-picW)/2 x = math.floor(x) end n:PaintBox(0,0,-1,-1, colBlack ) n:DisplayImage(image,x + SCREEN.OFF_X,y + SCREEN.OFF_Y,picW,picH) end if #glob.urlPicUrls > 1 then local str = nr .. "/" .. #glob.urlPicUrls n:RenderString(FontMenu, str, 20 + SCREEN.OFF_X , 40 + SCREEN.OFF_Y, colRed) end end end until msg == RC.home or msg == RC.setup or msg == RC.ok or stop n:PaintBox(-1,-1,-1,-1,COL.BACKGROUND) end end ----------------------------------------------------------------------------- function home() return MENU_RETURN.EXIT end function saveConfig() if conf.changed then local config = configfile.new() if config then config:setString("picdir", conf.picdir) config:setString("bindir", conf.bindir) config:setString("addonsdir", conf.addonsdir) config:setString("htmlviewer", conf.htmlviewer) config:setString("maxRes", conf.maxRes) config:setInt32("set_key", conf.set_key) config:setInt32("ctimeout", conf.ctimeout) config:setString("linksbrowserdir", conf.linksbrowserdir) config:setString('dlPath', conf.dlPath) config:setInt32("playKey", conf.playKey) config:saveConfig(get_confFile()) config = nil end conf.changed = false end end function loadConfig() local config = configfile.new() if config then config:loadConfig(get_confFile()) conf.picdir = config:getString("picdir", "/tmp/rssPics") conf.bindir = config:getString("bindir", "/bin") conf.addonsdir = config:getString("addonsdir", "/usr/share/tuxbox/neutrino/plugins/rss_addon/") conf.linksbrowserdir = config:getString("linksbrowserdir", "/usr/share/tuxbox/neutrino/plugins/") conf.htmlviewer = config:getString("htmlviewer", "nichts") conf.maxRes = config:getString("maxRes", "1280x720") conf.set_key = config:getInt32("set_key", 1) conf.ctimeout = config:getInt32("ctimeout", 5) conf.dlPath = config:getString('dlPath', '/') conf.playKey = config:getInt32("playKey", 1) config = nil end local Nconfig = configfile.new() Nconfig:loadConfig(CONF_PATH .. "neutrino.conf") conf.lang = Nconfig:getString("language", "english") LOC = locale[conf.lang] if LOC == nil then LOC = locale["english"] end conf.mpkey = Nconfig:getInt32("mpkey.play", 0) local key = Nconfig:getString("youtube_dev_id", '#') if key ~= '#' then youtube_dev_id = key end conf.changed = false glob.have_ffmpeg = which("ffmpeg") checkhtmlviewer() end function checkhtmlviewer() if fh:exist(conf.linksbrowserdir .. LinksBrowser, "f") == true then hva="links browser" hve="links viewer" end if fh:exist(conf.bindir .. "/" .. "html2text", "f") == true then hvb="html2text" end if fh:exist(conf.bindir .. "/" .. "w3m" , "f") == true then hvc="w3m" end end function set_action(id,value) if id == "ctimeout" then value = tonumber(value) end if id == 'set_key' then if LOC.fav_and_setup_key == value then conf.set_key = S_Key.fav_setup elseif LOC.fav_key == value then conf.set_key = S_Key.fav elseif LOC.setup_key == value then conf.set_key = S_Key.setup end if LOC.set_keyp_ok == value then conf.playKey = 1 elseif LOC.set_keyp_red == value then conf.playKey = 2 elseif LOC.set_keyp_play == value then conf.playKey = 3 end conf.changed = true return end conf.changed = true conf[id]=value if id == "maxRes" then tmpUrlLink,tmpUrlVideo,tmpUrlAudio,tmpUrlExtra,tmpUrlVideoAudio,tmpText = nil,nil,nil,nil,nil,nil end if id == 'addonsdir' then package.path = package.path .. ';' .. conf.addonsdir .. '/?.lua' end if id == 'linksbrowserdir' or id == 'bindir' then checkhtmlviewer() end end function settings(id,a) glob.sm:hide() local d = 1 local menu = menu.new{name="Einstellungen", icon="icon_blue"} glob.settings_menu = menu menu:addItem{type="back"} menu:addItem{type="separatorline"} menu:addItem{ type="filebrowser", dir_mode="1", id="picdir", name= LOC.picdir, action="set_action", enabled=true,value=conf.picdir,directkey=godirectkey(d), hint_icon="hint_service",hint= LOC.picdirhint } d=d+1 menu:addItem{ type="filebrowser", dir_mode="1", id="dlPath", name= LOC.dldir, action="set_action", enabled=true,value=conf.dlPath,directkey=godirectkey(d), hint_icon="hint_service",hint= LOC.dlhint } d=d+1 menu:addItem{ type="filebrowser", dir_mode="1", id="bindir", name="HtmlViewer: ", action="set_action", enabled=true,value=conf.bindir,directkey=godirectkey(d), hint_icon="hint_service",hint=LOC.bindirhint .. "(html2text,w3m,links)" } d=d+1 menu:addItem{ type="filebrowser", dir_mode="1", id="addonsdir", name=LOC.addonsdir, action="set_action", enabled=true,value=conf.addonsdir,directkey=godirectkey(d), hint_icon="hint_service",hint=LOC.addonsdirhint } d=d+1 menu:addItem{ type="filebrowser", dir_mode="1", id="linksbrowserdir", name=LOC.linksbrowserdir, action="set_action", enabled=true,value=conf.linksbrowserdir,directkey=godirectkey(d), hint_icon="hint_service",hint=LOC.linksbrowserdirhint } d=d+1 menu:addItem{type="chooser", action="set_action", options={ nothing,hva,hvb,hvc,hve,hvf }, id="htmlviewer", value=conf.htmlviewer, name=LOC.htmlviewer ,directkey=godirectkey(d),hint_icon="hint_service",hint=LOC.htmlviewerhint} d=d+1 local set_key_opt={ LOC.fav_and_setup_key,LOC.fav_key,LOC.setup_key } menu:addItem{type="chooser", action="set_action", options=set_key_opt, id="set_key", value=set_key_opt[conf.set_key], name=LOC.set_key ,directkey=godirectkey(d),hint_icon="hint_service",hint=LOC.set_key_hint} d=d+1 local set_keyp_opt={ LOC.set_keyp_ok, LOC.set_keyp_red, LOC.set_keyp_play} menu:addItem{type="chooser", action="set_action", options=set_keyp_opt, id="set_key", value=set_keyp_opt[conf.playKey], name=LOC.set_keyp ,directkey=godirectkey(d),hint_icon="hint_service",hint=LOC.set_keyp_hint} d=d+1 menu:addItem{type="stringinput", action="set_action", id="ctimeout", name=LOC.curlTimeout, value=conf.ctimeout, valid_chars="0123456789",size=2,hint_icon="hint_service",hint=LOC.curlTimeouthint} d=d+1 local res_opt={ '3840x2160','2560x1440','1920x1080','1280x720','854x480','640x360' } menu:addItem{type="chooser", action="set_action", options=res_opt, id="maxRes", value=conf.maxRes, name=LOC.maxRes ,directkey=godirectkey(d),hint_icon="hint_service",hint=LOC.maxReshint} menu:addItem{type="separatorline"} d=d+1 menu:addItem{type="forwarder", name=LOC.mt_ard, action="gen_MT_ard", id="ard", directkey==godirectkey(d) ,hint=LOC.mt_hint} d=d+1 menu:addItem{type="forwarder", name=LOC.mt_zdf, action="gen_MT_zdf", id="zdf", directkey==godirectkey(d) ,hint=LOC.mt_hint} menu:exec() menu:hide() menu = nil end ---- Mediatheken Gen function read_file(filename) local fp = io.open(filename, "r") if fp == nil then error("Error opening file '" .. filename .. "'.") end local data = fp:read("*a") fp:close() return data end function readDir(dir, fileType) local v = {} local p = io.popen('ls '.. dir .. " | grep " .. fileType) for file in p:lines() do table.insert(v, file) end return v end function LoadMediatheken() local vfile = readDir(CONF_PATH, "rss_gen_") for k,v in pairs(vfile) do loadMediathek(CONF_PATH .. v) end end function loadMediathek(filename) local data = read_file(filename) for _line in data:gmatch('(title.-)\n') do local _name = _line:match('title="(.-)"') local _url = _line:match('url="(.-)"') local _grup = _line:match('grup="(.-)"') local _submenu = _line:match('submenu="(.-)"') local _addon = _line:match('addon="(.-)"') table.insert(feedentries,{name=_name, exec=_url,grup=_grup, submenu=_submenu,addon=_addon}) end end function save_gen_con(table,mt_name,addon) local filename= CONF_PATH .. "rss_gen_" .. mt_name .. ".conf" local file = io.open(filename,'w+') if file then for k,v in pairs(table) do local grup="Mediathek-" .. mt_name local submenu=v.az file:write('title="' .. v.name .. '" url="' .. v.url .. '" grup="' .. grup .. '" submenu="' .. submenu .. '" addon="' .. addon .. '" \n') end file:close() return end info(filename, mt_name .. " save error file") end function gen_MT_ard() glob.settings_menu:hide() local az = {"A","B","C","D","E","F","G","H","I","J","K","L","M","N","O","P","Q","R","S","T","U","V","W","Z","0-9"} local allT = {} local tab = {} local h = hintbox.new{caption="Please Wait ...", text="I'm Thinking."} if h then h:paint() end for i, z in ipairs(az) do local url = "https://www.ardmediathek.de/sendungen-a-bis-z/" .. z local data = getdata(url) local json = require "json" data = data:match('') local jnTab = json:decode(data ) for k, v in pairs(jnTab) do if v.teasers then for kk, vv in pairs(v.teasers) do if vv.shortTitle then local title = vv.shortTitle:gsub(" ","%%20") table.insert(tab,{name=vv.shortTitle, url="https://mediathekviewweb.de/feed?query=!ard%20" .. title , az=z}) end end end end end h:hide() save_gen_con(tab,"ARD","mediathekviewweb") end function gen_MT_zdf() glob.settings_menu:hide() local allT = {} local _az = {"a","b","c","d","e","f","g","h","i","j","k","l","m","n","o","p","q","r","s","t","u","v","w","z","0%20-%209"} local tab = {} local h = hintbox.new{caption="Please Wait ...", text="I'm Thinking."} if h then h:paint() end for i, v in ipairs(_az) do local url = "https://www.zdf.de/sendungen-a-z?group=" .. v local data = getdata(url) if data then for _url , title in data:gmatch('", " ") title = title:gsub("", " ") else title = title .. " " end m:addItem{type="forwarder", name=title, action="showMenuItem", id=i, directkey=dkey } end m:exec() glob.feedpersed = nil collectgarbage() end function exec_url(id) glob.sm:hide() execUrl(id) end function exec_url2(id) glob.grupm:hide() execUrl(id) end function exec_urlsub(id) glob.subm:hide() execUrl(id) end function execUrl(id) local nr = tonumber(id) addon = feedentries[nr].addon rssurlmenu(feedentries[nr].exec) end function exec_submenu_grup(id) glob.grupm:hide() local d = 0 -- directkey local subm = menu.new{name=id, icon="icon_yellow"} glob.subm=subm for v, w in ipairs(feedentries) do if w.grup and w.submenu == id then if w.exec == "SEPARATOR" then subm:addItem{type="separator"} elseif w.exec == "SEPARATORLINE" then subm:addItem{type="separatorline", name=w.name} else d = d + 1 local dkey = godirectkey(d) subm:addItem{type="forwarder", name=w.name, action="exec_urlsub", id=v, directkey=dkey } end end end subm:exec() end function exec_submenu(id) glob.sm:hide() local d = 0 -- directkey local subm = menu.new{name=id, icon="icon_yellow"} glob.subm=subm for v, w in ipairs(feedentries) do if w.submenu == id and w.grup == nil then if w.exec == "SEPARATOR" then subm:addItem{type="separator"} elseif w.exec == "SEPARATORLINE" then subm:addItem{type="separatorline", name=w.name} else d = d + 1 local dkey = godirectkey(d) subm:addItem{type="forwarder", name=w.name, action="exec_urlsub", id=v, directkey=dkey } end end end subm:exec() end function exec_grup(id) glob.sm:hide() local submenus = {} local d = 0 -- directkey local grupm = menu.new{name=id, icon="icon_yellow"} glob.grupm=grupm for v, w in ipairs(feedentries) do if w.grup == id then if w and w.submenu and check_if_double(submenus,w.submenu) then submenus[#submenus+1]=w.submenu d = d + 1 local dkey = godirectkey(d) grupm:addItem{type="forwarder", name=w.submenu, action="exec_submenu_grup", id=w.submenu, directkey=dkey } end end end if #submenus then grupm:addItem{type="separatorline"} end for v, w in ipairs(feedentries) do if w and w.grup == id and not w.submenu then if w.exec == "SEPARATOR" then grupm:addItem{type="separator"} elseif w.exec == "SEPARATORLINE" then grupm:addItem{type="separatorline", name=w.name} else d = d + 1 local dkey = godirectkey(d) grupm:addItem{type="forwarder", name=w.name, action="exec_url2", id=v, directkey=dkey } end end end grupm:exec() end function start() local submenus = {} local grupmenus = {} local d = 0 -- directkey local sm = menu.new{name="Lua RSS READER", icon="icon_blue"} glob.sm=sm if S_Key.fav_setup == conf.set_key or S_Key.fav == conf.set_key then sm:addKey{directkey=RC.favorites, id="settings", action="settings"} else sm:addKey{directkey=RC.favorites, id="home", action="home"} end if S_Key.fav_setup == conf.set_key or S_Key.setup == conf.set_key then sm:addKey{directkey=RC.setup, id="settings", action="settings"} end sm:addKey{directkey=RC.home, id="home", action="home"} sm:addKey{directkey=RC.info, id=rssReaderVersion, action="info"} ----------------- for v, w in ipairs(feedentries) do if w and w.grup and w.submenu and check_if_double(grupmenus,w.grup) then grupmenus[#grupmenus+1]=w.grup d = d + 1 local dkey = godirectkey(d) sm:addItem{type="forwarder", name=w.grup, action="exec_grup", id=w.grup, directkey=dkey } end end if #grupmenus then sm:addItem{type="separatorline"} end ------------------ for v, w in ipairs(feedentries) do if w and w.submenu and w.grup == nil and check_if_double(submenus,w.submenu) then submenus[#submenus+1]=w.submenu d = d + 1 local dkey = godirectkey(d) sm:addItem{type="forwarder", name=w.submenu, action="exec_submenu", id=w.submenu, directkey=dkey } end end if #submenus then sm:addItem{type="separatorline"} end for v, w in ipairs(feedentries) do if not w.submenu and not w.grup then if w.exec == "SEPARATOR" then sm:addItem{type="separator"} elseif w.exec == "SEPARATORLINE" then sm:addItem{type="separatorline", name=w.name} else d = d + 1 local dkey = godirectkey(d) sm:addItem{type="forwarder", name=w.name, action="exec_url", id=v, directkey=dkey } end end end sm:exec() end function main() local configs = {"rssreader.conf", "media_one.conf"} local f = {} for i, v in ipairs(configs) do local config = CONF_PATH .. v if fh:exist(config, "f") or fh:exist(config, "l") then dofile(config) for j, w in ipairs(feedentries) do table.insert(f, w) end end end feedentries = f if not next(feedentries) then feedentries = { { name = "rssreader.conf Beispiel", exec = "SEPARATORLINE" }, { name = "heise.de", exec = "https://www.heise.de/newsticker/heise-atom.xml",addon="heise", submenu="TechNews"}, { name = "CHIP Hardware-News", exec = "http://www.chip.de/rss/rss_technik.xml", submenu="TechNews"}, { name = "Tatort - ARD Mediathek", exec = "https://classic.ardmediathek.de/tv/Tatort/Sendung?documentId=602916&rss=true", submenu="Podcast", addon="ard"}, { name = "Alle Filme - ARD Mediathek", exec = "https://classic.ardmediathek.de/tv/Alle-Filme/mehr?documentId=31610076&rss=true", submenu="Podcast",addon="ard"}, { name = "arte", exec = "http://www.arte.tv/papi/tvguide-flow/feeds/videos/de.xml?currentWeek=0", submenu="Podcast",addon="arte"}, { name = "ARTE : TV-Programm", exec = "http://www.arte.tv/papi/tvguide-flow/feeds/program/de.xml?currentWeek=0", submenu="Podcast",addon="arte"}, { name = "TecTime TV", exec = "https://www.youtube.com/feeds/videos.xml?user=DrDishTelevision", submenu="Youtube", addon="yt" }, { name = "KingOfSat News", exec = "http://de.kingofsat.net/rssnews.php",submenu="SatInfo",addon="kingofsat"}, } end fh:mkdir(picdir) LoadMediatheken() loadConfig() if conf.picdir == nil or fh:exist(conf.picdir , "d") == false then conf.picdir = picdir end package.path = package.path .. ';' .. conf.addonsdir .. '/?.lua' if next(feedentries) == nil then print("DEBUG ".. __LINE__()) print("failed while loading " .. config) return end if APIVERSION ~= nil and (APIVERSION.MAJOR > 1 or ( APIVERSION.MAJOR == 1 and APIVERSION.MINOR > 82 )) then M = misc.new() revision = M:GetRevision() local procmodel = "/proc/stb/info/model" if fh:exist(procmodel , "f") then local model = read_file(procmodel) if model and model:find("ufs%d+") then revision = 0x0E end end end start() saveConfig() fh:rmdir(picdir) local jsname = "/tmp/._js_data" if fh:exist(jsname , "f") then os.remove(jsname) --yt addon js data end end main()