Spaces:
Configuration error
Configuration error
Dee Ferdinand commited on
Commit ·
10992d3
1
Parent(s): 345fbd8
feat: init Dee Video Studio — HyperFrames cloud render for testimonial/teaser/trailer videos
Browse files- 4 workflows: testimonial (75s), teaser (30s), trailer (60s), community (60s)
- 6 royalty-free Pixabay music tracks auto-selected by workflow
- WebSocket real-time render progress
- Dark-mode Studio UI with drag-drop upload
- HuggingFace Docker Space ready (port 7860)
- lib/music.js +51 -0
lib/music.js
ADDED
|
@@ -0,0 +1,51 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
import fs from 'fs';
|
| 2 |
+
import path from 'path';
|
| 3 |
+
import { fileURLToPath } from 'url';
|
| 4 |
+
import { createWriteStream } from 'fs';
|
| 5 |
+
import { pipeline } from 'stream/promises';
|
| 6 |
+
|
| 7 |
+
const __dirname = path.dirname(fileURLToPath(import.meta.url));
|
| 8 |
+
const LIB = path.join(__dirname, '..', 'music', 'library');
|
| 9 |
+
|
| 10 |
+
export const MUSIC_LIBRARY = [
|
| 11 |
+
{ file: 'corporate-motivation.mp3', mood: 'corporate', bpm: 120, duration: 120, tags: ['corporate', 'testimonial', 'professional', 'uplifting'], url: 'https://cdn.pixabay.com/download/audio/2022/05/27/audio_1808fbf07a.mp3', license: 'Pixabay License' },
|
| 12 |
+
{ file: 'inspiring-cinematic.mp3', mood: 'cinematic', bpm: 90, duration: 150, tags: ['cinematic', 'trailer', 'emotional', 'inspiring'], url: 'https://cdn.pixabay.com/download/audio/2023/02/28/audio_a74ea30b0d.mp3', license: 'Pixabay License' },
|
| 13 |
+
{ file: 'upbeat-community.mp3', mood: 'upbeat', bpm: 128, duration: 90, tags: ['community', 'public-event', 'energetic', 'positive'], url: 'https://cdn.pixabay.com/download/audio/2022/08/02/audio_2dde668d05.mp3', license: 'Pixabay License' },
|
| 14 |
+
{ file: 'warm-documentary.mp3', mood: 'warm', bpm: 75, duration: 120, tags: ['community', 'documentary', 'story', 'heartfelt'], url: 'https://cdn.pixabay.com/download/audio/2023/01/30/audio_16b3ef0928.mp3', license: 'Pixabay License' },
|
| 15 |
+
{ file: 'tech-corporate.mp3', mood: 'tech', bpm: 110, duration: 100, tags: ['ai', 'tech', 'corporate', 'modern', 'training'], url: 'https://cdn.pixabay.com/download/audio/2022/11/22/audio_4d566a5081.mp3', license: 'Pixabay License' },
|
| 16 |
+
{ file: 'action-sport.mp3', mood: 'energetic', bpm: 145, duration: 80, tags: ['viral', 'hook', 'energetic', 'teaser'], url: 'https://cdn.pixabay.com/download/audio/2022/06/08/audio_c8a2c5a45d.mp3', license: 'Pixabay License' },
|
| 17 |
+
];
|
| 18 |
+
|
| 19 |
+
const MOOD_MAP = {
|
| 20 |
+
testimonial: ['corporate', 'warm'],
|
| 21 |
+
teaser: ['energetic', 'tech'],
|
| 22 |
+
trailer: ['cinematic', 'energetic'],
|
| 23 |
+
community: ['warm', 'upbeat'],
|
| 24 |
+
};
|
| 25 |
+
|
| 26 |
+
export async function getMusicTrack(trackName, workflow, duration, onProgress) {
|
| 27 |
+
fs.mkdirSync(LIB, { recursive: true });
|
| 28 |
+
let track;
|
| 29 |
+
if (trackName === 'auto') {
|
| 30 |
+
const moods = MOOD_MAP[workflow] || ['corporate'];
|
| 31 |
+
track = MUSIC_LIBRARY.find(t => t.tags.some(tag => moods.includes(tag))) || MUSIC_LIBRARY[0];
|
| 32 |
+
} else {
|
| 33 |
+
track = MUSIC_LIBRARY.find(t => t.file === trackName || t.mood === trackName) || MUSIC_LIBRARY[0];
|
| 34 |
+
}
|
| 35 |
+
const destPath = path.join(LIB, track.file);
|
| 36 |
+
if (!fs.existsSync(destPath)) {
|
| 37 |
+
onProgress?.({ status: 'downloading_music', progress: 10 });
|
| 38 |
+
await downloadFile(track.url, destPath);
|
| 39 |
+
}
|
| 40 |
+
return destPath;
|
| 41 |
+
}
|
| 42 |
+
|
| 43 |
+
async function downloadFile(url, dest) {
|
| 44 |
+
const res = await fetch(url);
|
| 45 |
+
if (!res.ok) throw new Error(`Music download failed: ${res.status}`);
|
| 46 |
+
await pipeline(res.body, createWriteStream(dest));
|
| 47 |
+
}
|
| 48 |
+
|
| 49 |
+
export function listTracks() {
|
| 50 |
+
return MUSIC_LIBRARY.map(({ file, mood, bpm, duration, tags, license }) => ({ file, mood, bpm, duration, tags, license }));
|
| 51 |
+
}
|