discord-portable-player
Version:
Easy to use, framework to facilitate music commands using discord.js
229 lines (228 loc) • 8.13 kB
JavaScript
;
Object.defineProperty(exports, "__esModule", { value: true });
exports.makeData = exports.getRawPlaylist = exports.getRawAlbum = exports.search = exports.linkType = void 0;
const tslib_1 = require("tslib");
const axios_1 = tslib_1.__importDefault(require("axios"));
const cheerio_1 = tslib_1.__importDefault(require("cheerio"));
const youtube_sr_1 = tslib_1.__importDefault(require("youtube-sr"));
function getRawPlaylist(document) {
const $ = cheerio_1.default.load(document);
const tracks = [];
const songList = $("div.songs-list-row").toArray();
songList.forEach((song) => {
const lookArtist = $(song).find("div.songs-list__col--artist").find("a.songs-list-row__link");
const track = {
author: {
name: lookArtist.text(),
url: lookArtist.attr("href") ?? ""
},
title: $(song).find("div.songs-list__col--song").find("div.songs-list-row__song-name").text(),
duration: $(song)
.find("div.songs-list__col--time")
.find("time")
.text()
.trim()
.split(":")
.map((value) => Number(value))
.reduce((acc, time) => 60 * acc + time),
url: $(song).find("div.songs-list__col--album").find("a.songs-list-row__link").attr("href") ?? "",
type: "song"
};
tracks.push(track);
});
const product = $("div.product-page-header");
const creator = product.find("div.product-creator").find("a.dt-link-to");
const playlist = {
title: product.find("h1.product-name").text().trim(),
description: product.find("div.product-page-header__metadata--notes").text().trim(),
creator: {
name: creator.text().trim(),
url: "https://music.apple.com" + creator.attr("href") ?? ""
},
tracks,
numTracks: tracks.length,
type: "playlist",
thumbnail: $("meta[property='og:image']").attr("content") ?? ""
};
return playlist;
}
exports.getRawPlaylist = getRawPlaylist;
function getRawAlbum(document) {
const $ = cheerio_1.default.load(document);
const tracks = [];
const product = $("div.product-page-header");
const creator = product.find("div.product-creator").find("a.dt-link-to");
const author = {
name: creator.text().trim(),
url: creator.attr("href") ?? ""
};
const albumUrl = $("meta[property='og:url']").attr("content");
const songList = $("div.songs-list-row").toArray();
songList.forEach((song) => {
const track = {
author,
title: $(song).find("div.songs-list__col--song").find("div.songs-list-row__song-name").text(),
duration: $(song)
.find("div.songs-list__col--time")
.find("time")
.text()
.trim()
.split(":")
.map((value) => Number(value))
.reduce((acc, time) => 60 * acc + time),
url: albumUrl
? albumUrl + "?i=" + JSON.parse($(song).find("div.songs-list__col--time").find("button.preview-button").attr("data-metrics-click") ?? "{ targetId: 0 }")["targetId"] ?? ""
: "",
type: "song"
};
tracks.push(track);
});
const playlist = {
title: product.find("h1.product-name").text().trim(),
description: product.find("div.product-page-header__metadata--notes").text().trim(),
author,
tracks,
numTracks: tracks.length,
type: "album",
thumbnail: $("meta[property='og:image']").attr("content") ?? ""
};
return playlist;
}
exports.getRawAlbum = getRawAlbum;
function linkType(url) {
if (RegExp(/https?:\/\/music\.apple\.com\/.+?\/album\/.+?\/.+?\?i=([0-9]+)/).test(url)) {
return "song";
}
else if (RegExp(/https?:\/\/music\.apple\.com\/.+?\/playlist\//).test(url)) {
return "playlist";
}
else if (RegExp(/https?:\/\/music\.apple\.com\/.+?\/album\//).test(url)) {
return "album";
}
else {
return false;
}
}
exports.linkType = linkType;
async function search(url) {
const urlType = linkType(url);
const page = await axios_1.default
.get(url)
.then((res) => res.data)
.catch(() => undefined);
if (!page) {
return null;
}
if (urlType === "playlist") {
return getRawPlaylist(page);
}
const album = getRawAlbum(page);
if (urlType === "album") {
return album;
}
const match = new RegExp(/https?:\/\/music\.apple\.com\/.+?\/album\/.+?\/.+?\?i=([0-9]+)/).exec(url);
const id = match ? match[1] : undefined;
if (!id) {
return null;
}
const track = album.tracks.find((track) => {
return track.url.includes(`?i=${id}`);
});
if (!track) {
return null;
}
return track;
}
exports.search = search;
async function makeData(query) {
const music_data = await search(query);
if (music_data.type === "song") {
const videos = await youtube_sr_1.default.search(music_data.title, {
type: "video"
});
if (!videos)
return null;
const info = {
data: [
{
title: music_data.title,
duration: videos[0].duration,
thumbnail: videos[0].thumbnail.url,
engine: "youtube",
views: 0,
author: music_data.author.name,
description: videos[0].description,
url: videos[0].url,
source: "applemusic"
}
]
};
return {
playlist: null,
data: info.data?.map((m) => ({
title: m.title,
duration: m.duration,
thumbnail: m.thumbnail,
engine: m.engine,
views: m.views,
author: m.author,
description: m.description,
url: m.url,
source: m.source
})) ?? []
};
}
// eslint-disable-next-line no-constant-condition
if (music_data.type === "playlist" || "album") {
const info = {
data: [],
playlist: {
title: music_data.title,
description: music_data.description,
thumbnail: "",
source: "applemusic",
url: query,
id: "",
type: music_data.type === "playlist" ? "playlist" : "album",
author: {
name: music_data.type === "playlist" ? music_data.creator.name : music_data.author.name,
url: music_data.type === "playlist" ? music_data.creator.url : music_data.author.url
}
}
};
for (const m of music_data.tracks) {
const videos = await youtube_sr_1.default.search(m.title, {
type: "video"
});
if (!videos)
return null;
const data = {
title: videos[0].title,
duration: videos[0].duration,
thumbnail: videos[0].thumbnail.url,
engine: "youtube",
views: 0,
author: videos[0].channel.name,
description: videos[0].description,
url: videos[0].url,
source: "applemusic"
};
info.data.push(data);
}
return {
playlist: info.playlist,
data: info.data?.map((m) => ({
title: m.title,
duration: m.duration,
thumbnail: m.thumbnail,
engine: m.engine,
views: m.views,
author: m.author,
description: m.description,
url: m.url,
source: m.source
})) ?? []
};
}
}
exports.makeData = makeData;