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.
@@ -265,9 +265,27 @@
265
265
  setup() {
266
266
  const roomId = "<%= roomId %>"
267
267
  const songs = ref([])
268
- const lastHash = ref("")
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(`api/${roomId}`, {
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; // 得到包含新 title/url 的新 Hash
311
+ lastHash.value = res.hash;
294
312
  return true;
295
313
  } else if (res.code === 'REJECT') {
296
- lastHash.value = ""; // Hash 冲突,强制 load 最新数据
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 = `api/${roomId}?lastHash=${lastHash.value}`;
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.2",
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
- const content = songs.map((s) => `${s.id}|${s.title}|${s.url}`).join(",");
1654
- return crypto.createHash("md5").update(content).digest("hex");
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]?.length) {
1758
- roomSongsCache[roomId] = await ctx.cache.get("ktv_room", roomId) || [];
1758
+ if (!roomSongsCache[roomId]) {
1759
+ const dbData = await ctx.cache.get("ktv_room", roomId);
1760
+ roomSongsCache[roomId] = dbData || [];
1759
1761
  }
1760
- const serverHash = getHash(roomSongsCache[roomId]);
1761
- if (!roomOpCache[roomId]) {
1762
+ const currentSongs = roomSongsCache[roomId];
1763
+ const serverHash = getHash(currentSongs);
1764
+ if (!roomOpCache[roomId] || roomOpCache[roomId].length === 0) {
1762
1765
  roomOpCache[roomId] = [{
1763
- idArray: roomSongsCache[roomId].map((s) => s.id),
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: roomSongsCache[roomId],
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
- const logs = roomOpCache[roomId] || [];
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) return koaCtx.body = { success: false, code: "REJECT" };
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
- const finalSongs = songOperation(nowSongs, spotIds, laterOps);
1800
- const finalIds = finalSongs.map((s) => s.id);
1801
- const finalHash = getHash(finalSongs);
1802
- currentOp.idArray = finalIds;
1803
- currentOp.hash = finalHash;
1804
- logs.push(currentOp);
1805
- roomSongsCache[roomId] = finalSongs;
1806
- await ctx.cache.set(`ktv_room`, roomId, finalSongs);
1807
- koaCtx.body = { success: true, hash: finalHash };
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
- window.location.href = \`\${id}\`;
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();
package/package.json CHANGED
@@ -4,7 +4,7 @@
4
4
  "contributors": [
5
5
  "StarFreedomX <starfreedomx@outlook.com>"
6
6
  ],
7
- "version": "0.26.3",
7
+ "version": "0.26.4",
8
8
  "main": "lib/index.js",
9
9
  "typings": "lib/index.d.ts",
10
10
  "files": [