Created
November 9, 2021 17:58
-
-
Save ITotalJustice/7dd2fc20c8ed22caa35ea8c5dbe0a59e to your computer and use it in GitHub Desktop.
funi
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#pragma once | |
#include "../nlohmann/json_fwd.hpp" | |
#include <cstdint> | |
#include <string> | |
#include <vector> | |
#include <optional> | |
namespace funi { | |
// the only none bloat struct that funi uses! | |
struct Account { | |
struct User { | |
std::uint32_t id; | |
std::string first_name; | |
std::string last_name; | |
std::string email; | |
std::string last_login_local; | |
std::string displayName; | |
std::string avatar; | |
std::string defaultLanguage; | |
std::string last_login; | |
std::string date_joined; | |
friend void from_json(const json& j, User& g); | |
}; | |
std::string token; | |
std::string rlildup_cookie; | |
User user; | |
std::string user_region; | |
friend void from_json(const json& j, Account& g); | |
}; | |
} // namespace funi |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#pragma once | |
#include "../nlohmann/json_fwd.hpp" | |
#include "types.hpp" | |
#include <cstdint> | |
#include <string> | |
#include <vector> | |
#include <optional> | |
namespace funi { | |
struct EpisodeEntry { | |
struct Item { | |
std::optional<SeasonID> seasonId; | |
std::string episodeNum; | |
EpisodeID episodeId; | |
TitleID titleId; | |
std::optional<std::string> seasonNum; | |
std::string episodeName; | |
friend void from_json(const json& j, Item& g); | |
}; | |
float starRating; | |
std::string synopsis; | |
std::string mediaCategory; | |
std::string contentType; | |
std::vector<std::string> genres; | |
Item item; | |
auto GetEpisodeID() const noexcept { return this->item.episodeId; } | |
// auto GetSeasonID() const noexcept { return this->item.sea; } | |
friend void from_json(const json& j, EpisodeEntry& g); | |
}; | |
struct EpisodeResult { | |
std::uint32_t count; | |
std::vector<EpisodeEntry> items; | |
int limit; | |
std::uint32_t offset; | |
std::uint32_t total; | |
auto Empty() const noexcept { return this->items.empty(); } | |
friend void from_json(const json& j, EpisodeResult& g); | |
}; | |
} // namespace funi |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#include "funapi.hpp" | |
#include "../nlohmann/json.hpp" | |
#include "../hlsparse/hlsparse.hpp" | |
#include "../../utils/logger.hpp" | |
#ifdef __SWITCH__ | |
#include <sys/select.h> | |
#endif | |
#include <curl/curl.h> | |
#include <cassert> | |
// todo: save auth token | |
#include <fstream> | |
namespace funi { | |
static constexpr auto API_URL = "https://prod-api-funimationnow.dadcdigital.com/api/"; | |
static auto DebugDump(const std::string& path, const std::string& data) -> void { | |
#if 0 | |
std::ofstream fs{path}; | |
if (fs.good()) { | |
fs << data; | |
} | |
#endif | |
} | |
#define GET_HELPER(type) \ | |
if (auto result = this->Get(stk, cmd, data)) { \ | |
DebugDump(#type + std::to_string(id) + ".json", *result); \ | |
try { \ | |
return json::parse(*result).get<type>(); \ | |
} catch (std::exception& e) { \ | |
LOG("[FUNI-THROW] in %s ID: %u : %s\n", __func__, id, e.what()); \ | |
} \ | |
} \ | |
return {}; | |
Funapi::Funapi() { | |
} | |
Funapi::~Funapi() { | |
} | |
auto Funapi::LoginAsync(std::stop_token stk, const std::string& user, const std::string& pass) -> bool { | |
static constexpr auto cmd = "auth/login/"; | |
const auto data = "username=" + user + "&password=" + pass; | |
if (auto result = this->Post(stk, cmd, data)) { | |
DebugDump("funi_login.json", *result); | |
return true; | |
} | |
return false; | |
} | |
auto Funapi::LogoutAsync(std::stop_token stk) -> bool { | |
this->account = std::nullopt; | |
// static constexpr auto cmd = "auth/logout/"; | |
// if (auto result = this->Post(cmd, data)) { | |
// return true; | |
// } | |
return false; | |
} | |
// auto Funapi::GetLibrary() -> std::optional<Episodes> { | |
// static constexpr auto cmd = "source/funimation/search/auto/"; | |
// const auto data = "?unique=true&limit=" + std::to_string(limit) + "&q=" + q + "&offset=" + std::to_string(offset); | |
// if (auto result = this->Get(cmd, data)) { | |
// return json::parse(*result).get<Media>(); | |
// DebugDump("funi_search.json", *result); | |
// } | |
// return {}; | |
// } | |
auto Funapi::GetHistoryAsync(std::stop_token stk, int limit) -> std::optional<EpisodeResult> { | |
static constexpr auto cmd = "source/funimation/history/"; | |
const auto data = "?unique=true&limit=" + std::to_string(limit); | |
if (auto result = this->Get(stk, cmd, data)) { | |
DebugDump("funi_history.json", *result); | |
return json::parse(*result).get<EpisodeResult>(); | |
} | |
return {}; | |
} | |
auto Funapi::GetQueueAsync(std::stop_token stk, int limit) -> std::optional<EpisodeResult> { | |
static constexpr auto cmd = "source/funimation/queue/"; | |
const auto data = "?unique=true&limit=" + std::to_string(limit); | |
if (auto result = this->Get(stk, cmd, data)) { | |
DebugDump("funi_queue.json", *result); | |
return json::parse(*result).get<EpisodeResult>(); | |
} | |
return {}; | |
} | |
auto Funapi::ListGenresAsync(std::stop_token stk, int limit, std::uint32_t offset) -> std::optional<Genres> { | |
static constexpr auto cmd = "funimation/genres/"; | |
const auto data = "?limit=" + std::to_string(limit) + "&offset=" + std::to_string(offset); | |
if (auto result = this->Get(stk, cmd, data)) { | |
DebugDump("genres.json", *result); | |
return json::parse(*result).get<Genres>(); | |
} | |
return {}; | |
} | |
auto Funapi::ListTitlesFromGenreAsync(std::stop_token stk, GenreID id, int limit, std::uint32_t offset) -> std::optional<GenresTitles> { | |
static constexpr auto cmd = "source/catalog/genres/"; | |
const auto data = std::to_string(id) + "/?limit=" + std::to_string(limit) + "&offset=" + std::to_string(offset); | |
GET_HELPER(GenresTitles); | |
} | |
auto Funapi::ListTitlesFromGenre2Async(std::stop_token stk, GenreID id, int limit, std::uint32_t offset) -> std::optional<GenresTitles2> { | |
static constexpr auto cmd = "funimation/genres/"; | |
const auto data = std::to_string(id) + "/?limit=" + std::to_string(limit) + "&offset=" + std::to_string(offset); | |
GET_HELPER(GenresTitles2); | |
} | |
auto Funapi::SearchAsync(std::stop_token stk, const std::string& q, int limit, uint32_t offset) -> std::optional<SearchResult> { | |
static constexpr auto cmd = "source/funimation/search/auto/"; | |
const auto data = "?unique=true&limit=" + std::to_string(limit) + "&q=" + q + "&offset=" + std::to_string(offset); | |
if (auto result = this->Get(stk, cmd, data)) { | |
DebugDump("funi_search.json", *result); | |
return json::parse(*result).get<SearchResult>(); | |
} | |
return {}; | |
} | |
auto Funapi::GetTitleInfoAsync(std::stop_token stk, TitleID id) -> std::optional<TitleInfo> { | |
static constexpr auto cmd = "source/catalog/title/"; | |
const auto data = std::to_string(id); | |
GET_HELPER(TitleInfo); | |
} | |
auto Funapi::ListEpisodesAsync(std::stop_token stk, TitleID id, std::optional<SeasonID> season, int limit) -> std::optional<EpisodeResult> { | |
static constexpr auto cmd = "funimation/episodes/"; | |
const auto data = [&](){ | |
if (season.has_value()) { | |
return "?season=" + std::to_string(*season) + "&limit=" + std::to_string(limit) + "&sort=order&sort_direction=ASC&title_id=" + std::to_string(id); | |
} | |
return "?limit=" + std::to_string(limit) + "&sort=order&sort_direction=ASC&title_id=" + std::to_string(id); | |
}(); | |
GET_HELPER(EpisodeResult); | |
} | |
auto Funapi::GetEpisodeAsync(std::stop_token stk, EpisodeID id) -> std::optional<EpisodeMedia> { | |
static constexpr auto cmd = "source/catalog/episode/"; | |
const auto data = std::to_string(id); | |
GET_HELPER(EpisodeMedia); | |
} | |
auto Funapi::GetShowExperienceAsync(std::stop_token stk, ExperienceID id) -> std::optional<ShowExperience> { | |
static constexpr auto cmd = "source/catalog/video/"; | |
const auto data = std::to_string(id) + "/signed/"; | |
GET_HELPER(ShowExperience); | |
} | |
auto Funapi::Get(std::stop_token stk, const std::string& cmd, const std::string& data) -> std::optional<std::string> { | |
const auto url = API_URL + cmd + data; | |
LOG("[FUNI-INFO] Get-URL: %s\n", url.c_str()); | |
return this->curl.Download( | |
curl::Url{url}, | |
curl::Header{ | |
{"devicetype", "Android"}, | |
{"Authorization", "Token cd2c113ad3a3fc7ac31b9d8a0fb7d140862c2ef4"} | |
}, | |
curl::StopCallback{[stk](){ | |
return stk.stop_requested(); | |
}} | |
); | |
} | |
auto Funapi::Post(std::stop_token stk, const std::string& cmd, const std::string& data) -> std::optional<std::string> { | |
const auto url = API_URL + cmd; | |
// LOG("[FUNI-INFO] Post-URL: %s\n", url.c_str()); | |
return this->curl.Download( | |
curl::Url{url}, | |
curl::Fields{data}, | |
curl::Header{ | |
{"devicetype", "Android"}, | |
{"Authorization", "Token cd2c113ad3a3fc7ac31b9d8a0fb7d140862c2ef4"} | |
}, | |
curl::StopCallback{[stk](){ | |
return stk.stop_requested(); | |
}} | |
); | |
} | |
} // namespace funi |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// very simple funimation api wrapper. | |
// funi api returns some of the most bloated json's i have ever seen. | |
// any request about *anything* returns *all* data linked to it. | |
// for example, look at a single entry in a history json, its 20kb. | |
// because of this, i've made much smaller (and sainer) structs that only | |
// contain useful data. | |
#pragma once | |
#include "account.hpp" | |
#include "episode.hpp" | |
#include "search.hpp" | |
#include "media.hpp" | |
#include "showexperience.hpp" | |
#include "titleinfo.hpp" | |
#include "language.hpp" | |
#include "genre.hpp" | |
#include "types.hpp" | |
#include "../curlwrapper/curl_wrapper.hpp" | |
#include <stop_token> | |
namespace funi { | |
class Funapi { | |
public: | |
enum class UrlType { HLS, MP4, ANY }; | |
public: | |
Funapi(); | |
~Funapi(); | |
auto LoginAsync(std::stop_token token, const std::string& user, const std::string& pass) -> bool; | |
auto Login(const std::string& user, const std::string& pass) -> bool { | |
return this->LoginAsync(std::stop_token{}, user, pass); | |
} | |
auto LogoutAsync(std::stop_token token) -> bool; | |
auto Logout() -> bool { | |
return this->LogoutAsync(std::stop_token{}); | |
} | |
// need auth! | |
// auto GetLibrary() -> std::optional<EpisodeResult>; | |
auto GetHistoryAsync(std::stop_token token, int limit = 30) -> std::optional<EpisodeResult>; | |
auto GetHistory(int limit = 30) -> std::optional<EpisodeResult> { | |
return this->GetHistoryAsync(std::stop_token{}, limit); | |
} | |
auto GetQueueAsync(std::stop_token token, int limit = 30) -> std::optional<EpisodeResult>; | |
auto GetQueue(int limit = 30) -> std::optional<EpisodeResult> { | |
return this->GetQueueAsync(std::stop_token{}, limit); | |
} | |
auto ListGenresAsync(std::stop_token token, int limit = -1, std::uint32_t offset = 0) -> std::optional<Genres>; | |
auto ListGenres(int limit = -1, std::uint32_t offset = 0) -> std::optional<Genres> { | |
return this->ListGenresAsync(std::stop_token{}, limit); | |
} | |
// seems to list a lot more titles, though does list those that aren't | |
// avaliable in matching regions... | |
auto ListTitlesFromGenreAsync(std::stop_token token, GenreID id, int limit = -1, std::uint32_t offset = 0) -> std::optional<GenresTitles>; | |
auto ListTitlesFromGenre(GenreID id, int limit = -1, std::uint32_t offset = 0) -> std::optional<GenresTitles> { | |
return this->ListTitlesFromGenreAsync(std::stop_token{}, id, limit, offset); | |
} | |
// returns less items, but seems to be better sorted by good anime, such | |
// that AOT and black clover are near the top. | |
// the json data is extremely bloated so will take longer to download, | |
// though this function should be preferred. | |
auto ListTitlesFromGenre2Async(std::stop_token token, GenreID id, int limit = -1, std::uint32_t offset = 0) -> std::optional<GenresTitles2>; | |
auto ListTitlesFromGenre2(GenreID id, int limit = -1, std::uint32_t offset = 0) -> std::optional<GenresTitles2> { | |
return this->ListTitlesFromGenre2Async(std::stop_token{}, id, limit, offset); | |
} | |
auto SearchAsync(std::stop_token token, const std::string& name, int limit = 25, std::uint32_t offset = 0) -> std::optional<SearchResult>; | |
auto Search(const std::string& name, int limit = 25, std::uint32_t offset = 0) -> std::optional<SearchResult> { | |
return this->SearchAsync(std::stop_token{}, name, limit, offset); | |
} | |
auto GetTitleInfoAsync(std::stop_token token, TitleID id) -> std::optional<TitleInfo>; | |
auto GetTitleInfo(TitleID id) -> std::optional<TitleInfo> { | |
return this->GetTitleInfoAsync(std::stop_token{}, id); | |
} | |
auto ListEpisodesAsync(std::stop_token token, TitleID id, std::optional<SeasonID> season = {}, int limit = -1) -> std::optional<EpisodeResult>; | |
auto ListEpisodes(TitleID id, std::optional<SeasonID> season = {}, int limit = -1) -> std::optional<EpisodeResult> { | |
return this->ListEpisodesAsync(std::stop_token{}, id, season, limit); | |
} | |
auto GetEpisodeAsync(std::stop_token token, EpisodeID id) -> std::optional<EpisodeMedia>; | |
auto GetEpisode(EpisodeID id) -> std::optional<EpisodeMedia> { | |
return this->GetEpisodeAsync(std::stop_token{}, id); | |
} | |
auto GetShowExperienceAsync(std::stop_token token, ExperienceID id) -> std::optional<ShowExperience>; | |
auto GetShowExperience(ExperienceID id) -> std::optional<ShowExperience> { | |
return this->GetShowExperienceAsync(std::stop_token{}, id); | |
} | |
// static auto GetMediaUri() | |
private: | |
auto Get(std::stop_token token, const std::string& cmd, const std::string& data) -> std::optional<std::string>; | |
auto Post(std::stop_token token, const std::string& cmd, const std::string& data) -> std::optional<std::string>; | |
private: | |
std::optional<Account> account; | |
curl::CurlWrapper curl; | |
}; | |
} // namespace funi |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#include "account.hpp" | |
#include "episode.hpp" | |
#include "media.hpp" | |
#include "search.hpp" | |
#include "showexperience.hpp" | |
#include "titleinfo.hpp" | |
#include "language.hpp" | |
#include "genre.hpp" | |
#include "../nlohmann/helper.hpp" | |
#define JSON_SET(name) j.at(#name).get_to(g.name) | |
#define JSON_SET_OP(name) if (j.contains(#name)) { j.at(#name).get_to(g.name); } | |
namespace funi { | |
void from_json(const json& j, Account::User& g) { | |
JSON_SET(id); | |
JSON_SET(first_name); | |
JSON_SET(last_name); | |
JSON_SET(email); | |
JSON_SET(last_login_local); | |
JSON_SET(displayName); | |
JSON_SET(avatar); | |
JSON_SET(defaultLanguage); | |
JSON_SET(last_login); | |
JSON_SET(date_joined); | |
} | |
void from_json(const json& j, Account& g) { | |
JSON_SET(token); | |
JSON_SET(rlildup_cookie); | |
JSON_SET(user); | |
JSON_SET(user_region); | |
} | |
void from_json(const json& j, EpisodeEntry::Item& g) { | |
JSON_SET(seasonId); | |
JSON_SET(episodeNum); | |
JSON_SET(episodeId); | |
JSON_SET(titleId); | |
JSON_SET(episodeName); | |
} | |
void from_json(const json& j, EpisodeEntry& g) { | |
JSON_SET(starRating); | |
JSON_SET(synopsis); | |
JSON_SET(mediaCategory); | |
JSON_SET(contentType); | |
JSON_SET(genres); | |
JSON_SET(item); | |
} | |
void from_json(const json& j, EpisodeResult& g) { | |
JSON_SET(count); | |
JSON_SET(limit); | |
JSON_SET(offset); | |
JSON_SET(items); | |
JSON_SET(total); | |
} | |
void from_json(const json& j, MediaInfo::Video& g) { | |
JSON_SET(codecId); | |
JSON_SET(container); | |
JSON_SET(frameRate); | |
JSON_SET(height); | |
JSON_SET(width); | |
} | |
void from_json(const json& j, MediaInfo& g) { | |
JSON_SET(format); | |
JSON_SET(frameHeight); | |
JSON_SET(frameWidth); | |
} | |
void from_json(const json& j, Language& g) { | |
JSON_SET(code); | |
JSON_SET(id); | |
JSON_SET(title); | |
} | |
void from_json(const json& j, MediaEntryChild& g) { | |
JSON_SET(id); | |
// JSON_SET(experienceType); | |
JSON_SET(ext); | |
JSON_SET(mediaType); | |
JSON_SET(status); | |
JSON_SET(languages); | |
// bug in nlohman json. | |
// there's a filepath field that sometimes exists. | |
// i think nlohman checks the first child struct for members | |
// and doesn't check the rest as it cannot find filepath at all! | |
JSON_SET(image); | |
static constexpr std::string_view sub_enc_filter = "/exp"; | |
if (auto itr = g.image.find(sub_enc_filter); itr != g.image.npos) { | |
g.image.erase(itr, sub_enc_filter.size()); | |
} | |
JSON_SET(seriesTitle); | |
JSON_SET(episodeTitle); | |
} | |
void from_json(const json& j, MediaEntry& g) { | |
JSON_SET(id); | |
JSON_SET(title); | |
JSON_SET(experienceType); | |
JSON_SET(ext); | |
JSON_SET(mediaType); | |
JSON_SET(status); | |
JSON_SET(languages); | |
JSON_SET(mediaChildren); | |
} | |
void from_json(const json& j, EpisodeMedia::Item& g) { | |
JSON_SET(id); | |
JSON_SET(title); | |
JSON_SET(number); | |
JSON_SET(description); | |
JSON_SET(media); | |
} | |
void from_json(const json& j, EpisodeMedia& g) { | |
JSON_SET(items); | |
} | |
void from_json(const json& j, Error& g) { | |
JSON_SET(code); | |
JSON_SET(detail); | |
JSON_SET(title); | |
} | |
void from_json(const json& j, ShowExperience::Item& g) { | |
JSON_SET(src); | |
JSON_SET(kind); | |
JSON_SET(isPromo); | |
JSON_SET(videoType); | |
JSON_SET(experienceId); | |
JSON_SET(showAds); | |
JSON_SET(id); | |
} | |
void from_json(const json& j, ShowExperience& g) { | |
JSON_SET_OP(items); | |
JSON_SET_OP(watchHistorySaveInterval); | |
} | |
void from_json(const json& j, SearchEntry& g) { | |
JSON_SET(languages); | |
JSON_SET(star_rating); | |
JSON_SET(title); | |
JSON_SET(synopsis); | |
// the ID for search is actually a string. | |
// because of the rest of the api using ints, i convert the | |
// id to a int. | |
// char id_buffer[11]{}; | |
std::string id_buffer{12}; | |
j.at("id").get_to(id_buffer); | |
g.id = std::stoul(id_buffer); | |
// g.id = std::strtoul(id_buffer, nullptr, 10); | |
} | |
void from_json(const json& j, SearchResult::Items& g) { | |
JSON_SET(hits); | |
JSON_SET(total); | |
} | |
void from_json(const json& j, SearchResult& g) { | |
JSON_SET(count); | |
JSON_SET(items); | |
JSON_SET(limit); | |
JSON_SET(queryId); | |
JSON_SET(offset); | |
} | |
void from_json(const json& j, TitleInfo::Item::ChildrenCounts& g) { | |
// different name for extras | |
if (j.contains("episodes")) { | |
j.at("episodes").get_to(g.episodes); | |
} else if (j.contains("episode")) { | |
j.at("episode").get_to(g.episodes); | |
} | |
JSON_SET_OP(extras); // not all have extras (SAO) | |
} | |
void from_json(const json& j, TitleInfo::Item::Children& g) { | |
JSON_SET(title); | |
JSON_SET(number); | |
JSON_SET(childCount); | |
JSON_SET(id); | |
JSON_SET(mediaCategory); | |
JSON_SET(order); | |
} | |
void from_json(const json& j, TitleInfo::Item& g) { | |
JSON_SET(id); | |
JSON_SET(title); | |
JSON_SET(childrenCounts); | |
JSON_SET(children); | |
JSON_SET(audio); | |
JSON_SET(type); | |
} | |
void from_json(const json& j, TitleInfo& g) { | |
JSON_SET(items); | |
} | |
void from_json(const json& j, GenresTitles::Item& g) { | |
JSON_SET(title); | |
JSON_SET(id); | |
JSON_SET(audio); | |
JSON_SET(subtitles); | |
} | |
void from_json(const json& j, GenresTitles& g) { | |
JSON_SET(id); | |
JSON_SET(title); | |
JSON_SET(description); | |
JSON_SET(items); | |
} | |
void from_json(const json& j, GenresTitles2::Item& g) { | |
JSON_SET(title); | |
JSON_SET(itemId); | |
} | |
void from_json(const json& j, GenresTitles2& g) { | |
JSON_SET(title); | |
JSON_SET(items); | |
JSON_SET(offset); | |
JSON_SET(id); | |
JSON_SET(limit); | |
JSON_SET(total); | |
} | |
void from_json(const json& j, GenreEntry& g) { | |
JSON_SET(description); | |
JSON_SET(id); | |
JSON_SET(name); | |
} | |
} // namespace funi |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#pragma once | |
#include "../nlohmann/json_fwd.hpp" | |
#include "types.hpp" | |
#include <cstdint> | |
#include <string> | |
#include <vector> | |
#include <optional> | |
namespace funi { | |
enum class Genre { | |
ACTION = 34, | |
COMEDY = 8, | |
DRAMA = 5, | |
FAN_SERVICE = 15, | |
FANTASY = 6, | |
HORROR = 9, | |
LIVE_ACTION = 47, | |
PSYCHOLOGICAL = 37, | |
ROMANCE = 33, | |
SCIFI = 35, | |
SHOUJO = 44, | |
SHOUNEN = 38, | |
SLICE_OF_LIFE = 26 | |
}; | |
struct GenresTitles { | |
struct Item { | |
std::string title; | |
TitleID id; // title_id | |
std::vector<std::string> audio; // langs | |
std::vector<std::string> subtitles; // langs | |
friend void from_json(const json& j, Item& g); | |
}; | |
GenreID id; | |
std::string title; | |
std::string description; | |
std::vector<Item> items; | |
friend void from_json(const json& j, GenresTitles& g); | |
}; | |
struct GenresTitles2 { | |
struct Item { | |
std::string title; | |
TitleID itemId; // title_id | |
friend void from_json(const json& j, Item& g); | |
}; | |
std::string title; | |
std::vector<Item> items; | |
std::uint32_t offset; | |
GenreID id; | |
int limit; | |
std::uint32_t total; | |
friend void from_json(const json& j, GenresTitles2& g); | |
}; | |
struct GenreEntry { | |
// std::string image; | |
std::string description; | |
GenreID id; | |
std::string name; | |
friend void from_json(const json& j, GenreEntry& g); | |
}; | |
// if connection is okay, this cannot really fail | |
using Genres = std::vector<GenreEntry>; | |
} // namespace funi |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#pragma once | |
#include "title_image.hpp" | |
#include <cstdint> | |
#include <string> | |
#include <vector> | |
#include <optional> | |
namespace funi { | |
// not finished, but this struct is 100% bloat. | |
// all we need is name, type and experience id. | |
struct History { | |
struct Show { | |
struct TotalEpisodes { | |
std::uint32_t episode; | |
}; | |
struct Synopsis { | |
std::string short_synopsis; | |
std::string medium_synopsis; | |
std::string long_synopsis; | |
}; | |
std::string tx_date; | |
std::vector<std::string> genres; | |
float star_rating; | |
std::optional<std::string> minimum_episode; | |
std::optional<std::string> pri_msg; | |
std::string external_item_id; | |
std::string image; | |
std::string title; | |
TotalEpisodes total_episodes; // sounds like an array but its an obj | |
std::uint32_t episode_count; | |
TitleImage title_images; | |
std::vector<std::string> regions; | |
}; | |
std::string content_type; | |
std::string external_ver_id; | |
Show show; | |
// std::string ; | |
}; | |
} // namespace funi |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#pragma once | |
#include "../nlohmann/json_fwd.hpp" | |
#include "types.hpp" | |
#include <cstdint> | |
#include <string> | |
#include <vector> | |
#include <optional> | |
namespace funi { | |
enum class LanguageCode { | |
EN = 10, | |
JA = 23, | |
}; | |
struct Language { | |
std::string code; | |
LanguageID id; | |
std::string title; | |
friend void from_json(const json& j, Language& g); | |
}; | |
} // namespace funi |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#pragma once | |
#include "../nlohmann/json_fwd.hpp" | |
#include "language.hpp" | |
#include <cstdint> | |
#include <string> | |
#include <string_view> | |
#include <vector> | |
#include <optional> | |
namespace funi { | |
enum class MediaVersion { | |
UNCUT, | |
SIMULCAST, | |
}; | |
// media stream structs are custom | |
struct MediaStreamEntry { | |
MediaStreamEntry(const std::string& _url, const Language& _lang) | |
: url{_url}, language{_lang} {} | |
std::string url; | |
Language language; | |
}; | |
struct MediaExperienceEntry { | |
MediaExperienceEntry(std::uint32_t _id, const Language& _lang) | |
: id{_id}, language{_lang} {} | |
ExperienceID id; | |
Language language; | |
}; | |
struct MediaStreams { | |
MediaStreams(std::uint32_t _id, const Language& _lang) | |
: experience{_id, _lang} {} | |
MediaExperienceEntry experience; | |
std::vector<MediaStreamEntry> subtitles; | |
auto GetExperienceID() const noexcept { return this->experience.id; } | |
}; | |
// not using atm | |
struct MediaInfo { | |
struct Video { | |
std::optional<std::string> codecId; | |
std::optional<std::string> container; | |
std::optional<std::string> frameRate; | |
std::optional<std::uint32_t> height; | |
std::optional<std::uint32_t> width; | |
friend void from_json(const json& j, Video& g); | |
}; | |
std::string format; | |
std::optional<std::uint32_t> frameHeight; | |
std::optional<std::uint32_t> frameWidth; | |
friend void from_json(const json& j, MediaInfo& g); | |
}; | |
// this is kinda like a variant, the fields depend of the mediaType | |
// eg, subs use filepath whilst audio streams use image | |
struct MediaEntryChild { | |
VideoID id; // used for video | |
// always the same as parent! | |
// std::string experienceType; // non-encrypted | |
std::string ext; // m3u8, srt | |
std::string mediaType; // experience, video, image, subtitle, audio | |
std::string status; | |
std::vector<Language> languages; | |
std::string image; // filepath doesn't always exist...so i use this instead | |
std::string seriesTitle; | |
std::string episodeTitle; | |
}; | |
struct MediaEntry { | |
VideoID id; // used for video | |
std::string title; // numbers_lang | |
std::string experienceType; // non-encrypted | |
std::string ext; // m3u8 | |
std::string mediaType; // experience, video, image, subtitle, audio | |
std::string status; | |
std::vector<Language> languages; | |
std::vector<MediaEntryChild> mediaChildren; | |
friend void from_json(const json& j, MediaEntry& g); | |
}; | |
// bad name... | |
struct EpisodeMedia { | |
struct Item { | |
EpisodeID id; | |
std::string title; | |
std::string number; | |
std::string description; | |
std::vector<MediaEntry> media; | |
friend void from_json(const json& j, Item& g); | |
}; | |
// should always be 1? | |
std::vector<Item> items; | |
auto GetEpisodeID() const noexcept { return this->items[0].id; } | |
auto Empty() const noexcept { return this->items.empty(); } | |
auto GetMediaStreams() const noexcept { | |
std::vector<MediaStreams> streams; | |
using namespace std::string_view_literals; | |
for (auto& item : this->items) { | |
for (auto& media : item.media) { | |
if (media.mediaType == "experience"sv && media.experienceType == "Non-Encrypted"sv) { | |
if (media.languages.empty()) { | |
continue; | |
} | |
auto& entry = streams.emplace_back(media.id, media.languages[0]); | |
for (auto& child : media.mediaChildren) { | |
if (child.mediaType == "subtitle"sv) { | |
if (child.languages.empty()) { | |
continue; | |
} | |
entry.subtitles.emplace_back(child.image, child.languages[0]); | |
} | |
} | |
} | |
} | |
} | |
return streams; | |
} | |
friend void from_json(const json& j, EpisodeMedia& g); | |
}; | |
} // namespace funi |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#pragma once | |
#include "../nlohmann/json_fwd.hpp" | |
#include "types.hpp" | |
#include <cstdint> | |
#include <string> | |
#include <vector> | |
#include <optional> | |
namespace funi { | |
struct SearchEntry { | |
std::vector<std::string> languages; | |
float star_rating; | |
std::string title; | |
std::string synopsis; | |
std::string quality; | |
// this is actually a string, for some reason. | |
// i convert this to an int when parsing as the rest of | |
// the api uses ID's as ints, not strings... | |
TitleID id; // needed for getting episodes | |
friend void from_json(const json& j, SearchEntry& g); | |
}; | |
struct SearchResult { | |
struct Items { | |
struct Hit { | |
}; | |
std::vector<SearchEntry> hits; | |
std::uint32_t total; | |
friend void from_json(const json& j, Items& g); | |
}; | |
std::uint32_t count; | |
Items items; // not an array, its an obj | |
std::string limit; // why is this a string??? | |
std::string queryId; // ^^ | |
std::string offset; // ^^ | |
auto Empty() const noexcept { return this->items.hits.empty(); } | |
friend void from_json(const json& j, SearchResult& g); | |
}; | |
} // namespace funi |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#pragma once | |
#include "../nlohmann/json_fwd.hpp" | |
#include "types.hpp" | |
#include <cstdint> | |
#include <string> | |
#include <vector> | |
#include <optional> | |
namespace funi { | |
struct Error { | |
int code; | |
std::string detail; | |
std::string title; | |
friend void from_json(const json& j, Error& g); | |
}; | |
// should be a variant of items or errors | |
struct ShowExperience { | |
struct Item { | |
std::string src; // the url we want | |
std::string kind; | |
bool isPromo; | |
std::string videoType; | |
std::string experienceId; | |
bool showAds; | |
ExperienceID id; // showexperience | |
friend void from_json(const json& j, Item& g); | |
}; | |
std::vector<Item> items; | |
std::uint32_t watchHistorySaveInterval; | |
std::vector<Error> errors; // only on errors | |
friend void from_json(const json& j, ShowExperience& g); | |
}; | |
} // namespace funi |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#pragma once | |
#include <cstdint> | |
#include <string> | |
#include <vector> | |
#include <optional> | |
namespace funi { | |
struct SubscriptionFeature { | |
struct SubProduct { | |
std::uint32_t id; | |
bool value; | |
std::string title; | |
}; | |
std::uint32_t id; | |
std::string title; | |
std::string description; | |
std::string notification; | |
std::string handle; | |
bool active; | |
std::vector<SubProduct> subProducts; | |
std::uint32_t order; | |
std::string createdDatetime; | |
std::string modifiedDatetime; | |
std::vector<std::string> regions; | |
}; | |
struct SubscriptionFeatures { | |
std::uint32_t count; | |
std::vector<SubscriptionFeature> items; | |
std::uint32_t total; | |
std::uint32_t offset; | |
}; | |
} // namespace funi |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#pragma once | |
#include <cstdint> | |
#include <string> | |
#include <vector> | |
#include <optional> | |
namespace funi { | |
struct TitleImage { | |
std::string showThumbnail; | |
std::string showBackgroundSite; | |
std::string showDetailHeaderDesktop; | |
std::string continueWatchingDesktop; | |
std::string showDetailHeroSite; | |
std::string appleHorizontalBannerShow; | |
std::string backgroundImageXbox_360; | |
std::string applePosterCover; | |
std::string showDetailBoxArtTablet; | |
std::string backgroundImageAppletvfiretv; | |
std::string newShowDetailHero; | |
std::string showDetailHeroDesktop; | |
std::string showKeyart; | |
std::string continueWatchingMobile; | |
std::string featuredSpotlightShowPhone; | |
std::string appleHorizontalBannerMovie; | |
std::string featuredSpotlightShowTablet; | |
std::string showDetailBoxArtPhone; | |
std::string appleSquareCover; | |
std::string backgroundVideo; | |
std::string showMasterKeyArt; | |
std::string newShowDetailHeroPhone; | |
std::string showDetailBoxArtXbox_360; | |
std::string showDetailHeaderMobile; | |
std::string showLogo; | |
}; | |
} // namespace funi |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#pragma once | |
#include "../nlohmann/json_fwd.hpp" | |
#include "types.hpp" | |
#include <cstdint> | |
#include <string> | |
#include <vector> | |
#include <optional> | |
namespace funi { | |
struct TitleInfo { | |
struct Item { | |
struct ChildrenCounts { | |
// this is called episode for extras!!! | |
std::uint32_t episodes{}; // total num of episodes | |
std::uint32_t extras{}; // total num of extras | |
friend void from_json(const json& j, ChildrenCounts& g); | |
}; | |
struct Children { | |
std::string title; | |
std::string number; // season number (99 for extras) | |
std::uint32_t childCount; // num ep this season | |
SeasonID id; // season ID? | |
std::string mediaCategory; // season, extras | |
float order; | |
friend void from_json(const json& j, Children& g); | |
}; | |
TitleID id; | |
std::string title; | |
ChildrenCounts childrenCounts; | |
std::vector<Children> children; | |
std::string audio; // English, Japanese, Portuguese (Brazil) | |
std::string type; // tv_series (always) | |
friend void from_json(const json& j, Item& g); | |
}; | |
std::vector<Item> items; | |
auto SeasonCount() const noexcept { | |
std::size_t season_max{}; | |
for (auto&item : this->items) { | |
for (auto&child : item.children) { | |
if (child.mediaCategory != "season") { | |
continue; | |
} | |
auto season_num = std::stoull(child.number); | |
if (season_num < 90 && season_num > season_max) { | |
season_max = season_num; | |
} | |
} | |
} | |
return season_max; | |
} | |
auto Empty() const noexcept { return this->items.empty(); } | |
friend void from_json(const json& j, TitleInfo& g); | |
}; | |
} // namespace funi |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#pragma once | |
#include "../nlohmann/json_fwd.hpp" | |
#include <cstdint> | |
namespace funi { | |
using GenreID = std::uint32_t; | |
using TitleID = std::uint32_t; | |
using VideoID = std::uint32_t; | |
using SeasonID = std::uint32_t; | |
using EpisodeID = std::uint32_t; | |
using ExperienceID = std::uint32_t; | |
using LanguageID = std::uint32_t; | |
} // namespace funi |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment