Azure Speech Download

为微软的文本转语音服务的 demo 页面添加下载按钮

目前為 2022-09-05 提交的版本,檢視 最新版本

  1. // ==UserScript==
  2. // @name Azure Speech Download
  3. // @namespace
  4. // @version 0.4
  5. // @description 为微软的文本转语音服务的 demo 页面添加下载按钮
  6. // @author Puteulanus
  7. // @homepage https://greasyfork.org/zh-CN/scripts/444347-azure-speech-download
  8. // @match https://azure.microsoft.com/*/services/cognitive-services/text-to-speech/*
  9. // @icon https://www.microsoft.com/favicon.ico
  10. // @require https://cdn.bootcdn.net/ajax/libs/FileSaver.js/2.0.5/FileSaver.min.js
  11. // @grant none
  12. // @run-at document-end
  13. // @namespace https://greasyfork.org/users/909438
  14. // ==/UserScript==
  15.  
  16. /* globals saveAs */
  17. /* jshint esversion: 6 */
  18. (function() {
  19. 'use strict';
  20.  
  21. // Your code here...
  22. if(!window.saveAs) {
  23. window.saveAs = (blob, name) => {
  24. const a = document.createElement("a");
  25. document.body.appendChild(a);
  26. a.style = "display: none";
  27.  
  28. const url = window.URL.createObjectURL(blob);
  29. a.href = url;
  30. a.download = name;
  31. a.click();
  32. window.URL.revokeObjectURL(url);
  33. }
  34. }
  35.  
  36. const SpeechSDK = window.SpeechSDK
  37. let fileSize = 0
  38. let streamSize = 0
  39. let wavFragments = []
  40. let enableDownload = false
  41. let enableCollect = false
  42.  
  43. const downloadStatus = document.createElement('div')
  44. const downloadSize = document.createElement('div')
  45. const downloadButton = document.getElementById('playli').cloneNode(true)
  46. const collectButton = document.getElementById('playli').cloneNode(true)
  47. const buttonArea = document.getElementById('playli').parentElement
  48.  
  49. // set download button
  50. downloadButton.id = 'donwloadli'
  51. downloadButton.querySelector('span:last-of-type').textContent = '下载'
  52. downloadButton.querySelector('button').style.backgroundColor = 'green'
  53. downloadButton.querySelector('button').style.borderColor = 'green'
  54. downloadButton.addEventListener('click', () => {
  55. downloadStatus.textContent = '下载中'
  56. enableDownload = true
  57. streamSize = 0
  58. document.getElementById('playbtn').click()
  59. enableDownload = false
  60. })
  61. downloadStatus.style.marginRight = '10px'
  62. buttonArea.appendChild(downloadButton)
  63. buttonArea.parentElement.appendChild(downloadStatus)
  64. buttonArea.parentElement.appendChild(downloadSize)
  65. // set collect button
  66. collectButton.id = 'collectli'
  67. collectButton.querySelector('span:last-of-type').textContent = '收集模式关'
  68. collectButton.querySelector('button').style.backgroundColor = 'red'
  69. collectButton.querySelector('button').style.borderColor = 'red'
  70. collectButton.addEventListener('click', () => {
  71. if(!enableCollect) {
  72. enableCollect = true
  73. collectButton.querySelector('span:last-of-type').textContent = '收集模式开'
  74. collectButton.querySelector('button').style.backgroundColor = 'green'
  75. collectButton.querySelector('button').style.borderColor = 'green'
  76. } else {
  77. enableCollect = false
  78. collectButton.querySelector('span:last-of-type').textContent = '收集模式关'
  79. collectButton.querySelector('button').style.backgroundColor = 'red'
  80. collectButton.querySelector('button').style.borderColor = 'red'
  81. if (!fileSize) return
  82. const sentAudio = new window.Uint8Array(fileSize)
  83. fileSize = 0
  84. streamSize = 0
  85. wavFragments.reduce((size, fragment) => {
  86. sentAudio.set(new window.Uint8Array(fragment), size)
  87. return size + fragment.byteLength
  88. }, 0)
  89. wavFragments.length = 0
  90. saveAs(new Blob([sentAudio]), (new Date()).toISOString().replace('T', ' ').replace(':', '_').split('.')[0] + '.mp3')
  91. }
  92. })
  93. collectButton.style.marginRight = '10px'
  94. buttonArea.appendChild(collectButton)
  95.  
  96. const streamHandler = {
  97. write: function (dataBuffer) {
  98. streamSize += dataBuffer.byteLength
  99. if (streamSize <= 1900800) {
  100. fileSize += dataBuffer.byteLength
  101. downloadSize.textContent = `已接收 ${fileSize / 1000} kb`
  102. wavFragments.push(dataBuffer)
  103. }
  104. if (streamSize === 1900800) {
  105. downloadStatus.textContent = '下载长度超过免费限额,请分割文本后使用收集模式'
  106. if (!enableCollect) {
  107. fileSize = 0
  108. wavFragments.length = 0
  109. } else {
  110. fileSize -= 1900800
  111. wavFragments.length -= 1320
  112. }
  113. }
  114. },
  115. close: function () {
  116. downloadStatus.textContent = '下载完成'
  117. if(enableCollect) return
  118. const sentAudio = new window.Uint8Array(fileSize)
  119. fileSize = 0
  120. streamSize = 0
  121. wavFragments.reduce((size, fragment) => {
  122. sentAudio.set(new window.Uint8Array(fragment), size)
  123. return size + fragment.byteLength
  124. }, 0)
  125. wavFragments.length = 0
  126. saveAs(new Blob([sentAudio]), (new Date()).toISOString().replace('T', ' ').replace(':', '_').split('.')[0] + '.mp3')
  127. }
  128. }
  129.  
  130. const outputStream = SpeechSDK.PushAudioOutputStream.create(streamHandler)
  131.  
  132. SpeechSDK.AudioConfig.fromSpeakerOutput = (() => {
  133. const fromSpeakerOutput = SpeechSDK.AudioConfig.fromSpeakerOutput
  134. return function (audioDestination) {
  135. return enableDownload ? audioDestination.onAudioEnd() || SpeechSDK.AudioConfig.fromStreamOutput(outputStream) : fromSpeakerOutput(audioDestination)
  136. }
  137. })()
  138. })();