Download the latest release, or find all released binaries here.
Mac OS X 10.7 or greater required.
BeardedSpice is a menubar application for Mac OSX that allows you to control web based media players with the media keys found on Mac keyboards. It is an extensible application that works with Chrome and Safari, and can control any tab with an applicable media player. BeardedSpice currently supports:
- 8Tracks
- Amazon Music
- BandCamp
- BeatsMusic
- Bop.fm
- Google Music
- GrooveShark
- HypeMachine
- Last.fm
- Mixcloud
- Music Unlimited
- Pandora
- Rdio
- Shuffler.fm
- Slacker
- Songza
- SoundCloud
- Spotify (Web)
- Synology
- XboxMusic
- YouTube
- VK ("My Music" from vk.com)
- Vimeo
If you want another supported app supported, simply open an issue with the tag 'app support'. Or, if you are feeling extra feisty, implement the handler yourself!
BeardedSpice is built with SPMediaKeyTap and works well with other applications listening to media key events.
We use CocoaPods to manage all obj-c/cocoa dependences. Install them locally using:
sudo gem install cocoapods
pod install
Always use BeardedSpice.xcworkspace for development, not BeardedSpice.xcodeproject
Tell BeardedSpice to control a tab by either clicking the menubar icon and selecting a tab from the dropdown, or by pressing the 'Set Active Tab' shortcut when a browser window is active. The shortcut defaults to โ+F8, and is configurable in the preferences panel. Switching active tabs will pause the currently active tab (if there is one).
In Chrome you must reset your active tab if you move your tab to a new window. With Safari, reset your active tab when changing the order of your active tab or moving it to a new window.
From the preferences menu, uncheck any types of webpages that you don't want BeardedSpice to have control over. By default, all implemented handlers are enabled.
Media controllers are written as strategies. Each strategy defines a collection of Javascript functions to be excecuted on particular webpages.
@interface MediaStrategy : NSObject
-(BOOL) accepts:(id <Tab>) tab;
-(NSString *) displayName;
-(NSString *) toggle;
-(NSString *) previous;
-(NSString *) next;
-(NSString *) pause;
@end
The accepts
method takes a Tab
object and returns YES
if the strategy can control the given tab. displayName
must return a unique string describing the controller and will be used as the name shown in the Preferences panel. All other functions return a Javascript function for the particular action. pause
is a special case and is used when changing the active tab.
A sample strategy for GrooveShark:
@implementation GrooveSharkStrategy
-(id) init
{
self = [super init];
if (self) {
predicate = [NSPredicate predicateWithFormat:@"SELF LIKE[c] '*grooveshark.com*'"];
}
return self;
}
-(BOOL) accepts:(id <Tab>)tab
{
return [predicate evaluateWithObject:[tab URL]];
}
-(NSString *) toggle
{
return @"(function(){return window.Grooveshark.togglePlayPause()})()";
}
-(NSString *) previous
{
return @"(function(){return window.Grooveshark.previous()})()";
}
-(NSString *) next
{
return @"(function(){return window.Grooveshark.next()})()";
}
-(NSString *) pause
{
return @"(function(){return window.Grooveshark.pause()})()";
}
-(NSString *) displayName
{
return @"Grooveshark";
}
@end
Update the MediaStrategyRegistry
to include an instance of your new strategy:
+(NSArray *) getDefaultMediaStrategies
{
DefaultMediaStrategies = [NSArray arrayWithObjects:
// ...
[[GoogleMusicStrategy alloc] init],
[[RdioStrategy alloc] init],
// add your new strategy!
[[GrooveSharkStrategy alloc] init],
nil];
}
Finally, update the default preferences plist to include your strategy.