Skip to content

Commit

Permalink
adaption to data structure changes
Browse files Browse the repository at this point in the history
  • Loading branch information
kringkaste committed Jan 4, 2024
1 parent fd79158 commit 88d2301
Show file tree
Hide file tree
Showing 3 changed files with 90 additions and 76 deletions.
8 changes: 8 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,13 @@
# Release Notes for Instagram Feed Plugin

## 2.2.0 - 2024-01-04

> {note} Instagram has changed the data structure. If you no longer get a feed, this update should fix the problem.
### Changed

- Adaptation to the recent changes in the data structure of Instagram.

## 2.1.0 - 2022-10-21

### Added
Expand Down
2 changes: 1 addition & 1 deletion composer.json
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
{
"name": "codemonauts/craft-instagram-feed",
"description": "Craft CMS plugin to receive Instagram feed data as variable in templates.",
"version": "2.1.0",
"version": "2.2.0",
"type": "craft-plugin",
"keywords": [
"craft",
Expand Down
156 changes: 81 additions & 75 deletions src/services/InstagramService.php
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@
use craft\helpers\FileHelper;
use Exception;
use GuzzleHttp\Client;
use GuzzleHttp\Cookie\CookieJar;
use GuzzleHttp\Exception\GuzzleException;
use Throwable;
use yii\base\InvalidConfigException;
Expand Down Expand Up @@ -106,31 +107,22 @@ public function getFeed(string $accountOrTag = null): array
* Fetches the feed from the public Instagram profile page.
*
* @param string $account The account name to fetch.
*
* @return array
* @throws \GuzzleHttp\Exception\GuzzleException
* @throws \craft\errors\SiteNotFoundException
*/
private function getInstagramAccountData(string $account): array
{
$html = $this->fetchInstagramPage($account . '/');
$html = $this->fetchInstagramAccount($account);

if (null === $html) {
Craft::error('Instagram profile data could not be fetched.', 'instagramfeed');

return [];
}

if ($this->canUseProxy()) {
$obj = $this->parseProxyResponse($html);
if (false === $obj) {
return [];
}
} else {
$obj = $this->parseInstagramResponse($html);
if (empty($obj)) {
return [];
}
$obj = $this->parseProxyResponse($html);
if (false === $obj) {
return [];
}

return $this->extractMedia($obj);
Expand All @@ -140,53 +132,40 @@ private function getInstagramAccountData(string $account): array
* Fetches the feed from the public Instagram tag page.
*
* @param string $tag The tag name to fetch.
*
* @return array
* @throws \GuzzleHttp\Exception\GuzzleException
* @throws \craft\errors\SiteNotFoundException
*/
private function getInstagramTagData(string $tag): array
{
$tag = substr($tag, 1);

$path = sprintf('explore/tags/%s/', $tag);
$html = $this->fetchInstagramPage($path);
$html = $this->fetchInstagramTag($tag);

if (null === $html) {
Craft::error('Instagram tag data could not be fetched.', 'instagramfeed');

return [];
}

if ($this->canUseProxy()) {
$obj = $this->parseProxyResponse($html);
if (false === $obj) {
return [];
}
} else {
$obj = $this->parseInstagramResponse($html);
if (empty($obj)) {
return [];
}
$obj = $this->parseProxyResponse($html);
if (false === $obj) {
return [];
}

return $this->extractMedia($obj);
}

/**
* Fetches the page from a given URL
*
* @param string $path The path to fetch
* Fetches an account from Instagram.
*
* @param string $account The account name to fetch.
* @return string|null
* @throws \GuzzleHttp\Exception\GuzzleException
* @throws \craft\errors\SiteNotFoundException
*/
private function fetchInstagramPage(string $path): ?string
private function fetchInstagramAccount(string $account): ?string
{
$url = 'https://www.instagram.com/' . $path;

$client = new Client();
$cookies = new CookieJar();
$client = new Client([
'cookies' => $cookies,
]);

$guzzleOptions = [
'timeout' => InstagramFeed::$settings->timeout,
Expand All @@ -196,16 +175,24 @@ private function fetchInstagramPage(string $path): ?string
],
];

if ($this->canUseProxy()) {
$url = 'https://igproxy.codemonauts.com/' . $path;
$referer = Craft::$app->getSites()->getCurrentSite()->getBaseUrl();
$guzzleOptions['headers']['Authorization'] = InstagramFeed::$settings->proxyKey;
$guzzleOptions['headers']['Referer'] = $referer;
$guzzleOptions['headers']['X-Plugin-Version'] = InstagramFeed::$plugin->getVersion();
}

try {
$response = $client->get($url, $guzzleOptions);
if ($this->canUseProxy()) {
$url = sprintf('https://igproxy.codemonauts.com/%s/', $account);
$referer = Craft::$app->getSites()->getCurrentSite()->getBaseUrl();
$guzzleOptions['headers']['Authorization'] = InstagramFeed::$settings->proxyKey;
$guzzleOptions['headers']['Referer'] = $referer;
$guzzleOptions['headers']['X-Plugin-Version'] = InstagramFeed::$plugin->getVersion();
$response = $client->get($url, $guzzleOptions);
} else {
$url = sprintf('https://www.instagram.com/%s/', $account);
$client->get($url, $guzzleOptions);
$guzzleOptions['headers']['Referer'] = $url;
$guzzleOptions['headers']['X-IG-App-ID'] = '936619743392459';
$guzzleOptions['headers']['X-Requested-With'] = 'XMLHttpRequest';
$guzzleOptions['headers']['Origin'] = 'https://www.instagram.com';
$url = sprintf('https://www.instagram.com/api/v1/users/web_profile_info/?username=%s', $account);
$response = $client->get($url, $guzzleOptions);
}
} catch (Exception $e) {
Craft::error('Error fetching page: ' . $e->getMessage(), 'instagramfeed');

Expand All @@ -216,51 +203,70 @@ private function fetchInstagramPage(string $path): ?string
}

/**
* Function to parse the response body from the proxy.
* Fetches a tag from Instagram.
*
* @param string $response
*
* @return mixed
* @param string $tag The tag to fetch.
* @return string|null
* @throws \GuzzleHttp\Exception\GuzzleException
*/
private function parseProxyResponse(string $response): mixed
private function fetchInstagramTag(string $tag): ?string
{
if (InstagramFeed::$settings->dump) {
$this->dumpResponse($response);
$tag = substr($tag, 1);

$cookies = new CookieJar();
$client = new Client([
'cookies' => $cookies,
]);

$guzzleOptions = [
'timeout' => InstagramFeed::$settings->timeout,
'headers' => [
'Accept-Language' => 'en-US;q=0.9,en;q=0.8',
'User-Agent' => self::DEFAULT_USER_AGENT,
],
];

try {
if ($this->canUseProxy()) {
$url = sprintf('https://igproxy.codemonauts.com/explore/tags/%s/', $tag);
$referer = Craft::$app->getSites()->getCurrentSite()->getBaseUrl();
$guzzleOptions['headers']['Authorization'] = InstagramFeed::$settings->proxyKey;
$guzzleOptions['headers']['Referer'] = $referer;
$guzzleOptions['headers']['X-Plugin-Version'] = InstagramFeed::$plugin->getVersion();
$response = $client->get($url, $guzzleOptions);
} else {
$url = sprintf('https://www.instagram.com/explore/tags/%s/', $tag);
$client->get($url, $guzzleOptions);
$guzzleOptions['headers']['Referer'] = $url;
$guzzleOptions['headers']['X-IG-App-ID'] = '936619743392459';
$guzzleOptions['headers']['X-Requested-With'] = 'XMLHttpRequest';
$guzzleOptions['headers']['Origin'] = 'https://www.instagram.com';
$url = sprintf('https://www.instagram.com/api/v1/tags/logged_out_web_info/?tag_name=%s', $tag);
$response = $client->get($url, $guzzleOptions);
}
} catch (Exception $e) {
Craft::error('Error fetching page: ' . $e->getMessage(), 'instagramfeed');

return null;
}

return json_decode($response, true);
return (string)$response->getBody();
}

/**
* Function to parse the response body from Instagram
* Function to parse the response body from the proxy.
*
* @param string $response Response body from Instagram
* @param string $response
*
* @return array
* @return mixed
*/
private function parseInstagramResponse(string $response): array
private function parseProxyResponse(string $response): mixed
{
$arr = explode('window._sharedData = ', $response);

if (!isset($arr[1])) {
// Check if Instagram returned a statement and not a valid page
$statement = json_decode($response, false);
if (isset($statement->errors)) {
Craft::error('Instagram responsed with an error: ' . implode(' ', $statement->errors->error), 'instagramfeed');
} else {
Craft::error('Unknown response from Instagram. Please check debug output in devMode.', 'instagramfeed');
}

$this->dumpResponse($response);
return [];
}

if (InstagramFeed::$settings->dump) {
$this->dumpResponse($response);
}

$arr = explode(';</script>', $arr[1]);
return json_decode($arr[0], true);
return json_decode($response, true);
}

/**
Expand Down

0 comments on commit 88d2301

Please sign in to comment.