Initial code from customer project

This commit is contained in:
Daniel Siepmann 2022-12-07 08:39:11 +01:00
parent 835980d99c
commit d61cdfe12f
Signed by: Daniel Siepmann
GPG key ID: 33D6629915560EF4
18 changed files with 1341 additions and 0 deletions

View file

@ -0,0 +1,34 @@
<?php
namespace Codappix\ExternalTypo3Multimedia;
/*
* Copyright (C) 2022 Daniel Siepmann <coding@daniel-siepmann.de>
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
* 02110-1301, USA.
*/
use TYPO3\CMS\Core\Http\RequestFactory;
use TYPO3\CMS\Core\Resource\OnlineMedia\Helpers\AbstractOnlineMediaHelper as Typo3AbstractOnlineMediaHelper;
use TYPO3\CMS\Core\Utility\GeneralUtility;
abstract class AbstractOnlineMediaHelper extends Typo3AbstractOnlineMediaHelper
{
protected function getRequestFactory(): RequestFactory
{
return GeneralUtility::makeInstance(RequestFactory::class);
}
}

View file

@ -0,0 +1,137 @@
<?php
namespace Codappix\ExternalTypo3Multimedia\Anchor;
/*
* Copyright (C) 2021 Daniel Siepmann <coding@daniel-siepmann.de>
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
* 02110-1301, USA.
*/
use Codappix\ExternalTypo3Multimedia\AbstractOnlineMediaHelper;
use Symfony\Component\DomCrawler\Crawler;
use TYPO3\CMS\Core\Http\Uri;
use TYPO3\CMS\Core\Resource\File;
use TYPO3\CMS\Core\Resource\Folder;
use TYPO3\CMS\Core\Utility\GeneralUtility;
class OnlineMediaHelper extends AbstractOnlineMediaHelper
{
public function transformUrlToFile($url, Folder $targetFolder)
{
$mediaId = null;
$uri = new Uri($url);
if ($uri->getHost() === Registration::DOMAIN) {
$mediaId = trim($uri->getPath(), '/');
}
if ($mediaId === null) {
return null;
}
$file = $this->findExistingFileByOnlineMediaId($mediaId, $targetFolder, $this->extension);
if ($file !== null) {
return $file;
}
$fileName = $mediaId . '.' . $this->extension;
$remoteData = $this->getRemoteData($mediaId);
if (!empty($remoteData['title'])) {
$fileName = $remoteData['title'] . '.' . $this->extension;
}
return $this->createNewFile($targetFolder, $fileName, $mediaId);
}
public function getPublicUrl(File $file, $relativeToCurrentScript = false)
{
return sprintf(
'https://' . Registration::DOMAIN . '/%s',
$this->getOnlineMediaId($file)
);
}
public function getPreviewImage(File $file)
{
$data = $this->getRemoteData($this->getOnlineMediaId($file));
if (isset($data['thumbnail_url']) === false) {
return '';
}
$imageContent = GeneralUtility::getUrl($data['thumbnail_url']);
if ($imageContent === false) {
return '';
}
$tempName = GeneralUtility::tempnam($file->getNameWithoutExtension(), $file->getExtension());
GeneralUtility::writeFile($tempName, $imageContent);
return $tempName;
}
public function getMetaData(File $file)
{
$remoteData = $this->getRemoteData($this->getOnlineMediaId($file));
if ($remoteData === []) {
return [];
}
$metadata = [
'width' => (int)$remoteData['width'],
'height' => (int)$remoteData['height'],
];
if (empty($file->getProperty('title'))) {
$metadata['title'] = strip_tags($remoteData['title']);
}
if (empty($file->getProperty('description'))) {
$metadata['description'] = strip_tags($remoteData['description']);
}
return $metadata;
}
private function getRemoteData(string $mediaId): array
{
static $data = [];
if (isset($data[$mediaId]) !== false) {
return $data[$mediaId];
}
$videoWebsite = $this->getRequestFactory()->request(
'https://' . Registration::DOMAIN . '/' . $mediaId
)->getBody()->getContents();
if ($videoWebsite === '') {
return [];
}
$domCrawler = new Crawler($videoWebsite);
$remoteData = [
'title' => $domCrawler->filter('meta[property="og:title"]')->first()->attr('content'),
'description' => $domCrawler->filter('meta[name="description"]')->first()->attr('content'),
'width' => (int) $domCrawler->filter('meta[property="og:image:width"]')->first()->attr('content'),
'height' => (int) $domCrawler->filter('meta[property="og:image:height"]')->first()->attr('content'),
'thumbnail_url' => $domCrawler->filter('meta[property="og:image"]')->first()->attr('content'),
];
$remoteData['title'] = str_replace(' • A podcast on Anchor', '', $remoteData['title']);
$data[$mediaId] = $remoteData;
return $remoteData;
}
}

