您需要先安装一个扩展,例如 篡改猴、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.2
- // @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, limit = 1e3) => {
- return new Promise((resolve, reject) => {
- let i = 0;
- const interval = setInterval(() => {
- const elem = document.querySelector(selector);
- if (elem !== null) {
- clearInterval(interval);
- resolve(elem);
- }
- if (limit < i) {
- clearInterval(interval);
- reject(null);
- }
- i = i + 1;
- });
- });
- };
- var findElementAll = (selector, limit = 1e3) => {
- return new Promise((resolve, reject) => {
- let i = 0;
- const interval = setInterval(() => {
- const elems = document.querySelectorAll(selector);
- if (elems.length !== 0) {
- clearInterval(interval);
- resolve(elems);
- }
- if (limit < i) {
- clearInterval(interval);
- reject([]);
- }
- i = i + 1;
- });
- });
- };
- // src/watch/getUserName.ts
- async function getUserName(href) {
- const id = href.split("/")[4];
- const data = await fetch(
- `https://yt-returnname-api.pages.dev/api/idToName?id=${id}`,
- {
- method: "POST"
- }
- ).then((res) => res.text());
- return data;
- }
- // src/watch/replaceComments.ts
- function replaceComments(comments, page) {
- const nameStore = [];
- comments.forEach(async (c, index) => {
- let nthChild;
- if (page === 0) {
- nthChild = index + 1;
- } else {
- nthChild = page * 20 + (index + 1);
- }
- const commentElem = await findElement(
- `#comments > #sections > #contents > ytd-comment-thread-renderer:nth-child(${nthChild})`
- );
- 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) {
- let nthChild;
- if (page === 0) {
- nthChild = targetIndex + 1;
- } else {
- 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);
- commentsPage = commentsPage + 1;
- eventRoot.native.removeEventListener(
- "commentsRenderingSuccess",
- handleRenderingSucess
- );
- };
- eventRoot.native.addEventListener(
- "commentsRenderingSuccess",
- handleRenderingSucess
- );
- } else {
- replaceComments(comments, commentsPage);
- 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();
- })();