uggly working i guess
This commit is contained in:
53
back/html/index.html
Normal file
53
back/html/index.html
Normal file
@@ -0,0 +1,53 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<title>TLT Guesser</title>
|
||||
<script
|
||||
src="https://cdn.jsdelivr.net/combine/npm/tone@14.7.58,npm/@magenta/music@1.23.1/es6/core.js,npm/focus-visible@5,npm/html-midi-player@1.5.0"></script>
|
||||
</head>
|
||||
|
||||
<body>
|
||||
<!-- <midi-player src="indie.mid" sound-font
|
||||
visualizer="#myVisualizer">
|
||||
</midi-player>
|
||||
<midi-visualizer type="piano-roll" id="myVisualizer"></midi-visualizer> -->
|
||||
|
||||
<h1>Défi :</h1>
|
||||
|
||||
<div id="content">
|
||||
<div id="audios"></div>
|
||||
</div>
|
||||
<button id="submit" disabled="true" onclick="checkAnswer()">Vérifier la réponse</button>
|
||||
|
||||
|
||||
<!-- <button onclick="document.getElementById('answer').hidden = false">Révéler la réponse</button> -->
|
||||
|
||||
<p id="message" hidden="true">T'es pas censé voir ça ...</p>
|
||||
|
||||
<form method="get" action="/">
|
||||
<input type="submit" value="Nouveau défi" />
|
||||
</form>
|
||||
|
||||
<script src="monscript.js"></script>
|
||||
|
||||
</body>
|
||||
|
||||
</html>
|
||||
|
||||
|
||||
<!--
|
||||
|
||||
|
||||
Prendre un fichier midi :
|
||||
|
||||
- Sélectionner un passage
|
||||
- Sélectionner les instruments
|
||||
- Générer les fichiers midi
|
||||
|
||||
|
||||
|
||||
|
||||
-->
|
||||
50
back/html/monscript.js
Normal file
50
back/html/monscript.js
Normal file
@@ -0,0 +1,50 @@
|
||||
const content = document.getElementById("content");
|
||||
const audios = document.getElementById("audios");
|
||||
const answerButton = document.getElementById("submit");
|
||||
|
||||
const select = document.createElement("select");
|
||||
|
||||
const messageText = document.getElementById("message");
|
||||
|
||||
let realAnswer = "";
|
||||
|
||||
function checkAnswer() {
|
||||
messageText.hidden = false;
|
||||
if (select.value === realAnswer) {
|
||||
messageText.innerText = "Bravo !";
|
||||
} else {
|
||||
messageText.innerText = "Dommage, la réponse était : " + realAnswer;
|
||||
}
|
||||
}
|
||||
|
||||
function addAudio(data) {
|
||||
const audio = document.createElement("audio");
|
||||
audio.controls = true;
|
||||
audio.src = "data:audio/ogg;base64," + data;
|
||||
audios.append(audio);
|
||||
}
|
||||
|
||||
function updateAudios(response) {
|
||||
addAudio(response.dataOne);
|
||||
addAudio(response.dataTwo);
|
||||
addAudio(response.dataThree);
|
||||
addAudio(response.dataFour);
|
||||
|
||||
content.append(document.createElement("br"));
|
||||
|
||||
response.answers.forEach(element => {
|
||||
const option = document.createElement("option");
|
||||
option.innerText = element;
|
||||
select.append(option);
|
||||
});
|
||||
content.append(select);
|
||||
|
||||
realAnswer = response.answer;
|
||||
answerButton.disabled = false;
|
||||
}
|
||||
|
||||
fetch("/newchallenge", {
|
||||
method: "POST"
|
||||
})
|
||||
.then((response) => response.json())
|
||||
.then((json) => updateAudios(json));
|
||||
170
back/src/main.cpp
Normal file
170
back/src/main.cpp
Normal file
@@ -0,0 +1,170 @@
|
||||
#include "stx-execpipe.h"
|
||||
|
||||
#include <iostream>
|
||||
#include <vector>
|
||||
#include <string>
|
||||
#include <random>
|
||||
|
||||
#include <httplib.h>
|
||||
#include <nlohmann/json.hpp>
|
||||
#include <turbobase64/turbob64.h>
|
||||
|
||||
static const std::map<std::string, std::string> links = {
|
||||
{"2gQ--SCEfmI", "What I Want"},
|
||||
{"9xBeLSXOvSY", "Drunk"},
|
||||
{"gv7QwZqMFYc", "Can't Wait"},
|
||||
{"tFRStkEkhbY", "Lazy"},
|
||||
{"OecoHvuxkxY", "Sunburn"},
|
||||
{"7SVKgjhpTHY", "Long Time Friends"},
|
||||
{"KF63Z27NPTE", "zero_one"},
|
||||
{"7fKPxTbFt88", "Animal"},
|
||||
{"ZccDikDUHmA", "Fly Home"},
|
||||
{"PjnHPuEUbjU", "Chosen"}};
|
||||
|
||||
static const std::string YTDLP_BINARY = "/home/simon/.local/bin/yt-dlp";
|
||||
|
||||
std::string GetAudioPath(const std::string &id)
|
||||
{
|
||||
return "audio/" + id + ".ogg";
|
||||
}
|
||||
|
||||
void DownloadFile(const std::string &id)
|
||||
{
|
||||
stx::ExecPipe ep;
|
||||
|
||||
std::string link = "https://music.youtube.com/watch?v=" + id;
|
||||
|
||||
std::vector<std::string> args = {YTDLP_BINARY, link.c_str(), "--extract-audio", "--audio-format", "vorbis", "--audio-quality", "10", "-o", "audio/%(id)s.%(ext)s"};
|
||||
|
||||
ep.add_exec(&args);
|
||||
ep.run();
|
||||
}
|
||||
|
||||
void DownloadFiles()
|
||||
{
|
||||
for (const auto &[id, title] : links)
|
||||
{
|
||||
DownloadFile(id);
|
||||
}
|
||||
}
|
||||
|
||||
float GetDuration(const std::string &id)
|
||||
{
|
||||
stx::ExecPipe ep;
|
||||
|
||||
std::string fileName = GetAudioPath(id);
|
||||
|
||||
std::vector<std::string> args = {"/usr/bin/ffprobe", "-v", "error", "-show_entries", "format=duration", "-of", "default=noprint_wrappers=1:nokey=1", fileName};
|
||||
|
||||
ep.add_exec(&args);
|
||||
std::string output;
|
||||
ep.set_output_string(&output);
|
||||
ep.run();
|
||||
|
||||
return std::stof(output);
|
||||
}
|
||||
|
||||
/**
|
||||
* \brief Returns a random real number between min and max.
|
||||
* \param min The minimum value.
|
||||
* \param max The maximum value.
|
||||
* \return A random real number between min and max.
|
||||
*/
|
||||
float GetRandomReal(float min, float max)
|
||||
{
|
||||
static std::random_device randomDevice;
|
||||
static std::mt19937 generator(randomDevice());
|
||||
std::uniform_real_distribution<float> distrib(min, max);
|
||||
return distrib(generator);
|
||||
}
|
||||
|
||||
std::string ExtractAudio(const std::string &id, float begin, float end)
|
||||
{
|
||||
stx::ExecPipe ep;
|
||||
|
||||
std::vector<std::string> args = {"/usr/bin/ffmpeg", "-y", "-loglevel", "panic", "-i", GetAudioPath(id), "-ss", std::to_string(begin), "-to", std::to_string(end), "-f", "ogg", "pipe:1"};
|
||||
|
||||
ep.add_exec(&args);
|
||||
|
||||
std::string output;
|
||||
ep.set_output_string(&output);
|
||||
|
||||
ep.run();
|
||||
|
||||
return output;
|
||||
}
|
||||
|
||||
std::pair<std::string, std::string> GetRandomLink()
|
||||
{
|
||||
auto it = links.begin();
|
||||
std::advance(it, rand() % links.size());
|
||||
return *it;
|
||||
}
|
||||
|
||||
struct Challenge
|
||||
{
|
||||
std::string one, two, three, four;
|
||||
std::string answer;
|
||||
};
|
||||
|
||||
Challenge GenRandomChallenge()
|
||||
{
|
||||
Challenge challenge;
|
||||
auto [randomLink, randomTitle] = GetRandomLink();
|
||||
float duration = GetDuration(randomLink);
|
||||
|
||||
float randomSeek = GetRandomReal(duration / 4.0f, duration * 3.0f / 4.0f);
|
||||
|
||||
challenge.answer = randomTitle;
|
||||
challenge.one = ExtractAudio(randomLink, randomSeek, randomSeek + 0.5f);
|
||||
challenge.two = ExtractAudio(randomLink, randomSeek, randomSeek + 1.0f);
|
||||
challenge.three = ExtractAudio(randomLink, randomSeek, randomSeek + 1.5f);
|
||||
challenge.four = ExtractAudio(randomLink, randomSeek, randomSeek + 2.0f);
|
||||
|
||||
std::cout << "Done !\n";
|
||||
|
||||
return challenge;
|
||||
}
|
||||
|
||||
std::string toBase64(const std::string &input)
|
||||
{
|
||||
std::string result;
|
||||
result.resize(tb64enclen(input.length()));
|
||||
|
||||
tb64enc(reinterpret_cast<const unsigned char *>(input.data()), input.size(), reinterpret_cast<unsigned char *>(result.data()));
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
std::vector<std::string> GetPossibleAnswers() {
|
||||
std::vector<std::string> answers;
|
||||
for (const auto& [link, title] : links) {
|
||||
answers.push_back(title);
|
||||
}
|
||||
return answers;
|
||||
}
|
||||
|
||||
int main(int argc, char **argv)
|
||||
{
|
||||
srand(time(0));
|
||||
|
||||
httplib::Server server;
|
||||
server.Post("/newchallenge", [](const httplib::Request &req, httplib::Response &res){
|
||||
Challenge challenge = GenRandomChallenge();
|
||||
|
||||
nlohmann::json j;
|
||||
j["answer"] = challenge.answer;
|
||||
j["dataOne"] = toBase64(challenge.one);
|
||||
j["dataTwo"] = toBase64(challenge.two);
|
||||
j["dataThree"] = toBase64(challenge.three);
|
||||
j["dataFour"] = toBase64(challenge.four);
|
||||
j["answers"] = GetPossibleAnswers();
|
||||
|
||||
res.set_content(j.dump(), "application/json");
|
||||
});
|
||||
|
||||
server.set_mount_point("/", "html");
|
||||
server.listen("0.0.0.0", 8080);
|
||||
|
||||
return 0;
|
||||
}
|
||||
1698
back/src/stx-execpipe.cpp
Normal file
1698
back/src/stx-execpipe.cpp
Normal file
File diff suppressed because it is too large
Load Diff
367
back/src/stx-execpipe.h
Normal file
367
back/src/stx-execpipe.h
Normal file
@@ -0,0 +1,367 @@
|
||||
// -*- mode: c++; fill-column: 79 -*-
|
||||
|
||||
/*
|
||||
* STX Execution Pipe Library v0.7.0
|
||||
* Copyright (C) 2010 Timo Bingmann
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU Lesser General Public License as published by the
|
||||
* Free Software Foundation; either version 2.1 of the License, or (at your
|
||||
* option) any later version.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License
|
||||
* for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with this library; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*/
|
||||
|
||||
#ifndef _STX_EXECPIPE_H_
|
||||
#define _STX_EXECPIPE_H_
|
||||
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
/// STX - Some Template Extensions namespace
|
||||
namespace stx {
|
||||
|
||||
/**
|
||||
* Abstract class used as an input stream source for an ExecPipe.
|
||||
*
|
||||
* Derived classes can be used in an ExecPipe to generate an input stream
|
||||
* source. Data generated by this class is written to the first stage of the
|
||||
* pipe.
|
||||
*
|
||||
* When data is needed by the pipe the function poll() is called. This pure
|
||||
* virtual function must generate data and push it into a buffer using the
|
||||
* write() function. The input stream is terminated when poll() returns false.
|
||||
*/
|
||||
class PipeSource
|
||||
{
|
||||
private:
|
||||
/// pointer to associated pipe. filled by ExecPipe::add_input_source()
|
||||
class ExecPipeImpl* m_impl;
|
||||
|
||||
/// association to the pipe implementation for write access to m_impl.
|
||||
friend class ExecPipeImpl;
|
||||
|
||||
public:
|
||||
/// Constructor which clears m_impl.
|
||||
PipeSource();
|
||||
|
||||
/// Poll the input source for new data. The input stream is closed when
|
||||
/// this function returns false, otherwise it will be polled again.
|
||||
virtual bool poll() = 0;
|
||||
|
||||
/// Write input data to the first stage via a buffer.
|
||||
void write(const void* data, unsigned int datalen);
|
||||
};
|
||||
|
||||
/**
|
||||
* Abstract class used as an output stream source for an ExecPipe.
|
||||
*
|
||||
* Derived classes can be attached to the end of an execution pipe. It will
|
||||
* receive all data outputted by the final pipe stage.
|
||||
*
|
||||
* Data read from the final or preceding stage is passed to the class via
|
||||
* process(). When the final stage closes the pipe, the function eof() is
|
||||
* called.
|
||||
*/
|
||||
class PipeSink
|
||||
{
|
||||
public:
|
||||
/// Pure virtual function which receives the output stream as read from the
|
||||
/// final or preceding pipe stage.
|
||||
virtual void process(const void* data, unsigned int datalen) = 0;
|
||||
|
||||
/// Pure virtual function called when the final or preceding pipe stage
|
||||
/// finishes.
|
||||
virtual void eof() = 0;
|
||||
};
|
||||
|
||||
/**
|
||||
* Abstract class used as an intermediate pipe stage between executed
|
||||
* processes.
|
||||
*
|
||||
* Derived classes can be inserted into an execution pipe between two
|
||||
* externally executed processes. It will receive all data from the preceding
|
||||
* pipe stage and after processing it may forward output to the next pipe
|
||||
* stage.
|
||||
*
|
||||
* The class is derived from PipeSink and receives data from the preceding
|
||||
* stage via the inherited functions process() and also the eof()
|
||||
* signal. Usually process() will perform some action on the data and then
|
||||
* forward the resulting data block to the next pipe stage via write().
|
||||
*/
|
||||
class PipeFunction : public PipeSink
|
||||
{
|
||||
private:
|
||||
/// pointer to associated pipe filled by ExecPipe::add_function()
|
||||
class ExecPipeImpl* m_impl;
|
||||
|
||||
/// pipe stage identifier
|
||||
unsigned int m_stageid;
|
||||
|
||||
/// association to the pipe implementation for write access to m_impl.
|
||||
friend class ExecPipeImpl;
|
||||
|
||||
public:
|
||||
/// Constructor which clears m_impl and m_stageid.
|
||||
PipeFunction();
|
||||
|
||||
/// Write input data to the next pipe stage via a buffer.
|
||||
void write(const void* data, unsigned int datalen);
|
||||
};
|
||||
|
||||
/**
|
||||
* \brief Main library interface (reference counted pointer)
|
||||
*
|
||||
* The ExecPipe class is the main interface to the library. It is a reference
|
||||
* counted pointer implementation, so you can easily copy and pass around
|
||||
* without duplicating the inside object. See the \ref index "main page" for
|
||||
* detailed information and examples.
|
||||
*/
|
||||
class ExecPipe
|
||||
{
|
||||
protected:
|
||||
/// reference-counted pointer implementation
|
||||
class ExecPipeImpl* m_impl;
|
||||
|
||||
public:
|
||||
/// Construct a new uninitialize execution pipe.
|
||||
ExecPipe();
|
||||
|
||||
/// Release reference to execution pipe.
|
||||
~ExecPipe();
|
||||
|
||||
/// Copy-constructor creates a new reference to the _same_ pipe.
|
||||
ExecPipe(const ExecPipe& ep);
|
||||
|
||||
/// Assignment operator creates a new reference to the right pipe.
|
||||
ExecPipe& operator=(const ExecPipe& ep);
|
||||
|
||||
// *** Debugging Output ***
|
||||
|
||||
/// Enumeration for ascending debug levels.
|
||||
enum DebugLevel
|
||||
{
|
||||
DL_ERROR=0, ///< error reporting is always active. shows failed syscalls.
|
||||
DL_INFO=1, ///< info reports at important points during pipe run.
|
||||
DL_DEBUG=2, ///< debug shows information about select() calls.
|
||||
DL_TRACE=3 ///< trace lists lots of info about read() and write() calls.
|
||||
};
|
||||
|
||||
/// Change the current debug level. The default is DL_ERROR.
|
||||
void set_debug_level(enum DebugLevel dl);
|
||||
|
||||
/// Change output function for debug messages. If set to NULL (the default)
|
||||
/// the debug lines are printed to stdout.
|
||||
void set_debug_output(void (*output)(const char *line));
|
||||
|
||||
// *** Input Selectors ***
|
||||
|
||||
///@{ \name Input Selectors
|
||||
|
||||
/**
|
||||
* Assign an already opened file descriptor as input stream for the first
|
||||
* exec stage.
|
||||
*/
|
||||
void set_input_fd(int fd);
|
||||
|
||||
/**
|
||||
* Assign a file as input stream source. This file will be opened read-only
|
||||
* and read by the first exec stage.
|
||||
*/
|
||||
void set_input_file(const char* path);
|
||||
|
||||
/**
|
||||
* Assign a std::string as input stream source. The contents of the string
|
||||
* will be written to the first exec stage. The string object is not copied
|
||||
* and must still exist when run() is called.
|
||||
*/
|
||||
void set_input_string(const std::string* input);
|
||||
|
||||
/**
|
||||
* Assign a PipeSource as input stream source. The object will be queried
|
||||
* via the read() function for data which is then written to the first exec
|
||||
* stage.
|
||||
*/
|
||||
void set_input_source(PipeSource* source);
|
||||
|
||||
///@}
|
||||
|
||||
// *** Output Selectors ***
|
||||
|
||||
///@{ \name Output Selectors
|
||||
|
||||
/**
|
||||
* Assign an already opened file descriptor as output stream for the last
|
||||
* exec stage.
|
||||
*/
|
||||
void set_output_fd(int fd);
|
||||
|
||||
/**
|
||||
* Assign a file as output stream destination. This file will be created or
|
||||
* truncated write-only and written by the last exec stage.
|
||||
*/
|
||||
void set_output_file(const char* path, int mode = 0666);
|
||||
|
||||
/**
|
||||
* Assign a std::string as output stream destination. The output of the
|
||||
* last exec stage will be stored as the contents of the string. The string
|
||||
* object is not copied and must still exist when run() is called.
|
||||
*/
|
||||
void set_output_string(std::string* output);
|
||||
|
||||
/**
|
||||
* Assign a PipeSink as output stream destination. The object will receive
|
||||
* data via the process() function and is informed via eof()
|
||||
*/
|
||||
void set_output_sink(PipeSink* sink);
|
||||
|
||||
///@}
|
||||
|
||||
// *** Pipe Stages ***
|
||||
|
||||
///@{ \name Add Pipe Stages
|
||||
|
||||
/**
|
||||
* Return the number of pipe stages added.
|
||||
*/
|
||||
unsigned int size() const;
|
||||
|
||||
/**
|
||||
* Add an exec() stage to the pipe with given arguments. Note that argv[0]
|
||||
* is set to prog.
|
||||
*/
|
||||
void add_exec(const char* prog);
|
||||
|
||||
/**
|
||||
* Add an exec() stage to the pipe with given arguments. Note that argv[0]
|
||||
* is set to prog.
|
||||
*/
|
||||
void add_exec(const char* prog, const char* arg1);
|
||||
|
||||
/**
|
||||
* Add an exec() stage to the pipe with given arguments. Note that argv[0]
|
||||
* is set to prog.
|
||||
*/
|
||||
void add_exec(const char* prog, const char* arg1, const char* arg2);
|
||||
|
||||
/**
|
||||
* Add an exec() stage to the pipe with given arguments. Note that argv[0]
|
||||
* is set to prog.
|
||||
*/
|
||||
void add_exec(const char* prog, const char* arg1, const char* arg2, const char* arg3);
|
||||
|
||||
/**
|
||||
* Add an exec() stage to the pipe with given arguments. The vector of
|
||||
* arguments is not copied, so it must still exist when run() is
|
||||
* called. Note that the program called is args[0].
|
||||
*/
|
||||
void add_exec(const std::vector<std::string>* args);
|
||||
|
||||
|
||||
/**
|
||||
* Add an execp() stage to the pipe with given arguments. The PATH variable
|
||||
* is search for programs not containing a slash / character. Note that
|
||||
* argv[0] is set to prog.
|
||||
*/
|
||||
void add_execp(const char* prog);
|
||||
|
||||
/**
|
||||
* Add an execp() stage to the pipe with given arguments. The PATH variable
|
||||
* is search for programs not containing a slash / character. Note that
|
||||
* argv[0] is set to prog.
|
||||
*/
|
||||
void add_execp(const char* prog, const char* arg1);
|
||||
|
||||
/**
|
||||
* Add an execp() stage to the pipe with given arguments. The PATH variable
|
||||
* is search for programs not containing a slash / character. Note that
|
||||
* argv[0] is set to prog.
|
||||
*/
|
||||
void add_execp(const char* prog, const char* arg1, const char* arg2);
|
||||
|
||||
/**
|
||||
* Add an execp() stage to the pipe with given arguments. The PATH variable
|
||||
* is search for programs not containing a slash / character. Note that
|
||||
* argv[0] is set to prog.
|
||||
*/
|
||||
void add_execp(const char* prog, const char* arg1, const char* arg2, const char* arg3);
|
||||
|
||||
/**
|
||||
* Add an execp() stage to the pipe with given arguments. The PATH variable
|
||||
* is search for programs not containing a slash / character. The vector of
|
||||
* arguments is not copied, so it must still exist when run() is
|
||||
* called. Note that the program called is args[0].
|
||||
*/
|
||||
void add_execp(const std::vector<std::string>* args);
|
||||
|
||||
/**
|
||||
* Add an exece() stage to the pipe with the given arguments and
|
||||
* environments. This is the most flexible exec() call. The vector of
|
||||
* arguments and environment variables is not copied, so it must still
|
||||
* exist when run() is called. The args[0] is _not_ override with path, so
|
||||
* you can fake program name calls.
|
||||
*/
|
||||
void add_exece(const char* path,
|
||||
const std::vector<std::string>* args,
|
||||
const std::vector<std::string>* env);
|
||||
|
||||
/**
|
||||
* Add a function stage to the pipe. This function object will be called in
|
||||
* the parent process with data passing through the stage. See PipeFunction
|
||||
* for more information.
|
||||
*/
|
||||
void add_function(PipeFunction* func);
|
||||
|
||||
///@}
|
||||
|
||||
// *** Run Pipe ***
|
||||
|
||||
/**
|
||||
* Run the configured pipe sequence and wait for all children processes to
|
||||
* complete. Returns a reference to *this for chaining.
|
||||
*
|
||||
* This function call should be wrapped into a try-catch block as it will
|
||||
* throw() if a system call fails.
|
||||
*/
|
||||
ExecPipe& run();
|
||||
|
||||
// *** Inspection After Pipe Execution ***
|
||||
|
||||
///@{ \name Inspect Return Codes
|
||||
|
||||
/**
|
||||
* Get the return status of exec() stage's program run after pipe execution
|
||||
* as indicated by wait().
|
||||
*/
|
||||
int get_return_status(unsigned int stageid) const;
|
||||
|
||||
/**
|
||||
* Get the return code of exec() stage's program run after pipe execution,
|
||||
* or -1 if the program terminated abnormally.
|
||||
*/
|
||||
int get_return_code(unsigned int stageid) const;
|
||||
|
||||
/**
|
||||
* Get the signal of the abnormally terminated exec() stage's program run
|
||||
* after pipe execution, or -1 if the program terminated normally.
|
||||
*/
|
||||
int get_return_signal(unsigned int stageid) const;
|
||||
|
||||
/**
|
||||
* Return true if the return code of all exec() stages were zero.
|
||||
*/
|
||||
bool all_return_codes_zero() const;
|
||||
|
||||
///@}
|
||||
};
|
||||
|
||||
} // namespace stx
|
||||
|
||||
#endif // _STX_EXECPIPE_H_
|
||||
12
back/xmake.lua
Normal file
12
back/xmake.lua
Normal file
@@ -0,0 +1,12 @@
|
||||
add_rules("mode.debug", "mode.release")
|
||||
|
||||
set_languages("c++17")
|
||||
|
||||
add_requires("cpp-httplib", "nlohmann_json", "turbobase64")
|
||||
|
||||
target("Songdle")
|
||||
set_kind("binary")
|
||||
add_files("src/*.cpp")
|
||||
set_rundir(".")
|
||||
add_packages("cpp-httplib", "nlohmann_json", "turbobase64")
|
||||
|
||||
Reference in New Issue
Block a user