From 7201d4bfba4aaedf5ff68ab9ccfa035554fa88be Mon Sep 17 00:00:00 2001 From: Alex Pott <alex.a.pott@googlemail.com> Date: Sat, 6 Apr 2024 15:58:22 +0100 Subject: [PATCH] Issue #3420997 by sorlov, quietone, DanielVeza, smustgrave, alexpott, mstrelan: Convert MediaSource plugin discovery to attributes --- .../media/src/Attribute/MediaSource.php | 87 +++++++++++++++++++ .../media/src/Attribute/OEmbedMediaSource.php | 86 ++++++++++++++++++ core/modules/media/src/MediaSourceManager.php | 4 +- .../src/Plugin/media/Source/AudioFile.php | 17 ++-- .../media/src/Plugin/media/Source/File.php | 16 ++-- .../media/src/Plugin/media/Source/Image.php | 19 ++-- .../media/src/Plugin/media/Source/OEmbed.php | 20 ++--- .../src/Plugin/media/Source/VideoFile.php | 17 ++-- .../src/Plugin/media/Source/Test.php | 15 ++-- .../media/Source/TestDifferentDisplays.php | 15 ++-- .../Plugin/media/Source/TestTranslation.php | 17 ++-- .../media/Source/TestWithConstraints.php | 15 ++-- .../Source/TestWithHiddenSourceField.php | 15 ++-- .../media_library/media_library.api.php | 19 ++-- 14 files changed, 271 insertions(+), 91 deletions(-) create mode 100644 core/modules/media/src/Attribute/MediaSource.php create mode 100644 core/modules/media/src/Attribute/OEmbedMediaSource.php diff --git a/core/modules/media/src/Attribute/MediaSource.php b/core/modules/media/src/Attribute/MediaSource.php new file mode 100644 index 000000000000..13289419f1f3 --- /dev/null +++ b/core/modules/media/src/Attribute/MediaSource.php @@ -0,0 +1,87 @@ +<?php + +declare(strict_types=1); + +namespace Drupal\media\Attribute; + +use Drupal\Component\Plugin\Attribute\Plugin; +use Drupal\Core\StringTranslation\TranslatableMarkup; + +/** + * Defines a MediaSource attribute. + * + * Media sources are responsible for implementing all the logic for dealing + * with a particular type of media. They provide various universal and + * type-specific metadata about media of the type they handle. + * + * Plugin namespace: Plugin\media\Source + * + * For a working example, see \Drupal\media\Plugin\media\Source\File. + * + * @see \Drupal\media\MediaSourceInterface + * @see \Drupal\media\MediaSourceBase + * @see \Drupal\media\MediaSourceManager + * @see hook_media_source_info_alter() + * @see plugin_api + */ +#[\Attribute(\Attribute::TARGET_CLASS)] +class MediaSource extends Plugin { + + /** + * Constructs a new MediaSource attribute. + * + * @param string $id + * The attribute class ID. + * @param \Drupal\Core\StringTranslation\TranslatableMarkup $label + * The human-readable name of the media source. + * @param \Drupal\Core\StringTranslation\TranslatableMarkup|null $description + * (optional) A brief description of the media source. + * @param string[] $allowed_field_types + * (optional) The field types that can be used as a source field for this + * media source. + * @param class-string[] $forms + * (optional) The classes used to define media source-specific forms. An + * array of form class names, keyed by ID. The ID represents the operation + * the form is used for, for example, 'media_library_add'. + * @param string $default_thumbnail_filename + * (optional) A filename for the default thumbnail. + * The thumbnails are placed in the directory defined by the config setting + * 'media.settings.icon_base_uri'. When using custom icons, make sure the + * module provides a hook_install() implementation to copy the custom icons + * to this directory. The media_install() function provides a clear example + * of how to do this. + * @param string $thumbnail_uri_metadata_attribute + * (optional) The metadata attribute name to provide the thumbnail URI. + * @param string $thumbnail_width_metadata_attribute + * (optional) The metadata attribute name to provide the thumbnail width. + * @param string $thumbnail_height_metadata_attribute + * (optional) The metadata attribute name to provide the thumbnail height. + * @param string|null $thumbnail_alt_metadata_attribute + * (optional) The metadata attribute name to provide the thumbnail alt. + * "Thumbnail" will be used if the attribute name is not provided. + * @param string|null $thumbnail_title_metadata_attribute + * (optional) The metadata attribute name to provide the thumbnail title. + * The name of the media item will be used if the attribute name is not + * provided. + * @param string $default_name_metadata_attribute + * (optional) The metadata attribute name to provide the default name. + * @param class-string|null $deriver + * (optional) The deriver class. + */ + public function __construct( + public readonly string $id, + public readonly TranslatableMarkup $label, + public readonly ?TranslatableMarkup $description = NULL, + public readonly array $allowed_field_types = [], + public readonly array $forms = [], + public readonly string $default_thumbnail_filename = 'generic.png', + public readonly string $thumbnail_uri_metadata_attribute = 'thumbnail_uri', + public readonly string $thumbnail_width_metadata_attribute = 'thumbnail_width', + public readonly string $thumbnail_height_metadata_attribute = 'thumbnail_height', + public readonly ?string $thumbnail_alt_metadata_attribute = NULL, + public readonly ?string $thumbnail_title_metadata_attribute = NULL, + public readonly string $default_name_metadata_attribute = 'default_name', + public readonly ?string $deriver = NULL + ) {} + +} diff --git a/core/modules/media/src/Attribute/OEmbedMediaSource.php b/core/modules/media/src/Attribute/OEmbedMediaSource.php new file mode 100644 index 000000000000..3de756bb9d7c --- /dev/null +++ b/core/modules/media/src/Attribute/OEmbedMediaSource.php @@ -0,0 +1,86 @@ +<?php + +declare(strict_types=1); + +namespace Drupal\media\Attribute; + +use Drupal\Core\StringTranslation\TranslatableMarkup; + +/** + * Defines a OEmbedMediaSource attribute. + * + * Plugin namespace: Plugin\media\Source + * + * For a working example, see \Drupal\media\Plugin\media\Source\OEmbed. + * + * @see \Drupal\media\MediaSourceInterface + * @see \Drupal\media\MediaSourceBase + * @see \Drupal\media\MediaSourceManager + * @see hook_media_source_info_alter() + * @see plugin_api + */ +#[\Attribute(\Attribute::TARGET_CLASS)] +class OEmbedMediaSource extends MediaSource { + + /** + * Constructs a new OEmbedMediaSource attribute. + * + * @param string $id + * The attribute class ID. + * @param \Drupal\Core\StringTranslation\TranslatableMarkup $label + * The human-readable name of the media source. + * @param \Drupal\Core\StringTranslation\TranslatableMarkup|null $description + * (optional) A brief description of the media source. + * @param string[] $allowed_field_types + * (optional) The field types that can be used as a source field for this + * media source. + * @param class-string[] $forms + * (optional) The classes used to define media source-specific forms. An + * array of form class names, keyed by ID. The ID represents the operation + * the form is used for, for example, 'media_library_add'. + * @param string[] $providers + * (optional) A set of provider names, exactly as they appear in the + * canonical oEmbed provider database at https://oembed.com/providers.json. + * @param string $default_thumbnail_filename + * (optional) A filename for the default thumbnail. + * The thumbnails are placed in the directory defined by the config setting + * 'media.settings.icon_base_uri'. When using custom icons, make sure the + * module provides a hook_install() implementation to copy the custom icons + * to this directory. The media_install() function provides a clear example + * of how to do this. + * @param string $thumbnail_uri_metadata_attribute + * (optional) The metadata attribute name to provide the thumbnail URI. + * @param string $thumbnail_width_metadata_attribute + * (optional) The metadata attribute name to provide the thumbnail width. + * @param string $thumbnail_height_metadata_attribute + * (optional) The metadata attribute name to provide the thumbnail height. + * @param string|null $thumbnail_alt_metadata_attribute + * (optional) The metadata attribute name to provide the thumbnail alt. + * "Thumbnail" will be used if the attribute name is not provided. + * @param string|null $thumbnail_title_metadata_attribute + * (optional) The metadata attribute name to provide the thumbnail title. + * The name of the media item will be used if the attribute name is not + * provided. + * @param string $default_name_metadata_attribute + * (optional) The metadata attribute name to provide the default name. + * @param class-string|null $deriver + * (optional) The deriver class. + */ + public function __construct( + public readonly string $id, + public readonly TranslatableMarkup $label, + public readonly ?TranslatableMarkup $description = NULL, + public readonly array $allowed_field_types = [], + public readonly array $forms = [], + public readonly array $providers = [], + public readonly string $default_thumbnail_filename = 'generic.png', + public readonly string $thumbnail_uri_metadata_attribute = 'thumbnail_uri', + public readonly string $thumbnail_width_metadata_attribute = 'thumbnail_width', + public readonly string $thumbnail_height_metadata_attribute = 'thumbnail_height', + public readonly ?string $thumbnail_alt_metadata_attribute = NULL, + public readonly ?string $thumbnail_title_metadata_attribute = NULL, + public readonly string $default_name_metadata_attribute = 'default_name', + public readonly ?string $deriver = NULL + ) {} + +} diff --git a/core/modules/media/src/MediaSourceManager.php b/core/modules/media/src/MediaSourceManager.php index 5b8778721c76..302a5ef55306 100644 --- a/core/modules/media/src/MediaSourceManager.php +++ b/core/modules/media/src/MediaSourceManager.php @@ -5,7 +5,7 @@ use Drupal\Core\Cache\CacheBackendInterface; use Drupal\Core\Extension\ModuleHandlerInterface; use Drupal\Core\Plugin\DefaultPluginManager; -use Drupal\media\Annotation\MediaSource; +use Drupal\media\Attribute\MediaSource; /** * Manages media source plugins. @@ -24,7 +24,7 @@ class MediaSourceManager extends DefaultPluginManager { * The module handler. */ public function __construct(\Traversable $namespaces, CacheBackendInterface $cache_backend, ModuleHandlerInterface $module_handler) { - parent::__construct('Plugin/media/Source', $namespaces, $module_handler, MediaSourceInterface::class, MediaSource::class); + parent::__construct('Plugin/media/Source', $namespaces, $module_handler, MediaSourceInterface::class, MediaSource::class, '\Drupal\media\Annotation\MediaSource'); $this->alterInfo('media_source_info'); $this->setCacheBackend($cache_backend, 'media_source_plugins'); diff --git a/core/modules/media/src/Plugin/media/Source/AudioFile.php b/core/modules/media/src/Plugin/media/Source/AudioFile.php index 1e215930851d..d2f2035fc607 100644 --- a/core/modules/media/src/Plugin/media/Source/AudioFile.php +++ b/core/modules/media/src/Plugin/media/Source/AudioFile.php @@ -3,21 +3,22 @@ namespace Drupal\media\Plugin\media\Source; use Drupal\Core\Entity\Display\EntityViewDisplayInterface; +use Drupal\Core\StringTranslation\TranslatableMarkup; +use Drupal\media\Attribute\MediaSource; use Drupal\media\MediaTypeInterface; /** * Media source wrapping around an audio file. * * @see \Drupal\file\FileInterface - * - * @MediaSource( - * id = "audio_file", - * label = @Translation("Audio file"), - * description = @Translation("Use audio files for reusable media."), - * allowed_field_types = {"file"}, - * default_thumbnail_filename = "audio.png" - * ) */ +#[MediaSource( + id: "audio_file", + label: new TranslatableMarkup("Audio file"), + description: new TranslatableMarkup("Use audio files for reusable media."), + allowed_field_types: ["file"], + default_thumbnail_filename: "audio.png" +)] class AudioFile extends File { /** diff --git a/core/modules/media/src/Plugin/media/Source/File.php b/core/modules/media/src/Plugin/media/Source/File.php index 1c963ef9636b..ba42d9a49686 100644 --- a/core/modules/media/src/Plugin/media/Source/File.php +++ b/core/modules/media/src/Plugin/media/Source/File.php @@ -2,7 +2,9 @@ namespace Drupal\media\Plugin\media\Source; +use Drupal\Core\StringTranslation\TranslatableMarkup; use Drupal\file\FileInterface; +use Drupal\media\Attribute\MediaSource; use Drupal\media\MediaInterface; use Drupal\media\MediaTypeInterface; use Drupal\media\MediaSourceBase; @@ -11,15 +13,13 @@ * File entity media source. * * @see \Drupal\file\FileInterface - * - * @MediaSource( - * id = "file", - * label = @Translation("File"), - * description = @Translation("Use local files for reusable media."), - * allowed_field_types = {"file"}, - * default_thumbnail_filename = "generic.png" - * ) */ +#[MediaSource( + id: "file", + label: new TranslatableMarkup("File"), + description: new TranslatableMarkup("Use local files for reusable media."), + allowed_field_types: ["file"], +)] class File extends MediaSourceBase { /** diff --git a/core/modules/media/src/Plugin/media/Source/Image.php b/core/modules/media/src/Plugin/media/Source/Image.php index 4b6d48bd01cb..e896f3b41a22 100644 --- a/core/modules/media/src/Plugin/media/Source/Image.php +++ b/core/modules/media/src/Plugin/media/Source/Image.php @@ -9,6 +9,8 @@ use Drupal\Core\Field\FieldTypePluginManagerInterface; use Drupal\Core\File\FileSystemInterface; use Drupal\Core\Image\ImageFactory; +use Drupal\Core\StringTranslation\TranslatableMarkup; +use Drupal\media\Attribute\MediaSource; use Drupal\media\MediaInterface; use Drupal\media\MediaTypeInterface; use Symfony\Component\DependencyInjection\ContainerInterface; @@ -17,16 +19,15 @@ * Image entity media source. * * @see \Drupal\Core\Image\ImageInterface - * - * @MediaSource( - * id = "image", - * label = @Translation("Image"), - * description = @Translation("Use local images for reusable media."), - * allowed_field_types = {"image"}, - * default_thumbnail_filename = "no-thumbnail.png", - * thumbnail_alt_metadata_attribute = "thumbnail_alt_value" - * ) */ +#[MediaSource( + id: "image", + label: new TranslatableMarkup("Image"), + description: new TranslatableMarkup("Use local images for reusable media."), + allowed_field_types: ["image"], + default_thumbnail_filename: "no-thumbnail.png", + thumbnail_alt_metadata_attribute: "thumbnail_alt_value" +)] class Image extends File { /** diff --git a/core/modules/media/src/Plugin/media/Source/OEmbed.php b/core/modules/media/src/Plugin/media/Source/OEmbed.php index 34b8581a1df2..671e1800c7f6 100644 --- a/core/modules/media/src/Plugin/media/Source/OEmbed.php +++ b/core/modules/media/src/Plugin/media/Source/OEmbed.php @@ -14,8 +14,10 @@ use Drupal\Core\File\FileSystemInterface; use Drupal\Core\Form\FormStateInterface; use Drupal\Core\Messenger\MessengerInterface; +use Drupal\Core\StringTranslation\TranslatableMarkup; use Drupal\Core\Url; use Drupal\Core\Utility\Token; +use Drupal\media\Attribute\OEmbedMediaSource; use Drupal\media\IFrameUrlHelper; use Drupal\media\OEmbed\Resource; use Drupal\media\OEmbed\ResourceException; @@ -65,17 +67,15 @@ * define a new class which extends it. With the code above, you will able to * create media types which use the "Artwork" source plugin, and use those media * types to link to assets on Deviantart and Flickr. - * - * @MediaSource( - * id = "oembed", - * label = @Translation("oEmbed source"), - * description = @Translation("Use oEmbed URL for reusable media."), - * allowed_field_types = {"string"}, - * default_thumbnail_filename = "no-thumbnail.png", - * deriver = "Drupal\media\Plugin\media\Source\OEmbedDeriver", - * providers = {}, - * ) */ +#[OEmbedMediaSource( + id: "oembed", + label: new TranslatableMarkup("oEmbed source"), + description: new TranslatableMarkup("Use oEmbed URL for reusable media."), + allowed_field_types: ["string"], + default_thumbnail_filename: "no-thumbnail.png", + deriver: OEmbedDeriver::class, +)] class OEmbed extends MediaSourceBase implements OEmbedInterface { /** diff --git a/core/modules/media/src/Plugin/media/Source/VideoFile.php b/core/modules/media/src/Plugin/media/Source/VideoFile.php index ebcf2f474a38..6c796e58ee37 100644 --- a/core/modules/media/src/Plugin/media/Source/VideoFile.php +++ b/core/modules/media/src/Plugin/media/Source/VideoFile.php @@ -3,21 +3,22 @@ namespace Drupal\media\Plugin\media\Source; use Drupal\Core\Entity\Display\EntityViewDisplayInterface; +use Drupal\Core\StringTranslation\TranslatableMarkup; +use Drupal\media\Attribute\MediaSource; use Drupal\media\MediaTypeInterface; /** * Media source wrapping around a video file. * * @see \Drupal\file\FileInterface - * - * @MediaSource( - * id = "video_file", - * label = @Translation("Video file"), - * description = @Translation("Use video files for reusable media."), - * allowed_field_types = {"file"}, - * default_thumbnail_filename = "video.png" - * ) */ +#[MediaSource( + id: "video_file", + label: new TranslatableMarkup("Video file"), + description: new TranslatableMarkup("Use video files for reusable media."), + allowed_field_types: ["file"], + default_thumbnail_filename: "video.png" +)] class VideoFile extends File { /** diff --git a/core/modules/media/tests/modules/media_test_source/src/Plugin/media/Source/Test.php b/core/modules/media/tests/modules/media_test_source/src/Plugin/media/Source/Test.php index b7baaa555781..3cf8a3e0e36c 100644 --- a/core/modules/media/tests/modules/media_test_source/src/Plugin/media/Source/Test.php +++ b/core/modules/media/tests/modules/media_test_source/src/Plugin/media/Source/Test.php @@ -4,19 +4,20 @@ use Drupal\Component\Utility\NestedArray; use Drupal\Core\Form\FormStateInterface; +use Drupal\Core\StringTranslation\TranslatableMarkup; +use Drupal\media\Attribute\MediaSource; use Drupal\media\MediaInterface; use Drupal\media\MediaSourceBase; /** * Provides test media source. - * - * @MediaSource( - * id = "test", - * label = @Translation("Test source"), - * description = @Translation("Test media source."), - * allowed_field_types = {"string"}, - * ) */ +#[MediaSource( + id: "test", + label: new TranslatableMarkup("Test source"), + description: new TranslatableMarkup("Test media source."), + allowed_field_types: ["string"] +)] class Test extends MediaSourceBase { /** diff --git a/core/modules/media/tests/modules/media_test_source/src/Plugin/media/Source/TestDifferentDisplays.php b/core/modules/media/tests/modules/media_test_source/src/Plugin/media/Source/TestDifferentDisplays.php index e2389f5301d4..61007c31c2ea 100644 --- a/core/modules/media/tests/modules/media_test_source/src/Plugin/media/Source/TestDifferentDisplays.php +++ b/core/modules/media/tests/modules/media_test_source/src/Plugin/media/Source/TestDifferentDisplays.php @@ -4,18 +4,19 @@ use Drupal\Core\Entity\Display\EntityFormDisplayInterface; use Drupal\Core\Entity\Display\EntityViewDisplayInterface; +use Drupal\Core\StringTranslation\TranslatableMarkup; +use Drupal\media\Attribute\MediaSource; use Drupal\media\MediaTypeInterface; /** * Provides test media source. - * - * @MediaSource( - * id = "test_different_displays", - * label = @Translation("Test source with different displays"), - * description = @Translation("Test source with different displays."), - * allowed_field_types = {"entity_reference"}, - * ) */ +#[MediaSource( + id: "test_different_displays", + label: new TranslatableMarkup("Test source with different displays"), + description: new TranslatableMarkup("Test source with different displays."), + allowed_field_types: ["entity_reference"] +)] class TestDifferentDisplays extends Test { /** diff --git a/core/modules/media/tests/modules/media_test_source/src/Plugin/media/Source/TestTranslation.php b/core/modules/media/tests/modules/media_test_source/src/Plugin/media/Source/TestTranslation.php index 947f06733b65..9565b724494b 100644 --- a/core/modules/media/tests/modules/media_test_source/src/Plugin/media/Source/TestTranslation.php +++ b/core/modules/media/tests/modules/media_test_source/src/Plugin/media/Source/TestTranslation.php @@ -2,19 +2,20 @@ namespace Drupal\media_test_source\Plugin\media\Source; +use Drupal\Core\StringTranslation\TranslatableMarkup; +use Drupal\media\Attribute\MediaSource; use Drupal\media\MediaInterface; /** * Provides test media source. - * - * @MediaSource( - * id = "test_translation", - * label = @Translation("Test source with translations"), - * description = @Translation("Test media source with translations."), - * allowed_field_types = {"string"}, - * thumbnail_alt_metadata_attribute = "test_thumbnail_alt", - * ) */ +#[MediaSource( + id: "test_translation", + label: new TranslatableMarkup("Test source with translations"), + description: new TranslatableMarkup("Test media source with translations."), + allowed_field_types: ["string"], + thumbnail_alt_metadata_attribute: "test_thumbnail_alt" +)] class TestTranslation extends Test { /** diff --git a/core/modules/media/tests/modules/media_test_source/src/Plugin/media/Source/TestWithConstraints.php b/core/modules/media/tests/modules/media_test_source/src/Plugin/media/Source/TestWithConstraints.php index 98039ca2d2a2..beb9b023e78d 100644 --- a/core/modules/media/tests/modules/media_test_source/src/Plugin/media/Source/TestWithConstraints.php +++ b/core/modules/media/tests/modules/media_test_source/src/Plugin/media/Source/TestWithConstraints.php @@ -2,19 +2,20 @@ namespace Drupal\media_test_source\Plugin\media\Source; +use Drupal\Core\StringTranslation\TranslatableMarkup; +use Drupal\media\Attribute\MediaSource; use Drupal\media\MediaSourceEntityConstraintsInterface; use Drupal\media\MediaSourceFieldConstraintsInterface; /** * Provides generic media type. - * - * @MediaSource( - * id = "test_constraints", - * label = @Translation("Test source with constraints"), - * description = @Translation("Test media source that provides constraints."), - * allowed_field_types = {"string_long"}, - * ) */ +#[MediaSource( + id: "test_constraints", + label: new TranslatableMarkup("Test source with constraints"), + description: new TranslatableMarkup("Test media source that provides constraints."), + allowed_field_types: ["string_long"], +)] class TestWithConstraints extends Test implements MediaSourceEntityConstraintsInterface, MediaSourceFieldConstraintsInterface { /** diff --git a/core/modules/media/tests/modules/media_test_source/src/Plugin/media/Source/TestWithHiddenSourceField.php b/core/modules/media/tests/modules/media_test_source/src/Plugin/media/Source/TestWithHiddenSourceField.php index e5ac525eb0e6..ac4754f2818f 100644 --- a/core/modules/media/tests/modules/media_test_source/src/Plugin/media/Source/TestWithHiddenSourceField.php +++ b/core/modules/media/tests/modules/media_test_source/src/Plugin/media/Source/TestWithHiddenSourceField.php @@ -4,18 +4,19 @@ use Drupal\Core\Entity\Display\EntityFormDisplayInterface; use Drupal\Core\Entity\Display\EntityViewDisplayInterface; +use Drupal\Core\StringTranslation\TranslatableMarkup; +use Drupal\media\Attribute\MediaSource; use Drupal\media\MediaTypeInterface; /** * Provides test media source. - * - * @MediaSource( - * id = "test_hidden_source_field", - * label = @Translation("Test source with hidden source field"), - * description = @Translation("Test media source with hidden source field."), - * allowed_field_types = {"string"}, - * ) */ +#[MediaSource( + id: "test_hidden_source_field", + label: new TranslatableMarkup("Test source with hidden source field"), + description: new TranslatableMarkup("Test media source with hidden source field."), + allowed_field_types: ["string"], +)] class TestWithHiddenSourceField extends Test { /** diff --git a/core/modules/media_library/media_library.api.php b/core/modules/media_library/media_library.api.php index 5c33600ff53f..4979fd1ae2e2 100644 --- a/core/modules/media_library/media_library.api.php +++ b/core/modules/media_library/media_library.api.php @@ -60,16 +60,15 @@ * source plugin definition which provides an add form for the media library: * * @code - * @MediaSource( - * id = "file", - * label = @Translation("File"), - * description = @Translation("Use local files for reusable media."), - * allowed_field_types = {"file"}, - * default_thumbnail_filename = "generic.png", - * forms = { - * "media_library_add" = "\Drupal\media_library\Form\FileUploadForm", - * }, - * ) + * #[MediaSource( + * id: "file", + * label: new TranslatableMarkup("File"), + * description: new TranslatableMarkup("Use local files for reusable media."), + * allowed_field_types: ["file"], + * forms = [ + * "media_library_add" => "\Drupal\media_library\Form\FileUploadForm", + * ] + * )] * @endcode * * This can also be done in hook_media_source_info_alter(). For example: -- GitLab