Skip to content

Commit

Permalink
Merge pull request #58 from Fleeym/v3-nong-data
Browse files Browse the repository at this point in the history
Lots of stuff lol
  • Loading branch information
Fleeym authored Oct 6, 2024
2 parents c1d6061 + 875ead2 commit 90c8666
Show file tree
Hide file tree
Showing 55 changed files with 4,941 additions and 1,537 deletions.
1 change: 1 addition & 0 deletions .github/workflows/build.yml
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ on:
push:
branches:
- "main"
- "v3-nong-data"

jobs:
build:
Expand Down
1 change: 1 addition & 0 deletions CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ file(GLOB SOURCES
src/hooks/*.cpp
src/events/*.cpp
src/api/*.cpp
src/utils/*.cpp
src/*.cpp
)

Expand Down
70 changes: 70 additions & 0 deletions include/index.hpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,70 @@
#pragma once

#include <fmt/core.h>
#include <matjson.hpp>
#include <optional>

#include "platform.hpp"

namespace jukebox {

struct JUKEBOX_DLL IndexSource final {
std::string m_url;
bool m_userAdded;
bool m_enabled;

bool operator==(IndexSource const& other) const {
return m_url == other.m_url && m_userAdded == other.m_userAdded && m_enabled == other.m_enabled;
}
};

struct IndexMetadata final {
struct Links final {
std::optional<std::string> m_discord = std::nullopt;
};

struct Features {
struct RequestParams final {
std::string m_url;
bool m_params;
};

struct RequestLink final {
std::string m_url;
};

enum class SupportedSongType {
local,
youtube,
hosted,
};

struct Submit final {
std::optional<RequestParams> m_requestParams = std::nullopt;
std::optional<std::string> m_preSubmitMessage;
std::unordered_map<SupportedSongType, bool> m_supportedSongTypes = {
{SupportedSongType::local, false},
{SupportedSongType::youtube, false},
{SupportedSongType::hosted, false},
};
};

struct Report final {
std::optional<RequestParams> m_requestParams = std::nullopt;
};

std::optional<Submit> m_submit = std::nullopt;
std::optional<Report> m_report = std::nullopt;
};

int m_manifest;
std::string m_url;
std::string m_id;
std::string m_name;
std::optional<std::string> m_description;
std::optional<int> m_lastUpdate;
Links m_links;
Features m_features;
};

}
191 changes: 191 additions & 0 deletions include/index_serialize.hpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,191 @@
#pragma once

#include "index.hpp"

template<>
struct matjson::Serialize<jukebox::IndexMetadata::Features::RequestParams> {
static geode::Result<jukebox::IndexMetadata::Features::RequestParams> from_json(matjson::Value const& value, int manifest) {
if (manifest != 1) return geode::Err("Using unsupported manifest version: " + std::to_string(manifest));

if (!value.is_object()) {
return geode::Err("Expected object in requestParams");
}
if (!value.contains("url") || !value["url"].is_string()) {
return geode::Err("Expected url in requestParams");
}
if (!value.contains("params") || !value["params"].is_bool()) {
return geode::Err("Expected params in requestParams");
}

return geode::Ok(jukebox::IndexMetadata::Features::RequestParams {
.m_url = value["url"].as_string(),
.m_params = value["params"].as_bool()
});
}
};

template<>
struct matjson::Serialize<jukebox::IndexMetadata::Features> {
protected:
static geode::Result<jukebox::IndexMetadata::Features::SupportedSongType> getSupportedSongTypeFromString(const std::string& str) {
if (str == "local") return geode::Ok(jukebox::IndexMetadata::Features::SupportedSongType::local);
if (str == "youtube") return geode::Ok(jukebox::IndexMetadata::Features::SupportedSongType::youtube);
if (str == "hosted") return geode::Ok(jukebox::IndexMetadata::Features::SupportedSongType::hosted);
return geode::Err("Invalid supported song type: " + str);
}
public:
static geode::Result<jukebox::IndexMetadata::Features> from_json(matjson::Value const& value, int manifest) {
if (manifest != 1) return geode::Err("Using unsupported manifest version: " + std::to_string(manifest));

if (!value.is_object()) {
return geode::Err("Expected object in features");
}

jukebox::IndexMetadata::Features features;

const auto& featuresObj = value;

if (featuresObj.contains("submit")) {
if (!featuresObj["submit"].is_object()) {
return geode::Err("Expected submit to be an object in features");
}
const auto& submitObj = featuresObj["submit"];

features.m_submit = jukebox::IndexMetadata::Features::Submit { };

if (submitObj.contains("preSubmitMessage")) {
if (!submitObj["preSubmitMessage"].is_string()) {
return geode::Err("Expected preSubmitMessage to be a string in submit");
}
features.m_submit.value().m_preSubmitMessage = submitObj["preSubmitMessage"].as_string();
}

if (submitObj.contains("supportedSongTypes")) {
if (!submitObj["supportedSongTypes"].is_array()) {
return geode::Err("Expected supportedSongTypes to be an array in submit");
}
for (const auto& songType : submitObj["supportedSongTypes"].as_array()) {
if (!songType.is_string()) {
return geode::Err("Expected supportedSongTypes to be an array of strings in submit");
}
auto supportedSongType = getSupportedSongTypeFromString(songType.as_string());
if (supportedSongType.isErr()) {
return geode::Err(supportedSongType.error());
}
features.m_submit.value().m_supportedSongTypes[supportedSongType.value()] = true;
}
}

if (submitObj.contains("requestParams")) {
auto requestParams = matjson::Serialize<jukebox::IndexMetadata::Features::RequestParams>::from_json(submitObj["requestParams"], manifest);
if (requestParams.isErr()) {
return geode::Err(requestParams.error());
}
features.m_submit.value().m_requestParams = requestParams.value();
}
}

if (featuresObj.contains("report")) {
if (!featuresObj["report"].is_object()) {
return geode::Err("Expected search to be an object in features");
}
const auto& searchObj = featuresObj["report"];

features.m_report = jukebox::IndexMetadata::Features::Report { };

if (searchObj.contains("requestParams")) {
auto requestParams = matjson::Serialize<jukebox::IndexMetadata::Features::RequestParams>::from_json(searchObj["requestParams"], manifest);
if (requestParams.isErr()) {
return geode::Err(requestParams.error());
}
features.m_report.value().m_requestParams = requestParams.value();
}
}

return geode::Ok(features);
};
};

template<>
struct matjson::Serialize<jukebox::IndexMetadata> {
static geode::Result<jukebox::IndexMetadata> from_json(matjson::Value const& value) {
if (!value.is_object()) {
return geode::Err("Expected object");
}

if (!value.contains("manifest") || !value["manifest"].is_number()) {
return geode::Err("Expected manifest version");
}
const int manifestVersion = value["manifest"].as_int();

if (manifestVersion == 1) {
// Links
jukebox::IndexMetadata::Links links;
if (value.contains("links") && value["links"].is_object()) {
const auto& linksObj = value["links"];
if (linksObj.contains("discord")) {
if (!linksObj["discord"].is_string()) {
return geode::Err("Expected discord to be a string in links");
}
}
links.m_discord = linksObj["discord"].as_string();
}

// Features
const auto featuresResult = value.contains("features")
? matjson::Serialize<jukebox::IndexMetadata::Features>::from_json(value["features"], manifestVersion)
: geode::Ok(jukebox::IndexMetadata::Features());
if (featuresResult.has_error()) {
return geode::Err(featuresResult.error());
}

// Validate fields
if (!value.contains("name") || !value["name"].is_string()) {
return geode::Err("Expected name");
}
if (!value.contains("id") || !value["id"].is_string()) {
return geode::Err("Expected id");
}
if (value.contains("description") && !value["description"].is_string()) {
return geode::Err("Description must be a string");
}

return geode::Ok(jukebox::IndexMetadata {
.m_manifest = manifestVersion,
.m_url = value["url"].as_string(),
.m_id = value["id"].as_string(),
.m_name = value["name"].as_string(),
.m_description = value.contains("description")
&& value["description"].is_string()
? std::optional(value["description"].as_string())
: std::nullopt,
.m_lastUpdate = value.contains("lastUpdate") && value["lastUpdate"].is_number()
? std::optional(value["lastUpdate"].as_int())
: std::nullopt,
.m_links = links,
.m_features = featuresResult.value()
});
}

return geode::Err("Using unsupported manifest version: " + std::to_string(manifestVersion));
}
};

template<>
struct matjson::Serialize<jukebox::IndexSource> {
static jukebox::IndexSource from_json(matjson::Value const& value) {
return jukebox::IndexSource {
.m_url = value["url"].as_string(),
.m_userAdded = value["userAdded"].as_bool(),
.m_enabled = value["enabled"].as_bool()
};
}

static matjson::Value to_json(jukebox::IndexSource const& value) {
auto indexObject = matjson::Object();
indexObject["url"] = value.m_url;
indexObject["userAdded"] = value.m_userAdded;
indexObject["enabled"] = value.m_enabled;
return indexObject;
}
};
82 changes: 37 additions & 45 deletions include/jukebox.hpp
Original file line number Diff line number Diff line change
@@ -1,56 +1,48 @@
#pragma once

#include "../src/types/song_info.hpp"
#include "../include/nong.hpp"
#include "platform.hpp"
#include <optional>

#ifdef GEODE_IS_WINDOWS
#ifdef FLEYM_JUKEBOX_EXPORTING
#define JUKEBOX_DLL __declspec(dllexport)
#else
#define JUKEBOX_DLL __declspec(dllimport)
#endif
#else
#define JUKEBOX_DLL __attribute__((visibility("default")))
#endif

namespace jukebox {
/**
* Adds a NONG to the JSON of a songID
*
* @param song the song to add
* @param songID the id of the song
*/
JUKEBOX_DLL void addNong(SongInfo const& song, int songID);
// /**
// * Adds a NONG to the JSON of a songID
// *
// * @param song the song to add
// * @param songID the id of the song
// */
// JUKEBOX_DLL void addNong(SongInfo const& song, int songID);

/**
* Sets the active song of a songID
*
* @param song the song to set as active
* @param songID the id of the song
* @param customSongWidget optional custom song widget to update
*/
JUKEBOX_DLL void setActiveNong(SongInfo const& song, int songID, const std::optional<geode::Ref<CustomSongWidget>>& customSongWidget);
// /**
// * Sets the active song of a songID
// *
// * @param song the song to set as active
// * @param songID the id of the song
// * @param customSongWidget optional custom song widget to update
// */
// JUKEBOX_DLL void setActiveNong(SongInfo const& song, int songID, const std::optional<geode::Ref<CustomSongWidget>>& customSongWidget);

/**
* Gets the active song of a songID
*
* @param songID the id of the song
*/
JUKEBOX_DLL std::optional<SongInfo> getActiveNong(int songID);
// /**
// * Gets the active song of a songID
// *
// * @param songID the id of the song
// */
// JUKEBOX_DLL std::optional<SongInfo> getActiveNong(int songID);

/**
* Deletes a NONG from the JSON of a songID
*
* @param song the song to delete
* @param songID the id of the replaced song
* @param deleteFile whether to delete the corresponding audio file created by Jukebox
*/
JUKEBOX_DLL void deleteNong(SongInfo const& song, int songID, bool deleteFile = true);
// /**
// * Deletes a NONG from the JSON of a songID
// *
// * @param song the song to delete
// * @param songID the id of the replaced song
// * @param deleteFile whether to delete the corresponding audio file created by Jukebox
// */
// JUKEBOX_DLL void deleteNong(SongInfo const& song, int songID, bool deleteFile = true);

/**
* Sets the song of the songID as the default song provided by GD
*
* @param songID the id of the song
*/
JUKEBOX_DLL std::optional<SongInfo> getDefaultNong(int songID);
// /**
// * Sets the song of the songID as the default song provided by GD
// *
// * @param songID the id of the song
// */
// JUKEBOX_DLL std::optional<SongInfo> getDefaultNong(int songID);
}
Loading

0 comments on commit 90c8666

Please sign in to comment.