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