NOMO.asia

UserScript 로 채팅 제어하기

Posted 2017. 8. 1. 05:23, Filed under: 개발/UserScript

UserScript 를 이용해서 채팅을 제어(파싱)하고 싶은 경우

UserScript 를 이용해서 채팅을 제어(파싱)하고 싶은 경우가 있을 수 있다. 예를 들어 어떠한 보기 싫은 글귀가 올라온 경우 삭제할 수 있고, 특정 사용자의 글을 보이지 않게 할 수도 있고, 실제 채팅창 관리자에 의해 삭제된 메시지를 보관하였다가 보여주거나, 채팅에 올라온 이미지 주소를 감지하여 이미지를 채팅창에서 미리보기 하게 할 수도 있다.


어려운 방법으로는 socket.io 등을 이용하여 자바스크립트로 채팅창에 접속하거나, 해당 채팅이 IRC를 사용하는 경우 javascript IRC 관련된 라이브러리를 사용할 수 있을 것 같다. 다만 해당 채팅창에서 클라이언트의 중복 접속을 막거나 별도의 인증을 하는 경우, 실제 사용자가 채팅을 하면서 동시에 유저스크립트를 동작할 수 있게 하기 위해서는 유저스크립트 쪽에서 파싱을 하기 위하여 프록시를 써야하거나, 해당 채팅에 관련된 패킷과 해당 웹사이트에서 채팅을 구현하는 소스 코드를 분석해야 하는 등 상당히 복잡해질 수 있다. 따라서 단순히 클라이언트 단에서 채팅이 새로 올라오며 생성되는 DOE 요소를 탐지하는 것이 효과적일 수 있다.



DOE 요소가 생성 또는 삭제되는 것을 탐지하기 - arrive 라이브러리

제목은 Userscript 로 채팅 파싱하기라고 적었지만, 새롭게 어떠한 DOE 요소가 생성 또는 삭제되는 경우에 대하여 쉽게 사용 가능한 라이브러리를 소개하고자 한다. 해당 스크립트는 arrive(https://github.com/uzairfarooq/arrive) 이다.


먼저 당연하게도 해당 라이브러리를 @require 로 불러오거나 직접 유저스크립트 내에 삽입하는 등의 방법으로 사용할 수 있도록 하여야한다.


이후 위의 github 링크로 들어가 사용법을 익히거나 아래의 예제와 같이 사용하면 된다.

// DOE 생성 확인 이벤트 등록
$(document).arrive(".chat_line", function(newElem) {
      var newElem = $(newElem);
      var newElem_html = newElem.html();
      console.log(newElem);

      // ① 금지어 삭제
      if(newElem_html.indexOf('금지어') !== -1){
            console.log('금지어 감지됨!',newElem_html);
            newElem.remove();
      }

      // ② 특정 조건에서 함수 동작
      if(newElem_html.indexOf('special') !== -1){
            console.log('special 문구 감지됨!',newElem_html);
            example_ajax_function( newElem_html );
      }
      newElem = null;
      newElem_html = null;
});

// DOE 삭제 확인 이벤트 등록
$(document).leave(".chat_line", function(removedElem) {
      var removedElem = $(removedElem);

      // ③ 삭제된 메시지 확인
      console.log( '삭제된 메시지',removedElem.html() );
      removedElem = null;
});

먼저 'chat_line' 이라는 이름의 class 엘리먼트가 새로 생성되는지를 감지하는 이벤트를 등록하며, ① 에서는 해당 class 내에 '금지어'가 포함되어 있으면 해당 엘리먼트를 삭제하도록 한다. 이벤트로 등록되므로 위 코드를 한 번만 등록해놓으면 채팅이 올라올 때마다 자동으로 금지어가 삭제된다.


② 에서는 새로 생성된 엘리먼트에서 'special' 한 문구가 탐지된 경우 정해진 함수가 동작하도록 한다. 내 경우에는 정규 표현식을 이용하여 보안이 보장된 이미지 링크를 감지한 뒤 해당 이미지를 미리보여주는 용도로 사용했다.


그 다음으로는 '.chat_line' 엘리먼트가 삭제되는 경우를 감지하는 이벤트를 등록하며, ③ 에서는 삭제된 엘리먼트의 메시지를 콘솔창에 보여주도록 한다.


실제 라이브러리의 사용법에 대한 내용은 github 링크(https://github.com/uzairfarooq/arrive) 에 충분히 설명되어 있는 것 같다. 이 라이브러리를 UserScript 에 실제로 적용한 예제는 구글에서 uzairfarooq arrive userscript, uzairfarooq arrive greasemonkey, uzairfarooq arrive tampermonkey 로 검색하면 일부 내용이 나온다. 따라서 자세한 내용은 생략하고 사용 시 겪었던 몇가지 문제점만 아래에 소개하고자 한다.



사용 시 주의할 점

내 경우 한 페이지에서 오래 잔류하는 경우와 동시에 복잡한 함수 호출 등이 위 이벤트로 인해 실행된 경우 채팅이 누적되며 garbage collection 이 제대로 동작하지 않아서 메모리 부족으로 브라우저가 터지는 경우가 있었다(Chrome 에서만 발생). 따라서 코드의 가장 마지막에 선언된 로컬 변수들을 null 로 초기화 하여 강제로 garbage collection을 실행하도록 해주는 것이 유효했다. 다만 이러한 초기화 동작이 ajax call 등에 문제를 발생시키는 경우 ajax 콜이 끝난 후 null 이 되도록 별도의 처리를 해주어야 한다.


위 코드에서 document 대신에 #chat_container 등과 같이 .chat_line 를 포함하는(둘러싸는) 다른 엘리먼트의 선택자를 입력할 수도 있다. 다만 해당 엘리먼트가 동적 생성으로 인해 유저스크립트에서 위 이벤트가 등록이 된 이후에 생성되는 경우 제대로 동작하지 않으니 위 코드 블록에 대하여 딜레이를 주거나 document ready, load 등에 위 코드를 등록해주는 것이 필요하다.


혹은 위 코드를 function 으로 정의한 뒤, 특정 조건이 되었을 때(예를 들면 채팅창이 동적으로 생성된 이후에) 해당 function 을 실행하여 이벤트를 등록하는 방법으로도 가능하다.