Arca base64 autodecoder

Arca.live Base64 auto decoder

当前为 2023-12-20 提交的版本,查看 最新版本

  1. // ==UserScript==
  2. // @name Arca base64 autodecoder
  3. // @name:ko 아카라이브 Base64 자동 디코더
  4. // @version 1.20
  5. // @author Laria
  6. // @match https://arca.live/b/*/*
  7. // @description Arca.live Base64 auto decoder
  8. // @description:ko 아카라이브 Base64 자동 복호화 스크립트
  9. // @icon https://www.google.com/s2/favicons?sz=64&domain=arca.live
  10. // @license MIT
  11. // @encoding utf-8
  12. // @run-at document-end
  13. // @supportURL https://greasyfork.org/ko/scripts/482577-arca-base64-autodecoder
  14. // @namespace https://greasyfork.org/users/1235854
  15. // @grant GM.getValue
  16. // @grant GM.setValue
  17. // @grant GM.registerMenuCommand
  18. // @grant GM.unregisterMenuCommand
  19. // ==/UserScript==
  20.  
  21. /*
  22. * == Change log ==
  23. * 1.0 - Release
  24. * 1.1 - Invalid character update (replace -> replaceAll)
  25. * 1.11 - Improved show multiple links
  26. * 1.12 - Show Single links Bugfix
  27. * 1.13 - Bugfix 1.12
  28. * 1.14 - Base64 add padding func
  29. * 1.15 - Add annotation, display improvements
  30. * 1.16 - Display improved - CSS applied
  31. * 1.17 - var safe, max_iter defined (~7, def:3)
  32. * 1.18 - auto update check, log system
  33. * 1.20 - add menu(base64 depth, user-drag auto decoding, hide encoded link, update notify)
  34. */
  35.  
  36. //base64 encoded(http:/*, https:/*) string prefix
  37. const regArr = [
  38. /(aHR0cDovL|aHR0cHM6Ly)(\w|=|\+|\/)*(?=[^\+=\w\/])/g, //encoding 1 time
  39. /(YUhSMGNEb3ZM|YUhSMGNITTZMe)(\w|=|\+|\/)*(?=[^\+=\w\/])/g, //encoding 2 time
  40. /(WVVoU01HTkViM1pN|WVVoU01HTklUVFpNZ)(\w|=|\+|\/)*(?=[^\+=\w\/])/g, //encoding 3 time
  41. /(V1ZWb1UwMUhUa1ZpTTFwT|V1ZWb1UwMUhUa2xVVkZwTl)(\w|=|\+|\/)*(?=[^\+=\w\/])/g, //encoding 4 time
  42. /(VjFaV2IxVXdNVWhVYTFacFRURndU|VjFaV2IxVXdNVWhVYTJ4VlZrWndUb)(\w|=|\+|\/)*(?=[^\+=\w\/])/g, //encoding 5 time
  43. /(VmpGYVYySXhWWGROVldoVllURmFjRlJVUm5kV|VmpGYVYySXhWWGROVldoVllUSjRWbFpyV25kVW)(\w|=|\+|\/)*(?=[^\+=\w\/])/g, //encoding 6 time
  44. /(Vm1wR1lWWXlTWGhXV0dST1ZsZG9WbGxVUm1GalJsSlZVbTVrV|Vm1wR1lWWXlTWGhXV0dST1ZsZG9WbGxVU2pSV2JGcHlWMjVrVl)(\w|=|\+|\/)*(?=[^\+=\w\/])/g, //encoding 7 time
  45. ];
  46.  
  47. //regex prefix - drag
  48. const regInvalid = /[^\w\+\/=]/;
  49.  
  50. //update chk
  51. let updateAvailble = true;
  52.  
  53. let draggableActivated = false;
  54.  
  55. //encoded link list, [uuid]: [encoded link]
  56. let encodedList = {};
  57.  
  58. //total decode count
  59. let hindex = 0;
  60.  
  61. //drag function comparison
  62. let lastSelected = document;
  63. let lastSelectedTime = Date.now();
  64.  
  65. //logging prefix, param
  66. const sc_name = '['+GM.info.script.name+']';
  67. const sc_name_upd = '['+GM.info.script.name+'-UPD]';
  68. const sc_ver = GM.info.script.version;
  69.  
  70. let localParameter = {
  71. 'basedepth': {
  72. 'param_name': 'basedepth',
  73. 'name': 'base64 깊이 조절하기 - 현재 값 : 알수없음',
  74. 'desc': '자동 base64 디코딩 깊이를 조절할 수 있습니다.',
  75. 'id': -1,
  76. 'func': menucmd_f_depth,
  77. 'value': 3,
  78. },
  79. 'enclinkhide': {
  80. 'param_name': 'enclinkhide',
  81. 'name': '인코딩된 링크 보이기',
  82. 'desc': '자동 base64 디코딩 전 인코딩된 링크 표시 여부를 설정할 수 있습니다.',
  83. 'id': -1,
  84. 'func': menucmd_f_enchide,
  85. 'value': false,
  86. },
  87. 'draggable': {
  88. 'param_name': 'draggable',
  89. 'name': '드래그 시 자동 디코딩 켜기',
  90. 'desc': '드래그 시 자동으로 base64로 디코딩할지 설정할 수 있습니다.',
  91. 'id': -1,
  92. 'func': menucmd_f_drag,
  93. 'value': false,
  94. },
  95. 'updatechk': {
  96. 'param_name': 'chkupd',
  97. 'name': '업데이트 알림 끄기',
  98. 'desc': '새 버전이 나올 시 업데이트 확인 알림을 띄울지 여부를 설정할 수 있습니다.',
  99. 'id': -1,
  100. 'func': menucmd_f_updchk,
  101. 'value': true,
  102. },
  103. };
  104.  
  105. //auto add padding - add '=' padding in base64 encoded string
  106. function base64AddPadding(str) {
  107. return str + Array((4 - str.length % 4) % 4 + 1).join('=');
  108. }
  109.  
  110. //base64 decode
  111. const Base64 = {
  112. _keyStr : "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=",
  113. decode : function (input) {
  114. let output = "";
  115. let chr1, chr2, chr3;
  116. let enc1, enc2, enc3, enc4;
  117. let i = 0;
  118.  
  119. input = input.replace(/[^A-Za-z0-9\+\/\=]/g, "");
  120.  
  121. while (i < input.length) {
  122. enc1 = this._keyStr.indexOf(input.charAt(i++));
  123. enc2 = this._keyStr.indexOf(input.charAt(i++));
  124. enc3 = this._keyStr.indexOf(input.charAt(i++));
  125. enc4 = this._keyStr.indexOf(input.charAt(i++));
  126.  
  127. chr1 = (enc1 << 2) | (enc2 >> 4);
  128. chr2 = ((enc2 & 15) << 4) | (enc3 >> 2);
  129. chr3 = ((enc3 & 3) << 6) | enc4;
  130.  
  131. //last bits
  132. output = output + String.fromCharCode(chr1);
  133. if (enc3 != 64) { //=
  134. output = output + String.fromCharCode(chr2);
  135. }
  136. if (enc4 != 64) { //==
  137. output = output + String.fromCharCode(chr3);
  138. }
  139. }
  140.  
  141. output = Base64._utf8_decode(output);
  142. return output;
  143. },
  144. // private method for UTF-8 decoding
  145. _utf8_decode : function (utftext) {
  146. let string = "";
  147. let i = 0;
  148. let c = 0;
  149. let c1 = 0;
  150. let c2 = 0;
  151. let c3 = 0;
  152.  
  153. while ( i < utftext.length ) {
  154. c = utftext.charCodeAt(i);
  155. if (c < 128) {
  156. string += String.fromCharCode(c);
  157. i++;
  158. }
  159. else if((c > 191) && (c < 224)) {
  160. c2 = utftext.charCodeAt(i+1);
  161. string += String.fromCharCode(((c & 31) << 6) | (c2 & 63));
  162. i += 2;
  163. }
  164. else {
  165. c2 = utftext.charCodeAt(i+1);
  166. c3 = utftext.charCodeAt(i+2);
  167. string += String.fromCharCode(((c & 15) << 12) | ((c2 & 63) << 6) | (c3 & 63));
  168. i += 3;
  169. }
  170. }
  171. return string;
  172. }
  173. };
  174.  
  175. //encoded link click callback
  176. function showEncodedLink(id) {
  177. //check already clicked
  178. if (encodedList.hasOwnProperty(id)) {
  179. console.log(sc_name,'show encoded link -',encodedList[id]);
  180. const self = document.getElementById(id);
  181. self.innerHTML = encodedList[id];
  182. self.style.color = 'rgb(71 88 188)';
  183. delete encodedList[id];
  184. }
  185. return;
  186. }
  187.  
  188. //link area
  189. function createLinkArea(src) {
  190. return '<span style="font-size: 87.5%;color: rgb(71 188 115);">[ ' + src.toString() + ' ]</span>';
  191. }
  192.  
  193. //encoded link element
  194. function createEncElem(src) {
  195. const uuid = 'abad_'+self.crypto.randomUUID();
  196. encodedList[uuid] = src;
  197. return '<span id="' + uuid.toString() + '">' + '클릭 시 인코딩된 코드 보기' + '</span>';
  198. }
  199.  
  200. //link creation
  201. function createLink(src, index, url, depth, hidelink = false) {
  202. //n번째 링크 (base64 깊이: 0) [ ABCDEF= / 클릭시 원본~ ]
  203. return '<a href="'+url+'" title="'+url+' (새 창으로 열기)" target="_blank" rel="external nofollow noopener noreferrer">'+index.toString()+'번째 링크 (base64 깊이: '+depth.toString()+')</a> '+(hidelink?createLinkArea(createEncElem(src)):createLinkArea(src))+'';
  204. }
  205.  
  206. //decode & generate
  207. function replacerGen(numIter) {
  208. return function(source) {
  209. try {
  210. let rstring = ""; //return msg
  211. console.log('\n'+sc_name,'No.',(hindex+1).toString(),'encoded link:\n', source.toString()); //source
  212.  
  213. //decode
  214. let converted = Base64.decode(base64AddPadding(source));
  215. //attempt to decode nested base64 encoded string
  216. for(let i=0; i<numIter; i++) {
  217. converted = Base64.decode(base64AddPadding(converted));
  218. }
  219. hindex++;
  220.  
  221. //remove invalid string - �
  222. converted = decodeURI(encodeURI(converted).replaceAll('%00', ''));
  223. console.log(sc_name,'No.',hindex.toString(),'decode completed:\n',converted.toString()); //converted
  224.  
  225. //split by new line
  226. converted = converted.split(/\r?\n/);
  227. //single component
  228. if (converted.length == 2 && converted[converted.length-1] == '') {
  229. rstring += createLink(source, hindex, converted[0], numIter+1, !localParameter['enclinkhide']['value']);
  230. //multiple component
  231. } else if (converted.length > 1) {
  232. rstring += createLinkArea(localParameter['enclinkhide']['value']?source.toString():createEncElem(source.toString()));
  233.  
  234. let nindex = 1;
  235. converted.forEach(function(i) {
  236. if (i != '') {
  237. rstring += '<br>' + createLink('<span style="color: rgb(71 188 115);">링크 자동 분할 : '+nindex.toString()+'번째</span>', hindex, i, numIter+1);
  238. hindex++;
  239. nindex++;
  240. }
  241. });
  242. //apply last components
  243. hindex--;
  244. nindex--;
  245.  
  246. console.log(sc_name,'No.',hindex.toString(),'- splitted total :', nindex.toString());
  247. rstring = '<span style="color: rgb(232 62 140);"><b><i>분할된 링크 총 '+nindex.toString()+'개</i></b></span> ' + rstring;
  248. } else rstring += createLink(source, hindex, converted, numIter+1, !localParameter['enclinkhide']['value']);
  249. return rstring;
  250. } catch(e) {
  251. console.warn('\n'+sc_name,'error occured during decoding:', e);
  252. console.warn(sc_name,'base64 decode fail:', source.toString());
  253. }
  254. return '<span style="color: rgb(255 0 0);">[ base64 변환 실패: '+source.toString()+' ]</span>';
  255. };
  256. }
  257.  
  258. //user drag event
  259. function selClicked(event) {
  260. const sel = document.getSelection().toString();
  261. if (!sel.match(regInvalid) && sel.length >= 10 && lastSelectedTime + 200 < Date.now()) {
  262. try {
  263. console.log(sc_name,'live match -',sel.toString());
  264. let converted = decodeURI(encodeURI(Base64.decode(base64AddPadding(sel))).replaceAll('%00', ''));
  265. console.log(sc_name,'converted -',converted.toString());
  266. this.innerHTML = this.innerHTML.replace(sel, converted);
  267. } catch (e) {
  268. return;
  269. } finally {
  270. this.removeEventListener('click', selClicked);
  271. }
  272. }
  273. }
  274.  
  275. //user drag activate
  276. function activateDragDecoding() {
  277. if(draggableActivated) {
  278. console.log(sc_name,'USR-Drag already enabled.');
  279. return;
  280. }
  281. draggableActivated = true;
  282. console.log(sc_name,'USR-Drag enabled.');
  283. document.addEventListener('selectionchange', function() {
  284. let sel = document.getSelection().anchorNode;
  285. if(sel) {
  286. sel = sel.parentElement;
  287. if(sel != lastSelected) {
  288. lastSelected.removeEventListener('click', selClicked);
  289. sel.addEventListener('click', selClicked);
  290. lastSelected = sel;
  291. lastSelectedTime = Date.now();
  292. }
  293. }
  294. });
  295. }
  296.  
  297. //update check
  298. function checkForUpdate(){
  299. if (!updateAvailble || !localParameter['updatechk']['value']) {
  300. console.log(sc_name_upd,'updchk skipped.');
  301. return;
  302. }
  303. console.log(sc_name_upd,'checking for update...');
  304. const tar_sc = 'https://update.greasyfork.org/scripts/482577/Arca%20base64%20autodecoder.user.js';
  305. fetch(tar_sc)
  306. .then(response => response.text())
  307. .then(data => {
  308. //extract version from greaskyfork script
  309. const match = data.match(/@version\s+(\d+\.\d+)/);
  310. if (match) {
  311. const tar_version = parseFloat(match[1]);
  312. const cur_version = parseFloat(sc_ver);
  313. //new version detected
  314. if (tar_version > cur_version) {
  315. console.log(sc_name_upd,'new version available. ('+cur_version+' -> '+tar_version+')');
  316. //y/n dialog
  317. if (window.confirm(sc_name+'\n새로운 버전이 감지되었습니다. 업데이트를 권장합니다.\n( 기존버전 : '+cur_version+', 새로운 버전 : '+tar_version+' )\n\n취소를 누르면 앞으로 업데이트 알림을 띄우지 않습니다.')) {
  318. //get extension env
  319. if(!GM.info.scriptWillUpdate) {
  320. console.log(sc_name_upd,'extension not allowed auto update..');
  321. if (window.confirm(sc_name+'\n주의! 스크립트 내용 변경 등으로 인해 자동 업데이트가 꺼져있는 것 같습니다.\n업데이트 시 기존 스크립트에 덮어쓰게 되어 기존 내용이 손실될 수 있습니다.\n이 점 확인 후 업데이트 바랍니다.\n\n(계속하려면 확인, 취소하려면 취소를 눌러주세요.)')) {
  322. console.log(sc_name_upd,'opening source url..');
  323. window.location.replace(tar_sc);
  324. } else {
  325. console.log(sc_name_upd,"user canceled.");
  326. }
  327. } else {
  328. console.log(sc_name_upd,'opening source url..');
  329. window.location.replace(tar_sc);
  330. }
  331. } else {
  332. console.log(sc_name_upd,'updatechk change',true.toString(),'to',false.toString());
  333. localParameter['updatechk']['value'] = false;
  334. try {
  335. GM.setValue('chkupd', false);
  336. console.log(sc_name_upd,"updatechk change successful");
  337. window.alert(sc_name+'\n앞으로 업데이트 알림을 띄우지 않습니다.');
  338. menucmd_update();
  339. } catch(e) {
  340. localParameter['updatechk']['value'] = true;
  341. console.error(sc_name_upd,"updatechk change fail -", e);
  342. window.alert(sc_name+'\n파라미터 변경 중 문제 발생, 로그를 확인해주세요..');
  343. }
  344. }
  345. } else {
  346. console.log(sc_name_upd,'latest version', cur_version, 'detected. (eth:',tar_version,')');
  347. }
  348. } else {
  349. console.error(sc_name_upd,'unable to extract version..');
  350. }
  351. })
  352. .catch(error => {
  353. updateAvailble = false;
  354. console.error(sc_name_upd,'link unreachable.. -', error);
  355. });
  356. updateAvailble = false;
  357. }
  358.  
  359. function menucmd_update(fist_run = false) {
  360. //pre process
  361. localParameter['basedepth']['value'] = localParameter['basedepth']['value'] > regArr.length ? regArr.length : localParameter['basedepth']['value'];
  362.  
  363. //update menu name
  364. localParameter['basedepth']['name'] = 'base64 깊이 조절하기 - 현재 값 : '+localParameter['basedepth']['value']+'회';
  365. localParameter['enclinkhide']['name'] = '인코딩된 링크 '+(localParameter['enclinkhide']['value']?'숨기기':'보이기');
  366. localParameter['draggable']['name'] = '드래그 시 자동 디코딩 '+(localParameter['draggable']['value']?'끄기':'켜기');
  367. localParameter['updatechk']['name'] = '업데이트 알림 '+(localParameter['updatechk']['value']?'끄기':'켜기');
  368.  
  369. //remove exist menu cmd
  370. if (!fist_run) {
  371. Object.keys(localParameter).forEach(function(i){
  372. try {
  373. GM.unregisterMenuCommand(localParameter[i]['id']);
  374. } catch(_) {}
  375. });
  376. }
  377. //monkey menu cmd register
  378. try {
  379. Object.keys(localParameter).forEach(function(i){
  380. localParameter[i]['id'] = GM.registerMenuCommand(localParameter[i]['name'], localParameter[i]['func'], {title:localParameter[i]['desc']});
  381. });
  382. console.log(sc_name,'sc cmd',(fist_run?'registered':'reloaded'));
  383. } catch(e) {
  384. console.error(sc_name,'err - sc cmd',(fist_run?'register':'reload'),'- ', e);
  385. Object.keys(localParameter).forEach(function(i){
  386. try {
  387. GM.unregisterMenuCommand(localParameter[i]['id']);
  388. } catch(_) {}
  389. });
  390. }
  391. }
  392.  
  393. function menucmd_f_depth() {
  394. menucmd_update();
  395. const prev_value = localParameter['basedepth']['value'];
  396. const str_common_1 = ' ( 지정 가능한 범위: 1~'+regArr.length.toString()+' )';
  397. while(true) {
  398. const input = window.prompt(sc_name+'\nBase64 자동 디코딩 중첩 횟수를 얼마로 지정할까요?\n(인코딩을 인코딩한 것을 여러번 반복한걸 자동으로 풀어냅니다.)\n현재 값: '+prev_value.toString()+'회,'+(prev_value == 3 ? '' : ' 기본값: 3회,')+str_common_1+'\n\n(값을 너무 크게 지정하면 컴퓨터 성능에 영향을 줄 수 있습니다.)', prev_value);
  399. if (input == null) {
  400. console.log(sc_name,'basedepth change canceled.');
  401. break;
  402. }
  403. if(!isNaN(input)){
  404. const tar_value = parseInt(input);
  405. if(tar_value == prev_value) {
  406. window.alert(sc_name+'\n동일한 값을 입력했습니다, 현재 값: '+prev_value+'회');
  407. } else if(tar_value >= 1 && tar_value <= regArr.length) {
  408. console.log(sc_name,'basedepth change',prev_value.toString(),'to',tar_value.toString());
  409. localParameter['basedepth']['value'] = tar_value;
  410. try {
  411. GM.setValue('basedepth', tar_value);
  412. menucmd_update();
  413. console.log(sc_name,"basedepth change successful");
  414. window.alert(sc_name+'\n값이 '+prev_value.toString()+'에서 '+tar_value.toString()+'으로 변경이 완료되었습니다.\n\n(사이트를 새로고침해야 반영됩니다.)');
  415. } catch(e) {
  416. localParameter['basedepth']['value'] = prev_value;
  417. console.error(sc_name,"basedepth change fail -", e);
  418. window.alert(sc_name+'\n파라미터 변경 중 문제 발생, 로그를 확인해주세요..');
  419. }
  420. break;
  421. } else {
  422. window.alert(sc_name+'\n'+tar_value+'(으)로 설정할 수 없습니다.\n범위를 초과하였습니다..'+str_common_1);
  423. }
  424. } else {
  425. window.alert(sc_name+'\n'+input+'은(는)숫자가 아닙니다.\n숫자만 입력해주세요..'+str_common_1);
  426. }
  427. }
  428. menucmd_update();
  429. }
  430.  
  431. function menucmd_f_enchide() {
  432. menucmd_update();
  433. const curr_state = localParameter['enclinkhide']['value'];
  434. if(window.confirm(sc_name+'\n디코딩 시 인코딩된 링크를 '+(curr_state?'숨기시':'표시하')+'겠습니까?\n\n(앞으로 디코딩 전 인코딩된 링크를\n"'+(curr_state?'클릭 시 기존링크 보기':'aHR0cHM6Ly9hcmNhLmx..')+'"와 같은 형태로 보여줍니다.)')) {
  435. const set_state = !curr_state;
  436. console.log(sc_name,'enchide change',curr_state.toString(),'to',set_state.toString());
  437. localParameter['enclinkhide']['value'] = set_state;
  438. try {
  439. GM.setValue('enclinkhide', set_state);
  440. menucmd_update();
  441. console.log(sc_name,"updatechk change successful");
  442. if(set_state) {
  443. window.alert(sc_name+'\n앞으로 인코딩된 링크를 표시합니다.\n\n(새로고침해야 적용됩니다.)');
  444. } else {
  445. window.alert(sc_name+'\n앞으로 인코딩된 링크를 숨깁니다.');
  446. }
  447. } catch(e) {
  448. localParameter['enclinkhide']['value'] = curr_state;
  449. console.error(sc_name,"enchide change fail -", e);
  450. window.alert(sc_name+'\n파라미터 변경 중 문제 발생, 로그를 확인해주세요..');
  451. }
  452. } else {
  453. console.log(sc_name,'enchide change canceled.');
  454. }
  455. menucmd_update();
  456. }
  457.  
  458. function menucmd_f_drag() {
  459. menucmd_update();
  460. const curr_state = localParameter['draggable']['value'];
  461. if(window.confirm(sc_name+'\n드래그 시 자동 디코딩을 '+(curr_state?'비':'')+'활성화 하시겠습니까?\n\n(앞으로 인코딩된 부분을 드래그'+(curr_state?'해도 자동으로 디코딩되지 않습':' 시 Base64로 인코딩된것으로\n판단 되면 자동으로 디코딩을 시도합')+'"니다.)')) {
  462. const set_state = !curr_state;
  463. console.log(sc_name,'draggable change',curr_state.toString(),'to',set_state.toString());
  464. localParameter['draggable']['value'] = set_state;
  465. try {
  466. GM.setValue('draggable', set_state);
  467. menucmd_update();
  468. console.log(sc_name,"draggable change successful");
  469. if(set_state) {
  470. try {
  471. activateDragDecoding();
  472. window.alert(sc_name+'\n앞으로 드래그 시 자동 디코딩을 진행합니다.');
  473. } catch(e) {
  474. console.error(sc_name,"draggable activate fail -", e);
  475. window.alert(sc_name+'\n드래그 시 자동 디코딩 활성화 중 문제가 발생했습니다.\n새로고침이 필요합니다..');
  476. }
  477. } else {
  478. window.alert(sc_name+'\n앞으로 드래그 해도 반응하지 않습니다.\n\n(새로고침해야 적용됩니다.)');
  479. }
  480. } catch(e) {
  481. localParameter['draggable']['value'] = curr_state;
  482. console.error(sc_name,"draggable change fail -", e);
  483. window.alert(sc_name+'\n파라미터 변경 중 문제 발생, 로그를 확인해주세요..');
  484. }
  485. } else {
  486. console.log(sc_name,'draggable change canceled.');
  487. }
  488. menucmd_update();
  489. }
  490.  
  491. function menucmd_f_updchk() {
  492. menucmd_update();
  493. const curr_state = localParameter['updatechk']['value'];
  494. if(window.confirm(sc_name+'\n업데이트 알림을 '+(curr_state?'끄':'켜')+'시겠습니까?\n\n(앞으로 업데이트가 있'+(curr_state?'어도 알려주지 않습':'으면 자동으로 알려줍')+'니다.)')) {
  495. const set_state = !curr_state;
  496. console.log(sc_name,'updatechk change',curr_state.toString(),'to',set_state.toString());
  497. localParameter['updatechk']['value'] = set_state;
  498. try {
  499. GM.setValue('chkupd', set_state);
  500. console.log(sc_name,"updatechk change successful");
  501. if(set_state) {
  502. window.alert(sc_name+'\n앞으로 업데이트가 존재하면 알림을 띄웁니다.');
  503. checkForUpdate();
  504. } else {
  505. window.alert(sc_name+'\n앞으로 업데이트 알림을 띄우지 않습니다.');
  506. }
  507. } catch(e) {
  508. localParameter['updatechk']['value'] = curr_state;
  509. console.error(sc_name,"updatechk change fail -", e);
  510. window.alert(sc_name+'\n파라미터 변경 중 문제 발생, 로그를 확인해주세요..');
  511. }
  512. } else {
  513. console.log(sc_name,'updatechk change canceled.');
  514. }
  515. menucmd_update();
  516. }
  517.  
  518. //main
  519. (async () => {
  520. 'use strict';
  521.  
  522. //chk browser env
  523. if (((navigator.language || navigator.userLanguage) != 'ko-KR')) console.warn('Warning! this script support only korean language..');
  524.  
  525. console.log(sc_name,'V',sc_ver,'enabled');
  526.  
  527. //load parameter
  528. try {
  529. for (const i of Object.keys(localParameter)) {
  530. localParameter[i]['value'] = await GM.getValue(localParameter[i]['param_name'], localParameter[i]['value']);
  531. }
  532. } catch(e) {
  533. console.error(sc_name,'err - get sc parameter - ', e);
  534. }
  535.  
  536. //apply parameter and register monkey menu command
  537. menucmd_update(true);
  538.  
  539. //chk update
  540. await checkForUpdate();
  541.  
  542. //drag auto decoding
  543. if (localParameter['draggable']['value']) {
  544. activateDragDecoding();
  545. }
  546.  
  547. console.log(sc_name,'ready');
  548. //main procedure
  549.  
  550. //article
  551. let article = document.getElementsByClassName("article-content")[0];
  552. for(let i=0; i<localParameter['basedepth']['value']; i++) {
  553. article.innerHTML = article.innerHTML.replaceAll(regArr[i], replacerGen(i));
  554. }
  555.  
  556. //comment
  557. let comments = document.getElementsByClassName("list-area");
  558. if (comments.length != 0) {
  559. for(let i=0; i<localParameter['basedepth']['value']; i++) {
  560. comments[0].innerHTML = comments[0].innerHTML.replaceAll(regArr[i], replacerGen(i));
  561. }
  562. }
  563. console.log(sc_name,'total',hindex.toString(),'decode task completed.');
  564.  
  565. //add eventlistner - click, show original encoded link
  566. if (!localParameter['enclinkhide']['value']) {
  567. Object.keys(encodedList).forEach(function(i) {
  568. document.getElementById(i).addEventListener('click', () => {showEncodedLink(i);});
  569. });
  570. }
  571. })();