mirror of
https://github.com/arabine/open-story-teller.git
synced 2025-12-06 08:59:35 +01:00
(WIP) new Download manager, download of commercial DB
This commit is contained in:
parent
3d9b60cb32
commit
fe920f4b15
17 changed files with 577 additions and 118 deletions
25
core/interfaces/i_story_db.h
Normal file
25
core/interfaces/i_story_db.h
Normal file
|
|
@ -0,0 +1,25 @@
|
|||
#pragma once
|
||||
|
||||
#include <string>
|
||||
|
||||
class IStoryDb
|
||||
{
|
||||
|
||||
public:
|
||||
struct Info {
|
||||
int age;
|
||||
std::string title;
|
||||
std::string description;
|
||||
std::string download;
|
||||
std::string image_url;
|
||||
std::string sound;
|
||||
std::string uuid;
|
||||
std::string url;
|
||||
};
|
||||
|
||||
virtual ~IStoryDb() {}
|
||||
|
||||
|
||||
virtual bool FindStory(const std::string &uuid, Info &info) = 0;
|
||||
virtual void AddStory(IStoryDb::Info &info, int origin) = 0;
|
||||
};
|
||||
|
|
@ -43,7 +43,7 @@ std::string SysLib::GetFileName(const std::string &path)
|
|||
}
|
||||
else
|
||||
{
|
||||
return "";
|
||||
return path;
|
||||
}
|
||||
}
|
||||
else
|
||||
|
|
|
|||
|
|
@ -15,7 +15,7 @@
|
|||
#include "story_page.h"
|
||||
#include "story_options.h"
|
||||
|
||||
// FIXME : Structure très Lunii style, à utiliser pour la conversion peut-être ...
|
||||
// FIXME : Structure très proche de la boiboite, à utiliser pour la conversion peut-être ...
|
||||
struct StoryNode
|
||||
{
|
||||
bool auto_jump;
|
||||
|
|
|
|||
|
|
@ -7,7 +7,7 @@ This documentation will guide you to make your own story teller. You can choose
|
|||
Before starting, here is a complete list of links where you'll find project information:
|
||||
|
||||
- :octopus: [Github](https://github.com/arabine/open-story-teller): source code for the firmware, the player and the story editor, issue tracking
|
||||
- Free stories community (in French) [Discord](https://monurl.ca/DiscordLuniiYT)
|
||||
- Free stories community (in French) [Discord](https://monurl.ca/lunii.creations)
|
||||
- My Discord channel for this project: https://discord.gg/4TW4B3R4Ye
|
||||
|
||||
## Helping
|
||||
|
|
|
|||
120
shared/downloader.cpp
Normal file
120
shared/downloader.cpp
Normal file
|
|
@ -0,0 +1,120 @@
|
|||
|
||||
#include "downloader.h"
|
||||
#include "json.hpp"
|
||||
|
||||
static size_t writeCallback(void* contents, size_t size, size_t nmemb, void* userp)
|
||||
{
|
||||
((std::string*)userp)->append((char*)contents, size * nmemb);
|
||||
return size * nmemb;
|
||||
}
|
||||
|
||||
Downloader::Downloader()
|
||||
{
|
||||
curl_global_init(CURL_GLOBAL_DEFAULT);
|
||||
|
||||
// Try to download the store index file
|
||||
m_curl = curl_easy_init();
|
||||
|
||||
m_downloadThread = std::thread( std::bind(&Downloader::DownloadThread, this) );
|
||||
}
|
||||
|
||||
Downloader::~Downloader()
|
||||
{
|
||||
if (m_curl)
|
||||
{
|
||||
m_downloadMutex.lock();
|
||||
m_cancel = true;
|
||||
m_downloadMutex.unlock();
|
||||
}
|
||||
|
||||
// Quit download thread
|
||||
m_downloadQueue.push({"quit", ""});
|
||||
if (m_downloadThread.joinable())
|
||||
{
|
||||
m_downloadThread.join();
|
||||
}
|
||||
|
||||
curl_global_cleanup();
|
||||
}
|
||||
|
||||
void Downloader::DownloadThread()
|
||||
{
|
||||
for (;;)
|
||||
{
|
||||
auto cmd = m_downloadQueue.front();
|
||||
m_downloadQueue.pop();
|
||||
|
||||
if (cmd.order == "quit")
|
||||
{
|
||||
curl_easy_cleanup(m_curl);
|
||||
|
||||
return;
|
||||
}
|
||||
else if (cmd.order == "dl")
|
||||
{
|
||||
// download_file(m_curl, cmd.url, cmd.filename, cmd.finished_callback);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
std::string Downloader::FetchToken()
|
||||
{
|
||||
std::string url = "https://server-auth-prod.lunii.com/guest/create";
|
||||
std::string response = PerformGetRequest(url);
|
||||
|
||||
// Parse the response JSON to extract the token
|
||||
try {
|
||||
auto jsonResponse = nlohmann::json::parse(response);
|
||||
return jsonResponse["response"]["token"]["server"].get<std::string>();
|
||||
} catch (const std::exception& ex) {
|
||||
throw std::runtime_error("Failed to parse token from response: " + std::string(ex.what()));
|
||||
}
|
||||
}
|
||||
|
||||
void Downloader::FetchDataAndSaveToFile(const std::string& token, const std::string& filePath)
|
||||
{
|
||||
std::string url = "https://server-data-prod.lunii.com/v2/packs";
|
||||
|
||||
struct curl_slist* headers = nullptr;
|
||||
headers = curl_slist_append(headers, ("X-AUTH-TOKEN: " + token).c_str());
|
||||
|
||||
std::string response = PerformGetRequest(url, headers);
|
||||
|
||||
// Enregistrer dans un fichier
|
||||
std::ofstream file(filePath);
|
||||
if (!file.is_open()) {
|
||||
throw std::runtime_error("Failed to open file for writing");
|
||||
}
|
||||
file << response;
|
||||
file.close();
|
||||
std::cout << "Data saved to " << filePath << std::endl;
|
||||
}
|
||||
|
||||
std::string Downloader::PerformGetRequest(const std::string& url, struct curl_slist* headers)
|
||||
{
|
||||
|
||||
std::string response;
|
||||
curl_easy_setopt(m_curl, CURLOPT_URL, url.c_str());
|
||||
curl_easy_setopt(m_curl, CURLOPT_WRITEFUNCTION, writeCallback);
|
||||
curl_easy_setopt(m_curl, CURLOPT_WRITEDATA, &response);
|
||||
|
||||
if (headers)
|
||||
{
|
||||
curl_easy_setopt(m_curl, CURLOPT_HTTPHEADER, headers);
|
||||
}
|
||||
|
||||
CURLcode res = curl_easy_perform(m_curl);
|
||||
if (res != CURLE_OK)
|
||||
{
|
||||
// FIXME: handle error
|
||||
}
|
||||
|
||||
if (headers)
|
||||
{
|
||||
curl_slist_free_all(headers);
|
||||
}
|
||||
|
||||
return response;
|
||||
}
|
||||
|
||||
|
||||
43
shared/downloader.h
Normal file
43
shared/downloader.h
Normal file
|
|
@ -0,0 +1,43 @@
|
|||
#pragma once
|
||||
|
||||
#include <iostream>
|
||||
#include <fstream>
|
||||
#include <sstream>
|
||||
#include <string>
|
||||
#include <stdexcept>
|
||||
#include <thread>
|
||||
#include <functional>
|
||||
|
||||
#include <curl/curl.h>
|
||||
|
||||
#include "thread_safe_queue.h"
|
||||
|
||||
|
||||
class Downloader
|
||||
{
|
||||
public:
|
||||
|
||||
struct Command {
|
||||
std::string order;
|
||||
std::string url;
|
||||
std::string filename;
|
||||
std::function<void(bool, const std::string &filename)> finished_callback;
|
||||
};
|
||||
|
||||
Downloader();
|
||||
~Downloader();
|
||||
|
||||
std::string FetchToken();
|
||||
|
||||
void FetchDataAndSaveToFile(const std::string& token, const std::string& filePath);
|
||||
|
||||
private:
|
||||
CURL *m_curl;
|
||||
std::thread m_downloadThread;
|
||||
ThreadSafeQueue<Downloader::Command> m_downloadQueue;
|
||||
std::mutex m_downloadMutex;
|
||||
bool m_cancel{false};
|
||||
|
||||
std::string PerformGetRequest(const std::string& url, struct curl_slist* headers = nullptr);
|
||||
void DownloadThread();
|
||||
};
|
||||
|
|
@ -193,3 +193,81 @@ std::string LibraryManager::GetVersion()
|
|||
{
|
||||
return std::to_string(VERSION_MAJOR) + '.' + std::to_string(VERSION_MINOR) + '.' + std::to_string(VERSION_PATCH);
|
||||
}
|
||||
|
||||
void LibraryManager::AddStory(IStoryDb::Info &info, int origin)
|
||||
{
|
||||
m_storyDb.AddStory(info, origin);
|
||||
}
|
||||
|
||||
void LibraryManager::ParseCommunityStore(const std::string &jsonFileName)
|
||||
{
|
||||
try {
|
||||
std::ifstream f(jsonFileName);
|
||||
nlohmann::json j = nlohmann::json::parse(f);
|
||||
|
||||
if (!j.contains("data")) {
|
||||
throw std::runtime_error("Invalid JSON: 'data' key not found");
|
||||
}
|
||||
|
||||
const auto& data = j["data"];
|
||||
|
||||
m_storyDb.ClearCommunity();
|
||||
for (const auto &obj : data)
|
||||
{
|
||||
IStoryDb::Info s;
|
||||
|
||||
s.title = obj["title"].get<std::string>();
|
||||
s.description = obj["description"].get<std::string>();
|
||||
s.download = obj["download"].get<std::string>();
|
||||
s.age = obj["age"].get<int>();
|
||||
|
||||
m_storyDb.AddStory(s, StoryDb::cCommunityStore);
|
||||
}
|
||||
}
|
||||
catch(std::exception &e)
|
||||
{
|
||||
std::cout << e.what() << std::endl;
|
||||
}
|
||||
}
|
||||
|
||||
void LibraryManager::ParseCommercialStore(const std::string &jsonFileName)
|
||||
{
|
||||
try
|
||||
{
|
||||
|
||||
std::ifstream f(jsonFileName);
|
||||
nlohmann::json j = nlohmann::json::parse(f);
|
||||
|
||||
if (!j.contains("response")) {
|
||||
throw std::runtime_error("Invalid JSON: 'response' key not found");
|
||||
}
|
||||
|
||||
const auto& response = j["response"];
|
||||
m_storyDb.ClearCommercial();
|
||||
|
||||
for (auto it = response.begin(); it != response.end(); ++it)
|
||||
{
|
||||
const auto& pack = it.value();
|
||||
|
||||
IStoryDb::Info story;
|
||||
story.title = pack["title"].get<std::string>();
|
||||
story.uuid = pack["uuid"].get<std::string>();
|
||||
|
||||
if (pack.contains("localized_infos") && pack["localized_infos"].contains("fr_FR"))
|
||||
{
|
||||
const auto& localized = pack["localized_infos"]["fr_FR"];
|
||||
story.title = localized["title"].get<std::string>();
|
||||
story.description = localized["description"].get<std::string>();
|
||||
|
||||
if (localized.contains("image") && localized["image"].contains("image_url")) {
|
||||
story.image_url = localized["image"]["image_url"].get<std::string>();
|
||||
}
|
||||
}
|
||||
|
||||
m_storyDb.AddStory(story, StoryDb::cCommercialStore);
|
||||
}
|
||||
} catch (const std::exception& ex) {
|
||||
std::cerr << "Error: " << ex.what() << std::endl;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -8,6 +8,8 @@
|
|||
|
||||
#include "story_project.h"
|
||||
#include "i_logger.h"
|
||||
#include "story_db.h"
|
||||
|
||||
class LibraryManager
|
||||
{
|
||||
public:
|
||||
|
|
@ -42,12 +44,26 @@ public:
|
|||
void SetStoreUrl(const std::string &store_url) { m_storeUrl = store_url; }
|
||||
std::string GetStoreUrl() const { return m_storeUrl; }
|
||||
|
||||
void AddStory(IStoryDb::Info &info, int origin);
|
||||
|
||||
void ParseCommunityStore(const std::string &jsonFileName);
|
||||
void ParseCommercialStore(const std::string &jsonFileName);
|
||||
|
||||
auto CommunityDbView() const {
|
||||
return m_storyDb.CommunityDbView();
|
||||
}
|
||||
|
||||
auto CommercialDbView() const {
|
||||
return m_storyDb.CommercialDbView();
|
||||
}
|
||||
|
||||
private:
|
||||
ILogger &m_log;
|
||||
std::string m_library_path;
|
||||
std::list<std::shared_ptr<StoryProject>> m_projectsList;
|
||||
std::string m_storeUrl;
|
||||
std::thread m_copyWorker;
|
||||
StoryDb m_storyDb;
|
||||
};
|
||||
|
||||
#endif // LIBRARYMANAGER_H
|
||||
|
|
|
|||
46
shared/story_db.cpp
Normal file
46
shared/story_db.cpp
Normal file
|
|
@ -0,0 +1,46 @@
|
|||
#include "story_db.h"
|
||||
|
||||
StoryDb::StoryDb()
|
||||
{
|
||||
}
|
||||
|
||||
StoryDb::~StoryDb()
|
||||
{
|
||||
}
|
||||
|
||||
bool StoryDb::FindStory(const std::string &uuid, Info &info)
|
||||
{
|
||||
for (const auto &s : m_store)
|
||||
{
|
||||
if (s.uuid == uuid)
|
||||
{
|
||||
info = s;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
for (const auto &s : m_commercialStore)
|
||||
{
|
||||
if (s.uuid == uuid)
|
||||
{
|
||||
info = s;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
void StoryDb::AddStory(IStoryDb::Info &info, int origin)
|
||||
{
|
||||
if (origin == cCommercialStore)
|
||||
{
|
||||
m_commercialStore.push_back(info);
|
||||
}
|
||||
|
||||
if (origin == cCommunityStore)
|
||||
{
|
||||
m_store.push_back(info);
|
||||
}
|
||||
|
||||
}
|
||||
45
shared/story_db.h
Normal file
45
shared/story_db.h
Normal file
|
|
@ -0,0 +1,45 @@
|
|||
#pragma once
|
||||
|
||||
#include <string>
|
||||
#include <vector>
|
||||
#include <ranges>
|
||||
|
||||
#include "i_story_db.h"
|
||||
|
||||
class StoryDb : public IStoryDb
|
||||
{
|
||||
public:
|
||||
static const int cCommercialStore = 0;
|
||||
static const int cCommunityStore = 1;
|
||||
|
||||
StoryDb();
|
||||
~StoryDb();
|
||||
|
||||
bool FindStory(const std::string &uuid, Info &info) override;
|
||||
void AddStory(IStoryDb::Info &info, int origin) override;
|
||||
|
||||
void Clear() {
|
||||
m_store.clear();
|
||||
m_commercialStore.clear();
|
||||
}
|
||||
|
||||
void ClearCommercial() {
|
||||
m_commercialStore.clear();
|
||||
}
|
||||
|
||||
void ClearCommunity() {
|
||||
m_store.clear();
|
||||
}
|
||||
|
||||
auto CommercialDbView() const {
|
||||
return std::ranges::views::all(m_commercialStore);
|
||||
}
|
||||
|
||||
auto CommunityDbView() const {
|
||||
return std::ranges::views::all(m_store);
|
||||
}
|
||||
|
||||
private:
|
||||
std::vector<IStoryDb::Info> m_store;
|
||||
std::vector<IStoryDb::Info> m_commercialStore;
|
||||
};
|
||||
|
|
@ -182,51 +182,26 @@ set(SRCS
|
|||
|
||||
src/main.cpp
|
||||
|
||||
src/window_base.h
|
||||
src/window_base.cpp
|
||||
|
||||
src/console_window.cpp
|
||||
src/console_window.h
|
||||
|
||||
src/emulator_window.cpp
|
||||
src/emulator_window.h
|
||||
|
||||
src/main_window.cpp
|
||||
src/main_window.h
|
||||
|
||||
src/library_window.cpp
|
||||
src/library_window.h
|
||||
|
||||
|
||||
src/platform_folders.cpp
|
||||
src/platform_folders.h
|
||||
|
||||
src/node_editor/media_node_widget.h
|
||||
|
||||
src/node_editor/media_node_widget.cpp
|
||||
src/node_editor/base_node_widget.h
|
||||
src/node_editor/base_node_widget.cpp
|
||||
src/node_editor/node_editor_window.h
|
||||
src/node_editor/node_editor_window.cpp
|
||||
src/node_editor/function_node_widget.h
|
||||
src/node_editor/function_node_widget.cpp
|
||||
|
||||
src/resources_window.cpp
|
||||
src/resources_window.h
|
||||
|
||||
src/properties_window.cpp
|
||||
src/properties_window.h
|
||||
|
||||
src/cpu_window.cpp
|
||||
src/cpu_window.h
|
||||
|
||||
src/gui.h
|
||||
src/gui.cpp
|
||||
|
||||
src/code_editor.cpp
|
||||
src/code_editor.h
|
||||
|
||||
src/media_converter.cpp
|
||||
src/media_converter.h
|
||||
|
||||
src/miniz.c
|
||||
src/zip.cpp
|
||||
|
|
@ -234,7 +209,6 @@ set(SRCS
|
|||
src/importers/pack_archive.cpp
|
||||
src/importers/ni_parser.c
|
||||
|
||||
|
||||
libs/imgui-node-editor/imgui_node_editor.cpp
|
||||
libs/imgui-node-editor/imgui_canvas.cpp
|
||||
libs/imgui-node-editor/imgui_node_editor_api.cpp
|
||||
|
|
@ -253,17 +227,11 @@ set(SRCS
|
|||
../firmware/chip32/chip32_vm.c
|
||||
|
||||
../shared/audio_player.cpp
|
||||
../shared/audio_player.h
|
||||
../shared/tlv.h
|
||||
../shared/miniaudio.h
|
||||
../shared/stb_vorbis.c
|
||||
../shared/uuid.h
|
||||
../shared/resource_manager.h
|
||||
../shared/resource_manager.cpp
|
||||
|
||||
../shared/thread_safe_queue.h
|
||||
../shared/library_manager.h
|
||||
../shared/library_manager.cpp
|
||||
../shared/downloader.cpp
|
||||
../shared/story_db.cpp
|
||||
|
||||
# Core engine files
|
||||
|
||||
|
|
|
|||
|
|
@ -9,20 +9,20 @@ Size=32,42
|
|||
Collapsed=0
|
||||
|
||||
[Window][Library Manager]
|
||||
Pos=466,26
|
||||
Size=814,262
|
||||
Pos=593,26
|
||||
Size=687,395
|
||||
Collapsed=0
|
||||
DockId=0x00000003,3
|
||||
|
||||
[Window][Console]
|
||||
Pos=60,623
|
||||
Size=1220,97
|
||||
Pos=60,423
|
||||
Size=1220,297
|
||||
Collapsed=0
|
||||
DockId=0x00000006,0
|
||||
|
||||
[Window][Emulator]
|
||||
Pos=466,26
|
||||
Size=814,262
|
||||
Pos=593,26
|
||||
Size=687,395
|
||||
Collapsed=0
|
||||
DockId=0x00000003,2
|
||||
|
||||
|
|
@ -33,20 +33,20 @@ Collapsed=0
|
|||
DockId=0x00000004,0
|
||||
|
||||
[Window][Resources]
|
||||
Pos=466,26
|
||||
Size=814,262
|
||||
Pos=593,26
|
||||
Size=687,395
|
||||
Collapsed=0
|
||||
DockId=0x00000003,0
|
||||
|
||||
[Window][Properties]
|
||||
Pos=466,26
|
||||
Size=814,262
|
||||
Pos=593,26
|
||||
Size=687,395
|
||||
Collapsed=0
|
||||
DockId=0x00000003,1
|
||||
|
||||
[Window][Node editor]
|
||||
Pos=60,26
|
||||
Size=404,595
|
||||
Size=531,395
|
||||
Collapsed=0
|
||||
DockId=0x00000002,0
|
||||
|
||||
|
|
@ -61,12 +61,12 @@ Size=60,694
|
|||
Collapsed=0
|
||||
|
||||
[Window][ProjectPropertiesPopup]
|
||||
Pos=381,236
|
||||
Pos=381,290
|
||||
Size=518,248
|
||||
Collapsed=0
|
||||
|
||||
[Window][AboutPopup]
|
||||
Pos=540,272
|
||||
Pos=436,235
|
||||
Size=408,249
|
||||
Collapsed=0
|
||||
|
||||
|
|
@ -86,8 +86,8 @@ Size=951,564
|
|||
Collapsed=0
|
||||
|
||||
[Window][CPU]
|
||||
Pos=466,26
|
||||
Size=814,262
|
||||
Pos=593,26
|
||||
Size=687,395
|
||||
Collapsed=0
|
||||
DockId=0x00000003,4
|
||||
|
||||
|
|
@ -106,6 +106,17 @@ Pos=60,26
|
|||
Size=1220,694
|
||||
Collapsed=0
|
||||
|
||||
[Window][Code viewer]
|
||||
Pos=593,26
|
||||
Size=687,395
|
||||
Collapsed=0
|
||||
DockId=0x00000003,5
|
||||
|
||||
[Window][Import story##ImportStoryDlgKey]
|
||||
Pos=246,21
|
||||
Size=916,532
|
||||
Collapsed=0
|
||||
|
||||
[Table][0x54B1A511,5]
|
||||
RefScale=20
|
||||
Column 0 Width=197 Sort=0v
|
||||
|
|
@ -187,12 +198,31 @@ RefScale=20
|
|||
Column 0 Width=22 Sort=0v
|
||||
Column 1 Width=96
|
||||
|
||||
[Table][0x37CE7681,4]
|
||||
RefScale=20
|
||||
Column 0 Width=468 Sort=0v
|
||||
Column 1 Width=273
|
||||
Column 2 Width=47
|
||||
Column 3 Width=93
|
||||
|
||||
[Table][0xACC2C3FC,4]
|
||||
RefScale=20
|
||||
Column 0 Sort=0v
|
||||
|
||||
[Table][0xE79886F3,4]
|
||||
RefScale=20
|
||||
Column 0 Sort=0v
|
||||
|
||||
[Table][0xD33987D9,4]
|
||||
RefScale=20
|
||||
Column 0 Sort=0v
|
||||
|
||||
[Docking][Data]
|
||||
DockSpace ID=0x08BD597D Window=0x1BBC0F80 Pos=60,26 Size=1220,694 Split=Y
|
||||
DockNode ID=0x00000005 Parent=0x08BD597D SizeRef=1220,595 Split=X
|
||||
DockNode ID=0x00000002 Parent=0x00000005 SizeRef=574,694 CentralNode=1 Selected=0xBB79A587
|
||||
DockNode ID=0x00000001 Parent=0x00000005 SizeRef=814,694 Split=Y Selected=0x63869CAF
|
||||
DockNode ID=0x00000003 Parent=0x00000001 SizeRef=543,294 Selected=0x4B07C626
|
||||
DockNode ID=0x00000005 Parent=0x08BD597D SizeRef=1220,504 Split=X
|
||||
DockNode ID=0x00000002 Parent=0x00000005 SizeRef=531,694 CentralNode=1 Selected=0xBB79A587
|
||||
DockNode ID=0x00000001 Parent=0x00000005 SizeRef=687,694 Split=Y Selected=0x63869CAF
|
||||
DockNode ID=0x00000003 Parent=0x00000001 SizeRef=543,294 Selected=0x63869CAF
|
||||
DockNode ID=0x00000004 Parent=0x00000001 SizeRef=543,372 Selected=0x7563A968
|
||||
DockNode ID=0x00000006 Parent=0x08BD597D SizeRef=1220,97 Selected=0xEA83D666
|
||||
DockNode ID=0x00000006 Parent=0x08BD597D SizeRef=1220,297 Selected=0xEA83D666
|
||||
|
||||
|
|
|
|||
|
|
@ -202,10 +202,19 @@ $MyArray DV8 10 ; array of 10 bytes
|
|||
*/
|
||||
|
||||
|
||||
// NI file is not ciphered
|
||||
// RI file is not ciphered
|
||||
uint8_t data[512];
|
||||
uint32_t size = ni_get_ri_block(data);
|
||||
WriteDataOnDisk(mPackName + "/ri", data, size);
|
||||
// WriteDataOnDisk(mPackName + "/ri", data, size);
|
||||
|
||||
StoryProject proj(m_log);
|
||||
ResourceManager res(m_log);
|
||||
|
||||
std::shared_ptr<StoryPage> page = proj.CreatePage("main");
|
||||
|
||||
|
||||
proj.New(uuid, outputDir);
|
||||
proj.SetName(j["title"].get<std::string>());
|
||||
|
||||
nlohmann::json jsonImages;
|
||||
{
|
||||
|
|
@ -224,7 +233,7 @@ $MyArray DV8 10 ; array of 10 bytes
|
|||
j["images"] = jsonImages;
|
||||
|
||||
size = ni_get_si_block(data);
|
||||
WriteDataOnDisk(mPackName + "/si", data, size);
|
||||
// WriteDataOnDisk(mPackName + "/si", data, size);
|
||||
|
||||
|
||||
nlohmann::json jsonSounds;
|
||||
|
|
@ -244,7 +253,7 @@ $MyArray DV8 10 ; array of 10 bytes
|
|||
j["sounds"] = jsonSounds;
|
||||
|
||||
size = ni_get_li_block(data);
|
||||
WriteDataOnDisk(mPackName + "/li", data, size);
|
||||
// WriteDataOnDisk(mPackName + "/li", data, size);
|
||||
|
||||
|
||||
std::vector<uint32_t> transitions;
|
||||
|
|
@ -333,11 +342,7 @@ $MyArray DV8 10 ; array of 10 bytes
|
|||
j["name"] = "";
|
||||
j["type"] = "lunii";
|
||||
|
||||
std::ofstream o("pack.json");
|
||||
o << std::setw(4) << j << std::endl; // pretty print
|
||||
|
||||
o.close();
|
||||
chip32.close();
|
||||
}
|
||||
|
||||
bool PackArchive::LoadNiFile(const std::string &filePath)
|
||||
|
|
|
|||
|
|
@ -59,7 +59,10 @@ LibraryWindow::LibraryWindow(IStoryManager &project, LibraryManager &library)
|
|||
|
||||
m_storeUrl[0] = 0;
|
||||
|
||||
// std::strcpy(m_storeUrl, "https://gist.githubusercontent.com/DantSu/8920929530b58f2acbfcf1ed0e7746f9/raw/stories-contrib.json");
|
||||
// std::strcpy(m_storeUrl, "https://gist.githubusercontent.com/DantSu/3aea4c1fe15070bcf394a40b89aec33e/raw/stories.json");
|
||||
|
||||
// https://gist.githubusercontent.com/DantSu/3aea4c1fe15070bcf394a40b89aec33e/raw/stories.json
|
||||
|
||||
}
|
||||
|
||||
LibraryWindow::~LibraryWindow()
|
||||
|
|
@ -105,29 +108,49 @@ void LibraryWindow::Initialize()
|
|||
curl_easy_setopt(m_curl, CURLOPT_XFERINFOFUNCTION, static_cast<xfer_callback_t>(Callback<int(void *, curl_off_t, curl_off_t, curl_off_t, curl_off_t)>::callback));
|
||||
}
|
||||
|
||||
|
||||
std::strcpy(&m_storeUrl[0], m_libraryManager.GetStoreUrl().c_str());
|
||||
m_storeIndexFilename = ToLocalStoreFile(m_storeUrl);
|
||||
|
||||
if (std::filesystem::is_regular_file(m_storeIndexFilename))
|
||||
auto communityStoreUrl = m_libraryManager.GetStoreUrl();
|
||||
if (!communityStoreUrl.empty())
|
||||
{
|
||||
// seems legit
|
||||
ParseStoreDataCallback(true, m_storeIndexFilename);
|
||||
std::strcpy(&m_storeUrl[0], m_libraryManager.GetStoreUrl().c_str());
|
||||
m_communityStoreFile = ToLocalStoreFile(m_storeUrl);
|
||||
|
||||
if (std::filesystem::is_regular_file(m_communityStoreFile))
|
||||
{
|
||||
std::cout << "Community store file already exists, skipping download" << std::endl;
|
||||
ParseCommunityStoreDataCallback(true, m_communityStoreFile);
|
||||
}
|
||||
else
|
||||
{
|
||||
// Not exists, download it
|
||||
m_downloadQueue.push({
|
||||
"dl",
|
||||
m_storeUrl,
|
||||
m_communityStoreFile,
|
||||
std::bind(&LibraryWindow::ParseCommunityStoreDataCallback, this, std::placeholders::_1, std::placeholders::_2)
|
||||
});
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
m_commercialStoreFile = ToLocalStoreFile("commercial_store_db.json");
|
||||
if (std::filesystem::is_regular_file(m_commercialStoreFile))
|
||||
{
|
||||
std::cout << "Commercial store file already exists, skipping download" << std::endl;
|
||||
ParseCommercialStoreDataCallback(true, m_commercialStoreFile);
|
||||
}
|
||||
else
|
||||
{
|
||||
// Not exists, download it
|
||||
m_downloadQueue.push({
|
||||
"dl",
|
||||
"dl_commercial",
|
||||
m_storeUrl,
|
||||
m_storeIndexFilename,
|
||||
std::bind(&LibraryWindow::ParseStoreDataCallback, this, std::placeholders::_1, std::placeholders::_2)
|
||||
m_communityStoreFile,
|
||||
std::bind(&LibraryWindow::ParseCommercialStoreDataCallback, this, std::placeholders::_1, std::placeholders::_2)
|
||||
});
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
void LibraryWindow::DownloadThread()
|
||||
{
|
||||
for (;;)
|
||||
|
|
@ -145,6 +168,22 @@ void LibraryWindow::DownloadThread()
|
|||
{
|
||||
download_file(m_curl, cmd.url, cmd.filename, cmd.finished_callback);
|
||||
}
|
||||
else if (cmd.order == "dl_commercial")
|
||||
{
|
||||
try
|
||||
{
|
||||
std::cout << "Fetching token..." << std::endl;
|
||||
std::string token = m_downloader.FetchToken();
|
||||
std::cout << "Token: " << token << std::endl;
|
||||
|
||||
std::cout << "Fetching data and saving to file..." << std::endl;
|
||||
m_downloader.FetchDataAndSaveToFile(token, m_commercialStoreFile);
|
||||
|
||||
ParseCommercialStoreDataCallback(true, m_commercialStoreFile);
|
||||
} catch (const std::exception& ex) {
|
||||
std::cerr << "Error: " << ex.what() << std::endl;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -313,28 +352,27 @@ void LibraryWindow::StoryFileDownloadedCallback(bool success, const std::string
|
|||
|
||||
}
|
||||
|
||||
void LibraryWindow::ParseStoreDataCallback(bool success, const std::string &filename)
|
||||
void LibraryWindow::ParseCommercialStoreDataCallback(bool success, const std::string &filename)
|
||||
{
|
||||
try {
|
||||
std::ifstream f(m_storeIndexFilename);
|
||||
nlohmann::json j = nlohmann::json::parse(f);
|
||||
|
||||
m_store.clear();
|
||||
for (const auto &obj : j)
|
||||
{
|
||||
StoryInf s;
|
||||
|
||||
s.title = obj["title"].get<std::string>();
|
||||
s.description = obj["description"].get<std::string>();
|
||||
s.download = obj["download"].get<std::string>();
|
||||
s.age = obj["age"].get<int>();
|
||||
|
||||
m_store.push_back(s);
|
||||
}
|
||||
}
|
||||
catch(std::exception &e)
|
||||
if (success)
|
||||
{
|
||||
std::cout << e.what() << std::endl;
|
||||
m_libraryManager.ParseCommercialStore(m_commercialStoreFile);
|
||||
}
|
||||
else
|
||||
{
|
||||
std::cout << "Error while downloading commercial store index file" << std::endl;
|
||||
}
|
||||
}
|
||||
|
||||
void LibraryWindow::ParseCommunityStoreDataCallback(bool success, const std::string &filename)
|
||||
{
|
||||
if (success)
|
||||
{
|
||||
m_libraryManager.ParseCommunityStore(m_communityStoreFile);
|
||||
}
|
||||
else
|
||||
{
|
||||
std::cout << "Error while downloading community store index file" << std::endl;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -362,7 +400,7 @@ std::string LibraryWindow::ToLocalStoreFile(const std::string &url)
|
|||
auto filename = SysLib::GetFileName(url);
|
||||
|
||||
filename = m_libraryManager.LibraryPath() + "/store/" + filename;
|
||||
std::cout << "Store file: " << filename << std::endl;
|
||||
std::cout << "Url: " << url << " will be downloaded in store file: " << filename << std::endl;
|
||||
return filename;
|
||||
}
|
||||
|
||||
|
|
@ -513,16 +551,22 @@ void LibraryWindow::Draw()
|
|||
// ============================================================================
|
||||
if (ImGui::BeginTabItem("Remote Store##StoreTabBar", nullptr, ImGuiTabItemFlags_None))
|
||||
{
|
||||
ImGui::InputTextWithHint("##store_url", "Store URL", m_storeUrl, IM_ARRAYSIZE(m_storeUrl));
|
||||
bool changed = ImGui::InputTextWithHint("##store_url", "Store URL", m_storeUrl, IM_ARRAYSIZE(m_storeUrl));
|
||||
|
||||
if (changed)
|
||||
{
|
||||
m_libraryManager.SetStoreUrl(m_storeUrl);
|
||||
}
|
||||
|
||||
ImGui::SameLine();
|
||||
if (ImGui::Button("Load"))
|
||||
{
|
||||
m_storeIndexFilename = ToLocalStoreFile(m_storeUrl);
|
||||
m_communityStoreFile = ToLocalStoreFile(m_storeUrl);
|
||||
m_downloadQueue.push({
|
||||
"dl",
|
||||
m_storeUrl,
|
||||
m_storeIndexFilename,
|
||||
std::bind(&LibraryWindow::ParseStoreDataCallback, this, std::placeholders::_1, std::placeholders::_2)
|
||||
m_communityStoreFile,
|
||||
std::bind(&LibraryWindow::ParseCommunityStoreDataCallback, this, std::placeholders::_1, std::placeholders::_2)
|
||||
});
|
||||
}
|
||||
|
||||
|
|
@ -557,7 +601,7 @@ void LibraryWindow::Draw()
|
|||
ImGui::TableHeadersRow();
|
||||
|
||||
int id = 1;
|
||||
for (const auto &obj : m_store)
|
||||
for (const auto &obj : m_libraryManager.CommunityDbView())
|
||||
{
|
||||
ImGui::TableNextColumn();
|
||||
ImGui::Text("%s", obj.title.c_str());
|
||||
|
|
|
|||
|
|
@ -5,16 +5,10 @@
|
|||
#include "library_manager.h"
|
||||
#include "i_story_manager.h"
|
||||
#include "thread_safe_queue.h"
|
||||
#include "downloader.h"
|
||||
|
||||
#include <curl/curl.h>
|
||||
|
||||
struct StoryInf {
|
||||
int age;
|
||||
std::string title;
|
||||
std::string description;
|
||||
std::string download;
|
||||
};
|
||||
|
||||
struct DownloadCommand {
|
||||
std::string order;
|
||||
std::string url;
|
||||
|
|
@ -80,6 +74,7 @@ private:
|
|||
IStoryManager &m_storyManager;
|
||||
LibraryManager &m_libraryManager;
|
||||
|
||||
Downloader m_downloader;
|
||||
CURL *m_curl;
|
||||
char m_storeUrl[1024];
|
||||
std::thread m_downloadThread;
|
||||
|
|
@ -90,18 +85,18 @@ private:
|
|||
|
||||
std::mutex m_downloadBusyMutex;
|
||||
bool m_downloadBusy{false};
|
||||
|
||||
std::vector<StoryInf> m_store;
|
||||
std::string m_storeIndexFilename;
|
||||
|
||||
std::string m_communityStoreFile;
|
||||
std::string m_commercialStoreFile;
|
||||
|
||||
std::string m_storeRawJson;
|
||||
void ParseStoreDataCallback(bool success, const std::string &filename);
|
||||
void ParseCommercialStoreDataCallback(bool success, const std::string &filename);
|
||||
void ParseCommunityStoreDataCallback(bool success, const std::string &filename);
|
||||
void StoryFileDownloadedCallback(bool success, const std::string &filename);
|
||||
void DownloadThread();
|
||||
int TransferCallback(void *clientp, curl_off_t dltotal, curl_off_t dlnow, curl_off_t ultotal, curl_off_t ulnow);
|
||||
|
||||
std::string ToLocalStoreFile(const std::string &url);
|
||||
|
||||
bool CheckIfSharepoint(const std::string &url, std::string &decoded_url);
|
||||
void SharePointJsonDownloadedCallback(bool success, const std::string &filename);
|
||||
};
|
||||
|
|
|
|||
|
|
@ -1178,7 +1178,7 @@ void MainWindow::LoadParams()
|
|||
m_libraryManager.Initialize(library_path);
|
||||
}
|
||||
|
||||
nlohmann::json store_url = j.value("store_url", "https://gist.githubusercontent.com/DantSu/8920929530b58f2acbfcf1ed0e7746f9/raw/stories-contrib.json");
|
||||
nlohmann::json store_url = j.value("store_url", "https://gist.githubusercontent.com/DantSu/3aea4c1fe15070bcf394a40b89aec33e/raw/stories.json");
|
||||
m_libraryManager.SetStoreUrl(store_url);
|
||||
|
||||
}
|
||||
|
|
|
|||
44
story-editor/tools/get_official_db.ts
Normal file
44
story-editor/tools/get_official_db.ts
Normal file
|
|
@ -0,0 +1,44 @@
|
|||
// A lancer avec Bun !
|
||||
|
||||
async function getCommercialStoreDb() {
|
||||
console.log("Fetching db from commercial store");
|
||||
|
||||
try {
|
||||
// Première requête pour obtenir le token
|
||||
const authResponse = await fetch('https://server-auth-prod.lunii.com/guest/create');
|
||||
if (!authResponse.ok) {
|
||||
throw new Error(`Failed to fetch auth token: ${authResponse.statusText}`);
|
||||
}
|
||||
|
||||
const authData = await authResponse.json();
|
||||
const token = authData?.response?.token?.server;
|
||||
if (!token) {
|
||||
throw new Error('Token not found in response');
|
||||
}
|
||||
|
||||
// Deuxième requête pour récupérer les données
|
||||
const dataResponse = await fetch('https://server-data-prod.lunii.com/v2/packs', {
|
||||
headers: {
|
||||
'X-AUTH-TOKEN': token,
|
||||
},
|
||||
});
|
||||
|
||||
if (!dataResponse.ok) {
|
||||
throw new Error(`Failed to fetch packs: ${dataResponse.statusText}`);
|
||||
}
|
||||
|
||||
const jsonData = await dataResponse.json(); // Récupérer les données en JSON
|
||||
|
||||
// Enregistrer les données dans un fichier local
|
||||
const filePath = "./commercial_store_db.json";
|
||||
await Bun.write(filePath, JSON.stringify(jsonData, null, 2));
|
||||
console.log(`Data saved to ${filePath}`);
|
||||
|
||||
return jsonData;
|
||||
} catch (error) {
|
||||
console.error(error);
|
||||
throw error;
|
||||
}
|
||||
}
|
||||
|
||||
await getCommercialStoreDb();
|
||||
Loading…
Reference in a new issue