summaryrefslogtreecommitdiff
path: root/mpv/lua-modules
diff options
context:
space:
mode:
Diffstat (limited to 'mpv/lua-modules')
-rw-r--r--mpv/lua-modules/auto-profiles-functions.lua122
-rw-r--r--mpv/lua-modules/scroll-list.lua236
-rw-r--r--mpv/lua-modules/user-input-module.lua49
3 files changed, 407 insertions, 0 deletions
diff --git a/mpv/lua-modules/auto-profiles-functions.lua b/mpv/lua-modules/auto-profiles-functions.lua
new file mode 100644
index 0000000..539a84d
--- /dev/null
+++ b/mpv/lua-modules/auto-profiles-functions.lua
@@ -0,0 +1,122 @@
+local utils = require 'mp.utils'
+local msg = require 'mp.msg'
+
+-- Quality levels
+local HIGH = "High Quality"
+local MID = "Mid Quality"
+local LOW = "Low Quality"
+-- Platform
+local is_linux, is_osx, is_windows = false, false, false
+local exec_cache = {}
+
+
+local function exec(process, force_exec)
+ local key = table.concat(process, " ")
+ if force_exec or exec_cache[key] == nil or exec_cache[key].error then
+ local p_ret = utils.subprocess({args = process, playback_only = false})
+ exec_cache[key] = p_ret
+ if p_ret.error and p_ret.error == "init" then
+ msg.error("executable not found: " .. key)
+ end
+ return p_ret
+ else
+ return exec_cache[key]
+ end
+end
+
+
+local function get_platform()
+ local is_linux = false
+ local is_osx = false
+ local is_windows = type(package) == 'table' and type(package.config) == 'string' and string.sub(package.config, 1, 1) == '\\'
+ if not is_windows then
+ uname = exec({"uname"})
+ is_linux = uname.stdout == "Linux\n"
+ is_osx = uname.stdout == "Darwin\n"
+ end
+ return is_linux, is_osx, is_windows
+end
+
+
+function on_battery()
+ if is_osx then
+ local bat = exec({"/usr/bin/pmset", "-g", "batt"}, true)
+ return string.match(bat.stdout, "Now drawing from 'Battery Power'")
+ elseif is_linux then
+ local res = exec({"/bin/cat", "/sys/class/power_supply/AC0/online"}, true)
+ return res.stdout == "0\n"
+ elseif is_windows then
+ msg.warn("on_battery() not implemented on windows. PRs welcome")
+ end
+ msg.warn("assuming AC power")
+ return false
+end
+
+
+-- This is a crude attempt to figure out if a (beefy) dedicated GPU is present.
+-- Can't identify the actually used GPU but works when we assume that an existing
+-- dedicated GPU can/will be used in case we are drawing power from AC.
+ -- local r = exec({"lshw", "-C", 'display'})
+ -- local r = exec({"nvidia-smi"})
+ -- r.stdout = string.lower(r.stdout)
+ -- return string.find(r.stdout, "amd") ~= nil or string.find(r.stdout, "nvidia") ~= nil
+ -- return string.find(r.stdout, "mpv") ~= nil
+function dedicated_gpu()
+ if is_osx then
+ local r = exec({"system_profiler", "SPDisplaysDataType"})
+ return string.find(r.stdout, "Chipset Model: Radeon") ~= nil or string.find(r.stdout, "Chipset Model: NVIDIA GeForce") ~= nil
+ -- Untested
+ elseif is_linux then
+ local nv = os.getenv("__NV_PRIME_RENDER_OFFLOAD")
+ return nv ~= nil
+ elseif is_windows then
+ msg.warn("dedicated_gpu() not implemented on windows. PRs welcome")
+ end
+ msg.warn("assuming dedicated GPU")
+ return true
+end
+
+
+local function determine_level(width, height, fps)
+
+ if on_battery() then
+ return LOW
+ end
+
+ if dedicated_gpu() then
+ if width > 4096 then
+ return MID
+ end
+ if width > 1920 and fps > 61 then
+ return MID
+ end
+ return HIGH
+ else
+ if width > 1919 then
+ return LOW
+ end
+ if fps > 58 then
+ return LOW
+ end
+ return MID
+ end
+
+ msg.error("could not determine profile")
+ msg.warn("assuming HIGH")
+ return HIGH
+end
+
+
+local function is_level(level)
+ return function(width, height, fps)
+ local l = determine_level(width, height, fps)
+ return l == level
+ end
+end
+
+
+is_high = is_level(HIGH)
+is_mid = is_level(MID)
+is_low = is_level(LOW)
+
+is_linux, is_osx, is_windows = get_platform()
diff --git a/mpv/lua-modules/scroll-list.lua b/mpv/lua-modules/scroll-list.lua
new file mode 100644
index 0000000..0666f5a
--- /dev/null
+++ b/mpv/lua-modules/scroll-list.lua
@@ -0,0 +1,236 @@
+local mp = require 'mp'
+local scroll_list = {
+ global_style = [[]],
+ header_style = [[{\q2\fs35\c&00ccff&}]],
+ list_style = [[{\q2\fs25\c&Hffffff&}]],
+ wrapper_style = [[{\c&00ccff&\fs16}]],
+ cursor_style = [[{\c&00ccff&}]],
+ selected_style = [[{\c&Hfce788&}]],
+
+ cursor = [[➤\h]],
+ indent = [[\h\h\h\h]],
+
+ num_entries = 16,
+ wrap = false,
+ empty_text = "no entries"
+}
+
+--formats strings for ass handling
+--this function is taken from https://github.com/mpv-player/mpv/blob/master/player/lua/console.lua#L110
+function scroll_list.ass_escape(str)
+ str = str:gsub('\\', '\\\239\187\191')
+ str = str:gsub('{', '\\{')
+ str = str:gsub('}', '\\}')
+ -- Precede newlines with a ZWNBSP to prevent ASS's weird collapsing of
+ -- consecutive newlines
+ str = str:gsub('\n', '\239\187\191\\N')
+ -- Turn leading spaces into hard spaces to prevent ASS from stripping them
+ str = str:gsub('\\N ', '\\N\\h')
+ str = str:gsub('^ ', '\\h')
+ return str
+end
+--appends the entered text to the overlay
+function scroll_list:append(text)
+ if text == nil then return end
+ self.ass.data = self.ass.data .. text
+ end
+
+--appends a newline character to the osd
+function scroll_list:newline()
+ self.ass.data = self.ass.data .. '\\N'
+end
+
+--re-parses the list into an ass string
+--if the list is closed then it flags an update on the next open
+function scroll_list:update()
+ if self.hidden then self.flag_update = true
+ else self:update_ass() end
+end
+
+--prints the header to the overlay
+function scroll_list:format_header()
+ self:append(self.header_style)
+ self:append(self.header)
+ self:newline()
+end
+
+--formats each line of the list and prints it to the overlay
+function scroll_list:format_line(index, item)
+ self:append(self.list_style)
+
+ if index == self.selected then self:append(self.cursor_style..self.cursor..self.selected_style)
+ else self:append(self.indent) end
+
+ self:append(item.style)
+ self:append(item.ass)
+ self:newline()
+end
+
+--refreshes the ass text using the contents of the list
+function scroll_list:update_ass()
+ self.ass.data = self.global_style
+ self:format_header()
+
+ if #self.list < 1 then
+ self:append(self.empty_text)
+ self.ass:update()
+ return
+ end
+
+ local start = 1
+ local finish = start+self.num_entries-1
+
+ --handling cursor positioning
+ local mid = math.ceil(self.num_entries/2)+1
+ if self.selected+mid > finish then
+ local offset = self.selected - finish + mid
+
+ --if we've overshot the end of the list then undo some of the offset
+ if finish + offset > #self.list then
+ offset = offset - ((finish+offset) - #self.list)
+ end
+
+ start = start + offset
+ finish = finish + offset
+ end
+
+ --making sure that we don't overstep the boundaries
+ if start < 1 then start = 1 end
+ local overflow = finish < #self.list
+ --this is necessary when the number of items in the dir is less than the max
+ if not overflow then finish = #self.list end
+
+ --adding a header to show there are items above in the list
+ if start > 1 then self:append(self.wrapper_style..(start-1)..' item(s) above\\N\\N') end
+
+ for i=start, finish do
+ self:format_line(i, self.list[i])
+ end
+
+ if overflow then self:append('\\N'..self.wrapper_style..#self.list-finish..' item(s) remaining') end
+ self.ass:update()
+end
+
+--moves the selector down the list
+function scroll_list:scroll_down()
+ if self.selected < #self.list then
+ self.selected = self.selected + 1
+ self:update_ass()
+ elseif self.wrap then
+ self.selected = 1
+ self:update_ass()
+ end
+end
+
+--moves the selector up the list
+function scroll_list:scroll_up()
+ if self.selected > 1 then
+ self.selected = self.selected - 1
+ self:update_ass()
+ elseif self.wrap then
+ self.selected = #self.list
+ self:update_ass()
+ end
+end
+
+--adds the forced keybinds
+function scroll_list:add_keybinds()
+ for _,v in ipairs(self.keybinds) do
+ mp.add_forced_key_binding(v[1], 'dynamic/'..self.ass.id..'/'..v[2], v[3], v[4])
+ end
+end
+
+--removes the forced keybinds
+function scroll_list:remove_keybinds()
+ for _,v in ipairs(self.keybinds) do
+ mp.remove_key_binding('dynamic/'..self.ass.id..'/'..v[2])
+ end
+end
+
+--opens the list and sets the hidden flag
+function scroll_list:open_list()
+ self.hidden = false
+ if not self.flag_update then self.ass:update()
+ else self.flag_update = false ; self:update_ass() end
+end
+
+--closes the list and sets the hidden flag
+function scroll_list:close_list()
+ self.hidden = true
+ self.ass:remove()
+end
+
+--modifiable function that opens the list
+function scroll_list:open()
+ self:open_list()
+ self:add_keybinds()
+end
+
+--modifiable function that closes the list
+function scroll_list:close ()
+ self:remove_keybinds()
+ self:close_list()
+end
+
+--toggles the list
+function scroll_list:toggle()
+ if self.hidden then self:open()
+ else self:close() end
+end
+
+--clears the list in-place
+function scroll_list:clear()
+ local i = 1
+ while self.list[i] do
+ self.list[i] = nil
+ i = i + 1
+ end
+end
+
+--added alias for ipairs(list.list) for lua 5.1
+function scroll_list:ipairs()
+ return ipairs(self.list)
+end
+
+--append item to the end of the list
+function scroll_list:insert(item)
+ self.list[#self.list + 1] = item
+end
+
+local metatable = {
+ __index = function(t, key)
+ if scroll_list[key] ~= nil then return scroll_list[key]
+ elseif key == "__current" then return t.list[t.selected]
+ elseif type(key) == "number" then return t.list[key] end
+ end,
+ __newindex = function(t, key, value)
+ if type(key) == "number" then rawset(t.list, key, value)
+ else rawset(t, key, value) end
+ end,
+ __scroll_list = scroll_list,
+ __len = function(t) return #t.list end,
+ __ipairs = function(t) return ipairs(t.list) end
+}
+
+--creates a new list object
+function scroll_list:new()
+ local vars
+ vars = {
+ ass = mp.create_osd_overlay('ass-events'),
+ hidden = true,
+ flag_update = true,
+
+ header = "header \\N ----------------------------------------------",
+ list = {},
+ selected = 1,
+
+ keybinds = {
+ {'DOWN', 'scroll_down', function() vars:scroll_down() end, {repeatable = true}},
+ {'UP', 'scroll_up', function() vars:scroll_up() end, {repeatable = true}},
+ {'ESC', 'close_browser', function() vars:close() end, {}}
+ }
+ }
+ return setmetatable(vars, metatable)
+end
+
+return scroll_list:new()
diff --git a/mpv/lua-modules/user-input-module.lua b/mpv/lua-modules/user-input-module.lua
new file mode 100644
index 0000000..2c25d42
--- /dev/null
+++ b/mpv/lua-modules/user-input-module.lua
@@ -0,0 +1,49 @@
+--[[
+ This is a module designed to interface with mpv-user-input
+ https://github.com/CogentRedTester/mpv-user-input
+
+ Loading this script as a module will return a table with two functions to format
+ requests to get and cancel user-input requests. See the README for details.
+
+ Alternatively, developers can just paste these functions directly into their script,
+ however this is not recommended as there is no guarantee that the formatting of
+ these requests will remain the same for future versions of user-input.
+]]
+
+local mp = require 'mp'
+local mod = {}
+
+local name = mp.get_script_name()
+local counter = 1
+
+-- sends a request to ask the user for input using formatted options provided
+-- creates a script message to recieve the response and call fn
+function mod.get_user_input(fn, options)
+ options = options or {}
+ local response_string = name.."/__user_input_request/"..counter
+ counter = counter + 1
+
+ -- create a callback for user-input to respond to
+ mp.register_script_message(response_string, function(input, err)
+ mp.unregister_script_message(response_string)
+ fn(err == "" and input or nil, err)
+ end)
+
+ -- send the input command
+ mp.commandv("script-message-to", "user_input", "request-user-input",
+ response_string,
+ name .. '/' .. (options.id or ""), -- id code for the request
+ options.request_text or options.text or (name.." is requesting user input:"),
+ options.default_input or "",
+ options.queueable and "1" or "",
+ options.replace and "1" or ""
+ )
+end
+
+-- sends a request to cancel all input requests with the given id
+function mod.cancel_user_input(id)
+ id = name .. '/' .. (id or "")
+ mp.commandv("script-message-to", "user_input", "cancel-user-input", id)
+end
+
+return mod