返回 AiToEarn
youtube.controller.ts
根目录 / project / aitoearn-electron / server / src / modules / plat / youtube / youtube.controller.ts
1 /*
2 * @Author: nevin
3 * @Date: 2025-02-15 20:59:55
4 * @LastEditTime: 2025-04-27 18:00:18
5 * @LastEditors: nevin
6 * @Description: signIn SignIn 签到
7 */
8 import {
9 Body,
10 Controller,
11 Get,
12 Param,
13 Post,
14 Query,
15 UploadedFile,
16 UseInterceptors,
17 BadRequestException,
18 Res
19 } from '@nestjs/common';
20 import { ApiOperation, ApiTags } from '@nestjs/swagger';
21 import {
22 AccessBackDto,
23 ArchiveAddByUtokenBodyDto,
24 ArchiveAddByUtokenQueryDto,
25 } from './dto/youtube.dto';
26 import { YoutubeService } from './youtube.service';
27 import { GoogleService } from '../google/google.service';
28 import { GetToken, Public } from 'src/auth/auth.guard';
29 import { FileInterceptor } from '@nestjs/platform-express';
30 import { TokenInfo } from 'src/auth/interfaces/auth.interfaces';
31 import { YouTubeAuthService } from './youtube.auth.service';
32 import { Response } from 'express';
33
34 @ApiTags('plat/youtube - Youtube平台')
35 @Controller('plat/youtube')
36 export class YoutubeController {
37 constructor(
38 private readonly youtubeService: YoutubeService,
39 private readonly youtubeAuthService: YouTubeAuthService,
40 ) {}
41
42 @ApiOperation({ summary: '测试' })
43 @Public()
44 @Get('test')
45 async getTest() {
46 const res = "success";
47 return res;
48 }
49
50 @ApiOperation({ summary: '获取YouTube授权URL' })
51 @Get('auth/url')
52 async getAuthUrl(
53 @GetToken() systemToken: TokenInfo,
54 @Query('mail') mail: string) {
55 if (!mail) {
56 throw new BadRequestException('邮箱参数不能为空');
57 }
58 // async getAuthUrl(@GetToken() token: TokenInfo) {
59 // // mail = token.id
60 // // if (!mail) {
61 // // throw new BadRequestException('邮箱参数不能为空');
62 // // }
63
64 return this.youtubeAuthService.getAuthorizationUrl(mail, systemToken.id);
65 }
66
67 @ApiOperation({ summary: '处理YouTube授权回调' })
68 @Public()
69 @Get('auth/callback')
70 async handleAuthCallback(
71 // @GetToken() systemToken: TokenInfo,
72 @Query('code') code: string,
73 @Query('state') state: string,
74 // @Query('userId') userId: string,
75 @Res() res: Response
76 ) {
77
78 if (!code || !state) {
79 throw new BadRequestException('授权参数不完整');
80 }
81 // 解析state参数以获取token
82 let stateData;
83 try {
84 stateData = JSON.parse(decodeURIComponent(state));
85 } catch (error) {
86 throw new BadRequestException('无效的state参数');
87 }
88
89 const { originalState, userId, email } = stateData;
90
91 // 现在您可以使用token变量
92 console.log('Retrieved userId and originalState:', userId, originalState, email);
93
94 try {
95 const results = await this.youtubeAuthService.handleAuthorizationCode(code, originalState, userId);
96 // 重定向到前端页面,带上token
97 // return res.redirect(`/auth/success?token=${token}`);
98 // return results
99 const render_msg = {
100 message: "授权成功! 这里是添加账号成功后的前端页面," ,
101 datas: results
102 };
103
104 return res.render('google/index', render_msg);
105
106 } catch (error) {
107 console.error('授权失败:', error);
108 // return res.redirect('/auth/error?message=授权失败');
109 return false
110 }
111 }
112
113 @ApiOperation({ summary: '检查是否已授权YouTube' })
114 @Get('auth/check')
115 async checkAuth(
116 @GetToken() systemToken: TokenInfo,
117 @Query('accountId') accountId: string,
118 ) {
119 // return {
120 // authorized: await this.youtubeAuthService.isAuthorized(systemToken.id)
121 // };
122 return await this.youtubeAuthService.isAuthorized(accountId)
123
124 }
125
126 @ApiOperation({ summary: '撤销YouTube授权' })
127 @Post('auth/revoke')
128 async revokeAuth(
129 @GetToken() token: TokenInfo,
130 @Body('accountId') accountId: string,
131 ) {
132 const result = await this.youtubeAuthService.revokeAuthorization(accountId);
133 return result
134 }
135
136
137 @ApiOperation({ summary: '获取频道列表' })
138 @Get('channels/list')
139 async getChannelsList(
140 @GetToken() token: TokenInfo,
141 @Query('accountId') accountId: string,
142 @Query('handle') handle?: string,
143 @Query('userName') userName?: string,
144 @Query('id') id?: string,
145 @Query('mine') mine?: boolean
146 ) {
147 // 校验确保只有一个参数传递
148 const params = [handle, userName, id, mine];
149 const nonEmptyParams = params.filter(param => param !== undefined && param !== null && param !== '');
150
151 if (nonEmptyParams.length > 1) {
152 throw new BadRequestException('只能选择一个参数: handle, userName, id 或 mine');
153 }
154 const accessToken = await this.youtubeAuthService.getUserAccessToken(accountId);
155
156 return this.youtubeService.getChannelsList(accessToken, handle, userName, id, mine);
157 }
158
159 @ApiOperation({ summary: '更新频道' })
160 @Post('channels/update')
161 async channelsUpdate(
162 @GetToken() token: TokenInfo,
163 @Body('accountId') accountId: string,
164 @Body('id') id: string,
165 @Body('brandingSettings') brandingSettings?: Record<string, any>,
166 @Body('status') status?: Record<string, any>,
167 ) {
168 const accessToken = await this.youtubeAuthService.getUserAccessToken(accountId);
169 return this.youtubeService.updateChannels(accessToken, id, brandingSettings, status);
170 }
171
172 @ApiOperation({ summary: '获取频道板块列表' })
173 @Get('channels/sections/list')
174 async getChannelSectionsList(
175 @GetToken() token: TokenInfo,
176 @Query('accountId') accountId: string,
177 @Query('channelId') channelId?: string,
178 @Query('id') id?: string,
179 @Query('maxResults') maxResults?: string,
180 @Query('mine') mine?: boolean,
181 @Query('pageToken') pageToken?: string,
182 ) {
183 // 校验确保只有一个参数传递
184 const params = [channelId, id, mine];
185 const nonEmptyParams = params.filter(param => param !== undefined && param !== null && param !== '');
186
187 if (nonEmptyParams.length > 1) {
188 throw new BadRequestException('只能选择一个参数: channelId, id, mine');
189 }
190 const accessToken = await this.youtubeAuthService.getUserAccessToken(accountId);
191 return this.youtubeService.getChannelSectionsList(accessToken, channelId, id, mine, maxResults, pageToken);
192 }
193
194 @ApiOperation({ summary: '创建频道板块' })
195 @Post('channels/sections/insert')
196 async channelsSectionsInsert(
197 @GetToken() token: TokenInfo,
198 @Body('accountId') accountId: string,
199 @Body('snippet') snippet?: Record<string, any>,
200 @Body('contentDetails') contentDetails?: Record<string, any>,
201 ) {
202 const accessToken = await this.youtubeAuthService.getUserAccessToken(accountId);
203 return this.youtubeService.insertChannelSection(accessToken, snippet, contentDetails);
204 }
205
206 @ApiOperation({ summary: '更新频道版块' })
207 @Post('channels/sections/update')
208 async channelsSectionsUpdate(
209 @GetToken() token: TokenInfo,
210 @Body('accountId') accountId,
211 @Body('snippet') snippet?: Record<string, any>,
212 @Body('contentDetails') contentDetails?: Record<string, any>,
213 ) {
214 const accessToken = await this.youtubeAuthService.getUserAccessToken(accountId);
215 return this.youtubeService.updateChannelSection(accessToken, snippet, contentDetails);
216 }
217
218 @ApiOperation({ summary: '删除频道版块' })
219 @Post('channels/sections/delete')
220 async channelsSectionsDelete(
221 @GetToken() token: TokenInfo,
222 @Body('accountId') accountId: string,
223 @Body('id') channelSectionId: string,
224 ) {
225 const accessToken = await this.youtubeAuthService.getUserAccessToken(accountId);
226 return this.youtubeService.deleteChannelsSections(accessToken, channelSectionId);
227 }
228
229 @ApiOperation({ summary: '获取评论列表' })
230 @Get('comments/list')
231 async getCommentsList(
232 @GetToken() token: TokenInfo,
233 @Query('accountId') accountId: string,
234 @Query('parentId') parentId: string,
235 @Query('id') id: string,
236 @Query('maxResults') maxResults?: string,
237 @Query('pageToken') pageToken?: string,
238 ) {
239 // 校验确保只有一个参数传递
240 const params = [parentId, id];
241 const nonEmptyParams = params.filter(param => param !== undefined && param !== null && param !== '');
242
243 if (nonEmptyParams.length > 1) {
244 throw new BadRequestException('只能选择一个参数: channelId, id, mine');
245 }
246 const accessToken = await this.youtubeAuthService.getUserAccessToken(accountId);
247 return this.youtubeService.getCommentsList(accessToken, parentId, id, maxResults, pageToken);
248 }
249
250 @ApiOperation({ summary: '创建对现有评论的回复' })
251 @Post('comments/insert')
252 async commentsInsert(
253 @GetToken() token: TokenInfo,
254 @Body('accountId') accountId: string,
255 @Body('snippet') snippet: Record<string, any>,
256 ) {
257 const accessToken = await this.youtubeAuthService.getUserAccessToken(accountId);
258 return this.youtubeService.insertComment(accessToken, snippet);
259 }
260
261 @ApiOperation({ summary: '修改评论' })
262 @Post('comments/update')
263 async commentsUpdate(
264 @GetToken() token: TokenInfo,
265 @Body('accountId') accountId: string,
266 @Body('snippet') snippet: Record<string, any>,
267 ) {
268 const accessToken = await this.youtubeAuthService.getUserAccessToken(accountId);
269 return this.youtubeService.updateComments(accessToken, snippet);
270 }
271
272 @ApiOperation({ summary: '设置一条或多条评论的审核状态' })
273 @Post('comments/setModerationStatus')
274 async commentsSetModerationStatus(
275 @GetToken() token: TokenInfo,
276 @Body('accountId') accountId: string,
277 @Body('id') id: string,
278 @Body('moderationStatus') moderationStatus: string,
279 @Body('banAuthor') banAuthor?: boolean
280 ) {
281 const accessToken = await this.youtubeAuthService.getUserAccessToken(accountId);
282 return this.youtubeService.setModerationStatusComments(accessToken, id, moderationStatus, banAuthor);
283 }
284
285 @ApiOperation({ summary: '删除评论' })
286 @Post('comments/delete')
287 async commentsDelete(
288 @GetToken() token: TokenInfo,
289 @Body('accountId') accountId: string,
290 @Body('id') id: string,
291 ) {
292 const accessToken = await this.youtubeAuthService.getUserAccessToken(accountId);
293 return this.youtubeService.deleteComments(accessToken, id);
294 }
295
296 @ApiOperation({ summary: '获取评论会话列表' })
297 @Get('commentThreads/list')
298 async getCommentThreadsList(
299 @GetToken() token: TokenInfo,
300 @Query('accountId') accountId: string,
301 @Query('allThreadsRelatedToChannelId') allThreadsRelatedToChannelId: string,
302 @Query('id') id: string,
303 @Query('videoId') videoId: string,
304 @Query('order') order?: string,
305 @Query('searchTerms') searchTerms?: string,
306 @Query('maxResults') maxResults?: string,
307 @Query('pageToken') pageToken?: string,
308 ) {
309 // 校验确保只有一个参数传递
310 const params = [allThreadsRelatedToChannelId, id, videoId];
311 const nonEmptyParams = params.filter(param => param !== undefined && param !== null && param !== '');
312
313 if (nonEmptyParams.length > 1) {
314 throw new BadRequestException('只能选择一个参数: allThreadsRelatedToChannelId, id, videoId');
315 }
316 const accessToken = await this.youtubeAuthService.getUserAccessToken(accountId);
317 return this.youtubeService.getCommentThreadsList(accessToken, allThreadsRelatedToChannelId, id, videoId, maxResults, pageToken, order, searchTerms);
318 }
319
320 @ApiOperation({ summary: '创建顶级评论' })
321 @Post('commentThreads/insert')
322 async commentThreadsInsert(
323 @GetToken() token: TokenInfo,
324 @Body('accountId') accountId: string,
325 @Body('snippet') snippet: Record<string, any>,
326 ) {
327 const accessToken = await this.youtubeAuthService.getUserAccessToken(accountId);
328 return this.youtubeService.insertCommentThreads(accessToken, snippet);
329 }
330
331 @ApiOperation({ summary: '获取视频类别列表' })
332 @Get('video/categories/list')
333 async getVideoCategoriesList(
334 @GetToken() token: TokenInfo,
335 @Query('accountId') accountId: string,
336 @Query('regionCode') regionCode?: string,
337 @Query('id') id?: string
338 ) {
339 // 校验确保只有一个参数传递
340 const params = [regionCode, id];
341 const nonEmptyParams = params.filter(param => param !== undefined && param !== null && param !== '');
342
343 if (nonEmptyParams.length > 1) {
344 throw new BadRequestException('只能选择一个参数: regionCode, id');
345 }
346 const accessToken = await this.youtubeAuthService.getUserAccessToken(accountId);
347 return this.youtubeService.getVideoCategoriesList(accessToken, id, regionCode);
348 }
349
350 @ApiOperation({ summary: '获取视频列表' })
351 @Get('videos/list')
352 async getVideosList(
353 @GetToken() token: TokenInfo,
354 @Query('accountId') accountId: string,
355 @Query('id') id?: string,
356 @Query('myRating') myRating?: string,
357 @Query('maxResults') maxResults?: string,
358 @Query('pageToken') pageToken?: string,
359 ) {
360 // 校验确保只有一个参数传递
361 const params = [id, myRating];
362 const nonEmptyParams = params.filter(param => param !== undefined && param !== null && param !== '');
363
364 if (nonEmptyParams.length > 1) {
365 throw new BadRequestException('只能选择一个参数: id, myRating');
366 }
367 const accessToken = await this.youtubeAuthService.getUserAccessToken(accountId);
368 return this.youtubeService.getVideosList(accessToken, id, myRating, maxResults, pageToken);
369 }
370
371 @ApiOperation({ summary: '视频上传' })
372 @UseInterceptors(FileInterceptor('file'))
373 @Post('videos/upload')
374 async videoUpload(
375 @GetToken() token: TokenInfo,
376 @Body('accountId') accountId: string,
377 @UploadedFile() file: Express.Multer.File,
378 @Body('title') title: string,
379 @Body('description') description: string,
380 @Body('keywords') keywords?: string,
381 @Body('categoryId') categoryId?: string,
382 @Body('privacyStatus') privacyStatus?: string,
383 @Body('publishAt') publishAt?: Date
384 ) {
385 const accessToken = await this.youtubeAuthService.getUserAccessToken(accountId);
386 return this.youtubeService.uploadVideo(token.id, accountId, accessToken, file, title, description, keywords, categoryId, privacyStatus, publishAt);
387 }
388
389 @ApiOperation({ summary: '视频删除' })
390 @Post('videos/delete')
391 async videoDelete(
392 @GetToken() token: TokenInfo,
393 @Body('id') videoId: string,
394 @Body('accountId') accountId: string,
395 ) {
396 const accessToken = await this.youtubeAuthService.getUserAccessToken(accountId);
397 return this.youtubeService.deleteVideo(accessToken, videoId);
398 }
399
400 @ApiOperation({ summary: '更新视频' })
401 @Post('videos/update')
402 async videoUpdate(
403 @GetToken() token: TokenInfo,
404 @Body('accountId') accountId: string,
405 @Body('id') videoId: string,
406 @Body('snippet') snippet?: Record<string, any>,
407 @Body('status') status?: Record<string, any>,
408 @Body('recordingDetails') recordingDetails?: Record<string, any>,
409 ) {
410 const accessToken = await this.youtubeAuthService.getUserAccessToken(accountId);
411 return this.youtubeService.updateVideo(accessToken, videoId, snippet, status, recordingDetails);
412 }
413
414 @ApiOperation({ summary: '创建播放列表' })
415 @Post('playlist/insert')
416 async playlistInsert(
417 @GetToken() token: TokenInfo,
418 @Body('accountId') accountId: string,
419 @Body('snippet') snippet?: Record<string, any>,
420 @Body('status') status?: Record<string, any>,
421 ) {
422 const accessToken = await this.youtubeAuthService.getUserAccessToken(accountId);
423 return this.youtubeService.insertPlayList(accessToken, snippet, status);
424 }
425
426 @ApiOperation({ summary: '获取播放列表' })
427 @Get('playlist/list')
428 async getPlayList(
429 @GetToken() token: TokenInfo,
430 @Query('accountId') accountId: string,
431 @Query('channelId') channelId?: string,
432 @Query('id') playListIds?: string,
433 @Query('mine') mine?: boolean,
434 @Query('maxResults') maxResults?: string,
435 @Query('pageToken') pageToken?: string,
436 ) {
437 // 校验确保只有一个参数传递
438 const params = [channelId, playListIds, mine];
439 const nonEmptyParams = params.filter(param => param !== undefined && param !== null && param !== '');
440
441 if (nonEmptyParams.length > 1) {
442 throw new BadRequestException('只能选择一个参数: channelId, playListIds, mine');
443 }
444 const accessToken = await this.youtubeAuthService.getUserAccessToken(accountId);
445 return this.youtubeService.getPlayList(accessToken, channelId, playListIds, mine, maxResults, pageToken);
446 }
447
448 @ApiOperation({ summary: '更新播放列表' })
449 @Post('playlist/update')
450 async playlistUpdate(
451 @GetToken() token: TokenInfo,
452 @Body('accountId') accountId: string,
453 @Body('playListId') playListId: string,
454 @Body('snippet') snippet?: Record<string, any>,
455 @Body('status') status?: Record<string, any>,
456 ) {
457 const accessToken = await this.youtubeAuthService.getUserAccessToken(accountId);
458 return this.youtubeService.updatePlayList(accessToken, playListId, snippet, status);
459 }
460
461 @ApiOperation({ summary: '删除播放列表' })
462 @Post('playlist/delete')
463 async playlistDelete(
464 @GetToken() token: TokenInfo,
465 @Body('id') playListId: string,
466 @Body('accountId') accountId: string,
467 ) {
468 const accessToken = await this.youtubeAuthService.getUserAccessToken(accountId);
469 return this.youtubeService.deletePlaylist(accessToken, playListId);
470 }
471
472 @ApiOperation({ summary: '获取播放列表项' })
473 // @Public()
474 @Get('playlist/items/list')
475 async getPlayItemsList(
476 @GetToken() token: TokenInfo,
477 @Query('accountId') accountId: string,
478 @Query('playlistId') playlistId: string,
479 @Query('id') playlistItemsIds: string,
480 @Query('maxResults') maxResults?: string,
481 @Query('pageToken') pageToken?: string,
482 ) {
483 // 校验确保只有一个参数传递
484 const params = [playlistId, playlistItemsIds];
485 const nonEmptyParams = params.filter(param => param !== undefined && param !== null && param !== '');
486
487 if (nonEmptyParams.length > 1) {
488 throw new BadRequestException('只能选择一个参数: playlistId, playlistItemsIds');
489 }
490 const accessToken = await this.youtubeAuthService.getUserAccessToken(accountId);
491 return this.youtubeService.getPlayItemsList(accessToken, playlistId, playlistItemsIds, maxResults, pageToken);
492 }
493
494 @ApiOperation({ summary: '添加播放列表项' })
495 @Post('playlist/items/insert')
496 async PlayItemsInsert(
497 @GetToken() token: TokenInfo,
498 @Body('accountId') accountId: string,
499 @Body('snippet') snippet?: Record<string, any>,
500 @Body('contentDetails') contentDetails?: Record<string, any>,
501 ) {
502 const accessToken = await this.youtubeAuthService.getUserAccessToken(accountId);
503 return this.youtubeService.insertPlayItems(accessToken, snippet, contentDetails);
504 }
505
506 @ApiOperation({ summary: '更新播放列表项' })
507 @Post('playlist/items/update')
508 async playItemsUpdate(
509 @GetToken() token: TokenInfo,
510 @Body('accountId') accountId: string,
511 @Body('id') playlistItemsId: string,
512 @Body('snippet') snippet?: Record<string, any>,
513 @Body('contentDetails') contentDetails?: Record<string, any>,
514
515 ) {
516 const accessToken = await this.youtubeAuthService.getUserAccessToken(accountId);
517 return this.youtubeService.updatePlayItems(accessToken, playlistItemsId, snippet, contentDetails);
518 }
519
520 @ApiOperation({ summary: '删除播放列表项' })
521 @Post('playlist/items/delete')
522 async playItemsDelete(
523 @GetToken() token: TokenInfo,
524 @Body('accountId') accountId: string,
525 @Body('id') playlistItemsId: string,
526 ) {
527 const accessToken = await this.youtubeAuthService.getUserAccessToken(accountId);
528 return this.youtubeService.deletePlayItems(accessToken, playlistItemsId);
529 }
530
531 @ApiOperation({ summary: '视频的点赞、踩' })
532 @Post('videos/rate')
533 async videosRate(
534 @GetToken() token: TokenInfo,
535 @Body('accountId') accountId: string,
536 @Body('id') videoId: string,
537 @Body('rating') rating: string,
538 ) {
539 const accessToken = await this.youtubeAuthService.getUserAccessToken(accountId);
540 return this.youtubeService.videosRate(accessToken, videoId, rating);
541 }
542
543 @ApiOperation({ summary: '获取视频的点赞、踩' })
544 @Get('videos/rate/list')
545 async getVideosRating(
546 @GetToken() token: TokenInfo,
547 @Query('accountId') accountId: string,
548 @Query('id') videoIds: string,
549 ) {
550 const accessToken = await this.youtubeAuthService.getUserAccessToken(accountId);
551 return this.youtubeService.getVideosRating(accessToken, videoIds);
552 }
553
554 }
555
556
556 lines TYPESCRIPT