148 lines
4.1 KiB
JavaScript
148 lines
4.1 KiB
JavaScript
// Synchronization Utilities
|
|
// Handles sync logic and conflict resolution
|
|
|
|
(function() {
|
|
'use strict';
|
|
|
|
const SyncUtils = {
|
|
|
|
// Sync mode descriptions
|
|
MODES: {
|
|
'bi-directional': {
|
|
name: 'Bi-Directional',
|
|
description: 'Keep both versions; additions/updates replicate both ways',
|
|
deleteFromLinkding: true,
|
|
keepBothOnUpdate: true
|
|
},
|
|
'write-only': {
|
|
name: 'Write-Only',
|
|
description: 'Browser is authoritative; updates push to Linkding only',
|
|
deleteFromLinkding: true,
|
|
keepBothOnUpdate: false
|
|
},
|
|
'read-only': {
|
|
name: 'Read-Only',
|
|
description: 'Linkding is authoritative; download from Linkding only',
|
|
deleteFromLinkding: false,
|
|
keepBothOnUpdate: false
|
|
}
|
|
},
|
|
|
|
// Get sync mode config
|
|
getModeConfig(mode) {
|
|
return this.MODES[mode] || this.MODES['bi-directional'];
|
|
},
|
|
|
|
// Determine sync action based on mode
|
|
determineSyncAction(mode, action) {
|
|
const config = this.getModeConfig(mode);
|
|
|
|
switch (action) {
|
|
case 'create':
|
|
// New bookmark in browser
|
|
if (config.deleteFromLinkding) {
|
|
return { action: 'create', deleteFromLinkding: false };
|
|
}
|
|
return { action: 'create' };
|
|
|
|
case 'update':
|
|
// Existing bookmark with changes
|
|
if (config.keepBothOnUpdate) {
|
|
return { action: 'update', keepBoth: true };
|
|
}
|
|
return { action: 'update' };
|
|
|
|
case 'delete':
|
|
// Bookmark deleted from browser
|
|
if (config.deleteFromLinkding) {
|
|
return { action: 'delete' };
|
|
}
|
|
return { action: 'ignore' };
|
|
|
|
default:
|
|
return { action: 'none' };
|
|
}
|
|
},
|
|
|
|
// Resolve conflict when same URL exists in different folders
|
|
resolveConflict(browserBookmark, linkdingBookmark, browserNotes, linkdingNotes, mode) {
|
|
const config = this.getModeConfig(mode);
|
|
|
|
if (config.keepBothOnUpdate) {
|
|
// Bi-directional: keep both, use Linkding notes as primary
|
|
const mergedNotes = {
|
|
path: browserNotes.path || linkdingNotes.path,
|
|
userNotes: config.keepBothOnUpdate ? linkdingNotes.userNotes : browserNotes.userNotes,
|
|
autoTags: []
|
|
};
|
|
|
|
return {
|
|
action: 'update',
|
|
notes: mergedNotes,
|
|
note: 'Updated with browser path; Linkding notes preserved'
|
|
};
|
|
}
|
|
|
|
// Write-only or read-only: use browser data
|
|
return {
|
|
action: 'update',
|
|
notes: browserNotes,
|
|
note: 'Updated from browser'
|
|
};
|
|
},
|
|
|
|
// Check if bookmark needs sync
|
|
needsSync(browserBookmark, linkdingBookmark, browserNotes, linkdingNotes) {
|
|
// Check if URLs match
|
|
if (browserBookmark.url !== linkdingBookmark.url) {
|
|
return true;
|
|
}
|
|
|
|
// Check if path changed
|
|
if (browserNotes.path !== linkdingNotes.path) {
|
|
return true;
|
|
}
|
|
|
|
// Check if notes changed
|
|
if (browserNotes.userNotes !== linkdingNotes.userNotes) {
|
|
return true;
|
|
}
|
|
|
|
// Check if tags changed
|
|
const browserTags = browserNotes.autoTags.map(t => t.name);
|
|
const linkdingTags = linkdingNotes.autoTags.map(t => t.name);
|
|
|
|
if (JSON.stringify(browserTags) !== JSON.stringify(linkdingTags)) {
|
|
return true;
|
|
}
|
|
|
|
return false;
|
|
},
|
|
|
|
// Get last sync timestamp
|
|
getLastSyncTime() {
|
|
return new Date().toISOString();
|
|
},
|
|
|
|
// Format sync timestamp for display
|
|
formatTimestamp(timestamp) {
|
|
if (!timestamp) return 'Never';
|
|
|
|
const date = new Date(timestamp);
|
|
const options = {
|
|
year: 'numeric',
|
|
month: 'short',
|
|
day: 'numeric',
|
|
hour: '2-digit',
|
|
minute: '2-digit',
|
|
timeZoneName: 'short'
|
|
};
|
|
|
|
return date.toLocaleDateString('en-US', options);
|
|
}
|
|
};
|
|
|
|
// Export for use in other scripts
|
|
window.SyncUtils = SyncUtils;
|
|
|
|
})(); |