E-Hentai Grep

Searches forum posts for lines that match given string patterns

目前为 2015-12-06 提交的版本。查看 最新版本

  1. // ==UserScript==
  2. // @name E-Hentai Grep
  3. // @description Searches forum posts for lines that match given string patterns
  4. // @include http://forums.e-hentai.org/index.php?*showtopic=*
  5. // @version 0.0.1.20151206103009
  6. // @namespace https://greasyfork.org/users/2233
  7. // ==/UserScript==
  8.  
  9. /*** Settings ***/
  10.  
  11. var default_on = true
  12. var hotkey = 71 // http://www.cambiaresearch.com/articles/15/javascript-char-codes-key-codes
  13. var max_length = 60
  14. var display_title_and_poster = false
  15. var remove_stockout_line = true
  16. var remove_strike_through_line = true
  17. var remove_quoted_text = true
  18. if(typeof result_box_position == 'undefined') {
  19. var result_box_position = 'center' // where to show the result box ("left", "center" or "right")
  20. }
  21. var blacklist = [
  22. '22234', // Ask the Experts
  23. '163637', // The Shared Free Shop
  24. '169987',
  25. '170830',
  26. ]
  27. if(typeof grep_patterns == 'undefined') {
  28. var grep_patterns = [ // Add [[pattern_1, pattern_2, ... , pattern_n], 'color'] to the array by yourself.
  29. [ // Items
  30. [
  31. // Rare materials
  32. /(((^|\s)\b)|x)phazon/i,
  33. // Bindings for staff
  34. ///(((^|\s)\b)|x)binding.*(slaughter|destruction|focus|friendship|heimdall|fenrir|heaven-sent|demon-fiend|curse-weaver|earth-walker|fox|owl)/i,
  35. ///^\s*(slaughter|destruction|focus|friendship|heimdall|fenrir|heaven-sent|demon-fiend|curse-weaver|earth-walker|fox|owl)/i,
  36. // Bindings for armor
  37. /(((^|\s)\b)|x)binding.*(destruction|balance|focus|protection|warding|fleet|negation|heimdall|dampening|cheetah|raccoon|fox|owl|heaven-sent)/i,
  38. /^\s*(destruction|balance|focus|protection|warding|fleet|negation|heimdall|dampening|cheetah|raccoon|fox|owl|heaven-sent)/i,
  39. // Graded materials
  40. /(((^|\s)\b)|x)(low|mid|high).*grade.*(cloth|wood)/i,
  41. /(((^|\s)\b)|x)(lg|mg|hg).?(cloth|wood)/i,
  42. /(((^|\s)\b)|x)scrap.*(cloth|wood).*@/i,
  43. /(((^|\s)\b)|x)scrap.*(cloth|wood).*\d *c\b/i,
  44. /(((^|\s)\b)|x)scrap.*(cloth|wood).*\b\d{2}\b/i,
  45. // Catalysts
  46. /(((^|\s)\b)|x)catalyst/i,
  47. // ED & artifact
  48. /(((^|\s)\b)|x)(energy|drink|(artifact|artefact)).*[@0]/i,
  49. /(((^|\s)\b)|x)(energy|drink|(artifact|artefact)).*\d *k\b/i,
  50. /(((^|\s)\b)|x)(energy|drink|(artifact|artefact)).* *\d+/i,
  51. // Shards
  52. /(((^|\s)\b)|x)amnesia/i,
  53. // Potions
  54. /(((^|\s)\b)|x)(health|last).*elixir/i,
  55. /(((^|\s)\b)|x)(mana|spirit).*(potion|elixir)/i,
  56. /(((^|\s)\b)|x)spirit.*draught/i,
  57. // Infusions and Scrolls
  58. /(((^|\s)\b)|x)(infusion|(scroll of))/i,
  59. // Trophies
  60. /(((^|\s)\b)|x)noodl/i,
  61. ///((^|\s)\b)(troph|manbearpig|antioch|mithra|dalek|lock|costume|hinamatsuri|broken|sapling|shirt|unicorn|noodl)/i,
  62. // Monster Foods
  63. /(((^|\s)\b)|x)(crystals?\b|chow|edible|cuisine|pill)/i,
  64. // Misc
  65. /(((^|\s)\b)|x)(vase|bubble)/i,
  66. ], 'purple', ''
  67. ],
  68. [ // Holy
  69. [
  70. /(Peer|Leg).*(Hallowed|Astral).*Katalox.*(Destruction|Heimdall|Heaven-sent)/i,
  71. /(Peer|Leg).*(Hallowed|Astral).*Oak.*Heimdall/i,
  72. /(Peer|Leg).*Radiant.*Heimdall/i,
  73. ], 'darkred', ''
  74. ],
  75. [ // Cotton
  76. [
  77. /(Peer|Leg).*(Charged|Frugal).*(Cotton|Gossamer).*(Heaven-sent|Elementalist|Curse-weaver)/i,
  78. ], 'darkgreen', ''
  79. ],
  80. [ // Hybrid
  81. [
  82. /Leg.*Dagger/i,
  83. /(Peer|Leg).*(Ethereal|Hallowed|Tempestuous).*Waki.*(Nimble|Battlecaster)/i,
  84. /(Peer|Leg).*Buckler.*(Barrier|Battlecaster)/i,
  85. ], 'darkblue', ''
  86. ],
  87. [ // Elemental
  88. [
  89. /*
  90. /(Peer|Leg).*(Tempestuous|Shocking).*Willow.*Destruction/i,
  91. /(Peer|Leg).*(Tempestuous|Shocking|Arctic|Fiery).*(Redwood|Ebony).*(Destruction|Elementalist|Focus)/i,
  92. /(Peer|Leg).*Tempestuous.*(Redwood|Ebony).*Freyr/i,
  93. /(Peer|Leg).*Shocking.*(Redwood|Ebony).*Mjolnir/i,
  94. /(Peer|Leg).*Arctic.*(Redwood|Ebony).*Niflheim/i,
  95. /(Peer|Leg).*Fiery.*(Redwood|Ebony).*Surtr/i,
  96. /(Peer|Leg).*(Radiant|Mystic|Charged|Frugal).*Phase.*(Freyr|Mjolnir|Niflheim|Surtr)/i,
  97. */
  98. /(Peer|Leg).*Tempestuous.*(Willow|Redwood|Ebony).*(Destruction|Elementalist|Focus)/i,
  99. /(Peer|Leg).*Phase.*Freyr/i,
  100. ], 'orange', ''
  101. ],
  102. ]
  103. }
  104.  
  105. /*** End of Settings ***/
  106.  
  107. var wnd = window
  108. var doc = wnd.document
  109. var loc = location
  110. var href = loc.href
  111.  
  112. if(!/&?\bst=[^0]/.test(href)) {
  113. for(var i=0; i<blacklist.length; i++) { if(new RegExp('showtopic=' + blacklist[i] + '\\b').test(href)) { default_on = false } }
  114.  
  115. var $ = function(e, css) { if(!css) { css=e; e=doc }; return e.querySelector(css) }
  116. var $$ = function(e, css) { if(!css) { css=e; e=doc }; return e.querySelectorAll(css) }
  117.  
  118. var stockout = function(line) {
  119. if(!remove_stockout_line) { return false }
  120. var stockout_patterns = [
  121. /[\|\(\[【(:x@]\s*[-0x×\/]+(\D|$)/i,
  122. // /(^|\D)[-0x×\/]+\s*[@×x:)】\]\)\|]/i,
  123. /(^|\D)[-0×\/]+\s*[@×:)】\]\)\|]/i,
  124. /(^|[^,])\b0+\s*[x×]/i,
  125. /(^|\s+)0+\s+/i,
  126. /out of stock/i,
  127. /This post has been edited by/i,
  128.  
  129. // Misc
  130. /\bnot\s+available\b/i,
  131. /\bunavailable\b/i,
  132. /\bnone\b/i,
  133. /\[restocking\]/i,
  134. /-\*0 /i,
  135. /qty=0/i,
  136. /_0_/i,
  137. /^0+ /i,
  138. /\(\/?\)/i,
  139. /\[\/?\]/i,
  140. /【\/?】/i,
  141. /(\/?)/i,
  142. /\[\*\]/i,
  143. ]
  144. for(var i=0, len=stockout_patterns.length; i<len; i++) {
  145. if(stockout_patterns[i].test(line)) {
  146. //console.log(stockout_patterns[i], line)
  147. return true
  148. }
  149. }
  150. return false
  151. }
  152.  
  153. var remove_quotes = function(s) {
  154. var p = [
  155. /<div [^>]*class=.quotetop.>.*?<\/div>/gi,
  156. /<div [^>]*class=.quotemain.>.*?<\/div>/gi,
  157. ]
  158. while(p[0].test(s) || p[1].test(s)) {
  159. s = s.replace(p[0], '')
  160. s = s.replace(p[1], '')
  161. }
  162. return s
  163. }
  164.  
  165. var get_text = function(e) {
  166. var s = e.innerHTML
  167. s = s.replace(/<!--.*?-->/gi, '')
  168. if(remove_quoted_text){ s = remove_quotes(s) }
  169. if(remove_strike_through_line) { s = s.replace(/<strike>.*?<\/strike>/g, '') }
  170. s = s.replace(/<br\s*[^>]*>/g, '\n').replace(/<\/li>/g, '\n').replace(/<ul>/g, '\n').replace(/<\/?blockquote>/g, '\n')
  171. s = s.replace(/<[^>]+>/g, '').replace(/\[(\w+)[^\]]*](.*?)\[\/\1]/g, '')
  172. s = s.replace(/&nbsp;/g, ' ').replace(/&amp;/g, '&')
  173. s = s.replace(/[ \t]+/g, ' ')
  174. //console.log('='.repeat(150)); console.log(s)
  175. return s
  176. }
  177. var out = ''
  178.  
  179. if(result_box_position == 'left') {
  180. var first_post = $('.post2')
  181. var posts = $$('.borderwrap')
  182. for(var i=0, len=posts.length; i<len; i++) {
  183. var poster = $(posts[i], '.bigusername')
  184. if((!poster) || (poster.textContent != $('.bigusername').textContent)) { continue } // skip threads that are not posted by the shop owner
  185.  
  186. var lines = get_text($(posts[i], '.postcolor')).split('\n')
  187. var out = ''
  188. for(var j=0, len2=lines.length; j<len2; j++) {
  189. var line = lines[j]
  190. if(stockout(line)) { continue }
  191. for(var k=0, len3=grep_patterns.length; k<len3; k++) {
  192. for(var m=0, len4=grep_patterns[k][0].length; m<len4; m++) {
  193. if(grep_patterns[k][0][m].test(line)) { out = out + line.substring(0, max_length) + '\n'; break }
  194. }
  195. }
  196. }
  197. if(out) {
  198. if(display_title_and_poster && (/#1/.test($(posts[i], '.postdetails').textContent))) {
  199. var shop_title = $$('.maintitle>table>tbody>tr>td>div')[0].textContent
  200. out = '[Title]\t' + shop_title.substring(0, max_length) + '\n' + '[Poster] ' + poster.textContent.substring(0, max_length)+ '\n\n' + out
  201. }
  202. var d = doc.createElement('DIV')
  203. d.className = 'result'
  204. d.style.cssText = 'background:rgba(237,235,223,1); color:#5C0D11'
  205. //d.appendChild($(posts[i], '.postdetails').cloneNode(true))
  206. var anchor = doc.createElement('A')
  207. anchor.text = $(posts[i], '.postdetails').textContent
  208. anchor.href = href.replace(loc.hash, '') + '#' + $(posts[i], '*[id^="post-main-"]').id
  209. d.appendChild(anchor)
  210. var pre = doc.createElement('PRE')
  211. pre.appendChild(doc.createTextNode(out))
  212. d.appendChild(pre)
  213. first_post.parentNode.insertBefore(d, first_post)
  214. }
  215. }
  216.  
  217. var toggle_results = function() {
  218. var divs = $$(first_post.parentNode, '.result')
  219. for(var i=divs.length-1; i>=0; i--) {
  220. if(divs[i].style.display != 'none') { divs[i].style.display = 'none' } else { divs[i].style.display = '' }
  221. }
  222. }
  223. addEventListener('keydown', function(evt) { if((evt.target.tagName!='INPUT') && (evt.target.tagName!='TEXTAREA') && (evt.keyCode == hotkey)) { toggle_results() } }, false)
  224. if(!default_on) { toggle_results() }
  225. }
  226. else {
  227. var result_box = doc.createElement('DIV')
  228. result_box.id = 'result_box'
  229. var position = 'inherent'
  230. if(result_box_position == 'right') { position = 'fixed' }
  231. result_box.style.cssText = 'top:' + wnd.innerHeight/6 + 'px; right:0px; position:' + position + '; z-index:2147483647;'
  232. var posts = $$('.borderwrap')
  233. for(var i=0, len=posts.length; i<len; i++) {
  234. var poster = $(posts[i], '.bigusername')
  235. if((!poster) || (poster.textContent != $('.bigusername').textContent)) { continue } // skip threads that are not posted by the shop owner
  236.  
  237. var lines = get_text($(posts[i], '.postcolor')).split('\n')
  238. var out = ''
  239. for(var j=0, len2=lines.length; j<len2; j++) {
  240. var line = lines[j]
  241. if(stockout(line)) { continue }
  242. for(var k=0, len3=grep_patterns.length; k<len3; k++) {
  243. var grepped = false
  244. for(var m=0, len4=grep_patterns[k][0].length; m<len4; m++) {
  245. if(grep_patterns[k][0][m].test(line)) {
  246. grepped = true
  247. out = out + line.substring(0, max_length) + '\n'
  248. break
  249. }
  250. }
  251. if(grepped) { break }
  252. }
  253. }
  254. if(out) {
  255. if(display_title_and_poster && (/#1/.test($(posts[i], '.postdetails').textContent))) {
  256. var shop_title = $$('.maintitle>table>tbody>tr>td>div')[0].textContent
  257. out = '[Title]\t' + shop_title.substring(0, max_length) + '\n' + '[Poster] ' + poster.textContent.substring(0, max_length)+ '\n\n' + out
  258. }
  259. var d = doc.createElement('DIV')
  260. d.className = 'result'
  261. d.style.cssText = 'background:rgba(237,235,223,1); color:#5C0D11'
  262. //d.appendChild($(posts[i], '.postdetails').cloneNode(true))
  263. var anchor = doc.createElement('A')
  264. anchor.text = $(posts[i], '.postdetails').textContent
  265. anchor.href = href.replace(loc.hash, '') + '#' + $(posts[i], '*[id^="post-main-"]').id
  266. d.appendChild(anchor)
  267. var pre = doc.createElement('PRE')
  268. pre.appendChild(doc.createTextNode(out))
  269. d.appendChild(pre)
  270. result_box.appendChild(d)
  271. }
  272. }
  273. $('.postcolor').parentNode.insertBefore(result_box, $('.postcolor'))
  274.  
  275. var toggle_result_box = function() {
  276. var result_box = $('#result_box')
  277. if(result_box.style.display != 'none') { result_box.style.display = 'none' } else { result_box.style.display = '' }
  278. }
  279. addEventListener('keydown', function(evt) { if((evt.target.tagName!='INPUT') && (evt.target.tagName!='TEXTAREA') && (evt.keyCode == hotkey)) { toggle_result_box() } }, false)
  280. if(!default_on) { toggle_result_box() }
  281. }
  282.  
  283. // Highlights equipments and items
  284. var posts = $$('.postcolor')
  285. for(var i=posts.length-1; i>=0; i--) {
  286. var lnks = $$(posts[i], 'A')
  287. for(var j=lnks.length-1; j>=0; j--) {
  288. for (var k=0, len=grep_patterns.length; k<len; k++) {
  289. var highlighted = false
  290. for(var m=grep_patterns[k][0].length-1; m>=0; m--) {
  291. if(grep_patterns[k][0][m].test(lnks[j].text)) {
  292. highlighted = true
  293. var spans = lnks[j].querySelectorAll('span')
  294. if(spans.length) {
  295. for(var n=spans.length-1; n>=0; n--) {
  296. (function(){
  297. var text = spans[n].textContent
  298. var node = doc.createTextNode(text)
  299. spans[n].parentNode.replaceChild(node, spans[n])
  300. }
  301. )()
  302. }
  303. }
  304. lnks[j].style.color = 'white'
  305. lnks[j].style.backgroundColor = grep_patterns[k][1]
  306. if(grep_patterns[k][2] != '') { lnks[j].style.cssText = grep_patterns[k][2] }
  307.  
  308. break
  309. }
  310. } if(highlighted) { break }
  311. }
  312. }
  313. }
  314. }