diff --git a/CMakeLists.txt b/CMakeLists.txt index d61187c..3e69274 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -62,6 +62,7 @@ target_link_libraries(${PROJECT_NAME} PRIVATE dwmapi.lib Shcore.lib Msimg32.lib + winhttp.lib nlohmann_json::nlohmann_json unofficial::webview2::webview2 OpenSSL::SSL diff --git a/src/core/globals.cpp b/src/core/globals.cpp index 8fd270a..5a211a3 100644 --- a/src/core/globals.cpp +++ b/src/core/globals.cpp @@ -10,7 +10,11 @@ HBRUSH g_darkBrush = nullptr; HANDLE g_hMutex = nullptr; HHOOK g_hMouseHook = nullptr; -std::wstring g_webuiUrl = L"https://stremio.zarg.me/"; +std::vector g_webuiUrls = { + L"https://stremio.zarg.me/", + L"https://zaarrg.github.io/stremio-web-shell-fixes/", + L"https://web.stremio.com/" +}; std::string g_updateUrl= "https://raw.githubusercontent.com/Zaarrg/stremio-desktop-v5/refs/heads/webview-windows/version/version.json"; // Command-line args diff --git a/src/core/globals.h b/src/core/globals.h index dcb513b..17feaed 100644 --- a/src/core/globals.h +++ b/src/core/globals.h @@ -41,7 +41,7 @@ extern HBRUSH g_darkBrush; extern HANDLE g_hMutex; extern HHOOK g_hMouseHook; -extern std::wstring g_webuiUrl; +extern std::vector g_webuiUrls; extern std::string g_updateUrl; // Args @@ -123,6 +123,7 @@ extern ULONG_PTR g_gdiplusToken; // App Ready and Event Queue #define WM_NOTIFY_FLUSH (WM_USER + 101) +#define WM_REACHABILITY_DONE (WM_USER + 200) extern std::vector g_outboundMessages; extern std::wstring g_launchProtocol; extern std::atomic g_isAppReady; diff --git a/src/main.cpp b/src/main.cpp index 5714b01..934c684 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -50,7 +50,7 @@ int main(int argc, char* argv[]) for(int i=1; i(wParam); + if(pUrl) + { + if (!pUrl->empty() && g_webview) + { + std::wcout << L"[WEBVIEW]: Navigating to " << *pUrl << std::endl; + g_webview->Navigate(pUrl->c_str()); + } + else + { + MessageBoxW(nullptr, + L"All endpoints are unreachable", + L"WebView2 Initialization Error", + MB_ICONERROR | MB_OK); + } + delete pUrl; + } + break; + } case WM_SETTINGCHANGE: { UpdateTheme(hWnd); diff --git a/src/utils/helpers.cpp b/src/utils/helpers.cpp index 1e363cb..f7d0936 100644 --- a/src/utils/helpers.cpp +++ b/src/utils/helpers.cpp @@ -1,5 +1,6 @@ #include "helpers.h" #include +#include #include "../core/globals.h" std::string WStringToUtf8(const std::wstring &wstr) @@ -116,4 +117,76 @@ bool isSubtitle(const std::wstring& filePath) { std::transform(lowerFilePath.begin(), lowerFilePath.end(), lowerFilePath.begin(), towlower); return std::any_of(g_subtitleExtensions.begin(), g_subtitleExtensions.end(), [&](const std::wstring& ext) { return lowerFilePath.ends_with(ext); }); +} + +bool IsEndpointReachable(const std::wstring& url) { + HINTERNET hSession = WinHttpOpen(L"Reachability Check", + WINHTTP_ACCESS_TYPE_DEFAULT_PROXY, NULL, NULL, 0); + if (!hSession) return false; + + // Set timeouts + WinHttpSetTimeouts(hSession, 3000, 3000, 3000, 3000); + + URL_COMPONENTS urlComp = { sizeof(URL_COMPONENTS) }; + urlComp.dwHostNameLength = (DWORD)-1; + urlComp.dwUrlPathLength = (DWORD)-1; + urlComp.dwSchemeLength = (DWORD)-1; + + if (!WinHttpCrackUrl(url.c_str(), (DWORD)url.length(), 0, &urlComp)) { + WinHttpCloseHandle(hSession); + return false; + } + + std::wstring host(urlComp.lpszHostName, urlComp.dwHostNameLength); + std::wstring path(urlComp.lpszUrlPath, urlComp.dwUrlPathLength); + INTERNET_PORT port = urlComp.nPort; + bool useSSL = (urlComp.nScheme == INTERNET_SCHEME_HTTPS); + + HINTERNET hConnect = WinHttpConnect(hSession, host.c_str(), port, 0); + if (!hConnect) { + WinHttpCloseHandle(hSession); + return false; + } + + HINTERNET hRequest = WinHttpOpenRequest(hConnect, L"HEAD", path.c_str(), + NULL, NULL, NULL, useSSL ? WINHTTP_FLAG_SECURE : 0); + if (!hRequest) { + WinHttpCloseHandle(hConnect); + WinHttpCloseHandle(hSession); + return false; + } + + BOOL sent = WinHttpSendRequest(hRequest, NULL, 0, NULL, 0, 0, 0); + if (!sent) { + WinHttpCloseHandle(hRequest); + WinHttpCloseHandle(hConnect); + WinHttpCloseHandle(hSession); + return false; + } + + BOOL received = WinHttpReceiveResponse(hRequest, NULL); + DWORD statusCode = 0; + DWORD statusSize = sizeof(statusCode); + + if (received) { + WinHttpQueryHeaders(hRequest, + WINHTTP_QUERY_STATUS_CODE | WINHTTP_QUERY_FLAG_NUMBER, + NULL, &statusCode, &statusSize, NULL); + } + + WinHttpCloseHandle(hRequest); + WinHttpCloseHandle(hConnect); + WinHttpCloseHandle(hSession); + + return received && (statusCode >= 200 && statusCode < 300); +} + +std::wstring GetFirstReachableUrl() { + for (const auto& url : g_webuiUrls) { + if (IsEndpointReachable(url)) { + return url; + } + } + // Fallback to first URL or handle error + return g_webuiUrls.empty() ? L"" : g_webuiUrls[0]; } \ No newline at end of file diff --git a/src/utils/helpers.h b/src/utils/helpers.h index 39c52b9..8655309 100644 --- a/src/utils/helpers.h +++ b/src/utils/helpers.h @@ -10,6 +10,7 @@ std::string WStringToUtf8(const std::wstring &wstr); std::wstring Utf8ToWstring(const std::string& utf8Str); std::string decodeURIComponent(const std::string& encoded); std::wstring GetExeDirectory(); +std::wstring GetFirstReachableUrl(); bool FileExists(const std::wstring& path); bool DirectoryExists(const std::wstring& dirPath); bool IsDuplicateProcessRunning(const std::vector& targetProcesses); diff --git a/src/webview/webview.cpp b/src/webview/webview.cpp index 4d2e761..b940810 100644 --- a/src/webview/webview.cpp +++ b/src/webview/webview.cpp @@ -218,8 +218,12 @@ void InitWebView2(HWND hWnd) SetupExtensions(); SetupWebMessageHandler(); - std::wcout << L"[WEBVIEW]: Navigating to " << g_webuiUrl << std::endl; - g_webview->Navigate(g_webuiUrl.c_str()); + std::thread([](){ + std::wcout << L"[WEBVIEW]: Checking web ui endpoints..." << std::endl; + std::wstring foundUrl = GetFirstReachableUrl(); + std::wstring* pResult = new std::wstring(foundUrl); + PostMessage(g_hWnd, WM_REACHABILITY_DONE, (WPARAM)pResult, 0); + }).detach(); return S_OK; }).Get() );