Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
66 changes: 66 additions & 0 deletions pkgs/by-name/je/jellystat/package.nix
Original file line number Diff line number Diff line change
@@ -0,0 +1,66 @@
{
lib,
buildNpmPackage,
fetchFromGitHub,
makeWrapper,
nodejs_22,
}:
buildNpmPackage (finalAttrs: {
pname = "jellystat";
version = "1.1.11";

__structuredAttrs = true;

src = fetchFromGitHub {
owner = "CyferShepard";
repo = "Jellystat";
tag = finalAttrs.version;
hash = "sha256-HuLSXhj90fPfxv5qyCVCY67w07WwTBGp220iG9dGZyk=";
};

patches = [
./remove-hardcoded-path.patch
];

npmDepsFetcherVersion = 2;

npmDepsHash = "sha256-yfcrBLbD11x3Siqv670jw8A3K11DrwnBj0VSC64JBP0=";

makeCacheWritable = true;

nodejs = nodejs_22;

npmPackFlags = [ "--ignore-scripts" ];
npmFlags = [ "--legacy-peer-deps" ];

env.NODE_OPTIONS = "--openssl-legacy-provider";

postPatch = ''
substituteInPlace backend/server.js \
--replace-fail "const PORT = 3000;" "const PORT = Number(process.env.JS_PORT || 3000);"
'';

nativeBuildInputs = [ makeWrapper ];

installPhase = ''
runHook preInstall

mkdir -p $out/share/jellystat $out/bin
cp -r . $out/share/jellystat/

makeWrapper ${nodejs_22}/bin/node $out/bin/jellystat \
--chdir $out/share/jellystat \
--add-flags $out/share/jellystat/backend/server.js

runHook postInstall
'';

meta = with lib; {
description = "Jellystat is a free and open source Statistics App for Jellyfin";
homepage = "https://github.com/CyferShepard/Jellystat";
license = licenses.mit;
maintainers = with maintainers; [ mistyttm ];
mainProgram = "jellystat";
platforms = platforms.linux;
};
})
151 changes: 151 additions & 0 deletions pkgs/by-name/je/jellystat/remove-hardcoded-path.patch
Original file line number Diff line number Diff line change
@@ -0,0 +1,151 @@
diff --git a/backend/classes/backup.js b/backend/classes/backup.js
index 981b7d6..c6b4124 100644
--- a/backend/classes/backup.js
+++ b/backend/classes/backup.js
@@ -15,7 +15,9 @@ const postgresPassword = process.env.POSTGRES_PASSWORD;
const postgresIp = process.env.POSTGRES_IP;
const postgresPort = process.env.POSTGRES_PORT;
const postgresDatabase = process.env.POSTGRES_DB || "jfstat";
-const backupfolder = "backup-data";
+const backupfolder = process.env.JS_BACKUP_DIR
+ ? path.resolve(process.env.JS_BACKUP_DIR)
+ : path.join(__dirname, "..", "backup-data");

