Advertisement
AHOHNMYC

0chan custom search

Apr 23rd, 2017
180
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
  1. // ==UserScript==
  2. // @name        0chan custom search
  3. // @name:ru     Поиск по тредам
  4. // @namespace   0ch usability
  5. // @author      AHOHNMYC
  6. // @description Скрипт схороняет ОП-посты в дазу банных и великодушно позволяет вам проводить по ней поиск
  7. // @homepage    https://pastebin.com/u/AHOHNMYC
  8. // @include     https://0chan.hk/*
  9. // @grant       GM_getValue
  10. // @grant       GM_setValue
  11. // @grant       GM_listValues
  12. // @grant       GM_deleteValue
  13. // @grant       unsafeWindow
  14. // @grant       GM_registerMenuCommand
  15. // @supportURL  https://0chan.hk/0x59f3c84d
  16. // @version     v0.0.1
  17. // ==/UserScript==
  18.  
  19. const debug = false;
  20.  
  21. // refreshContentDone -> addOPpostToBase -> ls.add -> GM_setValue
  22.  
  23. ///////////////////////////////////////////////////////////////
  24. // АПИ для работы с хранилищем
  25. const ls = {
  26.   _lastSearch: '',
  27.   _contextLength: 200,
  28.  
  29.   add: function(obj) {
  30.     if ( !obj ) return;
  31.     if ( obj.content == ' ' ) {
  32.       if (debug) console.log('0chan custom search: OP-post is empty. Thread will not be added in DB');
  33.       return;
  34.     }
  35.     let id = obj.board+' '+obj.postId;
  36.     if ( GM_getValue(id) ) {
  37.       if (debug) console.log('0chan custom search: ID:"%s %s" was already added', obj.board, obj. postId);
  38.       return;
  39.     }
  40.     GM_setValue(id, obj.content);
  41.     if (debug) console.log('0chan custom search: thread added to database. ID:"%s %s" DB contains %d elements', obj.board, obj. postId, GM_listValues().length);
  42.   },
  43.  
  44.   search: function(text, board) {
  45.     text = text.toLowerCase().replace(/[^ A-яё]/g,'');
  46.     ls._lastSearch = text.split(' ')[0];
  47.     if ( !board ) board = '[^ ]+';
  48.     let keywords = text.split(' '),
  49.         regex = new RegExp('^'+board+' ', 'i'),
  50.         threads = [];
  51.     GM_listValues().forEach(e=>{
  52.       if ( !regex.test(e) ) return;
  53.       for (let i=0; i<keywords.length; i++) {
  54.         if ( GM_getValue(e).search(new RegExp(keywords[i], 'i') ) == -1 ) return;
  55.       }
  56.       threads.push(e);
  57.     });
  58.     return threads;
  59.   },
  60.  
  61.   searchWithContext: function (text, board) {
  62.     return ls.search(text, board).map(e=>{return{
  63.       postId: e,
  64.       context: ls._getContext(e)
  65.     };}, ls);
  66.   },
  67.  
  68.   _getContext: function(id) {
  69.     let pos = GM_getValue(id).search(ls._lastSearch),
  70.         start = (pos < ls._contextLength/2) ? 0 : pos-ls._contextLength/2;
  71. //     console.log(ls._lastSearch+' '+id+' '+pos+' '+start);
  72. //     console.log( start +' '+ start+retLen );
  73.     return '...'+ GM_getValue(id).slice(start, start+ls._contextLength).replace(/\n/g, ' ') +'...';
  74.   },
  75.  
  76.   _clear: function() {
  77.     GM_listValues().forEach( GM_deleteValue );
  78.   }
  79. };
  80. // Конец АПИ для работы с хранилищем
  81. ///////////////////////////////////////////////////////////////
  82. // Вспомогательные функции
  83. function addOPpostToBase(oppost) {
  84.   // Пост может быть свёрнут
  85.   if ( !oppost.querySelector('.post-body-message') ) return false;
  86.   let meta    = oppost.querySelector('.post-header > span > span+a').href.split('/'),
  87.       message = oppost.querySelector('.post-body-message'),
  88.       entry   = {
  89.         board:   meta[3],
  90.         postId: +meta[4],
  91.         content: message.textContent
  92.       };
  93.   ls.add( entry );
  94. }
  95. // Конец вспомогательных функций
  96. ///////////////////////////////////////////////////////////////
  97. // Cобытиеёбля
  98.  
  99. // !!!!!!!!!!!!
  100. // ls._clear();
  101. // !!!!!!!!!!!!
  102.  
  103. // Some modified parts form Kagami's Шебм script
  104. unsafeWindow._searchIndexer = (typeof exportFunction === 'undefined') ? handleThreads : exportFunction(handleThreads, unsafeWindow);
  105. (function(){
  106.   let observer = new MutationObserver(function() {
  107.     let app = unsafeWindow.app;
  108.     if (!app.$bus) return;
  109.     observer.disconnect();
  110.     app.$bus.on('refreshContentDone', unsafeWindow._searchIndexer);
  111.   });
  112.   observer.observe(document.body, {childList: true});
  113. })();
  114.  
  115. function handleThreads() {
  116.   let thread  = document.querySelector('.threads');
  117.   if (!thread) return;
  118.   addOPpostToBase( thread.querySelector('.post-op') );
  119. }
  120. // Конец событиеебли
  121. ///////////////////////////////////////////////////////////////
  122. // Взаимодействие с пользователем
  123.  
  124. ////////////////////////
  125. // Регистрируем элемент в менюшке. Не хочу я влезать в нутро этой one-page хуйни
  126. function searchTextFromMenu(){
  127. //   console.log( 'Database contains %d elements', GM_listValues().length );
  128.   let txt   = prompt('Что искать?'),
  129. //       board = prompt('Где искать? (название борды. Напр "b")');
  130.       board = false;
  131.   let result = ls.searchWithContext(txt, board);
  132.   result.forEach( e=>{console.log(e);}  );
  133. //   alert( result );
  134. }
  135. GM_registerMenuCommand('Искать', searchTextFromMenu, 'И');
  136. ////////////////////////
  137.  
  138. // Конец взаимодействия с пользователем
  139. ///////////////////////////////////////////////////////////////
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement