Initial commit.
This commit is contained in:
@@ -0,0 +1,174 @@
|
||||
#!/usr/bin/env python3
|
||||
# -*- coding: utf-8 -*-
|
||||
"""
|
||||
Bookmark Manager
|
||||
|
||||
Manages reading positions for books using SQLite for persistence.
|
||||
Tracks chapter, paragraph, and sentence positions.
|
||||
"""
|
||||
|
||||
import sqlite3
|
||||
import hashlib
|
||||
from pathlib import Path
|
||||
from datetime import datetime
|
||||
|
||||
|
||||
class BookmarkManager:
|
||||
"""Manages bookmarks for books"""
|
||||
|
||||
def __init__(self, dbPath=None):
|
||||
"""
|
||||
Initialize bookmark manager
|
||||
|
||||
Args:
|
||||
dbPath: Path to SQLite database (default: ~/.bookstorm/bookmarks.db)
|
||||
"""
|
||||
if dbPath is None:
|
||||
homePath = Path.home()
|
||||
bookstormDir = homePath / ".bookstorm"
|
||||
bookstormDir.mkdir(exist_ok=True)
|
||||
dbPath = bookstormDir / "bookmarks.db"
|
||||
|
||||
self.dbPath = dbPath
|
||||
self._init_db()
|
||||
|
||||
def _init_db(self):
|
||||
"""Initialize database schema"""
|
||||
conn = sqlite3.connect(self.dbPath)
|
||||
cursor = conn.cursor()
|
||||
|
||||
cursor.execute('''
|
||||
CREATE TABLE IF NOT EXISTS bookmarks (
|
||||
book_id TEXT PRIMARY KEY,
|
||||
book_path TEXT NOT NULL,
|
||||
book_title TEXT,
|
||||
chapter_index INTEGER NOT NULL DEFAULT 0,
|
||||
paragraph_index INTEGER NOT NULL DEFAULT 0,
|
||||
sentence_index INTEGER NOT NULL DEFAULT 0,
|
||||
last_accessed TEXT,
|
||||
created_at TEXT
|
||||
)
|
||||
''')
|
||||
|
||||
conn.commit()
|
||||
conn.close()
|
||||
|
||||
def _get_book_id(self, bookPath):
|
||||
"""Generate unique book ID from file path"""
|
||||
bookPath = str(Path(bookPath).resolve())
|
||||
return hashlib.sha256(bookPath.encode()).hexdigest()[:16]
|
||||
|
||||
def save_bookmark(self, bookPath, bookTitle, chapterIndex, paragraphIndex, sentenceIndex=0):
|
||||
"""
|
||||
Save bookmark for a book
|
||||
|
||||
Args:
|
||||
bookPath: Path to book file
|
||||
bookTitle: Title of the book
|
||||
chapterIndex: Current chapter index
|
||||
paragraphIndex: Current paragraph index
|
||||
sentenceIndex: Current sentence index (default: 0)
|
||||
"""
|
||||
bookId = self._get_book_id(bookPath)
|
||||
timestamp = datetime.now().isoformat()
|
||||
|
||||
conn = sqlite3.connect(self.dbPath)
|
||||
cursor = conn.cursor()
|
||||
|
||||
cursor.execute('''
|
||||
INSERT OR REPLACE INTO bookmarks
|
||||
(book_id, book_path, book_title, chapter_index, paragraph_index,
|
||||
sentence_index, last_accessed, created_at)
|
||||
VALUES (?, ?, ?, ?, ?, ?, ?,
|
||||
COALESCE((SELECT created_at FROM bookmarks WHERE book_id = ?), ?))
|
||||
''', (bookId, str(bookPath), bookTitle, chapterIndex, paragraphIndex,
|
||||
sentenceIndex, timestamp, bookId, timestamp))
|
||||
|
||||
conn.commit()
|
||||
conn.close()
|
||||
|
||||
def get_bookmark(self, bookPath):
|
||||
"""
|
||||
Get bookmark for a book
|
||||
|
||||
Args:
|
||||
bookPath: Path to book file
|
||||
|
||||
Returns:
|
||||
Dictionary with bookmark data or None if not found
|
||||
"""
|
||||
bookId = self._get_book_id(bookPath)
|
||||
|
||||
conn = sqlite3.connect(self.dbPath)
|
||||
cursor = conn.cursor()
|
||||
|
||||
cursor.execute('''
|
||||
SELECT chapter_index, paragraph_index, sentence_index,
|
||||
book_title, last_accessed
|
||||
FROM bookmarks
|
||||
WHERE book_id = ?
|
||||
''', (bookId,))
|
||||
|
||||
row = cursor.fetchone()
|
||||
conn.close()
|
||||
|
||||
if row:
|
||||
return {
|
||||
'chapterIndex': row[0],
|
||||
'paragraphIndex': row[1],
|
||||
'sentenceIndex': row[2],
|
||||
'bookTitle': row[3],
|
||||
'lastAccessed': row[4]
|
||||
}
|
||||
|
||||
return None
|
||||
|
||||
def delete_bookmark(self, bookPath):
|
||||
"""
|
||||
Delete bookmark for a book
|
||||
|
||||
Args:
|
||||
bookPath: Path to book file
|
||||
"""
|
||||
bookId = self._get_book_id(bookPath)
|
||||
|
||||
conn = sqlite3.connect(self.dbPath)
|
||||
cursor = conn.cursor()
|
||||
|
||||
cursor.execute('DELETE FROM bookmarks WHERE book_id = ?', (bookId,))
|
||||
|
||||
conn.commit()
|
||||
conn.close()
|
||||
|
||||
def list_bookmarks(self):
|
||||
"""
|
||||
List all bookmarks
|
||||
|
||||
Returns:
|
||||
List of dictionaries with bookmark data
|
||||
"""
|
||||
conn = sqlite3.connect(self.dbPath)
|
||||
cursor = conn.cursor()
|
||||
|
||||
cursor.execute('''
|
||||
SELECT book_path, book_title, chapter_index, paragraph_index,
|
||||
sentence_index, last_accessed
|
||||
FROM bookmarks
|
||||
ORDER BY last_accessed DESC
|
||||
''')
|
||||
|
||||
rows = cursor.fetchall()
|
||||
conn.close()
|
||||
|
||||
bookmarks = []
|
||||
for row in rows:
|
||||
bookmarks.append({
|
||||
'bookPath': row[0],
|
||||
'bookTitle': row[1],
|
||||
'chapterIndex': row[2],
|
||||
'paragraphIndex': row[3],
|
||||
'sentenceIndex': row[4],
|
||||
'lastAccessed': row[5]
|
||||
})
|
||||
|
||||
return bookmarks
|
||||
Reference in New Issue
Block a user