98c8b025b7e9b6bea8cfeba0b5795f846eb4be75
[yaffs-website] / web / modules / contrib / blazy / src / Dejavu / BlazyVideoTrait.php
1 <?php
2
3 namespace Drupal\blazy\Dejavu;
4
5 use Drupal\Core\Url;
6 use Drupal\file\Entity\File;
7 use Drupal\blazy\BlazyMedia;
8
9 /**
10  * A Trait common for optional Media Entity and Video Embed Media integration.
11  *
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.
18  *
19  * For more robust VEM/ME integration, use Slick Media instead.
20  *
21  * @see Drupal\blazy\Plugin\views\field\BlazyViewsFieldPluginBase
22  * @see Drupal\slick_browser\SlickBrowser::widgetEntityBrowserFileFormAlter()
23  * @see Drupal\slick_browser\Plugin\EntityBrowser\FieldWidgetDisplay\...
24  */
25 trait BlazyVideoTrait {
26
27   /**
28    * Returns the image factory.
29    */
30   public function imageFactory() {
31     return \Drupal::service('image.factory');
32   }
33
34   /**
35    * Returns the optional VEF service to avoid dependency for optional plugins.
36    */
37   public static function videoEmbedMediaManager() {
38     if (function_exists('video_embed_field_theme')) {
39       return \Drupal::service('video_embed_field.provider_manager');
40     }
41     return FALSE;
42   }
43
44   /**
45    * Builds relevant video embed field settings based on the given media url.
46    *
47    * @param array $settings
48    *   An array of settings to be passed into theme_blazy().
49    * @param string $external_url
50    *   A video URL.
51    */
52   public function buildVideo(array &$settings = [], $external_url = '') {
53     /** @var \Drupal\video_embed_field\ProviderManagerInterface $video */
54     if (!($video = self::videoEmbedMediaManager())) {
55       return;
56     }
57
58     if (!($provider = $video->loadProviderFromInput($external_url))) {
59       return;
60     }
61
62     // Ensures thumbnail is available.
63     $provider->downloadThumbnail();
64
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'] : [];
70
71     // Prevents complication with multiple videos by now.
72     unset($query['autoplay'], $query['auto_play']);
73
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';
79
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';
84     }
85     if ($settings['scheme'] == 'soundcloud') {
86       $settings['autoplay_url'] = strpos($url, '?') === FALSE ? $url . '?auto_play=true' : $url . '&auto_play=true';
87     }
88
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;
95       }
96     }
97   }
98
99   /**
100    * Gets the faked image item out of file entity, or ER, if applicable.
101    *
102    * @param object $file
103    *   The expected file entity, or ER, to get image item from.
104    *
105    * @return array
106    *   The array of image item and settings if a file image, else empty.
107    */
108   public function getImageItem($file) {
109     $data = [];
110     $entity = $file;
111
112     /** @var Drupal\Core\Field\Plugin\Field\FieldType\EntityReferenceItem $file */
113     if (isset($file->entity) && !isset($file->alt)) {
114       $entity = $file->entity;
115     }
116
117     if (!$entity instanceof File) {
118       return $data;
119     }
120
121     /** @var \Drupal\file\Entity\File $entity */
122     list($type,) = explode('/', $entity->getMimeType(), 2);
123     $uri = $entity->getFileUri();
124
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();
132       $item->uri       = $uri;
133       $settings        = (array) $item;
134       $item->entity    = $entity;
135
136       $settings['type'] = 'image';
137
138       // Build item and settings.
139       $data['item']     = $item;
140       $data['settings'] = $settings;
141       unset($item);
142     }
143
144     return $data;
145   }
146
147   /**
148    * Gets the Media item thumbnail, or re-associate the file entity to ME.
149    *
150    * @param array $data
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.
154    */
155   public function getMediaItem(array &$data = [], $entity = NULL) {
156     $settings = $data['settings'];
157
158     $media = $entity;
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);
164
165         /** @var \Drupal\media_entity\Entity\Media $entity */
166         $media = $this->blazyManager()->getEntityTypeManager()->getStorage('media')->load($media_id);
167       }
168     }
169
170     // Only proceed if we do have ME.
171     if ($media->getEntityTypeId() != 'media') {
172       return;
173     }
174
175     $bundle = $media->bundle();
176     $fields = $media->getFields();
177
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'];
184
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];
189
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();
193       }
194     }
195
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'] : '');
200
201       if ($input_url) {
202         $settings['input_url'] = $input_url;
203         $this->buildVideo($settings, $input_url);
204       }
205       elseif (isset($value[0]['alt'])) {
206         $settings['type'] = 'image';
207       }
208
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;
214         }
215       }
216     }
217
218     $data['settings'] = $settings;
219   }
220
221 }