123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148 |
- -- Skins update script
- local S = minetest.get_translator("skinsdb")
- local _ID_ = "Lua Skins Updater"
- local internal = {}
- internal.errors = {}
- -- Binary downloads are required
- if not core.features.httpfetch_binary_data then
- internal.errors[#internal.errors + 1] =
- "Feature 'httpfetch_binary_data' is missing. Update Minetest."
- end
- -- Insecure environment for saving textures and meta
- local ie, http = skins.ie, skins.http
- if not ie or not http then
- internal.errors[#internal.errors + 1] = "Insecure environment is required. " ..
- "Please add skinsdb to `secure.trusted_mods` in minetest.conf"
- end
- minetest.register_chatcommand("skinsdb_download_skins", {
- params = "<skindb start page> <amount of pages>",
- description = S("Downloads the specified range of skins and shuts down the server"),
- privs = {server=true},
- func = function(name, param)
- if #internal.errors > 0 then
- return false, "Cannot run " .. _ID_ .. ":\n\t" ..
- table.concat(internal.errors, "\n\t")
- end
- local parts = string.split(param, " ")
- local start = tonumber(parts[1])
- local len = tonumber(parts[2])
- if not (start and len and len > 0) then
- return false, "Invalid page number or amount of pages"
- end
- internal.get_pages_count(internal.fetch_function, start, len)
- return true, "Started downloading..."
- end,
- })
- if #internal.errors > 0 then
- return -- Nonsense to load something that's not working
- end
- -- http://minetest.fensta.bplaced.net/api/apidoku.md
- local root_url = "http://minetest.fensta.bplaced.net"
- local page_url = root_url .. "/api/v2/get.json.php?getlist&page=%i&outformat=base64" -- [1] = Page#
- local preview_url = root_url .. "/skins/1/%i.png" -- [1] = ID
- local mod_path = skins.modpath
- local meta_path = mod_path .. "/meta/"
- local skins_path = mod_path .. "/textures/"
- -- Fancy debug wrapper to download an URL
- local function fetch_url(url, callback)
- http.fetch({
- url = url,
- user_agent = _ID_
- }, function(result)
- if result.succeeded then
- if result.code ~= 200 then
- core.log("warning", ("%s: STATUS=%i URL=%s"):format(
- _ID_, result.code, url))
- end
- return callback(result.data)
- end
- core.log("warning", ("%s: Failed to download URL=%s"):format(
- _ID_, url))
- end)
- end
- -- Insecure workaround since meta/ and textures/ cannot be written to
- local function unsafe_file_write(path, contents)
- local f = ie.io.open(path, "w")
- f:write(contents)
- f:close()
- end
- -- Takes a valid skin table from the Skins Database and saves it
- local function safe_single_skin(skin)
- local meta = {
- skin.name,
- skin.author,
- skin.license
- }
- local name = "character_" .. skin.id
- -- core.safe_file_write does not work here
- unsafe_file_write(
- meta_path .. name .. ".txt",
- table.concat(meta, "\n")
- )
- unsafe_file_write(
- skins_path .. name .. ".png",
- core.decode_base64(skin.img)
- )
- fetch_url(preview_url:format(skin.id), function(preview)
- unsafe_file_write(skins_path .. name .. "_preview.png", preview)
- end)
- core.log("action", ("%s: Completed skin %s"):format(_ID_, name))
- end
- -- Get total pages since it'll just return the last page all over again
- internal.get_pages_count = function(callback, ...)
- local vars = {...}
- fetch_url(page_url:format(1) .. "&per_page=1", function(data)
- local list = core.parse_json(data)
- -- "per_page" defaults to 20 if left away (docs say something else, though)
- callback(math.ceil(list.pages / 20), unpack(vars))
- end)
- end
-
- -- Function to fetch a range of pages
- internal.fetch_function = function(pages_total, start_page, len)
- start_page = math.max(start_page, 1)
- local end_page = math.min(start_page + len - 1, pages_total)
- for page_n = start_page, end_page do
- local page_cpy = page_n
- fetch_url(page_url:format(page_n), function(data)
- core.log("action", ("%s: Page %i"):format(_ID_, page_cpy))
- local list = core.parse_json(data)
- for i, skin in pairs(list.skins) do
- assert(skin.type == "image/png")
- assert(skin.id ~= "")
- if skin.id ~= 1 then -- Skin 1 is bundled with skinsdb
- safe_single_skin(skin)
- end
- end
- if page_cpy == end_page then
- local log = _ID_ .. " finished downloading all skins. " ..
- "Shutting down server to reload media cache"
- core.log("action", log)
- core.request_shutdown(log, true, 3 --[[give some time for pending requests]])
- end
- end)
- end
- end
|