Skip to content

Commit

Permalink
Store : RSS Feed, add option for write text on images
Browse files Browse the repository at this point in the history
  • Loading branch information
DantSu committed Dec 4, 2024
1 parent 3ddea89 commit 9b9010b
Show file tree
Hide file tree
Showing 11 changed files with 67 additions and 19 deletions.
Binary file added extraResources/fonts/exo2.ttf
Binary file not shown.
36 changes: 33 additions & 3 deletions public/MainEvents/Processes/BinFiles/FFmpegCommand.js
Original file line number Diff line number Diff line change
@@ -1,7 +1,8 @@
import {spawn} from 'child_process'
import {getBinPath} from '../Helpers/AppPaths.js'
import {getBinPath, getExtraResourcesPath} from '../Helpers/AppPaths.js'
import * as fs from 'fs'
import {rmFile} from '../../Helpers/Files.js'
import path from 'path'

const
getFFmpegFileName = () => {
Expand Down Expand Up @@ -78,10 +79,39 @@ const
})
})
},
convertImageToPng = (srcFile, dstPng, width, height) => {
processStringToFFmpeg = (str) => {
str = str.replaceAll('\'', '’')
const aStr = []
while (str.length > 32) {
const
s = str.substring(0, 32),
i = s.lastIndexOf(' ')
if (i === -1) {
const i2 = str.indexOf(' ')
if (i2 === -1) {
break
}
aStr.push(str.substring(0, i2))
str = str.substring(i2 + 1)
} else {
aStr.push(str.substring(0, i))
str = str.substring(i + 1)
}
}
aStr.push(str)
return aStr.map((s) => s.replace(/([^A-Za-z0-9 ]{1})/g, '\\$1')).join('\n')
},
convertImageToPng = (srcFile, dstPng, width, height, textToWrite) => {
return new Promise((resolve, reject) => {
rmFile(dstPng)
const stream = spawn(getFFmpegFilePath(), ['-i', srcFile, '-vf', 'scale=' + width + 'x' + height + ':flags=bilinear', dstPng])
const
textCommand = typeof textToWrite === 'string' ?
', drawtext=fontfile=\'' + path.join(getExtraResourcesPath(), 'fonts', 'exo2.ttf').replaceAll('\\', '\\\\').replaceAll(':', '\\:') +
'\':text=\'' + processStringToFFmpeg(textToWrite) + '\':text_align=M+C:fontcolor=black:fontsize=32:' +
'box=1:[email protected]:boxborderw=10|10:x=(w-text_w)/2:y=h-th-20' : '',

stream = spawn(getFFmpegFilePath(), ['-i', srcFile, '-vf', 'scale=' + width + 'x' + height + ':flags=bilinear' + textCommand, dstPng])

stream.on('close', (code) => {
if (code === 0) {
resolve()
Expand Down
1 change: 1 addition & 0 deletions public/MainEvents/Processes/Import/ConvertFolderFS.js
Original file line number Diff line number Diff line change
Expand Up @@ -187,6 +187,7 @@ function convertFolderFS (srcPath, storyName) {
(index) => convertStoryImages(
tmpImagesPathsArray,
toDstPathsArray(ri, dstImagesPath, renameImage),
null,
index,
countFiles,
(index) => decipherMedias(
Expand Down
1 change: 1 addition & 0 deletions public/MainEvents/Processes/Import/ConvertFolderSTUdio.js
Original file line number Diff line number Diff line change
Expand Up @@ -125,6 +125,7 @@ function convertFolderSTUdio (srcPath, storyName) {
convertStoryImages(
srcImages,
toDstPathsArray(srcImages, dstImagesPath, renameImage),
null,
2,
countFiles,
(index) => convertAudios(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -216,6 +216,7 @@ function convertFolderStoryPack(srcPath, storyName) {
convertStoryImages(
srcImages,
dstImages,
null,
2,
countFiles,
(index) => convertTextToSpeech(
Expand Down
27 changes: 14 additions & 13 deletions public/MainEvents/Processes/Import/Helpers/ImageFile.js
Original file line number Diff line number Diff line change
Expand Up @@ -6,33 +6,34 @@ const
const ext = path.extname(fileName).toLowerCase()
return ext === '.png' || ext === '.bmp' || ext === '.gif' || ext === '.jpg' || ext === '.jpeg' || ext === '.webp' || ext === '.avif'
},
convertMusicImage = async (fromPath, toPath) => {
await convertImageToPng(fromPath, toPath, 256, 256)
convertMusicImage = async (fromPath, toPath, textToWrite) => {
await convertImageToPng(fromPath, toPath, 256, 256, textToWrite)
},
convertCoverImage = async (fromPath, toPath) => {
await convertImageToPng(fromPath, toPath, 512, 512)
convertCoverImage = async (fromPath, toPath, textToWrite) => {
await convertImageToPng(fromPath, toPath, 512, 512, textToWrite)
},
convertStoryImage = async (fromPath, toPath) => {
await convertImageToPng(fromPath, toPath, 640, 480)
convertStoryImage = async (fromPath, toPath, textToWrite) => {
await convertImageToPng(fromPath, toPath, 640, 480, textToWrite)
},
convertInventoryImage = async (fromPath, toPath) => {
await convertImageToPng(fromPath, toPath, 128, 128)
convertInventoryImage = async (fromPath, toPath, textToWrite) => {
await convertImageToPng(fromPath, toPath, 128, 128, textToWrite)
},
convertStoryImages = (srcImages, dstImages, index, length, onEnd) => {
convertStoryImages = (srcImages, dstImages, textsToWrite, index, length, onEnd) => {
if (!srcImages.length) {
onEnd(index)
return
}

const
srcImage = srcImages.shift(),
dstImage = dstImages.shift()
dstImage = dstImages.shift(),
textToWrite = Array.isArray(textsToWrite) ? textsToWrite.shift() : undefined

process.stdout.write('*converting-images*' + index + '*' + length + '*')

convertStoryImage(srcImage, dstImage)
.then(() => convertStoryImages(srcImages, dstImages, index + 1, length, onEnd))
.catch(() => convertStoryImages(srcImages, dstImages, index + 1, length, onEnd))
convertStoryImage(srcImage, dstImage, textToWrite)
.then(() => convertStoryImages(srcImages, dstImages, textsToWrite, index + 1, length, onEnd))
.catch(() => convertStoryImages(srcImages, dstImages, textsToWrite, index + 1, length, onEnd))
},
convertInventoryImages = (srcImages, dstImages, index, length, onEnd) => {
if (!srcImages.length) {
Expand Down
5 changes: 4 additions & 1 deletion public/MainEvents/Processes/Store/StoreBuild.js
Original file line number Diff line number Diff line change
Expand Up @@ -59,11 +59,13 @@ function main(jsonPath) {
dstPath = getStoriesPath(generateDirNameStory(metadata.title, metadata.uuid, metadata.age, metadata.category)),
dstPathImages = path.join(dstPath, 'images'),
dstPathAudio = path.join(dstPath, 'audios'),
srcTts = [store.title, question, ...stories.map((s) => s.title)],
storiesTitles = stories.map((s) => s.title),
srcTts = [store.title, question, ...storiesTitles],
dstTts = [path.join(dstPath, 'title.mp3'), path.join(dstPathAudio, 'q.mp3'), ...stories.map((s, k) => path.join(dstPathAudio, 't' + k + '.mp3'))],
srcHttpAudio = stories.map((s) => s.download),
dstHttpAudio = stories.map((s, k) => path.join(dstPathAudio, 's' + k + '.mp3')),
srcImages = [store.cover, ...stories.map((s) => s.image)],
titleImages = store.titleImages ? [undefined, ...storiesTitles] : null,
dstImages = [path.join(dstPath, 'title.png'), ...stories.map((s, k) => path.join(dstPathImages, k + '.png'))],
countFiles = stories.length * 4 + 6,

Expand Down Expand Up @@ -118,6 +120,7 @@ function main(jsonPath) {
convertStoryImages(
srcImages,
dstImages,
titleImages,
0,
countFiles,
(index) => downloadAudios(
Expand Down
1 change: 1 addition & 0 deletions public/MainEvents/Processes/Studio/StudioSave.js
Original file line number Diff line number Diff line change
Expand Up @@ -279,6 +279,7 @@ function main(jsonPath) {
convertStoryImages(
files.newImages.src,
files.newImages.dst,
null,
10,
countFiles,
(index) => convertAudios(
Expand Down
12 changes: 10 additions & 2 deletions src/App/Modules/Stores/Store/ModalStoreBuildForm.js
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ import ButtonsContainer from '../../../Components/Buttons/ButtonsContainer.js'
import ButtonIconTextCheck from '../../../Components/Buttons/IconsTexts/ButtonIconTextCheck.js'
import InputText from '../../../Components/Form/Input/InputText.js'
import InputTextarea from '../../../Components/Form/Input/InputTextarea.js'
import InputSwitch from '../../../Components/Form/Input/InputSwitch.js'
import ModalTitle from '../../../Components/Modal/ModalTitle.js'
import ModalContent from '../../../Components/Modal/ModalContent.js'
import Form from '../../../Components/Form/Form.js'
Expand All @@ -18,7 +19,8 @@ function ModalStoreBuildForm({store, stories, onClose}) {
{addModal, rmModal} = useModal(),
titleRef = useRef(),
categoryRef = useRef(),
descriptionRef = useRef()
descriptionRef = useRef(),
titleImagesRef = useRef()

return <ModalLayoutPadded isClosable={true}
onClose={onClose}>
Expand Down Expand Up @@ -47,13 +49,18 @@ function ModalStoreBuildForm({store, stories, onClose}) {
required={false}
defaultValue={stripHtmlTags(store.description) + '\n\n' + stories.map((s) => '- ' + s.title).join('\n')}
ref={descriptionRef}/>

<InputSwitch label={getLocale('story-add-title-images')}
key="store-confirm"
id="store-confirm"
ref={titleImagesRef}/>
</ModalContent>
<ButtonsContainer>
<ButtonIconTextCheck text={getLocale('save')}
rounded={true}
onClick={() => {
validation(
[titleRef, categoryRef, descriptionRef],
[titleRef, categoryRef, descriptionRef, titleImagesRef],
(values) => {
onClose()
addModal((key) => {
Expand All @@ -63,6 +70,7 @@ function ModalStoreBuildForm({store, stories, onClose}) {
title: values[0],
category: values[1],
description: values[2],
titleImages: values[3],
cover: stories[0].image
}}
stories={stories}
Expand Down
1 change: 1 addition & 0 deletions src/Locales/en.js
Original file line number Diff line number Diff line change
Expand Up @@ -164,6 +164,7 @@ const en = {
'story-saving': 'Saving story',
'story-export': 'Exporting story',
'story-zipping': 'Pack story in a zip file',
'story-add-title-images': 'Add title to story images',
'stories': 'Stories',
'stories-local': 'My stories ({0})',
'stories-on-store': '{0} stories on the store',
Expand Down
1 change: 1 addition & 0 deletions src/Locales/fr.js
Original file line number Diff line number Diff line change
Expand Up @@ -164,6 +164,7 @@ const fr = {
'story-saving': 'Sauvegarde de l\'histoire',
'story-export': 'Export de l\'histoire',
'story-zipping': 'Export de l\'histoire au format zip',
'story-add-title-images': 'Ajouter le titre aux images des histoires',
'stories': 'Histoires',
'stories-local': 'Mes histoires ({0})',
'stories-on-store': '{0} histoires sur le store',
Expand Down

0 comments on commit 9b9010b

Please sign in to comment.