import isURL from 'validator/lib/isURL'; import differenceInDays from 'date-fns/differenceInDays'; import getTranslations from './i18n/extendedTribeProfile'; import requestCreator from './libs/requestCreator'; import { setPage, getPage, generatePaginationItems, getContainerStyles, } from './utils/pagination'; import renderTodaysStats from './common/renderTodaysStats'; import showEnnoblementsPopup from './common/showEnnoblementsPopup'; import showHistoryPopup from './common/showHistoryPopup'; import showPopup from './utils/showPopup'; import getIDFromURL from './utils/getIDFromURL'; import getCurrentServer from './utils/getCurrentServer'; import { setItem, getItem } from './utils/localStorage'; import formatDate from './utils/formatDate'; import { formatPlayerURL } from './utils/twstats'; import { formatPlayerURL as formatPlayerURLTribalWars } from './utils/tribalwars'; // ==UserScript== // @name Extended Tribe Profile // @namespace https://github.com/tribalwarshelp/scripts // @updateURL https://raw.githubusercontent.com/tribalwarshelp/scripts/master/dist/extendedTribeProfile.js // @downloadURL https://raw.githubusercontent.com/tribalwarshelp/scripts/master/dist/extendedTribeProfile.js // @version 1.0.8 // @description Extended Tribe Profile // @author Kichiyaki http://dawid-wysokinski.pl/ // @match *://*/game.php*screen=info_ally* // @grant none // @run-at document-end // ==/UserScript== const SERVER = getCurrentServer(); const TRIBE_ID = getIDFromURL(window.location.search); const LOCAL_STORAGE_KEY = 'kichiyaki_extended_tribe_profile' + TRIBE_ID; const TRIBE_QUERY = ` query tribe($server: String!, $id: Int!, $playerFilter: PlayerFilter!, $dailyTribeStatsFilter: DailyTribeStatsFilter!) { tribe(server: $server, id: $id) { id bestRank bestRankAt mostPoints mostPointsAt mostVillages mostVillagesAt createdAt dominance } dailyTribeStats(server: $server, filter: $dailyTribeStatsFilter) { items { rank rankAtt rankDef rankTotal points scoreAtt scoreAtt scoreDef scoreTotal villages members } } players(server: $server, filter: $playerFilter) { items { id rankAtt rankDef rankSup rankTotal scoreAtt scoreAtt scoreDef scoreSup scoreTotal dailyGrowth } } } `; const ENNOBLEMENTS_QUERY = ` query ennoblements($server: String!, $filter: EnnoblementFilter!) { ennoblements(server: $server, filter: $filter) { total items { village { id name x y } oldOwner { id name } oldOwnerTribe { id tag } newOwner { id name } newOwnerTribe { id tag } ennobledAt } } } `; const ENNOBLEMENTS_PER_PAGE = 15; const TRIBE_HISTORY_AND_TRIBE_DAILY_STATS_QUERY = ` query tribeHistoryAndTribeDailyStats($server: String!, $tribeHistoryFilter: TribeHistoryFilter!, $dailyTribeStatsFilter: DailyTribeStatsFilter!) { tribeHistory(server: $server, filter: $tribeHistoryFilter) { total items { totalVillages points rank scoreAtt rankAtt scoreDef rankDef scoreTotal rankTotal createDate totalMembers } } dailyTribeStats(server: $server, filter: $dailyTribeStatsFilter) { items { points scoreAtt scoreDef scoreTotal villages createDate members } } } `; const TRIBE_HISTORY_PER_PAGE = 15; const TRIBE_MEMBERS_DAILY_STATS_QUERY = ` query tribeMembersDailyStats($server: String!, $filter: DailyPlayerStatsFilter!) { dailyPlayerStats(server: $server, filter: $filter) { items { player { id name } points scoreAtt scoreDef scoreSup scoreTotal villages createDate } } } `; let MEMBERS_GROWTH_MODE = 'points'; const TRIBE_CHANGES_QUERY = ` query tribeChanges($server: String!, $filter: TribeChangeFilter!) { tribeChanges(server: $server, filter: $filter) { total items { player { id name } newTribe { id tag } createdAt } } } `; const TRIBE_CHANGES_PAGINATION_CONTAINER_ID = 'tribeChangesPagination'; const TRIBE_CHANGES_PER_PAGE = 15; const profileInfoTBody = document.querySelector( '#content_value > table:nth-child(3) > tbody > tr > td:nth-child(1) > table > tbody' ); const actionsContainer = profileInfoTBody; const otherElementsContainer = document.querySelector( '#content_value > table:nth-child(3) > tbody > tr > td:nth-child(2)' ); const membersContainer = document.querySelector( '#content_value > table.vis > tbody' ); const translations = getTranslations(); const loadDataFromCache = () => { return getItem(LOCAL_STORAGE_KEY); }; const cacheTribeData = (data = {}) => { setItem(LOCAL_STORAGE_KEY, data); }; const getMemberIDs = () => { const ids = []; membersContainer.querySelectorAll('a').forEach((a) => { const href = a.getAttribute('href'); if (href.includes('info_player')) { ids.push(getIDFromURL(href)); } }); return ids; }; const getMemberNames = () => { const ids = []; membersContainer.querySelectorAll('a').forEach((a) => { if (a.getAttribute('href').includes('info_player')) { ids.push(a.innerText.trim()); } }); return ids; }; const loadData = async () => { const memberIDs = getMemberIDs(); const data = await requestCreator({ query: TRIBE_QUERY, variables: { server: SERVER, id: TRIBE_ID, dailyTribeStatsFilter: { sort: 'createDate DESC', limit: 1, tribeID: [TRIBE_ID], }, playerFilter: { sort: 'rank ASC', limit: memberIDs.length, id: memberIDs, }, }, }); cacheTribeData(data); return data; }; const renderTr = ({ title, data, id }) => { let tr = document.querySelector('#' + id); if (!tr) { tr = document.createElement('tr'); tr.id = id; tr.appendChild(document.createElement('td')); tr.appendChild(document.createElement('td')); profileInfoTBody.append(tr); } tr.children[0].innerHTML = title; tr.children[1].innerHTML = data; }; const extendMembersData = (players) => { membersContainer.parentElement.style.width = '100%'; const heading = membersContainer.querySelector('tr:first-child'); if (heading.children.length !== 11) { [ translations.oda, translations.odd, translations.ods, translations.od, translations.dailyGrowth, translations.playerLinks, ].forEach((v) => { const th = document.createElement('th'); th.innerHTML = v; heading.appendChild(th); }); } membersContainer.querySelectorAll('tr').forEach((tr) => { const a = tr.querySelector('a'); if (!a) { return; } const playerID = getIDFromURL(a.getAttribute('href')); const player = players.items.find((p) => p.id === playerID); if (player) { [ [player.scoreAtt, player.rankAtt], [player.scoreDef, player.rankDef], [player.scoreSup, player.rankSup], [player.scoreTotal, player.rankTotal], player.dailyGrowth, [formatPlayerURL(SERVER, player.id), 'TWStats'], ].forEach((data, index) => { let td = tr.children[5 + index]; if (!td) { td = document.createElement('td'); tr.appendChild(td); } if (Array.isArray(data)) { if (typeof data[0] === 'number') { td.innerHTML = `${data[0].toLocaleString()} (${ data[1] })`; } else if (isURL(data[0])) { td.innerHTML = `${data[1]}`; } } else if (typeof data === 'number') { td.innerHTML = data.toLocaleString(); } }); } }); }; const render = ({ tribe, dailyTribeStats, players }) => { [ { title: translations.createdAt + ':', data: formatDate(tribe.createdAt), id: 'created_at', }, { title: translations.dominance + ':', data: tribe.dominance.toFixed(2) + '%', id: 'dominance', }, { title: translations.bestRank + ':', data: tribe.bestRank + ' ' + `(${formatDate(tribe.bestRankAt)})`, id: 'best_rank', }, { title: translations.mostPoints + ':', data: tribe.mostPoints.toLocaleString() + ' ' + `(${formatDate(tribe.mostPointsAt)})`, id: 'most_points', }, { title: translations.mostVillages + ':', data: tribe.mostVillages + ' ' + `(${formatDate(tribe.mostVillagesAt)})`, id: 'most_villages', }, ].forEach((data) => { renderTr(data); }); if (dailyTribeStats && dailyTribeStats.items.length > 0) { renderTodaysStats(otherElementsContainer, dailyTribeStats.items[0]); } if (players && players.items.length > 0) { extendMembersData(players); } }; const handleShowTribeEnnoblementsClick = async (e) => { e.preventDefault(); const page = getPage(e.target); if (!isNaN(page)) { const data = await requestCreator({ query: ENNOBLEMENTS_QUERY, variables: { filter: { or: { oldOwnerTribeID: [TRIBE_ID], newOwnerTribeID: [TRIBE_ID], }, offset: ENNOBLEMENTS_PER_PAGE * (page - 1), limit: ENNOBLEMENTS_PER_PAGE, sort: 'ennobledAt DESC', }, server: SERVER, }, }); showEnnoblementsPopup(e, data.ennoblements, { currentPage: page, limit: ENNOBLEMENTS_PER_PAGE, onPageChange: handleShowTribeEnnoblementsClick, }); } }; const handleShowTribeHistoryClick = async (e) => { e.preventDefault(); const page = getPage(e.target); if (!isNaN(page)) { try { const filter = { tribeID: [TRIBE_ID], offset: TRIBE_HISTORY_PER_PAGE * (page - 1), limit: TRIBE_HISTORY_PER_PAGE, sort: 'createDate DESC', }; const { tribeHistory, dailyTribeStats } = await requestCreator({ query: TRIBE_HISTORY_AND_TRIBE_DAILY_STATS_QUERY, variables: { server: SERVER, tribeHistoryFilter: filter, dailyTribeStatsFilter: { ...filter, offset: filter.offset + 1, }, }, }); showHistoryPopup(e, tribeHistory, dailyTribeStats, { currentPage: page, limit: TRIBE_HISTORY_PER_PAGE, tribe: true, onPageChange: handleShowTribeHistoryClick, }); } catch (error) { console.log('cannot load tribe history', error); } } }; const getMembersGrowthTdStyle = (value) => { const statIncreaseStyle = 'color: #000; background-color: #0f0'; const statDecreaseStyle = 'color: #000; background-color: #f00'; const defaultStyle = 'color: #000; background-color: #808080'; return value > 0 ? statIncreaseStyle : value < 0 ? statDecreaseStyle : defaultStyle; }; const mapMembersGrowthTdValue = (i) => { switch (MEMBERS_GROWTH_MODE) { case 'points': return i.points; case 'villages': return i.villages; case 'od': return i.scoreTotal; case 'oda': return i.scoreAtt; case 'odd': return i.scoreDef; case 'ods': return i.scoreSup; default: return 0; } }; const buildMembersGrowthTBody = (stats) => { const dates = [ ...new Set(stats.items.map((item) => item.createDate)), ].reverse(); return `
${translations.date} | ${translations.player} | ${translations.act} | |
---|---|---|---|
${formatDate(tribeChange.createdAt)} | `; if (tribeChange.player) { rowHTML += `${tribeChange.player.name} | `; } else { rowHTML += '- | '; } rowHTML += `${ tribeChange.newTribe && tribeChange.newTribe.id === TRIBE_ID ? translations.joined : translations.left } | `; return rowHTML + '