|
@@ -4,7 +4,7 @@
|
|
|
// @version 0.5
|
|
|
// @description Return of the YouTube Dislike, Based off https://www.returnyoutubedislike.com/
|
|
|
// @author Anarios & JRWR
|
|
|
-// @match *://*.youtube.com/watch*
|
|
|
+// @match *://*.youtube.com/*
|
|
|
// @compatible chrome
|
|
|
// @compatible firefox
|
|
|
// @compatible opera
|
|
@@ -16,36 +16,12 @@
|
|
|
// ==/UserScript==
|
|
|
function cLog(text, subtext = '') {
|
|
|
subtext = subtext.trim() === '' ? '' : `(${subtext})`;
|
|
|
- console.log(`[Return Youtube Dislikes] ${text} ${subtext}`);
|
|
|
-}
|
|
|
-
|
|
|
-function doXHR(opts) {
|
|
|
- if (typeof GM_xmlhttpRequest === 'function') {
|
|
|
- return GM_xmlhttpRequest(opts);
|
|
|
- }
|
|
|
- if (typeof GM !== 'undefined') /*This will prevent from throwing "Uncaught ReferenceError: GM is not defined"*/{
|
|
|
- if (typeof GM.xmlHttpRequest === 'function') {
|
|
|
- return GM.xmlHttpRequest(opts);
|
|
|
- }
|
|
|
- }
|
|
|
-
|
|
|
- console.warn('Unable to detect UserScript plugin, falling back to native XHR.');
|
|
|
-
|
|
|
- const xhr = new XMLHttpRequest();
|
|
|
-
|
|
|
- xhr.open(opts.method, opts.url, true);
|
|
|
- xhr.onload = () => opts.onload({
|
|
|
- response: JSON.parse(xhr.responseText),
|
|
|
- });
|
|
|
- xhr.onerror = err => console.error('XHR Failed', err);
|
|
|
- xhr.send();
|
|
|
+ console.log(`[Return YouTube Dislikes] ${text} ${subtext}`);
|
|
|
}
|
|
|
|
|
|
function getButtons() {
|
|
|
if (document.getElementById("menu-container").offsetParent === null) {
|
|
|
- return document.querySelector(
|
|
|
- "ytd-menu-renderer.ytd-watch-metadata > div"
|
|
|
- );
|
|
|
+ return document.querySelector("ytd-menu-renderer.ytd-watch-metadata > div");
|
|
|
} else {
|
|
|
return document
|
|
|
.getElementById("menu-container")
|
|
@@ -96,9 +72,7 @@ function setDislikes(dislikesCount) {
|
|
|
}
|
|
|
|
|
|
function createRateBar(likes, dislikes) {
|
|
|
- var rateBar = document.getElementById(
|
|
|
- "return-youtube-dislike-bar-container"
|
|
|
- );
|
|
|
+ var rateBar = document.getElementById("return-youtube-dislike-bar-container");
|
|
|
|
|
|
const widthPx =
|
|
|
getButtons().children[0].clientWidth +
|
|
@@ -144,32 +118,46 @@ function createRateBar(likes, dislikes) {
|
|
|
}
|
|
|
|
|
|
function setState() {
|
|
|
- cLog('Fetching votes...');
|
|
|
-
|
|
|
- doXHR({
|
|
|
- method: "GET",
|
|
|
- responseType: "json",
|
|
|
- url:
|
|
|
- "https://return-youtube-dislike-api.azurewebsites.net/votes?videoId=" +
|
|
|
- getVideoId(),
|
|
|
- onload: function (xhr) {
|
|
|
- if (xhr != undefined) {
|
|
|
- const { dislikes, likes } = xhr.response;
|
|
|
+ cLog("Fetching votes...");
|
|
|
+ let statsSet = false;
|
|
|
+
|
|
|
+ fetch(`https://www.youtube.com/watch?v=${getVideoId()}`).then((response) => {
|
|
|
+ response.text().then((text) => {
|
|
|
+ let result = getDislikesFromYoutubeResponse(text);
|
|
|
+ if (result) {
|
|
|
+ cLog("response from youtube:");
|
|
|
+ cLog(JSON.stringify(result));
|
|
|
+ if (result.likes || result.dislikes) {
|
|
|
+ const formattedDislike = numberFormat(result.dislikes);
|
|
|
+ setDislikes(formattedDislike);
|
|
|
+ createRateBar(result.likes, result.dislikes);
|
|
|
+ statsSet = true;
|
|
|
+ }
|
|
|
+ }
|
|
|
+ });
|
|
|
+ });
|
|
|
+
|
|
|
+ fetch(
|
|
|
+ `https://return-youtube-dislike-api.azurewebsites.net/votes?videoId=${getVideoId()}`
|
|
|
+ ).then((response) => {
|
|
|
+ response.json().then((json) => {
|
|
|
+ if (json && !statsSet) {
|
|
|
+ const { dislikes, likes } = json;
|
|
|
cLog(`Received count: ${dislikes}`);
|
|
|
setDislikes(numberFormat(dislikes));
|
|
|
createRateBar(likes, dislikes);
|
|
|
}
|
|
|
- },
|
|
|
+ });
|
|
|
});
|
|
|
}
|
|
|
|
|
|
function likeClicked() {
|
|
|
- cLog('Like clicked', getState());
|
|
|
+ cLog("Like clicked", getState());
|
|
|
setState();
|
|
|
}
|
|
|
|
|
|
function dislikeClicked() {
|
|
|
- cLog('Dislike clicked', getState());
|
|
|
+ cLog("Dislike clicked", getState());
|
|
|
setState();
|
|
|
}
|
|
|
|
|
@@ -194,21 +182,53 @@ function isVideoLoaded() {
|
|
|
|
|
|
function roundDown(num) {
|
|
|
if (num < 1000) return num;
|
|
|
- const decimal = Math.floor(Math.log10(num) - 1);
|
|
|
+ const int = Math.floor(Math.log10(num) - 2);
|
|
|
+ const decimal = int + (int % 3 ? 1 : 0);
|
|
|
const value = Math.floor(num / 10 ** decimal);
|
|
|
- return value * (10 ** decimal);
|
|
|
+ return value * 10 ** decimal;
|
|
|
}
|
|
|
|
|
|
function numberFormat(numberState) {
|
|
|
const userLocales = navigator.language;
|
|
|
|
|
|
const formatter = Intl.NumberFormat(userLocales, {
|
|
|
- notation: 'compact',
|
|
|
+ notation: "compact",
|
|
|
minimumFractionDigits: 1,
|
|
|
- maximumFractionDigits: 1
|
|
|
+ maximumFractionDigits: 1,
|
|
|
});
|
|
|
|
|
|
- return formatter.format(roundDown(numberState)).replace('.0', '');
|
|
|
+ return formatter.format(roundDown(numberState)).replace(/\.0|,0/, "");
|
|
|
+}
|
|
|
+
|
|
|
+function getDislikesFromYoutubeResponse(htmlResponse) {
|
|
|
+ let start =
|
|
|
+ htmlResponse.indexOf('"videoDetails":') + '"videoDetails":'.length;
|
|
|
+ let end =
|
|
|
+ htmlResponse.indexOf('"isLiveContent":false}', start) +
|
|
|
+ '"isLiveContent":false}'.length;
|
|
|
+ if (end < start) {
|
|
|
+ end =
|
|
|
+ htmlResponse.indexOf('"isLiveContent":true}', start) +
|
|
|
+ '"isLiveContent":true}'.length;
|
|
|
+ }
|
|
|
+ let jsonStr = htmlResponse.substring(start, end);
|
|
|
+ let jsonResult = JSON.parse(jsonStr);
|
|
|
+ let rating = jsonResult.averageRating;
|
|
|
+
|
|
|
+ start = htmlResponse.indexOf('"topLevelButtons":[', end);
|
|
|
+ start =
|
|
|
+ htmlResponse.indexOf('"accessibilityData":', start) +
|
|
|
+ '"accessibilityData":'.length;
|
|
|
+ end = htmlResponse.indexOf("}", start);
|
|
|
+ let likes = +htmlResponse.substring(start, end).replace(/\D/g, "");
|
|
|
+ let dislikes = (likes * (5 - rating)) / (rating - 1);
|
|
|
+ let result = {
|
|
|
+ likes,
|
|
|
+ dislikes: Math.round(dislikes),
|
|
|
+ rating,
|
|
|
+ viewCount: +jsonResult.viewCount,
|
|
|
+ };
|
|
|
+ return result;
|
|
|
}
|
|
|
|
|
|
function setEventListeners(evt) {
|
|
@@ -218,7 +238,7 @@ function setEventListeners(evt) {
|
|
|
const buttons = getButtons();
|
|
|
|
|
|
if (!window.returnDislikeButtonlistenersSet) {
|
|
|
- cLog('Registering button listeners...');
|
|
|
+ cLog("Registering button listeners...");
|
|
|
buttons.children[0].addEventListener("click", likeClicked);
|
|
|
buttons.children[1].addEventListener("click", dislikeClicked);
|
|
|
window.returnDislikeButtonlistenersSet = true;
|
|
@@ -228,7 +248,7 @@ function setEventListeners(evt) {
|
|
|
}
|
|
|
|
|
|
if (window.location.href.indexOf("watch?") >= 0) {
|
|
|
- cLog('Setting up...');
|
|
|
+ cLog("Setting up...");
|
|
|
var jsInitChecktimer = setInterval(checkForJS_Finish, 111);
|
|
|
}
|
|
|
}
|