Commit 294b71a1 authored by Paweł Wegner's avatar Paweł Wegner
Browse files

IItem: added size property.

parent f0ce9804
......@@ -39,6 +39,7 @@ class MockProvider : public ICloudProvider {
std::string extension() const override { return ""; }
std::string id() const override { return filename_; }
std::string url() const override { return ""; }
size_t size() const override { return 0; }
bool is_hidden() const override { return false; }
FileType type() const override { return type_; }
......
......@@ -91,7 +91,8 @@ std::string AmazonDrive::name() const { return "amazon"; }
std::string AmazonDrive::endpoint() const { return content_url(); }
IItem::Pointer AmazonDrive::rootDirectory() const {
return util::make_unique<Item>("root", "root", IItem::FileType::Directory);
return util::make_unique<Item>("root", "root", IItem::UnknownSize,
IItem::FileType::Directory);
}
ICloudProvider::MoveItemRequest::Pointer AmazonDrive::moveItemAsync(
......@@ -133,8 +134,8 @@ AuthorizeRequest::Pointer AmazonDrive::authorizeAsync() {
content_url_ = response["contentUrl"].asString();
lock.unlock();
complete(nullptr);
} catch (std::exception e) {
complete(Error{IHttpRequest::Failure, e.what()});
} catch (std::exception) {
complete(Error{IHttpRequest::Failure, output->str()});
}
},
input, output, error);
......@@ -257,7 +258,9 @@ IItem::FileType AmazonDrive::type(const Json::Value& v) const {
IItem::Pointer AmazonDrive::toItem(const Json::Value& v) const {
std::string name = v["isRoot"].asBool() ? "root" : v["name"].asString();
auto item = util::make_unique<Item>(name, v["id"].asString(), type(v));
auto item = util::make_unique<Item>(name, v["id"].asString(),
v["contentProperties"]["size"].asUInt64(),
type(v));
item->set_url(v["tempLink"].asString());
if (item->type() == IItem::FileType::Image)
item->set_thumbnail_url(item->url() +
......
......@@ -33,8 +33,8 @@ namespace cloudstorage {
namespace {
void rename(Request<EitherError<void>>::Pointer r, IHttp* http, std::string region,
std::string dest_id, std::string source_id,
void rename(Request<EitherError<void>>::Pointer r, IHttp* http,
std::string region, std::string dest_id, std::string source_id,
std::function<void(EitherError<void>)> complete);
std::string escapePath(const std::string& str) {
......@@ -66,7 +66,8 @@ void remove(Request<EitherError<void>>::Pointer r,
}));
}
void rename(Request<EitherError<void>>::Pointer r, IHttp* http, std::string region,
void rename(Request<EitherError<void>>::Pointer r, IHttp* http,
std::string region,
std::shared_ptr<std::vector<IItem::Pointer>> lst,
std::string dest_id, std::string source_id,
std::function<void(EitherError<void>)> complete) {
......@@ -82,8 +83,8 @@ void rename(Request<EitherError<void>>::Pointer r, IHttp* http, std::string regi
});
}
void rename(Request<EitherError<void>>::Pointer r, IHttp* http, std::string region,
std::string dest_id, std::string source_id,
void rename(Request<EitherError<void>>::Pointer r, IHttp* http,
std::string region, std::string dest_id, std::string source_id,
std::function<void(EitherError<void>)> complete) {
auto finalize = [=]() {
auto output = std::make_shared<std::stringstream>();
......@@ -254,7 +255,7 @@ ICloudProvider::CreateDirectoryRequest::Pointer AmazonS3::createDirectoryAsync(
} else {
auto path = getPath(parent->id());
if (!split(path).second.empty()) path += "/";
auto item = std::make_shared<Item>(name, path + name + "/",
auto item = std::make_shared<Item>(name, path + name + "/", 0,
IItem::FileType::Directory);
callback(EitherError<IItem>(item));
r->done(EitherError<IItem>(item));
......@@ -315,29 +316,53 @@ ICloudProvider::GetItemDataRequest::Pointer AmazonS3::getItemDataAsync(
const std::string& id, GetItemCallback callback) {
auto r = std::make_shared<Request<EitherError<IItem>>>(shared_from_this());
r->set([=](Request<EitherError<IItem>>::Pointer r) {
auto work = [=]() {
auto factory = [=](util::Output) {
auto data = split(id);
auto item = std::make_shared<Item>(
getFilename(data.second), id,
(data.second.empty() || data.second.back() == '/')
? IItem::FileType::Directory
: IItem::FileType::Unknown);
if (item->type() != IItem::FileType::Directory)
item->set_url(getUrl(*item));
callback(EitherError<IItem>(item));
r->done(EitherError<IItem>(item));
auto request = http()->create(
"https://" + data.first + ".s3." + region() + ".amazonaws.com/",
"GET");
request->setParameter("list-type", "2");
request->setParameter("prefix", data.second);
request->setParameter("delimiter", data.second);
return request;
};
if (access_id().empty() || secret().empty())
r->reauthorize([=](EitherError<void> e) {
if (e.left()) {
callback(e.left());
r->done(e.left());
} else {
work();
}
});
else
work();
auto output = std::make_shared<std::stringstream>();
r->sendRequest(
factory,
[=](EitherError<util::Output> e) {
if (e.left()) {
callback(e.left());
return r->done(e.left());
}
std::stringstream sstream;
sstream << output->rdbuf();
tinyxml2::XMLDocument document;
if (document.Parse(sstream.str().c_str(), sstream.str().size()) !=
tinyxml2::XML_SUCCESS) {
Error e{IHttpRequest::Failure, "invalid xml"};
callback(e);
return r->done(e);
}
auto get_size = [](const tinyxml2::XMLNode* node) {
auto contents_element = node->FirstChildElement("Contents");
if (!contents_element) return IItem::UnknownSize;
auto size_element = contents_element->FirstChildElement("Size");
if (!size_element) return IItem::UnknownSize;
auto text = size_element->GetText();
return text ? (size_t)std::atoll(text) : IItem::UnknownSize;
};
auto data = split(id);
auto item = std::make_shared<Item>(
getFilename(data.second), id, get_size(document.RootElement()),
(data.second.empty() || data.second.back() == '/')
? IItem::FileType::Directory
: IItem::FileType::Unknown);
if (item->type() != IItem::FileType::Directory)
item->set_url(getUrl(*item));
callback(EitherError<IItem>(item));
r->done(EitherError<IItem>(item));
},
output);
});
return r->run();
}
......@@ -385,26 +410,32 @@ std::vector<IItem::Pointer> AmazonS3::listDirectoryResponse(
tinyxml2::XMLDocument document;
if (document.Parse(sstream.str().c_str(), sstream.str().size()) !=
tinyxml2::XML_SUCCESS)
return {};
throw std::logic_error("invalid xml");
std::vector<IItem::Pointer> result;
if (auto buckets = document.RootElement()->FirstChildElement("Buckets")) {
for (auto child = buckets->FirstChild(); child;
child = child->NextSibling()) {
std::string name = child->FirstChildElement("Name")->GetText();
auto item = util::make_unique<Item>(name, name + Auth::SEPARATOR,
auto name_element = child->FirstChildElement("Name");
if (!name_element) throw std::logic_error("invalid xml");
std::string name = name_element->GetText();
auto item = util::make_unique<Item>(name, name + Auth::SEPARATOR, -1,
IItem::FileType::Directory);
result.push_back(std::move(item));
}
} else if (document.RootElement()->FirstChildElement("Name")) {
std::string bucket =
document.RootElement()->FirstChildElement("Name")->GetText();
} else if (auto name_element =
document.RootElement()->FirstChildElement("Name")) {
std::string bucket = name_element->GetText();
for (auto child = document.RootElement()->FirstChildElement("Contents");
child; child = child->NextSiblingElement("Contents")) {
if (child->FirstChildElement("Size")->GetText() == std::string("0"))
continue;
std::string id = child->FirstChildElement("Key")->GetText();
auto size_element = child->FirstChildElement("Size");
if (!size_element) throw std::logic_error("invalid xml");
auto size = std::atoll(size_element->GetText());
if (size == 0) continue;
auto key_element = child->FirstChildElement("Key");
if (!key_element) throw std::logic_error("invalid xml");
std::string id = key_element->GetText();
auto item = util::make_unique<Item>(getFilename(id),
bucket + Auth::SEPARATOR + id,
bucket + Auth::SEPARATOR + id, size,
IItem::FileType::Unknown);
item->set_url(getUrl(*item));
result.push_back(std::move(item));
......@@ -412,17 +443,22 @@ std::vector<IItem::Pointer> AmazonS3::listDirectoryResponse(
for (auto child =
document.RootElement()->FirstChildElement("CommonPrefixes");
child; child = child->NextSiblingElement("CommonPrefixes")) {
std::string id = child->FirstChildElement("Prefix")->GetText();
auto item = util::make_unique<Item>(getFilename(id),
bucket + Auth::SEPARATOR + id,
IItem::FileType::Directory);
auto prefix_element = child->FirstChildElement("Prefix");
if (!prefix_element) throw std::logic_error("invalid xml");
std::string id = prefix_element->GetText();
auto item = util::make_unique<Item>(
getFilename(id), bucket + Auth::SEPARATOR + id, IItem::UnknownSize,
IItem::FileType::Directory);
result.push_back(std::move(item));
}
if (document.RootElement()->FirstChildElement("IsTruncated")->GetText() ==
std::string("true")) {
next_page_token = document.RootElement()
->FirstChildElement("NextContinuationToken")
->GetText();
auto is_truncated_element =
document.RootElement()->FirstChildElement("IsTruncated");
if (!is_truncated_element) throw std::logic_error("invalid xml");
if (is_truncated_element->GetText() == std::string("true")) {
auto next_token_element =
document.RootElement()->FirstChildElement("NextContinuationToken");
if (!next_token_element) throw std::logic_error("invalid xml");
next_page_token = next_token_element->GetText();
}
}
return result;
......
......@@ -36,7 +36,8 @@ namespace cloudstorage {
Box::Box() : CloudProvider(util::make_unique<Auth>()) {}
IItem::Pointer Box::rootDirectory() const {
return util::make_unique<Item>("root", "0", IItem::FileType::Directory);
return util::make_unique<Item>("root", "0", IItem::UnknownSize,
IItem::FileType::Directory);
}
std::string Box::name() const { return "box"; }
......@@ -74,8 +75,8 @@ ICloudProvider::GetItemDataRequest::Pointer Box::getItemDataAsync(
auto item = toItem(response);
callback(item);
r->done(item);
} catch (std::exception e) {
Error err{IHttpRequest::Failure, e.what()};
} catch (std::exception) {
Error err{IHttpRequest::Failure, output->str()};
callback(err);
r->done(err);
}
......@@ -121,6 +122,7 @@ IHttpRequest::Pointer Box::listDirectoryRequest(const IItem& item,
std::ostream&) const {
auto request = http()->create(
endpoint() + "/2.0/folders/" + item.id() + "/items/", "GET");
request->setParameter("fields", "name,id,size");
if (!page_token.empty()) request->setParameter("offset", page_token);
return request;
}
......@@ -238,8 +240,8 @@ std::vector<IItem::Pointer> Box::listDirectoryResponse(
IItem::Pointer Box::toItem(const Json::Value& v) const {
IItem::FileType type = IItem::FileType::Unknown;
if (v["type"].asString() == "folder") type = IItem::FileType::Directory;
auto item =
util::make_unique<Item>(v["name"].asString(), v["id"].asString(), type);
auto item = util::make_unique<Item>(v["name"].asString(), v["id"].asString(),
v["size"].asUInt64(), type);
return std::move(item);
}
......
......@@ -247,7 +247,8 @@ std::string CloudProvider::token() const {
}
IItem::Pointer CloudProvider::rootDirectory() const {
return util::make_unique<Item>("/", "root", IItem::FileType::Directory);
return util::make_unique<Item>("/", "root", IItem::UnknownSize,
IItem::FileType::Directory);
}
ICloudProvider::IAuthCallback* CloudProvider::auth_callback() const {
......
......@@ -42,7 +42,8 @@ std::string Dropbox::name() const { return "dropbox"; }
std::string Dropbox::endpoint() const { return DROPBOXAPI_ENDPOINT; }
IItem::Pointer Dropbox::rootDirectory() const {
return util::make_unique<Item>("/", "", IItem::FileType::Directory);
return util::make_unique<Item>("/", "", IItem::UnknownSize,
IItem::FileType::Directory);
}
bool Dropbox::reauthorize(int code) const {
......@@ -101,16 +102,16 @@ ICloudProvider::GetItemDataRequest::Pointer Dropbox::getItemDataAsync(
->set_url(response["link"].asString());
callback(item);
r->done(item);
} catch (std::exception e) {
Error err{IHttpRequest::Failure, e.what()};
} catch (std::exception) {
Error err{IHttpRequest::Failure, output->str()};
callback(err);
r->done(err);
}
}
},
output);
} catch (std::exception e) {
Error err{IHttpRequest::Failure, e.what()};
} catch (std::exception) {
Error err{IHttpRequest::Failure, output->str()};
callback(err);
r->done(err);
}
......@@ -259,7 +260,8 @@ IItem::Pointer Dropbox::toItem(const Json::Value& v) {
type = IItem::FileType::Image;
}
return util::make_unique<Item>(v["name"].asString(),
v["path_display"].asString(), type);
v["path_display"].asString(),
v["size"].asUInt64(), type);
}
Dropbox::Auth::Auth() {
......
......@@ -45,7 +45,7 @@ IHttpRequest::Pointer GoogleDrive::getItemDataRequest(const std::string& id,
auto request = http()->create(endpoint() + "/drive/v3/files/" + id, "GET");
request->setParameter("fields",
"id,name,thumbnailLink,trashed,"
"mimeType,iconLink,parents");
"mimeType,iconLink,parents,size");
return request;
}
......@@ -56,7 +56,7 @@ IHttpRequest::Pointer GoogleDrive::listDirectoryRequest(
request->setParameter("q", std::string("'") + item.id() + "'+in+parents");
request->setParameter("fields",
"files(id,name,thumbnailLink,trashed,"
"mimeType,iconLink,parents),kind,"
"mimeType,iconLink,parents,size),kind,"
"nextPageToken");
if (!page_token.empty()) request->setParameter("pageToken", page_token);
return request;
......@@ -179,8 +179,11 @@ IItem::FileType GoogleDrive::toFileType(const std::string& mime_type) const {
}
IItem::Pointer GoogleDrive::toItem(const Json::Value& v) const {
auto item = util::make_unique<Item>(v["name"].asString(), v["id"].asString(),
toFileType(v["mimeType"].asString()));
auto item = util::make_unique<Item>(
v["name"].asString(), v["id"].asString(),
v.isMember("size") ? std::atoll(v["size"].asString().c_str())
: IItem::UnknownSize,
toFileType(v["mimeType"].asString()));
item->set_hidden(v["trashed"].asBool());
std::string thumnail_url = v["thumbnailLink"].asString();
if (!thumnail_url.empty() && isGoogleMimeType(v["mimeType"].asString()))
......
......@@ -40,7 +40,7 @@ using namespace std::placeholders;
const int BUFFER_SIZE = 1024;
const int CACHE_FILENAME_LENGTH = 12;
const std::string DEFAULT_FILE_URL = "http://127.0.0.1:12346";
const std::string DEFAULT_FILE_URL = "http://localhost:12346";
namespace cloudstorage {
......@@ -427,7 +427,8 @@ std::string MegaNz::name() const { return "mega"; }
std::string MegaNz::endpoint() const { return file_url_; }
IItem::Pointer MegaNz::rootDirectory() const {
return util::make_unique<Item>("root", "/", IItem::FileType::Directory);
return util::make_unique<Item>("root", "/", IItem::UnknownSize,
IItem::FileType::Directory);
}
ICloudProvider::Hints MegaNz::hints() const {
......@@ -784,9 +785,10 @@ MegaNz::listDirectoryPageAsync(IItem::Pointer item, const std::string&,
return r->run();
}
std::function<void(Request<EitherError<void>>::Pointer)> MegaNz::downloadResolver(
IItem::Pointer item, IDownloadFileCallback::Pointer callback, int64_t start,
int64_t size) {
std::function<void(Request<EitherError<void>>::Pointer)>
MegaNz::downloadResolver(IItem::Pointer item,
IDownloadFileCallback::Pointer callback, int64_t start,
int64_t size) {
return [=](Request<EitherError<void>>::Pointer r) {
ensureAuthorized<EitherError<void>>(
r, std::bind(&IDownloadFileCallback::done, callback.get(), _1), [=] {
......@@ -829,7 +831,7 @@ std::string MegaNz::passwordHash(const std::string& password) const {
IItem::Pointer MegaNz::toItem(MegaNode* node) {
std::unique_ptr<char[]> path(mega_->getNodePath(node));
auto item = util::make_unique<Item>(
node->getName(), path.get(),
node->getName(), path.get(), node->getSize(),
node->isFolder() ? IItem::FileType::Directory : IItem::FileType::Unknown);
item->set_url(endpoint() + "/?file=" + util::Url::escape(path.get()) +
"&state=" + auth()->state());
......
......@@ -99,8 +99,8 @@ ICloudProvider::UploadFileRequest::Pointer OneDrive::uploadFileAsync(
Json::Value response;
*output >> response;
upload(r, 0, callback, response);
} catch (std::exception e) {
Error err{IHttpRequest::Failure, e.what()};
} catch (std::exception) {
Error err{IHttpRequest::Failure, output->str()};
callback->done(err);
r->done(err);
}
......@@ -115,7 +115,8 @@ IHttpRequest::Pointer OneDrive::getItemDataRequest(const std::string& id,
IHttpRequest::Pointer request =
http()->create(endpoint() + "/v1.0/drive/items/" + id, "GET");
request->setParameter(
"select", "name,folder,audio,image,photo,video,id,@content.downloadUrl");
"select",
"name,folder,audio,image,photo,video,id,size,@content.downloadUrl");
return request;
}
......@@ -125,7 +126,8 @@ IHttpRequest::Pointer OneDrive::listDirectoryRequest(
auto request = http()->create(
endpoint() + "/v1.0/drive/items/" + item.id() + "/children", "GET");
request->setParameter(
"select", "name,folder,audio,image,photo,video,id,@content.downloadUrl");
"select",
"name,folder,audio,image,photo,video,id,size,@content.downloadUrl");
return request;
}
......@@ -198,8 +200,8 @@ IItem::Pointer OneDrive::toItem(const Json::Value& v) const {
type = IItem::FileType::Video;
else if (v.isMember("audio"))
type = IItem::FileType::Audio;
auto item =
util::make_unique<Item>(v["name"].asString(), v["id"].asString(), type);
auto item = util::make_unique<Item>(v["name"].asString(), v["id"].asString(),
v["size"].asUInt64(), type);
item->set_url(v["@content.downloadUrl"].asString());
item->set_thumbnail_url(
endpoint() + "/v1.0/drive/items/" + item->id() +
......
......@@ -33,7 +33,8 @@ namespace cloudstorage {
OwnCloud::OwnCloud() : CloudProvider(util::make_unique<Auth>()) {}
IItem::Pointer OwnCloud::rootDirectory() const {
return util::make_unique<Item>("root", "/", IItem::FileType::Directory);
return util::make_unique<Item>("root", "/", IItem::UnknownSize,
IItem::FileType::Directory);
}
void OwnCloud::initialize(InitData&& data) {
......@@ -73,7 +74,7 @@ ICloudProvider::CreateDirectoryRequest::Pointer OwnCloud::createDirectoryAsync(
r->done(e.left());
} else {
IItem::Pointer item = util::make_unique<Item>(
name, parent->id() + name + "/", IItem::FileType::Directory);
name, parent->id() + name + "/", 0, IItem::FileType::Directory);
callback(item);
r->done(item);
}
......@@ -189,7 +190,16 @@ IItem::Pointer OwnCloud::toItem(const tinyxml2::XMLNode* node) const {
std::string filename = id;
if (filename.back() == '/') filename.pop_back();
filename = filename.substr(filename.find_last_of('/') + 1);
auto item = util::make_unique<Item>(util::Url::unescape(filename), id, type);
auto get_size = [](const tinyxml2::XMLNode* node) {
auto propstat = node->FirstChildElement("d:propstat");
if (!propstat) return IItem::UnknownSize;
auto prop = propstat->FirstChildElement("d:prop");
if (!prop) return IItem::UnknownSize;
auto size = prop->FirstChildElement("d:getcontentlength");
return size ? (size_t)std::atoll(size->GetText()) : IItem::UnknownSize;
};
auto item = util::make_unique<Item>(util::Url::unescape(filename), id,
get_size(node), type);
item->set_url(api_url() + "/remote.php/webdav" + id);
return std::move(item);
}
......
......@@ -44,7 +44,8 @@ std::string YandexDisk::endpoint() const {
}
IItem::Pointer YandexDisk::rootDirectory() const {
return util::make_unique<Item>("disk", "disk:/", IItem::FileType::Directory);
return util::make_unique<Item>("disk", "disk:/", IItem::UnknownSize,
IItem::FileType::Directory);
}
ICloudProvider::GetItemDataRequest::Pointer YandexDisk::getItemDataAsync(
......@@ -83,8 +84,8 @@ ICloudProvider::GetItemDataRequest::Pointer YandexDisk::getItemDataAsync(
*output >> json;
static_cast<Item*>(item.get())
->set_url(json["href"].asString());
} catch (std::exception e) {
Error err{IHttpRequest::Failure, e.what()};
} catch (std::exception) {
Error err{IHttpRequest::Failure, output->str()};
callback(err);
r->done(err);
}
......@@ -97,8 +98,8 @@ ICloudProvider::GetItemDataRequest::Pointer YandexDisk::getItemDataAsync(
callback(item);
r->done(item);
}
} catch (std::exception e) {
Error err{IHttpRequest::Failure, e.what()};
} catch (std::exception) {
Error err{IHttpRequest::Failure, output->str()};
callback(err);
r->done(err);
}
......@@ -147,8 +148,8 @@ ICloudProvider::DownloadFileRequest::Pointer YandexDisk::downloadFileAsync(
},
stream, std::bind(&IDownloadFileCallback::progress,
callback.get(), _1, _2));
} catch (std::exception e) {
Error err{IHttpRequest::Failure, e.what()};
} catch (std::exception) {
Error err{IHttpRequest::Failure, output->str()};
callback->done(err);
r->done(err);
}
......@@ -208,8 +209,8 @@ ICloudProvider::UploadFileRequest::Pointer YandexDisk::uploadFileAsync(
},
output, nullptr, std::bind(&IUploadFileCallback::progress,
callback.get(), _1, _2));
} catch (std::exception e) {
Error err{IHttpRequest::Failure, e.what()};
} catch (std::exception) {
Error err{IHttpRequest::Failure, output->str()};
callback->done(err);
r->done(err);
}
......@@ -258,15 +259,15 @@ YandexDisk::createDirectoryAsync(IItem::Pointer parent, const std::string& name,
auto item = toItem(json);
callback(item);
r->done(item);
} catch (std::exception e) {
Error err{IHttpRequest::Failure, e.what()};
} catch (std::exception) {
Error err{IHttpRequest::Failure, output->str()};
callback(err);
r->done(err);
}
},
output);
} catch (std::exception e) {
Error err{IHttpRequest::Failure, e.what()};
} catch (std::exception) {
Error err{IHttpRequest::Failure, output->str()};
callback(err);
r->done(err);
}
......@@ -332,8 +333,8 @@ IItem::Pointer YandexDisk::toItem(const Json::Value& v) const {
IItem::FileType type = v["type"].asString() == "dir"
? IItem::FileType::Directory
: Item::fromMimeType(v["mime_type"].asString());
auto item =
util::make_unique<Item>(v["name"].asString(), v["path"].asString(), type);
auto item = util::make_unique<Item>(
v["name"].asString(), v["path"].asString(), v["size"].asUInt64(), type);
item->set_thumbnail_url(v["preview"].asString());
return std::move(item);
}
......
......@@ -87,7 +87,8 @@ ICloudProvider::GetItemDataRequest::Pointer YouTube::getItemDataAsync(
r->set([=](Request<EitherError<IItem>>::Pointer r) {
if (id == AUDIO_DIRECTORY) {
IItem::Pointer i = std::make_shared<Item>(
AUDIO_DIRECTORY, AUDIO_DIRECTORY, IItem::FileType::Directory);
AUDIO_DIRECTORY, AUDIO_DIRECTORY, IItem::UnknownSize,
IItem::FileType::Directory);
callback(i);
return r->done(i);
}
......@@ -102,50 +103,52 @@ ICloudProvider::GetItemDataRequest::Pointer YouTube::getItemDataAsync(
auto i = getItemDataResponse(
*response_stream, id.find(AUDIO_ID_PREFIX) != std::string::npos);
auto stream = std::make_shared<std::stringstream>();
if (i->type() == IItem::FileType::Audio) {
r->sendRequest(
[=](util::Output) {
auto request =
http()->create(youtube_dl_url_ + "/api/info", "GET");