sa2kit 1.0.8 → 1.1.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.
@@ -264,7 +264,7 @@ declare const MMDPlayerBase: React__default.FC<MMDPlayerBaseProps>;
264
264
  * 支持通过 resources 和 stage 配置快速使用
265
265
  * 所有资源均从 public 目录加载,无需额外配置
266
266
  */
267
- declare const MMDPlayerEnhanced: React__default.FC<MMDPlayerEnhancedProps>;
267
+ declare const MMDPlayerEnhanced: React__default.ForwardRefExoticComponent<MMDPlayerEnhancedProps & React__default.RefAttributes<any>>;
268
268
 
269
269
  /**
270
270
  * MMD 播放列表组件(预加载版本)
@@ -264,7 +264,7 @@ declare const MMDPlayerBase: React__default.FC<MMDPlayerBaseProps>;
264
264
  * 支持通过 resources 和 stage 配置快速使用
265
265
  * 所有资源均从 public 目录加载,无需额外配置
266
266
  */
267
- declare const MMDPlayerEnhanced: React__default.FC<MMDPlayerEnhancedProps>;
267
+ declare const MMDPlayerEnhanced: React__default.ForwardRefExoticComponent<MMDPlayerEnhancedProps & React__default.RefAttributes<any>>;
268
268
 
269
269
  /**
270
270
  * MMD 播放列表组件(预加载版本)
package/dist/mmd/index.js CHANGED
@@ -298,7 +298,7 @@ var MMDPlayerBase = ({
298
298
  } }, error)
299
299
  );
300
300
  };
301
- var MMDPlayerEnhanced = ({
301
+ var MMDPlayerEnhanced = React2.forwardRef(({
302
302
  resources,
303
303
  resourcesList,
304
304
  defaultResourceId,
@@ -315,7 +315,7 @@ var MMDPlayerEnhanced = ({
315
315
  onSelectionChange,
316
316
  onAudioEnded,
317
317
  onAnimationEnded
318
- }) => {
318
+ }, ref) => {
319
319
  console.log("\u{1F3A8} [MMDPlayerEnhanced] \u7EC4\u4EF6\u521D\u59CB\u5316");
320
320
  const [selectedResourceId, setSelectedResourceId] = React2.useState(
321
321
  defaultResourceId || resourcesList?.[0]?.id || ""
@@ -408,6 +408,55 @@ var MMDPlayerEnhanced = ({
408
408
  const [isInitialized, setIsInitialized] = React2.useState(false);
409
409
  const [reloadTrigger, setReloadTrigger] = React2.useState(0);
410
410
  const [needReset, setNeedReset] = React2.useState(false);
411
+ React2.useImperativeHandle(ref, () => ({
412
+ clearResources: () => {
413
+ console.log("\u{1F9F9} [MMDPlayerEnhanced] \u5916\u90E8\u89E6\u53D1\u8D44\u6E90\u6E05\u7406");
414
+ clearOldResources();
415
+ },
416
+ getIsPlaying: () => isPlayingRef.current,
417
+ getIsLoaded: () => isLoadedRef.current,
418
+ stopCompletely: () => {
419
+ console.log("\u23F9\uFE0F [MMDPlayerEnhanced] \u5B8C\u5168\u505C\u6B62");
420
+ stopCompletely();
421
+ }
422
+ }));
423
+ const stopCompletely = () => {
424
+ isPlayingRef.current = false;
425
+ setIsPlaying(false);
426
+ if (audioRef.current) {
427
+ audioRef.current.pause();
428
+ audioRef.current.currentTime = 0;
429
+ }
430
+ if (helperRef.current) {
431
+ helperRef.current.enable("physics", false);
432
+ }
433
+ animationEndedFiredRef.current = false;
434
+ lastAnimationTimeRef.current = 0;
435
+ animationStoppedCountRef.current = 0;
436
+ console.log("\u2705 [MMDPlayerEnhanced] \u5B8C\u5168\u505C\u6B62\u5B8C\u6210");
437
+ };
438
+ React2.useEffect(() => {
439
+ const container = containerRef.current;
440
+ if (!container) return;
441
+ const handleCleanupResources = () => {
442
+ console.log("\u{1F9F9} [MMDPlayerEnhanced] \u6536\u5230\u6E05\u7406\u8D44\u6E90\u4E8B\u4EF6");
443
+ if (!isPlayingRef.current) {
444
+ clearOldResources();
445
+ } else {
446
+ console.warn("\u26A0\uFE0F [MMDPlayerEnhanced] \u64AD\u653E\u4E2D\uFF0C\u8DF3\u8FC7\u8D44\u6E90\u6E05\u7406");
447
+ }
448
+ };
449
+ const handleStopCompletely = () => {
450
+ console.log("\u23F9\uFE0F [MMDPlayerEnhanced] \u6536\u5230\u5B8C\u5168\u505C\u6B62\u4E8B\u4EF6");
451
+ stopCompletely();
452
+ };
453
+ container.addEventListener("cleanupResources", handleCleanupResources);
454
+ container.addEventListener("stopCompletely", handleStopCompletely);
455
+ return () => {
456
+ container.removeEventListener("cleanupResources", handleCleanupResources);
457
+ container.removeEventListener("stopCompletely", handleStopCompletely);
458
+ };
459
+ }, []);
411
460
  React2.useEffect(() => {
412
461
  console.log("\u{1F3D7}\uFE0F [MMDPlayerEnhanced] \u573A\u666F\u521D\u59CB\u5316 useEffect \u89E6\u53D1");
413
462
  if (!containerRef.current) {
@@ -1225,7 +1274,8 @@ var MMDPlayerEnhanced = ({
1225
1274
  },
1226
1275
  background.name
1227
1276
  )))))));
1228
- };
1277
+ });
1278
+ MMDPlayerEnhanced.displayName = "MMDPlayerEnhanced";
1229
1279
  var MMDPlaylist = ({
1230
1280
  playlist,
1231
1281
  stage,
@@ -1248,6 +1298,8 @@ var MMDPlaylist = ({
1248
1298
  const currentNodeIndexRef = React2.useRef(defaultNodeIndex);
1249
1299
  const isAutoSwitchRef = React2.useRef(false);
1250
1300
  const playerRefsMap = React2.useRef(/* @__PURE__ */ new Map());
