migrate_spip-1.0.0/modules/examples/src/Plugin/SpipRichText/OEmbed.php
modules/examples/src/Plugin/SpipRichText/OEmbed.php
<?php
declare(strict_types=1);
namespace Drupal\migrate_spip_examples\Plugin\SpipRichText;
use Drupal\Core\Database\Connection;
use Drupal\Core\Entity\EntityTypeManagerInterface;
use Drupal\Core\Plugin\ContainerFactoryPluginInterface;
use Drupal\Core\StringTranslation\TranslatableMarkup;
use Drupal\media\MediaInterface;
use Drupal\migrate_spip\Attribute\SpipRichText;
use Drupal\migrate_spip\SpipRichTextBase;
use Symfony\Component\DependencyInjection\ContainerInterface;
/**
* Manage SPIP OEmbed plugin (based on version v3.0.3).
*
* Need to be executed before links.
*/
#[SpipRichText(
id: 'plugin_oembed',
label: new TranslatableMarkup('OEmbed plugin'),
weight: -25,
)]
final class OEmbed extends SpipRichTextBase implements ContainerFactoryPluginInterface {
/**
* Default providers list.
*
* @see inc/oembed.php::oembed_lister_providers()
*
* @var array
*/
private const PROVIDERS = [
'http://*.youtube.com/watch*' => 'https://www.youtube.com/oembed',
'http://*.youtube.com/playlist*' => 'https://www.youtube.com/oembed',
'http://youtu.be/*' => 'https://www.youtube.com/oembed',
'http://*.vimeo.com/*' => 'https://vimeo.com/api/oembed.json',
'http://vimeo.com/*' => 'https://vimeo.com/api/oembed.json',
'http://*.dailymotion.com/*' => 'https://www.dailymotion.com/services/oembed',
'http://dai.ly/*' => 'https://www.dailymotion.com/services/oembed',
'http://*.flickr.com/*' => 'https://www.flickr.com/services/oembed/',
'http://flickr.com/*' => 'https://www.flickr.com/services/oembed/',
'http://flic.kr/*' => 'https://www.flickr.com/services/oembed/',
'http://soundcloud.com/*' => 'https://soundcloud.com/oembed',
'http://mixcloud.com/*' => 'https://mixcloud.com/oembed',
'http://*.soundcloud.com/*' => 'https://soundcloud.com/oembed',
'http://*.mixcloud.com/*' => 'https://mixcloud.com/oembed',
'http://*.slideshare.net/*/*' => 'https://www.slideshare.net/api/oembed/2',
'http://www.slideshare.net/*/*' => 'https://www.slideshare.net/api/oembed/2',
'http://huffduffer.com/*/*' => 'http://huffduffer.com/oembed',
'http://nfb.ca/film/*' => 'http://www.nfb.ca/remote/services/oembed/',
'http://dotsub.com/view/*' => 'http://dotsub.com/services/oembed',
'http://clikthrough.com/theater/video/*' => 'http://clikthrough.com/services/oembed',
'http://kinomap.com/*' => 'http://www.kinomap.com/oembed',
'http://photobucket.com/albums/*' => 'http://api.photobucket.com/oembed',
'http://photobucket.com/groups/*' => 'http://api.photobucket.com/oembed',
'http://*.smugmug.com/*' => 'https://api.smugmug.com/services/oembed/',
'http://meetup.com/*' => 'https://api.meetup.com/oembed',
'http://meetup.ps/*' => 'http://api.meetup.com/oembed',
'http://*.wordpress.com/*' => 'https://public-api.wordpress.com/oembed/1.0/',
'http://twitter.com/*/status/*' => 'https://publish.twitter.com/oembed',
'http://twitter.com/*/likes' => 'https://publish.twitter.com/oembed',
'http://twitter.com/*/lists/*' => 'https://publish.twitter.com/oembed',
'http://twitter.com/*/timelines/*' => 'https://publish.twitter.com/oembed',
'http://twitter.com/i/moments/*' => 'https://publish.twitter.com/oembed',
'http://techcrunch.com/*' => 'http://public-api.wordpress.com/oembed/1.0/',
'http://wp.me/*' => 'http://public-api.wordpress.com/oembed/1.0/',
'http://my.opera.com/*' => 'http://my.opera.com/service/oembed',
'http://www.collegehumor.com/video/*' => 'http://www.collegehumor.com/oembed.json',
'http://imgur.com/*' => 'http://api.imgur.com/oembed',
'http://*.imgur.com/*' => 'http://api.imgur.com/oembed',
'http://*.onf.ca/*' => 'http://www.onf.ca/remote/services/oembed/',
'http://vine.co/v/*' => 'https://vine.co/oembed.json',
'http://*.tumblr.com/post/*' => 'https://www.tumblr.com/oembed/1.0',
'http://*.kickstarter.com/projects/*' => 'https://www.kickstarter.com/services/oembed',
'http://speakerdeck.com/*' => 'https://speakerdeck.com/oembed.json',
'http://issuu.com/*/docs/*' => 'https://issuu.com/oembed',
'http://*.calameo.com/books/*' => 'https://www.calameo.com/services/oembed',
'http://*.calameo.com/read/*' => 'https://www.calameo.com/services/oembed',
'http://*.arte.tv/*/videos/*' => 'https://api.arte.tv/api/player/v1/oembed/',
'http://egliseinfo.catholique.fr/*' => 'http://egliseinfo.catholique.fr/api/oembed',
// 'https://gist.github.com/*' => 'http://github.com/api/oembed?format=json',
];
/**
* The database connection.
*
* @var \Drupal\Core\Database\Connection
*/
protected Connection $connection;
/**
* The entity type manager.
*
* @var \Drupal\Core\Entity\EntityTypeManagerInterface
*/
protected EntityTypeManagerInterface $entityTypeManager;
/**
* {@inheritdoc}
*/
public static function create(
ContainerInterface $container,
array $configuration,
$plugin_id,
$plugin_definition
): static {
$instance = parent::create($container, $configuration, $plugin_id, $plugin_definition);
$instance->connection = $container->get('database');
$instance->entityTypeManager = $container->get('entity_type.manager');
return $instance;
}
/**
* {@inheritdoc}
*
* @SuppressWarnings(PHPMD.ElseExpression)
*/
public function apply(string $text): string {
// Search video URLs.
if (!preg_match_all("#(?:^|\n)(https?://(?:[-\w\.]+[-\w])+(?::\d+)?(?:/(?:[\w/_\.\#-]*(?:\?\S+)?[^\.\s])?)?)(?:\n|$)#s", $text, $matches)) {
return $text;
}
$mediaStorage = $this->entityTypeManager->getStorage('media');
foreach ($matches[1] as $index => $match) {
if (
empty($match) ||
!$this->isVideoProviderUrl($match)
) {
continue;
}
$mediaIds = $mediaStorage->getQuery()
->condition('field_media_oembed_video', $match)
->accessCheck(FALSE)
->execute();
if (!empty($mediaIds)) {
/** @var \Drupal\media\MediaInterface|null $media */
$media = $this->entityTypeManager->getStorage('media')
->load(reset($mediaIds));
}
else {
/** @var \Drupal\media\MediaInterface|null $media */
$media = $this->entityTypeManager->getStorage('media')
->create([
'bundle' => 'video',
'field_media_oembed_video' => [
'value' => $match,
],
]);
$media
->setName($this->getMediaName($media))
->setPublished()
->save();
}
if ($media) {
$text = str_replace(
$matches[0][$index],
$this->getMediaTag($media),
$text
);
}
}
return $text;
}
/**
* Get media name.
*
* @param \Drupal\media\MediaInterface $media
* The media entity.
*
* @return string
* The media name.
*/
private function getMediaName(MediaInterface $media): string {
$defaultName = $media->getSource()->getMetadata($media, 'default_name');
if ($defaultName) {
return $defaultName;
}
return (string) $this->t('Video @url', [
'@url' => $media->get('field_media_oembed_video')->value,
]);
}
/**
* Get Drupal media HTML tag.
*
* @param \Drupal\media\MediaInterface $media
* The media entity.
*
* @return string
* The media HTML tag.
*/
protected function getMediaTag(MediaInterface $media): string {
return '<drupal-media data-entity-type="media" data-entity-uuid="' .
$media->uuid() .
'"></drupal-media>';
}
/**
* Check if given URL is a video provider URL.
*
* @param string $url
* The given url.
*
* @return bool
* True if URL is a video provider URL, false otherwise.
*
* @see inc/oembeD.php::oembed_verifier_provider()
*/
private function isVideoProviderUrl(string $url): bool {
foreach (array_keys(self::PROVIDERS) as &$scheme) {
$regex = '#' . str_replace('\*', '(.+)', preg_quote($scheme, '#')) . '#';
$regex = preg_replace('|^#http\\\://|', '#https?\://', $regex);
if (preg_match($regex, $url)) {
return TRUE;
}
}
return FALSE;
}
}
