initial functional file indexer, added Qt / C++ port of Cartographer
This commit is contained in:
parent
fae3d30dbd
commit
c52386abb4
19 changed files with 721 additions and 149 deletions
4
.gitignore
vendored
4
.gitignore
vendored
|
@ -72,10 +72,12 @@ CMakeLists.txt.user*
|
||||||
*.dll
|
*.dll
|
||||||
*.exe
|
*.exe
|
||||||
|
|
||||||
|
.ccls-cache/
|
||||||
.qt/
|
.qt/
|
||||||
.rcc/
|
.rcc/
|
||||||
bin/
|
bin/
|
||||||
build/
|
build*/
|
||||||
|
cmake-build-debug/
|
||||||
**/qmldir
|
**/qmldir
|
||||||
**/meta_types
|
**/meta_types
|
||||||
**/qmltypes
|
**/qmltypes
|
||||||
|
|
|
@ -11,25 +11,29 @@ include(ECMQmlModule)
|
||||||
qt_standard_project_setup()
|
qt_standard_project_setup()
|
||||||
|
|
||||||
qt_add_executable(koto
|
qt_add_executable(koto
|
||||||
main.cpp
|
main.cpp
|
||||||
config/config.cpp
|
config/config.cpp
|
||||||
config/library.cpp
|
config/library.cpp
|
||||||
config/ui_prefs.cpp
|
config/ui_prefs.cpp
|
||||||
datalake/indexer.cpp
|
datalake/indexer.cpp
|
||||||
datalake/track.cpp
|
datalake/track.cpp
|
||||||
|
datalake/album.cpp
|
||||||
|
datalake/artist.cpp
|
||||||
|
datalake/cartographer.cpp
|
||||||
|
datalake/cartographer.hpp
|
||||||
)
|
)
|
||||||
|
|
||||||
ecm_add_qml_module(koto URI "com.github.joshstrobl.koto" GENERATE_PLUGIN_SOURCE)
|
ecm_add_qml_module(koto URI "com.github.joshstrobl.koto" GENERATE_PLUGIN_SOURCE)
|
||||||
|
|
||||||
ecm_target_qml_sources(koto
|
ecm_target_qml_sources(koto
|
||||||
SOURCES
|
SOURCES
|
||||||
qml/PrimaryNavigation.qml
|
qml/PrimaryNavigation.qml
|
||||||
qml/HomePage.qml
|
qml/HomePage.qml
|
||||||
qml/Main.qml
|
qml/Main.qml
|
||||||
)
|
)
|
||||||
|
|
||||||
target_link_libraries(koto
|
target_link_libraries(koto
|
||||||
PRIVATE KF6::Baloo KF6::FileMetaData Qt6::Quick Qt6::QuickControls2
|
PRIVATE KF6::Baloo KF6::FileMetaData Qt6::Quick Qt6::QuickControls2
|
||||||
)
|
)
|
||||||
|
|
||||||
install(FILES com.github.joshstrobl.koto.desktop DESTINATION ${KDE_INSTALL_APPDIR})
|
install(FILES com.github.joshstrobl.koto.desktop DESTINATION ${KDE_INSTALL_APPDIR})
|
||||||
|
|
|
@ -1,40 +1,43 @@
|
||||||
#include "config.hpp"
|
#include "config.hpp"
|
||||||
|
|
||||||
#include <QDir>
|
#include <QDir>
|
||||||
#include <QStandardPaths>
|
#include <QStandardPaths>
|
||||||
#include <filesystem>
|
#include <filesystem>
|
||||||
namespace fs = std::filesystem;
|
namespace fs = std::filesystem;
|
||||||
|
|
||||||
KotoConfig::KotoConfig() {
|
KotoConfig::KotoConfig() {
|
||||||
// Define our application's config location
|
// Define our application's config location
|
||||||
auto configDir = QDir(QStandardPaths::writableLocation(QStandardPaths::StandardLocation::AppConfigLocation));
|
auto configDir = QDir(QStandardPaths::writableLocation(QStandardPaths::StandardLocation::AppConfigLocation));
|
||||||
auto configDirPath = configDir.absolutePath();
|
auto configDirPath = configDir.absolutePath();
|
||||||
fs::path filePath {};
|
fs::path filePath {};
|
||||||
auto configPathStd = configDirPath.toStdString();
|
auto configPathStd = configDirPath.toStdString();
|
||||||
filePath /= configPathStd;
|
filePath /= configPathStd;
|
||||||
filePath /= "config.toml";
|
filePath /= "config.toml";
|
||||||
|
|
||||||
auto data = toml::parse(filePath);
|
auto data = toml::parse(filePath);
|
||||||
std::optional<toml::value> ui_prefs;
|
std::optional<toml::value> ui_prefs;
|
||||||
|
|
||||||
if (data.contains("preferences.ui")) {
|
if (data.contains("preferences.ui")) {
|
||||||
auto ui_prefs_at = data.at("preferences.ui");
|
auto ui_prefs_at = data.at("preferences.ui");
|
||||||
if (ui_prefs_at.is_table()) ui_prefs = ui_prefs_at.as_table();
|
if (ui_prefs_at.is_table()) ui_prefs = ui_prefs_at.as_table();
|
||||||
}
|
}
|
||||||
|
|
||||||
auto prefs = KotoUiPreferences(ui_prefs);
|
auto prefs = KotoUiPreferences(ui_prefs);
|
||||||
this->i_uiPreferences = &prefs;
|
this->i_uiPreferences = &prefs;
|
||||||
|
|
||||||
this->i_libraries = {};
|
this->i_libraries = {};
|
||||||
for (const auto& lib_value : toml::find<std::vector<toml::value>>(data, "libraries")) {
|
for (const auto& lib_value : toml::find<std::vector<toml::value>>(data, "libraries")) {
|
||||||
auto lib = KotoLibraryConfig(lib_value);
|
auto lib = KotoLibraryConfig(lib_value);
|
||||||
this->i_libraries.push_back(lib);
|
this->i_libraries.push_back(lib);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
KotoUiPreferences * KotoConfig::getUiPreferences() {
|
KotoConfig::~KotoConfig() {}
|
||||||
return this->i_uiPreferences;
|
|
||||||
|
KotoUiPreferences* KotoConfig::getUiPreferences() {
|
||||||
|
return this->i_uiPreferences;
|
||||||
}
|
}
|
||||||
|
|
||||||
std::vector<KotoLibraryConfig> KotoConfig::getLibraries() {
|
std::vector<KotoLibraryConfig> KotoConfig::getLibraries() {
|
||||||
return this->i_libraries;
|
return this->i_libraries;
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,15 +1,25 @@
|
||||||
#include "library.hpp"
|
#include "library.hpp"
|
||||||
|
|
||||||
|
#include <QDebug>
|
||||||
#include <string>
|
#include <string>
|
||||||
|
|
||||||
KotoLibraryConfig::KotoLibraryConfig(const toml::value &v) {
|
KotoLibraryConfig::KotoLibraryConfig(std::string name, fs::path path) {
|
||||||
this->i_name = toml::find<std::string>(v, "name");
|
this->i_name = name;
|
||||||
this->i_path = toml::find<std::string>(v, "path");
|
this->i_path = path;
|
||||||
|
qDebug() << "Library: " << this->i_name.c_str() << " at " << this->i_path.c_str();
|
||||||
|
}
|
||||||
|
|
||||||
|
KotoLibraryConfig::~KotoLibraryConfig() {}
|
||||||
|
|
||||||
|
KotoLibraryConfig::KotoLibraryConfig(const toml::value& v) {
|
||||||
|
this->i_name = toml::find<std::string>(v, "name");
|
||||||
|
this->i_path = toml::find<std::string>(v, "path");
|
||||||
}
|
}
|
||||||
|
|
||||||
std::string KotoLibraryConfig::getName() {
|
std::string KotoLibraryConfig::getName() {
|
||||||
return this->i_name;
|
return this->i_name;
|
||||||
}
|
}
|
||||||
|
|
||||||
fs::path KotoLibraryConfig::getPath() {
|
fs::path KotoLibraryConfig::getPath() {
|
||||||
return this->i_path;
|
return this->i_path;
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,17 +1,20 @@
|
||||||
#pragma once
|
#pragma once
|
||||||
#include "includes/toml.hpp"
|
|
||||||
#include <filesystem>
|
#include <filesystem>
|
||||||
#include <string>
|
#include <string>
|
||||||
|
|
||||||
|
#include "includes/toml.hpp"
|
||||||
|
|
||||||
namespace fs = std::filesystem;
|
namespace fs = std::filesystem;
|
||||||
|
|
||||||
class KotoLibraryConfig {
|
class KotoLibraryConfig {
|
||||||
public:
|
public:
|
||||||
KotoLibraryConfig(const toml::value &v);
|
KotoLibraryConfig(std::string name, fs::path path);
|
||||||
~KotoLibraryConfig();
|
KotoLibraryConfig(const toml::value& v);
|
||||||
std::string getName();
|
~KotoLibraryConfig();
|
||||||
fs::path getPath();
|
std::string getName();
|
||||||
private:
|
fs::path getPath();
|
||||||
std::string i_name;
|
|
||||||
fs::path i_path;
|
private:
|
||||||
|
std::string i_name;
|
||||||
|
fs::path i_path;
|
||||||
};
|
};
|
||||||
|
|
|
@ -1,38 +1,40 @@
|
||||||
#include "ui_prefs.hpp"
|
#include "ui_prefs.hpp"
|
||||||
|
|
||||||
KotoUiPreferences::KotoUiPreferences(std::optional<toml::value> v) {
|
KotoUiPreferences::KotoUiPreferences(std::optional<toml::value> v) {
|
||||||
this->i_albumInfoShowDescription = true;
|
this->i_albumInfoShowDescription = true;
|
||||||
this->i_albumInfoShowGenre = true;
|
this->i_albumInfoShowGenre = true;
|
||||||
this->i_albumInfoShowNarrator = true;
|
this->i_albumInfoShowNarrator = true;
|
||||||
this->i_albumInfoShowYear = true;
|
this->i_albumInfoShowYear = true;
|
||||||
this->i_lastUsedVolume = 0.5;
|
this->i_lastUsedVolume = 0.5;
|
||||||
|
|
||||||
// No UI prefs provided
|
// No UI prefs provided
|
||||||
if (!v.has_value()) return;
|
if (!v.has_value()) return;
|
||||||
toml::value& uiPrefs = v.value();
|
toml::value& uiPrefs = v.value();
|
||||||
this->i_albumInfoShowDescription = toml::find_or<bool>(uiPrefs, "album_info_show_description", false);
|
this->i_albumInfoShowDescription = toml::find_or<bool>(uiPrefs, "album_info_show_description", false);
|
||||||
this->i_albumInfoShowGenre = toml::find_or<bool>(uiPrefs, "album_info_show_genre", false);
|
this->i_albumInfoShowGenre = toml::find_or<bool>(uiPrefs, "album_info_show_genre", false);
|
||||||
this->i_albumInfoShowNarrator = toml::find_or<bool>(uiPrefs, "album_info_show_narrator", false);
|
this->i_albumInfoShowNarrator = toml::find_or<bool>(uiPrefs, "album_info_show_narrator", false);
|
||||||
this->i_albumInfoShowYear = toml::find_or<bool>(uiPrefs, "album_info_show_year", false);
|
this->i_albumInfoShowYear = toml::find_or<bool>(uiPrefs, "album_info_show_year", false);
|
||||||
this->i_lastUsedVolume = toml::find_or<float>(uiPrefs, "last_used_volume", 0.5);
|
this->i_lastUsedVolume = toml::find_or<float>(uiPrefs, "last_used_volume", 0.5);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
KotoUiPreferences::~KotoUiPreferences() {}
|
||||||
|
|
||||||
bool KotoUiPreferences::getAlbumInfoShowDescription() {
|
bool KotoUiPreferences::getAlbumInfoShowDescription() {
|
||||||
return this->i_albumInfoShowDescription;
|
return this->i_albumInfoShowDescription;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool KotoUiPreferences::getAlbumInfoShowGenre() {
|
bool KotoUiPreferences::getAlbumInfoShowGenre() {
|
||||||
return this->i_albumInfoShowGenre;
|
return this->i_albumInfoShowGenre;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool KotoUiPreferences::getAlbumInfoShowNarrator() {
|
bool KotoUiPreferences::getAlbumInfoShowNarrator() {
|
||||||
return this->i_albumInfoShowNarrator;
|
return this->i_albumInfoShowNarrator;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool KotoUiPreferences::getAlbumInfoShowYear() {
|
bool KotoUiPreferences::getAlbumInfoShowYear() {
|
||||||
return this->i_albumInfoShowYear;
|
return this->i_albumInfoShowYear;
|
||||||
}
|
}
|
||||||
|
|
||||||
float KotoUiPreferences::getLastUsedVolume() {
|
float KotoUiPreferences::getLastUsedVolume() {
|
||||||
return this->i_lastUsedVolume;
|
return this->i_lastUsedVolume;
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,30 +1,32 @@
|
||||||
#pragma once
|
#pragma once
|
||||||
#include "includes/toml.hpp"
|
|
||||||
#include <optional>
|
#include <optional>
|
||||||
#include <string>
|
#include <string>
|
||||||
#include <string_view>
|
#include <string_view>
|
||||||
#include <vector>
|
#include <vector>
|
||||||
|
|
||||||
|
#include "includes/toml.hpp"
|
||||||
|
|
||||||
class KotoUiPreferences {
|
class KotoUiPreferences {
|
||||||
public:
|
public:
|
||||||
KotoUiPreferences(std::optional<toml::value> v);
|
KotoUiPreferences(std::optional<toml::value> v);
|
||||||
~KotoUiPreferences();
|
~KotoUiPreferences();
|
||||||
|
|
||||||
bool getAlbumInfoShowDescription();
|
bool getAlbumInfoShowDescription();
|
||||||
bool getAlbumInfoShowGenre();
|
bool getAlbumInfoShowGenre();
|
||||||
bool getAlbumInfoShowNarrator();
|
bool getAlbumInfoShowNarrator();
|
||||||
bool getAlbumInfoShowYear();
|
bool getAlbumInfoShowYear();
|
||||||
float getLastUsedVolume();
|
float getLastUsedVolume();
|
||||||
|
|
||||||
void setAlbumInfoShowDescription(bool show);
|
void setAlbumInfoShowDescription(bool show);
|
||||||
void setAlbumInfoShowGenre(bool show);
|
void setAlbumInfoShowGenre(bool show);
|
||||||
void setAlbumInfoShowNarrator(bool show);
|
void setAlbumInfoShowNarrator(bool show);
|
||||||
void setAlbumInfoShowYear(bool show);
|
void setAlbumInfoShowYear(bool show);
|
||||||
void setLastUsedVolume(float volume);
|
void setLastUsedVolume(float volume);
|
||||||
private:
|
|
||||||
bool i_albumInfoShowDescription;
|
private:
|
||||||
bool i_albumInfoShowGenre;
|
bool i_albumInfoShowDescription;
|
||||||
bool i_albumInfoShowNarrator;
|
bool i_albumInfoShowGenre;
|
||||||
bool i_albumInfoShowYear;
|
bool i_albumInfoShowNarrator;
|
||||||
float i_lastUsedVolume;
|
bool i_albumInfoShowYear;
|
||||||
|
float i_lastUsedVolume;
|
||||||
};
|
};
|
||||||
|
|
83
desktop/datalake/album.cpp
Normal file
83
desktop/datalake/album.cpp
Normal file
|
@ -0,0 +1,83 @@
|
||||||
|
#include "structs.hpp"
|
||||||
|
|
||||||
|
KotoAlbum::KotoAlbum() {
|
||||||
|
this->uuid = QUuid::createUuid();
|
||||||
|
this->tracks = QList<KotoTrack*>();
|
||||||
|
}
|
||||||
|
|
||||||
|
KotoAlbum* KotoAlbum::fromDb() {
|
||||||
|
return new KotoAlbum();
|
||||||
|
}
|
||||||
|
|
||||||
|
KotoAlbum::~KotoAlbum() {
|
||||||
|
for (auto track : this->tracks) { delete track; }
|
||||||
|
this->tracks.clear();
|
||||||
|
}
|
||||||
|
|
||||||
|
void KotoAlbum::addTrack(KotoTrack* track) {
|
||||||
|
this->tracks.append(track);
|
||||||
|
}
|
||||||
|
|
||||||
|
QString KotoAlbum::getAlbumArtPath() {
|
||||||
|
return QString {this->album_art_path};
|
||||||
|
}
|
||||||
|
|
||||||
|
QString KotoAlbum::getDescription() {
|
||||||
|
return QString {this->description};
|
||||||
|
}
|
||||||
|
|
||||||
|
QList<QString> KotoAlbum::getGenres() {
|
||||||
|
return QList {this->genres};
|
||||||
|
}
|
||||||
|
|
||||||
|
QString KotoAlbum::getPath() {
|
||||||
|
return this->path;
|
||||||
|
}
|
||||||
|
|
||||||
|
QString KotoAlbum::getNarrator() {
|
||||||
|
return QString {this->narrator};
|
||||||
|
}
|
||||||
|
|
||||||
|
QString KotoAlbum::getTitle() {
|
||||||
|
return QString {this->title};
|
||||||
|
}
|
||||||
|
|
||||||
|
QList<KotoTrack*> KotoAlbum::getTracks() {
|
||||||
|
return QList {this->tracks};
|
||||||
|
}
|
||||||
|
|
||||||
|
int KotoAlbum::getYear() {
|
||||||
|
return this->year;
|
||||||
|
}
|
||||||
|
|
||||||
|
void KotoAlbum::removeTrack(KotoTrack* track) {
|
||||||
|
this->tracks.removeOne(track);
|
||||||
|
}
|
||||||
|
|
||||||
|
void KotoAlbum::setAlbumArtPath(QString str) {
|
||||||
|
this->album_art_path = QString {path};
|
||||||
|
}
|
||||||
|
|
||||||
|
void KotoAlbum::setDescription(QString str) {
|
||||||
|
this->description = QString {str};
|
||||||
|
}
|
||||||
|
|
||||||
|
void KotoAlbum::setGenres(QList<QString> list) {
|
||||||
|
this->genres = QList {list};
|
||||||
|
}
|
||||||
|
|
||||||
|
void KotoAlbum::setNarrator(QString str) {
|
||||||
|
this->narrator = QString {str};
|
||||||
|
}
|
||||||
|
|
||||||
|
void KotoAlbum::setPath(QString str) {
|
||||||
|
this->path = QString {str};
|
||||||
|
}
|
||||||
|
|
||||||
|
void KotoAlbum::setTitle(QString str) {
|
||||||
|
this->title = QString {str};
|
||||||
|
}
|
||||||
|
|
||||||
|
void KotoAlbum::setYear(int num) {
|
||||||
|
this->year = num;
|
||||||
|
}
|
60
desktop/datalake/artist.cpp
Normal file
60
desktop/datalake/artist.cpp
Normal file
|
@ -0,0 +1,60 @@
|
||||||
|
#include "structs.hpp"
|
||||||
|
|
||||||
|
KotoArtist::KotoArtist() {
|
||||||
|
this->uuid = QUuid::createUuid();
|
||||||
|
}
|
||||||
|
|
||||||
|
KotoArtist* KotoArtist::fromDb() {
|
||||||
|
return new KotoArtist();
|
||||||
|
}
|
||||||
|
|
||||||
|
KotoArtist::~KotoArtist() {
|
||||||
|
for (auto album : this->albums) { delete album; }
|
||||||
|
for (auto track : this->tracks) { delete track; }
|
||||||
|
this->albums.clear();
|
||||||
|
this->tracks.clear();
|
||||||
|
}
|
||||||
|
|
||||||
|
void KotoArtist::addAlbum(KotoAlbum* album) {
|
||||||
|
this->albums.append(album);
|
||||||
|
}
|
||||||
|
|
||||||
|
void KotoArtist::addTrack(KotoTrack* track) {
|
||||||
|
this->tracks.append(track);
|
||||||
|
}
|
||||||
|
|
||||||
|
QList<KotoAlbum*> KotoArtist::getAlbums() {
|
||||||
|
return QList {this->albums};
|
||||||
|
}
|
||||||
|
|
||||||
|
std::optional<KotoAlbum*> KotoArtist::getAlbumByName(QString name) {
|
||||||
|
for (auto album : this->albums) {
|
||||||
|
if (album->getTitle().contains(name)) { return std::optional {album}; }
|
||||||
|
}
|
||||||
|
|
||||||
|
return std::nullopt;
|
||||||
|
}
|
||||||
|
|
||||||
|
QString KotoArtist::getName() {
|
||||||
|
return QString {this->name};
|
||||||
|
}
|
||||||
|
|
||||||
|
QList<KotoTrack*> KotoArtist::getTracks() {
|
||||||
|
return QList {this->tracks};
|
||||||
|
}
|
||||||
|
|
||||||
|
void KotoArtist::removeAlbum(KotoAlbum* album) {
|
||||||
|
this->albums.removeOne(album);
|
||||||
|
}
|
||||||
|
|
||||||
|
void KotoArtist::removeTrack(KotoTrack* track) {
|
||||||
|
this->tracks.removeOne(track);
|
||||||
|
}
|
||||||
|
|
||||||
|
void KotoArtist::setName(QString str) {
|
||||||
|
this->name = QString {str};
|
||||||
|
}
|
||||||
|
|
||||||
|
void KotoArtist::setPath(QString str) {
|
||||||
|
this->path = QString {str};
|
||||||
|
}
|
45
desktop/datalake/cartographer.cpp
Normal file
45
desktop/datalake/cartographer.cpp
Normal file
|
@ -0,0 +1,45 @@
|
||||||
|
#include "cartographer.hpp"
|
||||||
|
|
||||||
|
Cartographer::Cartographer()
|
||||||
|
: i_albums(QHash<QUuid, KotoAlbum*>()),
|
||||||
|
i_artists(QHash<QUuid, KotoArtist*>()),
|
||||||
|
i_artists_by_name(QHash<QString, KotoArtist*>()),
|
||||||
|
i_tracks(QHash<QUuid, KotoTrack*>()) {}
|
||||||
|
|
||||||
|
Cartographer& Cartographer::instance() {
|
||||||
|
static Cartographer _instance;
|
||||||
|
return _instance;
|
||||||
|
}
|
||||||
|
|
||||||
|
void Cartographer::addAlbum(KotoAlbum* album) {
|
||||||
|
this->i_albums.insert(album->uuid, album);
|
||||||
|
}
|
||||||
|
|
||||||
|
void Cartographer::addArtist(KotoArtist* artist) {
|
||||||
|
this->i_artists.insert(artist->uuid, artist);
|
||||||
|
this->i_artists_by_name.insert(artist->getName(), artist);
|
||||||
|
}
|
||||||
|
|
||||||
|
void Cartographer::addTrack(KotoTrack* track) {
|
||||||
|
this->i_tracks.insert(track->uuid, track);
|
||||||
|
}
|
||||||
|
|
||||||
|
std::optional<KotoAlbum*> Cartographer::getAlbum(QUuid uuid) {
|
||||||
|
auto album = this->i_albums.value(uuid, nullptr);
|
||||||
|
return album ? std::optional {album} : std::nullopt;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::optional<KotoArtist*> Cartographer::getArtist(QUuid uuid) {
|
||||||
|
auto artist = this->i_artists.value(uuid, nullptr);
|
||||||
|
return artist ? std::optional {artist} : std::nullopt;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::optional<KotoArtist*> Cartographer::getArtist(QString name) {
|
||||||
|
auto artist = this->i_artists_by_name.value(name, nullptr);
|
||||||
|
return artist ? std::optional {artist} : std::nullopt;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::optional<KotoTrack*> Cartographer::getTrack(QUuid uuid) {
|
||||||
|
auto track = this->i_tracks.value(uuid, nullptr);
|
||||||
|
return track ? std::optional {track} : std::nullopt;
|
||||||
|
}
|
30
desktop/datalake/cartographer.hpp
Normal file
30
desktop/datalake/cartographer.hpp
Normal file
|
@ -0,0 +1,30 @@
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <QHash>
|
||||||
|
#include <QString>
|
||||||
|
#include <QUuid>
|
||||||
|
#include <optional>
|
||||||
|
|
||||||
|
#include "structs.hpp"
|
||||||
|
|
||||||
|
class Cartographer {
|
||||||
|
public:
|
||||||
|
Cartographer();
|
||||||
|
static Cartographer& instance();
|
||||||
|
static Cartographer* create() { return &instance(); }
|
||||||
|
|
||||||
|
void addAlbum(KotoAlbum* album);
|
||||||
|
void addArtist(KotoArtist* artist);
|
||||||
|
void addTrack(KotoTrack* track);
|
||||||
|
std::optional<KotoAlbum*> getAlbum(QUuid uuid);
|
||||||
|
//.std::optional<KotoAlbum*> getAlbum(QString name);
|
||||||
|
std::optional<KotoArtist*> getArtist(QUuid uuid);
|
||||||
|
std::optional<KotoArtist*> getArtist(QString name);
|
||||||
|
std::optional<KotoTrack*> getTrack(QUuid uuid);
|
||||||
|
|
||||||
|
private:
|
||||||
|
QHash<QUuid, KotoAlbum*> i_albums;
|
||||||
|
QHash<QUuid, KotoArtist*> i_artists;
|
||||||
|
QHash<QString, KotoArtist*> i_artists_by_name;
|
||||||
|
QHash<QUuid, KotoTrack*> i_tracks;
|
||||||
|
};
|
|
@ -1,6 +1,90 @@
|
||||||
#include "indexer.hpp"
|
#include "indexer.hpp"
|
||||||
|
|
||||||
|
#include <KFileMetaData/ExtractorCollection>
|
||||||
|
#include <QDebug>
|
||||||
#include <QDirIterator>
|
#include <QDirIterator>
|
||||||
|
#include <QMimeDatabase>
|
||||||
|
#include <iostream>
|
||||||
|
|
||||||
FileIndexer::FileIndexer(KotoLibraryConfig * config) {
|
FileIndexer::FileIndexer(KotoLibraryConfig* config) {
|
||||||
|
this->i_root = QString {config->getPath().c_str()};
|
||||||
|
}
|
||||||
|
|
||||||
|
FileIndexer::~FileIndexer() = default;
|
||||||
|
|
||||||
|
void FileIndexer::index() {
|
||||||
|
QMimeDatabase db;
|
||||||
|
KFileMetaData::ExtractorCollection extractors;
|
||||||
|
|
||||||
|
QStringList root_dirs {this->i_root.split(QDir::separator())};
|
||||||
|
|
||||||
|
QDirIterator it {this->i_root, QDir::Dirs | QDir::Files | QDir::NoDotAndDotDot, QDirIterator::Subdirectories};
|
||||||
|
|
||||||
|
// std::cout << "Indexing " << this->i_root.toStdString();
|
||||||
|
|
||||||
|
while (it.hasNext()) {
|
||||||
|
QString path = it.next();
|
||||||
|
QFileInfo info {path};
|
||||||
|
|
||||||
|
if (info.isDir()) {
|
||||||
|
auto diffPath = info.dir().relativeFilePath(this->i_root);
|
||||||
|
auto diffDirs = diffPath.split("..");
|
||||||
|
auto diffDirsSize = diffDirs.size() - 1;
|
||||||
|
|
||||||
|
// This is going to be an artist
|
||||||
|
if (diffDirsSize == 0) {
|
||||||
|
auto artist = new KotoArtist();
|
||||||
|
artist->setName(info.fileName());
|
||||||
|
artist->setPath(path);
|
||||||
|
this->i_artists.append(artist);
|
||||||
|
Cartographer::instance().addArtist(artist);
|
||||||
|
continue;
|
||||||
|
} else if (diffDirsSize == 1) {
|
||||||
|
auto album = new KotoAlbum();
|
||||||
|
album->setTitle(info.fileName());
|
||||||
|
|
||||||
|
auto artistDir = QDir(info.dir());
|
||||||
|
auto artistName = artistDir.dirName();
|
||||||
|
auto artistOptional = Cartographer::instance().getArtist(artistName);
|
||||||
|
|
||||||
|
if (artistOptional.has_value()) {
|
||||||
|
auto artist = artistOptional.value();
|
||||||
|
album->artist_uuid = artist->uuid;
|
||||||
|
artist->addAlbum(album);
|
||||||
|
}
|
||||||
|
|
||||||
|
Cartographer::instance().addAlbum(album);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// This is a file
|
||||||
|
QMimeType mime = db.mimeTypeForFile(info);
|
||||||
|
if (mime.name().startsWith("audio/")) {
|
||||||
|
auto extractorList = extractors.fetchExtractors(mime.name());
|
||||||
|
if (extractorList.isEmpty()) { continue; }
|
||||||
|
|
||||||
|
auto result = KFileMetaData::SimpleExtractionResult(path, mime.name(), KFileMetaData::ExtractionResult::ExtractMetaData);
|
||||||
|
extractorList.first()->extract(&result);
|
||||||
|
|
||||||
|
if (!result.types().contains(KFileMetaData::Type::Audio)) { continue; }
|
||||||
|
|
||||||
|
auto track = KotoTrack::fromMetadata(result);
|
||||||
|
track->setPath(path);
|
||||||
|
|
||||||
|
this->i_tracks.append(track);
|
||||||
|
Cartographer::instance().addTrack(track);
|
||||||
|
} else if (mime.name().startsWith("image/")) {
|
||||||
|
// This is an image, TODO add cover art to album
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
std::cout << "===== Summary =====" << std::endl;
|
||||||
|
for (auto artist : this->i_artists) {
|
||||||
|
std::cout << "Artist: " << artist->getName().toStdString() << std::endl;
|
||||||
|
for (auto album : artist->getAlbums()) {
|
||||||
|
std::cout << " Album: " << album->getTitle().toStdString() << std::endl;
|
||||||
|
for (auto track : album->getTracks()) { std::cout << " Track: " << track->getTitle().toStdString() << std::endl; }
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,19 +1,25 @@
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include <string>
|
#include <string>
|
||||||
|
|
||||||
|
#include "cartographer.hpp"
|
||||||
#include "config/library.hpp"
|
#include "config/library.hpp"
|
||||||
#include "track.hpp"
|
#include "structs.hpp"
|
||||||
|
|
||||||
class FileIndexer {
|
class FileIndexer {
|
||||||
public:
|
public:
|
||||||
FileIndexer(KotoLibraryConfig * config);
|
FileIndexer(KotoLibraryConfig* config);
|
||||||
~FileIndexer();
|
~FileIndexer();
|
||||||
|
|
||||||
std::vector<KotoTrack *> getFiles();
|
QList<KotoArtist*> getArtists();
|
||||||
std::string getRoot();
|
QList<KotoTrack*> getFiles();
|
||||||
|
QString getRoot();
|
||||||
|
|
||||||
void index();
|
void index();
|
||||||
protected:
|
|
||||||
std::vector<KotoTrack *> i_tracks;
|
protected:
|
||||||
std::string i_root;
|
void indexDirectory(QString path, int depth);
|
||||||
|
QList<KotoArtist*> i_artists;
|
||||||
|
QList<KotoTrack*> i_tracks;
|
||||||
|
QString i_root;
|
||||||
};
|
};
|
||||||
|
|
125
desktop/datalake/structs.hpp
Normal file
125
desktop/datalake/structs.hpp
Normal file
|
@ -0,0 +1,125 @@
|
||||||
|
#pragma once
|
||||||
|
#include <KFileMetaData/SimpleExtractionResult>
|
||||||
|
#include <QList>
|
||||||
|
#include <QString>
|
||||||
|
#include <QUuid>
|
||||||
|
#include <filesystem>
|
||||||
|
|
||||||
|
namespace fs = std::filesystem;
|
||||||
|
|
||||||
|
class KotoArtist;
|
||||||
|
class KotoAlbum;
|
||||||
|
class KotoTrack;
|
||||||
|
|
||||||
|
class KotoArtist {
|
||||||
|
public:
|
||||||
|
KotoArtist();
|
||||||
|
static KotoArtist* fromDb();
|
||||||
|
~KotoArtist();
|
||||||
|
|
||||||
|
QUuid uuid;
|
||||||
|
|
||||||
|
void addAlbum(KotoAlbum* album);
|
||||||
|
void addTrack(KotoTrack* track);
|
||||||
|
QList<KotoAlbum*> getAlbums();
|
||||||
|
std::optional<KotoAlbum*> getAlbumByName(QString name);
|
||||||
|
QString getName();
|
||||||
|
QString getPath();
|
||||||
|
QList<KotoTrack*> getTracks();
|
||||||
|
void removeAlbum(KotoAlbum* album);
|
||||||
|
void removeTrack(KotoTrack* track);
|
||||||
|
void setName(QString str);
|
||||||
|
void setPath(QString str);
|
||||||
|
|
||||||
|
private:
|
||||||
|
QString path;
|
||||||
|
QString name;
|
||||||
|
|
||||||
|
QList<KotoAlbum*> albums;
|
||||||
|
QList<KotoTrack*> tracks;
|
||||||
|
};
|
||||||
|
|
||||||
|
class KotoAlbum {
|
||||||
|
public:
|
||||||
|
KotoAlbum();
|
||||||
|
static KotoAlbum* fromDb();
|
||||||
|
~KotoAlbum();
|
||||||
|
|
||||||
|
QUuid uuid;
|
||||||
|
QUuid artist_uuid;
|
||||||
|
|
||||||
|
QString getAlbumArtPath();
|
||||||
|
QString getDescription();
|
||||||
|
QList<QString> getGenres();
|
||||||
|
QString getNarrator();
|
||||||
|
QString getPath();
|
||||||
|
QString getTitle();
|
||||||
|
QList<KotoTrack*> getTracks();
|
||||||
|
int getYear();
|
||||||
|
|
||||||
|
void addTrack(KotoTrack* track);
|
||||||
|
void removeTrack(KotoTrack* track);
|
||||||
|
void setAlbumArtPath(QString str);
|
||||||
|
void setDescription(QString str);
|
||||||
|
void setGenres(QList<QString> list);
|
||||||
|
void setNarrator(QString str);
|
||||||
|
void setPath(QString str);
|
||||||
|
void setTitle(QString str);
|
||||||
|
void setYear(int num);
|
||||||
|
|
||||||
|
private:
|
||||||
|
QString title;
|
||||||
|
QString description;
|
||||||
|
QString narrator;
|
||||||
|
int year;
|
||||||
|
|
||||||
|
QList<QString> genres;
|
||||||
|
QList<KotoTrack*> tracks;
|
||||||
|
|
||||||
|
QString path;
|
||||||
|
QString album_art_path;
|
||||||
|
};
|
||||||
|
|
||||||
|
class KotoTrack {
|
||||||
|
public:
|
||||||
|
KotoTrack(); // No-op constructor
|
||||||
|
static KotoTrack* fromDb();
|
||||||
|
static KotoTrack* fromMetadata(const KFileMetaData::SimpleExtractionResult& metadata);
|
||||||
|
~KotoTrack();
|
||||||
|
|
||||||
|
std::optional<QUuid> album_uuid;
|
||||||
|
QUuid artist_uuid;
|
||||||
|
QUuid uuid;
|
||||||
|
|
||||||
|
int getDuration();
|
||||||
|
QStringList getGenres();
|
||||||
|
QString getLyrics();
|
||||||
|
QString getNarrator();
|
||||||
|
QString getPath();
|
||||||
|
QString getTitle();
|
||||||
|
int getTrackNumber();
|
||||||
|
int getYear();
|
||||||
|
|
||||||
|
void setAlbum(KotoAlbum* album);
|
||||||
|
void setArtist(KotoArtist* artist);
|
||||||
|
void setDiscNumber(int num);
|
||||||
|
void setDuration(int num);
|
||||||
|
void setGenres(QList<QString> list);
|
||||||
|
void setLyrics(QString str);
|
||||||
|
void setNarrator(QString str);
|
||||||
|
void setPath(QString path);
|
||||||
|
void setTitle(QString str);
|
||||||
|
void setTrackNumber(int num);
|
||||||
|
void setYear(int num);
|
||||||
|
|
||||||
|
private:
|
||||||
|
int disc_number;
|
||||||
|
int duration;
|
||||||
|
QStringList genres;
|
||||||
|
QString lyrics;
|
||||||
|
QString narrator;
|
||||||
|
QString path;
|
||||||
|
QString title;
|
||||||
|
int track_number;
|
||||||
|
int year;
|
||||||
|
};
|
|
@ -0,0 +1,140 @@
|
||||||
|
#include <iostream>
|
||||||
|
|
||||||
|
#include "cartographer.hpp"
|
||||||
|
#include "structs.hpp"
|
||||||
|
|
||||||
|
KotoTrack::KotoTrack() {
|
||||||
|
this->uuid = QUuid::createUuid();
|
||||||
|
}
|
||||||
|
|
||||||
|
KotoTrack* KotoTrack::fromDb() {
|
||||||
|
return new KotoTrack();
|
||||||
|
}
|
||||||
|
|
||||||
|
KotoTrack::~KotoTrack() {}
|
||||||
|
|
||||||
|
KotoTrack* KotoTrack::fromMetadata(const KFileMetaData::SimpleExtractionResult& metadata) {
|
||||||
|
auto props = metadata.properties();
|
||||||
|
KotoTrack* track = new KotoTrack();
|
||||||
|
track->disc_number = props.value(KFileMetaData::Property::DiscNumber, 0).toInt();
|
||||||
|
track->duration = props.value(KFileMetaData::Property::Duration, 0).toInt();
|
||||||
|
|
||||||
|
QStringList genres;
|
||||||
|
for (auto v : props.values(KFileMetaData::Property::Genre)) { genres.append(v.toString()); }
|
||||||
|
|
||||||
|
track->genres = genres;
|
||||||
|
|
||||||
|
track->lyrics = props.value(KFileMetaData::Property::Lyrics).toString();
|
||||||
|
track->narrator = props.value(KFileMetaData::Property::Performer).toString();
|
||||||
|
track->title = props.value(KFileMetaData::Property::Title).toString();
|
||||||
|
track->track_number = props.value(KFileMetaData::Property::TrackNumber, 0).toInt();
|
||||||
|
track->year = props.value(KFileMetaData::Property::ReleaseYear, 0).toInt();
|
||||||
|
|
||||||
|
auto artistResult = props.value(KFileMetaData::Property::Artist);
|
||||||
|
auto artistOptional = std::optional<KotoArtist*>();
|
||||||
|
if (artistResult.isValid()) {
|
||||||
|
artistOptional = Cartographer::instance().getArtist(artistResult.toString());
|
||||||
|
|
||||||
|
if (artistOptional.has_value()) {
|
||||||
|
auto artist = artistOptional.value();
|
||||||
|
track->artist_uuid = QUuid(artist->uuid);
|
||||||
|
artist->addTrack(track);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
auto albumResult = props.value(KFileMetaData::Property::Album);
|
||||||
|
if (albumResult.isValid() && artistOptional.has_value()) {
|
||||||
|
auto artist = artistOptional.value();
|
||||||
|
std::cout << "Album: " << albumResult.toString().toStdString() << std::endl;
|
||||||
|
|
||||||
|
auto albumMetaName = albumResult.toString();
|
||||||
|
auto albumOptional = artist->getAlbumByName(albumMetaName);
|
||||||
|
|
||||||
|
if (albumOptional.has_value()) {
|
||||||
|
auto album = albumOptional.value();
|
||||||
|
track->album_uuid = QUuid(album->uuid);
|
||||||
|
album->addTrack(track);
|
||||||
|
if (album->getTitle() != albumMetaName) album->setTitle(albumMetaName);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return track;
|
||||||
|
}
|
||||||
|
|
||||||
|
int KotoTrack::getDuration() {
|
||||||
|
return this->duration;
|
||||||
|
}
|
||||||
|
|
||||||
|
QList<QString> KotoTrack::getGenres() {
|
||||||
|
return QList {this->genres};
|
||||||
|
}
|
||||||
|
|
||||||
|
QString KotoTrack::getLyrics() {
|
||||||
|
return QString {this->lyrics};
|
||||||
|
}
|
||||||
|
|
||||||
|
QString KotoTrack::getNarrator() {
|
||||||
|
return QString {this->narrator};
|
||||||
|
}
|
||||||
|
|
||||||
|
QString KotoTrack::getPath() {
|
||||||
|
return QString {this->path};
|
||||||
|
}
|
||||||
|
|
||||||
|
QString KotoTrack::getTitle() {
|
||||||
|
return QString {this->title};
|
||||||
|
}
|
||||||
|
|
||||||
|
int KotoTrack::getTrackNumber() {
|
||||||
|
return this->track_number;
|
||||||
|
}
|
||||||
|
|
||||||
|
int KotoTrack::getYear() {
|
||||||
|
return this->year;
|
||||||
|
}
|
||||||
|
|
||||||
|
void KotoTrack::setAlbum(KotoAlbum* album) {
|
||||||
|
this->album_uuid = QUuid(album->uuid);
|
||||||
|
|
||||||
|
if (this->artist_uuid.isNull()) QUuid(album->artist_uuid);
|
||||||
|
}
|
||||||
|
|
||||||
|
void KotoTrack::setArtist(KotoArtist* artist) {
|
||||||
|
this->artist_uuid = QUuid(artist->uuid);
|
||||||
|
}
|
||||||
|
|
||||||
|
void KotoTrack::setDiscNumber(int num) {
|
||||||
|
this->disc_number = num;
|
||||||
|
}
|
||||||
|
|
||||||
|
void KotoTrack::setDuration(int num) {
|
||||||
|
this->duration = num;
|
||||||
|
}
|
||||||
|
|
||||||
|
void KotoTrack::setGenres(QList<QString> list) {
|
||||||
|
this->genres = QList {list};
|
||||||
|
}
|
||||||
|
|
||||||
|
void KotoTrack::setLyrics(QString str) {
|
||||||
|
this->lyrics = QString {str};
|
||||||
|
}
|
||||||
|
|
||||||
|
void KotoTrack::setNarrator(QString str) {
|
||||||
|
this->narrator = QString {str};
|
||||||
|
}
|
||||||
|
|
||||||
|
void KotoTrack::setPath(QString str) {
|
||||||
|
this->path = QString {str};
|
||||||
|
}
|
||||||
|
|
||||||
|
void KotoTrack::setTitle(QString str) {
|
||||||
|
this->title = QString {str};
|
||||||
|
}
|
||||||
|
|
||||||
|
void KotoTrack::setTrackNumber(int num) {
|
||||||
|
this->track_number = num;
|
||||||
|
}
|
||||||
|
|
||||||
|
void KotoTrack::setYear(int num) {
|
||||||
|
this->year = num;
|
||||||
|
}
|
|
@ -1,26 +0,0 @@
|
||||||
#pragma once
|
|
||||||
#include <KFileMetaData/SimpleExtractionResult>
|
|
||||||
#include <string>
|
|
||||||
#include <vector>
|
|
||||||
|
|
||||||
class KotoTrack {
|
|
||||||
public:
|
|
||||||
KotoTrack(); // No-op constructor
|
|
||||||
static KotoTrack * fromDb();
|
|
||||||
static KotoTrack * fromMetadata(KFileMetaData::SimpleExtractionResult metadata);
|
|
||||||
~KotoTrack();
|
|
||||||
|
|
||||||
private:
|
|
||||||
std::string album;
|
|
||||||
std::string album_artist;
|
|
||||||
std::string artist;
|
|
||||||
int disc_number;
|
|
||||||
int duration;
|
|
||||||
std::vector<std::string> genres;
|
|
||||||
std::string lyrics;
|
|
||||||
std::string narrator;
|
|
||||||
std::string path;
|
|
||||||
std::string title;
|
|
||||||
int track_number;
|
|
||||||
int year;
|
|
||||||
};
|
|
|
@ -9,18 +9,6 @@ last_used_volume = 0.5
|
||||||
jump_backwards_seconds = 30
|
jump_backwards_seconds = 30
|
||||||
jump_forward_seconds = 30
|
jump_forward_seconds = 30
|
||||||
|
|
||||||
[[libraries]]
|
|
||||||
name = "Audiobooks"
|
|
||||||
path = "/home/joshua/Audiobooks"
|
|
||||||
|
|
||||||
[[libraries]]
|
[[libraries]]
|
||||||
name = "Music"
|
name = "Music"
|
||||||
path = "/home/joshua/Music"
|
path = "/home/joshua/Music"
|
||||||
|
|
||||||
[[libraries]]
|
|
||||||
name = "Streaming"
|
|
||||||
path = "/home/joshua/StreamingMusic"
|
|
||||||
|
|
||||||
[[libraries]]
|
|
||||||
name = "Podcasts"
|
|
||||||
path = "/home/joshua/Podcasts"
|
|
||||||
|
|
|
@ -1,21 +1,32 @@
|
||||||
#include <QGuiApplication>
|
#include <QGuiApplication>
|
||||||
#include <QQmlApplicationEngine>
|
#include <QQmlApplicationEngine>
|
||||||
#include <QQuickStyle>
|
#include <QQuickStyle>
|
||||||
|
#include <thread>
|
||||||
|
|
||||||
int main(int argc, char *argv[])
|
#include "config/library.hpp"
|
||||||
{
|
#include "datalake/indexer.hpp"
|
||||||
QQuickStyle::setStyle(QStringLiteral("org.kde.breeze"));
|
|
||||||
QGuiApplication app(argc, argv);
|
|
||||||
app.setApplicationDisplayName("Koto");
|
|
||||||
app.setDesktopFileName("com.github.joshstrobl.koto.desktop");
|
|
||||||
|
|
||||||
QQmlApplicationEngine engine;
|
int main(int argc, char* argv[]) {
|
||||||
|
QQuickStyle::setStyle(QStringLiteral("org.kde.breeze"));
|
||||||
|
QGuiApplication app(argc, argv);
|
||||||
|
app.setApplicationDisplayName("Koto");
|
||||||
|
app.setDesktopFileName("com.github.joshstrobl.koto.desktop");
|
||||||
|
|
||||||
engine.loadFromModule("com.github.joshstrobl.koto", "Main");
|
QQmlApplicationEngine engine;
|
||||||
|
|
||||||
if (engine.rootObjects().isEmpty()) {
|
engine.loadFromModule("com.github.joshstrobl.koto", "Main");
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
return app.exec();
|
if (engine.rootObjects().isEmpty()) { return -1; }
|
||||||
|
|
||||||
|
// std::thread([]() {
|
||||||
|
// auto config = KotoLibraryConfig("Music", "/home/joshua/Music");
|
||||||
|
//
|
||||||
|
// auto indexExample = FileIndexer(&config);
|
||||||
|
// indexExample.index();
|
||||||
|
// }).detach();
|
||||||
|
Cartographer::create();
|
||||||
|
auto config = KotoLibraryConfig("Music", "/home/joshua/Music");
|
||||||
|
auto indexExample = FileIndexer(&config);
|
||||||
|
indexExample.index();
|
||||||
|
return app.exec();
|
||||||
}
|
}
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue