Long Story short, i just programmed my own App now for that. Works with all garmin watches and let's use define a fixed Workout and allows to analyze your individual performances across exercises:
https://multisports.creatness.studio - i'm still waiting for Garmin to approve my App Store Submission (another long story with garmin) but it can already be downloaded and sideloaded on a garmin watch. using it for a few weeks now myself.
Remember I threw this together in about half an hour, and maybe that amount of cleanup to post here. "Works for me" is the order of the day. The extra debugging alone would be longer than the whole project!
Besides, the function that runs is so light it doesn't really seem worth it. It could even make performance worse, since for reliability you need to observe mutations across the entire DOM, which could occur a lot more often. So for performance you want to add some debouncing too, adding yet more complexity to what's supposed to be a 'quick and dirty' fix.
(function() { 'use strict';
const SITE = "https://www.youtube.com";
const LINK_TO_TIMESTAMP = true;
const SHOW_PREVIEW_IMAGE = true;
const createPreviewElement = (videoId, newURL, frame) => {
const container = document.createElement("div");
container.setAttribute('data-yt-preview', 'true');
container.style.position = "relative";
container.style.width = frame.width + "px";
container.style.height = frame.height + "px";
container.style.cursor = "pointer";
const img = document.createElement("img");
img.src = `https://i.ytimg.com/vi/${videoId}/mqdefault.jpg`;
img.alt = "Preview image of Youtube video";
img.style.width = "100%";
img.style.height = "100%";
img.style.objectFit = "cover";
const playButton = document.createElement("div");
playButton.innerHTML = "▶";
playButton.style.position = "absolute";
playButton.style.top = "50%";
playButton.style.left = "50%";
playButton.style.transform = "translate(-50%, -50%)";
playButton.style.fontSize = "48px";
playButton.style.color = "white";
playButton.style.backgroundColor = "rgba(0, 0, 0, 0.7)";
playButton.style.borderRadius = "50%";
playButton.style.width = "80px";
playButton.style.height = "80px";
playButton.style.display = "flex";
playButton.style.justifyContent = "center";
playButton.style.alignItems = "center";
container.appendChild(img);
container.appendChild(playButton);
container.addEventListener("click", () => {
const iframe = document.createElement("iframe");
iframe.src = frame.src + (frame.src.includes('?') ? '&' : '?') + 'autoplay=1';
iframe.width = frame.width;
iframe.height = frame.height;
iframe.frameBorder = "0";
iframe.allow = "accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture";
iframe.allowFullscreen = true;
iframe.setAttribute('data-yt-processed', 'true');
container.parentNode.replaceChild(iframe, container);
});
return container;
};
const replaceEmbed = (frame) => {
const frameURL = frame.src || frame.dataset?.src;
if (!frameURL) return;
const match = frameURL.match(/(^https?:)?\/\/(www\.)?youtube(-nocookie)?\.com\/embed\/([a-zA-Z0-9\-_]{11}).*?(\?.*((t|start)=([\dsmh]*)))?/i);
if (match?.length == 9) {
const videoId = match[4];
const newURL = SITE + "/watch?" + ((LINK_TO_TIMESTAMP && match[8]) ? "t=" + match[8] + "&" : "") + "v=" + videoId;
const previewElement = createPreviewElement(videoId, newURL, frame);
frame.parentNode.replaceChild(previewElement, frame);
// common lazyload hiding methods
previewElement.style.display = "block !important";
previewElement.style.opacity = "100% !important";
previewElement.style.background = "transparent !important";
const parent = previewElement.parentElement;
if (parent) {
parent.style.display = "block !important";
parent.style.opacity = "100% !important";
parent.style.background = "transparent !important";
}
}
};
const observeDOM = () => {
const observer = new MutationObserver((mutations) => {
mutations.forEach((mutation) => {
if (mutation.type === 'childList') {
mutation.addedNodes.forEach((node) => {
if (node.nodeType === Node.ELEMENT_NODE) {
if (node.tagName === 'IFRAME' && !node.hasAttribute('data-yt-processed')) {
replaceEmbed(node);
} else {
node.querySelectorAll('iframe:not([data-yt-processed])').forEach(replaceEmbed);
}
}
});
}
});
});
observer.observe(document.body, {
childList: true,
subtree: true
});
};
// Initial replacement
document.querySelectorAll('iframe:not([data-yt-processed])').forEach(replaceEmbed);
// Start observing DOM changes
observeDOM();
})();The biggest problem currently are people spreading those types of misinformation see https://www.reddit.com/r/uBlockOrigin/comments/17j6ygs/youtu...
It's obviously math.
This whole "computer implemented invention" workaround is a complete sham.
To think that the EU wastes billions annually on this broken institution, while completely failing to properly fund startups is simply infuriating.