1
0
mirror of https://github.com/DigitalDevices/octonet.git synced 2023-10-10 13:36:52 +02:00

Channelscan

Added features to TransponderList.json
   Allow to define sort order for channels
   Allow overwrite channel title,group,pids
   Define custom groups (i.e. favourites)

Removed client side sorting from browsertv.html
Reworked creating ChannelList.json from legacy database to allow
serveside sorting.
This commit is contained in:
mvoelkel 2016-01-24 12:58:42 +01:00
parent bbee4d1c4c
commit e65fb9aaab
6 changed files with 303 additions and 175 deletions

File diff suppressed because one or more lines are too long

View File

@ -51,7 +51,20 @@ local function GetGroup(ChannelList,Title)
return Group return Group
end end
local function cmp_title(a,b) local function CompareTitle(a,b)
if a.Order then
if b.Order then
if a.Order == b.Order then
return a.Title < b.Title
else
return a.Order < b.Order
end
else
return true
end
elseif b.Order then
return false
end
return a.Title < b.Title return a.Title < b.Title
end end
@ -108,9 +121,40 @@ if not ipAddr then
end end
local tl = LoadTransponderList(infile) local tl = LoadTransponderList(infile)
local CIMappings = {}
if tl.CIMapList then
local CIMap
local ID
for _,CIMap in ipairs(tl.CIMapList) do
for _,ID in ipairs(CIMap.CIMappings) do
CIMappings[ID] = CIMap
end
end
end
local ChannelOverwrites = {}
if tl.ChannelOverwriteList then
local ChannelOverwrite
for _,ChannelOverwrite in ipairs(tl.ChannelOverwriteList) do
ChannelOverwrites[ChannelOverwrite.ID] = ChannelOverwrite
end
end
local ChannelList = {} local ChannelList = {}
ChannelList.GroupList = {} ChannelList.GroupList = {}
if tl.GroupList then
local Group
local Order
for _,Group in ipairs(tl.GroupList) do
local g = GetGroup(ChannelList,Group.Title)
if Group.Order then
g.Order = Group.Order
end
end
end
local Max = 999999 local Max = 999999
local Count = 0 local Count = 0
local ChannelCount = 0 local ChannelCount = 0
@ -118,16 +162,14 @@ local ChannelCount = 0
Report(ChannelCount,"*") Report(ChannelCount,"*")
if tl.SourceList then if tl.SourceList then
local Source
for _,Source in ipairs(tl.SourceList) do for _,Source in ipairs(tl.SourceList) do
if keys[Source.Key] then if keys[Source.Key] then
Report(ChannelCount,Source.Title) Report(ChannelCount,Source.Title)
print("Scanning: "..Source.Title) print("Scanning: "..Source.Title)
local SourceOptions = "" local SourceOptions = ""
if Source.UseNIT then
SourceOptions = SourceOptions.."--use_nit "
end
if Source.DVBType == "S" then if Source.DVBType == "S" then
SourceOptions = '--src='..keys[Source.Key] SourceOptions = '--src='..keys[Source.Key].." "
end end
for _,Transponder in ipairs(Source.TransponderList) do for _,Transponder in ipairs(Source.TransponderList) do
@ -152,9 +194,14 @@ if tl.SourceList then
end end
end end
local Options = SourceOptions
if Transponder.UseNIT then
Options = SourceOptions.."--use_nit "
end
print("--------------------------------------------------------------") print("--------------------------------------------------------------")
print('octoscan '..SourceOptions..Params..' '..ipAddr) print('octoscan '..Options..Params..' '..ipAddr)
local octoscan = io.popen('octoscan '..SourceOptions..' '..Params..' '..ipAddr,"r") local octoscan = io.popen('octoscan '..Options..Params..' '..ipAddr,"r")
if octoscan then if octoscan then
while true do while true do
local line = octoscan:read("*l") local line = octoscan:read("*l")
@ -181,18 +228,24 @@ if tl.SourceList then
if line == "END" then if line == "END" then
local all_pids = "0" local all_pids = "0"
if include_sitables then if include_sitables then
if isencrypted then --~ if isencrypted then
all_pids = all_pids..",1" --~ all_pids = all_pids..",1"
end --~ end
all_pids = all_pids..",16,17,18,20" all_pids = all_pids..",16,17,18,20"
end end
if #pids > 0 then local cireq = ""
all_pids = all_pids..","..pids local ID = string.format("%s:%d:%d:%d",Source.Key,onid,tsid,sid)
if isencrypted then
local CIMap = CIMappings[ID]
if CIMap then
local pmt = pids:match("(%d+),?")
if pmt then
cireq = "&x_ci="..CIMap.Slot.."&x_pmt="..pmt.."."..sid
isencrypted = false
end
end
end end
local channel = { Title=sname,
Request = '?'..Request.."&pids="..all_pids,
Tracks=tracks,
ID = string.format("%s:%d:%d:%d",Source.Key,onid,tsid,sid) }
if pname == "" then if pname == "" then
pname = Source.Title pname = Source.Title
end end
@ -200,6 +253,29 @@ if tl.SourceList then
if isradio then if isradio then
gname = "Radio - "..gname gname = "Radio - "..gname
end end
local Order = none
local ChannelOverwrite = ChannelOverwrites[ID]
if ChannelOverwrite then
Order = ChannelOverwrite.Order
if ChannelOverwrite.Group then
gname = ChannelOverwrite.Group
end
if ChannelOverwrite.pids then
gname = ChannelOverwrite.pids
end
if ChannelOverwrite.Title then
sname = ChannelOverwrite.Title
end
end
if #pids > 0 then
all_pids = all_pids..","..pids
end
local channel = { Title=sname,
Request = '?'..Request..cireq.."&pids="..all_pids,
Tracks=tracks,
ID=ID, Order=Order }
if ((not isradio) or (include_radio > 0)) and ((not isencrypted) or (include_encrypted > 0)) then if ((not isradio) or (include_radio > 0)) and ((not isencrypted) or (include_encrypted > 0)) then
local group = GetGroup(ChannelList,gname) local group = GetGroup(ChannelList,gname)
if group then if group then
@ -247,13 +323,20 @@ if tl.SourceList then
for _,group in ipairs(ChannelList.GroupList) do for _,group in ipairs(ChannelList.GroupList) do
if sort then if sort then
table.sort(group.ChannelList,cmp_title) table.sort(group.ChannelList,CompareTitle)
end
for _,channel in ipairs(group.ChannelList) do
channel.Order = nil
end end
group.ChannelList[0] = #group.ChannelList group.ChannelList[0] = #group.ChannelList
end end
if sort then if sort then
table.sort(ChannelList.GroupList,cmp_title) table.sort(ChannelList.GroupList,CompareTitle)
end end
for _,group in ipairs(ChannelList.GroupList) do
group.Order = nil
end
ChannelList.GroupList[0] = #ChannelList.GroupList ChannelList.GroupList[0] = #ChannelList.GroupList
local encode = newencoder() local encode = newencoder()

