get('entity_type.manager'), $container->get('entity_field.manager'), $container->get('plugin.manager.field.field_type'), $container->get('config.factory'), $container->get('renderer') ); } /** * List of validation regular expressions. * * @var array */ public static $validationRegexp = [ // Embed code for Album '@(?P(.*) href=\"https://www.flickr.com/photos/(?[^\s]+)/albums/(?[0-9]+)\" title=\"(?P[^\"]+)\"><img src=\"(?P<thumbnail>[^\s]+)\" width=\"(?P<width>[0-9]+)\" height=\"(?P<height>[0-9]+)\" alt=\"(.*)\"></a>(.*))@i' => 'shortcode', // Embed code for Image '@(?P<shortcode>(.*) href=\"https://www.flickr.com/photos/(?<username>[^\s]+)/(?<imageid>[0-9]+)/(.*)\" title=\"(?P<title>[^\"]+)\"><img src=\"(?P<thumbnail>[^\s]+)\" width=\"(?P<width>[0-9]+)\" height=\"(?P<height>[0-9]+)\" alt=\"(.*)\"></a>(.*))@i' => 'shortcode', // URL of a single photo, eg https://www.flickr.com/photos/hoting2000/42633796482/ '@(?P<shortcode>(.*)https://www.flickr.com/photos/(?<username>[^\s]+)/(?<imageid>[0-9]+)/)@i' => 'shortcode', // Flickr photo ID, eg 42633796482 '@(?P<shortcode>(?<imageid>[0-9]+))@i' => 'shortcode', ]; /** * {@inheritdoc} */ public function getMetadataAttributes() { $fields = [ 'shortcode' => $this->t('Flickr shortcode'), 'username' => $this->t('Author of the post'), 'id' => $this->t('Flickr photo ID'), 'caption' => $this->t('Title of photo'), ]; return $fields; } /** * {@inheritdoc} */ public function getMetadata(MediaInterface $media, $attribute_name) { if ($attribute_name == 'default_name') { // Try to get some fields that need the API, if not available, just use // the shortcode as default name. $username = $this->getMetadata($media, 'username'); $id = $this->getMetadata($media, 'id'); if ($username && $id) { return $username . ' - ' . $id; } else { $code = $this->getMetadata($media, 'shortcode'); if (!empty($code)) { return $code; } } // Fallback to the parent's default name if everything else failed. return parent::getMetadata($media, 'default_name'); } elseif ($attribute_name == 'thumbnail_uri') { return $this->getMetadata($media, 'thumbnail_local'); } $matches = $this->matchRegexp($media); if (!$matches['shortcode'] || !$matches['imageid']) { // Can't work without these return FALSE; } $image_id = $matches['imageid']; // Flickr's numeric unique photo ID switch ($attribute_name) { case 'caption': return $this->getFlickrPhotoAttribute($image_id, 'title', $matches); case 'id': return $image_id; case 'shortcode': return $matches['shortcode']; case 'thumbnail': return $this->getFlickrThumbnail($image_id, $matches); case 'thumbnail_local': $local_uri = $this->getMetadata($media, 'thumbnail_local_uri'); if ($local_uri) { if (file_exists($local_uri)) { return $local_uri; } else { $directory = $this->configFactory->get('media_entity_flickr.settings')->get('local_images'); if (!file_exists($directory)) { \Drupal::service('file_system')->prepareDirectory($directory, FileSystemInterface::CREATE_DIRECTORY | FileSystemInterface::MODIFY_PERMISSIONS); } $image_url = $this->getMetadata($media, 'thumbnail'); // TODO Changeme with Guzzle $image_data = file_get_contents($image_url); if ($image_data) { return \Drupal::service('file_system')->saveData($image_data, $local_uri, FileSystemInterface::EXISTS_REPLACE); } } } return FALSE; case 'thumbnail_local_uri': $thumbnail = $this->getFlickrThumbnail($image_id, $matches); if ($thumbnail) { $file_info = pathinfo($thumbnail); return $this->configFactory->get('media_entity_flickr.settings')->get('local_images') . '/' . $file_info['filename'] . '.' . $file_info['extension']; } return FALSE; case 'username': return $this->getFlickrPhotoAttribute($image_id, 'username', $matches); } return FALSE; } /** * {@inheritdoc} */ public function getSourceFieldConstraints() { return ['FlickrEmbedCode' => []]; } /** * {@inheritdoc} */ public function createSourceField(MediaTypeInterface $type) { return parent::createSourceField($type)->set('label', 'Flickr Url'); } /** * Call one of the Flickr API's 'photos' methods * * @param $photo_id * The unique numeric ID of a Flickr photo * * @param $method * The API method to call. See the list at * https://www.flickr.com/services/api/ * * @return string|bool * Returns the result of the API call if successful, or * FALSE if there was an error. */ protected function flickrAPI($photo_id, $method) { if (self::$flickr_api_key == '') { // Can't access the API without a valid API key return FALSE; } $api_command = 'https://api.flickr.com/services/rest'; $api_command .= '/?method=' . $method; $api_command .= '&api_key=' . self::$flickr_api_key; $api_command .= '&photo_id=' . urlencode($photo_id); $api_command .= '&format=json&nojsoncallback=1'; try { $response = \Drupal::httpClient()->get($api_command, array('headers' => array('Accept' => 'text/plain'))); $body = (string) $response->getBody(); if (empty($body)) { return FALSE; } } catch (RequestException $e) { return FALSE; } $body=json_decode($body); if ($body->stat == 'ok') { // Flickr executed the API command successfully return $body; } return FALSE; } /** * Get an attribute of a photo, from the supplied embed-code / url * if possible, or otherwise by using Flickr's API * * @param $photo_id * The unique numeric ID of a Flickr photo * * @param $attribute_name * The attribute whose value to lookup * * @param $matches * The attributes extracted from the embed-code / url * * @return string|bool * Returns the value of the attribute, or FALSE if no match. */ protected function getFlickrPhotoAttribute($photo_id, $attribute_name, $matches) { // Based on code from the D7 Scald Flickr module static $searched_id = ''; static $flickr_photo_info; if (isset($matches[$attribute_name])) { // The attribute is in the embed-code / uri, so no need to use the API return $matches[$attribute_name]; } // We'll need to get the value from Flickr if ($searched_id != $photo_id){ // This is the first time through, so make the API call $data = $this->flickrAPI($photo_id, 'flickr.photos.getInfo'); if (!$data) { // The API call failed return FALSE; } // Remember the result for future use, so we don't have to make // repeated (and slow) calls to the Flickr API $searched_id = $photo_id; $flickr_photo_info = $data->photo; } switch ($attribute_name) { case 'title': return $flickr_photo_info->title->_content; case 'username': return $flickr_photo_info->owner->username; } return FALSE; } /** * Get the url of the thumbnail image using Flickr's API * * @param $photo_id * The unique numeric ID of a Flickr photo * * @param $matches * The attributes extracted from the embed-code / url * * @return string|bool * Returns the uri, or FALSE if none available. */ protected function getFlickrThumbnail($photo_id, $matches) { // Based on code from the D7 Scald Flickr module static $flickr_thumbnail; if (isset($matches['thumbnail'])) { // The url is in the embed-code, so no need to use the API return $matches['thumbnail']; } if ($flickr_thumbnail){ // We've already got the url from a previous call to this function return $flickr_thumbnail; } // We'll need to get the value from Flickr $data = $this->flickrAPI($photo_id, 'flickr.photos.getSizes'); if (!$data) { // The API call failed return FALSE; } if ($data->sizes->candownload) { // The owner of the Flickr image allows downloads // Define the Flickr sizes in the order we'd like to use, best first $preferred_size=array( 'Original', 'Large', 'Medium 800', 'Medium 640', 'Medium', 'Small 320', 'Small', 'Thumbnail' ); foreach ($preferred_size as $size) { // Is this size available to download? foreach ($data->sizes->size as $available_size) { if ($available_size->label == $size) { // We've found the best size $flickr_thumbnail = $available_size->source; return $flickr_thumbnail; } } } } return false; } /** * Runs preg_match on embed code/URL. * * @param \Drupal\media\MediaInterface $media * Media object. * * @return array|bool * Array of preg matches or FALSE if no match. * * @see preg_match() */ protected function matchRegexp(MediaInterface $media) { $matches = []; if (isset($this->configuration['source_field'])) { $source_field = $this->configuration['source_field']; if ($media->hasField($source_field)) { $property_name = $media->{$source_field}->first()->mainPropertyName(); foreach (static::$validationRegexp as $pattern => $key) { if (preg_match($pattern, $media->{$source_field}->{$property_name}, $matches)) { return $matches; } } } } return FALSE; } }