diff --git a/calibre-plugin/dialog/advanced_search.py b/calibre-plugin/dialog/advanced_search.py
index 3410a57..80dd04e 100644
--- a/calibre-plugin/dialog/advanced_search.py
+++ b/calibre-plugin/dialog/advanced_search.py
@@ -7,7 +7,6 @@
# See https://github.com/ping/libby-calibre-plugin for more
# information
#
-import copy
from threading import Lock
from typing import Dict, List
@@ -15,22 +14,18 @@
from qt.core import (
QAbstractItemView,
QButtonGroup,
- QCursor,
QFormLayout,
QGridLayout,
QHBoxLayout,
- QIcon,
QLineEdit,
- QMenu,
QRadioButton,
QThread,
QWidget,
Qt,
)
-from .base import BaseDialogMixin
+from .base_search import SearchBaseDialog
from .widgets import DefaultQPushButton, DefaultQTableView
-from .. import DEMO_MODE
from ..compat import (
QHeaderView_ResizeMode_ResizeToContents,
QHeaderView_ResizeMode_Stretch,
@@ -38,20 +33,17 @@
)
from ..config import (
BorrowActions,
- MAX_SEARCH_LIBRARIES,
PREFS,
PreferenceKeys,
SearchMode,
)
-from ..libby import LibbyClient, LibbyFormats
+from ..libby import LibbyFormats
from ..models import (
LibbySearchModel,
LibbySearchSortFilterModel,
- get_media_title,
- truncate_for_display,
)
from ..overdrive import LibraryMediaSearchParams
-from ..utils import PluginImages, obfuscate_name
+from ..utils import PluginImages
from ..workers import OverDriveLibraryMediaSearchWorker
# noinspection PyUnreachableCode
@@ -61,7 +53,7 @@
load_translations()
-class AdvancedSearchDialogMixin(BaseDialogMixin):
+class AdvancedSearchDialogMixin(SearchBaseDialog):
def __init__(self, *args):
super().__init__(*args)
@@ -266,214 +258,18 @@ def hold_removed_advsearch(self, hold: Dict):
self.adv_search_results_view.selectionModel().clearSelection()
def adv_search_results_view_selection_model_selectionchanged(self):
- selection_model = self.adv_search_results_view.selectionModel()
- if not selection_model.hasSelection():
- # selection cleared
- self.adv_search_borrow_btn.borrow_menu = None
- self.adv_search_borrow_btn.setMenu(None)
- self.adv_hold_btn.borrow_menu = None
- self.adv_hold_btn.setMenu(None)
- return
-
- indices = selection_model.selectedRows()
- media = indices[-1].data(Qt.UserRole)
- self.status_bar.showMessage(get_media_title(media, include_subtitle=True), 3000)
-
- borrow_action_default_is_borrow = PREFS[
- PreferenceKeys.LAST_BORROW_ACTION
- ] == BorrowActions.BORROW or not hasattr(self, "download_loan")
-
- available_sites = self.get_available_sites(media, self.adv_search_model)
-
- borrow_sites = [
- s
- for s in available_sites
- if s.get("isAvailable") or s.get("luckyDayAvailableCopies")
- ]
- hold_sites = [
- s
- for s in available_sites
- if not (s.get("isAvailable") or s.get("luckyDayAvailableCopies"))
- ]
- if borrow_sites:
- borrow_menu = QMenu()
- borrow_menu.setToolTipsVisible(True)
- for site in borrow_sites:
- cards = self.adv_search_model.get_cards_for_library_key(
- site["advantageKey"]
- )
- for card in cards:
- card_action = borrow_menu.addAction(
- QIcon(self.get_card_pixmap(site["__library"])),
- truncate_for_display(
- f'{card["advantageKey"]}: {card["cardName"] or ""}',
- font=borrow_menu.font(),
- ),
- )
- if not LibbyClient.can_borrow(card):
- card_action.setToolTip(
- self._wrap_for_rich_text(
- "
".join(
- [
- f'{site["__library"]["name"]}',
- _("This card is out of loans."),
- ]
- )
- )
- )
- card_action.setEnabled(False)
- continue
-
- if self.adv_search_model.has_loan(media["id"], card["cardId"]):
- card_action.setToolTip(
- self._wrap_for_rich_text(
- "
".join(
- [
- f'{site["__library"]["name"]}',
- _("You already have a loan for this title."),
- ]
- )
- )
- )
- card_action.setEnabled(False)
- continue
-
- card_action.setToolTip(self._borrow_tooltip(media, site))
- media_for_borrow = copy.deepcopy(media)
- media_for_borrow["cardId"] = card["cardId"]
- card_action.triggered.connect(
- # this is from the holds tab
- lambda checked, m=media_for_borrow, s=site: self.borrow_hold(
- m,
- availability=s,
- do_download=not borrow_action_default_is_borrow,
- )
- )
- self.adv_search_borrow_btn.setEnabled(True)
- self.adv_search_borrow_btn.borrow_menu = borrow_menu
- self.adv_search_borrow_btn.setMenu(borrow_menu)
- else:
- self.adv_search_borrow_btn.borrow_menu = None
- self.adv_search_borrow_btn.setMenu(None)
- self.adv_search_borrow_btn.setEnabled(False)
-
- if hold_sites:
- hold_menu = QMenu()
- hold_menu.setToolTipsVisible(True)
- for site in hold_sites:
- cards = self.adv_search_model.get_cards_for_library_key(
- site["advantageKey"]
- )
- for card in cards:
- card_action = hold_menu.addAction(
- QIcon(self.get_card_pixmap(site["__library"])),
- truncate_for_display(
- f'{card["advantageKey"]}: {card["cardName"] or ""}',
- font=hold_menu.font(),
- ),
- )
- if not LibbyClient.can_place_hold(card):
- card_action.setToolTip(
- self._wrap_for_rich_text(
- "
".join(
- [
- f'{site["__library"]["name"]}',
- _("This card is out of holds."),
- ]
- )
- )
- )
- card_action.setEnabled(False)
- continue
- if self.adv_search_model.has_hold(media["id"], card["cardId"]):
- card_action.setToolTip(
- self._wrap_for_rich_text(
- "
".join(
- [
- f'{site["__library"]["name"]}',
- _("You already have a hold for this title."),
- ]
- )
- )
- )
- card_action.setEnabled(False)
- continue
-
- card_action.setToolTip(self._hold_tooltip(media, site))
- card_action.triggered.connect(
- lambda checked, m=media, c=card: self.create_hold(m, c)
- )
- self.adv_hold_btn.setEnabled(True)
- self.adv_hold_btn.hold_menu = hold_menu
- self.adv_hold_btn.setMenu(hold_menu)
- else:
- self.adv_hold_btn.borrow_menu = None
- self.adv_hold_btn.setMenu(None)
- self.adv_hold_btn.setEnabled(False)
+ self.view_selection_model_selectionchanged(
+ self.adv_search_borrow_btn,
+ self.adv_hold_btn,
+ self.adv_search_results_view,
+ self.adv_search_model,
+ )
def adv_search_results_view_context_menu_requested(self, pos):
- selection_model = self.adv_search_results_view.selectionModel()
- if not selection_model.hasSelection():
- return
- mi = self.adv_search_results_view.indexAt(pos)
- media = mi.data(Qt.UserRole)
-
- menu = QMenu(self)
- menu.setToolTipsVisible(True)
- available_sites = self.get_available_sites(media, self.adv_search_model)
- view_in_libby_menu = QMenu(_("View in Libby"))
- view_in_libby_menu.setIcon(self.resources[PluginImages.ExternalLink])
- view_in_libby_menu.setToolTipsVisible(True)
- for site in available_sites:
- _card = site["__card"]
- library = site["__library"]
- libby_action = view_in_libby_menu.addAction(
- QIcon(self.get_card_pixmap(site["__library"])),
- _card["advantageKey"]
- if not DEMO_MODE
- else obfuscate_name(_card["advantageKey"]),
- )
- libby_action.setToolTip(library["name"])
- libby_action.triggered.connect(
- lambda checked, c=_card: self.view_in_libby_action_triggered(
- [mi], self.adv_search_model, c
- )
- )
- menu.addMenu(view_in_libby_menu)
- view_in_overdrive_menu = QMenu(_("View in OverDrive"))
- view_in_overdrive_menu.setIcon(self.resources[PluginImages.ExternalLink])
- view_in_overdrive_menu.setToolTipsVisible(True)
- for site in available_sites:
- _card = site["__card"]
- library = site["__library"]
- overdrive_action = view_in_overdrive_menu.addAction(
- QIcon(self.get_card_pixmap(site["__library"])),
- _card["advantageKey"]
- if not DEMO_MODE
- else obfuscate_name(_card["advantageKey"]),
- )
- overdrive_action.setToolTip(library["name"])
- overdrive_action.triggered.connect(
- lambda checked, c=_card: self.view_in_overdrive_action_triggered(
- [mi], self.adv_search_model, c
- )
- )
- menu.addMenu(view_in_overdrive_menu)
-
- selected_search = self.adv_search_results_view.indexAt(pos).data(Qt.UserRole)
- # view book details
- self.add_view_book_details_menu_action(menu, selected_search)
- # copy share link
- self.add_copy_share_link_menu_action(menu, selected_search)
- # find calibre matches
- self.add_find_library_match_menu_action(menu, selected_search)
- # search for author
- self.add_search_for_title_menu_action(
- menu, selected_search, search_for_author=True
+ self.view_context_menu_requested(
+ pos, self.adv_search_results_view, self.adv_search_model
)
- menu.exec(QCursor.pos())
-
def _adv_reset_borrow_hold_buttons(self):
self.adv_search_borrow_btn.borrow_menu = None
self.adv_search_borrow_btn.setMenu(None)
@@ -532,18 +328,13 @@ def adv_search_btn_clicked(self):
self.adv_search_btn.setText(_c("Searching..."))
self.adv_search_btn.setEnabled(False)
self.setCursor(Qt.WaitCursor)
- all_library_keys = self.adv_search_model.library_keys()
- library_keys = [
- lib
- for lib in all_library_keys
- if lib in PREFS[PreferenceKeys.SEARCH_LIBRARIES]
- ]
- if not library_keys:
- library_keys = all_library_keys
-
- library_keys = library_keys[:MAX_SEARCH_LIBRARIES]
+ library_keys = self.adv_search_model.limited_library_keys()
self.status_bar.showMessage(
- _("Searching across {n} libraries...").format(n=len(library_keys))
+ ngettext(
+ "Searching across {n} library...",
+ "Searching across {n} libraries...",
+ len(library_keys),
+ ).format(n=len(library_keys))
)
self._lib_search_threads = []
self._lib_search_result_sets = {}
diff --git a/calibre-plugin/dialog/base_search.py b/calibre-plugin/dialog/base_search.py
new file mode 100644
index 0000000..a9aaca6
--- /dev/null
+++ b/calibre-plugin/dialog/base_search.py
@@ -0,0 +1,283 @@
+#
+# Copyright (C) 2023 github.com/ping
+#
+# This file is part of the OverDrive Libby Plugin by ping
+# OverDrive Libby Plugin for calibre / libby-calibre-plugin
+#
+# See https://github.com/ping/libby-calibre-plugin for more
+# information
+#
+import copy
+
+from qt.core import Qt, QMenu, QIcon, QCursor
+
+from .base import BaseDialogMixin
+from .. import DEMO_MODE
+from ..compat import _c
+from ..config import PREFS, PreferenceKeys, BorrowActions
+from ..libby import LibbyClient
+from ..models import get_media_title, truncate_for_display
+from ..utils import PluginImages, obfuscate_name
+
+# noinspection PyUnreachableCode
+if False:
+ load_translations = _ = ngettext = lambda x=None, y=None, z=None: x
+
+load_translations()
+
+
+class SearchBaseDialog(BaseDialogMixin):
+ def __init__(self, *args):
+ super().__init__(*args)
+
+ def _wrap_for_rich_text(self, txt):
+ return f"
{txt}
" + + def _borrow_tooltip(self, media, site_availability): + available_copies = site_availability.get( + "luckyDayAvailableCopies", 0 + ) + site_availability.get("availableCopies", 0) + owned_copies = site_availability.get( + "luckyDayOwnedCopies", 0 + ) + site_availability.get("ownedCopies", 0) + texts = [f'{site_availability["__library"]["name"]}'] + if available_copies: + texts.append( + ngettext( + "{n} copy available.", + "{n} copies available.", + available_copies, + ).format(n=available_copies) + ) + if owned_copies: + texts.append( + ngettext("{n} copy owned.", "{n} copies owned.", owned_copies).format( + n=owned_copies + ) + ) + return self._wrap_for_rich_text("{txt}
" - - def _borrow_tooltip(self, media, site_availability): - available_copies = site_availability.get( - "luckyDayAvailableCopies", 0 - ) + site_availability.get("availableCopies", 0) - owned_copies = site_availability.get( - "luckyDayOwnedCopies", 0 - ) + site_availability.get("ownedCopies", 0) - texts = [f'{site_availability["__library"]["name"]}'] - if available_copies: - texts.append( - ngettext( - "{n} copy available.", - "{n} copies available.", - available_copies, - ).format(n=available_copies) - ) - if owned_copies: - texts.append( - ngettext("{n} copy owned.", "{n} copies owned.", owned_copies).format( - n=owned_copies - ) - ) - return self._wrap_for_rich_text("