mirror of
https://github.com/Syping/ragephoto-cli.git
synced 2025-11-09 21:25:18 +01:00
improve create command and impl. auto sign patching
This commit is contained in:
parent
1c52b4145c
commit
6bf70113da
2 changed files with 110 additions and 42 deletions
148
Program.cs
148
Program.cs
|
|
@ -1,5 +1,7 @@
|
||||||
using System.CommandLine;
|
using System.CommandLine;
|
||||||
using System.Text;
|
using System.Text;
|
||||||
|
using System.Text.Encodings.Web;
|
||||||
|
using System.Text.Json.Nodes;
|
||||||
namespace RagePhoto.Cli;
|
namespace RagePhoto.Cli;
|
||||||
|
|
||||||
internal static class Program {
|
internal static class Program {
|
||||||
|
|
@ -11,7 +13,7 @@ internal static class Program {
|
||||||
rootCommand.Parse(args).Invoke();
|
rootCommand.Parse(args).Invoke();
|
||||||
}
|
}
|
||||||
|
|
||||||
private static void Create(String format, String jpegFile, String outputFile, String? description, String? title) {
|
private static void Create(String format, String jpegFile, String outputFile, String? description, String? json, String? title) {
|
||||||
try {
|
try {
|
||||||
using Photo photo = new();
|
using Photo photo = new();
|
||||||
|
|
||||||
|
|
@ -21,7 +23,13 @@ internal static class Program {
|
||||||
_ => throw new ArgumentException("Invalid format", nameof(format))
|
_ => throw new ArgumentException("Invalid format", nameof(format))
|
||||||
};
|
};
|
||||||
|
|
||||||
/* NOTE: Photo corrupts here... */
|
if (photo.Format == PhotoFormat.GTA5) {
|
||||||
|
photo.SetHeader("PHOTO - 10/26/25 02:28:08", 798615001, 0);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
photo.SetHeader("PHOTO - 10/26/25 02:31:34", 3077307752, 2901366738);
|
||||||
|
}
|
||||||
|
|
||||||
if (jpegFile == String.Empty) {
|
if (jpegFile == String.Empty) {
|
||||||
photo.Jpeg = Properties.Resources.EmptyJpeg;
|
photo.Jpeg = Properties.Resources.EmptyJpeg;
|
||||||
}
|
}
|
||||||
|
|
@ -32,48 +40,17 @@ internal static class Program {
|
||||||
photo.Jpeg = jpegStream.ToArray();
|
photo.Jpeg = jpegStream.ToArray();
|
||||||
}
|
}
|
||||||
|
|
||||||
Int32 photoUid = Random.Shared.Next();
|
|
||||||
if (photo.Format == PhotoFormat.GTA5) {
|
if (photo.Format == PhotoFormat.GTA5) {
|
||||||
DateTimeOffset photoTime = DateTimeOffset.FromUnixTimeSeconds(Random.Shared.Next(1356998400, 1388534399));
|
photo.Json = json != null ?
|
||||||
photo.SetHeader("PHOTO - 10/26/25 02:28:08", 798615001, 0);
|
InitializeJson(PhotoFormat.GTA5, photo, Random.Shared.Next(),
|
||||||
photo.Json = "{\"loc\":{\"x\":0,\"y\":0,\"z\":0}," +
|
DateTimeOffset.FromUnixTimeSeconds(Random.Shared.Next(1356998400, 1388534399))) :
|
||||||
"\"area\":\"SANAND\",\"street\":0,\"nm\":\"\",\"rds\":\"\"," +
|
UpdateSign(photo, photo.Json);
|
||||||
"\"scr\":1,\"sid\":\"0x0\",\"crewid\":0,\"mid\":\"\"," +
|
|
||||||
"\"mode\":\"FREEMODE\",\"meme\":false,\"mug\":false," +
|
|
||||||
$"\"uid\":{photoUid}," + "\"time\":{" +
|
|
||||||
$"\"hour\":{photoTime.Hour}," +
|
|
||||||
$"\"minute\":{photoTime.Minute}," +
|
|
||||||
$"\"second\":{photoTime.Second}," +
|
|
||||||
$"\"day\":{photoTime.Day}," +
|
|
||||||
$"\"month\":{photoTime.Month}," +
|
|
||||||
$"\"year\":{photoTime.Year}" + "}," +
|
|
||||||
$"\"creat\":{DateTimeOffset.UtcNow.ToUnixTimeSeconds()}," +
|
|
||||||
"\"slf\":true,\"drctr\":false,\"rsedtr\":false,\"cv\":true," +
|
|
||||||
$"\"sign\":{photo.Sign}" +
|
|
||||||
"}";
|
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
DateTimeOffset photoTime = DateTimeOffset.FromUnixTimeSeconds(Random.Shared.NextInt64(-2240524800, -2208988801));
|
photo.Json = json != null ?
|
||||||
photo.SetHeader("PHOTO - 10/26/25 02:31:34", 3077307752, 2901366738);
|
InitializeJson(PhotoFormat.RDR2, photo, Random.Shared.Next(),
|
||||||
photo.Json = "{\"loc\":{\"x\":0,\"y\":0,\"z\":0}," +
|
DateTimeOffset.FromUnixTimeSeconds(Random.Shared.NextInt64(-2240524800, -2208988801))) :
|
||||||
"\"regionname\":0,\"districtname\":0,\"statename\":0,\"nm\":\"\"," +
|
UpdateSign(photo, photo.Json);
|
||||||
"\"sid\":\"0x0\",\"crewid\":0,\"mid\":\"\",\"mode\":\"SP\"," +
|
|
||||||
"\"meme\":false,\"mug\":false," +
|
|
||||||
$"\"uid\":{photoUid}," + "\"time\":{" +
|
|
||||||
$"\"hour\":{photoTime.Hour}," +
|
|
||||||
$"\"minute\":{photoTime.Minute}," +
|
|
||||||
$"\"second\":{photoTime.Second}," +
|
|
||||||
$"\"day\":{photoTime.Day}," +
|
|
||||||
$"\"month\":{photoTime.Month}," +
|
|
||||||
$"\"year\":{photoTime.Year}" + "}," +
|
|
||||||
$"\"creat\":{DateTimeOffset.UtcNow.ToUnixTimeSeconds()}," +
|
|
||||||
"\"slf\":false,\"drctr\":false,\"rsedtr\":false,\"inphotomode\":true," +
|
|
||||||
"\"advanced\":false," +
|
|
||||||
"\"width\":1920," +
|
|
||||||
"\"height\":1080," +
|
|
||||||
$"\"size\":{photo.JpegSize}," +
|
|
||||||
$"\"sign\":{photo.Sign}" +
|
|
||||||
"}";
|
|
||||||
}
|
}
|
||||||
|
|
||||||
photo.Description = description ?? String.Empty;
|
photo.Description = description ?? String.Empty;
|
||||||
|
|
@ -200,12 +177,14 @@ internal static class Program {
|
||||||
|
|
||||||
if (jpegFile == String.Empty) {
|
if (jpegFile == String.Empty) {
|
||||||
photo.Jpeg = Properties.Resources.EmptyJpeg;
|
photo.Jpeg = Properties.Resources.EmptyJpeg;
|
||||||
|
photo.Json = UpdateSign(photo, photo.Json);
|
||||||
}
|
}
|
||||||
else if (jpegFile != null) {
|
else if (jpegFile != null) {
|
||||||
using MemoryStream jpegStream = new();
|
using MemoryStream jpegStream = new();
|
||||||
using Stream input = jpegFile == "-" ? Console.OpenStandardInput() : File.OpenRead(jpegFile);
|
using Stream input = jpegFile == "-" ? Console.OpenStandardInput() : File.OpenRead(jpegFile);
|
||||||
input.CopyTo(jpegStream);
|
input.CopyTo(jpegStream);
|
||||||
photo.Jpeg = jpegStream.ToArray();
|
photo.Jpeg = jpegStream.ToArray();
|
||||||
|
photo.Json = UpdateSign(photo, photo.Json);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (outputFile == "-") {
|
if (outputFile == "-") {
|
||||||
|
|
@ -233,6 +212,89 @@ internal static class Program {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private static String InitializeJson(PhotoFormat format, Photo photo, Int32 photoUid, DateTimeOffset photoTime) {
|
||||||
|
JsonObject jsonLocation = new() {
|
||||||
|
["x"] = 0,
|
||||||
|
["y"] = 0,
|
||||||
|
["z"] = 0
|
||||||
|
};
|
||||||
|
JsonObject jsonTime = new() {
|
||||||
|
["hour"] = photoTime.Hour,
|
||||||
|
["minute"] = photoTime.Minute,
|
||||||
|
["second"] = photoTime.Second,
|
||||||
|
["day"] = photoTime.Day,
|
||||||
|
["month"] = photoTime.Month,
|
||||||
|
["year"] = photoTime.Year
|
||||||
|
};
|
||||||
|
JsonObject json = format switch {
|
||||||
|
PhotoFormat.GTA5 => new() {
|
||||||
|
["loc"] = jsonLocation,
|
||||||
|
["area"] = "SANAND",
|
||||||
|
["street"] = 0,
|
||||||
|
["nm"] = String.Empty,
|
||||||
|
["rds"] = String.Empty,
|
||||||
|
["scr"] = 1,
|
||||||
|
["sid"] = "0x0",
|
||||||
|
["crewid"] = 0,
|
||||||
|
["mid"] = String.Empty,
|
||||||
|
["mode"] = "FREEMODE",
|
||||||
|
["meme"] = false,
|
||||||
|
["uid"] = photoUid,
|
||||||
|
["time"] = jsonTime,
|
||||||
|
["creat"] = DateTimeOffset.UtcNow.ToUnixTimeSeconds(),
|
||||||
|
["slf"] = true,
|
||||||
|
["drctr"] = false,
|
||||||
|
["rsedtr"] = false,
|
||||||
|
["cv"] = true,
|
||||||
|
["sign"] = photo.Sign
|
||||||
|
},
|
||||||
|
PhotoFormat.RDR2 => new() {
|
||||||
|
["loc"] = jsonLocation,
|
||||||
|
["regionname"] = 0,
|
||||||
|
["districtname"] = 0,
|
||||||
|
["statename"] = 0,
|
||||||
|
["nm"] = String.Empty,
|
||||||
|
["sid"] = "0x0",
|
||||||
|
["crewid"] = 0,
|
||||||
|
["mid"] = String.Empty,
|
||||||
|
["mode"] = "SP",
|
||||||
|
["meme"] = false,
|
||||||
|
["mug"] = false,
|
||||||
|
["uid"] = photoUid,
|
||||||
|
["time"] = jsonTime,
|
||||||
|
["creat"] = DateTimeOffset.UtcNow.ToUnixTimeSeconds(),
|
||||||
|
["slf"] = false,
|
||||||
|
["drctr"] = false,
|
||||||
|
["rsedtr"] = false,
|
||||||
|
["inphotomode"] = true,
|
||||||
|
["advanced"] = false,
|
||||||
|
["width"] = 1920,
|
||||||
|
["height"] = 1080,
|
||||||
|
["size"] = photo.JpegSize,
|
||||||
|
["sign"] = photo.Sign
|
||||||
|
},
|
||||||
|
_ => throw new ArgumentException("Invalid format", nameof(format)),
|
||||||
|
};
|
||||||
|
return json.ToJsonString(new() {
|
||||||
|
Encoder = JavaScriptEncoder.UnsafeRelaxedJsonEscaping
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
private static String UpdateSign(Photo photo, String json) {
|
||||||
|
try {
|
||||||
|
if (JsonNode.Parse(json) is not JsonObject jsonObject)
|
||||||
|
throw new ArgumentException("Invalid json", nameof(json));
|
||||||
|
jsonObject["sign"] = photo.Sign;
|
||||||
|
return jsonObject.ToJsonString(new() {
|
||||||
|
Encoder = JavaScriptEncoder.UnsafeRelaxedJsonEscaping
|
||||||
|
});
|
||||||
|
}
|
||||||
|
catch (Exception exception) {
|
||||||
|
Console.Error.WriteLine($"Failed to update sign: {exception.Message}");
|
||||||
|
return json;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private static Command CreateCommand {
|
private static Command CreateCommand {
|
||||||
get {
|
get {
|
||||||
Argument<String> formatArgument = new("format") {
|
Argument<String> formatArgument = new("format") {
|
||||||
|
|
@ -252,6 +314,9 @@ internal static class Program {
|
||||||
Option<String?> descriptionOption = new("--description", "-d") {
|
Option<String?> descriptionOption = new("--description", "-d") {
|
||||||
Description = "Photo Description"
|
Description = "Photo Description"
|
||||||
};
|
};
|
||||||
|
Option<String?> jsonOption = new("--json", "-j") {
|
||||||
|
Description = "Photo JSON"
|
||||||
|
};
|
||||||
Option<String?> titleOption = new("--title", "-t") {
|
Option<String?> titleOption = new("--title", "-t") {
|
||||||
Description = "Photo Title"
|
Description = "Photo Title"
|
||||||
};
|
};
|
||||||
|
|
@ -263,6 +328,7 @@ internal static class Program {
|
||||||
result.GetRequiredValue(jpegArgument),
|
result.GetRequiredValue(jpegArgument),
|
||||||
result.GetRequiredValue(outputArgument),
|
result.GetRequiredValue(outputArgument),
|
||||||
result.GetValue(descriptionOption),
|
result.GetValue(descriptionOption),
|
||||||
|
result.GetValue(jsonOption),
|
||||||
result.GetValue(titleOption)));
|
result.GetValue(titleOption)));
|
||||||
return createCommand;
|
return createCommand;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -26,8 +26,10 @@ ragephoto-cli get PGTA5123456789 json
|
||||||
# Getting Title
|
# Getting Title
|
||||||
ragephoto-cli get PGTA5123456789 title
|
ragephoto-cli get PGTA5123456789 title
|
||||||
|
|
||||||
# Replacing JPEG (Patching Signature is required after)
|
# Replacing JPEG
|
||||||
ragephoto-cli set PGTA5123456789 --jpeg photo.jpg
|
ragephoto-cli set PGTA5123456789 --jpeg photo.jpg
|
||||||
|
|
||||||
|
# Patching Signature
|
||||||
ragephoto-cli set PGTA5123456789 --json "$(ragephoto-cli get PGTA5123456789 json \
|
ragephoto-cli set PGTA5123456789 --json "$(ragephoto-cli get PGTA5123456789 json \
|
||||||
| jq -c ".sign = $(ragephoto-cli get PGTA5123456789 sign)")"
|
| jq -c ".sign = $(ragephoto-cli get PGTA5123456789 sign)")"
|
||||||
|
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue