#include #include #include #include #include #include "YtdlpWrapper.hpp" using json = nlohmann::json; namespace py = pybind11; using namespace py::literals; void Video::to_json(json& j, const format& f) { j = json{{"format", f.format}, {"url", f.url}, {"vcodec", f.vcodec}, {"acodec", f.acodec}, {"ext", f.ext} }; if (f.quality.has_value()) { j["quality"] = f.quality.value(); } if (f.resolution.has_value()) { j["resolution"] = f.resolution.value(); } if (f.height.has_value()) { j["height"] = f.height.value(); } if (f.width.has_value()) { j["width"] = f.width.value(); } } void Video::to_json(json& j, const thumbnail& t) { j = json{{"url", t.url}, {"preference", t.preference}, {"id", t.id} }; if (t.resolution.has_value()) { j["resolution"] = t.resolution.value(); } if (t.height.has_value()) { j["height"] = t.height.value(); } if (t.width.has_value()) { j["width"] = t.width.value(); } } void Video::to_json(json& j, const video& v) { j = json{{"id", v.id}, {"title", v.title}, {"webpage_url", v.url}, {"channel_id", v.channelId}, {"channel_url", v.channelUrl}}; if (v.uploader.has_value()) { j["uploader"] = v.uploader.value(); } if (v.uploaderId.has_value()) { j["uploader_id"] = v.uploaderId.value(); } if (v.uploaderUrl.has_value()) { j["uploader_url"] = v.uploaderUrl.value(); } if (v.duration.has_value()) { j["duration"] = v.duration.value(); } if (v.viewcount.has_value()) { j["view_count"] = v.viewcount.value(); } if (v.description.has_value()) { j["description"] = v.description.value(); } j["formats"] = json::array(); for (format f: v.formats) { j.at("formats").emplace_back(json(f)); } j["thumbnails"] = json::array(); for (thumbnail t: v.thumbnails) { j.at("thumbnails").emplace_back(json(t)); } } void Video::from_json(const json& j, format& f) { j.at("format").get_to(f.format); j.at("url").get_to(f.url); j.at("vcodec").get_to(f.vcodec); j.at("acodec").get_to(f.acodec); j.at("ext").get_to(f.ext); if (j.contains("quality") && j.at("quality").is_string()) { f.quality = j.at("quality"); } if (j.contains("resolution") && j.at("resolution").is_string()) { f.resolution = j.at("resolution"); } if (j.contains("width") && j.at("width").is_number()) { f.width = j.at("width"); } if (j.contains("height") && j.at("height").is_number()) { f.height = j.at("height"); } } void Video::from_json(const json& j, thumbnail& t) { j.at("url").get_to(t.url); j.at("preference").get_to(t.preference); j.at("id").get_to(t.id); if (j.contains("resolution") && j.at("resolution").is_string()) { t.resolution = j.at("resolution"); } if (j.contains("width") && j.at("width").is_number()) { t.width = j.at("width"); } if (j.contains("height") && j.at("height").is_number()) { t.height = j.at("height"); } } void Video::from_json(const json& j, video& v) { j.at("id").get_to(v.id); j.at("title").get_to(v.title); j.at("webpage_url").get_to(v.url); j.at("channel_id").get_to(v.channelId); j.at("channel_url").get_to(v.channelUrl); if (j.contains("uploader")) { v.uploader = j.at("uploader"); } if (j.contains("uploader_id")) { v.uploaderId = j.at("uploader_id"); } if (j.contains("uploader_url")) { v.uploaderUrl = j.at("uploader_url"); } if (j.contains("duration")) { v.duration = j.at("duration"); } if (j.contains("view_count")) { v.viewcount = j.at("view_count"); } if (j.contains("description")) { v.description = j.at("description"); } for (json f: j.at("formats")) { format form; from_json(f, form); v.formats.push_back(form); } for (json t: j.at("thumbnails")) { thumbnail thumb; from_json(t, thumb); v.thumbnails.push_back(thumb); } } std::string pyDictToJsonString(const py::dict& dict) { pybind11::object json = py::module::import("json"); return json.attr("dumps")(dict).cast(); } py::object YtdlpWrapper::get_ytdl() { if (ytdl.is_none()) { ytdl = py::module::import("yt_dlp"); } return ytdl; } json YtdlpWrapper::getJsonSearch(const std::string& searchTerm, int limit) { py::dict info = get_ytdl() .attr("YoutubeDL")(py::dict("ignoreerrors"_a=py::bool_(true))) .attr("extract_info")("ytsearch"+std::to_string(limit)+":"+searchTerm, "download"_a=py::bool_(false)); return json::parse(pyDictToJsonString(info)); } std::vector YtdlpWrapper::searchVideos(const std::string& searchTerm, int limit) { std::vector resp; json info = getJsonSearch(searchTerm, limit); for (json i: info.at("entries")) { Video::video entry{i.at("id"), i.at("title"), i.at("original_url"), {i.at("channel_url")}}; for (json j: i.at("formats")) { Video::format form{j.at("format"), j.at("url"), j.at("vcodec"), j.at("acodec"), j.at("ext")}; if (j.contains("quality")) { form.quality = j.at("quality"); } if (j.contains("resolution")) { form.resolution = j.at("resolution"); } if (j.contains("width")) { form.width = j.at("width"); } if (j.contains("height")) { form.height = j.at("height"); } entry.formats.push_back(form); } for (json j: i.at("thumbnails")) { Video::thumbnail thumb{j.at("url"), j.at("preference"), j.at("id")}; if (j.contains("resolution")) { thumb.resolution = j.at("resolution"); } if (j.contains("height")) { thumb.height = j.at("height"); } if (j.contains("width")) { thumb.width = j.at("width"); } entry.thumbnails.push_back(thumb); } resp.push_back(entry); } return resp; } Video::video YtdlpWrapper::getVideoByUrl(const std::string& url) { json info = json::parse(pyDictToJsonString( get_ytdl().attr("YoutubeDL")(py::dict("ignoreerrors"_a=py::bool_(true), "noplaylist"_a=py::bool_(true))) .attr("extract_info")(url, "download"_a=py::bool_(false)) )); Video::video resp{info.at("id"), info.at("title"), info.at("original_url"), {info.at("channel_url")}}; for (json j: info.at("formats")) { Video::format form{j.at("format"), j.at("url"), j.at("vcodec"), j.at("acodec"), j.at("ext")}; if (j.contains("quality")) { form.quality = j.at("quality"); } if (j.contains("resolution")) { form.resolution = j.at("resolution"); } if (j.contains("width")) { form.width = j.at("width"); } if (j.contains("height")) { form.height = j.at("height"); } resp.formats.push_back(form); } for (json j: info.at("thumbnails")) { Video::thumbnail thumb{j.at("url"), j.at("preference"), j.at("id")}; if (j.contains("resolution")) { thumb.resolution = j.at("resolution"); } if (j.contains("height")) { thumb.height = j.at("height"); } if (j.contains("width")) { thumb.width = j.at("width"); } resp.thumbnails.push_back(thumb); } return resp; }