Advertisement
Guest User

te31_quarantine.js

a guest
Oct 13th, 2019
361
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
  1. /*
  2.  * 아래 userMatrix 의 형식에 주의하세요. 2개 이상을 입력한 경우, 마지막 줄에는 , 이 없어야 합니다.
  3.  * 따옴표 안에는 따옴표를 제외한 아무 내용이나 넣어도 괜찮습니다.
  4.  * var userMaterix = {
  5.  *     646: "고펑",                 // 두개 이상의 id 를 추가하려면 줄 끝에 콤마(,) 를 넣어야 합니다.
  6.  *     9999: "자지보지섹스얍얍"     // 마지막 줄의 끝에는 콤마(,) 가 없어야 합니다. 콤마가 있을 경우 스크립트가 동작하지 않을 수 있습니다.
  7.  * }
  8.  */
  9. var userMatrix = {
  10. };
  11.  
  12. // 게시글 xPath 정의
  13. var XPATH_POSTS_TABLE = "//*[@id='revolution_main_table']/tbody[2]";
  14. var XPATH_CONTENT_WITH_REPLIES = "/html/body/div[2]/div[2]";
  15. var XPATH_VIEW_ALL_REPLIES = "/html/body/div[2]/div[2]/table[10]/tbody/tr/td/p/a";
  16.  
  17. // 화면 모드 정의.
  18. var SCREEN_MODE_TITLE_GENERAL = "zboard.php";
  19. var SCREEN_MODE_DETAILS = "view.php";
  20. var SCREEN_MODE_TITLE_HOF = "best_pc.php";
  21. var SCREEN_MODES = [
  22.     SCREEN_MODE_TITLE_GENERAL, SCREEN_MODE_DETAILS, SCREEN_MODE_TITLE_HOF
  23. ];
  24.  
  25. // 메인 프로그램
  26. function main() {
  27.     // 화면 모드 먼저 판별하는 이유는 불필요한 연산 조금이라도 줄이기 위함
  28.     const screenMode = function() {
  29.         const pathFragments = document.location.pathname.split("/");
  30.         const lastPath = pathFragments[pathFragments.length - 1];
  31.         for (const value of SCREEN_MODES) {
  32.             if(value === lastPath) {
  33.                 return value;
  34.             }
  35.         }
  36.  
  37.         return null;
  38.     }();
  39.     if (screenMode == null) {
  40.         console.error(`URL 형식이 변경되어 더 이상 진행할 수 없습니다.`);
  41.         return;
  42.     }
  43.  
  44.     // zbLayerId 와 일치하는 memberId 사전 생성
  45.     const layerIdMap = buildLayerIdMap();
  46.     if (layerIdMap.length === 0) {
  47.         console.error(`Document 형식이 변경되어 더 이상 진행할 수 없습니다.`);
  48.         return;
  49.     }
  50.  
  51.     // 화면 모드에 따라 프로그램 진행
  52.     switch(screenMode) {
  53.         case SCREEN_MODE_TITLE_GENERAL: {
  54.             const table = getElementByXpath(XPATH_POSTS_TABLE);
  55.             const tableRowsCount = table.children.length;
  56.             const postsCount = Array.from(table.children).filter(it => {
  57.                 return it.children.length == 5;
  58.             }).length;
  59.             const trOffset = tableRowsCount - postsCount;
  60.    
  61.             removePosts(layerIdMap, postsCount, trOffset);
  62.         }
  63.         break;
  64.  
  65.         case SCREEN_MODE_DETAILS: {
  66.             const [replyXpathOffset, replyDomOffset] = function() {
  67.                 // Parent DOM 으로부터 제일 첫번째 댓글이 보이는 Element offset 을 구한다.
  68.                 if (getElementByXpath(XPATH_VIEW_ALL_REPLIES)) {
  69.                     return [11, 39];
  70.                 } else {
  71.                     return [9, 29];
  72.                 }
  73.             }();
  74.  
  75.             removeReplies(layerIdMap, replyXpathOffset, replyDomOffset);
  76.         }
  77.         break;
  78.  
  79.         default:
  80.             console.error(`'${screenMode}' 에 대한 처리 방법이 아직 없습니다.`);
  81.         break;
  82.     }
  83. }
  84.  
  85. function getElementByXpath(path) {
  86.   return document.evaluate(path, document, null, XPathResult.FIRST_ORDERED_NODE_TYPE, null).singleNodeValue;
  87. };
  88.  
  89. function buildLayerIdMap() {
  90.     // print_ZBlayer(name, homepage, mail, member_no, boardID,  writer, traceID, traceType, isAdmin, isMember)
  91.     var REGEX_ZB_LAYER_PRINT_FUNC = /print_ZBlayer\(['"](zbLayer[0-9]+)['"], ['"]()['"], ['"]()['"], ['"]([0-9]+)['"], .*\)/;
  92.  
  93.     const layerIdMap = {};
  94.     Array.from(document.getElementsByTagName("script")).forEach(script => {
  95.         const textNode = script.text.trim();
  96.         const match = textNode.match(REGEX_ZB_LAYER_PRINT_FUNC);
  97.         if (match) {
  98.             textNode.split("\n").forEach(it => {
  99.                 const printArgs = it.match(REGEX_ZB_LAYER_PRINT_FUNC);
  100.                 layerIdMap[printArgs[1]] = printArgs[4];
  101.             });
  102.         }
  103.     });
  104.  
  105.     return layerIdMap;
  106. }
  107.  
  108. function removePosts(layerIdMap, postsCount, trOffset) {
  109.     const quarantined = [];
  110.  
  111.     for (let i = 1; i <= postsCount; i++) {
  112.         const trIndex = trOffset + i;
  113.         const postRowXPath = `${XPATH_POSTS_TABLE}/tr[${trIndex}]`;
  114.         const row = getElementByXpath(postRowXPath);
  115.         const controller = getElementByXpath(`${postRowXPath}/td[1]/div/nobr/span/span`);
  116.         if (isQuaratineTarget(layerIdMap, controller)) {
  117.             quarantined.push(row);
  118.         }
  119.     }
  120.  
  121.     quarantined.forEach(it => it.remove());
  122. }
  123.  
  124. function removeReplies(layerIdMap, replyXpathOffset, replyDomOffset) {
  125.     const quarantined = [];
  126.     const REGEX_REPLY_ID = /re[0-9]+/;
  127.     const contents = getElementByXpath(XPATH_CONTENT_WITH_REPLIES).children;
  128.  
  129.     for (let i = 0; i < contents.length; i++) {
  130.         const row = contents[i];
  131.         const id = row.id;
  132.         if (id == null || id.length === 0 || !id.match(REGEX_REPLY_ID)) {
  133.             continue;
  134.         }
  135.  
  136.         const domIndex = i - replyDomOffset;
  137.         const replyIndex = replyXpathOffset + domIndex
  138.         const controller = getElementByXpath(`/html/body/div[2]/div[2]/table[${replyIndex}]/tbody/tr[1]/td[2]/span/span[1]/b/span`);
  139.         if (isQuaratineTarget(layerIdMap, controller)) {
  140.             quarantined.push(row);
  141.         }
  142.     }
  143.  
  144.     quarantined.forEach(it => it.remove());
  145. }
  146.  
  147. function isQuaratineTarget(layerIdMap, controller) {
  148.     const [memberId, name] = getMemberInfo(layerIdMap, controller);
  149.     if (memberId == null || userMatrix[memberId] == null) {
  150.         return false;
  151.     }
  152.  
  153.     console.debug(`게시물 숨김 대상: ${memberId} = '${name}', 메모: ${userMatrix[memberId]})`);
  154.     return true;
  155. }
  156.  
  157. function getMemberInfo(layerIdMap, zbActionControl) {
  158.     // 컨트롤러 레이아웃 id인 #zbLayer[0-9]+ 패턴 찾기: Capturing group #2
  159.     const REGEX_ZB_LAYER_INVOKE_FUNC = /ZB_layerAction\(['"](zbLayer[0-9]+)['"].*\)/;
  160.  
  161.     const action = zbActionControl.getAttribute("onmousedown");
  162.     if (action == null) {
  163.         return [];
  164.     }
  165.  
  166.     const result = action.match(REGEX_ZB_LAYER_INVOKE_FUNC);
  167.     if (result == null || result.length <= 1) {
  168.         return [];
  169.     }
  170.  
  171.     const zbLayerId = result[1];
  172.     const memberId = layerIdMap[zbLayerId];
  173.     if (memberId == null) {
  174.         return [null, ""];
  175.     } else {
  176.         const name = zbActionControl.firstChild.textContent;
  177.         return [memberId, name];
  178.     }
  179. }
  180.  
  181. // 프로그램 진입점
  182. main();
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement