Skip to content

Commit

Permalink
feat: Add local index
Browse files Browse the repository at this point in the history
(and a lot more changes)
  • Loading branch information
FlafyDev committed Jun 7, 2024
1 parent c73e47f commit 3535c81
Show file tree
Hide file tree
Showing 15 changed files with 500 additions and 132 deletions.
3 changes: 1 addition & 2 deletions src/hooks/custom_song_widget.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -89,8 +89,7 @@ struct ANCustomSongWidget : geode::Modify<ANCustomSongWidget, CustomSongWidget>
void onNongBtn(CCObject *) {
for (int songId : getSongIds()) {
auto anSongs = AutoNongManager::get()->getNongsFromSongID(songId);
auto layer = ANDropdownLayer::create(
songId, AutoNongManager::get()->getNongsFromSongID(songId), this, 1, 1, m_isRobtopSong);
auto layer = ANDropdownLayer::create(songId, this, 1, 1, m_isRobtopSong);
layer->m_noElasticity = true;
layer->setZOrder(106);
layer->show();
Expand Down
77 changes: 49 additions & 28 deletions src/managers/auto_nong_manager.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,9 @@

std::vector<std::shared_ptr<ANSong>> AutoNongManager::getNongsFromSongID(int songID) {
if (m_songIDToNongs.find(songID) == m_songIDToNongs.end()) {
return std::vector<std::shared_ptr<ANSong>>{};
return {};
}

return m_songIDToNongs[songID];
}

Expand All @@ -17,13 +18,46 @@ bool AutoNongManager::anySongExists(std::set<int> songIDs) {
return false;
}

void AutoNongManager::reloadLocalIndex() {
for (auto &pair : m_songIDToNongs) {
auto &songs = pair.second;
songs.erase(std::remove_if(
songs.begin(), songs.end(),
[](const std::shared_ptr<ANSong> &song) { return song->m_index == "local"; }),
songs.end());
}

auto localIndex = Mod::get()->getSavedValue<std::vector<ANSong *>>("local-index");

log::info("Reloading local index with {} songs", localIndex.size());
loadIndex(localIndex, "local");
}

void AutoNongManager::removeSongFromLocalIndex(ANSong *song) {
auto localIndex = Mod::get()->getSavedValue<matjson::Array>("local-index", {});
localIndex.erase(std::remove_if(localIndex.begin(), localIndex.end(),
[song](const matjson::Value &value) {
return matjson::Serialize<ANSong *>::to_json(song) == value;
}),
localIndex.end());
Mod::get()->setSavedValue<matjson::Array>("local-index", localIndex);
reloadLocalIndex();
}

void AutoNongManager::addSongToLocalIndex(ANSong *song) {
auto localIndex = Mod::get()->getSavedValue<matjson::Array>("local-index", {});
localIndex.push_back(matjson::Serialize<ANSong *>::to_json(song));
Mod::get()->setSavedValue<matjson::Array>("local-index", localIndex);
reloadLocalIndex();
}

void AutoNongManager::loadIndexesSchedule(float) { loadIndexes(); }

void AutoNongManager::loadIndexes() {
std::vector<std::string> indexes =
Mod::get()->getSettingValue<MultiStringSettingStruct>("indexes").m_strings;

m_songIDToNongs = {};
reloadLocalIndex();

for (std::string index : indexes) {
if (index.size() < 5)
Expand Down Expand Up @@ -53,37 +87,24 @@ void AutoNongManager::loadIndexes() {
return;
}

for (const auto &songData : jsonObj.value().as_array()) {
const std::string name = songData["name"].as_string();
const std::string artist = songData.contains("artist") ? songData["artist"].as_string() : "";
const std::string source = songData["source"].as_string();
const int startOffsetMS = songData.contains("startOffset") ? songData["startOffset"].as_int() : 0;

std::shared_ptr<ANSong> song;
if (source == "youtube") {
std::string yt_id = songData["yt-id"].as_string();
song = std::make_shared<ANYTSong>(name, artist, index, startOffsetMS, yt_id);
} else if (source == "host") {
std::string url = songData["url"].as_string();
song = std::make_shared<ANHostSong>(name, artist, index, startOffsetMS, url);
} else {
log::warn("Unsupported source: {}", source);
continue;
}

if (songData.contains("songs")) {
for (matjson::Value songID : songData["songs"].as_array()) {
m_songIDToNongs[songID.as_int()].push_back(song);
}
}
}
Loader::get()->queueInMainThread(
[this, index]() { log::info("Loaded index: {}", index); });
auto vectors = matjson::Serialize<std::vector<ANSong *>>::from_json(jsonObj.value());

this->loadIndex(vectors, index);
})
.send();
}
}

