Strava and Garmin Kudos All (Working)

Adds a button to give kudos to all visible activities on Strava and Garmin Connect.

目前為 2025-02-07 提交的版本,檢視 最新版本

// ==UserScript==
// @name         Strava and Garmin Kudos All (Working)
// @namespace    typpi.online
// @version      1.4
// @description  Adds a button to give kudos to all visible activities on Strava and Garmin Connect.
// @author       Nick2bad4u
// @license      Unlicense
// @homepageURL  https://github.com/Nick2bad4u/UserStyles/
// @grant        none
// @run-at       document-end
// @include      https://www.strava.com/*
// @include      https://connect.garmin.com/modern/*
// @icon         https://i.gyazo.com/e2fabcfc9e9fd6d011e98215764c109c.png
// ==/UserScript==

(function () {
	'use strict';

	// Function to get localized message
	function getMessage(messageName, substitutions) {
		const messages = {
			en: {
				kudo_all: 'Kudo All',
			},
			es: {
				kudo_all: 'Dar Kudos a Todos',
			},
			fr: {
				kudo_all: 'Féliciter Tout le Monde',
			},
			de: {
				kudo_all: 'Allen Kudos geben',
			},
			it: {
				kudo_all: 'Dai Kudos a Tutti',
			},
			pt: {
				kudo_all: 'Dar Kudos a Todos',
			},
			nl: {
				kudo_all: 'Geef Kudos aan Iedereen',
			},
			ru: {
				kudo_all: 'Похвалить всех',
			},
			zh: {
				kudo_all: '赞所有',
			},
			ja: {
				kudo_all: '全員にKudos',
			},
			ko: {
				kudo_all: '모두에게 칭찬하기',
			},
			ar: {
				kudo_all: 'إعطاء Kudos للجميع',
			},
			hi: {
				kudo_all: 'सभी को कुडोस दें',
			},
			bn: {
				kudo_all: 'সবাইকে কুডোস দিন',
			},
			// Add more languages as needed
		};

		const userLanguage = navigator.language.split('-')[0]; // Get the user's language
		const messageSet = messages[userLanguage] || messages['en']; // Default to English if language not supported

		return messageSet[messageName] || substitutions || messageName;
	}

	const Strava = {
		// Get the container element on Strava
		getContainer: function () {
			const container = document.querySelector('[class="user-nav nav-group"]');
			console.log('Strava: Found container:', container);
			return container;
		},

		// Find all kudos buttons within the container
		findKudosButtons: function (container) {
			const selector = "button[data-testid='kudos_button'] > svg[data-testid='unfilled_kudos']";
			const buttons = container ? Array.from(container.querySelectorAll(selector)) : Array.from(document.querySelectorAll(selector));
			console.log('Strava: Found kudos buttons:', buttons);
			return buttons;
		},

		// Create filter for athlete link to exclude own activities
		createFilter: function (athleteLink) {
			const href = athleteLink.href.replace('https://www.strava.com', '').replace('https://strava.com', '');
			console.log('Strava: Filter created for athlete link:', href);
			return (item) => !item.querySelector(`a[href^="${href}"]`);
		},

		// Get all kudos buttons for the current user
		getKudosButtons: function () {
			const athleteLink = document.querySelector("#athlete-profile a[href^='/athletes']");
			console.log('Strava: Athlete link:', athleteLink);

			if (!athleteLink) {
				return Strava.findKudosButtons();
			}

			let activities = document.querySelectorAll("div[data-testid='web-feed-entry']");
			console.log('Strava: Found activities:', activities);

			if (activities.length < 1) {
				return Strava.findKudosButtons();
			}

			activities = Array.from(activities).filter(Strava.createFilter(athleteLink));
			console.log('Strava: Filtered activities:', activities);

			if (activities.length < 1) {
				return Strava.findKudosButtons();
			}

			const buttons = activities.flatMap(Strava.findKudosButtons).filter((item) => !!item);
			console.log('Strava: Final kudos buttons:', buttons);
			return buttons;
		},

		// Create a new button for kudo all
		createButton: function () {
			const label = getMessage('kudo_all', 'Kudo All');
			console.log('Strava: Creating button with label:', label);

			const navItemLi = document.createElement('li');
			const navItemA = document.createElement('a');

			navItemLi.className = 'nav-item';
			navItemLi.style.marginRight = '10px';

			navItemA.href = '#';
			navItemA.className = 'btn btn-default btn-sm empty';

			const navItemIcon = document.createElement('span');
			navItemIcon.className = 'app-icon icon-kudo';
			navItemIcon.style.marginRight = '5px';

			const navItemText = document.createElement('span');
			navItemText.className = 'ka-progress text-caption1';
			navItemText.textContent = label;

			navItemA.append(navItemIcon);
			navItemA.append(navItemText);
			navItemLi.append(navItemA);

			return navItemLi;
		},

		// Handler for the kudo all button click event
		kudoAllHandler: function (event) {
			event.preventDefault();

			const icons = Strava.getKudosButtons();
			console.log('Strava: Clicking all kudos buttons, count:', icons.length);

			icons.forEach((item) => {
				const parentItem = item?.parentElement;
				if (parentItem) {
					parentItem.click();
				}
			});
		},

		// Initialize Strava functionality
		stravaStandBy: function () {
			console.log('Strava: Standby initiated');
			const buttonExisted = document.querySelector('div[class="ka-progress text-caption1"]');
			if (!buttonExisted) {
				console.log('Strava: Button does not exist, creating');

				const container = Strava.getContainer();

				if (container) {
					const button = Strava.createButton();
					container.prepend(button);
					button.addEventListener('click', Strava.kudoAllHandler);
				}
			}
		},
	};

	const GC = {
		// Get the container element on Garmin
		getContainer: function () {
			const container = document.querySelector('div[class="header-nav"]');
			console.log('Garmin: Found container:', container);

			if (container) {
				const el = document.createElement('div');
				el.classList.add('kudo-all-nav-item', 'header-nav-item');
				el.style.height = '60px';
				el.style.width = '50px';
				container.prepend(el);
				return document.querySelector('div[class^=kudo-all-nav-item]');
			}
			return null;
		},

		// Find all kudos buttons within the container
		findKudosButtons: function (container) {
			const selector = 'button[class^="CommentLikeSection_socialIconWrapper"] > div[class*="CommentLikeSection_animateBox"] > i[class*=icon-heart-inverted]';
			const buttons = container ? Array.from(container.querySelectorAll(selector)) : Array.from(document.querySelectorAll(selector));
			console.log('Garmin: Found kudos buttons:', buttons);
			return buttons;
		},

		// Create a new button for kudo all
		createButton: function () {
			const label = getMessage('kudo_all', 'Kudo All');
			console.log('Garmin: Creating button with label:', label);

			const link = document.createElement('a');
			link.href = '#';
			link.className = 'header-nav-link icon-heart-inverted';
			link.setAttribute('aria-label', label);
			link.setAttribute('data-original-title', label);
			link.setAttribute('data-rel', 'tooltip');
			return link;
		},

		// Handler for the kudo all button click event
		kudoAllHandler: function (event) {
			event.preventDefault();
			if (window.location.pathname !== '/modern/newsfeed') {
				console.log('Garmin: Not on the newsfeed page, aborting');
				return;
			}

			const icons = GC.findKudosButtons();
			console.log('Garmin: Clicking all kudos buttons, count:', icons.length);

			icons.forEach((item) => {
				if (item) {
					item.click();
				}
			});
		},

		// Execute Garmin functionality
		execute: function () {
			console.log('Garmin: Execute function called');
			const container = GC.getContainer();

			if (container) {
				const button = GC.createButton();
				container.append(button);
				button.addEventListener('click', GC.kudoAllHandler);
			}
		},

		// Initialize Garmin functionality
		garminConnectStandBy: function () {
			console.log('Garmin: Standby initiated');

			let loaded = false;

			var observer = new MutationObserver(function (mutations) {
				mutations.forEach(function (mutation) {
					if (mutation.addedNodes.length > 0) {
						mutation.addedNodes.forEach((node) => {
							if (
								!loaded &&
								node.nodeType === 1 && // Ensure it's an element
								node.className &&
								typeof node.className === 'string' &&
								node.className.startsWith('header-nav')
							) {
								console.log('Garmin: Target element loaded, executing...');
								loaded = true;
								GC.execute();
							}
						});
					}
				});
			});

			observer.observe(document.body, {
				childList: true,
				subtree: true,
			});
		},
	};

	// Check if the current host is Strava
	const isHostStrava = function () {
		const currentHostname = window.location.hostname;
		const stravaDomainPattern = /^.*\.strava\.com$/;
		return stravaDomainPattern.test(currentHostname);
	};

	// Check if the current host is Garmin
	const isHostGarmin = function () {
		const currentHostname = window.location.hostname;
		const garminDomainPattern = /^.*\.garmin\.com$/;
		const isGarmin = garminDomainPattern.test(currentHostname);
		console.log('Host check: Is Garmin?', isGarmin);
		return isGarmin;
	};

	// Initialize script on window load
	window.onload = function () {
		console.log('Kudo All Starts running....');

		const inStrava = isHostStrava();
		const inGarmin = isHostGarmin();

		if (inStrava) {
			console.log('Detected Strava domain. Initiating Strava standby...');
			Strava.stravaStandBy();
		} else if (inGarmin) {
			console.log('Detected Garmin domain. Initiating Garmin standby...');
			GC.garminConnectStandBy();
		} else {
			console.log('Unknown domain. No action taken.');
		}
	};
})();

QingJ © 2025

镜像随时可能失效,请加Q群300939539或关注我们的公众号极客氢云获取最新地址