diff --git a/CMakeLists.txt b/CMakeLists.txt index 9b75850..a9f6ce7 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -1,4 +1,4 @@ -cmake_minimum_required(VERSION 3.12) +cmake_minimum_required(VERSION 3.14) project(IcarusDownloadManager) @@ -9,29 +9,44 @@ message(STATUS "Checking compiler flags for C++17 support.") # Set C++17 support flags for various compilers include(CheckCXXCompilerFlag) -check_cxx_compiler_flag("-std=c++17" COMPILER_SUPPORTS_CXX17) -check_cxx_compiler_flag("-std=c++0x" COMPILER_SUPPORTS_CXX0X) +if(WIN32) + message("Windows") + set(vs_ver 19.29.30138) -if(COMPILER_SUPPORTS_CXX17) - message(STATUS "C++17 is supported.") + if (CMAKE_CXX_COMPILER_VERSION VERSION_GREATER_EQUAL ${vs_ver}) + message("Visual Studio version is at least ${vs_ver}") + + set(CMAKE_CXX_STANDARD_COMPILE_OPTION "-std:c++latest") + set(CMAKE_CXX_EXTENSION_COMPILE_OPTION "-std:c++latest") set(CMAKE_CXX_STANDARD 17) set(CMAKE_CXX_STANDARD_REQUIRED ON) - - if(${CMAKE_SYSTEM_NAME} MATCHES "Darwin") - set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++17 -stdlib=libc++") - else() - set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++17") - endif() -elseif(COMPILER_SUPPORTS_CXX0X) - message(STATUS "C++0x is supported.") - if(${CMAKE_SYSTEM_NAME} MATCHES "Darwin") - set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++0x -stdlib=libc++") - else() - set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++0x") - endif() + endif() else() - message(STATUS "The compiler ${CMAKE_CXX_COMPILER} has no C++17 support. Please use a different C++ compiler.") + check_cxx_compiler_flag("-std=c++17" COMPILER_SUPPORTS_CXX17) + check_cxx_compiler_flag("-std=c++0x" COMPILER_SUPPORTS_CXX0X) + + if(COMPILER_SUPPORTS_CXX17) + message(STATUS "C++17 is supported.") + + set(CMAKE_CXX_STANDARD 17) + set(CMAKE_CXX_STANDARD_REQUIRED ON) + + if(${CMAKE_SYSTEM_NAME} MATCHES "Darwin") + set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++17 -stdlib=libc++") + else() + set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++17") + endif() + elseif(COMPILER_SUPPORTS_CXX0X) + message(STATUS "C++0x is supported.") + if(${CMAKE_SYSTEM_NAME} MATCHES "Darwin") + set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++0x -stdlib=libc++") + else() + set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++0x") + endif() + else() + message(STATUS "The compiler ${CMAKE_CXX_COMPILER} has no C++17 support. Please use a different C++ compiler.") + endif() endif() @@ -42,6 +57,7 @@ set(SOURCES src/Managers/FileManager.cpp src/Managers/TokenManager.cpp src/Managers/UserManager.cpp + src/Models/Song.cpp src/Parsers/APIParser.cpp src/Syncers/Delete.cpp src/Syncers/Download.cpp @@ -54,7 +70,11 @@ set(IDM_INCLUDE_DIR "${CMAKE_CURRENT_SOURCE_DIR}/include") # conan -include(${CMAKE_BINARY_DIR}/conanbuildinfo.cmake) +set(CONAN_BUILDINFO +${CMAKE_BINARY_DIR}/conanbuildinfo.cmake) + +message("conan build info ${CONAN_BUILDINFO}") +include(${CONAN_BUILDINFO}) conan_basic_setup() include_directories(${CPR_INCLUDE_DIRS} ${IDM_INCLUDE_DIR}) diff --git a/README.md b/README.md index f2d5e6b..4434a28 100644 --- a/README.md +++ b/README.md @@ -7,7 +7,7 @@ IcarusDownloadManager is a Linux CLI software client application that has the fe * C++ with C++17 features * CMake -* GCC >= 9 or Visual Studio 2019 +* GCC >= 9 or Visual Studio >= 16 [2019] * [conan](https://github.com/conan-io/conan) * [json](https://github.com/nlohmann/json) * [openssl](https://github.com/openssl/openssl) @@ -28,23 +28,48 @@ cd build conan install .. --build -cmake -DCMAKE_BUILD_TYPE=RELEASE -cmake --build . -j +cmake .. +cmake --build . --config release -j ``` The program has been built and can be executed by the binary file *icd*. For information on how to use icd, merely execute the program without any command line arguments. ### Downloading Song -``icd download -u spacecadet -p stellar40 -h https://icarus.com -b 15`` + +```BASH +icd download -u spacecadet -p stellar40 -h https://icarus.com -b 15 +``` ### Uploading Song -``icd upload -u spacecadet -p stellar40 -h https://icarus.com -s /path/of/song.mp3`` + +```BASH +icd upload -u spacecadet -p stellar40 -h https://icarus.com -s /path/of/song.mp3 +``` + +### Uploading Song with metadata + +```BASH +icd upload-meta -u spacecadet -p stellar40 -h https://icarus.com -s /path/of/song.mp3 -t 1 -m /path/to/metadata/config/collection.json -ca /path/to/cover/art/image.png +``` + +### Uploading Song with metadata from directory + +```BASH +icd upload-meta -u spacecadet -p stellar40 -h https://icarus.com -smca /path/where/songs/and/metadata/exists/ +``` + ### Retrieving Song in json -``icd retrieve -u spacecadet -p stellar40 -h https://icarus.com -rt songs`` + +```Bash +icd retrieve -u spacecadet -p stellar40 -h https://icarus.com -rt songs +``` ### Deleting Song -``icd delete -u spacecadet -p stellar40 -h https://icarus.com -D 15`` + +```BASH +icd delete -u spacecadet -p stellar40 -h https://icarus.com -D 15 +``` ## Contributing @@ -53,6 +78,7 @@ Please read [CONTRIBUTING.md](CONTRIBUTING.md) for details on the code of conduc ## Versioning +[v0.2.0](https://github.com/kdeng00/IcarusDownloadManager/releases/tag/v0.2.0) [v0.1.1](https://github.com/kdeng00/IcarusDownloadManager/releases/tag/v0.1.1) [v0.1.0](https://github.com/kdeng00/IcarusDownloadManager/releases/tag/0.1.0) diff --git a/conanfile.txt b/conanfile.txt index 1a26411..cf5429e 100644 --- a/conanfile.txt +++ b/conanfile.txt @@ -6,3 +6,15 @@ cpr/1.7.2 [generators] cmake + +[options] +openssl:shared=False +libcurl:shared=False +cpr:shared=False +libcurl:with_ssl=openssl +libcurl:with_ftp=False +libcurl:with_gopher=False +libcurl:with_imap=False +libcurl:with_pop3=False +libcurl:with_smb=False +libcurl:with_smtp=False \ No newline at end of file diff --git a/include/Managers/ActionManager.h b/include/Managers/ActionManager.h index 2a30023..66bc3e1 100644 --- a/include/Managers/ActionManager.h +++ b/include/Managers/ActionManager.h @@ -1,6 +1,7 @@ #ifndef ACTIONMANAGER_H_ #define ACTIONMANAGER_H_ +#include #include #include #include @@ -12,6 +13,8 @@ namespace Managers { + + class ActionManager { public: @@ -19,19 +22,64 @@ public: Models::IcarusAction retrieveIcarusAction() const; private: - constexpr std::array supportedFlags() noexcept; - constexpr std::array supportedActions() noexcept; + constexpr std::array supportedFlags() noexcept + { + constexpr std::array allFlags{"-u", "-p", "-t", "-h", "-s", + "-sd", "-sr", "-d", "-D", "-b", "-rt", "-nc", + "-m", "-ca", "-smca", "-t"}; - bool isNumber(const std::string_view) noexcept; + return allFlags; + } + constexpr std::array supportedActions() noexcept; void initialize(); void validateFlags(); + // Checks to see if the flag is valid + template + bool isValidFlag(const Str flag) + { + const auto flags = supportedFlags(); + const auto i = std::find_if(flags.begin(), flags.end(), [&](const Str &f) + { + return f.compare(flag) == 0 ? true : false; + }); - std::vector parsedFlags(); + auto result = i != flags.end() ? true : false; + + return result; + } + + template + bool doesFlagHaveValue(const Str flag) + { + const auto flags = parsedFlags(); + auto i = std::find_if(flags.begin(), flags.end(), [&](const Str &f) + { + return f.compare(flag) == 0 ? true : false; + }); + + if (i != flags.end()) + { + if (++i != flags.end() && !isValidFlag(*i)) + { + return true; + } + else + { + return false; + } + } + else + { + return false; + } + } void printAction() noexcept; void printFlags() noexcept; + std::vector parsedFlags(); + std::string action; std::vector flags; diff --git a/include/Managers/CommitManager.h b/include/Managers/CommitManager.h index 937e1aa..2506637 100644 --- a/include/Managers/CommitManager.h +++ b/include/Managers/CommitManager.h @@ -2,11 +2,15 @@ #define COMMITMANAGER_H_ #include +#include #include +#include #include"Models/API.h" -#include"Models/Token.h" #include"Models/IcarusAction.h" +#include"Models/Song.h" +#include"Models/Token.h" +#include"Utilities/Checks.h" namespace Managers { @@ -18,32 +22,192 @@ public: void commitAction(); + enum class RetrieveTypes { songs }; + + // Used for parsing songs from the metadata file + class Album + { + public: + Album() = default; + + void printInfo(); + + + std::string album; + std::string albumArtist; + std::string genre; + int year; + int trackCount; + int discCount; + std::vector songs; + }; private: enum class ActionValues; - + std::map mapActions() noexcept; - Models::Token parseToken(Models::API); - void deleteSong(); void downloadSong(); void retrieveObjects(); void uploadSong(); + Models::Token parseToken(Models::API); + + // Uploads a single song. The song is constructed from a metadata file that contains + // information about the album the song is from. Also, the cover art of the song must + // be present. + // + // Expects + // * Song - mp3 file path + // * TrackID - track number to chose from when retrieving metadata. "1" and "1:1" are similar + // * Metadata - Source file containing metadata of the song + // * Cover art - path to image cover art + void uploadSongWithMetadata(); + + // Expects the song path, trackID, metadata file path, and cover path + void singTargetUpload(const std::string &songPath, const std::string &trackID, + const std::string &metaPath, const std::string &coverPath); + // Expects the source directory that contains songs, a metadata file, and cover image + // Disc and Track is retrieved from the filename if the filename conforms to a standard. + // If not, then the disc and track will default to 1 + // + // Standards + // * track01.mp3 - Disc 1, Track 1 + // * track05d02.mp3 - Disc 2, Track 5 + void multiTargetUpload(const std::string &sourcePath); + + // Standards + // * track01.mp3 - Disc 1, Track 1 + // * track05d02.mp3 - Disc 2, Track 5 + template + void initializeDiscAndTrack(Song &song) + { + auto disc = 1; + auto track = 1; + // If 1 go with first standard, if 2 go with the second, if 0 then will default to 1 for disc and track + auto mode = 0; + const Str &songPath = song.songPath; + + auto trd = song.songPath.find("trackd"); + auto tr = song.songPath.find("track"); + + if (tr != Str::npos) + { + mode = 1; + } + + if (trd != Str::npos) + { + mode = 2; + } + + auto dl = [](char c, char t){ return c == t; }; + auto d = Utilities::Checks::itemIterInContainer(songPath, 'd', dl); + auto k = Utilities::Checks::itemIterInContainer(songPath, 'k', dl); + auto dot = Utilities::Checks::itemIterInContainer(songPath, '.', dl); + + switch(mode) + { + case 1: + { + if (k != songPath.end() && dot != songPath.end()) + { + auto tStr = std::string(++k, dot); + std::cout << "TStr: " << tStr<<"\n"; + + if (Utilities::Checks::isNumber(tStr)) + { + track = std::atoi(tStr.c_str()); + } + } + break; + } + case 2: + { + if (k != songPath.end() && dot != songPath.end() && d != songPath.end()) + { + auto tStr = std::string(++k, d); + auto dStr = std::string(++d, dot); + std::cout<<"DStr: "< + void parseDiscAndTrack(Song &song, const Str &trackID) + { + auto sep = [](char c, char t) { return c == t; }; + auto separator = Utilities::Checks::itemIterInContainer(trackID, ':', sep); + + if (separator != trackID.end()) + { + auto dStr = Str(trackID.begin(), separator); + auto tStr = Str(++separator, trackID.end()); + + song.disc = std::atoi(dStr.c_str()); + song.track = std::atoi(tStr.c_str()); + } + else + { + auto isNumber = Utilities::Checks::isNumber(trackID); + if (isNumber) + { + song.track = std::atoi(trackID.c_str()); + } + } + } + + + // Checks for the no confirm flag. Used when uploading songs from a directory + bool checkForNoConfirm() + { + for (const auto &arg: this->icaAction.flags) + { + if (arg.flag.compare("-nc") == 0) + { + return true; + } + } + + return false; + } + + + Album retrieveMetadata(const std::string_view path); + std::string retrieveFileContent(const std::string_view path); + enum class ActionValues { deleteAct, downloadAct, retrieveAct, - uploadAct + uploadAct, + UPLOAD_SONG_WITH_METADATA // Uploads the song with metadata, including cover art }; + Models::IcarusAction icaAction; + }; } diff --git a/include/Models/Flags.h b/include/Models/Flags.h index 5e269fa..96206f5 100644 --- a/include/Models/Flags.h +++ b/include/Models/Flags.h @@ -6,8 +6,9 @@ namespace Models { -struct Flags +class Flags { +public: std::string flag; std::string value; }; diff --git a/include/Models/IcarusAction.h b/include/Models/IcarusAction.h index 39f7e54..031886d 100644 --- a/include/Models/IcarusAction.h +++ b/include/Models/IcarusAction.h @@ -2,15 +2,48 @@ #define ICARUSACTION_H_ #include +#include +#include #include +#include #include"Flags.h" namespace Models { -struct IcarusAction +class IcarusAction { +public: + std::string retrieveFlagValue(const std::string_view flag) + { + std::string value; + + const auto fg = std::find_if(flags.begin(), flags.end(), [&](Flags f) + { + return f.flag.compare(flag) == 0 ? true : false; + }); + + if (fg != flags.end()) + { + value.assign(fg->value); + } + + return value; + } + void print_action_and_flags() noexcept + { + std::cout<<"Action: "<action<<"\n"; + std::cout<<"Flag count: "<flags.size()<<"\n"; + + for (const auto &flag : this->flags) + { + std::cout<<"flag "< flags; }; diff --git a/include/Models/Song.h b/include/Models/Song.h index 7d5425d..a66c787 100644 --- a/include/Models/Song.h +++ b/include/Models/Song.h @@ -1,14 +1,66 @@ #ifndef SONG_H_ #define SONG_H_ -#include +#include +#include +#include namespace Models { -struct Song +class Song { +public: + Song() = default; + + void printInfo() + { + std::cout<<"Title: "<title<<"\n"; + std::cout<<"\n"; + } + + std::string song_path() noexcept + { + std::stringstream buffer; + + buffer << this->directory; + + const auto count = this->directory.size(); + + if (this->directory.at(count - 1) != '/' || this->directory.at(count - 1) != '\\') + { + buffer << "/"; + } + + buffer << this->filename; + + return buffer.str(); + } + + int generate_filename_from_track() + { + auto result = 0; + std::stringstream buffer; + buffer << "track"; + + // NOTE: Multiple discs in one directory is not being addressed + if (this->track < 10) + { + buffer << "0"; + } + + buffer << this->track << ".mp3"; + + + this->filename.assign(buffer.str()); + + return result; + } + + std::string toMetadataJson(); + + int id; std::string title; std::string artist; @@ -17,8 +69,20 @@ struct Song int year; int duration; int track; + int disc; std::string data; + [[deprecated("Use song_path() function instead")]] std::string songPath; + std::string filename; + std::string directory; +}; + +class CoverArt +{ +public: + int id; + std::string title; + std::string path; }; } diff --git a/include/Syncers/Upload.h b/include/Syncers/Upload.h index c7429e8..49b7ce1 100644 --- a/include/Syncers/Upload.h +++ b/include/Syncers/Upload.h @@ -1,17 +1,18 @@ #ifndef UPLOAD_H_ #define UPLOAD_H_ -#include -#include -#include +#include +#include +#include -#include +#include -#include"Managers/FileManager.h" -#include"Models/API.h" -#include"Models/Song.h" -#include"Models/Token.h" -#include"Models/UploadForm.h" +#include "Managers/CommitManager.h" +#include "Managers/FileManager.h" +#include "Models/API.h" +#include "Models/Song.h" +#include "Models/Token.h" +#include "Models/UploadForm.h" namespace fs = std::filesystem; @@ -22,16 +23,20 @@ namespace Syncers class Upload { public: - Upload(); - Upload(Models::API); + Upload() = default; + Upload(Models::API api, Models::Token token) : m_token(token), api(api) + { + this->api.endpoint = "song/data"; + } - Models::Song uploadSong(const Models::Token&, Models::Song&); - void uploadSongsFromDirectory(const Models::Token&, - const std::string&, const bool, bool); + Models::Song uploadSong(Models::Song&); + void uploadSongsFromDirectory(const std::string&, const bool, bool); + void uploadSongWithMetadata(Managers::CommitManager::Album&, Models::Song&, Models::CoverArt&); private: Managers::FileManager fMgr; Models::API api; Models::Song song; + Models::Token m_token; std::vector retrieveAllSongsFromDirectory(const std::string&, bool); diff --git a/include/Utilities/Checks.h b/include/Utilities/Checks.h new file mode 100644 index 0000000..b4c186d --- /dev/null +++ b/include/Utilities/Checks.h @@ -0,0 +1,68 @@ +#ifndef CHECKS_H_ +#define CHECKS_H_ + +#include +#include +#include + +namespace Utilities +{ + class Checks + { + public: + Checks() = delete; + + static auto isNumber(const std::string &val) + { + return !val.empty() && std::find_if(val.begin(), + val.end(), [](char c) + { + return !std::isdigit(c); + }) == val.end(); + } + + // Note: Not implemented + template + static auto itemInContainer(const Container container, const Item item, Func func) + { + auto result = false; + auto i = std::find_if(container.begin(), container.end(), [&](Item i) + { + return func(item, i); + }); + + if (i != container.end()) + { + result = true; + } + + return result; + } + + template + static auto itemIterInContainer(const Container &container, const Item &item, Func func) + { + auto result = false; + // std::cout< + template void printValue(T val); private: }; diff --git a/src/Main.cpp b/src/Main.cpp index 35e5550..eada2a0 100644 --- a/src/Main.cpp +++ b/src/Main.cpp @@ -14,7 +14,7 @@ using Managers::CommitManager; constexpr static auto IcarusDownloadManager_version() { - return "v0.1.2"; + return "v0.2.0"; } void printHelp() @@ -62,6 +62,8 @@ int main(int argc, char** argv) ActionManager actMgr(argv, argc); auto chosenAction = actMgr.retrieveIcarusAction(); + chosenAction.print_action_and_flags(); + CommitManager commitMgr(chosenAction); commitMgr.commitAction(); diff --git a/src/Managers/ActionManager.cpp b/src/Managers/ActionManager.cpp index 0e146d1..697f5d4 100644 --- a/src/Managers/ActionManager.cpp +++ b/src/Managers/ActionManager.cpp @@ -37,23 +37,6 @@ IcarusAction ActionManager::retrieveIcarusAction() const } -constexpr std::array ActionManager::supportedFlags() noexcept -{ - constexpr std::array allFlags{"-u", "-p", "-t", "-h", "-s", - "-sd", "-sr", "-d", "-D", "-b", "-rt", "-nc"}; - - return allFlags; -} - - -bool ActionManager::isNumber(string_view val) noexcept -{ - return !val.empty() && std::find_if(val.begin(), - val.end(), [](char c) - { - return !std::isdigit(c); - }) == val.end(); -} void ActionManager::initialize() { @@ -65,44 +48,33 @@ void ActionManager::initialize() } void ActionManager::validateFlags() { - cout<<"Validating flags"< 3 || isNumber(flag)) - { - flg.value = flag; + Flags flg; + cout<<"Value: "<<*flag<<"\n"; - flags.push_back(flg); - flg = Flags{}; - continue; - } - - if (std::any_of(allSupportedFlags.begin(), allSupportedFlags.end(), - [&](const char *val) - { - return !flag.compare(val); - })) + if (isValidFlag(*flag) && doesFlagHaveValue(*flag)) { - flg.flag = flag; + cout<<"Flag has value\n"; + flg.flag = *flag; + flg.value = *(++flag); + } + else if (isValidFlag(*flag)) + { + cout<<"Flag does not have a value\n"; + flg.flag = *flag; } else { - cout<<"Flag is not valid"< +#include +#include +#include +#include -#include"Models/API.h" -#include"Models/Song.h" -#include"Models/Token.h" -#include"Parsers/APIParser.h" -#include"Syncers/Delete.h" -#include"Syncers/Download.h" -#include"Syncers/RetrieveRecords.h" -#include"Syncers/Upload.h" +#include "nlohmann/json.hpp" -#include"Managers/TokenManager.h" -#include"Managers/UserManager.h" +#include "Models/API.h" +#include "Models/Song.h" +#include "Models/Token.h" +#include "Parsers/APIParser.h" +#include "Syncers/Delete.h" +#include "Syncers/Download.h" +#include "Syncers/RetrieveRecords.h" +#include "Syncers/Upload.h" + +#include "Managers/TokenManager.h" +#include "Managers/UserManager.h" using std::cout; using std::endl; @@ -31,6 +36,8 @@ using Syncers::Download; using Syncers::RetrieveRecords; using Syncers::Upload; +namespace filesystem = std::filesystem; + namespace Managers { @@ -45,6 +52,7 @@ void CommitManager::commitAction() { auto action = icaAction.action; cout<<"Commiting "< CommitManager::mapActions() noexcept @@ -74,16 +87,19 @@ std::map {"delete", ActionValues::deleteAct}, {"download", ActionValues::downloadAct}, {"retrieve", ActionValues::retrieveAct}, - {"upload", ActionValues::uploadAct} + {"upload", ActionValues::uploadAct}, + {"upload-meta", ActionValues::UPLOAD_SONG_WITH_METADATA} }; return actions; } + + Token CommitManager::parseToken(API api) { - cout<<"fetching token"<icaAction.retrieveFlagValue("-s"); + const auto metadataPath = this->icaAction.retrieveFlagValue("-m"); + const auto coverPath = this->icaAction.retrieveFlagValue("-ca"); + const auto trackID = this->icaAction.retrieveFlagValue("-t"); + const auto singleTarget = !songPath.empty() && !metadataPath.empty() && + !coverPath.empty() && !trackID.empty() ? true : false; + + const auto uni = this->icaAction.retrieveFlagValue("-smca"); + const auto multiTarget = !uni.empty() ? true : false; + + if (singleTarget && multiTarget) + { + cout<<"Cannot upload from source and directory\n"; + return; + } + + cout<<"Song path: "<(song, trackID); + + auto c = [](const Song &songA, const Song &songB) { return songA.track == songB.track && songA.disc == songB.disc; }; + auto sng = Utilities::Checks::itemIterInContainer>(album.songs, song, c); + + if (sng == album.songs.end()) + { + cout<<"Not found with disc "< songs; + Models::CoverArt cover; + string metadataPath; + + for (auto &p: fs::directory_iterator(sourcePath)) + { + const auto &pp = p.path(); + const auto stem = pp.stem(); + const auto file = pp.filename(); + const auto extension = pp.extension(); + + cout<<"Stem "<(song); + + songs.emplace_back(std::move(song)); + } + else if (extension.compare(".jpg") == 0 || extension.compare(".png") == 0) + { + cover.path.assign(pp.string()); + } + else if (extension.compare(".json") == 0) + { + metadataPath.assign(pp.string()); + } + } + + auto album = retrieveMetadata(metadataPath); + songs.clear(); + songs.assign(album.songs.begin(), album.songs.end()); + + Upload up(api, token); + + for (auto &song : songs) + { + up.uploadSongWithMetadata(album, song, cover); + } +} + +#pragma region private +CommitManager::Album CommitManager::retrieveMetadata(const std::string_view path) +{ + CommitManager::Album album; + const auto fileContent = retrieveFileContent(path); + cout<<"Parsing...\n"; + auto serialized = nlohmann::json::parse(fileContent); + cout<<"Parsed\n"; + + album.album = serialized["album"].get(); + album.albumArtist = serialized["album_artist"].get(); + album.genre = serialized["genre"].get(); + album.year = serialized["year"].get(); + album.trackCount = serialized["track_count"].get(); + album.discCount = serialized["disc_count"].get(); + album.songs.reserve(album.trackCount); + + for (auto &j : serialized["tracks"]) + { + Song song; + song.title = j["title"].get(); + song.track = j["track"].get(); + song.disc = j["disc"].get(); + song.artist = j["artist"].get(); + song.album = album.album; + song.year = album.year; + song.genre = album.genre; + song.generate_filename_from_track(); + const auto p = fs::path(path); + song.directory = p.parent_path().string(); + + album.songs.push_back(song); + } + + return album; +} + +string CommitManager::retrieveFileContent(const std::string_view path) +{ + string path_str(path); + string value; + + std::stringstream buffer; + std::fstream file(path_str, std::ios::in); + buffer<album<<"\n"; + std::cout<<"Album Artist: "<albumArtist<<"\n"; + std::cout<<"Genre: "<genre<<"\n"; + std::cout<<"Year: "<year<<"\n"; + std::cout<<"Track count: "<trackCount<<"\n"; + std::cout<<"Disc count: "<discCount<<"\n"; + std::cout<<"\n"; +} + +#pragma region Functions + } diff --git a/src/Models/Song.cpp b/src/Models/Song.cpp new file mode 100644 index 0000000..49338a7 --- /dev/null +++ b/src/Models/Song.cpp @@ -0,0 +1,22 @@ +#include "Models/Song.h" + +#include "nlohmann/json.hpp" + +using std::string; + +namespace Models +{ + string Song::toMetadataJson() + { + nlohmann::json s; + s["title"] = this->title; + s["artist"] = this->artist; + s["album"] = this->album; + s["genre"] = this->genre; + s["year"] = this->year; + s["track"] = this->track; + s["disc"] = this->disc; + + return s.dump(); + } +} \ No newline at end of file diff --git a/src/Parsers/APIParser.cpp b/src/Parsers/APIParser.cpp index 9722f56..783e3ae 100644 --- a/src/Parsers/APIParser.cpp +++ b/src/Parsers/APIParser.cpp @@ -41,7 +41,6 @@ void APIParser::parseAPI() api.url = (value[value.size()-1] == '/') ? value : value + "/"; break; } - } // TODO: For now I will hard code diff --git a/src/Syncers/Upload.cpp b/src/Syncers/Upload.cpp index 8728dc1..006691b 100644 --- a/src/Syncers/Upload.cpp +++ b/src/Syncers/Upload.cpp @@ -1,11 +1,11 @@ -#include -#include -#include +#include +#include +#include -#include -#include +#include "cpr/cpr.h" -#include"Syncers/Upload.h" +#include "Syncers/Upload.h" +#include "Utilities/Conversions.h" using std::cout; using std::cin; @@ -26,24 +26,19 @@ namespace Syncers { #pragma region Constructors -Upload::Upload() { } -Upload::Upload(API api) : api(api) -{ - this->api.endpoint = "song/data"; -} #pragma endregion #pragma region Functions -Song Upload::uploadSong(const Models::Token& token, Song& song) +Song Upload::uploadSong(Song& song) { try { auto url = retrieveUrl(); cout<<"url "<m_token.tokenType}; + auth.append(" " + this->m_token.accessToken); auto r = cpr::Post(cpr::Url{url}, cpr::Multipart{{"key", "small value"}, {"file", cpr::File{song.songPath}}}, @@ -70,12 +65,11 @@ Song Upload::uploadSong(const Models::Token& token, Song& song) auto msg = e.what(); cout<> answer; + Utilities::Conversions::toLowerChar(answer); if (answer == 'y' || answer == 'Y') { confirmUpload = true; break; } - else if (answer == 'n' || answer == 'N') - { - confirmUpload = false; - break; - } - } - - if (!confirmUpload) - { - cout << "exiting...\n"; - std::exit(-1); } cout << "uploading songs\n"; for (auto& song: songs) { - song = uploadSong(token, song); + song = uploadSong(song); } } catch (exception& e) @@ -120,10 +104,57 @@ void Upload::uploadSongsFromDirectory(const Models::Token& token, } +void Upload::uploadSongWithMetadata(Managers::CommitManager::Album &album, Models::Song& song, Models::CoverArt &cover) +{ + this->api.endpoint.assign("song/data/upload/with/data"); + + try + { + auto url = retrieveUrl(); + + cout << "url " << url << "\n"; + string auth(this->m_token.tokenType); + auth.append(" " + this->m_token.accessToken); + + nlohmann::json s; + s["title"] = song.title; + s["album"] = album.album; + s["album_artist"] = album.albumArtist; + s["artist"] = song.artist; + s["year"] = album.year; + s["genre"] = album.genre; + s["disc"] = song.disc; + s["track"] = song.track; + s["disc_count"] = album.discCount; + s["track_count"] = album.trackCount; + + const auto meta = s.dump(); + + cout<<"\n\nMeta:\n"< Upload::retrieveAllSongsFromDirectory(const std::string& directory, bool recursive) { std::vector allSongs; + if (recursive) { for (auto p: fs::recursive_directory_iterator(directory)) @@ -175,17 +206,7 @@ Song Upload::retrieveSongPath(fs::directory_entry& dirEntry) #pragma region Testing -void Upload::printSongDetails() -{ - cout<<"Song details: "<& songs) { for (auto& song: songs) @@ -201,6 +222,7 @@ void Upload::printSongDetails(std::vector& songs) cout<<"Path: "<