feat: merge audio
This commit is contained in:
@@ -199,8 +199,6 @@ const PlaybackDownload = ({ route }) => {
|
||||
}
|
||||
}, [projectForDownload?.playbackUrl])
|
||||
|
||||
|
||||
|
||||
const resolveAudioUrl = useCallback(() => {
|
||||
if (typeof projectForDownload?.songUrl === 'string' && projectForDownload.songUrl.trim()) {
|
||||
return projectForDownload.songUrl.trim()
|
||||
@@ -217,61 +215,32 @@ const PlaybackDownload = ({ route }) => {
|
||||
return null
|
||||
}, [projectForDownload])
|
||||
|
||||
const handleDownloadUri = useCallback(async () => {
|
||||
if (isPublishing || isDownloading) return
|
||||
const processMerge = useCallback(async () => {
|
||||
if (action !== 'playback') {
|
||||
setTooltip({
|
||||
type: 'error',
|
||||
text: 'Téléchargement indisponible pour cette action',
|
||||
})
|
||||
return
|
||||
throw new Error('Téléchargement indisponible pour cette action')
|
||||
}
|
||||
|
||||
const playbackUrlToDownload = pendingPlaybackUrl || projectForDownload?.playbackUrl || null
|
||||
if (playbackUrlToDownload) {
|
||||
setIsDownloading(true)
|
||||
try {
|
||||
await triggerDownload(playbackUrlToDownload, projectForDownload?.title)
|
||||
} finally {
|
||||
setIsDownloading(false)
|
||||
}
|
||||
return
|
||||
}
|
||||
const cachedPlaybackUrl = pendingPlaybackUrl || projectForDownload?.playbackUrl || null
|
||||
if (cachedPlaybackUrl) return cachedPlaybackUrl
|
||||
|
||||
if (!projectForDownload?.id) {
|
||||
setTooltip({
|
||||
type: 'error',
|
||||
text: 'Projet introuvable pour ce playback',
|
||||
})
|
||||
return
|
||||
throw new Error('Projet introuvable pour ce playback')
|
||||
}
|
||||
|
||||
if (!uri) {
|
||||
setTooltip({
|
||||
type: 'error',
|
||||
text: 'Aucune vidéo trouvée pour ce playback',
|
||||
})
|
||||
return
|
||||
throw new Error('Aucune vidéo trouvée pour ce playback')
|
||||
}
|
||||
|
||||
if (!currentUID) {
|
||||
setTooltip({
|
||||
type: 'error',
|
||||
text: 'Utilisateur non authentifié',
|
||||
})
|
||||
return
|
||||
throw new Error('Utilisateur non authentifié')
|
||||
}
|
||||
|
||||
const audioUrl = resolveAudioUrl()
|
||||
if (!audioUrl) {
|
||||
setTooltip({
|
||||
type: 'error',
|
||||
text: 'Aucune piste audio disponible pour ce projet',
|
||||
})
|
||||
return
|
||||
throw new Error('Aucune piste audio disponible pour ce projet')
|
||||
}
|
||||
|
||||
console.log('[PlaybackDownload] handleDownloadUri playback', {
|
||||
console.log('[PlaybackDownload] processMerge playback', {
|
||||
projectId: projectForDownload.id,
|
||||
uri,
|
||||
currentUID,
|
||||
@@ -279,7 +248,6 @@ const PlaybackDownload = ({ route }) => {
|
||||
|
||||
let tempSourcePath = null
|
||||
try {
|
||||
setIsDownloading(true)
|
||||
setIsLoading(true)
|
||||
const { sourcePath, videoUrl } = await uploadSourceRecording({
|
||||
uri,
|
||||
@@ -289,7 +257,7 @@ const PlaybackDownload = ({ route }) => {
|
||||
tempSourcePath = sourcePath
|
||||
|
||||
const payload = {
|
||||
projectId: projectForDownload?.id,
|
||||
projectId: projectForDownload.id,
|
||||
videoUrl,
|
||||
audioUrl,
|
||||
storagePath: `users/${currentUID}/projects/${projectForDownload.id}/playback.mp4`,
|
||||
@@ -303,29 +271,12 @@ const PlaybackDownload = ({ route }) => {
|
||||
|
||||
const resultURI = result?.url || null
|
||||
|
||||
if (resultURI) {
|
||||
setPendingPlaybackUrl(resultURI)
|
||||
setTooltip({
|
||||
type: 'success',
|
||||
text: 'Playback prêt à télécharger',
|
||||
})
|
||||
await triggerDownload(resultURI, projectForDownload?.title)
|
||||
if (tempSourcePath) {
|
||||
try {
|
||||
await firebase.storage().ref(tempSourcePath).delete()
|
||||
} catch (cleanupError) {
|
||||
console.log('[PlaybackDownload] unable to delete temp source', {
|
||||
message: cleanupError?.message,
|
||||
code: cleanupError?.code,
|
||||
})
|
||||
}
|
||||
}
|
||||
} else {
|
||||
setTooltip({
|
||||
type: 'error',
|
||||
text: 'Erreur lors de la publication du playback',
|
||||
})
|
||||
if (!resultURI) {
|
||||
throw new Error('Erreur lors de la publication du playback')
|
||||
}
|
||||
|
||||
setPendingPlaybackUrl(resultURI)
|
||||
return resultURI
|
||||
} catch (error) {
|
||||
console.log('[PlaybackDownload] error upload playback', {
|
||||
message: error?.message,
|
||||
@@ -333,31 +284,47 @@ const PlaybackDownload = ({ route }) => {
|
||||
name: error?.name,
|
||||
details: error?.details,
|
||||
})
|
||||
throw error
|
||||
} finally {
|
||||
if (tempSourcePath) {
|
||||
try {
|
||||
await firebase.storage().ref(tempSourcePath).delete()
|
||||
} catch { }
|
||||
} catch (cleanupError) {
|
||||
console.log('[PlaybackDownload] unable to delete temp source', {
|
||||
message: cleanupError?.message,
|
||||
code: cleanupError?.code,
|
||||
})
|
||||
}
|
||||
}
|
||||
releaseBlobUrl(uri || null)
|
||||
setIsLoading(false)
|
||||
}
|
||||
}, [action, currentUID, pendingPlaybackUrl, projectForDownload, resolveAudioUrl, setIsLoading, uri])
|
||||
|
||||
const handleDownloadUri = useCallback(async () => {
|
||||
if (isPublishing || isDownloading) return
|
||||
try {
|
||||
setIsDownloading(true)
|
||||
const resultURI = await processMerge()
|
||||
setTooltip({
|
||||
type: 'success',
|
||||
text: 'Playback prêt à télécharger',
|
||||
})
|
||||
await triggerDownload(resultURI, projectForDownload?.title)
|
||||
} catch (error) {
|
||||
setTooltip({
|
||||
type: 'error',
|
||||
text: String(error?.message || 'Erreur lors de la publication du playback'),
|
||||
})
|
||||
} finally {
|
||||
releaseBlobUrl(uri || null)
|
||||
setIsDownloading(false)
|
||||
setIsLoading(false)
|
||||
}
|
||||
}, [
|
||||
action,
|
||||
currentUID,
|
||||
isDownloading,
|
||||
isPublishing,
|
||||
pendingPlaybackUrl,
|
||||
processMerge,
|
||||
projectForDownload,
|
||||
resolveAudioUrl,
|
||||
setIsLoading,
|
||||
setTooltip,
|
||||
uri,
|
||||
])
|
||||
|
||||
const startPlaybackDownloadCheckout = useCallback(
|
||||
@@ -397,34 +364,21 @@ const PlaybackDownload = ({ route }) => {
|
||||
]
|
||||
)
|
||||
|
||||
const handleDownloadPress = useCallback(() => {
|
||||
if (isDownloading || isCheckoutLaunching) {
|
||||
return
|
||||
const handleDownloadPress = async () => {
|
||||
if (!canDownloadPlayback) return startPlaybackDownloadCheckout()
|
||||
|
||||
if (isDownloading || isPublishing) return
|
||||
|
||||
try {
|
||||
setIsDownloading(true)
|
||||
const url = await processMerge()
|
||||
await triggerDownload(url, projectForDownload?.title)
|
||||
} catch (err) {
|
||||
setTooltip({ type: 'error', text: err.message })
|
||||
} finally {
|
||||
setIsDownloading(false)
|
||||
}
|
||||
if (canDownloadPlayback) {
|
||||
handleDownloadUri()
|
||||
return
|
||||
}
|
||||
if (downloadPaymentPending) {
|
||||
Alert.alert(
|
||||
'Paiement en attente',
|
||||
"Le paiement n'est pas encore confirmé. Si tu as déjà payé, patiente quelques instants.",
|
||||
[
|
||||
{ text: 'Attendre', style: 'cancel' },
|
||||
{ text: 'Relancer le paiement', onPress: () => startPlaybackDownloadCheckout({ force: true }) },
|
||||
]
|
||||
)
|
||||
return
|
||||
}
|
||||
startPlaybackDownloadCheckout()
|
||||
}, [
|
||||
canDownloadPlayback,
|
||||
downloadPaymentPending,
|
||||
handleDownloadUri,
|
||||
isCheckoutLaunching,
|
||||
isDownloading,
|
||||
startPlaybackDownloadCheckout,
|
||||
])
|
||||
}
|
||||
|
||||
useEffect(() => {
|
||||
if (!downloadPaymentPending || !hasPaidPlaybackDownload || isDownloading) {
|
||||
@@ -435,135 +389,29 @@ const PlaybackDownload = ({ route }) => {
|
||||
}, [downloadPaymentPending, handleDownloadUri, hasPaidPlaybackDownload, isDownloading])
|
||||
|
||||
const handlePublish = async () => {
|
||||
if (isPublishing) {
|
||||
console.log('[PlaybackDownload] publish blocked: already publishing')
|
||||
return
|
||||
}
|
||||
if (!hasAcceptedPublication) {
|
||||
console.log('[PlaybackDownload] publish blocked: publication not accepted')
|
||||
setTooltip({
|
||||
type: 'error',
|
||||
text: 'Confirme la diffusion de ton playback sur Musicland avant de publier',
|
||||
})
|
||||
return
|
||||
}
|
||||
if (!projectForDownload?.id) {
|
||||
console.log('[PlaybackDownload] publish: missing project id, navigating directly', {
|
||||
projectForDownload: projectForDownload?.id,
|
||||
})
|
||||
setTooltip({
|
||||
type: 'success',
|
||||
text: publishSuccessMessage,
|
||||
})
|
||||
navigate(Routes.PublishYoutube)
|
||||
return
|
||||
}
|
||||
let tempSourcePath = null
|
||||
let playbackUrlToSave = pendingPlaybackUrl || projectForDownload?.playbackUrl || null
|
||||
const audioUrl = resolveAudioUrl()
|
||||
if (!audioUrl && !playbackUrlToSave) {
|
||||
console.log('[PlaybackDownload] publish blocked: missing audioUrl and playbackUrl', {
|
||||
audioUrl,
|
||||
playbackUrlToSave,
|
||||
})
|
||||
setTooltip({
|
||||
type: 'error',
|
||||
text: 'Aucune piste audio disponible pour ce projet',
|
||||
})
|
||||
return
|
||||
}
|
||||
if (!currentUID) {
|
||||
console.log('[PlaybackDownload] publish blocked: missing currentUID')
|
||||
setTooltip({
|
||||
type: 'error',
|
||||
text: 'Utilisateur non authentifié',
|
||||
})
|
||||
return
|
||||
}
|
||||
if (!hasAcceptedPublication) return
|
||||
|
||||
if (isPublishing) return
|
||||
|
||||
try {
|
||||
console.log('[PlaybackDownload] publish start', {
|
||||
projectId: projectForDownload?.id,
|
||||
hasPendingPlaybackUrl: Boolean(pendingPlaybackUrl),
|
||||
hasPlaybackUrl: Boolean(projectForDownload?.playbackUrl),
|
||||
hasAudioUrl: Boolean(audioUrl),
|
||||
hasUri: Boolean(uri),
|
||||
})
|
||||
setIsPublishing(true)
|
||||
setIsLoading(true)
|
||||
|
||||
if (!playbackUrlToSave) {
|
||||
console.log('[PlaybackDownload] publish: no playback url, uploading source')
|
||||
const { sourcePath, videoUrl } = await uploadSourceRecording({
|
||||
uri,
|
||||
uid: currentUID,
|
||||
projectId: projectForDownload.id,
|
||||
})
|
||||
tempSourcePath = sourcePath
|
||||
|
||||
const payload = {
|
||||
projectId: projectForDownload?.id,
|
||||
videoUrl,
|
||||
audioUrl,
|
||||
storagePath: `users/${currentUID}/projects/${projectForDownload.id}/playback.mp4`,
|
||||
}
|
||||
|
||||
console.log('[PlaybackDownload] publish: calling merge', payload)
|
||||
|
||||
const { data: result } = await callMergeVideoAndAudio(payload)
|
||||
|
||||
playbackUrlToSave = result?.url || null
|
||||
if (!playbackUrlToSave) {
|
||||
console.log('[PlaybackDownload] publish: merge result missing url', result)
|
||||
throw new Error('merge_failed')
|
||||
}
|
||||
setPendingPlaybackUrl(playbackUrlToSave)
|
||||
}
|
||||
|
||||
console.log('[PlaybackDownload] publish: saving playback url', {
|
||||
projectId: projectForDownload.id,
|
||||
playbackUrlToSave,
|
||||
})
|
||||
const url = await processMerge()
|
||||
await projectsRef.doc(projectForDownload.id).set(
|
||||
{
|
||||
playbackUrl: playbackUrlToSave,
|
||||
playbackUrl: url,
|
||||
updatedAt: serverTimestamp(),
|
||||
},
|
||||
{ merge: true }
|
||||
)
|
||||
|
||||
setTooltip({
|
||||
type: 'success',
|
||||
text: publishSuccessMessage,
|
||||
})
|
||||
console.log('[PlaybackDownload] publish: navigate to PublishYoutube', {
|
||||
projectId: projectForDownload.id,
|
||||
})
|
||||
navigate(Routes.PublishYoutube, { projectId: projectForDownload.id })
|
||||
} catch (error) {
|
||||
console.log('[PlaybackDownload] publish error', {
|
||||
message: error?.message,
|
||||
code: error?.code,
|
||||
name: error?.name,
|
||||
details: error?.details,
|
||||
})
|
||||
} catch (err) {
|
||||
setTooltip({
|
||||
type: 'error',
|
||||
text: String(error?.message || 'Publication impossible'),
|
||||
text: String(err?.message || 'Erreur de publication'),
|
||||
})
|
||||
} finally {
|
||||
if (tempSourcePath) {
|
||||
try {
|
||||
await firebase.storage().ref(tempSourcePath).delete()
|
||||
} catch (cleanupError) {
|
||||
console.log('[PlaybackDownload] unable to delete temp source', {
|
||||
message: cleanupError?.message,
|
||||
code: cleanupError?.code,
|
||||
})
|
||||
}
|
||||
}
|
||||
setIsPublishing(false)
|
||||
setIsLoading(false)
|
||||
}
|
||||
}
|
||||
return (
|
||||
|
||||
Reference in New Issue
Block a user