split function in the store

This commit is contained in:
pa
2026-03-04 21:41:29 +09:00
parent 4a72d77a96
commit c522ab21f1
4 changed files with 691 additions and 593 deletions

View File

@@ -8,37 +8,36 @@ import dayjs from 'dayjs';
import {
compareGameLogRows,
convertYoutubeTime,
findUserByDisplayName,
formatSeconds,
gameLogSearchFilter,
getGroupName,
isRpcWorld,
parseLocation,
replaceBioSymbols
} from '../shared/utils';
import { AppDebug } from '../service/appConfig';
import { database } from '../service/database';
import { useAdvancedSettingsStore } from './settings/advanced';
import { useFriendStore } from './friend';
import { useGalleryStore } from './gallery';
import { useGameStore } from './game';
import { useGeneralSettingsStore } from './settings/general';
import { useInstanceStore } from './instance';
import { useLocationStore } from './location';
import { useModalStore } from './modal';
import { useNotificationStore } from './notification';
import { usePhotonStore } from './photon';
import { useSharedFeedStore } from './sharedFeed';
import { useUiStore } from './ui';
import { useUserStore } from './user';
import { useVrStore } from './vr';
import { useVrcxStore } from './vrcx';
import { userRequest } from '../api';
import { watchState } from '../service/watchState';
} from '../../shared/utils';
import { AppDebug } from '../../service/appConfig';
import { createMediaParsers } from './mediaParsers';
import { database } from '../../service/database';
import { useAdvancedSettingsStore } from '../settings/advanced';
import { useFriendStore } from '../friend';
import { useGalleryStore } from '../gallery';
import { useGameStore } from '../game';
import { useGeneralSettingsStore } from '../settings/general';
import { useInstanceStore } from '../instance';
import { useLocationStore } from '../location';
import { useModalStore } from '../modal';
import { useNotificationStore } from '../notification';
import { usePhotonStore } from '../photon';
import { useSharedFeedStore } from '../sharedFeed';
import { useUiStore } from '../ui';
import { useUserStore } from '../user';
import { useVrStore } from '../vr';
import { useVrcxStore } from '../vrcx';
import { userRequest } from '../../api';
import { watchState } from '../../service/watchState';
import configRepository from '../service/config';
import gameLogService from '../service/gamelog.js';
import configRepository from '../../service/config';
import gameLogService from '../../service/gamelog.js';
import * as workerTimers from 'worker-timers';
@@ -243,6 +242,21 @@ export const useGameLogStore = defineStore('GameLog', () => {
}
}
const {
addGameLogVideo,
addGameLogPyPyDance,
addGameLogVRDancing,
addGameLogZuwaZuwaDance,
addGameLogLSMedia,
addGameLogPopcornPalace
} = createMediaParsers({
nowPlaying,
setNowPlaying,
clearNowPlaying,
userStore,
advancedSettingsStore
});
function updateNowPlaying() {
const np = nowPlaying.value;
if (!nowPlaying.value.playing) {
@@ -888,387 +902,6 @@ export const useGameLogStore = defineStore('GameLog', () => {
}
}
async function addGameLogVideo(gameLog, location, userId) {
let url;
const videoUrl = gameLog.videoUrl;
let youtubeVideoId = '';
let videoId = '';
let videoName = '';
let videoLength = 0;
let displayName = '';
let videoPos = 8; // video loading delay
if (typeof gameLog.displayName !== 'undefined') {
displayName = gameLog.displayName;
}
if (typeof gameLog.videoPos !== 'undefined') {
videoPos = gameLog.videoPos;
}
if (!isRpcWorld(location) || gameLog.videoId === 'YouTube') {
// skip PyPyDance and VRDancing videos
try {
url = new URL(videoUrl);
if (
url.origin === 'https://t-ne.x0.to' ||
url.origin === 'https://nextnex.com' ||
url.origin === 'https://r.0cm.org'
) {
url = new URL(url.searchParams.get('url'));
}
if (videoUrl.startsWith('https://u2b.cx/')) {
url = new URL(videoUrl.substring(15));
}
const id1 = url.pathname;
const id2 = url.searchParams.get('v');
if (id1 && id1.length === 12) {
// https://youtu.be/
youtubeVideoId = id1.substring(1, 12);
}
if (id1 && id1.length === 19) {
// https://www.youtube.com/shorts/
youtubeVideoId = id1.substring(8, 19);
}
if (id2 && id2.length === 11) {
// https://www.youtube.com/watch?v=
// https://music.youtube.com/watch?v=
youtubeVideoId = id2;
}
if (advancedSettingsStore.youTubeApi && youtubeVideoId) {
const data =
await advancedSettingsStore.lookupYouTubeVideo(
youtubeVideoId
);
if (data || data.pageInfo.totalResults !== 0) {
videoId = 'YouTube';
videoName = data.items[0].snippet.title;
videoLength = convertYoutubeTime(
data.items[0].contentDetails.duration
);
}
}
} catch {
console.error(`Invalid URL: ${url}`);
}
const entry = {
created_at: gameLog.dt,
type: 'VideoPlay',
videoUrl,
videoId,
videoName,
videoLength,
location,
displayName,
userId,
videoPos
};
setNowPlaying(entry);
}
}
function addGameLogPyPyDance(gameLog, location) {
const data =
/VideoPlay\(PyPyDance\) "(.+?)",([\d.]+),([\d.]+),"(.*)"/g.exec(
gameLog.data
);
if (!data) {
console.error('failed to parse', gameLog.data);
return;
}
const videoUrl = data[1];
const videoPos = Number(data[2]);
const videoLength = Number(data[3]);
const title = data[4];
const bracketArray = title.split('(');
const text1 = bracketArray.pop();
let displayName = text1.slice(0, -1);
let text2 = bracketArray.join('(');
let videoId = '';
if (text2 === 'Custom URL') {
videoId = 'YouTube';
} else {
videoId = text2.substr(0, text2.indexOf(':') - 1);
text2 = text2.substr(text2.indexOf(':') + 2);
}
const videoName = text2.slice(0, -1);
if (displayName === 'Random') {
displayName = '';
}
if (videoUrl === nowPlaying.value.url) {
const entry = {
updatedAt: gameLog.dt,
videoUrl,
videoLength,
videoPos
};
setNowPlaying(entry);
return;
}
let userId = '';
if (displayName) {
userId =
findUserByDisplayName(userStore.cachedUsers, displayName)?.id ??
'';
}
if (videoId === 'YouTube') {
const entry1 = {
dt: gameLog.dt,
videoUrl,
displayName,
videoPos,
videoId
};
addGameLogVideo(entry1, location, userId);
} else {
const entry2 = {
created_at: gameLog.dt,
type: 'VideoPlay',
videoUrl,
videoId,
videoName,
videoLength,
location,
displayName,
userId,
videoPos
};
setNowPlaying(entry2);
}
}
function addGameLogVRDancing(gameLog, location) {
const data =
/VideoPlay\(VRDancing\) "(.+?)",([\d.]+),([\d.]+),(-?[\d.]+),"(.+?)","(.+?)"/g.exec(
gameLog.data
);
if (!data) {
console.error('failed to parse', gameLog.data);
return;
}
const videoUrl = data[1];
let videoPos = Number(data[2]);
const videoLength = Number(data[3]);
let videoId = data[4];
const displayName = data[5];
let videoName = data[6];
if (videoId === '-1') {
videoId = 'YouTube';
}
const videoNameIndex = videoName.indexOf(']</b> ');
if (videoNameIndex !== -1) {
videoName = videoName.substring(videoNameIndex + 6);
}
if (videoPos === videoLength) {
// ummm okay
videoPos = 0;
}
if (videoUrl === nowPlaying.value.url) {
const entry = {
updatedAt: gameLog.dt,
videoUrl,
videoLength,
videoPos
};
setNowPlaying(entry);
return;
}
let userId = '';
if (displayName) {
userId =
findUserByDisplayName(userStore.cachedUsers, displayName)?.id ??
'';
}
if (videoId === 'YouTube') {
const entry1 = {
dt: gameLog.dt,
videoUrl,
displayName,
videoPos,
videoId
};
addGameLogVideo(entry1, location, userId);
} else {
const entry2 = {
created_at: gameLog.dt,
type: 'VideoPlay',
videoUrl,
videoId,
videoName,
videoLength,
location,
displayName,
userId,
videoPos
};
setNowPlaying(entry2);
}
}
function addGameLogZuwaZuwaDance(gameLog, location) {
const data =
/VideoPlay\(ZuwaZuwaDance\) "(.+?)",([\d.]+),([\d.]+),(-?[\d.]+),"(.+?)","(.+?)"/g.exec(
gameLog.data
);
if (!data) {
console.error('failed to parse', gameLog.data);
return;
}
const videoUrl = data[1];
const videoPos = Number(data[2]);
const videoLength = Number(data[3]);
let videoId = data[4];
let displayName = data[5];
const videoName = data[6];
if (displayName === 'Random') {
displayName = '';
}
if (videoId === '9999') {
videoId = 'YouTube';
}
if (videoUrl === nowPlaying.value.url) {
const entry = {
updatedAt: gameLog.dt,
videoUrl,
videoLength,
videoPos
};
setNowPlaying(entry);
return;
}
let userId = '';
if (displayName) {
userId =
findUserByDisplayName(userStore.cachedUsers, displayName)?.id ??
'';
}
if (videoId === 'YouTube') {
const entry1 = {
dt: gameLog.dt,
videoUrl,
displayName,
videoPos,
videoId
};
addGameLogVideo(entry1, location, userId);
} else {
const entry2 = {
created_at: gameLog.dt,
type: 'VideoPlay',
videoUrl,
videoId,
videoName,
videoLength,
location,
displayName,
userId,
videoPos
};
setNowPlaying(entry2);
}
}
function addGameLogLSMedia(gameLog, location) {
// [VRCX] LSMedia 0,4268.981,Natsumi-sama,,
// [VRCX] LSMedia 0,6298.292,Natsumi-sama,The Outfit (2022), 1080p
const data = /LSMedia ([\d.]+),([\d.]+),(.+?),(.+?),(?=[^,]*$)/g.exec(
gameLog.data
);
if (!data) {
return;
}
const videoPos = Number(data[1]);
const videoLength = Number(data[2]);
const displayName = data[3];
const videoName = replaceBioSymbols(data[4]);
const videoUrl = videoName;
const videoId = 'LSMedia';
if (videoUrl === nowPlaying.value.url) {
const entry = {
updatedAt: gameLog.dt,
videoUrl,
videoLength,
videoPos
};
setNowPlaying(entry);
return;
}
let userId = '';
if (displayName) {
userId =
findUserByDisplayName(userStore.cachedUsers, displayName)?.id ??
'';
}
const entry1 = {
created_at: gameLog.dt,
type: 'VideoPlay',
videoUrl,
videoId,
videoName,
videoLength,
location,
displayName,
userId,
videoPos
};
setNowPlaying(entry1);
}
function addGameLogPopcornPalace(gameLog, location) {
// [VRCX] VideoPlay(PopcornPalace) {"videoName": "How to Train Your Dragon - 2025-06-06", "videoPos": 37.28777, "videoLength": 11474.05, "thumbnailUrl": "", "displayName": "miner28_3", "isPaused": false, "is3D": false, "looping": false}
let data = gameLog.data;
if (!data) {
return;
}
try {
const j = data.indexOf('{');
data = JSON.parse(data.substring(j));
} catch (err) {
console.error('Failed to parse PopcornPalace data:', err);
return;
}
const videoPos = Number(data.videoPos);
const videoLength = Number(data.videoLength);
const displayName = data.displayName || '';
const videoName = data.videoName || '';
const videoUrl = videoName;
const videoId = 'PopcornPalace';
const thumbnailUrl = data.thumbnailUrl || '';
if (!videoName) {
clearNowPlaying();
return;
}
if (videoUrl === nowPlaying.value.url) {
const entry = {
updatedAt: gameLog.dt,
videoUrl,
videoLength,
videoPos,
thumbnailUrl
};
setNowPlaying(entry);
return;
}
let userId = '';
if (displayName) {
userId =
findUserByDisplayName(userStore.cachedUsers, displayName)?.id ??
'';
}
const entry1 = {
created_at: gameLog.dt,
type: 'VideoPlay',
videoUrl,
videoId,
videoName,
videoLength,
location,
displayName,
userId,
videoPos,
thumbnailUrl
};
setNowPlaying(entry1);
}
async function getGameLogTable() {
await database.initTables();
const dateTill = await database.getLastDateGameLogDatabase();

View File

@@ -0,0 +1,415 @@
import {
convertYoutubeTime,
findUserByDisplayName,
isRpcWorld,
replaceBioSymbols
} from '../../shared/utils';
/**
* Creates the media parser functions for the GameLog store.
*
* @param {object} deps
* @param {import('vue').Ref} deps.nowPlaying
* @param {Function} deps.setNowPlaying
* @param {Function} deps.clearNowPlaying
* @param {object} deps.userStore needs `.cachedUsers`
* @param {object} deps.advancedSettingsStore needs `.youTubeApi`, `.lookupYouTubeVideo()`
* @returns {object} The media parser functions
*/
export function createMediaParsers({
nowPlaying,
setNowPlaying,
clearNowPlaying,
userStore,
advancedSettingsStore
}) {
async function addGameLogVideo(gameLog, location, userId) {
let url;
const videoUrl = gameLog.videoUrl;
let youtubeVideoId = '';
let videoId = '';
let videoName = '';
let videoLength = 0;
let displayName = '';
let videoPos = 8; // video loading delay
if (typeof gameLog.displayName !== 'undefined') {
displayName = gameLog.displayName;
}
if (typeof gameLog.videoPos !== 'undefined') {
videoPos = gameLog.videoPos;
}
if (!isRpcWorld(location) || gameLog.videoId === 'YouTube') {
// skip PyPyDance and VRDancing videos
try {
url = new URL(videoUrl);
if (
url.origin === 'https://t-ne.x0.to' ||
url.origin === 'https://nextnex.com' ||
url.origin === 'https://r.0cm.org'
) {
url = new URL(url.searchParams.get('url'));
}
if (videoUrl.startsWith('https://u2b.cx/')) {
url = new URL(videoUrl.substring(15));
}
const id1 = url.pathname;
const id2 = url.searchParams.get('v');
if (id1 && id1.length === 12) {
// https://youtu.be/
youtubeVideoId = id1.substring(1, 12);
}
if (id1 && id1.length === 19) {
// https://www.youtube.com/shorts/
youtubeVideoId = id1.substring(8, 19);
}
if (id2 && id2.length === 11) {
// https://www.youtube.com/watch?v=
// https://music.youtube.com/watch?v=
youtubeVideoId = id2;
}
if (advancedSettingsStore.youTubeApi && youtubeVideoId) {
const data =
await advancedSettingsStore.lookupYouTubeVideo(
youtubeVideoId
);
if (data || data.pageInfo.totalResults !== 0) {
videoId = 'YouTube';
videoName = data.items[0].snippet.title;
videoLength = convertYoutubeTime(
data.items[0].contentDetails.duration
);
}
}
} catch {
console.error(`Invalid URL: ${url}`);
}
const entry = {
created_at: gameLog.dt,
type: 'VideoPlay',
videoUrl,
videoId,
videoName,
videoLength,
location,
displayName,
userId,
videoPos
};
setNowPlaying(entry);
}
}
function addGameLogPyPyDance(gameLog, location) {
const data =
/VideoPlay\(PyPyDance\) "(.+?)",([\d.]+),([\d.]+),"(.*)"/g.exec(
gameLog.data
);
if (!data) {
console.error('failed to parse', gameLog.data);
return;
}
const videoUrl = data[1];
const videoPos = Number(data[2]);
const videoLength = Number(data[3]);
const title = data[4];
const bracketArray = title.split('(');
const text1 = bracketArray.pop();
let displayName = text1.slice(0, -1);
let text2 = bracketArray.join('(');
let videoId = '';
if (text2 === 'Custom URL') {
videoId = 'YouTube';
} else {
videoId = text2.substr(0, text2.indexOf(':') - 1);
text2 = text2.substr(text2.indexOf(':') + 2);
}
const videoName = text2.slice(0, -1);
if (displayName === 'Random') {
displayName = '';
}
if (videoUrl === nowPlaying.value.url) {
const entry = {
updatedAt: gameLog.dt,
videoUrl,
videoLength,
videoPos
};
setNowPlaying(entry);
return;
}
let userId = '';
if (displayName) {
userId =
findUserByDisplayName(userStore.cachedUsers, displayName)?.id ??
'';
}
if (videoId === 'YouTube') {
const entry1 = {
dt: gameLog.dt,
videoUrl,
displayName,
videoPos,
videoId
};
addGameLogVideo(entry1, location, userId);
} else {
const entry2 = {
created_at: gameLog.dt,
type: 'VideoPlay',
videoUrl,
videoId,
videoName,
videoLength,
location,
displayName,
userId,
videoPos
};
setNowPlaying(entry2);
}
}
function addGameLogVRDancing(gameLog, location) {
const data =
/VideoPlay\(VRDancing\) "(.+?)",([\d.]+),([\d.]+),(-?[\d.]+),"(.+?)","(.+?)"/g.exec(
gameLog.data
);
if (!data) {
console.error('failed to parse', gameLog.data);
return;
}
const videoUrl = data[1];
let videoPos = Number(data[2]);
const videoLength = Number(data[3]);
let videoId = data[4];
const displayName = data[5];
let videoName = data[6];
if (videoId === '-1') {
videoId = 'YouTube';
}
const videoNameIndex = videoName.indexOf(']</b> ');
if (videoNameIndex !== -1) {
videoName = videoName.substring(videoNameIndex + 6);
}
if (videoPos === videoLength) {
// ummm okay
videoPos = 0;
}
if (videoUrl === nowPlaying.value.url) {
const entry = {
updatedAt: gameLog.dt,
videoUrl,
videoLength,
videoPos
};
setNowPlaying(entry);
return;
}
let userId = '';
if (displayName) {
userId =
findUserByDisplayName(userStore.cachedUsers, displayName)?.id ??
'';
}
if (videoId === 'YouTube') {
const entry1 = {
dt: gameLog.dt,
videoUrl,
displayName,
videoPos,
videoId
};
addGameLogVideo(entry1, location, userId);
} else {
const entry2 = {
created_at: gameLog.dt,
type: 'VideoPlay',
videoUrl,
videoId,
videoName,
videoLength,
location,
displayName,
userId,
videoPos
};
setNowPlaying(entry2);
}
}
function addGameLogZuwaZuwaDance(gameLog, location) {
const data =
/VideoPlay\(ZuwaZuwaDance\) "(.+?)",([\d.]+),([\d.]+),(-?[\d.]+),"(.+?)","(.+?)"/g.exec(
gameLog.data
);
if (!data) {
console.error('failed to parse', gameLog.data);
return;
}
const videoUrl = data[1];
const videoPos = Number(data[2]);
const videoLength = Number(data[3]);
let videoId = data[4];
let displayName = data[5];
const videoName = data[6];
if (displayName === 'Random') {
displayName = '';
}
if (videoId === '9999') {
videoId = 'YouTube';
}
if (videoUrl === nowPlaying.value.url) {
const entry = {
updatedAt: gameLog.dt,
videoUrl,
videoLength,
videoPos
};
setNowPlaying(entry);
return;
}
let userId = '';
if (displayName) {
userId =
findUserByDisplayName(userStore.cachedUsers, displayName)?.id ??
'';
}
if (videoId === 'YouTube') {
const entry1 = {
dt: gameLog.dt,
videoUrl,
displayName,
videoPos,
videoId
};
addGameLogVideo(entry1, location, userId);
} else {
const entry2 = {
created_at: gameLog.dt,
type: 'VideoPlay',
videoUrl,
videoId,
videoName,
videoLength,
location,
displayName,
userId,
videoPos
};
setNowPlaying(entry2);
}
}
function addGameLogLSMedia(gameLog, location) {
// [VRCX] LSMedia 0,4268.981,Natsumi-sama,,
// [VRCX] LSMedia 0,6298.292,Natsumi-sama,The Outfit (2022), 1080p
const data = /LSMedia ([\d.]+),([\d.]+),(.+?),(.+?),(?=[^,]*$)/g.exec(
gameLog.data
);
if (!data) {
return;
}
const videoPos = Number(data[1]);
const videoLength = Number(data[2]);
const displayName = data[3];
const videoName = replaceBioSymbols(data[4]);
const videoUrl = videoName;
const videoId = 'LSMedia';
if (videoUrl === nowPlaying.value.url) {
const entry = {
updatedAt: gameLog.dt,
videoUrl,
videoLength,
videoPos
};
setNowPlaying(entry);
return;
}
let userId = '';
if (displayName) {
userId =
findUserByDisplayName(userStore.cachedUsers, displayName)?.id ??
'';
}
const entry1 = {
created_at: gameLog.dt,
type: 'VideoPlay',
videoUrl,
videoId,
videoName,
videoLength,
location,
displayName,
userId,
videoPos
};
setNowPlaying(entry1);
}
function addGameLogPopcornPalace(gameLog, location) {
// [VRCX] VideoPlay(PopcornPalace) {"videoName": "How to Train Your Dragon - 2025-06-06", "videoPos": 37.28777, "videoLength": 11474.05, "thumbnailUrl": "", "displayName": "miner28_3", "isPaused": false, "is3D": false, "looping": false}
let data = gameLog.data;
if (!data) {
return;
}
try {
const j = data.indexOf('{');
data = JSON.parse(data.substring(j));
} catch (err) {
console.error('Failed to parse PopcornPalace data:', err);
return;
}
const videoPos = Number(data.videoPos);
const videoLength = Number(data.videoLength);
const displayName = data.displayName || '';
const videoName = data.videoName || '';
const videoUrl = videoName;
const videoId = 'PopcornPalace';
const thumbnailUrl = data.thumbnailUrl || '';
if (!videoName) {
clearNowPlaying();
return;
}
if (videoUrl === nowPlaying.value.url) {
const entry = {
updatedAt: gameLog.dt,
videoUrl,
videoLength,
videoPos,
thumbnailUrl
};
setNowPlaying(entry);
return;
}
let userId = '';
if (displayName) {
userId =
findUserByDisplayName(userStore.cachedUsers, displayName)?.id ??
'';
}
const entry1 = {
created_at: gameLog.dt,
type: 'VideoPlay',
videoUrl,
videoId,
videoName,
videoLength,
location,
displayName,
userId,
videoPos,
thumbnailUrl
};
setNowPlaying(entry1);
}
return {
addGameLogVideo,
addGameLogPyPyDance,
addGameLogVRDancing,
addGameLogZuwaZuwaDance,
addGameLogLSMedia,
addGameLogPopcornPalace
};
}

View File

@@ -10,50 +10,49 @@ import {
checkCanInvite,
escapeTag,
executeWithBackoff,
extractFileId,
extractFileVersion,
findUserByDisplayName,
getUserMemo,
parseLocation,
removeFromArray,
replaceBioSymbols
} from '../shared/utils';
} from '../../shared/utils';
import {
friendRequest,
instanceRequest,
notificationRequest,
userRequest,
worldRequest
} from '../api';
} from '../../api';
import {
getNotificationMessage,
getUserIdFromNoty as getUserIdFromNotyBase,
toNotificationText
} from '../shared/notificationMessage';
import { database, dbVars } from '../service/database';
} from '../../shared/notificationMessage';
import { database, dbVars } from '../../service/database';
import {
getNotificationCategory,
getNotificationTs
} from '../shared/notificationCategory';
import { AppDebug } from '../service/appConfig';
import { useAdvancedSettingsStore } from './settings/advanced';
import { useAppearanceSettingsStore } from './settings/appearance';
import { useFavoriteStore } from './favorite';
import { useFriendStore } from './friend';
import { useGameStore } from './game';
import { useGeneralSettingsStore } from './settings/general';
import { useGroupStore } from './group';
import { useInstanceStore } from './instance';
import { useLocationStore } from './location';
import { useModalStore } from './modal';
import { useNotificationsSettingsStore } from './settings/notifications';
import { useSharedFeedStore } from './sharedFeed';
import { useUiStore } from './ui';
import { useUserStore } from './user';
import { useWristOverlaySettingsStore } from './settings/wristOverlay';
import { watchState } from '../service/watchState';
} from '../../shared/notificationCategory';
import { AppDebug } from '../../service/appConfig';
import { createOverlayDispatch } from './overlayDispatch';
import { useAdvancedSettingsStore } from '../settings/advanced';
import { useAppearanceSettingsStore } from '../settings/appearance';
import { useFavoriteStore } from '../favorite';
import { useFriendStore } from '../friend';
import { useGameStore } from '../game';
import { useGeneralSettingsStore } from '../settings/general';
import { useGroupStore } from '../group';
import { useInstanceStore } from '../instance';
import { useLocationStore } from '../location';
import { useModalStore } from '../modal';
import { useNotificationsSettingsStore } from '../settings/notifications';
import { useSharedFeedStore } from '../sharedFeed';
import { useUiStore } from '../ui';
import { useUserStore } from '../user';
import { useWristOverlaySettingsStore } from '../settings/wristOverlay';
import { watchState } from '../../service/watchState';
import configRepository from '../service/config';
import configRepository from '../../service/config';
export const useNotificationStore = defineStore('Notification', () => {
const { t } = useI18n();
@@ -977,113 +976,22 @@ export const useNotificationStore = defineStore('Notification', () => {
}
}
/**
*
* @param {object} noty
* @returns
*/
async function notySaveImage(noty) {
const imageUrl = await notyGetImage(noty);
let fileId = extractFileId(imageUrl);
let fileVersion = extractFileVersion(imageUrl);
let imageLocation = '';
try {
if (fileId && fileVersion) {
imageLocation = await AppApi.GetImage(
imageUrl,
fileId,
fileVersion
);
} else if (imageUrl && imageUrl.startsWith('http')) {
fileVersion = imageUrl.split('/').pop(); // 1416226261.thumbnail-500.png
fileId = fileVersion.split('.').shift(); // 1416226261
imageLocation = await AppApi.GetImage(
imageUrl,
fileId,
fileVersion
);
}
} catch (err) {
console.error(imageUrl, err);
}
return imageLocation;
}
const {
notySaveImage,
displayDesktopToast,
displayOverlayNotification,
displayXSNotification,
displayOvrtNotification
} = createOverlayDispatch({
getUserIdFromNoty,
userRequest,
notificationsSettingsStore,
advancedSettingsStore,
appearanceSettingsStore
});
function displayDesktopToast(noty, message, image) {
const result = getNotificationMessage(noty, message);
if (result) {
desktopNotification(result.title, result.body, image);
}
}
/**
*
* @param {string} noty
* @param {string} message
* @param {string} imageFile
*/
function displayOverlayNotification(noty, message, imageFile) {
let image = '';
if (imageFile) {
image = `file:///${imageFile}`;
}
AppApi.ExecuteVrOverlayFunction(
'playNoty',
JSON.stringify({ noty, message, image })
);
}
/**
*
* @param {any} noty
* @param {string} message
* @param {string} image
*/
function displayXSNotification(noty, message, image) {
const result = getNotificationMessage(noty, message);
if (!result) return;
const timeout = Math.floor(
parseInt(
notificationsSettingsStore.notificationTimeout.toString(),
10
) / 1000
);
const opacity =
parseFloat(advancedSettingsStore.notificationOpacity.toString()) /
100;
const text = toNotificationText(result.title, result.body, noty.type);
AppApi.XSNotification('VRCX', text, timeout, opacity, image);
}
function displayOvrtNotification(
playOvrtHudNotifications,
playOvrtWristNotifications,
noty,
message,
image
) {
const result = getNotificationMessage(noty, message);
if (!result) return;
const timeout = Math.floor(
parseInt(
notificationsSettingsStore.notificationTimeout.toString(),
10
) / 1000
);
const opacity =
parseFloat(advancedSettingsStore.notificationOpacity.toString()) /
100;
const text = toNotificationText(result.title, result.body, noty.type);
AppApi.OVRTNotification(
playOvrtHudNotifications,
playOvrtWristNotifications,
'VRCX',
text,
timeout,
opacity,
image
);
}
// Overlay dispatch functions (notySaveImage, displayDesktopToast, etc.)
// are in ./overlayDispatch.js — destructured above via createOverlayDispatch().
/**
*
@@ -1102,63 +1010,6 @@ export const useNotificationStore = defineStore('Notification', () => {
return '';
}
/**
*
* @param {object} noty
* @returns
*/
async function notyGetImage(noty) {
let imageUrl = '';
const userId = getUserIdFromNoty(noty);
if (noty.thumbnailImageUrl) {
imageUrl = noty.thumbnailImageUrl;
} else if (noty.details && noty.details.imageUrl) {
imageUrl = noty.details.imageUrl;
} else if (noty.imageUrl) {
imageUrl = noty.imageUrl;
} else if (userId && !userId.startsWith('grp_')) {
imageUrl = await userRequest
.getCachedUser({
userId
})
.catch((err) => {
console.error(err);
return '';
})
.then((args) => {
if (!args.json) {
return '';
}
if (
appearanceSettingsStore.displayVRCPlusIconsAsAvatar &&
args.json.userIcon
) {
return args.json.userIcon;
}
if (args.json.profilePicOverride) {
return args.json.profilePicOverride;
}
return args.json.currentAvatarThumbnailImageUrl;
});
}
return imageUrl;
}
/**
*
* @param {string} displayName
* @param {string} message
* @param {string} image
*/
function desktopNotification(displayName, message, image) {
if (WINDOWS) {
AppApi.DesktopNotification(displayName, message, image);
} else {
window.electron.desktopNotification(displayName, message, image);
}
}
function queueGameLogNoty(gamelog) {
const noty = structuredClone(gamelog);
let bias;

View File

@@ -0,0 +1,199 @@
import { extractFileId, extractFileVersion } from '../../shared/utils';
import {
getNotificationMessage,
toNotificationText
} from '../../shared/notificationMessage';
/**
* Creates the overlay dispatch functions for the Notification store.
*
* @param {object} deps
* @param {Function} deps.getUserIdFromNoty
* @param {object} deps.userRequest
* @param {object} deps.notificationsSettingsStore
* @param {object} deps.advancedSettingsStore
* @param {object} deps.appearanceSettingsStore
* @returns {object} The overlay dispatch functions
*/
export function createOverlayDispatch({
getUserIdFromNoty,
userRequest,
notificationsSettingsStore,
advancedSettingsStore,
appearanceSettingsStore
}) {
/**
*
* @param {object} noty
* @returns
*/
async function notySaveImage(noty) {
const imageUrl = await notyGetImage(noty);
let fileId = extractFileId(imageUrl);
let fileVersion = extractFileVersion(imageUrl);
let imageLocation = '';
try {
if (fileId && fileVersion) {
imageLocation = await AppApi.GetImage(
imageUrl,
fileId,
fileVersion
);
} else if (imageUrl && imageUrl.startsWith('http')) {
fileVersion = imageUrl.split('/').pop(); // 1416226261.thumbnail-500.png
fileId = fileVersion.split('.').shift(); // 1416226261
imageLocation = await AppApi.GetImage(
imageUrl,
fileId,
fileVersion
);
}
} catch (err) {
console.error(imageUrl, err);
}
return imageLocation;
}
function displayDesktopToast(noty, message, image) {
const result = getNotificationMessage(noty, message);
if (result) {
desktopNotification(result.title, result.body, image);
}
}
/**
*
* @param {string} noty
* @param {string} message
* @param {string} imageFile
*/
function displayOverlayNotification(noty, message, imageFile) {
let image = '';
if (imageFile) {
image = `file:///${imageFile}`;
}
AppApi.ExecuteVrOverlayFunction(
'playNoty',
JSON.stringify({ noty, message, image })
);
}
/**
*
* @param {any} noty
* @param {string} message
* @param {string} image
*/
function displayXSNotification(noty, message, image) {
const result = getNotificationMessage(noty, message);
if (!result) return;
const timeout = Math.floor(
parseInt(
notificationsSettingsStore.notificationTimeout.toString(),
10
) / 1000
);
const opacity =
parseFloat(advancedSettingsStore.notificationOpacity.toString()) /
100;
const text = toNotificationText(result.title, result.body, noty.type);
AppApi.XSNotification('VRCX', text, timeout, opacity, image);
}
function displayOvrtNotification(
playOvrtHudNotifications,
playOvrtWristNotifications,
noty,
message,
image
) {
const result = getNotificationMessage(noty, message);
if (!result) return;
const timeout = Math.floor(
parseInt(
notificationsSettingsStore.notificationTimeout.toString(),
10
) / 1000
);
const opacity =
parseFloat(advancedSettingsStore.notificationOpacity.toString()) /
100;
const text = toNotificationText(result.title, result.body, noty.type);
AppApi.OVRTNotification(
playOvrtHudNotifications,
playOvrtWristNotifications,
'VRCX',
text,
timeout,
opacity,
image
);
}
/**
*
* @param {object} noty
* @returns
*/
async function notyGetImage(noty) {
let imageUrl = '';
const userId = getUserIdFromNoty(noty);
if (noty.thumbnailImageUrl) {
imageUrl = noty.thumbnailImageUrl;
} else if (noty.details && noty.details.imageUrl) {
imageUrl = noty.details.imageUrl;
} else if (noty.imageUrl) {
imageUrl = noty.imageUrl;
} else if (userId && !userId.startsWith('grp_')) {
imageUrl = await userRequest
.getCachedUser({
userId
})
.catch((err) => {
console.error(err);
return '';
})
.then((args) => {
if (!args.json) {
return '';
}
if (
appearanceSettingsStore.displayVRCPlusIconsAsAvatar &&
args.json.userIcon
) {
return args.json.userIcon;
}
if (args.json.profilePicOverride) {
return args.json.profilePicOverride;
}
return args.json.currentAvatarThumbnailImageUrl;
});
}
return imageUrl;
}
/**
*
* @param {string} displayName
* @param {string} message
* @param {string} image
*/
function desktopNotification(displayName, message, image) {
if (WINDOWS) {
AppApi.DesktopNotification(displayName, message, image);
} else {
window.electron.desktopNotification(displayName, message, image);
}
}
return {
notySaveImage,
displayDesktopToast,
displayOverlayNotification,
displayXSNotification,
displayOvrtNotification,
notyGetImage,
desktopNotification
};
}