mirror of
https://github.com/MrUnknownDE/VRCX.git
synced 2026-05-05 22:36:05 +02:00
split function in the store
This commit is contained in:
@@ -8,37 +8,36 @@ import dayjs from 'dayjs';
|
|||||||
|
|
||||||
import {
|
import {
|
||||||
compareGameLogRows,
|
compareGameLogRows,
|
||||||
convertYoutubeTime,
|
|
||||||
findUserByDisplayName,
|
findUserByDisplayName,
|
||||||
formatSeconds,
|
formatSeconds,
|
||||||
gameLogSearchFilter,
|
gameLogSearchFilter,
|
||||||
getGroupName,
|
getGroupName,
|
||||||
isRpcWorld,
|
|
||||||
parseLocation,
|
parseLocation,
|
||||||
replaceBioSymbols
|
replaceBioSymbols
|
||||||
} from '../shared/utils';
|
} from '../../shared/utils';
|
||||||
import { AppDebug } from '../service/appConfig';
|
import { AppDebug } from '../../service/appConfig';
|
||||||
import { database } from '../service/database';
|
import { createMediaParsers } from './mediaParsers';
|
||||||
import { useAdvancedSettingsStore } from './settings/advanced';
|
import { database } from '../../service/database';
|
||||||
import { useFriendStore } from './friend';
|
import { useAdvancedSettingsStore } from '../settings/advanced';
|
||||||
import { useGalleryStore } from './gallery';
|
import { useFriendStore } from '../friend';
|
||||||
import { useGameStore } from './game';
|
import { useGalleryStore } from '../gallery';
|
||||||
import { useGeneralSettingsStore } from './settings/general';
|
import { useGameStore } from '../game';
|
||||||
import { useInstanceStore } from './instance';
|
import { useGeneralSettingsStore } from '../settings/general';
|
||||||
import { useLocationStore } from './location';
|
import { useInstanceStore } from '../instance';
|
||||||
import { useModalStore } from './modal';
|
import { useLocationStore } from '../location';
|
||||||
import { useNotificationStore } from './notification';
|
import { useModalStore } from '../modal';
|
||||||
import { usePhotonStore } from './photon';
|
import { useNotificationStore } from '../notification';
|
||||||
import { useSharedFeedStore } from './sharedFeed';
|
import { usePhotonStore } from '../photon';
|
||||||
import { useUiStore } from './ui';
|
import { useSharedFeedStore } from '../sharedFeed';
|
||||||
import { useUserStore } from './user';
|
import { useUiStore } from '../ui';
|
||||||
import { useVrStore } from './vr';
|
import { useUserStore } from '../user';
|
||||||
import { useVrcxStore } from './vrcx';
|
import { useVrStore } from '../vr';
|
||||||
import { userRequest } from '../api';
|
import { useVrcxStore } from '../vrcx';
|
||||||
import { watchState } from '../service/watchState';
|
import { userRequest } from '../../api';
|
||||||
|
import { watchState } from '../../service/watchState';
|
||||||
|
|
||||||
import configRepository from '../service/config';
|
import configRepository from '../../service/config';
|
||||||
import gameLogService from '../service/gamelog.js';
|
import gameLogService from '../../service/gamelog.js';
|
||||||
|
|
||||||
import * as workerTimers from 'worker-timers';
|
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() {
|
function updateNowPlaying() {
|
||||||
const np = nowPlaying.value;
|
const np = nowPlaying.value;
|
||||||
if (!nowPlaying.value.playing) {
|
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() {
|
async function getGameLogTable() {
|
||||||
await database.initTables();
|
await database.initTables();
|
||||||
const dateTill = await database.getLastDateGameLogDatabase();
|
const dateTill = await database.getLastDateGameLogDatabase();
|
||||||
@@ -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
|
||||||
|
};
|
||||||
|
}
|
||||||
@@ -10,50 +10,49 @@ import {
|
|||||||
checkCanInvite,
|
checkCanInvite,
|
||||||
escapeTag,
|
escapeTag,
|
||||||
executeWithBackoff,
|
executeWithBackoff,
|
||||||
extractFileId,
|
|
||||||
extractFileVersion,
|
|
||||||
findUserByDisplayName,
|
findUserByDisplayName,
|
||||||
getUserMemo,
|
getUserMemo,
|
||||||
parseLocation,
|
parseLocation,
|
||||||
removeFromArray,
|
removeFromArray,
|
||||||
replaceBioSymbols
|
replaceBioSymbols
|
||||||
} from '../shared/utils';
|
} from '../../shared/utils';
|
||||||
import {
|
import {
|
||||||
friendRequest,
|
friendRequest,
|
||||||
instanceRequest,
|
instanceRequest,
|
||||||
notificationRequest,
|
notificationRequest,
|
||||||
userRequest,
|
userRequest,
|
||||||
worldRequest
|
worldRequest
|
||||||
} from '../api';
|
} from '../../api';
|
||||||
import {
|
import {
|
||||||
getNotificationMessage,
|
getNotificationMessage,
|
||||||
getUserIdFromNoty as getUserIdFromNotyBase,
|
getUserIdFromNoty as getUserIdFromNotyBase,
|
||||||
toNotificationText
|
toNotificationText
|
||||||
} from '../shared/notificationMessage';
|
} from '../../shared/notificationMessage';
|
||||||
import { database, dbVars } from '../service/database';
|
import { database, dbVars } from '../../service/database';
|
||||||
import {
|
import {
|
||||||
getNotificationCategory,
|
getNotificationCategory,
|
||||||
getNotificationTs
|
getNotificationTs
|
||||||
} from '../shared/notificationCategory';
|
} from '../../shared/notificationCategory';
|
||||||
import { AppDebug } from '../service/appConfig';
|
import { AppDebug } from '../../service/appConfig';
|
||||||
import { useAdvancedSettingsStore } from './settings/advanced';
|
import { createOverlayDispatch } from './overlayDispatch';
|
||||||
import { useAppearanceSettingsStore } from './settings/appearance';
|
import { useAdvancedSettingsStore } from '../settings/advanced';
|
||||||
import { useFavoriteStore } from './favorite';
|
import { useAppearanceSettingsStore } from '../settings/appearance';
|
||||||
import { useFriendStore } from './friend';
|
import { useFavoriteStore } from '../favorite';
|
||||||
import { useGameStore } from './game';
|
import { useFriendStore } from '../friend';
|
||||||
import { useGeneralSettingsStore } from './settings/general';
|
import { useGameStore } from '../game';
|
||||||
import { useGroupStore } from './group';
|
import { useGeneralSettingsStore } from '../settings/general';
|
||||||
import { useInstanceStore } from './instance';
|
import { useGroupStore } from '../group';
|
||||||
import { useLocationStore } from './location';
|
import { useInstanceStore } from '../instance';
|
||||||
import { useModalStore } from './modal';
|
import { useLocationStore } from '../location';
|
||||||
import { useNotificationsSettingsStore } from './settings/notifications';
|
import { useModalStore } from '../modal';
|
||||||
import { useSharedFeedStore } from './sharedFeed';
|
import { useNotificationsSettingsStore } from '../settings/notifications';
|
||||||
import { useUiStore } from './ui';
|
import { useSharedFeedStore } from '../sharedFeed';
|
||||||
import { useUserStore } from './user';
|
import { useUiStore } from '../ui';
|
||||||
import { useWristOverlaySettingsStore } from './settings/wristOverlay';
|
import { useUserStore } from '../user';
|
||||||
import { watchState } from '../service/watchState';
|
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', () => {
|
export const useNotificationStore = defineStore('Notification', () => {
|
||||||
const { t } = useI18n();
|
const { t } = useI18n();
|
||||||
@@ -977,113 +976,22 @@ export const useNotificationStore = defineStore('Notification', () => {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
const {
|
||||||
*
|
notySaveImage,
|
||||||
* @param {object} noty
|
displayDesktopToast,
|
||||||
* @returns
|
displayOverlayNotification,
|
||||||
*/
|
displayXSNotification,
|
||||||
async function notySaveImage(noty) {
|
displayOvrtNotification
|
||||||
const imageUrl = await notyGetImage(noty);
|
} = createOverlayDispatch({
|
||||||
let fileId = extractFileId(imageUrl);
|
getUserIdFromNoty,
|
||||||
let fileVersion = extractFileVersion(imageUrl);
|
userRequest,
|
||||||
let imageLocation = '';
|
notificationsSettingsStore,
|
||||||
try {
|
advancedSettingsStore,
|
||||||
if (fileId && fileVersion) {
|
appearanceSettingsStore
|
||||||
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) {
|
// Overlay dispatch functions (notySaveImage, displayDesktopToast, etc.)
|
||||||
const result = getNotificationMessage(noty, message);
|
// are in ./overlayDispatch.js — destructured above via createOverlayDispatch().
|
||||||
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
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
*
|
*
|
||||||
@@ -1102,63 +1010,6 @@ export const useNotificationStore = defineStore('Notification', () => {
|
|||||||
return '';
|
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) {
|
function queueGameLogNoty(gamelog) {
|
||||||
const noty = structuredClone(gamelog);
|
const noty = structuredClone(gamelog);
|
||||||
let bias;
|
let bias;
|
||||||
@@ -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
|
||||||
|
};
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user