init part 2

This commit is contained in:
nin0 2025-04-25 04:46:30 -04:00
parent e4453fad75
commit 55054e7c9e
Signed by: nin0
SSH key fingerprint: SHA256:NOoDnFVvZNFvqfXCIhzr6oCTDImZAbTTuyAysZ8Ufk8
6 changed files with 220 additions and 7 deletions

3
.gitignore vendored
View file

@ -1,3 +1,4 @@
node_modules/
dist/
.env
.env
state.json

8
.prettierrc.json Normal file
View file

@ -0,0 +1,8 @@
{
"tabWidth": 4,
"useTabs": true,
"semi": true,
"trailingComma": "none",
"singleQuote": false,
"jsxSingleQuote": false
}

60
Yapper.ts Normal file
View file

@ -0,0 +1,60 @@
function getDateTime() {
const now = new Date();
const hours = String(now.getHours()).padStart(2, "0");
const minutes = String(now.getMinutes()).padStart(2, "0");
const seconds = String(now.getSeconds()).padStart(2, "0");
const day = String(now.getDate()).padStart(2, "0");
const month = String(now.getMonth() + 1).padStart(2, "0");
const year = now.getFullYear();
return `${hours}:${minutes}:${seconds} ${day}-${month}-${year}`;
}
export class Yapper {
constructor() {}
trace(obj) {
console.log("\x1b[90;1m TRC\x1b[90;1m \x1b[0;90m", getDateTime(), obj);
}
debug(obj) {
console.log(
"\x1b[90;1;47m DBG",
`\x1b[0m \x1b[90m${getDateTime()}`,
obj,
"\x1b[0m"
);
}
info(obj) {
console.log(
"\x1b[44;1m INF",
`\x1b[0m \x1b[90m${getDateTime()}\x1b[0m`,
obj
);
}
warn(obj) {
console.log(
"\x1b[43;1m WRN",
`\x1b[0m \x1b[90m${getDateTime()}\x1b[0m`,
obj
);
}
error(obj) {
console.log(
"\x1b[41;1m ERR",
`\x1b[0m \x1b[90m${getDateTime()}\x1b[0m`,
obj
);
}
fatal(obj) {
console.log(
"\x1b[40;31;1m FTL",
`\x1b[0m \x1b[31;1m${getDateTime()}\x1b[0;31m`,
obj,
"\x1b[0m"
);
}
child() {
return new Yapper();
}
level; // unused
silent; // unused
}

84
index.ts Normal file
View file

@ -0,0 +1,84 @@
import Fastify from "fastify";
import { Yapper } from "./Yapper";
import path from "path";
import { readFileSync, 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;
}
}
);
const fastify = Fastify({
loggerInstance: new Yapper()
});
fastify.get("/", (request, reply) => {
reply.type("text/html");
return '<a href="/auth">auth</a>';
});
fastify.get("/auth", async (request, reply) => {
return reply.redirect(
`https://accounts.spotify.com/authorize?` +
new URLSearchParams({
response_type: "code",
client_id: process.env.CLIENT_ID!,
scope: "user-library-read user-library-modify playlist-read-private playlist-read-collaborative playlist-modify-private playlist-modify-public",
redirect_uri: `https://${request.hostname}/callback`,
show_dialog: "true",
state: "ballsgamingmeoww"
}).toString()
);
});
fastify.get("/callback", async (request, reply) => {
if ((request.query as any).error) return reply.code(400).send();
const tokenRes = await fetch("https://accounts.spotify.com/api/token", {
method: "POST",
headers: {
"Content-Type": "application/x-www-form-urlencoded",
Authorization:
"Basic " +
Buffer.from(
process.env.CLIENT_ID + ":" + process.env.CLIENT_SECRET
).toString("base64")
},
body: new URLSearchParams({
code: (request.query as any).code,
redirect_uri: `https://${request.hostname}/callback`,
grant_type: "authorization_code"
})
});
console.log(await tokenRes.json());
});
try {
fastify.listen({
port: 4929,
host: "0.0.0.0"
});
} catch (err) {
fastify.log.error(err);
process.exit(1);
}

View file

@ -1,8 +1,17 @@
{
"name": "likedsongstoplaylist",
"packageManager": "pnpm@10.8.1",
"dependencies": {
"esbuild": "^0.25.3",
"fastify": "^5.3.2"
}
"name": "likedsongstoplaylist",
"packageManager": "pnpm@10.8.1",
"dependencies": {
"esbuild": "^0.25.3",
"fastify": "^5.3.2"
},
"devDependencies": {
"@types/node": "^22.15.2",
"tsx": "^4.19.3"
},
"scripts": {
"dev": "tsx --watch --env-file-if-exists=.env index.ts",
"build": "node build.mjs",
"start": "node build.mjs && node dist/index.js"
}
}

51
pnpm-lock.yaml generated
View file

