Skip to content

Commit

Permalink
[InstagramBridge] Fix instagram GraphSidecar output and Video embeddi…
Browse files Browse the repository at this point in the history
…ng (RSS-Bridge#1361)

* [InstagramBridge] Fix GraphSidecar output

Fix following issues which related to output of the GraphSidecar type posts.
- The GraphSidecar post's media wasn't outputted except for first picture when searching by hashtag or location
- Video didn't embedded
NOTE:
The function getInstagramStory() which was called when the post type is GraphSidecar didn't seem to work just as one intended.
Because the web request called in that function is just to get the media of single post, NOT to get the media of Story.
But I don't have any idea to solve RSS-Bridge#694, so it seems be better to rename these function and member variable properly.
  • Loading branch information
shutosg authored and logmanoriginal committed Dec 1, 2019
1 parent 39e2603 commit f88ff25
Showing 1 changed file with 93 additions and 70 deletions.
163 changes: 93 additions & 70 deletions bridges/InstagramBridge.php
Original file line number Diff line number Diff line change
Expand Up @@ -32,14 +32,14 @@ class InstagramBridge extends BridgeAbstract {
'required' => false,
'values' => array(
'All' => 'all',
'Story' => 'story',
'Video' => 'video',
'Picture' => 'picture',
'Multiple' => 'multiple',
),
'defaultValue' => 'all'
),
'direct_links' => array(
'name' => 'Use direct image links',
'name' => 'Use direct media links',
'type' => 'checkbox',
)
)
Expand All @@ -48,7 +48,7 @@ class InstagramBridge extends BridgeAbstract {

const USER_QUERY_HASH = '58b6785bea111c67129decbe6a448951';
const TAG_QUERY_HASH = '174a5243287c5f3a7de741089750ab3b';
const STORY_QUERY_HASH = '865589822932d1b43dfe312121dd353a';
const SHORTCODE_QUERY_HASH = '865589822932d1b43dfe312121dd353a';

protected function getInstagramUserId($username) {

Expand Down Expand Up @@ -79,11 +79,6 @@ protected function getInstagramUserId($username) {
}

public function collectData(){

if(is_null($this->getInput('u')) && $this->getInput('media_type') == 'story') {
returnClientError('Stories are not supported for hashtags nor locations!');
}

$directLink = !is_null($this->getInput('direct_links')) && $this->getInput('direct_links');

$data = $this->getInstagramJSON($this->getURI());
Expand All @@ -99,22 +94,18 @@ public function collectData(){
foreach($userMedia as $media) {
$media = $media->node;

if(!is_null($this->getInput('u'))) {
switch($this->getInput('media_type')) {
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') == 'video' && !$media->is_video) continue;
switch($this->getInput('media_type')) {
case 'all': break;
case 'video':
if($media->__typename != 'GraphVideo' || !$media->is_video) continue 2;
break;
case 'picture':
if($media->__typename != 'GraphImage') continue 2;
break;
case 'multiple':
if($media->__typename != 'GraphSidecar') continue 2;
break;
default: break;
}

$item = array();
Expand All @@ -124,73 +115,105 @@ public function collectData(){
$item['author'] = $media->owner->username;
}

if (isset($media->edge_media_to_caption->edges[0]->node->text)) {
$textContent = $media->edge_media_to_caption->edges[0]->node->text;
} else {
$textContent = '(no text)';
}
$textContent = $this->getTextContent($media);

$item['title'] = ($media->is_video ? '' : '') . trim($textContent);
$item['title'] = ($media->is_video ? '' : '') . $textContent;
$titleLinePos = strpos(wordwrap($item['title'], 120), "\n");
if ($titleLinePos != false) {
$item['title'] = substr($item['title'], 0, $titleLinePos) . '...';
}

if(!is_null($this->getInput('u')) && $media->__typename == 'GraphSidecar') {

$data = $this->getInstagramStory($item['uri']);
$item['content'] = $data[0];
$item['enclosures'] = $data[1];
} else {
if($directLink) {
$mediaURI = $media->display_url;
} else {
$mediaURI = self::URI . 'p/' . $media->shortcode . '/media?size=l';
}
$item['content'] = '<a href="' . htmlentities($item['uri']) . '" target="_blank">';
$item['content'] .= '<img src="' . htmlentities($mediaURI) . '" alt="' . $item['title'] . '" />';
$item['content'] .= '</a><br><br>' . nl2br(htmlentities($textContent));
$item['enclosures'] = array($mediaURI);
switch($media->__typename) {
case 'GraphSidecar':
$data = $this->getInstagramSidecarData($item['uri'], $item['title']);
$item['content'] = $data[0];
$item['enclosures'] = $data[1];
break;
case 'GraphImage':
if($directLink) {
$mediaURI = $media->display_url;
} else {
$mediaURI = self::URI . 'p/' . $media->shortcode . '/media?size=l';
}
$item['content'] = '<a href="' . htmlentities($item['uri']) . '" target="_blank">';
$item['content'] .= '<img src="' . htmlentities($mediaURI) . '" alt="' . $item['title'] . '" />';
$item['content'] .= '</a><br><br>' . nl2br(htmlentities($textContent));
$item['enclosures'] = array($mediaURI);
break;
case 'GraphVideo':
$data = $this->getInstagramVideoData($item['uri']);
$item['content'] = $data[0];
if($directLink) {
$item['enclosures'] = $data[1];
} else {
$item['enclosures'] = array(self::URI . 'p/' . $media->shortcode . '/media?size=l');
}
break;
default: break;
}

$item['timestamp'] = $media->taken_at_timestamp;

$this->items[] = $item;
}
}

protected function getInstagramStory($uri) {

$shortcode = explode('/', $uri)[4];
$data = getContents(self::URI .
'graphql/query/?query_hash=' .
self::STORY_QUERY_HASH .
'&variables={"shortcode"%3A"' .
$shortcode .
'"}');
// returns Sidecar(a post which has multiple media)'s contents and enclosures
protected function getInstagramSidecarData($uri, $postTitle) {
$mediaInfo = $this->getSinglePostData($uri);

$mediaInfo = json_decode($data)->data->shortcode_media;
$textContent = $this->getTextContent($mediaInfo);

//Process the first element, that isn't in the node graph
if (count($mediaInfo->edge_media_to_caption->edges) > 0) {
$caption = $mediaInfo->edge_media_to_caption->edges[0]->node->text;
} else {
$caption = '';
$enclosures = array();
$content = '';
foreach($mediaInfo->edge_sidecar_to_children->edges as $singleMedia) {
$singleMedia = $singleMedia->node;
if($singleMedia->is_video) {
if(in_array($singleMedia->video_url, $enclosures)) continue; // check if not added yet
$content .= '<video controls><source src="' . $singleMedia->video_url . '" type="video/mp4"></video><br>';
array_push($enclosures, $singleMedia->video_url);
} else {
if(in_array($singleMedia->display_url, $enclosures)) continue; // check if not added yet
$content .= '<a href="' . $singleMedia->display_url . '" target="_blank">';
$content .= '<img src="' . $singleMedia->display_url . '" alt="' . $postTitle . '" />';
$content .= '</a><br>';
array_push($enclosures, $singleMedia->display_url);
}
}
$content .= '<br>' . nl2br(htmlentities($textContent));

return array($content, $enclosures);
}

$enclosures = array($mediaInfo->display_url);
$content = '<img src="' . htmlentities($mediaInfo->display_url) . '" alt="' . $caption . '" />';
// returns Video post's contents and enclosures
protected function getInstagramVideoData($uri) {
$mediaInfo = $this->getSinglePostData($uri);

foreach($mediaInfo->edge_sidecar_to_children->edges as $media) {
$display_url = $media->node->display_url;
if(!in_array($display_url, $enclosures)) { // add only if not added yet
$content .= '<img src="' . htmlentities($display_url) . '" alt="' . $caption . '" />';
$enclosures[] = $display_url;
}
$textContent = $this->getTextContent($mediaInfo);
$content = '<video controls><source src="' . $mediaInfo->video_url . '" type="video/mp4"></video><br>';
$content .= '<br>' . nl2br(htmlentities($textContent));

return array($content, array($mediaInfo->video_url));
}

protected function getTextContent($media) {
$textContent = '(no text)';
//Process the first element, that isn't in the node graph
if (count($media->edge_media_to_caption->edges) > 0) {
$textContent = trim($media->edge_media_to_caption->edges[0]->node->text);
}
return $textContent;
}

return array($content, $enclosures);
protected function getSinglePostData($uri) {
$shortcode = explode('/', $uri)[4];
$data = getContents(self::URI .
'graphql/query/?query_hash=' .
self::SHORTCODE_QUERY_HASH .
'&variables={"shortcode"%3A"' .
$shortcode .
'"}');

return json_decode($data)->data->shortcode_media;
}

protected function getInstagramJSON($uri) {
Expand Down

0 comments on commit f88ff25

Please sign in to comment.