Change record status: 
Project: 
Introduced in branch: 
8.6.x
Introduced in version: 
8.6.0
Description: 

As of #2831944: Implement media source plugin for remote video via oEmbed, the Media module has built-in support for remote media using the oEmbed standard.

Most popular services support oEmbed for embedding third-party media assets, including YouTube, Vimeo, Twitter, Instagram, Facebook, Flickr, and so forth. Drupal core implements a basic API for interacting with oEmbed services in a standard way, and provides a plugin that supports YouTube and Vimeo out of the box.

Architecture

Drupal's oEmbed API is built on top of three new core services:

media.oembed.provider_repository
This service is responsible for fetching and storing information about all known oEmbed providers. By default, it fetches this information from https://oembed.com/providers.json. Implements \Drupal\media\OEmbed\ProviderRepositoryInterface. Each provider is represented as an instance of \Drupal\media\OEmbed\Provider.

media.oembed.url_resolver
This service translates asset URLs (for instance, https://vimeo.com/7073899) into machine-consumable resource URLs which can be used by the oEmbed system. Implements \Drupal\media\OEmbed\UrlResolverInterface. Modules may alter the resource URLs by implementing hook_oembed_resource_url_alter().

media.oembed.resource_fetcher
This service takes a machine-consumable resource URL (i.e., as returned from the URL resolver), fetches it, and parses it into an instance of \Drupal\media\OEmbed\Resource, which provides all the information needed for Drupal to display the third-party media asset. Implements \Drupal\media\OEmbed\ResourceFetcherInterface.

Security

oEmbed support inherently introduces potential security hazards -- third-party oEmbed providers can return arbitrary HTML, which may in turn contain executable JavaScript code. Therefore, you should only support oEmbed providers that you trust. Drupal also tries to mitigate the risk of XSS attacks by displaying oEmbed content in an iframe, thus limiting the possible effects of harmful JavaScript. You can configure Media to serve this iframe from an alternate domain, which helps further secure cookies and other potentially sensitive information.

Extending

In order for the media system to interact with oEmbed services, there must be a source plugin which explicitly allows those services. For example, a source plugin which can interact with Deviantart and Flickr would look something like this:

<?php

namespace Drupal\mymodule\Plugin\media\Source;

use Drupal\media\Plugin\media\Source\OEmbed;

/**
 * @MediaSource(
 *   id = "artwork",
 *   label = @Translation("Artwork"),
 *   description = @Translation("Use artwork from Deviantart and Flickr."),
 *   providers = {"Deviantart.com", "Flickr"},
 *   allowed_field_types = {"string"},
 * )
 */
class Artwork extends OEmbed {
  // No need for anything in here; the base plugin can take care of typical interactions
  // with external oEmbed services.
}

This could also be accomplished by implementing hook_media_source_info_alter():

<?php

/**
  * Implements hook_media_source_info_alter().
  */
function mymodule_media_source_info_alter(array &$sources) {
  $sources['artwork'] = [
    'id' => 'artwork',
     'label' => t('Artwork'),
    'description' => t('Use artwork from Flickr and DeviantArt.'),
    'allowed_field_types' => ['string'],
    'default_thumbnail_filename' => 'no-thumbnail.png',
    'providers' => ['Deviantart.com', 'Flickr'],
    'class' => 'Drupal\media\Plugin\media\Source\OEmbed',
    'provider' => 'mymodule',
  ];
}

The providers key is crucial -- it defines which oEmbed providers (i.e., third-party services) will be allowed to be used by this plugin, and the plugin must explicitly opt in to each provider. The canonical list of providers is available at https://oembed.com/providers.json. The supported_providers array must contain the names of the providers you want to support, exactly as they appear in the canonical provider list.

Impacts: 
Site builders, administrators, editors
Module developers
Themers

Comments

chris matthews’s picture

Would it be possible to add a working example for Soundcloud oembed to this page?

luksak’s picture

I got adding Soundcloud embeds working. Displaying them still doesn't:

function hook_media_source_info_alter(array &$sources) {
  $sources['remote_audio'] = [
    'id' => 'remote_audio',
    'label' => t('Remote audio'),
    'description' => t('Use audio from Soundcloud and hearthis.at.'),
    'allowed_field_types' => ['string'],
    'default_thumbnail_filename' => 'no-thumbnail.png',
    'providers' => ['SoundCloud', 'hearthis.at'],
    'class' => 'Drupal\media\Plugin\media\Source\OEmbed',
  ];
}

Apart from that the second provider, hearthis.at, doesn't work at all.

scott_euser’s picture

Thanks Lukas, that got us most of the way there!

Ultimately this code work:

<?php

use Drupal\media_library\Form\OEmbedForm;

/**
 * Implements hook_media_source_info_alter().
 */
function iisd_backend_media_source_info_alter(array &$sources) {  // Add remote audio as a type.
  $sources['remote_audio'] = [
    'id' => 'remote_audio',
    'label' => t('Remote audio'),
    'description' => t('Use audio from Soundcloud.'),
    'allowed_field_types' => ['string'],
    'default_thumbnail_filename' => 'no-thumbnail.png',
    'providers' => ['SoundCloud'],
    'class' => 'Drupal\media\Plugin\media\Source\OEmbed',
    'provider' => 'media',
  ];

  // Make the new audio type use the media libary add form.
  $sources['remote_audio']['forms']['media_library_add'] = OEmbedForm::class;
}

Then the steps were:

  1. Add new Media Type 'Remote audio' selecting 'SoundCloud' as the provider
  2. Make that new Media Type available within the Node field (node type > manage fields > media field > Check 'Remote audio')

And that resulted in the ability to create a new Node and either select from existing Remote audio or add new Remote audio via URL (the latter was not possible without specifying that 'remote_audio' should use the OEmbedForm class for adding).

luksak’s picture

It turned out that Soundcloud doesn'timplement oembed correctly. I filed a support request: https://stackoverflow.com/questions/60128665/the-soundcloud-oembed-xml-e...