Initial commit

This commit is contained in:
Florian Bach 2021-09-19 16:20:56 +02:00
commit f0d9c07af3
7 changed files with 343 additions and 0 deletions

23
.github/workflows/main.yml vendored Normal file
View 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
View 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
View 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
View 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
View 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 ""

74
calibre-plugin/prefs.py Normal file
View 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