View file

@ -0,0 +1,55 @@
<?php
namespace Codappix\ExternalTypo3Multimedia\Anchor;
/*
* Copyright (C) 2021 Daniel Siepmann <coding@daniel-siepmann.de>
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
* 02110-1301, USA.
*/
use TYPO3\CMS\Core\Resource\Rendering\RendererRegistry;
use TYPO3\CMS\Core\Utility\ArrayUtility;
class Registration
{
public const FILE_EXTENSION = 'anchor';
public const FILE_MIME_TYPE = 'audio/anchor';
public const DOMAIN = 'anchor.fm';
public static function everything()
{
RendererRegistry::getInstance()->registerRendererClass(Renderer::class);
$GLOBALS['TYPO3_CONF_VARS']['SYS']['mediafile_ext'] .= ',' . self::FILE_EXTENSION;
ArrayUtility::mergeRecursiveWithOverrule($GLOBALS['TYPO3_CONF_VARS'], [
'SYS' => [
'fal' => [
'onlineMediaHelpers' => [
self::FILE_EXTENSION => OnlineMediaHelper::class,
],
],
'FileInfo' => [
'fileExtensionToMimeType' => [
self::FILE_EXTENSION => self::FILE_MIME_TYPE,
],
],
],
]);
}
}

102
Classes/Anchor/Renderer.php Normal file
View file

@ -0,0 +1,102 @@
<?php
namespace Codappix\ExternalTypo3Multimedia\Anchor;
/*
* Copyright (C) 2021 Daniel Siepmann <coding@daniel-siepmann.de>
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
* 02110-1301, USA.
*/
use Codappix\ExternalTypo3Multimedia\IFrameRenderer;
use TYPO3\CMS\Core\Http\Uri;
use TYPO3\CMS\Core\Resource\FileInterface;
use TYPO3\CMS\Core\Resource\FileReference;
use TYPO3\CMS\Core\Resource\Rendering\FileRendererInterface;
use TYPO3\CMS\Core\Utility\GeneralUtility;
class Renderer implements FileRendererInterface
{
/**
* @var IFrameRenderer
*/
private $iframeRenderer;
public function __construct(
IFrameRenderer $iframeRenderer
) {
$this->iframeRenderer = $iframeRenderer;
}
public function getPriority()
{
return 1;
}
public function canRender(FileInterface $file)
{
return (
$file->getMimeType() === Registration::FILE_MIME_TYPE
|| $file->getExtension() === Registration::FILE_EXTENSION
)
&& $this->iframeRenderer->getOnlineMediaHelper($file) !== false
;
}
public function render(
FileInterface $file,
$width,
$height,
array $options = [],
$usedPathsRelativeToCurrentScript = false
) {
$options = $this->iframeRenderer->collectOptions($options, $file);
$attributes = $this->iframeRenderer->collectAttributes('400px', '102px', $options);
$attributes['frameborder'] = 0;
$attributes['scrolling'] = 'no';
return sprintf(
'<iframe src="%s"%s></iframe>',
htmlspecialchars($this->createUrl($options, $file), ENT_QUOTES | ENT_HTML5),
empty($attributes) ? '' : ' ' . GeneralUtility::implodeAttributes($attributes)
);
}
private function createUrl(array $options, FileInterface $file)
{
if ($file instanceof FileReference) {
$file = $file->getOriginalFile();
}
$url = $this->iframeRenderer->getOnlineMediaHelper($file)->getPublicUrl($file);
$url = $this->addEmbedPathSegment($url);
return $url;
}
private function addEmbedPathSegment(string $url): string
{
$url = new Uri($url);
$pathSegments = GeneralUtility::trimExplode('/', $url->getPath(), true);
$url = $url->withPath(implode('/', array_merge([
$pathSegments[0],
'embed',
], array_slice($pathSegments, 1))));
return (string) $url;
}
}

