koishi-plugin-starfx-bot 0.26.3 → 0.26.4
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/assets/songRoom.ejs +32 -6
- package/lib/index.js +55 -25
- package/package.json +1 -1
package/assets/songRoom.ejs
CHANGED
|
@@ -265,9 +265,27 @@
|
|
|
265
265
|
setup() {
|
|
266
266
|
const roomId = "<%= roomId %>"
|
|
267
267
|
const songs = ref([])
|
|
268
|
-
const
|
|
268
|
+
const EMPTY_HASH = "EMPTY_LIST_HASH"; // 与后端 getHash 函数中的占位符一致
|
|
269
|
+
const lastHash = ref(EMPTY_HASH)
|
|
269
270
|
const isDragging = ref(false)
|
|
270
271
|
const form = ref({ title: '', url: '' })
|
|
272
|
+
const pathSegments = window.location.pathname.split('/').filter(Boolean);
|
|
273
|
+
// 找到 roomId 在路径中的索引位置
|
|
274
|
+
const roomIdx = pathSegments.indexOf(roomId);
|
|
275
|
+
|
|
276
|
+
let apiRoot;
|
|
277
|
+
if (roomIdx !== -1) {
|
|
278
|
+
// 取 roomId 之前的所有部分,重新拼起来
|
|
279
|
+
// 如果是 ["songRoom", "1145"] -> prefix 就是 "/songRoom"
|
|
280
|
+
// 如果是 ["1145"] -> prefix 就是 ""
|
|
281
|
+
const prefix = pathSegments.slice(0, roomIdx).join('/');
|
|
282
|
+
const slash = prefix ? '/' : '';
|
|
283
|
+
apiRoot = `${slash}${prefix}/api/${roomId}`;
|
|
284
|
+
} else {
|
|
285
|
+
// 兜底逻辑:如果路径里竟然没找到 roomId,回退到最简单的相对路径
|
|
286
|
+
apiRoot = `api/${roomId}`;
|
|
287
|
+
}
|
|
288
|
+
|
|
271
289
|
|
|
272
290
|
// 1. 修改 commitOp,防止前端标记传给后端导致 500 错误
|
|
273
291
|
const commitOp = async (opData) => {
|
|
@@ -279,7 +297,7 @@
|
|
|
279
297
|
}
|
|
280
298
|
|
|
281
299
|
try {
|
|
282
|
-
const res = await fetch(
|
|
300
|
+
const res = await fetch(apiRoot, {
|
|
283
301
|
method: 'POST',
|
|
284
302
|
headers: { 'Content-Type': 'application/json' },
|
|
285
303
|
body: JSON.stringify({
|
|
@@ -290,10 +308,11 @@
|
|
|
290
308
|
}).then(r => r.json());
|
|
291
309
|
|
|
292
310
|
if (res.success) {
|
|
293
|
-
lastHash.value = res.hash;
|
|
311
|
+
lastHash.value = res.hash;
|
|
294
312
|
return true;
|
|
295
313
|
} else if (res.code === 'REJECT') {
|
|
296
|
-
|
|
314
|
+
// 如果被拒绝,说明前端 Hash 过时或列表已空但前端不知道
|
|
315
|
+
lastHash.value = EMPTY_HASH; // 强制重置为初始状态
|
|
297
316
|
await load();
|
|
298
317
|
}
|
|
299
318
|
} catch (e) {
|
|
@@ -406,12 +425,19 @@
|
|
|
406
425
|
const load = async () => {
|
|
407
426
|
if (isDragging.value) return;
|
|
408
427
|
try {
|
|
409
|
-
const url =
|
|
428
|
+
const url = `${apiRoot}?lastHash=${lastHash.value}`;
|
|
410
429
|
const res = await fetch(url).then(r => r.json());
|
|
411
430
|
|
|
412
431
|
if (res.changed) {
|
|
413
432
|
const oldSongs = [...songs.value];
|
|
414
|
-
const newSongsData = res.list;
|
|
433
|
+
const newSongsData = res.list || []; // 防御性处理空返回
|
|
434
|
+
|
|
435
|
+
// 如果新数据就是空的,直接赋值并更新 Hash,跳过后续复杂的 LIS 计算
|
|
436
|
+
if (newSongsData.length === 0) {
|
|
437
|
+
songs.value = [];
|
|
438
|
+
lastHash.value = res.hash || EMPTY_HASH;
|
|
439
|
+
return;
|
|
440
|
+
}
|
|
415
441
|
|
|
416
442
|
// 1. 计算 ID 映射
|
|
417
443
|
const oldIdMap = new Map();
|
package/lib/index.js
CHANGED
|
@@ -65,7 +65,7 @@ var package_default = {
|
|
|
65
65
|
contributors: [
|
|
66
66
|
"StarFreedomX <starfreedomx@outlook.com>"
|
|
67
67
|
],
|
|
68
|
-
version: "0.26.
|
|
68
|
+
version: "0.26.3",
|
|
69
69
|
main: "lib/index.js",
|
|
70
70
|
typings: "lib/index.d.ts",
|
|
71
71
|
files: [
|
|
@@ -1650,8 +1650,9 @@ function apply(ctx, cfg) {
|
|
|
1650
1650
|
}
|
|
1651
1651
|
if (cfg.ktvServer && ctx.server) {
|
|
1652
1652
|
let getHash = function(songs) {
|
|
1653
|
-
|
|
1654
|
-
|
|
1653
|
+
if (!songs || songs.length === 0) return "EMPTY_LIST_HASH";
|
|
1654
|
+
const str = songs.map((s) => `${s.id}:${s.title}`).join("|");
|
|
1655
|
+
return crypto.createHash("md5").update(str).digest("hex");
|
|
1655
1656
|
}, songOperation = function(nowSongs, songIdArray, ops) {
|
|
1656
1657
|
const latestSongMap = /* @__PURE__ */ new Map();
|
|
1657
1658
|
if (Array.isArray(nowSongs)) {
|
|
@@ -1754,26 +1755,27 @@ function apply(ctx, cfg) {
|
|
|
1754
1755
|
ctx.server.get("/songRoom/api/:roomId", async (koaCtx) => {
|
|
1755
1756
|
const { roomId } = koaCtx.params;
|
|
1756
1757
|
const { lastHash: clientHash } = koaCtx.query;
|
|
1757
|
-
if (!roomSongsCache[roomId]
|
|
1758
|
-
|
|
1758
|
+
if (!roomSongsCache[roomId]) {
|
|
1759
|
+
const dbData = await ctx.cache.get("ktv_room", roomId);
|
|
1760
|
+
roomSongsCache[roomId] = dbData || [];
|
|
1759
1761
|
}
|
|
1760
|
-
const
|
|
1761
|
-
|
|
1762
|
+
const currentSongs = roomSongsCache[roomId];
|
|
1763
|
+
const serverHash = getHash(currentSongs);
|
|
1764
|
+
if (!roomOpCache[roomId] || roomOpCache[roomId].length === 0) {
|
|
1762
1765
|
roomOpCache[roomId] = [{
|
|
1763
|
-
idArray:
|
|
1764
|
-
// 顺序校验仍用 ID
|
|
1766
|
+
idArray: currentSongs.map((s) => s.id),
|
|
1765
1767
|
hash: serverHash,
|
|
1766
1768
|
song: null,
|
|
1767
1769
|
toIndex: -1,
|
|
1768
1770
|
timestamp: Date.now()
|
|
1769
1771
|
}];
|
|
1770
1772
|
}
|
|
1771
|
-
if (clientHash === serverHash) {
|
|
1773
|
+
if (clientHash && clientHash === serverHash) {
|
|
1772
1774
|
return koaCtx.body = { changed: false, hash: serverHash };
|
|
1773
1775
|
}
|
|
1774
1776
|
koaCtx.body = {
|
|
1775
1777
|
changed: true,
|
|
1776
|
-
list:
|
|
1778
|
+
list: currentSongs,
|
|
1777
1779
|
hash: serverHash
|
|
1778
1780
|
};
|
|
1779
1781
|
});
|
|
@@ -1781,30 +1783,49 @@ function apply(ctx, cfg) {
|
|
|
1781
1783
|
const { roomId } = koaCtx.params;
|
|
1782
1784
|
const body = koaCtx.request["body"];
|
|
1783
1785
|
const { idArrayHash, song, toIndex } = body;
|
|
1784
|
-
|
|
1786
|
+
if (!roomSongsCache[roomId]) {
|
|
1787
|
+
roomSongsCache[roomId] = await ctx.cache.get("ktv_room", roomId) || [];
|
|
1788
|
+
}
|
|
1789
|
+
if (!roomOpCache[roomId]) {
|
|
1790
|
+
roomOpCache[roomId] = [{
|
|
1791
|
+
idArray: roomSongsCache[roomId].map((s) => s.id),
|
|
1792
|
+
hash: getHash(roomSongsCache[roomId]),
|
|
1793
|
+
song: null,
|
|
1794
|
+
toIndex: -1,
|
|
1795
|
+
timestamp: Date.now()
|
|
1796
|
+
}];
|
|
1797
|
+
}
|
|
1798
|
+
const logs = roomOpCache[roomId];
|
|
1785
1799
|
const hitIdx = logs.findIndex((l) => l.hash === idArrayHash);
|
|
1786
|
-
if (hitIdx === -1)
|
|
1800
|
+
if (hitIdx === -1) {
|
|
1801
|
+
return koaCtx.body = { success: false, code: "REJECT" };
|
|
1802
|
+
}
|
|
1787
1803
|
const baseLog = logs[hitIdx];
|
|
1788
1804
|
const spotIds = [...baseLog.idArray];
|
|
1789
|
-
const nowSongs = roomSongsCache[roomId]
|
|
1805
|
+
const nowSongs = [...roomSongsCache[roomId]];
|
|
1790
1806
|
const currentOp = {
|
|
1791
1807
|
idArray: [],
|
|
1792
|
-
// 此时 finalIdArray 还没算出,后面补上
|
|
1793
1808
|
hash: "",
|
|
1794
1809
|
song,
|
|
1795
1810
|
toIndex,
|
|
1796
1811
|
timestamp: Date.now()
|
|
1797
1812
|
};
|
|
1798
1813
|
const laterOps = [...logs.slice(hitIdx + 1), currentOp];
|
|
1799
|
-
|
|
1800
|
-
|
|
1801
|
-
|
|
1802
|
-
|
|
1803
|
-
|
|
1804
|
-
|
|
1805
|
-
|
|
1806
|
-
|
|
1807
|
-
|
|
1814
|
+
try {
|
|
1815
|
+
const finalSongs = songOperation(nowSongs, spotIds, laterOps);
|
|
1816
|
+
const finalIds = finalSongs.map((s) => s.id);
|
|
1817
|
+
const finalHash = getHash(finalSongs);
|
|
1818
|
+
currentOp.idArray = finalIds;
|
|
1819
|
+
currentOp.hash = finalHash;
|
|
1820
|
+
logs.push(currentOp);
|
|
1821
|
+
if (logs.length > 50) logs.shift();
|
|
1822
|
+
roomSongsCache[roomId] = finalSongs;
|
|
1823
|
+
await ctx.cache.set(`ktv_room`, roomId, finalSongs);
|
|
1824
|
+
koaCtx.body = { success: true, hash: finalHash };
|
|
1825
|
+
} catch (e) {
|
|
1826
|
+
console.error("Operation re-run failed:", e);
|
|
1827
|
+
koaCtx.body = { success: false, code: "REJECT" };
|
|
1828
|
+
}
|
|
1808
1829
|
});
|
|
1809
1830
|
ctx.server.get("/songRoom/:roomId", async (koaCtx) => {
|
|
1810
1831
|
const { roomId } = koaCtx.params;
|
|
@@ -1858,9 +1879,18 @@ function apply(ctx, cfg) {
|
|
|
1858
1879
|
function joinRoom() {
|
|
1859
1880
|
const id = document.getElementById('roomInput').value.trim();
|
|
1860
1881
|
if (id) {
|
|
1861
|
-
|
|
1882
|
+
// 1. 获取当前页面的基础路径 (例如 "/songRoom" 或 "/")
|
|
1883
|
+
// 2. 移除末尾可能存在的斜杠
|
|
1884
|
+
const currentPath = window.location.pathname.replace(/\\/$/, '');
|
|
1885
|
+
|
|
1886
|
+
// 3. 拼接房间号实现跳转
|
|
1887
|
+
// 这样:
|
|
1888
|
+
// 如果是 127.0.0.1:5140/songRoom -> 会跳到 /songRoom/1145
|
|
1889
|
+
// 如果是 a.b.c -> 会跳到 /1145
|
|
1890
|
+
window.location.href = \`\${currentPath}/\${id}\`;
|
|
1862
1891
|
}
|
|
1863
1892
|
}
|
|
1893
|
+
|
|
1864
1894
|
// 支持回车键跳转
|
|
1865
1895
|
document.getElementById('roomInput').addEventListener('keypress', (e) => {
|
|
1866
1896
|
if (e.key === 'Enter') joinRoom();
|