Skip to content

Commit

Permalink
New: Add support for YouTube shorts
Browse files Browse the repository at this point in the history
  • Loading branch information
jonnitto committed Jan 7, 2025
1 parent 4825b26 commit d3c30ad
Show file tree
Hide file tree
Showing 5 changed files with 82 additions and 13 deletions.
36 changes: 25 additions & 11 deletions Classes/Service/ApiService.php
Original file line number Diff line number Diff line change
Expand Up @@ -54,7 +54,7 @@ public function __construct()
*/
public function youtube($id, string $type = 'video', ?string $apiKey = null): ?array
{
if (!$id || ($type !== 'video' && $type !== 'playlist')) {
if (!$id || ($type !== 'video' && $type !== 'playlist' && $type !== 'short')) {
return null;
}
if ($apiKey) {
Expand All @@ -63,8 +63,12 @@ public function youtube($id, string $type = 'video', ?string $apiKey = null): ?a
return $data;
}
}
$pathAndQuery = ($type === 'video' ? 'watch?v=' : 'playlist?list=') . $id;
$url = urlencode('https://youtube.com/' . $pathAndQuery);
$prefix = [
'video' => 'watch?v=',
'playlist' => 'playlist?list=',
'short' => 'shorts/',
];
$url = urlencode('https://youtube.com/' . $prefix[$type] . $id);
$data = $this->getJson('https://www.youtube.com/oembed?url=' . $url, $type, 'YouTube Oembed Service', $id);

return $data ?? null;
Expand Down Expand Up @@ -168,7 +172,12 @@ protected function convertToSeconds(?string $ISO8601duration = null): int
*/
protected function makeCallToGoogleApi(string $id, string $apiKey, string $type): ?array
{
$url = sprintf('https://www.googleapis.com/youtube/v3/%ss?key=%s&part=contentDetails', $type, $apiKey);
if ($type == 'short') {
$endpoint = 'videos';
} else {
$endpoint = $type . 's';
}
$url = sprintf('https://www.googleapis.com/youtube/v3/%s?key=%s&part=contentDetails', $endpoint, $apiKey);
$typeForLogger = $type === 'playlistItem' ? 'playlist items' : $type;

if ($type !== 'playlistItem') {
Expand Down Expand Up @@ -203,12 +212,17 @@ protected function getDataFromYoutubeVideoWithApi(string $id, string $apiKey, st
// Get the title
$title = $item['snippet']['title'];

// Get the dimensions
$dom = new DOMDocument();
$dom->loadHTML($item['player']['embedHtml']);
$iframe = $dom->getElementsByTagName('iframe')[0];
$width = $iframe ? (int) $iframe->getAttribute('width') : null;
$height = $iframe ? (int) $iframe->getAttribute('height') : null;
if ($type !== 'short') {
// Get the dimensions
$dom = new DOMDocument();
$dom->loadHTML($item['player']['embedHtml']);
$iframe = $dom->getElementsByTagName('iframe')[0];
$width = $iframe ? (int) $iframe->getAttribute('width') : null;
$height = $iframe ? (int) $iframe->getAttribute('height') : null;
} else {
$width = 9;
$height = 16;
}

// Get the best possible image
$thumbnail = end($item['snippet']['thumbnails']);
Expand All @@ -217,7 +231,7 @@ protected function getDataFromYoutubeVideoWithApi(string $id, string $apiKey, st

// Get the duration
$duration = 0;
if ($type === 'video') {
if ($type !== 'playlist') {
// From a single video
$duration = $this->convertToSeconds($item['contentDetails']['duration']);
} else {
Expand Down
8 changes: 8 additions & 0 deletions Classes/Service/ParseIDService.php
Original file line number Diff line number Diff line change
Expand Up @@ -113,6 +113,9 @@ public function vimeo($url = null): ?string
* http://www.youtube.com/user/Scobleizer#p/u/1/1p3vcRhsYGo
* http://www.youtube.com/watch?v=IdOfTheVideo&feature=c4-overview-vl&list=PlaylistID
* https://www.youtube.com/watch?v=IdOfTheVideo&list=PlaylistID
* shorts/IdOfTheVideo
* youtube.com/shorts/IdOfTheVideo
* https://www.youtube.com/shorts/IdOfTheVideo
*
* @param string|integer $url The URL or the plain id
* @return string|null The video id extracted from url
Expand All @@ -125,6 +128,11 @@ public function youtube($url = null, string $type = 'video'): ?string
$regs = [];
$url = trim((string) $url);

if (strpos($url, 'shorts/') !== false) {
preg_match_all('/shorts\/([A-Za-z0-9_-]*)/', $url, $regs);
return (string) $regs[1][0];
}

if (
preg_match_all(
'/(?<=(?:(?<=v)|(?<=i)|(?<=list))=)[a-zA-Z0-9-]+(?=&)|(?<=(?:(?<=v)|(?<=i)|(?<=list))\/)[^&\n]+|(?<=embed\/)[^"&\n]+|(?<=(?:(?<=v)|(?<=i)|(?<=list))=)[^&\n]+|(?<=youtu.be\/)[^&\n]+/im',
Expand Down
2 changes: 1 addition & 1 deletion Classes/Service/VimeoService.php
Original file line number Diff line number Diff line change
Expand Up @@ -77,7 +77,7 @@ public function getAndSaveDataFromApi(NodeInterface $node, bool $remove = false)
if (isset($data)) {
$videoID = $data['video_id'] ?? $videoID;
$title = $data['title'] ?? null;
$ratio = $data['width'] && $data['height'] ? sprintf('%s / %s', $data['width'], $data['height']) : null;
$ratio = Utility::getRatio($data['width'], $data['height']);
$image = $data['thumbnail_url'] ?? null;
$duration = $data['duration'] ?? null;

Expand Down
5 changes: 4 additions & 1 deletion Classes/Service/YoutubeService.php
Original file line number Diff line number Diff line change
Expand Up @@ -85,7 +85,7 @@ public function getAndSaveDataFromApi(NodeInterface $node, bool $remove = false)

if (isset($data)) {
$title = $data['title'] ?? null;
$ratio = $data['width'] && $data['height'] ? sprintf('%s / %s', $data['width'], $data['height']) : null;
$ratio = Utility::getRatio($data['width'], $data['height']);
$duration = $data['duration'] ?? null;
if (isset($data['imageUrl'], $data['imageResolution'])) {
$image = $data['imageUrl'];
Expand Down Expand Up @@ -140,6 +140,9 @@ public function type(string $url): string
if (!$url) {
return 'video';
}
if (strpos($url, 'shorts/') !== false) {
return 'short';
}
return strpos($url, 'list=') !== false ? 'playlist' : 'video';
}
}
44 changes: 44 additions & 0 deletions Classes/Utility/Utility.php
Original file line number Diff line number Diff line change
Expand Up @@ -123,6 +123,13 @@ public static function youtubeHref(string $videoID, ?string $type = 'video', boo
return sprintf('https://www.youtube.com/playlist?list=%s', $videoID);
}

if ($type == 'short') {
if ($embedded) {
return sprintf('https://www.youtube.com/embed/%s?%s', $videoID, $parameter);
}
return sprintf('https://www.youtube.com/shorts/%s', $videoID);
}

if ($embedded) {
return sprintf('https://www.youtube.com/embed/%s?%s', $videoID, $parameter);
}
Expand Down Expand Up @@ -215,4 +222,41 @@ public static function getBestPossibleYoutubeImage($videoID, ?string $url = null

return null;
}

/**
* Simplifies a fraction by dividing the numerator and denominator by their greatest common divisor.
*
* @param integer $numerator
* @param integer $denominator
* @return string
*/
public static function getRatio($numerator, $denominator): ?string
{
if (!is_int($numerator) || !is_int($denominator) || $denominator == 0) {
return null;
}

$divisor = self::greatestCommonDivisor($numerator, $denominator);
$simplifiedNumerator = $numerator / $divisor;
$simplifiedDenominator = $denominator / $divisor;

return sprintf('%s / %s', $simplifiedNumerator, $simplifiedDenominator);
}

/**
* Calculates the greatest common divisor using the Euclidean algorithm.
*
* @param integer $numerator
* @param integer $denominator
* @return integer
*/
protected static function greatestCommonDivisor(int $numerator, int $denominator): int
{
while ($denominator != 0) {
$temp = $denominator;
$denominator = $numerator % $denominator;
$numerator = $temp;
}
return abs($numerator); // Always return a positive GCD
}
}

0 comments on commit d3c30ad

Please sign in to comment.