View File

@ -127,12 +127,12 @@ function AddRow(table,name,request,tracks)
table.appendChild(row); table.appendChild(row);
} }
function TitleCompare(a,b) // function TitleCompare(a,b)
{ // {
if( a.Title.toUpperCase() < b.Title.toUpperCase() ) return -1; // if( a.Title.toUpperCase() < b.Title.toUpperCase() ) return -1;
if( a.Title.toUpperCase() > b.Title.toUpperCase() ) return 1; // if( a.Title.toUpperCase() > b.Title.toUpperCase() ) return 1;
return 0; // return 0;
} // }
var xmlhttp = new XMLHttpRequest(); var xmlhttp = new XMLHttpRequest();
var url = "/channellist.lua?select=json"; var url = "/channellist.lua?select=json";
@ -200,10 +200,10 @@ function myFunction(response) {
Index = Index + 1; Index = Index + 1;
} }
} }
for(var i = 0; i < SourceList.length; i++ ) // for(var i = 0; i < SourceList.length; i++ )
{ // {
SourceList[i].ChannelList.sort(TitleCompare); // SourceList[i].ChannelList.sort(TitleCompare);
} // }
document.Source.Select.selectedIndex = LastSource; document.Source.Select.selectedIndex = LastSource;
SetSource(LastSource); SetSource(LastSource);
} }

View File

