vendor/pimcore/pimcore/models/Document/Editable/Video.php line 28

Open in your IDE?
  1. <?php
  2. /**
  3.  * Pimcore
  4.  *
  5.  * This source file is available under two different licenses:
  6.  * - GNU General Public License version 3 (GPLv3)
  7.  * - Pimcore Enterprise License (PEL)
  8.  * Full copyright and license information is available in
  9.  * LICENSE.md which is distributed with this source code.
  10.  *
  11.  * @category   Pimcore
  12.  * @package    Document
  13.  *
  14.  * @copyright  Copyright (c) Pimcore GmbH (http://www.pimcore.org)
  15.  * @license    http://www.pimcore.org/license     GPLv3 and PEL
  16.  */
  17. namespace Pimcore\Model\Document\Editable;
  18. use Pimcore\Logger;
  19. use Pimcore\Model;
  20. use Pimcore\Model\Asset;
  21. use Pimcore\Tool;
  22. /**
  23.  * @method \Pimcore\Model\Document\Editable\Dao getDao()
  24.  */
  25. class Video extends Model\Document\Editable
  26. {
  27.     /**
  28.      * contains depending on the type of the video the unique identifier eg. "http://www.youtube.com", "789", ...
  29.      *
  30.      * @var int|string|null
  31.      */
  32.     public $id;
  33.     /**
  34.      * one of asset, youtube, vimeo, dailymotion
  35.      *
  36.      * @var string|null
  37.      */
  38.     public $type 'asset';
  39.     /**
  40.      * asset ID of poster image
  41.      *
  42.      * @var int|null
  43.      */
  44.     public $poster;
  45.     /**
  46.      * @var string
  47.      */
  48.     public $title '';
  49.     /**
  50.      * @var string
  51.      */
  52.     public $description '';
  53.     /**
  54.      * @param string $title
  55.      *
  56.      * @return $this
  57.      */
  58.     public function setTitle($title)
  59.     {
  60.         $this->title $title;
  61.         return $this;
  62.     }
  63.     /**
  64.      * @return string
  65.      */
  66.     public function getTitle()
  67.     {
  68.         if (!$this->title && $this->getVideoAsset()) {
  69.             // default title for microformats
  70.             return $this->getVideoAsset()->getFilename();
  71.         }
  72.         return $this->title;
  73.     }
  74.     /**
  75.      * @param string $description
  76.      *
  77.      * @return $this
  78.      */
  79.     public function setDescription($description)
  80.     {
  81.         $this->description $description;
  82.         return $this;
  83.     }
  84.     /**
  85.      * @return string
  86.      */
  87.     public function getDescription()
  88.     {
  89.         if (!$this->description) {
  90.             // default description for microformats
  91.             return $this->getTitle();
  92.         }
  93.         return $this->description;
  94.     }
  95.     /**
  96.      * @see EditableInterface::getType
  97.      *
  98.      * @return string
  99.      */
  100.     public function getType()
  101.     {
  102.         return 'video';
  103.     }
  104.     /**
  105.      * @see EditableInterface::getData
  106.      *
  107.      * @return mixed
  108.      */
  109.     public function getData()
  110.     {
  111.         $path $this->id;
  112.         if ($this->type == 'asset' && ($video Asset::getById($this->id))) {
  113.             $path $video->getFullPath();
  114.         }
  115.         $poster Asset::getById($this->poster);
  116.         return [
  117.             'id' => $this->id,
  118.             'type' => $this->type,
  119.             'title' => $this->title,
  120.             'description' => $this->description,
  121.             'path' => $path,
  122.             'poster' => $poster $poster->getFullPath() : '',
  123.         ];
  124.     }
  125.     /**
  126.      * @return array
  127.      */
  128.     public function getDataForResource()
  129.     {
  130.         return [
  131.             'id' => $this->id,
  132.             'type' => $this->type,
  133.             'title' => $this->title,
  134.             'description' => $this->description,
  135.             'poster' => $this->poster,
  136.         ];
  137.     }
  138.     /**
  139.      * @see EditableInterface::frontend
  140.      *
  141.      * @return string
  142.      */
  143.     public function frontend()
  144.     {
  145.         $inAdmin false;
  146.         $args func_get_args();
  147.         if (array_key_exists(0$args)) {
  148.             $inAdmin $args[0];
  149.         }
  150.         if (!$this->id || !$this->type) {
  151.             return $this->getEmptyCode();
  152.         } elseif ($this->type == 'asset') {
  153.             return $this->getAssetCode($inAdmin);
  154.         } elseif ($this->type == 'youtube') {
  155.             return $this->getYoutubeCode();
  156.         } elseif ($this->type == 'vimeo') {
  157.             return $this->getVimeoCode();
  158.         } elseif ($this->type == 'dailymotion') {
  159.             return $this->getDailymotionCode();
  160.         } elseif ($this->type == 'url') {
  161.             return $this->getUrlCode();
  162.         }
  163.         return $this->getEmptyCode();
  164.     }
  165.     /**
  166.      * @return array
  167.      */
  168.     public function resolveDependencies()
  169.     {
  170.         $dependencies = [];
  171.         if ($this->type == 'asset') {
  172.             $asset Asset::getById($this->id);
  173.             if ($asset instanceof Asset) {
  174.                 $key 'asset_' $asset->getId();
  175.                 $dependencies[$key] = [
  176.                     'id' => $asset->getId(),
  177.                     'type' => 'asset',
  178.                 ];
  179.             }
  180.         }
  181.         if ($poster Asset::getById($this->poster)) {
  182.             $key 'asset_' $poster->getId();
  183.             $dependencies[$key] = [
  184.                 'id' => $poster->getId(),
  185.                 'type' => 'asset',
  186.             ];
  187.         }
  188.         return $dependencies;
  189.     }
  190.     /**
  191.      * @return bool
  192.      */
  193.     public function checkValidity()
  194.     {
  195.         $sane true;
  196.         if ($this->type == 'asset' && !empty($this->id)) {
  197.             $el Asset::getById($this->id);
  198.             if (!$el instanceof Asset) {
  199.                 $sane false;
  200.                 Logger::notice('Detected insane relation, removing reference to non existent asset with id [' $this->id ']');
  201.                 $this->id null;
  202.                 $this->type null;
  203.             }
  204.         }
  205.         if (!($poster Asset::getById($this->poster))) {
  206.             $sane false;
  207.             Logger::notice('Detected insane relation, removing reference to non existent asset with id [' $this->id ']');
  208.             $this->poster null;
  209.         }
  210.         return $sane;
  211.     }
  212.     /**
  213.      * @see EditableInterface::admin
  214.      *
  215.      * @return string
  216.      */
  217.     public function admin()
  218.     {
  219.         $html parent::admin();
  220.         // get frontendcode for preview
  221.         // put the video code inside the generic code
  222.         $html str_replace('</div>'$this->frontend(true) . '</div>'$html);
  223.         return $html;
  224.     }
  225.     /**
  226.      * @see EditableInterface::setDataFromResource
  227.      *
  228.      * @param mixed $data
  229.      *
  230.      * @return $this
  231.      */
  232.     public function setDataFromResource($data)
  233.     {
  234.         if (!empty($data)) {
  235.             $data = \Pimcore\Tool\Serialize::unserialize($data);
  236.         }
  237.         $this->id $data['id'];
  238.         $this->type $data['type'];
  239.         $this->poster $data['poster'];
  240.         $this->title $data['title'];
  241.         $this->description $data['description'];
  242.         return $this;
  243.     }
  244.     /**
  245.      * @see EditableInterface::setDataFromEditmode
  246.      *
  247.      * @param mixed $data
  248.      *
  249.      * @return $this
  250.      */
  251.     public function setDataFromEditmode($data)
  252.     {
  253.         if ($data['type']) {
  254.             $this->type $data['type'];
  255.         }
  256.         if ($data['title']) {
  257.             $this->title $data['title'];
  258.         }
  259.         if ($data['description']) {
  260.             $this->description $data['description'];
  261.         }
  262.         // this is to be backward compatible to <= v 1.4.7
  263.         if (isset($data['id']) && $data['id']) {
  264.             $data['path'] = $data['id'];
  265.         }
  266.         $video Asset::getByPath($data['path']);
  267.         if ($video instanceof Asset\Video) {
  268.             $this->id $video->getId();
  269.         } else {
  270.             $this->id $data['path'];
  271.         }
  272.         $this->poster null;
  273.         $poster Asset::getByPath($data['poster']);
  274.         if ($poster instanceof Asset\Image) {
  275.             $this->poster $poster->getId();
  276.         }
  277.         return $this;
  278.     }
  279.     /**
  280.      * @return string
  281.      */
  282.     public function getWidth()
  283.     {
  284.         return $this->getConfig()['width'] ?? '100%';
  285.     }
  286.     /**
  287.      * @return int
  288.      */
  289.     public function getHeight()
  290.     {
  291.         return $this->getConfig()['height'] ?? 300;
  292.     }
  293.     /**
  294.      * @param bool $inAdmin
  295.      *
  296.      * @return string
  297.      */
  298.     public function getAssetCode($inAdmin false)
  299.     {
  300.         $asset Asset::getById($this->id);
  301.         $config $this->getConfig();
  302.         $thumbnailConfig $config['thumbnail'] ?? null;
  303.         // compatibility mode when FFMPEG is not present or no thumbnail config is given
  304.         if (!\Pimcore\Video::isAvailable() || !$thumbnailConfig) {
  305.             if ($asset instanceof Asset && preg_match("/\.(f4v|flv|mp4)/"$asset->getFullPath())) {
  306.                 $image $this->getPosterThumbnailImage($asset);
  307.                 return $this->getHtml5Code(['mp4' => (string) $asset], $image);
  308.             }
  309.             return $this->getErrorCode('Asset is not a video, or missing thumbnail configuration');
  310.         }
  311.         if ($asset instanceof Asset\Video && $thumbnailConfig) {
  312.             $thumbnail $asset->getThumbnail($thumbnailConfig);
  313.             if ($thumbnail) {
  314.                 $image $this->getPosterThumbnailImage($asset);
  315.                 if ($inAdmin && isset($config['editmodeImagePreview']) && $config['editmodeImagePreview']) {
  316.                     $code '<div id="pimcore_video_' $this->getName() . '" class="pimcore_tag_video pimcore_editable_video '.$config['class'].'">';
  317.                     $code .= '<img width="' $this->getWidth() . '" src="' $image '" />';
  318.                     $code .= '</div>';
  319.                     return $code;
  320.                 }
  321.                 if ($thumbnail['status'] === 'finished') {
  322.                     return $this->getHtml5Code($thumbnail['formats'], $image);
  323.                 }
  324.                 if ($thumbnail['status'] === 'inprogress') {
  325.                     // disable the output-cache if enabled
  326.                     $cacheService = \Pimcore::getContainer()->get('pimcore.event_listener.frontend.full_page_cache');
  327.                     $cacheService->disable('Video rendering in progress');
  328.                     return $this->getProgressCode($image);
  329.                 }
  330.                 return $this->getErrorCode('The video conversion failed, please see the log files in /var/logs for more details.');
  331.             }
  332.             return $this->getErrorCode("The given thumbnail doesn't exist: '" $thumbnailConfig "'");
  333.         }
  334.         return $this->getEmptyCode();
  335.     }
  336.     /**
  337.      * @param Asset\Video $asset
  338.      *
  339.      * @return Asset\Image\Thumbnail|null
  340.      */
  341.     private function getPosterThumbnailImage(Asset\Video $asset)
  342.     {
  343.         $config $this->getConfig();
  344.         if (!array_key_exists('imagethumbnail'$config) || empty($config['imagethumbnail'])) {
  345.             $thumbnailConfig $asset->getThumbnailConfig($config['thumbnail'] ?? null);
  346.             if ($thumbnailConfig instanceof Asset\Video\Thumbnail\Config) {
  347.                 // try to get the dimensions out ouf the video thumbnail
  348.                 $imageThumbnailConf $thumbnailConfig->getEstimatedDimensions();
  349.                 $imageThumbnailConf['format'] = 'JPEG';
  350.             }
  351.         } else {
  352.             $imageThumbnailConf $config['imagethumbnail'];
  353.         }
  354.         if (empty($imageThumbnailConf)) {
  355.             $imageThumbnailConf['width'] = 800;
  356.             $imageThumbnailConf['format'] = 'JPEG';
  357.         }
  358.         $image null;
  359.         if ($this->poster && ($poster Asset\Image::getById($this->poster))) {
  360.             $image $poster->getThumbnail($imageThumbnailConf);
  361.         } else {
  362.             if ($asset->getCustomSetting('image_thumbnail_asset')
  363.                 && ($customPreviewAsset Asset\Image::getById($asset->getCustomSetting('image_thumbnail_asset')))) {
  364.                 $image $customPreviewAsset->getThumbnail($imageThumbnailConf);
  365.             } else {
  366.                 $image $asset->getImageThumbnail($imageThumbnailConf);
  367.             }
  368.         }
  369.         return $image;
  370.     }
  371.     /**
  372.      * @return string
  373.      */
  374.     public function getUrlCode()
  375.     {
  376.         return $this->getHtml5Code(['mp4' => (string) $this->id]);
  377.     }
  378.     /**
  379.      * @param string $message
  380.      *
  381.      * @return string
  382.      */
  383.     public function getErrorCode($message '')
  384.     {
  385.         $width $this->getWidth();
  386.         if (strpos($this->getWidth(), '%') === false) {
  387.             $width = ((int)$this->getWidth() - 1) . 'px';
  388.         }
  389.         // only display error message in debug mode
  390.         if (!\Pimcore::inDebugMode()) {
  391.             $message '';
  392.         }
  393.         $code '
  394.         <div id="pimcore_video_' $this->getName() . '" class="pimcore_tag_video pimcore_editable_video">
  395.             <div class="pimcore_tag_video_error pimcore_editable_video_error" style="text-align:center; width: ' $width '; height: ' . ($this->getHeight() - 1) . 'px; border:1px solid #000; background: url(/bundles/pimcoreadmin/img/filetype-not-supported.svg) no-repeat center center #fff;">
  396.                 ' $message '
  397.             </div>
  398.         </div>';
  399.         return $code;
  400.     }
  401.     /**
  402.      * @return mixed|string
  403.      */
  404.     private function parseYoutubeId()
  405.     {
  406.         $youtubeId '';
  407.         if ($this->type == 'youtube') {
  408.             if ($youtubeId $this->id) {
  409.                 if (strpos($youtubeId'//') !== false) {
  410.                     $parts parse_url($this->id);
  411.                     parse_str($parts['query'], $vars);
  412.                     if ($vars['v']) {
  413.                         $youtubeId $vars['v'];
  414.                     }
  415.                     //get youtube id if form urls like  http://www.youtube.com/embed/youtubeId
  416.                     if (strpos($this->id'embed') !== false) {
  417.                         $explodedPath explode('/'$parts['path']);
  418.                         $youtubeId $explodedPath[array_search('embed'$explodedPath) + 1];
  419.                     }
  420.                     if ($parts['host'] == 'youtu.be') {
  421.                         $youtubeId trim($parts['path'], ' /');
  422.                     }
  423.                 }
  424.             }
  425.         }
  426.         return $youtubeId;
  427.     }
  428.     /**
  429.      * @return string
  430.      */
  431.     public function getYoutubeUrlEmbedded()
  432.     {
  433.         if ($this->type == 'youtube') {
  434.             if ($youtubeId $this->parseYoutubeId()) {
  435.                 if (strpos($youtubeId'PL') === 0) {
  436.                     $youtubeId .= sprintf('videoseries?list=%s'$youtubeId);
  437.                 }
  438.                 return 'https://www.youtube-nocookie.com/embed/'.$youtubeId;
  439.             }
  440.         }
  441.         return '';
  442.     }
  443.     /**
  444.      * @return string
  445.      */
  446.     public function getYoutubeCode()
  447.     {
  448.         if (!$this->id) {
  449.             return $this->getEmptyCode();
  450.         }
  451.         $config $this->getConfig();
  452.         $code '';
  453.         $youtubeId $this->parseYoutubeId();
  454.         if (!$youtubeId) {
  455.             return $this->getEmptyCode();
  456.         }
  457.         $width '100%';
  458.         if (array_key_exists('width'$config)) {
  459.             $width $config['width'];
  460.         }
  461.         $height '300';
  462.         if (array_key_exists('height'$config)) {
  463.             $height $config['height'];
  464.         }
  465.         $wmode '?wmode=transparent';
  466.         $seriesPrefix '';
  467.         if (strpos($youtubeId'PL') === 0) {
  468.             $wmode '';
  469.             $seriesPrefix 'videoseries?list=';
  470.         }
  471.         $valid_youtube_prams = [ 'autohide',
  472.             'autoplay',
  473.             'cc_load_policy',
  474.             'color',
  475.             'controls',
  476.             'disablekb',
  477.             'enablejsapi',
  478.             'end',
  479.             'fs',
  480.             'playsinline',
  481.             'hl',
  482.             'iv_load_policy',
  483.             'list',
  484.             'listType',
  485.             'loop',
  486.             'modestbranding',
  487.             'mute',
  488.             'origin',
  489.             'playerapiid',
  490.             'playlist',
  491.             'rel',
  492.             'showinfo',
  493.             'start',
  494.             'theme',
  495.             ];
  496.         $additional_params '';
  497.         $clipConfig = [];
  498.         if (isset($config['config']['clip']) && is_array($config['config']['clip'])) {
  499.             $clipConfig $config['config']['clip'];
  500.         }
  501.         // this is to be backward compatible to <= v 1.4.7
  502.         $configurations $clipConfig;
  503.         if (array_key_exists('youtube'$config) && is_array($config['youtube'])) {
  504.             $configurations array_merge($clipConfig$config['youtube']);
  505.         }
  506.         if (!empty($configurations)) {
  507.             foreach ($configurations as $key => $value) {
  508.                 if (in_array($key$valid_youtube_prams)) {
  509.                     if (is_bool($value)) {
  510.                         if ($value) {
  511.                             $additional_params .= '&'.$key.'=1';
  512.                         } else {
  513.                             $additional_params .= '&'.$key.'=0';
  514.                         }
  515.                     } else {
  516.                         $additional_params .= '&'.$key.'='.$value;
  517.                     }
  518.                 }
  519.             }
  520.         }
  521.         $code .= '<div id="pimcore_video_' $this->getName() . '" class="pimcore_tag_video pimcore_editable_video '.$config['class'].'">
  522.             <iframe width="' $width '" height="' $height '" src="https://www.youtube-nocookie.com/embed/' $seriesPrefix $youtubeId $wmode $additional_params .'" frameborder="0" webkitAllowFullScreen mozallowfullscreen allowFullScreen></iframe>
  523.         </div>';
  524.         return $code;
  525.     }
  526.     /**
  527.      * @return string
  528.      */
  529.     public function getVimeoCode()
  530.     {
  531.         if (!$this->id) {
  532.             return $this->getEmptyCode();
  533.         }
  534.         $config $this->getConfig();
  535.         $code '';
  536.         $uid 'video_' uniqid();
  537.         // get vimeo id
  538.         if (preg_match("@vimeo.*/([\d]+)@i"$this->id$matches)) {
  539.             $vimeoId intval($matches[1]);
  540.         } else {
  541.             // for object-videos
  542.             $vimeoId $this->id;
  543.         }
  544.         if (ctype_digit($vimeoId)) {
  545.             $width '100%';
  546.             if (array_key_exists('width'$config)) {
  547.                 $width $config['width'];
  548.             }
  549.             $height '300';
  550.             if (array_key_exists('height'$config)) {
  551.                 $height $config['height'];
  552.             }
  553.             $valid_vimeo_prams = [
  554.                 'autoplay',
  555.                 'background',
  556.                 'loop',
  557.                 'muted',
  558.                 ];
  559.             $additional_params '';
  560.             $clipConfig = [];
  561.             if (is_array($config['config']['clip'])) {
  562.                 $clipConfig $config['config']['clip'];
  563.             }
  564.             // this is to be backward compatible to <= v 1.4.7
  565.             $configurations $clipConfig;
  566.             if (is_array($config['vimeo'])) {
  567.                 $configurations array_merge($clipConfig$config['vimeo']);
  568.             }
  569.             if (!empty($configurations)) {
  570.                 foreach ($configurations as $key => $value) {
  571.                     if (in_array($key$valid_vimeo_prams)) {
  572.                         if (is_bool($value)) {
  573.                             if ($value) {
  574.                                 $additional_params .= '&'.$key.'=1';
  575.                             } else {
  576.                                 $additional_params .= '&'.$key.'=0';
  577.                             }
  578.                         } else {
  579.                             $additional_params .= '&'.$key.'='.$value;
  580.                         }
  581.                     }
  582.                 }
  583.             }
  584.             $code .= '<div id="pimcore_video_' $this->getName() . '" class="pimcore_tag_video pimcore_editable_video '.$config['class'].'">
  585.                 <iframe src="https://player.vimeo.com/video/' $vimeoId '?dnt=1&title=0&amp;byline=0&amp;portrait=0'$additional_params .'" width="' $width '" height="' $height '" frameborder="0" webkitAllowFullScreen mozallowfullscreen allowFullScreen></iframe>
  586.             </div>';
  587.             return $code;
  588.         }
  589.         // default => return the empty code
  590.         return $this->getEmptyCode();
  591.     }
  592.     /**
  593.      * @return string
  594.      */
  595.     public function getDailymotionCode()
  596.     {
  597.         if (!$this->id) {
  598.             return $this->getEmptyCode();
  599.         }
  600.         $config $this->getConfig();
  601.         $code '';
  602.         $uid 'video_' uniqid();
  603.         // get dailymotion id
  604.         if (preg_match('@dailymotion.*/video/([^_]+)@i'$this->id$matches)) {
  605.             $dailymotionId $matches[1];
  606.         } else {
  607.             // for object-videos
  608.             $dailymotionId $this->id;
  609.         }
  610.         if ($dailymotionId) {
  611.             $width $config['width'] ?? '100%';
  612.             $height $config['height'] ?? '300';
  613.             $valid_dailymotion_prams = [
  614.                 'autoplay',
  615.                 'loop',
  616.                 'mute', ];
  617.             $additional_params '';
  618.             $clipConfig is_array($config['config']['clip']) ? $config['config']['clip'] : [];
  619.             // this is to be backward compatible to <= v 1.4.7
  620.             $configurations $clipConfig;
  621.             if (is_array($config['dailymotion'])) {
  622.                 $configurations array_merge($clipConfig$config['dailymotion']);
  623.             }
  624.             if (!empty($configurations)) {
  625.                 foreach ($configurations as $key => $value) {
  626.                     if (in_array($key$valid_dailymotion_prams)) {
  627.                         if (is_bool($value)) {
  628.                             if ($value) {
  629.                                 $additional_params .= '&'.$key.'=1';
  630.                             } else {
  631.                                 $additional_params .= '&'.$key.'=0';
  632.                             }
  633.                         } else {
  634.                             $additional_params .= '&'.$key.'='.$value;
  635.                         }
  636.                     }
  637.                 }
  638.             }
  639.             $code .= '<div id="pimcore_video_' $this->getName() . '" class="pimcore_tag_video pimcore_editable_video '.$config['class'].'">
  640.                 <iframe src="https://www.dailymotion.com/embed/video/' $dailymotionId '?' $additional_params .'" width="' $width '" height="' $height '" frameborder="0" webkitAllowFullScreen mozallowfullscreen allowFullScreen></iframe>
  641.             </div>';
  642.             return $code;
  643.         }
  644.         // default => return the empty code
  645.         return $this->getEmptyCode();
  646.     }
  647.     /**
  648.      * @param array $urls
  649.      * @param string|null $thumbnail
  650.      *
  651.      * @return string
  652.      */
  653.     public function getHtml5Code($urls = [], $thumbnail null)
  654.     {
  655.         $code '';
  656.         $video $this->getVideoAsset();
  657.         if ($video) {
  658.             $duration ceil($video->getDuration());
  659.             $durationParts = ['PT'];
  660.             // hours
  661.             if ($duration 3600 >= 1) {
  662.                 $hours floor($duration 3600);
  663.                 $durationParts[] = $hours 'H';
  664.                 $duration $duration $hours 3600;
  665.             }
  666.             // minutes
  667.             if ($duration 60 >= 1) {
  668.                 $minutes floor($duration 60);
  669.                 $durationParts[] = $minutes 'M';
  670.                 $duration $duration $minutes 60;
  671.             }
  672.             $durationParts[] = $duration 'S';
  673.             $durationString implode(''$durationParts);
  674.             $code .= '<div id="pimcore_video_' $this->getName() . '" class="pimcore_tag_video pimcore_editable_video">' "\n";
  675.             $uploadDate = new \DateTime();
  676.             $uploadDate->setTimestamp($video->getCreationDate());
  677.             $jsonLd = [
  678.                 '@context' => 'http://schema.org',
  679.                 '@type' => 'VideoObject',
  680.                 'name' => $this->getTitle(),
  681.                 'description' => $this->getDescription(),
  682.                 'uploadDate' => $uploadDate->format(\DateTime::ISO8601),
  683.                 'duration' => $durationString,
  684.                 //'contentUrl' => Tool::getHostUrl() . $urls['mp4'],
  685.                 //"embedUrl" => "http://www.example.com/videoplayer.swf?video=123",
  686.                 //"interactionCount" => "1234",
  687.             ];
  688.             if (!$thumbnail) {
  689.                 $thumbnail $video->getImageThumbnail([]);
  690.             }
  691.             $jsonLd['contentUrl'] = $urls['mp4'];
  692.             if (!preg_match('@https?://@'$urls['mp4'])) {
  693.                 $jsonLd['contentUrl'] = Tool::getHostUrl() . $urls['mp4'];
  694.             }
  695.             $jsonLd['thumbnailUrl'] = (string)$thumbnail;
  696.             if (!preg_match('@https?://@', (string)$thumbnail)) {
  697.                 $jsonLd['thumbnailUrl'] = Tool::getHostUrl() . $thumbnail;
  698.             }
  699.             $code .= "\n\n<script type=\"application/ld+json\">\n" json_encode($jsonLd) . "\n</script>\n\n";
  700.             // default attributes
  701.             $attributesString '';
  702.             $attributes = [
  703.                 'width' => $this->getWidth(),
  704.                 'height' => $this->getHeight(),
  705.                 'poster' => $thumbnail,
  706.                 'controls' => 'controls',
  707.                 'class' => 'pimcore_video',
  708.             ];
  709.             $config $this->getConfig();
  710.             if (array_key_exists('attributes'$config)) {
  711.                 $attributes array_merge($attributes$config['attributes']);
  712.             }
  713.             if (isset($config['removeAttributes']) && is_array($config['removeAttributes'])) {
  714.                 foreach ($config['removeAttributes'] as $attribute) {
  715.                     unset($attributes[$attribute]);
  716.                 }
  717.             }
  718.             // do not allow an empty controls editable
  719.             if (isset($attributes['controls']) && !$attributes['controls']) {
  720.                 unset($attributes['controls']);
  721.             }
  722.             foreach ($attributes as $key => $value) {
  723.                 $attributesString .= ' ' $key;
  724.                 if (!empty($value)) {
  725.                     $quoteChar '"';
  726.                     if (strpos($value'"')) {
  727.                         $quoteChar "'";
  728.                     }
  729.                     $attributesString .= '=' $quoteChar $value $quoteChar;
  730.                 }
  731.             }
  732.             $code .= '<video' $attributesString '>' "\n";
  733.             foreach ($urls as $type => $url) {
  734.                 $code .= '<source type="video/' $type '" src="' $url '" />' "\n";
  735.             }
  736.             $code .= '</video>' "\n";
  737.             $code .= '</div>' "\n";
  738.         }
  739.         return $code;
  740.     }
  741.     /**
  742.      * @param string|null $thumbnail
  743.      *
  744.      * @return string
  745.      */
  746.     public function getProgressCode($thumbnail null)
  747.     {
  748.         $uid 'video_' uniqid();
  749.         $code '
  750.         <div id="pimcore_video_' $this->getName() . '" class="pimcore_tag_video pimcore_editable_video">
  751.             <style type="text/css">
  752.                 #' $uid ' .pimcore_tag_video_progress_status {
  753.                     box-sizing:content-box;
  754.                     background:#fff url(/bundles/pimcoreadmin/img/video-loading.gif) center center no-repeat;
  755.                     width:66px;
  756.                     height:66px;
  757.                     padding:20px;
  758.                     border:1px solid #555;
  759.                     box-shadow: 2px 2px 5px #333;
  760.                     border-radius:20px;
  761.                     margin: 0 20px 0 20px;
  762.                     top: calc(50% - 66px);
  763.                     left: calc(50% - 66px);
  764.                     position:absolute;
  765.                     opacity: 0.8;
  766.                 }
  767.             </style>
  768.             <div class="pimcore_tag_video_progress pimcore_editable_video_progress" id="' $uid '">
  769.                 <img src="' $thumbnail '" style="width: ' $this->getWidth() . 'px; height: ' $this->getHeight() . 'px;">
  770.                 <div class="pimcore_tag_video_progress_status pimcore_editable_video_progress_status"></div>
  771.             </div>
  772.         </div>';
  773.         return $code;
  774.     }
  775.     /**
  776.      * @return string
  777.      */
  778.     public function getEmptyCode()
  779.     {
  780.         $uid 'video_' uniqid();
  781.         return '<div id="pimcore_video_' $this->getName() . '" class="pimcore_tag_video pimcore_editable_video"><div class="pimcore_tag_video_empty" id="' $uid '" style="width: ' $this->getWidth() . 'px; height: ' $this->getHeight() . 'px;"></div></div>';
  782.     }
  783.     /**
  784.      * @return bool
  785.      */
  786.     public function isEmpty()
  787.     {
  788.         if ($this->id) {
  789.             return false;
  790.         }
  791.         return true;
  792.     }
  793.     /**
  794.      * @deprecated
  795.      *
  796.      * @param Model\Webservice\Data\Document\Element $wsElement
  797.      * @param Model\Document\PageSnippet $document
  798.      * @param array $params
  799.      * @param Model\Webservice\IdMapperInterface|null $idMapper
  800.      *
  801.      * @throws \Exception
  802.      */
  803.     public function getFromWebserviceImport($wsElement$document null$params = [], $idMapper null)
  804.     {
  805.         $data $this->sanitizeWebserviceData($wsElement->value);
  806.         if ($data->id) {
  807.             if ($data->type == 'asset') {
  808.                 $this->id $data->id;
  809.                 $asset Asset::getById($data->id);
  810.                 if (!$asset) {
  811.                     throw new \Exception('Referencing unknown asset with id [ '.$data->id.' ] in webservice import field [ '.$data->name.' ]');
  812.                 }
  813.                 $this->type $data->type;
  814.             } elseif (in_array($data->type, ['dailymotion''vimeo''youtube''url'])) {
  815.                 $this->id $data->id;
  816.                 $this->type $data->type;
  817.             } else {
  818.                 throw new \Exception('cannot get values from web service import - type must be asset,youtube,url, vimeo or dailymotion');
  819.             }
  820.         }
  821.     }
  822.     /**
  823.      * @return string
  824.      */
  825.     public function getVideoType()
  826.     {
  827.         return $this->type;
  828.     }
  829.     /**
  830.      * @return Asset\Video|null
  831.      */
  832.     public function getVideoAsset()
  833.     {
  834.         if ($this->getVideoType() == 'asset') {
  835.             return Asset\Video::getById($this->id);
  836.         }
  837.         return null;
  838.     }
  839.     /**
  840.      * @return Asset\Image
  841.      */
  842.     public function getPosterAsset()
  843.     {
  844.         return Asset\Image::getById($this->poster);
  845.     }
  846.     /**
  847.      * @param string|Asset\Video\Thumbnail\Config $config
  848.      *
  849.      * @return string
  850.      */
  851.     public function getImageThumbnail($config)
  852.     {
  853.         if ($this->poster && ($poster Asset\Image::getById($this->poster))) {
  854.             return $poster->getThumbnail($config);
  855.         }
  856.         if ($this->getVideoAsset()) {
  857.             return $this->getVideoAsset()->getImageThumbnail($config);
  858.         }
  859.         return '';
  860.     }
  861.     /**
  862.      * @param string|Asset\Video\Thumbnail\Config $config
  863.      *
  864.      * @return array
  865.      */
  866.     public function getThumbnail($config)
  867.     {
  868.         if ($this->getVideoAsset()) {
  869.             return $this->getVideoAsset()->getThumbnail($config);
  870.         }
  871.         return [];
  872.     }
  873.     /**
  874.      * @param int|string $id
  875.      *
  876.      * @return Video
  877.      */
  878.     public function setId($id)
  879.     {
  880.         $this->id $id;
  881.         return $this;
  882.     }
  883.     /**
  884.      * @return int|string
  885.      */
  886.     public function getId()
  887.     {
  888.         return $this->id;
  889.     }
  890.     /**
  891.      * Rewrites id from source to target, $idMapping contains
  892.      * array(
  893.      *  "document" => array(
  894.      *      SOURCE_ID => TARGET_ID,
  895.      *      SOURCE_ID => TARGET_ID
  896.      *  ),
  897.      *  "object" => array(...),
  898.      *  "asset" => array(...)
  899.      * )
  900.      *
  901.      * @param array $idMapping
  902.      */
  903.     public function rewriteIds($idMapping)
  904.     {
  905.         if ($this->type == 'asset' && array_key_exists('asset'$idMapping) and array_key_exists($this->getId(), $idMapping['asset'])) {
  906.             $this->setId($idMapping['asset'][$this->getId()]);
  907.         }
  908.     }
  909. }
  910. class_alias(Video::class, 'Pimcore\Model\Document\Tag\Video');