// ==UserScript== // @name TMVN Club Transfer // @namespace https://trophymanager.com // @version 10 // @description Trophymanager: transfer statistics of all seasons, the most expensive players, the most successful trades, revenue from the academy... A gift for Vasco Vitkovice and Tirana Smokers. In addition, the script also saves data for for TMVN League Transfer script (https://greasyfork.org/en/scripts/416755). // @include https://trophymanager.com/club/* // @include https://trophymanager.com/club/*/ // @exclude https://trophymanager.com/club/ // @exclude https://trophymanager.com/club/*/squad/ // @grant none // @downloadURL none // ==/UserScript== (function () { 'use strict'; const APPLICATION_PARAM = { DEFAULT_TOP_COUNT: 10, TOP_COUNT_LOCAL_STORAGE_KEY: "TMVN_CLUB_TRANSFER_TOP_COUNT", DEFAULT_SHOW_MODE: "11111", SHOW_MODE_LOCAL_STORAGE_KEY: "TMVN_CLUB_TRANSFER_SHOW_MODE", SEASON_SHOW: 2 } const CLASS_NAME = { SUMMARY_TRANSFER: 'tmvn_club_transfer_script_classname_summary_transfer', ACADEMY_REVENUE: 'tmvn_club_transfer_script_classname_academy_revenue' } const CONTROL_ID = { INPUT_SHOW_MODE: 'tmvn_club_transfer_script_input_show_mode', BUTTON_SHOW_MODE: 'tmvn_club_transfer_script_button_show_mode_set', INPUT_TOP_COUNT: 'tmvn_club_transfer_script_input_top_count', BUTTON_TOP_COUNT: 'tmvn_club_transfer_script_button_top_count_set', BUTTON_SHOW_ALL_SUMMARY_TRANSFER: 'tmvn_club_transfer_script_button_show_all_summary_transfer', BUTTON_SHOW_ALL_ACADEMY_REVENUE: 'tmvn_club_transfer_script_button_show_all_academy_revenue' } const APPLICATION_COLOR = { AVERAGE: 'Aqua', TOTAL: 'Yellow' } var topCount; var boughtArr = []; var soldArr = []; var tradeArr = []; var academySoldMap = new Map(); var academySummary = []; var transferSummary = []; var playerMap = new Map(); var loadCount = 0; var loadDone = false; var clubId = location.href.split('/')[4]; var seasonIds = []; $.ajaxSetup({ async: false }); $.ajax('https://trophymanager.com/history/club/transfers/' + clubId, { type: "GET", dataType: 'html', crossDomain: true, success: function (response) { let comboSeason = $('#stats_season', response)[0].options; for (let i = 0; i < comboSeason.length; i++) { seasonIds.push(comboSeason[i].value); } }, error: function (e) {} }); $.ajaxSetup({ async: true }); if (clubId != "" && seasonIds.length > 0) { seasonIds.forEach((seasonId) => { $.ajax('https://trophymanager.com/history/club/transfers/' + clubId + '/' + seasonId, { type: "GET", dataType: 'html', crossDomain: true, success: function (response) { let tbl = $('.zebra.hover', response); if (tbl.length != 2) { return; } let trBuy = $('tr', tbl[0]); let playerId, playerName, price; for (let i = 1; i < trBuy.length; i++) { let td = $('td', trBuy[i]); if (td.length < 4) continue; let a = $('a', td[0]); if (a.length == 0) continue; playerName = a[0].innerText; playerId = a[0].getAttribute('player_link'); price = td[3].innerText.replace(/,/g, ''); setMap(playerId, playerName, seasonId, price, 1); } let trSell = $('tr', tbl[1]); for (let i = 1; i < trSell.length; i++) { let td = $('td', trSell[i]); if (td.length < 4) continue; let a = $('a', td[0]); if (a.length == 0) continue; playerName = a[0].innerText; playerId = a[0].getAttribute('player_link'); price = td[3].innerText.replace(/,/g, ''); setMap(playerId, playerName, seasonId, price, 2); } let tdArr = $('.zebra.hover td', response); if (tdArr.length >= 3) { var bought, sold, balance, quantity, average; bought = Math.round(tdArr[tdArr.length - 3].children[0].innerText.replace(/,/g, '')); sold = Math.round(tdArr[tdArr.length - 2].children[0].innerText.replace(/,/g, '')); balance = sold - bought; if (bought > 0 && sold > 0) { quantity = (tdArr.length - 3) / 4; } else if ((bought == 0 && sold > 0) || (bought > 0 && sold == 0)) { quantity = Math.round((tdArr.length - 4) / 4); //bug when has sell/buy players but all prices = 0 --> round and accept wrong result } else if (bought == 0 && sold == 0) { quantity = 0; } if (quantity == 0) { average = '0.0'; } else { average = ((sold + bought) / quantity).toFixed(1); } transferSummary.push({ Season: seasonId, Bought: bought, Sold: sold, Balance: balance, Quantity: quantity, Average: average }); } loadCount++; if (loadCount >= seasonIds.length) { loadDone = true; } }, error: function (e) {} }); }); } var myInterval = setInterval(append, 1000); function append() { if (!loadDone) { return; } clearInterval(myInterval); processPlayer(); boughtArr.sort((a, b) => parseFloat(b.Price) - parseFloat(a.Price)); soldArr.sort((a, b) => parseFloat(b.Price) - parseFloat(a.Price)); tradeArr.sort((a, b) => parseFloat(b.Profit) - parseFloat(a.Profit)); transferSummary.sort(function (a, b) { return b.Season - a.Season }); //order an object array processAcademy(); if (!(boughtArr.length == 0 && soldArr.length == 0 && tradeArr.length == 0)) { present(); } try { $('.banner_placeholder.rectangle')[0].parentNode.removeChild($('.banner_placeholder.rectangle')[0]); } catch (err) {} } //buyOrSell: 1 - buy, 2 - sell function setMap(playerId, playerName, seasonId, price, buyOrSell) { let player; if (playerMap.has(playerId)) { player = playerMap.get(playerId); player.Transaction.push({ SeasonBS: seasonId + '.' + buyOrSell, Price: price }); try { if (player.Name.trim() == '') { player.Name = playerName; //fix bug of TM not show playername } } catch (e) {} } else { player = { Id: playerId, Name: playerName, Transaction: [{ SeasonBS: seasonId + '.' + buyOrSell, Price: price } ] } playerMap.set(playerId, player); } } function processPlayer() { for (let[key, value]of playerMap) { value.Transaction.sort((a, b) => parseFloat(a.SeasonBS) - parseFloat(b.SeasonBS)); let waitSellForTrade = false; let buyForTrade; value.Transaction.forEach(tran => { let temp = tran.SeasonBS.split('.'); if (temp[1] == 1) { boughtArr.push({ Id: value.Id, Name: value.Name, Season: temp[0], Price: tran.Price }); waitSellForTrade = true; buyForTrade = tran.Price; } else { if (waitSellForTrade) { tradeArr.push({ Id: value.Id, Name: value.Name, Buy: buyForTrade, Sell: tran.Price, Profit: (tran.Price - buyForTrade).toFixed(1) }); soldArr.push({ Id: value.Id, Name: value.Name, Season: temp[0], Price: tran.Price, YoungAcademy: false }); } else { soldArr.push({ Id: value.Id, Name: value.Name, Season: temp[0], Price: tran.Price, YoungAcademy: true }); if (academySoldMap.has(temp[0])) { let academySoldSeasonData = academySoldMap.get(temp[0]); academySoldSeasonData.Quantity++; academySoldSeasonData.Sold += parseFloat(tran.Price); academySoldMap.set(temp[0], academySoldSeasonData); } else { academySoldMap.set(temp[0], { Quantity: 1, Sold: parseFloat(tran.Price) }); } } waitSellForTrade = false; } }); } } function processAcademy() { seasonIds.forEach((seasonId) => { if (academySoldMap.has(seasonId)) { let season = academySoldMap.get(seasonId); let seasonAverage = (Math.round(season.Sold) / season.Quantity).toFixed(1); academySummary.push({ Season: seasonId, Quantity: season.Quantity, Sold: Math.round(season.Sold), Average: seasonAverage }); } else { academySummary.push({ Season: seasonId, Quantity: 0, Sold: 0, Average: '0.0' }); } }); } function present() { let clubTransfer = "
" + "
" + "