@ -70,44 +70,52 @@ function CreateM3U(host)
return table.concat(m3u) return table.concat(m3u)
end end
function JSONSource(host,SourceList,Title,System) local function CompareTitle(a,b)
local json = {} return a.Title < b.Title
local src = "" end
local sep1 = "\n"
local sep2 = "\n" function Legacy2JSON()
local newencoder = require("lunajson.encoder")
local SourceList = LoadSourceList()
local ChannelList = {}
ChannelList.GroupList = {}
local Group
local Channel
local f,c
table.insert(json,' "'..Title..'": [')
sep1 = "\n"
for _,f in pairs(SourceList) do for _,f in pairs(SourceList) do
if not System or f.system == System or f.system == System.."2" then Group = { Title=f.title, ChannelList = { } }
table.insert(json,sep1) table.insert(ChannelList.GroupList,Group)
sep1 = ",\n"
table.insert(json,' {\n')
table.insert(json,' "Title": "'..f.title..'",\n')
table.insert(json,' "ChannelList": [')
if System == "dvbs" then if f.system == "dvbs" or f.system == "dvbs2" then
src = 'src='..f.src..'&' src = 'src='..f.src..'&'
end
for _,c in ipairs(f.ChannelList) do
local tracks = {}
local track
for track in c.tracks:gmatch("%d+") do
table.insert(tracks,tonumber(track))
end end
tracks[0] = #tracks
sep2 = "\n" Channel = { Title=c.title,
for _,c in ipairs(f.ChannelList) do Request = '?'..src..c.request,
table.insert(json,sep2) Tracks=tracks }
sep2 = ",\n"
table.insert(json,' {\n')
table.insert(json,' "Title": "'..string.gsub(c.title,'"','\\"')..'",\n')
table.insert(json,' "Request": "?'..src..c.request..'",\n')
table.insert(json,' "Tracks": ['..c.tracks..']\n')
table.insert(json,' }')
end
table.insert(json,'\n ]\n') table.insert(Group.ChannelList,Channel)
table.insert(json,' }')
end end
end end
table.insert(json,'\n ]')
return table.concat(json) for _,Group in ipairs(ChannelList.GroupList) do
table.sort(Group.ChannelList,CompareTitle)
Group.ChannelList[0] = #Group.ChannelList
end
table.sort(ChannelList.GroupList,CompareTitle)
ChannelList.GroupList[0] = #ChannelList.GroupList
local encode = newencoder()
local data = encode(ChannelList)
return data
end end
function CreateJSON(host) function CreateJSON(host)
@ -117,17 +125,7 @@ function CreateJSON(host)
data = file:read("*a") data = file:read("*a")
file:close() file:close()
else else
local SourceList = LoadSourceList() data = Legacy2JSON()
local json = {}
table.insert(json,"{\n")
table.insert(json,JSONSource(host,SourceList,"GroupList",nil) .. "\n")
--~ table.insert(json,JSONSource(host,SourceList,"SourceListSat","dvbs") .. ",\n")
--~ table.insert(json,JSONSource(host,SourceList,"SourceListCable","dvbc") .. ",\n")
--~ table.insert(json,JSONSource(host,SourceList,"SourceListTer","dvbt") .. "\n")
table.insert(json,"}\n")
data = table.concat(json)
end end
return data return data
end end
@ -160,6 +158,7 @@ if method == "GET" then
contenttype = "text/m3u; charset=utf-8" contenttype = "text/m3u; charset=utf-8"
data = CreateM3U(host) data = CreateM3U(host)
elseif string.match(query,"select=json") then elseif string.match(query,"select=json") then
filename = "ChannelList.json"
contenttype = "application/json; charset=utf-8" contenttype = "application/json; charset=utf-8"
data = CreateJSON(host) data = CreateJSON(host)
end end

View File

