Initial commit: ReadLater v1.0

- Save articles via URL or bookmarklet
- Clean dark reader with customizable fonts/sizing
- Text-to-speech with browser + Kokoro support
- Speed control up to 3x
- Favorites and archive
- SQLite database with Drizzle ORM
- Docker deployment ready

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
Gemini Agent
2026-01-17 07:35:07 +00:00
commit 27963af055
45 changed files with 11298 additions and 0 deletions

24
src/lib/db/schema.ts Normal file
View File

@@ -0,0 +1,24 @@
import { sqliteTable, text, integer } from "drizzle-orm/sqlite-core";
export const articles = sqliteTable("articles", {
id: text("id").primaryKey(),
url: text("url").notNull(),
title: text("title").notNull(),
author: text("author"),
siteName: text("site_name"),
excerpt: text("excerpt"),
content: text("content").notNull(), // HTML content
textContent: text("text_content").notNull(), // Plain text for TTS
leadImage: text("lead_image"),
wordCount: integer("word_count").default(0),
readingProgress: integer("reading_progress").default(0), // 0-100
isFavorite: integer("is_favorite", { mode: "boolean" }).default(false),
isArchived: integer("is_archived", { mode: "boolean" }).default(false),
tags: text("tags").default("[]"), // JSON array of tags
createdAt: integer("created_at", { mode: "timestamp" }).$defaultFn(() => new Date()),
updatedAt: integer("updated_at", { mode: "timestamp" }).$defaultFn(() => new Date()),
readAt: integer("read_at", { mode: "timestamp" }),
});
export type Article = typeof articles.$inferSelect;
export type NewArticle = typeof articles.$inferInsert;