diff --git a/package.json b/package.json index d040997..8239cfc 100644 --- a/package.json +++ b/package.json @@ -9,7 +9,8 @@ }, "dependencies": { "discord.js": "^14.17.2", - "ts-node": "^10.9.2" + "ts-node": "^10.9.2", + "zod": "^3.24.2" }, "devDependencies": { "typescript": "^5.5.3" diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index fa2aff7..11d63c0 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -14,6 +14,9 @@ importers: ts-node: specifier: ^10.9.2 version: 10.9.2(@types/node@22.10.5)(typescript@5.7.2) + zod: + specifier: ^3.24.2 + version: 3.24.2 devDependencies: typescript: specifier: ^5.5.3 @@ -189,6 +192,9 @@ packages: resolution: {integrity: sha512-Ux4ygGWsu2c7isFWe8Yu1YluJmqVhxqK2cLXNQA5AcC3QfbGNpM7fu0Y8b/z16pXLnFxZYvWhd3fhBY9DLmC6Q==} engines: {node: '>=6'} + zod@3.24.2: + resolution: {integrity: sha512-lY7CDW43ECgW9u1TcT3IoXHflywfVqDYze4waEz812jR/bZ8FHDsl7pFQoSZTz5N+2NqRXs8GBwnAwo3ZNxqhQ==} + snapshots: '@cspotcode/source-map-support@0.8.1': @@ -353,3 +359,5 @@ snapshots: ws@8.18.0: {} yn@3.1.1: {} + + zod@3.24.2: {} diff --git a/src/helper.ts b/src/helper.ts new file mode 100644 index 0000000..a67bfeb --- /dev/null +++ b/src/helper.ts @@ -0,0 +1,57 @@ +import { z } from "zod"; + +export interface Song { + title: string; + artist: string; + apiProvider: string; + thumbnailUrl: string; + link: string; +} +const songLinkShape = z.object({ + userCountry: z.string(), + entitiesByUniqueId: z.record( + z.string(), + z.object({ + id: z.string(), + type: z.string(), + title: z.string(), + thumbnailUrl: z.string(), + apiProvider: z.string(), + artistName: z.string(), + }) + ), + linksByPlatform: z.record( + z.string(), + z.object({ + country: z.string(), + url: z.string().url(), + entityUniqueId: z.string(), + })) +}); +//i hate this +export const preferredProviders = [ + "spotify", + "deezer", + "youtubeMusic" +]; + +export function getSongOnPreferredProvider(json: any, link: string): Song | null { + const song = songLinkShape.parse(json); + for (const platform of preferredProviders) { + if (!song.linksByPlatform[platform]) { + console.log(`couldnt find song on ${platform}`) + continue + } + const entityId = song.linksByPlatform[platform].entityUniqueId; + const songInfo = song.entitiesByUniqueId[entityId] + + return { + title: songInfo.title, + artist: songInfo.artistName, + apiProvider: songInfo.apiProvider, + thumbnailUrl: songInfo.thumbnailUrl, + link + } + } + return null +} diff --git a/src/index.ts b/src/index.ts index 4ca101d..0b7964e 100644 --- a/src/index.ts +++ b/src/index.ts @@ -1,8 +1,13 @@ import config from "../config.json" with {type: "json"}; import { + ActionRow, + ActionRowBuilder, Application, ApplicationIntegrationType, + ButtonBuilder, + ButtonStyle, Client, + EmbedBuilder, Events, GatewayIntentBits, InteractionContextType, @@ -10,6 +15,7 @@ import { Routes, SlashCommandBuilder } from "discord.js"; +import { getSongOnPreferredProvider } from "./helper.ts"; const client = new Client({ intents: Object.keys(GatewayIntentBits).map((a) => { @@ -49,7 +55,7 @@ client.once(Events.ClientReady, async () => { console.log("Ready"); const rest = new REST().setToken(config.token); const data = await rest.put( - Routes.applicationCommands(client.user.id), {body: commands}, + Routes.applicationCommands(client.user.id), { body: commands }, ); // @ts-ignore console.log(`Successfully reloaded ${data.length} application (/) commands.`); @@ -58,7 +64,7 @@ client.once(Events.ClientReady, async () => { client.on(Events.InteractionCreate, async (interaction) => { if (!interaction.isChatInputCommand()) return; - const {commandName} = interaction; + const { commandName } = interaction; if (commandName !== "nowplaying") return; await interaction.deferReply() @@ -71,7 +77,26 @@ client.on(Events.InteractionCreate, async (interaction) => { if (meow.payload.count === 0) { interaction.followUp("user isnt listening to music"); } else { - interaction.followUp("[" + meow.payload.listens[0].track_metadata.artist_name + " - " + meow.payload.listens[0].track_metadata.track_name + "](" + keepV(meow.payload.listens[0].track_metadata.additional_info.origin_url) + ")"); + const track_metadata = meow.payload.listens[0].track_metadata + const link = keepV(track_metadata.additional_info.origin_url) + + const preferredApi = getSongOnPreferredProvider(await fetch(`https://api.song.link/v1-alpha.1/links?url=${link}`).then(a => a.json()), link) + const embed = new EmbedBuilder() + .setAuthor({ + name: preferredApi.artist, + }) + .setTitle(preferredApi.title) + .setThumbnail(preferredApi.thumbnailUrl) + .setFooter({ + text: "amy jr", + }); + const nya = new ActionRowBuilder().addComponents(new ButtonBuilder().setURL(preferredApi.link).setLabel("link").setStyle(ButtonStyle.Link)) + interaction.followUp({ + components: [ + nya + ], + embeds: [embed] + }); } })