diff --git a/approot/mediaplayer.xml b/approot/mediaplayer.xml index 0d445ca6..15ab6bb4 100644 --- a/approot/mediaplayer.xml +++ b/approot/mediaplayer.xml @@ -2,37 +2,18 @@ - - - - - - - - - - - - - - - - - - - - - - - - - ${previous} ${play-pause} ${next} - ${cover} - ${current-time} ${total-time} ${shuffle} ${repeat} - ${}${artist-name}${} - ${}${release-name}${} - ${track-name} + +
+ +
...
+
+
+
00:00
+
00:00
+
+
+
diff --git a/docroot/js/mediaplayer.js b/docroot/js/mediaplayer.js index 8a2ab650..69570ad8 100644 --- a/docroot/js/mediaplayer.js +++ b/docroot/js/mediaplayer.js @@ -1 +1,81 @@ -/* TEST */ +// @license magnet:?xt=urn:btih:1f739d935676111cfff4b4693e3816e664797050&dn=gpl-3.0.txt GPL-v3-or-Later + +var LMS = LMS || {}; + +LMS.mediaplayer = function () { + + var _root = {}; + var _elems = {}; + + var _updateControls = function() { + if (_elems.audio.paused) { + _elems.play.style.display = "block"; + _elems.pause.style.display = "none"; + } + else { + _elems.pause.style.display = "block"; + _elems.play.style.display = "none"; + } + } + + var init = function(root) { + _root = root; + + _elems.audio = document.getElementById("lms-mp-audio"); + _elems.play = document.getElementById("lms-mp-play"); + _elems.pause = document.getElementById("lms-mp-pause"); + _elems.previous = document.getElementById("lms-mp-previous"); + _elems.next = document.getElementById("lms-mp-next"); + _elems.title = document.getElementById("lms-mp-title"); + _elems.artist = document.getElementById("lms-mp-artist"); + _elems.release = document.getElementById("lms-mp-release"); + _elems.duration = document.getElementById("lms-mp-duration"); + + _elems.play.addEventListener("click", function() { + _elems.audio.play(); + }); + _elems.pause.addEventListener("click", function() { + _elems.audio.pause(); + }); + + _elems.previous.addEventListener("click", function() { + Wt.emit(_root, "playPrevious"); + }); + _elems.next.addEventListener("click", function() { + Wt.emit(_root, "playNext"); + }); + + _elems.audio.addEventListener("play", _updateControls); + _elems.audio.addEventListener("playing", _updateControls); + _elems.audio.addEventListener("pause", _updateControls); + + _elems.audio.addEventListener("ended", function() { + Wt.emit(_root, "playbackEnded"); + }); + } + + var loadTrack = function(params, autoplay) { + console.log("Loading track '" + params.name + "', release = '" + params.release + "', artist = '" + params.artist + "', resource = '" + params.resource + "', imgResource = '" + params.imgResource); + + _elems.title.innerHTML = params.name; + _elems.artist.innerHTML = params.artist; + _elems.release.innerHTML = params.release; + _elems.audio.src = params.resource; + _elems.duration.innerHTML = params.duration; + + if (autoplay) + _elems.audio.play(); + } + + var stop = function() { + _elems.audio.pause(); + } + + return { + init: init, + loadTrack: loadTrack, + stop: stop, + }; +}(); + +// @license-end diff --git a/src/ui/MediaPlayer.cpp b/src/ui/MediaPlayer.cpp index fa9a2003..62423135 100644 --- a/src/ui/MediaPlayer.cpp +++ b/src/ui/MediaPlayer.cpp @@ -16,10 +16,7 @@ * You should have received a copy of the GNU General Public License * along with LMS. If not, see . */ -#include -#include -#include -#include +#include #include "av/AvInfo.hpp" #include "utils/Logger.hpp" @@ -33,50 +30,17 @@ namespace UserInterface { MediaPlayer::MediaPlayer(Wt::WContainerWidget* parent) -: Wt::WContainerWidget(parent) +: Wt::WTemplate(Wt::WString::tr("template-mediaplayer"), parent), + playbackEnded(this, "playbackEnded"), + playPrevious(this, "playPrevious"), + playNext(this, "playNext") { - _audio = new Wt::WAudio(this); - _audio->setOptions(Wt::WAudio::Autoplay); - _audio->setPreloadMode(Wt::WAudio::PreloadNone); + wApp->doJavaScript("LMS.mediaplayer.init(" + jsRef() + ")"); +} - _audio->ended().connect(std::bind([=] () - { - playbackEnded.emit(); - })); - - auto player = new Wt::WTemplate(Wt::WString::tr("template-mediaplayer"), this); - - auto playPauseBtn = new Wt::WText(Wt::WString::tr("btn-mediaplayer-play"), Wt::XHTMLText); - player->bindWidget("play-pause", playPauseBtn); - - auto prevBtn = new Wt::WText(Wt::WString::tr("btn-mediaplayer-prev"), Wt::XHTMLText); - player->bindWidget("previous", prevBtn); - prevBtn->clicked().connect(std::bind([=] - { - playPrevious.emit(); - })); - - auto nextBtn = new Wt::WText(Wt::WString::tr("btn-mediaplayer-next"), Wt::XHTMLText); - player->bindWidget("next", nextBtn); - nextBtn->clicked().connect(std::bind([=] - { - playNext.emit(); - })); - - auto shuffleBtn = new Wt::WText(Wt::WString::tr("btn-mediaplayer-shuffle"), Wt::XHTMLText); - player->bindWidget("shuffle", shuffleBtn); - - auto repeatBtn = new Wt::WText(Wt::WString::tr("btn-mediaplayer-repeat"), Wt::XHTMLText); - player->bindWidget("repeat", repeatBtn); - - player->bindString("current-time", "00:00"); - player->bindString("total-time", "00:00"); - - auto cover = new Wt::WImage(); - player->bindWidget("cover", cover); - - auto trackName = new Wt::WText("---"); - player->bindWidget("track-name", trackName); +static std::string escape(const std::string& str) +{ + return boost::replace_all_copy(str, "\"", "\\\""); } void @@ -86,32 +50,39 @@ MediaPlayer::playTrack(Database::Track::id_type trackId) Wt::Dbo::Transaction transaction(DboSession()); auto track = Database::Track::getById(DboSession(), trackId); - transaction.commit(); // Analyse track, select the best media stream try { Av::MediaFile mediaFile(track->getPath()); - auto streamId = mediaFile.getBestStream(); + auto resource = LmsApp->getTranscodeResource()->getUrl(trackId, Av::Encoding::MP3, boost::posix_time::seconds(0)); - _audio->pause(); - _audio->clearSources(); - _audio->addSource(LmsApp->getTranscodeResource()->getUrl(trackId, Av::Encoding::MP3, boost::posix_time::seconds(0), streamId)); - _audio->setPreloadMode(Wt::WAudio::PreloadNone); - _audio->play(); + std::ostringstream oss; + oss + << "var params = {" + << " name: \"" << escape(track->getName()) + "\"," + << " release: " << (track->getRelease() ? "\"" + escape(track->getRelease()->getName()) + "\"" : "undefined" ) << "," + << " artist: " << (track->getArtist() ? "\"" + escape(track->getArtist()->getName()) + "\"" : "undefined" ) << "," + << " resource: \"" << resource << "\"," + << " duration: " << track->getDuration().total_seconds() << "," + << "};"; + oss << "LMS.mediaplayer.loadTrack(params, true)"; // true to autoplay + + LMS_LOG(UI, DEBUG) << "Runing js = '" << oss.str() << "'"; + + wApp->doJavaScript(oss.str()); } catch (Av::MediaFileException& e) { LMS_LOG(UI, ERROR) << "MediaFileException: " << e.what(); - stop(); } } void MediaPlayer::stop() { - _audio->pause(); + wApp->doJavaScript("LMS.mediaplayer.stop()"); } } // namespace UserInterface diff --git a/src/ui/MediaPlayer.hpp b/src/ui/MediaPlayer.hpp index 8b36d8eb..80d7d74d 100644 --- a/src/ui/MediaPlayer.hpp +++ b/src/ui/MediaPlayer.hpp @@ -19,15 +19,14 @@ #pragma once -#include -#include -#include +#include +#include #include "database/Types.hpp" namespace UserInterface { -class MediaPlayer : public Wt::WContainerWidget +class MediaPlayer : public Wt::WTemplate { public: MediaPlayer(Wt::WContainerWidget* parent = 0); @@ -36,12 +35,12 @@ class MediaPlayer : public Wt::WContainerWidget void playTrack(Database::Track::id_type); // Signals - Wt::Signal playbackEnded; - Wt::Signal playPrevious; - Wt::Signal playNext; + Wt::JSignal playbackEnded; + Wt::JSignal playPrevious; + Wt::JSignal playNext; private: - Wt::WAudio* _audio; + }; } // namespace UserInterface diff --git a/src/ui/resource/TranscodeResource.cpp b/src/ui/resource/TranscodeResource.cpp index 428a68d2..6d9203f9 100644 --- a/src/ui/resource/TranscodeResource.cpp +++ b/src/ui/resource/TranscodeResource.cpp @@ -41,11 +41,9 @@ TranscodeResource:: ~TranscodeResource() } std::string -TranscodeResource::getUrl(Database::Track::id_type trackId, Av::Encoding encoding, boost::posix_time::time_duration offset, boost::optional streamId) const +TranscodeResource::getUrl(Database::Track::id_type trackId, Av::Encoding encoding, boost::posix_time::time_duration offset) const { std::string res = url()+ "&trackid=" + std::to_string(trackId) + "&encoding=" + std::to_string(Av::encoding_to_int(encoding)); - if (streamId) - res += "&stream=" + std::to_string(*streamId); res += "&offset=" + std::to_string(offset.seconds()); return res; diff --git a/src/ui/resource/TranscodeResource.hpp b/src/ui/resource/TranscodeResource.hpp index a13f4e9b..51f8ecc8 100644 --- a/src/ui/resource/TranscodeResource.hpp +++ b/src/ui/resource/TranscodeResource.hpp @@ -21,8 +21,6 @@ #include -#include - #include #include "av/AvTranscoder.hpp" @@ -37,7 +35,7 @@ class TranscodeResource : public Wt::WResource TranscodeResource(Database::Handler& db, Wt::WObject *parent); ~TranscodeResource(); - std::string getUrl(Database::Track::id_type trackId, Av::Encoding encoding, boost::posix_time::time_duration offset, boost::optional stream = boost::none) const; + std::string getUrl(Database::Track::id_type trackId, Av::Encoding encoding, boost::posix_time::time_duration offset) const; void handleRequest(const Wt::Http::Request& request, Wt::Http::Response& response);