diff --git a/Makefile.am b/Makefile.am index 5e13197f..15ac8af4 100644 --- a/Makefile.am +++ b/Makefile.am @@ -1,7 +1,7 @@ AUTOMAKE_OPTIONS = dist-bzip2 no-dist-gzip -SUBDIRS = test src +SUBDIRS = test tools src lms_docrootdir=$(pkgdatadir)/docroot lms_approotdir=$(pkgdatadir)/approot diff --git a/configure.ac b/configure.ac index a5074afe..1e00f7e1 100644 --- a/configure.ac +++ b/configure.ac @@ -78,7 +78,9 @@ AC_CHECK_LIB( [config++], AC_CONFIG_FILES([Makefile src/Makefile - test/Makefile]) + test/Makefile + tools/Makefile + tools/metadata/Makefile]) AC_OUTPUT diff --git a/src/Makefile.am b/src/Makefile.am index 20275a2c..b049316e 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -44,6 +44,6 @@ lms_SOURCES = \ $(srcdir)/utils/Path.cpp \ $(srcdir)/utils/Utils.cpp -lms_CXXFLAGS=-std=c++14 -Wall -I$(srcdir)/third-party -I$(srcdir)/ui $(MAGICKXX_CFLAGS) -D_REENTRANT +lms_CXXFLAGS=-std=c++14 -Wall -I$(srcdir)/ui $(MAGICKXX_CFLAGS) -D_REENTRANT lms_LDADD=$(MAGICKXX_LIBS) diff --git a/test/CheckDatabaseUser.cpp b/test/CheckDatabaseUser.cpp deleted file mode 100644 index 1c5a0ad3..00000000 --- a/test/CheckDatabaseUser.cpp +++ /dev/null @@ -1,64 +0,0 @@ -/* - * Copyright (C) 2013 Emeric Poupon - * - * This file is part of LMS. - * - * LMS is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * LMS is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with LMS. If not, see . - */ - -#include "database/DatabaseHandler.hpp" -#include - -int main(void) -{ - try - { - boost::filesystem::remove("test_user.db"); - - // Set up the database session - Database::Handler::configureAuth(); - - std::unique_ptr connectionPool( Database::Handler::createConnectionPool("test_user.db")); - - Database::Handler db(*connectionPool); - - Wt::Dbo::Transaction transaction(db.getSession()); - - Wt::Auth::Identity identity; - Wt::Auth::User user = db.getUserDatabase().registerNew(); - std::cout << "User is valid = " << std::boolalpha << user.isValid() << std::endl; - - user.setIdentity(identity.provider(), "toto"); - - std::cout << "User is valid = " << std::boolalpha << user.isValid() << std::endl; - - std::cout << "Updating password" << std::endl; - db.getPasswordService().updatePassword(user, "This is my password"); - -// db.getSession().add( user ); - - std::cout << "Committing" << std::endl; - - transaction.commit(); - - } - catch(std::exception& e) - { - std::cerr << "Caught exception " << e.what() << std::endl; - return EXIT_FAILURE; - } - - return EXIT_SUCCESS; -} - diff --git a/test/CheckDbBasics.cpp b/test/CheckDbBasics.cpp deleted file mode 100644 index 716873a8..00000000 --- a/test/CheckDbBasics.cpp +++ /dev/null @@ -1,233 +0,0 @@ -/* - * Copyright (C) 2015 Emeric Poupon - * - * This file is part of LMS. - * - * LMS is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * LMS is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with LMS. If not, see . - */ - -#include "database/DatabaseHandler.hpp" - -static const std::string trackMBID = "123e4567-e89b-12d3-a456-426655440000"; -static const std::string artistMBID = "xxxxxxxx-xxxx-Mxxx-Nxxx-xxxxxxxxxxxx"; -static const std::string releaseMBID = "xxxxxxxx-xxxx-9877-Nxxx-xxxxxxxxxxxx"; - -int main(void) -{ - try - { - using namespace Database; - - boost::filesystem::remove("test.db"); - - std::unique_ptr connectionPool(Database::Handler::createConnectionPool( "test.db")); - - Handler db( *connectionPool ); - - // Create - { - Wt::Dbo::Transaction transaction(db.getSession()); - - Track::pointer track = Track::create(db.getSession(), "test.mp2"); - - track.modify()->setName("track01"); - track.modify()->setMBID(trackMBID); - - Artist::pointer artist = Artist::create(db.getSession(), "artist01", artistMBID); - Release::pointer release = Release::create(db.getSession(), "release01", releaseMBID); - Genre::pointer genre = Genre::create(db.getSession(), "genre01"); - - track.modify()->setArtist(artist); - track.modify()->setRelease(release); - track.modify()->setGenres( std::vector({ genre })); - } - - // Search - { - Wt::Dbo::Transaction transaction(db.getSession()); - - Track::pointer track = Track::getByMBID(db.getSession(), trackMBID); - assert(track); - assert(track->getArtist()->getMBID() == artistMBID); - - Track::pointer trackNotFound = Track::getByMBID(db.getSession(), "foobar"); - assert(!trackNotFound); - - Artist::pointer artist = Artist::getByMBID(db.getSession(), artistMBID); - assert(artist); - } - - // Search Filters - // Select track by track name - { - Wt::Dbo::Transaction transaction(db.getSession()); - - SearchFilter filter = SearchFilter::NameLikeMatch({{{SearchFilter::Field::Track, {"track"}}}}); - std::vector res = Track::getByFilter(db.getSession(), filter, -1, -1); - assert(res.size() == 1); - assert(res.front().id() == 1); - - filter = SearchFilter::NameLikeMatch({{{SearchFilter::Field::Track,{"not-found"}}}}); - res = Track::getByFilter(db.getSession(), filter, -1, -1); - assert(res.size() == 0 ); - } - - // Select track by artist name - { - Wt::Dbo::Transaction transaction(db.getSession()); - - SearchFilter filter = SearchFilter::NameLikeMatch({{{SearchFilter::Field::Artist, {"artist"}}}}); - std::vector res = Track::getByFilter(db.getSession(), filter, -1, -1); - assert(res.size() == 1); - assert(res.front().id() == 1); - } - - // Select track by artist id - { - Wt::Dbo::Transaction transaction(db.getSession()); - - SearchFilter filter = SearchFilter::IdMatch({{SearchFilter::Field::Artist, {1}}}); - std::vector res = Track::getByFilter(db.getSession(), filter, -1, -1); - assert(res.size() == 1); - assert(res.front().id() == 1); - } - - // Select track by track name + artist id - { - Wt::Dbo::Transaction transaction(db.getSession()); - - SearchFilter filter; - filter.idMatch[SearchFilter::Field::Artist] = { 1 }; - filter.nameLikeMatch = {{{ SearchFilter::Field::Track, {"track"} }}}; - std::vector res = Track::getByFilter(db.getSession(), filter, -1, -1); - assert(res.size() == 1); - assert(res.front().id() == 1); - assert(res.front()->getName() == "track01" ); - } - - // Select track by genre name - { - Wt::Dbo::Transaction transaction(db.getSession()); - - SearchFilter filter = SearchFilter::NameLikeMatch({{{SearchFilter::Field::Genre, {"genre"}}}}); - std::vector res = Track::getByFilter(db.getSession(), filter, -1, -1); - assert(res.size() == 1); - assert(res.front().id() == 1); - assert(res.front()->getName() == "track01" ); - } - - // Select artist by track name - { - Wt::Dbo::Transaction transaction(db.getSession()); - - SearchFilter filter = SearchFilter::NameLikeMatch({{{SearchFilter::Field::Track, { "track" } }}}); - std::vector res = Artist::getByFilter(db.getSession(), filter, -1, -1); - assert(res.size() == 1); - assert(res.front().id() == 1); - - filter = SearchFilter::NameLikeMatch({{{SearchFilter::Field::Track, {"badtrack"} }}}); - res = Artist::getByFilter(db.getSession(), filter, -1, -1); - assert(res.size() == 0); - } - - // Select artist by track id - { - Wt::Dbo::Transaction transaction(db.getSession()); - - SearchFilter filter = SearchFilter::IdMatch({{SearchFilter::Field::Track, {1} }}); - std::vector res = Artist::getByFilter(db.getSession(), filter, -1, -1); - assert(res.size() == 1); - assert(res.front().id() == 1); - } - - // Select Artist by name - { - Wt::Dbo::Transaction transaction(db.getSession()); - - SearchFilter filter = SearchFilter::NameLikeMatch({{{SearchFilter::Field::Artist, {"artist"}}}}); - std::vector res = Artist::getByFilter(db.getSession(), filter, -1, -1); - assert(res.size() == 1); - assert(res.front().id() == 1); - - // Make sure artist has a release - assert(res.front()->getReleases().size() == 1); - } - - // Select Release by name - { - Wt::Dbo::Transaction transaction(db.getSession()); - - SearchFilter filter = SearchFilter::NameLikeMatch({{{SearchFilter::Field::Release, {"release"} }}}); - - std::vector res = Release::getByFilter(db.getSession(), filter, -1, -1); - assert(res.size() == 1); - assert(res.front().id() == 1); - } - - // Select Release by track name - { - Wt::Dbo::Transaction transaction(db.getSession()); - - SearchFilter filter = SearchFilter::NameLikeMatch({{{SearchFilter::Field::Track, {"track"}}}}); - std::vector res = Release::getByFilter(db.getSession(), filter, -1, -1); - assert(res.size() == 1); - assert(res.front().id() == 1); - assert(res.front()->getName() == "release01"); - - } - - // Select genre by name - { - Wt::Dbo::Transaction transaction(db.getSession()); - - SearchFilter filter = SearchFilter::NameLikeMatch({{{SearchFilter::Field::Genre, {"genre"}}}}); - std::vector res = Genre::getByFilter(db.getSession(), filter, -1, -1); - assert(res.size() == 1); - assert(res.front().id() == 1); - assert(res.front()->getName() == "genre01"); - } - - // Select genre by track name - { - Wt::Dbo::Transaction transaction(db.getSession()); - - SearchFilter filter = SearchFilter::NameLikeMatch({{{SearchFilter::Field::Track, {"track"}}}}); - std::vector res = Genre::getByFilter(db.getSession(), filter, -1, -1); - assert(res.size() == 1); - assert(res.front().id() == 1); - assert(res.front()->getName() == "genre01"); - } - - // Select genre by track name and artist name - { - Wt::Dbo::Transaction transaction(db.getSession()); - - SearchFilter filter = SearchFilter::NameLikeMatch({{{SearchFilter::Field::Track, {"track"}}, - {SearchFilter::Field::Artist, {"artist"}}}}); - std::vector res = Genre::getByFilter(db.getSession(), filter, -1, -1); - assert(res.size() == 1); - assert(res.front().id() == 1); - assert(res.front()->getName() == "genre01"); - } - - } - catch(std::exception& e) - { - std::cerr << "Caught exception " << e.what() << std::endl; - return EXIT_FAILURE; - } - - return EXIT_SUCCESS; -} - diff --git a/test/CheckSqlQuery.cpp b/test/CheckSqlQuery.cpp deleted file mode 100644 index e5ab3153..00000000 --- a/test/CheckSqlQuery.cpp +++ /dev/null @@ -1,66 +0,0 @@ -/* - * Copyright (C) 2013 Emeric Poupon - * - * This file is part of LMS. - * - * LMS is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * LMS is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with LMS. If not, see . - */ - - -#include -#include -#include -#include - -#include "database/SqlQuery.hpp" - -int main(void) -{ - try { - SqlQuery query; - - - query.select("artist.name").And("track.name"); - query.from().And( FromClause("artist") ).And( FromClause("track")); - query.where().And( WhereClause("artist.id = track.artist_id") ); - - std::cout << "Query = '" << query.get() << "'" << std::endl; - - assert(query.get() == "SELECT artist.name,track.name FROM artist,track WHERE (artist.id = track.artist_id)"); - - { - WhereClause clause; - - clause.Or(WhereClause("artist.name = ?").bind("Sepultura1")); - clause.Or(WhereClause("artist.name = ?").bind("Sepultura2")); - clause.Or(WhereClause("artist.name = ?")).bind("Sepultura3"); - - query.where().And(clause); - - assert(query.get() == "SELECT artist.name,track.name FROM artist,track WHERE (artist.id = track.artist_id) AND ((artist.name = ?) OR (artist.name = ?) OR (artist.name = ?))"); - - assert(query.where().getBindArgs().size() == 3); - std::cout << "Query = '" << query.get() << "'" << std::endl; - } - - } - catch(std::exception& e) - { - std::cerr << "Caught exception " << e.what() << std::endl; - return EXIT_FAILURE; - } - - return EXIT_SUCCESS; -} - diff --git a/test/DatabaseIntegrity.cpp b/test/DatabaseIntegrity.cpp deleted file mode 100644 index 4b3d97dc..00000000 --- a/test/DatabaseIntegrity.cpp +++ /dev/null @@ -1,60 +0,0 @@ -/* - * Copyright (C) 2013 Emeric Poupon - * - * This file is part of LMS. - * - * LMS is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * LMS is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with LMS. If not, see . - */ - -#include -#include -#include - -#include - -#include "database/DatabaseHandler.hpp" - -int main(void) -{ - - try { - std::cout << "Starting test!" << std::endl; - - // Set up the long living database session - std::unique_ptr connectionPool(Database::Handler::createConnectionPool( "test.db")); - - Database::Handler database(*connectionPool); - - Wt::Dbo::Transaction transaction(database.getSession()); - - Wt::Dbo::collection< Database::Track::pointer > tracks (Database::Track::getAll( database.getSession() )); - - std::cout << "Found " << tracks.size() << " tracks!" << std::endl; - - for (auto track : tracks) - { - assert( !track->getName().empty() ); - assert( !track->getGenres().empty() ); - assert( !track->getDuration().is_not_a_date_time() ); - } - - } - catch(std::exception& e) - { - std::cerr << "Caught exception " << e.what() << std::endl; - return EXIT_FAILURE; - } - - return EXIT_SUCCESS; -} diff --git a/test/Makefile.am b/test/Makefile.am index deb16d46..8dbec7c5 100644 --- a/test/Makefile.am +++ b/test/Makefile.am @@ -1,109 +1,7 @@ -TESTS = sql-query database-user +TESTS = -check_PROGRAMS = test-avmetadata - -database_basics_SOURCES = \ - $(srcdir)/CheckDbBasics.cpp \ - $(top_srcdir)/src/logger/Logger.cpp \ - $(top_srcdir)/src/database/Artist.cpp \ - $(top_srcdir)/src/database/DatabaseHandler.cpp \ - $(top_srcdir)/src/database/MediaDirectory.cpp \ - $(top_srcdir)/src/database/Playlist.cpp \ - $(top_srcdir)/src/database/Release.cpp \ - $(top_srcdir)/src/database/SearchFilter.cpp \ - $(top_srcdir)/src/database/SqlQuery.cpp \ - $(top_srcdir)/src/database/Track.cpp \ - $(top_srcdir)/src/database/User.cpp \ - $(top_srcdir)/src/database/Video.cpp - -database_basics_CXXFLAGS=-std=c++11 -Wall -Wextra -I$(top_srcdir)/src - -database_user_SOURCES = \ - $(srcdir)/CheckDatabaseUser.cpp \ - $(top_srcdir)/src/logger/Logger.cpp \ - $(top_srcdir)/src/database/Artist.cpp \ - $(top_srcdir)/src/database/Playlist.cpp \ - $(top_srcdir)/src/database/Release.cpp \ - $(top_srcdir)/src/database/Track.cpp \ - $(top_srcdir)/src/database/DatabaseHandler.cpp \ - $(top_srcdir)/src/database/MediaDirectory.cpp \ - $(top_srcdir)/src/database/SearchFilter.cpp \ - $(top_srcdir)/src/database/SqlQuery.cpp \ - $(top_srcdir)/src/database/User.cpp \ - $(top_srcdir)/src/database/Video.cpp - -database_user_CXXFLAGS=-std=c++11 -Wall -Wextra -I$(top_srcdir)/src +check_PROGRAMS = -database_integrity_SOURCES = \ - $(srcdir)/DatabaseIntegrity.cpp \ - $(top_srcdir)/src/logger/Logger.cpp \ - $(top_srcdir)/src/database/Artist.cpp \ - $(top_srcdir)/src/database/Playlist.cpp \ - $(top_srcdir)/src/database/Track.cpp \ - $(top_srcdir)/src/database/DatabaseHandler.cpp \ - $(top_srcdir)/src/database/MediaDirectory.cpp \ - $(top_srcdir)/src/database/Release.cpp \ - $(top_srcdir)/src/database/SearchFilter.cpp \ - $(top_srcdir)/src/database/SqlQuery.cpp \ - $(top_srcdir)/src/database/User.cpp \ - $(top_srcdir)/src/database/Video.cpp - -database_integrity_CXXFLAGS=-std=c++11 -Wall -Wextra -I$(top_srcdir)/src - -sql_query_SOURCES = \ - $(srcdir)/CheckSqlQuery.cpp \ - $(top_srcdir)/src/database/SqlQuery.cpp - -sql_query_CXXFLAGS=-std=c++11 -Wall -Wextra -I$(top_srcdir)/src - - -test_wt_SOURCES = TestWt.cpp -test_wt_CXXFLAGS=-std=c++11 -Wall -Wextra - -test_wt_audio_SOURCES = TestWtAudio.cpp\ - $(top_srcdir)/src/logger/Logger.cpp \ - $(top_srcdir)/src/utils/Utils.cpp \ - $(top_srcdir)/src/metadata/AvFormat.cpp \ - $(top_srcdir)/src/av/AvInfo.cpp \ - $(top_srcdir)/src/av/AvTranscoder.cpp \ - $(top_srcdir)/src/cover/CoverArtGrabber.cpp \ - $(top_srcdir)/src/database/Artist.cpp \ - $(top_srcdir)/src/database/Playlist.cpp \ - $(top_srcdir)/src/database/Track.cpp \ - $(top_srcdir)/src/database/DatabaseHandler.cpp \ - $(top_srcdir)/src/database/MediaDirectory.cpp \ - $(top_srcdir)/src/database/Release.cpp \ - $(top_srcdir)/src/database/SearchFilter.cpp \ - $(top_srcdir)/src/database/SqlQuery.cpp \ - $(top_srcdir)/src/database/User.cpp \ - $(top_srcdir)/src/database/Video.cpp \ - $(top_srcdir)/src/image/Image.cpp \ - $(top_srcdir)/src/ui/resource/CoverResource.cpp \ - $(top_srcdir)/src/ui/resource/TranscodeResource.cpp - -test_wt_audio_CXXFLAGS=-std=c++11 -Wall -Wextra -I$(top_srcdir)/src -I$(top_srcdir)/src/ui $(MAGICKXX_CFLAGS) -test_wt_audio_LDADD=$(MAGICKXX_LIBS) - - -test_avmetadata_SOURCES = TestAvMetadata.cpp \ - $(top_srcdir)/src/utils/Logger.cpp \ - $(top_srcdir)/src/utils/Utils.cpp \ - $(top_srcdir)/src/metadata/AvFormat.cpp \ - $(top_srcdir)/src/metadata/TagLibParser.cpp \ - $(top_srcdir)/src/metadata/MetaData.cpp \ - $(top_srcdir)/src/av/AvInfo.cpp - -test_avmetadata_CXXFLAGS=-std=c++11 -Wall -Wextra -I$(top_srcdir)/src - - -test_avtranscoder_SOURCES = TestAvTranscoder.cpp \ - $(top_srcdir)/src/logger/Logger.cpp \ - $(top_srcdir)/src/utils/Utils.cpp \ - $(top_srcdir)/src/av/AvInfo.cpp \ - $(top_srcdir)/src/av/AvTranscoder.cpp - -test_avtranscoder_CXXFLAGS=-std=c++11 -Wall -Wextra -I$(top_srcdir)/src - diff --git a/test/TestAvMetadata.cpp b/test/TestAvMetadata.cpp deleted file mode 100644 index 93985aac..00000000 --- a/test/TestAvMetadata.cpp +++ /dev/null @@ -1,143 +0,0 @@ -#include -#include - -#include -#include - -#include - -#include "av/AvInfo.hpp" -#include "metadata/AvFormat.hpp" -#include "metadata/TagLibParser.hpp" - -int main(int argc, char *argv[]) -{ - if (argc != 2) - { - std::cerr << "Usage: " << std::endl; - return EXIT_FAILURE; - } - - try - { - Av::AvInit(); - - - MetaData::AvFormat avFormatParser; - MetaData::TagLibParser tagLibParser; - - std::vector parsers = {&avFormatParser, &tagLibParser }; - - for (auto& parser : parsers) - { - boost::optional items = parser->parse(argv[1], true); - - if (!items) - { - std::cout << "Parsing failed" << std::endl; - continue; - } - - std::cout << "Items:" << std::endl; - for (auto item : (*items)) - { - switch (item.first) - { - case MetaData::Type::Title: - std::cout << "Title: " << boost::any_cast(item.second) << std::endl; - break; - - case MetaData::Type::Artist: - std::cout << "Artist: " << boost::any_cast(item.second) << std::endl; - break; - - case MetaData::Type::Album: - std::cout << "Album: " << boost::any_cast(item.second) << std::endl; - break; - - case MetaData::Type::Clusters: - for (const auto& cluster : boost::any_cast(item.second)) - { - std::cout << "Cluster: " << cluster.first << std::endl; - for (const auto name : cluster.second) - { - std::cout << "\t" << name << std::endl; - } - } - break; - - case MetaData::Type::Duration: - std::cout << "Duration: " << boost::any_cast(item.second).count() / 1000 << "s" << std::endl; - break; - - case MetaData::Type::TrackNumber: - std::cout << "Track: " << boost::any_cast(item.second) << std::endl; - break; - - case MetaData::Type::TotalTrack: - std::cout << "TotalTrack: " << boost::any_cast(item.second) << std::endl; - break; - - case MetaData::Type::DiscNumber: - std::cout << "Disc: " << boost::any_cast(item.second) << std::endl; - break; - - case MetaData::Type::TotalDisc: - std::cout << "TotalDisc: " << boost::any_cast(item.second) << std::endl; - break; - - case MetaData::Type::Year: - std::cout << "Year: " << std::to_string(boost::any_cast(item.second)) << std::endl; - break; - - case MetaData::Type::OriginalYear: - std::cout << "Original year: " << std::to_string(boost::any_cast(item.second)) << std::endl; - break; - - case MetaData::Type::HasCover: - std::cout << "HasCover = " << std::boolalpha << boost::any_cast(item.second) << std::endl; - break; - - case MetaData::Type::AudioStreams: - for (auto& audioStream : boost::any_cast >(item.second)) - std::cout << "Audio stream: " << audioStream.bitRate << " bps" << std::endl; - break; - - case MetaData::Type::MusicBrainzArtistID: - std::cout << "MusicBrainzArtistID: " << boost::any_cast(item.second) << std::endl; - break; - - case MetaData::Type::MusicBrainzAlbumID: - std::cout << "MusicBrainzAlbumID: " << boost::any_cast(item.second) << std::endl; - break; - - case MetaData::Type::MusicBrainzTrackID: - std::cout << "MusicBrainzTrackID: " << boost::any_cast(item.second) << std::endl; - break; - - case MetaData::Type::MusicBrainzRecordingID: - std::cout << "MusicBrainzRecordingID: " << boost::any_cast(item.second) << std::endl; - break; - - case MetaData::Type::AcoustID: - std::cout << "AcoustID: " << boost::any_cast(item.second) << std::endl; - break; - - default: - break; - } - } - - std::cout << std::endl; - } - - return EXIT_SUCCESS; - } - catch (std::exception& e) - { - std::cerr << "Caught exception: " << e.what(); - return EXIT_FAILURE; - } - -} - diff --git a/test/TestAvTranscoder.cpp b/test/TestAvTranscoder.cpp deleted file mode 100644 index f5a7e932..00000000 --- a/test/TestAvTranscoder.cpp +++ /dev/null @@ -1,55 +0,0 @@ -#include - -#include -#include - -#include "av/AvInfo.hpp" -#include "av/AvTranscoder.hpp" - -int main(int argc, char *argv[]) -{ - if (argc != 2) - { - std::cerr << "Usage: " << std::endl; - return EXIT_FAILURE; - } - - try - { - Av::AvInit(); - Av::Transcoder::init(); - - // Make pstream work with ffmpeg - close(STDIN_FILENO); - - Av::TranscodeParameters parameters; - parameters.setEncoding(Av::Encoding::MP3); - parameters.setOffset( boost::posix_time::seconds(0) ); - parameters.setBitrate( Av::Stream::Type::Audio, 160000 ); -// parameters.addStream(0); - - Av::Transcoder transcoder(argv[1], parameters); - - if (!transcoder.start()) - throw std::runtime_error("transcoder.start failed!"); - - while (!transcoder.isComplete()) - { - std::vector data; - std::cout << "Processing ..." << std::endl; - transcoder.process(data, 65536); - std::cout << "Processing done" << std::endl; - } - - std::cout << "Complete!" << std::endl; - - return EXIT_SUCCESS; - } - catch (std::exception& e) - { - std::cerr << "Caught exception: " << e.what(); - return EXIT_FAILURE; - } - -} - diff --git a/test/TestDatabase.cpp b/test/TestDatabase.cpp deleted file mode 100644 index 497894a4..00000000 --- a/test/TestDatabase.cpp +++ /dev/null @@ -1,46 +0,0 @@ -/* - * Copyright (C) 2013 Emeric Poupon - * - * This file is part of LMS. - * - * LMS is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * LMS is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with LMS. If not, see . - */ - - -#include "TestDatabase.hpp" - -namespace TestDatabase { - - Database::Handler* create() -{ - - boost::filesystem::path p ("test_db"); - - // Remove previous db -// boost::filesystem::remove(p); - - Database::Handler* db = new Database::Handler(p); - - - // Populate DB - - // Add artist - - // Add - - - return db; -} - -} // namespace TestDatabase diff --git a/test/TestDatabase.hpp b/test/TestDatabase.hpp deleted file mode 100644 index f639c791..00000000 --- a/test/TestDatabase.hpp +++ /dev/null @@ -1,27 +0,0 @@ -/* - * Copyright (C) 2013 Emeric Poupon - * - * This file is part of LMS. - * - * LMS is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * LMS is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with LMS. If not, see . - */ - - -#include "database/DatabaseHandler.hpp" - -namespace TestDatabase { - - Database::Handler* create(); - -} // namespace TestDatabase diff --git a/test/TestWt.cpp b/test/TestWt.cpp deleted file mode 100644 index f86d44c2..00000000 --- a/test/TestWt.cpp +++ /dev/null @@ -1,166 +0,0 @@ - -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include - - -class ArtistView : public Wt::WContainerWidget -{ - public: - ArtistView(Wt::WContainerWidget *parent = 0) - : Wt::WContainerWidget(parent) - { - } - - void setId(int id) - { - clear(); - - Wt::WText *header = new Wt::WText("Artist view ID = " + std::to_string(id), this); - header->setInline(false); - - for (int i = id; i > 0; --i) - { - Wt::WAnchor *anchor = new Wt::WAnchor(Wt::WLink(Wt::WLink::InternalPath, "/release/" + std::to_string(i)), this); - Wt::WText *text = new Wt::WText("Release " + std::to_string(i), anchor); - text->setInline(false); - } - } -}; - -class ReleaseView : public Wt::WContainerWidget -{ - public: - ReleaseView(Wt::WContainerWidget *parent = 0) - : Wt::WContainerWidget(parent) - { - } - - void setId(int id) - { - clear(); - Wt::WText *header = new Wt::WText("Release view ID = " + std::to_string(id), this); - header->setInline(false); - - for (int i = id; i > 0; --i) - { - Wt::WAnchor *anchor = new Wt::WAnchor(Wt::WLink(Wt::WLink::InternalPath, "/artist/" + std::to_string(i)), this); - Wt::WText *text = new Wt::WText("Artist " + std::to_string(i), anchor); - text->setInline(false); - } - } -}; - -class TestApplication : public Wt::WApplication -{ - public: - TestApplication(const Wt::WEnvironment& env) - : Wt::WApplication(env) - { - - enableInternalPaths(); - - Wt::WComboBox *combo = new Wt::WComboBox(root()); - combo->addItem("Artist"); - combo->addItem("Release"); - - Wt::WLineEdit *edit = new Wt::WLineEdit("Enter id", root()); - - edit->changed().connect(std::bind([=] - { - if (combo->currentText() == "Artist") - wApp->setInternalPath("/artist/" + edit->text().toUTF8(), true); - else if (combo->currentText() == "Release") - wApp->setInternalPath("/release/" + edit->text().toUTF8(), true); - })); - - Wt::WStackedWidget *stack = new Wt::WStackedWidget(root()); - - Wt::WContainerWidget *artistContainer = new Wt::WContainerWidget(); - Wt::WContainerWidget *releaseContainer = new Wt::WContainerWidget(); - - stack->addWidget(releaseContainer); - stack->addWidget(artistContainer); - - internalPathChanged().connect(std::bind([=] (std::string path) - { - wApp->log("info") << "Path set to '" << path << "'"; - - std::vector strings; - boost::algorithm::split(strings, path, boost::is_any_of("/"), boost::token_compress_on); - - if (strings.size() != 3) - return; - - std::string view = strings[1]; - int id; - try { - id = std::stol(strings[2]); - } - catch (std::exception& e) { - return; - } - - if (view == "release") - { - releaseContainer->clear(); - ReleaseView *releaseView = new ReleaseView(releaseContainer); - releaseView->setId(id); - - stack->setCurrentIndex(0); - } - else if (view == "artist") - { - artistContainer->clear(); - ArtistView *artistView = new ArtistView(artistContainer); - artistView->setId(id); - - stack->setCurrentIndex(1); - } - - }, std::placeholders::_1)); - - setInternalPath("/main"); - } - -}; - -static Wt::WApplication *createTestApplication(const Wt::WEnvironment& env) -{ - return new TestApplication(env); -} - -int main(int argc, char *argv[]) -{ - try - { - - Wt::WServer server(argv[0]); - server.setServerConfiguration (argc, argv); - - server.addEntryPoint(Wt::Application, createTestApplication); - - server.start(); - - Wt::WServer::waitForShutdown(argv[0]); - - server.stop(); - - return EXIT_SUCCESS; - } - catch (std::exception& e) - { - std::cerr << "Caught exception: " << e.what(); - return EXIT_FAILURE; - } - -} - diff --git a/test/TestWtAudio.cpp b/test/TestWtAudio.cpp deleted file mode 100644 index d53541c5..00000000 --- a/test/TestWtAudio.cpp +++ /dev/null @@ -1,322 +0,0 @@ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include "database/DatabaseHandler.hpp" - -#include "ui/resource/TranscodeResource.hpp" -#include "ui/resource/CoverResource.hpp" - - -class InputRange : public Wt::WWebWidget -{ - public: - InputRange(Wt::WContainerWidget *parent = 0) - : Wt::WWebWidget(parent) - { - setHtmlTagName("input"); - setAttributeValue("type", "range"); - } - - Wt::DomElementType domElementType() const - { - return Wt::DomElement_INPUT; - } -}; - - -Wt::WString MyPlayerTemplate = "${shuffle} ${repeat} ${playlist} ${prev} ${play-pause} ${next} ${cover} ${artist} ${track} ${release} ${curtime} ${seekbar} ${duration} ${volume}"; - -class MyPlayer : public Wt::WContainerWidget -{ - public: - - void playbackComplete(void) - { - // Switch to the next track - } - - void loadTrack(Database::Track::id_type trackId) - { - Wt::Dbo::Transaction transaction(_db.getSession()); - - Database::Track::pointer track = Database::Track::getById(_db.getSession(), trackId); - if (!track) - { - std::cerr << "no track for this id!" << std::endl; - return; - } - - _trackName->setText(Wt::WString::fromUTF8(track->getName())); - _artistName->setText( Wt::WString::fromUTF8(track->getArtist()->getName())); - _releaseName->setText( Wt::WString::fromUTF8(track->getRelease()->getName())); - _cover->setImageLink(_coverResource->getTrackUrl(trackId, 64)); - _trackDuration->setText( boost::posix_time::to_simple_string( track->getDuration() )); - - // Analyse track, select the best media stream - Av::MediaFile mediaFile(track->getPath()); - - if (!mediaFile.open() || !mediaFile.scan()) - { - std::cerr << "cannot open file '" << track->getPath() << std::endl; - return; - } - - - int audioBestStreamId = mediaFile.getBestStreamId(Av::Stream::Type::Audio); - std::vector streams; - if (audioBestStreamId != -1) - streams.push_back(audioBestStreamId); - - this->doJavaScript("\ - document.lms.audio.state = \"loaded\";\ - document.lms.audio.seekbar.min = " + std::to_string(0) + ";\ - document.lms.audio.seekbar.max = " + std::to_string(track->getDuration().total_seconds()) + ";\ - document.lms.audio.seekbar.value = 0;\ - document.lms.audio.seekbar.disabled = false;\ - document.lms.audio.offset = 0;\ - document.lms.audio.curTime = 0;\ - "); - - _audio->pause(); - _audio->clearSources(); - _audio->addSource(_transcodeResource->getUrl(trackId, Av::Encoding::MP3, 0, streams)); - _audio->play(); - } - - - MyPlayer(Database::Handler &db, Wt::WContainerWidget *parent = 0) - : Wt::WContainerWidget(parent), - _db(db) - { - - _transcodeResource = new UserInterface::TranscodeResource(db, this); - _coverResource = new UserInterface::CoverResource(db, this); - - Wt::WTemplate *t = new Wt::WTemplate(MyPlayerTemplate, this); - - _audio = new Wt::WAudio(this); - - _cover = new Wt::WImage(); - t->bindWidget("cover", _cover); - _cover->setImageLink(_coverResource->getUnknownTrackUrl(64)); - - InputRange *seekbar = new InputRange(); - t->bindWidget("seekbar", seekbar); - - _trackName = new Wt::WText(); - t->bindWidget("track", _trackName); - - _artistName = new Wt::WText(); - t->bindWidget("artist", _artistName); - - _releaseName = new Wt::WText(); - t->bindWidget("release", _releaseName); - - InputRange *volumeSlider = new InputRange(); - t->bindWidget("volume", volumeSlider); - - Wt::WPushButton *playlistBtn = new Wt::WPushButton("", Wt::XHTMLText); - t->bindWidget("playlist", playlistBtn); - - Wt::WPushButton *repeatBtn = new Wt::WPushButton("", Wt::XHTMLText); - t->bindWidget("repeat", repeatBtn); - - Wt::WPushButton *shuffleBtn = new Wt::WPushButton("", Wt::XHTMLText); - t->bindWidget("shuffle", shuffleBtn); - - Wt::WPushButton *prevBtn = new Wt::WPushButton("", Wt::XHTMLText); - t->bindWidget("prev", prevBtn); - - Wt::WPushButton *nextBtn = new Wt::WPushButton("", Wt::XHTMLText); - t->bindWidget("next", nextBtn); - - Wt::WPushButton *playPauseBtn = new Wt::WPushButton("", Wt::XHTMLText); - t->bindWidget("play-pause", playPauseBtn); - - Wt::WText *trackCurrentTime = new Wt::WText("00:00"); - t->bindWidget("curtime", trackCurrentTime); - - _trackDuration = new Wt::WText("00:00"); - t->bindWidget("duration", _trackDuration); - - //Wt::WTemplate *_volumeSlider = new Wt::WTemplate(VolumeSliderTemplate, this); - - this->doJavaScript( -"\ - document.lms = {};\ - document.lms.audio = {};\ - document.lms.audio.audio = " + _audio->jsRef() + ";\ - document.lms.audio.seekbar = " + seekbar->jsRef() +";\ - document.lms.audio.volumeSlider = " + volumeSlider->jsRef() + ";\ - document.lms.audio.curTimeText = " + trackCurrentTime->jsRef() + ";\ - document.lms.audio.playPause = " + playPauseBtn->jsRef() + ";\ -\ - document.lms.audio.offset = 0;\ - document.lms.audio.curTime = 0;\ - document.lms.audio.state = \"init\";\ - document.lms.audio.volume = 1;\ -\ - document.lms.audio.seekbar.value = 0;\ - document.lms.audio.seekbar.disabled = true;\ -\ - document.lms.audio.volumeSlider.min = 0;\ - document.lms.audio.volumeSlider.max = 100;\ - document.lms.audio.volumeSlider.value = 100;\ -\ - function updateUI() {\ - document.lms.audio.curTimeText.innerHTML = document.lms.audio.curTime;\ - document.lms.audio.seekbar.value = document.lms.audio.curTime;\ - }\ -\ - var mouseDown = 0;\ - function seekMouseDown(e) {\ - ++mouseDown;\ - }\ - function seekMouseUp(e) {\ - --mouseDown;\ - }\ -\ - function seeking(e) {\ - if (document.lms.audio.state == \"init\")\ - return;\ -\ - document.lms.audio.curTimeText.innerHTML = document.lms.audio.seekbar.value;\ - }\ -\ - function seek(e) {\ - if (document.lms.audio.state == \"init\")\ - return;\ -\ - document.lms.audio.audio.pause(); \ - document.lms.audio.offset = parseInt(document.lms.audio.seekbar.value);\ - document.lms.audio.curTime = document.lms.audio.seekbar.value;\ - var audioSource = document.lms.audio.audio.getElementsByTagName(\"source\")[0];\ - var src = audioSource.src;\ - src = src.slice(0, src.lastIndexOf(\"=\") + 1);\ - audioSource.src = src + document.lms.audio.seekbar.value;\ - document.lms.audio.audio.load(); \ - document.lms.audio.audio.play(); \ - document.lms.audio.curTimeText.innerHTML = ~~document.lms.audio.curTime + \" \";\ - }\ -\ - function volumeChanged() {\ - document.lms.audio.audio.volume = document.lms.audio.volumeSlider.value / 100;\ - }\ -\ - function updateCurTime() {\ - document.lms.audio.curTime = document.lms.audio.offset + ~~document.lms.audio.audio.currentTime; \ - if (mouseDown == 0)\ - updateUI();\ - } \ -\ - function playPause() {\ - if (document.lms.audio.state == \"init\") \ - return;\ -\ - if (document.lms.audio.audio.paused)\ - document.lms.audio.audio.play();\ - else\ - document.lms.audio.audio.pause();\ -\ - }\ -\ - document.lms.audio.audio.addEventListener('timeupdate', updateCurTime); \ - document.lms.audio.seekbar.addEventListener('change', seek);\ - document.lms.audio.seekbar.addEventListener('input', seeking);\ - document.lms.audio.seekbar.addEventListener('mousedown', seekMouseDown);\ - document.lms.audio.seekbar.addEventListener('mouseup', seekMouseUp);\ - document.lms.audio.volumeSlider.addEventListener('input', volumeChanged);\ - document.lms.audio.playPause.addEventListener('click', playPause);\ -" -); - } - - UserInterface::TranscodeResource* _transcodeResource; - UserInterface::CoverResource* _coverResource; - Database::Handler& _db; - Wt::WAudio* _audio; - Wt::WText* _trackDuration; - Wt::WText* _trackName; - Wt::WText* _artistName; - Wt::WText* _releaseName; - Wt::WImage* _cover; -}; - -class TestApplication : public Wt::WApplication -{ - public: - TestApplication(const Wt::WEnvironment& env, Wt::Dbo::SqlConnectionPool& connectionPool) - : Wt::WApplication(env) - , _db(connectionPool) - { - Wt::WBootstrapTheme *bootstrapTheme = new Wt::WBootstrapTheme(this); - bootstrapTheme->setVersion(Wt::WBootstrapTheme::Version3); - bootstrapTheme->setResponsive(true); - setTheme(bootstrapTheme); - - useStyleSheet("resources/font-awesome/css/font-awesome.min.css"); - - Wt::WLineEdit* trackSelector = new Wt::WLineEdit(); - MyPlayer* player = new MyPlayer(_db); - - trackSelector->changed().connect(std::bind([=] { - player->loadTrack(Wt::asNumber(trackSelector->valueText())); - })); - - root()->addWidget(trackSelector); - root()->addWidget(player); - } - - private: - Database::Handler _db; - -}; - -static Wt::WApplication *createTestApplication(const Wt::WEnvironment& env, Wt::Dbo::SqlConnectionPool& connectionPool ) -{ - return new TestApplication(env, connectionPool); -} - -int main(int argc, char *argv[]) -{ - try - { - Av::AvInit(); - Av::Transcoder::init(); - - Wt::WServer server(argv[0]); - server.setServerConfiguration (argc, argv); - - // Make pstream work with ffmpeg - close(STDIN_FILENO); - - Database::Handler::configureAuth(); - std::unique_ptr connectionPool( Database::Handler::createConnectionPool("/var/lms/lms.db")); - - server.addEntryPoint(Wt::Application, boost::bind(createTestApplication, _1, boost::ref(*connectionPool))); - - server.start(); - - Wt::WServer::waitForShutdown(argv[0]); - - server.stop(); - - return EXIT_SUCCESS; - } - catch (std::exception& e) - { - std::cerr << "Caught exception: " << e.what(); - return EXIT_FAILURE; - } - -} - diff --git a/tools/Makefile.am b/tools/Makefile.am new file mode 100644 index 00000000..085ca08c --- /dev/null +++ b/tools/Makefile.am @@ -0,0 +1,2 @@ +SUBDIRS = metadata + diff --git a/tools/metadata/LmsMetadata.cpp b/tools/metadata/LmsMetadata.cpp new file mode 100644 index 00000000..42fe5089 --- /dev/null +++ b/tools/metadata/LmsMetadata.cpp @@ -0,0 +1,129 @@ +#include +#include + +#include +#include + +#include + +#include "metadata/TagLibParser.hpp" + +int main(int argc, char *argv[]) +{ + if (argc != 2) + { + std::cerr << "Usage: " << std::endl; + return EXIT_FAILURE; + } + + try + { + MetaData::TagLibParser parser; + + boost::optional items = parser.parse(argv[1], true); + if (!items) + { + std::cerr << "Parsing failed" << std::endl; + return EXIT_FAILURE; + } + + std::cout << "Items:" << std::endl; + for (auto item : (*items)) + { + switch (item.first) + { + case MetaData::Type::Title: + std::cout << "Title: " << boost::any_cast(item.second) << std::endl; + break; + + case MetaData::Type::Artist: + std::cout << "Artist: " << boost::any_cast(item.second) << std::endl; + break; + + case MetaData::Type::Album: + std::cout << "Album: " << boost::any_cast(item.second) << std::endl; + break; + + case MetaData::Type::Clusters: + for (const auto& cluster : boost::any_cast(item.second)) + { + std::cout << "Cluster: " << cluster.first << std::endl; + for (const auto name : cluster.second) + { + std::cout << "\t" << name << std::endl; + } + } + break; + + case MetaData::Type::Duration: + std::cout << "Duration: " << boost::any_cast(item.second).count() / 1000 << "s" << std::endl; + break; + + case MetaData::Type::TrackNumber: + std::cout << "Track: " << boost::any_cast(item.second) << std::endl; + break; + + case MetaData::Type::TotalTrack: + std::cout << "TotalTrack: " << boost::any_cast(item.second) << std::endl; + break; + + case MetaData::Type::DiscNumber: + std::cout << "Disc: " << boost::any_cast(item.second) << std::endl; + break; + + case MetaData::Type::TotalDisc: + std::cout << "TotalDisc: " << boost::any_cast(item.second) << std::endl; + break; + + case MetaData::Type::Year: + std::cout << "Year: " << std::to_string(boost::any_cast(item.second)) << std::endl; + break; + + case MetaData::Type::OriginalYear: + std::cout << "Original year: " << std::to_string(boost::any_cast(item.second)) << std::endl; + break; + + case MetaData::Type::HasCover: + std::cout << "HasCover = " << std::boolalpha << boost::any_cast(item.second) << std::endl; + break; + + case MetaData::Type::AudioStreams: + for (auto& audioStream : boost::any_cast >(item.second)) + std::cout << "Audio stream: " << audioStream.bitRate << " bps" << std::endl; + break; + + case MetaData::Type::MusicBrainzArtistID: + std::cout << "MusicBrainzArtistID: " << boost::any_cast(item.second) << std::endl; + break; + + case MetaData::Type::MusicBrainzAlbumID: + std::cout << "MusicBrainzAlbumID: " << boost::any_cast(item.second) << std::endl; + break; + + case MetaData::Type::MusicBrainzTrackID: + std::cout << "MusicBrainzTrackID: " << boost::any_cast(item.second) << std::endl; + break; + + case MetaData::Type::MusicBrainzRecordingID: + std::cout << "MusicBrainzRecordingID: " << boost::any_cast(item.second) << std::endl; + break; + + case MetaData::Type::AcoustID: + std::cout << "AcoustID: " << boost::any_cast(item.second) << std::endl; + break; + + default: + break; + } + } + + std::cout << std::endl; + } + catch (std::exception& e) + { + std::cerr << "Caught exception: " << e.what(); + return EXIT_FAILURE; + } + + return EXIT_SUCCESS; +} diff --git a/tools/metadata/Makefile.am b/tools/metadata/Makefile.am new file mode 100644 index 00000000..cded72b1 --- /dev/null +++ b/tools/metadata/Makefile.am @@ -0,0 +1,11 @@ +bin_PROGRAMS = lms-metadata + +lms_metadata_SOURCES = \ + $(srcdir)/LmsMetadata.cpp \ + $(top_srcdir)/src/utils/Logger.cpp \ + $(top_srcdir)/src/utils/Utils.cpp \ + $(top_srcdir)/src/metadata/TagLibParser.cpp \ + $(top_srcdir)/src/metadata/MetaData.cpp + +lms_metadata_CXXFLAGS=-std=c++14 -Wall -I$(top_srcdir)/src -D_REENTRANT +