Skip to content

Commit

Permalink
feat: Improve get channel api
Browse files Browse the repository at this point in the history
  • Loading branch information
dokdo2013 committed Jan 2, 2024
1 parent 4d98440 commit b6a24af
Show file tree
Hide file tree
Showing 10 changed files with 144 additions and 168 deletions.
4 changes: 1 addition & 3 deletions .github/workflows/api-cicd.yml
Original file line number Diff line number Diff line change
@@ -1,6 +1,4 @@
# Example Workflow (Just Dockerfile Build)

name: CI/CD to Haenu Cluster
name: CI/CD to Haenu Cluster (API)

on:
push:
Expand Down
71 changes: 33 additions & 38 deletions api/src/channels/channels.controller.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import {
Controller,
Get,
NotFoundException,
NotImplementedException,
ParseArrayPipe,
Patch,
Expand All @@ -16,60 +17,36 @@ import {
ApiQuery,
ApiTags,
} from '@nestjs/swagger';
import {
NotImplementedExceptionImplementSoonResponse,
NotImplementedExceptionWontImplementResponse,
} from 'src/common/common-response.dto';
import {
getChannelDto,
twitchGetChannelResponseDto,
} from './dto/get-channel.dto';
import { NotImplementedExceptionImplementSoonResponse } from 'src/common/common-response.dto';
import { TwitchGetChannelResponseDto } from './dto/get-channel.dto';
import { ChzzkService } from 'src/chzzk/chzzk.service';
import { GetChannelByIdParamsDto } from 'src/chzzk/dto/params.dto';
import { ChzzkChannel } from 'src/chzzk/dto/response.interface';

@Controller('helix/channels')
@ApiTags('Channels')
export class ChannelsController {
constructor(private readonly channelsService: ChannelsService) {}
constructor(
private readonly channelsService: ChannelsService,
private readonly chzzkService: ChzzkService,
) {}

@Post('commercial')
@ApiExcludeEndpoint()
@ApiOperation({
summary: 'Start Commercial',
})
@ApiNotImplementedResponse({
description: 'WONT_IMPLEMENT',
type: NotImplementedExceptionWontImplementResponse,
})
async commercial() {
throw new NotImplementedException('WONT_IMPLEMENT');
// return await this.channelsService.commercial();
}

@Get('ads')
@ApiExcludeEndpoint()
@ApiOperation({
summary: 'Get Ad Schedule',
})
@ApiNotImplementedResponse({
description: 'WONT_IMPLEMENT',
type: NotImplementedExceptionWontImplementResponse,
})
async ads() {
throw new NotImplementedException('WONT_IMPLEMENT');
// return await this.channelsService.ads();
}

@Post('ads/schedule/snooze')
@ApiExcludeEndpoint()
@ApiOperation({
summary: 'Snooze Next Ad',
})
@ApiNotImplementedResponse({
description: 'WONT_IMPLEMENT',
type: NotImplementedExceptionWontImplementResponse,
})
async adsScheduleSnooze() {
throw new NotImplementedException('WONT_IMPLEMENT');
// return await this.channelsService.adsScheduleSnooze();
}

@Get('')
Expand All @@ -78,7 +55,7 @@ export class ChannelsController {
})
@ApiOkResponse({
description: 'OK',
type: twitchGetChannelResponseDto,
type: TwitchGetChannelResponseDto,
})
@ApiQuery({
name: 'broadcaster_id',
Expand All @@ -87,22 +64,40 @@ export class ChannelsController {
type: [String],
description: '채널 ID 여러 개를 입력합니다',
})
async getChannelInformation(
async getChannel(
@Query('broadcaster_id', ParseArrayPipe) broadcaster_ids: string[],
) {
const chzzkResults = (await Promise.all(
broadcaster_ids.map(async (id) => {
return (await this.channelsService.getChannel(id)).content;
const params: GetChannelByIdParamsDto = {
channelId: id,
};
return await this.chzzkService.getChannelById(params);
}),
)) as getChannelDto[];
)) as ChzzkChannel[];

// chzzkResults가 null인 경우에 대한 처리
const chzzkResultsFiltered = chzzkResults.filter((chzzkResult) => {
return chzzkResult !== null;
});

console.log(chzzkResultsFiltered);

if (chzzkResultsFiltered.length === 0) {
// chzzkResultsFiltered가 빈 배열인 경우
// 즉, chzzkResults가 모두 null인 경우
// 채널을 찾을 수 없다는 에러를 던짐

throw new NotFoundException('채널을 찾을 수 없습니다.');
}

const twitchResults = chzzkResults.map((chzzkResult) => {
return this.channelsService.getChannelConverter(chzzkResult);
});

const response = {
data: twitchResults,
} as twitchGetChannelResponseDto;
} as TwitchGetChannelResponseDto;

return response;
}
Expand Down
2 changes: 2 additions & 0 deletions api/src/channels/channels.module.ts
Original file line number Diff line number Diff line change
@@ -1,8 +1,10 @@
import { Module } from '@nestjs/common';
import { ChannelsController } from './channels.controller';
import { ChannelsService } from './channels.service';
import { ChzzkModule } from 'src/chzzk/chzzk.module';

