Skip to content

Instantly share code, notes, and snippets.

@b159732000
Forked from Yukaii/READMD.md
Created November 21, 2021 07:09
Show Gist options
  • Save b159732000/70f29541237b28740d5e2aa3487f9bef to your computer and use it in GitHub Desktop.
Save b159732000/70f29541237b28740d5e2aa3487f9bef to your computer and use it in GitHub Desktop.
A Tampermonkey script to make YouTube dislike count back

Make YouTube dislike count BACK!

ATTENTION: According to YouTube's announcement, this script will soon become invalid.

Developers: If you’re using the YouTube API for dislikes, you will no longer have access to public dislike data beginning on December 13th ref: https://support.google.com/youtube/thread/134791097/update-to-youtube-dislike-counts?hl=en

スクリーンショット 2021-11-13 午後0 28 00

Installation

  1. Install Tampermoneky or Greasemonkey(Firefox) for your browser
  2. Click on this link to install.
  3. Go to Google Developer Console and generate new YouTube Data API key:
    1. Create a new project:
      スクリーンショット 2021-11-13 午後0 05 02
    2. Go to "API and Services", and enable YouTube Data API: スクリーンショット 2021-11-13 午後0 07 21 スクリーンショット 2021-11-13 午後0 08 24
    3. Create new API key credentials, and copy it for later use: スクリーンショット 2021-11-13 午後0 09 14
  4. Go to an YouTube video, it will prompt you to enter the key, paste it and hit enter スクリーンショット 2021-11-13 午後0 11 49
  5. And you will get dislike count back!
// ==UserScript==
// @name Make YouTube dislike count BACK!
// @namespace https://yukai.dev
// @version 0.3
// @description try to take over the world!
// @author Yukai Huang
// @include https://www.youtube.com/*
// @icon https://www.google.com/s2/favicons?domain=youtube.com
// @downloadURL https://gist.githubusercontent.com/Tajnymag/48801545e9cb2c1e7fb84ac39af112b2/raw/youtube-dislike-back.user.js
// @grant none
// ==/UserScript==
(function () {
function loadConfig() {
const ITEM_KEY = 'YOUTUBE_DISLIKE_COUNT_API_KEY';
const apiKey = window.localStorage.getItem(ITEM_KEY);
if (apiKey) {
return apiKey;
} else {
const key = prompt('Enter your youtube dislike count api key');
window.localStorage.setItem(ITEM_KEY, key);
return key;
}
}
function getVideoId() {
const params = new URLSearchParams(window.location.search);
const videoId = params.get('v') || '';
return videoId;
}
function cacheFn(fn) {
const cache = {};
return async function (...args) {
const key = args.join('-');
if (cache[key]) {
return cache[key];
} else {
const result = await Promise.resolve(fn(...args));
cache[key] = result;
return result;
}
};
}
async function fetchVideoStatistics(videoId) {
if (!videoId) {
return;
}
const key = loadConfig();
const params = new URLSearchParams({
part: 'statistics',
id: videoId,
key,
});
const { items = [] } = await fetch(
`https://www.googleapis.com/youtube/v3/videos?${params}`,
).then((res) => res.json());
if (items?.length === 0) {
return {};
}
const { likeCount: likeCountString, dislikeCount: dislikeCountString } =
items && items[0] && items[0].statistics;
const likeCount = parseInt(likeCountString, 10);
const dislikeCount = parseInt(dislikeCountString, 10);
return {
likeCount,
dislikeCount,
};
}
const fetchVideoStatisticsCached = cacheFn(fetchVideoStatistics);
async function getVideoStatistics() {
const videoId = getVideoId();
return fetchVideoStatisticsCached(videoId);
}
function formatCount(count) {
if (Math.log10(count) > 9) {
return `${Math.floor(count / 1000000)}M`;
} else if (Math.log10(count) > 6) {
return `${Math.floor(count / 1000)}K`;
} else {
return count;
}
}
function renderStatistics(likeCount, dislikeCount) {
const percentage = (likeCount / (likeCount + dislikeCount)) * 100;
const existingBar = document.querySelector(
'#sentiment.ytd-video-primary-info-renderer',
);
if (existingBar) {
existingBar.remove();
}
const barElement = document.createElement('div');
barElement.setAttribute('id', 'sentiment');
barElement.setAttribute('system-icons', '');
barElement.setAttribute('style', `width: 145px;`);
barElement.className = 'style-scope ytd-video-primary-info-renderer';
barElement.title = `${likeCount} / ${likeCount + dislikeCount}`;
barElement.innerHTML = `
<div id="container" class="style-scope ytd-sentiment-bar-renderer">
<div id="like-bar" class="style-scope ytd-sentiment-bar-renderer" style="width: ${percentage}%;"></div>
</div>`;
document
.querySelector('#menu-container.ytd-video-primary-info-renderer')
?.append(barElement);
const dislikeTextNode = document.querySelectorAll(
'#menu ytd-toggle-button-renderer yt-formatted-string',
)[1];
if (dislikeTextNode) {
dislikeTextNode.textContent = `${formatCount(dislikeCount)}`;
}
}
async function run() {
const { dislikeCount, likeCount } = await getVideoStatistics();
if (likeCount && dislikeCount) {
renderStatistics(likeCount, dislikeCount);
}
}
const menuSelector = '#menu';
new MutationObserver(function (mutations) {
mutations.forEach(function (mutation) {
if (mutation.addedNodes.length > 0) {
const menu =
mutation.addedNodes[0].querySelector &&
mutation.addedNodes[0].querySelector(menuSelector);
if (menu) {
run();
}
}
});
}).observe(document.body, {
childList: true,
subtree: true,
});
new MutationObserver(function (mutations) {
mutations.forEach(function (mutation) {
const menu = document.querySelector(menuSelector);
if (menu) {
run();
}
});
}).observe(document.querySelector('ytd-app'), {
attributes: true,
});
})();
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment