E(x)-Hentai CompactSearch

Compacts the search into the topbar, saving vertical space. Supports E-Hentai & EXHentai.

  1. // ==UserScript==
  2. // @name E(x)-Hentai CompactSearch
  3. // @description Compacts the search into the topbar, saving vertical space. Supports E-Hentai & EXHentai.
  4. // @author Daku (admin@codeanimu.net)
  5. // @namespace https://github.com/DakuTree/userscripts
  6. // @homepage https://github.com/DakuTree/userscripts
  7. // @homepageURL https://github.com/DakuTree/userscripts
  8. // @supportURL https://github.com/DakuTree/userscripts/issues
  9. // @icon https://e-hentai.org/favicon.ico
  10. // @match https://e-hentai.org/*
  11. // @match https://exhentai.org/*
  12. // @exclude https://e-hentai.org/archiver.php*
  13. // @version 2.1.6
  14. // @require https://ajax.googleapis.com/ajax/libs/jquery/1.12.2/jquery.min.js
  15. // @grant GM_addStyle
  16. // @run-at document-start
  17. // ==/UserScript==
  18.  
  19. /* jshint -W097, browser:true, devel:true, multistr: true */
  20.  
  21. //Auto-redirect to https & non g.e (NOTE: This will be done by EH automatically some time in the future so this is just a temp-fix.)
  22. if (location.hostname !== 'exhentai.org' && location.origin !== "https://e-hentai.org") {
  23. location.href = (location.href.replace(/^https?:\/\/(?:g\.)?e-hentai\.org/, "https://e-hentai.org"));
  24. } else if (location.hostname === 'exhentai.org' && location.protocol !== 'https:') {
  25. location.href = (location.href.replace(/^https?:\/\/exhentai\.org/, "https://exhentai.org"));
  26. }
  27.  
  28. var domain = (location.host.match(/([^.]+)\.\w{2,3}(?:\.\w{2})?$/) || [])[1].replace('-', '');
  29. var https = location.protocol.replace(/.$/, '');
  30. GM_addStyle("#toppane, #nb {display: none !important;}"); //Hide elements before load
  31.  
  32. if (typeof window.jQuery === "undefined") {
  33. addJQuery(main); //@require doesn't work, so load JQuery then load the script
  34. } else {
  35. main(); //@require works, so just load the script
  36. }
  37.  
  38. function main() {
  39. jQuery(document).ready(function ($) {
  40. //Get/set default settings
  41. //This seems to be stored in the uconfig cookie, but it seems to be somewhat encrypted.
  42. var unsafeWindow = this.unsafeWindow || window;
  43. var v = {};
  44. if ($('form input[id*="f_"], #searchbox input[name="f_search"]').length > 0) {
  45. $('form input[id*="f_"], input[name="f_search"]').each(function () { v[$(this).attr('name')] = $(this).attr('value'); });
  46. unsafeWindow.localStorage.setItem('s', JSON.stringify(v));
  47. } else {
  48. v = JSON.parse(unsafeWindow.localStorage.getItem('s')) || {};
  49. v.f_search = "Search Keywords"; //Show default text on non-search pages.
  50. }
  51.  
  52. var colors = {
  53. ehentai: ['#E3E0D1', '#EDEBDF', '#5C0D11', '#9B4E03', '#F2EFDF', '#5C0D11', '#5C0D11'],
  54. exhentai: ['#34353b', '#4f535b', '#000000', '#43464e', '#43464e', '#f1f1f1', '#f1f1f1']
  55. };
  56.  
  57. var color1 = colors[domain][0],
  58. color2 = colors[domain][1],
  59. color3 = colors[domain][2], //borders, also main text color
  60. color4 = colors[domain][3],
  61. color5 = colors[domain][4], //search focus background
  62. color6 = colors[domain][5], //text
  63. color7 = colors[domain][6]; //text:hover:focus
  64.  
  65. $('#toppane').remove();
  66. $('<style/>').attr('rel', 'stylesheet').attr('type', 'text/css') //{
  67. .text("\
  68. .ido {padding-top: 0 !important;}\
  69. #navwrap {width: 90%; min-width: 975px; height: 24px; margin: auto; z-index: 99; position: relative; background-color: "+ color2 + "; border: 1px solid " + color3 + "; margin-bottom: 10px;}\
  70. .navbar {height: 24px; padding: 0; margin: 0; position: absolute; width: 100%;}\
  71. .navbar li {height: 24px; width: 150px; float: left; text-align: center; list-style: none; font: normal bold 12px/1.2em Arial, Verdana, Helvetica; padding: 0; margin: 0; background-color: "+ color2 + ";}\
  72. .navbar li a {padding: 5px 0; text-decoration: none; color: "+ color6 + "; display: block; border-right: 1px solid " + color3 + ";}\
  73. .navbar li a:hover {background-color: "+ color1 + ";}\
  74. .navbar li ul {display: none; height: auto; margin: 0; margin-left: -1px; padding: 0; border-top: 1px solid "+ color3 + "; border-left: 1px solid " + color3 + "; border-right: 1px solid " + color3 + "; border-bottom: 1px solid " + color3 + ";}\
  75. .navbar li:hover ul {display: block;}\
  76. .navbar li ul {background-color: "+ color2 + ";}\
  77. .navbar li:last-child ul {margin-top: 2px; margin-right: -1px;}\
  78. .navbar li ul a {border-right: 0;}\
  79. .navbar li ul a:not(:first-child) {border-top: 1px solid "+ color3 + "}\
  80. .navbar li ul a:hover {background-color: "+ color1 + ";}\
  81. .navbar li form {margin-top: 0;}\
  82. .navbar li form input {margin-right: 1px;}\
  83. .navbar li form ul {font-weight: normal;}\
  84. .navbar .nopm a {text-decoration: underline; font-size: 8pt; display: inline; border: 0 !important;}\
  85. .navbar .nopm a:hover {background-color: transparent;}\n\
  86. .navbar input.stdinput {width: 349px; background-color: "+ color1 + "; color: " + color6 + "; padding: 1px 3px 2px 3px; border: 1px solid " + color3 + ";}\
  87. @-moz-document url-prefix() { .navbar input.stdinput {padding: 1px 3px 1px 3px !important;} }\
  88. .navbar input.stdinput {width: 349px; background-color: "+ color1 + "; color: " + color6 + "; padding: 1px 3px 2px 3px; border: 1px solid " + color3 + ";}\
  89. .navbar .stdinput:enabled:hover, .navbar .stdinput:enabled:focus {color: "+ color7 + "; background: " + color5 + ";}\
  90. .navbar .stdinput, .stdbtn {margin: auto;}\
  91. .navbar .stdbtn {height: 19px !important; padding: 0px 6px; margin: 3px 1px 0px 1px; background-color: "+ color1 + "; color: " + color6 + ";}\
  92. .navbar .stdbtn:hover {border: 2px outset "+ color3 + ";}\
  93. .navbar .stdbtn:enabled:hover, .navbar .stdbtn:enabled:active, .navbar .stdbtn:enabled:focus {color: "+ color7 + "; background: " + color5 + "; border: 2px outset " + color3 + ";}\
  94. .navbar table.itc {border-spacing: 1px; padding-top: 1px; padding-bottom: 1px;}\
  95. .navbar table.itc td {padding: 0;}\
  96. .navbar #fill {width: calc(100% - 450px - 507px - 16px);}\
  97. .navbar table.itss {margin: 0; width: calc(100% - 28px); font-size:11px; margin-left: 28px;}\
  98. .navbar table.itss td.ic2 {width: 45%}\
  99. .navbar #fsdiv {font-size: 11px; font-weight: normal;}\
  100. ").appendTo('head'); //}
  101.  
  102. var nav_wrap = $('<div/>', { id: 'navwrap' });
  103. var nav = $('<ul/>', { class: 'navbar' }).appendTo(nav_wrap);
  104. $('<li/>').append( //{
  105. $('<a/>', { text: "Front Page", href: location.origin })).append(
  106. $('<ul/>').append(
  107. $('<a/>', { text: "News", href: 'https://forums.e-hentai.org/index.php?showforum=2' })).append(
  108. $('<a/>', { text: "Forums", href: 'https://forums.e-hentai.org/' })).append(
  109. $('<a/>', { text: "Wiki", href: 'https://ehwiki.org/wiki/Category:E-Hentai_Galleries' })).append(
  110. $('<a/>', { text: "Torrents", href: location.origin + '/torrents.php' })).append(
  111. $('<a/>', { text: "Bounties", href: 'https://e-hentai.org/bounty.php' })).append(
  112. $('<a/>', { text: "Toplists", href: 'https://e-hentai.org/toplist.php' }))).appendTo(nav);
  113. $('<li/>').append(
  114. $('<a/>', { text: "My Home", href: 'https://e-hentai.org/home.php' })).append(
  115. $('<ul/>').append(
  116. $('<a/>', { text: "Favorites", href: location.origin + '/favorites.php' })).append(
  117. $('<a/>', { text: "Maintain Galleries", href: 'https://ul.' + location.hostname.replace(/^g\./, '') + '/manage.php' })).append(
  118. $('<a/>', { text: "Upload Gallery", href: 'https://ul.' + location.hostname.replace(/^g\./, '') + '/manage.php?act=new' })).append(
  119. $('<a/>', { text: "Options", href: location.origin + '/uconfig.php' }))).appendTo(nav);
  120. $('<li/>').append(
  121. $('<a/>', { text: "HentaiVerse", href: 'https://hentaiverse.org/', onclick: "popUp('https://hentaiverse.org/',1250,720); return false" })).appendTo(nav);
  122. $('<li/>', { id: 'fill', style: "border-right: 1px solid " + color3 + ";" }).appendTo(nav);
  123. $('<li/>', { style: "border-right: 1px solid " + color3 + "; width: 15px !important; min-width: 15px; max-width: 15px;" }).append(
  124. $('<a/>', { href: '#', text: '#', id: 'addenglish', style: 'border-right: 0' })).appendTo(nav);
  125. $('<li/>', { style: "width: 506px !important; min-width: 506px; max-width: 506px;" }).append(
  126. $('<form/>', { action: https + "://" + location.hostname, method: "GET" }).append(
  127. $('<div/>').append(
  128. $('<input/>', { type: "text", name: "f_search", value: v.f_search, class: "stdinput", onfocus: "if(this.value=='Search Keywords') this.value = '';", size: "50", maxlength: "200" })).append(
  129. $('<input/>', { type: "submit", name: "f_apply", value: "Apply Filter", class: "stdbtn", style: "width: 70px" })).append(
  130. $('<input/>', { type: "submit", name: "f_clear", value: "Clear Filter", class: "stdbtn", style: "width: 70px", onclick: "top.location.href='https://e-hentai.org/'; return false" }))).append(
  131. $('<ul/>').append(
  132. $('<table/>', { class: "itc" }).append(
  133. $('<tr/>').append(
  134. $('<td/>').append(
  135. $('<input/>', { type: "hidden", name: "f_doujinshi", value: v.f_doujinshi, id: "f_doujinshi" })).append(
  136. $('<img/>', { id: "f_doujinshi_img", src: "https://ehgt.org/g/c/doujinshi" + (v.f_doujinshi == 1 ? "" : "_d") + ".png", class: "ic", alt: "doujinshi", style: "cursor:pointer" }))).append(
  137. $('<td/>').append(
  138. $('<input/>', { type: "hidden", name: "f_manga", value: v.f_manga, id: "f_manga" })).append(
  139. $('<img/>', { id: "f_manga_img", src: "https://ehgt.org/g/c/manga" + (v.f_manga == 1 ? "" : "_d") + ".png", class: "ic", alt: "mangat", style: "cursor:pointer" }))).append(
  140. $('<td/>').append(
  141. $('<input/>', { type: "hidden", name: "f_artistcg", value: v.f_artistcg, id: "f_artistcg" })).append(
  142. $('<img/>', { id: "f_artistcg_img", src: "https://ehgt.org/g/c/artistcg" + (v.f_artistcg == 1 ? "" : "_d") + ".png", class: "ic", alt: "artistcg", style: "cursor:pointer" }))).append(
  143. $('<td/>').append(
  144. $('<input/>', { type: "hidden", name: "f_gamecg", value: v.f_gamecg, id: "f_gamecg" })).append(
  145. $('<img/>', { id: "f_gamecg_img", src: "https://ehgt.org/g/c/gamecg" + (v.f_gamecg == 1 ? "" : "_d") + ".png", class: "ic", alt: "gamecg", style: "cursor:pointer" }))).append(
  146. $('<td/>').append(
  147. $('<input/>', { type: "hidden", name: "f_western", value: v.f_western, id: "f_western" })).append(
  148. $('<img/>', { id: "f_western_img", src: "https://ehgt.org/g/c/western" + (v.f_western == 1 ? "" : "_d") + ".png", class: "ic", alt: "western", style: "cursor:pointer" })))).append(
  149. $('<tr/>').append(
  150. $('<td/>').append(
  151. $('<input/>', { type: "hidden", name: "f_non-h", value: v["f_non-h"], id: "f_non-h" })).append(
  152. $('<img/>', { id: "f_non-h_img", src: "https://ehgt.org/g/c/non-h" + (v["f_non-h"] == 1 ? "" : "_d") + ".png", class: "ic", alt: "non-h", style: "cursor:pointer" }))).append(
  153. $('<td/>').append(
  154. $('<input/>', { type: "hidden", name: "f_imageset", value: v.f_imageset, id: "f_imageset" })).append(
  155. $('<img/>', { id: "f_imageset_img", src: "https://ehgt.org/g/c/imageset" + (v.f_imageset == 1 ? "" : "_d") + ".png", class: "ic", alt: "imageset", style: "cursor:pointer" }))).append(
  156. $('<td/>').append(
  157. $('<input/>', { type: "hidden", name: "f_cosplay", value: v.f_cosplay, id: "f_cosplay" })).append(
  158. $('<img/>', { id: "f_cosplay_img", src: "https://ehgt.org/g/c/cosplay" + (v.f_cosplay == 1 ? "" : "_d") + ".png", class: "ic", alt: "cosplay", style: "cursor:pointer", }))).append(
  159. $('<td/>').append(
  160. $('<input/>', { type: "hidden", name: "f_asianporn", value: v.f_asianporn, id: "f_asianporn" })).append(
  161. $('<img/>', { id: "f_asianporn_img", src: "https://ehgt.org/g/c/asianporn" + (v.f_asianporn == 1 ? "" : "_d") + ".png", class: "ic", alt: "asianporn", style: "cursor:pointer" }))).append(
  162. $('<td/>').append(
  163. $('<input/>', { type: "hidden", name: "f_misc", value: v.f_misc, id: "f_misc" })).append(
  164. $('<img/>', { id: "f_misc_img", src: "https://ehgt.org/g/c/misc" + (v.f_misc == 1 ? "" : "_d") + ".png", class: "ic", alt: "misc", style: "cursor:pointer" }))))).append(
  165. $('<div/>').append(
  166. $('<p/>', { class: "nopm", style: "margin-top:2px;" }).append(
  167. $('<a/>', { href: "#", rel: "nofollow", id: "show_ao", text: "Show Advanced Options", style: "margin-right:5px;" })).append(
  168. $('<a/>', { href: "#", rel: "nofollow", id: "show_fs", text: "Show File Search", style: "margin-left:5px;", disabled: 'disabled' }))).append(
  169. $('<div/>', { id: 'advdiv', style: 'display: none;' }))))).append(
  170. $('<ul/>', { style: 'margin-top: -1px;' }).append(
  171. $('<div/>', { id: 'fsdiv', style: 'display: none;' }))
  172. ).appendTo(nav); //}
  173.  
  174. //$('#nb').replaceWith(nav_wrap);
  175. $('body').prepend(nav_wrap);
  176.  
  177. $('#navwrap').on('click', '.nopm > a', function (e) {
  178. var id = ($(this).attr('id') == 'show_ao' ? 'advdiv' : 'fsdiv');
  179.  
  180. if ($('#' + id).css('display') == 'none') {
  181. if (id == 'advdiv') {
  182. $('#' + id).append(
  183. $('<input/>', { type: 'hidden', id: 'advsearch', name: 'advsearch', value: '1' })).append(
  184. $('<table/>', { class: 'itss' }).append(
  185. $('<tbody/>').append(
  186. $('<tr/>').append(
  187. $('<td/>', { class: 'ic4' }).append(
  188. $('<input/>', { id: 'adv11', type: 'checkbox', name: 'f_sname', checked: 'checked' })).append(
  189. $('<label/>', { for: 'adv11', text: 'Search Gallery Name' }))).append(
  190. $('<td/>', { class: 'ic4' }).append(
  191. $('<input/>', { id: 'adv12', type: 'checkbox', name: 'f_stags', checked: 'checked' })).append(
  192. $('<label/>', { for: 'adv12', text: 'Search Gallery Tags' }))).append(
  193. $('<td/>', { class: 'ic2' }).append(
  194. $('<input/>', { id: 'adv13', type: 'checkbox', name: 'f_sdesc', colspan: '2' })).append(
  195. $('<label/>', { for: 'adv13', text: 'Search Gallery Description' })))).append(
  196. $('<tr/>').append(
  197. $('<td/>', { class: 'ic2', colspan: '2' }).append(
  198. $('<input/>', { id: 'adv15', type: 'checkbox', name: 'f_storr' })).append(
  199. $('<label/>', { for: 'adv15', text: 'Search Torrent Filenames' }))).append(
  200. $('<td/>', { class: 'ic2', colspan: '2' }).append(
  201. $('<input/>', { id: 'adv16', type: 'checkbox', name: 'f_sto' })).append(
  202. $('<label/>', { for: 'adv16', text: 'Only Show Galleries With Torrents' })))).append(
  203. $('<tr/>').append(
  204. $('<td/>', { class: 'ic2', colspan: '2' }).append(
  205. $('<input/>', { id: 'adv21', type: 'checkbox', name: 'f_sdt1' })).append(
  206. $('<label/>', { for: 'adv21', text: 'Search Low-Power Tags' }))).append(
  207. $('<td/>', { class: 'ic2', colspan: '2' }).append(
  208. $('<input/>', { id: 'adv22', type: 'checkbox', name: 'f_sdt2' })).append(
  209. $('<label/>', { for: 'adv22', text: 'Search Downvoted Tags' })))).append(
  210. $('<tr/>').append(
  211. $('<td/>', { class: 'ic2', colspan: '2' }).append(
  212. $('<input/>', { id: 'adv31', type: 'checkbox', name: 'f_sh' })).append(
  213. $('<label/>', { for: 'adv31', text: 'Show Expunged Galleries' }))).append(
  214. $('<td/>', { class: 'ic2', colspan: '2' }).append(
  215. $('<input/>', { id: 'adv32', type: 'checkbox', name: 'f_sr' })).append(
  216. $('<label/>', { for: 'adv32', text: 'Minimum Rating: ' })).append(
  217. $('<select/>', { id: 'adv42', class: 'stdinput imr', name: 'f_srdd' }).append(
  218. $('<option/>', { value: '2', text: '2 stars' })).append(
  219. $('<option/>', { value: '3', text: '3 stars' })).append(
  220. $('<option/>', { value: '4', text: '4 stars' })).append(
  221. $('<option/>', { value: '5', text: '5 stars' }))))
  222. )));
  223. }
  224. else if (id == 'fsdiv') {
  225. $('#' + id).append(
  226. $('<form/>', { action: https + '://' + (domain == 'ehentai' ? 'upload.e-hentai.org' : 'exhentai.org/upload') + '/image_lookup.php', method: 'post', enctype: 'multipart/form-data' }).append(
  227. $('<div/>').append(
  228. $('<p/>', { text: 'If you want to combine a file search with a category/keyword search, upload the file first.', style: 'font-weight: bold;' })).append(
  229. $('<p/>', { text: 'Select a file to upload, then hit File Search. All public galleries containing this exact file will be displayed.' })).append(
  230. $('<div/>').append(
  231. $('<input/>', { type: 'file', name: 'sfile', size: '40', style: 'font-size:8pt;' })).append(
  232. $('<input/>', { type: 'submit', name: 'f_sfile', value: 'File Search', style: 'font-size:8pt;' }))).append(
  233. $('<p/>', { text: 'For color images, the system can also perform a similarity lookup to find resampled images.' })).append(
  234. $('<table/>', { class: 'itsf' }).append(
  235. $('<tbody/>').append(
  236. $('<tr/>').append(
  237. $('<td/>', { class: 'ic3' }).append(
  238. $('<input/>', { id: 'fs_similiar', type: 'checkbox', name: 'fs_similar', checked: 'checked' })).append(
  239. $('<label/>', { for: 'fs_similar', text: 'Use Similarity Scan' }))).append(
  240. $('<td/>', { class: 'ic3' }).append(
  241. $('<input/>', { id: 'fs_covers', type: 'checkbox', name: 'fs_covers' })).append(
  242. $('<label/>', { for: 'fs_covers', text: 'Only Search Covers' }))).append(
  243. $('<td/>', { class: 'ic3' }).append(
  244. $('<input/>', { id: 'fs_exp', type: 'checkbox', name: 'fs_exp' })).append(
  245. $('<label/>', { for: 'fs_exp', text: 'Show Expunged' }))))))));
  246. }
  247.  
  248. $(this).text(function () {
  249. return $(this).text().replace("Show", "Hide");
  250. });
  251. } else {
  252. $('#' + id).empty();
  253. $(this).text(function () {
  254. return $(this).text().replace("Hide", "Show");
  255. });
  256. }
  257. $('#' + id).toggle();
  258.  
  259. e.preventDefault();
  260. });
  261.  
  262. $('#addenglish').on('click', function (e) {
  263. $('input[name="f_search"]').val(function (i, v) {
  264. return v.replace(/(.*)/, 'english' + (v == 'Search Keywords' || v === '' ? '' : ' $1'));
  265. });
  266. });
  267. //TODO: Possibly use jQuery slide?
  268.  
  269.  
  270. setupToggleCategory();
  271. });
  272. }
  273.  
  274. function setupToggleCategory() {
  275. //This is "more or less" the built-in "toggle_category" function.
  276. //Sadly that doesn't get loaded on gallery pages, so we use this instead.
  277. $('body').on('click', 'img[id^=f_]', function () {
  278. var img = $(this), //img
  279. input = $(img).prev(), //input
  280. input_val = parseInt($(input).val());
  281.  
  282. if (input_val) {
  283. $(input).val(0);
  284. $(img).attr('src', $(img).attr('src').replace('.png', '_d.png'));
  285. } else {
  286. $(input).val(1);
  287. $(input).attr('src', $(img).attr('src').replace('_d.png', '.png'));
  288. }
  289. });
  290. }
  291.  
  292. /*** Only used if @require doesn't work properly ***/
  293. function addJQuery(callback) {
  294. var script = document.createElement("script");
  295. script.setAttribute("src", "//ajax.googleapis.com/ajax/libs/jquery/1.12.2/jquery.min.js");
  296. script.addEventListener('load', function () {
  297. var script = document.createElement("script");
  298. script.textContent = "(" + callback.toString() + ")();";
  299. document.body.appendChild(script);
  300. }, false);
  301. document.body.appendChild(script);
  302. }