Added functionality to retrieve the song cover's art from Icarus
This commit is contained in:
@@ -21,6 +21,7 @@ set(CMAKE_CXX_FLAGS_RELEASE "${CMAKE_CXX_FLAGS} -O3 -std=c++17 -DNDEBUG")
|
||||
set (SOURCES
|
||||
APIRepository.cpp
|
||||
BaseRepository.cpp
|
||||
CoverArtRepository.cpp
|
||||
Demo.cpp
|
||||
RepeatRepository.cpp
|
||||
ShuffleRepository.cpp
|
||||
@@ -33,6 +34,8 @@ set (SOURCES
|
||||
set (HEADERS
|
||||
APIRepository.h
|
||||
BaseRepository.h
|
||||
model/CoverArt.h
|
||||
CoverArtRepository.h
|
||||
Demo.h
|
||||
model/APIInfo.h
|
||||
model/Song.h
|
||||
|
||||
@@ -0,0 +1,86 @@
|
||||
//
|
||||
// Created by brahmix on 11/8/19.
|
||||
//
|
||||
|
||||
#include "CoverArtRepository.h"
|
||||
|
||||
#include <curl/curl.h>
|
||||
|
||||
namespace repository {
|
||||
|
||||
/**
|
||||
template<typename C>
|
||||
std::vector<C> CoverArtRepository<C>::retrieveCoverArtRecords(const model::Token& token,
|
||||
const std::string& uri) {
|
||||
std::vector<std::string> vals;
|
||||
|
||||
return vals;
|
||||
}
|
||||
|
||||
template<typename C>
|
||||
std::vector<data> CoverArtRepository<C>::retrieveCoverArtData(const model::Token& token,
|
||||
const C& cover,
|
||||
const std::string& uri) {
|
||||
std::string fullUri(uri);
|
||||
if (fullUri.at(fullUri.size() - 1) != '/') {
|
||||
fullUri.append("/");
|
||||
}
|
||||
fullUri.append(downloadEndpoint());
|
||||
fullUri.append(std::to_string(cover.id));
|
||||
|
||||
CURL *curl;
|
||||
CURLcode res;
|
||||
struct curl_slist *chunk = nullptr;
|
||||
curl = curl_easy_init();
|
||||
|
||||
std::vector<data> vals;
|
||||
|
||||
if (!curl) {
|
||||
return vals;
|
||||
}
|
||||
|
||||
std::string data;
|
||||
std::string authHeader("Authorization: Bearer ");
|
||||
authHeader.append(token.accessToken);
|
||||
constexpr auto keepAliveHeader = "Content-type: Keep-alive";
|
||||
chunk = curl_slist_append(chunk, authHeader.c_str());
|
||||
chunk = curl_slist_append(chunk, keepAliveHeader);
|
||||
|
||||
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);
|
||||
|
||||
std::copy(data.begin(), data.end(), vals);
|
||||
|
||||
return vals;
|
||||
}
|
||||
|
||||
template<typename C>
|
||||
C CoverArtRepository<C>::retrieveCoverArtRecord(const model::Token& token,
|
||||
const C& cover,
|
||||
const std::string& uri) {
|
||||
model::CoverArt cov;
|
||||
|
||||
return cov;
|
||||
}
|
||||
|
||||
|
||||
template<typename C>
|
||||
constexpr auto CoverArtRepository<C>::downloadEndpoint() noexcept {
|
||||
return "api/v1/coverart/download";
|
||||
}
|
||||
template<typename C>
|
||||
constexpr auto CoverArtRepository<C>::recordsEndpoint() noexcept {
|
||||
return "api/v1/coverart/";
|
||||
}
|
||||
|
||||
template<typename C>
|
||||
size_t CoverArtRepository<C>::respBodyRetriever(void *ptr, size_t size, size_t nmemb, char *e) {
|
||||
((std::string*)e)->append((char*)ptr, size * nmemb);
|
||||
|
||||
return size * nmemb;
|
||||
}
|
||||
*/
|
||||
}
|
||||
@@ -0,0 +1,122 @@
|
||||
//
|
||||
// Created by brahmix on 11/8/19.
|
||||
//
|
||||
|
||||
#ifndef MEAR_COVERARTREPOSITORY_H
|
||||
#define MEAR_COVERARTREPOSITORY_H
|
||||
|
||||
#include <string>
|
||||
#include <sstream>
|
||||
#include <iterator>
|
||||
#include <vector>
|
||||
|
||||
#include <curl/curl.h>
|
||||
|
||||
#include "model/CoverArt.h"
|
||||
#include "model/Token.h"
|
||||
|
||||
using data = char;
|
||||
|
||||
namespace repository {
|
||||
template<typename C>
|
||||
class CoverArtRepository {
|
||||
public:
|
||||
std::vector<C> retrieveCoverArtRecords(const model::Token&, const std::string&);
|
||||
std::vector<data> retrieveCoverArtData(const model::Token&, const C&, const std::string&);
|
||||
|
||||
C retrieveCoverArtRecord(const model::Token&, const C&, const std::string&);
|
||||
|
||||
private:
|
||||
constexpr auto downloadEndpoint() noexcept;
|
||||
constexpr auto recordsEndpoint() noexcept;
|
||||
|
||||
static size_t respBodyRetriever(void*, size_t, size_t, char*);
|
||||
};
|
||||
|
||||
|
||||
template<typename C>
|
||||
std::vector<C> CoverArtRepository<C>::retrieveCoverArtRecords(const model::Token& token,
|
||||
const std::string& uri) {
|
||||
std::vector<std::string> vals;
|
||||
|
||||
return vals;
|
||||
}
|
||||
|
||||
template<typename C>
|
||||
std::vector<data> CoverArtRepository<C>::retrieveCoverArtData(const model::Token& token,
|
||||
const C& cover,
|
||||
const std::string& uri) {
|
||||
std::string fullUri(uri);
|
||||
if (fullUri.at(fullUri.size() - 1) != '/') {
|
||||
fullUri.append("/");
|
||||
}
|
||||
fullUri.append(downloadEndpoint());
|
||||
fullUri.append(std::to_string(cover.id));
|
||||
|
||||
CURL *curl;
|
||||
CURLcode res;
|
||||
struct curl_slist *chunk = nullptr;
|
||||
curl = curl_easy_init();
|
||||
|
||||
if (!curl) {
|
||||
return std::vector<data>();
|
||||
}
|
||||
|
||||
std::string data;
|
||||
std::string authHeader("Authorization: Bearer ");
|
||||
authHeader.append(token.accessToken);
|
||||
constexpr auto keepAliveHeader = "Content-type: Keep-alive";
|
||||
chunk = curl_slist_append(chunk, authHeader.c_str());
|
||||
chunk = curl_slist_append(chunk, keepAliveHeader);
|
||||
|
||||
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);
|
||||
|
||||
res = curl_easy_perform(curl);
|
||||
curl_easy_cleanup(curl);
|
||||
|
||||
std::stringstream buff(data);
|
||||
std::vector<char> vals(data.begin(), data.end());
|
||||
//vals.reserve(data.size());
|
||||
//vals.assign(data.begin(), data.end());
|
||||
/**
|
||||
vals.assign(std::istream_iterator<unsigned char>(buff),
|
||||
std::istream_iterator<unsigned char>());
|
||||
*/
|
||||
//std::copy(data.begin(), data.end(), &vals);
|
||||
|
||||
return vals;
|
||||
}
|
||||
|
||||
template<typename C>
|
||||
C CoverArtRepository<C>::retrieveCoverArtRecord(const model::Token& token,
|
||||
const C& cover,
|
||||
const std::string& uri) {
|
||||
model::CoverArt cov;
|
||||
|
||||
return cov;
|
||||
}
|
||||
|
||||
|
||||
template<typename C>
|
||||
constexpr auto CoverArtRepository<C>::downloadEndpoint() noexcept {
|
||||
return "api/v1/coverart/download/";
|
||||
}
|
||||
template<typename C>
|
||||
constexpr auto CoverArtRepository<C>::recordsEndpoint() noexcept {
|
||||
return "api/v1/coverart/";
|
||||
}
|
||||
|
||||
template<typename C>
|
||||
size_t CoverArtRepository<C>::respBodyRetriever(void *ptr, size_t size, size_t nmemb, char *e) {
|
||||
((std::string*)e)->append((char*)ptr, size * nmemb);
|
||||
|
||||
return size * nmemb;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
#endif //MEAR_COVERARTREPOSITORY_H
|
||||
@@ -24,6 +24,7 @@
|
||||
#include <sys/mman.h>
|
||||
|
||||
#include "APIRepository.h"
|
||||
#include "CoverArtRepository.h"
|
||||
#include "RepeatRepository.h"
|
||||
#include "ShuffleRepository.h"
|
||||
#include "SongRepository.h"
|
||||
@@ -51,6 +52,7 @@ jobject songToObj(JNIEnv *env, const model::Song& song)
|
||||
jmethodID songId = env->GetMethodID( songClass, "setId", "(I)V" );
|
||||
jmethodID songTitle = env->GetMethodID( songClass, "setTitle", "(Ljava/lang/String;)V" );
|
||||
jmethodID songAlbum = env->GetMethodID( songClass, "setAlbum", "(Ljava/lang/String;)V" );
|
||||
jmethodID songAlbumArtist = env->GetMethodID(songClass, "setAlbumArtist", "(Ljava/lang/String;)V");
|
||||
jmethodID songArtist = env->GetMethodID( songClass, "setArtist", "(Ljava/lang/String;)V" );
|
||||
jmethodID songGenre = env->GetMethodID( songClass, "setGenre", "(Ljava/lang/String;)V" );
|
||||
jmethodID songDuration = env->GetMethodID( songClass, "setDuration", "(I)V" );
|
||||
@@ -60,6 +62,7 @@ jobject songToObj(JNIEnv *env, const model::Song& song)
|
||||
jint id = song.id;
|
||||
jstring title = env->NewStringUTF(song.title.c_str());
|
||||
jstring album = env->NewStringUTF(song.album.c_str());
|
||||
jstring albumArtist = env->NewStringUTF(song.albumArtist.c_str());
|
||||
jstring artist = env->NewStringUTF(song.artist.c_str());
|
||||
jstring genre = env->NewStringUTF(song.genre.c_str());
|
||||
jint duration = song.duration;
|
||||
@@ -69,6 +72,7 @@ jobject songToObj(JNIEnv *env, const model::Song& song)
|
||||
env->CallVoidMethod( songObj, songId, id );
|
||||
env->CallVoidMethod(songObj, songTitle, title);
|
||||
env->CallVoidMethod(songObj, songAlbum, album);
|
||||
env->CallVoidMethod(songObj, songAlbumArtist, albumArtist);
|
||||
env->CallVoidMethod(songObj, songArtist, artist);
|
||||
env->CallVoidMethod(songObj, songGenre, genre);
|
||||
env->CallVoidMethod(songObj, songDuration, duration);
|
||||
@@ -113,6 +117,9 @@ model::Token fetchToken(const model::User& user, const std::string& apiUri)
|
||||
model::Token retrieveSavedToken(const std::string& path)
|
||||
{
|
||||
repository::local::TokenRepository tokenRepo;
|
||||
if (!tokenRepo.databaseExist(path)) {
|
||||
tokenRepo.initializedDatabase(path);
|
||||
}
|
||||
auto token = tokenRepo.retrieveToken(path);
|
||||
|
||||
return token;
|
||||
@@ -122,6 +129,9 @@ model::Token retrieveSavedToken(const std::string& path)
|
||||
model::User retrieveCredentials(const std::string& dataPath)
|
||||
{
|
||||
repository::local::UserRepository userRepo;
|
||||
if (!userRepo.databaseExist(dataPath)) {
|
||||
userRepo.initializedDatabase(dataPath);
|
||||
}
|
||||
auto user = userRepo.retrieveUserCredentials(dataPath);
|
||||
|
||||
return user;
|
||||
@@ -131,6 +141,9 @@ model::User retrieveCredentials(const std::string& dataPath)
|
||||
int retrieveRepeatMode(const std::string& path)
|
||||
{
|
||||
repository::local::RepeatRepository repeatRepo;
|
||||
if (!repeatRepo.databaseExist(path)) {
|
||||
repeatRepo.initializedDatabase(path);
|
||||
}
|
||||
if (!repeatRepo.doesTableExist(path)) {
|
||||
repeatRepo.createRepeatTable(path);
|
||||
}
|
||||
@@ -143,6 +156,9 @@ int retrieveRepeatMode(const std::string& path)
|
||||
int retrieveShuffleMode(const std::string& path)
|
||||
{
|
||||
repository::local::ShuffleRepository shuffleRepo;
|
||||
if (!shuffleRepo.databaseExist(path)) {
|
||||
shuffleRepo.initializedDatabase(path);
|
||||
}
|
||||
if (!shuffleRepo.doesTableExist(path)) {
|
||||
shuffleRepo.createShuffleTable(path);
|
||||
}
|
||||
@@ -236,12 +252,18 @@ void saveToken(const model::Token& token, const std::string& path)
|
||||
void updateRepeatMode(const std::string& path)
|
||||
{
|
||||
repository::local::RepeatRepository repeatRepo;
|
||||
if (!repeatRepo.databaseExist(path)) {
|
||||
repeatRepo.initializedDatabase(path);
|
||||
}
|
||||
repeatRepo.updateRepeat(path);
|
||||
}
|
||||
|
||||
void updateShuffleMode(const std::string& path)
|
||||
{
|
||||
repository::local::ShuffleRepository shuffleRepo;
|
||||
if (!shuffleRepo.databaseExist(path)) {
|
||||
shuffleRepo.initializedDatabase(path);
|
||||
}
|
||||
shuffleRepo.updateShuffle(path);
|
||||
}
|
||||
|
||||
@@ -418,6 +440,47 @@ Java_com_example_mear_repositories_UserRepository_logUser(
|
||||
}
|
||||
|
||||
|
||||
extern "C"
|
||||
JNIEXPORT jbyteArray
|
||||
JNICALL
|
||||
Java_com_example_mear_repositories_CoverArtRepository_retrieveCoverArtImage(
|
||||
JNIEnv *env,
|
||||
jobject thisObj,
|
||||
jobject tokenObj,
|
||||
jobject coverArt,
|
||||
jstring apiUri
|
||||
) {
|
||||
jclass coverArtClass = env->GetObjectClass(coverArt);
|
||||
auto idField = env->GetFieldID(coverArtClass, "id", "I");
|
||||
auto titleField = env->GetFieldID(coverArtClass, "title", "Ljava/lang/String;");
|
||||
auto id = env->GetIntField(coverArt, idField);
|
||||
auto title = (jstring)env->GetObjectField(coverArt, titleField);
|
||||
|
||||
jclass tokenClass = env->GetObjectClass(tokenObj);
|
||||
auto accessTokenId = env->GetFieldID(tokenClass, "accessToken", "Ljava/lang/String;");
|
||||
auto accessTokenVal = (jstring) env->GetObjectField(tokenObj, accessTokenId);
|
||||
|
||||
model::Token token;
|
||||
token.accessToken = env->GetStringUTFChars(accessTokenVal, nullptr);
|
||||
|
||||
model::CoverArt cover(id, env->GetStringUTFChars(title, nullptr));
|
||||
repository::CoverArtRepository<model::CoverArt> coverArtRepo;
|
||||
auto data = coverArtRepo.retrieveCoverArtData(token, cover, env->GetStringUTFChars(apiUri, nullptr));
|
||||
|
||||
jbyteArray image = env->NewByteArray(data.size());
|
||||
//for (auto& b: data) {
|
||||
env->SetByteArrayRegion(image, 0, data.size(), (jbyte*) data.data());
|
||||
//}
|
||||
//constexpr auto testImagePath = "/data/data/com.example.mear/image.png";
|
||||
//std::ofstream out(testImagePath, std::ios::out | std::ios::binary);
|
||||
//out.write(reinterpret_cast<char*>(data.data()), data.size());
|
||||
//out.close();
|
||||
|
||||
|
||||
return image;
|
||||
}
|
||||
|
||||
|
||||
extern "C"
|
||||
JNIEXPORT jint
|
||||
JNICALL
|
||||
|
||||
@@ -10,6 +10,7 @@
|
||||
#include <jni.h>
|
||||
|
||||
#include "model/APIInfo.h"
|
||||
#include "model/CoverArt.h"
|
||||
#include "model/Song.h"
|
||||
#include "model/Token.h"
|
||||
#include "model/User.h"
|
||||
|
||||
@@ -15,7 +15,8 @@ namespace repository {
|
||||
if (fullUri.at(fullUri.size()-1) != '/') {
|
||||
fullUri.append("/");
|
||||
}
|
||||
fullUri.append("api/v1/song");
|
||||
//fullUri.append("api/v1/song");
|
||||
fullUri.append(songRecordEndpoint());
|
||||
std::vector<model::Song> songs;
|
||||
|
||||
CURL *curl;
|
||||
@@ -27,29 +28,31 @@ namespace repository {
|
||||
return songs;
|
||||
}
|
||||
|
||||
constexpr auto EXPECTED_CHAR_AMOUNT = 100000;
|
||||
auto resp = std::make_unique<char[]>(EXPECTED_CHAR_AMOUNT);
|
||||
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.get());
|
||||
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.get());
|
||||
auto songsJson = nlohmann::json::parse(resp.c_str());
|
||||
for (auto& songJson: songsJson) {
|
||||
model::Song song(songJson["id"].get<int>(), songJson["title"].get<std::string>(),
|
||||
songJson["artist"].get<std::string>(), songJson["album"].get<std::string>(),
|
||||
songJson["genre"].get<std::string>(), songJson["duration"].get<int>(),
|
||||
songJson["year"].get<int>());
|
||||
song.albumArtist = songJson["album_artist"].get<std::string>();
|
||||
song.coverArtId = songJson["coverart_id"].get<int>();
|
||||
|
||||
songs.push_back(song);
|
||||
@@ -63,13 +66,13 @@ namespace repository {
|
||||
model::Song SongRepository::retrieveSong(const model::Token& token, const model::Song& sng,
|
||||
const std::string& baseUri) {
|
||||
std::string uri(baseUri);
|
||||
uri.append("/api/v1/song/");
|
||||
uri.append(songRecordEndpoint());
|
||||
uri.append(std::to_string(sng.id));
|
||||
model::Song song;
|
||||
|
||||
CURL *curl;
|
||||
CURLcode res;
|
||||
struct curl_slist *chunk = NULL;
|
||||
struct curl_slist *chunk = nullptr;
|
||||
curl = curl_easy_init();
|
||||
|
||||
if (!curl) {
|
||||
@@ -80,7 +83,9 @@ namespace repository {
|
||||
|
||||
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);
|
||||
@@ -96,6 +101,7 @@ namespace repository {
|
||||
song.id = s["id"].get<int>();
|
||||
song.title = s["title"].get<std::string>();
|
||||
song.album = s["album"].get<std::string>();
|
||||
song.albumArtist = s["album_artist"].get<std::string>();
|
||||
song.artist = s["artist"].get<std::string>();
|
||||
song.genre = s["genre"].get<std::string>();
|
||||
song.duration = s["duration"].get<int>();
|
||||
@@ -111,9 +117,14 @@ namespace repository {
|
||||
|
||||
size_t SongRepository::respBodyRetriever(void* ptr, size_t size, size_t nmemb, char *e)
|
||||
{
|
||||
std::memcpy(e, ptr, nmemb);
|
||||
e[nmemb] = '\0';
|
||||
((std::string*)e)->append((char*)ptr, size * nmemb);
|
||||
return size * nmemb;
|
||||
}
|
||||
|
||||
return nmemb;
|
||||
|
||||
/**
|
||||
constexpr auto SongRepository::songRecordEndpoint() noexcept {
|
||||
return "api/v1/song";
|
||||
}
|
||||
*/
|
||||
}
|
||||
|
||||
@@ -20,7 +20,13 @@ namespace repository {
|
||||
model::Song retrieveSong(const model::Token&, const model::Song&, const std::string&);
|
||||
private:
|
||||
static size_t respBodyRetriever(void*, size_t, size_t, char*);
|
||||
|
||||
constexpr auto songRecordEndpoint() noexcept;
|
||||
};
|
||||
|
||||
constexpr auto SongRepository::songRecordEndpoint() noexcept {
|
||||
return "api/v1/song/";
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
+24
-45
@@ -4,6 +4,7 @@
|
||||
|
||||
#include "Tok.h"
|
||||
|
||||
#include <algorithm>
|
||||
#include <memory>
|
||||
#include <cstring>
|
||||
|
||||
@@ -13,6 +14,7 @@
|
||||
namespace manager {
|
||||
model::Token Tok::fetchTokenTrans(const model::User &user, const std::string& uri) {
|
||||
CURL *curl;
|
||||
struct curl_slist *chunk = nullptr;
|
||||
CURLcode res;
|
||||
|
||||
curl = curl_easy_init();
|
||||
@@ -21,71 +23,49 @@ namespace manager {
|
||||
return model::Token("none");
|
||||
}
|
||||
|
||||
auto resp = std::make_unique<char[]>(10000);
|
||||
|
||||
std::string resp;
|
||||
const auto loginUri = fetchLoginUri(uri);
|
||||
const auto obj = userJsonString(user);
|
||||
|
||||
constexpr auto contentType = "Content-type: Keep-alive";
|
||||
chunk = curl_slist_append(chunk , contentType);
|
||||
|
||||
curl_easy_setopt(curl, CURLOPT_URL, loginUri.c_str());
|
||||
curl_easy_setopt(curl, CURLOPT_POSTFIELDS, obj.c_str());
|
||||
curl_easy_setopt(curl, CURLOPT_HTTPHEADER, chunk);
|
||||
curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, respBodyRetriever);
|
||||
curl_easy_setopt(curl, CURLOPT_WRITEDATA, resp.get());
|
||||
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.get());
|
||||
auto s = nlohmann::json::parse(resp);
|
||||
const auto tokenStr = std::move(s["token"].get<std::string>());
|
||||
|
||||
return model::Token(s["token"].get<std::string>());
|
||||
return model::Token(std::move(tokenStr));
|
||||
}
|
||||
|
||||
return model::Token("failure");
|
||||
}
|
||||
|
||||
|
||||
std::string Tok::fetchToken(const model::User &user, const std::string& uri) {
|
||||
CURL *curl;
|
||||
CURLcode res;
|
||||
|
||||
curl = curl_easy_init();
|
||||
|
||||
if (!curl) {
|
||||
return "none";
|
||||
}
|
||||
|
||||
auto resp = std::make_unique<char[]>(10000);
|
||||
|
||||
const auto loginUri = fetchLoginUri(uri);
|
||||
const auto obj = userJsonString(user);
|
||||
|
||||
curl_easy_setopt(curl, CURLOPT_URL, loginUri.c_str());
|
||||
curl_easy_setopt(curl, CURLOPT_POSTFIELDS, obj.c_str());
|
||||
curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, respBodyRetriever);
|
||||
curl_easy_setopt(curl, CURLOPT_WRITEDATA, resp.get());
|
||||
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.get());
|
||||
return s["token"].get<std::string>();
|
||||
}
|
||||
|
||||
return "failure";
|
||||
}
|
||||
|
||||
|
||||
std::string Tok::fetchLoginUri(const std::string& baseUri)
|
||||
constexpr auto Tok::loginEndpoint() noexcept
|
||||
{
|
||||
std::string uri(baseUri);
|
||||
uri.append("/api/v1/login");
|
||||
return "api/v1/login";
|
||||
}
|
||||
|
||||
std::string Tok::fetchLoginUri(const std::string& uriBase) noexcept
|
||||
{
|
||||
std::string uri(uriBase);
|
||||
if (uri.at(uri.size() - 1) != '/') {
|
||||
uri.append("/");
|
||||
}
|
||||
uri.append(loginEndpoint());
|
||||
|
||||
return uri;
|
||||
}
|
||||
|
||||
std::string Tok::userJsonString(const model::User& user)
|
||||
{
|
||||
nlohmann::json usr;
|
||||
@@ -98,9 +78,8 @@ namespace manager {
|
||||
|
||||
size_t Tok::respBodyRetriever(void* ptr, size_t size, size_t nmemb, char *e)
|
||||
{
|
||||
std::memcpy(e, ptr, nmemb);
|
||||
e[nmemb] = '\0';
|
||||
((std::string*)e)->append((char*)ptr, size * nmemb);
|
||||
|
||||
return nmemb;
|
||||
return size * nmemb;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -16,10 +16,9 @@ namespace manager {
|
||||
class Tok {
|
||||
public:
|
||||
model::Token fetchTokenTrans(const model::User&, const std::string&);
|
||||
|
||||
std::string fetchToken(const model::User&, const std::string&);
|
||||
private:
|
||||
std::string fetchLoginUri(const std::string&);
|
||||
std::string fetchLoginUri(const std::string&) noexcept;
|
||||
constexpr auto loginEndpoint() noexcept;
|
||||
std::string userJsonString(const model::User&);
|
||||
|
||||
static size_t respBodyRetriever(void*, size_t, size_t, char*);
|
||||
|
||||
@@ -26,7 +26,8 @@ namespace repository { namespace local {
|
||||
SQLite::Statement query(db, queryString);
|
||||
|
||||
auto result = query.executeStep();
|
||||
model::Token token(query.getColumn(1).getString());
|
||||
//const std::string t(query.getColumn(1).getString());
|
||||
token.accessToken = std::move(query.getColumn(1).getString());
|
||||
|
||||
return token;
|
||||
} catch (std::exception& ex) {
|
||||
|
||||
@@ -0,0 +1,22 @@
|
||||
//
|
||||
// Created by brahmix on 11/8/19.
|
||||
//
|
||||
|
||||
#ifndef MEAR_COVERART_H
|
||||
#define MEAR_COVERART_H
|
||||
|
||||
#include <string>
|
||||
|
||||
namespace model {
|
||||
class CoverArt {
|
||||
public:
|
||||
CoverArt() = default;
|
||||
CoverArt(const int id, const std::string& title) :
|
||||
id(id), title(title) { }
|
||||
|
||||
int id;
|
||||
std::string title;
|
||||
};
|
||||
}
|
||||
|
||||
#endif //MEAR_COVERART_H
|
||||
@@ -30,6 +30,7 @@ public:
|
||||
int id;
|
||||
std::string title;
|
||||
std::string artist;
|
||||
std::string albumArtist;
|
||||
std::string album;
|
||||
std::string genre;
|
||||
int duration;
|
||||
|
||||
@@ -15,7 +15,7 @@ namespace model {
|
||||
Token() = default;
|
||||
Token(const std::string& accessToken) : accessToken(accessToken) { }
|
||||
Token(const std::string&& accessToken) :
|
||||
accessToken(std::move(accessToken)) { }
|
||||
accessToken(accessToken) { }
|
||||
|
||||
std::string accessToken;
|
||||
};
|
||||
|
||||
@@ -31,7 +31,6 @@ class IcarusSongActivity : BaseServiceActivity() {
|
||||
//setSupportActionBar(toolbar)
|
||||
supportActionBar?.setDisplayHomeAsUpEnabled(true)
|
||||
|
||||
val colr = R.color.track_seek
|
||||
window.statusBarColor = resources.getColor(R.color.track_seek)
|
||||
doBindService()
|
||||
initializeAdapter()
|
||||
|
||||
@@ -1,15 +1,15 @@
|
||||
package com.example.mear.activities
|
||||
|
||||
import kotlinx.android.synthetic.main.activity_login.*
|
||||
import kotlinx.android.synthetic.main.content_login.*
|
||||
|
||||
import android.content.Intent
|
||||
import android.os.Bundle
|
||||
import android.support.design.widget.Snackbar
|
||||
import com.example.mear.R
|
||||
import com.example.mear.models.*
|
||||
|
||||
import kotlinx.android.synthetic.main.activity_login.*
|
||||
import kotlinx.android.synthetic.main.content_login.*
|
||||
import org.jetbrains.anko.toast
|
||||
|
||||
import com.example.mear.models.*
|
||||
import com.example.mear.R
|
||||
import com.example.mear.repositories.*
|
||||
|
||||
class LoginActivity : BaseServiceActivity() {
|
||||
|
||||
@@ -29,11 +29,11 @@ import org.jetbrains.anko.imageBitmap
|
||||
import com.example.mear.listeners.TrackElaspingChange
|
||||
import com.example.mear.models.Song
|
||||
import com.example.mear.R
|
||||
import com.example.mear.repositories.PlayCountRepository
|
||||
import com.example.mear.repositories.RepeatRepository
|
||||
import com.example.mear.repositories.*
|
||||
import com.example.mear.repositories.RepeatRepository.RepeatTypes
|
||||
import com.example.mear.repositories.ShuffleRepository
|
||||
import com.example.mear.repositories.ShuffleRepository.ShuffleTypes
|
||||
import com.example.mear.util.ConvertByteArray
|
||||
import org.jetbrains.anko.image
|
||||
|
||||
|
||||
class MainActivity : BaseServiceActivity() {
|
||||
@@ -44,6 +44,7 @@ class MainActivity : BaseServiceActivity() {
|
||||
private var updateLibraryHandler: Handler? = Handler()
|
||||
private var playCountUpdated: Boolean? = false
|
||||
private var serviceBinded: Boolean? = false
|
||||
private var metadataInitialized: Boolean = false
|
||||
private var repeatOn: Boolean? = false
|
||||
private var shuffleOn: Boolean? = false
|
||||
|
||||
@@ -262,12 +263,25 @@ class MainActivity : BaseServiceActivity() {
|
||||
(currSong.duration % 60)
|
||||
)
|
||||
|
||||
val coverArtRepo = CoverArtRepository()
|
||||
val apiRepo = APIRepository()
|
||||
val tokenRepo = TokenRepository()
|
||||
val path = appDirectory()
|
||||
val apiUri = apiRepo.retrieveRecord(path)
|
||||
val myToken = tokenRepo.retrieveToken(path)
|
||||
val coverArt = CoverArtRepository.CoverArt(currSong.coverArtId, currSong.title)
|
||||
val imgData = coverArtRepo.fetchCoverArtImage(myToken, coverArt, apiUri.uri)
|
||||
val ImageConvByte = ConvertByteArray(imgData)
|
||||
val convertedImage = ImageConvByte.convertToBmp(imgData)
|
||||
|
||||
|
||||
resetControls()
|
||||
|
||||
TrackTitle.text = currSong.title
|
||||
ArtistTitle.text = currSong.artist
|
||||
AlbumTitle.text = currSong.album
|
||||
TrackDuration.text = dur
|
||||
TrackCover.imageBitmap = convertedImage
|
||||
}
|
||||
}
|
||||
catch (ex: Exception) {
|
||||
@@ -298,6 +312,32 @@ class MainActivity : BaseServiceActivity() {
|
||||
}
|
||||
}
|
||||
|
||||
private fun songMetadataLoaded(): Boolean {
|
||||
if (TrackTitle.text.isEmpty()) {
|
||||
return false
|
||||
}
|
||||
if (ArtistTitle.text.isEmpty()) {
|
||||
return false
|
||||
}
|
||||
if (AlbumTitle.text.isEmpty()) {
|
||||
return false
|
||||
}
|
||||
if (TrackCover.image == null) {
|
||||
return false
|
||||
}
|
||||
|
||||
val currSong = musicService!!.getCurrentSong()
|
||||
|
||||
if (!TrackTitle.text.equals(currSong.title)) {
|
||||
return false
|
||||
}
|
||||
if ((ArtistTitle.text != currSong.artist)) {
|
||||
return false
|
||||
}
|
||||
|
||||
return true
|
||||
}
|
||||
|
||||
// TODO: Might need this down the road for playing songs off an external
|
||||
// storage
|
||||
private fun permissionPrompt() {
|
||||
@@ -348,7 +388,9 @@ class MainActivity : BaseServiceActivity() {
|
||||
private var musicTrackTimeUpdateTask = object: Runnable {
|
||||
override fun run() {
|
||||
try {
|
||||
if (!songMetadataLoaded()) {
|
||||
configureTrackDisplay()
|
||||
}
|
||||
val currentPosition = musicService!!.currentPositionOfTrack() / 1000
|
||||
val dur = String.format( "%02d:%02d", TimeUnit.SECONDS.toMinutes(currentPosition.toLong()),
|
||||
(currentPosition % 60) )
|
||||
|
||||
@@ -91,7 +91,7 @@ class SongAdapter(val mOnClickListener: (Song) -> Unit,
|
||||
this.songItem = songItems
|
||||
|
||||
v.trackTitle.setText(songItems.title)
|
||||
v.trackArtist.setText(songItems.artist)
|
||||
v.trackArtist.setText(songItems.albumArtist)
|
||||
|
||||
v.setOnClickListener { clickList(songItem!!)}
|
||||
}
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
package com.example.mear.models
|
||||
|
||||
class Song (var id: Int = 3, var title: String = "", var album: String = "", var artist: String = "",
|
||||
class Song (var id: Int = 3, var title: String = "", var album: String = "",
|
||||
var albumArtist: String = "", var artist: String = "",
|
||||
var genre: String = "", var year: Int = 0, var duration: Int = 0,
|
||||
var coverArtId: Int = 0)
|
||||
|
||||
@@ -0,0 +1,18 @@
|
||||
package com.example.mear.repositories
|
||||
|
||||
import com.example.mear.models.Token
|
||||
|
||||
class CoverArtRepository : BaseRepository() {
|
||||
|
||||
private external fun retrieveCoverArtImage(token: Token, coverArt: CoverArt, apiUri: String): ByteArray
|
||||
|
||||
|
||||
fun fetchCoverArtImage(token: Token, coverArt: CoverArt, apiUri: String): ByteArray {
|
||||
val img = retrieveCoverArtImage(token, coverArt, apiUri)
|
||||
|
||||
return img
|
||||
}
|
||||
|
||||
// TODO: Move this to it's own file later on
|
||||
class CoverArt (var id: Int = 0, var title: String = "")
|
||||
}
|
||||
@@ -7,7 +7,12 @@ class ConvertByteArray(private val byteArray: ByteArray?) {
|
||||
|
||||
fun convertToBmp(): Bitmap {
|
||||
val songImage = BitmapFactory
|
||||
.decodeByteArray(byteArray, 0, byteArray!!.size)
|
||||
.decodeByteArray(byteArray!!, 0, byteArray!!.size)
|
||||
|
||||
return songImage
|
||||
}
|
||||
fun convertToBmp(rawData: ByteArray): Bitmap {
|
||||
val songImage = BitmapFactory.decodeByteArray(rawData, 0, rawData.size)
|
||||
|
||||
return songImage
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user