Skip to content

Commit

Permalink
Merge branch 'release/3.9'
Browse files Browse the repository at this point in the history
  • Loading branch information
svenackermann committed Feb 22, 2016
2 parents bc3c03f + ddf2ee9 commit cba43d8
Show file tree
Hide file tree
Showing 13 changed files with 224 additions and 657 deletions.
43 changes: 43 additions & 0 deletions CONTRIBUTING.md
Original file line number Diff line number Diff line change
Expand Up @@ -32,3 +32,46 @@ I do not use any automated tests. That would just be too hard to implement, beca
So please take care that you tested your changes manually. Don't forget that users can have many different setups because of the large number of extension options and the different kinds of Google Music accounts (with or without "All Access" or with some labs enabled).

Your changes should work in the currently stable Chrome release. If you implement sth. that needs Chrome features which are only available for the Canary/Dev/Beta build at the moment, I might accept it but will not release it yet. Instead it will be moved to some branch and maybe merged in later. In such case please also take care of the `minimum_chrome_version` property in the `manifest.json`.

### Adding a setting to the options page
These are the steps if you add sth. that should be configurable with an option:

1. In ```bp.js``` add a property with its default value (e.g. ```myNewSetting: false```) to ```settings``` (or ```localSettings``` if it's not intended to be synchronized with Chrome sync). Take care that you add it at the position corresponding to the position where you'd like it on the options page. Because of the large number of options I need some order here.
2. In ```options.html``` add a ```div``` at the desired position (e.g. ```<div class="i-c" id="myNewSetting"></div>``` for a checkbox). Its ```id``` must be the name of the setting. The version and mode filter classes (e.g. ```v-3.8 adv```) will be added by me later. For local settings (see above) the class ```local``` must be added. The type (checkbox, select, ...) is required in the class attribute:
* ```i-c``` is for boolean properties (checkbox).
* ```i-n``` is for number properties (number input), minimum/maximum allowed values can be provided with ```data-min```/```data-max``` attributes.
* ```i-s``` is for enum properties (i.e. type string/number with predefined values, results in select input), possible values can be defined with attribute ```data-options``` (comma-separated). If an option needs a special CSS class added, you can add a colon and the class after the value (e.g. ```data-options="option1,option2:myCssClass,option3"```). If the type is number, ```data-type="n"``` must be added. You can also provide a custom function to determine the labels for the options with ```data-getoptionstext="myCustomFunction"``` if you need more control than described below.
* Other rare cases are color inputs (```i-co```) and select inputs that have their values copied from another select (```i-sf```). See ```options.html``` and code in ```options.js``` for examples.
* If the setting needs detailed explanation with a hint (green question mark icon), class ```i-h``` must be added and additional texts provided (see below).
3. Add texts to the resource bundles (```_locales/*/messages.json```) (at least English is required):
* The label for the option has key "setting_" followed by the name of the setting (e.g. "setting_myNewSetting").
* If the setting has a hint, the same key with suffix "Hint" is used for that (e.g. "setting_myNewSettingHint").
* For enum properties, the options labels have the same key with suffix "_(option)" (e.g. "setting_myNewSetting_option1"; if you provided a custom function with ```data-getoptionstext```, you don't need that).
4. Use the new setting (```bp.settings.myNewSetting```) wherever you need it and register listeners as described below.

### Using settings for control
You can use the ```settings```, ```localSettings```, ```song``` and ```player``` objects from the background page to react on current state of user settings, the current song and the Google player.

You can access the current value like with a normal object (e.g. ```if (settings.myNewSetting) ...```). Note that this value is actually hidden behind a Javascript get property. If you set the value, all registered listeners will be notified if and only if it really changed (so setting the same value multiple times will only trigger one notification).

To register or remove a listener you have the following functions:
* ```al```: add a listener function
* ```rl```: remove a listener function
* ```arl```: add or remove a listener function (depending on value of the ```add``` attribute)
* ```ral```: remove all listeners for a given source (e.g. the miniplayer)
* ```w```: add a watcher function, that is the same as ```al```, except that the listener will be called immediately with the current value for old and new value, this is useful for initialisation
* ```wrl```: same as ```arl```, except that the listener will be called immediately if the ```add``` attribute is ```true```

You e.g. call ```settings.al("myNewSetting", myListener)```. The listener function will be called with 3 arguments: The new value, the old value and the name of the property that changed. Just look at the existing examples in the code.

If you add a listener to the miniplayer (in ```player.js```) or options page (in ```options.js```), be sure to provide the ```src``` attribute (either ```typeClass``` or ```CONTEXT```). This is needed for the listener to be removed when the miniplayer/popup/toast/page closes (```ral``` is called on unload for that).

For more details see ```beans.js```.

### Adding a lyrics provider
If you want to add a new provider, you basically need the following steps. For details see the existing implementations.

1. In ```manifest.json``` add an optional permission for the providers URL.
2. In ```lyrics.js``` implement a new ```LyricsProvider``` object to search/load/parse the lyrics from the page via AJAX.
3. Add a file ```cs-myProvider.js``` to be used as content script on the provider page if the user decides to open the lyrics on the page directly.
4. Add a new ```div``` below the other providers in ```options.html``` to make it available to the user.
18 changes: 9 additions & 9 deletions package.json
Original file line number Diff line number Diff line change
@@ -1,31 +1,31 @@
{
"name": "primeplayer",
"version": "3.8.0",
"version": "3.9.0",
"dependencies": {
"jquery": "2.1.4"
"jquery": "2.2.0"
},
"devDependencies": {
"del": "^2.2.0",
"gulp": "^3.9.0",
"gulp": "^3.9.1",
"gulp-changed": "^1.3.0",
"gulp-concat": "^2.6.0",
"gulp-htmlmin": "^1.3.0",
"gulp-if": "^2.0.0",
"gulp-jscs": "^3.0.2",
"gulp-jscs-stylish": "^1.3.0",
"gulp-jshint": "^2.0.0",
"gulp-json-transform": "^0.3.0",
"gulp-htmlmin": "^1.3.0",
"gulp-native2ascii": "^0.0.3",
"gulp-replace": "^0.5.4",
"gulp-sass": "^2.1.1",
"gulp-sass": "^2.2.0",
"gulp-sourcemaps": "^1.6.0",
"gulp-uglify": "^1.5.1",
"gulp-zip": "^3.0.2",
"jshint": "^2.8.0",
"gulp-uglify": "^1.5.2",
"gulp-zip": "^3.2.0",
"jshint": "^2.9.1",
"jshint-stylish": "^2.1.0",
"merge-stream": "^1.0.0",
"run-sequence": "^1.1.5",
"yargs": "^3.31.0"
"yargs": "^4.1.0"
},
"scripts": {
"preinstall": "npm i -g gulp"
Expand Down
9 changes: 6 additions & 3 deletions src/_locales/de/messages.json
Original file line number Diff line number Diff line change
Expand Up @@ -14,9 +14,6 @@
"gotoGmusic": {
"message": "Öffne Google Play Music"
},
"myPlaylists": {
"message": "Meine Playlists"
},
"setting_scrobble": {
"message": "Scrobbeln aktivieren"
},
Expand Down Expand Up @@ -563,6 +560,9 @@
"quicklink_wms": {
"message": "Sender"
},
"quicklink_wmp": {
"message": "Meine Playlists"
},
"quicklink_ap_queue": {
"message": "Wiedergabeliste"
},
Expand Down Expand Up @@ -674,6 +674,9 @@
"command_ff": {
"message": "15 Sekunden vorspulen"
},
"command_rew": {
"message": "15 Sekunden zurückspulen"
},
"command_rate1": {
"message": "Bewerte 1 Stern/Daumen runter"
},
Expand Down
12 changes: 8 additions & 4 deletions src/_locales/en/messages.json
Original file line number Diff line number Diff line change
Expand Up @@ -19,10 +19,6 @@
"message": "Open Google Play Music",
"description": "link text in miniplayer when not connected to Google music"
},
"myPlaylists": {
"message": "My Playlists",
"description": "text for quicklink 'my playlists'"
},
"setting_scrobble": {
"message": "Enable scrobbling",
"description": "label for option to enable scrobbling"
Expand Down Expand Up @@ -750,6 +746,10 @@
"message": "Stations",
"description": "text for click action option 'instant mixes/radio' (will be replaced with text from Google Music if connected)"
},
"quicklink_wmp": {
"message": "My Playlists",
"description": "text for quicklink 'my playlists'"
},
"quicklink_ap_queue": {
"message": "Queue",
"description": "text for click action option 'queue' (will be replaced with text from Google Music if connected)"
Expand Down Expand Up @@ -897,6 +897,10 @@
"message": "Fast forward 15 seconds",
"description": "text for fast forward in toast action and keyboard shortcut"
},
"command_rew": {
"message": "Rewind 15 seconds",
"description": "text for rewind in toast action and keyboard shortcut"
},
"command_rate1": {
"message": "Rate 1 star/thumbs down",
"description": "text for rate 1 in toast action (if not connected to Google Music) and keyboard shortcut"
Expand Down
6 changes: 3 additions & 3 deletions src/_locales/ru/messages.json
Original file line number Diff line number Diff line change
Expand Up @@ -11,9 +11,6 @@
"gotoGmusic": {
"message": "Открыть Google Play Music"
},
"myPlaylists": {
"message": "Мои плейлисты"
},
"setting_scrobble": {
"message": "Включить скробблинг"
},
Expand Down Expand Up @@ -533,6 +530,9 @@
"quicklink_wms": {
"message": "Радиостанции"
},
"quicklink_wmp": {
"message": "Мои плейлисты"
},
"quicklink_ap_queue": {
"message": "Очередь"
},
Expand Down
18 changes: 16 additions & 2 deletions src/css/options.scss
Original file line number Diff line number Diff line change
Expand Up @@ -164,6 +164,7 @@ img.hint {

#changelog {
clear: both;
display: none;
h2 {
display: inline-block;
margin-right: 1ex;
Expand All @@ -180,6 +181,7 @@ img.hint {
height: 12px;
}
li {
font-size: 11px;
&.B:before {
content: "B: ";
}
Expand All @@ -202,8 +204,20 @@ img.hint {
&.F .F, &.I .I, &.B .B {
display: list-item;
}
&.V h3 {
display: block;
> div {
font-size: 0;
}
&.V {
h3 {
display: block;
margin-bottom: 1ex;
}
> div {
font-size: 11px;
}
}
h3 > a {
text-decoration: none;
}
}

Expand Down
Binary file added src/img/cmd/rew.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
60 changes: 38 additions & 22 deletions src/js/bp.js
Original file line number Diff line number Diff line change
Expand Up @@ -281,18 +281,23 @@ function fixForUri(string) {
//do not notify listeners, if not a real change (the content script might send the same song info multiple times)
song.setEqualsFn("info", songsEqual);

/** @return a value > 0 if v1 is newer, < 0 if v2 is newer, 0 if equal */
function compareVersions(v1, v2) {
v1 = v1.split(".");
v2 = v2.split(".");
for (var i = 0; i < v1.length; i++) {
if (v2.length <= i) return 1;//v2 is shorter (e.g. 1.0.1 > 1.0)
var v1i = parseInt(v1[i]);
var v2i = parseInt(v2[i]);
if (v1i != v2i) return v1i - v2i;//maybe same length, but different number (e.g. 1.1.x < 1.2)
}
return v1.length - v2.length;//v2 is longer (e.g. 1.0 < 1.0.1), else same version
}

/** @return true, if the given version is newer than the saved previous version (used by options page and update listener) */
function isNewerVersion(version) {
if (previousVersion == null) return false;//jshint ignore:line
var prev = previousVersion.split(".");
version = version.split(".");
for (var i = 0; i < prev.length; i++) {
if (version.length <= i) return false;//version is shorter (e.g. 1.0 < 1.0.1)
var p = parseInt(prev[i]);
var v = parseInt(version[i]);
if (p != v) return v > p;
}
return version.length > prev.length;//version is longer (e.g. 1.0.1 > 1.0), else same version
return compareVersions(previousVersion, version) < 0;
}

function getQuicklinks() {
Expand All @@ -302,7 +307,7 @@ function fixForUri(string) {
"albums",
"genres",
"wms",
"myPlaylists",
"wmp",
"ap/queue",
"ap/auto-playlist-thumbs-up",
"ap/auto-playlist-recent",
Expand Down Expand Up @@ -339,7 +344,6 @@ function fixForUri(string) {

/** @return the label for a quick link, if connected to Google Music, the labels from the site are used. */
function getTextForQuicklink(link) {
if (link == "myPlaylists") return i18n("myPlaylists");
var text;
if (link) text = localSettings.quicklinks[link];//try to get text from Google site
//use default
Expand Down Expand Up @@ -1616,18 +1620,24 @@ function fixForUri(string) {
}

//--- 3.4 ---
function migrateQuicklink(name) {
if (settings[name] == "rd") settings[name] = "wms";
else if (settings[name] == "expnew") settings[name] = "wnr";
else if (settings[name] == "exptop") settings[name] = "wtc";
else if (settings[name] == "exprec" || settings[name] == "ap/google-play-recommends") settings[name] = "";
function migrateQuicklink(oldLink, newLink) {
if (settings.coverClickLink == oldLink) settings.coverClickLink = newLink;
if (settings.titleClickLink == oldLink) settings.titleClickLink = newLink;
}
if (previousVersion < 3.4) {
migrateQuicklink("rd", "wms");
migrateQuicklink("expnew", "wnr");
migrateQuicklink("exptop", "wtc");
migrateQuicklink("exprec", "");
migrateQuicklink("ap/google-play-recommends", "");
if (localSettings.quicklinks && localSettings.quicklinks.exptop) localSettings.quicklinks.wtc = i18n("quicklink_wtc");
}
migrateQuicklink("coverClickLink");
migrateQuicklink("titleClickLink");
if (localSettings.quicklinks && localSettings.quicklinks.exptop) localSettings.quicklinks.wtc = i18n("quicklink_wtc");

//--- Chrome 47 ---
if (settings.toastPriority < 2) settings.toastPriority = 2;

//--- 3.9 ---
if (previousVersion <= 3.8) migrateQuicklink("myPlaylists", "wmp");
}

/** handler for onInstalled event (show the orange icon on update / notification on install) */
Expand Down Expand Up @@ -1857,7 +1867,7 @@ function fixForUri(string) {
if (player.connected) {
var menuConnectedId = "menuConnected";
createContextMenuEntry(menuConnectedId, i18n("action"), function() {
var commands = ["playPause", "prevSong", "nextSong", "ff", "openMiniplayer", "volumeUp", "volumeDown", "volumeMute", "toggleRepeat", "toggleShuffle"];
var commands = ["playPause", "prevSong", "nextSong", "ff", "rew", "openMiniplayer", "volumeUp", "volumeDown", "volumeMute", "toggleRepeat", "toggleShuffle"];
if (localSettings.lastfmSessionKey) commands.push("loveUnloveSong");
commands.push("rate-1");
if (isStarRatingMode()) commands.push("rate-2", "rate-3", "rate-4");
Expand Down Expand Up @@ -1890,7 +1900,7 @@ function fixForUri(string) {
var menuQuicklinksId = "menuQuicklinks";
createContextMenuEntry(menuQuicklinksId, i18n("quicklinks"), function() {
getQuicklinks().forEach(function(ql) {
if (ql != "myPlaylists") createContextMenuEntry("ql_" + ql, getTextForQuicklink(ql).replace(/&/g, "&&"), null, menuQuicklinksId);
createContextMenuEntry("ql_" + ql, getTextForQuicklink(ql).replace(/&/g, "&&"), null, menuQuicklinksId);
});
});
}
Expand Down Expand Up @@ -2220,7 +2230,7 @@ function fixForUri(string) {
calcScrobbleTime();
if (!old != !info) {//jshint ignore:line
// (only update if exactly one of them is null)
var commands = ["prevSong", "nextSong", "ff", "openLyrics", "rate-1", "rate-5"];
var commands = ["prevSong", "nextSong", "ff", "rew", "openLyrics", "rate-1", "rate-5"];
if (isStarRatingMode()) commands.push("rate-2", "rate-3", "rate-4");
updateContextMenuConnectedItem(commands);
}
Expand Down Expand Up @@ -2352,6 +2362,8 @@ function fixForUri(string) {
return player.forward;
case "ff":
return !!song.info;
case "rew":
return !!song.info;
case "volumeUp":
return !!player.volume && player.volume != "100";
case "volumeDown":
Expand Down Expand Up @@ -2452,6 +2464,9 @@ function fixForUri(string) {
case "ff":
if (song.info && song.info.durationSec > 0) setSongPosition(Math.min(1, (song.positionSec + 15) / song.info.durationSec));
break;
case "rew":
if (song.info && song.info.durationSec > 0) setSongPosition(Math.max(0, (song.positionSec - 15) / song.info.durationSec));
break;
case "openLyrics":
if (localSettings.lyrics) openLyrics();
break;
Expand Down Expand Up @@ -2605,6 +2620,7 @@ function fixForUri(string) {
exports.parseSeconds = parseSeconds;
exports.songsEqual = songsEqual;
exports.isNewerVersion = isNewerVersion;
exports.compareVersions = compareVersions;
exports.getQuicklinks = getQuicklinks;
exports.isRatingReset = isRatingReset;
exports.getLastSong = getLastSong;
Expand Down
5 changes: 3 additions & 2 deletions src/js/cs.js
Original file line number Diff line number Diff line change
Expand Up @@ -535,6 +535,7 @@ $(function() {
ql[getLink($(this))] = $.trim($(this).find(".tooltip").text());
});
ql.searchPlaceholder = $.trim($("#material-one-middle input.material-search").attr("placeholder"));
ql.wmp = $.trim($("#playlists").prev(".nav-section-header").text());
post("connected", {
ratingMode: "thumbs",
quicklinks: ql
Expand Down Expand Up @@ -826,7 +827,7 @@ $(function() {
$("#playlists").children("a").each(function() {
playlists.push({ title: $.trim($(this).find(".tooltip").text()), titleLink: getLink($(this)) });
});
post("player-navigationList", { type: "playlistsList", link: "myPlaylists", list: playlists, empty: !playlists.length });
post("player-navigationList", { type: "playlistsList", link: "wmp", list: playlists, empty: !playlists.length });
}

/** @return the type of list for a hash value ("playlistsList" [e.g. artist page showing albums], "playlist" [e.g. album page] or "albumContainers" [e.g. genre page showing artists]) */
Expand Down Expand Up @@ -979,7 +980,7 @@ $(function() {
case "getNavigationList":
clearTimeout(asyncListTimer);
listRatings = null;
if (msg.link == "myPlaylists") sendMyPlaylists();
if (msg.link == "wmp") sendMyPlaylists();
else sendNavigationList(msg.link, msg.omitUnknownAlbums);
break;
case "selectLink":
Expand Down
2 changes: 1 addition & 1 deletion src/js/injected.js
Original file line number Diff line number Diff line change
Expand Up @@ -119,7 +119,7 @@
*/
function startPlaylistRow(col, success) {
if (!col) return false;
var span = col.querySelector(".content");
var span = col.querySelector(".column-content");
if (span) {
simulateMouseEvent("mouseover", span);
setTimeout(function() {
Expand Down
Loading

0 comments on commit cba43d8

Please sign in to comment.