MZ - 2D/3D Buttons

Adds 2D/3D buttons to certain pages

  1. // ==UserScript==
  2. // @name MZ - 2D/3D Buttons
  3. // @namespace douglaskampl
  4. // @version 1.6
  5. // @description Adds 2D/3D buttons to certain pages
  6. // @author Douglas
  7. // @match https://www.managerzone.com/?p=league*
  8. // @match https://www.managerzone.com/?p=friendlyseries*
  9. // @match https://www.managerzone.com/?p=cup*
  10. // @match https://www.managerzone.com/?p=private_cup*
  11. // @match https://www.managerzone.com/?p=national_teams*
  12. // @icon https://www.google.com/s2/favicons?sz=64&domain=managerzone.com
  13. // @grant none
  14. // @run-at document-idle
  15. // @license MIT
  16. // ==/UserScript==
  17.  
  18. (function () {
  19. 'use strict';
  20.  
  21. function processLeagueOrWorldLeaguePage() {
  22. const matchDate = parseDateFromHeader();
  23. if (matchDate && matchDate > new Date()) return;
  24. const tables = document.querySelectorAll('table.hitlist.marker');
  25. tables.forEach(t => {
  26. const rows = t.querySelectorAll('tbody tr');
  27. rows.forEach(r => {
  28. const link = r.querySelector('td:nth-child(2) a[href*="mid="]');
  29. if (!link) return;
  30. if (/X\s*-\s*X/i.test(link.textContent)) return;
  31. const mid = link.href.match(/mid=(\d+)/)?.[1];
  32. if (!mid) return;
  33. const td3 = r.querySelector('td:nth-child(3)');
  34. if (!td3 || td3.querySelector('.matchIcon')) return;
  35. td3.appendChild(createButtons(mid));
  36. });
  37. });
  38. }
  39.  
  40. function processFriendlyLeaguePage() {
  41. const matchDate = parseDateFromHeader();
  42. if (matchDate && matchDate > new Date()) return;
  43. const tables = document.querySelectorAll('table.hitlist.marker');
  44. tables.forEach(t => {
  45. const rows = t.querySelectorAll('tbody tr');
  46. rows.forEach(x => {
  47. const a = x.querySelector('td:nth-child(2) a[href*="mid="]');
  48. if (!a) return;
  49. if (/X\s*-\s*X/i.test(a.textContent)) return;
  50. const mid = a.href.match(/mid=(\d+)/)?.[1];
  51. if (!mid) return;
  52. const td3 = x.querySelector('td:nth-child(3)');
  53. if (!td3 || td3.querySelector('.matchIcon')) return;
  54. td3.appendChild(createButtons(mid));
  55. });
  56. });
  57. }
  58.  
  59. function processCupPage() {
  60. const t = document.querySelector('table.hitlist.marker');
  61. if (!t) return;
  62. const r = t.querySelectorAll('tbody tr');
  63. r.forEach(x => {
  64. const a = x.querySelector('td:nth-child(2) a[href*="mid="]');
  65. if (!a) return;
  66. if (/X\s*-\s*X/i.test(a.textContent)) return;
  67. const mid = a.href.match(/mid=(\d+)/)?.[1];
  68. if (!mid) return;
  69. const td3 = x.querySelector('td:nth-child(3)');
  70. if (!td3 || td3.querySelector('.matchIcon')) return;
  71. td3.appendChild(createButtons(mid));
  72. });
  73. }
  74.  
  75. function processNTPage() {
  76. const rows = document.querySelectorAll('td.bold[style*="white-space: nowrap"]');
  77. let lastMatchRow = null;
  78.  
  79. for (const row of rows) {
  80. const sibling = row.nextElementSibling;
  81. if (!sibling) continue;
  82.  
  83. const matchLink = sibling.querySelector('a[href*="mid="]');
  84. if (matchLink) {
  85. lastMatchRow = sibling;
  86. break;
  87. }
  88. }
  89.  
  90. if (!lastMatchRow) return;
  91. if (lastMatchRow.querySelector('.matchIcon')) return;
  92.  
  93. const matchLink = lastMatchRow.querySelector('a[href*="mid="]');
  94. if (!matchLink || /X\s*-\s*X/i.test(matchLink.textContent)) return;
  95.  
  96. const matchId = matchLink.href.match(/mid=(\d+)/)?.[1];
  97. if (!matchId) return;
  98.  
  99. const flags = lastMatchRow.querySelectorAll('img[src*="flags"]');
  100. if (flags.length >= 2) {
  101. flags[1].insertAdjacentElement('afterend', createButtons(matchId));
  102. } else {
  103. matchLink.insertAdjacentElement('afterend', createButtons(matchId));
  104. }
  105. }
  106.  
  107. function handlePage() {
  108. if (location.search.includes('p=league')) {
  109. processLeagueOrWorldLeaguePage();
  110. } else if (location.search.includes('p=friendlyseries')) {
  111. processFriendlyLeaguePage();
  112. } else if (location.search.includes('p=national_teams')) {
  113. processNTPage();
  114. } else {
  115. processCupPage();
  116. }
  117. }
  118.  
  119. function createButtons(matchId) {
  120. const btnContainer = document.createElement('span');
  121. const btn2d = document.createElement('a');
  122. btn2d.className = 'matchIcon shadow_soft';
  123. btn2d.href = `/?p=match&sub=result&type=2d&play=2d&mid=${matchId}`;
  124. btn2d.title = 'Watch match in 2D';
  125. btn2d.rel = 'nofollow';
  126. btn2d.style.fontSize = '9px';
  127. btn2d.style.height = '10px';
  128. btn2d.innerHTML = '<i>2D</i><span>&nbsp;2D&nbsp;</span>';
  129. btn2d.onclick = function(e) {
  130. e.preventDefault();
  131. powerboxCloseAll();
  132. mz.openGameLayer('2d', matchId);
  133. mz.noSleep.enable();
  134. return false;
  135. };
  136. const btn3d = document.createElement('a');
  137. btn3d.className = 'matchIcon shadow_soft inverted';
  138. btn3d.href = `/?p=match&sub=result&type=3d&play=3d&mid=${matchId}`;
  139. btn3d.title = 'Watch match in 3D';
  140. btn3d.rel = 'nofollow';
  141. btn3d.style.fontSize = '9px';
  142. btn3d.style.height = '10px';
  143. btn3d.style.margin = '0';
  144. btn3d.innerHTML = '<i>3D</i><span>&nbsp;3D&nbsp;</span>';
  145. btn3d.onclick = function(e) {
  146. e.preventDefault();
  147. powerboxCloseAll();
  148. mz.openGameLayer('3d', matchId);
  149. mz.noSleep.enable();
  150. return false;
  151. };
  152. btnContainer.appendChild(btn2d);
  153. btnContainer.appendChild(btn3d);
  154. return btnContainer;
  155. }
  156.  
  157. function parseDateFromHeader() {
  158. const h2 = document.querySelector('h2.subheader.clearfix');
  159. if (!h2) return null;
  160. const text = h2.textContent.trim();
  161. const match = text.match(/(\d{1,2}\/\d{1,2}\/\d{4})\s+(\d{1,2}:\d{2}(am|pm))/i);
  162. if (!match) return null;
  163. const [ , datePart, timePart ] = match;
  164. const [ d, m, y ] = datePart.split('/').map(n => parseInt(n, 10));
  165. const parts = timePart.match(/(\d{1,2}):(\d{2})(am|pm)/i);
  166. if (!parts) return null;
  167. let [ , hh, mm, ampm ] = parts;
  168. let h = parseInt(hh, 10);
  169. const min = parseInt(mm, 10);
  170. ampm = ampm.toLowerCase();
  171. if (ampm === 'pm' && h < 12) h += 12;
  172. if (ampm === 'am' && h === 12) h = 0;
  173. return new Date(y, m - 1, d, h, min, 0);
  174. }
  175.  
  176. let timeout = null;
  177. const observer = new MutationObserver(() => {
  178. if (!timeout) {
  179. timeout = setTimeout(() => {
  180. handlePage();
  181. timeout = null;
  182. }, 500);
  183. }
  184. });
  185. observer.observe(document.body, { childList: true, subtree: true });
  186. if (document.readyState === 'loading') {
  187. document.addEventListener('DOMContentLoaded', handlePage);
  188. } else {
  189. handlePage();
  190. }
  191. })();