osu-play 1.0.7 → 1.2.0
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/README.md +93 -39
- package/dist/cli.cjs +1579 -0
- package/dist/cli.cjs.map +25 -0
- package/dist/cli.d.cts +2 -0
- package/dist/cli.d.ts +2 -0
- package/dist/cli.js +1569 -0
- package/dist/cli.js.map +25 -0
- package/dist/core/cli/main.d.ts +20 -0
- package/dist/core/lazer/compat.d.ts +24 -0
- package/dist/core/lazer/mod.d.ts +10 -0
- package/dist/core/lazer/schema/beatmap.d.ts +35 -0
- package/dist/core/lazer/schema/beatmapMetadata.d.ts +16 -0
- package/dist/core/lazer/schema/beatmapSet.d.ts +18 -0
- package/{src/realm/schema/mod.ts → dist/core/lazer/schema/mod.d.ts} +0 -1
- package/dist/core/lazer/schema/realmFile.d.ts +6 -0
- package/dist/core/lazer/schema/realmNamedFileUsage.d.ts +9 -0
- package/dist/core/lazer/schema/realmUser.d.ts +9 -0
- package/dist/core/player/mod.d.ts +3 -0
- package/dist/core/player/mpv.d.ts +37 -0
- package/dist/core/player/session.d.ts +45 -0
- package/dist/core/player/types.d.ts +46 -0
- package/dist/core/playlist/mod.d.ts +28 -0
- package/dist/core/tui/player-screen.d.ts +26 -0
- package/dist/core/utils/mod.d.ts +16 -0
- package/dist/index.cjs +529 -0
- package/dist/index.cjs.map +21 -0
- package/dist/index.d.cts +4 -0
- package/dist/index.d.ts +4 -0
- package/dist/index.js +512 -0
- package/dist/index.js.map +21 -0
- package/package.json +54 -25
- package/bin/osu-play.js +0 -7
- package/index.ts +0 -1
- package/src/cli/main.ts +0 -156
- package/src/mod.ts +0 -2
- package/src/realm/mod.ts +0 -54
- package/src/realm/schema/beatmap.ts +0 -85
- package/src/realm/schema/beatmapMetadata.ts +0 -33
- package/src/realm/schema/beatmapSet.ts +0 -36
- package/src/realm/schema/realmFile.ts +0 -15
- package/src/realm/schema/realmNamedFileUsage.ts +0 -19
- package/src/realm/schema/realmUser.ts +0 -21
- package/src/utils/mod.ts +0 -77
- package/tsconfig.json +0 -109
package/package.json
CHANGED
|
@@ -1,44 +1,73 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "osu-play",
|
|
3
|
-
"version": "1.0
|
|
3
|
+
"version": "1.2.0",
|
|
4
4
|
"description": "Play music from your osu!lazer beatmaps from the terminal.",
|
|
5
5
|
"type": "module",
|
|
6
|
-
"main": "
|
|
7
|
-
"module": "index.
|
|
8
|
-
"types": "dist/index.d.ts",
|
|
6
|
+
"main": "./dist/index.cjs",
|
|
7
|
+
"module": "./dist/index.js",
|
|
8
|
+
"types": "./dist/index.d.ts",
|
|
9
|
+
"exports": {
|
|
10
|
+
".": {
|
|
11
|
+
"import": {
|
|
12
|
+
"types": "./dist/index.d.ts",
|
|
13
|
+
"default": "./dist/index.js"
|
|
14
|
+
},
|
|
15
|
+
"require": {
|
|
16
|
+
"types": "./dist/index.d.cts",
|
|
17
|
+
"default": "./dist/index.cjs"
|
|
18
|
+
},
|
|
19
|
+
"default": "./dist/index.js"
|
|
20
|
+
},
|
|
21
|
+
"./package.json": "./package.json"
|
|
22
|
+
},
|
|
9
23
|
"files": [
|
|
10
|
-
"bin",
|
|
11
24
|
"dist",
|
|
12
|
-
"src",
|
|
13
|
-
"index.ts",
|
|
14
|
-
"package.json",
|
|
15
25
|
"README.md",
|
|
16
|
-
"tsconfig.json",
|
|
17
26
|
"LICENSE"
|
|
18
27
|
],
|
|
19
28
|
"bin": {
|
|
20
|
-
"osu-play": "./
|
|
29
|
+
"osu-play": "./dist/cli.cjs"
|
|
30
|
+
},
|
|
31
|
+
"sideEffects": false,
|
|
32
|
+
"packageManager": "bun@1.3.5",
|
|
33
|
+
"engines": {
|
|
34
|
+
"node": ">=20"
|
|
35
|
+
},
|
|
36
|
+
"trustedDependencies": [
|
|
37
|
+
"realm"
|
|
38
|
+
],
|
|
39
|
+
"publishConfig": {
|
|
40
|
+
"access": "public"
|
|
21
41
|
},
|
|
22
42
|
"scripts": {
|
|
23
|
-
"
|
|
24
|
-
"build": "
|
|
25
|
-
"
|
|
26
|
-
"
|
|
27
|
-
"
|
|
43
|
+
"setup": "bun install && bun run repair:realm",
|
|
44
|
+
"build": "bun run scripts/build.mjs",
|
|
45
|
+
"dev": "bun run build && node dist/cli.cjs",
|
|
46
|
+
"repair:realm": "bun run scripts/repair-realm.mjs",
|
|
47
|
+
"test": "bun run build && bun test",
|
|
48
|
+
"typecheck": "bun x tsc --project tsconfig.json --noEmit",
|
|
49
|
+
"lint": "eslint --config eslint.config.mjs src scripts test",
|
|
50
|
+
"package": "bun run build && bun pm pack --quiet",
|
|
51
|
+
"check": "bun run typecheck && bun run lint && bun run test && bun pm pack --dry-run && bun run scripts/run-with-local-tmp.mjs bun x publint && bun run scripts/run-with-local-tmp.mjs bun x attw --pack .",
|
|
52
|
+
"prepublishOnly": "bun run check"
|
|
28
53
|
},
|
|
29
54
|
"author": "KorigamiK",
|
|
30
55
|
"license": "MIT",
|
|
31
56
|
"devDependencies": {
|
|
32
|
-
"@
|
|
33
|
-
"@
|
|
34
|
-
"
|
|
35
|
-
"
|
|
57
|
+
"@arethetypeswrong/cli": "^0.18.2",
|
|
58
|
+
"@eslint/js": "^10.0.1",
|
|
59
|
+
"@types/node": "^25.5.0",
|
|
60
|
+
"@types/yargs": "^17.0.35",
|
|
61
|
+
"eslint": "^10.0.3",
|
|
62
|
+
"globals": "^17.4.0",
|
|
63
|
+
"publint": "^0.3.18",
|
|
64
|
+
"typescript": "^5.9.3",
|
|
65
|
+
"typescript-eslint": "^8.57.0"
|
|
36
66
|
},
|
|
37
67
|
"dependencies": {
|
|
38
|
-
"@
|
|
39
|
-
"
|
|
40
|
-
"
|
|
41
|
-
"yargs": "^17.7.2"
|
|
68
|
+
"@mariozechner/pi-tui": "^0.58.4",
|
|
69
|
+
"realm": "^20.2.0",
|
|
70
|
+
"yargs": "^18.0.0"
|
|
42
71
|
},
|
|
43
72
|
"keywords": [
|
|
44
73
|
"osu",
|
|
@@ -50,7 +79,7 @@
|
|
|
50
79
|
],
|
|
51
80
|
"repository": {
|
|
52
81
|
"type": "git",
|
|
53
|
-
"url": "https://github.com/KorigamiK/osu-play"
|
|
82
|
+
"url": "git+https://github.com/KorigamiK/osu-play.git"
|
|
54
83
|
},
|
|
55
84
|
"bugs": "https://github.com/KorigamiK/osu-play/issues"
|
|
56
|
-
}
|
|
85
|
+
}
|
package/bin/osu-play.js
DELETED
package/index.ts
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
export * from "./src/mod.js";
|
package/src/cli/main.ts
DELETED
|
@@ -1,156 +0,0 @@
|
|
|
1
|
-
import path from "node:path";
|
|
2
|
-
import { existsSync, writeFileSync } from "node:fs";
|
|
3
|
-
|
|
4
|
-
import Realm from "realm";
|
|
5
|
-
import prompts from "prompts";
|
|
6
|
-
import { BeatmapSet } from "../realm/schema/mod.js";
|
|
7
|
-
import { getConfigDir, getDataDir, getRealmDBPath } from "../utils/mod.js";
|
|
8
|
-
import { getLazerDB, getNamedFileHash, hashedFilePath } from "../realm/mod.js";
|
|
9
|
-
|
|
10
|
-
import yargs from "yargs/yargs";
|
|
11
|
-
import { hideBin } from "yargs/helpers";
|
|
12
|
-
import util from "node:util";
|
|
13
|
-
import { execFile } from "node:child_process";
|
|
14
|
-
|
|
15
|
-
const execFilePromise = util.promisify(execFile);
|
|
16
|
-
|
|
17
|
-
export function getArgs() {
|
|
18
|
-
const argv = yargs(hideBin(process.argv))
|
|
19
|
-
.usage("Play music from your osu!lazer beatmaps from the terminal\nUsage: $0 [options]")
|
|
20
|
-
.options({
|
|
21
|
-
reload: {
|
|
22
|
-
type: "boolean",
|
|
23
|
-
default: false,
|
|
24
|
-
alias: "r",
|
|
25
|
-
describe: "Reload lazer database",
|
|
26
|
-
},
|
|
27
|
-
exportPlaylist: {
|
|
28
|
-
type: "string",
|
|
29
|
-
describe: "Export playlist to a file",
|
|
30
|
-
},
|
|
31
|
-
osuDataDir: {
|
|
32
|
-
type: "string",
|
|
33
|
-
default: path.join(getDataDir() || ".", "osu"),
|
|
34
|
-
alias: "d",
|
|
35
|
-
describe: "Osu!lazer data directory",
|
|
36
|
-
},
|
|
37
|
-
configDir: {
|
|
38
|
-
type: "string",
|
|
39
|
-
default: path.join(getConfigDir() || ".", "osu-play"),
|
|
40
|
-
alias: "c",
|
|
41
|
-
describe: "Config directory",
|
|
42
|
-
},
|
|
43
|
-
loop: {
|
|
44
|
-
type: "boolean",
|
|
45
|
-
default: false,
|
|
46
|
-
alias: "l",
|
|
47
|
-
describe: "Loop the playlist on end",
|
|
48
|
-
},
|
|
49
|
-
help: {
|
|
50
|
-
type: "boolean",
|
|
51
|
-
alias: "h",
|
|
52
|
-
describe: "Show help",
|
|
53
|
-
}
|
|
54
|
-
}).argv;
|
|
55
|
-
return argv;
|
|
56
|
-
}
|
|
57
|
-
|
|
58
|
-
export async function main() {
|
|
59
|
-
const argv = await getArgs();
|
|
60
|
-
console.log("[INFO] osu!play");
|
|
61
|
-
|
|
62
|
-
let reload = false;
|
|
63
|
-
let osuDataDir = argv.osuDataDir;
|
|
64
|
-
|
|
65
|
-
if (argv.reload) {
|
|
66
|
-
console.log("[INFO] Reloading lazer database");
|
|
67
|
-
reload = true;
|
|
68
|
-
}
|
|
69
|
-
|
|
70
|
-
if (argv.osuDataDir !== getDataDir()) {
|
|
71
|
-
console.log(`[INFO] Using osu!lazer data directory: ${ argv.osuDataDir }`);
|
|
72
|
-
}
|
|
73
|
-
|
|
74
|
-
const realmDBPath = getRealmDBPath(argv.configDir, { reload, osuDataDir });
|
|
75
|
-
|
|
76
|
-
if (realmDBPath == null) {
|
|
77
|
-
console.log("[ERROR] Realm DB not found");
|
|
78
|
-
process.exit(1);
|
|
79
|
-
}
|
|
80
|
-
|
|
81
|
-
const currentSchema = Realm.schemaVersion(realmDBPath);
|
|
82
|
-
console.log(`currentSchema: ${ currentSchema }`);
|
|
83
|
-
|
|
84
|
-
Realm.flags.ALLOW_CLEAR_TEST_STATE = true;
|
|
85
|
-
|
|
86
|
-
const realm: Realm = await getLazerDB(realmDBPath);
|
|
87
|
-
|
|
88
|
-
const beatmapSets = realm.objects(BeatmapSet);
|
|
89
|
-
|
|
90
|
-
const songSet = new Set<string>();
|
|
91
|
-
const uniqueBeatmaps: {
|
|
92
|
-
title: string;
|
|
93
|
-
path: string | null;
|
|
94
|
-
}[] = [];
|
|
95
|
-
|
|
96
|
-
for (const beatmapSet of beatmapSets) {
|
|
97
|
-
for (const beatmap of beatmapSet.Beatmaps) {
|
|
98
|
-
const fileName = beatmap.Metadata.AudioFile;
|
|
99
|
-
const hash = getNamedFileHash(fileName ?? "", beatmapSet);
|
|
100
|
-
if (!hash) continue;
|
|
101
|
-
if (songSet.has(hash)) continue;
|
|
102
|
-
songSet.add(hash);
|
|
103
|
-
const meta = beatmap.Metadata;
|
|
104
|
-
const path = hashedFilePath(hash);
|
|
105
|
-
const title = `${ meta.Title } : ${ meta.Artist } - ${ meta.TitleUnicode } : ${ meta.ArtistUnicode }`;
|
|
106
|
-
uniqueBeatmaps.push({ title, path });
|
|
107
|
-
}
|
|
108
|
-
}
|
|
109
|
-
|
|
110
|
-
console.log(`beatmap songs: ${ beatmapSets.length }`);
|
|
111
|
-
|
|
112
|
-
if (argv.exportPlaylist) {
|
|
113
|
-
console.log(`[INFO] Exporting playlist to ${ argv.exportPlaylist }`);
|
|
114
|
-
const playlist = uniqueBeatmaps.map((mp) => mp.path).join("\n");
|
|
115
|
-
writeFileSync(argv.exportPlaylist, playlist);
|
|
116
|
-
console.log(`[INFO] Done. Use something like \`mpv --playlist=${ argv.exportPlaylist }\` to play the playlist`);
|
|
117
|
-
return;
|
|
118
|
-
}
|
|
119
|
-
|
|
120
|
-
let selectedBeatmap: number = (
|
|
121
|
-
await prompts({
|
|
122
|
-
type: "autocomplete",
|
|
123
|
-
name: "beatmap",
|
|
124
|
-
message: "Which map do you want to play:",
|
|
125
|
-
choices: uniqueBeatmaps.map((mp, index) => ({
|
|
126
|
-
title: mp.title,
|
|
127
|
-
value: index,
|
|
128
|
-
})),
|
|
129
|
-
})
|
|
130
|
-
).beatmap;
|
|
131
|
-
console.log(`Selected: ${ selectedBeatmap }`);
|
|
132
|
-
|
|
133
|
-
let i = selectedBeatmap
|
|
134
|
-
|
|
135
|
-
for (; i < uniqueBeatmaps.length; ++i) {
|
|
136
|
-
const beatmap = uniqueBeatmaps[i];
|
|
137
|
-
console.log(`Map : ${ beatmap.title }`);
|
|
138
|
-
if (beatmap.path && existsSync(beatmap.path)) {
|
|
139
|
-
console.log(`Playing ${ beatmap.title }`);
|
|
140
|
-
await execFilePromise('exo-open', [beatmap.path]);
|
|
141
|
-
} else {
|
|
142
|
-
console.log(`File does not exist: ${ beatmap.path }`);
|
|
143
|
-
}
|
|
144
|
-
if (i < uniqueBeatmaps.length - 1) {
|
|
145
|
-
// Wait 1 second between
|
|
146
|
-
await new Promise((resolve) => setTimeout(resolve, 1000));
|
|
147
|
-
} else if (argv.loop) {
|
|
148
|
-
console.log('[INFO] Looping playlist');
|
|
149
|
-
i = 0;
|
|
150
|
-
} else {
|
|
151
|
-
console.log('[INFO] Done. Use --loop to loop the playlist');
|
|
152
|
-
}
|
|
153
|
-
}
|
|
154
|
-
|
|
155
|
-
realm.close();
|
|
156
|
-
}
|
package/src/mod.ts
DELETED
package/src/realm/mod.ts
DELETED
|
@@ -1,54 +0,0 @@
|
|
|
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: 41,
|
|
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
|
-
};
|
|
@@ -1,85 +0,0 @@
|
|
|
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
|
-
}
|
|
@@ -1,33 +0,0 @@
|
|
|
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
|
-
|
|
@@ -1,36 +0,0 @@
|
|
|
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
|
-
}
|
|
@@ -1,15 +0,0 @@
|
|
|
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
|
-
|
|
@@ -1,19 +0,0 @@
|
|
|
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
|
-
}
|
|
@@ -1,21 +0,0 @@
|
|
|
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
DELETED
|
@@ -1,77 +0,0 @@
|
|
|
1
|
-
import path from "node:path";
|
|
2
|
-
import { copyFileSync, existsSync, mkdirSync } from "node:fs";
|
|
3
|
-
|
|
4
|
-
export function getDataDir(): string | undefined {
|
|
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"] ?? undefined;
|
|
24
|
-
}
|
|
25
|
-
|
|
26
|
-
return undefined;
|
|
27
|
-
}
|
|
28
|
-
|
|
29
|
-
export function getConfigDir(): string | undefined {
|
|
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"] ?? undefined;
|
|
49
|
-
}
|
|
50
|
-
|
|
51
|
-
return undefined;
|
|
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
|
-
options: {
|
|
60
|
-
osuDataDir: string;
|
|
61
|
-
reload: boolean;
|
|
62
|
-
} = { reload: false, osuDataDir: getDataDir() || "." },
|
|
63
|
-
) {
|
|
64
|
-
const localDBPath = path.join(appConfigDir, "client.realm");
|
|
65
|
-
if (!options.reload && existsSync(localDBPath)) return localDBPath;
|
|
66
|
-
|
|
67
|
-
const osuDBPath = path.join(options.osuDataDir, "client.realm");
|
|
68
|
-
if (existsSync(osuDBPath)) {
|
|
69
|
-
console.log( `[getRealmDBPath]: ${osuDBPath} is being imported from osu!lazer to ${localDBPath}`);
|
|
70
|
-
mkdirSync(appConfigDir, { recursive: true });
|
|
71
|
-
copyFileSync(osuDBPath, localDBPath );
|
|
72
|
-
return localDBPath;
|
|
73
|
-
} else {
|
|
74
|
-
console.log(`[getRealmDBPath]: ${osuDBPath} not found`);
|
|
75
|
-
return null;
|
|
76
|
-
}
|
|
77
|
-
}
|