aboutsummaryrefslogtreecommitdiffstatshomepage
path: root/home/.config/mpv/scripts/webtorrent-hook.lua
blob: 80d991ffffe78e37570b74f51b0f36e343da952b (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
-- 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)