MazyarTools

Mazyar Tools & Utilities

此脚本不应直接安装。它是供其他脚本使用的外部库,要使用该库请加入元指令 // @require https://update.cn-greasyfork.org/scripts/513041/1593345/MazyarTools.js

  1. // ==UserScript==
  2. // @name MazyarTools
  3. // @namespace http://tampermonkey.net/
  4. // @version 2.4
  5. // @description Mazyar Tools & Utilities
  6. // @copyright z7z from managerzone.com
  7. // @author z7z from managerzone.com
  8. // @license MIT
  9. // @grant GM_xmlhttpRequest
  10. // @match https://www.managerzone.com/*
  11. // @match https://test.managerzone.com/*
  12. // @icon https://www.google.com/s2/favicons?sz=64&domain=managerzone.com
  13. // @supportURL https://github.com/mz-ir/mazyar
  14. // ==/UserScript==
  15.  
  16. // --------------------------------------- Formatter -----------------------------
  17.  
  18. function mazyarFormatBigNumber(n, sep = " ") {
  19. if (n) {
  20. const numberString = n.toString();
  21. let formattedParts = [];
  22. for (let i = numberString.length - 1; i >= 0; i -= 3) {
  23. let part = numberString.substring(Math.max(i - 2, 0), i + 1);
  24. formattedParts.unshift(part);
  25. }
  26. return formattedParts.join(sep);
  27. }
  28. return "0";
  29. }
  30.  
  31. function mazyarFormatAverageAge(age, fractionDigits = 1) {
  32. if (age) {
  33. return age.toFixed(fractionDigits);
  34. }
  35. return "0.0";
  36. }
  37.  
  38. function mazyarFormatFileSize(b) {
  39. const s = 1024;
  40. let u = 0;
  41. while (b >= s || -b >= s) {
  42. b /= s;
  43. u++;
  44. }
  45. return (u ? b.toFixed(1) + " " : b) + " KMGTPEZY"[u] + "B";
  46. }
  47.  
  48. // -------------------------------- Parser -------------------------------------
  49.  
  50. function mazyarParseMzDate(dateString) {
  51. const [day, month, year] = dateString.split('-').map(Number);
  52. return new Date(year, month - 1, day);
  53. }
  54.  
  55. function mazyarParseMzDateTime(dateTimeString) {
  56. const [date, time] = dateTimeString.split(' ');
  57. const [day, month, year] = date.split('-').map(Number);
  58. const [hours, minutes] = time.split(':').map(Number);
  59. return new Date(year, month - 1, day, hours, minutes);
  60. }
  61.  
  62. function mazyarGenerateUuidV4() {
  63. return "xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx".replace(/[xy]/g, function (c) {
  64. const r = (Math.random() * 16) | 0,
  65. v = c == "x" ? r : (r & 0x3) | 0x8;
  66. return v.toString(16);
  67. });
  68. }
  69.  
  70. function mazyarIsFilterHitsValid(hits) {
  71. return typeof hits === "number" && hits >= 0;
  72. }
  73.  
  74. function mazyarHasDuplicates(array) {
  75. return new Set(array).size !== array.length;
  76. }
  77.  
  78. function mazyarExtractSportType(doc = document) {
  79. const zone = doc.querySelector("a#shortcut_link_thezone");
  80. if (zone) {
  81. return zone.href.indexOf("hockey") > -1 ? "hockey" : "soccer";
  82. }
  83. return "soccer";
  84. }
  85.  
  86. function mazyarExtractClubCurrency(doc) {
  87. const players = doc.getElementById("playerAltViewTable")?.querySelectorAll("tbody tr");
  88. if (players && players.length > 0) {
  89. const parts = players[0].querySelector("td:nth-child(3)")?.innerText.split(" ");
  90. return parts[parts.length - 1].trim();
  91. }
  92. return "";
  93. }
  94.  
  95. function mazyarExtractNationalCurrency(doc) {
  96. // works for both domestic and foreign countries
  97. const playerNode = doc.getElementById("thePlayers_0")?.querySelector("table tbody tr:nth-child(6)");
  98. if (playerNode) {
  99. const parts = playerNode.innerText.split(" ");
  100. return parts[parts.length - 1].trim();
  101. }
  102. return "";
  103. }
  104.  
  105. function mazyarExtractTeamId(link) {
  106. const regex = /tid=(\d+)/;
  107. const match = regex.exec(link);
  108. return match ? match[1] : null;
  109. }
  110.  
  111. function mazyarExtractPlayerIdFromProfileLink(link) {
  112. const regex = /pid=(\d+)/;
  113. const match = regex.exec(link);
  114. return match ? match[1] : null;
  115. }
  116.  
  117. function mazyarExtractMatchId(link) {
  118. const regex = /mid=(\d+)/;
  119. const match = regex.exec(link);
  120. return match ? match[1] : null;
  121. }
  122.  
  123. function mazyarExtractPlayerIdFromTransferMonitor(link) {
  124. const regex = /u=(\d+)/;
  125. const match = regex.exec(link);
  126. return match ? match[1] : null;
  127. }
  128.  
  129. function mazyarExtractPlayerIdFromContainer(player) {
  130. return player?.querySelector("h2 span.player_id_span")?.innerText;
  131. }
  132.  
  133. function mazyarIsMatchInProgress(resultText) {
  134. const scoreRegex = /\b(X|0|[1-9]\d*) - (X|0|[1-9]\d*)\b/;
  135. return !scoreRegex.test(resultText);
  136. }
  137.  
  138. function mazyarIsPlayerSentToCamp(doc) {
  139. return !!doc.querySelector(`#thePlayers_0 span.player_icon_wrapper i.fa-traffic-cone.tc-status-icon:not(.tc-status-icon--disabled)`);
  140. }
  141.  
  142. function mazyarExtractSkillNamesFromPlayerInfo(player) {
  143. const skills = player?.querySelectorAll("table.player_skills > tbody > tr > td > span.skill_name > span:first-child");
  144. return [...skills].map((el) => el.innerText);
  145. }
  146.  
  147. function mazyarExtractSkillsFromScoutReport(section, skillList) {
  148. const skills = section.querySelectorAll("div.flex-grow-1 ul li.blurred span");
  149. return [...skills].map((el) => skillList.indexOf(el.innerText));
  150. }
  151.  
  152. function mazyarExtractStarsFromScoutReport(section) {
  153. return section.querySelectorAll(".stars i.lit")?.length;
  154. }
  155.  
  156. function mazyarExtractResidencyDaysAndPrice(doc = document) {
  157. if (!doc) {
  158. return { days: 0, price: '' };
  159. }
  160. const transfers = doc?.querySelector("div.baz > div > div.win_back > table.hitlist");
  161. const history = transfers?.querySelector("tbody");
  162. if (history?.children.length > 1) {
  163. const arrived = history?.lastChild?.querySelector("td")?.innerText;
  164. const days = Math.floor((new Date() - mazyarParseMzDate(arrived)) / 86_400_000);
  165. const price = history.lastChild?.querySelector("td:last-child")?.innerText;
  166. const currency = transfers?.querySelector("thead tr td:last-child")?.innerText?.match(/.*\((.*)\)/)?.[1];
  167. return { days, price: price + ' ' + currency };
  168. }
  169. return { days: -1, price: '' };
  170. }
  171.  
  172. async function mazyarExtractPlayerProfile(playerId) {
  173. const url = `https://${location.hostname}/?p=players&pid=${playerId}`;
  174. const doc = await mazyarFetchHtml(url);
  175. if (doc) {
  176. const { days, price } = mazyarExtractResidencyDaysAndPrice(doc);
  177. const camp = mazyarIsPlayerSentToCamp(doc);
  178. const skills = doc.querySelectorAll("#thePlayers_0 table.player_skills tbody tr");
  179. let i = 0;
  180. const maxed = [];
  181. for (const skill of skills) {
  182. if (skill.querySelector(".maxed")) {
  183. maxed.push(i);
  184. }
  185. i++;
  186. }
  187. return {
  188. pid: playerId,
  189. maxed,
  190. days,
  191. price,
  192. camp,
  193. };
  194. }
  195. return null;
  196. }
  197.  
  198. function mazyarExtractPlayerNameFromContainer(player) {
  199. return player?.querySelector("span.player_name")?.innerText;
  200. }
  201.  
  202. async function mazyarFetchPlayerName(playerId) {
  203. const url = `https://${location.hostname}/?p=players&pid=${playerId}`;
  204. const doc = await mazyarFetchHtml(url);
  205. if (doc) {
  206. const profile = doc.getElementById("thePlayers_0");
  207. return mazyarExtractPlayerNameFromContainer(profile);
  208. }
  209. return null;
  210. }
  211.  
  212. async function mazyarExtractPlayerScoutReport(pid, skills, sport = "soccer") {
  213. const url = `https://${location.hostname}/ajax.php?p=players&sub=scout_report&pid=${pid}&sport=${sport}`;
  214. const doc = await mazyarFetchHtml(url);
  215. if (doc) {
  216. const report = doc.querySelectorAll(".paper-content.clearfix dl dd");
  217. if (report.length == 3) {
  218. const high = mazyarExtractStarsFromScoutReport(report[0]);
  219. const highSkills = mazyarExtractSkillsFromScoutReport(report[0], skills);
  220. const low = mazyarExtractStarsFromScoutReport(report[1]);
  221. const lowSkills = mazyarExtractSkillsFromScoutReport(report[1], skills);
  222. const trainingSpeed = mazyarExtractStarsFromScoutReport(report[2]);
  223. return {
  224. pid,
  225. H: high,
  226. HS: highSkills,
  227. L: low,
  228. LS: lowSkills,
  229. S: trainingSpeed,
  230. };
  231. }
  232. }
  233. return null;
  234. }
  235.  
  236. function mazyarExtractClubPlayersDetails(doc, currency) {
  237. const players = [];
  238. const playerNodes = doc.querySelectorAll("table#playerAltViewTable tr");
  239. for (const playerNode of playerNodes) {
  240. const age = playerNode.querySelector("td:nth-child(5)")?.innerText.replace(/\s/g, "");
  241. if (age) {
  242. const value = playerNode.querySelector("td:nth-child(3)")?.innerText.replaceAll(currency, "").replace(/\s/g, "");
  243. const shirtNumber = playerNode.querySelector("td:nth-child(0)")?.innerText.replace(/\s/g, "");
  244. const pid = playerNode.querySelector("a")?.href;
  245. players.push({
  246. shirtNumber,
  247. age: parseInt(age, 10),
  248. value: parseInt(value, 10),
  249. id: mazyarExtractPlayerIdFromProfileLink(pid),
  250. });
  251. }
  252. }
  253. return players;
  254. }
  255.  
  256. function mazyarExtractNumberOfFlags(infoTable) {
  257. const images = infoTable.getElementsByTagName("img");
  258. return images ? [...images].filter((img) => img.src.indexOf("/flags/") > -1).length : 0;
  259. }
  260.  
  261. function mazyarIsPlayerDomestic(infoTable) {
  262. return mazyarExtractNumberOfFlags(infoTable) === 1;
  263. }
  264.  
  265. function mazyarExtractNationalPlayersDetails(doc, currency) {
  266. const players = [];
  267. const playerNodes = doc.querySelectorAll("div.playerContainer");
  268. for (const playerNode of playerNodes) {
  269. const id = mazyarExtractPlayerIdFromProfileLink(playerNode.querySelector("h2 a")?.href);
  270. const infoTable = playerNode.querySelector("div.dg_playerview_info table");
  271. const age = infoTable.querySelector("tbody tr:nth-child(1) td strong").innerText;
  272. const selector = mazyarIsPlayerDomestic(infoTable) ? "tbody tr:nth-child(5) td span" : "tbody tr:nth-child(6) td span";
  273. const value = infoTable.querySelector(selector)?.innerText.replaceAll(currency, "").replace(/\s/g, "");
  274. players.push({
  275. age: parseInt(age, 10),
  276. value: parseInt(value, 10),
  277. id,
  278. });
  279. }
  280. return players;
  281. }
  282.  
  283. function mazyarGetNumberOfPlayers(players, ageLow = 0, ageHigh = 99) {
  284. return players.filter((player) => player.age <= ageHigh && player.age >= ageLow).length;
  285. }
  286.  
  287. // ----------------------------------- Fetch ---------------------------------
  288.  
  289. async function mazyarFetchHtmlWithGM(url, timeout = 10) {
  290. try {
  291. const response = await new Promise((resolve, reject) => {
  292. GM_xmlhttpRequest({
  293. url,
  294. // timeout: timeout * 1000,
  295. onload: (resp) => resolve(resp),
  296. onerror: reject
  297. });
  298. });
  299. const parser = new DOMParser();
  300. return parser.parseFromString(response.responseText, "text/html");
  301. } catch (error) {
  302. console.warn(error);
  303. return null;
  304. }
  305. }
  306.  
  307. async function mazyarFetchHtml(url) {
  308. return await fetch(url)
  309. .then((resp) => resp.text())
  310. .then((content) => {
  311. const parser = new DOMParser();
  312. return parser.parseFromString(content, "text/html");
  313. })
  314. .catch((error) => {
  315. console.warn(error);
  316. return null;
  317. });
  318. }
  319.  
  320. async function mazyarFetchXml(url) {
  321. return await fetch(url)
  322. .then((resp) => resp.text())
  323. .then((content) => {
  324. const parser = new DOMParser();
  325. return parser.parseFromString(content, "text/xml");
  326. })
  327. .catch((error) => {
  328. console.warn(error);
  329. return null;
  330. });
  331. }
  332.  
  333. async function mazyarFetchJson(url) {
  334. return await fetch(url)
  335. .then((resp) => resp.json())
  336. .catch((error) => {
  337. console.warn(error);
  338. return null;
  339. });
  340. }
  341.  
  342. function mazyarGetSquadSummaryUrl(tid) {
  343. return `https://${location.hostname}/?p=players&sub=alt&tid=${tid}`;
  344. }
  345.  
  346. function mazyarExtractSquadSummaryDetails(players, sport = "soccer") {
  347. if (!players) {
  348. return [];
  349. }
  350. const rows = [];
  351. if (sport === "hockey") {
  352. {
  353. const all = mazyarFilterPlayers(players);
  354. const top21 = mazyarFilterPlayers(players, 21);
  355. rows.push({
  356. title: "All",
  357. count: players.length,
  358. all: all.values,
  359. allAge: all.avgAge,
  360. top21: top21.values,
  361. top21Age: top21.avgAge,
  362. });
  363. }
  364. {
  365. const all = mazyarFilterPlayers(players, 0, 0, 23);
  366. const top21 = mazyarFilterPlayers(players, 21, 0, 23);
  367. rows.push({
  368. title: "U23",
  369. count: mazyarGetNumberOfPlayers(players, 0, 23),
  370. all: all.values,
  371. allAge: all.avgAge,
  372. top21: top21.values,
  373. top21Age: top21.avgAge,
  374. });
  375. }
  376. {
  377. const all = mazyarFilterPlayers(players, 0, 0, 21);
  378. const top21 = mazyarFilterPlayers(players, 21, 0, 21);
  379. rows.push({
  380. title: "U21",
  381. count: mazyarGetNumberOfPlayers(players, 0, 21),
  382. all: all.values,
  383. allAge: all.avgAge,
  384. top21: top21.values,
  385. top21Age: top21.avgAge,
  386. });
  387. }
  388. {
  389. const all = mazyarFilterPlayers(players, 0, 0, 18);
  390. const top21 = mazyarFilterPlayers(players, 21, 0, 18);
  391. rows.push({
  392. title: "U18",
  393. count: mazyarGetNumberOfPlayers(players, 0, 18),
  394. all: all.values,
  395. allAge: all.avgAge,
  396. top21: top21.values,
  397. top21Age: top21.avgAge,
  398. });
  399. }
  400. } else {
  401. {
  402. const all = mazyarFilterPlayers(players);
  403. const top16 = mazyarFilterPlayers(players, 16);
  404. const top11 = mazyarFilterPlayers(players, 11);
  405. rows.push({
  406. title: "All",
  407. count: players.length,
  408. all: all.values,
  409. allAge: all.avgAge,
  410. top16: top16.values,
  411. top16Age: top16.avgAge,
  412. top11: top11.values,
  413. top11Age: top11.avgAge,
  414. });
  415. }
  416. {
  417. const all = mazyarFilterPlayers(players, 0, 0, 23);
  418. const top16 = mazyarFilterPlayers(players, 16, 0, 23);
  419. const top11 = mazyarFilterPlayers(players, 11, 0, 23);
  420. rows.push({
  421. title: "U23",
  422. count: mazyarGetNumberOfPlayers(players, 0, 23),
  423. all: all.values,
  424. allAge: all.avgAge,
  425. top16: top16.values,
  426. top16Age: top16.avgAge,
  427. top11: top11.values,
  428. top11Age: top11.avgAge,
  429. });
  430. }
  431. {
  432. const all = mazyarFilterPlayers(players, 0, 0, 21);
  433. const top16 = mazyarFilterPlayers(players, 16, 0, 21);
  434. const top11 = mazyarFilterPlayers(players, 11, 0, 21);
  435. rows.push({
  436. title: "U21",
  437. count: mazyarGetNumberOfPlayers(players, 0, 21),
  438. all: all.values,
  439. allAge: all.avgAge,
  440. top16: top16.values,
  441. top16Age: top16.avgAge,
  442. top11: top11.values,
  443. top11Age: top11.avgAge,
  444. });
  445. }
  446. {
  447. const all = mazyarFilterPlayers(players, 0, 0, 18);
  448. const top16 = mazyarFilterPlayers(players, 16, 0, 18);
  449. const top11 = mazyarFilterPlayers(players, 11, 0, 18);
  450. rows.push({
  451. title: "U18",
  452. count: mazyarGetNumberOfPlayers(players, 0, 18),
  453. all: all.values,
  454. allAge: all.avgAge,
  455. top16: top16.values,
  456. top16Age: top16.avgAge,
  457. top11: top11.values,
  458. top11Age: top11.avgAge,
  459. });
  460. }
  461. }
  462. return rows;
  463. }
  464.  
  465. function mazyarFilterPlayers(players, count = 0, ageLow = 0, ageHigh = 99) {
  466. if (players.length === 0) {
  467. return { values: 0, avgAge: 0.0 };
  468. }
  469.  
  470. const n = count === 0 ? players.length : count;
  471. const filtered = players
  472. .filter((player) => player.age <= ageHigh && player.age >= ageLow)
  473. .sort((a, b) => b.value - a.value)
  474. .slice(0, n);
  475. if (filtered.length === 0) {
  476. return { values: 0, avgAge: 0.0 };
  477. }
  478. const values = filtered.map((player) => player.value).reduce((a, b) => a + b, 0);
  479. const avgAge = filtered.map((player) => player.age).reduce((a, b) => a + b, 0) / filtered.length;
  480. return { values, avgAge };
  481. }
  482.  
  483. async function mazyarFetchNationalPlayersAndCurrency(tid, sport) {
  484. const url = `https://${location.hostname}/ajax.php?p=nationalTeams&sub=players&ntid=${tid}&sport=${sport}`;
  485. const doc = await mazyarFetchHtml(url);
  486. if (doc) {
  487. const currency = mazyarExtractNationalCurrency(doc);
  488. const players = mazyarExtractNationalPlayersDetails(doc, currency);
  489. return { players, currency };
  490. }
  491. return { players: [], currency: '' };
  492. }
  493.  
  494. async function mazyarFetchClubPlayersAndCurrency(tid) {
  495. const url = mazyarGetSquadSummaryUrl(tid);
  496. const doc = await mazyarFetchHtml(url);
  497. if (doc) {
  498. const currency = mazyarExtractClubCurrency(doc);
  499. const players = mazyarExtractClubPlayersDetails(doc, currency);
  500. return { players, currency };
  501. }
  502. return { players: [], currency: '' };
  503. }
  504.  
  505. async function mazyarFetchPlayersAndCurrency(tid, sport) {
  506. const url = mazyarGetSquadSummaryUrl(tid);
  507. const isNational = await fetch(url, { method: "HEAD" })
  508. .then((resp) => (resp.url.search("p=national_teams") > -1));
  509. return isNational ? await mazyarFetchNationalPlayersAndCurrency(tid, sport) : await mazyarFetchClubPlayersAndCurrency(tid);
  510. }
  511.  
  512. function mazyarExtractClubTopPlyers(doc) {
  513. const currency = mazyarExtractClubCurrency(doc);
  514. const players = mazyarExtractClubPlayersDetails(doc, currency);
  515. const sport = mazyarExtractSportType(doc);
  516. const count = sport === "soccer" ? 11 : 21;
  517. return players ? mazyarFilterPlayers(players, count) : { values: 0, avgAge: 0 };
  518. }
  519.  
  520. async function mazyarExtractPlayersProfileDetails(teamId) {
  521. if (!teamId) {
  522. return null;
  523. }
  524. const url = `https://${location.hostname}/?p=players&tid=${teamId}`;
  525. const doc = await mazyarFetchHtml(url);
  526. if (doc) {
  527. const players = doc.getElementById("players_container")?.querySelectorAll("div.playerContainer");
  528. const info = {};
  529. for (const player of players) {
  530. const playerId = player.querySelector("span.player_id_span")?.innerText;
  531. const inMarket = [...player.querySelectorAll("a")].find((el) => el.href?.indexOf("p=transfer&sub") > -1);
  532. info[playerId] = {
  533. detail: player,
  534. shared: !!player.querySelector("i.special_player.fa-share-alt"),
  535. market: !!inMarket,
  536. marketLink: inMarket?.href,
  537. name: player.querySelector("span.player_name")?.innerText,
  538. age: player.querySelector(".dg_playerview_info tbody tr:nth-child(1) td:nth-child(1) strong")?.innerText,
  539. }
  540. }
  541. return info;
  542. }
  543. return null;
  544. }
  545.  
  546. // -------------------------------------------- Icons ------------------------------------------
  547.  
  548. function mazyarStartSpinning(element) {
  549. element.classList.add("fa-spin");
  550. }
  551.  
  552. function mazyarStopSpinning(element) {
  553. element.classList.remove("fa-spin");
  554. }
  555.  
  556. function mazyarCreateIconFromFontAwesomeClass(classes = [], title = "") {
  557. const icon = document.createElement("i");
  558. icon.classList.add(...classes);
  559. icon.setAttribute("aria-hidden", "true");
  560. icon.style.cursor = "pointer";
  561. if (title) {
  562. icon.title = title;
  563. }
  564. return icon;
  565. }
  566.  
  567. function mazyarCreateToggleIcon(title, isOn) {
  568. return mazyarCreateIconFromFontAwesomeClass(["fas", isOn ? "fa-toggle-on" : "fa-toggle-off"], title);
  569. }
  570.  
  571. function mazyarCreateMoveIcon(title) {
  572. return mazyarCreateIconFromFontAwesomeClass(["fa-solid", "fa-up-down-left-right"], title);
  573. }
  574.  
  575. function mazyarCreateSharedIcon(title) {
  576. return mazyarCreateIconFromFontAwesomeClass(["fa", "fa-share-alt"], title);
  577. }
  578.  
  579. function mazyarCreateMarketIcon(title) {
  580. return mazyarCreateIconFromFontAwesomeClass(["fa", "fa-legal"], title);
  581. }
  582.  
  583. function mazyarCreateCogIcon(title = "") {
  584. return mazyarCreateIconFromFontAwesomeClass(["fa", "fa-cog"], title);
  585. }
  586.  
  587. function mazyarCreateCommentIcon(title = "", style = null) {
  588. const icon = mazyarCreateIconFromFontAwesomeClass(["fa-solid", "fa-comment"], title);
  589. icon.style.cursor = "pointer";
  590. if (style?.fontSize) {
  591. icon.style.fontSize = style.fontSize;
  592. }
  593. if (style?.margin) {
  594. icon.style.margin = style.margin;
  595. }
  596. return icon
  597. }
  598.  
  599. function mazyarCreateSearchIcon(title = "") {
  600. return mazyarCreateIconFromFontAwesomeClass(["fa", "fa-search"], title);
  601. }
  602.  
  603. function mazyarCreateNoteIcon(title = "") {
  604. return mazyarCreateIconFromFontAwesomeClass(["fa-solid", "fa-note-sticky"], title);
  605. }
  606.  
  607. function mazyarCreateRefreshIcon(title = "") {
  608. return mazyarCreateIconFromFontAwesomeClass(["fa", "fa-refresh"], title);
  609. }
  610.  
  611. function mazyarCreateLegalIcon(title = "") {
  612. return mazyarCreateIconFromFontAwesomeClass(["fa", "fa-legal"], title);
  613. }
  614.  
  615. function mazyarCreateSignalIcon(title = "") {
  616. return mazyarCreateIconFromFontAwesomeClass(["fa-solid", "fa-signal-stream"], title);
  617. }
  618.  
  619. function mazyarCreateLoadingIcon(title = "") {
  620. const icon = mazyarCreateIconFromFontAwesomeClass(["fa", "fa-spinner", "fa-spin"], title);
  621. icon.style.cursor = "unset";
  622. return icon;
  623. }
  624.  
  625. function mazyarCreateLoadingIcon2(title = "") {
  626. const icon = mazyarCreateIconFromFontAwesomeClass(["fa-solid", "fa-loader", "fa-pulse", "fa-fw"], title);
  627. icon.style.cursor = "unset";
  628. return icon;
  629. }
  630.  
  631. function mazyarCreateTrashIcon(title = "", style = { fontSize: "1rem", margin: "unset" }) {
  632. const icon = mazyarCreateIconFromFontAwesomeClass(["fa-solid", "fa-trash", "discard-icon"], title);
  633. icon.style.cursor = "pointer";
  634. if (style?.fontSize) {
  635. icon.style.fontSize = style.fontSize;
  636. }
  637. if (style?.margin) {
  638. icon.style.margin = style.margin;
  639. }
  640. return icon;
  641. }
  642.  
  643. function mazyarCreateAddToDeadlineIcon(title, color) {
  644. const icon = mazyarCreateLegalIcon();
  645. icon.style.verticalAlign = "unset";
  646. icon.style.borderRadius = "50%";
  647. icon.style.border = "solid 1px";
  648. icon.style.padding = "3px";
  649.  
  650. const span = document.createElement("span");
  651. span.style.color = color;
  652. span.classList.add("floatRight");
  653. if (title) {
  654. span.title = title;
  655. }
  656. span.appendChild(icon);
  657. return span;
  658. }
  659.  
  660. function mazyarCreateHideFromTransferIcon(title) {
  661. const icon = mazyarCreateTrashIcon(title, { fontSize: "0.9rem" });
  662. icon.style.verticalAlign = "unset";
  663. icon.style.padding = "3px";
  664.  
  665. const span = document.createElement("span");
  666. span.classList.add("floatRight");
  667. if (title) {
  668. span.title = title;
  669. }
  670. span.appendChild(icon);
  671. return span;
  672. }
  673.  
  674. function mazyarCreateCommentIconForTransferResults(title) {
  675. const icon = mazyarCreateCommentIcon(title, { fontSize: "1.1rem" });
  676. icon.style.verticalAlign = "unset";
  677. icon.style.padding = "3px";
  678.  
  679. const span = document.createElement("span");
  680. span.classList.add("floatRight");
  681. if (title) {
  682. span.title = title;
  683. }
  684. span.appendChild(icon);
  685. return span;
  686. }
  687.  
  688. // -------------------------------- DOM Utils ------------------------------
  689.  
  690. async function mazyarGetTransferHistory(url) {
  691. const doc = await mazyarFetchHtml(url);
  692. if (doc) {
  693. const table = doc.querySelector("#transfer-history");
  694. const tbody = table.querySelector("tbody");
  695. tbody.querySelectorAll("tr:not(.bought, .sold)")?.forEach((child) => {
  696. tbody.removeChild(child);
  697. });
  698. return table;
  699. }
  700. return null;
  701. }
  702.  
  703. async function mazyarGetTableTransferHistories(table) {
  704. const teams = table.querySelectorAll("tbody tr.responsive-hide");
  705. const jobs = [];
  706. for (const team of teams) {
  707. const teamLink = team.querySelector("td:nth-child(2) a:last-child");
  708. const tid = mazyarExtractTeamId(teamLink?.href);
  709. const url = `https://${location.hostname}/?p=transfer_history&tid=${tid}`;
  710. jobs.push(mazyarGetTransferHistory(url).then((history) => {
  711. if (history) {
  712. const name = document.createElement("td");
  713. name.innerHTML = `For Team: <a style="text-decoration: none !important;" href="${url}">${teamLink?.innerText}</a>`;
  714. name.colSpan = 5;
  715. // name.style.backgroundColor = "khaki";
  716. name.style.fontWeight = "bold";
  717. name.style.padding = "10px 5px 5px";
  718. const tr = document.createElement("tr");
  719. tr.classList.add("mazyar-history-name", "hitlist-compact-list-column");
  720. tr.style.border = "2px solid darkgray";
  721. tr.appendChild(name);
  722. history.querySelector("tbody").prepend(tr);
  723. return history;
  724. }
  725. return null;
  726. }));
  727. }
  728. return (await Promise.all(jobs)).filter((h) => !!h);
  729. }
  730.  
  731. function mazyarFilterTransferHistory(history, weeks = 2) {
  732. history.filterResults = 0;
  733. const players = history?.querySelectorAll("tbody tr:not(.mazyar-history-name)");
  734. players?.forEach((child) => {
  735. const date = child.querySelector("td.hitlist-compact-list-column")?.firstChild?.nodeValue?.trim();
  736. if (Date.now() - mazyarParseMzDate(date) >= weeks * 7 * 24 * 60 * 60 * 1000) {
  737. child.style.display = 'none';
  738. } else {
  739. child.style.display = "table-row";
  740. history.filterResults += 1;
  741. }
  742. });
  743. }
  744.  
  745. function mazyarRemoveOldTransferHistory(history, weeks = 4) {
  746. const players = history?.querySelectorAll("tbody tr:not(.mazyar-history-name)");
  747. players?.forEach((child) => {
  748. const date = child.querySelector("td.hitlist-compact-list-column")?.firstChild?.nodeValue?.trim();
  749. if (Date.now() - mazyarParseMzDate(date) >= weeks * 7 * 24 * 60 * 60 * 1000) {
  750. child.parentNode.removeChild(child);
  751. }
  752. });
  753. }
  754.  
  755. function mazyarMakeElementDraggable(element, dragHandleElement, dragEndCallback = null) {
  756. let deltaX = 0, deltaY = 0, lastX = 0, lastY = 0;
  757.  
  758. dragHandleElement.style.cursor = "move";
  759. dragHandleElement.onmousedown = dragMouseDown;
  760.  
  761. function dragMouseDown(e) {
  762. e = e || window.event;
  763. e.preventDefault();
  764. // get the mouse cursor position at startup:
  765. lastX = e.clientX;
  766. lastY = e.clientY;
  767. document.onmouseup = closeDragElement;
  768. // call a function whenever the cursor moves:
  769. document.onmousemove = elementDrag;
  770. }
  771.  
  772. function elementDrag(e) {
  773. e = e || window.event;
  774. e.preventDefault();
  775.  
  776. // calculate the new cursor position:
  777. deltaX = lastX - e.clientX;
  778. deltaY = lastY - e.clientY;
  779. lastX = e.clientX;
  780. lastY = e.clientY;
  781.  
  782. // set the element's new position:
  783. let newTop = Math.max(0, element.offsetTop - deltaY);
  784. let newLeft = Math.max(0, element.offsetLeft - deltaX);
  785.  
  786. const { right, bottom, width, height } = element.getBoundingClientRect();
  787. if (right > window.innerWidth) {
  788. newLeft = window.innerWidth - width;
  789. }
  790. if (bottom > window.innerHeight) {
  791. newTop = window.innerHeight - height;
  792. }
  793.  
  794. element.style.top = newTop + "px";
  795. element.style.left = newLeft + "px";
  796. }
  797.  
  798. function closeDragElement() {
  799. // stop moving when mouse button is released:
  800. document.onmouseup = null;
  801. document.onmousemove = null;
  802. if (dragEndCallback) {
  803. dragEndCallback();
  804. }
  805. }
  806. }
  807.  
  808. function mazyarColorizeMaxedSkills(player, maxed = []) {
  809. if (maxed) {
  810. const playerSkills = player.querySelectorAll("table.player_skills tr td.skillval span");
  811. for (const skill of maxed) {
  812. playerSkills[skill]?.classList.add("maxed");
  813. }
  814. }
  815. }
  816.  
  817. function mazyarColorizeSkills(player, report = { H: 4, L: 2, HS: [0, 1], LS: [2, 3] }) {
  818. if (report) {
  819. const playerSkills = player?.querySelectorAll("table.player_skills tr td:nth-child(1)");
  820. playerSkills[report.HS[0]]?.classList.add("mazyar-scout-h", `mazyar-scout-${report.H}`);
  821. playerSkills[report.HS[1]]?.classList.add("mazyar-scout-h", `mazyar-scout-${report.H}`);
  822. playerSkills[report.LS[0]]?.classList.add(`mazyar-scout-${report.L}`);
  823. playerSkills[report.LS[1]]?.classList.add(`mazyar-scout-${report.L}`);
  824. }
  825. }
  826.  
  827. function mazyarGetMzButtonColorClass(color) {
  828. if (color) {
  829. if (color === "red") {
  830. return "button_red";
  831. } else if (color === "blue") {
  832. return "button_blue";
  833. } else if (color === "grey") {
  834. return "buttondiv_disabled";
  835. }
  836. }
  837. // green or other values
  838. return "button_account";
  839. }
  840.  
  841. function mazyarCreateMzStyledButton(title, color = "", floatDirection = null) {
  842. const div = document.createElement("div");
  843. div.style.margin = "auto 0.3rem";
  844. if (floatDirection) {
  845. // floatDirection: floatRight, floatLeft
  846. div.classList.add(floatDirection);
  847. }
  848.  
  849. const button = document.createElement("div");
  850. button.classList.add("mzbtn", "buttondiv", mazyarGetMzButtonColorClass(color));
  851. button.innerHTML = `<span class="buttonClassMiddle"><span style="white-space: nowrap">${title}</span></span><span class="buttonClassRight">&nbsp;</span>`;
  852.  
  853. div.appendChild(button);
  854. return div;
  855. }
  856.  
  857. function mazyarCreateSettingsSectionButton(html = "", style = { backgroundColor: null }) {
  858. const button = document.createElement("button");
  859. button.innerHTML = html;
  860. button.classList.add("mazyar-settings-section-button");
  861. if (style?.backgroundColor) {
  862. button.style.backgroundColor = style.backgroundColor;
  863. }
  864. return button;
  865. }
  866.  
  867. function mazyarCreateUpdateTip(version, url) {
  868. const div = document.createElement("div");
  869. div.classList.add("mazyar-update-tip");
  870. div.innerHTML = `
  871. <span><b>Update Available!</b></span><br />
  872. <button><a href="${url}" target="_blank">Install v${version}</a></button>`;
  873. return div;
  874. }
  875.  
  876. function mazyarCreateMzStyledCloseButton(closeCallback) {
  877. const close = document.createElement("div");
  878. close.classList.add("mazyar-cross-close-button");
  879.  
  880. close.innerHTML = `
  881. <span class="fa-stack fa-lg">
  882. <i class="fa fa-circle fa-stack-2x fa-inverse"></i>
  883. <i class="fa fa-close fa-stack-1x"></i>
  884. </span>`;
  885. if (closeCallback) {
  886. close.addEventListener("click", closeCallback);
  887. }
  888. return close;
  889. }
  890.  
  891. function mazyarCreateMzStyledModalHeader(text = "", closeCallback = null) {
  892. const header = document.createElement("div");
  893. header.classList.add("mazyar-flexbox-row", "mazyar-modal-header");
  894.  
  895. const title = document.createElement("span");
  896. title.innerText = text;
  897. title.style.flexGrow = "1";
  898. title.style.fontWeight = "bold";
  899. title.style.fontSize = "larger";
  900. title.style.padding = "5px";
  901.  
  902. header.appendChild(title);
  903.  
  904. if (closeCallback) {
  905. const close = mazyarCreateMzStyledCloseButton(closeCallback);
  906. header.appendChild(close);
  907. }
  908. return header;
  909. }
  910.  
  911. function mazyarCreateSuggestionList(items) {
  912. const datalist = document.createElement("datalist");
  913. datalist.id = mazyarGenerateUuidV4();
  914. for (const item of items) {
  915. const option = document.createElement("option");
  916. option.value = item.toString();
  917. datalist.appendChild(option);
  918. }
  919. return datalist;
  920. }
  921.  
  922. function mazyarCreateMenuTextInput(title = "input", placeholder = "example", datalistId = "") {
  923. const div = document.createElement("div");
  924. div.classList.add("mazyar-flexbox-row");
  925. div.style.justifyItems = "space-between";
  926. div.innerHTML = `
  927. <label style="margin: 0.5rem; font-weight: bold;">${title}: </label>
  928. <input list="${datalistId}" style="margin: 0.5rem;" type="text" value="" placeholder="${placeholder}">`;
  929. return div;
  930. }
  931.  
  932. function mazyarCreateSubMenuTextInput(title = "input", placeholder = "example", initialValue = 0, style = {
  933. margin: "0.1rem 2.2rem",
  934. inputSize: "5px"
  935. }) {
  936. const div = document.createElement("div");
  937. div.classList.add("mazyar-flexbox-row");
  938. div.style.justifyItems = "space-between";
  939. div.style.margin = style?.margin ?? "0.1rem 2.2rem";
  940. div.innerHTML = `
  941. <label style="margin-left: 0.5rem;">${title}: </label>
  942. <input style="margin-left: 0.5rem;" type="text" size="${style?.inputSize ?? "5px"}" placeholder="${placeholder}", value="${initialValue}">`;
  943. return div;
  944. }
  945.  
  946. function mazyarCreateMenuCheckBox(
  947. label,
  948. initialValue = true,
  949. style = {
  950. alignSelf: "flex-start",
  951. margin: "0.3rem 0.7rem",
  952. }
  953. ) {
  954. const id = mazyarGenerateUuidV4();
  955.  
  956. const div = document.createElement("div");
  957. div.style.alignSelf = style?.alignSelf ?? "flex-start";
  958. div.style.margin = style?.margin ?? "0.3rem 0.7rem";
  959.  
  960. const checkbox = document.createElement("input");
  961. checkbox.id = id;
  962. checkbox.type = "checkbox";
  963. checkbox.checked = initialValue;
  964.  
  965. const labelElement = document.createElement("label");
  966. labelElement.htmlFor = id;
  967. labelElement.innerHTML = label;
  968.  
  969. div.appendChild(checkbox);
  970. div.appendChild(labelElement);
  971. return div;
  972. }
  973.  
  974. function mazyarCreateMenuGroup(title = "") {
  975. const group = document.createElement("div");
  976. group.classList.add("mazyar-flexbox-column");
  977. group.style.alignSelf = "flex-start";
  978. group.style.alignItems = "flex-start";
  979. group.style.margin = "0.2rem 0.6rem";
  980. const header = document.createElement("h4");
  981. header.innerText = title;
  982. header.style.margin = "0.3rem 0rem";
  983. group.appendChild(header);
  984. return group;
  985. }
  986.  
  987. function mazyarAppendOptionList(parent, options, selected) {
  988. // options = a object full of 'key: {value, label}'
  989. for (const key in options) {
  990. if (options.hasOwnProperty(key)) {
  991. const child = document.createElement("option");
  992. child.value = options[key].value;
  993. child.innerText = options[key].label;
  994. if (child.value === selected) {
  995. child.selected = true;
  996. }
  997. parent.appendChild(child);
  998. }
  999. }
  1000. }
  1001.  
  1002. function mazyarCreateDropDownMenu(label, options, initialValue) {
  1003. // options = a object full of 'key: {value, label}'
  1004. // initialValue = one of the options.value
  1005.  
  1006. const div = document.createElement("div");
  1007. const labelElement = document.createElement("label");
  1008. const dropdown = document.createElement("select");
  1009.  
  1010. div.style.alignSelf = "flex-start";
  1011. div.style.margin = "0.3rem 0.7rem";
  1012.  
  1013. labelElement.innerText = label;
  1014. labelElement.style.paddingRight = "0.5rem";
  1015.  
  1016. mazyarAppendOptionList(dropdown, options, initialValue);
  1017.  
  1018. div.appendChild(labelElement);
  1019. div.appendChild(dropdown);
  1020. return div;
  1021. }
  1022.  
  1023. function mazyarCreateDeleteAllFiltersButton(title = "Delete", clickCallback = null) {
  1024. const div = document.createElement("div");
  1025. div.classList.add("mazyar-flexbox-row");
  1026. div.style.width = "100%";
  1027. const button = document.createElement("button");
  1028. button.classList.add("mazyar-button");
  1029. const icon = mazyarCreateTrashIcon(null, { fontSize: "0.9rem", margin: "1px 3px" });
  1030. const text = document.createElement("span");
  1031. text.innerText = title;
  1032. text.style.fontWeight = "bold";
  1033. button.appendChild(icon);
  1034. button.appendChild(text);
  1035. div.append(button);
  1036.  
  1037. button.style.margin = "4px";
  1038. button.style.padding = "3px";
  1039.  
  1040. if (clickCallback) {
  1041. button.addEventListener("click", clickCallback);
  1042. }
  1043.  
  1044. return div;
  1045. }
  1046.  
  1047. function mazyarCreateTableHeaderForFiltersView() {
  1048. const tr = document.createElement("tr");
  1049.  
  1050. const name = document.createElement("th");
  1051. name.classList.add("header");
  1052. name.innerText = "Name";
  1053. name.title = "Filter name";
  1054. name.style.textAlign = "left";
  1055. name.style.textDecoration = "none";
  1056. name.style.width = "11rem";
  1057.  
  1058. const totalHits = document.createElement("th");
  1059. totalHits.classList.add("header");
  1060. totalHits.innerText = "Total";
  1061. totalHits.title = "Total hits founds for this filter";
  1062. totalHits.style.textAlign = "center";
  1063. totalHits.style.textDecoration = "none";
  1064.  
  1065. const scoutHits = document.createElement("th");
  1066. scoutHits.classList.add("header");
  1067. scoutHits.innerText = "Scout";
  1068. scoutHits.title = "Hits found after applying scout filters";
  1069. scoutHits.style.textAlign = "center";
  1070. scoutHits.style.textDecoration = "none";
  1071.  
  1072. const tools = document.createElement("th");
  1073. tools.classList.add("header");
  1074. tools.innerHTML = " ";
  1075. tools.style.textAlign = "center";
  1076. tools.style.textDecoration = "none";
  1077.  
  1078. tr.appendChild(tools);
  1079. tr.appendChild(name);
  1080. tr.appendChild(totalHits);
  1081. tr.appendChild(scoutHits);
  1082.  
  1083. const thead = document.createElement("thead");
  1084. thead.appendChild(tr);
  1085. return thead;
  1086. }
  1087.  
  1088.  
  1089. function mazyarCreateTableHeaderForCommentsView() {
  1090. const tr = document.createElement("tr");
  1091.  
  1092. const pid = document.createElement("th");
  1093. pid.classList.add("header");
  1094. pid.innerText = "ID";
  1095. pid.title = "Player ID";
  1096. pid.style.textAlign = "left";
  1097. pid.style.textDecoration = "none";
  1098.  
  1099. const name = document.createElement("th");
  1100. name.classList.add("header");
  1101. name.innerText = "Name";
  1102. name.title = "Player Name";
  1103. name.style.textAlign = "left";
  1104. name.style.textDecoration = "none";
  1105. name.style.minWidth = "7rem";
  1106.  
  1107. const del = document.createElement("th");
  1108. del.classList.add("header");
  1109. del.innerHTML = " ";
  1110. del.style.textAlign = "center";
  1111. del.style.textDecoration = "none";
  1112.  
  1113. const view = document.createElement("th");
  1114. view.classList.add("header");
  1115. view.innerHTML = " ";
  1116. view.style.textAlign = "center";
  1117. view.style.textDecoration = "none";
  1118.  
  1119. tr.appendChild(del);
  1120. tr.appendChild(pid);
  1121. tr.appendChild(name);
  1122. tr.appendChild(view);
  1123.  
  1124. const thead = document.createElement("thead");
  1125. thead.appendChild(tr);
  1126. return thead;
  1127. }
  1128.  
  1129. function mazyarCreateToolbar() {
  1130. const toolbar = document.createElement("div");
  1131. const logo = document.createElement("span");
  1132. const menu = mazyarCreateCogIcon("Settings");
  1133. const note = mazyarCreateNoteIcon("Notebook");
  1134. const comments = mazyarCreateCommentIcon("Comments");
  1135. const live = mazyarCreateSignalIcon("In Progress Results");
  1136. const separator = document.createElement("span");
  1137. const transfer = document.createElement("div");
  1138. const transferIcon = mazyarCreateSearchIcon("Transfer");
  1139. const transferCount = document.createElement("span");
  1140.  
  1141. toolbar.id = "mazyar-toolbar-overlay";
  1142. toolbar.classList.add("mazyar-flexbox-column");
  1143.  
  1144. logo.innerText = "MZY";
  1145. logo.style.fontSize = "0.6rem";
  1146. logo.style.fontWeight = "bold";
  1147. logo.style.margin = "2px";
  1148. logo.style.padding = "1px";
  1149.  
  1150. menu.style.fontSize = "large";
  1151.  
  1152. note.style.fontSize = "large";
  1153. note.style.marginTop = "5px";
  1154.  
  1155. comments.style.fontSize = "large";
  1156. comments.style.marginTop = "5px";
  1157.  
  1158. live.style.fontSize = "large";
  1159. live.style.marginTop = "5px";
  1160. live.id = "mazyar-in-progress-icon";
  1161.  
  1162. transferIcon.style.fontSize = "large";
  1163.  
  1164. separator.innerText = "-------";
  1165. separator.style.textAlign = "center";
  1166. separator.style.fontSize = "0.6rem";
  1167. separator.style.fontWeight = "bolder";
  1168. separator.style.margin = "0";
  1169. separator.style.padding = "0";
  1170.  
  1171. transfer.classList.add("mazyar-flexbox-column");
  1172. transfer.style.cursor = "pointer";
  1173.  
  1174. transferCount.id = "mazyar-transfer-filter-hits";
  1175. transferCount.innerText = "0";
  1176. transferCount.style.fontSize = "0.6rem";
  1177. transferCount.style.fontWeight = "bold";
  1178. transferCount.style.margin = "1px 0";
  1179. transferCount.style.padding = "1px";
  1180.  
  1181. transfer.appendChild(transferIcon);
  1182. transfer.appendChild(transferCount);
  1183.  
  1184. toolbar.appendChild(logo);
  1185. toolbar.appendChild(menu);
  1186. toolbar.appendChild(note);
  1187. toolbar.appendChild(comments);
  1188. toolbar.appendChild(live);
  1189. toolbar.appendChild(separator);
  1190. toolbar.appendChild(transfer);
  1191.  
  1192. return { toolbar, menu, transfer, note, comments, live };
  1193. }
  1194.  
  1195. function mazyarCreateFiltersOverview(filters, label, labelColor = "black") {
  1196. const div = document.createElement("div");
  1197. div.classList.add("mazyar-flexbox-column");
  1198. div.style.minWidth = "250px";
  1199. div.style.marginBottom = "20px";
  1200. div.style.alignItems = "flex-start";
  1201.  
  1202. const header = document.createElement("div");
  1203. header.innerText = label;
  1204. header.style.color = labelColor;
  1205. header.style.fontWeight = "bolder";
  1206. header.style.padding = "5px";
  1207. header.style.alignSelf = "center";
  1208. div.appendChild(header);
  1209.  
  1210. const rows = document.createElement("div");
  1211. rows.classList.add("mazyar-flexbox-column");
  1212. rows.style.justifyContent = "left";
  1213. rows.style.margin = "8px";
  1214. div.appendChild(rows);
  1215.  
  1216. if (filters.soccer.length > 0 || filters.hockey.length > 0) {
  1217. if (filters.soccer.length > 0) {
  1218. const title = document.createElement("div");
  1219. title.classList.add("mazyar-import-sport-title");
  1220. title.innerHTML = "<b>Soccer:</b>";
  1221. rows.appendChild(title);
  1222. for (const filter of filters.soccer) {
  1223. const row = document.createElement("div");
  1224. row.classList.add("mazyar-import-filter-row");
  1225. row.innerHTML = `
  1226. <span>
  1227. name: <b style="color: ${labelColor}">${filter.name}</b>
  1228. </span>`;
  1229. rows.appendChild(row);
  1230. }
  1231. }
  1232. if (filters.hockey.length > 0) {
  1233. const title = document.createElement("div");
  1234. title.classList.add("mazyar-import-sport-title");
  1235. title.innerHTML = "<b>Hockey:</b>";
  1236. rows.appendChild(title);
  1237. for (const filter of filters.hockey) {
  1238. const row = document.createElement("div");
  1239. row.classList.add("mazyar-import-filter-row");
  1240. row.innerHTML = `
  1241. <span>
  1242. name: <b style="color: ${labelColor}">${filter.name}</b>
  1243. </span>`;
  1244. rows.appendChild(row);
  1245. }
  1246. }
  1247. } else {
  1248. rows.appendChild(document.createTextNode("No Filters"));
  1249. }
  1250.  
  1251. return div;
  1252. }
  1253.  
  1254. // -------------------------------- Monitor ------------------------------
  1255.  
  1256. function mazyarCreateSectionSeparatorForMonitor() {
  1257. const tr = document.createElement("tr");
  1258. tr.style.height = "10px";
  1259. tr.innerHTML = '<td></td>';
  1260. return tr;
  1261. }
  1262.  
  1263. function mazyarCreateRowSeparatorForMonitor(color) {
  1264. const tr = document.createElement("tr");
  1265. tr.classList.add("mazyar-monitor-player-row");
  1266. tr.style.height = "1px";
  1267. tr.style.backgroundColor = color;
  1268. tr.innerHTML = '<td></td>';
  1269. return tr;
  1270. }
  1271.  
  1272. function monitorAddRowSeparator() {
  1273. return [
  1274. mazyarCreateRowSeparatorForMonitor("#999999"),
  1275. mazyarCreateRowSeparatorForMonitor("#FFFFFF")
  1276. ];
  1277. }
  1278.  
  1279. function mazyarCreateSectionForMonitor(title, id) {
  1280. const tr = document.createElement("tr");
  1281. tr.innerHTML = `
  1282. <td>
  1283. <div id="${id}">
  1284. <table width="100%" cellpadding="0" cellspacing="0">
  1285. <tbody>
  1286. <tr>
  1287. <td style="background-image: url(img/subheader_right.gif);">
  1288. <table border="0" cellpadding="0" cellspacing="0" width="100%">
  1289. <tbody>
  1290. <tr>
  1291. <td class="subheader" valign="bottom">${title}</td>
  1292. </tr>
  1293. </tbody>
  1294. </table>
  1295. </td>
  1296. </tr>
  1297. </tbody>
  1298. </table>
  1299. </div>
  1300. </td>`;
  1301. return tr;
  1302. }
  1303.  
  1304. function mazyarClearPlayerRowsInMonitor(tbody) {
  1305. const players = tbody.querySelectorAll(".mazyar-monitor-player-row");
  1306. for (const player of players) {
  1307. tbody.removeChild(player);
  1308. }
  1309. }
  1310.  
  1311. async function mazyarFetchPlayerMarketDetail(pid, sport = "soccer") {
  1312. const url = `https://${location.hostname}/ajax.php?p=transfer&sub=transfer-search&sport=${sport}&u=${pid}`;
  1313. const result = await mazyarFetchJson(url);
  1314. if (result) {
  1315. if (result.totalHits > 0) {
  1316. const parser = new DOMParser();
  1317. const playerDiv = parser.parseFromString(result?.players, "text/html").body.firstChild;
  1318. const deadline = playerDiv.querySelector(".transfer-control-area div.box_dark:nth-child(1) table:nth-child(1) tr:nth-child(3) strong")?.innerText;
  1319. const fee = playerDiv.querySelector(".transfer-control-area > div > div:nth-child(1) > table > tbody > tr:last-child strong")?.innerText;
  1320. const latestBid = playerDiv.querySelector(".transfer-control-area > div > div:nth-child(2) > table > tbody > tr:last-child strong")?.innerText;
  1321. const flag = playerDiv.querySelector(`img[src*="/flags/"]`)?.src;
  1322. const player = {
  1323. name: playerDiv.querySelector(".player_name")?.innerText,
  1324. pid,
  1325. deadline: 1 + Math.ceil((mazyarParseMzDateTime(deadline.trim()) - new Date()) / 60_000),
  1326. deadlineFull: deadline.trim(),
  1327. latestBid,
  1328. fee,
  1329. source: "mzy",
  1330. flag,
  1331. };
  1332. return { player, remove: false };
  1333. }
  1334. return { player: null, remove: true };
  1335. }
  1336. return { player: null, remove: false };
  1337. }
  1338.  
  1339. async function mazyarFetchTrainingCampDetail() {
  1340. const url = `https://${location.hostname}/?p=training_camp`;
  1341. const doc = await mazyarFetchHtml(url);
  1342. if (doc) {
  1343. const players = doc.querySelectorAll("#training_camp_players_container div.tc_table_container");
  1344. const detail = {};
  1345. for (const player of players) {
  1346. const pid = mazyarExtractPlayerIdFromProfileLink(player.querySelector(".player_link")?.href);
  1347. const daysFull = player.querySelector(".tc_table_duration > div:nth-child(2)")?.innerText;
  1348. detail[pid] = {
  1349. days: daysFull?.split(": ")?.[1],
  1350. }
  1351. }
  1352. return detail;
  1353. }
  1354. return null;
  1355. }
  1356.  
  1357. function mazyarCreatePlayerRowForMonitor(
  1358. player = { pid: "", name: "", deadline: 0, deadlineFull: "", latestBid: "", flag: "" },
  1359. timeout = 0) {
  1360. const tr = document.createElement("tr");
  1361. tr.classList.add("mazyar-monitor-player-row");
  1362. if (player.deadline <= timeout) {
  1363. tr.classList.add("mazyar-deadline-monitor-throb");
  1364. }
  1365. tr.innerHTML = `
  1366. <td valign="top" style="" width="100%">
  1367. <table width="100%" border="0">
  1368. <tbody>
  1369. <tr style="height: 25px;">
  1370. <td colspan="2">
  1371. <table cellpadding="0" cellspacing="0" width="100%" border="0">
  1372. <tbody>
  1373. <tr>
  1374. <td width="220">
  1375. <table>
  1376. <tbody>
  1377. <tr>
  1378. <td><img src="${player.flag}"></td>
  1379. <td><a target="_blank", href="/?p=transfer&sub=players&u=${player.pid}">${player.name}</a></td>
  1380. <td></td>
  1381. </tr>
  1382. </tbody>
  1383. </table>
  1384. </td>
  1385. <td>
  1386. <table class="deadline-table">
  1387. <tbody>
  1388. <tr>
  1389. <td><img src="img/icon_deadline.gif" width="13" height="15"></td>
  1390. <td>${player.deadlineFull}</td>
  1391. </tr>
  1392. </tbody>
  1393. </table>
  1394. </td>
  1395. <td align="right">
  1396. <table border="0">
  1397. <tbody>
  1398. <tr>
  1399. <td>Latest bid:</td>
  1400. <td align="right" style="font-size: 11px; font-weight: bold;">${player.latestBid}</td>
  1401. <td>&nbsp;</td>
  1402. </tr>
  1403. </tbody>
  1404. </table>
  1405. </td>
  1406. </tr>
  1407. </tbody>
  1408. </table>
  1409. </td>
  1410. </tr>
  1411. </tbody>
  1412. </table>
  1413. </td>`;
  1414. return tr;
  1415. }
  1416.  
  1417. // -------------------------------- Tools ------------------------------
  1418.  
  1419. function mazyarConvertFilterArrayToFilterObject(filters) {
  1420. return filters?.reduce((filter, { id, name, params, scout, interval }) => {
  1421. filter[name] = { id, name, params, scout, interval };
  1422. return filter;
  1423. }, {});
  1424. }
  1425.  
  1426. function mazyarMergeFilters(a = [], b = []) {
  1427. // 'b' members could replace 'a' members
  1428. const aObj = mazyarConvertFilterArrayToFilterObject(a);
  1429. const bObj = mazyarConvertFilterArrayToFilterObject(b);
  1430. return Object.values({ ...aObj, ...bObj });
  1431. }