Added DVB EPG

requires dddvb commit f323471384a592eb0772c19c5e6d1dc0589831c7
This commit is contained in:
mvoelkel 2016-01-30 16:41:58 +01:00
parent 8ffaac8c7f
commit 92c835be8c
8 changed files with 645 additions and 77 deletions

View File

@ -0,0 +1,217 @@
#!/usr/bin/lua
--
local newdecoder = require("lunajson.decoder")
local newencoder = require("lunajson.encoder")
local function GetIPAddr()
local myip = nil
local ifconfig = io.popen("ifconfig eth0")
if ifconfig then
local eth0 = ifconfig:read("*a")
ifconfig:close()
myip = string.match(eth0,"inet addr%:(%d+%.%d+%.%d+%.%d+)")
end
return myip
end
local function LoadChannelList(infile)
local cl = nil
local f = nil
if infile then
f = io.open(infile,"r")
else
f = io.open("/config/ChannelList.json","r")
end
if f then
local t = f:read("*a")
f:close()
local decode = newdecoder()
cl = decode(t)
end
return cl
end
local function Report(count,Title)
local f = io.open("/tmp/doscan.lock/doscan.tmp","w+")
if f then
f:write(count..":"..Title)
f:close()
os.execute("mv /tmp/doscan.lock/doscan.tmp /tmp/doscan.lock/doscan.msg")
end
end
local infile = nil
local outfile = "/config/epg.gz"
local ipAddr = nil
local a
for _,a in ipairs(arg) do
local par,val = a:match("(%a+)=(.+)")
if par == "in" then
infile = val
elseif par == "out" then
outfile = val
elseif par == "ip" then
ipAddr = val
end
end
if not ipAddr then
ipAddr = GetIPAddr()
end
local cl = LoadChannelList(infile)
local Max = 999999
local Count = 0
local ChannelCount = 0
local EventCount = 0
Report(ChannelCount,"*")
local tl = {}
local Options = ""
if not cl then
Report(0,"Channellist not Found, channelscan required")
elseif not cl.GroupList then
Report(0,"Invalid channellist")
else
local Group
for _,Group in ipairs(cl.GroupList) do
for _,Channel in ipairs(Group.ChannelList) do
if Channel.ID then
local Params = ""
local p,v
for p,v in Channel.Request:gmatch("(%a+)=([%w%.]+)") do
if p == "src" then
Params = Params .. " --src="..v
elseif p == "freq" then
Params = Params .. " --freq="..v
elseif p == "pol" then
Params = Params .. " --pol="..v
elseif p == "msys" then
Params = Params .. " --msys="..v
elseif p == "sr" then
Params = Params .. " --sr="..v
elseif p == "mtype" then
Params = Params .. " --mtype="..v
end
end
local Key,Sid = Channel.ID:match("^(%a+):%d+:%d+:(%d+)")
if Key and Sid then
local t = tl[Params]
if t then
t.Sids = t.Sids..","..Sid
else
tl[Params] = { Key=Key, Sids=Sid }
ChannelCount = ChannelCount + 1
end
end
end
end
end
os.execute("rm "..outfile)
local gzip = io.popen('gzip >'..outfile..".tmp","w")
if gzip then
gzip:write('{"EventList":[');
local newline = "\n "
local Params
local Key, t
for Params,t in pairs(tl) do
Report(Count,"of "..ChannelCount.." transponders, "..EventCount.." events")
Count = Count + 1
Key = t.Key
print("--------------------------------------------------------------")
collectgarbage();
local cmd = 'octoscan --eit_sid '..t.Sids..' '..Options..Params..' '..ipAddr
print(cmd)
local octoscan = io.popen(cmd,"r")
if octoscan then
while true do
local line = octoscan:read("*l")
if not line then
break
end
--~ print(line)
local eid = nil
local name = nil
local text = nil
local time = nil
local duration = nil
local language = nil
if line == "EVENT" then
while true do
line = octoscan:read("*l")
if not line then
break
end
--~ print(line)
if line == "END" then
if eid then
local event = { ID = Key..":"..eid }
if name then
event.Name = name
end
if text then
event.Text = text
end
if time then
event.Time = time
end
if duration then
event.Duration = duration
end
-- if language then
-- event.Language = language
-- end
local encode = newencoder()
local e = encode(event)
gzip:write(newline..e)
newline = ",\n "
EventCount = EventCount + 1
end
collectgarbage();
break
end
local par,val = line:match("^ (%a+):(.*)")
if par == "ID" then
eid = val
elseif par == "NAME" then
name = val
elseif par == "TEXT" then
text = val
elseif par == "TIME" then
time = val
elseif par == "DUR" then
duration = val
-- elseif par == "LANG" then
-- language = val
end
end
end
end
octoscan:close()
end
end
gzip:write("\n]}")
gzip:close()
else
Report(0,"Internal error")
end
--~ if outfile == "/config/ChannelList.json" then
--~ os.execute("mv /config/ChannelList.json /config/ChannelList.bak")
--~ end
Report(ChannelCount,"EPG done "..EventCount.." events")
end
os.execute("mv "..outfile..".tmp "..outfile)
os.execute("mv /tmp/doscan.lock/doscan.msg /tmp/doscan.msg")
os.execute("rm -rf /tmp/doscan.lock");

