IS2511

catbox.lua

Jul 19th, 2020 (edited)
136
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
  1. --[[
  2.   Catbox https://gist.github.com/IS2511/e4c6a6f638609fcfa733ceeb432cfced
  3.   An implementation of CatBox.moe API in Lua
  4.   Pastebin: https://pastebin.com/kuGkdm53
  5.   Author: IS2511
  6.  
  7.   parg library
  8.   https://gist.github.com/IS2511/96847fe185278b457505218b1c141f9d
  9.  
  10.   Special thanks to fingercomp
  11. ]]--
  12.  
  13. -- Libs, components
  14. local shell = require("shell")
  15. local fs = require("filesystem")
  16. local io = require("io")
  17. local print = print -- Bring print() to local so redef not global
  18. local os = require("os")
  19. local comp = require("computer")
  20.  
  21. if not require("component").isAvailable("internet") then error("No internet card found!") end
  22. local compRequest = require("component").internet.request
  23.  
  24. local CONFIG_FILE = fs.concat(os.getenv("HOME"), ".catbox")
  25. local HOST = "https://catbox.moe/user/api.php"
  26.  
  27.  
  28. local ok, parg = pcall(require, "parg")
  29. if not ok then
  30.   print("Library \"parg\" not found!")
  31.   print("Installing...")
  32.   if not fs.isDirectory("/usr/lib") then fs.makeDirectory("/usr/lib") end
  33.   shell.execute("pastebin get nSgXWHtp /usr/lib/parg.lua")
  34.   print("Done installing!")
  35. end
  36. local parg = require("parg")
  37.  
  38. -- Command-line arguments
  39. local anon, requestTimeout, yesToAll
  40.  
  41. parg.register({"help", "h"}, "flag")
  42.  
  43. parg.register({"anonymous", "a"}, "flag",
  44.   function (count) anon = (count > 0) or (not fs.exists(CONFIG_FILE)) end)
  45.  
  46. parg.register({"timeout", "t"}, "value",
  47.   function (value) requestTimeout = tonumber(value) or 10 end)
  48.  
  49. parg.register({"yes", "y"}, "flag",
  50.   function (count) yesToAll = (count > 0) end)
  51.  
  52. parg.register({"quite", "q"}, "flag",
  53.   function (count)
  54.     if count > 0 then
  55.       print = function (...) end
  56.     end
  57.   end)
  58.  
  59. local args = parg( {...} )
  60.  
  61. if args.quite > 0 then yesToAll = true end
  62.  
  63.  
  64. -- Helper functions
  65. local Multipart = {}
  66.  
  67. function Multipart.generateBorder(str)
  68.   local border = tostring({}):sub(14) -- 10?
  69.   local longestOccurence = nil
  70.   for match in str:gmatch("%-*"..border) do
  71.     if (not longestOccurence) or (#match > #longestOccurence) then
  72.       longestOccurence = match
  73.     end
  74.   end
  75.   return longestOccurence and ("-" .. longestOccurence) or border
  76. end
  77.  
  78. function Multipart:formData()
  79.   local border = ""
  80.   for i, v in ipairs(self.data) do
  81.     border = border..Multipart.generateBorder(v.value)
  82.   end
  83.  
  84.   local data = ""
  85.   for i, v in ipairs(self.data) do
  86.     local params = ""
  87.     if v.params then
  88.       for k, vv in pairs(v.params) do
  89.         params = params.."; "..k.."=\""..vv.."\""
  90.       end
  91.     end
  92.     data = data..([[--%s
  93. Content-Disposition: form-data; name="%s"%s
  94.  
  95. %s
  96. ]]):format(border, v.name, params, v.value)
  97.   end
  98.   data = data.."--"..border.."--"
  99.   -- data:gsub("\n", "\r\n") -- Nope
  100.  
  101.   return data, ("multipart/form-data; boundary="..border) -- data, Content-Type
  102. end
  103.  
  104. function Multipart.new()
  105.   return {
  106.     formData = Multipart.formData,
  107.     data = {}
  108.   }
  109. end
  110.  
  111.  
  112. local function urlEncode(str)
  113.    if str then
  114.       str = str:gsub("\n", "\r\n")
  115.       str = str:gsub("([^%w %-%_%.%~])", function(c)
  116.          return ("%%%02X"):format(string.byte(c))
  117.       end)
  118.       str = str:gsub(" ", "+")
  119.    end
  120.    return str
  121. end
  122.  
  123. local function dataUrlEncode(t)
  124.   local data = ""
  125.   for k, v in pairs(t) do
  126.     data = data..k.."="..urlEncode(v).."&"
  127.   end
  128.   data = data:sub(1, #data-1)
  129.   return data
  130. end
  131.  
  132.  
  133. local function request(url, body, headers, method, timeout)
  134.  
  135.   local handle, err = compRequest(url, body, headers, method)
  136.   if not handle then
  137.     return nil, ("request failed: %s"):format(err or "unknown error")
  138.   end
  139.  
  140.   local start = comp.uptime()
  141.   while true do
  142.     local status, err = handle.finishConnect()
  143.     if status then break end
  144.     if status == nil then
  145.       return nil, ("request failed: %s"):format(err or "unknown error")
  146.     end
  147.  
  148.     if comp.uptime() >= start + timeout then
  149.       handle.close()
  150.       return nil, "request failed: connection timed out"
  151.     end
  152.  
  153.     os.sleep(0.05)
  154.   end
  155.  
  156.   return handle
  157. end
  158.  
  159.  
  160. -- Main functions
  161. local function catboxRequest (reqtype, arg, data)
  162.   local handle, err
  163.   if reqtype == "fileupload" then
  164.     handle, err = request(HOST, data.data, {["Content-Type"] = data.contentType}, "POST", requestTimeout)
  165.   else
  166.     handle, err = request(HOST, dataUrlEncode(data), {["Content-Type"] = "application/x-www-form-urlencoded; charset=UTF-8"}, "POST", requestTimeout)
  167.   end
  168.   data = nil form = nil contentType = nil -- Clearing memory
  169.   for i=1, 10 do os.sleep(0) end -- Collect garbadge
  170.   if handle == nil then
  171.     print("Request error \""..arg.."\": "..tostring(err))
  172.   else
  173.     local result = ""
  174.     while true do
  175.       local chunk, err = handle.read()
  176.       if not chunk then break end
  177.       result = result..chunk
  178.     end
  179.     if handle.response() == 200 then -- Response code == 200 OK
  180.       if (result:sub(1, 25) == "https://files.catbox.moe/") or (result:sub(1, 19) == "https://catbox.moe/") then
  181.         if result:sub(1, 21) == "https://catbox.moe/c/" then -- "createalbum" ?
  182.           print("Album short: "..result:sub(22))
  183.         end
  184.         print("Link: "..result)
  185.       else
  186.         print("Success! "..result)
  187.       end
  188.     else
  189.       print("Catbox error \""..arg.."\": "..result)
  190.     end
  191.   end
  192. end
  193.  
  194. local function usage (album)
  195.   if album then
  196.     print([[
  197.     Usage: catbox album <command> [arguments]
  198.     Every command here needs userhash so be sure you have set it up!
  199.     Every title or discription must be written in "" if you want to write more than one word!
  200.     Commands:
  201.        create <title> <description> <file(s)>       - Create album
  202.        edit <short> <title> <description> [file(s)] - Edit album
  203.        add <short> <file(s)>                        - Add files to album
  204.        remove <short> <file(s)>                     - Remove files from album
  205.        delete <short>                               - Delete album]])
  206.   else
  207.     print([[
  208. Usage: catbox <command> [arguments]
  209. Commands:
  210.     user [userhash]       - Get or set current userhash.
  211.                             Pass 'off' to forget set userhash
  212.     file <filename(s)>    - Upload files to catbox.moe
  213.     url <url(s)>          - Upload files from URLs to catbox.moe
  214.     delete <filenames(s)> - Delete files from catbox.moe. Requires userhash
  215.     album                 - Album Managment ('catbox album' for help)
  216.     -a, --anonymous       - Ignore userhash, upload anonymously
  217.     -h, --help            - Print this message
  218.     -y, --yes             - Yes to everything, skip all checks
  219.     -q, --quite           - Suppress all output (except sys err) and --yes]])
  220.   end
  221. end
  222.  
  223. local function Hash (hash)
  224.   if hash then
  225.     local file, err = io.open(CONFIG_FILE, "w")
  226.     if not file then error(err) end
  227.     file:write(hash)
  228.     file:close()
  229.     hash = true
  230.   else
  231.     if anon or (not fs.exists(CONFIG_FILE)) then
  232.       return nil
  233.     end
  234.     local file, err = io.open(CONFIG_FILE, "r")
  235.     if not file then error(err) end
  236.     hash = file:read("*l")
  237.   end
  238.  
  239.   return hash
  240. end
  241.  
  242.  
  243.  
  244. -- Program start
  245. if #args == 0 or (args.help > 0) then
  246.   usage(args[1] == "album")
  247.   return
  248. elseif args[1] == "user" then -- NOTE: user
  249.   if not args[2] then
  250.     if fs.exists(CONFIG_FILE) then
  251.       print("Your current userhash is: "..Hash())
  252.     else
  253.       print("No userhash is currently set, so you are anonymous")
  254.     end
  255.   else
  256.     if args[2] ~= "off" then
  257.       Hash(args[2])
  258.       print("Userhash "..args[2].." set in "..CONFIG_FILE)
  259.     else
  260.       fs.remove(CONFIG_FILE)
  261.       print("You are now Anonymous!")
  262.     end
  263.   end
  264. elseif args[1] == "file" then -- NOTE: file
  265.   if #args == 1 then
  266.     print("Usage: catbox file <filename> [<filename>...] - Uploads files to CatBox.moe")
  267.     return
  268.   end
  269.   if anon then
  270.     print("Uploading anonymously...")
  271.   else
  272.     print("Uploading with userhash...")
  273.   end
  274.   for i=2, #args do
  275.     local path = fs.concat(fs.path(args[0]), args[i])
  276.     if fs.exists(path) and (not fs.isDirectory(path)) then
  277.       local form = Multipart.new()
  278.       table.insert(form.data, {name = "reqtype", value = "fileupload"})
  279.       if not anon then table.insert(form.data, {name = "userhash", value = Hash()}) end
  280.       table.insert(form.data, {
  281.         name = "fileToUpload",
  282.         params = { filename = fs.name(path) },
  283.         value = io.open(path):read("*a") })
  284.       local data, contentType = form:formData()
  285.       -- print("DEBUG:") print(data) print(contentType)
  286.       catboxRequest("fileupload", path, {data = data, contentType = contentType})
  287.     else
  288.       print("File "..path.." does not exist or is a directory!")
  289.     end
  290.   end
  291.   print("Done!")
  292.  
  293. elseif args[1] == "url" then -- NOTE: url
  294.   if #args == 1 then
  295.     print("Usage: catbox url <url> [<url>...] - Uploads files from urls to CatBox.moe")
  296.     return
  297.   end
  298.   if anon then
  299.     print("Uploading anonymously...")
  300.   else
  301.     print("Uploading with userhash...")
  302.   end
  303.   for i=2, #args do
  304.     local data = {
  305.       reqtype = "urlupload",
  306.       userhash = Hash(), -- If anon Hash():nil
  307.       url = args[i]
  308.     }
  309.     catboxRequest("urlupload", args[i], data)
  310.   end
  311.   print("Done!")
  312.  
  313. elseif args[1] == "delete" then -- NOTE: delete
  314.   if #args == 1 then
  315.     print("Usage: catbox delete <filename> [<filename>...] - Deletes files from your CatBox.moe account")
  316.     return
  317.   end
  318.   if anon then
  319.     print("Can't delete files! No userhash!")
  320.     return
  321.   end
  322.   print("Deleting files...")
  323.   for i=2, #args do
  324.     local data = {
  325.       reqtype = "deletefiles",
  326.       userhash = Hash(),
  327.       files = args[i] -- Deleting 1 file at a time
  328.     }
  329.     catboxRequest("deletefiles", args[i], data)
  330.   end
  331.   print("Done!")
  332.  
  333. elseif args[1] == "album" then -- NOTE: album
  334.   if #args == 1 then
  335.     usage(true)
  336.     return
  337.   end
  338.   if args[2] == "create" then
  339.     if #args < 5 then
  340.       print("Usage: catbox album create <title> <description> <filename> [<filename> ...] - Careates an album with given title, discription and files")
  341.       return
  342.     end
  343.     if anon then
  344.       print("Anonymous albums are permanently disabled in this program.")
  345.       print("I don't think they are needed anyway. Use userhash for albums.")
  346.       return
  347.     end
  348.     local title, desc, files = args[3], args[4], ""
  349.     for i=5, #args do
  350.       files = files..args[i]..((i ~= #args) and " " or "")
  351.     end
  352.     print("Creating Album...")
  353.     print("Title: "..title)
  354.     print("Description: "..desc)
  355.     print("Files: "..files)
  356.     print()
  357.  
  358.     if not yesToAll then
  359.       io.write("Are you sure? [y/N] ")
  360.       local answer = io.read() -- "*line" (default)
  361.       if (string.lower(answer) == "no") or (string.lower(answer) == "n") or (answer == "") then
  362.         print("Aborting.")
  363.         return
  364.       end
  365.     end
  366.  
  367.     local data = {
  368.       reqtype = "createalbum",
  369.       userhash = Hash(),
  370.       title = title,
  371.       desc = desc,
  372.       files = files
  373.     }
  374.     catboxRequest("createalbum", title, data)
  375.     print("Done!")
  376.  
  377.   elseif args[2] == "edit" then
  378.     if #args < 5 then
  379.       print("Usage: catbox album edit <short> <title> <description> [<filename> ...] - Edites album")
  380.       print("Filenames are optional, BUT if none are specified the album WILL BE EMPTY!")
  381.       return
  382.     end
  383.     if anon then
  384.       print("Can't edit albums! No userhash!")
  385.       return
  386.     end
  387.     local short, title, desc, files = args[3], args[4], args[5], ""
  388.     for i=6, #args do
  389.       files = files..args[i]..((i ~= #args) and " " or "")
  390.     end
  391.     print("Editing Album...")
  392.     print("Short: "..short)
  393.     print("Title: "..title)
  394.     print("Description: "..desc)
  395.     print("Files: "..files)
  396.     print("Filenames are optional, BUT if none are specified the album WILL BE EMPTY!")
  397.     print()
  398.  
  399.     if not yesToAll then
  400.       io.write("Are you sure? [y/N] ")
  401.       local answer = io.read() -- "*line" (default)
  402.       if (string.lower(answer) == "no") or (string.lower(answer) == "n") or (answer == "") then
  403.         print("Aborting.")
  404.         return
  405.       end
  406.     end
  407.  
  408.     local data = {
  409.       reqtype = "editalbum",
  410.       userhash = Hash(),
  411.       short = short,
  412.       title = title,
  413.       desc = desc,
  414.       files = files
  415.     }
  416.     catboxRequest("editalbum", short, data)
  417.     print("Done!")
  418.  
  419.   elseif args[2] == "add" then
  420.     if #args < 4 then
  421.       print("Usage: catbox album add <short> <filename> [<filename> ...] - Adds files to the specific album")
  422.       return
  423.     end
  424.     if anon then
  425.       print("Can't add files to albums! No userhash!")
  426.       return
  427.     end
  428.     local short, files = args[3], ""
  429.     for i=4, #args do
  430.       files = files..args[i]..((i ~= #args) and " " or "")
  431.     end
  432.     print("Adding files to Album...")
  433.     print("Short: "..short)
  434.     print("Files: "..files)
  435.     print()
  436.  
  437.     local data = {
  438.       reqtype = "addtoalbum",
  439.       userhash = Hash(),
  440.       short = short,
  441.       files = files
  442.     }
  443.     catboxRequest("addtoalbum", short, data)
  444.     print("Done!")
  445.  
  446.   elseif args[2] == "remove" then
  447.     if #args < 4 then
  448.       print("Usage: catbox album remove <short> <filename> [<filename> ...] - Removes files from the specific album")
  449.       return
  450.     end
  451.     if anon then
  452.       print("Can't remove files from albums! No userhash!")
  453.       return
  454.     end
  455.     local short, files = args[3], ""
  456.     for i=4, #args do
  457.       files = files..args[i]..((i ~= #args) and " " or "")
  458.     end
  459.     print("Removing files from Album...")
  460.     print("Short: "..short)
  461.     print("Files: "..files)
  462.     print()
  463.  
  464.     local data = {
  465.       reqtype = "removefromalbum",
  466.       userhash = Hash(),
  467.       short = short,
  468.       files = files
  469.     }
  470.     catboxRequest("removefromalbum", short, data)
  471.     print("Done!")
  472.  
  473.   elseif args[2] == "delete" then
  474.     if #args < 3 then
  475.       print("Usage: catbox album delete <short> [<short> ...] - Deletes album")
  476.       return
  477.     end
  478.     if anon then
  479.       print("Can't delete albums! No userhash!")
  480.       return
  481.     end
  482.     local short = args[3]
  483.     print("Deleting Album...")
  484.     print("Short: "..short)
  485.     print()
  486.  
  487.     if not yesToAll then
  488.       io.write("Are you sure? [y/N] ")
  489.       local answer = io.read() -- "*line" (default)
  490.       if (string.lower(answer) == "no") or (string.lower(answer) == "n") or (answer == "") then
  491.         print("Aborting.")
  492.         return
  493.       end
  494.     end
  495.  
  496.     local data = {
  497.       reqtype = "deletealbum",
  498.       userhash = Hash(),
  499.       short = short
  500.     }
  501.     catboxRequest("deletealbum", short, data)
  502.     print("Done!")
  503.  
  504.   else
  505.     usage(true)
  506.   end
  507.  
  508. else
  509.   usage()
  510. end
RAW Paste Data