diff --git a/Dotnet/AppApi/Common/ImageSaving.cs b/Dotnet/AppApi/Common/ImageSaving.cs index 4cdbb7be..1443205a 100644 --- a/Dotnet/AppApi/Common/ImageSaving.cs +++ b/Dotnet/AppApi/Common/ImageSaving.cs @@ -1,5 +1,7 @@ using System; +using System.Collections.Generic; using System.IO; +using System.Text.Json; using System.Threading.Tasks; using SixLabors.ImageSharp; using SixLabors.ImageSharp.Drawing.Processing; @@ -16,6 +18,12 @@ namespace VRCX { public partial class AppApi { + public void PopulateImageHosts(string json) + { + var hosts = JsonSerializer.Deserialize>(json); + ImageCache.PopulateImageHosts(hosts); + } + public async Task GetImage(string url, string fileId, string version) { return await ImageCache.GetImage(url, fileId, version); diff --git a/Dotnet/ImageCache.cs b/Dotnet/ImageCache.cs index 26e4b903..8a0b695b 100644 --- a/Dotnet/ImageCache.cs +++ b/Dotnet/ImageCache.cs @@ -12,7 +12,7 @@ internal static class ImageCache { private static readonly string cacheLocation; private static readonly HttpClient httpClient; - private static readonly List _imageHosts = + private static readonly List ImageHosts = [ "api.vrchat.cloud", "files.vrchat.cloud", @@ -30,6 +30,22 @@ internal static class ImageCache httpClient = new HttpClient(httpClientHandler); httpClient.DefaultRequestHeaders.Add("User-Agent", Program.Version); } + + public static void PopulateImageHosts(List hosts) + { + foreach (var host in hosts) + { + if (string.IsNullOrEmpty(host)) + continue; + + var uri = new Uri(host); + if (string.IsNullOrEmpty(uri.Host)) + continue; + + if (!ImageHosts.Contains(uri.Host)) + ImageHosts.Add(uri.Host); + } + } public static async Task GetImage(string url, string fileId, string version) { @@ -47,7 +63,7 @@ internal static class ImageCache Directory.CreateDirectory(directoryLocation); var uri = new Uri(url); - if (!_imageHosts.Contains(uri.Host)) + if (!ImageHosts.Contains(uri.Host)) throw new ArgumentException("Invalid image host", url); var cookieString = string.Empty; @@ -91,7 +107,7 @@ internal static class ImageCache public static async Task SaveImageToFile(string url, string path) { var uri = new Uri(url); - if (!_imageHosts.Contains(uri.Host)) + if (!ImageHosts.Contains(uri.Host)) throw new ArgumentException("Invalid image host", url); var cookieString = string.Empty; diff --git a/Dotnet/ScreenshotMetadata/ScreenshotHelper.cs b/Dotnet/ScreenshotMetadata/ScreenshotHelper.cs index 4827a781..9a078331 100644 --- a/Dotnet/ScreenshotMetadata/ScreenshotHelper.cs +++ b/Dotnet/ScreenshotMetadata/ScreenshotHelper.cs @@ -101,7 +101,10 @@ namespace VRCX break; case ScreenshotSearchType.WorldName: - if (metadata.World.Name.IndexOf(query, StringComparison.OrdinalIgnoreCase) != -1) + if (metadata.World.Name == null) + continue; + + if (metadata.World.Name.Contains(query, StringComparison.OrdinalIgnoreCase)) result.Add(metadata); break; diff --git a/Dotnet/ScreenshotMetadata/ScreenshotMetadata.cs b/Dotnet/ScreenshotMetadata/ScreenshotMetadata.cs index 62e086f6..920a4703 100644 --- a/Dotnet/ScreenshotMetadata/ScreenshotMetadata.cs +++ b/Dotnet/ScreenshotMetadata/ScreenshotMetadata.cs @@ -107,7 +107,7 @@ namespace VRCX /// /// The display name of the user. /// - public string DisplayName { get; set; } + public string? DisplayName { get; set; } } public class WorldDetail @@ -120,7 +120,7 @@ namespace VRCX /// /// The name of the world. /// - public string Name { get; set; } + public string? Name { get; set; } /// /// The full ID of the game instance. diff --git a/src/classes/API/config.js b/src/classes/API/config.js index 6ad6bb3a..5a86cacf 100644 --- a/src/classes/API/config.js +++ b/src/classes/API/config.js @@ -22,6 +22,15 @@ export default class extends baseClass { args.ref = this.applyConfig(args.json); }); + API.$on('CONFIG', function (args) { + if (typeof args.ref?.whiteListedAssetUrls !== 'object') { + console.error('Invalid config whiteListedAssetUrls'); + } + AppApi.PopulateImageHosts( + JSON.stringify(args.ref.whiteListedAssetUrls) + ); + }); + API.applyConfig = function (json) { var ref = { ...json diff --git a/src/mixins/dialogs/userDialog.pug b/src/mixins/dialogs/userDialog.pug index 19111a59..6789ad02 100644 --- a/src/mixins/dialogs/userDialog.pug +++ b/src/mixins/dialogs/userDialog.pug @@ -532,21 +532,21 @@ mixin userDialog span.extra(v-if='userDialog.timeSpent === 0') - span.extra(v-else) {{ timeToText(userDialog.timeSpent) }} template(v-else) - el-tooltip( - :disabled='hideTooltips || API.currentUser.id !== userDialog.id' - placement='top' - :content='$t("dialog.user.info.open_previouse_instance")') - .x-friend-item(@click='showPreviousInstancesUserDialog(userDialog.ref)') - .detail - span.name {{ $t('dialog.user.info.play_time') }} - el-tooltip( - v-if='!hideTooltips' - placement='top' - style='margin-left: 5px' - :content='$t("dialog.user.info.accuracy_notice")') - i.el-icon-warning - span.extra(v-if='userDialog.timeSpent === 0') - - span.extra(v-else) {{ timeToText(userDialog.timeSpent) }} + el-tooltip( + :disabled='hideTooltips || API.currentUser.id !== userDialog.id' + placement='top' + :content='$t("dialog.user.info.open_previouse_instance")') + .x-friend-item(@click='showPreviousInstancesUserDialog(userDialog.ref)') + .detail + span.name {{ $t('dialog.user.info.play_time') }} + el-tooltip( + v-if='!hideTooltips' + placement='top' + style='margin-left: 5px' + :content='$t("dialog.user.info.accuracy_notice")') + i.el-icon-warning + span.extra(v-if='userDialog.timeSpent === 0') - + span.extra(v-else) {{ timeToText(userDialog.timeSpent) }} .x-friend-item(style='cursor: default') el-tooltip(:placement='API.currentUser.id !== userDialog.id ? "bottom" : "top"') template(#content)