osu-play 1.0.2 → 1.0.3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/bin/osu-play.js +1 -1
- package/dist/{mod.js → index.js} +1 -1
- package/dist/src/cli/main.js.map +1 -0
- package/index.ts +1 -0
- package/package.json +6 -3
- package/src/cli/main.ts +73 -0
- package/src/mod.ts +2 -0
- package/src/realm/mod.ts +54 -0
- package/src/realm/schema/beatmap.ts +85 -0
- package/src/realm/schema/beatmapMetadata.ts +33 -0
- package/src/realm/schema/beatmapSet.ts +36 -0
- package/src/realm/schema/mod.ts +7 -0
- package/src/realm/schema/realmFile.ts +15 -0
- package/src/realm/schema/realmNamedFileUsage.ts +19 -0
- package/src/realm/schema/realmUser.ts +21 -0
- package/src/utils/mod.ts +81 -0
- package/dist/cli/main.cjs +0 -400
- package/dist/cli/main.cjs.map +0 -1
- package/dist/cli/main.d.cts +0 -3
- package/dist/cli/main.js.map +0 -1
- package/dist/mod.cjs +0 -367
- package/dist/mod.cjs.map +0 -1
- package/dist/mod.d.ts +0 -121
- /package/dist/{mod.d.cts → index.d.ts} +0 -0
- /package/dist/{mod.js.map → index.js.map} +0 -0
- /package/dist/{cli → src/cli}/main.d.ts +0 -0
- /package/dist/{cli → src/cli}/main.js +0 -0
package/bin/osu-play.js
CHANGED
package/dist/{mod.js → index.js}
RENAMED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../../../src/cli/main.ts","../../../src/realm/schema/beatmap.ts","../../../src/realm/schema/beatmapMetadata.ts","../../../src/realm/schema/beatmapSet.ts","../../../src/realm/schema/realmFile.ts","../../../src/realm/schema/realmUser.ts","../../../src/realm/schema/realmNamedFileUsage.ts","../../../src/utils/mod.ts","../../../src/realm/mod.ts"],"sourcesContent":["import path from \"node:path\";\nimport { existsSync } from \"node:fs\";\nimport { execSync } from \"node:child_process\";\n\nimport Realm from \"realm\";\nimport prompts from \"prompts\";\nimport { BeatmapSet } from \"../realm/schema/mod.js\";\nimport { getConfigDir, getRealmDBPath } from \"../utils/mod.js\";\nimport { getLazerDB, getNamedFileHash, hashedFilePath } from \"../realm/mod.js\";\n\nexport async function main() {\n console.log(\"[INFO] OSU!list\");\n\n const realmDBPath = getRealmDBPath(\n path.join(getConfigDir() || \".\", \"osu-play\"),\n );\n\n if (realmDBPath == null) {\n console.log(\"[ERROR] Realm DB not found\");\n process.exit(1);\n }\n\n const currentSchema = Realm.schemaVersion(realmDBPath);\n console.log(`currentSchema: ${currentSchema}`);\n\n Realm.flags.ALLOW_CLEAR_TEST_STATE = true;\n\n const realm: Realm = await getLazerDB(realmDBPath);\n\n console.log(`realm.isClosed: ${realm.isClosed}`);\n\n const beatmapSets = realm.objects(BeatmapSet);\n\n console.log(`beatmaps: ${beatmapSets.length}`);\n\n // Get the map index from the user\n const selectedBeatmapSet = (\n await prompts({\n type: \"autocomplete\",\n name: \"beatmapSet\",\n message: \"Which map do you want to play:\",\n choices: beatmapSets.map((beatmapSet) => {\n const meta = beatmapSet.Beatmaps[0].Metadata;\n return {\n title:\n `${meta.Title} : ${meta.Artist} - ${meta.TitleUnicode} : ${meta.ArtistUnicode}`,\n value: beatmapSet,\n };\n }),\n })\n ).beatmapSet;\n\n console.log(`Map : ${selectedBeatmapSet.Beatmaps[0].Metadata.Title}`);\n const fileName = selectedBeatmapSet.Beatmaps[0].Metadata.AudioFile;\n const fileHash = fileName\n ? getNamedFileHash(fileName, selectedBeatmapSet)\n : undefined;\n const filePath = fileHash ? hashedFilePath(fileHash) : undefined;\n if (filePath && existsSync(filePath)) {\n console.log(`File exists: ${filePath}`);\n } else {\n console.log(`File does not exist: ${filePath}`);\n }\n\n // Open file using exo-open.\n console.log(`Playing file ${selectedBeatmapSet.Beatmaps[0].Metadata.Title}`);\n filePath && execSync(`exo-open ${filePath}`);\n\n realm.close();\n console.log(`realm.isClosed: ${realm.isClosed}`);\n\n // Realm.clearTestState();\n}\n","import Realm from \"realm\";\nimport type { ObjectSchema } from \"realm\";\nimport { BeatmapMetadata } from \"./beatmapMetadata.js\";\n\nexport class Beatmap extends Realm.Object<Beatmap> {\n ID!: string;\n DifficultyName?: string;\n Ruleset!: any;\n Difficulty!: any;\n Metadata!: BeatmapMetadata;\n UserSettings!: any;\n BeatmapSet!: any;\n Status!: number;\n OnlineID!: number;\n Length!: number;\n BPM!: number;\n Hash?: string;\n StarRating!: number;\n MD5Hash?: string;\n OnlineMD5Hash?: string;\n LastLocalUpdate?: Date;\n LastOnlineUpdate?: Date;\n Hidden!: boolean;\n AudioLeadIn!: number;\n StackLeniency!: number;\n SpecialStyle!: boolean;\n LetterboxInBreaks!: boolean;\n WidescreenStoryboard!: boolean;\n EpilepsyWarning!: boolean;\n SamplesMatchPlaybackRate!: boolean;\n LastPlayed?: Date;\n DistanceSpacing!: number;\n BeatDivisor!: number;\n GridSize!: number;\n TimelineZoom!: number;\n EditorTimestamp?: number;\n CountdownOffset!: number;\n\n static schema: ObjectSchema = {\n name: \"Beatmap\",\n primaryKey: \"ID\",\n properties: {\n ID: { type: \"uuid\", default: \"\" },\n DifficultyName: { type: \"string\", default: \"\", optional: true },\n // Ruleset: { type: \"object\", objectType: \"Ruleset\", default: null },\n // Difficulty: { type: \"object\", objectType: \"BeatmapDifficulty\", default: null },\n Metadata: {\n type: \"object\",\n objectType: \"BeatmapMetadata\",\n default: null,\n },\n // UserSettings: { type: \"object\", objectType: \"BeatmapUserSettings\", default: null },\n BeatmapSet: { type: \"object\", objectType: \"BeatmapSet\", default: null },\n Status: { type: \"int\", default: -3 },\n OnlineID: { type: \"int\", default: -1 },\n Length: { type: \"double\", default: 0 },\n BPM: { type: \"double\", default: 0 },\n Hash: { type: \"string\", default: \"\", optional: true },\n StarRating: { type: \"double\", default: -1 },\n MD5Hash: { type: \"string\", default: \"\", optional: true },\n OnlineMD5Hash: {\n type: \"string\",\n default: \"\",\n optional: true,\n },\n LastLocalUpdate: { type: \"date\", optional: true },\n LastOnlineUpdate: { type: \"date\", optional: true },\n Hidden: { type: \"bool\", default: false },\n AudioLeadIn: { type: \"double\", default: 0 },\n StackLeniency: { type: \"float\", default: 0.7 },\n SpecialStyle: { type: \"bool\", default: false },\n LetterboxInBreaks: { type: \"bool\", default: false },\n WidescreenStoryboard: { type: \"bool\", default: false },\n EpilepsyWarning: { type: \"bool\", default: false },\n SamplesMatchPlaybackRate: { type: \"bool\", default: false },\n LastPlayed: { type: \"date\", optional: true },\n DistanceSpacing: { type: \"double\", default: 0 },\n BeatDivisor: { type: \"int\", default: 0 },\n GridSize: { type: \"int\", default: 0 },\n TimelineZoom: { type: \"double\", default: 0 },\n EditorTimestamp: { type: \"double\", optional: true },\n CountdownOffset: { type: \"int\", default: 0 },\n },\n };\n}\n","import Realm from \"realm\";\nimport type { ObjectSchema } from \"realm\";\nimport { RealmUser } from \"./realmUser.js\";\n\nexport class BeatmapMetadata extends Realm.Object<BeatmapMetadata> {\n Title?: string;\n TitleUnicode?: string;\n Artist?: string;\n ArtistUnicode?: string;\n Author?: RealmUser;\n Source?: string;\n Tags?: string;\n PreviewTime?: number;\n AudioFile?: string;\n BackgroundFile?: string;\n\n static schema: ObjectSchema = {\n name: \"BeatmapMetadata\",\n properties: {\n Title: { type: \"string\", default: \"\", optional: true },\n TitleUnicode: { type: \"string\", default: \"\", optional: true },\n Artist: { type: \"string\", default: \"\", optional: true },\n ArtistUnicode: { type: \"string\", default: \"\", optional: true },\n Author: { type: \"object\", objectType: \"RealmUser\", default: null },\n Source: { type: \"string\", default: \"\", optional: true },\n Tags: { type: \"string\", default: \"\", optional: true },\n PreviewTime: { type: \"int\", default: 0 },\n AudioFile: { type: \"string\", default: \"\", optional: true },\n BackgroundFile: { type: \"string\", default: \"\", optional: true },\n },\n };\n}\n\n","import Realm from \"realm\";\nimport type { ObjectSchema } from \"realm\";\nimport { Beatmap } from \"./beatmap.js\";\nimport { RealmNamedFileUsage } from \"./realmNamedFileUsage.js\";\n\nexport class BeatmapSet extends Realm.Object<BeatmapSet> {\n ID!: string;\n OnlineID!: number;\n DateAdded!: Date;\n DateSubmitted?: Date;\n DateRanked?: Date;\n Beatmaps!: Array<Beatmap>;\n Files!: Array<RealmNamedFileUsage>;\n Status!: number;\n DeletePending!: boolean;\n Hash?: string;\n Protected!: boolean;\n\n static schema: ObjectSchema = {\n name: \"BeatmapSet\",\n primaryKey: \"ID\",\n properties: {\n ID: { type: \"uuid\", default: \"\" },\n OnlineID: { type: \"int\", default: -1 },\n DateAdded: { type: \"date\" },\n DateSubmitted: { type: \"date\", optional: true },\n DateRanked: { type: \"date\", optional: true },\n Beatmaps: { type: \"list\", objectType: \"Beatmap\", default: [] },\n Files: { type: \"list\", objectType: \"RealmNamedFileUsage\", default: [] },\n Status: { type: \"int\", default: -3 },\n DeletePending: { type: \"bool\", default: false },\n Hash: { type: \"string\", default: \"\", optional: true },\n Protected: { type: \"bool\", default: false },\n },\n };\n}\n","import Realm from \"realm\";\nimport type { ObjectSchema } from \"realm\";\n\nexport class RealmFile extends Realm.Object<RealmFile> {\n Hash?: string;\n\n static schema: ObjectSchema = {\n name: \"File\",\n primaryKey: \"Hash\",\n properties: {\n Hash: { type: \"string\", default: \"\", optional: true },\n },\n };\n}\n\n","import Realm from \"realm\";\nimport type { ObjectSchema } from \"realm\";\n\nexport class RealmUser extends Realm.Object<RealmUser> {\n OnlineID!: number;\n Username?: string;\n CountryCode?: string;\n\n static embedded = true;\n\n static schema: ObjectSchema = {\n name: \"RealmUser\",\n embedded: true,\n properties: {\n OnlineID: { type: \"int\", default: 1 },\n Username: { type: \"string\", default: \"\", optional: true },\n CountryCode: { type: \"string\", optional: true },\n },\n };\n}\n\n","import Realm from \"realm\";\nimport type { ObjectSchema } from \"realm\";\nimport { RealmFile } from \"./realmFile.js\";\n\nexport class RealmNamedFileUsage extends Realm.Object<RealmNamedFileUsage> {\n File!: RealmFile;\n Filename?: string;\n\n static embedded = true;\n\n static schema: ObjectSchema = {\n name: \"RealmNamedFileUsage\",\n embedded: true,\n properties: {\n File: \"File\",\n Filename: { type: \"string\", optional: true },\n },\n };\n}\n","import path from \"node:path\";\nimport { copyFileSync, existsSync, mkdirSync } from \"node:fs\";\n\nexport function getDataDir(): string | null {\n switch (process.platform) {\n case \"linux\":\n case \"openbsd\":\n case \"freebsd\": {\n const xdg = process.env[\"XDG_DATA_HOME\"];\n if (xdg) return xdg;\n const home = process.env[\"HOME\"];\n if (home) return path.join(home, \".local\", \"share\");\n break;\n }\n\n case \"darwin\": {\n const home = process.env[\"HOME\"];\n if (home) return path.join(home, \"Library\", \"Application Support\");\n break;\n }\n\n case \"win32\":\n return process.env[\"LOCALAPPDATA\"] ?? null;\n }\n\n return null;\n}\n\nexport function getConfigDir(): string | null {\n switch (process.platform) {\n case \"openbsd\":\n case \"freebsd\":\n case \"linux\": {\n const xdg = process.env[\"XDG_CONFIG_HOME\"];\n if (xdg) return xdg;\n const home = process.env[\"HOME\"];\n if (home) return path.join(home, \".config\");\n break;\n }\n\n case \"darwin\": {\n const home = process.env[\"HOME\"];\n if (home) return path.join(home, \"Library\", \"Preferences\");\n break;\n }\n\n case \"win32\":\n return process.env[\"APPDATA\"] ?? null;\n }\n\n return null;\n}\n\n/**\n * Get Realm for the app, import to the config if it doesn't exist\n */\nexport function getRealmDBPath(\n appConfigDir: string,\n osuDataDir?: string,\n reload: boolean = false,\n) {\n const localDBPath = path.join(appConfigDir, \"client.realm\");\n if (!reload && existsSync(localDBPath)) return localDBPath;\n\n const osuDBPath = path.join(\n osuDataDir || getDataDir()! || \".\",\n \"osu\",\n \"client.realm\",\n );\n if (existsSync(osuDBPath)) {\n console.log(\n `[getRealmDBPath]: ${osuDBPath} is being imported from osu!lazer to ${localDBPath}`,\n );\n mkdirSync(appConfigDir);\n copyFileSync(osuDBPath, localDBPath);\n return localDBPath;\n } else {\n console.log(`[getRealmDBPath]: ${osuDBPath} not found`);\n return null;\n }\n}\n","import Realm from \"realm\";\nimport path from \"node:path\";\nimport { getDataDir } from \"../utils/mod.js\";\nimport {\n Beatmap,\n BeatmapMetadata,\n BeatmapSet,\n RealmFile,\n RealmNamedFileUsage,\n RealmUser,\n} from \"./schema/mod.js\";\n\nexport const getLazerDB = async (realmDBPath: string) => {\n const realm = await Realm.open({\n schema: [\n BeatmapSet,\n RealmFile,\n RealmNamedFileUsage,\n Beatmap,\n BeatmapMetadata,\n RealmUser,\n ],\n path: realmDBPath,\n schemaVersion: 36,\n onMigration: (oldRealm, newRealm) => {\n console.log(\n `[onMigration]: Migrating ${oldRealm.path} - ${oldRealm.schemaVersion} -> ${newRealm.path} - ${newRealm.schemaVersion}`,\n );\n },\n });\n\n return realm;\n};\n\nexport const hashedFilePath = (hash: string) => {\n const dataDir = getDataDir();\n if (!dataDir) return null;\n return path.join(\n dataDir,\n \"osu\",\n \"files\",\n hash.slice(0, 1),\n hash.slice(0, 2),\n hash,\n );\n};\n\nexport const getNamedFileHash = (fileName: string, beatmapSet: BeatmapSet) => {\n const files = beatmapSet.Files;\n for (const file of files) {\n if (file.Filename == fileName) return file.File.Hash;\n }\n return undefined;\n};\n"],"mappings":"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","names":["path","existsSync","Realm","Realm","Realm","Realm","Realm","Realm","Realm","path","Realm","path","path","Realm","existsSync"]}
|
package/index.ts
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export * from "./src/mod.js";
|
package/package.json
CHANGED
|
@@ -1,18 +1,21 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "osu-play",
|
|
3
|
-
"version": "1.0.
|
|
4
|
-
"description": "Play
|
|
3
|
+
"version": "1.0.3",
|
|
4
|
+
"description": "Play music from your osu!lazer beatmaps from the terminal.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "bin/osu-play.js",
|
|
7
|
+
"module": "index.ts",
|
|
8
|
+
"types": "dist/index.d.ts",
|
|
7
9
|
"files": [
|
|
8
10
|
"bin",
|
|
9
11
|
"dist",
|
|
12
|
+
"src",
|
|
13
|
+
"index.ts",
|
|
10
14
|
"package.json",
|
|
11
15
|
"README.md",
|
|
12
16
|
"tsconfig.json",
|
|
13
17
|
"LICENSE"
|
|
14
18
|
],
|
|
15
|
-
"types": "dist/index.d.ts",
|
|
16
19
|
"bin": {
|
|
17
20
|
"osu-play": "./bin/osu-play.js"
|
|
18
21
|
},
|
package/src/cli/main.ts
ADDED
|
@@ -0,0 +1,73 @@
|
|
|
1
|
+
import path from "node:path";
|
|
2
|
+
import { existsSync } from "node:fs";
|
|
3
|
+
import { execSync } from "node:child_process";
|
|
4
|
+
|
|
5
|
+
import Realm from "realm";
|
|
6
|
+
import prompts from "prompts";
|
|
7
|
+
import { BeatmapSet } from "../realm/schema/mod.js";
|
|
8
|
+
import { getConfigDir, getRealmDBPath } from "../utils/mod.js";
|
|
9
|
+
import { getLazerDB, getNamedFileHash, hashedFilePath } from "../realm/mod.js";
|
|
10
|
+
|
|
11
|
+
export async function main() {
|
|
12
|
+
console.log("[INFO] OSU!list");
|
|
13
|
+
|
|
14
|
+
const realmDBPath = getRealmDBPath(
|
|
15
|
+
path.join(getConfigDir() || ".", "osu-play"),
|
|
16
|
+
);
|
|
17
|
+
|
|
18
|
+
if (realmDBPath == null) {
|
|
19
|
+
console.log("[ERROR] Realm DB not found");
|
|
20
|
+
process.exit(1);
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
const currentSchema = Realm.schemaVersion(realmDBPath);
|
|
24
|
+
console.log(`currentSchema: ${currentSchema}`);
|
|
25
|
+
|
|
26
|
+
Realm.flags.ALLOW_CLEAR_TEST_STATE = true;
|
|
27
|
+
|
|
28
|
+
const realm: Realm = await getLazerDB(realmDBPath);
|
|
29
|
+
|
|
30
|
+
console.log(`realm.isClosed: ${realm.isClosed}`);
|
|
31
|
+
|
|
32
|
+
const beatmapSets = realm.objects(BeatmapSet);
|
|
33
|
+
|
|
34
|
+
console.log(`beatmaps: ${beatmapSets.length}`);
|
|
35
|
+
|
|
36
|
+
// Get the map index from the user
|
|
37
|
+
const selectedBeatmapSet = (
|
|
38
|
+
await prompts({
|
|
39
|
+
type: "autocomplete",
|
|
40
|
+
name: "beatmapSet",
|
|
41
|
+
message: "Which map do you want to play:",
|
|
42
|
+
choices: beatmapSets.map((beatmapSet) => {
|
|
43
|
+
const meta = beatmapSet.Beatmaps[0].Metadata;
|
|
44
|
+
return {
|
|
45
|
+
title:
|
|
46
|
+
`${meta.Title} : ${meta.Artist} - ${meta.TitleUnicode} : ${meta.ArtistUnicode}`,
|
|
47
|
+
value: beatmapSet,
|
|
48
|
+
};
|
|
49
|
+
}),
|
|
50
|
+
})
|
|
51
|
+
).beatmapSet;
|
|
52
|
+
|
|
53
|
+
console.log(`Map : ${selectedBeatmapSet.Beatmaps[0].Metadata.Title}`);
|
|
54
|
+
const fileName = selectedBeatmapSet.Beatmaps[0].Metadata.AudioFile;
|
|
55
|
+
const fileHash = fileName
|
|
56
|
+
? getNamedFileHash(fileName, selectedBeatmapSet)
|
|
57
|
+
: undefined;
|
|
58
|
+
const filePath = fileHash ? hashedFilePath(fileHash) : undefined;
|
|
59
|
+
if (filePath && existsSync(filePath)) {
|
|
60
|
+
console.log(`File exists: ${filePath}`);
|
|
61
|
+
} else {
|
|
62
|
+
console.log(`File does not exist: ${filePath}`);
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
// Open file using exo-open.
|
|
66
|
+
console.log(`Playing file ${selectedBeatmapSet.Beatmaps[0].Metadata.Title}`);
|
|
67
|
+
filePath && execSync(`exo-open ${filePath}`);
|
|
68
|
+
|
|
69
|
+
realm.close();
|
|
70
|
+
console.log(`realm.isClosed: ${realm.isClosed}`);
|
|
71
|
+
|
|
72
|
+
// Realm.clearTestState();
|
|
73
|
+
}
|
package/src/mod.ts
ADDED
package/src/realm/mod.ts
ADDED
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
import Realm from "realm";
|
|
2
|
+
import path from "node:path";
|
|
3
|
+
import { getDataDir } from "../utils/mod.js";
|
|
4
|
+
import {
|
|
5
|
+
Beatmap,
|
|
6
|
+
BeatmapMetadata,
|
|
7
|
+
BeatmapSet,
|
|
8
|
+
RealmFile,
|
|
9
|
+
RealmNamedFileUsage,
|
|
10
|
+
RealmUser,
|
|
11
|
+
} from "./schema/mod.js";
|
|
12
|
+
|
|
13
|
+
export const getLazerDB = async (realmDBPath: string) => {
|
|
14
|
+
const realm = await Realm.open({
|
|
15
|
+
schema: [
|
|
16
|
+
BeatmapSet,
|
|
17
|
+
RealmFile,
|
|
18
|
+
RealmNamedFileUsage,
|
|
19
|
+
Beatmap,
|
|
20
|
+
BeatmapMetadata,
|
|
21
|
+
RealmUser,
|
|
22
|
+
],
|
|
23
|
+
path: realmDBPath,
|
|
24
|
+
schemaVersion: 36,
|
|
25
|
+
onMigration: (oldRealm, newRealm) => {
|
|
26
|
+
console.log(
|
|
27
|
+
`[onMigration]: Migrating ${oldRealm.path} - ${oldRealm.schemaVersion} -> ${newRealm.path} - ${newRealm.schemaVersion}`,
|
|
28
|
+
);
|
|
29
|
+
},
|
|
30
|
+
});
|
|
31
|
+
|
|
32
|
+
return realm;
|
|
33
|
+
};
|
|
34
|
+
|
|
35
|
+
export const hashedFilePath = (hash: string) => {
|
|
36
|
+
const dataDir = getDataDir();
|
|
37
|
+
if (!dataDir) return null;
|
|
38
|
+
return path.join(
|
|
39
|
+
dataDir,
|
|
40
|
+
"osu",
|
|
41
|
+
"files",
|
|
42
|
+
hash.slice(0, 1),
|
|
43
|
+
hash.slice(0, 2),
|
|
44
|
+
hash,
|
|
45
|
+
);
|
|
46
|
+
};
|
|
47
|
+
|
|
48
|
+
export const getNamedFileHash = (fileName: string, beatmapSet: BeatmapSet) => {
|
|
49
|
+
const files = beatmapSet.Files;
|
|
50
|
+
for (const file of files) {
|
|
51
|
+
if (file.Filename == fileName) return file.File.Hash;
|
|
52
|
+
}
|
|
53
|
+
return undefined;
|
|
54
|
+
};
|
|
@@ -0,0 +1,85 @@
|
|
|
1
|
+
import Realm from "realm";
|
|
2
|
+
import type { ObjectSchema } from "realm";
|
|
3
|
+
import { BeatmapMetadata } from "./beatmapMetadata.js";
|
|
4
|
+
|
|
5
|
+
export class Beatmap extends Realm.Object<Beatmap> {
|
|
6
|
+
ID!: string;
|
|
7
|
+
DifficultyName?: string;
|
|
8
|
+
Ruleset!: any;
|
|
9
|
+
Difficulty!: any;
|
|
10
|
+
Metadata!: BeatmapMetadata;
|
|
11
|
+
UserSettings!: any;
|
|
12
|
+
BeatmapSet!: any;
|
|
13
|
+
Status!: number;
|
|
14
|
+
OnlineID!: number;
|
|
15
|
+
Length!: number;
|
|
16
|
+
BPM!: number;
|
|
17
|
+
Hash?: string;
|
|
18
|
+
StarRating!: number;
|
|
19
|
+
MD5Hash?: string;
|
|
20
|
+
OnlineMD5Hash?: string;
|
|
21
|
+
LastLocalUpdate?: Date;
|
|
22
|
+
LastOnlineUpdate?: Date;
|
|
23
|
+
Hidden!: boolean;
|
|
24
|
+
AudioLeadIn!: number;
|
|
25
|
+
StackLeniency!: number;
|
|
26
|
+
SpecialStyle!: boolean;
|
|
27
|
+
LetterboxInBreaks!: boolean;
|
|
28
|
+
WidescreenStoryboard!: boolean;
|
|
29
|
+
EpilepsyWarning!: boolean;
|
|
30
|
+
SamplesMatchPlaybackRate!: boolean;
|
|
31
|
+
LastPlayed?: Date;
|
|
32
|
+
DistanceSpacing!: number;
|
|
33
|
+
BeatDivisor!: number;
|
|
34
|
+
GridSize!: number;
|
|
35
|
+
TimelineZoom!: number;
|
|
36
|
+
EditorTimestamp?: number;
|
|
37
|
+
CountdownOffset!: number;
|
|
38
|
+
|
|
39
|
+
static schema: ObjectSchema = {
|
|
40
|
+
name: "Beatmap",
|
|
41
|
+
primaryKey: "ID",
|
|
42
|
+
properties: {
|
|
43
|
+
ID: { type: "uuid", default: "" },
|
|
44
|
+
DifficultyName: { type: "string", default: "", optional: true },
|
|
45
|
+
// Ruleset: { type: "object", objectType: "Ruleset", default: null },
|
|
46
|
+
// Difficulty: { type: "object", objectType: "BeatmapDifficulty", default: null },
|
|
47
|
+
Metadata: {
|
|
48
|
+
type: "object",
|
|
49
|
+
objectType: "BeatmapMetadata",
|
|
50
|
+
default: null,
|
|
51
|
+
},
|
|
52
|
+
// UserSettings: { type: "object", objectType: "BeatmapUserSettings", default: null },
|
|
53
|
+
BeatmapSet: { type: "object", objectType: "BeatmapSet", default: null },
|
|
54
|
+
Status: { type: "int", default: -3 },
|
|
55
|
+
OnlineID: { type: "int", default: -1 },
|
|
56
|
+
Length: { type: "double", default: 0 },
|
|
57
|
+
BPM: { type: "double", default: 0 },
|
|
58
|
+
Hash: { type: "string", default: "", optional: true },
|
|
59
|
+
StarRating: { type: "double", default: -1 },
|
|
60
|
+
MD5Hash: { type: "string", default: "", optional: true },
|
|
61
|
+
OnlineMD5Hash: {
|
|
62
|
+
type: "string",
|
|
63
|
+
default: "",
|
|
64
|
+
optional: true,
|
|
65
|
+
},
|
|
66
|
+
LastLocalUpdate: { type: "date", optional: true },
|
|
67
|
+
LastOnlineUpdate: { type: "date", optional: true },
|
|
68
|
+
Hidden: { type: "bool", default: false },
|
|
69
|
+
AudioLeadIn: { type: "double", default: 0 },
|
|
70
|
+
StackLeniency: { type: "float", default: 0.7 },
|
|
71
|
+
SpecialStyle: { type: "bool", default: false },
|
|
72
|
+
LetterboxInBreaks: { type: "bool", default: false },
|
|
73
|
+
WidescreenStoryboard: { type: "bool", default: false },
|
|
74
|
+
EpilepsyWarning: { type: "bool", default: false },
|
|
75
|
+
SamplesMatchPlaybackRate: { type: "bool", default: false },
|
|
76
|
+
LastPlayed: { type: "date", optional: true },
|
|
77
|
+
DistanceSpacing: { type: "double", default: 0 },
|
|
78
|
+
BeatDivisor: { type: "int", default: 0 },
|
|
79
|
+
GridSize: { type: "int", default: 0 },
|
|
80
|
+
TimelineZoom: { type: "double", default: 0 },
|
|
81
|
+
EditorTimestamp: { type: "double", optional: true },
|
|
82
|
+
CountdownOffset: { type: "int", default: 0 },
|
|
83
|
+
},
|
|
84
|
+
};
|
|
85
|
+
}
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
import Realm from "realm";
|
|
2
|
+
import type { ObjectSchema } from "realm";
|
|
3
|
+
import { RealmUser } from "./realmUser.js";
|
|
4
|
+
|
|
5
|
+
export class BeatmapMetadata extends Realm.Object<BeatmapMetadata> {
|
|
6
|
+
Title?: string;
|
|
7
|
+
TitleUnicode?: string;
|
|
8
|
+
Artist?: string;
|
|
9
|
+
ArtistUnicode?: string;
|
|
10
|
+
Author?: RealmUser;
|
|
11
|
+
Source?: string;
|
|
12
|
+
Tags?: string;
|
|
13
|
+
PreviewTime?: number;
|
|
14
|
+
AudioFile?: string;
|
|
15
|
+
BackgroundFile?: string;
|
|
16
|
+
|
|
17
|
+
static schema: ObjectSchema = {
|
|
18
|
+
name: "BeatmapMetadata",
|
|
19
|
+
properties: {
|
|
20
|
+
Title: { type: "string", default: "", optional: true },
|
|
21
|
+
TitleUnicode: { type: "string", default: "", optional: true },
|
|
22
|
+
Artist: { type: "string", default: "", optional: true },
|
|
23
|
+
ArtistUnicode: { type: "string", default: "", optional: true },
|
|
24
|
+
Author: { type: "object", objectType: "RealmUser", default: null },
|
|
25
|
+
Source: { type: "string", default: "", optional: true },
|
|
26
|
+
Tags: { type: "string", default: "", optional: true },
|
|
27
|
+
PreviewTime: { type: "int", default: 0 },
|
|
28
|
+
AudioFile: { type: "string", default: "", optional: true },
|
|
29
|
+
BackgroundFile: { type: "string", default: "", optional: true },
|
|
30
|
+
},
|
|
31
|
+
};
|
|
32
|
+
}
|
|
33
|
+
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
import Realm from "realm";
|
|
2
|
+
import type { ObjectSchema } from "realm";
|
|
3
|
+
import { Beatmap } from "./beatmap.js";
|
|
4
|
+
import { RealmNamedFileUsage } from "./realmNamedFileUsage.js";
|
|
5
|
+
|
|
6
|
+
export class BeatmapSet extends Realm.Object<BeatmapSet> {
|
|
7
|
+
ID!: string;
|
|
8
|
+
OnlineID!: number;
|
|
9
|
+
DateAdded!: Date;
|
|
10
|
+
DateSubmitted?: Date;
|
|
11
|
+
DateRanked?: Date;
|
|
12
|
+
Beatmaps!: Array<Beatmap>;
|
|
13
|
+
Files!: Array<RealmNamedFileUsage>;
|
|
14
|
+
Status!: number;
|
|
15
|
+
DeletePending!: boolean;
|
|
16
|
+
Hash?: string;
|
|
17
|
+
Protected!: boolean;
|
|
18
|
+
|
|
19
|
+
static schema: ObjectSchema = {
|
|
20
|
+
name: "BeatmapSet",
|
|
21
|
+
primaryKey: "ID",
|
|
22
|
+
properties: {
|
|
23
|
+
ID: { type: "uuid", default: "" },
|
|
24
|
+
OnlineID: { type: "int", default: -1 },
|
|
25
|
+
DateAdded: { type: "date" },
|
|
26
|
+
DateSubmitted: { type: "date", optional: true },
|
|
27
|
+
DateRanked: { type: "date", optional: true },
|
|
28
|
+
Beatmaps: { type: "list", objectType: "Beatmap", default: [] },
|
|
29
|
+
Files: { type: "list", objectType: "RealmNamedFileUsage", default: [] },
|
|
30
|
+
Status: { type: "int", default: -3 },
|
|
31
|
+
DeletePending: { type: "bool", default: false },
|
|
32
|
+
Hash: { type: "string", default: "", optional: true },
|
|
33
|
+
Protected: { type: "bool", default: false },
|
|
34
|
+
},
|
|
35
|
+
};
|
|
36
|
+
}
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
export { Beatmap } from "./beatmap.js";
|
|
2
|
+
export { BeatmapMetadata } from "./beatmapMetadata.js";
|
|
3
|
+
export { BeatmapSet } from "./beatmapSet.js";
|
|
4
|
+
export { RealmFile } from "./realmFile.js";
|
|
5
|
+
export { RealmUser } from "./realmUser.js";
|
|
6
|
+
export { RealmNamedFileUsage } from "./realmNamedFileUsage.js";
|
|
7
|
+
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import Realm from "realm";
|
|
2
|
+
import type { ObjectSchema } from "realm";
|
|
3
|
+
|
|
4
|
+
export class RealmFile extends Realm.Object<RealmFile> {
|
|
5
|
+
Hash?: string;
|
|
6
|
+
|
|
7
|
+
static schema: ObjectSchema = {
|
|
8
|
+
name: "File",
|
|
9
|
+
primaryKey: "Hash",
|
|
10
|
+
properties: {
|
|
11
|
+
Hash: { type: "string", default: "", optional: true },
|
|
12
|
+
},
|
|
13
|
+
};
|
|
14
|
+
}
|
|
15
|
+
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
import Realm from "realm";
|
|
2
|
+
import type { ObjectSchema } from "realm";
|
|
3
|
+
import { RealmFile } from "./realmFile.js";
|
|
4
|
+
|
|
5
|
+
export class RealmNamedFileUsage extends Realm.Object<RealmNamedFileUsage> {
|
|
6
|
+
File!: RealmFile;
|
|
7
|
+
Filename?: string;
|
|
8
|
+
|
|
9
|
+
static embedded = true;
|
|
10
|
+
|
|
11
|
+
static schema: ObjectSchema = {
|
|
12
|
+
name: "RealmNamedFileUsage",
|
|
13
|
+
embedded: true,
|
|
14
|
+
properties: {
|
|
15
|
+
File: "File",
|
|
16
|
+
Filename: { type: "string", optional: true },
|
|
17
|
+
},
|
|
18
|
+
};
|
|
19
|
+
}
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
import Realm from "realm";
|
|
2
|
+
import type { ObjectSchema } from "realm";
|
|
3
|
+
|
|
4
|
+
export class RealmUser extends Realm.Object<RealmUser> {
|
|
5
|
+
OnlineID!: number;
|
|
6
|
+
Username?: string;
|
|
7
|
+
CountryCode?: string;
|
|
8
|
+
|
|
9
|
+
static embedded = true;
|
|
10
|
+
|
|
11
|
+
static schema: ObjectSchema = {
|
|
12
|
+
name: "RealmUser",
|
|
13
|
+
embedded: true,
|
|
14
|
+
properties: {
|
|
15
|
+
OnlineID: { type: "int", default: 1 },
|
|
16
|
+
Username: { type: "string", default: "", optional: true },
|
|
17
|
+
CountryCode: { type: "string", optional: true },
|
|
18
|
+
},
|
|
19
|
+
};
|
|
20
|
+
}
|
|
21
|
+
|
package/src/utils/mod.ts
ADDED
|
@@ -0,0 +1,81 @@
|
|
|
1
|
+
import path from "node:path";
|
|
2
|
+
import { copyFileSync, existsSync, mkdirSync } from "node:fs";
|
|
3
|
+
|
|
4
|
+
export function getDataDir(): string | null {
|
|
5
|
+
switch (process.platform) {
|
|
6
|
+
case "linux":
|
|
7
|
+
case "openbsd":
|
|
8
|
+
case "freebsd": {
|
|
9
|
+
const xdg = process.env["XDG_DATA_HOME"];
|
|
10
|
+
if (xdg) return xdg;
|
|
11
|
+
const home = process.env["HOME"];
|
|
12
|
+
if (home) return path.join(home, ".local", "share");
|
|
13
|
+
break;
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
case "darwin": {
|
|
17
|
+
const home = process.env["HOME"];
|
|
18
|
+
if (home) return path.join(home, "Library", "Application Support");
|
|
19
|
+
break;
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
case "win32":
|
|
23
|
+
return process.env["LOCALAPPDATA"] ?? null;
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
return null;
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
export function getConfigDir(): string | null {
|
|
30
|
+
switch (process.platform) {
|
|
31
|
+
case "openbsd":
|
|
32
|
+
case "freebsd":
|
|
33
|
+
case "linux": {
|
|
34
|
+
const xdg = process.env["XDG_CONFIG_HOME"];
|
|
35
|
+
if (xdg) return xdg;
|
|
36
|
+
const home = process.env["HOME"];
|
|
37
|
+
if (home) return path.join(home, ".config");
|
|
38
|
+
break;
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
case "darwin": {
|
|
42
|
+
const home = process.env["HOME"];
|
|
43
|
+
if (home) return path.join(home, "Library", "Preferences");
|
|
44
|
+
break;
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
case "win32":
|
|
48
|
+
return process.env["APPDATA"] ?? null;
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
return null;
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
/**
|
|
55
|
+
* Get Realm for the app, import to the config if it doesn't exist
|
|
56
|
+
*/
|
|
57
|
+
export function getRealmDBPath(
|
|
58
|
+
appConfigDir: string,
|
|
59
|
+
osuDataDir?: string,
|
|
60
|
+
reload: boolean = false,
|
|
61
|
+
) {
|
|
62
|
+
const localDBPath = path.join(appConfigDir, "client.realm");
|
|
63
|
+
if (!reload && existsSync(localDBPath)) return localDBPath;
|
|
64
|
+
|
|
65
|
+
const osuDBPath = path.join(
|
|
66
|
+
osuDataDir || getDataDir()! || ".",
|
|
67
|
+
"osu",
|
|
68
|
+
"client.realm",
|
|
69
|
+
);
|
|
70
|
+
if (existsSync(osuDBPath)) {
|
|
71
|
+
console.log(
|
|
72
|
+
`[getRealmDBPath]: ${osuDBPath} is being imported from osu!lazer to ${localDBPath}`,
|
|
73
|
+
);
|
|
74
|
+
mkdirSync(appConfigDir);
|
|
75
|
+
copyFileSync(osuDBPath, localDBPath);
|
|
76
|
+
return localDBPath;
|
|
77
|
+
} else {
|
|
78
|
+
console.log(`[getRealmDBPath]: ${osuDBPath} not found`);
|
|
79
|
+
return null;
|
|
80
|
+
}
|
|
81
|
+
}
|