fromis_9/backend/src/services/youtube/index.js

142 lines
3.6 KiB
JavaScript
Raw Normal View History

import fp from 'fastify-plugin';
import { fetchRecentVideos, fetchAllVideos } from './api.js';
import bots from '../../config/bots.js';
const YOUTUBE_CATEGORY_ID = 2;
async function youtubeBotPlugin(fastify, opts) {
/**
* 멤버 이름 조회
*/
async function getMemberNameMap() {
const [rows] = await fastify.db.query('SELECT id, name FROM members');
const map = {};
for (const r of rows) {
map[r.name] = r.id;
}
return map;
}
/**
* description에서 멤버 추출
*/
function extractMemberIds(description, memberNameMap) {
if (!description) return [];
const ids = [];
for (const [name, id] of Object.entries(memberNameMap)) {
if (description.includes(name)) {
ids.push(id);
}
}
return ids;
}
/**
* 영상을 DB에 저장
*/
async function saveVideo(video, bot) {
// 중복 체크 (video_id로)
const [existing] = await fastify.db.query(
'SELECT id FROM schedule_youtube WHERE video_id = ?',
[video.videoId]
);
if (existing.length > 0) {
return null;
}
// 커스텀 설정 적용
if (bot.titleFilter && !video.title.includes(bot.titleFilter)) {
return null;
}
// schedules 테이블에 저장
const [result] = await fastify.db.query(
'INSERT INTO schedules (category_id, title, date, time) VALUES (?, ?, ?, ?)',
[YOUTUBE_CATEGORY_ID, video.title, video.date, video.time]
);
const scheduleId = result.insertId;
// schedule_youtube 테이블에 저장
await fastify.db.query(
'INSERT INTO schedule_youtube (schedule_id, video_id, video_type, channel_id, channel_name) VALUES (?, ?, ?, ?, ?)',
[scheduleId, video.videoId, video.videoType, video.channelId, bot.channelName]
);
// 멤버 연결 (커스텀 설정)
if (bot.defaultMemberId || bot.extractMembersFromDesc) {
const memberIds = [];
if (bot.defaultMemberId) {
memberIds.push(bot.defaultMemberId);
}
if (bot.extractMembersFromDesc) {
const nameMap = await getMemberNameMap();
memberIds.push(...extractMemberIds(video.description, nameMap));
}
if (memberIds.length > 0) {
const uniqueIds = [...new Set(memberIds)];
const values = uniqueIds.map(id => [scheduleId, id]);
await fastify.db.query(
'INSERT INTO schedule_members (schedule_id, member_id) VALUES ?',
[values]
);
}
}
return scheduleId;
}
/**
* 최근 영상 동기화 (정기 실행)
*/
async function syncNewVideos(bot) {
const videos = await fetchRecentVideos(bot.channelId, 10);
let addedCount = 0;
for (const video of videos) {
const scheduleId = await saveVideo(video, bot);
if (scheduleId) {
addedCount++;
}
}
return { addedCount, total: videos.length };
}
/**
* 전체 영상 동기화 (초기화)
*/
async function syncAllVideos(bot) {
const videos = await fetchAllVideos(bot.channelId);
let addedCount = 0;
for (const video of videos) {
const scheduleId = await saveVideo(video, bot);
if (scheduleId) {
addedCount++;
}
}
return { addedCount, total: videos.length };
}
/**
* 관리 중인 채널 ID 목록
*/
function getManagedChannelIds() {
return bots
.filter(b => b.type === 'youtube')
.map(b => b.channelId);
}
fastify.decorate('youtubeBot', {
syncNewVideos,
syncAllVideos,
getManagedChannelIds,
});
}
export default fp(youtubeBotPlugin, {
name: 'youtubeBot',
dependencies: ['db'],
});