View file

@ -0,0 +1,139 @@
<?php
namespace Codappix\ExternalTypo3Multimedia\Facebook\Video;
/*
* Copyright (C) 2020 Daniel Siepmann <coding@daniel-siepmann.de>
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
* 02110-1301, USA.
*/
use Codappix\ExternalTypo3Multimedia\AbstractOnlineMediaHelper;
use Symfony\Component\DomCrawler\Crawler;
use TYPO3\CMS\Core\Http\RequestFactory;
use TYPO3\CMS\Core\Http\Uri;
use TYPO3\CMS\Core\Resource\File;
use TYPO3\CMS\Core\Resource\Folder;
use TYPO3\CMS\Core\Utility\GeneralUtility;
class OnlineMediaHelper extends AbstractOnlineMediaHelper
{
public function transformUrlToFile($url, Folder $targetFolder)
{
$mediaId = null;
$uri = new Uri($url);
if (
$uri->getHost() === Registration::DOMAIN
|| $uri->getHost() === 'www.facebook.com'
) {
$mediaId = trim($uri->getPath(), '/');
}
if ($mediaId === null) {
return null;
}
$file = $this->findExistingFileByOnlineMediaId($mediaId, $targetFolder, $this->extension);
if ($file !== null) {
return $file;
}
$fileName = $mediaId . '.' . $this->extension;
$remoteData = $this->getRemoteData($mediaId);
if (!empty($remoteData['title'])) {
$fileName = $remoteData['title'] . '.' . $this->extension;
}
return $this->createNewFile($targetFolder, $fileName, $mediaId);
}
public function getPublicUrl(File $file, $relativeToCurrentScript = false)
{
return sprintf(
'https://' . Registration::DOMAIN . '/%s',
$this->getOnlineMediaId($file)
);
}
public function getPreviewImage(File $file)
{
$data = $this->getRemoteData($this->getOnlineMediaId($file));
if (isset($data['thumbnail_url']) === false) {
return '';
}
$imageContent = GeneralUtility::getUrl($data['thumbnail_url']);
if ($imageContent === false) {
return '';
}
$tempName = GeneralUtility::tempnam($file->getNameWithoutExtension(), $file->getExtension());
GeneralUtility::writeFile($tempName, $imageContent);
return $tempName;
}
public function getMetaData(File $file)
{
$remoteData = $this->getRemoteData($this->getOnlineMediaId($file));
if ($remoteData === []) {
return [];
}
$metadata = [
'width' => (int)$remoteData['width'],
'height' => (int)$remoteData['height'],
];
if (empty($file->getProperty('title'))) {
$metadata['title'] = strip_tags($remoteData['title']);
}
if (empty($file->getProperty('description'))) {
$metadata['description'] = strip_tags($remoteData['description']);
}
return $metadata;
}
private function getRemoteData(string $mediaId): array
{
static $data = [];
if (isset($data[$mediaId]) !== false) {
return $data[$mediaId];
}
$videoWebsite = $this->getRequestFactory()->request(
'https://www.facebook.com/' . $mediaId
)->getBody()->getContents();
if ($videoWebsite === '') {
return [];
}
$domCrawler = new Crawler($videoWebsite);
$remoteData = [
'title' => $domCrawler->filter('meta[property="og:title"]')->first()->attr('content'),
'description' => $domCrawler->filter('meta[name="description"]')->first()->attr('content'),
'width' => (int) $domCrawler->filter('meta[property="og:video:width"]')->first()->attr('content'),
'height' => (int) $domCrawler->filter('meta[property="og:video:height"]')->first()->attr('content'),
'thumbnail_url' => $domCrawler->filter('meta[property="og:image"]')->first()->attr('content'),
];
$data[$mediaId] = $remoteData;
return $remoteData;
}
}

View file

@ -0,0 +1,55 @@
<?php
namespace Codappix\ExternalTypo3Multimedia\Facebook\Video;
/*
* Copyright (C) 2020 Daniel Siepmann <coding@daniel-siepmann.de>
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
* 02110-1301, USA.
*/
use TYPO3\CMS\Core\Resource\Rendering\RendererRegistry;
use TYPO3\CMS\Core\Utility\ArrayUtility;
class Registration
{
public const FILE_EXTENSION = 'facebookvideo';
public const FILE_MIME_TYPE = 'video/facebook';
public const DOMAIN = 'facebook.com';
public static function everything()
{
RendererRegistry::getInstance()->registerRendererClass(Renderer::class);
$GLOBALS['TYPO3_CONF_VARS']['SYS']['mediafile_ext'] .= ',' . self::FILE_EXTENSION;
ArrayUtility::mergeRecursiveWithOverrule($GLOBALS['TYPO3_CONF_VARS'], [
'SYS' => [
'fal' => [
'onlineMediaHelpers' => [
self::FILE_EXTENSION => OnlineMediaHelper::class,
],
],
'FileInfo' => [
'fileExtensionToMimeType' => [
self::FILE_EXTENSION => self::FILE_MIME_TYPE,
],
],
],
]);
}
}

View file

@ -0,0 +1,83 @@
<?php
namespace Codappix\ExternalTypo3Multimedia\Facebook\Video;
/*
* Copyright (C) 2020 Daniel Siepmann <coding@daniel-siepmann.de>
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
* 02110-1301, USA.
*/
use Codappix\ExternalTypo3Multimedia\IFrameRenderer;
use TYPO3\CMS\Core\Resource\FileInterface;
use TYPO3\CMS\Core\Resource\Rendering\FileRendererInterface;
use TYPO3\CMS\Core\Utility\GeneralUtility;
class Renderer implements FileRendererInterface
{
/**
* @var IFrameRenderer
*/
private $iframeRenderer;
public function __construct(
IFrameRenderer $iframeRenderer
) {
$this->iframeRenderer = $iframeRenderer;
}
public function getPriority()
{
return 1;
}
public function canRender(FileInterface $file)
{
return (
$file->getMimeType() === Registration::FILE_MIME_TYPE
|| $file->getExtension() === Registration::FILE_EXTENSION
)
&& $this->iframeRenderer->getOnlineMediaHelper($file) !== false
;
}
public function render(
FileInterface $file,
$width,
$height,
array $options = [],
$usedPathsRelativeToCurrentScript = false
) {
$options = $this->iframeRenderer->collectOptions($options, $file);
$attributes = $this->iframeRenderer->collectAttributes((int) $width, (int) $height, $options);
return sprintf(
'<iframe src="%s"%s></iframe>',
htmlspecialchars($this->createUrl($options, $file), ENT_QUOTES | ENT_HTML5),
empty($attributes) ? '' : ' ' . GeneralUtility::implodeAttributes($attributes)
);
}
private function createUrl(array $options, FileInterface $file)
{
$file = $this->iframeRenderer->getOriginalFile($file);
return sprintf(
'https://' . Registration::DOMAIN . '/plugins/video.php?href=%s',
rawurlencode($this->iframeRenderer->getOnlineMediaHelper($file)->getPublicUrl($file))
);
}
}

134
Classes/IFrameRenderer.php Normal file
View file

