Version 1
[yaffs-website] / web / modules / contrib / blazy / src / Dejavu / BlazyVideoTrait.php
diff --git a/web/modules/contrib/blazy/src/Dejavu/BlazyVideoTrait.php b/web/modules/contrib/blazy/src/Dejavu/BlazyVideoTrait.php
new file mode 100644 (file)
index 0000000..98c8b02
--- /dev/null
@@ -0,0 +1,221 @@
+<?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 video URL.
+   */
+  public function buildVideo(array &$settings = [], $external_url = '') {
+    /** @var \Drupal\video_embed_field\ProviderManagerInterface $video */
+    if (!($video = self::videoEmbedMediaManager())) {
+      return;
+    }
+
+    if (!($provider = $video->loadProviderFromInput($external_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($external_url);
+    $settings['embed_url'] = Url::fromUri($embed_url, ['query' => $query])->toString();
+    $settings['scheme']    = $video->loadDefinitionFromInput($external_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';
+    }
+    if ($settings['scheme'] == 'soundcloud') {
+      $settings['autoplay_url'] = strpos($url, '?') === FALSE ? $url . '?auto_play=true' : $url . '&auto_play=true';
+    }
+
+    // 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;
+    }
+
+    $bundle = $media->bundle();
+    $fields = $media->getFields();
+
+    $source_field[$bundle]    = $media->getType()->getConfiguration()['source_field'];
+    $settings['bundle']       = $bundle;
+    $settings['source_field'] = $source_field[$bundle];
+    $settings['media_url']    = $media->url();
+    $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 (isset($fields['thumbnail'])) {
+      $data['item'] = $fields['thumbnail']->get(0);
+      $settings['file_tags'] = ['file:' . $data['item']->target_id];
+
+      // Provides thumbnail URI for EB selection with various Media entities.
+      if (empty($settings['uri'])) {
+        $settings['uri'] = File::load($data['item']->target_id)->getFileUri();
+      }
+    }
+
+    $source = empty($settings['source_field']) ? '' : $settings['source_field'];
+    if ($source && isset($media->{$source})) {
+      $value     = $media->{$source}->getValue();
+      $input_url = isset($value[0]['uri']) ? $value[0]['uri'] : (isset($value[0]['value']) ? $value[0]['value'] : '');
+
+      if ($input_url) {
+        $settings['input_url'] = $input_url;
+        $this->buildVideo($settings, $input_url);
+      }
+      elseif (isset($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'])) {
+        if ($build = BlazyMedia::build($media, $settings)) {
+          $data['content'][] = $build;
+        }
+      }
+    }
+
+    $data['settings'] = $settings;
+  }
+
+}