Einen eigenen TYPO3 MediaRenderer schreiben

Seit Version TYPO3 v7 kann man eigene MediaRenderer registrieren. In dem damaligen Beispiel wurde noch MyVideo als Beispiel genutzt. Na, wer kennt es noch? Für das Tutorial hab ich mir tiktok als Beispiel geschnappt. Die fertige Extension könnt ihr hier finden. Mit dem MediaRenderer hängen wir uns in den Core und sind somit stabil und Updates sind kein Problem.

Bevor wir mit der Programmierung startet, überlegt euch einen Key. Diese wird als Dateiendung genutzt und auch an den entsprechenden Stellen so angezeigt. Beispiel: Videoname.tiktok oder eben video/tiktok.

ext_localconf.php


defined('TYPO3_MODE') || die();

(function ($mediaFileExt) {
    $GLOBALS['TYPO3_CONF_VARS']['SYS']['fal']['onlineMediaHelpers'][$mediaFileExt] = \Ayacoo\Tiktok\Helper\TiktokHelper::class;

    $rendererRegistry = \TYPO3\CMS\Core\Utility\GeneralUtility::makeInstance(\TYPO3\CMS\Core\Resource\Rendering\RendererRegistry::class);
    $rendererRegistry->registerRendererClass(\Ayacoo\Tiktok\Rendering\TiktokRenderer::class);

    $GLOBALS['TYPO3_CONF_VARS']['SYS']['FileInfo']['fileExtensionToMimeType'][$mediaFileExt] = 'video/tiktok';
    $GLOBALS['TYPO3_CONF_VARS']['SYS']['mediafile_ext'] .= ',' . $mediaFileExt;

    $iconRegistry = \TYPO3\CMS\Core\Utility\GeneralUtility::makeInstance(\TYPO3\CMS\Core\Imaging\IconRegistry::class);
    $iconRegistry->registerIcon(
        'mimetypes-media-image-tiktok',
        \TYPO3\CMS\Core\Imaging\IconProvider\SvgIconProvider::class,
        ['source' => 'EXT:tiktok/Resources/Public/Icons/tiktok.svg']
    );
    $iconRegistry->registerFileExtension('tiktok', 'mimetypes-media-image-tiktok');

})('tiktok');

                                                

Was passiert hier? Wir definieren zuerst einen Helper. Diese Klasse wird vom Core aufgerufen um den Dateidownload bzw. die Verarbeitung durchzuführen. Wir holen uns also z.B. aus der oEmbed Schnittstelle alle benötigten Daten.

Der Renderer ist letztlich für das Ausspiele der Daten da. Im Falle von tiktok ist es lediglich das Holen des zwischengespeicherten HTML.

Und zu guter Letzt registrieren wir noch ein Icon für diesen Dateitypen. Hinweis: Ab v11 kann man die Icons übrigens moderner registrieren, siehe TYPO3 Documentation.

MediaHelper

Der MediaHelper erbt vom AbstractOEmbedHelper. Damit einher gehen ein paar notwendige Funktionen. Mit der Funktion transformUrlToFile habt ihr die Möglichkeit das erlaubte URL Format zu steuern. Bei tiktok ist der regex relativ simpel. Komplizierter ist es bei Youtube und Vimeo, weil es mehrere Varianten gibt.

In der Funktion transformMediaIdToFile wird letztlich die Datei in fileadmin oder anderem beliebigen Storage abgespeichert. Hier nutzt man in der Regel den title des Videos aus dem oEmbed Request.

Die Funktion getPublicUrl ist besonders für das Frontend interessant, was in unserem Falle letztlich den Link zur Tiktok Detailseite generiert.

Bei der Funktion getPreviewImage sind wir dafür verantwortlich das Thumbnail zum Video zu holen. Bei tiktok gibt es einen URL Pfad im oEmbed Request, den wir bereits in der Datenbank zwischengespeichert haben. Die Speichermethode selbst kann dann bequem vom Core übernommen werden.

