Advertisement
Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- local component = require("component")
- local event = require("event")
- local internet = require("internet")
- local term = require("term")
- local unicode = require("unicode")
- local computer = require("computer")
- local gpu = component.gpu
- local hasColor = gpu.getDepth() > 1
- local function trim(s)
- return s:match("^%s*(.-)%s*$")
- end
- local function serialize(tbl)
- local result = {}
- for k, v in pairs(tbl) do
- table.insert(result, k .. "=" .. v)
- end
- return table.concat(result, ",")
- end
- local function deserialize(str)
- local result = {}
- for pair in str:gmatch("([^,]+)") do
- local k, v = pair:match("(.-)=(.*)")
- result[trim(k)] = trim(v)
- end
- return result
- end
- local function bootUpScreen()
- term.clear()
- local logo = [[
- :::::::: :::::::: ::: ::: :::::::::: :::::::::
- :+: :+: :+: :+: :+: :+: :+: :+: :+:
- +:+ +:+ +:+ +:+ +:+ +:+ +:+ +:+
- +#+ +:+ +#+ +#++:++#++:++ +#+ +:+ +#+ +#++:++# +#++:++#+
- +#+ +#+ +#+ +#+ +#+#+ +#+ +#+ +#+ +#+
- #+# #+# #+# #+# #+#+# #+#+# #+# #+# #+#
- ######## ######## ### ### ########## #########
- ]]
- term.setCursor(1, 1)
- term.write(logo)
- term.setCursor(1, select(2, term.getCursor()) + 1)
- term.write("Loading...")
- term.setCursor(1, select(2, term.getCursor()) + 2)
- term.write("OC-WEB 2.0: A Web Browser For OpenComputers Coded by nonogamer9")
- os.sleep(3)
- end
- local function resolveURL(base, relative)
- if not base or not relative then return nil end
- if relative:match("^https?://") then return relative end
- if relative:sub(1, 1) == "/" then
- return base:match("^(https?://[^/]+)") .. relative
- else
- local baseMatch = base:match("^(https?://.*/)") or base:match("^(https?://[^/]+)")
- if baseMatch then
- if baseMatch:sub(-1) ~= "/" then
- baseMatch = baseMatch .. "/"
- end
- return baseMatch .. relative
- else
- return nil
- end
- end
- end
- local function handleJavaScript(html, currentBaseURL)
- local redirectUrl = html:match("window%.location%s*=%s*['\"](.-)['\"]")
- if redirectUrl then
- return resolveURL(currentBaseURL, redirectUrl)
- end
- return nil
- end
- local function fetch(url, visited)
- visited = visited or {}
- if visited[url] then
- return false, "Redirect loop detected"
- end
- visited[url] = true
- local headers = {
- ["User-Agent"] = "OpenComputers/2.0 (Compatible; OCWeb/2.0)",
- ["Accept"] = "text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8",
- }
- os.sleep(0)
- local handle, err = internet.request(url, nil, headers)
- if not handle then
- return false, "Failed to connect to " .. url .. ": " .. (err or "unknown error")
- end
- local data = ""
- local status, responseHeaders
- local startTime = computer.uptime()
- local chunkCount = 0
- for chunk in handle do
- chunkCount = chunkCount + 1
- if computer.uptime() - startTime > 0.5 or chunkCount % 10 == 0 then
- os.sleep(0)
- startTime = computer.uptime()
- end
- if not status then
- status, responseHeaders = handle.response()
- end
- if chunk then
- data = data .. chunk
- end
- end
- os.sleep(0)
- if status then
- if status >= 400 then
- return false, "HTTP Error: " .. status
- elseif status >= 300 and status < 400 then
- local redirectUrl = responseHeaders and responseHeaders["location"]
- if redirectUrl then
- local resolvedRedirectUrl = resolveURL(url, redirectUrl)
- if resolvedRedirectUrl then
- print("Redirecting to: " .. resolvedRedirectUrl)
- os.sleep(0)
- return fetch(resolvedRedirectUrl, visited)
- else
- return false, "Invalid redirect URL: " .. redirectUrl
- end
- end
- end
- end
- os.sleep(0)
- local metaRedirectUrl = data:match('<meta%s+http%-equiv="refresh"%s+content=".-;url=(.-)"')
- if metaRedirectUrl then
- local resolvedRedirectUrl = resolveURL(url, metaRedirectUrl)
- if resolvedRedirectUrl then
- print("Meta redirecting to: " .. resolvedRedirectUrl)
- os.sleep(0) -- Yield before recursive call
- return fetch(resolvedRedirectUrl, visited)
- else
- return false, "Invalid meta redirect URL: " .. metaRedirectUrl
- end
- end
- os.sleep(0)
- local jsRedirectUrl = handleJavaScript(data, url)
- if jsRedirectUrl then
- print("JavaScript redirecting to: " .. jsRedirectUrl)
- os.sleep(0)
- return fetch(jsRedirectUrl, visited)
- end
- return true, data
- end
- local function parseCSS(cssText)
- local styles = {}
- for selector, properties in cssText:gmatch("([^{]+){([^}]+)}") do
- selector = trim(selector)
- styles[selector] = {}
- for property, value in properties:gmatch("([^:]+):([^;]+)") do
- styles[selector][trim(property)] = trim(value)
- end
- os.sleep(0)
- end
- return styles
- end
- local function applyStyles(text, styles)
- if styles["color"] then
- local color = tonumber(styles["color"]:match("#(%x+)"), 16) or 0xFFFFFF
- gpu.setForeground(color)
- end
- if styles["background-color"] then
- local bgColor = tonumber(styles["background-color"]:match("#(%x+)"), 16) or 0x000000
- gpu.setBackground(bgColor)
- end
- if styles["font-weight"] == "bold" then
- text = "[B]" .. text .. "[/B]"
- end
- if styles["font-style"] == "italic" then
- text = "[I]" .. text .. "[/I]"
- end
- return text
- end
- local function parseHTML(html, baseStyles)
- local links = {}
- local styles = baseStyles or {}
- html = html:gsub('style="(.-)"', function(style)
- local inlineStyles = {}
- for property, value in style:gmatch("([^:]+):([^;]+)") do
- inlineStyles[trim(property)] = trim(value)
- end
- return "data-inline-style='" .. serialize(inlineStyles) .. "'"
- end)
- html = html:gsub("<script.->.-</script>", "")
- html = html:gsub("<style.->.-</style>", "")
- html = html:gsub("<b>(.-)</b>", function(content) return "[B]" .. content .. "[/B]" end)
- html = html:gsub("<strong>(.-)</strong>", function(content) return "[B]" .. content .. "[/B]" end)
- html = html:gsub("<i>(.-)</i>", function(content) return "[I]" .. content .. "[/I]" end)
- html = html:gsub("<em>(.-)</em>", function(content) return "[I]" .. content .. "[/I]" end)
- html = html:gsub("<u>(.-)</u>", function(content) return "[U]" .. content .. "[/U]" end)
- html = html:gsub("<a href=\"(.-)\">(.-)</a>", function(href, content)
- table.insert(links, {href = href, content = content})
- return content .. " [" .. #links .. "]"
- end)
- html = html:gsub("<h([1-6])>(.-)</h%1>", function(level, content) return "[H" .. level .. "]" .. content .. "[/H" .. level .. "]" end)
- html = html:gsub("<li>(.-)</li>", function(content) return " * " .. content end)
- html = html:gsub("<br>", "\n")
- html = html:gsub("<p>(.-)</p>", function(content) return "\n\n" .. content .. "\n\n" end)
- html = html:gsub("<div>(.-)</div>", function(content) return content .. "\n" end)
- html = html:gsub("<table>(.-)</table>", function(tableContent)
- local result = "\n"
- for row in tableContent:gmatch("<tr>(.-)</tr>") do
- for cell in row:gmatch("<t[dh]>(.-)</t[dh]>") do
- result = result .. cell .. "\t"
- end
- result = result .. "\n"
- end
- return result
- end)
- html = html:gsub("data%-inline%-style='(.-)'(.-)", function(styleData, content)
- local inlineStyles = deserialize(styleData)
- return applyStyles(content, inlineStyles)
- end)
- html = html:gsub("<.->", "")
- html = html:gsub("<", "<")
- html = html:gsub(">", ">")
- html = html:gsub("&", "&")
- html = html:gsub(""", "\"")
- html = html:gsub("'", "'")
- html = html:gsub(" ", " ")
- html = html:gsub("—", "—")
- os.sleep(0)
- return html, links
- end
- local function display(baseURL, data, links, styles)
- local w, h = gpu.getResolution()
- local bufferIndex = gpu.allocateBuffer(w, h)
- gpu.setActiveBuffer(bufferIndex)
- local lines = {}
- for line in data:gmatch("[^\r\n]+") do
- table.insert(lines, line)
- if #lines % 10 == 0 then
- os.sleep(0)
- end
- end
- local offset = 0
- local contentHeight = h - 1
- local function redraw()
- gpu.setBackground(0x000000)
- gpu.fill(1, 1, w, h, " ")
- for i = 1, contentHeight do
- local line = lines[i + offset] or ""
- line = applyStyles(line, styles["body"] or {})
- for tag, tagStyles in pairs(styles) do
- if tag ~= "body" then
- line = line:gsub("%[" .. tag .. "%](.-)[/%]", function(content)
- return applyStyles(content, tagStyles)
- end)
- end
- end
- gpu.set(1, i, unicode.sub(line, 1, w))
- if i % 5 == 0 then
- os.sleep(0)
- end
- end
- gpu.setBackground(0x333333)
- gpu.fill(1, h, w, 1, " ")
- gpu.set(1, h, "URL: " .. (baseURL or "N/A") .. " | Use Arrow Keys to Scroll, Q to Quit, U to Change URL")
- gpu.setBackground(0x000000)
- gpu.setActiveBuffer(0)
- gpu.bitblt(0, 1, 1, w, h, bufferIndex)
- gpu.setActiveBuffer(bufferIndex)
- end
- redraw()
- while true do
- local eventType, _, _, y, _, scrollDirection = event.pull()
- local needsRedraw = false
- if eventType == "key_down" then
- if y == 200 then
- offset = math.max(0, offset - 1)
- needsRedraw = true
- elseif y == 208 then
- offset = math.min(#lines - contentHeight, offset + 1)
- needsRedraw = true
- elseif y == 16 then
- break
- elseif y == 22 then
- gpu.freeBuffer(bufferIndex)
- return false
- end
- elseif eventType == "scroll" then
- if scrollDirection == 1 then
- offset = math.max(0, offset - 1)
- needsRedraw = true
- elseif scrollDirection == -1 then
- offset = math.min(#lines - contentHeight, offset + 1)
- needsRedraw = true
- end
- elseif eventType == "touch" then
- local lineIndex = y + offset
- if lineIndex <= #lines then
- local line = lines[lineIndex]
- local linkIndex = line:match("%[(%d+)%]$")
- if linkIndex then
- local link = links[tonumber(linkIndex)]
- if link and link.href then
- local resolvedURL = resolveURL(baseURL, link.href)
- if resolvedURL then
- print("Opening link: " .. resolvedURL)
- gpu.freeBuffer(bufferIndex)
- local success, newData = fetch(resolvedURL)
- if success then
- local newStyles = parseCSS(newData:match("<style>(.-)</style>") or "")
- local newParsedData, newLinks = parseHTML(newData, newStyles)
- display(resolvedURL, newParsedData, newLinks, newStyles)
- else
- print("Error fetching URL: " .. newData)
- end
- return
- else
- print("Invalid URL: " .. tostring(link.href))
- end
- else
- print("Invalid link at index: " .. linkIndex)
- end
- end
- end
- end
- if needsRedraw then
- redraw()
- end
- os.sleep(0)
- end
- gpu.freeBuffer(bufferIndex)
- end
- function main(showBootScreen)
- if showBootScreen then
- bootUpScreen()
- end
- term.clear()
- print("Enter a URL:")
- local url = io.read()
- if not url:match("^https?://") then
- print("Invalid URL. Please include http:// or https://")
- else
- local success, data = fetch(url)
- if success then
- local styles = parseCSS(data:match("<style>(.-)</style>") or "")
- local parsedData, links = parseHTML(data, styles)
- if display(url, parsedData, links, styles) == false then
- main(false)
- end
- else
- print("Error fetching URL: " .. data)
- end
- end
- end
- main(true)
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement