Skip to content
Charles G. edited this page Jun 8, 2015 · 19 revisions

All plugins are stored in the src/js/plugins directory and are referenced in src/js/plugins/index.js. Plugins are used by the scroblr content-script in order to answer a few simple questions:

  1. Should this plugin be active in the current browser window?
  2. Is a song being played in the current browser window?
  3. If so, retrieve as many details about the track as possible (title, artist, duration, etc).

The Big Picture

Whenever the user opens a new browser window, the extension will look at the URL and decide whether to inject the bundle-content-script.js file into the document or not. To determine this, the URL for the page must match one of the URL globs defined in the manifest.json file (i.e. "*://*.beatsmusic.com/*").

Once the content script is loaded, it will cycle through all of the plugins defined in src/plugins/index.js and run their Plugin.test() method. If the test method returns true, the plugin will be activated. During activation, if the plugin has a Plugin.initialize() method, it will be called, and then an interval will be created that will call the Plugin.scrape() method every 5 seconds for as long as that page is open.

In Practice

Plugins inherit from the Plugin object which is defined in src/js/modules/Plugin.js, and have the following methods and parameters:

  • {String} name - The name of the plugin, preferably lowercase letters only (i.e. 'google')
  • {String} displayName - The full name of the plugin that will be displayed to the user (i.e. 'Google Play')
  • {Function} init - Init method, used when creating an instance of the Plugin object
  • {Function} initialize - A method that will be called once when the plugin is activated (optional)
  • {Function} scrape - When the plugin is activated, this method is called every 5 seconds, it's purpose is to scrape the page for track information
  • {Function} test - This should return true or false whether the plugin should be activated or not, typically by testing the document location

Below is an example of a simple plugin.

"use strict";

var $      = require("jquery");
var Plugin = require("../modules/Plugin");
var songza = Object.create(Plugin);

songza.init("songza", "Songza"); // name, displayName

songza.test = function () {
    var domainTest = /songza\.com/i.test(document.location.hostname);
    var playerTest = $("#player").length > 0;

    return domainTest && playerTest;
};

songza.scrape = function () {
    var info = {
        artist:  $("#player .szi-artist").text(),
        stopped: $("#player .player-play").css("display") === "none" ? false : true,
        title:   $("#player .szi-title").text()
    };

    return info;
};

module.exports = songza;

The scrape method is expected to return an object with certain parameters. For a track to be recognized it MUST include an artist and a title. All other parameters are optional, but the more information the better. Below is a list of parameters that scroblr expects to receive from the Plugin.scrape() method.

  • {String} artist - The name of the artist
  • {String} title - The title of the track
  • {String} album - The name of the album that the track belongs to
  • {Boolean} stopped - Is the song currently stopped/paused? true or false
  • {Integer} duration - The duration of the song in milliseconds
  • {Integer} elapsed - How much of the song has played in milliseconds
  • {Float} percent - A number between 0 and 1, representing how much of the song has elapsed in percentage (i.e. 0.40)

Most sites display duration and elapsed time in a format like "3:27", in order to convert that to milliseconds, you can use a utility function called calculateDuration() by requiring the utilities module that is defined in src/js/modules/Utilities.js.

var Utils = require("./modules/Utilities");
Utils.calculateDuration("1:23"); // 83000

Example

To see an example of a single commit that encompasses all the changes necessary to add support for a new site, see commit 6b57c90fbd7e3d37c3ee3bb59117d64c967636f3

Clone this wiki locally