@ -0,0 +1,134 @@
<?php
namespace Codappix\ExternalTypo3Multimedia;
/*
* Copyright (C) 2020 Daniel Siepmann <coding@daniel-siepmann.de>
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
* 02110-1301, USA.
*/
use TYPO3\CMS\Core\Resource\File;
use TYPO3\CMS\Core\Resource\FileInterface;
use TYPO3\CMS\Core\Resource\FileReference;
use TYPO3\CMS\Core\Resource\OnlineMedia\Helpers\OnlineMediaHelperInterface;
use TYPO3\CMS\Core\Resource\OnlineMedia\Helpers\OnlineMediaHelperRegistry;
/**
* Provides common API to generate iFrames for external multimedia.
*/
class IFrameRenderer
{
/**
* Generates pairs of key/value; not yet html-escaped
*/
public function collectAttributes(
string $width,
string $height,
array $options
): array {
$attributes = [];
$attributes['allowfullscreen'] = true;
if (isset($options['additionalAttributes']) && is_array($options['additionalAttributes'])) {
$attributes = array_merge($attributes, $options['additionalAttributes']);
}
if (isset($options['data']) && is_array($options['data'])) {
array_walk(
$options['data'],
function (&$value, $key) use (&$attributes) {
$attributes['data-' . $key] = $value;
}
);
}
if ($width !== '' && $width !== 0) {
$attributes['width'] = htmlspecialchars($width);
}
if ($height !== '' && $height !== 0) {
$attributes['height'] = htmlspecialchars($height);
}
if (
isset($GLOBALS['TSFE'])
&& is_object($GLOBALS['TSFE'])
&& (
isset($GLOBALS['TSFE']->config['config']['doctype'])
&& $GLOBALS['TSFE']->config['config']['doctype'] !== 'html5'
)
) {
$attributes['frameborder'] = 0;
}
$allowedAttributes = [
'class',
'dir',
'id',
'lang',
'style',
'title',
'accesskey',
'tabindex',
'onclick',
'allow',
];
foreach ($allowedAttributes as $key) {
if (!empty($options[$key])) {
$attributes[$key] = $options[$key];
}
}
$attributes = array_map('htmlspecialchars', $attributes);
return $attributes;
}
public function collectOptions(
array $options,
FileInterface $file
): array {
// Check for an autoplay option at the file reference itself, if not overridden yet.
if (!isset($options['autoplay']) && $file instanceof FileReference) {
$autoplay = $file->getProperty('autoplay');
if ($autoplay !== null) {
$options['autoplay'] = $autoplay;
}
}
if (!isset($options['allow'])) {
$options['allow'] = 'fullscreen';
if (!empty($options['autoplay'])) {
$options['allow'] = 'autoplay; fullscreen';
}
}
return $options;
}
public function getOriginalFile(FileInterface $file): File
{
$orgFile = $file;
if ($orgFile instanceof FileReference) {
$orgFile = $orgFile->getOriginalFile();
}
return $orgFile;
}
public function getOnlineMediaHelper(FileInterface $file): OnlineMediaHelperInterface
{
return OnlineMediaHelperRegistry::getInstance()
->getOnlineMediaHelper($this->getOriginalFile($file));
}
}

View file

@ -0,0 +1,107 @@
<?php
namespace Codappix\ExternalTypo3Multimedia\Soundcloud;
/*
* Copyright (C) 2020 Daniel Siepmann <coding@daniel-siepmann.de>
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
* 02110-1301, USA.
*/
use TYPO3\CMS\Core\Http\Uri;
use TYPO3\CMS\Core\Resource\File;
use TYPO3\CMS\Core\Resource\Folder;
use TYPO3\CMS\Core\Resource\OnlineMedia\Helpers\AbstractOEmbedHelper;
use TYPO3\CMS\Core\Utility\GeneralUtility;
class OnlineMediaHelper extends AbstractOEmbedHelper
{
public function transformUrlToFile($url, Folder $targetFolder)
{
$id = null;
$uri = new Uri($url);
if ($uri->getHost() === Registration::DOMAIN) {
$id = trim($uri->getPath(), '/');
}
if ($id === null) {
return null;
}
return $this->transformMediaIdToFile($id, $targetFolder, $this->extension);
}
public function getPublicUrl(File $file, $relativeToCurrentScript = false)
{
return sprintf(
'https://' . Registration::DOMAIN . '/%s',
$this->getOnlineMediaId($file)
);
}
public function getPreviewImage(File $file)
{
$data = $this->getOEmbedData($this->getOnlineMediaId($file));
if ($data === false || isset($data['thumbnail_url']) === false) {
return '';
}
$imageContent = GeneralUtility::getUrl($data['thumbnail_url']);
if ($imageContent === false) {
return '';
}
$tempName = GeneralUtility::tempnam($file->getNameWithoutExtension(), $file->getExtension());
GeneralUtility::writeFile($tempName, $imageContent);
return $tempName;
}
// Wrap original to add caching.
// Otherwise foreign API might be called multiple times.
protected function getOEmbedData($mediaId)
{
static $data = [];
if (isset($data[$mediaId]) === false) {
$data[$mediaId] = parent::getOEmbedData($mediaId);
}
return $data[$mediaId];
}
public function getMetaData(File $file)
{
$oEmbed = $this->getOEmbedData($this->getOnlineMediaId($file));
$metadata = parent::getMetaData($file);
if (empty($file->getProperty('description'))) {
$metadata['description'] = strip_tags($oEmbed['description']);
}
return $metadata;
}
protected function getOEmbedUrl($mediaId, $format = 'json')
{
return sprintf(
'https://' . Registration::DOMAIN . '/oembed?format=%s&url=%s',
rawurlencode($format),
sprintf('https://' . Registration::DOMAIN . '/%s', $mediaId)
);
}
}

