diff --git a/Dotnet/AppApi/Common/Screenshot.cs b/Dotnet/AppApi/Common/Screenshot.cs index c18a6a95..8da85883 100644 --- a/Dotnet/AppApi/Common/Screenshot.cs +++ b/Dotnet/AppApi/Common/Screenshot.cs @@ -116,14 +116,11 @@ public partial class AppApi var path = GetVRChatPhotosLocation(); if (!Directory.Exists(path)) return null; - - var lastDirectory = Directory.GetDirectories(path).OrderByDescending(Directory.GetCreationTime).FirstOrDefault(); - if (lastDirectory == null) - return null; - - var lastScreenshot = Directory.GetFiles(lastDirectory, "*.png").OrderByDescending(File.GetCreationTime).FirstOrDefault(); - if (lastScreenshot == null) - return null; + + // exclude folder names that contain "Prints" or "Stickers" + var imageFiles = Directory.GetFiles(path, "*.png", SearchOption.AllDirectories) + .Where(x => !Regex.IsMatch(x, @"\\Prints\\|\\Stickers\\", RegexOptions.IgnoreCase)); + var lastScreenshot = imageFiles.OrderByDescending(Directory.GetCreationTime).FirstOrDefault(); return lastScreenshot; } diff --git a/Dotnet/ScreenshotMetadata/ScreenshotHelper.cs b/Dotnet/ScreenshotMetadata/ScreenshotHelper.cs index 59455406..b8fff74f 100644 --- a/Dotnet/ScreenshotMetadata/ScreenshotHelper.cs +++ b/Dotnet/ScreenshotMetadata/ScreenshotHelper.cs @@ -76,16 +76,17 @@ namespace VRCX if (metadata == null || metadata.Error != null) { addToCache.Add(dbEntry); - metadataCache.Add(file, null); + metadataCache.TryAdd(file, null); continue; } dbEntry.Metadata = JsonConvert.SerializeObject(metadata); addToCache.Add(dbEntry); - metadataCache.Add(file, metadata); + metadataCache.TryAdd(file, metadata); } - if (metadata == null) continue; + if (metadata == null) + continue; switch (searchType) { @@ -121,18 +122,13 @@ namespace VRCX return result; } - /// - /// Retrieves metadata from a PNG screenshot file and attempts to parse it. - /// - /// The path to the PNG screenshot file. - /// A JObject containing the metadata or null if no metadata was found. - public static ScreenshotMetadata GetScreenshotMetadata(string path, bool includeJSON = false) + public static ScreenshotMetadata? GetScreenshotMetadata(string path, bool includeJSON = false) { // Early return if file doesn't exist, or isn't a PNG(Check both extension and file header) if (!File.Exists(path) || !path.EndsWith(".png") || !IsPNGFile(path)) return null; - ///if (metadataCache.TryGetValue(path, out var cachedMetadata)) + // if (metadataCache.TryGetValue(path, out var cachedMetadata)) // return cachedMetadata; string metadataString; diff --git a/Dotnet/ScreenshotMetadata/ScreenshotMetadata.cs b/Dotnet/ScreenshotMetadata/ScreenshotMetadata.cs index 7856393d..62e086f6 100644 --- a/Dotnet/ScreenshotMetadata/ScreenshotMetadata.cs +++ b/Dotnet/ScreenshotMetadata/ScreenshotMetadata.cs @@ -57,7 +57,7 @@ namespace VRCX /// Any error that occurred while parsing the file. This being true implies nothing else is set. /// [JsonIgnore] - internal string Error; + internal string? Error; [JsonIgnore] internal string JSON; diff --git a/src-electron/main.js b/src-electron/main.js index 8d9e969d..0589aa34 100644 --- a/src-electron/main.js +++ b/src-electron/main.js @@ -17,11 +17,12 @@ if (!isDotNetInstalled()) { app.quit(); return; } +console.log('DOTNET_ROOT:', process.env.DOTNET_ROOT); // get launch arguments const args = process.argv.slice(1); const noInstall = args.some((val) => val === '--no-install'); - +const homePath = getHomePath(); tryCopyFromWinePrefix(); const rootDir = app.getAppPath(); @@ -261,7 +262,7 @@ async function installVRCXappImageLauncher() { let targetIconName; const desktopFiles = fs.readdirSync( - path.join(app.getPath('home'), '.local/share/applications') + path.join(homePath, '.local/share/applications') ); for (const file of desktopFiles) { if (file.includes('appimagekit_') && file.includes('VRCX')) { @@ -284,8 +285,7 @@ async function installVRCXappImageLauncher() { */ async function installVRCX() { - let homePath = getHomePath(); - console.log('True Home path:', homePath); + console.log('Home path:', homePath); console.log('AppImage path:', appImagePath); if (!appImagePath) { console.error('AppImage path is not available!'); @@ -302,10 +302,8 @@ async function installVRCX() { appImageLauncherInstalled = true; } */ - - if ( - appImagePath.startsWith(path.join(homePath, 'Applications')) - ) { + + if (appImagePath.startsWith(path.join(homePath, 'Applications'))) { /* if (appImageLauncherInstalled) { installVRCXappImageLauncher(); @@ -332,9 +330,7 @@ async function installVRCX() { } if ( - process.env.APPIMAGE.startsWith( - path.join(homePath, 'Applications') - ) && + process.env.APPIMAGE.startsWith(path.join(homePath, 'Applications')) && path.basename(process.env.APPIMAGE) === 'VRCX.AppImage' ) { interopApi.getDotNetObject('Update').Init(appImagePath); @@ -369,10 +365,7 @@ async function installVRCX() { // Download the icon and save it to the target directory const iconUrl = 'https://raw.githubusercontent.com/vrcx-team/VRCX/master/VRCX.png'; - const iconPath = path.join( - homePath, - '.local/share/icons/VRCX.png' - ); + const iconPath = path.join(homePath, '.local/share/icons/VRCX.png'); await downloadIcon(iconUrl, iconPath) .then(() => { console.log('Icon downloaded and saved to:', iconPath); @@ -448,17 +441,13 @@ function getVRCXPath() { } function getHomePath() { - let relativeHomePath = path.join(app.getPath('home')); - // console.log('Relative Home Path: ' + relativeHomePath); + const relativeHomePath = path.join(app.getPath('home')); try { - let absoluteHomePath = fs.realpathSync(relativeHomePath); - // console.log('readlink output: ' + absoluteHomePath); - return absoluteHomePath; - } - catch (err) { + const absoluteHomePath = fs.realpathSync(relativeHomePath); + return absoluteHomePath; + } catch (err) { return relativeHomePath; } - } function getVersion() { @@ -488,7 +477,7 @@ function tryCopyFromWinePrefix() { // try copy from old wine path const userName = process.env.USER || process.env.USERNAME; const oldPath = path.join( - app.getPath('home'), + homePath, '.local/share/vrcx/drive_c/users', userName, 'AppData/Roaming/VRCX' diff --git a/src/app.js b/src/app.js index 127b9c6c..5bebeee8 100644 --- a/src/app.js +++ b/src/app.js @@ -8126,7 +8126,7 @@ console.log(`isLinux: ${LINUX}`); '[ "https://avtr.just-h.party/vrcx_search.php" ]' ) ); - $app.data.pendingOfflineDelay = 130000; + $app.data.pendingOfflineDelay = 180000; if (await configRepository.getString('VRCX_avatarRemoteDatabaseProvider')) { // move existing provider to new list var avatarRemoteDatabaseProvider = await configRepository.getString( @@ -16769,9 +16769,12 @@ console.log(`isLinux: ${LINUX}`); $app.methods.getAndDisplayLastScreenshot = function () { this.screenshotMetadataResetSearch(); - AppApi.GetLastScreenshot().then((path) => - this.getAndDisplayScreenshot(path) - ); + AppApi.GetLastScreenshot().then((path) => { + if (!path) { + return; + } + this.getAndDisplayScreenshot(path); + }); }; /** @@ -17054,6 +17057,9 @@ console.log(`isLinux: ${LINUX}`); }; $app.methods.copyImageToClipboard = function (path) { + if (!path) { + return; + } AppApi.CopyImageToClipboard(path).then(() => { this.$message({ message: 'Image copied to clipboard', @@ -17063,6 +17069,9 @@ console.log(`isLinux: ${LINUX}`); }; $app.methods.openImageFolder = function (path) { + if (!path) { + return; + } AppApi.OpenFolderAndSelectItem(path).then(() => { this.$message({ message: 'Opened image folder', diff --git a/src/classes/apiLogin.js b/src/classes/apiLogin.js index 9f82a37e..b71f16b3 100644 --- a/src/classes/apiLogin.js +++ b/src/classes/apiLogin.js @@ -15,6 +15,7 @@ export default class extends baseClass { async init() { API.isLoggedIn = false; API.attemptingAutoLogin = false; + API.autoLoginAttempts = new Set(); /** * @param {{ username: string, password: string }} params credential to login @@ -126,9 +127,25 @@ export default class extends baseClass { return; } if ($app.enablePrimaryPassword) { + console.error( + 'Primary password is enabled, this disables auto login.' + ); + this.attemptingAutoLogin = false; this.logout(); return; } + var attemptsInLastHour = Array.from(this.autoLoginAttempts).filter( + (timestamp) => timestamp > new Date().getTime() - 3600000 + ).length; + if (attemptsInLastHour >= 3) { + console.error( + 'More than 3 auto login attempts within the past hour, logging out instead of attempting auto login.' + ); + this.attemptingAutoLogin = false; + this.logout(); + return; + } + this.autoLoginAttempts.add(new Date().getTime()); $app.relogin(user) .then(() => { if (this.errorNoty) { @@ -167,6 +184,7 @@ export default class extends baseClass { API.$on('LOGOUT', function () { this.attemptingAutoLogin = false; + this.autoLoginAttempts.clear(); }); API.logout = function () { diff --git a/src/localization/en/en.json b/src/localization/en/en.json index d154172e..88293682 100644 --- a/src/localization/en/en.json +++ b/src/localization/en/en.json @@ -165,7 +165,8 @@ "unmute": "Unmute", "interactOn": "Interact On", "interactOff": "Interact Off", - "muteChat": "Mute chat" + "muteChat": "Mute chat", + "unmuteChat": "Unmute chat" } }, "notification": { diff --git a/src/views/tabs/Moderation.vue b/src/views/tabs/Moderation.vue index 1133f9c5..44674a91 100644 --- a/src/views/tabs/Moderation.vue +++ b/src/views/tabs/Moderation.vue @@ -171,7 +171,8 @@ 'unmute', 'interactOn', 'interactOff', - 'muteChat' + 'muteChat', + 'unmuteChat' ], tableProps: { stripe: true,