您需要先安装一个扩展,例如 篡改猴、Greasemonkey 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 Userscripts ,之后才能安装此脚本。
您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey,才能安装此脚本。
您需要先安装用户脚本管理器扩展后才能安装此脚本。
Automatically scan the last conversation message for MP3 links, transcribe them, and avoid duplicates using local storage. Limits to 3 entries.
- // ==UserScript==
- // @name MP3 to Transcript with Auto-Detection and Persistent Storage
- // @namespace http://tampermonkey.net/
- // @version 1.8
- // @description Automatically scan the last conversation message for MP3 links, transcribe them, and avoid duplicates using local storage. Limits to 3 entries.
- // @author Vishanka
- // @match https://discord.com/channels/*
- // @grant GM_addStyle
- // @grant GM_xmlhttpRequest
- // @grant unsafeWindow
- // @run-at document-idle
- // ==/UserScript==
- (function () {
- 'use strict';
- // Function to get API key from local storage or prompt user to input it
- function getApiKey() {
- let apiKey = localStorage.getItem('google_cloud_api_key');
- if (!apiKey) {
- apiKey = prompt("Please enter your Google Cloud API key for speech recognition:");
- if (apiKey) {
- localStorage.setItem('google_cloud_api_key', apiKey);
- } else {
- alert("API key is required to proceed.");
- return null;
- }
- }
- return apiKey;
- }
- // Fetch the API key
- let API_KEY = getApiKey();
- if (!API_KEY) {
- return; // Exit if no API key provided
- }
- const API_URL = `https://speech.googleapis.com/v1/speech:recognize?key=${API_KEY}`;
- // Create a button to toggle the transcription panel
- const toggleButton = document.createElement('div');
- toggleButton.innerHTML = `
- <button id="toggle-transcription-panel" style="position: relative; top: 10px; right: 0px; left: 10px; padding: 10px; background: #007bff; color: white; border: none; border-radius: 3px; cursor: pointer; z-index: 1001;">Show MP3 Transcription Tool</button>
- `;
- // Append the button to DCstoragePanel if available, otherwise to the body
- DCstoragePanel.appendChild(toggleButton);
- // Add a simple panel to the webpage
- const panelHTML = `
- <div id="transcription-panel" style="display: none;">
- <h3>MP3 Transcription Tool</h3>
- <input type="text" id="mp3-url" placeholder="Enter MP3 URL here" />
- <button id="transcribe-button">Transcribe</button>
- <textarea id="transcription-result" placeholder="Transcript will appear here..." readonly></textarea>
- </div>
- `;
- document.body.insertAdjacentHTML('beforeend', panelHTML);
- // Add styles for the panel
- GM_addStyle(`
- #transcription-panel {
- position: fixed;
- bottom: 50px;
- right: 10px;
- width: 300px;
- background: #f8f9fa;
- border: 1px solid #ccc;
- padding: 10px;
- box-shadow: 0 2px 10px rgba(0, 0, 0, 0.1);
- z-index: 9999;
- font-family: Arial, sans-serif;
- }
- #transcription-panel h3 {
- margin: 0 0 10px;
- font-size: 16px;
- }
- #transcription-panel input, #transcription-panel textarea {
- width: 100%;
- margin-bottom: 10px;
- padding: 5px;
- box-sizing: border-box;
- }
- #transcription-panel button {
- width: 100%;
- padding: 5px;
- cursor: pointer;
- background: #007bff;
- color: white;
- border: none;
- border-radius: 3px;
- }
- #transcription-done-message {
- position: fixed;
- bottom: 100px;
- left: 50%;
- transform: translateX(-50%);
- background: #28a745;
- color: white;
- padding: 10px;
- border-radius: 3px;
- box-shadow: 0 2px 10px rgba(0, 0, 0, 0.1);
- z-index: 10000;
- font-family: Arial, sans-serif;
- display: none;
- }
- `);
- // Add event listener to the toggle button
- document.getElementById('toggle-transcription-panel').addEventListener('click', () => {
- const panel = document.getElementById('transcription-panel');
- if (panel.style.display === 'none') {
- panel.style.display = 'block';
- document.getElementById('toggle-transcription-panel').innerText = 'Hide MP3 Transcription Tool';
- } else {
- panel.style.display = 'none';
- document.getElementById('toggle-transcription-panel').innerText = 'Show MP3 Transcription Tool';
- }
- });
- // Add event listener to the Transcribe button
- document.getElementById('transcribe-button').addEventListener('click', transcribe);
- // Function to transcribe the entered MP3 URL
- function transcribe() {
- const mp3Url = document.getElementById('mp3-url').value.trim();
- if (!mp3Url) {
- alert('Please enter a valid MP3 URL.');
- return;
- }
- // Check if the transcript already exists in local storage
- const storedTranscript = localStorage.getItem(mp3Url);
- if (storedTranscript) {
- document.getElementById('transcription-result').value = storedTranscript;
- return;
- }
- // Fetch MP3 file using GM_xmlhttpRequest and process it
- GM_xmlhttpRequest({
- method: 'GET',
- url: mp3Url,
- responseType: 'arraybuffer', // Required for audio data
- onload: (response) => {
- // Convert the audio file to Base64
- const audioBase64 = arrayBufferToBase64(response.response);
- // Send the Base64-encoded audio to Google Cloud Speech-to-Text API
- sendToGoogleCloud(audioBase64, mp3Url);
- },
- onerror: (err) => {
- alert('Failed to fetch the MP3 file.');
- console.error(err);
- },
- });
- }
- // Function to send the Base64 audio data to Google Cloud Speech-to-Text API
- function sendToGoogleCloud(audioBase64, mp3Url) {
- GM_xmlhttpRequest({
- method: 'POST',
- url: API_URL,
- headers: { 'Content-Type': 'application/json' },
- data: JSON.stringify({
- config: {
- encoding: 'MP3',
- sampleRateHertz: 16000,
- languageCode: 'en-US',
- },
- audio: {
- content: audioBase64,
- },
- }),
- onload: (response) => {
- const result = JSON.parse(response.responseText);
- if (result.error) {
- alert(`Error: ${result.error.message}`);
- } else {
- const transcript = result.results
- ?.map((r) => r.alternatives[0].transcript)
- .join('\n');
- document.getElementById('transcription-result').value =
- transcript || 'No transcript found.';
- // Store the transcript in local storage
- localStorage.setItem(mp3Url, transcript || 'No transcript found.');
- // Limit local storage to 3 entries
- manageLocalStorageLimit();
- // Show "Transcript done!" message
- showTranscriptionDoneMessage();
- }
- },
- onerror: (err) => {
- alert('Failed to process the transcription.');
- console.error(err);
- },
- });
- }
- // Function to convert ArrayBuffer to Base64
- function arrayBufferToBase64(buffer) {
- const binary = [];
- const bytes = new Uint8Array(buffer);
- const len = bytes.byteLength;
- for (let i = 0; i < len; i++) {
- binary.push(String.fromCharCode(bytes[i]));
- }
- return btoa(binary.join(''));
- }
- // Observe the conversation for changes and detect MP3 links
- const observer = new MutationObserver(() => {
- const messageItems = document.querySelectorAll('div[class*="messageContent_"]');
- const lastMessage = messageItems[messageItems.length - 1];
- if (lastMessage) {
- const mp3LinkMatch = lastMessage.innerText.match(/https:\/\/files\.shapes\.inc\/.*\.mp3/);
- if (mp3LinkMatch) {
- const mp3Link = mp3LinkMatch[0];
- const storedLink = localStorage.getItem('lastMp3Link');
- // Check if the link is new or different
- if (mp3Link !== storedLink) {
- localStorage.setItem('lastMp3Link', mp3Link); // Store the new link
- document.getElementById('mp3-url').value = mp3Link; // Populate the input
- transcribe(); // Automatically transcribe the new link
- }
- }
- }
- });
- // Start observing the document body for new messages
- observer.observe(document.body, { childList: true, subtree: true });
- // Function to manage local storage limit of 3 entries
- function manageLocalStorageLimit() {
- const keys = Object.keys(localStorage).filter((key) => key.startsWith('http'));
- if (keys.length > 10) {
- // Remove oldest entries until only 3 remain
- while (keys.length > 10) {
- localStorage.removeItem(keys.shift());
- }
- }
- }
- // Function to show "Transcript done!" message
- function showTranscriptionDoneMessage() {
- let messageDiv = document.getElementById('transcription-done-message');
- if (!messageDiv) {
- messageDiv = document.createElement('div');
- messageDiv.id = 'transcription-done-message';
- messageDiv.innerText = 'Transcript done!';
- document.body.appendChild(messageDiv);
- }
- messageDiv.style.display = 'block';
- setTimeout(() => {
- messageDiv.style.display = 'none';
- }, 3000);
- }
- })();