void AutoNongManager::loadIndex(const std::vector<ANSong *> &indexJson, const std::string &index) {
for (ANSong *song : indexJson) {
for (const int songID : song->m_songIDs) {
song->m_index = index;
m_songIDToNongs[songID].push_back(std::shared_ptr<ANSong>(song));
}
}
Loader::get()->queueInMainThread([this, index]() { log::info("Loaded index: {}", index); });
}

void AutoNongManager::setCurrentLevelID(int levelID) { m_currentLevelID = levelID; }

int AutoNongManager::getCurrentLevelID() { return m_currentLevelID; }
4 changes: 4 additions & 0 deletions src/managers/auto_nong_manager.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -21,9 +21,13 @@ class AutoNongManager : public CCNode {
std::vector<std::shared_ptr<ANSong>> getNongsFromSongID(int songID);
bool anySongExists(std::set<int> songIDs);
void loadIndexes();
void loadIndex(const std::vector<ANSong *> &indexJson, const std::string &index);
int getCurrentLevelID();
void setCurrentLevelID(int levelID);
void loadIndexesSchedule(float);
void removeSongFromLocalIndex(ANSong *song);
void addSongToLocalIndex(ANSong *song);
void reloadLocalIndex();

static AutoNongManager *get() {
if (m_instance == nullptr) {
Expand Down
20 changes: 5 additions & 15 deletions src/types/an_song.cpp
Original file line number Diff line number Diff line change
@@ -1,20 +1,10 @@
#include "an_song.hpp"
#include "../utils/utils.hpp"

std::string ANSong::getSource() {
if (typeid(*this) == typeid(ANYTSong)) {
return "youtube";
} else if (typeid(*this) == typeid(ANHostSong)) {
return "host";
} else {
return "unknown";
}
}
std::string ANYTSong::getHash() const { return hashValues(m_ytId); }

std::string ANYTSong::getHash() {
return hashValues(m_name, m_artist, m_index, m_startOffsetMS, m_ytId);
}
std::string ANYTSong::getSource() const { return "youtube"; }

std::string ANHostSong::getHash() {
return hashValues(m_name, m_artist, m_index, m_startOffsetMS, m_url);
}
std::string ANHostSong::getHash() const { return hashValues(m_url); }

std::string ANHostSong::getSource() const { return "host"; }
103 changes: 90 additions & 13 deletions src/types/an_song.hpp
Original file line number Diff line number Diff line change
@@ -1,35 +1,112 @@
#pragma once

#include "../includes/geode.hpp"
#include "serializable_vector.hpp"
#include <matjson.hpp>
#include <memory>

class ANYTSong;
class ANHostSong;

class ANSong {
public:
ANSong(const std::string &name, const std::string &artist, const std::string &index, const int startOffsetMS)
: m_name(name), m_artist(artist), m_index(index), m_startOffsetMS(startOffsetMS) {}
ANSong(const std::string &name, const std::string &artist, const std::string &index,
const std::vector<int> &songIDs, const int startOffsetMS)
: m_name(name), m_artist(artist), m_index(index), m_songIDs(songIDs),
m_startOffsetMS(startOffsetMS) {}
std::string m_name;
std::string m_artist;
std::string m_index;
int m_startOffsetMS;
virtual ~ANSong() {}
virtual std::string getHash() = 0;
std::string getSource();
std::vector<int> m_songIDs;
virtual ~ANSong() = default;
virtual std::string getHash() const = 0;
virtual std::string getSource() const = 0;
};

class ANYTSong : public ANSong {
public:
ANYTSong(const std::string &name, const std::string &artist, const std::string &index, const int startOffsetMS,
const std::string &yt_id)
: ANSong(name, artist, index, startOffsetMS), m_ytId(yt_id) {}
ANYTSong(const std::string &name, const std::string &artist, const std::string &index,
const std::vector<int> &songIDs, const int startOffsetMS, const std::string &yt_id)
: ANSong(name, artist, index, songIDs, startOffsetMS), m_ytId(yt_id) {}
std::string m_ytId;
std::string getHash() override;
std::string getHash() const override;
std::string getSource() const override;
};

class ANHostSong : public ANSong {
public:
ANHostSong(const std::string &name, const std::string &artist, const std::string &index, const int startOffsetMS,
const std::string &url)
: ANSong(name, artist, index, startOffsetMS), m_url(url) {}
ANHostSong(const std::string &name, const std::string &artist, const std::string &index,
const std::vector<int> &songIDs, const int startOffsetMS, const std::string &url)
: ANSong(name, artist, index, songIDs, startOffsetMS), m_url(url) {}
std::string m_url;
std::string getHash() override;
std::string getHash() const override;
std::string getSource() const override;
};

template <> struct matjson::Serialize<ANSong *> {
static bool is_json(matjson::Value const &value) {
return value.is_object() && value.contains("source");
}

static ANSong *from_json(matjson::Value const &value) {
const std::string name = value["name"].as_string();
const std::string artist = value.contains("artist") ? value["artist"].as_string() : "";
const std::string source = value["source"].as_string();
const std::vector<int> songIDs =
matjson::Serialize<std::vector<int>>::from_json(value["songs"]);
const int startOffsetMS = value.contains("startOffset") ? value["startOffset"].as_int() : 0;

if (source == "youtube") {
const std::string ytId = value["yt-id"].as_string();
return new ANYTSong(name, artist, "", songIDs, startOffsetMS, ytId);
} else if (source == "host") {
const std::string url = value["url"].as_string();
return new ANHostSong(name, artist, "", songIDs, startOffsetMS, url);
} else {
return nullptr;
}
}

static matjson::Value to_json(const ANSong *song) {
matjson::Object obj;
obj["name"] = song->m_name;
obj["artist"] = song->m_artist;
obj["index"] = song->m_index;
obj["startOffset"] = song->m_startOffsetMS;
obj["songs"] = matjson::Serialize<std::vector<int>>::to_json(song->m_songIDs);
obj["source"] = song->getSource();

if (auto ytSong = dynamic_cast<const ANYTSong *>(song)) {
obj["yt-id"] = ytSong->m_ytId;
} else if (auto hostSong = dynamic_cast<const ANHostSong *>(song)) {
obj["url"] = hostSong->m_url;
}

return obj;
}
};

template <> struct matjson::Serialize<std::vector<ANSong *>> {
static bool is_json(matjson::Value const &value) { return value.is_array(); }

static std::vector<ANSong *> from_json(matjson::Value const &value) {
std::vector<ANSong *> vec;
if (!is_json(value)) {
return vec;
}
auto array = value.as_array();
for (const auto &elem : array) {
vec.push_back(matjson::Serialize<ANSong *>::from_json(elem));
}
return vec;
}

static matjson::Value to_json(std::vector<ANSong> &vec) {
auto array = matjson::Array();
for (auto &elem : vec) {
array.push_back(matjson::Serialize<ANSong *>::to_json(&elem));
}
return array;
}
};
11 changes: 9 additions & 2 deletions src/types/serializable_vector.hpp
Original file line number Diff line number Diff line change
@@ -1,13 +1,17 @@
#pragma once

#include <matjson.hpp>
#include <string>
#include <vector>

template <> struct matjson::Serialize<std::vector<int>> {
static bool is_json(matjson::Value const &value) { return value.is_array(); }

static std::vector<int> from_json(matjson::Value const &value) {
std::vector<int> vec;
if (!is_json(value)) {
return vec;
}
auto array = value.as_array();
for (auto const &elem : array) {
vec.push_back(elem.as_int());
Expand All @@ -18,7 +22,7 @@ template <> struct matjson::Serialize<std::vector<int>> {
static matjson::Value to_json(std::vector<int> const &vec) {
auto array = matjson::Array();
for (auto const &elem : vec) {
array.push_back(elem);
array.push_back(matjson::Value(elem));
}
return array;
}
Expand All @@ -29,6 +33,9 @@ template <> struct matjson::Serialize<std::vector<std::string>> {

static std::vector<std::string> from_json(matjson::Value const &value) {
std::vector<std::string> vec;
if (!is_json(value)) {
return vec;
}
auto array = value.as_array();
for (auto const &elem : array) {
vec.push_back(elem.as_string());
Expand All @@ -39,7 +46,7 @@ template <> struct matjson::Serialize<std::vector<std::string>> {
static matjson::Value to_json(std::vector<std::string> const &vec) {
auto array = matjson::Array();
for (auto const &elem : vec) {
array.push_back(elem);
array.push_back(matjson::Value(elem));
}
return array;
}
Expand Down
Loading

0 comments on commit 3535c81

Please sign in to comment.