feat: add reader infrastructure - Phase 0 database schema and queries
Implement Phase 0 prerequisites for reader functionality including database schema, SQL queries, and frontend dependencies. ## Database Schema (5 New Tables + 1 Column Addition) ### New Tables Added: 1. **panel_data** - Comic/manga panel detection results - Stores detected panel boundaries (x, y, width, height) - Supports grid, ML, and manual detection methods - JSONB storage for flexible panel structures 2. **reading_speed** - User reading speed statistics - Tracks pages per minute and total reading time - Per-user per-media-item tracking - Enables progress estimation and analytics 3. **dictionary_cache** - Offline dictionary word definitions - Caches external dictionary lookups - Reduces API calls and improves performance - Supports offline reading functionality 4. **reader_settings** - User reader preferences (per-user) - Stores typography, theme, and display settings - JSONB storage for flexible configuration - Per-user customization (fonts, margins, themes) 5. **media_bookmarks** - Enhanced bookmarks with chapter/CFI support - Unified bookmarking for ebooks, comics, manga, PDFs - Supports page_number, chapter_number, and epubcfi_position - Includes notes field for annotations - Unique constraint on (media_item_id, user_id, title) ### Column Addition: - **media_items.chapter_metadata** (JSONB) - Caches detected chapter structure - Stores TOC/chapter detection results - Prevents re-parsing files on every read - Populated by ReaderService.DetectChapters() ## Database Queries (12 New Queries) Added queries for all reader functionality: - Panel data: GetPanelData, UpsertPanelData - Reading speed: GetReadingSpeed, CreateReadingSpeed, UpdateReadingSpeed - Dictionary: GetDictionaryEntry, CreateDictionaryEntry, UpdateDictionaryAccessed - Settings: GetReaderSettings, UpsertReaderSettings - Bookmarks: GetMediaBookmarks, CreateMediaBookmark, DeleteMediaBookmark, UpdateMediaBookmark ## Frontend Dependencies Added to package.json: - jszip@^3.10.1 - EPUB/comic archive parsing (client-side) - pdfjs-dist@^3.11.174 - PDF rendering library (Mozilla PDF.js) ## Generated Code Ran `sqlc generate` to regenerate: - models.go - Go structs for new tables (55 lines added) - querier.go - Database query methods (14 lines added) - queries.sql.go - Compiled SQL queries (504 lines added) ## Implementation Status Phase 0 prerequisites now complete: ✅ Database schema (5 tables + 1 column) ✅ SQL queries (12 queries) ✅ Frontend dependencies (2 packages) ✅ Generated Go code (sqlc) ✅ Database recreated with new schema Ready for Phase 1: Infrastructure & Basic Reader implementation. Related to: Universal web reader for ebooks, comics, manga, PDFs
This commit is contained in:
@@ -1924,3 +1924,89 @@ RETURNING *;
|
||||
DELETE FROM saved_filters
|
||||
WHERE id = @id AND user_id = @user_id
|
||||
RETURNING *;
|
||||
|
||||
-- name: GetPanelData :one
|
||||
SELECT * FROM panel_data
|
||||
WHERE media_item_id = $1 AND page_number = $2;
|
||||
|
||||
-- name: UpsertPanelData :one
|
||||
INSERT INTO panel_data (media_item_id, page_number, detection_method, panels)
|
||||
VALUES ($1, $2, $3, $4)
|
||||
ON CONFLICT (media_item_id, page_number)
|
||||
DO UPDATE SET
|
||||
detection_method = EXCLUDED.detection_method,
|
||||
panels = EXCLUDED.panels,
|
||||
updated_at = NOW()
|
||||
RETURNING *;
|
||||
|
||||
-- name: GetReadingSpeed :one
|
||||
SELECT * FROM reading_speed
|
||||
WHERE user_id = $1 AND media_item_id = $2;
|
||||
|
||||
-- name: CreateReadingSpeed :one
|
||||
INSERT INTO reading_speed (user_id, media_item_id, pages_per_minute, pages_read, total_reading_minutes, last_read_at)
|
||||
VALUES ($1, $2, $3, $4, $5, $6)
|
||||
RETURNING *;
|
||||
|
||||
-- name: UpdateReadingSpeed :one
|
||||
UPDATE reading_speed
|
||||
SET
|
||||
pages_per_minute = $3,
|
||||
pages_read = pages_read + $4,
|
||||
total_reading_minutes = total_reading_minutes + $5,
|
||||
last_read_at = $6,
|
||||
updated_at = NOW()
|
||||
WHERE user_id = $1 AND media_item_id = $2
|
||||
RETURNING *;
|
||||
|
||||
-- name: GetDictionaryEntry :one
|
||||
SELECT * FROM dictionary_cache
|
||||
WHERE word = $1;
|
||||
|
||||
-- name: CreateDictionaryEntry :one
|
||||
INSERT INTO dictionary_cache (word, definition, part_of_speech, example, etymology, accessed_at)
|
||||
VALUES ($1, $2, $3, $4, $5, NOW())
|
||||
RETURNING *;
|
||||
|
||||
-- name: UpdateDictionaryAccessed :one
|
||||
UPDATE dictionary_cache
|
||||
SET accessed_at = NOW()
|
||||
WHERE word = $1
|
||||
RETURNING *;
|
||||
|
||||
-- name: GetReaderSettings :one
|
||||
SELECT setting_value FROM reader_settings
|
||||
WHERE user_id = $1 AND setting_key = 'reader_settings';
|
||||
|
||||
-- name: UpsertReaderSettings :one
|
||||
INSERT INTO reader_settings (user_id, setting_key, setting_value)
|
||||
VALUES ($1, 'reader_settings', $2)
|
||||
ON CONFLICT (user_id, setting_key)
|
||||
DO UPDATE SET
|
||||
setting_value = EXCLUDED.setting_value,
|
||||
updated_at = NOW()
|
||||
RETURNING *;
|
||||
|
||||
-- name: GetMediaBookmarks :many
|
||||
SELECT * FROM media_bookmarks
|
||||
WHERE media_item_id = $1 AND user_id = $2
|
||||
ORDER BY created_at DESC;
|
||||
|
||||
-- name: CreateMediaBookmark :one
|
||||
INSERT INTO media_bookmarks (media_item_id, user_id, page_number, chapter_number, cfi_position, title, position, notes)
|
||||
VALUES ($1, $2, $3, $4, $5, $6, $7, $8)
|
||||
RETURNING *;
|
||||
|
||||
-- name: DeleteMediaBookmark :exec
|
||||
DELETE FROM media_bookmarks
|
||||
WHERE id = $1;
|
||||
|
||||
-- name: UpdateMediaBookmark :one
|
||||
UPDATE media_bookmarks
|
||||
SET
|
||||
title = $2,
|
||||
notes = $3,
|
||||
position = $4,
|
||||
updated_at = NOW()
|
||||
WHERE id = $1 AND user_id = $5
|
||||
RETURNING *;
|
||||
|
||||
Reference in New Issue
Block a user