A Sample Application: Personalized Radio



OpenStrands is a unique platform for application development, below please find a sample of our Personalized Radio (a la Pandora):

Develop your own algorithms to maximize the impact of your own radio application tailored to your specific needs!

The OpenStrands platform enables you develop and launch a personalized radio like Pandora or last.fm with just two pages of source code! Of course, you need the content and the right licenses. You can easily compete with them by just using OpenStrands!

How the application works:

  1. Login into the system through your MyStrands account. Based on your most recently played tracks, it begins generating a playstream.
  2. You can rate any of the suggested tracks with three options:
    • Thumbs up: drives the stream towards similar songs.
    • Neutral: indicates the user does not have enough information to rate the song up or down.
    • Thumbs down: drives the stream towards different songs.
  3. You can also skip a song, indicating you do not want to listen to this song at that moment.

  4. In the Preferences tab, you can adjust:


    • Popularity to specify how popular the streamed music should be.
    • Diveristy to indicate a broader selection of streamed music.
    • Filters to filter out songs according to your MyStrands profile.
Take a look at Personalized Radio Example!

Personalized Radio

All materials to launch, modify and enjoy the app can be found at:

CC-GNU GPL
This software is licensed under CC-GNU GPL.

Learn more about the source code of this sample application:

The source code that calls OpenStrands can be found in the file PlayerFoundations.as.
Below please find an outline of the types of calls made to the OpenStrands platform/client:

Initialization

Initialitzation of some key variables.
IMPORTANT NOTE: The developer has to put his own OpenStrands subscriber Id in the variable SUBSCRIBER_ID.

var SUBSCRIBER_ID:String = "EnterYourSubscriberID";
...
var RECOMMENDATIONS_URL:String =
"https://www.MyStrands.com/services/recommend/tracks";
...


function startStream

Call OpenStrands validate user, passing the given username and password.

parameters.username = userName;
parameters.password = passw;
parameters.subscriberId = SUBSCRIBER_ID;
parameters.sendAndLoad(VALIDATE_USER_URL, xmlResponse, "POST");

Check if user was valid, if firstChild is null username/password was not recognized

if (this.firstChild != null) {

Call OpenStrands to retrieve a listening history for the user that was validated

parameters2.alias = userAlias;
parameters2.num = SHORT_ARRAY_SIZE;
parameters2.subscriberId = SUBSCRIBER_ID;
parameters2.showOrphans = false;
parameters2.sendAndLoad(LISTENING_HISTORY_URL, xmlResponse2, "POST");


function rateDown

Add to the Hard negative filter the track, album and artist.

addToArray(id, filterTracks, MEDIUM_ARRAY_SIZE);
addToArray(albumId, filterAlbums, MEDIUM_ARRAY_SIZE);
addToArray(artistId, negativeArtists, ARRAY_SIZES);

Ask for artist recommendations to be added as soft filter.

parameters.id = artistId;
parameters.max = RECOMMENDATION_SIZE;
parameters.serendipty = popularityValue;
parameters.subscriberId = SUBSCRIBER_ID;
parameters.sendAndLoad(ARTIST_RECOMMENDATIONS_URL, xmlResponse, "POST");

Call OpenStrands artist recommendation passing the users specified popularity, and the artistId that was rated down.

parameters.id = artistId;
parameters.max = RECOMMENDATION_SIZE;
parameters.serendipty = popularityValue;
parameters.subscriberId = SUBSCRIBER_ID;
parameters.sendAndLoad(ARTIST_RECOMMENDATIONS_URL, xmlResponse, "POST");

Use the returned recommendations in our negativeArtists filter

var artistId = xRows[i].attributes.ArtistId;
addToArray(artistId, negativeArtists, ARRAY_SIZES);

Once all the filterings have been done, the function just calls getNextSongData. If the rating comes from the current playing track, we have to skip it. Otherwise, if the rating was in the upcoming track, we have to replace it. If the rating was in a past track, we will use the rating to compute the next songs.

if (recompute) {
	// We will recompute if we rate down the central or right track
	if (doSkip) {
		// We will generate a new track if the user has rate down the central track
		getNextSongData(true);
	} else {
		// We will just modify the last track if the user rates down the right track
		getNextSongData(false);
	}
} else {
	// We don't recompute if the user has rated down the left track
	mustWait = false;
}


function rateUp

Call OpenStrands artist recommendation service passing the user specified popularity value, the artistId which was rated up, and the existing positive Artists array if any

parameters.serendipty = popularityValue;
    parameters.subscriberId = SUBSCRIBER_ID;
    var plainRequest:String = "";
    if (positiveArtists.length > 0) {
        plainRequest = "?filter=artist,false,0|";
        for (var i = 0; i < positiveArtists.length; i++) {
            plainRequest += positiveArtists[i];
            if (i != positiveArtists.length - 1) {
                plainRequest += ",";
            }
        }
    }
parameters.sendAndLoad(ARTIST_RECOMMENDATIONS_URL + plainRequest, xmlResponse, "POST");

Add the returned recommendations to the positiveArtists array

var artistId = xRows[i].attributes.ArtistId;
addToArray(artistId, positiveArtists, ARRAY_SIZES);


function completeArrayWithCoverArt

Call the OpenStrands get album information service, passing the albumId.

parameters.subscriberId = SUBSCRIBER_ID;
parameters.id = albumId;
// set an interval to try again if the server is too busy
iId = setInterval(tryCoverAgain, SERVER_BUSY_WAITING_TIME, xmlResponse, albumId, array, generate);
parameters.sendAndLoad(GET_ALBUM_INFO_URL, xmlResponse, "POST");

If we are generating a new song use the returned album info in the new song

if (generate) {
    // create a new song (and move the others)
    var positionTo = ((_root["t"+nrTracksShown]._width) * 3 + BOUNDARY * 4);
    insertSong(array, positionTo);

If we are not generating a new song, just modify the last visible song with the returned information.

} else {
    modifyLastSong(array);
    mustWait = false;
powered by OpenStrands