// ==UserScript== // @name nightly.link buttons // @namespace blankie-scripts // @match http*://github.com/* // @grant none // @version 1.2.4 // @author blankie // @run-at document-end // @description Show buttons to nightly.link on artifacts and build logs // ==/UserScript== "use strict"; const INSTANCE_URL = "https://nightly.link"; function addArtifactsButtonAndLinks(artifactsDiv) { if (artifactsDiv === null) { return false; } let header = artifactsDiv.querySelector("div.mx-0.mx-md-1"); if (header === null) { return false; } let artifactsButton = document.createElement("a"); artifactsButton.className = "btn"; // https://stackoverflow.com/a/17228764 artifactsButton.style.float = "right"; artifactsButton.innerText = "View on nightly.link"; artifactsButton.href = INSTANCE_URL + location.pathname; header.prepend(artifactsButton); for (let artifactDiv of artifactsDiv.querySelectorAll("tbody > tr > td > div")) { let artifactIcon = artifactDiv.querySelector("span.mr-2"); let artifactNode = artifactDiv.querySelector("span.text-bold"); if (artifactIcon === null || artifactNode === null) { continue; } let artifactName = artifactNode.textContent.trim(); let artifactUrl = INSTANCE_URL + location.pathname + "/" + artifactName + ".zip"; let newArtifactLink = document.createElement("a"); newArtifactLink.text = artifactName; newArtifactLink.href = artifactUrl; newArtifactLink.className = "text-bold no-underline Link--primary"; artifactNode.replaceWith(newArtifactLink); let newArtifactIcon = document.createElement("a"); newArtifactIcon.className = artifactIcon.className; newArtifactIcon.href = artifactUrl; for (let child of artifactIcon.children) { newArtifactIcon.appendChild(child); } artifactIcon.replaceWith(newArtifactIcon); } return true; } // https://github.com/EbookFoundation/free-programming-books/actions/runs/3213752190/jobs/5253657996 // https://github.com/kotatogram/kotatogram-desktop/actions/runs/3231502508/jobs/5291098845 function getGithubJobsPath(logsHeader) { if (logsHeader === null) { // https://github.com/the-blank-x/furry-guide/actions/runs/2613813876 return location.pathname; } let timestampElement = logsHeader.querySelector(".CheckRun-header-timestamp"); if (timestampElement === null) { return location.pathname; } let headerUrl = timestampElement.getAttribute("data-url"); if (headerUrl === null) { return location.pathname; } let jobLogsUrl = new URL(headerUrl, location); return jobLogsUrl.pathname.replace(/\/header\/*$/, ""); } function addLogsButton(githubLogsButton, logsHeader) { let logsUrl = INSTANCE_URL + getGithubJobsPath(logsHeader) + ".txt"; if (githubLogsButton !== null) { let nightlyLogsButton = document.createElement("a"); nightlyLogsButton.className = "pl-5 dropdown-item btn-link"; nightlyLogsButton.innerText = "View logs on nightly.link"; nightlyLogsButton.href = logsUrl; githubLogsButton.parentNode.append(nightlyLogsButton); return true; } else if (logsHeader !== null) { let logsLink = document.createElement("a"); logsLink.style.alignSelf = "center"; logsLink.innerText = "View on nightly.link"; logsLink.href = logsUrl; logsHeader.append(logsLink); return true; } return false; } function handleNewPage() { let artifactsDiv = document.body.querySelector("div#artifacts"); let githubLogsButton = document.body.querySelector("a.js-steps-dropdown-raw-logs"); let logsHeader = document.body.querySelector("div.js-checks-log-toolbar"); addArtifactsButtonAndLinks(artifactsDiv) || addLogsButton(githubLogsButton, logsHeader); }; handleNewPage(); function observerCallback(mutationList, observer) { for (let mutation of mutationList) { if (mutation.type !== "childList") { continue; } for (let node of mutation.removedNodes) { if (node.nodeName === "DIV" && node.classList.contains("turbo-progress-bar")) { handleNewPage(); return; } } } } let observer = new MutationObserver(observerCallback); observer.observe(document.documentElement, {childList: true});