@Module({
imports: [ChzzkModule],
controllers: [ChannelsController],
providers: [ChannelsService],
})
Expand Down
37 changes: 6 additions & 31 deletions api/src/channels/channels.service.ts
Original file line number Diff line number Diff line change
@@ -1,38 +1,13 @@
import { Injectable, NotFoundException } from '@nestjs/common';
import axios from 'axios';
import {
getChannelDto,
getChannelResponseDto,
twitchGetChannelDto,
} from './dto/get-channel.dto';
import { Injectable } from '@nestjs/common';
import { TwitchGetChannelDto } from './dto/get-channel.dto';
import { ChzzkChannel } from 'src/chzzk/dto/response.interface';

@Injectable()
export class ChannelsService {
async getChannel(
channelId: string,
throwError = false,
): Promise<getChannelResponseDto> {
const apiUrl = `https://api.chzzk.naver.com/service/v1/channels/${channelId}`;
constructor() {}

const response = await axios
.get(apiUrl)
.then((response) => {
return response.data as getChannelResponseDto;
})
.catch((error) => {
console.log(error);
if (throwError) {
throw new NotFoundException('채널을 찾을 수 없습니다.');
}

return {} as getChannelResponseDto;
});

return response;
}

getChannelConverter(channelResponse: getChannelDto): twitchGetChannelDto {
const twitchChannelInfo: twitchGetChannelDto = {
getChannelConverter(channelResponse: ChzzkChannel): TwitchGetChannelDto {
const twitchChannelInfo: TwitchGetChannelDto = {
broadcaster_id: channelResponse?.channelId,
broadcaster_login: channelResponse?.channelName,
broadcaster_name: channelResponse?.channelName,
Expand Down
101 changes: 5 additions & 96 deletions api/src/channels/dto/get-channel.dto.ts
Original file line number Diff line number Diff line change
@@ -1,97 +1,6 @@
import { ApiProperty } from '@nestjs/swagger';

export class getChannelDto {
@ApiProperty({
example: 'a1b2c3d4e5f6g7h8i9j0',
description: '채널 ID',
nullable: false,
})
channelId: string;

@ApiProperty({
example: '채널 이름',
description: '채널 이름',
nullable: false,
})
channelName: string;

@ApiProperty({
example:
'https://nng-phinf.pstatic.net/MjAyMzEyMTVfMjYy/MDAxNzAyNjIwMzQ5NjE1.tVl6ew-9iBd3Z3fEG8iRmzCFbUpf3qKj_o1BSXWB73og.kqiVM7bjKl40zr9m52PqMdO6cZB6mIXYA7PRIM388mcg.JPEG/Symbol.jpg?type=f120_120_na',
description: '채널 프로필 이미지 URL',
nullable: true,
})
channelImageUrl: string;

@ApiProperty({
example: false,
description: '채널 인증마크 여부',
nullable: false,
})
verifiedMark: boolean;

@ApiProperty({
example: 'STREAMING',
description: '채널 타입',
nullable: false,
})
channelType: string;

@ApiProperty({
example: '채널 설명',
description: '채널 설명',
nullable: false,
})
channelDescription: string;

@ApiProperty({
example: 0,
description: '채널 팔로워 수',
nullable: false,
})
followerCount: number;

@ApiProperty({
example: true,
description: 'LIVE 방송 실행가능 여부',
nullable: false,
})
openLive: boolean;
}

export class getChannelResponseDto {
@ApiProperty({
description: '응답 코드',
})
code: number;

@ApiProperty({
description: '응답 메시지',
nullable: true,
})
message: string;

@ApiProperty({
description: '채널 정보',
})
content: getChannelDto;
}

// {
// "broadcaster_id": "141981764",
// "broadcaster_login": "twitchdev",
// "broadcaster_name": "TwitchDev",
// "broadcaster_language": "en",
// "game_id": "509670",
// "game_name": "Science & Technology",
// "title": "TwitchDev Monthly Update // May 6, 2021",
// "delay": 0,
// "tags": ["DevsInTheKnow"],
// "content_classification_labels": ["Gambling", "DrugsIntoxication", "MatureGame"],
// "is_branded_content": false
// }

export class twitchGetChannelDto {
export class TwitchGetChannelDto {
@ApiProperty({
example: '141981764',
description: '채널 ID',
Expand All @@ -115,7 +24,7 @@ export class twitchGetChannelDto {

@ApiProperty({
example: 'en',
description: '채널 언어',
description: '채널 언어 (ko로 고정)',
nullable: false,
})
broadcaster_language: string;
Expand Down Expand Up @@ -170,10 +79,10 @@ export class twitchGetChannelDto {
is_branded_content: boolean;
}

export class twitchGetChannelResponseDto {
export class TwitchGetChannelResponseDto {
@ApiProperty({
description: '채널 정보',
type: [twitchGetChannelDto],
type: [TwitchGetChannelDto],
})
data: twitchGetChannelDto[];
data: TwitchGetChannelDto[];
}
8 changes: 8 additions & 0 deletions api/src/chzzk/chzzk.module.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
import { Module } from '@nestjs/common';
import { ChzzkService } from './chzzk.service';

@Module({
providers: [ChzzkService],
exports: [ChzzkService],
})
export class ChzzkModule {}
49 changes: 49 additions & 0 deletions api/src/chzzk/chzzk.service.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
import { Injectable, NotFoundException } from '@nestjs/common';
import axios from 'axios';
import { CommonOptionsDto } from './dto/common.dto';
import { GetChannelByIdParamsDto } from './dto/params.dto';
import {
ChzzkChannel,
ChzzkGetChannelResponse,
} from './dto/response.interface';

@Injectable()
export class ChzzkService {
constructor() {}

/**
* Get Chzzk Channel Information by Channel ID
* @param params
* @param options
* @returns ChzzkChannel | null
*/
async getChannelById(
params: GetChannelByIdParamsDto,
options?: CommonOptionsDto,
): Promise<ChzzkChannel> {
const apiUrl = `https://api.chzzk.naver.com/service/v1/channels/${params.channelId}`;

const response = await axios
.get(apiUrl)
.then((response) => {
if (response.data.content.channelId === null) {
throw new NotFoundException('채널을 찾을 수 없습니다.');
}

return response.data as ChzzkGetChannelResponse;
})
.catch((error) => {
if (options?.throwException) {
throw new NotFoundException('채널을 찾을 수 없습니다.');
}

console.log(error);

return {
content: null,
} as ChzzkGetChannelResponse;
});

return response.content;
}
}
9 changes: 9 additions & 0 deletions api/src/chzzk/dto/common.dto.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
/**
* Common options for all requests
*/
export class CommonOptionsDto {
/**
* Throw exception when error occurs
*/
throwException: boolean = false;
}
6 changes: 6 additions & 0 deletions api/src/chzzk/dto/params.dto.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
export class GetChannelByIdParamsDto {
/**
* Channel ID
*/
channelId: string;
}
Loading

0 comments on commit b6a24af

Please sign in to comment.