Make deezify not pick up garbage albums
This commit is contained in:
parent
a2cc4c7793
commit
6ca31b2916
1 changed files with 66 additions and 41 deletions
103
src/deezify.js
103
src/deezify.js
|
|
@ -1,14 +1,12 @@
|
||||||
import fs from "fs";
|
import fs from "fs";
|
||||||
import path from "path";
|
import path from "path";
|
||||||
import crypto from "crypto"
|
import crypto from "crypto";
|
||||||
|
|
||||||
const CACHE_DIR = "./deezer_cache";
|
const CACHE_DIR = "./deezer_cache";
|
||||||
fs.mkdirSync(CACHE_DIR, { recursive: true });
|
fs.mkdirSync(CACHE_DIR, { recursive: true });
|
||||||
|
|
||||||
const artists = [
|
const artists = [];
|
||||||
];
|
const album_links = [];
|
||||||
const album_links = [
|
|
||||||
]
|
|
||||||
const BAD_KEYWORDS = [
|
const BAD_KEYWORDS = [
|
||||||
" remix",
|
" remix",
|
||||||
"remix ",
|
"remix ",
|
||||||
|
|
@ -22,7 +20,8 @@ const BAD_KEYWORDS = [
|
||||||
"anniversary",
|
"anniversary",
|
||||||
"(remixes)",
|
"(remixes)",
|
||||||
"(remix)",
|
"(remix)",
|
||||||
"(acustic)"
|
"(acustic)",
|
||||||
|
"mixes",
|
||||||
];
|
];
|
||||||
|
|
||||||
function normalize(str) {
|
function normalize(str) {
|
||||||
|
|
@ -31,8 +30,9 @@ function normalize(str) {
|
||||||
|
|
||||||
function hasBadKeyword(title) {
|
function hasBadKeyword(title) {
|
||||||
const t = normalize(title);
|
const t = normalize(title);
|
||||||
return BAD_KEYWORDS.some(k => t.includes(k));
|
return BAD_KEYWORDS.some((k) => t.includes(k));
|
||||||
}
|
}
|
||||||
|
|
||||||
function cachePath(url) {
|
function cachePath(url) {
|
||||||
const hash = crypto.createHash("sha1").update(url).digest("hex");
|
const hash = crypto.createHash("sha1").update(url).digest("hex");
|
||||||
return path.join(CACHE_DIR, `${hash}.json`);
|
return path.join(CACHE_DIR, `${hash}.json`);
|
||||||
|
|
@ -53,13 +53,9 @@ async function cachedFetch(url) {
|
||||||
return json;
|
return json;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
async function getArtistId(name) {
|
async function getArtistId(name) {
|
||||||
const q = encodeURIComponent(name);
|
const q = encodeURIComponent(name);
|
||||||
const data = await cachedFetch(
|
const data = await cachedFetch(`https://api.deezer.com/search/artist?q=${q}`);
|
||||||
`https://api.deezer.com/search/artist?q=${q}`
|
|
||||||
);
|
|
||||||
|
|
||||||
return data?.data?.[0]?.id ?? null;
|
return data?.data?.[0]?.id ?? null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -75,63 +71,84 @@ async function getAllAlbums(artistId) {
|
||||||
|
|
||||||
return out;
|
return out;
|
||||||
}
|
}
|
||||||
|
|
||||||
async function getAlbum(albumId) {
|
async function getAlbum(albumId) {
|
||||||
const url = `https://api.deezer.com/album/${albumId}`;
|
const url = `https://api.deezer.com/album/${albumId}`;
|
||||||
return await cachedFetch(url);
|
return await cachedFetch(url);
|
||||||
}
|
}
|
||||||
function selectBestAlbumVersions(albums) {
|
|
||||||
const byTitle = new Map();
|
|
||||||
|
|
||||||
for (const a of albums) {
|
async function selectUniqueReleases(albums) {
|
||||||
if (hasBadKeyword(a.title)) continue;
|
const seenTracks = new Set();
|
||||||
|
const finalReleases = [];
|
||||||
|
|
||||||
const key = normalize(a.title.replace(/\s*\(.*?\)\s*/g, ""));
|
const albumsOnly = albums.filter(
|
||||||
|
(a) => a.record_type === "album" && !hasBadKeyword(a.title),
|
||||||
|
);
|
||||||
|
const singlesEPs = albums.filter(
|
||||||
|
(a) =>
|
||||||
|
(a.record_type === "single" || a.record_type === "ep") &&
|
||||||
|
!hasBadKeyword(a.title),
|
||||||
|
);
|
||||||
|
|
||||||
if (!byTitle.has(key)) {
|
for (const a of albumsOnly) {
|
||||||
byTitle.set(key, a);
|
const fullAlbum = await getAlbum(a.id);
|
||||||
continue;
|
const tracks = (fullAlbum.tracks?.data ?? []).map((t) =>
|
||||||
|
normalize(t.title),
|
||||||
|
);
|
||||||
|
|
||||||
|
if (tracks.every((t) => seenTracks.has(t))) continue;
|
||||||
|
tracks.forEach((t) => seenTracks.add(t));
|
||||||
|
finalReleases.push(fullAlbum);
|
||||||
}
|
}
|
||||||
|
|
||||||
const existing = byTitle.get(key);
|
for (const s of singlesEPs) {
|
||||||
|
const fullSingle = await getAlbum(s.id);
|
||||||
|
const tracks = (fullSingle.tracks?.data ?? []).map((t) =>
|
||||||
|
normalize(t.title),
|
||||||
|
);
|
||||||
|
|
||||||
// Prefer explicit
|
if (tracks.every((t) => seenTracks.has(t))) continue;
|
||||||
if (!existing.explicit_lyrics && a.explicit_lyrics) {
|
tracks.forEach((t) => seenTracks.add(t));
|
||||||
byTitle.set(key, a);
|
finalReleases.push(fullSingle);
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return [...byTitle.values()];
|
return finalReleases;
|
||||||
}
|
}
|
||||||
|
|
||||||
(async () => {
|
(async () => {
|
||||||
const links = [];
|
const links = [];
|
||||||
const displays = []
|
const displays = [];
|
||||||
const album_links_raw = await Promise.all(album_links.map(async z => await getAlbum(z.replace(/[^\d]*(\d*)$/gm, "$1"))));
|
const album_links_raw = await Promise.all(
|
||||||
|
album_links.map(
|
||||||
|
async (z) => await getAlbum(z.replace(/[^\d]*(\d*)$/gm, "$1")),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
|
||||||
for (const artist of artists) {
|
for (const artist of artists) {
|
||||||
console.log(`\n=== ${artist} ===`);
|
console.log(`\n=== ${artist} ===`);
|
||||||
|
|
||||||
const artistId = typeof artist == "number" ? artist : await getArtistId(artist);
|
const artistId =
|
||||||
|
typeof artist === "number" ? artist : await getArtistId(artist);
|
||||||
if (!artistId) {
|
if (!artistId) {
|
||||||
console.log("Artist not found");
|
console.log("Artist not found");
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
const albums = (await getAllAlbums(artistId));
|
const albums = await getAllAlbums(artistId);
|
||||||
|
const cleanAlbums = await selectUniqueReleases(albums);
|
||||||
|
|
||||||
const cleanAlbums = selectBestAlbumVersions(albums);
|
|
||||||
let artistLines = [];
|
let artistLines = [];
|
||||||
let extraCount = 0;
|
let extraCount = 0;
|
||||||
|
|
||||||
for (const a of cleanAlbums) {
|
for (const a of cleanAlbums) {
|
||||||
console.log(
|
console.log(
|
||||||
`${a.title} | ${a.explicit_lyrics ? "EXPLICIT" : "CLEAN"} | https://www.deezer.com/en/album/${a.id}`
|
`${a.title} | ${a.explicit_lyrics ? "EXPLICIT" : "CLEAN"} | https://www.deezer.com/en/album/${a.id}`,
|
||||||
);
|
);
|
||||||
|
|
||||||
links.push(`https://www.deezer.com/en/album/${a.id}`);
|
links.push(`https://www.deezer.com/en/album/${a.id}`);
|
||||||
if (artistLines.length < 100) {
|
if (artistLines.length < 100) {
|
||||||
artistLines.push(
|
artistLines.push(
|
||||||
`+ ${typeof artist == "number" ? `No name (${artist})` : artist} - ${a.title} ${a.explicit_lyrics ? "[E]" : ""}`
|
`+ ${typeof artist === "number" ? `No name (${artist})` : artist} - ${a.title} ${a.explicit_lyrics ? "[E]" : ""}`,
|
||||||
);
|
);
|
||||||
} else {
|
} else {
|
||||||
extraCount++;
|
extraCount++;
|
||||||
|
|
@ -144,16 +161,24 @@ function selectBestAlbumVersions(albums) {
|
||||||
|
|
||||||
displays.push(...artistLines);
|
displays.push(...artistLines);
|
||||||
}
|
}
|
||||||
album_links_raw.forEach(z => {
|
|
||||||
|
album_links_raw.forEach((z) => {
|
||||||
links.push(`https://www.deezer.com/en/album/${z.id}`);
|
links.push(`https://www.deezer.com/en/album/${z.id}`);
|
||||||
displays.push(
|
displays.push(
|
||||||
`+ ${z.artist.name} - ${z.title} ${z.explicit_lyrics ? "[E]" : ""}`
|
`+ ${z.artist.name} - ${z.title} ${z.explicit_lyrics ? "[E]" : ""}`,
|
||||||
);
|
);
|
||||||
})
|
});
|
||||||
fs.writeFileSync("orpheus_links.txt", links.join(" "))
|
|
||||||
fs.writeFileSync("discord_send.txt", displays.join(" \n").match(/.{1,2000}$/gms).map(z => z.trim()).join("\n\n"+'-'.repeat(15)+"\n\n"))
|
|
||||||
|
|
||||||
})().catch(err => {
|
fs.writeFileSync("orpheus_links.txt", links.join(" "));
|
||||||
|
fs.writeFileSync(
|
||||||
|
"discord_send.txt",
|
||||||
|
displays
|
||||||
|
.join(" \n")
|
||||||
|
.match(/.{1,2000}$/gms)
|
||||||
|
.map((z) => z.trim())
|
||||||
|
.join("\n\n" + "-".repeat(15) + "\n\n"),
|
||||||
|
);
|
||||||
|
})().catch((err) => {
|
||||||
console.error(err);
|
console.error(err);
|
||||||
process.exit(1);
|
process.exit(1);
|
||||||
});
|
});
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue