ENFRKOantony langlois
작업

Twitch Chest Auto Claimer

방문크롬 확장 프로그램Chrome ExtensionJavaScript

시청하는 동안 Twitch 보너스 상자를 자동으로 수령하는 Chrome 확장 프로그램입니다 · 시맨틱 선택자 캐스케이드로 Twitch의 난독화된 CSS 변경에도 버팁니다 · 백엔드 없음

아키텍처

published
Distribution · store
Chrome Web Store
v1.4.5 · auto-updates
공개 등록물; Chrome이 새 버전을 사용자에게 조용히 푸시합니다
HTML + JS
Frontend · popup
Stats 팝업
popup.html · popup.js
수령 카운터를 읽어 획득한 포인트를 산출합니다 (x50)
vanilla JS
Core · content script
자동 수령 루프
content.js · injected on twitch.tv/*
5초마다 폴링합니다: findClaimButton()이 4개 선택자 캐스케이드를 따라가 실제 버튼까지 올라가 클릭합니다
5초 인터벌선택자 캐스케이드closest('button') 올라가기readyState 가드비활성화 확인
third-party
Host page · DOM
Twitch 라이브 페이지
커뮤니티 포인트 요약
상자 버튼이 약 15분마다 나타납니다; 클래스 해시는 CSS를 리빌드할 때마다 바뀝니다
key-value
Storage · local
chrome.storage.local
claimedBonusChestCount
단일 카운터: 수령 시 증가하고 팝업이 읽습니다

Chrome은 모든 twitch.tv 페이지에 content.js를 주입합니다. readyState 가드는 load 이벤트가 이미 발생했든 아니든 루프를 시작하고, 이후 5초마다 폴링합니다. 매 틱마다 findClaimButton()은 커뮤니티 포인트 요약으로 검색 범위를 좁히고 4개의 시맨틱 선택자 캐스케이드를 따라갑니다. 상자가 나타나면 closest()로 감싸는 <button>까지 올라가 비활성화되지 않았는지 확인한 뒤 클릭합니다. 수령에 성공하면 chrome.storage.localclaimedBonusChestCount를 증가시킵니다. Stats 팝업은 열릴 때 이 카운터를 읽어 획득한 채널 포인트를 산출합니다.

배포: Extension → Chrome Web Store · MV3, 모든 것이 클라이언트 측에서 실행됩니다

성과

  • ≤ 5초 · 상자 표시됨 → 수령됨
  • 0 · 서버 · 모든 로직이 탭 안에서 실행됨
  • 4 · 폴백 선택자, 장식적인 것보다 시맨틱한 것 우선
  • 2 · 총 권한: storage + twitch.tv 호스트

보여준 역량: 견고한 DOM 선택자 전략 · Chrome 확장 프로그램 MV3 · SPA 인식 콘텐츠 스크립트 · 최소한의 권한 표면

문제와 해결책

모든 선택은 하나의 제약에 답합니다: 확장 프로그램은 자신이 제어할 수 없고 예고 없이 바뀌는 페이지 안에서 동작합니다.

▓ Twitch의 CSS 변경을 넘어 살아남기

문제: Twitch는 styled-components로 UI를 구성합니다: 클래스 이름은 ScCoreButton-sc-ocjdkq-0 같은 컴파일러 해시이며 프론트엔드를 리빌드할 때마다 바뀝니다. 초기 버전은 이런 해시에 고정되어 조용히 깨졌고, git 히스토리의 별개 릴리스 네 건이 선택자 수정입니다.

저는 해시 선택자를 4개의 시맨틱 훅으로 이루어진 우선순위 캐스케이드로 교체했습니다: 상자 아이콘 클래스, Twitch 자체의 data-test-selector 속성 두 개, 그리고 data-a-target 하나입니다. 매칭된 것이 내부 아이콘일 수 있으므로, 코드는 closest('button')으로 클릭 가능한 요소까지 올라갑니다.

  • 반복된 깨짐 이후 해시 클래스를 거부했습니다: 그것은 컴파일러 출력이지 API가 아닙니다
  • 버튼 텍스트 매칭을 거부했습니다: 영어가 아닌 모든 로케일에서 깨집니다
  • 테스트 훅도 여전히 Twitch 내부 요소이므로, 어느 하나에 의존하는 대신 4개의 독립적인 폴백을 둡니다

▒ MutationObserver 대신 폴링

문제: 상자는 예측할 수 없는 순간에 나타나고, 감지는 이미 비디오 재생으로 바쁜 탭 안에서 실행됩니다. 여기서 잘못된 선택은 모든 채팅 메시지마다 CPU를 소모합니다.

틱마다 범위가 좁혀진 querySelector 하나를 실행하는 단순한 5초 setInterval입니다: Twitch의 약 15분 주기에서 상자 하나당 대략 180번의 저렴한 no-op 검사입니다.

  • MutationObserver를 먼저 시도했습니다 (그 실험은 content copy.js로 남아 있습니다): Twitch 채팅은 끊임없이 변형되어 콜백이 폭풍처럼 발화했습니다
  • 사소할 정도로 올바른 루프를 얻는 대가로 최대 5초의 수령 지연을 받아들였습니다
  • 채널 전환 사이에 문서가 유지되므로, 이 인터벌은 Twitch의 SPA 내비게이션에도 살아남습니다

▚ 백그라운드 서비스 워커 없음

문제: MV3는 확장 프로그램 로직을 서비스 워커 쪽으로 밀어붙입니다: 더 많은 구성 요소, 더 많은 생명주기 버그, 더 많은 Web Store 심사 검토입니다.

확장 프로그램 전체는 콘텐츠 스크립트 하나와 팝업 하나입니다. twitch.tv 호스트 외에 유일한 권한은 storage뿐입니다.

  • alarms API를 쓰는 백그라운드 워커를 거부했습니다: Twitch 탭이 열려 있지 않을 때는 할 일이 없습니다
  • 항목 2개짜리 권한 표면은 더 빠른 스토어 심사와 사용자가 실제로 신뢰할 수 있는 설치 안내를 의미합니다
  • 트레이드오프: 탭 간 조율이 없어 각 탭이 독립적으로 폴링하지만, 이미 수령한 상자를 클릭하는 것은 no-op(비활성화 확인)이므로 허용됩니다

▧ SPA에서의 주입 타이밍

문제: 콘텐츠 스크립트는 페이지의 load 이벤트 전이나 후에 실행될 수 있고, Twitch는 pushState로 채널 사이를 이동하며 절대 새로고침하지 않습니다. 초기 버전은 사용자가 채널을 전환한 뒤 모든 상자를 놓쳤습니다.

readyState 가드load가 이미 발생했으면 루프를 즉시 시작하고 아니면 이를 대기합니다. 그러면 인터벌은 모든 앱 내 내비게이션을 넘어 살아남습니다.

  • webNavigation 이벤트를 통한 재주입을 거부했습니다: 지속되는 인터벌이 이미 해결하는 문제에 대한 추가 권한입니다
  • 이 가드는 늦게 주입된 스크립트가 결코 오지 않는 load 이벤트를 기다리는 경합을 막습니다
  • 하나의 인터벌이 사용자가 그 탭에서 이동하는 모든 채널을 커버합니다

▤ 백엔드 없는 통계

문제: 사용자는 확장 프로그램이 동작한다는 증거를 원하지만, 텔레메트리 서버는 무료 도구에게 비용, 유지보수, 그리고 개인정보 책임이 됩니다.

chrome.storage.local의 단일 카운터로, 수령할 때마다 증가합니다. 팝업은 이를 읽어 획득한 채널 포인트를 산출합니다 (x50).

  • 원격 분석을 전면 거부했습니다: 인프라 없음, 데이터가 절대 브라우저를 떠나지 않습니다
  • 트레이드오프: 카운터는 기기 로컬이며 여러 기기 간에 동기화되지 않지만, 허영 통계로는 괜찮습니다
  • 비동기 스토리지 API를 통한 read-modify-write는 팝업과 콘텐츠 스크립트를 분리된 상태로 유지합니다