mirror of
https://github.com/Leseratte10/acsm-calibre-plugin.git
synced 2024-12-22 17:29:56 +06:00
Add GUI, rename to "ACSM Input"
This commit is contained in:
parent
9be0d5e55d
commit
2904e187c4
8
.github/ISSUE_TEMPLATE/bug_report.yml
vendored
8
.github/ISSUE_TEMPLATE/bug_report.yml
vendored
@ -35,16 +35,16 @@ body:
|
|||||||
id: calibre-version
|
id: calibre-version
|
||||||
attributes:
|
attributes:
|
||||||
label: Which version of Calibre are you running?
|
label: Which version of Calibre are you running?
|
||||||
description: "Example: 6.2.1"
|
description: "Example: 6.4"
|
||||||
placeholder: "6.2.1"
|
placeholder: "6.4"
|
||||||
validations:
|
validations:
|
||||||
required: true
|
required: true
|
||||||
- type: input
|
- type: input
|
||||||
id: plugin-version
|
id: plugin-version
|
||||||
attributes:
|
attributes:
|
||||||
label: Which version of the DeACSM plugin are you running?
|
label: Which version of the DeACSM plugin are you running?
|
||||||
description: "Example: v0.0.16"
|
description: "Example: v0.0.17"
|
||||||
placeholder: "v0.0.16"
|
placeholder: "v0.0.17"
|
||||||
validations:
|
validations:
|
||||||
required: true
|
required: true
|
||||||
- type: textarea
|
- type: textarea
|
||||||
|
@ -43,10 +43,11 @@
|
|||||||
# update python-oscrypto to unofficial fork to fix OpenSSL 3 support.
|
# update python-oscrypto to unofficial fork to fix OpenSSL 3 support.
|
||||||
# In Progress:
|
# In Progress:
|
||||||
# Fix bug that would sometimes return the wrong book (or none at all) if you had
|
# Fix bug that would sometimes return the wrong book (or none at all) if you had
|
||||||
# multiple active loans from the same distributor.
|
# multiple active loans from the same distributor, add experimental GUI button,
|
||||||
|
# rename plugin from "DeACSM" to "ACSM Input"
|
||||||
|
|
||||||
|
|
||||||
PLUGIN_NAME = "DeACSM"
|
PLUGIN_NAME = "ACSM Input"
|
||||||
PLUGIN_VERSION_TUPLE = (0, 0, 16)
|
PLUGIN_VERSION_TUPLE = (0, 0, 16)
|
||||||
|
|
||||||
from calibre.customize import FileTypePlugin # type: ignore
|
from calibre.customize import FileTypePlugin # type: ignore
|
||||||
@ -60,10 +61,11 @@ from calibre.constants import isosx, iswindows, islinux # type:
|
|||||||
import os, shutil, traceback, sys, time, io, random
|
import os, shutil, traceback, sys, time, io, random
|
||||||
import zipfile
|
import zipfile
|
||||||
from lxml import etree
|
from lxml import etree
|
||||||
|
from calibre.gui2 import error_dialog
|
||||||
|
|
||||||
#@@CALIBRE_COMPAT_CODE@@
|
#@@CALIBRE_COMPAT_CODE@@
|
||||||
|
|
||||||
class DeACSM(FileTypePlugin):
|
class ACSMInput(FileTypePlugin):
|
||||||
name = PLUGIN_NAME
|
name = PLUGIN_NAME
|
||||||
description = "ACSM Input Plugin - Takes an Adobe ACSM file and converts that into a useable EPUB or PDF file. Python reimplementation of libgourou by Grégory Soutadé"
|
description = "ACSM Input Plugin - Takes an Adobe ACSM file and converts that into a useable EPUB or PDF file. Python reimplementation of libgourou by Grégory Soutadé"
|
||||||
supported_platforms = ['linux', 'osx', 'windows']
|
supported_platforms = ['linux', 'osx', 'windows']
|
||||||
@ -75,7 +77,35 @@ class DeACSM(FileTypePlugin):
|
|||||||
on_preprocess = True
|
on_preprocess = True
|
||||||
priority = 2000
|
priority = 2000
|
||||||
|
|
||||||
|
def init_embedded_plugins(self):
|
||||||
|
"""
|
||||||
|
A Calibre plugin can normally only contain one Plugin class.
|
||||||
|
In our case, this would be the DeACSM class.
|
||||||
|
However, we want to load the GUI plugin, too, so we have to trick
|
||||||
|
Calibre into believing that there's actually a 2nd plugin.
|
||||||
|
"""
|
||||||
|
from calibre.customize.ui import _initialized_plugins
|
||||||
|
from calibre_plugins.deacsm.gui_main_wrapper import DeACSMGUIExtension
|
||||||
|
|
||||||
|
def init_plg(plg_type):
|
||||||
|
for plugin in _initialized_plugins:
|
||||||
|
if isinstance(plugin, plg_type):
|
||||||
|
return plugin
|
||||||
|
|
||||||
|
plg_type.version = self.version
|
||||||
|
plg_type.minimum_calibre_version = self.minimum_calibre_version
|
||||||
|
plugin = plg_type(self.plugin_path)
|
||||||
|
_initialized_plugins.append(plugin)
|
||||||
|
plugin.initialize()
|
||||||
|
|
||||||
|
return plugin
|
||||||
|
|
||||||
|
init_plg(DeACSMGUIExtension)
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
def initialize(self):
|
def initialize(self):
|
||||||
|
|
||||||
"""
|
"""
|
||||||
On initialization, make sure we have all the libraries (oscrypto and its dependency
|
On initialization, make sure we have all the libraries (oscrypto and its dependency
|
||||||
asn1crypto) that the plugin needs. Unfortunately the Adobe encryption is kinda weird
|
asn1crypto) that the plugin needs. Unfortunately the Adobe encryption is kinda weird
|
||||||
@ -98,7 +128,49 @@ class DeACSM(FileTypePlugin):
|
|||||||
self.pluginsdir = os.path.join(config_dir,"plugins")
|
self.pluginsdir = os.path.join(config_dir,"plugins")
|
||||||
if not os.path.exists(self.pluginsdir):
|
if not os.path.exists(self.pluginsdir):
|
||||||
os.mkdir(self.pluginsdir)
|
os.mkdir(self.pluginsdir)
|
||||||
self.maindir = os.path.join(self.pluginsdir,"DeACSM")
|
|
||||||
|
# Okay, "I" am now the new version. If I'm running under the old name,
|
||||||
|
# move "me" to the new one.
|
||||||
|
if os.path.exists(os.path.join(self.pluginsdir, "DeACSM.zip")):
|
||||||
|
|
||||||
|
from calibre.customize.ui import _config
|
||||||
|
|
||||||
|
shutil.copyfile(os.path.join(self.pluginsdir, "DeACSM.zip"), os.path.join(self.pluginsdir, "ACSM Input.zip"))
|
||||||
|
|
||||||
|
# Delete the old plugin.
|
||||||
|
os.remove(os.path.join(self.pluginsdir, "DeACSM.zip"))
|
||||||
|
|
||||||
|
# Forcibly add the new plugin, circumventing the Calibre code.
|
||||||
|
ui_plg_config = _config()
|
||||||
|
plugins = ui_plg_config['plugins']
|
||||||
|
plugins["ACSM Input"] = os.path.join(self.pluginsdir, "ACSM Input.zip")
|
||||||
|
ui_plg_config['plugins'] = plugins
|
||||||
|
|
||||||
|
return
|
||||||
|
|
||||||
|
|
||||||
|
# Make sure the GUI extension is loaded:
|
||||||
|
self.init_embedded_plugins()
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
self.maindir_old = os.path.join(self.pluginsdir,"DeACSM")
|
||||||
|
self.maindir = os.path.join(self.pluginsdir,"ACSMInput")
|
||||||
|
|
||||||
|
if os.path.exists(self.maindir_old) and not os.path.exists(self.maindir):
|
||||||
|
# Migrate config to new folder
|
||||||
|
os.rename(self.maindir_old, self.maindir)
|
||||||
|
if not iswindows:
|
||||||
|
# Linux and Mac support symlinks, so create one so the old paths
|
||||||
|
# still work and people can downgrade the plugin again.
|
||||||
|
# Windows ... doesn't, so downgrading will be tricky.
|
||||||
|
try:
|
||||||
|
os.symlink(self.maindir_old, self.maindir)
|
||||||
|
except:
|
||||||
|
pass
|
||||||
|
|
||||||
|
|
||||||
if not os.path.exists(self.maindir):
|
if not os.path.exists(self.maindir):
|
||||||
os.mkdir(self.maindir)
|
os.mkdir(self.maindir)
|
||||||
|
|
||||||
@ -222,7 +294,7 @@ class DeACSM(FileTypePlugin):
|
|||||||
|
|
||||||
|
|
||||||
import calibre_plugins.deacsm.prefs as prefs # type: ignore
|
import calibre_plugins.deacsm.prefs as prefs # type: ignore
|
||||||
deacsmprefs = prefs.DeACSM_Prefs()
|
deacsmprefs = prefs.ACSMInput_Prefs()
|
||||||
update_account_path(deacsmprefs["path_to_account_data"])
|
update_account_path(deacsmprefs["path_to_account_data"])
|
||||||
|
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
@ -242,7 +314,7 @@ class DeACSM(FileTypePlugin):
|
|||||||
|
|
||||||
def ADE_sanity_check(self):
|
def ADE_sanity_check(self):
|
||||||
import calibre_plugins.deacsm.prefs as prefs # type: ignore
|
import calibre_plugins.deacsm.prefs as prefs # type: ignore
|
||||||
deacsmprefs = prefs.DeACSM_Prefs()
|
deacsmprefs = prefs.ACSMInput_Prefs()
|
||||||
|
|
||||||
from libadobe import get_activation_xml_path
|
from libadobe import get_activation_xml_path
|
||||||
|
|
||||||
@ -403,7 +475,7 @@ class DeACSM(FileTypePlugin):
|
|||||||
print("{0} v{1}: Try to fulfill ...".format(PLUGIN_NAME, PLUGIN_VERSION))
|
print("{0} v{1}: Try to fulfill ...".format(PLUGIN_NAME, PLUGIN_VERSION))
|
||||||
|
|
||||||
import calibre_plugins.deacsm.prefs as prefs # type: ignore
|
import calibre_plugins.deacsm.prefs as prefs # type: ignore
|
||||||
deacsmprefs = prefs.DeACSM_Prefs()
|
deacsmprefs = prefs.ACSMInput_Prefs()
|
||||||
|
|
||||||
|
|
||||||
success, replyData = fulfill(path_to_ebook, deacsmprefs["notify_fulfillment"])
|
success, replyData = fulfill(path_to_ebook, deacsmprefs["notify_fulfillment"])
|
||||||
|
BIN
calibre-plugin/acsm_logo_2.png
Normal file
BIN
calibre-plugin/acsm_logo_2.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 13 KiB |
@ -46,7 +46,7 @@ class ConfigWidget(QWidget):
|
|||||||
self.plugin_path = plugin_path
|
self.plugin_path = plugin_path
|
||||||
|
|
||||||
# get the prefs
|
# get the prefs
|
||||||
self.deacsmprefs = prefs.DeACSM_Prefs()
|
self.deacsmprefs = prefs.ACSMInput_Prefs()
|
||||||
|
|
||||||
# make a local copy
|
# make a local copy
|
||||||
self.tempdeacsmprefs = {}
|
self.tempdeacsmprefs = {}
|
||||||
@ -58,7 +58,6 @@ class ConfigWidget(QWidget):
|
|||||||
|
|
||||||
self.tempdeacsmprefs['list_of_rented_books'] = self.deacsmprefs['list_of_rented_books']
|
self.tempdeacsmprefs['list_of_rented_books'] = self.deacsmprefs['list_of_rented_books']
|
||||||
|
|
||||||
|
|
||||||
# Start Qt Gui dialog layout
|
# Start Qt Gui dialog layout
|
||||||
layout = QVBoxLayout(self)
|
layout = QVBoxLayout(self)
|
||||||
self.setLayout(layout)
|
self.setLayout(layout)
|
||||||
@ -150,7 +149,13 @@ class ConfigWidget(QWidget):
|
|||||||
self.button_rented_books.setEnabled(activated)
|
self.button_rented_books.setEnabled(activated)
|
||||||
ua_group_box_layout.addWidget(self.button_rented_books)
|
ua_group_box_layout.addWidget(self.button_rented_books)
|
||||||
|
|
||||||
if (len(self.deacsmprefs["list_of_rented_books"]) == 0):
|
|
||||||
|
# First remove all overdue books from the loan list,
|
||||||
|
# to determine if we should enable the button.
|
||||||
|
self.delete_overdue_books_from_loan_list()
|
||||||
|
|
||||||
|
if (len(self.tempdeacsmprefs["list_of_rented_books"]) == 0):
|
||||||
|
self.button_rented_books.setText(_("No loaned books available"))
|
||||||
self.button_rented_books.setEnabled(False)
|
self.button_rented_books.setEnabled(False)
|
||||||
|
|
||||||
|
|
||||||
@ -1275,17 +1280,47 @@ class ConfigWidget(QWidget):
|
|||||||
|
|
||||||
|
|
||||||
def show_rented_books(self):
|
def show_rented_books(self):
|
||||||
d = RentedBooksDialog(self, self.deacsmprefs["list_of_rented_books"])
|
self.delete_overdue_books_from_loan_list()
|
||||||
|
|
||||||
|
d = RentedBooksDialog(self)
|
||||||
d.exec_()
|
d.exec_()
|
||||||
|
|
||||||
|
|
||||||
|
def delete_overdue_books_from_loan_list(self):
|
||||||
|
overdue_books = []
|
||||||
|
|
||||||
|
for book in self.deacsmprefs["list_of_rented_books"]:
|
||||||
|
try:
|
||||||
|
book_time_stamp = book["validUntil"]
|
||||||
|
timestamp = datetime.datetime.strptime(book_time_stamp, "%Y-%m-%dT%H:%M:%SZ")
|
||||||
|
currenttime = datetime.datetime.utcnow()
|
||||||
|
except:
|
||||||
|
# Invalid book timestano
|
||||||
|
continue
|
||||||
|
|
||||||
|
if (timestamp <= currenttime):
|
||||||
|
# Book is overdue, no need to return. Delete from list.
|
||||||
|
overdue_books.append(book)
|
||||||
|
continue
|
||||||
|
|
||||||
|
templist = self.deacsmprefs["list_of_rented_books"]
|
||||||
|
|
||||||
|
for book in overdue_books:
|
||||||
|
templist.remove(book)
|
||||||
|
|
||||||
|
self.deacsmprefs.set("list_of_rented_books", templist)
|
||||||
|
self.deacsmprefs.writeprefs()
|
||||||
|
|
||||||
|
|
||||||
class RentedBooksDialog(QDialog):
|
class RentedBooksDialog(QDialog):
|
||||||
def __init__(self, parent, booklist):
|
def __init__(self, parent):
|
||||||
QDialog.__init__(self,parent)
|
QDialog.__init__(self,parent)
|
||||||
self.parent = parent
|
self.parent = parent
|
||||||
|
|
||||||
self.setWindowTitle("DeACSM: Manage loaned Books")
|
self.setWindowTitle("DeACSM: Manage loaned Books")
|
||||||
|
|
||||||
|
self.deacsmprefs = prefs.ACSMInput_Prefs()
|
||||||
|
|
||||||
# Start Qt Gui dialog layout
|
# Start Qt Gui dialog layout
|
||||||
layout = QVBoxLayout(self)
|
layout = QVBoxLayout(self)
|
||||||
self.setLayout(layout)
|
self.setLayout(layout)
|
||||||
@ -1353,37 +1388,22 @@ class RentedBooksDialog(QDialog):
|
|||||||
def populate_list(self):
|
def populate_list(self):
|
||||||
self.listy.clear()
|
self.listy.clear()
|
||||||
|
|
||||||
overdue_books = []
|
for book in self.deacsmprefs["list_of_rented_books"]:
|
||||||
|
|
||||||
for book in self.parent.deacsmprefs["list_of_rented_books"]:
|
|
||||||
|
|
||||||
try:
|
try:
|
||||||
book_time_stamp = book["validUntil"]
|
book_time_stamp = book["validUntil"]
|
||||||
timestamp = datetime.datetime.strptime(book_time_stamp, "%Y-%m-%dT%H:%M:%SZ")
|
timestamp = datetime.datetime.strptime(book_time_stamp, "%Y-%m-%dT%H:%M:%SZ")
|
||||||
currenttime = datetime.datetime.utcnow()
|
currenttime = datetime.datetime.utcnow()
|
||||||
except:
|
except:
|
||||||
# Invalid book timestano
|
# Invalid book timestamp
|
||||||
continue
|
continue
|
||||||
|
|
||||||
|
info = "(" + self.td_format(timestamp - currenttime) + " remaining)"
|
||||||
if (timestamp <= currenttime):
|
|
||||||
# Book is overdue, no need to return. Delete from list.
|
|
||||||
overdue_books.append(book)
|
|
||||||
continue
|
|
||||||
else:
|
|
||||||
info = "(" + self.td_format(timestamp - currenttime)
|
|
||||||
info += " remaining)"
|
|
||||||
|
|
||||||
|
|
||||||
item = QListWidgetItem(book["book_name"] + " " + info)
|
item = QListWidgetItem(book["book_name"] + " " + info)
|
||||||
item.setData(QtCore.Qt.UserRole, book["loanID"])
|
item.setData(QtCore.Qt.UserRole, book["loanID"])
|
||||||
self.listy.addItem(item)
|
self.listy.addItem(item)
|
||||||
|
|
||||||
for book in overdue_books:
|
|
||||||
self.parent.deacsmprefs["list_of_rented_books"].remove(book)
|
|
||||||
|
|
||||||
self.parent.deacsmprefs.writeprefs()
|
|
||||||
|
|
||||||
|
|
||||||
def return_book(self):
|
def return_book(self):
|
||||||
if not self.listy.currentItem():
|
if not self.listy.currentItem():
|
||||||
@ -1400,7 +1420,7 @@ class RentedBooksDialog(QDialog):
|
|||||||
traceback.print_exc()
|
traceback.print_exc()
|
||||||
|
|
||||||
Ret_book = None
|
Ret_book = None
|
||||||
for book in self.parent.deacsmprefs["list_of_rented_books"]:
|
for book in self.deacsmprefs["list_of_rented_books"]:
|
||||||
if book["loanID"] == userdata:
|
if book["loanID"] == userdata:
|
||||||
Ret_book = book
|
Ret_book = book
|
||||||
break
|
break
|
||||||
@ -1430,14 +1450,16 @@ class RentedBooksDialog(QDialog):
|
|||||||
|
|
||||||
success = False
|
success = False
|
||||||
done = False
|
done = False
|
||||||
|
templist = self.deacsmprefs["list_of_rented_books"]
|
||||||
while not done:
|
while not done:
|
||||||
done = True
|
done = True
|
||||||
for book in self.parent.deacsmprefs["list_of_rented_books"]:
|
for book in templist:
|
||||||
if book["loanID"] == userdata:
|
if book["loanID"] == userdata:
|
||||||
done = False
|
done = False
|
||||||
self.parent.deacsmprefs["list_of_rented_books"].remove(book)
|
templist.remove(book)
|
||||||
success = True
|
success = True
|
||||||
break
|
break
|
||||||
|
self.deacsmprefs.set("list_of_rented_books", templist)
|
||||||
|
|
||||||
self.populate_list()
|
self.populate_list()
|
||||||
|
|
||||||
|
@ -101,7 +101,7 @@ def GetMasterKey():
|
|||||||
verbose_logging = False
|
verbose_logging = False
|
||||||
try:
|
try:
|
||||||
import calibre_plugins.deacsm.prefs as prefs
|
import calibre_plugins.deacsm.prefs as prefs
|
||||||
deacsmprefs = prefs.DeACSM_Prefs()
|
deacsmprefs = prefs.ACSMInput_Prefs()
|
||||||
verbose_logging = deacsmprefs["detailed_logging"]
|
verbose_logging = deacsmprefs["detailed_logging"]
|
||||||
except:
|
except:
|
||||||
pass
|
pass
|
||||||
|
@ -11,7 +11,7 @@ def GetMasterKey(wineprefix):
|
|||||||
verbose_logging = False
|
verbose_logging = False
|
||||||
try:
|
try:
|
||||||
import calibre_plugins.deacsm.prefs as prefs
|
import calibre_plugins.deacsm.prefs as prefs
|
||||||
deacsmprefs = prefs.DeACSM_Prefs()
|
deacsmprefs = prefs.ACSMInput_Prefs()
|
||||||
verbose_logging = deacsmprefs["detailed_logging"]
|
verbose_logging = deacsmprefs["detailed_logging"]
|
||||||
except:
|
except:
|
||||||
pass
|
pass
|
||||||
|
@ -115,7 +115,7 @@ def GetMasterKey():
|
|||||||
verbose_logging = False
|
verbose_logging = False
|
||||||
try:
|
try:
|
||||||
import calibre_plugins.deacsm.prefs as prefs
|
import calibre_plugins.deacsm.prefs as prefs
|
||||||
deacsmprefs = prefs.DeACSM_Prefs()
|
deacsmprefs = prefs.ACSMInput_Prefs()
|
||||||
verbose_logging = deacsmprefs["detailed_logging"]
|
verbose_logging = deacsmprefs["detailed_logging"]
|
||||||
except:
|
except:
|
||||||
pass
|
pass
|
||||||
|
116
calibre-plugin/gui_main.py
Normal file
116
calibre-plugin/gui_main.py
Normal file
@ -0,0 +1,116 @@
|
|||||||
|
#!/usr/bin/env python3
|
||||||
|
# -*- coding: utf-8 -*-
|
||||||
|
|
||||||
|
# GUI for the ACSM plugin.
|
||||||
|
#
|
||||||
|
# "create_menu_action_unique" taken from the Quality Check plugin:
|
||||||
|
# GPLv3, Copyright 2011, Grant Drake <grant.drake@gmail.com>
|
||||||
|
|
||||||
|
|
||||||
|
from calibre.gui2.actions import InterfaceAction
|
||||||
|
from calibre.gui2.actions import menu_action_unique_name
|
||||||
|
from PyQt5.QtGui import QMenu, QToolButton
|
||||||
|
|
||||||
|
|
||||||
|
#@@CALIBRE_COMPAT_CODE@@
|
||||||
|
|
||||||
|
|
||||||
|
def create_menu_action_unique(ia, parent_menu, menu_text, image=None, tooltip=None,
|
||||||
|
shortcut=None, triggered=None, is_checked=None, shortcut_name=None,
|
||||||
|
unique_name=None, favourites_menu_unique_name=None):
|
||||||
|
'''
|
||||||
|
Create a menu action with the specified criteria and action, using the new
|
||||||
|
InterfaceAction.create_menu_action() function which ensures that regardless of
|
||||||
|
whether a shortcut is specified it will appear in Preferences->Keyboard
|
||||||
|
'''
|
||||||
|
orig_shortcut = shortcut
|
||||||
|
kb = ia.gui.keyboard
|
||||||
|
if unique_name is None:
|
||||||
|
unique_name = menu_text
|
||||||
|
if not shortcut == False:
|
||||||
|
full_unique_name = menu_action_unique_name(ia, unique_name)
|
||||||
|
if full_unique_name in kb.shortcuts:
|
||||||
|
shortcut = False
|
||||||
|
else:
|
||||||
|
if shortcut is not None and not shortcut == False:
|
||||||
|
if len(shortcut) == 0:
|
||||||
|
shortcut = None
|
||||||
|
else:
|
||||||
|
shortcut = _(shortcut)
|
||||||
|
|
||||||
|
if shortcut_name is None:
|
||||||
|
shortcut_name = menu_text.replace('&','')
|
||||||
|
|
||||||
|
ac = ia.create_menu_action(parent_menu, unique_name, menu_text, icon=None, shortcut=shortcut,
|
||||||
|
description=tooltip, triggered=triggered, shortcut_name=shortcut_name)
|
||||||
|
if shortcut == False and not orig_shortcut == False:
|
||||||
|
if ac.calibre_shortcut_unique_name in ia.gui.keyboard.shortcuts:
|
||||||
|
kb.replace_action(ac.calibre_shortcut_unique_name, ac)
|
||||||
|
#if image:
|
||||||
|
#ac.setIcon(get_icons(image, "ACSM Input"))
|
||||||
|
|
||||||
|
|
||||||
|
return ac
|
||||||
|
|
||||||
|
class ActualDeACSMGUIExtension(InterfaceAction):
|
||||||
|
name = "ACSM Input Plugin GUI Extension"
|
||||||
|
|
||||||
|
popup_type = QToolButton.ToolButtonPopupMode.InstantPopup
|
||||||
|
action_type = 'global'
|
||||||
|
action_spec = ("ACSM Input", None, "ACSM Input Plugin by Leseratte10", None)
|
||||||
|
# Text, icon, tooltip, keyboard shortcut
|
||||||
|
|
||||||
|
def genesis(self):
|
||||||
|
print("Genesis!")
|
||||||
|
self.menu = QMenu(self.gui)
|
||||||
|
|
||||||
|
self.rebuild_menus()
|
||||||
|
|
||||||
|
self.qaction.setMenu(self.menu)
|
||||||
|
icon = get_icons('acsm_logo_2.png', "ACSM Input Plugin")
|
||||||
|
self.qaction.setIcon(icon)
|
||||||
|
#self.qaction.triggered.connect(self.trigger_config_dialog)
|
||||||
|
|
||||||
|
def rebuild_menus(self):
|
||||||
|
m = self.menu
|
||||||
|
m.clear()
|
||||||
|
|
||||||
|
create_menu_action_unique(self, m, "ACSM Input configuration", None, shortcut=None, shortcut_name="Open ACSM Input plugin settings dialog", triggered=self.trigger_config_dialog)
|
||||||
|
create_menu_action_unique(self, m, "Show loaned books", None, shortcut=None, shortcut_name="ACSM: Open list of loaned books", triggered=self.trigger_loan_dialog)
|
||||||
|
|
||||||
|
|
||||||
|
def trigger_loan_dialog(self):
|
||||||
|
import calibre_plugins.deacsm.prefs as prefs
|
||||||
|
from calibre.gui2 import info_dialog
|
||||||
|
deacsmprefs = prefs.ACSMInput_Prefs()
|
||||||
|
|
||||||
|
if (len(deacsmprefs["list_of_rented_books"]) == 0):
|
||||||
|
return info_dialog(None, "No loaned books", "You currently have no loaned books.", show=True, show_copy_button=False)
|
||||||
|
|
||||||
|
from calibre_plugins.deacsm.config import RentedBooksDialog # type: ignore
|
||||||
|
d = RentedBooksDialog(self.gui)
|
||||||
|
d.exec_()
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
def trigger_config_dialog(self):
|
||||||
|
from calibre.customize.ui import _initialized_plugins
|
||||||
|
from calibre_plugins.deacsm.__init__ import PLUGIN_NAME
|
||||||
|
from calibre.gui2 import error_dialog
|
||||||
|
|
||||||
|
plg = None
|
||||||
|
for plugin in _initialized_plugins:
|
||||||
|
if plugin.name == PLUGIN_NAME:
|
||||||
|
plg = plugin
|
||||||
|
break
|
||||||
|
|
||||||
|
if plg is None:
|
||||||
|
msg = "Tried to open the ACSM Input plugin (DeACSM) settings, but I couldn't find the ACSM Input plugin. "
|
||||||
|
msg += "This is most likely a bug in the plugin. Try restarting Calibre, and if you still get this error, "
|
||||||
|
msg += "please open a bug report. "
|
||||||
|
return error_dialog(None, "Plugin not found", msg, show=True)
|
||||||
|
|
||||||
|
plg.do_user_config(self.gui)
|
||||||
|
|
||||||
|
|
36
calibre-plugin/gui_main_wrapper.py
Normal file
36
calibre-plugin/gui_main_wrapper.py
Normal file
@ -0,0 +1,36 @@
|
|||||||
|
#!/usr/bin/env python3
|
||||||
|
# -*- coding: utf-8 -*-
|
||||||
|
|
||||||
|
# GUI for the ACSM plugin.
|
||||||
|
#
|
||||||
|
|
||||||
|
from calibre.customize import InterfaceActionBase # type: ignore
|
||||||
|
from calibre.customize import PluginInstallationType
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
#@@CALIBRE_COMPAT_CODE@@
|
||||||
|
|
||||||
|
class DeACSMGUIExtension(InterfaceActionBase):
|
||||||
|
name = "ACSM Input Plugin GUI Extension"
|
||||||
|
description = "GUI code for ACSM Input Plugin (DeACSM). This is automatically installed and updated with the ACSM plugin."
|
||||||
|
supported_platforms = ['linux', 'osx', 'windows']
|
||||||
|
author = "Leseratte10"
|
||||||
|
minimum_calibre_version = (4, 0, 0)
|
||||||
|
|
||||||
|
can_be_disabled = False
|
||||||
|
# This plugin will be auto-loaded from the ACSM Input plugin. It doesn't make sense for the user
|
||||||
|
# to disable it. If necessary, the menu bar button can be removed through the Calibre settings.
|
||||||
|
|
||||||
|
type = "File type"
|
||||||
|
# Just so that the GUI extension shows up at the same place as the actual ACSM Input plugin.
|
||||||
|
|
||||||
|
installation_type = PluginInstallationType.EXTERNAL
|
||||||
|
# Mark this as user-installed so it shows up in the plugin list by default.
|
||||||
|
|
||||||
|
actual_plugin = "calibre_plugins.deacsm.gui_main:ActualDeACSMGUIExtension"
|
||||||
|
|
||||||
|
def is_customizable(self):
|
||||||
|
return False
|
||||||
|
|
||||||
|
|
@ -787,7 +787,7 @@ def activateDevice(useVersionIndex = 0, proxyData = None):
|
|||||||
verbose_logging = False
|
verbose_logging = False
|
||||||
try:
|
try:
|
||||||
import calibre_plugins.deacsm.prefs as prefs
|
import calibre_plugins.deacsm.prefs as prefs
|
||||||
deacsmprefs = prefs.DeACSM_Prefs()
|
deacsmprefs = prefs.ACSMInput_Prefs()
|
||||||
verbose_logging = deacsmprefs["detailed_logging"]
|
verbose_logging = deacsmprefs["detailed_logging"]
|
||||||
except:
|
except:
|
||||||
pass
|
pass
|
||||||
|
@ -321,7 +321,7 @@ def fulfill(acsm_file, do_notify = False):
|
|||||||
verbose_logging = False
|
verbose_logging = False
|
||||||
try:
|
try:
|
||||||
import calibre_plugins.deacsm.prefs as prefs
|
import calibre_plugins.deacsm.prefs as prefs
|
||||||
deacsmprefs = prefs.DeACSM_Prefs()
|
deacsmprefs = prefs.ACSMInput_Prefs()
|
||||||
verbose_logging = deacsmprefs["detailed_logging"]
|
verbose_logging = deacsmprefs["detailed_logging"]
|
||||||
except:
|
except:
|
||||||
pass
|
pass
|
||||||
@ -549,7 +549,7 @@ def updateLoanReturnData(fulfillmentResultToken, forceTestBehaviour=False):
|
|||||||
|
|
||||||
try:
|
try:
|
||||||
import calibre_plugins.deacsm.prefs as prefs # type: ignore
|
import calibre_plugins.deacsm.prefs as prefs # type: ignore
|
||||||
deacsmprefs = prefs.DeACSM_Prefs()
|
deacsmprefs = prefs.ACSMInput_Prefs()
|
||||||
except:
|
except:
|
||||||
print("Exception while reading config file")
|
print("Exception while reading config file")
|
||||||
return False
|
return False
|
||||||
@ -563,7 +563,7 @@ def updateLoanReturnData(fulfillmentResultToken, forceTestBehaviour=False):
|
|||||||
done = False
|
done = False
|
||||||
deacsmprefs["list_of_rented_books"].remove(book)
|
deacsmprefs["list_of_rented_books"].remove(book)
|
||||||
break
|
break
|
||||||
|
|
||||||
|
|
||||||
# Add all necessary information for a book return to the JSON array.
|
# Add all necessary information for a book return to the JSON array.
|
||||||
# The config widget can then read this and present a list of not-yet-returned
|
# The config widget can then read this and present a list of not-yet-returned
|
||||||
@ -583,7 +583,7 @@ def tryReturnBook(bookData):
|
|||||||
verbose_logging = False
|
verbose_logging = False
|
||||||
try:
|
try:
|
||||||
import calibre_plugins.deacsm.prefs as prefs
|
import calibre_plugins.deacsm.prefs as prefs
|
||||||
deacsmprefs = prefs.DeACSM_Prefs()
|
deacsmprefs = prefs.ACSMInput_Prefs()
|
||||||
verbose_logging = deacsmprefs["detailed_logging"]
|
verbose_logging = deacsmprefs["detailed_logging"]
|
||||||
except:
|
except:
|
||||||
pass
|
pass
|
||||||
@ -620,7 +620,7 @@ def tryReturnBook(bookData):
|
|||||||
|
|
||||||
etree.SubElement(full_text_xml, etree.QName(NSMAP["adept"], "signature")).text = signature
|
etree.SubElement(full_text_xml, etree.QName(NSMAP["adept"], "signature")).text = signature
|
||||||
|
|
||||||
print("Would notify server %s:" % (operatorURL + "/LoanReturn"))
|
print("Notifying loan return server %s" % (operatorURL + "/LoanReturn"))
|
||||||
doc_send = "<?xml version=\"1.0\"?>\n" + etree.tostring(full_text_xml, encoding="utf-8", pretty_print=True, xml_declaration=False).decode("utf-8")
|
doc_send = "<?xml version=\"1.0\"?>\n" + etree.tostring(full_text_xml, encoding="utf-8", pretty_print=True, xml_declaration=False).decode("utf-8")
|
||||||
if verbose_logging:
|
if verbose_logging:
|
||||||
print(doc_send)
|
print(doc_send)
|
||||||
@ -650,7 +650,7 @@ def performFulfillmentNotification(fulfillmentResultToken, forceOptional = False
|
|||||||
verbose_logging = False
|
verbose_logging = False
|
||||||
try:
|
try:
|
||||||
import calibre_plugins.deacsm.prefs as prefs
|
import calibre_plugins.deacsm.prefs as prefs
|
||||||
deacsmprefs = prefs.DeACSM_Prefs()
|
deacsmprefs = prefs.ACSMInput_Prefs()
|
||||||
verbose_logging = deacsmprefs["detailed_logging"]
|
verbose_logging = deacsmprefs["detailed_logging"]
|
||||||
except:
|
except:
|
||||||
pass
|
pass
|
||||||
|
@ -8,12 +8,20 @@ import os
|
|||||||
import traceback
|
import traceback
|
||||||
|
|
||||||
from calibre.utils.config import JSONConfig, config_dir # type: ignore
|
from calibre.utils.config import JSONConfig, config_dir # type: ignore
|
||||||
from calibre_plugins.deacsm.__init__ import PLUGIN_NAME # type: ignore
|
from calibre.constants import iswindows # type: ignore
|
||||||
|
|
||||||
|
|
||||||
class DeACSM_Prefs():
|
class ACSMInput_Prefs():
|
||||||
def __init__(self):
|
def __init__(self):
|
||||||
JSON_PATH = os.path.join("plugins", PLUGIN_NAME.strip().lower().replace(' ', '_') + '.json')
|
|
||||||
|
JSON_PATH_OLD = os.path.join("plugins", "deacsm.json")
|
||||||
|
JSON_PATH = os.path.join("plugins", "ACSMInput", "ACSMInput.json")
|
||||||
|
|
||||||
|
if os.path.exists(JSON_PATH_OLD) and not os.path.exists(JSON_PATH):
|
||||||
|
os.rename(JSON_PATH_OLD, JSON_PATH)
|
||||||
|
if not iswindows:
|
||||||
|
os.symlink(JSON_PATH_OLD, JSON_PATH)
|
||||||
|
|
||||||
self.deacsmprefs = JSONConfig(JSON_PATH)
|
self.deacsmprefs = JSONConfig(JSON_PATH)
|
||||||
|
|
||||||
self.deacsmprefs.defaults['configured'] = False
|
self.deacsmprefs.defaults['configured'] = False
|
||||||
@ -30,19 +38,15 @@ class DeACSM_Prefs():
|
|||||||
|
|
||||||
|
|
||||||
self.pluginsdir = os.path.join(config_dir,"plugins")
|
self.pluginsdir = os.path.join(config_dir,"plugins")
|
||||||
if not os.path.exists(self.pluginsdir):
|
self.maindir = os.path.join(self.pluginsdir,"ACSMInput")
|
||||||
os.mkdir(self.pluginsdir)
|
|
||||||
self.maindir = os.path.join(self.pluginsdir,"DeACSM")
|
|
||||||
if not os.path.exists(self.maindir):
|
|
||||||
os.mkdir(self.maindir)
|
|
||||||
self.accountdir = os.path.join(self.maindir,"account")
|
self.accountdir = os.path.join(self.maindir,"account")
|
||||||
if not os.path.exists(self.accountdir):
|
if not os.path.exists(self.accountdir):
|
||||||
os.mkdir(self.accountdir)
|
raise Exception("Why does the account folder not exist?")
|
||||||
|
|
||||||
# Default to the builtin UA
|
# Default to the builtin account path
|
||||||
self.deacsmprefs.defaults['path_to_account_data'] = self.accountdir
|
self.deacsmprefs.defaults['path_to_account_data'] = self.accountdir
|
||||||
|
|
||||||
|
|
||||||
def __getitem__(self,kind = None):
|
def __getitem__(self,kind = None):
|
||||||
if kind is not None:
|
if kind is not None:
|
||||||
return self.deacsmprefs[kind]
|
return self.deacsmprefs[kind]
|
||||||
|
Loading…
Reference in New Issue
Block a user