diff --git a/epubreader/CMakeLists.txt b/epubreader/CMakeLists.txt index 793d68e..ccbebab 100644 --- a/epubreader/CMakeLists.txt +++ b/epubreader/CMakeLists.txt @@ -2,6 +2,7 @@ set(PLUGIN_DIR Epub) set(epubreader_SRCS epubreader.cpp + cbzreader.cpp epubreaderplugin.cpp quazip/JlCompress.cpp quazip/qioapi.cpp diff --git a/epubreader/cbzreader.cpp b/epubreader/cbzreader.cpp new file mode 100644 index 0000000..61d667d --- /dev/null +++ b/epubreader/cbzreader.cpp @@ -0,0 +1,171 @@ +/* Copyright 2015 Robert Schroll + * + * This file is part of Beru and is distributed under the terms of + * the GPL. See the file COPYING for full details. + */ + +#include "cbzreader.h" +#include +#include +#include +#include +#include +#include +#include +#include "quazip/quazip.h" +#include "quazip/quazipfile.h" +#include "../qhttpserver/qhttpresponse.h" + +QString guessMimeType(const QString &filename); + +CBZReader::CBZReader(QObject *parent) : + QObject(parent) +{ + this->zip = NULL; +} + +bool CBZReader::load(const QString &filename) +{ + if (this->zip != NULL) { + delete this->zip; + this->zip = NULL; + } + this->_hash = ""; + this->spine.clear(); + + this->zip = new QuaZip(filename); + if (!this->zip->open(QuaZip::mdUnzip)) { + delete this->zip; + this->zip = NULL; + return false; + } + if (!this->parse()) { + delete this->zip; + this->zip = NULL; + return false; + } + return true; +} + +bool CBZReader::parse() { + QList fileList = this->zip->getFileInfoList(); + foreach (const QuaZipFileInfo info, fileList) { + if (info.uncompressedSize > 0) + this->spine.append(info.name); + } + return true; +} + +QString CBZReader::hash() { + if (this->_hash != "") + return this->_hash; + + if (!this->zip || !this->zip->isOpen()) + return this->_hash; + + QByteArray CRCarray; + QDataStream CRCstream(&CRCarray, QIODevice::WriteOnly); + QList fileList = this->zip->getFileInfoList(); + foreach (const QuaZipFileInfo info, fileList) { + CRCstream << info.crc; + } + this->_hash = QCryptographicHash::hash(CRCarray, QCryptographicHash::Md5).toHex(); + return this->_hash; +} + +QString CBZReader::title() { + return ""; +} + +void CBZReader::serveComponent(const QString &filename, QHttpResponse *response) +{ + if (!this->zip || !this->zip->isOpen()) { + response->writeHead(500); + response->end("Epub file not open for reading"); + return; + } + + this->zip->setCurrentFile(filename); + QuaZipFile zfile(this->zip); + if (!zfile.open(QIODevice::ReadOnly)) { + response->writeHead(404); + response->end("Could not find \"" + filename + "\" in epub file"); + return; + } + + response->setHeader("Content-Type", guessMimeType(filename)); + response->writeHead(200); + // Important -- use write instead of end, so binary data doesn't get messed up! + response->write(zfile.readAll()); + response->end(); + zfile.close(); +} + +QVariantList CBZReader::getContents() +{ + QVariantList res; + for (int i=0; ispine.length(); i++) { + QVariantMap entry; + entry["title"] = "%PAGE% " + QString::number(i + 1); + entry["src"] = this->spine[i]; + res.append(entry); + } + emit contentsReady(res); + return res; +} + +void CBZReader::serveBookData(QHttpResponse *response) +{ + if (!this->zip || !this->zip->isOpen()) { + response->writeHead(500); + response->end("Epub file not open for reading"); + return; + } + + response->setHeader("Content-Type", guessMimeType("js")); + response->writeHead(200); + QJsonDocument spine(QJsonArray::fromStringList(this->spine)); + QJsonDocument contents(QJsonArray::fromVariantList(this->getContents())); + QString res = "var bookData = {" \ + "getComponents: function () { return %1; }, " \ + "getContents: function () { return %2; }, " \ + "getComponent: function (component) { return " \ + "\"\"; }, " \ + "getMetaData: function (key) { return ''; } }"; + response->write(res.arg(QString(spine.toJson()), QString(contents.toJson()))); + response->end(); +} + +QVariantMap CBZReader::getCoverInfo(int thumbsize, int fullsize) +{ + QVariantMap res; + if (!this->zip || !this->zip->isOpen()) + return res; + + res["title"] = "ZZZnone"; + res["author"] = ""; + res["authorsort"] = "zzznone"; + res["cover"] = "ZZZnone"; + + this->zip->setCurrentFile(this->spine[0]); + QuaZipFile zfile(this->zip); + if (!zfile.open(QIODevice::ReadOnly)) + return res; + + QImage coverimg; + if (!coverimg.loadFromData(zfile.readAll())) { + zfile.close(); + return res; + } + zfile.close(); + QByteArray byteArray; + QBuffer buffer(&byteArray); + coverimg.scaledToWidth(thumbsize, Qt::SmoothTransformation).save(&buffer, "PNG"); + res["cover"] = "data:image/png;base64," + QString(byteArray.toBase64()); + QByteArray byteArrayf; + QBuffer bufferf(&byteArrayf); + coverimg.scaledToWidth(fullsize, Qt::SmoothTransformation).save(&bufferf, "PNG"); + res["fullcover"] = "data:image/png;base64," + QString(byteArrayf.toBase64()); + return res; +} diff --git a/epubreader/cbzreader.h b/epubreader/cbzreader.h new file mode 100644 index 0000000..c489d33 --- /dev/null +++ b/epubreader/cbzreader.h @@ -0,0 +1,43 @@ +/* Copyright 2015 Robert Schroll + * + * This file is part of Beru and is distributed under the terms of + * the GPL. See the file COPYING for full details. + */ + +#ifndef CBZREADER_H +#define CBZREADER_H + +#include +#include +#include +#include "quazip/quazip.h" +#include "../qhttpserver/qhttpresponse.h" + +class CBZReader : public QObject +{ + Q_OBJECT + Q_PROPERTY(QString hash READ hash) + Q_PROPERTY(QString title READ title) +public: + explicit CBZReader(QObject *parent = 0); + QString hash(); + QString title(); + Q_INVOKABLE bool load(const QString &filename); + Q_INVOKABLE void serveBookData(QHttpResponse *response); + Q_INVOKABLE void serveComponent(const QString &filename, QHttpResponse *response); + Q_INVOKABLE QVariantMap getCoverInfo(int thumbsize, int fullsize); + +signals: + void contentsReady(QVariantList contents); + +private: + bool parse(); + QVariantList getContents(); + + QuaZip* zip; + QString _hash; + QStringList spine; + +}; + +#endif // CBZREADER_H diff --git a/epubreader/epubreaderplugin.cpp b/epubreader/epubreaderplugin.cpp index 9264b3c..d9e3525 100644 --- a/epubreader/epubreaderplugin.cpp +++ b/epubreader/epubreaderplugin.cpp @@ -6,9 +6,11 @@ #include "epubreaderplugin.h" #include "epubreader.h" +#include "cbzreader.h" #include void EpubReaderPlugin::registerTypes(const char *uri) { qmlRegisterType(uri, 1, 0, "EpubReader"); + qmlRegisterType(uri, 1, 0, "CBZReader"); } diff --git a/ui/BookPage.qml b/ui/BookPage.qml index af3815f..e52cb73 100644 --- a/ui/BookPage.qml +++ b/ui/BookPage.qml @@ -164,7 +164,7 @@ PageWithBottomEdge { model: contentsListModel delegate: Standard { text: (new Array(model.level + 1)).join(" ") + - model.title.replace(/(\n| )+/g, " ") + model.title.replace(/(\n| )+/g, " ").replace(/^%PAGE%/, i18n.tr("Page")) selected: bookPage.currentChapter == model.src onClicked: { Messaging.sendMessage("NavigateChapter", model.src) @@ -613,7 +613,7 @@ PageWithBottomEdge { Messaging.registerHandler("PageChange", onPageChange) Messaging.registerHandler("Styles", bookStyles.load) Messaging.registerHandler("Ready", onReady) - server.epub.contentsReady.connect(parseContents) + server.reader.contentsReady.connect(parseContents) onWidthChanged.connect(windowSizeChanged) onHeightChanged.connect(windowSizeChanged) } diff --git a/ui/CMakeLists.txt b/ui/CMakeLists.txt index df5876a..68eb793 100644 --- a/ui/CMakeLists.txt +++ b/ui/CMakeLists.txt @@ -8,6 +8,7 @@ set(UI_SRC_FILES main.qml qmlmessaging.js qmlmessaging-userscript.js + Reader.qml Server.qml components/FloatingButton.qml components/OptionSelector.qml diff --git a/ui/LocalBooks.qml b/ui/LocalBooks.qml index feb5f7e..fd486e0 100644 --- a/ui/LocalBooks.qml +++ b/ui/LocalBooks.qml @@ -10,7 +10,6 @@ import QtGraphicalEffects 1.0 import Ubuntu.Components 1.1 import Ubuntu.Components.ListItems 1.0 import Ubuntu.Components.Popups 1.0 -import Epub 1.0 import "components" @@ -52,7 +51,7 @@ Page { } function fileToTitle(filename) { - return filename.replace(/\.epub$/, "").replace(/_/g, " ") + return filename.replace(/\.epub$/, "").replace(/\.cbz$/, "").replace(/_/g, " ") } // New items are given a lastread time of now, since these are probably @@ -74,7 +73,7 @@ Page { function addBookDir() { var db = openDatabase() db.transaction(function (tx) { - var files = filesystem.listDir(bookdir, ["*.epub"]) + var files = filesystem.listDir(bookdir, ["*.epub", "*.cbz"]) for (var i=0; i