]> Some of my projects - localmylist.git/commitdiff
Add RenameHandler.
authorAPTX <marek321@gmail.com>
Tue, 12 Jun 2012 18:05:24 +0000 (20:05 +0200)
committerAPTX <marek321@gmail.com>
Tue, 12 Jun 2012 18:05:24 +0000 (20:05 +0200)
localmylist/addfiletask.cpp
localmylist/database.cpp
localmylist/database.h
localmylist/localmylist.pro
localmylist/mylist.cpp
localmylist/mylist.h
localmylist/renamehandler.cpp [new file with mode: 0644]
localmylist/renamehandler.h [new file with mode: 0644]
localmylist/requesthandler.cpp

index 6880bd04b36679c0ee723c654ea8fbe9b791b30d..bb50ce771b73294f4f1c94c601819bdf07581b26 100644 (file)
@@ -59,7 +59,11 @@ void AddFileTask::hashingFinished()
        int fid = db->isKnownFile(hashResult->hash(), m_file.size());
        if (fid)
        {
-               db->setFileLocation(fid, MyList::instance()->hostId(), m_file.canonicalFilePath());
+               FileLocation fl;
+               fl.fid = fid;
+               fl.hostId = MyList::instance()->hostId();
+               fl.path = m_file.canonicalFilePath();
+               db->addFileLocation(fl);
                emit finished();
                return;
        }
index 5cfa2e61da402a2ffe787268b0c2fc70e8627e50..69dea0cb7cc54edc8c460f1cc631bf3c60d7df28 100644 (file)
@@ -60,6 +60,13 @@ File::File()
        myFileState = 0;
 }
 
+FileLocation::FileLocation()
+{
+       fid = 0;
+       hostId = 0;
+       failedRename = false;
+}
+
 FileEpisodeRel::FileEpisodeRel()
 {
        fid = 0;
@@ -268,13 +275,26 @@ int Database::isKnownFile(const QByteArray &ed2k, qint64 size)
        return fid;
 }
 
-bool Database::setFileLocation(int fid, int hostId, const QString &location)
+bool Database::addFileLocation(const FileLocation &fileLocation)
+{
+       QSqlQuery q(d->db);
+       q.prepare("INSERT INTO file_location VALUES(:fid, :hostId, :path, DEFAULT, DEFAULT)");
+       q.bindValue(":fid", fileLocation.fid);
+       q.bindValue(":hostId", fileLocation.hostId);
+       q.bindValue(":path", fileLocation.path);
+
+       return exec(q);
+}
+
+bool Database::setFileLocation(const FileLocation &fileLocation)
 {
        QSqlQuery q(d->db);
-       q.prepare("INSERT INTO file_location VALUES(:fid, :hostId, :path)");
-       q.bindValue(":fid", fid);
-       q.bindValue(":hostId", hostId);
-       q.bindValue(":path", location);
+       q.prepare("UPDATE file_location SET host_id = :hostId, path = :path, renamed = :renamed, failed_rename = :failedRename WHERE fid = :fid");
+       q.bindValue(":fid", fileLocation.fid);
+       q.bindValue(":hostId", fileLocation.hostId);
+       q.bindValue(":path", fileLocation.path);
+       q.bindValue(":renamed", fileLocation.renamed);
+       q.bindValue(":failedRename", fileLocation.failedRename);
 
        return exec(q);
 }
@@ -992,6 +1012,7 @@ void Database::prepareQueries()
 
        d->db.driver()->subscribeToNotification("new_pending_request");
        d->db.driver()->subscribeToNotification("new_pending_mylist_update");
+       d->db.driver()->subscribeToNotification("rename_data_changed");
 }
 
 bool Database::exec(QSqlQuery &query)
@@ -1038,6 +1059,11 @@ bool Database::exec(const QString &sql)
        return result;
 }
 
