|
|
@@ -0,0 +1,226 @@
|
|
|
+#include "book.h"
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+// void Book::extractEPUBMetadata() {
|
|
|
+// try {
|
|
|
+// xmlpp::DomParser parser;
|
|
|
+// parser.parse_file(file_path);
|
|
|
+// if (parser) {
|
|
|
+// auto root = parser.get_document()->get_root_node();
|
|
|
+// auto metadataNode = root->get_first_child("metadata");
|
|
|
+
|
|
|
+// if (metadataNode) {
|
|
|
+// auto titleNode = metadataNode->get_first_child("dc:title");
|
|
|
+// auto authorNode = metadataNode->get_first_child("dc:creator");
|
|
|
+
|
|
|
+// if (titleNode) {
|
|
|
+// title = titleNode->get_child_text()->get_content();
|
|
|
+// }
|
|
|
+// if (authorNode) {
|
|
|
+// authors = authorNode->get_child_text()->get_content();
|
|
|
+// }
|
|
|
+// }
|
|
|
+
|
|
|
+// // Extract cover from EPUB (usually a reference to the image in the manifest)
|
|
|
+// auto manifestNode = root->get_first_child("manifest");
|
|
|
+// if (manifestNode) {
|
|
|
+// for (auto child : manifestNode->get_children()) {
|
|
|
+// auto element = dynamic_cast<xmlpp::Element*>(child);
|
|
|
+// if (element && element->get_attribute_value("id") == "cover-image") {
|
|
|
+// std::string href = element->get_attribute_value("href");
|
|
|
+// cover_image = Gdk::Pixbuf::create_from_file(href);
|
|
|
+// break;
|
|
|
+// }
|
|
|
+// }
|
|
|
+// }
|
|
|
+// }
|
|
|
+// } catch (const std::exception& ex) {
|
|
|
+// std::cerr << "Error extracting EPUB metadata: " << ex.what() << std::endl;
|
|
|
+// }
|
|
|
+// }
|
|
|
+
|
|
|
+void Book::extractPDFMetadata() {
|
|
|
+ PopplerDocument* document = poppler_document_new_from_file(("file://" + file_path).c_str(), nullptr, nullptr);
|
|
|
+ if (document) {
|
|
|
+ title = poppler_document_get_title(document);
|
|
|
+ authors = poppler_document_get_author(document);
|
|
|
+
|
|
|
+ cover_image = render_pdf_page_to_pixbuf(file_path, 0);
|
|
|
+
|
|
|
+ g_object_unref(document);
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
+Glib::RefPtr<Gdk::Pixbuf> Book::render_pdf_page_to_pixbuf(const std::string& pdf_file, int page_num) {
|
|
|
+ PopplerDocument* document = poppler_document_new_from_file(("file://" + pdf_file).c_str(), nullptr, nullptr);
|
|
|
+ if (!document) {
|
|
|
+ std::cerr << "Error loading PDF file." << std::endl;
|
|
|
+ return Glib::RefPtr<Gdk::Pixbuf>();
|
|
|
+ }
|
|
|
+
|
|
|
+ PopplerPage* page = poppler_document_get_page(document, page_num);
|
|
|
+ if (!page) {
|
|
|
+ std::cerr << "Error loading PDF page." << std::endl;
|
|
|
+ g_object_unref(document);
|
|
|
+ return Glib::RefPtr<Gdk::Pixbuf>();
|
|
|
+ }
|
|
|
+
|
|
|
+ int width = 150;
|
|
|
+ int height = 200;
|
|
|
+ Cairo::RefPtr<Cairo::ImageSurface> surface = Cairo::ImageSurface::create(Cairo::FORMAT_RGB24, width, height);
|
|
|
+ Cairo::RefPtr<Cairo::Context> cr = Cairo::Context::create(surface);
|
|
|
+
|
|
|
+ poppler_page_render(page, cr->cobj());
|
|
|
+
|
|
|
+ Glib::RefPtr<Gdk::Pixbuf> pixbuf = create_pixbuf_from_cairo_surface(surface);
|
|
|
+
|
|
|
+ g_object_unref(page);
|
|
|
+ g_object_unref(document);
|
|
|
+
|
|
|
+ return pixbuf;
|
|
|
+}
|
|
|
+
|
|
|
+void Book::loadMetadata() {
|
|
|
+ if (file_path.find(".pdf") != std::string::npos) {
|
|
|
+ extractPDFMetadata();
|
|
|
+ } else if (file_path.find(".epub") != std::string::npos) {
|
|
|
+ extractEPUBMetadata();
|
|
|
+ } else {
|
|
|
+ std::cerr << "Unsupported file format: " << file_path << std::endl;
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
+void Book::loadCover() {
|
|
|
+ // This can be handled inside `extractPDFMetadata` and `extractEPUBMetadata`
|
|
|
+}
|
|
|
+
|
|
|
+// Initialize the SQLite database and create the necessary table
|
|
|
+void Book::initDatabase() {
|
|
|
+ sqlite3* db;
|
|
|
+ int rc = sqlite3_open("bookcollection.db", &db);
|
|
|
+ if (rc != SQLITE_OK) {
|
|
|
+ std::cerr << "Cannot open database: " << sqlite3_errmsg(db) << std::endl;
|
|
|
+ return;
|
|
|
+ }
|
|
|
+
|
|
|
+ const char* createTableSQL =
|
|
|
+ "CREATE TABLE IF NOT EXISTS books ("
|
|
|
+ "id INTEGER PRIMARY KEY, "
|
|
|
+ "title TEXT, "
|
|
|
+ "authors TEXT, "
|
|
|
+ "isbn TEXT, "
|
|
|
+ "file_path TEXT, "
|
|
|
+ "cover BLOB);";
|
|
|
+
|
|
|
+ char* errorMessage;
|
|
|
+ rc = sqlite3_exec(db, createTableSQL, 0, 0, &errorMessage);
|
|
|
+ if (rc != SQLITE_OK) {
|
|
|
+ std::cerr << "Failed to create table: " << errorMessage << std::endl;
|
|
|
+ sqlite3_free(errorMessage);
|
|
|
+ }
|
|
|
+
|
|
|
+ sqlite3_close(db);
|
|
|
+}
|
|
|
+
|
|
|
+// Save the book's metadata and cover image to the SQLite database
|
|
|
+void Book::saveToDatabase() {
|
|
|
+ sqlite3* db;
|
|
|
+ sqlite3_open("bookcollection.db", &db);
|
|
|
+
|
|
|
+ const char* insertSQL = "INSERT INTO books (title, authors, isbn, file_path, cover) VALUES (?, ?, ?, ?, ?);";
|
|
|
+ sqlite3_stmt* stmt;
|
|
|
+ sqlite3_prepare_v2(db, insertSQL, -1, &stmt, nullptr);
|
|
|
+
|
|
|
+ sqlite3_bind_text(stmt, 1, title.c_str(), -1, SQLITE_STATIC);
|
|
|
+ sqlite3_bind_text(stmt, 2, authors.c_str(), -1, SQLITE_STATIC);
|
|
|
+ sqlite3_bind_text(stmt, 3, isbn.c_str(), -1, SQLITE_STATIC);
|
|
|
+ sqlite3_bind_text(stmt, 4, file_path.c_str(), -1, SQLITE_STATIC);
|
|
|
+
|
|
|
+ // Load cover image as binary data (BLOB)
|
|
|
+ if (cover_image) {
|
|
|
+ Glib::RefPtr<Gdk::PixbufLoader> loader = Gdk::PixbufLoader::create();
|
|
|
+ cover_image->save(loader->get_pixbuf(), "jpeg");
|
|
|
+ std::string coverData(loader->get_data(), loader->get_size());
|
|
|
+ sqlite3_bind_blob(stmt, 5, coverData.c_str(), coverData.size(), SQLITE_STATIC);
|
|
|
+ } else {
|
|
|
+ sqlite3_bind_null(stmt, 5);
|
|
|
+ }
|
|
|
+
|
|
|
+ if (sqlite3_step(stmt) != SQLITE_DONE) {
|
|
|
+ std::cerr << "Failed to insert data into the database: " << sqlite3_errmsg(db) << std::endl;
|
|
|
+ }
|
|
|
+
|
|
|
+ sqlite3_finalize(stmt);
|
|
|
+ sqlite3_close(db);
|
|
|
+}
|
|
|
+
|
|
|
+// Load all books from the SQLite database
|
|
|
+std::vector<std::shared_ptr<Book>> Book::loadFromDatabase() {
|
|
|
+ std::vector<std::shared_ptr<Book>> books;
|
|
|
+
|
|
|
+ sqlite3* db;
|
|
|
+ sqlite3_open("bookcollection.db", &db);
|
|
|
+
|
|
|
+ const char* selectSQL = "SELECT title, authors, isbn, file_path, cover FROM books;";
|
|
|
+ sqlite3_stmt* stmt;
|
|
|
+ sqlite3_prepare_v2(db, selectSQL, -1, &stmt, nullptr);
|
|
|
+
|
|
|
+ while (sqlite3_step(stmt) == SQLITE_ROW) {
|
|
|
+ auto book = std::make_shared<Book>((const char*)sqlite3_column_text(stmt, 3));
|
|
|
+ book->title = (const char*)sqlite3_column_text(stmt, 0);
|
|
|
+ book->authors = (const char*)sqlite3_column_text(stmt, 1);
|
|
|
+ book->isbn = (const char*)sqlite3_column_text(stmt, 2);
|
|
|
+
|
|
|
+ // Load cover from BLOB
|
|
|
+ const void* coverBlob = sqlite3_column_blob(stmt, 4);
|
|
|
+ int coverSize = sqlite3_column_bytes(stmt, 4);
|
|
|
+ if (coverBlob && coverSize > 0) {
|
|
|
+ std::string coverData((const char*)coverBlob, coverSize);
|
|
|
+ Glib::RefPtr<Gdk::PixbufLoader> loader = Gdk::PixbufLoader::create();
|
|
|
+ loader->write((const guint8*)coverData.c_str(), coverSize);
|
|
|
+ loader->close();
|
|
|
+ book->cover_image = loader->get_pixbuf();
|
|
|
+ }
|
|
|
+
|
|
|
+ books.push_back(book);
|
|
|
+ }
|
|
|
+
|
|
|
+ sqlite3_finalize(stmt);
|
|
|
+ sqlite3_close(db);
|
|
|
+ return books;
|
|
|
+}
|
|
|
+
|
|
|
+// Synchronize the book to the cloud using a cloud API (e.g., Google Drive)
|
|
|
+void Book::syncToCloud() {
|
|
|
+ CURL* curl;
|
|
|
+ CURLcode res;
|
|
|
+ curl_global_init(CURL_GLOBAL_DEFAULT);
|
|
|
+ curl = curl_easy_init();
|
|
|
+ if (curl) {
|
|
|
+ // Replace with your cloud storage URL
|
|
|
+ const std::string url = "https://cloud-storage-url.com/upload";
|
|
|
+
|
|
|
+ curl_easy_setopt(curl, CURLOPT_URL, url.c_str());
|
|
|
+ curl_easy_setopt(curl, CURLOPT_POST, 1L);
|
|
|
+
|
|
|
+ // Set up form data
|
|
|
+ curl_mime* form = curl_mime_init(curl);
|
|
|
+ curl_mimepart* field = curl_mime_addpart(form);
|
|
|
+ curl_mime_name(field, "file");
|
|
|
+ curl_mime_filedata(field, file_path.c_str());
|
|
|
+ curl_easy_setopt(curl, CURLOPT_MIMEPOST, form);
|
|
|
+
|
|
|
+ // Perform the upload
|
|
|
+ res = curl_easy_perform(curl);
|
|
|
+ if (res != CURLE_OK) {
|
|
|
+ std::cerr << "Cloud sync failed: " << curl_easy_strerror(res) << std::endl;
|
|
|
+ } else {
|
|
|
+ std::cout << "Book successfully uploaded to the cloud!" << std::endl;
|
|
|
+ }
|
|
|
+
|
|
|
+ curl_mime_free(form);
|
|
|
+ curl_easy_cleanup(curl);
|
|
|
+ }
|
|
|
+ curl_global_cleanup();
|
|
|
+}
|