You are here

BlazyVideoTrait.php in Blazy 8

Same filename and directory in other branches
  1. 8.2 src/Dejavu/BlazyVideoTrait.php

File

src/Dejavu/BlazyVideoTrait.php
View source
<?php

namespace Drupal\blazy\Dejavu;

use Drupal\Core\Url;
use Drupal\file\Entity\File;
use Drupal\blazy\BlazyMedia;

/**
 * A Trait common for optional Media Entity and Video Embed Media integration.
 *
 * The basic idea is to display videos along with images even within core Image,
 * and to re-associate VEF/ME video thumbnails beyond their own entity display.
 * For editors, use Slick Browser, or Blazy Views field.
 * For client-side, Blazy Views field, BlazyFileFormatter, SlickFileFormatter.
 * Why bother? This addresses a mix of images/videos beyond field formatters
 * or when ME and VEM integration is optional.
 *
 * For more robust VEM/ME integration, use Slick Media instead.
 *
 * @see Drupal\blazy\Plugin\views\field\BlazyViewsFieldPluginBase
 * @see Drupal\slick_browser\SlickBrowser::widgetEntityBrowserFileFormAlter()
 * @see Drupal\slick_browser\Plugin\EntityBrowser\FieldWidgetDisplay\...
 */
trait BlazyVideoTrait {

  /**
   * Returns the image factory.
   */
  public function imageFactory() {
    return \Drupal::service('image.factory');
  }

  /**
   * Returns the optional VEF service to avoid dependency for optional plugins.
   */
  public static function videoEmbedMediaManager() {
    if (function_exists('video_embed_field_theme')) {
      return \Drupal::service('video_embed_field.provider_manager');
    }
    return FALSE;
  }

  /**
   * Builds relevant video embed field settings based on the given media url.
   *
   * @param array $settings
   *   An array of settings to be passed into theme_blazy().
   * @param string $external_url
   *   A deprecated video URL for $settings['input_url'].
   */
  public function buildVideo(array &$settings = [], $external_url = '') {
    $settings['input_url'] = empty($settings['input_url']) ? $external_url : $settings['input_url'];

    /** @var \Drupal\video_embed_field\ProviderManagerInterface $video */
    if (!($video = self::videoEmbedMediaManager())) {
      return;
    }
    if (!($provider = $video
      ->loadProviderFromInput($settings['input_url']))) {
      return;
    }

    // Ensures thumbnail is available.
    $provider
      ->downloadThumbnail();

    // @todo extract URL from the SRC of final rendered TWIG instead.
    $render = $provider
      ->renderEmbedCode(640, 360, '0');
    $old_url = isset($render['#attributes']) && isset($render['#attributes']['src']) ? $render['#attributes']['src'] : '';
    $embed_url = isset($render['#url']) ? $render['#url'] : $old_url;
    $query = isset($render['#query']) ? $render['#query'] : [];

    // Prevents complication with multiple videos by now.
    unset($query['autoplay'], $query['auto_play']);
    $settings['video_id'] = $provider::getIdFromInput($settings['input_url']);
    $settings['embed_url'] = Url::fromUri($embed_url, [
      'query' => $query,
    ])
      ->toString();
    $settings['scheme'] = $video
      ->loadDefinitionFromInput($settings['input_url'])['id'];
    $settings['uri'] = $provider
      ->getLocalThumbnailUri();
    $settings['type'] = 'video';

    // Adds autoplay for media URL on lightboxes, saving another click.
    $url = $settings['embed_url'];
    if (strpos($url, 'autoplay') === FALSE || strpos($url, 'autoplay=0') !== FALSE) {
      $settings['autoplay_url'] = strpos($url, '?') === FALSE ? $url . '?autoplay=1' : $url . '&autoplay=1';
    }

    // Only applies when Image style is empty, no file API, no $item,
    // with unmanaged VEF image without image_style.
    // Prevents 404 warning when video thumbnail missing for a reason.
    if (empty($settings['image_style'])) {
      if ($data = @getimagesize($settings['uri'])) {
        list($settings['width'], $settings['height']) = $data;
      }
    }
  }

