feat(sync): Add Kobo/Koreader sync and conflict handling

- Add Kobo markup/sync endpoints for bookshelves
- Add Koreader progress sync with SHA-256 support
- Add sync conflict detection and resolution
- Update ebook scanner for better file matching
This commit is contained in:
2026-01-31 22:32:09 -05:00
parent 63008001c6
commit d28002e4cb
4 changed files with 728 additions and 134 deletions
+20 -10
View File
@@ -64,7 +64,7 @@ type ConflictResolveResponse struct {
DevicesSynced []string `json:"devices_synced"`
}
func (h *ConflictHandler) ListConflicts(c echo.Context) error {
func (h *ConflictHandler) GetConflictsData(c echo.Context) ([]ConflictDetailResponse, int, int, error) {
user := c.Get("user").(database.Users)
status := c.QueryParam("status")
@@ -80,14 +80,11 @@ func (h *ConflictHandler) ListConflicts(c echo.Context) error {
})
if err != nil && err != pgx.ErrNoRows {
return echo.NewHTTPError(http.StatusInternalServerError, "failed to list conflicts")
return nil, 0, 0, err
}
response := ConflictListResponse{
Conflicts: make([]ConflictDetailResponse, 0),
Total: len(conflicts),
Unresolved: 0,
}
response := make([]ConflictDetailResponse, 0, len(conflicts))
unresolvedCount := 0
for _, conflict := range conflicts {
var conflictData map[string]ConflictSourceData
@@ -116,13 +113,26 @@ func (h *ConflictHandler) ListConflicts(c echo.Context) error {
}
}
response.Conflicts = append(response.Conflicts, detail)
response = append(response, detail)
if conflict.ResolutionStatus.String == "unresolved" {
response.Unresolved++
unresolvedCount++
}
}
return c.JSON(http.StatusOK, response)
return response, len(response), unresolvedCount, nil
}
func (h *ConflictHandler) ListConflicts(c echo.Context) error {
conflicts, total, unresolved, err := h.GetConflictsData(c)
if err != nil {
return echo.NewHTTPError(http.StatusInternalServerError, "failed to list conflicts")
}
return c.JSON(http.StatusOK, ConflictListResponse{
Conflicts: conflicts,
Total: total,
Unresolved: unresolved,
})
}
func (h *ConflictHandler) GetConflict(c echo.Context) error {