TYPO3 v15 dev-main snapshot ()
This commit is contained in:
@@ -0,0 +1,53 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
/*
|
||||
* This file is part of the TYPO3 CMS project.
|
||||
*
|
||||
* It is free software; you can redistribute it and/or modify it under
|
||||
* the terms of the GNU General Public License, either version 2
|
||||
* of the License, or any later version.
|
||||
*
|
||||
* For the full copyright and license information, please read the
|
||||
* LICENSE.txt file that was distributed with this source code.
|
||||
*
|
||||
* The TYPO3 project - inspiring people to share!
|
||||
*/
|
||||
|
||||
namespace TYPO3\CMS\Core\Resource\OnlineMedia\Event;
|
||||
|
||||
use TYPO3\CMS\Core\Resource\File;
|
||||
use TYPO3\CMS\Core\Resource\OnlineMedia\Helpers\OnlineMediaHelperInterface;
|
||||
|
||||
/**
|
||||
* Allows to modify a generated YouTube/Vimeo (or other Online Media) preview images
|
||||
*/
|
||||
final class AfterVideoPreviewFetchedEvent
|
||||
{
|
||||
public function __construct(
|
||||
private readonly File $file,
|
||||
private readonly OnlineMediaHelperInterface $onlineMediaHelper,
|
||||
private string $previewImageFilename
|
||||
) {}
|
||||
|
||||
public function getFile(): File
|
||||
{
|
||||
return $this->file;
|
||||
}
|
||||
|
||||
public function getOnlineMediaId(): string
|
||||
{
|
||||
return $this->onlineMediaHelper->getOnlineMediaId($this->file);
|
||||
}
|
||||
|
||||
public function getPreviewImageFilename(): string
|
||||
{
|
||||
return $this->previewImageFilename;
|
||||
}
|
||||
|
||||
public function setPreviewImageFilename(string $previewImageFilename): void
|
||||
{
|
||||
$this->previewImageFilename = $previewImageFilename;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,101 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of the TYPO3 CMS project.
|
||||
*
|
||||
* It is free software; you can redistribute it and/or modify it under
|
||||
* the terms of the GNU General Public License, either version 2
|
||||
* of the License, or any later version.
|
||||
*
|
||||
* For the full copyright and license information, please read the
|
||||
* LICENSE.txt file that was distributed with this source code.
|
||||
*
|
||||
* The TYPO3 project - inspiring people to share!
|
||||
*/
|
||||
|
||||
namespace TYPO3\CMS\Core\Resource\OnlineMedia\Helpers;
|
||||
|
||||
use TYPO3\CMS\Core\Resource\Exception\OnlineMediaAlreadyExistsException;
|
||||
use TYPO3\CMS\Core\Resource\File;
|
||||
use TYPO3\CMS\Core\Resource\Folder;
|
||||
use TYPO3\CMS\Core\Utility\GeneralUtility;
|
||||
|
||||
/**
|
||||
* See http://oembed.com/ for more on OEmbed specification
|
||||
*/
|
||||
abstract class AbstractOEmbedHelper extends AbstractOnlineMediaHelper
|
||||
{
|
||||
/**
|
||||
* @param string $mediaId
|
||||
* @param string $format
|
||||
* @return string
|
||||
*/
|
||||
abstract protected function getOEmbedUrl($mediaId, $format = 'json');
|
||||
|
||||
/**
|
||||
* Transform mediaId to File
|
||||
*
|
||||
* @param string $mediaId
|
||||
* @param string $fileExtension
|
||||
* @return File
|
||||
*/
|
||||
protected function transformMediaIdToFile($mediaId, Folder $targetFolder, $fileExtension)
|
||||
{
|
||||
$file = $this->findExistingFileByOnlineMediaId($mediaId, $targetFolder, $fileExtension);
|
||||
if ($file !== null) {
|
||||
throw new OnlineMediaAlreadyExistsException($file, 1695236851);
|
||||
}
|
||||
// no existing file create new
|
||||
$oEmbed = $this->getOEmbedData($mediaId);
|
||||
if (!empty($oEmbed['title'])) {
|
||||
$fileName = $oEmbed['title'] . '.' . $fileExtension;
|
||||
} else {
|
||||
$fileName = $mediaId . '.' . $fileExtension;
|
||||
}
|
||||
return $this->createNewFile($targetFolder, $fileName, $mediaId);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get OEmbed data
|
||||
*
|
||||
* @param string $mediaId
|
||||
* @return array|null
|
||||
*/
|
||||
protected function getOEmbedData($mediaId)
|
||||
{
|
||||
$oEmbed = (string)GeneralUtility::getUrl(
|
||||
$this->getOEmbedUrl($mediaId)
|
||||
);
|
||||
if ($oEmbed !== '') {
|
||||
$oEmbed = json_decode($oEmbed, true);
|
||||
if (is_array($oEmbed)) {
|
||||
return $oEmbed;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get meta data for OnlineMedia item
|
||||
* Using the meta data from oEmbed
|
||||
*
|
||||
* @return array with metadata
|
||||
*/
|
||||
public function getMetaData(File $file)
|
||||
{
|
||||
$metadata = [];
|
||||
|
||||
$oEmbed = $this->getOEmbedData($this->getOnlineMediaId($file));
|
||||
|
||||
if (is_array($oEmbed) && $oEmbed !== []) {
|
||||
$metadata['width'] = (int)($oEmbed['width'] ?? 0);
|
||||
$metadata['height'] = (int)($oEmbed['height'] ?? 0);
|
||||
if (empty($file->getProperty('title'))) {
|
||||
$metadata['title'] = strip_tags($oEmbed['title'] ?? '');
|
||||
}
|
||||
$metadata['author'] = $oEmbed['author_name'] ?? '';
|
||||
}
|
||||
|
||||
return $metadata;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,149 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of the TYPO3 CMS project.
|
||||
*
|
||||
* It is free software; you can redistribute it and/or modify it under
|
||||
* the terms of the GNU General Public License, either version 2
|
||||
* of the License, or any later version.
|
||||
*
|
||||
* For the full copyright and license information, please read the
|
||||
* LICENSE.txt file that was distributed with this source code.
|
||||
*
|
||||
* The TYPO3 project - inspiring people to share!
|
||||
*/
|
||||
|
||||
namespace TYPO3\CMS\Core\Resource\OnlineMedia\Helpers;
|
||||
|
||||
use TYPO3\CMS\Core\Core\Environment;
|
||||
use TYPO3\CMS\Core\Resource\Enum\DuplicationBehavior;
|
||||
use TYPO3\CMS\Core\Resource\Exception\IllegalFileExtensionException;
|
||||
use TYPO3\CMS\Core\Resource\Exception\InsufficientFileAccessPermissionsException;
|
||||
use TYPO3\CMS\Core\Resource\File;
|
||||
use TYPO3\CMS\Core\Resource\Folder;
|
||||
use TYPO3\CMS\Core\Resource\Index\FileIndexRepository;
|
||||
use TYPO3\CMS\Core\Resource\ResourceFactory;
|
||||
use TYPO3\CMS\Core\Resource\ResourceInstructionTrait;
|
||||
use TYPO3\CMS\Core\Utility\GeneralUtility;
|
||||
|
||||
abstract class AbstractOnlineMediaHelper implements OnlineMediaHelperInterface
|
||||
{
|
||||
use ResourceInstructionTrait;
|
||||
|
||||
/**
|
||||
* Cached OnlineMediaIds [fileUid => id]
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
protected $onlineMediaIdCache = [];
|
||||
|
||||
/**
|
||||
* File extension bind to the OnlineMedia helper
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
protected $extension = '';
|
||||
|
||||
/**
|
||||
* Constructor
|
||||
*
|
||||
* @param string $extension file extension bind to the OnlineMedia helper
|
||||
*/
|
||||
public function __construct($extension)
|
||||
{
|
||||
$this->extension = $extension;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get Online Media item id
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function getOnlineMediaId(File $file)
|
||||
{
|
||||
if (!isset($this->onlineMediaIdCache[$file->getUid()])) {
|
||||
// Limiting media identifier to 2048 bytes
|
||||
if ($file->getSize() > 2048) {
|
||||
return '';
|
||||
}
|
||||
try {
|
||||
// By definition these files only contain the ID of the remote media source
|
||||
$this->onlineMediaIdCache[$file->getUid()] = trim($file->getContents());
|
||||
} catch (InsufficientFileAccessPermissionsException|IllegalFileExtensionException $e) {
|
||||
// User has no access to the file - online media id can not be fetched
|
||||
return '';
|
||||
}
|
||||
}
|
||||
return $this->onlineMediaIdCache[$file->getUid()];
|
||||
}
|
||||
|
||||
/**
|
||||
* Search for files with same onlineMediaId by content hash in indexed storage
|
||||
*
|
||||
* @param string $onlineMediaId
|
||||
* @param string $fileExtension
|
||||
* @return File|null
|
||||
*/
|
||||
protected function findExistingFileByOnlineMediaId($onlineMediaId, Folder $targetFolder, $fileExtension)
|
||||
{
|
||||
$file = null;
|
||||
$fileHash = sha1($onlineMediaId);
|
||||
$files = $this->getFileIndexRepository()->findByContentHash($fileHash);
|
||||
if (!empty($files)) {
|
||||
foreach ($files as $fileIndexEntry) {
|
||||
if (
|
||||
$fileIndexEntry['folder_hash'] === $targetFolder->getHashedIdentifier()
|
||||
&& (int)$fileIndexEntry['storage'] === $targetFolder->getStorage()->getUid()
|
||||
&& $fileIndexEntry['extension'] === $fileExtension
|
||||
) {
|
||||
$file = $this->getResourceFactory()->getFileObject($fileIndexEntry['uid'], $fileIndexEntry);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
return $file;
|
||||
}
|
||||
|
||||
/**
|
||||
* Create new OnlineMedia item container file.
|
||||
* This is created inside typo3temp/ and then moved from FAL to the proper storage.
|
||||
*
|
||||
* @param string $fileName
|
||||
* @param string $onlineMediaId
|
||||
* @return File
|
||||
*/
|
||||
protected function createNewFile(Folder $targetFolder, $fileName, $onlineMediaId)
|
||||
{
|
||||
$temporaryFile = GeneralUtility::tempnam('online_media');
|
||||
GeneralUtility::writeFileToTypo3tempDir($temporaryFile, $onlineMediaId);
|
||||
$this->skipResourceConsistencyCheckForCommands($targetFolder->getStorage(), $temporaryFile, $fileName);
|
||||
$file = $targetFolder->addFile($temporaryFile, $fileName, DuplicationBehavior::RENAME);
|
||||
return $file;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get temporary folder path to save preview images.
|
||||
* In composer-mode with TYPO3 installations, this needs to be put under public/
|
||||
* In the future this should be handled via processed file objects.
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
protected function getTempFolderPath()
|
||||
{
|
||||
$path = Environment::getPublicPath() . '/typo3temp/assets/online_media/';
|
||||
if (!is_dir($path)) {
|
||||
GeneralUtility::mkdir_deep($path);
|
||||
}
|
||||
return $path;
|
||||
}
|
||||
|
||||
protected function getFileIndexRepository(): FileIndexRepository
|
||||
{
|
||||
return GeneralUtility::makeInstance(FileIndexRepository::class);
|
||||
}
|
||||
|
||||
protected function getResourceFactory(): ResourceFactory
|
||||
{
|
||||
return GeneralUtility::makeInstance(ResourceFactory::class);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,77 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of the TYPO3 CMS project.
|
||||
*
|
||||
* It is free software; you can redistribute it and/or modify it under
|
||||
* the terms of the GNU General Public License, either version 2
|
||||
* of the License, or any later version.
|
||||
*
|
||||
* For the full copyright and license information, please read the
|
||||
* LICENSE.txt file that was distributed with this source code.
|
||||
*
|
||||
* The TYPO3 project - inspiring people to share!
|
||||
*/
|
||||
|
||||
namespace TYPO3\CMS\Core\Resource\OnlineMedia\Helpers;
|
||||
|
||||
use TYPO3\CMS\Core\Resource\File;
|
||||
use TYPO3\CMS\Core\Resource\Folder;
|
||||
|
||||
/**
|
||||
* Interface OnlineMediaInterface
|
||||
*/
|
||||
interface OnlineMediaHelperInterface
|
||||
{
|
||||
/**
|
||||
* Constructor
|
||||
*
|
||||
* @param string $extension file extension bind to the OnlineMedia helper
|
||||
*/
|
||||
public function __construct($extension);
|
||||
|
||||
/**
|
||||
* Try to transform given URL to a File
|
||||
*
|
||||
* @param string $url
|
||||
* @return File|null
|
||||
*/
|
||||
public function transformUrlToFile($url, Folder $targetFolder);
|
||||
|
||||
/**
|
||||
* Get Online Media item id
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function getOnlineMediaId(File $file);
|
||||
|
||||
/**
|
||||
* Get public url
|
||||
*
|
||||
* Return NULL if you want to use core default behaviour
|
||||
*
|
||||
* @param File $file
|
||||
* @return string|null
|
||||
*/
|
||||
public function getPublicUrl(File $file);
|
||||
|
||||
/**
|
||||
* Get local absolute file path to preview image
|
||||
*
|
||||
* Return an empty string when no preview image is available
|
||||
*
|
||||
* @param File $file
|
||||
* @return string
|
||||
*/
|
||||
public function getPreviewImage(File $file);
|
||||
|
||||
/**
|
||||
* Get meta data for OnlineMedia item
|
||||
*
|
||||
* See $GLOBALS[TCA][sys_file_metadata][columns] for possible fields to fill/use
|
||||
*
|
||||
* @param File $file
|
||||
* @return array with metadata
|
||||
*/
|
||||
public function getMetaData(File $file);
|
||||
}
|
||||
@@ -0,0 +1,83 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of the TYPO3 CMS project.
|
||||
*
|
||||
* It is free software; you can redistribute it and/or modify it under
|
||||
* the terms of the GNU General Public License, either version 2
|
||||
* of the License, or any later version.
|
||||
*
|
||||
* For the full copyright and license information, please read the
|
||||
* LICENSE.txt file that was distributed with this source code.
|
||||
*
|
||||
* The TYPO3 project - inspiring people to share!
|
||||
*/
|
||||
|
||||
namespace TYPO3\CMS\Core\Resource\OnlineMedia\Helpers;
|
||||
|
||||
use TYPO3\CMS\Core\Resource\File;
|
||||
use TYPO3\CMS\Core\Resource\Folder;
|
||||
use TYPO3\CMS\Core\SingletonInterface;
|
||||
use TYPO3\CMS\Core\Utility\GeneralUtility;
|
||||
|
||||
/**
|
||||
* Online Media Source Registry
|
||||
*/
|
||||
class OnlineMediaHelperRegistry implements SingletonInterface
|
||||
{
|
||||
/**
|
||||
* Checks if there is a helper for this file extension
|
||||
*/
|
||||
public function hasOnlineMediaHelper(string $fileExtension): bool
|
||||
{
|
||||
return isset($GLOBALS['TYPO3_CONF_VARS']['SYS']['fal']['onlineMediaHelpers'][$fileExtension]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get helper class for given File
|
||||
*
|
||||
* @return false|OnlineMediaHelperInterface
|
||||
*/
|
||||
public function getOnlineMediaHelper(File $file)
|
||||
{
|
||||
$registeredHelpers = $GLOBALS['TYPO3_CONF_VARS']['SYS']['fal']['onlineMediaHelpers'];
|
||||
if (isset($registeredHelpers[$file->getExtension()])) {
|
||||
return GeneralUtility::makeInstance($registeredHelpers[$file->getExtension()], $file->getExtension());
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Try to transform given URL to a File
|
||||
*
|
||||
* @param string $url
|
||||
* @param string[] $allowedExtensions
|
||||
* @return File|null
|
||||
*/
|
||||
public function transformUrlToFile($url, Folder $targetFolder, $allowedExtensions = [])
|
||||
{
|
||||
$registeredHelpers = $GLOBALS['TYPO3_CONF_VARS']['SYS']['fal']['onlineMediaHelpers'];
|
||||
foreach ($registeredHelpers as $extension => $className) {
|
||||
if (!empty($allowedExtensions) && !in_array($extension, $allowedExtensions, true)) {
|
||||
continue;
|
||||
}
|
||||
/** @var OnlineMediaHelperInterface $helper */
|
||||
$helper = GeneralUtility::makeInstance($className, $extension);
|
||||
$file = $helper->transformUrlToFile($url, $targetFolder);
|
||||
if ($file !== null) {
|
||||
return $file;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get all file extensions that have an OnlineMediaHelper
|
||||
*
|
||||
* @return string[]
|
||||
*/
|
||||
public function getSupportedFileExtensions()
|
||||
{
|
||||
return array_keys($GLOBALS['TYPO3_CONF_VARS']['SYS']['fal']['onlineMediaHelpers']);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,98 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of the TYPO3 CMS project.
|
||||
*
|
||||
* It is free software; you can redistribute it and/or modify it under
|
||||
* the terms of the GNU General Public License, either version 2
|
||||
* of the License, or any later version.
|
||||
*
|
||||
* For the full copyright and license information, please read the
|
||||
* LICENSE.txt file that was distributed with this source code.
|
||||
*
|
||||
* The TYPO3 project - inspiring people to share!
|
||||
*/
|
||||
|
||||
namespace TYPO3\CMS\Core\Resource\OnlineMedia\Helpers;
|
||||
|
||||
use TYPO3\CMS\Core\Resource\File;
|
||||
use TYPO3\CMS\Core\Resource\Folder;
|
||||
use TYPO3\CMS\Core\Utility\GeneralUtility;
|
||||
|
||||
/**
|
||||
* Vimeo helper class
|
||||
*/
|
||||
class VimeoHelper extends AbstractOEmbedHelper
|
||||
{
|
||||
/**
|
||||
* Get public url
|
||||
* Return NULL if you want to use core default behaviour
|
||||
*
|
||||
* @return string|null
|
||||
*/
|
||||
public function getPublicUrl(File $file)
|
||||
{
|
||||
$videoId = $this->getOnlineMediaId($file);
|
||||
return sprintf('https://vimeo.com/%s', rawurlencode($videoId));
|
||||
}
|
||||
|
||||
/**
|
||||
* Get local absolute file path to preview image
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function getPreviewImage(File $file)
|
||||
{
|
||||
$videoId = $this->getOnlineMediaId($file);
|
||||
$temporaryFileName = $this->getTempFolderPath() . 'vimeo_' . md5($videoId) . '.jpg';
|
||||
if (!file_exists($temporaryFileName)) {
|
||||
$oEmbedData = $this->getOEmbedData($videoId);
|
||||
if (!empty($oEmbedData['thumbnail_url'])) {
|
||||
$previewImage = GeneralUtility::getUrl($oEmbedData['thumbnail_url']);
|
||||
if ($previewImage !== false) {
|
||||
GeneralUtility::writeFile($temporaryFileName, $previewImage, true);
|
||||
}
|
||||
}
|
||||
}
|
||||
return $temporaryFileName;
|
||||
}
|
||||
|
||||
/**
|
||||
* Try to transform given URL to a File
|
||||
*
|
||||
* @param string $url
|
||||
* @return File|null
|
||||
*/
|
||||
public function transformUrlToFile($url, Folder $targetFolder)
|
||||
{
|
||||
$videoId = null;
|
||||
// Try to get the Vimeo code from given url.
|
||||
// Next formats are supported with and without http(s)://
|
||||
// - vimeo.com/<code>/<optionalPrivateCode> # Share URL
|
||||
// - vimeo.com/event/<code>
|
||||
// - player.vimeo.com/video/<code>/<optionalPrivateCode> # URL form iframe embed code, can also get code from full iframe snippet
|
||||
if (preg_match('/vimeo\.com\/(?:video\/|event\/)?([0-9a-z\/]+)/i', $url, $matches)) {
|
||||
$videoId = $matches[1];
|
||||
}
|
||||
if (empty($videoId)) {
|
||||
return null;
|
||||
}
|
||||
return $this->transformMediaIdToFile($videoId, $targetFolder, $this->extension);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get oEmbed data url
|
||||
*
|
||||
* @param string $mediaId
|
||||
* @param string $format
|
||||
* @return string
|
||||
*/
|
||||
protected function getOEmbedUrl($mediaId, $format = 'json')
|
||||
{
|
||||
return sprintf(
|
||||
'https://vimeo.com/api/oembed.%s?width=2048&url=%s',
|
||||
rawurlencode($format),
|
||||
rawurlencode(sprintf('https://vimeo.com/%s', rawurlencode($mediaId)))
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,106 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of the TYPO3 CMS project.
|
||||
*
|
||||
* It is free software; you can redistribute it and/or modify it under
|
||||
* the terms of the GNU General Public License, either version 2
|
||||
* of the License, or any later version.
|
||||
*
|
||||
* For the full copyright and license information, please read the
|
||||
* LICENSE.txt file that was distributed with this source code.
|
||||
*
|
||||
* The TYPO3 project - inspiring people to share!
|
||||
*/
|
||||
|
||||
namespace TYPO3\CMS\Core\Resource\OnlineMedia\Helpers;
|
||||
|
||||
use TYPO3\CMS\Core\Resource\File;
|
||||
use TYPO3\CMS\Core\Resource\Folder;
|
||||
use TYPO3\CMS\Core\Utility\GeneralUtility;
|
||||
|
||||
/**
|
||||
* Youtube helper class
|
||||
*/
|
||||
class YouTubeHelper extends AbstractOEmbedHelper
|
||||
{
|
||||
/**
|
||||
* Get public url
|
||||
*
|
||||
* @return string|null
|
||||
*/
|
||||
public function getPublicUrl(File $file)
|
||||
{
|
||||
$videoId = $this->getOnlineMediaId($file);
|
||||
return sprintf('https://www.youtube.com/watch?v=%s', rawurlencode($videoId));
|
||||
}
|
||||
|
||||
/**
|
||||
* Get local absolute file path to preview image
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function getPreviewImage(File $file)
|
||||
{
|
||||
$videoId = $this->getOnlineMediaId($file);
|
||||
$temporaryFileName = $this->getTempFolderPath() . 'youtube_' . md5($videoId) . '.jpg';
|
||||
|
||||
if (!file_exists($temporaryFileName)) {
|
||||
$tryNames = ['maxresdefault.jpg', 'sddefault.jpg', 'hqdefault.jpg', 'mqdefault.jpg', '0.jpg'];
|
||||
foreach ($tryNames as $tryName) {
|
||||
$previewImage = GeneralUtility::getUrl(
|
||||
sprintf('https://img.youtube.com/vi/%s/%s', $videoId, $tryName)
|
||||
);
|
||||
if ($previewImage !== false) {
|
||||
GeneralUtility::writeFile($temporaryFileName, $previewImage, true);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return $temporaryFileName;
|
||||
}
|
||||
|
||||
/**
|
||||
* Try to transform given URL to a File
|
||||
*
|
||||
* @param string $url
|
||||
* @return File|null
|
||||
*/
|
||||
public function transformUrlToFile($url, Folder $targetFolder)
|
||||
{
|
||||
$videoId = null;
|
||||
// Try to get the YouTube code from given url.
|
||||
// These formats are supported with and without http(s)://
|
||||
// - youtu.be/<code> # Share URL
|
||||
// - www.youtube.com/watch?v=<code> # Normal web link
|
||||
// - www.youtube.com/v/<code>
|
||||
// - www.youtube-nocookie.com/v/<code> # youtube-nocookie.com web link
|
||||
// - www.youtube.com/embed/<code> # URL form iframe embed code, can also get code from full iframe snippet
|
||||
// - www.youtube.com/shorts/<code>
|
||||
// - www.youtube.com/live/<code>
|
||||
if (preg_match('%(?:youtube(?:-nocookie)?\.com/(?:[^/]+/.+/|(?:v|e(?:mbed)?|shorts|live)/|.*[?&]v=)|youtu\.be/)([^"&?/ ]{11})%i', $url, $match)) {
|
||||
$videoId = $match[1];
|
||||
}
|
||||
if (empty($videoId)) {
|
||||
return null;
|
||||
}
|
||||
return $this->transformMediaIdToFile($videoId, $targetFolder, $this->extension);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get oEmbed url to retrieve oEmbed data
|
||||
*
|
||||
* @param string $mediaId
|
||||
* @param string $format
|
||||
* @return string
|
||||
*/
|
||||
protected function getOEmbedUrl($mediaId, $format = 'json')
|
||||
{
|
||||
return sprintf(
|
||||
'https://www.youtube.com/oembed?url=%s&format=%s&maxwidth=2048&maxheight=2048',
|
||||
rawurlencode(sprintf('https://www.youtube.com/watch?v=%s', rawurlencode($mediaId))),
|
||||
rawurlencode($format)
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,88 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of the TYPO3 CMS project.
|
||||
*
|
||||
* It is free software; you can redistribute it and/or modify it under
|
||||
* the terms of the GNU General Public License, either version 2
|
||||
* of the License, or any later version.
|
||||
*
|
||||
* For the full copyright and license information, please read the
|
||||
* LICENSE.txt file that was distributed with this source code.
|
||||
*
|
||||
* The TYPO3 project - inspiring people to share!
|
||||
*/
|
||||
|
||||
namespace TYPO3\CMS\Core\Resource\OnlineMedia\Metadata;
|
||||
|
||||
use TYPO3\CMS\Core\Resource\File;
|
||||
use TYPO3\CMS\Core\Resource\Index\ExtractorInterface;
|
||||
use TYPO3\CMS\Core\Resource\OnlineMedia\Helpers\OnlineMediaHelperRegistry;
|
||||
use TYPO3\CMS\Core\Utility\GeneralUtility;
|
||||
|
||||
class Extractor implements ExtractorInterface
|
||||
{
|
||||
/**
|
||||
* Returns an array of supported file types
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function getFileTypeRestrictions()
|
||||
{
|
||||
return [];
|
||||
}
|
||||
|
||||
/**
|
||||
* Get all supported DriverClasses
|
||||
* empty array indicates no restrictions
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function getDriverRestrictions()
|
||||
{
|
||||
return [];
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the data priority of the extraction Service
|
||||
*
|
||||
* @return int
|
||||
*/
|
||||
public function getPriority()
|
||||
{
|
||||
return 10;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the execution priority of the extraction Service
|
||||
*
|
||||
* @return int
|
||||
*/
|
||||
public function getExecutionPriority()
|
||||
{
|
||||
return 10;
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks if the given file can be processed by this Extractor
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public function canProcess(File $file)
|
||||
{
|
||||
return GeneralUtility::makeInstance(OnlineMediaHelperRegistry::class)->getOnlineMediaHelper($file) !== false;
|
||||
}
|
||||
|
||||
/**
|
||||
* The actual processing TASK
|
||||
* Should return an array with database properties for sys_file_metadata to write
|
||||
*
|
||||
* @param array $previousExtractedData optional, contains the array of already extracted data
|
||||
* @return array
|
||||
*/
|
||||
public function extractMetaData(File $file, array $previousExtractedData = [])
|
||||
{
|
||||
$helper = GeneralUtility::makeInstance(OnlineMediaHelperRegistry::class)->getOnlineMediaHelper($file);
|
||||
return $helper !== false ? $helper->getMetaData($file) : [];
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,72 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of the TYPO3 CMS project.
|
||||
*
|
||||
* It is free software; you can redistribute it and/or modify it under
|
||||
* the terms of the GNU General Public License, either version 2
|
||||
* of the License, or any later version.
|
||||
*
|
||||
* For the full copyright and license information, please read the
|
||||
* LICENSE.txt file that was distributed with this source code.
|
||||
*
|
||||
* The TYPO3 project - inspiring people to share!
|
||||
*/
|
||||
|
||||
namespace TYPO3\CMS\Core\Resource\OnlineMedia\Processing;
|
||||
|
||||
use Psr\EventDispatcher\EventDispatcherInterface;
|
||||
use Symfony\Component\DependencyInjection\Attribute\Autoconfigure;
|
||||
use TYPO3\CMS\Core\Resource\File;
|
||||
use TYPO3\CMS\Core\Resource\OnlineMedia\Event\AfterVideoPreviewFetchedEvent;
|
||||
use TYPO3\CMS\Core\Resource\OnlineMedia\Helpers\OnlineMediaHelperRegistry;
|
||||
use TYPO3\CMS\Core\Resource\Processing\LocalImageProcessor;
|
||||
use TYPO3\CMS\Core\Resource\Processing\ProcessorInterface;
|
||||
use TYPO3\CMS\Core\Resource\Processing\TaskInterface;
|
||||
|
||||
/**
|
||||
* Preview of Online Media item Processing
|
||||
*/
|
||||
#[Autoconfigure(public: true)]
|
||||
final class PreviewProcessing extends LocalImageProcessor implements ProcessorInterface
|
||||
{
|
||||
public function __construct(
|
||||
private readonly OnlineMediaHelperRegistry $onlineMediaHelperRegistry,
|
||||
private readonly EventDispatcherInterface $eventDispatcher,
|
||||
) {}
|
||||
|
||||
public function canProcessTask(TaskInterface $task): bool
|
||||
{
|
||||
if ($task->getType() !== 'Image') {
|
||||
return false;
|
||||
}
|
||||
if (!in_array($task->getName(), ['Preview', 'CropScaleMask'], true)) {
|
||||
return false;
|
||||
}
|
||||
$sourceFile = $task->getSourceFile();
|
||||
if (!$this->onlineMediaHelperRegistry->hasOnlineMediaHelper($sourceFile->getExtension())) {
|
||||
return false;
|
||||
}
|
||||
$previewImageFile = $this->getPreviewImageFromOnlineMedia($sourceFile);
|
||||
return !empty($previewImageFile) && file_exists($previewImageFile);
|
||||
}
|
||||
|
||||
public function processTask(TaskInterface $task): void
|
||||
{
|
||||
$this->processTaskWithLocalFile(
|
||||
$task,
|
||||
$this->getPreviewImageFromOnlineMedia($task->getSourceFile())
|
||||
);
|
||||
}
|
||||
|
||||
private function getPreviewImageFromOnlineMedia(File $file): string
|
||||
{
|
||||
$onlineMediaHelper = $this->onlineMediaHelperRegistry->getOnlineMediaHelper($file);
|
||||
$previewImage = $onlineMediaHelper->getPreviewImage($file);
|
||||
|
||||
$videoPreviewEvent = new AfterVideoPreviewFetchedEvent($file, $onlineMediaHelper, $previewImage);
|
||||
$this->eventDispatcher->dispatch($videoPreviewEvent);
|
||||
|
||||
return $videoPreviewEvent->getPreviewImageFilename();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,54 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
/*
|
||||
* This file is part of the TYPO3 CMS project.
|
||||
*
|
||||
* It is free software; you can redistribute it and/or modify it under
|
||||
* the terms of the GNU General Public License, either version 2
|
||||
* of the License, or any later version.
|
||||
*
|
||||
* For the full copyright and license information, please read the
|
||||
* LICENSE.txt file that was distributed with this source code.
|
||||
*
|
||||
* The TYPO3 project - inspiring people to share!
|
||||
*/
|
||||
|
||||
namespace TYPO3\CMS\Core\Resource\OnlineMedia\Service;
|
||||
|
||||
use TYPO3\CMS\Core\Resource\File;
|
||||
use TYPO3\CMS\Core\Resource\OnlineMedia\Helpers\OnlineMediaHelperRegistry;
|
||||
use TYPO3\CMS\Core\Resource\ProcessedFileRepository;
|
||||
|
||||
/**
|
||||
* Service for handling the preview of online media assets
|
||||
*/
|
||||
readonly class PreviewService
|
||||
{
|
||||
public function __construct(
|
||||
protected OnlineMediaHelperRegistry $onlineMediaHelperRegistry,
|
||||
protected ProcessedFileRepository $processedFileRepository
|
||||
) {}
|
||||
|
||||
public function updatePreviewImage(File $file): string
|
||||
{
|
||||
if (!$this->onlineMediaHelperRegistry->hasOnlineMediaHelper($file->getExtension())) {
|
||||
throw new \InvalidArgumentException('No online media helper exists for extension ' . $file->getExtension(), 1695130495);
|
||||
}
|
||||
|
||||
$onlineMediaHelper = $this->onlineMediaHelperRegistry->getOnlineMediaHelper($file);
|
||||
|
||||
// Remove the current preview image to force regeneration on calling getPreviewImage() again
|
||||
if (file_exists($previewImage = $onlineMediaHelper->getPreviewImage($file))) {
|
||||
// Remove preview image and processed files
|
||||
unlink($previewImage);
|
||||
foreach ($this->processedFileRepository->findAllByOriginalFile($file) as $processedFile) {
|
||||
$processedFile->delete();
|
||||
}
|
||||
}
|
||||
|
||||
// Force regeneration of the preview image and return the path
|
||||
return $onlineMediaHelper->getPreviewImage($file);
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user