Added support for MediaSession API. fixes #17
This commit is contained in:
@@ -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) {
|
var init = function(root) {
|
||||||
_root = root;
|
_root = root;
|
||||||
|
|
||||||
@@ -72,10 +80,10 @@ LMS.mediaplayer = function () {
|
|||||||
});
|
});
|
||||||
|
|
||||||
_elems.previous.addEventListener("click", function() {
|
_elems.previous.addEventListener("click", function() {
|
||||||
Wt.emit(_root, "playPrevious");
|
_requestPreviousTrack();
|
||||||
});
|
});
|
||||||
_elems.next.addEventListener("click", function() {
|
_elems.next.addEventListener("click", function() {
|
||||||
Wt.emit(_root, "playNext");
|
_requestNextTrack();
|
||||||
});
|
});
|
||||||
_elems.seek.addEventListener("change", function() {
|
_elems.seek.addEventListener("change", function() {
|
||||||
if (!_elems.audio.hasAttribute("src"))
|
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) {
|
var loadTrack = function(params, autoplay) {
|
||||||
console.log("Loading track, resource = '" + params.resource + "', imgResource = '" + params.imgResource + "'");
|
|
||||||
|
|
||||||
_offset = 0;
|
_offset = 0;
|
||||||
_duration = params.duration;
|
_duration = params.duration;
|
||||||
_audioSrc = params.resource;
|
_audioSrc = params.resource;
|
||||||
@@ -150,6 +165,15 @@ LMS.mediaplayer = function () {
|
|||||||
|
|
||||||
if (autoplay)
|
if (autoplay)
|
||||||
_playTrack();
|
_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() {
|
var stop = function() {
|
||||||
|
|||||||
@@ -630,12 +630,6 @@ LmsApplication::post(std::function<void()> func)
|
|||||||
Wt::WServer::instance()->post(LmsApp->sessionId(), std::move(func));
|
Wt::WServer::instance()->post(LmsApp->sessionId(), std::move(func));
|
||||||
}
|
}
|
||||||
|
|
||||||
static
|
|
||||||
std::string
|
|
||||||
escape(const std::string& str)
|
|
||||||
{
|
|
||||||
return replaceInString(std::move(str), "\'", "\\\'");
|
|
||||||
}
|
|
||||||
|
|
||||||
void
|
void
|
||||||
LmsApplication::notifyMsg(MsgType type, const Wt::WString& message, std::chrono::milliseconds duration)
|
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;
|
std::ostringstream oss;
|
||||||
|
|
||||||
oss << "$.notify({"
|
oss << "$.notify({"
|
||||||
"message: '" << escape(message.toUTF8()) << "'"
|
"message: '" << jsEscape(message.toUTF8()) << "'"
|
||||||
"},{"
|
"},{"
|
||||||
"type: '" << msgTypeToString(type) << "',"
|
"type: '" << msgTypeToString(type) << "',"
|
||||||
"placement: {from: 'top', align: 'center'},"
|
"placement: {from: 'top', align: 'center'},"
|
||||||
|
|||||||
+14
-4
@@ -29,6 +29,8 @@
|
|||||||
#include "resource/ImageResource.hpp"
|
#include "resource/ImageResource.hpp"
|
||||||
#include "resource/AudioResource.hpp"
|
#include "resource/AudioResource.hpp"
|
||||||
|
|
||||||
|
#include "utils/Utils.hpp"
|
||||||
|
|
||||||
#include "LmsApplication.hpp"
|
#include "LmsApplication.hpp"
|
||||||
|
|
||||||
namespace UserInterface {
|
namespace UserInterface {
|
||||||
@@ -66,15 +68,24 @@ MediaPlayer::loadTrack(Database::IdType trackId, bool play)
|
|||||||
{
|
{
|
||||||
const Av::MediaFile mediaFile {track->getPath()};
|
const Av::MediaFile mediaFile {track->getPath()};
|
||||||
|
|
||||||
auto resource = LmsApp->getAudioResource()->getUrl(trackId);
|
const std::string resource {LmsApp->getAudioResource()->getUrl(trackId)};
|
||||||
auto imgResource = LmsApp->getImageResource()->getTrackUrl(trackId, 64);
|
const std::string imgResourceMimeType {LmsApp->getImageResource()->getMimeType()};
|
||||||
|
|
||||||
|
const auto artists {track->getArtists()};
|
||||||
|
|
||||||
std::ostringstream oss;
|
std::ostringstream oss;
|
||||||
oss
|
oss
|
||||||
<< "var params = {"
|
<< "var params = {"
|
||||||
<< " resource: \"" << resource << "\","
|
<< " resource: \"" << resource << "\","
|
||||||
<< " duration: " << std::chrono::duration_cast<std::chrono::seconds>(track->getDuration()).count() << ","
|
<< " duration: " << std::chrono::duration_cast<std::chrono::seconds>(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
|
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()));
|
_title->setText(Wt::WString::fromUTF8(track->getName()));
|
||||||
|
|
||||||
auto artists = track->getArtists();
|
|
||||||
if (!artists.empty())
|
if (!artists.empty())
|
||||||
{
|
{
|
||||||
_artist->setText(Wt::WString::fromUTF8(artists.front()->getName()));
|
_artist->setText(Wt::WString::fromUTF8(artists.front()->getName()));
|
||||||
|
|||||||
@@ -98,8 +98,15 @@ ImageResource::handleRequest(const Wt::Http::Request& request, Wt::Http::Respons
|
|||||||
else
|
else
|
||||||
return;
|
return;
|
||||||
|
|
||||||
response.setMimeType( Image::format_to_mimeType(Image::Format::JPEG) );
|
response.setMimeType(getMimeType());
|
||||||
|
|
||||||
response.out().write(reinterpret_cast<const char *>(&cover[0]), cover.size());
|
response.out().write(reinterpret_cast<const char *>(&cover[0]), cover.size());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
std::string
|
||||||
|
ImageResource::getMimeType()
|
||||||
|
{
|
||||||
|
return Image::format_to_mimeType(Image::Format::JPEG);
|
||||||
|
}
|
||||||
|
|
||||||
} // namespace UserInterface
|
} // namespace UserInterface
|
||||||
|
|||||||
@@ -41,6 +41,8 @@ class ImageResource : public Wt::WResource
|
|||||||
std::string getReleaseUrl(Database::IdType releaseId, size_t size) const;
|
std::string getReleaseUrl(Database::IdType releaseId, size_t size) const;
|
||||||
std::string getTrackUrl(Database::IdType trackId, 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);
|
void handleRequest(const Wt::Http::Request& request, Wt::Http::Response& response);
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -131,6 +131,12 @@ replaceInString(const std::string& str, const std::string& from, const std::stri
|
|||||||
return res;
|
return res;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
std::string
|
||||||
|
jsEscape(const std::string& str)
|
||||||
|
{
|
||||||
|
return replaceInString(str, "\'", "\\\'");
|
||||||
|
}
|
||||||
|
|
||||||
bool
|
bool
|
||||||
stringEndsWith(const std::string& str, const std::string& ending)
|
stringEndsWith(const std::string& str, const std::string& ending)
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -67,6 +67,9 @@ std::optional<T> readAs(const std::string& str)
|
|||||||
std::string
|
std::string
|
||||||
replaceInString(const std::string& str, const std::string& from, const std::string& to);
|
replaceInString(const std::string& str, const std::string& from, const std::string& to);
|
||||||
|
|
||||||
|
std::string
|
||||||
|
jsEscape(const std::string& str);
|
||||||
|
|
||||||
bool
|
bool
|
||||||
stringEndsWith(const std::string& str, const std::string& ending);
|
stringEndsWith(const std::string& str, const std::string& ending);
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user