+/**
+ * Parse Twitter status URLs since Twitter removed OEmbed
+ *
+ * @param App $a
+ * @param array $b Expected format:
+ * [
+ * 'url' => [URL to parse],
+ * 'format' => 'json'|'',
+ * 'text' => Output parameter
+ * ]
+ * @throws \Friendica\Network\HTTPException\InternalServerErrorException
+ */
+function twitter_parse_link(App $a, array &$b)
+{
+ // Only handle Twitter status URLs
+ if (!preg_match('#^https?://(?:mobile\.|www\.)?twitter.com/[^/]+/status/(\d+).*#', $b['url'], $matches)) {
+ return;
+ }
+
+ $ckey = DI::config()->get('twitter', 'consumerkey');
+ $csecret = DI::config()->get('twitter', 'consumersecret');
+
+ if (empty($ckey) || empty($csecret)) {
+ return;
+ }
+
+ $connection = new TwitterOAuth($ckey, $csecret);
+
+ $parameters = ['trim_user' => false, 'tweet_mode' => 'extended', 'id' => $matches[1], 'include_ext_alt_text' => true];
+
+ $status = $connection->get('statuses/show', $parameters);
+
+ if (empty($status->id)) {
+ return;
+ }
+
+ $item = twitter_createpost($a, 0, $status, [], true, false, true);
+
+ if ($b['format'] == 'json') {
+ $images = [];
+ foreach ($status->extended_entities->media ?? [] as $media) {
+ if (!empty($media->media_url_https)) {
+ $images[] = [
+ 'src' => $media->media_url_https,
+ 'width' => $media->sizes->thumb->w,
+ 'height' => $media->sizes->thumb->h,
+ ];
+ }
+ }
+
+ $b['text'] = [
+ 'data' => [
+ 'type' => 'link',
+ 'url' => $item['plink'],
+ 'title' => DI::l10n()->t('%s on Twitter', $status->user->name),
+ 'text' => BBCode::toPlaintext($item['body'], false),
+ 'images' => $images,
+ ],
+ 'contentType' => 'attachment',
+ 'success' => true,
+ ];
+ } else {
+ $b['text'] = BBCode::getShareOpeningTag(
+ $item['author-name'],
+ $item['author-link'],
+ $item['author-avatar'],
+ $item['plink'],
+ $item['created']
+ );
+ $b['text'] .= $item['body'] . '[/share]';
+ }
+}
+
+
+/*********************
+ *
+ * General functions
+ *
+ *********************/
+
+