init part 2
This commit is contained in:
parent
e4453fad75
commit
55054e7c9e
6 changed files with 220 additions and 7 deletions
3
.gitignore
vendored
3
.gitignore
vendored
|
@ -1,3 +1,4 @@
|
||||||
node_modules/
|
node_modules/
|
||||||
dist/
|
dist/
|
||||||
.env
|
.env
|
||||||
|
state.json
|
8
.prettierrc.json
Normal file
8
.prettierrc.json
Normal file
|
@ -0,0 +1,8 @@
|
||||||
|
{
|
||||||
|
"tabWidth": 4,
|
||||||
|
"useTabs": true,
|
||||||
|
"semi": true,
|
||||||
|
"trailingComma": "none",
|
||||||
|
"singleQuote": false,
|
||||||
|
"jsxSingleQuote": false
|
||||||
|
}
|
60
Yapper.ts
Normal file
60
Yapper.ts
Normal 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
84
index.ts
Normal 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);
|
||||||
|
}
|
21
package.json
21
package.json
|
@ -1,8 +1,17 @@
|
||||||
{
|
{
|
||||||
"name": "likedsongstoplaylist",
|
"name": "likedsongstoplaylist",
|
||||||
"packageManager": "pnpm@10.8.1",
|
"packageManager": "pnpm@10.8.1",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"esbuild": "^0.25.3",
|
"esbuild": "^0.25.3",
|
||||||
"fastify": "^5.3.2"
|
"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
51
pnpm-lock.yaml
generated
|
@ -14,6 +14,13 @@ importers:
|
||||||
fastify:
|
fastify:
|
||||||
specifier: ^5.3.2
|
specifier: ^5.3.2
|
||||||
version: 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:
|
packages:
|
||||||
|
|
||||||
|
@ -185,6 +192,9 @@ packages:
|
||||||
'@fastify/proxy-addr@5.0.0':
|
'@fastify/proxy-addr@5.0.0':
|
||||||
resolution: {integrity: sha512-37qVVA1qZ5sgH7KpHkkC4z9SK6StIsIcOmpjvMPXNb3vx2GQxhZocogVYbr2PbbeLCQxYIPDok307xEvRZOzGA==}
|
resolution: {integrity: sha512-37qVVA1qZ5sgH7KpHkkC4z9SK6StIsIcOmpjvMPXNb3vx2GQxhZocogVYbr2PbbeLCQxYIPDok307xEvRZOzGA==}
|
||||||
|
|
||||||
|
'@types/node@22.15.2':
|
||||||
|
resolution: {integrity: sha512-uKXqKN9beGoMdBfcaTY1ecwz6ctxuJAcUlwE55938g0ZJ8lRxwAZqRz2AJ4pzpt5dHdTPMB863UZ0ESiFUcP7A==}
|
||||||
|
|
||||||
abstract-logging@2.0.1:
|
abstract-logging@2.0.1:
|
||||||
resolution: {integrity: sha512-2BjRTZxTPvheOvGbBslFSYOUkr+SjPtOnrLP33f+VIWLzezQpZcqVg7ja3L4dBXmzzgwT+a029jRx5PCi3JuiA==}
|
resolution: {integrity: sha512-2BjRTZxTPvheOvGbBslFSYOUkr+SjPtOnrLP33f+VIWLzezQpZcqVg7ja3L4dBXmzzgwT+a029jRx5PCi3JuiA==}
|
||||||
|
|
||||||
|
@ -248,6 +258,14 @@ packages:
|
||||||
resolution: {integrity: sha512-eRoFWQw+Yv2tuYlK2pjFS2jGXSxSppAs3hSQjfxVKxM5amECzIgYYc1FEI8ZmhSh/Ig+FrKEz43NLRKJjYCZVg==}
|
resolution: {integrity: sha512-eRoFWQw+Yv2tuYlK2pjFS2jGXSxSppAs3hSQjfxVKxM5amECzIgYYc1FEI8ZmhSh/Ig+FrKEz43NLRKJjYCZVg==}
|
||||||
engines: {node: '>=20'}
|
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:
|
ipaddr.js@2.2.0:
|
||||||
resolution: {integrity: sha512-Ag3wB2o37wslZS19hZqorUnrnzSkpOVy+IiiDEiTqNubEYpYuHWIf6K4psgN2ZWKExS4xhVCrRVfb/wfW8fWJA==}
|
resolution: {integrity: sha512-Ag3wB2o37wslZS19hZqorUnrnzSkpOVy+IiiDEiTqNubEYpYuHWIf6K4psgN2ZWKExS4xhVCrRVfb/wfW8fWJA==}
|
||||||
engines: {node: '>= 10'}
|
engines: {node: '>= 10'}
|
||||||
|
@ -292,6 +310,9 @@ packages:
|
||||||
resolution: {integrity: sha512-Xf0nWe6RseziFMu+Ap9biiUbmplq6S9/p+7w7YXP/JBHhrUDDUhwa+vANyubuqfZWTveU//DYVGsDG7RKL/vEw==}
|
resolution: {integrity: sha512-Xf0nWe6RseziFMu+Ap9biiUbmplq6S9/p+7w7YXP/JBHhrUDDUhwa+vANyubuqfZWTveU//DYVGsDG7RKL/vEw==}
|
||||||
engines: {node: '>=0.10.0'}
|
engines: {node: '>=0.10.0'}
|
||||||
|
|
||||||
|
resolve-pkg-maps@1.0.0:
|
||||||
|
resolution: {integrity: sha512-seS2Tj26TBVOC2NIc2rOe2y2ZO7efxITtLZcGSOnHHNOQ7CkiUBfw0Iw2ck6xkIhPwLhKNLS8BO+hEpngQlqzw==}
|
||||||
|
|
||||||
ret@0.5.0:
|
ret@0.5.0:
|
||||||
resolution: {integrity: sha512-I1XxrZSQ+oErkRR4jYbAyEEu2I0avBvvMM5JN+6EBprOGRCs63ENqZ3vjavq8fBw2+62G5LF5XelKwuJpcvcxw==}
|
resolution: {integrity: sha512-I1XxrZSQ+oErkRR4jYbAyEEu2I0avBvvMM5JN+6EBprOGRCs63ENqZ3vjavq8fBw2+62G5LF5XelKwuJpcvcxw==}
|
||||||
engines: {node: '>=10'}
|
engines: {node: '>=10'}
|
||||||
|
@ -335,6 +356,14 @@ packages:
|
||||||
resolution: {integrity: sha512-/m8M+2BJUpoJdgAHoG+baCwBT+tf2VraSfkBgl0Y00qIWt41DJ8R5B8nsEw0I58YwF5IZH6z24/2TobDKnqSWw==}
|
resolution: {integrity: sha512-/m8M+2BJUpoJdgAHoG+baCwBT+tf2VraSfkBgl0Y00qIWt41DJ8R5B8nsEw0I58YwF5IZH6z24/2TobDKnqSWw==}
|
||||||
engines: {node: '>=12'}
|
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:
|
snapshots:
|
||||||
|
|
||||||
'@esbuild/aix-ppc64@0.25.3':
|
'@esbuild/aix-ppc64@0.25.3':
|
||||||
|
@ -435,6 +464,10 @@ snapshots:
|
||||||
'@fastify/forwarded': 3.0.0
|
'@fastify/forwarded': 3.0.0
|
||||||
ipaddr.js: 2.2.0
|
ipaddr.js: 2.2.0
|
||||||
|
|
||||||
|
'@types/node@22.15.2':
|
||||||
|
dependencies:
|
||||||
|
undici-types: 6.21.0
|
||||||
|
|
||||||
abstract-logging@2.0.1: {}
|
abstract-logging@2.0.1: {}
|
||||||
|
|
||||||
ajv-formats@3.0.1(ajv@8.17.1):
|
ajv-formats@3.0.1(ajv@8.17.1):
|
||||||
|
@ -536,6 +569,13 @@ snapshots:
|
||||||
fast-querystring: 1.1.2
|
fast-querystring: 1.1.2
|
||||||
safe-regex2: 5.0.0
|
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: {}
|
ipaddr.js@2.2.0: {}
|
||||||
|
|
||||||
json-schema-ref-resolver@2.0.1:
|
json-schema-ref-resolver@2.0.1:
|
||||||
|
@ -582,6 +622,8 @@ snapshots:
|
||||||
|
|
||||||
require-from-string@2.0.2: {}
|
require-from-string@2.0.2: {}
|
||||||
|
|
||||||
|
resolve-pkg-maps@1.0.0: {}
|
||||||
|
|
||||||
ret@0.5.0: {}
|
ret@0.5.0: {}
|
||||||
|
|
||||||
reusify@1.1.0: {}
|
reusify@1.1.0: {}
|
||||||
|
@ -611,3 +653,12 @@ snapshots:
|
||||||
real-require: 0.2.0
|
real-require: 0.2.0
|
||||||
|
|
||||||
toad-cache@3.7.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: {}
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue