new plugin glitch.lua
This commit is contained in:
parent
ed4c6f500b
commit
67b99a8c1c
3
.gitignore
vendored
3
.gitignore
vendored
@ -45,4 +45,5 @@ plugins/dantest.lua
|
||||
plugins/flickr.lua
|
||||
plugins/flickr_search.lua
|
||||
plugins/google_books.lua
|
||||
plugins/safebrowsing.lua
|
||||
plugins/safebrowsing.lua
|
||||
plugins/stats2.lua
|
144
plugins/glitch.lua
Normal file
144
plugins/glitch.lua
Normal file
@ -0,0 +1,144 @@
|
||||
-- JPEG Glitcher v1.1
|
||||
-- Contributed by Francesco <https://github.com/Francesco149>
|
||||
do
|
||||
local KILOBYTE = 1000
|
||||
local MEGABYTE = KILOBYTE * 1000
|
||||
|
||||
function handle_http_response(code, status)
|
||||
if code ~= 200 then
|
||||
if status then
|
||||
print(status)
|
||||
else
|
||||
print("http.request failed! (invalid url?)")
|
||||
end
|
||||
return false
|
||||
end
|
||||
return true
|
||||
end
|
||||
|
||||
function get_jpg_header_size(data)
|
||||
local res = 417
|
||||
for i, byte in ipairs(data) do
|
||||
if byte == 255 and data[i + 1] == 218 then
|
||||
res = i + 2
|
||||
break
|
||||
end
|
||||
end
|
||||
return res
|
||||
end
|
||||
|
||||
function simple_file_size(bytes)
|
||||
local simplesize = bytes
|
||||
local unit = "B"
|
||||
if bytes >= MEGABYTE then
|
||||
simplesize = simplesize / MEGABYTE
|
||||
unit = "MB"
|
||||
elseif bytes >= KILOBYTE then
|
||||
simplesize = simplesize / KILOBYTE
|
||||
unit = "KB"
|
||||
end
|
||||
return simplesize, unit
|
||||
end
|
||||
|
||||
local GLITCH_MAX_FILE = MEGABYTE
|
||||
|
||||
function run(msg, matches)
|
||||
http = require("socket.http")
|
||||
local stamp = os.time()
|
||||
|
||||
-- try checking file size from a HEAD request
|
||||
local default_timeout = http.TIMEOUT
|
||||
http.TIMEOUT = 5
|
||||
local _, code, headers, status = http.request {
|
||||
url = matches[1],
|
||||
method = "HEAD"
|
||||
}
|
||||
if not handle_http_response(code, status) then
|
||||
return "HTTP request failed or file not found"
|
||||
end
|
||||
|
||||
if not string.find(headers["content-type"], "jpeg") then
|
||||
-- TODO: convert to jpg?
|
||||
return "Not a JPEG file!"
|
||||
end
|
||||
|
||||
local filesize = tonumber(headers["content-length"])
|
||||
local response = nil
|
||||
|
||||
-- if the HEAD request doesn't contain content-length,
|
||||
-- send a full GET request. the timeout will abort the request
|
||||
-- after 5 seconds if the file is too large or takes too long
|
||||
-- to download
|
||||
if not filesize then
|
||||
print("No content-length, performing a full request...")
|
||||
response = http.request(matches[1])
|
||||
filesize = #response
|
||||
end
|
||||
|
||||
-- show user-friendly filesize
|
||||
simplesize, unit = simple_file_size(filesize)
|
||||
print("File Size: " .. simplesize .. unit .. " (" .. filesize .. " bytes)")
|
||||
|
||||
-- check filesize limit
|
||||
if filesize > GLITCH_MAX_FILE then
|
||||
return "Sorry, maximum filesize is " .. GLITCH_MAX_FILE / MEGABYTE .. "MB!"
|
||||
end
|
||||
|
||||
-- if we previously got the file size through a HEAD request,
|
||||
-- retrieve the actual data with a full request
|
||||
if not response then
|
||||
response, code, _, status = http.request(matches[1])
|
||||
if not handle_http_response(code, status) then
|
||||
return "HTTP request failed or file not found"
|
||||
end
|
||||
end
|
||||
|
||||
-- convert to byte array for manipulation
|
||||
local arr = {}
|
||||
response:gsub(".", function(c) table.insert(arr, string.byte(c)) end)
|
||||
response = nil
|
||||
|
||||
-- skip jpeg header
|
||||
local header_size = get_jpg_header_size(arr)
|
||||
print("JPEG header size: " .. header_size .. " bytes")
|
||||
|
||||
-- corrupt a set amount of bytes
|
||||
local data_end = #arr - 4
|
||||
local corrupt_count = matches[2]
|
||||
if not corrupt_count then
|
||||
corrupt_count = 20
|
||||
end
|
||||
for i=1, corrupt_count do
|
||||
local index = math.random(header_size, data_end)
|
||||
print("Corrupting byte " .. index)
|
||||
arr[index] = math.floor(math.random() * 255)
|
||||
end
|
||||
|
||||
-- write glitched jpg
|
||||
print("Writing glitched.jpg")
|
||||
local out = assert(io.open("tmp/"..stamp..".jpg", "wb"))
|
||||
local glitched = ""
|
||||
for i=1, #arr do
|
||||
out:write(string.char(arr[i]))
|
||||
end
|
||||
arr = nil
|
||||
assert(out:close())
|
||||
|
||||
-- send glitched jpg
|
||||
local receiver = get_receiver(msg)
|
||||
send_photo(receiver, "tmp/"..stamp..".jpg", function() end, function() end)
|
||||
|
||||
http.TIMEOUT = default_timeout
|
||||
end
|
||||
|
||||
return {
|
||||
description = "Randomly glitches a JPEG image",
|
||||
usage = "!glitch [url] [amount]: glitches the JPEG image retrieved from _url_ " ..
|
||||
"by corrupting _amount_ bytes. Amount is optional and defaults to 20 bytes.",
|
||||
patterns = {
|
||||
"^/glitch ([^ ]*) ([0-9]*)$",
|
||||
"^/glitch ([^ ]*)$"
|
||||
},
|
||||
run = run
|
||||
}
|
||||
end
|
Reference in New Issue
Block a user