@@ -10,19 +10,26 @@ local _ = require("gettext")
1010local SyncService = require (" frontend/apps/cloudstorage/syncservice" )
1111local Merge = require (" merge" )
1212local rapidjson = require (" rapidjson" )
13+ local NetworkMgr = require (" ui/network/manager" )
14+ local logger = require (" logger" )
15+
16+ local is_reloading_due_to_sync = false
17+
18+
1319
1420local function dir_exists (path )
1521 local ok , _ , code = os.rename (path , path )
1622 if not ok then
17- -- Código 13 = permission denied, mas o diretório existe
23+ -- Código 13 = permission denied, bat folder has to exist
1824 return code == 13
1925 end
2026 return true
2127end
2228
2329local function ensure_dir_exists (path )
2430 if not dir_exists (path ) then
25- local result = os.execute (' mkdir -p "' .. path .. ' "' )
31+ local safe_path = path :gsub (" %$" , " \\ $" )
32+ local result = os.execute (' mkdir -p "' .. safe_path .. ' "' )
2633 if not result then
2734 error (" Failed to create directory: " .. path )
2835 end
7683local function read_json_file (path )
7784 local file = io.open (path , " r" )
7885 if not file then
79- -- Arquivo não existe
86+ -- file doesn't exist
8087 return {}
8188 end
8289
108115
109116
110117function Highlightsync :onDispatcherRegisterActions ()
111- Dispatcher :registerAction (" hightlightsync_action" , {category = " none" , event = " SyncBookHighlights" , title = _ (" Highlight Sync" ), reader = true ,})
118+
119+ --- for gestures
120+ Dispatcher :registerAction (" hightlightsync_action" , {
121+ category = " none" ,
122+ event = " SyncBookHighlights" ,
123+ title = _ (" Sync Highlights Now" ),
124+ help = _ (" Synchronize highlights with the cloud." ),
125+ reader = true ,
126+ callback = function ()
127+ self :onSyncBookHighlights (false )
128+ end
129+ })
130+
112131end
113132
114133Highlightsync .default_settings = {
@@ -122,21 +141,79 @@ function Highlightsync:init()
122141 return -- disable in PIC documents
123142 end
124143
144+ self .is_syncing = false
145+
125146 Highlightsync .settings = G_reader_settings :readSetting (" highlight_sync" , self .default_settings )
126147 self :onDispatcherRegisterActions (
127148 self .ui .menu :registerToMainMenu (self ))
128149end
129150
151+ function Highlightsync :onReaderReady ()
152+
153+ if is_reloading_due_to_sync then
154+ is_reloading_due_to_sync = false
155+ return
156+ end
157+
158+ if self .settings .sync_on_open and self :canSync () then
159+ UIManager :nextTick (function ()
160+ self :onSyncBookHighlights (false , true )
161+ end )
162+ end
163+ end
164+
165+ function Highlightsync :onCloseDocument ()
166+
167+ if is_reloading_due_to_sync then
168+ return
169+ end
170+
171+
172+ if self .settings .sync_on_close and self :canSync () then
173+ -- Sincroniza e sai (sem reload, pois estamos saindo)
174+ self :onSyncBookHighlights (false , false )
175+ end
176+ end
177+
178+ function Highlightsync :onResume ()
179+
180+ if self .settings .sync_on_resume then
181+ UIManager :nextTick (function ()
182+ if NetworkMgr :isWifiOn () then
183+ self :onSyncBookHighlights (false , true )
184+ self .settings .pending_sync = false
185+ G_reader_settings :saveSetting (" highlight_sync" , self .settings )
186+ end
187+ end )
188+ end
189+
190+ end
191+
130192
131- function Highlightsync .onSync (local_path , cached_path , income_path )
193+
194+ function Highlightsync :onSync (local_path , cached_path , income_path , reload )
132195
133196 local local_highlights = DataAnnotations -- read_json_file(local_path) or {}
134197 local cached_highlights = read_json_file (cached_path ) or {}
135198 local income_highlights = read_json_file (income_path ) or {}
199+
136200 local annotations = Merge .Merge_highlights (local_highlights ,income_highlights ,cached_highlights )
137201
138202 write_json_file (SidecarDir .. " /" .. FileName .. " .json" , annotations ) -- Save annotations local
139203 DataAnnotations = annotations
204+
205+
206+ UIManager :nextTick (function ()
207+ if self .ui and self .ui .annotation then
208+ self .ui .annotation .annotations = DataAnnotations
209+ if reload then
210+ is_reloading_due_to_sync = true
211+ self .ui :reloadDocument ()
212+ end
213+ end
214+ end )
215+
216+
140217 return true
141218end
142219
@@ -152,25 +229,55 @@ function Highlightsync:canSync()
152229 return self .is_doc (self ) and self .settings .sync_server ~= nil
153230end
154231
232+ local function sanitize_filename (str )
233+ if not str then return " " end
234+ return str :gsub (" [^%w%.%-%_]" , " _" )
235+ end
155236
156237
157- function Highlightsync :onSyncBookHighlights ()
238+
239+ function Highlightsync :onSyncBookHighlights (silent , reload )
158240 if not self :canSync () then return end
159241
160- UIManager :show (InfoMessage :new {
161- text = _ (" Syncing book highlights. This may take a while." ),
162- timeout = 1 ,
163- })
242+ if not silent then
243+ UIManager :show (InfoMessage :new {
244+ text = _ (" Syncing book highlights. This may take a while." ),
245+ timeout = 1 ,
246+ })
247+ end
248+
249+ if self .is_syncing then
250+ logger .warn (" Highlightsync: Duplicate sync attempt ignored." )
251+ return
252+ end
253+
254+ -- enable lock
255+ self .is_syncing = true
164256
165257 UIManager :nextTick (function ()
166- DataAnnotations = self .ui .annotation .annotations -- self.ui.doc_settings.data.annotations
167- SidecarDir = self .ui .doc_settings .doc_sidecar_dir
168- FileName = SidecarDir :match (" ([^/]+)/*$" )
258+
259+ local doc_path = self .document and self .document .file
260+ local doc_settings = self .ui and self .ui .doc_settings
261+ SidecarDir = doc_settings :getSidecarDir (doc_path )
169262 ensure_dir_exists (SidecarDir )
263+ DataAnnotations = self .ui .annotation .annotations -- self.ui.doc_settings.data.annotations
264+
265+ Raw_name = SidecarDir :match (" ([^/]+)/*$" )
266+ FileName = sanitize_filename (Raw_name )
267+
170268 write_json_file (SidecarDir .. " /" .. FileName .. " .json" , self .ui .annotation .annotations ) -- Save annotations local
171- SyncService .sync (self .settings .sync_server , SidecarDir .. " /" .. FileName .. " .json" , self .onSync )
172- self .ui .annotation .annotations = DataAnnotations
173- self .ui :reloadDocument ()
269+
270+ SyncService .sync (self .settings .sync_server , SidecarDir .. " /" .. FileName .. " .json" ,
271+ function (local_path , cached_path , income_path )
272+ local success = self :onSync (local_path , cached_path , income_path , reload )
273+ self .is_syncing = false
274+ return success
275+ end ,
276+ silent
277+ )
278+
279+
280+
174281 end )
175282end
176283
@@ -246,9 +353,38 @@ function Highlightsync:addToMainMenu(menu_items)
246353 {
247354 text = _ (" Sync Highlights" ),
248355 callback = function ()
249- self :onSyncBookHighlights ()
356+ self :onSyncBookHighlights (true , false )
250357 end ,
251358 enabled_func = function () return self .canSync (self ) end
359+ },
360+ {
361+ text = _ (" Settings" ),
362+ sub_item_table = {
363+ {
364+ text = _ (" Sync on Book Open" ),
365+ checked_func = function () return self .settings .sync_on_open end ,
366+ callback = function ()
367+ self .settings .sync_on_open = not self .settings .sync_on_open
368+ G_reader_settings :saveSetting (" highlight_sync" , self .settings )
369+ end ,
370+ },
371+ {
372+ text = _ (" Sync on Book Close" ),
373+ checked_func = function () return self .settings .sync_on_close end ,
374+ callback = function ()
375+ self .settings .sync_on_close = not self .settings .sync_on_close
376+ G_reader_settings :saveSetting (" highlight_sync" , self .settings )
377+ end ,
378+ },
379+ {
380+ text = _ (" Sync on Book on resume" ),
381+ checked_func = function () return self .settings .sync_on_resume end ,
382+ callback = function ()
383+ self .settings .sync_on_resume = not self .settings .sync_on_resume
384+ G_reader_settings :saveSetting (" highlight_sync" , self .settings )
385+ end ,
386+ },
387+ }
252388 }
253389 }
254390 }
0 commit comments