From 43b8f5218a7c06422659d0ac610085ac9ded235a Mon Sep 17 00:00:00 2001 From: 5tarry Date: Sun, 10 Dec 2023 22:44:30 +0900 Subject: [PATCH 1/2] =?UTF-8?q?feat=20:=20=EB=B9=84=EB=94=94=EC=98=A4=20?= =?UTF-8?q?=EC=9D=91=EB=8B=B5=20=EC=8B=9C=20userRating=20=EC=B6=94?= =?UTF-8?q?=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .vscode/settings.json | 2 +- server/src/user/user.service.ts | 2 +- server/src/video/video.controller.ts | 15 +++++++----- server/src/video/video.service.ts | 36 ++++++++++++++++++++-------- 4 files changed, 37 insertions(+), 18 deletions(-) diff --git a/.vscode/settings.json b/.vscode/settings.json index 0e7ac9a..1f8ad4d 100644 --- a/.vscode/settings.json +++ b/.vscode/settings.json @@ -1,5 +1,5 @@ { "editor.codeActionsOnSave": { - "source.fixAll.eslint": true + "source.fixAll.eslint": true }, } \ No newline at end of file diff --git a/server/src/user/user.service.ts b/server/src/user/user.service.ts index 7b0db08..1b5f5f0 100644 --- a/server/src/user/user.service.ts +++ b/server/src/user/user.service.ts @@ -209,7 +209,7 @@ export class UserService { _id: action.videoId, }).populate('uploaderId', '-_id -actions'); const video = videoData - ? await this.videoService.getVideoInfo(videoData.toObject()) + ? await this.videoService.getVideoInfo(videoData.toObject(), uuid) : { video: null, uploader: null }; return { ...video, ratedAt: action.updatedAt }; }), diff --git a/server/src/video/video.controller.ts b/server/src/video/video.controller.ts index cced770..4059f04 100644 --- a/server/src/video/video.controller.ts +++ b/server/src/video/video.controller.ts @@ -92,8 +92,11 @@ export class VideoController { */ @Get('top-rated') @ApiSuccessResponse(200, 'TOP 10 조회 성공', VideoListResponseDto) - getTopRatedVideo(@Query() query: TopVideoQueryDto) { - return this.videoService.getTopRatedVideo(query.category); + getTopRatedVideo( + @Query() query: TopVideoQueryDto, + @RequestUser() user: User, + ) { + return this.videoService.getTopRatedVideo(query.category, user.id); } /** @@ -101,8 +104,8 @@ export class VideoController { */ @Get('trend') @ApiSuccessResponse(200, '비디오 조회 성공', VideoListResponseDto) - getTrendVideo(@Query('limit') limit: number) { - return this.videoService.getTrendVideo(limit); + getTrendVideo(@Query('limit') limit: number, @RequestUser() user: User) { + return this.videoService.getTrendVideo(limit, user.id); } /** @@ -111,8 +114,8 @@ export class VideoController { @Get(':id') @ApiSuccessResponse(200, '비디오 조회 성공', VideoInfoDto) @ApiFailResponse('비디오를 찾을 수 없음', [VideoNotFoundException]) - getVideo(@Param('id') videoId: string) { - return this.videoService.getVideo(videoId); + getVideo(@Param('id') videoId: string, @RequestUser() user: User) { + return this.videoService.getVideo(videoId, user.id); } /** diff --git a/server/src/video/video.service.ts b/server/src/video/video.service.ts index 57eb3cb..444dd0d 100644 --- a/server/src/video/video.service.ts +++ b/server/src/video/video.service.ts @@ -98,14 +98,15 @@ export class VideoService { const SEED_MAX = 1_000_000; const viewSeed = seed ?? Math.floor(Math.random() * SEED_MAX); const videoInfos = await Promise.all( - videos.map((video) => this.getVideoInfo(video)), + videos.map((video) => this.getVideoInfo(video, userId)), ); return { videos: videoInfos, seed: viewSeed }; } - async getVideoInfo(video: any): Promise { + async getVideoInfo(video: any, userId: string): Promise { const { totalRating, raterCount, uploaderId, ...videoInfo } = video; const rating = raterCount ? (totalRating / raterCount).toFixed(1) : null; + const userRating = await this.getUserRating(userId, videoInfo._id); const manifest = `${process.env.MANIFEST_URL_PREFIX}/${videoInfo._id}_master.m3u8`; @@ -132,11 +133,26 @@ export class VideoService { }; return { - video: { ...videoInfo, manifest, rating, thumbnailImageUrl }, + video: { ...videoInfo, manifest, rating, userRating, thumbnailImageUrl }, uploader, }; } + async getUserRating(uuid: string, videoId: string) { + const userData = await this.UserModel.findOne( + { + uuid, + 'actions.videoId': videoId, + }, + { + _id: 0, + 'actions.$': 1, + }, + ); + const userRating = userData ? userData.actions.pop().rating : null; + return userRating; + } + async uploadVideo(videoDto: VideoDto, uuid: string, videoId: string) { if (!Types.ObjectId.isValid(videoId)) throw new BadRequestFormatException(); const checkDuplicate = await this.VideoModel.findOne({ _id: videoId }); @@ -191,7 +207,7 @@ export class VideoService { accessKey, secretKey, }; - console.log(data); + try { await axios.post(process.env.ENCODING_API_URL, data); } catch (error) { @@ -241,7 +257,7 @@ export class VideoService { }; } - async getTrendVideo(limit: number) { + async getTrendVideo(limit: number, userId: string) { const fields = Object.keys(this.VideoModel.schema.paths).reduce( (acc, field) => { acc[field] = 1; @@ -273,13 +289,13 @@ export class VideoService { }); const videos = await Promise.all( - trendVideos.map((video) => this.getVideoInfo(video)), + trendVideos.map((video) => this.getVideoInfo(video, userId)), ); return { videos }; } - async getTopRatedVideo(category: string) { + async getTopRatedVideo(category: string, userId: string) { const videoTotal = await this.VideoModel.aggregate([ { $match: { category } }, { @@ -328,12 +344,12 @@ export class VideoService { }); const videos = await Promise.all( - top10Videos.map((video) => this.getVideoInfo(video)), + top10Videos.map((video) => this.getVideoInfo(video, userId)), ); return { videos }; } - async getVideo(videoId: string) { + async getVideo(videoId: string, userId: string) { const video = await this.VideoModel.findOne( { _id: videoId }, {}, @@ -342,6 +358,6 @@ export class VideoService { if (!video) { throw new VideoNotFoundException(); } - return this.getVideoInfo(video); + return this.getVideoInfo(video, userId); } } From 9861a366a995f0f03241ff1b02fe662b97c289d4 Mon Sep 17 00:00:00 2001 From: 5tarry Date: Sun, 10 Dec 2023 23:04:40 +0900 Subject: [PATCH 2/2] =?UTF-8?q?feat=20:=20=EC=9D=91=EB=8B=B5=20dto=20?= =?UTF-8?q?=EC=88=98=EC=A0=95=20=EB=B0=8F=20=ED=8A=B9=EC=A0=95=20=EC=9C=A0?= =?UTF-8?q?=EC=A0=80=EA=B0=80=20=EC=97=85=EB=A1=9C=EB=93=9C=20=ED=95=9C=20?= =?UTF-8?q?=EB=B9=84=EB=94=94=EC=98=A4=20userRating=20=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- server/src/user/user.service.ts | 16 +++++++++++++--- server/src/video/dto/video-response.dto.ts | 6 ++++++ 2 files changed, 19 insertions(+), 3 deletions(-) diff --git a/server/src/user/user.service.ts b/server/src/user/user.service.ts index 1b5f5f0..85eb0ae 100644 --- a/server/src/user/user.service.ts +++ b/server/src/user/user.service.ts @@ -116,7 +116,7 @@ export class UserService { .sort({ _id: -1 }) .limit(limit); - const videos = await this.getVideoInfos(videoData, uploader); + const videos = await this.getVideoInfos(videoData, uploader, uuid); return { videos }; } @@ -140,7 +140,7 @@ export class UserService { return { uploader, uploaderId }; } - async getVideoInfos(videoData: Array, uploader: object) { + async getVideoInfos(videoData: Array, uploader: object, uuid: string) { const videos = await Promise.all( videoData.map(async (video) => { const { thumbnailExtension, raterCount, totalRating, ...videoInfo } = @@ -148,6 +148,10 @@ export class UserService { const rating = raterCount ? (totalRating / raterCount).toFixed(1) : null; + const userRating = await this.videoService.getUserRating( + uuid, + videoInfo._id, + ); const manifest = `${process.env.MANIFEST_URL_PREFIX}/${videoInfo._id}_master.m3u8`; const thumbnailImageUrl = await createPresignedUrl( process.env.THUMBNAIL_BUCKET, @@ -155,7 +159,13 @@ export class UserService { 'GET', ); return { - video: { ...videoInfo, manifest, rating, thumbnailImageUrl }, + video: { + ...videoInfo, + manifest, + rating, + userRating, + thumbnailImageUrl, + }, uploader, }; }), diff --git a/server/src/video/dto/video-response.dto.ts b/server/src/video/dto/video-response.dto.ts index e04cf4d..bc4a44d 100644 --- a/server/src/video/dto/video-response.dto.ts +++ b/server/src/video/dto/video-response.dto.ts @@ -19,6 +19,12 @@ export class VideoResponseDto { */ rating: string; + /** + * 유저가 준 점수 + * @example 5 + */ + userRating: number | null; + /** * 카테고리 * @example "챌린지"