Firefox bookmarks into filesystem shortcuts
2013-Feb-17, Sunday 01:43 amI wrote a Powershell script to convert my Firefox browser bookmarks into shortcut files on my hard drive. I was getting too large a collection, and saving new bookmarks was finally taking obviously more-than-zero time to process. From now on, I'll just drag shortcuts into folders for easier sorting and searching.
Powershell V3 includes new JSON commands, but they didn't work because my data store was too large. I had to use a 3-line command instead of a 1-line command to do the same thing, so it was an easy workaround. I retained the same directory structure and creation timestamp as in my bookmarks, too. I didn't bother with webpage icons, but the script could be upgraded to handle those too.
It took several more hours than I expected to get that script working, but it works well. I like my bookmark folders. I expect to do some manual work to create a better sorting nomenclature for them.
Powershell V3 includes new JSON commands, but they didn't work because my data store was too large. I had to use a 3-line command instead of a 1-line command to do the same thing, so it was an easy workaround. I retained the same directory structure and creation timestamp as in my bookmarks, too. I didn't bother with webpage icons, but the script could be upgraded to handle those too.
# Convert bookmarks from Firefox browser JSON backup to Windows 7 filesystem # This script works in PowerShell v3. # configure these variables as needed $sourcefile = 'p:\www\bookmarks-2013-02-16.json' $destfolder = 'p:\www\bookmarks\' $foldertype = 'text/x-moz-place-container' # specific to Mozilla Firefox browser # unix epoch time is milliseconds since 1970-01-01 00:00:00 GMT # http://www.epochconverter.com/ $epoch = [datetime]'1970-01-01' # i found that a delay was necessary, otherwise errors cropped up occasionally $delay = 10 # milliseconds function CheckNodeType([object]$node, [string]$parent) { if ($node.type -eq $foldertype) { ProcessDirectory $node $parent } else { ProcessBookmark $node $parent } } function ProcessDirectory([object]$node, [string]$parent) { # remove bad characters from directory names $fixname = [system.text.regularexpressions.regex]::replace($node.title,"[^1-9a-zA-Z._]","") $dir = $parent + $fixname + '\' if (-not (test-path $dir)) { new-item -name $fixname -path $parent -itemtype 'directory' $offset = $node.dateAdded / 1000000 $time = [timezone]::CurrentTimeZone.ToLocalTime($epoch.AddSeconds($offset)) sleep -Milliseconds $delay Set-ItemProperty -path $dir -name CreationTime -value $time } foreach($subnode in $node.children) { CheckNodeType $subnode $dir } } function ProcessBookmark([object]$node, [string]$parent) { # remove bad characters from filenames $fixname = [system.text.regularexpressions.regex]::replace($node.title,"[^1-9a-zA-Z. _]","") # truncate excessive filename lengths if ($fixname.Length -gt 200) { $fixname = $fixname.substring(0,200) } # process the good filename $file = $parent + $fixname + '.url' if (-not (test-path $file)) { $data = "[InternetShortcut]`nURL="+$node.uri new-item -name ($fixname + '.url') -path $parent -itemtype 'file' -value $data $offset = $node.dateAdded / 1000000 $time = [timezone]::CurrentTimeZone.ToLocalTime($epoch.AddSeconds($offset)) sleep -Milliseconds $delay Set-ItemProperty -path $file -name CreationTime -value $time Set-ItemProperty -path $file -name LastWriteTime -value $time } } # read the JSON-formatted text string from the bookmark backup file $json = get-content $sourcefile # the native ConvertFrom-Json command does not work on very large JSON stores, so use this method instead [Reflection.Assembly]::LoadWithPartialName("System.Web.Extensions") | out-null $jsser = New-Object System.Web.Script.Serialization.JavaScriptSerializer $jsser.MaxJsonLength = $json.Length $tree = $jsser.DeserializeObject($json) # process the object tree $menu = $tree.children | where { $_.title -eq 'Bookmarks Menu' } foreach($node in $menu.children) { # ignore management folders if (($node.title -ne 'Recently Bookmarked') -and ($node.title -ne 'Recent Tags') -and ($node.title -ne 'JSTOR liberator')) { CheckNodeType $node $destfolder } }
It took several more hours than I expected to get that script working, but it works well. I like my bookmark folders. I expect to do some manual work to create a better sorting nomenclature for them.