aboutsummaryrefslogtreecommitdiffstatshomepage
path: root/dot_config/mpv/scripts/webtorrent-hook.lua
blob: afe0adeb865ef5adef048ea156afad66fc0a6706 (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
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
-- selene: allow(incorrect_standard_library_use, shadowing)
-- 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
local function 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 = capture(webtorrent_command)
    mp.msg.info("Waiting for webtorrent server")

    local url_command = "tail -f "
      .. output_file
      .. " | awk '/Server running at:/ {print $4; exit}'"
    url = 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 = 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)