// // Created by brahmix on 10/3/19. // #ifndef MEAR_SONGREPOSITORY_H #define MEAR_SONGREPOSITORY_H #include #include #include "../3rdparty/android/include/curl/curl.h" #include "../3rdparty/json/single_include/nlohmann/json.hpp" #include "../model/Song.h" #include "../model/Token.h" #include "BaseRepository.h" #include "../utility/GeneralUtility.h" namespace repository { template class SongRepository { public: template std::vector fetchSongs(const Token& token, const std::string& uri) { auto fullUri = utility::GeneralUtility::appendForwardSlashToUri(uri); fullUri.append(songRecordEndpoint()); std::vector songs; CURL *curl; CURLcode res; struct curl_slist *chunk = nullptr; curl = curl_easy_init(); if (!curl) { return songs; } std::string resp; std::string authInfo("Authorization: Bearer "); authInfo.append(token.accessToken); constexpr auto contentType = "Content-type: Keep-alive"; chunk = curl_slist_append(chunk, authInfo.c_str()); chunk = curl_slist_append(chunk, contentType); curl_easy_setopt(curl, CURLOPT_URL, fullUri.c_str()); curl_easy_setopt(curl, CURLOPT_HTTPHEADER, chunk); curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, respBodyRetriever); curl_easy_setopt(curl, CURLOPT_WRITEDATA, &resp); curl_easy_setopt(curl, CURLOPT_SSL_VERIFYPEER, 0L); res = curl_easy_perform(curl); curl_easy_cleanup(curl); if (res == CURLE_OK) { auto songsJson = nlohmann::json::parse(resp.c_str()); for (auto& songJson: songsJson) { Song song(songJson["id"].get(), songJson["title"].get(), songJson["artist"].get(), songJson["album"].get(), songJson["album_artist"].get(), songJson["genre"].get(), songJson["duration"].get(), songJson["year"].get(), songJson["coverart_id"].get()); song.filename = ""; song.path = ""; song.track = songJson["track"].get(); song.disc = songJson["disc"].get(); song.downloaded = false; songs.push_back(song); } } return songs; } template Song retrieveSong(const Token& token, const Song& sng, const std::string& baseUri) { auto uri = utility::GeneralUtility::appendForwardSlashToUri(baseUri); uri.append(songRecordEndpoint()); uri.append(std::to_string(sng.id)); CURL *curl; CURLcode res; struct curl_slist *chunk = nullptr; curl = curl_easy_init(); if (!curl) { return sng; } std::string resp; std::string authInfo("Authorization: Bearer "); authInfo.append(token.accessToken); constexpr auto contentType = "Content-type: Keep-alive"; chunk = curl_slist_append(chunk, authInfo.c_str()); chunk = curl_slist_append(chunk, contentType); curl_easy_setopt(curl, CURLOPT_URL, uri.c_str()); curl_easy_setopt(curl, CURLOPT_HTTPHEADER, chunk); curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, respBodyRetriever); curl_easy_setopt(curl, CURLOPT_WRITEDATA, &resp); curl_easy_setopt(curl, CURLOPT_SSL_VERIFYPEER, 0L); res = curl_easy_perform(curl); curl_easy_cleanup(curl); if (res == CURLE_OK) { auto s = nlohmann::json::parse(resp.c_str()); Song song(s["id"].get(), s["title"].get(), s["artist"].get(), s["album"].get(), s["album_artist"].get(), s["genre"].get(), s["duration"].get(), s["year"].get(), s["coverart_id"].get()); song.track = s["track"].get(); song.disc = s["disc"].get(); song.filename = ""; song.path = ""; song.downloaded = false; return song; } return sng; } template Song downloadSong(const Token &token, const Song& song, const API& uri) { auto fullUri = utility::GeneralUtility::appendForwardSlashToUri(uri.uri); fullUri.append(songDownloadEndpoint()); fullUri.append(std::to_string(song.id)); Song downloadedSong = song; CURL *curl = curl_easy_init(); struct curl_slist *chunk = nullptr; std::string data; const auto authHeader = utility::GeneralUtility::authHeader(token); chunk = curl_slist_append(chunk, authHeader.c_str()); chunk = curl_slist_append(chunk, "Content-type: Keep-alive"); curl_easy_setopt(curl, CURLOPT_URL, fullUri.c_str()); curl_easy_setopt(curl, CURLOPT_HTTPHEADER, chunk); curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, respBodyRetriever); curl_easy_setopt(curl, CURLOPT_WRITEDATA, &data); curl_easy_setopt(curl, CURLOPT_SSL_VERIFYPEER, 0L); auto res = curl_easy_perform(curl); curl_easy_cleanup(curl); downloadedSong.data = std::move(std::vector(data.begin(), data.end())); return downloadedSong; } private: static size_t respBodyRetriever(void *ptr, size_t size, size_t nmemb, char *e) { ((std::string*)e)->append((char*)ptr, size * nmemb); return size * nmemb; } constexpr auto songRecordEndpoint() noexcept { return "api/v1/song/"; } constexpr auto songDownloadEndpoint() noexcept { return "api/v1/song/data/"; } }; namespace local { template class SongRepository : public BaseRepository { public: SongRepository() { m_tableName = songTable(); } template SongRepository(const Str& val) { m_tableName = songTable(); if (!databaseExist(val)) { initializedDatabase(val); } if (!doesTableExist(val)) { createSongTable(val); } } std::vector retrieveAllSongs(const std::string& appPath) { std::vector downloadedSongs; try { const auto dbPath = pathOfDatabase(appPath); SQLite::Database db(dbPath, SQLite::OPEN_READONLY); std::string queryString("SELECT * FROM "); queryString.append(m_tableName); SQLite::Statement query(db, queryString); while (query.executeStep()) { Song song; song.id = query.getColumn(0).getInt(); song.title = query.getColumn(1).getString(); song.artist = query.getColumn(2).getString(); song.album = query.getColumn(3).getString(); song.albumArtist = query.getColumn(4).getString(); song.genre = query.getColumn(5).getString(); song.year = query.getColumn(6).getInt(); song.duration = query.getColumn(7).getInt(); song.track = query.getColumn(8).getInt(); song.disc = query.getColumn(9).getInt(); song.filename = query.getColumn(10).getString(); song.path = query.getColumn(11).getString(); song.coverArtId = query.getColumn(12).getInt(); song.downloaded = true; downloadedSongs.push_back(song); } } catch (std::exception& ex) { auto msg = ex.what(); } return downloadedSongs; } Song retrieveSong(const Song& song, const std::string& appPath) { Song retrievedSong; try { const auto dbPath = pathOfDatabase(appPath); SQLite::Database db(dbPath, SQLite::OPEN_READONLY); std::string queryString("SELECT * FROM "); queryString.append(m_tableName); queryString.append(" WHERE Id = ?"); queryString.append(" LIMIT 1"); SQLite::Statement query(db, queryString); query.bind(1, song.id); auto result = query.executeStep(); retrievedSong.id = query.getColumn(0).getInt(); retrievedSong.title = query.getColumn(1).getString(); retrievedSong.artist = query.getColumn(2).getString(); retrievedSong.album = query.getColumn(3).getString(); retrievedSong.albumArtist = query.getColumn(4).getString(); retrievedSong.genre = query.getColumn(5).getString(); retrievedSong.year = query.getColumn(6).getInt(); retrievedSong.duration = query.getColumn(7).getInt(); retrievedSong.track = query.getColumn(8).getInt(); retrievedSong.disc = query.getColumn(9).getInt(); retrievedSong.filename = query.getColumn(10).getString(); retrievedSong.path = query.getColumn(11).getString(); retrievedSong.coverArtId = query.getColumn(12).getInt(); retrievedSong.downloaded = true; } catch (std::exception& ex) { auto msg = ex.what(); } return retrievedSong; } void createSongTable(const std::string& appPath) { try { const auto dbPath = pathOfDatabase(appPath); SQLite::Database db(dbPath, SQLite::OPEN_READWRITE); std::string queryString("CREATE TABLE "); queryString.append(m_tableName); queryString.append(" (Id INTEGER, Title TEXT, Artist TEXT, Album TEXT, "); queryString.append("AlbumArtist TEXT, Genre TEXT, Year INTEGER, "); queryString.append("Duration INTEGER, Track INTEGER, Disc INTEGER, "); queryString.append("Filename TEXT, Path TEXT, CoverArtId INTEGER)"); db.exec(queryString); } catch (std::exception& ex) { auto msg = ex.what(); } } void deleteSongFromTable(const Song& song, const std::string& appPath) { try { const auto dbPath = pathOfDatabase(appPath); SQLite::Database db(dbPath, SQLite::OPEN_READWRITE); std::string queryString("DELETE FROM "); queryString.append(m_tableName); queryString.append(" WHERE Id = ?"); SQLite::Statement query(db, queryString); query.bind(1, song.id); query.exec(); } catch (std::exception& ex) { auto msg = ex.what(); } } void saveSong(const Song& song, const std::string& appPath) { try { const auto dbPath = pathOfDatabase(appPath); SQLite::Database db(dbPath, SQLite::OPEN_READWRITE); std::string queryString("INSERT INTO "); queryString.append(m_tableName); queryString.append(" (Id, Title, Artist, Album, AlbumArtist, Genre, Year, "); queryString.append("Duration, Track, Disc, Filename, Path, CoverArtId) "); queryString.append("VALUES(?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)"); SQLite::Statement query(db, queryString); query.bind(1, song.id); query.bind(2, song.title); query.bind(3, song.artist); query.bind(4, song.album); query.bind(5, song.albumArtist); query.bind(6, song.genre); query.bind(7, song.year); query.bind(8, song.duration); query.bind(9, song.track); query.bind(10, song.disc); query.bind(11, song.filename); query.bind(12, song.path); query.bind(13, song.coverArtId); auto result = query.exec(); } catch (std::exception& ex) { auto msg = ex.what(); } } private: constexpr auto songTable() noexcept { return "Song"; } }; } } #endif //MEAR_SONGREPOSITORY_H