-- vim:set ft=lua:
dofile(mg.document_root..'\\api\\util.lua')
ini='Setting\\HttpPublic.ini'
dir=edcb.GetPrivateProfile('SET', 'ModulePath', '', 'Common.ini')..'\\Tools\\'
ffmpeg=edcb.GetPrivateProfile('SET','ffmpeg',dir..'ffmpeg.exe',ini)
ffprobe=edcb.GetPrivateProfile('SET','ffprobe',dir..'ffprobe.exe',ini)
readex=edcb.GetPrivateProfile('SET','readex',dir..'readex.exe',ini)

mp4=tonumber(edcb.GetPrivateProfile('SET','mp4',0,ini))~=0

-- トランスコードするかどうか
XCODE=tonumber(mg.get_var(mg.request_info.query_string, 'xcode') or 1)~=0
-- 変換コマンド
quality=mg.get_var(mg.request_info.query_string, 'quality') or ''
if mp4 then
  XOPT=edcb.GetPrivateProfile('MOVIE',quality,'-vcodec libx264 -profile:v main -level 31 -b:v 896k -maxrate 4M -bufsize 4M -preset veryfast -g 120 -vf yadif=0:-1:1 -s 512x288 -r 30000/1001 -acodec aac -ab 128k -f mp4 -movflags frag_keyframe+empty_moov -',ini)
else
  XOPT=edcb.GetPrivateProfile('MOVIE',quality,'-vcodec libvpx -b:v 896k -quality realtime -cpu-used 1 -vf yadif=0:-1:1 -s 512x288 -r 30000/1001 -acodec libvorbis -ab 128k -f webm -',ini)
end

audio=tonumber(mg.get_var(mg.request_info.query_string, 'audio'))
if audio then
  if audio==0 then
    XOPT='-map 0:0 -map 0:1 -map 0:2 '..XOPT
  elseif audio<10 then
    XOPT='-map 0:0 -map 0:'..audio..' '..XOPT
  elseif audio==10 then
    XOPT='-filter_complex channelsplit[FL][FR] -map 0:v -map [FL] -map [FR] '..XOPT  --デュアルモノ[日]
  elseif audio==11 then
    XOPT='-filter_complex channelsplit[FL][FR] -map 0:v -map [FR] -map [FL] '..XOPT  --デュアルモノ[英]
  end
end

XCMD='"'..ffmpeg..'" -i pipe:0 '..XOPT
-- 変換後の拡張子
XEXT=mp4 and '.mp4' or '.webm'
-- 転送開始前に変換しておく量(bytes)
XPREPARE=tonumber(edcb.GetPrivateProfile('SET','xprepare',48128,ini))

r=edcb.GetRecFilePath((mg.get_var(mg.request_info.query_string,'reid') or 0))
v=edcb.GetRecFileInfo((mg.get_var(mg.request_info.query_string,'id') or 0))

if r then
  fpath=r
  if XCODE then
    -- トランスコード中のファイルがあればそっち使う
    f=edcb.FindFile(fpath..XEXT, 1)
    if f then
      fpath=fpath..XEXT
      XCODE=false
    end
  end
elseif v then
  fpath=v.recFilePath
else
  fpath=nil
  faddr=mg.get_var(mg.request_info.query_string,'fname')
  if faddr then
    if mg.get_var(mg.request_info.query_string,'public') then
      fpath=DocumentToNativePath(faddr)
    else
      -- 冗長表現の可能性を潰す
      faddr=edcb.Convert('utf-8','utf-8',faddr):gsub('[\\/]+','\\')
      for i,v in ipairs(GetLibraryPathList()) do
        -- ライブラリ配下にあるか＋禁止文字と正規化のチェック
        v=(v..'\\'):gsub('[\\/]+','\\')
        if faddr:sub(1,#v):lower()==v:lower() and not faddr:sub(#v+1):find('[\0-\x1f\x7f:*?"<>|]') and not faddr:sub(#v+1):find('%.\\') then
          fpath=faddr
          break
        end
      end
    end
  end
end

-- 転送開始位置(99分率)
offset=tonumber(mg.get_var(mg.request_info.query_string,'offset')) or 0

f=nil
if fpath then
  fname='xcode'..(fpath:match('%.[0-9A-Za-z]+$') or '')
  -- 拡張子を限定
  if mg.get_mime_type(fname):find('^video/') or fname:lower():find('%.ts$') or fname:lower():find('%.m2ts$') then
    f=edcb.io.open(fpath, 'rb')
    if f then
      meta=mg.get_var(mg.request_info.query_string,'meta')
      if meta then
        ff=edcb.FindFile and edcb.FindFile(ffprobe, 1)
        if ff then
          ff=edcb.io.popen('""'..ffprobe..'" -i "'..fpath..'" -hide_banner -show_format -show_entries format=duration 2>&1"', 'rb'):read('*a')
          meta={duration=ff:match('duration=(.-)\r\n'), audio={}}
          for v in ff:gmatch(':%sAudio:%s(.-)\r\n') do
             table.insert(meta.audio,v)
          end
        else
          meta={duration=GetDurationSec(f)}
        end
        f:close()
      else
        fsec,fsize=GetDurationSec(f,fpath)
        if offset~=0 and offset~=99 and fsec>0 and SeekSec(f,fsec*offset/99) then
          offset=f:seek('cur',0) or 0
        else
          offset=math.floor(fsize*offset/99/188)*188
        end
        if XCODE then
          f:close()
          -- 容量確保の可能性があるときは周期188+同期語0x47(188*256+0x47=48199)で対象ファイルを終端判定する
          sync=fname:lower():find('%.ts$') and edcb.GetPrivateProfile('SET','KeepDisk',0,'EpgTimerSrv.ini')~='0'
          f=edcb.io.popen('""'..readex..'" '..offset..(sync and ' 4p48199' or ' 4')..' "'..fpath..'" | '..XCMD..'"', 'rb')
          fname='xcode'..XEXT
        else
          f:seek('set', offset)
          XPREPARE=nil
        end
      end
    end
  end
end

if meta then
  ct='<?xml version="1.0" encoding="UTF-8" ?><entry>'..(type(meta)=='table' and (meta.duration~='N/A' and '<duration>'..meta.duration..'</duration>' or '')..'<audio>'..#meta.audio..'</audio>' or '<err>なし</err>')..'</entry>'
  mg.write('HTTP/1.1 200 OK\r\nContent-Type: text/xml\r\nContent-Length: '..#ct..'\r\nConnection: close\r\n\r\n', ct)
elseif not f then
  mg.write('HTTP/1.1 404 Not Found\r\nConnection: close\r\n\r\n')
else
  mg.write('HTTP/1.1 200 OK\r\nContent-Type: '..mg.get_mime_type(fname)..'\r\nContent-Disposition: filename='..mg.url_encode(fname)..'\r\nConnection: close\r\n\r\n')
  retry=0
  while true do
    buf=f:read(XPREPARE or 48128)
    XPREPARE=nil
    if buf and #buf ~= 0 then
      retry=0
      if not mg.write(buf) then
        -- キャンセルされた
        mg.cry('canceled')
        break
      end
    else
      -- 終端に達した。4秒間この状態が続けば対象ファイルへの追記が終息したとみなす
      retry=retry+1
      if XCODE or retry > 20 then
        mg.cry('end')
        break
      end
      edcb.Sleep(200)
    end
  end
  f:close()
end