Problem/Motivation

Currently, when https://oembed.com/providers.json is fetched to generate a list of available oEmbed providers, there is no opportunity to alter the list of providers.

This would be useful in scenarios such as 1) Peer Tube and 2) oEmbed providers that may be organization-specific. Peer Tube is a decentralized video platform. The user can search videos across multiple instance of PeerTube with different domain names. Re custom oEmbed providers, the University of Nebraska-Lincoln hosts its own video service, which will soon support oEmbed. This functionality is needed by this organization.

Proposed resolution

Provide hook_oembed_providers_alter(). (Media already provides hook_oembed_resource_url_alter()).

Remaining tasks

  • Submit patch
  • Tests pass
  • Subsystem maintainer review
  • Change record

User interface changes

None.

API changes

Adding hook_oembed_providers_alter().

Data model changes

None.

Release notes snippet

TBD

Original report by phjou

I have studied the code from the oEmbed system in the core and I have discovered that it is based on the list provided by https://oembed.com/providers.json

This is a good list to start but I am wondering how to add a provider to this list?
You can host a new file with the additional services and change the settings "oembed_providers_url". But this method is really complicated to just support more providers.

Moreover I am creating this issue in order to support PeerTube which is a decentralized video platform. The user can search videos across multiple instance of PeerTube with different domain names. Such a complicated way to support a new provider is just impossible for a simple contributor.

In order to resolve this problem:
- The user should be able to override the default URL. The issue already exists for another reason: #2999018
- We should be able to alter the provider list by using a hook. What do you think about adding an alter call in the getAll function from Drupal\media\OEmbed\ProviderRepository?

Comments

phjou created an issue. See original summary.

phjou’s picture

chris burge’s picture

Version: 8.6.x-dev » 8.8.x-dev
Assigned: Unassigned » chris burge

Updating version to 8.8.x-dev. Patch is coming.

chris burge’s picture

Status: Active » Needs review
StatusFileSize
new6.32 KB

Attached patch provides hook_oembed_providers_alter(). Tests have been updated.

chris burge’s picture

Issue summary: View changes
chris burge’s picture

Title: Alter the oEmbed provider list » Provide hook_oembed_providers_alter()
Assigned: chris burge » Unassigned
Issue tags: +Media Initiative, +Needs subsystem maintainer review, +Needs change record
chris burge’s picture

Issue summary: View changes
phenaproxima’s picture

Issue tags: +oembed

I don't know if we want to have both #2999018: Expose oEmbed provider URL setting in the Media configuration form and this hook. If you can provide your own providers.json, do you really need this hook? The only "advantage" the hook provides is that you can alter the providers dynamically depending on various conditions -- sorta (they are strongly cached). But that goes against what the provider data is for; it's meant to be static database of oEmbed providers you want to support. An alter hook for this data does not, IMHO, make a lot of sense.

For now, I'll leave this issue open, but I'm in favor of closing this one out. If there is some other justification for adding this hook, I'd like a framework manager to weigh in on those potential pros and cons.

chris burge’s picture

Re #8, the primary benefit of using hook_oembed_providers_alter() to add a provider is that it's a maintenance-free solution. If you provide your own providers.json file, then you are [probably] forking the authoritative source. Once you've done that, now you must periodically merge in any changes from upstream. With hook_oembed_providers_alter(), you never have to revisit it.

seanb’s picture

I agree with the alter hook is more flexible than #2999018: Expose oEmbed provider URL setting in the Media configuration form and it also avoids exposing a setting a lot of users might not understand. So +1 from me for closing #2999018: Expose oEmbed provider URL setting in the Media configuration form as a duplicate and use an alter hook instead.

phenaproxima’s picture

The approach has been signed off by a subsystem maintainer, so removing that tag.

phjou’s picture

The other advantage in addition of being more flexible is that without a hook to alter the providers, we have to override the default list. That's what I did in the Peertube module: it takes the default list and add more providers inside it. But if there is another contrib module that needs to do the same, both modules will not be able to work together. The last enabled module will override the config to use his own list. So using a hook will solve that problem and give the opportunity to the contrib modules to easily support new providers without conflicts.

chris burge’s picture

I'm happy to make whatever changes come up during code review :-)

