您需要先安装一个扩展,例如 篡改猴、Greasemonkey 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 Userscripts ,之后才能安装此脚本。
您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey,才能安装此脚本。
您需要先安装用户脚本管理器扩展后才能安装此脚本。
Return dislikes on youtube mobile page. Uses returnyoutubedislike.com API
// ==UserScript== // @name Return Youtube Dislike On Mobile // @namespace https://gitlab.com/Dwyriel // @version 1.3.5 // @description Return dislikes on youtube mobile page. Uses returnyoutubedislike.com API // @author Dwyriel // @license MIT // @match *://*.youtube.com/* // @grant none // @homepageURL https://gitlab.com/Dwyriel/Greasyfork-Scripts // ==/UserScript== (function () { 'use strict'; const scriptName = "[Return Youtube Dislike On Mobile]"; const scriptPolicyName = "RYDoM_Policy"; const API_URL = "https://returnyoutubedislikeapi.com/votes?videoId="; const buttonSegmentClass = "ytSegmentedLikeDislikeButtonViewModelSegmentedButtonsWrapper"; const dislikeButtonID = "dislikeButtonID_198wa16df78ms1d"; let dislikeCache = {}; let oldURL = ""; let videoID; let fetching = false; const config = { attributes: true, childList: true, subtree: true }; let mutationObserver = new MutationObserver(() => { }); const getVideoID = () => { return (new Proxy(new URLSearchParams(window.location.search), { get: (UrlSearchParams, key) => UrlSearchParams.get(key) })).v; } const formatedDislikeNumber = () => { let dislikes = dislikeCache[videoID]; let formattedNum = ""; if (dislikes / 10E8 >= 1) formattedNum = `${Math.round(dislikes / 10E8)}B`; else if (dislikes / 10E5 >= 1) formattedNum = `${Math.round(dislikes / 10E5)}M`; else if (dislikes / 1000 >= 1) { if (dislikes < 10E3) formattedNum += `${Math.floor(dislikes / 1000)}.${Math.floor((dislikes % 1000) / 100)}K`; else formattedNum = `${Math.round(dislikes / 1000)}K`; } else formattedNum = `${dislikes}`; return formattedNum; } const setInnerHTML = (element, html) => { try { if (trustedTypes) { const trustedTypesPolice = trustedTypes.createPolicy(scriptPolicyName, { createHTML: (string) => string }); element.innerHTML = trustedTypesPolice.createHTML(html); } else { element.innerHTML = html; } } catch (err) { console.error(err); } } const modifyDislikeButton = () => { //check explanation at the end of the file let buttons = document.getElementsByClassName(buttonSegmentClass)[0].children; if (buttons.length == 0) return; document.getElementById(dislikeButtonID)?.remove(); let dislikeButton = buttons[1].getElementsByTagName("button")[0]; dislikeButton.children[0].style = "margin: 0 6px 0 -6px"; let dislikes = buttons[0].getElementsByClassName("yt-spec-button-shape-next__button-text-content")[0].cloneNode(true); dislikes.id = dislikeButtonID; dislikeButton.appendChild(dislikes); dislikeButton.appendChild(dislikeButton.children[1]); let dislikeString = formatedDislikeNumber(); setInnerHTML(dislikes, dislikeString); dislikeButton.style = `width: ${62 + (8 * dislikeString.length)}px !important; padding-left: 14px`; } let hookObserver = async () => { let buttons = document.getElementsByClassName(buttonSegmentClass); if (buttons.length > 0 && buttons[0].children != undefined) { mutationObserver.disconnect(); modifyDislikeButton(); mutationObserver.observe(buttons[0], config); } else await new Promise(() => setTimeout(hookObserver, 100)); } const callback = () => { let currURL = window.location.href; if (window.location.pathname != "/watch") { oldURL = currURL; return; } if (fetching || (oldURL == currURL)) return; fetching = true; oldURL = currURL; videoID = getVideoID(); if (typeof videoID != 'string') { fetching = false; return; } if (dislikeCache[videoID] != undefined) { fetching = false; hookObserver(); return; } let request = new Request(API_URL + videoID); fetch(request).then(response => response.json(), (reason) => { fetching = false; console.error("Couldn't fetch dislikes", reason) }).then(response => { console.log(`${scriptName} response from api: \n${JSON.stringify(response)}`); dislikeCache[videoID] = response.dislikes; fetching = false; hookObserver(); }, (reason) => { fetching = false; console.error("Couldn't fetch dislikes", reason) }); }; mutationObserver = new MutationObserver(() => { hookObserver(); }); const old_pushState = history.pushState; history.pushState = function pushState() { let origFuncReturn = old_pushState.apply(this, arguments); window.dispatchEvent(new Event('historyChanged')); return origFuncReturn; }; window.addEventListener('popstate', () => window.dispatchEvent(new Event('historyChanged'))); window.addEventListener('load', () => callback()); window.addEventListener('historyChanged', () => { mutationObserver.disconnect(); callback(); }); })(); /* modifyDislikeButton function explanation let buttons = document.getElementsByClassName(buttonSegmentClass)[0].children; //get both like and dislike buttons if they exist if (buttons.length == 0) return; document.getElementById(dislikeButtonID)?.remove(); //remove if it was already created before let dislikeButton = buttons[1].getElementsByTagName("button")[0]; //the dislike "button" element dislikeButton.children[0].style = "margin: 0 6px 0 -6px"; //fix margin to accomodate changes let dislikes = buttons[0].getElementsByClassName("yt-spec-button-shape-next__button-text-content")[0].cloneNode(true); //clone the text tag of the like button to be added to the dislike dislikes.id = dislikeButtonID; //set custom ID dislikeButton.appendChild(dislikes); //append cloned node to dislike button dislikeButton.appendChild(dislikeButton.children[1]); //move nodes around to be in the same order as the like button let dislikeString = formatedDislikeNumber(); //formats and adds the formated string to the cloned node's inner HTML dislikes.innerHTML = dislikeString; dislikeButton.style = `width: ${56 + (8 * dislikeString.length)}px`; //adjust button width based on formated string */