--[[
	Tierwelt TV-App
	Vers.: 0.4
	Copyright
        (C) 2020 fritz

        Addon Description:
        The addon evaluates Videos from the Tierwelt-live.de Homepage and 
        provides the videos for playing with the neutrino media player on.

        This addon is not endorsed, certified or otherwise approved in any 
        way by Doclights GmbH.

        The plugin respects Doclights's General Terms and Conditions of Use, 
        which prohibits the publishing or making publicly available of any 
        software, app or similar which allows the livestream / videos to 
        be fully or partially definitely and permanently downloaded.

	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.

        Copyright (C) for the linked videos and for the Tierwelt TV -Logo by Doclights GmbH, Hamburg or the respective owners!
        Copyright (C) for the Base64 encoder/decoder function by Alex Kloss <alexthkloss@web.de>, licensed under the terms of the LGPL
]]

local json = require "json"

-- Auswahl 
local subs = {
	{'channels/8', 'BBC Earth'},
	{'channels/9', 'Die Erde von oben'},
	{'channels/10', 'Tiere beobachten'},
	{'channels/11', 'Natur genießen'},
	{'playlists/15', 'Amerika'},
	{'playlists/16', 'Südamerika'},
	{'playlists/17', 'Afrika'},
	{'playlists/18', 'Asien'},
	{'playlists/19', 'Europa'},
	{'playlists/42', 'Australien'},
	{'playlists/32', 'Weite Welt'},
	{'playlists/21', 'Tiere im Fokus'},
	{'playlists/33', 'Menschen und Tiere'},
	{'playlists/46', 'Klassiker'},
	{'playlists/24', 'Expeditionen'},
	{'playlists/45', 'Kielings Welt'},
	{'playlists/38', 'Die Erde von oben'},
	{'playlists/28', 'Kates Tierwelt'},
	{'playlists/37', 'Geschichten aus den Wäldern'},
	{'playlists/27', 'Naturfilme'},
	{'playlists/34', 'Eisige Welten'},
	{'playlists/25', 'Making of'},
	{'playlists/22', 'Die Tierärzte'},
	{'playlists/23', 'Tipps vom Tierarzt'},
	{'playlists/14', 'Raubkatzen'},
	{'playlists/26', 'Wildnis Blog'},
	{'playlists/48', '#6 Fighting Extinction'},
	{'playlists/44', 'Filmauswahl Welt'}
}

--Objekte
function script_path()
	local str = debug.getinfo(2, "S").source:sub(2)
	return str:match("(.*/)")
end

function init()
	n = neutrino();
	p = {}
	func = {}
	pmid = 0
	stream = 1
        tmpPath = "/tmp"
	tierwelt_tv = decodeImage("data:image/png;base64,[encoded data, 5428 characters]")
end

