249 lines
7.6 KiB
Lua
249 lines
7.6 KiB
Lua
-- TODO start webtorrent instance immediately when pasting into playlist instead
|
|
-- of waiting for load?
|
|
-- TODO what happens with --prefetch-playlist?
|
|
|
|
local settings = {
|
|
close_webtorrent = true,
|
|
remove_files = true,
|
|
download_directory = "/tmp/webtorrent-hook",
|
|
webtorrent_flags = [[]],
|
|
show_speed = true,
|
|
remember_last_played = true,
|
|
remember_directory = "/tmp/webtorrent-hook-last-played"
|
|
}
|
|
|
|
(require "mp.options").read_options(settings, "webtorrent-hook")
|
|
|
|
local utils = require "mp.utils";
|
|
|
|
local webtorrent_instances = {}
|
|
local webtorrent_files = {}
|
|
local script_dir = mp.get_script_directory()
|
|
local printer_pid = nil
|
|
|
|
-- * Helpers
|
|
-- http://lua-users.org/wiki/StringRecipes
|
|
function ends_with(str, ending)
|
|
return ending == "" or str:sub(-#ending) == ending
|
|
end
|
|
|
|
function read_file(file)
|
|
local fh = assert(io.open(file, "rb"))
|
|
local contents = fh:read("*all")
|
|
fh:close()
|
|
return contents
|
|
end
|
|
|
|
function write_file(file, text)
|
|
local fh = io.open(file, "w")
|
|
fh:write(text)
|
|
fh:close()
|
|
end
|
|
|
|
function is_handled_url(url, load_failed)
|
|
if load_failed then
|
|
-- info hash
|
|
return (load_failed and string.match(url, "%w+"))
|
|
else
|
|
return (url:find("magnet:") == 1 or url:find("peerflix://") == 1
|
|
or url:find("webtorrent://") == 1 or ends_with(url, "torrent"))
|
|
end
|
|
end
|
|
|
|
function load_file_after_current(url, option_table, num_entries)
|
|
mp.command_native({
|
|
"loadfile", url, "append", -1, option_table
|
|
})
|
|
local index = mp.get_property("playlist-pos")
|
|
mp.command_native({
|
|
"playlist-move",
|
|
mp.get_property("playlist-count") - 1,
|
|
index + 1 + num_entries
|
|
})
|
|
end
|
|
|
|
-- * Store Last Played Files
|
|
function file_info_hash(filename)
|
|
return webtorrent_files[filename]
|
|
end
|
|
|
|
function get_remember_file_path(info_hash)
|
|
return utils.join_path(settings.remember_directory, info_hash)
|
|
end
|
|
|
|
function maybe_store_last_played_torrent_file(_)
|
|
if settings.remember_last_played then
|
|
mp.commandv("run", "mkdir", "-p", settings.remember_directory)
|
|
local filename = mp.get_property("media-title")
|
|
local info_hash = file_info_hash(filename)
|
|
if info_hash ~= nil then
|
|
local remember_file = get_remember_file_path(info_hash)
|
|
write_file(remember_file, filename)
|
|
end
|
|
end
|
|
end
|
|
|
|
mp.register_event("file-loaded", maybe_store_last_played_torrent_file)
|
|
|
|
function get_last_played_filename_for_torrent(info_hash)
|
|
local remember_file = get_remember_file_path(info_hash)
|
|
if utils.file_info(remember_file) then
|
|
return read_file(remember_file)
|
|
end
|
|
end
|
|
|
|
-- * Play Torrents
|
|
function load_webtorrent_files(info_hash, webtorrent_info)
|
|
local first = true
|
|
local found_last_played = false
|
|
local last_played_filename = ""
|
|
if settings.remember_last_played then
|
|
last_played_filename = get_last_played_filename_for_torrent(info_hash)
|
|
end
|
|
local should_remember = settings.remember_last_played
|
|
and last_played_filename
|
|
local file_index = 0
|
|
local file_play_index = 0
|
|
for _, file in pairs(webtorrent_info["files"]) do
|
|
local title = file["title"]
|
|
webtorrent_files[title] = info_hash
|
|
local option_table = {}
|
|
-- TODO is it actually necessary to set force-media-title for sub
|
|
-- plugins? it seems to be correctly set by default for what I've
|
|
-- tried
|
|
option_table["force-media-title"] = title
|
|
local url = file["url"]
|
|
if first then
|
|
load_file_after_current(url, option_table, 0)
|
|
mp.command_native({"playlist-remove", mp.get_property("playlist-pos")})
|
|
else
|
|
load_file_after_current(url, option_table,
|
|
file_index - (file_play_index + 1))
|
|
if should_remember and not found_last_played then
|
|
file_play_index = file_play_index + 1
|
|
mp.set_property("playlist-pos", mp.get_property("playlist-pos") + 1)
|
|
if title == last_played_filename then
|
|
found_last_played = true
|
|
end
|
|
end
|
|
end
|
|
file_index = file_index + 1
|
|
first = false
|
|
end
|
|
end
|
|
|
|
function maybe_kill_printer()
|
|
if printer_pid then
|
|
mp.commandv("run", "kill", printer_pid)
|
|
printer_pid = nil
|
|
end
|
|
end
|
|
|
|
mp.register_event("file-loaded", maybe_kill_printer)
|
|
|
|
function start_speed_printer(out_dir)
|
|
if utils.file_info(utils.join_path(out_dir, "webtorrent-output")) then
|
|
local speed_printer_path =
|
|
utils.join_path(script_dir, "webtorrent-speed-printer.sh")
|
|
os.execute(speed_printer_path .. ' "' .. out_dir .. '"')
|
|
printer_pid = read_file(utils.join_path(out_dir, "printer.pid"))
|
|
end
|
|
end
|
|
|
|
function start_webtorrent(url, torrent_info)
|
|
local base_dir = mp.command_native({
|
|
"expand-path", settings.download_directory
|
|
})
|
|
local info_hash = torrent_info["infoHash"]
|
|
local out_dir = utils.join_path(base_dir, info_hash)
|
|
|
|
local wrapper_path =
|
|
utils.join_path(script_dir, "webtorrent-wrap.sh")
|
|
local webtorrent_args = {wrapper_path, out_dir, url}
|
|
local flags = utils.parse_json(settings.webtorrent_flags)
|
|
if flags ~= nil then
|
|
for _, flag in pairs(flags) do
|
|
table.insert(webtorrent_args, flag)
|
|
end
|
|
end
|
|
mp.msg.info("Waiting for webtorrent server")
|
|
local webtorrent_result = mp.command_native({
|
|
name = "subprocess",
|
|
playback_only = false,
|
|
capture_stdout = true,
|
|
args = webtorrent_args
|
|
})
|
|
if webtorrent_result.status == 0 then
|
|
mp.msg.info("Webtorrent server is up")
|
|
local webtorrent_info = utils.parse_json(webtorrent_result.stdout)
|
|
local pid = webtorrent_info["pid"]
|
|
mp.msg.debug(webtorrent_info)
|
|
local name = "Unknown name"
|
|
if torrent_info["name"] ~= nil then
|
|
name = torrent_info["name"]
|
|
end
|
|
table.insert(webtorrent_instances,
|
|
{download_dir=out_dir,pid=pid,name=name})
|
|
|
|
if settings.show_speed then
|
|
start_speed_printer(out_dir)
|
|
end
|
|
|
|
load_webtorrent_files(info_hash, webtorrent_info)
|
|
else
|
|
mp.msg.info("Failed to start webtorrent")
|
|
end
|
|
end
|
|
|
|
-- check if the url is a torrent and play it if it is
|
|
function maybe_play_torrent(load_failed)
|
|
local url = mp.get_property("stream-open-filename")
|
|
if is_handled_url(url, load_failed) then
|
|
if url:find("webtorrent://") == 1 then
|
|
url = url:sub(14)
|
|
end
|
|
if url:find("peerflix://") == 1 then
|
|
url = url:sub(12)
|
|
end
|
|
|
|
local torrent_info_command = mp.command_native({
|
|
name = "subprocess",
|
|
playback_only = false,
|
|
capture_stdout = true,
|
|
args = {"webtorrent", "info", url},
|
|
})
|
|
if torrent_info_command.status == 0 then
|
|
local torrent_info = utils.parse_json(torrent_info_command.stdout)
|
|
local info_hash = torrent_info["infoHash"]
|
|
if info_hash ~= nil then
|
|
start_webtorrent(url, torrent_info)
|
|
end
|
|
end
|
|
end
|
|
end
|
|
|
|
function check_if_torrent_on_load()
|
|
maybe_play_torrent(false)
|
|
end
|
|
|
|
function check_if_torrent_on_load_fail()
|
|
maybe_play_torrent(true)
|
|
end
|
|
|
|
function webtorrent_cleanup()
|
|
if settings.close_webtorrent then
|
|
for _, instance in pairs(webtorrent_instances) do
|
|
mp.msg.verbose("Killing WebTorrent pid " .. instance.pid)
|
|
mp.commandv("run", "kill", instance.pid)
|
|
if settings.remove_files then
|
|
mp.msg.verbose("Removing files for torrent " .. instance.name)
|
|
mp.commandv("run", "rm", "-r", instance.download_dir)
|
|
end
|
|
end
|
|
end
|
|
end
|
|
|
|
mp.add_hook("on_load", 50, check_if_torrent_on_load)
|
|
mp.add_hook("on_load_fail", 50, check_if_torrent_on_load_fail)
|
|
|
|
mp.register_event("shutdown", webtorrent_cleanup)
|