osu-play 1.3.1 → 1.3.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/README.md +4 -2
- package/dist/cli.cjs +107 -14
- package/dist/cli.cjs.map +6 -6
- package/dist/cli.js +106 -13
- package/dist/cli.js.map +6 -6
- package/dist/core/player/mod.d.ts +1 -1
- package/dist/core/player/session.d.ts +5 -0
- package/dist/core/utils/mod.d.ts +1 -0
- package/dist/index.cjs +30 -4
- package/dist/index.cjs.map +3 -3
- package/dist/index.js +29 -3
- package/dist/index.js.map +3 -3
- package/package.json +1 -1
package/dist/cli.js
CHANGED
|
@@ -29,8 +29,33 @@ var __esm = (fn, res) => () => (fn && (res = fn(fn = 0)), res);
|
|
|
29
29
|
var __require = /* @__PURE__ */ createRequire(import.meta.url);
|
|
30
30
|
|
|
31
31
|
// src/core/utils/mod.ts
|
|
32
|
+
var exports_mod = {};
|
|
33
|
+
__export(exports_mod, {
|
|
34
|
+
revealFile: () => revealFile,
|
|
35
|
+
hashedFilePath: () => hashedFilePath,
|
|
36
|
+
getRealmDBPath: () => getRealmDBPath,
|
|
37
|
+
getDefaultOsuDataDir: () => getDefaultOsuDataDir,
|
|
38
|
+
getDefaultConfigPath: () => getDefaultConfigPath,
|
|
39
|
+
getDataDir: () => getDataDir,
|
|
40
|
+
getConfigDir: () => getConfigDir
|
|
41
|
+
});
|
|
32
42
|
import path from "node:path";
|
|
33
43
|
import { existsSync } from "node:fs";
|
|
44
|
+
import { spawn } from "node:child_process";
|
|
45
|
+
function revealFile(filePath) {
|
|
46
|
+
const command = process.platform === "darwin" ? { args: ["-R", filePath], executable: "open" } : process.platform === "win32" ? { args: ["/select,", filePath], executable: "explorer.exe" } : { args: [path.dirname(filePath)], executable: "xdg-open" };
|
|
47
|
+
return new Promise((resolve, reject) => {
|
|
48
|
+
const child = spawn(command.executable, command.args, {
|
|
49
|
+
detached: true,
|
|
50
|
+
stdio: "ignore"
|
|
51
|
+
});
|
|
52
|
+
child.once("error", reject);
|
|
53
|
+
child.once("spawn", () => {
|
|
54
|
+
child.unref();
|
|
55
|
+
resolve();
|
|
56
|
+
});
|
|
57
|
+
});
|
|
58
|
+
}
|
|
34
59
|
function getDataDir() {
|
|
35
60
|
switch (process.platform) {
|
|
36
61
|
case "linux":
|
|
@@ -400,8 +425,8 @@ var init_mod2 = __esm(() => {
|
|
|
400
425
|
});
|
|
401
426
|
|
|
402
427
|
// src/core/lazer/mod.ts
|
|
403
|
-
var
|
|
404
|
-
__export(
|
|
428
|
+
var exports_mod2 = {};
|
|
429
|
+
__export(exports_mod2, {
|
|
405
430
|
inspectLazerSchemaEntries: () => inspectLazerSchemaEntries,
|
|
406
431
|
inspectLazerSchema: () => inspectLazerSchema,
|
|
407
432
|
hashedFilePath: () => hashedFilePath,
|
|
@@ -540,7 +565,7 @@ function buildPlaylist(beatmapSets, osuDataDir) {
|
|
|
540
565
|
}
|
|
541
566
|
|
|
542
567
|
// src/core/player/mpv.ts
|
|
543
|
-
import { spawn } from "node:child_process";
|
|
568
|
+
import { spawn as spawn2 } from "node:child_process";
|
|
544
569
|
import { existsSync as existsSync2, rmSync } from "node:fs";
|
|
545
570
|
import net from "node:net";
|
|
546
571
|
import os from "node:os";
|
|
@@ -695,7 +720,7 @@ class MpvPlayerBackend {
|
|
|
695
720
|
this.cleanupSocketPath();
|
|
696
721
|
this.disposing = false;
|
|
697
722
|
this.stderrBuffer = "";
|
|
698
|
-
const processHandle =
|
|
723
|
+
const processHandle = spawn2("mpv", [
|
|
699
724
|
"--no-config",
|
|
700
725
|
"--no-terminal",
|
|
701
726
|
"--idle=yes",
|
|
@@ -974,6 +999,13 @@ function findTrackIndexByQuery(playlist, query) {
|
|
|
974
999
|
}
|
|
975
1000
|
return playlist.findIndex((track) => normalizeSearchText(track.title).includes(normalizedQuery));
|
|
976
1001
|
}
|
|
1002
|
+
function findTrackIndicesByQuery(playlist, query) {
|
|
1003
|
+
const normalizedQuery = normalizeSearchText(query);
|
|
1004
|
+
if (!normalizedQuery) {
|
|
1005
|
+
return playlist.map((_, index) => index);
|
|
1006
|
+
}
|
|
1007
|
+
return playlist.flatMap((track, index) => normalizeSearchText(track.title).includes(normalizedQuery) ? [index] : []);
|
|
1008
|
+
}
|
|
977
1009
|
|
|
978
1010
|
class PlaylistPlayerSession {
|
|
979
1011
|
backend;
|
|
@@ -984,6 +1016,7 @@ class PlaylistPlayerSession {
|
|
|
984
1016
|
deleteTrack;
|
|
985
1017
|
playlist;
|
|
986
1018
|
reloadPlaylist;
|
|
1019
|
+
revealTrack;
|
|
987
1020
|
searchQuery = "";
|
|
988
1021
|
selectedIndex = 0;
|
|
989
1022
|
operationQueue = Promise.resolve();
|
|
@@ -994,6 +1027,7 @@ class PlaylistPlayerSession {
|
|
|
994
1027
|
this.deleteTrack = options.deleteTrack;
|
|
995
1028
|
this.loop = options.loop ?? false;
|
|
996
1029
|
this.reloadPlaylist = options.reloadPlaylist;
|
|
1030
|
+
this.revealTrack = options.revealTrack;
|
|
997
1031
|
this.unsubscribeBackend = backend.subscribe((event) => {
|
|
998
1032
|
this.handleBackendEvent(event);
|
|
999
1033
|
});
|
|
@@ -1034,24 +1068,44 @@ class PlaylistPlayerSession {
|
|
|
1034
1068
|
if (this.playlist.length === 0) {
|
|
1035
1069
|
return;
|
|
1036
1070
|
}
|
|
1071
|
+
if (this.searchQuery) {
|
|
1072
|
+
this.moveSearchSelection(delta);
|
|
1073
|
+
return;
|
|
1074
|
+
}
|
|
1037
1075
|
this.selectedIndex = wrapIndex(this.selectedIndex + delta, this.playlist.length);
|
|
1038
1076
|
this.emit();
|
|
1039
1077
|
}
|
|
1040
1078
|
moveSelectionPage(delta, pageSize) {
|
|
1079
|
+
if (this.searchQuery) {
|
|
1080
|
+
this.moveSearchSelection(delta * Math.max(1, pageSize));
|
|
1081
|
+
return;
|
|
1082
|
+
}
|
|
1041
1083
|
this.moveSelection(delta * Math.max(1, pageSize));
|
|
1042
1084
|
}
|
|
1085
|
+
moveSearchSelection(delta) {
|
|
1086
|
+
const matches = findTrackIndicesByQuery(this.playlist, this.searchQuery);
|
|
1087
|
+
if (matches.length === 0) {
|
|
1088
|
+
return;
|
|
1089
|
+
}
|
|
1090
|
+
const currentMatchIndex = matches.indexOf(this.selectedIndex);
|
|
1091
|
+
const nextMatchIndex = wrapIndex(currentMatchIndex + delta, matches.length);
|
|
1092
|
+
this.selectedIndex = matches[nextMatchIndex] ?? this.selectedIndex;
|
|
1093
|
+
this.emit();
|
|
1094
|
+
}
|
|
1043
1095
|
selectHome() {
|
|
1044
1096
|
if (this.playlist.length === 0) {
|
|
1045
1097
|
return;
|
|
1046
1098
|
}
|
|
1047
|
-
this.
|
|
1099
|
+
const matches = findTrackIndicesByQuery(this.playlist, this.searchQuery);
|
|
1100
|
+
this.selectedIndex = matches[0] ?? 0;
|
|
1048
1101
|
this.emit();
|
|
1049
1102
|
}
|
|
1050
1103
|
selectEnd() {
|
|
1051
1104
|
if (this.playlist.length === 0) {
|
|
1052
1105
|
return;
|
|
1053
1106
|
}
|
|
1054
|
-
|
|
1107
|
+
const matches = findTrackIndicesByQuery(this.playlist, this.searchQuery);
|
|
1108
|
+
this.selectedIndex = matches.at(-1) ?? this.playlist.length - 1;
|
|
1055
1109
|
this.emit();
|
|
1056
1110
|
}
|
|
1057
1111
|
setSelectionIndex(index) {
|
|
@@ -1157,6 +1211,22 @@ class PlaylistPlayerSession {
|
|
|
1157
1211
|
}
|
|
1158
1212
|
});
|
|
1159
1213
|
}
|
|
1214
|
+
async revealSelectedTrack() {
|
|
1215
|
+
const track = this.playlist[this.selectedIndex];
|
|
1216
|
+
if (!track) {
|
|
1217
|
+
return;
|
|
1218
|
+
}
|
|
1219
|
+
if (!this.revealTrack) {
|
|
1220
|
+
this.reportError(new Error("Opening the containing folder is unavailable."));
|
|
1221
|
+
return;
|
|
1222
|
+
}
|
|
1223
|
+
try {
|
|
1224
|
+
this.clearError();
|
|
1225
|
+
await this.revealTrack(track);
|
|
1226
|
+
} catch (error) {
|
|
1227
|
+
this.reportError(error);
|
|
1228
|
+
}
|
|
1229
|
+
}
|
|
1160
1230
|
async deleteSelectedTrack() {
|
|
1161
1231
|
const selectedIndex = this.selectedIndex;
|
|
1162
1232
|
await this.enqueueOperation(async () => {
|
|
@@ -1463,6 +1533,10 @@ class PlaylistPlayerScreen {
|
|
|
1463
1533
|
this.session.toggleLoop();
|
|
1464
1534
|
return;
|
|
1465
1535
|
}
|
|
1536
|
+
if (matchesKey(data, "o")) {
|
|
1537
|
+
this.session.revealSelectedTrack();
|
|
1538
|
+
return;
|
|
1539
|
+
}
|
|
1466
1540
|
if (matchesKey(data, Key.backspace)) {
|
|
1467
1541
|
this.session.deleteSearchCharacter();
|
|
1468
1542
|
return;
|
|
@@ -1474,9 +1548,11 @@ class PlaylistPlayerScreen {
|
|
|
1474
1548
|
}
|
|
1475
1549
|
render(width) {
|
|
1476
1550
|
const { playlist } = this.snapshot;
|
|
1551
|
+
const visibleIndices = this.snapshot.searchQuery ? findTrackIndicesByQuery(playlist, this.snapshot.searchQuery) : playlist.map((_, index) => index);
|
|
1552
|
+
const selectedVisibleIndex = Math.max(0, visibleIndices.indexOf(this.snapshot.selectedIndex));
|
|
1477
1553
|
const viewportHeight = Math.max(this.getViewportHeight(), RESERVED_ROWS);
|
|
1478
1554
|
const listHeight = this.getListHeight(viewportHeight);
|
|
1479
|
-
const { start, end } = getVisibleTrackRange(
|
|
1555
|
+
const { start, end } = getVisibleTrackRange(selectedVisibleIndex, visibleIndices.length, listHeight);
|
|
1480
1556
|
const position = formatSeconds(this.snapshot.timePositionSeconds);
|
|
1481
1557
|
const duration = formatSeconds(this.snapshot.durationSeconds);
|
|
1482
1558
|
const glyph = STATUS_GLYPH[this.snapshot.status] ?? "·";
|
|
@@ -1498,8 +1574,14 @@ class PlaylistPlayerScreen {
|
|
|
1498
1574
|
}
|
|
1499
1575
|
if (playlist.length === 0) {
|
|
1500
1576
|
lines.push(truncateToWidth("No tracks were found in your osu!lazer library.", width));
|
|
1577
|
+
} else if (visibleIndices.length === 0) {
|
|
1578
|
+
lines.push(truncateToWidth("No tracks match the current search.", width));
|
|
1501
1579
|
} else {
|
|
1502
|
-
for (let
|
|
1580
|
+
for (let visibleIndex = start;visibleIndex < end; visibleIndex += 1) {
|
|
1581
|
+
const index = visibleIndices[visibleIndex];
|
|
1582
|
+
if (index === undefined) {
|
|
1583
|
+
continue;
|
|
1584
|
+
}
|
|
1503
1585
|
const track = playlist[index];
|
|
1504
1586
|
if (!track) {
|
|
1505
1587
|
continue;
|
|
@@ -1514,7 +1596,7 @@ class PlaylistPlayerScreen {
|
|
|
1514
1596
|
while (lines.length < viewportHeight - 1) {
|
|
1515
1597
|
lines.push("");
|
|
1516
1598
|
}
|
|
1517
|
-
lines.push(truncateToWidth(style(this.searchMode ? "type to
|
|
1599
|
+
lines.push(truncateToWidth(style(this.searchMode ? "type to filter · ↑/↓ results · enter play · backspace edit · esc leave" : "j/k move · ⏎ play · space pause · n/p track · h/l seek · o reveal · r loop · d delete · / search · q quit", DIM), width));
|
|
1518
1600
|
return lines;
|
|
1519
1601
|
}
|
|
1520
1602
|
armPendingGoToTop() {
|
|
@@ -1556,6 +1638,7 @@ class PlaylistPlayerScreen {
|
|
|
1556
1638
|
}
|
|
1557
1639
|
if (matchesKey(data, Key.enter)) {
|
|
1558
1640
|
this.searchMode = false;
|
|
1641
|
+
this.session.playSelected();
|
|
1559
1642
|
return;
|
|
1560
1643
|
}
|
|
1561
1644
|
if (matchesKey(data, Key.escape)) {
|
|
@@ -1570,8 +1653,16 @@ class PlaylistPlayerScreen {
|
|
|
1570
1653
|
this.session.clearSearch();
|
|
1571
1654
|
return;
|
|
1572
1655
|
}
|
|
1656
|
+
if (matchesKey(data, Key.up) || matchesKey(data, Key.ctrl("p"))) {
|
|
1657
|
+
this.session.moveSearchSelection(-1);
|
|
1658
|
+
return;
|
|
1659
|
+
}
|
|
1660
|
+
if (matchesKey(data, Key.down) || matchesKey(data, Key.ctrl("n"))) {
|
|
1661
|
+
this.session.moveSearchSelection(1);
|
|
1662
|
+
return;
|
|
1663
|
+
}
|
|
1573
1664
|
const printable = decodePrintableText(data);
|
|
1574
|
-
if (!printable
|
|
1665
|
+
if (!printable) {
|
|
1575
1666
|
return;
|
|
1576
1667
|
}
|
|
1577
1668
|
this.session.appendSearchQuery(printable);
|
|
@@ -1614,7 +1705,7 @@ async function loadRealmDependencies() {
|
|
|
1614
1705
|
try {
|
|
1615
1706
|
const [{ default: Realm8 }, lazerModule] = await Promise.all([
|
|
1616
1707
|
import("realm"),
|
|
1617
|
-
Promise.resolve().then(() => (init_mod3(),
|
|
1708
|
+
Promise.resolve().then(() => (init_mod3(), exports_mod2))
|
|
1618
1709
|
]);
|
|
1619
1710
|
return {
|
|
1620
1711
|
Realm: Realm8,
|
|
@@ -1679,11 +1770,13 @@ async function deleteTrackFromCollection(track, osuDataDir) {
|
|
|
1679
1770
|
await deleteBeatmapSet2(track, osuDataDir);
|
|
1680
1771
|
}
|
|
1681
1772
|
async function runTuiPlayer(playlist, osuDataDir, loop) {
|
|
1773
|
+
const { revealFile: revealFile2 } = await Promise.resolve().then(() => (init_mod(), exports_mod));
|
|
1682
1774
|
const backend = new MpvPlayerBackend;
|
|
1683
1775
|
const session = new PlaylistPlayerSession(playlist, backend, {
|
|
1684
1776
|
deleteTrack: (track) => deleteTrackFromCollection(track, osuDataDir),
|
|
1685
1777
|
loop,
|
|
1686
|
-
reloadPlaylist: () => createPlaylist(osuDataDir)
|
|
1778
|
+
reloadPlaylist: () => createPlaylist(osuDataDir),
|
|
1779
|
+
revealTrack: (track) => revealFile2(track.path)
|
|
1687
1780
|
});
|
|
1688
1781
|
const terminal = new ProcessTerminal;
|
|
1689
1782
|
const tui = new TUI(terminal);
|
|
@@ -1742,4 +1835,4 @@ main().then(() => {
|
|
|
1742
1835
|
process.exit(1);
|
|
1743
1836
|
});
|
|
1744
1837
|
|
|
1745
|
-
//# debugId=
|
|
1838
|
+
//# debugId=E1B92021231DEE2064756E2164756E21
|