View file

@ -0,0 +1,57 @@
<?php
namespace Codappix\ExternalTypo3Multimedia\Soundcloud;
/*
* Copyright (C) 2020 Daniel Siepmann <coding@daniel-siepmann.de>
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
* 02110-1301, USA.
*/
use TYPO3\CMS\Core\Resource\Rendering\RendererRegistry;
use TYPO3\CMS\Core\Utility\ArrayUtility;
class Registration
{
public const FILE_EXTENSION = 'soundcloud';
public const FILE_MIME_TYPE = 'audio/soundcloud';
public const DOMAIN = 'soundcloud.com';
public const EMBED_DOMAIN = 'w.soundcloud.com';
public static function everything()
{
RendererRegistry::getInstance()->registerRendererClass(Renderer::class);
$GLOBALS['TYPO3_CONF_VARS']['SYS']['mediafile_ext'] .= ',' . self::FILE_EXTENSION;
ArrayUtility::mergeRecursiveWithOverrule($GLOBALS['TYPO3_CONF_VARS'], [
'SYS' => [
'fal' => [
'onlineMediaHelpers' => [
self::FILE_EXTENSION => OnlineMediaHelper::class,
],
],
'FileInfo' => [
'fileExtensionToMimeType' => [
self::FILE_EXTENSION => self::FILE_MIME_TYPE,
],
],
],
]);
}
}

View file

@ -0,0 +1,89 @@
<?php
namespace Codappix\ExternalTypo3Multimedia\Soundcloud;
/*
* Copyright (C) 2020 Daniel Siepmann <coding@daniel-siepmann.de>
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
* 02110-1301, USA.
*/
use Codappix\ExternalTypo3Multimedia\IFrameRenderer;
use TYPO3\CMS\Core\Resource\FileInterface;
use TYPO3\CMS\Core\Resource\Rendering\FileRendererInterface;
use TYPO3\CMS\Core\Utility\GeneralUtility;
class Renderer implements FileRendererInterface
{
/**
* @var IFrameRenderer
*/
private $iframeRenderer;
public function __construct(
IFrameRenderer $iframeRenderer
) {
$this->iframeRenderer = $iframeRenderer;
}
public function getPriority()
{
return 1;
}
public function canRender(FileInterface $file)
{
return (
$file->getMimeType() === Registration::FILE_MIME_TYPE
|| $file->getExtension() === Registration::FILE_EXTENSION
)
&& $this->iframeRenderer->getOnlineMediaHelper($file) !== false
;
}
public function render(
FileInterface $file,
$width,
$height,
array $options = [],
$usedPathsRelativeToCurrentScript = false
) {
$options = $this->iframeRenderer->collectOptions($options, $file);
$attributes = $this->iframeRenderer->collectAttributes($width . '%', $height, $options);
return sprintf(
'<iframe src="%s"%s></iframe>',
htmlspecialchars($this->createUrl($options, $file), ENT_QUOTES | ENT_HTML5),
empty($attributes) ? '' : ' ' . GeneralUtility::implodeAttributes($attributes)
);
}
private function createUrl(array $options, FileInterface $file)
{
$urlParams = [];
if (!empty($options['autoplay'])) {
$urlParams[] = 'auto_play=1';
}
$file = $this->iframeRenderer->getOriginalFile($file);
return sprintf(
'https://' . Registration::EMBED_DOMAIN . '/player/?url=%s?%s',
rawurlencode($this->iframeRenderer->getOnlineMediaHelper($file)->getPublicUrl($file)),
implode('&', $urlParams)
);
}
}

View file

