--[[ Eat It - a Mpv plugin manager Copyright © 2023 squibid This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. ]] local mp = require('mp') -- load the config file dofile(mp.command_native({'expand-path', '~~/eatit-cfg.lua'})) -- helper functions -- local function tablelength(T) local count = 0 for _ in pairs(T) do count = count + 1 end return count end local function fileexists(name) local ok, err, code = os.rename(name, name) if not ok then if code == 13 then -- Permission denied, but it exists return true end end return ok, err end local function testforslash(str) if string.match(str, '/') then return string.match(str, '/([^/]+)$') else return str end end local function run(cmd) local x = io.popen(cmd) if not x then return 1 end local y = x:read("*a") x:close() return y end local function cp(a, b) local i = io.open(a, 'r') if not i then return 1 end local o = io.open(b, 'w') if not o then return 2 end o:write(i:read('*a')) o:close() i:close() end local function getsrc(id) local src if string.find(id, ":") then src = id:match("^[a-z]+[^:]") end local name = id:match([[[^:]*$]]) if name then local pre = opts.nameexp.pre or "https://" local map = opts.nameexp.map or { gl = 'gitlab.com', cb = 'codeberg.org', sr = 'sr.ht', gh = 'github.com' } return { link = (pre..map[src]) or false, repo = name } end end local function openlog() if opts.logging.log then -- log if asked to -- get our logfile's full path fn = mp.command_native({'expand-path', opts.logging.logfile}) f = io.open(fn, 'a') -- open file buffer if not f then return 1 end io.output(f) -- set it as default end end local function logwrite(string) if opts.logging.log then io.write(os.date(opts.logging.logdate)..' '..string..'\n') end end local function closelog() if opts.logging.log then io.close(f) end end -- get the requested git repos local function clonegit(plugdir, url, branch) logwrite('downloading '..url) -- clone the repo -- BUG: logwriting the git command doesn't actually log the output run('git -C '..opts.dl.dir..' clone '..url..' '..plugdir) run('git -C '..plugdir..' checkout -q '..branch) end -- check for updates local function checkupdates(plugdir) local localhash = run('git -C '..plugdir..' log -1 --format=format:"%H"') local remotehash = run('git -C '..plugdir..' rev-parse $(git -C '.. plugdir..' branch -r) | tail -1') if localhash ~= remotehash then return true else return false end end -- start install local function startinstall(i) local src = getsrc(plugins[i][1]) local plugin = { -- plugin table spec id = plugins[i][1] or false, url = plugins[i]['url'] or (src['link'].."/"..src['repo']), file = plugins[i]['file'] or false, dir = plugins[i]['dir'] or 'scripts', pin = plugins[i]['pin'] or false, branch = plugins[i]['branch'] or false, } -- check if the user has defined a file for the current plugin if not plugin['file'] then logwrite('WARNING! File not configured for '..plugin[1]) goto continue end -- skip install of pinned files if plugin['pin'] == true then goto continue end -- get the plugins tmp download dir local plugdir = opts.dl.dir..'/'..testforslash(src['repo']):gsub('.git', '') -- if no specified branch we use the default plugin['branch'] = plugin['branch'] or testforslash( run('git -C '..plugdir..' symbolic-ref refs/remotes/origin/HEAD') ) -- check for multiple files if type(plugin['file']) == 'string' then plugin['file'] = {} table.insert(plugin['file'], plugins[i]['file']) end -- get the requested file(s) for j = 1, #plugin['file'] or 1 do -- get the file's dir local pluginfile = plugdir..'/'..plugin['file'][j] -- get the dest dir local destfile = mp.command_native({'expand-path', '~~/'}).. '/'..plugin['dir']..'/'..testforslash(plugin['file'][j]) if fileexists(plugdir..'/') then -- if we need to update, update if checkupdates(plugdir) then logwrite(plugin['file'][j]..' is updating.') -- make sure we are on the main branch run('git -C '..plugdir..' checkout -q '..plugin['branch']) run('git -C '..plugdir..' pull') -- get the latest commits else logwrite(plugin['file'][j]..' is up to date!') end else clonegit(plugdir, plugin['url'], plugin['branch']) end -- copy the file contents over to the desired location cp(pluginfile, destfile) end ::continue:: end local function initupdate() openlog() logwrite('# of plugins defined in table: '..tablelength(plugins)) os.execute('mkdir -p '..opts.dl.dir) -- make download dir -- start the install process logwrite('Starting Download...') mp.osd_message('Downloading plugins!') -- start iterating through plugins for i = 1, tablelength(plugins) do local f = coroutine.create(function() startinstall(i) end) coroutine.resume(f) end -- closing/removing everything if opts.dl.powerwash == true then logwrite('powerwashing the tmp dir "'..opts.dl.dir..'"') os.execute('rm -rf '..opts.dl.dir) end closelog() end -- remove logfile on startup if opts.logging.log then openlog() os.remove(fn) closelog() end mp.add_key_binding(opts.bind, 'UpdatePlugins', initupdate)