diff --git a/examples/getStories.php b/examples/getStories.php new file mode 100644 index 00000000..13a36919 --- /dev/null +++ b/examples/getStories.php @@ -0,0 +1,8 @@ +login(); + +$stories = $instagram->getStories(); +print_r($stories); \ No newline at end of file diff --git a/src/InstagramScraper/Endpoints.php b/src/InstagramScraper/Endpoints.php index 2b00a0f1..b4343ae7 100644 --- a/src/InstagramScraper/Endpoints.php +++ b/src/InstagramScraper/Endpoints.php @@ -34,6 +34,10 @@ class Endpoints const GRAPH_QL_QUERY_URL = 'https://www.instagram.com/graphql/query/?query_id={{queryId}}'; + //stories use GRAPH_QL_QUERY_URL + const USER_STORIES_QUERY_ID = '17890626976041463'; + const STORIES_QUERY_ID = '17873473675158481'; + public static function getAccountPageLink($username) { @@ -108,8 +112,9 @@ public static function getLastLikesByCode($code, $count, $lastLikeID) public static function getGraphQlUrl($queryId, $parameters) { $url = str_replace('{{queryId}}', urlencode($queryId), static::GRAPH_QL_QUERY_URL); - foreach ($parameters as $key => $value) { - $url .= "&$key=$value"; + if (!empty($parameters)) { + $query_string = http_build_query($parameters); + $url .= '&' . $query_string; } return $url; } @@ -147,4 +152,16 @@ public static function getFollowingJsonLink($accountId, $count, $after = '') return $url; } + + public static function getUserStoriesLink() + { + $url = self::getGraphQlUrl(static::USER_STORIES_QUERY_ID, ['variables' => json_encode([])]); + return $url; + } + + public static function getStoriesLink($variables) + { + $url = self::getGraphQlUrl(static::STORIES_QUERY_ID, ['variables' => json_encode($variables)]); + return $url; + } } diff --git a/src/InstagramScraper/Instagram.php b/src/InstagramScraper/Instagram.php index 22d7acfa..7ba7d938 100644 --- a/src/InstagramScraper/Instagram.php +++ b/src/InstagramScraper/Instagram.php @@ -10,6 +10,7 @@ use InstagramScraper\Model\Like; use InstagramScraper\Model\Location; use InstagramScraper\Model\Media; +use InstagramScraper\Model\Story; use InstagramScraper\Model\Tag; use phpFastCache\CacheManager; use Unirest\Request; @@ -899,6 +900,50 @@ public function getFollowing($accountId, $count = 20, $pageSize = 20, $delayed = return $accounts; } + public function getStories() + { + $response = Request::get(Endpoints::getUserStoriesLink(), + $this->generateHeaders($this->userSession)); + + if ($response->code !== 200) { + throw new InstagramException('Response code is ' . $response->code . '. Body: ' . static::getErrorBody($response->body) . ' Something went wrong. Please report issue.'); + } + + $jsonResponse = json_decode($response->raw_body, true, 512, JSON_BIGINT_AS_STRING); + if (empty($jsonResponse['data']['user']['feed_reels_tray']['edge_reels_tray_to_reel']['edges'])) { + return []; + } + + $variables = ['precomposed_overlay' => false, 'reel_ids' => []]; + foreach ($jsonResponse['data']['user']['feed_reels_tray']['edge_reels_tray_to_reel']['edges'] as $edge) { + $variables['reel_ids'][] = $edge['node']['id']; + } + + $response = Request::get(Endpoints::getStoriesLink($variables), + $this->generateHeaders($this->userSession)); + + if ($response->code !== 200) { + throw new InstagramException('Response code is ' . $response->code . '. Body: ' . static::getErrorBody($response->body) . ' Something went wrong. Please report issue.'); + } + + $jsonResponse = json_decode($response->raw_body, true, 512, JSON_BIGINT_AS_STRING); + + if (empty($jsonResponse['data']['reels_media'])) { + return []; + } + + $stories = []; + foreach ($jsonResponse['data']['reels_media'] as $user) { + $Story = Story::create(); + $Story->setOwner(Account::create($user['user'])); + foreach ($user['items'] as $item) { + $Story->addStory(Media::create($item)); + } + $stories[] = $Story; + } + return $stories; + } + /** * @param bool $force * diff --git a/src/InstagramScraper/Model/Media.php b/src/InstagramScraper/Model/Media.php index 7ad6b549..9f1295d5 100644 --- a/src/InstagramScraper/Model/Media.php +++ b/src/InstagramScraper/Model/Media.php @@ -407,6 +407,16 @@ protected function initPropertiesCustom($value, $prop, $arr) $this->videoStandardResolutionUrl = $arr[$prop]['standard_resolution']['url']; $this->videoLowBandwidthUrl = $arr[$prop]['low_bandwidth']['url']; break; + case 'video_resources': + foreach ($value as $video) { + if ($video['profile'] == 'MAIN') { + $this->videoStandardResolutionUrl = $video['src']; + } elseif ($video['profile'] == 'BASELINE') { + $this->videoLowResolutionUrl = $video['src']; + $this->videoLowBandwidthUrl = $video['src']; + } + } + break; case 'location': switch ($prop) { case 'id': diff --git a/src/InstagramScraper/Model/Story.php b/src/InstagramScraper/Model/Story.php new file mode 100644 index 00000000..53707304 --- /dev/null +++ b/src/InstagramScraper/Model/Story.php @@ -0,0 +1,41 @@ +owner = $owner; + } + + public function getOwner() + { + return $this->owner; + } + + public function addStory($story) + { + $this->stories[] = $story; + } + + public function setStories($stories) + { + $this->stories = $stories; + } + + public function getStories() + { + return $this->stories; + } +} \ No newline at end of file