@ -0,0 +1,133 @@
<?php
namespace Codappix\ExternalTypo3Multimedia\Spotify;
/*
* Copyright (C) 2021 Daniel Siepmann <coding@daniel-siepmann.de>
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
* 02110-1301, USA.
*/
use Codappix\ExternalTypo3Multimedia\AbstractOnlineMediaHelper;
use Symfony\Component\DomCrawler\Crawler;
use TYPO3\CMS\Core\Http\Uri;
use TYPO3\CMS\Core\Resource\File;
use TYPO3\CMS\Core\Resource\Folder;
use TYPO3\CMS\Core\Utility\GeneralUtility;
class OnlineMediaHelper extends AbstractOnlineMediaHelper
{
public function transformUrlToFile($url, Folder $targetFolder)
{
$mediaId = null;
$uri = new Uri($url);
if ($uri->getHost() === Registration::DOMAIN) {
$mediaId = trim($uri->getPath(), '/');
}
if ($mediaId === null) {
return null;
}
$file = $this->findExistingFileByOnlineMediaId($mediaId, $targetFolder, $this->extension);
if ($file !== null) {
return $file;
}
$fileName = $mediaId . '.' . $this->extension;
$remoteData = $this->getRemoteData($mediaId);
if (!empty($remoteData['title'])) {
$fileName = $remoteData['title'] . '.' . $this->extension;
}
return $this->createNewFile($targetFolder, $fileName, $mediaId);
}
public function getPublicUrl(File $file, $relativeToCurrentScript = false)
{
return sprintf(
'https://' . Registration::DOMAIN . '/%s',
$this->getOnlineMediaId($file)
);
}
public function getPreviewImage(File $file)
{
$data = $this->getRemoteData($this->getOnlineMediaId($file));
if (isset($data['thumbnail_url']) === false) {
return '';
}
$imageContent = GeneralUtility::getUrl($data['thumbnail_url']);
if ($imageContent === false) {
return '';
}
$tempName = GeneralUtility::tempnam($file->getNameWithoutExtension(), $file->getExtension());
GeneralUtility::writeFile($tempName, $imageContent);
return $tempName;
}
public function getMetaData(File $file)
{
$remoteData = $this->getRemoteData($this->getOnlineMediaId($file));
if ($remoteData === []) {
return [];
}
$metadata = [
'width' => (int)$remoteData['width'],
'height' => (int)$remoteData['height'],
];
if (empty($file->getProperty('title'))) {
$metadata['title'] = strip_tags($remoteData['title']);
}
if (empty($file->getProperty('description'))) {
$metadata['description'] = strip_tags($remoteData['description']);
}
return $metadata;
}
private function getRemoteData(string $mediaId): array
{
static $data = [];
if (isset($data[$mediaId]) !== false) {
return $data[$mediaId];
}
$videoWebsite = $this->getRequestFactory()->request(
'https://' . Registration::DOMAIN . '/' . $mediaId
)->getBody()->getContents();
if ($videoWebsite === '') {
return [];
}
$domCrawler = new Crawler($videoWebsite);
$remoteData = [
'title' => $domCrawler->filter('meta[property="og:title"]')->first()->attr('content'),
'description' => $domCrawler->filter('meta[name="description"]')->first()->attr('content'),
'thumbnail_url' => $domCrawler->filter('meta[property="og:image"]')->first()->attr('content'),
];
$data[$mediaId] = $remoteData;
return $remoteData;
}
}

View file

@ -0,0 +1,55 @@
<?php
namespace Codappix\ExternalTypo3Multimedia\Spotify;
/*
* Copyright (C) 2021 Daniel Siepmann <coding@daniel-siepmann.de>
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
* 02110-1301, USA.
*/
use TYPO3\CMS\Core\Resource\Rendering\RendererRegistry;
use TYPO3\CMS\Core\Utility\ArrayUtility;
class Registration
{
public const FILE_EXTENSION = 'spotify';
public const FILE_MIME_TYPE = 'audio/spotify';
public const DOMAIN = 'open.spotify.com';
public static function everything()
{
RendererRegistry::getInstance()->registerRendererClass(Renderer::class);
$GLOBALS['TYPO3_CONF_VARS']['SYS']['mediafile_ext'] .= ',' . self::FILE_EXTENSION;
ArrayUtility::mergeRecursiveWithOverrule($GLOBALS['TYPO3_CONF_VARS'], [
'SYS' => [
'fal' => [
'onlineMediaHelpers' => [
self::FILE_EXTENSION => OnlineMediaHelper::class,
],
],
'FileInfo' => [
'fileExtensionToMimeType' => [
self::FILE_EXTENSION => self::FILE_MIME_TYPE,
],
],
],
]);
}
}

View file

