Skip to content

Instantly share code, notes, and snippets.

Created September 2, 2012 19:57
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save bltavares/3603997 to your computer and use it in GitHub Desktop.
Save bltavares/3603997 to your computer and use it in GitHub Desktop.
Firefox hackday

Mozilla hackday

This is the result of the Mozilla's hackday after BrazilJS 2012.

The idea is to create a text-to-speech app to run on the Firefox OS.

Due to some restrictions (like audio media and cross-domain requests) we need to setup a small proxy. It is written in ruby, using sinatra and it requires ffmpeg to be installed with vorbis support.


  1. Install ruby on your machine if you don't have
  2. Install sinatra ($ gem install sinatra)
  3. Install ffmpeg with vorbis support (on mac with brew:$ brew install ffmpeg --with-libvorbis --with-theora)
  4. Run the server ($ ruby server.rb)


It is really dumb right now, and can only read wikipedia articles with brazilian portuguese accent. It is just a proof of concept about a text-to-speech service.

Some limitations.

This server uses Google translate text-to-speech. It may take long to run it since it is donwloading the mp3 first. We could implement it using also Mac's native speech-to-text or any other one, which would be faster.

<!DOCTYPE html>
<html lang="en-us">
<script src=""></script>
<script src=""></script>
Array.prototype.chunk = function ( n ) {
if ( !this.length ) {
return [];
return [ this.slice( 0, n ) ].concat( this.slice(n).chunk(n) );
function toca(titles) {
var title = titles.shift();
var url = "/translation?text=" + (title);
var urlMp3 = "/translationMp3?text=" + (title);
$('#player').html("<audio controls='controls' autoplay='autoplay'> <source src='" + urlMp3 + "' type='audio/mpeg' /> <source src='" + url + "' type='audio/ogg' /> </audio>");
$("audio").on("ended", function() {
if(titles !== []){
var iframe = $("iframe");
iframe.attr("src", "/remote?url=" + $("#url").val());
var title = $("h1", iframe.contents()).text();
var p = $("#mw-content-text p", iframe.contents()).text().replace(/é/gi,"e").replace(/ã/gi,"a").replace(/\[.*\]/gi,'');
var ps = p.split(" ").chunk(10);
var pss =, function(i) { return i.join(" ");});
toca(_.flatten([title, pss]));
body {
text-align: center;
input {
margin: 1%;
<input id="url" value="" />
<input id="go" type="submit" value="Go!" />
<br />
<iframe id="canvas" height="100%" width="100%"> </iframe>
<div id="player" />
# encoding: utf-8
require 'sinatra'
require 'uri'
require 'net/http'
get '/' do"index.html")
get '/remote' do
Net::HTTP.get URI(URI.escape(params[:url]))
get '/translationMp3' do
content_type 'audio/mpeg'
`curl -A "Mozilla" '{URI.escape(params[:text])}'`
get '/translation' do
content_type 'audio/ogg'
`curl -A "Mozilla" '{URI.escape(params[:text])}' | ffmpeg -i pipe:0 -f ogg -acodec libvorbis pipe:1`
get '/webapp' do
content_type 'application/x-web-app-manifest+json'
"version": "1.0",
"name": "Mulher do google lê para você",
"description": "Tenha otimos sonhos e peça a melhor pizza com esse app",
"icons": {
"16": "",
"48": "",
"128": ""
"developer": {
"name": "Bruno Tavares/TC/Portela",
"url": ""
"installs_allowed_from": ["*"],
"orientation": "portrait,landscape-secondary",
"fullscreen": "true",
"default_locale": "en"
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment