Spaces:
Sleeping
Sleeping
File size: 4,400 Bytes
6678fa1 | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 | /**
* Local File Storage
*
* Stores uploaded files locally in the uploads/ directory.
* Files are served via Express static middleware.
*/
import fs from "fs/promises";
import path from "path";
import { fileURLToPath } from "url";
import { nanoid } from "nanoid";
// Get directory name in ESM
const __filename = fileURLToPath(import.meta.url);
const __dirname = path.dirname(__filename);
// Base directory for uploads (relative to project root)
const UPLOADS_DIR = path.resolve(__dirname, "../uploads");
// Subdirectories
const TRACKS_DIR = path.join(UPLOADS_DIR, "tracks");
const STEMS_DIR = path.join(UPLOADS_DIR, "stems");
/**
* Ensure upload directories exist
*/
export async function ensureUploadDirs(): Promise<void> {
await fs.mkdir(TRACKS_DIR, { recursive: true });
await fs.mkdir(STEMS_DIR, { recursive: true });
}
/**
* Get the uploads base directory path
*/
export function getUploadsDir(): string {
return UPLOADS_DIR;
}
/**
* Save an uploaded track file
*
* @param userId User ID
* @param fileName Original filename
* @param data File data as Buffer
* @returns Object with fileKey (relative path) and filePath (absolute path)
*/
export async function saveTrackFile(
userId: number,
fileName: string,
data: Buffer
): Promise<{ fileKey: string; filePath: string; fileUrl: string }> {
await ensureUploadDirs();
// Create user-specific directory
const userDir = path.join(TRACKS_DIR, String(userId));
await fs.mkdir(userDir, { recursive: true });
// Generate unique filename
const ext = path.extname(fileName) || ".mp3";
const uniqueName = `${nanoid(16)}${ext}`;
const filePath = path.join(userDir, uniqueName);
// Write file
await fs.writeFile(filePath, data);
// Generate relative key for database storage
const fileKey = `tracks/${userId}/${uniqueName}`;
// URL path for serving (will be served via /uploads/ route)
const fileUrl = `/uploads/${fileKey}`;
return { fileKey, filePath, fileUrl };
}
/**
* Save a stem file from ML processing
*
* @param trackId Track ID
* @param stemType Stem type (vocals, drums, bass, other)
* @param sourcePath Source file path from ML output
* @returns Object with fileKey, filePath, and fileUrl
*/
export async function saveStemFile(
trackId: number,
stemType: string,
sourcePath: string
): Promise<{ fileKey: string; filePath: string; fileUrl: string }> {
await ensureUploadDirs();
// Create track-specific stems directory
const trackStemsDir = path.join(STEMS_DIR, String(trackId));
await fs.mkdir(trackStemsDir, { recursive: true });
// Get extension from source
const ext = path.extname(sourcePath) || ".mp3";
const uniqueName = `${stemType}-${nanoid(8)}${ext}`;
const filePath = path.join(trackStemsDir, uniqueName);
// Copy file from ML output to uploads directory
await fs.copyFile(sourcePath, filePath);
// Generate relative key for database storage
const fileKey = `stems/${trackId}/${uniqueName}`;
// URL path for serving
const fileUrl = `/uploads/${fileKey}`;
return { fileKey, filePath, fileUrl };
}
/**
* Get the absolute path for a file key
*/
export function getFilePath(fileKey: string): string {
return path.join(UPLOADS_DIR, fileKey);
}
/**
* Check if a file exists
*/
export async function fileExists(fileKey: string): Promise<boolean> {
try {
await fs.access(getFilePath(fileKey));
return true;
} catch {
return false;
}
}
/**
* Delete a file
*/
export async function deleteFile(fileKey: string): Promise<void> {
try {
await fs.unlink(getFilePath(fileKey));
} catch {
// Ignore if file doesn't exist
}
}
/**
* Get file stats
*/
export async function getFileStats(fileKey: string): Promise<{ size: number } | null> {
try {
const stats = await fs.stat(getFilePath(fileKey));
return { size: stats.size };
} catch {
return null;
}
}
/**
* Create a temp directory for ML processing output
*/
export async function createTempDir(prefix: string): Promise<string> {
const tempDir = path.join(UPLOADS_DIR, "temp", `${prefix}-${nanoid(8)}`);
await fs.mkdir(tempDir, { recursive: true });
return tempDir;
}
/**
* Clean up a temp directory
*/
export async function cleanupTempDir(tempDir: string): Promise<void> {
try {
await fs.rm(tempDir, { recursive: true, force: true });
} catch {
// Ignore errors
}
}
|