diff options
Diffstat (limited to 'bridges/YouTubeCommunityTabBridge.php')
-rw-r--r-- | bridges/YouTubeCommunityTabBridge.php | 513 |
1 files changed, 261 insertions, 252 deletions
diff --git a/bridges/YouTubeCommunityTabBridge.php b/bridges/YouTubeCommunityTabBridge.php index 842e7489..c44e9557 100644 --- a/bridges/YouTubeCommunityTabBridge.php +++ b/bridges/YouTubeCommunityTabBridge.php @@ -1,271 +1,280 @@ <?php -class YouTubeCommunityTabBridge extends BridgeAbstract { - const NAME = 'YouTube Community Tab Bridge'; - const URI = 'https://www.youtube.com'; - const DESCRIPTION = 'Returns posts from a channel\'s community tab'; - const MAINTAINER = 'VerifiedJoseph'; - const PARAMETERS = array( - 'By channel ID' => array( - 'channel' => array( - 'name' => 'Channel ID', - 'type' => 'text', - 'required' => true, - 'exampleValue' => 'UCULkRHBdLC5ZcEQBaL0oYHQ' - ) - ), - 'By username' => array( - 'username' => array( - 'name' => 'Username', - 'type' => 'text', - 'required' => true, - 'exampleValue' => 'YouTubeUK' - ), - ) - ); - - const CACHE_TIMEOUT = 3600; // 1 hour - - private $feedUrl = ''; - private $feedName = ''; - private $itemTitle = ''; - - private $urlRegex = '/youtube\.com\/(channel|user|c)\/([\w]+)\/community/'; - private $jsonRegex = '/var ytInitialData = (.*);<\/script>/'; - - public function detectParameters($url) { - $params = array(); - - if(preg_match($this->urlRegex, $url, $matches)) { - if ($matches[1] === 'channel') { - $params['context'] = 'By channel ID'; - $params['channel'] = $matches[2]; - } - - if ($matches[1] === 'user') { - $params['context'] = 'By username'; - $params['username'] = $matches[2]; - } - - return $params; - } - - return null; - } - - public function collectData() { - - if (is_null($this->getInput('username')) === false) { - try { - $this->feedUrl = $this->buildCommunityUri($this->getInput('username'), 'c'); - $html = getSimpleHTMLDOM($this->feedUrl); - - } catch (Exception $e) { - $this->feedUrl = $this->buildCommunityUri($this->getInput('username'), 'user'); - $html = getSimpleHTMLDOM($this->feedUrl); - } - } else { - $this->feedUrl = $this->buildCommunityUri($this->getInput('channel'), 'channel'); - $html = getSimpleHTMLDOM($this->feedUrl); - } - - $json = $this->extractJson($html->find('body', 0)->innertext); - - $this->feedName = $json->header->c4TabbedHeaderRenderer->title; - - if ($this->hasCommunityTab($json) === false) { - returnServerError('Channel does not have a community tab'); - } - - foreach ($this->getCommunityPosts($json) as $post) { - $this->itemTitle = ''; - - if (!isset($post->backstagePostThreadRenderer)) { - continue; - } - - $details = $post->backstagePostThreadRenderer->post->backstagePostRenderer; - - $item = array(); - $item['uri'] = self::URI . '/post/' . $details->postId; - $item['author'] = $details->authorText->runs[0]->text; - $item['content'] = ''; - - if (isset($details->contentText)) { - $text = $this->getText($details->contentText->runs); - - $this->itemTitle = $this->ellipsisTitle($text); - $item['content'] = $text; - } - - $item['content'] .= $this->getAttachments($details); - $item['title'] = $this->itemTitle; - - $this->items[] = $item; - } - } - - public function getURI() { - - if (!empty($this->feedUri)) { - return $this->feedUri; - } - - return parent::getURI(); - } - public function getName() { - - if (!empty($this->feedName)) { - return $this->feedName . ' - YouTube Community Tab'; - } - - return parent::getName(); - } - - /** - * Build Community URI - */ - private function buildCommunityUri($value, $type) { - return self::URI . '/' . $type . '/' . $value . '/community'; - } - - /** - * Extract JSON from page - */ - private function extractJson($html) { - - if (!preg_match($this->jsonRegex, $html, $parts)) { - returnServerError('Failed to extract data from page'); - } - - $data = json_decode($parts[1]); - - if ($data === false) { - returnServerError('Failed to decode extracted data'); - } - - return $data; - } - - /** - * Check if channel has a community tab - */ - private function hasCommunityTab($json) { - - foreach ($json->contents->twoColumnBrowseResultsRenderer->tabs as $tab) { - if (isset($tab->tabRenderer) - && str_ends_with($tab->tabRenderer->endpoint->commandMetadata->webCommandMetadata->url, 'community')) { - - return true; - } - } - - return false; - } - - /** - * Get community tab posts - */ - private function getCommunityPosts($json) { - - foreach ($json->contents->twoColumnBrowseResultsRenderer->tabs as $tab) { - if (isset($tab->tabRenderer) - && str_ends_with($tab->tabRenderer->endpoint->commandMetadata->webCommandMetadata->url, 'community')) { - - return $tab->tabRenderer->content->sectionListRenderer->contents[0]->itemSectionRenderer->contents; - } - } - } - - /** - * Get text content for a post - */ - private function getText($runs) { - $text = ''; - - foreach ($runs as $part) { - $text .= $this->formatUrls($part->text); - } - - return nl2br($text); - } - - /** - * Get attachments for posts - */ - private function getAttachments($details) { - $content = ''; - - if (isset($details->backstageAttachment)) { - $attachments = $details->backstageAttachment; - - // Video - if (isset($attachments->videoRenderer) && isset($attachments->videoRenderer->videoId)) { - if (empty($this->itemTitle)) { - $this->itemTitle = $this->feedName . ' posted a video'; - } - - $content = <<<EOD +class YouTubeCommunityTabBridge extends BridgeAbstract +{ + const NAME = 'YouTube Community Tab Bridge'; + const URI = 'https://www.youtube.com'; + const DESCRIPTION = 'Returns posts from a channel\'s community tab'; + const MAINTAINER = 'VerifiedJoseph'; + const PARAMETERS = [ + 'By channel ID' => [ + 'channel' => [ + 'name' => 'Channel ID', + 'type' => 'text', + 'required' => true, + 'exampleValue' => 'UCULkRHBdLC5ZcEQBaL0oYHQ' + ] + ], + 'By username' => [ + 'username' => [ + 'name' => 'Username', + 'type' => 'text', + 'required' => true, + 'exampleValue' => 'YouTubeUK' + ], + ] + ]; + + const CACHE_TIMEOUT = 3600; // 1 hour + + private $feedUrl = ''; + private $feedName = ''; + private $itemTitle = ''; + + private $urlRegex = '/youtube\.com\/(channel|user|c)\/([\w]+)\/community/'; + private $jsonRegex = '/var ytInitialData = (.*);<\/script>/'; + + public function detectParameters($url) + { + $params = []; + + if (preg_match($this->urlRegex, $url, $matches)) { + if ($matches[1] === 'channel') { + $params['context'] = 'By channel ID'; + $params['channel'] = $matches[2]; + } + + if ($matches[1] === 'user') { + $params['context'] = 'By username'; + $params['username'] = $matches[2]; + } + + return $params; + } + + return null; + } + + public function collectData() + { + if (is_null($this->getInput('username')) === false) { + try { + $this->feedUrl = $this->buildCommunityUri($this->getInput('username'), 'c'); + $html = getSimpleHTMLDOM($this->feedUrl); + } catch (Exception $e) { + $this->feedUrl = $this->buildCommunityUri($this->getInput('username'), 'user'); + $html = getSimpleHTMLDOM($this->feedUrl); + } + } else { + $this->feedUrl = $this->buildCommunityUri($this->getInput('channel'), 'channel'); + $html = getSimpleHTMLDOM($this->feedUrl); + } + + $json = $this->extractJson($html->find('body', 0)->innertext); + + $this->feedName = $json->header->c4TabbedHeaderRenderer->title; + + if ($this->hasCommunityTab($json) === false) { + returnServerError('Channel does not have a community tab'); + } + + foreach ($this->getCommunityPosts($json) as $post) { + $this->itemTitle = ''; + + if (!isset($post->backstagePostThreadRenderer)) { + continue; + } + + $details = $post->backstagePostThreadRenderer->post->backstagePostRenderer; + + $item = []; + $item['uri'] = self::URI . '/post/' . $details->postId; + $item['author'] = $details->authorText->runs[0]->text; + $item['content'] = ''; + + if (isset($details->contentText)) { + $text = $this->getText($details->contentText->runs); + + $this->itemTitle = $this->ellipsisTitle($text); + $item['content'] = $text; + } + + $item['content'] .= $this->getAttachments($details); + $item['title'] = $this->itemTitle; + + $this->items[] = $item; + } + } + + public function getURI() + { + if (!empty($this->feedUri)) { + return $this->feedUri; + } + + return parent::getURI(); + } + + public function getName() + { + if (!empty($this->feedName)) { + return $this->feedName . ' - YouTube Community Tab'; + } + + return parent::getName(); + } + + /** + * Build Community URI + */ + private function buildCommunityUri($value, $type) + { + return self::URI . '/' . $type . '/' . $value . '/community'; + } + + /** + * Extract JSON from page + */ + private function extractJson($html) + { + if (!preg_match($this->jsonRegex, $html, $parts)) { + returnServerError('Failed to extract data from page'); + } + + $data = json_decode($parts[1]); + + if ($data === false) { + returnServerError('Failed to decode extracted data'); + } + + return $data; + } + + /** + * Check if channel has a community tab + */ + private function hasCommunityTab($json) + { + foreach ($json->contents->twoColumnBrowseResultsRenderer->tabs as $tab) { + if ( + isset($tab->tabRenderer) + && str_ends_with($tab->tabRenderer->endpoint->commandMetadata->webCommandMetadata->url, 'community') + ) { + return true; + } + } + + return false; + } + + /** + * Get community tab posts + */ + private function getCommunityPosts($json) + { + foreach ($json->contents->twoColumnBrowseResultsRenderer->tabs as $tab) { + if ( + isset($tab->tabRenderer) + && str_ends_with($tab->tabRenderer->endpoint->commandMetadata->webCommandMetadata->url, 'community') + ) { + return $tab->tabRenderer->content->sectionListRenderer->contents[0]->itemSectionRenderer->contents; + } + } + } + + /** + * Get text content for a post + */ + private function getText($runs) + { + $text = ''; + + foreach ($runs as $part) { + $text .= $this->formatUrls($part->text); + } + + return nl2br($text); + } + + /** + * Get attachments for posts + */ + private function getAttachments($details) + { + $content = ''; + + if (isset($details->backstageAttachment)) { + $attachments = $details->backstageAttachment; + + // Video + if (isset($attachments->videoRenderer) && isset($attachments->videoRenderer->videoId)) { + if (empty($this->itemTitle)) { + $this->itemTitle = $this->feedName . ' posted a video'; + } + + $content = <<<EOD <iframe width="100%" height="410" src="https://www.youtube.com/embed/{$attachments->videoRenderer->videoId}" frameborder="0" allow="encrypted-media;" allowfullscreen></iframe> EOD; - } + } - // Image - if (isset($attachments->backstageImageRenderer)) { - if (empty($this->itemTitle)) { - $this->itemTitle = $this->feedName . ' posted an image'; - } + // Image + if (isset($attachments->backstageImageRenderer)) { + if (empty($this->itemTitle)) { + $this->itemTitle = $this->feedName . ' posted an image'; + } - $lastThumb = end($attachments->backstageImageRenderer->image->thumbnails); + $lastThumb = end($attachments->backstageImageRenderer->image->thumbnails); - $content = <<<EOD + $content = <<<EOD <p><img src="{$lastThumb->url}"></p> EOD; - } + } - // Poll - if (isset($attachments->pollRenderer)) { - if (empty($this->itemTitle)) { - $this->itemTitle = $this->feedName . ' posted a poll'; - } + // Poll + if (isset($attachments->pollRenderer)) { + if (empty($this->itemTitle)) { + $this->itemTitle = $this->feedName . ' posted a poll'; + } - $pollChoices = ''; + $pollChoices = ''; - foreach ($attachments->pollRenderer->choices as $choice) { - $pollChoices .= <<<EOD + foreach ($attachments->pollRenderer->choices as $choice) { + $pollChoices .= <<<EOD <li>{$choice->text->runs[0]->text}</li> EOD; - } + } - $content = <<<EOD + $content = <<<EOD <hr><p>Poll ({$attachments->pollRenderer->totalVotes->simpleText})<br><ul>{$pollChoices}</ul><p> EOD; - } - } - - return $content; - } - - /* - Ellipsis text for title - */ - private function ellipsisTitle($text) { - $length = 100; - - if (strlen($text) > $length) { - $text = explode('<br>', wordwrap($text, $length, '<br>')); - return $text[0] . '...'; - } - - return $text; - } - - private function formatUrls($content) { - return preg_replace( - '/(http[s]{0,1}\:\/\/[a-zA-Z0-9.\/\?\&=\-_]{4,})/ims', - '<a target="_blank" href="$1" target="_blank">$1</a> ', - $content - ); - } + } + } + + return $content; + } + + /* + Ellipsis text for title + */ + private function ellipsisTitle($text) + { + $length = 100; + + if (strlen($text) > $length) { + $text = explode('<br>', wordwrap($text, $length, '<br>')); + return $text[0] . '...'; + } + + return $text; + } + + private function formatUrls($content) + { + return preg_replace( + '/(http[s]{0,1}\:\/\/[a-zA-Z0-9.\/\?\&=\-_]{4,})/ims', + '<a target="_blank" href="$1" target="_blank">$1</a> ', + $content + ); + } } |