@ -0,0 +1,96 @@
<?php
namespace Codappix\ExternalTypo3Multimedia\Spotify;
/*
* Copyright (C) 2021 Daniel Siepmann <coding@daniel-siepmann.de>
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
* 02110-1301, USA.
*/
use Codappix\ExternalTypo3Multimedia\IFrameRenderer;
use TYPO3\CMS\Core\Http\Uri;
use TYPO3\CMS\Core\Resource\FileInterface;
use TYPO3\CMS\Core\Resource\FileReference;
use TYPO3\CMS\Core\Resource\Rendering\FileRendererInterface;
use TYPO3\CMS\Core\Utility\GeneralUtility;
class Renderer implements FileRendererInterface
{
/**
* @var IFrameRenderer
*/
private $iframeRenderer;
public function __construct(
IFrameRenderer $iframeRenderer
) {
$this->iframeRenderer = $iframeRenderer;
}
public function getPriority()
{
return 1;
}
public function canRender(FileInterface $file)
{
return (
$file->getMimeType() === Registration::FILE_MIME_TYPE
|| $file->getExtension() === Registration::FILE_EXTENSION
)
&& $this->iframeRenderer->getOnlineMediaHelper($file) !== false
;
}
public function render(
FileInterface $file,
$width,
$height,
array $options = [],
$usedPathsRelativeToCurrentScript = false
) {
$options = $this->iframeRenderer->collectOptions($options, $file);
$attributes = $this->iframeRenderer->collectAttributes('100%', '235px', $options);
$attributes['allowtransparency'] = 'true';
$attributes['allow'] = 'encrypted-media';
return sprintf(
'<iframe src="%s"%s></iframe>',
htmlspecialchars($this->createUrl($options, $file), ENT_QUOTES | ENT_HTML5),
empty($attributes) ? '' : ' ' . GeneralUtility::implodeAttributes($attributes)
);
}
private function createUrl(array $options, FileInterface $file)
{
if ($file instanceof FileReference) {
$file = $file->getOriginalFile();
}
$url = $this->iframeRenderer->getOnlineMediaHelper($file)->getPublicUrl($file);
$url = $this->addEmbedPathSegment($url);
return $url;
}
private function addEmbedPathSegment(string $url): string
{
$url = new Uri($url);
$url = $url->withPath('embed-podcast/' . ltrim($url->getPath(), '/'));
return (string) $url;
}
}

View file

@ -0,0 +1,8 @@
services:
_defaults:
autowire: true
autoconfigure: true
public: false
Codappix\ExternalTypo3Multimedia\:
resource: '../Classes/*'

28
composer.json Normal file
View file

@ -0,0 +1,28 @@
{
"name": "codappix/external-typo3-multimedia",
"type": "typo3-cms-extension",
"description": "Provide integration of external multimedia like Soundcloud and Facebook videos",
"license": "GPL-2.0-or-later",
"version": "1.0.0",
"authors": [
{
"name": "Daniel Siepmann",
"email": "coding@daniel-siepmann.de",
"role": "Developer"
}
],
"require": {
"typo3/cms-core": "^10.4",
"symfony/dom-crawler": "^5.0"
},
"autoload": {
"psr-4": {
"Codappix\\ExternalTypo3Multimedia\\": "Classes/"
}
},
"extra": {
"typo3/cms": {
"extension-key": "external_multimedia"
}
}
}

21
ext_emconf.php Normal file
View file

@ -0,0 +1,21 @@
<?php
$EM_CONF['external_multimedia'] = [
'title' => 'Support External Multimedia',
'description' => 'Add support for media like Soundcloud or Facebook videos.',
'category' => 'plugin',
'author' => 'Daniel Siepmann',
'author_email' => 'coding@daniel-siepmann.de',
'author_company' => 'Codappix GmbH',
'state' => 'beta',
'version' => '1.0.0',
'constraints' => [
'depends' => [
'typo3' => '*',
],
'conflicts' => [
],
'suggests' => [
],
],
];

8
ext_localconf.php Normal file
View file

@ -0,0 +1,8 @@
<?php
defined('TYPO3_MODE') or die();
\Codappix\ExternalTypo3Multimedia\Anchor\Registration::everything();
\Codappix\ExternalTypo3Multimedia\Soundcloud\Registration::everything();
\Codappix\ExternalTypo3Multimedia\Spotify\Registration::everything();
\Codappix\ExternalTypo3Multimedia\Facebook\Video\Registration::everything();