diff --git a/.gitignore b/.gitignore index aa54747..ba8ba77 100644 --- a/.gitignore +++ b/.gitignore @@ -26,4 +26,5 @@ dist-ssr *.private.* -Out/ \ No newline at end of file +Out/ +Backup/ \ No newline at end of file diff --git a/Server/Source/Handlers/Database.ts b/Server/Source/Handlers/Database.ts index c1537be..8379665 100644 --- a/Server/Source/Handlers/Database.ts +++ b/Server/Source/Handlers/Database.ts @@ -1,5 +1,5 @@ import { DataSource } from "typeorm"; -import { ENVIRONMENT } from "../Modules/Constants"; +import { ENVIRONMENT, SAVED_DATA_PATH } from "../Modules/Constants"; import { Song } from "../Schemas/Song"; import { ForcedCategory } from "../Schemas/ForcedCategory"; import { User } from "../Schemas/User"; @@ -7,7 +7,7 @@ import { Rating } from "../Schemas/Rating"; export const DBSource = new DataSource({ type: "better-sqlite3", - database: `Partypack${ENVIRONMENT !== "prod" ? `-${ENVIRONMENT}` : ""}.db`, + database: `${SAVED_DATA_PATH}/Partypack${ENVIRONMENT !== "prod" ? `-${ENVIRONMENT}` : ""}.db`, synchronize: true, logging: false, entities: [ diff --git a/Server/Source/Handlers/Server.ts b/Server/Source/Handlers/Server.ts index a29c25d..26c2120 100644 --- a/Server/Source/Handlers/Server.ts +++ b/Server/Source/Handlers/Server.ts @@ -1,6 +1,6 @@ import e from "express" import fs, { existsSync, mkdirSync } from "fs"; -import { BODY_SIZE_LIMIT, COOKIE_SIGN_KEY, DASHBOARD_ROOT, ENDPOINT_AUTHENTICATION_ENABLED, ENDPOINT_AUTH_HEADER, ENDPOINT_AUTH_VALUE, IS_DEBUG, PORT, PROJECT_NAME, SERVER_URL } from "../Modules/Constants"; +import { SAVED_DATA_PATH, BODY_SIZE_LIMIT, COOKIE_SIGN_KEY, DASHBOARD_ROOT, ENDPOINT_AUTHENTICATION_ENABLED, ENDPOINT_AUTH_HEADER, ENDPOINT_AUTH_VALUE, IS_DEBUG, PORT, PROJECT_NAME, SERVER_URL } from "../Modules/Constants"; import { Debug, Msg, Warn } from "../Modules/Logger"; import { italic, magenta, red, yellow } from "colorette"; import cookieParser from "cookie-parser"; @@ -19,8 +19,8 @@ export const App = e() .use(e.urlencoded({ limit: BODY_SIZE_LIMIT, extended: false })); async function Initialize() { - if (!existsSync("./Saved") || !existsSync("./Saved/Songs")) - mkdirSync("./Saved/Songs", { recursive: true }); + if (!existsSync(SAVED_DATA_PATH) || !existsSync(`${SAVED_DATA_PATH}/Songs`)) + mkdirSync(`${SAVED_DATA_PATH}/Songs`, { recursive: true }); Debug(`The CWD is ${magenta(process.cwd())}.`); diff --git a/Server/Source/Modules/Constants.ts b/Server/Source/Modules/Constants.ts index 2453a07..adcba6f 100644 --- a/Server/Source/Modules/Constants.ts +++ b/Server/Source/Modules/Constants.ts @@ -1,6 +1,7 @@ export const ENVIRONMENT = process.env.ENVIRONMENT ?? "dev"; export const IS_DEBUG = ENVIRONMENT.toLowerCase() === "dev" || ENVIRONMENT.toLowerCase() === "stage"; // IS_DEBUG can be used to enable test endpoints, unsafe code and more. +export const SAVED_DATA_PATH = ENVIRONMENT.toLowerCase() === "prod" || ENVIRONMENT.toLowerCase() === "stage" ? "../Saved" : "./Saved"; export const PROJECT_NAME = process.env.PROJECT_NAME ?? "BasedServer"; // Default prefix for the logger module. export const BODY_SIZE_LIMIT = process.env.BODY_SIZE_LIMIT ?? "10mb"; // Doesn't accept requests with body sizes larger than this value. export const SERVER_URL = process.env.SERVER_URL ?? "localhost"; // The server's URL. Not used for a lot by default. diff --git a/Server/Source/Routes/Drafting.ts b/Server/Source/Routes/Drafting.ts index b726826..55d7ac8 100644 --- a/Server/Source/Routes/Drafting.ts +++ b/Server/Source/Routes/Drafting.ts @@ -9,7 +9,7 @@ import { Debug } from "../Modules/Logger"; import { magenta } from "colorette"; import { fromBuffer } from "file-type"; import { rmSync, writeFileSync, renameSync, readFileSync } from "fs"; -import { FULL_SERVER_ROOT, MAX_AMOUNT_OF_DRAFTS_AT_ONCE } from "../Modules/Constants"; +import { FULL_SERVER_ROOT, MAX_AMOUNT_OF_DRAFTS_AT_ONCE, SAVED_DATA_PATH } from "../Modules/Constants"; import { UserPermissions } from "../Schemas/User"; cron.schedule("*/2 * * * *", async () => { @@ -84,13 +84,13 @@ App.post("/upload/midi", if (SongData.Status !== SongStatus.BROKEN && SongData.Status !== SongStatus.DEFAULT && SongData.Status !== SongStatus.DENIED && SongData.Status !== SongStatus.PUBLIC) return res.status(400).send("You cannot update this song at this moment."); - rmSync(`./Saved/Songs/${req.body.TargetSong}/Data.mid`); + rmSync(`${SAVED_DATA_PATH}/Songs/${req.body.TargetSong}/Data.mid`); SongData.HasMidi = false; SongData.IsDraft = true; await SongData.save(); } - writeFileSync(`./Saved/Songs/${req.body.TargetSong}/Data.mid`, Decoded); + writeFileSync(`${SAVED_DATA_PATH}/Songs/${req.body.TargetSong}/Data.mid`, Decoded); res.send(`${FULL_SERVER_ROOT}/song/download/${req.body.TargetSong}/midi.mid`); await SongData.reload(); @@ -123,7 +123,7 @@ App.post("/upload/cover", if (SongData.Status !== SongStatus.BROKEN && SongData.Status !== SongStatus.DEFAULT && SongData.Status !== SongStatus.DENIED && SongData.Status !== SongStatus.PUBLIC) return res.status(400).send("You cannot update this song at this moment."); - rmSync(`./Saved/Songs/${req.body.TargetSong}/Cover.png`); + rmSync(`${SAVED_DATA_PATH}/Songs/${req.body.TargetSong}/Cover.png`); SongData.HasCover = false; SongData.IsDraft = true; await SongData.save(); @@ -158,7 +158,7 @@ App.post("/upload/cover", SongData.Status = SongData.HasMidi && SongData.HasCover && SongData.HasAudio ? SongStatus.DEFAULT : SongData.Status; await SongData.save(); - writeFileSync(`./Saved/Songs/${req.body.TargetSong}/Cover.png`, Decoded); + writeFileSync(`${SAVED_DATA_PATH}/Songs/${req.body.TargetSong}/Cover.png`, Decoded); res.send(`${FULL_SERVER_ROOT}/song/download/${req.body.TargetSong}/cover.png`); }); @@ -186,29 +186,30 @@ App.post("/upload/audio", if (SongData.Status !== SongStatus.BROKEN && SongData.Status !== SongStatus.DEFAULT && SongData.Status !== SongStatus.DENIED && SongData.Status !== SongStatus.PUBLIC) return res.status(400).send("You cannot update this song at this moment."); - rmSync(`./Saved/Songs/${req.body.TargetSong}/Chunks`, { recursive: true }); + rmSync(`${SAVED_DATA_PATH}/Songs/${req.body.TargetSong}/Chunks`, { recursive: true }); SongData.HasAudio = false; SongData.IsDraft = true; SongData.Status = SongStatus.PROCESSING; await SongData.save(); } - await writeFileSync(`./Saved/Songs/${req.body.TargetSong}/Audio.${ext}`, Decoded); + await writeFileSync(`${SAVED_DATA_PATH}/Songs/${req.body.TargetSong}/Audio.${ext}`, Decoded); ffmpeg() - .input(`./Saved/Songs/${req.body.TargetSong}/Audio.${ext}`) + .input(`${SAVED_DATA_PATH}/Songs/${req.body.TargetSong}/Audio.${ext}`) + .audioCodec("libopus") .outputOptions([ "-use_timeline 1", "-f dash" ]) - .output(`./Saved/Songs/${req.body.TargetSong}/Chunks/Manifest.mpd`) + .output(`${SAVED_DATA_PATH}/Songs/${req.body.TargetSong}/Chunks/Manifest.mpd`) .on("start", cl => Debug(`ffmpeg running with ${magenta(cl)}`)) .on("end", async () => { Debug("Ffmpeg finished running"); - rmSync(`./Saved/Songs/${req.body.TargetSong}/Audio.${ext}`); + rmSync(`${SAVED_DATA_PATH}/Songs/${req.body.TargetSong}/Audio.${ext}`); - renameSync(`./Saved/Songs/${req.body.TargetSong}/Chunks/Manifest.mpd`, `./Saved/Songs/${req.body.TargetSong}/Manifest.mpd`); + renameSync(`${SAVED_DATA_PATH}/Songs/${req.body.TargetSong}/Chunks/Manifest.mpd`, `${SAVED_DATA_PATH}/Songs/${req.body.TargetSong}/Manifest.mpd`); // i love creating thread-safe code that always works! (never gonna error trust me) - writeFileSync(`./Saved/Songs/${req.body.TargetSong}/Manifest.mpd`, readFileSync(`./Saved/Songs/${req.body.TargetSong}/Manifest.mpd`).toString().replace(/[\w\d\r\n\t]*<\/ProgramInformation>/i, "{BASEURL}")); + writeFileSync(`${SAVED_DATA_PATH}/Songs/${req.body.TargetSong}/Manifest.mpd`, readFileSync(`${SAVED_DATA_PATH}/Songs/${req.body.TargetSong}/Manifest.mpd`).toString().replace(/[\w\d\r\n\t]*<\/ProgramInformation>/i, "{BASEURL}")); await SongData.reload(); SongData.HasAudio = true; @@ -218,7 +219,7 @@ App.post("/upload/audio", console.error(e); console.log(stdout); console.error(stderr); - rmSync(`./Saved/Songs/${req.body.TargetSong}/Audio.${ext}`); + rmSync(`${SAVED_DATA_PATH}/Songs/${req.body.TargetSong}/Audio.${ext}`); await SongData.reload(); SongData.Status = SongStatus.BROKEN; diff --git a/Server/Source/Schemas/Song.ts b/Server/Source/Schemas/Song.ts index 2835033..b999cf2 100644 --- a/Server/Source/Schemas/Song.ts +++ b/Server/Source/Schemas/Song.ts @@ -1,5 +1,5 @@ import { BaseEntity, BeforeInsert, BeforeRemove, Column, Entity, ManyToOne, OneToMany, PrimaryGeneratedColumn } from "typeorm"; -import { FULL_SERVER_ROOT } from "../Modules/Constants"; +import { FULL_SERVER_ROOT, SAVED_DATA_PATH } from "../Modules/Constants"; import { Rating } from "./Rating"; import { existsSync, mkdirSync, rmSync } from "fs"; import { v4 } from "uuid"; @@ -102,7 +102,7 @@ export class Song extends BaseEntity { @BeforeInsert() Setup() { this.ID = v4(); - this.Directory = `./Saved/Songs/${this.ID}`; + this.Directory = `${SAVED_DATA_PATH}/Songs/${this.ID}`; if (!existsSync(join(this.Directory, "Chunks"))) mkdirSync(join(this.Directory, "Chunks"), { recursive: true }); diff --git a/Server/Source/Schemas/User.ts b/Server/Source/Schemas/User.ts index 88a5389..cc7b8d2 100644 --- a/Server/Source/Schemas/User.ts +++ b/Server/Source/Schemas/User.ts @@ -15,6 +15,15 @@ export class User extends BaseEntity { @PrimaryColumn() ID: string; + @Column({ default: "unknown" }) + Username: string; + + @Column({ default: "Unknown" }) + DisplayName: string; + + @Column({ nullable: true }) + ProfilePictureURL?: string; + @Column({ type: "simple-json" }) Library: { SongID: string, Overriding: string }[]; diff --git a/index.html b/index.html index f961f13..87c9ef3 100644 --- a/index.html +++ b/index.html @@ -6,9 +6,7 @@ - + diff --git a/package.json b/package.json index dd98e35..97efd3a 100644 --- a/package.json +++ b/package.json @@ -7,19 +7,16 @@ "dev": "vite", "build:prod": "vite build", "build:stage": "vite build --mode staging", - - "win:create:prod": "mkdir \"./Out\" && npm run build:prod && move \"./dist\" \"./Out/dist\" && cd \"Server\" && tsc && cd .. && copy \"./Server/.env.prod\" \"./Out/.env\" && copy \"./Server/package.json\" \"./Out/package.json\" && copy \"./Server/package-lock.json\" \"./Out/package-lock.json\"", - "win:publish:prod": "npm run win:create:prod && ssh partypack \"cd /home/PartypackProd; rm -rf ./Out\" && scp -r \"./Out\" partypack:/home/PartypackProd && ssh partypack \"cd /home/PartypackProd/Out && npm i && pm2 restart PartypackProd --update-env\" && rmdir \"./Out\"", - - "win:create:stage": "mkdir \"./Out\" && npm run build:stage && move \"./dist\" \"./Out/dist\" && cd \"Server\" && tsc && cd .. && copy \"./Server/.env.staging\" \"./Out/.env\" && copy \"./Server/package.json\" \"./Out/package.json\" && copy \"./Server/package-lock.json\" \"./Out/package-lock.json\"", + "win:create:prod": "mkdir \"./Out\" ; vite build ; move \"./dist\" \"./Out/dist\" ; cd \"Server\" ; tsc ; cd .. ; copy \"./Server/.env.prod\" \"./Out/.env\" ; copy \"./Server/package.json\" \"./Out/package.json\" ; copy \"./Server/package-lock.json\" \"./Out/package-lock.json\"", + "win:publish:prod": "npm run win:create:prod ; ssh partypack \"cd /home/PartypackProd; rm -rf ./Out\" ; scp -r \"./Out\" partypack:/home/PartypackProd ; ssh partypack \"cd /home/PartypackProd/Out && npm i && pm2 restart PartypackProd --update-env\" ; rmdir \"./Out\"", + "win:create:stage": "mkdir \"./Out\" && vite build --mode staging && move \"./dist\" \"./Out/dist\" && cd \"Server\" && tsc && cd .. && copy \"./Server/.env.staging\" \"./Out/.env\" && copy \"./Server/package.json\" \"./Out/package.json\" && copy \"./Server/package-lock.json\" \"./Out/package-lock.json\"", "win:publish:stage": "npm run win:create:stage && ssh partypack \"cd /home/PartypackStage; rm -rf ./Out\" && scp -r ./Out partypack:/home/PartypackStage && ssh partypack \"cd /home/PartypackStage/Out && npm i && pm2 restart PartypackStage --update-env\" && rmdir \"./Out\"", - "create:prod": "mkdir ./Out && npm run build:prod && mv ./dist ./Out/dist && cd Server && tsc && cd .. && cp ./Server/.env.prod ./Out/.env && cp ./Server/package.json ./Out && cp ./Server/package-lock.json ./Out", "publish:prod": "npm run create:prod && ssh partypack \"cd /home/PartypackProd; rm -rf ./Out\" && scp -r ./Out partypack:/home/PartypackProd && ssh partypack \"cd /home/PartypackProd/Out && npm i && pm2 restart PartypackProd --update-env\" && rm -rf ./Out", - "create:stage": "mkdir ./Out && npm run build:stage && mv ./dist ./Out/dist && cd Server && tsc && cd .. && cp ./Server/.env.staging ./Out/.env && cp ./Server/package.json ./Out && cp ./Server/package-lock.json ./Out", "publish:stage": "npm run create:stage && ssh partypack \"cd /home/PartypackStage; rm -rf ./Out\" && scp -r ./Out partypack:/home/PartypackStage && ssh partypack \"cd /home/PartypackStage/Out && npm i && pm2 restart PartypackStage --update-env\" && rm -rf ./Out", - + "backup:prod": "scp -r partypack:/home/PartypackProd/Out/Saved ./Backup/Prod/ && scp partypack:/home/PartypackProd/Out/Partypack-prod.db* ./Backup/Prod/", + "backup:stage": "scp -r partypack:/home/PartypackStage/Out/Saved ./Backup/Stage/ && scp partypack:/home/PartypackStage/Out/Partypack-stage.db* ./Backup/Stage/", "lint": "eslint . --ext ts,tsx --report-unused-disable-directives --max-warnings 0", "preview": "vite preview", "dev:all": "start cmd.exe /k \"cd ./Server && npm run dev:watch\" && vite" diff --git a/src/components/SiteHeader.tsx b/src/components/SiteHeader.tsx index 27fde00..6fdf89d 100644 --- a/src/components/SiteHeader.tsx +++ b/src/components/SiteHeader.tsx @@ -2,7 +2,7 @@ import { Avatar, Box, Header } from "@primer/react"; import { SignInIcon } from "@primer/octicons-react" import { useCookies } from "react-cookie"; import { useNavigate } from "react-router-dom"; -import { useContext, useEffect, useState } from "react"; +import { useContext, useEffect } from "react"; import { SiteContext, UserDetailInterface } from "../utils/State"; import { toast } from "react-toastify"; import { Buffer } from "buffer/"; @@ -39,7 +39,7 @@ export function SiteHeader() { navigate("/faq")}>FAQ window.open("https://discord.gg/KaxknAbqDS")}>Discord navigate("/download")}>Download - { state.UserDetails?.IsAdmin ? navigate("/admin")} sx={{ cursor: "pointer", color: "danger.emphasis" }}>Admin : <> } + { state.UserDetails?.IsAdmin ? navigate("/admin")} sx={{ cursor: "pointer", color: "danger.emphasis" }}>Admin : <> } { cookies["Token"] && state.UserDetails ? navigate("/profile")}> : diff --git a/src/css/index.css b/src/css/index.css index 3b4c531..84b5d11 100644 --- a/src/css/index.css +++ b/src/css/index.css @@ -7,10 +7,14 @@ .songCategory { display: inline-flex; - flex: none; - overflow-x: auto; - overflow-y: hidden; gap: 10px; + width: 100%; + overflow-y: hidden; + overflow-x: auto; +} + +.songCategory > * { + flex-shrink: 0; } #__primerPortalRoot__ > div { diff --git a/src/routes/AdminTrackList.tsx b/src/routes/AdminTrackList.tsx index 0778d9d..654a543 100644 --- a/src/routes/AdminTrackList.tsx +++ b/src/routes/AdminTrackList.tsx @@ -24,10 +24,21 @@ export function AdminTrackList() { [ADMIN] All tracks { - tracks.map(x => { + tracks.map((x, i) => { return - + }) } diff --git a/src/routes/Home.tsx b/src/routes/Home.tsx index 0e35844..53d2ba5 100644 --- a/src/routes/Home.tsx +++ b/src/routes/Home.tsx @@ -1,11 +1,13 @@ -import { Box, Text } from "@primer/react"; +import { Box, Heading, Text } from "@primer/react"; export function Home() { return ( <> - online test 2 please kill me thanks - CLICK THE LOGIN ICON ON THE TOP RIGHT + PARTYPACK - Placeholder Place Logo Here + Welcome to Partypack! blah blah someone please make this text for me im way too lazy to do allat + Quickstart Guide + 1. Kill yourself
2. Do it again
)