Forráskód Böngészése

feat: add endpoints for latest and recommended videos with caching support

Dave 1 hónapja
szülő
commit
2aeb230694

+ 44 - 2
apps/box-app-api/src/feature/video/video.controller.ts

@@ -53,8 +53,7 @@ export class VideoController {
   @Get('search')
   @ApiOperation({
     summary: '基于 secondTags 搜索视频',
-    description:
-      '使用缓存中 secondTags 值过滤视频;支持多个标签,用逗号分隔,tag 为空则返回全部。',
+    description: '过滤视频;支持多个标签,用逗号分隔,tag 为空则返回全部。',
   })
   @ApiQuery({
     name: 'tags',
@@ -75,6 +74,49 @@ export class VideoController {
   }
 
   /**
+   * GET /api/v1/video/latest
+   *
+   * Returns the latest cached video list populated by box-mgnt-api.
+   */
+  @Get('latest')
+  @ApiOperation({
+    summary: '最新视频列表',
+  })
+  @ApiResponse({
+    status: 200,
+    description: '最新视频',
+    type: VideoItemDto,
+    isArray: true,
+  })
+  async getLatestVideos(): Promise<{ total: number; list: VideoItemDto[] }> {
+    const list = await this.videoService.getLatestVideosFromCache();
+    return { total: list.length, list };
+  }
+
+  /**
+   * GET /api/v1/video/recommended
+   *
+   * Returns the recommended cache populated by box-mgnt-api.
+   */
+  @Get('recommended')
+  @ApiOperation({
+    summary: '推荐视频列表',
+  })
+  @ApiResponse({
+    status: 200,
+    description: '推荐视频',
+    type: VideoItemDto,
+    isArray: true,
+  })
+  async getRecommendedVideos(): Promise<{
+    total: number;
+    list: VideoItemDto[];
+  }> {
+    const list = await this.videoService.getRecommendedVideosFromCache();
+    return { total: list.length, list };
+  }
+
+  /**
    * POST /video/click
    *
    * Record video click event for analytics.

+ 39 - 0
apps/box-app-api/src/feature/video/video.service.ts

@@ -1115,6 +1115,45 @@ export class VideoService {
   }
 
   /**
+   * Read the cached latest video list built by box-mgnt-api.
+   */
+  async getLatestVideosFromCache(): Promise<VideoItemDto[]> {
+    const key = tsCacheKeys.video.latest();
+    return this.readCachedVideoList(key, 'latest videos');
+  }
+
+  async getRecommendedVideosFromCache(): Promise<VideoItemDto[]> {
+    const key = tsCacheKeys.video.recommended();
+    return this.readCachedVideoList(key, 'recommended videos');
+  }
+
+  private async readCachedVideoList(
+    key: string,
+    label: string,
+  ): Promise<VideoItemDto[]> {
+    try {
+      const raw = await this.redis.get(key);
+      if (!raw) {
+        return [];
+      }
+
+      const parsed = JSON.parse(raw);
+      if (Array.isArray(parsed)) {
+        return parsed;
+      }
+
+      this.logger.warn(`${label} cache (${key}) returned non-array payload`);
+    } catch (err) {
+      this.logger.error(
+        `Failed to read ${label} cache (${key})`,
+        err instanceof Error ? err.stack : String(err),
+      );
+    }
+
+    return [];
+  }
+
+  /**
    * Search the cached video list by secondTags, with fallback for videos that have no secondTags.
    */
   async searchVideosBySecondTags(tags?: string): Promise<VideoItemDto[]> {