339 lines
14 KiB
C++
339 lines
14 KiB
C++
//
|
|
// Created by brahmix on 10/3/19.
|
|
//
|
|
|
|
#ifndef MEAR_SONGREPOSITORY_H
|
|
#define MEAR_SONGREPOSITORY_H
|
|
|
|
#include <string>
|
|
#include <vector>
|
|
|
|
#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 Song = model::Song>
|
|
class SongRepository {
|
|
public:
|
|
template<typename Token = model::Token>
|
|
std::vector<Song> fetchSongs(const Token& token, const std::string& uri) {
|
|
auto fullUri = utility::GeneralUtility::appendForwardSlashToUri<std::string>(uri);
|
|
fullUri.append(songRecordEndpoint());
|
|
std::vector<Song> 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<int>(), songJson["title"].get<std::string>(),
|
|
songJson["artist"].get<std::string>(),
|
|
songJson["album"].get<std::string>(),
|
|
songJson["album_artist"].get<std::string>(),
|
|
songJson["genre"].get<std::string>(), songJson["duration"].get<int>(),
|
|
songJson["year"].get<int>(), songJson["coverart_id"].get<int>());
|
|
song.filename = "";
|
|
song.path = "";
|
|
song.track = songJson["track"].get<int>();
|
|
song.disc = songJson["disc"].get<int>();
|
|
song.downloaded = false;
|
|
|
|
songs.push_back(song);
|
|
}
|
|
}
|
|
|
|
return songs;
|
|
}
|
|
|
|
template<typename Token = model::Token>
|
|
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<int>(), s["title"].get<std::string>(),
|
|
s["artist"].get<std::string>(), s["album"].get<std::string>(),
|
|
s["album_artist"].get<std::string>(), s["genre"].get<std::string>(),
|
|
s["duration"].get<int>(), s["year"].get<int>(),
|
|
s["coverart_id"].get<int>());
|
|
song.track = s["track"].get<int>();
|
|
song.disc = s["disc"].get<int>();
|
|
song.filename = "";
|
|
song.path = "";
|
|
song.downloaded = false;
|
|
|
|
return song;
|
|
}
|
|
|
|
return sng;
|
|
}
|
|
|
|
template<typename Token = model::Token, typename API = model::APIInfo>
|
|
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<char>(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 Song = model::Song>
|
|
class SongRepository : public BaseRepository {
|
|
public:
|
|
SongRepository() {
|
|
m_tableName = songTable();
|
|
}
|
|
|
|
template<typename Str = std::string>
|
|
SongRepository(const Str& val) {
|
|
m_tableName = songTable();
|
|
if (!databaseExist(val)) {
|
|
initializedDatabase(val);
|
|
}
|
|
if (!doesTableExist(val)) {
|
|
createSongTable(val);
|
|
}
|
|
}
|
|
|
|
|
|
std::vector<Song> retrieveAllSongs(const std::string& appPath) {
|
|
std::vector<Song> 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
|