@ -130,38 +130,36 @@ ScanReq.onreadystatechange=function()
function GetStatus() function GetStatus()
{ {
ScanReq.open("GET", "/channelscan.lua?select=status", true); ScanReq.open("GET", "/channelscan.lua?select=status&t=" + Math.random(), true);
ScanReq.send(); ScanReq.send();
} }
function ScanStatus(response) function ScanStatus(response)
{ {
var s = JSON.parse(response); var s = JSON.parse(response);
var done = false; var done = true;
if( s.status ) if( s.status )
{ {
if( s.status == "active" ) if( s.status == "active" )
{ {
document.getElementById("scancount").firstChild.nodeValue = s.count; document.getElementById("scancount").firstChild.nodeValue = s.count;
document.getElementById("scantext").firstChild.nodeValue = s.msg; document.getElementById("scantext").firstChild.nodeValue = s.msg;
done = false;
} }
else if( s.status == "busy" ) else if( s.status == "busy" )
{ {
document.getElementById("scancount").firstChild.nodeValue = "\u00A0"; document.getElementById("scancount").firstChild.nodeValue = "\u00A0";
document.getElementById("scantext").firstChild.nodeValue = "BUSY"; document.getElementById("scantext").firstChild.nodeValue = "BUSY";
done = true;
} }
else if( s.status == "done" ) else if( s.status == "done" )
{ {
document.getElementById("scancount").firstChild.nodeValue = s.count; document.getElementById("scancount").firstChild.nodeValue = s.count;
document.getElementById("scantext").firstChild.nodeValue = "Channels found"; document.getElementById("scantext").firstChild.nodeValue = "Channels found";
done = true;
} }
else if( s.status == "deleted" ) else if( s.status == "deleted" )
{ {
document.getElementById("scancount").firstChild.nodeValue = "\u00A0"; document.getElementById("scancount").firstChild.nodeValue = "\u00A0";
document.getElementById("scantext").firstChild.nodeValue = "Channel list deleted"; document.getElementById("scantext").firstChild.nodeValue = "Channel list deleted";
done = true;
} }
else if( s.status == "restored" ) else if( s.status == "restored" )
{ {
@ -170,7 +168,10 @@ function ScanStatus(response)
document.getElementById("scantext").firstChild.nodeValue = "Nothing restored"; document.getElementById("scantext").firstChild.nodeValue = "Nothing restored";
else else
document.getElementById("scantext").firstChild.nodeValue = "Previous channel list restored"; document.getElementById("scantext").firstChild.nodeValue = "Previous channel list restored";
done = true; }
else if( s.status == "retry" )
{
done = false;
} }
} }
@ -216,8 +217,9 @@ function InitiateScan()
if( param != "" ) if( param != "" )
{ {
ScanReq.open("GET", "/channelscan.lua?select=scan" + param + "&sitables=1&sort=1&restartdms=1", true); ScanReq.open("POST", "/channelscan.lua", true);
ScanReq.send(); ScanReq.setRequestHeader("Content-type","application/x-www-form-urlencoded");
ScanReq.send("select=scan" + param + "&sitables=1&sort=1&restartdms=1");
document.getElementById("scancount").firstChild.nodeValue = "\u00A0"; document.getElementById("scancount").firstChild.nodeValue = "\u00A0";
document.getElementById("scantext").firstChild.nodeValue = "Scanning..."; document.getElementById("scantext").firstChild.nodeValue = "Scanning...";
} }
@ -237,15 +239,16 @@ function PollStatus()
function DeleteScan() function DeleteScan()
{ {
DisableButtons(true); DisableButtons(true);
ScanReq.open("GET", "/channelscan.lua?select=delete", true); ScanReq.setRequestHeader("Content-type","application/x-www-form-urlencoded");
ScanReq.send(); ScanReq.send("select=delete");
} }
function RestoreScan() function RestoreScan()
{ {
DisableButtons(true); DisableButtons(true);
ScanReq.open("GET", "/channelscan.lua?select=restore", true); ScanReq.open("POST", "/channelscan.lua", true);
ScanReq.send(); ScanReq.setRequestHeader("Content-type","application/x-www-form-urlencoded");
ScanReq.send("select=restore");
} }
</script> </script>

View File

@ -55,121 +55,164 @@ local function LoadTransponderList()
return tl return tl
end end
if method == "GET" then local function GetCMD(s)
local filename = nil
local contenttype = "application/json; charset=utf-8"
local data = nil
local q,v local q,v
local params = "" local params = ""
local cmd = "" local cmd = ""
for q,v in query:gmatch("(%a+)=([%w%.]+)") do for q,v in s:gmatch("(%a+)=([%w%.]+)") do
if q == "select" then if q == "select" then
cmd = v cmd = v
else elseif q ~= "t" then
params = params.." "..q.."="..v params = params.." "..q.."="..v
end end
end end
return cmd,params
end
if cmd == "keys" then local function Keys()
local tl = LoadTransponderList() local data = nil
if tl then local tl = LoadTransponderList()
local kl = { KeyList = { } } if tl then
local s local kl = { KeyList = { } }
for _,s in ipairs(tl.SourceList) do local s
table.insert(kl.KeyList, { Key=s.Key,Title=s.Title,DVBType=s.DVBType }) for _,s in ipairs(tl.SourceList) do
end table.insert(kl.KeyList, { Key=s.Key,Title=s.Title,DVBType=s.DVBType })
kl.KeyList[0] = #kl.KeyList
local encode = newencoder()
data = encode(kl)
end end
elseif cmd == "scan" then kl.KeyList[0] = #kl.KeyList
local rc = os.execute("mkdir /tmp/doscan.lock") local encode = newencoder()
if rc ~= 0 then data = encode(kl)
data = '{"status":"busy"}' end
else return data
data = '{"status":"retry"}' end
local f = io.open("/tmp/doscan.msg","w+")
if f then local function Scan(params)
f:write("Scanning") local data = nil
f:close() local rc = os.execute("mkdir /tmp/doscan.lock")
end if rc ~= 0 then
os.execute("/var/channels/doscan.lua "..params.." >/tmp/doscan.log 2>&1 &") data = '{"status":"busy"}'
end else
elseif cmd == "status" then data = '{"status":"retry"}'
local js = { } local f = io.open("/tmp/doscan.msg","w+")
local f = io.open("/tmp/doscan.lock/doscan.msg") if f then
f:write("Scanning")
f:close()
end
os.execute("/var/channels/doscan.lua "..params.." >/tmp/doscan.log 2>&1 &")
end
return data
end
local function Status()
local data = nil
local js = { }
local f = io.open("/tmp/doscan.lock/doscan.msg")
if f then
js.status = "active"
local m = f:read("*l")
local count,msg = m:match("(%d+):(.*)")
js.count = count
js.msg = msg
f:close()
else
f = io.open("/tmp/doscan.msg")
if f then if f then
js.status = "active"
local m = f:read("*l") local m = f:read("*l")
local count,msg = m:match("(%d+):(.*)") local count,msg = m:match("(%d+):(.*)")
js.count = count if count and msg then
js.msg = msg js.count = count
js.msg = msg
js.status = "done"
else
if m == "Scanning" then
js.status = "retry"
else
js.status = nil
end
end
f:close() f:close()
else else
f = io.open("/tmp/doscan.msg") js.status = ""
if f then
local m = f:read("*l")
local count,msg = m:match("(%d+):(.*)")
if count and msg then
js.count = count
js.msg = msg
js.status = "done"
else
if m == "Scanning" then
js.status = "retry"
else
js.status = nil
end
end
f:close()
else
js.status = ""
end
end
local encode = newencoder()
data = encode(js)
elseif cmd == "delete" then
local rc = os.execute("mkdir /tmp/doscan.lock")
if rc ~= 0 then
data = '{"status":"busy"}'
else
data = '{"status":"deleted"}'
os.execute("rm /config/ChannelList.json");
os.execute("rm /tmp/doscan.msg");
os.execute("rm -rf /tmp/doscan.lock");
end
elseif cmd == "restore" then
local rc = os.execute("mkdir /tmp/doscan.lock")
if rc ~= 0 then
data = '{"status":"busy"}'
else
local rc = os.execute("mv /config/ChannelList.bak /config/ChannelList.json");
if rc == 0 then
data = '{"status":"restored", "count":1}'
else
data = '{"status":"restored", "count":0}'
end
os.execute("rm /tmp/doscan.msg");
os.execute("rm -rf /tmp/doscan.lock");
end end
end end
local encode = newencoder()
data = encode(js)
return data
end
if data then local function Delete()
http_print(proto.." 200" ) local data = nil
http_print("Pragma: no-cache") local rc = os.execute("mkdir /tmp/doscan.lock")
http_print("Cache-Control: no-cache") if rc ~= 0 then
http_print("Content-Type: "..contenttype) data = '{"status":"busy"}'
if filename then
http_print('Content-Disposition: filename="'..filename..'"')
end
http_print(string.format("Content-Length: %d",#data))
http_print()
http_print(data)
else else
SendError("404","not found") data = '{"status":"deleted"}'
os.execute("rm /config/ChannelList.json");
os.execute("rm /tmp/doscan.msg");
os.execute("rm -rf /tmp/doscan.lock");
end end
return data
end
local function Restore()
local data = nil
local rc = os.execute("mkdir /tmp/doscan.lock")
if rc ~= 0 then
data = '{"status":"busy"}'
else
local rc = os.execute("mv /config/ChannelList.bak /config/ChannelList.json");
if rc == 0 then
data = '{"status":"restored", "count":1}'
else
data = '{"status":"restored", "count":0}'
end
os.execute("rm /tmp/doscan.msg");
os.execute("rm -rf /tmp/doscan.lock");
end
return data
end
local filename = nil
local contenttype = "application/json; charset=utf-8"
local data = nil
local cmd = ""
local params
if method == "GET" then
cmd,params = GetCMD(query)
elseif method == "POST" and clength and ctype then
if ctype:match("application/x%-www%-form%-urlencoded") then
local query = io.read(tonumber(clength))
query = string.gsub(query,"\r","")
cmd,params = GetCMD(query)
end
else else
SendError("500","What") SendError("500","What")
return
end
if cmd == "keys" then
data = Keys()
elseif cmd == "scan" then
data = Scan(params)
elseif cmd == "status" then
data = Status()
elseif cmd == "delete" then
data = Delete()
elseif cmd == "restore" then
data = Restore()
end
if data 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()
http_print(data)
else
SendError("404","not found")
end end