From 781098141724f194fd68067d5c541717c043eebd Mon Sep 17 00:00:00 2001 From: Huang Xin Date: Fri, 19 Jun 2026 21:37:32 +0800 Subject: [PATCH] fix(koplugin): repair reading-stats sync push/pull (#4666) * fix(koplugin): repair reading-stats sync push/pull Reading statistics (statistics.sqlite3 page events) never reached the Readest sync server. Three stacked defects in the koplugin stats path: 1. push/pull called settings:readSetting/saveSetting on self.settings, which is the plain readest_sync data table (not a LuaSettings object), so auto-sync crashed on every book open ("attempt to call method 'readSetting' (a nil value)"). 2. pushChanges declares books/notes/configs as required_params, but the stats push sent only statBooks/statPages, so Spore rejected the request client-side ("books is required for method pushChanges"). 3. statBooks/statPages were listed only under the spec's payload, not as optional_params. Spore's expected-param set is required_params + optional_params, so it rejected them too ("statBooks is not expected for method pushChanges"). Fixes: - Read/persist the cursor as a plain field and save the whole table via G_reader_settings:saveSetting, mirroring readest_syncauth. - Send empty books/notes/configs alongside statBooks/statPages; the server defaults each to [] and processes the stat arrays independently. - Declare statBooks/statPages as optional_params in readest-sync-api.json. Also add ReadestStats debug logging across pushBookStats/pullBookStats and push/pull (cursor, collected counts, dispatch, response status, cursor advance), and surface the push failure status/body that was previously swallowed on non-interactive syncs. Tests: cover push/pull cursor handling, the pushChanges required_params contract, and a spec-level check that every stats payload key is an expected pushChanges param. Co-Authored-By: Claude Opus 4.8 (1M context) * feat(koplugin): add interactive Push/Pull stats now menu items Add "Push stats now" and "Pull stats now" entries to the Readest sync menu, placed after "Readest library" and before "Push books now" and gated on being signed in (access_token + user_id) like the other account-level items. They call pushBookStats(true) / pullBookStats(true) for a manual interactive sync of reading statistics (the whole statistics.sqlite3 delta), complementing the automatic pull-on-open / push-on-close. Interactive push/pull now also confirm their result (pushed / pulled / up to date) to match the sibling "now" items, since a silent success would look like a no-op. Extract the five new strings into the koplugin .po catalogs (empty msgstr, English fallback at runtime). Co-Authored-By: Claude Opus 4.8 (1M context) * chore(koplugin): translate reading-stats sync strings (33 locales) Fill the previously empty msgstr entries for the reading-statistics sync strings across all koplugin locale catalogs: the two new "Push/Pull stats now" menu items, the pushed / pulled / up-to-date confirmations, and the push/pull failure messages. Each locale mirrors its existing Push/Pull/Failed-to verbs and "reading" terminology for consistency. Co-Authored-By: Claude Opus 4.8 (1M context) --------- Co-authored-by: Claude Opus 4.8 (1M context) --- apps/readest-app/.claude/memory/MEMORY.md | 1 + .../.claude/memory/koplugin-stats-sync.md | 27 ++++++ .../locales/ar/translation.po | 19 +++- .../locales/bn/translation.po | 19 +++- .../locales/bo/translation.po | 19 +++- .../locales/de/translation.po | 19 +++- .../locales/el/translation.po | 19 +++- .../locales/es/translation.po | 19 +++- .../locales/fa/translation.po | 19 +++- .../locales/fr/translation.po | 19 +++- .../locales/he/translation.po | 19 +++- .../locales/hi/translation.po | 19 +++- .../locales/hu/translation.po | 19 +++- .../locales/id/translation.po | 19 +++- .../locales/it/translation.po | 19 +++- .../locales/ja/translation.po | 19 +++- .../locales/ko/translation.po | 19 +++- .../locales/ms/translation.po | 19 +++- .../locales/nl/translation.po | 19 +++- .../locales/pl/translation.po | 19 +++- .../locales/pt-BR/translation.po | 19 +++- .../locales/pt/translation.po | 19 +++- .../locales/ro/translation.po | 19 +++- .../locales/ru/translation.po | 19 +++- .../locales/si/translation.po | 19 +++- .../locales/sl/translation.po | 19 +++- .../locales/sv/translation.po | 19 +++- .../locales/ta/translation.po | 19 +++- .../locales/th/translation.po | 19 +++- .../locales/tr/translation.po | 19 +++- .../locales/uk/translation.po | 19 +++- .../locales/uz/translation.po | 19 +++- .../locales/vi/translation.po | 19 +++- .../locales/zh-CN/translation.po | 19 +++- .../locales/zh-TW/translation.po | 19 +++- apps/readest.koplugin/main.lua | 30 +++++- apps/readest.koplugin/readest-sync-api.json | 1 + apps/readest.koplugin/readest_syncstats.lua | 65 +++++++++++-- apps/readest.koplugin/spec/syncstats_spec.lua | 97 +++++++++++++++++++ 39 files changed, 771 insertions(+), 77 deletions(-) create mode 100644 apps/readest-app/.claude/memory/koplugin-stats-sync.md diff --git a/apps/readest-app/.claude/memory/MEMORY.md b/apps/readest-app/.claude/memory/MEMORY.md index 769b7922..d996c0e4 100644 --- a/apps/readest-app/.claude/memory/MEMORY.md +++ b/apps/readest-app/.claude/memory/MEMORY.md @@ -38,6 +38,7 @@ - [Empty-start CFI sync bug](empty-start-cfi-sync.md) — `epubcfi(/6/24!/4,,/20/1:58)` (empty-start range) from the cfi-inert skip-link transitional window; jumps to wrong section end; `isMalformedLocationCfi` → discard the synced value in `useProgressSync` (NOT the local open path); foliate fix doesn't repair already-synced values - [Custom fonts disappear on cloud sync (#4410)](custom-fonts-reincarnation-4410.md) — CRDT remove-wins: re-import-after-delete needs a `reincarnation` token or the pull re-applies the tombstone; `addFont`/`addTexture` minted none; fix mirrors dictionary (both cases) + OPDS token style; coverage matrix per kind - [koplugin note deletion sync](koplugin-note-deletion-sync.md) — koplugin push only walked LIVE annotations so deletions never reached the server; fix = `recordDeletion` persists a `deletedAt` tombstone to `doc_settings.readest_sync.deleted_notes`, `push` folds+clears them; deletion signal in `onAnnotationsModified` is `items.index_modified < 0` +- [koplugin stats sync (#4666)](koplugin-stats-sync.md) — reading-stats sync (pull on open / push on close, whole statistics.sqlite3 delta, cursor-based); 3-bug chain: plain-table-not-LuaSettings `settings:readSetting` crash; missing required books/notes/configs; statBooks/statPages need `optional_params` (Spore expected=required∪optional, `payload`≠accepted); large-backlog UI-stall + silent-retry risk unfixed ## Testing - [Nightly updater Android E2E](nightly-updater-android-e2e.md) — real Xiaomi/HyperOS test of #4577 self-updater; `pnpm dev-android` (--features devtools) for CDP, raw-socket CDP discovery, nightly>stable comparator, MIUI 单次安装授权 install gates diff --git a/apps/readest-app/.claude/memory/koplugin-stats-sync.md b/apps/readest-app/.claude/memory/koplugin-stats-sync.md new file mode 100644 index 00000000..f7e8568c --- /dev/null +++ b/apps/readest-app/.claude/memory/koplugin-stats-sync.md @@ -0,0 +1,27 @@ +--- +name: koplugin-stats-sync +description: KOReader readest.koplugin reading-stats sync (push on close / pull on open); 3-bug chain fixed in PR +metadata: + node_type: memory + type: project + originSessionId: 9b3eaf27-8688-4293-ab42-f635af2e1905 +--- + +`readest.koplugin` reading-statistics sync (KOReader `statistics.sqlite3` page events) — fixed in PR #4666 (`readest_syncstats.lua`, `main.lua`, `readest-sync-api.json`). + +**Trigger model (fully automatic, no menu/gesture):** +- **Pull** on book OPEN: `onReaderReady` → `pullBookStats(false)` (via `nextTick`). +- **Push** on book CLOSE: `onCloseDocument` → `pushBookStats(false)` (wrapped in `goOnlineToRun`). +- Both gated on `self.settings.auto_sync and self.settings.access_token`, `interactive=false` (silent on failure). +- NOT per-book: `collectSince` queries the whole `statistics.sqlite3` (`page_stat_data JOIN book`, no book filter). Open/close is just the trigger; it syncs the entire stats delta. Incremental via `stats_push_cursor` (max `start_time`) / `stats_pull_cursor` (max `updated_at_ms`); cursor advances only on full success. + +**3 stacked bugs (each hid the next):** +1. `push`/`pull` called `settings:readSetting/saveSetting` on `self.settings`, which is the PLAIN `readest_sync` data table (from `G_reader_settings:readSetting("readest_sync", default)`), NOT a `LuaSettings` object → `attempt to call method 'readSetting' (a nil value)` on every open. Fix: field access + persist via `G_reader_settings:saveSetting("readest_sync", settings)` (mirrors `readest_syncauth.lua`). Field-access pattern is used everywhere else (`self.settings.access_token`, etc.). +2. `pushChanges` requires `books/notes/configs` (`required_params`); stats sent only `statBooks/statPages` → Spore `books is required`. Fix: send empty `books={},notes={},configs={}` alongside. Server (`src/pages/api/sync.ts`) defaults each to `[]` and processes `statBooks`/`statPages` independently (gated only on their own `.length`). +3. `statBooks/statPages` were in the spec's `payload` but not `optional_params` → Spore `statBooks is not expected`. **Spore's expected-param set = `required_params ∪ optional_params`; `payload` only controls body serialization, NOT acceptance** (`common/Spore/Request.lua` `validate()`). Fix: add `optional_params:["statBooks","statPages"]` to `readest-sync-api.json`. Must be optional not required (library/config/annotation pushes legitimately omit them). + +**Spore client:** `readest_syncclient.lua` `_dispatch` runs the RPC in a coroutine with Turbo `AsyncHTTP` (network is non-blocking, yields to event loop); `Format.JSON` encodes the body synchronously first. `SYNC_TIMEOUTS={5,10}` (block/total). + +**Large-backlog blocking risk (UNFIXED, potential follow-up):** push sends the WHOLE backlog in one request (no client chunking; only pull is paginated). For ~10k `page_stat_data` rows: `collectSince` builds a 10k-entry Lua table + ~1MB JSON encode SYNCHRONOUSLY on the main thread → ~1-2s UI stall on weak e-ink CPUs at book close (network part is async, doesn't freeze). Worse: 10s timeout + no chunking + all-or-nothing cursor → if it can't finish in time it fails silently, cursor stays 0, and every later close re-collects/re-encodes/re-uploads the same backlog (server upserts are idempotent but wasteful). Fix idea: chunk push (~500-1000/req, matching server `BATCH=500`), advance cursor per successful chunk. + +**Testing gap that hid it:** `spec/syncstats_spec.lua` originally tested only `collectSince`/`applyRemote`, never `push`/`pull`. Added tests: cursor advance on success (mock client enforces `required_params`), pull cursor from newest `updated_at_ms`, and a spec-level check parsing `readest-sync-api.json` to assert every stats-push key is an expected param (reproduces bug 3). Busted runs with `cwd=KOPLUGIN_DIR` so `io.open("readest-sync-api.json")` works; `require("json")`→dkjson via spec_helper shim. Debug logging kept (`ReadestStats` prefix). Related: [[koplugin-note-deletion-sync]], [[kosync-cfi-spine-resolution]]. diff --git a/apps/readest.koplugin/locales/ar/translation.po b/apps/readest.koplugin/locales/ar/translation.po index 4a2cdb64..9101687e 100644 --- a/apps/readest.koplugin/locales/ar/translation.po +++ b/apps/readest.koplugin/locales/ar/translation.po @@ -251,6 +251,12 @@ msgstr "المزامنة التلقائية" msgid "Readest library" msgstr "مكتبة Readest" +msgid "Push stats now" +msgstr "إرسال الإحصائيات الآن" + +msgid "Pull stats now" +msgstr "جلب الإحصائيات الآن" + msgid "Push books now" msgstr "إرسال الكتب الآن" @@ -437,8 +443,17 @@ msgstr "تمت مزامنة تقدم القراءة" msgid "No saved reading progress found for this book" msgstr "لم يتم العثور على تقدم قراءة محفوظ لهذا الكتاب" +msgid "Reading statistics are up to date" +msgstr "إحصائيات القراءة محدّثة" + +msgid "Reading statistics pushed" +msgstr "تم إرسال إحصائيات القراءة" + msgid "Failed to push reading statistics" -msgstr "" +msgstr "فشل إرسال إحصائيات القراءة" msgid "Failed to pull reading statistics" -msgstr "" +msgstr "فشل جلب إحصائيات القراءة" + +msgid "Reading statistics pulled" +msgstr "تم جلب إحصائيات القراءة" diff --git a/apps/readest.koplugin/locales/bn/translation.po b/apps/readest.koplugin/locales/bn/translation.po index f4d65620..e366a043 100644 --- a/apps/readest.koplugin/locales/bn/translation.po +++ b/apps/readest.koplugin/locales/bn/translation.po @@ -251,6 +251,12 @@ msgstr "অটো সিঙ্ক" msgid "Readest library" msgstr "Readest লাইব্রেরি" +msgid "Push stats now" +msgstr "এখনই পরিসংখ্যান পুশ করুন" + +msgid "Pull stats now" +msgstr "এখনই পরিসংখ্যান পুল করুন" + msgid "Push books now" msgstr "এখনই বই পুশ করুন" @@ -437,8 +443,17 @@ msgstr "পড়ার অগ্রগতি সিঙ্ক হয়েছে msgid "No saved reading progress found for this book" msgstr "এই বইয়ের জন্য সংরক্ষিত পড়ার অগ্রগতি পাওয়া যায়নি" +msgid "Reading statistics are up to date" +msgstr "পড়ার পরিসংখ্যান হালনাগাদ আছে" + +msgid "Reading statistics pushed" +msgstr "পড়ার পরিসংখ্যান পাঠানো হয়েছে" + msgid "Failed to push reading statistics" -msgstr "" +msgstr "পড়ার পরিসংখ্যান পাঠানো ব্যর্থ" msgid "Failed to pull reading statistics" -msgstr "" +msgstr "পড়ার পরিসংখ্যান আনা ব্যর্থ" + +msgid "Reading statistics pulled" +msgstr "পড়ার পরিসংখ্যান আনা হয়েছে" diff --git a/apps/readest.koplugin/locales/bo/translation.po b/apps/readest.koplugin/locales/bo/translation.po index 49395e2e..35f3c54d 100644 --- a/apps/readest.koplugin/locales/bo/translation.po +++ b/apps/readest.koplugin/locales/bo/translation.po @@ -251,6 +251,12 @@ msgstr "རང་འགུལ་མཉམ་སྦྱོར་" msgid "Readest library" msgstr "Readest དཔེ་མཛོད་" +msgid "Push stats now" +msgstr "གྲངས་ཐོ་ད་ལྟ་སྐུར་" + +msgid "Pull stats now" +msgstr "གྲངས་ཐོ་ད་ལྟ་ལེན་" + msgid "Push books now" msgstr "དེབ་རྣམས་ད་ལྟ་སྐུར་" @@ -437,8 +443,17 @@ msgstr "ཀློག་པའི་འཕེལ་རིམ་མཉམ་འག msgid "No saved reading progress found for this book" msgstr "དཔེ་ཆ་འདིའི་ཀློག་པའི་འཕེལ་རིམ་ཉར་ཚགས་མ་རྙེད།" +msgid "Reading statistics are up to date" +msgstr "ཀློག་པའི་གྲངས་ཐོ་གསར་ཤོས་ཡིན།" + +msgid "Reading statistics pushed" +msgstr "ཀློག་པའི་གྲངས་ཐོ་སྐུར་སོང་།" + msgid "Failed to push reading statistics" -msgstr "" +msgstr "ཀློག་པའི་གྲངས་ཐོ་སྐུར་མ་ཐུབ།" msgid "Failed to pull reading statistics" -msgstr "" +msgstr "ཀློག་པའི་གྲངས་ཐོ་ལེན་མ་ཐུབ།" + +msgid "Reading statistics pulled" +msgstr "ཀློག་པའི་གྲངས་ཐོ་ལེན་སོང་།" diff --git a/apps/readest.koplugin/locales/de/translation.po b/apps/readest.koplugin/locales/de/translation.po index 807931a6..7da387a4 100644 --- a/apps/readest.koplugin/locales/de/translation.po +++ b/apps/readest.koplugin/locales/de/translation.po @@ -251,6 +251,12 @@ msgstr "Automatische Synchronisierung" msgid "Readest library" msgstr "Readest-Bibliothek" +msgid "Push stats now" +msgstr "Statistik jetzt senden" + +msgid "Pull stats now" +msgstr "Statistik jetzt abrufen" + msgid "Push books now" msgstr "Bücher jetzt senden" @@ -437,8 +443,17 @@ msgstr "Lesefortschritt synchronisiert" msgid "No saved reading progress found for this book" msgstr "Kein gespeicherter Lesefortschritt für dieses Buch gefunden" +msgid "Reading statistics are up to date" +msgstr "Lesestatistik ist auf dem neuesten Stand" + +msgid "Reading statistics pushed" +msgstr "Lesestatistik gesendet" + msgid "Failed to push reading statistics" -msgstr "" +msgstr "Senden der Lesestatistik fehlgeschlagen" msgid "Failed to pull reading statistics" -msgstr "" +msgstr "Abrufen der Lesestatistik fehlgeschlagen" + +msgid "Reading statistics pulled" +msgstr "Lesestatistik abgerufen" diff --git a/apps/readest.koplugin/locales/el/translation.po b/apps/readest.koplugin/locales/el/translation.po index 9a6f9eda..d6ae937c 100644 --- a/apps/readest.koplugin/locales/el/translation.po +++ b/apps/readest.koplugin/locales/el/translation.po @@ -251,6 +251,12 @@ msgstr "Αυτόματος συγχρονισμός" msgid "Readest library" msgstr "Βιβλιοθήκη Readest" +msgid "Push stats now" +msgstr "Αποστολή στατιστικών τώρα" + +msgid "Pull stats now" +msgstr "Λήψη στατιστικών τώρα" + msgid "Push books now" msgstr "Αποστολή βιβλίων τώρα" @@ -437,8 +443,17 @@ msgstr "Η πρόοδος ανάγνωσης συγχρονίστηκε" msgid "No saved reading progress found for this book" msgstr "Δεν βρέθηκε αποθηκευμένη πρόοδος ανάγνωσης για αυτό το βιβλίο" +msgid "Reading statistics are up to date" +msgstr "Τα στατιστικά ανάγνωσης είναι ενημερωμένα" + +msgid "Reading statistics pushed" +msgstr "Τα στατιστικά ανάγνωσης αποστάλθηκαν" + msgid "Failed to push reading statistics" -msgstr "" +msgstr "Η αποστολή των στατιστικών ανάγνωσης απέτυχε" msgid "Failed to pull reading statistics" -msgstr "" +msgstr "Η λήψη των στατιστικών ανάγνωσης απέτυχε" + +msgid "Reading statistics pulled" +msgstr "Τα στατιστικά ανάγνωσης ελήφθησαν" diff --git a/apps/readest.koplugin/locales/es/translation.po b/apps/readest.koplugin/locales/es/translation.po index 616895b5..fc8604af 100644 --- a/apps/readest.koplugin/locales/es/translation.po +++ b/apps/readest.koplugin/locales/es/translation.po @@ -251,6 +251,12 @@ msgstr "Sincronización automática" msgid "Readest library" msgstr "Biblioteca de Readest" +msgid "Push stats now" +msgstr "Enviar estadísticas ahora" + +msgid "Pull stats now" +msgstr "Obtener estadísticas ahora" + msgid "Push books now" msgstr "Enviar libros ahora" @@ -437,8 +443,17 @@ msgstr "Progreso de lectura sincronizado" msgid "No saved reading progress found for this book" msgstr "No se encontró progreso de lectura guardado para este libro" +msgid "Reading statistics are up to date" +msgstr "Las estadísticas de lectura están actualizadas" + +msgid "Reading statistics pushed" +msgstr "Estadísticas de lectura enviadas" + msgid "Failed to push reading statistics" -msgstr "" +msgstr "Error al enviar las estadísticas de lectura" msgid "Failed to pull reading statistics" -msgstr "" +msgstr "Error al obtener las estadísticas de lectura" + +msgid "Reading statistics pulled" +msgstr "Estadísticas de lectura obtenidas" diff --git a/apps/readest.koplugin/locales/fa/translation.po b/apps/readest.koplugin/locales/fa/translation.po index 0c59b52f..9c5d8c05 100644 --- a/apps/readest.koplugin/locales/fa/translation.po +++ b/apps/readest.koplugin/locales/fa/translation.po @@ -251,6 +251,12 @@ msgstr "همگام‌سازی خودکار" msgid "Readest library" msgstr "کتابخانه Readest" +msgid "Push stats now" +msgstr "اکنون ارسال آمار" + +msgid "Pull stats now" +msgstr "اکنون دریافت آمار" + msgid "Push books now" msgstr "اکنون ارسال کتاب‌ها" @@ -437,8 +443,17 @@ msgstr "پیشرفت مطالعه همگام‌سازی شد" msgid "No saved reading progress found for this book" msgstr "پیشرفت مطالعه ذخیره‌شده‌ای برای این کتاب یافت نشد" +msgid "Reading statistics are up to date" +msgstr "آمار مطالعه به‌روز است" + +msgid "Reading statistics pushed" +msgstr "آمار مطالعه ارسال شد" + msgid "Failed to push reading statistics" -msgstr "" +msgstr "ارسال آمار مطالعه ناموفق بود" msgid "Failed to pull reading statistics" -msgstr "" +msgstr "دریافت آمار مطالعه ناموفق بود" + +msgid "Reading statistics pulled" +msgstr "آمار مطالعه دریافت شد" diff --git a/apps/readest.koplugin/locales/fr/translation.po b/apps/readest.koplugin/locales/fr/translation.po index f5b45e34..2cb19b9c 100644 --- a/apps/readest.koplugin/locales/fr/translation.po +++ b/apps/readest.koplugin/locales/fr/translation.po @@ -251,6 +251,12 @@ msgstr "Synchronisation auto" msgid "Readest library" msgstr "Bibliothèque Readest" +msgid "Push stats now" +msgstr "Envoyer les statistiques maintenant" + +msgid "Pull stats now" +msgstr "Récupérer les statistiques maintenant" + msgid "Push books now" msgstr "Envoyer les livres maintenant" @@ -437,8 +443,17 @@ msgstr "Progression de lecture synchronisée" msgid "No saved reading progress found for this book" msgstr "Aucune progression de lecture enregistrée pour ce livre" +msgid "Reading statistics are up to date" +msgstr "Les statistiques de lecture sont à jour" + +msgid "Reading statistics pushed" +msgstr "Statistiques de lecture envoyées" + msgid "Failed to push reading statistics" -msgstr "" +msgstr "Échec de l'envoi des statistiques de lecture" msgid "Failed to pull reading statistics" -msgstr "" +msgstr "Échec de la récupération des statistiques de lecture" + +msgid "Reading statistics pulled" +msgstr "Statistiques de lecture récupérées" diff --git a/apps/readest.koplugin/locales/he/translation.po b/apps/readest.koplugin/locales/he/translation.po index 49ef223b..6ffe0894 100644 --- a/apps/readest.koplugin/locales/he/translation.po +++ b/apps/readest.koplugin/locales/he/translation.po @@ -251,6 +251,12 @@ msgstr "סנכרון אוטומטי" msgid "Readest library" msgstr "ספריית Readest" +msgid "Push stats now" +msgstr "שלח סטטיסטיקות עכשיו" + +msgid "Pull stats now" +msgstr "משוך סטטיסטיקות עכשיו" + msgid "Push books now" msgstr "שלח ספרים עכשיו" @@ -437,8 +443,17 @@ msgstr "התקדמות הקריאה סונכרנה" msgid "No saved reading progress found for this book" msgstr "לא נמצאה התקדמות קריאה שמורה לספר זה" +msgid "Reading statistics are up to date" +msgstr "סטטיסטיקות הקריאה מעודכנות" + +msgid "Reading statistics pushed" +msgstr "סטטיסטיקות הקריאה נשלחו" + msgid "Failed to push reading statistics" -msgstr "" +msgstr "שליחת סטטיסטיקות הקריאה נכשלה" msgid "Failed to pull reading statistics" -msgstr "" +msgstr "משיכת סטטיסטיקות הקריאה נכשלה" + +msgid "Reading statistics pulled" +msgstr "סטטיסטיקות הקריאה נמשכו" diff --git a/apps/readest.koplugin/locales/hi/translation.po b/apps/readest.koplugin/locales/hi/translation.po index 018c5c46..452b702a 100644 --- a/apps/readest.koplugin/locales/hi/translation.po +++ b/apps/readest.koplugin/locales/hi/translation.po @@ -251,6 +251,12 @@ msgstr "स्वतः सिंक" msgid "Readest library" msgstr "Readest लाइब्रेरी" +msgid "Push stats now" +msgstr "अभी आँकड़े पुश करें" + +msgid "Pull stats now" +msgstr "अभी आँकड़े पुल करें" + msgid "Push books now" msgstr "अभी पुस्तकें पुश करें" @@ -437,8 +443,17 @@ msgstr "पठन प्रगति सिंक हो गई" msgid "No saved reading progress found for this book" msgstr "इस पुस्तक के लिए सहेजी गई पठन प्रगति नहीं मिली" +msgid "Reading statistics are up to date" +msgstr "पठन आँकड़े अद्यतित हैं" + +msgid "Reading statistics pushed" +msgstr "पठन आँकड़े भेजे गए" + msgid "Failed to push reading statistics" -msgstr "" +msgstr "पठन आँकड़े भेजने में विफल" msgid "Failed to pull reading statistics" -msgstr "" +msgstr "पठन आँकड़े प्राप्त करने में विफल" + +msgid "Reading statistics pulled" +msgstr "पठन आँकड़े प्राप्त हुए" diff --git a/apps/readest.koplugin/locales/hu/translation.po b/apps/readest.koplugin/locales/hu/translation.po index 964cde89..57825093 100644 --- a/apps/readest.koplugin/locales/hu/translation.po +++ b/apps/readest.koplugin/locales/hu/translation.po @@ -251,6 +251,12 @@ msgstr "Automatikus szinkron" msgid "Readest library" msgstr "Readest könyvtár" +msgid "Push stats now" +msgstr "Statisztikák küldése most" + +msgid "Pull stats now" +msgstr "Statisztikák lekérése most" + msgid "Push books now" msgstr "Könyvek küldése most" @@ -437,8 +443,17 @@ msgstr "Olvasási haladás szinkronizálva" msgid "No saved reading progress found for this book" msgstr "Nem található mentett olvasási haladás ehhez a könyvhöz" +msgid "Reading statistics are up to date" +msgstr "Az olvasási statisztikák naprakészek" + +msgid "Reading statistics pushed" +msgstr "Olvasási statisztikák elküldve" + msgid "Failed to push reading statistics" -msgstr "" +msgstr "Az olvasási statisztikák küldése sikertelen" msgid "Failed to pull reading statistics" -msgstr "" +msgstr "Az olvasási statisztikák lekérése sikertelen" + +msgid "Reading statistics pulled" +msgstr "Olvasási statisztikák lekérve" diff --git a/apps/readest.koplugin/locales/id/translation.po b/apps/readest.koplugin/locales/id/translation.po index 050331e5..cc7444da 100644 --- a/apps/readest.koplugin/locales/id/translation.po +++ b/apps/readest.koplugin/locales/id/translation.po @@ -251,6 +251,12 @@ msgstr "Sinkronisasi otomatis" msgid "Readest library" msgstr "Pustaka Readest" +msgid "Push stats now" +msgstr "Kirim statistik sekarang" + +msgid "Pull stats now" +msgstr "Tarik statistik sekarang" + msgid "Push books now" msgstr "Kirim buku sekarang" @@ -437,8 +443,17 @@ msgstr "Progres baca disinkronkan" msgid "No saved reading progress found for this book" msgstr "Tidak ada progres baca tersimpan untuk buku ini" +msgid "Reading statistics are up to date" +msgstr "Statistik baca sudah terbaru" + +msgid "Reading statistics pushed" +msgstr "Statistik baca terkirim" + msgid "Failed to push reading statistics" -msgstr "" +msgstr "Gagal mengirim statistik baca" msgid "Failed to pull reading statistics" -msgstr "" +msgstr "Gagal mengambil statistik baca" + +msgid "Reading statistics pulled" +msgstr "Statistik baca diambil" diff --git a/apps/readest.koplugin/locales/it/translation.po b/apps/readest.koplugin/locales/it/translation.po index 3f3ecfe8..1f5d749a 100644 --- a/apps/readest.koplugin/locales/it/translation.po +++ b/apps/readest.koplugin/locales/it/translation.po @@ -251,6 +251,12 @@ msgstr "Sincronizzazione automatica" msgid "Readest library" msgstr "Libreria Readest" +msgid "Push stats now" +msgstr "Invia statistiche ora" + +msgid "Pull stats now" +msgstr "Recupera statistiche ora" + msgid "Push books now" msgstr "Invia libri ora" @@ -437,8 +443,17 @@ msgstr "Progresso di lettura sincronizzato" msgid "No saved reading progress found for this book" msgstr "Nessun progresso di lettura salvato per questo libro" +msgid "Reading statistics are up to date" +msgstr "Le statistiche di lettura sono aggiornate" + +msgid "Reading statistics pushed" +msgstr "Statistiche di lettura inviate" + msgid "Failed to push reading statistics" -msgstr "" +msgstr "Invio delle statistiche di lettura non riuscito" msgid "Failed to pull reading statistics" -msgstr "" +msgstr "Recupero delle statistiche di lettura non riuscito" + +msgid "Reading statistics pulled" +msgstr "Statistiche di lettura ricevute" diff --git a/apps/readest.koplugin/locales/ja/translation.po b/apps/readest.koplugin/locales/ja/translation.po index fd28c072..eb573023 100644 --- a/apps/readest.koplugin/locales/ja/translation.po +++ b/apps/readest.koplugin/locales/ja/translation.po @@ -251,6 +251,12 @@ msgstr "自動同期" msgid "Readest library" msgstr "Readest ライブラリ" +msgid "Push stats now" +msgstr "今すぐ統計を送信" + +msgid "Pull stats now" +msgstr "今すぐ統計を取得" + msgid "Push books now" msgstr "今すぐ書籍を送信" @@ -437,8 +443,17 @@ msgstr "読書の進捗を同期しました" msgid "No saved reading progress found for this book" msgstr "この書籍の保存された読書進捗が見つかりません" +msgid "Reading statistics are up to date" +msgstr "読書統計は最新です" + +msgid "Reading statistics pushed" +msgstr "読書統計を送信しました" + msgid "Failed to push reading statistics" -msgstr "" +msgstr "読書統計の送信に失敗しました" msgid "Failed to pull reading statistics" -msgstr "" +msgstr "読書統計の取得に失敗しました" + +msgid "Reading statistics pulled" +msgstr "読書統計を取得しました" diff --git a/apps/readest.koplugin/locales/ko/translation.po b/apps/readest.koplugin/locales/ko/translation.po index a9bd2b93..9ffad8d6 100644 --- a/apps/readest.koplugin/locales/ko/translation.po +++ b/apps/readest.koplugin/locales/ko/translation.po @@ -251,6 +251,12 @@ msgstr "자동 동기화" msgid "Readest library" msgstr "Readest 라이브러리" +msgid "Push stats now" +msgstr "지금 통계 푸시" + +msgid "Pull stats now" +msgstr "지금 통계 풀" + msgid "Push books now" msgstr "지금 책 푸시" @@ -437,8 +443,17 @@ msgstr "읽기 진행 상황이 동기화되었습니다" msgid "No saved reading progress found for this book" msgstr "이 책의 저장된 읽기 진행 상황을 찾을 수 없습니다" +msgid "Reading statistics are up to date" +msgstr "읽기 통계가 최신 상태입니다" + +msgid "Reading statistics pushed" +msgstr "읽기 통계를 보냈습니다" + msgid "Failed to push reading statistics" -msgstr "" +msgstr "읽기 통계 보내기에 실패했습니다" msgid "Failed to pull reading statistics" -msgstr "" +msgstr "읽기 통계 가져오기에 실패했습니다" + +msgid "Reading statistics pulled" +msgstr "읽기 통계를 가져왔습니다" diff --git a/apps/readest.koplugin/locales/ms/translation.po b/apps/readest.koplugin/locales/ms/translation.po index 59f3b31d..4eaf1778 100644 --- a/apps/readest.koplugin/locales/ms/translation.po +++ b/apps/readest.koplugin/locales/ms/translation.po @@ -251,6 +251,12 @@ msgstr "Penyegerakan automatik" msgid "Readest library" msgstr "Pustaka Readest" +msgid "Push stats now" +msgstr "Hantar statistik sekarang" + +msgid "Pull stats now" +msgstr "Tarik statistik sekarang" + msgid "Push books now" msgstr "Hantar buku sekarang" @@ -437,8 +443,17 @@ msgstr "Kemajuan bacaan disegerakkan" msgid "No saved reading progress found for this book" msgstr "Tiada kemajuan bacaan tersimpan ditemui untuk buku ini" +msgid "Reading statistics are up to date" +msgstr "Statistik bacaan adalah terkini" + +msgid "Reading statistics pushed" +msgstr "Statistik bacaan dihantar" + msgid "Failed to push reading statistics" -msgstr "" +msgstr "Gagal menghantar statistik bacaan" msgid "Failed to pull reading statistics" -msgstr "" +msgstr "Gagal menarik statistik bacaan" + +msgid "Reading statistics pulled" +msgstr "Statistik bacaan ditarik" diff --git a/apps/readest.koplugin/locales/nl/translation.po b/apps/readest.koplugin/locales/nl/translation.po index 85f45640..41b4cf0f 100644 --- a/apps/readest.koplugin/locales/nl/translation.po +++ b/apps/readest.koplugin/locales/nl/translation.po @@ -251,6 +251,12 @@ msgstr "Automatische synchronisatie" msgid "Readest library" msgstr "Readest-bibliotheek" +msgid "Push stats now" +msgstr "Statistieken nu pushen" + +msgid "Pull stats now" +msgstr "Statistieken nu pullen" + msgid "Push books now" msgstr "Boeken nu pushen" @@ -437,8 +443,17 @@ msgstr "Leesvoortgang gesynchroniseerd" msgid "No saved reading progress found for this book" msgstr "Geen opgeslagen leesvoortgang gevonden voor dit boek" +msgid "Reading statistics are up to date" +msgstr "Leesstatistieken zijn up-to-date" + +msgid "Reading statistics pushed" +msgstr "Leesstatistieken verzonden" + msgid "Failed to push reading statistics" -msgstr "" +msgstr "Leesstatistieken verzenden mislukt" msgid "Failed to pull reading statistics" -msgstr "" +msgstr "Leesstatistieken ophalen mislukt" + +msgid "Reading statistics pulled" +msgstr "Leesstatistieken opgehaald" diff --git a/apps/readest.koplugin/locales/pl/translation.po b/apps/readest.koplugin/locales/pl/translation.po index 9c979f1d..5f4814f7 100644 --- a/apps/readest.koplugin/locales/pl/translation.po +++ b/apps/readest.koplugin/locales/pl/translation.po @@ -251,6 +251,12 @@ msgstr "Auto synchronizacja" msgid "Readest library" msgstr "Biblioteka Readest" +msgid "Push stats now" +msgstr "Wyślij statystyki teraz" + +msgid "Pull stats now" +msgstr "Pobierz statystyki teraz" + msgid "Push books now" msgstr "Wyślij książki teraz" @@ -437,8 +443,17 @@ msgstr "Postęp czytania zsynchronizowany" msgid "No saved reading progress found for this book" msgstr "Nie znaleziono zapisanego postępu czytania dla tej książki" +msgid "Reading statistics are up to date" +msgstr "Statystyki czytania są aktualne" + +msgid "Reading statistics pushed" +msgstr "Statystyki czytania wysłane" + msgid "Failed to push reading statistics" -msgstr "" +msgstr "Nie udało się wysłać statystyk czytania" msgid "Failed to pull reading statistics" -msgstr "" +msgstr "Nie udało się pobrać statystyk czytania" + +msgid "Reading statistics pulled" +msgstr "Statystyki czytania pobrane" diff --git a/apps/readest.koplugin/locales/pt-BR/translation.po b/apps/readest.koplugin/locales/pt-BR/translation.po index f0fc7c0c..e91caf9d 100644 --- a/apps/readest.koplugin/locales/pt-BR/translation.po +++ b/apps/readest.koplugin/locales/pt-BR/translation.po @@ -251,6 +251,12 @@ msgstr "Sincronização automática" msgid "Readest library" msgstr "Biblioteca Readest" +msgid "Push stats now" +msgstr "Enviar estatísticas agora" + +msgid "Pull stats now" +msgstr "Obter estatísticas agora" + msgid "Push books now" msgstr "Enviar livros agora" @@ -437,8 +443,17 @@ msgstr "Progresso de leitura sincronizado" msgid "No saved reading progress found for this book" msgstr "Nenhum progresso de leitura salvo encontrado para este livro" +msgid "Reading statistics are up to date" +msgstr "As estatísticas de leitura estão atualizadas" + +msgid "Reading statistics pushed" +msgstr "Estatísticas de leitura enviadas" + msgid "Failed to push reading statistics" -msgstr "" +msgstr "Falha ao enviar as estatísticas de leitura" msgid "Failed to pull reading statistics" -msgstr "" +msgstr "Falha ao obter as estatísticas de leitura" + +msgid "Reading statistics pulled" +msgstr "Estatísticas de leitura obtidas" diff --git a/apps/readest.koplugin/locales/pt/translation.po b/apps/readest.koplugin/locales/pt/translation.po index 9518fa3e..7353055b 100644 --- a/apps/readest.koplugin/locales/pt/translation.po +++ b/apps/readest.koplugin/locales/pt/translation.po @@ -251,6 +251,12 @@ msgstr "Sincronização automática" msgid "Readest library" msgstr "Biblioteca Readest" +msgid "Push stats now" +msgstr "Enviar estatísticas agora" + +msgid "Pull stats now" +msgstr "Obter estatísticas agora" + msgid "Push books now" msgstr "Enviar livros agora" @@ -437,8 +443,17 @@ msgstr "Progresso de leitura sincronizado" msgid "No saved reading progress found for this book" msgstr "Não foi encontrado progresso de leitura guardado para este livro" +msgid "Reading statistics are up to date" +msgstr "As estatísticas de leitura estão atualizadas" + +msgid "Reading statistics pushed" +msgstr "Estatísticas de leitura enviadas" + msgid "Failed to push reading statistics" -msgstr "" +msgstr "Falha ao enviar as estatísticas de leitura" msgid "Failed to pull reading statistics" -msgstr "" +msgstr "Falha ao obter as estatísticas de leitura" + +msgid "Reading statistics pulled" +msgstr "Estatísticas de leitura obtidas" diff --git a/apps/readest.koplugin/locales/ro/translation.po b/apps/readest.koplugin/locales/ro/translation.po index c589428c..2bc18be8 100644 --- a/apps/readest.koplugin/locales/ro/translation.po +++ b/apps/readest.koplugin/locales/ro/translation.po @@ -251,6 +251,12 @@ msgstr "Sincronizare automată" msgid "Readest library" msgstr "Biblioteca Readest" +msgid "Push stats now" +msgstr "Trimite statisticile acum" + +msgid "Pull stats now" +msgstr "Preia statisticile acum" + msgid "Push books now" msgstr "Trimite cărțile acum" @@ -437,8 +443,17 @@ msgstr "Progres de citire sincronizat" msgid "No saved reading progress found for this book" msgstr "Nu s-a găsit progres de citire salvat pentru această carte" +msgid "Reading statistics are up to date" +msgstr "Statisticile de citire sunt actualizate" + +msgid "Reading statistics pushed" +msgstr "Statistici de citire trimise" + msgid "Failed to push reading statistics" -msgstr "" +msgstr "Trimiterea statisticilor de citire a eșuat" msgid "Failed to pull reading statistics" -msgstr "" +msgstr "Obținerea statisticilor de citire a eșuat" + +msgid "Reading statistics pulled" +msgstr "Statistici de citire obținute" diff --git a/apps/readest.koplugin/locales/ru/translation.po b/apps/readest.koplugin/locales/ru/translation.po index 53de7f1c..c6c2ad39 100644 --- a/apps/readest.koplugin/locales/ru/translation.po +++ b/apps/readest.koplugin/locales/ru/translation.po @@ -251,6 +251,12 @@ msgstr "Автосинхронизация" msgid "Readest library" msgstr "Библиотека Readest" +msgid "Push stats now" +msgstr "Отправить статистику сейчас" + +msgid "Pull stats now" +msgstr "Получить статистику сейчас" + msgid "Push books now" msgstr "Отправить книги сейчас" @@ -437,8 +443,17 @@ msgstr "Прогресс чтения синхронизирован" msgid "No saved reading progress found for this book" msgstr "Сохранённый прогресс чтения для этой книги не найден" +msgid "Reading statistics are up to date" +msgstr "Статистика чтения актуальна" + +msgid "Reading statistics pushed" +msgstr "Статистика чтения отправлена" + msgid "Failed to push reading statistics" -msgstr "" +msgstr "Не удалось отправить статистику чтения" msgid "Failed to pull reading statistics" -msgstr "" +msgstr "Не удалось получить статистику чтения" + +msgid "Reading statistics pulled" +msgstr "Статистика чтения получена" diff --git a/apps/readest.koplugin/locales/si/translation.po b/apps/readest.koplugin/locales/si/translation.po index 8921c18e..aa9384d5 100644 --- a/apps/readest.koplugin/locales/si/translation.po +++ b/apps/readest.koplugin/locales/si/translation.po @@ -251,6 +251,12 @@ msgstr "ස්වයංක්‍රීය සමමුහූර්ත" msgid "Readest library" msgstr "Readest පුස්තකාලය" +msgid "Push stats now" +msgstr "සංඛ්‍යාලේඛන දැන් යවන්න" + +msgid "Pull stats now" +msgstr "සංඛ්‍යාලේඛන දැන් ලබාගන්න" + msgid "Push books now" msgstr "දැන් පොත් යවන්න" @@ -437,8 +443,17 @@ msgstr "කියවීමේ ප්‍රගතිය සමමුහූර් msgid "No saved reading progress found for this book" msgstr "මෙම පොත සඳහා සුරකින ලද කියවීමේ ප්‍රගතියක් හමු නොවුණි" +msgid "Reading statistics are up to date" +msgstr "කියවීමේ සංඛ්‍යාලේඛන යාවත්කාලීනයි" + +msgid "Reading statistics pushed" +msgstr "කියවීමේ සංඛ්‍යාලේඛන යවන ලදී" + msgid "Failed to push reading statistics" -msgstr "" +msgstr "කියවීමේ සංඛ්‍යාලේඛන යැවීම අසාර්ථකයි" msgid "Failed to pull reading statistics" -msgstr "" +msgstr "කියවීමේ සංඛ්‍යාලේඛන ලබාගැනීම අසාර්ථකයි" + +msgid "Reading statistics pulled" +msgstr "කියවීමේ සංඛ්‍යාලේඛන ලබා ගන්නා ලදී" diff --git a/apps/readest.koplugin/locales/sl/translation.po b/apps/readest.koplugin/locales/sl/translation.po index 6f37fc29..4f551ead 100644 --- a/apps/readest.koplugin/locales/sl/translation.po +++ b/apps/readest.koplugin/locales/sl/translation.po @@ -251,6 +251,12 @@ msgstr "Samodejna sinhronizacija" msgid "Readest library" msgstr "Knjižnica Readest" +msgid "Push stats now" +msgstr "Pošlji statistiko zdaj" + +msgid "Pull stats now" +msgstr "Pridobi statistiko zdaj" + msgid "Push books now" msgstr "Pošlji knjige zdaj" @@ -437,8 +443,17 @@ msgstr "Napredek branja sinhroniziran" msgid "No saved reading progress found for this book" msgstr "Za to knjigo ni shranjenega napredka branja" +msgid "Reading statistics are up to date" +msgstr "Statistika branja je posodobljena" + +msgid "Reading statistics pushed" +msgstr "Statistika branja poslana" + msgid "Failed to push reading statistics" -msgstr "" +msgstr "Pošiljanje statistike branja ni uspelo" msgid "Failed to pull reading statistics" -msgstr "" +msgstr "Pridobivanje statistike branja ni uspelo" + +msgid "Reading statistics pulled" +msgstr "Statistika branja pridobljena" diff --git a/apps/readest.koplugin/locales/sv/translation.po b/apps/readest.koplugin/locales/sv/translation.po index d8123292..89b4dd12 100644 --- a/apps/readest.koplugin/locales/sv/translation.po +++ b/apps/readest.koplugin/locales/sv/translation.po @@ -251,6 +251,12 @@ msgstr "Automatisk synkronisering" msgid "Readest library" msgstr "Readest-bibliotek" +msgid "Push stats now" +msgstr "Skicka statistik nu" + +msgid "Pull stats now" +msgstr "Hämta statistik nu" + msgid "Push books now" msgstr "Skicka böcker nu" @@ -437,8 +443,17 @@ msgstr "Läsförloppet synkroniserat" msgid "No saved reading progress found for this book" msgstr "Inget sparat läsförlopp hittades för boken" +msgid "Reading statistics are up to date" +msgstr "Lässtatistiken är uppdaterad" + +msgid "Reading statistics pushed" +msgstr "Lässtatistik skickad" + msgid "Failed to push reading statistics" -msgstr "" +msgstr "Det gick inte att skicka lässtatistiken" msgid "Failed to pull reading statistics" -msgstr "" +msgstr "Det gick inte att hämta lässtatistiken" + +msgid "Reading statistics pulled" +msgstr "Lässtatistik hämtad" diff --git a/apps/readest.koplugin/locales/ta/translation.po b/apps/readest.koplugin/locales/ta/translation.po index df21e804..4753d85e 100644 --- a/apps/readest.koplugin/locales/ta/translation.po +++ b/apps/readest.koplugin/locales/ta/translation.po @@ -251,6 +251,12 @@ msgstr "தானியங்கி ஒத்திசைவு" msgid "Readest library" msgstr "Readest நூலகம்" +msgid "Push stats now" +msgstr "புள்ளிவிவரங்களை இப்போது அனுப்பு" + +msgid "Pull stats now" +msgstr "புள்ளிவிவரங்களை இப்போது பெறு" + msgid "Push books now" msgstr "இப்போது புத்தகங்களை அனுப்பு" @@ -437,8 +443,17 @@ msgstr "வாசிப்பு முன்னேற்றம் ஒத்த msgid "No saved reading progress found for this book" msgstr "இந்த நூலுக்கான சேமிக்கப்பட்ட வாசிப்பு முன்னேற்றம் இல்லை" +msgid "Reading statistics are up to date" +msgstr "வாசிப்பு புள்ளிவிவரங்கள் புதுப்பித்த நிலையில் உள்ளன" + +msgid "Reading statistics pushed" +msgstr "வாசிப்பு புள்ளிவிவரங்கள் அனுப்பப்பட்டன" + msgid "Failed to push reading statistics" -msgstr "" +msgstr "வாசிப்பு புள்ளிவிவரங்களை அனுப்புவதில் தோல்வி" msgid "Failed to pull reading statistics" -msgstr "" +msgstr "வாசிப்பு புள்ளிவிவரங்களைப் பெறுவதில் தோல்வி" + +msgid "Reading statistics pulled" +msgstr "வாசிப்பு புள்ளிவிவரங்கள் பெறப்பட்டன" diff --git a/apps/readest.koplugin/locales/th/translation.po b/apps/readest.koplugin/locales/th/translation.po index 0336bab5..1ff30169 100644 --- a/apps/readest.koplugin/locales/th/translation.po +++ b/apps/readest.koplugin/locales/th/translation.po @@ -251,6 +251,12 @@ msgstr "ซิงค์อัตโนมัติ" msgid "Readest library" msgstr "คลัง Readest" +msgid "Push stats now" +msgstr "ส่งสถิติเดี๋ยวนี้" + +msgid "Pull stats now" +msgstr "ดึงสถิติเดี๋ยวนี้" + msgid "Push books now" msgstr "ส่งหนังสือเดี๋ยวนี้" @@ -437,8 +443,17 @@ msgstr "ซิงค์ความคืบหน้าการอ่านแ msgid "No saved reading progress found for this book" msgstr "ไม่พบความคืบหน้าการอ่านที่บันทึกไว้สำหรับหนังสือเล่มนี้" +msgid "Reading statistics are up to date" +msgstr "สถิติการอ่านเป็นปัจจุบันแล้ว" + +msgid "Reading statistics pushed" +msgstr "ส่งสถิติการอ่านแล้ว" + msgid "Failed to push reading statistics" -msgstr "" +msgstr "ส่งสถิติการอ่านไม่สำเร็จ" msgid "Failed to pull reading statistics" -msgstr "" +msgstr "ดึงสถิติการอ่านไม่สำเร็จ" + +msgid "Reading statistics pulled" +msgstr "ดึงสถิติการอ่านแล้ว" diff --git a/apps/readest.koplugin/locales/tr/translation.po b/apps/readest.koplugin/locales/tr/translation.po index 12f215c8..eab1f1dc 100644 --- a/apps/readest.koplugin/locales/tr/translation.po +++ b/apps/readest.koplugin/locales/tr/translation.po @@ -251,6 +251,12 @@ msgstr "Otomatik senkronizasyon" msgid "Readest library" msgstr "Readest kütüphanesi" +msgid "Push stats now" +msgstr "İstatistikleri şimdi gönder" + +msgid "Pull stats now" +msgstr "İstatistikleri şimdi al" + msgid "Push books now" msgstr "Kitapları şimdi gönder" @@ -437,8 +443,17 @@ msgstr "Okuma ilerlemesi senkronize edildi" msgid "No saved reading progress found for this book" msgstr "Bu kitap için kayıtlı okuma ilerlemesi bulunamadı" +msgid "Reading statistics are up to date" +msgstr "Okuma istatistikleri güncel" + +msgid "Reading statistics pushed" +msgstr "Okuma istatistikleri gönderildi" + msgid "Failed to push reading statistics" -msgstr "" +msgstr "Okuma istatistikleri gönderilemedi" msgid "Failed to pull reading statistics" -msgstr "" +msgstr "Okuma istatistikleri alınamadı" + +msgid "Reading statistics pulled" +msgstr "Okuma istatistikleri alındı" diff --git a/apps/readest.koplugin/locales/uk/translation.po b/apps/readest.koplugin/locales/uk/translation.po index 275a6442..c67c5cd0 100644 --- a/apps/readest.koplugin/locales/uk/translation.po +++ b/apps/readest.koplugin/locales/uk/translation.po @@ -251,6 +251,12 @@ msgstr "Автосинхронізація" msgid "Readest library" msgstr "Бібліотека Readest" +msgid "Push stats now" +msgstr "Надіслати статистику зараз" + +msgid "Pull stats now" +msgstr "Отримати статистику зараз" + msgid "Push books now" msgstr "Надіслати книги зараз" @@ -437,8 +443,17 @@ msgstr "Прогрес читання синхронізовано" msgid "No saved reading progress found for this book" msgstr "Збережений прогрес читання для цієї книги не знайдено" +msgid "Reading statistics are up to date" +msgstr "Статистика читання актуальна" + +msgid "Reading statistics pushed" +msgstr "Статистику читання надіслано" + msgid "Failed to push reading statistics" -msgstr "" +msgstr "Не вдалося надіслати статистику читання" msgid "Failed to pull reading statistics" -msgstr "" +msgstr "Не вдалося отримати статистику читання" + +msgid "Reading statistics pulled" +msgstr "Статистику читання отримано" diff --git a/apps/readest.koplugin/locales/uz/translation.po b/apps/readest.koplugin/locales/uz/translation.po index 0cd874f0..90bc9f67 100644 --- a/apps/readest.koplugin/locales/uz/translation.po +++ b/apps/readest.koplugin/locales/uz/translation.po @@ -251,6 +251,12 @@ msgstr "Avtomatik sinxronlash" msgid "Readest library" msgstr "Readest kutubxonasi" +msgid "Push stats now" +msgstr "Statistikani hozir yuborish" + +msgid "Pull stats now" +msgstr "Statistikani hozir olish" + msgid "Push books now" msgstr "Kitoblarni hozir yuborish" @@ -437,8 +443,17 @@ msgstr "Oʻqish jarayoni sinxronlandi" msgid "No saved reading progress found for this book" msgstr "Ushbu kitob uchun saqlangan oʻqish jarayoni topilmadi" +msgid "Reading statistics are up to date" +msgstr "Oʻqish statistikasi eng songgi holatda" + +msgid "Reading statistics pushed" +msgstr "Oʻqish statistikasi yuborildi" + msgid "Failed to push reading statistics" -msgstr "" +msgstr "Oʻqish statistikasini yuborib boʻlmadi" msgid "Failed to pull reading statistics" -msgstr "" +msgstr "Oʻqish statistikasini olib boʻlmadi" + +msgid "Reading statistics pulled" +msgstr "Oʻqish statistikasi olindi" diff --git a/apps/readest.koplugin/locales/vi/translation.po b/apps/readest.koplugin/locales/vi/translation.po index d1553fad..ada33cfc 100644 --- a/apps/readest.koplugin/locales/vi/translation.po +++ b/apps/readest.koplugin/locales/vi/translation.po @@ -251,6 +251,12 @@ msgstr "Tự động đồng bộ" msgid "Readest library" msgstr "Thư viện Readest" +msgid "Push stats now" +msgstr "Gửi thống kê ngay" + +msgid "Pull stats now" +msgstr "Lấy thống kê ngay" + msgid "Push books now" msgstr "Gửi sách ngay" @@ -437,8 +443,17 @@ msgstr "Tiến trình đọc đã đồng bộ" msgid "No saved reading progress found for this book" msgstr "Không tìm thấy tiến trình đọc đã lưu cho sách này" +msgid "Reading statistics are up to date" +msgstr "Thống kê đọc đã được cập nhật" + +msgid "Reading statistics pushed" +msgstr "Đã đẩy thống kê đọc" + msgid "Failed to push reading statistics" -msgstr "" +msgstr "Không thể đẩy thống kê đọc" msgid "Failed to pull reading statistics" -msgstr "" +msgstr "Không thể lấy thống kê đọc" + +msgid "Reading statistics pulled" +msgstr "Đã lấy thống kê đọc" diff --git a/apps/readest.koplugin/locales/zh-CN/translation.po b/apps/readest.koplugin/locales/zh-CN/translation.po index cf73f4e4..f6a7a37e 100644 --- a/apps/readest.koplugin/locales/zh-CN/translation.po +++ b/apps/readest.koplugin/locales/zh-CN/translation.po @@ -251,6 +251,12 @@ msgstr "自动同步" msgid "Readest library" msgstr "Readest 书库" +msgid "Push stats now" +msgstr "立即推送统计" + +msgid "Pull stats now" +msgstr "立即拉取统计" + msgid "Push books now" msgstr "立即推送书籍" @@ -437,8 +443,17 @@ msgstr "阅读进度已同步" msgid "No saved reading progress found for this book" msgstr "未找到此书籍的已保存阅读进度" +msgid "Reading statistics are up to date" +msgstr "阅读统计已是最新" + +msgid "Reading statistics pushed" +msgstr "阅读统计已推送" + msgid "Failed to push reading statistics" -msgstr "" +msgstr "推送阅读统计失败" msgid "Failed to pull reading statistics" -msgstr "" +msgstr "拉取阅读统计失败" + +msgid "Reading statistics pulled" +msgstr "阅读统计已拉取" diff --git a/apps/readest.koplugin/locales/zh-TW/translation.po b/apps/readest.koplugin/locales/zh-TW/translation.po index 1802d988..c86ef4f6 100644 --- a/apps/readest.koplugin/locales/zh-TW/translation.po +++ b/apps/readest.koplugin/locales/zh-TW/translation.po @@ -251,6 +251,12 @@ msgstr "自動同步" msgid "Readest library" msgstr "Readest 書庫" +msgid "Push stats now" +msgstr "立即推送統計" + +msgid "Pull stats now" +msgstr "立即拉取統計" + msgid "Push books now" msgstr "立即推送書籍" @@ -437,8 +443,17 @@ msgstr "閱讀進度已同步" msgid "No saved reading progress found for this book" msgstr "找不到此書籍的閱讀進度" +msgid "Reading statistics are up to date" +msgstr "閱讀統計已是最新" + +msgid "Reading statistics pushed" +msgstr "閱讀統計已推送" + msgid "Failed to push reading statistics" -msgstr "" +msgstr "推送閱讀統計失敗" msgid "Failed to pull reading statistics" -msgstr "" +msgstr "拉取閱讀統計失敗" + +msgid "Reading statistics pulled" +msgstr "閱讀統計已拉取" diff --git a/apps/readest.koplugin/main.lua b/apps/readest.koplugin/main.lua index eb58b315..b7b1cc09 100644 --- a/apps/readest.koplugin/main.lua +++ b/apps/readest.koplugin/main.lua @@ -331,6 +331,24 @@ function ReadestSync:addToMainMenu(menu_items) self:openLibrary() end, }, + { + text = _("Push stats now"), + enabled_func = function() + return self.settings.access_token ~= nil and self.settings.user_id ~= nil + end, + callback = function() + self:pushBookStats(true) + end, + }, + { + text = _("Pull stats now"), + enabled_func = function() + return self.settings.access_token ~= nil and self.settings.user_id ~= nil + end, + callback = function() + self:pullBookStats(true) + end, + }, { text = _("Push books now"), enabled_func = function() @@ -538,20 +556,28 @@ end -- ── Reading statistics sync ──────────────────────────────────────── function ReadestSync:pushBookStats(interactive) + logger.dbg("ReadestStats pushBookStats: triggered, interactive=" .. tostring(interactive)) if interactive and NetworkMgr:willRerunWhenOnline(function() self:pushBookStats(interactive) end) then return end local client = self:ensureClient(interactive) - if not client then return end + if not client then + logger.dbg("ReadestStats pushBookStats: no client (not signed in / offline); skipping") + return + end SyncStats:push(self.settings, client, interactive) end function ReadestSync:pullBookStats(interactive) + logger.dbg("ReadestStats pullBookStats: triggered, interactive=" .. tostring(interactive)) if NetworkMgr:willRerunWhenOnline(function() self:pullBookStats(interactive) end) then return end local client = self:ensureClient(interactive) - if not client then return end + if not client then + logger.dbg("ReadestStats pullBookStats: no client (not signed in / offline); skipping") + return + end SyncStats:pull(self.settings, client, interactive, function() SyncAuth:logout(self.settings, self.path) end) end diff --git a/apps/readest.koplugin/readest-sync-api.json b/apps/readest.koplugin/readest-sync-api.json index 757c6439..3f54f8bb 100644 --- a/apps/readest.koplugin/readest-sync-api.json +++ b/apps/readest.koplugin/readest-sync-api.json @@ -12,6 +12,7 @@ "path": "/sync", "method": "POST", "required_params": ["books", "notes", "configs"], + "optional_params": ["statBooks", "statPages"], "payload": ["books", "notes", "configs", "statBooks", "statPages"], "expected_status": [200, 201, 301, 400, 401, 403] }, diff --git a/apps/readest.koplugin/readest_syncstats.lua b/apps/readest.koplugin/readest_syncstats.lua index a55bb2bd..5ab12550 100644 --- a/apps/readest.koplugin/readest_syncstats.lua +++ b/apps/readest.koplugin/readest_syncstats.lua @@ -2,6 +2,7 @@ local DataStorage = require("datastorage") local InfoMessage = require("ui/widget/infomessage") local UIManager = require("ui/uimanager") local SQ3 = require("lua-ljsqlite3/init") +local logger = require("logger") local _ = require("readest_i18n") local SyncStats = {} @@ -85,28 +86,60 @@ function SyncStats:applyRemote(books, pages) end function SyncStats:push(settings, client, interactive) - local cursor = settings:readSetting("stats_push_cursor") or 0 + -- `settings` is the plain readest_sync data table (see main.lua:init), so + -- the cursor is a field; persist by saving the whole table back to + -- G_reader_settings, mirroring readest_syncauth. + local cursor = settings.stats_push_cursor or 0 local books, pages = self:collectSince(cursor) - if #pages == 0 then return end + logger.dbg("ReadestStats push: cursor=" .. tostring(cursor) + .. " collected books=" .. #books .. " pages=" .. #pages + .. " interactive=" .. tostring(interactive)) + if #pages == 0 then + logger.dbg("ReadestStats push: nothing to push (no page events past cursor)") + if interactive then + UIManager:show(InfoMessage:new{ text = _("Reading statistics are up to date"), timeout = 2 }) + end + return + end local max_start = cursor for _, p in ipairs(pages) do if p.start_time > max_start then max_start = p.start_time end end + logger.dbg("ReadestStats push: dispatching " .. #pages .. " page(s); new cursor would be " + .. tostring(max_start)) + -- pushChanges declares books/notes/configs as required_params (shared /sync + -- POST contract, readest-sync-api.json); include them empty so Spore sends + -- the request — the server defaults each to [] and processes statBooks/ + -- statPages independently (apps/readest-app/src/pages/api/sync.ts). client:pushChanges( - { statBooks = books, statPages = pages }, - function(success) + { books = {}, notes = {}, configs = {}, statBooks = books, statPages = pages }, + function(success, body, status) + logger.dbg("ReadestStats push: response success=" .. tostring(success) + .. " status=" .. tostring(status)) if success then - settings:saveSetting("stats_push_cursor", max_start) - elseif interactive then - UIManager:show(InfoMessage:new{ text = _("Failed to push reading statistics"), timeout = 2 }) + settings.stats_push_cursor = max_start + G_reader_settings:saveSetting("readest_sync", settings) + logger.dbg("ReadestStats push: cursor advanced to " .. tostring(max_start)) + if interactive then + UIManager:show(InfoMessage:new{ text = _("Reading statistics pushed"), timeout = 2 }) + end + else + logger.dbg("ReadestStats push: failed, cursor unchanged; body=" .. tostring(body)) + if interactive then + UIManager:show(InfoMessage:new{ text = _("Failed to push reading statistics"), timeout = 2 }) + end end end) end function SyncStats:pull(settings, client, interactive, logout_fn) - local since = settings:readSetting("stats_pull_cursor") or 0 + local since = settings.stats_pull_cursor or 0 + logger.dbg("ReadestStats pull: since=" .. tostring(since) + .. " interactive=" .. tostring(interactive)) -- pullChanges requires since/type/book/meta_hash params (readest-sync-api.json). client:pullChanges( { since = since, type = "stats", book = "", meta_hash = "" }, function(success, response, status) + logger.dbg("ReadestStats pull: response success=" .. tostring(success) + .. " status=" .. tostring(status)) if not success then if status == 401 or status == 403 then if logout_fn then logout_fn() end @@ -116,13 +149,27 @@ function SyncStats:pull(settings, client, interactive, logout_fn) end return end + local nbooks = response and response.statBooks and #response.statBooks or 0 + local npages = response and response.statPages and #response.statPages or 0 + logger.dbg("ReadestStats pull: applying statBooks=" .. nbooks .. " statPages=" .. npages) self:applyRemote(response.statBooks, response.statPages) local newest = since for _, p in ipairs(response.statPages or {}) do local u = tonumber(p.updated_at_ms) or 0 if u > newest then newest = u end end - if newest > since then settings:saveSetting("stats_pull_cursor", newest) end + if newest > since then + settings.stats_pull_cursor = newest + G_reader_settings:saveSetting("readest_sync", settings) + logger.dbg("ReadestStats pull: cursor advanced to " .. tostring(newest)) + else + logger.dbg("ReadestStats pull: cursor unchanged (no newer rows)") + end + if interactive then + local text = npages > 0 and _("Reading statistics pulled") + or _("Reading statistics are up to date") + UIManager:show(InfoMessage:new{ text = text, timeout = 2 }) + end end) end diff --git a/apps/readest.koplugin/spec/syncstats_spec.lua b/apps/readest.koplugin/spec/syncstats_spec.lua index 1dce910c..51622478 100644 --- a/apps/readest.koplugin/spec/syncstats_spec.lua +++ b/apps/readest.koplugin/spec/syncstats_spec.lua @@ -146,4 +146,101 @@ describe("readest_syncstats", function() assert.are.equal(2, tonumber(total_pages)) -- distinct pages 1,2 assert.are.equal(212, tonumber(last_open)) -- max(start_time + duration) = 200 + 12 end) + + -- settings here is the plain readest_sync data table (as returned by + -- G_reader_settings:readSetting("readest_sync", ...)), NOT a LuaSettings + -- object — push/pull must read/persist the cursor as a field, not via + -- settings:readSetting/saveSetting (which would crash on the plain table). + -- The shared /sync POST (pushChanges) declares books/notes/configs as + -- required_params in readest-sync-api.json, so Spore rejects the request + -- before sending if any is absent. This mock mirrors that rejection so the + -- stats push must include them (empty) alongside statBooks/statPages. + local PUSH_REQUIRED = { "books", "notes", "configs" } + local function makePushClient(captured) + return { + pushChanges = function(_, payload, cb) + captured.payload = payload + for _, k in ipairs(PUSH_REQUIRED) do + if payload[k] == nil then + captured.missing = k + return cb(false) -- Spore would reject; request never sent + end + end + cb(true) + end, + } + end + + it("advances stats_push_cursor as a plain field after a successful push", function() + local conn = SQ3.open(statsDbPath()) + conn:exec("INSERT INTO book (title, authors, md5) VALUES ('T', 'A', 'md5-p');") + conn:exec("INSERT INTO page_stat_data (id_book, page, start_time, duration, total_pages) VALUES (1, 1, 100, 5, 9);") + conn:exec("INSERT INTO page_stat_data (id_book, page, start_time, duration, total_pages) VALUES (1, 2, 250, 6, 9);") + conn:close() + + local settings = { stats_push_cursor = 0 } + local captured = {} + + SyncStats:push(settings, makePushClient(captured), false) + + assert.is_nil(captured.missing) -- satisfied the pushChanges required_params + assert.are.equal(2, #captured.payload.statPages) + assert.are.equal(250, settings.stats_push_cursor) -- max start_time; only set on success + end) + + -- The "Push stats now" / "Pull stats now" menu entries call push/pull with + -- interactive=true; an interactive sync must confirm its result the way the + -- sibling "now" menu items do (a silent success looks like a no-op). + it("shows an interactive confirmation when there is nothing to push", function() + local InfoMessage = require("ui/widget/infomessage") + local UIManager = require("ui/uimanager") + local orig_new, orig_show = InfoMessage.new, UIManager.show + local shown + InfoMessage.new = function(_, o) return { text = o and o.text } end + UIManager.show = function(_, w) shown = w and w.text end + + -- fresh empty stats DB (before_each) → no page events past the cursor + SyncStats:push({ stats_push_cursor = 0 }, makePushClient({}), true) + + InfoMessage.new, UIManager.show = orig_new, orig_show + assert.are.equal("Reading statistics are up to date", shown) + end) + + -- Spore's validate() (common/Spore/Request.lua) asserts every param passed + -- to a method is in required_params ∪ optional_params ("X is not expected"), + -- and that every required_param is present. Declaring a key only under + -- `payload` controls body serialization, NOT acceptance. So the readest-sync + -- spec must list statBooks/statPages as optional_params for the stats push. + it("declares the stats push payload keys as expected pushChanges params", function() + local json = require("json") + local f = assert(io.open("readest-sync-api.json", "r")) + local spec = json.decode(f:read("*a")) + f:close() + + local method = spec.methods.pushChanges + local expected = {} + for _, k in ipairs(method.required_params or {}) do expected[k] = true end + for _, k in ipairs(method.optional_params or {}) do expected[k] = true end + + -- the exact set of keys SyncStats:push sends + for _, k in ipairs({ "books", "notes", "configs", "statBooks", "statPages" }) do + assert.is_true(expected[k] == true, k .. " must be an expected pushChanges param") + end + end) + + it("advances stats_pull_cursor as a plain field after a successful pull", function() + local settings = { stats_pull_cursor = 0 } + local response = { + statBooks = { { book_hash = "md5-pull", title = "P", authors = "A" } }, + statPages = { + { book_hash = "md5-pull", page = 1, start_time = 100, duration = 5, + total_pages = 10, updated_at_ms = 4242 }, + }, + } + local client = { pullChanges = function(_, _params, cb) cb(true, response, 200) end } + + SyncStats:pull(settings, client, false, function() end) + + assert.are.equal(4242, settings.stats_pull_cursor) -- newest updated_at_ms + end) end)