diff --git a/lib/MusicBrainz/Server/Data/URL.pm b/lib/MusicBrainz/Server/Data/URL.pm index 74d2a90c524..852f5fcea43 100644 --- a/lib/MusicBrainz/Server/Data/URL.pm +++ b/lib/MusicBrainz/Server/Data/URL.pm @@ -27,6 +27,7 @@ my %URL_SPECIALIZATIONS = ( 'AmazonMusic' => qr{^https:\/\/music\.amazon\.(?:ae|at|com\.au|com\.br|ca|cn|com|de|es|fr|in|it|jp|co\.jp|com\.mx|nl|pl|se|sg|com\.tr|co\.uk)/}i, 'Anghami' => qr{^https?://([^/]+\.)?anghami\.com/}i, 'AniDB' => qr{^https?://(?:www\.)?anidb\.net/}i, + 'AniList' => qr{^https?://(?:www\.)?anilist\.co/}i, 'AnimeNewsNetwork' => qr{^https?://(?:www\.)?animenewsnetwork\.com/}i, 'AnisonGeneration' => qr{^https?://anison\.info/}i, 'AppleBooks' => qr{^https?://books\.apple\.com/}i, diff --git a/lib/MusicBrainz/Server/Entity/URL/AniList.pm b/lib/MusicBrainz/Server/Entity/URL/AniList.pm new file mode 100644 index 00000000000..7aff19ecbd8 --- /dev/null +++ b/lib/MusicBrainz/Server/Entity/URL/AniList.pm @@ -0,0 +1,22 @@ +package MusicBrainz::Server::Entity::URL::AniList; + +use Moose; + +extends 'MusicBrainz::Server::Entity::URL'; +with 'MusicBrainz::Server::Entity::URL::Sidebar'; + +sub sidebar_name { 'AniList' } + +__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/anilist-32.png b/root/static/images/external-favicons/anilist-32.png new file mode 100644 index 00000000000..11f68dd4da1 Binary files /dev/null and b/root/static/images/external-favicons/anilist-32.png differ diff --git a/root/static/scripts/common/constants.js b/root/static/scripts/common/constants.js index b9fa14195de..1ca784e1a26 100644 --- a/root/static/scripts/common/constants.js +++ b/root/static/scripts/common/constants.js @@ -83,6 +83,7 @@ export const FAVICON_CLASSES: { 'allmusic.com': 'allmusic', 'anghami.com': 'anghami', 'anidb.net': 'anidb', + 'anilist.co': 'anilist', 'animenewsnetwork.com': 'animenewsnetwork', 'anison.info': 'anisongeneration', 'archive.org': 'archive', diff --git a/root/static/scripts/edit/URLCleanup.js b/root/static/scripts/edit/URLCleanup.js index 1c25376d670..3f2f5a2a128 100644 --- a/root/static/scripts/edit/URLCleanup.js +++ b/root/static/scripts/edit/URLCleanup.js @@ -857,6 +857,34 @@ export const CLEANUPS: CleanupEntries = { return {result: false, target: ERROR_TARGETS.URL}; }, }, + 'anilist': { + hostname: 'anilist.co', + match: [/^(?:https?:\/\/)?(?:www\.)?anilist\.co/i], + restrict: [LINK_TYPES.otherdatabases], + clean(url) { + return url.replace(/^(?:https?:\/\/)?(?:www\.)?anilist\.co\/(staff|character|studio)\/(\d+).*$/, 'https://anilist.co/$1/$2'); + }, + validate(url, id) { + const m = /^https:\/\/anilist\.co\/(staff|character|studio)\/(\d+)$/.exec(url); + if (m) { + const prefix = m[1]; + switch (id) { + case LINK_TYPES.otherdatabases.artist: + return { + result: prefix === 'staff' || prefix === 'character', + target: ERROR_TARGETS.ENTITY, + }; + case LINK_TYPES.otherdatabases.label: + return { + result: prefix === 'studio', + target: ERROR_TARGETS.ENTITY, + }; + } + return {result: false, target: ERROR_TARGETS.RELATIONSHIP}; + } + return {result: false, target: ERROR_TARGETS.URL}; + }, + }, 'animenewsnetwork': { hostname: 'animenewsnetwork.com', match: [/^(https?:\/\/)?(www\.)?animenewsnetwork\.com/i], diff --git a/root/static/scripts/tests/Control/URLCleanup.js b/root/static/scripts/tests/Control/URLCleanup.js index 2e4cfd62189..71d6f35b2d0 100644 --- a/root/static/scripts/tests/Control/URLCleanup.js +++ b/root/static/scripts/tests/Control/URLCleanup.js @@ -651,6 +651,28 @@ const testData = [ expected_clean_url: 'https://anidb.net/collection/4451', only_valid_entity_types: ['release'], }, + // AniList + { + input_url: 'https://anilist.co/staff/95185/Kana-Hanazawa?hello&world', + input_entity_type: 'artist', + expected_relationship_type: 'otherdatabases', + expected_clean_url: 'https://anilist.co/staff/95185', + only_valid_entity_types: ['artist'], + }, + { + input_url: 'https://anilist.co/character/40/Luffy-D-Monkey?hello#world', + input_entity_type: 'artist', + expected_relationship_type: 'otherdatabases', + expected_clean_url: 'https://anilist.co/character/40', + only_valid_entity_types: ['artist'], + }, + { + input_url: 'https://anilist.co/studio/6698/KADOKAWA?hello#world', + input_entity_type: 'label', + expected_relationship_type: 'otherdatabases', + expected_clean_url: 'https://anilist.co/studio/6698', + only_valid_entity_types: ['label'], + }, // Anime News Network { input_url: 'https://animenewsnetwork.com/encyclopedia/people.php?id=59062', diff --git a/root/static/styles/favicons.less b/root/static/styles/favicons.less index 31718bb3491..00fbdad0cf7 100644 --- a/root/static/styles/favicons.less +++ b/root/static/styles/favicons.less @@ -21,6 +21,7 @@ .favicon("amazonmusic", 32); .favicon("anghami", 32); .favicon("anidb", 32); +.favicon("anilist", 32); .favicon("animenewsnetwork"); .favicon("anisongeneration"); .favicon("applebooks", 32);