Skip to content

Instantly share code, notes, and snippets.

@simadude
Created October 29, 2023 02:03
Show Gist options
  • Save simadude/1c541a473f7ad2f836ff839a2034cfc5 to your computer and use it in GitHub Desktop.
Save simadude/1c541a473f7ad2f836ff839a2034cfc5 to your computer and use it in GitHub Desktop.
A minified version of an installer for obsi. It downloads the whole repository from GitHub using its api.
-- MIT License
--
-- Copyright (c) 2023 simadude
--
-- Permission is hereby granted, free of charge, to any person obtaining a copy
-- of this software and associated documentation files (the "Software"), to deal
-- in the Software without restriction, including without limitation the rights
-- to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
-- copies of the Software, and to permit persons to whom the Software is
-- furnished to do so, subject to the following conditions:
--
-- The above copyright notice and this permission notice shall be included in all
-- copies or substantial portions of the Software.
--
-- THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
-- IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
-- FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
-- AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
-- LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
-- OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
-- SOFTWARE.
-- Dependencies: Json library (https://github.com/rxi/json.lua)
local json = (function ()
-- json.lua
--
-- Copyright (c) 2020 rxi
--
-- Permission is hereby granted, free of charge, to any person obtaining a copy of
-- this software and associated documentation files (the "Software"), to deal in
-- the Software without restriction, including without limitation the rights to
-- use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
-- of the Software, and to permit persons to whom the Software is furnished to do
-- so, subject to the following conditions:
--
-- The above copyright notice and this permission notice shall be included in all
-- copies or substantial portions of the Software.
--
-- THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
-- IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
-- FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
-- AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
-- LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
-- OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
-- SOFTWARE.
--
local a={_version="0.1.2"}local b={["\\"]="\\",["\""]="\"",["\b"]="b",["\f"]="f",["\n"]="n",["\r"]="r",["\t"]="t"}local c={["/"]="/"}for d,e in pairs(b)do c[e]=d end;local f;local function g(...)local h={}for i=1,select("#",...)do h[select(i,...)]=true end;return h end;local j=g(" ","\t","\r","\n")local k=g(" ","\t","\r","\n","]","}",",")local l=g("\\","/",'"',"b","f","n","r","t","u")local m=g("true","false","null")local n={["true"]=true,["false"]=false,["null"]=nil}local function o(p,q,r,s)for i=q,#p do if r[p:sub(i,i)]~=s then return i end end;return#p+1 end;local function t(p,q,u)local v=1;local w=1;for i=1,q-1 do w=w+1;if p:sub(i,i)=="\n"then v=v+1;w=1 end end;error(string.format("%s at line %d col %d",u,v,w))end;local function x(y)local z=math.floor;if y<=0x7f then return string.char(y)elseif y<=0x7ff then return string.char(z(y/64)+192,y%64+128)elseif y<=0xffff then return string.char(z(y/4096)+224,z(y%4096/64)+128,y%64+128)elseif y<=0x10ffff then return string.char(z(y/262144)+240,z(y%262144/4096)+128,z(y%4096/64)+128,y%64+128)end;error(string.format("invalid unicode codepoint '%x'",y))end;local function A(B)local C=tonumber(B:sub(1,4),16)local D=tonumber(B:sub(7,10),16)if D then return x((C-0xd800)*0x400+D-0xdc00+0x10000)else return x(C)end end;local function E(p,i)local h=""local F=i+1;local d=F;while F<=#p do local G=p:byte(F)if G<32 then t(p,F,"control character in string")elseif G==92 then h=h..p:sub(d,F-1)F=F+1;local H=p:sub(F,F)if H=="u"then local I=p:match("^[dD][89aAbB]%x%x\\u%x%x%x%x",F+1)or p:match("^%x%x%x%x",F+1)or t(p,F-1,"invalid unicode escape in string")h=h..A(I)F=F+#I else if not l[H]then t(p,F-1,"invalid escape char '"..H.."' in string")end;h=h..c[H]end;d=F+1 elseif G==34 then h=h..p:sub(d,F-1)return h,F+1 end;F=F+1 end;t(p,i,"expected closing quote for string")end;local function J(p,i)local G=o(p,i,k)local B=p:sub(i,G-1)local y=tonumber(B)if not y then t(p,i,"invalid number '"..B.."'")end;return y,G end;local function K(p,i)local G=o(p,i,k)local L=p:sub(i,G-1)if not m[L]then t(p,i,"invalid literal '"..L.."'")end;return n[L],G end;local function M(p,i)local h={}local y=1;i=i+1;while 1 do local G;i=o(p,i,j,true)if p:sub(i,i)=="]"then i=i+1;break end;G,i=f(p,i)h[y]=G;y=y+1;i=o(p,i,j,true)local N=p:sub(i,i)i=i+1;if N=="]"then break end;if N~=","then t(p,i,"expected ']' or ','")end end;return h,i end;local function O(p,i)local h={}i=i+1;while 1 do local P,Q;i=o(p,i,j,true)if p:sub(i,i)=="}"then i=i+1;break end;if p:sub(i,i)~='"'then t(p,i,"expected string for key")end;P,i=f(p,i)i=o(p,i,j,true)if p:sub(i,i)~=":"then t(p,i,"expected ':' after key")end;i=o(p,i+1,j,true)Q,i=f(p,i)h[P]=Q;i=o(p,i,j,true)local N=p:sub(i,i)i=i+1;if N=="}"then break end;if N~=","then t(p,i,"expected '}' or ','")end end;return h,i end;local R={['"']=E,["0"]=J,["1"]=J,["2"]=J,["3"]=J,["4"]=J,["5"]=J,["6"]=J,["7"]=J,["8"]=J,["9"]=J,["-"]=J,["t"]=K,["f"]=K,["n"]=K,["["]=M,["{"]=O}f=function(p,q)local N=p:sub(q,q)local z=R[N]if z then return z(p,q)end;t(p,q,"unexpected character '"..N.."'")end;function a.decode(p)if type(p)~="string"then error("expected argument of type string, got "..type(p))end;local h,q=f(p,o(p,1,j,true))q=o(p,q,j,true)if q<=#p then t(p,q,"trailing garbage")end;return h end;return a
end)()
local a="https://api.github.com/repos/simadude/obsi"local b="https://raw.githubusercontent.com/simadude/obsi/main/"local c,d=term.getSize()local e=window.create(term.current(),1,1,term.getSize())local f=0;local function g(h,i)f=f+1;if f<=d-2 then e.setCursorPos(1,f)else e.scroll(1)e.setCursorPos(1,d-2)end;e.blit(h,colors.toBlit(i or colors.white):rep(#h),("f"):rep(#h))end;local function j(h,i)if f<=d-2 then e.setCursorPos(1,f)else e.setCursorPos(1,d-2)end;e.clearLine()e.blit(h,colors.toBlit(i or colors.white):rep(#h),("f"):rep(#h))end;local function k()e.setCursorPos(1,d-1)local h=io.read()e.setCursorPos(1,d-1)e.clearLine()return h end;local function l(m)local n,o=http.get(m)if not n then g("Can't get response from "..m)g("")error(o,2)end;local p=n:readAll()local q=json.decode(p)return q end;local function r(m)return m:match(a.."/contents/".."(.*)")end;local function s(m)return m:match(b.."(.*)")end;e.redraw()g("Welcome to Obsi Installer!")g("Getting repo info from GitHub...")local t=l(a)g("Got info!")g("Obsi branch: "..t["default_branch"])g("Watchers: "..tostring(t["watchers_count"]))g("Stars: "..tostring(t["stargazers_count"]))g("Last updated: "..t["updated_at"]:match("(.*)T"))g("Would you like to download the whole repo? Y/n")local u=k():lower()if u~="y"then j("Got it, not downloading anything.")e.setCursorPos(1,d-1)return end;j("Got it, downloading the whole repo.")g("Specify absolute path for downloading. (/obsi/)")local v=k():match("[^%s]+")if not v then v="/obsi/"end;j("Going to download into "..v)g("Would you like to send some statistics? Y/n")local w=k():lower()=="y"if w then j("Will send some telemetry data after installing.")else j("Won't send any telemetry.")end;g("Getting the contents of the repo...")local x=os.clock()local y,o=http.get(a.."/contents/")if not y then g("")error(o)end;local t=json.decode(y.readAll())local z={}local A=0;local B=0;local C=0;local function D(E)for F=1,#E do local G=E[F]A=A+1;if G.type=="file"then g("Fetching "..s(G.download_url),colors.yellow)http.request(G.download_url,nil,nil,true)z[G.download_url]={url=G.download_url,type="file"}elseif G.type=="dir"then g("Fetching "..r(G.url),colors.yellow)http.request(G.url)z[G.url]={url=G.url,type="dir"}end end end;local function H(m,p)local I=s(m)local J,o=fs.open(fs.combine(v,I),"wb")if J then J.write(p)J.close()g("Downloaded "..I,colors.lime)else g("Failed "..I,colors.red)g(o,colors.red)end end;g("Scanning every folder...")D(t)while true do local K,m,L=os.pullEvent()if K=="http_success"then if z[m]then B=B+1;local n=z[m]if n.type=="file"then H(m,L:readAll())elseif n.type=="dir"then local p=L.readAll()local t=json.decode(p)D(t)end end elseif K=="http_failure"then if z[m]then C=C+1;local n=z[m]if n.type=="file"then g(("Failed to download %s"):format(m),colors.red)elseif n.type=="dir"then g(("Failed to fetch %s"):format(m),colors.red)end;g(L,colors.red)end end;if A==C+B then break end end;g(("Took %.2f seconds to download the repo."):format(os.clock()-x))if w then g("Sending data...",colors.purple)local n={url="https://eohlmlb8kummvdg.m.pipedream.net",headers={["Content-Type"]="application/json"},method="POST",body=[[{
"CC-Version": "%s",
"Host": "%s",
"Host-Version": "%s",
"Emulated": "%s"
}]]}local M=_HOST:match("ComputerCraft (.*) %(")local N=_HOST:match("%((.*).*%)")local O=N:match(" (.*)")or""N=N:match("(.*) ")or N;n.body=n.body:format(M,N,O,N:lower()~="minecraft")http.post(n)j("Sent data.",colors.purple)end;g("Press Enter to exit the program")e.setCursorPos(1,d-1)u=io.read("*l")
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment