3 namespace Drupal\blazy\Dejavu;
6 use Drupal\file\Entity\File;
7 use Drupal\blazy\BlazyMedia;
10 * A Trait common for optional Media Entity and Video Embed Media integration.
12 * The basic idea is to display videos along with images even within core Image,
13 * and to re-associate VEF/ME video thumbnails beyond their own entity display.
14 * For editors, use Slick Browser, or Blazy Views field.
15 * For client-side, Blazy Views field, BlazyFileFormatter, SlickFileFormatter.
16 * Why bother? This addresses a mix of images/videos beyond field formatters
17 * or when ME and VEM integration is optional.
19 * For more robust VEM/ME integration, use Slick Media instead.
21 * @see Drupal\blazy\Plugin\views\field\BlazyViewsFieldPluginBase
22 * @see Drupal\slick_browser\SlickBrowser::widgetEntityBrowserFileFormAlter()
23 * @see Drupal\slick_browser\Plugin\EntityBrowser\FieldWidgetDisplay\...
25 trait BlazyVideoTrait {
28 * Returns the image factory.
30 public function imageFactory() {
31 return \Drupal::service('image.factory');
35 * Returns the optional VEF service to avoid dependency for optional plugins.
37 public static function videoEmbedMediaManager() {
38 if (function_exists('video_embed_field_theme')) {
39 return \Drupal::service('video_embed_field.provider_manager');
45 * Builds relevant video embed field settings based on the given media url.
47 * @param array $settings
48 * An array of settings to be passed into theme_blazy().
49 * @param string $external_url
52 public function buildVideo(array &$settings = [], $external_url = '') {
53 /** @var \Drupal\video_embed_field\ProviderManagerInterface $video */
54 if (!($video = self::videoEmbedMediaManager())) {
58 if (!($provider = $video->loadProviderFromInput($external_url))) {
62 // Ensures thumbnail is available.
63 $provider->downloadThumbnail();
65 // @todo extract URL from the SRC of final rendered TWIG instead.
66 $render = $provider->renderEmbedCode(640, 360, '0');
67 $old_url = isset($render['#attributes']) && isset($render['#attributes']['src']) ? $render['#attributes']['src'] : '';
68 $embed_url = isset($render['#url']) ? $render['#url'] : $old_url;
69 $query = isset($render['#query']) ? $render['#query'] : [];
71 // Prevents complication with multiple videos by now.
72 unset($query['autoplay'], $query['auto_play']);
74 $settings['video_id'] = $provider::getIdFromInput($external_url);
75 $settings['embed_url'] = Url::fromUri($embed_url, ['query' => $query])->toString();
76 $settings['scheme'] = $video->loadDefinitionFromInput($external_url)['id'];
77 $settings['uri'] = $provider->getLocalThumbnailUri();
78 $settings['type'] = 'video';
80 // Adds autoplay for media URL on lightboxes, saving another click.
81 $url = $settings['embed_url'];
82 if (strpos($url, 'autoplay') === FALSE || strpos($url, 'autoplay=0') !== FALSE) {
83 $settings['autoplay_url'] = strpos($url, '?') === FALSE ? $url . '?autoplay=1' : $url . '&autoplay=1';
85 if ($settings['scheme'] == 'soundcloud') {
86 $settings['autoplay_url'] = strpos($url, '?') === FALSE ? $url . '?auto_play=true' : $url . '&auto_play=true';
89 // Only applies when Image style is empty, no file API, no $item,
90 // with unmanaged VEF image without image_style.
91 // Prevents 404 warning when video thumbnail missing for a reason.
92 if (empty($settings['image_style'])) {
93 if ($data = @getimagesize($settings['uri'])) {
94 list($settings['width'], $settings['height']) = $data;
100 * Gets the faked image item out of file entity, or ER, if applicable.
102 * @param object $file
103 * The expected file entity, or ER, to get image item from.
106 * The array of image item and settings if a file image, else empty.
108 public function getImageItem($file) {
112 /** @var Drupal\Core\Field\Plugin\Field\FieldType\EntityReferenceItem $file */
113 if (isset($file->entity) && !isset($file->alt)) {
114 $entity = $file->entity;
117 if (!$entity instanceof File) {
121 /** @var \Drupal\file\Entity\File $entity */
122 list($type,) = explode('/', $entity->getMimeType(), 2);
123 $uri = $entity->getFileUri();
125 if ($type == 'image' && ($image = $this->imageFactory()->get($uri)) && $image->isValid()) {
126 $item = new \stdClass();
127 $item->target_id = $entity->id();
128 $item->width = $image->getWidth();
129 $item->height = $image->getHeight();
130 $item->alt = $entity->getFilename();
131 $item->title = $entity->getFilename();
133 $settings = (array) $item;
134 $item->entity = $entity;
136 $settings['type'] = 'image';
138 // Build item and settings.
139 $data['item'] = $item;
140 $data['settings'] = $settings;
148 * Gets the Media item thumbnail, or re-associate the file entity to ME.
151 * An array of data containing settings, and potential video thumbnail item.
152 * @param object $entity
153 * The media entity, else file entity to be associated to media, if any.
155 public function getMediaItem(array &$data = [], $entity = NULL) {
156 $settings = $data['settings'];
159 // Core File stores Media thumbnails, re-associate it to Media entity.
160 // @todo: If any proper method to get video URL from image URI, or FID.
161 if ($entity->getEntityTypeId() == 'file' && !empty($settings['uri']) && strpos($settings['uri'], 'video_thumbnails') !== FALSE) {
162 if ($media_id = \Drupal::entityQuery('media')->condition('thumbnail.target_id', $entity->id())->execute()) {
163 $media_id = reset($media_id);
165 /** @var \Drupal\media_entity\Entity\Media $entity */
166 $media = $this->blazyManager()->getEntityTypeManager()->getStorage('media')->load($media_id);
170 // Only proceed if we do have ME.
171 if ($media->getEntityTypeId() != 'media') {
175 $bundle = $media->bundle();
176 $fields = $media->getFields();
178 $source_field[$bundle] = $media->getType()->getConfiguration()['source_field'];
179 $settings['bundle'] = $bundle;
180 $settings['source_field'] = $source_field[$bundle];
181 $settings['media_url'] = $media->url();
182 $settings['media_id'] = $media->id();
183 $settings['view_mode'] = empty($settings['view_mode']) ? 'default' : $settings['view_mode'];
185 // If Media entity has a defined thumbnail, add it to data item.
186 if (isset($fields['thumbnail'])) {
187 $data['item'] = $fields['thumbnail']->get(0);
188 $settings['file_tags'] = ['file:' . $data['item']->target_id];
190 // Provides thumbnail URI for EB selection with various Media entities.
191 if (empty($settings['uri'])) {
192 $settings['uri'] = File::load($data['item']->target_id)->getFileUri();
196 $source = empty($settings['source_field']) ? '' : $settings['source_field'];
197 if ($source && isset($media->{$source})) {
198 $value = $media->{$source}->getValue();
199 $input_url = isset($value[0]['uri']) ? $value[0]['uri'] : (isset($value[0]['value']) ? $value[0]['value'] : '');
202 $settings['input_url'] = $input_url;
203 $this->buildVideo($settings, $input_url);
205 elseif (isset($value[0]['alt'])) {
206 $settings['type'] = 'image';
209 // Do not proceed if it has type, already managed by theme_blazy().
210 // Supports other Media entities: Facebook, Instagram, Twitter, etc.
211 if (empty($settings['type'])) {
212 if ($build = BlazyMedia::build($media, $settings)) {
213 $data['content'][] = $build;
218 $data['settings'] = $settings;