diff --git a/scraper/internal/server/ui.go b/scraper/internal/server/ui.go index 60615e7..322c598 100644 --- a/scraper/internal/server/ui.go +++ b/scraper/internal/server/ui.go @@ -179,34 +179,79 @@ func (s *Server) respond(w http.ResponseWriter, r *http.Request, title, fragment // ─── GET / — book catalogue ─────────────────────────────────────────────────── const homeTmpl = ` -
-
+ + +
+ + + -

{{len .Books}} book{{if ne (len .Books) 1}}s{{end}} on disk

- + + +

{{len .Books}} book{{if ne (len .Books) 1}}s{{end}} on disk

+ + + + + - -
- - + + - + +
+
+ +
+ +
+ + + + +
+ + + +
+ +
-

Available

-
+

All books

+
{{range .Books}} -
+ data-genres="{{range .Genres}}{{.}}|{{end}}" + class="book-card group block rounded-xl border border-zinc-800 bg-zinc-900 p-4 hover:border-amber-500 transition-colors cursor-pointer min-w-0 overflow-hidden"> +
{{if .Cover}} - cover + cover {{end}} -
-

{{.Title}}

- {{if .Author}}

{{.Author}}

{{end}} -
- {{if .Status}}{{.Status}}{{end}} - {{if .TotalChapters}}{{.TotalChapters}} ch{{end}} - {{if .Downloaded}}{{.Downloaded}} downloaded{{end}} +
+

{{.Title}}

+ {{if .Author}}

{{.Author}}

{{end}} + + +
+ {{if .Status}}{{.Status}}{{end}} + {{if .TotalChapters}}{{.TotalChapters}} ch{{end}} + {{if .Downloaded}}{{.Downloaded}} dl{{end}} +
@@ -240,118 +299,241 @@ const homeTmpl = ` ` -// homeBookItem wraps BookMeta with the count of chapters already on disk. +// homeBookItem wraps BookMeta with the count of chapters already on disk +// and the Unix timestamp of when the book was added (metadata.yaml mtime). type homeBookItem struct { scraper.BookMeta Downloaded int + AddedAt int64 } func (s *Server) handleHome(w http.ResponseWriter, r *http.Request) { @@ -387,6 +639,7 @@ func (s *Server) handleHome(w http.ResponseWriter, r *http.Request) { items[i] = homeBookItem{ BookMeta: b, Downloaded: s.writer.CountChapters(b.Slug), + AddedAt: s.writer.MetadataMtime(b.Slug), } } @@ -2195,6 +2448,9 @@ const chapterTmpl = ` var p = JSON.parse(localStorage.getItem('reading_progress') || '{}'); p[SLUG] = CHAPTER_N; localStorage.setItem('reading_progress', JSON.stringify(p)); + var ts = JSON.parse(localStorage.getItem('reading_progress_ts') || '{}'); + ts[SLUG] = Date.now(); + localStorage.setItem('reading_progress_ts', JSON.stringify(ts)); } catch(_) {} })(); diff --git a/scraper/internal/writer/writer.go b/scraper/internal/writer/writer.go index fdd9ee4..c6dc898 100644 --- a/scraper/internal/writer/writer.go +++ b/scraper/internal/writer/writer.go @@ -85,6 +85,17 @@ func (w *Writer) ReadMetadata(slug string) (scraper.BookMeta, bool, error) { return meta, true, nil } +// MetadataMtime returns the modification time (Unix seconds) of the +// metadata.yaml file for slug, or 0 if the file cannot be stat'd. +func (w *Writer) MetadataMtime(slug string) int64 { + path := filepath.Join(w.bookDir(slug), "metadata.yaml") + fi, err := os.Stat(path) + if err != nil { + return 0 + } + return fi.ModTime().Unix() +} + // ─── Chapters ───────────────────────────────────────────────────────────────── // ChapterExists returns true if the markdown file for ref already exists on disk.