您需要先安装一个扩展,例如 篡改猴、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)
- }
- })()
- })();