Recently Written · git

sbm-sync

Sync server for sbm bookmark files: one small Go program, plain files, AGPL

git clone https://github.com/equwal/sbm-sync

Log | Files | Refs


commit 5b66cf8c8a7f3588bf2025693aa2f2a826f73b39
equwal <truex@equwal.com>
2026-09-26 12:42:53 -0700

Link the other sites and apps of the author

The footer of each page lists the other sites and apps. The daily digest ends with one line about SubRead.

 feedjob.go      |  3 ++-
 feedjob_test.go |  2 +-
 pages.html      | 26 ++++++++++++++++++++++++++
 server_test.go  | 17 +++++++++++++++++
 4 files changed, 46 insertions(+), 2 deletions(-)
diff --git a/feedjob.go b/feedjob.go
index 075ad30..985d758 100644
--- a/feedjob.go
+++ b/feedjob.go
@@ -423,7 +423,8 @@ func (s *server) digest(a Account, dir string, feeds []Feed) error {
 		subject = "sbm feed: 1 new item"
 	}
 	body = strings.TrimRight(body, "\n") + "\n\nYour feed: " + s.site + "/feed\n" +
-		"To stop these emails, turn off the daily digest in the settings of that page.\n"
+		"To stop these emails, turn off the daily digest in the settings of that page.\n\n" +
+		"Also from the author of sbm: SubRead, read along with an audiobook: https://subread.space/\n"
 	if err := s.mail(a.Email, subject, body); err != nil {
 		return err
 	}
diff --git a/feedjob_test.go b/feedjob_test.go
index 558380c..fd11bf4 100644
--- a/feedjob_test.go
+++ b/feedjob_test.go
@@ -169,7 +169,7 @@ func TestJobSendsADailyDigest(t *testing.T) {
 		t.Fatalf("%d emails after a day", e.sent())
 	}
 	mail := e.mails[0]
-	for _, want := range []string{"me@example.org\nsbm feed: 1 new item\n", "Alpha:\n  Two  https://a.org/2\n", "Your feed: " + e.s.site + "/feed\n"} {
+	for _, want := range []string{"me@example.org\nsbm feed: 1 new item\n", "Alpha:\n  Two  https://a.org/2\n", "Your feed: " + e.s.site + "/feed\n", "https://subread.space/\n"} {
 		if !strings.Contains(mail, want) {
 			t.Errorf("the digest lacks %q:\n%s", want, mail)
 		}
diff --git a/pages.html b/pages.html
index d90a126..557951b 100644
--- a/pages.html
+++ b/pages.html
@@ -42,6 +42,32 @@ details { margin: 1em 0; } summary { cursor: pointer; }
 <a href="/privacy">Privacy</a> ·
 <a href="/terms">Terms of sale</a> ·
 <a href="https://ko-fi.com/truex">Support sbm on Ko-fi</a>
+<nav aria-label="More sites and apps">
+<p>More sites and apps:
+<a href="https://subread.space/" title="Read along with an audiobook.">SubRead</a> ·
+<a href="https://booksimulator.com/" title="A reading room for Aozora Bunko and Project Gutenberg books.">Book Simulator</a> ·
+<a href="https://honjimaku.com/" title="Subtitles for Japanese audiobooks.">honjimaku.com</a> ·
+<a href="https://dickt.store/" title="Language-learning tools, flashcards and web toys.">dickt.store</a> ·
+<a href="https://hentaibun.online/" title="Learn kanbun and kobun.">hentaibun.online</a> ·
+<a href="https://mowimypopol.online/" title="Archival study materials for Polish.">mowimypopol.online</a> ·
+<a href="https://alljapanesealltheti.me/" title="All Japanese All The Time.">AJATT mirror</a> ·
+<a href="https://recentlywritten.com/" title="The blog.">Recently Written</a></p>
+<p>Apps:
+<a href="https://github.com/equwal/sbm-android/releases/latest">sbm for Android</a> ·
+<a href="https://github.com/equwal/sbm-extension/releases/latest">sbm add-on</a> ·
+<a href="https://github.com/equwal/subread-android/releases/latest">SubRead for Android</a> ·
+<a href="https://github.com/equwal/subread-overlay/releases/latest">SubRead Overlay</a> ·
+<a href="https://github.com/equwal/subread-dictionary/releases/latest">SubRead Dictionary</a> ·
+<a href="https://github.com/equwal/subread-anki">SubRead Anki</a> ·
+<a href="https://github.com/equwal/subread-extension/releases/latest">SubRead for YouTube</a> ·
+<a href="https://github.com/equwal/subread.koplugin">SubRead for KOReader</a> ·
+<a href="https://github.com/equwal/subrep-android/releases/latest">Subrep</a> ·
+<a href="https://github.com/equwal/rebind/releases">Rebind</a> ·
+<a href="https://github.com/equwal/ink-recents/releases/latest">Ink Recents</a> ·
+<a href="https://github.com/equwal/ink-dim/releases/latest">Ink Dim</a> ·
+<a href="https://github.com/equwal/ink-update/releases/latest">Ink Update</a> ·
+<a href="https://recentlywritten.com/projects.html">All projects</a></p>
+</nav>
 </footer>
 </body>
 </html>
diff --git a/server_test.go b/server_test.go
index be1ea31..44830fd 100644
--- a/server_test.go
+++ b/server_test.go
@@ -567,6 +567,23 @@ func TestHomePrivacy(t *testing.T) {
 	}
 }
 
+// Each page links the other sites and apps of the author, but not sbm Sync
+// itself.
+func TestFooterLinksTheOtherProjects(t *testing.T) {
+	e := newEnv(t, false)
+	for _, path := range []string{"/", "/privacy", "/terms", "/login"} {
+		page := e.body(http.DefaultClient, path)
+		for _, want := range []string{`href="https://subread.space/"`, `href="https://booksimulator.com/"`, `href="https://github.com/equwal/sbm-android/releases/latest"`, `href="https://recentlywritten.com/projects.html"`} {
+			if !strings.Contains(page, want) {
+				t.Errorf("%s lacks %s", path, want)
+			}
+		}
+		if strings.Contains(page, `href="https://sbmsync.com/"`) {
+			t.Errorf("%s links sbm Sync itself", path)
+		}
+	}
+}
+
 // api sends a request with the token of a device, as the add-on does, and
 // gives the status and the body of the answer.
 func (e *harness) api(method, token, path string, form url.Values) (int, string) {