Die Funktion getMetaData bereitet die Daten auf, die dann letztlich in sys_file_metadata landet. So könnt ihr weitere Informationen speichern, die euch die Anbieter mitgeben. Im Falle von Tiktok wird z.B. das komplett HTML mitgeliefert, was wir damit abspeichern. Das würde normalerweise erst im Renderer gebaut werden.


    public function transformUrlToFile($url, Folder $targetFolder)
    {
        $videoId = null;
        // Try to get the Tiktok code from given url.
        // - https://www.tiktok.com/@username/video/code?parameter # Share URL
        if (preg_match('%(?:.*)tiktok\.com\/@(?:[a-z.\-_0-9]*)\/video\/([0-9]*)%i', $url, $match)) {
            $videoId = $match[1];
        }
        if (empty($videoId)) {
            return null;
        }

        return $this->transformMediaIdToFile($videoId, $targetFolder, $this->extension);
    }

    protected function transformMediaIdToFile($mediaId, Folder $targetFolder, $fileExtension)
    {
        $file = $this->findExistingFileByOnlineMediaId($mediaId, $targetFolder, $fileExtension);
        if ($file === null) {
            $fileName = $mediaId . '.' . $fileExtension;

            $oEmbed = $this->getOEmbedData($mediaId);
            if (!empty($oEmbed['title'])) {
                $title = $this->handleTiktokTitle($oEmbed['title']);
                if (!empty($title)) {
                    $fileName = $title . '.' . $fileExtension;
                }
            }
            $file = $this->createNewFile($targetFolder, $fileName, $mediaId);
        }
        return $file;
    }

    public function getPublicUrl(File $file, $relativeToCurrentScript = false)
    {
        // @deprecated $relativeToCurrentScript since v11, will be removed in TYPO3 v12.0
        $videoId = $this->getOnlineMediaId($file);

        $properties = $file->getProperties();
        $username = $properties['tiktok_username'] ?? '';

        return sprintf(self::TIKTOK_URL . '@' . $username . '/video/%s', rawurlencode($videoId));
    }

    public function getPreviewImage(File $file)
    {
        $properties = $file->getProperties();
        $previewImageUrl = $properties['tiktok_thumbnail'] ?? '';

        $videoId = $this->getOnlineMediaId($file);
        $temporaryFileName = $this->getTempFolderPath() . 'tiktok_' . md5($videoId) . '.jpg';

        if (!empty($previewImageUrl)) {
            $previewImage = GeneralUtility::getUrl($previewImageUrl);
            file_put_contents($temporaryFileName, $previewImage);
            GeneralUtility::fixPermissions($temporaryFileName);
            return $temporaryFileName;
        }

        return '';
    }

    public function getMetaData(File $file)
    {
        $metaData = [];

        $oEmbed = $this->getOEmbedData($this->getOnlineMediaId($file));
        if ($oEmbed) {
            $metaData['width'] = (int)$oEmbed['width'];
            $metaData['height'] = (int)$oEmbed['height'];
            if (empty($file->getProperty('title'))) {
                $metaData['title'] = $this->handleTiktokTitle($oEmbed['title']);
            }
            $metaData['author'] = $oEmbed['author_name'];
            $metaData['tiktok_html'] = preg_replace(self::UNICODE_PATTERN, '', $oEmbed['html']);
            $metaData['tiktok_thumbnail'] = $oEmbed['thumbnail_url'];
            $metaData['tiktok_author_url'] = $oEmbed['author_url'];
            $metaData['tiktok_username'] = str_replace(self::TIKTOK_URL . '@', '', $oEmbed['author_url']);
        }

        return $metaData;
    }
                                            

MediaRenderer

Der Renderer ist recht klein gehalten. Neben einer MimeType Prüfung findet hier der Aufbau des HTMLs statt. Beim YoutubeRenderer sieht man ganz gut, was noch alles geht. Neben dem Erzeugen des HTML werden auch alle möglichen Optionen überprüft, die man z.B. via Fluid übermitteln kann. Beispiel: Man möchte autoplay einschalten. Bei tiktok ist das relativ einfach, weil es selbst schon angeboten wird.


    public function render(FileInterface $file, $width, $height, array $options = [], $usedPathsRelativeToCurrentScript = false)
    {
        return $file->getProperty('tiktok_html') ?? '';
    }
                                            

So sieht es im Backend aus






Fazit

Der MediaRenderer ist ein unterschätztes Feature von TYPO3 und sicher auch nicht allen bekannt. Seit Version 7 kann man sich in den TYPO3 Core hängen und stabil weitere Anbieter ergänzen, wie z.B. Tiktok oder Instagram. Und wer selbst das Ganze mal ausprobieren möchte: Die ARD Mediathek bietet in Teilen auch eine Einbettung an.