From 568bc51248dc9175b1800a2147a26f515a4c1830 Mon Sep 17 00:00:00 2001 From: Aaron Parecki Date: Sun, 10 Mar 2024 13:25:52 -0700 Subject: [PATCH] remove twitter --- README.md | 19 +- lib/XRay/Fetcher.php | 24 - lib/XRay/Formats/Twitter.php | 344 ------------- lib/XRay/Parser.php | 4 - tests/LibraryTest.php | 25 - tests/TwitterTest.php | 332 ------------ .../api.twitter.com/719914707566649344.json | 166 ------ .../api.twitter.com/791704641046052864.json | 191 ------- .../api.twitter.com/818912506496229376.json | 227 --------- .../api.twitter.com/818913178260160512.json | 262 ---------- .../api.twitter.com/818913351623245824.json | 482 ------------------ .../api.twitter.com/818913488609251331.json | 431 ---------------- .../api.twitter.com/818913630569664512.json | 177 ------- .../api.twitter.com/818928092383166465.json | 147 ------ .../api.twitter.com/818935308813103104.json | 263 ---------- .../api.twitter.com/818943244553699328.json | 147 ------ .../api.twitter.com/820039442773798912.json | 393 -------------- .../api.twitter.com/967046438822674432.json | 120 ----- .../streaming-tweet-reply.json | 110 ---- .../streaming-tweet-truncated-with-photo.json | 434 ---------------- .../streaming-tweet-truncated-with-video.json | 290 ----------- .../streaming-tweet-truncated.json | 113 ---- .../streaming-tweet-with-link.json | 85 --- .../streaming-tweet-with-mentions.json | 105 ---- .../data/api.twitter.com/tweet-with-gif.json | 206 -------- .../data/api.twitter.com/tweet-with-html.json | 113 ---- .../api.twitter.com/tweet-with-newlines.json | 318 ------------ .../tweet-with-truncated-quoted-tweet.json | 378 -------------- 28 files changed, 4 insertions(+), 5902 deletions(-) delete mode 100644 lib/XRay/Formats/Twitter.php delete mode 100644 tests/TwitterTest.php delete mode 100644 tests/data/api.twitter.com/719914707566649344.json delete mode 100644 tests/data/api.twitter.com/791704641046052864.json delete mode 100644 tests/data/api.twitter.com/818912506496229376.json delete mode 100644 tests/data/api.twitter.com/818913178260160512.json delete mode 100644 tests/data/api.twitter.com/818913351623245824.json delete mode 100644 tests/data/api.twitter.com/818913488609251331.json delete mode 100644 tests/data/api.twitter.com/818913630569664512.json delete mode 100644 tests/data/api.twitter.com/818928092383166465.json delete mode 100644 tests/data/api.twitter.com/818935308813103104.json delete mode 100644 tests/data/api.twitter.com/818943244553699328.json delete mode 100644 tests/data/api.twitter.com/820039442773798912.json delete mode 100644 tests/data/api.twitter.com/967046438822674432.json delete mode 100644 tests/data/api.twitter.com/streaming-tweet-reply.json delete mode 100644 tests/data/api.twitter.com/streaming-tweet-truncated-with-photo.json delete mode 100644 tests/data/api.twitter.com/streaming-tweet-truncated-with-video.json delete mode 100644 tests/data/api.twitter.com/streaming-tweet-truncated.json delete mode 100644 tests/data/api.twitter.com/streaming-tweet-with-link.json delete mode 100644 tests/data/api.twitter.com/streaming-tweet-with-mentions.json delete mode 100644 tests/data/api.twitter.com/tweet-with-gif.json delete mode 100644 tests/data/api.twitter.com/tweet-with-html.json delete mode 100644 tests/data/api.twitter.com/tweet-with-newlines.json delete mode 100644 tests/data/api.twitter.com/tweet-with-truncated-quoted-tweet.json diff --git a/README.md b/README.md index 1292146..980c53a 100644 --- a/README.md +++ b/README.md @@ -8,7 +8,6 @@ XRay parses structured content from a URL. XRay will parse content in the following formats. First the URL is checked against known services: -* Twitter * GitHub * XKCD * Hackernews @@ -68,7 +67,7 @@ In both cases, you can add an additional parameter to configure various options * `expect=feed` - If you know the thing you are parsing is a feed, include this parameter which will avoid running the autodetection rules and will provide better results for some feeds. * `accept` - (options: `html`, `json`, `activitypub`, `xml`) - Without this parameter, XRay sends a default `Accept` header to prioritize getting the most likely best result from a page. If you are parsing a page for a specific purpose and expect to find only one type of content (e.g. webmentions will probably only be from HTML pages), you can include this parameter to adjust the `Accept` header XRay sends. -Additional parameters are supported when making requests that use the Twitter or GitHub API. See the Authentication section below for details. +Additional parameters are supported when making requests that use the GitHub API. See the Authentication section below for details. The XRay constructor can optionally be passed an array of default options, which will be applied in addition to (and can be overridden by) the options passed to individual `parse()` calls. @@ -249,7 +248,7 @@ url=https://aaronparecki.com/2016/01/16/11/ &body=.... ``` -or for Twitter/GitHub where you might have JSON, +or for GitHub where you might have JSON, ``` POST /parse @@ -286,19 +285,9 @@ url=https://aaronparecki.com/2016/01/16/11/ ### API Authentication -XRay uses the Twitter and Github APIs to fetch posts, and those API require authentication. In order to keep XRay stateless, it is required that you pass in the credentials to the parse call. +XRay uses the Github APIs to fetch posts, and those API require authentication. In order to keep XRay stateless, it is required that you pass in the credentials to the parse call. -You should only send the credentials when the URL you are trying to parse is a Twitter URL or a GitHub URL, so you'll want to check for whether the hostname is `twitter.com`, `github.com`, etc. before you include credentials in this call. - - -#### Twitter Authentication - -XRay uses the Twitter API to fetch Twitter URLs. You can register an application on the Twitter developer website, and generate an access token for your account without writing any code, and then use those credentials when making an API request to XRay. - -* `twitter_api_key` - Your application's API key -* `twitter_api_secret` - Your application's API secret -* `twitter_access_token` - Your Twitter access token -* `twitter_access_token_secret` - Your Twitter secret access token +You should only send the credentials when the URL you are trying to parse is a GitHub URL, so you'll want to check for whether the hostname is `github.com`, etc. before you include credentials in this call. #### GitHub Authentication diff --git a/lib/XRay/Fetcher.php b/lib/XRay/Fetcher.php index c4cdd07..3231fb4 100644 --- a/lib/XRay/Fetcher.php +++ b/lib/XRay/Fetcher.php @@ -38,11 +38,6 @@ class Fetcher { $url = normalize_url($url); $host = parse_url($url, PHP_URL_HOST); - // Check if this is a Twitter URL and use the API - if(Formats\Twitter::matches_host($url)) { - return $this->_fetch_tweet($url, $opts); - } - // Transform the HTML GitHub URL into an GitHub API request and fetch the API response if(Formats\GitHub::matches_host($url)) { return $this->_fetch_github($url, $opts); @@ -164,25 +159,6 @@ class Fetcher { ]; } - private function _fetch_tweet($url, $opts) { - $fields = ['twitter_api_key','twitter_api_secret','twitter_access_token','twitter_access_token_secret']; - $creds = []; - foreach($fields as $f) { - if(isset($opts[$f])) - $creds[$f] = $opts[$f]; - } - - if(count($creds) < 4) { - return [ - 'error_code' => 400, - 'error' => 'missing_parameters', - 'error_description' => 'All 4 Twitter credentials must be included in the request' - ]; - } - - return Formats\Twitter::fetch($url, $creds); - } - private function _fetch_github($url, $opts) { $fields = ['github_access_token']; $creds = []; diff --git a/lib/XRay/Formats/Twitter.php b/lib/XRay/Formats/Twitter.php deleted file mode 100644 index fdae499..0000000 --- a/lib/XRay/Formats/Twitter.php +++ /dev/null @@ -1,344 +0,0 @@ -request('statuses/show/'.$tweet_id, 'GET', ['tweet_mode'=>'extended']); - } catch(\TwitterException $e) { - return [ - 'error' => 'twitter_error', - 'error_description' => $e->getMessage() - ]; - } - - return [ - 'url' => $url, - 'body' => $tweet, - 'code' => 200, - ]; - } - - public static function parse($http_response) { - $json = is_array($http_response) ? $http_response['body'] : $http_response->body; - $url = is_array($http_response) ? $http_response['url'] : $http_response->url; - - if(is_string($json)) - $tweet = json_decode($json); - else - $tweet = $json; - - if(!$tweet) { - return self::_unknown(); - } - - $entry = array( - 'type' => 'entry', - 'url' => $url, - 'author' => [ - 'type' => 'card', - 'name' => null, - 'nickname' => null, - 'photo' => null, - 'url' => null, - ] - ); - $refs = []; - - if(property_exists($tweet, 'retweeted_status')) { - // No content for retweets - - $reposted = $tweet->retweeted_status; - $repostOf = 'https://twitter.com/' . $reposted->user->screen_name . '/status/' . $reposted->id_str; - $entry['repost-of'] = $repostOf; - - $repostedEntry = self::parse(['body' => $reposted, 'url' => $repostOf]); - if(isset($repostedEntry['data']['refs'])) { - foreach($repostedEntry['data']['refs'] as $k=>$v) { - $refs[$k] = $v; - } - } - - $refs[$repostOf] = $repostedEntry['data']; - - } else { - $entry['content'] = self::expandTweetContent($tweet); - } - - // Published date - $published = new DateTime($tweet->created_at); - if(property_exists($tweet->user, 'utc_offset')) { - $tz = new DateTimeZone(sprintf('%+d', $tweet->user->utc_offset / 3600)); - $published->setTimeZone($tz); - } - $entry['published'] = $published->format('c'); - - // Hashtags - if(property_exists($tweet, 'entities') && property_exists($tweet->entities, 'hashtags')) { - if(count($tweet->entities->hashtags)) { - $entry['category'] = []; - foreach($tweet->entities->hashtags as $hashtag) { - $entry['category'][] = $hashtag->text; - } - } - } - - // In-Reply-To - if(property_exists($tweet, 'in_reply_to_status_id_str') && $tweet->in_reply_to_status_id_str) { - $entry['in-reply-to'] = [ - 'https://twitter.com/'.$tweet->in_reply_to_screen_name.'/status/'.$tweet->in_reply_to_status_id_str - ]; - } - - // Don't include the RT'd photo or video in the main object. - // They get included in the reposted object instead. - if(!property_exists($tweet, 'retweeted_status')) { - // Photos and Videos - if(property_exists($tweet, 'extended_entities') && property_exists($tweet->extended_entities, 'media')) { - foreach($tweet->extended_entities->media as $media) { - self::extractMedia($media, $entry); - } - } - - // Photos from Streaming API Tweets - if(property_exists($tweet, 'extended_tweet')) { - if(property_exists($tweet->extended_tweet, 'entities') && property_exists($tweet->extended_tweet->entities, 'media')) { - foreach($tweet->extended_tweet->entities->media as $media) { - self::extractMedia($media, $entry); - } - } - } - - // Place - if(property_exists($tweet, 'place') && $tweet->place) { - $place = $tweet->place; - if($place->place_type == 'city') { - $entry['location'] = $place->url; - $refs[$place->url] = [ - 'type' => 'adr', - 'name' => $place->full_name, - 'locality' => $place->name, - 'country-name' => $place->country, - ]; - } - } - } - - // Quoted Status - if(property_exists($tweet, 'quoted_status')) { - $quoteOf = 'https://twitter.com/' . $tweet->quoted_status->user->screen_name . '/status/' . $tweet->quoted_status_id_str; - $quotedEntry = self::parse(['body' => $tweet->quoted_status, 'url' => $quoteOf]); - if(isset($quotedEntry['data']['refs'])) { - foreach($quotedEntry['data']['refs'] as $k=>$v) { - $refs[$k] = $v; - } - } - $refs[$quoteOf] = $quotedEntry['data']; - $entry['quotation-of'] = $quoteOf; - } - - if($author = self::_buildHCardFromTwitterProfile($tweet->user)) { - $entry['author'] = $author; - } - - if(count($refs)) { - $entry['refs'] = $refs; - } - - $entry['post-type'] = \p3k\XRay\PostType::discover($entry); - - return [ - 'data' => $entry, - 'original' => $tweet, - 'source-format' => 'twitter', - ]; - } - - private static function extractMedia($media, &$entry) { - if($media->type == 'photo') { - if(!array_key_exists('photo', $entry)) - $entry['photo'] = []; - - $entry['photo'][] = $media->media_url_https; - - } elseif($media->type == 'video' || $media->type == 'animated_gif') { - if(!array_key_exists('photo', $entry)) - $entry['photo'] = []; - - if(!array_key_exists('video', $entry)) - $entry['video'] = []; - - // Include the thumbnail - $entry['photo'][] = $media->media_url_https; - - // Find the highest bitrate video that is mp4 - $videos = $media->video_info->variants; - $videos = array_filter($videos, function($v) { - return property_exists($v, 'bitrate') && $v->content_type == 'video/mp4'; - }); - if(count($videos)) { - usort($videos, function($a,$b) { - return $a->bitrate < $b->bitrate; - }); - $entry['video'][] = $videos[0]->url; - } - } - } - - private static function _buildHCardFromTwitterProfile($profile) { - if(!$profile) return false; - - $author = [ - 'type' => 'card' - ]; - - $author['nickname'] = $profile->screen_name; - $author['location'] = $profile->location; - $author['bio'] = self::expandTwitterObjectURLs($profile->description, $profile, 'description'); - - if($profile->name) - $author['name'] = $profile->name; - else - $author['name'] = $profile->screen_name; - - $author['url'] = 'https://twitter.com/' . $profile->screen_name; - - $author['photo'] = $profile->profile_image_url_https; - - return $author; - } - - 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; - - $text = mb_substr($text, - $tweet->extended_tweet->display_text_range[0], - $tweet->extended_tweet->display_text_range[1]-$tweet->extended_tweet->display_text_range[0], - 'UTF-8'); - - 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 = htmlspecialchars($text); - $html = str_replace("\n", "
\n", $html); - - if(property_exists($entities, 'user_mentions')) { - foreach($entities->user_mentions as $user) { - $html = str_replace('@'.$user->screen_name, '@'.$user->screen_name.'', $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, ''.$url->expanded_url.'', $html); - } - } - - $content = [ - 'text' => $text, - ]; - - if($html != $text) - $content['html'] = $html; - - return $content; - } - - private static function expandTwitterObjectURLs($text, $object, $key) { - if(property_exists($object, 'entities') - && property_exists($object->entities, $key) - && property_exists($object->entities->{$key}, 'urls')) { - foreach($object->entities->{$key}->urls as $url) { - $text = str_replace($url->url, $url->expanded_url, $text); - } - } - return $text; - } - - /** - * Converts base 60 to base 10, with error checking - * http://tantek.pbworks.com/NewBase60 - * @param string $s - * @return int - */ - function b60to10($s) - { - $n = 0; - for($i = 0; $i < strlen($s); $i++) // iterate from first to last char of $s - { - $c = ord($s[$i]); // put current ASCII of char into $c - if ($c>=48 && $c<=57) { $c=bcsub($c,48); } - else if ($c>=65 && $c<=72) { $c=bcsub($c,55); } - else if ($c==73 || $c==108) { $c=1; } // typo capital I, lowercase l to 1 - else if ($c>=74 && $c<=78) { $c=bcsub($c,56); } - else if ($c==79) { $c=0; } // error correct typo capital O to 0 - else if ($c>=80 && $c<=90) { $c=bcsub($c,57); } - else if ($c==95) { $c=34; } // underscore - else if ($c>=97 && $c<=107) { $c=bcsub($c,62); } - else if ($c>=109 && $c<=122) { $c=bcsub($c,63); } - else { $c = 0; } // treat all other noise as 0 - $n = bcadd(bcmul(60, $n), $c); - } - return $n; - } - -} diff --git a/lib/XRay/Parser.php b/lib/XRay/Parser.php index f7b405d..952c6ff 100644 --- a/lib/XRay/Parser.php +++ b/lib/XRay/Parser.php @@ -83,10 +83,6 @@ class Parser { return Formats\GitHub::parse($http_response); } - if(Formats\Twitter::matches($url)) { - return Formats\Twitter::parse($http_response); - } - if(Formats\XKCD::matches($url)) { return Formats\XKCD::parse($http_response); } diff --git a/tests/LibraryTest.php b/tests/LibraryTest.php index 3252faa..3218bbd 100644 --- a/tests/LibraryTest.php +++ b/tests/LibraryTest.php @@ -109,29 +109,4 @@ class LibraryTest extends PHPUnit\Framework\TestCase ); } - public function testDefaultOptionsAreUsedForFetching() - { - // LibraryTest::testDefaultOptionsAreUsed can only test that default options are merged and passed - // to the relevant format handler. To test that they’re additionally passed to the fetcher currently - // requires a network request to the twitter API for an auth error. - // A potential future improvement for this would be to make a new mock HTTP client object which - // accepts a callback, which gets passed the request it would send. We can then check that the - // request has the parameters we want without having to actually hit the network. - $url = 'https://twitter.com/BarnabyWalters/status/990659593561952256'; - - // Confirm the expected behaviour. - $xray = new p3k\XRay(); - $result = $xray->parse($url); - $this->assertEquals('missing_parameters', $result['error']); - - $xray = new p3k\XRay([ - 'twitter_api_key' => 'extremely real API credentials', - 'twitter_api_secret' => 'extremely real API credentials', - 'twitter_access_token' => 'extremely real API credentials', - 'twitter_access_token_secret' => 'extremely real API credentials' - ]); - $result = $xray->parse($url); - $this->assertEquals('twitter_error', $result['error']); - } - } diff --git a/tests/TwitterTest.php b/tests/TwitterTest.php deleted file mode 100644 index f54d9d6..0000000 --- a/tests/TwitterTest.php +++ /dev/null @@ -1,332 +0,0 @@ -client = new Parse(); - $this->client->mc = null; - } - - private function parse($params) - { - $request = new Request($params); - $response = new Response(); - $result = $this->client->parse($request, $response); - $body = $result->getContent(); - $this->assertEquals(200, $result->getStatusCode()); - return json_decode($body, true); - } - - private function loadTweet($id) - { - $url = 'https://twitter.com/_/status/'.$id; - $json = file_get_contents(dirname(__FILE__).'/data/api.twitter.com/'.$id.'.json'); - $parsed = json_decode($json); - $url = 'https://twitter.com/'.$parsed->user->screen_name.'/status/'.$id; - return [$url, $json]; - } - - public function testBasicProfileInfo() - { - list($url, $json) = $this->loadTweet('818912506496229376'); - - $data = $this->parse(['url' => $url, 'body' => $json]); - - $this->assertEquals('twitter', $data['source-format']); - - $this->assertEquals('entry', $data['data']['type']); - $this->assertEquals('aaronpk dev', $data['data']['author']['name']); - $this->assertEquals('pkdev', $data['data']['author']['nickname']); - $this->assertEquals('https://twitter.com/pkdev', $data['data']['author']['url']); - $this->assertEquals('Portland, OR', $data['data']['author']['location']); - $this->assertEquals('Dev account for testing Twitter things. Follow me here: https://twitter.com/aaronpk', $data['data']['author']['bio']); - $this->assertEquals('https://pbs.twimg.com/profile_images/638125135904436224/qd_d94Qn_normal.jpg', $data['data']['author']['photo']); - } - - public function testProfileWithNonExpandedURL() - { - list($url, $json) = $this->loadTweet('791704641046052864'); - - $data = $this->parse(['url' => $url, 'body' => $json]); - - $this->assertEquals('https://twitter.com/agiletortoise', $data['data']['author']['url']); - } - - public function testBasicTestStuff() - { - list($url, $json) = $this->loadTweet('818913630569664512'); - - $data = $this->parse(['url' => $url, 'body' => $json]); - - $this->assertEquals(null, $data['code']); // no code is expected if we pass in the body - $this->assertEquals('twitter', $data['source-format']); - - $this->assertEquals('https://twitter.com/pkdev/status/818913630569664512', $data['url']); - $this->assertEquals('entry', $data['data']['type']); - $this->assertEquals('note', $data['data']['post-type']); - $this->assertEquals('A tweet with a URL https://indieweb.org/ #and #some #hashtags', $data['data']['content']['text']); - $this->assertContains('and', $data['data']['category']); - $this->assertContains('some', $data['data']['category']); - $this->assertContains('hashtags', $data['data']['category']); - // Published date should be set to the timezone of the user - $this->assertEquals('2017-01-10T12:13:18-08:00', $data['data']['published']); - } - - public function testPositiveTimezone() - { - list($url, $json) = $this->loadTweet('719914707566649344'); - - $data = $this->parse(['url' => $url, 'body' => $json]); - $this->assertEquals("2016-04-12T16:46:56+01:00", $data['data']['published']); - } - - public function testTweetWithEmoji() - { - list($url, $json) = $this->loadTweet('818943244553699328'); - - $data = $this->parse(['url' => $url, 'body' => $json]); - - $this->assertEquals('twitter', $data['source-format']); - $this->assertEquals('entry', $data['data']['type']); - $this->assertEquals('Here 🎉 have an emoji', $data['data']['content']['text']); - } - - public function testHTMLEscaping() - { - list($url, $json) = $this->loadTweet('818928092383166465'); - - $data = $this->parse(['url' => $url, 'body' => $json]); - - $this->assertEquals('entry', $data['data']['type']); - $this->assertEquals('Double escaping & & amp', $data['data']['content']['text']); - } - - public function testTweetWithPhoto() - { - list($url, $json) = $this->loadTweet('818912506496229376'); - - $data = $this->parse(['url' => $url, 'body' => $json]); - - $this->assertEquals('entry', $data['data']['type']); - $this->assertEquals('photo', $data['data']['post-type']); - $this->assertEquals('Tweet with a photo and a location', $data['data']['content']['text']); - $this->assertEquals('https://pbs.twimg.com/media/C11cfRJUoAI26h9.jpg', $data['data']['photo'][0]); - } - - public function testTweetWithTwoPhotos() - { - list($url, $json) = $this->loadTweet('818935308813103104'); - - $data = $this->parse(['url' => $url, 'body' => $json]); - - $this->assertEquals('entry', $data['data']['type']); - $this->assertEquals('photo', $data['data']['post-type']); - $this->assertEquals('Two photos', $data['data']['content']['text']); - $this->assertContains('https://pbs.twimg.com/media/C11xS1wUcAAeaKF.jpg', $data['data']['photo']); - $this->assertContains('https://pbs.twimg.com/media/C11wtndUoAE1WfE.jpg', $data['data']['photo']); - } - - public function testTweetWithVideo() - { - list($url, $json) = $this->loadTweet('818913178260160512'); - - $data = $this->parse(['url' => $url, 'body' => $json]); - - $this->assertEquals('entry', $data['data']['type']); - $this->assertEquals('video', $data['data']['post-type']); - $this->assertEquals('Tweet with a video', $data['data']['content']['text']); - $this->assertEquals('https://pbs.twimg.com/ext_tw_video_thumb/818913089248595970/pr/img/qVoEjF03Y41SKpNt.jpg', $data['data']['photo'][0]); - $this->assertEquals('https://video.twimg.com/ext_tw_video/818913089248595970/pr/vid/1280x720/qP-sDx-Q0Hs-ckVv.mp4', $data['data']['video'][0]); - } - - public function testTweetWithGif() - { - list($url, $json) = $this->loadTweet('tweet-with-gif'); - - $data = $this->parse(['url' => $url, 'body' => $json]); - - $this->assertEquals('entry', $data['data']['type']); - $this->assertEquals('reply', $data['data']['post-type']); - $this->assertEquals('https://twitter.com/SwiftOnSecurity/status/1018178408398966784', $data['data']['in-reply-to'][0]); - $this->assertEquals('Look! A distraction 🐁', $data['data']['content']['text']); - $this->assertEquals('https://video.twimg.com/tweet_video/DiFOUuYV4AAUsgL.mp4', $data['data']['video'][0]); - $this->assertEquals('https://pbs.twimg.com/tweet_video_thumb/DiFOUuYV4AAUsgL.jpg', $data['data']['photo'][0]); - } - - public function testTweetWithLocation() - { - list($url, $json) = $this->loadTweet('818912506496229376'); - - $data = $this->parse(['url' => $url, 'body' => $json]); - - $this->assertEquals('entry', $data['data']['type']); - $this->assertEquals('Tweet with a photo and a location', $data['data']['content']['text']); - $this->assertEquals('https://api.twitter.com/1.1/geo/id/ac88a4f17a51c7fc.json', $data['data']['location']); - $location = $data['data']['refs']['https://api.twitter.com/1.1/geo/id/ac88a4f17a51c7fc.json']; - $this->assertEquals('adr', $location['type']); - $this->assertEquals('Portland', $location['locality']); - $this->assertEquals('United States', $location['country-name']); - $this->assertEquals('Portland, OR', $location['name']); - } - - public function testRetweet() - { - list($url, $json) = $this->loadTweet('818913351623245824'); - - $data = $this->parse(['url' => $url, 'body' => $json]); - - $this->assertEquals('twitter', $data['source-format']); - $this->assertEquals('entry', $data['data']['type']); - $this->assertEquals('repost', $data['data']['post-type']); - $this->assertArrayNotHasKey('content', $data['data']); - $repostOf = 'https://twitter.com/aaronpk/status/817414679131660288'; - $this->assertEquals($repostOf, $data['data']['repost-of']); - $tweet = $data['data']['refs'][$repostOf]; - $this->assertEquals('Yeah that\'s me http://xkcd.com/1782/', $tweet['content']['text']); - } - - public function testRetweetWithPhoto() - { - list($url, $json) = $this->loadTweet('820039442773798912'); - - $data = $this->parse(['url' => $url, 'body' => $json]); - - $this->assertEquals('entry', $data['data']['type']); - $this->assertEquals('repost', $data['data']['post-type']); - $this->assertArrayNotHasKey('content', $data['data']); - $this->assertArrayNotHasKey('photo', $data['data']); - $repostOf = 'https://twitter.com/phlaimeaux/status/819943954724556800'; - $this->assertEquals($repostOf, $data['data']['repost-of']); - $tweet = $data['data']['refs'][$repostOf]; - $this->assertEquals('this headline is such a rollercoaster', $tweet['content']['text']); - } - - public function testQuotedTweet() - { - list($url, $json) = $this->loadTweet('818913488609251331'); - - $data = $this->parse(['url' => $url, 'body' => $json]); - - $this->assertEquals('entry', $data['data']['type']); - $this->assertEquals('note', $data['data']['post-type']); - $this->assertEquals('Quoted tweet with a #hashtag https://twitter.com/aaronpk/status/817414679131660288', $data['data']['content']['text']); - $this->assertEquals('https://twitter.com/aaronpk/status/817414679131660288', $data['data']['quotation-of']); - $tweet = $data['data']['refs']['https://twitter.com/aaronpk/status/817414679131660288']; - $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 @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']['html']); - } - - public function testTweetWithHTML() - { - list($url, $json) = $this->loadTweet('tweet-with-html'); - - $data = $this->parse(['url' => $url, 'body' => $json]); - - $this->assertStringContainsString('