covers with logo
This commit is contained in:
Binary file not shown.
|
After Width: | Height: | Size: 86 KiB |
@@ -49,7 +49,7 @@ exports.generatePicturePrompt = (project = {}) => {
|
||||
|
||||
const prompt = `
|
||||
<BRIEF>
|
||||
<OBJECTIF>Créer une pochette d'album abstraite et lumineuse.</OBJECTIF>
|
||||
<OBJECTIF>Créer une pochette lumineuse.</OBJECTIF>
|
||||
<TITRE>${title || "Sans titre"}</TITRE>
|
||||
<STYLE_MUSICAL>${tagsLine}</STYLE_MUSICAL>
|
||||
<EXTRAITS_PAROLES>${lyricsLine}</EXTRAITS_PAROLES>
|
||||
@@ -58,7 +58,6 @@ exports.generatePicturePrompt = (project = {}) => {
|
||||
<CONTEXTES_VISUELS>
|
||||
<FORMAT>Image carrée 1024x1024 pixels.</FORMAT>
|
||||
<STYLE>Abstrait, graphique, formes géométriques et dégradés.</STYLE>
|
||||
<PALETTE>${paletteHint}</PALETTE>
|
||||
<COMPOSITION>Remplis toute la surface sans laisser de bordures ou zones vides.</COMPOSITION>
|
||||
</CONTEXTES_VISUELS>
|
||||
|
||||
@@ -66,7 +65,7 @@ exports.generatePicturePrompt = (project = {}) => {
|
||||
<INTERDIT>Texte ou typographie.</INTERDIT>
|
||||
<INTERDIT>Personnes ou visages.</INTERDIT>
|
||||
<INTERDIT>Fond blanc ou bordures.</INTERDIT>
|
||||
<INTERDIT>Filigrane ou logo.</INTERDIT>
|
||||
<INTERDIT>Autre logo ou filigrane que celui prévu en bas à droite.</INTERDIT>
|
||||
</CONTRAINTES>
|
||||
`.trim();
|
||||
|
||||
|
||||
Generated
+435
-5
@@ -15,7 +15,8 @@
|
||||
"firebase-admin": "^12.7.0",
|
||||
"firebase-functions": "^6.4.0",
|
||||
"fluent-ffmpeg": "^2.1.3",
|
||||
"genkit": "^1.18.0"
|
||||
"genkit": "^1.18.0",
|
||||
"sharp": "^0.33.4"
|
||||
},
|
||||
"devDependencies": {
|
||||
"eslint": "^8.15.0",
|
||||
@@ -62,6 +63,16 @@
|
||||
"node": ">=6.0.0"
|
||||
}
|
||||
},
|
||||
"node_modules/@emnapi/runtime": {
|
||||
"version": "1.6.0",
|
||||
"resolved": "https://registry.npmjs.org/@emnapi/runtime/-/runtime-1.6.0.tgz",
|
||||
"integrity": "sha512-obtUmAHTMjll499P+D9A3axeJFlhdjOWdKUNs/U6QIGT7V5RjcUW1xToAzjvmgTSQhDbYn/NwfTRoJcQ2rNBxA==",
|
||||
"license": "MIT",
|
||||
"optional": true,
|
||||
"dependencies": {
|
||||
"tslib": "^2.4.0"
|
||||
}
|
||||
},
|
||||
"node_modules/@eslint-community/eslint-utils": {
|
||||
"version": "4.8.0",
|
||||
"resolved": "https://registry.npmjs.org/@eslint-community/eslint-utils/-/eslint-utils-4.8.0.tgz",
|
||||
@@ -799,6 +810,367 @@
|
||||
"dev": true,
|
||||
"license": "BSD-3-Clause"
|
||||
},
|
||||
"node_modules/@img/sharp-darwin-arm64": {
|
||||
"version": "0.33.5",
|
||||
"resolved": "https://registry.npmjs.org/@img/sharp-darwin-arm64/-/sharp-darwin-arm64-0.33.5.tgz",
|
||||
"integrity": "sha512-UT4p+iz/2H4twwAoLCqfA9UH5pI6DggwKEGuaPy7nCVQ8ZsiY5PIcrRvD1DzuY3qYL07NtIQcWnBSY/heikIFQ==",
|
||||
"cpu": [
|
||||
"arm64"
|
||||
],
|
||||
"license": "Apache-2.0",
|
||||
"optional": true,
|
||||
"os": [
|
||||
"darwin"
|
||||
],
|
||||
"engines": {
|
||||
"node": "^18.17.0 || ^20.3.0 || >=21.0.0"
|
||||
},
|
||||
"funding": {
|
||||
"url": "https://opencollective.com/libvips"
|
||||
},
|
||||
"optionalDependencies": {
|
||||
"@img/sharp-libvips-darwin-arm64": "1.0.4"
|
||||
}
|
||||
},
|
||||
"node_modules/@img/sharp-darwin-x64": {
|
||||
"version": "0.33.5",
|
||||
"resolved": "https://registry.npmjs.org/@img/sharp-darwin-x64/-/sharp-darwin-x64-0.33.5.tgz",
|
||||
"integrity": "sha512-fyHac4jIc1ANYGRDxtiqelIbdWkIuQaI84Mv45KvGRRxSAa7o7d1ZKAOBaYbnepLC1WqxfpimdeWfvqqSGwR2Q==",
|
||||
"cpu": [
|
||||
"x64"
|
||||
],
|
||||
"license": "Apache-2.0",
|
||||
"optional": true,
|
||||
"os": [
|
||||
"darwin"
|
||||
],
|
||||
"engines": {
|
||||
"node": "^18.17.0 || ^20.3.0 || >=21.0.0"
|
||||
},
|
||||
"funding": {
|
||||
"url": "https://opencollective.com/libvips"
|
||||
},
|
||||
"optionalDependencies": {
|
||||
"@img/sharp-libvips-darwin-x64": "1.0.4"
|
||||
}
|
||||
},
|
||||
"node_modules/@img/sharp-libvips-darwin-arm64": {
|
||||
"version": "1.0.4",
|
||||
"resolved": "https://registry.npmjs.org/@img/sharp-libvips-darwin-arm64/-/sharp-libvips-darwin-arm64-1.0.4.tgz",
|
||||
"integrity": "sha512-XblONe153h0O2zuFfTAbQYAX2JhYmDHeWikp1LM9Hul9gVPjFY427k6dFEcOL72O01QxQsWi761svJ/ev9xEDg==",
|
||||
"cpu": [
|
||||
"arm64"
|
||||
],
|
||||
"license": "LGPL-3.0-or-later",
|
||||
"optional": true,
|
||||
"os": [
|
||||
"darwin"
|
||||
],
|
||||
"funding": {
|
||||
"url": "https://opencollective.com/libvips"
|
||||
}
|
||||
},
|
||||
"node_modules/@img/sharp-libvips-darwin-x64": {
|
||||
"version": "1.0.4",
|
||||
"resolved": "https://registry.npmjs.org/@img/sharp-libvips-darwin-x64/-/sharp-libvips-darwin-x64-1.0.4.tgz",
|
||||
"integrity": "sha512-xnGR8YuZYfJGmWPvmlunFaWJsb9T/AO2ykoP3Fz/0X5XV2aoYBPkX6xqCQvUTKKiLddarLaxpzNe+b1hjeWHAQ==",
|
||||
"cpu": [
|
||||
"x64"
|
||||
],
|
||||
"license": "LGPL-3.0-or-later",
|
||||
"optional": true,
|
||||
"os": [
|
||||
"darwin"
|
||||
],
|
||||
"funding": {
|
||||
"url": "https://opencollective.com/libvips"
|
||||
}
|
||||
},
|
||||
"node_modules/@img/sharp-libvips-linux-arm": {
|
||||
"version": "1.0.5",
|
||||
"resolved": "https://registry.npmjs.org/@img/sharp-libvips-linux-arm/-/sharp-libvips-linux-arm-1.0.5.tgz",
|
||||
"integrity": "sha512-gvcC4ACAOPRNATg/ov8/MnbxFDJqf/pDePbBnuBDcjsI8PssmjoKMAz4LtLaVi+OnSb5FK/yIOamqDwGmXW32g==",
|
||||
"cpu": [
|
||||
"arm"
|
||||
],
|
||||
"license": "LGPL-3.0-or-later",
|
||||
"optional": true,
|
||||
"os": [
|
||||
"linux"
|
||||
],
|
||||
"funding": {
|
||||
"url": "https://opencollective.com/libvips"
|
||||
}
|
||||
},
|
||||
"node_modules/@img/sharp-libvips-linux-arm64": {
|
||||
"version": "1.0.4",
|
||||
"resolved": "https://registry.npmjs.org/@img/sharp-libvips-linux-arm64/-/sharp-libvips-linux-arm64-1.0.4.tgz",
|
||||
"integrity": "sha512-9B+taZ8DlyyqzZQnoeIvDVR/2F4EbMepXMc/NdVbkzsJbzkUjhXv/70GQJ7tdLA4YJgNP25zukcxpX2/SueNrA==",
|
||||
"cpu": [
|
||||
"arm64"
|
||||
],
|
||||
"license": "LGPL-3.0-or-later",
|
||||
"optional": true,
|
||||
"os": [
|
||||
"linux"
|
||||
],
|
||||
"funding": {
|
||||
"url": "https://opencollective.com/libvips"
|
||||
}
|
||||
},
|
||||
"node_modules/@img/sharp-libvips-linux-s390x": {
|
||||
"version": "1.0.4",
|
||||
"resolved": "https://registry.npmjs.org/@img/sharp-libvips-linux-s390x/-/sharp-libvips-linux-s390x-1.0.4.tgz",
|
||||
"integrity": "sha512-u7Wz6ntiSSgGSGcjZ55im6uvTrOxSIS8/dgoVMoiGE9I6JAfU50yH5BoDlYA1tcuGS7g/QNtetJnxA6QEsCVTA==",
|
||||
"cpu": [
|
||||
"s390x"
|
||||
],
|
||||
"license": "LGPL-3.0-or-later",
|
||||
"optional": true,
|
||||
"os": [
|
||||
"linux"
|
||||
],
|
||||
"funding": {
|
||||
"url": "https://opencollective.com/libvips"
|
||||
}
|
||||
},
|
||||
"node_modules/@img/sharp-libvips-linux-x64": {
|
||||
"version": "1.0.4",
|
||||
"resolved": "https://registry.npmjs.org/@img/sharp-libvips-linux-x64/-/sharp-libvips-linux-x64-1.0.4.tgz",
|
||||
"integrity": "sha512-MmWmQ3iPFZr0Iev+BAgVMb3ZyC4KeFc3jFxnNbEPas60e1cIfevbtuyf9nDGIzOaW9PdnDciJm+wFFaTlj5xYw==",
|
||||
"cpu": [
|
||||
"x64"
|
||||
],
|
||||
"license": "LGPL-3.0-or-later",
|
||||
"optional": true,
|
||||
"os": [
|
||||
"linux"
|
||||
],
|
||||
"funding": {
|
||||
"url": "https://opencollective.com/libvips"
|
||||
}
|
||||
},
|
||||
"node_modules/@img/sharp-libvips-linuxmusl-arm64": {
|
||||
"version": "1.0.4",
|
||||
"resolved": "https://registry.npmjs.org/@img/sharp-libvips-linuxmusl-arm64/-/sharp-libvips-linuxmusl-arm64-1.0.4.tgz",
|
||||
"integrity": "sha512-9Ti+BbTYDcsbp4wfYib8Ctm1ilkugkA/uscUn6UXK1ldpC1JjiXbLfFZtRlBhjPZ5o1NCLiDbg8fhUPKStHoTA==",
|
||||
"cpu": [
|
||||
"arm64"
|
||||
],
|
||||
"license": "LGPL-3.0-or-later",
|
||||
"optional": true,
|
||||
"os": [
|
||||
"linux"
|
||||
],
|
||||
"funding": {
|
||||
"url": "https://opencollective.com/libvips"
|
||||
}
|
||||
},
|
||||
"node_modules/@img/sharp-libvips-linuxmusl-x64": {
|
||||
"version": "1.0.4",
|
||||
"resolved": "https://registry.npmjs.org/@img/sharp-libvips-linuxmusl-x64/-/sharp-libvips-linuxmusl-x64-1.0.4.tgz",
|
||||
"integrity": "sha512-viYN1KX9m+/hGkJtvYYp+CCLgnJXwiQB39damAO7WMdKWlIhmYTfHjwSbQeUK/20vY154mwezd9HflVFM1wVSw==",
|
||||
"cpu": [
|
||||
"x64"
|
||||
],
|
||||
"license": "LGPL-3.0-or-later",
|
||||
"optional": true,
|
||||
"os": [
|
||||
"linux"
|
||||
],
|
||||
"funding": {
|
||||
"url": "https://opencollective.com/libvips"
|
||||
}
|
||||
},
|
||||
"node_modules/@img/sharp-linux-arm": {
|
||||
"version": "0.33.5",
|
||||
"resolved": "https://registry.npmjs.org/@img/sharp-linux-arm/-/sharp-linux-arm-0.33.5.tgz",
|
||||
"integrity": "sha512-JTS1eldqZbJxjvKaAkxhZmBqPRGmxgu+qFKSInv8moZ2AmT5Yib3EQ1c6gp493HvrvV8QgdOXdyaIBrhvFhBMQ==",
|
||||
"cpu": [
|
||||
"arm"
|
||||
],
|
||||
"license": "Apache-2.0",
|
||||
"optional": true,
|
||||
"os": [
|
||||
"linux"
|
||||
],
|
||||
"engines": {
|
||||
"node": "^18.17.0 || ^20.3.0 || >=21.0.0"
|
||||
},
|
||||
"funding": {
|
||||
"url": "https://opencollective.com/libvips"
|
||||
},
|
||||
"optionalDependencies": {
|
||||
"@img/sharp-libvips-linux-arm": "1.0.5"
|
||||
}
|
||||
},
|
||||
"node_modules/@img/sharp-linux-arm64": {
|
||||
"version": "0.33.5",
|
||||
"resolved": "https://registry.npmjs.org/@img/sharp-linux-arm64/-/sharp-linux-arm64-0.33.5.tgz",
|
||||
"integrity": "sha512-JMVv+AMRyGOHtO1RFBiJy/MBsgz0x4AWrT6QoEVVTyh1E39TrCUpTRI7mx9VksGX4awWASxqCYLCV4wBZHAYxA==",
|
||||
"cpu": [
|
||||
"arm64"
|
||||
],
|
||||
"license": "Apache-2.0",
|
||||
"optional": true,
|
||||
"os": [
|
||||
"linux"
|
||||
],
|
||||
"engines": {
|
||||
"node": "^18.17.0 || ^20.3.0 || >=21.0.0"
|
||||
},
|
||||
"funding": {
|
||||
"url": "https://opencollective.com/libvips"
|
||||
},
|
||||
"optionalDependencies": {
|
||||
"@img/sharp-libvips-linux-arm64": "1.0.4"
|
||||
}
|
||||
},
|
||||
"node_modules/@img/sharp-linux-s390x": {
|
||||
"version": "0.33.5",
|
||||
"resolved": "https://registry.npmjs.org/@img/sharp-linux-s390x/-/sharp-linux-s390x-0.33.5.tgz",
|
||||
"integrity": "sha512-y/5PCd+mP4CA/sPDKl2961b+C9d+vPAveS33s6Z3zfASk2j5upL6fXVPZi7ztePZ5CuH+1kW8JtvxgbuXHRa4Q==",
|
||||
"cpu": [
|
||||
"s390x"
|
||||
],
|
||||
"license": "Apache-2.0",
|
||||
"optional": true,
|
||||
"os": [
|
||||
"linux"
|
||||
],
|
||||
"engines": {
|
||||
"node": "^18.17.0 || ^20.3.0 || >=21.0.0"
|
||||
},
|
||||
"funding": {
|
||||
"url": "https://opencollective.com/libvips"
|
||||
},
|
||||
"optionalDependencies": {
|
||||
"@img/sharp-libvips-linux-s390x": "1.0.4"
|
||||
}
|
||||
},
|
||||
"node_modules/@img/sharp-linux-x64": {
|
||||
"version": "0.33.5",
|
||||
"resolved": "https://registry.npmjs.org/@img/sharp-linux-x64/-/sharp-linux-x64-0.33.5.tgz",
|
||||
"integrity": "sha512-opC+Ok5pRNAzuvq1AG0ar+1owsu842/Ab+4qvU879ippJBHvyY5n2mxF1izXqkPYlGuP/M556uh53jRLJmzTWA==",
|
||||
"cpu": [
|
||||
"x64"
|
||||
],
|
||||
"license": "Apache-2.0",
|
||||
"optional": true,
|
||||
"os": [
|
||||
"linux"
|
||||
],
|
||||
"engines": {
|
||||
"node": "^18.17.0 || ^20.3.0 || >=21.0.0"
|
||||
},
|
||||
"funding": {
|
||||
"url": "https://opencollective.com/libvips"
|
||||
},
|
||||
"optionalDependencies": {
|
||||
"@img/sharp-libvips-linux-x64": "1.0.4"
|
||||
}
|
||||
},
|
||||
"node_modules/@img/sharp-linuxmusl-arm64": {
|
||||
"version": "0.33.5",
|
||||
"resolved": "https://registry.npmjs.org/@img/sharp-linuxmusl-arm64/-/sharp-linuxmusl-arm64-0.33.5.tgz",
|
||||
"integrity": "sha512-XrHMZwGQGvJg2V/oRSUfSAfjfPxO+4DkiRh6p2AFjLQztWUuY/o8Mq0eMQVIY7HJ1CDQUJlxGGZRw1a5bqmd1g==",
|
||||
"cpu": [
|
||||
"arm64"
|
||||
],
|
||||
"license": "Apache-2.0",
|
||||
"optional": true,
|
||||
"os": [
|
||||
"linux"
|
||||
],
|
||||
"engines": {
|
||||
"node": "^18.17.0 || ^20.3.0 || >=21.0.0"
|
||||
},
|
||||
"funding": {
|
||||
"url": "https://opencollective.com/libvips"
|
||||
},
|
||||
"optionalDependencies": {
|
||||
"@img/sharp-libvips-linuxmusl-arm64": "1.0.4"
|
||||
}
|
||||
},
|
||||
"node_modules/@img/sharp-linuxmusl-x64": {
|
||||
"version": "0.33.5",
|
||||
"resolved": "https://registry.npmjs.org/@img/sharp-linuxmusl-x64/-/sharp-linuxmusl-x64-0.33.5.tgz",
|
||||
"integrity": "sha512-WT+d/cgqKkkKySYmqoZ8y3pxx7lx9vVejxW/W4DOFMYVSkErR+w7mf2u8m/y4+xHe7yY9DAXQMWQhpnMuFfScw==",
|
||||
"cpu": [
|
||||
"x64"
|
||||
],
|
||||
"license": "Apache-2.0",
|
||||
"optional": true,
|
||||
"os": [
|
||||
"linux"
|
||||
],
|
||||
"engines": {
|
||||
"node": "^18.17.0 || ^20.3.0 || >=21.0.0"
|
||||
},
|
||||
"funding": {
|
||||
"url": "https://opencollective.com/libvips"
|
||||
},
|
||||
"optionalDependencies": {
|
||||
"@img/sharp-libvips-linuxmusl-x64": "1.0.4"
|
||||
}
|
||||
},
|
||||
"node_modules/@img/sharp-wasm32": {
|
||||
"version": "0.33.5",
|
||||
"resolved": "https://registry.npmjs.org/@img/sharp-wasm32/-/sharp-wasm32-0.33.5.tgz",
|
||||
"integrity": "sha512-ykUW4LVGaMcU9lu9thv85CbRMAwfeadCJHRsg2GmeRa/cJxsVY9Rbd57JcMxBkKHag5U/x7TSBpScF4U8ElVzg==",
|
||||
"cpu": [
|
||||
"wasm32"
|
||||
],
|
||||
"license": "Apache-2.0 AND LGPL-3.0-or-later AND MIT",
|
||||
"optional": true,
|
||||
"dependencies": {
|
||||
"@emnapi/runtime": "^1.2.0"
|
||||
},
|
||||
"engines": {
|
||||
"node": "^18.17.0 || ^20.3.0 || >=21.0.0"
|
||||
},
|
||||
"funding": {
|
||||
"url": "https://opencollective.com/libvips"
|
||||
}
|
||||
},
|
||||
"node_modules/@img/sharp-win32-ia32": {
|
||||
"version": "0.33.5",
|
||||
"resolved": "https://registry.npmjs.org/@img/sharp-win32-ia32/-/sharp-win32-ia32-0.33.5.tgz",
|
||||
"integrity": "sha512-T36PblLaTwuVJ/zw/LaH0PdZkRz5rd3SmMHX8GSmR7vtNSP5Z6bQkExdSK7xGWyxLw4sUknBuugTelgw2faBbQ==",
|
||||
"cpu": [
|
||||
"ia32"
|
||||
],
|
||||
"license": "Apache-2.0 AND LGPL-3.0-or-later",
|
||||
"optional": true,
|
||||
"os": [
|
||||
"win32"
|
||||
],
|
||||
"engines": {
|
||||
"node": "^18.17.0 || ^20.3.0 || >=21.0.0"
|
||||
},
|
||||
"funding": {
|
||||
"url": "https://opencollective.com/libvips"
|
||||
}
|
||||
},
|
||||
"node_modules/@img/sharp-win32-x64": {
|
||||
"version": "0.33.5",
|
||||
"resolved": "https://registry.npmjs.org/@img/sharp-win32-x64/-/sharp-win32-x64-0.33.5.tgz",
|
||||
"integrity": "sha512-MpY/o8/8kj+EcnxwvrP4aTJSWw/aZ7JIGR4aBeZkZw5B7/Jn+tY9/VNwtcoGmdT7GfggGIU4kygOMSbYnOrAbg==",
|
||||
"cpu": [
|
||||
"x64"
|
||||
],
|
||||
"license": "Apache-2.0 AND LGPL-3.0-or-later",
|
||||
"optional": true,
|
||||
"os": [
|
||||
"win32"
|
||||
],
|
||||
"engines": {
|
||||
"node": "^18.17.0 || ^20.3.0 || >=21.0.0"
|
||||
},
|
||||
"funding": {
|
||||
"url": "https://opencollective.com/libvips"
|
||||
}
|
||||
},
|
||||
"node_modules/@js-sdsl/ordered-map": {
|
||||
"version": "4.4.2",
|
||||
"resolved": "https://registry.npmjs.org/@js-sdsl/ordered-map/-/ordered-map-4.4.2.tgz",
|
||||
@@ -3097,7 +3469,6 @@
|
||||
"resolved": "https://registry.npmjs.org/color-string/-/color-string-1.9.1.tgz",
|
||||
"integrity": "sha512-shrVawQFojnZv6xM40anx4CkoDP+fZsw/ZerEMsW/pyzsRbElpsL/DBVW7q3ExxwusdNXI3lXpuhEZkzs8p5Eg==",
|
||||
"license": "MIT",
|
||||
"optional": true,
|
||||
"dependencies": {
|
||||
"color-name": "^1.0.0",
|
||||
"simple-swizzle": "^0.2.2"
|
||||
@@ -3296,6 +3667,15 @@
|
||||
"npm": "1.2.8000 || >= 1.4.16"
|
||||
}
|
||||
},
|
||||
"node_modules/detect-libc": {
|
||||
"version": "2.1.2",
|
||||
"resolved": "https://registry.npmjs.org/detect-libc/-/detect-libc-2.1.2.tgz",
|
||||
"integrity": "sha512-Btj2BOOO83o3WyH59e8MgXsxEQVcarkUOpEYrubB0urwnN10yQ364rsiByU11nZlqWYZm05i/of7io4mzihBtQ==",
|
||||
"license": "Apache-2.0",
|
||||
"engines": {
|
||||
"node": ">=8"
|
||||
}
|
||||
},
|
||||
"node_modules/doctrine": {
|
||||
"version": "3.0.0",
|
||||
"resolved": "https://registry.npmjs.org/doctrine/-/doctrine-3.0.0.tgz",
|
||||
@@ -4842,8 +5222,7 @@
|
||||
"version": "0.3.2",
|
||||
"resolved": "https://registry.npmjs.org/is-arrayish/-/is-arrayish-0.3.2.tgz",
|
||||
"integrity": "sha512-eVRqCvVlZbuw3GrM63ovNSNAeA1K16kaR/LRY/92w0zxQ5/1YzwblUX652i4Xs9RwAGjW9d9y6X88t8OaAJfWQ==",
|
||||
"license": "MIT",
|
||||
"optional": true
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/is-core-module": {
|
||||
"version": "2.16.1",
|
||||
@@ -6205,6 +6584,58 @@
|
||||
"integrity": "sha512-E5LDX7Wrp85Kil5bhZv46j8jOeboKq5JMmYM3gVGdGH8xFpPWXUMsNrlODCrkoxMEeNi/XZIwuRvY4XNwYMJpw==",
|
||||
"license": "ISC"
|
||||
},
|
||||
"node_modules/sharp": {
|
||||
"version": "0.33.5",
|
||||
"resolved": "https://registry.npmjs.org/sharp/-/sharp-0.33.5.tgz",
|
||||
"integrity": "sha512-haPVm1EkS9pgvHrQ/F3Xy+hgcuMV0Wm9vfIBSiwZ05k+xgb0PkBQpGsAA/oWdDobNaZTH5ppvHtzCFbnSEwHVw==",
|
||||
"hasInstallScript": true,
|
||||
"license": "Apache-2.0",
|
||||
"dependencies": {
|
||||
"color": "^4.2.3",
|
||||
"detect-libc": "^2.0.3",
|
||||
"semver": "^7.6.3"
|
||||
},
|
||||
"engines": {
|
||||
"node": "^18.17.0 || ^20.3.0 || >=21.0.0"
|
||||
},
|
||||
"funding": {
|
||||
"url": "https://opencollective.com/libvips"
|
||||
},
|
||||
"optionalDependencies": {
|
||||
"@img/sharp-darwin-arm64": "0.33.5",
|
||||
"@img/sharp-darwin-x64": "0.33.5",
|
||||
"@img/sharp-libvips-darwin-arm64": "1.0.4",
|
||||
"@img/sharp-libvips-darwin-x64": "1.0.4",
|
||||
"@img/sharp-libvips-linux-arm": "1.0.5",
|
||||
"@img/sharp-libvips-linux-arm64": "1.0.4",
|
||||
"@img/sharp-libvips-linux-s390x": "1.0.4",
|
||||
"@img/sharp-libvips-linux-x64": "1.0.4",
|
||||
"@img/sharp-libvips-linuxmusl-arm64": "1.0.4",
|
||||
"@img/sharp-libvips-linuxmusl-x64": "1.0.4",
|
||||
"@img/sharp-linux-arm": "0.33.5",
|
||||
"@img/sharp-linux-arm64": "0.33.5",
|
||||
"@img/sharp-linux-s390x": "0.33.5",
|
||||
"@img/sharp-linux-x64": "0.33.5",
|
||||
"@img/sharp-linuxmusl-arm64": "0.33.5",
|
||||
"@img/sharp-linuxmusl-x64": "0.33.5",
|
||||
"@img/sharp-wasm32": "0.33.5",
|
||||
"@img/sharp-win32-ia32": "0.33.5",
|
||||
"@img/sharp-win32-x64": "0.33.5"
|
||||
}
|
||||
},
|
||||
"node_modules/sharp/node_modules/color": {
|
||||
"version": "4.2.3",
|
||||
"resolved": "https://registry.npmjs.org/color/-/color-4.2.3.tgz",
|
||||
"integrity": "sha512-1rXeuUUiGGrykh+CeBdu5Ie7OJwinCgQY0bc7GCRxy5xVHy+moaqkpL/jqQq0MtQOeYcrqEz4abc5f0KtU7W4A==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"color-convert": "^2.0.1",
|
||||
"color-string": "^1.9.0"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=12.5.0"
|
||||
}
|
||||
},
|
||||
"node_modules/shebang-command": {
|
||||
"version": "2.0.0",
|
||||
"resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-2.0.0.tgz",
|
||||
@@ -6311,7 +6742,6 @@
|
||||
"resolved": "https://registry.npmjs.org/simple-swizzle/-/simple-swizzle-0.2.2.tgz",
|
||||
"integrity": "sha512-JA//kQgZtbuY83m+xT+tXJkmJncGMTFT+C+g2h2R9uxkYIrE2yy9sgmcLhCnw57/WSD+Eh3J97FPEDFnbXnDUg==",
|
||||
"license": "MIT",
|
||||
"optional": true,
|
||||
"dependencies": {
|
||||
"is-arrayish": "^0.3.1"
|
||||
}
|
||||
|
||||
@@ -23,7 +23,8 @@
|
||||
"firebase-admin": "^12.7.0",
|
||||
"firebase-functions": "^6.4.0",
|
||||
"fluent-ffmpeg": "^2.1.3",
|
||||
"genkit": "^1.18.0"
|
||||
"genkit": "^1.18.0",
|
||||
"sharp": "^0.33.4"
|
||||
},
|
||||
"devDependencies": {
|
||||
"eslint": "^8.15.0",
|
||||
|
||||
+91
-54
@@ -3,11 +3,68 @@ const admin = require("firebase-admin");
|
||||
const logger = require("firebase-functions/logger");
|
||||
const {
|
||||
generateImageV2,
|
||||
CombineCoverAndPicture,
|
||||
} = require("../helpers/gemini");
|
||||
const { generatePicturePrompt } = require("../helpers/prompts");
|
||||
const path = require("path");
|
||||
const fs = require("fs");
|
||||
const axios = require("axios");
|
||||
const sharp = require("sharp");
|
||||
|
||||
const db = admin.firestore();
|
||||
const bucket = admin.storage().bucket();
|
||||
const LOGO_PATH = path.resolve(
|
||||
__dirname,
|
||||
"../assets/musicLandProduction.png",
|
||||
);
|
||||
|
||||
async function buildCoverWithLogo(backgroundUrl, targetPath) {
|
||||
logger.info("🖼️ [Cover] Adding logo to generated background");
|
||||
const [{ data: backgroundBuffer }, logoBuffer] = await Promise.all([
|
||||
axios.get(backgroundUrl, { responseType: "arraybuffer" }),
|
||||
fs.promises.readFile(LOGO_PATH),
|
||||
]);
|
||||
|
||||
const baseImage = sharp(backgroundBuffer);
|
||||
const { width = 1024, height = 1024 } = await baseImage.metadata();
|
||||
|
||||
const desiredWidth = Math.round(width * 0.32);
|
||||
const margin = Math.round(width * 0.04);
|
||||
|
||||
const { data: resizedLogo, info: logoInfo } = await sharp(logoBuffer)
|
||||
.resize({ width: desiredWidth })
|
||||
.png()
|
||||
.toBuffer({ resolveWithObject: true });
|
||||
|
||||
const left = Math.max(width - logoInfo.width - margin, 0);
|
||||
const top = Math.max(height - logoInfo.height - margin, 0);
|
||||
|
||||
const stampedBuffer = await baseImage
|
||||
.ensureAlpha()
|
||||
.composite([
|
||||
{
|
||||
input: resizedLogo,
|
||||
left,
|
||||
top,
|
||||
blend: "over",
|
||||
},
|
||||
])
|
||||
.png()
|
||||
.toBuffer();
|
||||
|
||||
const token = require("crypto").randomUUID();
|
||||
await bucket.file(targetPath).save(stampedBuffer, {
|
||||
resumable: false,
|
||||
metadata: {
|
||||
contentType: "image/png",
|
||||
cacheControl: "public, max-age=31536000",
|
||||
metadata: { firebaseStorageDownloadTokens: token },
|
||||
},
|
||||
});
|
||||
|
||||
return `https://firebasestorage.googleapis.com/v0/b/${bucket.name}/o/${encodeURIComponent(
|
||||
targetPath,
|
||||
)}?alt=media&token=${token}`;
|
||||
}
|
||||
|
||||
// Shared core for generating and saving the cover, and updating the project
|
||||
async function performCoverGeneration(project) {
|
||||
@@ -19,12 +76,13 @@ async function performCoverGeneration(project) {
|
||||
promptPreview: String(prompt).slice(0, 160),
|
||||
});
|
||||
let coverUrl = "";
|
||||
const timestamp = Date.now();
|
||||
try {
|
||||
// Utiliser une taille fixe de 1024 pixels
|
||||
coverUrl = await generateImageV2(
|
||||
prompt,
|
||||
1024,
|
||||
`users/${project.userId}/projects/${project.id}/generated-${Date.now()}.png`,
|
||||
`users/${project.userId}/projects/${project.id}/generated-${timestamp}.png`,
|
||||
);
|
||||
console.log("coverUrl", coverUrl);
|
||||
} catch (e) {
|
||||
@@ -38,6 +96,19 @@ async function performCoverGeneration(project) {
|
||||
throw new Error("Génération d'image échouée (URL vide)");
|
||||
}
|
||||
|
||||
let finalCoverUrl = "";
|
||||
try {
|
||||
const stampedPath = `users/${project.userId}/projects/${project.id}/cover-${timestamp}-stamped.png`;
|
||||
finalCoverUrl = await buildCoverWithLogo(coverUrl, stampedPath);
|
||||
} catch (e) {
|
||||
logger.error("❌ [Cover] Logo overlay failed", {
|
||||
projectId: project.id,
|
||||
error: e?.message || String(e),
|
||||
});
|
||||
// En cas d'échec, on retient au moins la cover générée
|
||||
finalCoverUrl = coverUrl;
|
||||
}
|
||||
|
||||
// Mettre à jour le projet avec l'URL et le statut
|
||||
await db
|
||||
.collection("projects")
|
||||
@@ -46,6 +117,7 @@ async function performCoverGeneration(project) {
|
||||
{
|
||||
cover: {
|
||||
generatedBackground: coverUrl,
|
||||
result: finalCoverUrl,
|
||||
},
|
||||
coverStatus: "GENERATED",
|
||||
updatedAt: admin.firestore.FieldValue.serverTimestamp(),
|
||||
@@ -56,56 +128,10 @@ async function performCoverGeneration(project) {
|
||||
logger.info("✅ [Cover] Saved", {
|
||||
projectId: project.id,
|
||||
coverUrl,
|
||||
finalCoverUrl,
|
||||
ms: Date.now() - t0,
|
||||
});
|
||||
return coverUrl;
|
||||
}
|
||||
|
||||
async function performCombineGeneration(project) {
|
||||
const t0 = Date.now();
|
||||
const background = project?.cover?.generatedBackground || null;
|
||||
const foreground = project?.cover?.userForeground || null;
|
||||
|
||||
if (!background || !foreground) {
|
||||
throw new Error(
|
||||
"Images manquantes: cover.generatedBackground et cover.userForground sont requis",
|
||||
);
|
||||
}
|
||||
|
||||
logger.info("🧩 [Combine] Inputs detected", {
|
||||
bgPreview: String(background).slice(0, 80),
|
||||
fgPreview: String(foreground).slice(0, 80),
|
||||
});
|
||||
|
||||
const combinedUrl = await CombineCoverAndPicture(
|
||||
background,
|
||||
foreground,
|
||||
`users/${project.userId}/projects/${project.id}/combine-${Date.now()}.png`,
|
||||
);
|
||||
|
||||
// Sauvegarder le résultat et marquer comme généré
|
||||
await db
|
||||
.collection("projects")
|
||||
.doc(project.id)
|
||||
.set(
|
||||
{
|
||||
cover: {
|
||||
...project.cover,
|
||||
result: combinedUrl,
|
||||
},
|
||||
coverStatus: "GENERATED",
|
||||
updatedAt: admin.firestore.FieldValue.serverTimestamp(),
|
||||
},
|
||||
{ merge: true },
|
||||
);
|
||||
|
||||
logger.info("✅ [Cover] Combined image saved", {
|
||||
projectId: project.id,
|
||||
combinedUrl,
|
||||
ms: Date.now() - t0,
|
||||
});
|
||||
|
||||
return combinedUrl;
|
||||
return finalCoverUrl;
|
||||
}
|
||||
|
||||
// Firestore trigger: création d'une tâche de génération de cover
|
||||
@@ -132,6 +158,21 @@ exports.onTaskCreateGenerateCover = onDocumentCreated(
|
||||
type,
|
||||
projectId,
|
||||
});
|
||||
|
||||
if (type === "combine") {
|
||||
logger.warn("⛔ [Task] Combine task ignored (feature disabled)", {
|
||||
projectId,
|
||||
taskId: event?.params?.taskId,
|
||||
});
|
||||
await event.data.ref.update({
|
||||
status: "CANCELLED",
|
||||
error:
|
||||
"La personnalisation de la pochette avec une photo n'est plus disponible.",
|
||||
updatedAt: admin.firestore.FieldValue.serverTimestamp(),
|
||||
});
|
||||
return;
|
||||
}
|
||||
|
||||
await db.collection("projects").doc(projectId).update({
|
||||
coverStatus: "GENERATING",
|
||||
updatedAt: admin.firestore.FieldValue.serverTimestamp(),
|
||||
@@ -154,10 +195,6 @@ exports.onTaskCreateGenerateCover = onDocumentCreated(
|
||||
logger.info("🎨 [Task] Start cover generation", { projectId });
|
||||
coverUrl = await performCoverGeneration(project);
|
||||
logger.info("✅ [Task] Cover generated", { projectId });
|
||||
} else if (type === "combine") {
|
||||
logger.info("🧩 [Task] Start combine (cover + photo)", { projectId });
|
||||
coverUrl = await performCombineGeneration(project);
|
||||
logger.info("✅ [Task] Combine generated", { projectId, coverUrl });
|
||||
}
|
||||
|
||||
await event.data.ref.update({
|
||||
|
||||
@@ -1,30 +1,21 @@
|
||||
import * as ImagePicker from "expo-image-picker";
|
||||
import { BlurView } from "expo-blur";
|
||||
import React, { useCallback, useEffect, useMemo, useState } from "react";
|
||||
import {
|
||||
Image,
|
||||
Modal,
|
||||
Pressable,
|
||||
StyleSheet,
|
||||
Text,
|
||||
View,
|
||||
} from "react-native";
|
||||
import { Image, Modal, Pressable, StyleSheet, Text, View } from "react-native";
|
||||
import useMinuit from "react-native-minuit/src/hooks/useMinuit";
|
||||
import { ai, background } from "../../assets";
|
||||
import BorderGradientButton from "../../components/BorderGradientButton";
|
||||
import FullscreenIntroVideo from "../../components/FullscreenIntroVideo";
|
||||
import GradientButton from "../../components/GradientButton";
|
||||
import MusicLandHeader from "../../components/MusicLandHeader";
|
||||
import { Input } from "../../components/Input";
|
||||
import MusicLandHeader from "../../components/MusicLandHeader";
|
||||
import firebase, { projectsRef, usersRef } from "../../config/firebase";
|
||||
import { uploadFileToFirebase } from "../../helpers/uploadToFirebase";
|
||||
import Page from "../../layouts/Page";
|
||||
import { Routes } from "../../navigation";
|
||||
import { goBack, navigate } from "../../navigation/NavigationService";
|
||||
import { useUserData } from "../../providers/UserDataProvider";
|
||||
import { buildFullName } from "../../utils/artistName";
|
||||
import { gutters, Palette } from "../../styles";
|
||||
import { FONT_FAMILY } from "../../styles/Fonts";
|
||||
import { buildFullName } from "../../utils/artistName";
|
||||
|
||||
export const ChooseCoverType = () => {
|
||||
const [showIntro, setShowIntro] = useState(true);
|
||||
@@ -52,11 +43,14 @@ export const ChooseCoverType = () => {
|
||||
return pref === "REAL_NAME" || pref === "CUSTOM";
|
||||
}, [currentUserData?.artistNamePreference, currentUserData?.userName]);
|
||||
|
||||
const realName = useMemo(() => buildFullName(currentUserData), [
|
||||
const realName = useMemo(
|
||||
() => buildFullName(currentUserData),
|
||||
[
|
||||
currentUserData?.firstName,
|
||||
currentUserData?.lastName,
|
||||
currentUserData?.displayName,
|
||||
]);
|
||||
]
|
||||
);
|
||||
|
||||
useEffect(() => {
|
||||
if (pseudoVisible) {
|
||||
@@ -122,48 +116,48 @@ export const ChooseCoverType = () => {
|
||||
[currentUID, projectId]
|
||||
);
|
||||
|
||||
const pickUserImage = useCallback(async () => {
|
||||
try {
|
||||
await setIsLoading(true);
|
||||
const result = await ImagePicker.launchImageLibraryAsync({
|
||||
mediaTypes: ["images"],
|
||||
allowsEditing: true,
|
||||
aspect: [1, 1],
|
||||
quality: 1,
|
||||
});
|
||||
// const pickUserImage = useCallback(async () => {
|
||||
// try {
|
||||
// await setIsLoading(true);
|
||||
// const result = await ImagePicker.launchImageLibraryAsync({
|
||||
// mediaTypes: ["images"],
|
||||
// allowsEditing: true,
|
||||
// aspect: [1, 1],
|
||||
// quality: 1,
|
||||
// });
|
||||
|
||||
const uri = result?.assets?.[0]?.uri || null;
|
||||
if (!uri) return;
|
||||
// const uri = result?.assets?.[0]?.uri || null;
|
||||
// if (!uri) return;
|
||||
|
||||
if (!projectId) return;
|
||||
const path = `musics/${projectId}/userSelectedCover.png`;
|
||||
// if (!projectId) return;
|
||||
// const path = `musics/${projectId}/userSelectedCover.png`;
|
||||
|
||||
const { resultURI } = await uploadFileToFirebase({
|
||||
uri,
|
||||
path,
|
||||
shouldCompress: true,
|
||||
fileType: "IMAGE",
|
||||
});
|
||||
// const { resultURI } = await uploadFileToFirebase({
|
||||
// uri,
|
||||
// path,
|
||||
// shouldCompress: true,
|
||||
// fileType: "IMAGE",
|
||||
// });
|
||||
|
||||
if (!resultURI) {
|
||||
throw new Error("Erreur lors de l'upload");
|
||||
}
|
||||
await updateProjectData({
|
||||
cover: {
|
||||
result: resultURI,
|
||||
},
|
||||
});
|
||||
navigate(Routes.ValidateCover);
|
||||
} catch (e) {
|
||||
console.log("onPickUserImage error", e?.message);
|
||||
} finally {
|
||||
await setIsLoading(false);
|
||||
}
|
||||
}, [projectId, setIsLoading, updateProjectData]);
|
||||
// if (!resultURI) {
|
||||
// throw new Error("Erreur lors de l'upload");
|
||||
// }
|
||||
// await updateProjectData({
|
||||
// cover: {
|
||||
// result: resultURI,
|
||||
// },
|
||||
// });
|
||||
// navigate(Routes.ValidateCover);
|
||||
// } catch (e) {
|
||||
// console.log("onPickUserImage error", e?.message);
|
||||
// } finally {
|
||||
// await setIsLoading(false);
|
||||
// }
|
||||
// }, [projectId, setIsLoading, updateProjectData]);
|
||||
|
||||
const handlePickUserImage = useCallback(() => {
|
||||
ensureArtistPreference(pickUserImage);
|
||||
}, [ensureArtistPreference, pickUserImage]);
|
||||
// const handlePickUserImage = useCallback(() => {
|
||||
// ensureArtistPreference(pickUserImage);
|
||||
// }, [ensureArtistPreference, pickUserImage]);
|
||||
|
||||
const handleGenerateCover = useCallback(() => {
|
||||
ensureArtistPreference(() => navigate(Routes.PouchReady));
|
||||
@@ -184,8 +178,7 @@ export const ChooseCoverType = () => {
|
||||
if (!realName) {
|
||||
setTooltip({
|
||||
type: "error",
|
||||
text:
|
||||
"Renseigne ton prénom et nom dans ton profil ou crée un nom d'artiste.",
|
||||
text: "Renseigne ton prénom et nom dans ton profil ou crée un nom d'artiste.",
|
||||
});
|
||||
setChoiceVisible(false);
|
||||
setPseudoVisible(true);
|
||||
@@ -298,10 +291,10 @@ export const ChooseCoverType = () => {
|
||||
gap: 12,
|
||||
}}
|
||||
>
|
||||
<BorderGradientButton
|
||||
{/* <BorderGradientButton
|
||||
title="Choisir une image"
|
||||
onPress={handlePickUserImage}
|
||||
/>
|
||||
/> */}
|
||||
<GradientButton
|
||||
title="Générer une pochette"
|
||||
onPress={handleGenerateCover}
|
||||
@@ -333,9 +326,7 @@ export const ChooseCoverType = () => {
|
||||
</Text>
|
||||
<View style={styles.modalButtons}>
|
||||
<BorderGradientButton
|
||||
title={
|
||||
savingChoice ? "Chargement..." : "Utiliser prénom/nom"
|
||||
}
|
||||
title={savingChoice ? "Chargement..." : "Utiliser prénom/nom"}
|
||||
onPress={handleUseRealName}
|
||||
disabled={savingChoice}
|
||||
/>
|
||||
|
||||
@@ -1,15 +1,11 @@
|
||||
import { Image as ExpoImage } from "expo-image";
|
||||
import * as ImagePicker from "expo-image-picker";
|
||||
import React from "react";
|
||||
import { ActivityIndicator, Text, View } from "react-native";
|
||||
import useMinuit from "react-native-minuit/src/hooks/useMinuit";
|
||||
import { background } from "../../assets";
|
||||
import BorderGradientButton from "../../components/BorderGradientButton";
|
||||
import GradientButton from "../../components/GradientButton";
|
||||
import MusicLandHeader from "../../components/MusicLandHeader";
|
||||
import firebase, { tasksRef } from "../../config/firebase";
|
||||
import loaderMessages from "../../config/loaderMessages";
|
||||
import { uploadFileToFirebase } from "../../helpers/uploadToFirebase";
|
||||
import { isWeb } from "../../hooks/useLayoutType";
|
||||
import Page from "../../layouts/Page";
|
||||
import { Routes } from "../../navigation";
|
||||
@@ -19,69 +15,30 @@ import { gutters, Palette, Style } from "../../styles";
|
||||
import CreateLyricsHeader from "../Writing/components/CreateLyricsHeader";
|
||||
|
||||
const PhotoCover = () => {
|
||||
const { selectedProject, selectedProjectId, updateProjectData } =
|
||||
useUserData();
|
||||
const { setIsLoading } = useMinuit();
|
||||
const { selectedProject } = useUserData();
|
||||
const isGenerating = selectedProject?.coverStatus === "GENERATING";
|
||||
const coverGenerationMessage = isWeb
|
||||
? loaderMessages.photoCoverGenerationWeb
|
||||
: "";
|
||||
|
||||
const onChooseForegroundImage = async () => {
|
||||
try {
|
||||
await setIsLoading(true);
|
||||
const result = await ImagePicker.launchImageLibraryAsync({
|
||||
mediaTypes: ["images"],
|
||||
allowsEditing: true,
|
||||
aspect: [1, 1],
|
||||
quality: 1,
|
||||
});
|
||||
|
||||
const uri = result?.assets?.[0]?.uri || null;
|
||||
if (!uri) return;
|
||||
|
||||
const projectId = selectedProject?.id || selectedProjectId;
|
||||
const path = `musics/${projectId}/userForeground.png`;
|
||||
|
||||
const { resultURI } = await uploadFileToFirebase({
|
||||
uri,
|
||||
path,
|
||||
shouldCompress: true,
|
||||
fileType: "IMAGE",
|
||||
});
|
||||
|
||||
if (!resultURI) {
|
||||
throw new Error("Erreur lors de l'upload");
|
||||
}
|
||||
await updateProjectData({
|
||||
cover: {
|
||||
...selectedProject.cover,
|
||||
userForeground: resultURI,
|
||||
},
|
||||
});
|
||||
await tasksRef.add({
|
||||
type: "combine",
|
||||
projectId: selectedProjectId,
|
||||
status: "PENDING",
|
||||
createdAt: firebase.firestore.FieldValue.serverTimestamp(),
|
||||
});
|
||||
} catch (e) {
|
||||
console.log("onPickUserImage error", e?.message);
|
||||
} finally {
|
||||
await setIsLoading(false);
|
||||
}
|
||||
};
|
||||
const coverUrl =
|
||||
selectedProject?.cover?.result ||
|
||||
selectedProject?.cover?.generatedBackground ||
|
||||
null;
|
||||
|
||||
return (
|
||||
<Page backgroundImg={background.studioBG2} headerType="NONE">
|
||||
<MusicLandHeader onPressBack={goBack} progress={81} />
|
||||
<View style={{ flex: 1, marginTop: 16 }}>
|
||||
<CreateLyricsHeader title="Souhaites-tu rajouter une photo de toi sur la pochette?" />
|
||||
<CreateLyricsHeader
|
||||
title="Ta pochette MusicLand Production"
|
||||
subTitle="Le logo est automatiquement ajouté en bas à droite."
|
||||
/>
|
||||
<View style={{ flex: 1, ...Style.containerCenter }}>
|
||||
<View style={{ width: "80%", position: "relative" }}>
|
||||
{selectedProject?.cover?.result && !isGenerating ? (
|
||||
{coverUrl && !isGenerating ? (
|
||||
<ExpoImage
|
||||
source={{ uri: selectedProject?.cover?.result }}
|
||||
source={{ uri: coverUrl }}
|
||||
cachePolicy="memory-disk"
|
||||
priority="high"
|
||||
contentFit="cover"
|
||||
@@ -103,11 +60,11 @@ const PhotoCover = () => {
|
||||
...Style.containerCenter,
|
||||
}}
|
||||
>
|
||||
{isGenerating && (
|
||||
<View style={{ alignItems: "center", gap: 8 }}>
|
||||
{isGenerating ? (
|
||||
<>
|
||||
<ActivityIndicator color={Palette.white} />
|
||||
{isWeb ? (
|
||||
coverGenerationMessage ? (
|
||||
{isWeb && coverGenerationMessage ? (
|
||||
<Text
|
||||
style={{
|
||||
color: Palette.white,
|
||||
@@ -118,7 +75,6 @@ const PhotoCover = () => {
|
||||
>
|
||||
{coverGenerationMessage}
|
||||
</Text>
|
||||
) : null
|
||||
) : (
|
||||
<Text
|
||||
style={{
|
||||
@@ -131,9 +87,22 @@ const PhotoCover = () => {
|
||||
Génération en cours.
|
||||
</Text>
|
||||
)}
|
||||
</View>
|
||||
</>
|
||||
) : (
|
||||
<Text
|
||||
style={{
|
||||
color: Palette.white,
|
||||
marginTop: 6,
|
||||
textAlign: "center",
|
||||
opacity: 0.9,
|
||||
}}
|
||||
>
|
||||
La pochette sera disponible une fois la génération
|
||||
terminée.
|
||||
</Text>
|
||||
)}
|
||||
</View>
|
||||
</View>
|
||||
)}
|
||||
</View>
|
||||
</View>
|
||||
@@ -147,18 +116,14 @@ const PhotoCover = () => {
|
||||
}}
|
||||
>
|
||||
<BorderGradientButton
|
||||
onPress={() => navigate(Routes.ValidateCover)}
|
||||
title={
|
||||
isGenerating ? "Génération en cours..." : "Valider la pochette"
|
||||
}
|
||||
onPress={() => navigate(Routes.PouchReady)}
|
||||
title="Regénérer la pochette"
|
||||
disabled={isGenerating}
|
||||
/>
|
||||
<GradientButton
|
||||
title={
|
||||
isGenerating ? "Génération en cours..." : "Oui choisir une image"
|
||||
}
|
||||
onPress={() => onChooseForegroundImage()}
|
||||
disabled={isGenerating}
|
||||
title="Valider la pochette"
|
||||
onPress={() => navigate(Routes.ValidateCover)}
|
||||
disabled={isGenerating || !coverUrl}
|
||||
/>
|
||||
</View>
|
||||
</Page>
|
||||
|
||||
@@ -19,7 +19,7 @@ import { gutters, Palette, Style } from "../../styles";
|
||||
import CreateLyricsHeader from "../Writing/components/CreateLyricsHeader";
|
||||
|
||||
const PouchReady = () => {
|
||||
const { selectedProjectId, selectedProject, updateProjectData } = useUser();
|
||||
const { selectedProjectId, selectedProject } = useUser();
|
||||
const { setIsLoading } = useMinuit();
|
||||
const isGenerating = selectedProject?.coverStatus === "GENERATING";
|
||||
const isFocused = useIsFocused();
|
||||
@@ -44,22 +44,9 @@ const PouchReady = () => {
|
||||
}
|
||||
}, [selectedProjectId, setIsLoading]);
|
||||
|
||||
async function validateCover() {
|
||||
try {
|
||||
await setIsLoading(true);
|
||||
await updateProjectData({
|
||||
cover: {
|
||||
...selectedProject.cover,
|
||||
result: selectedProject.cover.generatedBackground,
|
||||
},
|
||||
});
|
||||
navigate(Routes.PhotoCover);
|
||||
} catch (e) {
|
||||
console.log(e);
|
||||
} finally {
|
||||
await setIsLoading(false);
|
||||
}
|
||||
}
|
||||
const validateCover = () => {
|
||||
navigate(Routes.ValidateCover);
|
||||
};
|
||||
|
||||
useEffect(() => {
|
||||
if (
|
||||
@@ -84,6 +71,11 @@ const PouchReady = () => {
|
||||
}
|
||||
}, [generateCover, isFocused, selectedProject]);
|
||||
|
||||
const coverPreviewUrl =
|
||||
selectedProject?.cover?.result ||
|
||||
selectedProject?.cover?.generatedBackground ||
|
||||
null;
|
||||
|
||||
return (
|
||||
<Page backgroundImg={background.studioBG2} headerType="NONE">
|
||||
<MusicLandHeader onPressBack={goBack} progress={72} />
|
||||
@@ -98,9 +90,9 @@ const PouchReady = () => {
|
||||
/>
|
||||
<View style={{ flex: 1, ...Style.containerCenter }}>
|
||||
<View style={{ width: "80%", position: "relative" }}>
|
||||
{selectedProject?.cover?.generatedBackground && !isGenerating ? (
|
||||
{coverPreviewUrl && !isGenerating ? (
|
||||
<ExpoImage
|
||||
source={{ uri: selectedProject?.cover?.generatedBackground }}
|
||||
source={{ uri: coverPreviewUrl }}
|
||||
cachePolicy="memory-disk"
|
||||
priority="high"
|
||||
contentFit="cover"
|
||||
@@ -215,7 +207,7 @@ const PouchReady = () => {
|
||||
/>
|
||||
<GradientButton
|
||||
title={isGenerating ? "Veuillez patienter..." : "Valider"}
|
||||
disabled={isGenerating}
|
||||
disabled={isGenerating || !coverPreviewUrl}
|
||||
onPress={() => validateCover()}
|
||||
/>
|
||||
</View>
|
||||
|
||||
@@ -205,7 +205,7 @@ export const getStageAction = (key, project) => {
|
||||
}
|
||||
|
||||
if (!hasFinalCover) {
|
||||
return { route: Routes.PhotoCover };
|
||||
return { route: Routes.ValidateCover };
|
||||
}
|
||||
|
||||
return { route: Routes.ChooseCoverType };
|
||||
|
||||
Reference in New Issue
Block a user