diff --git a/README.md b/README.md
index da46d7b6..7a26f16b 100644
--- a/README.md
+++ b/README.md
@@ -1,7 +1,6 @@
# LMS - Lightweight Music Server
-LMS is a self-hosted music streaming software, released under the GPLv3 license.
-It allows you to access your music using a web interface.
+LMS is a self-hosted music streaming software: access your music files from anywhere using a web interface!
A [demo](http://lms.demo.poupon.io) instance is available, with the following limitations:
- Settings cannot be saved
@@ -10,8 +9,8 @@ A [demo](http://lms.demo.poupon.io) instance is available, with the following li
## Main features
- Responsive design
- Browse your audio collection using tag-based filters
-- User management
- Persistent play queue
+- User management
- Radio mode
- MusicBrainzID support to handle duplicated artist and release names
- Audio transcode for maximum interoperability and low bandwith requirements
diff --git a/approot/messages.xml b/approot/messages.xml
index 5a606c24..cc421dab 100644
--- a/approot/messages.xml
+++ b/approot/messages.xml
@@ -79,6 +79,9 @@
Recently added
Top artists
+
+Copyright
+
Recently added
Top releases
diff --git a/approot/release.xml b/approot/release.xml
index 51b9bc9d..ea9191ec 100644
--- a/approot/release.xml
+++ b/approot/release.xml
@@ -16,6 +16,13 @@
${play-btn}${add-btn}
${tracks}
+ ${}
+
+ ${}${copyright}${}
+ ${}${copyright-url}${}
+ ${}
diff --git a/src/av/AvTranscoder.hpp b/src/av/AvTranscoder.hpp
index 40df78fe..c91ac9c5 100644
--- a/src/av/AvTranscoder.hpp
+++ b/src/av/AvTranscoder.hpp
@@ -48,9 +48,9 @@ struct TranscodeParameters
Encoding encoding = Encoding::MP3;
std::size_t bitrate = 128000;
boost::optional stream = boost::none; // Id of the stream to be transcoded (auto detect by default)
- boost::optional offset;
+ boost::optional offset = boost::none;;
- TranscodeParameters() {}
+ TranscodeParameters() = default;
};
class Transcoder
diff --git a/src/cover/CoverArtGrabber.cpp b/src/cover/CoverArtGrabber.cpp
index ce688492..4936a406 100644
--- a/src/cover/CoverArtGrabber.cpp
+++ b/src/cover/CoverArtGrabber.cpp
@@ -178,12 +178,12 @@ Grabber::getFromTrack(Wt::Dbo::Session& session, Database::IdType trackId, std::
Track::pointer track = Track::getById(session, trackId);
if (track)
{
- Track::CoverType coverType = track->getCoverType();
+ bool hasCover = track->hasCover();
boost::filesystem::path trackPath = track->getPath();
transaction.commit();
- if (coverType == Track::CoverType::Embedded)
+ if (hasCover)
cover = getFromTrack(trackPath);
if (!cover)
diff --git a/src/database/Artist.cpp b/src/database/Artist.cpp
index 194b8581..ccff0b47 100644
--- a/src/database/Artist.cpp
+++ b/src/database/Artist.cpp
@@ -65,7 +65,7 @@ Artist::create(Wt::Dbo::Session& session, const std::string& name, const std::st
std::vector
Artist::getAll(Wt::Dbo::Session& session, int offset, int size)
{
- Wt::Dbo::collection res = session.find().orderBy("LOWER(name)").offset(offset).limit(size);
+ Wt::Dbo::collection res = session.find().offset(offset).limit(size);
return std::vector(res.begin(), res.end());
}
@@ -107,7 +107,7 @@ getQuery(Wt::Dbo::Session& session,
if (!clusterIds.empty())
oss << " GROUP BY t.id HAVING COUNT(*) = " << clusterIds.size();
- oss << " ORDER BY a.name";
+ oss << " ORDER BY a.name COLLATE NOCASE";
Wt::Dbo::Query query = session.query( oss.str() );
diff --git a/src/database/Release.cpp b/src/database/Release.cpp
index 7cabd1d8..6f97e3a3 100644
--- a/src/database/Release.cpp
+++ b/src/database/Release.cpp
@@ -19,6 +19,8 @@
#include "Release.hpp"
+#include "utils/Logger.hpp"
+
#include "Artist.hpp"
#include "Cluster.hpp"
#include "SqlQuery.hpp"
@@ -117,7 +119,7 @@ getQuery(Wt::Dbo::Session& session,
if (!clusterIds.empty())
oss << " GROUP BY t.id HAVING COUNT(*) = " << clusterIds.size();
- oss << " ORDER BY r.name";
+ oss << " ORDER BY r.name COLLATE NOCASE";
Wt::Dbo::Query query = session.query( oss.str() );
@@ -163,7 +165,7 @@ Release::getReleaseYear(bool original) const
.groupBy(field)
.bind(this->id());
- /* various dates, no date */
+ // various dates => no date
if (dates.empty() || dates.size() > 1)
return boost::none;
@@ -175,6 +177,46 @@ Release::getReleaseYear(bool original) const
return boost::none;
}
+boost::optional
+Release::getCopyright() const
+{
+ assert(session());
+
+ Wt::Dbo::collection copyrights = session()->query
+ ("SELECT copyright FROM track t INNER JOIN release r ON r.id = t.release_id")
+ .where("r.id = ?")
+ .groupBy("copyright")
+ .bind(this->id());
+
+ std::vector values(copyrights.begin(), copyrights.end());
+
+ // various copyrights => no copyright
+ if (values.empty() || values.size() > 1 || values.front().empty())
+ return boost::none;
+
+ return values.front();
+}
+
+boost::optional
+Release::getCopyrightURL() const
+{
+ assert(session());
+
+ Wt::Dbo::collection copyrights = session()->query
+ ("SELECT copyright_url FROM track t INNER JOIN release r ON r.id = t.release_id")
+ .where("r.id = ?")
+ .groupBy("copyright_url")
+ .bind(this->id());
+
+ std::vector values(copyrights.begin(), copyrights.end());
+
+ // various copyright URLs => no copyright URL
+ if (values.empty() || values.size() > 1 || values.front().empty())
+ return boost::none;
+
+ return values.front();
+}
+
std::vector>
Release::getArtists() const
{
diff --git a/src/database/Release.hpp b/src/database/Release.hpp
index 1122314a..86584919 100644
--- a/src/database/Release.hpp
+++ b/src/database/Release.hpp
@@ -69,6 +69,8 @@ class Release : public Wt::Dbo::Dbo
// Utility functions
boost::optional getReleaseYear(bool originalDate = false) const; // 0 if unknown or various
+ boost::optional getCopyright() const;
+ boost::optional getCopyrightURL() const;
// Accessors
std::string getName() const { return _name; }
diff --git a/src/database/Track.cpp b/src/database/Track.cpp
index d7535afe..aa95619e 100644
--- a/src/database/Track.cpp
+++ b/src/database/Track.cpp
@@ -146,7 +146,7 @@ getQuery(Wt::Dbo::Session& session,
if (!clusterIds.empty())
oss << " GROUP BY t.id HAVING COUNT(*) = " << clusterIds.size();
- oss << " ORDER BY t.name";
+ oss << " ORDER BY t.name COLLATE NOCASE";
Wt::Dbo::Query query = session.query( oss.str() );
@@ -224,6 +224,18 @@ Track::getOriginalYear() const
return (_originalYear > 0) ? boost::make_optional(_originalYear) : boost::none;
}
+boost::optional
+Track::getCopyright() const
+{
+ return _copyright != "" ? boost::make_optional(_copyright) : boost::none;
+}
+
+boost::optional
+Track::getCopyrightURL() const
+{
+ return _copyrightURL != "" ? boost::make_optional(_copyrightURL) : boost::none;
+}
+
std::vector>
Track::getClusterGroups(std::vector clusterTypes, std::size_t size) const
{
diff --git a/src/database/Track.hpp b/src/database/Track.hpp
index 334ce2d9..e16b54d3 100644
--- a/src/database/Track.hpp
+++ b/src/database/Track.hpp
@@ -49,12 +49,6 @@ class Track : public Wt::Dbo::Dbo