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';
86 // Only applies when Image style is empty, no file API, no $item,
87 // with unmanaged VEF image without image_style.
88 // Prevents 404 warning when video thumbnail missing for a reason.
89 if (empty($settings['image_style'])) {
90 if ($data = @getimagesize($settings['uri'])) {
91 list($settings['width'], $settings['height']) = $data;
97 * Gets the faked image item out of file entity, or ER, if applicable.
100 * The expected file entity, or ER, to get image item from.
103 * The array of image item and settings if a file image, else empty.
105 public function getImageItem($file) {
109 /** @var Drupal\Core\Field\Plugin\Field\FieldType\EntityReferenceItem $file */
110 if (isset($file->entity) && !isset($file->alt)) {
111 $entity = $file->entity;
114 if (!$entity instanceof File) {
118 /** @var \Drupal\file\Entity\File $entity */
119 list($type,) = explode('/', $entity->getMimeType(), 2);
120 $uri = $entity->getFileUri();
122 if ($type == 'image' && ($image = $this->imageFactory()->get($uri)) && $image->isValid()) {
123 $item = new \stdClass();
124 $item->target_id = $entity->id();
125 $item->width = $image->getWidth();
126 $item->height = $image->getHeight();
127 $item->alt = $entity->getFilename();
128 $item->title = $entity->getFilename();
130 $settings = (array) $item;
131 $item->entity = $entity;
133 $settings['type'] = 'image';
135 // Build item and settings.
136 $data['item'] = $item;
137 $data['settings'] = $settings;
145 * Gets the Media item thumbnail, or re-associate the file entity to ME.
148 * An array of data containing settings, and potential video thumbnail item.
149 * @param object $entity
150 * The media entity, else file entity to be associated to media, if any.
152 public function getMediaItem(array &$data = [], $entity = NULL) {
153 $settings = $data['settings'];
156 // Core File stores Media thumbnails, re-associate it to Media entity.
157 // @todo: If any proper method to get video URL from image URI, or FID.
158 if ($entity->getEntityTypeId() == 'file' && !empty($settings['uri']) && strpos($settings['uri'], 'video_thumbnails') !== FALSE) {
159 if ($media_id = \Drupal::entityQuery('media')->condition('thumbnail.target_id', $entity->id())->execute()) {
160 $media_id = reset($media_id);
162 /** @var \Drupal\media_entity\Entity\Media $entity */
163 $media = $this->blazyManager()->getEntityTypeManager()->getStorage('media')->load($media_id);
167 // Only proceed if we do have ME.
168 if ($media->getEntityTypeId() != 'media') {
172 $bundle = $media->bundle();
173 $fields = $media->getFields();
174 $config = method_exists($media, 'getSource') ? $media->getSource()->getConfiguration() : $media->getType()->getConfiguration();
175 $source = isset($config['source_url_field']) ? $config['source_url_field'] : '';
177 $source_field[$bundle] = isset($config['source_field']) ? $config['source_field'] : $source;
178 $settings['bundle'] = $bundle;
179 $settings['source_field'] = $source_field[$bundle];
180 $settings['media_url'] = $media->url();
181 $settings['media_id'] = $media->id();
182 $settings['view_mode'] = empty($settings['view_mode']) ? 'default' : $settings['view_mode'];
184 // If Media entity has a defined thumbnail, add it to data item.
185 if (isset($fields['thumbnail'])) {
186 $data['item'] = $fields['thumbnail']->get(0);
187 $settings['file_tags'] = ['file:' . $data['item']->target_id];
189 // Provides thumbnail URI for EB selection with various Media entities.
190 if (empty($settings['uri'])) {
191 $settings['uri'] = File::load($data['item']->target_id)->getFileUri();
195 $source = empty($settings['source_field']) ? '' : $settings['source_field'];
196 if ($source && isset($media->{$source})) {
197 $value = $media->{$source}->getValue();
198 $input_url = isset($value[0]['uri']) ? $value[0]['uri'] : (isset($value[0]['value']) ? $value[0]['value'] : '');
199 $input_url = strip_tags($input_url);
202 $settings['input_url'] = $input_url;
204 // Soundcloud has different source_field name: source_url_field.
205 if (strpos($input_url, 'soundcloud') === FALSE) {
206 $this->buildVideo($settings, $input_url);
209 elseif (isset($value[0]['alt'])) {
210 $settings['type'] = 'image';
213 // Do not proceed if it has type, already managed by theme_blazy().
214 // Supports other Media entities: Facebook, Instagram, Twitter, etc.
215 if (empty($settings['type'])) {
216 if ($build = BlazyMedia::build($media, $settings)) {
217 $data['content'][] = $build;
222 $data['settings'] = $settings;