diff --git a/apps/api/src/lib/crypto.ts b/apps/api/src/lib/crypto.ts index d74912c8..4973c18b 100644 --- a/apps/api/src/lib/crypto.ts +++ b/apps/api/src/lib/crypto.ts @@ -1,4 +1,4 @@ -import crypto from "crypto"; +import crypto from "node:crypto"; import { env } from "./env"; export function encrypt(text: string, key: string) { @@ -6,7 +6,7 @@ export function encrypt(text: string, key: string) { const cipher = crypto.createCipheriv( "aes-256-ctr", Buffer.from(key, "hex"), - iv, + iv ); const encrypted = Buffer.concat([ cipher.update(text, "utf8"), @@ -21,7 +21,7 @@ export function decrypt(encrypted: string, key: string) { const decipher = crypto.createDecipheriv( "aes-256-ctr", Buffer.from(key, "hex"), - iv, + iv ); const decrypted = Buffer.concat([decipher.update(content), decipher.final()]); return decrypted.toString("utf8"); diff --git a/apps/api/src/lovedtracks/lovedtracks.service.ts b/apps/api/src/lovedtracks/lovedtracks.service.ts index 1bf9a078..e4dd5985 100644 --- a/apps/api/src/lovedtracks/lovedtracks.service.ts +++ b/apps/api/src/lovedtracks/lovedtracks.service.ts @@ -2,16 +2,16 @@ import type { Agent } from "@atproto/api"; import { TID } from "@atproto/common"; import { equals } from "@xata.io/client"; import type { Context } from "context"; -import { createHash } from "crypto"; import * as LikeLexicon from "lexicon/types/app/rocksky/like"; import { validateMain } from "lexicon/types/com/atproto/repo/strongRef"; +import { createHash } from "node:crypto"; import type { Track } from "types/track"; export async function likeTrack( ctx: Context, track: Track, user, - agent: Agent, + agent: Agent ) { const existingTrack = await ctx.client.db.tracks .filter( @@ -19,10 +19,10 @@ export async function likeTrack( equals( createHash("sha256") .update( - `${track.title} - ${track.artist} - ${track.album}`.toLowerCase(), + `${track.title} - ${track.artist} - ${track.album}`.toLowerCase() ) - .digest("hex"), - ), + .digest("hex") + ) ) .getFirst(); @@ -43,10 +43,10 @@ export async function likeTrack( // compute sha256 (lowercase(title + artist + album)) sha256: createHash("sha256") .update( - `${track.title} - ${track.artist} - ${track.album}`.toLowerCase(), + `${track.title} - ${track.artist} - ${track.album}`.toLowerCase() ) .digest("hex"), - }, + } ); const existingArtist = await ctx.client.db.artists @@ -55,8 +55,8 @@ export async function likeTrack( equals( createHash("sha256") .update(track.albumArtist.toLocaleLowerCase()) - .digest("hex"), - ), + .digest("hex") + ) ) .getFirst(); const { xata_id: artist_id } = await ctx.client.db.artists.createOrUpdate( @@ -67,7 +67,7 @@ export async function likeTrack( sha256: createHash("sha256") .update(track.albumArtist.toLowerCase()) .digest("hex"), - }, + } ); const existingAlbum = await ctx.client.db.albums @@ -76,8 +76,8 @@ export async function likeTrack( equals( createHash("sha256") .update(`${track.album} - ${track.albumArtist}`.toLowerCase()) - .digest("hex"), - ), + .digest("hex") + ) ) .getFirst(); @@ -95,7 +95,7 @@ export async function likeTrack( sha256: createHash("sha256") .update(`${track.album} - ${track.albumArtist}`.toLowerCase()) .digest("hex"), - }, + } ); const existingAlbumTrack = await ctx.client.db.album_tracks @@ -118,7 +118,7 @@ export async function likeTrack( { artist_id, track_id, - }, + } ); const existingArtistAlbum = await ctx.client.db.artist_albums @@ -131,7 +131,7 @@ export async function likeTrack( { artist_id, album_id, - }, + } ); const lovedTrack = await ctx.client.db.loved_tracks @@ -144,7 +144,7 @@ export async function likeTrack( { user_id: user.xata_id, track_id, - }, + } ); if (existingTrack.uri) { @@ -206,7 +206,7 @@ export async function unLikeTrack( ctx: Context, trackSha256: string, user, - agent: Agent, + agent: Agent ) { const track = await ctx.client.db.tracks .filter("sha256", equals(trackSha256)) @@ -244,7 +244,7 @@ export async function getLovedTracks( ctx: Context, user, size = 10, - offset = 0, + offset = 0 ) { const lovedTracks = await ctx.client.db.loved_tracks .select(["track_id.*"]) diff --git a/apps/api/src/nowplaying/nowplaying.service.ts b/apps/api/src/nowplaying/nowplaying.service.ts index 04331eac..8d5388bd 100644 --- a/apps/api/src/nowplaying/nowplaying.service.ts +++ b/apps/api/src/nowplaying/nowplaying.service.ts @@ -3,18 +3,18 @@ import { TID } from "@atproto/common"; import { equals } from "@xata.io/client"; import chalk from "chalk"; import type { Context } from "context"; -import { createHash } from "crypto"; import dayjs from "dayjs"; import * as Album from "lexicon/types/app/rocksky/album"; import * as Artist from "lexicon/types/app/rocksky/artist"; import * as Scrobble from "lexicon/types/app/rocksky/scrobble"; import * as Song from "lexicon/types/app/rocksky/song"; import downloadImage, { getContentType } from "lib/downloadImage"; +import { createHash } from "node:crypto"; import type { Track } from "types/track"; export async function putArtistRecord( track: Track, - agent: Agent, + agent: Agent ): Promise { const rkey = TID.nextStr(); const record: { @@ -63,7 +63,7 @@ export async function putArtistRecord( export async function putAlbumRecord( track: Track, - agent: Agent, + agent: Agent ): Promise { const rkey = TID.nextStr(); let albumArt; @@ -123,7 +123,7 @@ export async function putAlbumRecord( export async function putSongRecord( track: Track, - agent: Agent, + agent: Agent ): Promise { const rkey = TID.nextStr(); let albumArt; @@ -191,7 +191,7 @@ export async function putSongRecord( async function putScrobbleRecord( track: Track, - agent: Agent, + agent: Agent ): Promise { const rkey = TID.nextStr(); let albumArt; @@ -369,7 +369,7 @@ export async function scrobbleTrack( ctx: Context, track: Track, agent: Agent, - userDid: string, + userDid: string ): Promise { // check if scrobble already exists (user did + timestamp) const scrobbleTime = dayjs.unix(track.timestamp); @@ -393,8 +393,8 @@ export async function scrobbleTrack( if (existingScrobble) { console.log( `Scrobble already exists for ${chalk.cyan(track.title)} at ${chalk.cyan( - dayjs.unix(track.timestamp).format("YYYY-MM-DD HH:mm:ss"), - )}`, + dayjs.unix(track.timestamp).format("YYYY-MM-DD HH:mm:ss") + )}` ); return; } @@ -406,10 +406,10 @@ export async function scrobbleTrack( equals( createHash("sha256") .update( - `${track.title} - ${track.artist} - ${track.album}`.toLowerCase(), + `${track.title} - ${track.artist} - ${track.album}`.toLowerCase() ) - .digest("hex"), - ), + .digest("hex") + ) ) .getFirst(); @@ -420,8 +420,8 @@ export async function scrobbleTrack( equals( createHash("sha256") .update(`${track.album} - ${track.albumArtist}`.toLowerCase()) - .digest("hex"), - ), + .digest("hex") + ) ) .getFirst(); if (album) { @@ -438,8 +438,8 @@ export async function scrobbleTrack( equals( createHash("sha256") .update(track.albumArtist.toLowerCase()) - .digest("hex"), - ), + .digest("hex") + ) ) .getFirst(); if (artist) { @@ -466,8 +466,8 @@ export async function scrobbleTrack( equals( createHash("sha256") .update(`${track.album} - ${track.albumArtist}`.toLowerCase()) - .digest("hex"), - ), + .digest("hex") + ) ) .getFirst(); @@ -480,10 +480,10 @@ export async function scrobbleTrack( equals( createHash("sha256") .update( - `${track.title} - ${track.artist} - ${track.album}`.toLowerCase(), + `${track.title} - ${track.artist} - ${track.album}`.toLowerCase() ) - .digest("hex"), - ), + .digest("hex") + ) ) .getFirst(); await new Promise((resolve) => setTimeout(resolve, 1000)); @@ -496,7 +496,7 @@ export async function scrobbleTrack( if (existingTrack) { console.log( - `Song found: ${chalk.cyan(existingTrack.xata_id)} - ${track.title}, after ${chalk.magenta(tries)} tries`, + `Song found: ${chalk.cyan(existingTrack.xata_id)} - ${track.title}, after ${chalk.magenta(tries)} tries` ); } @@ -546,10 +546,10 @@ export async function scrobbleTrack( equals( createHash("sha256") .update( - `${track.title} - ${track.artist} - ${track.album}`.toLowerCase(), + `${track.title} - ${track.artist} - ${track.album}`.toLowerCase() ) - .digest("hex"), - ), + .digest("hex") + ) ) .getFirst(); @@ -559,7 +559,7 @@ export async function scrobbleTrack( tries < 30 ) { console.log( - `Artist uri not ready, trying again: ${chalk.magenta(tries + 1)}`, + `Artist uri not ready, trying again: ${chalk.magenta(tries + 1)}` ); existingTrack = await ctx.client.db.tracks .filter( @@ -567,10 +567,10 @@ export async function scrobbleTrack( equals( createHash("sha256") .update( - `${track.title} - ${track.artist} - ${track.album}`.toLowerCase(), + `${track.title} - ${track.artist} - ${track.album}`.toLowerCase() ) - .digest("hex"), - ), + .digest("hex") + ) ) .getFirst(); @@ -582,8 +582,8 @@ export async function scrobbleTrack( equals( createHash("sha256") .update(track.albumArtist.toLowerCase()) - .digest("hex"), - ), + .digest("hex") + ) ) .getFirst(); if (artist) { @@ -602,8 +602,8 @@ export async function scrobbleTrack( equals( createHash("sha256") .update(`${track.album} - ${track.albumArtist}`.toLowerCase()) - .digest("hex"), - ), + .digest("hex") + ) ) .getFirst(); if (album) { @@ -630,7 +630,7 @@ export async function scrobbleTrack( if (existingTrack?.artist_uri) { console.log( - `Artist uri ready: ${chalk.cyan(existingTrack.xata_id)} - ${track.title}, after ${chalk.magenta(tries)} tries`, + `Artist uri ready: ${chalk.cyan(existingTrack.xata_id)} - ${track.title}, after ${chalk.magenta(tries)} tries` ); } diff --git a/apps/api/src/spotify/app.ts b/apps/api/src/spotify/app.ts index ef20c936..cd6266b5 100644 --- a/apps/api/src/spotify/app.ts +++ b/apps/api/src/spotify/app.ts @@ -1,11 +1,11 @@ import { equals } from "@xata.io/client"; import { ctx } from "context"; -import crypto, { createHash } from "crypto"; import { Hono } from "hono"; import jwt from "jsonwebtoken"; import { decrypt, encrypt } from "lib/crypto"; import { env } from "lib/env"; import { requestCounter } from "metrics"; +import crypto, { createHash } from "node:crypto"; import { rateLimiter } from "ratelimiter"; import { emailSchema } from "types/email"; @@ -17,7 +17,7 @@ app.use( limit: 10, // max Spotify API calls window: 15, // per 10 seconds keyPrefix: "spotify-ratelimit", - }), + }) ); app.get("/login", async (c) => { @@ -44,7 +44,7 @@ app.get("/login", async (c) => { const redirectUrl = `https://accounts.spotify.com/en/authorize?client_id=${env.SPOTIFY_CLIENT_ID}&response_type=code&redirect_uri=${env.SPOTIFY_REDIRECT_URI}&scope=user-read-private%20user-read-email%20user-read-playback-state%20user-read-currently-playing%20user-modify-playback-state%20playlist-modify-public%20playlist-modify-private%20playlist-read-private%20playlist-read-collaborative&state=${state}`; c.header( "Set-Cookie", - `session-id=${state}; Path=/; HttpOnly; SameSite=Strict; Secure`, + `session-id=${state}; Path=/; HttpOnly; SameSite=Strict; Secure` ); return c.json({ redirectUrl }); }); @@ -210,7 +210,7 @@ app.get("/currently-playing", async (c) => { const sha256 = createHash("sha256") .update( - `${track.item.name} - ${track.item.artists.map((x) => x.name).join(", ")} - ${track.item.album.name}`.toLowerCase(), + `${track.item.name} - ${track.item.artists.map((x) => x.name).join(", ")} - ${track.item.album.name}`.toLowerCase() ) .digest("hex"); @@ -264,7 +264,7 @@ app.put("/pause", async (c) => { const refreshToken = decrypt( spotifyToken.refresh_token, - env.SPOTIFY_ENCRYPTION_KEY, + env.SPOTIFY_ENCRYPTION_KEY ); // get new access token @@ -330,7 +330,7 @@ app.put("/play", async (c) => { const refreshToken = decrypt( spotifyToken.refresh_token, - env.SPOTIFY_ENCRYPTION_KEY, + env.SPOTIFY_ENCRYPTION_KEY ); // get new access token @@ -396,7 +396,7 @@ app.post("/next", async (c) => { const refreshToken = decrypt( spotifyToken.refresh_token, - env.SPOTIFY_ENCRYPTION_KEY, + env.SPOTIFY_ENCRYPTION_KEY ); // get new access token @@ -462,7 +462,7 @@ app.post("/previous", async (c) => { const refreshToken = decrypt( spotifyToken.refresh_token, - env.SPOTIFY_ENCRYPTION_KEY, + env.SPOTIFY_ENCRYPTION_KEY ); // get new access token @@ -488,7 +488,7 @@ app.post("/previous", async (c) => { headers: { Authorization: `Bearer ${access_token}`, }, - }, + } ); if (response.status === 403) { @@ -531,7 +531,7 @@ app.put("/seek", async (c) => { const refreshToken = decrypt( spotifyToken.refresh_token, - env.SPOTIFY_ENCRYPTION_KEY, + env.SPOTIFY_ENCRYPTION_KEY ); // get new access token @@ -558,7 +558,7 @@ app.put("/seek", async (c) => { headers: { Authorization: `Bearer ${access_token}`, }, - }, + } ); if (response.status === 403) { diff --git a/apps/api/src/tracks/tracks.service.ts b/apps/api/src/tracks/tracks.service.ts index e2f17197..60150b68 100644 --- a/apps/api/src/tracks/tracks.service.ts +++ b/apps/api/src/tracks/tracks.service.ts @@ -1,7 +1,7 @@ import type { Agent } from "@atproto/api"; import { equals } from "@xata.io/client"; import type { Context } from "context"; -import { createHash } from "crypto"; +import { createHash } from "node:crypto"; import { putAlbumRecord, putArtistRecord, @@ -16,10 +16,10 @@ export async function saveTrack(ctx: Context, track: Track, agent: Agent) { equals( createHash("sha256") .update( - `${track.title} - ${track.artist} - ${track.album}`.toLowerCase(), + `${track.title} - ${track.artist} - ${track.album}`.toLowerCase() ) - .digest("hex"), - ), + .digest("hex") + ) ) .getFirst(); @@ -36,8 +36,8 @@ export async function saveTrack(ctx: Context, track: Track, agent: Agent) { equals( createHash("sha256") .update(`${track.album} - ${track.albumArtist}`.toLowerCase()) - .digest("hex"), - ), + .digest("hex") + ) ) .getFirst(); if (album) { @@ -54,8 +54,8 @@ export async function saveTrack(ctx: Context, track: Track, agent: Agent) { equals( createHash("sha256") .update(track.albumArtist.toLowerCase()) - .digest("hex"), - ), + .digest("hex") + ) ) .getFirst(); if (artist) { @@ -72,8 +72,8 @@ export async function saveTrack(ctx: Context, track: Track, agent: Agent) { equals( createHash("sha256") .update(track.albumArtist.toLocaleLowerCase()) - .digest("hex"), - ), + .digest("hex") + ) ) .getFirst(); @@ -88,8 +88,8 @@ export async function saveTrack(ctx: Context, track: Track, agent: Agent) { equals( createHash("sha256") .update(`${track.album} - ${track.albumArtist}`.toLowerCase()) - .digest("hex"), - ), + .digest("hex") + ) ) .getFirst(); @@ -116,7 +116,7 @@ export async function saveTrack(ctx: Context, track: Track, agent: Agent) { if (!track_id || !album_id || !artist_id) { console.log( "Track not yet saved (uri not saved), retrying...", - tries + 1, + tries + 1 ); await new Promise((resolve) => setTimeout(resolve, 1000)); tries += 1; diff --git a/apps/api/src/websocket/handler.ts b/apps/api/src/websocket/handler.ts index 5dd6baef..92df568a 100644 --- a/apps/api/src/websocket/handler.ts +++ b/apps/api/src/websocket/handler.ts @@ -1,10 +1,10 @@ import chalk from "chalk"; import { ctx } from "context"; -import { createHash } from "crypto"; import { and, eq } from "drizzle-orm"; import type { Context } from "hono"; import jwt from "jsonwebtoken"; import { env } from "lib/env"; +import { createHash } from "node:crypto"; import lovedTracks from "schema/loved-tracks"; import tracks from "schema/tracks"; import users from "schema/users"; @@ -70,7 +70,7 @@ function handleWebsocket(c: Context) { if (data.type === "track") { const sha256 = createHash("sha256") .update( - `${data.title} - ${data.artist} - ${data.album}`.toLowerCase(), + `${data.title} - ${data.artist} - ${data.album}`.toLowerCase() ) .digest("hex"); const [cachedTrack, cachedLikes] = await Promise.all([ @@ -93,7 +93,7 @@ function handleWebsocket(c: Context) { await ctx.redis.setEx( `likes:${did}:${sha256}`, 2, - JSON.stringify({ liked: data.liked }), + JSON.stringify({ liked: data.liked }) ); } @@ -113,7 +113,7 @@ function handleWebsocket(c: Context) { ...data, sha256, liked: data.liked, - }), + }) ); } else { const [track] = await ctx.db @@ -136,7 +136,7 @@ function handleWebsocket(c: Context) { albumUri: track.albumUri, artistUri: track.artistUri, liked: data.liked, - }), + }) ), ctx.redis.setEx( `nowplaying:${did}`, @@ -145,7 +145,7 @@ function handleWebsocket(c: Context) { ...data, sha256, liked: data.liked, - }), + }) ), ]); } @@ -154,7 +154,7 @@ function handleWebsocket(c: Context) { await ctx.redis.setEx( `nowplaying:${did}:status`, 3, - `${data.status}`, + `${data.status}` ); } @@ -163,7 +163,7 @@ function handleWebsocket(c: Context) { type: "message", data, device_id, - }), + }) ); } }); @@ -175,7 +175,7 @@ function handleWebsocket(c: Context) { ignoreExpiration: true, }); console.log( - `Control message: ${chalk.greenBright(type)}, ${chalk.greenBright(target)}, ${chalk.greenBright(action)}, ${chalk.greenBright(args)}, ${chalk.greenBright("***")}`, + `Control message: ${chalk.greenBright(type)}, ${chalk.greenBright(target)}, ${chalk.greenBright(action)}, ${chalk.greenBright(args)}, ${chalk.greenBright("***")}` ); // Handle control message const deviceId = userDevices[did]?.find((id) => id === target); @@ -184,7 +184,7 @@ function handleWebsocket(c: Context) { if (targetDevice) { targetDevice.send(JSON.stringify({ type, action, args })); console.log( - `Control message sent to device: ${chalk.greenBright(deviceId)}, ${chalk.greenBright(target)}`, + `Control message sent to device: ${chalk.greenBright(deviceId)}, ${chalk.greenBright(target)}` ); return; } @@ -196,7 +196,7 @@ function handleWebsocket(c: Context) { if (targetDevice) { targetDevice.send(JSON.stringify({ type, action, args })); console.log( - `Control message sent to all devices: ${chalk.greenBright(id)}, ${chalk.greenBright(target)}`, + `Control message sent to all devices: ${chalk.greenBright(id)}, ${chalk.greenBright(target)}` ); } }); @@ -208,7 +208,7 @@ function handleWebsocket(c: Context) { if (registerMessage.success) { const { type, clientName, token } = registerMessage.data; console.log( - `Register message: ${chalk.greenBright(type)}, ${chalk.greenBright(clientName)}, ${chalk.greenBright("****")}`, + `Register message: ${chalk.greenBright(type)}, ${chalk.greenBright(clientName)}, ${chalk.greenBright("****")}` ); // Handle register Message const { did } = jwt.verify(token, env.JWT_SECRET, { @@ -221,7 +221,7 @@ function handleWebsocket(c: Context) { deviceNames[deviceId] = clientName; userDevices[did] = [...(userDevices[did] || []), deviceId]; console.log( - `Device registered: ${chalk.greenBright(deviceId)}, ${chalk.greenBright(clientName)}`, + `Device registered: ${chalk.greenBright(deviceId)}, ${chalk.greenBright(clientName)}` ); // broadcast to all devices @@ -235,7 +235,7 @@ function handleWebsocket(c: Context) { type: "device_registered", deviceId, clientName, - }), + }) ); } }); @@ -266,7 +266,7 @@ function handleWebsocket(c: Context) { const clientName = deviceNames[deviceId]; delete deviceNames[deviceId]; console.log( - `Device name removed: ${chalk.redBright(deviceId)}, ${chalk.redBright(clientName)}`, + `Device name removed: ${chalk.redBright(deviceId)}, ${chalk.redBright(clientName)}` ); } },