diff --git a/html/src/app.js b/html/src/app.js
index 40369cec..184f62ac 100644
--- a/html/src/app.js
+++ b/html/src/app.js
@@ -10342,6 +10342,11 @@ speechSynthesis.getVoices();
this.showUserDialog(ref.userId);
return;
}
+ if (ref.displayName === 'F⁄A-18E Super Hornet') {
+ // :eyes:
+ this.showUserDialog('usr_5cd9007b-1802-45fe-92e2-0b6617639344');
+ return;
+ }
if (!ref.displayName || ref.displayName.substring(0, 3) === 'ID:') {
return;
}
@@ -11753,9 +11758,37 @@ speechSynthesis.getVoices();
$app.data.avatarRemoteDatabase = configRepository.getBool(
'VRCX_avatarRemoteDatabase'
);
- $app.data.avatarRemoteDatabaseProvider = configRepository.getString(
- 'VRCX_avatarRemoteDatabaseProvider'
- );
+ $app.data.avatarRemoteDatabaseProvider = '';
+ $app.data.avatarRemoteDatabaseProviderList = [];
+ if (configRepository.getString('VRCX_avatarRemoteDatabaseProviderList')) {
+ $app.data.avatarRemoteDatabaseProviderList = JSON.parse(
+ configRepository.getString('VRCX_avatarRemoteDatabaseProviderList')
+ );
+ }
+ if (configRepository.getString('VRCX_avatarRemoteDatabaseProvider')) {
+ // move existing provider to new list
+ var avatarRemoteDatabaseProvider = configRepository.getString(
+ 'VRCX_avatarRemoteDatabaseProvider'
+ );
+ if (
+ !$app.data.avatarRemoteDatabaseProviderList.includes(
+ avatarRemoteDatabaseProvider
+ )
+ ) {
+ $app.data.avatarRemoteDatabaseProviderList.push(
+ avatarRemoteDatabaseProvider
+ );
+ }
+ configRepository.remove('VRCX_avatarRemoteDatabaseProvider');
+ configRepository.setString(
+ 'VRCX_avatarRemoteDatabaseProviderList',
+ JSON.stringify($app.data.avatarRemoteDatabaseProviderList)
+ );
+ }
+ if ($app.data.avatarRemoteDatabaseProviderList.length > 0) {
+ $app.data.avatarRemoteDatabaseProvider =
+ $app.data.avatarRemoteDatabaseProviderList[0];
+ }
$app.data.sortFavorites = configRepository.getBool('VRCX_sortFavorites');
$app.data.randomUserColours = configRepository.getBool(
'VRCX_randomUserColours'
@@ -12961,42 +12994,6 @@ speechSynthesis.getVoices();
);
};
- $app.methods.promptSetAvatarRemoteDatabase = function (newUrl) {
- var inputValue = this.avatarRemoteDatabaseProvider;
- if (newUrl) {
- inputValue = newUrl;
- }
- this.$prompt(
- 'Enter avatar database provider URL',
- 'Avatar Database Provider',
- {
- distinguishCancelAndClose: true,
- confirmButtonText: 'OK',
- cancelButtonText: 'Cancel',
- inputValue,
- inputErrorMessage: 'Valid URL is required',
- callback: (action, instance) => {
- if (action === 'confirm') {
- this.avatarRemoteDatabaseProvider = instance.inputValue;
- configRepository.setString(
- 'VRCX_avatarRemoteDatabaseProvider',
- this.avatarRemoteDatabaseProvider
- );
- if (this.avatarRemoteDatabaseProvider) {
- this.avatarRemoteDatabase = true;
- } else {
- this.avatarRemoteDatabase = false;
- }
- configRepository.setBool(
- 'VRCX_avatarRemoteDatabase',
- this.avatarRemoteDatabase
- );
- }
- }
- }
- );
- };
-
// App: Dialog
var adjustDialogZ = (el) => {
@@ -13877,36 +13874,76 @@ speechSynthesis.getVoices();
};
$app.methods.lookupAvatars = async function (type, search) {
- if (
- this.avatarRemoteDatabaseProvider ===
- 'https://requi.dev/vrcx_search.php'
- ) {
- this.$alert(
- 'ReMod remote avatar search has been shutdown due to EAC more info here: https://requi.dev/vrcx_search.php',
- 'Remote avatar search'
- );
- this.avatarRemoteDatabaseProvider = '';
- configRepository.setString(
- 'VRCX_avatarRemoteDatabaseProvider',
- this.avatarRemoteDatabaseProvider
- );
- this.avatarRemoteDatabase = false;
- configRepository.setBool(
- 'VRCX_avatarRemoteDatabase',
- this.avatarRemoteDatabase
- );
- }
- if (type === 'search') {
- var limit = '&n=5000';
- } else {
- var limit = '';
- }
var avatars = new Map();
+ if (type === 'search') {
+ try {
+ var response = await webApiService.execute({
+ url: `${
+ this.avatarRemoteDatabaseProvider
+ }?${type}=${encodeURIComponent(search)}&n=5000`,
+ method: 'GET',
+ headers: {
+ 'User-Agent': appVersion,
+ Referer: 'https://vrcx.pypy.moe'
+ }
+ });
+ var json = JSON.parse(response.data);
+ if (this.debugWebRequests) {
+ console.log(json, response);
+ }
+ if (response.status === 200 && typeof json === 'object') {
+ json.forEach((avatar) => {
+ if (!avatars.has(avatar.Id)) {
+ var ref = {
+ authorId: '',
+ authorName: '',
+ name: '',
+ description: '',
+ id: '',
+ imageUrl: '',
+ thumbnailImageUrl: '',
+ created_at: '0001-01-01T00:00:00.0000000Z',
+ updated_at: '0001-01-01T00:00:00.0000000Z',
+ releaseStatus: 'public',
+ ...avatar
+ };
+ avatars.set(ref.id, ref);
+ }
+ });
+ } else {
+ throw new Error(`Error: ${response.data}`);
+ }
+ } catch (err) {
+ var msg = `Avatar search failed for ${search} with ${this.avatarRemoteDatabaseProvider}\n${err}`;
+ console.error(msg);
+ this.$message({
+ message: msg,
+ type: 'error'
+ });
+ }
+ } else if (type === 'authorId') {
+ var length = this.avatarRemoteDatabaseProviderList.length;
+ for (var i = 0; i < length; ++i) {
+ var url = this.avatarRemoteDatabaseProviderList[i];
+ var avatarArray = await this.lookupAvatarsByAuthor(url, search);
+ avatarArray.forEach((avatar) => {
+ if (!avatars.has(avatar.id)) {
+ avatars.set(avatar.id, avatar);
+ }
+ });
+ }
+ }
+ return avatars;
+ };
+
+ $app.methods.lookupAvatarsByAuthor = async function (url, authorId) {
+ var avatars = [];
+ if (!url) {
+ return avatars;
+ }
try {
var response = await webApiService.execute({
- url: `${
- this.avatarRemoteDatabaseProvider
- }?${type}=${encodeURIComponent(search)}${limit}`,
+ url: `${url}?authorId=${encodeURIComponent(authorId)}`,
method: 'GET',
headers: {
'User-Agent': appVersion,
@@ -13919,28 +13956,31 @@ speechSynthesis.getVoices();
}
if (response.status === 200 && typeof json === 'object') {
json.forEach((avatar) => {
- if (!avatars.has(avatar.Id)) {
- var ref1 = {
- authorId: '',
- authorName: '',
- name: '',
- description: '',
- id: '',
- imageUrl: '',
- thumbnailImageUrl: '',
- created_at: '0001-01-01T00:00:00.0000000Z',
- updated_at: '0001-01-01T00:00:00.0000000Z',
- releaseStatus: 'public',
- ...avatar
- };
- avatars.set(ref1.id, ref1);
- }
+ var ref = {
+ authorId: '',
+ authorName: '',
+ name: '',
+ description: '',
+ id: '',
+ imageUrl: '',
+ thumbnailImageUrl: '',
+ created_at: '0001-01-01T00:00:00.0000000Z',
+ updated_at: '0001-01-01T00:00:00.0000000Z',
+ releaseStatus: 'public',
+ ...avatar
+ };
+ avatars.push(ref);
});
} else {
throw new Error(`Error: ${response.data}`);
}
- } catch {
- console.error(`Avatar lookup failed for ${search}`);
+ } catch (err) {
+ var msg = `Avatar lookup failed for ${authorId} with ${url}\n${err}`;
+ console.error(msg);
+ this.$message({
+ message: msg,
+ type: 'error'
+ });
}
return avatars;
};
@@ -19461,9 +19501,7 @@ speechSynthesis.getVoices();
this.showUserDialog(commandArg);
break;
case 'addavatardb':
- this.promptSetAvatarRemoteDatabase(
- input.replace('addavatardb/', '')
- );
+ this.addAvatarProvider(input.replace('addavatardb/', ''));
break;
}
};
@@ -20794,6 +20832,70 @@ speechSynthesis.getVoices();
this.noteExportDialog.loading = false;
};
+ // avatar database provider
+
+ $app.data.avatarProviderDialog = {
+ visible: false
+ };
+
+ $app.methods.showAvatarProviderDialog = function () {
+ this.$nextTick(() =>
+ adjustDialogZ(this.$refs.avatarProviderDialog.$el)
+ );
+ var D = this.avatarProviderDialog;
+ D.visible = true;
+ };
+
+ $app.methods.addAvatarProvider = function (url) {
+ if (!url) {
+ return;
+ }
+ this.showAvatarProviderDialog();
+ if (!this.avatarRemoteDatabaseProviderList.includes(url)) {
+ this.avatarRemoteDatabaseProviderList.push(url);
+ }
+ this.saveAvatarProviderList();
+ };
+
+ $app.methods.removeAvatarProvider = function (url) {
+ var length = this.avatarRemoteDatabaseProviderList.length;
+ for (var i = 0; i < length; ++i) {
+ if (this.avatarRemoteDatabaseProviderList[i] === url) {
+ this.avatarRemoteDatabaseProviderList.splice(i, 1);
+ }
+ }
+ this.saveAvatarProviderList();
+ };
+
+ $app.methods.saveAvatarProviderList = function () {
+ var length = this.avatarRemoteDatabaseProviderList.length;
+ for (var i = 0; i < length; ++i) {
+ if (!this.avatarRemoteDatabaseProviderList[i]) {
+ this.avatarRemoteDatabaseProviderList.splice(i, 1);
+ }
+ }
+ configRepository.setString(
+ 'VRCX_avatarRemoteDatabaseProviderList',
+ JSON.stringify(this.avatarRemoteDatabaseProviderList)
+ );
+ if (this.avatarRemoteDatabaseProviderList.length > 0) {
+ this.avatarRemoteDatabaseProvider =
+ this.avatarRemoteDatabaseProviderList[0];
+ this.avatarRemoteDatabase = true;
+ } else {
+ this.avatarRemoteDatabaseProvider = '';
+ this.avatarRemoteDatabase = false;
+ }
+ configRepository.setBool(
+ 'VRCX_avatarRemoteDatabase',
+ this.avatarRemoteDatabase
+ );
+ };
+
+ $app.methods.setAvatarProvider = function (provider) {
+ this.avatarRemoteDatabaseProvider = provider;
+ };
+
$app = new Vue($app);
window.$app = $app;
})();
diff --git a/html/src/index.pug b/html/src/index.pug
index 7b4b45fe..8c037e69 100644
--- a/html/src/index.pug
+++ b/html/src/index.pug
@@ -469,6 +469,10 @@ html
el-button(v-if="searchWorldParams.offset" @click="moreSearchWorld(-1)" icon="el-icon-back" size="small") Prev
el-button(v-if="searchWorldResults.length >= 10" @click="moreSearchWorld(1)" icon="el-icon-right" size="small") Next
el-tab-pane(label="Avatar" v-loading="isSearchAvatarLoading" style="min-height:60px")
+ el-dropdown(v-if="avatarRemoteDatabaseProviderList.length > 1" trigger="click" @click.native.stop size="mini" style="margin-right:5px")
+ el-button(size="small") Search Provider #[i.el-icon-arrow-down.el-icon--right]
+ el-dropdown-menu(#default="dropdown")
+ el-dropdown-item(v-for="provider in avatarRemoteDatabaseProviderList" :key="provider" @click.native="setAvatarProvider(provider)") #[i.el-icon-check.el-icon--left(v-if="provider === avatarRemoteDatabaseProvider")] {{ provider }}
el-tooltip(placement="bottom" content="Refresh own avatars" :disabled="hideTooltips")
el-button(type="default" :loading="userDialog.isAvatarsLoading" @click="refreshUserDialogAvatars()" size="mini" icon="el-icon-refresh" circle)
span(style="font-size:14px;margin-left:5px;margin-right:5px") Results {{ searchAvatarResults.length }}
@@ -1268,7 +1272,7 @@ html
span.name Enable
el-switch(v-model="avatarRemoteDatabase" @change="saveOpenVROption")
div.options-container-item
- el-button(size="small" icon="el-icon-user-solid" @click="promptSetAvatarRemoteDatabase('')" :disabled="!avatarRemoteDatabase") Avatar Database Provider
+ el-button(size="small" icon="el-icon-user-solid" @click="showAvatarProviderDialog") Avatar Database Provider
div.options-container
span.header YouTube API
div.options-container-item
@@ -3190,6 +3194,13 @@ html
template(v-once #default="scope")
el-button(type="text" icon="el-icon-close" size="mini" @click="removeFromNoteExportTable(scope.row)")
+ //- dialog: avatar database provider
+ el-dialog.x-dialog(:before-close="beforeDialogClose" @mousedown.native="dialogMouseDown" @mouseup.native="dialogMouseUp" ref="avatarProviderDialog" :visible.sync="avatarProviderDialog.visible" title="Avatar Database Provider" width="600px")
+ div
+ el-input(v-for="(provider, index) in avatarRemoteDatabaseProviderList" :key="index" :value="provider" v-model="avatarRemoteDatabaseProviderList[index]" @change="saveAvatarProviderList" size="small" style="margin-top:5px")
+ el-button(slot="append" icon="el-icon-delete" @click="removeAvatarProvider(provider)")
+ el-button(@click="avatarRemoteDatabaseProviderList.push('')" size="mini" style="margin-top:5px") Add Provider
+
//- dialog: open source software notice
el-dialog.x-dialog(:before-close="beforeDialogClose" @mousedown.native="dialogMouseDown" @mouseup.native="dialogMouseUp" :visible.sync="ossDialog" title="Open Source Software Notice" width="650px")
div(v-if="ossDialog" style="height:350px;overflow:hidden scroll;word-break:break-all")