Introduction
Ecoute includes a Desktop Controller which displays an HTML + CSS webpage with the ability to communicate with Ecoute. If you are familiar with HTML, CSS, this documentation may help you communicate with Ecoute using Javascript.
This documentation includes new methods / keys which are only compatible with Ecoute 2.0 or later. If you wish to make a theme for Ecoute 1.x, check the old documentation. Please also notice that Ecoute 1.x themes are still compatible with Ecoute 2.0 or later, but Javascript methods are deprecated.
Themes bundles
An Ecoute theme is a simple folder which may contains multiple files like a CSS file, some HML and Javascript code, images, etc. The most important file to make you theme understandable for Ecoute is the Info.plist.
A PLIST is a Property List file. It's an Apple standard XML format which can support some values like Numbers, Strings, Dates, Datas, Arrays, Dictionaries. This plist can be edited with Property List Editor which is delivered with the Apple Developer Tools (/Developer/Applications/Utilities/). But some text editors may be able to read those files because it's just a standardized and simplified XML file (Coda, TextMate, Espresso etc.).
Info.plist
This file may contains several important information for your theme.
An info.plist example
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>ECMainFile</key>
<string>skin.html</string>
<key>ECWindowWidth</key>
<integer>100</integer>
<key>ECWindowHeight</key>
<integer>120</integer>
<key>ECThemeName</key>
<string>Renouveau</string>
<key>ECThemeVariantName</key>
<string>Dark</string>
<key>ECThemeIdentifier</key>
<string>com.juliensagot.Renouveau</string>
<key>ECThemeVariantIdentifier</key>
<string>com.juliensagot.RenouveauDark</string>
<key>ECThemeArtist</key>
<string>Julien Sagot</string>
<key>ECThemeHasProgressIndicator</key>
<false/>
<key>ECThemePreviewImage</key>
<string>preview.png</string>
<key>ECThemeMiniPreviewImage</key>
<string>minipreview.png</string>
<key>ECArtworkSize</key>
<string>{80, 80}/<string>
<key>ECThemeVersion</key>
<string>1.0</string>
</dict>
</plist>
Available keys, the mandatory keys are written in red:
ECMainFile
The name of your HTML file (string)
ECWindowWidth
The estimated theme width (integer)
ECWindowHeight
The estimated theme height (integer)
ECThemeName
The name you want to use for your theme. (string)
ECThemeVariantName
The name of your variant. (string)
ECThemeIdentifier
A unique identifier for your theme (e.g.: com.YourName.YourThemeName ) (string)
ECThemeVariantIdentifier
A unique identifier for your theme variant (e.g.: com.YourName.YourThemeName.YourVariantName ) (string)
ECThemeArtist
Your name! (string)
ECThemeHasProgressIndicator
A boolean value. Set to <true/> if your theme is displaying something related to the current track time (progress bar, time remaining, etc..). Else, simply do not add this key to the Info.plist file (boolean)
ECThemePreviewImage
A preview image of your theme. Must be 450 x 263 px (string). Please read our Themes Previews Guidelines
ECThemeMiniPreviewImage
A mini preview image of your theme. Must be 116 x 73 px (string)
ECArtworkSize
A string representing a size. Simply format the size like this: {myWidth, myHeight}. e.g: {145, 145}. If you do not add this key, Ecoute will use a ECArtworkSizeRegular value (Which is a 128 x 128 px artwork) (integer)
The following key is required only if your theme appears or if you plan to submit it to Ecoute Theme Center
ECThemeVersion
Your theme version. Only use numbers separated by a dot. Do no use any letters like "b" for "beta". (string)
Themes Previews Guidelines
If you're building an Ecoute Theme, please pay attention about the following rules (which only applies on PREVIEW image, not the mini-preview one):
- Do not add your theme name or variant name on the preview
- Do not add your name on the preview
- Make sure your preview is 450 pixels width and 263 pixels height
- Only PNG or JPG previews allowed (PNG would be great)
- Do not show any app running next to your theme nor any hard/external drives, folders, or files on your desktop. Be sure to ONLY display your theme running (Any wallpaper allowed as background illustration)
- No white backgrounds
Javascript functions
Your Javascript file will have the ability to communicate with Ecoute once a theme is loaded. The JS object 'Ecoute' understands the following methods:
Getters
Ecoute.volume()
Returns a float value from 0.0 to 1.0. (float)
Ecoute.shuffle()
Returns an integer value from 0 to 1. (integer)
- 0 = Shuffle disabled
- 1 = Shuffle enabled
Ecoute.repeat()
Returns an integer value from 0 to 2. (integer)
- 0 = Repeat none
- 1 = Repeat one
- 2 = Repeat all
Ecoute.playState()
Returns an integer value from 0 to 1. (integer)
- 0 = Paused
- 1 = Playing
Ecoute.frame()
Returns an array containing the theme window frame. (array)
- index 0 = Window Origin X (integer)
- index 1 = Window Origin Y (integer)
- index 2 = Window Size Width (integer)
- index 3 = Window Size Height (integer)
Ecoute.playerPosition()
Returns a float value representing the current track elapsed time in seconds (integer).
Ecoute.rating()
Returns an integer representing the current track rating value from 0 to 100. (integer).
Get a rating from 0 to 5 by dividing the returned value by 20. e.g.: var rating = Ecoute.rating() / 20; Working with a value from 0 to 100 allows you to easily display half-stars.
Ecoute.track()
Returns a wrapper of the current playing track. (id) -- See ECMedia wrapper
Ecoute.preferenceForKey('aKey')
Returns a value for the given key (id)
Ecoute allows any theme to save some preferences. For example, your theme may need to know what was the latest display mode the user used (if your theme supports different display behaviors) There's a getter 'preferenceForKey('aKey')' and a setter 'setPreferenceForKey(aValue, 'aKey')' Each preferences are stored in Ecoute preferences, and are linked to your theme identifier, or your theme variant identifier (if exists). However, you should never use the 'frame' key.
Setters
Ecoute.setVolume(aVolume)
Sets the Ecoute player volume to aVolume. Must be a float from 0.0 to 1.0.
Ecoute.setShuffle(shuffleMode)
Sets the Ecoute player shuffle mode to shuffleMode. Must be an integer from 0 to 1.
- 0 = Shuffle disabled
- 1 = Shuffle enabled
Ecoute.setRepeat(repeatMode)
Sets the Ecoute player repeat mode to repeatMode. Must be an integer from 0 to 2.
- 0 = Repeat none
- 1 = Repeat all
- 2 = Repeat one
Ecoute.setFrame(aFrame)
Sets the Desktop controller window frame to aFrame. Must be an array containing:
- index 0 = Window Origin X (integer)
- index 1 = Window Origin Y (integer)
- index 2 = Window Size Width (integer)
- index 3 = Window Size Height (integer)
Ecoute.setPlayerPosition(aTime)
Sets the Ecoute player current track time to aTime. Must be a integer from 0 to Ecoute.track().property('duration'). -- See ECMedia wrapper
Ecoute.setRating(aRating)
Sets the current playing track rating to aRating. Must be an integer from 0 to 100.
Ecoute.setPreferenceForKey(aValue, 'aKey')
Stores aValue for given key 'aKey' in Ecoute preferences.
Player actions
Ecoute.playPause()
Toggles play/pause Ecoute player.
Ecoute.nextTrack()
Goes to the next track.
Ecoute.previousTrack()
Goes to the previous track. Also goes to the beginning of the current track if its current time exceeds 3 seconds.
ECMedia Wrapper
When you ask for Ecoute.track(); it returns a wrapper of the current playing track. You can ask many properties on it:
track.property('title')
Returns the track name (string)
track.property('artist')
Returns the track artist (string)
track.property('album')
Returns the track album (string)
track.property('albumArtist')
Returns the track album artist (string)
track.property('composer')
Returns the track composer (string)
track.property('genre')
Returns the track genre (string)
track.property('lyrics')
Returns the track lyrics (string), requires Ecoute version 2.0.4 or later
track.property('length')
Returns the track length/duration in seconds (integer)
track.property('duration')
similar to track.property('length')
track.property('year')
Returns the track album release year (integer)
track.property('trackNumber')
Returns the current track number in the album (integer)
track.property('discCount')
Returns the number of discs for the current track album (integer)
track.property('discNumber')
Returns the disc number where's the current track is (integer)
Notifications
Your Javascript file will also receive up to 4 different notifications from Ecoute.
function artworkUpdate(anURL)
Sent when Ecoute has loaded the current track artwork. anURL is a string value. Use this method to update the artwork you display on your theme. Do not include this method if your theme do not display artworks. Sample implementation in your javascript:
function artworkUpdate(anURL)
{
if (! anURL)
document.getElementById('coverImg').src = "images/nocover.png"; // Use a custom "nocover"
else
document.getElementById('coverImg').src = anURL;
}
function playerUpdate()
Sent when Ecoute player when play/pause, shuffleMode, repeatMode has changed state. Use this method to update player visual states on your HTML file. Sample implementation in your javascript:
function playerUpdate()
{
var pState = Ecoute.playState();
if (pState != oldPlayState)
{
if (pState == 0) // Ecoute is currently paused. The image should then represent a "play" (or resume) button
document.getElementById('playLink').innerHTML = '<img src="images/play.png">';
else // Ecoute is currently playing. The image should then represent a "pause" button
document.getElementById('playLink').innerHTML = '<img src="images/pause.png">';
oldPlayState = pState;
}
var shuffle = Ecoute.shuffle();
var repeat = Ecoute.repeat();
if (shuffle) // Ecoute player is currently in shuffle mode. The image should then represent a "shuffle" state button
document.getElementById('shuffleLink').innerHTML = '<img src="images/shuffled.png">';
else // Ecoute player is not in shuffle mode. The image should then represent a "not in shuffle" state button"
document.getElementById('shuffleLink').innerHTML = '<img src="images/notShuffled.png">';
// ……… tutti quanti
}
function trackUpdate(aTrack)
Sent when Ecoute current playing track has changed. Use this method to update track properties on your HTML file. See ECMedia wrapper properties. Sample implementation in your javascript:
function trackUpdate(track)
{
var name = track.property('title');
var artist = track.property('artist');
var album = track.property('album');
document.getElementById('songname').innerHTML = name;
document.getElementById('artist').innerHTML = artist;
document.getElementById('album').innerHTML = album;
// ……… tutti quanti
}
function timeUpdate(aTime)
Sent when he current track time has changed. \!Warning!/ -> Will be only called if your Info.plist has ECThemeHasProgressIndicator sets to <true/>. Sample implementation in your javascript:
function timeUpdate(aTime)
{
var length = Ecoute.track().property('length'); // It may be better to previously save 'length' when your javascript receives a trackUpdate(aTrack);
// Our progressbar is 100 px width.
var progressIn = 100/length*aTime; // We now have the "done" progress width for our progressbar.
document.('progression').width = progressIn;
}
Handling Theme's window movements
You Javascript must also implement the mouseMoved events to change the Desktop Controller frame using the Ecoute object
mouseDown = false;
mouseX = 0;
mouseY = 0;
mouseStartX = 0;
mouseStartY = 0;
startFrame = [];
document.onmousedown = function(e)
{
mouseDown = true;
mouseStartX = e.screenX;
mouseStartY = e.screenY;
startFrame = Ecoute.frame();
}
document.onmouseup = function()
{
mouseDown = false;
}
document.onmousemove = function(e)
{
mouseX = e.screenX;
mouseY = e.screenY;
if (mouseDown)
{
deltaX = mouseX - mouseStartX;
deltaY = mouseStartY - mouseY; // flipped coordinate system
Ecoute.setFrame(startFrame[0]+deltaX, startFrame[1]+deltaY, startFrame[2], startFrame[3]);
}
}
Packaging
-
Create a folder named "You Theme Name" and put all the needed files in it.
-
Simply rename "My Awesome Theme" with "My Awesome Theme.ecoute". It will prompt a Finder window asking if you really want to add the ecoute extension. Accept!
-
Take a nap, you're done !
Submit your theme
You can submit your theme on the Theme Center (not ready yet). Once approved, your theme will appear on the Ecoute themes feed and users will be able to download and install it from the Ecoute themes preferences panel.