/* content script running on youtube.com */ let browserType = getBrowser(); // boilerplate to dedect browser type api function getBrowser() { if (typeof chrome !== "undefined") { if (typeof browser !== "undefined") { console.log("detected firefox"); return browser; } else { console.log("detected chrome"); return chrome; } } else { console.log("failed to dedect browser"); throw "browser detection error" }; } const downloadIcon = ` `; const checkmarkIcon = ` ` function buildButtonDiv() { var buttonDiv = document.createElement("div"); buttonDiv.setAttribute("id", "ta-channel-button"); Object.assign(buttonDiv.style, { display: "flex", alignItems: "center", backgroundColor: "#00202f", color: "#fff", fontSize: "1.7rem", padding: "5px", margin: "0 5px", borderRadius: "8px", }); return buttonDiv } function buildSubLink(channelContainer) { var subLink = document.createElement("span"); var currentLocation = window.location; subLink.innerText = "Subscribe"; subLink.addEventListener('click', e => { e.preventDefault(); console.log("subscribe to: " + currentLocation); sendUrl(currentLocation, "subscribe"); }); subLink.addEventListener("mouseover", e => { let subText if (window.location.pathname == "/watch") { subText = window.location.href; } else { subText = channelContainer.querySelector("#text").textContent; }; e.target.title = "TA Subscribe: " + subText; }); Object.assign(subLink.style, { padding: "5px 10px", cursor: "pointer", }); return subLink } function buildSpacer() { var spacer = document.createElement("span"); spacer.innerText = "|"; return spacer } function buildDlLink(channelContainer) { var dlLink = document.createElement("span"); var currentLocation = window.location; dlLink.innerHTML = downloadIcon; dlLink.addEventListener('click', e => { e.preventDefault(); console.log("download: " + currentLocation) sendUrl(currentLocation, "download"); }); dlLink.addEventListener("mouseover", e => { let subText if (window.location.pathname == "/watch") { subText = window.location.href; } else { subText = channelContainer.querySelector("#text").textContent; }; e.target.title = "TA Download: " + subText; }); Object.assign(dlLink.style, { filter: "invert()", width: "20px", padding: "0 10px", cursor: "pointer", }); return dlLink } function buildChannelButton(channelContainer) { var buttonDiv = buildButtonDiv() var subLink = buildSubLink(channelContainer); buttonDiv.appendChild(subLink) var spacer = buildSpacer() buttonDiv.appendChild(spacer); var dlLink = buildDlLink(channelContainer) buttonDiv.appendChild(dlLink); return buttonDiv } function getChannelContainers() { var nodes = document.querySelectorAll("#inner-header-container, #owner"); return nodes } function getThubnailContainers() { var nodes = document.querySelectorAll('#thumbnail'); return nodes } function buildVideoButton(thumbContainer) { var thumbLink = thumbContainer?.href; if (!thumbLink) return; if (thumbLink.includes('list=') || thumbLink.includes('/shorts/')) return; var dlButton = document.createElement("a"); dlButton.setAttribute("id", "ta-video-button"); dlButton.href = '#' dlButton.addEventListener('click', e => { e.preventDefault(); let videoLink = thumbContainer.href; console.log("download: " + videoLink); sendUrl(videoLink, "download"); }); dlButton.addEventListener('mouseover', e => { Object.assign(dlButton.style, { opacity: 1, }); let videoTitle = thumbContainer.href; e.target.title = "TA download: " + videoTitle; }) dlButton.addEventListener('mouseout', e => { Object.assign(dlButton.style, { opacity: 0, }); }) Object.assign(dlButton.style, { display: "flex", position: "absolute", top: "5px", left: "5px", alignItems: "center", backgroundColor: "#00202f", color: "#fff", fontSize: "1.4rem", textDecoration: "none", borderRadius: "8px", cursor: "pointer", opacity: 0, transition: "all 0.3s ease 0.3s", }); var dlIcon = document.createElement("span"); dlIcon.innerHTML = downloadIcon; Object.assign(dlIcon.style, { filter: "invert()", width: "20px", padding: "10px 13px", }); dlButton.appendChild(dlIcon); return dlButton } function ensureTALinks() { var channelContainerNodes = getChannelContainers() for (var channelContainer of channelContainerNodes) { if (channelContainer.hasTA) continue; var channelButton = buildChannelButton(channelContainer); channelContainer.appendChild(channelButton); channelContainer.hasTA = true; } var thumbContainerNodes = getThubnailContainers(); for (var thumbContainer of thumbContainerNodes) { if (thumbContainer.hasTA) continue; var videoButton = buildVideoButton(thumbContainer); if (videoButton == null) continue; thumbContainer.parentElement.appendChild(videoButton); thumbContainer.hasTA = true; } } function sendUrl(url, action) { let payload = { "youtube": { "url": url, "action": action, } } console.log("youtube link: " + JSON.stringify(payload)); browserType.runtime.sendMessage(payload, function(response) { console.log("sendUrl response: " + JSON.stringify(response)) }); }; let observer = new MutationObserver(list => { if (list.some(i => i.type === 'childList' && i.addedNodes.length > 0)) { console.log("observer hit") ensureTALinks(); } }); observer.observe(document.body, { attributes: false, childList: true, subtree: true });