/******/ (() => { // webpackBootstrap /******/ "use strict"; var __webpack_exports__ = {}; ;// CONCATENATED MODULE: ./Extensions/combined/src/utils.js function numberFormat(numberState) { return getNumberFormatter(extConfig.numberDisplayFormat).format( numberState ); } function getNumberFormatter(optionSelect) { let userLocales; if (document.documentElement.lang) { userLocales = document.documentElement.lang; } else if (navigator.language) { userLocales = navigator.language; } else { try { userLocales = new URL( Array.from(document.querySelectorAll("head > link[rel='search']")) ?.find((n) => n?.getAttribute("href")?.includes("?locale=")) ?.getAttribute("href") )?.searchParams?.get("locale"); } catch { utils_cLog( "Cannot find browser locale. Use en as default for number formatting." ); userLocales = "en"; } } let formatterNotation; let formatterCompactDisplay; switch (optionSelect) { case "compactLong": formatterNotation = "compact"; formatterCompactDisplay = "long"; break; case "standard": formatterNotation = "standard"; formatterCompactDisplay = "short"; break; case "compactShort": default: formatterNotation = "compact"; formatterCompactDisplay = "short"; } const formatter = Intl.NumberFormat(userLocales, { notation: formatterNotation, compactDisplay: formatterCompactDisplay, }); return formatter; } function localize(localeString) { return chrome.i18n.getMessage(localeString); } function getBrowser() { if (typeof chrome !== "undefined" && typeof chrome.runtime !== "undefined") { return chrome; } else if ( typeof browser !== "undefined" && typeof browser.runtime !== "undefined" ) { return browser; } else { console.log("browser is not supported"); return false; } } function getVideoId(url) { const urlObject = new URL(url); const pathname = urlObject.pathname; if (pathname.startsWith("/clip")) { return document.querySelector("meta[itemprop='videoId']").content; } else { if (pathname.startsWith("/shorts")) { return pathname.slice(8); } return urlObject.searchParams.get("v"); } } function isInViewport(element) { const rect = element.getBoundingClientRect(); const height = innerHeight || document.documentElement.clientHeight; const width = innerWidth || document.documentElement.clientWidth; return ( // When short (channel) is ignored, the element (like/dislike AND short itself) is // hidden with a 0 DOMRect. In this case, consider it outside of Viewport !(rect.top == 0 && rect.left == 0 && rect.bottom == 0 && rect.right == 0) && rect.top >= 0 && rect.left >= 0 && rect.bottom <= height && rect.right <= width ); } function isVideoLoaded() { const videoId = getVideoId(window.location.href); return ( document.querySelector(`ytd-watch-flexy[video-id='${videoId}']`) !== null || // mobile: no video-id attribute document.querySelector('#player[loading="false"]:not([hidden])') !== null ); } function utils_cLog(message, writer) { message = `[return youtube dislike]: ${message}`; if (writer) { writer(message); } else { console.log(message); } } function getColorFromTheme(voteIsLike) { let colorString; switch (extConfig.colorTheme) { case "accessible": if (voteIsLike === true) { colorString = "dodgerblue"; } else { colorString = "gold"; } break; case "neon": if (voteIsLike === true) { colorString = "aqua"; } else { colorString = "magenta"; } break; case "classic": default: if (voteIsLike === true) { colorString = "lime"; } else { colorString = "red"; } } return colorString; } ;// CONCATENATED MODULE: ./Extensions/combined/src/bar.js function createRateBar(likes, dislikes) { if (!isLikesDisabled()) { let rateBar = document.getElementById("ryd-bar-container"); const widthPx = getLikeButton().clientWidth + getDislikeButton().clientWidth + 8; const widthPercent = likes + dislikes > 0 ? (likes / (likes + dislikes)) * 100 : 50; var likePercentage = parseFloat(widthPercent.toFixed(1)); const dislikePercentage = (100 - likePercentage).toLocaleString(); likePercentage = likePercentage.toLocaleString(); if (extConfig.showTooltipPercentage) { var tooltipInnerHTML; switch (extConfig.tooltipPercentageMode) { case "dash_dislike": tooltipInnerHTML = `${likes.toLocaleString()} / ${dislikes.toLocaleString()}  -  ${dislikePercentage}%`; break; case "both": tooltipInnerHTML = `${likePercentage}% / ${dislikePercentage}%`; break; case "only_like": tooltipInnerHTML = `${likePercentage}%`; break; case "only_dislike": tooltipInnerHTML = `${dislikePercentage}%`; break; default: // dash_like tooltipInnerHTML = `${likes.toLocaleString()} / ${dislikes.toLocaleString()}  -  ${likePercentage}%`; } } else { tooltipInnerHTML = `${likes.toLocaleString()} / ${dislikes.toLocaleString()}`; } if (!isShorts()) { if (!rateBar && !isMobile()) { let colorLikeStyle = ""; let colorDislikeStyle = ""; if (extConfig.coloredBar) { colorLikeStyle = "; background-color: " + getColorFromTheme(true); colorDislikeStyle = "; background-color: " + getColorFromTheme(false); } ( document.getElementById( isNewDesign() ? "actions-inner" : "menu-container" ) || document.querySelector("ytm-slim-video-action-bar-renderer") ).insertAdjacentHTML( "beforeend", `
${tooltipInnerHTML}
` ); // Add border between info and comments if (isNewDesign()) { let descriptionAndActionsElement = document.getElementById("top-row"); descriptionAndActionsElement.style.borderBottom = "1px solid var(--yt-spec-10-percent-layer)"; descriptionAndActionsElement.style.paddingBottom = "10px"; } } else { document.getElementById("ryd-bar-container").style.width = widthPx + "px"; document.getElementById("ryd-bar").style.width = widthPercent + "%"; document.querySelector("#ryd-dislike-tooltip > #tooltip").innerHTML = tooltipInnerHTML; if (extConfig.coloredBar) { document.getElementById("ryd-bar-container").style.backgroundColor = getColorFromTheme(false); document.getElementById("ryd-bar").style.backgroundColor = getColorFromTheme(true); } } } } else { utils_cLog("removing bar"); let ratebar = document.getElementById("ryd-bar-container"); if (ratebar) { ratebar.parentNode.removeChild(ratebar); } } } ;// CONCATENATED MODULE: ./Extensions/combined/src/starRating.js function createStarRating(rating, isMobile) { let starRating = document.createElement("label"); let starSlider = document.createElement("input"); starSlider.setAttribute("class", "rating"); starSlider.setAttribute("max", "5"); starSlider.setAttribute("readonly", ""); starSlider.setAttribute( "style", `--fill:rgb(255, 215, 0);--value:${rating.toString()};};background-color: transparent;` ); starSlider.setAttribute("type", "range"); starRating.appendChild(starSlider); let YTLikeButton; if (isMobile) { YTLikeButton = document.querySelector( "#app > div.page-container > ytm-watch > ytm-single-column-watch-next-results-renderer > ytm-slim-video-metadata-section-renderer > ytm-slim-video-action-bar-renderer > div > ytm-slim-metadata-toggle-button-renderer:nth-child(1)" ); } else { YTLikeButton = document.querySelector( "#top-level-buttons-computed > ytd-toggle-button-renderer:nth-child(1)" ); } YTLikeButton.insertAdjacentElement("afterend", starRating); try { let YTBar = document.querySelector("#ryd-bar-container"); YTBar.setAttribute("style", "width: 190%; height: 2px;"); } catch (err) { cLog("RateBar Not Present"); } let style = ``; document.head.insertAdjacentHTML("beforeend", style); } ;// CONCATENATED MODULE: ./Extensions/combined/src/state.js //TODO: Do not duplicate here and in ryd.background.js const apiUrl = "https://returnyoutubedislikeapi.com"; const LIKED_STATE = "LIKED_STATE"; const DISLIKED_STATE = "DISLIKED_STATE"; const NEUTRAL_STATE = "NEUTRAL_STATE"; let extConfig = { disableVoteSubmission: false, coloredThumbs: false, coloredBar: false, colorTheme: "classic", numberDisplayFormat: "compactShort", showTooltipPercentage: false, tooltipPercentageMode: "dash_like", numberDisplayReformatLikes: false, }; let storedData = { likes: 0, dislikes: 0, previousState: NEUTRAL_STATE, }; function isMobile() { return location.hostname == "m.youtube.com"; } function isShorts() { return location.pathname.startsWith("/shorts"); } function isNewDesign() { return document.getElementById("comment-teaser") !== null; } let mutationObserver = new Object(); if (isShorts() && mutationObserver.exists !== true) { utils_cLog("initializing mutation observer"); mutationObserver.options = { childList: false, attributes: true, subtree: false, }; mutationObserver.exists = true; mutationObserver.observer = new MutationObserver(function ( mutationList, observer ) { mutationList.forEach((mutation) => { if ( mutation.type === "attributes" && mutation.target.nodeName === "TP-YT-PAPER-BUTTON" && mutation.target.id === "button" ) { // cLog('Short thumb button status changed'); if (mutation.target.getAttribute("aria-pressed") === "true") { mutation.target.style.color = mutation.target.parentElement.parentElement.id === "like-button" ? getColorFromTheme(true) : getColorFromTheme(false); } else { mutation.target.style.color = "unset"; } return; } utils_cLog( "unexpected mutation observer event: " + mutation.target + mutation.type ); }); }); } function isLikesDisabled() { // return true if the like button's text doesn't contain any number if (isMobile()) { return /^\D*$/.test( getButtons().children[0].querySelector(".button-renderer-text").innerText ); } return /^\D*$/.test( getButtons().children[0].innerText ); } function isVideoLiked() { if (isMobile()) { return ( getLikeButton().querySelector("button").getAttribute("aria-label") == "true" ); } return getLikeButton().classList.contains("style-default-active"); } function isVideoDisliked() { if (isMobile()) { return ( getDislikeButton().querySelector("button").getAttribute("aria-label") == "true" ); } return getDislikeButton().classList.contains("style-default-active"); } function getState(storedData) { if (isVideoLiked()) { return { current: LIKED_STATE, previous: storedData.previousState }; } if (isVideoDisliked()) { return { current: DISLIKED_STATE, previous: storedData.previousState }; } return { current: NEUTRAL_STATE, previous: storedData.previousState }; } //--- Sets The Likes And Dislikes Values ---// function setLikes(likesCount) { getLikeTextContainer().innerText = likesCount; } function setDislikes(dislikesCount) { getDislikeTextContainer()?.removeAttribute('is-empty'); if (!isLikesDisabled()) { if (isMobile()) { getButtons().children[1].querySelector( ".button-renderer-text" ).innerText = dislikesCount; return; } getDislikeTextContainer().innerText = dislikesCount; } else { utils_cLog("likes count disabled by creator"); if (isMobile()) { getButtons().children[1].querySelector( ".button-renderer-text" ).innerText = localize("TextLikesDisabled"); return; } getDislikeTextContainer().innerText = localize("TextLikesDisabled"); } } function getLikeCountFromButton() { try { if (isShorts()) { //Youtube Shorts don't work with this query. It's not nessecary; we can skip it and still see the results. //It should be possible to fix this function, but it's not critical to showing the dislike count. return false; } let likesStr = getLikeButton() .querySelector("yt-formatted-string#text") .getAttribute("aria-label") .replace(/\D/g, ""); return likesStr.length > 0 ? parseInt(likesStr) : false; } catch { return false; } } function processResponse(response, storedData) { const formattedDislike = numberFormat(response.dislikes); setDislikes(formattedDislike); if (extConfig.numberDisplayReformatLikes === true) { const nativeLikes = getLikeCountFromButton(); if (nativeLikes !== false) { setLikes(numberFormat(nativeLikes)); } } storedData.dislikes = parseInt(response.dislikes); storedData.likes = getLikeCountFromButton() || parseInt(response.likes); createRateBar(storedData.likes, storedData.dislikes); if (extConfig.coloredThumbs === true) { if (isShorts()) { // for shorts, leave deactived buttons in default color let shortLikeButton = getLikeButton().querySelector( "tp-yt-paper-button#button" ); let shortDislikeButton = getDislikeButton().querySelector( "tp-yt-paper-button#button" ); if (shortLikeButton.getAttribute("aria-pressed") === "true") { shortLikeButton.style.color = getColorFromTheme(true); } if (shortDislikeButton.getAttribute("aria-pressed") === "true") { shortDislikeButton.style.color = getColorFromTheme(false); } mutationObserver.observer.observe( shortLikeButton, mutationObserver.options ); mutationObserver.observer.observe( shortDislikeButton, mutationObserver.options ); } else { getLikeButton().style.color = getColorFromTheme(true); getDislikeButton().style.color = getColorFromTheme(false); } } //Temporary disabling this - it breaks all places where getButtons()[1] is used // createStarRating(response.rating, isMobile()); } // Tells the user if the API is down function displayError(error) { getButtons().children[1].querySelector("#text").innerText = localize( "textTempUnavailable" ); } async function setState(storedData) { storedData.previousState = isVideoDisliked() ? DISLIKED_STATE : isVideoLiked() ? LIKED_STATE : NEUTRAL_STATE; let statsSet = false; let videoId = getVideoId(window.location.href); let likeCount = getLikeCountFromButton() || null; let response = await fetch( `${apiUrl}/votes?videoId=${videoId}&likeCount=${likeCount || ""}`, { method: "GET", headers: { Accept: "application/json", }, } ) .then((response) => { if (!response.ok) displayError(response.error); return response; }) .then((response) => response.json()) .catch(displayError); utils_cLog("response from api:"); utils_cLog(JSON.stringify(response)); if (response !== undefined && !("traceId" in response) && !statsSet) { processResponse(response, storedData); } } function setInitialState() { setState(storedData); } function initExtConfig() { initializeDisableVoteSubmission(); initializeColoredThumbs(); initializeColoredBar(); initializeColorTheme(); initializeNumberDisplayFormat(); initializeTooltipPercentage(); initializeTooltipPercentageMode(); initializeNumberDisplayReformatLikes(); } function initializeDisableVoteSubmission() { getBrowser().storage.sync.get(["disableVoteSubmission"], (res) => { if (res.disableVoteSubmission === undefined) { getBrowser().storage.sync.set({ disableVoteSubmission: false }); } else { extConfig.disableVoteSubmission = res.disableVoteSubmission; } }); } function initializeColoredThumbs() { getBrowser().storage.sync.get(["coloredThumbs"], (res) => { if (res.coloredThumbs === undefined) { getBrowser().storage.sync.set({ coloredThumbs: false }); } else { extConfig.coloredThumbs = res.coloredThumbs; } }); } function initializeColoredBar() { getBrowser().storage.sync.get(["coloredBar"], (res) => { if (res.coloredBar === undefined) { getBrowser().storage.sync.set({ coloredBar: false }); } else { extConfig.coloredBar = res.coloredBar; } }); } function initializeColorTheme() { getBrowser().storage.sync.get(["colorTheme"], (res) => { if (res.colorTheme === undefined) { getBrowser().storage.sync.set({ colorTheme: false }); } else { extConfig.colorTheme = res.colorTheme; } }); } function initializeNumberDisplayFormat() { getBrowser().storage.sync.get(["numberDisplayFormat"], (res) => { if (res.numberDisplayFormat === undefined) { getBrowser().storage.sync.set({ numberDisplayFormat: "compactShort" }); } else { extConfig.numberDisplayFormat = res.numberDisplayFormat; } }); } function initializeTooltipPercentage() { getBrowser().storage.sync.get(["showTooltipPercentage"], (res) => { if (res.showTooltipPercentage === undefined) { getBrowser().storage.sync.set({ showTooltipPercentage: false }); } else { extConfig.showTooltipPercentage = res.showTooltipPercentage; } }); } function initializeTooltipPercentageMode() { getBrowser().storage.sync.get(["tooltipPercentageMode"], (res) => { if (res.tooltipPercentageMode === undefined) { getBrowser().storage.sync.set({ tooltipPercentageMode: "dash_like" }); } else { extConfig.tooltipPercentageMode = res.tooltipPercentageMode; } }); } function initializeNumberDisplayReformatLikes() { getBrowser().storage.sync.get(["numberDisplayReformatLikes"], (res) => { if (res.numberDisplayReformatLikes === undefined) { getBrowser().storage.sync.set({ numberDisplayReformatLikes: false }); } else { extConfig.numberDisplayReformatLikes = res.numberDisplayReformatLikes; } }); } ;// CONCATENATED MODULE: ./Extensions/combined/src/buttons.js function getButtons() { //--- If Watching Youtube Shorts: ---// if (isShorts()) { let elements = document.querySelectorAll( isMobile() ? "ytm-like-button-renderer" : "#like-button > ytd-like-button-renderer" ); for (let element of elements) { //Youtube Shorts can have multiple like/dislike buttons when scrolling through videos //However, only one of them should be visible (no matter how you zoom) if (isInViewport(element)) { return element; } } } //--- If Watching On Mobile: ---// if (isMobile()) { return document.querySelector(".slim-video-action-bar-actions"); } //--- If Menu Element Is Displayed: ---// if (document.getElementById("menu-container")?.offsetParent === null) { return document.querySelector("ytd-menu-renderer.ytd-watch-metadata > div"); //--- If Menu Element Isnt Displayed: ---// } else { return document .getElementById("menu-container") ?.querySelector("#top-level-buttons-computed"); } } function getLikeButton() { return getButtons().children[0].tagName === "YTD-SEGMENTED-LIKE-DISLIKE-BUTTON-RENDERER" ? getButtons().children[0].children[0] : getButtons().children[0]; } function getLikeTextContainer() { return ( getLikeButton().querySelector("#text") ?? getLikeButton().getElementsByTagName("yt-formatted-string")[0] ); } function getDislikeButton() { return getButtons().children[0].tagName === "YTD-SEGMENTED-LIKE-DISLIKE-BUTTON-RENDERER" ? getButtons().children[0].children[1] : getButtons().children[1]; } function getDislikeTextContainer() { let result = getDislikeButton().querySelector("#text") ?? getDislikeButton().getElementsByTagName("yt-formatted-string")[0] ?? getDislikeButton().querySelector("span[role='text']"); if (result == null) { let textSpan = document.createElement("span"); textSpan.id = "text"; getDislikeButton().querySelector("button").appendChild(textSpan); getDislikeButton().querySelector("button").style.width = "auto"; result = getDislikeButton().querySelector("#text"); } return result; } function checkForSignInButton() { if ( document.querySelector( "a[href^='https://accounts.google.com/ServiceLogin']" ) ) { return true; } else { return false; } } ;// CONCATENATED MODULE: ./Extensions/combined/src/events.js function sendVote(vote) { if (extConfig.disableVoteSubmission !== true) { getBrowser().runtime.sendMessage({ message: "send_vote", vote: vote, videoId: getVideoId(window.location.href), }); } } function likeClicked() { if (checkForSignInButton() === false) { if (storedData.previousState === DISLIKED_STATE) { sendVote(1); if (storedData.dislikes > 0) storedData.dislikes--; storedData.likes++; createRateBar(storedData.likes, storedData.dislikes); setDislikes(numberFormat(storedData.dislikes)); storedData.previousState = LIKED_STATE; } else if (storedData.previousState === NEUTRAL_STATE) { sendVote(1); storedData.likes++; createRateBar(storedData.likes, storedData.dislikes); storedData.previousState = LIKED_STATE; } else if ((storedData.previousState = LIKED_STATE)) { sendVote(0); if (storedData.likes > 0) storedData.likes--; createRateBar(storedData.likes, storedData.dislikes); storedData.previousState = NEUTRAL_STATE; } if (extConfig.numberDisplayReformatLikes === true) { const nativeLikes = getLikeCountFromButton(); if (nativeLikes !== false) { setLikes(numberFormat(nativeLikes)); } } } } function dislikeClicked() { if (checkForSignInButton() == false) { if (storedData.previousState === NEUTRAL_STATE) { sendVote(-1); storedData.dislikes++; setDislikes(numberFormat(storedData.dislikes)); createRateBar(storedData.likes, storedData.dislikes); storedData.previousState = DISLIKED_STATE; } else if (storedData.previousState === DISLIKED_STATE) { sendVote(0); if (storedData.dislikes > 0) storedData.dislikes--; setDislikes(numberFormat(storedData.dislikes)); createRateBar(storedData.likes, storedData.dislikes); storedData.previousState = NEUTRAL_STATE; } else if (storedData.previousState === LIKED_STATE) { sendVote(-1); if (storedData.likes > 0) storedData.likes--; storedData.dislikes++; setDislikes(numberFormat(storedData.dislikes)); createRateBar(storedData.likes, storedData.dislikes); storedData.previousState = DISLIKED_STATE; if (extConfig.numberDisplayReformatLikes === true) { const nativeLikes = getLikeCountFromButton(); if (nativeLikes !== false) { setLikes(numberFormat(nativeLikes)); } } } } } function addLikeDislikeEventListener() { if (!window.returnDislikeButtonlistenersSet) { getLikeButton().addEventListener("click", likeClicked); getDislikeButton().addEventListener("click", dislikeClicked); getLikeButton().addEventListener("touchstart", likeClicked); getLikeButton().addEventListener("touchstart", dislikeClicked); window.returnDislikeButtonlistenersSet = true; } } function storageChangeHandler(changes, area) { if (changes.disableVoteSubmission !== undefined) { handleDisableVoteSubmissionChangeEvent( changes.disableVoteSubmission.newValue ); } if (changes.coloredThumbs !== undefined) { handleColoredThumbsChangeEvent(changes.coloredThumbs.newValue); } if (changes.coloredBar !== undefined) { handleColoredBarChangeEvent(changes.coloredBar.newValue); } if (changes.colorTheme !== undefined) { handleColorThemeChangeEvent(changes.colorTheme.newValue); } if (changes.numberDisplayFormat !== undefined) { handleNumberDisplayFormatChangeEvent(changes.numberDisplayFormat.newValue); } if (changes.numberDisplayReformatLikes !== undefined) { handleNumberDisplayReformatLikesChangeEvent( changes.numberDisplayReformatLikes.newValue ); } } function handleDisableVoteSubmissionChangeEvent(value) { extConfig.disableVoteSubmission = value; } function handleColoredThumbsChangeEvent(value) { extConfig.coloredThumbs = value; } function handleColoredBarChangeEvent(value) { extConfig.coloredBar = value; } function handleColorThemeChangeEvent(value) { if (!value) value = "classic"; extConfig.colorTheme = value; } function handleNumberDisplayFormatChangeEvent(value) { extConfig.numberDisplayFormat = value; } function handleNumberDisplayReformatLikesChangeEvent(value) { extConfig.numberDisplayReformatLikes = value; } ;// CONCATENATED MODULE: ./Extensions/combined/ryd.content-script.js //--- Import Button Functions ---// //--- Import State Functions ---// //--- Import Video & Browser Functions ---// initExtConfig(); let jsInitChecktimer = null; function setEventListeners(evt) { function checkForJS_Finish() { if (isShorts() || (getButtons()?.offsetParent && isVideoLoaded())) { addLikeDislikeEventListener(); setInitialState(); getBrowser().storage.onChanged.addListener(storageChangeHandler); clearInterval(jsInitChecktimer); jsInitChecktimer = null; } } jsInitChecktimer = setInterval(checkForJS_Finish, 111); } setEventListeners(); document.addEventListener("yt-navigate-finish", function (event) { if (jsInitChecktimer !== null) clearInterval(jsInitChecktimer); window.returnDislikeButtonlistenersSet = false; setEventListeners(); }); /******/ })() ;