function add_stream(t,u,f,r)
  p[#p+1]={title=t,url=u,from=f,rubrik=r,access=stream}
end

function getdata(Url,outputfile)
	if Url == nil then return nil end
	if Curl == nil then
		Curl = curl.new()
	end
	local ret, data = Curl:download{url=Url,A="Mozilla/5.0;",followRedir=true,o=outputfile }
	if ret == CURL.OK then
		return data
	else
		return nil
	end
end

-- ####################################################################
-- Base64 encoder/decoder function

-- character table string
local b='ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/'

-- decode
function dec(data)
	data = string.gsub(data, '[^'..b..'=]', '')
	return (data:gsub('.', function(x)
    	if (x == '=') then return '' end
    	local r,f='',(b:find(x)-1)
    	for i=6,1,-1 do r=r..(f%2^i-f%2^(i-1)>0 and '1' or '0') end
    	return r;
	end):gsub('%d%d%d?%d?%d?%d?%d?%d?', function(x)
    	if (#x ~= 8) then return '' end
    	local c=0
    	for i=1,8 do c=c+(x:sub(i,i)=='1' and 2^(8-i) or 0) end
    	return string.char(c)
	end))
end

function decodeImage(b64Image)
	local imgTyp = b64Image:match("data:image/(.-);base64,")
	local repData = "data:image/" .. imgTyp .. ";base64,"
	local b64Data = string.gsub(b64Image, repData, "");

	local tmpImg = os.tmpname()
	local retImg = tmpImg .. "." .. imgTyp

	local f = io.open(retImg, "w+")
	f:write(dec(b64Data))
	f:close()
--	os.remove(tmpImg) -- only for testing

	return retImg
end

-- ####################################################################

-- Convert special characters
function conv_str(_string)
	if _string == nil then return _string end
        _string = string.gsub(_string,'\\','');
	_string = string.gsub(_string,"&amp;","&");
	_string = string.gsub(_string,"&quot;","'");
	_string = string.gsub(_string,"%s+%s+", "")
	return _string
end

function fill_playlist(id) --- > begin playlist
	p = {}
	for i,v in  pairs(subs) do
		if v[1] == id then
			sm:hide()
			nameid = v[2]	
			local data  = getdata('https://d36olg7tmj6zg3.cloudfront.net/20200304160755/restapi/' .. id .. '.json',nil)
			if data then
				for  item in data:gmatch('{.-"subtitle"(.-duration_in_ms.-)"slug"')  do
					title,description,pk = item:match('"title":.-"(.-)", .-"teaser":.-"(.-)",.-"pk": (.-),') 

					if title == nameid then
                                            title,description,pk  = item:match('"media".-"description".-"title":.-"(.-)", .-"teaser":.-"(.-)",.-"pk": (.-),')
                                        end  

					if pk and title then
						add_stream( conv_str(title),"https://d36olg7tmj6zg3.cloudfront.net/20200304160755/restapi/media/" .. pk .. ".json", conv_str(description), nameid )
					end
				end
			end
			select_playitem()
		end
	end
end --- > end of playlist

-- Duration
function msec_to_min(_string)
	local seconds = tonumber(_string/1000) -- json therefore returns time in msec
		if seconds <= 0 then
		return "00:00:00";
	else
		hours = string.format("%02.f", math.floor(seconds/3600));
		mins = string.format("%02.f", math.floor(seconds/60 - (hours*60)));
		secs = string.format("%02.f", math.floor(seconds - hours*3600 - mins *60));
--		return hours..":"..mins..":"..secs -- hours, minutes and seconds are displayed
		return " " ..mins.. " Min." -- only minutes are displayed, default
	end
end

local epg = ""
local title = ""

function epgInfo (xres, yres, aspectRatio, framerate)
	if #epg < 1 then return end
	local dx = 700;
	local dy = 400;
	local x = 290;
	local y = 0;

	local hw = n:getRenderWidth(FONT['MENU'],title) + 20
	if hw > 400 then
		dy = hw
	end
	if dy >  SCREEN.END_X - SCREEN.OFF_X - 20 then
		dy = SCREEN.END_X - SCREEN.OFF_X - 20
	end
	local wh = cwindow.new{x=x, y=y, dx=dx, dy=dy, title="", icon=tierwelt_tv, has_shadow="true", show_header="true", show_footer="false"};  -- with out footer
	dy = dy + wh:headerHeight()

	local ct = ctext.new{parent=wh, x=20, y=0, dx=0, dy=dy, text = epg, font_text=FONT['MENU'], mode = "ALIGN_SCROLL | DECODE_HTML"};
 	h = ct:getLines() * n:FontHeight(FONT['MENU'])
	h = (ct:getLines() +4) * n:FontHeight(FONT['MENU'])
	if h > SCREEN.END_Y - SCREEN.OFF_Y -20 then
		h = SCREEN.END_Y - SCREEN.OFF_Y -20
	end
 	wh:setDimensionsAll(x,y,dx,h)
        ct:setDimensionsAll(20,0,dx-40,h)
	wh:setCenterPos{3}
	wh:paint()

	repeat
		msg, data = n:GetInput(500)
		if msg == RC.up or msg == RC.page_up then
			ct:scroll{dir="up"};
		elseif msg == RC.down or msg == RC.page_down then
			ct:scroll{dir="down"};
		end
	until msg == RC.ok or msg == RC.home
	wh:hide()
end

function set_pmid(id)
  pmid=tonumber(id);
  return MENU_RETURN["EXIT_ALL"];
end

function select_playitem()
    local m=menu.new{name="", icon=tierwelt_tv}

  for i,r in  ipairs(p) do
    m:addItem{type="forwarder", action="set_pmid", id=i, icon="streaming", name=r.title, hint=r.from, hint_icon="hint_reload"}
  end

  repeat
    pmid=0
    m:exec()
    if pmid==0 then
      return
    end

    local vPlay = nil
    local url=func[p[pmid].access](p[pmid].url)
    if url~=nil then
      if  vPlay  ==  nil  then
	vPlay  =  video.new()
      end

	local js_data = getdata(url,nil)
	local video_url,title = js_data:match('"uuid":.-"(.-)".-"title": "(.-)",')
	local duration_in_ms = js_data:match('"duration_in_ms": (.-),')
        duration = "Dauer: " .. msec_to_min(duration_in_ms)
	epg1 = p[pmid].from
	title = p[pmid].title

	if video_url then 
		epg = 'Rubrik ' .. p[pmid].rubrik .. ': ' .. conv_str(title) .. '\n\n' .. conv_str(epg1) .. '\n\n' .. duration
		vPlay:setInfoFunc("epgInfo")
                url = 'https://cdn-media.tierwelt-live.de/' .. video_url ..'_twl_720p.m4v' -- 360p = _twl_0500_16x9.m4v, 480p = _twl_480p.m4v, 720p = _twl_720p.m4v
	        vPlay:PlayFile("Tierwelt TV",url," " .. conv_str(title), " " .. duration );
	else
		print("Video URL not found")
	end

   end
  until false

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 selectmenu()
	sm = menu.new{name="", icon=tierwelt_tv}
	sm:addItem{type="separator"}
	sm:addItem{type="back"}
	sm:addItem{type="separatorline"}
	local d = 0 -- directkey
	for i,v in  ipairs(subs) do
		d = d + 1
		local dkey = godirectkey(d)
		sm:addItem{type="forwarder", name=v[2], action="fill_playlist",id=v[1], hint=' Beiträge aus der Rubrik: ' ..v[2], directkey=dkey }
	end
	sm:exec()
end

--Main
init()
func={
  [stream]=function (x) return x end,
}

selectmenu()
os.execute("rm /tmp/lua*.png");
