Skip to content

Commit

Permalink
Add method to fetch IGTV
Browse files Browse the repository at this point in the history
  • Loading branch information
pgrimaud committed Sep 3, 2021
1 parent fdec5c9 commit b0ff8be
Show file tree
Hide file tree
Showing 27 changed files with 2,052 additions and 1,241 deletions.
13 changes: 10 additions & 3 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -29,9 +29,11 @@ If you like or use this package, please share your love by starring this reposit
- Fetch feed of followings
- Follow or unfollow users
- Like or unlike posts
- Get posts of hashtag
- Get comments of a post
- **NEW : Get live-streaming info**
- Fetch posts of hashtag
- Fetch comments of a post
- **NEW : Fetch live-streaming info**
- **NEW : Fetch Reels 🎉**
- **NEW : Fetch IGTV 🎉**

This version can retrieve **ANY** Instagram feed using **web scrapping**.

Expand All @@ -51,6 +53,11 @@ composer require pgrimaud/instagram-user-feed

## Changelog

**v6.10** - 2021-09-03:
- Add method to fetch IGTV (example [here](https://github.com/pgrimaud/instagram-user-feed/blob/master/examples/igtv.php)) 🎉.
- Add method to fetch Reels (example [here](https://github.com/pgrimaud/instagram-user-feed/blob/master/examples/reels.php) 🎉.
- Split dirty tests in multiple files.

**v6.9** - 2021-09-02:
- Add method to fetch Instagram live-streaming info. Thanks to [David-Kurniawan](https://github.com/David-Kurniawan)
- Minor fixes.
Expand Down
47 changes: 47 additions & 0 deletions examples/igtv.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
<?php

declare(strict_types=1);

use Instagram\Api;
use Instagram\Exception\InstagramException;

use Psr\Cache\CacheException;
use Symfony\Component\Cache\Adapter\FilesystemAdapter;

require realpath(dirname(__FILE__)) . '/../vendor/autoload.php';
$credentials = include_once realpath(dirname(__FILE__)) . '/credentials.php';

$cachePool = new FilesystemAdapter('Instagram', 0, __DIR__ . '/../cache');

try {
$api = new Api($cachePool);
$api->login($credentials->getLogin(), $credentials->getPassword());

$profile = $api->getProfile('wendyswan');

printIgtvs($profile->getIgtvs());

do {
$profile = $api->getMoreIgtvs($profile);
printIgtvs($profile->getIgtvs());

// avoid 429 Rate limit from Instagram
sleep(1);
} while ($profile->hasMoreIgtvs());

} catch (InstagramException $e) {
print_r($e->getMessage());
} catch (CacheException $e) {
print_r($e->getMessage());
}

function printIgtvs(array $medias)
{
foreach ($medias as $media) {
echo 'ID : ' . $media->getId() . "\n";
echo 'Caption : ' . $media->getCaption() . "\n";
echo 'Link : ' . $media->getLink() . "\n";
echo 'Likes : ' . $media->getLikes() . "\n";
echo 'Date : ' . $media->getDate()->format('Y-m-d h:i:s') . "\n\n";
}
}
22 changes: 21 additions & 1 deletion src/Instagram/Api.php
Original file line number Diff line number Diff line change
Expand Up @@ -103,7 +103,7 @@ public function login(string $username, string $password, ?ImapClient $imapClien
{
$login = new Login($this->client, $username, $password, $imapClient, $this->challengeDelay);

// fetch previous session an re-use it
// fetch previous session and re-use it
$sessionData = $this->cachePool->getItem(Session::SESSION_KEY . '.' . CacheHelper::sanitizeUsername($username));
$cookies = $sessionData->get();

Expand Down Expand Up @@ -153,6 +153,7 @@ public function getProfile(string $user): Profile
$hydrator = new ProfileHydrator();
$hydrator->hydrateProfile($data);
$hydrator->hydrateMedias($data);
$hydrator->hydrateIgtvs($data);

return $hydrator->getProfile();
}
Expand Down Expand Up @@ -635,4 +636,23 @@ public function getReels(int $userId, string $maxId = null): ReelsFeed

return $hydrator->getReelsFeed();
}

/**
* @param Profile $instagramProfile
* @param int $limit
*
* @return Profile
*
* @throws InstagramException
*/
public function getMoreIgtvs(Profile $instagramProfile, int $limit = InstagramHelper::PAGINATION_DEFAULT): Profile
{
$feed = new JsonMediasDataFeed($this->client, $this->session);
$data = $feed->fetchData($instagramProfile, $limit, InstagramHelper::QUERY_HASH_IGTVS);

$hydrator = new ProfileHydrator($instagramProfile);
$hydrator->hydrateIgtvs($data);

return $hydrator->getProfile();
}
}
14 changes: 14 additions & 0 deletions src/Instagram/Hydrator/ProfileHydrator.php
Original file line number Diff line number Diff line change
Expand Up @@ -79,6 +79,20 @@ public function hydrateMedias(\StdClass $data): void
$this->profile->setEndCursor($data->edge_owner_to_timeline_media->page_info->end_cursor);
}

public function hydrateIgtvs(\StdClass $data): void
{
// reset igtvs
$this->profile->setIGTV([]);

foreach ($data->edge_felix_video_timeline->edges as $item) {
$igtv = $this->mediaHydrator->hydrateMediaFromProfile($item->node);
$this->profile->addIGTV($igtv);
}

$this->profile->setHasMoreIgtvs($data->edge_felix_video_timeline->page_info->end_cursor != null);
$this->profile->setEndCursorIgtvs($data->edge_felix_video_timeline->page_info->end_cursor);
}

/**
* @return Profile
*/
Expand Down
2 changes: 2 additions & 0 deletions src/Instagram/Model/Comment.php
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
<?php

declare(strict_types=1);

namespace Instagram\Model;

class Comment
Expand Down
2 changes: 2 additions & 0 deletions src/Instagram/Model/Media.php
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
<?php

declare(strict_types=1);

namespace Instagram\Model;

use Instagram\Utils\InstagramHelper;
Expand Down
77 changes: 77 additions & 0 deletions src/Instagram/Model/Profile.php
Original file line number Diff line number Diff line change
Expand Up @@ -81,6 +81,21 @@ class Profile
*/
private $endCursor = null;

/**
* @var Media[]
*/
private $igtvs = [];

/**
* @var bool
*/
private $hasMoreIgtvs = false;

/**
* @var string
*/
private $endCursorIgtvs = null;

/**
* @return string
*/
Expand Down Expand Up @@ -274,6 +289,9 @@ public function addMedia(Media $media): void
$this->medias[] = $media;
}

/**
* @param bool $hasMoreMedias
*/
public function setHasMoreMedias(bool $hasMoreMedias): void
{
$this->hasMoreMedias = $hasMoreMedias;
Expand Down Expand Up @@ -331,6 +349,9 @@ public function toArray(): array
'medias' => array_map(function ($media) {
return $media->toArray();
}, $this->medias),
'igtvs' => array_map(function ($igtv) {
return $igtv->toArray();
}, $this->igtvs),
'hasMoreMedias' => $this->hasMoreMedias,
'endCursor' => $this->endCursor,
];
Expand Down Expand Up @@ -359,4 +380,60 @@ public function setId32Bit(string $id32Bit): void
{
$this->id32Bit = $id32Bit;
}

/**
* @param Media[] $igtvs
*/
public function setIgtv(array $igtvs): void
{
$this->igtvs = $igtvs;
}

/**
* @return Media[]
*/
public function getIgtvs(): array
{
return $this->igtvs;
}

/**
* @param Media $igtv
*/
public function addIgtv(Media $igtv): void
{
$this->igtvs[] = $igtv;
}

/**
* @param bool $hasMoreIgtvs
*/
public function setHasMoreIgtvs(bool $hasMoreIgtvs): void
{
$this->hasMoreIgtvs = $hasMoreIgtvs;
}

/**
* @return bool
*/
public function hasMoreIgtvs(): bool
{
return $this->hasMoreIgtvs;
}

/**
* @return string
*/
public function getEndCursorIgtvs(): ?string
{
return $this->endCursorIgtvs;
}

/**
* @param string|null $endCursorIgtvs
*/
public function setEndCursorIgtvs(?string $endCursorIgtvs): void
{
$this->endCursorIgtvs = $endCursorIgtvs;
}
}
2 changes: 2 additions & 0 deletions src/Instagram/Model/Reels.php
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
<?php

declare(strict_types=1);

namespace Instagram\Model;

class Reels
Expand Down
4 changes: 2 additions & 2 deletions src/Instagram/Transport/HtmlProfileDataFeed.php
Original file line number Diff line number Diff line change
Expand Up @@ -45,7 +45,7 @@ public function fetchData(string $userName): \StdClass
preg_match('/<script type="text\/javascript">window\._sharedData\s?=(.+);<\/script>/', $html, $matches);

if (!isset($matches[1])) {
throw new InstagramFetchException('Unable to extract JSON data');
throw new InstagramFetchException('Profile #1 : Unable to extract JSON data');
}

$data = json_decode($matches[1], false);
Expand All @@ -61,7 +61,7 @@ public function fetchData(string $userName): \StdClass
preg_match('/<script type="text\/javascript">window\.__additionalDataLoaded\([^,]*,(.+)\);<\/script>/', $html, $matches);

if (!isset($matches[1])) {
throw new InstagramFetchException('Unable to extract JSON data');
throw new InstagramFetchException('Profile #2 : Unable to extract JSON data');
}

$data = json_decode($matches[1], false);
Expand Down
12 changes: 8 additions & 4 deletions src/Instagram/Transport/JsonMediasDataFeed.php
Original file line number Diff line number Diff line change
Expand Up @@ -11,21 +11,25 @@ class JsonMediasDataFeed extends AbstractDataFeed
{
/**
* @param Profile $instagramProfile
* @param int $limit
* @param int $limit
* @param string $queryHash
*
* @return \StdClass
*
* @throws InstagramFetchException
*/
public function fetchData(Profile $instagramProfile, int $limit): \StdClass
public function fetchData(Profile $instagramProfile, int $limit, string $queryHash = InstagramHelper::QUERY_HASH_MEDIAS): \StdClass
{
// check if this method was called for medias or igtvs
$after = $queryHash === InstagramHelper::QUERY_HASH_MEDIAS ? $instagramProfile->getEndCursor() : $instagramProfile->getEndCursorIgtvs();

$variables = [
'id' => PHP_INT_SIZE === 4 ? $instagramProfile->getId32Bit() : $instagramProfile->getId(),
'first' => $limit,
'after' => $instagramProfile->getEndCursor()
'after' => $after,
];

$endpoint = InstagramHelper::URL_BASE . 'graphql/query/?query_hash=' . InstagramHelper::QUERY_HASH_MEDIAS . '&variables=' . json_encode($variables);
$endpoint = InstagramHelper::URL_BASE . 'graphql/query/?query_hash=' . $queryHash . '&variables=' . json_encode($variables);

$data = $this->fetchJsonDataFeed($endpoint);

Expand Down
1 change: 1 addition & 0 deletions src/Instagram/Utils/InstagramHelper.php
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ class InstagramHelper

const QUERY_HASH_PROFILE = 'c9100bf9110dd6361671f113dd02e7d6';
const QUERY_HASH_MEDIAS = '42323d64886122307be10013ad2dcc44';
const QUERY_HASH_IGTVS = 'bc78b344a68ed16dd5d7f264681c4c76';
const QUERY_HASH_STORIES = '5ec1d322b38839230f8e256e1f638d5f';
const QUERY_HASH_HIGHLIGHTS_FOLDERS = 'ad99dd9d3646cc3c0dda65debcd266a7';
const QUERY_HASH_HIGHLIGHTS_STORIES = '5ec1d322b38839230f8e256e1f638d5f';
Expand Down
Loading

0 comments on commit b0ff8be

Please sign in to comment.