InstagramBridge.php 3.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149
  1. <?php
  2. class InstagramBridge extends BridgeAbstract {
  3. const MAINTAINER = 'pauder';
  4. const NAME = 'Instagram Bridge';
  5. const URI = 'https://instagram.com/';
  6. const DESCRIPTION = 'Returns the newest images';
  7. const PARAMETERS = array(
  8. array(
  9. 'u' => array(
  10. 'name' => 'username',
  11. 'required' => true
  12. )
  13. ),
  14. array(
  15. 'h' => array(
  16. 'name' => 'hashtag',
  17. 'required' => true
  18. )
  19. ),
  20. 'global' => array(
  21. 'media_type' => array(
  22. 'name' => 'Media type',
  23. 'type' => 'list',
  24. 'required' => false,
  25. 'values' => array(
  26. 'All' => 'all',
  27. 'Story' => 'story',
  28. 'Video' => 'video',
  29. 'Picture' => 'picture',
  30. ),
  31. 'defaultValue' => 'all'
  32. )
  33. )
  34. );
  35. public function collectData(){
  36. if(!is_null($this->getInput('h')) && $this->getInput('media_type') == 'story') {
  37. returnClientError('Stories are not supported for hashtags!');
  38. }
  39. $data = $this->getInstagramJSON($this->getURI());
  40. if(!is_null($this->getInput('u'))) {
  41. $userMedia = $data->entry_data->ProfilePage[0]->graphql->user->edge_owner_to_timeline_media->edges;
  42. } else {
  43. $userMedia = $data->entry_data->TagPage[0]->graphql->hashtag->edge_hashtag_to_media->edges;
  44. }
  45. foreach($userMedia as $media) {
  46. $media = $media->node;
  47. if(!is_null($this->getInput('u'))) {
  48. switch($this->getInput('media_type')) {
  49. case 'all': break;
  50. case 'video':
  51. if($media->__typename != 'GraphVideo') continue 2;
  52. break;
  53. case 'picture':
  54. if($media->__typename != 'GraphImage') continue 2;
  55. break;
  56. case 'story':
  57. if($media->__typename != 'GraphSidecar') continue 2;
  58. break;
  59. default: break;
  60. }
  61. } else {
  62. if($this->getInput('media_type') == 'video' && !$media->is_video) continue;
  63. }
  64. $item = array();
  65. $item['uri'] = self::URI . 'p/' . $media->shortcode . '/';
  66. if (isset($media->edge_media_to_caption->edges[0]->node->text)) {
  67. $item['title'] = $media->edge_media_to_caption->edges[0]->node->text;
  68. } else {
  69. $item['title'] = basename($media->display_url);
  70. }
  71. if(!is_null($this->getInput('u')) && $media->__typename == 'GraphSidecar') {
  72. $data = $this->getInstagramStory($item['uri']);
  73. $item['content'] = $data[0];
  74. $item['enclosures'] = $data[1];
  75. } else {
  76. $item['content'] = '<img src="' . htmlentities($media->display_url) . '" alt="'. $item['title'] . '" />';
  77. $item['enclosures'] = array($media->display_url);
  78. }
  79. $item['timestamp'] = $media->taken_at_timestamp;
  80. $this->items[] = $item;
  81. }
  82. }
  83. protected function getInstagramStory($uri) {
  84. $data = $this->getInstagramJSON($uri);
  85. $mediaInfo = $data->entry_data->PostPage[0]->graphql->shortcode_media;
  86. //Process the first element, that isn't in the node graph
  87. $caption = $mediaInfo->edge_media_to_caption->edges[0]->node->text;
  88. $enclosures = [$mediaInfo->display_url];
  89. $content = '<img src="' . htmlentities($mediaInfo->display_url) . '" alt="'. $caption . '" />';
  90. foreach($mediaInfo->edge_sidecar_to_children->edges as $media) {
  91. $content .= '<img src="' . htmlentities($media->node->display_url) . '" alt="'. $caption . '" />';
  92. $enclosures[] = $media->node->display_url;
  93. }
  94. return [$content, $enclosures];
  95. }
  96. protected function getInstagramJSON($uri) {
  97. $html = getContents($uri)
  98. or returnServerError('Could not request Instagram.');
  99. $scriptRegex = '/window\._sharedData = (.*);<\/script>/';
  100. preg_match($scriptRegex, $html, $matches, PREG_OFFSET_CAPTURE, 0);
  101. return json_decode($matches[1][0]);
  102. }
  103. public function getName(){
  104. if(!is_null($this->getInput('u'))) {
  105. return $this->getInput('u') . ' - Instagram Bridge';
  106. }
  107. return parent::getName();
  108. }
  109. public function getURI(){
  110. if(!is_null($this->getInput('u'))) {
  111. return self::URI . urlencode($this->getInput('u'));
  112. } elseif(!is_null($this->getInput('h'))) {
  113. return self::URI . 'explore/tags/' . urlencode($this->getInput('h'));
  114. }
  115. return parent::getURI();
  116. }
  117. }