您需要先安装一个扩展,例如 篡改猴、Greasemonkey 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 Userscripts ,之后才能安装此脚本。
您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey,才能安装此脚本。
您需要先安装用户脚本管理器扩展后才能安装此脚本。
This is to change the handle in the YouTube comments section to a username.
当前为
// ==UserScript== // @name Return YouTube Comment Username // @name:ja YouTubeコメント欄の名前を元に戻す // @version 0.1.5 // @author yakisova41 // @license MIT // @namespace https://yt-returnname-api.pages.dev/extension/ // @description This is to change the handle in the YouTube comments section to a username. // @description:ja YouTubeのコメント欄の名前がハンドル(@...)表記になってしまった場合に、元のユーザーネームに上書きします。 // @match https://www.youtube.com/* // @grant none // ==/UserScript== (() => { // src/lib/eventRoot.ts function pageChangeListener(eventElement) { let beforeHref = ""; const observer = new MutationObserver(() => { const href = location.href; if (href !== beforeHref) { eventElement.dispatchEvent( new CustomEvent("pageChange", { detail: { beforeHref, newHref: href } }) ); } beforeHref = href; }); observer.observe(document.querySelector("body"), { childList: true, subtree: true }); } function createEventRoot() { const eventElement = document.createElement("div"); pageChangeListener(eventElement); return { addEventListener: (eName, listener, options) => { eventElement.addEventListener(eName, listener, options); const pageChangeListener2 = () => { eventElement.removeEventListener( "pageChange", pageChangeListener2 ); eventElement.removeEventListener(eName, listener, options); }; eventElement.addEventListener("pageChange", pageChangeListener2); }, dispatchEvent: (e) => { eventElement.dispatchEvent(e); }, removeEventListener: (eName, listener, options) => { eventElement.removeEventListener(eName, listener, options); }, native: eventElement }; } // src/lib/findElement.ts var findElement = (selector) => { return new Promise((resolve, reject) => { if (isNativeInterval()) { const interval = setInterval(() => { const elem = document.querySelector(selector); if (elem !== null) { clearInterval(interval); resolve(elem); } }); } else { let search = function() { setTimeout(() => { const elem = document.querySelector(selector); if (elem !== null) { resolve(elem); } else { search(); } }); }; search(); } }); }; var findElementAll = (selector) => { return new Promise((resolve, reject) => { if (isNativeInterval()) { const interval = setInterval(() => { const elems = document.querySelectorAll(selector); if (elems.length !== 0) { clearInterval(interval); resolve(elems); } }); } else { let search = function() { setTimeout(() => { const elems = document.querySelectorAll(selector); if (elems.length !== 0) { resolve(elems); } else { search(); } }); }; search(); } }); }; function isNativeInterval() { return window.setInterval.toString() === "function setInterval() { [native code] }"; } // src/lib/getUserName.ts async function getUserName(href) { const id = href.split("/")[4]; const data = await fetch( `https://www.youtube.com/youtubei/v1/browse?key=AIzaSyAO_FJ2SlqU8Q4STEHLGCilw_Y9_11qcW8&prettyPrint=false`, { method: "POST", headers: { accept: "*/*", "accept-encoding": "gzip, deflate, br", "accept-language": "ja", "content-type": "application/json", cookie: `GPS=1; YSC=sHEZ9k4QSS0; DEVICE_INFO=DEVICE_INFO; VISITOR_INFO1_LIVE=LLIIVVEE; PREF=f6=40000000&tz=Asia.Tokyo; ST-o2eza2=itct=itct&endpoint=%7B%22clickTrackingParams%22%3A%22CBQQ8JMBGAciEwjNqtCN86H9AhXnm1YBHABY%3D%22%2C%22commandMetadata%22%3A%7B%22webCommandMetadata%22%3A%7B%22url%22%3A%22%2F%40FUCKYOUTUBE%2Fchannels%22%2C%22webPageType%22%3A%22WEB_PAGE_TYPE_CHANNEL%22%2C%22rootVe%22%3A3611%2C%22apiUrl%22%3A%22%2Fyoutubei%2Fv1%2Fbrowse%22%7D%7D%2C%22browseEndpoint%22%3A%7B%22browseId%22%3A%22${id}%22%2C%22params%22%3A%22EghjaGFubmVsc_IGBAoCUgA%253D%22%2C%22canonicalBaseUrl%22%3A%22%2F%40FUCK_YOUTUBE%22%7D%7D`, dnt: "1", referer: `https://www.youtube.com/channel/${id}`, "sec-ch-ua": `"Chromium";v="110", "Not A(Brand";v="24", "Google Chrome";v="110"`, "sec-ch-ua-arch": "x86", "sec-ch-ua-bitness": "64", "sec-ch-ua-full-version": "110.0.5481.104", "sec-ch-ua-full-version-list": `"Chromium";v="110.0.5481.104", "Not A(Brand";v="24.0.0.0", "Google Chrome";v="110.0.5481.104"`, "sec-ch-ua-mobile": "?0", "sec-ch-ua-platform": "Windows", "sec-ch-ua-platform-version": "15.0.0", "sec-ch-ua-wow64": "?0", "sec-fetch-dest": "empty", "sec-fetch-mode": "same-origin", "sec-fetch-site": "same-origin", "user-agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/110.0.0.0 Safari/537.36", "x-client-data": "x-client-data", "x-goog-authuser": "0", "x-goog-visitor-id": "visitorData", "x-origin": "https://www.youtube.com", "x-youtube-bootstrap-logged-in": "true", "x-youtube-client-name": "1", "x-youtube-client-version": "2.20230217.01.00" }, body: JSON.stringify({ context: { client: { hl: "ja", gl: "JP", remoteHost: "1919:8a10:1145:1419:e1c9:b81a:09db:ff3a", deviceMake: "", deviceModel: "", visitorData: "visitorData", userAgent: "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/110.0.0.0 Safari/537.36,gzip(gfe)", clientName: "WEB", clientVersion: "2.20230217.01.00", osName: "Windows", osVersion: "10.0", originalUrl: "https://www.youtube.com/@FUCK_YOUTUBE/channels", platform: "DESKTOP", clientFormFactor: "UNKNOWN_FORM_FACTOR", configInfo: { appInstallData: "appInstallData" }, userInterfaceTheme: "USER_INTERFACE_THEME_DARK", timeZone: "Asia/Tokyo", browserName: "Chrome", browserVersion: "110.0.0.0", acceptHeader: "text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.7", deviceExperimentId: "deviceExperimentId", screenWidthPoints: 599, screenHeightPoints: 937, screenPixelDensity: 1, screenDensityFloat: 1, utcOffsetMinutes: 540, memoryTotalKbytes: "8000000", mainAppWebInfo: { graftUrl: "/@FUCK_YOUTUBE/channels", pwaInstallabilityStatus: "PWA_INSTALLABILITY_STATUS_CAN_BE_INSTALLED", webDisplayMode: "WEB_DISPLAY_MODE_BROWSER", isWebNativeShareAvailable: true } }, user: { lockedSafetyMode: false }, request: { useSsl: true, internalExperimentFlags: [], consistencyTokenJars: [] }, clickTracking: { clickTrackingParams: "CCgQ8JMBGAgiEwiW5Pey8qH9AhVVSA8CHUHLAGc=" }, adSignalsInfo: { params: [ { key: "dt", value: "1676820301790" }, { key: "flash", value: "0" }, { key: "frm", value: "0" }, { key: "u_tz", value: "540" }, { key: "u_his", value: "1" }, { key: "u_h", value: "1080" }, { key: "u_w", value: "1920" }, { key: "u_ah", value: "1040" }, { key: "u_aw", value: "1920" }, { key: "u_cd", value: "24" }, { key: "bc", value: "31" }, { key: "bih", value: "937" }, { key: "biw", value: "582" }, { key: "brdim", value: "-1920,0,-1920,0,1920,0,1920,1040,599,937" }, { key: "vis", value: "1" }, { key: "wgl", value: "true" }, { key: "ca_type", value: "image" } ] } }, browseId: id, params: "EghjaGFubmVsc_IGBAoCUgA%3D" }) } ).then((res) => res.text()).then((text) => { const data2 = JSON.parse(text); const name = data2["header"]["c4TabbedHeaderRenderer"]["title"]; return name; }); return data; } // src/watch/replaceComments.ts function replaceComments(comments, page, eventRoot) { const nameStore = []; comments.forEach(async (c, index) => { const nthChild = page * 20 + (index + 1); const commentElem = await findElement( `#comments > #sections > #contents > ytd-comment-thread-renderer:nth-child(${nthChild})` ); eventRoot.addEventListener("pageChange", () => { commentElem.remove(); }); const channelHrefElem = commentElem.querySelector( "#comment > #body > #main > #header > #header-author > h3 > a " ); let nameElem; nameElem = commentElem.querySelector( "#comment > #body > #main > #header > #header-author > #author-comment-badge > ytd-author-comment-badge-renderer > #name > ytd-channel-name > #container > #text-container > #text " ); if (nameElem === null) { nameElem = channelHrefElem.querySelector("span"); } if (channelHrefElem.href in nameStore) { nameElem.innerHTML = nameStore[channelHrefElem.href]; } else { getUserName(channelHrefElem.href).then((name) => { nameElem.innerHTML = name; nameStore[channelHrefElem.href] = name; }); } }); } // src/listeners/commentRenderingListener.ts async function renderingListener(eventRoot) { let renderingTrigger = false; const contents = await findElement("#comments > #sections"); const observer = new MutationObserver(() => { if ("can-show-more" in contents.attributes) { renderingTrigger = true; } else if ("continuation-is-reloading" in contents.attributes) { renderingTrigger = true; eventRoot.dispatchEvent( new CustomEvent("commentsContinuationReloading") ); } else { if (renderingTrigger) { renderingTrigger = false; eventRoot.dispatchEvent( new CustomEvent("commentsRenderingSuccess") ); } } }); observer.observe(contents, { attributes: true }); return observer; } // src/watch/replaceReplies.ts async function replaceReplies(page, targetIndex) { const nthChild = page * 20 + (targetIndex + 1); const repliesElem = await findElementAll( `#comments > #sections > #contents > ytd-comment-thread-renderer:nth-child(${nthChild}) > #replies > ytd-comment-replies-renderer > #expander > #expander-contents > #contents > ytd-comment-renderer` ); repliesElem.forEach((elem) => { const channelHrefElem = elem.querySelector( "#body > #main > #header > #header-author > h3 > a " ); let nameElem; nameElem = elem.querySelector( "#body > #main > #header > #header-author > #author-comment-badge > ytd-author-comment-badge-renderer > #name > ytd-channel-name > #container > #text-container > #text " ); if (nameElem === null) { nameElem = channelHrefElem.querySelector("span"); } getUserName(channelHrefElem.href).then((name) => { nameElem.innerHTML = name; }); const textElems = elem.querySelectorAll( "#body > #main > #comment-content > #expander > #content > #content-text > a.yt-formatted-string" ); textElems.forEach((textElem) => { const text = textElem.innerHTML; if (text.match("@.*")) { getUserName(textElem.href).then((name) => { textElem.innerHTML = "@" + name; }); } }); }); } // src/watch/watch.ts async function watch(eventRoot) { const renderListener = await renderingListener(eventRoot); eventRoot.addEventListener("pageChange", () => { renderListener.disconnect(); }); const commentsTargetIdStore = []; let commentsPage = 0; eventRoot.addEventListener("commentsContinuationReloading", () => { commentsPage = 0; }); eventRoot.addEventListener( "commentFetch", ({ detail: { comments, mode } }) => { comments.forEach((comment, index) => { if (comment["commentThreadRenderer"]["replies"] !== void 0) { commentsTargetIdStore.push({ index, commentsPage, targetId: comment["commentThreadRenderer"]["replies"]["commentRepliesRenderer"]["targetId"] }); } }); if (mode === 1) { const handleRenderingSucess = () => { replaceComments(comments, commentsPage, eventRoot); commentsPage = commentsPage + 1; eventRoot.native.removeEventListener( "commentsRenderingSuccess", handleRenderingSucess ); }; eventRoot.native.addEventListener( "commentsRenderingSuccess", handleRenderingSucess ); } else { replaceComments(comments, commentsPage, eventRoot); commentsPage = commentsPage + 1; } } ); eventRoot.addEventListener( "repliesFetch", ({ detail: { replies, targetId } }) => { commentsTargetIdStore.forEach((targetData, index) => { if (targetData.targetId === targetId) { replaceReplies(targetData.commentsPage, targetData.index); } }); } ); } // src/lib/FetchIntercepter.ts function FetchIntercepter(originalFetch) { const actions = []; return { start: () => { window.fetch = (...arg) => { const [request, init] = arg; const response = originalFetch(request, init); response.then((res) => { actions.forEach((action) => { action({ request, init, response: res }); }); }); return response; }; }, addAction: (action) => { actions.push(action); }, stop: () => { window.fetch = originalFetch; } }; } // src/listeners/commentFetchListener.ts function commentFetchListener(eventRoot) { const intercepter = FetchIntercepter(window.fetch); intercepter.start(); intercepter.addAction(async (data) => { if (typeof data.request["url"] === "string" && data.request["url"].match( "https://www.youtube.com/youtubei/v1/next.*" )) { const responseClone = data.response.clone(); const text = await responseClone.text(); const body = JSON.parse(text); const commentFetchMode = is_comments(body); if (commentFetchMode === 1) { const comments = body["onResponseReceivedEndpoints"][1]["reloadContinuationItemsCommand"]["continuationItems"]; const data2 = removeContinuationItem(comments); eventRoot.dispatchEvent( new CustomEvent("commentFetch", { detail: { comments: data2, mode: commentFetchMode } }) ); } if (commentFetchMode === 2) { const comments = body["onResponseReceivedEndpoints"][0]["appendContinuationItemsAction"]["continuationItems"]; const data2 = removeContinuationItem(comments); eventRoot.dispatchEvent( new CustomEvent("commentFetch", { detail: { comments: data2, mode: commentFetchMode } }) ); } if (commentFetchMode === 0) { if (body["onResponseReceivedEndpoints"][0]["appendContinuationItemsAction"]["targetId"].match("comment-replies.*")) { const replies = body["onResponseReceivedEndpoints"][0]["appendContinuationItemsAction"]["continuationItems"]; const targetId = body["onResponseReceivedEndpoints"][0]["appendContinuationItemsAction"]["targetId"]; eventRoot.dispatchEvent( new CustomEvent("repliesFetch", { detail: { replies, targetId } }) ); } } } }); return { stop: intercepter.stop }; } function is_comments(body) { const onResponseReceivedEndpoints = body["onResponseReceivedEndpoints"]; if (onResponseReceivedEndpoints.length > 1 && "reloadContinuationItemsCommand" in onResponseReceivedEndpoints[1] && onResponseReceivedEndpoints[1]["reloadContinuationItemsCommand"]["targetId"] === "comments-section") { return 1; } if ("appendContinuationItemsAction" in onResponseReceivedEndpoints[0] && onResponseReceivedEndpoints[0]["appendContinuationItemsAction"]["targetId"] === "comments-section") { return 2; } return 0; } function removeContinuationItem(comments) { comments.forEach((comment, index) => { if ("continuationItemRenderer" in comment) { comments.splice(index, 1); } }); return comments; } // src/index.ts function main() { const eventRoot = createEventRoot(); commentFetchListener(eventRoot); eventRoot.native.addEventListener( "pageChange", async (e) => { const { newHref } = e.detail; const pageName = newHref.split("/")[3].split("?")[0]; if (pageName === "watch") { watch(eventRoot); } } ); } main(); })();
QingJ © 2025
镜像随时可能失效,请加Q群300939539或关注我们的公众号极客氢云获取最新地址