Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,10 @@
# Changelog

1.103.0

- Support for station level like/skip adjustments
- Bugfix for 'play-resumed' event not being triggered

1.102.3

- Improved handling of non-200 HTTP errors
Expand Down
2 changes: 1 addition & 1 deletion dist/feed-media-audio-player.min.js

Large diffs are not rendered by default.

36 changes: 29 additions & 7 deletions html/manual.html
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,8 @@
<button class="pause-button">pause</button>
<button class="skip-button">skip</button>
<button class="stop-button">stop</button>
<button class="like-button">like</button>
<button class="dislike-button">dislike</button>
<button class="initialize-audio">initializeAudio</button>
</div>

Expand All @@ -40,30 +42,50 @@
<div class="status"></div>
</div>

<div>
<select id="ip">
<option value="US" selected>US</option>
<option value="CA">CA</option>
</select>
</div>


<script>
console.log('**** PAGE RELOAD ******');

const ips = {
US: '75.37.70.130',
CA: '192.206.151.131'
};

const country = this.location.search ? this.location.search.slice(1) : 'US';
const ip = ips[country];

$('#ip').val(country);

$('#ip').on('change', function() {
window.location.search = $(this).val();
});

var simulcast = 'nGwPEXk4js9V4Yp3HcyM2i';

// Create basic player.
console.log('pre');
var player = Feed.resumable(60000) ||
new Feed.Player('demo', 'demo', {
baseUrl: 'https://feed.fm',
new Feed.Player('country', 'country', {
baseUrl: 'https://stage.feed.fm',
debug: true,
simulcast: simulcast,
remoteLogging: true
});
console.log("post!");

player.session.extraHeaders = { 'X-Streaming-For': ips[country] };
console.log('state', player.getCurrentState());

// Display all the events the player triggers
player.on('all', function (event) {
console.log('EVENT: \'' + event + '\' with arguments:', Array.prototype.splice.call(arguments, 1));
console.log(' state', player.getCurrentState());
console.log(' ', JSON.stringify(player._persist(), null, 2));

console.log(' ', player._persist());
});

player.on('stations', function (stations) {
Expand Down
4 changes: 2 additions & 2 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@
"name": "Eric Lambrecht",
"email": "eric@feed.fm"
},
"version": "1.102.3",
"version": "1.103.0",
"scripts": {
"build": "rollup -c",
"watch": "rollup -c -w",
Expand Down
27 changes: 22 additions & 5 deletions src/player-view.js
Original file line number Diff line number Diff line change
Expand Up @@ -90,6 +90,7 @@ var PlayerView = function (id, player) {
this.player.on('play-liked', this._onPlayLiked, this);
this.player.on('play-unliked', this._onPlayUnliked, this);
this.player.on('play-disliked', this._onPlayDisliked, this);
this.player.on('station-changed', this._onStationChanged, this);
this.player.on('plays-exhausted', this._onPlaysExhausted, this);
this.player.on('skip-denied', this._onSkipDenied, this);
this.player.on('suspend', this._onSuspend, this);
Expand Down Expand Up @@ -188,6 +189,10 @@ PlayerView.prototype._onPlayStarted = function (play) {
this._enablePositionTracker();
};

PlayerView.prototype._onStationChanged = function () {
this._enableButtonsBasedOnState();
};

PlayerView.prototype._enablePositionTracker = function () {
var playerView = this;

Expand Down Expand Up @@ -368,21 +373,33 @@ PlayerView.prototype._enableButtonsBasedOnState = function () {

switch (state) {
case 'playing':
toEnable = ['.pause-button', '.like-button', '.dislike-button'];
toEnable = ['.pause-button'];
toDisable = ['.play-button', '.start-button', '.resume-button'];

if (this.player.maybeCanSkip()) {
if (this.player.canLike()) {
toEnable.push('.dislike-button', '.like-button');
} else {
toDisable.push('.dislike-button', '.like-button');
}

if (this.player.canSkip()) {
toEnable.push('.skip-button');
} else {
toDisable.push('.skip-button');
}
break;

case 'paused':
toEnable = ['.play-button', '.resume-button', '.like-button', '.dislike-button'];
toEnable = ['.play-button', '.resume-button'];
toDisable = ['.pause-button', '.start-button'];

if (this.player.maybeCanSkip()) {
if (this.player.canLike()) {
toEnable.push('.dislike-button', '.like-button');
} else {
toDisable.push('.dislike-button', '.like-button');
}

if (this.player.canSkip()) {
toEnable.push('.skip-button');
} else {
toDisable.push('.skip-button');
Expand All @@ -395,7 +412,7 @@ PlayerView.prototype._enableButtonsBasedOnState = function () {
toDisable = ['.resume-button', '.pause-button', '.like-button', '.dislike-button', '.skip-button'];
break;
}

for (let item of toDisable) {
this.$el.querySelectorAll(item).forEach((element) => {
element.classList.remove('button-enabled');
Expand Down
57 changes: 51 additions & 6 deletions src/player.js
Original file line number Diff line number Diff line change
Expand Up @@ -94,6 +94,9 @@
* Some misc methods:
*
* setMuted(muted)
* canLike() - returns true if the current song may be liked/unliked/disliked
* canSkip() - returns true if the current song may be skipped (some stations have
* skip frequency limits or disable skipping entirely)
*
*/

Expand Down Expand Up @@ -464,7 +467,7 @@ Player.prototype._onSoundPlay = function (playId) {

return this.session.reportPlayStarted();

} else if (!playerWasResumed) {
} else if (playerWasResumed) {
// subsequent plays are considered 'resumed' events
this.trigger('play-resumed', this.session.getActivePlay());
}
Expand Down Expand Up @@ -658,10 +661,6 @@ Player.prototype.isPaused = function () {
return this.session.isTuned() && this.state.paused;
};

Player.prototype.getStationInformation = function (stationInformationCallback) {
return this.session.getStationInformation(stationInformationCallback);
};

Player.prototype.tune = function () {
log('TUNE');

Expand Down Expand Up @@ -801,12 +800,28 @@ Player.prototype.pause = function () {
this.updateSimulcast();
};

/**
* Some regions disallow 'like'ing of songs (e.g. Canada). Check this after
* changing the active station or when a new song starts to know if the current
* song may be liked/disliked/unliked.
*
* @returns {boolean} true if we can 'like' songs in the currently active station
*/

Player.prototype.canLike = function() {
return this.session.canLike();
};

Player.prototype.like = function () {
log('LIKE');

if (!this.session.hasActivePlayStarted()) {
return;
}

if (!this.session.canLike()) {
return;
}

this.session.likePlay(this.state.activePlay.id);

Expand All @@ -820,6 +835,10 @@ Player.prototype.unlike = function () {
return;
}

if (!this.session.canLike()) {
return;
}

this.session.unlikePlay(this.state.activePlay.id);

this.trigger('play-unliked');
Expand All @@ -832,6 +851,10 @@ Player.prototype.dislike = function () {
return;
}

if (!this.session.canLike()) {
return;
}

this.session.dislikePlay(this.state.activePlay.id);

this.trigger('play-disliked');
Expand All @@ -849,6 +872,11 @@ Player.prototype.skip = function () {
return;
}

// cannot skip in station with skipping disabled
if (!this.session.canSkipInStation()) {
return;
}

this.state.paused = false;

this.session.requestSkip();
Expand Down Expand Up @@ -930,8 +958,25 @@ Player.prototype.getDuration = function () {
}
};

/**
* Return true if the user may skip the current song.
*
* @returns {boolean}
*/

Player.prototype.canSkip = function() {
return this.session.canSkip();
};

/**
* Technically, you might not be able to skip a song at the time it starts, but
* eventually enough time might pass that you can skip the song. Hence, we
* had 'maybeCanSkip'. However, nobody is repeatedly checking for skippability
* while playing a song, so this method is deprecated.
*/

Player.prototype.maybeCanSkip = function () {
return !!this.session.maybeCanSkip();
return this.canSkip();
};

var mutedKey = 'muted';
Expand Down
61 changes: 51 additions & 10 deletions src/session.js
Original file line number Diff line number Diff line change
Expand Up @@ -84,9 +84,8 @@
* session.isTuned(): true if the session has active plays available or is awaiting
* plays from the server
* session.hasActivePlayStarted(): returns true if the active play is playing now
* session.maybeCanSkip(): returns true if there is a song being played now and
* we believe we can skip it (this might not hold true, and the server can
* override this)
* session.canSkip(): returns true if there is a song being played now and
* we believe we can skip it.
*
* Other misc calls:
*
Expand Down Expand Up @@ -440,12 +439,8 @@ Session.prototype.reportPlayStopped = function (seconds) {
};

Session.prototype.requestSkip = function () {
if (!this.config.current) {
throw new Error('No song being played');
}

if (!this.config.current.started) {
throw new Error('No song has been started');
if (!this.hasActivePlayStarted()) {
throw new Error('No song playing or started');
}

if (!this.config.current.canSkip) {
Expand Down Expand Up @@ -891,11 +886,45 @@ Session.prototype._failedNextPlay = function (delay, ajax, response) {
}
};

Session.prototype.canSkipInStation = function() {
return !(this.config.station && this.config.station.can_skip === false);
};

/**
* @returns {boolean} true if the user can skip the current song
*/
Session.prototype.maybeCanSkip = function () {
return this.config.current && this.config.current.started && this.config.current.canSkip;
return this.canSkip();
};

/**
* @returns {boolean} true if the user can skip the current song
*/

Session.prototype.canSkip = function () {
// you can probably skip unless we've explicitly disallowed it at the station or current song level
const can = this.canSkipInStation() && this.config.current && this.config.current.started && this.config.current.canSkip;

return !!can;
};

/**
* @returns {boolean} true if the user can like the current song
*/

Session.prototype.canLike = function() {
const response = !(this.config.station && this.config.station.can_like === false);

return response;
};

Session.prototype.likePlay = function (playId) {
if (!this.canLike()) {
// technically, this play could be from a different station, but we're not tracking
// that right now... so let's just assume it is in the current station.
return;
}

this._signedAjax(getBaseUrl() + '/api/v2/play/' + playId + '/like', {
method: 'POST'
})
Expand All @@ -908,6 +937,12 @@ Session.prototype.likePlay = function (playId) {
};

Session.prototype.unlikePlay = function (playId) {
if (!this.canLike()) {
// technically, this play could be from a different station, but we're not tracking
// that right now... so let's just assume it is in the current station.
return;
}

this._signedAjax(getBaseUrl() + '/api/v2/play/' + playId + '/like', {
method: 'DELETE'
})
Expand All @@ -920,6 +955,12 @@ Session.prototype.unlikePlay = function (playId) {
};

Session.prototype.dislikePlay = function (playId) {
if (!this.canLike()) {
// technically, this play could be from a different station, but we're not tracking
// that right now... so let's just assume it is in the current station.
return;
}

this._signedAjax(getBaseUrl() + '/api/v2/play/' + playId + '/dislike', {
method: 'POST'
})
Expand Down