mirror of
https://github.com/minetest-mods/skinsdb.git
synced 2024-12-22 23:40:18 +01:00
Add updater script using the HTTP API (#27)
Check for core feature `httpfetch_binary_data` to run the updater properly. This requires Minetest cb00632 or newer. README.md: Add documentation for the updater
This commit is contained in:
parent
a2470f06fb
commit
428fea2eb4
23
README.md
23
README.md
@ -15,6 +15,29 @@ This Minetest mod offers changeable player skins with a graphical interface for
|
|||||||
- Full [3d_armor](https://forum.minetest.net/viewtopic.php?t=4654) support
|
- Full [3d_armor](https://forum.minetest.net/viewtopic.php?t=4654) support
|
||||||
- Compatible to 1.0 and 1.8 Minecraft skins format
|
- Compatible to 1.0 and 1.8 Minecraft skins format
|
||||||
|
|
||||||
|
|
||||||
|
## Installing skins
|
||||||
|
|
||||||
|
### Download from the database
|
||||||
|
|
||||||
|
1) Get Minetest 5.1.0-dev-cb00632 or newer
|
||||||
|
2) Uncomment the lines in `init.lua` mentioning `skins_updater.lua`
|
||||||
|
3) Start your world and wait until it reports that the skins were downloaded.
|
||||||
|
4) Let the Minetest server shut down
|
||||||
|
5) Comment the lines in `init.lua` again
|
||||||
|
6) Start the server again
|
||||||
|
|
||||||
|
You might want to run `minetest` in a Terminal/Console window to check the log output instantly.
|
||||||
|
|
||||||
|
### Manual addition
|
||||||
|
|
||||||
|
1) Copy your skin textures to `textures` as documented in `textures/readme.txt`
|
||||||
|
2) Create `meta/character_<name>.txt` with the following fields (separated by new lines):
|
||||||
|
* Skin name
|
||||||
|
* Author
|
||||||
|
* Skin license
|
||||||
|
|
||||||
|
|
||||||
## License:
|
## License:
|
||||||
- GPLv3
|
- GPLv3
|
||||||
|
|
||||||
|
7
init.lua
7
init.lua
@ -30,6 +30,13 @@ if minetest.get_modpath("sfinv") then
|
|||||||
dofile(skins.modpath.."/sfinv_page.lua")
|
dofile(skins.modpath.."/sfinv_page.lua")
|
||||||
end
|
end
|
||||||
|
|
||||||
|
-- ie.loadfile does not exist?
|
||||||
|
--[[skins.ie = minetest.request_insecure_environment()
|
||||||
|
skins.http = minetest.request_http_api()
|
||||||
|
dofile(skins.modpath.."/skins_updater.lua")
|
||||||
|
skins.ie = nil
|
||||||
|
skins.http = nil]]
|
||||||
|
|
||||||
-- 3d_armor compatibility
|
-- 3d_armor compatibility
|
||||||
if minetest.global_exists("armor") then
|
if minetest.global_exists("armor") then
|
||||||
skins.armor_loaded = true
|
skins.armor_loaded = true
|
||||||
|
115
skins_updater.lua
Normal file
115
skins_updater.lua
Normal file
@ -0,0 +1,115 @@
|
|||||||
|
-- Skins update script
|
||||||
|
-- Load it in init.lua or write a frontend GUI/chatcommand for it. Good luck.
|
||||||
|
|
||||||
|
local _ID_ = "Lua Skins Updater"
|
||||||
|
local _SKIN_PAGE_START_ = 1 -- Starting page to fetch the skins
|
||||||
|
local _SKIN_PAGE_END_ = nil -- End page number (nil = all skins)
|
||||||
|
|
||||||
|
if not core.features.httpfetch_binary_data then
|
||||||
|
error(_ID_ .. " requires the feature 'httpfetch_binary_data'. Update Minetest.")
|
||||||
|
end
|
||||||
|
|
||||||
|
local ie, http = skins.ie, skins.http
|
||||||
|
if not ie or not http then
|
||||||
|
error(_ID_ .. " requires the insecure environment. " ..
|
||||||
|
"Please add skinsdb to `secure.trusted_mods` in minetest.conf")
|
||||||
|
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
|
||||||
|
local function get_pages_count(callback)
|
||||||
|
fetch_url(page_url:format(1) .. "&per_page=5", function(data)
|
||||||
|
local list = core.parse_json(data)
|
||||||
|
print(dump(list))
|
||||||
|
callback(list.pages)
|
||||||
|
end)
|
||||||
|
end
|
||||||
|
|
||||||
|
-- Just fetch them all. YOLO
|
||||||
|
get_pages_count(function(pages_total)
|
||||||
|
local start_page = _SKIN_PAGE_START_ or 1
|
||||||
|
local end_page = math.min(pages_total, _SKIN_PAGE_END_ or pages_total)
|
||||||
|
|
||||||
|
for page_n = 1, 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
|
||||||
|
core.log("action", _ID_ .. " finished downloading all skins. " ..
|
||||||
|
"Please comment out this script to reduce server traffic.")
|
||||||
|
core.request_shutdown("Reloading skinsdb media cache after download",
|
||||||
|
true, 3 --[[give some time for pending requests]])
|
||||||
|
end
|
||||||
|
end)
|
||||||
|
end
|
||||||
|
end)
|
@ -1,4 +1,12 @@
|
|||||||
In this folder the skin files could be placed according the next file naming convention
|
In this folder the skin files could be placed according the following file naming convention.
|
||||||
character_[number-or-name].png - Public skin, available for all users
|
|
||||||
player_[nick].png or player_[nick]_[number-or-name].png - one or multiple private skins for player "nick"
|
Public skin available for all users:
|
||||||
*_preview.png - Preview files for public and private skins
|
character_[number-or-name].png
|
||||||
|
|
||||||
|
One or multiple private skins for player "nick":
|
||||||
|
player_[nick].png or
|
||||||
|
player_[nick]_[number-or-name].png
|
||||||
|
|
||||||
|
Preview files for public and private skins:
|
||||||
|
character_*_preview.png or
|
||||||
|
player_*_*_preview.png
|
||||||
|
Loading…
Reference in New Issue
Block a user