您需要先安装一个扩展,例如 篡改猴、Greasemonkey 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 Userscripts ,之后才能安装此脚本。
您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey,才能安装此脚本。
您需要先安装用户脚本管理器扩展后才能安装此脚本。
Automatically expands all comment threads and adds a button to copy all comments to the clipboard.
// ==UserScript== // @name TikTok - Expand & Copy Comments (v4.0) // @namespace http://tampermonkey.net/ // @version 4.0 // @description Automatically expands all comment threads and adds a button to copy all comments to the clipboard. // @author torch // @match https://www.tiktok.com/@*/video/* // @icon https://www.google.com/s2/favicons?sz=64&domain=tiktok.com // @grant none // @license MIT // ==/UserScript== (function() { 'use-strict'; // --- НАСТРОЙКИ --- const checkInterval = 1500; // Проверять на наличие новых кнопок каждые 1.5 сек // --- СЕЛЕКТОРЫ И КЛЮЧЕВЫЕ СЛОВА --- const expandButtonContainerSelector = '.e2j3pk12'; // Контейнер кнопок "Просмотреть/Скрыть" const viewKeywords = { ru: ['Просмотреть'], en: ['View'] }; const commentContainerSelector = '.ejcng160'; // Главный контейнер всех комментариев const topLevelCommentSelector = '.e1970p9w9'; // Обертка для комментария и его ответов const commentItemSelector = '.e1970p9w0'; // Конкретный элемент комментария const replyContainerSelector = '.e2j3pk10'; // Контейнер с ответами // --- СОСТОЯНИЕ СКРИПТА --- let buttonAdded = false; // --- ФУНКЦИОНАЛ --- /** * Создает и добавляет на страницу кнопку "Скопировать все комментарии" */ function addCopyButton() { const targetContainer = document.querySelector(commentContainerSelector); if (!targetContainer) return; // Создаем кнопку const copyButton = document.createElement('button'); copyButton.innerText = 'Скопировать все комментарии'; copyButton.id = 'copy-all-comments-button'; // Добавляем стили для кнопки const styles = ` #copy-all-comments-button { background-color: #FE2C55; color: white; border: none; padding: 8px 16px; margin-bottom: 15px; border-radius: 4px; cursor: pointer; font-weight: bold; font-size: 14px; transition: background-color 0.2s; } #copy-all-comments-button:hover { background-color: #e41e45; } #copy-all-comments-button:active { background-color: #c81035; } `; const styleSheet = document.createElement('style'); styleSheet.type = 'text/css'; styleSheet.innerText = styles; document.head.appendChild(styleSheet); // Добавляем обработчик клика copyButton.addEventListener('click', () => { copyAllComments(copyButton); }); // Вставляем кнопку в начало контейнера комментариев targetContainer.prepend(copyButton); buttonAdded = true; console.log('[TikTok Expander] Кнопка "Скопировать" добавлена.'); } /** * Собирает и копирует все комментарии * @param {HTMLElement} button - Элемент кнопки для обратной связи */ async function copyAllComments(button) { const topLevelComments = document.querySelectorAll(topLevelCommentSelector); let allCommentsText = []; topLevelComments.forEach(commentThread => { // Парсим основной комментарий const mainComment = commentThread.querySelector(commentItemSelector); if (mainComment) { allCommentsText.push(parseComment(mainComment)); } // Парсим все ответы на него const replies = commentThread.querySelectorAll(`${replyContainerSelector} ${commentItemSelector}`); replies.forEach(reply => { allCommentsText.push(parseComment(reply, true)); // true = это ответ }); allCommentsText.push('---'); // Разделитель между ветками }); const formattedString = allCommentsText.join('\n\n'); try { await navigator.clipboard.writeText(formattedString); console.log(`[TikTok Expander] Скопировано ${topLevelComments.length} веток комментариев.`); // Обратная связь для пользователя const originalText = button.innerText; button.innerText = 'Скопировано!'; button.disabled = true; setTimeout(() => { button.innerText = originalText; button.disabled = false; }, 3000); } catch (err) { console.error('[TikTok Expander] Не удалось скопировать комментарии: ', err); alert('Ошибка при копировании комментариев. Проверьте консоль (F12) для деталей.'); } } /** * Извлекает информацию из одного элемента комментария * @param {HTMLElement} element - DOM-элемент комментария (.e1970p9w0) * @param {boolean} isReply - Является ли комментарий ответом * @returns {string} - Отформатированная строка комментария */ function parseComment(element, isReply = false) { const usernameEl = element.querySelector('[data-e2e^="comment-username-"]'); const textEl = element.querySelector('[data-e2e^="comment-level-"]'); const username = usernameEl ? usernameEl.textContent.trim() : 'Unknown User'; const text = textEl ? textEl.textContent.trim() : ''; const prefix = isReply ? ' - ' : ''; return `${prefix}${username}:\n${prefix}${text}`; } /** * Основной цикл, который ищет кнопки для раскрытия комментариев */ function mainLoop() { // Раскрытие комментариев const allButtonContainers = document.querySelectorAll(expandButtonContainerSelector); let buttonsExpanded = 0; allButtonContainers.forEach(button => { const text = button.textContent; const isViewButton = viewKeywords.ru.some(k => text.includes(k)) || viewKeywords.en.some(k => text.includes(k)); if (isViewButton && document.body.contains(button) && button.offsetParent !== null) { button.click(); buttonsExpanded++; } }); if (buttonsExpanded > 0) { console.log(`[TikTok Expander] Раскрыто ${buttonsExpanded} веток комментариев.`); } // Добавление кнопки копирования (только один раз) if (!buttonAdded && document.querySelector(commentContainerSelector)) { addCopyButton(); } } console.log("TikTok - Expand & Copy Comments script (v4.0) is running..."); setInterval(mainLoop, checkInterval); })();