Skip to content

Commit

Permalink
Merge pull request #16 from hyvor/dev
Browse files Browse the repository at this point in the history
Facebook
  • Loading branch information
supun-io authored Oct 23, 2024
2 parents a7bdddb + 8e29952 commit b053d8f
Show file tree
Hide file tree
Showing 20 changed files with 349 additions and 10 deletions.
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -10,11 +10,11 @@ OEmbed:
- X (Twitter)
- TikTok
- Reddit
- Facebook

Custom:

- Youtube
- Facebook
- Instagram
- Github Gist

Expand Down
26 changes: 25 additions & 1 deletion src/Embed/Embed.php
Original file line number Diff line number Diff line change
Expand Up @@ -17,10 +17,15 @@ class Embed
public static function getParsers(): array
{
$namespace = __NAMESPACE__ . '\\Platforms\\';
return array_map(

$parsers = array_map(
fn ($file) => $namespace . pathinfo((string)$file, PATHINFO_FILENAME),
(array)glob(__DIR__ . '/Platforms/*.php')
);

usort($parsers, fn ($a, $b) => $b::PRIORITY <=> $a::PRIORITY);

return $parsers;
}

/**
Expand All @@ -40,6 +45,25 @@ public static function parse(
throw new EmbedUnableToResolveException();
}

/**
* @param string $url
* @return array{parser: EmbedParserAbstract, matches: string[]}|null
*/
public static function getMatchingParser(string $url): ?array
{
foreach (self::getParsers() as $parserClass) {
/** @var EmbedParserAbstract $parser */
$parser = new $parserClass($url);
if ($parser->match()) {
return [
'parser' => $parser,
'matches' => $parser->match(),
];
}
}
return null;
}

/**
* @throws UnfoldException
*/
Expand Down
3 changes: 3 additions & 0 deletions src/Embed/EmbedParserAbstract.php
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,9 @@
*/
abstract class EmbedParserAbstract
{
// define priority relatively
public const PRIORITY = 0;

protected UnfoldConfig $config;

public function __construct(
Expand Down
15 changes: 15 additions & 0 deletions src/Embed/PlatformHelpers/FacebookHelper.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
<?php

namespace Hyvor\Unfold\Embed\PlatformHelpers;

class FacebookHelper
{
public static function sdkScript(): string
{
return <<<HTML
<div id="fb-root"></div>
<script async defer crossorigin="anonymous" src="https://connect.facebook.net/en_GB/sdk.js#xfbml=1&version=v21.0"></script>
HTML;
}

}
36 changes: 36 additions & 0 deletions src/Embed/Platforms/FacebookPage.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
<?php

namespace Hyvor\Unfold\Embed\Platforms;

use Hyvor\Unfold\Embed\EmbedParserAbstract;
use Hyvor\Unfold\Embed\EmbedParserCustomInterface;
use Hyvor\Unfold\Embed\PlatformHelpers\FacebookHelper;

class FacebookPage extends EmbedParserAbstract implements EmbedParserCustomInterface
{
public const PRIORITY = 1;

public function regex()
{
return [
/**
* Pages have URLs like: facebook.com/MyPage
* They can also be: facebook.com/MyPage/about
*/
'https?://(www|m).facebook.com/[^/]+/?(about|photos|videos|events|timeline|photos_stream)?/?(\?[^/]+)?$',
];
}

public function getEmbedHtml(array $matches): string
{
$url = $this->url;

$name = explode('/', $url)[3] ?? '';
$sdk = FacebookHelper::sdkScript();

return <<<HTML
$sdk
<div class="fb-page" data-href="$url" data-tabs="timeline" data-width="500" data-height="" data-small-header="false" data-adapt-container-width="true" data-hide-cover="false" data-show-facepile="true"><blockquote cite="$url" class="fb-xfbml-parse-ignore"><a href="$url">$name</a></blockquote></div>
HTML;
}
}
50 changes: 50 additions & 0 deletions src/Embed/Platforms/FacebookPost.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
<?php

namespace Hyvor\Unfold\Embed\Platforms;

use Hyvor\Unfold\Embed\EmbedParserAbstract;
use Hyvor\Unfold\Embed\EmbedParserCustomInterface;
use Hyvor\Unfold\Embed\PlatformHelpers\FacebookHelper;

class FacebookPost extends EmbedParserAbstract implements EmbedParserCustomInterface
{
public const PRIORITY = 2;

public function regex()
{
return [
/**
* The following regex are derived from the FacebookPost oembed schema
* "https://www.facebook.com/* /posts/*",
* "https://www.facebook.com/* /activity/*",
* "https://www.facebook.com/* /photos/*",
* "https://www.facebook.com/photo.php?fbid=*",
* ~~"https://www.facebook.com/photos/*",~~
* "https://www.facebook.com/permalink.php?story_fbid=*",
* "https://www.facebook.com/media/set?set=*",
* ~~"https://www.facebook.com/questions/*",~~
* ~~"https://www.facebook.com/notes/* / * /*"~~
*/

// with username
'https?://(?:www|m|business)\.facebook\.com/(?:[^/]+)/(?:posts|activity|photos)/(?:[^/]+)',
// photo.php
'https?://(?:www|m|business)\.facebook\.com/photo\.php\?[^/]*fbid=(?:\d+)',
// permalink.php and story.php
'https?://(?:www|m|business)\.facebook\.com/(permalink|story)\.php\?[^/]*story_fbid=.*',
// media set
'https?://(?:www|m|business)\.facebook\.com/media/set/\?set=.*',
];
}

public function getEmbedHtml(array $matches): string
{
$url = $this->url;
$sdk = FacebookHelper::sdkScript();

return <<<HTML
$sdk
<div class="fb-post" data-href="$url" data-width="500" data-show-text="true"></div>
HTML;
}
}
46 changes: 46 additions & 0 deletions src/Embed/Platforms/FacebookVideo.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
<?php

namespace Hyvor\Unfold\Embed\Platforms;

use Hyvor\Unfold\Embed\EmbedParserAbstract;
use Hyvor\Unfold\Embed\EmbedParserCustomInterface;
use Hyvor\Unfold\Embed\PlatformHelpers\FacebookHelper;

class FacebookVideo extends EmbedParserAbstract implements EmbedParserCustomInterface
{
public const PRIORITY = 3;

public function regex()
{
return [
/**
* The following regex are derived from the FacebookVideo oembed schema
* "https://www.facebook.com/* /videos/*",
* "https://www.facebook.com/video.php?id=*",
* "https://www.facebook.com/video.php?v=*"
*/

// with username
'https?://(www|m|business)\.facebook\.com/([^/]+)/videos/([^/]+)',

// video.php with id or v
'https?://(www|m|business)\.facebook\.com/video\.php\?[^/]*(id|v)=([^&]+)',

// watch with v
'https?://(www|m|business)\.facebook\.com/watch/?\?[^/]*v=([^&]+)',

// reel
'https?://(www|m|business)\.facebook\.com/reel/([^/]+)',
];
}

public function getEmbedHtml(array $matches): string
{
$sdk = FacebookHelper::sdkScript();
$url = $this->url;
return <<<HTML
$sdk
<div class="fb-video" data-href="$url" data-width="500" data-show-text="true"></div>
HTML;
}
}
6 changes: 1 addition & 5 deletions src/Embed/Platforms/Reddit.php
Original file line number Diff line number Diff line change
Expand Up @@ -11,11 +11,7 @@ public function regex()
{
return [
// oembed
"https://reddit.com/r/.*/comments/.*/.*",
"https://www.reddit.com/r/.*/comments/.*/.*",

// custom
"https://old.reddit.com/r/.*/comments/.*/.*", // added: 2024-10-19
"https://(?:(?:www|old)\.)?reddit.com/r/.*/comments/.*/.*",
];
}

Expand Down
2 changes: 1 addition & 1 deletion src/UnfoldConfig.php
Original file line number Diff line number Diff line change
Expand Up @@ -75,7 +75,7 @@ public function __construct(

/**
* Meta requires an access_token to access the OEmbed Read Graph API
* This is required for both Facebook & Instagram
* This is required for both FacebookPost & Instagram
* @todo
*/
public ?string $facebookAccessToken = null,
Expand Down
14 changes: 14 additions & 0 deletions tests/Unit/Embed/EmbedTest.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
<?php

use Hyvor\Unfold\Embed\Embed;
use Hyvor\Unfold\Embed\Platforms\FacebookPage;
use Hyvor\Unfold\Embed\Platforms\FacebookPost;

it('gets parsers with correct sort', function () {
$parsers = Embed::getParsers();

$fbPost = array_search(FacebookPost::class, $parsers);
$fbPage = array_search(FacebookPage::class, $parsers);

expect($fbPost < $fbPage)->toBeTrue();
});
File renamed without changes.
61 changes: 61 additions & 0 deletions tests/Unit/Embed/Platforms/FacebookPageTest.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,61 @@
<?php

namespace Unit\Parsers;

use Hyvor\Unfold\Embed\Embed;
use Hyvor\Unfold\Embed\Platforms\FacebookPage;
use Hyvor\Unfold\Embed\Platforms\FacebookPost;

//it('matches a facebook page', function () {
// $url = 'https://www.facebook.com/GMANetwork/about';
// $parser = new FacebookPage($url);
//
// $response = $parser->parse($parser->match());
// var_dump($response->html);
// expect($response->html)->toBeString();
//});

it('embeds facebook page', function () {
$url = 'https://www.facebook.com/geonarah';

$parser = new FacebookPage($url);
$match = $parser->match();
$response = $parser->parse($match);

$html = $response->html;
expect($html)->toContain('<div class="fb-page" data-href="' . $url);
expect($html)->toContain(
'<script async defer crossorigin="anonymous" src="https://connect.facebook.net/en_GB/sdk.js#xfbml=1&version=v21.0">'
);
});

it('embed class prioritizes facebook post before page', function () {
$url = 'https://www.facebook.com/permalink.php?story_fbid=10159000000000000&id=100000000000000';
$match = Embed::getMatchingParser($url);
expect($match['parser'])->toBeInstanceOf(FacebookPost::class);
expect($match['matches'])->toBeArray();
})
->with([
'https://www.facebook.com/permalink.php?story_fbid=10159000000000000&id=100000000000000',
'https://www.facebook.com/media/set/?set=a.10159000000000000&type=3',
'https://www.facebook.com/photo.php?fbid=10159000000000000',
]);

it('matches', function ($url) {
$parser = new FacebookPage($url);
expect($parser->match())->toBeArray();
})->with([
'https://www.facebook.com/MyPage',
'https://www.facebook.com/MyPage/about',
'https://www.facebook.com/MyPage/photos',
'https://www.facebook.com/MyPage/videos',
'https://www.facebook.com/MyPage/events',
'https://www.facebook.com/MyPage/timeline',
]);

it('does not match', function ($url) {
$parser = new FacebookPage($url);
expect($parser->match())->toBeFalse();
})->with([
'https://www.facebook.com/Mypage/other',
]);
43 changes: 43 additions & 0 deletions tests/Unit/Embed/Platforms/FacebookPostTest.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
<?php

namespace Unit\Parsers;

use Hyvor\Unfold\Embed\Platforms\FacebookPost;

it('parses facebook embeds', function () {
$url = 'https://www.facebook.com/geonarah/posts/pfbid027mqcVugNt1ChK6dwvjR2SkVJrtN754X1toi1XA1auyHgrng1g3bb3Ph2DoYANAhnl';

$parser = new FacebookPost($url);
$match = $parser->match();
$response = $parser->parse($match);

$html = $response->html;
expect($html)->toContain('<div class="fb-post" data-href="' . $url);
expect($html)->toContain(
'<script async defer crossorigin="anonymous" src="https://connect.facebook.net/en_GB/sdk.js#xfbml=1&version=v21.0">'
);
});

it('matches', function ($url) {
$parser = new FacebookPost($url);
$match = $parser->match();
expect($match)->toBeArray();
})->with([

// post with username
'https://www.facebook.com/geonarah/posts/027mqcVugNt1ChK6dwvjR2SkVJrtN754X1toi1XA1auyHgrng1g3bb3Ph2DoYANAhnl',
'https://www.facebook.com/geonarah/activity/027mqcVugNt1ChK6dwvjR2SkVJrtN754X1toi1XA1auyHgrng1g3bb3Ph2Do',
'https://www.facebook.com/geonarah/photos/027mqcVugNt1ChK6dwvjR2SkVJrtN754X1toi1XA1auyHgrng1g3bb3Ph2Do',

// photo.php
'https://www.facebook.com/photo.php?fbid=934147948738763&set=a.414821727338057&type=3',
'https://www.facebook.com/photo.php?set=a&fbid=934147948738763',

// permalink.php
'https://www.facebook.com/permalink.php?id=100064783864247&story_fbid=pfbid091orNDfpRpetrjS4JfNXPdctLCWG4mjhjP38xCzKxqvWFzHT9Cd4txnuV3MGs1zql',
// story.php
'https://www.facebook.com/story.php?story_fbid=1098197861821196&id=100048929783038',

// media set
'https://www.facebook.com/media/set/?set=a.301563726371715',
]);
Loading

0 comments on commit b053d8f

Please sign in to comment.