From 87c8a2986d468a3fc897169c1b00fc4695e09d39 Mon Sep 17 00:00:00 2001 From: dec05eba Date: Sun, 4 Sep 2022 05:01:36 +0200 Subject: Add dramacool --- src/plugins/DramaCool.cpp | 412 +++++++++++++++++++++++++++++++++++++++++++ src/plugins/HotExamples.cpp | 2 +- src/plugins/Lbry.cpp | 6 +- src/plugins/MangaGeneric.cpp | 2 +- src/plugins/Manganelo.cpp | 16 +- src/plugins/MediaGeneric.cpp | 6 +- src/plugins/MyAnimeList.cpp | 10 +- src/plugins/NyaaSi.cpp | 8 +- src/plugins/Peertube.cpp | 8 +- src/plugins/Saucenao.cpp | 4 +- src/plugins/Soundcloud.cpp | 8 +- src/plugins/Youtube.cpp | 6 +- 12 files changed, 447 insertions(+), 41 deletions(-) create mode 100644 src/plugins/DramaCool.cpp (limited to 'src/plugins') diff --git a/src/plugins/DramaCool.cpp b/src/plugins/DramaCool.cpp new file mode 100644 index 0000000..9b419f9 --- /dev/null +++ b/src/plugins/DramaCool.cpp @@ -0,0 +1,412 @@ +#include "../../plugins/DramaCool.hpp" +#include "../../include/Theme.hpp" +#include "../../include/StringUtils.hpp" +#include "../../include/M3U8.hpp" +#include +#include + +// TODO: Add bookmarks page, history, track watch progress, automatically go to next episode, subscribe, etc. + +namespace QuickMedia { + SearchResult DramaCoolSearchPage::search(const std::string &str, BodyItems &result_items) { + if(str.empty()) + return SearchResult::OK; + + std::vector additional_args = { + { "-H", "x-requested-with: XMLHttpRequest" } + }; + + Json::Value json_root; + DownloadResult result = download_json(json_root, "https://dramacool.cr/search?keyword=" + url_param_encode(str) + "&type=movies", std::move(additional_args), true); + if(result != DownloadResult::OK) return download_result_to_search_result(result); + + if(!json_root.isArray()) + return SearchResult::ERR; + + for(const Json::Value &json_item : json_root) { + if(!json_item.isObject()) + continue; + + const Json::Value &name_json = json_item["name"]; + const Json::Value &status_json = json_item["status"]; + const Json::Value &cover_url_json = json_item["cover"]; + const Json::Value &url_json = json_item["url"]; + + if(!name_json.isString() || !url_json.isString()) + continue; + + auto body_item = BodyItem::create(name_json.asString()); + if(status_json.isString()) { + body_item->set_description(status_json.asString()); + body_item->set_description_color(get_theme().faded_text_color); + } + if(cover_url_json.isString()) { + body_item->thumbnail_url = "https://imagecdn.me/" + url_param_encode(cover_url_json.asString()); + body_item->thumbnail_size = { 150, 225 }; + } + body_item->url = "https://dramacool.cr" + url_json.asString(); + + result_items.push_back(std::move(body_item)); + } + + return SearchResult::OK; + } + + static bool node_get_inner_text(const QuickMediaHtmlChildNode *node, QuickMediaStringView &str) { + if(!node || !node->node.is_tag || !node->node.first_child || node->node.first_child->node.is_tag) + return false; + + str = node->node.first_child->node.name; + return true; + } + + PluginResult DramaCoolSearchPage::submit(const SubmitArgs &args, std::vector &result_tabs) { + std::string website_data; + DownloadResult result = download_to_string(args.url, website_data, {}, true); + if(result != DownloadResult::OK) return download_result_to_plugin_result(result); + + BodyItems result_items; + + QuickMediaHtmlSearch html_search; + int res = quickmedia_html_search_init(&html_search, website_data.c_str(), website_data.size()); + if(res != 0) + return PluginResult::ERR; + + quickmedia_html_find_nodes_xpath(&html_search, "//div[class='content']//a", + [](QuickMediaMatchNode *node, void *userdata) { + auto *result_items = (BodyItems*)userdata; + QuickMediaStringView href = quickmedia_html_node_get_attribute_value(node->node, "href"); + if(!href.data || !memmem(href.data, href.size, ".html", 5)) + return 0; + + QuickMediaHtmlChildNode *sub_node = node->node->first_child; + if(!sub_node) + return 0; + + QuickMediaHtmlChildNode *title_node = sub_node->next; + if(!title_node) + return 0; + + QuickMediaHtmlChildNode *time_node = title_node->next; + if(!time_node) + return 0; + + QuickMediaStringView sub_str; + QuickMediaStringView title_str; + QuickMediaStringView time_str; + if(!node_get_inner_text(sub_node, sub_str) || !node_get_inner_text(title_node, title_str) || !node_get_inner_text(time_node, time_str)) + return 0; + + std::string title(title_str.data, title_str.size); + html_unescape_sequences(title); + + std::string time(time_str.data, time_str.size); + html_unescape_sequences(time); + + const bool is_subbed = sub_str.size == 3 && memcmp(sub_str.data, "SUB", 3) == 0; + + auto body_item = BodyItem::create(std::move(title)); + body_item->set_description((is_subbed ? "Subbed" : "Raw") + std::string(" • ") + time); + body_item->set_description_color(get_theme().faded_text_color); + body_item->url = "https://dramacool.cr" + std::string(href.data, href.size); + result_items->push_back(std::move(body_item)); + + return 0; + }, &result_items); + + quickmedia_html_search_deinit(&html_search); + + auto body = create_body(); + body->set_items(std::move(result_items)); + result_tabs.push_back(Tab{ std::move(body), std::make_unique(program), create_search_bar("Search...", SEARCH_DELAY_FILTER) }); + return PluginResult::OK; + } + + struct VideoSources { + //std::string streamsss; + std::string streamtape; + std::string mixdrop; + std::string mp4upload; + }; + + static bool dembed_extract_video_source(const std::string &website_data, const std::string &video_source_url, std::string &video_source) { + size_t st_start = website_data.find(video_source_url); + if(st_start == std::string::npos) + return false; + + st_start += video_source_url.size(); + size_t st_end = website_data.find("\"", st_start); + if(st_end == std::string::npos) + return false; + + video_source = "https://" + video_source_url + website_data.substr(st_start, st_end - st_start); + return true; + } + + static void dembed_extract_video_sources(const std::string &website_data, VideoSources &video_sources) { + //dembed_extract_video_source(website_data, "streamsss.net", video_sources.streamsss); + dembed_extract_video_source(website_data, "streamtape.com", video_sources.streamtape); + dembed_extract_video_source(website_data, "mixdrop.co", video_sources.mixdrop); + dembed_extract_video_source(website_data, "www.mp4upload.com", video_sources.mp4upload); + } + + // TODO: Re-add. It's broken right now (because of the json_url has incorrect value I guess) + /* + static bool streamsss_extract_video_url(Page *page, const std::string &streamsss_url, std::string &url) { + size_t url_end = streamsss_url.find("/e"); + if(url_end == std::string::npos) + return false; + + size_t id_start = streamsss_url.find("e/"); + if(id_start == std::string::npos) + return false; + + id_start += 2; + size_t id_end = streamsss_url.find("?", id_start); + if(id_end == std::string::npos) + id_end = streamsss_url.size(); + + const std::string url_base = streamsss_url.substr(0, url_end); + const std::string id = streamsss_url.substr(id_start, id_end - id_start); + + std::ostringstream id_hex; + id_hex << std::hex; + for(size_t i = 0; i < id.size(); ++i) + id_hex << (int)(unsigned char)id[i]; + + const std::string json_url = url_base + "/sources43/566d337678566f743674494a7c7c" + id_hex.str() + "7c7c346b6767586d6934774855537c7c73747265616d7362/6565417268755339773461447c7c346133383438333436313335376136323337373433383634376337633465366534393338373136643732373736343735373237613763376334363733353737303533366236333463353333363534366137633763373337343732363536313664373336327c7c6b586c3163614468645a47617c7c73747265616d7362"; + + Json::Value json_root; + DownloadResult result = page->download_json(json_root, json_url, {}, true); + if(result != DownloadResult::OK) + return false; + + if(!json_root.isObject()) + return false; + + const Json::Value &stream_data_json = json_root["stream_data"]; + if(!stream_data_json.isObject()) + return false; + + const Json::Value &file_json = stream_data_json["file"]; + if(!file_json.isString()) + return false; + + // TODO: Record resolution and duration + std::string website_data; + result = download_to_string(file_json.asString(), website_data, {}, true); + if(result != DownloadResult::OK) + return false; + + url = M3U8Stream::get_highest_resolution_stream(m3u8_get_streams(website_data)).url; + return true; + } + */ + static bool streamtape_extract_video_url(const std::string &website_data, std::string &url) { + size_t id_start = website_data.find("getElementById('robotlink')"); + if(id_start == std::string::npos) + return false; + + id_start += 27; + id_start = website_data.find("id=", id_start); + if(id_start == std::string::npos) + return false; + + id_start += 3; + size_t id_end = website_data.find("'", id_start); + if(id_end == std::string::npos) + return false; + + url = "https://streamtape.com/get_video?id=" + website_data.substr(id_start, id_end - id_start); + return true; + } + + static bool mixdrop_extract_mdcore_script(const std::string &website_data, const std::string &prefix, std::string &mdcore_script) { + size_t script_start = website_data.find(prefix); + if(script_start == std::string::npos) + return false; + + script_start += prefix.size(); + size_t script_end = website_data.find("\"", script_start); + if(script_end == std::string::npos) + return false; + + mdcore_script = website_data.substr(script_start, script_end - script_start); + return true; + } + + static bool mixdrop_extract_mdcore_parts(const std::string &website_data, std::vector &parts) { + size_t mdcore_start = website_data.find(",'|"); + if(mdcore_start == std::string::npos) { + mdcore_start = website_data.find("MDCore|"); + if(mdcore_start == std::string::npos) + return false; + } else { + mdcore_start += 2; + } + + size_t mdcore_end = website_data.find("'", mdcore_start); + if(mdcore_end == std::string::npos) + return false; + + std::string mdcore_str = website_data.substr(mdcore_start, mdcore_end - mdcore_start); + string_split(mdcore_str, '|', [&parts](const char *str, size_t size) { + parts.emplace_back(str, size); + return true; + }); + + return true; + } + + static int mdcore_number_get(char c) { + if(c >= '0' && c <= '9') + return c - '0'; + else if(c >= 'a' && c <= 'z') + return 10 + (c - 'a'); + else + return -1; + } + + static bool mixdrop_extract_video_url(const std::string &website_data, const std::string &prefix, std::string &url) { + std::string mdcore_script; + if(!mixdrop_extract_mdcore_script(website_data, prefix, mdcore_script)) + return false; + + std::vector mdcore_parts; + if(!mixdrop_extract_mdcore_parts(website_data, mdcore_parts)) + return false; + + for(size_t i = 0; i < mdcore_script.size();) { + char c = mdcore_script[i]; + int index = mdcore_number_get(c); + + if(index >= 0) { + ++i; + while(i < mdcore_script.size() && ((mdcore_script[i] >= '0' && mdcore_script[i] <= '9') || (mdcore_script[i] >= 'a' && mdcore_script[i] <= 'z'))) { + // 36 = 0-9 + a-z + index = (index * 36) + mdcore_number_get(mdcore_script[i]); + ++i; + } + } else { + url += c; + ++i; + continue; + } + + if(index >= (int)mdcore_parts.size() || mdcore_parts[index].empty()) + url += c; + else + url += mdcore_parts[index]; + } + + if(string_starts_with(url, "//")) + url = "http:" + url; + + return true; + } + + PluginResult DramaCoolEpisodesPage::submit(const SubmitArgs &args, std::vector &result_tabs) { + std::string website_data; + DownloadResult result = download_to_string(args.url, website_data, {}, true); + if(result != DownloadResult::OK) return download_result_to_plugin_result(result); + + std::string video_sources_url; + + QuickMediaHtmlSearch html_search; + int res = quickmedia_html_search_init(&html_search, website_data.c_str(), website_data.size()); + if(res != 0) + return PluginResult::ERR; + + quickmedia_html_find_nodes_xpath(&html_search, "//div", + [](QuickMediaMatchNode *node, void *userdata) { + auto *video_sources_url = (std::string*)userdata; + QuickMediaStringView klass = quickmedia_html_node_get_attribute_value(node->node, "class"); + if(!klass.data || !memmem(klass.data, klass.size, "watch_video", 11)) + return 0; + + QuickMediaHtmlChildNode *iframe_node = node->node->first_child; + if(!iframe_node || !iframe_node->node.is_tag || iframe_node->node.name.size != 6 || memcmp(iframe_node->node.name.data, "iframe", 6) != 0) + return 0; + + QuickMediaStringView src = quickmedia_html_node_get_attribute_value(&iframe_node->node, "src"); + if(!src.data) + return 0; + + video_sources_url->assign(src.data, src.size); + return 1; + }, &video_sources_url); + + quickmedia_html_search_deinit(&html_search); + + if(video_sources_url.empty()) + return PluginResult::ERR; + + if(string_starts_with(video_sources_url, "//")) + video_sources_url = "https:" + video_sources_url; + + result = download_to_string(video_sources_url, website_data, {}, true); + if(result != DownloadResult::OK) return download_result_to_plugin_result(result); + + // TODO: Extract all video sources and allow the user to select which one to use. + // Streamtape or mixdrop may not be available or if it's available it may not load properly + // or the quality may be worse or slower than other sources. + // We also want to load the high resolution version of the video. + // TODO: Make videos sources work even when captions are not embedded. + VideoSources video_sources; + dembed_extract_video_sources(website_data, video_sources); + + std::string video_url; + std::string referer; + + if(!video_sources.streamtape.empty() && video_url.empty()) { + result = download_to_string(video_sources.streamtape, website_data, {}, true); + if(result != DownloadResult::OK) return download_result_to_plugin_result(result); + streamtape_extract_video_url(website_data, video_url); + + if(!video_url.empty()) + referer = "https://streamtape.com"; + } + + if(!video_sources.mixdrop.empty() && video_url.empty()) { + result = download_to_string(video_sources.mixdrop, website_data, {}, true); + if(result != DownloadResult::OK) return download_result_to_plugin_result(result); + mixdrop_extract_video_url(website_data, "0.f=\"", video_url); + + if(!video_url.empty()) + referer = "https://mixdrop.co"; + } + + if(!video_sources.mp4upload.empty() && video_url.empty()) { + result = download_to_string(video_sources.mp4upload, website_data, {}, true); + if(result != DownloadResult::OK) return download_result_to_plugin_result(result); + // mp4upload uses the same algorithm as mixdrop but with different format + mixdrop_extract_video_url(website_data, "2.25(\"", video_url); + + if(!video_url.empty()) + referer = "https://www.mp4upload.com"; + } + + if(video_url.empty()) + return PluginResult::ERR; + + /* + if(!video_sources.streamsss.empty() && video_url.empty()) { + streamsss_extract_video_url(this, video_sources.streamsss, video_url); + } + */ + + result_tabs.push_back(Tab{ nullptr, std::make_unique(program, std::move(video_url), args.title, std::move(referer)), nullptr }); + + return PluginResult::OK; + } + + PluginResult DramaCoolVideoPage::load(const SubmitArgs&, VideoInfo &video_info, std::string &err_str) { + video_info.title = title; + video_info.channel_url.clear(); + video_info.duration = 0.0; + video_info.chapters.clear(); + video_info.referer = referer; + err_str.clear(); + return PluginResult::OK; + } +} \ No newline at end of file diff --git a/src/plugins/HotExamples.cpp b/src/plugins/HotExamples.cpp index fbefad5..7cb811b 100644 --- a/src/plugins/HotExamples.cpp +++ b/src/plugins/HotExamples.cpp @@ -44,7 +44,7 @@ namespace QuickMedia { quickmedia_html_find_nodes_xpath(&html_search, "//div[class='search-result row']//div[class='header']//a", [](QuickMediaMatchNode *node, void *userdata) { auto *item_data = (BodyItems*)userdata; - QuickMediaStringView href = quickmedia_html_node_get_attribute_value(node, "href"); + QuickMediaStringView href = quickmedia_html_node_get_attribute_value(node->node, "href"); if(href.data && memmem(href.data, href.size, "/examples/", 10)) { QuickMediaStringView text = quickmedia_html_node_get_text(node); if(text.data) { diff --git a/src/plugins/Lbry.cpp b/src/plugins/Lbry.cpp index 069bd89..6be0148 100644 --- a/src/plugins/Lbry.cpp +++ b/src/plugins/Lbry.cpp @@ -395,11 +395,11 @@ namespace QuickMedia { return ""; } - PluginResult LbryVideoPage::load(const SubmitArgs &args, std::string &title, std::string&, double &duration, std::vector&, std::string &err_str) { + PluginResult LbryVideoPage::load(const SubmitArgs &args, VideoInfo &video_info, std::string &err_str) { streaming_url.clear(); - title = args.title; + video_info.title = args.title; //title = this->title; - duration = 0.0; + video_info.duration = 0.0; return video_get_stream_url(this, url, streaming_url, err_str); } } \ No newline at end of file diff --git a/src/plugins/MangaGeneric.cpp b/src/plugins/MangaGeneric.cpp index 767f077..2c77773 100644 --- a/src/plugins/MangaGeneric.cpp +++ b/src/plugins/MangaGeneric.cpp @@ -52,7 +52,7 @@ namespace QuickMedia { if(strcmp(field_name, "text") == 0) return quickmedia_html_node_get_text(node); else - return quickmedia_html_node_get_attribute_value(node, field_name); + return quickmedia_html_node_get_attribute_value(node->node, field_name); } static void body_items_prepend_website_url(BodyItems &body_items, const std::string &website_url) { diff --git a/src/plugins/Manganelo.cpp b/src/plugins/Manganelo.cpp index 5a75d5d..ef7f52c 100644 --- a/src/plugins/Manganelo.cpp +++ b/src/plugins/Manganelo.cpp @@ -106,7 +106,7 @@ namespace QuickMedia { result = quickmedia_html_find_nodes_xpath(&html_search, "//ul[class='row-content-chapter']//a", [](QuickMediaMatchNode *node, void *userdata) { auto *item_data = (BodyItems*)userdata; - QuickMediaStringView href = quickmedia_html_node_get_attribute_value(node, "href"); + QuickMediaStringView href = quickmedia_html_node_get_attribute_value(node->node, "href"); QuickMediaStringView text = quickmedia_html_node_get_text(node); if(href.data && text.data) { auto item = BodyItem::create(std::string(text.data, text.size)); @@ -119,7 +119,7 @@ namespace QuickMedia { result = quickmedia_html_find_nodes_xpath(&html_search, "//div[class='chapter-list']//a", [](QuickMediaMatchNode *node, void *userdata) { auto *item_data = (BodyItems*)userdata; - QuickMediaStringView href = quickmedia_html_node_get_attribute_value(node, "href"); + QuickMediaStringView href = quickmedia_html_node_get_attribute_value(node->node, "href"); QuickMediaStringView text = quickmedia_html_node_get_text(node); if(href.data && text.data) { auto item = BodyItem::create(std::string(text.data, text.size)); @@ -136,7 +136,7 @@ namespace QuickMedia { quickmedia_html_find_nodes_xpath(&html_search, "//ul[class='row-content-chapter']//span", [](QuickMediaMatchNode *node, void *userdata) { auto *item_data = (BodyItemContext*)userdata; - QuickMediaStringView class_attr = quickmedia_html_node_get_attribute_value(node, "class"); + QuickMediaStringView class_attr = quickmedia_html_node_get_attribute_value(node->node, "class"); QuickMediaStringView text = quickmedia_html_node_get_text(node); if(text.data && class_attr.data && string_view_contains(class_attr, "chapter-time") && item_data->index < item_data->body_items->size()) { std::string uploaded_date(text.data, text.size); @@ -150,7 +150,7 @@ namespace QuickMedia { quickmedia_html_find_nodes_xpath(&html_search, "//a[class='a-h']", [](QuickMediaMatchNode *node, void *userdata) { std::vector *creators = (std::vector*)userdata; - QuickMediaStringView href = quickmedia_html_node_get_attribute_value(node, "href"); + QuickMediaStringView href = quickmedia_html_node_get_attribute_value(node->node, "href"); QuickMediaStringView text = quickmedia_html_node_get_text(node); if(href.data && text.data && string_view_contains(href, "/author/story/")) { Creator creator; @@ -281,8 +281,8 @@ namespace QuickMedia { result = quickmedia_html_find_nodes_xpath(&html_search, "//div[class='search-story-item']//a[class='item-img']", [](QuickMediaMatchNode *node, void *userdata) { auto *item_data = (BodyItems*)userdata; - QuickMediaStringView href = quickmedia_html_node_get_attribute_value(node, "href"); - QuickMediaStringView title = quickmedia_html_node_get_attribute_value(node, "title"); + QuickMediaStringView href = quickmedia_html_node_get_attribute_value(node->node, "href"); + QuickMediaStringView title = quickmedia_html_node_get_attribute_value(node->node, "title"); if(href.data && title.data && string_view_contains(href, "/manga/")) { auto body_item = BodyItem::create(std::string(title.data, title.size)); body_item->url.assign(href.data, href.size); @@ -301,7 +301,7 @@ namespace QuickMedia { result = quickmedia_html_find_nodes_xpath(&html_search, "//div[class='search-story-item']//a[class='item-img']//img", [](QuickMediaMatchNode *node, void *userdata) { auto *item_data = (BodyItemContext*)userdata; - QuickMediaStringView src = quickmedia_html_node_get_attribute_value(node, "src"); + QuickMediaStringView src = quickmedia_html_node_get_attribute_value(node->node, "src"); if(src.data && item_data->index < item_data->body_items->size()) { (*item_data->body_items)[item_data->index]->thumbnail_url.assign(src.data, src.size); (*item_data->body_items)[item_data->index]->thumbnail_size = {101, 141}; @@ -334,7 +334,7 @@ namespace QuickMedia { result = quickmedia_html_find_nodes_xpath(&html_search, "//div[class='container-chapter-reader']/img", [](QuickMediaMatchNode *node, void *userdata) { auto *urls = (std::vector*)userdata; - QuickMediaStringView src = quickmedia_html_node_get_attribute_value(node, "src"); + QuickMediaStringView src = quickmedia_html_node_get_attribute_value(node->node, "src"); if(src.data) { std::string image_url(src.data, src.size); urls->push_back(std::move(image_url)); diff --git a/src/plugins/MediaGeneric.cpp b/src/plugins/MediaGeneric.cpp index 4ff55da..cc869ef 100644 --- a/src/plugins/MediaGeneric.cpp +++ b/src/plugins/MediaGeneric.cpp @@ -20,7 +20,7 @@ namespace QuickMedia { if(strcmp(field_name, "text") == 0) return quickmedia_html_node_get_text(node); else - return quickmedia_html_node_get_attribute_value(node, field_name); + return quickmedia_html_node_get_attribute_value(node->node, field_name); } static void body_items_prepend_website_url(BodyItems &body_items, const std::string &website_url) { @@ -224,9 +224,9 @@ namespace QuickMedia { return video_url; } - PluginResult MediaGenericVideoPage::load(const SubmitArgs&, std::string&, std::string&, double &duration, std::vector&, std::string &err_msg) { + PluginResult MediaGenericVideoPage::load(const SubmitArgs&, VideoInfo &video_info, std::string &err_msg) { video_url.clear(); - duration = 0.0; + video_info.duration = 0.0; if(!search_page->video_custom_handler) { video_url = url; return PluginResult::OK; diff --git a/src/plugins/MyAnimeList.cpp b/src/plugins/MyAnimeList.cpp index b982e3c..aa72750 100644 --- a/src/plugins/MyAnimeList.cpp +++ b/src/plugins/MyAnimeList.cpp @@ -179,7 +179,7 @@ namespace QuickMedia { quickmedia_html_find_nodes_xpath(&html_search, "//img[itemprop='image']", [](QuickMediaMatchNode *node, void *userdata) { std::string *thumbnail_url = (std::string*)userdata; - QuickMediaStringView data_src = quickmedia_html_node_get_attribute_value(node, "data-src"); + QuickMediaStringView data_src = quickmedia_html_node_get_attribute_value(node->node, "data-src"); if(data_src.data) { thumbnail_url->assign(data_src.data, data_src.size); html_unescape_sequences(*thumbnail_url); @@ -223,12 +223,6 @@ namespace QuickMedia { return alt.substr(index + 2); } - static QuickMediaStringView quickmedia_html_node_get_attribute_value(QuickMediaHtmlNode *node, const char *attribute_name) { - QuickMediaMatchNode match_node; - match_node.node = node; - return quickmedia_html_node_get_attribute_value(&match_node, attribute_name); - } - PluginResult MyAnimeListRecommendationsPage::lazy_fetch(BodyItems &result_items) { std::string website_data; DownloadResult download_result = download_to_string(url + "/userrecs", website_data, {}, true); @@ -242,7 +236,7 @@ namespace QuickMedia { quickmedia_html_find_nodes_xpath(&html_search, "//div[class='picSurround']/a", [](QuickMediaMatchNode *node, void *userdata) { BodyItems *result_items = (BodyItems*)userdata; - QuickMediaStringView href = quickmedia_html_node_get_attribute_value(node, "href"); + QuickMediaStringView href = quickmedia_html_node_get_attribute_value(node->node, "href"); if(!href.data) return 0; diff --git a/src/plugins/NyaaSi.cpp b/src/plugins/NyaaSi.cpp index fd24e71..b56ef69 100644 --- a/src/plugins/NyaaSi.cpp +++ b/src/plugins/NyaaSi.cpp @@ -367,7 +367,7 @@ namespace QuickMedia { result = quickmedia_html_find_nodes_xpath(&html_search, "//div[class='panel-body']//div[class='row']//a", [](QuickMediaMatchNode *node, void *userdata) { ResultItemExtra *item_data = (ResultItemExtra*)userdata; - QuickMediaStringView href = quickmedia_html_node_get_attribute_value(node, "href"); + QuickMediaStringView href = quickmedia_html_node_get_attribute_value(node->node, "href"); QuickMediaStringView text = quickmedia_html_node_get_text(node); if(item_data->result_items->empty() && href.data && text.data && href.size >= 6 && memcmp(href.data, "/user/", 6) == 0) { auto body_item = BodyItem::create(""); @@ -410,7 +410,7 @@ namespace QuickMedia { result = quickmedia_html_find_nodes_xpath(&html_search, "//div[class='container']//a", [](QuickMediaMatchNode *node, void *userdata) { std::string *magnet_url = (std::string*)userdata; - QuickMediaStringView href = quickmedia_html_node_get_attribute_value(node, "href"); + QuickMediaStringView href = quickmedia_html_node_get_attribute_value(node->node, "href"); if(magnet_url->empty() && href.data && href.size >= 8 && memcmp(href.data, "magnet:?", 8) == 0) { magnet_url->assign(href.data, href.size); } @@ -434,7 +434,7 @@ namespace QuickMedia { result = quickmedia_html_find_nodes_xpath(&html_search, "//div[id='comments']//a", [](QuickMediaMatchNode *node, void *userdata) { auto *item_data = (BodyItems*)userdata; - QuickMediaStringView href = quickmedia_html_node_get_attribute_value(node, "href"); + QuickMediaStringView href = quickmedia_html_node_get_attribute_value(node->node, "href"); QuickMediaStringView text = quickmedia_html_node_get_text(node); if(href.data && text.data && href.size >= 6 && memcmp(href.data, "/user/", 6) == 0) { auto body_item = BodyItem::create(std::string(text.data, text.size)); @@ -454,7 +454,7 @@ namespace QuickMedia { result = quickmedia_html_find_nodes_xpath(&html_search, "//div[id='comments']//img[class='avatar']", [](QuickMediaMatchNode *node, void *userdata) { auto *item_data = (BodyItemContext*)userdata; - QuickMediaStringView src = quickmedia_html_node_get_attribute_value(node, "src"); + QuickMediaStringView src = quickmedia_html_node_get_attribute_value(node->node, "src"); if(src.data && item_data->index < item_data->body_items->size()) { (*item_data->body_items)[item_data->index]->thumbnail_url.assign(src.data, src.size); (*item_data->body_items)[item_data->index]->thumbnail_size = mgl::vec2i(120, 120); diff --git a/src/plugins/Peertube.cpp b/src/plugins/Peertube.cpp index 4e19f1a..4fb2ac4 100644 --- a/src/plugins/Peertube.cpp +++ b/src/plugins/Peertube.cpp @@ -370,7 +370,7 @@ namespace QuickMedia { } // TODO: Media chapters - PluginResult PeertubeVideoPage::load(const SubmitArgs&, std::string &title, std::string &channel_url, double &duration, std::vector&, std::string &err_str) { + PluginResult PeertubeVideoPage::load(const SubmitArgs&, VideoInfo &video_info, std::string &err_str) { Json::Value json_root; std::string err_msg; DownloadResult download_result = download_json(json_root, server + "/api/v1/videos/" + url, {}, true, &err_msg); @@ -384,17 +384,17 @@ namespace QuickMedia { const Json::Value &name_json = json_root["name"]; if(name_json.isString()) - title = name_json.asString(); + video_info.title = name_json.asString(); const Json::Value &duration_json = json_root["duration"]; if(duration_json.isInt64()) - duration = duration_json.asInt64(); + video_info.duration = duration_json.asInt64(); const Json::Value &channel_json = json_root["channel"]; if(channel_json.isObject()) { const Json::Value &channel_url_json = channel_json["url"]; if(channel_url_json.isString()) - channel_url = channel_url_json.asString(); + video_info.channel_url = channel_url_json.asString(); } video_sources.clear(); diff --git a/src/plugins/Saucenao.cpp b/src/plugins/Saucenao.cpp index 6833bea..ac2b622 100644 --- a/src/plugins/Saucenao.cpp +++ b/src/plugins/Saucenao.cpp @@ -131,8 +131,8 @@ namespace QuickMedia { quickmedia_html_find_nodes_xpath(&html_search, "//td[class='resulttableimage']//img", [](QuickMediaMatchNode *node, void *userdata) { BodyItemContext *item_data = (BodyItemContext*)userdata; - QuickMediaStringView src = quickmedia_html_node_get_attribute_value(node, "src"); - QuickMediaStringView data_src = quickmedia_html_node_get_attribute_value(node, "data-src"); + QuickMediaStringView src = quickmedia_html_node_get_attribute_value(node->node, "src"); + QuickMediaStringView data_src = quickmedia_html_node_get_attribute_value(node->node, "data-src"); QuickMediaStringView image_url = data_src.data ? data_src : src; if(image_url.data && item_data->index < item_data->body_items->size()) { (*item_data->body_items)[item_data->index]->thumbnail_url.assign(image_url.data, image_url.size); diff --git a/src/plugins/Soundcloud.cpp b/src/plugins/Soundcloud.cpp index bc89448..0d4d8e1 100644 --- a/src/plugins/Soundcloud.cpp +++ b/src/plugins/Soundcloud.cpp @@ -361,7 +361,7 @@ namespace QuickMedia { result = quickmedia_html_find_nodes_xpath(&html_search, "//script", [](QuickMediaMatchNode *node, void *userdata) { std::vector *script_sources = (std::vector*)userdata; - QuickMediaStringView src = quickmedia_html_node_get_attribute_value(node, "src"); + QuickMediaStringView src = quickmedia_html_node_get_attribute_value(node->node, "src"); if(src.data && (memmem(src.data, src.size, "sndcdn.com", 10) || memmem(src.data, src.size, "soundcloud.com", 14))) script_sources->push_back(std::string(src.data, src.size)); return 0; @@ -477,14 +477,14 @@ namespace QuickMedia { return PluginResult::OK; } - PluginResult SoundcloudAudioPage::load(const SubmitArgs &args, std::string &title, std::string&, double &duration, std::vector&, std::string&) { + PluginResult SoundcloudAudioPage::load(const SubmitArgs &args, VideoInfo &video_info, std::string&) { SoundcloudTrack *track = static_cast(args.extra.get()); if(track) permalink_url = track->permalink_url; - title = args.title; + video_info.title = args.title; //title = this->title; - duration = 0.0; + video_info.duration = 0.0; return PluginResult::OK; } diff --git a/src/plugins/Youtube.cpp b/src/plugins/Youtube.cpp index a0c15de..93cb266 100644 --- a/src/plugins/Youtube.cpp +++ b/src/plugins/Youtube.cpp @@ -2423,7 +2423,7 @@ namespace QuickMedia { return PluginResult::OK; } - PluginResult YoutubeVideoPage::load(const SubmitArgs&, std::string &title, std::string &channel_url, double &duration, std::vector &chapters, std::string &err_str) { + PluginResult YoutubeVideoPage::load(const SubmitArgs&, VideoInfo &video_info, std::string &err_str) { std::string video_id; if(!youtube_url_extract_id(url, video_id)) { fprintf(stderr, "Failed to extract youtube id from %s\n", url.c_str()); @@ -2530,10 +2530,10 @@ R"END( if(download_result != DownloadResult::OK) continue; - PluginResult result = parse_video_response(json_root, title, channel_url, chapters, err_str); + PluginResult result = parse_video_response(json_root, video_info.title, video_info.channel_url, video_info.chapters, err_str); if(result == PluginResult::OK) { err_str.clear(); - duration = video_details.duration; + video_info.duration = video_details.duration; return PluginResult::OK; } } -- cgit v1.2.3