Skip to content

Instantly share code, notes, and snippets.

@pudquick
Created February 14, 2016 02:16
Show Gist options
  • Save pudquick/b85fcfd4a0479810e6aa to your computer and use it in GitHub Desktop.
Save pudquick/b85fcfd4a0479810e6aa to your computer and use it in GitHub Desktop.
Modifying the Favorite Servers list (in Finder's "Connect to Server" dialog) on OS X 10.11, a revisit of my blog post at: http://michaellynn.github.io/2015/10/24/apples-bookmarkdata-exposed/
import os.path
from Foundation import NSData, NSKeyedUnarchiver, SFLListItem, NSURL, NSMutableDictionary, NSKeyedArchiver, NSString, NSDictionary, NSArray
def load_favservers(sfl_path):
if os.path.isfile(sfl_path):
# File exists, use it
sfl_decoded = NSKeyedUnarchiver.unarchiveObjectWithData_(NSData.dataWithContentsOfFile_(sfl_path))
else:
# File doesn't exist, make a blank template
sfl_decoded = {u'items': [],
u'version': 1L,
u'properties': {"com.apple.LSSharedFileList.ForceTemplateIcons": False,},
}
mutable_favs = dict(sfl_decoded)
mutable_favs['items'] = list(mutable_favs['items'])
return mutable_favs
def create_favitem(url=None, name=None):
if name is None:
# Make the display name the same as the URL by default
name = url
props = {NSString.stringWithString_('com.apple.LSSharedFileList.OverrideIcon.OSType'): NSString.stringWithString_(u'srvr')}
props = NSDictionary.alloc().initWithDictionary_(props)
return SFLListItem.alloc().initWithName_URL_properties_(name, NSURL.alloc().initWithString_(url), props)
def purify(obj):
# This code ensures that certain data types are very definitely the ObjC versions
d = dir(obj)
if '__reversed__' in d:
# list / NSArray
return NSArray.alloc().initWithArray_(obj)
elif 'items' in d:
# dictionary / NSDictionary
return NSDictionary.alloc().initWithDictionary_(obj)
elif 'strip' in d:
# string / NSString
return NSString.alloc().initWithString_(obj)
# Unhandled
return obj
def save_favservers(favs, path):
# Prior to running code through NSKeyedArchiver, we want to strip out custom pyObjC subclass types
temp_keys = favs.keys()
fixed_values = [purify(favs[x]) for x in temp_keys]
fixed_keys = [purify(x) for x in temp_keys]
# Once everything is cleaned up, put it into a new NSDictionary
formatted_favs = NSDictionary.alloc().initWithObjects_forKeys_(fixed_values, fixed_keys)
return NSKeyedArchiver.archiveRootObject_toFile_(formatted_favs, path)
# How to use it
# -------------
# Pick the path:
sfl_path = os.path.expanduser('~/Library/Application Support/com.apple.sharedfilelist/com.apple.LSSharedFileList.FavoriteServers.sfl')
# Load it:
my_favs = load_favservers(sfl_path)
# Make a new favorite:
new_fav = create_favitem(url='smb://username@servername', name='A Cool Custom Name')
# Append it to the end:
my_favs['items'].append(new_fav)
# Saving back like this probably won't work if the user has the dialog open, so you'll want to
# do it at login with a tool like outset: https://github.com/chilcote/outset
# (The best time to do it would be when they're not logged in at all ...)
result = save_favservers(my_favs, sfl_path)
@sonic84
Copy link

sonic84 commented Apr 7, 2016

Many thanks! this script is great! I've found Finder will sometimes overwrite the modified com.apple.LSSharedFileList.FavoriteServers.sfl with the copy it seems to have in memory. Do you know of any way around this?

@masyanru
Copy link

@sonic84 just run "killall Finder" after script

@kernsb
Copy link

kernsb commented Jan 8, 2018

Any possibility of an update for High Sierra on this? Loading the list seems to work fine, but create_favitem seems to error out on line 22 for me.

@prashantvidja
Copy link

Hello,
Is there any way to remove item from fav server using that type of script?
I have tried many times but not able to remove item from "myfavs" dict
getting below error:
argument of type 'SFLListItem' is not iterable
Thanks

@prashantvidja
Copy link

Any possibility of an update for High Sierra on this? Loading the list seems to work fine, but create_favitem seems to error out on line 22 for me.

@kernsb Have you find anything for MacOS High Sierra?

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