@mahidsec/nest 1.0.3 → 1.0.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/dist/server.js CHANGED
@@ -141,11 +141,14 @@ var countVideoFiles = async (dirPath) => {
141
141
  const videoExts = [".mp4", ".mkv", ".avi", ".mov", ".webm", ".m4v"];
142
142
  try {
143
143
  const entries = await readdir(dirPath, { withFileTypes: true });
144
+ const promises = [];
144
145
  for (const entry of entries) {
145
146
  if (entry.name.startsWith(".")) continue;
146
- if (entry.isDirectory()) count += await countVideoFiles(path.join(dirPath, entry.name));
147
+ if (entry.isDirectory()) promises.push(countVideoFiles(path.join(dirPath, entry.name)));
147
148
  else if (videoExts.includes(path.extname(entry.name).toLowerCase())) count++;
148
149
  }
150
+ const results = await Promise.all(promises);
151
+ count += results.reduce((a, b) => a + b, 0);
149
152
  } catch {
150
153
  }
151
154
  return count;
@@ -153,16 +156,47 @@ var countVideoFiles = async (dirPath) => {
153
156
  var videoCountCache = /* @__PURE__ */ new Map();
154
157
  var CACHE_TTL = 3e4;
155
158
  var CACHE_MAX = 200;
156
- var getCachedVideoCount = async (dirPath) => {
159
+ var triggerVideoCountUpdate = async (course) => {
160
+ const dirPath = course.localPath;
161
+ let cached = videoCountCache.get(dirPath);
162
+ if (!cached) {
163
+ cached = { count: course.totalVideos || 0, ts: 0, updating: true };
164
+ if (videoCountCache.size >= CACHE_MAX) {
165
+ const oldest = videoCountCache.keys().next().value;
166
+ if (oldest) videoCountCache.delete(oldest);
167
+ }
168
+ videoCountCache.set(dirPath, cached);
169
+ } else {
170
+ cached.updating = true;
171
+ }
172
+ try {
173
+ const count = await countVideoFiles(dirPath);
174
+ videoCountCache.set(dirPath, { count, ts: Date.now(), updating: false });
175
+ if (course.totalVideos !== count) {
176
+ const allCourses = await getCourses();
177
+ const target = allCourses.find((c) => c.id === course.id);
178
+ if (target && target.totalVideos !== count) {
179
+ target.totalVideos = count;
180
+ await saveCourses(allCourses);
181
+ }
182
+ }
183
+ } catch (err) {
184
+ if (cached) cached.updating = false;
185
+ }
186
+ };
187
+ var getCachedVideoCount = (course) => {
188
+ const dirPath = course.localPath;
157
189
  const cached = videoCountCache.get(dirPath);
158
- if (cached && Date.now() - cached.ts < CACHE_TTL) return cached.count;
159
- const count = await countVideoFiles(dirPath);
160
- if (videoCountCache.size >= CACHE_MAX) {
161
- const oldest = videoCountCache.keys().next().value;
162
- if (oldest) videoCountCache.delete(oldest);
190
+ if (cached) {
191
+ if (Date.now() - cached.ts > CACHE_TTL && !cached.updating) {
192
+ triggerVideoCountUpdate(course).catch(() => {
193
+ });
194
+ }
195
+ return cached.count;
163
196
  }
164
- videoCountCache.set(dirPath, { count, ts: Date.now() });
165
- return count;
197
+ triggerVideoCountUpdate(course).catch(() => {
198
+ });
199
+ return course.totalVideos || 0;
166
200
  };
167
201
  var invalidateVideoCount = (dirPath) => {
168
202
  videoCountCache.delete(dirPath);
@@ -278,10 +312,10 @@ app.post("/api/tunnel/stop", (_req, res) => {
278
312
  app.get("/api/courses", async (_req, res) => {
279
313
  try {
280
314
  const courses = await getCourses();
281
- const enriched = await Promise.all(courses.map(async (c) => ({
315
+ const enriched = courses.map((c) => ({
282
316
  ...c,
283
- totalVideos: await getCachedVideoCount(c.localPath)
284
- })));
317
+ totalVideos: getCachedVideoCount(c)
318
+ }));
285
319
  res.json(enriched);
286
320
  } catch {
287
321
  res.status(500).json({ error: "Failed to load courses" });
@@ -323,6 +357,14 @@ app.delete("/api/courses/:id", async (req, res) => {
323
357
  await saveCourses(courses.filter((c) => c.id !== req.params.id));
324
358
  res.json({ success: true });
325
359
  });
360
+ app.get("/api/courses/progress", async (_req, res) => {
361
+ const all = await getCourseProgressData();
362
+ const result = {};
363
+ for (const [courseId, files] of Object.entries(all)) {
364
+ result[courseId] = Object.keys(files).length;
365
+ }
366
+ res.json(result);
367
+ });
326
368
  app.get("/api/courses/:id/browse", async (req, res) => {
327
369
  const courses = await getCourses();
328
370
  const course = courses.find((c) => c.id === req.params.id);