A webapp that reads your articles to you while you're on the subway

Overview

ReadToMyShoe logo

ReadToMyShoe

Video Demo

A website that reads articles to you, even when you're offline. Still in early development.

This is a full-stack Rust webapp, using axum for the backend and yew for the frontend.

Installation

Google Cloud

We use Google Cloud's text to speech engine. Here's how to get an API key:

  • Make a Google Cloud account,
  • Go to the credentials page
  • Click "Create Credentials" at the top of the page and select "API Key"
  • You can copy the API key right now or click "Edit API key" and restrict its capabilities. To restrict:
    • Click "Edit API key"
    • Under "API restrictions" click "Restrict key"
    • Select "Cloud Text-to-Speech API"
  • Now copy your API key to the clipboard

Once you've got your API key, you need to give it to the ReadToMyShoe server:

  • Create a new file in the server/ directory, called gcp_api.key
  • Paste the API key into that file

That's it!

OpenSSL

You need to have OpenSSL installed on your machine:

  • For Ubuntu and Debian, do sudo apt-get install libssl-dev
  • For Mac, do brew install openssl

Python dependencies

We use trafilatura for article content extraction. This is installed directly in the local directory.

  • Install pip3. On a Mac: brew install python3. On Ubuntu: sudo apt-get install python3-pip.
  • In readtomyshoe/, run pip3 install trafilatura -t python_deps
    • In the future, if you want to update trafilatura, run pip3 install --upgrade trafilatura -t python_deps

ReadToMyShoe will now be able to use the python_deps/bin/trafilatura binary.

For devs: If you wanna run trafilatura yourself, first cd python_deps, then run PYTHONPATH=. ./bin/trafilatura

Other necessary setup

We need a few utilities for building the website.

  • First, make sure you have rustup installed. Follow the directions here. Make sure to add $HOME/.cargo/bin to your PATH.
  • Run rustup target add wasm32-unknown-unknown. This installs the WASM target so Rust knows how to output code for the browser.
  • cargo install --locked trunk. The trunk utility packages the frontend assets of the website.
  • If you're on an M1 Mac, run cargo install --locked wasm-bindgen-cli. This is because trunk doesn't know how to download the bindgen CLI itself (tracking issue).

Dev Setup

If you want to work on this repo in an IDE, it will be easiest if you put the following lines in your ~/.cargo/config file. This is because web_sys gates unstable features via cfg. I know this is very weird.

[build]
rustflags = ["--cfg=web_sys_unstable_apis"]
rustdocflags = ["--cfg=web_sys_unstable_apis"]

You'll also need to run cargo install cargo-watch in order to use script/dev.sh. This is a filesystem watcher that tells the server to autoreload whenever a file is changed.

Usage

Run the dev version (auto-reloads server & client on file change) with ./scripts/dev.sh.

Run the pre-compiled version with ./scripts/prod.sh.

The app will start at https://localhost:8080 by default. The default behavior is to make the service visible to your whole local network. To make it only accessible from your own machine, delete --address 0.0.0.0 from dev.sh and/or prod.sh.

NOTE: If you run ReadToMyShoe on your local network or generally without HTTPS, iOS will NOT cache anything. This is because Service Workers are only allowed in "secure contexts" (meaning via HTTPS or on localhost).

Deployment

Docker: The Dockerfile in this directory should Just Work. Run docker run readtomyshoe -p 8080:8080 to start ReadToMyShoe on port 8080. Currently, this does not support storing audio files on an external volume. This is in the TODOs.

Fly.io: We also support one-click deployment on Fly.io. To deploy, simply pick a new app name in fly.toml, make an app with that name in your Fly.io account, and run flyctl deploy. This uses the Dockerfile for deployment, so any changes there will change your Fly.io deployment.

TODO

An incomplete to-do list, roughly in order of most important to least important:

  • Save current article, playback position, and speed
  • Write an accessible progress notifs for adding to queue, and error notifs for fetch and what not
  • Implement "next track" functionality with queue
  • Make the Dockerfile compatible with external volumes
  • Handle errors in article fetch better: delete temp files, implement retries to Google TTS
  • Save more metadata than article title: id, url, title, byline, text. Maybe store in the ID3v2 tags?
  • Show more detailed progress in the add article view
  • Make whole site WCAG-compliant
  • Make queue order mutable
  • Fix caching in dev mode (the trouble is that assets are in /assets/ in prod, but / in dev)
  • Implement login functionality and make per-user libraries
  • Write rate-limiting code for TTS service

Licenses

All code is licensed under either of

at your option.

Images are licensed by Michael Rosenberg under the CC BY 4.0.

Thanks

A lot of the ideas and code in this crate started with Robert Krahn's fantastic template. Thanks

Also, big thanks to my friend Sharon Ye for her immense help in the design of the logo.