zipymonkey’s picture

The patch in #4 is working for us. I am able to add our instance of kaltura mediaspace to the list of approved providers.

joewhitsitt’s picture

We are using #4 as well for the University of Iowa's Kaltura/Mediaspace.

zipymonkey’s picture

@joewhitsitt I'm having issues with pulling down a proper thumbnail from Kaltura/Mediaspace (see https://www.drupal.org/project/drupal/issues/3080666). Are you having similar issues? Did you figure out a work around?

Version: 8.8.x-dev » 8.9.x-dev

Drupal 8.8.0-alpha1 will be released the week of October 14th, 2019, which means new developments and disruptive changes should now be targeted against the 8.9.x-dev branch. (Any changes to 8.9.x will also be committed to 9.0.x in preparation for Drupal 9’s release, but some changes like significant feature additions will be deferred to 9.1.x.). For more information see the Drupal 8 and 9 minor version schedule and the Allowed changes during the Drupal 8 and 9 release cycles.

chris burge’s picture

Status: Needs review » Reviewed & tested by the community

Tests still pass on 8.9.x. Per #14 and #15, setting to RTBC.

phenaproxima’s picture

Status: Reviewed & tested by the community » Needs work

Sorry to kick this back, but it looks like it still needs a change record before it can be committed. :(

chris burge’s picture

Status: Needs work » Needs review
Issue tags: -Needs change record
phenaproxima’s picture

Could the change record get a bit more detail about the hook? For example, we should state that it runs before providers are cached, and that it operates on raw provider information, before they are converted to Provider value objects. Also, maybe we want to mention that one could consult media.api.php for further information. While I'm at it, I'd also like to expand the doc comment in that file so that we state everything I just mentioned, and examples of why you'd want to implement this hook.

I'm really sorry to keep moving the goal posts on this one, but we're adding a whole new hook here and it's important that it be properly documented. There's a good chance committers would raise these concerns as well.

chris burge’s picture

Issue summary: View changes
StatusFileSize
new6.49 KB
new792 bytes

Updated patch with modified doc block per #21 (also caught a typo). Change record is updated.

phenaproxima’s picture

Status: Needs review » Reviewed & tested by the community

I like that. Restoring RTBC.

chris matthews’s picture

Would it be possible to back port this patch to 8.8.x or has that ship sailed?

phenaproxima’s picture

This is a feature request, so I don't think it will be backported.

chris burge’s picture

@Chris Matthews - We're running 8.8.1 with patch #22. It's fairly self-contained in what it does, so the only risk, from our point of view, is that it needs rerolled at some point between 8.8.1 and 8.9.0.

Status: Reviewed & tested by the community » Needs work
chris burge’s picture

Status: Needs work » Reviewed & tested by the community

Setting back to RTBC. That test failure is random. See #3103492: Random fail in WidgetUploadTest.

alexpott’s picture

Status: Reviewed & tested by the community » Needs work
  1. +++ b/core/modules/media/media.api.php
    @@ -37,6 +37,36 @@ function hook_oembed_resource_url_alter(array &$parsed_url, \Drupal\media\OEmbed
    + * The provider list is a pre-cache array of oEmbed providers. This hook fires
    + * before \Drupal\media\OEmbed\Provider objects are generated from the
    + * provider list.
    

    +1 on pointing out that altering occurs pre-cache. I think we should point out that implementations need to avoid anything dynamic.

    However given the need seems to be to add new providers I'm wondering whether an alter hook is really the best way forward here. There are a couple of ways we could go forward - we could implement some yaml parsing thing to add new providers or we could say that modules such as Peer Tube should be encouraged to decorate the service by doing something like:

      peertube.media.oembed.provider_repository:
        # Override the media.oembed.provider_repository to add peer tube.
        decorates: media.oembed.provider_repository
        class: Drupal\peertube\ProviderRepository
        public: false
        arguments: ['@peertube.media.oembed.provider_repository.inner']
    

    And then Drupal\peertube\ProviderRepository gets the info from the inner service and adds its own.

    Is there a (usual) case for altering the existing list of providers rather than just adding?

  2. +++ b/core/modules/media/media.services.yml
    @@ -12,7 +12,7 @@ services:
    -    arguments: ['@http_client', '@config.factory', '@datetime.time', '@cache.default']
    
    +++ b/core/modules/media/src/OEmbed/ProviderRepository.php
    @@ -59,9 +69,10 @@ class ProviderRepository implements ProviderRepositoryInterface {
    -  public function __construct(ClientInterface $http_client, ConfigFactoryInterface $config_factory, TimeInterface $time, CacheBackendInterface $cache_backend = NULL, $max_age = 604800) {
    +  public function __construct(ClientInterface $http_client, ConfigFactoryInterface $config_factory, ModuleHandlerInterface $module_handler, TimeInterface $time, CacheBackendInterface $cache_backend = NULL, $max_age = 604800) {
    

    Adding an argument in the middle of a constructor is hard from an BC point of view.

chris burge’s picture

Assigned: Unassigned » chris burge

We're using hook_oembed_providers_alter() to add a custom provider. We're not modifying providers. There may be a valid case for modifying a provider; however, someone else will need to jump in with that use case.

There are a couple of ways we could go forward - we could implement some yaml parsing thing to add new providers or we could say that modules such as Peer Tube should be encouraged to decorate the service

Re service decoration, this makes sense from a CS standpoint; however, this feature becomes accessible to only senior developers at that point.

Re parsing yaml, this doesn't seem like an unreasonable approach. It remains accessible to junior developers. Are you thinking something like 'my_module.media.oembed.yml'?

my_module.unl_media_hub: 
  provider_name: 'UNL MediaHub'
  provider_url: 'https://mediahub.unl.edu'
  endpoints: 
    - 
      schemes: 
        - 'https://mediahub.unl.edu/media/*'
        - 'http://mediahub.unl.edu/media/*'

      url: 'https://mediahub.unl.edu/oembed'
      discovery: 'false'

One of the benefits of hook_oembed_providers_alter() is that it would be easy for developers to find on api.drupal.org and the documentation is automatically handled.

phjou’s picture

I am not very familiar with "decorates". I just read a little article about it. For the quick look, decorating allows you to override the content of the methods of the service
If you have two contrib modules that decorates the service "media.oembed.provider_repository", will it work?

For PeerTube, I don't see any usual case for altering the existing list of providers, just adding the new provider with multiple endpoints.

I don't think YML parsing is an option for PeerTube. Your list is completely dynamic since it is a decentralized platform (there are hundreds of different websites matching that provider), I am building the list using PHP. Users are allowed to add new instances of Peertube using a config form. If we introduce a YML file, I will have to generate it and I guess it will introduce changes inside the contrib module which is probably a bad idea.

chris burge’s picture

Status: Needs work » Needs review
StatusFileSize
new8.42 KB

New patch attached that uses the YAML approach. Because it's a change in direction, there's no interdiff.

If we go this direction, we'll need to rename the issue, update the issue summary, and modify the change record.

(Note: The patch inserts a new argument in the middle of ProviderRepository::_construct, which I know was objected to in the patch #22; however, adding the argument to the end violates Drupal code standards, so in the middle it went.)

phenaproxima’s picture

I don't think we actually need the providers to be plugins -- the reason being, they don't provide any functionality at all. I suspect we can simply use \Drupal\Component\Discovery\YamlDiscovery to find providers in YAML files, without any need for plugin stuff.

phenaproxima’s picture

This, I just realized, is something we could do with a contrib project. All we'd need to do is decorate the provider repository with a YamlDiscovery thing that will scan modules for MODULE.oembed_providers.yml. So that said, maybe we could do this more quickly/easily in contrib?

chris burge’s picture

StatusFileSize
new5.62 KB

Plugin code is removed.

@phjou - Is my understanding correct that you need to dynamically add providers from user-provided config? If that's the case, can you confirm that the current approach (yaml) will not support your use case?

@phenaproxima - Quick and easy, yes.

phjou’s picture

@chris-burge Yes, the Yml files will not solve my use case. You can't know in advance the URLs of the instances of the platform the user wants to use. I definitely need to be able to add myself the provider with PHP. YML files are good for centralized platforms but not at all for decentralized ones.

chris burge’s picture

If we’re just adding providers and aren’t altering them, then we’d be looking at a function something like hook_media_oembed_provider_add(). That is the type of procedural code we’ve moved away from. So then the challenge becomes how to register providers at runtime [from config]. I think we might be left with a contrib module that decorates the provider repository and provides a UI and defines config for providers. (I suppose it could also scan for YAML. There are multiple ways to register menu items. We could allow two ways to define providers - config and module YAML files.)

phjou’s picture

A contrib module that provides a config and YML sounds good to me, but this contrib module will have to provide a hook to modify the list.
So at the end the contrib module will have the same feature as the hook_oembed_providers_alter I guess?

One of the feature of the Peertube module I wanted to code is providing endpoints based on users choices like the language or category of the videos instances: https://joinpeertube.org/instances#instances-list
It will define the Peertube provider with the endpoints that match those criteria, so I will need a hook to modify it because parsing the config to find the provider sounds like a bad idea no?

chris burge’s picture

If we do go the contrib route, we could also add an option to disable the call to grab the JSON provider file. If you're only allowing custom providers, then there's no need to download and parse the provider JSON file. We would actually use that feature.

phjou’s picture

I am not sure to follow you because you can want both JSON parsing and config for different providers (one same provider can't be included in both).
Or do you mean the JSON parsing is a performance issue and it justifies disabling it with a global option?

chris burge’s picture

@phjou - It could provide an option to disable the downloading and parsing of providers.json. It sounds like in your case that you would not enable that option because you need one or more providers defined by providers.json. In the event that a site only used custom providers, then downloading and parsing providers.json would be unnecessary (thus a potential performance hit).

ankithashetty’s picture

I had a requirement to add the custom providers to the existing providers' list and the solution provided here was just what I needed!
I applied the patch provided in #22. Even then when I try to add a URL of the custom provider in the remote-video type field, I am not able to embed it. On debugging I was able to find the following error.

Error: Call to a member function getEndpoints() on null in Drupal\media\OEmbed\UrlResolver->getResourceUrl() (line 161 of /app/web/core/modules/media/src/OEmbed/UrlResolver.php).

I am new to Drupal so facing all these difficulties. KIndly if someone could guide me here I would be grateful.

Thank You.

chris burge’s picture

We've added the ability to define custom oEmbed providers in the oEmbed Providers module. They're defined as config entities. AFAIK, this solution addresses every use case described herein. If needed, adding hook_oembed_providers_alter() would be really easy. @phjou - Does this address your use case?

phjou’s picture

So nice, thanks! I will need to find some time to test it. If I can't find a moment before the 23rd of april, I should have some time after that date.

chris burge’s picture

Assigned: chris burge » Unassigned

Version: 8.9.x-dev » 9.1.x-dev

Drupal 8.9.0-beta1 was released on March 20, 2020. 8.9.x is the final, long-term support (LTS) minor release of Drupal 8, which means new developments and disruptive changes should now be targeted against the 9.1.x-dev branch. For more information see the Drupal 8 and 9 minor version schedule and the Allowed changes during the Drupal 8 and 9 release cycles.

slv_’s picture

While https://www.drupal.org/project/drupal/issues/2999018 is closed as a duplicate of this, I see the point of the UI not WSODing out when the provider url is not available. Imho a media overview page should never crash because a 3rd-party service can't be reached. Status / warning messages are fine, shouldn't the WSOD be tackled as well?

phenaproxima’s picture

I see the point of the UI not WSODing out when the provider url is not available. Imho a media overview page should never crash because a 3rd-party service can't be reached. Status / warning messages are fine, shouldn't the WSOD be tackled as well?

Yes, it should be, but it's out of scope for this issue. Would you be willing to open a separate issue to work on that?

phenaproxima’s picture

weekbeforenext’s picture

I'm using the patch from #22 to alter oEmbed provider information fixing bugs before the oEmbed.com information is updated.

  • Can you alter providers using the YAML method?
  • Can you also alter or add multiple providers in the YAML file?

I like the idea of using the YAML file, but I need the ability to alter multiple providers.

Thanks all!

chris burge’s picture

Can you alter providers using the YAML method?

No.

Can you also alter or add multiple providers in the YAML file?

Alter - no. Add multiple - yes.

If there were interest, we would add hook_oembed_providers_alter() to the oEmbed Providers module. It's basically a matter of lifting the code from #22. Part of the reason we wrote the module was to avoid running multiple core patches.

phenaproxima’s picture

I wonder if we shouldn't wontfix this issue in core. It seems like the oEmbed Providers module fills the gap pretty well, and if we could implement the hook there, then I don't think we'd need to do this in core (although we could certainly revisit the idea if enough need arose).

chris burge’s picture

Version: 9.1.x-dev » 9.2.x-dev

Drupal 9.1.0-alpha1 will be released the week of October 19, 2020, which means new developments and disruptive changes should now be targeted for the 9.2.x-dev branch. For more information see the Drupal 9 minor version schedule and the Allowed changes during the Drupal 9 release cycle.

chris matthews’s picture

I wonder if we shouldn't wontfix this issue in core. - #52

FWIW, since Media already provides hook_oembed_resource_url_alter() it makes sense to me to provide hook_oembed_providers_alter() in Core. The oEmbed Providers contrib module does fill in the gap, but it seems like a pretty wide gap that "should" be handled in Core.

randell’s picture

Well, sites went down yesterday. At the very least, the dependency to an external resource should not be a Core default as it serves like a ticking time bomb.

chris burge’s picture

Version: 9.2.x-dev » 9.3.x-dev

Drupal 9.2.0-alpha1 will be released the week of May 3, 2021, which means new developments and disruptive changes should now be targeted for the 9.3.x-dev branch. For more information see the Drupal core minor version schedule and the Allowed changes during the Drupal core release cycle.

Version: 9.3.x-dev » 9.4.x-dev

Drupal 9.3.0-rc1 was released on November 26, 2021, which means new developments and disruptive changes should now be targeted for the 9.4.x-dev branch. For more information see the Drupal core minor version schedule and the Allowed changes during the Drupal core release cycle.

lobsterr’s picture

I have rerolled the patch #3008119-22: Provide hook_oembed_providers_alter(). I can't create interdiff, because it is to much work to do taking into account it could be applied only for 9.1.*. Basically, it is absolutely the same. I have tested with the stable 9.3.0 version

phjou’s picture

Just realized I never answered here, the oEmbed Providers module is enough since it is providing the hook.

ranjith_kumar_k_u’s picture

StatusFileSize
new6.8 KB

Status: Needs review » Needs work

The last submitted patch, 62: 3008119-62.patch, failed testing. View results

lobsterr’s picture

@ranjith_kumar_k_u - What is the point to reupload basically the same patch without any changes. Why do you do this ?

ankithashetty’s picture

The test bot in #60 says the patch failed to apply in core 9.4.x ( https://www.drupal.org/pift-ci-job/2284443 ), may be thats why a corrected patch is re-uploaded in #62 for 9.4.x?

Anyways, as suggested in #61 by @phjou, the oEmbed providers contributed module provides us the hook and additional cool features. I have used the module and it's great! :)

Have a great day everyone, cheers!

matthieuscarset’s picture

Status: Needs work » Postponed

Agree with @ankithashetty in #65

The oembed_providers module works and solve this issue.

I think it's good to keep solution as a separate contrib module for now.

There was not much activity on this thread for over year so there is certainly not an urgent need to modify core.

Marking this issue as Postponed.

Linking to OEmbed Providers module again for the record.

Version: 9.4.x-dev » 9.5.x-dev

Drupal 9.4.0-alpha1 was released on May 6, 2022, which means new developments and disruptive changes should now be targeted for the 9.5.x-dev branch. For more information see the Drupal core minor version schedule and the Allowed changes during the Drupal core release cycle.

chris matthews’s picture

In #52 Adam (phenaproxima) said,

I wonder if we shouldn't won't fix this issue in core. It seems like the oEmbed Providers module fills the gap pretty well, and if we could implement the hook there, then I don't think we'd need to do this in core (although we could certainly revisit the idea if enough need arose).

FWIW, I also think this feature request issue should be closed (won't fix) in favor of the contrib solution.

tstoeckler’s picture

So the issue is that while the contrib module works it currently has to override and circumvent a lot of the logic in core because of core's missing flexiblity. This is definitely not ideal and it would be great if that situation could be improved so that the contrib module has to do less work, this issue being one fairly straightforward way to go about it. If the hook is not deemed appropriate by core maintainers it would be great if a different approach to allow the same or similar flexibility could be discussed before rejecting the issue altogether.

That's just my two cents and if the current state of the module is the best we can get that's also fine, I just personally think we could do better.

steinmb’s picture

I have been re-reading this issue and looking at some of the changes rolled to core media since the it was started and I not sure about this issue. Perhaps it need rescoping. Would love to hear @Chris-Burge thoughts on what might make life easier for modules like oEmbed Providers (#52).

chris burge’s picture

It would be nice if there were a way to call the decorated ->getAll() method inside the decorator ->getAll() method (like you would parent::method() with an extended class); however, the fact that we're using key-value store as a caching mechanism makes that unworkable. We would want to control caching in the decorator method and disable it in the decorated method. I think we're stuck with how we're doing things now.

That actually makes me think that the current implementation of hook_oembed_providers_alter() has a fairly major bug. The key-value store is set to store providers for 7 days (604800 seconds). There's no way to clear it. You just have to wait up to 7 days. So.. I would expect hook_oembed_providers_alter() would only run if the key-value value has expired, not every time ->getAll() is executed. Am I thinking about that correctly?

Version: 9.5.x-dev » 10.1.x-dev

Drupal 9.5.0-beta2 and Drupal 10.0.0-beta2 were released on September 29, 2022, which means new developments and disruptive changes should now be targeted for the 10.1.x-dev branch. For more information see the Drupal core minor version schedule and the Allowed changes during the Drupal core release cycle.

Version: 10.1.x-dev » 11.x-dev

Drupal core is moving towards using a “main” branch. As an interim step, a new 11.x branch has been opened, as Drupal.org infrastructure cannot currently fully support a branch named main. New developments and disruptive changes should now be targeted for the 11.x branch, which currently accepts only minor-version allowed changes. For more information, see the Drupal core minor version schedule and the Allowed changes during the Drupal core release cycle.

chris matthews’s picture

Seems as though there are 3 paths that could be taken ...

  1. Won't fix issue and rely on oEmbed Providers, which already includes hook_oembed_providers_alter()
  2. Implement hook_oembed_providers_alter() in Core per the original proposed resolution in the IS
  3. Re-scope this issue to assist oEmbed Providers as Chris Burge detailed in #71

What is the will of the council?

chris burge’s picture

@Chris Matthews - Thanks for reanimating this issue.

Re #71, the first part is still an issue, but it probably falls under the "would be nice" category. We could break the current ->getAll() method into two methods. The first [new] method would solely be responsible for fetching (no caching). The second method would be ->getAll(). It would call the first method and then cache the results in key/value before returning the providers list. From a BC standpoint, it would be 100% non-breaking. Then - the oembed_providers module could call the new fetch-only method instead of ->getAll(). Now that I think about it. It would be pretty easy to implement and to add test coverage. This isn't a heavy lift.

The second part was addressed in #3296300: Add UI to clear provider list from keyvalue. If hook_oembed_providers_alter() were implemented in core, then I think we would also want to address the caching issue in core - namely how to clear the values cached in key/value if someone doesn't want to wait 7 days. That might be a can of worms not worth opening.

What about this?

  1. Add a new, fetch-only method to the ProviderRepository class in core.
  2. Keep hook_oembed_providers_alter() in contrib.
chris matthews’s picture

  1. Add a new, fetch-only method to the ProviderRepository class in core. 💯 ✅ 👍
  2. Keep hook_oembed_providers_alter() in contrib. 💯 ✅ 👍

Both make sense to me.

chris burge’s picture

I dove into ProviderRepository, and now that I'm in the code, I'm seeing it's going to be a bit more challenging to refactor ->getAll() into two methods. We'd also have to update ProviderRepositoryInterrface, which creates a BC issue. So - on second thought, let's not move forward on that.

In terms of this issue, I think we're good to change the status to 'Closed (won't fix)'.

Version: 11.x-dev » main

Drupal core is now using the main branch as the primary development branch. New developments and disruptive changes should now be targeted to the main branch.

Read more in the announcement.