File indexing completed on 2024-05-05 16:08:26

0001 /*****************************************************************************
0002  * Copyright (C) 2011 by Peter Penz <peter.penz19@gmail.com>                 *
0003  *                                                                           *
0004  * This library is free software; you can redistribute it and/or             *
0005  * modify it under the terms of the GNU Library General Public               *
0006  * License as published by the Free Software Foundation; either              *
0007  * version 2 of the License, or (at your option) any later version.          *
0008  *                                                                           *
0009  * This library is distributed in the hope that it will be useful,           *
0010  * but WITHOUT ANY WARRANTY; without even the implied warranty of            *
0011  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU         *
0012  * Library General Public License for more details.                          *
0013  *                                                                           *
0014  * You should have received a copy of the GNU Library General Public License *
0015  * along with this library; see the file COPYING.LIB.  If not, write to      *
0016  * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,      *
0017  * Boston, MA 02110-1301, USA.                                               *
0018  *****************************************************************************/
0019 
0020 #include <iostream>
0021 
0022 #include <k4aboutdata.h>
0023 #include <kcmdlineargs.h>
0024 #include <kfilemetainfo.h>
0025 #include <klocalizedstring.h>
0026 #include <kconfiggroup.h>
0027 
0028 #include <QByteArray>
0029 #include <QCoreApplication>
0030 #include <QDataStream>
0031 #include <QHash>
0032 #include <QString>
0033 #include <QTimer>
0034 
0035 #define DISABLE_NEPOMUK_LEGACY
0036 #include "config-nepomuk.h"
0037 
0038 #include <nepomuk/query/filequery.h>
0039 #include <nepomuk/query/comparisonterm.h>
0040 #include <nepomuk/query/andterm.h>
0041 #include <nepomuk/query/resourceterm.h>
0042 #include <nepomuk/query/resourcetypeterm.h>
0043 #include <nepomuk/query/optionalterm.h>
0044 #include <nepomuk/utils/utils.h>
0045 #include <nepomuk/types/property.h>
0046 #include <nepomuk/core/tag.h>
0047 #include <nepomuk/core/variant.h>
0048 #include <nepomuk/core/resourcemanager.h>
0049 
0050 using namespace std;
0051 
0052 class KFileMetaDataReaderApplication : public QCoreApplication
0053 {
0054     Q_OBJECT
0055 
0056 public:
0057     KFileMetaDataReaderApplication(int &argc, char **argv);
0058 
0059 private Q_SLOTS:
0060     void readAndSendMetaData();
0061 
0062 private:
0063     void sendMetaData(const QHash<QUrl, Nepomuk::Variant> &data);
0064     QHash<QUrl, Nepomuk::Variant> readFileMetaData(const QList<QUrl> &urls) const;
0065     QHash<QUrl, Nepomuk::Variant> readFileAndContextMetaData(const QList<QUrl> &urls) const;
0066 };
0067 
0068 KFileMetaDataReaderApplication::KFileMetaDataReaderApplication(int &argc, char **argv) :
0069     QCoreApplication(argc, argv)
0070 {
0071     QTimer::singleShot(0, this, SLOT(readAndSendMetaData()));
0072 }
0073 
0074 void KFileMetaDataReaderApplication::readAndSendMetaData()
0075 {
0076     const KCmdLineArgs *args = KCmdLineArgs::parsedArgs();
0077 
0078     QList<QUrl> urls;
0079     for (int i = 0; i < args->count(); ++i) {
0080         urls.append(args->url(i));
0081     }
0082 
0083     QHash<QUrl, Nepomuk::Variant> metaData;
0084     if (args->isSet("file")) {
0085         metaData = readFileMetaData(urls);
0086     } else {
0087         metaData = readFileAndContextMetaData(urls);
0088     }
0089 
0090     sendMetaData(metaData);
0091 
0092     quit();
0093 }
0094 
0095 void KFileMetaDataReaderApplication::sendMetaData(const QHash<QUrl, Nepomuk::Variant> &data)
0096 {
0097     QByteArray byteArray;
0098     QDataStream out(&byteArray, QIODevice::WriteOnly);
0099 
0100     QHashIterator<QUrl, Nepomuk::Variant> it(data);
0101     while (it.hasNext()) {
0102         it.next();
0103 
0104         out << it.key();
0105 
0106         // Unlike QVariant no streaming operators are implemented for Nepomuk::Variant.
0107         // So it is required to manually encode the variant for the stream.
0108         // The decoding counterpart is located in KFileMetaDataReader.
0109         const Nepomuk::Variant &variant = it.value();
0110         if (variant.isList()) {
0111             out << 0 << variant.toStringList();
0112         } else if (variant.isResource()) {
0113             out << 1 << variant.toString();
0114         } else {
0115             out << 2 << variant.variant();
0116         }
0117     }
0118 
0119     cout << byteArray.toBase64().constData();
0120 }
0121 
0122 QHash<QUrl, Nepomuk::Variant> KFileMetaDataReaderApplication::readFileMetaData(const QList<QUrl> &urls) const
0123 {
0124     QHash<QUrl, Nepomuk::Variant> data;
0125 
0126     // Currently only the meta-data of one file is supported.
0127     // It might be an option to read all meta-data and show
0128     // ranges for each key.
0129     if (urls.count() == 1) {
0130         const QString path = urls.first().toLocalFile();
0131         KFileMetaInfo metaInfo(path, QString(), KFileMetaInfo::Fastest);
0132         const QHash<QString, KFileMetaInfoItem> metaInfoItems = metaInfo.items();
0133         foreach (const KFileMetaInfoItem &metaInfoItem, metaInfoItems) {
0134             const QString uriString = metaInfoItem.name();
0135             const Nepomuk::Variant value(metaInfoItem.value());
0136             data.insert(uriString,
0137                         Nepomuk::Utils::formatPropertyValue(Nepomuk::Types::Property(), value));
0138         }
0139     }
0140 
0141     return data;
0142 }
0143 
0144 QHash<QUrl, Nepomuk::Variant> KFileMetaDataReaderApplication::readFileAndContextMetaData(const QList<QUrl> &urls) const
0145 {
0146     QHash<QUrl, Nepomuk::Variant> metaData;
0147 
0148     bool isNepomukIndexerActive = false;
0149     if (Nepomuk::ResourceManager::instance()->initialized()) {
0150         KConfig config("nepomukserverrc");
0151         isNepomukIndexerActive = config.group("Service-nepomukfileindexer").readEntry("autostart", false);
0152     } else {
0153         // No context meta data can be read without enabled Nepomuk
0154         return readFileMetaData(urls);
0155     }
0156 
0157     unsigned int rating = 0;
0158     QString comment;
0159     QList<Nepomuk::Tag> tags;
0160 
0161     if (urls.count() == 1) {
0162         // Read the metadata of the file that are provided as properties
0163         // (e.g. image-size, artist, album, ...)
0164         bool useReadFromFileFallback = true;
0165 
0166         Nepomuk::Resource file(urls.first());
0167         if (file.isValid() && !file.resourceUri().isEmpty()) {
0168             QHash<QUrl, Nepomuk::Variant> variants = file.properties();
0169             QHash<QUrl, Nepomuk::Variant>::const_iterator it = variants.constBegin();
0170             while (it != variants.constEnd()) {
0171                 Nepomuk::Types::Property prop(it.key());
0172                 metaData.insert(prop.uri(), Nepomuk::Utils::formatPropertyValue(prop, it.value(),
0173                                 QList<Nepomuk::Resource>() << file,
0174                                 Nepomuk::Utils::WithKioLinks));
0175                 ++it;
0176             }
0177             useReadFromFileFallback = !isNepomukIndexerActive || variants.isEmpty();
0178 
0179             rating = file.rating();
0180             comment = file.description();
0181             tags = file.tags();
0182         }
0183 
0184         if (useReadFromFileFallback) {
0185             // No metadata could be received with Nepomuk. Parse the file
0186             // itself as fallback to extract metadata.
0187             metaData = readFileMetaData(QList<QUrl>() << urls.first());
0188         }
0189     } else {
0190         // Read the data for rating, comment and tags
0191         bool first = true;
0192         foreach (const QUrl &url, urls) {
0193             Nepomuk::Resource file(url);
0194             if (!file.isValid()) {
0195                 continue;
0196             }
0197 
0198             if (!first && rating != file.rating()) {
0199                 rating = 0; // Reset rating
0200             } else if (first) {
0201                 rating = file.rating();
0202             }
0203 
0204             if (!first && comment != file.description()) {
0205                 comment.clear(); // Reset comment
0206             } else if (first) {
0207                 comment = file.description();
0208             }
0209 
0210             if (!first && tags != file.tags()) {
0211                 tags.clear(); // Reset tags
0212             } else if (first) {
0213                 tags = file.tags();
0214             }
0215 
0216             first = false;
0217         }
0218     }
0219 
0220     metaData.insert(QUrl("kfileitem#rating"), rating);
0221     metaData.insert(QUrl("kfileitem#comment"), comment);
0222 
0223     QList<Nepomuk::Variant> tagVariants;
0224     foreach (const Nepomuk::Tag &tag, tags) {
0225         tagVariants.append(Nepomuk::Variant(tag));
0226     }
0227     metaData.insert(QUrl("kfileitem#tags"), tagVariants);
0228 
0229     return metaData;
0230 }
0231 
0232 int main(int argc, char *argv[])
0233 {
0234     K4AboutData aboutData("kfilemetadatareader", "kio4", ki18n("KFileMetaDataReader"),
0235                           "1.0",
0236                           ki18n("KFileMetaDataReader can be used to read metadata from a file"),
0237                           K4AboutData::License_GPL,
0238                           ki18n("(C) 2011, Peter Penz"));
0239     aboutData.addAuthor(ki18n("Peter Penz"), ki18n("Current maintainer"), "peter.penz19@gmail.com");
0240 
0241     KCmdLineArgs::init(argc, argv, &aboutData);
0242 
0243     KCmdLineOptions options;
0244     options.add("file", ki18n("Only the meta data that is part of the file is read"));
0245     options.add("+[arg]", ki18n("List of URLs where the meta-data should be read from"));
0246 
0247     KCmdLineArgs::addCmdLineOptions(options);
0248 
0249     KFileMetaDataReaderApplication app(argc, argv);
0250     return app.exec();
0251 }
0252 
0253 #include "kfilemetadatareaderprocess.moc"