  /**
   * Gets the faked image item out of file entity, or ER, if applicable.
   *
   * @param object $file
   *   The expected file entity, or ER, to get image item from.
   *
   * @return array
   *   The array of image item and settings if a file image, else empty.
   */
  public function getImageItem($file) {
    $data = [];
    $entity = $file;

    /** @var Drupal\Core\Field\Plugin\Field\FieldType\EntityReferenceItem $file */
    if (isset($file->entity) && !isset($file->alt)) {
      $entity = $file->entity;
    }
    if (!$entity instanceof File) {
      return $data;
    }

    /** @var \Drupal\file\Entity\File $entity */
    list($type, ) = explode('/', $entity
      ->getMimeType(), 2);
    $uri = $entity
      ->getFileUri();
    if ($type == 'image' && ($image = $this
      ->imageFactory()
      ->get($uri)) && $image
      ->isValid()) {
      $item = new \stdClass();
      $item->target_id = $entity
        ->id();
      $item->width = $image
        ->getWidth();
      $item->height = $image
        ->getHeight();
      $item->alt = $entity
        ->getFilename();
      $item->title = $entity
        ->getFilename();
      $item->uri = $uri;
      $settings = (array) $item;
      $item->entity = $entity;
      $settings['type'] = 'image';

      // Build item and settings.
      $data['item'] = $item;
      $data['settings'] = $settings;
      unset($item);
    }
    return $data;
  }

  /**
   * Gets the Media item thumbnail, or re-associate the file entity to ME.
   *
   * @param array $data
   *   An array of data containing settings, and potential video thumbnail item.
   * @param object $entity
   *   The media entity, else file entity to be associated to media, if any.
   */
  public function getMediaItem(array &$data = [], $entity = NULL) {
    $settings = $data['settings'];
    $media = $entity;

    // Core File stores Media thumbnails, re-associate it to Media entity.
    // @todo: If any proper method to get video URL from image URI, or FID.
    if ($entity
      ->getEntityTypeId() == 'file' && !empty($settings['uri']) && strpos($settings['uri'], 'video_thumbnails') !== FALSE) {
      if ($media_id = \Drupal::entityQuery('media')
        ->condition('thumbnail.target_id', $entity
        ->id())
        ->execute()) {
        $media_id = reset($media_id);

        /** @var \Drupal\media_entity\Entity\Media $entity */
        $media = $this
          ->blazyManager()
          ->getEntityTypeManager()
          ->getStorage('media')
          ->load($media_id);
      }
    }

    // Only proceed if we do have ME.
    if ($media
      ->getEntityTypeId() != 'media') {
      return;
    }
    $item = NULL;
    $bundle = $media
      ->bundle();
    $config = method_exists($media, 'getSource') ? $media
      ->getSource()
      ->getConfiguration() : $media
      ->getType()
      ->getConfiguration();
    $source = isset($config['source_url_field']) ? $config['source_url_field'] : '';
    $source_field[$bundle] = isset($config['source_field']) ? $config['source_field'] : $source;
    $settings['bundle'] = $bundle;
    $settings['source_field'] = $source_field[$bundle];
    $settings['media_url'] = $media
      ->toUrl()
      ->toString();
    $settings['media_id'] = $media
      ->id();
    $settings['view_mode'] = empty($settings['view_mode']) ? 'default' : $settings['view_mode'];

    // If Media entity has a defined thumbnail, add it to data item.
    if ($media
      ->hasField('thumbnail')) {
      $item = $media
        ->get('thumbnail')
        ->first();
      $settings['file_tags'] = [
        'file:' . $item->target_id,
      ];

      // Provides thumbnail URI for EB selection with various Media entities.
      if (empty($settings['uri'])) {
        $settings['uri'] = ($entity = $item->entity) && empty($item->uri) ? $entity
          ->getFileUri() : $item->uri;
      }
    }
    $content = [];
    if ($settings['source_field'] && $media
      ->hasField($settings['source_field'])) {
      $value = $media->{$settings['source_field']}
        ->getValue();
      $input_url = isset($value[0]['uri']) ? $value[0]['uri'] : (isset($value[0]['value']) ? $value[0]['value'] : '');
      $input_url = trim(strip_tags($input_url));
      if ($input_url) {
        $settings['input_url'] = $input_url;

        // Soundcloud has different source_field name: source_url_field.
        if (strpos($input_url, 'soundcloud') === FALSE) {
          $this
            ->buildVideo($settings);
        }
      }
      elseif (isset($value[0]['alt']) || is_null($value[0]['alt'])) {
        $settings['type'] = 'image';
      }

      // Do not proceed if it has type, already managed by theme_blazy().
      // Supports other Media entities: Facebook, Instagram, Twitter, etc.
      if (empty($settings['type']) && ($build = BlazyMedia::build($media, $settings))) {
        $content[] = $build;
      }
    }

    // Collect what's needed for clarity.
    $data['item'] = $item;
    $data['settings'] = $settings;
    $data['content'] = $content;
  }

}

Traits

Namesort descending Description
BlazyVideoTrait A Trait common for optional Media Entity and Video Embed Media integration.