Advertisement
arekay115

duels stats csv

Apr 22nd, 2025
15
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
text 28.35 KB | None | 0 0
  1. // ==UserScript==
  2. // @name duels stats csv
  3. // @namespace http://tampermonkey.net/
  4. // @version 6.0
  5. // @description Fetches Geoguessr API data to get advanced stats for duel games and displays them on the profile page.
  6. // @author You
  7. // @match https://www.geoguessr.com/*/me/profile
  8. // @match https://www.geoguessr.com/me/profile
  9. // @icon https://www.geoguessr.com/_next/static/media/favicon.bffdd9d3.png
  10.  
  11. // @grant GM_xmlhttpRequest
  12. // @grant GM_addStyle
  13. // @require https://code.jquery.com/jquery-3.6.0.min.js
  14. // @require https://unpkg.com/[email protected]/dist/axios.min.js
  15. // @require https://cdn.jsdelivr.net/npm/[email protected]/dist/progressbar.min.js
  16. // @require https://cdn.jsdelivr.net/npm/[email protected]/dist/chart.min.js
  17. // @connect https://game-server.geoguessr.com/
  18. // ==/UserScript==
  19.  
  20. (function() {
  21. 'use strict';
  22.  
  23. //*** Constants and Variables ***//
  24. // Constants
  25. const API_BASE_URL = 'https://game-server.geoguessr.com/api/duels';
  26.  
  27. // Variables
  28. let playerId = '';
  29.  
  30.  
  31. //*** Helper Functions ***//
  32. // Function to convert JSON to CSV
  33. function jsonToCsv(json) {
  34. console.log(json)
  35. const keys = Object.keys(json[0]);
  36. const csv = json.map(row =>
  37. keys.map(key => JSON.stringify(row[key], (_, value) => value === null ? '' : value)).join(',')
  38. );
  39.  
  40. return [keys.join(','), ...csv].join('\r\n');
  41. }
  42.  
  43. //delay setup
  44. function delay(ms) {
  45. return new Promise(resolve => setTimeout(resolve, ms));
  46. }
  47.  
  48. // Function to download a CSV file
  49. function downloadCsv(data, filename) {
  50. const blob = new Blob([data], { type: 'text/csv;charset=utf-8;' });
  51. const url = URL.createObjectURL(blob);
  52. const link = document.createElement("a");
  53. link.setAttribute("href", url);
  54.  
  55. // Correct replacement string
  56. const baseFilename = filename.replace(/ - (\d{4}-\d{2}-\d{2})T(\d{2})(\d{2})(\d{2})\.\d{3}/, ' - $1-$2$3');
  57. link.setAttribute("download", baseFilename);
  58.  
  59. link.style.visibility = 'hidden';
  60. document.body.appendChild(link);
  61. link.click();
  62. document.body.removeChild(link);
  63. }
  64.  
  65. // Function to count new duels
  66. function countNewDuels(gameIds, lastDownloadDate) {
  67. if (!lastDownloadDate) {
  68. // If no previous timestamp is found, all duels are considered "new"
  69. return gameIds.length;
  70. }
  71.  
  72. // Count the duels with timestamps later than the last download timestamp
  73. const newDuels = gameIds.filter(game => new Date(game.time) > lastDownloadDate);
  74. console.log(`${newDuels.length} new duels found since last download.`);
  75. return newDuels.length;
  76. }
  77.  
  78. //*** API Interactions ***//
  79. // Function to get game IDs - Phase 1
  80. async function getGameIds(session) {
  81. const startTime = new Date(); // Start time of getGameIds
  82. console.log("getGameIds started at:", startTime.toLocaleString());
  83.  
  84. const gameIds = [];
  85. let paginationToken = null;
  86.  
  87. try {
  88. while (true) {
  89. const response = await session.get('https://www.geoguessr.com/api/v4/feed/private', { params: { paginationToken } });
  90. const data = response.data;
  91. paginationToken = data.paginationToken;
  92.  
  93. if (!playerId && data.entries.length > 0) {
  94. playerId = data.entries[0].user.id;
  95. console.log("Player ID:", playerId);
  96. }
  97.  
  98. data.entries.forEach(entry => {
  99. try {
  100. extractGameIds(entry, gameIds);
  101. } catch (error) {
  102. console.error(error);
  103. }
  104. });
  105.  
  106. if (!paginationToken) break;
  107. }
  108. } catch (error) {
  109. console.error("An error occurred while fetching game IDs:", error);
  110. }
  111. console.log("Number of Game IDs found:", gameIds.length);
  112.  
  113. const endTimePhase1 = new Date(); // End time after game IDs are fetched
  114. const durationPhase1 = (endTimePhase1 - startTime) / 1000; // Duration in seconds
  115. console.log("getGameIds finished at:", endTimePhase1.toLocaleString());
  116. console.log("Time taken for getGameIds:", durationPhase1, "seconds");
  117.  
  118. gameIds.sort((a, b) => new Date(a.time) - new Date(b.time)); // Crucial sort!
  119.  
  120. const gameIdsCsv = jsonToCsv(gameIds.map((gameId, index) => ({
  121. duel_id: gameId.id,
  122. duel_datetime: gameId.time,
  123. duel_type: gameId.gameMode,
  124. duel_mode: gameId.competitiveGameMode
  125. })));
  126.  
  127. downloadCsv(gameIdsCsv, 'newDuels.csv');
  128. return gameIds;
  129. }
  130.  
  131. // extract game IDs
  132. function extractGameIds(entry, gameIds) {
  133. try {
  134. const payloadJson = JSON.parse(entry.payload);
  135.  
  136. if (Array.isArray(payloadJson)) {
  137. payloadJson.forEach(payloadItem => {
  138. let gameData = null;
  139. if (payloadItem.payload && payloadItem.payload.gameMode === 'Duels') {
  140. gameData = payloadItem.payload;
  141. } else if (payloadItem.gameMode === 'Duels') {
  142. gameData = payloadItem;
  143. }
  144.  
  145. if (gameData) { // Only proceed if gameData is found
  146. const gameTime = payloadItem.time || "Not Applicable";
  147. const gameMode = gameData.gameMode || "Not Applicable";
  148. const competitiveGameMode = gameData.competitiveGameMode || "Not Applicable";
  149. const gameId = gameData.gameId; // Extract gameId
  150.  
  151. if (gameMode === 'Duels' && gameData.partyId === undefined) {
  152. gameIds.push({
  153. id: gameId,
  154. time: gameTime,
  155. gameMode: gameMode,
  156. competitiveGameMode: competitiveGameMode
  157. });
  158. }
  159. }
  160. });
  161. } else if (payloadJson && payloadJson.gameMode === 'Duels') { // Handle single object case
  162. const gameTime = entry.time || "Not Applicable"; // Use entry.time for single object case
  163. const gameMode = payloadJson.gameMode || "Not Applicable";
  164. const competitiveGameMode = payloadJson.competitiveGameMode || "Not Applicable";
  165. const gameId = payloadJson.gameId;
  166.  
  167. if (payloadJson.gameMode === 'Duels' && payloadJson.partyId === undefined) {
  168. gameIds.push({
  169. id: gameId,
  170. time: gameTime,
  171. gameMode: gameMode,
  172. competitiveGameMode: competitiveGameMode
  173. });
  174. }
  175. }
  176.  
  177. } catch (error) {
  178. console.error("Error parsing payload:", error, entry.payload);
  179. }
  180. }
  181.  
  182. // function to fetch duels - Phase 2 - iterates through the gameIds and feches data
  183. async function fetchDuels(session, gameIds) {
  184. const duels = [];
  185. for (const gameId of gameIds) {
  186. let response = null; // Declare response here, initialize to null
  187. try {
  188. response = await session.get(`${API_BASE_URL}/${gameId}`); // Assign inside try
  189. duels.push(response.data);
  190. await delay(1000);
  191. }
  192. catch (error) {
  193. console.error(`Error fetching duel data for game ${gameId}:`, error, response ? response.status : "No Response"); // Check if response exists
  194.  
  195. // Handle error as needed (e.g., retry, skip)
  196. await delay(1000);
  197. }
  198. }
  199. return duels;
  200. }
  201.  
  202. //***Data Processing ***//
  203. // Function to extract player round data from duel JSON - Phase 2 - Processes data from fetchduels
  204. function extractPlayerRoundData(duels, playerId) {
  205. return duels.flatMap(duel => {
  206. const playerTeam = duel.teams.find(team => team.players.some(p => p.playerId === playerId));
  207. const opponentTeam = duel.teams.find(team => team.players.some(p => p.playerId !== playerId));
  208.  
  209. if (!playerTeam || !opponentTeam) {
  210. console.error("Player or opponent not found in duel:", duel);
  211. return [];
  212. }
  213.  
  214. const player = playerTeam.players.find(p => p.playerId === playerId);
  215. const opponent = opponentTeam.players.find(p => p.playerId !== playerId);
  216.  
  217. if (!player || !opponent) {
  218. console.error("Player or opponent data missing:", duel);
  219. return [];
  220. }
  221.  
  222. return duel.rounds.map(round => {
  223. const playerGuess = player.guesses.find(g => g.roundNumber === round.roundNumber);
  224. const opponentGuess = opponent.guesses.find(g => g.roundNumber === round.roundNumber);
  225.  
  226. const playerRoundResult = playerTeam.roundResults.find(r => r.roundNumber === round.roundNumber);
  227. const opponentRoundResult = opponentTeam.roundResults.find(r => r.roundNumber === round.roundNumber);
  228.  
  229. const playerGuessData = {
  230. GuessLat: playerGuess ? playerGuess.lat : null,
  231. GuessLng: playerGuess ? playerGuess.lng : null,
  232. distance: playerGuess ? playerGuess.distance : null,
  233. score: playerRoundResult ? playerRoundResult.score : null,
  234. playerHealthBefore: playerRoundResult ? playerRoundResult.healthBefore : null,
  235. playerHealthAfter: playerRoundResult ? playerRoundResult.healthAfter : null,
  236. playerRatingBefore: player.progressChange?.rankedSystemProgress?.ratingBefore ?? null, // Correct path!
  237. playerRatingAfter: player.progressChange?.rankedSystemProgress?.ratingAfter ?? null, // Correct path!
  238. playerGameMode: player.progressChange?.rankedSystemProgress?.gameMode ?? null, // Correct path!
  239. playerGameModeRatingBefore: player.progressChange?.rankedSystemProgress?.gameModeRatingBefore ?? null, // Correct path!
  240. playerGameModeRatingAfter: player.progressChange?.rankedSystemProgress?.gameModeRatingAfter ?? null, // Correct path!
  241. playerGameModeGamesPlayed: player.progressChange?.rankedSystemProgress?.gameModeGamesPlayed ?? null,
  242. };
  243.  
  244. const opponentGuessData = {
  245. opponentGuessLat: opponentGuess ? opponentGuess.lat : null,
  246. opponentGuessLng: opponentGuess ? opponentGuess.lng : null,
  247. opponentDistance: opponentGuess ? opponentGuess.distance : null,
  248. opponentScore: opponentRoundResult ? opponentRoundResult.score : null,
  249. opponentHealthBefore: opponentRoundResult ? opponentRoundResult.healthBefore : null,
  250. opponentHealthAfter: opponentRoundResult ? opponentRoundResult.healthAfter : null,
  251. opponentRatingBefore: opponent.progressChange?.rankedSystemProgress?.ratingBefore ?? null, // Correct path!
  252. opponentRatingAfter: opponent.progressChange?.rankedSystemProgress?.ratingAfter ?? null, // Correct path!
  253. opponentGameMode: opponent.progressChange?.rankedSystemProgress?.gameMode ?? null, // Correct path!
  254. opponentGameModeRatingBefore: opponent.progressChange?.rankedSystemProgress?.gameModeRatingBefore ?? null, // Correct path!
  255. opponentGameModeRatingAfter: opponent.progressChange?.rankedSystemProgress?.gameModeRatingAfter ?? null, // Correct path!
  256. opponentGameModeGamesPlayed: opponent.progressChange?.rankedSystemProgress?.gameModeGamesPlayed ?? null,
  257. };
  258.  
  259. return {
  260. gameId: duel.gameId,
  261. mapName: duel.options.map.name,
  262. gameMode: duel.options.competitiveGameMode ?? "Not Available",
  263. forbidMoving: duel.options.movementOptions.forbidMoving,
  264. forbidZooming: duel.options.movementOptions.forbidZooming,
  265. forbidRotating: duel.options.movementOptions.forbidRotating,
  266. roundStartTime: round.startTime,
  267. roundEndTime: round.endTime,
  268. roundNumber: round.roundNumber,
  269. roundMultiplier: round.multiplier,
  270. roundDamageMultiplier: round.damageMultiplier ?? "Not Available",
  271. LocLat: round.panorama.lat,
  272. LocLng: round.panorama.lng,
  273. panoramaCountryCode: round.panorama.countryCode,
  274. playerId: player.playerId,
  275. ...playerGuessData,
  276. opponentPlayerId: opponent.playerId,
  277. ...opponentGuessData,
  278. };
  279. }).filter(Boolean);
  280. });
  281. }
  282. //*** Event Handlers ***//
  283. //function to handle CSV button click - Phase 2 - called when user confirms number duels to download
  284. async function handleDownloadCsv(session, gameIds) {
  285. const numDuels = gameIds.length; // Store the number of duels to fetch
  286.  
  287. const progressPopup = document.createElement('div');
  288. const topOffset = 80;
  289. const rightOffset = 80;
  290.  
  291. progressPopup.style.cssText = `
  292. position: fixed;
  293. top: ${topOffset}px;
  294. right: ${rightOffset}px;
  295. transform: translate(0, 0);
  296. background-color: #fff;
  297. padding: 20px;
  298. border: 1px solid #ccc;
  299. box-shadow: 0 4px 8px rgba(0, 0, 0, 0.1);
  300. z-index: 10003; /* Ensure it's on top */
  301. width: auto;
  302. min-width: 300px; /* Adjust as needed */
  303. `;
  304.  
  305. progressPopup.innerHTML = `
  306. <p><span id="duelsFetchedCount">0</span> of ${numDuels} fetched</p>
  307. <div id="progressBar"></div>
  308. <button id="cancelFetchButton" style="background-color: red; color: white; padding: 10px 20px; margin-top: 10px;">Cancel</button>
  309. `;
  310.  
  311. document.body.appendChild(progressPopup);
  312.  
  313. const progressBar = new ProgressBar.Line('#progressBar', {
  314. strokeWidth: 4,
  315. easing: 'easeInOut',
  316. duration: 1400,
  317. color: '#007bff', // Blue color for progress
  318. trailColor: '#eee',
  319. svgStyle: { width: '100%', height: '10px' }, // Make the progress bar fill the container
  320. text: {
  321. style: {
  322. color: '#333', // Darker text color
  323. position: 'absolute',
  324. left: '50%',
  325. top: '50%',
  326. padding: 0,
  327. margin: 0,
  328. transform: {
  329. prefix: true,
  330. x: '-50%',
  331. y: '-50%'
  332. }
  333. },
  334. autoStyleContainer: false
  335. },
  336. step: (state, bar) => {
  337. bar.setText(Math.round(bar.value() * 100) + ' %');
  338. }
  339. });
  340.  
  341.  
  342. let fetchedCount = 0;
  343. const duels = [];
  344. let cancelled = false; // Flag to track cancellation
  345.  
  346. const cancelFetchButton = document.getElementById('cancelFetchButton');
  347. cancelFetchButton.onclick = () => {
  348. cancelled = true;
  349. document.body.removeChild(progressPopup); // Close the popup immediately
  350. console.log("Duel fetching cancelled by user.");
  351. };
  352.  
  353.  
  354. for (let i = 0; i < numDuels; i++) {
  355. if (cancelled) break; // Check for cancellation before each fetch
  356.  
  357. let response = null;
  358. try {
  359. response = await session.get(`${API_BASE_URL}/${gameIds[i].id}`);
  360. duels.push(response.data);
  361. fetchedCount++;
  362. document.getElementById('duelsFetchedCount').textContent = fetchedCount;
  363. progressBar.set(fetchedCount / numDuels); // Update progress bar
  364. await delay(1000);
  365. } catch (error) {
  366. console.error(`Error fetching duel data for game ${gameIds[i].id}:`, error, response ? response.status : "No Response");
  367. await delay(1000);
  368. }
  369. }
  370.  
  371. if (!cancelled) { // Only proceed if not cancelled
  372. document.body.removeChild(progressPopup); // Remove the progress popup after completion
  373.  
  374. const playerRoundData = extractPlayerRoundData(duels, playerId);
  375. const csvData = jsonToCsv(playerRoundData.map(round => ({
  376. duel_id: round.gameId,
  377. map: round.mapName,
  378. duel_mode: round.gameMode,
  379. forbid_moving: round.forbidMoving,
  380. forbid_zooming: round.forbidZooming,
  381. forbid_rotating: round.forbidRotating,
  382. round_start_datetime: round.roundStartTime,
  383. round_end_datetime: round.roundEndTime,
  384. duel_round_number: round.roundNumber,
  385. round_multiplier: round.roundMultiplier,
  386. round_damage: round.roundDamageMultiplier,
  387. loc_lat: round.LocLat,
  388. loc_lng: round.LocLng,
  389. loc_cc: round.panoramaCountryCode,
  390. player_id: round.playerId,
  391. player_guess_lat: round.GuessLat,
  392. player_guess_lng: round.GuessLng,
  393. player_distance: round.distance,
  394. player_score: round.score,
  395. player_health_before: round.playerHealthBefore,
  396. player_health_after: round.playerHealthAfter,
  397. player_rating_before: round.playerRatingBefore,
  398. player_rating_after: round.playerRatingAfter,
  399. player_game_mode: round.playerGameMode,
  400. player_game_mode_rating_before: round.playerGameModeRatingBefore,
  401. player_game_mode_rating_after: round.playerGameModeRatingAfter,
  402. player_game_mode_games_played: round.playerGameModeGamesPlayed,
  403. opponent_player_id: round.opponentPlayerId,
  404. opponent_guess_lat: round.opponentGuessLat,
  405. opponent_guess_lng: round.opponentGuessLng,
  406. opponent_distance: round.opponentDistance,
  407. opponent_score: round.opponentScore,
  408. opponent_health_before: round.opponentHealthBefore,
  409. opponent_health_after: round.opponentHealthAfter,
  410. opponent_rating_before: round.opponentRatingBefore,
  411. opponent_rating_after: round.opponentRatingAfter,
  412. opponent_game_mode: round.opponentGameMode,
  413. opponent_game_mode_rating_before: round.opponentGameModeRatingBefore,
  414. opponent_game_mode_rating_after: round.opponentGameModeRatingAfter,
  415. opponent_game_mode_games_played: round.opponentGameModeGamesPlayed
  416. })));
  417. downloadCsv(csvData, 'newDuelsRounds.csv');
  418. console.log("Duel stats download complete.");
  419. }
  420.  
  421. }
  422.  
  423.  
  424. //*** UI Popups ***//
  425. //Show confirmation popup at page load
  426. function showConfirmationPopup() {
  427. return new Promise((resolve) => {
  428. const popup = document.createElement('div');
  429. const topOffset = 80; // 80px from the top
  430. const rightOffset = 80; // 80px from the right
  431.  
  432. popup.style.cssText = `
  433. position: fixed;
  434. top: ${topOffset}px;
  435. right: ${rightOffset}px;
  436. transform: translate(0, 0); /* Remove default centering transform */
  437. background-color: #fff;
  438. padding: 20px;
  439. border: 1px solid #ccc;
  440. box-shadow: 0 4px 8px rgba(0, 0, 0, 0.1);
  441. z-index: 10000;
  442. `;
  443.  
  444. popup.innerHTML = `
  445. <p>Do You Want to Fetch Duels Data?</p>
  446. <button id="confirmButton" style="background-color: green; color: white; padding: 10px 20px; margin-right: 10px;">Yes ✓</button>
  447. <button id="cancelButton" style="background-color: red; color: white; padding: 10px 20px;">No X</button>
  448. `;
  449.  
  450. document.body.appendChild(popup);
  451.  
  452. const confirmButton = document.getElementById('confirmButton');
  453. const cancelButton = document.getElementById('cancelButton');
  454.  
  455. confirmButton.onclick = () => {
  456. document.body.removeChild(popup);
  457. resolve(true); // Resolve with true when confirmed
  458. };
  459.  
  460. cancelButton.onclick = () => {
  461. document.body.removeChild(popup);
  462. resolve(false); // Resolve with false when canceled
  463. };
  464. });
  465. }
  466.  
  467. //Sow searching popup
  468. function showSearchingPopup() {
  469. const popup = document.createElement('div');
  470. const topOffset = 80;
  471. const rightOffset = 80;
  472.  
  473. popup.style.cssText = `
  474. position: fixed;
  475. top: ${topOffset}px;
  476. right: ${rightOffset}px;
  477. transform: translate(0, 0);
  478. background-color: #fff; /* White background */
  479. padding: 20px;
  480. border: 1px solid #ccc;
  481. box-shadow: 0 4px 8px rgba(0, 0, 0, 0.1);
  482. z-index: 10001;
  483. width: auto; /* Adjust width as needed */
  484. min-width: 200px; /* Minimum width to prevent it from being too small */
  485. `;
  486. popup.innerHTML = `<p>Searching For Duels...</p>`;
  487. document.body.appendChild(popup);
  488. return popup;
  489. }
  490.  
  491. //Hide popup
  492. function hidePopup(popup) {
  493. if (popup && popup.parentNode) { // Check if the popup exists and is in the DOM
  494. popup.parentNode.removeChild(popup);
  495. }
  496. }
  497.  
  498. //Show phase 1 complete popup
  499. function showPhase1CompletePopup(gameIds, lastDownloadDate) {
  500. return new Promise((resolve) => {
  501. const popup = document.createElement('div');
  502. const topOffset = 80;
  503. const rightOffset = 80;
  504.  
  505. popup.style.cssText = `
  506. position: fixed;
  507. top: ${topOffset}px;
  508. right: ${rightOffset}px;
  509. transform: translate(0, 0);
  510. background-color: #fff !important; /* White background - override other styles */
  511. padding: 20px;
  512. border: 1px solid #ccc;
  513. box-shadow: 0 4px 8px rgba(0, 0, 0, 0.1);
  514. z-index: 10002;
  515. width: auto;
  516. min-width: 250px;
  517. `;
  518.  
  519. const newDuelsCount = countNewDuels(gameIds, lastDownloadDate); // Use the helper function
  520. const lastDownloadText = lastDownloadDate
  521. ? `Last download occurred on ${lastDownloadDate.toLocaleString()}`
  522. : "No previous downloads detected"; // Dynamic message
  523.  
  524. popup.innerHTML = `
  525. <p>${gameIds.length} Duels found and downloaded</p>
  526. <p>${lastDownloadText}</p>
  527. <p>${newDuelsCount} new duels have occurred since then</p>
  528. <p>How many do you want to fetch?</p>
  529. <input type="number" id="numDuels" value="${newDuelsCount}" min="1" max="${gameIds.length}" style="width: 100px; margin-right: 10px;">
  530. <button id="confirmButton" style="background-color: green; color: white; padding: 10px 20px; margin-right: 10px;">Confirm</button>
  531. <button id="cancelButton" style="background-color: red; color: white; padding: 10px 20px;">Cancel</button>
  532. `;
  533.  
  534. document.body.appendChild(popup);
  535.  
  536. const confirmButton = document.getElementById('confirmButton');
  537. const cancelButton = document.getElementById('cancelButton');
  538. const numDuelsInput = document.getElementById('numDuels');
  539.  
  540. confirmButton.onclick = () => {
  541. let numDuels = parseInt(numDuelsInput.value, 10);
  542.  
  543. if (isNaN(numDuels) || numDuels < 1) {
  544. alert("Please enter a valid number greater than 0.");
  545. return;
  546. }
  547.  
  548. numDuels = Math.min(numDuels, gameIds.length);
  549.  
  550. // Save the current timestamp in local storage
  551. localStorage.setItem("lastDownloadTimestamp", JSON.stringify(new Date()));
  552.  
  553. document.body.removeChild(popup);
  554. resolve(numDuels);
  555. };
  556.  
  557. cancelButton.onclick = () => {
  558. document.body.removeChild(popup);
  559. resolve(false);
  560. };
  561. });
  562. }
  563.  
  564. //*** Initialization ***//
  565. //*** Initialization ***//
  566. async function init() {
  567. // Retrieve the last download timestamp from local storage
  568. const lastDownloadTimestamp = localStorage.getItem("lastDownloadTimestamp");
  569. let lastDownloadDate = null;
  570.  
  571. if (lastDownloadTimestamp) {
  572. lastDownloadDate = new Date(JSON.parse(lastDownloadTimestamp)); // Parse the timestamp into a Date object
  573. console.log("Last download occurred on:", lastDownloadDate.toLocaleString());
  574. } else {
  575. console.log("No previous downloads detected.");
  576. }
  577.  
  578. const userConfirmed = await showConfirmationPopup();
  579.  
  580. if (userConfirmed) {
  581. const scriptStartTime = performance.now(); // Capture start time using performance.now()
  582. console.time('total_script_time'); // Start timer *after* confirmation
  583. console.log("Script execution started at:", new Date().toLocaleString()); // Log start time
  584.  
  585. const session = axios.create({
  586. withCredentials: true
  587. });
  588.  
  589. const searchingPopup = showSearchingPopup();
  590.  
  591. getGameIds(session).then(gameIds => {
  592. const phase1EndTime = performance.now(); // Capture end time using performance.now()
  593. const phase1Duration = (phase1EndTime - scriptStartTime) / 1000; // Calculate duration (using performance.now consistently)
  594.  
  595. console.log("Phase 1 (Game IDs and CSV Download) finished at:", new Date().toLocaleString());
  596.  
  597. hidePopup(searchingPopup);
  598.  
  599. showPhase1CompletePopup(gameIds, lastDownloadDate).then(numDuels => {
  600. if (numDuels) {
  601. const recentGameIds = gameIds.slice(-numDuels);
  602.  
  603. const phase2StartTime = performance.now(); // Capture Phase 2 start time
  604. console.time('phase2_loading'); // Phase 2 start time
  605. console.log("Phase 2 started at:", new Date().toLocaleString()); // Human-readable start time
  606.  
  607. handleDownloadCsv(session, recentGameIds).then(() => {
  608. const phase2EndTime = performance.now(); // Capture Phase 2 end time
  609. const phase2Duration = (phase2EndTime - phase2StartTime) / 1000; // Calculate phase 2 duration
  610.  
  611. console.timeEnd('phase2_loading'); // Phase 2 end time
  612. console.timeEnd('total_script_time'); // Total time end
  613.  
  614. const scriptEndTime = performance.now(); // Capture script end time
  615. const scriptDuration = (scriptEndTime - scriptStartTime) / 1000; // Calculate total script duration
  616.  
  617. console.log("Phase 2 finished at:", new Date().toLocaleString());
  618. console.log("Total time for Phase 2:", phase2Duration, "seconds");
  619. console.log("Total script execution time:", scriptDuration, "seconds");
  620.  
  621. }).catch(error => {
  622. console.timeEnd('phase2_loading'); // End timer on error in Phase 2
  623. console.timeEnd('total_script_time'); // Total time end
  624. // ... (Phase 2 error handling)
  625.  
  626. const scriptEndTime = performance.now();
  627. const scriptDuration = (scriptEndTime - scriptStartTime) / 1000;
  628.  
  629. console.log("Script finished at:", new Date().toLocaleString());
  630. console.log("Total script execution time:", scriptDuration, "seconds");
  631. });
  632.  
  633. console.log(`Fetching ${numDuels} duels...`);
  634. } else {
  635. console.log("User chose not to proceed to Phase 2.");
  636. console.timeEnd('total_script_time'); // End timer if no Phase 2
  637.  
  638. const scriptEndTime = performance.now();
  639. const scriptDuration = (scriptEndTime - scriptStartTime) / 1000;
  640.  
  641. console.log("Script finished at:", new Date().toLocaleString());
  642. console.log("Total script execution time:", scriptDuration, "seconds");
  643. }
  644. }).catch(error => {
  645. console.timeEnd('total_script_time'); // End timer on error in Phase 1
  646. // ... (Phase 1 error handling)
  647.  
  648. const scriptEndTime = performance.now();
  649. const scriptDuration = (scriptEndTime - scriptStartTime) / 1000;
  650.  
  651. console.log("Script finished at:", new Date().toLocaleString());
  652. console.log("Total script execution time:", scriptDuration, "seconds");
  653. });
  654. }).catch(error => {
  655. console.timeEnd('total_script_time'); // End timer on error in getGameIds
  656. // ... (getGameIds error handling)
  657.  
  658. const scriptEndTime = performance.now();
  659. const scriptDuration = (scriptEndTime - scriptStartTime) / 1000;
  660.  
  661. console.log("Script finished at:", new Date().toLocaleString());
  662. console.log("Total script execution time:", scriptDuration, "seconds");
  663. });
  664.  
  665. } else {
  666. console.log("Script execution cancelled by user.");
  667. }
  668. }
  669. $(document).ready(init);
  670.  
  671. })();
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement