From 8770c87389ffde62551e4a1a8923ded1c95b077a Mon Sep 17 00:00:00 2001 From: teromene Date: Sat, 5 May 2018 13:00:59 +0100 Subject: [PATCH] Added support for stories in InstagramBridge. Closes #665 Renamed parameters as stories are only available in user mode. Use a regex instead of HTML parsing to extract the JSON, as it is way faster. --- bridges/InstagramBridge.php | 105 +++++++++++++++++++++++------------- 1 file changed, 69 insertions(+), 36 deletions(-) diff --git a/bridges/InstagramBridge.php b/bridges/InstagramBridge.php index e34e922..b0b1d17 100644 --- a/bridges/InstagramBridge.php +++ b/bridges/InstagramBridge.php @@ -12,14 +12,15 @@ class InstagramBridge extends BridgeAbstract { 'name' => 'username', 'required' => true ), - 'media_type' => array( + 'media_type_u' => array( 'name' => 'Media type', 'type' => 'list', 'required' => false, 'values' => array( - 'Both' => 'all', + 'All' => 'all', + 'Story' => 'story', 'Video' => 'video', - 'Picture' => 'picture' + 'Picture' => 'picture', ), 'defaultValue' => 'all' ) @@ -29,7 +30,7 @@ class InstagramBridge extends BridgeAbstract { 'name' => 'hashtag', 'required' => true ), - 'media_type' => array( + 'media_type_h' => array( 'name' => 'Media type', 'type' => 'list', 'required' => false, @@ -44,27 +45,8 @@ class InstagramBridge extends BridgeAbstract { ); public function collectData(){ - $html = getSimpleHTMLDOM($this->getURI()) - or returnServerError('Could not request Instagram.'); - $innertext = null; - - foreach($html->find('script') as $script) { - if('' === $script->innertext) { - continue; - } - - $pos = strpos(trim($script->innertext), 'window._sharedData'); - if(0 !== $pos) { - continue; - } - - $innertext = $script->innertext; - break; - } - - $json = trim(substr($innertext, $pos + 18), ' =;'); - $data = json_decode($json); + $data = $this->getInstagramJSON($this->getURI()); if(!is_null($this->getInput('u'))) { $userMedia = $data->entry_data->ProfilePage[0]->graphql->user->edge_owner_to_timeline_media->edges; @@ -74,32 +56,83 @@ class InstagramBridge extends BridgeAbstract { foreach($userMedia as $media) { $media = $media->node; - // Check media type - switch($this->getInput('media_type')) { - case 'all': break; - case 'video': - if($media->is_video === false) continue 2; - break; - case 'picture': - if($media->is_video === true) continue 2; - break; - default: break; + + if(!is_null($this->getInput('u'))) { + switch($this->getInput('media_type_u')) { + case 'all': break; + case 'video': + if($media->__typename != 'GraphVideo') continue 2; + break; + case 'picture': + if($media->__typename != 'GraphImage') continue 2; + break; + case 'story': + if($media->__typename != 'GraphSidecar') continue 2; + break; + default: break; + } + } else { + if($this->getInput('media_type_h') == 'video' && !$media->is_video) continue; } $item = array(); $item['uri'] = self::URI . 'p/' . $media->shortcode . '/'; - $item['content'] = ''; + if (isset($media->edge_media_to_caption->edges[0]->node->text)) { $item['title'] = $media->edge_media_to_caption->edges[0]->node->text; } else { $item['title'] = basename($media->display_url); } + + if(!is_null($this->getInput('u')) && $media->__typename == 'GraphSidecar') { + $data = $this->getInstagramStory($item['uri']); + $item['content'] = $data[0]; + $item['enclosures'] = $data[1]; + } else { + $item['content'] = ''. $item['; + $item['enclosures'] = array($media->display_url); + } + $item['timestamp'] = $media->taken_at_timestamp; - $item['enclosures'] = array($media->display_url); + $this->items[] = $item; } } + protected function getInstagramStory($uri) { + + $data = $this->getInstagramJSON($uri); + $mediaInfo = $data->entry_data->PostPage[0]->graphql->shortcode_media; + + //Process the first element, that isn't in the node graph + $caption = $mediaInfo->edge_media_to_caption->edges[0]->node->text; + + $enclosures = [$mediaInfo->display_url]; + $content = ''. $caption . ''; + + foreach($mediaInfo->edge_sidecar_to_children->edges as $media) { + + $content .= ''. $caption . ''; + $enclosures[] = $media->node->display_url; + + } + + return [$content, $enclosures]; + + } + + protected function getInstagramJSON($uri) { + + $html = getContents($uri) + or returnServerError('Could not request Instagram.'); + $scriptRegex = '/window\._sharedData = (.*);<\/script>/'; + + preg_match($scriptRegex, $html, $matches, PREG_OFFSET_CAPTURE, 0); + + return json_decode($matches[1][0]); + + } + public function getName(){ if(!is_null($this->getInput('u'))) { return $this->getInput('u') . ' - Instagram Bridge';