diff --git a/functions/src/cover.js b/functions/src/cover.js
index e591487..81b6b8a 100644
--- a/functions/src/cover.js
+++ b/functions/src/cover.js
@@ -32,40 +32,56 @@ const normalizeArtistName = (value) => {
return trimmedValue || 'MusicLand'
}
-const getArtistFontSize = (artistName) => {
- if (artistName.length <= 16) return 52
- if (artistName.length <= 24) return 44
+const normalizeSongTitle = (value) => {
+ if (typeof value !== 'string') {
+ return 'Sans titre'
+ }
+ const trimmedValue = value.trim()
+ return trimmedValue || 'Sans titre'
+}
+
+const getTitleFontSize = (songTitle) => {
+ if (songTitle.length <= 16) return 38
+ if (songTitle.length <= 24) return 32
+ return 26
+}
+
+const getUsernameFontSize = (username) => {
+ if (username.length <= 16) return 52
+ if (username.length <= 24) return 44
return 36
}
-const buildTextOverlay = (artistName) => {
- const safeArtistName = escapeSvgText(artistName)
- const artistFontSize = getArtistFontSize(artistName)
+const buildTextOverlay = ({ songTitle, username }) => {
+ const safeSongTitle = escapeSvgText(songTitle)
+ const safeUsername = escapeSvgText(username)
+ const titleFontSize = getTitleFontSize(songTitle)
+ const usernameFontSize = getUsernameFontSize(username)
return Buffer.from(`
`)
}
@@ -90,26 +106,28 @@ const buildCircularMask = (size) => {
}
async function loadCoverIdentity(project) {
- const artistName = normalizeArtistName(project.userName)
+ const username = normalizeArtistName(project.userName)
+ const songTitle = normalizeSongTitle(project.title)
const userId = typeof project.userId === 'string' ? project.userId.trim() : ''
if (!userId) {
- return { artistName, profilePictureURL: null }
+ return { songTitle, username, profilePictureURL: project.coverCenterImageURL || null }
}
try {
const userSnapshot = await refList.users.doc(userId).get()
const userData = userSnapshot.exists ? userSnapshot.data() : null
return {
- artistName: normalizeArtistName(project.userName || userData?.userName),
- profilePictureURL: userData?.profilePictureURL || null,
+ songTitle,
+ username: normalizeArtistName(project.userName || userData?.userName),
+ profilePictureURL: project.coverCenterImageURL || userData?.profilePictureURL || null,
}
} catch (error) {
logger.warn('[Cover] Unable to load profile picture', {
projectId: project.id,
error: error.message,
})
- return { artistName, profilePictureURL: null }
+ return { songTitle, username, profilePictureURL: project.coverCenterImageURL || null }
}
}
@@ -169,9 +187,9 @@ async function prepareMusiclandCover(project) {
throw new Error('Utilisateur du projet introuvable')
}
- const { artistName, profilePictureURL } = await loadCoverIdentity(project)
+ const { songTitle, username, profilePictureURL } = await loadCoverIdentity(project)
const profileOverlay = await buildProfileOverlay(profilePictureURL)
- const overlays = [{ input: buildTextOverlay(artistName), left: 0, top: 0 }]
+ const overlays = [{ input: buildTextOverlay({ songTitle, username }), left: 0, top: 0 }]
if (profileOverlay) {
overlays.unshift({
diff --git a/src/assets/UI/musiclandPlaybackCover.png b/src/assets/UI/musiclandPlaybackCover.png
index a9ac203..96e389d 100644
Binary files a/src/assets/UI/musiclandPlaybackCover.png and b/src/assets/UI/musiclandPlaybackCover.png differ
diff --git a/src/components/MusiclandPlaybackCover.js b/src/components/MusiclandPlaybackCover.js
index ed81039..adbfc9b 100644
--- a/src/components/MusiclandPlaybackCover.js
+++ b/src/components/MusiclandPlaybackCover.js
@@ -5,13 +5,16 @@ import { img } from '../assets'
import { FONT_FAMILY } from '../styles/Fonts'
const MusiclandPlaybackCover = ({
- artistName,
+ songTitle,
+ username,
profilePictureURL,
coverUrl,
style,
}) => {
- const displayName =
- typeof artistName === 'string' && artistName.trim() ? artistName.trim() : 'MusicLand'
+ const displayTitle =
+ typeof songTitle === 'string' && songTitle.trim() ? songTitle.trim() : 'Sans titre'
+ const displayUsername =
+ typeof username === 'string' && username.trim() ? username.trim() : 'MusicLand'
return (
@@ -36,11 +39,18 @@ const MusiclandPlaybackCover = ({
adjustsFontSizeToFit
minimumFontScale={0.55}
numberOfLines={1}
- style={styles.artistName}
+ style={styles.songTitle}
>
- {displayName}
+ {displayTitle}
+
+
+ {displayUsername}
- PLAYBACKER
>
) : null}
@@ -63,19 +73,19 @@ const styles = StyleSheet.create({
top: '39.84375%',
borderRadius: 999,
},
- artistName: {
+ songTitle: {
position: 'absolute',
- top: '76.5%',
- left: '16%',
- width: '68%',
+ top: '15%',
+ left: '10%',
+ width: '80%',
color: '#FFFFFF',
fontFamily: FONT_FAMILY.InterRegular,
- fontSize: 21,
- lineHeight: 26,
- letterSpacing: 1.2,
+ fontSize: 14,
+ lineHeight: 18,
+ letterSpacing: 0.8,
textAlign: 'center',
},
- playbacker: {
+ username: {
position: 'absolute',
bottom: '3%',
left: '10%',
diff --git a/src/screens/cover/ChooseCoverType.js b/src/screens/cover/ChooseCoverType.js
index 6ef901c..7be3090 100644
--- a/src/screens/cover/ChooseCoverType.js
+++ b/src/screens/cover/ChooseCoverType.js
@@ -330,7 +330,8 @@ export const ChooseCoverType = () => {
{
const coverUrl = templateCover?.result || null
const isPreparing = selectedProject?.coverStatus === 'GENERATING'
const hasPreparationError = selectedProject?.coverStatus === 'ERROR'
- const artistName =
+ const username =
typeof selectedProject?.userName === 'string' && selectedProject.userName.trim()
? selectedProject.userName.trim()
: currentUserData?.userName || 'MusicLand'
+ const songTitle = selectedProject?.title || 'Sans titre'
const profilePictureURL = currentUserData?.profilePictureURL || null
const centerImageURL = selectedProject?.coverCenterImageURL || profilePictureURL
@@ -119,7 +120,8 @@ const PouchReady = () => {
throw new Error('cover_project_identity_missing')
}
const coverBlob = await createMusiclandPlaybackCover({
- artistName,
+ songTitle,
+ username,
profilePictureURL: centerImageURL,
})
const storagePath = `users/${userId}/projects/${selectedProjectId}/cover-musicland-playbacker.png`
@@ -170,13 +172,14 @@ const PouchReady = () => {
setIsSaving(false)
}
}, [
- artistName,
coverUrl,
centerImageURL,
selectedOption,
selectedProject,
selectedProjectId,
+ songTitle,
updateProjectData,
+ username,
])
return (
@@ -193,7 +196,8 @@ const PouchReady = () => {
/>
{
})
}
-const getArtistFontSize = (artistName) => {
- if (artistName.length <= 16) return 52
- if (artistName.length <= 24) return 44
+const getTitleFontSize = (songTitle) => {
+ if (songTitle.length <= 16) return 38
+ if (songTitle.length <= 24) return 32
+ return 26
+}
+
+const getUsernameFontSize = (username) => {
+ if (username.length <= 16) return 52
+ if (username.length <= 24) return 44
return 36
}
@@ -67,7 +73,7 @@ const drawProfilePicture = (context, profilePicture) => {
context.restore()
}
-export const createMusiclandPlaybackCover = async ({ artistName, profilePictureURL }) => {
+export const createMusiclandPlaybackCover = async ({ songTitle, username, profilePictureURL }) => {
const templateAsset = Asset.fromModule(img.musiclandPlaybackCover)
await templateAsset.downloadAsync()
const assetUri = templateAsset.localUri || templateAsset.uri
@@ -91,10 +97,12 @@ export const createMusiclandPlaybackCover = async ({ artistName, profilePictureU
context.fillStyle = '#FFFFFF'
context.textBaseline = 'middle'
- context.font = `400 ${getArtistFontSize(artistName)}px Inter, Arial, sans-serif`
- drawCenteredText(context, artistName, 824, getArtistFontSize(artistName), 3)
- context.font = '400 54px Inter, Arial, sans-serif'
- drawCenteredText(context, 'PLAYBACKER', 963, 54, 5)
+ const titleFontSize = getTitleFontSize(songTitle)
+ context.font = `400 ${titleFontSize}px Inter, Arial, sans-serif`
+ drawCenteredText(context, songTitle, 170, titleFontSize, 2)
+ const usernameFontSize = getUsernameFontSize(username)
+ context.font = `400 ${usernameFontSize}px Inter, Arial, sans-serif`
+ drawCenteredText(context, username, 963, usernameFontSize, 4)
return new Promise((resolve, reject) => {
canvas.toBlob((blob) => {