feat: fix merge audio
This commit is contained in:
@@ -12,6 +12,7 @@ const ffmpeg = require('fluent-ffmpeg')
|
|||||||
const ffmpegInstaller = require('@ffmpeg-installer/ffmpeg')
|
const ffmpegInstaller = require('@ffmpeg-installer/ffmpeg')
|
||||||
const { Buffer } = require('node:buffer')
|
const { Buffer } = require('node:buffer')
|
||||||
const { FieldValue } = require('firebase-admin/firestore')
|
const { FieldValue } = require('firebase-admin/firestore')
|
||||||
|
const { REGION } = require('../index')
|
||||||
|
|
||||||
if (!admin.apps.length) admin.initializeApp()
|
if (!admin.apps.length) admin.initializeApp()
|
||||||
ffmpeg.setFfmpegPath(ffmpegInstaller.path)
|
ffmpeg.setFfmpegPath(ffmpegInstaller.path)
|
||||||
@@ -151,7 +152,7 @@ async function markPlaybackCompatibility({ projectId, initiatorUid = null }) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
exports.mergeVideoAndAudio = onCall(
|
exports.mergeVideoAndAudio = onCall(
|
||||||
{ timeoutSeconds: 540, memory: '1GiB' },
|
{ region: REGION, timeoutSeconds: 540, memory: '1GiB' },
|
||||||
async ({ data = {}, auth }) => {
|
async ({ data = {}, auth }) => {
|
||||||
const uid = auth?.uid
|
const uid = auth?.uid
|
||||||
if (!uid) throw new HttpsError('unauthenticated', 'Authentification requise')
|
if (!uid) throw new HttpsError('unauthenticated', 'Authentification requise')
|
||||||
@@ -176,7 +177,7 @@ exports.mergeVideoAndAudio = onCall(
|
|||||||
)
|
)
|
||||||
|
|
||||||
exports.reencodePlayback = onCall(
|
exports.reencodePlayback = onCall(
|
||||||
{ timeoutSeconds: 540, memory: '1GiB' },
|
{ region: REGION, timeoutSeconds: 540, memory: '1GiB' },
|
||||||
async ({ data = {}, auth }) => {
|
async ({ data = {}, auth }) => {
|
||||||
const uid = auth?.uid
|
const uid = auth?.uid
|
||||||
if (!uid) throw new HttpsError('unauthenticated', 'Authentification requise')
|
if (!uid) throw new HttpsError('unauthenticated', 'Authentification requise')
|
||||||
|
|||||||
@@ -1,7 +1,24 @@
|
|||||||
import { Platform } from 'react-native'
|
import { Platform } from 'react-native'
|
||||||
|
import * as FileSystem from 'expo-file-system'
|
||||||
import Compressor from 'react-native-compressor'
|
import Compressor from 'react-native-compressor'
|
||||||
import firebase from '../config/firebase'
|
import firebase from '../config/firebase'
|
||||||
|
|
||||||
|
const fetchBlobFromUri = (uri) =>
|
||||||
|
new Promise((resolve, reject) => {
|
||||||
|
const xhr = new XMLHttpRequest()
|
||||||
|
xhr.onload = () => resolve(xhr.response)
|
||||||
|
xhr.onerror = () => reject(new TypeError('Network request failed'))
|
||||||
|
xhr.responseType = 'blob'
|
||||||
|
xhr.open('GET', uri, true)
|
||||||
|
xhr.send(null)
|
||||||
|
})
|
||||||
|
|
||||||
|
const getContentTypeForFile = (fileType) => {
|
||||||
|
if (fileType === 'VIDEO') return 'video/mp4'
|
||||||
|
if (fileType === 'IMAGE') return 'image/jpeg'
|
||||||
|
return 'application/octet-stream'
|
||||||
|
}
|
||||||
|
|
||||||
export function uploadFileToFirebase({
|
export function uploadFileToFirebase({
|
||||||
uri,
|
uri,
|
||||||
path,
|
path,
|
||||||
@@ -11,53 +28,163 @@ export function uploadFileToFirebase({
|
|||||||
}) {
|
}) {
|
||||||
return new Promise(async (resolve, reject) => {
|
return new Promise(async (resolve, reject) => {
|
||||||
try {
|
try {
|
||||||
|
console.log('[uploadToFirebase] start', {
|
||||||
|
path,
|
||||||
|
shouldCompress,
|
||||||
|
fileType,
|
||||||
|
hasBlob: Boolean(providedBlob),
|
||||||
|
uri,
|
||||||
|
})
|
||||||
let workingURI = uri
|
let workingURI = uri
|
||||||
let uploadBlob = providedBlob
|
let uploadBlob = providedBlob
|
||||||
|
let uploadTask = null
|
||||||
|
|
||||||
// Optionally compress before upload
|
// Optionally compress before upload
|
||||||
try {
|
try {
|
||||||
if (shouldCompress && Platform.OS !== 'web') {
|
if (shouldCompress && Platform.OS !== 'web') {
|
||||||
if (fileType === 'VIDEO') {
|
if (fileType === 'VIDEO') {
|
||||||
console.log('Compressing video...')
|
const compressStart = Date.now()
|
||||||
|
console.log('[uploadToFirebase] compress video start')
|
||||||
workingURI = await Compressor.Video.compress(workingURI)
|
workingURI = await Compressor.Video.compress(workingURI)
|
||||||
|
console.log('[uploadToFirebase] compress video done', {
|
||||||
|
durationMs: Date.now() - compressStart,
|
||||||
|
workingURI,
|
||||||
|
})
|
||||||
} else if (fileType === 'IMAGE') {
|
} else if (fileType === 'IMAGE') {
|
||||||
// Basic image compression
|
// Basic image compression
|
||||||
|
const compressStart = Date.now()
|
||||||
|
console.log('[uploadToFirebase] compress image start')
|
||||||
workingURI = await Compressor.Image.compress(workingURI, {
|
workingURI = await Compressor.Image.compress(workingURI, {
|
||||||
compressionMethod: 'auto',
|
compressionMethod: 'auto',
|
||||||
})
|
})
|
||||||
|
console.log('[uploadToFirebase] compress image done', {
|
||||||
|
durationMs: Date.now() - compressStart,
|
||||||
|
workingURI,
|
||||||
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
console.warn('Compression failed, uploading original file', e?.message)
|
console.warn('[uploadToFirebase] compression failed, using original file', {
|
||||||
|
message: e?.message,
|
||||||
|
code: e?.code,
|
||||||
|
name: e?.name,
|
||||||
|
})
|
||||||
workingURI = uri
|
workingURI = uri
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!uploadBlob) {
|
const isLocalUri =
|
||||||
|
Platform.OS !== 'web' &&
|
||||||
|
typeof workingURI === 'string' &&
|
||||||
|
(workingURI.startsWith('file://') || workingURI.startsWith('content://'))
|
||||||
|
|
||||||
|
if (!uploadBlob && isLocalUri) {
|
||||||
|
try {
|
||||||
|
const bucket = firebase.app()?.options?.storageBucket
|
||||||
|
const token = await firebase.auth().currentUser?.getIdToken?.()
|
||||||
|
if (!bucket || !token) {
|
||||||
|
throw new Error('missing_bucket_or_token')
|
||||||
|
}
|
||||||
|
const contentType = getContentTypeForFile(fileType)
|
||||||
|
const uploadUrl = `https://firebasestorage.googleapis.com/v0/b/${bucket}/o?uploadType=media&name=${encodeURIComponent(
|
||||||
|
path
|
||||||
|
)}`
|
||||||
|
console.log('[uploadToFirebase] upload via FileSystem', {
|
||||||
|
uploadUrl,
|
||||||
|
contentType,
|
||||||
|
})
|
||||||
|
const uploadResult = await FileSystem.uploadAsync(uploadUrl, workingURI, {
|
||||||
|
httpMethod: 'POST',
|
||||||
|
uploadType: FileSystem.FileSystemUploadType.BINARY_CONTENT,
|
||||||
|
headers: {
|
||||||
|
Authorization: `Bearer ${token}`,
|
||||||
|
'Content-Type': contentType,
|
||||||
|
},
|
||||||
|
})
|
||||||
|
console.log('[uploadToFirebase] uploadAsync result', {
|
||||||
|
status: uploadResult?.status,
|
||||||
|
})
|
||||||
|
if (uploadResult?.status < 200 || uploadResult?.status >= 300) {
|
||||||
|
throw new Error(`upload_failed_${uploadResult?.status || 'unknown'}`)
|
||||||
|
}
|
||||||
|
const resultURI = await firebase.storage().ref(path).getDownloadURL()
|
||||||
|
console.log('[uploadToFirebase] upload success (uploadAsync)', { resultURI })
|
||||||
|
resolve({ resultURI })
|
||||||
|
return
|
||||||
|
} catch (e) {
|
||||||
|
console.log('[uploadToFirebase] uploadAsync failed, fallback to xhr', {
|
||||||
|
message: e?.message,
|
||||||
|
code: e?.code,
|
||||||
|
name: e?.name,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
console.log('[uploadToFirebase] fetching blob via xhr', { workingURI })
|
||||||
|
uploadBlob = await fetchBlobFromUri(workingURI)
|
||||||
|
console.log('[uploadToFirebase] blob ready (xhr)', {
|
||||||
|
size: uploadBlob?.size,
|
||||||
|
type: uploadBlob?.type,
|
||||||
|
})
|
||||||
|
} else if (!uploadBlob) {
|
||||||
|
console.log('[uploadToFirebase] fetching blob', { workingURI })
|
||||||
const response = await fetch(workingURI)
|
const response = await fetch(workingURI)
|
||||||
|
console.log('[uploadToFirebase] fetch blob response', {
|
||||||
|
ok: response?.ok,
|
||||||
|
status: response?.status,
|
||||||
|
type: response?.type,
|
||||||
|
})
|
||||||
uploadBlob = await response.blob()
|
uploadBlob = await response.blob()
|
||||||
|
console.log('[uploadToFirebase] blob ready', {
|
||||||
|
size: uploadBlob?.size,
|
||||||
|
type: uploadBlob?.type,
|
||||||
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
const uploadTask = firebase.storage().ref(path).put(uploadBlob)
|
if (!uploadTask) {
|
||||||
|
console.log('[uploadToFirebase] upload start', { path })
|
||||||
|
uploadTask = firebase.storage().ref(path).put(uploadBlob)
|
||||||
|
}
|
||||||
|
|
||||||
uploadTask.on(
|
uploadTask.on(
|
||||||
Platform.OS === 'web' ? 'state_changed' : firebase.storage.TaskEvent.STATE_CHANGED,
|
Platform.OS === 'web' ? 'state_changed' : firebase.storage.TaskEvent.STATE_CHANGED,
|
||||||
(snapshot) => {
|
(snapshot) => {
|
||||||
|
console.log('[uploadToFirebase] upload progress', {
|
||||||
|
state: snapshot?.state,
|
||||||
|
bytesTransferred: snapshot?.bytesTransferred,
|
||||||
|
totalBytes: snapshot?.totalBytes,
|
||||||
|
})
|
||||||
if (Platform.OS !== 'web' && snapshot.state === firebase.storage.TaskState.SUCCESS) {
|
if (Platform.OS !== 'web' && snapshot.state === firebase.storage.TaskState.SUCCESS) {
|
||||||
snapshot.ref.getDownloadURL().then((resultURI) => {
|
snapshot.ref.getDownloadURL().then((resultURI) => {
|
||||||
|
console.log('[uploadToFirebase] upload success (native)', { resultURI })
|
||||||
|
if (uploadBlob && typeof uploadBlob.close === 'function') {
|
||||||
|
uploadBlob.close()
|
||||||
|
}
|
||||||
resolve({ resultURI })
|
resolve({ resultURI })
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
(error) => {
|
(error) => {
|
||||||
|
console.log('[uploadToFirebase] upload error', {
|
||||||
|
message: error?.message,
|
||||||
|
code: error?.code,
|
||||||
|
name: error?.name,
|
||||||
|
})
|
||||||
reject(error)
|
reject(error)
|
||||||
},
|
},
|
||||||
async () => {
|
async () => {
|
||||||
const url = await firebase.storage().ref(path).getDownloadURL()
|
const url = await firebase.storage().ref(path).getDownloadURL()
|
||||||
|
|
||||||
|
console.log('[uploadToFirebase] upload success (finalize)', { resultURI: url })
|
||||||
|
if (uploadBlob && typeof uploadBlob.close === 'function') {
|
||||||
|
uploadBlob.close()
|
||||||
|
}
|
||||||
resolve({ resultURI: url })
|
resolve({ resultURI: url })
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
|
console.log('[uploadToFirebase] unexpected error', {
|
||||||
|
message: e?.message,
|
||||||
|
code: e?.code,
|
||||||
|
name: e?.name,
|
||||||
|
})
|
||||||
reject(e)
|
reject(e)
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|||||||
@@ -41,6 +41,7 @@ const HIDDEN_ROUTE_NAMES = new Set([
|
|||||||
Routes.ChooseDecor,
|
Routes.ChooseDecor,
|
||||||
Routes.CreatingDecor,
|
Routes.CreatingDecor,
|
||||||
Routes.VideoFinalize,
|
Routes.VideoFinalize,
|
||||||
|
Routes.PublishYoutube,
|
||||||
Routes.FlowSelection,
|
Routes.FlowSelection,
|
||||||
Routes.ChooseCoverType,
|
Routes.ChooseCoverType,
|
||||||
Routes.Settings,
|
Routes.Settings,
|
||||||
|
|||||||
@@ -9,7 +9,7 @@ import BorderGradientButton from '../../components/BorderGradientButton'
|
|||||||
import GradientButton from '../../components/GradientButton'
|
import GradientButton from '../../components/GradientButton'
|
||||||
import MusicLandHeader from '../../components/MusicLandHeader'
|
import MusicLandHeader from '../../components/MusicLandHeader'
|
||||||
import AppCheckbox from '../../components/AppCheckbox'
|
import AppCheckbox from '../../components/AppCheckbox'
|
||||||
import firebase, { projectsRef, serverTimestamp } from '../../config/firebase'
|
import firebase, { getFunctionsClient, projectsRef, serverTimestamp } from '../../config/firebase'
|
||||||
import { uploadFileToFirebase } from '../../helpers/uploadToFirebase'
|
import { uploadFileToFirebase } from '../../helpers/uploadToFirebase'
|
||||||
import Page from '../../layouts/Page'
|
import Page from '../../layouts/Page'
|
||||||
import { Routes } from '../../navigation'
|
import { Routes } from '../../navigation'
|
||||||
@@ -135,6 +135,12 @@ const uploadSourceRecording = async ({ uri, uid, projectId }) => {
|
|||||||
return { sourcePath, videoUrl }
|
return { sourcePath, videoUrl }
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const FUNCTIONS_REGION = 'europe-west1'
|
||||||
|
const callMergeVideoAndAudio = (payload) => {
|
||||||
|
const callable = getFunctionsClient(FUNCTIONS_REGION).httpsCallable('upload-mergeVideoAndAudio')
|
||||||
|
return callable(payload)
|
||||||
|
}
|
||||||
|
|
||||||
const PlaybackDownload = ({ route }) => {
|
const PlaybackDownload = ({ route }) => {
|
||||||
const { currentUID, selectedProject } = useUserData()
|
const { currentUID, selectedProject } = useUserData()
|
||||||
const { hasActiveSubscription, hasPurchased, videos } = useUser() || {}
|
const { hasActiveSubscription, hasPurchased, videos } = useUser() || {}
|
||||||
@@ -282,8 +288,6 @@ const PlaybackDownload = ({ route }) => {
|
|||||||
})
|
})
|
||||||
tempSourcePath = sourcePath
|
tempSourcePath = sourcePath
|
||||||
|
|
||||||
const callable = firebase.functions().httpsCallable('upload-mergeVideoAndAudio')
|
|
||||||
|
|
||||||
const payload = {
|
const payload = {
|
||||||
projectId: projectForDownload?.id,
|
projectId: projectForDownload?.id,
|
||||||
videoUrl,
|
videoUrl,
|
||||||
@@ -293,7 +297,7 @@ const PlaybackDownload = ({ route }) => {
|
|||||||
|
|
||||||
console.log('[PlaybackDownload] calling upload-mergeVideoAndAudio', payload)
|
console.log('[PlaybackDownload] calling upload-mergeVideoAndAudio', payload)
|
||||||
|
|
||||||
const { data: result } = await callable(payload)
|
const { data: result } = await callMergeVideoAndAudio(payload)
|
||||||
|
|
||||||
console.log('[PlaybackDownload] upload-mergeVideoAndAudio result', result)
|
console.log('[PlaybackDownload] upload-mergeVideoAndAudio result', result)
|
||||||
|
|
||||||
@@ -431,8 +435,12 @@ const PlaybackDownload = ({ route }) => {
|
|||||||
}, [downloadPaymentPending, handleDownloadUri, hasPaidPlaybackDownload, isDownloading])
|
}, [downloadPaymentPending, handleDownloadUri, hasPaidPlaybackDownload, isDownloading])
|
||||||
|
|
||||||
const handlePublish = async () => {
|
const handlePublish = async () => {
|
||||||
if (isPublishing) return
|
if (isPublishing) {
|
||||||
|
console.log('[PlaybackDownload] publish blocked: already publishing')
|
||||||
|
return
|
||||||
|
}
|
||||||
if (!hasAcceptedPublication) {
|
if (!hasAcceptedPublication) {
|
||||||
|
console.log('[PlaybackDownload] publish blocked: publication not accepted')
|
||||||
setTooltip({
|
setTooltip({
|
||||||
type: 'error',
|
type: 'error',
|
||||||
text: 'Confirme la diffusion de ton playback sur Musicland avant de publier',
|
text: 'Confirme la diffusion de ton playback sur Musicland avant de publier',
|
||||||
@@ -440,6 +448,9 @@ const PlaybackDownload = ({ route }) => {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
if (!projectForDownload?.id) {
|
if (!projectForDownload?.id) {
|
||||||
|
console.log('[PlaybackDownload] publish: missing project id, navigating directly', {
|
||||||
|
projectForDownload: projectForDownload?.id,
|
||||||
|
})
|
||||||
setTooltip({
|
setTooltip({
|
||||||
type: 'success',
|
type: 'success',
|
||||||
text: publishSuccessMessage,
|
text: publishSuccessMessage,
|
||||||
@@ -451,6 +462,10 @@ const PlaybackDownload = ({ route }) => {
|
|||||||
let playbackUrlToSave = pendingPlaybackUrl || projectForDownload?.playbackUrl || null
|
let playbackUrlToSave = pendingPlaybackUrl || projectForDownload?.playbackUrl || null
|
||||||
const audioUrl = resolveAudioUrl()
|
const audioUrl = resolveAudioUrl()
|
||||||
if (!audioUrl && !playbackUrlToSave) {
|
if (!audioUrl && !playbackUrlToSave) {
|
||||||
|
console.log('[PlaybackDownload] publish blocked: missing audioUrl and playbackUrl', {
|
||||||
|
audioUrl,
|
||||||
|
playbackUrlToSave,
|
||||||
|
})
|
||||||
setTooltip({
|
setTooltip({
|
||||||
type: 'error',
|
type: 'error',
|
||||||
text: 'Aucune piste audio disponible pour ce projet',
|
text: 'Aucune piste audio disponible pour ce projet',
|
||||||
@@ -458,6 +473,7 @@ const PlaybackDownload = ({ route }) => {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
if (!currentUID) {
|
if (!currentUID) {
|
||||||
|
console.log('[PlaybackDownload] publish blocked: missing currentUID')
|
||||||
setTooltip({
|
setTooltip({
|
||||||
type: 'error',
|
type: 'error',
|
||||||
text: 'Utilisateur non authentifié',
|
text: 'Utilisateur non authentifié',
|
||||||
@@ -466,10 +482,18 @@ const PlaybackDownload = ({ route }) => {
|
|||||||
}
|
}
|
||||||
|
|
||||||
try {
|
try {
|
||||||
|
console.log('[PlaybackDownload] publish start', {
|
||||||
|
projectId: projectForDownload?.id,
|
||||||
|
hasPendingPlaybackUrl: Boolean(pendingPlaybackUrl),
|
||||||
|
hasPlaybackUrl: Boolean(projectForDownload?.playbackUrl),
|
||||||
|
hasAudioUrl: Boolean(audioUrl),
|
||||||
|
hasUri: Boolean(uri),
|
||||||
|
})
|
||||||
setIsPublishing(true)
|
setIsPublishing(true)
|
||||||
setIsLoading(true)
|
setIsLoading(true)
|
||||||
|
|
||||||
if (!playbackUrlToSave) {
|
if (!playbackUrlToSave) {
|
||||||
|
console.log('[PlaybackDownload] publish: no playback url, uploading source')
|
||||||
const { sourcePath, videoUrl } = await uploadSourceRecording({
|
const { sourcePath, videoUrl } = await uploadSourceRecording({
|
||||||
uri,
|
uri,
|
||||||
uid: currentUID,
|
uid: currentUID,
|
||||||
@@ -477,8 +501,6 @@ const PlaybackDownload = ({ route }) => {
|
|||||||
})
|
})
|
||||||
tempSourcePath = sourcePath
|
tempSourcePath = sourcePath
|
||||||
|
|
||||||
const callable = firebase.functions().httpsCallable('upload-mergeVideoAndAudio')
|
|
||||||
|
|
||||||
const payload = {
|
const payload = {
|
||||||
projectId: projectForDownload?.id,
|
projectId: projectForDownload?.id,
|
||||||
videoUrl,
|
videoUrl,
|
||||||
@@ -488,15 +510,20 @@ const PlaybackDownload = ({ route }) => {
|
|||||||
|
|
||||||
console.log('[PlaybackDownload] publish: calling merge', payload)
|
console.log('[PlaybackDownload] publish: calling merge', payload)
|
||||||
|
|
||||||
const { data: result } = await callable(payload)
|
const { data: result } = await callMergeVideoAndAudio(payload)
|
||||||
|
|
||||||
playbackUrlToSave = result?.url || null
|
playbackUrlToSave = result?.url || null
|
||||||
if (!playbackUrlToSave) {
|
if (!playbackUrlToSave) {
|
||||||
|
console.log('[PlaybackDownload] publish: merge result missing url', result)
|
||||||
throw new Error('merge_failed')
|
throw new Error('merge_failed')
|
||||||
}
|
}
|
||||||
setPendingPlaybackUrl(playbackUrlToSave)
|
setPendingPlaybackUrl(playbackUrlToSave)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
console.log('[PlaybackDownload] publish: saving playback url', {
|
||||||
|
projectId: projectForDownload.id,
|
||||||
|
playbackUrlToSave,
|
||||||
|
})
|
||||||
await projectsRef.doc(projectForDownload.id).set(
|
await projectsRef.doc(projectForDownload.id).set(
|
||||||
{
|
{
|
||||||
playbackUrl: playbackUrlToSave,
|
playbackUrl: playbackUrlToSave,
|
||||||
@@ -509,6 +536,9 @@ const PlaybackDownload = ({ route }) => {
|
|||||||
type: 'success',
|
type: 'success',
|
||||||
text: publishSuccessMessage,
|
text: publishSuccessMessage,
|
||||||
})
|
})
|
||||||
|
console.log('[PlaybackDownload] publish: navigate to PublishYoutube', {
|
||||||
|
projectId: projectForDownload.id,
|
||||||
|
})
|
||||||
navigate(Routes.PublishYoutube, { projectId: projectForDownload.id })
|
navigate(Routes.PublishYoutube, { projectId: projectForDownload.id })
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.log('[PlaybackDownload] publish error', {
|
console.log('[PlaybackDownload] publish error', {
|
||||||
|
|||||||
@@ -119,7 +119,7 @@ const PublishYoutube = () => {
|
|||||||
if (!hasAcceptedPublication) {
|
if (!hasAcceptedPublication) {
|
||||||
setTooltip?.({
|
setTooltip?.({
|
||||||
type: 'error',
|
type: 'error',
|
||||||
text: 'Confirme la diffusion sur Musicland et YouTube avant de publier',
|
text: 'Confirme la diffusion sur YouTube avant de publier',
|
||||||
})
|
})
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
@@ -131,7 +131,7 @@ const PublishYoutube = () => {
|
|||||||
: 'Confirmer la publication'
|
: 'Confirmer la publication'
|
||||||
const confirmDescription = hasYoutubePublication
|
const confirmDescription = hasYoutubePublication
|
||||||
? 'La vidéo existe déjà sur YouTube. Confirme que tu souhaites remplacer la version publiée.'
|
? 'La vidéo existe déjà sur YouTube. Confirme que tu souhaites remplacer la version publiée.'
|
||||||
: 'Confirme que tu souhaites publier ce playback sur la chaîne YouTube MusicLand. Il sera visible publiquement.'
|
: 'Confirme que tu souhaites publier ce playback sur YouTube. Il sera visible publiquement.'
|
||||||
alert(confirmTitle, confirmDescription, [
|
alert(confirmTitle, confirmDescription, [
|
||||||
{ text: 'Annuler', style: 'cancel' },
|
{ text: 'Annuler', style: 'cancel' },
|
||||||
{
|
{
|
||||||
@@ -249,10 +249,10 @@ const PublishYoutube = () => {
|
|||||||
<AppCheckbox
|
<AppCheckbox
|
||||||
selected={hasAcceptedPublication}
|
selected={hasAcceptedPublication}
|
||||||
onPress={() => setHasAcceptedPublication((prevState) => !prevState)}
|
onPress={() => setHasAcceptedPublication((prevState) => !prevState)}
|
||||||
label="J'accepte la diffusion de mon contenu sur Musicland et YouTube."
|
label="J'accepte la diffusion de mon contenu sur YouTube."
|
||||||
/>
|
/>
|
||||||
<Text style={styles.consentDescription}>
|
<Text style={styles.consentDescription}>
|
||||||
Cette confirmation est requise avant toute mise en ligne.
|
Cette confirmation est requise avant toute publication sur YouTube.
|
||||||
</Text>
|
</Text>
|
||||||
</View>
|
</View>
|
||||||
<GradientButton
|
<GradientButton
|
||||||
|
|||||||
Reference in New Issue
Block a user