Skip to content

Instantly share code, notes, and snippets.

@Clustmart
Last active July 14, 2024 11:52
Show Gist options
  • Save Clustmart/707fe005fecc1efcb7fe51b3ff8d1e42 to your computer and use it in GitHub Desktop.
Save Clustmart/707fe005fecc1efcb7fe51b3ff8d1e42 to your computer and use it in GitHub Desktop.
Export Safari bookmarks and folder structure to ~/bookmarks.csv
import Foundation
// Define the file path to save the CSV
let filePath = FileManager.default.homeDirectoryForCurrentUser.appendingPathComponent("bookmarks.csv")
// Create the CSV file if it doesn't exist
if !FileManager.default.fileExists(atPath: filePath.path) {
FileManager.default.createFile(atPath: filePath.path, contents: nil, attributes: nil)
}
// Open the file handle for writing
guard let fileHandle = try? FileHandle(forWritingTo: filePath) else {
print("Failed to open file for writing.")
exit(1)
}
defer {
fileHandle.closeFile()
}
// Write the CSV headers
let headers = "Website name,URL,Bookmark path\n"
fileHandle.write(headers.data(using: .utf8)!)
// Get all bookmarks
let bookmarksPlistPath = "\(NSHomeDirectory())/Library/Safari/Bookmarks.plist"
let bookmarksData = try! Data(contentsOf: URL(fileURLWithPath: bookmarksPlistPath))
let plist = try! PropertyListSerialization.propertyList(from: bookmarksData, options: [], format: nil)
// Recursive function to get all bookmarks with their parent folders
func getAllBookmarks(bookmarks: [[String: Any]], parentFolders: [String]) -> [[String]] {
var results: [[String]] = []
for bookmark in bookmarks {
if let url = bookmark["URLString"] as? String,
let uriDictionary = bookmark["URIDictionary"] as? [String: Any],
let name = uriDictionary["title"] as? String {
let bookmarkPath = parentFolders.joined(separator: " > ")
results.append([name, url, bookmarkPath])
}
if let children = bookmark["Children"] as? [[String: Any]] {
let newParentFolders = parentFolders + [bookmark["Title"] as! String]
results += getAllBookmarks(bookmarks: children, parentFolders: newParentFolders)
}
}
return results
}
// Call the recursive function to get all bookmarks with their parent folders
let allBookmarks = getAllBookmarks(bookmarks: (plist as! NSDictionary)["Children"] as! [[String: Any]], parentFolders: [])
// Write the bookmarks to the CSV
for bookmark in allBookmarks {
let line = "\(bookmark[0]),\(bookmark[1]),\(bookmark[2])\n"
fileHandle.write(line.data(using: .utf8)!)
}
print("Bookmarks exported to: \(filePath)")
@Clustmart
Copy link
Author

I couldn't replicate your issue. The error import: command not found indicates that the import statement is being interpreted as a shell command rather than a valid Swift language construct. This typically happens when you try to execute a Swift script using a shell interpreter.
You should make sure that swift is installed (execute swift --version). Executing swift export-safari-bookmarks-new.swift is correct, it works on my system.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment