Last active
July 14, 2024 11:52
-
-
Save Clustmart/707fe005fecc1efcb7fe51b3ff8d1e42 to your computer and use it in GitHub Desktop.
Export Safari bookmarks and folder structure to ~/bookmarks.csv
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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)") |
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
Thank you for the response! I have tried the new code, but ran into similar issues
I actually had the import command not found issue, before as well.
I realized that maybe this script was not meant as an executable file, so I tried running it with
swift export-safari-bookmarks-new.swift
which got me permission error, so I tried with sudo but that messed with NSHomeDirectory().
I don't have any prior experience with Swift, can you please share some instructions for your workflow?