From cce5d35ca24191091786e722f15189165eb259eb Mon Sep 17 00:00:00 2001 From: emeric Date: Mon, 20 Jan 2020 13:55:32 +0100 Subject: [PATCH] Added support for MediaSession API. fixes #17 --- docroot/js/mediaplayer.js | 32 +++++++++++++++++++++++++++---- src/ui/LmsApplication.cpp | 8 +------- src/ui/MediaPlayer.cpp | 18 +++++++++++++---- src/ui/resource/ImageResource.cpp | 9 ++++++++- src/ui/resource/ImageResource.hpp | 2 ++ src/utils/Utils.cpp | 6 ++++++ src/utils/Utils.hpp | 3 +++ 7 files changed, 62 insertions(+), 16 deletions(-) diff --git a/docroot/js/mediaplayer.js b/docroot/js/mediaplayer.js index 3987eeab..e194fc00 100644 --- a/docroot/js/mediaplayer.js +++ b/docroot/js/mediaplayer.js @@ -48,6 +48,14 @@ LMS.mediaplayer = function () { } } + var _requestPreviousTrack = function() { + Wt.emit(_root, "playNext"); + } + + var _requestNextTrack = function() { + Wt.emit(_root, "playNext"); + } + var init = function(root) { _root = root; @@ -72,10 +80,10 @@ LMS.mediaplayer = function () { }); _elems.previous.addEventListener("click", function() { - Wt.emit(_root, "playPrevious"); + _requestPreviousTrack(); }); _elems.next.addEventListener("click", function() { - Wt.emit(_root, "playNext"); + _requestNextTrack(); }); _elems.seek.addEventListener("change", function() { if (!_elems.audio.hasAttribute("src")) @@ -133,11 +141,18 @@ LMS.mediaplayer = function () { } }); + if ('mediaSession' in navigator) { + navigator.mediaSession.setActionHandler("previoustrack", function() { + _requestPreviousTrack(); + }); + navigator.mediaSession.setActionHandler("nexttrack", function() { + _requestNextTrack(); + }); + } + } var loadTrack = function(params, autoplay) { - console.log("Loading track, resource = '" + params.resource + "', imgResource = '" + params.imgResource + "'"); - _offset = 0; _duration = params.duration; _audioSrc = params.resource; @@ -150,6 +165,15 @@ LMS.mediaplayer = function () { if (autoplay) _playTrack(); + + if ('mediaSession' in navigator) { + navigator.mediaSession.metadata = new MediaMetadata({ + title: params.title, + artist: params.artist, + album: params.release, + artwork: params.artwork, + }); + } } var stop = function() { diff --git a/src/ui/LmsApplication.cpp b/src/ui/LmsApplication.cpp index ef746020..e3585d8d 100644 --- a/src/ui/LmsApplication.cpp +++ b/src/ui/LmsApplication.cpp @@ -630,12 +630,6 @@ LmsApplication::post(std::function func) Wt::WServer::instance()->post(LmsApp->sessionId(), std::move(func)); } -static -std::string -escape(const std::string& str) -{ - return replaceInString(std::move(str), "\'", "\\\'"); -} void LmsApplication::notifyMsg(MsgType type, const Wt::WString& message, std::chrono::milliseconds duration) @@ -645,7 +639,7 @@ LmsApplication::notifyMsg(MsgType type, const Wt::WString& message, std::chrono: std::ostringstream oss; oss << "$.notify({" - "message: '" << escape(message.toUTF8()) << "'" + "message: '" << jsEscape(message.toUTF8()) << "'" "},{" "type: '" << msgTypeToString(type) << "'," "placement: {from: 'top', align: 'center'}," diff --git a/src/ui/MediaPlayer.cpp b/src/ui/MediaPlayer.cpp index ae4c9595..8cca5ffb 100644 --- a/src/ui/MediaPlayer.cpp +++ b/src/ui/MediaPlayer.cpp @@ -29,6 +29,8 @@ #include "resource/ImageResource.hpp" #include "resource/AudioResource.hpp" +#include "utils/Utils.hpp" + #include "LmsApplication.hpp" namespace UserInterface { @@ -66,15 +68,24 @@ MediaPlayer::loadTrack(Database::IdType trackId, bool play) { const Av::MediaFile mediaFile {track->getPath()}; - auto resource = LmsApp->getAudioResource()->getUrl(trackId); - auto imgResource = LmsApp->getImageResource()->getTrackUrl(trackId, 64); + const std::string resource {LmsApp->getAudioResource()->getUrl(trackId)}; + const std::string imgResourceMimeType {LmsApp->getImageResource()->getMimeType()}; + + const auto artists {track->getArtists()}; std::ostringstream oss; oss << "var params = {" << " resource: \"" << resource << "\"," << " duration: " << std::chrono::duration_cast(track->getDuration()).count() << "," - << " imgResource: \"" << imgResource << "\"," + << " title: \"" << jsEscape(track->getName()) << "\"," + << " artist: \"" << (!artists.empty() ? jsEscape(artists.front()->getName()) : "") << "\"," + << " release: \"" << (track->getRelease() ? jsEscape(track->getRelease()->getName()) : "") << "\"," + << " artwork: [" + << " { src: \"" << LmsApp->getImageResource()->getTrackUrl(trackId, 96) << "\", sizes: \"96x96\", type: \"" << imgResourceMimeType << "\" }," + << " { src: \"" << LmsApp->getImageResource()->getTrackUrl(trackId, 256) << "\", sizes: \"256x256\", type: \"" << imgResourceMimeType << "\" }," + << " { src: \"" << LmsApp->getImageResource()->getTrackUrl(trackId, 512) << "\", sizes: \"512x512\", type: \"" << imgResourceMimeType << "\" }," + << " ]" << "};"; oss << "LMS.mediaplayer.loadTrack(params, " << (play ? "true" : "false") << ")"; // true to autoplay @@ -82,7 +93,6 @@ MediaPlayer::loadTrack(Database::IdType trackId, bool play) _title->setText(Wt::WString::fromUTF8(track->getName())); - auto artists = track->getArtists(); if (!artists.empty()) { _artist->setText(Wt::WString::fromUTF8(artists.front()->getName())); diff --git a/src/ui/resource/ImageResource.cpp b/src/ui/resource/ImageResource.cpp index 114ce5b5..5ae08324 100644 --- a/src/ui/resource/ImageResource.cpp +++ b/src/ui/resource/ImageResource.cpp @@ -98,8 +98,15 @@ ImageResource::handleRequest(const Wt::Http::Request& request, Wt::Http::Respons else return; - response.setMimeType( Image::format_to_mimeType(Image::Format::JPEG) ); + response.setMimeType(getMimeType()); + response.out().write(reinterpret_cast(&cover[0]), cover.size()); } +std::string +ImageResource::getMimeType() +{ + return Image::format_to_mimeType(Image::Format::JPEG); +} + } // namespace UserInterface diff --git a/src/ui/resource/ImageResource.hpp b/src/ui/resource/ImageResource.hpp index 49b61559..2f372b7d 100644 --- a/src/ui/resource/ImageResource.hpp +++ b/src/ui/resource/ImageResource.hpp @@ -41,6 +41,8 @@ class ImageResource : public Wt::WResource std::string getReleaseUrl(Database::IdType releaseId, size_t size) const; std::string getTrackUrl(Database::IdType trackId, size_t size) const; + static std::string getMimeType(); + void handleRequest(const Wt::Http::Request& request, Wt::Http::Response& response); }; diff --git a/src/utils/Utils.cpp b/src/utils/Utils.cpp index c199386b..29d1a3a6 100644 --- a/src/utils/Utils.cpp +++ b/src/utils/Utils.cpp @@ -131,6 +131,12 @@ replaceInString(const std::string& str, const std::string& from, const std::stri return res; } +std::string +jsEscape(const std::string& str) +{ + return replaceInString(str, "\'", "\\\'"); +} + bool stringEndsWith(const std::string& str, const std::string& ending) { diff --git a/src/utils/Utils.hpp b/src/utils/Utils.hpp index 17aacb83..562dbad7 100644 --- a/src/utils/Utils.hpp +++ b/src/utils/Utils.hpp @@ -67,6 +67,9 @@ std::optional readAs(const std::string& str) std::string replaceInString(const std::string& str, const std::string& from, const std::string& to); +std::string +jsEscape(const std::string& str); + bool stringEndsWith(const std::string& str, const std::string& ending);