Skip to content

Commit

Permalink
Merge pull request #79 from aidewoode/dev
Browse files Browse the repository at this point in the history
fix issue #69, add support for Media Session API
  • Loading branch information
aidewoode committed Feb 5, 2021
2 parents 29f8890 + 28c1876 commit a105a3a
Show file tree
Hide file tree
Showing 6 changed files with 132 additions and 8 deletions.
4 changes: 3 additions & 1 deletion .eslintrc.js
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,8 @@ module.exports = {
"App": true,
"Turbolinks": true,
"CustomEvent": true,
"IntersectionObserver": true
"IntersectionObserver": true,
"MediaMetadata": true,
"navigator": true
}
};
118 changes: 118 additions & 0 deletions app/frontend/javascripts/controllers/media_session_controller.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,118 @@
import { Controller } from 'stimulus';

export default class extends Controller {
DEFAULT_SKIP_TIME = 10;

connect() {
if (!('mediaSession' in navigator)) { return; }

document.addEventListener('player:playing', this._setPlayingStatus);

Object.entries(this.mediaSessionActions).forEach(([actionName, actionHandler]) => {
try {
navigator.mediaSession.setActionHandler(actionName, actionHandler);
} catch (error) {
// The media session ation is not supported.
}
});
}

disconnect() {
if (!('mediaSession' in navigator)) { return; }

document.removeEventListener('player:playing', this._setPlayingStatus);
}


_setPlayingStatus = () => {
this._updateMetadata();
this._updatePositionState();
}

_updateMetadata = () => {
navigator.mediaSession.metadata = new MediaMetadata({
title: this.currentSong.name,
artist: this.currentSong.artist_name,
album: this.currentSong.album_name,
artwork: [
{ src: this.currentSong.album_image_url.small, sizes: '200x200' },
{ src: this.currentSong.album_image_url.medium, sizes: '300x300' },
{ src: this.currentSong.album_image_url.large, sizes: '400x400' },
]
});
}

_updatePositionState = () => {
if (!('setPositionState' in navigator.mediaSession)) { return; }

navigator.mediaSession.setPositionState({
duration: this.currentSong.length,
playbackRate: this.currentSong.howl.rate(),
position: this.currentSong.howl.seek()
});
}

_play = () => {
this.player.play(this.currentIndex);
}

_pause = () => {
this.player.pause();
}

_next = () => {
this.player.next();
}

_previous = () => {
this.player.previous();
}

_stop = () => {
this.player.stop();
}

_seekBackward = (event) => {
const skipTime = event.seekOffset || this.DEFAULT_SKIP_TIME;

this.player.seek(this.currentSong.howl.seek() - skipTime);
this._updatePositionState();
}

_seekForward = (event) => {
const skipTime = event.seekOffset || this.DEFAULT_SKIP_TIME;

this.player.seek(this.currentSong.howl.seek() + skipTime);
this._updatePositionState();
}

_seekTo = (event) => {
this.player.seek(event.seekTime);
this._updatePositionState();
}

get mediaSessionActions() {
return {
play: this._play,
pause: this._pause,
previoustrack: this._previous,
nexttrack: this._next,
stop: this._stop,
seekbackward: this._seekBackward,
seekforward: this._seekForward,
seekto: this._seekTo
};
}

get player() {
return App.player;
}

get currentSong() {
return this.player.currentSong;
}

get currentIndex() {
return this.player.currentIndex;
}
}
6 changes: 3 additions & 3 deletions app/frontend/javascripts/controllers/player_controller.js
Original file line number Diff line number Diff line change
Expand Up @@ -91,7 +91,7 @@ export default class extends Controller {
}

seek(event) {
this.player.seek(event.offsetX / event.target.offsetWidth);
this.player.seek((event.offsetX / event.target.offsetWidth) * this.currentSong.length);
window.requestAnimationFrame(this._setProgress.bind(this));
}

Expand Down Expand Up @@ -119,8 +119,8 @@ export default class extends Controller {
_setPlayingStatus = () => {
const { currentSong } = this;

this.imageTarget.src = currentSong.album_image_url;
this.backgroundImageTarget.style.backgroundImage = `url(${currentSong.album_image_url})`;
this.imageTarget.src = currentSong.album_image_url.small;
this.backgroundImageTarget.style.backgroundImage = `url(${currentSong.album_image_url.small})`;
this.songNameTarget.textContent = currentSong.name;
this.artistNameTarget.textContent = currentSong.artist_name;
this.albumNameTarget.textContent = currentSong.album_name;
Expand Down
4 changes: 2 additions & 2 deletions app/frontend/javascripts/player.js
Original file line number Diff line number Diff line change
Expand Up @@ -73,8 +73,8 @@ class Player {
this.play(index);
}

seek(percent) {
this.currentSong.howl.seek(this.currentSong.length * percent);
seek(seconds) {
this.currentSong.howl.seek(seconds);
}
}

Expand Down
2 changes: 1 addition & 1 deletion app/views/shared/_player.html.erb
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
<div class='c-player u-h-100' data-controller='player'>
<div class='c-player u-h-100' data-controller='player media-session'>
<div data-player-target='header' class='c-player__header u-position-relative'>
<div class='u-position-relative u-overflow-hidden'>
<div class='c-player__header__background' data-player-target='backgroundImage'></div>
Expand Down
6 changes: 5 additions & 1 deletion app/views/songs/show.json.jbuilder
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,10 @@ json.call(@song, :id, :name, :length)
json.url new_stream_path(song_id: @song.id)
json.album_name @song.album.title
json.artist_name @song.artist.title
json.album_image_url image_url_for(@song.album, size: 'small')
json.is_favorited Current.user.favorited? @song
json.format @song.format
json.album_image_url do
json.small image_url_for(@song.album, size: 'small')
json.medium image_url_for(@song.album, size: 'medium')
json.large image_url_for(@song.album, size: 'large')
end

0 comments on commit a105a3a

Please sign in to comment.