Left-Right Balance for Strava [Updated]

Shows your Left/Right balance under the analysis section on Strava.

// ==UserScript==
// @name         Left-Right Balance for Strava [Updated]
// @namespace    typpi.online
// @description  Shows your Left/Right balance under the analysis section on Strava.
// @version      2.9
// @include      https://www.strava.com/activities/*
// @icon         https://www.google.com/s2/favicons?sz=64&domain=strava.com
// @author       Nick2bad4u
// @license      UnLicense
// @grant        none
// @homepageURL  https://github.com/Nick2bad4u/UserStyles
// ==/UserScript==

/**
 * URL of the script to be loaded from the CDN.
 * This script is hosted on jsDelivr and is part of the UserStyles repository.
 *
 * @constant {string}
 */
const SCRIPT_URL = 'https://cdn.jsdelivr.net/gh/Nick2bad4u/UserStyles@main/strava-balance/Strava-AddBalance.js';
// Cache expiration time set to 24 hours in milliseconds
const CACHE_EXPIRE_TIME = 24 * 60 * 60 * 1000;
// Key used to store the last fetch time of the script in localStorage
const CACHE_LAST_FETCH_TIME_KEY = 'stravaBalanceScriptFetchTime';
// Key used to store the cached script in localStorage
const CACHED_SCRIPT_KEY = 'stravaBalanceScript';

//SCRIPT_BALANCE_ELEMENT.src="https://dmwnz.github.io/lrbalance4strava/addbal.js";

/**
 * Determines if the cache has expired based on the last fetch time and the cache expiration time.
 *
 * @param {number} CACHE_LAST_FETCH_TIME - The timestamp of the last fetch.
 * @param {number} CACHE_EXPIRE_TIME - The duration in milliseconds after which the cache is considered expired.
 * @returns {boolean} - Returns true if the cache is expired, otherwise false.
 */
const isCacheExpired = (CACHE_LAST_FETCH_TIME, CACHE_EXPIRE_TIME) => {
	const CURRENT_TIME = Date.now();
	return !CACHE_LAST_FETCH_TIME || CURRENT_TIME - CACHE_LAST_FETCH_TIME > CACHE_EXPIRE_TIME;
};

/**
 * Immediately Invoked Function Expression (IIFE) to load and execute the Strava balance script.
 * It checks the cache for the script and fetches it from the network if the cache is expired.
 */
function loadStravaBalanceScript() {
	const CACHED_SCRIPT = localStorage.getItem(CACHED_SCRIPT_KEY) || '';
	const CACHE_LAST_FETCH_TIME = localStorage.getItem(CACHE_LAST_FETCH_TIME_KEY) || '0';

	const CACHE_EXPIRED = isCacheExpired(Number(CACHE_LAST_FETCH_TIME) || 0, CACHE_EXPIRE_TIME);
	if (CACHED_SCRIPT && !CACHE_EXPIRED) {
		loadScriptFromCache(CACHED_SCRIPT);
		console.log('Strava balance script loaded from cache and executed successfully.');
	} else {
		fetchAndCacheScript();
	}
}

/**
 * Loads and executes the provided script from the cache.
 *
 * @param {string} script - The script content to be executed.
 */
function loadScriptFromCache(script) {
	let SCRIPT_BALANCE_ELEMENT = document.querySelector('script[data-source="stravaBalanceScript"]');
	if (!SCRIPT_BALANCE_ELEMENT) {
		SCRIPT_BALANCE_ELEMENT = document.createElement('script');
		SCRIPT_BALANCE_ELEMENT.type = 'module';
		SCRIPT_BALANCE_ELEMENT.setAttribute('data-source', 'stravaBalanceScript');
		document.body.appendChild(SCRIPT_BALANCE_ELEMENT);
	}
	SCRIPT_BALANCE_ELEMENT.text = script;
}

function fetchAndCacheScript() {
	const CONTROLLER = new AbortController();
	const TIMEOUT_ID = setTimeout(() => CONTROLLER.abort(), 10000); // 10 seconds timeout
	fetch(SCRIPT_URL, { signal: CONTROLLER.signal })
		.then((SCRIPT_URL_RESPONSE) => {
			clearTimeout(TIMEOUT_ID);
			if (!SCRIPT_URL_RESPONSE.ok) {
				throw new Error(`HTTP error! status: ${SCRIPT_URL_RESPONSE.status} while fetching ${SCRIPT_URL}`);
			}
			return SCRIPT_URL_RESPONSE.text();
		})
		.then((SCRIPT_URL_RESPONSE_DATA) => {
			localStorage.setItem(CACHED_SCRIPT_KEY, SCRIPT_URL_RESPONSE_DATA);
			localStorage.setItem(CACHE_LAST_FETCH_TIME_KEY, Date.now().toString());
			loadScriptFromCache(SCRIPT_URL_RESPONSE_DATA);
			console.log('Strava balance script loaded from network and executed successfully.');
		})
		.catch((error) => {
			if (error.name === 'AbortError') {
				console.error('Fetch request timed out after 10 seconds');
			} else {
				console.error(`Error fetching script from ${SCRIPT_URL}:`, error);
			}
		});
}

(function () {
	loadStravaBalanceScript();
})();