diff --git a/README.md b/README.md index 1973c6b..c7f93c9 100644 --- a/README.md +++ b/README.md @@ -20,6 +20,9 @@ restclient: https://github.com/mrtazz/restclient-cpp libjpeg-turbo: https://libjpeg-turbo.org/ sqlite: https://www.sqlite.org/index.html ## 更新记录 +### 2024年2月25日 -- 1.6.0 ++ 1.更新B站登录API,解决无法登录的问题。 ++ 2.更新B站用户信息API,解决登陆后请求用户信息失败的问题。 ### 2022年11月6日 -- 1.5.0 + 1.引入开源库sqlite3、turbojpeg。 + 2.支持写入mp3封面图片。 diff --git a/include/utils/string_utils.h b/include/utils/string_utils.h index 9b78da0..6ac9b33 100644 --- a/include/utils/string_utils.h +++ b/include/utils/string_utils.h @@ -3,6 +3,8 @@ #include #include #include +#include + using std::string; using std::wstring; using std::vector; @@ -53,6 +55,8 @@ namespace string_utils { std::string GetFileExtentionNameByUrl(const std::string& url); + std::map CommandLineToArgMap(const wchar_t* command); + // ȥWindowsļַܰ\/:*?"<>| template T TrimFileName(T ch) diff --git a/src/BVLoader/BVLoader.rc b/src/BVLoader/BVLoader.rc index 8a3140c..993a87c 100644 Binary files a/src/BVLoader/BVLoader.rc and b/src/BVLoader/BVLoader.rc differ diff --git a/src/BVLoader/BVLoader.vcxproj b/src/BVLoader/BVLoader.vcxproj index 96097b3..3b06d53 100644 --- a/src/BVLoader/BVLoader.vcxproj +++ b/src/BVLoader/BVLoader.vcxproj @@ -23,20 +23,20 @@ Win32Proj {8f011e58-ee97-4a49-95b6-f6a33d4759c0} BVLoader - 10.0 + 10.0.17763.0 BVLoader Application true - v142 + v143 Unicode Application false - v142 + v141 true Unicode diff --git a/src/BVLoader/define/api_define.h b/src/BVLoader/define/api_define.h index c204d18..a6f9161 100644 --- a/src/BVLoader/define/api_define.h +++ b/src/BVLoader/define/api_define.h @@ -5,8 +5,12 @@ constexpr const char* kUgcDetailApi = "https://api.bilibili.com/x/web-interface/ // UGCƵҳѯӿ constexpr const char* kUgcPlayerApi = "https://api.bilibili.com/x/player/playurl?avid=%I64d&cid=%I64d&qn=%d&fourk=1"; // ά -static constexpr const char* kRequestLoginUrl = "https://passport.bilibili.com/qrcode/getLoginUrl"; +// static constexpr const char* kRequestLoginUrl = "https://passport.bilibili.com/qrcode/getLoginUrl"; +// °汾 +static constexpr const char* kRequestLoginUrl = "https://passport.bilibili.com/x/passport-login/web/qrcode/generate?source=main-fe-header"; // ¼ -static constexpr const char* kRequestLoginInfo = "https://passport.bilibili.com/qrcode/getLoginInfo"; +// static constexpr const char* kRequestLoginInfo = "https://passport.bilibili.com/qrcode/getLoginInfo"; +// °汾 +static constexpr const char* kRequestLoginInfo = "https://passport.bilibili.com/x/passport-login/web/qrcode/poll?qrcode_key="; // ȡûϢ -static constexpr const char* kRequestUserInfo = "https://api.bilibili.com/nav"; \ No newline at end of file +static constexpr const char* kRequestUserInfo = "https://api.bilibili.com/x/web-interface/nav"; \ No newline at end of file diff --git a/src/BVLoader/define/message_define.h b/src/BVLoader/define/message_define.h index b76a55a..6ad801e 100644 --- a/src/BVLoader/define/message_define.h +++ b/src/BVLoader/define/message_define.h @@ -40,6 +40,9 @@ enum ShowwndWparam { enum { WM_QRCODEWND_ASYNC_SUCCESS = kBaseWindowMessage + 1, WM_QRCODEWND_ASYNC_ERROR, + + WM_QRCODEWND_GET_QRCODE, + WM_QRCODEWND_GET_LOGIN_RESULT, }; // qrcode window timer diff --git a/src/BVLoader/define/soft_define.h b/src/BVLoader/define/soft_define.h index 3e990c1..8d0be3d 100644 --- a/src/BVLoader/define/soft_define.h +++ b/src/BVLoader/define/soft_define.h @@ -23,6 +23,7 @@ static constexpr const char* kAppNameAscii = "DownloadTools"; // qrcode login static constexpr const wchar_t* kTextQrcodeExpired = L"άѹ"; static constexpr const wchar_t* kTextQrcodeRequestFailed = L"άʧ"; +static constexpr const wchar_t* kTextQrcodeResultParseFailed = L"άɨʧ"; static constexpr const wchar_t* kTextQrcodeConfirmed = L"ɨɹֻȷ"; static constexpr const wchar_t* kDefaultCover = L"cover.png"; \ No newline at end of file diff --git a/src/BVLoader/main.cpp b/src/BVLoader/main.cpp index a9503c3..262f4dc 100644 --- a/src/BVLoader/main.cpp +++ b/src/BVLoader/main.cpp @@ -23,6 +23,7 @@ int APIENTRY wWinMain(_In_ HINSTANCE hInstance, LOG(INFO) << "Process is already running, exit"; return 0; } + CPaintManagerUI::SetInstance(hInstance); #ifdef _DEBUG CDuiString wstrResoucePath = CPaintManagerUI::GetInstancePath(); diff --git a/src/BVLoader/service/async/async_service.cpp b/src/BVLoader/service/async/async_service.cpp index 8f9c607..f48e492 100644 --- a/src/BVLoader/service/async/async_service.cpp +++ b/src/BVLoader/service/async/async_service.cpp @@ -261,9 +261,12 @@ void AsyncService::OnGetLoginUrl(const std::shared_ptr& task) return; } // ݽ - bool result = ParseLoginUrl(task, response); - if (!result && !IsDelegateEmpty()) { - NotifyDelegate(task->task_type, AsyncErrorCode::ERROR_PARSE_RESPONSE, nullptr); + QrcodeUrlInfo* info = new QrcodeUrlInfo(); + bool result = ParseLoginUrl(task, response, info); + // ϣص֪ͨ + if (!IsDelegateEmpty()) { + auto code = result ? AsyncErrorCode::ERROR_SUCCESS : AsyncErrorCode::ERROR_PARSE_RESPONSE; + NotifyDelegate(task->task_type, code, info); } } @@ -276,9 +279,9 @@ void AsyncService::OnGetLoginInfo(const std::shared_ptr& task) } RestClient::Connection http; InitHttp(http); - std_str param("oauthKey="); - param += login_task->auth_key; - auto response = http.post(login_task->url, param); + std::string url = login_task->url + + login_task->auth_key + "&source=main-fe-header"; + auto response = http.get(url); if (response.curl_code != CURLE_OK) { LOG(ERROR) << "DoHttpRequest network error, code: " << response.curl_code; if (!IsDelegateEmpty()) { @@ -287,9 +290,12 @@ void AsyncService::OnGetLoginInfo(const std::shared_ptr& task) return; } // ݽ - bool result = ParseLoginInfo(task, response.body); - if (!result && !IsDelegateEmpty()) { - NotifyDelegate(login_task->task_type, AsyncErrorCode::ERROR_PARSE_RESPONSE, nullptr); + QrcodeLoginInfo* info = new QrcodeLoginInfo(); + bool result = ParseLoginInfo(task, response.body, info); + // ϣص֪ͨ + if (!IsDelegateEmpty()) { + auto code = result ? AsyncErrorCode::ERROR_SUCCESS : AsyncErrorCode::ERROR_PARSE_RESPONSE; + NotifyDelegate(task->task_type, code, info); } } @@ -430,9 +436,11 @@ bool AsyncService::ParseUgcPlayerUrl(const std::shared_ptr& task, st return false; } -bool AsyncService::ParseLoginUrl(const std::shared_ptr& task, std_cstr_ref response) +bool AsyncService::ParseLoginUrl(const std::shared_ptr& task, std_cstr_ref response, QrcodeUrlInfo* info) { + // {"code":0,"message":"0","ttl":1,"data":{"url":"https://passport.bilibili.com/h5-app/passport/login/scan?navhide=1\u0026qrcode_key=8a7373d74db2c69108e6de6fc5bdf491\u0026from=main-fe-header","qrcode_key":"8a7373d74db2c69108e6de6fc5bdf491"}} try { + assert(info); Json::Value root; Json::CharReaderBuilder builder; std::shared_ptr rd(builder.newCharReader()); @@ -447,13 +455,9 @@ bool AsyncService::ParseLoginUrl(const std::shared_ptr& task, std_cs return false; } auto& data = root[kHttpResponseData]; - auto url = data["url"].asString(); - auto auth_key = data["oauthKey"].asString(); - // ϣص֪ͨ - if (!IsDelegateEmpty()) { - QrcodeUrlInfo* userData = new QrcodeUrlInfo(std::move(url), std::move(auth_key)); - NotifyDelegate(task->task_type, AsyncErrorCode::ERROR_SUCCESS, userData); - } + info->url = data["url"].asString(); + info->auth_key = data["qrcode_key"].asString(); + return true; } catch (...) { LOG(ERROR) << "ParseLoginUrl parse json failed"; @@ -461,9 +465,14 @@ bool AsyncService::ParseLoginUrl(const std::shared_ptr& task, std_cs return false; } -bool AsyncService::ParseLoginInfo(const std::shared_ptr& task, std_cstr_ref response) +bool AsyncService::ParseLoginInfo(const std::shared_ptr& task, std_cstr_ref response, + QrcodeLoginInfo* info) { try { + assert(info); + // {"code":20000,"message":"ð汾Ѳֵ֧ǰܣ°汾"} + // {"code":0,"message":"0","ttl":1,"data":{"url":"","refresh_token":"","timestamp":0,"code":86038,"message":"άʧЧ"}} + Json::Value root; Json::CharReaderBuilder builder; std::shared_ptr rd(builder.newCharReader()); @@ -473,15 +482,19 @@ bool AsyncService::ParseLoginInfo(const std::shared_ptr& task, std_c return false; } auto& data = root[kHttpResponseData]; - int code = 0; - std_str url; - std_str cookie; - if (data.isInt()) { - code = data.asInt(); + if (!data.isObject()) { + LOG(ERROR) << "ӿڷݳ" << string_utils::Utf8ToA(response); + return false; } - else { - // ½ɹûϢ - url = data["url"].asString(); + + info->url = data["url"].asString(); + info->code = data["code"].asInt(); + info->msg = data["message"].asString(); + + std_str url; + // ½ɹûϢ + url = data["url"].asString(); + if (!url.empty()) { size_t pos = url.find('?'); if (pos != std::string::npos) { url = url.substr(pos + 1); @@ -490,17 +503,12 @@ bool AsyncService::ParseLoginInfo(const std::shared_ptr& task, std_c string_utils::SplitStringA(url, "&", param_list); size_t count = param_list.size(); for (size_t i = 0; i < count; ++i) { - cookie += param_list[i]; + info->cookie += param_list[i]; if (i != count - 1) { - cookie.append("; "); + info->cookie.append("; "); } } } - // ϣص֪ͨ - if (!IsDelegateEmpty()) { - QrcodeLoginInfo* login_info = new QrcodeLoginInfo(code, std::move(url), std::move(cookie)); - NotifyDelegate(task->task_type, AsyncErrorCode::ERROR_SUCCESS, login_info); - } return true; } catch (...) { diff --git a/src/BVLoader/service/async/async_service.h b/src/BVLoader/service/async/async_service.h index a100d8b..dbe2100 100644 --- a/src/BVLoader/service/async/async_service.h +++ b/src/BVLoader/service/async/async_service.h @@ -47,8 +47,10 @@ class AsyncService // ݽ bool ParseUgcInfo(const std::shared_ptr& task, std_cstr_ref response); bool ParseUgcPlayerUrl(const std::shared_ptr& task, std_cstr_ref response); - bool ParseLoginUrl(const std::shared_ptr& task, std_cstr_ref response); - bool ParseLoginInfo(const std::shared_ptr& task, std_cstr_ref response); + bool ParseLoginUrl(const std::shared_ptr& task, std_cstr_ref response, + QrcodeUrlInfo* info); + bool ParseLoginInfo(const std::shared_ptr& task, std_cstr_ref response, + QrcodeLoginInfo* info); bool ParseUserInfo(const std::shared_ptr& task, std_cstr_ref response); void NotifyDelegate(AsyncTaskType task_type, AsyncErrorCode code, void* data); diff --git a/src/BVLoader/service/async/async_service_define.h b/src/BVLoader/service/async/async_service_define.h index cc22740..2b3282c 100644 --- a/src/BVLoader/service/async/async_service_define.h +++ b/src/BVLoader/service/async/async_service_define.h @@ -85,6 +85,8 @@ class PlayerInfo { // ¼άurlϢ class QrcodeUrlInfo { public: + QrcodeUrlInfo() = default; + QrcodeUrlInfo(std_str_r_ref _url, std_str_r_ref _key) : url(std::move(_url)) , auth_key(std::move(_key)) { @@ -97,6 +99,8 @@ class QrcodeUrlInfo { // ¼״̬Ϣ class QrcodeLoginInfo { public: + QrcodeLoginInfo() = default; + QrcodeLoginInfo(int _code, std_str_r_ref _url, std_str_r_ref _cookie) : code(_code) , url(std::move(_url)) @@ -106,6 +110,7 @@ class QrcodeLoginInfo { int code = 0; std_str url; std_str cookie; + std_str msg; }; // ûϢ diff --git a/src/BVLoader/wnd/wnd_login.cpp b/src/BVLoader/wnd/wnd_login.cpp index 89645ca..a3d5edf 100644 --- a/src/BVLoader/wnd/wnd_login.cpp +++ b/src/BVLoader/wnd/wnd_login.cpp @@ -61,6 +61,10 @@ LRESULT WndLogin::HandleMessage(UINT uMsg, WPARAM wParam, LPARAM lParam) return OnMsgAsyncSuccess(wParam, lParam); case WM_QRCODEWND_ASYNC_ERROR: return OnMsgAsyncError(wParam, lParam); + case WM_QRCODEWND_GET_QRCODE: + return OnMsgGetQrcode(wParam, lParam); + case WM_QRCODEWND_GET_LOGIN_RESULT: + return OnMsgGetLoginResult(wParam, lParam); default: break; } @@ -104,12 +108,26 @@ void WndLogin::RefreshQrcode() void WndLogin::OnAsyncComplete(AsyncTaskType task_type, AsyncErrorCode code, void* data, void* param) { - if (task_type == AsyncTaskType::TASK_GET_LOGIN_URL - || task_type == AsyncTaskType::TASK_GET_LOGIN_INFO) { - // UI߳ת - UINT msg = (code == AsyncErrorCode::ERROR_SUCCESS) ? WM_QRCODEWND_ASYNC_SUCCESS : WM_QRCODEWND_ASYNC_ERROR; - ::PostMessage(m_hWnd, msg, (WPARAM)task_type, (LPARAM)data); + // UI߳ת + switch (task_type) { + case AsyncTaskType::TASK_GET_LOGIN_URL: { + ::PostMessage(m_hWnd, WM_QRCODEWND_GET_QRCODE, (WPARAM)code, (LPARAM)data); + break; + } + case AsyncTaskType::TASK_GET_LOGIN_INFO: { + ::PostMessage(m_hWnd, WM_QRCODEWND_GET_LOGIN_RESULT, (WPARAM)code, (LPARAM)data); + break; + } + default: + break; } + + //if (task_type == AsyncTaskType::TASK_GET_LOGIN_URL + // || task_type == AsyncTaskType::TASK_GET_LOGIN_INFO) { + // // UI߳ת + // UINT msg = (code == AsyncErrorCode::ERROR_SUCCESS) ? WM_QRCODEWND_ASYNC_SUCCESS : WM_QRCODEWND_ASYNC_ERROR; + // ::PostMessage(m_hWnd, msg, (WPARAM)task_type, (LPARAM)data); + //} } LRESULT WndLogin::OnMsgAsyncSuccess(WPARAM wParam, LPARAM lParam) @@ -181,3 +199,61 @@ LRESULT WndLogin::OnMsgAsyncError(WPARAM wParam, LPARAM lParam) } return 0; } + +LRESULT WndLogin::OnMsgGetQrcode(WPARAM wParam, LPARAM lParam) +{ + AsyncErrorCode code = (AsyncErrorCode)wParam; + auto info = reinterpret_cast(lParam); + assert(info); + std::unique_ptr auto_ptr(info); + if (code == AsyncErrorCode::ERROR_SUCCESS) { + // ȡ¼άɹ + qrcode_view_->SetQrcodeUrl(std::move(info->url)); + auth_key_ = std::move(info->auth_key); + // ʱ + StartLoginTimer(); + } + else { + qrcode_view_->ShowExpire(kTextQrcodeRequestFailed); + } + return 0; +} + +LRESULT WndLogin::OnMsgGetLoginResult(WPARAM wParam, LPARAM lParam) +{ + AsyncErrorCode code = (AsyncErrorCode)wParam; + auto info = reinterpret_cast(lParam); + assert(info); + std::unique_ptr auto_ptr(info); + if (code == AsyncErrorCode::ERROR_SUCCESS) { + // ɹ + switch (info->code) + { + case 0: { + // ½ɹ + std_str* cookie = new std_str(std::move(info->cookie)); + ::PostMessage(main_wnd_, WM_MAINWND_LOGIN_SUCCESS, 0, (LPARAM)cookie); + Close(); + break; + } + case 86038: // άʧЧ + qrcode_view_->ShowExpire(kTextQrcodeExpired); + break; + case 86101: // δɨ + StartLoginTimer(); + break; + case 86090: // άɨδȷ + qrcode_view_->ShowExpire(kTextQrcodeConfirmed); + StartLoginTimer(); + break; + default: + break; + } + } + else { + // ʧ + qrcode_view_->ShowExpire(kTextQrcodeResultParseFailed); + } + + return 0; +} \ No newline at end of file diff --git a/src/BVLoader/wnd/wnd_login.h b/src/BVLoader/wnd/wnd_login.h index 04d0b35..64cfe42 100644 --- a/src/BVLoader/wnd/wnd_login.h +++ b/src/BVLoader/wnd/wnd_login.h @@ -34,6 +34,9 @@ class WndLogin LRESULT OnMsgAsyncSuccess(WPARAM wParam, LPARAM lParam); LRESULT OnMsgAsyncError(WPARAM wParam, LPARAM lParam); + LRESULT OnMsgGetQrcode(WPARAM wParam, LPARAM lParam); + LRESULT OnMsgGetLoginResult(WPARAM wParam, LPARAM lParam); + private: QrcodeView* qrcode_view_ = nullptr; std_str auth_key_; diff --git a/src/Utils/Utils.vcxproj b/src/Utils/Utils.vcxproj index 5092df4..2175535 100644 --- a/src/Utils/Utils.vcxproj +++ b/src/Utils/Utils.vcxproj @@ -23,19 +23,19 @@ Win32Proj {06a01e97-333d-4309-a605-7d28324d750d} Utils - 10.0 + 10.0.17763.0 StaticLibrary true - v142 + v143 Unicode StaticLibrary false - v142 + v141 true Unicode diff --git a/src/Utils/string/string_utils.cpp b/src/Utils/string/string_utils.cpp index c856331..903a7ed 100644 --- a/src/Utils/string/string_utils.cpp +++ b/src/Utils/string/string_utils.cpp @@ -351,10 +351,10 @@ namespace string_utils { void StrTrim(std::string& s) { s.erase(s.begin(), std::find_if(s.begin(), s.end(), [](unsigned char ch) { - return !std::isspace(ch); + return !isspace(ch); })); s.erase(std::find_if(s.rbegin(), s.rend(), [](unsigned char ch) { - return !std::isspace(ch); + return !isspace(ch); }).base(), s.end()); } @@ -385,12 +385,28 @@ namespace string_utils { return ""; } - char TrimFileNameA(char ch) { - if ((ch == '\\') || (ch == '/') || (ch == ':' )|| (ch == '*') - || (ch == '?') || (ch == '<') || (ch == '>') || (ch == '|')) { - return '#'; + std::map CommandLineToArgMap(const wchar_t* command) + { + std::map argMap; + int argCount = 0; + LPWSTR* cmdArray = ::CommandLineToArgvW(command, &argCount); + if (cmdArray == nullptr || argCount == 0) { + return argMap; + } + for (int i = 0; i < argCount; ++i) { + std::wstring arg(cmdArray[i]); + auto pos = arg.find('='); + if (pos == std::wstring::npos) { + continue; + } + std::wstring key = arg.substr(0, pos); + std::wstring value = arg.substr(pos + 1); + while (!key.empty() && key[0] == '-') { + key.erase(key.begin()); + } + argMap.emplace(std::move(key), std::move(value)); } - return ch; + return argMap; } }// namespace string_utils diff --git a/src/duilib/DuiLib.vcxproj b/src/duilib/DuiLib.vcxproj index 20dbd84..9107b88 100644 --- a/src/duilib/DuiLib.vcxproj +++ b/src/duilib/DuiLib.vcxproj @@ -21,13 +21,13 @@ {E106ACD7-4E53-4AEE-942B-D0DD426DB34E} DuiLib - 10.0 + 10.0.17763.0 DynamicLibrary Unicode - v142 + v141 DynamicLibrary @@ -37,7 +37,7 @@ DynamicLibrary Unicode - v142 + v143 DynamicLibrary