aboutsummaryrefslogblamecommitdiffstatshomepage
path: root/home/.config/mpv/scripts/webtorrent-hook.lua
blob: 80d991ffffe78e37570b74f51b0f36e343da952b (plain) (tree)








































































































































                                                                                                                           
-- TODO prefetch if next in playlist?
-- TODO handle torrent with multiple video files (if webtorrent can print json)
-- - don't close kill webtorrent while still videos unplayed? or in playlist?
-- - store titles/info when starting webtorrent and check stream-open-filename
--   for any item in playlist to see if it matches stored entry

local settings = {
   close_webtorrent = true,
   remove_files = true,
   download_directory = "/tmp/webtorrent",
   webtorrent_flags = "",
   webtorrent_verbosity = "speed"
}

(require "mp.options").read_options(settings, "webtorrent-hook")

local open_videos = {}

-- http://lua-users.org/wiki/StringRecipes
local function ends_with(str, ending)
   return ending == "" or str:sub(-#ending) == ending
end

-- https://stackoverflow.com/questions/132397/get-back-the-output-of-os-execute-in-lua
function os.capture(cmd, decolorize, raw)
   if decolorize then
      -- https://github.com/webtorrent/webtorrent-cli/issues/132
      -- TODO webtorrent should have a way to just print json information with
      -- no colors
      -- https://stackoverflow.com/questions/19296667/remove-ansi-color-codes-from-a-text-file-using-bash/30938702#30938702
      cmd = cmd .. " | sed -r 's/\\x1B\\[(([0-9]{1,2})?(;)?([0-9]{1,2})?)?[m,K,H,f,J]//g'"
   end
   local f = assert(io.popen(cmd, 'r'))
   local s = assert(f:read('*a'))
   f:close()
   if raw then return s end
   s = string.gsub(s, '^%s+', '')
   s = string.gsub(s, '%s+$', '')
   -- s = string.gsub(s, '[\n\r]+', ' ')
   return s
end

function read_file(file)
   local fh = assert(io.open(file, "rb"))
   local contents = fh:read("*all")
   fh:close()
   return contents
end

function play_torrent()
   local url = mp.get_property("stream-open-filename")
   if (url:find("magnet:") == 1 or url:find("peerflix://") == 1
       or url:find("webtorrent://") == 1 or ends_with(url, "torrent")) then
      if url:find("webtorrent://") == 1 then
         url = url:sub(14)
      end
      if url:find("peerflix://") == 1 then
         url = url:sub(12)
      end

      os.execute("mkdir -p " .. settings.download_directory)
      -- don't reuse files (so multiple mpvs works)
      local output_file = settings.download_directory
         .. "/webtorrent-output-" .. mp.get_time() .. ".log"
      -- --keep-seeding is to prevent webtorrent from quitting once the download
      -- is done
      local webtorrent_command = "webtorrent "
         .. settings.webtorrent_flags
         .. " --out '" .. settings.download_directory .. "' --keep-seeding \""
         .. url .. "\" > " .. output_file .. " 2>&1 & echo $!"
      mp.msg.info("Starting webtorrent server")
      mp.msg.info(webtorrent_command)
      local pid = os.capture(webtorrent_command)
      mp.msg.info("Waiting for webtorrent server")

      local url_command = "tail -f " .. output_file
         .. " | awk '/Server running at:/ {print $4; exit}'"
      local url = os.capture(url_command, true)
      mp.msg.info("Webtorrent server is up")

      local title_command = "awk '/(Seeding|Downloading): / "
         .. "{gsub(/(Seeding|Downloading): /, \"\"); print; exit}' "
         .. output_file
      local title = os.capture(title_command, true)
      mp.msg.info("Setting media title to: " .. title)
      mp.set_property("force-media-title", title)

      local path
      if title then
         path = settings.download_directory .. "/\"" .. title .. "\""
      end
      open_videos[url] = {title=title,path=path,pid=pid}

      mp.set_property("stream-open-filename", url)

      if settings.webtorrent_verbosity == "speed" then
         local printer_pid
         local printer_pid_file = settings.download_directory
            .. "/webtorrent-printer-" .. mp.get_time() .. ".pid"
         os.execute("tail -f " .. output_file
                       .. " | awk '/Speed:/' ORS='\r' & echo -n $! > "
                       .. printer_pid_file)
         printer_pid = read_file(printer_pid_file)
         mp.register_event("file-loaded",
                           function()
                              os.execute("kill " .. printer_pid)
                           end
         )
      end
   end
end

function webtorrent_cleanup()
   local url = mp.get_property("stream-open-filename")
   if settings.close_webtorrent and open_videos[url] then
      local title = open_videos[url].title
      local path = open_videos[url].path
      local pid = open_videos[url].pid

      if pid then
         mp.msg.info("Closing webtorrent for " .. title .. " with pid " .. pid)
         os.execute("kill " .. pid)
      end

      if settings.remove_files then
         if path then
            mp.msg.info("Removing media file for " .. title .. " with path " .. path)
            os.execute("rm -r " .. path)
         end
      end

      open_videos[url] = {}
   end
end

mp.add_hook("on_load", 50, play_torrent)

mp.add_hook("on_unload", 10, webtorrent_cleanup)