11
This commit is contained in:
parent
9bcf455037
commit
2c36af7989
@ -113,7 +113,7 @@ app.use('/api/tracks', passport.authenticate('jwt', {session: false}), tracksRou
|
||||
app.use('/api/midi_clips', passport.authenticate('jwt', {session: false}), midi_clipsRoutes);
|
||||
app.use('/api/audio_clips', passport.authenticate('jwt', {session: false}), audio_clipsRoutes);
|
||||
app.use('/api/lyrics', passport.authenticate('jwt', {session: false}), lyricsRoutes);
|
||||
app.use('/api/ai_song_requests', passport.authenticate('jwt', {session: false}), ai_song_requestsRoutes);
|
||||
app.use('/api/ai_song_requests', ai_song_requestsRoutes);
|
||||
app.use('/api/exports', passport.authenticate('jwt', {session: false}), exportsRoutes);
|
||||
app.use('/api/collaborations', passport.authenticate('jwt', {session: false}), collaborationsRoutes);
|
||||
app.use('/api/project_assets', passport.authenticate('jwt', {session: false}), project_assetsRoutes);
|
||||
|
||||
@ -1,4 +1,5 @@
|
||||
const express = require('express');
|
||||
const passport = require('passport');
|
||||
|
||||
const Ai_song_requestsService = require('../services/ai_song_requests');
|
||||
const Ai_song_requestsDBApi = require('../db/api/ai_song_requests');
|
||||
@ -15,8 +16,7 @@ const {
|
||||
checkCrudPermissions,
|
||||
} = require('../middlewares/check-permissions');
|
||||
|
||||
router.use(checkCrudPermissions('ai_song_requests'));
|
||||
|
||||
// Proxy route should be PUBLIC for browser <audio> tag to work
|
||||
router.get('/proxy-audio', wrapAsync(async (req, res) => {
|
||||
const url = req.query.url;
|
||||
if (!url) {
|
||||
@ -34,7 +34,7 @@ router.get('/proxy-audio', wrapAsync(async (req, res) => {
|
||||
}
|
||||
});
|
||||
|
||||
res.setHeader('Content-Type', response.headers['content-type']);
|
||||
res.setHeader('Content-Type', response.headers['content-type'] || 'audio/mpeg');
|
||||
if (response.headers['content-length']) {
|
||||
res.setHeader('Content-Length', response.headers['content-length']);
|
||||
}
|
||||
@ -46,6 +46,10 @@ router.get('/proxy-audio', wrapAsync(async (req, res) => {
|
||||
}
|
||||
}));
|
||||
|
||||
// Apply authentication to ALL other routes
|
||||
router.use(passport.authenticate('jwt', { session: false }));
|
||||
router.use(checkCrudPermissions('ai_song_requests'));
|
||||
|
||||
router.post('/generate-lyrics', wrapAsync(async (req, res) => {
|
||||
const payload = await Ai_song_requestsService.generateLyrics(req.body.data, req.currentUser);
|
||||
res.status(200).send(payload);
|
||||
|
||||
@ -106,8 +106,8 @@ module.exports = class Ai_song_requestsService {
|
||||
|
||||
// Selection logic for "Real" sounding audio samples
|
||||
const rawAudioUrl = this.getRealAudioUrl(style, voiceType, instrumental);
|
||||
// Use proxy to avoid 403/CORS issues
|
||||
const audioUrl = `/api/ai_song_requests/proxy-audio?url=${encodeURIComponent(rawAudioUrl)}`;
|
||||
// Use proxy to avoid 403/CORS issues - Store WITHOUT /api prefix for axios compatibility
|
||||
const audioUrl = `/ai_song_requests/proxy-audio?url=${encodeURIComponent(rawAudioUrl)}`;
|
||||
|
||||
const project = await ProjectsDBApi.create({
|
||||
title: aiData.title,
|
||||
@ -117,7 +117,7 @@ module.exports = class Ai_song_requestsService {
|
||||
owner: currentUser.id,
|
||||
audio_url: audioUrl,
|
||||
ai_data: aiData,
|
||||
createdBy: currentUser.id
|
||||
createdById: currentUser.id
|
||||
}, { transaction });
|
||||
|
||||
// Create tracks and clips for the studio engine
|
||||
@ -127,7 +127,7 @@ module.exports = class Ai_song_requestsService {
|
||||
projectId: project.id,
|
||||
order_index: 0,
|
||||
volume: 1.0,
|
||||
createdBy: currentUser.id
|
||||
createdById: currentUser.id
|
||||
}, { transaction });
|
||||
|
||||
await db.audio_clips.create({
|
||||
@ -136,7 +136,7 @@ module.exports = class Ai_song_requestsService {
|
||||
start_bar: 0,
|
||||
length_bars: 32,
|
||||
gain: 1.0,
|
||||
createdBy: currentUser.id
|
||||
createdById: currentUser.id
|
||||
}, { transaction });
|
||||
|
||||
await Ai_song_requestsDBApi.create(
|
||||
@ -159,9 +159,7 @@ module.exports = class Ai_song_requestsService {
|
||||
await transaction.commit();
|
||||
|
||||
return {
|
||||
...project,
|
||||
id: project.id,
|
||||
title: project.title,
|
||||
...project.get({ plain: true }),
|
||||
ai_data: aiData,
|
||||
audio_url: audioUrl
|
||||
};
|
||||
|
||||
@ -160,11 +160,17 @@ const SunoStudio = () => {
|
||||
setIsPlaying(true);
|
||||
if (audioRef.current) {
|
||||
// Ensure audio_url is present
|
||||
const url = track?.audio_url;
|
||||
let url = track?.audio_url;
|
||||
if (!url) {
|
||||
toast.error('Áudio não disponível');
|
||||
return;
|
||||
}
|
||||
|
||||
// Handle proxy URL for <audio> tag (needs /api prefix to be proxied by Apache)
|
||||
if (url.startsWith('/') && !url.startsWith('/api/') && !url.startsWith('http')) {
|
||||
url = `/api${url}`;
|
||||
}
|
||||
|
||||
audioRef.current.src = url;
|
||||
audioRef.current.load();
|
||||
audioRef.current.play().catch((e: any) => {
|
||||
@ -212,24 +218,34 @@ const SunoStudio = () => {
|
||||
if (!track?.audio_url) return;
|
||||
try {
|
||||
toast.info('Preparando download...', { theme: 'dark' });
|
||||
const response = await axios.get(track.audio_url, {
|
||||
|
||||
// Remove /api/ prefix if present for axios because it already has it in baseURL
|
||||
let url = track.audio_url;
|
||||
if (url.startsWith('/api/')) {
|
||||
url = url.substring(4);
|
||||
}
|
||||
|
||||
const response = await axios.get(url, {
|
||||
responseType: 'blob'
|
||||
});
|
||||
const url = window.URL.createObjectURL(new Blob([response.data]));
|
||||
const blobUrl = window.URL.createObjectURL(new Blob([response.data]));
|
||||
const link = document.createElement('a');
|
||||
link.href = url;
|
||||
// If user mentioned MP4, maybe they want it as MP4? We provide MP3/MPEG
|
||||
link.href = blobUrl;
|
||||
const extension = track.audio_url.includes('.mp3') ? 'mp3' : 'mp4';
|
||||
link.setAttribute('download', `${track.title || 'ai-song'}.${extension}`);
|
||||
document.body.appendChild(link);
|
||||
link.click();
|
||||
document.body.removeChild(link);
|
||||
window.URL.revokeObjectURL(url);
|
||||
window.URL.revokeObjectURL(blobUrl);
|
||||
toast.success('Download concluído!', { theme: 'dark' });
|
||||
} catch (e) {
|
||||
console.error('Download error:', e);
|
||||
// Fallback to direct link
|
||||
window.open(track.audio_url, '_blank');
|
||||
// Fallback to direct link with /api prefix for browser
|
||||
let url = track.audio_url;
|
||||
if (url.startsWith('/') && !url.startsWith('/api/') && !url.startsWith('http')) {
|
||||
url = `/api${url}`;
|
||||
}
|
||||
window.open(url, '_blank');
|
||||
}
|
||||
};
|
||||
|
||||
@ -621,4 +637,4 @@ SunoStudio.getLayout = function getLayout(page: ReactElement) {
|
||||
return <LayoutAuthenticated>{page}</LayoutAuthenticated>;
|
||||
};
|
||||
|
||||
export default SunoStudio;
|
||||
export default SunoStudio;
|
||||
Loading…
x
Reference in New Issue
Block a user