#!/usr/bin/env python3 """ Clean up LiveSync database - removes orphaned docs and fixes corruption """ import couchdb import time from urllib.parse import quote USER = "admin" PASSWORD = "DonCucarach0!?" IP_ADDRESS = "100.100.112.48" PORT = "5984" DB_NAME = "obsidiandb" def cleanup_db(): safe_password = quote(PASSWORD, safe="") safe_username = quote(USER, safe="") url = f"http://{safe_username}:{safe_password}@{IP_ADDRESS}:{PORT}/" server = couchdb.Server(url) db = server[DB_NAME] print("Scanning for issues...") files_to_fix = [] # Find all file metadata docs for row in db.view('_all_docs', include_docs=True): doc = row.doc # Skip non-file docs if 'children' not in doc: continue # Check if missing required LiveSync fields missing_fields = [] if 'type' not in doc: missing_fields.append('type') if 'size' not in doc: missing_fields.append('size') if 'ctime' not in doc: missing_fields.append('ctime') if 'eden' not in doc: missing_fields.append('eden') if missing_fields: files_to_fix.append((doc['_id'], doc, missing_fields)) print(f"❌ {doc.get('path', doc['_id'])}: missing {missing_fields}") if not files_to_fix: print("\n✅ No issues found!") return print(f"\nFound {len(files_to_fix)} files to fix") print("Fixing...") for doc_id, doc, missing in files_to_fix: # Add missing fields with sensible defaults if 'type' in missing: doc['type'] = 'plain' if 'size' in missing: # Calculate size from chunks doc['size'] = 0 for chunk_id in doc.get('children', []): if chunk_id in db: chunk = db[chunk_id] data = chunk.get('data', chunk.get('content', '')) doc['size'] += len(str(data)) if 'ctime' in missing: doc['ctime'] = doc.get('mtime', int(time.time() * 1000)) if 'eden' in missing: doc['eden'] = {} # Update mtime to trigger sync doc['mtime'] = int(time.time() * 1000) try: db.save(doc) print(f"✓ Fixed: {doc.get('path', doc_id)}") except Exception as e: print(f"✗ Failed to fix {doc_id}: {e}") print("\n✅ Cleanup complete!") print("Now run force_sync.py to trigger Obsidian re-sync") if __name__ == "__main__": cleanup_db()