|
| 1 | +using Realms; |
| 2 | +using Realms.Exceptions; |
| 3 | +using CollectionDowngrader.LazerSchema; |
| 4 | + |
| 5 | +namespace CollectionDowngrader |
| 6 | +{ |
| 7 | + class CollectionDowngrader |
| 8 | + { |
| 9 | + const int LazerSchemaVersion = 26; |
| 10 | + |
| 11 | + private static int Main(string[] args) |
| 12 | + { |
| 13 | + String realmFile, outputFile; |
| 14 | + FileStream outStream; |
| 15 | + BinaryWriter binWriter; |
| 16 | + Realm db; |
| 17 | + DateTimeOffset lastMod; |
| 18 | + BeatmapCollection? lastModCollection; |
| 19 | + |
| 20 | + if (args.Length != 2) |
| 21 | + { |
| 22 | + Console.Error.WriteLine("Usage: CollectionDowngrader <path to osu! (lazer) client.realm> " + |
| 23 | + "<output osu! (stable) collection.db path>"); |
| 24 | + |
| 25 | + return 1; |
| 26 | + } |
| 27 | + |
| 28 | + realmFile = args[0]; |
| 29 | + outputFile = args[1]; |
| 30 | + |
| 31 | + if (File.Exists(realmFile)) { |
| 32 | + Console.WriteLine("Found realm file."); |
| 33 | + } else { |
| 34 | + Console.Error.WriteLine("Realm file does not exist, stop."); |
| 35 | + |
| 36 | + return 1; |
| 37 | + } |
| 38 | + |
| 39 | + if (File.Exists(outputFile)) |
| 40 | + { |
| 41 | + Console.Error.WriteLine("Output file already exists, aborting."); |
| 42 | + |
| 43 | + return 1; |
| 44 | + } |
| 45 | + |
| 46 | + RealmConfiguration config = new(realmFile) |
| 47 | + { |
| 48 | + IsReadOnly = true, |
| 49 | + SchemaVersion = LazerSchemaVersion |
| 50 | + }; |
| 51 | + |
| 52 | + config.Schema = new[] { |
| 53 | + typeof(Beatmap), |
| 54 | + typeof(BeatmapCollection), |
| 55 | + typeof(BeatmapDifficulty), |
| 56 | + typeof(BeatmapMetadata), |
| 57 | + typeof(BeatmapSet), |
| 58 | + typeof(BeatmapUserSettings), |
| 59 | + typeof(RealmFile), |
| 60 | + typeof(RealmNamedFileUsage), |
| 61 | + typeof(RealmUser), |
| 62 | + typeof(Ruleset), |
| 63 | + typeof(ModPreset) |
| 64 | + }; |
| 65 | + |
| 66 | + try |
| 67 | + { |
| 68 | + db = Realm.GetInstance(config); |
| 69 | + } |
| 70 | + catch (RealmException re) |
| 71 | + { |
| 72 | + Console.Error.WriteLine($"Error opening database:\n\n{re.Message}"); |
| 73 | + if (re.Message.Contains("is less than last set version")) |
| 74 | + { |
| 75 | + Console.Error.WriteLine("It seemed like the specified osu! (lazer) database is in a new format " + |
| 76 | + "which is not compatible with this version of CollectionDowngrader."); |
| 77 | + Console.Error.WriteLine("\nYou can go check the project page to see if there's a new release, " + |
| 78 | + "or file an Issue on GitHub to let me know it needs updating."); |
| 79 | + } |
| 80 | + |
| 81 | + return 1; |
| 82 | + } |
| 83 | + |
| 84 | + Console.WriteLine("The specified osu! (lazer) database is loaded successfully."); |
| 85 | + |
| 86 | + List<BeatmapCollection> collections = db.All<BeatmapCollection>().ToList(); |
| 87 | + int collectionCount = collections.Count; |
| 88 | + |
| 89 | + Console.WriteLine($"Found {collectionCount} collections in the database."); |
| 90 | + |
| 91 | + try |
| 92 | + { |
| 93 | + outStream = File.Open(outputFile, FileMode.CreateNew, FileAccess.Write); |
| 94 | + } |
| 95 | + catch (IOException ioe) |
| 96 | + { |
| 97 | + Console.Error.WriteLine($"Cannot create output file for writing: {ioe.Message}"); |
| 98 | + |
| 99 | + return 1; |
| 100 | + } |
| 101 | + |
| 102 | + Console.WriteLine("Output file is created successfully, now start writing data."); |
| 103 | + |
| 104 | + binWriter = new BinaryWriter(outStream); |
| 105 | + |
| 106 | + // find the last modified collection and its modification date |
| 107 | + lastModCollection = collections.MaxBy(i => i.LastModified.Ticks); |
| 108 | + lastMod = lastModCollection is null ? DateTimeOffset.Now : lastModCollection.LastModified; |
| 109 | + |
| 110 | + binWriter.Write((int) lastMod.Ticks); // last modification date |
| 111 | + binWriter.Write(collectionCount); // collection count |
| 112 | + |
| 113 | + foreach (BeatmapCollection collection in collections) |
| 114 | + { |
| 115 | + binWriter.Write((byte) 0x0b); |
| 116 | + binWriter.Write(collection.Name); // collection name |
| 117 | + binWriter.Write(collection.BeatmapMD5Hashes.Count); // beatmap count |
| 118 | + |
| 119 | + foreach (string hash in collection.BeatmapMD5Hashes) |
| 120 | + { |
| 121 | + binWriter.Write((byte) 0x0b); |
| 122 | + binWriter.Write(hash); // beatmap MD5 hash |
| 123 | + } |
| 124 | + } |
| 125 | + |
| 126 | + binWriter.Close(); |
| 127 | + outStream.Close(); |
| 128 | + |
| 129 | + Console.WriteLine("Everything is OK."); |
| 130 | + |
| 131 | + return 0; |
| 132 | + } |
| 133 | + } |
| 134 | +} |
0 commit comments