social-link-parser
Version:
Extract usernames, IDs, and metadata from social media URLs across 100+ platforms
138 lines • 5.86 kB
JavaScript
import { Platforms } from '../../core/types.js';
import { normalize, getUrlSafe } from '../../utils/url.js';
import { QUERY_HASH } from '../../utils/constants.js';
function getAppleMusicEmbedUrl(hostname, link) {
const url = new URL(link);
url.hostname = hostname;
url.searchParams.set('theme', 'auto');
return url.toString();
}
const domains = [
'music.apple.com',
'embed.music.apple.com',
'podcasts.apple.com',
'embed.podcasts.apple.com',
];
const MUSIC_DOMAIN_PATTERN = '^https?://(?:www\\.)?(?:embed\\.)?music\\.apple\\.com';
const PODCASTS_DOMAIN_PATTERN = '^https?://(?:www\\.)?(?:embed\\.)?podcasts\\.apple\\.com';
const LOCALE_GROUP = '(?:(?<locale>[a-z]{2}(?:-[a-z]{2})?)\/)?';
const NAME_GROUP = '(?<name>[^\/]+)';
export const applemusic = {
id: Platforms.AppleMusic,
name: 'Apple Music',
color: '#fa243c',
domains: domains,
domainsRegexp: new RegExp(`^(?:https?://)?(?:www\\.)?(?:(?:music|podcasts)\\.apple\\.com|embed\\.(?:music\\.|podcasts\\.)?apple\\.com)`, 'i'),
patterns: {
profile: new RegExp(`^https?://(music|podcasts)\\.apple\\.com/(?:(\w{2})/)?(album|artist|playlist|song|station|podcast)/[^/]+/([a-zA-Z0-9.-]+)/?${QUERY_HASH}$`, 'i'),
handle: /^\d+$/,
content: {
playlist: new RegExp(`${MUSIC_DOMAIN_PATTERN}\\/${LOCALE_GROUP}playlist\\/${NAME_GROUP}\\/(?<playlistId>[a-zA-Z0-9.-]+)(?:\\?.*)?$`, 'i'),
artist: new RegExp(`${MUSIC_DOMAIN_PATTERN}\\/${LOCALE_GROUP}artist\\/${NAME_GROUP}\\/(?<artistId>\\d+)(?:\\?.*)?$`, 'i'),
station: new RegExp(`${MUSIC_DOMAIN_PATTERN}\\/${LOCALE_GROUP}station\\/${NAME_GROUP}\\/(?<stationId>[a-zA-Z0-9.-]+)(?:\\?.*)?$`, 'i'),
podcastEpisode: new RegExp(`${PODCASTS_DOMAIN_PATTERN}\\/${LOCALE_GROUP}podcast\\/${NAME_GROUP}\\/id(?<podcastId>\\d+)\\?.*i=(?<episodeId>\\d+).*$`, 'i'),
podcast: new RegExp(`${PODCASTS_DOMAIN_PATTERN}\\/${LOCALE_GROUP}podcast\\/${NAME_GROUP}\\/id(?<podcastId>\\d+)(?:\\?.*)?$`, 'i'),
song: new RegExp(`${MUSIC_DOMAIN_PATTERN}\\/${LOCALE_GROUP}song\\/${NAME_GROUP}\\/(?<songId>\\d+)(?:\\?.*)?$`, 'i'),
track: new RegExp(`${MUSIC_DOMAIN_PATTERN}\\/${LOCALE_GROUP}album\\/${NAME_GROUP}\\/(?<albumId>\\d+)\\?.*i=(?<trackId>\\d+).*$`, 'i'),
album: new RegExp(`${MUSIC_DOMAIN_PATTERN}\\/${LOCALE_GROUP}album\\/${NAME_GROUP}\\/(?<albumId>\\d+)(?:\\?.*)?$`, 'i')
}
},
detect(url) {
return this.domainsRegexp.test(url);
},
extract(url, res) {
const urlObj = getUrlSafe(url);
if (!urlObj)
return;
const contentPatterns = this.patterns.content;
if (!contentPatterns)
return;
let matchResult = null;
for (const [contentType, pattern] of Object.entries(contentPatterns)) {
if (!pattern)
continue;
const match = urlObj.href.match(pattern);
if (match && match.groups) {
matchResult = { contentType, match };
break;
}
}
if (!matchResult)
return;
const { contentType, match } = matchResult;
const groups = match.groups;
res.metadata.contentType = contentType;
if (groups.locale) {
res.metadata.locale = groups.locale;
}
switch (contentType) {
case 'artist':
res.ids.artistId = groups.artistId;
res.metadata.isProfile = true;
break;
case 'album':
res.ids.albumId = groups.albumId;
res.metadata.isAlbum = true;
break;
case 'playlist':
res.ids.playlistId = groups.playlistId;
res.metadata.isPlaylist = true;
break;
case 'song':
res.ids.songId = groups.songId;
res.metadata.isSong = true;
break;
case 'track':
res.ids.albumId = groups.albumId;
res.ids.trackId = groups.trackId;
res.metadata.isTrack = true;
break;
case 'station':
res.ids.stationId = groups.stationId;
res.metadata.isStation = true;
break;
case 'podcast':
res.ids.podcastId = groups.podcastId;
res.metadata.isPodcast = true;
break;
case 'podcastEpisode':
res.ids.podcastId = groups.podcastId;
res.ids.episodeId = groups.episodeId;
res.metadata.isPodcastEpisode = true;
break;
}
res.metadata.domain = urlObj.hostname;
},
validateHandle(handle) {
return this.patterns.handle.test(handle);
},
buildProfileUrl(artistId) {
return `https://music.apple.com/us/artist/id${artistId}`;
},
normalizeUrl(url) {
return normalize(url);
},
getEmbedInfo(url) {
if (url.includes('embed.music.apple.com') || url.includes('embed.podcasts.apple.com')) {
return { embedUrl: url, isEmbedAlready: true };
}
const result = {
isValid: false,
originalUrl: url,
normalizedUrl: url,
platform: null,
ids: {},
metadata: {}
};
this.extract(url, result);
if (!result.metadata.contentType) {
return null;
}
const targetDomain = (result.metadata.contentType === 'podcast' || result.metadata.contentType === 'podcastEpisode')
? 'embed.podcasts.apple.com'
: 'embed.music.apple.com';
const embedUrl = getAppleMusicEmbedUrl(targetDomain, url);
return { embedUrl, type: 'iframe' };
}
};
//# sourceMappingURL=index.js.map