+bool Database::notify(const QString &notification)
+{
+       return exec("NOTIFY " + notification);
+}
+
 void Database::handleNotification(const QString &notification)
 {
        qDebug() << "Recieved notification" << notification;
@@ -1049,6 +1075,10 @@ void Database::handleNotification(const QString &notification)
        {
                emit newPendingMyListUpdate();
        }
+       else if (notification == "rename_data_changed")
+       {
+               emit renameDataChanged();
+       }
 }
 
 
index 39435c7610e1b104e6473dedd06a3d3cd366890d..fb8db87f8abacd1e0f315435fea32d541b4e0f6a 100644 (file)
@@ -97,7 +97,7 @@ struct LOCALMYLISTSHARED_EXPORT File
        QDateTime releaseDate;
        int version;
        bool censored;
-       QString type;
+       QString type; // TODO rename this to source
        int qualityId;
        QString quality;
        QString resolution;
@@ -116,6 +116,17 @@ struct LOCALMYLISTSHARED_EXPORT File
        File();
 };
 
+struct LOCALMYLISTSHARED_EXPORT FileLocation
+{
+       int fid;
+       int hostId;
+       QString path;
+       QDateTime renamed;
+       bool failedRename;
+
+       FileLocation();
+};
+
 struct LOCALMYLISTSHARED_EXPORT UnknownFile
 {
        QByteArray ed2k;
@@ -215,7 +226,8 @@ public:
        bool setConfig(const QString &key, const QVariant &value);
 
        int isKnownFile(const QByteArray &ed2k, qint64 size);
-       bool setFileLocation(int fid, int hostId, const QString &location);
+       bool addFileLocation(const FileLocation &fileLocation);
+       bool setFileLocation(const FileLocation &fileLocation);
 
        Anime getAnime(int aid);
        Episode getEpisode(int eid);
@@ -249,6 +261,11 @@ public:
 
        QSqlDatabase connection() const;
 
+       bool exec(QSqlQuery &query);
+       bool exec(const QString &sql);
+
+       bool notify(const QString &notification);
+
 public slots:
        bool connect();
        void disconnect();
@@ -259,13 +276,12 @@ signals:
 
        void newPendingRequest();
        void newPendingMyListUpdate();
+       void renameDataChanged();
 
 private slots:
        void handleNotification(const QString &notification);
 
 private:
-       bool exec(QSqlQuery &query);
-       bool exec(const QString &sql);
        void prepareQueries();
 
        DatabaseInternal *d;
index 60c3db762c81637ae82b50239c0bf50b6a9785a2..3c2951e227917bbc4dca8268522e1c0e133656f7 100644 (file)
@@ -21,7 +21,8 @@ SOURCES += \
        mylistnode.cpp \
        animetitleparsetask.cpp \
        mylistexportparsetask.cpp \
-       settings.cpp
+       settings.cpp \
+       renamehandler.cpp
 
 HEADERS += \
        localmylist_global.h \
@@ -36,7 +37,8 @@ HEADERS += \
        mylistnode.h \
        animetitleparsetask.h \
        mylistexportparsetask.h \
-       settings.h
+       settings.h \
+       renamehandler.h
 
 CONV_HEADERS += \
        include/LocalMyList/AbstractTask \
index 50f8e33785e2e11853d20ca92d9af803c2aa3b9a..70b97723c9270779df809e51e45a9afa15ed3375 100644 (file)
@@ -11,6 +11,7 @@
 #include "mylistexportparsetask.h"
 #include "workthread.h"
 #include "requesthandler.h"
+#include "renamehandler.h"
 #include <AniDBUdpClient/Client>
 
 namespace LocalMyList {
@@ -20,6 +21,7 @@ MyList::MyList()
        init();
 
        m_requestHandler = 0;
+       m_renameHandler = 0;
        workThread = 0;
 
        db = new Database("main");
@@ -31,7 +33,9 @@ MyList::~MyList()
 {
        delete db;
        if (workThread)
-               delete workThread;
+       {
+               QMetaObject::invokeMethod(workThread, "quit");
+       }
 }
 
 QString MyList::hostName() const
@@ -96,7 +100,7 @@ void MyList::setupUdpClient()
 
 void MyList::setupRequestHandler()
 {
-       if(m_requestHandler)
+       if (m_requestHandler)
                return;
 
        m_requestHandler = new RequestHandler(db, this);
@@ -104,11 +108,24 @@ void MyList::setupRequestHandler()
        connect(db, SIGNAL(newPendingMyListUpdate()), m_requestHandler, SLOT(handleMyListUpdates()));
 }
 
+void MyList::setupRenameHandler()
+{
+       if (m_renameHandler || !db->isConnected())
+               return;
+
+       setupWorkThread();
+
+       m_renameHandler = new RenameHandler(workThread->database());
+       m_renameHandler->moveToThread(workThread);
+       connect(db, SIGNAL(renameDataChanged()), m_renameHandler, SLOT(handleRename()), Qt::QueuedConnection);
+}
+
 void MyList::setupWorkThread()
 {
        if (workThread)
                return;
        workThread = new WorkThread("workThread", dbs, this);
+       connect(workThread, SIGNAL(finished()), workThread, SLOT(deleteLater()));
        workThread->start();
 }
 
index 4f17cadb3c362412f94c065c82f0ae84cc4b9245..66391fdc8ed30f13b0769d454252be43a5943833 100644 (file)
@@ -17,6 +17,7 @@ namespace LocalMyList {
 class AbstractTask;
 class WorkThread;
 class RequestHandler;
+class RenameHandler;
 
 class LOCALMYLISTSHARED_EXPORT MyList : public QObject {
        Q_OBJECT
@@ -47,6 +48,7 @@ public slots:
 
        void setupUdpClient();
        void setupRequestHandler();
+       void setupRenameHandler();
        void setupWorkThread();
        void setupHostInfo();
 
@@ -65,6 +67,7 @@ private:
        Database *db;
        WorkThread *workThread;
        RequestHandler *m_requestHandler;
+       RenameHandler *m_renameHandler;
        Settings *m_settings;
 
        HostInfo hostInfo;
diff --git a/localmylist/renamehandler.cpp b/localmylist/renamehandler.cpp
new file mode 100644 (file)
index 0000000..246c083
--- /dev/null
@@ -0,0 +1,188 @@
+#include "renamehandler.h"
+
+#include "mylist.h"
+#include "database.h"
+#include "settings.h"
+#include <RenameParser/RenameEngine>
+#include <QSqlQuery>
+#include <QSqlRecord>
+
+#include <QDebug>
+
+namespace LocalMyList {
+
+RenameHandler::RenameHandler(Database *db, QObject *parent) :
+       QObject(parent), renameEngine(0), validScript(false)
+{
+       this->db = db;
+       connect(this, SIGNAL(renameBatchFinished()), this, SLOT(handleRename()), Qt::QueuedConnection);
+       setupRenameEngine();
+}
+
+
+void RenameHandler::handleRename()
+{
+       QSqlQuery q(db->connection());
+
+       q.prepare("SELECT fid, eid, aid, gid, anime_anidb_update, anime_entry_update, anime_my_update, anime_title_english, anime_title_romaji, anime_title_kanji, "
+                         "             description, year, start_date, end_date, anime_type, anime_rating, anime_votes, temp_rating, temp_votes, anime_my_vote, anime_my_vote_date, my_temp_vote, my_temp_vote_date, "
+                         "episode_anidb_update, episode_entry_update, episode_my_update, epno, episode_title_english, episode_title_romaji, episode_title_kanji, episode_length, airdate, state, special, recap, "
+                         "             opening, ending, rating, votes, my_vote, my_vote_date, "
+                         "anidb_update, entry_update, my_update, ed2k, size, length, extension, group_name, group_name_short, crc, release_date, version, censored, type, quality_id, quality, resolution, "
+                         "             video_codec, audio_codec, audio_language, subtitle_language, aspect_ratio, my_watched, my_state, my_file_state, my_storage, my_source, my_other, host_id, path, renamed "
+                         "FROM rename_data "
+                         "WHERE host_id = :host_id "
+                         "LIMIT :limit");
+
+       q.bindValue(":host_id", MyList::instance()->hostId());
+       q.bindValue(":limit", 10);
+
+       if (!db->exec(q))
+               return;
+
+       qDebug() << "Rename: Got" << q.size() << "rows";
+
+       if (q.size() < 1)
+               return;
+
+       if (!validScript)
+               return;
+
+       while (q.next())
+       {
+               QSqlRecord r = q.record();
+               QFileInfo oldFile(r.value("path").toString());
+
+               RaiiTransaction t(db);
+               t.commit();
+
+               FileLocation fl;
+               fl.fid = q.value(0).toInt();
+               fl.hostId = MyList::instance()->hostId();
+               fl.path = r.value("path").toString();
+               fl.renamed = QDateTime::currentDateTime();
+
+               qDebug() << "Rename: renaming" << oldFile.filePath();
+               if (!oldFile.exists())
+               {
+                       db->log(tr("Rename: Failed to rename file <%1>. File does not exist").arg(oldFile.filePath()), 2);
+                       fl.failedRename = true;
+                       db->setFileLocation(fl);
+                       continue;
+               }
+
+               RenameParser::Environment env;
+               env["ATr"] = r.value("anime_title_romaji").toString();
+               env["ATe"] = r.value("anime_title_english").toString();
+               env["ATk"] = r.value("anime_title_kanji").toString();
+
+               env["ETr"] = r.value("episode_title_romaji").toString();
+               env["ETe"] = r.value("episode_title_english").toString();
+               env["ETk"] = r.value("episode_title_kanji").toString();
+
+               env["GTs"] = r.value("group_name_short").toString();
+               env["GTl"] = r.value("group_name").toString();
+
+               env["EpNo"] = r.value("epno").toString();
+               env["EpHiNo"] = r.value("episode_count").toString();
+               env["EpCount"] = "0"; // TODO This is missing from the data
+
+               QString year = r.value("year").toString();
+               if (!year.contains('-'))
+               {
+                       env["AYearBegin"] = year;
+                       env["AYearEnd"] = "";
+               }
+               else
+               {
+                       QStringList years = year.split('-');
+                       env["AYearBegin"] = years[0].trimmed();
+                       env["AYearEnd"] = years[1].trimmed();
+               }
+
+               env["Type"] = r.value("anime_type").toString();
+               env["Depr"] = /*r.value("")*/ false ? "1" : ""; // Data missing?
+
+               env["Cen"] = r.value("censored").toBool() ? "1" : "0";
+
+               env["Ver"] = r.value("version").toString();
+               env["Source"] = r.value("type").toString(); // TODO This is called source on AniDB
+               env["Quality"] = r.value("quality").toString();
+               env["FCrc"] = r.value("crc").toString();
+               env["FVideoRes"] = r.value("resolution").toString();
+               env["FALng"] = r.value("audio_language").toString();
+               env["FSLng"] = r.value("subtitle_language").toString();
+               env["FACodec"] = r.value("audio_codec").toString();
+               env["FVCodec"] = r.value("video_codec").toString();
+               env["Watched"] = r.value("my_watched").toDateTime().isValid() ? "1" : "0";
+
+               renameEngine->evaluate(env);
+
+               if (env.value("FileName", "").isEmpty())
+               {
+                       fl.failedRename = true;
+                       db->setFileLocation(fl);
+                       db->log(tr("Rename: Failed to rename file <%1>. Rename script did not set a file name.").arg(oldFile.filePath()), 2);
+                       continue;
+               }
+
+               QString newFileName = env.value("FileName", "") + "." + r.value("extension").toString();
+               QString newFilePath = env.value("FilePath", "");
+
+               if (newFilePath.isEmpty())
+                       newFilePath = oldFile.canonicalPath();
+
+               QString newFileString = newFilePath + "/" + newFileName;
+               QFileInfo newFile(newFileString);
+
+               if (newFile.exists())
+               {
+                       fl.failedRename = true;
+                       db->setFileLocation(fl);
+                       db->log(tr("Rename: Failed to rename file <%1>. Destination <%2> exists.").arg(oldFile.filePath()).arg(newFile.canonicalPath()), 2);
+                       continue;
+               }
+
+               if (!newFile.absoluteDir().exists())
+               {
+                       if (!QDir().mkpath(newFile.canonicalPath()))
+                       {
+                               fl.failedRename = true;
+                               db->setFileLocation(fl);
+                               db->log(tr("Rename: Failed to rename file <%1>. Destination path <%2> does not exists and could not be created.").arg(oldFile.filePath()).arg(newFile.canonicalPath()), 2);
+                               continue;
+                       }
+               }
+
+               if (oldFile.canonicalPath() != newFileString && !QFile::rename(oldFile.canonicalFilePath(), newFileString))
+               {
+                       fl.failedRename = true;
+                       db->setFileLocation(fl);
+                       db->log(tr("Rename: Failed to rename file <%1>. Failed to rename file to <%2>").arg(oldFile.canonicalFilePath()).arg(newFileString), 2);
+                       continue;
+               }
+
+               fl.path = newFileString;
+               fl.failedRename = false;
+               db->setFileLocation(fl);
+
+               db->log(tr("Rename: File <%1> was renamed to <%2>").arg(oldFile.canonicalFilePath()).arg(newFileString));
+       }
+
+       emit renameBatchFinished();
+}
+
+void RenameHandler::setupRenameEngine()
+{
+       if (!renameEngine)
+               renameEngine = new RenameParser::RenameEngine();
+
+       renameEngine->setCurrentParserType(RenameParser::RenameEngine::ParserType(
+                                                                                  MyList::instance()->settings()->get("renameLanguage").toInt()));
+       validScript = renameEngine->parse(MyList::instance()->settings()->get("renameScript").toString());
+
+       if (validScript)
+               db->log(tr("Rename Current rename script is invalid: %1, line: %2, column: %3").arg(renameEngine->error()).arg(renameEngine->line()).arg(renameEngine->column()), 2);
+}
+
+} // namespace LocalMyList
diff --git a/localmylist/renamehandler.h b/localmylist/renamehandler.h
new file mode 100644 (file)
index 0000000..ab51886
--- /dev/null
@@ -0,0 +1,38 @@
+#ifndef RENAMEHANDLER_H
+#define RENAMEHANDLER_H
+
+#include "localmylist_global.h"
+#include <QObject>
+
+namespace RenameParser {
+       class RenameEngine;
+}
+
+namespace LocalMyList {
+
+class Database;
+
+class RenameHandler : public QObject
+{
+       Q_OBJECT
+public:
+       explicit RenameHandler(Database *db, QObject *parent = 0);
+       
+signals:
+       void renameBatchFinished();
+
+public slots:
+       void handleRename();
+
+       void setupRenameEngine();
+
+private:
+       Database *db;
+       RenameParser::RenameEngine *renameEngine;
+
+       bool validScript;
+};
+
+} // namespace LocalMyList
+
+#endif // RENAMEHANDLER_H
index 7546780ce1a9072c504977b18742244c40a80fd8..f8beecd4502a85badfd9627ad3fd295980b4dfd9 100644 (file)
@@ -49,6 +49,7 @@ void RequestHandler::handleRequests()
                        | FileFlag::FileType
                        | FileFlag::Crc32
                        | FileFlag::State
+                       | FileFlag::Source
                        | FileFlag::Quality
                        | FileFlag::VideoResolution
                        | FileFlag::VideoCodec
@@ -298,7 +299,7 @@ void RequestHandler::fileRequestComplete(bool success)
        //next.releaseDate
        next.version = reply->version();
        next.censored = reply->isCensored();
-       next.type = reply->type();
+       next.type = reply->source(); // TODO This is called sourcein AniDB
        // next.qualityId - can map quality to qualityId
        next.quality = reply->quality();
        next.resolution = reply->videoResolution();