diff --git a/src/main.cpp b/src/main.cpp index 088a307..3524cce 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -18,67 +18,6 @@ #include #include -QMap readFb2MetadataFromZip(const QString& zipPath) -{ - QMap metadata; - QuaZip zip(zipPath); - - if (!zip.open(QuaZip::mdUnzip)) - { - qWarning() << "Failed to open ZIP archive"; - return metadata; - } - - int count = 0; - for (bool more = zip.goToFirstFile(); more; more = zip.goToNextFile()) - { - ++count; - - qWarning() << "*********" << count << "*********"; - - // Получение информации о файле - // QuaZipFileInfo fileInfo; - // if (zip.getCurrentFileInfo(&fileInfo)) - // { - // qDebug() << "File:" << fileInfo.name - // << "Size:" << fileInfo.uncompressedSize << "bytes" - // << "Compressed:" << fileInfo.compressedSize << "bytes" - // << "Modified:" << fileInfo.dateTime.toString(Qt::ISODate); - // } - - QString fb2FileName = zip.getCurrentFileName(); - qWarning() << fb2FileName; - // if (fb2FileName.isEmpty()) - // { - // qWarning() << "No FB2 file found in archive"; - // zip.close(); - // return metadata; - // } - - // // Читаем FB2 файл из архива - // // qWarning() << "Читаем FB2 файл из архива" << fb2FileName; - QuaZipFile fb2File(&zip); - // bool isOpen = fb2File.open(QIODevice::ReadOnly); - // int zipError = fb2File.getZipError(); - // if (!isOpen || zipError != UNZ_OK) - // { - // qWarning() << "Failed to open FB2 file in archive"; - // zip.close(); - // return metadata; - // } - - // // Парсим XML метаданные - // QXmlStreamReader fXmlBook(&fb2File); - // const auto data = parseFb2Metadata(fXmlBook); - - // qWarning() << data.title << data.authors << data.genres; - - // qWarning() << "*********" << count << "*********"; - } - - return metadata; -} - void fillBooksBD(uDBase& db) { try @@ -184,21 +123,20 @@ int main(int argc, char* argv[]) RestApiServer server(*db); server.start(8080); - // QString zipArzh = "f.fb2-631519-634744.zip"; QString zipArzh = "/home/alex/repos/exp/cpp-opds/f.fb2-631519-634744.zip"; - const auto books = readFb2MetadataFromZip(zipArzh); - // qWarning() << " books.count()" << books.count(); - auto z = ZipWrapper(zipArzh); - for (const auto& filename : z.getFiles()) + const auto books = z.work(); + + for (const auto& book : books) { - if (filename.endsWith(".fb2")) + try { - auto zf = z.getFile(filename).data(); - auto fb2File = FB2Extractor(*zf); - const auto book = fb2File.parse(); - // qWarning() << book.title; + addBook(*db, book.title, book.authors); + } + catch (const odb::exception& e) + { + std::cerr << "Error adding test data: " << e.what() << std::endl; } } @@ -213,6 +151,6 @@ int main(int argc, char* argv[]) // If you do not need a running Qt event loop, remove the call // to a.exec() or use the Non-Qt Plain C++ Application template. - qWarning() << "S EXIT"; + // qWarning() << "S EXIT"; return a.exec(); } diff --git a/src/restapi/restapiserver.cpp b/src/restapi/restapiserver.cpp index 7d11978..88b4662 100644 --- a/src/restapi/restapiserver.cpp +++ b/src/restapi/restapiserver.cpp @@ -112,19 +112,18 @@ QByteArray RestApiServer::processRequest(const QString& request) QJsonObject j; j["id"] = QString::number(book.id()); - // QJsonObject author; // author["id"] = QString::number(book.author()->id()); // author["fullName"] = book.author()->fullName(); // author["langCode"] = book.author()->langCode(); // j["author"] = author; - // // j["series"] = book.series()->serName(); - // // j["genre"] = book.genre()->name(); - // j["title"] = book.title(); + // j["series"] = book.series()->serName(); + // j["genre"] = book.genre()->name(); + j["title"] = book.title(); // j["year"] = book.year(); // j["lastModified"] = book.lastModified().toString(); // j["lang"] = book.lang(); - // jArray.push_back(j); + jArray.push_back(j); } auto jDoc = QJsonDocument(jArray); t.commit(); diff --git a/src/utils/fb2extractor.cpp b/src/utils/fb2extractor.cpp index da59847..72ddb61 100644 --- a/src/utils/fb2extractor.cpp +++ b/src/utils/fb2extractor.cpp @@ -16,6 +16,14 @@ FB2Extractor::~FB2Extractor() Fb2Metadata FB2Extractor::parse() { + bool isOpen = m_file.open(QIODevice::ReadOnly); + // int zipError = fb2File.getZipError(); + if (!isOpen) + { + qWarning() << "file in extractor is not open"; + return {}; + } + QXmlStreamReader xmlData(&m_file); Fb2Metadata meta; diff --git a/src/utils/fb2extractor.h b/src/utils/fb2extractor.h index 9b33a83..8966acb 100644 --- a/src/utils/fb2extractor.h +++ b/src/utils/fb2extractor.h @@ -11,9 +11,9 @@ struct Fb2Metadata { - QString title; // Название книги - QStringList authors; // Авторы - QStringList genres; // Жанры + QString title; // Название книги + QVector authors; // Авторы + QStringList genres; // Жанры }; Fb2Metadata UTILS_EXPORT parseFb2Metadata(QXmlStreamReader& sr); diff --git a/src/utils/zipwrapper.cpp b/src/utils/zipwrapper.cpp index 0822709..c8460c4 100644 --- a/src/utils/zipwrapper.cpp +++ b/src/utils/zipwrapper.cpp @@ -1,60 +1,142 @@ #include "zipwrapper.h" -#include +#include "fb2extractor.h" + #include -// zipwrapper.cpp -#include "zipwrapper.h" +namespace +{ +Fb2Metadata parse(QuaZipFile& m_file) +{ + bool isOpen = m_file.open(QIODevice::ReadOnly); + // int zipError = fb2File.getZipError(); + if (!isOpen) + { + qWarning() << "file in extractor is not open"; + return {}; + } -#include + QXmlStreamReader xmlData(&m_file); + + Fb2Metadata meta; + QString currentElement; + bool inTitleInfo = false; + bool inAuthor = false; + QString currentAuthor; + + while (!xmlData.atEnd()) + { + switch (xmlData.readNext()) + { + case QXmlStreamReader::StartElement: + currentElement = xmlData.name().toString(); + + if (currentElement == "title-info") + { + inTitleInfo = true; + } + else if (inTitleInfo) + { + if (currentElement == "book-title") + { + meta.title = xmlData.readElementText(); + } + else if (currentElement == "genre") + { + meta.genres << xmlData.readElementText(); + } + else if (currentElement == "author") + { + inAuthor = true; + currentAuthor.clear(); + } + else if (inAuthor && (currentElement == "first-name" || currentElement == "last-name" || currentElement == "middle-name")) + { + currentAuthor += xmlData.readElementText() + " "; + } + } + break; + + case QXmlStreamReader::EndElement: + if (xmlData.name().toString() == "title-info") + { + inTitleInfo = false; + } + else if (xmlData.name().toString() == "author" && inAuthor) + { + meta.authors << currentAuthor.trimmed(); + inAuthor = false; + } + break; + + case QXmlStreamReader::Characters: + // Обработка текста уже делается в readElementText() + break; + + default: + break; + } + + // Прерываем парсинг, если нашли все метаданные + if (!meta.title.isEmpty() && !meta.authors.isEmpty() && !meta.genres.isEmpty()) + { + break; + } + } + + if (xmlData.hasError()) + { + qWarning() << "XML parsing error:" << xmlData.errorString(); + } + + return meta; +} + +} // namespace ZipWrapper::ZipWrapper(const QString& zipFilePath) : - m_zip(new QuaZip(zipFilePath)) + m_zip(zipFilePath) { - if (!m_zip->open(QuaZip::mdUnzip)) - { - qWarning() << "Failed to open archive:" << zipFilePath - << "Error:" << m_zip->getZipError(); - } + m_zip.open(QuaZip::mdUnzip); + isOpen(); } ZipWrapper::~ZipWrapper() { - if (isOpen()) - { - m_zip->close(); - } + // В любом случае закрываем архив + m_zip.close(); } -QStringList ZipWrapper::getFiles() +QVector ZipWrapper::work() { if (!isOpen()) return {}; - return m_zip->getFileNameList(); -} -QSharedPointer ZipWrapper::getFile(const QString& filename) -{ - QSharedPointer file(new QuaZipFile(m_zip.data())); - - if (!file->open(QIODevice::ReadOnly)) + // int i = 0; + QVector parsedBooks; + for (bool more = m_zip.goToFirstFile(); more; more = m_zip.goToNextFile()) { - qWarning() << "Failed to open file:" << filename - << "Error:" << file->getZipError(); - return nullptr; + // ++i; + if (m_zip.getCurrentFileName().endsWith(".fb2")) + { + QuaZipFile fb2File(&m_zip); + + auto fb2Extr = parse(fb2File); + // qWarning() << i << ":" << fb2Extr.title << fb2Extr.authors << fb2Extr.genres; + parsedBooks.push_back(fb2Extr); + } + else + qWarning() << "Неизвестный файл" << &m_zip; } - for (bool more = m_zip->goToFirstFile(); more; more = m_zip->goToNextFile()) - if (m_zip->getCurrentFileName() == filename) - { - auto shqzf = QSharedPointer(new QuaZipFile(m_zip.data())); - return shqzf; - }; - - return file; + return parsedBooks; } -bool ZipWrapper::isOpen() const +bool ZipWrapper::isOpen() { - return m_zip && m_zip->isOpen(); + if (m_zip.isOpen()) + return true; + + qWarning() << "Не удалось открыть архив:" << m_zip.getZipName(); + return false; } diff --git a/src/utils/zipwrapper.h b/src/utils/zipwrapper.h index 72c5dca..9052812 100644 --- a/src/utils/zipwrapper.h +++ b/src/utils/zipwrapper.h @@ -1,29 +1,31 @@ -// zipwrapper.h #ifndef ZIPWRAPPER_H #define ZIPWRAPPER_H #include "utils_global.h" -#include +#include #include -#include -#include +#include -class QuaZip; -class QuaZipFile; + + +#include +#include // TODO для совместимости. Временно + +#include "fb2extractor.h" class UTILS_EXPORT ZipWrapper { public: - explicit ZipWrapper(const QString& zipFilePath); + ZipWrapper(const QString& zipFilePath); ~ZipWrapper(); - QStringList getFiles(); - QSharedPointer getFile(const QString& filename); - bool isOpen() const; + QVector work(); private: - QSharedPointer m_zip; + bool isOpen(); + + QuaZip m_zip; }; #endif // ZIPWRAPPER_H