@lumy-pack/scene-sieve 0.0.11 → 0.0.13

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/dist/cli.mjs CHANGED
@@ -173,6 +173,7 @@ var init_dbscan = __esm({
173
173
 
174
174
  // src/core/analyzer.ts
175
175
  import { createRequire } from "module";
176
+ import { filter, map } from "@winglet/common-utils";
176
177
  import sharp from "sharp";
177
178
  async function ensureOpenCV() {
178
179
  if (!cvReady) {
@@ -356,7 +357,7 @@ function computeInformationGain(clusters, clusterPoints, imageArea, animationInd
356
357
  async function analyzeBatch(cvLib, frames, scale, tracker, pairOffset) {
357
358
  const edges = [];
358
359
  const preprocessed = await Promise.all(
359
- frames.map((f) => preprocessFrame(f.extractPath, scale))
360
+ map(frames, (f) => preprocessFrame(f.extractPath, scale))
360
361
  );
361
362
  const imageWidth = preprocessed[0]?.width ?? scale;
362
363
  const imageHeight = preprocessed[0]?.height ?? Math.round(scale * 9 / 16);
@@ -398,7 +399,8 @@ async function analyzeBatch(cvLib, frames, scale, tracker, pairOffset) {
398
399
  }
399
400
  }
400
401
  const animationIndices = tracker.update(clusters, pairIndex);
401
- const animationWeights = clusters.map(
402
+ const animationWeights = map(
403
+ clusters,
402
404
  (_, ci) => animationIndices.has(ci) ? tracker.getAnimationWeight(ci, clusters) : 0
403
405
  );
404
406
  const score = computeInformationGain(
@@ -524,7 +526,8 @@ var init_analyzer = __esm({
524
526
  this.collectAnimation(region);
525
527
  }
526
528
  }
527
- this.regions = this.regions.filter(
529
+ this.regions = filter(
530
+ this.regions,
528
531
  (r, i) => r.weight > 0.01 || matched.has(i)
529
532
  );
530
533
  return animationIndices;
@@ -607,6 +610,7 @@ var init_paths = __esm({
607
610
  import { readdir } from "fs/promises";
608
611
  import { join as join2 } from "path";
609
612
  import { path as ffprobePath } from "@ffprobe-installer/ffprobe";
613
+ import { filter as filter2, map as map2 } from "@winglet/common-utils";
610
614
  import { execa } from "execa";
611
615
  import ffmpegPath from "ffmpeg-static";
612
616
  async function extractFrames(ctx) {
@@ -685,11 +689,11 @@ async function getVideoMetadata(inputPath) {
685
689
  }
686
690
  async function buildFrameList(framesDir, duration) {
687
691
  const files = await readdir(framesDir);
688
- const jpgFiles = files.filter((f) => f.endsWith(".jpg")).sort();
692
+ const jpgFiles = filter2(files, (f) => f.endsWith(".jpg")).sort();
689
693
  if (jpgFiles.length === 0) {
690
694
  return [];
691
695
  }
692
- return jpgFiles.map((file, index) => ({
696
+ return map2(jpgFiles, (file, index) => ({
693
697
  id: index,
694
698
  timestamp: duration > 0 && jpgFiles.length > 1 ? duration * index / (jpgFiles.length - 1) : index,
695
699
  extractPath: join2(framesDir, file)
@@ -724,6 +728,7 @@ var init_extractor = __esm({
724
728
  // src/core/workspace.ts
725
729
  import { readdir as readdir2, rename, rm, stat as stat2, writeFile } from "fs/promises";
726
730
  import { join as join3 } from "path";
731
+ import { map as map3 } from "@winglet/common-utils";
727
732
  import sharp2 from "sharp";
728
733
  async function createWorkspace(sessionId) {
729
734
  const workspacePath = getTempWorkspaceDir(sessionId);
@@ -764,7 +769,7 @@ async function finalizeOutput(ctx, selectedFrames) {
764
769
  }
765
770
  },
766
771
  frames: framesMetadata,
767
- animations: (ctx.animations || []).map((anim) => ({
772
+ animations: map3(ctx.animations || [], (anim) => ({
768
773
  ...anim,
769
774
  startFrameId: anim.startFrameId + 1,
770
775
  endFrameId: anim.endFrameId + 1,
@@ -831,7 +836,8 @@ async function writeInputFrames(frames, workspacePath) {
831
836
  }
832
837
  async function readFramesAsBuffers(frameNodes, quality) {
833
838
  return Promise.all(
834
- frameNodes.map(
839
+ map3(
840
+ frameNodes,
835
841
  (f) => sharp2(f.extractPath).jpeg({ quality, mozjpeg: true }).toBuffer()
836
842
  )
837
843
  );
@@ -907,38 +913,42 @@ var init_input_resolver = __esm({
907
913
  });
908
914
 
909
915
  // src/utils/math.ts
916
+ import { filter as filter3, map as map4 } from "@winglet/common-utils";
910
917
  function normalizeScores(items) {
911
918
  if (items.length === 0) return [];
912
- const safeScores = items.map(
919
+ const safeScores = map4(
920
+ items,
913
921
  (e) => Number.isFinite(e.score) && e.score > 0 ? e.score : 0
914
922
  );
915
- const positiveScores = safeScores.filter((s) => s > 0);
923
+ const positiveScores = filter3(safeScores, (s) => s > 0);
916
924
  if (positiveScores.length === 0) return safeScores;
917
925
  const sorted = [...positiveScores].sort((a, b) => a - b);
918
926
  if (positiveScores.length <= NORMALIZATION_MIN_SAMPLE_SIZE) {
919
927
  const min = sorted[0];
920
928
  const max = sorted[sorted.length - 1];
921
- if (max === min) return safeScores.map((s) => s > 0 ? 1 : 0);
922
- return safeScores.map(
929
+ if (max === min) return map4(safeScores, (s) => s > 0 ? 1 : 0);
930
+ return map4(
931
+ safeScores,
923
932
  (s) => s <= 0 ? 0 : Math.max(0, Math.min((s - min) / (max - min), 1))
924
933
  );
925
934
  }
926
935
  const median = sorted[Math.floor(sorted.length / 2)];
927
- const absoluteDiffs = positiveScores.map((v) => Math.abs(v - median));
936
+ const absoluteDiffs = map4(positiveScores, (v) => Math.abs(v - median));
928
937
  const mad = [...absoluteDiffs].sort((a, b) => a - b)[Math.floor(absoluteDiffs.length / 2)];
929
938
  const scale = mad === 0 ? median : mad * NORMALIZATION_MAD_COEFFICIENT;
930
- const logisticZ = safeScores.map((s) => {
939
+ const logisticZ = map4(safeScores, (s) => {
931
940
  if (s <= 0) return 0;
932
941
  if (scale === 0) return 1;
933
942
  const z = (s - median) / scale;
934
943
  return 1 / (1 + Math.exp(-NORMALIZATION_LOGISTIC_K * z));
935
944
  });
936
- const cdf = safeScores.map((s) => {
945
+ const cdf = map4(safeScores, (s) => {
937
946
  if (s <= 0) return 0;
938
947
  const rank = sorted.findIndex((v) => v >= s);
939
948
  return rank / sorted.length;
940
949
  });
941
- return logisticZ.map(
950
+ return map4(
951
+ logisticZ,
942
952
  (z, i) => z * (1 - NORMALIZATION_ALPHA) + cdf[i] * NORMALIZATION_ALPHA
943
953
  );
944
954
  }
@@ -1000,9 +1010,10 @@ var init_min_heap = __esm({
1000
1010
  });
1001
1011
 
1002
1012
  // src/core/pruner.ts
1013
+ import { filter as filter4, map as map5 } from "@winglet/common-utils";
1003
1014
  function pruneTo(graph, frames, targetCount) {
1004
1015
  if (frames.length <= targetCount) {
1005
- return new Set(frames.map((f) => f.id));
1016
+ return new Set(map5(frames, (f) => f.id));
1006
1017
  }
1007
1018
  const prev = /* @__PURE__ */ new Map();
1008
1019
  const next = /* @__PURE__ */ new Map();
@@ -1020,7 +1031,7 @@ function pruneTo(graph, frames, targetCount) {
1020
1031
  tgtId: edge.targetId
1021
1032
  });
1022
1033
  }
1023
- const surviving = new Set(frames.map((f) => f.id));
1034
+ const surviving = new Set(map5(frames, (f) => f.id));
1024
1035
  const firstId = frames[0].id;
1025
1036
  const lastId = frames[frames.length - 1].id;
1026
1037
  while (surviving.size > targetCount && heap.size > 0) {
@@ -1113,7 +1124,7 @@ function pruneByThresholdWithCap(graph, frames, threshold, maxCount) {
1113
1124
  if (thresholdSurvivors.size <= maxCount) {
1114
1125
  return thresholdSurvivors;
1115
1126
  }
1116
- const survivingFrames = frames.filter((f) => thresholdSurvivors.has(f.id));
1127
+ const survivingFrames = filter4(frames, (f) => thresholdSurvivors.has(f.id));
1117
1128
  const idToOrigIdx = /* @__PURE__ */ new Map();
1118
1129
  for (let i = 0; i < frames.length; i++) {
1119
1130
  idToOrigIdx.set(frames[i].id, i);
@@ -1180,6 +1191,7 @@ var init_concurrency = __esm({
1180
1191
  // src/core/segmenter.ts
1181
1192
  import { randomUUID } from "crypto";
1182
1193
  import { join as join5 } from "path";
1194
+ import { filter as filter5, map as map6 } from "@winglet/common-utils";
1183
1195
  function shouldSegment(resolvedOptions, originalOptions) {
1184
1196
  if (resolvedOptions.mode === "frames") return false;
1185
1197
  if (originalOptions.mode === "file") {
@@ -1422,7 +1434,7 @@ async function runSegmentedPipeline(options, resolvedOptions) {
1422
1434
  logger.debug(`Segment plan: ${segments.length} segments`);
1423
1435
  const limit = concurrencyLimit(resolvedOptions.concurrency);
1424
1436
  const segmentProgresses = new Array(segments.length).fill(0);
1425
- const weights = segments.map((s) => s.duration / totalDuration);
1437
+ const weights = map6(segments, (s) => s.duration / totalDuration);
1426
1438
  const emitOverallProgress = (phase) => {
1427
1439
  if (!options.onProgress) return;
1428
1440
  const overall = weights.reduce(
@@ -1433,7 +1445,8 @@ async function runSegmentedPipeline(options, resolvedOptions) {
1433
1445
  };
1434
1446
  options.onProgress?.("EXTRACTING", 0);
1435
1447
  const results = await Promise.all(
1436
- segments.map(
1448
+ map6(
1449
+ segments,
1437
1450
  (segment) => limit(async () => {
1438
1451
  const segWorkspace = await createSegmentWorkspace(
1439
1452
  mainWorkspace,
@@ -1465,7 +1478,7 @@ async function runSegmentedPipeline(options, resolvedOptions) {
1465
1478
  resolvedOptions.threshold,
1466
1479
  resolvedOptions.count
1467
1480
  );
1468
- const prunedFrames = frames.filter((f) => survivingIds.has(f.id));
1481
+ const prunedFrames = filter5(frames, (f) => survivingIds.has(f.id));
1469
1482
  options.onProgress?.("PRUNING", 100);
1470
1483
  options.onProgress?.("FINALIZING", 0);
1471
1484
  const ctx = {
@@ -1539,6 +1552,7 @@ __export(orchestrator_exports, {
1539
1552
  runPipeline: () => runPipeline
1540
1553
  });
1541
1554
  import { randomUUID as randomUUID2 } from "crypto";
1555
+ import { filter as filter6 } from "@winglet/common-utils";
1542
1556
  async function runPipeline(options) {
1543
1557
  const debug = options.debug ?? false;
1544
1558
  if (debug) setDebugMode(true);
@@ -1592,7 +1606,7 @@ async function runPipeline(options) {
1592
1606
  resolvedOptions.threshold,
1593
1607
  resolvedOptions.count
1594
1608
  );
1595
- const prunedFrames = ctx.frames.filter((f) => survivingIds.has(f.id));
1609
+ const prunedFrames = filter6(ctx.frames, (f) => survivingIds.has(f.id));
1596
1610
  ctx.emitProgress(100);
1597
1611
  ctx.status = "FINALIZING";
1598
1612
  let outputFiles = [];
@@ -1656,7 +1670,6 @@ var init_orchestrator = __esm({
1656
1670
 
1657
1671
  // src/cli.ts
1658
1672
  import { createRequire as createRequire2 } from "module";
1659
- import { Command } from "commander";
1660
1673
 
1661
1674
  // ../shared/src/respond.ts
1662
1675
  function respond(command, data, startTime, version2) {
@@ -1687,6 +1700,9 @@ function respondError(command, code, message, startTime, version2, details) {
1687
1700
  process.exitCode = 1;
1688
1701
  }
1689
1702
 
1703
+ // src/cli.ts
1704
+ import { Command } from "commander";
1705
+
1690
1706
  // src/commands/Sieve.tsx
1691
1707
  import { existsSync } from "fs";
1692
1708
  import { Box as Box2, Text as Text3, useApp } from "ink";
@@ -2202,7 +2218,13 @@ if (process.argv.includes("--describe")) {
2202
2218
  }
2203
2219
  program.parseAsync(process.argv).catch((error) => {
2204
2220
  if (process.argv.includes("--json")) {
2205
- respondError("extract", SieveErrorCode.UNKNOWN, error.message, Date.now(), version);
2221
+ respondError(
2222
+ "extract",
2223
+ SieveErrorCode.UNKNOWN,
2224
+ error.message,
2225
+ Date.now(),
2226
+ version
2227
+ );
2206
2228
  } else {
2207
2229
  console.error("Fatal error:", error.message);
2208
2230
  }
package/dist/index.cjs CHANGED
@@ -40,6 +40,7 @@ var importMetaUrl = /* @__PURE__ */ getImportMetaUrl();
40
40
 
41
41
  // src/core/orchestrator.ts
42
42
  var import_node_crypto2 = require("crypto");
43
+ var import_common_utils7 = require("@winglet/common-utils");
43
44
 
44
45
  // src/utils/logger.ts
45
46
  var import_picocolors = __toESM(require("picocolors"), 1);
@@ -73,6 +74,7 @@ ${import_picocolors.default.green("done")} ${message}`);
73
74
 
74
75
  // src/core/analyzer.ts
75
76
  var import_node_module = require("module");
77
+ var import_common_utils = require("@winglet/common-utils");
76
78
  var import_sharp = __toESM(require("sharp"), 1);
77
79
 
78
80
  // src/constants.ts
@@ -289,7 +291,8 @@ var IoUTracker = class {
289
291
  this.collectAnimation(region);
290
292
  }
291
293
  }
292
- this.regions = this.regions.filter(
294
+ this.regions = (0, import_common_utils.filter)(
295
+ this.regions,
293
296
  (r, i) => r.weight > 0.01 || matched.has(i)
294
297
  );
295
298
  return animationIndices;
@@ -470,7 +473,7 @@ function computeInformationGain(clusters, clusterPoints, imageArea, animationInd
470
473
  async function analyzeBatch(cvLib, frames, scale, tracker, pairOffset) {
471
474
  const edges = [];
472
475
  const preprocessed = await Promise.all(
473
- frames.map((f) => preprocessFrame(f.extractPath, scale))
476
+ (0, import_common_utils.map)(frames, (f) => preprocessFrame(f.extractPath, scale))
474
477
  );
475
478
  const imageWidth = preprocessed[0]?.width ?? scale;
476
479
  const imageHeight = preprocessed[0]?.height ?? Math.round(scale * 9 / 16);
@@ -512,7 +515,8 @@ async function analyzeBatch(cvLib, frames, scale, tracker, pairOffset) {
512
515
  }
513
516
  }
514
517
  const animationIndices = tracker.update(clusters, pairIndex);
515
- const animationWeights = clusters.map(
518
+ const animationWeights = (0, import_common_utils.map)(
519
+ clusters,
516
520
  (_, ci) => animationIndices.has(ci) ? tracker.getAnimationWeight(ci, clusters) : 0
517
521
  );
518
522
  const score = computeInformationGain(
@@ -577,6 +581,7 @@ async function analyzeFrames(ctx) {
577
581
  var import_promises2 = require("fs/promises");
578
582
  var import_node_path3 = require("path");
579
583
  var import_ffprobe = require("@ffprobe-installer/ffprobe");
584
+ var import_common_utils2 = require("@winglet/common-utils");
580
585
  var import_execa = require("execa");
581
586
  var import_ffmpeg_static = __toESM(require("ffmpeg-static"), 1);
582
587
 
@@ -688,11 +693,11 @@ async function getVideoMetadata(inputPath) {
688
693
  }
689
694
  async function buildFrameList(framesDir, duration) {
690
695
  const files = await (0, import_promises2.readdir)(framesDir);
691
- const jpgFiles = files.filter((f) => f.endsWith(".jpg")).sort();
696
+ const jpgFiles = (0, import_common_utils2.filter)(files, (f) => f.endsWith(".jpg")).sort();
692
697
  if (jpgFiles.length === 0) {
693
698
  return [];
694
699
  }
695
- return jpgFiles.map((file, index) => ({
700
+ return (0, import_common_utils2.map)(jpgFiles, (file, index) => ({
696
701
  id: index,
697
702
  timestamp: duration > 0 && jpgFiles.length > 1 ? duration * index / (jpgFiles.length - 1) : index,
698
703
  extractPath: (0, import_node_path3.join)(framesDir, file)
@@ -722,6 +727,7 @@ var import_node_path5 = require("path");
722
727
  // src/core/workspace.ts
723
728
  var import_promises3 = require("fs/promises");
724
729
  var import_node_path4 = require("path");
730
+ var import_common_utils3 = require("@winglet/common-utils");
725
731
  var import_sharp2 = __toESM(require("sharp"), 1);
726
732
  async function createWorkspace(sessionId) {
727
733
  const workspacePath = getTempWorkspaceDir(sessionId);
@@ -762,7 +768,7 @@ async function finalizeOutput(ctx, selectedFrames) {
762
768
  }
763
769
  },
764
770
  frames: framesMetadata,
765
- animations: (ctx.animations || []).map((anim) => ({
771
+ animations: (0, import_common_utils3.map)(ctx.animations || [], (anim) => ({
766
772
  ...anim,
767
773
  startFrameId: anim.startFrameId + 1,
768
774
  endFrameId: anim.endFrameId + 1,
@@ -815,7 +821,8 @@ async function writeInputFrames(frames, workspacePath) {
815
821
  }
816
822
  async function readFramesAsBuffers(frameNodes, quality) {
817
823
  return Promise.all(
818
- frameNodes.map(
824
+ (0, import_common_utils3.map)(
825
+ frameNodes,
819
826
  (f) => (0, import_sharp2.default)(f.extractPath).jpeg({ quality, mozjpeg: true }).toBuffer()
820
827
  )
821
828
  );
@@ -872,39 +879,46 @@ async function resolveInput(options, workspacePath) {
872
879
  throw new Error(`Unsupported input mode: ${options.mode}`);
873
880
  }
874
881
 
882
+ // src/core/pruner.ts
883
+ var import_common_utils5 = require("@winglet/common-utils");
884
+
875
885
  // src/utils/math.ts
886
+ var import_common_utils4 = require("@winglet/common-utils");
876
887
  function normalizeScores(items) {
877
888
  if (items.length === 0) return [];
878
- const safeScores = items.map(
889
+ const safeScores = (0, import_common_utils4.map)(
890
+ items,
879
891
  (e) => Number.isFinite(e.score) && e.score > 0 ? e.score : 0
880
892
  );
881
- const positiveScores = safeScores.filter((s) => s > 0);
893
+ const positiveScores = (0, import_common_utils4.filter)(safeScores, (s) => s > 0);
882
894
  if (positiveScores.length === 0) return safeScores;
883
895
  const sorted = [...positiveScores].sort((a, b) => a - b);
884
896
  if (positiveScores.length <= NORMALIZATION_MIN_SAMPLE_SIZE) {
885
897
  const min = sorted[0];
886
898
  const max = sorted[sorted.length - 1];
887
- if (max === min) return safeScores.map((s) => s > 0 ? 1 : 0);
888
- return safeScores.map(
899
+ if (max === min) return (0, import_common_utils4.map)(safeScores, (s) => s > 0 ? 1 : 0);
900
+ return (0, import_common_utils4.map)(
901
+ safeScores,
889
902
  (s) => s <= 0 ? 0 : Math.max(0, Math.min((s - min) / (max - min), 1))
890
903
  );
891
904
  }
892
905
  const median = sorted[Math.floor(sorted.length / 2)];
893
- const absoluteDiffs = positiveScores.map((v) => Math.abs(v - median));
906
+ const absoluteDiffs = (0, import_common_utils4.map)(positiveScores, (v) => Math.abs(v - median));
894
907
  const mad = [...absoluteDiffs].sort((a, b) => a - b)[Math.floor(absoluteDiffs.length / 2)];
895
908
  const scale = mad === 0 ? median : mad * NORMALIZATION_MAD_COEFFICIENT;
896
- const logisticZ = safeScores.map((s) => {
909
+ const logisticZ = (0, import_common_utils4.map)(safeScores, (s) => {
897
910
  if (s <= 0) return 0;
898
911
  if (scale === 0) return 1;
899
912
  const z = (s - median) / scale;
900
913
  return 1 / (1 + Math.exp(-NORMALIZATION_LOGISTIC_K * z));
901
914
  });
902
- const cdf = safeScores.map((s) => {
915
+ const cdf = (0, import_common_utils4.map)(safeScores, (s) => {
903
916
  if (s <= 0) return 0;
904
917
  const rank = sorted.findIndex((v) => v >= s);
905
918
  return rank / sorted.length;
906
919
  });
907
- return logisticZ.map(
920
+ return (0, import_common_utils4.map)(
921
+ logisticZ,
908
922
  (z, i) => z * (1 - NORMALIZATION_ALPHA) + cdf[i] * NORMALIZATION_ALPHA
909
923
  );
910
924
  }
@@ -956,7 +970,7 @@ var MinHeap = class {
956
970
  // src/core/pruner.ts
957
971
  function pruneTo(graph, frames, targetCount) {
958
972
  if (frames.length <= targetCount) {
959
- return new Set(frames.map((f) => f.id));
973
+ return new Set((0, import_common_utils5.map)(frames, (f) => f.id));
960
974
  }
961
975
  const prev = /* @__PURE__ */ new Map();
962
976
  const next = /* @__PURE__ */ new Map();
@@ -974,7 +988,7 @@ function pruneTo(graph, frames, targetCount) {
974
988
  tgtId: edge.targetId
975
989
  });
976
990
  }
977
- const surviving = new Set(frames.map((f) => f.id));
991
+ const surviving = new Set((0, import_common_utils5.map)(frames, (f) => f.id));
978
992
  const firstId = frames[0].id;
979
993
  const lastId = frames[frames.length - 1].id;
980
994
  while (surviving.size > targetCount && heap.size > 0) {
@@ -1067,7 +1081,7 @@ function pruneByThresholdWithCap(graph, frames, threshold, maxCount) {
1067
1081
  if (thresholdSurvivors.size <= maxCount) {
1068
1082
  return thresholdSurvivors;
1069
1083
  }
1070
- const survivingFrames = frames.filter((f) => thresholdSurvivors.has(f.id));
1084
+ const survivingFrames = (0, import_common_utils5.filter)(frames, (f) => thresholdSurvivors.has(f.id));
1071
1085
  const idToOrigIdx = /* @__PURE__ */ new Map();
1072
1086
  for (let i = 0; i < frames.length; i++) {
1073
1087
  idToOrigIdx.set(frames[i].id, i);
@@ -1103,6 +1117,7 @@ function pruneByThresholdWithCap(graph, frames, threshold, maxCount) {
1103
1117
  // src/core/segmenter.ts
1104
1118
  var import_node_crypto = require("crypto");
1105
1119
  var import_node_path6 = require("path");
1120
+ var import_common_utils6 = require("@winglet/common-utils");
1106
1121
 
1107
1122
  // src/utils/concurrency.ts
1108
1123
  function concurrencyLimit(limit) {
@@ -1366,7 +1381,7 @@ async function runSegmentedPipeline(options, resolvedOptions) {
1366
1381
  logger.debug(`Segment plan: ${segments.length} segments`);
1367
1382
  const limit = concurrencyLimit(resolvedOptions.concurrency);
1368
1383
  const segmentProgresses = new Array(segments.length).fill(0);
1369
- const weights = segments.map((s) => s.duration / totalDuration);
1384
+ const weights = (0, import_common_utils6.map)(segments, (s) => s.duration / totalDuration);
1370
1385
  const emitOverallProgress = (phase) => {
1371
1386
  if (!options.onProgress) return;
1372
1387
  const overall = weights.reduce(
@@ -1377,7 +1392,8 @@ async function runSegmentedPipeline(options, resolvedOptions) {
1377
1392
  };
1378
1393
  options.onProgress?.("EXTRACTING", 0);
1379
1394
  const results = await Promise.all(
1380
- segments.map(
1395
+ (0, import_common_utils6.map)(
1396
+ segments,
1381
1397
  (segment) => limit(async () => {
1382
1398
  const segWorkspace = await createSegmentWorkspace(
1383
1399
  mainWorkspace,
@@ -1409,7 +1425,7 @@ async function runSegmentedPipeline(options, resolvedOptions) {
1409
1425
  resolvedOptions.threshold,
1410
1426
  resolvedOptions.count
1411
1427
  );
1412
- const prunedFrames = frames.filter((f) => survivingIds.has(f.id));
1428
+ const prunedFrames = (0, import_common_utils6.filter)(frames, (f) => survivingIds.has(f.id));
1413
1429
  options.onProgress?.("PRUNING", 100);
1414
1430
  options.onProgress?.("FINALIZING", 0);
1415
1431
  const ctx = {
@@ -1519,7 +1535,7 @@ async function runPipeline(options) {
1519
1535
  resolvedOptions.threshold,
1520
1536
  resolvedOptions.count
1521
1537
  );
1522
- const prunedFrames = ctx.frames.filter((f) => survivingIds.has(f.id));
1538
+ const prunedFrames = (0, import_common_utils7.filter)(ctx.frames, (f) => survivingIds.has(f.id));
1523
1539
  ctx.emitProgress(100);
1524
1540
  ctx.status = "FINALIZING";
1525
1541
  let outputFiles = [];
package/dist/index.mjs CHANGED
@@ -1,5 +1,6 @@
1
1
  // src/core/orchestrator.ts
2
2
  import { randomUUID as randomUUID2 } from "crypto";
3
+ import { filter as filter6 } from "@winglet/common-utils";
3
4
 
4
5
  // src/utils/logger.ts
5
6
  import pc from "picocolors";
@@ -33,6 +34,7 @@ ${pc.green("done")} ${message}`);
33
34
 
34
35
  // src/core/analyzer.ts
35
36
  import { createRequire } from "module";
37
+ import { filter, map } from "@winglet/common-utils";
36
38
  import sharp from "sharp";
37
39
 
38
40
  // src/constants.ts
@@ -249,7 +251,8 @@ var IoUTracker = class {
249
251
  this.collectAnimation(region);
250
252
  }
251
253
  }
252
- this.regions = this.regions.filter(
254
+ this.regions = filter(
255
+ this.regions,
253
256
  (r, i) => r.weight > 0.01 || matched.has(i)
254
257
  );
255
258
  return animationIndices;
@@ -430,7 +433,7 @@ function computeInformationGain(clusters, clusterPoints, imageArea, animationInd
430
433
  async function analyzeBatch(cvLib, frames, scale, tracker, pairOffset) {
431
434
  const edges = [];
432
435
  const preprocessed = await Promise.all(
433
- frames.map((f) => preprocessFrame(f.extractPath, scale))
436
+ map(frames, (f) => preprocessFrame(f.extractPath, scale))
434
437
  );
435
438
  const imageWidth = preprocessed[0]?.width ?? scale;
436
439
  const imageHeight = preprocessed[0]?.height ?? Math.round(scale * 9 / 16);
@@ -472,7 +475,8 @@ async function analyzeBatch(cvLib, frames, scale, tracker, pairOffset) {
472
475
  }
473
476
  }
474
477
  const animationIndices = tracker.update(clusters, pairIndex);
475
- const animationWeights = clusters.map(
478
+ const animationWeights = map(
479
+ clusters,
476
480
  (_, ci) => animationIndices.has(ci) ? tracker.getAnimationWeight(ci, clusters) : 0
477
481
  );
478
482
  const score = computeInformationGain(
@@ -537,6 +541,7 @@ async function analyzeFrames(ctx) {
537
541
  import { readdir } from "fs/promises";
538
542
  import { join as join2 } from "path";
539
543
  import { path as ffprobePath } from "@ffprobe-installer/ffprobe";
544
+ import { filter as filter2, map as map2 } from "@winglet/common-utils";
540
545
  import { execa } from "execa";
541
546
  import ffmpegPath from "ffmpeg-static";
542
547
 
@@ -648,11 +653,11 @@ async function getVideoMetadata(inputPath) {
648
653
  }
649
654
  async function buildFrameList(framesDir, duration) {
650
655
  const files = await readdir(framesDir);
651
- const jpgFiles = files.filter((f) => f.endsWith(".jpg")).sort();
656
+ const jpgFiles = filter2(files, (f) => f.endsWith(".jpg")).sort();
652
657
  if (jpgFiles.length === 0) {
653
658
  return [];
654
659
  }
655
- return jpgFiles.map((file, index) => ({
660
+ return map2(jpgFiles, (file, index) => ({
656
661
  id: index,
657
662
  timestamp: duration > 0 && jpgFiles.length > 1 ? duration * index / (jpgFiles.length - 1) : index,
658
663
  extractPath: join2(framesDir, file)
@@ -682,6 +687,7 @@ import { join as join4 } from "path";
682
687
  // src/core/workspace.ts
683
688
  import { readdir as readdir2, rename, rm, stat as stat2, writeFile } from "fs/promises";
684
689
  import { join as join3 } from "path";
690
+ import { map as map3 } from "@winglet/common-utils";
685
691
  import sharp2 from "sharp";
686
692
  async function createWorkspace(sessionId) {
687
693
  const workspacePath = getTempWorkspaceDir(sessionId);
@@ -722,7 +728,7 @@ async function finalizeOutput(ctx, selectedFrames) {
722
728
  }
723
729
  },
724
730
  frames: framesMetadata,
725
- animations: (ctx.animations || []).map((anim) => ({
731
+ animations: map3(ctx.animations || [], (anim) => ({
726
732
  ...anim,
727
733
  startFrameId: anim.startFrameId + 1,
728
734
  endFrameId: anim.endFrameId + 1,
@@ -775,7 +781,8 @@ async function writeInputFrames(frames, workspacePath) {
775
781
  }
776
782
  async function readFramesAsBuffers(frameNodes, quality) {
777
783
  return Promise.all(
778
- frameNodes.map(
784
+ map3(
785
+ frameNodes,
779
786
  (f) => sharp2(f.extractPath).jpeg({ quality, mozjpeg: true }).toBuffer()
780
787
  )
781
788
  );
@@ -832,39 +839,46 @@ async function resolveInput(options, workspacePath) {
832
839
  throw new Error(`Unsupported input mode: ${options.mode}`);
833
840
  }
834
841
 
842
+ // src/core/pruner.ts
843
+ import { filter as filter4, map as map5 } from "@winglet/common-utils";
844
+
835
845
  // src/utils/math.ts
846
+ import { filter as filter3, map as map4 } from "@winglet/common-utils";
836
847
  function normalizeScores(items) {
837
848
  if (items.length === 0) return [];
838
- const safeScores = items.map(
849
+ const safeScores = map4(
850
+ items,
839
851
  (e) => Number.isFinite(e.score) && e.score > 0 ? e.score : 0
840
852
  );
841
- const positiveScores = safeScores.filter((s) => s > 0);
853
+ const positiveScores = filter3(safeScores, (s) => s > 0);
842
854
  if (positiveScores.length === 0) return safeScores;
843
855
  const sorted = [...positiveScores].sort((a, b) => a - b);
844
856
  if (positiveScores.length <= NORMALIZATION_MIN_SAMPLE_SIZE) {
845
857
  const min = sorted[0];
846
858
  const max = sorted[sorted.length - 1];
847
- if (max === min) return safeScores.map((s) => s > 0 ? 1 : 0);
848
- return safeScores.map(
859
+ if (max === min) return map4(safeScores, (s) => s > 0 ? 1 : 0);
860
+ return map4(
861
+ safeScores,
849
862
  (s) => s <= 0 ? 0 : Math.max(0, Math.min((s - min) / (max - min), 1))
850
863
  );
851
864
  }
852
865
  const median = sorted[Math.floor(sorted.length / 2)];
853
- const absoluteDiffs = positiveScores.map((v) => Math.abs(v - median));
866
+ const absoluteDiffs = map4(positiveScores, (v) => Math.abs(v - median));
854
867
  const mad = [...absoluteDiffs].sort((a, b) => a - b)[Math.floor(absoluteDiffs.length / 2)];
855
868
  const scale = mad === 0 ? median : mad * NORMALIZATION_MAD_COEFFICIENT;
856
- const logisticZ = safeScores.map((s) => {
869
+ const logisticZ = map4(safeScores, (s) => {
857
870
  if (s <= 0) return 0;
858
871
  if (scale === 0) return 1;
859
872
  const z = (s - median) / scale;
860
873
  return 1 / (1 + Math.exp(-NORMALIZATION_LOGISTIC_K * z));
861
874
  });
862
- const cdf = safeScores.map((s) => {
875
+ const cdf = map4(safeScores, (s) => {
863
876
  if (s <= 0) return 0;
864
877
  const rank = sorted.findIndex((v) => v >= s);
865
878
  return rank / sorted.length;
866
879
  });
867
- return logisticZ.map(
880
+ return map4(
881
+ logisticZ,
868
882
  (z, i) => z * (1 - NORMALIZATION_ALPHA) + cdf[i] * NORMALIZATION_ALPHA
869
883
  );
870
884
  }
@@ -916,7 +930,7 @@ var MinHeap = class {
916
930
  // src/core/pruner.ts
917
931
  function pruneTo(graph, frames, targetCount) {
918
932
  if (frames.length <= targetCount) {
919
- return new Set(frames.map((f) => f.id));
933
+ return new Set(map5(frames, (f) => f.id));
920
934
  }
921
935
  const prev = /* @__PURE__ */ new Map();
922
936
  const next = /* @__PURE__ */ new Map();
@@ -934,7 +948,7 @@ function pruneTo(graph, frames, targetCount) {
934
948
  tgtId: edge.targetId
935
949
  });
936
950
  }
937
- const surviving = new Set(frames.map((f) => f.id));
951
+ const surviving = new Set(map5(frames, (f) => f.id));
938
952
  const firstId = frames[0].id;
939
953
  const lastId = frames[frames.length - 1].id;
940
954
  while (surviving.size > targetCount && heap.size > 0) {
@@ -1027,7 +1041,7 @@ function pruneByThresholdWithCap(graph, frames, threshold, maxCount) {
1027
1041
  if (thresholdSurvivors.size <= maxCount) {
1028
1042
  return thresholdSurvivors;
1029
1043
  }
1030
- const survivingFrames = frames.filter((f) => thresholdSurvivors.has(f.id));
1044
+ const survivingFrames = filter4(frames, (f) => thresholdSurvivors.has(f.id));
1031
1045
  const idToOrigIdx = /* @__PURE__ */ new Map();
1032
1046
  for (let i = 0; i < frames.length; i++) {
1033
1047
  idToOrigIdx.set(frames[i].id, i);
@@ -1063,6 +1077,7 @@ function pruneByThresholdWithCap(graph, frames, threshold, maxCount) {
1063
1077
  // src/core/segmenter.ts
1064
1078
  import { randomUUID } from "crypto";
1065
1079
  import { join as join5 } from "path";
1080
+ import { filter as filter5, map as map6 } from "@winglet/common-utils";
1066
1081
 
1067
1082
  // src/utils/concurrency.ts
1068
1083
  function concurrencyLimit(limit) {
@@ -1326,7 +1341,7 @@ async function runSegmentedPipeline(options, resolvedOptions) {
1326
1341
  logger.debug(`Segment plan: ${segments.length} segments`);
1327
1342
  const limit = concurrencyLimit(resolvedOptions.concurrency);
1328
1343
  const segmentProgresses = new Array(segments.length).fill(0);
1329
- const weights = segments.map((s) => s.duration / totalDuration);
1344
+ const weights = map6(segments, (s) => s.duration / totalDuration);
1330
1345
  const emitOverallProgress = (phase) => {
1331
1346
  if (!options.onProgress) return;
1332
1347
  const overall = weights.reduce(
@@ -1337,7 +1352,8 @@ async function runSegmentedPipeline(options, resolvedOptions) {
1337
1352
  };
1338
1353
  options.onProgress?.("EXTRACTING", 0);
1339
1354
  const results = await Promise.all(
1340
- segments.map(
1355
+ map6(
1356
+ segments,
1341
1357
  (segment) => limit(async () => {
1342
1358
  const segWorkspace = await createSegmentWorkspace(
1343
1359
  mainWorkspace,
@@ -1369,7 +1385,7 @@ async function runSegmentedPipeline(options, resolvedOptions) {
1369
1385
  resolvedOptions.threshold,
1370
1386
  resolvedOptions.count
1371
1387
  );
1372
- const prunedFrames = frames.filter((f) => survivingIds.has(f.id));
1388
+ const prunedFrames = filter5(frames, (f) => survivingIds.has(f.id));
1373
1389
  options.onProgress?.("PRUNING", 100);
1374
1390
  options.onProgress?.("FINALIZING", 0);
1375
1391
  const ctx = {
@@ -1479,7 +1495,7 @@ async function runPipeline(options) {
1479
1495
  resolvedOptions.threshold,
1480
1496
  resolvedOptions.count
1481
1497
  );
1482
- const prunedFrames = ctx.frames.filter((f) => survivingIds.has(f.id));
1498
+ const prunedFrames = filter6(ctx.frames, (f) => survivingIds.has(f.id));
1483
1499
  ctx.emitProgress(100);
1484
1500
  ctx.status = "FINALIZING";
1485
1501
  let outputFiles = [];
@@ -3,6 +3,7 @@ import { parentPort, workerData } from "worker_threads";
3
3
 
4
4
  // src/core/orchestrator.ts
5
5
  import { randomUUID as randomUUID2 } from "crypto";
6
+ import { filter as filter6 } from "@winglet/common-utils";
6
7
 
7
8
  // src/utils/logger.ts
8
9
  import pc from "picocolors";
@@ -36,6 +37,7 @@ ${pc.green("done")} ${message}`);
36
37
 
37
38
  // src/core/analyzer.ts
38
39
  import { createRequire } from "module";
40
+ import { filter, map } from "@winglet/common-utils";
39
41
  import sharp from "sharp";
40
42
 
41
43
  // src/constants.ts
@@ -252,7 +254,8 @@ var IoUTracker = class {
252
254
  this.collectAnimation(region);
253
255
  }
254
256
  }
255
- this.regions = this.regions.filter(
257
+ this.regions = filter(
258
+ this.regions,
256
259
  (r, i) => r.weight > 0.01 || matched.has(i)
257
260
  );
258
261
  return animationIndices;
@@ -433,7 +436,7 @@ function computeInformationGain(clusters, clusterPoints, imageArea, animationInd
433
436
  async function analyzeBatch(cvLib, frames, scale, tracker, pairOffset) {
434
437
  const edges = [];
435
438
  const preprocessed = await Promise.all(
436
- frames.map((f) => preprocessFrame(f.extractPath, scale))
439
+ map(frames, (f) => preprocessFrame(f.extractPath, scale))
437
440
  );
438
441
  const imageWidth = preprocessed[0]?.width ?? scale;
439
442
  const imageHeight = preprocessed[0]?.height ?? Math.round(scale * 9 / 16);
@@ -475,7 +478,8 @@ async function analyzeBatch(cvLib, frames, scale, tracker, pairOffset) {
475
478
  }
476
479
  }
477
480
  const animationIndices = tracker.update(clusters, pairIndex);
478
- const animationWeights = clusters.map(
481
+ const animationWeights = map(
482
+ clusters,
479
483
  (_, ci) => animationIndices.has(ci) ? tracker.getAnimationWeight(ci, clusters) : 0
480
484
  );
481
485
  const score = computeInformationGain(
@@ -540,6 +544,7 @@ async function analyzeFrames(ctx) {
540
544
  import { readdir } from "fs/promises";
541
545
  import { join as join2 } from "path";
542
546
  import { path as ffprobePath } from "@ffprobe-installer/ffprobe";
547
+ import { filter as filter2, map as map2 } from "@winglet/common-utils";
543
548
  import { execa } from "execa";
544
549
  import ffmpegPath from "ffmpeg-static";
545
550
 
@@ -651,11 +656,11 @@ async function getVideoMetadata(inputPath) {
651
656
  }
652
657
  async function buildFrameList(framesDir, duration) {
653
658
  const files = await readdir(framesDir);
654
- const jpgFiles = files.filter((f) => f.endsWith(".jpg")).sort();
659
+ const jpgFiles = filter2(files, (f) => f.endsWith(".jpg")).sort();
655
660
  if (jpgFiles.length === 0) {
656
661
  return [];
657
662
  }
658
- return jpgFiles.map((file, index) => ({
663
+ return map2(jpgFiles, (file, index) => ({
659
664
  id: index,
660
665
  timestamp: duration > 0 && jpgFiles.length > 1 ? duration * index / (jpgFiles.length - 1) : index,
661
666
  extractPath: join2(framesDir, file)
@@ -685,6 +690,7 @@ import { join as join4 } from "path";
685
690
  // src/core/workspace.ts
686
691
  import { readdir as readdir2, rename, rm, stat as stat2, writeFile } from "fs/promises";
687
692
  import { join as join3 } from "path";
693
+ import { map as map3 } from "@winglet/common-utils";
688
694
  import sharp2 from "sharp";
689
695
  async function createWorkspace(sessionId) {
690
696
  const workspacePath = getTempWorkspaceDir(sessionId);
@@ -725,7 +731,7 @@ async function finalizeOutput(ctx, selectedFrames) {
725
731
  }
726
732
  },
727
733
  frames: framesMetadata,
728
- animations: (ctx.animations || []).map((anim) => ({
734
+ animations: map3(ctx.animations || [], (anim) => ({
729
735
  ...anim,
730
736
  startFrameId: anim.startFrameId + 1,
731
737
  endFrameId: anim.endFrameId + 1,
@@ -778,7 +784,8 @@ async function writeInputFrames(frames, workspacePath) {
778
784
  }
779
785
  async function readFramesAsBuffers(frameNodes, quality) {
780
786
  return Promise.all(
781
- frameNodes.map(
787
+ map3(
788
+ frameNodes,
782
789
  (f) => sharp2(f.extractPath).jpeg({ quality, mozjpeg: true }).toBuffer()
783
790
  )
784
791
  );
@@ -835,39 +842,46 @@ async function resolveInput(options2, workspacePath) {
835
842
  throw new Error(`Unsupported input mode: ${options2.mode}`);
836
843
  }
837
844
 
845
+ // src/core/pruner.ts
846
+ import { filter as filter4, map as map5 } from "@winglet/common-utils";
847
+
838
848
  // src/utils/math.ts
849
+ import { filter as filter3, map as map4 } from "@winglet/common-utils";
839
850
  function normalizeScores(items) {
840
851
  if (items.length === 0) return [];
841
- const safeScores = items.map(
852
+ const safeScores = map4(
853
+ items,
842
854
  (e) => Number.isFinite(e.score) && e.score > 0 ? e.score : 0
843
855
  );
844
- const positiveScores = safeScores.filter((s) => s > 0);
856
+ const positiveScores = filter3(safeScores, (s) => s > 0);
845
857
  if (positiveScores.length === 0) return safeScores;
846
858
  const sorted = [...positiveScores].sort((a, b) => a - b);
847
859
  if (positiveScores.length <= NORMALIZATION_MIN_SAMPLE_SIZE) {
848
860
  const min = sorted[0];
849
861
  const max = sorted[sorted.length - 1];
850
- if (max === min) return safeScores.map((s) => s > 0 ? 1 : 0);
851
- return safeScores.map(
862
+ if (max === min) return map4(safeScores, (s) => s > 0 ? 1 : 0);
863
+ return map4(
864
+ safeScores,
852
865
  (s) => s <= 0 ? 0 : Math.max(0, Math.min((s - min) / (max - min), 1))
853
866
  );
854
867
  }
855
868
  const median = sorted[Math.floor(sorted.length / 2)];
856
- const absoluteDiffs = positiveScores.map((v) => Math.abs(v - median));
869
+ const absoluteDiffs = map4(positiveScores, (v) => Math.abs(v - median));
857
870
  const mad = [...absoluteDiffs].sort((a, b) => a - b)[Math.floor(absoluteDiffs.length / 2)];
858
871
  const scale = mad === 0 ? median : mad * NORMALIZATION_MAD_COEFFICIENT;
859
- const logisticZ = safeScores.map((s) => {
872
+ const logisticZ = map4(safeScores, (s) => {
860
873
  if (s <= 0) return 0;
861
874
  if (scale === 0) return 1;
862
875
  const z = (s - median) / scale;
863
876
  return 1 / (1 + Math.exp(-NORMALIZATION_LOGISTIC_K * z));
864
877
  });
865
- const cdf = safeScores.map((s) => {
878
+ const cdf = map4(safeScores, (s) => {
866
879
  if (s <= 0) return 0;
867
880
  const rank = sorted.findIndex((v) => v >= s);
868
881
  return rank / sorted.length;
869
882
  });
870
- return logisticZ.map(
883
+ return map4(
884
+ logisticZ,
871
885
  (z, i) => z * (1 - NORMALIZATION_ALPHA) + cdf[i] * NORMALIZATION_ALPHA
872
886
  );
873
887
  }
@@ -919,7 +933,7 @@ var MinHeap = class {
919
933
  // src/core/pruner.ts
920
934
  function pruneTo(graph, frames, targetCount) {
921
935
  if (frames.length <= targetCount) {
922
- return new Set(frames.map((f) => f.id));
936
+ return new Set(map5(frames, (f) => f.id));
923
937
  }
924
938
  const prev = /* @__PURE__ */ new Map();
925
939
  const next = /* @__PURE__ */ new Map();
@@ -937,7 +951,7 @@ function pruneTo(graph, frames, targetCount) {
937
951
  tgtId: edge.targetId
938
952
  });
939
953
  }
940
- const surviving = new Set(frames.map((f) => f.id));
954
+ const surviving = new Set(map5(frames, (f) => f.id));
941
955
  const firstId = frames[0].id;
942
956
  const lastId = frames[frames.length - 1].id;
943
957
  while (surviving.size > targetCount && heap.size > 0) {
@@ -1030,7 +1044,7 @@ function pruneByThresholdWithCap(graph, frames, threshold, maxCount) {
1030
1044
  if (thresholdSurvivors.size <= maxCount) {
1031
1045
  return thresholdSurvivors;
1032
1046
  }
1033
- const survivingFrames = frames.filter((f) => thresholdSurvivors.has(f.id));
1047
+ const survivingFrames = filter4(frames, (f) => thresholdSurvivors.has(f.id));
1034
1048
  const idToOrigIdx = /* @__PURE__ */ new Map();
1035
1049
  for (let i = 0; i < frames.length; i++) {
1036
1050
  idToOrigIdx.set(frames[i].id, i);
@@ -1066,6 +1080,7 @@ function pruneByThresholdWithCap(graph, frames, threshold, maxCount) {
1066
1080
  // src/core/segmenter.ts
1067
1081
  import { randomUUID } from "crypto";
1068
1082
  import { join as join5 } from "path";
1083
+ import { filter as filter5, map as map6 } from "@winglet/common-utils";
1069
1084
 
1070
1085
  // src/utils/concurrency.ts
1071
1086
  function concurrencyLimit(limit) {
@@ -1329,7 +1344,7 @@ async function runSegmentedPipeline(options2, resolvedOptions) {
1329
1344
  logger.debug(`Segment plan: ${segments.length} segments`);
1330
1345
  const limit = concurrencyLimit(resolvedOptions.concurrency);
1331
1346
  const segmentProgresses = new Array(segments.length).fill(0);
1332
- const weights = segments.map((s) => s.duration / totalDuration);
1347
+ const weights = map6(segments, (s) => s.duration / totalDuration);
1333
1348
  const emitOverallProgress = (phase) => {
1334
1349
  if (!options2.onProgress) return;
1335
1350
  const overall = weights.reduce(
@@ -1340,7 +1355,8 @@ async function runSegmentedPipeline(options2, resolvedOptions) {
1340
1355
  };
1341
1356
  options2.onProgress?.("EXTRACTING", 0);
1342
1357
  const results = await Promise.all(
1343
- segments.map(
1358
+ map6(
1359
+ segments,
1344
1360
  (segment) => limit(async () => {
1345
1361
  const segWorkspace = await createSegmentWorkspace(
1346
1362
  mainWorkspace,
@@ -1372,7 +1388,7 @@ async function runSegmentedPipeline(options2, resolvedOptions) {
1372
1388
  resolvedOptions.threshold,
1373
1389
  resolvedOptions.count
1374
1390
  );
1375
- const prunedFrames = frames.filter((f) => survivingIds.has(f.id));
1391
+ const prunedFrames = filter5(frames, (f) => survivingIds.has(f.id));
1376
1392
  options2.onProgress?.("PRUNING", 100);
1377
1393
  options2.onProgress?.("FINALIZING", 0);
1378
1394
  const ctx = {
@@ -1482,7 +1498,7 @@ async function runPipeline(options2) {
1482
1498
  resolvedOptions.threshold,
1483
1499
  resolvedOptions.count
1484
1500
  );
1485
- const prunedFrames = ctx.frames.filter((f) => survivingIds.has(f.id));
1501
+ const prunedFrames = filter6(ctx.frames, (f) => survivingIds.has(f.id));
1486
1502
  ctx.emitProgress(100);
1487
1503
  ctx.status = "FINALIZING";
1488
1504
  let outputFiles = [];
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@lumy-pack/scene-sieve",
3
- "version": "0.0.11",
3
+ "version": "0.0.13",
4
4
  "description": "CLI tool for extracting key frames from video and GIF files",
5
5
  "keywords": [
6
6
  "cli",
@@ -56,6 +56,7 @@
56
56
  "dependencies": {
57
57
  "@ffprobe-installer/ffprobe": "^1.4.1",
58
58
  "@techstark/opencv-js": "4.12.0-release.1",
59
+ "@winglet/common-utils": "^0.11.2",
59
60
  "commander": "^12.1.0",
60
61
  "execa": "^9.5.0",
61
62
  "ffmpeg-static": "^5.2.0",