Rewrite shared feed

This commit is contained in:
Natsumi
2026-01-17 11:44:09 +13:00
parent 56bf69f64e
commit 9f80d5e64a
22 changed files with 534 additions and 841 deletions
+2 -10
View File
@@ -174,14 +174,10 @@
groupName.value = props.grouphint; groupName.value = props.grouphint;
} else if (L.groupId) { } else if (L.groupId) {
groupName.value = L.groupId; groupName.value = L.groupId;
getGroupName(instanceId) getGroupName(instanceId).then((name) => {
.then((name) => {
if (!isDisposed && name && currentInstanceId() === L.tag) { if (!isDisposed && name && currentInstanceId() === L.tag) {
groupName.value = name; groupName.value = name;
} }
})
.catch((e) => {
console.error(e);
}); });
} }
region.value = ''; region.value = '';
@@ -217,8 +213,7 @@
} }
const ref = cachedWorlds.get(L.worldId); const ref = cachedWorlds.get(L.worldId);
if (typeof ref === 'undefined') { if (typeof ref === 'undefined') {
getWorldName(L.worldId) getWorldName(L.worldId).then((name) => {
.then((name) => {
if (!isDisposed && name && currentInstanceId() === L.tag) { if (!isDisposed && name && currentInstanceId() === L.tag) {
if (L.instanceId) { if (L.instanceId) {
text.value = `${name} · ${translateAccessType(L.accessTypeName)}`; text.value = `${name} · ${translateAccessType(L.accessTypeName)}`;
@@ -226,9 +221,6 @@
text.value = name; text.value = name;
} }
} }
})
.catch((e) => {
console.error(e);
}); });
} else if (L.instanceId) { } else if (L.instanceId) {
text.value = `${ref.name} · ${accessTypeLabel}`; text.value = `${ref.name} · ${accessTypeLabel}`;
+1 -5
View File
@@ -84,14 +84,10 @@
groupName.value = props.grouphint; groupName.value = props.grouphint;
} else if (locObj.groupId) { } else if (locObj.groupId) {
groupName.value = locObj.groupId; groupName.value = locObj.groupId;
getGroupName(locObj.groupId) getGroupName(locObj.groupId).then((name) => {
.then((name) => {
if (name && props.locationobject.tag === locObj.tag) { if (name && props.locationobject.tag === locObj.tag) {
groupName.value = name; groupName.value = name;
} }
})
.catch((e) => {
console.error(e);
}); });
} else { } else {
groupName.value = ''; groupName.value = '';
+13 -8
View File
@@ -177,7 +177,12 @@ const feed = {
); );
}, },
async lookupFeedDatabase(search, filters, vipList) { async lookupFeedDatabase(
search,
filters,
vipList,
maxEntries = dbVars.maxTableSize
) {
search = search.replaceAll("'", "''"); search = search.replaceAll("'", "''");
if (search.startsWith('wrld_') || search.startsWith('grp_')) { if (search.startsWith('wrld_') || search.startsWith('grp_')) {
return this.getFeedByInstanceId(search, filters, vipList); return this.getFeedByInstanceId(search, filters, vipList);
@@ -247,7 +252,7 @@ const feed = {
groupName: dbRow[8] groupName: dbRow[8]
}; };
feedDatabase.push(row); feedDatabase.push(row);
}, `SELECT * FROM ${dbVars.userPrefix}_feed_gps WHERE (display_name LIKE '%${search}%' OR world_name LIKE '%${search}%' OR group_name LIKE '%${search}%') ${vipQuery} ORDER BY id DESC LIMIT ${dbVars.maxTableSize}`); }, `SELECT * FROM ${dbVars.userPrefix}_feed_gps WHERE (display_name LIKE '%${search}%' OR world_name LIKE '%${search}%' OR group_name LIKE '%${search}%') ${vipQuery} ORDER BY id DESC LIMIT ${maxEntries}`);
} }
if (status) { if (status) {
await sqliteService.execute((dbRow) => { await sqliteService.execute((dbRow) => {
@@ -263,7 +268,7 @@ const feed = {
previousStatusDescription: dbRow[7] previousStatusDescription: dbRow[7]
}; };
feedDatabase.push(row); feedDatabase.push(row);
}, `SELECT * FROM ${dbVars.userPrefix}_feed_status WHERE (display_name LIKE '%${search}%' OR status LIKE '%${search}%' OR status_description LIKE '%${search}%') ${vipQuery} ORDER BY id DESC LIMIT ${dbVars.maxTableSize}`); }, `SELECT * FROM ${dbVars.userPrefix}_feed_status WHERE (display_name LIKE '%${search}%' OR status LIKE '%${search}%' OR status_description LIKE '%${search}%') ${vipQuery} ORDER BY id DESC LIMIT ${maxEntries}`);
} }
if (bio) { if (bio) {
await sqliteService.execute((dbRow) => { await sqliteService.execute((dbRow) => {
@@ -277,7 +282,7 @@ const feed = {
previousBio: dbRow[5] previousBio: dbRow[5]
}; };
feedDatabase.push(row); feedDatabase.push(row);
}, `SELECT * FROM ${dbVars.userPrefix}_feed_bio WHERE (display_name LIKE '%${search}%' OR bio LIKE '%${search}%') ${vipQuery} ORDER BY id DESC LIMIT ${dbVars.maxTableSize}`); }, `SELECT * FROM ${dbVars.userPrefix}_feed_bio WHERE (display_name LIKE '%${search}%' OR bio LIKE '%${search}%') ${vipQuery} ORDER BY id DESC LIMIT ${maxEntries}`);
} }
if (avatar) { if (avatar) {
var avatarQuery = ''; var avatarQuery = '';
@@ -301,7 +306,7 @@ const feed = {
previousCurrentAvatarThumbnailImageUrl: dbRow[9] previousCurrentAvatarThumbnailImageUrl: dbRow[9]
}; };
feedDatabase.push(row); feedDatabase.push(row);
}, `SELECT * FROM ${dbVars.userPrefix}_feed_avatar WHERE ((display_name LIKE '%${search}%' OR avatar_name LIKE '%${search}%') ${avatarQuery}) ${vipQuery} ORDER BY id DESC LIMIT ${dbVars.maxTableSize}`); }, `SELECT * FROM ${dbVars.userPrefix}_feed_avatar WHERE ((display_name LIKE '%${search}%' OR avatar_name LIKE '%${search}%') ${avatarQuery}) ${vipQuery} ORDER BY id DESC LIMIT ${maxEntries}`);
} }
if (online || offline) { if (online || offline) {
var query = ''; var query = '';
@@ -325,7 +330,7 @@ const feed = {
groupName: dbRow[8] groupName: dbRow[8]
}; };
feedDatabase.push(row); feedDatabase.push(row);
}, `SELECT * FROM ${dbVars.userPrefix}_feed_online_offline WHERE ((display_name LIKE '%${search}%' OR world_name LIKE '%${search}%' OR group_name LIKE '%${search}%') ${query}) ${vipQuery} ORDER BY id DESC LIMIT ${dbVars.maxTableSize}`); }, `SELECT * FROM ${dbVars.userPrefix}_feed_online_offline WHERE ((display_name LIKE '%${search}%' OR world_name LIKE '%${search}%' OR group_name LIKE '%${search}%') ${query}) ${vipQuery} ORDER BY id DESC LIMIT ${maxEntries}`);
} }
var compareByCreatedAt = function (a, b) { var compareByCreatedAt = function (a, b) {
var A = a.created_at; var A = a.created_at;
@@ -339,8 +344,8 @@ const feed = {
return 0; return 0;
}; };
feedDatabase.sort(compareByCreatedAt); feedDatabase.sort(compareByCreatedAt);
if (feedDatabase.length > dbVars.maxTableSize) { if (feedDatabase.length > maxEntries) {
feedDatabase.splice(0, feedDatabase.length - dbVars.maxTableSize); feedDatabase.splice(0, feedDatabase.length - maxEntries);
} }
return feedDatabase; return feedDatabase;
}, },
+16 -9
View File
@@ -671,7 +671,12 @@ const gameLog = {
* @returns {Promise<any[]>} The game log data * @returns {Promise<any[]>} The game log data
*/ */
async lookupGameLogDatabase(search, filters, vipList = []) { async lookupGameLogDatabase(
search,
filters,
vipList,
maxEntries = dbVars.maxTableSize
) {
search = search.replaceAll("'", "''"); search = search.replaceAll("'", "''");
if (search.startsWith('wrld_') || search.startsWith('grp_')) { if (search.startsWith('wrld_') || search.startsWith('grp_')) {
return this.getGameLogByLocation(search, filters); return this.getGameLogByLocation(search, filters);
@@ -752,7 +757,7 @@ const gameLog = {
groupName: dbRow[6] groupName: dbRow[6]
}; };
gamelogDatabase.push(row); gamelogDatabase.push(row);
}, `SELECT * FROM gamelog_location WHERE world_name LIKE '%${search}%' OR group_name LIKE '%${search}%' ORDER BY id DESC LIMIT ${dbVars.maxTableSize}`); }, `SELECT * FROM gamelog_location WHERE world_name LIKE '%${search}%' OR group_name LIKE '%${search}%' ORDER BY id DESC LIMIT ${maxEntries}`);
} }
if (onplayerjoined || onplayerleft) { if (onplayerjoined || onplayerleft) {
var query = ''; var query = '';
@@ -774,7 +779,7 @@ const gameLog = {
time: dbRow[6] time: dbRow[6]
}; };
gamelogDatabase.push(row); gamelogDatabase.push(row);
}, `SELECT * FROM gamelog_join_leave WHERE (display_name LIKE '%${search}%' AND user_id != '${dbVars.userId}') ${vipQuery} ${query} ORDER BY id DESC LIMIT ${dbVars.maxTableSize}`); }, `SELECT * FROM gamelog_join_leave WHERE (display_name LIKE '%${search}%' AND user_id != '${dbVars.userId}') ${vipQuery} ${query} ORDER BY id DESC LIMIT ${maxEntries}`);
} }
if (portalspawn) { if (portalspawn) {
await sqliteService.execute((dbRow) => { await sqliteService.execute((dbRow) => {
@@ -789,7 +794,7 @@ const gameLog = {
worldName: dbRow[6] worldName: dbRow[6]
}; };
gamelogDatabase.push(row); gamelogDatabase.push(row);
}, `SELECT * FROM gamelog_portal_spawn WHERE (display_name LIKE '%${search}%' OR world_name LIKE '%${search}%') ${vipQuery} ORDER BY id DESC LIMIT ${dbVars.maxTableSize}`); }, `SELECT * FROM gamelog_portal_spawn WHERE (display_name LIKE '%${search}%' OR world_name LIKE '%${search}%') ${vipQuery} ORDER BY id DESC LIMIT ${maxEntries}`);
} }
if (msgevent) { if (msgevent) {
await sqliteService.execute((dbRow) => { await sqliteService.execute((dbRow) => {
@@ -800,7 +805,7 @@ const gameLog = {
data: dbRow[2] data: dbRow[2]
}; };
gamelogDatabase.push(row); gamelogDatabase.push(row);
}, `SELECT * FROM gamelog_event WHERE data LIKE '%${search}%' ORDER BY id DESC LIMIT ${dbVars.maxTableSize}`); }, `SELECT * FROM gamelog_event WHERE data LIKE '%${search}%' ORDER BY id DESC LIMIT ${maxEntries}`);
} }
if (external) { if (external) {
await sqliteService.execute((dbRow) => { await sqliteService.execute((dbRow) => {
@@ -814,7 +819,7 @@ const gameLog = {
location: dbRow[5] location: dbRow[5]
}; };
gamelogDatabase.push(row); gamelogDatabase.push(row);
}, `SELECT * FROM gamelog_external WHERE (display_name LIKE '%${search}%' OR message LIKE '%${search}%') ${vipQuery} ORDER BY id DESC LIMIT ${dbVars.maxTableSize}`); }, `SELECT * FROM gamelog_external WHERE (display_name LIKE '%${search}%' OR message LIKE '%${search}%') ${vipQuery} ORDER BY id DESC LIMIT ${maxEntries}`);
} }
if (videoplay) { if (videoplay) {
await sqliteService.execute((dbRow) => { await sqliteService.execute((dbRow) => {
@@ -830,7 +835,7 @@ const gameLog = {
userId: dbRow[7] userId: dbRow[7]
}; };
gamelogDatabase.push(row); gamelogDatabase.push(row);
}, `SELECT * FROM gamelog_video_play WHERE (video_url LIKE '%${search}%' OR video_name LIKE '%${search}%' OR display_name LIKE '%${search}%') ${vipQuery} ORDER BY id DESC LIMIT ${dbVars.maxTableSize}`); }, `SELECT * FROM gamelog_video_play WHERE (video_url LIKE '%${search}%' OR video_name LIKE '%${search}%' OR display_name LIKE '%${search}%') ${vipQuery} ORDER BY id DESC LIMIT ${maxEntries}`);
} }
if (resourceload_string || resourceload_image) { if (resourceload_string || resourceload_image) {
var checkString = ''; var checkString = '';
@@ -850,7 +855,7 @@ const gameLog = {
location: dbRow[4] location: dbRow[4]
}; };
gamelogDatabase.push(row); gamelogDatabase.push(row);
}, `SELECT * FROM gamelog_resource_load WHERE resource_url LIKE '%${search}%' ${checkString} ${checkImage} ORDER BY id DESC LIMIT ${dbVars.maxTableSize}`); }, `SELECT * FROM gamelog_resource_load WHERE resource_url LIKE '%${search}%' ${checkString} ${checkImage} ORDER BY id DESC LIMIT ${maxEntries}`);
} }
var compareByCreatedAt = function (a, b) { var compareByCreatedAt = function (a, b) {
var A = a.created_at; var A = a.created_at;
@@ -864,7 +869,9 @@ const gameLog = {
return 0; return 0;
}; };
gamelogDatabase.sort(compareByCreatedAt); gamelogDatabase.sort(compareByCreatedAt);
gamelogDatabase.splice(0, gamelogDatabase.length - dbVars.maxTableSize); if (gamelogDatabase.length > maxEntries) {
gamelogDatabase.splice(0, gamelogDatabase.length - maxEntries);
}
return gamelogDatabase; return gamelogDatabase;
}, },
+51 -5
View File
@@ -21,17 +21,63 @@ const notifications = {
inviteMessage: dbRow[10], inviteMessage: dbRow[10],
requestMessage: dbRow[11], requestMessage: dbRow[11],
responseMessage: dbRow[12] responseMessage: dbRow[12]
} },
$isExpired: dbRow[13] === 1
}; };
row.$isExpired = false;
if (dbRow[13] === 1) {
row.$isExpired = true;
}
notifications.unshift(row); notifications.unshift(row);
}, `SELECT * FROM ${dbVars.userPrefix}_notifications ORDER BY created_at DESC LIMIT ${dbVars.maxTableSize}`); }, `SELECT * FROM ${dbVars.userPrefix}_notifications ORDER BY created_at DESC LIMIT ${dbVars.maxTableSize}`);
return notifications; return notifications;
}, },
async lookupNotificationDatabase(
search,
filters,
vipList,
maxEntries = dbVars.maxTableSize
) {
search = search.replaceAll("'", "''");
let notifications = [];
let vipQuery = '';
if (vipList.length > 0) {
const vipIds = vipList.map(
(userId) => `'${userId.replaceAll("'", "''")}'`
);
vipQuery = `AND sender_user_id IN (${vipIds.join(',')})`;
}
let filterQuery = '';
if (filters.length > 0) {
const filterTypes = filters.map(
(type) => `'${type.replaceAll("'", "''")}'`
);
filterQuery = `AND type IN (${filterTypes.join(',')})`;
}
await sqliteService.execute((dbRow) => {
let row = {
id: dbRow[0],
created_at: dbRow[1],
type: dbRow[2],
senderUserId: dbRow[3],
senderUsername: dbRow[4],
receiverUserId: dbRow[5],
message: dbRow[6],
details: {
worldId: dbRow[7],
worldName: dbRow[8],
imageUrl: dbRow[9],
inviteMessage: dbRow[10],
requestMessage: dbRow[11],
responseMessage: dbRow[12]
},
$isExpired: dbRow[13] === 1
};
notifications.unshift(row);
}, `SELECT * FROM ${dbVars.userPrefix}_notifications WHERE (sender_username LIKE '%${search}%' OR message LIKE '%${search}%' OR world_name LIKE '%${search}%') ${vipQuery} ${filterQuery} ORDER BY created_at DESC LIMIT ${maxEntries}`);
return notifications;
},
addNotificationToDatabase(row) { addNotificationToDatabase(row) {
var entry = { var entry = {
id: '', id: '',
+1 -1
View File
@@ -573,7 +573,7 @@ function handlePipeline(args) {
} }
notificationStore.queueNotificationNoty(noty); notificationStore.queueNotificationNoty(noty);
notificationStore.notificationTable.data.push(noty); notificationStore.notificationTable.data.push(noty);
sharedFeedStore.updateSharedFeed(true); sharedFeedStore.addEntry(noty);
break; break;
default: default:
+4
View File
@@ -12,10 +12,14 @@ async function getWorldName(location) {
const L = parseLocation(location); const L = parseLocation(location);
if (L.isRealInstance && L.worldId) { if (L.isRealInstance && L.worldId) {
try {
const args = await worldRequest.getCachedWorld({ const args = await worldRequest.getCachedWorld({
worldId: L.worldId worldId: L.worldId
}); });
worldName = args.ref.name; worldName = args.ref.name;
} catch (e) {
console.error('getWorldName failed location', location, e);
}
} }
return worldName; return worldName;
+1 -50
View File
@@ -28,13 +28,10 @@ export const useFeedStore = defineStore('Feed', () => {
pageSizeLinked: true pageSizeLinked: true
}); });
const feedSessionTable = ref([]);
watch( watch(
() => watchState.isLoggedIn, () => watchState.isLoggedIn,
(isLoggedIn) => { (isLoggedIn) => {
feedTable.value.data.length = 0; feedTable.value.data.length = 0;
feedSessionTable.value = [];
if (isLoggedIn) { if (isLoggedIn) {
initFeedTable(); initFeedTable();
} }
@@ -160,9 +157,7 @@ export const useFeedStore = defineStore('Feed', () => {
function addFeed(feed) { function addFeed(feed) {
notificationStore.queueFeedNoty(feed); notificationStore.queueFeedNoty(feed);
feedSessionTable.value.push(feed); sharedFeedStore.addEntry(feed);
sweepFeedSessionTable();
sharedFeedStore.updateSharedFeed(false);
if ( if (
feedTable.value.filter.length > 0 && feedTable.value.filter.length > 0 &&
!feedTable.value.filter.includes(feed.type) !feedTable.value.filter.includes(feed.type)
@@ -183,65 +178,21 @@ export const useFeedStore = defineStore('Feed', () => {
UiStore.notifyMenu('feed'); UiStore.notifyMenu('feed');
} }
function sweepFeedSessionTable() {
const data = feedSessionTable.value;
const k = data.length;
if (!k) {
return;
}
// 24 hour limit
const date = new Date();
date.setDate(date.getDate() - 1);
const limit = date.toJSON();
if (data[0].created_at < limit) {
let i = 0;
while (i < k && data[i].created_at < limit) {
++i;
}
if (i === k) {
feedSessionTable.value = [];
return;
}
if (i) {
data.splice(0, i);
}
}
const maxLen = Math.floor(vrcxStore.maxTableSize * 1.5);
if (maxLen > 0 && data.length > maxLen + 100) {
data.splice(0, 100);
}
}
function sweepFeed() { function sweepFeed() {
const { data } = feedTable.value; const { data } = feedTable.value;
const j = data.length; const j = data.length;
if (j > vrcxStore.maxTableSize + 50) { if (j > vrcxStore.maxTableSize + 50) {
data.splice(0, 50); data.splice(0, 50);
} }
sweepFeedSessionTable();
} }
async function initFeedTable() { async function initFeedTable() {
feedTable.value.loading = true; feedTable.value.loading = true;
feedTableLookup(); feedTableLookup();
const getFeedDatabaseResult = await database.getFeedDatabase();
if (getFeedDatabaseResult && getFeedDatabaseResult.length > 0) {
// rough, maybe 100 is enough
feedSessionTable.value = getFeedDatabaseResult.slice(-100);
} else {
feedSessionTable.value = [];
}
} }
return { return {
feedTable, feedTable,
feedSessionTable,
initFeedTable, initFeedTable,
feedTableLookup, feedTableLookup,
addFeed addFeed
+4 -4
View File
@@ -993,6 +993,7 @@ export const useFriendStore = defineStore('Friend', () => {
friendLogTable.value.data.push(friendLogHistory); friendLogTable.value.data.push(friendLogHistory);
database.addFriendLogHistory(friendLogHistory); database.addFriendLogHistory(friendLogHistory);
notificationStore.queueFriendLogNoty(friendLogHistory); notificationStore.queueFriendLogNoty(friendLogHistory);
sharedFeedStore.addEntry(friendLogHistory);
const friendLogCurrent = { const friendLogCurrent = {
userId: id, userId: id,
displayName: ref.displayName, displayName: ref.displayName,
@@ -1003,7 +1004,6 @@ export const useFriendStore = defineStore('Friend', () => {
database.setFriendLogCurrent(friendLogCurrent); database.setFriendLogCurrent(friendLogCurrent);
uiStore.notifyMenu('friend-log'); uiStore.notifyMenu('friend-log');
deleteFriendRequest(id); deleteFriendRequest(id);
sharedFeedStore.updateSharedFeed(true);
userRequest userRequest
.getUser({ .getUser({
userId: id userId: id
@@ -1067,13 +1067,13 @@ export const useFriendStore = defineStore('Friend', () => {
friendLogTable.value.data.push(friendLogHistory); friendLogTable.value.data.push(friendLogHistory);
database.addFriendLogHistory(friendLogHistory); database.addFriendLogHistory(friendLogHistory);
notificationStore.queueFriendLogNoty(friendLogHistory); notificationStore.queueFriendLogNoty(friendLogHistory);
sharedFeedStore.addEntry(friendLogHistory);
friendLog.delete(id); friendLog.delete(id);
database.deleteFriendLogCurrent(id); database.deleteFriendLogCurrent(id);
favoriteStore.handleFavoriteDelete(id); favoriteStore.handleFavoriteDelete(id);
if (!appearanceSettingsStore.hideUnfriends) { if (!appearanceSettingsStore.hideUnfriends) {
uiStore.notifyMenu('friend-log'); uiStore.notifyMenu('friend-log');
} }
sharedFeedStore.updateSharedFeed(true);
deleteFriend(id); deleteFriend(id);
} }
}); });
@@ -1130,6 +1130,7 @@ export const useFriendStore = defineStore('Friend', () => {
notificationStore.queueFriendLogNoty( notificationStore.queueFriendLogNoty(
friendLogHistoryDisplayName friendLogHistoryDisplayName
); );
sharedFeedStore.addEntry(friendLogHistoryDisplayName);
const friendLogCurrent = { const friendLogCurrent = {
userId: ref.id, userId: ref.id,
displayName: ref.displayName, displayName: ref.displayName,
@@ -1140,7 +1141,6 @@ export const useFriendStore = defineStore('Friend', () => {
database.setFriendLogCurrent(friendLogCurrent); database.setFriendLogCurrent(friendLogCurrent);
ctx.displayName = ref.displayName; ctx.displayName = ref.displayName;
uiStore.notifyMenu('friend-log'); uiStore.notifyMenu('friend-log');
sharedFeedStore.updateSharedFeed(true);
} }
} }
if ( if (
@@ -1176,6 +1176,7 @@ export const useFriendStore = defineStore('Friend', () => {
friendLogTable.value.data.push(friendLogHistoryTrustLevel); friendLogTable.value.data.push(friendLogHistoryTrustLevel);
database.addFriendLogHistory(friendLogHistoryTrustLevel); database.addFriendLogHistory(friendLogHistoryTrustLevel);
notificationStore.queueFriendLogNoty(friendLogHistoryTrustLevel); notificationStore.queueFriendLogNoty(friendLogHistoryTrustLevel);
sharedFeedStore.addEntry(friendLogHistoryTrustLevel);
const friendLogCurrent2 = { const friendLogCurrent2 = {
userId: ref.id, userId: ref.id,
displayName: ref.displayName, displayName: ref.displayName,
@@ -1185,7 +1186,6 @@ export const useFriendStore = defineStore('Friend', () => {
friendLog.set(ref.id, friendLogCurrent2); friendLog.set(ref.id, friendLogCurrent2);
database.setFriendLogCurrent(friendLogCurrent2); database.setFriendLogCurrent(friendLogCurrent2);
uiStore.notifyMenu('friend-log'); uiStore.notifyMenu('friend-log');
sharedFeedStore.updateSharedFeed(true);
} }
ctx.trustLevel = ref.$trustLevel; ctx.trustLevel = ref.$trustLevel;
} }
+6 -75
View File
@@ -15,7 +15,6 @@ import {
import { AppDebug } from '../service/appConfig'; import { AppDebug } from '../service/appConfig';
import { database } from '../service/database'; import { database } from '../service/database';
import { useAdvancedSettingsStore } from './settings/advanced'; import { useAdvancedSettingsStore } from './settings/advanced';
import { useAppearanceSettingsStore } from './settings/appearance';
import { useFriendStore } from './friend'; import { useFriendStore } from './friend';
import { useGalleryStore } from './gallery'; import { useGalleryStore } from './gallery';
import { useGameStore } from './game'; import { useGameStore } from './game';
@@ -49,7 +48,6 @@ export const useGameLogStore = defineStore('GameLog', () => {
const vrcxStore = useVrcxStore(); const vrcxStore = useVrcxStore();
const advancedSettingsStore = useAdvancedSettingsStore(); const advancedSettingsStore = useAdvancedSettingsStore();
const gameStore = useGameStore(); const gameStore = useGameStore();
const appearanceSettingsStore = useAppearanceSettingsStore();
const generalSettingsStore = useGeneralSettingsStore(); const generalSettingsStore = useGeneralSettingsStore();
const galleryStore = useGalleryStore(); const galleryStore = useGalleryStore();
const photonStore = usePhotonStore(); const photonStore = usePhotonStore();
@@ -70,8 +68,6 @@ export const useGameLogStore = defineStore('GameLog', () => {
vip: false vip: false
}); });
const gameLogSessionTable = ref([]);
const nowPlaying = ref({ const nowPlaying = ref({
url: '', url: '',
name: '', name: '',
@@ -93,7 +89,6 @@ export const useGameLogStore = defineStore('GameLog', () => {
() => watchState.isLoggedIn, () => watchState.isLoggedIn,
(isLoggedIn) => { (isLoggedIn) => {
gameLogTable.value.data.length = 0; gameLogTable.value.data.length = 0;
gameLogSessionTable.value = [];
if (isLoggedIn) { if (isLoggedIn) {
// wait for friends to load, silly but works // wait for friends to load, silly but works
setTimeout(() => { setTimeout(() => {
@@ -225,14 +220,15 @@ export const useGameLogStore = defineStore('GameLog', () => {
workerTimers.setTimeout(() => updateNowPlaying(), 1000); workerTimers.setTimeout(() => updateNowPlaying(), 1000);
} }
function tryLoadPlayerList() { async function tryLoadPlayerList() {
// TODO: make this work again
if (!gameStore.isGameRunning) { if (!gameStore.isGameRunning) {
return; return;
} }
console.log('Loading player list from game log...'); console.log('Loading player list from game log...');
let ctx; let ctx;
let i; let i;
const data = gameLogSessionTable.value; const data = await database.getGamelogDatabase();
if (data.length === 0) { if (data.length === 0) {
return; return;
} }
@@ -358,13 +354,6 @@ export const useGameLogStore = defineStore('GameLog', () => {
function addGameLog(entry) { function addGameLog(entry) {
entry.isFriend = gameLogIsFriend(entry); entry.isFriend = gameLogIsFriend(entry);
entry.isFavorite = gameLogIsFavorite(entry); entry.isFavorite = gameLogIsFavorite(entry);
gameLogSessionTable.value.push(entry);
sweepGameLogSessionTable();
sharedFeedStore.updateSharedFeed(false);
if (entry.type === 'VideoPlay') {
// event time can be before last gameLog entry
sharedFeedStore.updateSharedFeed(true);
}
// If the VIP friend filter is enabled, logs from other friends will be ignored. // If the VIP friend filter is enabled, logs from other friends will be ignored.
if ( if (
@@ -402,38 +391,6 @@ export const useGameLogStore = defineStore('GameLog', () => {
uiStore.notifyMenu('game-log'); uiStore.notifyMenu('game-log');
} }
function sweepGameLogSessionTable() {
const data = gameLogSessionTable.value;
const k = data.length;
if (!k) {
return;
}
// 24 hour limit
const date = new Date();
date.setDate(date.getDate() - 1);
const limit = date.toJSON();
if (data[0].created_at < limit) {
let i = 0;
while (i < k && data[i].created_at < limit) {
++i;
}
if (i === k) {
gameLogSessionTable.value = [];
return;
}
if (i) {
data.splice(0, i);
}
}
const maxLen = Math.floor(vrcxStore.maxTableSize * 1.5);
if (maxLen > 0 && data.length > maxLen + 100) {
data.splice(0, 100);
}
}
async function addGamelogLocationToDatabase(input) { async function addGamelogLocationToDatabase(input) {
const groupName = await getGroupName(input.location); const groupName = await getGroupName(input.location);
const entry = { const entry = {
@@ -518,8 +475,6 @@ export const useGameLogStore = defineStore('GameLog', () => {
if (j > vrcxStore.maxTableSize + 50) { if (j > vrcxStore.maxTableSize + 50) {
data.splice(0, 50); data.splice(0, 50);
} }
sweepGameLogSessionTable();
} }
function addGameLogEntry(gameLog, location) { function addGameLogEntry(gameLog, location) {
@@ -657,22 +612,6 @@ export const useGameLogStore = defineStore('GameLog', () => {
if (typeof ref1 === 'undefined') { if (typeof ref1 === 'undefined') {
break; break;
} }
const friendRef = friendStore.friends.get(userId);
if (typeof friendRef?.ref !== 'undefined') {
friendRef.ref.$joinCount++;
friendRef.ref.$lastSeen = new Date().toJSON();
friendRef.ref.$timeSpent +=
dayjs(gameLog.dt) - ref1.joinTime;
if (
appearanceSettingsStore.sidebarSortMethods.includes(
'Sort by Last Seen'
)
) {
// TODO: remove
friendStore.sortVIPFriends = true;
friendStore.sortOnlineFriends = true;
}
}
const time = dayjs(gameLog.dt) - ref1.joinTime; const time = dayjs(gameLog.dt) - ref1.joinTime;
locationStore.lastLocation.playerList.delete(userId); locationStore.lastLocation.playerList.delete(userId);
locationStore.lastLocation.friendList.delete(userId); locationStore.lastLocation.friendList.delete(userId);
@@ -958,13 +897,7 @@ export const useGameLogStore = defineStore('GameLog', () => {
break; break;
} }
if (typeof entry !== 'undefined') { if (typeof entry !== 'undefined') {
// add tag colour sharedFeedStore.addEntry(entry);
if (entry.userId) {
const tagRef = userStore.customUserTags.get(entry.userId);
if (typeof tagRef !== 'undefined') {
entry.tagColour = tagRef.colour;
}
}
notificationStore.queueGameLogNoty(entry); notificationStore.queueGameLogNoty(entry);
addGameLog(entry); addGameLog(entry);
} }
@@ -1368,8 +1301,6 @@ export const useGameLogStore = defineStore('GameLog', () => {
async function getGameLogTable() { async function getGameLogTable() {
await database.initTables(); await database.initTables();
gameLogSessionTable.value = await database.getGamelogDatabase();
sweepGameLogSessionTable();
const dateTill = await database.getLastDateGameLogDatabase(); const dateTill = await database.getLastDateGameLogDatabase();
updateGameLog(dateTill); updateGameLog(dateTill);
} }
@@ -1433,7 +1364,8 @@ export const useGameLogStore = defineStore('GameLog', () => {
async function initGameLogTable() { async function initGameLogTable() {
const rows = await database.lookupGameLogDatabase( const rows = await database.lookupGameLogDatabase(
gameLogTable.value.search, gameLogTable.value.search,
gameLogTable.value.filter gameLogTable.value.filter,
[]
); );
for (const row of rows) { for (const row of rows) {
row.isFriend = gameLogIsFriend(row); row.isFriend = gameLogIsFriend(row);
@@ -1447,7 +1379,6 @@ export const useGameLogStore = defineStore('GameLog', () => {
nowPlaying, nowPlaying,
gameLogTable, gameLogTable,
gameLogSessionTable,
lastVideoUrl, lastVideoUrl,
lastResourceloadUrl, lastResourceloadUrl,
+2 -3
View File
@@ -73,8 +73,7 @@ async function registerSentryPiniaPlugin() {
GameLog: { GameLog: {
// @ts-ignore // @ts-ignore
...state.GameLog, ...state.GameLog,
gameLogTable: null, gameLogTable: null
gameLogSessionTable: null
}, },
Notification: { Notification: {
// @ts-ignore // @ts-ignore
@@ -92,7 +91,7 @@ async function registerSentryPiniaPlugin() {
SharedFeed: { SharedFeed: {
// @ts-ignore // @ts-ignore
...state.SharedFeed, ...state.SharedFeed,
sharedFeed: null sharedFeedData: null
}, },
Group: { Group: {
// @ts-ignore // @ts-ignore
+5 -1
View File
@@ -387,11 +387,15 @@ export const useInstanceStore = defineStore('Instance', () => {
const L = parseLocation(location); const L = parseLocation(location);
if (L.isRealInstance && L.worldId && L.instanceId) { if (L.isRealInstance && L.worldId && L.instanceId) {
try {
const args = await instanceRequest.getCachedInstance({ const args = await instanceRequest.getCachedInstance({
worldId: L.worldId, worldId: L.worldId,
instanceId: L.instanceId instanceId: L.instanceId
}); });
instanceName = args.ref.displayName; instanceName = args.ref.displayName;
} catch (e) {
console.error('getInstanceName failed location', location, e);
}
} }
return instanceName; return instanceName;
@@ -976,8 +980,8 @@ export const useInstanceStore = defineStore('Instance', () => {
uiStore.notifyMenu('notification'); uiStore.notifyMenu('notification');
} }
notificationStore.queueNotificationNoty(noty); notificationStore.queueNotificationNoty(noty);
sharedFeedStore.addEntry(noty);
notificationStore.notificationTable.data.push(noty); notificationStore.notificationTable.data.push(noty);
sharedFeedStore.updateSharedFeed(true);
} }
/** /**
+8 -8
View File
@@ -95,14 +95,14 @@ export const useLocationStore = defineStore('Location', () => {
// with the current state of things, lets not run this if we don't need to // with the current state of things, lets not run this if we don't need to
return; return;
} }
let lastLocationTemp = ''; const lastLocationArray = await database.lookupGameLogDatabase(
for (let i = gameLogStore.gameLogSessionTable.length - 1; i > -1; i--) { '',
const item = gameLogStore.gameLogSessionTable[i]; ['Location'],
if (item.type === 'Location') { [],
lastLocationTemp = item.location; 1
break; );
} const lastLocationTemp =
} lastLocationArray.length > 0 ? lastLocationArray[0].location : '';
if (lastLocationTemp === location) { if (lastLocationTemp === location) {
return; return;
} }
+1 -1
View File
@@ -146,10 +146,10 @@ export const useNotificationStore = defineStore('Notification', () => {
} }
unseenNotifications.value.push(ref.id); unseenNotifications.value.push(ref.id);
queueNotificationNoty(ref); queueNotificationNoty(ref);
sharedFeedStore.addEntry(ref);
} }
} }
notificationTable.value.data.push(ref); notificationTable.value.data.push(ref);
sharedFeedStore.updateSharedFeed(true);
const D = userStore.userDialog; const D = userStore.userDialog;
if ( if (
D.visible === false || D.visible === false ||
+1 -3
View File
@@ -1645,6 +1645,7 @@ export const usePhotonStore = defineStore('Photon', () => {
type type
}; };
notificationStore.queueModerationNoty(noty); notificationStore.queueModerationNoty(noty);
sharedFeedStore.addEntry(noty);
const entry = { const entry = {
created_at: gameLogDate, created_at: gameLogDate,
userId: ref.id, userId: ref.id,
@@ -1653,9 +1654,6 @@ export const usePhotonStore = defineStore('Photon', () => {
}; };
moderationAgainstTable.value.push(entry); moderationAgainstTable.value.push(entry);
} }
if (block || mute || block !== row.block || mute !== row.mute) {
sharedFeedStore.updateSharedFeed(true);
}
if (block || mute) { if (block || mute) {
database.setModeration({ database.setModeration({
userId: ref.id, userId: ref.id,
+5
View File
@@ -1,11 +1,15 @@
import { defineStore } from 'pinia'; import { defineStore } from 'pinia';
import { ref } from 'vue'; import { ref } from 'vue';
import { useSharedFeedStore } from '../sharedFeed';
import configRepository from '../../service/config'; import configRepository from '../../service/config';
export const useWristOverlaySettingsStore = defineStore( export const useWristOverlaySettingsStore = defineStore(
'WristOverlaySettings', 'WristOverlaySettings',
() => { () => {
const sharedFeed = useSharedFeedStore();
const overlayWrist = ref(true); const overlayWrist = ref(true);
const hidePrivateFromFeed = ref(false); const hidePrivateFromFeed = ref(false);
const openVRAlways = ref(false); const openVRAlways = ref(false);
@@ -68,6 +72,7 @@ export const useWristOverlaySettingsStore = defineStore(
'VRCX_hidePrivateFromFeed', 'VRCX_hidePrivateFromFeed',
hidePrivateFromFeed.value hidePrivateFromFeed.value
); );
sharedFeed.loadSharedFeed();
} }
function setOpenVRAlways() { function setOpenVRAlways() {
openVRAlways.value = !openVRAlways.value; openVRAlways.value = !openVRAlways.value;
+313 -543
View File
@@ -1,179 +1,66 @@
import { reactive, ref } from 'vue';
import { defineStore } from 'pinia'; import { defineStore } from 'pinia';
import { ref } from 'vue';
import { watch } from 'vue';
import { groupRequest, worldRequest } from '../api'; import {
import { useFeedStore } from './feed'; compareByCreatedAt,
getGroupName,
getWorldName
} from '../shared/utils';
import { database } from '../service/database';
import { useFriendStore } from './friend'; import { useFriendStore } from './friend';
import { useGameLogStore } from './gameLog';
import { useGroupStore } from './group';
import { useInstanceStore } from './instance'; import { useInstanceStore } from './instance';
import { useLocationStore } from './location'; import { useLocationStore } from './location';
import { useModerationStore } from './moderation'; import { useModerationStore } from './moderation';
import { useNotificationStore } from './notification'; import { useNotificationStore } from './notification';
import { useNotificationsSettingsStore } from './settings/notifications'; import { useNotificationsSettingsStore } from './settings/notifications';
import { usePhotonStore } from './photon';
import { useUserStore } from './user'; import { useUserStore } from './user';
import { useWorldStore } from './world';
import { useWristOverlaySettingsStore } from './settings/wristOverlay'; import { useWristOverlaySettingsStore } from './settings/wristOverlay';
import { watchState } from '../service/watchState'; import { watchState } from '../service/watchState';
import * as workerTimers from 'worker-timers';
export const useSharedFeedStore = defineStore('SharedFeed', () => { export const useSharedFeedStore = defineStore('SharedFeed', () => {
const friendStore = useFriendStore(); const friendStore = useFriendStore();
const notificationsSettingsStore = useNotificationsSettingsStore(); const notificationsSettingsStore = useNotificationsSettingsStore();
const locationStore = useLocationStore(); const locationStore = useLocationStore();
const groupStore = useGroupStore();
const userStore = useUserStore(); const userStore = useUserStore();
const wristOverlaySettingsStore = useWristOverlaySettingsStore(); const wristOverlaySettingsStore = useWristOverlaySettingsStore();
const instanceStore = useInstanceStore(); const instanceStore = useInstanceStore();
const gameLogStore = useGameLogStore();
const moderationStore = useModerationStore(); const moderationStore = useModerationStore();
const notificationStore = useNotificationStore(); const notificationStore = useNotificationStore();
const feedStore = useFeedStore();
const worldStore = useWorldStore();
const photonStore = usePhotonStore();
const state = reactive({ const onPlayerJoining = ref([]);
updateSharedFeedTimer: null,
updateSharedFeedPending: false,
updateSharedFeedPendingForceUpdate: false
});
const sharedFeed = ref({ async function rebuildOnPlayerJoining() {
gameLog: { let newOnPlayerJoining = [];
wrist: [], for (const ref of userStore.currentTravelers.values()) {
lastEntryDate: ''
},
feedTable: {
wrist: [],
lastEntryDate: ''
},
notificationTable: {
wrist: [],
lastEntryDate: ''
},
friendLogTable: {
wrist: [],
lastEntryDate: ''
},
moderationAgainstTable: {
wrist: [],
lastEntryDate: ''
},
pendingUpdate: false
});
function updateSharedFeed(forceUpdate) {
if (!watchState.isFriendsLoaded) {
return;
}
// TODO: remove debounce, decouple blocked player join/leave notifications, pull data from database with filters instead of sharedFeed
if (state.updateSharedFeedTimer) {
if (forceUpdate) {
state.updateSharedFeedPendingForceUpdate = true;
}
state.updateSharedFeedPending = true;
} else {
updateSharedExecute(forceUpdate);
state.updateSharedFeedTimer = setTimeout(() => {
if (state.updateSharedFeedPending) {
updateSharedExecute(
state.updateSharedFeedPendingForceUpdate
);
}
state.updateSharedFeedTimer = null;
}, 150);
}
}
function updateSharedExecute(forceUpdate) {
try {
updateSharedFeedDebounce(forceUpdate);
} catch (err) {
console.error(err);
}
state.updateSharedFeedTimer = null;
state.updateSharedFeedPending = false;
state.updateSharedFeedPendingForceUpdate = false;
}
function updateSharedFeedDebounce(forceUpdate) {
updateSharedFeedGameLog(forceUpdate);
updateSharedFeedFeedTable(forceUpdate);
updateSharedFeedNotificationTable(forceUpdate);
updateSharedFeedFriendLogTable(forceUpdate);
updateSharedFeedModerationAgainstTable(forceUpdate);
const feeds = sharedFeed.value;
if (!feeds.pendingUpdate) {
return;
}
let wristFeed = [];
wristFeed = wristFeed.concat(
feeds.gameLog.wrist,
feeds.feedTable.wrist,
feeds.notificationTable.wrist,
feeds.friendLogTable.wrist,
feeds.moderationAgainstTable.wrist
);
// OnPlayerJoining/Traveling
userStore.currentTravelers.forEach((ref) => {
const isFavorite = friendStore.localFavoriteFriends.has(ref.id); const isFavorite = friendStore.localFavoriteFriends.has(ref.id);
if ( if (
(notificationsSettingsStore.sharedFeedFilters.wrist locationStore.lastLocation.playerList.has(ref.id) ||
.OnPlayerJoining === 'Friends' ||
(notificationsSettingsStore.sharedFeedFilters.wrist (notificationsSettingsStore.sharedFeedFilters.wrist
.OnPlayerJoining === 'VIP' && .OnPlayerJoining === 'VIP' &&
isFavorite)) && !isFavorite)
!locationStore.lastLocation.playerList.has(ref.id)
) { ) {
continue;
}
if (ref.$location.tag === locationStore.lastLocation.location) { if (ref.$location.tag === locationStore.lastLocation.location) {
var feedEntry = { const feedEntry = {
...ref, ...ref,
isFavorite, isFavorite,
isFriend: true, isFriend: true,
type: 'OnPlayerJoining' type: 'OnPlayerJoining'
}; };
wristFeed.unshift(feedEntry); newOnPlayerJoining.unshift(feedEntry);
} else { continue;
const worldRef = worldStore.cachedWorlds.get(
ref.$location.worldId
);
let groupName = '';
if (ref.$location.groupId) {
const groupRef = groupStore.cachedGroups.get(
ref.$location.groupId
);
if (typeof groupRef !== 'undefined') {
groupName = groupRef.name;
} else {
// no group cache, fetch group and try again
groupRequest
.getGroup({
groupId: ref.$location.groupId
})
.then((args) => {
args.ref = groupStore.applyGroup(args.json);
workerTimers.setTimeout(() => {
// delay to allow for group cache to update
sharedFeed.value.pendingUpdate = true;
updateSharedFeed(false);
}, 100);
return args;
})
.catch((err) => {
console.error(err);
});
} }
} const worldName = await getWorldName(ref.$location.worldId);
if (typeof worldRef !== 'undefined') { const groupName = await getGroupName(ref.$location.groupId);
let feedEntry = { const feedEntry = {
created_at: ref.created_at, created_at: ref.created_at,
type: 'GPS', type: 'GPS',
userId: ref.id, userId: ref.id,
displayName: ref.displayName, displayName: ref.displayName,
location: ref.$location.tag, location: ref.$location.tag,
worldName: worldRef.name, worldName,
groupName, groupName,
previousLocation: '', previousLocation: '',
isFavorite, isFavorite,
@@ -181,192 +68,295 @@ export const useSharedFeedStore = defineStore('SharedFeed', () => {
isFriend: true, isFriend: true,
isTraveling: true isTraveling: true
}; };
wristFeed.unshift(feedEntry); newOnPlayerJoining.unshift(feedEntry);
} else {
// no world cache, fetch world and try again
worldRequest
.getWorld({
worldId: ref.$location.worldId
})
.then((args) => {
workerTimers.setTimeout(() => {
// delay to allow for world cache to update
sharedFeed.value.pendingUpdate = true;
updateSharedFeed(false);
}, 100);
return args;
})
.catch((err) => {
console.error(err);
});
} }
} onPlayerJoining.value = newOnPlayerJoining;
}
}); sharedFeedData.value = sharedFeedData.value.filter(
wristFeed.sort(function (a, b) { (ctx) => ctx.type !== 'OnPlayerJoining'
if (a.created_at < b.created_at) {
return 1;
}
if (a.created_at > b.created_at) {
return -1;
}
return 0;
});
wristFeed.splice(16);
// temp fix, tack on instance names in the worst way possible
for (let feedEntry of wristFeed) {
if (feedEntry.location) {
const instanceRef = instanceStore.cachedInstances.get(
feedEntry.location
); );
if (instanceRef?.displayName) { sharedFeedData.value.unshift(...onPlayerJoining.value);
feedEntry.instanceDisplayName = instanceRef.displayName; if (sharedFeedData.value.length > maxEntries) {
sharedFeedData.value.splice(maxEntries);
} }
} sendSharedFeed();
// invites
if (feedEntry.details?.worldId) {
const instanceRef = instanceStore.cachedInstances.get(
feedEntry.details.worldId
);
if (instanceRef?.displayName) {
feedEntry.instanceDisplayName = instanceRef.displayName;
}
}
}
AppApi.ExecuteVrOverlayFunction(
'wristFeedUpdate',
JSON.stringify(wristFeed)
);
userStore.applyUserDialogLocation();
instanceStore.applyWorldDialogInstances();
instanceStore.applyGroupDialogInstances();
feeds.pendingUpdate = false;
} }
function updateSharedFeedGameLog(forceUpdate) { watch(
// Location, OnPlayerJoined, OnPlayerLeft () => userStore.currentTravelers,
const sessionTable = gameLogStore.gameLogSessionTable; () => rebuildOnPlayerJoining(),
let i = sessionTable.length; { deep: true }
if (i > 0) { );
if (
sessionTable[i - 1].created_at === watch(
sharedFeed.value.gameLog.lastEntryDate && () => watchState.isLoggedIn,
forceUpdate === false (isLoggedIn) => {
) { if (isLoggedIn) {
return; sharedFeedData.value = [];
loadSharedFeed();
} }
sharedFeed.value.gameLog.lastEntryDate = },
sessionTable[i - 1].created_at; { flush: 'sync' }
} else { );
return;
} const sharedFeedData = ref([]);
const bias = new Date(Date.now() - 1000 * 60 * 60 * 12).toJSON(); // 12 hours const maxEntries = 25;
const wristArr = [];
let w = 0; async function loadSharedFeed() {
let newFeed = [];
const wristFilter = notificationsSettingsStore.sharedFeedFilters.wrist; const wristFilter = notificationsSettingsStore.sharedFeedFilters.wrist;
let currentUserLeaveTime = 0; // run after fav and friendlist init
let locationJoinTime = 0; const vipList = Array.from(friendStore.localFavoriteFriends.values());
let earliestKeptTime = 0; const friendList = Array.from(friendStore.friends.keys());
for (i = sessionTable.length - 1; i > -1; i--) {
const ctx = sessionTable[i]; // Filters
if (ctx.created_at < bias) { const vipFilters = Object.keys(wristFilter).filter(
break; (key) => wristFilter[key] === 'VIP'
);
const friendsFilters = Object.keys(wristFilter).filter(
(key) => wristFilter[key] === 'Friends'
);
const everyoneFilters = Object.keys(wristFilter).filter(
(key) =>
wristFilter[key] === 'On' || wristFilter[key] === 'Everyone'
);
const everyoneAndFriendsFilters = Object.keys(wristFilter).filter(
(key) =>
wristFilter[key] === 'Friends' ||
wristFilter[key] === 'On' ||
wristFilter[key] === 'Everyone'
);
// Feed
if (vipFilters.length) {
const vipFeedRows = await database.lookupFeedDatabase(
'',
vipFilters,
vipList,
maxEntries
);
newFeed = newFeed.concat(vipFeedRows);
} }
if (ctx.type === 'Notification') { if (everyoneAndFriendsFilters.length) {
continue; const friendsFeedRows = await database.lookupFeedDatabase(
'',
everyoneAndFriendsFilters,
[],
maxEntries
);
newFeed = newFeed.concat(friendsFeedRows);
} }
let ctxTime = 0;
if (w >= 50 && earliestKeptTime > 0) { // GameLog
ctxTime = Date.parse(ctx.created_at); if (vipFilters.length) {
if (ctxTime < earliestKeptTime - 20 * 1000) { const vipGameLogRows = await database.lookupGameLogDatabase(
break; '',
vipFilters,
vipList,
maxEntries
);
newFeed = newFeed.concat(vipGameLogRows);
} }
if (friendsFilters.length) {
const friendsGameLogRows = await database.lookupGameLogDatabase(
'',
friendsFilters,
friendList,
maxEntries
);
newFeed = newFeed.concat(friendsGameLogRows);
} }
// on Location change remove OnPlayerLeft if (everyoneFilters.length) {
if (ctx.type === 'LocationDestination') { const everyoneGameLogRows = await database.lookupGameLogDatabase(
if (!ctxTime) { '',
ctxTime = Date.parse(ctx.created_at); everyoneFilters,
[],
maxEntries
);
newFeed = newFeed.concat(everyoneGameLogRows);
} }
currentUserLeaveTime = ctxTime;
const currentUserLeaveTimeOffset = // Notifications
currentUserLeaveTime + 5 * 1000; if (vipFilters.length) {
for (var k = w - 1; k > -1; k--) { const vipNotificationRows =
var feedItem = wristArr[k]; await database.lookupNotificationDatabase(
const feedItemTime = Date.parse(feedItem.created_at); '',
if ( vipFilters,
(feedItem.type === 'OnPlayerLeft' || vipList,
feedItem.type === 'BlockedOnPlayerLeft' || maxEntries
feedItem.type === 'MutedOnPlayerLeft') && );
feedItemTime >= currentUserLeaveTime && newFeed = newFeed.concat(vipNotificationRows);
feedItemTime <= currentUserLeaveTimeOffset
) {
wristArr.splice(k, 1);
w--;
}
}
}
// on Location change remove OnPlayerJoined
if (ctx.type === 'Location') {
if (!ctxTime) {
ctxTime = Date.parse(ctx.created_at);
}
locationJoinTime = ctxTime;
const locationJoinTimeOffset = locationJoinTime + 20 * 1000;
for (let k = w - 1; k > -1; k--) {
let feedItem = wristArr[k];
const feedItemTime = Date.parse(feedItem.created_at);
if (
(feedItem.type === 'OnPlayerJoined' ||
feedItem.type === 'BlockedOnPlayerJoined' ||
feedItem.type === 'MutedOnPlayerJoined') &&
feedItemTime >= locationJoinTime &&
feedItemTime <= locationJoinTimeOffset
) {
wristArr.splice(k, 1);
w--;
} }
if (everyoneAndFriendsFilters.length) {
const friendsNotificationRows =
await database.lookupNotificationDatabase(
'',
everyoneAndFriendsFilters,
[],
maxEntries
);
newFeed = newFeed.concat(friendsNotificationRows);
} }
// hide private worlds from feed
if (wristOverlaySettingsStore.hidePrivateFromFeed) {
newFeed = newFeed.filter(
(ctx) => !(ctx.type === 'GPS' && ctx.location === 'private')
);
} }
// remove current user // remove current user
if ( newFeed = newFeed.filter(
(ctx.type === 'OnPlayerJoined' || (ctx) => ctx.userId !== userStore.currentUser.id
ctx.type === 'OnPlayerLeft' || );
ctx.type === 'PortalSpawn') &&
ctx.displayName === userStore.currentUser.displayName // FriendLog, Moderations Against (nope, not worth it)
) {
continue; newFeed.sort(compareByCreatedAt);
newFeed.splice(maxEntries);
for (const entry of newFeed) {
const userId = entry.userId || entry.senderUserId;
entry.isFriend = false;
entry.isFavorite = false;
entry.tagColour = '';
if (userId) {
entry.isFriend = friendStore.friends.has(userId);
entry.isFavorite = friendStore.localFavoriteFriends.has(userId);
entry.tagColour =
userStore.customUserTags.get(userId)?.colour ?? '';
} }
// tack on instance names
const location = entry.location || entry.details?.location;
if (location) {
entry.instanceDisplayName =
await instanceStore.getInstanceName(location);
}
}
sharedFeedData.value = newFeed;
rebuildOnPlayerJoining(); // also sends updated feed
}
async function addEntry(ctx) {
const userId = ctx.userId || ctx.senderUserId;
const wristFilter = notificationsSettingsStore.sharedFeedFilters.wrist;
if (userId === userStore.currentUser.id) {
return;
}
if (
wristOverlaySettingsStore.hidePrivateFromFeed &&
ctx.type === 'GPS' &&
ctx.location === 'private'
) {
return;
}
if (ctx.type === 'FriendRequest' || ctx.type === 'Avatar') {
return;
}
let isFriend = false; let isFriend = false;
let isFavorite = false; let isFavorite = false;
if (ctx.userId) {
isFriend = friendStore.friends.has(ctx.userId);
isFavorite = friendStore.localFavoriteFriends.has(ctx.userId);
} else if (ctx.displayName) {
for (let ref of userStore.cachedUsers.values()) {
if (ref.displayName === ctx.displayName) {
isFriend = friendStore.friends.has(ref.id);
isFavorite = friendStore.localFavoriteFriends.has(
ref.id
);
break;
}
}
}
// add tag colour
let tagColour = ''; let tagColour = '';
if (ctx.userId) { if (userId) {
const tagRef = userStore.customUserTags.get(ctx.userId); isFriend = friendStore.friends.has(userId);
if (typeof tagRef !== 'undefined') { isFavorite = friendStore.localFavoriteFriends.has(userId);
tagColour = tagRef.colour; tagColour = userStore.customUserTags.get(userId)?.colour ?? '';
} }
// tack on instance names
const location = ctx.location || ctx.details?.location;
if (location) {
ctx.instanceDisplayName =
await instanceStore.getInstanceName(location);
} }
// BlockedOnPlayerJoined, BlockedOnPlayerLeft, MutedOnPlayerJoined, MutedOnPlayerLeft
// TODO: videoPlay come through before it gets video name
// TODO: On Location change remove OnPlayerLeft & OnPlayerJoined
{
// on Location change remove OnPlayerLeft
// if (ctx.type === 'LocationDestination') {
// if (!ctxTime) {
// ctxTime = Date.parse(ctx.created_at);
// }
// currentUserLeaveTime = ctxTime;
// const currentUserLeaveTimeOffset = currentUserLeaveTime + 5 * 1000;
// for (var k = w - 1; k > -1; k--) {
// var feedItem = wristArr[k];
// const feedItemTime = Date.parse(feedItem.created_at);
// if (
// (feedItem.type === 'OnPlayerLeft' ||
// feedItem.type === 'BlockedOnPlayerLeft' ||
// feedItem.type === 'MutedOnPlayerLeft') &&
// feedItemTime >= currentUserLeaveTime &&
// feedItemTime <= currentUserLeaveTimeOffset
// ) {
// wristArr.splice(k, 1);
// w--;
// }
// }
// }
// on Location change remove OnPlayerJoined
// if (ctx.type === 'Location') {
// if (!ctxTime) {
// ctxTime = Date.parse(ctx.created_at);
// }
// locationJoinTime = ctxTime;
// const locationJoinTimeOffset = locationJoinTime + 20 * 1000;
// for (let k = w - 1; k > -1; k--) {
// let feedItem = wristArr[k];
// const feedItemTime = Date.parse(feedItem.created_at);
// if (
// (feedItem.type === 'OnPlayerJoined' ||
// feedItem.type === 'BlockedOnPlayerJoined' ||
// feedItem.type === 'MutedOnPlayerJoined') &&
// feedItemTime >= locationJoinTime &&
// feedItemTime <= locationJoinTimeOffset
// ) {
// wristArr.splice(k, 1);
// w--;
// }
// }
// }
}
if (ctx.type === 'OnPlayerJoined' || ctx.type === 'OnPlayerLeft') { if (ctx.type === 'OnPlayerJoined' || ctx.type === 'OnPlayerLeft') {
for (var ref of moderationStore.cachedPlayerModerations.values()) { moderationAgainstCheck({
...ctx,
isFavorite,
isFriend,
tagColour
});
}
if ( if (
ref.targetDisplayName !== ctx.displayName && wristFilter[ctx.type] &&
ref.sourceUserId !== ctx.userId (wristFilter[ctx.type] === 'On' ||
wristFilter[ctx.type] === 'Everyone' ||
(wristFilter[ctx.type] === 'Friends' && isFriend) ||
(wristFilter[ctx.type] === 'VIP' && isFavorite))
) { ) {
addToSharedFeed({
...ctx,
isFavorite,
isFriend,
tagColour
});
}
}
function addToSharedFeed(ref) {
sharedFeedData.value.unshift(ref);
if (sharedFeedData.value.length > maxEntries) {
sharedFeedData.value.splice(maxEntries);
}
sendSharedFeed();
}
function moderationAgainstCheck(ctx) {
const wristFilter = notificationsSettingsStore.sharedFeedFilters.wrist;
// BlockedOnPlayerJoined, BlockedOnPlayerLeft, MutedOnPlayerJoined, MutedOnPlayerLeft
for (const ref of moderationStore.cachedPlayerModerations.values()) {
if (ref.sourceUserId !== ctx.userId) {
continue; continue;
} }
@@ -382,268 +372,48 @@ export const useSharedFeedStore = defineStore('SharedFeed', () => {
const entry = { const entry = {
created_at: ctx.created_at, created_at: ctx.created_at,
type, type,
displayName: ref.targetDisplayName, displayName: ctx.displayName,
userId: ref.targetUserId, userId: ctx.userId,
isFriend, isFavorite: ctx.isFavorite,
isFavorite isFriend: ctx.isFriend,
tagColour: ctx.tagColour
}; };
notificationStore.queueGameLogNoty(entry);
if ( if (
wristFilter[type] && wristFilter[type] &&
(wristFilter[type] === 'Everyone' || (wristFilter[type] === 'Everyone' ||
(wristFilter[type] === 'Friends' && isFriend) || (wristFilter[type] === 'Friends' && ctx.isFriend) ||
(wristFilter[type] === 'VIP' && isFavorite)) (wristFilter[type] === 'VIP' && ctx.isFavorite))
) { ) {
wristArr.unshift(entry); addToSharedFeed(entry);
}
notificationStore.queueGameLogNoty(entry);
} }
} }
// when too many user joins happen at once when switching instances
// the "w" counter maxes out and wont add any more entries
// until the onJoins are cleared by "Location"
// e.g. if a "VideoPlay" occurs between "OnPlayerJoined" and "Location" it wont be added
if (
w < 50 &&
wristFilter[ctx.type] &&
(wristFilter[ctx.type] === 'On' ||
wristFilter[ctx.type] === 'Everyone' ||
(wristFilter[ctx.type] === 'Friends' && isFriend) ||
(wristFilter[ctx.type] === 'VIP' && isFavorite))
) {
wristArr.push({
...ctx,
tagColour,
isFriend,
isFavorite
});
++w;
if (!ctxTime) {
ctxTime = Date.parse(ctx.created_at);
}
if (!earliestKeptTime || ctxTime < earliestKeptTime) {
earliestKeptTime = ctxTime;
}
}
}
wristArr.splice(50);
sharedFeed.value.gameLog.wrist = wristArr;
sharedFeed.value.pendingUpdate = true;
} }
function updateSharedFeedFeedTable(forceUpdate) { function addTag(userId, colour) {
// GPS, Online, Offline, Status, Avatar let changed = false;
const feedSession = feedStore.feedSessionTable; for (const entry of sharedFeedData.value) {
var i = feedSession.length; if (entry.userId === userId) {
if (i > 0) { entry.tagColour = colour;
if ( changed = true;
feedSession[i - 1].created_at ===
sharedFeed.value.feedTable.lastEntryDate &&
forceUpdate === false
) {
return;
}
sharedFeed.value.feedTable.lastEntryDate =
feedSession[i - 1].created_at;
} else {
return;
}
const bias = new Date(Date.now() - 86400000).toJSON(); // 24 hours
const wristArr = [];
let w = 0;
const wristFilter = notificationsSettingsStore.sharedFeedFilters.wrist;
for (let i = feedSession.length - 1; i > -1; i--) {
const ctx = feedSession[i];
if (ctx.created_at < bias) {
break;
}
if (ctx.type === 'Avatar') {
continue;
}
// hide private worlds from feed
if (
wristOverlaySettingsStore.hidePrivateFromFeed &&
ctx.type === 'GPS' &&
ctx.location === 'private'
) {
continue;
}
const isFriend = friendStore.friends.has(ctx.userId);
const isFavorite = friendStore.localFavoriteFriends.has(ctx.userId);
if (
w < 20 &&
wristFilter[ctx.type] &&
(wristFilter[ctx.type] === 'Friends' ||
(wristFilter[ctx.type] === 'VIP' && isFavorite))
) {
wristArr.push({
...ctx,
isFriend,
isFavorite
});
++w;
} }
} }
sharedFeed.value.feedTable.wrist = wristArr; if (changed) {
sharedFeed.value.pendingUpdate = true; sendSharedFeed();
}
} }
function updateSharedFeedNotificationTable(forceUpdate) { async function sendSharedFeed() {
// invite, requestInvite, requestInviteResponse, inviteResponse, friendRequest await AppApi.ExecuteVrOverlayFunction(
const notificationTable = notificationStore.notificationTable.data; 'wristFeedUpdate',
let i = notificationTable.length; JSON.stringify(sharedFeedData.value)
if (i > 0) {
if (
notificationTable[i - 1].created_at ===
sharedFeed.value.notificationTable.lastEntryDate &&
forceUpdate === false
) {
return;
}
sharedFeed.value.notificationTable.lastEntryDate =
notificationTable[i - 1].created_at;
} else {
return;
}
const bias = new Date(Date.now() - 86400000).toJSON(); // 24 hours
const wristArr = [];
let w = 0;
const wristFilter = notificationsSettingsStore.sharedFeedFilters.wrist;
for (i = notificationTable.length - 1; i > -1; i--) {
const ctx = notificationTable[i];
if (ctx.created_at < bias) {
break;
}
if (ctx.senderUserId === userStore.currentUser.id) {
continue;
}
const isFriend = friendStore.friends.has(ctx.senderUserId);
const isFavorite = friendStore.localFavoriteFriends.has(
ctx.senderUserId
); );
if (
w < 20 &&
wristFilter[ctx.type] &&
(wristFilter[ctx.type] === 'On' ||
wristFilter[ctx.type] === 'Friends' ||
(wristFilter[ctx.type] === 'VIP' && isFavorite))
) {
wristArr.push({
...ctx,
isFriend,
isFavorite
});
++w;
}
}
sharedFeed.value.notificationTable.wrist = wristArr;
sharedFeed.value.pendingUpdate = true;
}
function updateSharedFeedFriendLogTable(forceUpdate) {
// TrustLevel, Friend, FriendRequest, Unfriend, DisplayName
const friendLog = friendStore.friendLogTable.data;
var i = friendLog.length;
if (i > 0) {
if (
friendLog[i - 1].created_at ===
sharedFeed.value.friendLogTable.lastEntryDate &&
forceUpdate === false
) {
return;
}
sharedFeed.value.friendLogTable.lastEntryDate =
friendLog[i - 1].created_at;
} else {
return;
}
const bias = new Date(Date.now() - 86400000).toJSON(); // 24 hours
const wristArr = [];
let w = 0;
const wristFilter = notificationsSettingsStore.sharedFeedFilters.wrist;
for (let i = friendLog.length - 1; i > -1; i--) {
const ctx = friendLog[i];
if (ctx.created_at < bias) {
break;
}
if (ctx.type === 'FriendRequest') {
continue;
}
const isFriend = friendStore.friends.has(ctx.userId);
const isFavorite = friendStore.localFavoriteFriends.has(ctx.userId);
if (
w < 20 &&
wristFilter[ctx.type] &&
(wristFilter[ctx.type] === 'On' ||
wristFilter[ctx.type] === 'Friends' ||
(wristFilter[ctx.type] === 'VIP' && isFavorite))
) {
wristArr.push({
...ctx,
isFriend,
isFavorite
});
++w;
}
}
sharedFeed.value.friendLogTable.wrist = wristArr;
sharedFeed.value.pendingUpdate = true;
}
function updateSharedFeedModerationAgainstTable(forceUpdate) {
// Unblocked, Blocked, Muted, Unmuted
const moderationAgainst = photonStore.moderationAgainstTable;
var i = moderationAgainst.length;
if (i > 0) {
if (
moderationAgainst[i - 1].created_at ===
sharedFeed.value.moderationAgainstTable.lastEntryDate &&
forceUpdate === false
) {
return;
}
sharedFeed.value.moderationAgainstTable.lastEntryDate =
moderationAgainst[i - 1].created_at;
} else {
return;
}
const bias = new Date(Date.now() - 86400000).toJSON(); // 24 hours
const wristArr = [];
let w = 0;
const wristFilter = notificationsSettingsStore.sharedFeedFilters.wrist;
for (let i = moderationAgainst.length - 1; i > -1; i--) {
const ctx = moderationAgainst[i];
if (ctx.created_at < bias) {
break;
}
const isFriend = friendStore.friends.has(ctx.userId);
const isFavorite = friendStore.localFavoriteFriends.has(ctx.userId);
// add tag colour
let tagColour = '';
const tagRef = userStore.customUserTags.get(ctx.userId);
if (typeof tagRef !== 'undefined') {
tagColour = tagRef.colour;
}
if (
w < 20 &&
wristFilter[ctx.type] &&
wristFilter[ctx.type] === 'On'
) {
wristArr.push({
...ctx,
isFriend,
isFavorite,
tagColour
});
++w;
}
}
sharedFeed.value.moderationAgainstTable.wrist = wristArr;
sharedFeed.value.pendingUpdate = true;
} }
return { return {
state, loadSharedFeed,
sharedFeed, sendSharedFeed,
updateSharedFeed addEntry,
addTag
}; };
}); });
+1 -7
View File
@@ -630,17 +630,11 @@ export const useUserStore = defineStore('User', () => {
...ref ...ref
}); });
currentTravelers.set(ref.id, travelRef); currentTravelers.set(ref.id, travelRef);
sharedFeedStore.sharedFeed.pendingUpdate = true;
sharedFeedStore.updateSharedFeed(false);
onPlayerTraveling(travelRef); onPlayerTraveling(travelRef);
} }
} else { } else {
ref.$location = parseLocation(ref.location); ref.$location = parseLocation(ref.location);
if (currentTravelers.has(ref.id)) {
currentTravelers.delete(ref.id); currentTravelers.delete(ref.id);
sharedFeedStore.sharedFeed.pendingUpdate = true;
sharedFeedStore.updateSharedFeed(false);
}
} }
if ( if (
!instanceStore.cachedInstances.has(ref.$location.tag) && !instanceStore.cachedInstances.has(ref.$location.tag) &&
@@ -1651,7 +1645,7 @@ export const useUserStore = defineStore('User', () => {
ref.$customTag = data.Tag; ref.$customTag = data.Tag;
ref.$customTagColour = data.TagColour; ref.$customTagColour = data.TagColour;
} }
sharedFeedStore.updateSharedFeed(true); sharedFeedStore.addTag(data.UserId, data.TagColour);
} }
async function initUserNotes() { async function initUserNotes() {
+1 -2
View File
@@ -44,12 +44,11 @@ export const useVrStore = defineStore('Vr', () => {
updateVRLastLocation(); updateVRLastLocation();
updateVrNowPlaying(); updateVrNowPlaying();
// run these methods again to send data to the overlay // run these methods again to send data to the overlay
sharedFeedStore.updateSharedFeed(true); sharedFeedStore.sendSharedFeed();
friendStore.updateOnlineFriendCounter(true); // force an update friendStore.updateOnlineFriendCounter(true); // force an update
} }
async function saveOpenVROption() { async function saveOpenVROption() {
sharedFeedStore.updateSharedFeed(true);
updateVRConfigVars(); updateVRConfigVars();
updateVRLastLocation(); updateVRLastLocation();
AppApi.ExecuteVrOverlayFunction('notyClear', ''); AppApi.ExecuteVrOverlayFunction('notyClear', '');
@@ -30,15 +30,7 @@ export function useInstanceActivityData() {
async function getWorldNameData() { async function getWorldNameData() {
worldNameArray.value = await Promise.all( worldNameArray.value = await Promise.all(
activityData.value.map(async (item) => { activityData.value.map(async (item) => {
try {
return await getWorldName(item.location); return await getWorldName(item.location);
} catch {
console.error(
'getWorldName failed location',
item.location
);
return 'Unknown world';
}
}) })
); );
} }
@@ -65,7 +65,7 @@
padding: `${16 * props.cardScale * props.cardSpacing}px` padding: `${16 * props.cardScale * props.cardSpacing}px`
})); }));
const avatarFallback = computed(() => props.friend.name.charAt(0) ?? '?'); const avatarFallback = computed(() => props.friend?.name?.charAt(0) ?? '?');
const statusDotClass = computed(() => { const statusDotClass = computed(() => {
const status = userStatusClass(props.friend.ref, props.friend.pendingOffline); const status = userStatusClass(props.friend.ref, props.friend.pendingOffline);
@@ -100,7 +100,7 @@
const { photonLoggingEnabled } = storeToRefs(usePhotonStore()); const { photonLoggingEnabled } = storeToRefs(usePhotonStore());
const { notyFeedFiltersOptions, wristFeedFiltersOptions, photonFeedFiltersOptions } = feedFiltersOptions(); const { notyFeedFiltersOptions, wristFeedFiltersOptions, photonFeedFiltersOptions } = feedFiltersOptions();
const { sharedFeedFilters } = storeToRefs(useNotificationsSettingsStore()); const { sharedFeedFilters } = storeToRefs(useNotificationsSettingsStore());
const { updateSharedFeed } = useSharedFeedStore(); const { loadSharedFeed } = useSharedFeedStore();
const props = defineProps({ const props = defineProps({
feedFiltersDialogMode: { feedFiltersDialogMode: {
@@ -136,7 +136,7 @@
function saveSharedFeedFilters() { function saveSharedFeedFilters() {
configRepository.setString('sharedFeedFilters', JSON.stringify(sharedFeedFilters.value)); configRepository.setString('sharedFeedFilters', JSON.stringify(sharedFeedFilters.value));
updateSharedFeed(true); loadSharedFeed();
} }
function resetNotyFeedFilters() { function resetNotyFeedFilters() {