diff --git a/lib/MusicBrainz/Server/Data/URL.pm b/lib/MusicBrainz/Server/Data/URL.pm index 74d2a90c524..a7fbd7c94df 100644 --- a/lib/MusicBrainz/Server/Data/URL.pm +++ b/lib/MusicBrainz/Server/Data/URL.pm @@ -144,6 +144,7 @@ my %URL_SPECIALIZATIONS = ( 'Muziekweb' => qr{^https?://www\.muziekweb\.nl/}i, 'Muzikum' => qr{^https?://(?:www\.)?muzikum\.eu/}i, 'MVDbase' => qr{^https?://(?:www\.)?mvdbase\.com/}i, + 'MyAnimeList' => qr{^https?://(?:www\.)?myanimelist\.net/}i, 'MySpace' => qr{^https?://(?:www\.)?myspace\.com/}i, 'Napster' => qr{^https?://[\w-]{2}\.napster\.com/}i, 'NDL' => qr{^https?://(?:www\.)?iss\.ndl\.go\.jp/}i, diff --git a/lib/MusicBrainz/Server/Entity/URL/MyAnimeList.pm b/lib/MusicBrainz/Server/Entity/URL/MyAnimeList.pm new file mode 100644 index 00000000000..a76d0b155f8 --- /dev/null +++ b/lib/MusicBrainz/Server/Entity/URL/MyAnimeList.pm @@ -0,0 +1,22 @@ +package MusicBrainz::Server::Entity::URL::MyAnimeList; + +use Moose; + +extends 'MusicBrainz::Server::Entity::URL'; +with 'MusicBrainz::Server::Entity::URL::Sidebar'; + +sub sidebar_name { 'MyAnimeList' } + +__PACKAGE__->meta->make_immutable; +no Moose; +1; + +=head1 COPYRIGHT AND LICENSE + +Copyright (C) 2026 MetaBrainz Foundation + +This file is part of MusicBrainz, the open internet music database, +and is licensed under the GPL version 2, or (at your option) any +later version: http://www.gnu.org/licenses/gpl-2.0.txt + +=cut diff --git a/root/static/images/external-favicons/myanimelist-32.png b/root/static/images/external-favicons/myanimelist-32.png new file mode 100644 index 00000000000..40bfbed8db8 Binary files /dev/null and b/root/static/images/external-favicons/myanimelist-32.png differ diff --git a/root/static/scripts/common/constants.js b/root/static/scripts/common/constants.js index b9fa14195de..be5dc622e55 100644 --- a/root/static/scripts/common/constants.js +++ b/root/static/scripts/common/constants.js @@ -190,6 +190,7 @@ export const FAVICON_CLASSES: { 'musopen.org': 'musopen', 'muziekweb.nl': 'muziekweb', 'muzikum.eu': 'muzikum', + 'myanimelist.net': 'myanimelist', 'myspace.com': 'myspace', 'napster.com': 'napster', 'nicovideo.jp': 'niconicovideo', diff --git a/root/static/scripts/edit/URLCleanup.js b/root/static/scripts/edit/URLCleanup.js index 1c25376d670..15da5f9cf12 100644 --- a/root/static/scripts/edit/URLCleanup.js +++ b/root/static/scripts/edit/URLCleanup.js @@ -4676,6 +4676,34 @@ export const CLEANUPS: CleanupEntries = { return {result: false, target: ERROR_TARGETS.URL}; }, }, + 'myanimelist': { + hostname: 'myanimelist.net', + match: [/^(?:https?:\/\/)?(?:www\.)?myanimelist\.net/i], + restrict: [LINK_TYPES.otherdatabases], + clean(url) { + return url.replace(/^(?:https?:\/\/)?(?:www\.)?myanimelist\.net\/(people|character|anime\/producer)\/(\d+).*$/, 'https://myanimelist.net/$1/$2'); + }, + validate(url, id) { + const m = /^https:\/\/myanimelist\.net\/(people|character|anime\/producer)\/(\d+)$/.exec(url); + if (m) { + const prefix = m[1]; + switch (id) { + case LINK_TYPES.otherdatabases.artist: + return { + result: prefix === 'people' || prefix === 'character', + target: ERROR_TARGETS.ENTITY, + }; + case LINK_TYPES.otherdatabases.label: + return { + result: prefix === 'anime/producer', + target: ERROR_TARGETS.ENTITY, + }; + } + return {result: false, target: ERROR_TARGETS.RELATIONSHIP}; + } + return {result: false, target: ERROR_TARGETS.URL}; + }, + }, 'myspace': { hostname: ['myspace.com', 'myspace.de', 'myspace.fr'], match: [/^(https?:\/\/)?([^/]+\.)?myspace\.(com|de|fr)/i], diff --git a/root/static/scripts/tests/Control/URLCleanup.js b/root/static/scripts/tests/Control/URLCleanup.js index 2e4cfd62189..159f4f3dc44 100644 --- a/root/static/scripts/tests/Control/URLCleanup.js +++ b/root/static/scripts/tests/Control/URLCleanup.js @@ -4625,6 +4625,28 @@ limited_link_type_combinations: [ input_entity_type: 'recording', expected_relationship_type: 'otherdatabases', }, + // MyAnimeList + { + input_url: 'https://myanimelist.net/people/185/Kana_Hanazawa', + input_entity_type: 'artist', + expected_relationship_type: 'otherdatabases', + expected_clean_url: 'https://myanimelist.net/people/185', + only_valid_entity_types: ['artist'], + }, + { + input_url: 'https://myanimelist.net/character/40/Luffy_Monkey_D/clubs', + input_entity_type: 'artist', + expected_relationship_type: 'otherdatabases', + expected_clean_url: 'https://myanimelist.net/character/40', + only_valid_entity_types: ['artist'], + }, + { + input_url: 'https://myanimelist.net/anime/producer/1696/Kadokawa', + input_entity_type: 'label', + expected_relationship_type: 'otherdatabases', + expected_clean_url: 'https://myanimelist.net/anime/producer/1696', + only_valid_entity_types: ['label'], + }, // Myspace { input_url: 'https://myspace.com/instramentaluk', diff --git a/root/static/styles/favicons.less b/root/static/styles/favicons.less index 31718bb3491..c5cec61ed72 100644 --- a/root/static/styles/favicons.less +++ b/root/static/styles/favicons.less @@ -127,6 +127,7 @@ .favicon("musopen", 32); .favicon("muziekweb", 32); .favicon("muzikum", 32); +.favicon("myanimelist", 32); .favicon("myspace", 32); .favicon("napster", 32); .favicon("ndl");