feat(koplugin): support sync bookmarks between Koreader and Readest devices (#3580)
This commit is contained in:
@@ -45,38 +45,38 @@
|
||||
|
||||
<div align="left">✅ Implemented</div>
|
||||
|
||||
| **Feature** | **Description** | **Status** |
|
||||
| --------------------------------------- | ---------------------------------------------------------------------------------------------------------------------- | ---------- |
|
||||
| **Multi-Format Support** | Support EPUB, MOBI, KF8 (AZW3), FB2, CBZ, TXT, PDF | ✅ |
|
||||
| **Scroll/Page View Modes** | Switch between scrolling or paginated reading modes. | ✅ |
|
||||
| **Full-Text Search** | Search across the entire book to find relevant sections. | ✅ |
|
||||
| **Annotations and Highlighting** | Add highlights, bookmarks, and notes to enhance your reading experience and use instant mode for quicker interactions. | ✅ |
|
||||
| **Dictionary/Wikipedia Lookup** | Instantly look up words and terms when reading. | ✅ |
|
||||
| **[Parallel Read][link-parallel-read]** | Read two books or documents simultaneously in a split-screen view. | ✅ |
|
||||
| **Customize Font and Layout** | Adjust font, layout, theme mode, and theme colors for a personalized experience. | ✅ |
|
||||
| **Code Syntax Highlighting** | Read software manuals with rich coloring of code examples. | ✅ |
|
||||
| **File Association and Open With** | Quickly open files in Readest in your file browser with one-click. | ✅ |
|
||||
| **Library Management** | Organize, sort, and manage your entire ebook library. | ✅ |
|
||||
| **OPDS/Calibre Integration** | Integrate OPDS/Calibre to access online libraries and catalogs. | ✅ |
|
||||
| **Translate with DeepL and Yandex** | From a single sentence to the entire book—translate instantly. | ✅ |
|
||||
| **Text-to-Speech (TTS) Support** | Enjoy smooth, multilingual narration—even within a single book. | ✅ |
|
||||
| **Sync across Platforms** | Synchronize book files, reading progress, notes, and bookmarks across all supported platforms. | ✅ |
|
||||
| **Accessibility** | Provides full keyboard navigation and supports for screen readers such as VoiceOver, TalkBack, NVDA, and Orca. | ✅ |
|
||||
| **Visual & Focus Aids** | Reading ruler, paragraph-by-paragraph reading mode, and speed reading features. | ✅ |
|
||||
| **Feature** | **Description** | **Status** |
|
||||
| ------------------------------------------ | ---------------------------------------------------------------------------------------------------------------------- | ---------- |
|
||||
| **Multi-Format Support** | Support EPUB, MOBI, KF8 (AZW3), FB2, CBZ, TXT, PDF | ✅ |
|
||||
| **Scroll/Page View Modes** | Switch between scrolling or paginated reading modes. | ✅ |
|
||||
| **Full-Text Search** | Search across the entire book to find relevant sections. | ✅ |
|
||||
| **Annotations and Highlighting** | Add highlights, bookmarks, and notes to enhance your reading experience and use instant mode for quicker interactions. | ✅ |
|
||||
| **Dictionary/Wikipedia Lookup** | Instantly look up words and terms when reading. | ✅ |
|
||||
| **[Parallel Read][link-parallel-read]** | Read two books or documents simultaneously in a split-screen view. | ✅ |
|
||||
| **Customize Font and Layout** | Adjust font, layout, theme mode, and theme colors for a personalized experience. | ✅ |
|
||||
| **Code Syntax Highlighting** | Read software manuals with rich coloring of code examples. | ✅ |
|
||||
| **File Association and Open With** | Quickly open files in Readest in your file browser with one-click. | ✅ |
|
||||
| **Library Management** | Organize, sort, and manage your entire ebook library. | ✅ |
|
||||
| **OPDS/Calibre Integration** | Integrate OPDS/Calibre to access online libraries and catalogs. | ✅ |
|
||||
| **Translate with DeepL and Yandex** | From a single sentence to the entire book—translate instantly. | ✅ |
|
||||
| **Text-to-Speech (TTS) Support** | Enjoy smooth, multilingual narration—even within a single book. | ✅ |
|
||||
| **Sync across Platforms** | Synchronize book files, reading progress, notes, and bookmarks across all supported platforms. | ✅ |
|
||||
| [**Sync with Koreader**][link-kosync-wiki] | Synchronize reading progress, notes, and bookmarks with [Koreader][link-koreader] devices. | ✅ |
|
||||
| **Accessibility** | Provides full keyboard navigation and supports for screen readers such as VoiceOver, TalkBack, NVDA, and Orca. | ✅ |
|
||||
| **Visual & Focus Aids** | Reading ruler, paragraph-by-paragraph reading mode, and speed reading features. | ✅ |
|
||||
|
||||
## Planned Features
|
||||
|
||||
<div align="left">🛠 Building</div>
|
||||
<div align="left">🔄 Planned</div>
|
||||
|
||||
| **Feature** | **Description** | **Priority** |
|
||||
| ------------------------------------------ | ------------------------------------------------------------------------------------------ | ------------ |
|
||||
| [**Sync with Koreader**][link-kosync-wiki] | Synchronize reading progress, notes, and bookmarks with [Koreader][link-koreader] devices. | 🛠 |
|
||||
| **AI-Powered Summarization** | Generate summaries of books or chapters using AI for quick insights. | 🛠 |
|
||||
| **Advanced Reading Stats** | Track reading time, pages read, and more for detailed insights. | 🛠 |
|
||||
| **Audiobook Support** | Extend functionality to play and manage audiobooks. | 🔄 |
|
||||
| **Handwriting Annotations** | Add support for handwriting annotations using a pen on compatible devices. | 🔄 |
|
||||
| **In-Library Full-Text Search** | Search across your entire ebook library to find topics and quotes. | 🔄 |
|
||||
| **Feature** | **Description** | **Priority** |
|
||||
| ------------------------------- | -------------------------------------------------------------------------- | ------------ |
|
||||
| **AI-Powered Summarization** | Generate summaries of books or chapters using AI for quick insights. | 🛠 |
|
||||
| **Advanced Reading Stats** | Track reading time, pages read, and more for detailed insights. | 🛠 |
|
||||
| **Audiobook Support** | Extend functionality to play and manage audiobooks. | 🔄 |
|
||||
| **Handwriting Annotations** | Add support for handwriting annotations using a pen on compatible devices. | 🔄 |
|
||||
| **In-Library Full-Text Search** | Search across your entire ebook library to find topics and quotes. | 🔄 |
|
||||
|
||||
Stay tuned for continuous improvements and updates! Contributions and suggestions are always welcome—let's build the ultimate reading experience together. 😊
|
||||
|
||||
|
||||
@@ -60,18 +60,18 @@ function SyncAnnotations:getAnnotations(ui, settings, book_hash, meta_hash)
|
||||
|
||||
local notes = {}
|
||||
for _, item in ipairs(annotations) do
|
||||
local updated_at = self:parseDatetimeToMs(item.datetime_updated or item.datetime)
|
||||
if updated_at <= last_sync then
|
||||
goto skip
|
||||
end
|
||||
|
||||
local pos0 = item.pos0
|
||||
local pos1 = item.pos1
|
||||
if type(pos0) == "table" then pos0 = nil end
|
||||
if type(pos1) == "table" then pos1 = nil end
|
||||
if pos0 then
|
||||
local updated_at = self:parseDatetimeToMs(item.datetime_updated or item.datetime)
|
||||
if updated_at <= last_sync then
|
||||
goto skip
|
||||
end
|
||||
|
||||
local note_type = item.drawer and "annotation" or "bookmark"
|
||||
local id = self:generateNoteId(book_hash, note_type, tostring(pos0), pos1 and tostring(pos1))
|
||||
if item.drawer and pos0 then
|
||||
-- Annotation (highlight/underline/strikeout): has drawer and pos0/pos1
|
||||
local style = "highlight"
|
||||
if item.drawer == "underscore" then
|
||||
style = "underline"
|
||||
@@ -79,23 +79,38 @@ function SyncAnnotations:getAnnotations(ui, settings, book_hash, meta_hash)
|
||||
style = "squiggly"
|
||||
end
|
||||
|
||||
local note = {
|
||||
local id = self:generateNoteId(book_hash, "annotation", tostring(pos0), pos1 and tostring(pos1))
|
||||
table.insert(notes, {
|
||||
bookHash = book_hash,
|
||||
metaHash = meta_hash,
|
||||
id = id,
|
||||
type = note_type,
|
||||
type = "annotation",
|
||||
xpointer0 = tostring(pos0),
|
||||
xpointer1 = pos1 and tostring(pos1) or nil,
|
||||
text = item.text or "",
|
||||
note = item.note or "",
|
||||
style = note_type == "annotation" and style or nil,
|
||||
color = note_type == "annotation" and KO_TO_READEST_COLOR[item.color or "yellow"] or nil,
|
||||
style = style,
|
||||
color = KO_TO_READEST_COLOR[item.color or "yellow"],
|
||||
page = item.pageno,
|
||||
createdAt = self:parseDatetimeToMs(item.datetime),
|
||||
updatedAt = updated_at,
|
||||
}
|
||||
|
||||
table.insert(notes, note)
|
||||
})
|
||||
elseif not item.drawer and type(item.page) == "string" then
|
||||
-- Bookmark: no drawer, position in page field (xpointer string)
|
||||
local page_xp = item.page
|
||||
local id = self:generateNoteId(book_hash, "bookmark", page_xp)
|
||||
table.insert(notes, {
|
||||
bookHash = book_hash,
|
||||
metaHash = meta_hash,
|
||||
id = id,
|
||||
type = "bookmark",
|
||||
xpointer0 = page_xp,
|
||||
text = item.text or "",
|
||||
note = item.note or "",
|
||||
page = item.pageno,
|
||||
createdAt = self:parseDatetimeToMs(item.datetime),
|
||||
updatedAt = updated_at,
|
||||
})
|
||||
end
|
||||
::skip::
|
||||
end
|
||||
@@ -208,10 +223,16 @@ function SyncAnnotations:pull(ui, settings, client, book_hash, meta_hash, dialog
|
||||
local annotation_mgr = ui.annotation
|
||||
if not annotation_mgr then return end
|
||||
|
||||
local existing_positions = {}
|
||||
-- Build dedup sets: annotations by pos0|pos1, bookmarks by page xpointer
|
||||
local existing_annotations = {}
|
||||
local existing_bookmarks = {}
|
||||
for _, item in ipairs(annotation_mgr.annotations) do
|
||||
local key = tostring(item.pos0) .. "|" .. tostring(item.pos1 or "")
|
||||
existing_positions[key] = true
|
||||
if item.drawer then
|
||||
local key = tostring(item.pos0) .. "|" .. tostring(item.pos1 or "")
|
||||
existing_annotations[key] = true
|
||||
elseif type(item.page) == "string" then
|
||||
existing_bookmarks[item.page] = true
|
||||
end
|
||||
end
|
||||
|
||||
local added = 0
|
||||
@@ -221,37 +242,51 @@ function SyncAnnotations:pull(ui, settings, client, book_hash, meta_hash, dialog
|
||||
end
|
||||
|
||||
local xp0 = note.xpointer0
|
||||
local xp1 = note.xpointer1
|
||||
if not xp0 then goto continue end
|
||||
|
||||
local key = xp0 .. "|" .. (xp1 or "")
|
||||
if existing_positions[key] then goto continue end
|
||||
|
||||
local drawer = "lighten"
|
||||
local note_type = note.type
|
||||
local item
|
||||
|
||||
if note_type == "bookmark" then
|
||||
drawer = nil
|
||||
elseif note.style == "underline" then
|
||||
drawer = "underscore"
|
||||
elseif note.style == "squiggly" then
|
||||
drawer = "strikeout"
|
||||
if existing_bookmarks[xp0] then goto continue end
|
||||
|
||||
item = {
|
||||
page = xp0,
|
||||
text = note.text or "",
|
||||
note = note.note or "",
|
||||
pageno = note.page,
|
||||
datetime = os.date("%Y-%m-%d %H:%M:%S"),
|
||||
}
|
||||
existing_bookmarks[xp0] = true
|
||||
else
|
||||
local xp1 = note.xpointer1
|
||||
local key = xp0 .. "|" .. (xp1 or "")
|
||||
if existing_annotations[key] then goto continue end
|
||||
|
||||
local drawer = "lighten"
|
||||
if note.style == "underline" then
|
||||
drawer = "underscore"
|
||||
elseif note.style == "squiggly" then
|
||||
drawer = "strikeout"
|
||||
end
|
||||
|
||||
item = {
|
||||
pos0 = xp0,
|
||||
pos1 = xp1 or xp0,
|
||||
page = xp0,
|
||||
text = note.text or "",
|
||||
note = note.note or "",
|
||||
drawer = drawer,
|
||||
color = READEST_TO_KO_COLOR[note.color] or "yellow",
|
||||
pageno = note.page,
|
||||
datetime = os.date("%Y-%m-%d %H:%M:%S"),
|
||||
}
|
||||
existing_annotations[key] = true
|
||||
end
|
||||
|
||||
local item = {
|
||||
pos0 = xp0,
|
||||
pos1 = xp1 or xp0,
|
||||
page = xp0,
|
||||
text = note.text or "",
|
||||
note = note.note or "",
|
||||
drawer = drawer,
|
||||
color = READEST_TO_KO_COLOR[note.color] or "yellow",
|
||||
pageno = note.page,
|
||||
datetime = os.date("%Y-%m-%d %H:%M:%S"),
|
||||
}
|
||||
local index = annotation_mgr:addItem(item)
|
||||
ui:handleEvent(Event:new("AnnotationsModified", { item, index_modified = index }))
|
||||
logger.dbg("ReadestSync: Added annotation from sync:", item)
|
||||
existing_positions[key] = true
|
||||
added = added + 1
|
||||
|
||||
::continue::
|
||||
|
||||
Reference in New Issue
Block a user