atualizacoes codex

This commit is contained in:
Vitex Tecnologia
2026-03-20 00:02:12 -03:00
parent 6bf7e7d42e
commit 6537e2dd53
10 changed files with 232 additions and 67 deletions
+83
View File
@@ -180,6 +180,89 @@ class AudioGenerationService {
this.toApiError(error, 'Erro ao deletar áudio');
}
}
/**
* Baixa o arquivo no navegador (sem navegar para a URL).
* Usa blob local + <a download> — necessário porque links cross-origin ignoram `download` e abrem a URL.
*/
async downloadAudioFile(audioUrl: string, filename?: string): Promise<void> {
const urlTrim = audioUrl?.trim();
if (!urlTrim) {
throw new Error('URL do áudio inválida');
}
const safeName = (filename || `audio_${Date.now()}.mp3`).replace(/[/\\?%*:|"<>]/g, '_');
let sameOrigin = false;
try {
const u = new URL(urlTrim, typeof window !== 'undefined' ? window.location.href : undefined);
sameOrigin = typeof window !== 'undefined' && u.origin === window.location.origin;
} catch {
sameOrigin = false;
}
const fetchBlob = async (): Promise<Blob> => {
const response = await fetch(urlTrim, {
mode: 'cors',
credentials: sameOrigin ? 'include' : 'omit',
cache: 'no-store',
});
if (!response.ok) {
throw new Error(`Falha ao baixar (HTTP ${response.status})`);
}
return response.blob();
};
const xhrBlob = (): Promise<Blob> =>
new Promise((resolve, reject) => {
const xhr = new XMLHttpRequest();
xhr.open('GET', urlTrim, true);
xhr.responseType = 'blob';
xhr.onload = () => {
if (xhr.status >= 200 && xhr.status < 300) {
resolve(xhr.response);
} else {
reject(new Error(`Falha ao baixar (HTTP ${xhr.status})`));
}
};
xhr.onerror = () => reject(new Error('Falha de rede ao baixar o áudio'));
xhr.send();
});
let blob: Blob;
try {
blob = await fetchBlob();
} catch (e1) {
try {
blob = await xhrBlob();
} catch (e2) {
console.error('downloadAudioFile:', e1, e2);
throw new Error(
'Não foi possível baixar o áudio. Se o arquivo estiver em outro domínio, é preciso CORS liberando GET para esta origem.'
);
}
}
const needsMimeFix =
!blob.type ||
blob.type === 'application/octet-stream' ||
blob.type === 'text/html';
const typedBlob = needsMimeFix ? new Blob([blob], { type: 'audio/mpeg' }) : blob;
const objectUrl = URL.createObjectURL(typedBlob);
try {
const a = document.createElement('a');
a.href = objectUrl;
a.download = safeName.endsWith('.mp3') ? safeName : `${safeName}.mp3`;
a.style.display = 'none';
a.rel = 'noopener';
document.body.appendChild(a);
a.click();
document.body.removeChild(a);
} finally {
URL.revokeObjectURL(objectUrl);
}
}
}
export const audioGenerationService = new AudioGenerationService();