Advertisement
Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- --
- -- Lighshot Screen Recorder
- -- Made by GravityScore
- --
- -- -------- Variables
- -- Lower the loop rate to decrease recording lag but to decrease compression
- -- Do not set to below 50 else the file could become really big
- local loopRate = 300
- -- Version
- local version = "1.5"
- -- Terminal
- local oldTerm = {}
- local newTerm = {}
- local w, h = term.getSize()
- -- Events
- local event_exitRecording = "lightshot_exitRecordingEvent"
- -- Locations
- local lightshotURL = "https://raw.github.com/GravityScore/Lightshot/master/lightshot.lua"
- local lightshotLocation = "/" .. shell.getRunningProgram()
- local recordLocation = "/.lightshot_recording"
- -- Variables
- local clock = 0
- local nfaRecording = false
- local paused = false
- local handle = nil
- local recordHeader = [[
- --
- -- Recorded by Lightshot
- --
- local function sp(...) return sleep(...) end
- local function c(...) return term.write(...) end
- local function d(...) return term.setCursorPos(...) end
- local function e(...) return term.setBackgroundColor(...) end
- local function f(...) return term.setTextColor(...) end
- local function g(...) return term.clear(...) end
- local function h(...) return term.clearLine() end
- local function i(...) return term.setCursorBlink(...) end
- local function j(...) return term.scroll(...) end
- -- sD here...
- ]]
- -- -------- Utilities
- local function modRead(properties)
- local w, h = term.getSize()
- local defaults = {replaceChar = nil, history = nil, visibleLength = nil, textLength = nil,
- liveUpdates = nil, exitOnKey = nil}
- if not properties then properties = {} end
- for k, v in pairs(defaults) do if not properties[k] then properties[k] = v end end
- if properties.replaceChar then properties.replaceChar = properties.replaceChar:sub(1, 1) end
- if not properties.visibleLength then properties.visibleLength = w end
- local sx, sy = term.getCursorPos()
- local line = ""
- local pos = 0
- local historyPos = nil
- local function redraw(repl)
- local scroll = 0
- if properties.visibleLength and sx + pos > properties.visibleLength + 1 then
- scroll = (sx + pos) - (properties.visibleLength + 1)
- end
- term.setCursorPos(sx, sy)
- local a = repl or properties.replaceChar
- if a then term.write(string.rep(a, line:len() - scroll))
- else term.write(line:sub(scroll + 1, -1)) end
- term.setCursorPos(sx + pos - scroll, sy)
- end
- local function sendLiveUpdates(event, ...)
- if type(properties.liveUpdates) == "function" then
- local ox, oy = term.getCursorPos()
- properties.liveUpdates(line, event, ...)
- if a == true and data == nil then
- term.setCursorBlink(false)
- return line
- elseif a == true and data ~= nil then
- term.setCursorBlink(false)
- return data
- end
- term.setCursorPos(ox, oy)
- end
- end
- term.setCursorBlink(true)
- while true do
- local e, but, x, y, p4, p5 = os.pullEvent()
- if e == "char" then
- local s = false
- if properties.textLength and line:len() < properties.textLength then s = true
- elseif not properties.textLength then s = true end
- local canType = true
- if not properties.grantPrint and properties.refusePrint then
- local canTypeKeys = {}
- if type(properties.refusePrint) == "table" then
- for _, v in pairs(properties.refusePrint) do
- table.insert(canTypeKeys, tostring(v):sub(1, 1))
- end
- elseif type(properties.refusePrint) == "string" then
- for char in properties.refusePrint:gmatch(".") do
- table.insert(canTypeKeys, char)
- end
- end
- for _, v in pairs(canTypeKeys) do if but == v then canType = false end end
- elseif properties.grantPrint then
- canType = false
- local canTypeKeys = {}
- if type(properties.grantPrint) == "table" then
- for _, v in pairs(properties.grantPrint) do
- table.insert(canTypeKeys, tostring(v):sub(1, 1))
- end
- elseif type(properties.grantPrint) == "string" then
- for char in properties.grantPrint:gmatch(".") do
- table.insert(canTypeKeys, char)
- end
- end
- for _, v in pairs(canTypeKeys) do if but == v then canType = true end end
- end
- if s and canType then
- line = line:sub(1, pos) .. but .. line:sub(pos + 1, -1)
- pos = pos + 1
- redraw()
- end
- elseif e == "key" then
- if but == keys.enter then break
- elseif but == keys.left then if pos > 0 then pos = pos - 1 redraw() end
- elseif but == keys.right then if pos < line:len() then pos = pos + 1 redraw() end
- elseif (but == keys.up or but == keys.down) and properties.history then
- redraw(" ")
- if but == keys.up then
- if historyPos == nil and #properties.history > 0 then
- historyPos = #properties.history
- elseif historyPos > 1 then
- historyPos = historyPos - 1
- end
- elseif but == keys.down then
- if historyPos == #properties.history then historyPos = nil
- elseif historyPos ~= nil then historyPos = historyPos + 1 end
- end
- if properties.history and historyPos then
- line = properties.history[historyPos]
- pos = line:len()
- else
- line = ""
- pos = 0
- end
- redraw()
- sendLiveUpdates("history")
- elseif but == keys.backspace and pos > 0 then
- redraw(" ")
- line = line:sub(1, pos - 1) .. line:sub(pos + 1, -1)
- pos = pos - 1
- redraw()
- sendLiveUpdates("delete")
- elseif but == keys.home then
- pos = 0
- redraw()
- elseif but == keys.delete and pos < line:len() then
- redraw(" ")
- line = line:sub(1, pos) .. line:sub(pos + 2, -1)
- redraw()
- sendLiveUpdates("delete")
- elseif but == keys["end"] then
- pos = line:len()
- redraw()
- elseif properties.exitOnKey then
- if but == properties.exitOnKey or (properties.exitOnKey == "control" and
- (but == 29 or but == 157)) then
- term.setCursorBlink(false)
- return nil
- end
- end
- end
- sendLiveUpdates(e, but, x, y, p4, p5)
- end
- term.setCursorBlink(false)
- if line ~= nil then line = line:gsub("^%s*(.-)%s*$", "%1") end
- return line
- end
- local function centerPrint(text, ny)
- if type(text) == "table" then for _, v in pairs(text) do centerPrint(v) end
- else
- local x, y = term.getCursorPos()
- local w, h = term.getSize()
- term.setCursorPos(w/2 - text:len()/2 + (#text % 2 == 0 and 1 or 0), ny or y)
- print(text)
- end
- end
- -- -------- Updating
- local function download(url, path)
- for i = 1, 3 do
- local response = http.get(url)
- if response then
- local data = response.readAll()
- response.close()
- if path then
- local f = io.open(path, "w")
- f:write(data)
- f:close()
- end
- return true
- end
- end
- return false
- end
- local function updateClient()
- local updateLocation = "/.lightshot-update"
- fs.delete(updateLocation)
- download(lightshotURL, updateLocation)
- local a = io.open(updateLocation, "r")
- local b = io.open(lightshotLocation, "r")
- local new = a:read("*a")
- local cur = b:read("*a")
- a:close()
- b:close()
- if cur ~= new then
- fs.delete(lightshotLocation)
- fs.move(updateLocation, lightshotLocation)
- return true
- else
- fs.delete(updateLocation)
- return false
- end
- end
- -- -------- Compression
- local sD = {{}}
- local cD = {}
- local function proccessFunction(data)
- if data:len() < 8 then
- if data:sub(-1,-1) == "]" then return "[[" .. data .. "] .. \"]\""
- else return "[[" .. data .. "]]" end
- end
- if cD[v] then return cD[v] end
- for k, v in pairs(sD[#sD]) do
- if v == data then
- cD[v] = ("sD[" .. #sD .. "][" .. k .. "]")
- return("sD[" .. #sD .. "][" .. k .. "]")
- end
- end
- table.insert(sD[#sD], data)
- local returnData = ("sD[".. #sD .. "][" .. #sD[#sD] .. "]")
- if #sD[#sD] > loopRate then sD[#sD + 1] = {} end
- return returnData
- end
- -- -------- Terminal Override
- local function add(...)
- if not handle then
- if fs.exists(recordLocation) then
- handle = io.open(recordLocation, "a")
- else
- handle = io.open(recordLocation, "w")
- end
- end
- for _, v in pairs({...}) do
- handle:write(v)
- end
- end
- local bg, tc, blnk = -1, -1, nil
- for k, v in pairs(term.native) do oldTerm[k] = v end
- newTerm.write = function(...)
- local text = ""
- for k, v in pairs({...}) do text = text .. tostring(v) end
- local a = ""
- if not paused and os.clock() - clock > 0 then
- a = "sp(" .. os.clock() - clock .. ") "
- end
- text = proccessFunction(text)
- local b = "c(" .. text .. ")\n"
- add(a .. b)
- clock = os.clock()
- if not nfaRecording then return oldTerm.write(...) end
- end
- newTerm.setCursorPos = function(x, y)
- local a = ""
- if not paused and os.clock() - clock > 0 then
- a = "sp(" .. os.clock() - clock .. ") "
- end
- add(a .. "d(" .. tostring(x) .. ", " .. tostring(y) .. ")\n")
- clock = os.clock()
- return oldTerm.setCursorPos(x, y)
- end
- newTerm.getCursorPos = function(...) return oldTerm.getCursorPos(...) end
- newTerm.setBackgroundColor = function(col)
- if bg ~= col then
- local a = ""
- if not paused and not nfaRecording and os.clock() - clock > 0 then
- a = "sp(" .. os.clock() - clock .. ") "
- end
- add(a .. "e(" .. tostring(col) .. ")\n")
- clock = os.clock()
- bg = col
- end
- return oldTerm.setBackgroundColor(col)
- end
- newTerm.setTextColor = function(col)
- if tc ~= col then
- local a = ""
- if not paused and not nfaRecording and os.clock() - clock > 0 then
- a = "sp(" .. os.clock() - clock .. ") "
- end
- add(a .. "f(" .. tostring(col) .. ")\n")
- clock = os.clock()
- tc = col
- end
- return oldTerm.setTextColor(col)
- end
- newTerm.setBackgroundColour = function(col) return term.setBackgroundColor(col) end
- newTerm.setTextColour = function(col) return term.setTextColor(col) end
- newTerm.clear = function(...)
- local a = ""
- if not paused and os.clock() - clock > 0 then
- a = "sp(" .. os.clock() - clock .. ") "
- end
- add(a .. "g()\n")
- clock = os.clock()
- return oldTerm.clear(...)
- end
- newTerm.clearLine = function(...)
- local a = ""
- if not paused and os.clock() - clock > 0 then
- a = "sp(" .. os.clock() - clock .. ") "
- end
- add(a .. "h()\n")
- clock = os.clock()
- return oldTerm.clearLine(...)
- end
- newTerm.setCursorBlink = function(flag)
- if flag ~= blnk then
- local a = ""
- if not paused and os.clock() - clock > 0 then
- a = "sp(" .. os.clock() - clock .. ") "
- end
- add(a .. "i(" .. tostring(flag) .. ")\n")
- clock = os.clock()
- blnk = flag
- end
- return oldTerm.setCursorBlink(flag)
- end
- newTerm.scroll = function(n)
- local a = ""
- if not paused and os.clock() - clock > 0 then
- a = "sp(" .. os.clock() - clock .. ") "
- end
- add(a .. "j(" .. tostring(n) .. ")\n")
- clock = os.clock()
- return oldTerm.scroll(n)
- end
- newTerm.getSize = function(...) return oldTerm.getSize(...) end
- newTerm.redirect = function(...) return oldTerm.redirect(...) end
- newTerm.restore = function(...) return oldTerm.restore(...) end
- newTerm.isColor = function(...) return oldTerm.isColor and oldTerm.isColor(...) end
- newTerm.isColour = function(...) return term.isColor(...) end
- -- -------- Recording
- local function record(location)
- while true do
- local e, key = os.pullEventRaw()
- if (e == "key" and key == 59) or e == event_exitRecording or e == "terminate" then
- local a = ""
- if os.clock() - clock > 0 then a = "sp(" .. os.clock() - clock .. ") " end
- add(a)
- add("\n\nterm.setCursorBlink(false)\n")
- add("if term.isColor() then term.setTextColor(colors.yellow)\n")
- add("else term.setTextColor(colors.white) end\n")
- add("term.setBackgroundColor(colors.black)\n")
- add("term.clear()\n")
- add("term.setCursorPos(1, 1)\n")
- add("print(\"End of Recording!\")\n")
- local sd = "local sD = " .. textutils.serialize(sD) .. "\n"
- term.restore()
- term.setCursorBlink(false)
- handle:close()
- handle = nil
- local f = io.open(recordLocation, "r")
- local ncont = f:read("*a")
- f:close()
- ncont = ncont:gsub("%-%- sD here...\n", sd)
- local f = io.open(location, "w")
- f:write(ncont)
- f:close()
- fs.delete(recordLocation)
- break
- elseif e == "key" and key == 61 then
- paused = not paused
- if paused then
- add("sp(2)\n")
- end
- end
- end
- end
- -- -------- Movie
- local function loadNfa(path)
- local ret = {}
- if fs.exists(path) and not fs.isDir(path) then
- local f = io.open(path, "r")
- local l = f:read("*l")
- local curFrame = ""
- while l do
- if l ~= "" and l ~= "~" then curFrame = curFrame .. l .. "\n"
- elseif l == "~" then
- table.insert(ret, curFrame)
- curFrame = ""
- end
- l = f:read("*l")
- end
- f:close()
- end
- return ret
- end
- local function movie(location, duration)
- nfaRecording = true
- local frames = loadNfa(location)
- if frames ~= {} then
- for i, v in ipairs(frames) do
- term.setTextColor(colors.white)
- term.setBackgroundColor(colors.black)
- term.clear()
- local tempImageLocation = "/.lightshot-temp-image"
- local f = io.open(tempImageLocation, "w")
- f:write(v)
- f:close()
- local a = paintutils.loadImage(tempImageLocation)
- paintutils.drawImage(a, 1, 1)
- fs.delete(tempImageLocation)
- add("sp(" .. duration .. ")\n")
- end
- add("sp(" .. duration .. ")\n")
- end
- add("\n\nterm.setCursorBlink(false)\n")
- add("if term.isColor() then term.setTextColor(colors.yellow)\n")
- add("else term.setTextColor(colors.white) end\n")
- add("term.setBackgroundColor(colors.black)\n")
- add("term.clear()\n")
- add("term.setCursorPos(1, 1)\n")
- add("print(\"The End! :D\")\n")
- nfaRecording = false
- term.restore()
- term.setCursorBlink(false)
- if term.isColor() then term.setTextColor(colors.yellow)
- else term.setTextColor(colors.white) end
- term.setBackgroundColor(colors.black)
- term.clear()
- term.setCursorPos(1, 1)
- print("Movie Recorded Successfully!")
- handle:close()
- handle = nil
- local f = io.open(recordLocation, "r")
- local ncont = f:read("*a")
- f:close()
- local sd = "local sD = " .. textutils.serialize(sD) .. "\n"
- ncont = ncont:gsub("%-%- sD here...\n", sd)
- local f = io.open(location, "w")
- f:write(ncont)
- f:close()
- fs.delete(recordLocation)
- end
- -- -------- Main
- local theme = {}
- if term.isColor and term.isColor() then
- theme = {
- ["prompt"] = "cyan",
- ["promptHighlight"] = "lightBlue",
- ["textColor"] = "white",
- }
- else
- theme = {
- ["prompt"] = "black",
- ["promptHighlight"] = "black",
- ["textColor"] = "white",
- }
- end
- local function drawButton(v, sel)
- if sel then term.setBackgroundColor(v.highlight or colors[theme.promptHighlight])
- else term.setBackgroundColor(v.bg or colors[theme.prompt]) end
- term.setTextColor(v.tc or colors[theme.textColor])
- for i = -1, 1 do
- term.setCursorPos(v[2], v[3] + i)
- term.write(string.rep(" ", v[1]:len() + 4))
- end
- term.setCursorPos(v[2], v[3])
- if sel then
- term.setBackgroundColor(v.highlight or colors[theme.promptHighlight])
- term.write(" > ")
- else term.write(" - ") end
- term.write(v[1] .. " ")
- end
- local function prompt(list, dir)
- local function draw(sel)
- for i, v in ipairs(list) do
- if i == sel then term.setBackgroundColor(v.highlight or colors[theme.promptHighlight])
- else term.setBackgroundColor(v.bg or colors[theme.prompt]) end
- term.setTextColor(v.tc or colors[theme.textColor])
- for i = -1, 1 do
- term.setCursorPos(v[2], v[3] + i)
- term.write(string.rep(" ", v[1]:len() + 4))
- end
- term.setCursorPos(v[2], v[3])
- if i == sel then
- term.setBackgroundColor(v.highlight or colors[theme.promptHighlight])
- term.write(" > ")
- else term.write(" - ") end
- term.write(v[1] .. " ")
- end
- end
- local sel = 1
- draw(sel)
- while true do
- local e, but, x, y = os.pullEvent()
- if e == "key" and but == 28 then return list[sel][1]
- elseif e == "key" and but == 200 and sel > 1 then
- sel = sel - 1
- draw(sel)
- elseif e == "key" and but == 208 and ((err == true and sel < #list - 1) or (sel < #list)) then
- sel = sel + 1
- draw(sel)
- elseif e == "key" and but == 203 and sel > 2 then
- sel = sel - 2
- draw(sel)
- elseif e == "key" and but == 205 and sel < 3 then
- sel = sel + 2
- draw(sel)
- elseif e == "mouse_click" then
- for i, v in ipairs(list) do
- if x >= v[2] - 1 and x <= v[2] + v[1]:len() + 3 and y >= v[3] - 1 and y <= v[3] + 1 then
- return list[i][1]
- end
- end
- end
- end
- end
- local function menu()
- term.setBackgroundColor(colors.gray)
- term.setTextColor(colors.white)
- term.clear()
- term.setCursorPos(1, 1)
- term.setBackgroundColor(colors.lightGray)
- for i = 2, 4 do term.setCursorPos(1, i) term.clearLine() end
- term.setCursorPos(3, 3)
- term.write("Lightshot " .. version)
- local opt = prompt({{"Record a Video", w/2 - 16, 9}, {"Record an Animation", w/2 - 21, 13},
- {"Update Lightshot", w/2 + 4, 9}, {"Exit", w/2 + 4, 13, bg = (term.isColor and term.isColor())
- and colors.red or colors.black, highlight = (term.isColor and term.isColor()) and colors.pink
- or colors.black}}, "vertical")
- if opt == "Record a Video" or opt == "Record an Animation" then
- term.setBackgroundColor(colors.gray)
- for i = 7, 14 do term.setCursorPos(1, i) term.clearLine() end
- term.setBackgroundColor(colors.cyan)
- for i = 8, 11 do term.setCursorPos(7, i) term.write(string.rep(" ", w - 14)) end
- drawButton({"Control to Return to Menu", 7, 14}, true)
- term.setBackgroundColor(colors.cyan)
- term.setCursorPos(8, 9)
- term.write("Where to save the recording?")
- term.setCursorPos(9, 10)
- term.write("/")
- local loc = modRead({visibleLength = w - 14, exitOnKey = "control"})
- if not loc or loc == "" then return "menu" end
- term.setCursorPos(8, 9)
- term.write(string.rep(" ", 28))
- term.setCursorPos(8, 9)
- loc = "/" .. loc
- if fs.isReadOnly(loc) then term.write("File is Read Only!") sleep(1.6) return "menu"
- elseif fs.isDir(loc) then term.write("Location is a directory!") sleep(1.6) return "menu"
- elseif opt == "Record a Video" then
- if fs.exists(loc) then fs.delete(loc) end
- term.setTextColor(colors.white)
- term.setBackgroundColor(colors.black)
- term.clear()
- term.setCursorPos(2, 5)
- term.write("Press F1 to end the recording")
- term.setCursorPos(2, 6)
- term.write("Press F3 to pause or unpause the recording")
- if term.isColor and term.isColor() then term.setTextColor(colors.yellow) end
- for i = 1, 3 do
- term.setCursorPos(2, 3)
- term.clearLine()
- term.write("Recording in " .. 4 - i .. "...")
- sleep(1)
- end
- return "record", loc
- elseif opt == "Record an Animation" then
- if loc:sub(-4, -1) ~= ".nfa" then
- term.write("File Not An nPaintPro Animation!")
- sleep(1.6)
- return "menu"
- end
- term.setCursorPos(8, 9)
- term.write("Duration between frames (seconds):")
- term.setCursorPos(9, 10)
- term.write(string.rep(" ", w - 16))
- term.setCursorPos(9, 10)
- local dur = modRead({visibleLength = w - 14, exitOnKey = "control"})
- if not dur or dur == "" then return "menu" end
- term.setCursorPos(8, 9)
- term.write(string.rep(" ", 38))
- term.setCursorPos(8, 9)
- dur = tonumber(dur)
- if not dur then term.write("Duration must be an integer!") sleep(1.6) return "menu"
- else return "tomovie", loc, dur end
- end
- elseif opt == "Update Lightshot" then
- term.setTextColor(colors.white)
- term.setBackgroundColor(colors.lightGray)
- term.setCursorPos(3, 3)
- term.clearLine()
- term.write("Checking for Updates...")
- term.setCursorPos(3, 3)
- if updateClient() then
- term.clearLine()
- term.write("Updated!")
- sleep(1.6)
- opt = "Exit"
- else
- term.clearLine()
- term.write("No Updates Found!")
- sleep(1.6)
- return "menu"
- end
- end if opt == "Exit" then return nil end
- end
- local function main()
- local action, location, duration = "menu", nil, nil
- while action == "menu" do action, location, duration = menu() end
- if action and location then
- clock = os.clock()
- add(recordHeader)
- term.redirect(newTerm)
- term.setTextColor(colors.white)
- term.setBackgroundColor(colors.black)
- term.clear()
- term.setCursorPos(1, 1)
- if action == "record" then
- parallel.waitForAny(function()
- record(location)
- end, function()
- term.setBackgroundColor(colors.black)
- term.setTextColor(colors.white)
- term.clear()
- term.setCursorPos(1, 1)
- --[[
- -- Run startup
- if fs.exists("/startup") and not fs.isDir("/startup") then shell.run("/startup") end
- term.setBackgroundColor(colors.black)
- term.setTextColor(colors.white)
- term.clear()
- term.setCursorPos(1, 1)
- ]]--
- -- Run shell
- shell.run("/rom/programs/shell")
- os.queueEvent(event_exitRecording)
- end)
- if term.isColor() then term.setTextColor(colors.yellow)
- else term.setTextColor(colors.white) end
- term.setBackgroundColor(colors.black)
- term.clear()
- term.setCursorPos(2, 3)
- print("Recording Saved!")
- sleep(1.1)
- elseif action == "tomovie" then
- movie(location, duration)
- end
- else
- return "exit"
- end
- end
- -- Run
- local oldDir = shell.dir()
- while main() ~= "exit" do end
- shell.setDir(oldDir)
- -- Exit Message
- term.setBackgroundColor(colors.black)
- term.setTextColor(colors.white)
- term.clear()
- term.setCursorPos(1, 1)
- centerPrint("Thanks for Using Lightshot " .. version .. "!")
- centerPrint("Made by GravityScore and 1lann")
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement