Handle the original date of the songs

This commit is contained in:
emeric
2014-10-11 17:37:02 +02:00
parent 5b67519966
commit 92891ea070
8 changed files with 99 additions and 56 deletions
-2
View File
@@ -43,11 +43,9 @@
- Search patterns in the genre list
- ReleaseView/ArtistView/GenreView: <All> -> Track count for this special category. Easier: add a special entry '<All>' that contains everything?
- MediaPlayer: move slider using js (http://redmine.webtoolkit.eu/boards/2/topics/7924?r=8478)
- TrackView : handle original release date
- TrackView : handle duration > 1 hour
- TrackView : select only relevant columns to speed up queries (do not fetch eveything)
- TrackView : Reselect the current selected item when displaying the updated search results
- ReleaseView: display the original release's publication year
- OGG metadata -> properly handle metadata nested in the audio stream
- Filters: use directly the id as constraint, instead of the name?
- Implement a playlist:
+34 -25
View File
@@ -283,8 +283,8 @@ Updater::processAudioFile( const boost::filesystem::path& file, Stats& stats)
// We estimate this is a audio file if:
// - we found a least one audio stream
// - the duration is not null
if (items.find(MetaData::AudioStreams) == items.end()
|| boost::any_cast<std::vector<MetaData::AudioStream> >(items[MetaData::AudioStreams]).empty())
if (items.find(MetaData::Type::AudioStreams) == items.end()
|| boost::any_cast<std::vector<MetaData::AudioStream> >(items[MetaData::Type::AudioStreams]).empty())
{
LMS_LOG(MOD_DBUPDATER, SEV_DEBUG) << "Skipped '" << file << "' (no audio stream found)";
@@ -295,8 +295,8 @@ Updater::processAudioFile( const boost::filesystem::path& file, Stats& stats)
}
return;
}
if (items.find(MetaData::Duration) == items.end()
|| boost::any_cast<boost::posix_time::time_duration>(items[MetaData::Duration]).total_seconds() == 0)
if (items.find(MetaData::Type::Duration) == items.end()
|| boost::any_cast<boost::posix_time::time_duration>(items[MetaData::Type::Duration]).total_seconds() == 0)
{
LMS_LOG(MOD_DBUPDATER, SEV_DEBUG) << "Skipped '" << file << "' (no duration or duration 0)";
@@ -310,8 +310,8 @@ Updater::processAudioFile( const boost::filesystem::path& file, Stats& stats)
// ***** Title
std::string title;
if (items.find(MetaData::Title) != items.end()) {
title = boost::any_cast<std::string>(items[MetaData::Title]);
if (items.find(MetaData::Type::Title) != items.end()) {
title = boost::any_cast<std::string>(items[MetaData::Type::Title]);
}
else
{
@@ -322,9 +322,9 @@ Updater::processAudioFile( const boost::filesystem::path& file, Stats& stats)
// ***** Artist
Wt::Dbo::ptr<Artist> artist;
if (items.find(MetaData::Artist) != items.end())
if (items.find(MetaData::Type::Artist) != items.end())
{
const std::string artistName (boost::any_cast<std::string>(items[MetaData::Artist]));
const std::string artistName (boost::any_cast<std::string>(items[MetaData::Type::Artist]));
artist = Artist::getByName(_db.getSession(), artistName );
if (!artist)
artist = Artist::create( _db.getSession(), artistName );
@@ -337,9 +337,9 @@ Updater::processAudioFile( const boost::filesystem::path& file, Stats& stats)
// ***** Release
Wt::Dbo::ptr<Release> release;
if (items.find(MetaData::Album) != items.end())
if (items.find(MetaData::Type::Album) != items.end())
{
const std::string albumName (boost::any_cast<std::string>(items[MetaData::Album]));
const std::string albumName (boost::any_cast<std::string>(items[MetaData::Type::Album]));
release = Release::getByName(_db.getSession(), albumName);
if (!release)
release = Release::create( _db.getSession(), albumName );
@@ -354,9 +354,9 @@ Updater::processAudioFile( const boost::filesystem::path& file, Stats& stats)
typedef std::list<std::string> GenreList;
GenreList genreList;
std::vector< Genre::pointer > genres;
if (items.find(MetaData::Genres) != items.end())
if (items.find(MetaData::Type::Genres) != items.end())
{
genreList = (boost::any_cast<GenreList>(items[MetaData::Genres]));
genreList = (boost::any_cast<GenreList>(items[MetaData::Type::Genres]));
BOOST_FOREACH(const std::string& genre, genreList) {
Genre::pointer dbGenre ( Genre::getByName(_db.getSession(), genre) );
@@ -406,17 +406,26 @@ Updater::processAudioFile( const boost::filesystem::path& file, Stats& stats)
track.modify()->setArtist( artist );
track.modify()->setRelease( release );
if (items.find(MetaData::TrackNumber) != items.end())
track.modify()->setTrackNumber( boost::any_cast<std::size_t>(items[MetaData::TrackNumber]) );
if (items.find(MetaData::Type::TrackNumber) != items.end())
track.modify()->setTrackNumber( boost::any_cast<std::size_t>(items[MetaData::Type::TrackNumber]) );
if (items.find(MetaData::DiscNumber) != items.end())
track.modify()->setDiscNumber( boost::any_cast<std::size_t>(items[MetaData::DiscNumber]) );
if (items.find(MetaData::Type::DiscNumber) != items.end())
track.modify()->setDiscNumber( boost::any_cast<std::size_t>(items[MetaData::Type::DiscNumber]) );
if (items.find(MetaData::Duration) != items.end())
track.modify()->setDuration( boost::any_cast<boost::posix_time::time_duration>(items[MetaData::Duration]) );
if (items.find(MetaData::Type::Duration) != items.end())
track.modify()->setDuration( boost::any_cast<boost::posix_time::time_duration>(items[MetaData::Type::Duration]) );
if (items.find(MetaData::CreationTime) != items.end())
track.modify()->setCreationTime( boost::any_cast<boost::posix_time::ptime>(items[MetaData::CreationTime]) );
if (items.find(MetaData::Type::Date) != items.end())
track.modify()->setDate( boost::any_cast<boost::posix_time::ptime>(items[MetaData::Type::Date]) );
if (items.find(MetaData::Type::OriginalDate) != items.end())
{
track.modify()->setOriginalDate( boost::any_cast<boost::posix_time::ptime>(items[MetaData::Type::OriginalDate]) );
// If a file has an OriginalDate but no date, set the date to ease filtering
if (items.find(MetaData::Type::Date) == items.end())
track.modify()->setDate( boost::any_cast<boost::posix_time::ptime>(items[MetaData::Type::OriginalDate]) );
}
transaction.commit();
@@ -616,8 +625,8 @@ Updater::processVideoFile( const boost::filesystem::path& file, Stats& stats)
// We estimate this is a video if:
// - we found a least one video stream
// - the duration is not null
if (items.find(MetaData::VideoStreams) == items.end()
|| boost::any_cast<std::vector<MetaData::VideoStream> >(items[MetaData::VideoStreams]).empty())
if (items.find(MetaData::Type::VideoStreams) == items.end()
|| boost::any_cast<std::vector<MetaData::VideoStream> >(items[MetaData::Type::VideoStreams]).empty())
{
LMS_LOG(MOD_DBUPDATER, SEV_ERROR) << "Skipped '" << file << "' (no video stream found)";
@@ -628,8 +637,8 @@ Updater::processVideoFile( const boost::filesystem::path& file, Stats& stats)
}
return;
}
if (items.find(MetaData::Duration) == items.end()
|| boost::any_cast<boost::posix_time::time_duration>(items[MetaData::Duration]).total_seconds() == 0)
if (items.find(MetaData::Type::Duration) == items.end()
|| boost::any_cast<boost::posix_time::time_duration>(items[MetaData::Type::Duration]).total_seconds() == 0)
{
LMS_LOG(MOD_DBUPDATER, SEV_ERROR) << "Skipped '" << file << "' (no duration or duration 0)";
@@ -659,7 +668,7 @@ Updater::processVideoFile( const boost::filesystem::path& file, Stats& stats)
assert(video);
video.modify()->setName( file.filename().string() );
video.modify()->setDuration( boost::any_cast<boost::posix_time::time_duration>(items[MetaData::Duration]) );
video.modify()->setDuration( boost::any_cast<boost::posix_time::time_duration>(items[MetaData::Type::Duration]) );
video.modify()->setLastWriteTime(lastWriteTime);
transaction.commit();
+8 -4
View File
@@ -196,7 +196,8 @@ class Track
void setDuration(boost::posix_time::time_duration duration) { _duration = duration; }
void setLastWriteTime(boost::posix_time::ptime time) { _fileLastWrite = time; }
void setChecksum(const std::vector<unsigned char>& checksum) { _fileChecksum = checksum; }
void setCreationTime(const boost::posix_time::ptime& time) { _creationTime = time; }
void setDate(const boost::posix_time::ptime& date) { _date = date; }
void setOriginalDate(const boost::posix_time::ptime& date) { _originalDate = date; }
void setGenres(const std::string& genreList) { _genreList = genreList; }
void setGenres(std::vector<Genre::pointer> genres);
void setArtist(Artist::pointer artist) { _artist = artist; }
@@ -207,7 +208,8 @@ class Track
std::string getName(void) const { return _name; }
const std::string& getPath(void) const { return _filePath; }
boost::posix_time::time_duration getDuration(void) const { return _duration; }
boost::posix_time::ptime getCreationTime(void) const { return _creationTime; }
boost::posix_time::ptime getDate(void) const { return _date; }
boost::posix_time::ptime getOriginalDate(void) const { return _originalDate; }
Artist::pointer getArtist(void) const { return _artist; }
Release::pointer getRelease(void) const { return _release; }
bool hasGenre(Genre::pointer genre) const { return _genres.count(genre); }
@@ -223,7 +225,8 @@ class Track
Wt::Dbo::field(a, _discNumber, "disc_number");
Wt::Dbo::field(a, _name, "name");
Wt::Dbo::field(a, _duration, "duration");
Wt::Dbo::field(a, _creationTime, "creation_time");
Wt::Dbo::field(a, _date, "date");
Wt::Dbo::field(a, _originalDate, "original_date");
Wt::Dbo::field(a, _genreList, "genre_list");
Wt::Dbo::field(a, _filePath, "path");
Wt::Dbo::field(a, _fileLastWrite, "last_write");
@@ -241,7 +244,8 @@ class Track
int _discNumber;
std::string _name;
boost::posix_time::time_duration _duration;
boost::posix_time::ptime _creationTime;
boost::posix_time::ptime _date;
boost::posix_time::ptime _originalDate;
std::string _genreList;
std::string _filePath;
std::vector<unsigned char> _fileChecksum;
+19 -15
View File
@@ -103,16 +103,16 @@ AvFormat::parse(const boost::filesystem::path& p, Items& items)
}
if (!videoStreams.empty())
items.insert( std::make_pair(MetaData::VideoStreams, videoStreams));
items.insert( std::make_pair(MetaData::Type::VideoStreams, videoStreams));
if (!audioStreams.empty())
items.insert( std::make_pair(MetaData::AudioStreams, audioStreams));
items.insert( std::make_pair(MetaData::Type::AudioStreams, audioStreams));
if (!subtitleStreams.empty())
items.insert( std::make_pair(MetaData::SubtitleStreams, SubtitleStreams));
items.insert( std::make_pair(MetaData::Type::SubtitleStreams, subtitleStreams));
}
// Duration
items.insert( std::make_pair(MetaData::Duration, boost::posix_time::time_duration( boost::posix_time::seconds( input.getDurationSecs() )) ));
items.insert( std::make_pair(MetaData::Type::Duration, boost::posix_time::time_duration( boost::posix_time::seconds( input.getDurationSecs() )) ));
// Embedded MetaData
// Make sure to convert strings into UTF-8
@@ -120,38 +120,42 @@ AvFormat::parse(const boost::filesystem::path& p, Items& items)
for (it = metadata.begin(); it != metadata.end(); ++it)
{
if (boost::iequals(it->first, "artist"))
items.insert( std::make_pair(MetaData::Artist, string_trim( string_to_utf8(it->second)) ));
items.insert( std::make_pair(MetaData::Type::Artist, string_trim( string_to_utf8(it->second)) ));
else if (boost::iequals(it->first, "album"))
items.insert( std::make_pair(MetaData::Album, string_trim( string_to_utf8(it->second)) ));
items.insert( std::make_pair(MetaData::Type::Album, string_trim( string_to_utf8(it->second)) ));
else if (boost::iequals(it->first, "title"))
items.insert( std::make_pair(MetaData::Title, string_trim( string_to_utf8(it->second)) ));
items.insert( std::make_pair(MetaData::Type::Title, string_trim( string_to_utf8(it->second)) ));
else if (boost::iequals(it->first, "track")) {
std::size_t number;
if (readAs<std::size_t>(it->second, number))
items.insert( std::make_pair(MetaData::TrackNumber, number ));
items.insert( std::make_pair(MetaData::Type::TrackNumber, number ));
}
else if (boost::iequals(it->first, "disc"))
{
std::size_t number;
if (readAs<std::size_t>(it->second, number))
items.insert( std::make_pair(MetaData::DiscNumber, number ));
items.insert( std::make_pair(MetaData::Type::DiscNumber, number ));
}
else if (boost::iequals(it->first, "date")
|| boost::iequals(it->first, "year")
|| boost::iequals(it->first, "WM/Year")
|| boost::iequals(it->first, "TDOR") // Original date fallback
|| boost::iequals(it->first, "TORY") // Original date fallback
)
|| boost::iequals(it->first, "WM/Year"))
{
boost::posix_time::ptime p;
if (readAsPosixTime(it->second, p))
items.insert( std::make_pair(MetaData::CreationTime, p));
items.insert( std::make_pair(MetaData::Type::Date, p));
}
else if (boost::iequals(it->first, "TDOR") // Original release time (ID3v2 2.4)
|| boost::iequals(it->first, "TORY")) // Original release year
{
boost::posix_time::ptime p;
if (readAsPosixTime(it->second, p))
items.insert( std::make_pair(MetaData::Type::OriginalDate, p));
}
else if (boost::iequals(it->first, "genre"))
{
std::list<std::string> genres;
if (readList(it->second, ";,", genres))
items.insert( std::make_pair(MetaData::Genres, genres));
items.insert( std::make_pair(MetaData::Type::Genres, genres));
}
/* else
+3 -2
View File
@@ -28,7 +28,7 @@
namespace MetaData
{
enum Type
enum class Type
{
Artist, // string
Title, // string
@@ -37,7 +37,8 @@ namespace MetaData
Duration, // boost::posix_time::time_duration
TrackNumber, // size_t
DiscNumber, // size_t
CreationTime, // boost::posix_time::ptime
Date, // boost::posix_time::ptime
OriginalDate, // boost::posix_time::ptime
Cover, // GenericData
AudioStreams, // vector<AudioStream>
VideoStreams, // vector<VideoStream>
@@ -284,8 +284,12 @@ AudioCollectionRequestHandler::processGetTracks(const AudioCollectionRequest::Ge
track->set_name( std::string( boost::locale::conv::to_utf<char>((*it)->getName(), "UTF-8") ) );
track->set_duration_secs( (*it)->getDuration().total_seconds() );
// if (!(*it)->getCreationTime().is_special())
// track->set_release_date( boost::posix_time::to_simple_string((*it)->getCreationTime()) );
// Only send the year part of the release times
if (!(*it)->getDate().is_special())
track->set_release_date( std::to_string((*it)->getDate().date().year()) );
if (!(*it)->getOriginalDate().is_special())
track->set_original_release_date( std::to_string((*it)->getOriginalDate().date().year()) );
BOOST_FOREACH(Database::Genre::pointer genre, (*it)->getGenres())
track->add_genre_id( genre.id() );
+14 -5
View File
@@ -44,7 +44,8 @@ _trackStats(nullptr)
_queryModel.addColumn( "track.track_number", "Track #" );
_queryModel.addColumn( "track.name", "Track" );
_queryModel.addColumn( "track.duration", "Duration" );
_queryModel.addColumn( "track.creation_time", "Date" );
_queryModel.addColumn( "track.date", "Date" );
_queryModel.addColumn( "track.original_date", "Original Date" );
_queryModel.addColumn( "track.genre_list", "Genres" );
_queryModel.setBatchSize(1000);
@@ -57,16 +58,24 @@ _trackStats(nullptr)
_tableView->setAlternatingRowColors(true);
_tableView->setModel(&_queryModel);
// Duration display
{
// TODO better handle 1 hour+ files!
Wt::WItemDelegate *delegate = new Wt::WItemDelegate(this);
delegate->setTextFormat("mm:ss");
_tableView->setItemDelegateForColumn(5, delegate);
}
// Date display, just the year
{
Wt::WItemDelegate *delegate = new Wt::WItemDelegate(this);
delegate->setTextFormat("yyyy");
_tableView->setItemDelegateForColumn(6, delegate);
}
{
// TODO better handle 1 hour+ files!
Wt::WItemDelegate *delegate = new Wt::WItemDelegate(this);
delegate->setTextFormat("mm:ss");
_tableView->setItemDelegateForColumn(5, delegate);
delegate->setTextFormat("yyyy");
_tableView->setItemDelegateForColumn(7, delegate);
}
// TODO other event!
@@ -101,7 +110,7 @@ TrackWidget::refresh(const Constraint& constraint)
Wt::Dbo::Query<ResultType> query = _db.getSession().query<ResultType>( sqlQuery.get() );
query.groupBy("track").orderBy("artist.name,track.creation_time,release.name,track.disc_number,track.track_number");
query.groupBy("track").orderBy("artist.name,track.date,release.name,track.disc_number,track.track_number");
BOOST_FOREACH(const std::string& bindArg, sqlQuery.where().getBindArgs()) {
LMS_LOG(MOD_UI, SEV_DEBUG) << "Binding value '" << bindArg << "'";
+15 -1
View File
@@ -83,12 +83,20 @@ struct TrackInfo
boost::posix_time::time_duration duration;
std::string date;
std::string original_date;
TrackInfo(): id(0), release_id(0), artist_id(0), disc_number(0), track_number(0) {}
};
std::ostream& operator<<(std::ostream& os, const TrackInfo& info)
{
os << "id = " << info.id << ", name = '" << info.name << "', track_number = " << info.track_number << ", duration = " << info.duration;
if (!info.date.empty())
os << ", date = " << info.date;
if (!info.original_date.empty())
os << ", original date = " << info.original_date;
return os;
}
@@ -352,6 +360,12 @@ class TestClient
if (response.audio_collection_response().track_list().tracks(i).has_disc_number())
track.disc_number = response.audio_collection_response().track_list().tracks(i).disc_number();
if (response.audio_collection_response().track_list().tracks(i).has_release_date())
track.date = response.audio_collection_response().track_list().tracks(i).release_date();
if (response.audio_collection_response().track_list().tracks(i).has_original_release_date())
track.original_date = response.audio_collection_response().track_list().tracks(i).original_release_date();
tracks.push_back( track );
nbAdded++;
@@ -756,7 +770,7 @@ int main()
TestClient client( boost::asio::ip::tcp::endpoint( boost::asio::ip::address_v4::loopback(), 5080));
// Use a dumb account in order to login TODO parametrize
if (!client.login("admin", "admin"))
if (!client.login("admin", "toto"))
throw std::runtime_error("login failed!");
// **** REVISION ***