diff --git a/html/src/app.js b/html/src/app.js index b5eb0ec6..afd506af 100644 --- a/html/src/app.js +++ b/html/src/app.js @@ -7713,16 +7713,25 @@ speechSynthesis.getVoices(); return worldName; }; - $app.methods.getGroupName = async function (location) { + $app.methods.getGroupName = async function (data) { + if (!data) { + return ''; + } var groupName = ''; - try { + var groupId = data; + if (!data.startsWith('grp_')) { var L = API.parseLocation(location); if (L.groupId) { - var args = await API.getCachedGroup({ - groupId: L.groupId - }); - groupName = args.ref.name; + groupId = L.groupId; + } else { + return ''; } + } + try { + var args = await API.getCachedGroup({ + groupId + }); + groupName = args.ref.name; } catch (err) {} return groupName; }; @@ -9531,6 +9540,7 @@ speechSynthesis.getVoices(); 'OnPlayerLeft', 'ChangeAvatar', 'ChangeStatus', + 'ChangeGroup', 'PortalSpawn', 'DeletedPortal', 'ChatBoxMessage', @@ -9743,6 +9753,12 @@ speechSynthesis.getVoices(); user.avatarDict, gameLogDate ); + this.parsePhotonGroupChange( + id, + user.user, + user.groupOnNameplate, + gameLogDate + ); this.parsePhotonAvatar(user.avatarDict); this.parsePhotonAvatar(user.favatarDict); var hasInstantiated = false; @@ -9773,6 +9789,12 @@ speechSynthesis.getVoices(); user.avatarDict, gameLogDate ); + this.parsePhotonGroupChange( + id, + user.user, + user.groupOnNameplate, + gameLogDate + ); this.parsePhotonAvatar(user.avatarDict); this.parsePhotonAvatar(user.favatarDict); var hasInstantiated = false; @@ -9805,6 +9827,12 @@ speechSynthesis.getVoices(); user.avatarDict, gameLogDate ); + this.parsePhotonGroupChange( + id, + user.user, + user.groupOnNameplate, + gameLogDate + ); this.parsePhotonAvatar(user.avatarDict); this.parsePhotonAvatar(user.favatarDict); var lobbyJointime = this.photonLobbyJointime.get(id); @@ -9833,6 +9861,12 @@ speechSynthesis.getVoices(); data.Parameters[249].avatarDict, gameLogDate ); + this.parsePhotonGroupChange( + data.Parameters[254], + data.Parameters[249].user, + data.Parameters[249].groupOnNameplate, + gameLogDate + ); this.parsePhotonAvatar(data.Parameters[249].avatarDict); this.parsePhotonAvatar(data.Parameters[249].favatarDict); } @@ -10564,6 +10598,40 @@ speechSynthesis.getVoices(); this.photonLobbyAvatars.set(user.id, avatar.id); }; + $app.methods.parsePhotonGroupChange = async function ( + photonId, + user, + groupId, + gameLogDate + ) { + if ( + typeof user === 'undefined' || + !this.photonLobbyJointime.has(photonId) + ) { + return; + } + var {groupOnNameplate} = this.photonLobbyJointime.get(photonId); + if ( + groupOnNameplate !== groupId && + photonId !== this.photonLobbyCurrentUser + ) { + var groupName = await this.getGroupName(groupId); + var previousGroupName = await this.getGroupName(groupOnNameplate); + this.addEntryPhotonEvent({ + photonId, + displayName: user.displayName, + userId: user.id, + text: `ChangeGroup ${groupName}`, + type: 'ChangeGroup', + created_at: gameLogDate, + groupId, + groupName, + previousGroupId: groupOnNameplate, + previousGroupName + }); + } + }; + $app.methods.parsePhotonAvatar = function (avatar) { if (typeof avatar === 'undefined' || typeof avatar.id === 'undefined') { console.error('PhotonAvatar: avatar is undefined'); @@ -21129,6 +21197,12 @@ speechSynthesis.getVoices(); user.avatarDict, dateTime ); + this.parsePhotonGroupChange( + id, + user.user, + user.groupOnNameplate, + dateTime + ); this.parsePhotonAvatar(user.avatarDict); this.parsePhotonAvatar(user.favatarDict); var hasInstantiated = false; diff --git a/html/src/index.pug b/html/src/index.pug index 76dde4cb..b7e47945 100644 --- a/html/src/index.pug +++ b/html/src/index.pug @@ -175,6 +175,13 @@ html span(v-else) Offline i.x-user-status(:class="statusClass(scope.row.status)" style="margin-right:5px") span(v-if="scope.row.statusDescription !== scope.row.previousStatusDescription" v-text="scope.row.statusDescription") + template(v-else-if="scope.row.type === 'ChangeGroup'") + span.x-link(v-if="scope.row.previousGroupName" v-text="scope.row.previousGroupName" @click="showGroupDialog(scope.row.previousGroupId)" style="margin-right:5px") + span.x-link(v-else v-text="scope.row.previousGroupId" @click="showGroupDialog(scope.row.previousGroupId)" style="margin-right:5px") + span + i.el-icon-right + span.x-link(v-if="scope.row.groupName" v-text="scope.row.groupName" @click="showGroupDialog(scope.row.groupId)" style="margin-left:5px") + span.x-link(v-else v-text="scope.row.groupId" @click="showGroupDialog(scope.row.groupId)" style="margin-left:5px") span.x-link(v-else-if="scope.row.type === 'PortalSpawn'" @click="showWorldDialog(scope.row.location, scope.row.shortName)") location(:location="scope.row.location" :hint="scope.row.worldName" :grouphint="scope.row.groupName" :link="false") span(v-else-if="scope.row.type === 'ChatBoxMessage'" v-text="scope.row.text") @@ -229,6 +236,13 @@ html span(v-else) {{ $t('dialog.user.status.offline') }} i.x-user-status(:class="statusClass(scope.row.status)") span(v-if="scope.row.statusDescription !== scope.row.previousStatusDescription" v-text="scope.row.statusDescription" style="margin-left:5px") + template(v-else-if="scope.row.type === 'ChangeGroup'") + span.x-link(v-if="scope.row.previousGroupName" v-text="scope.row.previousGroupName" @click="showGroupDialog(scope.row.previousGroupId)" style="margin-right:5px") + span.x-link(v-else v-text="scope.row.previousGroupId" @click="showGroupDialog(scope.row.previousGroupId)" style="margin-right:5px") + span + i.el-icon-right + span.x-link(v-if="scope.row.groupName" v-text="scope.row.groupName" @click="showGroupDialog(scope.row.groupId)" style="margin-left:5px") + span.x-link(v-else v-text="scope.row.groupId" @click="showGroupDialog(scope.row.groupId)" style="margin-left:5px") span.x-link(v-else-if="scope.row.type === 'PortalSpawn'" @click="showWorldDialog(scope.row.location, scope.row.shortName)") location(:location="scope.row.location" :hint="scope.row.worldName" :grouphint="scope.row.groupName" :link="false") span(v-else-if="scope.row.type === 'ChatBoxMessage'" v-text="scope.row.text") @@ -453,7 +467,7 @@ html template(v-else-if="scope.row.type === 'Event'") span(v-text="scope.row.data") template(v-else-if="scope.row.type === 'VideoPlay'") - span(v-if="scope.row.videoId") {{ scope.row.videoId }}: + span(v-if="scope.row.videoId" style="margin-right:5px") {{ scope.row.videoId }}: span(v-if="scope.row.videoId === 'LSMedia'" v-text="scope.row.videoName") span.x-link(v-else-if="scope.row.videoName" @click="openExternalLink(scope.row.videoUrl)" v-text="scope.row.videoName") span.x-link(v-else @click="openExternalLink(scope.row.videoUrl)" v-text="scope.row.videoUrl") @@ -929,7 +943,7 @@ html template(v-once #default="scope") el-button(type="text" icon="el-icon-edit" size="mini" @click="showEditInviteMessageDialog('request', scope.row)") div.options-container - span.header {{ $t('view.profile.invite__request_response_messages') }} + span.header {{ $t('view.profile.invite_request_response_messages') }} el-tooltip(placement="top" :content="$t('view.profile.refresh_tooltip')" :disabled="hideTooltips") el-button(type="default" @click="inviteRequestResponseMessageTable.visible = true; refreshInviteMessageTable('requestResponse')" size="mini" icon="el-icon-refresh" circle style="margin-left:5px") el-tooltip(placement="top" :content="$t('view.profile.clear_results_tooltip')" :disabled="hideTooltips") @@ -2448,7 +2462,7 @@ html data-tables(v-bind="socialStatusHistoryTable" @row-click="setSocialStatusFromHistory" style="cursor:pointer") el-table-column(:label="$t('table.social_status.no')" prop="no" width="50") el-table-column(:label="$t('table.social_status.status')" prop="status") - el-select(v-model="socialStatusDialog.status" style="dispaly:block;margin-top:10px") + el-select(v-model="socialStatusDialog.status" style="display:block;margin-top:10px") el-option(:label="$t('dialog.user.status.online')" value="active"). #[i.x-user-status.online] {{ $t('dialog.user.status.online') }} el-option(:label="$t('dialog.user.status.join_me')" value="join me"). @@ -2459,7 +2473,7 @@ html #[i.x-user-status.busy] {{ $t('dialog.user.status.busy') }} el-option(v-if="API.currentUser.$isModerator" :label="$t('dialog.user.status.offline')" value="offline"). #[i.x-user-status.offline] {{ $t('dialog.user.status.offline') }} - el-input(v-model="socialStatusDialog.statusDescription" :placeholder="$t('dialog.social_status.status_placeholder')" maxlength="32" show-word-limit style="dispaly:block;margin-top:10px") + el-input(v-model="socialStatusDialog.statusDescription" :placeholder="$t('dialog.social_status.status_placeholder')" maxlength="32" show-word-limit style="display:block;margin-top:10px") template(#footer) el-button(type="primary" size="small" :disabled="socialStatusDialog.loading" @click="saveSocialStatus") {{ $t('dialog.social_status.update') }} @@ -2574,7 +2588,7 @@ html el-input(type="textarea" v-model="launchOptionsDialog.launchArguments" size="mini" show-word-limit :autosize="{ minRows:2, maxRows:5 }" placeholder="" style="margin-top:10px") div(style="font-size:12px;margin-top:10px") | {{ $t('dialog.launch_options.path_override') }} - el-input(type="textarea" v-model="launchOptionsDialog.vrcLaunchPathOverride" placeholder="C:\\Program Files (x86)\\Steam\\steamapps\\common\\VRChat" :rows="1" style="dispaly:block;margin-top:10px") + el-input(type="textarea" v-model="launchOptionsDialog.vrcLaunchPathOverride" placeholder="C:\\Program Files (x86)\\Steam\\steamapps\\common\\VRChat" :rows="1" style="display:block;margin-top:10px") template(#footer) div(style="display:flex") el-button(size="small" @click="openExternalLink('https://docs.vrchat.com/docs/launch-options')") {{ $t('dialog.launch_options.vrchat_docs') }} @@ -2631,7 +2645,7 @@ html el-dialog.x-dialog(:before-close="beforeDialogClose" @mousedown.native="dialogMouseDown" @mouseup.native="dialogMouseUp" ref="youTubeApiDialog" :visible.sync="youTubeApiDialog.visible" :title="$t('dialog.youtube_api.header')" width="400px") div(style='font-size:12px;') | {{ $t('dialog.youtube_api.description') }} #[br] - el-input(type="textarea" v-model="youTubeApiKey" :placeholder="$t('dialog.youtube_api.placeholder')" maxlength="39" show-word-limit style="dispaly:block;margin-top:10px") + el-input(type="textarea" v-model="youTubeApiKey" :placeholder="$t('dialog.youtube_api.placeholder')" maxlength="39" show-word-limit style="display:block;margin-top:10px") template(#footer) div(style="display:flex") el-button(size="small" @click="openExternalLink('https://rapidapi.com/blog/how-to-get-youtube-api-key/')") {{ $t('dialog.youtube_api.guide') }} diff --git a/html/src/localization/strings/en.json b/html/src/localization/strings/en.json index f96ff2f0..044858c7 100644 --- a/html/src/localization/strings/en.json +++ b/html/src/localization/strings/en.json @@ -74,7 +74,7 @@ "sort_created": "Sort by created" }, "prev_page": "Prev", - "next_page": "Nect" + "next_page": "Next" }, "favorite": { "friends": { @@ -159,7 +159,7 @@ "invite_messages": "Invite Messages", "invite_response_messages": "Invite Response Messages", "invite_request_messages": "Invite Request Messages", - "invite__request_response_messages": "Invite Request Response Messages", + "invite_request_response_messages": "Invite Request Response Messages", "past_display_names": "Past Display Names", "config_json": "Config JSON", "current_user_json": "Current User JSON", @@ -723,6 +723,9 @@ "friends_only": "Friends Only", "load_more": "Load more..." }, + "gallery": { + "header": "Gallery" + }, "json": { "header": "JSON" } @@ -733,10 +736,10 @@ "local_favorites": "Local Favorites" }, "invite": { - "header": "傳送邀請", - "select_placeholder": "選擇好友", - "invite_with_message": "訊息邀請", - "invite": "邀請" + "header": "Invite", + "select_placeholder": "Choose Friends", + "invite_with_message": "Invite With Message", + "invite": "Invite" }, "social_status": { "header": "Social Status", diff --git a/html/src/localization/strings/zh_TW.json b/html/src/localization/strings/zh_TW.json index 90b7d345..1b47f911 100644 --- a/html/src/localization/strings/zh_TW.json +++ b/html/src/localization/strings/zh_TW.json @@ -159,7 +159,7 @@ "invite_messages": "邀請訊息", "invite_response_messages": "邀請回覆訊息", "invite_request_messages": "邀請請求訊息", - "invite__request_response_messages": "邀請請求回覆訊息", + "invite_request_response_messages": "邀請請求回覆訊息", "past_display_names": "過去顯示名稱", "config_json": "JSON 資料", "current_user_json": "目前玩家的 JSON 資料", @@ -733,10 +733,10 @@ "local_favorites": "本地收藏" }, "invite": { - "header": "Invite", - "select_placeholder": "Choose Friends", - "invite_with_message": "Invite With Message", - "invite": "Invite" + "header": "邀請玩家", + "select_placeholder": "選擇好友", + "invite_with_message": "邀請訊息", + "invite": "邀請" }, "social_status": { "header": "社交狀態", diff --git a/html/src/vr.pug b/html/src/vr.pug index c1890028..9ca7aa26 100644 --- a/html/src/vr.pug +++ b/html/src/vr.pug @@ -69,7 +69,7 @@ html .detail span.extra span.time {{ feed.created_at | formatDate }} - | 🎵 #[span.name(v-text="feed.displayName" style="margin-right:5px")] + | 🎵 #[span.name(v-if="feed.displayName" v-text="feed.displayName" style="margin-right:5px")] template(v-if="feed.videoName") | #[span(v-text="feed.videoName")] template(v-else) @@ -489,6 +489,9 @@ html i.el-icon-right i.x-user-status(:class="statusClass(feed.status)" style="width:20px;height:20px") span(v-if="feed.statusDescription !== feed.previousStatusDescription" v-text="feed.statusDescription" style="margin-left:10px") + template(v-else-if="feed.type === 'ChangeGroup'") + span(style="margin-left:10px") ChangeGroup + span(v-text="feed.groupName" style="margin-left:10px") template(v-else-if="feed.type === 'ChatBoxMessage'") span(style="margin-left:10px") ChatBox span(v-text="feed.text" style="margin-left:10px;white-space:normal")