From 087e790ec10d287f944e3abeb5ab3bda9a1a045a Mon Sep 17 00:00:00 2001 From: sysadminstory Date: Wed, 19 Jul 2023 03:28:14 +0200 Subject: [PATCH] [ImgsedBridge] Add new Instagram Bridge Alternative (#3550) * [ImgsedBridge] Add new Instagram Bridge Alternative Imgsed is a Website adverstised on instagram website, that's is not behind Cloudflare Anti Bot feature. You can select to display Posts, Tags, and Stories of a specific username * [ImgsedBridge] Fix empty defaultValue --- bridges/ImgsedBridge.php | 256 +++++++++++++++++++++++++++++++++++++++ 1 file changed, 256 insertions(+) create mode 100644 bridges/ImgsedBridge.php diff --git a/bridges/ImgsedBridge.php b/bridges/ImgsedBridge.php new file mode 100644 index 00000000..6c49facb --- /dev/null +++ b/bridges/ImgsedBridge.php @@ -0,0 +1,256 @@ + [ + 'u' => [ + 'name' => 'username', + 'type' => 'text', + 'title' => 'Instagram username you want to follow', + 'exampleValue' => 'aesoprockwins', + 'required' => true, + ], + 'post' => [ + 'name' => 'posts', + 'type' => 'checkbox', + 'title' => 'Show posts for this Instagram user', + 'defaultValue' => 'checked', + ], + 'story' => [ + 'name' => 'stories', + 'type' => 'checkbox', + 'title' => 'Show stories for this Instagram user', + ], + 'tagged' => [ + 'name' => 'tagged', + 'type' => 'checkbox', + 'title' => 'Show tagged post for this Instagram user', + ], + ] + ]; + + public function getURI() + { + if (!is_null($this->getInput('u'))) { + return urljoin(self::URI, '/' . $this->getInput('u') . '/'); + } + + return parent::getURI(); + } + + public function collectData() + { + $username = $this->getInput('u'); + try { + // Check if the user exist + $html = getSimpleHTMLDOMCached(self::URI . $username . '/'); + if ($this->getInput('post')) { + $this->collectPosts(); + } + if ($this->getInput('story')) { + $this->collectStories(); + } + if ($this->getInput('tagged')) { + $this->collectTaggeds(); + } + } catch (HttpException $e) { + throw new \Exception(sprintf('Unable to find user `%s`', $username)); + } + } + + private function collectPosts() + { + $username = $this->getInput('u'); + $html = getSimpleHTMLDOMCached(self::URI . $username . '/'); + $html = defaultLinkTo($html, self::URI); + + foreach ($html->find('div[class=item]') as $post) { + $url = $post->find('a', 0)->href; + $instagramURL = $this->convertURLToInstagram($url); + $date = $this->parseDate($post->find('div[class=time]', 0)->plaintext); + $description = $post->find('img', 0)->alt; + $imageUrl = $post->find('img', 0)->src; + // Sometimes, there is some lazy image instead of the real URL + if ($imageUrl == 'https://imgsed.com/img/lazy.jpg') { + $imageUrl = $post->find('img', 0)->getAttribute('data-src'); + } + $download = $post->find('a[class=download]', 0)->href; + $author = $username; + $uid = $post->find('a', 0)->href; + $title = 'Post - ' . $username . ' - ' . $this->descriptionToTitle($description); + + // Checking post type + $isVideo = (bool) $post->find('i[class=video]', 0); + $videoNote = $isVideo ? '

(video)

' : ''; + + $isMoreContent = (bool) $post->find('svg', 0); + $moreContentNote = $isMoreContent ? '

(multiple images and/or videos)

' : ''; + + + + + $this->items[] = [ + 'uri' => $url, + 'author' => $author, + 'timestamp' => $date, + 'title' => $title, + 'thumbnail' => $imageUrl, + 'enclosures' => [$imageUrl, $download], + 'content' => << + {$description} + +{$videoNote} +{$moreContentNote} +

{$description}

+

Download

+

Display on Instagram

+HTML, + 'uid' => $uid + ]; + } + } + + private function collectStories() + { + try { + $username = $this->getInput('u'); + $html = getSimpleHTMLDOMCached(self::URI . 'api/media/?name=' . $username); + $json = Json::decode($html); + + foreach ($json as $post) { + $url = $post['src']; + $imageUrl = $post['thumb']; + $download = $url; + $author = $username; + $uid = $url; + $title = 'Story - ' . $username; + + $this->items[] = [ + 'uri' => $url, + 'author' => $author, + 'title' => $title, + 'thumbnail' => $imageUrl, + 'enclosures' => [$imageUrl, $download], + 'content' => << + story + +

Download

+ HTML, + 'uid' => $uid + ]; + } + } catch (Exception $e) { + // If it fails, it's because there are no stories, so don't do anything + } + } + + private function collectTaggeds() + { + $username = $this->getInput('u'); + try { + $html = getSimpleHTMLDOMCached(self::URI . 'tagged/' . $username . '/'); + $html = defaultLinkTo($html, self::URI); + + foreach ($html->find('div[class=item]') as $post) { + $url = $post->find('a', 1)->href; + $instagramURL = $this->convertURLToInstagram($url); + $fromURL = $post->find('div[class=username]', 0)->find('a', 0)->href; + $fromUsername = $post->find('div[class=username]', 0)->plaintext; + $date = $this->parseDate($post->find('div[class=time]', 0)->plaintext); + $description = $post->find('img', 0)->alt; + $imageUrl = $post->find('img', 0)->src; + $download = $post->find('a[class=download]', 0)->href; + $author = $fromUsername; + $uid = $post->find('a', 0)->href; + $title = 'Tagged - ' . $fromUsername . ' - ' . $this->descriptionToTitle($description); + + // Checking post type + $isVideo = (bool) $post->find('i[class=video]', 0); + $videoNote = $isVideo ? '

(video)

' : ''; + + $isMoreContent = (bool) $post->find('svg', 0); + $moreContentNote = $isMoreContent ? '

(multiple images and/or videos)

' : ''; + + + $this->items[] = [ + 'uri' => $url, + 'author' => $author, + 'timestamp' => $date, + 'title' => $title, + 'thumbnail' => $imageUrl, + 'enclosures' => [$imageUrl, $download], + 'content' => << + {$description} + +{$videoNote} +{$moreContentNote} +

From {$fromUsername}

+

{$description}

+

Download

+

Display on Instagram

+HTML, + 'uid' => $uid + ]; + } + } catch (Exception $e) { + // If it fails, it's because the account was not tagged + } + } + + // Parse date, and transform the date into a timetamp, even in a case of a relative date + private function parseDate($content) + { + $date = date_create(); + $relativeDate = date_interval_create_from_date_string(str_replace(' ago', '', $content)); + if ($relativeDate) { + date_sub($date, $relativeDate); + } + return date_format($date, 'r'); + } + + private function convertURLToInstagram($url) + { + return str_replace(self::URI, self::INSTAGRAMURI, $url); + } + private function descriptionToTitle($description) + { + return strlen($description) > 60 ? mb_substr($description, 0, 57) . '...' : $description; + } + + public function getName() + { + if (!is_null($this->getInput('u'))) { + $types = []; + if ($this->getInput('post')) { + $types[] = 'Posts'; + } + if ($this->getInput('story')) { + $types[] = 'Stories'; + } + if ($this->getInput('tagged')) { + $types[] = 'Tags'; + } + $typesText = $types[0]; + if (count($types) > 1) { + for ($i = 1; $i < count($types) - 1; $i++) { + $typesText .= ', ' . $types[$i]; + } + $typesText .= ' & ' . $types[$i]; + } + + return 'Username ' . $this->getInput('u') . ' - ' . $typesText . ' - Imgsed Bridge'; + } + return parent::getName(); + } +}