add new-releases (cursed ass script)
This commit is contained in:
parent
bf09f00d45
commit
823af0c65f
3 changed files with 153 additions and 1 deletions
3
.gitignore
vendored
3
.gitignore
vendored
|
|
@ -2,5 +2,8 @@
|
|||
deezer_cache
|
||||
orpheus_links.txt
|
||||
discord_send.txt
|
||||
new_releases.json
|
||||
state.json
|
||||
node_modules
|
||||
fixcache.js
|
||||
new-releases-reparser.js
|
||||
|
|
|
|||
|
|
@ -10,7 +10,8 @@
|
|||
"request-bot": "bun run src/request-bot.js",
|
||||
"pillow": "bun run src/pillow.js",
|
||||
"sendgb": "bun run src/sendgb.js",
|
||||
"uamal": "bun run src/unambigious-artist-lookup.js"
|
||||
"uamal": "bun run src/unambigious-artist-lookup.js",
|
||||
"new-releases": "bun run src/new-releases"
|
||||
},
|
||||
"engineStrict": true,
|
||||
"engines": {
|
||||
|
|
|
|||
148
src/new-releases.js
Normal file
148
src/new-releases.js
Normal file
|
|
@ -0,0 +1,148 @@
|
|||
#!/usr/bin/env bun
|
||||
|
||||
import { writeFileSync, mkdirSync, readFileSync, existsSync } from "fs";
|
||||
import crypto from "crypto";
|
||||
import path from "path";
|
||||
|
||||
const MIN_DATE = new Date("2026-01-01");
|
||||
const CONCURRENT_LIMIT = 2;
|
||||
|
||||
const CACHE_DIR = "./deezer_cache";
|
||||
mkdirSync(CACHE_DIR, { recursive: true });
|
||||
|
||||
function cachePath(url) {
|
||||
const hash = crypto.createHash("sha1").update(url).digest("hex");
|
||||
return path.join(CACHE_DIR, `${hash}.json`);
|
||||
}
|
||||
|
||||
async function cachedFetch(url) {
|
||||
const file = cachePath(url);
|
||||
|
||||
if (existsSync(file)) {
|
||||
return JSON.parse(readFileSync(file, "utf8"));
|
||||
}
|
||||
|
||||
const res = await fetch(url);
|
||||
if (!res.ok) throw new Error(`${res.status} ${res.statusText}`);
|
||||
const json = await res.json();
|
||||
|
||||
writeFileSync(file, JSON.stringify(json, null, 2));
|
||||
return json;
|
||||
}
|
||||
|
||||
async function subsonicRequest(endpoint, params = {}) {
|
||||
params.u = process.env.NAVIDROME_USER;
|
||||
params.p = process.env.NAVIDROME_PASS;
|
||||
params.v = "1.16.1";
|
||||
params.c = "NewAlbumChecker";
|
||||
params.f = "json";
|
||||
|
||||
const urlParams = new URLSearchParams(params);
|
||||
const url = `${process.env.NAVIDROME_URL}/rest/${endpoint}.view?${urlParams}`;
|
||||
const res = await fetch(url);
|
||||
if (!res.ok) throw new Error(`Subsonic request failed: ${res.status}`);
|
||||
const data = await res.json();
|
||||
return data["subsonic-response"];
|
||||
}
|
||||
|
||||
async function getAllArtists() {
|
||||
const data = await subsonicRequest("getArtists");
|
||||
return data.artists.index.flatMap((z) => z.artist).map((a) => a.name);
|
||||
}
|
||||
|
||||
async function searchDeezerArtist(artistName) {
|
||||
try {
|
||||
const data = await cachedFetch(
|
||||
`https://api.deezer.com/search/artist?q=${encodeURIComponent(artistName)}`,
|
||||
);
|
||||
if (!data.data || !data.data.length) return null;
|
||||
return data.data[0].id;
|
||||
} catch (err) {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
async function getDeezerAlbums(artistId) {
|
||||
try {
|
||||
const data = await cachedFetch(
|
||||
`https://api.deezer.com/artist/${artistId}/albums`,
|
||||
);
|
||||
|
||||
return data.data
|
||||
.filter((album) => {
|
||||
if (!album.release_date) return false;
|
||||
const date = new Date(album.release_date);
|
||||
return date >= MIN_DATE;
|
||||
})
|
||||
.map((album) => ({
|
||||
title: album.title,
|
||||
explicit: album.explicit_lyrics,
|
||||
release_date: album.release_date,
|
||||
url: album.link,
|
||||
}));
|
||||
} catch (err) {
|
||||
return [];
|
||||
}
|
||||
}
|
||||
|
||||
async function runWithConcurrency(items, worker, limit = CONCURRENT_LIMIT) {
|
||||
const results = [];
|
||||
let i = 0;
|
||||
|
||||
async function next() {
|
||||
if (i >= items.length) return;
|
||||
const index = i++;
|
||||
try {
|
||||
const res = await worker(items[index]);
|
||||
results.push(...res);
|
||||
} catch (e) {
|
||||
console.error("Error processing", items[index], e);
|
||||
}
|
||||
return next();
|
||||
}
|
||||
|
||||
const runners = Array.from({ length: Math.min(limit, items.length) }, next);
|
||||
await Promise.all(runners);
|
||||
return results;
|
||||
}
|
||||
|
||||
async function checkNewReleases() {
|
||||
const artists = await getAllArtists();
|
||||
console.log(`Found ${artists.length} artists, checking Deezer...`);
|
||||
|
||||
const releases = await runWithConcurrency(
|
||||
artists,
|
||||
async (artist) => {
|
||||
console.log("checking " + artist);
|
||||
const deezerId = await searchDeezerArtist(artist);
|
||||
if (!deezerId) return [];
|
||||
|
||||
const albums = await getDeezerAlbums(deezerId);
|
||||
const formatted = albums.map((a) => ({
|
||||
artist,
|
||||
album: a.title,
|
||||
release_date: a.release_date,
|
||||
url: a.url,
|
||||
explicit: a.explicit,
|
||||
}));
|
||||
console.log("checked " + artist);
|
||||
return formatted;
|
||||
},
|
||||
CONCURRENT_LIMIT,
|
||||
);
|
||||
|
||||
return releases;
|
||||
}
|
||||
|
||||
(async () => {
|
||||
const releases = await checkNewReleases();
|
||||
if (releases.length) {
|
||||
console.log("New albums/tracks since 2026-01-01 on Deezer:");
|
||||
releases.forEach((r) => {
|
||||
console.log(`${r.release_date} - ${r.artist} - ${r.album}`);
|
||||
});
|
||||
writeFileSync("new_releases.json", JSON.stringify(releases, null, 2));
|
||||
} else {
|
||||
console.log("No new releases found since 2026-01-01.");
|
||||
}
|
||||
})();
|
||||
Loading…
Add table
Add a link
Reference in a new issue