diff --git a/include/Containers.h b/include/Containers.h index 8647576..171d5bf 100644 --- a/include/Containers.h +++ b/include/Containers.h @@ -31,7 +31,7 @@ struct Track { unsigned int length; unsigned int year; std::string filePath; - std::string artwork; + TagLib::VariantMap artwork; TagLib::String genre; std::string format; uint64_t hash; diff --git a/include/Database.h b/include/Database.h index 5e740da..1efbe1e 100644 --- a/include/Database.h +++ b/include/Database.h @@ -22,10 +22,12 @@ class Database { std::optional getArtistId( const std::string& artistName ); std::optional getAlbumId( const std::string& albumTitle ); std::optional getGenreId( const std::string& genre ); + void addTrack( Track t); void addArtist( const std::string& artistName ); void addAlbum( Track t); - void addGenre( std::string& genre ); + void addGenre( const std::string& genre ); + void setActive( bool active ); void updateFilePath( const std::string& filePath ); diff --git a/include/File.h b/include/File.h index 86df0a0..f597280 100644 --- a/include/File.h +++ b/include/File.h @@ -11,8 +11,9 @@ namespace fs = std::filesystem; class File { public: Track importFile( const std::string& filePath ); - void importFolder( const std::string& folderPath, std::vector& tracks ); + void scanFolder( const std::string& folderPath, std::vector& tracks ); void readFileTag( Track& t ); + TagLib::VariantMap importArtwork( Track& t ); std::string parseFiletype( const std::string& path ); void updateLibrary(); uint64_t hashString( Track t ); diff --git a/include/Player.h b/include/Player.h index 369ced1..6a1d292 100644 --- a/include/Player.h +++ b/include/Player.h @@ -17,6 +17,9 @@ class Player { virtual void initPlayer (); virtual void loadFile ( Track track ); + virtual void scanLibrary(); + virtual void updateLibrary(); + virtual void editMetadata(); // Transport Control virtual void play (); @@ -24,6 +27,7 @@ class Player { virtual void pause (); virtual void previous (); virtual void next (); + virtual void seek(); virtual ma_uint64 getPlayheadPosition (); virtual void setPlayheadPosition () const; @@ -44,6 +48,7 @@ class Player { protected: PlaybackEngine PE_; trackVec queue_; + std::vector library; private: std::string artist_; diff --git a/include/PlayerLocal.h b/include/PlayerLocal.h index 19d4a85..e375954 100644 --- a/include/PlayerLocal.h +++ b/include/PlayerLocal.h @@ -1,17 +1,33 @@ #pragma once #include "Player.h" +#include "Database.h" + +using db = Database; class PlayerLocal : public Player { public: + // Library Controls + void loadFile ( Track track ) override; + void scanLibrary() override; + void updateLibrary() override; + void editMetadata() override; + // Transport Controls + void play() override; + void pause() override; + void stop() override; void next() override; void previous() override; + void seek() override; ma_uint64 getPlayheadPosition () override; - void loadFile ( Track track ) override; + + // Queue void addToQueue( Track& track ); void playQueue(); private: unsigned int currentTrack_; + db db_; + std::string musicFolder_ = "data/"; }; diff --git a/include/Tag.h b/include/Tag.h deleted file mode 100644 index 2500f0f..0000000 --- a/include/Tag.h +++ /dev/null @@ -1,26 +0,0 @@ -#pragma once - -#include "containers.h" -//#include "file.h" - -#include -#include -#include -#include -#include - - -namespace fs = std::filesystem; - -class tag { - public: - void readtag( TagLib::filename filename ); - metadata getmetadata() const; - - const std::string& getfilepath() const; - const auto getartwork() const; - private: - metadata metadata_; - std::string filepath_; - fs::path musicdir = music_folder; -}; diff --git a/include/utility.h b/include/utility.h new file mode 100644 index 0000000..06089a3 --- /dev/null +++ b/include/utility.h @@ -0,0 +1,11 @@ +#pragma once + +#include "Containers.h" +#include + +namespace utility { + + uint64_t hashString( const std::string& s ); + std::string parseFiletype( const std::string& filePath ); + +} diff --git a/src/File.cpp b/src/File.cpp index f617e79..706f7a5 100644 --- a/src/File.cpp +++ b/src/File.cpp @@ -1,11 +1,17 @@ #include "../include/File.h" #include "../include/Database.h" #include "../include/miniaudio.h" +#include "../include/utility.h" -#include #include +#include +#include #include +#include +#include +#include +#include #include #include #include @@ -15,28 +21,18 @@ namespace fs = std::filesystem; Track File::importFile( const std::string& filePath ) { Track t; t.filePath = filePath; - t.artwork = "./cover.png"; + t.artwork = importArtwork( t ); readFileTag( t ); return t; } -void File::importFolder(const std::string& folderPath, std::vector& tracks ) { +void File::scanFolder(const std::string& folderPath, std::vector& tracks ) { for ( const auto& audioFile : fs::directory_iterator{ folderPath }) { Track t = importFile( audioFile.path()); tracks.push_back( t ); } } -uint64_t hashString( Track t ) { - std::string s = (t.artist + t.title + t.album).toCString(); - uint64_t hash = 14695981039346656037ULL; - for ( char c : s ) { - hash ^= static_cast ( c ); - hash *= 1099511628211ULL; - } - return hash; -} - void File::readFileTag( Track& t ) { TagLib::FileRef f( reinterpret_cast(&t.filePath )); if ( !f.isNull() ) { @@ -46,19 +42,12 @@ void File::readFileTag( Track& t ) { t.trackNr = ( f.tag()->track() ); t.year = ( f.tag()->track() ); t.genre = ( f.tag()->genre().isEmpty() ) ? "" : ( f.tag()->genre() ); - t.format = parseFiletype( t.filePath ); + t.format = utility::parseFiletype( t.filePath ); t.length = ( f.audioProperties()->lengthInSeconds() ) ? f.audioProperties()->lengthInSeconds() : 0; - t.hash = hashString( t ); + t.hash = utility::hashString( (t.artist + t.title + t.album).toCString() ); } } -std::string File::parseFiletype( const std::string& path ){ - - size_t length = path.size(); - size_t dot = path.find_last_of( "."); - - return path.substr( dot + 1, length - dot ); -} void File::updateLibrary() { Database database( "sound_serve.db"); @@ -67,7 +56,7 @@ void File::updateLibrary() { std::set db_filePaths; std::set hashes; - importFolder( musicFolder_, musicFolder); + scanFolder( musicFolder_, musicFolder); database.fetchFilePaths(); database.fetchHashes( hashes ); @@ -87,3 +76,34 @@ void File::updateLibrary() { } } + +TagLib::VariantMap File::importArtwork( Track& t ) { + auto path = t.filePath; + TagLib::String mimeType; + TagLib::ByteVector imgData; + TagLib::VariantMap picture; + + std::ifstream in(path, std::ios::binary); + if (!in) throw std::runtime_error("Could not open image: " + path); + + std::vector bytes{ + std::istreambuf_iterator(in), + std::istreambuf_iterator() + }; + + imgData = (TagLib::ByteVector( bytes.data(), static_cast( bytes.size()) )); + + std::string ext = utility::parseFiletype( path ); + + if (ext == "jpg" || ext == "jpeg") mimeType = "image/jpeg"; + if (ext == "png") mimeType = "image/png"; + + throw std::runtime_error("Only JPEG/PNG cover art is handled here"); + + picture["data"] = imgData; + picture["pictureType"] = TagLib::String( "Front Cover" ); + picture["mimeType"] = mimeType; + picture["description"] = TagLib::String( "Cover" ); + + return picture; +} diff --git a/src/PlayerLocal.cpp b/src/PlayerLocal.cpp index 80357e9..b5ae263 100644 --- a/src/PlayerLocal.cpp +++ b/src/PlayerLocal.cpp @@ -1,5 +1,10 @@ #include "../include/PlayerLocal.h" #include "../include/Player.h" +#include "../include/File.h" +#include "../include/Database.h" +#include "../include/Containers.h" + +using db = Database; void Player::play () { PE_.startPlayback(); } void Player::stop () { PE_.stopPlayback(); } @@ -20,7 +25,7 @@ void PlayerLocal::previous() { ma_uint64 Player::getPlayheadPosition () { return PE_.getPosition(); }; void PlayerLocal::loadFile ( Track track ) { - const char *fp = track.filePath; + const char *fp = track.filePath.c_str(); PE_.initDecoder ( fp ); } @@ -35,3 +40,18 @@ void::PlayerLocal::playQueue() { ++currentTrack_; } } + +void PlayerLocal::scanLibrary(){ + File f; + Track t; + std::vector tracks; + + f.scanFolder( musicFolder_, tracks ); + + for ( auto t : tracks ) { + db_.addArtist( t.artist.toCString() ); + db_.addGenre( t.genre.toCString() ); + db_.addAlbum( t ); + db_.addTrack( t ); + } +} diff --git a/src/Tag.cpp b/src/Tag.cpp deleted file mode 100644 index 89ab7bc..0000000 --- a/src/Tag.cpp +++ /dev/null @@ -1,29 +0,0 @@ -#include "../include/Tag.h" -#include "../include/File.h" - -#include -#include - - -void Tag::readTag( TagLib::FileName fileName ){ - TagLib::FileRef f( fileName ); - if ( !f.isNull() ) { - metadata_.artist = ( f.tag()->artist().isEmpty() ) ? "" : f.tag()->artist(); - metadata_.title = ( f.tag()->title().isEmpty() ) ? "" : f.tag()->title(); - metadata_.album = ( f.tag()->album().isEmpty() ) ? "" : f.tag()->album(); - metadata_.trackNr = f.tag()->track(); - metadata_.year = f.tag()->year(); - metadata_.genre = f.tag()->genre(); - metadata_.sampleRate = f.audioProperties()->sampleRate(); - metadata_.bitRate = f.audioProperties()->bitrate(); - metadata_.length = f.audioProperties()->lengthInSeconds(); - metadata_.format = parseFiletype( fileName ); - // TODO - // file format - } -} - - -Metadata Tag::getMetadata() const { - return metadata_; -} diff --git a/src/utility.cpp b/src/utility.cpp new file mode 100644 index 0000000..9b9bc2b --- /dev/null +++ b/src/utility.cpp @@ -0,0 +1,18 @@ +#include "../include/utility.h" + +uint64_t utility::hashString( const std::string& s ) { + uint64_t hash = 14695981039346656037ULL; + for ( char c : s ) { + hash ^= static_cast ( c ); + hash *= 1099511628211ULL; + } + return hash; +} + +std::string utility::parseFiletype( const std::string& path ){ + + size_t length = path.size(); + size_t dot = path.find_last_of( "."); + + return path.substr( dot + 1, length - dot ); +}