├── .gitignore ├── Procfile ├── README.md ├── bin └── sendTweet ├── index.js ├── modules ├── T.js └── twitter.js ├── package-lock.json ├── package.json └── views └── index.html /.gitignore: -------------------------------------------------------------------------------- 1 | node_modules 2 | .idea/ 3 | secrets.js 4 | npm-debug.log -------------------------------------------------------------------------------- /Procfile: -------------------------------------------------------------------------------- 1 | worker: node index.js -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # botsofcode 2 | 3 | 4 | 5 | A twitter bot for [bitsofco.de](https://bitsofco.de). 6 | 7 | [Read the blog post](https://bitsofco.de/making-botsofcode-an-introduction-to-twitter-bots/) | [Follow @botsofcode](https://twitter.com/botsofcode) 8 | -------------------------------------------------------------------------------- /bin/sendTweet: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env node 2 | 3 | "use strict"; 4 | 5 | const T = require('../modules/T'); 6 | const https = require('https'); 7 | const Twitter = require('../modules/twitter'); 8 | const url = process.env.bitsofcode_backup_url; 9 | 10 | function fetch(url) { 11 | return new Promise((resolve, reject) => { 12 | https.get(url, function (res) { 13 | let body = ''; 14 | res.on('data', function (data) { 15 | data = data.toString(); 16 | body += data; 17 | }); 18 | 19 | res.on('end', function () { 20 | body = JSON.parse(body); 21 | resolve(body); 22 | }); 23 | 24 | }).on('error', function (err) { 25 | reject(err); 26 | }); 27 | 28 | }) 29 | } 30 | 31 | 32 | function createTweet(post, tags) { 33 | let hashtags = ''; 34 | tags.map(tag => hashtags += `#${tag} `) 35 | const tweetText = `'${post.title}' https://bitsofco.de/${post.slug}/ ${hashtags}`; 36 | console.log(tweetText); 37 | Twitter.tweet(tweetText); 38 | } 39 | 40 | fetch(url).then((response) => { 41 | 42 | const posts = response.db[0].data.posts; 43 | const posts_tags = response.db[0].data.posts_tags; 44 | const tags = response.db[0].data.tags; 45 | 46 | function getRandomPost() { 47 | for (let i = 0; i < posts.length; i++) { 48 | let post = posts[Math.floor(Math.random()*posts.length)]; 49 | let isPost = post.page === 0; 50 | let isPublished = post.status === 'published'; 51 | let isPublic = post.visibility === 'public'; 52 | if ( isPost && isPublished && isPublic ) { 53 | return post; 54 | break; 55 | } 56 | } 57 | } 58 | 59 | function getPostTags(postID) { 60 | const postTagsIds = []; 61 | posts_tags.find((posts_tag) => { 62 | if ( posts_tag.post_id === postID ) postTagsIds.push(posts_tag.tag_id); 63 | }); 64 | const postTags = []; 65 | postTagsIds.map((postTagsID) => { 66 | tags.find((tag) => { 67 | if ( tag.id === postTagsID ) return postTags.push(tag.name); 68 | }) 69 | }) 70 | return postTags; 71 | } 72 | 73 | const randomPost = getRandomPost(); 74 | const randomPostTags = getPostTags(randomPost.id); 75 | createTweet(randomPost, randomPostTags) 76 | }) -------------------------------------------------------------------------------- /index.js: -------------------------------------------------------------------------------- 1 | /* ****************** 2 | 3 | Fixes for Heroku 4 | See http://stackoverflow.com/a/31094668 5 | 6 | ******************* */ 7 | 8 | const express = require('express'); 9 | const app = express(); 10 | const path = require('path'); 11 | app.set('port', (process.env.PORT || 5000)); 12 | app.get('/', function (request, response) { 13 | response.sendFile(path.join(__dirname + '/views/index.html')); 14 | }).listen(app.get('port'), function () { 15 | console.log('App is running, server is listening on port ', app.get('port')); 16 | }); 17 | 18 | 19 | /* ****************** 20 | 21 | The Setup 22 | 23 | ******************* */ 24 | const T = require('./modules/T'); 25 | const Twitter = require('./modules/twitter'); 26 | 27 | /* ****************** 28 | 29 | Key Variables 30 | 31 | ******************* */ 32 | const me = { 33 | id: 2714960622, 34 | screen_name: 'ireaderinokun' 35 | }; 36 | 37 | const botsofcode = { 38 | id: 743145993844179000, 39 | screen_name: 'botsofcode' 40 | }; 41 | 42 | const emojis = ['👊', '👊', '🙌', '👍', '💁', '👌', '🙅', '👯']; 43 | 44 | 45 | /* ****************** 46 | 47 | General Functions 48 | 49 | ******************* */ 50 | function shouldSendReply() { 51 | const randomNumber = Math.random(); 52 | if (randomNumber > 0.3) return true; 53 | return false; 54 | } 55 | 56 | function getEmoji() { 57 | return emojis[Math.floor(Math.random() * emojis.length)]; 58 | } 59 | 60 | function getTweet(tweet) { 61 | 62 | const text = `Thanks for sharing! ${ getEmoji() }`; 63 | return text; 64 | 65 | } 66 | 67 | 68 | /* ****************** 69 | 70 | Stream 71 | 72 | ******************* */ 73 | 74 | const stream = T.stream('statuses/filter', { track: ['bitsofco.de'] }); 75 | 76 | stream.on('tweet', (tweet) => { 77 | 78 | if ( tweet.user.id === botsofcode.id ) { 79 | return; 80 | } 81 | 82 | Twitter.like(tweet); 83 | 84 | if ( tweet.user.id === me.id ) { 85 | Twitter.retweet(tweet); 86 | return; 87 | } 88 | 89 | if ( tweet.retweeted_status ) return; 90 | 91 | if ( tweet.text.toLowerCase().includes('@ireaderinokun') ) { 92 | if ( shouldSendReply() ) { 93 | Twitter.reply(tweet, getTweet(tweet)); 94 | } 95 | return; 96 | } 97 | 98 | Twitter.reply(tweet, getTweet(tweet)); 99 | 100 | }); 101 | 102 | 103 | 104 | -------------------------------------------------------------------------------- /modules/T.js: -------------------------------------------------------------------------------- 1 | const Twit = require('twit'); 2 | module.exports = new Twit({ 3 | consumer_key: process.env.consumer_key, 4 | consumer_secret: process.env.consumer_secret, 5 | access_token: process.env.access_token, 6 | access_token_secret: process.env.access_token_secret 7 | }); -------------------------------------------------------------------------------- /modules/twitter.js: -------------------------------------------------------------------------------- 1 | const T = require('./T'); 2 | 3 | module.exports = { 4 | tweet: (tweet) => { 5 | T.post('statuses/update', { 6 | status: tweet 7 | }); 8 | }, 9 | 10 | retweet: (tweet) => { 11 | T.post('statuses/retweet/:id', {id: tweet.id_str}); 12 | }, 13 | 14 | reply: (tweet, reply) => { 15 | T.post('statuses/update', { 16 | status: `@${tweet.user.screen_name} ${reply}`, 17 | in_reply_to_status_id: tweet.id_str 18 | }); 19 | }, 20 | 21 | like: (tweet) => { 22 | T.post('favorites/create', {id: tweet.id_str}); 23 | }, 24 | 25 | addToList: (list, user) => { 26 | T.post('lists/members/create', { 27 | slug: list, 28 | owner_screen_name: botsofcode.screen_name, 29 | screen_name: user 30 | }); 31 | } 32 | } -------------------------------------------------------------------------------- /package-lock.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "botsofcode", 3 | "version": "1.0.1", 4 | "lockfileVersion": 1, 5 | "requires": true, 6 | "dependencies": { 7 | "accepts": { 8 | "version": "1.3.5", 9 | "resolved": "https://registry.npmjs.org/accepts/-/accepts-1.3.5.tgz", 10 | "integrity": "sha1-63d99gEXI6OxTopywIBcjoZ0a9I=", 11 | "requires": { 12 | "mime-types": "2.1.22", 13 | "negotiator": "0.6.1" 14 | } 15 | }, 16 | "ajv": { 17 | "version": "6.9.1", 18 | "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.9.1.tgz", 19 | "integrity": "sha512-XDN92U311aINL77ieWHmqCcNlwjoP5cHXDxIxbf2MaPYuCXOHS7gHH8jktxeK5omgd52XbSTX6a4Piwd1pQmzA==", 20 | "requires": { 21 | "fast-deep-equal": "2.0.1", 22 | "fast-json-stable-stringify": "2.0.0", 23 | "json-schema-traverse": "0.4.1", 24 | "uri-js": "4.2.2" 25 | } 26 | }, 27 | "array-flatten": { 28 | "version": "1.1.1", 29 | "resolved": "https://registry.npmjs.org/array-flatten/-/array-flatten-1.1.1.tgz", 30 | "integrity": "sha1-ml9pkFGx5wczKPKgCJaLZOopVdI=" 31 | }, 32 | "asn1": { 33 | "version": "0.2.4", 34 | "resolved": "https://registry.npmjs.org/asn1/-/asn1-0.2.4.tgz", 35 | "integrity": "sha512-jxwzQpLQjSmWXgwaCZE9Nz+glAG01yF1QnWgbhGwHI5A6FRIEY6IVqtHhIepHqI7/kyEyQEagBC5mBEFlIYvdg==", 36 | "requires": { 37 | "safer-buffer": "2.1.2" 38 | } 39 | }, 40 | "assert-plus": { 41 | "version": "1.0.0", 42 | "resolved": "https://registry.npmjs.org/assert-plus/-/assert-plus-1.0.0.tgz", 43 | "integrity": "sha1-8S4PPF13sLHN2RRpQuTpbB5N1SU=" 44 | }, 45 | "asynckit": { 46 | "version": "0.4.0", 47 | "resolved": "https://registry.npmjs.org/asynckit/-/asynckit-0.4.0.tgz", 48 | "integrity": "sha1-x57Zf380y48robyXkLzDZkdLS3k=" 49 | }, 50 | "aws-sign2": { 51 | "version": "0.7.0", 52 | "resolved": "https://registry.npmjs.org/aws-sign2/-/aws-sign2-0.7.0.tgz", 53 | "integrity": "sha1-tG6JCTSpWR8tL2+G1+ap8bP+dqg=" 54 | }, 55 | "aws4": { 56 | "version": "1.8.0", 57 | "resolved": "https://registry.npmjs.org/aws4/-/aws4-1.8.0.tgz", 58 | "integrity": "sha512-ReZxvNHIOv88FlT7rxcXIIC0fPt4KZqZbOlivyWtXLt8ESx84zd3kMC6iK5jVeS2qt+g7ftS7ye4fi06X5rtRQ==" 59 | }, 60 | "bcrypt-pbkdf": { 61 | "version": "1.0.2", 62 | "resolved": "https://registry.npmjs.org/bcrypt-pbkdf/-/bcrypt-pbkdf-1.0.2.tgz", 63 | "integrity": "sha1-pDAdOJtqQ/m2f/PKEaP2Y342Dp4=", 64 | "requires": { 65 | "tweetnacl": "0.14.5" 66 | } 67 | }, 68 | "bluebird": { 69 | "version": "3.5.3", 70 | "resolved": "https://registry.npmjs.org/bluebird/-/bluebird-3.5.3.tgz", 71 | "integrity": "sha512-/qKPUQlaW1OyR51WeCPBvRnAlnZFUJkCSG5HzGnuIqhgyJtF+T94lFnn33eiazjRm2LAHVy2guNnaq48X9SJuw==" 72 | }, 73 | "body-parser": { 74 | "version": "1.18.3", 75 | "resolved": "https://registry.npmjs.org/body-parser/-/body-parser-1.18.3.tgz", 76 | "integrity": "sha1-WykhmP/dVTs6DyDe0FkrlWlVyLQ=", 77 | "requires": { 78 | "bytes": "3.0.0", 79 | "content-type": "1.0.4", 80 | "debug": "2.6.9", 81 | "depd": "1.1.2", 82 | "http-errors": "1.6.3", 83 | "iconv-lite": "0.4.23", 84 | "on-finished": "2.3.0", 85 | "qs": "6.5.2", 86 | "raw-body": "2.3.3", 87 | "type-is": "1.6.16" 88 | } 89 | }, 90 | "bytes": { 91 | "version": "3.0.0", 92 | "resolved": "https://registry.npmjs.org/bytes/-/bytes-3.0.0.tgz", 93 | "integrity": "sha1-0ygVQE1olpn4Wk6k+odV3ROpYEg=" 94 | }, 95 | "caseless": { 96 | "version": "0.12.0", 97 | "resolved": "https://registry.npmjs.org/caseless/-/caseless-0.12.0.tgz", 98 | "integrity": "sha1-G2gcIf+EAzyCZUMJBolCDRhxUdw=" 99 | }, 100 | "combined-stream": { 101 | "version": "1.0.7", 102 | "resolved": "https://registry.npmjs.org/combined-stream/-/combined-stream-1.0.7.tgz", 103 | "integrity": "sha512-brWl9y6vOB1xYPZcpZde3N9zDByXTosAeMDo4p1wzo6UMOX4vumB+TP1RZ76sfE6Md68Q0NJSrE/gbezd4Ul+w==", 104 | "requires": { 105 | "delayed-stream": "1.0.0" 106 | } 107 | }, 108 | "content-disposition": { 109 | "version": "0.5.2", 110 | "resolved": "https://registry.npmjs.org/content-disposition/-/content-disposition-0.5.2.tgz", 111 | "integrity": "sha1-DPaLud318r55YcOoUXjLhdunjLQ=" 112 | }, 113 | "content-type": { 114 | "version": "1.0.4", 115 | "resolved": "https://registry.npmjs.org/content-type/-/content-type-1.0.4.tgz", 116 | "integrity": "sha512-hIP3EEPs8tB9AT1L+NUqtwOAps4mk2Zob89MWXMHjHWg9milF/j4osnnQLXBCBFBk/tvIG/tUc9mOUJiPBhPXA==" 117 | }, 118 | "cookie": { 119 | "version": "0.3.1", 120 | "resolved": "https://registry.npmjs.org/cookie/-/cookie-0.3.1.tgz", 121 | "integrity": "sha1-5+Ch+e9DtMi6klxcWpboBtFoc7s=" 122 | }, 123 | "cookie-signature": { 124 | "version": "1.0.6", 125 | "resolved": "https://registry.npmjs.org/cookie-signature/-/cookie-signature-1.0.6.tgz", 126 | "integrity": "sha1-4wOogrNCzD7oylE6eZmXNNqzriw=" 127 | }, 128 | "core-util-is": { 129 | "version": "1.0.2", 130 | "resolved": "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.2.tgz", 131 | "integrity": "sha1-tf1UIgqivFq1eqtxQMlAdUUDwac=" 132 | }, 133 | "dashdash": { 134 | "version": "1.14.1", 135 | "resolved": "https://registry.npmjs.org/dashdash/-/dashdash-1.14.1.tgz", 136 | "integrity": "sha1-hTz6D3y+L+1d4gMmuN1YEDX24vA=", 137 | "requires": { 138 | "assert-plus": "1.0.0" 139 | } 140 | }, 141 | "debug": { 142 | "version": "2.6.9", 143 | "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", 144 | "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", 145 | "requires": { 146 | "ms": "2.0.0" 147 | } 148 | }, 149 | "delayed-stream": { 150 | "version": "1.0.0", 151 | "resolved": "https://registry.npmjs.org/delayed-stream/-/delayed-stream-1.0.0.tgz", 152 | "integrity": "sha1-3zrhmayt+31ECqrgsp4icrJOxhk=" 153 | }, 154 | "depd": { 155 | "version": "1.1.2", 156 | "resolved": "https://registry.npmjs.org/depd/-/depd-1.1.2.tgz", 157 | "integrity": "sha1-m81S4UwJd2PnSbJ0xDRu0uVgtak=" 158 | }, 159 | "destroy": { 160 | "version": "1.0.4", 161 | "resolved": "https://registry.npmjs.org/destroy/-/destroy-1.0.4.tgz", 162 | "integrity": "sha1-l4hXRCxEdJ5CBmE+N5RiBYJqvYA=" 163 | }, 164 | "ecc-jsbn": { 165 | "version": "0.1.2", 166 | "resolved": "https://registry.npmjs.org/ecc-jsbn/-/ecc-jsbn-0.1.2.tgz", 167 | "integrity": "sha1-OoOpBOVDUyh4dMVkt1SThoSamMk=", 168 | "requires": { 169 | "jsbn": "0.1.1", 170 | "safer-buffer": "2.1.2" 171 | } 172 | }, 173 | "ee-first": { 174 | "version": "1.1.1", 175 | "resolved": "https://registry.npmjs.org/ee-first/-/ee-first-1.1.1.tgz", 176 | "integrity": "sha1-WQxhFWsK4vTwJVcyoViyZrxWsh0=" 177 | }, 178 | "encodeurl": { 179 | "version": "1.0.2", 180 | "resolved": "https://registry.npmjs.org/encodeurl/-/encodeurl-1.0.2.tgz", 181 | "integrity": "sha1-rT/0yG7C0CkyL1oCw6mmBslbP1k=" 182 | }, 183 | "escape-html": { 184 | "version": "1.0.3", 185 | "resolved": "https://registry.npmjs.org/escape-html/-/escape-html-1.0.3.tgz", 186 | "integrity": "sha1-Aljq5NPQwJdN4cFpGI7wBR0dGYg=" 187 | }, 188 | "etag": { 189 | "version": "1.8.1", 190 | "resolved": "https://registry.npmjs.org/etag/-/etag-1.8.1.tgz", 191 | "integrity": "sha1-Qa4u62XvpiJorr/qg6x9eSmbCIc=" 192 | }, 193 | "express": { 194 | "version": "4.16.4", 195 | "resolved": "https://registry.npmjs.org/express/-/express-4.16.4.tgz", 196 | "integrity": "sha512-j12Uuyb4FMrd/qQAm6uCHAkPtO8FDTRJZBDd5D2KOL2eLaz1yUNdUB/NOIyq0iU4q4cFarsUCrnFDPBcnksuOg==", 197 | "requires": { 198 | "accepts": "1.3.5", 199 | "array-flatten": "1.1.1", 200 | "body-parser": "1.18.3", 201 | "content-disposition": "0.5.2", 202 | "content-type": "1.0.4", 203 | "cookie": "0.3.1", 204 | "cookie-signature": "1.0.6", 205 | "debug": "2.6.9", 206 | "depd": "1.1.2", 207 | "encodeurl": "1.0.2", 208 | "escape-html": "1.0.3", 209 | "etag": "1.8.1", 210 | "finalhandler": "1.1.1", 211 | "fresh": "0.5.2", 212 | "merge-descriptors": "1.0.1", 213 | "methods": "1.1.2", 214 | "on-finished": "2.3.0", 215 | "parseurl": "1.3.2", 216 | "path-to-regexp": "0.1.7", 217 | "proxy-addr": "2.0.4", 218 | "qs": "6.5.2", 219 | "range-parser": "1.2.0", 220 | "safe-buffer": "5.1.2", 221 | "send": "0.16.2", 222 | "serve-static": "1.13.2", 223 | "setprototypeof": "1.1.0", 224 | "statuses": "1.4.0", 225 | "type-is": "1.6.16", 226 | "utils-merge": "1.0.1", 227 | "vary": "1.1.2" 228 | } 229 | }, 230 | "extend": { 231 | "version": "3.0.2", 232 | "resolved": "https://registry.npmjs.org/extend/-/extend-3.0.2.tgz", 233 | "integrity": "sha512-fjquC59cD7CyW6urNXK0FBufkZcoiGG80wTuPujX590cB5Ttln20E2UB4S/WARVqhXffZl2LNgS+gQdPIIim/g==" 234 | }, 235 | "extsprintf": { 236 | "version": "1.3.0", 237 | "resolved": "https://registry.npmjs.org/extsprintf/-/extsprintf-1.3.0.tgz", 238 | "integrity": "sha1-lpGEQOMEGnpBT4xS48V06zw+HgU=" 239 | }, 240 | "fast-deep-equal": { 241 | "version": "2.0.1", 242 | "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-2.0.1.tgz", 243 | "integrity": "sha1-ewUhjd+WZ79/Nwv3/bLLFf3Qqkk=" 244 | }, 245 | "fast-json-stable-stringify": { 246 | "version": "2.0.0", 247 | "resolved": "https://registry.npmjs.org/fast-json-stable-stringify/-/fast-json-stable-stringify-2.0.0.tgz", 248 | "integrity": "sha1-1RQsDK7msRifh9OnYREGT4bIu/I=" 249 | }, 250 | "finalhandler": { 251 | "version": "1.1.1", 252 | "resolved": "https://registry.npmjs.org/finalhandler/-/finalhandler-1.1.1.tgz", 253 | "integrity": "sha512-Y1GUDo39ez4aHAw7MysnUD5JzYX+WaIj8I57kO3aEPT1fFRL4sr7mjei97FgnwhAyyzRYmQZaTHb2+9uZ1dPtg==", 254 | "requires": { 255 | "debug": "2.6.9", 256 | "encodeurl": "1.0.2", 257 | "escape-html": "1.0.3", 258 | "on-finished": "2.3.0", 259 | "parseurl": "1.3.2", 260 | "statuses": "1.4.0", 261 | "unpipe": "1.0.0" 262 | } 263 | }, 264 | "forever-agent": { 265 | "version": "0.6.1", 266 | "resolved": "https://registry.npmjs.org/forever-agent/-/forever-agent-0.6.1.tgz", 267 | "integrity": "sha1-+8cfDEGt6zf5bFd60e1C2P2sypE=" 268 | }, 269 | "form-data": { 270 | "version": "2.3.3", 271 | "resolved": "https://registry.npmjs.org/form-data/-/form-data-2.3.3.tgz", 272 | "integrity": "sha512-1lLKB2Mu3aGP1Q/2eCOx0fNbRMe7XdwktwOruhfqqd0rIJWwN4Dh+E3hrPSlDCXnSR7UtZ1N38rVXm+6+MEhJQ==", 273 | "requires": { 274 | "asynckit": "0.4.0", 275 | "combined-stream": "1.0.7", 276 | "mime-types": "2.1.22" 277 | } 278 | }, 279 | "forwarded": { 280 | "version": "0.1.2", 281 | "resolved": "https://registry.npmjs.org/forwarded/-/forwarded-0.1.2.tgz", 282 | "integrity": "sha1-mMI9qxF1ZXuMBXPozszZGw/xjIQ=" 283 | }, 284 | "fresh": { 285 | "version": "0.5.2", 286 | "resolved": "https://registry.npmjs.org/fresh/-/fresh-0.5.2.tgz", 287 | "integrity": "sha1-PYyt2Q2XZWn6g1qx+OSyOhBWBac=" 288 | }, 289 | "getpass": { 290 | "version": "0.1.7", 291 | "resolved": "https://registry.npmjs.org/getpass/-/getpass-0.1.7.tgz", 292 | "integrity": "sha1-Xv+OPmhNVprkyysSgmBOi6YhSfo=", 293 | "requires": { 294 | "assert-plus": "1.0.0" 295 | } 296 | }, 297 | "har-schema": { 298 | "version": "2.0.0", 299 | "resolved": "https://registry.npmjs.org/har-schema/-/har-schema-2.0.0.tgz", 300 | "integrity": "sha1-qUwiJOvKwEeCoNkDVSHyRzW37JI=" 301 | }, 302 | "har-validator": { 303 | "version": "5.1.3", 304 | "resolved": "https://registry.npmjs.org/har-validator/-/har-validator-5.1.3.tgz", 305 | "integrity": "sha512-sNvOCzEQNr/qrvJgc3UG/kD4QtlHycrzwS+6mfTrrSq97BvaYcPZZI1ZSqGSPR73Cxn4LKTD4PttRwfU7jWq5g==", 306 | "requires": { 307 | "ajv": "6.9.1", 308 | "har-schema": "2.0.0" 309 | } 310 | }, 311 | "http-errors": { 312 | "version": "1.6.3", 313 | "resolved": "https://registry.npmjs.org/http-errors/-/http-errors-1.6.3.tgz", 314 | "integrity": "sha1-i1VoC7S+KDoLW/TqLjhYC+HZMg0=", 315 | "requires": { 316 | "depd": "1.1.2", 317 | "inherits": "2.0.3", 318 | "setprototypeof": "1.1.0", 319 | "statuses": "1.4.0" 320 | } 321 | }, 322 | "http-signature": { 323 | "version": "1.2.0", 324 | "resolved": "https://registry.npmjs.org/http-signature/-/http-signature-1.2.0.tgz", 325 | "integrity": "sha1-muzZJRFHcvPZW2WmCruPfBj7rOE=", 326 | "requires": { 327 | "assert-plus": "1.0.0", 328 | "jsprim": "1.4.1", 329 | "sshpk": "1.16.1" 330 | } 331 | }, 332 | "iconv-lite": { 333 | "version": "0.4.23", 334 | "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.23.tgz", 335 | "integrity": "sha512-neyTUVFtahjf0mB3dZT77u+8O0QB89jFdnBkd5P1JgYPbPaia3gXXOVL2fq8VyU2gMMD7SaN7QukTB/pmXYvDA==", 336 | "requires": { 337 | "safer-buffer": "2.1.2" 338 | } 339 | }, 340 | "inherits": { 341 | "version": "2.0.3", 342 | "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.3.tgz", 343 | "integrity": "sha1-Yzwsg+PaQqUC9SRmAiSA9CCCYd4=" 344 | }, 345 | "ipaddr.js": { 346 | "version": "1.8.0", 347 | "resolved": "https://registry.npmjs.org/ipaddr.js/-/ipaddr.js-1.8.0.tgz", 348 | "integrity": "sha1-6qM9bd16zo9/b+DJygRA5wZzix4=" 349 | }, 350 | "is-typedarray": { 351 | "version": "1.0.0", 352 | "resolved": "https://registry.npmjs.org/is-typedarray/-/is-typedarray-1.0.0.tgz", 353 | "integrity": "sha1-5HnICFjfDBsR3dppQPlgEfzaSpo=" 354 | }, 355 | "isstream": { 356 | "version": "0.1.2", 357 | "resolved": "https://registry.npmjs.org/isstream/-/isstream-0.1.2.tgz", 358 | "integrity": "sha1-R+Y/evVa+m+S4VAOaQ64uFKcCZo=" 359 | }, 360 | "jsbn": { 361 | "version": "0.1.1", 362 | "resolved": "https://registry.npmjs.org/jsbn/-/jsbn-0.1.1.tgz", 363 | "integrity": "sha1-peZUwuWi3rXyAdls77yoDA7y9RM=" 364 | }, 365 | "json-schema": { 366 | "version": "0.2.3", 367 | "resolved": "https://registry.npmjs.org/json-schema/-/json-schema-0.2.3.tgz", 368 | "integrity": "sha1-tIDIkuWaLwWVTOcnvT8qTogvnhM=" 369 | }, 370 | "json-schema-traverse": { 371 | "version": "0.4.1", 372 | "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz", 373 | "integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==" 374 | }, 375 | "json-stringify-safe": { 376 | "version": "5.0.1", 377 | "resolved": "https://registry.npmjs.org/json-stringify-safe/-/json-stringify-safe-5.0.1.tgz", 378 | "integrity": "sha1-Epai1Y/UXxmg9s4B1lcB4sc1tus=" 379 | }, 380 | "jsprim": { 381 | "version": "1.4.1", 382 | "resolved": "https://registry.npmjs.org/jsprim/-/jsprim-1.4.1.tgz", 383 | "integrity": "sha1-MT5mvB5cwG5Di8G3SZwuXFastqI=", 384 | "requires": { 385 | "assert-plus": "1.0.0", 386 | "extsprintf": "1.3.0", 387 | "json-schema": "0.2.3", 388 | "verror": "1.10.0" 389 | } 390 | }, 391 | "media-typer": { 392 | "version": "0.3.0", 393 | "resolved": "https://registry.npmjs.org/media-typer/-/media-typer-0.3.0.tgz", 394 | "integrity": "sha1-hxDXrwqmJvj/+hzgAWhUUmMlV0g=" 395 | }, 396 | "merge-descriptors": { 397 | "version": "1.0.1", 398 | "resolved": "https://registry.npmjs.org/merge-descriptors/-/merge-descriptors-1.0.1.tgz", 399 | "integrity": "sha1-sAqqVW3YtEVoFQ7J0blT8/kMu2E=" 400 | }, 401 | "methods": { 402 | "version": "1.1.2", 403 | "resolved": "https://registry.npmjs.org/methods/-/methods-1.1.2.tgz", 404 | "integrity": "sha1-VSmk1nZUE07cxSZmVoNbD4Ua/O4=" 405 | }, 406 | "mime": { 407 | "version": "1.4.1", 408 | "resolved": "https://registry.npmjs.org/mime/-/mime-1.4.1.tgz", 409 | "integrity": "sha512-KI1+qOZu5DcW6wayYHSzR/tXKCDC5Om4s1z2QJjDULzLcmf3DvzS7oluY4HCTrc+9FiKmWUgeNLg7W3uIQvxtQ==" 410 | }, 411 | "mime-db": { 412 | "version": "1.38.0", 413 | "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.38.0.tgz", 414 | "integrity": "sha512-bqVioMFFzc2awcdJZIzR3HjZFX20QhilVS7hytkKrv7xFAn8bM1gzc/FOX2awLISvWe0PV8ptFKcon+wZ5qYkg==" 415 | }, 416 | "mime-types": { 417 | "version": "2.1.22", 418 | "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.22.tgz", 419 | "integrity": "sha512-aGl6TZGnhm/li6F7yx82bJiBZwgiEa4Hf6CNr8YO+r5UHr53tSTYZb102zyU50DOWWKeOv0uQLRL0/9EiKWCog==", 420 | "requires": { 421 | "mime-db": "1.38.0" 422 | } 423 | }, 424 | "ms": { 425 | "version": "2.0.0", 426 | "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", 427 | "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=" 428 | }, 429 | "negotiator": { 430 | "version": "0.6.1", 431 | "resolved": "https://registry.npmjs.org/negotiator/-/negotiator-0.6.1.tgz", 432 | "integrity": "sha1-KzJxhOiZIQEXeyhWP7XnECrNDKk=" 433 | }, 434 | "oauth-sign": { 435 | "version": "0.9.0", 436 | "resolved": "https://registry.npmjs.org/oauth-sign/-/oauth-sign-0.9.0.tgz", 437 | "integrity": "sha512-fexhUFFPTGV8ybAtSIGbV6gOkSv8UtRbDBnAyLQw4QPKkgNlsH2ByPGtMUqdWkos6YCRmAqViwgZrJc/mRDzZQ==" 438 | }, 439 | "on-finished": { 440 | "version": "2.3.0", 441 | "resolved": "https://registry.npmjs.org/on-finished/-/on-finished-2.3.0.tgz", 442 | "integrity": "sha1-IPEzZIGwg811M3mSoWlxqi2QaUc=", 443 | "requires": { 444 | "ee-first": "1.1.1" 445 | } 446 | }, 447 | "parseurl": { 448 | "version": "1.3.2", 449 | "resolved": "https://registry.npmjs.org/parseurl/-/parseurl-1.3.2.tgz", 450 | "integrity": "sha1-/CidTtiZMRlGDBViUyYs3I3mW/M=" 451 | }, 452 | "path": { 453 | "version": "0.12.7", 454 | "resolved": "https://registry.npmjs.org/path/-/path-0.12.7.tgz", 455 | "integrity": "sha1-1NwqUGxM4hl+tIHr/NWzbAFAsQ8=", 456 | "requires": { 457 | "process": "0.11.10", 458 | "util": "0.10.4" 459 | } 460 | }, 461 | "path-to-regexp": { 462 | "version": "0.1.7", 463 | "resolved": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-0.1.7.tgz", 464 | "integrity": "sha1-32BBeABfUi8V60SQ5yR6G/qmf4w=" 465 | }, 466 | "performance-now": { 467 | "version": "2.1.0", 468 | "resolved": "https://registry.npmjs.org/performance-now/-/performance-now-2.1.0.tgz", 469 | "integrity": "sha1-Ywn04OX6kT7BxpMHrjZLSzd8nns=" 470 | }, 471 | "process": { 472 | "version": "0.11.10", 473 | "resolved": "https://registry.npmjs.org/process/-/process-0.11.10.tgz", 474 | "integrity": "sha1-czIwDoQBYb2j5podHZGn1LwW8YI=" 475 | }, 476 | "proxy-addr": { 477 | "version": "2.0.4", 478 | "resolved": "https://registry.npmjs.org/proxy-addr/-/proxy-addr-2.0.4.tgz", 479 | "integrity": "sha512-5erio2h9jp5CHGwcybmxmVqHmnCBZeewlfJ0pex+UW7Qny7OOZXTtH56TGNyBizkgiOwhJtMKrVzDTeKcySZwA==", 480 | "requires": { 481 | "forwarded": "0.1.2", 482 | "ipaddr.js": "1.8.0" 483 | } 484 | }, 485 | "psl": { 486 | "version": "1.1.31", 487 | "resolved": "https://registry.npmjs.org/psl/-/psl-1.1.31.tgz", 488 | "integrity": "sha512-/6pt4+C+T+wZUieKR620OpzN/LlnNKuWjy1iFLQ/UG35JqHlR/89MP1d96dUfkf6Dne3TuLQzOYEYshJ+Hx8mw==" 489 | }, 490 | "punycode": { 491 | "version": "2.1.1", 492 | "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.1.1.tgz", 493 | "integrity": "sha512-XRsRjdf+j5ml+y/6GKHPZbrF/8p2Yga0JPtdqTIY2Xe5ohJPD9saDJJLPvp9+NSBprVvevdXZybnj2cv8OEd0A==" 494 | }, 495 | "qs": { 496 | "version": "6.5.2", 497 | "resolved": "https://registry.npmjs.org/qs/-/qs-6.5.2.tgz", 498 | "integrity": "sha512-N5ZAX4/LxJmF+7wN74pUD6qAh9/wnvdQcjq9TZjevvXzSUo7bfmw91saqMjzGS2xq91/odN2dW/WOl7qQHNDGA==" 499 | }, 500 | "range-parser": { 501 | "version": "1.2.0", 502 | "resolved": "https://registry.npmjs.org/range-parser/-/range-parser-1.2.0.tgz", 503 | "integrity": "sha1-9JvmtIeJTdxA3MlKMi9hEJLgDV4=" 504 | }, 505 | "raw-body": { 506 | "version": "2.3.3", 507 | "resolved": "https://registry.npmjs.org/raw-body/-/raw-body-2.3.3.tgz", 508 | "integrity": "sha512-9esiElv1BrZoI3rCDuOuKCBRbuApGGaDPQfjSflGxdy4oyzqghxu6klEkkVIvBje+FF0BX9coEv8KqW6X/7njw==", 509 | "requires": { 510 | "bytes": "3.0.0", 511 | "http-errors": "1.6.3", 512 | "iconv-lite": "0.4.23", 513 | "unpipe": "1.0.0" 514 | } 515 | }, 516 | "request": { 517 | "version": "2.88.0", 518 | "resolved": "https://registry.npmjs.org/request/-/request-2.88.0.tgz", 519 | "integrity": "sha512-NAqBSrijGLZdM0WZNsInLJpkJokL72XYjUpnB0iwsRgxh7dB6COrHnTBNwN0E+lHDAJzu7kLAkDeY08z2/A0hg==", 520 | "requires": { 521 | "aws-sign2": "0.7.0", 522 | "aws4": "1.8.0", 523 | "caseless": "0.12.0", 524 | "combined-stream": "1.0.7", 525 | "extend": "3.0.2", 526 | "forever-agent": "0.6.1", 527 | "form-data": "2.3.3", 528 | "har-validator": "5.1.3", 529 | "http-signature": "1.2.0", 530 | "is-typedarray": "1.0.0", 531 | "isstream": "0.1.2", 532 | "json-stringify-safe": "5.0.1", 533 | "mime-types": "2.1.22", 534 | "oauth-sign": "0.9.0", 535 | "performance-now": "2.1.0", 536 | "qs": "6.5.2", 537 | "safe-buffer": "5.1.2", 538 | "tough-cookie": "2.4.3", 539 | "tunnel-agent": "0.6.0", 540 | "uuid": "3.3.2" 541 | } 542 | }, 543 | "safe-buffer": { 544 | "version": "5.1.2", 545 | "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", 546 | "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==" 547 | }, 548 | "safer-buffer": { 549 | "version": "2.1.2", 550 | "resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz", 551 | "integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==" 552 | }, 553 | "send": { 554 | "version": "0.16.2", 555 | "resolved": "https://registry.npmjs.org/send/-/send-0.16.2.tgz", 556 | "integrity": "sha512-E64YFPUssFHEFBvpbbjr44NCLtI1AohxQ8ZSiJjQLskAdKuriYEP6VyGEsRDH8ScozGpkaX1BGvhanqCwkcEZw==", 557 | "requires": { 558 | "debug": "2.6.9", 559 | "depd": "1.1.2", 560 | "destroy": "1.0.4", 561 | "encodeurl": "1.0.2", 562 | "escape-html": "1.0.3", 563 | "etag": "1.8.1", 564 | "fresh": "0.5.2", 565 | "http-errors": "1.6.3", 566 | "mime": "1.4.1", 567 | "ms": "2.0.0", 568 | "on-finished": "2.3.0", 569 | "range-parser": "1.2.0", 570 | "statuses": "1.4.0" 571 | } 572 | }, 573 | "serve-static": { 574 | "version": "1.13.2", 575 | "resolved": "https://registry.npmjs.org/serve-static/-/serve-static-1.13.2.tgz", 576 | "integrity": "sha512-p/tdJrO4U387R9oMjb1oj7qSMaMfmOyd4j9hOFoxZe2baQszgHcSWjuya/CiT5kgZZKRudHNOA0pYXOl8rQ5nw==", 577 | "requires": { 578 | "encodeurl": "1.0.2", 579 | "escape-html": "1.0.3", 580 | "parseurl": "1.3.2", 581 | "send": "0.16.2" 582 | } 583 | }, 584 | "setprototypeof": { 585 | "version": "1.1.0", 586 | "resolved": "https://registry.npmjs.org/setprototypeof/-/setprototypeof-1.1.0.tgz", 587 | "integrity": "sha512-BvE/TwpZX4FXExxOxZyRGQQv651MSwmWKZGqvmPcRIjDqWub67kTKuIMx43cZZrS/cBBzwBcNDWoFxt2XEFIpQ==" 588 | }, 589 | "sshpk": { 590 | "version": "1.16.1", 591 | "resolved": "https://registry.npmjs.org/sshpk/-/sshpk-1.16.1.tgz", 592 | "integrity": "sha512-HXXqVUq7+pcKeLqqZj6mHFUMvXtOJt1uoUx09pFW6011inTMxqI8BA8PM95myrIyyKwdnzjdFjLiE6KBPVtJIg==", 593 | "requires": { 594 | "asn1": "0.2.4", 595 | "assert-plus": "1.0.0", 596 | "bcrypt-pbkdf": "1.0.2", 597 | "dashdash": "1.14.1", 598 | "ecc-jsbn": "0.1.2", 599 | "getpass": "0.1.7", 600 | "jsbn": "0.1.1", 601 | "safer-buffer": "2.1.2", 602 | "tweetnacl": "0.14.5" 603 | } 604 | }, 605 | "statuses": { 606 | "version": "1.4.0", 607 | "resolved": "https://registry.npmjs.org/statuses/-/statuses-1.4.0.tgz", 608 | "integrity": "sha512-zhSCtt8v2NDrRlPQpCNtw/heZLtfUDqxBM1udqikb/Hbk52LK4nQSwr10u77iopCW5LsyHpuXS0GnEc48mLeew==" 609 | }, 610 | "tough-cookie": { 611 | "version": "2.4.3", 612 | "resolved": "https://registry.npmjs.org/tough-cookie/-/tough-cookie-2.4.3.tgz", 613 | "integrity": "sha512-Q5srk/4vDM54WJsJio3XNn6K2sCG+CQ8G5Wz6bZhRZoAe/+TxjWB/GlFAnYEbkYVlON9FMk/fE3h2RLpPXo4lQ==", 614 | "requires": { 615 | "psl": "1.1.31", 616 | "punycode": "1.4.1" 617 | }, 618 | "dependencies": { 619 | "punycode": { 620 | "version": "1.4.1", 621 | "resolved": "https://registry.npmjs.org/punycode/-/punycode-1.4.1.tgz", 622 | "integrity": "sha1-wNWmOycYgArY4esPpSachN1BhF4=" 623 | } 624 | } 625 | }, 626 | "tunnel-agent": { 627 | "version": "0.6.0", 628 | "resolved": "https://registry.npmjs.org/tunnel-agent/-/tunnel-agent-0.6.0.tgz", 629 | "integrity": "sha1-J6XeoGs2sEoKmWZ3SykIaPD8QP0=", 630 | "requires": { 631 | "safe-buffer": "5.1.2" 632 | } 633 | }, 634 | "tweetnacl": { 635 | "version": "0.14.5", 636 | "resolved": "https://registry.npmjs.org/tweetnacl/-/tweetnacl-0.14.5.tgz", 637 | "integrity": "sha1-WuaBd/GS1EViadEIr6k/+HQ/T2Q=" 638 | }, 639 | "twit": { 640 | "version": "2.2.11", 641 | "resolved": "https://registry.npmjs.org/twit/-/twit-2.2.11.tgz", 642 | "integrity": "sha512-BkdwvZGRVoUTcEBp0zuocuqfih4LB+kEFUWkWJOVBg6pAE9Ebv9vmsYTTrfXleZGf45Bj5H3A1/O9YhF2uSYNg==", 643 | "requires": { 644 | "bluebird": "3.5.3", 645 | "mime": "1.4.1", 646 | "request": "2.88.0" 647 | } 648 | }, 649 | "type-is": { 650 | "version": "1.6.16", 651 | "resolved": "https://registry.npmjs.org/type-is/-/type-is-1.6.16.tgz", 652 | "integrity": "sha512-HRkVv/5qY2G6I8iab9cI7v1bOIdhm94dVjQCPFElW9W+3GeDOSHmy2EBYe4VTApuzolPcmgFTN3ftVJRKR2J9Q==", 653 | "requires": { 654 | "media-typer": "0.3.0", 655 | "mime-types": "2.1.22" 656 | } 657 | }, 658 | "unpipe": { 659 | "version": "1.0.0", 660 | "resolved": "https://registry.npmjs.org/unpipe/-/unpipe-1.0.0.tgz", 661 | "integrity": "sha1-sr9O6FFKrmFltIF4KdIbLvSZBOw=" 662 | }, 663 | "uri-js": { 664 | "version": "4.2.2", 665 | "resolved": "https://registry.npmjs.org/uri-js/-/uri-js-4.2.2.tgz", 666 | "integrity": "sha512-KY9Frmirql91X2Qgjry0Wd4Y+YTdrdZheS8TFwvkbLWf/G5KNJDCh6pKL5OZctEW4+0Baa5idK2ZQuELRwPznQ==", 667 | "requires": { 668 | "punycode": "2.1.1" 669 | } 670 | }, 671 | "util": { 672 | "version": "0.10.4", 673 | "resolved": "https://registry.npmjs.org/util/-/util-0.10.4.tgz", 674 | "integrity": "sha512-0Pm9hTQ3se5ll1XihRic3FDIku70C+iHUdT/W926rSgHV5QgXsYbKZN8MSC3tJtSkhuROzvsQjAaFENRXr+19A==", 675 | "requires": { 676 | "inherits": "2.0.3" 677 | } 678 | }, 679 | "utils-merge": { 680 | "version": "1.0.1", 681 | "resolved": "https://registry.npmjs.org/utils-merge/-/utils-merge-1.0.1.tgz", 682 | "integrity": "sha1-n5VxD1CiZ5R7LMwSR0HBAoQn5xM=" 683 | }, 684 | "uuid": { 685 | "version": "3.3.2", 686 | "resolved": "https://registry.npmjs.org/uuid/-/uuid-3.3.2.tgz", 687 | "integrity": "sha512-yXJmeNaw3DnnKAOKJE51sL/ZaYfWJRl1pK9dr19YFCu0ObS231AB1/LbqTKRAQ5kw8A90rA6fr4riOUpTZvQZA==" 688 | }, 689 | "vary": { 690 | "version": "1.1.2", 691 | "resolved": "https://registry.npmjs.org/vary/-/vary-1.1.2.tgz", 692 | "integrity": "sha1-IpnwLG3tMNSllhsLn3RSShj2NPw=" 693 | }, 694 | "verror": { 695 | "version": "1.10.0", 696 | "resolved": "https://registry.npmjs.org/verror/-/verror-1.10.0.tgz", 697 | "integrity": "sha1-OhBcoXBTr1XW4nDB+CiGguGNpAA=", 698 | "requires": { 699 | "assert-plus": "1.0.0", 700 | "core-util-is": "1.0.2", 701 | "extsprintf": "1.3.0" 702 | } 703 | } 704 | } 705 | } 706 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "botsofcode", 3 | "version": "1.0.1", 4 | "description": "A bot for bitsofco.de", 5 | "main": "index.js", 6 | "scripts": { 7 | "start": "node index.js" 8 | }, 9 | "author": "ire-aderinokun", 10 | "dependencies": { 11 | "express": "^4.14.0", 12 | "path": "^0.12.7", 13 | "twit": "^2.2.4" 14 | }, 15 | "engines": { 16 | "node": "4.1.1" 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /views/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | botsofcode 6 | 7 | 8 | 46 | 47 | 48 | 49 |
50 |
51 |

botsofcode

52 |
53 | 54 | Go to botsofcode on twitter 55 | 56 |

I'm a Twitter bot for @IreAderinokun's blog, bitsofco.de. You can view my source code, 57 | follow me, or read the blog.

58 |
59 | 60 | 61 | --------------------------------------------------------------------------------