Club Transfer (M)

" + "
" + "
" + "
" + "

TOP BOUGHT

" + "
" + "

TOP SOLD

" + "
" + "

TOP TRADE PROFIT

" + "
" + "

SUMMARY TRANSFER

" + "
" + "

ACADEMY REVENUE

" + "
" + "

CONFIG

" + "" + "Set Show Mode" + "" + "Set Top Count" + "
" + "
" + "
" + "
" + "
"; $(".column3_a").append(clubTransfer); document.getElementById(CONTROL_ID.BUTTON_SHOW_MODE).addEventListener('click', (e) => { setShowMode(); }); let showMode = localStorage.getItem(APPLICATION_PARAM.SHOW_MODE_LOCAL_STORAGE_KEY); if (showMode == null || showMode == "") { showMode = APPLICATION_PARAM.DEFAULT_SHOW_MODE; } $('#' + CONTROL_ID.INPUT_SHOW_MODE).val(showMode); document.getElementById(CONTROL_ID.BUTTON_TOP_COUNT).addEventListener('click', (e) => { setTopCount(); }); topCount = localStorage.getItem(APPLICATION_PARAM.TOP_COUNT_LOCAL_STORAGE_KEY); if (topCount == null || topCount == "") { topCount = APPLICATION_PARAM.DEFAULT_TOP_COUNT; } $('#' + CONTROL_ID.INPUT_TOP_COUNT).val(topCount); let invidualMode = showMode.split(""); if (invidualMode[0] == "1") { showTopBought(); } if (invidualMode[1] == "1") { showTopSold(); } if (invidualMode[2] == "1") { showTopTradeProfit(); } if (invidualMode[3] == "1") { showSummaryTransfer(); } if (invidualMode[4] == "1") { showAcademyRevenue(); } } function showTopBought() { if (boughtArr.length > 0) { var topBought_content = "" + ""; let rowCount = 0; for (let i = 0; i < boughtArr.length && i < topCount; i++) { rowCount++; let classOdd = ""; if ((rowCount % 2) == 1) { classOdd = "class='odd'"; } topBought_content += ''; } topBought_content += "
#PlayerSSPrice
' + (i + 1) + '. ' + '' + '' + boughtArr[i].Name + '' + '' + boughtArr[i].Season + '' + boughtArr[i].Price.toString().replace(/\B(?=(\d{3})+(?!\d))/g, ",") + '
"; $("#topBought_content").append(topBought_content); } } function showTopSold() { if (soldArr.length > 0) { var topSold_content = "" + ""; let rowCount = 0; for (let i = 0; i < soldArr.length && i < topCount; i++) { rowCount++; let classOdd = ""; if ((rowCount % 2) == 1) { classOdd = "class='odd'"; } if (soldArr[i].YoungAcademy) { topSold_content += ""; } else { topSold_content += ""; } topSold_content += ''; } topSold_content += "
#PlayerSSPrice
' + (i + 1) + '. ' + '' + '' + soldArr[i].Name + '' + '' + soldArr[i].Season + '' + soldArr[i].Price.toString().replace(/\B(?=(\d{3})+(?!\d))/g, ",") + '
"; $("#topSold_content").append(topSold_content); } } function showTopTradeProfit() { if (tradeArr.length > 0) { var topTrade_content = "" + ""; let rowCount = 0; for (let i = 0; i < tradeArr.length && i < topCount; i++) { rowCount++; let classOdd = ""; if ((rowCount % 2) == 1) { classOdd = "class='odd'"; } topTrade_content += ''; } topTrade_content += "
#PlayerBuySellProfit
' + (i + 1) + '. ' + '' + '' + tradeArr[i].Name + '' + '' + tradeArr[i].Buy.toString().replace(/\B(?=(\d{3})+(?!\d))/g, ",") + '' + tradeArr[i].Sell.toString().replace(/\B(?=(\d{3})+(?!\d))/g, ",") + '' + tradeArr[i].Profit.toString().replace(/\B(?=(\d{3})+(?!\d))/g, ",") + '
"; $("#topTrade_content").append(topTrade_content); } } function showSummaryTransfer() { let summaryTransfer_content = "" + ""; let totalBought = 0, totalSold = 0, totalQuantity = 0; let rowCount = 0; let seasonTrArr = []; transferSummary.forEach((summary) => { rowCount++; let trClass = "", display = ""; if (rowCount <= APPLICATION_PARAM.SEASON_SHOW) { if ((rowCount % 2) == 1) { trClass = "class='odd'"; } } else { display = "style='display:none'"; if ((rowCount % 2) == 1) { trClass = "class='odd " + CLASS_NAME.SUMMARY_TRANSFER + "'"; } else { trClass = "class='" + CLASS_NAME.SUMMARY_TRANSFER + "'"; } } let seasonTr = ''; seasonTrArr.push(seasonTr); totalBought += summary.Bought; totalSold += summary.Sold; totalQuantity += summary.Quantity; }); summaryTransfer_content += ''; summaryTransfer_content += ''; seasonTrArr.forEach((seasonTr) => { summaryTransfer_content += seasonTr; }); if (rowCount > APPLICATION_PARAM.SEASON_SHOW) { let buttonLabel = "Show all season " + seasonIds[seasonIds.length - 1] + " - " + seasonIds[0]; summaryTransfer_content += ""; } summaryTransfer_content += "
SSBuySell+-#Avg
' + summary.Season + '' + summary.Bought.toString().replace(/\B(?=(\d{3})+(?!\d))/g, ",") + '' + summary.Sold.toString().replace(/\B(?=(\d{3})+(?!\d))/g, ",") + '' + summary.Balance.toString().replace(/\B(?=(\d{3})+(?!\d))/g, ",") + '' + summary.Quantity + '' + summary.Average.toString().replace(/\B(?=(\d{3})+(?!\d))/g, ",") + '
Average' + (totalBought / transferSummary.length).toFixed(0).replace(/\B(?=(\d{3})+(?!\d))/g, ",") + '' + (totalSold / transferSummary.length).toFixed(0).replace(/\B(?=(\d{3})+(?!\d))/g, ",") + '' + (Math.round(totalSold / transferSummary.length) - Math.round(totalBought / transferSummary.length)).toFixed(0).replace(/\B(?=(\d{3})+(?!\d))/g, ",") + '' + (totalQuantity / transferSummary.length).toFixed(0) + '' + (totalQuantity > 0 ? ((totalSold + totalBought) / totalQuantity).toFixed(1).replace(/\B(?=(\d{3})+(?!\d))/g, ",") : 0) + '
Total' + totalBought.toString().replace(/\B(?=(\d{3})+(?!\d))/g, ",") + '' + totalSold.toString().replace(/\B(?=(\d{3})+(?!\d))/g, ",") + '' + (totalSold - totalBought).toString().replace(/\B(?=(\d{3})+(?!\d))/g, ",") + '' + totalQuantity.toString().replace(/\B(?=(\d{3})+(?!\d))/g, ",") + '' + '
" + "" + buttonLabel + "" + "
"; $("#summaryTransfer_content").append(summaryTransfer_content); if (rowCount > APPLICATION_PARAM.SEASON_SHOW) { document.getElementById(CONTROL_ID.BUTTON_SHOW_ALL_SUMMARY_TRANSFER).addEventListener('click', (e) => { showAll(CLASS_NAME.SUMMARY_TRANSFER, CONTROL_ID.BUTTON_SHOW_ALL_SUMMARY_TRANSFER); }); } localStorage.setItem(clubId + "_AVERAGE_TRANSFER", JSON.stringify({ "Time": new Date(), "Bought": Number((totalBought / transferSummary.length).toFixed(0)), "Sold": Number((totalSold / transferSummary.length).toFixed(0)), "Balance": Math.round(totalSold / transferSummary.length) - Math.round(totalBought / transferSummary.length), "Quantity": Number((totalQuantity / transferSummary.length).toFixed(0)), "Average": totalQuantity > 0 ? Number(((totalSold + totalBought) / totalQuantity).toFixed(1)) : 0, "SeasonCount": transferSummary.length })); } function showAcademyRevenue() { let academyRevenue_content = "" + ""; let totalSold = 0, totalQuantity = 0; let rowCount = 0; let seasonTrArr = []; academySummary.forEach((summary) => { rowCount++; let trClass = "", display = ""; if (rowCount <= APPLICATION_PARAM.SEASON_SHOW) { if ((rowCount % 2) == 1) { trClass = "class='odd'"; } } else { display = "style='display:none'"; if ((rowCount % 2) == 1) { trClass = "class='odd " + CLASS_NAME.ACADEMY_REVENUE + "'"; } else { trClass = "class='" + CLASS_NAME.ACADEMY_REVENUE + "'"; } } let seasonTr = ''; seasonTrArr.push(seasonTr); totalSold += summary.Sold; totalQuantity += summary.Quantity; }); academyRevenue_content += ''; academyRevenue_content += ''; seasonTrArr.forEach((seasonTr) => { academyRevenue_content += seasonTr; }); if (rowCount > APPLICATION_PARAM.SEASON_SHOW) { let buttonLabel = "Show all season " + seasonIds[seasonIds.length - 1] + " - " + seasonIds[0]; academyRevenue_content += ""; } academyRevenue_content += "
SSSell#Avg
' + summary.Season + '' + summary.Sold.toString().replace(/\B(?=(\d{3})+(?!\d))/g, ",") + '' + summary.Quantity + '' + summary.Average.toString().replace(/\B(?=(\d{3})+(?!\d))/g, ",") + '
Average' + (totalSold / academySummary.length).toFixed(0).replace(/\B(?=(\d{3})+(?!\d))/g, ",") + '' + (totalQuantity / academySummary.length).toFixed(0) + '' + (totalQuantity > 0 ? (totalSold / totalQuantity).toFixed(1).replace(/\B(?=(\d{3})+(?!\d))/g, ",") : 0) + '
Total' + totalSold.toString().replace(/\B(?=(\d{3})+(?!\d))/g, ",") + '' + totalQuantity.toString().replace(/\B(?=(\d{3})+(?!\d))/g, ",") + '' + '
" + "" + buttonLabel + "" + "
"; $("#academyRevenue_content").append(academyRevenue_content); if (rowCount > APPLICATION_PARAM.SEASON_SHOW) { document.getElementById(CONTROL_ID.BUTTON_SHOW_ALL_ACADEMY_REVENUE).addEventListener('click', (e) => { showAll(CLASS_NAME.ACADEMY_REVENUE, CONTROL_ID.BUTTON_SHOW_ALL_ACADEMY_REVENUE); }); } } function showAll(className, controlId) { let trArr = $('.' + className); for (let i = 0; i < trArr.length; i++) { trArr[i].style = 'display:""'; } $('#' + controlId)[0].style = 'display:none'; } function setShowMode() { let showMode = $('#' + CONTROL_ID.INPUT_SHOW_MODE)[0].value; if (showMode == '') { localStorage.removeItem(APPLICATION_PARAM.SHOW_MODE_LOCAL_STORAGE_KEY); } else if (!isValidShowMode(showMode)) { alert('Allowable show mode value has the form XXXXX where X is 0 or 1'); } else { localStorage.setItem(APPLICATION_PARAM.SHOW_MODE_LOCAL_STORAGE_KEY, showMode); alert('Set successful, please refresh'); } } function isValidShowMode(mode) { let arr = mode.split(''); if (arr.length != 5) return false; for (let i = 0; i < arr.length; i++) { if (arr[i] != '0' && arr[i] != '1') { return false; } } return true; } function setTopCount() { let topCount = $('#' + CONTROL_ID.INPUT_TOP_COUNT)[0].value; if (topCount == '') { localStorage.removeItem(APPLICATION_PARAM.TOP_COUNT_LOCAL_STORAGE_KEY); } else if (isNaN(topCount) || topCount <= 0) { alert('Top count must be positive integer'); } else { localStorage.setItem(APPLICATION_PARAM.TOP_COUNT_LOCAL_STORAGE_KEY, topCount); alert('Set successful, please refresh'); } } })();