function checkFolderWritePermission(folderPath) {
try {
@@ -51,7 +53,7 @@ async function backup(refLog) {

try {
let now = dayjs();
- const backuppath = "./" + backupfolder;
+ const backuppath = backupfolder;

if (!fs.existsSync(backuppath)) {
fs.mkdirSync(backuppath);
@@ -79,7 +81,7 @@ async function backup(refLog) {
}

// const backupPath = `../backup-data/backup_${now.format('YYYY-MM-DD HH-mm-ss')}.json`;
- const directoryPath = path.join(__dirname, "..", backupfolder, `backup_${now.format("YYYY-MM-DD HH-mm-ss")}.json`);
+ const directoryPath = path.join(backupfolder, `backup_${now.format("YYYY-MM-DD HH-mm-ss")}.json`);
refLog.logData.push({ color: "yellow", Message: "Begin Backup " + directoryPath });
const stream = fs.createWriteStream(directoryPath, { flags: "a" });
stream.on("error", async (error) => {
@@ -105,7 +107,7 @@ async function backup(refLog) {

//Cleanup excess backups
let deleteCount = 0;
- const directoryPathDelete = path.join(__dirname, "..", backupfolder);
+ const directoryPathDelete = backupfolder;

const files = await new Promise((resolve, reject) => {
fs.readdir(directoryPathDelete, (err, files) => {
@@ -132,7 +134,7 @@ async function backup(refLog) {
fileData = fileData.sort((a, b) => new Date(b.datecreated) - new Date(a.datecreated)).slice(5);

for (var oldBackup of fileData) {
- const oldBackupFile = path.join(__dirname, "..", backupfolder, oldBackup.name);
+ const oldBackupFile = path.join(backupfolder, oldBackup.name);

await new Promise((resolve, reject) => {
fs.unlink(oldBackupFile, (err) => {
diff --git a/backend/classes/env.js b/backend/classes/env.js
index afb76e7..5863934 100644
--- a/backend/classes/env.js
+++ b/backend/classes/env.js
@@ -16,7 +16,12 @@ async function writeEnvVariables() {
const envContent = `window.env = ${JSON.stringify(envVariables, null, 2)};`;

// Define the output file path
- const outputPath = path.join(__dirname, "..", "..", "dist", "env.js");
+ const envDir = process.env.JS_ENV_DIR ? path.resolve(process.env.JS_ENV_DIR) : path.join(__dirname, "..", "..", "dist");
+ const outputPath = path.join(envDir, "env.js");
+
+ if (process.env.JS_ENV_DIR) {
+ fs.mkdirSync(envDir, { recursive: true });
+ }

// Write the environment variables to the file
fs.writeFile(outputPath, envContent, "utf8", (err) => {
diff --git a/backend/routes/backup.js b/backend/routes/backup.js
index cfc3d3f..12d9b32 100644
--- a/backend/routes/backup.js
+++ b/backend/routes/backup.js
@@ -25,7 +25,9 @@ const postgresPort = process.env.POSTGRES_PORT;
const postgresDatabase = process.env.POSTGRES_DB || "jfstat";
const postgresSslRejectUnauthorized = process.env.POSTGRES_SSL_REJECT_UNAUTHORIZED === undefined ? true : process.env.POSTGRES_SSL_REJECT_UNAUTHORIZED === "true";

-const backupfolder = "backup-data";
+const backupfolder = process.env.JS_BACKUP_DIR
+ ? path.resolve(process.env.JS_BACKUP_DIR)
+ : path.join(__dirname, "..", "backup-data");

// Restore function

@@ -187,7 +189,7 @@ router.get("/restore/:filename", async (req, res) => {
Logging.insertLog(uuid, triggertype.Manual, taskName.restore);

const filename = sanitizeFilename(req.params.filename);
- const filePath = path.join(__dirname, "..", backupfolder, filename);
+ const filePath = path.join(backupfolder, filename);

await restore(filePath, refLog);
Logging.updateLog(uuid, refLog.logData, taskstate.SUCCESS);
@@ -202,7 +204,7 @@ router.get("/restore/:filename", async (req, res) => {

router.get("/files", (req, res) => {
try {
- const directoryPath = path.join(__dirname, "..", backupfolder);
+ const directoryPath = backupfolder;
fs.readdir(directoryPath, (err, files) => {
if (err) {
res.status(500).send("Unable to read directory");
@@ -229,7 +231,7 @@ router.get("/files", (req, res) => {
//download backup file
router.get("/files/:filename", (req, res) => {
const filename = sanitizeFilename(req.params.filename);
- const filePath = path.join(__dirname, "..", backupfolder, filename);
+ const filePath = path.join(backupfolder, filename);
res.download(filePath);
});

@@ -237,7 +239,7 @@ router.get("/files/:filename", (req, res) => {
router.delete("/files/:filename", (req, res) => {
try {
const filename = sanitizeFilename(req.params.filename);
- const filePath = path.join(__dirname, "..", backupfolder, filename);
+ const filePath = path.join(backupfolder, filename);

fs.unlink(filePath, (err) => {
if (err) {
@@ -256,7 +258,7 @@ router.delete("/files/:filename", (req, res) => {

const storage = multer.diskStorage({
destination: function (req, file, cb) {
- cb(null, path.join(__dirname, "..", backupfolder)); // Set the destination folder for uploaded files
+ cb(null, backupfolder); // Set the destination folder for uploaded files
},
filename: function (req, file, cb) {
cb(null, file.originalname); // Set the file name
diff --git a/backend/server.js b/backend/server.js
index d70975d..1898ec6 100644
--- a/backend/server.js
+++ b/backend/server.js
@@ -106,6 +106,17 @@ const findFile = (dir, fileName) => {

const root = path.join(__dirname, "..", "dist");

+// When JS_ENV_DIR is set, env.js is written outside of `root` (e.g. because
+// `root` lives on a read-only filesystem), so serve it explicitly from
+// there instead of relying on the findFile() lookup below, which only
+// searches under `root`.
+if (process.env.JS_ENV_DIR) {
+ const envDir = path.resolve(process.env.JS_ENV_DIR);
+ app.get(/\/env\.js$/, (req, res) => {
+ res.sendFile(path.join(envDir, "env.js"));
+ });
+}
+
//hacky middleware to handle basename changes for UI

app.use((req, res, next) => {
Loading