diff --git a/examples/discordCC.lua b/examples/discordCC.lua new file mode 100644 index 0000000..bd9337c --- /dev/null +++ b/examples/discordCC.lua @@ -0,0 +1,290 @@ +local bot_id = "" -- put the bot id between the ""! +local servers = { -- setup the server/channels here, look at the example. + [""] = { + "", + }, + + --[[ Example: + ["SERVER_ID"] = { + "CHANNEL_ID", + "CHANNEL_ID", + "CHANNEL_ID", + }, + ["SERVER_ID"] = { + "CHANNEL_ID", + "CHANNEL_ID", + "CHANNEL_ID", + }, + ]] +} + +if(bot_id=="")then + error("Please setup the bot id and servers/channels first!") +end + +local filePath = "basalt" +if not(fs.exists(filePath))then + shell.run("pastebin run ESs1mg7P packed true "..filePath) +end +local basalt = require(filePath) -- UI Library + +local main = basalt.createFrame():setBackground(colors.lightGray) +local loginFrame = main:addFrame():setBackground(colors.lightGray) +local messageFrameList = main:addFrame():setPosition("parent.w+1", 1):setBackground(colors.black):setScrollable(true):setImportantScroll(true) + +local refreshRate = 2 +local messageFrames = {} +local availableGuilds = {} + +local channel_id = "" +for k,v in pairs(servers)do + if(v[1]~=nil)then + channel_id = v[1] + end + break +end + +local function getAllGuilds(bot) + local content = http.get("https://discord.com/api/users/@me/guilds", {["Content-Type"] = "application/json", ["Authorization"] = "Bot "..bot}) + if(content~=nil)then + return textutils.unserializeJSON(content.readAll()) + end +end + +local function getAllChannels(bot, guild) + local content = http.get("https://discord.com/api/guilds/"..guild.."/channels", {["Content-Type"] = "application/json", ["Authorization"] = "Bot "..bot}) + if(content~=nil)then + local t = {} + for k,v in pairs(textutils.unserializeJSON(content.readAll()))do + table.insert(t, v.position, v) + end + return t + end +end + +local splitString = function(str, sep) + if sep == nil then + sep = "%s" + end + local t={} + for v in string.gmatch(str, "([^"..sep.."]+)") do + table.insert(t, v) + end + if(#t==0)then table.insert(t,str) end + return t +end + +local function createText(str, width) + local uniqueLines = splitString(str, "\n") + local lines = {} + for k,v in pairs(uniqueLines)do + local line = "" + local words = splitString(v, " ") + for a,b in pairs(words)do + if(#line+#b <= width)then + line = line=="" and b or line.." "..b + if(a==#words)then table.insert(lines, line) end + else + table.insert(lines, line) + line = b:sub(1,width) + if(a==#words)then table.insert(lines, line) end + end + end + end + return lines +end + +local maxOffset = 0 +local autoOffset = true +local function newMessage(position, msg, username, sendTime) + local lines = createText(msg, messageFrameList:getWidth()-5) + if(messageFrames[position]==nil)then + if(messageFrames[position-1]~=nil)then + messageFrames[position] = messageFrameList:addFrame("message"..tostring(position)):setPosition(2, "message"..(position-1)..".y + message"..(position-1)..".h") + else + messageFrames[position] = messageFrameList:addFrame("message"..tostring(position)):setPosition(2, 1) + end + messageFrames[position]:addLabel("title") + messageFrames[position]:addLabel("body") + end + maxOffset = maxOffset + #lines+3 + if(autoOffset)then + messageFrameList:setOffset(0, maxOffset - messageFrameList:getHeight()+1) + end + messageFrames[position]:setSize("parent.w-1", #lines+3):setBackground(colors.black) + messageFrames[position]:getObject("title"):setSize("parent.w-2", 1):setPosition(2,1):setText(username):setForeground(colors.lightGray):setBackground(colors.gray) + messageFrames[position]:getObject("body"):setSize("parent.w-2", #lines+1):setPosition(2,3):setText(msg):setForeground(colors.lightGray) +end + +local function updateDiscordMessages(channel, bot) + if(channel~=nil)and(bot~=nil)then + currentMessages = {} + local content = http.get("https://discord.com/api/channels/"..channel.."/messages?limit=25", {["Content-Type"] = "application/json", ["Authorization"] = "Bot "..bot}) + if(content~=nil)then + local t = textutils.unserializeJSON(content.readAll()) + local tR = {} + for i=#t, 1, -1 do + tR[#tR+1] = t[i] + end + for k,v in pairs(tR)do + newMessage(k, v.content, v.author.username, v.time) + end + end + end +end + +local animations = {} + +local function offsetAnimation(obj, x, y, t) + if(animations[obj:getName()]~=nil)then animations[obj:getName()]:cancel() end + animations[obj:getName()] = main:addAnimation():setAutoDestroy(true):setObject(obj):offset(x, y, t or 1):play() +end + +local function positionAnimation(obj, x, y, t) + if(animations[obj:getName()]~=nil)then animations[obj:getName()]:cancel() end + animations[obj:getName()] = main:addAnimation():setAutoDestroy(true):setObject(obj):move(x, y, t or 1):play() +end + +local sideBar = messageFrameList:addFrame():setPosition(-18, 1):setSize(20, "parent.h"):setZIndex(17):ignoreOffset():setScrollable(true):setImportantScroll(true) +sideBar:addButton():setText("Back"):setForeground(colors.lightGray):setBackground(colors.black):setPosition(3,2):setSize("parent.w - 4", 3):onClick(function() + offsetAnimation(main, 0, 0) + positionAnimation(sideBar, -18, 1) +end) +sideBar:addLabel():setText("Channels:"):setForeground(colors.black):setPosition(2,6) +sideBar:onClick(function(self, event) + if(event=="mouse_click")then + positionAnimation(self, 1, 1) + messageFrameList:setImportantScroll(false) + end +end) +sideBar:onLoseFocus(function() + positionAnimation(sideBar, -18, 1) + messageFrameList:setImportantScroll(true) +end) + + +local newTextFrame = messageFrameList:addFrame():setSize("parent.w - 4", 10):setPosition(3, 1):setZIndex(16):ignoreOffset():setBackground(colors.gray):setAnchor("bottomLeft") +local msgInfo = newTextFrame:addLabel():setText("Click here to write a message") + +local messageField = newTextFrame:addTextfield():setSize("parent.w-2", "parent.h-4"):setPosition(2,3):setBackground(colors.lightGray) +newTextFrame:onClick(function(self, event) + if(event=="mouse_click")then + positionAnimation(self, 3, -8, 0.5) + messageFrameList:setImportantScroll(false) + msgInfo:setText("New Message:") + end +end) + +messageFrameList:onScroll(function() + local xO, yO = messageFrameList:getOffset() + messageFrameList:getMaxScroll() + if(yO==messageFrameList:getMaxScroll())then + autoOffset = true + else + autoOffset = false + end +end) + +local function messageBoxLoseFocus() + positionAnimation(newTextFrame, 3, 1, 0.5) + messageFrameList:setImportantScroll(true) + msgInfo:setText("Click here to write a message") + messageField:clear() +end + +newTextFrame:addButton():setText("Cancel"):setAnchor("bottomLeft"):setBackground(colors.black):setForeground(colors.lightGray):setSize(12,1):setPosition(2,1):onClick(function() + messageBoxLoseFocus() +end) + +newTextFrame:onLoseFocus(messageBoxLoseFocus) + +loginFrame:addLabel():setAnchor("center"):setPosition(-2, -1):setText("Username:") +local nameInput = loginFrame:addInput():setAnchor("center"):setPosition(3,0):setBackground(colors.black):setForeground(colors.lightGray):setSize(16,1):setDefaultText("Username...", colors.gray) + +local serverList = loginFrame:addList():setPosition(3, 6):setSize(16, 10) +local channelRadio = sideBar:addRadio():setForeground(colors.black):setBackground(colors.gray):setSelectedItem(colors.gray, colors.lightGray):setActiveSymbol(" ") +local channelObjects = {} +local updateChannels = basalt.shedule(function() + if(bot_id~=nil)then + for k,v in pairs(channelObjects)do + sideBar:removeObject(v) + end + channelObjects = {} + if(serverList:getValue().args~=nil)then + local y = 8 + local maxScroll = 2 + for k,v in pairs(servers[serverList:getValue().args[1]])do + local content = http.get("https://discord.com/api/channels/"..v, {["Content-Type"] = "application/json", ["Authorization"] = "Bot "..bot_id}) + local channel = textutils.unserializeJSON(content.readAll()) + if(channel~=nil)then + channelRadio:addItem("#"..channel.name,1, y, nil,nil,v) + y = y + 1 + maxScroll = maxScroll + 1 + end + end + end + end +end) + +serverList:onChange(updateChannels) +basalt.shedule(function() + if(bot_id~=nil)then + for k,v in pairs(servers)do + local content = http.get("https://discord.com/api/guilds/"..k, {["Content-Type"] = "application/json", ["Authorization"] = "Bot "..bot_id}) + local guild = textutils.unserializeJSON(content.readAll()) + if(guild~=nil)then + serverList:addItem(guild.name,nil,nil,k) + end + end + end +end)() + +updateChannels() + + + +channelRadio:onChange(function(self) + local val = self:getValue() + if(val~=nil)and(val.args[1]~=nil)then + channel_id = val.args[1] + end +end) + +loginFrame:addButton():setAnchor("bottomRight"):setPosition(-10, -2):setSize(11,3):setText("Login"):onClick(function() + offsetAnimation(main, main:getWidth(), 0) +end) +loginFrame:addLabel():setPosition(3, 5):setText("Servers:") + + + +local function sendDiscordMessage(msg, channel, bot) + if(channel~=nil)and(bot~=nil)then + if(nameInput:getValue()~="")then + msg = string.gsub(msg, "\n", "\\n") + http.post("https://discord.com/api/channels/"..channel.."/messages", '{ "content": "['..nameInput:getValue()..']: '..msg..'" }', {["Content-Type"] = "application/json", ["Authorization"] = "Bot "..bot}) + end + end +end + +newTextFrame:addButton():setText("Send"):setAnchor("bottomRight"):setBackground(colors.black):setForeground(colors.lightGray):setSize(12,1):setPosition(-11,1) + :onClick(function() + local msg = table.concat(messageField:getLines(), "\n") + if(#msg>0)then + sendDiscordMessage(msg, channel_id, bot_id) + end + messageBoxLoseFocus() + end) + +local function refreshMessages() + while true do + maxOffset = 0 + updateDiscordMessages(channel_id, bot_id) + maxOffset = maxOffset - messageFrameList:getHeight()+1 + messageFrameList:setMaxScroll(maxOffset) + sleep(refreshRate) + end +end + +local thread = main:addThread():start(refreshMessages) + +basalt.autoUpdate()