fix: adjust free space

This commit is contained in:
WonderAliceUwU committed 2026-08-03 10:07:03 +02:00
1 parent 5013d16b35
commit 7bd8b0600f
6 files changed
+47 -34

No files matched your search

-2
View File
@@ -13,8 +13,6 @@ services:
environment:
PORT: "8787"
OMNIARR_DATA_DIR: /app/data
OMNIARR_STORAGE_PATH: /media
TMDB_BEARER_TOKEN: ""
volumes:
- ./data:/app/data
- ./media:/media:ro
+3 -23
View File
@@ -1,5 +1,5 @@
import { createServer, type IncomingMessage, type ServerResponse } from 'node:http';
import { readFile, statfs } from 'node:fs/promises';
import { readFile } from 'node:fs/promises';
import { resolve } from 'node:path';
import {
defaultConfig,
@@ -49,8 +49,6 @@ const SESSION_COOKIE = 'omniarr_session';
const SESSION_TTL_MS = 1000 * 60 * 60 * 12;
const sessions = new Map<string, SessionRecord>();
const failedAttempts = new Map<string, { count: number; lastAttempt: number }>();
const DATA_DIR = resolve(process.env.OMNIARR_DATA_DIR || resolve(process.cwd(), 'data'));
const STORAGE_DIR = resolve(process.env.OMNIARR_STORAGE_PATH || DATA_DIR);
const server = createServer(async (request, response) => {
try {
@@ -412,26 +410,8 @@ function createSession(encryptionKey: Buffer): string {
return token;
}
async function getDiskSpaceStatus(config: AppConfig): Promise<DiskSpaceStatus> {
if (process.env.OMNIARR_STORAGE_PATH) {
return getFilesystemDiskSpace(STORAGE_DIR);
}
const mediaDiskSpace = await getMediaDiskSpace(config);
if (mediaDiskSpace) {
return mediaDiskSpace;
}
return getFilesystemDiskSpace(DATA_DIR);
}
async function getFilesystemDiskSpace(path: string): Promise<DiskSpaceStatus> {
const stats = await statfs(path);
return {
totalBytes: Number(stats.bsize) * Number(stats.blocks),
availableBytes: Number(stats.bsize) * Number(stats.bavail),
path
};
async function getDiskSpaceStatus(config: AppConfig): Promise<DiskSpaceStatus | null> {
return getMediaDiskSpace(config);
}
function getSession(request: IncomingMessage): SessionRecord | null {
+40 -7
View File
@@ -443,8 +443,8 @@ export async function getServiceOptions(config: AppConfig): Promise<ServiceOptio
export async function getMediaDiskSpace(config: AppConfig): Promise<DiskSpaceStatus | null> {
const services = [
{ baseUrl: config.radarr.baseUrl, apiKey: config.radarr.apiKey, rootFolderPath: config.radarr.rootFolderPath },
{ baseUrl: config.sonarr.baseUrl, apiKey: config.sonarr.apiKey, rootFolderPath: config.sonarr.rootFolderPath }
{ source: 'radarr' as const, baseUrl: config.radarr.baseUrl, apiKey: config.radarr.apiKey, rootFolderPath: config.radarr.rootFolderPath },
{ source: 'sonarr' as const, baseUrl: config.sonarr.baseUrl, apiKey: config.sonarr.apiKey, rootFolderPath: config.sonarr.rootFolderPath }
];
for (const service of services) {
@@ -453,18 +453,25 @@ export async function getMediaDiskSpace(config: AppConfig): Promise<DiskSpaceSta
}
try {
const folders = await fetchJson<Record<string, unknown>[]>(`${service.baseUrl}/api/v3/rootFolder`, {
const disks = await fetchJson<Record<string, unknown>[]>(`${service.baseUrl}/api/v3/diskspace`, {
headers: { 'X-Api-Key': service.apiKey }
});
const folder = folders.find((entry) => String(entry.path || '') === service.rootFolderPath) || folders[0];
const totalBytes = Number(folder?.totalSpace);
const availableBytes = Number(folder?.freeSpace);
const disk = selectDiskSpaceForRootFolder(disks, service.rootFolderPath);
if (!disk) {
console.warn(
`[Storage] ${service.source} did not report disk space for ${service.rootFolderPath}. Reported paths: ${disks.map((entry) => String(entry.path || '')).join(', ') || 'none'}`
);
continue;
}
const totalBytes = Number(disk?.totalSpace);
const availableBytes = Number(disk?.freeSpace);
if (Number.isFinite(totalBytes) && totalBytes > 0 && Number.isFinite(availableBytes) && availableBytes >= 0) {
return {
totalBytes,
availableBytes,
path: String(folder?.path || service.rootFolderPath)
path: String(disk?.path || service.rootFolderPath),
source: service.source
};
}
} catch {
@@ -475,6 +482,32 @@ export async function getMediaDiskSpace(config: AppConfig): Promise<DiskSpaceSta
return null;
}
function selectDiskSpaceForRootFolder(
disks: Record<string, unknown>[],
rootFolderPath: string
): Record<string, unknown> | undefined {
const normalizedRoot = rootFolderPath.replace(/\/+$/, '');
const matchingDisks = disks
.filter((disk) => {
const diskPath = String(disk.path || '').replace(/\/+$/, '');
return diskPath && (normalizedRoot === diskPath || normalizedRoot.startsWith(`${diskPath}/`));
})
.sort((left, right) => String(right.path || '').length - String(left.path || '').length);
if (matchingDisks[0]) {
return matchingDisks[0];
}
if (!normalizedRoot) {
return disks.find((disk) => {
const path = String(disk.path || '').replace(/\/+$/, '');
return path && path !== '/config';
});
}
return undefined;
}
export async function loadJellyfinUsers(baseUrl: string, apiKey: string): Promise<SelectOption[]> {
if (!baseUrl.trim() || !apiKey.trim()) {
return [];
+1
View File
@@ -89,6 +89,7 @@ export interface DiskSpaceStatus {
totalBytes: number;
availableBytes: number;
path?: string;
source: 'radarr' | 'sonarr';
}
export interface MediaCard {
+2 -1
View File
@@ -679,7 +679,8 @@ function formatBytes(bytes: number): string {
const units = ['B', 'KB', 'MB', 'GB', 'TB']
const unitIndex = Math.min(Math.floor(Math.log(bytes) / Math.log(1024)), units.length - 1)
const value = bytes / (1024 ** unitIndex)
return `${value >= 10 || unitIndex === 0 ? value.toFixed(0) : value.toFixed(1)} ${units[unitIndex]}`
const formattedValue = unitIndex === 0 || Number.isInteger(value) ? value.toFixed(0) : value.toFixed(1)
return `${formattedValue} ${units[unitIndex]}`
}
function LoadingScreen() {
+1 -1
View File
@@ -84,7 +84,7 @@ export const api = {
body: JSON.stringify(payload),
}),
getDashboard: () => request<DashboardResponse>('/api/dashboard'),
getDiskSpace: () => request<DiskSpaceStatus>('/api/storage'),
getDiskSpace: () => request<DiskSpaceStatus | null>('/api/storage'),
getCalendar: (start: Date, end: Date) => request<CalendarResponse>(`/api/calendar?start=${start.toISOString()}&end=${end.toISOString()}`),
getHub: (page: HubPageResponse['page']) => request<HubPageResponse>(`/api/hubs/${page}`),
searchTitles: (query: string) => request<SearchResponse>(`/api/search?query=${encodeURIComponent(query)}`),