diff --git a/DBMerger/DBMerger.csproj b/DBMerger/DBMerger.csproj
index 99e91aef..9f7e0f56 100644
--- a/DBMerger/DBMerger.csproj
+++ b/DBMerger/DBMerger.csproj
@@ -43,7 +43,7 @@
-
+
diff --git a/Dotnet/ScreenshotMetadata/ScreenshotHelper.cs b/Dotnet/ScreenshotMetadata/ScreenshotHelper.cs
index 670744be..f3490376 100644
--- a/Dotnet/ScreenshotMetadata/ScreenshotHelper.cs
+++ b/Dotnet/ScreenshotMetadata/ScreenshotHelper.cs
@@ -170,15 +170,15 @@ namespace VRCX
{
var xmlString = metadataString.Substring(xmlIndex);
// everything after index
- var result = ParseVRCPrint(xmlString.Substring(xmlIndex - 7));
+ var result = ParseVRCImage(xmlString);
result.SourceFile = path;
return result;
}
catch (Exception ex)
{
- Logger.Error(ex, "Failed to parse VRCPrint XML metadata for file '{0}'", path);
- return ScreenshotMetadata.JustError(path, "Failed to parse VRCPrint metadata.");
+ Logger.Error(ex, "Failed to parse VRC image XML metadata for file '{0}'", path);
+ return ScreenshotMetadata.JustError(path, "Failed to parse VRC image metadata.");
}
}
@@ -204,7 +204,7 @@ namespace VRCX
}
}
- public static ScreenshotMetadata ParseVRCPrint(string xmlString)
+ public static ScreenshotMetadata ParseVRCImage(string xmlString)
{
var doc = new XmlDocument();
doc.LoadXml(xmlString);
@@ -217,10 +217,22 @@ namespace VRCX
nsManager.AddNamespace("dc", "http://purl.org/dc/elements/1.1/");
nsManager.AddNamespace("vrc", "http://ns.vrchat.com/vrc/1.0/");
var creatorTool = root.SelectSingleNode("//xmp:CreatorTool", nsManager)?.InnerText;
- var authorId = root.SelectSingleNode("//xmp:Author", nsManager)?.InnerText;
+ var authorName = root.SelectSingleNode("//xmp:Author", nsManager)?.InnerText; // legacy, it was authorId
var dateTime = root.SelectSingleNode("//tiff:DateTime", nsManager)?.InnerText;
var note = root.SelectSingleNode("//dc:title/rdf:Alt/rdf:li", nsManager)?.InnerText;
- var worldId = root.SelectSingleNode("//vrc:World", nsManager)?.InnerText;
+ var worldId = root.SelectSingleNode("//vrc:WorldID", nsManager)?.InnerText;
+ var worldDisplayName = root.SelectSingleNode("//vrc:WorldDisplayName", nsManager)?.InnerText; // new, 01.08.2025
+ var authorId = root.SelectSingleNode("//vrc:AuthorID", nsManager)?.InnerText; // new, 01.08.2025
+
+ if (string.IsNullOrEmpty(worldId))
+ worldId = root.SelectSingleNode("//vrc:World", nsManager)?.InnerText; // legacy, it's gone now
+
+ if (string.IsNullOrEmpty(authorId))
+ {
+ // If authorId is not set, we assume legacy metadata format where authorName is used as authorId.
+ authorId = authorName;
+ authorName = null;
+ }
return new ScreenshotMetadata
{
@@ -229,13 +241,13 @@ namespace VRCX
Author = new ScreenshotMetadata.AuthorDetail
{
Id = authorId,
- DisplayName = null
+ DisplayName = authorName
},
World = new ScreenshotMetadata.WorldDetail
{
Id = worldId,
InstanceId = worldId,
- Name = null
+ Name = worldDisplayName
},
Timestamp = DateTime.TryParse(dateTime, out var dt) ? dt : null,
Note = note
@@ -254,16 +266,21 @@ namespace VRCX
///
public static bool WritePNGDescription(string path, string text)
{
- if (!File.Exists(path) || !IsPNGFile(path)) return false;
+ if (!File.Exists(path) || !IsPNGFile(path))
+ return false;
var png = File.ReadAllBytes(path);
-
var newChunkIndex = FindEndOfChunk(png, "IHDR");
- if (newChunkIndex == -1) return false;
+ if (newChunkIndex == -1)
+ return false;
// If this file already has a text chunk, chances are it got logged twice for some reason. Stop.
- // var existingiTXt = FindChunkIndex(png, "iTXt");
- // if (existingiTXt != -1) return false;
+ var screenShotMetadata = GetScreenshotMetadata(path);
+ if (screenShotMetadata != null && screenShotMetadata.Application == "VRCX")
+ {
+ Logger.Error("Screenshot file '{0}' already has VRCX metadata", path);
+ return false;
+ }
var newChunk = new PNGChunk("iTXt");
newChunk.InitializeTextChunk("Description", text);
diff --git a/Dotnet/VRCX-Cef.csproj b/Dotnet/VRCX-Cef.csproj
index de5a0996..0c9b8dd8 100644
--- a/Dotnet/VRCX-Cef.csproj
+++ b/Dotnet/VRCX-Cef.csproj
@@ -96,10 +96,10 @@
-
+
-
+
diff --git a/Dotnet/VRCX-Electron.csproj b/Dotnet/VRCX-Electron.csproj
index 5801fe05..55129d11 100644
--- a/Dotnet/VRCX-Electron.csproj
+++ b/Dotnet/VRCX-Electron.csproj
@@ -1,4 +1,4 @@
-
+
obj1\
..\build\Electron\
@@ -98,10 +98,10 @@
-
+
-
+
diff --git a/src/views/Settings/dialogs/ScreenshotMetadataDialog.vue b/src/views/Settings/dialogs/ScreenshotMetadataDialog.vue
index 08d629a0..b7debe57 100644
--- a/src/views/Settings/dialogs/ScreenshotMetadataDialog.vue
+++ b/src/views/Settings/dialogs/ScreenshotMetadataDialog.vue
@@ -436,8 +436,9 @@
D.searchIndex = searchIndex;
}
- function getAndDisplayScreenshot(path, needsCarouselFiles = true) {
- AppApi.GetScreenshotMetadata(path).then((metadata) => displayScreenshotMetadata(metadata, needsCarouselFiles));
+ async function getAndDisplayScreenshot(path, needsCarouselFiles = true) {
+ const metadata = await AppApi.GetScreenshotMetadata(path);
+ displayScreenshotMetadata(metadata, needsCarouselFiles);
}
/**
@@ -446,13 +447,19 @@
* Example: {"error":"Invalid file selected. Please select a valid VRChat screenshot."}
* See docs/screenshotMetadata.json for schema
* @param {string} metadata - JSON string grabbed from PNG file
- * @param {string} needsCarouselFiles - Whether or not to get the last/next files for the carousel
- * @returns {void}
+ * @param {boolean} needsCarouselFiles - Whether or not to get the last/next files for the carousel
+ * @returns {Promise}
*/
async function displayScreenshotMetadata(json, needsCarouselFiles = true) {
let time;
let date;
const D = props.screenshotMetadataDialog;
+ D.metadata.author = {};
+ D.metadata.world = {};
+ D.metadata.players = [];
+ D.metadata.creationDate = '';
+ D.metadata.application = '';
+
const metadata = JSON.parse(json);
if (!metadata?.sourceFile) {
D.metadata = {};