Sleazy Fork is available in English.

Navigational Keyboard Shortcuts

Navigate through websites using keyboard buttons N/B for next/previous pages.

  1. // ==UserScript==
  2. // @name Navigational Keyboard Shortcuts
  3. // @namespace https://github.com/kittenparry/
  4. // @version 1.27.1
  5. // @description Navigate through websites using keyboard buttons N/B for next/previous pages.
  6. // @author kittenparry
  7. // @match *://*/*
  8. // @grant none
  9. // @license GPL-3.0-or-later
  10. // ==/UserScript==
  11.  
  12. /* LIST:
  13. * archived.moe
  14. * google.com
  15. * imgfrog.pw
  16. * metal-tracker.com
  17. * mods.factorio.com
  18. * nexusmods.com
  19. * nyaa.si
  20. * opengameart.org
  21. * rarbg.to || rarbgproxy.org || rarbg2020.org || rarbgget.org
  22. * reddit.com
  23. * stargate.fandom.com
  24. * steamcommunity.com/workshop/
  25. * steamgifts.com
  26. * trakt.tv
  27. * tumblr.com
  28. * xkcd.com
  29.  
  30. * NSFW:
  31. * 420chan.org
  32. * 8muses.com
  33. * *.booru.org
  34. * camshowhub.to
  35. * camvault.xyz
  36. * camwhores.tv
  37. * chaturbate.com
  38. * coedcherry.com
  39. * erome.com
  40. * f95zone.com
  41. * forum.sexy-egirls.com
  42. * forum.thotsbay.com
  43. * forums.sexy-youtubers.com
  44. * forums.socialmediagirls.com
  45. * hanime.tv
  46. * hentai-foundry.com
  47. * hongfire.com
  48. * javbus.com
  49. * kitty-kats.net
  50. * loverslab.com
  51. * meitulu.com
  52. * meituri.com
  53. * nhentai.net
  54. * nobodyhome.tv
  55. * pixietrixcomix.com
  56. * planetsuzy.org
  57. * pornbay.org
  58. * pornhub.com
  59. * recurbate.com
  60. * rec-tube.com
  61. * shadbase.com
  62. * simpcity.su
  63. * sinnercomics.com
  64. * thothub.tv
  65. * totempole666.com
  66. * xbunker.nu
  67. * xbunker.su
  68. * yiff.party/activity
  69. */
  70.  
  71. /* CHANGELOG:
  72. * 1.27.1: +xbunker.nu (xbunker.su alt/ rather updated domain)
  73. * 1.27: +xbunker.su +simpcity.su +forums.socialmediagirls.com
  74. * 1.26.1: +rarbgget.org (rarbg.to alt)
  75. * 1.26: +forum.thotsbay.com
  76. * 1.25: +opengameart.org
  77. * 1.24: +rarbg2020.org (rarbg.to alt) +xkcd.com +pixietrixcomix.com
  78. * 1.23: +forums.sexy-youtubers.com +forum.sexy-egirls.com
  79. * 1.22: +420chan.org
  80. * 1.21: +totempole666.com
  81. * 1.20.1: fix archived.moe first (& likely last) page navigation
  82. * 1.20: +loverslab.com | could probably be better with a special of its own similar to nexusmods
  83. * 1.19: +pornhub.com
  84. * 1.18: +google.com
  85. * 1.17: +archived.moe
  86. * 1.16: +kitty-kats.net
  87. * 1.15: +mods.factorio.com
  88. * 1.14: +imgfrog.pw
  89. * 1.13.1: lack of special handling similar to focus_input_key script (fik.user.js)
  90. * 1.13: +*.booru.org
  91. * 1.12: +camshowhub.to
  92. * 1.11.1: fix trakt.tv back keybind not working
  93. * 1.11: +stargate.fandom.com | navigates the episodes (preceded by & followed by)
  94. * 1.10: +trakt.tv +camvault.xyz | trakt.tv only works in episode/season views
  95. * 1.9.2: additional functions to ease repetition & meituri/meitulu isn't special anymore
  96. * 1.9.1: ability to navigate to first/last pages on pornbay.org
  97. * 1.9: +rec-tube.com
  98. * 1.8: +erome.com +recurbate.com +hanime.tv
  99. * 1.7.1: +nobodyhome.tv instead of nobodyhome.ga (domain change)
  100. * 1.7: +planetsuzy.org
  101. * 1.6.1: +rarbgproxy.org as an alternative to rarbg.to
  102. * 1.6: +chaturbate.com
  103. * 1.5: +meituri.com +meitulu.com | they work the same way so a simple or will do
  104. * 1.4: +javbus.com | switch to semantic versioning so incrementing minor instead of patch part (https://semver.org/)
  105. * 1.3.7: +thothub.tv
  106. * 1.3.6: +nexusmods.com | a special case similar to camwhores.tv
  107. * 1.3.5: +yiff.party/activity | with some clunky mechanics
  108. * 1.3.4: +steamcommunity.com/workshop/
  109. * 1.3.3: +f95zone.to/latest/ | change the original link to .to as well
  110. * 1.3.2: +metal-tracker.com | btn case i wanted to use in camwhores.tv
  111. * 1.3.1: +shadbase.com
  112. * 1.3: +camwhores.tv | element needs to be reassigned each time so it's in the function
  113. * 1.2.4: +8muses.com
  114. * 1.2.3: +nobodyhome.ga
  115. * 1.2.2: +hongfire.com
  116. * 1.2.1: prevent execution of code when not on these sites
  117. * 1.2: +f95zone.com
  118. * 1.1: +nyaa.si +coedcherry.com
  119. * 1.0: initial | rarbg.com reddit.com steamgifts.com tumblr.com
  120. * & hentai-foundry.com nhentai.net pornbay.org sinnercomics.com
  121. */
  122.  
  123. check_nav_key_press = (e, prev, next, special) => {
  124. var type = e.target.getAttribute('type');
  125. var tag = e.target.tagName.toLowerCase();
  126. if (type != 'text' && tag != 'textarea' && type != 'search') {
  127. if (e.keyCode == 66) {
  128. if (special == 'camwhores') {
  129. document.querySelector('li[class="page-current"]').previousElementSibling.firstElementChild.click();
  130. } else if (special == 'nexusmods') {
  131. document.querySelector('li[class="prev"]').firstElementChild.click();
  132. } else if (special == 'hanime') {
  133. sel_and_click('.pagination__navigation', 0);
  134. } else if (special == 'btn' && prev != undefined) {
  135. document.querySelector(prev).click();
  136. } else if (special == 'url' && prev != undefined) {
  137. window.location = prev;
  138. } else if (special == '') {
  139. window.location = get_query_href(prev);
  140. }
  141. } else if (e.keyCode == 78) {
  142. if (special == 'camwhores') {
  143. document.querySelector('li[class="page-current"]').nextElementSibling.firstElementChild.click();
  144. } else if (special == 'nexusmods') {
  145. document.querySelector('li[class="next"]').firstElementChild.click();
  146. } else if (special == 'hanime') {
  147. sel_and_click('.pagination__navigation', 3);
  148. } else if (special == 'btn' && next != undefined) {
  149. document.querySelector(next).click();
  150. } else if (special == 'url' && next != undefined) {
  151. window.location = next;
  152. } else if (special == '') {
  153. window.location = get_query_href(next);
  154. }
  155. }
  156. }
  157. };
  158.  
  159. // return the first result of a given tag with the text
  160. // eg. ('a', 'prev') returns the anchor with 'prev' innerHTML
  161. find_els_with_text = (tag, text) => {
  162. var els = document.getElementsByTagName(tag);
  163. var found = [];
  164. for (var i = 0; i < els.length; i++) {
  165. if (els[i].innerHTML == text) {
  166. found.push(els[i]);
  167. }
  168. }
  169.  
  170. return found[0].href;
  171. };
  172.  
  173. // return the href of given selector
  174. get_query_href = (sel) => {
  175. return document.querySelector(sel).href;
  176. };
  177.  
  178. // click the idxth element of given selector
  179. sel_and_click = (sel, idx) => {
  180. document.querySelectorAll(sel)[idx].click();
  181. };
  182.  
  183. // return the href of given selector at idxth
  184. get_sel_href = (sel, idx) => {
  185. return document.querySelectorAll(sel)[idx].href;
  186. };
  187.  
  188. /* probably need a better way than simply .includes()
  189. * pqsel: previous query selector
  190. * nqsel: next query selector
  191. * nav_spcl: used when url is given instead of selector
  192. * check steamgifts example
  193. * also these include try/catch if they don't exist yet (first/last page)
  194. * !this section really looks ugly and repetitive
  195. */
  196.  
  197. var cur_loc = window.location.href;
  198.  
  199. if (cur_loc.includes('archived.moe')) {
  200. var nav_spcl = 'url';
  201. try {
  202. var pqsel = document.querySelector('li[class="prev"]').firstElementChild.href;
  203. } catch (e) {}
  204. try {
  205. var nqsel = document.querySelector('li[class="next"]').firstElementChild.href;
  206. } catch (e) {}
  207. } else if (cur_loc.includes('google.com')) {
  208. var nav_spcl = 'url';
  209. try {
  210. var nqsel = get_sel_href('.pn', 1);
  211. } catch (e) {
  212. // if the first page
  213. var nqsel = get_sel_href('.pn', 0);
  214. }
  215. try {
  216. var pqsel = get_sel_href('.pn', 0);
  217. // if the first page
  218. if (nqsel == pqsel) {
  219. pqsel = null;
  220. }
  221. } catch (e) {}
  222. } else if (cur_loc.includes('imgfrog.pw')) {
  223. var pqsel = 'a[data-pagination="prev"]';
  224. var nqsel = 'a[data-pagination="next"]';
  225. } else if (cur_loc.includes('metal-tracker.com')) {
  226. var nav_spcl = 'btn';
  227. var pqsel = 'li[class="previous"]';
  228. var nqsel = 'li[class="next"]';
  229. } else if (cur_loc.includes('mods.factorio.com')) {
  230. var nav_spcl = 'url';
  231. try {
  232. var pqsel = find_els_with_text('a', '« Previous');
  233. } catch (e) {}
  234. try {
  235. var nqsel = find_els_with_text('a', 'Next »');
  236. } catch (e) {}
  237. } else if (cur_loc.includes('nexusmods.com')) {
  238. var nav_spcl = 'nexusmods';
  239. var pqsel = '';
  240. var nqsel = '';
  241. } else if (cur_loc.includes('nyaa.si')) {
  242. var pqsel = 'a[rel="prev"]';
  243. var nqsel = 'a[rel="next"]';
  244. } else if (cur_loc.includes('opengameart.org')) {
  245. var pqsel = 'a[title="Go to previous page"]';
  246. var nqsel = 'a[title="Go to next page"]';
  247. } else if (cur_loc.includes('rarbg.to') || cur_loc.includes('rarbgproxy.org') || (cur_loc.includes('rarbg2020.org')) || (cur_loc.includes('rarbgget.org'))) {
  248. var pqsel = 'a[title="previous page"]';
  249. var nqsel = 'a[title="next page"]'
  250. } else if (cur_loc.includes('reddit.com')) {
  251. var pqsel = 'a[rel="nofollow prev"]';
  252. var nqsel = 'a[rel="nofollow next"]';
  253. } else if (cur_loc.includes('stargate.fandom.com')) {
  254. var nav_spcl = 'url';
  255. try {
  256. var pqsel = document.querySelector('div[data-source="preceded_by"]').lastElementChild.firstElementChild.href;
  257. } catch (e) {}
  258. try {
  259. var nqsel = document.querySelector('div[data-source="followed_by"]').lastElementChild.firstElementChild.href;
  260. } catch (e) {}
  261. } else if (cur_loc.includes('steamcommunity.com/workshop/')) {
  262. var nav_spcl = 'url';
  263. try {
  264. var pqsel = get_sel_href('.pagebtn', 0);
  265. } catch (e) {}
  266. try {
  267. var nqsel = get_sel_href('.pagebtn', 1);
  268. } catch (e) {}
  269. } else if (cur_loc.includes('steamgifts.com')) {
  270. var nav_spcl = 'url';
  271. try {
  272. var pqsel = document.querySelector('i[class="fa fa-angle-left"]').parentNode.href;
  273. } catch (e) {}
  274. try {
  275. var nqsel = document.querySelector('i[class="fa fa-angle-right"]').parentNode.href;
  276. } catch (e) {}
  277. } else if (cur_loc.includes('trakt.tv')) {
  278. var pqsel = 'a[rel="prev"]';
  279. var nqsel = 'a[rel="next"]';
  280. } else if (cur_loc.includes('tumblr.com')) {
  281. var pqsel = 'a[id="previous_page_link"]';
  282. var nqsel = 'a[id="next_page_link"]';
  283. } else if (cur_loc.includes('xkcd.com')) {
  284. var pqsel = 'a[rel="prev"]';
  285. var nqsel = 'a[rel="next"]';
  286. /* * * * * * * *
  287. * * * * * * * *
  288. * NSFW BELOW *
  289. * * * * * * * *
  290. * * * * * * * */
  291. } else if (cur_loc.includes('420chan.org')) {
  292. var nav_spcl = 'url';
  293. try {
  294. var pqsel = find_els_with_text('a', '« Previous');
  295. } catch (e) {}
  296. try {
  297. var nqsel = find_els_with_text('a', 'Next »');
  298. } catch (e) {}
  299. } else if (cur_loc.includes('8muses.com')) {
  300. var pqsel = 'a[class="pageNav-jump pageNav-jump--prev"]';
  301. var nqsel = 'a[class="pageNav-jump pageNav-jump--next"]';
  302. } else if (cur_loc.includes('.booru.org')) {
  303. var pqsel = 'a[alt="back"]';
  304. var nqsel = 'a[alt="next"]';
  305. } else if (cur_loc.includes('camshowhub.to')) {
  306. var pqsel = 'a[title="Previous page"]';
  307. var nqsel = 'a[title="Next page"]';
  308. } else if (cur_loc.includes('camvault.xyz')) {
  309. var pqsel = 'a[rel="prev"]';
  310. var nqsel = 'a[rel="next"]';
  311. } else if (cur_loc.includes('camwhores.tv')) {
  312. var nav_spcl = 'camwhores';
  313. var pqsel = '';
  314. var nqsel = '';
  315. } else if (cur_loc.includes('chaturbate.com')) {
  316. var pqsel = 'a[class="prev endless_page_link"]';
  317. var nqsel = 'a[class="next endless_page_link"]';
  318. } else if (cur_loc.includes('coedcherry.com')) {
  319. var pqsel = 'a[rel="prev"]';
  320. var nqsel = 'a[rel="next"]';
  321. } else if (cur_loc.includes('erome.com')) {
  322. var pqsel = 'a[rel="prev"]';
  323. var nqsel = 'a[rel="next"]';
  324. } else if (cur_loc.includes('f95zone.to/latest/')) {
  325. // something else for "/pages/latest/"
  326. var pqsel = 'a[class="nav_prev"]';
  327. var nqsel = 'a[class="nav_next"]';
  328. } else if (cur_loc.includes('f95zone.to')) {
  329. // for only threads/forums
  330. // something else is required for /pages/latest/
  331. var pqsel = 'a[class="pageNav-jump pageNav-jump--prev"]';
  332. var nqsel = 'a[class="pageNav-jump pageNav-jump--next"]';
  333. } else if (cur_loc.includes('hanime.tv')) {
  334. var nav_spcl = 'hanime'
  335. var pqsel = '';
  336. var nqsel = '';
  337. } else if (cur_loc.includes('hentai-foundry.com')) {
  338. var nav_spcl = 'url';
  339. try {
  340. var pqsel = document.querySelector('li[class="previous"]').firstChild.href;
  341. } catch (e) {}
  342. try {
  343. var nqsel = document.querySelector('li[class="next"]').firstChild.href;
  344. } catch (e) {}
  345. } else if (cur_loc.includes('hongfire.com')) {
  346. var pqsel = 'a[class="js-pagenav-button js-pagenav-prev-button b-button b-button--secondary js-shrink-event-child"]';
  347. var nqsel = 'a[class="js-pagenav-button js-pagenav-next-button b-button b-button--secondary js-shrink-event-child"]';
  348. } else if (cur_loc.includes('javbus.com')) {
  349. var pqsel = 'a[id="pre"]';
  350. var nqsel = 'a[id="next"]';
  351. } else if (cur_loc.includes('kitty-kats.net')) {
  352. var pqsel = 'a[class="pageNav-jump pageNav-jump--prev"]';
  353. var nqsel = 'a[class="pageNav-jump pageNav-jump--next"]';
  354. } else if (cur_loc.includes('loverslab.com')) {
  355. var pqsel = 'a[rel="prev"]';
  356. var nqsel = 'a[rel="next"]';
  357. } else if (cur_loc.includes('meituri.com') || cur_loc.includes('meitulu.com')) {
  358. var nav_spcl = 'url';
  359. try {
  360. var pqsel = get_sel_href('.a1', 0);
  361. } catch (e) {}
  362. try {
  363. var nqsel = get_sel_href('.a1', 1);
  364. } catch (e) {}
  365. } else if (cur_loc.includes('nhentai.net')) {
  366. var pqsel = 'a[class="previous"]';
  367. var nqsel = 'a[class="next"]';
  368. } else if (cur_loc.includes('nobodyhome.tv')) {
  369. var pqsel = 'a[class="pagination_previous"]';
  370. var nqsel = 'a[class="pagination_next"]';
  371. } else if (cur_loc.includes('pixietrixcomix.com')) {
  372. var pqsel = 'a[rel="prev"]';
  373. var nqsel = 'a[rel="next"]';
  374. } else if (cur_loc.includes('planetsuzy.org')) {
  375. var pqsel = 'a[rel="prev"]';
  376. var nqsel = 'a[rel="next"]';
  377. } else if (cur_loc.includes('pornbay.org')) {
  378. var nav_spcl = 'url';
  379. try {
  380. try {
  381. var pqsel = get_query_href('a[class="pager pager_prev"]');
  382. } catch (e) {
  383. var pqsel = get_query_href('a[class="pager pager_first"]');
  384. }
  385. } catch (e) {}
  386. try {
  387. try {
  388. var nqsel = get_query_href('a[class="pager pager_next"]');
  389. } catch (e) {
  390. var nqsel = get_query_href('a[class="pager pager_last"]');
  391. }
  392. } catch (e) {}
  393. } else if (cur_loc.includes('pornhub.com')) {
  394. var nav_spcl = 'url';
  395. try {
  396. var pqsel = document.querySelector('li[class="page_previous alpha"]').firstElementChild.href;
  397. } catch (e) {}
  398. try {
  399. var nqsel = document.querySelector('li[class="page_next omega"]').firstElementChild.href;
  400. } catch (e) {}
  401. } else if (cur_loc.includes('recurbate.com')) {
  402. var pqsel = 'a[aria-label="Previous"]';
  403. var nqsel = 'a[aria-label="Next"]';
  404. } else if (cur_loc.includes('rec-tube.com')) {
  405. var nav_spcl = 'url';
  406. try {
  407. try {
  408. var pqsel = find_els_with_text('a', 'Prev Page');
  409. } catch (e) {
  410. var pqsel = find_els_with_text('a', 'First Page')
  411. }
  412. } catch (e) {}
  413. try {
  414. try {
  415. var nqsel = find_els_with_text('a', 'Next Page');
  416. } catch (e) {
  417. var nqsel = find_els_with_text('a', 'Last Page')
  418. }
  419. } catch (e) {}
  420. } else if (cur_loc.includes('shadbase.com')) {
  421. var pqsel = 'a[class="navi navi-prev"]';
  422. var nqsel = 'a[class="navi navi-next"]';
  423. } else if (cur_loc.includes('sinnercomics.com')) {
  424. var pqsel = 'a[class="comic-nav-base comic-nav-previous"]';
  425. var nqsel = 'a[class="comic-nav-base comic-nav-next"]';
  426. } else if (cur_loc.includes('thothub.tv') || cur_loc.includes('forums.sexy-youtubers.com') || cur_loc.includes('forum.sexy-egirls.com') || cur_loc.includes('forum.thotsbay.com') || cur_loc.includes('xbunker.su') || cur_loc.includes('simpcity.su') || cur_loc.includes('forums.socialmediagirls.com') || cur_loc.includes('xbunker.nu')) {
  427. var pqsel = 'a[class="pageNav-jump pageNav-jump--prev"]';
  428. var nqsel = 'a[class="pageNav-jump pageNav-jump--next"]';
  429. } else if (cur_loc.includes('totempole666.com')) {
  430. var pqsel = 'a[class="navi comic-nav-previous navi-prev"]';
  431. var nqsel = 'a[class="navi comic-nav-next navi-next"]';
  432. } else if (cur_loc.includes('yiff.party/activity')) {
  433. var nav_spcl = 'url';
  434. try {
  435. var pqsel = find_els_with_text('a', 'prev');
  436. } catch (e) {}
  437. try {
  438. var nqsel = find_els_with_text('a', 'next');
  439. } catch (e) {}
  440. }
  441.  
  442. if (pqsel != undefined || nqsel != undefined) {
  443. try {
  444. if (!nav_spcl) {
  445. var nav_spcl = '';
  446. }
  447. window.addEventListener('keydown', (e) => check_nav_key_press(e, pqsel, nqsel, nav_spcl), false);
  448. } catch (e) {}
  449. }