mirror of
https://github.com/Leseratte10/acsm-calibre-plugin.git
synced 2024-12-22 17:29:56 +06:00
Initial commit
This commit is contained in:
commit
f0d9c07af3
23
.github/workflows/main.yml
vendored
Normal file
23
.github/workflows/main.yml
vendored
Normal file
@ -0,0 +1,23 @@
|
|||||||
|
name: Build binaries
|
||||||
|
|
||||||
|
on:
|
||||||
|
push:
|
||||||
|
branches: [ master ]
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
build-linux:
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
steps:
|
||||||
|
- uses: actions/checkout@v2
|
||||||
|
- name: Compile
|
||||||
|
run: |
|
||||||
|
DOCKER_BUILDKIT=1 docker build -o final .
|
||||||
|
cp calibre-plugin/* final/stretch/
|
||||||
|
|
||||||
|
- name: Upload
|
||||||
|
uses: actions/upload-artifact@v2
|
||||||
|
with:
|
||||||
|
name: linux
|
||||||
|
path: |
|
||||||
|
final/stretch/
|
||||||
|
|
67
Dockerfile
Normal file
67
Dockerfile
Normal file
@ -0,0 +1,67 @@
|
|||||||
|
# Clear cache:
|
||||||
|
# docker builder prune
|
||||||
|
|
||||||
|
# Build:
|
||||||
|
# DOCKER_BUILDKIT=1 docker build -o output .
|
||||||
|
# for Windows, use
|
||||||
|
# { "features": { "buildkit": true } }
|
||||||
|
# instead of the environment variable
|
||||||
|
|
||||||
|
# Build a container
|
||||||
|
#FROM debian:bullseye as main_bullseye
|
||||||
|
#ENV DEBIAN_FRONTEND="noninteractive" TZ="Europe/London"
|
||||||
|
#RUN apt-get update -y && apt-get install -y \
|
||||||
|
# git && apt-get install -y --no-install-recommends make g++ pkg-config qtbase5-dev libssl-dev libzip-dev
|
||||||
|
#
|
||||||
|
#FROM debian:buster as main_buster
|
||||||
|
#ENV DEBIAN_FRONTEND="noninteractive" TZ="Europe/London"
|
||||||
|
#RUN apt-get update -y && apt-get install -y \
|
||||||
|
# git && apt-get install -y --no-install-recommends make g++ pkg-config qtbase5-dev libssl-dev libzip-dev
|
||||||
|
|
||||||
|
FROM debian:stretch as main_stretch
|
||||||
|
ENV DEBIAN_FRONTEND="noninteractive" TZ="Europe/London"
|
||||||
|
RUN apt-get update -y && apt-get install -y \
|
||||||
|
git && apt-get install -y --no-install-recommends make g++ pkg-config qtbase5-dev libssl-dev libzip-dev
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
#FROM main_bullseye as compile_bullseye
|
||||||
|
#RUN git clone git://soutade.fr/libgourou.git && \
|
||||||
|
# cd libgourou && \
|
||||||
|
# make BUILD_SHARED=1 BUILD_UTILS=1
|
||||||
|
# mkdir final && \
|
||||||
|
# cp utils/acsmdownloader final/ && \
|
||||||
|
# cp utils/adept_activate final/ && \
|
||||||
|
# cp libgourou.so final/ && \
|
||||||
|
# cp /usr/lib/x86_64-linux-gnu/libzip.so.4 final/ && \
|
||||||
|
# true
|
||||||
|
#
|
||||||
|
#FROM main_buster as compile_buster
|
||||||
|
#RUN git clone git://soutade.fr/libgourou.git && \
|
||||||
|
# cd libgourou && \
|
||||||
|
# make BUILD_SHARED=1 BUILD_UTILS=1
|
||||||
|
# mkdir final && \
|
||||||
|
# cp utils/acsmdownloader final/ && \
|
||||||
|
# cp utils/adept_activate final/ && \
|
||||||
|
# cp libgourou.so final/ && \
|
||||||
|
# cp /usr/lib/x86_64-linux-gnu/libzip.so.4 final/ && \
|
||||||
|
# true
|
||||||
|
|
||||||
|
FROM main_stretch as compile_stretch
|
||||||
|
RUN git clone git://soutade.fr/libgourou.git && \
|
||||||
|
cd libgourou && \
|
||||||
|
make BUILD_SHARED=1 BUILD_UTILS=1 && \
|
||||||
|
mkdir final && \
|
||||||
|
cp utils/acsmdownloader final/ && \
|
||||||
|
cp utils/adept_activate final/ && \
|
||||||
|
cp libgourou.so final/ && \
|
||||||
|
cp /usr/lib/x86_64-linux-gnu/libzip.so.4 final/ && \
|
||||||
|
true
|
||||||
|
|
||||||
|
|
||||||
|
FROM scratch AS export-stage
|
||||||
|
#COPY --from=compile_bullseye /libgourou/final/ /bullseye/
|
||||||
|
#COPY --from=compile_buster /libgourou/final/ /buster/
|
||||||
|
COPY --from=compile_stretch /libgourou/final/ /stretch/
|
||||||
|
|
8
README
Normal file
8
README
Normal file
@ -0,0 +1,8 @@
|
|||||||
|
- Linux x86_64 only
|
||||||
|
|
||||||
|
- Debian Stretch or newer (or comparable)
|
||||||
|
|
||||||
|
- You need these packages:
|
||||||
|
- qtbase5-dev
|
||||||
|
|
||||||
|
|
108
calibre-plugin/__init__.py
Normal file
108
calibre-plugin/__init__.py
Normal file
@ -0,0 +1,108 @@
|
|||||||
|
#!/usr/bin/env python3
|
||||||
|
# -*- coding: utf-8 -*-
|
||||||
|
|
||||||
|
# Calibre plugin for ACSM files.
|
||||||
|
|
||||||
|
|
||||||
|
from calibre.customize import FileTypePlugin # type: ignore
|
||||||
|
__version__ = '0.0.1'
|
||||||
|
|
||||||
|
PLUGIN_NAME = "DeACSM"
|
||||||
|
PLUGIN_VERSION_TUPLE = tuple([int(x) for x in __version__.split(".")])
|
||||||
|
PLUGIN_VERSION = ".".join([str(x)for x in PLUGIN_VERSION_TUPLE])
|
||||||
|
|
||||||
|
import os
|
||||||
|
import traceback
|
||||||
|
|
||||||
|
from calibre.utils.config import config_dir # type: ignore
|
||||||
|
from calibre.constants import iswindows, isosx # type: ignore
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
class DeACSM(FileTypePlugin):
|
||||||
|
name = PLUGIN_NAME
|
||||||
|
description = "Takes an Adobe ACSM file and converts that into a useable EPUB file"
|
||||||
|
supported_platforms = ['linux']
|
||||||
|
author = "Leseratte10"
|
||||||
|
version = PLUGIN_VERSION_TUPLE
|
||||||
|
minimum_calibre_version = (5, 0, 0)
|
||||||
|
file_types = set(['acsm'])
|
||||||
|
on_import = True
|
||||||
|
on_preprocess = True
|
||||||
|
priority = 2000
|
||||||
|
|
||||||
|
def initialize(self):
|
||||||
|
"""
|
||||||
|
Dynamic modules can't be imported/loaded from a zipfile.
|
||||||
|
So this routine will extract the appropriate
|
||||||
|
library for the target OS and copy it to the 'alfcrypto' subdirectory of
|
||||||
|
calibre's configuration directory. That 'alfcrypto' directory is then
|
||||||
|
inserted into the syspath (as the very first entry) in the run function
|
||||||
|
so the CDLL stuff will work in the alfcrypto.py script.
|
||||||
|
The extraction only happens once per version of the plugin
|
||||||
|
Also perform upgrade of preferences once per version
|
||||||
|
"""
|
||||||
|
try:
|
||||||
|
self.pluginsdir = os.path.join(config_dir,"plugins")
|
||||||
|
if not os.path.exists(self.pluginsdir):
|
||||||
|
os.mkdir(self.pluginsdir)
|
||||||
|
self.maindir = os.path.join(self.pluginsdir,"DeACSM")
|
||||||
|
if not os.path.exists(self.maindir):
|
||||||
|
os.mkdir(self.maindir)
|
||||||
|
|
||||||
|
# only continue if we've never run this version of the plugin before
|
||||||
|
self.verdir = os.path.join(self.maindir,PLUGIN_VERSION)
|
||||||
|
if not os.path.exists(self.verdir):
|
||||||
|
if iswindows:
|
||||||
|
print("Windows not supported yet")
|
||||||
|
return
|
||||||
|
elif isosx:
|
||||||
|
print("Mac not supported yet")
|
||||||
|
return
|
||||||
|
else:
|
||||||
|
names = ["acsmdownloader", "adept_activate", "libgourou.so", "libzip.so.4"]
|
||||||
|
|
||||||
|
lib_dict = self.load_resources(names)
|
||||||
|
print("{0} v{1}: Copying needed library files from plugin's zip".format(PLUGIN_NAME, PLUGIN_VERSION))
|
||||||
|
|
||||||
|
for entry, data in lib_dict.items():
|
||||||
|
file_path = os.path.join(self.alfdir, entry)
|
||||||
|
try:
|
||||||
|
os.remove(file_path)
|
||||||
|
except:
|
||||||
|
pass
|
||||||
|
|
||||||
|
try:
|
||||||
|
open(file_path,'wb').write(data)
|
||||||
|
except:
|
||||||
|
print("{0} v{1}: Exception when copying needed library files".format(PLUGIN_NAME, PLUGIN_VERSION))
|
||||||
|
traceback.print_exc()
|
||||||
|
pass
|
||||||
|
|
||||||
|
# mark that this version has been initialized
|
||||||
|
os.mkdir(self.verdir)
|
||||||
|
except Exception as e:
|
||||||
|
traceback.print_exc()
|
||||||
|
raise
|
||||||
|
|
||||||
|
def is_customizable(self):
|
||||||
|
return True
|
||||||
|
|
||||||
|
def config_widget(self):
|
||||||
|
import calibre_plugins.deacsm.config as config # type: ignore
|
||||||
|
return config.ConfigWidget(self.plugin_path)
|
||||||
|
|
||||||
|
def save_settings(self, config_widget):
|
||||||
|
config_widget.save_settings()
|
||||||
|
|
||||||
|
def run(self, path_to_ebook: str):
|
||||||
|
# This code gets called by Calibre with a path to the new book file.
|
||||||
|
# We need to check if it's an ACSM file
|
||||||
|
|
||||||
|
print("{0} v{1}: Trying to parse file {2}".format(PLUGIN_NAME, PLUGIN_VERSION, os.path.basename(path_to_ebook)))
|
||||||
|
|
||||||
|
print("{0} v{1}: Failed, return original ...".format(PLUGIN_NAME, PLUGIN_VERSION))
|
||||||
|
return path_to_ebook
|
||||||
|
|
||||||
|
|
||||||
|
|
63
calibre-plugin/config.py
Normal file
63
calibre-plugin/config.py
Normal file
@ -0,0 +1,63 @@
|
|||||||
|
#!/usr/bin/env python3
|
||||||
|
# -*- coding: utf-8 -*-
|
||||||
|
|
||||||
|
# pyright: reportUndefinedVariable=false
|
||||||
|
|
||||||
|
|
||||||
|
from PyQt5.Qt import (Qt, QWidget, QHBoxLayout, QVBoxLayout, QLabel, QLineEdit,
|
||||||
|
QGroupBox, QPushButton, QListWidget, QListWidgetItem,
|
||||||
|
QAbstractItemView, QIcon, QDialog, QDialogButtonBox, QUrl)
|
||||||
|
|
||||||
|
from PyQt5 import Qt as QtGui
|
||||||
|
from zipfile import ZipFile
|
||||||
|
|
||||||
|
# calibre modules and constants.
|
||||||
|
from calibre.gui2 import (question_dialog, info_dialog) # type: ignore
|
||||||
|
# modules from this plugin's zipfile.
|
||||||
|
from calibre_plugins.deacsm.__init__ import PLUGIN_NAME, PLUGIN_VERSION # type: ignore
|
||||||
|
import calibre_plugins.deacsm.prefs as prefs # type: ignore
|
||||||
|
|
||||||
|
|
||||||
|
class ConfigWidget(QWidget):
|
||||||
|
def __init__(self, plugin_path):
|
||||||
|
QWidget.__init__(self)
|
||||||
|
|
||||||
|
self.plugin_path = plugin_path
|
||||||
|
|
||||||
|
# get the prefs
|
||||||
|
self.deacsmprefs = prefs.DeACSM_Prefs()
|
||||||
|
|
||||||
|
# make a local copy
|
||||||
|
self.tempdeacsmprefs = {}
|
||||||
|
self.tempdeacsmprefs['path_to_account_data'] = self.deacsmprefs['path_to_account_data']
|
||||||
|
|
||||||
|
|
||||||
|
# Start Qt Gui dialog layout
|
||||||
|
layout = QVBoxLayout(self)
|
||||||
|
self.setLayout(layout)
|
||||||
|
|
||||||
|
|
||||||
|
ua_group_box = QGroupBox(_('Path to account:'), self)
|
||||||
|
layout.addWidget(ua_group_box)
|
||||||
|
ua_group_box_layout = QVBoxLayout()
|
||||||
|
ua_group_box.setLayout(ua_group_box_layout)
|
||||||
|
|
||||||
|
self.txtboxUA = QtGui.QLineEdit(self)
|
||||||
|
self.txtboxUA.setToolTip(_("Enter folder path to account data"))
|
||||||
|
self.txtboxUA.setText(self.tempdeacsmprefs['path_to_account_data'])
|
||||||
|
ua_group_box_layout.addWidget(self.txtboxUA)
|
||||||
|
|
||||||
|
|
||||||
|
self.resize(self.sizeHint())
|
||||||
|
|
||||||
|
|
||||||
|
def save_settings(self):
|
||||||
|
self.deacsmprefs.set('path_to_account_data', self.txtboxUA.text())
|
||||||
|
self.deacsmprefs.writeprefs()
|
||||||
|
|
||||||
|
def load_resource(self, name):
|
||||||
|
with ZipFile(self.plugin_path, 'r') as zf:
|
||||||
|
if name in zf.namelist():
|
||||||
|
return zf.read(name).decode('utf-8')
|
||||||
|
return ""
|
||||||
|
|
0
calibre-plugin/plugin-import-name-deacsm.txt
Normal file
0
calibre-plugin/plugin-import-name-deacsm.txt
Normal file
74
calibre-plugin/prefs.py
Normal file
74
calibre-plugin/prefs.py
Normal file
@ -0,0 +1,74 @@
|
|||||||
|
#!/usr/bin/env python3
|
||||||
|
# -*- coding: utf-8 -*-
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
# Standard Python modules.
|
||||||
|
import os
|
||||||
|
import traceback
|
||||||
|
|
||||||
|
from calibre.utils.config import JSONConfig, config_dir # type: ignore
|
||||||
|
from calibre_plugins.deacsm.__init__ import PLUGIN_NAME # type: ignore
|
||||||
|
from calibre.constants import isosx, islinux # type: ignore
|
||||||
|
|
||||||
|
|
||||||
|
class DeACSM_Prefs():
|
||||||
|
def __init__(self):
|
||||||
|
JSON_PATH = os.path.join("plugins", PLUGIN_NAME.strip().lower().replace(' ', '_') + '.json')
|
||||||
|
self.deacsmprefs = JSONConfig(JSON_PATH)
|
||||||
|
|
||||||
|
self.deacsmprefs.defaults['configured'] = False
|
||||||
|
|
||||||
|
self.pluginsdir = os.path.join(config_dir,"plugins")
|
||||||
|
if not os.path.exists(self.pluginsdir):
|
||||||
|
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")
|
||||||
|
if not os.path.exists(self.accountdir):
|
||||||
|
os.mkdir(self.accountdir)
|
||||||
|
|
||||||
|
# Default to the builtin UA
|
||||||
|
self.deacsmprefs.defaults['path_to_account_data'] = self.accountdir
|
||||||
|
|
||||||
|
|
||||||
|
def __getitem__(self,kind = None):
|
||||||
|
if kind is not None:
|
||||||
|
return self.deacsmprefs[kind]
|
||||||
|
return self.deacsmprefs
|
||||||
|
|
||||||
|
def set(self, kind, value):
|
||||||
|
self.deacsmprefs[kind] = value
|
||||||
|
|
||||||
|
def writeprefs(self,value = True):
|
||||||
|
self.deacsmprefs['configured'] = value
|
||||||
|
|
||||||
|
def addnamedvaluetoprefs(self, prefkind, keyname, keyvalue):
|
||||||
|
try:
|
||||||
|
if keyvalue not in self.deacsmprefs[prefkind].values():
|
||||||
|
# ensure that the keyname is unique
|
||||||
|
# by adding a number (starting with 2) to the name if it is not
|
||||||
|
namecount = 1
|
||||||
|
newname = keyname
|
||||||
|
while newname in self.deacsmprefs[prefkind]:
|
||||||
|
namecount += 1
|
||||||
|
newname = "{0:s}_{1:d}".format(keyname,namecount)
|
||||||
|
# add to the preferences
|
||||||
|
self.deacsmprefs[prefkind][newname] = keyvalue
|
||||||
|
return (True, newname)
|
||||||
|
except:
|
||||||
|
traceback.print_exc()
|
||||||
|
pass
|
||||||
|
return (False, keyname)
|
||||||
|
|
||||||
|
def addvaluetoprefs(self, prefkind, prefsvalue):
|
||||||
|
# ensure the keyvalue isn't already in the preferences
|
||||||
|
try:
|
||||||
|
if prefsvalue not in self.deacsmprefs[prefkind]:
|
||||||
|
self.deacsmprefs[prefkind].append(prefsvalue)
|
||||||
|
return True
|
||||||
|
except:
|
||||||
|
traceback.print_exc()
|
||||||
|
return False
|
||||||
|
|
Loading…
Reference in New Issue
Block a user