@anandaramr/obscura 1.1.1 → 1.2.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -29,30 +29,48 @@ npx @anandaramr/obscura [directory]
29
29
 
30
30
  ## Usage
31
31
 
32
- To spin up Obscura, pass the path to your media gallery folder as the default argument:
32
+ ### Starting the server
33
33
 
34
34
  ```bash
35
- obscura /path/to/your/media/gallery
35
+ obscura [directory] [options]
36
36
  ```
37
37
 
38
- ### CLI Command Options
38
+ Serves the specified directory (defaults to the current directory). Open the displayed URL on any device in your local network to browse the gallery.
39
39
 
40
- You can fully customize how the server binds, hosts, and reads from disk using flag configurations:
40
+ ```bash
41
+ obscura /path/to/media
42
+ obscura -p 8080 # custom port
43
+ obscura -a 192.168.1.10 /path/to/media # bind to specific interface
44
+ ```
45
+
46
+ | Flag | Description | Default |
47
+ |------|-------------|---------|
48
+ | `-a, --address <ip>` | Address to bind to | `0.0.0.0` |
49
+ | `-p, --port <number>` | Port to listen on | `4963` |
50
+ | `--disk-concurrency <number>` | Max concurrent disk operations | `3` |
51
+ | `-v, --version` | Print version | |
52
+ | `-h, --help` | Show help | |
53
+
54
+ ### Indexing a directory
55
+
56
+ Pre-build the cache for a directory. Useful for large libraries.
41
57
 
42
58
  ```bash
43
- Usage: obscura [options] [directory]
59
+ obscura index /path/to/media
60
+ obscura index /path/to/media --refresh # rebuild, overwriting existing cache
61
+ ```
44
62
 
45
- Lightweight self-hosted media gallery server for local networks
63
+ | Flag | Description |
64
+ |------|-------------|
65
+ | `-r, --refresh` | Overwrite existing cache entries |
46
66
 
47
- Arguments:
48
- directory Directory to serve (default: ".")
67
+ ### Managing the cache
49
68
 
50
- Options:
51
- -v, --version output the version number
52
- -a, --address <ip> Address to bind to (default: "0.0.0.0")
53
- -p, --port <number> Port to listen to (default: "4963")
54
- --disk-concurrency <number> Maximum number of concurrent disk operations (default: "3")
55
- -h, --help display help for command
69
+ Inspect and manage the application cache.
70
+
71
+ ```bash
72
+ obscura cache stats # show cache size and storage statistics
73
+ obscura cache clean # delete all cached data
56
74
  ```
57
75
 
58
76
  ## Environment Variables
@@ -0,0 +1,8 @@
1
+ import type { FileMetaData } from "./types.js";
2
+ export declare const THUMBS_DIR: string;
3
+ export declare function getCacheSize(): Promise<number>;
4
+ export declare function emptyCache(): Promise<number>;
5
+ export declare function shouldAvoidCaching(file: FileMetaData, threshold: number): boolean;
6
+ export declare function getThumbPath(fileId: string): string;
7
+ export declare function isAlreadyCached(fileId: string): boolean;
8
+ //# sourceMappingURL=cache.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"cache.d.ts","sourceRoot":"","sources":["../src/cache.ts"],"names":[],"mappings":"AAIA,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,YAAY,CAAA;AAE9C,eAAO,MAAM,UAAU,QAAkD,CAAA;AAEzE,wBAAsB,YAAY,IAAI,OAAO,CAAC,MAAM,CAAC,CAkBpD;AAED,wBAAsB,UAAU,oBAoB/B;AAaD,wBAAgB,kBAAkB,CAAC,IAAI,EAAE,YAAY,EAAE,SAAS,EAAE,MAAM,WAEvE;AAED,wBAAgB,YAAY,CAAC,MAAM,EAAE,MAAM,UAE1C;AAED,wBAAgB,eAAe,CAAC,MAAM,EAAE,MAAM,WAE7C"}
package/dist/cache.js ADDED
@@ -0,0 +1,61 @@
1
+ import path from "path";
2
+ import fs from "fs/promises";
3
+ import fsSync from "fs";
4
+ import { defaults, PROJECT_ROOT } from "./config.js";
5
+ export const THUMBS_DIR = path.resolve(PROJECT_ROOT, defaults.THUMBS_DIR);
6
+ export async function getCacheSize() {
7
+ let totalSize = 0;
8
+ let files;
9
+ try {
10
+ files = await fs.readdir(THUMBS_DIR, { withFileTypes: true });
11
+ }
12
+ catch (e) {
13
+ if (compareErrorCode(e, "ENOENT"))
14
+ return 0;
15
+ throw e;
16
+ }
17
+ for (const file of files) {
18
+ const fullPath = path.join(THUMBS_DIR, file.name);
19
+ const stats = await fs.stat(fullPath);
20
+ totalSize += stats.size;
21
+ }
22
+ return totalSize;
23
+ }
24
+ export async function emptyCache() {
25
+ let totalSize = 0;
26
+ let files;
27
+ try {
28
+ files = await fs.readdir(THUMBS_DIR);
29
+ }
30
+ catch (e) {
31
+ if (compareErrorCode(e, "ENOENT"))
32
+ return 0;
33
+ throw e;
34
+ }
35
+ for (const file of files) {
36
+ const fullPath = path.join(THUMBS_DIR, file);
37
+ const stats = await fs.stat(fullPath);
38
+ totalSize += stats.size;
39
+ await fs.rm(fullPath, { force: true });
40
+ }
41
+ return totalSize;
42
+ }
43
+ function compareErrorCode(e, code) {
44
+ if (typeof e === "object" && e !== null && "code" in e) {
45
+ const err = e;
46
+ if (err.code === code) {
47
+ return true;
48
+ }
49
+ }
50
+ return false;
51
+ }
52
+ export function shouldAvoidCaching(file, threshold) {
53
+ return file.type == "image" && file.size < threshold && !file.isAnimated;
54
+ }
55
+ export function getThumbPath(fileId) {
56
+ return path.join(THUMBS_DIR, `${fileId}.jpg`);
57
+ }
58
+ export function isAlreadyCached(fileId) {
59
+ return fsSync.existsSync(getThumbPath(fileId));
60
+ }
61
+ //# sourceMappingURL=cache.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"cache.js","sourceRoot":"","sources":["../src/cache.ts"],"names":[],"mappings":"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"}
package/dist/config.d.ts CHANGED
@@ -1,8 +1,9 @@
1
1
  import type { DefaultConfig } from "./types.js";
2
+ export declare const PROJECT_ROOT: string;
2
3
  export declare const defaults: DefaultConfig;
3
4
  export declare function parsePort(p: string): number;
4
5
  export declare function parseDiskConcurrency(conc: string): number;
5
6
  export declare function parseDirectory(dir: string): string;
6
7
  export declare function parseAddress(ip: string): string;
7
- export declare function getFfmpegPath(): string | null;
8
+ export declare function getFfmpegPath(): Promise<string>;
8
9
  //# sourceMappingURL=config.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"config.d.ts","sourceRoot":"","sources":["../src/config.ts"],"names":[],"mappings":"AAIA,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,YAAY,CAAA;AAE/C,eAAO,MAAM,QAAQ,EAAE,aAStB,CAAA;AAED,wBAAgB,SAAS,CAAC,CAAC,EAAE,MAAM,UAMlC;AAED,wBAAgB,oBAAoB,CAAC,IAAI,EAAE,MAAM,UAMhD;AAED,wBAAgB,cAAc,CAAC,GAAG,EAAE,MAAM,UAOzC;AAED,wBAAgB,YAAY,CAAC,EAAE,EAAE,MAAM,UAKtC;AAED,wBAAgB,aAAa,kBAE5B"}
1
+ {"version":3,"file":"config.d.ts","sourceRoot":"","sources":["../src/config.ts"],"names":[],"mappings":"AAIA,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,YAAY,CAAA;AAK/C,eAAO,MAAM,YAAY,QAA+C,CAAA;AAExE,eAAO,MAAM,QAAQ,EAAE,aAStB,CAAA;AAED,wBAAgB,SAAS,CAAC,CAAC,EAAE,MAAM,UAMlC;AAED,wBAAgB,oBAAoB,CAAC,IAAI,EAAE,MAAM,UAMhD;AAED,wBAAgB,cAAc,CAAC,GAAG,EAAE,MAAM,UAOzC;AAED,wBAAgB,YAAY,CAAC,EAAE,EAAE,MAAM,UAOtC;AAED,wBAAsB,aAAa,oBAElC"}
package/dist/config.js CHANGED
@@ -2,6 +2,10 @@ import { InvalidArgumentError, InvalidOptionArgumentError } from "commander";
2
2
  import path from "path";
3
3
  import { validateDirectory } from "./file.js";
4
4
  import net from "net";
