[office/tellico] /: Import metadata from EPub, FB2, and Mobi ebook formats

Robby Stephenson null at kde.org
Fri Mar 10 02:41:30 GMT 2023


Git commit c7e7eb08c431163733cfac23be594d9ee53c7524 by Robby Stephenson.
Committed on 10/03/2023 at 02:41.
Pushed by rstephenson into branch 'master'.

Import metadata from EPub, FB2, and Mobi ebook formats

Importing is supported for drag-and-drop, subject to support from
KFileMetadata. Combining with PDF import isn't supported yet.

BUG: 450192
FIXED-IN: 3.5

M  +4    -0    ChangeLog
M  +1    -1    doc/importing-exporting.docbook
M  +10   -3    src/gui/drophandler.cpp
M  +10   -0    src/importdialog.cpp
M  +1    -0    src/translators/CMakeLists.txt
A  +136  -0    src/translators/ebookimporter.cpp     [License: GPL (v2/3)]
C  +34   -68   src/translators/ebookimporter.h [from: src/translators/translators.h - 063% similarity]
M  +2    -1    src/translators/translators.h

https://invent.kde.org/office/tellico/commit/c7e7eb08c431163733cfac23be594d9ee53c7524

diff --git a/ChangeLog b/ChangeLog
index 167838cc..c5866af1 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,7 @@
+2023-03-09  Robby Stephenson  <robby at periapsis.org>
+
+	* Added support for importing EPub data on drag/drop (Bug 450192).
+
 2023-02-20  Robby Stephenson  <robby at periapsis.org>
 
 	* Updated AMS MR Lookup data source.
diff --git a/doc/importing-exporting.docbook b/doc/importing-exporting.docbook
index 753815da..249470af 100644
--- a/doc/importing-exporting.docbook
+++ b/doc/importing-exporting.docbook
@@ -222,7 +222,7 @@ Any &XML; file may be imported into &appname; provided an &XSL; stylesheet is av
 <sect1 id="drag-n-drop">
 <title>Drag and Drop</title>
 
-<para>Dragging data files to the main &appname; window and dropping them will import the files, just as if the <link linkend="importing">import command</link> was made from the menus. Drag and drop works for the following file formats: Tellico, Bibtex, RIS, and &PDF;. Importing multiple files at once is also supported.</para>
+<para>Dragging data files to the main &appname; window and dropping them will import the files, just as if the <link linkend="importing">import command</link> was made from the menus. Drag and drop works for the following file formats: Tellico, Bibtex, RIS, &PDF;, and EPub. Importing multiple files at once is also supported.</para>
 
 <para>So, for example, if you want to catalog several <link linkend="importing-pdf">&PDF; files</link>, select them in the file manager and drag them to the &appname; window. &appname; will import as much metadata from the files as it can, and then fetch additional information from various configured Internet sources.</para>
 
