Skip to content

Commit db26697

Browse files
authored
Remove the playsound library and just print spoken text to console (#1462)
* Remove the playsound library and just print spoken text to console * Fix more tests * More import removals * A new exercise to implement a speech engine * Language tweaks in the pyttsx exericse * Remove playsound/gtts/os.remove shims
1 parent 998be4b commit db26697

10 files changed

Lines changed: 27 additions & 111 deletions

File tree

book/accessibility.md

Lines changed: 24 additions & 40 deletions
Original file line numberDiff line numberDiff line change
@@ -1769,6 +1769,12 @@ more clearly how screen readers interact with the accessibility tree, our
17691769
discussion of screen reader support will instead include a minimal
17701770
screen reader integrated directly into the browser.
17711771

1772+
[^why-diff]: Screen readers need to help the user with operating
1773+
system actions such as logging in, starting applications, and
1774+
switching between them, so it makes sense for the screen reader to
1775+
be outside any application and to integrate with them through the
1776+
operating system.
1777+
17721778
But should our built-in screen reader live in the `Browser` or each `Tab`?
17731779
Modern browsers generally talk to screen readers from something like the
17741780
`Browser`, so we'll do that too.^[And therefore the browser thread in our
@@ -1813,54 +1819,22 @@ browser thread, much like with the display list, to avoid a data race.
18131819
[ch12-commit]: scheduling.html#committing-a-display-list
18141820

18151821
Now that the tree is in the browser thread, let's implement the screen
1816-
reader. We'll use two Python libraries to actually read text out loud:
1817-
[`gtts`][gtts] (which wraps the Google [text-to-speech service][tts])
1818-
and [`playsound`][playsound]. You can install them using `pip`:
1819-
1820-
[^why-diff]: Screen readers need to help the user with operating
1821-
system actions such as logging in, starting applications, and
1822-
switching between them, so it makes sense for the screen reader to
1823-
be outside any application and to integrate with them through the
1824-
operating system.
1825-
1826-
[gtts]: https://pypi.org/project/gTTS/
1827-
1828-
[tts]: https://cloud.google.com/text-to-speech/docs/apis
1822+
reader. Normally screen readers read text aloud, often much faster
1823+
than a normal speaking pace. Let's skip that---it'd add all sorts of
1824+
complexities around audio mixing and playback---and just have the
1825+
screen reader print the text it's going to say to the screen.[^playsound]
18291826

1830-
[playsound]: https://pypi.org/project/playsound/
1831-
1832-
``` {.sh}
1833-
python3 -m pip install gtts
1834-
python3 -m pip install playsound
1835-
```
1827+
[^playsound]: Older editions of this book implemented an actual speech
1828+
engine using the `playsound` and `gtts` libraries, but it was
1829+
perhaps too simple to be useful; see Exercise 14-11.
18361830

18371831
You can use these libraries to convert text to an audio file, and then
18381832
play it:
18391833

18401834
``` {.python}
1841-
import os
1842-
import gtts
1843-
import playsound
1844-
1845-
SPEECH_FILE = "/tmp/speech-fragment.mp3"
1846-
18471835
def speak_text(text):
18481836
print("SPEAK:", text)
1849-
tts = gtts.gTTS(text)
1850-
tts.save(SPEECH_FILE)
1851-
playsound.playsound(SPEECH_FILE)
1852-
os.remove(SPEECH_FILE)
1853-
```
1854-
1855-
::: {.quirk}
1856-
You may need to adjust the `SPEECH_FILE` path to fit your system
1857-
better. If you have trouble importing any of the libraries, you may
1858-
need to consult the [`gtts`][gtts] or [`playsound`][playsound]
1859-
documentation. If you can't get these libraries working, just delete
1860-
everything in `speak_text` except the `print` statement. You won't
1861-
hear things being spoken, but you can at least debug by watching the
1862-
console output.
1863-
:::
1837+
```
18641838

18651839
To start with, we'll want a key binding that turns the screen reader
18661840
on and off. While real operating systems typically use more obscure
@@ -2724,3 +2698,13 @@ accessibility feature to web developers, plus it allows applying it only
27242698
to designated HTML subtrees.
27252699

27262700
[zoom-property]: https://developer.mozilla.org/en-US/docs/Web/CSS/zoom
2701+
2702+
14-11 *Speaking out loud*. Add code to actually read web pages aloud.
2703+
The [`pyttsx`][pyttsx] library can speak text in "non-blocking" mode,
2704+
though it will require some integration with the browser event loop.
2705+
Make sure to interrupt speech when the user hovers over nodes or tabs
2706+
throughout the document. Implement the `aria-live` attribute so the
2707+
author can create either `assertive` alerts that interrupt current
2708+
speech or `polite` ones that don't.
2709+
2710+
[pyttsx]: https://pypi.org/project/pyttsx3/

requirements.txt

Lines changed: 0 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -11,23 +11,3 @@ pysdl2-dll==2.26.5
1111

1212
# OpenGL is used in Chapters 13+ for GPU-accellerated Skia
1313
PyOpenGL==3.1.6
14-
15-
# gTTS is used in Chapter 14+ for reading accessibility text
16-
gTTS==2.3.2
17-
charset-normalizer==3.1.0
18-
six==1.16.0
19-
click==8.1.3
20-
21-
requests==2.32.4
22-
urllib3==2.5.0
23-
idna==3.7
24-
certifi==2024.7.4
25-
26-
# PlaySound is used in Chapters 14+ for reading accessibility text
27-
# PyObjC is useful on macOS systems for accellerating playsound
28-
# And quieting an error message. Transitive dependencies of
29-
# PyObjC are not frozen because there are a lot and they may depend
30-
# on macOS version.
31-
playsound==1.3.0; sys_platform == "darwin"
32-
pyobjc==9.1.1; sys_platform == "darwin"
33-
pyobjc-core==9.1.1; sys_platform == "darwin"

src/lab14-tests.md

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,6 @@ This file contains tests for Chapter 14 (Accessibility).
88
>>> import test
99
>>> _ = test.socket.patch().start()
1010
>>> _ = test.ssl.patch().start()
11-
>>> _ = test.gtts.patch()
1211
>>> _ = test.MockLock.patch().start()
1312
>>> import lab14
1413
>>> import time

src/lab14.py

Lines changed: 1 addition & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -8,13 +8,7 @@
88
import ctypes
99
import dukpy
1010
import math
11-
import os
12-
import gtts
13-
try:
14-
import playsound
15-
except:
16-
playsound = None
17-
11+
1812
import sdl2
1913
import skia
2014
import socket
@@ -494,15 +488,8 @@ def __repr__(self):
494488
return "AccessibilityNode(node={} role={} text={} bounds={}".format(
495489
str(self.node), self.role, self.text, self.bounds)
496490

497-
SPEECH_FILE = "/tmp/speech-fragment.mp3"
498-
499491
def speak_text(text):
500492
print("SPEAK:", text)
501-
tts = gtts.gTTS(text)
502-
tts.save(SPEECH_FILE)
503-
if playsound:
504-
playsound.playsound(SPEECH_FILE)
505-
os.remove(SPEECH_FILE)
506493

507494
class PseudoclassSelector:
508495
def __init__(self, pseudoclass, base):

src/lab15-tests.md

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,6 @@ This file contains tests for Chapter 15 (Embedded Content).
88
>>> import test
99
>>> _ = test.socket.patch().start()
1010
>>> _ = test.ssl.patch().start()
11-
>>> _ = test.gtts.patch()
1211
>>> _ = test.MockLock.patch().start()
1312
>>> import lab15
1413
>>> import time

src/lab15.py

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,6 @@
77
import sys
88
import ctypes
99
import dukpy
10-
import gtts
1110
import math
1211
import os
1312
import sdl2
@@ -44,7 +43,7 @@
4443
dpx, cascade_priority, style, \
4544
is_focusable, get_tabindex, speak_text, \
4645
CSSParser, mainloop, Browser, Chrome, Tab, \
47-
AccessibilityNode, PseudoclassSelector, SPEECH_FILE
46+
AccessibilityNode, PseudoclassSelector
4847
from lab14 import DocumentLayout, BlockLayout, LineLayout, TextLayout
4948

5049
@wbetools.patch(URL)

src/lab16-tests.md

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,6 @@ This file contains tests for Chapter 16 (Invalidation).
88
>>> import test
99
>>> _ = test.socket.patch().start()
1010
>>> _ = test.ssl.patch().start()
11-
>>> _ = test.gtts.patch()
1211
>>> _ = test.MockLock.patch().start()
1312
>>> import lab16
1413
>>> import time

src/lab16.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -40,7 +40,7 @@
4040
from lab14 import parse_outline, style, \
4141
paint_outline, dpx, cascade_priority, \
4242
is_focusable, get_tabindex, speak_text, \
43-
CSSParser, mainloop, Chrome, PseudoclassSelector, SPEECH_FILE
43+
CSSParser, mainloop, Chrome, PseudoclassSelector
4444
from lab15 import URL, HTMLParser, AttributeParser, DrawImage, \
4545
DocumentLayout, BlockLayout, \
4646
EmbedLayout, InputLayout, LineLayout, TextLayout, ImageLayout, \

src/test.py

Lines changed: 0 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -234,20 +234,6 @@ def __init__(self, x, y):
234234
self.x = x
235235
self.y = y
236236

237-
class gtts:
238-
class gTTS:
239-
def __init__(self, text):
240-
pass
241-
def save(self, file):
242-
pass
243-
244-
@classmethod
245-
def patch(cls):
246-
import sys
247-
sys.modules["gtts"] = cls()
248-
249-
250-
251237
def SDL_GetWindowSurfacePatched(window):
252238
return None
253239

www/widgets/rt.js

Lines changed: 0 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,6 @@ export {
66
truthy, comparator, pysplit, pyrsplit, asyncfilter,
77
rt_constants, Widget, http_textarea, skia, sdl2, init_skia,
88
init_window, threading, time, OpenGL, patch_class, patch_function, dict,
9-
gtts, os, playsound
109
};
1110

1211
function patch_class(cls, patched_cls) {
@@ -898,22 +897,6 @@ class OpenGL {
898897
}
899898
}
900899

901-
class gtts {
902-
static gTTS(text) {
903-
return { save: (file) => {} }
904-
}
905-
}
906-
907-
class playsound {
908-
static playsound(file) {
909-
}
910-
}
911-
912-
class os {
913-
static remove(file) {
914-
}
915-
}
916-
917900
class ctypes {
918901
}
919902

0 commit comments

Comments
 (0)