您需要先安装一个扩展,例如 篡改猴、Greasemonkey 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 Userscripts ,之后才能安装此脚本。
您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey,才能安装此脚本。
您需要先安装用户脚本管理器扩展后才能安装此脚本。
为微软的文本转语音服务的 demo 页面添加下载按钮
当前为
// ==UserScript== // @name Azure Speech Download // @namespace // @version 0.5 // @description 为微软的文本转语音服务的 demo 页面添加下载按钮 // @author Puteulanus // @homepage https://greasyfork.org/zh-CN/scripts/444347-azure-speech-download // @match https://azure.microsoft.com/*/services/cognitive-services/text-to-speech/* // @icon https://www.microsoft.com/favicon.ico // @require https://cdn.bootcdn.net/ajax/libs/FileSaver.js/2.0.5/FileSaver.min.js // @grant none // @run-at document-end // @namespace https://greasyfork.org/users/909438 // ==/UserScript== /* globals saveAs */ /* jshint esversion: 6 */ (function() { 'use strict'; // Your code here... if(!window.saveAs) { window.saveAs = (blob, name) => { const a = document.createElement("a"); document.body.appendChild(a); a.style = "display: none"; const url = window.URL.createObjectURL(blob); a.href = url; a.download = name; a.click(); window.URL.revokeObjectURL(url); } } const SpeechSDK = window.SpeechSDK let fileSize = 0 let streamSize = 0 let wavFragments = [] let enableDownload = false let enableCollect = false let autoProcessing = false let tasks = [] function createButton(id, color, content) { const button = document.getElementById('playli').cloneNode(true) button.id = id button.querySelector('span:last-of-type').textContent = content button.querySelector('button').style.backgroundColor = color button.querySelector('button').style.borderColor = color return button } function setButton(button, color, content) { button.querySelector('span:last-of-type').textContent = content button.querySelector('button').style.backgroundColor = color button.querySelector('button').style.borderColor = color } function downloadAndClean() { const sentAudio = new window.Uint8Array(fileSize) fileSize = 0 streamSize = 0 wavFragments.reduce((size, fragment) => { sentAudio.set(new window.Uint8Array(fragment), size) return size + fragment.byteLength }, 0) wavFragments.length = 0 saveAs(new Blob([sentAudio]), (new Date()).toISOString().replace('T', ' ').replace(':', '_').split('.')[0] + '.mp3') } function switchOptionDisplay() { if (enableCollect) { document.getElementById('autosplit').style.display = 'block' document.getElementById('optiondiv').style.display = 'block' } else { document.getElementById('autosplit').style.display = 'none' document.getElementById('optiondiv').style.display = 'none' } } const downloadStatus = document.createElement('div') const downloadSize = document.createElement('div') const buttonArea = document.getElementById('playli').parentElement // set download button const downloadButton = createButton('donwloadli', 'green', '下载') downloadButton.addEventListener('click', () => { downloadStatus.textContent = '下载中' enableDownload = true streamSize = 0 document.getElementById('playbtn').click() enableDownload = false }) downloadStatus.style.marginRight = '10px' buttonArea.appendChild(downloadButton) // set collect button const collectButton = createButton('collectli', 'red', '收集模式关') collectButton.addEventListener('click', () => { if(!enableCollect) { enableCollect = true switchOptionDisplay() setButton(collectButton, 'green', '收集模式开') } else { enableCollect = false switchOptionDisplay() setButton(collectButton, 'red', '收集模式关') if (!fileSize) return downloadAndClean() } }) collectButton.style.marginRight = '10px' buttonArea.appendChild(collectButton) // set options const optionArea = document.createElement('div') const maxSizeInput = document.createElement('input') const delimiterInput = document.createElement('input') const maxSizeLabel = document.createElement('span') const delimiterLabel = document.createElement('span') optionArea.id = 'optiondiv' optionArea.style.display = 'none' maxSizeLabel.textContent = '段落长度' maxSizeInput.style.width = '50px' maxSizeInput.style.margin = '10px' maxSizeInput.value = '300' delimiterLabel.textContent = '分隔符' delimiterInput.style.width = '100px' delimiterInput.style.margin = '10px' delimiterInput.value = ',。?,.?' optionArea.appendChild(maxSizeLabel) optionArea.appendChild(maxSizeInput) optionArea.appendChild(delimiterLabel) optionArea.appendChild(delimiterInput) buttonArea.parentElement.appendChild(optionArea) // set download status buttonArea.parentElement.appendChild(downloadStatus) buttonArea.parentElement.appendChild(downloadSize) // set auto split button const autoSplitButton = createButton('autosplit', 'red', '自动拆分') autoSplitButton.addEventListener('click', () => { setButton(autoSplitButton, 'green', '拆分中') autoProcessing = true const maxSize = +maxSizeInput.value const delimiters = delimiterInput.value.split('') const text = document.getElementById('ttstext').value const textHandler = text.split('').reduce( (obj, char, index, arr) => { obj.buffer.push(char) if (delimiters.indexOf(char) >= 0) obj.end = index if (obj.buffer.length === maxSize) { obj.res.push(obj.buffer.splice(0, obj.end + 1 - obj.offset).join('')) obj.offset += obj.res[obj.res.length - 1].length } return obj }, { buffer: [], end: 0, offset:0, res: [] }) textHandler.res.push(textHandler.buffer.join('')) document.getElementById('ttstext').value = textHandler.res.shift() tasks = textHandler.res const evt = document.createEvent('HTMLEvents') evt.initEvent('input', true, true) document.getElementById('ttstext').dispatchEvent(evt) downloadButton.click() }) autoSplitButton.style.display = 'none' buttonArea.appendChild(autoSplitButton) const streamHandler = { write: function (dataBuffer) { streamSize += dataBuffer.byteLength if (streamSize <= 1900800) { fileSize += dataBuffer.byteLength downloadSize.textContent = `已接收 ${fileSize / 1000} kb` wavFragments.push(dataBuffer) } if (streamSize === 1900800) { downloadStatus.textContent = '下载长度超过免费限额,请分割文本后使用收集模式' if (!enableCollect) { fileSize = 0 wavFragments.length = 0 } else { fileSize -= 1900800 wavFragments.length -= 1320 } } }, close: function () { downloadStatus.textContent = '下载完成' if (!enableCollect) { downloadAndClean() return } if (!autoProcessing) return if (tasks.length) { document.getElementById('ttstext').value = tasks.shift() const evt = document.createEvent('HTMLEvents') evt.initEvent('input', true, true) document.getElementById('ttstext').dispatchEvent(evt) downloadButton.click() } else { autoProcessing = false setButton(autoSplitButton, 'red', '自动拆分') collectButton.click() } } } const outputStream = SpeechSDK.PushAudioOutputStream.create(streamHandler) SpeechSDK.AudioConfig.fromSpeakerOutput = (() => { const fromSpeakerOutput = SpeechSDK.AudioConfig.fromSpeakerOutput return function (audioDestination) { return enableDownload ? audioDestination.onAudioEnd() || SpeechSDK.AudioConfig.fromStreamOutput(outputStream) : fromSpeakerOutput(audioDestination) } })() })();