local json = require('opus.json') local Util = require('opus.util') local GITHUB_TREE_URL = 'https://api.github.com/repos/%s/%s/git/trees/%s?recursive=1' local GITHUB_FILE_URL = 'https://raw.githubusercontent.com/%s/%s/%s/%s' local GITEA_TREE_URL = 'https://%s/api/v1/repos/%s/%s/git/trees/%s?recursive=1' local GITEA_FILE_URL = 'https://%s/%s/%s/raw/branch/%s/%s' local TREE_HEADERS = {} local git = { } if _G._GIT_API_KEY then TREE_HEADERS.Authorization = 'token ' .. _G._GIT_API_KEY end local function parseTree(data, path, fileUrlFn) if data.message then if data.message:find("API rate limit exceeded") then error("Out of API calls, try again later") end if data.message == "Not found" or data.message == "Not Found" then error("Invalid repository") end end local list = { } for _, v in pairs(data.tree) do if v.type == "blob" then v.path = v.path:gsub("%s", "%%20") if not path then list[v.path] = { url = fileUrlFn(v.path), size = v.size, } elseif Util.startsWith(v.path, path) then local p = string.sub(v.path, #path) list[p] = { url = fileUrlFn(path .. p), size = v.size, } end end end return list end local function fetchTree(url) local contents, msg = Util.httpGet(url, TREE_HEADERS) if not contents then error(string.format('Failed to download %s\n%s', url, msg), 2) end return json.decode(contents) or error('Invalid repository') end -- GitHub: user/repo/branch/subdir/ local function listGithub(repository) local t = Util.split(repository, '(.-)/') local user = table.remove(t, 1) local repo = table.remove(t, 1) local branch = table.remove(t, 1) or 'main' local path = not Util.empty(t) and (table.concat(t, '/') .. '/') or nil local data = fetchTree(string.format(GITHUB_TREE_URL, user, repo, branch)) return parseTree(data, path, function(p) return string.format(GITHUB_FILE_URL, user, repo, branch, p) end) end -- Gitea: gitea://host/user/repo/branch/subdir/ local function listGitea(host, remainder) local t = Util.split(remainder, '(.-)/') local user = table.remove(t, 1) local repo = table.remove(t, 1) local branch = table.remove(t, 1) or 'main' local path = not Util.empty(t) and (table.concat(t, '/') .. '/') or nil local data = fetchTree(string.format(GITEA_TREE_URL, host, user, repo, branch)) return parseTree(data, path, function(p) return string.format(GITEA_FILE_URL, host, user, repo, branch, p) end) end function git.list(repository) local host_type, host, rest = repository:match('^(%w+)://(.-)/(.*)') if host_type == 'gitea' then return listGitea(host, rest) end return listGithub(repository) end return git