Files
ace-step-ui/server/src/services/storage/local.ts
T
fspecii e1625a717d Fix multiple issues: format API, Gradio availability, storage, UI responsiveness
- Format endpoint now calls ACE-Step /format_input REST API directly instead of
  spawning Python, fixing ENOENT errors on Windows (#44, #27, #34)
- isGradioAvailable() tries /gradio_api/info, /info, / in sequence to handle
  Gradio 4.x/5.x/6.x version differences, fixing generation fallback (#53, #20)
- Storage getUrl/getPublicUrl normalize /audio/ prefix to prevent double-prefix
  URLs when reference tracks are used for cover generation (#10)
- Gradio args: fix normalization_db default from 0.0 to -1.0 (Gradio default)
- Volume popover: add 400ms delay before hiding to prevent accidental dismissal (#51)
- Polling: skip setSongs state update when nothing changed to reduce re-renders (#51)
- FFmpeg: add jsdelivr CDN fallback when unpkg fails (#30)
- Model switching: add switchModelIfNeeded() via /v1/init REST API (#45)
2026-03-02 17:43:53 +02:00

63 lines
1.9 KiB
TypeScript

import { writeFile, unlink, stat, mkdir, copyFile } from 'fs/promises';
import path from 'path';
import { fileURLToPath } from 'url';
import type { StorageProvider } from './index.js';
const __filename = fileURLToPath(import.meta.url);
const __dirname = path.dirname(__filename);
const AUDIO_DIR = path.join(__dirname, '../../../public/audio');
export class LocalStorageProvider implements StorageProvider {
private audioDir: string;
constructor() {
this.audioDir = AUDIO_DIR;
}
async upload(key: string, data: Buffer, _contentType: string): Promise<string> {
const filepath = path.join(this.audioDir, key);
await mkdir(path.dirname(filepath), { recursive: true });
await writeFile(filepath, data);
return key;
}
async getUrl(key: string, _expiresIn?: number): Promise<string> {
const cleanKey = key.startsWith('/audio/') ? key.slice('/audio/'.length) : key;
return `/audio/${cleanKey.replace(/^\/+/, '')}`;
}
getPublicUrl(key: string): string {
const cleanKey = key.startsWith('/audio/') ? key.slice('/audio/'.length) : key;
return `/audio/${cleanKey.replace(/^\/+/, '')}`;
}
async delete(key: string): Promise<void> {
const filepath = path.join(this.audioDir, key);
try {
await unlink(filepath);
} catch (err) {
const error = err as NodeJS.ErrnoException;
if (error.code !== 'ENOENT') {
throw error;
}
}
}
async exists(key: string): Promise<boolean> {
const filepath = path.join(this.audioDir, key);
try {
await stat(filepath);
return true;
} catch {
return false;
}
}
async copy(sourceKey: string, destKey: string): Promise<void> {
const sourcePath = path.join(this.audioDir, sourceKey);
const destPath = path.join(this.audioDir, destKey);
await mkdir(path.dirname(destPath), { recursive: true });
await copyFile(sourcePath, destPath);
}
}