View File

@ -218,7 +218,7 @@ if tl.SourceList then
local tracks= { }
local isradio = false
local isencrypted = false
if line == "BEGIN" then
if line == "SERVICE" then
while true do
line = octoscan:read("*l")
if not line then
@ -261,8 +261,8 @@ if tl.SourceList then
if ChannelOverwrite.Group then
gname = ChannelOverwrite.Group
end
if ChannelOverwrite.pids then
gname = ChannelOverwrite.pids
if ChannelOverwrite.Pids then
gname = ChannelOverwrite.Pids
end
if ChannelOverwrite.Title then
sname = ChannelOverwrite.Title
@ -355,7 +355,7 @@ if tl.SourceList then
end
Report(ChannelCount,"Done")
Report(ChannelCount,"Channels found")
os.execute("mv /tmp/doscan.lock/doscan.msg /tmp/doscan.msg")
if restart_dms then

View File

@ -104,6 +104,7 @@ function OnLoad()
function DisableButtons(disabled)
{
document.getElementById("EpgButton").disabled = disabled;
document.getElementById("ScanButton").disabled = disabled;
document.getElementById("StatusButton").disabled = disabled;
document.getElementById("DeleteButton").disabled = disabled;
@ -156,7 +157,7 @@ function ScanStatus(response)
else if( s.status == "done" )
{
document.getElementById("scancount").firstChild.nodeValue = s.count;
document.getElementById("scantext").firstChild.nodeValue = "Channels found";
document.getElementById("scantext").firstChild.nodeValue = s.msg;
}
else if( s.status == "deleted" )
{
@ -242,6 +243,16 @@ function InitiateScan()
}
}
function InitiateEPGScan()
{
DisableButtons(true);
ScanReq.open("POST", "/channelscan.lua", true);
ScanReq.setRequestHeader("Content-type","application/x-www-form-urlencoded");
ScanReq.send("select=epg");
document.getElementById("scancount").firstChild.nodeValue = "\u00A0";
document.getElementById("scantext").firstChild.nodeValue = "Scanning...";
}
function PollStatus()
{
DisableButtons(true);
@ -350,8 +361,9 @@ function Uploader(event)
<td>&nbsp;</td>
<td style="text-align:right">
<form action="">
<input id="ScanButton" type="Button" value="Start Scan" onclick="InitiateScan()" >
<input id="StatusButton" type="Button" value="Get Status" onclick="PollStatus()" >
<input id="ScanButton" type="Button" value="Start Channel Scan" onclick="InitiateScan()" >
<input id="EpgButton" type="Button" value="Start EPG Scan" onclick="InitiateEPGScan()" >
</form>
</td>
</tr>
@ -367,8 +379,8 @@ function Uploader(event)
<td>&nbsp;</td>
<td style="text-align:right">
<form action="">
<input id="DeleteButton" type="Button" value="Delete Scan" onclick="DeleteScan()" >
<input id="RestoreButton" type="Button" value="Restore Previous Scan" onclick="RestoreScan()" >
<input id="DeleteButton" type="Button" value="Delete Channel List" onclick="DeleteScan()" >
<input id="RestoreButton" type="Button" value="Restore Previous Channel List" onclick="RestoreScan()" >
</form>
</td>
</tr>

View File

@ -159,7 +159,7 @@ local function Keys()
return data
end
local function Scan(params)
local function Scan(cmd,params)
local data = nil
local rc = os.execute("mkdir /tmp/doscan.lock")
if rc ~= 0 then
@ -171,7 +171,7 @@ local function Scan(params)
f:write("Scanning")
f:close()
end
os.execute("/var/channels/doscan.lua "..params.." >/tmp/doscan.log 2>&1 &")
os.execute("/var/channels/do"..cmd..".lua "..params.." >/tmp/doscan.log 2>&1 &")
end
return data
end
@ -336,7 +336,9 @@ end
if cmd == "keys" then
data = Keys()
elseif cmd == "scan" then
data = Scan(params)
data = Scan("scan",params)
elseif cmd == "epg" then
data = Scan("epgscan",params)
elseif cmd == "status" then
data = Status()
elseif cmd == "delete" then

304
octoserve/var/www/epg.html Normal file
View File

@ -0,0 +1,304 @@
<!DOCTYPE HTML>
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
<title>OctopusNet</title>
<link rel="stylesheet" type="text/css" href="/style.css">
<script type="text/javascript" src="/menu.js"></script>
<!-- Add included scripts here -->
<!-- Add page scripts here -->
<style>
.event_scroll {
text-align:right;
margin-left: auto;
margin-right: 2px;
width: 650px;
}
.event {
color:#000000;
background-color:#FFC0FF;
text-align:left;
margin-top: 3px;
margin-left: auto;
margin-right: auto;
width: 650px;
border-radius: 15px;
padding: 10px;
}
.event_date {
display: inline-block;
font-weight: bold;
width: 330px;
text-align:left;
}
.event_duration {
display: inline-block;
width: 100px;
text-align:left;
}
.event_channel {
display: inline-block;
width: 200px;
text-align:left;
}
.event_name {
display: block;
font-size: 1em;
font-weight: bold;
text-align:left;
}
.event_text {
display: block;
margin-left: 20px;
text-align:left;
}
.message {
color:#FF0000;
font-size: 1.5em;
font-weight: bold;
text-align:center;
margin-top: 3px;
margin-left: auto;
margin-right: auto;
width: 650px;
}
</style>
<script type="text/javascript">
var reqChannelList = new XMLHttpRequest();
reqChannelList.onreadystatechange=function()
{
if (reqChannelList.readyState == 4 )
{
if( reqChannelList.status == 200 )
ChannelListResponse(reqChannelList.responseText);
else if( reqChannelList.status == 404 )
document.getElementById("message").firstChild.nodeValue = "Error loading channellist";
}
}
var reqEPG = new XMLHttpRequest();
reqEPG.onreadystatechange=function()
{
if (reqEPG.readyState == 4 )
{
if( reqEPG.status == 200 )
EPGResponse(reqEPG.responseText);
else if ( reqEPG.status == 404 )
document.getElementById("message").firstChild.nodeValue = "EPG not available";
}
}
var EPG = null;
var ChannelList = null;
var ChannelLookup = null;
function LoadEPG()
{
reqEPG.open("GET", "/epg.lua", true);
reqEPG.send();
}
function ChannelListResponse(response)
{
ChannelList = JSON.parse(response);
if( ChannelList.GroupList[0].ChannelList[0].ID )
{
ChannelLookup = new Object();
for(var i = 0; i < ChannelList.GroupList.length; i += 1)
{
var Group = ChannelList.GroupList[i];
for(var j = 0; j < Group.ChannelList.length; j += 1)
{
ChannelLookup[Group.ChannelList[j].ID] = Group.ChannelList[j];
}
}
LoadEPG();
}
else
{
document.getElementById("message").firstChild.nodeValue = "EPG not available";
}
}
function CompareTime(a,b)
{
//~ if( a.Time > b.Time ) return 1;
//~ if( a.Time < b.Time ) return -1;
return ( a.Time > b.Time ) ? 1 : -1;
}
var Position = 2000;
function EPGResponse(response)
{
try
{
EPG = JSON.parse(response);
document.getElementById("message").firstChild.nodeValue = "Sorting...";
EPG.EventList.sort(CompareTime);
document.getElementById("message").firstChild.nodeValue = EPG.EventList.length + " Events";
document.getElementById("message").style.display = "none";
document.getElementById("events").style.display = "block";
Current();
}
catch(e)
{
document.getElementById("message").firstChild.nodeValue = e.message;
}
}
function OnLoad()
{
document.getElementById("events").style.display = "none";
EPG = null;
var msg = document.getElementById("message");
msg.firstChild.nodeValue = "Loading...";
msg.style.display = "block";
reqChannelList.open("GET", "/channellist.lua?select=json", true);
reqChannelList.send();
}
function Current() {
Position = Search(new Date())
Scroll(0);
}
function Scroll(amount)
{
Position += amount;
if( Position < 0 )
Position = 0;
else if( Position + 1 >= EPG.EventList.length )
Position = EPG.EventList.length - 5;
for( var i = 0; i < 5; i += 1 )
{
ShowEvent(EPG.EventList[Position+i],i);
}
}
function Search(d)
{
var a = 0;
var b = EPG.EventList.length - 1;
var i;
while((b - a) > 1)
{
i = Math.floor(a + (b - a)/2);
d1 = new Date(EPG.EventList[i].Time);
if( d1 >= d )
b = i;
else
a = i;
}
return b;
}
function ShowEvent(event,index)
{
var box = document.getElementById("event" + index);
var d = new Date(event.Time);
var id = event.ID.match(/[A-Z]+:\d+:\d+:\d+/);
var ch = ChannelLookup[id[0]];
var Channel = "\u00A0";
var Text = "";
var Name = "";
if( ch ) Channel = ch.Title;
if( event.Text ) Text = event.Text;
if( event.Name ) Name = event.Name;
box.getElementsByClassName("event_date")[0].firstChild.nodeValue = d.toLocaleString();
box.getElementsByClassName("event_duration")[0].firstChild.nodeValue = event.Duration;
box.getElementsByClassName("event_channel")[0].firstChild.nodeValue = Channel;
box.getElementsByClassName("event_name")[0].firstChild.nodeValue = Name;
box.getElementsByClassName("event_text")[0].firstChild.nodeValue = Text;
}
</script>
</head>
<body onload="OnLoad()">
<table class="maintable">
<colgroup>
<col style="width: 182px"/>
<col style="width: 728px"/>
</colgroup>
<tr><td class="maintd" colspan="2">
<a href="http://www.digitaldevices.de"><img src="/BannerDD.jpg" alt="DD" width="910" height="130" /></a>
</td></tr>
<tr><td class="maintd" colspan="2">&nbsp;</td></tr>
<tr>
<td class="maintd"><script type="text/javascript">CreateMenu();</script></td>
<td class="content">
<div>
<!-- Begin Content -->
<div id="message" class="message">&nbsp;</div>
<div id="events">
<div class="event_scroll">
<form action="">
<input type="Button" value="|<" onclick="Scroll(-9999999)" >
<input type="Button" value="<<<" onclick="Scroll(-500)" >
<input type="Button" value="<<" onclick="Scroll(-50)" >
<input type="Button" value="<" onclick="Scroll(-5)" >
<input type="Button" value="[]" onclick="Current()" >
<input type="Button" value=">" onclick="Scroll(+5)" >
<input type="Button" value=">> " onclick="Scroll(+50)" >
<input type="Button" value=">>>" onclick="Scroll(+500)" >
<input type="Button" value=">|" onclick="Scroll(+9999999)" >
</form>
</div>
<div id="event0" class="event">
<div class="event_date">&nbsp;</div>
<div class="event_duration">&nbsp;</div>
<div class="event_channel">&nbsp;</div>
<div class="event_name">&nbsp;</div>
<div class="event_text">&nbsp;</div>
</div>
<div id="event1" class="event">
<div class="event_date">&nbsp;</div>
<div class="event_duration">&nbsp;</div>
<div class="event_channel">&nbsp;</div>
<div class="event_name">&nbsp;</div>
<div class="event_text">&nbsp;</div>
</div>
<div id="event2" class="event">
<div class="event_date">&nbsp;</div>
<div class="event_duration">&nbsp;</div>
<div class="event_channel">&nbsp;</div>
<div class="event_name">&nbsp;</div>
<div class="event_text">&nbsp;</div>
</div>
<div id="event3" class="event">
<div class="event_date">&nbsp;</div>
<div class="event_duration">&nbsp;</div>
<div class="event_channel">&nbsp;</div>
<div class="event_name">&nbsp;</div>
<div class="event_text">&nbsp;</div>
</div>
<div id="event4" class="event">
<div class="event_date">&nbsp;</div>
<div class="event_duration">&nbsp;</div>
<div class="event_channel">&nbsp;</div>
<div class="event_name">&nbsp;</div>
<div class="event_text">&nbsp;</div>
</div>
</div>
<!-- End Content -->
</div>
</td>
</tr>
<tr><td colspan="2">&nbsp;</td></tr>
</table>
</body>
</html>

73
octoserve/var/www/epg.lua Normal file
View File

@ -0,0 +1,73 @@
#!/usr/bin/lua
local host = os.getenv("HTTP_HOST")
local proto = os.getenv("SERVER_PROTOCOL")
local query = os.getenv("QUERY_STRING")
local method = os.getenv("REQUEST_METHOD")
local clength = os.getenv("CONTENT_LENGTH")
local ctype = os.getenv("CONTENT_TYPE")
function http_print(s)
if s then
io.stdout:write(tostring(s).."\r\n")
else
io.stdout:write("\r\n")
end
end
if #arg> 0 then
method="GET"
query="select=m3u"
proto = "HTTP/1.0"
end
function SendError(err,desc)
http_print(proto.." "..err)
http_print("Content-Type: text/html")
http_print()
local file = io.open("e404.html")
if file then
local tmp = file:read("*a")
tmp = string.gsub(tmp,"404 Not Found",err .. " " .. desc)
http_print(tmp)
file:close()
end
end
if method == "GET" then
local filename = "epg.json"
contenttype = "application/json; charset=utf-8"
local data = nil
local f = io.open("/config/epg.gz","r")
if not f then
f = io.open("/var/channels/epg.gz","r")
end
if f then
http_print(proto.." 200" )
http_print("Pragma: no-cache")
http_print("Cache-Control: no-cache")
http_print("Content-Type: "..contenttype)
if filename then
http_print('Content-Disposition: filename="'..filename..'"')
end
--http_print(string.format("Content-Length: %d",#data))
http_print(string.format("Content-Encoding: gzip"))
http_print()
while true do
data = f:read(65536)
if not data then
break
end
io.stdout:write(data)
end
f:close()
else
SendError("404","not found")
end
else
SendError("500","What")
end

View File

@ -3,59 +3,19 @@
MenuItems = new Array();
MenuItems[0] = new Object();
MenuItems[0].Text = "Home";
MenuItems[0].Link = "index.html";
MenuItems[1] = new Object();
MenuItems[1].Text = "Browser TV";
MenuItems[1].Link = "browsertv.html";
MenuItems[2] = new Object();
MenuItems[2].Text = "Stream Status";
MenuItems[2].Link = "streamstatus.html";
MenuItems[3] = new Object();
MenuItems[3].Text = "Tuner Status";
MenuItems[3].Link = "tunerstatus.html";
MenuItems[4] = new Object();
MenuItems[4].Text = "Unicable Settings";
MenuItems[4].Link = "scif.html";
MenuItems[5] = new Object();
MenuItems[5].Text = "LNB Settings";
MenuItems[5].Link = "lnbsettings.html";
MenuItems[6] = new Object();
MenuItems[6].Text = "System Settings";
MenuItems[6].Link = "system.html";
MenuItems[7] = new Object();
MenuItems[7].Text = "Multicast Setup";
MenuItems[7].Link = "multicast.html";
MenuItems[8] = new Object();
MenuItems[8].Text = "Channel Lists";
MenuItems[8].Link = "channellists.html";
MenuItems[9] = new Object();
MenuItems[9].Text = "Update";
MenuItems[9].Link = "update.html";
MenuItems[10] = new Object();
MenuItems[10].Text = "Reboot";
MenuItems[10].Link = "reboot.html";
MenuItems[11] = new Object();
MenuItems[11].Text = "Hardware Monitor";
MenuItems[11].Link = "monitor.html";
MenuItems[12] = new Object();
MenuItems[12].Text = "Licenses";
MenuItems[12].Link = "licenses.html";
// add additional items here
MenuItems.push( { Text:"Home", Link:"index.html" } );
MenuItems.push( { Text:"Browser TV", Link:"browsertv.html" } );
MenuItems.push( { Text:"EPG", Link:"epg.html" } );
MenuItems.push( { Text:"Stream Status", Link:"streamstatus.html" } );
MenuItems.push( { Text:"Tuner Status", Link:"tunerstatus.html" } );
MenuItems.push( { Text:"Unicable Settings", Link:"scif.html" } );
MenuItems.push( { Text:"LNB Settings", Link:"lnbsettings.html" } );
MenuItems.push( { Text:"System Settings", Link:"system.html" } );
MenuItems.push( { Text:"Multicast Setup", Link:"multicast.html" } );
MenuItems.push( { Text:"Channel Lists", Link:"channellists.html" } );
MenuItems.push( { Text:"Update", Link:"update.html" } );
MenuItems.push( { Text:"Hardware Monitor", Link:"monitor.html" } );
MenuItems.push( { Text:"Licenses", Link:"licenses.html" } );
// ---------------------------------------------------------------
// Don't touch

View File

@ -1,12 +1,12 @@
body {
color:#000000;
background-color:#000000;
margin:0;
color:#000000;
background-color:#000000;
margin:0;
font-family:Arial,sans-serif;
}
.maintable {
color:#000000;
color:#000000;
background-color:#FFFFFF;
text-align:center;
border:0;
@ -19,7 +19,7 @@ body {
}
.menutable {
color:#000000;
color:#000000;
background-color:#e0e0e0;
text-align:center;
border:5px;
@ -30,7 +30,7 @@ body {
}
.menucur {
color:#e0e0e0;
color:#e0e0e0;
background-color:#000000;
}
@ -44,7 +44,7 @@ body {
}
.content {
color:#000000;
color:#000000;
background-color:#FFFFF0;
text-align:left;
vertical-align:top;
@ -53,36 +53,36 @@ body {
}
.table {
color:#000000;
color:#000000;
text-align:center;
border:1px;
}
.tableleft {
color:#000000;
color:#000000;
float:center;
text-align:left;
border:1px;
}
#streamstatus {
color:#000000;
color:#000000;
text-align:center;
border:1px;
width:90%;
}
td#streamstatus {
color:#000080;
color:#000000;
}
#tunerstatus {
color:#000000;
color:#000000;
text-align:center;
border:1px;
width:60%;
}
a img {
border:none;
border:none;
}