mirror of
https://github.com/MrUnknownDE/VRCX.git
synced 2026-05-07 14:56:06 +02:00
Save instance emojis
This commit is contained in:
@@ -257,5 +257,26 @@ namespace VRCX
|
|||||||
|
|
||||||
return filePath;
|
return filePath;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public async Task<string> SaveEmojiToFile(string url, string ugcFolderPath, string monthFolder, string fileName)
|
||||||
|
{
|
||||||
|
var folder = Path.Join(GetUGCPhotoLocation(ugcFolderPath), "Emoji", MakeValidFileName(monthFolder));
|
||||||
|
Directory.CreateDirectory(folder);
|
||||||
|
var filePath = Path.Join(folder, MakeValidFileName(fileName));
|
||||||
|
if (File.Exists(filePath))
|
||||||
|
return null;
|
||||||
|
|
||||||
|
try
|
||||||
|
{
|
||||||
|
await ImageCache.SaveImageToFile(url, filePath);
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
logger.Error(ex, "Failed to save print to file");
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
return filePath;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
+84
@@ -32,6 +32,7 @@ import {
|
|||||||
groupRequest,
|
groupRequest,
|
||||||
imageRequest,
|
imageRequest,
|
||||||
instanceRequest,
|
instanceRequest,
|
||||||
|
inventoryRequest,
|
||||||
inviteMessagesRequest,
|
inviteMessagesRequest,
|
||||||
miscRequest,
|
miscRequest,
|
||||||
notificationRequest,
|
notificationRequest,
|
||||||
@@ -119,6 +120,7 @@ import { userDialogGroupSortingOptions } from './composables/user/constants/user
|
|||||||
import {
|
import {
|
||||||
getPrintFileName,
|
getPrintFileName,
|
||||||
getPrintLocalDate,
|
getPrintLocalDate,
|
||||||
|
getEmojiFileName,
|
||||||
languageClass
|
languageClass
|
||||||
} from './composables/user/utils';
|
} from './composables/user/utils';
|
||||||
import InteropApi from './ipc-electron/interopApi.js';
|
import InteropApi from './ipc-electron/interopApi.js';
|
||||||
@@ -6768,6 +6770,9 @@ console.log(`isLinux: ${LINUX}`);
|
|||||||
case 'VRCX_saveInstanceStickers':
|
case 'VRCX_saveInstanceStickers':
|
||||||
this.saveInstanceStickers = !this.saveInstanceStickers;
|
this.saveInstanceStickers = !this.saveInstanceStickers;
|
||||||
break;
|
break;
|
||||||
|
case 'VRCX_saveInstanceEmoji':
|
||||||
|
this.saveInstanceEmoji = !this.saveInstanceEmoji;
|
||||||
|
break;
|
||||||
case 'VRCX_StartAsMinimizedState':
|
case 'VRCX_StartAsMinimizedState':
|
||||||
this.isStartAsMinimizedState = !this.isStartAsMinimizedState;
|
this.isStartAsMinimizedState = !this.isStartAsMinimizedState;
|
||||||
break;
|
break;
|
||||||
@@ -6808,6 +6813,11 @@ console.log(`isLinux: ${LINUX}`);
|
|||||||
this.saveInstanceStickers
|
this.saveInstanceStickers
|
||||||
);
|
);
|
||||||
|
|
||||||
|
await configRepository.setBool(
|
||||||
|
'VRCX_saveInstanceEmoji',
|
||||||
|
this.saveInstanceEmoji
|
||||||
|
);
|
||||||
|
|
||||||
VRCXStorage.Set(
|
VRCXStorage.Set(
|
||||||
'VRCX_StartAsMinimizedState',
|
'VRCX_StartAsMinimizedState',
|
||||||
this.isStartAsMinimizedState.toString()
|
this.isStartAsMinimizedState.toString()
|
||||||
@@ -10954,6 +10964,75 @@ console.log(`isLinux: ${LINUX}`);
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// #endregion
|
||||||
|
// #region | Emoji
|
||||||
|
|
||||||
|
$app.data.instanceInventoryCache = [];
|
||||||
|
$app.data.instanceInventoryQueue = [];
|
||||||
|
$app.data.instanceInventoryQueueWorker = null;
|
||||||
|
|
||||||
|
$app.methods.queueCheckInstanceInventory = function (inventoryId) {
|
||||||
|
if (this.instanceInventoryCache.includes(inventoryId)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
this.instanceInventoryCache.push(inventoryId);
|
||||||
|
if (this.instanceInventoryCache.length > 100) {
|
||||||
|
this.instanceInventoryCache.shift();
|
||||||
|
}
|
||||||
|
|
||||||
|
this.instanceInventoryQueue.push(inventoryId);
|
||||||
|
|
||||||
|
if (!this.instanceInventoryQueueWorker) {
|
||||||
|
this.instanceInventoryQueueWorker = workerTimers.setInterval(() => {
|
||||||
|
let inventoryId = this.instanceInventoryQueue.shift();
|
||||||
|
if (inventoryId) {
|
||||||
|
this.trySaveEmojiToFile(inventoryId);
|
||||||
|
}
|
||||||
|
}, 2_500);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
$app.methods.trySaveEmojiToFile = async function (inventoryId) {
|
||||||
|
const args = await inventoryRequest.getInventoryItem({
|
||||||
|
inventoryId
|
||||||
|
});
|
||||||
|
|
||||||
|
if (args.json.itemType !== 'emoji') {
|
||||||
|
// Not an emoji, skip
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const userArgs = await userRequest.getCachedUser({
|
||||||
|
userId: args.json.holderId
|
||||||
|
});
|
||||||
|
const displayName = userArgs.json?.displayName ?? '';
|
||||||
|
|
||||||
|
let emoji = args.json.metadata;
|
||||||
|
emoji.name = `${displayName}_${inventoryId}`;
|
||||||
|
|
||||||
|
const emojiFileName = getEmojiFileName(emoji);
|
||||||
|
const imageUrl = args.json.metadata?.imageUrl ?? args.json.imageUrl;
|
||||||
|
const createdAt = args.json.created_at;
|
||||||
|
const monthFolder = createdAt.slice(0, 7);
|
||||||
|
|
||||||
|
const filePath = await AppApi.SaveEmojiToFile(
|
||||||
|
imageUrl,
|
||||||
|
this.ugcFolderPath,
|
||||||
|
monthFolder,
|
||||||
|
emojiFileName
|
||||||
|
);
|
||||||
|
if (filePath) {
|
||||||
|
console.log(
|
||||||
|
`Emoji saved to file: ${monthFolder}\\${emojiFileName}`
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (this.instanceInventoryQueue.length === 0) {
|
||||||
|
workerTimers.clearInterval(this.instanceInventoryQueueWorker);
|
||||||
|
this.instanceInventoryQueueWorker = null;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
// #endregion
|
// #endregion
|
||||||
// #region | Prints
|
// #region | Prints
|
||||||
$app.methods.cropPrintsChanged = function () {
|
$app.methods.cropPrintsChanged = function () {
|
||||||
@@ -11038,6 +11117,11 @@ console.log(`isLinux: ${LINUX}`);
|
|||||||
false
|
false
|
||||||
);
|
);
|
||||||
|
|
||||||
|
$app.data.saveInstanceEmoji = await configRepository.getBool(
|
||||||
|
'VRCX_saveInstanceEmoji',
|
||||||
|
false
|
||||||
|
);
|
||||||
|
|
||||||
$app.data.printCache = [];
|
$app.data.printCache = [];
|
||||||
$app.data.printQueue = [];
|
$app.data.printQueue = [];
|
||||||
$app.data.printQueueWorker = null;
|
$app.data.printQueueWorker = null;
|
||||||
|
|||||||
+39
-15
@@ -260,6 +260,10 @@ export default class extends baseClass {
|
|||||||
this.processScreenshot(gameLog.screenshotPath);
|
this.processScreenshot(gameLog.screenshotPath);
|
||||||
break;
|
break;
|
||||||
case 'api-request':
|
case 'api-request':
|
||||||
|
if ($app.debugWebRequests) {
|
||||||
|
console.log('API Request:', gameLog.url);
|
||||||
|
}
|
||||||
|
|
||||||
// var userId = '';
|
// var userId = '';
|
||||||
// try {
|
// try {
|
||||||
// var url = new URL(gameLog.url);
|
// var url = new URL(gameLog.url);
|
||||||
@@ -277,23 +281,43 @@ export default class extends baseClass {
|
|||||||
// break;
|
// break;
|
||||||
// }
|
// }
|
||||||
|
|
||||||
if (!$app.saveInstancePrints) {
|
if ($app.saveInstanceEmoji) {
|
||||||
break;
|
try {
|
||||||
|
// https://api.vrchat.cloud/api/1/inventory/spawn?id=inv_75781d65-92fe-4a80-a1ff-27ee6e843b08
|
||||||
|
const url = new URL(gameLog.url);
|
||||||
|
if (
|
||||||
|
url.pathname.substring(0, 22) ===
|
||||||
|
'/api/1/inventory/spawn'
|
||||||
|
) {
|
||||||
|
const inventoryId = url.searchParams.get('id');
|
||||||
|
if (inventoryId && inventoryId.length === 40) {
|
||||||
|
$app.queueCheckInstanceInventory(
|
||||||
|
inventoryId
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} catch (err) {
|
||||||
|
console.error(err);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
try {
|
|
||||||
var printId = '';
|
if ($app.saveInstancePrints) {
|
||||||
var url = new URL(gameLog.url);
|
try {
|
||||||
if (
|
let printId = '';
|
||||||
url.pathname.substring(0, 14) === '/api/1/prints/'
|
const url1 = new URL(gameLog.url);
|
||||||
) {
|
if (
|
||||||
var pathArray = url.pathname.split('/');
|
url1.pathname.substring(0, 14) ===
|
||||||
printId = pathArray[4];
|
'/api/1/prints/'
|
||||||
|
) {
|
||||||
|
const pathArray = url1.pathname.split('/');
|
||||||
|
printId = pathArray[4];
|
||||||
|
}
|
||||||
|
if (printId && printId.length === 41) {
|
||||||
|
$app.queueSavePrintToFile(printId);
|
||||||
|
}
|
||||||
|
} catch (err) {
|
||||||
|
console.error(err);
|
||||||
}
|
}
|
||||||
if (printId && printId.length === 41) {
|
|
||||||
$app.queueSavePrintToFile(printId);
|
|
||||||
}
|
|
||||||
} catch (err) {
|
|
||||||
console.error(err);
|
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case 'avatar-change':
|
case 'avatar-change':
|
||||||
|
|||||||
@@ -162,7 +162,7 @@
|
|||||||
<span>{{ t('dialog.gallery_icons.recommended_image_size') }}: 1024x1024px (1:1)</span>
|
<span>{{ t('dialog.gallery_icons.recommended_image_size') }}: 1024x1024px (1:1)</span>
|
||||||
<br />
|
<br />
|
||||||
<br />
|
<br />
|
||||||
<div style="display: flex; align-items: center">
|
<div>
|
||||||
<el-button-group style="margin-right: 10px">
|
<el-button-group style="margin-right: 10px">
|
||||||
<el-button type="default" size="small" @click="refreshEmojiTable" icon="el-icon-refresh">
|
<el-button type="default" size="small" @click="refreshEmojiTable" icon="el-icon-refresh">
|
||||||
{{ t('dialog.gallery_icons.refresh') }}
|
{{ t('dialog.gallery_icons.refresh') }}
|
||||||
@@ -237,7 +237,7 @@
|
|||||||
@click="
|
@click="
|
||||||
showFullscreenImageDialog(
|
showFullscreenImageDialog(
|
||||||
image.versions[image.versions.length - 1].file.url,
|
image.versions[image.versions.length - 1].file.url,
|
||||||
getEmojiFileName(image)
|
getEmojiName(image)
|
||||||
)
|
)
|
||||||
">
|
">
|
||||||
<template v-if="image.frames">
|
<template v-if="image.frames">
|
||||||
@@ -271,7 +271,7 @@
|
|||||||
@click="
|
@click="
|
||||||
showFullscreenImageDialog(
|
showFullscreenImageDialog(
|
||||||
image.versions[image.versions.length - 1].file.url,
|
image.versions[image.versions.length - 1].file.url,
|
||||||
getEmojiFileName(image)
|
getEmojiName(image)
|
||||||
)
|
)
|
||||||
"
|
"
|
||||||
size="mini"
|
size="mini"
|
||||||
@@ -489,6 +489,7 @@
|
|||||||
@click="consumeInventoryBundle(item.id)"
|
@click="consumeInventoryBundle(item.id)"
|
||||||
size="mini"
|
size="mini"
|
||||||
icon="el-icon-plus"
|
icon="el-icon-plus"
|
||||||
|
style="float: right"
|
||||||
circle>
|
circle>
|
||||||
{{ t('dialog.gallery_icons.consume_bundle') }}
|
{{ t('dialog.gallery_icons.consume_bundle') }}
|
||||||
</el-button>
|
</el-button>
|
||||||
@@ -504,7 +505,7 @@
|
|||||||
import { inventoryRequest, miscRequest, userRequest, vrcPlusIconRequest, vrcPlusImageRequest } from '../../api';
|
import { inventoryRequest, miscRequest, userRequest, vrcPlusIconRequest, vrcPlusImageRequest } from '../../api';
|
||||||
import { extractFileId } from '../../composables/shared/utils';
|
import { extractFileId } from '../../composables/shared/utils';
|
||||||
import { emojiAnimationStyleList, emojiAnimationStyleUrl } from '../../composables/user/constants/emoji';
|
import { emojiAnimationStyleList, emojiAnimationStyleUrl } from '../../composables/user/constants/emoji';
|
||||||
import { getPrintFileName } from '../../composables/user/utils';
|
import { getPrintFileName, getEmojiFileName } from '../../composables/user/utils';
|
||||||
import Location from '../Location.vue';
|
import Location from '../Location.vue';
|
||||||
|
|
||||||
const { t } = useI18n();
|
const { t } = useI18n();
|
||||||
@@ -822,7 +823,7 @@
|
|||||||
emojiAnimFps.value = parseInt(value.replace('fps', ''));
|
emojiAnimFps.value = parseInt(value.replace('fps', ''));
|
||||||
}
|
}
|
||||||
if (value.endsWith('loopStyle')) {
|
if (value.endsWith('loopStyle')) {
|
||||||
emojiAnimLoopPingPong.value = value === 'pingpong';
|
emojiAnimLoopPingPong.value = value.replace('loopStyle', '').toLowerCase() === 'pingpong';
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -891,13 +892,8 @@
|
|||||||
document.getElementById('EmojiUploadButton').click();
|
document.getElementById('EmojiUploadButton').click();
|
||||||
}
|
}
|
||||||
|
|
||||||
function getEmojiFileName(emoji) {
|
function getEmojiName(emoji) {
|
||||||
if (emoji.frames) {
|
getEmojiFileName(emoji);
|
||||||
const 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`;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
function generateEmojiStyle(url, fps, frameCount, loopStyle) {
|
function generateEmojiStyle(url, fps, frameCount, loopStyle) {
|
||||||
|
|||||||
@@ -35,6 +35,15 @@ function getPrintFileName(print) {
|
|||||||
return fileName;
|
return fileName;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function getEmojiFileName(emoji) {
|
||||||
|
if (emoji.frames) {
|
||||||
|
const 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`;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
function getPrintLocalDate(print) {
|
function getPrintLocalDate(print) {
|
||||||
if (print.createdAt) {
|
if (print.createdAt) {
|
||||||
const createdAt = new Date(print.createdAt);
|
const createdAt = new Date(print.createdAt);
|
||||||
@@ -75,5 +84,6 @@ export {
|
|||||||
languageClass,
|
languageClass,
|
||||||
getPrintFileName,
|
getPrintFileName,
|
||||||
getPrintLocalDate,
|
getPrintLocalDate,
|
||||||
|
getEmojiFileName,
|
||||||
isFriendOnline
|
isFriendOnline
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -568,6 +568,10 @@
|
|||||||
"header": "Save Instance Stickers To File",
|
"header": "Save Instance Stickers To File",
|
||||||
"description": "Save placed stickers to your VRChat Pictures folder"
|
"description": "Save placed stickers to your VRChat Pictures folder"
|
||||||
},
|
},
|
||||||
|
"save_instance_emoji_to_file": {
|
||||||
|
"header": "Save Instance Emoji To File",
|
||||||
|
"description": "Save spawned emoji to your VRChat Pictures folder"
|
||||||
|
},
|
||||||
"remote_database": {
|
"remote_database": {
|
||||||
"header": "Remote Avatar Database",
|
"header": "Remote Avatar Database",
|
||||||
"enable": "Enable",
|
"enable": "Enable",
|
||||||
|
|||||||
@@ -871,6 +871,18 @@ mixin settingsTab
|
|||||||
:value='saveInstanceStickers'
|
:value='saveInstanceStickers'
|
||||||
@change='saveVRCXWindowOption("VRCX_saveInstanceStickers")'
|
@change='saveVRCXWindowOption("VRCX_saveInstanceStickers")'
|
||||||
:long-label='true')
|
:long-label='true')
|
||||||
|
br
|
||||||
|
span.sub-header {{ $t('view.settings.advanced.advanced.save_instance_emoji_to_file.header') }}
|
||||||
|
el-tooltip(
|
||||||
|
placement='top'
|
||||||
|
style='margin-left: 5px'
|
||||||
|
:content='$t("view.settings.advanced.advanced.save_instance_prints_to_file.header_tooltip")')
|
||||||
|
i.el-icon-info
|
||||||
|
simple-switch(
|
||||||
|
:label='$t("view.settings.advanced.advanced.save_instance_emoji_to_file.description")'
|
||||||
|
:value='saveInstanceEmoji'
|
||||||
|
@change='saveVRCXWindowOption("VRCX_saveInstanceEmoji")'
|
||||||
|
:long-label='true')
|
||||||
|
|
||||||
//- "Advanced" Tab
|
//- "Advanced" Tab
|
||||||
el-tab-pane(lazy :label='$t("view.settings.category.advanced")')
|
el-tab-pane(lazy :label='$t("view.settings.category.advanced")')
|
||||||
|
|||||||
Reference in New Issue
Block a user