Browse Source

include HTML for tweets with links or user mentions

also expands parsing to be able to handle twitter JSON from the streaming API which is subtly different from the HTTP API.

closes #61
pull/64/head v1.4.15
Aaron Parecki 6 years ago
parent
commit
fb2fcec9c6
No known key found for this signature in database GPG Key ID: 276C2817346D6056
6 changed files with 784 additions and 20 deletions
  1. +66
    -20
      lib/XRay/Formats/Twitter.php
  2. +37
    -0
      tests/TwitterTest.php
  3. +113
    -0
      tests/data/api.twitter.com/streaming-tweet-truncated.json
  4. +85
    -0
      tests/data/api.twitter.com/streaming-tweet-with-link.json
  5. +105
    -0
      tests/data/api.twitter.com/streaming-tweet-with-mentions.json
  6. +378
    -0
      tests/data/api.twitter.com/tweet-with-truncated-quoted-tweet.json

+ 66
- 20
lib/XRay/Formats/Twitter.php View File

@ -70,12 +70,6 @@ class Twitter extends Format {
);
$refs = [];
// Only use the "display" segment of the text
$text = mb_substr($tweet->full_text,
$tweet->display_text_range[0],
$tweet->display_text_range[1]-$tweet->display_text_range[0],
'UTF-8');
if(property_exists($tweet, 'retweeted_status')) {
// No content for retweets
@ -93,12 +87,7 @@ class Twitter extends Format {
$refs[$repostOf] = $repostedEntry['data'];
} else {
// Twitter escapes & as & in the text
$text = html_entity_decode($text);
$text = self::expandTweetURLs($text, $tweet);
$entry['content'] = ['text' => $text];
$entry['content'] = self::expandTweetContent($tweet);
}
// Published date
@ -209,10 +198,14 @@ class Twitter extends Format {
$author['name'] = $profile->screen_name;
if($profile->url) {
if($profile->entities->url->urls[0]->expanded_url)
$author['url'] = $profile->entities->url->urls[0]->expanded_url;
else
$author['url'] = $profile->entities->url->urls[0]->url;
if(property_exists($profile, 'entities')) {
if($profile->entities->url->urls[0]->expanded_url)
$author['url'] = $profile->entities->url->urls[0]->expanded_url;
else
$author['url'] = $profile->entities->url->urls[0]->url;
} else {
$author['url'] = $profile->url;
}
}
else {
$author['url'] = 'https://twitter.com/' . $profile->screen_name;
@ -223,13 +216,66 @@ class Twitter extends Format {
return $author;
}
private static function expandTweetURLs($text, $object) {
if(property_exists($object, 'entities') && property_exists($object->entities, 'urls')) {
foreach($object->entities->urls as $url) {
private static function expandTweetContent($tweet) {
$entities = new \StdClass;
if(property_exists($tweet, 'truncated') && $tweet->truncated) {
if(property_exists($tweet, 'extended_tweet')) {
$text = $tweet->extended_tweet->full_text;
if(property_exists($tweet->extended_tweet, 'entities')) {
$entities = $tweet->extended_tweet->entities;
}
} else {
$text = $tweet->text;
if(property_exists($tweet, 'entities')) {
$entities = $tweet->entities;
}
}
} else {
// Only use the "display" segment of the text
if(property_exists($tweet, 'full_text')) {
// Only use the "display" segment of the text
$text = mb_substr($tweet->full_text,
$tweet->display_text_range[0],
$tweet->display_text_range[1]-$tweet->display_text_range[0],
'UTF-8');
} else {
$text = $tweet->text;
}
if(property_exists($tweet, 'entities')) {
$entities = $tweet->entities;
}
}
// Twitter escapes & as & in the text
$text = html_entity_decode($text);
$html = $text;
if(property_exists($entities, 'user_mentions')) {
foreach($entities->user_mentions as $user) {
$html = str_replace('@'.$user->screen_name, '<a href="https://twitter.com/'.$user->screen_name.'">@'.$user->screen_name.'</a>', $html);
}
}
if(property_exists($entities, 'urls')) {
foreach($entities->urls as $url) {
$text = str_replace($url->url, $url->expanded_url, $text);
$html = str_replace($url->url, '<a href="'.$url->expanded_url.'">'.$url->expanded_url.'</a>', $html);
}
}
return $text;
$content = [
'text' => $text,
];
if($html != $text)
$content['html'] = $html;
return $content;
}
private static function expandTwitterObjectURLs($text, $object, $key) {

+ 37
- 0
tests/TwitterTest.php View File

@ -174,4 +174,41 @@ class TwitterTest extends PHPUnit_Framework_TestCase {
$this->assertEquals('Yeah that\'s me http://xkcd.com/1782/', $tweet['content']['text']);
}
public function testTruncatedQuotedTweet() {
list($url, $json) = $this->loadTweet('tweet-with-truncated-quoted-tweet');
$data = $this->parse(['url' => $url, 'body' => $json]);
$this->assertEquals('entry', $data['data']['type']);
$this->assertEquals('.@stream_pdx is a real treasure of our city.', $data['data']['content']['text']);
$this->assertEquals('https://twitter.com/PDXStephenG/status/964598574322339841', $data['data']['quotation-of']);
$tweet = $data['data']['refs']['https://twitter.com/PDXStephenG/status/964598574322339841'];
$this->assertEquals('Hey @OregonGovBrown @tedwheeler day 16 of #BHM is for @stream_pdx. An amazing podcast trailer run by @tyeshasnow helping to democratize story telling in #PDX. Folks can get training in the production of podcasts. @siliconflorist #SupportBlackBusiness', $tweet['content']['text']);
$this->assertEquals("Hey <a href=\"https://twitter.com/OregonGovBrown\">@OregonGovBrown</a> <a href=\"https://twitter.com/tedwheeler\">@tedwheeler</a> day 16 of #BHM is for <a href=\"https://twitter.com/stream_pdx\">@stream_pdx</a>. An amazing podcast trailer run by <a href=\"https://twitter.com/tyeshasnow\">@tyeshasnow</a> helping to democratize story telling in #PDX. Folks can get training in the production of podcasts. <a href=\"https://twitter.com/siliconflorist\">@siliconflorist</a> #SupportBlackBusiness", $tweet['content']['html']);
}
public function testStreamingTweetWithLink() {
list($url, $json) = $this->loadTweet('streaming-tweet-with-link');
$data = $this->parse(['url' => $url, 'body' => $json]);
$this->assertEquals('what happens if i include a link like https://kmikeym.com', $data['data']['content']['text']);
$this->assertEquals('what happens if i include a link like <a href="https://kmikeym.com">https://kmikeym.com</a>', $data['data']['content']['html']);
}
public function testStreamingTweetWithMentions() {
list($url, $json) = $this->loadTweet('streaming-tweet-with-mentions');
$data = $this->parse(['url' => $url, 'body' => $json]);
$this->assertEquals('Offer accepted! @aaronpk bought 1 shares from @coledrobison at $6.73 https://kmikeym.com/trades', $data['data']['content']['text']);
$this->assertEquals('Offer accepted! <a href="https://twitter.com/aaronpk">@aaronpk</a> bought 1 shares from <a href="https://twitter.com/coledrobison">@coledrobison</a> at $6.73 <a href="https://kmikeym.com/trades">https://kmikeym.com/trades</a>', $data['data']['content']['html']);
}
public function testStreamingTweetTruncated() {
list($url, $json) = $this->loadTweet('streaming-tweet-truncated');
$data = $this->parse(['url' => $url, 'body' => $json]);
$this->assertEquals("#indieweb community. Really would like to see a Micropub client for Gratitude logging and also a Mastodon poster similar to the twitter one.\nFeel like I could (maybe) rewrite previous open code to do some of this :)", $data['data']['content']['text']);
$this->assertArrayNotHasKey('html', $data['data']['content']);
}
}

+ 113
- 0
tests/data/api.twitter.com/streaming-tweet-truncated.json View File

@ -0,0 +1,113 @@
{
"created_at": "Mon Feb 19 11:13:36 +0000 2018",
"id": 965544896588406784,
"id_str": "965544896588406784",
"text": "#indieweb community. Really would like to see a Micropub client for Gratitude logging and also a Mastodon poster si\u2026 https://t.co/ElywIO64tX",
"source": "<a href=\"http://corebird.baedert.org\" rel=\"nofollow\">Corebird</a>",
"truncated": true,
"in_reply_to_status_id": null,
"in_reply_to_status_id_str": null,
"in_reply_to_user_id": null,
"in_reply_to_user_id_str": null,
"in_reply_to_screen_name": null,
"user": {
"id": 11525,
"id_str": "11525",
"name": "Ian Forrester",
"screen_name": "cubicgarden",
"location": "Manchester, UK",
"url": "http://www.cubicgarden.com",
"description": "Senior firestarter at BBC R&D, emergent technology expert and serial social geek event organiser.",
"translator_type": "none",
"protected": false,
"verified": false,
"followers_count": 5842,
"friends_count": 216,
"listed_count": 383,
"favourites_count": 535,
"statuses_count": 71775,
"created_at": "Sun Nov 05 12:18:48 +0000 2006",
"utc_offset": 0,
"time_zone": "London",
"geo_enabled": true,
"lang": "en",
"contributors_enabled": false,
"is_translator": false,
"profile_background_color": "000000",
"profile_background_image_url": "http://pbs.twimg.com/profile_background_images/824523637/0aa843688f47b92a6d887901b962e10d.jpeg",
"profile_background_image_url_https": "https://pbs.twimg.com/profile_background_images/824523637/0aa843688f47b92a6d887901b962e10d.jpeg",
"profile_background_tile": false,
"profile_link_color": "009999",
"profile_sidebar_border_color": "000000",
"profile_sidebar_fill_color": "006767",
"profile_text_color": "000000",
"profile_use_background_image": true,
"profile_image_url": "http://pbs.twimg.com/profile_images/766757305413148672/f1-y-0Ng_normal.jpg",
"profile_image_url_https": "https://pbs.twimg.com/profile_images/766757305413148672/f1-y-0Ng_normal.jpg",
"profile_banner_url": "https://pbs.twimg.com/profile_banners/11525/1471649200",
"default_profile": false,
"default_profile_image": false,
"following": null,
"follow_request_sent": null,
"notifications": null
},
"geo": null,
"coordinates": null,
"place": null,
"contributors": null,
"is_quote_status": false,
"extended_tweet": {
"full_text": "#indieweb community. Really would like to see a Micropub client for Gratitude logging and also a Mastodon poster similar to the twitter one.\nFeel like I could (maybe) rewrite previous open code to do some of this :)",
"display_text_range": [
0,
215
],
"entities": {
"hashtags": [
{
"text": "indieweb",
"indices": [
0,
9
]
}
],
"urls": [],
"user_mentions": [],
"symbols": []
}
},
"quote_count": 0,
"reply_count": 0,
"retweet_count": 0,
"favorite_count": 0,
"entities": {
"hashtags": [
{
"text": "indieweb",
"indices": [
0,
9
]
}
],
"urls": [
{
"url": "https://t.co/ElywIO64tX",
"expanded_url": "https://twitter.com/i/web/status/965544896588406784",
"display_url": "twitter.com/i/web/status/9\u2026",
"indices": [
117,
140
]
}
],
"user_mentions": [],
"symbols": []
},
"favorited": false,
"retweeted": false,
"filter_level": "low",
"lang": "en",
"timestamp_ms": "1519038816960"
}

+ 85
- 0
tests/data/api.twitter.com/streaming-tweet-with-link.json View File

@ -0,0 +1,85 @@
{
"created_at": "Mon Feb 19 03:27:58 +0000 2018",
"id": 965427716135665664,
"id_str": "965427716135665664",
"text": "what happens if i include a link like https://t.co/ut9caNOtx6",
"source": "<a href=\"http://twitter.com\" rel=\"nofollow\">Twitter Web Client</a>",
"truncated": false,
"in_reply_to_status_id": null,
"in_reply_to_status_id_str": null,
"in_reply_to_user_id": null,
"in_reply_to_user_id_str": null,
"in_reply_to_screen_name": null,
"user": {
"id": 143883456,
"id_str": "143883456",
"name": "aaronpk dev",
"screen_name": "pkdev",
"location": "Portland, OR",
"url": "http://aaronpk.micro.blog/",
"description": "Dev account for testing Twitter things. Follow me here: https://twitter.com/aaronpk",
"translator_type": "none",
"protected": false,
"verified": false,
"followers_count": 1,
"friends_count": 1,
"listed_count": 0,
"favourites_count": 2,
"statuses_count": 56,
"created_at": "Fri May 14 17:47:15 +0000 2010",
"utc_offset": -28800,
"time_zone": "Pacific Time (US & Canada)",
"geo_enabled": true,
"lang": "en",
"contributors_enabled": false,
"is_translator": false,
"profile_background_color": "C0DEED",
"profile_background_image_url": "http://abs.twimg.com/images/themes/theme1/bg.png",
"profile_background_image_url_https": "https://abs.twimg.com/images/themes/theme1/bg.png",
"profile_background_tile": false,
"profile_link_color": "1DA1F2",
"profile_sidebar_border_color": "C0DEED",
"profile_sidebar_fill_color": "DDEEF6",
"profile_text_color": "333333",
"profile_use_background_image": true,
"profile_image_url": "http://pbs.twimg.com/profile_images/638125135904436224/qd_d94Qn_normal.jpg",
"profile_image_url_https": "https://pbs.twimg.com/profile_images/638125135904436224/qd_d94Qn_normal.jpg",
"default_profile": true,
"default_profile_image": false,
"following": null,
"follow_request_sent": null,
"notifications": null
},
"geo": null,
"coordinates": null,
"place": null,
"contributors": null,
"is_quote_status": false,
"quote_count": 0,
"reply_count": 0,
"retweet_count": 0,
"favorite_count": 0,
"entities": {
"hashtags": [],
"urls": [
{
"url": "https://t.co/ut9caNOtx6",
"expanded_url": "https://kmikeym.com",
"display_url": "kmikeym.com",
"indices": [
38,
61
]
}
],
"user_mentions": [],
"symbols": []
},
"favorited": false,
"retweeted": false,
"possibly_sensitive": false,
"filter_level": "low",
"lang": "en",
"timestamp_ms": "1519010878963"
}

+ 105
- 0
tests/data/api.twitter.com/streaming-tweet-with-mentions.json View File

@ -0,0 +1,105 @@
{
"created_at": "Mon Feb 19 04:35:43 +0000 2018",
"id": 965444763569635328,
"id_str": "965444763569635328",
"text": "Offer accepted! @aaronpk bought 1 shares from @coledrobison at $6.73 https://t.co/aALIOaq0Ud",
"source": "<a href=\"http://kmikeym.com\" rel=\"nofollow\">k5m</a>",
"truncated": false,
"in_reply_to_status_id": null,
"in_reply_to_status_id_str": null,
"in_reply_to_user_id": null,
"in_reply_to_user_id_str": null,
"in_reply_to_screen_name": null,
"user": {
"id": 1311430404,
"id_str": "1311430404",
"name": "KmikeyM Trades",
"screen_name": "k5mtrades",
"location": "The Internet",
"url": "http://www.kmikeym.com/trades",
"description": "Tweets about recent trades and other activity on http://www.kmikeym.com",
"translator_type": "none",
"protected": false,
"verified": false,
"followers_count": 58,
"friends_count": 1,
"listed_count": 2,
"favourites_count": 1,
"statuses_count": 6448,
"created_at": "Thu Mar 28 18:51:43 +0000 2013",
"utc_offset": -28800,
"time_zone": "Pacific Time (US & Canada)",
"geo_enabled": false,
"lang": "en",
"contributors_enabled": false,
"is_translator": false,
"profile_background_color": "C0DEED",
"profile_background_image_url": "http://abs.twimg.com/images/themes/theme1/bg.png",
"profile_background_image_url_https": "https://abs.twimg.com/images/themes/theme1/bg.png",
"profile_background_tile": false,
"profile_link_color": "1DA1F2",
"profile_sidebar_border_color": "C0DEED",
"profile_sidebar_fill_color": "DDEEF6",
"profile_text_color": "333333",
"profile_use_background_image": true,
"profile_image_url": "http://pbs.twimg.com/profile_images/3450169500/3e3afb3219d4c43187d3b8752d731170_normal.png",
"profile_image_url_https": "https://pbs.twimg.com/profile_images/3450169500/3e3afb3219d4c43187d3b8752d731170_normal.png",
"default_profile": true,
"default_profile_image": false,
"following": null,
"follow_request_sent": null,
"notifications": null
},
"geo": null,
"coordinates": null,
"place": null,
"contributors": null,
"is_quote_status": false,
"quote_count": 0,
"reply_count": 0,
"retweet_count": 0,
"favorite_count": 0,
"entities": {
"hashtags": [],
"urls": [
{
"url": "https://t.co/aALIOaq0Ud",
"expanded_url": "https://kmikeym.com/trades",
"display_url": "kmikeym.com/trades",
"indices": [
69,
92
]
}
],
"user_mentions": [
{
"screen_name": "aaronpk",
"name": "Aaron Parecki",
"id": 14447132,
"id_str": "14447132",
"indices": [
16,
24
]
},
{
"screen_name": "coledrobison",
"name": "COL\u039e Robison",
"id": 2962255453,
"id_str": "2962255453",
"indices": [
46,
59
]
}
],
"symbols": []
},
"favorited": false,
"retweeted": false,
"possibly_sensitive": false,
"filter_level": "low",
"lang": "en",
"timestamp_ms": "1519014943388"
}

+ 378
- 0
tests/data/api.twitter.com/tweet-with-truncated-quoted-tweet.json View File

@ -0,0 +1,378 @@
{
"created_at": "Mon Feb 19 07:25:44 +0000 2018",
"id": 965487550512054273,
"id_str": "965487550512054273",
"full_text": ".@stream_pdx is a real treasure of our city. https://t.co/twMOevR80T",
"truncated": false,
"display_text_range": [
0,
44
],
"entities": {
"hashtags": [
],
"symbols": [
],
"user_mentions": [
{
"screen_name": "stream_pdx",
"name": "Stream PDX",
"id": 770362395579396097,
"id_str": "770362395579396097",
"indices": [
1,
12
]
}
],
"urls": [
{
"url": "https://t.co/twMOevR80T",
"expanded_url": "https://twitter.com/pdxstepheng/status/964598574322339841",
"display_url": "twitter.com/pdxstepheng/st…",
"indices": [
45,
68
]
}
]
},
"source": "<a href=\"http://twitter.com/download/iphone\" rel=\"nofollow\">Twitter for iPhone</a>",
"in_reply_to_status_id": null,
"in_reply_to_status_id_str": null,
"in_reply_to_user_id": null,
"in_reply_to_user_id_str": null,
"in_reply_to_screen_name": null,
"user": {
"id": 3138466140,
"id_str": "3138466140",
"name": "Rowan Bradley",
"screen_name": "rowbradley",
"location": "Portland, Oregon",
"description": "Photography & Digital Marketing @scoutbooks",
"url": "https://t.co/eBvYQVeMHs",
"entities": {
"url": {
"urls": [
{
"url": "https://t.co/eBvYQVeMHs",
"expanded_url": "http://rowanbradley.com",
"display_url": "rowanbradley.com",
"indices": [
0,
23
]
}
]
},
"description": {
"urls": [
]
}
},
"protected": false,
"followers_count": 436,
"friends_count": 2001,
"listed_count": 33,
"created_at": "Sat Apr 04 05:47:27 +0000 2015",
"favourites_count": 27442,
"utc_offset": -28800,
"time_zone": "Pacific Time (US & Canada)",
"geo_enabled": true,
"verified": false,
"statuses_count": 4833,
"lang": "en",
"contributors_enabled": false,
"is_translator": false,
"is_translation_enabled": false,
"profile_background_color": "000000",
"profile_background_image_url": "http://abs.twimg.com/images/themes/theme1/bg.png",
"profile_background_image_url_https": "https://abs.twimg.com/images/themes/theme1/bg.png",
"profile_background_tile": false,
"profile_image_url": "http://pbs.twimg.com/profile_images/703441818038378499/3pkWJotj_normal.jpg",
"profile_image_url_https": "https://pbs.twimg.com/profile_images/703441818038378499/3pkWJotj_normal.jpg",
"profile_banner_url": "https://pbs.twimg.com/profile_banners/3138466140/1444289891",
"profile_link_color": "4A913C",
"profile_sidebar_border_color": "000000",
"profile_sidebar_fill_color": "000000",
"profile_text_color": "000000",
"profile_use_background_image": false,
"has_extended_profile": false,
"default_profile": false,
"default_profile_image": false,
"following": false,
"follow_request_sent": false,
"notifications": false,
"translator_type": "none"
},
"geo": null,
"coordinates": null,
"place": null,
"contributors": null,
"is_quote_status": true,
"quoted_status_id": 964598574322339841,
"quoted_status_id_str": "964598574322339841",
"quoted_status": {
"created_at": "Fri Feb 16 20:33:16 +0000 2018",
"id": 964598574322339841,
"id_str": "964598574322339841",
"full_text": "Hey @OregonGovBrown @tedwheeler day 16 of #BHM is for @stream_pdx. An amazing podcast trailer run by @tyeshasnow helping to democratize story telling in #PDX. Folks can get training in the production of podcasts. @siliconflorist #SupportBlackBusiness https://t.co/dvWAMrzffF",
"truncated": false,
"display_text_range": [
0,
250
],
"entities": {
"hashtags": [
{
"text": "BHM",
"indices": [
42,
46
]
},
{
"text": "PDX",
"indices": [
153,
157
]
},
{
"text": "SupportBlackBusiness",
"indices": [
229,
250
]
}
],
"symbols": [
],
"user_mentions": [
{
"screen_name": "OregonGovBrown",
"name": "Governor Kate Brown",
"id": 3023272478,
"id_str": "3023272478",
"indices": [
4,
19
]
},
{
"screen_name": "tedwheeler",
"name": "Ted Wheeler",
"id": 18708561,
"id_str": "18708561",
"indices": [
20,
31
]
},
{
"screen_name": "stream_pdx",
"name": "Stream PDX",
"id": 770362395579396097,
"id_str": "770362395579396097",
"indices": [
54,
65
]
},
{
"screen_name": "tyeshasnow",
"name": "tyesha snow",
"id": 21260096,
"id_str": "21260096",
"indices": [
101,
112
]
},
{
"screen_name": "siliconflorist",
"name": "Silicon Florist",
"id": 8072912,
"id_str": "8072912",
"indices": [
213,
228
]
}
],
"urls": [
],
"media": [
{
"id": 964598550842826752,
"id_str": "964598550842826752",
"indices": [
251,
274
],
"media_url": "http://pbs.twimg.com/media/DWLxRXXX4AAgn2K.jpg",
"media_url_https": "https://pbs.twimg.com/media/DWLxRXXX4AAgn2K.jpg",
"url": "https://t.co/dvWAMrzffF",
"display_url": "pic.twitter.com/dvWAMrzffF",
"expanded_url": "https://twitter.com/PDXStephenG/status/964598574322339841/photo/1",
"type": "photo",
"sizes": {
"large": {
"w": 1800,
"h": 530,
"resize": "fit"
},
"thumb": {
"w": 150,
"h": 150,
"resize": "crop"
},
"medium": {
"w": 1200,
"h": 353,
"resize": "fit"
},
"small": {
"w": 680,
"h": 200,
"resize": "fit"
}
}
}
]
},
"extended_entities": {
"media": [
{
"id": 964598550842826752,
"id_str": "964598550842826752",
"indices": [
251,
274
],
"media_url": "http://pbs.twimg.com/media/DWLxRXXX4AAgn2K.jpg",
"media_url_https": "https://pbs.twimg.com/media/DWLxRXXX4AAgn2K.jpg",
"url": "https://t.co/dvWAMrzffF",
"display_url": "pic.twitter.com/dvWAMrzffF",
"expanded_url": "https://twitter.com/PDXStephenG/status/964598574322339841/photo/1",
"type": "photo",
"sizes": {
"large": {
"w": 1800,
"h": 530,
"resize": "fit"
},
"thumb": {
"w": 150,
"h": 150,
"resize": "crop"
},
"medium": {
"w": 1200,
"h": 353,
"resize": "fit"
},
"small": {
"w": 680,
"h": 200,
"resize": "fit"
}
}
}
]
},
"source": "<a href=\"http://twitter.com\" rel=\"nofollow\">Twitter Web Client</a>",
"in_reply_to_status_id": null,
"in_reply_to_status_id_str": null,
"in_reply_to_user_id": null,
"in_reply_to_user_id_str": null,
"in_reply_to_screen_name": null,
"user": {
"id": 518975229,
"id_str": "518975229",
"name": "Stephen Green",
"screen_name": "PDXStephenG",
"location": "Portland, OR",
"description": "Blatino, husband, dad, entrepreneur, economist, TEDx talker & recovering banker/vc. Day job, Community Director at @WeWork. #Startup advisor @backstage_cap",
"url": "https://t.co/DNQHGaIJWP",
"entities": {
"url": {
"urls": [
{
"url": "https://t.co/DNQHGaIJWP",
"expanded_url": "http://www.pitchblackpdx.com",
"display_url": "pitchblackpdx.com",
"indices": [
0,
23
]
}
]
},
"description": {
"urls": [
]
}
},
"protected": false,
"followers_count": 8958,
"friends_count": 9790,
"listed_count": 404,
"created_at": "Thu Mar 08 23:12:01 +0000 2012",
"favourites_count": 12352,
"utc_offset": -28800,
"time_zone": "Pacific Time (US & Canada)",
"geo_enabled": true,
"verified": false,
"statuses_count": 7506,
"lang": "en",
"contributors_enabled": false,
"is_translator": false,
"is_translation_enabled": false,
"profile_background_color": "000000",
"profile_background_image_url": "http://abs.twimg.com/images/themes/theme1/bg.png",
"profile_background_image_url_https": "https://abs.twimg.com/images/themes/theme1/bg.png",
"profile_background_tile": false,
"profile_image_url": "http://pbs.twimg.com/profile_images/882333395287658497/KpZZzrI9_normal.jpg",
"profile_image_url_https": "https://pbs.twimg.com/profile_images/882333395287658497/KpZZzrI9_normal.jpg",
"profile_banner_url": "https://pbs.twimg.com/profile_banners/518975229/1511838336",
"profile_link_color": "19CF86",
"profile_sidebar_border_color": "000000",
"profile_sidebar_fill_color": "000000",
"profile_text_color": "000000",
"profile_use_background_image": false,
"has_extended_profile": false,
"default_profile": false,
"default_profile_image": false,
"following": false,
"follow_request_sent": false,
"notifications": false,
"translator_type": "none"
},
"geo": null,
"coordinates": null,
"place": null,
"contributors": null,
"is_quote_status": false,
"retweet_count": 10,
"favorite_count": 22,
"favorited": false,
"retweeted": false,
"possibly_sensitive": false,
"possibly_sensitive_appealable": false,
"lang": "en"
},
"retweet_count": 0,
"favorite_count": 1,
"favorited": false,
"retweeted": false,
"possibly_sensitive": false,
"possibly_sensitive_appealable": false,
"lang": "en"
}

Loading…
Cancel
Save