YouTubeでおすすめに表示される再生回数の少ない動画・投稿日の古い動画・ライブ視聴者数が少ない動画を非表示にします。再生回数・視聴者数のしきい値はコード内で変更可能。古い動画の非表示は1年前の動画から設定可能。チャンネル内の動画は無視するオプション付き。
当前为
// ==UserScript==
// @name YouTube用低視聴回数・古い動画・ライブ動画の非表示
// @namespace http://tampermonkey.net/
// @description YouTubeでおすすめに表示される再生回数の少ない動画・投稿日の古い動画・ライブ視聴者数が少ない動画を非表示にします。再生回数・視聴者数のしきい値はコード内で変更可能。古い動画の非表示は1年前の動画から設定可能。チャンネル内の動画は無視するオプション付き。
// @author sun
// @match *://*.youtube.com/*
// @icon https://www.google.com/s2/favicons?sz=64&domain=youtube.com
// @grant GM_registerMenuCommand
// @version 2.1
// ==/UserScript==
const VIEW_THRESHOLD = 1000; // 再生回数のしきい値
const AGE_THRESHOLD_YEARS = 0; // 年以上前の動画を非表示(0=無効)
const LIVE_FILTER_ENABLED = 0; // ライブ視聴者数で非表示判定(0=無効,1=有効)
const LIVE_VIEWER_THRESHOLD = 100; // ライブ視聴者数のしきい値
const DISABLE_ON_SUBSCRIPTIONS = true; // チャンネル内の動画は無視するか
const OPTION_STORAGE_KEY = 'YT_LowViewFilter_Settings';
const VIDEO_SELECTORS = "ytd-rich-item-renderer, ytd-compact-video-renderer, .yt-lockup-view-model-wiz";
const VIEW_COUNT_SELECTOR = [
".inline-metadata-item.style-scope.ytd-video-meta-block",
"span.yt-core-attributed-string.yt-content-metadata-view-model-wiz__metadata-text"
];
const LIVE_VIEWER_SELECTORS = [
".yt-content-metadata-view-model-wiz__metadata-text",
"span.yt-core-attributed-string"
];
let menuRegistered = false;
function parseViewCount(text) {
if (!text) return 0;
const multipliers = { "K": 1e3, "M": 1e6, "万": 1e4, "億": 1e8 };
let numText = text.replace(/[^0-9\.KM万億]/g, "");
let unit = Object.keys(multipliers).find(u => numText.includes(u)) || "";
numText = numText.replace(unit, "");
return numText ? parseFloat(numText) * (multipliers[unit] || 1) : 0;
}
function parseLiveViewerCount(text) {
if (!text) return 0;
const m = text.replace(/,/g, "").match(/([0-9]+)/);
if (m) {
return parseInt(m[1], 10);
}
return 0;
}
function isLiveVideo(videoElement) {
if (!videoElement || LIVE_FILTER_ENABLED === 0) return false;
for (const selector of LIVE_VIEWER_SELECTORS) {
const elems = videoElement.querySelectorAll(selector);
for (const elem of elems) {
if (elem && /[0-9,]+ 人が視聴中/.test(elem.innerText)) {
const count = parseLiveViewerCount(elem.innerText);
if (count > 0 && count < LIVE_VIEWER_THRESHOLD) {
return true;
}
return false;
}
}
}
return false;
}
function isBadVideo(videoElement) {
if (!videoElement) return false;
if (isLiveVideo(videoElement)) return true;
for (const selector of VIEW_COUNT_SELECTOR) {
const elems = videoElement.querySelectorAll(selector);
for (const elem of elems) {
if (elem && elem.innerText.includes('回視聴')) {
const viewCount = parseViewCount(elem.innerText);
if (viewCount > 0 && viewCount < VIEW_THRESHOLD) {
return true;
}
}
}
}
return false;
}
function isOldVideo(videoElement) {
if (AGE_THRESHOLD_YEARS === 0) return false;
const dateTexts = [];
const dateSelectors = [
".inline-metadata-item.style-scope.ytd-video-meta-block",
"span.yt-core-attributed-string.yt-content-metadata-view-model-wiz__metadata-text"
];
dateSelectors.forEach(sel => {
videoElement.querySelectorAll(sel).forEach(elm => {
const text = elm.innerText;
if (text && /前$/.test(text)) {
dateTexts.push(text);
}
});
});
for (const dateText of dateTexts) {
if (/([0-9]+)\s*年前/.test(dateText)) {
const years = parseInt(RegExp.$1, 10);
if (years >= AGE_THRESHOLD_YEARS) return true;
}
if (/([0-9]+)\s*ヶ月前/.test(dateText)) {
const months = parseInt(RegExp.$1, 10);
if (months >= AGE_THRESHOLD_YEARS * 12) return true;
}
}
return false;
}
function isSubscriptionsPage() {
return location.pathname.includes('/@') && location.pathname.includes('/videos');
}
function isLivePage() {
return location.pathname.includes('/streams');
}
function getSettings() {
return JSON.parse(localStorage.getItem(OPTION_STORAGE_KEY)) || { disableOnSubs: DISABLE_ON_SUBSCRIPTIONS };
}
function hideBadVideo(videoElement) {
if (!videoElement || isLivePage()) return;
const { disableOnSubs } = getSettings();
if (disableOnSubs && isSubscriptionsPage()) return;
if (isBadVideo(videoElement) || isOldVideo(videoElement)) {
videoElement.style.display = "none";
}
}
const observer = new IntersectionObserver(entries => {
entries.forEach(entry => {
if (entry.isIntersecting) {
hideBadVideo(entry.target);
observer.unobserve(entry.target);
}
});
}, { rootMargin: "300px" });
function update() {
if (isLivePage()) return;
document.querySelectorAll(VIDEO_SELECTORS).forEach(video => {
hideBadVideo(video);
observer.observe(video);
});
}
function initTampermonkeyMenu() {
if (menuRegistered) return;
menuRegistered = true;
const { disableOnSubs } = getSettings();
GM_registerMenuCommand(
`チャンネル内の動画は無視する: ${disableOnSubs ? "ON" : "OFF"}`,
() => {
localStorage.setItem(OPTION_STORAGE_KEY, JSON.stringify({ disableOnSubs: !disableOnSubs }));
window.location.reload();
}
);
GM_registerMenuCommand(
`ライブ視聴者数で非表示判定: ${LIVE_FILTER_ENABLED ? "ON" : "OFF"}`,
() => {
const newValue = LIVE_FILTER_ENABLED ? 0 : 1;
localStorage.setItem('YT_LiveFilter_Enabled', newValue);
alert('ライブ視聴者数フィルター設定を変更しました。ページを再読み込みします。');
window.location.reload();
}
);
}
(function(){
const liveFilterStorage = localStorage.getItem('YT_LiveFilter_Enabled');
if (liveFilterStorage !== null) {
window.LIVE_FILTER_ENABLED = parseInt(liveFilterStorage, 10);
} else {
window.LIVE_FILTER_ENABLED = LIVE_FILTER_ENABLED;
}
})();
window.addEventListener("load", () => {
initTampermonkeyMenu();
update();
["yt-navigate-finish", "yt-page-data-updated", "yt-action"].forEach(event => {
window.addEventListener(event, () => setTimeout(update, 500));
});
const mutationObserver = new MutationObserver(mutations => {
if (isLivePage()) return;
mutations.forEach(mutation => {
mutation.addedNodes.forEach(node => {
if (node.nodeType !== 1) return;
if (node.matches?.(VIDEO_SELECTORS)) {
hideBadVideo(node);
observer.observe(node);
} else if (node.querySelectorAll) {
node.querySelectorAll(VIDEO_SELECTORS).forEach(video => {
hideBadVideo(video);
observer.observe(video);
});
}
});
});
});
mutationObserver.observe(document.body, { childList: true, subtree: true });
});
QingJ © 2025
镜像随时可能失效,请加Q群300939539或关注我们的公众号极客氢云获取最新地址