diff --git a/html/src/app.js b/html/src/app.js index 66db5ebb..43771a42 100644 --- a/html/src/app.js +++ b/html/src/app.js @@ -1383,17 +1383,18 @@ speechSynthesis.getVoices(); API.applyUserTrustLevel = function (ref) { ref.$isModerator = ref.developerType && ref.developerType !== 'none'; ref.$isTroll = false; + ref.$isProbableTroll = false; var trustColor = ''; var {tags} = ref; if (tags.includes('admin_moderator')) { ref.$isModerator = true; } - if ( - tags.includes('system_troll') || - tags.includes('system_probable_troll') - ) { + if (tags.includes('system_troll')) { ref.$isTroll = true; } + if (tags.includes('system_probable_troll') && !ref.$isTroll) { + ref.$isProbableTroll = true; + } if (tags.includes('system_trust_veteran')) { ref.$trustLevel = 'Trusted User'; ref.$trustClass = 'x-tag-veteran'; @@ -1420,7 +1421,7 @@ speechSynthesis.getVoices(); trustColor = 'untrusted'; ref.$trustSortNum = 1; } - if (ref.$isTroll) { + if (ref.$isTroll || ref.$isProbableTroll) { trustColor = 'troll'; ref.$trustSortNum += 0.1; } @@ -1535,6 +1536,7 @@ speechSynthesis.getVoices(); $isVRCPlus: false, $isModerator: false, $isTroll: false, + $isProbableTroll: false, $trustLevel: 'Visitor', $trustClass: 'x-tag-untrusted', $userColour: '', @@ -1675,6 +1677,7 @@ speechSynthesis.getVoices(); $isVRCPlus: false, $isModerator: false, $isTroll: false, + $isProbableTroll: false, $trustLevel: 'Visitor', $trustClass: 'x-tag-untrusted', $userColour: '', @@ -4261,7 +4264,22 @@ speechSynthesis.getVoices(); }); API.$on('PIPELINE', function (args) { - var {type, content} = args.json; + var {type, content, err} = args.json; + if (typeof err !== 'undefined') { + console.error('PIPELINE: error', args); + if (this.errorNoty) { + this.errorNoty.close(); + } + this.errorNoty = new Noty({ + type: 'error', + text: `WebSocket Error: ${err}` + }).show(); + return; + } + if (typeof content === 'undefined') { + console.error('PIPELINE: missing content', args); + return; + } if (typeof content.user !== 'undefined') { delete content.user.state; } @@ -4542,6 +4560,11 @@ speechSynthesis.getVoices(); API.connectWebSocket = function (token) { if (this.webSocket === null) { var socket = new WebSocket(`${API.websocketDomain}/?auth=${token}`); + socket.onopen = () => { + if ($app.debugWebSocket) { + console.log('WebSocket connected'); + } + }; socket.onclose = () => { if (this.webSocket === socket) { this.webSocket = null; @@ -4549,6 +4572,9 @@ speechSynthesis.getVoices(); try { socket.close(); } catch (err) {} + if ($app.debugWebSocket) { + console.log('WebSocket closed'); + } }; socket.onerror = () => { if (this.errorNoty) { @@ -4948,20 +4974,21 @@ speechSynthesis.getVoices(); $app.methods.updateLoop = function () { try { if (API.isLoggedIn === true) { + if (--this.nextFriendsRefresh <= 0) { + this.nextFriendsRefresh = 7200; // 1hour + this.nextCurrentUserRefresh = 60; // 30secs + this.refreshFriendsList(); + this.updateStoredUser(API.currentUser); + if (this.isGameRunning) { + API.refreshPlayerModerations(); + } + } if (--this.nextCurrentUserRefresh <= 0) { this.nextCurrentUserRefresh = 60; // 30secs API.getCurrentUser().catch((err1) => { throw err1; }); } - if (--this.nextFriendsRefresh <= 0) { - this.nextFriendsRefresh = 7200; // 1hour - API.refreshFriends(); - this.updateStoredUser(API.currentUser); - if (this.isGameRunning) { - API.refreshPlayerModerations(); - } - } if (--this.nextAppUpdateCheck <= 0) { if (this.branch === 'Stable') { this.nextAppUpdateCheck = 14400; // 2hours @@ -7426,6 +7453,15 @@ speechSynthesis.getVoices(); $app.nextFriendsRefresh = 0; }); + $app.methods.refreshFriendsList = async function () { + await API.getCurrentUser(); + this.nextCurrentUserRefresh = 60; // 30secs + await API.refreshFriends(); + API.closeWebSocket(); + await API.getCurrentUser(); + this.nextCurrentUserRefresh = 60; // 30secs + }; + $app.methods.refreshFriends = function (ref, origin) { var map = new Map(); for (var id of ref.friends) { @@ -10281,7 +10317,6 @@ speechSynthesis.getVoices(); ); } else if (data.Parameters[245][0] === 22) { var portalId = data.Parameters[245][1]; - this.lastPortalList.delete(portalId); var date = this.lastPortalList.get(portalId); var time = timeToText(Date.parse(gameLogDate) - date); this.addEntryPhotonEvent({ @@ -10289,6 +10324,7 @@ speechSynthesis.getVoices(); type: 'DeletedPortal', created_at: gameLogDate }); + this.lastPortalList.delete(portalId); } break; } @@ -10302,76 +10338,15 @@ speechSynthesis.getVoices(); if (this.debugPhotonLogging) { console.log('VrcEvent:', json); } - if ( - eventData.EventName === '_InstantiateObject' && - eventData.Data[0] === 'Portals/PortalInternalDynamic' - ) { - this.lastPortalList.set(eventData.Data[3], Date.parse(datetime)); - return; - } else if ( - eventData.EventName === '_DestroyObject' && - this.lastPortalList.has(eventData.Data[0]) - ) { - var portalId = eventData.Data[0]; - var date = this.lastPortalList.get(portalId); - var time = timeToText(Date.parse(datetime) - date); - this.addEntryPhotonEvent({ - photonId: senderId, - text: `DeletedPortal ${time}`, - type: 'DeletedPortal', - created_at: datetime - }); - return; - } else if (eventData.EventName === 'ConfigurePortal') { - var shortName = eventData.Data[0]; - var displayName = this.getDisplayNameFromPhotonId(senderId); - var ref = { - id: this.getUserIdFromPhotonId(senderId), - displayName - }; - workerTimers.setTimeout(() => { - // Delay to fix 404? lol - API.getInstanceFromShortName({shortName}) - .then((args) => { - var location = args.json.location; - var newShortName = args.json.shortName; - var portalType = 'Secure'; - if (shortName === newShortName) { - portalType = 'Unlocked'; - } - this.parsePhotonPortalSpawn( - datetime, - location, - ref, - portalType, - newShortName, - senderId - ); - return args; - }) - .catch((err) => { - console.log('PortalSpawn', err); - this.parsePhotonPortalSpawn( - datetime, - '', - ref, - 'Error', - shortName, - senderId - ); - API.failedGetRequests.delete( - `instances/s/${shortName}` - ); - }); - }, 1000); - return; - } else if (eventData.EventName === '_SendOnSpawn') { + if (eventData.EventName === '_SendOnSpawn') { return; } else if (eventData.EventType > 34) { var entry = { created_at: datetime, type: 'Event', - data: `${displayName} called non existent RPC ${eventData.EventType}` + data: `${this.getDisplayNameFromPhotonId( + senderId + )} called non existent RPC ${eventData.EventType}` }; this.addPhotonEventToGameLog(entry); return; @@ -14892,9 +14867,7 @@ speechSynthesis.getVoices(); } ); } - if (this.ipcEnabled) { - AppApi.SendIpc('ShowUserDialog', userId); - } + AppApi.SendIpc('ShowUserDialog', userId); API.getCachedUser({ userId }) @@ -21398,6 +21371,10 @@ speechSynthesis.getVoices(); } if (json === Object(json) && json.name && json.published_at) { this.VRCXUpdateDialog.updateJson = json; + this.changeLogDialog.buildName = json.name; + this.changeLogDialog.changeLog = this.changeLogRemoveLinks( + json.body + ); this.latestAppVersion = json.name; var name = json.name; this.VRCXUpdateDialog.updatePendingIsLatest = false; @@ -25082,7 +25059,9 @@ speechSynthesis.getVoices(); }; $app.data.changeLogDialog = { - visible: false + visible: false, + buildName: '', + changeLog: '' }; $app.methods.showChangeLogDialog = function () { @@ -25150,6 +25129,10 @@ speechSynthesis.getVoices(); }); }; + $app.methods.changeLogRemoveLinks = function (text) { + return text.replace(/([^!])\[[^\]]+\]\([^)]+\)/g, '$1'); + }; + $app = new Vue($app); window.$app = $app; })(); diff --git a/html/src/index.pug b/html/src/index.pug index 4e8f154a..b53b5f11 100644 --- a/html/src/index.pug +++ b/html/src/index.pug @@ -1561,13 +1561,13 @@ html el-tooltip(placement="bottom" :content="$t('side_panel.direct_access_tooltip')" :disabled="hideTooltips") el-button(type="default" @click="directAccessPaste" size="mini" icon="el-icon-discover" circle) el-tooltip(placement="bottom" :content="$t('side_panel.refresh_tooltip')" :disabled="hideTooltips") - el-button(type="default" @click="API.closeWebSocket(); API.getCurrentUser(); API.refreshFriends()" :loading="API.isRefreshFriendsLoading" size="mini" icon="el-icon-refresh" circle style="margin-right:10px") + el-button(type="default" @click="refreshFriendsList" :loading="API.isRefreshFriendsLoading" size="mini" icon="el-icon-refresh" circle style="margin-right:10px") .x-friend-list(style="padding-bottom:10px") .x-friend-group(style="padding:5px 0 0") span {{ $t('side_panel.friends') }} ― {{ onlineFriendCount }}/{{ friends.size }} - .x-friend-group(style="padding:10px 0 5px") + .x-friend-group.x-link(@click="isFriendsGroupMe = !isFriendsGroupMe" style="padding:10px 0 5px") i.el-icon-arrow-right(:class="{ rotate: isFriendsGroupMe }") - span.x-link(@click="isFriendsGroupMe = !isFriendsGroupMe" style="margin-left:5px") {{ $t('side_panel.me') }} + span(style="margin-left:5px") {{ $t('side_panel.me') }} div(v-show="isFriendsGroupMe") .x-friend-item(:key="API.currentUser.id" @click="showUserDialog(API.currentUser.id)") .avatar(:class="userStatusClass(API.currentUser)") @@ -1576,9 +1576,9 @@ html span.name(v-text="API.currentUser.displayName" :style="{'color':API.currentUser.$userColour}") location.extra(v-if="isGameRunning === true" :location="lastLocation.location" :traveling="lastLocationDestination" :link="false") span.extra(v-else v-text="API.currentUser.statusDescription" :link="false") - .x-friend-group(v-show="friendsGroup0.length") + .x-friend-group.x-link(@click="isFriendsGroup0 = !isFriendsGroup0" v-show="friendsGroup0.length") i.el-icon-arrow-right(:class="{ rotate: isFriendsGroup0 }") - span.x-link(@click="isFriendsGroup0 = !isFriendsGroup0" style="margin-left:5px") {{ $t('side_panel.favorite') }} ― {{ friendsGroup0.length }} + span(style="margin-left:5px") {{ $t('side_panel.favorite') }} ― {{ friendsGroup0.length }} div(v-show="isFriendsGroup0") .x-friend-item(v-for="friend in friendsGroup0" :key="friend.id" @click="showUserDialog(friend.id)") template(v-if="friend.ref") @@ -1592,9 +1592,9 @@ html template(v-else) span(v-text="friend.name || friend.id") el-button(type="text" icon="el-icon-close" size="mini" @click.stop="confirmDeleteFriend(friend.id)" style="margin-left:5px") - .x-friend-group(v-show="friendsGroup1.length") + .x-friend-group.x-link(@click="isFriendsGroup1 = !isFriendsGroup1" v-show="friendsGroup1.length") i.el-icon-arrow-right(:class="{ rotate: isFriendsGroup1 }") - span.x-link(@click="isFriendsGroup1 = !isFriendsGroup1" style="margin-left:5px") {{ $t('side_panel.online') }} ― {{ friendsGroup1.length }} + span(style="margin-left:5px") {{ $t('side_panel.online') }} ― {{ friendsGroup1.length }} div(v-show="isFriendsGroup1") .x-friend-item(v-for="friend in friendsGroup1" :key="friend.id" @click="showUserDialog(friend.id)") template(v-if="friend.ref") @@ -1608,9 +1608,9 @@ html template(v-else) span(v-text="friend.name || friend.id") el-button(type="text" icon="el-icon-close" size="mini" @click.stop="confirmDeleteFriend(friend.id)" style="margin-left:5px") - .x-friend-group(v-show="friendsGroup2.length") + .x-friend-group.x-link(@click="isFriendsGroup2 = !isFriendsGroup2" v-show="friendsGroup2.length") i.el-icon-arrow-right(:class="{ rotate: isFriendsGroup2 }") - span.x-link(@click="isFriendsGroup2 = !isFriendsGroup2" style="margin-left:5px") {{ $t('side_panel.active') }} ― {{ friendsGroup2.length }} + span(style="margin-left:5px") {{ $t('side_panel.active') }} ― {{ friendsGroup2.length }} div(v-show="isFriendsGroup2") .x-friend-item(v-for="friend in friendsGroup2" :key="friend.id" @click="showUserDialog(friend.id)") template(v-if="friend.ref") @@ -1623,9 +1623,9 @@ html template(v-else) span(v-text="friend.name || friend.id") el-button(type="text" icon="el-icon-close" size="mini" @click.stop="confirmDeleteFriend(friend.id)" style="margin-left:5px") - .x-friend-group(v-show="friendsGroup3.length") + .x-friend-group.x-link(@click="isFriendsGroup3 = !isFriendsGroup3" v-show="friendsGroup3.length") i.el-icon-arrow-right(:class="{ rotate: isFriendsGroup3 }") - span.x-link(@click="isFriendsGroup3 = !isFriendsGroup3" style="margin-left:5px") {{ $t('side_panel.offline') }} ― {{ friendsGroup3.length }} + span(style="margin-left:5px") {{ $t('side_panel.offline') }} ― {{ friendsGroup3.length }} div(v-show="isFriendsGroup3") .x-friend-item(v-for="friend in friendsGroup3" :key="friend.id" @click="showUserDialog(friend.id)") template(v-if="friend.ref") @@ -1682,6 +1682,7 @@ html el-tag.name(type="info" effect="plain" size="mini" :class="userDialog.ref.$trustClass" v-text="userDialog.ref.$trustLevel" style="margin-right:5px;margin-top:5px") el-tag.x-tag-friend(v-if="userDialog.isFriend && userDialog.friend" type="info" effect="plain" size="mini" style="margin-right:5px;margin-top:5px") {{ $t('dialog.user.tags.friend_no', { number: userDialog.friend.no }) }} el-tag.x-tag-troll(v-if="userDialog.ref.$isTroll" type="info" effect="plain" size="mini" style="margin-right:5px;margin-top:5px") Nuisance + el-tag.x-tag-troll(v-if="userDialog.ref.$isProbableTroll" type="info" effect="plain" size="mini" style="margin-right:5px;margin-top:5px") Almost Nuisance el-tag.x-tag-vip(v-if="userDialog.ref.$isModerator" type="info" effect="plain" size="mini" style="margin-right:5px;margin-top:5px") {{ $t('dialog.user.tags.vrchat_team') }} el-tag.x-tag-vrcplus(v-if="userDialog.ref.$isVRCPlus" type="info" effect="plain" size="mini" style="margin-right:5px;margin-top:5px") VRC+ el-tag.x-tag-platform-pc(v-if="userDialog.ref.last_platform === 'standalonewindows'" type="info" effect="plain" size="mini" style="margin-right:5px;margin-top:5px") PC @@ -3839,8 +3840,8 @@ html //- dialog: change log el-dialog.x-dialog(:before-close="beforeDialogClose" @mousedown.native="dialogMouseDown" @mouseup.native="dialogMouseUp" ref="changeLogDialog" :visible.sync="changeLogDialog.visible" :title="$t('dialog.change_log.header')" width="800px") .changelog-dialog(v-if="changeLogDialog.visible") - h2(v-text="VRCXUpdateDialog.updateJson?.name") - vue-markdown(:source="VRCXUpdateDialog.updateJson?.body") + h2(v-text="changeLogDialog.buildName") + vue-markdown(:source="changeLogDialog.changeLog" :linkify="false") template(#footer) el-button(type="small" @click="openExternalLink('https://github.com/vrcx-team/VRCX/releases')") {{ $t('dialog.change_log.github') }} el-button(type="small" @click="openExternalLink('https://patreon.com/Natsumi_VRCX')") {{ $t('dialog.change_log.donate') }}