Advertisement
PaymentOption

Recorder

Jan 23rd, 2013
141
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
Lua 6.39 KB | None | 0 0
  1. local tArgs = { ... } -- Capture arguments.
  2.  
  3. --[[
  4.     Recorder        PaymentOption
  5.                     22 January 2013
  6.                    
  7.     This is a simple implementation of
  8.     screen recording software that seems
  9.     to be so popular now-a-days.
  10. ]]--
  11.  
  12. -- Variables --
  13. local NATIVE_TERM     = {} -- A copy of the native terminal.
  14. local recordingTerm   = {} -- The terminal which will house edited functions for recording.
  15. local recordingTable  = {} -- The table that will record all calls by the terminal.
  16.  
  17. local RECORDING_PATH = nil      -- The path that the user wants to save a new recording to.
  18. local END_RECORDING = "Recording finished." -- The string that is returned by the shell thread when it has exited.
  19. -- Below is the thread which houses the shell which will be used to record the terminal output of the computer.
  20. -- This thread returns once the user has exited the shell by running the 'exit' program on their machine.
  21. local shellThread = coroutine.create(function()
  22.  
  23.     while true do
  24.         local eventData   = { os.pullEvent() }
  25.        
  26.         local hasFinished = coroutine.resume(os.run({["shell"] = shell}, "rom/programs/shell"), unpack(eventData))
  27.        
  28.         -- In the case that this shell is exited because the 'exit' program was run, then we need to mimic the shell
  29.         -- and almost shutdown the computer, except we'll just return from this recording.
  30.         if hasFinished then
  31.             return END_RECORDING
  32.         end
  33.     end
  34.  
  35. end)
  36. -- Variables --
  37.  
  38. -- Terminal Functions --
  39. -- Creates and returns a copy of the current terminal table.
  40. function createTerminalCopy()
  41.  
  42.     local copy = {}
  43.     for itemName, item in pairs(term.native) do
  44.         copy[itemName] = item
  45.     end
  46.    
  47.     return copy
  48.  
  49. end
  50.  
  51. -- Takes a terminal table and recording table and modifies the functions of
  52. -- the terminal table to record the screen.
  53. -- In a recording table, entries are made in the format: t[n] = {functionName = (string), parameters = (variable number of arguemts ( ... ))}
  54. function modifyTerminalForRecording(terminalTable, recordingTable)
  55.  
  56.     -- Returns a modified function that acts as an old terminal function by
  57.     -- adding the call of the function to the recording table and calling the old
  58.     -- function from the terminalTable.
  59.     local function modifyFunction(functionName, recordingTable)
  60.    
  61.         return function ( ... )
  62.            
  63.             recordingTable[#recordingTable + 1] = {functionName = functionName, parameters = { ... }, currentTime = os.clock()}
  64.             return NATIVE_TERM[functionName]( ... )
  65.            
  66.         end
  67.    
  68.     end
  69.  
  70.     for itemName, item in pairs(terminalTable) do
  71.         terminalTable[itemName] = modifyFunction(itemName, recordingTable)
  72.     end
  73.    
  74.     return terminalTable
  75.  
  76. end
  77. -- Terminal Functions --
  78.  
  79. -- File Functions --
  80. -- Writes a recording to a file. Takes a recording table.
  81. function writeRecordingToFile(recordingTable, filePath)
  82.  
  83.     local fileHandle = fs.open(filePath, 'w')    
  84.     print("Saving recording... ")
  85.    
  86.     fileHandle.writeLine(textutils.serialize(recordingTable))
  87.     fileHandle.close()
  88.  
  89. end
  90.  
  91. -- Reads a recording from a file. Returns the recording table.
  92. function readRecordingFromFile(filePath)
  93.  
  94.     local fileHandle     = fs.open(filePath, 'r')
  95.     local recordingTable = textutils.unserialize(fileHandle.readLine())
  96.     fileHandle.close()
  97.    
  98.     return recordingTable
  99.  
  100. end
  101. -- File Functions --
  102.  
  103. -- Playback Functions --
  104. -- Plays back a recording table.
  105. function playRecording(recordingTable)
  106.  
  107.     NATIVE_TERM.clear()
  108.     NATIVE_TERM.setCursorPos(1, 1)
  109.    
  110.     print(#recordingTable)
  111.     -- Sleep the difference between each call, assuming this isn't the first call.
  112.     for itemIndex, item in pairs(recordingTable) do
  113.         -- Make sure that the difference for sleeping is greater than 0.3. If this isn't the case, then don't sleep at all.
  114.         if itemIndex > 1 and item.currentTime - recordingTable[itemIndex - 1].currentTime > 0 then
  115.             sleep(item.currentTime - recordingTable[itemIndex - 1].currentTime)
  116.         end
  117.        
  118.         NATIVE_TERM[item.functionName](unpack(item.parameters))
  119.     end
  120.    
  121.     NATIVE_TERM.clear()
  122.     NATIVE_TERM.setCursorPos(1, 1)
  123.  
  124. end
  125. -- Playback Functions --
  126.  
  127.  
  128.  
  129. -- Initialization --
  130. NATIVE_TERM   = createTerminalCopy()
  131.  
  132. recordingTerm = createTerminalCopy()
  133. recordingTerm = modifyTerminalForRecording(recordingTerm, recordingTable)
  134. -- Initialization --
  135.  
  136.  
  137. -- Handle arguments.
  138. if #tArgs > 0 then
  139.     -- If the user wants to play a recording, then attempt to load it.
  140.     if fs.exists(tArgs[1]) and not fs.isDir(tArgs[1]) then
  141.         playRecording(readRecordingFromFile(tArgs[1]))
  142.         print("End of recording at " .. tArgs[1] .. '.')
  143.         return
  144.    
  145.     -- If the user wants to record a new recording, then do that.
  146.     -- Don't return here.
  147.     elseif tArgs[1] == "record" and not fs.exists(tArgs[2]) then
  148.         RECORDING_PATH = tArgs[2]
  149.         term.clear()
  150.         term.setCursorPos(1, 1)
  151.         print("Run the 'exit' program in the shell to stop recording and save.")
  152.         sleep(1)
  153.     else
  154.         -- If none of the argument setups match, then print the usage.
  155.         print("Usage: " .. shell.getRunningProgram() .. " <recording path>")
  156.         print("       " .. shell.getRunningProgram() .. " record <new recording path>")
  157.         return
  158.     end
  159. else
  160.     -- If none of the argument setups match, then print the usage.
  161.     print("Usage: " .. shell.getRunningProgram() .. " <recording path>")
  162.     print("       " .. shell.getRunningProgram() .. " record <new recording path>")
  163.     return
  164. end
  165. -- Handle arguments.
  166.  
  167.  
  168. -- Main entry point --
  169. -- Redirect terminal output to the modified terminal table.
  170. term.redirect(recordingTerm)
  171. term.clear()
  172. term.setCursorPos(1, 1)
  173.  
  174. -- Queue a couple of events to get the shell going.
  175. os.queueEvent("char", '')
  176. os.queueEvent("char", '')
  177. while coroutine.status(shellThread) ~= "dead" do
  178.     local eventData = { os.pullEvent() }
  179.    
  180.     coroutine.resume(shellThread, unpack(eventData))
  181. end
  182.  
  183. -- Once the thread has died, redirect the terminal output back to the standard terminal
  184. -- and replay the recording.
  185. term.redirect(NATIVE_TERM)
  186. NATIVE_TERM.clear()
  187. NATIVE_TERM.setCursorPos(1, 1)
  188. writeRecordingToFile(recordingTable, RECORDING_PATH)
  189. print("Finished recording. Saved as " .. RECORDING_PATH)
  190.  
  191. -- Main entry point --
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement