diff --git a/html/src/app.js b/html/src/app.js index 273ca89a..433f3426 100644 --- a/html/src/app.js +++ b/html/src/app.js @@ -17643,28 +17643,39 @@ speechSynthesis.getVoices(); false ); - $app.methods.trySavePrintToFile = async function (printId) { - var print = await API.getPrint({ printId }); - var imageUrl = print.json?.files?.image; - if (!imageUrl) { - console.error('Print image URL is missing', print); - return; - } + $app.methods.getPrintDate = function (print) { var createdAt = new Date(); - if (print.json.timestamp) { - createdAt = new Date(print.json.timestamp); - } else if (print.json.createdAt) { - createdAt = new Date(print.json.createdAt); + if (print.timestamp) { + createdAt = new Date(print.timestamp); + } else if (print.createdAt) { + createdAt = new Date(print.createdAt); } - var authorName = print.json.authorName; + return createdAt; + }; + + $app.methods.getPrintFileName = function (print) { + var authorName = print.authorName; // fileDate format: 2024-11-03_16-14-25.757 + var createdAt = this.getPrintDate(print); var fileNameDate = createdAt .toISOString() .replace(/:/g, '-') .replace(/T/g, '_') .replace(/Z/g, ''); + var fileName = `${authorName}_${fileNameDate}_${print.id}.png`; + return fileName; + }; + + $app.methods.trySavePrintToFile = async function (printId) { + var args = await API.getPrint({ printId }); + var imageUrl = args.json?.files?.image; + if (!imageUrl) { + console.error('Print image URL is missing', args); + return; + } + var createdAt = this.getPrintDate(args.json); var path = `${createdAt.toISOString().slice(0, 7)}`; - var fileName = `${authorName}_${fileNameDate}_${printId}.png`; + var fileName = this.getPrintFileName(args.json); var status = await AppApi.SavePrintToFile(imageUrl, path, fileName); if (status) { console.log(`Print saved to file: ${path}\\${fileName}`); @@ -17739,6 +17750,8 @@ speechSynthesis.getVoices(); clearFile(); return; } + // set Emoji settings from fileName + this.parseEmojiFileName(files[0].name); var r = new FileReader(); r.onload = function () { var params = { @@ -17853,6 +17866,42 @@ speechSynthesis.getVoices(); return style; }; + $app.methods.getEmojiFileName = function (emoji) { + if (emoji.frames) { + var loopStyle = emoji.loopStyle || 'linear'; + return `${emoji.name}_${emoji.animationStyle}animationStyle_${emoji.frames}frames_${emoji.framesOverTime}fps_${loopStyle}loopStyle.png`; + } else { + return `${emoji.name}_${emoji.animationStyle}animationStyle.png`; + } + }; + + $app.methods.parseEmojiFileName = function (fileName) { + // remove file extension + fileName = fileName.replace(/\.[^/.]+$/, ''); + var array = fileName.split('_'); + for (var i = 0; i < array.length; ++i) { + var value = array[i]; + if (value.endsWith('animationStyle')) { + this.emojiAnimType = false; + this.emojiAnimationStyle = value + .replace('animationStyle', '') + .toLowerCase(); + } + if (value.endsWith('frames')) { + this.emojiAnimType = true; + this.emojiAnimFrameCount = parseInt( + value.replace('frames', '') + ); + } + if (value.endsWith('fps')) { + this.emojiAnimFps = parseInt(value.replace('fps', '')); + } + if (value.endsWith('loopStyle')) { + this.emojiAnimLoopPingPong = value === 'pingpong'; + } + } + }; + // #endregion // #region Misc @@ -21302,7 +21351,7 @@ speechSynthesis.getVoices(); } }; - $app.methods.downloadAndSaveImage = async function (url) { + $app.methods.downloadAndSaveImage = async function (url, fileName) { if (!url) { return; } @@ -21323,7 +21372,10 @@ speechSynthesis.getVoices(); } var link = document.createElement('a'); link.href = response.data; - var fileName = `${$utils.extractFileId(url)}.png`; + var fileId = $utils.extractFileId(url); + if (!fileName && fileId) { + fileName = `${fileId}.png`; + } if (!fileName) { fileName = `${url.split('/').pop()}.png`; } @@ -21703,10 +21755,11 @@ speechSynthesis.getVoices(); $app.data.fullscreenImageDialog = { visible: false, - imageUrl: '' + imageUrl: '', + fileName: '' }; - $app.methods.showFullscreenImageDialog = function (imageUrl) { + $app.methods.showFullscreenImageDialog = function (imageUrl, fileName) { if (!imageUrl) { return; } @@ -21715,6 +21768,7 @@ speechSynthesis.getVoices(); ); var D = this.fullscreenImageDialog; D.imageUrl = imageUrl; + D.fileName = fileName; D.visible = true; }; diff --git a/html/src/mixins/dialogs/currentUser.pug b/html/src/mixins/dialogs/currentUser.pug index e7d60620..7d893ae1 100644 --- a/html/src/mixins/dialogs/currentUser.pug +++ b/html/src/mixins/dialogs/currentUser.pug @@ -84,7 +84,7 @@ mixin currentUser() span(slot="label") {{ $t('dialog.gallery_icons.icons') }} span(style="color:#909399;font-size:12px;margin-left:5px") {{ VRCPlusIconsTable.length }}/64 input(type="file" accept="image/*" @change="onFileChangeVRCPlusIcon" id="VRCPlusIconUploadButton" style="display:none") - span {{ $t('dialog.gallery_icons.recommended_image_size') }}: 2000x2000px (1:1) + span {{ $t('dialog.gallery_icons.recommended_image_size') }}: 2048x2048px (1:1) br br el-button-group @@ -102,7 +102,7 @@ mixin currentUser() span(slot="label") {{ $t('dialog.gallery_icons.emojis') }} span(style="color:#909399;font-size:12px;margin-left:5px") {{ emojiTable.length }}/9 input(type="file" accept="image/*" @change="onFileChangeEmoji" id="EmojiUploadButton" style="display:none") - span {{ $t('dialog.gallery_icons.recommended_image_size') }}: 2000x2000px (1:1) + span {{ $t('dialog.gallery_icons.recommended_image_size') }}: 1024x1024px (1:1) br br el-button-group(style="margin-right:10px") @@ -125,10 +125,11 @@ mixin currentUser() el-checkbox(v-model="emojiAnimLoopPingPong" style="margin-left:10px;margin-right:10px") span {{ $t('dialog.gallery_icons.emoji_loop_pingpong') }} br + br span {{ $t('dialog.gallery_icons.flipbook_info') }} br .x-friend-item(v-if="image.versions && image.versions.length > 0" v-for="image in emojiTable" :key="image.id" style="display:inline-block;margin-top:10px;width:unset;cursor:default") - .vrcplus-icon(v-if="image.versions[image.versions.length - 1].file.url" style="overflow:hidden" @click="showFullscreenImageDialog(image.versions[image.versions.length - 1].file.url)") + .vrcplus-icon(v-if="image.versions[image.versions.length - 1].file.url" style="overflow:hidden" @click="showFullscreenImageDialog(image.versions[image.versions.length - 1].file.url, getEmojiFileName(image))") template(v-if="image.frames") .avatar(:style="generateEmojiStyle(image.versions[image.versions.length - 1].file.url, image.framesOverTime, image.frames, image.loopStyle)") template(v-else) @@ -140,13 +141,13 @@ mixin currentUser() span(v-if="image.frames" style="margin-right:5px") {{ image.frames }}frames br div(style="float:right;margin-top:5px") - el-button(type="default" @click="showFullscreenImageDialog(image.versions[image.versions.length - 1].file.url)" size="mini" icon="el-icon-picture-outline" circle) + el-button(type="default" @click="showFullscreenImageDialog(image.versions[image.versions.length - 1].file.url, getEmojiFileName(image))" size="mini" icon="el-icon-picture-outline" circle) el-button(type="default" @click="deleteEmoji(image.id)" size="mini" icon="el-icon-delete" circle style="margin-left:5px") el-tab-pane(v-if="galleryDialogVisible" v-loading="galleryDialogStickersLoading") span(slot="label") {{ $t('dialog.gallery_icons.stickers') }} span(style="color:#909399;font-size:12px;margin-left:5px") {{ stickerTable.length }}/9 input(type="file" accept="image/*" @change="onFileChangeSticker" id="StickerUploadButton" style="display:none") - span {{ $t('dialog.gallery_icons.recommended_image_size') }}: 2000x2000px (1:1) + span {{ $t('dialog.gallery_icons.recommended_image_size') }}: 1024x1024px (1:1) br br el-button-group @@ -172,7 +173,7 @@ mixin currentUser() el-input(type="textarea" v-model="printUploadNote" size="mini" rows="1" resize="none" maxlength="32" style="margin-left:10px;width:300px" :placeholder="$t('dialog.gallery_icons.note')") br .x-friend-item(v-for="image in printTable" :key="image.id" style="display:inline-block;margin-top:10px;width:unset;cursor:default") - .vrcplus-icon(style="overflow:hidden" @click="showFullscreenImageDialog(image.files.image)") + .vrcplus-icon(style="overflow:hidden" @click="showFullscreenImageDialog(image.files.image, getPrintFileName(image))") img.avatar(v-lazy="image.files.image") div(style="margin-top:5px;width:208px") span.x-ellipsis(v-if="image.note" v-text="image.note" style="display:block") @@ -184,5 +185,5 @@ mixin currentUser() span.x-ellipsis(v-if="image.timestamp" style="color:#909399;font-family:monospace;font-size:11px;display:block") {{ image.timestamp | formatDate('long') }} span(v-else style="display:block")   div(style="float:right") - el-button(type="default" @click="showFullscreenImageDialog(image.files.image)" size="mini" icon="el-icon-picture-outline" circle) + el-button(type="default" @click="showFullscreenImageDialog(image.files.image, getPrintFileName(image))" size="mini" icon="el-icon-picture-outline" circle) el-button(type="default" @click="deletePrint(image.id)" size="mini" icon="el-icon-delete" circle style="margin-left:5px") diff --git a/html/src/mixins/dialogs/images.pug b/html/src/mixins/dialogs/images.pug index c013202c..414b347f 100644 --- a/html/src/mixins/dialogs/images.pug +++ b/html/src/mixins/dialogs/images.pug @@ -56,5 +56,5 @@ mixin images() //- dialog: full screen image el-dialog.x-dialog(ref="fullscreenImageDialog" :before-close="beforeDialogClose" @mousedown.native="dialogMouseDown" @mouseup.native="dialogMouseUp" :visible.sync="fullscreenImageDialog.visible" top="3vh" width="97vw") el-button(@click="copyImageUrl(fullscreenImageDialog.imageUrl)" size="mini" icon="el-icon-s-order" circle) - el-button(type="default" size="mini" icon="el-icon-download" circle @click="downloadAndSaveImage(fullscreenImageDialog.imageUrl)" style="margin-left:5px") + el-button(type="default" size="mini" icon="el-icon-download" circle @click="downloadAndSaveImage(fullscreenImageDialog.imageUrl, fullscreenImageDialog.fileName)" style="margin-left:5px") img(v-lazy="fullscreenImageDialog.imageUrl" style="width:100%;height:100vh;object-fit:contain")