diff --git a/statuscafe.lua b/statuscafe.lua new file mode 100644 index 0000000..9efbb57 --- /dev/null +++ b/statuscafe.lua @@ -0,0 +1,171 @@ +-- requires xmlparser to be wgeted +-- https://raw.githubusercontent.com/jonathanpoelen/lua-xmlparser/refs/heads/master/xmlparser.lua +-- requires morefonts to be installed +-- put statuscafe.lua in startup/ +-- change my username in http.get +-- get a sanjuuni.sad.ovh password from me or selfhost it +-- https://git.sad.ovh/sophie/sanjuuni-to-emoji-api + +-- for your knowledge: AI was used to create the querySelector and getTextContent functions + +local parse = require('../xmlparser').parse +local mf = require("../morefonts") +local strings = require "cc.strings" +function querySelector(rootNode, selector) + local parts = {} + for part in string.gmatch(selector, "[^%s>]+") do + table.insert(parts, part) + end + + local currentNodes = {} + if rootNode and rootNode.children then + for _, child in ipairs(rootNode.children) do + table.insert(currentNodes, child) + end + end + + local resultNode = nil + for i, tagName in ipairs(parts) do + local nextNodes = {} + local foundInThisLevel = false + + for _, node in ipairs(currentNodes) do + if node.tag == tagName then + foundInThisLevel = true + if i == #parts then + resultNode = node + break + end + if node.children then + for _, child in ipairs(node.children) do + table.insert(nextNodes, child) + end + end + end + end + + if resultNode then break end + + if not foundInThisLevel and i < #parts then + return nil + end + currentNodes = nextNodes + end + + return resultNode +end + +function getTextContent(node) + if not node or not node.children then return nil end + local text = "" + for _, child in ipairs(node.children) do + if child.text then + text = text .. child.text + end + end + return text +end + +function trim(s) + if s == nil then return nil end + return s:match("^%s*(.-)%s*$") +end + +--- Draws an image to the terminal. +---@param image bimg The image to draw. +---@param x number The x position to draw the image at. +---@param y number The y position to draw the image at. +---@param palette table? The palette to use for the image. +local function drawImage(monitor, image, x, y, palette) + for _, frame in ipairs(image) do + for y, row in ipairs(frame) do + monitor.setCursorPos(1, y) + monitor.blit(table.unpack(row)) + end + if frame.palette then for i = 0, #frame.palette do + local c = frame.palette[i] + if type(c) == "table" then monitor.setPaletteColor(2^i, table.unpack(c)) + else monitor.setPaletteColor(2^i, c) end + end end + if image.animation then sleep(frame.duration or image.secondsPerFrame or 0.05) end + end + monitor.setBackgroundColor(colors.black) + monitor.setTextColor(colors.white) + --monitor.clear() + monitor.setCursorPos(1, 1) + --for i = 0, 15 do monitor.setPaletteColor(2^i, monitor.nativePaletteColor(2^i)) end +end + +local monitor = peripheral.find("monitor") +monitor.clear() + +monitor.setCursorPos(2,2) +monitor.write("Loading..") + +local req = http.get("https://status.cafe/users/sophie.atom") +local rawXML = req.readAll(); + +local doc, err = parse(rawXML) + +if err then + print("Error parsing XML: " .. err) + return +end + +local latestEntryRaw = querySelector(doc, "feed > entry") + +if not latestEntryRaw then + print("Error: Missing latest entry in the feed!") +else + local latestEntry = {} + + local usernameNode = querySelector(doc, "feed > author > name") + latestEntry.username = getTextContent(usernameNode) or "" + + local statusNode = querySelector(latestEntryRaw, "content") + latestEntry.status = getTextContent(statusNode) or "" + + local titleNode = querySelector(latestEntryRaw, "title") + latestEntry.title = getTextContent(titleNode) or "" + + local updatedNode = querySelector(latestEntryRaw, "updated") + latestEntry.updated = getTextContent(updatedNode) or "" + + local usernameLength = string.len(latestEntry.username) + local statusLength = string.len(latestEntry.status) + + local titlePart = string.sub(latestEntry.title, usernameLength + 1) + + local endIndex = math.min(statusLength, 53) + + local emojiRaw = string.sub(titlePart, 1, string.len(titlePart) - endIndex) + + latestEntry.emoji = trim(emojiRaw) + + local req = http.post({ + url = "https://sanjuuni.sad.ovh/render", + body = "{\"emoji\": \"" .. latestEntry.emoji .. "\"}", + headers = { + ["Content-Type"] = "application/json", + ["Authorization"] = "<..>" + } + }) + + local data = req.readAll() -- actually read the data. + print(data) + monitor.setTextScale(0.5) + data = textutils.unserialize(data) -- convert the string file data into a usable lua object + drawImage(monitor, data, 0, 0) + + monitor.setCursorPos(1, 1) + mf.writeOn(monitor, latestEntry.username, 18, 2, {font="fonts/Times9k"}) + mf.writeOn(monitor, "At " .. latestEntry.updated, 18, 5, {font="fonts/3x3-Mono"}) + + width, height = monitor.getSize(); + + local lines = strings.wrap(latestEntry.status, width-(18+5)) + for i = 0, #lines-1 do + monitor.setCursorPos(18, 7+i) + monitor.write(lines[i+1]) + end +end