KillKagi 개발기 — 치지직 도네이션 API 연동하면서 겪은 것들

치지직 도네이션 API 연동부터 OBS 오버레이 구현, 이벤트 처리 구조까지 KillKagi를 만들며 겪은 시행착오와 해결 방법을 단계별로 정리한 개발 일지입니다.

본문 상단 광고

광고 영역

가시 영역 진입 시 로드

목차

시작하게 된 계기

스트리머 친구가 방송 중에 이런 말을 했습니다.

“도네이션 받을 때마다 킬 목표 계산하는 게 너무 귀찮아. 자동으로 해주는 툴 없나?”

그 순간 ‘아, 이거 만들면 되겠다’ 싶었습니다. 치지직 API가 공개되어 있다는 것도 알고 있었고, OBS 브라우저 소스 기능을 활용하면 오버레이도 쉽게 만들 수 있을 것 같았습니다.

관련 글: OBS 오버레이를 React로 만드는 법, KillKagi 툴 상세

치지직 API 탐색

치지직은 네이버에서 운영하는 게임 스트리밍 플랫폼입니다. 공식 API 문서가 잘 정리되어 있지는 않아서, 처음에는 네트워크 탭을 열어서 직접 분석해야 했습니다.

WebSocket 연결

도네이션 이벤트는 WebSocket을 통해 실시간으로 전달됩니다.

const ws = new WebSocket('wss://kr-ss1.chat.naver.com/chat');

ws.onopen = () => {
  // 채널 구독
  ws.send(JSON.stringify({
    svcid: 'game',
    cid: channelId,
    svcNo: 1,
    cmd: 100,
    tid: 1,
    bdy: {
      accTkn: accessToken,
      auth: 'READ',
      devType: 2001,
    }
  }));
};

도네이션 이벤트 파싱

ws.onmessage = (event) => {
  const data = JSON.parse(event.data);
  
  // 도네이션 이벤트 타입 확인
  if (data.cmd === 10100) {
    const donation = data.bdy;
    const amount = donation.payAmount;
    const nickname = donation.userNickname;
    
    console.log(`${nickname}님이 ${amount}원 도네이션!`);
    updateKillCounter(amount);
  }
};

가장 힘들었던 부분: 파티 도네이션

일반 도네이션은 비교적 쉽게 처리할 수 있었습니다. 문제는 파티 도네이션이었습니다.

파티 도네이션은 여러 명이 함께 도네이션하는 기능인데, 이벤트 구조가 일반 도네이션과 달랐습니다.

// 일반 도네이션
{
  "cmd": 10100,
  "bdy": {
    "payAmount": 1000,
    "userNickname": "시청자A"
  }
}

// 파티 도네이션 (구조가 다름!)
{
  "cmd": 10101,
  "bdy": {
    "partyDonation": {
      "totalAmount": 5000,
      "participants": [
        { "nickname": "시청자A", "amount": 2000 },
        { "nickname": "시청자B", "amount": 3000 }
      ]
    }
  }
}

처음에는 파티 도네이션을 놓쳐서 킬 카운터가 제대로 업데이트되지 않는 버그가 있었습니다. 이벤트 타입을 10101로 별도 처리하는 로직을 추가해서 해결했습니다.

OBS 오버레이 구현

OBS 브라우저 소스는 기본적으로 Chromium 기반이라 일반 웹 기술을 그대로 사용할 수 있습니다.

실시간 업데이트

서버에서 클라이언트로 실시간 데이터를 전달하기 위해 Server-Sent Events(SSE)를 사용했습니다.

// 서버 (Express)
app.get('/events', (req, res) => {
  res.setHeader('Content-Type', 'text/event-stream');
  res.setHeader('Cache-Control', 'no-cache');
  res.setHeader('Connection', 'keep-alive');

  const sendUpdate = (data) => {
    res.write(`data: ${JSON.stringify(data)}\n\n`);
  };

  killCounter.on('update', sendUpdate);
  
  req.on('close', () => {
    killCounter.off('update', sendUpdate);
  });
});
// 클라이언트 (오버레이)
const eventSource = new EventSource('/events');

eventSource.onmessage = (event) => {
  const { current, target } = JSON.parse(event.data);
  document.getElementById('kill-count').textContent = `${current} / ${target}`;
  updateProgressBar(current / target * 100);
};

배운 점

  1. API 문서 없이도 개발할 수 있다: 네트워크 탭과 약간의 인내심이면 됩니다.
  2. 엣지 케이스를 미리 생각하자: 파티 도네이션처럼 예외적인 케이스를 놓치면 사용자 경험이 나빠집니다.
  3. SSE가 WebSocket보다 간단한 경우가 많다: 단방향 실시간 통신에는 SSE가 더 적합합니다.

다음 계획

  • 아프리카TV 슈퍼챗 연동
  • 오버레이 테마 추가 (5가지 예정)
  • 목표 달성 시 애니메이션 효과
  • 웹 대시보드로 실시간 설정 변경

GitHub에서 Star 눌러주시면 개발 의욕이 올라갑니다 ⭐

본문 하단 광고

광고 영역

가시 영역 진입 시 로드

시리즈 — killkagi-launch

이전 · 다음 글

이전 글 Adversarial Robustness 논문 리뷰 — FGSM/PGD/C&W 공격 비교 분석