Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
58 commits
Select commit Hold shift + click to select a range
4431ec4
preserve Cantonese hyphenation
ssb22 Mar 18, 2023
b391a56
clarify comment
ssb22 Jul 1, 2023
bc7528d
Sidney Lau aa->a rule was wrong (typo in the example I used as a guide)
ssb22 Jul 9, 2023
d451c6c
Sidney Lau also fix in Java
ssb22 Jul 10, 2023
18ff713
fix Cantonese transliteration duplicating pre-included jyutping
ssb22 Sep 21, 2023
e0fdf29
properly fix last commit: it was a Python 3 compatibility issue
ssb22 Sep 22, 2023
babc589
this was also supposed to be in last commit
ssb22 Sep 22, 2023
3260b95
fix Cantonese Mandarin-driven override table (bian/pian was swapped)
ssb22 Sep 24, 2023
f8e9998
Cantonese readings from shen/shi
ssb22 Dec 3, 2023
c42c892
web: try harder to stop users accidentally playing two lessons at once
ssb22 Dec 5, 2023
0bd9f2b
server avoid spurious settings files; update identifier wording
ssb22 Dec 6, 2023
6b0896d
Mac: fix launcher for macOS 14
ssb22 Dec 10, 2023
706d688
fix occasional Python 3 crash
ssb22 Dec 12, 2023
61f718c
fix Mac afplay partials-synth on Python 3
ssb22 Dec 19, 2023
08fd2de
Rasbperry Pi OS 12 Bluetooth settings
ssb22 Jan 2, 2024
3ff3eea
player does not need to start pulseaudio on startup
ssb22 Jan 14, 2024
6491bd3
player RPi12 comment
ssb22 Jan 16, 2024
be2aebf
Cantonese handle emoji pass-through on Python 2
ssb22 Jan 21, 2024
1f96861
server script modernisations
ssb22 Mar 23, 2024
f9e8f3c
fix write to closed file on transliteration cache in Python 3 + ready…
ssb22 Jun 9, 2024
c4d0dba
fix executable flag
ssb22 Jun 22, 2024
af62f7e
cgi: zoom control; script variants; lesson timer; error localisations…
ssb22 Jul 5, 2024
7fe0510
idiomatic Cantonese hanzi prompts that eSpeak zh-yue can transliterate
ssb22 Jul 10, 2024
c489f51
cgi: big-print layout tweaks + nginx/fcgiwrap compatibility + fix Pyt…
ssb22 Jul 15, 2024
70d28fc
fix Python 3 compatibility issue in Unicode progress files
ssb22 Jul 20, 2024
033aa83
experimental support for Coqui speech synthesis on GNU/Linux
ssb22 Dec 5, 2024
122ea17
fix Coqui support + Python 2 compatibility
ssb22 Dec 6, 2024
5f792aa
fix PATH for some recent Macs; server support HTTP Range (improves iO…
ssb22 Dec 26, 2024
bf7912a
minor Mac warning simplification
ssb22 Dec 28, 2024
70c0e93
omit pycache from gradint-build.7z
ssb22 Dec 28, 2024
94788bf
fix a Python 2.3 compatibility regression that broke the Windows pack…
ssb22 Jan 26, 2025
617e6ca
another Python 2.3 compatibility regression, this time in Coqui handling
ssb22 Jan 26, 2025
3562904
and a third Python 2.3 compatibility regression: can't use inline con…
ssb22 Jan 26, 2025
0311fd7
player script Bluetooth setup on Raspberry Pi OS 12 on Zero W
ssb22 Feb 8, 2025
d254f01
support Piper TTS on GNU/Linux
ssb22 Feb 21, 2025
bacf242
misc fixes for Ubuntu 24.04
ssb22 Feb 23, 2025
fbd7292
LXDE/LXQt compatibility
ssb22 Mar 2, 2025
f9d58b3
GNU/Linux install script for multiuser + desktop menu entry
ssb22 Mar 4, 2025
10a6ad6
GNU/Linux uninstall: missed detail
ssb22 Mar 6, 2025
e16f7a7
server: note legacy-cgi for Python 3.13
ssb22 Apr 4, 2025
7c8d843
support transliteration of more quote marks (including some used in C…
ssb22 Apr 26, 2025
e6331ce
option to test on remote Mac via GitHub Actions
ssb22 Jun 12, 2025
62c71af
remember to make gradint.py on the Actions runner
ssb22 Jun 14, 2025
c24624a
fix .sh-output mp3 playing; fix Mac voice scan on recent models with …
ssb22 Jun 21, 2025
b4acf2d
fix importing recordings in Python 3 + fix GitHub action handling of …
ssb22 Jul 7, 2025
69229cb
ChatterboxTTS support
ssb22 Aug 9, 2025
2d4425f
Gemini TTS support
ssb22 Aug 17, 2025
484b863
fix Gemini voice support
ssb22 Aug 22, 2025
6cbb0a4
minor tweak to GitHub test
ssb22 Sep 3, 2025
22ffe68
player compatibility with Raspberry Pi OS 13
ssb22 Oct 24, 2025
335d61d
Gemini voices are rate-limited
ssb22 Oct 30, 2025
fbff96f
Piper voices: use archive URL (new URL not yet showing binaries) pend…
ssb22 Nov 1, 2025
862972d
PiperTTS updated deployment; Python 3 compatibility fix in mixed-part…
ssb22 Nov 4, 2025
1653747
fix another Python 3 incompatibility; fix regression in v0.996 that s…
ssb22 Nov 21, 2025
22e250c
improve readmes by copying more text from homepage (seeing as some pe…
ssb22 Nov 25, 2025
08f0ea3
support playing over BlueALSA
ssb22 Dec 13, 2025
17d16fa
support combining PulseAudio with direct ALSA
ssb22 Dec 15, 2025
de54556
add Chinese readme (from website)
ssb22 Jan 3, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
53 changes: 53 additions & 0 deletions .github/workflows/macos-test.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
name: macOS custom test
run-name: macOS custom test
on:
workflow_dispatch:
inputs:
samplesUrl:
description: 'samples zip URL (if any)'
vocabUrl:
description: 'vocab.txt URL (if any)'
progressUrl:
description: 'progress.txt URL (if any)'
L1:
description: 'first language'
default: 'en'
L2:
description: 'second language'
default: 'zh'
maxNew:
description: 'max new words'
default: 5
jobs:
Test-Run:
runs-on: macos-latest
steps:
- name: Install sound tools
run: brew install sox lame
- name: Check out repository
uses: actions/checkout@v4
- name: Set up input
run: |
set -e
cd ${{ github.workspace }}
make gradint.py || true # missing python2 not an issue
mv hanzi-prompts/*.txt samples/prompts/
if [ "${{ inputs.samplesUrl }}" ]; then curl -L "${{ inputs.samplesUrl }}" > samples.zip; cd samples ; unzip -o ../samples.zip ; cd .. ; fi
if [ "${{ inputs.vocabUrl }}" ] ; then curl -L "${{ inputs.vocabUrl }}" > vocab.txt ; fi
if [ "${{ inputs.progressUrl }}" ] ; then curl -L "${{ inputs.progressUrl }}" > progress.txt ; fi
echo firstLanguage = '"'${{ inputs.L1 }}'"' > settings.txt
echo secondLanguage = '"'${{ inputs.L2 }}'"' >> settings.txt
echo maxNewWords = ${{ inputs.maxNew }} >> advanced.txt
echo 'outputFile="lesson.mp3"' >> advanced.txt
- name: Make MP3
run: |
set -e
cd ${{ github.workspace }}
python3 gradint.py
mkdir out
mv progress.txt lesson.mp3 out/
- name: Upload output
uses: actions/upload-artifact@v4
with:
name: output
path: ${{ github.workspace }}/out/
2 changes: 2 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -1 +1,3 @@
*~
__pycache__
src/defaults.py
49 changes: 0 additions & 49 deletions INSTALL.txt

This file was deleted.

14 changes: 8 additions & 6 deletions Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@ EData := $(shell for N in $(Extra_Data); do if [ -e $$N ]; then echo $$N; fi; do
Common_Files=vocab.txt settings.txt advanced.txt samples $(EData)
Most_Mac_Files=$(Common_Files) gradint.py
Mac_Files=$(Most_Mac_Files) mac/start-gradint.app
Linux_Files=$(Common_Files) gradint.py INSTALL.txt
Linux_Files=$(Common_Files) gradint.py install.sh
Riscos_Files=$(Common_Files) gradint.py

CODE=src/lessonplan.py src/sequence.py src/loop.py src/booktime.py src/play.py src/synth.py src/makeevent.py src/filescan.py src/recording.py src/users.py
Expand Down Expand Up @@ -207,6 +207,7 @@ gradint.dmg: gradint-installer.command
gradint.bgz: $(Linux_Files)
mkdir gradint
cp -r $(Linux_Files) gradint
chmod +x gradint/install.sh
tar -c gradint/ | bzip2 -9 > gradint.bgz
rm -rf gradint

Expand All @@ -231,15 +232,15 @@ publish: $(All_Versions) gradint.py
cp samples/prompts/README.txt ~/homepage/public/gradint/prompts-readme.txt
grep ^program_name < src/top.py|head -1|sed -e 's/.*radint v/v/' -e 's/ .*/./' > ~/homepage/public/gradint/latest-version.txt
make clean
~/homepage/update
ssh st0rage "cd eGuidedog/ssb22/gradint; screen -d -m /bin/bash -c 'sleep 60;. build-sync.sh'"
make -C ~/homepage

gradint-build.7z:
mkdir /tmp/gradint-build00
cp -r * /tmp/gradint-build00
rm -r /tmp/gradint-build00/LICENSE /tmp/gradint-build00/README.md /tmp/gradint-build00/charlearn
mv /tmp/gradint-build00 gradint
cd gradint ; make clean ; rm -rf extras ; cd ..
make -C gradint clean
rm -rf gradint/extras
7za a gradint-build.7z gradint/
rm -rf gradint

Expand All @@ -266,6 +267,7 @@ CD: $(Mac_Files) gradint.zip
echo;echo;echo "Made CD directory. Can add gradint/samples, gradint/vocab.txt, gradint/espeak for Windows, gradint/espeak-.. for OSX, sox Win/Mac binaries, oggenc or whatever for Windows, etc."

cleanup:
rm -f `find . -type f -name '*~' -o -name '*.pyc' -o -name DEADJOE`
find . -type f '(' -name '*~' -o -name '*.pyc' -o -name DEADJOE ')' -exec rm -vf '{}' ';'
rm -rvf __pycache__ # must be separate from find, as some find implementations exec before trying to descend and then error
clean: cleanup
rm -f gradint.py $(All_Versions) src/defaults.py gradint-installer.command gradint.dmg
rm -rf gradint.py $(All_Versions) src/defaults.py gradint-installer.command gradint.dmg
66 changes: 66 additions & 0 deletions README-wrapper.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,66 @@
# Is gradint-wrapper.exe a virus?
From https://ssb22.user.srcf.net/gradint/gradint-wrapper.html
(also [mirrored on GitLab Pages](https://ssb22.gitlab.io/gradint/gradint-wrapper.html) just in case)

The genuine gradint-wrapper.exe is **not** a virus.

The Windows version of [Gradint](README.md) defaults to starting itself automatically once per day. This is because I’ve sometimes installed it for people who say they don’t know how to start programs (!) and/or want to be reminded about their daily vocabulary practice.

(When the simpler commercial “DuoLingo” app came on the scene later, their owl picture became famous for posting reminders some people found annoying. I was doing it first.)

Modern Windows laptops tend to hibernate rather than shut down. Therefore it’s no longer enough to put Gradint in the “Startup” folder—I also have to run a background process to make sure the “once per day” thing works.

## Does gradint-wrapper.exe slow the computer down?
It shouldn’t! The background process wakes up once per hour and checks to see if the computer has hibernated overnight in the meantime. If the computer is being slow then it must have other problems, such as:

1. Multiple anti-virus programs all scanning at once (an anti-virus program is no substitute for being careful and/or using a safer operating system, but if you must have one then consider if one is sufficient because the benefits of having more are rarely worth the cost in watching them “fight each other” over disk access),
2. Malware that is unknown to the anti-virus programs, and/or excessive amounts of “advertisement” software that was either pre-loaded by a shop or downloaded by a user who can’t tell the difference between advert-supported “free” and real free (try telling them to check for GPL, Apache or similar licenses, and/or verify the reputation of the publisher; don’t trust suggestions just because they seem to be from friends or the system),
3. Disk errors on very old hardware.

Sometimes it’s easier to replace Windows with a good GNU/Linux installation as long as the hardware is functioning.

## Why are there 3 or 4 instances of gradint-wrapper.exe?
There should normally be only one background instance, plus another if Gradint is currently open. When Gradint is launched from the desktop or start menu, it tries to stop the other instances and start its own, but on Vista and above this sometimes fails and multiple background processes can result. This is harmless as old ones should detect the situation next time they wake up (the code to do this has been improved in recent versions). It’s still occasionally possible for a user to launch two Gradint windows accidentally, but you should never see more than one automatically started.

## Is it safe to Terminate gradint-wrapper.exe?
Yes, this is safe. But it will start again next time you reboot or run Gradint.

## Is it safe to delete gradint-wrapper.exe?
That will break your Gradint installation. gradint-wrapper.exe is not just the background process: it is also the “wrapper” for loading the main part of Gradint on Windows (I use a 2-part loader to make the Windows version easier to update from GNU/Linux).

## How do you stop Gradint from running every day?
If you upgrade to Gradint v0.9979+ you can:

* set it at installation time (by answering No to the question “Do you want Gradint to start by itself and remind you to practise?” when first run);
* change it in the advanced settings (search for disable_once_per_day and set it to 1)

Alternatively, go to Start menu > All programs > Startup, right-click on “Run gradint once per day” and delete it. Gradint will still start the background process when you run it manually (I set that in case it fails to find the startup folder); if you want to stop this, go to Start menu > All programs > Gradint and/or desktop > Gradint, right-click on Gradint, open in Notepad, delete `once_per_day=2` and save.

## How do you uninstall Gradint?
Go to Start menu > All programs > Gradint > uninstall, or desktop > Gradint > uninstall. If it isn’t there, try re-downloading [the Gradint installer](https://ssb22.user.srcf.net/gradint/gradint.exe) and run it—it should replace the uninstall scripts which you can then use.

## Why is Gradint not in “Add/Remove Programs”?
To get into the “Add/Remove Programs” list, a program must be installed system-wide. Gradint does not install itself system-wide; it installs itself in your user name’s home folder (unless you have an ancient version of Windows that doesn’t have them). This means you can install Gradint even when you don’t have permission to install system-wide programs (such as in a computer lab), but it also means Gradint cannot use the “Add/Remove Programs” list.

## Why did some anti-virus labs flag Gradint as malicious in August 2020?
On 13th August 2020, some anti-virus labs I’d never heard of (AnyRun and VirusTotal, the latter citing Antiy-AVL, CrowdStrike Falcon, K7AntiVirus, Zillya, SecureAge APEX, Jiangmin and K7GW) incorrectly tagged the Gradint installer as a malicious trojan, and a company called Netcraft even sent a take-down notice to Cambridge University Information Services and the Student-Run Computing Facility hosting my website.

After I contacted AnyRun support asking for an appeal against the “verdict: malicious activity” they had published, they confirmed their technicians decided it was a “false positive” and made that report private to the submitter, but they were unable to relay a message to the submitter that they had done so.

I don’t know if this “detection” effort was anything to do with an incident that began the same day involving 200+ attempts from DigitalOcean-owned IP addresses to issue POST requests to gradint.exe (causing over a gigabyte of traffic), which I then blocked and reported to DigitalOcean. Since whoever it was continued to try (making another 700+ attempts over the next 5 days), we could just be looking at two separate issues that coincidentally started at about the same time. (My report to DigitalOcean was made after Cambridge University received the take-down notice, but before I had been told about it.)

I don’t yet know what it is about the Gradint installer that these “detectors” objected to, but I suspect it’s because the Gradint installer unpacks copies of certain free and open source software components that Gradint uses, namely, Python (with its standard libraries), eSpeak, LAME, MadPlay, PTTS and SoX. It seems that the authors of these “detectors” regarded any attempt to unpack another executable as suspicious, especially if it’s being done from an installer that is “unsigned” because I have not paid Microsoft’s extortionate fee to be a “recognised” publisher. I’m glad to say that this was not the case with the “big” anti-virus programs (the ones I’d heard of), which did not flag Gradint as malicious on that day.

I have asked Netcraft for an explanation of their take-down request and have not yet received any reply.

## Why is the Gradint installer not signed?
As I said on the Gradint download page, I have not paid Microsoft to make me a “known publisher” (I consider it a bit extortionate of them to require this payment even for small hobby projects)—if you make sure to fetch the installer from my own page and via HTTPS, that should be ‘signature’ enough. If you’re being really cautious then you are welcome to download the source code, install Python and all required dependencies yourself and run it that way; I simply packaged up an installer as a convenience to those Windows users who prefer a “one-click” setup, and I don’t see why I should have to pay Microsoft not to issue a warning—that seems wrong.

## Why did AnyRun say the Gradint installer uses Task Scheduler?
Some previous versions of Gradint used Task Scheduler for the “once per day” feature. The installer for the current version of Gradint contains one call to the Task Scheduler, but only to delete the task that those old versions left, if present.

## Why did AnyRun report Bitcoin addresses in Gradint?
There are no Bitcoin addresses in Gradint. AnyRun’s detector must have found a false positive.

## Why did AnyRun report Gradint using SearchProtocolHost.exe?
Again this appears to be a false positive. `SearchProtocolHost.exe` is a Microsoft component pre-installed on many versions of Windows that has frequently been known to misbehave, and it seems AnyRun’s detector misidentified it as being run by Gradint on that occasion.
Loading