您需要先安装一个扩展,例如 篡改猴、Greasemonkey 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 Userscripts ,之后才能安装此脚本。
您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey,才能安装此脚本。
您需要先安装用户脚本管理器扩展后才能安装此脚本。
Adds buttons to copy Coursera transcripts and easily summarize videos with the most popular AI platforms.
当前为
// ==UserScript== // @name Coursera Transcript to AI: Video Summarizer 🎬📝 // @namespace thecolourofmadness // @version 1.0 // @description Adds buttons to copy Coursera transcripts and easily summarize videos with the most popular AI platforms. // @author nucleargengar // @match https://www.coursera.org/* // @match https://chatgpt.com/* // @match https://gemini.google.com/* // @match https://chat.deepseek.com/* // @grant GM_xmlhttpRequest // @grant GM_setClipboard // @grant GM_addStyle // @grant GM_setValue // @grant GM_getValue // @grant GM_registerMenuCommand // @icon https://www.coursera.org/favicon.ico // @license All Rights Reserved // ==/UserScript== (function() { 'use strict'; // Global variable for auto-send feature const autoSendKey = "autoSendEnabled"; let autoSendEnabled = GM_getValue(autoSendKey, false); // Function to get the full language name using Intl.DisplayNames API function getFullLanguageName() { // Retrieve the raw language code from the browser const rawLanguage = navigator.language || navigator.userLanguage; // Extract the primary language code (e.g., "de" from "de-DE") const languageCode = rawLanguage.split('-')[0]; let fullLanguage; try { // Use Intl.DisplayNames to get the full language name in English const displayNames = new Intl.DisplayNames(['en'], { type: 'language' }); fullLanguage = displayNames.of(languageCode); } catch (error) { // Fallback in case Intl.DisplayNames is not supported fullLanguage = languageCode; } return fullLanguage; } // Global queue for actions when ctrl key is used let ctrlActionQueue = []; // Wrapper to handle ctrl key click events function handleCtrlClick(event, action) { if (event.ctrlKey) { ctrlActionQueue.push(action); console.log("Queued action for AI platform"); } else { action(); } } // Execute queued actions when ctrl key is released window.addEventListener('keyup', function(e) { if (e.key === "Control") { if (ctrlActionQueue.length > 0) { ctrlActionQueue.forEach(fn => fn()); ctrlActionQueue = []; } } }); // On Coursera pages (lecture pages): Setup UI and submission operations if (window.location.hostname.includes("coursera.org")) { GM_addStyle(` /* Common UI styles */ #copyTranscriptButton, #chatGPTButton, #geminiButton { position: fixed; background-color: #f5f5f5; border: none; color: #0056d2; width: 40px; height: 40px; font-size: 18px; cursor: pointer; z-index: 9999; border-radius: 50%; transition: background-color 0.3s; display: flex; align-items: center; justify-content: center; } #copyTranscriptButton:hover, #chatGPTButton:hover, #geminiButton:hover { background-color: #eee; } /* Button positioning: Vertical arrangement */ #copyTranscriptButton { left: 20px; bottom: 20px; } #chatGPTButton { left: 20px; bottom: 70px; } #geminiButton { left: 20px; bottom: 120px; } /* Message box */ #messageBox { position: fixed; top: 20px; left: 50%; transform: translateX(-50%); background-color: rgba(0, 0, 0, 0.8); color: white; padding: 10px 20px; border-radius: 5px; z-index: 10000; display: none; } `); // DeepSeek button styles GM_addStyle(` #deepseekButton { position: fixed; background-color: #f5f5f5; border: none; color: #0056d2; width: 40px; height: 40px; font-size: 18px; cursor: pointer; z-index: 9999; border-radius: 50%; transition: background-color 0.3s; display: flex; align-items: center; justify-content: center; left: 20px; bottom: 170px; } #deepseekButton:hover { background-color: #eee; } `); function displayMessage(message) { const messageBox = document.getElementById('messageBox'); if (!messageBox) return; messageBox.textContent = message; messageBox.style.display = 'block'; setTimeout(() => messageBox.style.display = 'none', 3000); } // Fetch the transcript and copy it to the clipboard function fetchAndCopyTranscript(url) { GM_xmlhttpRequest({ method: "GET", url: url, onload: response => { if (response.status === 200) { GM_setClipboard(response.responseText, "text"); console.log("Transcript copied to clipboard!"); displayMessage("Transcript copied to clipboard!"); } else { console.error("Error fetching transcript:", response.status, response.statusText); displayMessage("Error copying transcript: " + response.statusText); } }, onerror: error => { console.error("Request error:", error); displayMessage("Error copying transcript: " + error); } }); } // Fetch and send transcript for ChatGPT function fetchAndSendTranscriptForChatGPT(url) { GM_xmlhttpRequest({ method: "GET", url: url, onload: response => { if (response.status === 200) { const fullLanguageName = getFullLanguageName(); const prefixText = "Here, a transcript of a lecture given by an educator to their students is provided. Summarize this content comprehensively and explain it in detail. Divide it into sections and keep its readability high. If necessary, support it with tables. Present it in " + fullLanguageName + " language.\n\n"; const combinedText = prefixText + response.responseText; GM_setValue("chatgptTranscript", combinedText); console.log("Transcript prepared for ChatGPT!"); displayMessage("Transcript prepared for ChatGPT!"); window.open("https://chatgpt.com", "_blank"); } else { console.error("Error fetching transcript:", response.status, response.statusText); displayMessage("Error sending transcript: " + response.statusText); } }, onerror: error => { console.error("Request error:", error); displayMessage("Error sending transcript: " + error); } }); } // Fetch and send transcript for Gemini function fetchAndSendTranscriptForGemini(url) { GM_xmlhttpRequest({ method: "GET", url: url, onload: response => { if (response.status === 200) { const fullLanguageName = getFullLanguageName(); const prefixText = "Here, a transcript of a lecture given by an educator to their students is provided. Summarize this content comprehensively and explain it in detail. Divide it into sections and keep its readability high. If necessary, support it with tables. Present it in " + fullLanguageName + " language.\n\n"; const combinedText = prefixText + response.responseText; GM_setValue("geminiTranscript", combinedText); console.log("Transcript prepared for Gemini!"); displayMessage("Transcript prepared for Gemini!"); window.open("https://gemini.google.com", "_blank"); } else { console.error("Error fetching transcript:", response.status, response.statusText); displayMessage("Error sending transcript: " + response.statusText); } }, onerror: error => { console.error("Request error:", error); displayMessage("Error sending transcript: " + error); } }); } // Fetch and send transcript for DeepSeek function fetchAndSendTranscriptForDeepSeek(url) { GM_xmlhttpRequest({ method: "GET", url: url, onload: response => { if (response.status === 200) { const fullLanguageName = getFullLanguageName(); const prefixText = "Here, a transcript of a lecture given by an educator to their students is provided. Summarize this content comprehensively and explain it in detail. Divide it into sections and keep its readability high. If necessary, support it with tables. Present it in " + fullLanguageName + " language.\n\n"; const combinedText = prefixText + response.responseText; GM_setValue("deepseekTranscript", combinedText); console.log("Transcript prepared for DeepSeek!"); displayMessage("Transcript prepared for DeepSeek!"); window.open("https://chat.deepseek.com", "_blank"); } else { console.error("Error fetching transcript:", response.status, response.statusText); displayMessage("Error sending transcript: " + response.statusText); } }, onerror: error => { console.error("Request error:", error); displayMessage("Error sending transcript: " + error); } }); } // Get the transcript URL using XPath function getTranscriptUrl() { const xpath = "//li[@class='css-ap6dbz']/a[contains(@href, '/api/subtitleAssetProxy.v1/') and contains(@download, 'transcript.txt')]"; return document.evaluate(xpath, document, null, XPathResult.FIRST_ORDERED_NODE_TYPE, null).singleNodeValue; } function copyTranscript() { let transcriptLink = getTranscriptUrl(); if (transcriptLink) { fetchAndCopyTranscript(transcriptLink.href); } else { displayMessage("Transcript link not found. Clicking Downloads tab."); clickDownloadsTab(); // Click Downloads tab if transcript link is missing const pollInterval = setInterval(() => { transcriptLink = getTranscriptUrl(); if (transcriptLink) { clearInterval(pollInterval); fetchAndCopyTranscript(transcriptLink.href); } }, 500); } } function sendTranscriptToChatGPT() { let transcriptLink = getTranscriptUrl(); if (transcriptLink) { fetchAndSendTranscriptForChatGPT(transcriptLink.href); } else { displayMessage("Transcript link not found. Clicking Downloads tab."); clickDownloadsTab(); const pollInterval = setInterval(() => { transcriptLink = getTranscriptUrl(); if (transcriptLink) { clearInterval(pollInterval); fetchAndSendTranscriptForChatGPT(transcriptLink.href); } }, 500); } } function sendTranscriptToGemini() { let transcriptLink = getTranscriptUrl(); if (transcriptLink) { fetchAndSendTranscriptForGemini(transcriptLink.href); } else { displayMessage("Transcript link not found. Clicking Downloads tab."); clickDownloadsTab(); const pollInterval = setInterval(() => { transcriptLink = getTranscriptUrl(); if (transcriptLink) { clearInterval(pollInterval); fetchAndSendTranscriptForGemini(transcriptLink.href); } }, 500); } } function sendTranscriptToDeepSeek() { let transcriptLink = getTranscriptUrl(); if (transcriptLink) { fetchAndSendTranscriptForDeepSeek(transcriptLink.href); } else { displayMessage("Transcript link not found. Clicking Downloads tab."); clickDownloadsTab(); const pollInterval = setInterval(() => { transcriptLink = getTranscriptUrl(); if (transcriptLink) { clearInterval(pollInterval); fetchAndSendTranscriptForDeepSeek(transcriptLink.href); } }, 500); } } function addUI() { if (!document.getElementById('copyTranscriptButton')) { const btnCopy = document.createElement('button'); btnCopy.id = 'copyTranscriptButton'; btnCopy.innerHTML = '📋'; btnCopy.title = 'Copy Transcript to Clipboard'; btnCopy.addEventListener('click', copyTranscript); document.body.appendChild(btnCopy); } if (!document.getElementById('chatGPTButton')) { const btnChatGPT = document.createElement('button'); btnChatGPT.id = 'chatGPTButton'; btnChatGPT.innerHTML = '<img src="https://chatgpt.com/favicon.ico" alt="ChatGPT" style="width:24px;height:24px;">'; btnChatGPT.title = 'Send Transcript to ChatGPT'; btnChatGPT.addEventListener('click', function(e) { handleCtrlClick(e, sendTranscriptToChatGPT); }); document.body.appendChild(btnChatGPT); } if (!document.getElementById('geminiButton')) { const btnGemini = document.createElement('button'); btnGemini.id = 'geminiButton'; btnGemini.innerHTML = '<img src="https://www.gstatic.com/lamda/images/gemini_favicon_f069958c85030456e93de685481c559f160ea06b.png" alt="Gemini" style="width:24px;height:24px;">'; btnGemini.title = 'Send Transcript to Gemini'; btnGemini.addEventListener('click', function(e) { handleCtrlClick(e, sendTranscriptToGemini); }); document.body.appendChild(btnGemini); } if (!document.getElementById('deepseekButton')) { const btnDeepSeek = document.createElement('button'); btnDeepSeek.id = 'deepseekButton'; btnDeepSeek.innerHTML = '<img src="https://i.imgur.com/KQW7Nbc.png" alt="DeepSeek" style="width:24px;height:24px;">'; btnDeepSeek.title = 'Send Transcript to DeepSeek'; btnDeepSeek.addEventListener('click', function(e) { handleCtrlClick(e, sendTranscriptToDeepSeek); }); document.body.appendChild(btnDeepSeek); } if (!document.getElementById('messageBox')) { const messageBox = document.createElement('div'); messageBox.id = 'messageBox'; document.body.appendChild(messageBox); } } function removeUI() { document.getElementById('copyTranscriptButton')?.remove(); document.getElementById('chatGPTButton')?.remove(); document.getElementById('geminiButton')?.remove(); document.getElementById('deepseekButton')?.remove(); document.getElementById('messageBox')?.remove(); } function updateUI() { const isLecturePage = /^https:\/\/www\.coursera\.org\/learn\/[^\/]+\/lecture\/.+/.test(window.location.href); isLecturePage ? addUI() : removeUI(); // Automatically click Downloads tab on dynamic URL change if (isLecturePage) { clickDownloadsTab(); } } // Override history methods to detect URL changes const originalPushState = history.pushState; history.pushState = function(...args) { const result = originalPushState.apply(this, args); window.dispatchEvent(new Event('locationchange')); return result; }; const originalReplaceState = history.replaceState; history.replaceState = function(...args) { const result = originalReplaceState.apply(this, args); window.dispatchEvent(new Event('locationchange')); return result; }; window.addEventListener('popstate', () => window.dispatchEvent(new Event('locationchange'))); window.addEventListener('locationchange', updateUI); if (document.readyState === 'loading') { document.addEventListener('DOMContentLoaded', updateUI); } else { updateUI(); } // Automatically click the Downloads tab on page load using the provided code function clickDownloadsTab() { let tab = document.querySelector("button[data-track-component='focused_lex_lecture_tabs_download']"); if (tab) { tab.click(); console.log("Downloads tab clicked."); } else { console.log("Downloads tab not found, retrying."); setTimeout(clickDownloadsTab, 1000); // Retry after 1 second if tab is not loaded } } window.addEventListener('load', clickDownloadsTab); } // ChatGPT page: Auto-paste transcript. else if (window.location.hostname.includes("chatgpt.com")) { function autoPasteTranscriptForChatGPT() { const transcript = GM_getValue("chatgptTranscript", ""); if (!transcript) return; console.log("Transcript found for ChatGPT, starting auto-paste."); const intervalId = setInterval(() => { const promptArea = document.getElementById("prompt-textarea"); if (promptArea) { promptArea.textContent = transcript; promptArea.dispatchEvent(new Event("input", { bubbles: true })); promptArea.focus(); clearInterval(intervalId); console.log("Transcript pasted in ChatGPT."); GM_setValue("chatgptTranscript", ""); if (autoSendEnabled) { // Poll for send button until it becomes available, then click it const sendInterval = setInterval(() => { const sendButton = document.querySelector('button[data-testid="send-button"]'); if (sendButton) { sendButton.click(); console.log("Auto-send triggered for ChatGPT."); clearInterval(sendInterval); } }, 500); } } }, 500); } window.addEventListener("load", () => { setTimeout(autoPasteTranscriptForChatGPT, 1000); }); } // Gemini page: Auto-paste transcript. else if (window.location.hostname.includes("gemini.google.com")) { function autoPasteTranscriptForGemini() { const transcript = GM_getValue("geminiTranscript", ""); if (!transcript) return; console.log("Transcript found for Gemini, starting auto-paste."); const intervalId = setInterval(() => { const promptArea = document.querySelector("div.ql-editor.ql-blank.textarea.new-input-ui"); if (promptArea) { promptArea.textContent = transcript; promptArea.dispatchEvent(new Event("input", { bubbles: true })); promptArea.focus(); clearInterval(intervalId); console.log("Transcript pasted in Gemini."); GM_setValue("geminiTranscript", ""); if (autoSendEnabled) { // Poll for send button until it becomes available, then click it const sendInterval = setInterval(() => { const sendButton = document.querySelector('button[aria-label="Send message"]'); if (sendButton) { sendButton.click(); console.log("Auto-send triggered for Gemini."); clearInterval(sendInterval); } }, 500); } } }, 500); } window.addEventListener("load", () => { setTimeout(autoPasteTranscriptForGemini, 1000); }); } // DeepSeek page: Auto-paste transcript. else if (window.location.hostname.includes("chat.deepseek.com")) { function autoPasteTranscriptForDeepSeek() { const transcript = GM_getValue("deepseekTranscript", ""); if (!transcript) return; console.log("Transcript found for DeepSeek, starting auto-paste."); const intervalId = setInterval(() => { const promptArea = document.getElementById("chat-input"); if (promptArea) { promptArea.textContent = transcript; promptArea.dispatchEvent(new Event("input", { bubbles: true })); promptArea.focus(); clearInterval(intervalId); console.log("Transcript pasted in DeepSeek."); GM_setValue("deepseekTranscript", ""); if (autoSendEnabled) { // Poll for send button until it becomes available, then click it const sendInterval = setInterval(() => { const sendButton = document.querySelector('div[role="button"].f6d670'); if (sendButton) { sendButton.click(); console.log("Auto-send triggered for DeepSeek."); clearInterval(sendInterval); } }, 500); } } }, 500); } window.addEventListener("load", () => { setTimeout(autoPasteTranscriptForDeepSeek, 1000); }); } // Menu command for toggling auto-send feature function toggleAutoSend() { autoSendEnabled = !autoSendEnabled; GM_setValue(autoSendKey, autoSendEnabled); location.reload(); } const menuLabel = autoSendEnabled ? "✅ Deactivate Auto-Send" : "❌ Activate Auto-Send"; GM_registerMenuCommand(menuLabel, toggleAutoSend); })();
QingJ © 2025
镜像随时可能失效,请加Q群300939539或关注我们的公众号极客氢云获取最新地址