1337x - UX Enhancement

Extend titles, add images to torrent list, full width site

  1. // ==UserScript==
  2. // @name 1337x - UX Enhancement
  3. // @namespace http://tampermonkey.net/
  4. // @version 1.4
  5. // @description Extend titles, add images to torrent list, full width site
  6. // @author French Bond
  7. // @match https://1337x.to/*
  8. // @grant GM_xmlhttpRequest
  9. // @grant GM_addStyle
  10. // @license MIT
  11. // ==/UserScript==
  12.  
  13. const VISIBLE_IMAGES = 4; // Number of images to show initially
  14.  
  15. (function () {
  16. 'use strict';
  17.  
  18. // List all torrent links on the page
  19. function listTorrentLinks() {
  20. return document.querySelectorAll('.table-list a[href^="/torrent/"]');
  21. }
  22.  
  23. // Clean the page title in order to get the torrent title
  24. function cleanTitle(title) {
  25. // Remove "Download " from the beginning
  26. if (title.startsWith('Download ')) {
  27. title = title.substring('Download '.length);
  28. }
  29. // Remove anything after " |"
  30. let pipeIndex = title.indexOf(' Torrent |');
  31. if (pipeIndex !== -1) {
  32. title = title.substring(0, pipeIndex);
  33. }
  34. return title;
  35. }
  36.  
  37. // Modify the H1 content on torrent pages to show the full title
  38. function modifyH1ContentOnTorrentPages() {
  39. if (window.location.pathname.startsWith('/torrent/')) {
  40. let h1Element = document.querySelector('.box-info-heading h1');
  41. if (h1Element) {
  42. let cleanedTitle = cleanTitle(document.title);
  43. h1Element.textContent = cleanedTitle;
  44. }
  45. }
  46. }
  47.  
  48. // Fetch the content of the link
  49. function fetchContent(link, onSuccess) {
  50. GM_xmlhttpRequest({
  51. method: 'GET',
  52. url: link.href,
  53. onload: function (response) {
  54. let parser = new DOMParser();
  55. let doc = parser.parseFromString(response.responseText, 'text/html');
  56. onSuccess(doc);
  57. },
  58. });
  59. }
  60.  
  61. // Process the link to update the title and add download buttons and images
  62. function processLink(link) {
  63. fetchContent(link, (doc) => {
  64. updateLinkTitle(link, doc);
  65. appendImages(link, doc);
  66. addDownloadButtons(link, doc);
  67. });
  68. }
  69.  
  70. // Update the link title
  71. function updateLinkTitle(link, doc) {
  72. let title = cleanTitle(doc.querySelector('title').innerText);
  73. link.innerText = title;
  74. }
  75.  
  76. // Add download buttons next to the link
  77. function addDownloadButtons(link, doc) {
  78. let torrentLink = doc.querySelector("a[href*='itorrents.org/torrent/']");
  79. let magnetLink = doc.querySelector("a[href^='magnet:?']");
  80.  
  81. let buttonsContainer = document.createElement('div');
  82. buttonsContainer.style.display = 'flex';
  83. buttonsContainer.style.alignItems = 'center';
  84. buttonsContainer.style.gap = '5px';
  85. buttonsContainer.style.marginTop = '10px';
  86.  
  87. // Torrent button
  88. let torrentButton = document.createElement('a');
  89. torrentButton.href = torrentLink ? torrentLink.href.replace('http:', 'https:') : '#';
  90. torrentButton.title = 'Download torrent file';
  91. torrentButton.innerHTML =
  92. '<i class="flaticon-torrent-download" style="color: #89ad19; font-size: 16px"></i>';
  93.  
  94. // Magnet button
  95. let magnetButton = document.createElement('a');
  96. magnetButton.href = magnetLink ? magnetLink.href : '#';
  97. magnetButton.title = 'Download via magnet';
  98. magnetButton.innerHTML =
  99. '<i class="flaticon-magnet" style="color: #da3a04; font-size: 16px"></i>';
  100.  
  101. buttonsContainer.appendChild(torrentButton);
  102. buttonsContainer.appendChild(magnetButton);
  103.  
  104. link.after(buttonsContainer);
  105. }
  106.  
  107. // Append images related to the torrent
  108. function appendImages(link, doc) {
  109. let images = doc.querySelectorAll('#description img');
  110. if (images.length > 0) {
  111. let flexContainer = document.createElement('div');
  112. flexContainer.style.display = 'flex';
  113. flexContainer.style.flexWrap = 'wrap';
  114. flexContainer.style.gap = '10px';
  115. flexContainer.style.marginTop = '10px';
  116.  
  117. let clonedImages = []; // Array to store cloned images
  118.  
  119. images.forEach((img, index) => {
  120. let clonedImg = img.cloneNode(true);
  121. if (img.hasAttribute('data-original')) {
  122. clonedImg.src = img.getAttribute('data-original');
  123. }
  124. clonedImg.style.maxHeight = '100px';
  125. clonedImg.style.setProperty('margin', '0', 'important');
  126.  
  127. // Show only the first VISIBLE_IMAGES images initially
  128. clonedImg.style.display = index < VISIBLE_IMAGES ? 'block' : 'none';
  129. flexContainer.appendChild(clonedImg);
  130. clonedImages.push(clonedImg); // Store the cloned image
  131. });
  132.  
  133. // Add "Show More/Less" button if there are more than VISIBLE_IMAGES images
  134. if (images.length > VISIBLE_IMAGES) {
  135. let showMoreButton = document.createElement('button');
  136. showMoreButton.textContent = 'Show More';
  137.  
  138. showMoreButton.onclick = function () {
  139. // Toggle visibility of additional images
  140. let isShowingMore = showMoreButton.textContent === 'Show Less';
  141. clonedImages.forEach((img, index) => {
  142. if (index >= VISIBLE_IMAGES) {
  143. img.style.display = isShowingMore ? 'none' : 'block';
  144. }
  145. });
  146. showMoreButton.textContent = isShowingMore ? 'Show More' : 'Show Less';
  147. };
  148.  
  149. flexContainer.appendChild(showMoreButton);
  150. }
  151.  
  152. link.parentNode.insertBefore(flexContainer, link.nextSibling);
  153.  
  154. clonedImages.forEach((clonedImg) => {
  155. // Mouseover event to show enlarged image
  156. clonedImg.addEventListener('mouseover', function () {
  157. showEnlargedImg(clonedImg.src);
  158. });
  159.  
  160. // Mousemove event to update the position of the enlarged image
  161. clonedImg.addEventListener('mousemove', updateEnlargedImgPosition);
  162.  
  163. // Mouseout event to remove enlarged image
  164. clonedImg.addEventListener('mouseout', function () {
  165. removeEnlargedImg();
  166. });
  167. });
  168. }
  169. }
  170.  
  171. // Function to show an enlarged image
  172. function showEnlargedImg(imgSrc) {
  173. const enlargedImg = document.createElement('img');
  174. enlargedImg.src = imgSrc;
  175. enlargedImg.style.position = 'fixed';
  176. enlargedImg.style.width = '500px';
  177. enlargedImg.style.height = '500px';
  178. enlargedImg.style.pointerEvents = 'none'; // Ignore pointer events
  179. enlargedImg.id = 'enlargedImg';
  180. document.body.appendChild(enlargedImg);
  181. }
  182.  
  183. // Function to update the position of the enlarged image
  184. function updateEnlargedImgPosition(e) {
  185. const enlargedImg = document.getElementById('enlargedImg');
  186. if (enlargedImg) {
  187. const viewportWidth = window.innerWidth;
  188. const viewportHeight = window.innerHeight;
  189. const imgWidth = 500; // Width of the enlarged image
  190. const imgHeight = 500; // Height of the enlarged image
  191. const offsetX = 10; // Horizontal offset from the cursor
  192. const offsetY = 10; // Vertical offset from the cursor
  193.  
  194. let leftPosition = e.clientX + offsetX;
  195. let topPosition = e.clientY + offsetY;
  196.  
  197. // Adjust position if the image goes out of the viewport
  198. if (leftPosition + imgWidth > viewportWidth) {
  199. leftPosition = e.clientX - imgWidth - offsetX;
  200. }
  201. if (topPosition + imgHeight > viewportHeight) {
  202. topPosition = e.clientY - imgHeight - offsetY;
  203. }
  204.  
  205. enlargedImg.style.left = leftPosition + 'px';
  206. enlargedImg.style.top = topPosition + 'px';
  207. }
  208. }
  209.  
  210. // Function to remove enlarged image
  211. function removeEnlargedImg() {
  212. const enlargedImg = document.getElementById('enlargedImg');
  213. if (enlargedImg) {
  214. document.body.removeChild(enlargedImg);
  215. }
  216. }
  217.  
  218. // Replace the link text with the title and append images
  219. function replaceLinkTextWithTitlesAndAppendImages() {
  220. let torrentLinks = listTorrentLinks();
  221. torrentLinks.forEach(processLink);
  222. }
  223.  
  224. function injectCustomCSS() {
  225. // Remove the max-width on the container
  226. GM_addStyle('.container { max-width: none !important; }');
  227. }
  228.  
  229. // Modify the function calls accordingly
  230. replaceLinkTextWithTitlesAndAppendImages();
  231. modifyH1ContentOnTorrentPages();
  232. injectCustomCSS();
  233. })();