@ -14,6 +14,13 @@ importers:
fastify:
specifier: ^5.3.2
version: 5.3.2
devDependencies:
'@types/node':
specifier: ^22.15.2
version: 22.15.2
tsx:
specifier: ^4.19.3
version: 4.19.3
packages:
@ -185,6 +192,9 @@ packages:
'@fastify/proxy-addr@5.0.0':
resolution: {integrity: sha512-37qVVA1qZ5sgH7KpHkkC4z9SK6StIsIcOmpjvMPXNb3vx2GQxhZocogVYbr2PbbeLCQxYIPDok307xEvRZOzGA==}
'@types/node@22.15.2':
resolution: {integrity: sha512-uKXqKN9beGoMdBfcaTY1ecwz6ctxuJAcUlwE55938g0ZJ8lRxwAZqRz2AJ4pzpt5dHdTPMB863UZ0ESiFUcP7A==}
abstract-logging@2.0.1:
resolution: {integrity: sha512-2BjRTZxTPvheOvGbBslFSYOUkr+SjPtOnrLP33f+VIWLzezQpZcqVg7ja3L4dBXmzzgwT+a029jRx5PCi3JuiA==}
@ -248,6 +258,14 @@ packages:
resolution: {integrity: sha512-eRoFWQw+Yv2tuYlK2pjFS2jGXSxSppAs3hSQjfxVKxM5amECzIgYYc1FEI8ZmhSh/Ig+FrKEz43NLRKJjYCZVg==}
engines: {node: '>=20'}
fsevents@2.3.3:
resolution: {integrity: sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==}
engines: {node: ^8.16.0 || ^10.6.0 || >=11.0.0}
os: [darwin]
get-tsconfig@4.10.0:
resolution: {integrity: sha512-kGzZ3LWWQcGIAmg6iWvXn0ei6WDtV26wzHRMwDSzmAbcXrTEXxHy6IehI6/4eT6VRKyMP1eF1VqwrVUmE/LR7A==}
ipaddr.js@2.2.0:
resolution: {integrity: sha512-Ag3wB2o37wslZS19hZqorUnrnzSkpOVy+IiiDEiTqNubEYpYuHWIf6K4psgN2ZWKExS4xhVCrRVfb/wfW8fWJA==}
engines: {node: '>= 10'}
@ -292,6 +310,9 @@ packages:
resolution: {integrity: sha512-Xf0nWe6RseziFMu+Ap9biiUbmplq6S9/p+7w7YXP/JBHhrUDDUhwa+vANyubuqfZWTveU//DYVGsDG7RKL/vEw==}
engines: {node: '>=0.10.0'}
resolve-pkg-maps@1.0.0:
resolution: {integrity: sha512-seS2Tj26TBVOC2NIc2rOe2y2ZO7efxITtLZcGSOnHHNOQ7CkiUBfw0Iw2ck6xkIhPwLhKNLS8BO+hEpngQlqzw==}
ret@0.5.0:
resolution: {integrity: sha512-I1XxrZSQ+oErkRR4jYbAyEEu2I0avBvvMM5JN+6EBprOGRCs63ENqZ3vjavq8fBw2+62G5LF5XelKwuJpcvcxw==}
engines: {node: '>=10'}
@ -335,6 +356,14 @@ packages:
resolution: {integrity: sha512-/m8M+2BJUpoJdgAHoG+baCwBT+tf2VraSfkBgl0Y00qIWt41DJ8R5B8nsEw0I58YwF5IZH6z24/2TobDKnqSWw==}
engines: {node: '>=12'}
tsx@4.19.3:
resolution: {integrity: sha512-4H8vUNGNjQ4V2EOoGw005+c+dGuPSnhpPBPHBtsZdGZBk/iJb4kguGlPWaZTZ3q5nMtFOEsY0nRDlh9PJyd6SQ==}
engines: {node: '>=18.0.0'}
hasBin: true
undici-types@6.21.0:
resolution: {integrity: sha512-iwDZqg0QAGrg9Rav5H4n0M64c3mkR59cJ6wQp+7C4nI0gsmExaedaYLNO44eT4AtBBwjbTiGPMlt2Md0T9H9JQ==}
snapshots:
'@esbuild/aix-ppc64@0.25.3':
@ -435,6 +464,10 @@ snapshots:
'@fastify/forwarded': 3.0.0
ipaddr.js: 2.2.0
'@types/node@22.15.2':
dependencies:
undici-types: 6.21.0
abstract-logging@2.0.1: {}
ajv-formats@3.0.1(ajv@8.17.1):
@ -536,6 +569,13 @@ snapshots:
fast-querystring: 1.1.2
safe-regex2: 5.0.0
fsevents@2.3.3:
optional: true
get-tsconfig@4.10.0:
dependencies:
resolve-pkg-maps: 1.0.0
ipaddr.js@2.2.0: {}
json-schema-ref-resolver@2.0.1:
@ -582,6 +622,8 @@ snapshots:
require-from-string@2.0.2: {}
resolve-pkg-maps@1.0.0: {}
ret@0.5.0: {}
reusify@1.1.0: {}
@ -611,3 +653,12 @@ snapshots:
real-require: 0.2.0
toad-cache@3.7.0: {}
tsx@4.19.3:
dependencies:
esbuild: 0.25.3
get-tsconfig: 4.10.0
optionalDependencies:
fsevents: 2.3.3
undici-types@6.21.0: {}