Comments
  • UI improvements for Add to Queue

    UI improvements for Add to Queue

    Add to Queue is pretty hard to use right now. There's a few things that should be done:

    1. Some UI feedback that acknowledges you pressed the button to add the article to queue
    2. Adding an article to the queue might take a long time if you have a poor internet connection. So a progress on the status of the download would be helpful
    3. Something should prevent you from adding the same article to queue multiple times (or at least optimize it so that it doesn't have to download anything twice). On the flip side, deleting from queue should remove all instances of the deleted article.
    enhancement 
    opened by rozbb 1
  • Article extraction errors are bad

    Article extraction errors are bad

    Currently, if trafilatura fails at extracting an article, the error presented in the Add Article view is a parsing error. This is because trafilatura exits with a 0 error code, even on failure.

    Note: this is a trafilatura bug that was reported and fixed. Once the fix is upstreamed, this will be closed.

    bug 
    opened by rozbb 1
  • Add Article creates corrupt file on error

    Add Article creates corrupt file on error

    Browser: All browsers

    Description: If you add an article and an error occurs during TTS, the corrupt file will remain in the library.

    Note: Simple fix is to do everything using a temp file and to move it to the library under the appropriate filename after everything succeeds.

    opened by rozbb 1
  • Play/Pause <button> does not always act like a play/pause button

    Play/Pause

    Browser: All browsers

    Description: If you pause, then seek, then hit the play/pause button to resume, it will play from the position before the seek. This is because the play/pause button loads the last known state when playing. It seems the

    Notes: One possible solution to make play/pause respect seeking/jumping is to trigger a save on every seek/jump. A better solution I think is to remove the play/pause button altogether. The reason it exists is because clicking the play button on the <audio> element will sometimes not play from the correct time, because the tab may have previously been unloaded and lost its place. This would be fixed if we had callbacks from the Page Lifecycle API that reload the player state whenever the player becomes visible again and was not playing something already. See visibilitychange

    opened by rozbb 1
  • Make a Wiki

    Make a Wiki

    There's too much info in the README. The Wiki should have, at least:

    • A high-level overview
    • Design goals and non-goals
    • Dev notes
    • Deployment notes. Cover Fly.io, Caddy config, nginx config, and GCP setup and cost
    • A quickstart guide
    documentation 
    opened by rozbb 0
  • Blocked by reverse proxies

    Blocked by reverse proxies

    RTMS instances are being detected as bots, and receiving 403 (Forbidden) on pages hosted by Cloudlflare and AWS Cloudfront. The traffic volume of the instance is irrelevant to whether it gets banned.

    Possible solutions:

    1. Register with Cloudflare as a friendly bot
    2. Write a bookmarklet that will submit articles directly to the server, rather than having the server make the request. This is a nice solution because it also solves #28 without any extra work.
    bug 
    opened by rozbb 0
  • Keyboard bindings

    Keyboard bindings

    This really really needs keyboard bindings. You shouldn't need to use a screen reader just to find the pause button for the audio that's currently playing. Copy popular bindings, maybe from youtube.

    enhancement accessibility 
    opened by rozbb 0
  • Insert sentence breaks to titles

    Insert sentence breaks to titles

    Currently, the TTS voice speeds through the entire title, byline, and first sentence of the article. These should all be spoken as separate sentences. The reason they're not is because the text extraction has them separated by newlines. The TTS for web-derived articles should replace newlines with periods, so that the TTS breaks at the appropriate places.

    enhancement accessibility 
    opened by rozbb 0
  • Add total queue length

    Add total queue length

    It would be nice to be able to see the total length of the downloaded queue. Since you can't see the length of articles without opening them (including before you download them), the only way to know how much time you have queued up is to manually open every article. Total queue length solves this problem with less clutter than displaying every article length individually.

    opened by ericwinsor 0
  • Implement a readalong UI

    Implement a readalong UI

    It would be nice to have a way of reading the text along with the voice. This would be possible using the current API by adding an SSML <mark> tag to every sentence. The TTS will return timepoints that can tell the client which sentence they're reading at a given timestamp.

    enhancement accessibility 
    opened by rozbb 0
  • Let users use their own Google Cloud account for TTS

    Let users use their own Google Cloud account for TTS

    It should be possible to make RTMS use a service account that can bill to subordinate accounts. This would allow me to run a persistent RTMS server and only pay for storage, rather than the expensive TTS bills too.

    The flow would roughly be:

    1. User makes a Google Cloud account just like in Getting Started
    2. User logs into RTMS and is presented with a special authentication link
    3. User clicks the link, which will take them to GCP and ask if they want to give access to their TTS API key. User clicks OK
    4. User returns to RTMS and can use it on their own dime.
    enhancement 
    opened by rozbb 1
Releases(v0.2.0)
  • v0.2.0(Sep 12, 2022)

    Initial release. Intended for a Show HN on 2022-09-12. Changelog:

    [0.2.0] - 2022-09-12

    Additions

    • Introduced CHANGELOG.md
    • Added progress bar indicator to Add to Queue buttons.
    • Implemented TTS rate limiting on the backend. CLI flag is --max-chars-per-min.
    • Instituted size limit on title length. 300 UTF-16 code units.

    Fixes

    • Made backend use (and clean up) temp files in article extraction. Fixes bug where a failed extraction makes retry impossible due to "File already exists" error.
    • Improved presentation of errors. Trafilatura errors now say "extraction error" rather than "error parsing trafilatura JSON output"
    Source code(tar.gz)
    Source code(zip)
Owner
Michael Rosenberg
Cryptography PhD student at the University of Maryland. PM me your orphan blocks
Michael Rosenberg
A bunch of links to blog posts, articles, videos, etc for learning Rust

rust-learning A bunch of links to blog posts, articles, videos, etc for learning Rust. Feel free to submit a pull request if you have some links/resou

Camille TJHOA 9k Jan 4, 2023
Functions for mapping plaintexts to a u64 while preserving sort order

ore_encoding.rs This is a companion package to ore.rs that can generate and manipulate u64 plaintexts before they are encrypted by ore.rs. Being able

CipherStash 2 Dec 14, 2022
Grimsby is an Erlang Port written in Rust that can close its standard input while retaining standard output (and error)

Grimsby An Erlang Port provides the basic mechanism for communication from Erlang with the external world. From the Ports and Port Drivers: Erlang Ref

Peter Morgan 5 May 29, 2023
📱️🚫️🌝️💾️ 3FakeIM is a joke program meant to imitate various fictional characters, and the "[CHARACTER] CALLED ME AT 3:00 AM" clickbait trend, while poking fun.

3FakeIM ??️??️??️??️ 3FakeIM is a joke program meant to imitate various fictional characters, and the "[CHARACTER] CALLED ME AT 3:00 AM" clickbait tre

Sean P. Myrick V19.1.7.2 2 Jul 3, 2023
A tray application for Windows that gives you push notifications and instant downloads of new posts, messages and stories posted by models you subscribe to on Onlyfans.

OF-notifier A tray application for Windows that gives you push notifications and instant downloads of new posts, messages and stories posted by models

Gentlemen Mercenary 10 Dec 20, 2022
TypeRust - simple Rust playground where you can build or run your Rust code and share it with others

Rust playground Welcome to TypeRust! This is a simple Rust playground where you can build or run your Rust code and share it with others. There are a

Kirill Vasiltsov 28 Dec 12, 2022
Goodname is a tool to assist you with cool naming of your methods and software

Goodname is a tool to assist you with cool naming of your methods and software. Given a brief description of your method or software, this tool enumerates name candidates forming subsequences of the description (i.e., abbreviation).

Shunsuke Kanda 118 Dec 28, 2022
:crab: Small exercises to get you used to reading and writing Rust code!

rustlings ?? ❤️ Greetings and welcome to rustlings. This project contains small exercises to get you used to reading and writing Rust code. This inclu

The Rust Programming Language 33.1k Jan 2, 2023
Cogo is a high-performance library for programming stackful coroutines with which you can easily develop and maintain massive concurrent programs.

Cogo is a high-performance library for programming stackful coroutines with which you can easily develop and maintain massive concurrent programs.

co-rs 47 Nov 17, 2022
This project contains small exercises to get you used to reading and writing Rust code

rustlings ?? ❤️ Greetings and welcome to rustlings. This project contains small exercises to get you used to reading and writing Rust code. This inclu

Cynthia Tran 1 May 24, 2022
A tool & library to help you with the compiler course.

Compiler Course Helper Support: eliminate left recursion (require grammar with no cycles or ϵ-production) calculate nullable, first sets, follow, sets

水夕 4 May 2, 2022
In this repository you can find modules with code and comments that explain rust syntax and all about Rust lang.

Learn Rust What is this? In this repository you can find modules with code and comments that explain rust syntax and all about Rust lang. This is usef

Domagoj Ratko 5 Nov 5, 2022
Rust app that creates cli quiz for you!

quizer rust app that creates cli quiz for you! Installation Download binary release or build from source using cargo Make binary executable chmod +x /

Fedya Petrakov 1 Sep 5, 2022
rust database for you to use and help me make!

Welcome To Rust Database! What is this? this is a database for you to git clone and use in your project! Why should i use it? It is fast and it takes

Carghai74 2 Dec 4, 2022
A dos attack for you to use!

Welcome To Rust Dos attacker! Why should I use it? It has unrivaled speeds because it is built in rust and hand optimized. It also comes with an AI mo

Carghai74 5 Dec 2, 2022
A tool that helps you to turn in one command a Rust crate into a Haskell Cabal library!

cabal-pack A tool that helps you to turn in one command a Rust crate into a Haskell Cabal library! To generate bindings, you need to annotate the Rust

Yvan Sraka 18 Dec 31, 2022
This is the Rust course used by the Android team at Google. It provides you the material to quickly teach Rust to everyone.

Comprehensive Rust ?? This repository has the source code for Comprehensive Rust ?? , a four day Rust course developed by the Android team. The course

Google 5.2k Jan 3, 2023
A cli tool to write your idea in terminal

Ideas ideas is a cli tools to write your idea in your terminal. Demo Features tagged idea, contains tips, idea, todo status switch ascii icon write yo

王祎 12 Jun 22, 2022
Take your first step in writing a compiler. Implemented in Rust.

first-step-rust Take your first step in writing a compiler, using Rust. Building from Source Make sure the Rust toolchain is installed on your compute

PKU Compiler Course 13 Aug 28, 2022