diff --git a/github_down/gen.py b/github_down/gen.py new file mode 100644 index 0000000..dbdae89 --- /dev/null +++ b/github_down/gen.py @@ -0,0 +1,39 @@ +from subprocess import run + +proxies = [ + "https://hk.gh-proxy.org/", + "https://cdn.gh-proxy.org/", + "https://gh-proxy.org/", + "https://edgeone.gh-proxy.org/", + "https://gh-proxy.top/", + "https://gh-proxy.net/", + "https://gh-proxy.com/", + "https://ghfast.top/", + "https://gh.ddlc.top/", + "https://gh.llkk.cc/", + "https://ghproxy.homeboyc.cn/", + "", +] + +cmd = [ + "aria2c", + "--auto-file-renaming=false", + "--retry-wait=2", + "--max-tries=0", + "--timeout=10", + "--connect-timeout=5", + "--lowest-speed-limit=100K", + "-x","4","-s","24","-k","1M", +] + +try: + run("aria2c --version", check=True, capture_output=True) +except Exception: + print("请先安装aria2") + exit(1) + +input_url = input("请输入GitHub文件链接: ").strip() +cmd.extend( + [f"{proxy}{input_url}" for proxy in proxies] +) +run(cmd) diff --git a/github_down/gen_win.cpp b/github_down/gen_win.cpp new file mode 100644 index 0000000..bc1328c --- /dev/null +++ b/github_down/gen_win.cpp @@ -0,0 +1,250 @@ +#define NOMINMAX +#include + +#include +#include +#include +#include +#include +#include +#include + +// ---------------- UTF helpers ---------------- +static std::wstring utf8_to_wstring(const std::string& s) { + if (s.empty()) return L""; + int wlen = MultiByteToWideChar(CP_UTF8, 0, s.c_str(), (int)s.size(), nullptr, 0); + std::wstring w(wlen, L'\0'); + MultiByteToWideChar(CP_UTF8, 0, s.c_str(), (int)s.size(), w.data(), wlen); + return w; +} + +static std::string trim_copy(std::string s) { + auto is_space = [](unsigned char c) { return c==' '||c=='\t'||c=='\n'||c=='\r'; }; + while (!s.empty() && is_space((unsigned char)s.back())) s.pop_back(); + size_t i = 0; + while (i < s.size() && is_space((unsigned char)s[i])) i++; + return s.substr(i); +} + +// Quote a single arg for CreateProcess command line. +static std::wstring quote_arg_windows(const std::wstring& arg) { + bool need_quotes = arg.empty(); + for (wchar_t c : arg) { + if (c == L' ' || c == L'\t' || c == L'\n' || c == L'\v' || c == L'"') { + need_quotes = true; break; + } + } + if (!need_quotes) return arg; + + std::wstring out = L"\""; + size_t bs_count = 0; + for (wchar_t c : arg) { + if (c == L'\\') { + bs_count++; + } else if (c == L'"') { + out.append(bs_count * 2 + 1, L'\\'); + out.push_back(L'"'); + bs_count = 0; + } else { + if (bs_count) out.append(bs_count, L'\\'); + bs_count = 0; + out.push_back(c); + } + } + if (bs_count) out.append(bs_count * 2, L'\\'); + out.push_back(L'"'); + return out; +} + +// ---------------- RAII cleanup guard ---------------- +struct TempBundleGuard { + std::filesystem::path dir; + std::filesystem::path aria2_path; + + ~TempBundleGuard() { + // Best-effort cleanup + try { + if (!aria2_path.empty() && std::filesystem::exists(aria2_path)) { + std::error_code ec; + std::filesystem::remove(aria2_path, ec); + } + if (!dir.empty() && std::filesystem::exists(dir)) { + std::error_code ec; + std::filesystem::remove_all(dir, ec); + } + } catch (...) { + // swallow + } + } +}; + +// ---------------- Resource extraction ---------------- +static bool extract_resource_to_file( + const wchar_t* res_name, + const std::filesystem::path& out_path +) { + HRSRC hrsrc = FindResourceW(nullptr, res_name, RT_RCDATA); + if (!hrsrc) return false; + + HGLOBAL hglob = LoadResource(nullptr, hrsrc); + if (!hglob) return false; + + DWORD size = SizeofResource(nullptr, hrsrc); + void* data = LockResource(hglob); + if (!data || size == 0) return false; + + std::ofstream ofs(out_path, std::ios::binary); + ofs.write(reinterpret_cast(data), size); + return ofs.good(); +} + + + +// ---------------- Process runner ---------------- +static int run_process(const std::wstring& exe_path, const std::vector& args, bool show) { + std::wstring cmdline = quote_arg_windows(exe_path); + for (const auto& a : args) { + cmdline.push_back(L' '); + cmdline += quote_arg_windows(a); + } + + STARTUPINFOW si{}; + si.cb = sizeof(si); + si.dwFlags = STARTF_USESHOWWINDOW; + si.wShowWindow = SW_SHOW; + + PROCESS_INFORMATION pi{}; + + // CreateProcessW may modify buffer + std::vector buf(cmdline.begin(), cmdline.end()); + buf.push_back(L'\0'); + + BOOL ok = CreateProcessW( + nullptr, + buf.data(), + nullptr, nullptr, + FALSE, + show ? 0 : CREATE_NO_WINDOW, + nullptr, + nullptr, + &si, + &pi + ); + + if (!ok) { + return -1; + } + + WaitForSingleObject(pi.hProcess, INFINITE); + + DWORD code = 0; + GetExitCodeProcess(pi.hProcess, &code); + + CloseHandle(pi.hThread); + CloseHandle(pi.hProcess); + + return (int)code; +} + +// ---------------- Get temp directory ---------------- +static std::filesystem::path get_temp_dir() { + wchar_t buf[MAX_PATH + 1]; + DWORD n = GetTempPathW(MAX_PATH, buf); + if (n == 0 || n > MAX_PATH) throw std::runtime_error("GetTempPathW failed"); + return std::filesystem::path(buf); +} + +static std::filesystem::path make_unique_subdir(const std::filesystem::path& base) { + // Use PID + tick count for uniqueness + DWORD pid = GetCurrentProcessId(); + ULONGLONG t = GetTickCount64(); + + std::filesystem::path dir = base / L"MyAria2Bundle"; + std::filesystem::path uniq = dir / (L"run_" + std::to_wstring(pid) + L"_" + std::to_wstring(t)); + + std::error_code ec; + std::filesystem::create_directories(uniq, ec); + if (ec) throw std::runtime_error("create_directories failed"); + return uniq; +} + +int main() { + // Windows console UTF-8 + SetConsoleCP(65001); + SetConsoleOutputCP(65001); + std::setlocale(LC_ALL, ".UTF-8"); + + // Proxies list (same as your python) + const std::vector proxies = { + "https://hk.gh-proxy.org/", + "https://cdn.gh-proxy.org/", + "https://gh-proxy.org/", + "https://edgeone.gh-proxy.org/", + "https://gh-proxy.top/", + "https://gh-proxy.net/", + "https://gh-proxy.com/", + "https://ghfast.top/", + "https://gh.ddlc.top/", + "https://gh.llkk.cc/", + "https://ghproxy.homeboyc.cn/", + "" + }; + + TempBundleGuard guard; + try { + // Extract aria2c.exe to %TEMP%\MyAria2Bundle\run_xxx\aria2c.exe + auto temp_base = get_temp_dir(); + guard.dir = make_unique_subdir(temp_base); + guard.aria2_path = guard.dir / L"aria2c.exe"; + + if (!extract_resource_to_file(L"ARIA2_BIN", guard.aria2_path)) { + std::cerr << "释放 aria2c.exe 失败:资源 ARIA2_BIN 不存在或写入失败。\n"; + return 1; + } + + + { + int rc = run_process(guard.aria2_path, {L"--version"},false); + if (rc != 0) { + std::cerr << "aria2c 自检失败(exit=" << rc << ")。\n"; + return 1; + } + } + + std::cout << "请输入GitHub文件链接: "; + std::string input_url; + std::getline(std::cin, input_url); + input_url = trim_copy(input_url); + if (input_url.empty()) { + std::cerr << "输入为空,退出。\n"; + return 1; + } + + std::vector args = { + L"--auto-file-renaming=false", + L"--retry-wait=2", + L"--max-tries=0", + L"--timeout=10", + L"--connect-timeout=5", + L"--lowest-speed-limit=100K", + L"-x", L"4", + L"-s", L"24", + L"-k", L"1M" + }; + + for (const auto& p : proxies) { + std::string full = p + input_url; + args.push_back(utf8_to_wstring(full)); + } + + int rc = run_process(guard.aria2_path, args,true); + if (rc != 0) { + std::cerr << "aria2c 执行失败(exit=" << rc << ")。\n"; + } + return rc; + + } catch (const std::exception& e) { + std::cerr << "异常: " << e.what() << "\n"; + return 1; + } +} diff --git a/github_down/resource.rc b/github_down/resource.rc new file mode 100644 index 0000000..39653c3 --- /dev/null +++ b/github_down/resource.rc @@ -0,0 +1 @@ +ARIA2_BIN RCDATA "aria2c.exe"