chrome扩展程序
本文由Marc Towler进行同行评审。 感谢所有SitePoint的同行评审员使SitePoint内容达到最佳状态!
将文本转换为语音,也称为语音合成或TTS(文本转语音),是一种产生人类语音的人工方式。 这并不是什么新鲜事物,因为根据Wikipedia的介绍 ,人们已经尝试制造出可以产生人类语音的机器。
如今,TTS在我们的生活中变得越来越普遍,每个人都可以利用它。 我们将通过创建将文本转换为语音的Chrome扩展程序来演示这一点。 HTML5为我们带来了语音合成API ,该API允许任何Web应用程序将任意文本字符串转换为语音,并免费向用户播放。
Chrome扩展程序通常包含以下内容:
由于Chrome的普及和TTS的兴起,我们将创建一个Chrome扩展程序,将文本转换为语音。 该扩展程序将等待,直到用户单击其图标或按特殊的热键( shift + Y
),然后它将尝试查找用户在他们当前正在查看的页面上突出显示的内容,或者将尝试查找复制到剪贴板的内容。 如果有任何内容,它将首先尝试使用HTML5语音合成API,如果不可用,则将其转换为语音-通过调用第三方API。
每个Chrome扩展程序都需要有一个名为manifest.json的文件。 清单是JSON格式的文件,其中包含对应用程序至关重要的数据,范围包括名称,描述,图标和扩展的作者,以及定义扩展需求的数据-扩展应能够访问哪些网站运行(这些权限将是用户必须授予的权限)或在用户浏览特定网站时运行哪些文件。
{
"manifest_version": 2,
"name": "Page to Speech",
"description": "This extension will produce English speech to whatever text you highlight on a webpage.Highlight text and click the extension's icon",
"author": "Ivan Dimov",
"version": "1.0",
"icons": {
"16": "icon16.png",
"48": "icon48.png",
"128": "icon128.png"
},
我们的清单首先记录了扩展名,描述,作者,版本和图标。 您可以在icons
对象中提供许多响应不同大小的icons
。
"background": {
"scripts": ["background.min.js"]
},
"content_scripts": [
{
"matches": ["http://*/*", "https://*/*"],
"js": [ "polyfill.min.js", "ext.min.js"],
"run_at": "document_end"
}],
然后,在background
对象中定义了一个称为background.min.js
的后台脚本(注意,我们使用的是缩小文件)。 后台脚本是长时间运行的脚本,它将继续运行,直到关闭用户的浏览器或禁用扩展名为止。
然后,我们有一个content_scripts
数组,该数组指示Chrome由于通配符"http://*/*"
和"https://*/*"
而在每个网站请求中加载两个JavaScript文件。 与后台脚本不同, 内容脚本可以访问用户正在访问的实际网站的DOM。 内容脚本可以读取并进行修改,以使它们嵌入任何网页的DOM。因此,我们的polyfill.min.js
和ext.min.js
将能够对每一个网页读取和修改的所有数据。
"browser_action": {
"default_icon": "speech.png"
},
"permissions": [
"activeTab",
"clipboardRead"
]
}
没那么快! 我们还有另一个称为permissions
数组,我们要求使用该数组仅访问用户当前打开的网页(活动选项卡)。 我们还请求另一个名为clipboardRead
读取的权限,该权限将允许我们读取用户的剪贴板(以便将其内容转换为语音)。
首先,我们创建一个唯一的后台脚本,该脚本连接一个事件监听器,当用户单击扩展程序的图标时将触发该事件监听器。 发生这种情况时,我们调用sendMessage
函数,该函数在chrome.tabs.sendMessage(tabId, message, callback)
的帮助下将消息发送到我们的内容脚本(内容脚本可以读取DOM并找出用户突出显示的内容或/和用户放置在剪贴板上的内容) chrome.tabs.sendMessage(tabId, message, callback)
方法。 我们通过chrome.tabs.query
方法将消息发送到当前打开的选项卡-这正是我们感兴趣的并且是我们可以访问的选项卡,该方法的参数涉及回调,该回调将被包含以下参数的参数调用与查询匹配的标签。
chrome.browserAction.onClicked.addListener(function (tab) {
//fired when the user clicks on the ext's icon
sendMessage();
});
function sendMessage() {
chrome.tabs.query({active: true, currentWindow: true}, function(tabs){
chrome.tabs.sendMessage(tabs[0].id, {action: "pageToSpeech"}, function(response) {});
});
}
现在,更长的部分是我们的内容脚本。 我们创建一个对象,该对象将保存扩展所涉及的一些数据,然后定义我们的初始化方法。
initialize: function() {
if (!pageToSpeech.hasText()) { return;}
if (!pageToSpeech.trySpeechSynthesizer()) {
pageToSpeech.trySpeechApi();
}
},
该方法检查用户是否未突出显示文本或剪贴板上没有任何内容,并且仅在这种情况下返回。 否则,它将尝试使用HTML5语音合成API产生语音。 如果那也失败了,它最终会尝试使用第三方API。
检查文本的方法有几件事情。 它尝试借助内置的getSelection()
方法获取带有突出显示文本的对象,并使用toString()
将其转换为文本字符串。 然后,如果没有突出显示文本,它将尝试在用户剪贴板上查找文本。 通过在页面上添加输入元素,对其进行聚焦,在execCommand('paste')
的帮助下触发粘贴事件,然后将输入内的粘贴文本保存在属性中,可以完成此操作。 然后清空输入。 无论哪种情况,它都会返回找到的内容。
hasText: function() {
this.data.highlightedText = window.getSelection().toString();
if (!this.data.highlightedText) {
var input = document.createElement("input");
input.setAttribute("type", "text");
input.id = "sandbox";
document.getElementsByTagName("body")[0].appendChild(input);
var sandbox = document.getElementById("sandbox");
sandbox.value = "";
sandbox.style.opacity = 0;
sandbox.focus();
if (document.execCommand('paste')) {
this.data.highlightedText = sandbox.value;
}
sandbox.value = "";
}
return this.data.highlightedText;
},
为了使用户能够使用热键(硬编码为shift + Y
)运行文本到语音的转换,我们初始化了一个数组,并为onkeydown
和onkeyup
事件设置了一个事件侦听器。 在侦听器中,我们存储一个与按下的键的keyCode
对应的索引,该索引的值是从事件e.type
与keydown
的比较e.type
,并且是布尔值。 因此,每当按下一个键时,相应的键索引的值将被设置为true
而每当释放一个键时–索引的值将被更改为false
。 因此,如果索引16和84都保持真实值–我们知道用户正在使用我们的热键,因此我们将文本初始化为语音转换。
addHotkeys: function() {
var activeKeys = [];
onkeydown = onkeyup = function(evt) {
var e = evt || event;
activeKeys[e.keyCode] = e.type == 'keydown';
if (activeKeys[16] && activeKeys[84]) {
pageToSpeech.initialize();
}
};
}
要将文本转换为语音,我们需要使用trySpeechSynthesizer()
方法。 如果用户的浏览器中存在HTML5语音合成( window.speechSynthesis
),我们知道用户可以使用它,因此我们检查语音是否正在运行(我们知道它是否通过pageToSpeech.data.speechInProgress
布尔值运行)。 。 如果当前语音正在进行中,我们将停止它(因为trySpeechSynthesizer
将开始新的语音,并且我们不希望同时发出两种声音)。 然后,我们将speechInProgress
设置为true
并且每当语音结束时,都将属性再次设置为假值。
现在,我不想详细说明为什么我们要使用speechUtteranceChunker
但这是与Chrome有关的一个错误修复程序 ,该Chrome会在发出200-300个单词后停止语音合成,而语音合成仍在进行中。 基本上,它将文本字符串分成许多较小的块(在我们的示例中为120个单词),然后一个接一个地调用语音合成API。
trySpeechSynthesizer: function() {
if (window.speechSynthesis ) {
//new speech is about to get started
if (this.data.speechInProgress) {
polyfills.speechUtteranceChunker.cancel = true;
}
this.data.speechInProgress = true;
var msg = new SpeechSynthesisUtterance(this.data.highlightedText);
//speechSynthesis.speak(msg);
// Chrome Implementation BUG: http://stackoverflow.com/questions/21947730/chrome-speech-synthesis-with-longer-texts
polyfills.speechUtteranceChunker(msg, {
chunkLength: 120
},function() {
//speech has finished
pageToSpeech.data.speechInProgress = false;
});
最后,如果HTML5语音合成API不可用,我们尝试使用API。 我们具有用于了解是否有必要停止已经运行的音频的相同属性。 然后,我们直接创建一个新的Audio
对象,并将URL传递给所需的API端点,因为我们为演示选择的API直接流了音频。 我们只是将API密钥和要传递的文本传递给它。 我们还会检查音频是否触发错误。 在这种情况下,我们只向用户显示alert
,说这一次我们无能为力(此特定的API,即Voice RSS ,允许我们在测试代码的免费层上进行300个请求)。
trySpeechApi: function() {
if (this.data.speechInProgress) {
this.data.fallbackAudio.pause();
}
this.data.speechInProgress = true;
this.data.fallbackAudio = new Audio("http://api.voicerss.org/?key=your_api_key&src=" + this.data.highlightedText);
this.data.fallbackAudio.addEventListener("error", function(evt) {
alert("Sorry, we cannot produce speech right now. Try upgrading your Chrome browser!");
})
this.data.fallbackAudio.play();
this.data.fallbackAudio.onended = function() {
pageToSpeech.data.speechInProgress = false;
}
},
最后,在任何本地范围之外,我们都调用addHotkeys
方法,该方法将开始等待用户按下右侧的热键,并设置一个侦听器,该侦听器将等待直到从后台脚本接收到消息为止。 如果收到了正确的消息( speakHighlight )或按下了热键,我们将把文本初始化为语音转换对象。
chrome.extension.onMessage.addListener(function(msg, sender, sendResponse) {
if (msg.action == 'pageToSpeech') {
pageToSpeech.initialize();
}
});
pageToSpeech.addHotkeys();
全面介绍PHP和MySQL,从而实现服务器端编程的飞跃。
原价$ 11.95 您的完全免费
而且,我们有一个不错的Chrome扩展程序,可将文本转换为语音。 此处的概念可用于创建用于不同用途的Chrome扩展程序。 您是否构建了任何有趣的Chrome扩展程序,还是想构建一个? 在评论中让我知道!
如果您喜欢这个想法并希望进一步发展,可以在我们的GitHub存储库中找到完整的代码。 如果您要测试扩展程序的生产版本,可以在Chrome网上应用店中找到它。
参考文献:
https://zh.wikipedia.org/wiki/语音合成#历史
http://stackoverflow.com/questions/21947730/chrome-speech-synthesis-with-longer-texts
翻译自: https://www.sitepoint.com/create-text-to-speech-chrome-extension/
chrome扩展程序