Working on HTTP endpoint to delete songs. Finished with album. Need to work on the Artist, Genre, and Year aspects
This commit is contained in:
@@ -1,6 +1,7 @@
|
|||||||
#ifndef ALBUMREPOSITORY_H_
|
#ifndef ALBUMREPOSITORY_H_
|
||||||
#define ALBUMREPOSITORY_H_
|
#define ALBUMREPOSITORY_H_
|
||||||
|
|
||||||
|
#include <utility>
|
||||||
#include <vector>
|
#include <vector>
|
||||||
|
|
||||||
#include "database/BaseRepository.h"
|
#include "database/BaseRepository.h"
|
||||||
@@ -16,14 +17,19 @@ namespace database
|
|||||||
|
|
||||||
std::vector<model::Album> retrieveRecords();
|
std::vector<model::Album> retrieveRecords();
|
||||||
|
|
||||||
|
std::pair<model::Album, int> retrieveRecordWithSongCount(model::Album&, type::AlbumFilter);
|
||||||
|
|
||||||
model::Album retrieveRecord(model::Album&, type::AlbumFilter);
|
model::Album retrieveRecord(model::Album&, type::AlbumFilter);
|
||||||
|
|
||||||
bool doesAlbumExists(const model::Album&, type::AlbumFilter);
|
bool doesAlbumExists(const model::Album&, type::AlbumFilter);
|
||||||
|
|
||||||
void saveAlbum(const model::Album&);
|
void saveAlbum(const model::Album&);
|
||||||
|
void deleteAlbum(const model::Album&, type::AlbumFilter);
|
||||||
private:
|
private:
|
||||||
std::vector<model::Album> parseRecords(MYSQL_STMT*);
|
std::vector<model::Album> parseRecords(MYSQL_STMT*);
|
||||||
|
|
||||||
|
std::pair<model::Album, int> parseRecordWithSongCount(MYSQL_STMT*);
|
||||||
|
|
||||||
// TODO: after parseRecord(MYSQL_STMT*) is implemented remove
|
// TODO: after parseRecord(MYSQL_STMT*) is implemented remove
|
||||||
// parseRecord(MYSQL_RES*)
|
// parseRecord(MYSQL_RES*)
|
||||||
model::Album parseRecord(MYSQL_RES*);
|
model::Album parseRecord(MYSQL_RES*);
|
||||||
|
|||||||
@@ -13,6 +13,8 @@ namespace manager
|
|||||||
model::Album retrieveAlbum(model::Album&);
|
model::Album retrieveAlbum(model::Album&);
|
||||||
model::Album saveAlbum(const model::Song&);
|
model::Album saveAlbum(const model::Song&);
|
||||||
|
|
||||||
|
void deleteAlbum(const model::Song&);
|
||||||
|
|
||||||
static void printAlbum(const model::Album&);
|
static void printAlbum(const model::Album&);
|
||||||
private:
|
private:
|
||||||
model::BinaryPath m_bConf;
|
model::BinaryPath m_bConf;
|
||||||
|
|||||||
@@ -14,6 +14,8 @@ namespace manager
|
|||||||
CoverArtManager(const model::BinaryPath& bConf);
|
CoverArtManager(const model::BinaryPath& bConf);
|
||||||
|
|
||||||
model::Cover saveCover(const model::Song&, std::string&, const std::string&);
|
model::Cover saveCover(const model::Song&, std::string&, const std::string&);
|
||||||
|
|
||||||
|
void deleteCover(const model::Song&);
|
||||||
private:
|
private:
|
||||||
model::BinaryPath m_bConf;
|
model::BinaryPath m_bConf;
|
||||||
std::string path;
|
std::string path;
|
||||||
|
|||||||
@@ -23,6 +23,7 @@ namespace manager
|
|||||||
private:
|
private:
|
||||||
void saveSongTemp(model::Song&);
|
void saveSongTemp(model::Song&);
|
||||||
void saveMisc(model::Song&);
|
void saveMisc(model::Song&);
|
||||||
|
void deleteMisc(const model::Song&);
|
||||||
|
|
||||||
model::BinaryPath m_bConf;
|
model::BinaryPath m_bConf;
|
||||||
std::string exe_path;
|
std::string exe_path;
|
||||||
|
|||||||
@@ -32,6 +32,11 @@ namespace model
|
|||||||
struct Artist
|
struct Artist
|
||||||
{
|
{
|
||||||
Artist() = default;
|
Artist() = default;
|
||||||
|
Artist(const Song& song)
|
||||||
|
{
|
||||||
|
id = song.artistId;
|
||||||
|
artist = song.artist;
|
||||||
|
}
|
||||||
Artist(const int id) : id(id) { }
|
Artist(const int id) : id(id) { }
|
||||||
|
|
||||||
int id;
|
int id;
|
||||||
@@ -41,6 +46,12 @@ namespace model
|
|||||||
struct Album
|
struct Album
|
||||||
{
|
{
|
||||||
Album() = default;
|
Album() = default;
|
||||||
|
Album(const Song& song)
|
||||||
|
{
|
||||||
|
id = song.albumId;
|
||||||
|
title = song.album;
|
||||||
|
year = song.year;
|
||||||
|
}
|
||||||
Album(const int id) : id(id) { }
|
Album(const int id) : id(id) { }
|
||||||
|
|
||||||
int id;
|
int id;
|
||||||
@@ -52,6 +63,11 @@ namespace model
|
|||||||
struct Genre
|
struct Genre
|
||||||
{
|
{
|
||||||
Genre() = default;
|
Genre() = default;
|
||||||
|
Genre(const Song& song)
|
||||||
|
{
|
||||||
|
id = song.genreId;
|
||||||
|
category = song.genre;
|
||||||
|
}
|
||||||
Genre(const int id) : id(id) { }
|
Genre(const int id) : id(id) { }
|
||||||
|
|
||||||
int id;
|
int id;
|
||||||
@@ -62,6 +78,11 @@ namespace model
|
|||||||
struct Year
|
struct Year
|
||||||
{
|
{
|
||||||
Year() = default;
|
Year() = default;
|
||||||
|
Year(const Song& song)
|
||||||
|
{
|
||||||
|
id = song.yearId;
|
||||||
|
year = song.year;
|
||||||
|
}
|
||||||
Year(const int id) : id(id) { }
|
Year(const int id) : id(id) { }
|
||||||
|
|
||||||
int id;
|
int id;
|
||||||
@@ -71,6 +92,11 @@ namespace model
|
|||||||
struct Cover
|
struct Cover
|
||||||
{
|
{
|
||||||
Cover() = default;
|
Cover() = default;
|
||||||
|
Cover(const Song& song)
|
||||||
|
{
|
||||||
|
id = song.coverArtId;
|
||||||
|
songTitle = song.title;
|
||||||
|
}
|
||||||
Cover(const int id) : id(id) { }
|
Cover(const int id) : id(id) { }
|
||||||
|
|
||||||
int id;
|
int id;
|
||||||
|
|||||||
@@ -29,6 +29,51 @@ std::vector<model::Album> database::AlbumRepository::retrieveRecords()
|
|||||||
return albums;
|
return albums;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
std::pair<model::Album, int> database::AlbumRepository::retrieveRecordWithSongCount(model::Album& album, type::AlbumFilter filter = type::AlbumFilter::id)
|
||||||
|
{
|
||||||
|
std::stringstream qry;
|
||||||
|
auto conn = setupMysqlConnection();
|
||||||
|
auto stmt = mysql_stmt_init(conn);
|
||||||
|
|
||||||
|
MYSQL_BIND params[4];
|
||||||
|
std::memset(params, 0, sizeof(params));
|
||||||
|
|
||||||
|
qry << "SELECT alb.*, COUNT(*) AS SongCount FROM Album alb LEFT JOIN ";
|
||||||
|
qry << "Song sng ON alb.AlbumId=sng.AlbumId WHERE ";
|
||||||
|
|
||||||
|
switch (filter) {
|
||||||
|
case type::AlbumFilter::id:
|
||||||
|
qry << "alb.AlbumId = ?";
|
||||||
|
|
||||||
|
params[0].buffer_type = MYSQL_TYPE_LONG;
|
||||||
|
params[0].buffer = (char*)&album.id;
|
||||||
|
params[0].length = 0;
|
||||||
|
params[0].is_null = 0;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
qry << " GROUP BY alb.AlbumId LIMIT 1";
|
||||||
|
|
||||||
|
const auto query = qry.str();
|
||||||
|
|
||||||
|
auto status = mysql_stmt_prepare(stmt, query.c_str(), query.size());
|
||||||
|
status = mysql_stmt_bind_param(stmt, params);
|
||||||
|
status = mysql_stmt_execute(stmt);
|
||||||
|
|
||||||
|
std::cout << "query has been performed" << std::endl;
|
||||||
|
|
||||||
|
auto albWSC = parseRecordWithSongCount(stmt);
|
||||||
|
|
||||||
|
mysql_stmt_close(stmt);
|
||||||
|
mysql_close(conn);
|
||||||
|
|
||||||
|
std::cout << "record has been parsed" << std::endl;
|
||||||
|
|
||||||
|
return albWSC;
|
||||||
|
}
|
||||||
|
|
||||||
model::Album database::AlbumRepository::retrieveRecord(model::Album& album, type::AlbumFilter filter)
|
model::Album database::AlbumRepository::retrieveRecord(model::Album& album, type::AlbumFilter filter)
|
||||||
{
|
{
|
||||||
std::cout << "retrieving album record" << std::endl;
|
std::cout << "retrieving album record" << std::endl;
|
||||||
@@ -165,9 +210,45 @@ void database::AlbumRepository::saveAlbum(const model::Album& album)
|
|||||||
std::cout << "done inserting album record" << std::endl;
|
std::cout << "done inserting album record" << std::endl;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void database::AlbumRepository::deleteAlbum(const model::Album& album, type::AlbumFilter filter = type::AlbumFilter::id)
|
||||||
|
{
|
||||||
|
std::cout << "deleting album record" << std::endl;
|
||||||
|
|
||||||
|
std::stringstream qry;
|
||||||
|
auto conn = setupMysqlConnection();
|
||||||
|
auto stmt = mysql_stmt_init(conn);
|
||||||
|
|
||||||
|
MYSQL_BIND params[1];
|
||||||
|
std::memset(params, 0, sizeof(params));
|
||||||
|
|
||||||
|
qry << "DELETE FROM Album WHERE ";
|
||||||
|
|
||||||
|
switch (filter) {
|
||||||
|
case type::AlbumFilter::id:
|
||||||
|
qry << "AlbumId = ?";
|
||||||
|
|
||||||
|
params[0].buffer_type = MYSQL_TYPE_LONG;
|
||||||
|
params[0].buffer = (char*)&album.id;
|
||||||
|
params[0].length = 0;
|
||||||
|
params[0].is_null = 0;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
const auto query = qry.str();
|
||||||
|
|
||||||
|
auto status = mysql_stmt_prepare(stmt, query.c_str(), query.size());
|
||||||
|
status = mysql_stmt_bind_param(stmt, params);
|
||||||
|
status = mysql_stmt_execute(stmt);
|
||||||
|
|
||||||
|
std::cout << "execute delete query" << std::endl;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
std::vector<model::Album> database::AlbumRepository::parseRecords(MYSQL_STMT* stmt)
|
std::vector<model::Album> database::AlbumRepository::parseRecords(MYSQL_STMT* stmt)
|
||||||
{
|
{
|
||||||
|
std::cout << "parsing album record" << std::endl;
|
||||||
mysql_stmt_store_result(stmt);
|
mysql_stmt_store_result(stmt);
|
||||||
|
|
||||||
std::vector<model::Album> albums;
|
std::vector<model::Album> albums;
|
||||||
@@ -225,6 +306,7 @@ std::vector<model::Album> database::AlbumRepository::parseRecords(MYSQL_STMT* st
|
|||||||
return albums;
|
return albums;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// TODO: check to see if this is not used, if not then remove it
|
||||||
model::Album database::AlbumRepository::parseRecord(MYSQL_RES* results)
|
model::Album database::AlbumRepository::parseRecord(MYSQL_RES* results)
|
||||||
{
|
{
|
||||||
std::cout << "parsing album record" << std::endl;
|
std::cout << "parsing album record" << std::endl;
|
||||||
@@ -250,6 +332,65 @@ model::Album database::AlbumRepository::parseRecord(MYSQL_RES* results)
|
|||||||
return album;
|
return album;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
std::pair<model::Album, int> database::AlbumRepository::parseRecordWithSongCount(MYSQL_STMT *stmt)
|
||||||
|
{
|
||||||
|
std::cout << "parsing album record with song count" << std::endl;
|
||||||
|
mysql_stmt_store_result(stmt);
|
||||||
|
auto rowCount = mysql_stmt_num_rows(stmt);
|
||||||
|
std::cout << "result count " << rowCount << std::endl;
|
||||||
|
|
||||||
|
model::Album album;
|
||||||
|
int songCount;
|
||||||
|
|
||||||
|
if (mysql_stmt_field_count(stmt) == 0) {
|
||||||
|
std::cout << "field count is 0, must be an incorrect query" << std::endl;
|
||||||
|
return std::make_pair(model::Album(), 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
auto res = mysql_stmt_result_metadata(stmt);
|
||||||
|
const auto valAmt = 4;
|
||||||
|
const auto strLen = 1024;
|
||||||
|
unsigned long len[valAmt];
|
||||||
|
my_bool nullRes[valAmt];
|
||||||
|
|
||||||
|
MYSQL_BIND val[valAmt];
|
||||||
|
std::memset(val, 0, sizeof(val));
|
||||||
|
|
||||||
|
char title[strLen];
|
||||||
|
|
||||||
|
val[0].buffer_type = MYSQL_TYPE_LONG;
|
||||||
|
val[0].buffer = (char*)&album.id;
|
||||||
|
val[0].length = &len[0];
|
||||||
|
val[0].is_null = &nullRes[0];
|
||||||
|
|
||||||
|
val[1].buffer_type = MYSQL_TYPE_STRING;
|
||||||
|
val[1].buffer = (char*)title;
|
||||||
|
val[1].buffer_length = strLen;
|
||||||
|
val[1].length = &len[1];
|
||||||
|
val[1].is_null = &nullRes[1];
|
||||||
|
|
||||||
|
val[2].buffer_type = MYSQL_TYPE_LONG;
|
||||||
|
val[2].buffer = (char*)&album.year;
|
||||||
|
val[2].length = &len[2];
|
||||||
|
val[2].is_null = &nullRes[2];
|
||||||
|
|
||||||
|
val[3].buffer_type = MYSQL_TYPE_LONG;
|
||||||
|
val[3].buffer = (char*)&songCount;
|
||||||
|
val[3].length = &len[2];
|
||||||
|
val[3].is_null = &nullRes[2];
|
||||||
|
|
||||||
|
auto status = mysql_stmt_bind_result(stmt, val);
|
||||||
|
status = mysql_stmt_fetch(stmt);
|
||||||
|
|
||||||
|
album.title = std::move(title);
|
||||||
|
|
||||||
|
std::cout << "done parsing album record with song count" << std::endl;
|
||||||
|
|
||||||
|
auto albWSC = std::make_pair(album, songCount);
|
||||||
|
|
||||||
|
return albWSC;
|
||||||
|
}
|
||||||
|
|
||||||
model::Album database::AlbumRepository::parseRecord(MYSQL_STMT *stmt)
|
model::Album database::AlbumRepository::parseRecord(MYSQL_STMT *stmt)
|
||||||
{
|
{
|
||||||
std::cout << "parsing album record" << std::endl;
|
std::cout << "parsing album record" << std::endl;
|
||||||
|
|||||||
@@ -211,6 +211,7 @@ model::Year database::YearRepository::parseRecord(MYSQL_RES *results)
|
|||||||
model::Year database::YearRepository::parseRecord(MYSQL_STMT *stmt)
|
model::Year database::YearRepository::parseRecord(MYSQL_STMT *stmt)
|
||||||
{
|
{
|
||||||
// TODO: imeplement this
|
// TODO: imeplement this
|
||||||
|
// I really thought that I had already done this
|
||||||
|
|
||||||
model::Year year;
|
model::Year year;
|
||||||
|
|
||||||
|
|||||||
@@ -36,6 +36,23 @@ model::Album manager::AlbumManager::saveAlbum(const model::Song& song)
|
|||||||
return album;
|
return album;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void manager::AlbumManager::deleteAlbum(const model::Song& song)
|
||||||
|
{
|
||||||
|
model::Album album(song);
|
||||||
|
|
||||||
|
database::AlbumRepository albRepo(m_bConf);
|
||||||
|
auto albWSC = albRepo.retrieveRecordWithSongCount(album, type::AlbumFilter::id);
|
||||||
|
|
||||||
|
if (albWSC.second > 1) {
|
||||||
|
std::cout << "album still contain songs related to it, will not delete" << std::endl;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::cout << "safe to delete the album record" << std::endl;
|
||||||
|
albRepo.deleteAlbum(album, type::AlbumFilter::id);
|
||||||
|
}
|
||||||
|
|
||||||
void manager::AlbumManager::printAlbum(const model::Album& album)
|
void manager::AlbumManager::printAlbum(const model::Album& album)
|
||||||
{
|
{
|
||||||
std::cout << "\nalbum record" << std::endl;
|
std::cout << "\nalbum record" << std::endl;
|
||||||
|
|||||||
@@ -1,9 +1,15 @@
|
|||||||
#include "manager/CoverArtManager.h"
|
#include "manager/CoverArtManager.h"
|
||||||
|
|
||||||
|
#include <iostream>
|
||||||
|
#include <filesystem>
|
||||||
|
|
||||||
#include "database/CoverArtRepository.h"
|
#include "database/CoverArtRepository.h"
|
||||||
|
#include "manager/DirectoryManager.h"
|
||||||
#include "type/CoverFilter.h"
|
#include "type/CoverFilter.h"
|
||||||
#include "utility/MetadataRetriever.h"
|
#include "utility/MetadataRetriever.h"
|
||||||
|
|
||||||
|
namespace fs = std::filesystem;
|
||||||
|
|
||||||
manager::CoverArtManager::CoverArtManager(const std::string& configPath) : path(configPath)
|
manager::CoverArtManager::CoverArtManager(const std::string& configPath) : path(configPath)
|
||||||
{ }
|
{ }
|
||||||
|
|
||||||
@@ -32,3 +38,29 @@ model::Cover manager::CoverArtManager::saveCover(const model::Song& song, std::s
|
|||||||
|
|
||||||
return cov;
|
return cov;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void manager::CoverArtManager::deleteCover(const model::Song& song)
|
||||||
|
{
|
||||||
|
database::CoverArtRepository covRepo(m_bConf);
|
||||||
|
|
||||||
|
model::Cover cov(song.coverArtId);
|
||||||
|
|
||||||
|
cov = covRepo.retrieveRecord(cov, type::CoverFilter::id);
|
||||||
|
covRepo.deleteRecord(cov);
|
||||||
|
|
||||||
|
auto paths = manager::DirectoryManager::pathConfigContent(m_bConf);
|
||||||
|
|
||||||
|
const auto coverArtPath = paths["cover_root_path"].get<std::string>();
|
||||||
|
std::string stockCoverArtPath = coverArtPath;
|
||||||
|
stockCoverArtPath.append("CoverArt.png");
|
||||||
|
|
||||||
|
if (stockCoverArtPath.compare(cov.imagePath) != 0) {
|
||||||
|
fs::remove(cov.imagePath);
|
||||||
|
std::cout << "deleting cover art" << std::endl;
|
||||||
|
} else {
|
||||||
|
std::cout << "song contains the stock cover art, will not delete" << std::endl;
|
||||||
|
}
|
||||||
|
|
||||||
|
manager::DirectoryManager::deleteDirectories(song, coverArtPath);
|
||||||
|
}
|
||||||
|
|||||||
+19
-15
@@ -48,30 +48,18 @@ void manager::SongManager::deleteSong(model::Song& song)
|
|||||||
// TODO: handle what happens to miscellanes records
|
// TODO: handle what happens to miscellanes records
|
||||||
// like Album, Artist, Genre, etc. when a song
|
// like Album, Artist, Genre, etc. when a song
|
||||||
// is deleted
|
// is deleted
|
||||||
database::CoverArtRepository covRepo(m_bConf);
|
|
||||||
database::SongRepository songRepo(m_bConf);
|
database::SongRepository songRepo(m_bConf);
|
||||||
|
|
||||||
song = songRepo.retrieveRecord(song, type::SongFilter::id);
|
song = songRepo.retrieveRecord(song, type::SongFilter::id);
|
||||||
songRepo.deleteRecord(song);
|
|
||||||
|
|
||||||
model::Cover cov;
|
|
||||||
cov.id = song.coverArtId;
|
|
||||||
cov = covRepo.retrieveRecord(cov, type::CoverFilter::id);
|
|
||||||
covRepo.deleteRecord(cov);
|
|
||||||
|
|
||||||
auto paths = manager::DirectoryManager::pathConfigContent(m_bConf);
|
auto paths = manager::DirectoryManager::pathConfigContent(m_bConf);
|
||||||
const auto coverArtPath = paths["cover_root_path"].get<std::string>();
|
deleteMisc(song);
|
||||||
std::string stockCoverArtPath = coverArtPath;
|
|
||||||
stockCoverArtPath.append("CoverArt.png");
|
songRepo.deleteRecord(song);
|
||||||
|
|
||||||
if (stockCoverArtPath.compare(cov.imagePath) != 0) {
|
|
||||||
fs::remove(cov.imagePath);
|
|
||||||
std::cout << "deleting cover art" << std::endl;
|
|
||||||
}
|
|
||||||
fs::remove(song.songPath);
|
fs::remove(song.songPath);
|
||||||
|
|
||||||
manager::DirectoryManager::deleteDirectories(song, paths["root_music_path"].get<std::string>());
|
manager::DirectoryManager::deleteDirectories(song, paths["root_music_path"].get<std::string>());
|
||||||
manager::DirectoryManager::deleteDirectories(song, coverArtPath);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void manager::SongManager::printSong(const model::Song& song)
|
void manager::SongManager::printSong(const model::Song& song)
|
||||||
@@ -111,6 +99,7 @@ void manager::SongManager::saveSongTemp(model::Song& song)
|
|||||||
|
|
||||||
song.songPath = tmpSongPath;
|
song.songPath = tmpSongPath;
|
||||||
}
|
}
|
||||||
|
|
||||||
void manager::SongManager::saveMisc(model::Song& song)
|
void manager::SongManager::saveMisc(model::Song& song)
|
||||||
{
|
{
|
||||||
CoverArtManager covMgr(m_bConf);
|
CoverArtManager covMgr(m_bConf);
|
||||||
@@ -164,3 +153,18 @@ void manager::SongManager::saveMisc(model::Song& song)
|
|||||||
|
|
||||||
std::cout << "done with miscellaneous database records" << std::endl;
|
std::cout << "done with miscellaneous database records" << std::endl;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void manager::SongManager::deleteMisc(const model::Song& song)
|
||||||
|
{
|
||||||
|
manager::CoverArtManager covMgr(m_bConf);
|
||||||
|
covMgr.deleteCover(song);
|
||||||
|
|
||||||
|
manager::AlbumManager albMgr(m_bConf);
|
||||||
|
albMgr.deleteAlbum(song);
|
||||||
|
|
||||||
|
manager::ArtistManager artMgr(m_bConf);
|
||||||
|
|
||||||
|
manager::GenreManager gnrMgr(m_bConf);
|
||||||
|
|
||||||
|
manager::YearManager yrMgr(m_bConf);
|
||||||
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user