-
-
+ ${}
+
+
- ${}
-
-
diff --git a/docroot/js/mediaplayer.js b/docroot/js/mediaplayer.js
index 6135c86a..c5ebcb3f 100644
--- a/docroot/js/mediaplayer.js
+++ b/docroot/js/mediaplayer.js
@@ -22,10 +22,10 @@ LMS.mediaplayer = function () {
var _offset = 0;
var _duration = 0;
var _audioNativeSrc;
- var _audioTranscodedSrc;
- var _transcodeMode = TranscodeMode.Never;
- var _transcodeFormat = 0;
- var _transcodeBitrate = 0;
+ var _audioTranscodeSrc;
+ var _settings = {};
+ var audioCtx = new (window.AudioContext || window.webkitAudioContext)();
+ var _gainNode = audioCtx.createGain();
var _updateControls = function() {
if (_elems.audio.paused) {
@@ -81,27 +81,15 @@ LMS.mediaplayer = function () {
_setVolume(_elems.volumeslider.value);
}
- var _initTranscodeSettings = function(defaultTranscodeMode, defaultTranscodeFormat, defaultTranscodeBitrate) {
- if (typeof(Storage) !== "undefined" && localStorage.transcodeMode) {
- _transcodeMode = Number(localStorage.transcodeMode);
+ var _initDefaultSettings = function(defaultSettings) {
+ if (typeof(Storage) !== "undefined" && localStorage.settings) {
+ _settings = Object.assign(defaultSettings, JSON.parse(localStorage.settings));
}
else {
- _transcodeMode = defaultTranscodeMode;
- }
- if (typeof(Storage) !== "undefined" && localStorage.transcodeFormat) {
- _transcodeFormat = Number(localStorage.transcodeFormat);
- }
- else {
- _transcodeFormat = defaultTranscodeFormat;
- }
- if (typeof(Storage) !== "undefined" && localStorage.transcodeBitrate) {
- _transcodeBitrate = Number(localStorage.transcodeBitrate);
- }
- else {
- _transcodeBitrate = defaultTranscodeBitrate;
+ _settings = defaultSettings;
}
- Wt.emit(_root, "settingsLoaded", _transcodeMode, _transcodeFormat, _transcodeBitrate);
+ Wt.emit(_root, "settingsLoaded", JSON.stringify(_settings));
}
var _setVolume = function(volume) {
@@ -132,7 +120,12 @@ LMS.mediaplayer = function () {
}
}
- var init = function(root, defaultTranscodeMode, defaultTranscodeFormat, defaultTranscodeBitrate) {
+ var _setReplayGain = function (replayGain) {
+ console.log("Applying gain " + replayGain);
+ _gainNode.gain.value = Math.pow(10, (_settings.replayGain.preAmpGain + replayGain) / 20);
+ }
+
+ var init = function(root, defaultSettings) {
_root = root;
_elems.audio = document.getElementById("lms-mp-audio");
@@ -146,6 +139,10 @@ LMS.mediaplayer = function () {
_elems.volume = document.getElementById("lms-mp-volume");
_elems.volumeslider = document.getElementById("lms-mp-volume-slider");
+ var source = audioCtx.createMediaElementSource(_elems.audio);
+ source.connect(_gainNode);
+ _gainNode.connect(audioCtx.destination);
+
_elems.playpause.addEventListener("click", function() {
if (_elems.audio.paused) {
if (_elems.audio.firstChild)
@@ -199,7 +196,7 @@ LMS.mediaplayer = function () {
});
_initVolume();
- _initTranscodeSettings(defaultTranscodeMode, defaultTranscodeFormat, defaultTranscodeBitrate);
+ _initDefaultSettings(defaultSettings);
_elems.volumeslider.addEventListener("input", function() {
_setVolume(_elems.volumeslider.value);
@@ -251,23 +248,24 @@ LMS.mediaplayer = function () {
var loadTrack = function(params, autoplay) {
_offset = 0;
_duration = params.duration;
- _audioNativeSrc = params.native_resource;
- _audioTranscodeSrc = params.transcode_resource + "&bitrate=" + _transcodeBitrate + "&format=" + _transcodeFormat;
+ _audioNativeSrc = params.nativeResource;
+ _audioTranscodeSrc = params.transcodeResource + "&bitrate=" + _settings.transcode.bitrate + "&format=" + _settings.transcode.format;
_elems.seek.max = _duration;
_removeAudioSources();
// ! order is important
- if (_transcodeMode == TranscodeMode.Never || _transcodeMode == TranscodeMode.IfFormatNotSupported)
+ if (_settings.transcode.mode == TranscodeMode.Never || _settings.transcode.mode == TranscodeMode.IfFormatNotSupported)
{
_addAudioSource(_audioNativeSrc);
}
- if (_transcodeMode == TranscodeMode.Always || _transcodeMode == TranscodeMode.IfFormatNotSupported)
+ if (_settings.transcode.mode == TranscodeMode.Always || _settings.transcode.mode == TranscodeMode.IfFormatNotSupported)
{
_addAudioSource(_audioTranscodeSrc);
}
_elems.audio.load();
+ _setReplayGain(params.replayGain);
_elems.curtime.innerHTML = _durationToString(_offset);
_elems.duration.innerHTML = _durationToString(_duration);
@@ -289,15 +287,11 @@ LMS.mediaplayer = function () {
_elems.audio.pause();
}
- var setSettings = function(transcodeMode, transcodeFormat, transcodeBitrate) {
- _transcodeMode = transcodeMode;
- _transcodeFormat = transcodeFormat;
- _transcodeBitrate = transcodeBitrate;
+ var setSettings = function(settings) {
+ _settings = settings;
if (typeof(Storage) !== "undefined") {
- localStorage.transcodeMode = _transcodeMode;
- localStorage.transcodeFormat = _transcodeFormat;
- localStorage.transcodeBitrate = _transcodeBitrate;
+ localStorage.settings = JSON.stringify(_settings);
}
}
diff --git a/src/libs/database/impl/Session.cpp b/src/libs/database/impl/Session.cpp
index 22a7b250..2e96ffd1 100644
--- a/src/libs/database/impl/Session.cpp
+++ b/src/libs/database/impl/Session.cpp
@@ -40,7 +40,7 @@
namespace Database {
-#define LMS_DATABASE_VERSION 21
+#define LMS_DATABASE_VERSION 22
using Version = std::size_t;
@@ -246,6 +246,14 @@ CREATE TABLE "user_backup" (
{
_session.execute("DROP TABLE subsonic_settings");
}
+ else if (version == 21)
+ {
+ _session.execute("ALTER TABLE track ADD track_replay_gain REAL");
+ _session.execute("ALTER TABLE track ADD release_replay_gain REAL");
+
+ // Just increment the scan version of the settings to make the next scheduled scan rescan everything
+ ScanSettings::get(*this).modify()->incScanVersion();
+ }
else
{
LMS_LOG(DB, ERROR) << "Database version " << version << " cannot be handled using migration";
diff --git a/src/libs/database/impl/Track.cpp b/src/libs/database/impl/Track.cpp
index e62f875f..f0deedab 100644
--- a/src/libs/database/impl/Track.cpp
+++ b/src/libs/database/impl/Track.cpp
@@ -38,6 +38,14 @@ _filePath( p.string() )
{
}
+std::size_t
+Track::getCount(Session& session)
+{
+ session.checkSharedLocked();
+
+ return session.getDboSession().query
("SELECT COUNT(*) FROM track");
+}
+
std::vector
Track::getAll(Session& session, std::optional limit)
{
@@ -107,13 +115,26 @@ Track::create(Session& session, const std::filesystem::path& p)
return res;
}
-std::vector
-Track::getAllPaths(Session& session)
+std::vector>
+Track::getAllPaths(Session& session, std::optional offset, std::optional size)
{
+ using QueryResultType = std::tuple;
session.checkSharedLocked();
- Wt::Dbo::collection res = session.getDboSession().query("SELECT file_path FROM track");
- return std::vector(res.begin(), res.end());
+ Wt::Dbo::collection queryRes = session.getDboSession().query("SELECT id,file_path FROM track")
+ .limit(size ? static_cast(*size) + 1 : -1)
+ .offset(offset ? static_cast(*offset) : -1);
+
+ std::vector> result;
+ result.reserve(queryRes.size());
+
+ std::transform(std::begin(queryRes), std::end(queryRes), std::back_inserter(result),
+ [](const QueryResultType& queryResult)
+ {
+ return std::make_pair(std::get<0>(queryResult), std::get<1>(queryResult));
+ });
+
+ return result;
}
std::vector
diff --git a/src/libs/database/include/database/Track.hpp b/src/libs/database/include/database/Track.hpp
index 2bbeb9ee..9dbd4083 100644
--- a/src/libs/database/include/database/Track.hpp
+++ b/src/libs/database/include/database/Track.hpp
@@ -55,6 +55,7 @@ class Track : public Wt::Dbo::Dbo