diff --git a/CHANGELOG.md b/CHANGELOG.md index d6311664..56e34450 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -6,11 +6,12 @@ spanish only. Sorry for the mess. Version counting is based on semantic versioning (Major.Feature.Patch) -## 9.6.7 (unreleased) +## 9.7.0 (unreleased) ### YACReaderLibrary * update QsLog logger to version 2.1, snapshot 46b643d5bcbc * fix object leaks in database code +* add bidirectional sync support ## 9.6.0 ### Reader and Library diff --git a/YACReaderLibrary/db/comic_model.cpp b/YACReaderLibrary/db/comic_model.cpp index 982f051a..7fee8000 100644 --- a/YACReaderLibrary/db/comic_model.cpp +++ b/YACReaderLibrary/db/comic_model.cpp @@ -798,6 +798,7 @@ QVector ComicModel::setComicsRead(QList l c.info.read = false; c.info.currentPage = 1; c.info.hasBeenOpened = false; + c.info.lastTimeOpened.setValue(QVariant()); DBHelper::update(&(c.info), db); } } diff --git a/YACReaderLibrary/db_helper.cpp b/YACReaderLibrary/db_helper.cpp index a81bd916..47fdc68c 100644 --- a/YACReaderLibrary/db_helper.cpp +++ b/YACReaderLibrary/db_helper.cpp @@ -827,10 +827,15 @@ void DBHelper::updateFromRemoteClientWithHash(const ComicInfo &comicInfo) } } -void DBHelper::updateFromRemoteClient(const QMap> &comics) +QMap> DBHelper::updateFromRemoteClient(const QMap> &comics) { + QMap> moreRecentComics; + foreach (qulonglong libraryId, comics.keys()) { + QList libraryMoreRecentComics; + QString libraryPath = DBHelper::getLibraries().getPath(libraryId); + QString connectionName = ""; { QSqlDatabase db = DataBaseManagement::loadDatabase(libraryPath + "/.yacreaderlibrary"); @@ -850,37 +855,58 @@ void DBHelper::updateFromRemoteClient(const QMap> & ComicDB comic = DBHelper::loadComic(comicInfo.id, db); if (comic.info.hash == comicInfo.hash) { - if (comicInfo.currentPage > 0) { - comic.info.currentPage = comicInfo.currentPage; + bool isMoreRecent = false; - if (comic.info.currentPage == comic.info.numPages) - comic.info.read = true; - - comic.info.hasBeenOpened = true; - - if (comic.info.lastTimeOpened.toULongLong() < comicInfo.lastTimeOpened.toULongLong()) - comic.info.lastTimeOpened = comicInfo.lastTimeOpened; + //completion takes precedence over lastTimeOpened, if we just want to synchronize the lastest status we should use only lastTimeOpened + if ((comic.info.currentPage > 1 && comic.info.currentPage > comicInfo.currentPage) || comic.info.hasBeenOpened || (comic.info.read && !comicInfo.read)) { + isMoreRecent = true; } + if (comic.info.lastTimeOpened.toULongLong() > 0 && comicInfo.lastTimeOpened.toULongLong() == 0) { + isMoreRecent = true; + } + + comic.info.currentPage = qMax(comic.info.currentPage, comicInfo.currentPage); + + if (comic.info.currentPage == comic.info.numPages) + comic.info.read = true; + + comic.info.read = comic.info.read || comicInfo.read; + + comic.info.hasBeenOpened = comic.info.hasBeenOpened || comicInfo.currentPage > 0; + + if (comic.info.lastTimeOpened.toULongLong() < comicInfo.lastTimeOpened.toULongLong() && comicInfo.lastTimeOpened.toULongLong() > 0) + comic.info.lastTimeOpened = comicInfo.lastTimeOpened; + if (comicInfo.rating > 0) comic.info.rating = comicInfo.rating; updateComicInfo.bindValue(":read", comic.info.read ? 1 : 0); updateComicInfo.bindValue(":currentPage", comic.info.currentPage); updateComicInfo.bindValue(":hasBeenOpened", comic.info.hasBeenOpened ? 1 : 0); - updateComicInfo.bindValue(":lastTimeOpened", QDateTime::currentMSecsSinceEpoch() / 1000); + updateComicInfo.bindValue(":lastTimeOpened", comic.info.lastTimeOpened); updateComicInfo.bindValue(":id", comic.info.id); updateComicInfo.bindValue(":rating", comic.info.rating); updateComicInfo.exec(); + + if (isMoreRecent) { + libraryMoreRecentComics.append(comic); + } } } + if (!libraryMoreRecentComics.isEmpty()) { + moreRecentComics[libraryId] = libraryMoreRecentComics; + } + db.commit(); connectionName = db.connectionName(); } QSqlDatabase::removeDatabase(connectionName); } + + return moreRecentComics; } void DBHelper::updateFromRemoteClientWithHash(const QList &comics) diff --git a/YACReaderLibrary/db_helper.h b/YACReaderLibrary/db_helper.h index fb61b854..3b11f41f 100644 --- a/YACReaderLibrary/db_helper.h +++ b/YACReaderLibrary/db_helper.h @@ -72,7 +72,7 @@ public: static void updateFromRemoteClient(qulonglong libraryId, const ComicInfo &comicInfo); static void updateFromRemoteClientWithHash(const ComicInfo &comicInfo); static void updateReadingRemoteProgress(const ComicInfo &comicInfo, QSqlDatabase &db); - static void updateFromRemoteClient(const QMap> &comics); + static QMap> updateFromRemoteClient(const QMap> &comics); static void updateFromRemoteClientWithHash(const QList &comics); static void renameLabel(qulonglong id, const QString &name, QSqlDatabase &db); static void renameList(qulonglong id, const QString &name, QSqlDatabase &db); diff --git a/YACReaderLibrary/server/controllers/v2/synccontroller_v2.cpp b/YACReaderLibrary/server/controllers/v2/synccontroller_v2.cpp index 8883a8ce..8adef636 100644 --- a/YACReaderLibrary/server/controllers/v2/synccontroller_v2.cpp +++ b/YACReaderLibrary/server/controllers/v2/synccontroller_v2.cpp @@ -5,6 +5,7 @@ #include "comic_db.h" #include "db_helper.h" +#include "yacreader_server_data_helper.h" using stefanfrings::HttpRequest; using stefanfrings::HttpResponse; @@ -15,13 +16,13 @@ SyncControllerV2::SyncControllerV2() void SyncControllerV2::service(HttpRequest &request, HttpResponse &response) { + response.setHeader("Content-Type", "text/plain; charset=utf-8"); + QString postData = QString::fromUtf8(request.getBody()); QLOG_TRACE() << "POST DATA: " << postData; if (postData.length() > 0) { - response.write("OK", true); - QList data = postData.split("\n"); qulonglong libraryId; @@ -35,7 +36,7 @@ void SyncControllerV2::service(HttpRequest &request, HttpResponse &response) foreach (QString comicInfo, data) { QList comicInfoProgress = comicInfo.split("\t"); - if (comicInfoProgress.length() == 6) { + if (comicInfoProgress.length() >= 6) { if (comicInfoProgress.at(0) != "unknown") { libraryId = comicInfoProgress.at(0).toULongLong(); comicId = comicInfoProgress.at(1).toULongLong(); @@ -52,6 +53,11 @@ void SyncControllerV2::service(HttpRequest &request, HttpResponse &response) lastTimeOpened = comicInfoProgress.at(5).toULong(); info.lastTimeOpened = lastTimeOpened; + + if (comicInfoProgress.length() >= 7) { + info.read = comicInfoProgress.at(6).toInt(); + } + if (!comics.contains(libraryId)) { comics[libraryId] = QList(); } @@ -75,11 +81,26 @@ void SyncControllerV2::service(HttpRequest &request, HttpResponse &response) } } - DBHelper::updateFromRemoteClient(comics); + auto moreRecentComicsFound = DBHelper::updateFromRemoteClient(comics); + + QJsonArray items; + + foreach (qulonglong libraryId, moreRecentComicsFound.keys()) { + foreach (ComicDB comic, moreRecentComicsFound[libraryId]) { + items.append(YACReaderServerDataHelper::comicToJSON(libraryId, comic)); + } + } + + QJsonDocument output(items); + + response.write(output.toJson(QJsonDocument::Compact), true); + + //TODO does it make sense to send these back? The source is not YACReaderLibrary... DBHelper::updateFromRemoteClientWithHash(comicsWithNoLibrary); + } else { response.setStatus(412, "No comic info received"); - response.write("", true); + response.write("[]", true); return; } } diff --git a/YACReaderLibrary/server/yacreader_server_data_helper.cpp b/YACReaderLibrary/server/yacreader_server_data_helper.cpp index ab16a427..5af2389d 100644 --- a/YACReaderLibrary/server/yacreader_server_data_helper.cpp +++ b/YACReaderLibrary/server/yacreader_server_data_helper.cpp @@ -53,6 +53,7 @@ QJsonObject YACReaderServerDataHelper::comicToJSON(const qulonglong libraryId, c json["cover_size_ratio"] = comic.info.coverSizeRatio.toFloat(); json["title"] = comic.info.title.toString(); json["number"] = comic.info.number.toInt(); + json["last_time_opened"] = comic.info.lastTimeOpened.toLongLong(); return json; }