1301
+ const playerComponentRefs = React2.useRef(/* @__PURE__ */ new Map());
1302
+ const [memoryUsage, setMemoryUsage] = React2.useState(0);
1251
1303
  React2.useEffect(() => {
1252
1304
  currentNodeIndexRef.current = currentNodeIndex;
1253
1305
  }, [currentNodeIndex]);
@@ -1258,24 +1310,62 @@ var MMDPlaylist = ({
1258
1310
  }
1259
1311
  console.log("\u{1F3AF} [MMDPlaylist] \u5F53\u524D\u8282\u70B9:", currentNode.name, "\u7D22\u5F15:", currentNodeIndex);
1260
1312
  const stopNode = (nodeIndex) => {
1261
- const playerElement = playerRefsMap.current.get(nodeIndex);
1262
- if (!playerElement) return;
1263
- console.log(`\u23F9\uFE0F [MMDPlaylist] \u505C\u6B62\u8282\u70B9 ${nodeIndex}`);
1264
- const audioElement = playerElement.querySelector("audio");
1265
- if (audioElement) {
1266
- audioElement.pause();
1267
- audioElement.currentTime = 0;
1268
- console.log(` \u{1F507} \u505C\u6B62\u97F3\u9891`);
1313
+ const playerComponent = playerComponentRefs.current.get(nodeIndex);
1314
+ if (playerComponent && playerComponent.stopCompletely) {
1315
+ console.log(`\u23F9\uFE0F [MMDPlaylist] \u505C\u6B62\u8282\u70B9 ${nodeIndex}`);
1316
+ playerComponent.stopCompletely();
1317
+ } else {
1318
+ const playerElement = playerRefsMap.current.get(nodeIndex);
1319
+ if (!playerElement) return;
1320
+ console.log(`\u23F9\uFE0F [MMDPlaylist] \u505C\u6B62\u8282\u70B9 ${nodeIndex} (DOM\u65B9\u5F0F)`);
1321
+ const audioElement = playerElement.querySelector("audio");
1322
+ if (audioElement) {
1323
+ audioElement.pause();
1324
+ audioElement.currentTime = 0;
1325
+ console.log(` \u{1F507} \u505C\u6B62\u97F3\u9891`);
1326
+ }
1327
+ const stopEvent = new CustomEvent("stopCompletely");
1328
+ playerElement.dispatchEvent(stopEvent);
1329
+ console.log(` \u{1F4E1} \u53D1\u9001\u505C\u6B62\u4E8B\u4EF6`);
1330
+ }
1331
+ };
1332
+ const clearNodeResources = (nodeIndex, excludeCurrent = true) => {
1333
+ if (excludeCurrent && nodeIndex === currentNodeIndex) {
1334
+ console.log(`\u26A0\uFE0F [MMDPlaylist] \u8DF3\u8FC7\u6E05\u7406\u5F53\u524D\u64AD\u653E\u8282\u70B9 ${nodeIndex}`);
1335
+ return;
1269
1336
  }
1270
- const stopButton = playerElement.querySelector('button[title="\u505C\u6B62"]');
1271
- if (stopButton) {
1272
- stopButton.click();
1273
- console.log(` \u23F9\uFE0F \u70B9\u51FB\u505C\u6B62\u6309\u94AE`);
1337
+ const playerComponent = playerComponentRefs.current.get(nodeIndex);
1338
+ if (playerComponent && playerComponent.clearResources) {
1339
+ console.log(`\u{1F9F9} [MMDPlaylist] \u6E05\u7406\u8282\u70B9 ${nodeIndex} \u8D44\u6E90`);
1340
+ playerComponent.clearResources();
1274
1341
  } else {
1275
- const pauseButton = playerElement.querySelector('button[title="\u6682\u505C"]');
1276
- if (pauseButton) {
1277
- pauseButton.click();
1278
- console.log(` \u23F8\uFE0F \u70B9\u51FB\u6682\u505C\u6309\u94AE`);
1342
+ const playerElement = playerRefsMap.current.get(nodeIndex);
1343
+ if (playerElement) {
1344
+ const cleanupEvent = new CustomEvent("cleanupResources");
1345
+ playerElement.dispatchEvent(cleanupEvent);
1346
+ }
1347
+ }
1348
+ };
1349
+ const emergencyMemoryCleanup = () => {
1350
+ if (window.performance?.memory) {
1351
+ const memInfo = window.performance.memory;
1352
+ const usage = memInfo.usedJSHeapSize / memInfo.totalJSHeapSize;
1353
+ if (usage > 0.9) {
1354
+ console.error(`\u{1F6A8} [MMDPlaylist] \u5185\u5B58\u4F7F\u7528\u4E25\u91CD\u8FC7\u9AD8 (${(usage * 100).toFixed(1)}%)\uFF0C\u7D27\u6025\u6E05\u7406`);
1355
+ const nodesToClean = editableNodes.map((_, index) => ({
1356
+ index,
1357
+ distance: Math.abs(index - currentNodeIndex)
1358
+ })).filter((node) => node.distance > 2).sort((a, b) => b.distance - a.distance).slice(0, 2);
1359
+ nodesToClean.forEach(({ index }) => {
1360
+ console.warn(`\u{1F9F9} [MMDPlaylist] \u7D27\u6025\u6E05\u7406\u8282\u70B9 ${index}`);
1361
+ clearNodeResources(index, false);
1362
+ });
1363
+ if (window.gc) {
1364
+ try {
1365
+ window.gc();
1366
+ } catch (e) {
1367
+ }
1368
+ }
1279
1369
  }
1280
1370
  }
1281
1371
  };
@@ -1286,6 +1376,19 @@ var MMDPlaylist = ({
1286
1376
  stopNode(index);
1287
1377
  }
1288
1378
  });
1379
+ const nodesToKeep = /* @__PURE__ */ new Set();
1380
+ nodesToKeep.add(currentNodeIndex);
1381
+ if (playlist.loop && currentNodeIndex > 0) {
1382
+ nodesToKeep.add(currentNodeIndex - 1);
1383
+ }
1384
+ if (currentNodeIndex < editableNodes.length - 1) {
1385
+ nodesToKeep.add(currentNodeIndex + 1);
1386
+ }
1387
+ editableNodes.forEach((_, index) => {
1388
+ if (!nodesToKeep.has(index)) {
1389
+ clearNodeResources(index, false);
1390
+ }
1391
+ });
1289
1392
  onNodeChange?.(currentNodeIndex, currentNode);
1290
1393
  if (!isPreloading && (isAutoSwitchRef.current || playlist.autoPlay)) {
1291
1394
  console.log(`\u25B6\uFE0F [MMDPlaylist] \u51C6\u5907\u64AD\u653E\u8282\u70B9 ${currentNodeIndex}`);
@@ -1308,7 +1411,7 @@ var MMDPlaylist = ({
1308
1411
  }
1309
1412
  });
1310
1413
  }
1311
- }, [currentNodeIndex, currentNode, onNodeChange, isPreloading, playlist.autoPlay, preloadedNodes, editableNodes]);
1414
+ }, [currentNodeIndex, currentNode, onNodeChange, isPreloading, playlist.autoPlay, playlist.loop, preloadedNodes, editableNodes]);
1312
1415
  const handleNodePreloaded = (nodeIndex) => {
1313
1416
  console.log(`\u2705 [MMDPlaylist] \u8282\u70B9 ${nodeIndex} \u9884\u52A0\u8F7D\u5B8C\u6210`);
1314
1417
  setPreloadedNodes((prev) => {
@@ -1327,6 +1430,20 @@ var MMDPlaylist = ({
1327
1430
  setPreloadProgress(progress);
1328
1431
  }
1329
1432
  }, [preloadedNodes, editableNodes.length, onLoad]);
1433
+ React2.useEffect(() => {
1434
+ const checkMemory = () => {
1435
+ if (window.performance?.memory) {
1436
+ const memInfo = window.performance.memory;
1437
+ const usage = memInfo.usedJSHeapSize / memInfo.totalJSHeapSize;
1438
+ setMemoryUsage(usage);
1439
+ if (usage > 0.9) {
1440
+ emergencyMemoryCleanup();
1441
+ }
1442
+ }
1443
+ };
1444
+ const interval = setInterval(checkMemory, 15e3);
1445
+ return () => clearInterval(interval);
1446
+ }, [currentNodeIndex, editableNodes]);
1330
1447
  const handlePlaybackEnded = (nodeIndex) => {
1331
1448
  console.log(`\u{1F3B5} [MMDPlaylist] \u8282\u70B9 ${nodeIndex} \u64AD\u653E\u5B8C\u6210`);
1332
1449
  if (nodeIndex !== currentNodeIndexRef.current) {
@@ -1436,6 +1553,11 @@ var MMDPlaylist = ({
1436
1553
  /* @__PURE__ */ React2__default.default.createElement(
1437
1554
  MMDPlayerEnhanced,
1438
1555
  {
1556
+ ref: (componentRef) => {
1557
+ if (componentRef) {
1558
+ playerComponentRefs.current.set(index, componentRef);
1559
+ }
1560
+ },
1439
1561
  resources: node.resources,
1440
1562
  stage,
1441
1563
  autoPlay: index === currentNodeIndex && shouldAutoPlayInitial,