File indexing completed on 2025-01-26 04:24:56
0001 /* Copyright 2015 Robert Schroll 0002 * 0003 * This file is part of Beru and is distributed under the terms of 0004 * the GPL. See the file COPYING for full details. 0005 */ 0006 0007 #include "cbzreader.h" 0008 #include <QJsonObject> 0009 #include <QJsonArray> 0010 #include <QJsonDocument> 0011 #include <QtGui/QImage> 0012 #include <QBuffer> 0013 #include <QDir> 0014 #include <QCryptographicHash> 0015 #include "quazip/quazip.h" 0016 #include "quazip/quazipfile.h" 0017 #include "../qhttpserver/qhttpresponse.h" 0018 0019 QString guessMimeType(const QString &filename); 0020 0021 CBZReader::CBZReader(QObject *parent) : 0022 QObject(parent) 0023 { 0024 this->zip = NULL; 0025 } 0026 0027 bool CBZReader::load(const QString &filename) 0028 { 0029 if (this->zip != NULL) { 0030 delete this->zip; 0031 this->zip = NULL; 0032 } 0033 this->_hash = ""; 0034 this->spine.clear(); 0035 0036 this->zip = new QuaZip(filename); 0037 if (!this->zip->open(QuaZip::mdUnzip)) { 0038 delete this->zip; 0039 this->zip = NULL; 0040 return false; 0041 } 0042 if (!this->parse()) { 0043 delete this->zip; 0044 this->zip = NULL; 0045 return false; 0046 } 0047 return true; 0048 } 0049 0050 bool CBZReader::parse() { 0051 QList<QuaZipFileInfo> fileList = this->zip->getFileInfoList(); 0052 foreach (const QuaZipFileInfo info, fileList) { 0053 if (info.uncompressedSize > 0) 0054 this->spine.append(info.name); 0055 } 0056 return true; 0057 } 0058 0059 QString CBZReader::hash() { 0060 if (this->_hash != "") 0061 return this->_hash; 0062 0063 if (!this->zip || !this->zip->isOpen()) 0064 return this->_hash; 0065 0066 QByteArray CRCarray; 0067 QDataStream CRCstream(&CRCarray, QIODevice::WriteOnly); 0068 QList<QuaZipFileInfo> fileList = this->zip->getFileInfoList(); 0069 foreach (const QuaZipFileInfo info, fileList) { 0070 CRCstream << info.crc; 0071 } 0072 this->_hash = QCryptographicHash::hash(CRCarray, QCryptographicHash::Md5).toHex(); 0073 return this->_hash; 0074 } 0075 0076 QString CBZReader::title() { 0077 return ""; 0078 } 0079 0080 void CBZReader::serveComponent(const QString &filename, QHttpResponse *response) 0081 { 0082 if (!this->zip || !this->zip->isOpen()) { 0083 response->writeHead(500); 0084 response->end("Epub file not open for reading"); 0085 return; 0086 } 0087 0088 this->zip->setCurrentFile(filename); 0089 QuaZipFile zfile(this->zip); 0090 if (!zfile.open(QIODevice::ReadOnly)) { 0091 response->writeHead(404); 0092 response->end("Could not find \"" + filename + "\" in epub file"); 0093 return; 0094 } 0095 0096 response->setHeader("Content-Type", guessMimeType(filename)); 0097 response->writeHead(200); 0098 // Important -- use write instead of end, so binary data doesn't get messed up! 0099 response->write(zfile.readAll()); 0100 response->end(); 0101 zfile.close(); 0102 } 0103 0104 QVariantList CBZReader::getContents() 0105 { 0106 QVariantList res; 0107 for (int i=0; i<this->spine.length(); i++) { 0108 QVariantMap entry; 0109 entry["title"] = "%PAGE% " + QString::number(i + 1); 0110 entry["src"] = this->spine[i]; 0111 res.append(entry); 0112 } 0113 Q_EMIT contentsReady(res); 0114 return res; 0115 } 0116 0117 void CBZReader::serveBookData(QHttpResponse *response) 0118 { 0119 if (!this->zip || !this->zip->isOpen()) { 0120 response->writeHead(500); 0121 response->end("Epub file not open for reading"); 0122 return; 0123 } 0124 0125 response->setHeader("Content-Type", guessMimeType("js")); 0126 response->writeHead(200); 0127 QJsonDocument spine(QJsonArray::fromStringList(this->spine)); 0128 QJsonDocument contents(QJsonArray::fromVariantList(this->getContents())); 0129 QString res = "var bookData = {" \ 0130 "getComponents: function () { return %1; }, " \ 0131 "getContents: function () { return %2; }, " \ 0132 "getComponent: function (component) { return " \ 0133 "\"<img style='display: block; margin: auto; max-height: 100% !important' src='\"" \ 0134 "+ component.replace(/\"/g, \""\").replace(/'/g, \"'\") + \"' />\"; }, " \ 0135 "getMetaData: function (key) { return ''; } }"; 0136 response->write(res.arg(QString(spine.toJson()), QString(contents.toJson()))); 0137 response->end(); 0138 } 0139 0140 QVariantMap CBZReader::getCoverInfo(int thumbsize, int fullsize) 0141 { 0142 QVariantMap res; 0143 if (!this->zip || !this->zip->isOpen()) 0144 return res; 0145 0146 res["title"] = "ZZZnone"; 0147 res["author"] = ""; 0148 res["authorsort"] = "zzznone"; 0149 res["cover"] = "ZZZnone"; 0150 0151 this->zip->setCurrentFile(this->spine[0]); 0152 QuaZipFile zfile(this->zip); 0153 if (!zfile.open(QIODevice::ReadOnly)) 0154 return res; 0155 0156 QImage coverimg; 0157 if (!coverimg.loadFromData(zfile.readAll())) { 0158 zfile.close(); 0159 return res; 0160 } 0161 zfile.close(); 0162 QByteArray byteArray; 0163 QBuffer buffer(&byteArray); 0164 coverimg.scaledToWidth(thumbsize, Qt::SmoothTransformation).save(&buffer, "PNG"); 0165 res["cover"] = "data:image/png;base64," + QString(byteArray.toBase64()); 0166 QByteArray byteArrayf; 0167 QBuffer bufferf(&byteArrayf); 0168 coverimg.scaledToWidth(fullsize, Qt::SmoothTransformation).save(&bufferf, "PNG"); 0169 res["fullcover"] = "data:image/png;base64," + QString(byteArrayf.toBase64()); 0170 return res; 0171 }