From 7c74f50c355209eb39b6e7af0fe1d17e30fcef05 Mon Sep 17 00:00:00 2001 From: nin0 Date: Fri, 25 Apr 2025 05:47:35 -0400 Subject: [PATCH] I AM MUSIC --- src/SpotifyAPI.ts | 0 src/index.ts | 40 ++++++++++-------------------- src/spotify.ts | 62 +++++++++++++++++++++++++++++++++++++++++++++++ src/utils.ts | 27 +++++++++++++++++++++ 4 files changed, 102 insertions(+), 27 deletions(-) delete mode 100644 src/SpotifyAPI.ts create mode 100644 src/spotify.ts create mode 100644 src/utils.ts diff --git a/src/SpotifyAPI.ts b/src/SpotifyAPI.ts deleted file mode 100644 index e69de29..0000000 diff --git a/src/index.ts b/src/index.ts index 4900b38..6417718 100644 --- a/src/index.ts +++ b/src/index.ts @@ -1,34 +1,11 @@ import Fastify from "fastify"; import { Yapper } from "./Yapper"; -import path from "path"; -import { readFileSync, stat, writeFileSync } from "fs"; - -const state = new Proxy( - JSON.parse(readFileSync(path.join(__dirname, "state.json"), "utf-8")), - { - get(target, prop) { - const data = readFileSync( - path.join(__dirname, "state.json"), - "utf-8" - ); - return JSON.parse(data); - }, - set(target, prop, value) { - const data = JSON.parse( - readFileSync(path.join(__dirname, "state.json"), "utf-8") - ); - data[prop] = value; - writeFileSync( - path.join(__dirname, "state.json"), - JSON.stringify(data) - ); - return true; - } - } -); +import { state } from "./utils"; +import { reqSpotify, spotifyFilter } from "./spotify"; const fastify = Fastify({ - loggerInstance: new Yapper() + loggerInstance: new Yapper(), + disableRequestLogging: true }); fastify.get("/", (request, reply) => { @@ -72,12 +49,21 @@ fastify.get("/callback", async (request, reply) => { }) ).json(); + if (tokenRes.error) return reply.code(400).send(); + state.accessToken = tokenRes.access_token; state.explodesAt = Date.now() + tokenRes.expires_in * 1000; state.refreshToken = tokenRes.refresh_token; + + return `Logged in as ${ + (await reqSpotify("/me")).display_name + }. You're good to go!`; }); try { + setInterval(spotifyFilter, 5000); + spotifyFilter(); + fastify.listen({ port: 4929, host: "0.0.0.0" diff --git a/src/spotify.ts b/src/spotify.ts new file mode 100644 index 0000000..ac56690 --- /dev/null +++ b/src/spotify.ts @@ -0,0 +1,62 @@ +import { state } from "./utils"; + +export async function reqSpotify( + endpoint: string, + method: string = "GET", + data?: object +) { + if (state.explodesAt >= Date.now()) { + const tokenRes = await ( + await fetch("https://accounts.spotify.com/api/token", { + method: "POST", + headers: { + "Content-Type": "application/x-www-form-urlencoded" + }, + body: new URLSearchParams({ + refresh_token: state.refreshToken, + client_id: process.env.CLIENT_ID!, + grant_type: "refresh_token" + }) + }) + ).json(); + + if (!tokenRes.error) { + state.accessToken = tokenRes.access_token; + state.explodesAt = Date.now() + tokenRes.expires_in * 1000; + state.refreshToken = tokenRes.refresh_token; + } + } + + try { + return await ( + await fetch("https://api.spotify.com/v1" + endpoint, { + method, + headers: { + Authorization: `Bearer ${state.accessToken}` + }, + body: JSON.stringify(data) + }) + ).json(); + } catch { + return {}; + } +} + +export async function spotifyFilter() { + const likedSongs = (await reqSpotify("/me/tracks")).items.map((item) => { + return { + uri: item.track.uri + }; + }); + + await reqSpotify("/playlists/0jWbMtGfptAzenepLTL4ED/tracks", "DELETE", { + tracks: likedSongs + }); + await reqSpotify("/playlists/0jWbMtGfptAzenepLTL4ED/tracks", "POST", { + uris: likedSongs.map((lss) => lss.uri), + position: 0 + }); + await reqSpotify("/me/tracks", "DELETE", { + ids: likedSongs.map((lss) => lss.uri.replace("spotify:track:", "")) + }); +} diff --git a/src/utils.ts b/src/utils.ts new file mode 100644 index 0000000..74c41ca --- /dev/null +++ b/src/utils.ts @@ -0,0 +1,27 @@ +import { readFileSync, writeFileSync } from "fs"; +import path from "path"; + +export const state = new Proxy<{ + explodesAt: number; + accessToken: string; + refreshToken: string; +}>(JSON.parse(readFileSync(path.join(__dirname, "../state.json"), "utf-8")), { + get(target, prop) { + const data = readFileSync( + path.join(__dirname, "../state.json"), + "utf-8" + ); + return JSON.parse(data)[prop]; + }, + set(target, prop, value) { + const data = JSON.parse( + readFileSync(path.join(__dirname, "../state.json"), "utf-8") + ); + data[prop] = value; + writeFileSync( + path.join(__dirname, "../state.json"), + JSON.stringify(data) + ); + return true; + } +});