Skip to content

Commit 711b891

Browse files
committed
Merge branch 'develop' into daisy
2 parents 3ac8346 + c18c405 commit 711b891

File tree

3 files changed

+76
-1
lines changed

3 files changed

+76
-1
lines changed

bookworm/gui/book_viewer/menu_constants.py

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -45,6 +45,9 @@ class ViewerMenuIds(enum.IntEnum):
4545
about = next(ID_GEN)
4646
clear_documents_cache = next(ID_GEN)
4747

48+
class ImportMenuIds(enum.IntEnum):
49+
"""Ids for the import submenu"""
50+
qread = next(ID_GEN)
4851

4952
FOCUS_TABLE_OF_CONTENTS = next(ID_GEN)
5053

bookworm/gui/book_viewer/menubar.py

Lines changed: 36 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@
1515
import wx
1616
from slugify import slugify
1717

18-
from bookworm import app, config, ocr, paths, speech
18+
from bookworm import app, config, ocr, paths, qread, speech
1919
from bookworm.commandline_handler import run_subcommand_in_a_new_process
2020
from bookworm.concurrency import call_threaded, process_worker
2121
from bookworm.document import READING_MODE_LABELS
@@ -89,12 +89,23 @@ def create(self):
8989
self.pinnedDocumentsMenu = wx.Menu()
9090
# A submenu for recent documents
9191
self.recentFilesMenu = wx.Menu()
92+
# a submenu to import books from external sources
93+
self.import_menu = wx.Menu()
9294
# File menu
9395
# Translators: the label of an item in the application menubar
9496
self.Append(wx.ID_OPEN, _("Open...\tCtrl-O"))
9597
# Translators: the label of an item in the application menubar
9698
self.Append(wx.ID_NEW, _("New Window...\tCtrl-N"))
9799
self.AppendSeparator()
100+
self.AppendSubMenu(
101+
self.import_menu,
102+
# translators, the label of an item in the application menubar
103+
_("i&mport"),
104+
# Translators: the help text of an item in the application menubar
105+
_("Import a book from an external resource")
106+
)
107+
self.import_menu.Append(ImportMenuIds.qread, _("&Import QRD file"))
108+
self.AppendSeparator()
98109
# Translators: the label of an item in the application menubar
99110
self.Append(
100111
BookRelatedMenuIds.pin_document, _("&Pin\tCtrl-P"), kind=wx.ITEM_CHECK
@@ -163,6 +174,7 @@ def create(self):
163174
# Bind event handlers
164175
self.view.Bind(wx.EVT_MENU, self.onOpenEBook, id=wx.ID_OPEN)
165176
self.view.Bind(wx.EVT_MENU, self.onNewWindow, id=wx.ID_NEW)
177+
self.view.Bind(wx.EVT_MENU, self.onImportQread, id=ImportMenuIds.qread)
166178
self.view.Bind(
167179
wx.EVT_MENU, self.onClearPinDocuments, id=self.clearPinnedDocumentsID
168180
)
@@ -230,6 +242,29 @@ def onNewWindow(self, event):
230242
args.append("--debug")
231243
run_subcommand_in_a_new_process(args, hidden=False)
232244

245+
def onImportQread(self, event):
246+
with wx.FileDialog(
247+
self.view,
248+
# translators: the title of a file dialog to import qrd files
249+
message = _("Import QRD file"),
250+
style=wx.FD_OPEN | wx.FD_FILE_MUST_EXIST,
251+
wildcard=("*.qrd")
252+
) as dlg:
253+
if dlg.ShowModal() != wx.ID_OK:
254+
return
255+
256+
qrd_path = dlg.GetPath()
257+
book_info = qread.get_book_info(qrd_path)
258+
if not book_info:
259+
return self.view.notify_user(
260+
_("Failed to import QRD file"),
261+
_("The QRD file could not be imported"),
262+
icon=wx.ICON_ERROR
263+
)
264+
uri = DocumentUri.from_filename(book_info.original_path)
265+
uri.openner_args = {"position": book_info.current_position}
266+
return self.view.open_uri(uri)
267+
233268
def onClearPinDocuments(self, event):
234269
recents_manager.clear_pinned()
235270
self.populate_pinned_documents_list()

bookworm/qread/__init__.py

Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,37 @@
1+
"""QRead interoperability"""
2+
import sqlite3
3+
from typing import Optional
4+
5+
from pydantic import BaseModel, ValidationError
6+
7+
from bookworm.logger import logger
8+
9+
log = logger.getChild(__name__)
10+
11+
class BookInfo(BaseModel):
12+
"""Saved book information
13+
QRead stores book metadata inside a .qrd file, which is an unencrypted sqlite database
14+
The table we are interested from is named shelf, and it contains information related to book position, among other things
15+
"""
16+
# Current position of the book
17+
current_position: int
18+
# File location of the book
19+
original_path: str
20+
21+
22+
def get_book_info(qrd_path: str) -> Optional[BookInfo]:
23+
"""Connects to the .qrd sqlite database and retrieves the book information we require, if any"""
24+
log.debug(f"Connecting to {qrd_path}")
25+
with sqlite3.connect(qrd_path) as conn:
26+
cur = conn.cursor()
27+
# the shelf table is made up by two columns, key and value
28+
cur.execute('SELECT value FROM shelf WHERE key="book.json"')
29+
try:
30+
value = cur.fetchone()[0]
31+
info = BookInfo.model_validate_json(value)
32+
return info
33+
except ValidationError:
34+
log.error("Failed to obtain book information from QRD file", exc_info=True)
35+
return None
36+
finally:
37+
cur.close()

0 commit comments

Comments
 (0)