5
+ import { fileURLToPath } from "node:url";
6
+ import { getFfmpegStaticPath } from "./lib/lib-ffmpeg.js";
7
+ const __filename = fileURLToPath(import.meta.url);
8
+ export const PROJECT_ROOT = path.resolve(path.dirname(__filename), "..");
5
9
  export const defaults = {
6
10
  DIRECTORY: ".",
7
11
  THUMBS_DIR: "thumbs",
@@ -34,12 +38,12 @@ export function parseDirectory(dir) {
34
38
  return galleryDir;
35
39
  }
36
40
  export function parseAddress(ip) {
37
- if (!ip || (!net.isIPv4(ip) && ip !== 'localhost')) {
41
+ if (!ip || (!net.isIPv4(ip) && ip !== "localhost")) {
38
42
  throw new InvalidOptionArgumentError(`Invalid IP address \"${ip}\". Should be an IPv4 address`);
39
43
  }
40
44
  return ip;
41
45
  }
42
- export function getFfmpegPath() {
43
- return process.env.FFMPEG_PATH || null;
46
+ export async function getFfmpegPath() {
47
+ return process.env.FFMPEG_PATH || getFfmpegStaticPath();
44
48
  }
45
49
  //# sourceMappingURL=config.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"config.js","sourceRoot":"","sources":["../src/config.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,oBAAoB,EAAE,0BAA0B,EAAE,MAAM,WAAW,CAAA;AAC5E,OAAO,IAAI,MAAM,MAAM,CAAA;AACvB,OAAO,EAAE,iBAAiB,EAAE,MAAM,WAAW,CAAA;AAC7C,OAAO,GAAG,MAAM,KAAK,CAAA;AAGrB,MAAM,CAAC,MAAM,QAAQ,GAAkB;IACnC,SAAS,EAAE,GAAG;IACd,UAAU,EAAE,QAAQ;IACpB,OAAO,EAAE,SAAS;IAClB,IAAI,EAAE,IAAI;IAEV,UAAU,EAAE,GAAG;IACf,mBAAmB,EAAE,IAAI,GAAG,IAAI;IAChC,gBAAgB,EAAE,CAAC;CACtB,CAAA;AAED,MAAM,UAAU,SAAS,CAAC,CAAS;IAC/B,MAAM,IAAI,GAAG,MAAM,CAAC,CAAC,CAAC,CAAA;IACtB,IAAI,CAAC,MAAM,CAAC,SAAS,CAAC,IAAI,CAAC,IAAI,IAAI,GAAG,CAAC,IAAI,IAAI,GAAG,KAAK,EAAE,CAAC;QACtD,MAAM,IAAI,0BAA0B,CAAC,6CAA6C,CAAC,CAAA;IACvF,CAAC;IACD,OAAO,IAAI,CAAA;AACf,CAAC;AAED,MAAM,UAAU,oBAAoB,CAAC,IAAY;IAC7C,MAAM,eAAe,GAAG,MAAM,CAAC,IAAI,CAAC,CAAA;IACpC,IAAI,CAAC,MAAM,CAAC,SAAS,CAAC,eAAe,CAAC,IAAI,eAAe,GAAG,CAAC,EAAE,CAAC;QAC5D,MAAM,IAAI,0BAA0B,CAAC,yCAAyC,CAAC,CAAA;IACnF,CAAC;IACD,OAAO,eAAe,CAAA;AAC1B,CAAC;AAED,MAAM,UAAU,cAAc,CAAC,GAAW;IACtC,MAAM,UAAU,GAAG,IAAI,CAAC,OAAO,CAAC,OAAO,CAAC,GAAG,EAAE,EAAE,GAAG,CAAC,CAAA;IACnD,MAAM,EAAE,KAAK,EAAE,GAAG,iBAAiB,CAAC,UAAU,CAAC,CAAA;IAC/C,IAAI,KAAK,EAAE,CAAC;QACR,MAAM,IAAI,oBAAoB,CAAC,KAAK,CAAC,CAAA;IACzC,CAAC;IACD,OAAO,UAAU,CAAA;AACrB,CAAC;AAED,MAAM,UAAU,YAAY,CAAC,EAAU;IACnC,IAAI,CAAC,EAAE,IAAI,CAAC,CAAC,GAAG,CAAC,MAAM,CAAC,EAAE,CAAC,IAAI,EAAE,KAAK,WAAW,CAAC,EAAE,CAAC;QACjD,MAAM,IAAI,0BAA0B,CAAC,wBAAwB,EAAE,+BAA+B,CAAC,CAAA;IACnG,CAAC;IACD,OAAO,EAAE,CAAA;AACb,CAAC;AAED,MAAM,UAAU,aAAa;IACzB,OAAO,OAAO,CAAC,GAAG,CAAC,WAAW,IAAI,IAAI,CAAA;AAC1C,CAAC"}
1
+ {"version":3,"file":"config.js","sourceRoot":"","sources":["../src/config.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,oBAAoB,EAAE,0BAA0B,EAAE,MAAM,WAAW,CAAA;AAC5E,OAAO,IAAI,MAAM,MAAM,CAAA;AACvB,OAAO,EAAE,iBAAiB,EAAE,MAAM,WAAW,CAAA;AAC7C,OAAO,GAAG,MAAM,KAAK,CAAA;AAErB,OAAO,EAAE,aAAa,EAAE,MAAM,UAAU,CAAA;AACxC,OAAO,EAAE,mBAAmB,EAAE,MAAM,qBAAqB,CAAA;AAEzD,MAAM,UAAU,GAAG,aAAa,CAAC,MAAM,CAAC,IAAI,CAAC,GAAG,CAAC,CAAA;AACjD,MAAM,CAAC,MAAM,YAAY,GAAG,IAAI,CAAC,OAAO,CAAC,IAAI,CAAC,OAAO,CAAC,UAAU,CAAC,EAAE,IAAI,CAAC,CAAA;AAExE,MAAM,CAAC,MAAM,QAAQ,GAAkB;IACnC,SAAS,EAAE,GAAG;IACd,UAAU,EAAE,QAAQ;IACpB,OAAO,EAAE,SAAS;IAClB,IAAI,EAAE,IAAI;IAEV,UAAU,EAAE,GAAG;IACf,mBAAmB,EAAE,IAAI,GAAG,IAAI;IAChC,gBAAgB,EAAE,CAAC;CACtB,CAAA;AAED,MAAM,UAAU,SAAS,CAAC,CAAS;IAC/B,MAAM,IAAI,GAAG,MAAM,CAAC,CAAC,CAAC,CAAA;IACtB,IAAI,CAAC,MAAM,CAAC,SAAS,CAAC,IAAI,CAAC,IAAI,IAAI,GAAG,CAAC,IAAI,IAAI,GAAG,KAAK,EAAE,CAAC;QACtD,MAAM,IAAI,0BAA0B,CAAC,6CAA6C,CAAC,CAAA;IACvF,CAAC;IACD,OAAO,IAAI,CAAA;AACf,CAAC;AAED,MAAM,UAAU,oBAAoB,CAAC,IAAY;IAC7C,MAAM,eAAe,GAAG,MAAM,CAAC,IAAI,CAAC,CAAA;IACpC,IAAI,CAAC,MAAM,CAAC,SAAS,CAAC,eAAe,CAAC,IAAI,eAAe,GAAG,CAAC,EAAE,CAAC;QAC5D,MAAM,IAAI,0BAA0B,CAAC,yCAAyC,CAAC,CAAA;IACnF,CAAC;IACD,OAAO,eAAe,CAAA;AAC1B,CAAC;AAED,MAAM,UAAU,cAAc,CAAC,GAAW;IACtC,MAAM,UAAU,GAAG,IAAI,CAAC,OAAO,CAAC,OAAO,CAAC,GAAG,EAAE,EAAE,GAAG,CAAC,CAAA;IACnD,MAAM,EAAE,KAAK,EAAE,GAAG,iBAAiB,CAAC,UAAU,CAAC,CAAA;IAC/C,IAAI,KAAK,EAAE,CAAC;QACR,MAAM,IAAI,oBAAoB,CAAC,KAAK,CAAC,CAAA;IACzC,CAAC;IACD,OAAO,UAAU,CAAA;AACrB,CAAC;AAED,MAAM,UAAU,YAAY,CAAC,EAAU;IACnC,IAAI,CAAC,EAAE,IAAI,CAAC,CAAC,GAAG,CAAC,MAAM,CAAC,EAAE,CAAC,IAAI,EAAE,KAAK,WAAW,CAAC,EAAE,CAAC;QACjD,MAAM,IAAI,0BAA0B,CAChC,wBAAwB,EAAE,+BAA+B,CAC5D,CAAA;IACL,CAAC;IACD,OAAO,EAAE,CAAA;AACb,CAAC;AAED,MAAM,CAAC,KAAK,UAAU,aAAa;IAC/B,OAAO,OAAO,CAAC,GAAG,CAAC,WAAW,IAAI,mBAAmB,EAAE,CAAA;AAC3D,CAAC"}
package/dist/file.d.ts CHANGED
@@ -2,4 +2,5 @@ import type { Result, FileMetaData } from "./types.js";
2
2
  export declare function validateDirectory(absoluteDirPath: string): Result<void, string>;
3
3
  export declare function parseFileMetadata(filePath: string): Promise<FileMetaData | null>;
4
4
  export declare function generateHash(fullPath: string): string;
5
+ export declare function getFiles(directory: string, onScan?: (scanned: number) => void): Promise<FileMetaData[]>;
5
6
  //# sourceMappingURL=file.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"file.d.ts","sourceRoot":"","sources":["../src/file.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,MAAM,EAAE,YAAY,EAAE,MAAM,YAAY,CAAA;AAgCtD,wBAAgB,iBAAiB,CAAC,eAAe,EAAE,MAAM,GAAG,MAAM,CAAC,IAAI,EAAE,MAAM,CAAC,CAc/E;AAED,wBAAsB,iBAAiB,CAAC,QAAQ,EAAE,MAAM,GAAG,OAAO,CAAC,YAAY,GAAG,IAAI,CAAC,CAqBtF;AAED,wBAAgB,YAAY,CAAC,QAAQ,EAAE,MAAM,UAE5C"}
1
+ {"version":3,"file":"file.d.ts","sourceRoot":"","sources":["../src/file.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,MAAM,EAAE,YAAY,EAAE,MAAM,YAAY,CAAA;AAyBtD,wBAAgB,iBAAiB,CAAC,eAAe,EAAE,MAAM,GAAG,MAAM,CAAC,IAAI,EAAE,MAAM,CAAC,CAc/E;AAED,wBAAsB,iBAAiB,CAAC,QAAQ,EAAE,MAAM,GAAG,OAAO,CAAC,YAAY,GAAG,IAAI,CAAC,CAqBtF;AAED,wBAAgB,YAAY,CAAC,QAAQ,EAAE,MAAM,UAE5C;AAWD,wBAAsB,QAAQ,CAC1B,SAAS,EAAE,MAAM,EACjB,MAAM,GAAE,CAAC,OAAO,EAAE,MAAM,KAAK,IAAe,GAC7C,OAAO,CAAC,YAAY,EAAE,CAAC,CAqBzB"}
package/dist/file.js CHANGED
@@ -12,16 +12,9 @@ const IMAGE_EXTS = [
12
12
  ".heif",
13
13
  ".tiff",
14
14
  ".tif",
15
- ".avif",
16
- ];
17
- const VIDEO_EXTS = [
18
- ".mp4",
19
- ".mov",
20
- ".mkv",
21
- ".webm",
22
- ".m4v",
23
- ".m2ts",
15
+ ".avif"
24
16
  ];
17
+ const VIDEO_EXTS = [".mp4", ".mov", ".mkv", ".webm", ".m4v", ".m2ts"];
25
18
  const ALWAYS_ANIMATED_EXTS = new Set([".gif"]);
26
19
  const SOMETIMES_ANIMATED = new Set([".webp", ".avif", ".png"]);
27
20
  export function validateDirectory(absoluteDirPath) {
@@ -56,7 +49,7 @@ export async function parseFileMetadata(filePath) {
56
49
  date: stat.mtime,
57
50
  size: stat.size,
58
51
  ext: ext,
59
- isAnimated: animated,
52
+ isAnimated: animated
60
53
  };
61
54
  }
62
55
  export function generateHash(fullPath) {
@@ -71,4 +64,26 @@ async function isAnimated(filePath) {
71
64
  return false;
72
65
  }
73
66
  }
67
+ export async function getFiles(directory, onScan = () => { }) {
68
+ const files = await fs.promises.readdir(directory);
69
+ const result = [];
70
+ for (const entry of files) {
71
+ const fullPath = path.resolve(directory, entry);
72
+ const stat = await fs.promises.lstat(fullPath);
73
+ if (stat.isSymbolicLink())
74
+ continue;
75
+ if (stat.isDirectory()) {
76
+ const files = await getFiles(fullPath, scanned => onScan(result.length + scanned));
77
+ result.push(...files);
78
+ }
79
+ else {
80
+ const file = await parseFileMetadata(fullPath);
81
+ if (!file)
82
+ continue;
83
+ result.push(file);
84
+ onScan(result.length);
85
+ }
86
+ }
87
+ return result;
88
+ }
74
89
  //# sourceMappingURL=file.js.map
package/dist/file.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"file.js","sourceRoot":"","sources":["../src/file.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"file.js","sourceRoot":"","sources":["../src/file.ts"],"names":[],"mappings":"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"}
package/dist/index.js CHANGED
@@ -1,10 +1,16 @@
1
1
  #!/usr/bin/env node
2
2
  import dotenv from "dotenv";
3
3
  dotenv.config({ quiet: true });
4
+ import path from "path";
5
+ import pLimit from "p-limit";
4
6
  import { Command } from "commander";
5
7
  import manifest from "../package.json" with { type: "json" };
6
- import { defaults, getFfmpegPath, parseAddress, parseDirectory, parseDiskConcurrency, parsePort } from "./config.js";
8
+ import { defaults, getFfmpegPath, parseAddress, parseDirectory, parseDiskConcurrency, parsePort, PROJECT_ROOT } from "./config.js";
7
9
  import startServer from "./server.js";
10
+ import { emptyCache, getCacheSize, THUMBS_DIR, shouldAvoidCaching, getThumbPath, isAlreadyCached } from "./cache.js";
11
+ import { bytesToString } from "./utils.js";
12
+ import { getFiles } from "./file.js";
13
+ import { generateImageThumbnail, generateVideoThumbnail } from "./thumbnail.js";
8
14
  const program = new Command();
9
15
  program
10
16
  .name("obscura")
@@ -20,7 +26,7 @@ program
20
26
  const port = parsePort(options.port);
21
27
  const diskConcurrency = parseDiskConcurrency(options.diskConcurrency);
22
28
  const address = parseAddress(options.address);
23
- const ffmpegPath = getFfmpegPath();
29
+ const ffmpegPath = await getFfmpegPath();
24
30
  try {
25
31
  const config = {
26
32
  galleryDir: galleryDir,
@@ -43,5 +49,105 @@ program
43
49
  process.exit(1);
44
50
  }
45
51
  });
52
+ const cache = program.command("cache").description("Manage and inspect the application cache");
53
+ cache
54
+ .command("stats")
55
+ .description("Show cache usage and storage statistics")
56
+ .action(async () => {
57
+ console.log(`Cache directory: \x1b[36m${THUMBS_DIR}\x1b[0m`);
58
+ const cacheSize = await getCacheSize();
59
+ console.log(`Cache size: ${bytesToString(cacheSize)}`);
60
+ });
61
+ cache
62
+ .command("clean")
63
+ .description("Clear the cache directory")
64
+ .action(async () => {
65
+ try {
66
+ const clearedBytes = await emptyCache();
67
+ console.log(`Cache cleaned (Freed ${bytesToString(clearedBytes)})`);
68
+ }
69
+ catch (e) {
70
+ console.log(`Error encountered: ${e}`);
71
+ }
72
+ });
73
+ program
74
+ .command("index")
75
+ .description("Index directory")
76
+ .argument("[directory]", "Directory to be indexed", ".")
77
+ .option("-r, --refresh", "Overwrite existing cache")
78
+ .action(async (dir, options) => {
79
+ const directory = path.resolve(PROJECT_ROOT, dir);
80
+ const diskConcurrency = parseDiskConcurrency(process.env.DISK_CONCURRENCY || String(defaults.DISK_CONCURRENCY));
81
+ const limit = pLimit(diskConcurrency);
82
+ const start = Date.now();
83
+ const throttled = createThrottler(500, 500);
84
+ let files = await getFiles(directory, scanned => {
85
+ throttled(() => process.stdout.write(`\x1b[2KScanned ${scanned} files\r`));
86
+ });
87
+ const totalFiles = files.length;
88
+ files = files.filter(f => !shouldAvoidCaching(f, defaults.IMG_CACHE_THRESHOLD));
89
+ const filesToBeCached = files.length;
90
+ process.stdout.write(`\x1b[2KFound ${totalFiles} files (${filesToBeCached} to be cached)\n\n`);
91
+ let completed = 0;
92
+ const ffmpegPath = await getFfmpegPath();
93
+ const writer = progressWriter(100);
94
+ const tasks = files.map(file => limit(async () => {
95
+ await cacheFile(file, ffmpegPath, { refresh: options.refresh });
96
+ completed++;
97
+ writer(completed, filesToBeCached);
98
+ }));
99
+ await Promise.all(tasks);
100
+ process.stdout.write(`\x1b[2K\x1b[2A\x1b[2K\nIndexed ${totalFiles} files from \x1b[36m${directory}\x1b[0m (${filesToBeCached} cached)\n`);
101
+ const duration = (Date.now() - start) / 1000;
102
+ console.log(`Completed in ${duration.toFixed(2)}s`);
103
+ });
104
+ function progressWriter(interval) {
105
+ let lastWriteTime = 0;
106
+ let lastValue = 0;
107
+ const INFINITY_SYMBOL = `\u221e`;
108
+ return (current, total) => {
109
+ const now = Date.now();
110
+ if (now - lastWriteTime < interval)
111
+ return;
112
+ const perc = Math.round((current / total) * 100);
113
+ const rate = (current - lastValue) / (now - lastWriteTime);
114
+ const eta = rate !== 0 && lastValue > 3
115
+ ? ((total - current) / (rate * 1000)).toFixed(2) + "s"
116
+ : INFINITY_SYMBOL;
117
+ const width = 30;
118
+ const bars = Math.floor((width * current) / total);
119
+ const progressBar = `[${"#".repeat(bars).padEnd(width)}]`;
120
+ process.stdout.write(`\x1b[2K${progressBar} ${current}/${total} (${perc}%) | ETA ${eta}\r`);
121
+ lastWriteTime = now;
122
+ lastValue = current;
123
+ };
124
+ }
125
+ function createThrottler(interval, delay) {
126
+ let lastUpdate = 0;
127
+ let start = undefined;
128
+ return (cb) => {
129
+ const now = Date.now();
130
+ if (!start)
131
+ start = now;
132
+ if (now - lastUpdate < interval)
133
+ return;
134
+ if (now - start < delay)
135
+ return;
136
+ cb();
137
+ lastUpdate = now;
138
+ };
139
+ }
140
+ async function cacheFile(file, ffmpegPath, opts = { refresh: false }) {
141
+ const thumbPath = getThumbPath(file.id);
142
+ // Skip already cached files unless in refresh mode
143
+ if (!opts.refresh && isAlreadyCached(file.id))
144
+ return;
145
+ if (file.type === "image") {
146
+ await generateImageThumbnail(file, thumbPath, defaults.THUMB_SIZE);
147
+ }
148
+ else {
149
+ await generateVideoThumbnail(ffmpegPath, file, thumbPath, defaults.THUMB_SIZE);
150
+ }
151
+ }
46
152
  program.parse(process.argv);
47
153
  //# sourceMappingURL=index.js.map
package/dist/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":";AAEA,OAAO,MAAM,MAAM,QAAQ,CAAA;AAC3B,MAAM,CAAC,MAAM,CAAC,EAAE,KAAK,EAAE,IAAI,EAAE,CAAC,CAAA;AAE9B,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAA;AACnC,OAAO,QAAQ,MAAM,iBAAiB,CAAC,OAAO,IAAI,EAAE,MAAM,EAAE,CAAA;AAC5D,OAAO,EAAE,QAAQ,EAAE,aAAa,EAAE,YAAY,EAAE,cAAc,EAAE,oBAAoB,EAAE,SAAS,EAAE,MAAM,aAAa,CAAA;AACpH,OAAO,WAAW,MAAM,aAAa,CAAA;AAGrC,MAAM,OAAO,GAAG,IAAI,OAAO,EAAE,CAAA;AAE7B,OAAO;KACF,IAAI,CAAC,SAAS,CAAC;KACf,WAAW,CAAC,iEAAiE,CAAC;KAC9E,OAAO,CAAC,QAAQ,CAAC,OAAO,EAAE,eAAe,EAAE,2BAA2B,CAAC,CAAA;AAE5E,OAAO;KACF,QAAQ,CAAC,aAAa,EAAE,oBAAoB,EAAE,OAAO,CAAC,GAAG,CAAC,SAAS,IAAI,QAAQ,CAAC,SAAS,CAAC;KAC1F,MAAM,CAAC,oBAAoB,EAAE,oBAAoB,EAAE,OAAO,CAAC,GAAG,CAAC,OAAO,IAAI,QAAQ,CAAC,OAAO,CAAC;KAC3F,MAAM,CACH,qBAAqB,EACrB,mBAAmB,EACnB,OAAO,CAAC,GAAG,CAAC,IAAI,IAAI,QAAQ,CAAC,IAAI,CAAC,QAAQ,EAAE,CAC/C;KACA,MAAM,CACH,6BAA6B,EAC7B,8CAA8C,EAC9C,OAAO,CAAC,GAAG,CAAC,gBAAgB,IAAI,QAAQ,CAAC,gBAAgB,CAAC,QAAQ,EAAE,CACvE;KACA,MAAM,CAAC,KAAK,EAAE,SAAS,EAAE,OAAO,EAAE,EAAE;IACjC,MAAM,UAAU,GAAG,cAAc,CAAC,SAAS,CAAC,CAAA;IAC5C,MAAM,IAAI,GAAG,SAAS,CAAC,OAAO,CAAC,IAAI,CAAC,CAAA;IACpC,MAAM,eAAe,GAAG,oBAAoB,CAAC,OAAO,CAAC,eAAe,CAAC,CAAA;IACrE,MAAM,OAAO,GAAG,YAAY,CAAC,OAAO,CAAC,OAAO,CAAC,CAAA;IAC7C,MAAM,UAAU,GAAG,aAAa,EAAE,CAAA;IAElC,IAAI,CAAC;QACD,MAAM,MAAM,GAAiB;YACzB,UAAU,EAAE,UAAU;YACtB,OAAO,EAAE,OAAO;YAChB,IAAI,EAAE,IAAI;YACV,SAAS,EAAE,QAAQ,CAAC,UAAU;YAC9B,iBAAiB,EAAE,QAAQ,CAAC,mBAAmB;YAC/C,eAAe,EAAE,eAAe;YAChC,UAAU,EAAE,UAAU;SACzB,CAAA;QAED,MAAM,KAAK,GAAG,MAAM,WAAW,CAAC,MAAM,CAAC,CAAA;QAEvC,OAAO,CAAC,EAAE,CAAC,QAAQ,EAAE,KAAK,IAAI,EAAE;YAC5B,MAAM,KAAK,EAAE,CAAA;YACb,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAA;QACnB,CAAC,CAAC,CAAA;IACN,CAAC;IAAC,OAAO,KAAK,EAAE,CAAC;QACb,OAAO,CAAC,KAAK,CAAC,iCAAiC,CAAC,CAAA;QAChD,OAAO,CAAC,KAAK,CAAC,KAAK,KAAK,SAAS,CAAC,CAAA;QAClC,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAA;IACnB,CAAC;AACL,CAAC,CAAC,CAAA;AAEN,OAAO,CAAC,KAAK,CAAC,OAAO,CAAC,IAAI,CAAC,CAAA"}
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"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"}
@@ -1,2 +1,2 @@
1
- export declare function getFfmpegPath(): Promise<string>;
1
+ export declare function getFfmpegStaticPath(): Promise<string>;
2
2
  //# sourceMappingURL=lib-ffmpeg.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"lib-ffmpeg.d.ts","sourceRoot":"","sources":["../../src/lib/lib-ffmpeg.ts"],"names":[],"mappings":"AAEA,wBAAsB,aAAa,IAAI,OAAO,CAAC,MAAM,CAAC,CAcrD"}
1
+ {"version":3,"file":"lib-ffmpeg.d.ts","sourceRoot":"","sources":["../../src/lib/lib-ffmpeg.ts"],"names":[],"mappings":"AAEA,wBAAsB,mBAAmB,IAAI,OAAO,CAAC,MAAM,CAAC,CAc3D"}
@@ -1,5 +1,5 @@
1
1
  let ffmpegPath = null;
2
- export async function getFfmpegPath() {
2
+ export async function getFfmpegStaticPath() {
3
3
  if (ffmpegPath)
4
4
  return ffmpegPath;
5
5
  try {
@@ -1 +1 @@
1
- {"version":3,"file":"lib-ffmpeg.js","sourceRoot":"","sources":["../../src/lib/lib-ffmpeg.ts"],"names":[],"mappings":"AAAA,IAAI,UAAU,GAAkB,IAAI,CAAA;AAEpC,MAAM,CAAC,KAAK,UAAU,aAAa;IAC/B,IAAI,UAAU;QAAE,OAAO,UAAU,CAAA;IAEjC,IAAI,CAAC;QACD,MAAM,MAAM,GAAG,MAAM,MAAM,CAAC,eAAe,CAAC,CAAA;QAC5C,UAAU,GAAG,OAAO,MAAM,KAAK,QAAQ,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,CAAE,MAAc,CAAC,OAAO,CAAA;QAC1E,OAAO,UAAoB,CAAA;IAC/B,CAAC;IAAC,OAAO,CAAM,EAAE,CAAC;QACd,IAAI,CAAC,CAAC,IAAI,KAAK,sBAAsB,EAAE,CAAC;YACpC,MAAM,IAAI,KAAK,CAAC,0CAA0C,CAAC,CAAA;QAC/D,CAAC;aAAM,CAAC;YACJ,MAAM,CAAC,CAAA;QACX,CAAC;IACL,CAAC;AACL,CAAC"}
1
+ {"version":3,"file":"lib-ffmpeg.js","sourceRoot":"","sources":["../../src/lib/lib-ffmpeg.ts"],"names":[],"mappings":"AAAA,IAAI,UAAU,GAAkB,IAAI,CAAA;AAEpC,MAAM,CAAC,KAAK,UAAU,mBAAmB;IACrC,IAAI,UAAU;QAAE,OAAO,UAAU,CAAA;IAEjC,IAAI,CAAC;QACD,MAAM,MAAM,GAAG,MAAM,MAAM,CAAC,eAAe,CAAC,CAAA;QAC5C,UAAU,GAAG,OAAO,MAAM,KAAK,QAAQ,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,CAAE,MAAc,CAAC,OAAO,CAAA;QAC1E,OAAO,UAAoB,CAAA;IAC/B,CAAC;IAAC,OAAO,CAAM,EAAE,CAAC;QACd,IAAI,CAAC,CAAC,IAAI,KAAK,sBAAsB,EAAE,CAAC;YACpC,MAAM,IAAI,KAAK,CAAC,0CAA0C,CAAC,CAAA;QAC/D,CAAC;aAAM,CAAC;YACJ,MAAM,CAAC,CAAA;QACX,CAAC;IACL,CAAC;AACL,CAAC"}
@@ -1 +1 @@
1
- {"version":3,"file":"server.d.ts","sourceRoot":"","sources":["../src/server.ts"],"names":[],"mappings":"AAeA,OAAO,KAAK,EAAoC,YAAY,EAAa,MAAM,YAAY,CAAA;AAgB3F,MAAM,CAAC,OAAO,UAAU,WAAW,CAAC,MAAM,EAAE,YAAY,iBAiH3B,OAAO,CAAC,IAAI,CAAC,EAkCzC"}
1
+ {"version":3,"file":"server.d.ts","sourceRoot":"","sources":["../src/server.ts"],"names":[],"mappings":"AAcA,OAAO,KAAK,EAAoC,YAAY,EAAa,MAAM,YAAY,CAAA;AAc3F,MAAM,CAAC,OAAO,UAAU,WAAW,CAAC,MAAM,EAAE,YAAY,GAAG,OAAO,CAAC,MAAM,OAAO,CAAC,IAAI,CAAC,CAAC,CAyMtF"}
package/dist/server.js CHANGED
@@ -8,12 +8,9 @@ import fs from "fs";
8
8
  import { parseFileMetadata, generateHash } from "./file.js";
9
9
  import logger from "./logger.js";
10
10
  import { generateImageThumbnail, generateVideoThumbnail } from "./thumbnail.js";
11
- import { getFfmpegPath } from "./lib/lib-ffmpeg.js";
12
11
  import { insertSorted } from "./utils.js";
13
- import { fileURLToPath } from "url";
14
- import { defaults } from "./config.js";
15
- const __filename = fileURLToPath(import.meta.url);
16
- const PROJECT_ROOT = path.resolve(path.dirname(__filename), "..");
12
+ import { getThumbPath, THUMBS_DIR, shouldAvoidCaching } from "./cache.js";
13
+ import { PROJECT_ROOT } from "./config.js";
17
14
  function createApp() {
18
15
  const app = express();
19
16
  app.use(express.json());
@@ -23,8 +20,8 @@ function createApp() {
23
20
  return app;
24
21
  }
25
22
  export default function startServer(config) {
23
+ const ffmpegPath = config.ffmpegPath;
26
24
  const limit = pLimit(config.diskConcurrency);
27
- const THUMBS_DIR = path.resolve(PROJECT_ROOT, defaults.THUMBS_DIR);
28
25
  if (!fs.existsSync(THUMBS_DIR))
29
26
  fs.mkdirSync(THUMBS_DIR, { recursive: true });
30
27
  let filesMap = new Map();
@@ -40,6 +37,14 @@ export default function startServer(config) {
40
37
  client.res.write(`data: ${JSON.stringify({ action, file: fileData })}\n\n`);
41
38
  });
42
39
  }
40
+ function toClientFile(file) {
41
+ const { id, name, type, date, size, isAnimated } = file;
42
+ return { id, name, type, date, size, isAnimated };
43
+ }
44
+ function insertToSortedFiles(file) {
45
+ const clientFile = toClientFile(file);
46
+ insertSorted(sortedFiles, clientFile, file => new Date(file.date).getTime(), (a, b) => b - a);
47
+ }
43
48
  let isBooting = true;
44
49
  watcher.on("add", async (filePath) => {
45
50
  const fileData = await parseFileMetadata(filePath);
@@ -49,12 +54,24 @@ export default function startServer(config) {
49
54
  filesMap.set(fileData.id, fileData);
50
55
  if (isExisting)
51
56
  return;
52
- const { id, name, type, date, size, isAnimated } = fileData;
53
- const clientFileData = { id, name, type, date, size, isAnimated };
54
- insertSorted(sortedFiles, clientFileData, file => new Date(file.date).getTime(), (a, b) => b - a);
57
+ insertToSortedFiles(fileData);
55
58
  if (isBooting)
56
59
  return;
57
- broadcastToUsers("add", clientFileData);
60
+ broadcastToUsers("add", fileData);
61
+ });
62
+ watcher.on("change", async (filePath) => {
63
+ const file = await parseFileMetadata(filePath);
64
+ if (!file)
65
+ return;
66
+ sortedFiles = sortedFiles.filter(f => f.id !== file.id);
67
+ insertToSortedFiles(file);
68
+ try {
69
+ await refreshThumbnail(file);
70
+ broadcastToUsers("update", file);
71
+ }
72
+ catch (err) {
73
+ console.error(`Error while updating file metadat change: ${err}`);
74
+ }
58
75
  });
59
76
  watcher.on("unlink", filePath => {
60
77
  const fileId = generateHash(filePath);
@@ -62,7 +79,7 @@ export default function startServer(config) {
62
79
  filesMap.delete(fileId);
63
80
  sortedFiles = sortedFiles.filter(file => file.id !== fileId);
64
81
  broadcastToUsers("remove", { id: fileId });
65
- const thumbPath = getThumbPath(THUMBS_DIR, fileId);
82
+ const thumbPath = getThumbPath(fileId);
66
83
  fs.unlink(thumbPath, () => { });
67
84
  }
68
85
  });
@@ -94,29 +111,59 @@ export default function startServer(config) {
94
111
  const file = filesMap.get(req.params.id);
95
112
  if (!file)
96
113
  return res.sendStatus(404);
114
+ try {
115
+ const thumbPath = await getOrCreateThumbnail(file);
116
+ res.sendFile(thumbPath);
117
+ }
118
+ catch (err) {
119
+ console.error(err);
120
+ res.sendStatus(500);
121
+ }
122
+ });
123
+ async function getOrCreateThumbnail(file) {
97
124
  if (shouldAvoidCaching(file, config.imgCacheThreshold)) {
98
- return res.sendFile(file.path);
125
+ return file.path;
99
126
  }
100
- const thumbPath = getThumbPath(THUMBS_DIR, file.id);
127
+ const thumbPath = getThumbPath(file.id);
101
128
  try {
102
129
  await limit(async () => {
103
- if (fs.existsSync(thumbPath))
104
- return;
105
- if (file.type === "image") {
106
- await generateImageThumbnail(file, thumbPath, config.thumbSize);
107
- }
108
- else {
109
- const ffmpegPath = config.ffmpegPath || await getFfmpegPath();
110
- await generateVideoThumbnail(ffmpegPath, file, thumbPath, config.thumbSize);
130
+ if (fs.existsSync(thumbPath)) {
131
+ const stat = fs.statSync(thumbPath);
132
+ if (stat.mtime >= file.date)
133
+ return;
111
134
  }
135
+ await createThumbnail(file, thumbPath);
112
136
  });
113
- res.sendFile(path.resolve(thumbPath));
137
+ return path.resolve(thumbPath);
114
138
  }
115
139
  catch (err) {
116
- console.error(`Error while creating thumbnail: ${err}`);
117
- res.sendStatus(500);
140
+ throw new Error(`Error while creating thumbnail: ${err}`);
118
141
  }
119
- });
142
+ }
143
+ async function refreshThumbnail(file) {
144
+ const thumbPath = getThumbPath(file.id);
145
+ if (shouldAvoidCaching(file, config.imgCacheThreshold)) {
146
+ await fs.promises.rm(thumbPath, { force: true });
147
+ return;
148
+ }
149
+ try {
150
+ await limit(async () => {
151
+ await createThumbnail(file, thumbPath);
152
+ });
153
+ return;
154
+ }
155
+ catch (err) {
156
+ throw new Error(`Error while creating thumbnail: ${err}`);
157
+ }
158
+ }
159
+ async function createThumbnail(file, thumbPath) {
160
+ if (file.type === "image") {
161
+ await generateImageThumbnail(file, thumbPath, config.thumbSize);
162
+ }
163
+ else {
164
+ await generateVideoThumbnail(ffmpegPath, file, thumbPath, config.thumbSize);
165
+ }
166
+ }
120
167
  return new Promise((resolve, reject) => {
121
168
  const server = app.listen(config.port, config.address, error => {
122
169
  if (error) {
@@ -151,10 +198,4 @@ function logAddress(addr, port, name) {
151
198
  const url = `http://${addr}:${port}`;
152
199
  console.log(`- \x1b[36m${url.padEnd(30)}\x1b[0m ${name ? "[" + name + "]" : ""}`);
153
200
  }
154
- function getThumbPath(thumbsDir, fileId) {
155
- return path.join(thumbsDir, `${fileId}.jpg`);
156
- }
157
- function shouldAvoidCaching(file, threshold) {
158
- return file.type == "image" && file.size < threshold && !file.isAnimated;
159
- }
160
201
  //# sourceMappingURL=server.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"server.js","sourceRoot":"","sources":["../src/server.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"server.js","sourceRoot":"","sources":["../src/server.ts"],"names":[],"mappings":"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"}
@@ -1 +1 @@
1
- {"version":3,"file":"thumbnail.d.ts","sourceRoot":"","sources":["../src/thumbnail.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,YAAY,CAAA;AAK9C,wBAAgB,sBAAsB,CAAC,UAAU,EAAE,MAAM,EAAE,IAAI,EAAE,YAAY,EAAE,SAAS,EAAE,MAAM,EAAE,SAAS,EAAE,MAAM,iBAuBlH;AAED,wBAAsB,sBAAsB,CAAC,IAAI,EAAE,YAAY,EAAE,SAAS,EAAE,MAAM,EAAE,SAAS,EAAE,MAAM,iBAKpG"}
1
+ {"version":3,"file":"thumbnail.d.ts","sourceRoot":"","sources":["../src/thumbnail.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,YAAY,CAAA;AAK9C,wBAAgB,sBAAsB,CAAC,UAAU,EAAE,MAAM,EAAE,IAAI,EAAE,YAAY,EAAE,SAAS,EAAE,MAAM,EAAE,SAAS,EAAE,MAAM,iBAyBlH;AAED,wBAAsB,sBAAsB,CAAC,IAAI,EAAE,YAAY,EAAE,SAAS,EAAE,MAAM,EAAE,SAAS,EAAE,MAAM,iBAKpG"}
package/dist/thumbnail.js CHANGED
@@ -3,6 +3,8 @@ import libSharp from "./lib/lib-sharp.js";
3
3
  export function generateVideoThumbnail(ffmpegPath, file, thumbPath, thumbSize) {
4
4
  return new Promise((resolve, reject) => {
5
5
  execFile(ffmpegPath, [
6
+ "-y", // allow overwrite
7
+ "-nostdin",
6
8
  "-i",
7
9
  file.path,
8
10
  "-frames:v",
@@ -1 +1 @@
1
- {"version":3,"file":"thumbnail.js","sourceRoot":"","sources":["../src/thumbnail.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,QAAQ,EAAE,MAAM,eAAe,CAAA;AACxC,OAAO,QAAQ,MAAM,oBAAoB,CAAA;AAEzC,MAAM,UAAU,sBAAsB,CAAC,UAAkB,EAAE,IAAkB,EAAE,SAAiB,EAAE,SAAiB;IAC/G,OAAO,IAAI,OAAO,CAAO,CAAC,OAAO,EAAE,MAAM,EAAE,EAAE;QACzC,QAAQ,CACJ,UAAU,EACV;YACI,IAAI;YACJ,IAAI,CAAC,IAAI;YACT,WAAW;YACX,GAAG;YACH,KAAK;YACL,SAAS,SAAS,IAAI,SAAS,8CAA8C,SAAS,IAAI,SAAS,QAAQ,SAAS,WAAW,SAAS,KAAK;YAC7I,MAAM;YACN,GAAG;YACH,SAAS;SACZ,EACD,CAAC,GAAG,EAAE,OAAO,EAAE,OAAO,EAAE,EAAE;YACtB,IAAI,GAAG,EAAE,CAAC;gBACN,OAAO,MAAM,CAAC,IAAI,KAAK,CAAC,iBAAiB,GAAG,CAAC,OAAO,EAAE,CAAC,CAAC,CAAA;YAC5D,CAAC;YACD,OAAO,EAAE,CAAA;QACb,CAAC,CACJ,CAAA;IACL,CAAC,CAAC,CAAA;AACN,CAAC;AAED,MAAM,CAAC,KAAK,UAAU,sBAAsB,CAAC,IAAkB,EAAE,SAAiB,EAAE,SAAiB;IACjG,MAAM,QAAQ,CAAC,IAAI,CAAC,IAAI,EAAE,EAAE,QAAQ,EAAE,KAAK,EAAE,IAAI,EAAE,CAAC,EAAE,CAAC;SAClD,MAAM,CAAC,SAAS,EAAE,SAAS,EAAE,EAAE,GAAG,EAAE,OAAO,EAAE,CAAC;SAC9C,IAAI,CAAC,EAAE,OAAO,EAAE,EAAE,EAAE,CAAC;SACrB,MAAM,CAAC,SAAS,CAAC,CAAA;AAC1B,CAAC"}
1
+ {"version":3,"file":"thumbnail.js","sourceRoot":"","sources":["../src/thumbnail.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,QAAQ,EAAE,MAAM,eAAe,CAAA;AACxC,OAAO,QAAQ,MAAM,oBAAoB,CAAA;AAEzC,MAAM,UAAU,sBAAsB,CAAC,UAAkB,EAAE,IAAkB,EAAE,SAAiB,EAAE,SAAiB;IAC/G,OAAO,IAAI,OAAO,CAAO,CAAC,OAAO,EAAE,MAAM,EAAE,EAAE;QACzC,QAAQ,CACJ,UAAU,EACV;YACI,IAAI,EAAE,kBAAkB;YACxB,UAAU;YACV,IAAI;YACJ,IAAI,CAAC,IAAI;YACT,WAAW;YACX,GAAG;YACH,KAAK;YACL,SAAS,SAAS,IAAI,SAAS,8CAA8C,SAAS,IAAI,SAAS,QAAQ,SAAS,WAAW,SAAS,KAAK;YAC7I,MAAM;YACN,GAAG;YACH,SAAS;SACZ,EACD,CAAC,GAAG,EAAE,OAAO,EAAE,OAAO,EAAE,EAAE;YACtB,IAAI,GAAG,EAAE,CAAC;gBACN,OAAO,MAAM,CAAC,IAAI,KAAK,CAAC,iBAAiB,GAAG,CAAC,OAAO,EAAE,CAAC,CAAC,CAAA;YAC5D,CAAC;YACD,OAAO,EAAE,CAAA;QACb,CAAC,CACJ,CAAA;IACL,CAAC,CAAC,CAAA;AACN,CAAC;AAED,MAAM,CAAC,KAAK,UAAU,sBAAsB,CAAC,IAAkB,EAAE,SAAiB,EAAE,SAAiB;IACjG,MAAM,QAAQ,CAAC,IAAI,CAAC,IAAI,EAAE,EAAE,QAAQ,EAAE,KAAK,EAAE,IAAI,EAAE,CAAC,EAAE,CAAC;SAClD,MAAM,CAAC,SAAS,EAAE,SAAS,EAAE,EAAE,GAAG,EAAE,OAAO,EAAE,CAAC;SAC9C,IAAI,CAAC,EAAE,OAAO,EAAE,EAAE,EAAE,CAAC;SACrB,MAAM,CAAC,SAAS,CAAC,CAAA;AAC1B,CAAC"}
package/dist/types.d.ts CHANGED
@@ -25,7 +25,7 @@ export interface ServerConfig {
25
25
  thumbSize: number;
26
26
  imgCacheThreshold: number;
27
27
  diskConcurrency: number;
28
- ffmpegPath: string | null;
28
+ ffmpegPath: string;
29
29
  }
30
30
  export interface DefaultConfig {
31
31
  DIRECTORY: string;
@@ -36,4 +36,7 @@ export interface DefaultConfig {
36
36
  IMG_CACHE_THRESHOLD: number;
37
37
  DISK_CONCURRENCY: number;
38
38
  }
39
+ export interface IndexOpts {
40
+ refresh: boolean;
41
+ }
39
42
  //# sourceMappingURL=types.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,SAAS,CAAA;AAEvC,MAAM,WAAW,YAAY;IACzB,EAAE,EAAE,MAAM,CAAA;IACV,IAAI,EAAE,MAAM,CAAA;IACZ,IAAI,EAAE,MAAM,CAAA;IACZ,IAAI,EAAE,OAAO,GAAG,OAAO,CAAA;IACvB,IAAI,EAAE,IAAI,CAAA;IACV,IAAI,EAAE,MAAM,CAAA;IACZ,GAAG,EAAE,MAAM,CAAA;IACX,UAAU,EAAE,OAAO,CAAA;CACtB;AAED,MAAM,MAAM,kBAAkB,GAAG,IAAI,CAAC,YAAY,EAAE,IAAI,GAAG,MAAM,GAAG,MAAM,GAAG,MAAM,GAAG,MAAM,GAAG,YAAY,CAAC,CAAA;AAE5G,MAAM,WAAW,SAAS;IACtB,EAAE,EAAE,MAAM,CAAA;IACV,GAAG,EAAE,QAAQ,CAAA;CAChB;AAED,MAAM,WAAW,MAAM,CAAC,CAAC,EAAE,CAAC;IACxB,MAAM,CAAC,EAAE,CAAC,CAAA;IACV,KAAK,CAAC,EAAE,CAAC,CAAA;CACZ;AAED,MAAM,WAAW,YAAY;IACzB,UAAU,EAAE,MAAM,CAAC;IACnB,OAAO,EAAE,MAAM,CAAC;IAChB,IAAI,EAAE,MAAM,CAAC;IACb,SAAS,EAAE,MAAM,CAAC;IAClB,iBAAiB,EAAE,MAAM,CAAC;IAC1B,eAAe,EAAE,MAAM,CAAC;IACxB,UAAU,EAAE,MAAM,GAAG,IAAI,CAAA;CAC5B;AAED,MAAM,WAAW,aAAa;IAC1B,SAAS,EAAE,MAAM,CAAC;IAClB,UAAU,EAAE,MAAM,CAAC;IACnB,OAAO,EAAE,MAAM,CAAC;IAChB,IAAI,EAAE,MAAM,CAAC;IAEb,UAAU,EAAE,MAAM,CAAC;IACnB,mBAAmB,EAAE,MAAM,CAAC;IAC5B,gBAAgB,EAAE,MAAM,CAAA;CAC3B"}
1
+ {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,SAAS,CAAA;AAEvC,MAAM,WAAW,YAAY;IACzB,EAAE,EAAE,MAAM,CAAA;IACV,IAAI,EAAE,MAAM,CAAA;IACZ,IAAI,EAAE,MAAM,CAAA;IACZ,IAAI,EAAE,OAAO,GAAG,OAAO,CAAA;IACvB,IAAI,EAAE,IAAI,CAAA;IACV,IAAI,EAAE,MAAM,CAAA;IACZ,GAAG,EAAE,MAAM,CAAA;IACX,UAAU,EAAE,OAAO,CAAA;CACtB;AAED,MAAM,MAAM,kBAAkB,GAAG,IAAI,CACjC,YAAY,EACZ,IAAI,GAAG,MAAM,GAAG,MAAM,GAAG,MAAM,GAAG,MAAM,GAAG,YAAY,CAC1D,CAAA;AAED,MAAM,WAAW,SAAS;IACtB,EAAE,EAAE,MAAM,CAAA;IACV,GAAG,EAAE,QAAQ,CAAA;CAChB;AAED,MAAM,WAAW,MAAM,CAAC,CAAC,EAAE,CAAC;IACxB,MAAM,CAAC,EAAE,CAAC,CAAA;IACV,KAAK,CAAC,EAAE,CAAC,CAAA;CACZ;AAED,MAAM,WAAW,YAAY;IACzB,UAAU,EAAE,MAAM,CAAA;IAClB,OAAO,EAAE,MAAM,CAAA;IACf,IAAI,EAAE,MAAM,CAAA;IACZ,SAAS,EAAE,MAAM,CAAA;IACjB,iBAAiB,EAAE,MAAM,CAAA;IACzB,eAAe,EAAE,MAAM,CAAA;IACvB,UAAU,EAAE,MAAM,CAAA;CACrB;AAED,MAAM,WAAW,aAAa;IAC1B,SAAS,EAAE,MAAM,CAAA;IACjB,UAAU,EAAE,MAAM,CAAA;IAClB,OAAO,EAAE,MAAM,CAAA;IACf,IAAI,EAAE,MAAM,CAAA;IAEZ,UAAU,EAAE,MAAM,CAAA;IAClB,mBAAmB,EAAE,MAAM,CAAA;IAC3B,gBAAgB,EAAE,MAAM,CAAA;CAC3B;AAED,MAAM,WAAW,SAAS;IACtB,OAAO,EAAE,OAAO,CAAA;CACnB"}
package/dist/utils.d.ts CHANGED
@@ -1,2 +1,3 @@
1
1
  export declare function insertSorted<T>(arr: T[], element: T, key: (element: T) => number, comparator?: (a: number, b: number) => number): void;
2
+ export declare function bytesToString(bytes: number): string;
2
3
  //# sourceMappingURL=utils.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"utils.d.ts","sourceRoot":"","sources":["../src/utils.ts"],"names":[],"mappings":"AAAA,wBAAgB,YAAY,CAAC,CAAC,EAC1B,GAAG,EAAE,CAAC,EAAE,EACR,OAAO,EAAE,CAAC,EACV,GAAG,EAAE,CAAC,OAAO,EAAE,CAAC,KAAK,MAAM,EAC3B,UAAU,IAAI,GAAG,MAAM,EAAE,GAAG,MAAM,WAAU,QAkB/C"}
1
+ {"version":3,"file":"utils.d.ts","sourceRoot":"","sources":["../src/utils.ts"],"names":[],"mappings":"AAAA,wBAAgB,YAAY,CAAC,CAAC,EAC1B,GAAG,EAAE,CAAC,EAAE,EACR,OAAO,EAAE,CAAC,EACV,GAAG,EAAE,CAAC,OAAO,EAAE,CAAC,KAAK,MAAM,EAC3B,UAAU,IAAI,GAAG,MAAM,EAAE,GAAG,MAAM,WAAU,QAkB/C;AAED,wBAAgB,aAAa,CAAC,KAAK,EAAE,MAAM,GAAG,MAAM,CAWnD"}
package/dist/utils.js CHANGED
@@ -14,4 +14,21 @@ export function insertSorted(arr, element, key, comparator = (a, b) => a - b) {
14
14
  }
15
15
  arr.splice(low, 0, element);
16
16
  }
17
+ export function bytesToString(bytes) {
18
+ const KB = 1000;
19
+ const MB = 1000 * KB;
20
+ const GB = 1000 * MB;
21
+ if (bytes < MB) {
22
+ return `${formatDecimal(bytes / KB)} KB`;
23
+ }
24
+ else if (bytes < GB) {
25
+ return `${formatDecimal(bytes / MB)} MB`;
26
+ }
27
+ else {
28
+ return `${formatDecimal(bytes / GB)} GB`;
29
+ }
30
+ }
31
+ function formatDecimal(num, fractionDigits = 2) {
32
+ return parseFloat(num.toFixed(fractionDigits)).toString();
33
+ }
17
34
  //# sourceMappingURL=utils.js.map
package/dist/utils.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"utils.js","sourceRoot":"","sources":["../src/utils.ts"],"names":[],"mappings":"AAAA,MAAM,UAAU,YAAY,CACxB,GAAQ,EACR,OAAU,EACV,GAA2B,EAC3B,aAAa,CAAC,CAAS,EAAE,CAAS,EAAE,EAAE,CAAC,CAAC,GAAG,CAAC;IAE5C,IAAI,GAAG,GAAG,CAAC,CAAA;IACX,IAAI,IAAI,GAAG,GAAG,CAAC,MAAM,CAAA;IACrB,MAAM,WAAW,GAAG,GAAG,CAAC,OAAO,CAAC,CAAA;IAEhC,OAAO,GAAG,GAAG,IAAI,EAAE,CAAC;QAChB,MAAM,GAAG,GAAG,CAAC,GAAG,GAAG,IAAI,CAAC,KAAK,CAAC,CAAA;QAC9B,MAAM,QAAQ,GAAG,GAAG,CAAC,GAAG,CAAC,GAAG,CAAM,CAAC,CAAA;QAEnC,IAAI,UAAU,CAAC,WAAW,EAAE,QAAQ,CAAC,GAAG,CAAC,EAAE,CAAC;YACxC,GAAG,GAAG,GAAG,GAAG,CAAC,CAAA;QACjB,CAAC;aAAM,CAAC;YACJ,IAAI,GAAG,GAAG,CAAA;QACd,CAAC;IACL,CAAC;IAED,GAAG,CAAC,MAAM,CAAC,GAAG,EAAE,CAAC,EAAE,OAAO,CAAC,CAAA;AAC/B,CAAC"}
1
+ {"version":3,"file":"utils.js","sourceRoot":"","sources":["../src/utils.ts"],"names":[],"mappings":"AAAA,MAAM,UAAU,YAAY,CACxB,GAAQ,EACR,OAAU,EACV,GAA2B,EAC3B,aAAa,CAAC,CAAS,EAAE,CAAS,EAAE,EAAE,CAAC,CAAC,GAAG,CAAC;IAE5C,IAAI,GAAG,GAAG,CAAC,CAAA;IACX,IAAI,IAAI,GAAG,GAAG,CAAC,MAAM,CAAA;IACrB,MAAM,WAAW,GAAG,GAAG,CAAC,OAAO,CAAC,CAAA;IAEhC,OAAO,GAAG,GAAG,IAAI,EAAE,CAAC;QAChB,MAAM,GAAG,GAAG,CAAC,GAAG,GAAG,IAAI,CAAC,KAAK,CAAC,CAAA;QAC9B,MAAM,QAAQ,GAAG,GAAG,CAAC,GAAG,CAAC,GAAG,CAAM,CAAC,CAAA;QAEnC,IAAI,UAAU,CAAC,WAAW,EAAE,QAAQ,CAAC,GAAG,CAAC,EAAE,CAAC;YACxC,GAAG,GAAG,GAAG,GAAG,CAAC,CAAA;QACjB,CAAC;aAAM,CAAC;YACJ,IAAI,GAAG,GAAG,CAAA;QACd,CAAC;IACL,CAAC;IAED,GAAG,CAAC,MAAM,CAAC,GAAG,EAAE,CAAC,EAAE,OAAO,CAAC,CAAA;AAC/B,CAAC;AAED,MAAM,UAAU,aAAa,CAAC,KAAa;IACvC,MAAM,EAAE,GAAG,IAAI,CAAA;IACf,MAAM,EAAE,GAAG,IAAI,GAAG,EAAE,CAAA;IACpB,MAAM,EAAE,GAAG,IAAI,GAAG,EAAE,CAAA;IACpB,IAAI,KAAK,GAAG,EAAE,EAAE,CAAC;QACb,OAAO,GAAG,aAAa,CAAC,KAAK,GAAG,EAAE,CAAC,KAAK,CAAA;IAC5C,CAAC;SAAM,IAAI,KAAK,GAAG,EAAE,EAAE,CAAC;QACpB,OAAO,GAAG,aAAa,CAAC,KAAK,GAAG,EAAE,CAAC,KAAK,CAAA;IAC5C,CAAC;SAAM,CAAC;QACJ,OAAO,GAAG,aAAa,CAAC,KAAK,GAAG,EAAE,CAAC,KAAK,CAAA;IAC5C,CAAC;AACL,CAAC;AAED,SAAS,aAAa,CAAC,GAAW,EAAE,iBAAyB,CAAC;IAC1D,OAAO,UAAU,CAAC,GAAG,CAAC,OAAO,CAAC,cAAc,CAAC,CAAC,CAAC,QAAQ,EAAE,CAAA;AAC7D,CAAC"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@anandaramr/obscura",
3
- "version": "1.1.1",
3
+ "version": "1.2.0",
4
4
  "description": "A lightweight local media streaming server",
5
5
  "main": "dist/index.js",
6
6
  "type": "module",
@@ -14,14 +14,14 @@
14
14
  "files": [
15
15
  "dist/**/*",
16
16
  "public/**/*",
17
- "API.md",
18
17
  "README.md"
19
18
  ],
20
19
  "scripts": {
21
20
  "dev": "tsx watch src/index.ts",
22
21
  "build": "tsc",
23
22
  "start": "node dist/index.js",
24
- "prepublishOnly": "npm run build"
23
+ "prepublishOnly": "npm run build",
24
+ "watch": "tsc --watch"
25
25
  },
26
26
  "dependencies": {
27
27
  "chokidar": "^5.0.0",
package/public/app.js CHANGED
@@ -42,15 +42,32 @@ const eventSource = new EventSource('/api/events')
42
42
 
43
43
  eventSource.onmessage = evt => {
44
44
  const data = JSON.parse(evt.data)
45
- const grid = document.getElementById('grid')
46
45
 
47
46
  if (data.action === 'add') {
48
- insertGridItem(data.file, grid, true)
47
+ onAdd(data.file)
49
48
  } else if (data.action === 'remove') {
50
- removeGridItem(data.file.id)
49
+ onRemove(data.file.id)
50
+ } else if (data.action === 'update') {
51
+ onUpdate(data.file)
51
52
  }
52
53
  }
53
54
 
55
+ function onUpdate(file) {
56
+ onRemove(file.id)
57
+ onAdd(file)
58
+ }
59
+
60
+ function onRemove(fileId) {
61
+ files = files.filter(f => f.id !== fileId)
62
+ removeGridItem(fileId)
63
+ }
64
+
65
+ function onAdd(file) {
66
+ files.unshift(file)
67
+ const grid = document.getElementById('grid')
68
+ insertGridItem(file, grid, true)
69
+ }
70
+
54
71
  eventSource.onopen = () => {
55
72
  window.dispatchEvent(new Event('connected'))
56
73
  }
@@ -75,11 +92,11 @@ function insertGridItem(file, grid, prepend = false) {
75
92
  const preview = document.createElement('a')
76
93
 
77
94
  preview.className = 'grid-item'
78
- preview.href = `/api/files/${file.id}`
95
+ preview.href = getFileSource(file)
79
96
  preview.id = file.id
80
97
 
81
98
  const media = document.createElement('img')
82
- media.src = `/api/thumb/${file.id}`
99
+ media.src = getThumbSource(file)
83
100
  media.loading = 'lazy'
84
101
  media.className = file.type === 'image' ? 'img' : 'video'
85
102
  media.onerror = () => {
@@ -111,7 +128,7 @@ function insertGridItem(file, grid, prepend = false) {
111
128
 
112
129
  preview.onmouseenter = () => {
113
130
  if (!isMobileDevice()) {
114
- startVideoPreview(vid, file.id, media, icon)
131
+ startVideoPreview(vid, file, media, icon)
115
132
  }
116
133
  }
117
134
 
@@ -128,13 +145,13 @@ function insertGridItem(file, grid, prepend = false) {
128
145
 
129
146
  preview.onmouseenter = () => {
130
147
  if (!isMobileDevice()) {
131
- media.src = `/api/files/${file.id}`
148
+ media.src = getFileSource(file)
132
149
  }
133
150
  }
134
151
 
135
152
  preview.onmouseleave = () => {
136
153
  if (!isMobileDevice()) {
137
- media.src = `/api/thumb/${file.id}`
154
+ media.src = getThumbSource(file)
138
155
  }
139
156
  }
140
157
  }
@@ -149,6 +166,14 @@ function insertGridItem(file, grid, prepend = false) {
149
166
  elementMap.set(file.id, preview)
150
167
  }
151
168
 
169
+ function getFileSource(file) {
170
+ return `/api/files/${file.id}?v=${file.date}`
171
+ }
172
+
173
+ function getThumbSource(file) {
174
+ return `/api/thumb/${file.id}?v=${file.date}`
175
+ }
176
+
152
177
  function isServerReachable() {
153
178
  return eventSource.readyState === EventSource.OPEN
154
179
  }
@@ -245,7 +270,7 @@ function stopVideoPreview(vid, id, media, icon) {
245
270
  icon.classList.remove('fade')
246
271
  }
247
272
 
248
- function startVideoPreview(vid, id, media, icon) {
273
+ function startVideoPreview(vid, file, media, icon) {
249
274
  icon.classList.add('blink')
250
275
  vid.addEventListener(
251
276
  'playing',
@@ -257,14 +282,14 @@ function startVideoPreview(vid, id, media, icon) {
257
282
  )
258
283
 
259
284
  if (needsVideoLoading(vid)) {
260
- vid.src = `/api/files/${id}`
285
+ vid.src = getFileSource(file)
261
286
  vid.load()
262
287
  }
263
288
 
264
289
  vid.classList.remove('fade')
265
290
  media.classList.add('fade')
266
291
 
267
- onVideoPlay(id)
292
+ onVideoPlay(file.id)
268
293
  vid.currentTime = 0
269
294
  vid.play().catch(err => console.log('Play interrupted:', err))
270
295
  }
@@ -283,7 +308,6 @@ function removeGridItem(fileId) {
283
308
  const grid = document.getElementById('grid')
284
309
  grid.removeChild(child)
285
310
  elementMap.delete(fileId)
286
- files = files.filter(f => f.id !== fileId)
287
311
  }
288
312
  }
289
313
 
package/API.md DELETED
@@ -1,93 +0,0 @@
1
- # Obscura API
2
-
3
- Base URL: `/api`
4
-
5
- All endpoints return JSON unless otherwise noted.
6
-
7
- ## Files
8
-
9
- ### List files
10
-
11
- `GET /api/files`
12
-
13
- Returns all files sorted by date descending.
14
-
15
- **Response** `200 OK`
16
-
17
- ```json
18
- [
19
- {
20
- "id": "4186824008a4299b7587c6902d00e6df",
21
- "name": "beach_volleyball.mp4",
22
- "type": "video",
23
- "date": "2026-05-25T22:15:30.000Z",
24
- "size": 45102080,
25
- "isAnimated": false
26
- },
27
- {
28
- "id": "4316e0adec899c7fdd40bb55d47900e4",
29
- "name": "sunset.jpg",
30
- "type": "image",
31
- "date": "2026-05-25T23:11:00.000Z",
32
- "size": 2048576,
33
- "isAnimated": false
34
- }
35
- ]
36
- ```
37
-
38
- ### Get file
39
-
40
- `GET /api/files/:id`
41
-
42
- Returns the raw file for rendering in the browser.
43
-
44
- **Responses**
45
-
46
- - `200` — raw file bytes
47
- - `404` — file not found
48
-
49
- ## Thumbnails
50
-
51
- ### Get thumbnail
52
-
53
- `GET /api/thumb/:id`
54
-
55
- Returns a JPEG thumbnail for the file. Generated on first request and cached to disk. Images below the cache threshold are returned as-is without processing. Thumbnail generation is subject to the configured disk concurrency limit.
56
-
57
- **Responses**
58
-
59
- - `200` — JPEG thumbnail (or original file if below cache threshold)
60
- - `404` — file not found
61
- - `500` — thumbnail generation failed
62
-
63
- ## Events
64
-
65
- ### Subscribe to file changes
66
-
67
- `GET /api/events`
68
-
69
- Opens a server-sent events stream. Emits an event whenever a file is added or removed from the gallery directory. Reconnect and re-fetch `/api/files` if the connection drops.
70
-
71
- **Event shape**
72
-
73
- `add` — emitted when a file is added to the gallery directory.
74
-
75
- ```json
76
- {
77
- "action": "add",
78
- "file": {
79
- "id": "4186824008a4299b7587c6902d00e6df",
80
- "name": "beach_volleyball.mp4",
81
- "type": "video",
82
- "date": "2026-05-25T22:15:30.000Z",
83
- "size": 45102080,
84
- "isAnimated": false
85
- }
86
- }
87
- ```
88
-
89
- `remove` — emitted when a file is removed from the gallery directory.
90
-
91
- ```json
92
- { "action": "remove", "file": { "id": "4186824008a4299b7587c6902d00e6df" } }
93
- ```