-- Mtape -- tape managing program -- made by LDDestroier local _DEBUG = false local function checkOption(argName, argInfo, isShort) for i = 1, #argInfo do if argInfo[i][isShort and 2 or 3] == argName then return i end end return false end local function argParse(argInput, argInfo) local sDelim = "-" local lDelim = "--" local optOutput = {} local argOutput = {} local argError = {} local usedTokens = {} local lOpt, sOpt, optNum for i = 1, #argInfo do optOutput[i] = {} end for i = 1, #argInput do lOpt = argInput[i] -- check type of delimiter if lOpt:sub(1, #lDelim) == lDelim then -- handle long delimiter lOpt = lOpt:sub(#lDelim + 1) optNum = checkOption(lOpt, argInfo, false) if optNum then if argInfo[optNum][1] == 0 then optOutput[optNum] = true else optOutput[optNum] = {} for ii = 1, argInfo[optNum][1] do if argInput[i + ii] then optOutput[optNum][#optOutput[optNum] + 1] = argInput[i + ii] usedTokens[i + ii] = true else argError[#argError + 1] = "expected parameter " .. tostring(ii) .. " for argument " .. lDelim .. lOpt break end end i = i + argInfo[optNum][1] end else argError[#argError + 1] = "invalid argument " .. lDelim .. lOpt end elseif lOpt:sub(1, #sDelim) == sDelim then -- handle short delimiter lOpt = lOpt:sub(#sDelim + 1) for si = 1, #lOpt do sOpt = lOpt:sub(si, si) optNum = checkOption(sOpt, argInfo, true) if optNum then if argInfo[optNum][1] == 0 then optOutput[optNum] = true elseif si == #lOpt then optOutput[optNum] = {} for ii = 1, argInfo[optNum][1] do if argInput[i + ii] then optOutput[optNum][#optOutput[optNum] + 1] = argInput[i + ii] usedTokens[i + ii] = true else argError[#argError + 1] = "expected parameter " .. tostring(ii) .. " for argument " .. sDelim .. sOpt break end end i = i + argInfo[optNum][1] else argError[#argError + 1] = "options with parameters must be at the end of their group" break end else argError[#argError + 1] = "invalid argument " .. sDelim .. sOpt break end end elseif not usedTokens[i] then argOutput[#argOutput + 1] = lOpt end end return argOutput, optOutput, argError end local function getHelp(specify) if not specify then print("mtape [file / url] (label)") print("mtape [-i --info]") print("mtape [-e --erase]") print("mtape [-u --unclean]") print("mtape [-c --cc-media]") print("mtape [-u]") print("Use -h with other options for details") else if specify == "--info" then print("Prints information about the connected tape drive.") print("This includes the label, size, minutes length, and current seeking position.") elseif specify == "--erase" then print("Erases the connected tape drive.") elseif specify == "--unclean" then print("Normally, tapes are erased before writing them anew. Use this option to not erase them first.") print("If the tape has something longer written to it beforehand, you'll hear it after whatever is written now.") elseif specify == "--ldd-github" then print("Adds URL info from LDDestroier's personal CC-Media github to make it easier to pull from there.") print("Ex. 'tapey -c krabii'") print(" 'tapey -c simple'") elseif specify == "--reinstall" then print("Updates Mtape to the latest version on the LDDestroier/CC github.") end end end local tierInfo = { -- damage value indicates type of tape -- value of tierInfo indicates minutes of storage [0] = 4, [1] = 8, [2] = 16, [3] = 32, [4] = 64, [5] = 2, [6] = 6, [8] = 128 } local function getFileContents(path, isURL) local file, contents if isURL then file = http.get(path, nil, true) else file = fs.open(fs.combine(shell.dir(), path), "rb") end if not file then return false, "" else contents = file.readAll() file.close() return true, contents end end local function getTapeDrive(side) local tape if side then tape = peripheral.wrap(side) if not tape then return false, "No such tape drive found.", 0 elseif peripheral.getType(tape) ~= "tape_drive" then return false, "Not a tape drive.", 0 else return true, tape, tape.getSize() end else tape = peripheral.find("tape_drive") if not tape then return false, "Tape drive not connected.", 0 else return true, tape, tape.getSize() end end end local function writeToTape(tape, contents, tapeName) local output = "" if not tape then error("expected tape peripheral") end if not contents then error("expected contents") end local totalTapeSize = tape.getSize() if tapeName then tape.setLabel(tapeName) end tape.stop() tape.seek(-tape.getPosition()) if #contents > totalTapeSize then output = "Tape too small, audio truncated." for i = 0, 8 do if tierInfo[i] then if tierInfo[i] * 360000 >= #contents then output = output .. "\nIt would fit on a" .. (tierInfo[i] == 8 and "n " or " ") .. tostring(tierInfo[i]) .. " minute tape." break end end end contents = contents:sub(1, totalTapeSize) end tape.write(contents) tape.seek(-tape.getPosition()) tape.stop() return output end local function infoMode(tape) local scr_x, scr_y = term.getSize() print("Info for tape drive:") print(("-"):rep(scr_x)) local gi = tape.getItem(1).getMetadata() local info = { inserted = gi ~= nil } local minute = 360000 if not info.inserted then print("No tape inserted.") else info.displayname = gi.displayName info.label = gi.media.label info.itemname = gi.name info.damage = gi.damage info.minutes = tierInfo[info.damage] info.maxsize = tape.getSize() info.position = tape.getPosition() print(info.displayname .. " inserted.") print("Label: \"" .. info.label .. "\"") write("Stores " .. tostring(info.minutes) .. " minutes") print(" (" .. tostring(info.maxsize) .. " bytes)") print("Seeked to " .. tostring(info.position) .. "/" .. tostring(info.maxsize)) end return info end local argInfo = { [1] = {0, "h", "help"}, [2] = {0, "i", "info"}, [3] = {1, "d", "drive"}, [4] = {0, "e", "erase"}, [5] = {0, "u", "unclean"}, [6] = {1, "c", "cc-media"}, [7] = {0, "r", "reinstall"} } local arguments, options, errors = argParse({...}, argInfo) local tape, totalTapeSize, success, contents if #errors > 0 then for i = 1, #errors do printError(errors[i]) end return end local fileName = arguments[1] local tapeName = arguments[2] local tapeDriveName = options[3][1] local wantedHelp = options[1] == true local wantedInfo = options[2] == true local wantedErase = options[4] == true local doUnclean = options[5] == true local getFromGithub = options[6][1] local wantedUpdate = options[7] == true if wantedHelp then if wantedInfo then getHelp("--info") elseif wantedErase then getHelp("--erase") elseif doUnclean then getHelp("--unclean") elseif getFromGithub then getHelp("--ldd-github") elseif wantedUpdate then getHelp("--reinstall") else getHelp() end return end if wantedUpdate then print("Redownloading Mtape...") local cpath = shell.getRunningProgram() local file = http.get("https://github.com/LDDestroier/CC/raw/master/mtape.lua") local contents local sizeBefore = fs.getSize(cpath) local sizeAfter = 0 if file then contents = file.readAll() sizeAfter = #contents file.close() file = fs.open(cpath, "w") file.write(contents) file.close() print("Done! (diff: " .. tostring(sizeAfter - sizeBefore) .. " bytes)") return else print("Couldn't update.") return end end -- Try to wrap specified tape drive OR find tape drive success, tape, totalTapeSize = getTapeDrive(tapeDriveName) if not success then print(tape) return end if wantedInfo then infoMode(tape) return true end if wantedErase then success = writeToTape(tape, string.char(0):rep(tape.getSize()), tapeName) print("Tape erased.") return end if getFromGithub then print("Pulling from CC-Media.") tapeName = arguments[1] fileName = "https://github.com/LDDestroier/CC-Media/raw/master/DFPWM/" .. getFromGithub .. ".dfpwm" end if not fileName then getHelp() return end -- Make file, and detect URL if fileName:sub(1,8) == "https://" then write("Downloading...") success, contents = getFileContents(fileName, true) print("Done.") else if not fs.exists(fileName) then fileName = fileName .. ".dfpwm" end success, contents = getFileContents(fileName, false) end if not success then error("Could not get file. Abort.") else if _DEBUG then print("File size: " .. tostring(#contents) .. " bytes") print("Tape size: " .. tostring(tape.getSize()) .. " bytes") end end -- Adds null data to the end of the file if you want a clean tape write if doUnclean then print("Won't clean up tape first.") else contents = contents .. string.char(0):rep(math.max(0, totalTapeSize - #contents)) end write("Writing...") success = writeToTape(tape, contents, tapeName) if success then print("\n" .. success) print("Nonetheless, it is written.") else print("done!") end return true