From acd6d2e9e2e106062dc394165c69deadbf83ccce Mon Sep 17 00:00:00 2001 From: sky Date: Tue, 8 Jul 2025 22:01:16 -0400 Subject: [PATCH] finish up profiles, begin custom songs --- accounts/music.js | 39 +++++++ accounts/profile.js | 2 +- html/profile.html | 129 ++++++++++++++-------- html/profile_edit.html | 244 +++++++++++++++++++++++++++-------------- index.js | 55 ++-------- package-lock.json | 207 +++++++++++++++++++++++++++++++++- package.json | 1 + 7 files changed, 502 insertions(+), 175 deletions(-) create mode 100644 accounts/music.js diff --git a/accounts/music.js b/accounts/music.js new file mode 100644 index 0000000..8a22e36 --- /dev/null +++ b/accounts/music.js @@ -0,0 +1,39 @@ +import Soundcloud from 'lucida/streamers/soundcloud/main.js' +let clientId = process.env.SOUNDCLOUD_CLIENT_ID; + +let sc = new Soundcloud({ + // oauthToken: clientId +}) + +async function search(query) { + let data = sc.search(query); + return data; +} +async function download(url, res) { + if (!url) { + return res.status(400).send('Please provide a SoundCloud track URL as ?url=') + } + + try { + const info = await sc.getByUrl(url) + + if (info.type !== 'track') { + return res.status(400).send('URL is not a SoundCloud track') + } + + const { stream, mimeType, sizeBytes } = await info.getStream() + + res.setHeader('Content-Type', mimeType) + if (sizeBytes) { + res.setHeader('Content-Length', sizeBytes.toString()) + } + res.setHeader('Cache-Control', 'no-cache') + + stream.pipe(res) + } catch (err) { + console.error('Stream error:', err) + res.status(500).send(err.message || 'Failed to stream track') + } +} + +export { search, download }; \ No newline at end of file diff --git a/accounts/profile.js b/accounts/profile.js index e06f5a7..3bc1775 100755 --- a/accounts/profile.js +++ b/accounts/profile.js @@ -235,7 +235,7 @@ async function generateAccountPage(name, cookie, admin) { modifiedHTML = modifiedHTML.replaceAll("{{ user_pfp }}", userData.pfp_url || "/img/user.svg"); modifiedHTML = modifiedHTML.replaceAll("{{ custom_css }}", userData.custom_css || ""); modifiedHTML = modifiedHTML.replaceAll("{{ online_time }}", dayjs(userData.last_login).fromNow()); - modifiedHTML = modifiedHTML.replaceAll("{{ played_games }}", buildGameHTML(userData)); + modifiedHTML = modifiedHTML.replaceAll("{{ username }}", sanitizeHtml(userData.username, allowNone)); let badges_html = ""; if (userData.badges !== null) { diff --git a/html/profile.html b/html/profile.html index 45ab2c8..49a5242 100755 --- a/html/profile.html +++ b/html/profile.html @@ -4,64 +4,99 @@ - - - - - - + + + + + + + + + + + + - + - - + + + + - {{ name }}'s Profile | Selenite + + - -
- Home - Bookmarklets - Games - Apps - Settings - Open Blank - -
-
-
- -
-

{{ name }}

-
{{ badges }}
-

Joined {{ join_date }}

-

Last online {{ online_time }}

-
-
-

About Me

-

{{ about }}

-
+ +

click to enter

this user selected a song, please mute the tab if you don't want to listen

+

{{ name }}'s profile

+
+ +
+

{{ name }}

+

/u/{{ username }}

+
{{ badges }}
-
-

Top Games:

-
- {{ played_games }} -
+
+

{{ song_title }}

+

{{ song_artist }}

+
+

0:00

+ +

9:99

+
+
+ + +
-
- +
+

Joined {{ join_date }}

+

Last online {{ online_time }}

+
+ +
+

about me

+

{{ about }}

+
diff --git a/html/profile_edit.html b/html/profile_edit.html index 413eef8..9b1d41d 100755 --- a/html/profile_edit.html +++ b/html/profile_edit.html @@ -5,18 +5,65 @@ https://coolors.co/10002b-240046-3c096c-5a189a-7b2cbf-9d4edd-c77dff-e0aaff --> - - + + + + + + + + + + + + - + - - + + + + {{ name }}'s Profile | Selenite + + - -
- Home - Bookmarklets - Games - Apps - Settings - Open Blank - -
-
- - -
- - + +
+ + +
+

{{ name }}'s profile

+
+ + +
+
+

{{ name }}

+ +
+

/u/{{ username }}

+
{{ badges }}
-
- {{ css_edit }} +
+

{{ song_title }}

+ +
+

{{ song_artist }}

+
+

0:00

+ +

9:99

+
+
+ + +
-
- +
+

Joined {{ join_date }}

+

Last online {{ online_time }}

+
+
+
+
+

about me

-
-
-

{{ name }}

- -
-
{{ badges }}
-

Joined {{ join_date }}

-

Last online {{ online_time }}

-
-
-
-

Bio

- -
-

{{ about }}

-
-
-

Top Games:

-
- {{ played_games }} -
-
-
- - - - +

{{ about }}

+ diff --git a/index.js b/index.js index 10a42c1..ad1a636 100755 --- a/index.js +++ b/index.js @@ -1,4 +1,3 @@ -const io = require('@pm2/io') import { log } from "./log.js"; import bodyParser from "body-parser"; import express from "express"; @@ -10,6 +9,7 @@ import mime from "mime-types"; import compression from "compression"; import { accs, infdb, polytrack } from "./database.js"; import { } from "./accounts/friend.js"; +import { search, download } from "./accounts/music.js"; import { banUser, removeAccount, verifyCookie, getUserFromCookie, createAccount, resetPassword, loginAccount, addBadge } from "./accounts/manage.js"; import { } from "./accounts/misc.js"; import { getRawData, generateAccountPage, editProfile, saveData, getUsers, isAdmin, retrieveData } from "./accounts/profile.js"; @@ -26,29 +26,13 @@ app.use(cookieParser()); app.use(express.json({ limit: "10mb" })); app.use(express.urlencoded({ extended: false })); app.use(express.text()); -let requests = 0; -const requestsPerSec = io.meter({ - name: 'req/sec', - id: 'app/requests/sec' -}); -const requestsPerMin = io.meter({ - name: 'req/min', - id: 'app/requests/min' -}); app.use("/", (req, res, next) => { - requestsPerSec.mark(); - requestsPerMin.mark(); next(); }); -const sockets = io.metric({ - name: 'Open Websockets', - id: 'app/requests/sockets', -}); // setInterval(()=>{ // }, 1000) import WebSocket, { WebSocketServer } from "ws"; -import { request } from "node:http"; const wss = new WebSocketServer({ noServer: true }); let openSockets = 0; wss.on("connection", function connection(ws, req, res) { @@ -77,32 +61,11 @@ wss.on("connection", function connection(ws, req, res) { if (ws.id) { const updateAccount = accs.query(`UPDATE accounts SET last_login = $login WHERE username = $user`) updateAccount.get({ $login: new Date().toUTCString(), $user: ws.id }); - if (message.substring(4)) { - const existingAccount = accs.query(`SELECT * FROM accounts WHERE username LIKE $1`) - let userData = existingAccount.get({ $1: ws.id }); - if (userData == null) { - return { success: false, reason: "The account doesn't exist." }; - } - let games; - if (userData.playedgames) { - games = JSON.parse(userData.playedgames); - } else { - games = {}; - } - if (games[message.substring(4)]) { - games[message.substring(4)] += 30; - } else { - games[message.substring(4)] = 30; - } - const updateAccount = accs.query(`UPDATE accounts SET playedgames = $playedgames WHERE username = $user`) - updateAccount.get({ $playedgames: JSON.stringify(games), $user: ws.id }); - } } } }); - ws.on("close", () => {openSockets--; - sockets.set(openSockets);}); + ws.on("close", () => {openSockets--;}); }); app.post( "/api/event", @@ -120,11 +83,6 @@ app.post( }) } ); -// app.use("*.json", async (req, res, next) => { -// optimize json -// console.log("got data"); -// next() -// }); app.post("/register", async (req, res) => { let status = await createAccount(req.body.username, req.body.password, req.body["h-captcha-response"]); if (status["success"]) { @@ -477,6 +435,15 @@ app.post("/api/admin/ban", async (req, res) => { let status = await banUser(req.body.name, req.body.reason, req.cookies.token); res.status(200).send(status); }); + + +app.use("/api/music/search", async (req, res, next) => { + res.status(200).send(await search(req.query.q)) +}); +app.use("/api/music/download", async (req, res, next) => { + await download(req.query.url, res); +}); + const server = app.listen(port, () => { console.log(log.success("Express is online.")); console.log("- " + log.info("http://localhost:" + port)); diff --git a/package-lock.json b/package-lock.json index 5941336..ffe0ab7 100755 --- a/package-lock.json +++ b/package-lock.json @@ -21,6 +21,7 @@ "fast-glob": "^3.3.2", "file-type": "^19.0.0", "install": "^0.13.0", + "lucida": "^2.0.0-54", "mime-types": "^2.1.35", "node-html-parser": "^6.1.13", "openai": "^4.85.3", @@ -40,6 +41,15 @@ "tslib": "^2.4.0" } }, + "node_modules/@fastify/busboy": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/@fastify/busboy/-/busboy-2.1.1.tgz", + "integrity": "sha512-vBZP4NlzfOlerQTnba4aqZoMhE/a9HY7HRqoOPaETQcSQuWEIyZMHGfVu6w9wGtGK5fED5qRs2DteVCjOH60sA==", + "license": "MIT", + "engines": { + "node": ">=14" + } + }, "node_modules/@img/sharp-darwin-arm64": { "version": "0.33.4", "resolved": "https://registry.npmjs.org/@img/sharp-darwin-arm64/-/sharp-darwin-arm64-0.33.4.tgz", @@ -569,6 +579,70 @@ "integrity": "sha512-4krF8scpejhaOgqzBEcGM7yDIEfi0/8+8zDRZhNZZ2kjmHJ4hv3zCbQWxoJGz1iw5U0Jl0nma13xzHXcncMavQ==", "license": "Apache-2.0" }, + "node_modules/@protobufjs/aspromise": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/@protobufjs/aspromise/-/aspromise-1.1.2.tgz", + "integrity": "sha512-j+gKExEuLmKwvz3OgROXtrJ2UG2x8Ch2YZUxahh+s1F2HZ+wAceUNLkvy6zKCPVRkU++ZWQrdxsUeQXmcg4uoQ==", + "license": "BSD-3-Clause" + }, + "node_modules/@protobufjs/base64": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/@protobufjs/base64/-/base64-1.1.2.tgz", + "integrity": "sha512-AZkcAA5vnN/v4PDqKyMR5lx7hZttPDgClv83E//FMNhR2TMcLUhfRUBHCmSl0oi9zMgDDqRUJkSxO3wm85+XLg==", + "license": "BSD-3-Clause" + }, + "node_modules/@protobufjs/codegen": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/@protobufjs/codegen/-/codegen-2.0.4.tgz", + "integrity": "sha512-YyFaikqM5sH0ziFZCN3xDC7zeGaB/d0IUb9CATugHWbd1FRFwWwt4ld4OYMPWu5a3Xe01mGAULCdqhMlPl29Jg==", + "license": "BSD-3-Clause" + }, + "node_modules/@protobufjs/eventemitter": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@protobufjs/eventemitter/-/eventemitter-1.1.0.tgz", + "integrity": "sha512-j9ednRT81vYJ9OfVuXG6ERSTdEL1xVsNgqpkxMsbIabzSo3goCjDIveeGv5d03om39ML71RdmrGNjG5SReBP/Q==", + "license": "BSD-3-Clause" + }, + "node_modules/@protobufjs/fetch": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@protobufjs/fetch/-/fetch-1.1.0.tgz", + "integrity": "sha512-lljVXpqXebpsijW71PZaCYeIcE5on1w5DlQy5WH6GLbFryLUrBD4932W/E2BSpfRJWseIL4v/KPgBFxDOIdKpQ==", + "license": "BSD-3-Clause", + "dependencies": { + "@protobufjs/aspromise": "^1.1.1", + "@protobufjs/inquire": "^1.1.0" + } + }, + "node_modules/@protobufjs/float": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/@protobufjs/float/-/float-1.0.2.tgz", + "integrity": "sha512-Ddb+kVXlXst9d+R9PfTIxh1EdNkgoRe5tOX6t01f1lYWOvJnSPDBlG241QLzcyPdoNTsblLUdujGSE4RzrTZGQ==", + "license": "BSD-3-Clause" + }, + "node_modules/@protobufjs/inquire": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@protobufjs/inquire/-/inquire-1.1.0.tgz", + "integrity": "sha512-kdSefcPdruJiFMVSbn801t4vFK7KB/5gd2fYvrxhuJYg8ILrmn9SKSX2tZdV6V+ksulWqS7aXjBcRXl3wHoD9Q==", + "license": "BSD-3-Clause" + }, + "node_modules/@protobufjs/path": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/@protobufjs/path/-/path-1.1.2.tgz", + "integrity": "sha512-6JOcJ5Tm08dOHAbdR3GrvP+yUUfkjG5ePsHYczMFLq3ZmMkAD98cDgcT2iA1lJ9NVwFd4tH/iSSoe44YWkltEA==", + "license": "BSD-3-Clause" + }, + "node_modules/@protobufjs/pool": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@protobufjs/pool/-/pool-1.1.0.tgz", + "integrity": "sha512-0kELaGSIDBKvcgS4zkjz1PeddatrjYcmMWOlAuAPwAeccUrPHdUqo/J6LiymHHEiJT5NrF1UVwxY14f+fy4WQw==", + "license": "BSD-3-Clause" + }, + "node_modules/@protobufjs/utf8": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@protobufjs/utf8/-/utf8-1.1.0.tgz", + "integrity": "sha512-Vvn3zZrhQZkkBE8LSuW3em98c0FwgO4nxzv6OdSxPKJIEKY2bGbHn+mhGIPerzI4twdxaP8/0+06HBpwf345Lw==", + "license": "BSD-3-Clause" + }, "node_modules/@tokenizer/token": { "version": "0.3.0", "resolved": "https://registry.npmjs.org/@tokenizer/token/-/token-0.3.0.tgz", @@ -664,9 +738,9 @@ "integrity": "sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q==" }, "node_modules/axios": { - "version": "1.7.4", - "resolved": "https://registry.npmjs.org/axios/-/axios-1.7.4.tgz", - "integrity": "sha512-DukmaFRnY6AzAALSH4J2M3k6PkaC+MfaAGdEERRWcC9q3/TWQwLpHR8ZRLKTdQ3aBDL64EdluRDjJqKw+BPZEw==", + "version": "1.10.0", + "resolved": "https://registry.npmjs.org/axios/-/axios-1.10.0.tgz", + "integrity": "sha512-/1xYAC4MP/HEG+3duIhFr4ZQXR4sQXOIe+o6sdqzeykGLx6Upp/1p8MHqhINOvGeP7xyNHe7tsiJByc4SSVUxw==", "license": "MIT", "dependencies": { "follow-redirects": "^1.15.6", @@ -674,6 +748,17 @@ "proxy-from-env": "^1.1.0" } }, + "node_modules/blowfish-cbc": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/blowfish-cbc/-/blowfish-cbc-1.0.1.tgz", + "integrity": "sha512-o1JN6g6+ATW/4k7q1BZzy14VqLxwYa1mCii47qT4kmAaYD0NAfdM6/pz6uizbhTra/xunsPQI27LZt08OQS4sA==", + "deprecated": "Package no longer supported. Contact Support at https://www.npmjs.com/support for more info.", + "hasInstallScript": true, + "license": "MIT", + "dependencies": { + "node-addon-api": "^8.1.0" + } + }, "node_modules/body-parser": { "version": "2.0.2", "resolved": "https://registry.npmjs.org/body-parser/-/body-parser-2.0.2.tgz", @@ -1661,6 +1746,21 @@ } ] }, + "node_modules/image-size": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/image-size/-/image-size-1.2.1.tgz", + "integrity": "sha512-rH+46sQJ2dlwfjfhCyNx5thzrv+dtmBIhPHk0zgRUukHzZ/kRueTJXoYYsclBaKcSMBWuGbOFXtioLpzTb5euw==", + "license": "MIT", + "dependencies": { + "queue": "6.0.2" + }, + "bin": { + "image-size": "bin/image-size.js" + }, + "engines": { + "node": ">=16.x" + } + }, "node_modules/inflection": { "version": "1.13.4", "resolved": "https://registry.npmjs.org/inflection/-/inflection-1.13.4.tgz", @@ -1754,11 +1854,39 @@ "integrity": "sha512-hvpoI6korhJMnej285dSg6nu1+e6uxs7zG3BYAm5byqDsgJNWwxzM6z6iZiAgQR4TJ30JmBTOwqZUw3WlyH3AQ==", "license": "MIT" }, + "node_modules/librespot": { + "version": "0.2.22", + "resolved": "https://registry.npmjs.org/librespot/-/librespot-0.2.22.tgz", + "integrity": "sha512-szLknWSrgF+mRuypNXQTmdq8PGGhgPRAazm8sJmD8wiCAbtO9LYHihZhQcRmCzmVz818sRHZM/BU6K6XslXSHQ==", + "license": "MIT", + "dependencies": { + "protobufjs": "^7.2.5", + "undici": "^5.27.0" + } + }, + "node_modules/librespot/node_modules/undici": { + "version": "5.29.0", + "resolved": "https://registry.npmjs.org/undici/-/undici-5.29.0.tgz", + "integrity": "sha512-raqeBD6NQK4SkWhQzeYKd1KmIG6dllBOTt55Rmkt4HtI9mwdWtJljnrXjAFUBLTSN67HWrOIZ3EPF4kjUw80Bg==", + "license": "MIT", + "dependencies": { + "@fastify/busboy": "^2.0.0" + }, + "engines": { + "node": ">=14.0" + } + }, "node_modules/lodash": { "version": "4.17.21", "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.21.tgz", "integrity": "sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==" }, + "node_modules/long": { + "version": "5.3.2", + "resolved": "https://registry.npmjs.org/long/-/long-5.3.2.tgz", + "integrity": "sha512-mNAgZ1GmyNhD7AuqnTG3/VQ26o760+ZYBPKjPvugO8+nLbYfX6TVpJPseBvopbdY+qpZ/lKUnmEc1LeZYS3QAA==", + "license": "Apache-2.0" + }, "node_modules/lru-cache": { "version": "6.0.0", "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-6.0.0.tgz", @@ -1771,6 +1899,19 @@ "node": ">=10" } }, + "node_modules/lucida": { + "version": "2.0.0-54", + "resolved": "https://registry.npmjs.org/lucida/-/lucida-2.0.0-54.tgz", + "integrity": "sha512-3Y24WkCI1Ks6EjOAElYAeYXkxT/HtunEW+SnhDKFb681B/QEMhS/EzLzFi8D5l95/pOVODUZQMMxYNKmMMC1fQ==", + "license": "OQL", + "dependencies": { + "blowfish-cbc": "^1.0.1", + "image-size": "^1.1.1", + "librespot": "^0.2.21", + "undici": "^6.19.4", + "xmldom-qsa": "^1.1.3" + } + }, "node_modules/media-typer": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/media-typer/-/media-typer-1.1.0.tgz", @@ -1897,6 +2038,15 @@ "node": ">= 0.6" } }, + "node_modules/node-addon-api": { + "version": "8.4.0", + "resolved": "https://registry.npmjs.org/node-addon-api/-/node-addon-api-8.4.0.tgz", + "integrity": "sha512-D9DI/gXHvVmjHS08SVch0Em8G5S1P+QWtU31appcKT/8wFSPRcdHadIFSAntdMMVM5zz+/DL+bL/gz3UDppqtg==", + "license": "MIT", + "engines": { + "node": "^18 || ^20 || >= 21" + } + }, "node_modules/node-domexception": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/node-domexception/-/node-domexception-1.0.0.tgz", @@ -2125,6 +2275,30 @@ "node": "^10 || ^12 || >=14" } }, + "node_modules/protobufjs": { + "version": "7.5.3", + "resolved": "https://registry.npmjs.org/protobufjs/-/protobufjs-7.5.3.tgz", + "integrity": "sha512-sildjKwVqOI2kmFDiXQ6aEB0fjYTafpEvIBs8tOR8qI4spuL9OPROLVu2qZqi/xgCfsHIwVqlaF8JBjWFHnKbw==", + "hasInstallScript": true, + "license": "BSD-3-Clause", + "dependencies": { + "@protobufjs/aspromise": "^1.1.2", + "@protobufjs/base64": "^1.1.2", + "@protobufjs/codegen": "^2.0.4", + "@protobufjs/eventemitter": "^1.1.0", + "@protobufjs/fetch": "^1.1.0", + "@protobufjs/float": "^1.0.2", + "@protobufjs/inquire": "^1.1.0", + "@protobufjs/path": "^1.1.2", + "@protobufjs/pool": "^1.1.0", + "@protobufjs/utf8": "^1.1.0", + "@types/node": ">=13.7.0", + "long": "^5.0.0" + }, + "engines": { + "node": ">=12.0.0" + } + }, "node_modules/proxy-addr": { "version": "2.0.7", "resolved": "https://registry.npmjs.org/proxy-addr/-/proxy-addr-2.0.7.tgz", @@ -2157,6 +2331,15 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/queue": { + "version": "6.0.2", + "resolved": "https://registry.npmjs.org/queue/-/queue-6.0.2.tgz", + "integrity": "sha512-iHZWu+q3IdFZFX36ro/lKBkSvfkztY5Y7HMiPlOUjhupPcG2JMfst2KKEpu5XndviX/3UhFbRngUPNKtgvtZiA==", + "license": "MIT", + "dependencies": { + "inherits": "~2.0.3" + } + }, "node_modules/queue-microtask": { "version": "1.2.3", "resolved": "https://registry.npmjs.org/queue-microtask/-/queue-microtask-1.2.3.tgz", @@ -2826,6 +3009,15 @@ "node": ">= 0.6" } }, + "node_modules/undici": { + "version": "6.21.3", + "resolved": "https://registry.npmjs.org/undici/-/undici-6.21.3.tgz", + "integrity": "sha512-gBLkYIlEnSp8pFbT64yFgGE6UIB9tAkhukC23PmMDCe5Nd+cRqKxSjw5y54MK2AZMgZfJWMaNE4nYUHgi1XEOw==", + "license": "MIT", + "engines": { + "node": ">=18.17" + } + }, "node_modules/undici-types": { "version": "5.26.5", "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-5.26.5.tgz", @@ -2924,6 +3116,15 @@ } } }, + "node_modules/xmldom-qsa": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/xmldom-qsa/-/xmldom-qsa-1.1.3.tgz", + "integrity": "sha512-IJBOczBpAYrIBJFFsmCBwfBhwe4zdMR3Xz0ZBX0OFtgO49rLy/BWbhkegOwsthdBWb1gUtFK6ZZnGdT8ZqPRBA==", + "license": "MIT", + "engines": { + "node": ">=8.0.0" + } + }, "node_modules/yallist": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", diff --git a/package.json b/package.json index 38d6312..0c97e11 100755 --- a/package.json +++ b/package.json @@ -24,6 +24,7 @@ "fast-glob": "^3.3.2", "file-type": "^19.0.0", "install": "^0.13.0", + "lucida": "^2.0.0-54", "mime-types": "^2.1.35", "node-html-parser": "^6.1.13", "openai": "^4.85.3",