Guest User

twitter

a guest
Jul 1st, 2016
61
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
Lua 12.42 KB | None | 0 0
  1. -- Code written by Cruor, after request by Mikee
  2. -- Demonstration video can be found at http://www.youtube.com/watch?v=ElFNEgElPdo also by Cruor
  3. -- Help page can be found at http://pastebin.com/2wKZWR0u
  4.  
  5. local function printUsage()
  6.     local scriptName = shell.getRunningProgram()
  7.     return 'Usage: ' .. scriptName .. ' <side>'
  8. end
  9.  
  10. local args = {...}
  11. local side = args[1]
  12.  
  13. assert(http, 'HTTP is required for this program.')
  14. assert(side, printUsage())
  15.  
  16. local glass = assert(peripheral.wrap(side), printUsage())
  17. glass.clear()
  18.  
  19. local settings = {
  20.     displayTime = 10,
  21.     autoDisplay = false,
  22.     toastCount = 2,
  23.     display = true,
  24.     timerRate = 2.5
  25. }
  26.  
  27. local lastID
  28. local watching = {
  29.     ftb_team = true
  30. }
  31.  
  32. local tweets = {}
  33.  
  34. local function StatusBar(x, y)
  35.     local t = {
  36.         update = function(self)
  37.             local str = 'You have: ' .. #tweets .. ' unread tweet(s).'
  38.             if self.text.getText() ~= str and settings.display then
  39.                 self.text.setText(str)
  40.             end
  41.         end,
  42.         hide = function(self)
  43.             self.text.setText('')
  44.  
  45.             self.background.setAlpha(0)
  46.             self.background.setAlpha2(0)
  47.  
  48.             self.background.setWidth(0)
  49.             self.background.setHeight(0)
  50.  
  51.         end,
  52.         show = function(self)
  53.             if settings.display then
  54.                 self.background.setAlpha(0.7)
  55.                 self.background.setAlpha2(0.7)
  56.  
  57.                 self.background.setWidth(200)
  58.                 self.background.setHeight(16)
  59.  
  60.                 self:update()
  61.             end
  62.         end,
  63.         delete = function(self)
  64.             self.background.delete()
  65.             self.text.delete()
  66.         end,
  67.         background = glass.addBox(x, y, 200, 16, 0x262626, 0),
  68.         text = glass.addText(x + 4, y + 4, '', 0xFFFFFF)
  69.     }
  70.     t.background.setZIndex(0)
  71.     t.text.setZIndex(1)
  72.  
  73.     return t
  74. end
  75.  
  76. local function TweetToast(x, y)
  77.     local t = {
  78.         lines = {},
  79.         hidden = true,
  80.         show = function(self, title, text)
  81.             self.hidden = false
  82.  
  83.             local i = 1
  84.             local str = ''
  85.  
  86.             for w in string.gmatch(text, '%S+') do
  87.                 local currentWidth = glass.getStringWidth(str)
  88.                 local wordWidth = glass.getStringWidth(w)
  89.  
  90.                 if currentWidth + wordWidth > 257 then
  91.                     if self.lines[i] and settings.display then
  92.                         self.lines[i].setText(str)
  93.                     end
  94.                     str = ''
  95.                     i = i + 1
  96.                 end
  97.                 str = str .. w .. ' '
  98.             end
  99.            
  100.             if settings.display then
  101.                 if self.lines[i] then
  102.                     self.lines[i].setText(str)
  103.                 end
  104.  
  105.                 self.title.setText(title)
  106.  
  107.                 self.background.setAlpha(0.7)
  108.                 self.background.setAlpha2(0.7)
  109.  
  110.                 self.background.setWidth(265)
  111.                 self.background.setHeight(112)
  112.  
  113.                 self.displayTimeAcc = 0
  114.             end
  115.         end,
  116.         update = function(self, dt)
  117.             self.displayTimeAcc = self.displayTimeAcc + dt
  118.             if not self.hidden and self.displayTimeAcc >= settings.displayTime then
  119.                 self:hide()
  120.                 self.hidden = true
  121.             end
  122.         end,
  123.         hide = function(self)
  124.             for i = 1, #self.lines do
  125.                 self.lines[i].setText('')
  126.             end
  127.  
  128.             self.background.setWidth(0)
  129.             self.background.setHeight(0)
  130.  
  131.             self.background.setAlpha(0)
  132.             self.background.setAlpha2(0)
  133.  
  134.             self.title.setText('')
  135.  
  136.             self.hidden = true
  137.         end,
  138.         delete = function(self)
  139.             self.background.delete()
  140.             self.title.delete()
  141.  
  142.             for i = 1, #self.lines do
  143.                 self.lines[i].delete()
  144.             end
  145.         end,
  146.         displayTimeAcc = settings.displayTime,
  147.         background = glass.addBox(x, y, 265, 112, 0x262626, 0),
  148.         title = glass.addText(x + 4, y + 4, '', 0xFFFFFF)
  149.     }
  150.  
  151.     for i = 1, 7 do
  152.         t.lines[i] = glass.addText(x + 4, y + 4 + i * 10, '', 0xFFFFFF)
  153.         t.lines[i].setZIndex(1)
  154.     end
  155.  
  156.     t.title.setZIndex(1)
  157.     t.background.setZIndex(0)
  158.  
  159.     return t
  160. end
  161.  
  162. local function parseTweet(msg)
  163.     local unescapePattern = '&#(%x+);'
  164.     local userPattern = '<a href="/(.-)" class="twitter%-atreply.-</a>'
  165.     local linkPattern = '<a href="(.-)".-</a>'
  166.     local searchPattern = '<a href="/search.-%%23(.-)&amp;.-</a>'
  167.  
  168.     local msg = string.gsub(msg, unescapePattern, function(s)
  169.         return string.char(s)
  170.     end)
  171.  
  172.     msg = string.gsub(msg, userPattern, function(s)
  173.         return '@' .. s
  174.     end)
  175.  
  176.     msg = string.gsub(msg, searchPattern, function(s)
  177.         return '#' .. s
  178.     end)
  179.  
  180.     msg = string.gsub(msg, linkPattern, function(s)
  181.         return s
  182.     end)
  183.  
  184.     return msg
  185. end
  186.  
  187. local function pullTweet(name)
  188.     local data
  189.  
  190.     local fh = http.get('https://twitter.com/' .. name)
  191.     if fh then
  192.         data = fh.readAll()
  193.         fh.close()
  194.     end
  195.  
  196.     if data then
  197.         local pattern = 'data%-tweet%-id="(.-)".-data%-screen%-name="(.-)".-"(.-)".-title="(.-)".-<p class="js%-tweet%-text tweet%-text">(.-)</p>'
  198.  
  199.         local id, screenName, name, timestamp, text = string.match(data, pattern)
  200.         local text = parseTweet(text)
  201.  
  202.         return id, text, name, screenName, timestamp
  203.     end
  204.  
  205.     return
  206. end
  207.  
  208. local function displayToasts(toasts, statusBar)
  209.     for i = 1, #toasts do
  210.         if toasts[i].displayTimeAcc >= settings.displayTime and settings.display then
  211.             if tweets[1] then
  212.                 local tweet = tweets[1]
  213.                 local title = tweet['name'] .. ' (@' .. tweet['screenName'] .. ')'
  214.                 local text = tweet['text']
  215.  
  216.                 toasts[i]:show(title, text)
  217.  
  218.                 table.remove(tweets, 1)
  219.  
  220.                 statusBar:update()
  221.             end
  222.         end
  223.     end
  224. end
  225.  
  226. local function loadConfig(filename)
  227.     local fh = io.open(filename)
  228.     local data = fh:read('*a')
  229.     fh:close()
  230.  
  231.     local config = {}
  232.  
  233.     for line in string.gmatch(data, '[^\n]+') do
  234.         local k, v = string.match(line, '([^ =]+)%s+=%s+(.*)')
  235.  
  236.         if v == 'true' then
  237.             v = true
  238.  
  239.         elseif v == 'false' then
  240.             v = false
  241.         end
  242.  
  243.         if tonumber(v) then
  244.             v = tonumber(v)
  245.         end
  246.  
  247.         if k and v then
  248.             config[k] = v
  249.         end
  250.     end
  251.  
  252.     return config
  253. end
  254.  
  255. local function saveConfig(filename, t)
  256.     local fh = io.open(filename, 'w')
  257.  
  258.     local data = ''
  259.  
  260.     for k, v in pairs(t) do
  261.         data = data .. tostring(k) .. ' = ' .. tostring(v) .. '\n'
  262.     end
  263.  
  264.     fh:write(data)
  265.     fh:close()
  266. end
  267.  
  268. local function loadWatchingList(filename)
  269.     local fh = io.open(filename)
  270.     local data = fh:read('*a')
  271.     fh:close()
  272.  
  273.     local list = {}
  274.  
  275.     for line in string.gmatch(data, '[^\n]+') do
  276.         list[line] = true
  277.     end
  278.  
  279.     return list
  280. end
  281.  
  282. local function saveWatchingList(filename, t)
  283.     local fh = io.open(filename, 'w')
  284.  
  285.     local data = ''
  286.  
  287.     for k, v in pairs(t) do
  288.         if v then
  289.             data = data .. k .. '\n'
  290.         end
  291.     end
  292.  
  293.     fh:write(data)
  294.     fh:close()
  295. end
  296.  
  297. local function watchingNum(watching)
  298.     local i = 0
  299.     for k, v in pairs(watching) do
  300.         if v then
  301.             i = i + 1
  302.         end
  303.     end
  304.     return i
  305. end
  306.  
  307. local folder = '.twitter'
  308. local settingsFilename = '.twitter/config'
  309. local lastIDFilename = '.twitter/lastID'
  310. local watchingFilename = '.twitter/watching'
  311.  
  312. if fs.exists(folder) and not fs.isDir(folder) then
  313.     print('File with name .twitter allready exists.')
  314.     print('Please delete this file and re run this program.')
  315. end
  316.  
  317. if not fs.exists(folder) then
  318.     fs.makeDir(folder)
  319. end
  320.  
  321. if fs.exists(settingsFilename) then
  322.     print('Loaded config')
  323.     settings = loadConfig(settingsFilename)
  324. else
  325.     print('Saved config to: ' .. settingsFilename)
  326.     saveConfig(settingsFilename, settings)
  327. end
  328.  
  329. if fs.exists(lastIDFilename) then
  330.     lastID = loadConfig(lastIDFilename)
  331. else
  332.     lastID = {}
  333. end
  334.  
  335. if fs.exists(watchingFilename) then
  336.     watching = loadWatchingList(watchingFilename)
  337. else
  338.     watching = {}
  339. end
  340.  
  341.  
  342. local statusBar = StatusBar(10, 10)
  343. statusBar:show()
  344.  
  345. local toasts = {}
  346.  
  347. for i = 1, settings.toastCount do
  348.     toasts[i] = TweetToast(10, 50 + 132 * (i - 1))
  349.     toasts[i]:hide()
  350. end
  351.  
  352. -- This is to make twitter not hate us!
  353. local sleepLength = 24 * watchingNum(watching) + 1
  354. local updateAcc = sleepLength
  355.  
  356. local timerID = os.startTimer(settings.timerRate)
  357.  
  358. while true do
  359.     local event, par1, par2 = os.pullEvent()
  360.     if event == 'timer' then
  361.         timerID = os.startTimer(settings.timerRate)
  362.  
  363.         if #tweets > 0 and settings.autoDisplay then
  364.             displayToasts(toasts, statusBar)
  365.         end
  366.  
  367.         for i = 1, #toasts do
  368.             toasts[i]:update(settings.timerRate)
  369.         end
  370.  
  371.         if updateAcc >= sleepLength then
  372.             updateAcc = updateAcc - sleepLength
  373.  
  374.             for k, v in pairs(watching) do
  375.                 if v then
  376.                     local id, text, name, screenName, timestamp = pullTweet(k)
  377.                     id = tonumber(id)
  378.                     if id then
  379.                         if not lastID[k] or id ~= lastID[k] then
  380.                             lastID[k] = id
  381.  
  382.                             table.insert(tweets, {
  383.                                 text = text,
  384.                                 name = name,
  385.                                 screenName = screenName,
  386.                                 timestamp = timestamp
  387.                             })
  388.                         end
  389.                     end
  390.                 end
  391.             end
  392.             statusBar:update()
  393.  
  394.             saveConfig(lastIDFilename, lastID)
  395.         end
  396.  
  397.         updateAcc = updateAcc + settings.timerRate
  398.  
  399.     elseif event == 'chat_command' then
  400.         local command = par1
  401.         local user = par2
  402.         local splitted = {}
  403.  
  404.         if user then
  405.             print(user .. ' used command: ' .. command)
  406.         else
  407.             print('Command: ' .. command)
  408.         end
  409.  
  410.         for w in string.gmatch(command, '[^ ]+') do
  411.             table.insert(splitted, w)
  412.         end
  413.  
  414.         if command == 'hide' then
  415.             settings.display = false
  416.             statusBar:hide()
  417.            
  418.             for i = 1, #toasts do
  419.                 toasts[i]:hide()
  420.             end
  421.  
  422.             saveConfig(settingsFilename, settings)
  423.  
  424.         elseif command == 'show' then
  425.             settings.display = true
  426.             statusBar:show()
  427.  
  428.             saveConfig(settingsFilename, settings)
  429.  
  430.         elseif command == 'display' then
  431.             if not settings.autoDisplay then
  432.                 displayToasts(toasts, statusBar)
  433.             end
  434.  
  435.         elseif command == 'clear' then
  436.             lastID = {}
  437.             saveConfig(lastIDFilename, lastID)
  438.  
  439.         elseif splitted[1] == 'watch' then
  440.             watching[splitted[2]] = true
  441.             saveWatchingList(watchingFilename, watching)
  442.  
  443.             sleepLength = math.floor(3600 / 150 * watchingNum(watching)) + 1
  444.  
  445.             -- Maybe show on the HUD?
  446.             print('Added "' .. splitted[2] .. '" to watching list.')
  447.  
  448.         elseif splitted[1] == 'unwatch' then
  449.             watching[splitted[2]] = false
  450.             saveWatchingList(watchingFilename, watching)
  451.  
  452.             sleepLength = 24 * watchingNum(watching) + 1
  453.  
  454.             print('Removed "' .. splitted[2] .. '" from watching list.')
  455.  
  456.         elseif splitted[1] == 'set' then
  457.             if splitted[2] == 'displayTime' then
  458.                 settings.displaytime = tonumber(splitted[3])
  459.  
  460.             elseif splitted[2] == 'autoDisplay' then
  461.                 if splitted[3] == 'true' then
  462.                     settings.autoDisplay = true
  463.  
  464.                 elseif splitted[3] == 'false' then
  465.                     settings.autoDisplay = false
  466.                 end
  467.  
  468.             elseif splitted[2] == 'toastCount' then
  469.                 settings.toastCount = tonumber(splitted[3])
  470.  
  471.             elseif splitted[2] == 'timerRate' then
  472.                 settings.timerRate = tonumber(splitted[3])
  473.             end
  474.             saveConfig(settingsFilename, settings)
  475.         end
  476.     end
  477. end
Add Comment
Please, Sign In to add comment