Nodejs

 

유튜브 자막 추출후  구글 번역기로 한국어 번역  텍스트 출력

 

라이브러리 설치:

npm install youtube-captions-scraper @vitalets/google-translate-api http-proxy-agent https-proxy-agent got
 

 

 

1) proxyLists.ts

 

import fs from 'fs/promises';
import got from 'got';
import path from 'path';

const FILE_PATH = path.join(__dirname, 'proxies.txt');

export async function getFastestProxy(): Promise<string | null> {
  try {
    const today = new Date().toISOString().split('T')[0]; // YYYY-MM-DD
    let proxies: string[] = [];

    // 파일이 존재하는지 체크
    try {
      const fileData = await fs.readFile(FILE_PATH, 'utf-8');
      const [fileDate, ...fileProxies] = fileData.split('\n').filter(Boolean);

      if (fileDate === today) {
        console.log('✅ 오늘 날짜 프록시 캐시 사용');
        proxies = fileProxies;
      } else {
        console.log('???? 날짜 다름, 새로 프록시 가져오기');
        proxies = await fetchAndSaveProxies(today);
      }
    } catch (err) {
      console.log('???? 파일 없음 또는 에러, 새로 프록시 가져오기');
      proxies = await fetchAndSaveProxies(today);
    }

    if (proxies.length === 0) {
      throw new Error('프록시가 없습니다.');
    }

    // 랜덤 프록시 선택
    const randomIndex = Math.floor(Math.random() * proxies.length);
    const proxy = proxies[randomIndex].trim(); // 랜덤으로 선택된 프록시
    console.log('✅ 선택된 랜덤 프록시:', proxy);
    return `http://${proxy}`;
  } catch (error) {
    console.error('❌ 프록시 가져오기 실패:', error);
    return null;
  }
}

async function fetchAndSaveProxies(today: string): Promise<string[]> {
  const response = await got('https://api.proxyscrape.com/v2/?request=getproxies&protocol=http&timeout=3000&country=all&ssl=all&anonymity=all');
  const proxies = response.body.split('\n').filter(Boolean);

  if (proxies.length === 0) {
    throw new Error('받아온 프록시 리스트가 비어있습니다.');
  }

  const fileContent = [today, ...proxies].join('\n');
  await fs.writeFile(FILE_PATH, fileContent, 'utf-8');

  console.log('???? 새 프록시 파일 저장 완료');
  return proxies;
}

 

 

 

 

 

2)service.ts

import type { Core } from "@strapi/strapi";
import { getSubtitles } from 'youtube-captions-scraper';
import { translate } from '@vitalets/google-translate-api';
import { HttpProxyAgent } from 'http-proxy-agent';

import { HttpsProxyAgent } from "https-proxy-agent";
import got from "got";
import { getFastestProxy } from "./proxyLists";

/**
 * ???? youtube-captions-scraper 라이브러리를 사용한 번역
 *  ????  service.ts 복사 붙여 넣기
 * @param videoId 
 * @param lang 
 * @returns 
 */

// 첫 문장이 한국어인지 확인하는 함수
function isKorean(text: string): boolean {
  const koreanRegex = /[ㄱ-ㅎ|ㅏ-ㅣ|가-힣]/;
  return koreanRegex.test(text);
}



async function getYouTubeTranscript(videoId: string, lang: string = 'ko'): Promise<string | null> {
  const languages = ['ko', 'en']; // 우선 한국어, 그다음 영어 자막으로 시도

  for (let language of languages) {
    try {
      const transcriptItems = await getSubtitles({
        videoID: videoId,
        lang: language // 각 언어로 자막을 가져옵니다.
      });

      if (transcriptItems.length > 0) {
        return transcriptItems.map(item => item.text).join(' ');
      } else {
        console.log(`${language} 자막이 없습니다.`);
      }
    } catch (error) {
      //  console.error(`${language} 자막을 가져오는 중 오류가 발생했습니다.`, error);
    }
  }

  return null; // 자막을 찾지 못한 경우 null 반환
}

const service = ({ strapi }: { strapi: Core.Strapi }) => ({
  async getYoutubeTranscript(videoId: string) {
    const youtubeIdRegex = /^[a-zA-Z0-9_-]{11}$/;
    const isValid = youtubeIdRegex.test(videoId);

    if (!isValid) {
      return { error: "Invalid video ID", data: null };
    }

    try {
      const transcript = await getYouTubeTranscript(videoId);

      if (!transcript) {
        return { error: "대본을 가져오는 데 실패했습니다.", data: null };
      }

      let korTranscript =transcript;

      // 첫 번째 문장이 한국어인지 확인
      if (isKorean(transcript.split(' ')[0])) {
        console.log("✅ 첫 문장이 한국어로 확인되어 프록시 없이 바로 반환합니다.");
        return korTranscript;
      }

      try { 
        //???? 여기에서 번역을 수행    
        console.log("????프록시 설정:");
        //const agent = new HttpProxyAgent('http://103.152.112.162:80');
        const proxyUrl = await getFastestProxy();
        if (proxyUrl) {
          console.log("✅ 사용 프록시:", proxyUrl);

          const agent = proxyUrl.startsWith('https')
            ? new HttpsProxyAgent(proxyUrl)
            : new HttpProxyAgent(proxyUrl);

          const customGot = got.extend({
            agent: {
              http: agent,
              https: agent,
            },
          });

          const { text } = await translate(transcript, { to: 'ko', fetchOptions: customGot });
          korTranscript = text;
          console.log("✅ 사용 프록시 적용 번역 ????????????????:", korTranscript);
        }                      
      
      } catch (error) {
        console.log("⚠️ 빠른 프록시를 찾지 못했습니다. 프록시 없이 번역 시도합니다.");
        try {
          const { text } = await translate(transcript, { to: 'ko' });
          korTranscript = text;  
        } catch (error) {
          console.log(" 오류 --원본::")
          korTranscript =transcript;        
        }        
      }

    
      return korTranscript;
    } catch (error) {
      return { error: "대본을 가져오는 중 오류가 발생했습니다: " + error, data: null };
    }
  },
});

export default service;

 

 

 

 

 

 

about author

PHRASE

Level 60  라이트

진리가 나를 인도해 주는데 무엇이 두려우랴. -간디

댓글 ( 0)

댓글 남기기

작성