├── .eslintrc.json ├── .gitignore ├── README.md ├── app.js ├── censored-phrases.json ├── keys-example.json ├── lib ├── censor.js ├── get-reply-text.js ├── get-tweet.js ├── read-alt-text.js └── send-tweet.js ├── package-lock.json ├── package.json ├── test-tweets.json └── test ├── censor.js └── get-reply-text.js /.eslintrc.json: -------------------------------------------------------------------------------- 1 | { 2 | "env": { 3 | "browser": true, 4 | "commonjs": true, 5 | "es2021": true 6 | }, 7 | "extends": [ 8 | "plugin:node/recommended", 9 | "eslint:recommended" 10 | ], 11 | "rules": { 12 | // allow import/require of local, unpublished modules 13 | "node/no-unpublished-require": "off" 14 | }, 15 | "parserOptions": { 16 | "ecmaVersion": "latest" 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | keys.json 2 | *.swp 3 | .DS_Store 4 | node_modules 5 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | @get_altText is a twitter bot that tweets image descriptions when mentioned in a tweet or a reply to a tweet containing media. 2 | For more information, see twitter.com/get_altText 3 | -------------------------------------------------------------------------------- /app.js: -------------------------------------------------------------------------------- 1 | const TwitterP = require('twitter') 2 | const keys = require('./keys') 3 | const sendTweet = require('./lib/send-tweet') 4 | const getReplyText = require('./lib/get-reply-text') 5 | const getTweet = require('./lib/get-tweet') 6 | 7 | const Twitter = new TwitterP(keys) 8 | 9 | Twitter.stream('statuses/filter', { track: '@get_altText' }, function (stream) { 10 | stream.on('data', (brokenTweet) => { 11 | const mentioningTweetId = brokenTweet.id_str 12 | const mentioningUsername = brokenTweet.user.screen_name 13 | 14 | getTweet(mentioningTweetId) 15 | .then(getReplyText) 16 | .then((reply) => { 17 | if (reply && reply.length > 0) { 18 | sendTweet(reply, mentioningTweetId, mentioningUsername) 19 | } 20 | }) 21 | .catch((err) => console.error(err)) 22 | 23 | stream.on('error', (err) => { 24 | console.log(err) 25 | }) 26 | }) 27 | 28 | stream.on('error', (err) => { 29 | console.log(err) 30 | }) 31 | }) 32 | -------------------------------------------------------------------------------- /censored-phrases.json: -------------------------------------------------------------------------------- 1 | ["kill", "die", "rape"] 2 | -------------------------------------------------------------------------------- /keys-example.json: -------------------------------------------------------------------------------- 1 | { 2 | "consumer_key": "CONSUMER_KEY", 3 | "consumer_secret": "CONSUMER_SECRET", 4 | "access_token_key": "ACCESS_TOKEN_KEY", 5 | "access_token_secret": "ACCESS_TOKEN_SECRET" 6 | } -------------------------------------------------------------------------------- /lib/censor.js: -------------------------------------------------------------------------------- 1 | const censoredPhrases = require('../censored-phrases.json') 2 | 3 | module.exports = (text) => { 4 | let isCensored = false 5 | 6 | censoredPhrases.forEach((phrase) => { 7 | const regex = new RegExp(`\\b${phrase}\\b`, 'g') 8 | const censoredVersion = phrase.replace(/a|e|i|o|u/, '*') 9 | 10 | if (!isCensored) { 11 | isCensored = regex.test(text) 12 | } 13 | 14 | text = text.replace(regex, censoredVersion) 15 | }) 16 | 17 | if (isCensored) { 18 | text += 19 | "\n\n(Note from the bot: I had to censor a part of the description to avoid suspension from twitter, I'm sorry.)" 20 | } 21 | 22 | return text 23 | } 24 | -------------------------------------------------------------------------------- /lib/get-reply-text.js: -------------------------------------------------------------------------------- 1 | const getTweet = require('./get-tweet') 2 | const readAltText = require('./read-alt-text') 3 | 4 | module.exports = async (tweet) => { 5 | const mentioningTweetId = tweet.id_str 6 | const mentioningUsername = tweet.user.screen_name 7 | 8 | let content = `@${mentioningUsername} ` 9 | 10 | try { 11 | if (!tweet) { 12 | console.log('🚨This should not happen🚨') 13 | throw 'No tweet found' 14 | } 15 | 16 | // do not reply to retweets 17 | if (typeof tweet.retweeted_status !== 'undefined') { 18 | return 19 | } 20 | 21 | let originalTweetId = tweet.in_reply_to_status_id_str 22 | let originalUsername = tweet.in_reply_to_screen_name 23 | 24 | // ppl posting the pic and triggering the bot within the same tweet 25 | if (originalTweetId == null) { 26 | originalTweetId = mentioningTweetId 27 | originalUsername = mentioningUsername 28 | } 29 | 30 | // pls no loops of death! 31 | if (mentioningUsername == 'get_altText') { 32 | return 33 | } 34 | 35 | const originalTweet = await getTweet(originalTweetId) 36 | 37 | // media in the original tweet 38 | if ( 39 | originalTweet.extended_entities && 40 | originalTweet.extended_entities.media 41 | ) { 42 | content += readAltText(originalTweet, originalUsername) 43 | return content 44 | } 45 | 46 | // media in the triggering tweet 47 | if (tweet.extended_entities && tweet.extended_entities.media) { 48 | content += readAltText(tweet, mentioningUsername) 49 | return content 50 | } 51 | 52 | // in the quoted tweet? 53 | if (tweet.is_quote_status) { 54 | const quotedTweet = await getTweet(tweet.quoted_status_id_str) 55 | // media in the quoted tweet 56 | if ( 57 | quotedTweet.extended_entities && 58 | quotedTweet.extended_entities.media 59 | ) { 60 | content += readAltText(quotedTweet, quotedTweet.user.screen_name) 61 | return content 62 | } else { 63 | // no media in quoted tweet => no tweet 64 | return 65 | } 66 | } 67 | 68 | return 69 | } catch (err) { 70 | console.log(JSON.stringify(err)) 71 | if (err.length === 1) { 72 | return content + err[0].message.replace('you are', 'I am') 73 | } else { 74 | return ( 75 | content + 76 | 'There has been an error while trying to read the alt text, please try again later – @malfynnction, you should probably look into this!' 77 | ) 78 | } 79 | } 80 | } 81 | -------------------------------------------------------------------------------- /lib/get-tweet.js: -------------------------------------------------------------------------------- 1 | const TwitterP = require('twitter') 2 | const keys = require('../keys') 3 | 4 | const Twitter = new TwitterP(keys) 5 | 6 | module.exports = async (id) => { 7 | return Twitter.get('statuses/show', { 8 | id: id, 9 | include_ext_alt_text: 'true', 10 | tweet_mode: 'extended', 11 | }) 12 | } 13 | -------------------------------------------------------------------------------- /lib/read-alt-text.js: -------------------------------------------------------------------------------- 1 | const censor = require('./censor') 2 | 3 | const altForMedium = (medium) => 4 | medium.ext_alt_text === null 5 | ? "There is no alt text for this image, I'm sorry." 6 | : censor(medium.ext_alt_text) 7 | 8 | module.exports = (tweet) => { 9 | const media = tweet.extended_entities.media 10 | 11 | // unfortunately, it is impossible to add alt texts to videos 12 | const supportedMediaTypes = ['photo', 'animated_gif'] 13 | const mediaType = media[0].type 14 | 15 | if (!supportedMediaTypes.includes(mediaType)) { 16 | return `This is a ${mediaType}. Unfortunately, twitter doesn't allow to add alt texts for ${mediaType}s yet.` 17 | } else if (media.length === 1) { 18 | return altForMedium(media[0]) 19 | } else { 20 | return media.reduce( 21 | (alt, medium, i) => alt + `${i + 1}. Picture: ${altForMedium(medium)}\n`, 22 | '' 23 | ) 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /lib/send-tweet.js: -------------------------------------------------------------------------------- 1 | const TwitterP = require('twitter') 2 | const keys = require('../keys') 3 | 4 | const Twitter = new TwitterP(keys) 5 | 6 | const tweetThis = (content, inReplyToTweetId, mentioningUsername) => { 7 | if (content.length <= 280) { 8 | const reply = { status: content, in_reply_to_status_id: inReplyToTweetId } 9 | Twitter.post('statuses/update', reply, (err) => { 10 | if (err) { 11 | console.log(err) 12 | } 13 | }) 14 | } else { 15 | const contentWords = content.split(' ') 16 | let part = '' 17 | 18 | while ( 19 | contentWords.length > 0 && 20 | part.length + contentWords[0].length <= 279 21 | ) { 22 | part += contentWords[0] + ' ' 23 | contentWords.splice(0, 1) 24 | } 25 | 26 | const reply = { status: part, in_reply_to_status_id: inReplyToTweetId } 27 | Twitter.post('statuses/update', reply, function (err, tweet) { 28 | if (err) { 29 | console.log(err) 30 | } else { 31 | tweetThis( 32 | `@${mentioningUsername} ${contentWords.join(' ')}`, 33 | tweet.id_str, 34 | mentioningUsername 35 | ) 36 | } 37 | }) 38 | } 39 | } 40 | 41 | module.exports = tweetThis 42 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "get_alttext", 3 | "version": "1.0.0", 4 | "description": "", 5 | "main": "app.js", 6 | "dependencies": { 7 | "twitter": "^1.7.1" 8 | }, 9 | "devDependencies": { 10 | "ava": "^3.12.1", 11 | "eslint": "^8.9.0", 12 | "eslint-plugin-node": "^11.1.0" 13 | }, 14 | "scripts": { 15 | "test": "ava", 16 | "lint": "eslint '*.js'" 17 | }, 18 | "repository": { 19 | "type": "git", 20 | "url": "git+https://github.com/malfynnction/AltText-Tweeter.git" 21 | }, 22 | "author": "", 23 | "license": "ISC", 24 | "bugs": { 25 | "url": "https://github.com/malfynnction/AltText-Tweeter/issues" 26 | }, 27 | "homepage": "https://github.com/malfynnction/AltText-Tweeter#readme", 28 | "ava": { 29 | "files": [ 30 | "test/**/*" 31 | ] 32 | } 33 | } 34 | -------------------------------------------------------------------------------- /test-tweets.json: -------------------------------------------------------------------------------- 1 | { 2 | "1": { 3 | "created_at": "Wed Sep 12 15:57:03 +0000 2018", 4 | "id": 1039905741245689900, 5 | "id_str": "1039905741245689857", 6 | "full_text": "@get_altText", 7 | "truncated": false, 8 | "display_text_range": [0, 12], 9 | "entities": { 10 | "hashtags": [], 11 | "symbols": [], 12 | "user_mentions": [ 13 | { 14 | "screen_name": "get_altText", 15 | "name": "Alt Text Reader", 16 | "id": 968802481856794600, 17 | "id_str": "968802481856794624", 18 | "indices": [0, 12] 19 | } 20 | ], 21 | "urls": [] 22 | }, 23 | "source": "Twitter for iPhone", 24 | "in_reply_to_status_id": 1039905540514701300, 25 | "in_reply_to_status_id_str": "1039905540514701312", 26 | "in_reply_to_user_id": 2977720848, 27 | "in_reply_to_user_id_str": "2977720848", 28 | "in_reply_to_screen_name": "SnoringDoggo", 29 | "user": { 30 | "id": 2977720848, 31 | "id_str": "2977720848", 32 | "name": "Noor (He) 💗☪️♿️", 33 | "screen_name": "SnoringDoggo", 34 | "location": "npervez@autisticadvocacy.org", 35 | "description": "Community Engagement Coordinator for ASAN, Accessibility Director @masjidalrabia, board @transstudent, MyLC @AdvocatesTweets, PLEASE LET ME PAT YOUR🐕", 36 | "url": "https://t.co/rxAM9J4tcI", 37 | "entities": { 38 | "url": { 39 | "urls": [ 40 | { 41 | "url": "https://t.co/rxAM9J4tcI", 42 | "expanded_url": "https://paypal.me/NPervez", 43 | "display_url": "paypal.me/NPervez", 44 | "indices": [0, 23] 45 | } 46 | ] 47 | }, 48 | "description": { "urls": [] } 49 | }, 50 | "protected": false, 51 | "followers_count": 1576, 52 | "friends_count": 705, 53 | "listed_count": 24, 54 | "created_at": "Mon Jan 12 22:09:30 +0000 2015", 55 | "favourites_count": 30355, 56 | "utc_offset": null, 57 | "time_zone": null, 58 | "geo_enabled": false, 59 | "verified": false, 60 | "statuses_count": 23681, 61 | "lang": "en", 62 | "contributors_enabled": false, 63 | "is_translator": false, 64 | "is_translation_enabled": false, 65 | "profile_background_color": "000000", 66 | "profile_background_image_url": "http://abs.twimg.com/images/themes/theme1/bg.png", 67 | "profile_background_image_url_https": "https://abs.twimg.com/images/themes/theme1/bg.png", 68 | "profile_background_tile": false, 69 | "profile_image_url": "http://pbs.twimg.com/profile_images/1089685874256826368/RdzHOlj5_normal.jpg", 70 | "profile_image_url_https": "https://pbs.twimg.com/profile_images/1089685874256826368/RdzHOlj5_normal.jpg", 71 | "profile_banner_url": "https://pbs.twimg.com/profile_banners/2977720848/1546564383", 72 | "profile_image_extensions_alt_text": null, 73 | "profile_banner_extensions_alt_text": null, 74 | "profile_link_color": "19CF86", 75 | "profile_sidebar_border_color": "000000", 76 | "profile_sidebar_fill_color": "000000", 77 | "profile_text_color": "000000", 78 | "profile_use_background_image": false, 79 | "has_extended_profile": true, 80 | "default_profile": false, 81 | "default_profile_image": false, 82 | "following": false, 83 | "follow_request_sent": false, 84 | "notifications": false, 85 | "translator_type": "none" 86 | }, 87 | "geo": null, 88 | "coordinates": null, 89 | "place": null, 90 | "contributors": null, 91 | "is_quote_status": false, 92 | "retweet_count": 0, 93 | "favorite_count": 0, 94 | "favorited": false, 95 | "retweeted": false, 96 | "lang": "und" 97 | }, 98 | "2": { 99 | "created_at": "Sat Mar 02 22:34:38 +0000 2019", 100 | "id": 1101974120009556000, 101 | "id_str": "1101974120009555980", 102 | "full_text": "@IAStartingLine @get_altText", 103 | "truncated": false, 104 | "display_text_range": [16, 28], 105 | "entities": { 106 | "hashtags": [], 107 | "symbols": [], 108 | "user_mentions": [ 109 | { 110 | "screen_name": "IAStartingLine", 111 | "name": "Iowa Starting Line", 112 | "id": 2940964728, 113 | "id_str": "2940964728", 114 | "indices": [0, 15] 115 | }, 116 | { 117 | "screen_name": "get_altText", 118 | "name": "Alt Text Reader", 119 | "id": 968802481856794600, 120 | "id_str": "968802481856794624", 121 | "indices": [16, 28] 122 | } 123 | ], 124 | "urls": [] 125 | }, 126 | "source": "Twitter for iPhone", 127 | "in_reply_to_status_id": 1101921103289741300, 128 | "in_reply_to_status_id_str": "1101921103289741313", 129 | "in_reply_to_user_id": 2940964728, 130 | "in_reply_to_user_id_str": "2940964728", 131 | "in_reply_to_screen_name": "IAStartingLine", 132 | "user": { 133 | "id": 3058863267, 134 | "id_str": "3058863267", 135 | "name": "Kit ♿️", 136 | "screen_name": "solitaryrainbow", 137 | "location": "United Kingdom", 138 | "description": "they/them. queer AF. disabled/autistic/ADHD. wheelchair liberated. parent of three small humans and many cats. rapidly collecting tattoos.", 139 | "url": null, 140 | "entities": { "description": { "urls": [] } }, 141 | "protected": false, 142 | "followers_count": 480, 143 | "friends_count": 915, 144 | "listed_count": 7, 145 | "created_at": "Tue Feb 24 13:11:51 +0000 2015", 146 | "favourites_count": 18772, 147 | "utc_offset": null, 148 | "time_zone": null, 149 | "geo_enabled": true, 150 | "verified": false, 151 | "statuses_count": 6053, 152 | "lang": "en", 153 | "contributors_enabled": false, 154 | "is_translator": false, 155 | "is_translation_enabled": false, 156 | "profile_background_color": "000000", 157 | "profile_background_image_url": "http://abs.twimg.com/images/themes/theme1/bg.png", 158 | "profile_background_image_url_https": "https://abs.twimg.com/images/themes/theme1/bg.png", 159 | "profile_background_tile": false, 160 | "profile_image_url": "http://pbs.twimg.com/profile_images/967836568349216769/8ujyFi8K_normal.jpg", 161 | "profile_image_url_https": "https://pbs.twimg.com/profile_images/967836568349216769/8ujyFi8K_normal.jpg", 162 | "profile_banner_url": "https://pbs.twimg.com/profile_banners/3058863267/1447185535", 163 | "profile_image_extensions_alt_text": null, 164 | "profile_banner_extensions_alt_text": null, 165 | "profile_link_color": "981CEB", 166 | "profile_sidebar_border_color": "000000", 167 | "profile_sidebar_fill_color": "000000", 168 | "profile_text_color": "000000", 169 | "profile_use_background_image": false, 170 | "has_extended_profile": false, 171 | "default_profile": false, 172 | "default_profile_image": false, 173 | "following": false, 174 | "follow_request_sent": false, 175 | "notifications": false, 176 | "translator_type": "none" 177 | }, 178 | "geo": null, 179 | "coordinates": null, 180 | "place": null, 181 | "contributors": null, 182 | "is_quote_status": false, 183 | "retweet_count": 0, 184 | "favorite_count": 0, 185 | "favorited": false, 186 | "retweeted": false, 187 | "lang": "und" 188 | }, 189 | "3": { 190 | "created_at": "Sat Sep 29 08:37:11 +0000 2018", 191 | "id": 1045955638898167800, 192 | "id_str": "1045955638898167808", 193 | "full_text": "Award-winning, Indian botanical illustrator Hemlata Pradhan #womensart https://t.co/IV7WmrdVJ8", 194 | "truncated": false, 195 | "display_text_range": [0, 70], 196 | "entities": { 197 | "hashtags": [{ "text": "womensart", "indices": [60, 70] }], 198 | "symbols": [], 199 | "user_mentions": [], 200 | "urls": [], 201 | "media": [ 202 | { 203 | "id": 1045955538390065200, 204 | "id_str": "1045955538390065153", 205 | "indices": [71, 94], 206 | "media_url": "http://pbs.twimg.com/media/DoP7BTyXoAE8U2o.jpg", 207 | "media_url_https": "https://pbs.twimg.com/media/DoP7BTyXoAE8U2o.jpg", 208 | "url": "https://t.co/IV7WmrdVJ8", 209 | "display_url": "pic.twitter.com/IV7WmrdVJ8", 210 | "expanded_url": "https://twitter.com/womensart1/status/1045955638898167808/photo/1", 211 | "type": "photo", 212 | "sizes": { 213 | "thumb": { "w": 150, "h": 150, "resize": "crop" }, 214 | "large": { "w": 787, "h": 564, "resize": "fit" }, 215 | "small": { "w": 680, "h": 487, "resize": "fit" }, 216 | "medium": { "w": 787, "h": 564, "resize": "fit" } 217 | } 218 | } 219 | ] 220 | }, 221 | "extended_entities": { 222 | "media": [ 223 | { 224 | "id": 1045955538390065200, 225 | "id_str": "1045955538390065153", 226 | "indices": [71, 94], 227 | "media_url": "http://pbs.twimg.com/media/DoP7BTyXoAE8U2o.jpg", 228 | "media_url_https": "https://pbs.twimg.com/media/DoP7BTyXoAE8U2o.jpg", 229 | "url": "https://t.co/IV7WmrdVJ8", 230 | "display_url": "pic.twitter.com/IV7WmrdVJ8", 231 | "expanded_url": "https://twitter.com/womensart1/status/1045955638898167808/photo/1", 232 | "type": "photo", 233 | "sizes": { 234 | "thumb": { "w": 150, "h": 150, "resize": "crop" }, 235 | "large": { "w": 787, "h": 564, "resize": "fit" }, 236 | "small": { "w": 680, "h": 487, "resize": "fit" }, 237 | "medium": { "w": 787, "h": 564, "resize": "fit" } 238 | }, 239 | "ext_alt_text": null 240 | } 241 | ] 242 | }, 243 | "source": "Twitter Web Client", 244 | "in_reply_to_status_id": null, 245 | "in_reply_to_status_id_str": null, 246 | "in_reply_to_user_id": null, 247 | "in_reply_to_user_id_str": null, 248 | "in_reply_to_screen_name": null, 249 | "user": { 250 | "id": 4823705386, 251 | "id_str": "4823705386", 252 | "name": "#WOMENSART", 253 | "screen_name": "womensart1", 254 | "location": "", 255 | "description": "#womensart celebrating ♀'s art and creativity, created and curated by freelance writer/reviewer @PL_Henderson1 Images are © to their respective owners", 256 | "url": "https://t.co/gDV7wWbjgm", 257 | "entities": { 258 | "url": { 259 | "urls": [ 260 | { 261 | "url": "https://t.co/gDV7wWbjgm", 262 | "expanded_url": "https://womensartblog.wordpress.com/", 263 | "display_url": "womensartblog.wordpress.com", 264 | "indices": [0, 23] 265 | } 266 | ] 267 | }, 268 | "description": { "urls": [] } 269 | }, 270 | "protected": false, 271 | "followers_count": 209749, 272 | "friends_count": 0, 273 | "listed_count": 2758, 274 | "created_at": "Mon Jan 18 10:32:28 +0000 2016", 275 | "favourites_count": 18350, 276 | "utc_offset": null, 277 | "time_zone": null, 278 | "geo_enabled": false, 279 | "verified": false, 280 | "statuses_count": 22943, 281 | "lang": "en", 282 | "contributors_enabled": false, 283 | "is_translator": false, 284 | "is_translation_enabled": false, 285 | "profile_background_color": "F5F8FA", 286 | "profile_background_image_url": null, 287 | "profile_background_image_url_https": null, 288 | "profile_background_tile": false, 289 | "profile_image_url": "http://pbs.twimg.com/profile_images/871701499335847936/jyeHvT9e_normal.jpg", 290 | "profile_image_url_https": "https://pbs.twimg.com/profile_images/871701499335847936/jyeHvT9e_normal.jpg", 291 | "profile_banner_url": "https://pbs.twimg.com/profile_banners/4823705386/1496667909", 292 | "profile_image_extensions_alt_text": null, 293 | "profile_banner_extensions_alt_text": null, 294 | "profile_link_color": "1DA1F2", 295 | "profile_sidebar_border_color": "C0DEED", 296 | "profile_sidebar_fill_color": "DDEEF6", 297 | "profile_text_color": "333333", 298 | "profile_use_background_image": true, 299 | "has_extended_profile": false, 300 | "default_profile": true, 301 | "default_profile_image": false, 302 | "following": false, 303 | "follow_request_sent": false, 304 | "notifications": false, 305 | "translator_type": "none" 306 | }, 307 | "geo": null, 308 | "coordinates": null, 309 | "place": null, 310 | "contributors": null, 311 | "is_quote_status": false, 312 | "retweet_count": 157, 313 | "favorite_count": 615, 314 | "favorited": false, 315 | "retweeted": false, 316 | "possibly_sensitive": false, 317 | "possibly_sensitive_appealable": false, 318 | "lang": "en" 319 | }, 320 | "4": { 321 | "created_at": "Fri Oct 05 20:25:32 +0000 2018", 322 | "id": 1048308227438510100, 323 | "id_str": "1048308227438510080", 324 | "full_text": "Heute abend weckt meine Timeline wieder jenes perlend funkelnde Twitfühl.* \n\nDanke euch allen! #Fuxknix\n\n#Bildbeschreibung #Bibesch #alt_text @get_altText \n\n*(Gesponserte Effekthaschereien mal ausgenommen, die sich anbiedern, als kennten sie all meine Neugierden...) https://t.co/vQtiUJYf8S", 325 | "truncated": false, 326 | "display_text_range": [0, 266], 327 | "entities": { 328 | "hashtags": [ 329 | { "text": "Fuxknix", "indices": [95, 103] }, 330 | { "text": "Bildbeschreibung", "indices": [105, 122] }, 331 | { "text": "Bibesch", "indices": [123, 131] }, 332 | { "text": "alt_text", "indices": [132, 141] } 333 | ], 334 | "symbols": [], 335 | "user_mentions": [ 336 | { 337 | "screen_name": "get_altText", 338 | "name": "Alt Text Reader", 339 | "id": 968802481856794600, 340 | "id_str": "968802481856794624", 341 | "indices": [142, 154] 342 | } 343 | ], 344 | "urls": [], 345 | "media": [ 346 | { 347 | "id": 1048305562415521800, 348 | "id_str": "1048305562415521798", 349 | "indices": [267, 290], 350 | "media_url": "http://pbs.twimg.com/media/DoxUWtfX4AYouTq.jpg", 351 | "media_url_https": "https://pbs.twimg.com/media/DoxUWtfX4AYouTq.jpg", 352 | "url": "https://t.co/vQtiUJYf8S", 353 | "display_url": "pic.twitter.com/vQtiUJYf8S", 354 | "expanded_url": "https://twitter.com/foxeen/status/1048308227438510080/photo/1", 355 | "type": "photo", 356 | "sizes": { 357 | "small": { "w": 640, "h": 480, "resize": "fit" }, 358 | "thumb": { "w": 150, "h": 150, "resize": "crop" }, 359 | "large": { "w": 640, "h": 480, "resize": "fit" }, 360 | "medium": { "w": 640, "h": 480, "resize": "fit" } 361 | } 362 | } 363 | ] 364 | }, 365 | "extended_entities": { 366 | "media": [ 367 | { 368 | "id": 1048305562415521800, 369 | "id_str": "1048305562415521798", 370 | "indices": [267, 290], 371 | "media_url": "http://pbs.twimg.com/media/DoxUWtfX4AYouTq.jpg", 372 | "media_url_https": "https://pbs.twimg.com/media/DoxUWtfX4AYouTq.jpg", 373 | "url": "https://t.co/vQtiUJYf8S", 374 | "display_url": "pic.twitter.com/vQtiUJYf8S", 375 | "expanded_url": "https://twitter.com/foxeen/status/1048308227438510080/photo/1", 376 | "type": "photo", 377 | "sizes": { 378 | "small": { "w": 640, "h": 480, "resize": "fit" }, 379 | "thumb": { "w": 150, "h": 150, "resize": "crop" }, 380 | "large": { "w": 640, "h": 480, "resize": "fit" }, 381 | "medium": { "w": 640, "h": 480, "resize": "fit" } 382 | }, 383 | "ext_alt_text": "Winzige runde Tropfen entlang den fast unsichtbaren Fäden eines Spinnennetzes in Nahaufnahme - manche sind ganz scharf, manche unscharf, aber alle zusammen wirken wie feinste Perlen-Spitze, meisterlich geklöppelt." 384 | } 385 | ] 386 | }, 387 | "source": "Twitter Web Client", 388 | "in_reply_to_status_id": null, 389 | "in_reply_to_status_id_str": null, 390 | "in_reply_to_user_id": null, 391 | "in_reply_to_user_id_str": null, 392 | "in_reply_to_screen_name": null, 393 | "user": { 394 | "id": 46904555, 395 | "id_str": "46904555", 396 | "name": "Füxin vong ab wegen *^~_~^*", 397 | "screen_name": "foxeen", 398 | "location": "Zweifel zu Werkzeugen.", 399 | "description": "Neugiertier. Gans verstohlen. #RefugeesWelcome Bilingomaniac of sorts. RT = for lack of better words. Caution: Bedenklicher Hang zum Komplizierten. #notjustsad", 400 | "url": "http://t.co/1ZFTBSq7jw", 401 | "entities": { 402 | "url": { 403 | "urls": [ 404 | { 405 | "url": "http://t.co/1ZFTBSq7jw", 406 | "expanded_url": "http://www.textgruende.wordpress.com", 407 | "display_url": "textgruende.wordpress.com", 408 | "indices": [0, 22] 409 | } 410 | ] 411 | }, 412 | "description": { "urls": [] } 413 | }, 414 | "protected": false, 415 | "followers_count": 1553, 416 | "friends_count": 776, 417 | "listed_count": 232, 418 | "created_at": "Sat Jun 13 15:31:33 +0000 2009", 419 | "favourites_count": 135314, 420 | "utc_offset": null, 421 | "time_zone": null, 422 | "geo_enabled": false, 423 | "verified": false, 424 | "statuses_count": 65998, 425 | "lang": "de", 426 | "contributors_enabled": false, 427 | "is_translator": false, 428 | "is_translation_enabled": false, 429 | "profile_background_color": "5C5C5C", 430 | "profile_background_image_url": "http://abs.twimg.com/images/themes/theme4/bg.gif", 431 | "profile_background_image_url_https": "https://abs.twimg.com/images/themes/theme4/bg.gif", 432 | "profile_background_tile": true, 433 | "profile_image_url": "http://pbs.twimg.com/profile_images/714394259319824385/5RM06BOS_normal.jpg", 434 | "profile_image_url_https": "https://pbs.twimg.com/profile_images/714394259319824385/5RM06BOS_normal.jpg", 435 | "profile_banner_url": "https://pbs.twimg.com/profile_banners/46904555/1397410316", 436 | "profile_image_extensions_alt_text": null, 437 | "profile_banner_extensions_alt_text": null, 438 | "profile_link_color": "590606", 439 | "profile_sidebar_border_color": "000000", 440 | "profile_sidebar_fill_color": "705A55", 441 | "profile_text_color": "080808", 442 | "profile_use_background_image": true, 443 | "has_extended_profile": false, 444 | "default_profile": false, 445 | "default_profile_image": false, 446 | "following": false, 447 | "follow_request_sent": false, 448 | "notifications": false, 449 | "translator_type": "regular" 450 | }, 451 | "geo": null, 452 | "coordinates": null, 453 | "place": null, 454 | "contributors": null, 455 | "is_quote_status": false, 456 | "retweet_count": 0, 457 | "favorite_count": 5, 458 | "favorited": false, 459 | "retweeted": false, 460 | "possibly_sensitive": false, 461 | "possibly_sensitive_appealable": false, 462 | "lang": "de" 463 | }, 464 | "5": { 465 | "created_at": "Thu Mar 07 16:54:23 +0000 2019", 466 | "id": 1103700431648243700, 467 | "id_str": "1103700431648243712", 468 | "full_text": "#SehrysWho\n\nwe will try to keep track of this year’s reading in this thread, tagging with #SehrysReads ⬇️\n\nhttps://t.co/CYu8aSMRTj", 469 | "truncated": false, 470 | "display_text_range": [0, 130], 471 | "entities": { 472 | "hashtags": [ 473 | { "text": "SehrysWho", "indices": [0, 10] }, 474 | { "text": "SehrysReads", "indices": [90, 102] } 475 | ], 476 | "symbols": [], 477 | "user_mentions": [], 478 | "urls": [ 479 | { 480 | "url": "https://t.co/CYu8aSMRTj", 481 | "expanded_url": "https://twitter.com/sehrysflausch/status/1103699905338634240?s=21", 482 | "display_url": "twitter.com/sehrysflausch/…", 483 | "indices": [107, 130] 484 | } 485 | ] 486 | }, 487 | "source": "Twitter for iPhone", 488 | "in_reply_to_status_id": 1081636996827807700, 489 | "in_reply_to_status_id_str": "1081636996827807745", 490 | "in_reply_to_user_id": 890161666129834000, 491 | "in_reply_to_user_id_str": "890161666129833984", 492 | "in_reply_to_screen_name": "SehrysFlausch", 493 | "user": { 494 | "id": 890161666129834000, 495 | "id_str": "890161666129833984", 496 | "name": "Sehrys [ey/em | keins]", 497 | "screen_name": "SehrysFlausch", 498 | "location": "", 499 | "description": "[ey/em, plural they] queer, trans masc, fluidflux. neurodivergent, plural👥. white, fat. [tip us at: https://t.co/0AXhPwjVgX] #nsfw. pic by @coffeeandtheart", 500 | "url": "https://t.co/YkfgwS59sz", 501 | "entities": { 502 | "url": { 503 | "urls": [ 504 | { 505 | "url": "https://t.co/YkfgwS59sz", 506 | "expanded_url": "https://www.amazon.de/registry/wishlist/W53W1S6W7NGG", 507 | "display_url": "amazon.de/registry/wishl…", 508 | "indices": [0, 23] 509 | } 510 | ] 511 | }, 512 | "description": { 513 | "urls": [ 514 | { 515 | "url": "https://t.co/0AXhPwjVgX", 516 | "expanded_url": "http://ko-fi.com/sehrys", 517 | "display_url": "ko-fi.com/sehrys", 518 | "indices": [100, 123] 519 | } 520 | ] 521 | } 522 | }, 523 | "protected": false, 524 | "followers_count": 343, 525 | "friends_count": 303, 526 | "listed_count": 2, 527 | "created_at": "Wed Jul 26 10:47:34 +0000 2017", 528 | "favourites_count": 53088, 529 | "utc_offset": null, 530 | "time_zone": null, 531 | "geo_enabled": false, 532 | "verified": false, 533 | "statuses_count": 10492, 534 | "lang": "de", 535 | "contributors_enabled": false, 536 | "is_translator": false, 537 | "is_translation_enabled": false, 538 | "profile_background_color": "000000", 539 | "profile_background_image_url": "http://abs.twimg.com/images/themes/theme1/bg.png", 540 | "profile_background_image_url_https": "https://abs.twimg.com/images/themes/theme1/bg.png", 541 | "profile_background_tile": false, 542 | "profile_image_url": "http://pbs.twimg.com/profile_images/1082378840872235008/Js7Obz6k_normal.jpg", 543 | "profile_image_url_https": "https://pbs.twimg.com/profile_images/1082378840872235008/Js7Obz6k_normal.jpg", 544 | "profile_banner_url": "https://pbs.twimg.com/profile_banners/890161666129833984/1548150995", 545 | "profile_image_extensions_alt_text": null, 546 | "profile_banner_extensions_alt_text": null, 547 | "profile_link_color": "1DA1F2", 548 | "profile_sidebar_border_color": "000000", 549 | "profile_sidebar_fill_color": "000000", 550 | "profile_text_color": "000000", 551 | "profile_use_background_image": false, 552 | "has_extended_profile": true, 553 | "default_profile": false, 554 | "default_profile_image": false, 555 | "following": false, 556 | "follow_request_sent": false, 557 | "notifications": false, 558 | "translator_type": "none" 559 | }, 560 | "geo": null, 561 | "coordinates": null, 562 | "place": null, 563 | "contributors": null, 564 | "is_quote_status": true, 565 | "quoted_status_id": 1103699905338634200, 566 | "quoted_status_id_str": "1103699905338634240", 567 | "quoted_status_permalink": { 568 | "url": "https://t.co/CYu8aSMRTj", 569 | "expanded": "https://twitter.com/sehrysflausch/status/1103699905338634240?s=21", 570 | "display": "twitter.com/sehrysflausch/…" 571 | }, 572 | "quoted_status": { 573 | "created_at": "Thu Mar 07 16:52:17 +0000 2019", 574 | "id": 1103699905338634200, 575 | "id_str": "1103699905338634240", 576 | "full_text": "we will try and keep track of all the books we read this year, because we love when others do that\n\ngonna start this by trying to remember the past months,\n\ntagging with #SehrysReads \n\n✨#thread starter kitten included, because cats!✨ https://t.co/wzFDoEi0Af", 577 | "truncated": false, 578 | "display_text_range": [0, 233], 579 | "entities": { 580 | "hashtags": [ 581 | { "text": "SehrysReads", "indices": [170, 182] }, 582 | { "text": "thread", "indices": [186, 193] } 583 | ], 584 | "symbols": [], 585 | "user_mentions": [], 586 | "urls": [], 587 | "media": [ 588 | { 589 | "id": 1103699898703188000, 590 | "id_str": "1103699898703187969", 591 | "indices": [234, 257], 592 | "media_url": "http://pbs.twimg.com/media/D1EhNdDWkAEJxoC.jpg", 593 | "media_url_https": "https://pbs.twimg.com/media/D1EhNdDWkAEJxoC.jpg", 594 | "url": "https://t.co/wzFDoEi0Af", 595 | "display_url": "pic.twitter.com/wzFDoEi0Af", 596 | "expanded_url": "https://twitter.com/SehrysFlausch/status/1103699905338634240/photo/1", 597 | "type": "photo", 598 | "sizes": { 599 | "medium": { "w": 900, "h": 1200, "resize": "fit" }, 600 | "thumb": { "w": 150, "h": 150, "resize": "crop" }, 601 | "small": { "w": 510, "h": 680, "resize": "fit" }, 602 | "large": { "w": 1536, "h": 2048, "resize": "fit" } 603 | } 604 | } 605 | ] 606 | }, 607 | "extended_entities": { 608 | "media": [ 609 | { 610 | "id": 1103699898703188000, 611 | "id_str": "1103699898703187969", 612 | "indices": [234, 257], 613 | "media_url": "http://pbs.twimg.com/media/D1EhNdDWkAEJxoC.jpg", 614 | "media_url_https": "https://pbs.twimg.com/media/D1EhNdDWkAEJxoC.jpg", 615 | "url": "https://t.co/wzFDoEi0Af", 616 | "display_url": "pic.twitter.com/wzFDoEi0Af", 617 | "expanded_url": "https://twitter.com/SehrysFlausch/status/1103699905338634240/photo/1", 618 | "type": "photo", 619 | "sizes": { 620 | "medium": { "w": 900, "h": 1200, "resize": "fit" }, 621 | "thumb": { "w": 150, "h": 150, "resize": "crop" }, 622 | "small": { "w": 510, "h": 680, "resize": "fit" }, 623 | "large": { "w": 1536, "h": 2048, "resize": "fit" } 624 | }, 625 | "ext_alt_text": "a tabby cat (@skyescats #OhMyOllie) sits on a chair, with its head looking up over a kitchen table. on the table is an unfinished jigsaw puzzle, the picture also featuring two tabby cats." 626 | } 627 | ] 628 | }, 629 | "source": "Twitter for iPhone", 630 | "in_reply_to_status_id": null, 631 | "in_reply_to_status_id_str": null, 632 | "in_reply_to_user_id": null, 633 | "in_reply_to_user_id_str": null, 634 | "in_reply_to_screen_name": null, 635 | "user": { 636 | "id": 890161666129834000, 637 | "id_str": "890161666129833984", 638 | "name": "Sehrys [ey/em | keins]", 639 | "screen_name": "SehrysFlausch", 640 | "location": "", 641 | "description": "[ey/em, plural they] queer, trans masc, fluidflux. neurodivergent, plural👥. white, fat. [tip us at: https://t.co/0AXhPwjVgX] #nsfw. pic by @coffeeandtheart", 642 | "url": "https://t.co/YkfgwS59sz", 643 | "entities": { 644 | "url": { 645 | "urls": [ 646 | { 647 | "url": "https://t.co/YkfgwS59sz", 648 | "expanded_url": "https://www.amazon.de/registry/wishlist/W53W1S6W7NGG", 649 | "display_url": "amazon.de/registry/wishl…", 650 | "indices": [0, 23] 651 | } 652 | ] 653 | }, 654 | "description": { 655 | "urls": [ 656 | { 657 | "url": "https://t.co/0AXhPwjVgX", 658 | "expanded_url": "http://ko-fi.com/sehrys", 659 | "display_url": "ko-fi.com/sehrys", 660 | "indices": [100, 123] 661 | } 662 | ] 663 | } 664 | }, 665 | "protected": false, 666 | "followers_count": 343, 667 | "friends_count": 303, 668 | "listed_count": 2, 669 | "created_at": "Wed Jul 26 10:47:34 +0000 2017", 670 | "favourites_count": 53088, 671 | "utc_offset": null, 672 | "time_zone": null, 673 | "geo_enabled": false, 674 | "verified": false, 675 | "statuses_count": 10492, 676 | "lang": "de", 677 | "contributors_enabled": false, 678 | "is_translator": false, 679 | "is_translation_enabled": false, 680 | "profile_background_color": "000000", 681 | "profile_background_image_url": "http://abs.twimg.com/images/themes/theme1/bg.png", 682 | "profile_background_image_url_https": "https://abs.twimg.com/images/themes/theme1/bg.png", 683 | "profile_background_tile": false, 684 | "profile_image_url": "http://pbs.twimg.com/profile_images/1082378840872235008/Js7Obz6k_normal.jpg", 685 | "profile_image_url_https": "https://pbs.twimg.com/profile_images/1082378840872235008/Js7Obz6k_normal.jpg", 686 | "profile_banner_url": "https://pbs.twimg.com/profile_banners/890161666129833984/1548150995", 687 | "profile_image_extensions_alt_text": null, 688 | "profile_banner_extensions_alt_text": null, 689 | "profile_link_color": "1DA1F2", 690 | "profile_sidebar_border_color": "000000", 691 | "profile_sidebar_fill_color": "000000", 692 | "profile_text_color": "000000", 693 | "profile_use_background_image": false, 694 | "has_extended_profile": true, 695 | "default_profile": false, 696 | "default_profile_image": false, 697 | "following": false, 698 | "follow_request_sent": false, 699 | "notifications": false, 700 | "translator_type": "none" 701 | }, 702 | "geo": null, 703 | "coordinates": null, 704 | "place": null, 705 | "contributors": null, 706 | "is_quote_status": false, 707 | "retweet_count": 0, 708 | "favorite_count": 5, 709 | "favorited": false, 710 | "retweeted": false, 711 | "possibly_sensitive": false, 712 | "possibly_sensitive_appealable": false, 713 | "lang": "en" 714 | }, 715 | "retweet_count": 0, 716 | "favorite_count": 0, 717 | "favorited": false, 718 | "retweeted": false, 719 | "possibly_sensitive": false, 720 | "possibly_sensitive_appealable": false, 721 | "lang": "en" 722 | }, 723 | "6": { 724 | "created_at": "Sat Mar 09 16:47:17 +0000 2019", 725 | "id": 1104423422925422600, 726 | "id_str": "1104423422925422595", 727 | "full_text": "o https://t.co/nL5jHq9EX6", 728 | "truncated": false, 729 | "display_text_range": [0, 1], 730 | "entities": { 731 | "hashtags": [], 732 | "symbols": [], 733 | "user_mentions": [], 734 | "urls": [ 735 | { 736 | "url": "https://t.co/nL5jHq9EX6", 737 | "expanded_url": "https://twitter.com/blurryechopilot/status/1104044949123796995", 738 | "display_url": "twitter.com/blurryechopilo…", 739 | "indices": [2, 25] 740 | } 741 | ] 742 | }, 743 | "source": "Twitter for Android", 744 | "in_reply_to_status_id": null, 745 | "in_reply_to_status_id_str": null, 746 | "in_reply_to_user_id": null, 747 | "in_reply_to_user_id_str": null, 748 | "in_reply_to_screen_name": null, 749 | "user": { 750 | "id": 3262161021, 751 | "id_str": "3262161021", 752 | "name": "florian - mikkelslut", 753 | "screen_name": "_cumasyouare_", 754 | "location": "[he/him] Germany GER/ENG", 755 | "description": "| you should always eat the rude | Aristocrat of Evil | 18 | fandom trash content und aktivismus |\nhttps://t.co/fKzBVAL3j5", 756 | "url": "https://t.co/wlwmAbcYl5", 757 | "entities": { 758 | "url": { 759 | "urls": [ 760 | { 761 | "url": "https://t.co/wlwmAbcYl5", 762 | "expanded_url": "https://curiouscat.me/cumasyouare", 763 | "display_url": "curiouscat.me/cumasyouare", 764 | "indices": [0, 23] 765 | } 766 | ] 767 | }, 768 | "description": { 769 | "urls": [ 770 | { 771 | "url": "https://t.co/fKzBVAL3j5", 772 | "expanded_url": "http://tellonym.me/omegaonmars", 773 | "display_url": "tellonym.me/omegaonmars", 774 | "indices": [99, 122] 775 | } 776 | ] 777 | } 778 | }, 779 | "protected": false, 780 | "followers_count": 511, 781 | "friends_count": 244, 782 | "listed_count": 5, 783 | "created_at": "Sat May 16 17:45:14 +0000 2015", 784 | "favourites_count": 5154, 785 | "utc_offset": null, 786 | "time_zone": null, 787 | "geo_enabled": false, 788 | "verified": false, 789 | "statuses_count": 26162, 790 | "lang": "de", 791 | "contributors_enabled": false, 792 | "is_translator": false, 793 | "is_translation_enabled": false, 794 | "profile_background_color": "C0DEED", 795 | "profile_background_image_url": "http://abs.twimg.com/images/themes/theme1/bg.png", 796 | "profile_background_image_url_https": "https://abs.twimg.com/images/themes/theme1/bg.png", 797 | "profile_background_tile": false, 798 | "profile_image_url": "http://pbs.twimg.com/profile_images/1092849205511626752/oVwd1iqf_normal.jpg", 799 | "profile_image_url_https": "https://pbs.twimg.com/profile_images/1092849205511626752/oVwd1iqf_normal.jpg", 800 | "profile_banner_url": "https://pbs.twimg.com/profile_banners/3262161021/1544820020", 801 | "profile_image_extensions_alt_text": null, 802 | "profile_banner_extensions_alt_text": null, 803 | "profile_link_color": "1DA1F2", 804 | "profile_sidebar_border_color": "C0DEED", 805 | "profile_sidebar_fill_color": "DDEEF6", 806 | "profile_text_color": "333333", 807 | "profile_use_background_image": true, 808 | "has_extended_profile": true, 809 | "default_profile": true, 810 | "default_profile_image": false, 811 | "following": false, 812 | "follow_request_sent": false, 813 | "notifications": false, 814 | "translator_type": "none" 815 | }, 816 | "geo": null, 817 | "coordinates": null, 818 | "place": null, 819 | "contributors": null, 820 | "is_quote_status": true, 821 | "quoted_status_id": 1104044949123797000, 822 | "quoted_status_id_str": "1104044949123796995", 823 | "quoted_status_permalink": { 824 | "url": "https://t.co/nL5jHq9EX6", 825 | "expanded": "https://twitter.com/blurryechopilot/status/1104044949123796995", 826 | "display": "twitter.com/blurryechopilo…" 827 | }, 828 | "quoted_status": { 829 | "created_at": "Fri Mar 08 15:43:22 +0000 2019", 830 | "id": 1104044949123797000, 831 | "id_str": "1104044949123796995", 832 | "full_text": "i’ll start, oph t https://t.co/OOfatNoeC7", 833 | "truncated": false, 834 | "display_text_range": [0, 17], 835 | "entities": { 836 | "hashtags": [], 837 | "symbols": [], 838 | "user_mentions": [], 839 | "urls": [], 840 | "media": [ 841 | { 842 | "id": 1104044942438133800, 843 | "id_str": "1104044942438133765", 844 | "indices": [18, 41], 845 | "media_url": "http://pbs.twimg.com/media/D1JbBpIXcAUXzvR.jpg", 846 | "media_url_https": "https://pbs.twimg.com/media/D1JbBpIXcAUXzvR.jpg", 847 | "url": "https://t.co/OOfatNoeC7", 848 | "display_url": "pic.twitter.com/OOfatNoeC7", 849 | "expanded_url": "https://twitter.com/blurryechopilot/status/1104044949123796995/photo/1", 850 | "type": "photo", 851 | "sizes": { 852 | "thumb": { "w": 150, "h": 150, "resize": "crop" }, 853 | "small": { "w": 680, "h": 552, "resize": "fit" }, 854 | "large": { "w": 1242, "h": 1009, "resize": "fit" }, 855 | "medium": { "w": 1200, "h": 975, "resize": "fit" } 856 | } 857 | } 858 | ] 859 | }, 860 | "extended_entities": { 861 | "media": [ 862 | { 863 | "id": 1104044942438133800, 864 | "id_str": "1104044942438133765", 865 | "indices": [18, 41], 866 | "media_url": "http://pbs.twimg.com/media/D1JbBpIXcAUXzvR.jpg", 867 | "media_url_https": "https://pbs.twimg.com/media/D1JbBpIXcAUXzvR.jpg", 868 | "url": "https://t.co/OOfatNoeC7", 869 | "display_url": "pic.twitter.com/OOfatNoeC7", 870 | "expanded_url": "https://twitter.com/blurryechopilot/status/1104044949123796995/photo/1", 871 | "type": "photo", 872 | "sizes": { 873 | "thumb": { "w": 150, "h": 150, "resize": "crop" }, 874 | "small": { "w": 680, "h": 552, "resize": "fit" }, 875 | "large": { "w": 1242, "h": 1009, "resize": "fit" }, 876 | "medium": { "w": 1200, "h": 975, "resize": "fit" } 877 | }, 878 | "ext_alt_text": null 879 | } 880 | ] 881 | }, 882 | "source": "Twitter for iPhone", 883 | "in_reply_to_status_id": null, 884 | "in_reply_to_status_id_str": null, 885 | "in_reply_to_user_id": null, 886 | "in_reply_to_user_id_str": null, 887 | "in_reply_to_screen_name": null, 888 | "user": { 889 | "id": 878193344605769700, 890 | "id_str": "878193344605769729", 891 | "name": "soph 🥵", 892 | "screen_name": "blurryechopilot", 893 | "location": "trench", 894 | "description": "+ 𝒻𝑜𝓇 𝓎𝑜𝓊, 𝒾 𝓌𝑜𝓊𝓁𝒹 𝑔𝑒𝓉 𝒷𝑒𝒶𝓉 𝓉𝑜 𝓈𝓂𝒾𝓉𝒽𝑒𝓇𝑒𝑒𝓃𝓈 5/3/19💛", 895 | "url": "https://t.co/dk4ZO2P0nr", 896 | "entities": { 897 | "url": { 898 | "urls": [ 899 | { 900 | "url": "https://t.co/dk4ZO2P0nr", 901 | "expanded_url": "https://curiouscat.me/blurryechopilot", 902 | "display_url": "curiouscat.me/blurryechopilot", 903 | "indices": [0, 23] 904 | } 905 | ] 906 | }, 907 | "description": { "urls": [] } 908 | }, 909 | "protected": false, 910 | "followers_count": 2587, 911 | "friends_count": 2459, 912 | "listed_count": 21, 913 | "created_at": "Fri Jun 23 10:09:44 +0000 2017", 914 | "favourites_count": 1735, 915 | "utc_offset": null, 916 | "time_zone": null, 917 | "geo_enabled": true, 918 | "verified": false, 919 | "statuses_count": 2696, 920 | "lang": "en", 921 | "contributors_enabled": false, 922 | "is_translator": false, 923 | "is_translation_enabled": false, 924 | "profile_background_color": "000000", 925 | "profile_background_image_url": "http://abs.twimg.com/images/themes/theme1/bg.png", 926 | "profile_background_image_url_https": "https://abs.twimg.com/images/themes/theme1/bg.png", 927 | "profile_background_tile": false, 928 | "profile_image_url": "http://pbs.twimg.com/profile_images/1104332154845257729/bAc_0M9E_normal.jpg", 929 | "profile_image_url_https": "https://pbs.twimg.com/profile_images/1104332154845257729/bAc_0M9E_normal.jpg", 930 | "profile_banner_url": "https://pbs.twimg.com/profile_banners/878193344605769729/1552128279", 931 | "profile_image_extensions_alt_text": null, 932 | "profile_banner_extensions_alt_text": null, 933 | "profile_link_color": "E81C4F", 934 | "profile_sidebar_border_color": "000000", 935 | "profile_sidebar_fill_color": "000000", 936 | "profile_text_color": "000000", 937 | "profile_use_background_image": false, 938 | "has_extended_profile": true, 939 | "default_profile": false, 940 | "default_profile_image": false, 941 | "following": false, 942 | "follow_request_sent": false, 943 | "notifications": false, 944 | "translator_type": "none" 945 | }, 946 | "geo": null, 947 | "coordinates": null, 948 | "place": null, 949 | "contributors": null, 950 | "is_quote_status": false, 951 | "retweet_count": 25, 952 | "favorite_count": 788, 953 | "favorited": false, 954 | "retweeted": false, 955 | "possibly_sensitive": false, 956 | "possibly_sensitive_appealable": false, 957 | "lang": "en" 958 | }, 959 | "retweet_count": 0, 960 | "favorite_count": 2, 961 | "favorited": false, 962 | "retweeted": false, 963 | "possibly_sensitive": false, 964 | "possibly_sensitive_appealable": false, 965 | "lang": "und" 966 | }, 967 | "7": { 968 | "created_at": "Sat Mar 02 06:52:43 +0000 2019", 969 | "id": 1101737078956666900, 970 | "id_str": "1101737078956666880", 971 | "full_text": "People who think Saturday 8am is a good time for an exam should be banned from ever holding an exam again.", 972 | "truncated": false, 973 | "display_text_range": [0, 106], 974 | "entities": { 975 | "hashtags": [], 976 | "symbols": [], 977 | "user_mentions": [], 978 | "urls": [] 979 | }, 980 | "source": "Tweetbot for iΟS", 981 | "in_reply_to_status_id": null, 982 | "in_reply_to_status_id_str": null, 983 | "in_reply_to_user_id": null, 984 | "in_reply_to_user_id_str": null, 985 | "in_reply_to_screen_name": null, 986 | "user": { 987 | "id": 1865110807, 988 | "id_str": "1865110807", 989 | "name": "φnn", 990 | "screen_name": "malfynnction", 991 | "location": "Berlin, Germany", 992 | "description": "Fynn | 21 | he/him | does things with computers, gender, and other queer stuff | knows how to fold a fitted sheet | ava by @_morre_", 993 | "url": null, 994 | "entities": { "description": { "urls": [] } }, 995 | "protected": false, 996 | "followers_count": 927, 997 | "friends_count": 248, 998 | "listed_count": 34, 999 | "created_at": "Sat Sep 14 21:35:38 +0000 2013", 1000 | "favourites_count": 40125, 1001 | "utc_offset": null, 1002 | "time_zone": null, 1003 | "geo_enabled": true, 1004 | "verified": false, 1005 | "statuses_count": 38316, 1006 | "lang": "en-gb", 1007 | "contributors_enabled": false, 1008 | "is_translator": false, 1009 | "is_translation_enabled": false, 1010 | "profile_background_color": "000000", 1011 | "profile_background_image_url": "http://abs.twimg.com/images/themes/theme18/bg.gif", 1012 | "profile_background_image_url_https": "https://abs.twimg.com/images/themes/theme18/bg.gif", 1013 | "profile_background_tile": false, 1014 | "profile_image_url": "http://pbs.twimg.com/profile_images/1071082881831833601/uxR94Gp8_normal.jpg", 1015 | "profile_image_url_https": "https://pbs.twimg.com/profile_images/1071082881831833601/uxR94Gp8_normal.jpg", 1016 | "profile_banner_url": "https://pbs.twimg.com/profile_banners/1865110807/1496517525", 1017 | "profile_image_extensions_alt_text": null, 1018 | "profile_banner_extensions_alt_text": null, 1019 | "profile_link_color": "336699", 1020 | "profile_sidebar_border_color": "000000", 1021 | "profile_sidebar_fill_color": "000000", 1022 | "profile_text_color": "000000", 1023 | "profile_use_background_image": false, 1024 | "has_extended_profile": false, 1025 | "default_profile": false, 1026 | "default_profile_image": false, 1027 | "following": false, 1028 | "follow_request_sent": false, 1029 | "notifications": false, 1030 | "translator_type": "none" 1031 | }, 1032 | "geo": null, 1033 | "coordinates": null, 1034 | "place": null, 1035 | "contributors": null, 1036 | "is_quote_status": false, 1037 | "retweet_count": 0, 1038 | "favorite_count": 17, 1039 | "favorited": false, 1040 | "retweeted": false, 1041 | "lang": "en" 1042 | }, 1043 | "8": { 1044 | "created_at": "Sat Feb 16 19:05:10 +0000 2019", 1045 | "id": 1096847973919670300, 1046 | "id_str": "1096847973919670272", 1047 | "full_text": "@behindmypride “i was born and that was so viel” mood", 1048 | "truncated": false, 1049 | "display_text_range": [15, 53], 1050 | "entities": { 1051 | "hashtags": [], 1052 | "symbols": [], 1053 | "user_mentions": [ 1054 | { 1055 | "screen_name": "behindmypride", 1056 | "name": "noah", 1057 | "id": 2388083673, 1058 | "id_str": "2388083673", 1059 | "indices": [0, 14] 1060 | } 1061 | ], 1062 | "urls": [] 1063 | }, 1064 | "source": "Tweetbot for Mac", 1065 | "in_reply_to_status_id": 1096831377440456700, 1066 | "in_reply_to_status_id_str": "1096831377440456704", 1067 | "in_reply_to_user_id": 2388083673, 1068 | "in_reply_to_user_id_str": "2388083673", 1069 | "in_reply_to_screen_name": "behindmypride", 1070 | "user": { 1071 | "id": 1865110807, 1072 | "id_str": "1865110807", 1073 | "name": "φnn", 1074 | "screen_name": "malfynnction", 1075 | "location": "Berlin, Germany", 1076 | "description": "Fynn | 21 | he/him | does things with computers, gender, and other queer stuff | knows how to fold a fitted sheet | ava by @_morre_", 1077 | "url": null, 1078 | "entities": { "description": { "urls": [] } }, 1079 | "protected": false, 1080 | "followers_count": 927, 1081 | "friends_count": 248, 1082 | "listed_count": 34, 1083 | "created_at": "Sat Sep 14 21:35:38 +0000 2013", 1084 | "favourites_count": 40125, 1085 | "utc_offset": null, 1086 | "time_zone": null, 1087 | "geo_enabled": true, 1088 | "verified": false, 1089 | "statuses_count": 38316, 1090 | "lang": "en-gb", 1091 | "contributors_enabled": false, 1092 | "is_translator": false, 1093 | "is_translation_enabled": false, 1094 | "profile_background_color": "000000", 1095 | "profile_background_image_url": "http://abs.twimg.com/images/themes/theme18/bg.gif", 1096 | "profile_background_image_url_https": "https://abs.twimg.com/images/themes/theme18/bg.gif", 1097 | "profile_background_tile": false, 1098 | "profile_image_url": "http://pbs.twimg.com/profile_images/1071082881831833601/uxR94Gp8_normal.jpg", 1099 | "profile_image_url_https": "https://pbs.twimg.com/profile_images/1071082881831833601/uxR94Gp8_normal.jpg", 1100 | "profile_banner_url": "https://pbs.twimg.com/profile_banners/1865110807/1496517525", 1101 | "profile_image_extensions_alt_text": null, 1102 | "profile_banner_extensions_alt_text": null, 1103 | "profile_link_color": "336699", 1104 | "profile_sidebar_border_color": "000000", 1105 | "profile_sidebar_fill_color": "000000", 1106 | "profile_text_color": "000000", 1107 | "profile_use_background_image": false, 1108 | "has_extended_profile": false, 1109 | "default_profile": false, 1110 | "default_profile_image": false, 1111 | "following": false, 1112 | "follow_request_sent": false, 1113 | "notifications": false, 1114 | "translator_type": "none" 1115 | }, 1116 | "geo": null, 1117 | "coordinates": null, 1118 | "place": null, 1119 | "contributors": null, 1120 | "is_quote_status": false, 1121 | "retweet_count": 0, 1122 | "favorite_count": 3, 1123 | "favorited": false, 1124 | "retweeted": false, 1125 | "lang": "en" 1126 | }, 1127 | "9": { 1128 | "created_at": "Thu Jan 31 19:56:09 +0000 2019", 1129 | "id": 1091062601017163800, 1130 | "id_str": "1091062601017163776", 1131 | "full_text": "The blue one is still available! https://t.co/K8oTwlxKYV", 1132 | "truncated": false, 1133 | "display_text_range": [0, 32], 1134 | "entities": { 1135 | "hashtags": [], 1136 | "symbols": [], 1137 | "user_mentions": [], 1138 | "urls": [ 1139 | { 1140 | "url": "https://t.co/K8oTwlxKYV", 1141 | "expanded_url": "https://twitter.com/malfynnction/status/1089123853681545217", 1142 | "display_url": "twitter.com/malfynnction/s…", 1143 | "indices": [33, 56] 1144 | } 1145 | ] 1146 | }, 1147 | "source": "Tweetbot for iΟS", 1148 | "in_reply_to_status_id": 1089123853681545200, 1149 | "in_reply_to_status_id_str": "1089123853681545217", 1150 | "in_reply_to_user_id": 1865110807, 1151 | "in_reply_to_user_id_str": "1865110807", 1152 | "in_reply_to_screen_name": "malfynnction", 1153 | "user": { 1154 | "id": 1865110807, 1155 | "id_str": "1865110807", 1156 | "name": "φnn", 1157 | "screen_name": "malfynnction", 1158 | "location": "Berlin, Germany", 1159 | "description": "Fynn | 21 | he/him | does things with computers, gender, and other queer stuff | knows how to fold a fitted sheet | ava by @_morre_", 1160 | "url": null, 1161 | "entities": { "description": { "urls": [] } }, 1162 | "protected": false, 1163 | "followers_count": 927, 1164 | "friends_count": 248, 1165 | "listed_count": 34, 1166 | "created_at": "Sat Sep 14 21:35:38 +0000 2013", 1167 | "favourites_count": 40125, 1168 | "utc_offset": null, 1169 | "time_zone": null, 1170 | "geo_enabled": true, 1171 | "verified": false, 1172 | "statuses_count": 38316, 1173 | "lang": "en-gb", 1174 | "contributors_enabled": false, 1175 | "is_translator": false, 1176 | "is_translation_enabled": false, 1177 | "profile_background_color": "000000", 1178 | "profile_background_image_url": "http://abs.twimg.com/images/themes/theme18/bg.gif", 1179 | "profile_background_image_url_https": "https://abs.twimg.com/images/themes/theme18/bg.gif", 1180 | "profile_background_tile": false, 1181 | "profile_image_url": "http://pbs.twimg.com/profile_images/1071082881831833601/uxR94Gp8_normal.jpg", 1182 | "profile_image_url_https": "https://pbs.twimg.com/profile_images/1071082881831833601/uxR94Gp8_normal.jpg", 1183 | "profile_banner_url": "https://pbs.twimg.com/profile_banners/1865110807/1496517525", 1184 | "profile_image_extensions_alt_text": null, 1185 | "profile_banner_extensions_alt_text": null, 1186 | "profile_link_color": "336699", 1187 | "profile_sidebar_border_color": "000000", 1188 | "profile_sidebar_fill_color": "000000", 1189 | "profile_text_color": "000000", 1190 | "profile_use_background_image": false, 1191 | "has_extended_profile": false, 1192 | "default_profile": false, 1193 | "default_profile_image": false, 1194 | "following": false, 1195 | "follow_request_sent": false, 1196 | "notifications": false, 1197 | "translator_type": "none" 1198 | }, 1199 | "geo": null, 1200 | "coordinates": null, 1201 | "place": null, 1202 | "contributors": null, 1203 | "is_quote_status": true, 1204 | "quoted_status_id": 1089123853681545200, 1205 | "quoted_status_id_str": "1089123853681545217", 1206 | "quoted_status_permalink": { 1207 | "url": "https://t.co/K8oTwlxKYV", 1208 | "expanded": "https://twitter.com/malfynnction/status/1089123853681545217", 1209 | "display": "twitter.com/malfynnction/s…" 1210 | }, 1211 | "quoted_status": { 1212 | "created_at": "Sat Jan 26 11:32:16 +0000 2019", 1213 | "id": 1089123853681545200, 1214 | "id_str": "1089123853681545217", 1215 | "full_text": "Does anybody need a binder?\n\ni have \n- gc2b half binder, blue, M\n- gc2b half binder, nude no. 4, M\n- danae half binder, black, M\nand would be happy to give them to ppl who need one", 1216 | "truncated": false, 1217 | "display_text_range": [0, 180], 1218 | "entities": { 1219 | "hashtags": [], 1220 | "symbols": [], 1221 | "user_mentions": [], 1222 | "urls": [] 1223 | }, 1224 | "source": "Tweetbot for Mac", 1225 | "in_reply_to_status_id": null, 1226 | "in_reply_to_status_id_str": null, 1227 | "in_reply_to_user_id": null, 1228 | "in_reply_to_user_id_str": null, 1229 | "in_reply_to_screen_name": null, 1230 | "user": { 1231 | "id": 1865110807, 1232 | "id_str": "1865110807", 1233 | "name": "φnn", 1234 | "screen_name": "malfynnction", 1235 | "location": "Berlin, Germany", 1236 | "description": "Fynn | 21 | he/him | does things with computers, gender, and other queer stuff | knows how to fold a fitted sheet | ava by @_morre_", 1237 | "url": null, 1238 | "entities": { "description": { "urls": [] } }, 1239 | "protected": false, 1240 | "followers_count": 927, 1241 | "friends_count": 248, 1242 | "listed_count": 34, 1243 | "created_at": "Sat Sep 14 21:35:38 +0000 2013", 1244 | "favourites_count": 40125, 1245 | "utc_offset": null, 1246 | "time_zone": null, 1247 | "geo_enabled": true, 1248 | "verified": false, 1249 | "statuses_count": 38316, 1250 | "lang": "en-gb", 1251 | "contributors_enabled": false, 1252 | "is_translator": false, 1253 | "is_translation_enabled": false, 1254 | "profile_background_color": "000000", 1255 | "profile_background_image_url": "http://abs.twimg.com/images/themes/theme18/bg.gif", 1256 | "profile_background_image_url_https": "https://abs.twimg.com/images/themes/theme18/bg.gif", 1257 | "profile_background_tile": false, 1258 | "profile_image_url": "http://pbs.twimg.com/profile_images/1071082881831833601/uxR94Gp8_normal.jpg", 1259 | "profile_image_url_https": "https://pbs.twimg.com/profile_images/1071082881831833601/uxR94Gp8_normal.jpg", 1260 | "profile_banner_url": "https://pbs.twimg.com/profile_banners/1865110807/1496517525", 1261 | "profile_image_extensions_alt_text": null, 1262 | "profile_banner_extensions_alt_text": null, 1263 | "profile_link_color": "336699", 1264 | "profile_sidebar_border_color": "000000", 1265 | "profile_sidebar_fill_color": "000000", 1266 | "profile_text_color": "000000", 1267 | "profile_use_background_image": false, 1268 | "has_extended_profile": false, 1269 | "default_profile": false, 1270 | "default_profile_image": false, 1271 | "following": false, 1272 | "follow_request_sent": false, 1273 | "notifications": false, 1274 | "translator_type": "none" 1275 | }, 1276 | "geo": null, 1277 | "coordinates": null, 1278 | "place": null, 1279 | "contributors": null, 1280 | "is_quote_status": false, 1281 | "retweet_count": 163, 1282 | "favorite_count": 71, 1283 | "favorited": false, 1284 | "retweeted": false, 1285 | "lang": "en" 1286 | }, 1287 | "retweet_count": 5, 1288 | "favorite_count": 1, 1289 | "favorited": false, 1290 | "retweeted": false, 1291 | "possibly_sensitive": false, 1292 | "possibly_sensitive_appealable": false, 1293 | "lang": "en" 1294 | }, 1295 | "10": { 1296 | "created_at": "Fri Sep 07 11:30:25 +0000 2018", 1297 | "id": 1038026699827564500, 1298 | "id_str": "1038026699827564545", 1299 | "full_text": "So, my health insurance has finally decided that they’re going to pay for my top surgery & hysto!! 🎉 https://t.co/hHTWpljKpp", 1300 | "truncated": false, 1301 | "display_text_range": [0, 104], 1302 | "entities": { 1303 | "hashtags": [], 1304 | "symbols": [], 1305 | "user_mentions": [], 1306 | "urls": [], 1307 | "media": [ 1308 | { 1309 | "id": 1038026693380898800, 1310 | "id_str": "1038026693380898817", 1311 | "indices": [105, 128], 1312 | "media_url": "http://pbs.twimg.com/media/DmfPxyZXgAEyqGD.jpg", 1313 | "media_url_https": "https://pbs.twimg.com/media/DmfPxyZXgAEyqGD.jpg", 1314 | "url": "https://t.co/hHTWpljKpp", 1315 | "display_url": "pic.twitter.com/hHTWpljKpp", 1316 | "expanded_url": "https://twitter.com/malfynnction/status/1038026699827564545/photo/1", 1317 | "type": "photo", 1318 | "sizes": { 1319 | "small": { "w": 680, "h": 298, "resize": "fit" }, 1320 | "thumb": { "w": 150, "h": 150, "resize": "crop" }, 1321 | "large": { "w": 2048, "h": 897, "resize": "fit" }, 1322 | "medium": { "w": 1200, "h": 526, "resize": "fit" } 1323 | } 1324 | } 1325 | ] 1326 | }, 1327 | "extended_entities": { 1328 | "media": [ 1329 | { 1330 | "id": 1038026693380898800, 1331 | "id_str": "1038026693380898817", 1332 | "indices": [105, 128], 1333 | "media_url": "http://pbs.twimg.com/media/DmfPxyZXgAEyqGD.jpg", 1334 | "media_url_https": "https://pbs.twimg.com/media/DmfPxyZXgAEyqGD.jpg", 1335 | "url": "https://t.co/hHTWpljKpp", 1336 | "display_url": "pic.twitter.com/hHTWpljKpp", 1337 | "expanded_url": "https://twitter.com/malfynnction/status/1038026699827564545/photo/1", 1338 | "type": "photo", 1339 | "sizes": { 1340 | "small": { "w": 680, "h": 298, "resize": "fit" }, 1341 | "thumb": { "w": 150, "h": 150, "resize": "crop" }, 1342 | "large": { "w": 2048, "h": 897, "resize": "fit" }, 1343 | "medium": { "w": 1200, "h": 526, "resize": "fit" } 1344 | }, 1345 | "ext_alt_text": "Letter from my health insurance, saying: “Sehr geehrter Herr Heintz, auf Ihren Antrag auf Kostenübernahme für eine geschlechtsangleichende Operation bei Transsexualität nehmen wir Bezug. Hinsichtlich der folgenden Maßnahmen sagen wir Ihnen die Kostenübernahne zu: 1. Mastektomie bds. 2. Hysterektomie 3. Adnektomie”" 1346 | } 1347 | ] 1348 | }, 1349 | "source": "Twitter for iPhone", 1350 | "in_reply_to_status_id": 1014945233753256000, 1351 | "in_reply_to_status_id_str": "1014945233753255938", 1352 | "in_reply_to_user_id": 1865110807, 1353 | "in_reply_to_user_id_str": "1865110807", 1354 | "in_reply_to_screen_name": "malfynnction", 1355 | "user": { 1356 | "id": 1865110807, 1357 | "id_str": "1865110807", 1358 | "name": "φnn", 1359 | "screen_name": "malfynnction", 1360 | "location": "Berlin, Germany", 1361 | "description": "Fynn | 21 | he/him | does things with computers, gender, and other queer stuff | knows how to fold a fitted sheet | ava by @_morre_", 1362 | "url": null, 1363 | "entities": { "description": { "urls": [] } }, 1364 | "protected": false, 1365 | "followers_count": 927, 1366 | "friends_count": 248, 1367 | "listed_count": 34, 1368 | "created_at": "Sat Sep 14 21:35:38 +0000 2013", 1369 | "favourites_count": 40125, 1370 | "utc_offset": null, 1371 | "time_zone": null, 1372 | "geo_enabled": true, 1373 | "verified": false, 1374 | "statuses_count": 38316, 1375 | "lang": "en-gb", 1376 | "contributors_enabled": false, 1377 | "is_translator": false, 1378 | "is_translation_enabled": false, 1379 | "profile_background_color": "000000", 1380 | "profile_background_image_url": "http://abs.twimg.com/images/themes/theme18/bg.gif", 1381 | "profile_background_image_url_https": "https://abs.twimg.com/images/themes/theme18/bg.gif", 1382 | "profile_background_tile": false, 1383 | "profile_image_url": "http://pbs.twimg.com/profile_images/1071082881831833601/uxR94Gp8_normal.jpg", 1384 | "profile_image_url_https": "https://pbs.twimg.com/profile_images/1071082881831833601/uxR94Gp8_normal.jpg", 1385 | "profile_banner_url": "https://pbs.twimg.com/profile_banners/1865110807/1496517525", 1386 | "profile_image_extensions_alt_text": null, 1387 | "profile_banner_extensions_alt_text": null, 1388 | "profile_link_color": "336699", 1389 | "profile_sidebar_border_color": "000000", 1390 | "profile_sidebar_fill_color": "000000", 1391 | "profile_text_color": "000000", 1392 | "profile_use_background_image": false, 1393 | "has_extended_profile": false, 1394 | "default_profile": false, 1395 | "default_profile_image": false, 1396 | "following": false, 1397 | "follow_request_sent": false, 1398 | "notifications": false, 1399 | "translator_type": "none" 1400 | }, 1401 | "geo": null, 1402 | "coordinates": null, 1403 | "place": null, 1404 | "contributors": null, 1405 | "is_quote_status": false, 1406 | "retweet_count": 0, 1407 | "favorite_count": 53, 1408 | "favorited": false, 1409 | "retweeted": false, 1410 | "possibly_sensitive": false, 1411 | "possibly_sensitive_appealable": false, 1412 | "lang": "en" 1413 | }, 1414 | "11": { 1415 | "created_at": "Sat Sep 29 10:43:03 +0000 2018", 1416 | "id": 1045987312516169700, 1417 | "id_str": "1045987312516169729", 1418 | "full_text": "Sorry, I've been asleep for a few days, but I'm back now \\o/", 1419 | "truncated": false, 1420 | "display_text_range": [0, 60], 1421 | "entities": { 1422 | "hashtags": [], 1423 | "symbols": [], 1424 | "user_mentions": [], 1425 | "urls": [] 1426 | }, 1427 | "source": "Twitter Web Client", 1428 | "in_reply_to_status_id": null, 1429 | "in_reply_to_status_id_str": null, 1430 | "in_reply_to_user_id": null, 1431 | "in_reply_to_user_id_str": null, 1432 | "in_reply_to_screen_name": null, 1433 | "user": { 1434 | "id": 968802481856794600, 1435 | "id_str": "968802481856794624", 1436 | "name": "Alt Text Reader", 1437 | "screen_name": "get_altText", 1438 | "location": "(If I'm broken, complain to @malfynnction)", 1439 | "description": "I read alt texts from images for you - just mention me in the reply to an image! (alt texts are a cool & accessible way to describe images - see pinned tweet)", 1440 | "url": "https://t.co/HVZ2T4ZpAW", 1441 | "entities": { 1442 | "url": { 1443 | "urls": [ 1444 | { 1445 | "url": "https://t.co/HVZ2T4ZpAW", 1446 | "expanded_url": "https://github.com/malfynnction/AltText-Tweeter", 1447 | "display_url": "github.com/malfynnction/A…", 1448 | "indices": [0, 23] 1449 | } 1450 | ] 1451 | }, 1452 | "description": { "urls": [] } 1453 | }, 1454 | "protected": false, 1455 | "followers_count": 359, 1456 | "friends_count": 1, 1457 | "listed_count": 9, 1458 | "created_at": "Wed Feb 28 10:58:05 +0000 2018", 1459 | "favourites_count": 1, 1460 | "utc_offset": null, 1461 | "time_zone": null, 1462 | "geo_enabled": false, 1463 | "verified": false, 1464 | "statuses_count": 1159, 1465 | "lang": "en", 1466 | "contributors_enabled": false, 1467 | "is_translator": false, 1468 | "is_translation_enabled": false, 1469 | "profile_background_color": "F5F8FA", 1470 | "profile_background_image_url": null, 1471 | "profile_background_image_url_https": null, 1472 | "profile_background_tile": false, 1473 | "profile_image_url": "http://pbs.twimg.com/profile_images/968844589263151104/7GgGo_53_normal.jpg", 1474 | "profile_image_url_https": "https://pbs.twimg.com/profile_images/968844589263151104/7GgGo_53_normal.jpg", 1475 | "profile_image_extensions_alt_text": null, 1476 | "profile_link_color": "1DA1F2", 1477 | "profile_sidebar_border_color": "C0DEED", 1478 | "profile_sidebar_fill_color": "DDEEF6", 1479 | "profile_text_color": "333333", 1480 | "profile_use_background_image": true, 1481 | "has_extended_profile": false, 1482 | "default_profile": true, 1483 | "default_profile_image": false, 1484 | "following": false, 1485 | "follow_request_sent": false, 1486 | "notifications": false, 1487 | "translator_type": "none" 1488 | }, 1489 | "geo": null, 1490 | "coordinates": null, 1491 | "place": null, 1492 | "contributors": null, 1493 | "is_quote_status": false, 1494 | "retweet_count": 1, 1495 | "favorite_count": 3, 1496 | "favorited": false, 1497 | "retweeted": false, 1498 | "lang": "en" 1499 | }, 1500 | "12": { 1501 | "created_at": "Mon Feb 18 10:26:22 +0000 2019", 1502 | "id": 1097442191264366600, 1503 | "id_str": "1097442191264366592", 1504 | "full_text": "@MalcolmMusic @pets4cats Rassismus als Abendunterhaltung zum Lachen u Niedlichfinden. 🤮", 1505 | "truncated": false, 1506 | "display_text_range": [25, 87], 1507 | "entities": { 1508 | "hashtags": [], 1509 | "symbols": [], 1510 | "user_mentions": [ 1511 | { 1512 | "screen_name": "MalcolmMusic", 1513 | "name": "Malcolm Ohanwe", 1514 | "id": 341059687, 1515 | "id_str": "341059687", 1516 | "indices": [0, 13] 1517 | }, 1518 | { 1519 | "screen_name": "pets4cats", 1520 | "name": "Happy Croc Inuidō 乾 道", 1521 | "id": 135250496, 1522 | "id_str": "135250496", 1523 | "indices": [14, 24] 1524 | } 1525 | ], 1526 | "urls": [] 1527 | }, 1528 | "source": "Twitter for iPad", 1529 | "in_reply_to_status_id": 1097438488696406000, 1530 | "in_reply_to_status_id_str": "1097438488696406017", 1531 | "in_reply_to_user_id": 341059687, 1532 | "in_reply_to_user_id_str": "341059687", 1533 | "in_reply_to_screen_name": "MalcolmMusic", 1534 | "user": { 1535 | "id": 839649983959818200, 1536 | "id_str": "839649983959818242", 1537 | "name": "Soup.", 1538 | "screen_name": "souplemur", 1539 | "location": "Berlin, Deutschland", 1540 | "description": "Kleener renitenter Homofürst aus der Hauptstadt.", 1541 | "url": null, 1542 | "entities": { "description": { "urls": [] } }, 1543 | "protected": false, 1544 | "followers_count": 1294, 1545 | "friends_count": 732, 1546 | "listed_count": 21, 1547 | "created_at": "Thu Mar 09 01:32:10 +0000 2017", 1548 | "favourites_count": 65371, 1549 | "utc_offset": null, 1550 | "time_zone": null, 1551 | "geo_enabled": false, 1552 | "verified": false, 1553 | "statuses_count": 11520, 1554 | "lang": "de", 1555 | "contributors_enabled": false, 1556 | "is_translator": false, 1557 | "is_translation_enabled": false, 1558 | "profile_background_color": "000000", 1559 | "profile_background_image_url": "http://abs.twimg.com/images/themes/theme1/bg.png", 1560 | "profile_background_image_url_https": "https://abs.twimg.com/images/themes/theme1/bg.png", 1561 | "profile_background_tile": false, 1562 | "profile_image_url": "http://pbs.twimg.com/profile_images/1011889999619461121/_qY7bdb7_normal.jpg", 1563 | "profile_image_url_https": "https://pbs.twimg.com/profile_images/1011889999619461121/_qY7bdb7_normal.jpg", 1564 | "profile_banner_url": "https://pbs.twimg.com/profile_banners/839649983959818242/1489684295", 1565 | "profile_image_extensions_alt_text": null, 1566 | "profile_banner_extensions_alt_text": null, 1567 | "profile_link_color": "FAB81E", 1568 | "profile_sidebar_border_color": "000000", 1569 | "profile_sidebar_fill_color": "000000", 1570 | "profile_text_color": "000000", 1571 | "profile_use_background_image": false, 1572 | "has_extended_profile": true, 1573 | "default_profile": false, 1574 | "default_profile_image": false, 1575 | "following": false, 1576 | "follow_request_sent": false, 1577 | "notifications": false, 1578 | "translator_type": "none" 1579 | }, 1580 | "geo": null, 1581 | "coordinates": null, 1582 | "place": null, 1583 | "contributors": null, 1584 | "is_quote_status": false, 1585 | "retweet_count": 4, 1586 | "favorite_count": 65, 1587 | "favorited": false, 1588 | "retweeted": false, 1589 | "lang": "de" 1590 | }, 1591 | "13": { 1592 | "created_at": "Wed Mar 06 19:33:33 +0000 2019", 1593 | "id": 1103378101420081200, 1594 | "id_str": "1103378101420081153", 1595 | "full_text": "@ryanlcooper @get_altText", 1596 | "truncated": false, 1597 | "display_text_range": [13, 25], 1598 | "entities": { 1599 | "hashtags": [], 1600 | "symbols": [], 1601 | "user_mentions": [ 1602 | { 1603 | "screen_name": "ryanlcooper", 1604 | "name": "ryan cooper", 1605 | "id": 214120461, 1606 | "id_str": "214120461", 1607 | "indices": [0, 12] 1608 | }, 1609 | { 1610 | "screen_name": "get_altText", 1611 | "name": "Alt Text Reader", 1612 | "id": 968802481856794600, 1613 | "id_str": "968802481856794624", 1614 | "indices": [13, 25] 1615 | } 1616 | ], 1617 | "urls": [] 1618 | }, 1619 | "source": "Twitter for iPhone", 1620 | "in_reply_to_status_id": 1102617669537284100, 1621 | "in_reply_to_status_id_str": "1102617669537284098", 1622 | "in_reply_to_user_id": 214120461, 1623 | "in_reply_to_user_id_str": "214120461", 1624 | "in_reply_to_screen_name": "ryanlcooper", 1625 | "user": { 1626 | "id": 3058863267, 1627 | "id_str": "3058863267", 1628 | "name": "Kit ♿️", 1629 | "screen_name": "solitaryrainbow", 1630 | "location": "United Kingdom", 1631 | "description": "they/them. queer AF. disabled/autistic/ADHD. wheelchair liberated. parent of three small humans and many cats. rapidly collecting tattoos.", 1632 | "url": null, 1633 | "entities": { "description": { "urls": [] } }, 1634 | "protected": false, 1635 | "followers_count": 480, 1636 | "friends_count": 915, 1637 | "listed_count": 7, 1638 | "created_at": "Tue Feb 24 13:11:51 +0000 2015", 1639 | "favourites_count": 18773, 1640 | "utc_offset": null, 1641 | "time_zone": null, 1642 | "geo_enabled": true, 1643 | "verified": false, 1644 | "statuses_count": 6055, 1645 | "lang": "en", 1646 | "contributors_enabled": false, 1647 | "is_translator": false, 1648 | "is_translation_enabled": false, 1649 | "profile_background_color": "000000", 1650 | "profile_background_image_url": "http://abs.twimg.com/images/themes/theme1/bg.png", 1651 | "profile_background_image_url_https": "https://abs.twimg.com/images/themes/theme1/bg.png", 1652 | "profile_background_tile": false, 1653 | "profile_image_url": "http://pbs.twimg.com/profile_images/967836568349216769/8ujyFi8K_normal.jpg", 1654 | "profile_image_url_https": "https://pbs.twimg.com/profile_images/967836568349216769/8ujyFi8K_normal.jpg", 1655 | "profile_banner_url": "https://pbs.twimg.com/profile_banners/3058863267/1447185535", 1656 | "profile_image_extensions_alt_text": null, 1657 | "profile_banner_extensions_alt_text": null, 1658 | "profile_link_color": "981CEB", 1659 | "profile_sidebar_border_color": "000000", 1660 | "profile_sidebar_fill_color": "000000", 1661 | "profile_text_color": "000000", 1662 | "profile_use_background_image": false, 1663 | "has_extended_profile": false, 1664 | "default_profile": false, 1665 | "default_profile_image": false, 1666 | "following": false, 1667 | "follow_request_sent": false, 1668 | "notifications": false, 1669 | "translator_type": "none" 1670 | }, 1671 | "geo": null, 1672 | "coordinates": null, 1673 | "place": null, 1674 | "contributors": null, 1675 | "is_quote_status": false, 1676 | "retweet_count": 0, 1677 | "favorite_count": 0, 1678 | "favorited": false, 1679 | "retweeted": false, 1680 | "lang": "und" 1681 | } 1682 | } 1683 | -------------------------------------------------------------------------------- /test/censor.js: -------------------------------------------------------------------------------- 1 | const test = require('ava') 2 | const censor = require('../lib/censor') 3 | 4 | test("it returns the original text when there's nothing to censor", (t) => { 5 | t.is( 6 | censor('No reason to change anything about me!'), 7 | 'No reason to change anything about me!' 8 | ) 9 | }) 10 | 11 | test("it ignores the word when it's part of another word", (t) => { 12 | t.is(censor('Medieval'), 'Medieval') 13 | }) 14 | 15 | test('it replaces slurs & other ban-worthy words with a censored version', (t) => { 16 | t.is( 17 | censor('This is kill a normal sentence, nothing die to see kill here.'), 18 | "This is k*ll a normal sentence, nothing d*e to see k*ll here.\n\n(Note from the bot: I had to censor a part of the description to avoid suspension from twitter, I'm sorry.)" 19 | ) 20 | }) 21 | -------------------------------------------------------------------------------- /test/get-reply-text.js: -------------------------------------------------------------------------------- 1 | const test = require('ava') 2 | const testTweets = require('../test-tweets.json') 3 | const getReplyText = require('../lib/get-reply-text') 4 | 5 | const noAltText = "There is no alt text for this image, I'm sorry." 6 | const video = 7 | "This is a video. Unfortunately, twitter doesn't allow to add alt texts for videos yet." 8 | 9 | test('classic flow, with alt text', async (t) => { 10 | const reply = getReplyText(testTweets[1]) 11 | t.is( 12 | await reply, 13 | '@SnoringDoggo Athena the fluffy white and brown cat looks up innocently in front of a plush' 14 | ) 15 | }) 16 | 17 | test('classic flow, no alt text', async (t) => { 18 | const reply = getReplyText(testTweets[2]) 19 | t.is(await reply, `@solitaryrainbow ${noAltText}`) 20 | }) 21 | 22 | test('triggering = original, no alt text', async (t) => { 23 | const reply = getReplyText(testTweets[3]) 24 | t.is(await reply, `@womensart1 ${noAltText}`) 25 | }) 26 | 27 | test('triggering = original, with alt text', async (t) => { 28 | const reply = getReplyText(testTweets[4]) 29 | t.is( 30 | await reply, 31 | '@foxeen Winzige runde Tropfen entlang den fast unsichtbaren Fäden eines Spinnennetzes in Nahaufnahme - manche sind ganz scharf, manche unscharf, aber alle zusammen wirken wie feinste Perlen-Spitze, meisterlich geklöppelt.' 32 | ) 33 | }) 34 | 35 | test('image in quote, alt text', async (t) => { 36 | const reply = getReplyText(testTweets[5]) 37 | t.is( 38 | await reply, 39 | '@SehrysFlausch a tabby cat (@skyescats #OhMyOllie) sits on a chair, with its head looking up over a kitchen table. on the table is an unfinished jigsaw puzzle, the picture also featuring two tabby cats.' 40 | ) 41 | }) 42 | 43 | test('image in quote, no alt text', async (t) => { 44 | const reply = getReplyText(testTweets[6]) 45 | t.is(await reply, `@_cumasyouare_ ${noAltText}`) 46 | }) 47 | 48 | test('no quote, no reply, no image', async (t) => { 49 | const reply = getReplyText(testTweets[7]) 50 | t.is(await reply, undefined) 51 | }) 52 | 53 | test('reply, but no image anywhere', async (t) => { 54 | const reply = getReplyText(testTweets[8]) 55 | t.is(await reply, undefined) 56 | }) 57 | 58 | test('quote, but no image anywhere', async (t) => { 59 | const reply = getReplyText(testTweets[9]) 60 | t.is(await reply, undefined) 61 | }) 62 | 63 | test('image in triggering as well as original', async (t) => { 64 | const reply = getReplyText(testTweets[10]) 65 | t.is( 66 | await reply, 67 | '@malfynnction My new ID, stating that my first name is Fynn and my second name is Julius, everything else - except the photo - is blacked out' 68 | ) 69 | }) 70 | 71 | test('tweet by bot itself', async (t) => { 72 | const reply = getReplyText(testTweets[11]) 73 | t.is(await reply, undefined) 74 | }) 75 | 76 | test('video', async (t) => { 77 | const reply = getReplyText(testTweets[12]) 78 | t.is(await reply, `@souplemur ${video}`) 79 | }) 80 | 81 | test('multiple images', async (t) => { 82 | const reply = getReplyText(testTweets[13]) 83 | t.is( 84 | await reply, 85 | `@solitaryrainbow 1. Picture: ${noAltText}\n2. Picture: ${noAltText}\n3. Picture: ${noAltText}\n` 86 | ) 87 | }) 88 | --------------------------------------------------------------------------------