Comick.io Random Comic Button

Replaces the Home button with a Random button that navigates to random comics

  1. // ==UserScript==
  2. // @name Comick.io Random Comic Button
  3. // @namespace https://github.com/GooglyBlox
  4. // @version 1.0
  5. // @description Replaces the Home button with a Random button that navigates to random comics
  6. // @author GooglyBlox
  7. // @match https://comick.io/*
  8. // @grant GM_xmlhttpRequest
  9. // @connect api.comick.io
  10. // @license MIT
  11. // ==/UserScript==
  12.  
  13. (function() {
  14. 'use strict';
  15.  
  16. let comics = [];
  17. let isLoading = false;
  18.  
  19. function loadComics() {
  20. if (isLoading) return;
  21. isLoading = true;
  22. loadPage(1);
  23. }
  24.  
  25. function loadPage(page, maxPages = 50) {
  26. GM_xmlhttpRequest({
  27. method: "GET",
  28. url: `https://api.comick.io/v1.0/search?limit=50&page=${page}`,
  29. onload: function(response) {
  30. try {
  31. const data = JSON.parse(response.responseText);
  32. if (data && Array.isArray(data)) {
  33. comics = comics.concat(data);
  34.  
  35. if (data.length > 0 && page < maxPages) {
  36. loadPage(page + 1, maxPages);
  37. } else {
  38. isLoading = false;
  39. console.log(`Loaded ${comics.length} comics for random selection`);
  40. }
  41. }
  42. } catch (error) {
  43. console.error("Error loading comics:", error);
  44. isLoading = false;
  45. }
  46. },
  47. onerror: function(error) {
  48. console.error("Error loading comics:", error);
  49. isLoading = false;
  50. }
  51. });
  52. }
  53.  
  54. function updateButton() {
  55. const homeLink = document.querySelector('a[href="/home2"].relative.grow-0.w-9\\/12.flex.justify-center.h-28, a[href="/home2"].relative.grow-0.flex.justify-center');
  56.  
  57. if (!homeLink) return false;
  58.  
  59. if (homeLink.getAttribute('data-random-button-modified')) return true;
  60.  
  61. homeLink.setAttribute('data-random-button-modified', 'true');
  62.  
  63. const buttonDiv = homeLink.querySelector('button div');
  64. if (buttonDiv) {
  65. buttonDiv.innerHTML = `
  66. <svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-dices-icon lucide-dices w-5 h-5 md:w-6 md:h-6 lg:w-7 lg:h-7">
  67. <rect width="12" height="12" x="2" y="10" rx="2" ry="2"/>
  68. <path d="m17.92 14 3.5-3.5a2.24 2.24 0 0 0 0-3l-5-4.92a2.24 2.24 0 0 0-3 0L10 6"/>
  69. <path d="M6 18h.01"/>
  70. <path d="M10 14h.01"/>
  71. <path d="M15 6h.01"/>
  72. <path d="M18 9h.01"/>
  73. </svg>
  74. <div class="text-xs absolute left-1/2 -translate-x-1/2">Random</div>
  75. `;
  76. }
  77.  
  78. const newHomeLink = homeLink.cloneNode(true);
  79. homeLink.parentNode.replaceChild(newHomeLink, homeLink);
  80.  
  81. newHomeLink.setAttribute('href', '#');
  82. newHomeLink.setAttribute('data-random-button-modified', 'true');
  83.  
  84. newHomeLink.addEventListener('click', function(e) {
  85. e.preventDefault();
  86. e.stopPropagation();
  87.  
  88. if (comics.length === 0) {
  89. alert("Still loading comics. Please try again in a moment.");
  90. return;
  91. }
  92.  
  93. const randomComic = comics[Math.floor(Math.random() * comics.length)];
  94. if (randomComic && randomComic.slug) {
  95. window.location.href = `https://comick.io/comic/${randomComic.slug}`;
  96. }
  97. });
  98.  
  99. return true;
  100. }
  101.  
  102. function checkForButton() {
  103. if (updateButton()) {
  104. setTimeout(checkForButton, 1000);
  105. return;
  106. }
  107.  
  108. setTimeout(checkForButton, 300);
  109. }
  110.  
  111. loadComics();
  112. checkForButton();
  113.  
  114. const observer = new MutationObserver(function(mutations) {
  115. for (let i = 0; i < mutations.length; i++) {
  116. const mutation = mutations[i];
  117.  
  118. if (mutation.type === 'childList' && mutation.addedNodes.length > 0) {
  119. if (mutation.target.tagName === 'NAV' ||
  120. mutation.target.closest('nav') ||
  121. mutation.target.closest('.sidebar')) {
  122. updateButton();
  123. break;
  124. }
  125. }
  126. }
  127. });
  128.  
  129. const navElements = document.querySelectorAll('nav, .sidebar, header');
  130. if (navElements.length > 0) {
  131. navElements.forEach(el => observer.observe(el, { childList: true, subtree: true }));
  132. } else {
  133. observer.observe(document.body, { childList: true, subtree: true });
  134. }
  135. })();