// ==UserScript==
// @name TMVN Club Transfer
// @namespace https://trophymanager.com
// @version 11
// @description Trophymanager: transfer statistics of all seasons, the most expensive players, the most successful trades, revenue from the academy... It made by request of Vasco Vitkovice, Tirana Smokers, Bones and Langevåg IL. 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_SEASON_COUNT: 0,
SEASON_COUNT_LOCAL_STORAGE_KEY: "TMVN_CLUB_TRANSFER_SEASON_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',
INPUT_SEASON_COUNT: 'tmvn_club_transfer_script_input_season_count',
BUTTON_SEASON_COUNT: 'tmvn_club_transfer_script_button_season_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,
seasonCount;
seasonCount = localStorage.getItem(APPLICATION_PARAM.SEASON_COUNT_LOCAL_STORAGE_KEY);
if (seasonCount == null || seasonCount == "") {
seasonCount = APPLICATION_PARAM.DEFAULT_SEASON_COUNT;
}
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 (seasonCount > 0 && seasonCount < seasonIds.length) {
do {
seasonIds.pop();
} while (seasonCount < seasonIds.length);
}
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
" +
"
" +
"
Show Mode" +
"
" +
"
Top Count" +
"
" +
"
Season Count" +
"
" +
"" +
"
";
$(".column3_a").append(clubTransfer);
/*** SHOW MODE ***/
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);
/*********/
/*** TOP COUT ***/
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);
/*********/
/*** SEASON COUT ***/
document.getElementById(CONTROL_ID.BUTTON_SEASON_COUNT).addEventListener('click', (e) => {
setSeasonCount();
});
$('#' + CONTROL_ID.INPUT_SEASON_COUNT).val(seasonCount);
/*********/
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 = "" +
"# | Player | SS | Price |
";
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 +=
'' + (i + 1) + '. ' +
' | ' + '' + boughtArr[i].Name + '' +
' | ' + boughtArr[i].Season +
' | ' + boughtArr[i].Price.toString().replace(/\B(?=(\d{3})+(?!\d))/g, ",") +
' |
';
}
topBought_content += "
";
$("#topBought_content").append(topBought_content);
}
}
function showTopSold() {
if (soldArr.length > 0) {
var topSold_content = "" +
"# | Player | SS | Price |
";
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 +=
'' + (i + 1) + '. ' +
' | ' + '' + soldArr[i].Name + '' +
' | ' + soldArr[i].Season +
' | ' + soldArr[i].Price.toString().replace(/\B(?=(\d{3})+(?!\d))/g, ",") +
' |
';
}
topSold_content += "
";
$("#topSold_content").append(topSold_content);
}
}
function showTopTradeProfit() {
if (tradeArr.length > 0) {
var topTrade_content = "" +
"# | Player | Buy | Sell | Profit |
";
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 +=
'' + (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 += "
";
$("#topTrade_content").append(topTrade_content);
}
}
function showSummaryTransfer() {
let summaryTransfer_content = "" +
"SS | Buy | Sell | +- | # | Avg |
";
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 =
'' + 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, ",") +
' |
';
seasonTrArr.push(seasonTr);
totalBought += summary.Bought;
totalSold += summary.Sold;
totalQuantity += summary.Quantity;
});
summaryTransfer_content +=
'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) + ' |
';
summaryTransfer_content +=
'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, ",") + ' | ' +
' |
';
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 += "" + "" + buttonLabel + "" + " |
";
}
summaryTransfer_content += "
";
$("#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 = "" +
"SS | Sell | # | Avg |
";
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 =
'' + summary.Season +
' | ' + summary.Sold.toString().replace(/\B(?=(\d{3})+(?!\d))/g, ",") +
' | ' + summary.Quantity +
' | ' + summary.Average.toString().replace(/\B(?=(\d{3})+(?!\d))/g, ",") +
' |
';
seasonTrArr.push(seasonTr);
totalSold += summary.Sold;
totalQuantity += summary.Quantity;
});
academyRevenue_content +=
'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) + ' |
';
academyRevenue_content +=
'Total | ' +
totalSold.toString().replace(/\B(?=(\d{3})+(?!\d))/g, ",") + ' | ' +
totalQuantity.toString().replace(/\B(?=(\d{3})+(?!\d))/g, ",") + ' | ' +
' |
';
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 += "" + "" + buttonLabel + "" + " |
";
}
academyRevenue_content += "
";
$("#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');
}
}
function setSeasonCount() {
let seasonCount = $('#' + CONTROL_ID.INPUT_SEASON_COUNT)[0].value;
if (seasonCount == '') {
localStorage.removeItem(APPLICATION_PARAM.SEASON_COUNT_LOCAL_STORAGE_KEY);
} else if (isNaN(seasonCount) || seasonCount < 0) {
alert('Season count must be positive integer. Season count = 0 means all seasons.');
} else {
localStorage.setItem(APPLICATION_PARAM.SEASON_COUNT_LOCAL_STORAGE_KEY, seasonCount);
alert('Set successful, please refresh');
}
}
})();