diff --git a/src/gui/drophandler.cpp b/src/gui/drophandler.cpp
index 8bac7b03..3bf5cc77 100644
--- a/src/gui/drophandler.cpp
+++ b/src/gui/drophandler.cpp
@@ -84,19 +84,18 @@ bool DropHandler::drop(QDropEvent* event_) {
 
 bool DropHandler::handleURL(const QList<QUrl>& urls_) {
   bool hasUnknown = false;
-  QList<QUrl> tc, pdf, bib, ris, ciw;
+  QMimeDatabase db;
+  QList<QUrl> tc, pdf, bib, ris, ciw, ebook;
   foreach(const QUrl& url, urls_) {
     QMimeType ptr;
     // findByURL doesn't work for http, so actually query
     // the url itself
     if(url.scheme() != QLatin1String("http")) {
-      QMimeDatabase db;
       ptr = db.mimeTypeForUrl(url);
     } else {
       KIO::MimetypeJob* job = KIO::mimetype(url, KIO::HideProgressInfo);
       KJobWidgets::setWindow(job, GUI::Proxy::widget());
       job->exec();
-      QMimeDatabase db;
       ptr = db.mimeTypeForName(job->mimetype());
     }
     if(ptr.inherits(QStringLiteral("application/x-tellico"))) {
@@ -109,6 +108,11 @@ bool DropHandler::handleURL(const QList<QUrl>& urls_) {
       bib << url;
     } else if(ptr.inherits(QStringLiteral("application/x-research-info-systems"))) {
       ris << url;
+    } else if(ptr.inherits(QStringLiteral("application/epub+zip")) ||
+              ptr.inherits(QStringLiteral("application/x-mobipocket-ebook")) ||
+              ptr.inherits(QStringLiteral("application/x-fictionbook+xml")) ||
+              ptr.inherits(QStringLiteral("application/x-zip-compressed-fb2"))) {
+      ebook << url;
     } else if(url.fileName().endsWith(QLatin1String(".bib"))) {
       bib << url;
     } else if(url.fileName().endsWith(QLatin1String(".ris"))) {
@@ -146,6 +150,9 @@ bool DropHandler::handleURL(const QList<QUrl>& urls_) {
   if(!ciw.isEmpty()) {
     mainWindow->importFile(Import::CIW, ciw);
   }
+  if(!ebook.isEmpty()) {
+    mainWindow->importFile(Import::EBook, ebook);
+  }
   // any unknown urls get passed
   return !hasUnknown;
 }
diff --git a/src/importdialog.cpp b/src/importdialog.cpp
index 408d2dda..c4b22525 100644
--- a/src/importdialog.cpp
+++ b/src/importdialog.cpp
@@ -55,6 +55,7 @@
 #include "translators/collectorzimporter.h"
 #include "translators/datacrowimporter.h"
 #include "translators/marcimporter.h"
+#include "translators/ebookimporter.h"
 #include "utils/datafileregistry.h"
 
 #include <KLocalizedString>
@@ -328,6 +329,10 @@ Tellico::Import::Importer* ImportDialog::importer(Tellico::Import::Format format
       CHECK_SIZE;
       importer = new Import::MarcImporter(firstURL);
       break;
+
+    case Import::EBook:
+      importer = new Import::EBookImporter(urls_);
+      break;
   }
   if(!importer) {
     myWarning() << "importer not created!";
@@ -414,6 +419,11 @@ QString ImportDialog::fileFilter(Tellico::Import::Format format_) {
       text += i18n("XML Files") + QLatin1String(" (*.xml)") + QLatin1String(";;");
       break;
 
+    case Import::EBook:
+      // KFileMetaData has extractors that support mimetypes with these typical extensions
+      text = i18n("eBook Files") + QLatin1String(" (*.epub *.fb2 *.fb2zip *.mobi)") + QLatin1String(";;");
+      break;
+
     case Import::AudioFile:
     case Import::Alexandria:
     case Import::FreeDB:
diff --git a/src/translators/CMakeLists.txt b/src/translators/CMakeLists.txt
index 602b28f4..1d92c123 100644
--- a/src/translators/CMakeLists.txt
+++ b/src/translators/CMakeLists.txt
@@ -19,6 +19,7 @@ SET(translators_STAT_SRCS
    datacrowimporter.cpp
    dataimporter.cpp
    deliciousimporter.cpp
+   ebookimporter.cpp
    exporter.cpp
    filelistingimporter.cpp
    freedb_util.cpp
diff --git a/src/translators/ebookimporter.cpp b/src/translators/ebookimporter.cpp
new file mode 100644
index 00000000..b67a5d6b
--- /dev/null
+++ b/src/translators/ebookimporter.cpp
@@ -0,0 +1,136 @@
+/***************************************************************************
+    Copyright (C) 2023 Robby Stephenson <robby at periapsis.org>
+ ***************************************************************************/
+
+/***************************************************************************
+ *                                                                         *
+ *   This program is free software; you can redistribute it and/or         *
+ *   modify it under the terms of the GNU General Public License as        *
+ *   published by the Free Software Foundation; either version 2 of        *
+ *   the License or (at your option) version 3 or any later version        *
+ *   accepted by the membership of KDE e.V. (or its successor approved     *
+ *   by the membership of KDE e.V.), which shall act as a proxy            *
+ *   defined in Section 14 of version 3 of the license.                    *
+ *                                                                         *
+ *   This program is distributed in the hope that it will be useful,       *
+ *   but WITHOUT ANY WARRANTY; without even the implied warranty of        *
+ *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the         *
+ *   GNU General Public License for more details.                          *
+ *                                                                         *
+ *   You should have received a copy of the GNU General Public License     *
+ *   along with this program.  If not, see <http://www.gnu.org/licenses/>. *
+ *                                                                         *
+ ***************************************************************************/
+
+#include <config.h>
+
+#include "ebookimporter.h"
+#include "../collections/bookcollection.h"
+#include "../core/netaccess.h"
+#include "../images/imagefactory.h"
+#include "../utils/datafileregistry.h"
+#include "../tellico_debug.h"
+
+#include <KLocalizedString>
+#include <KFileItem>
+#ifdef HAVE_KFILEMETADATA
+#include <KFileMetaData/Extractor>
+#include <KFileMetaData/ExtractorCollection>
+#include <KFileMetaData/SimpleExtractionResult>
+#include <KFileMetaData/PropertyInfo>
+#endif
+
+#include <QPixmap>
+
+using Tellico::Import::EBookImporter;
+
+EBookImporter::EBookImporter(const QUrl& url_) : Importer(url_) {
+}
+
+EBookImporter::EBookImporter(const QList<QUrl>& urls_) : Importer(urls_) {
+}
+
+bool EBookImporter::canImport(int type) const {
+  return type == Data::Collection::Book;
+}
+
+Tellico::Data::CollPtr EBookImporter::collection() {
+  Data::CollPtr coll(new Data::BookCollection(true));
+#ifdef HAVE_KFILEMETADATA
+  KFileMetaData::ExtractorCollection extractors;
+  foreach(const QUrl& url, urls()) {
+    KFileItem item(url);
+    myDebug() << "Reading" << url.url() << item.mimetype();
+    KFileMetaData::SimpleExtractionResult result(url.toLocalFile(),
+                                                 item.mimetype(),
+                                                 KFileMetaData::ExtractionResult::ExtractMetaData);
+    auto exList = extractors.fetchExtractors(item.mimetype());
+    if(exList.isEmpty()) continue;
+    foreach(auto ex, exList) {
+      ex->extract(&result);
+    }
+    bool isEmpty = true;
+    Data::EntryPtr entry(new Data::Entry(coll));
+    entry->setField(QStringLiteral("comments"), url.toLocalFile());
+    QStringList authors, publishers, genres;
+    KFileMetaData::PropertyMap properties = result.properties();
+    KFileMetaData::PropertyMap::const_iterator it = properties.constBegin();
+    for( ; it != properties.constEnd(); ++it) {
+      const QString value = it.value().toString();
+      if(value.isEmpty()) continue;
+      switch(it.key()) {
+        case KFileMetaData::Property::Title:
+          isEmpty = false; // require a title or author
+          entry->setField(QStringLiteral("title"), value);
+          break;
+
+        case KFileMetaData::Property::Author:
+          isEmpty = false; // require a title or author
+          authors += value;
+          break;
+
+        case KFileMetaData::Property::Publisher:
+          publishers += value;
+          break;
+
+        case KFileMetaData::Property::Subject:
+        case KFileMetaData::Property::Genre:
+          genres += value;
+          break;
+
+        case KFileMetaData::Property::ReleaseYear:
+          entry->setField(QStringLiteral("pub_year"), value);
+          break;
+
+        // is description usually the plot or just comments?
+        case KFileMetaData::Property::Description:
+          entry->setField(QStringLiteral("plot"), value);
+          break;
+
+        default:
+          if(!value.isEmpty()) {
+            myDebug() << "skipping" << it.key() << it.value();
+          }
+          break;
+      }
+    }
+    if(!authors.isEmpty()) {
+      entry->setField(QStringLiteral("author"), authors.join(FieldFormat::delimiterString()));
+    }
+    if(!publishers.isEmpty()) {
+      entry->setField(QStringLiteral("publisher"), publishers.join(FieldFormat::delimiterString()));
+    }
+    if(!genres.isEmpty()) {
+      entry->setField(QStringLiteral("genre"), genres.join(FieldFormat::delimiterString()));
+    }
+    if(!isEmpty) {
+      coll->addEntries(entry);
+     }
+  }
+#endif
+  return coll;
+}
+
+void EBookImporter::slotCancel() {
+  myDebug() << "EBookImporter::slotCancel() - unimplemented";
+}
diff --git a/src/translators/translators.h b/src/translators/ebookimporter.h
similarity index 63%
copy from src/translators/translators.h
copy to src/translators/ebookimporter.h
index 45c384d3..9df575f9 100644
--- a/src/translators/translators.h
+++ b/src/translators/ebookimporter.h
@@ -1,5 +1,5 @@
 /***************************************************************************
-    Copyright (C) 2003-2009 Robby Stephenson <robby at periapsis.org>
+    Copyright (C) 2023 Robby Stephenson <robby at periapsis.org>
  ***************************************************************************/
 
 /***************************************************************************
@@ -22,75 +22,41 @@
  *                                                                         *
  ***************************************************************************/
 
-#ifndef TRANSLATORS_H
-#define TRANSLATORS_H
+#ifndef TELLICO_IMPORT_EBOOKIMPORTER_H
+#define TELLICO_IMPORT_EBOOKIMPORTER_H
+
+#include "importer.h"
+#include "../datavectors.h"
 
 namespace Tellico {
   namespace Import {
-    enum Format {
-      TellicoXML = 0,
-      Bibtex,
-      Bibtexml,
-      CSV,
-      XSLT,
-      AudioFile,
-      MODS,
-      Alexandria,
-      FreeDB,
-      RIS,
-      GCstar,
-      FileListing,
-      GRS1,
-      AMC,
-      Griffith,
-      PDF,
-      Referencer,
-      Delicious,
-      Goodreads,
-      CIW,
-      VinoXML,
-      BoardGameGeek,
-      LibraryThing,
-      Collectorz,
-      DataCrow,
-      MARC
-    };
-
-    enum Action {
-      Replace,
-      Append,
-      Merge
-    };
-
-    enum Target {
-      None,
-      File,
-      Dir
-    };
-  }
-
-  namespace Export {
-    enum Format {
-      TellicoXML = 0,
-      TellicoZip,
-      Bibtex,
-      Bibtexml,
-      HTML,
-      CSV,
-      XSLT,
-      Text,
-      PilotDB, // Deprecated
-      Alexandria,
-      ONIX,
-      GCstar
-    };
-
-    enum Target {
-      None,
-      File,
-      Dir
-    };
-  }
-}
 
+/**
+ * @author Robby Stephenson
+*/
+class EBookImporter : public Importer {
+Q_OBJECT
+
+public:
+  /**
+   */
+  EBookImporter(const QUrl& url);
+  EBookImporter(const QList<QUrl>& urls);
+
+  /**
+   */
+  virtual Data::CollPtr collection() Q_DECL_OVERRIDE;
+  /**
+   */
+  virtual QWidget* widget(QWidget*) Q_DECL_OVERRIDE { return nullptr; }
+  virtual bool canImport(int type) const Q_DECL_OVERRIDE;
+
+public Q_SLOTS:
+  void slotCancel() Q_DECL_OVERRIDE;
+
+private:
+};
+
+  } // end namespace
+} // end namespace
 #endif
diff --git a/src/translators/translators.h b/src/translators/translators.h
index 45c384d3..074bf6bd 100644
--- a/src/translators/translators.h
+++ b/src/translators/translators.h
@@ -53,7 +53,8 @@ namespace Tellico {
       LibraryThing,
       Collectorz,
       DataCrow,
-      MARC
+      MARC,
+      EBook
     };
 
     enum Action {


More information about the kde-doc-english mailing list