From 8878760f59dc93005ce2628002ce19f1acb5f4fb Mon Sep 17 00:00:00 2001 From: shubhamharlalka-stack Date: Thu, 4 Jun 2026 16:11:12 +0530 Subject: [PATCH] Add DODI Repacks provider and update AnkerGames script DODIRepacks.lua (New): Built from scratch to add support for this provider. AnkerGames.lua (Updated): Uploaded the newest version to replace the old one. --- Scripts/AnkerGames.lua | 75 ++-- Scripts/DODIRepacks.lua | 743 ++++++++++++++++++++++++++++++++++++++++ 2 files changed, 779 insertions(+), 39 deletions(-) create mode 100644 Scripts/DODIRepacks.lua diff --git a/Scripts/AnkerGames.lua b/Scripts/AnkerGames.lua index 342d10a..9b2aa1b 100644 --- a/Scripts/AnkerGames.lua +++ b/Scripts/AnkerGames.lua @@ -1,17 +1,10 @@ -- Project GLD Provider Script: AnkerGames -local VERSION = "1.3.0" +local VERSION = "1.3.1" client.auto_script_update("https://raw.githubusercontent.com/Y0URD34TH/Project-GLD/refs/heads/main/Scripts/AnkerGames.lua", VERSION) local searchprovider = "ankergames.net" local BASE_URL = "https://ankergames.net" local version = client.GetVersionDouble() - -local session_headers = { - ["User-Agent"] = "Mozilla/5.0 (Windows NT 10.0; Win64; x64)", - ["Accept"] = "application/json, text/html", - ["X-Requested-With"] = "XMLHttpRequest" -} - local pendingResolvers = {} local imagelink = "" local gamename = "" @@ -19,9 +12,14 @@ local expectedurl = "" local pathcheck = "" local defaultdir = "C:/Games" local pass = "" +local session_headers = { + ["User-Agent"] = "Mozilla/5.0 (Windows NT 10.0; Win64; x64)", + ["Accept"] = "application/json, text/html", + ["X-Requested-With"] = "XMLHttpRequest" +} -- ============================================================================ --- PHASE 1: SEARCH LOGIC +-- UTILITIES -- ============================================================================ local function updateSession() local response = http.get(BASE_URL .. "/csrf-token", session_headers) @@ -40,7 +38,10 @@ local function sanitize(str) return str:lower():gsub("[%s%p]", "") end -local function ankersearch() +-- ============================================================================ +-- PHASE 1: SEARCH LOGIC +-- ============================================================================ +local function ankergamessearch() settings.save() updateSession() Notifications.push_success("AnkerGames", "Mr. Ghost's AnkerGames Script loaded.") @@ -108,9 +109,9 @@ local function ankersearch() end -- ============================================================================ --- PHASE 2: HYBRID FAST-FETCH RESOLVER +-- PHASE 2: DOWNLOAD ENGINE -- ============================================================================ -local function ondownloadclick(gamejson, downloadurl, scriptname) +local function ondownloadclick(gamejson, url, scriptname) if scriptname == "AnkerGames" then local success, jsonResults = pcall(JsonWrapper.parse, gamejson) if success and jsonResults then @@ -134,33 +135,28 @@ local function ondownloadclick(gamejson, downloadurl, scriptname) end end -local function on_beforedownload(url) +local function onbeforedownload(url) if url:match("^https://ankergames%.net/game/") then Notifications.push_warning("AnkerGames", "Download will start in few seconds.") - local browserName = "AnkerResolver_" .. tostring(os.time()) .. "_" .. tostring(math.random(1000, 9999)) local resolverBrowser = browser.CreateBrowser(browserName, url) browser.set_visible(false, browserName) - pendingResolvers[resolverBrowser:GetID()] = { originalUrl = url, name = browserName } - return "cancel", nil, nil end return nil, nil, nil end -local function on_browserloaded(browserID) +local function onbrowserloaded(browserID) local resolverBrowser = browser.GetBrowserByID(browserID) if not resolverBrowser then return end if pendingResolvers[browserID] then - -- This JS skips the 10s wait and hits the API immediately using the browser's native session state local fastFetchAutomation = [=[ if (document.title.includes("Just a moment") || document.title.includes("Cloudflare")) { - // Let Cloudflare finish solving before proceeding } else { let match = document.body.innerHTML.match(/generateDownloadUrl\(\s*(\d+)\s*\)/); if (match && match[1]) { @@ -190,14 +186,13 @@ local function on_browserloaded(browserID) end end -local function on_browserbeforedownload(browserID, downloadUrl, suggestedName, size) +local function onbrowserbeforedownload(browserID, downloadUrl, suggestedName, size) local resolverBrowser = browser.GetBrowserByID(browserID) if not resolverBrowser then return nil end if pendingResolvers[browserID] then local resolverInfo = pendingResolvers[browserID] - --expectedurl = downloadUrl expectedurl = resolverInfo.originalUrl Download.SetHistoryUrl(downloadUrl, resolverInfo.originalUrl) @@ -216,11 +211,11 @@ local function ondownloadcompleted(path, url) if expectedurl == url then local gamenametopath = gamename gamenametopath = gamenametopath:gsub(":", "") - defaultdir = menu.get_text("Anker Game Dir") .. "/" .. gamenametopath .. "/" + defaultdir = menu.get_text("AnkerGames Dir") .. "/" .. gamenametopath .. "/" path = path:gsub("\\", "/") pathcheck = path - pass = menu.get_text("Pass") - local deleteafterextraction = menu.get_bool("Delete After Extraction") + pass = menu.get_text("Password AnkerGames") + local deleteafterextraction = menu.get_bool("Delete After Extraction AnkerGames") zip.extract(path, defaultdir, deleteafterextraction, pass) settings.save() end @@ -243,10 +238,10 @@ local function onextractioncompleted(origin, path) if gameidl == -1 then local imagePath = Download.DownloadImage(imagelink) GameLibrary.addGame(fullExecutablePath, imagePath, gamename, "") - Notifications.push_success("Anker Script", "Game Successfully Installed!") + Notifications.push_success("AnkerGames", "Game Successfully Installed!") else GameLibrary.changeGameinfo(gameidl, fullExecutablePath) - Notifications.push_success("Anker Script", "Game Successfully Installed!") + Notifications.push_success("AnkerGames", "Game Successfully Installed!") end else local executables2 = file.listexecutablesrecursive(fullFolderPath) @@ -256,10 +251,10 @@ local function onextractioncompleted(origin, path) if gameidl == -1 then local imagePath = Download.DownloadImage(imagelink) GameLibrary.addGame(firstExecutable, imagePath, gamename, "") - Notifications.push_success("Anker Script", "Game Successfully Installed!") + Notifications.push_success("AnkerGames", "Game Successfully Installed!") else GameLibrary.changeGameinfo(gameidl, firstExecutable) - Notifications.push_success("Anker Script", "Game Successfully Installed!") + Notifications.push_success("AnkerGames", "Game Successfully Installed!") end end end @@ -273,19 +268,21 @@ end if version < 7.00 then Notifications.push_error("Lua Script", "Program is Outdated. Please Update to use this Script") else - Notifications.push_success("Lua Script", "Anker Script Loaded and Working") - menu.add_input_text("Anker Game Dir") - menu.set_text("Anker Game Dir", defaultdir) - menu.add_input_text("Pass") - menu.set_text("Pass", "") - menu.add_check_box("Delete After Extraction") + Notifications.push_success("Lua Script", "AnkerGames Script Loaded and Working") + menu.add_text("=== AnkerGames ===") + menu.add_input_text("AnkerGames Dir") + menu.set_text("AnkerGames Dir", defaultdir) + menu.add_input_text("Password AnkerGames") + menu.set_text("Password AnkerGames", "") + menu.add_check_box("Delete After Extraction AnkerGames") + menu.add_text("===============") settings.load() - client.add_callback("on_scriptselected", ankersearch) + client.add_callback("on_scriptselected", ankergamessearch) client.add_callback("on_downloadclick", ondownloadclick) - client.add_callback("on_beforedownload", on_beforedownload) - client.add_callback("on_browserloaded", on_browserloaded) - client.add_callback("on_browserbeforedownload", on_browserbeforedownload) + client.add_callback("on_beforedownload", onbeforedownload) + client.add_callback("on_browserloaded", onbrowserloaded) + client.add_callback("on_browserbeforedownload", onbrowserbeforedownload) client.add_callback("on_downloadcompleted", ondownloadcompleted) client.add_callback("on_extractioncompleted", onextractioncompleted) -end +end \ No newline at end of file diff --git a/Scripts/DODIRepacks.lua b/Scripts/DODIRepacks.lua new file mode 100644 index 0000000..db04ab3 --- /dev/null +++ b/Scripts/DODIRepacks.lua @@ -0,0 +1,743 @@ +-- Project GLD Provider Script: DODIRepacks +local VERSION = "1.0.0" +client.auto_script_update("https://raw.githubusercontent.com/Y0URD34TH/Project-GLD/refs/heads/main/Scripts/DODIRepacks.lua", VERSION) + +local searchprovider = "dodi-repacks.site" +local BASE_URL = "https://dodi-repacks.site" +local version = client.GetVersionDouble() +local cf_cookie = nil +local expectedInstallTimeSeconds = 300 +local currentMirrorQueue = {} +local originalDodiUrl = "" +local gamename = "" +local isspawning = false +local activeQueueIndex = 1 +local activeBrowserID = nil +local searchBrowserID = nil +local watchdogTargetTime = 0 +local isWatchdogActive = false +local isdownloadstarted = false +local HOST_UP4EVER = "up-4ever.net" +local HOST_SWIFT = "swiftuploads.com" +local HOST_FILEME = "file-me.top" +local imagelink = "" +local expectedurl = "" +local defaultdir = "C:/Games" +local pathcheck = "" +local isSeedingEnabled = false +local pendingOrigin = "" +local pendingDir = "" +local isDodiInstalling = false +local lastProcessCheckTime = 0 +local DYNAMIC_TRACKERS = "" +local configPath = file.get_parent_path(file.get_parent_path(client.GetScriptsPath())) .. "/Configs/Default.cfg" +local AD_BLACKLIST = { + "zovo.ink", "d1owuvqs9tkert", "cloudfront.net", "googlesyndication", + "googletagmanager", "adblock", "popunder", "aliexpress", "obqj2.com", + "clarity.ms", "click", "pop", "banner", "turnstile" +} +local session_headers = { + ["User-Agent"] = "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/120.0.0.0 Safari/537.36 ProjectGLD/2.15", + ["Accept"] = "text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,*/*;q=0.8", + ["Accept-Language"] = "en-US,en;q=0.9" +} + +-- ============================================================================ +-- UTILITIES +-- ============================================================================ +local function sanitize(str) + if not str then return "" end + return str:lower():gsub("[%s%p]", "") +end + +local function fetchDynamicTrackers() + if DYNAMIC_TRACKERS ~= "" then return DYNAMIC_TRACKERS end + local trackerUrls = { + "https://raw.githubusercontent.com/ngosang/trackerslist/master/trackers_best.txt", + "https://raw.githubusercontent.com/ngosang/trackerslist/master/trackers_best_ip.txt" + } + for i = 1, #trackerUrls do + local content = http.get(trackerUrls[i], {}) + if content then + -- Loop through every non-empty line in the text file + for tracker in content:gmatch("[^\r\n]+") do + DYNAMIC_TRACKERS = DYNAMIC_TRACKERS .. "&tr=" .. tracker + end + end + end + return DYNAMIC_TRACKERS +end + +-- ============================================================================ +-- PHASE 1: SEARCH LOGIC +-- ============================================================================ +local function dodirepackssearch() + settings.save() + + local getgamename = game.getgamename() + if not getgamename or getgamename == "" then return end + + if not cf_cookie then + Notifications.push_warning("DODI Repacks", "Bypassing Cloudflare protection, please wait...") + http.CloudFlareSolver(BASE_URL) + return + end + + local encodedName = getgamename:gsub(" ", "+") + local searchUrl = BASE_URL .. "/?s=" .. encodedName + local htmlContent = http.get(searchUrl, session_headers) + if not htmlContent or htmlContent == "" then + Notifications.push_error("DODI Repacks", "Failed to retrieve search results. Token may be expired.") + cf_cookie = nil + return + end + local lowerHTML = htmlContent:lower() + if lowerHTML:find("protected by cpguard", 1, true) or lowerHTML:find("cf-turnstile", 1, true) then + Notifications.push_warning("DODI Repacks", "cPGuard firewall detected. Spawning browser to solve...") + local bName = "DODISearchBypass_" .. tostring(os.time()) + local bObj = browser.CreateBrowser(bName, searchUrl) + if bObj then + searchBrowserID = bObj:GetID() + browser.set_visible(true, bName) + else + communication.receiveSearchResults({}) -- Prevents the UI warning hang + end + return + end + + Notifications.push_success("DODI Repacks", "Mr. Ghost's DODI Repacks Script loaded.") + local doc = html.parse(htmlContent) + local headings = doc:css("h2.entry-title a") + + local results = {} + local cleanedQuery = sanitize(getgamename) + + for i = 1, #headings do + local heading = headings[i] + local name = heading:text() + local link = heading:attr("href") + + if name and link then + if name:match("^%d+%-") then + + local isMatch = true + for word in getgamename:gmatch("%S+") do + local cleanedWord = sanitize(word) + local cleanedName = sanitize(name) + if not cleanedName:find(cleanedWord, 1, true) then + isMatch = false + break + end + end + + if isMatch then + local extractedSize = name:match("([%d%.]+%s*[Gg][Bb])") + + if not extractedSize then + local pageHtml = http.get(link, session_headers) + + if pageHtml and pageHtml ~= "" then + local sizeMatch = pageHtml:match("[Rr]epack%s+[Ss]ize.-([%d%.]+%s*[Gg][Bb])") + if sizeMatch then extractedSize = sizeMatch end + end + end + + local displayName = name + if extractedSize then + local normalizedSize = extractedSize:upper():gsub("%s+", "") + displayName = "[" .. normalizedSize .. "] " .. name + end + + local tooltip = "Platform: PC\nSource: DODI Repacks\nPost URL: " .. link + + local searchResult = { + name = displayName, + links = {}, + tooltip = tooltip, + ScriptName = "DODIRepacks", + } + + table.insert(searchResult.links, { + name = "Download", + link = link, + addtodownloadlist = true + }) + + table.insert(results, searchResult) + end + end + end + end + + if #results > 0 then + communication.receiveSearchResults(results) + else + Notifications.push_error("DODI Repacks", "No matching games found.") + end +end + +-- ============================================================================ +-- PHASE 2: DOWNLOAD ENGINE +-- ============================================================================ +local function cleanBrowserContext() + isWatchdogActive = false + local activeBrowser = browser.GetBrowserByID(activeBrowserID) + if activeBrowser then activeBrowser:CloseBrowser() end + activeBrowserID = nil +end + +local function processNextMirror() + cleanBrowserContext() + if activeQueueIndex > #currentMirrorQueue then + Notifications.push_error("DODI Repacks", "All available mirrors failed.") + isspawning = false + if originalDodiUrl and originalDodiUrl ~= "" then + Download.SetHistoryUrl(originalDodiUrl, originalDodiUrl) + end + return + end + local nextTarget = currentMirrorQueue[activeQueueIndex] + local bName = "DODI_" .. tostring(os.time()) .. "_" .. tostring(math.random(1000, 9999)) + local bObj = browser.CreateBrowser(bName, nextTarget) + if bObj then + activeBrowserID = bObj:GetID() + browser.set_visible(false, bName) + browser.DisableCaptchaDetection(bName) + watchdogTargetTime = utils.GetTimeUnix() + 25 + isWatchdogActive = true + else + isspawning = false + activeQueueIndex = activeQueueIndex + 1 + processNextMirror() + return + end +end + +function ondownloadclick(gamejson, url, scriptname) + if scriptname ~= "DODIRepacks" then return end + if isdownloadstarted then + isdownloadstarted = false + return + end + if isspawning then return end + isspawning = true + originalDodiUrl = url + local success, jsonResults = pcall(JsonWrapper.parse, gamejson) + if not success or not jsonResults then return end + local coverImageUrl = nil + if jsonResults["cover"] and jsonResults["cover"]["url"] then + coverImageUrl = jsonResults["cover"]["url"] + elseif jsonResults.coverurl then + coverImageUrl = jsonResults.coverurl + end + if coverImageUrl and coverImageUrl:sub(1, 2) == "//" then + coverImageUrl = "https:" .. coverImageUrl + end + if coverImageUrl then + coverImageUrl = coverImageUrl:gsub("t_thumb", "t_cover_big") + end + gamename = jsonResults.name or "" + imagelink = coverImageUrl or "" + local targetUrl = url + local htmlContent = http.get(targetUrl, session_headers) + if not htmlContent or htmlContent == "" then return end + local lowerHtml = htmlContent:lower() + local installTimePos = lowerHtml:find("install time", 1, true) + if installTimePos then + local extractedMax = 0 + local multiplier = 0 + local chunk = lowerHtml:sub(installTimePos, installTimePos + 120) + chunk = chunk:gsub("&#%d+;", "-") + chunk = chunk:gsub(" ", " ") + chunk = chunk:gsub("<[^>]+>", " ") + chunk = chunk:match("(%d+.-mins?)") or + chunk:match("(%d+.-hours?)") or + chunk:match("(%d+.-hrs?)") + if chunk:find("hour") or chunk:find("hr") then + multiplier = 3600 + elseif chunk:find("min") then + multiplier = 60 + end + for num in chunk:gmatch("%d+%.?%d*") do + extractedMax = tonumber(num) * multiplier + if extractedMax and extractedMax > expectedInstallTimeSeconds then + expectedInstallTimeSeconds = extractedMax + end + extractedMax = 0 + end + end + local doc = html.parse(htmlContent) + local foundMirrors = {} + local searchIndex = 1 + while true do + local startPos = lowerHtml:find("torrent", searchIndex, true) + if not startPos then break end + local endPos = lowerHtml:find("

", startPos, true) + if not endPos then endPos = #lowerHtml end + local chunk = htmlContent:sub(startPos, endPos) + local anyLinkFoundInChunk = false + for link in chunk:gmatch('href=["\'](http.-)["\']') do + anyLinkFoundInChunk = true + local lowerLink = link:lower() + if lowerLink:find(HOST_SWIFT, 1, true) or + lowerLink:find(HOST_FILEME, 1, true) or + lowerLink:find(HOST_UP4EVER, 1, true) then + table.insert(foundMirrors, link) + end + end + if anyLinkFoundInChunk then + break + end + searchIndex = endPos + end + if #foundMirrors == 0 then + isspawning = false + Notifications.push_error("DODI Repacks", "No torrent download links extracted from page layout.") + if originalDodiUrl and originalDodiUrl ~= "" then + Download.SetHistoryUrl(originalDodiUrl, originalDodiUrl) + end + return + end + table.sort(foundMirrors, function(a, b) + local getWeight = function(url) + local lowerUrl = url:lower() + if lowerUrl:find(HOST_FILEME, 1, true) then return 1 end + if lowerUrl:find(HOST_SWIFT, 1, true) then return 2 end + if lowerUrl:find(HOST_UP4EVER, 1, true) then return 3 end + return 5 + end + return getWeight(a) < getWeight(b) + end) + currentMirrorQueue = foundMirrors + activeQueueIndex = 1 + processNextMirror() +end + +function onbeforedownload(url) + local safe_url = tostring(url) + if safe_url:find("dodi-repacks.site", 1, true) then + Notifications.push_warning("DODI Repacks", "Download will start automatically in 15-20 seconds.") + return "cancel", nil, nil + end + return nil, nil, nil +end + +function onbrowserbeforeresourceload(browserID, url, method, referrer, resourceType) + if browserID ~= activeBrowserID then return end + local lowerUrl = url:lower() + for i = 1, #AD_BLACKLIST do + if lowerUrl:find(AD_BLACKLIST[i], 1, true) then return "block" end + end +end + +function onbrowserloaded(browserID) + if browserID == searchBrowserID then + local activeBrowser = browser.GetBrowserByID(browserID) + if not activeBrowser then return end + local url = activeBrowser:BrowserUrl() or "" + local pageTitle = (activeBrowser:GetPageTitle() or ""):lower() + if url:match("^https?://dodi%-repacks%.site") and not url:find("recaptcha.cloud", 1, true) then + Notifications.push_success("DODI Repacks", "Firewall bypassed successfully! Resuming search...") + activeBrowser:CloseBrowser() + searchBrowserID = nil + dodirepackssearch() + end + return + end + if browserID ~= activeBrowserID then return end + local activeBrowser = browser.GetBrowserByID(browserID) + if not activeBrowser then return end + activeBrowser:GetBrowserSource(function(pageSource) + if not pageSource or pageSource == "" then return end + local lowerSource = pageSource:lower() + local pageTitle = (activeBrowser:GetPageTitle() or ""):lower() + if lowerSource:find("file not found", 1, true) then + watchdogTargetTime = 0 + return + end + if pageTitle:find("just a moment", 1, true) or pageTitle:find("cloudflare", 1, true) or lowerSource:find("cf-challenge", 1, true) then + Notifications.push_warning("DODI Repacks", "Bypassing Cloudflare protection, please wait...") + browser.set_visible(true, activeBrowser.name) + isWatchdogActive = false + return + end + local url = activeBrowser:BrowserUrl() or "" + browser.set_visible(false, activeBrowser.name) + + if url:find(HOST_FILEME, 1, true) then + activeBrowser:ExecuteJavaScriptOnMainFrame("if(document.forms['F1']) { document.forms['F1'].submit(); } else { $('.file-download-btnn').click(); }") + + elseif url:find(HOST_SWIFT, 1, true) then + + local hybridBypassJS = [[ + (function() { + let attempts = 0; + let watcher = setInterval(function() { + attempts++; + + let token = document.querySelector('meta[name="csrf-token"]')?.content; + if (!token) { + let tokenInput = document.querySelector('input[name="_token"]'); + if (tokenInput) token = tokenInput.value; + } + + if (!token) { + if (attempts % 5 === 0); + return; + } + + let step1Input = document.querySelector('input[name="p"][value="down_1"]'); + let step2Form = document.getElementById('down_2Form'); + let anchors = document.querySelectorAll('a'); + let foundFinalButton = false; + let finalButtonElement = null; + + for (let i = 0; i < anchors.length; i++) { + let text = anchors[i].innerText.toLowerCase(); + if (text.includes('click here to download') || text.includes('download file')) { + foundFinalButton = true; + finalButtonElement = anchors[i]; + break; + } + } + + if (step1Input && step1Input.form) { + clearInterval(watcher); + triggerGhostSubmit(token, 'down_1'); + } + else if (step2Form) { + clearInterval(watcher); + triggerGhostSubmit(token, 'down_2'); + } + else if (foundFinalButton) { + clearInterval(watcher); + console.log("EXTEND_WATCHDOG_TIMER"); + finalButtonElement.click(); + } + else { + if (attempts > 30) { + clearInterval(watcher); + console.log("WARN: Landed on a page with no recognizable download structures."); + } + } + }, 500); + + function triggerGhostSubmit(token, stepValue) { + let cleanForm = document.createElement('form'); + cleanForm.method = 'POST'; + cleanForm.action = window.location.href; + cleanForm.innerHTML = ` + + + + `; + document.body.appendChild(cleanForm); + cleanForm.submit(); + } + })(); + ]] + activeBrowser:ExecuteJavaScriptOnMainFrame(hybridBypassJS) + + elseif url:find(HOST_UP4EVER, 1, true) then + + local up4everBypassJS = [[ + (function() { + if (document.getElementById('gld-up4ever-guard')) return; + let guard = document.createElement('div'); + guard.id = 'gld-up4ever-guard'; + guard.style.display = 'none'; + document.body.appendChild(guard); + + let attempts = 0; + let captchaShown = false; + let watcher = setInterval(function() { + attempts++; + + if (attempts >= 180) { + console.log("WARN: Landed on a page with no recognizable download structures."); + clearInterval(watcher); + return; + } + + let finalBtn = document.getElementById('downLoadLinkButton'); + if (finalBtn) { + clearInterval(watcher); + let targetUrl = finalBtn.getAttribute('data-target'); + if (targetUrl) window.location.href = targetUrl; + return; + } + + let captchaBtn = document.getElementById('downloadbtn'); + if (captchaBtn) { + if (attempts % 10 === 0) console.log("EXTEND_WATCHDOG_TIMER"); + if (!captchaShown) { + console.log("UP4EVER_SHOW_CAPTCHA"); + captchaShown = true; + } + let recaptchaResponse = document.getElementById('g-recaptcha-response'); + let isCaptchaSolved = recaptchaResponse && recaptchaResponse.value.trim() !== ""; + if (isCaptchaSolved) { + console.log("UP4EVER_HIDE_BROWSER"); + clearInterval(watcher); + let idInput = document.querySelector('input[name="id"]'); + let randInput = document.querySelector('input[name="rand"]'); + let cleanForm = document.createElement('form'); + cleanForm.method = 'POST'; + cleanForm.action = window.location.href; + cleanForm.innerHTML = ` + + + + + + `; + document.body.appendChild(cleanForm); + cleanForm.submit(); + } + return; + } + + let freeDownloadBtn = document.querySelector('input[name="method_free"]'); + let opInput = document.querySelector('input[name="op"][value="download1"]'); + if (freeDownloadBtn && opInput) { + clearInterval(watcher); + let idInput = document.querySelector('input[name="id"]'); + let cleanForm = document.createElement('form'); + cleanForm.method = 'POST'; + cleanForm.action = window.location.href; + cleanForm.innerHTML = ` + + + + `; + document.body.appendChild(cleanForm); + cleanForm.submit(); + return; + } + }, 500); + })(); + ]] + activeBrowser:ExecuteJavaScriptOnMainFrame(up4everBypassJS) + + end + end) +end + +function onbrowserbeforedownload(browserID, downloadUrl, filename, size) + if browserID ~= activeBrowserID then return end + local lower_url = tostring(downloadUrl):lower() + if lower_url:find("%.torrent") then + if originalDodiUrl and originalDodiUrl ~= "" then + Download.SetHistoryUrl(downloadUrl, originalDodiUrl) + end + local torrent_content = http.get(tostring(downloadUrl), {}) + if torrent_content and torrent_content ~= "" then + local magnet = Download.TorrentContentToMagnet(torrent_content) + if magnet and magnet ~= "" then + local bestTrackers = fetchDynamicTrackers() + magnet = magnet .. bestTrackers + expectedurl = magnet + Download.DownloadFile(magnet) + isdownloadstarted = true + end + end + end + cleanBrowserContext() + isspawning = false + return originalDodiUrl +end + +-- ============================================================================ +-- PHASE 3: INSTALLATION LOGIC +-- ============================================================================ +local function ondownloadcompleted(path, url) + local installAfter = menu.get_bool("Install After Download DODI Repacks") + if not installAfter then return end + if expectedurl == url then + Notifications.push_success("DODI Repacks", "Game Successfully Downloaded! Initiating Installation. Please wait...") + path = path:gsub("\\", "/") + local gamenametopath = gamename:gsub(":", "") + defaultdir = menu.get_text("DODI Repacks Dir") .. "/" .. gamenametopath + local exes = file.listexecutables(path) + local setupExeName = "" + local setupExePath = "" + if exes and #exes > 0 then + for i = 1, #exes do + local currentExe = exes[i] + local lowerExe = currentExe:lower() + if lowerExe:find("setup") and not lowerExe:find("unins") then + setupExeName = currentExe + setupExePath = path .. "/" .. setupExeName + break + end + end + end + if setupExeName ~= "" and setupExePath ~= "" then + local commandLine = '/DIR="' .. defaultdir .. '" /VERYSILENT /SUPPRESSMSGBOXES /NORESTART' + local ghostSetupPath = path .. "/" .. "Setup_GLD_Unlocked.exe" + pathcheck = ghostSetupPath:gsub("\\", "/") + file.copy_file(setupExePath, ghostSetupPath) + sleep(500) + file.exec(ghostSetupPath, 2000, commandLine, flase, "") + pendingOrigin = ghostSetupPath + pendingDir = defaultdir + isDodiInstalling = true + lastProcessCheckTime = utils.GetTimeUnix() + expectedInstallTimeSeconds + Notifications.push("DODI Repacks", "Installer launched! Press 'UP' arrow. Script will automatically complete when you close the installer.") + end + end +end + +local function onsetupcompleted(origin, path) + local installAfter = menu.get_bool("Install After Download DODI Repacks") + if not installAfter then return end + local cleanOrigin = origin:gsub("\\", "/") + if pathcheck == cleanOrigin then + gldconsole.print("COMPLETE ENTER: Installation verified.") + local installDir = path:gsub("\\", "/") + local targetExe = "" + local exes = file.listexecutablesrecursive(installDir) + local validExes = {} + local blacklist = {"unins", "redist", "crash", "dxweb", "vc_redist", "dotnet", "setup", "helper", "uninstall"} + if exes and #exes > 0 then + for i = 1, #exes do + local currentExe = exes[i] + local lowerExe = currentExe:lower() + local isValid = true + for j = 1, #blacklist do + if lowerExe:find(blacklist[j]) then + isValid = false + break + end + end + if isValid then + table.insert(validExes, currentExe) + end + end + end + if #validExes > 0 then + targetExe = validExes[1] + local gameNameLower = gamename:lower():gsub("[%s%p]", "") + for i = 1, #validExes do + local exe = validExes[i] + local lowerExe = exe:lower() + if lowerExe:find(gameNameLower) or lowerExe:find("shipping") or lowerExe:find("win64") then + targetExe = exe + break + end + end + end + if targetExe ~= "" then + targetExe = targetExe:gsub("/", "\\") + local gameidl = GameLibrary.GetGameIdFromName(gamename) + local imagePath = "" + if imagelink and imagelink ~= "" then + imagePath = Download.DownloadImage(imagelink) + end + if gameidl == -1 then + GameLibrary.addGame(targetExe, imagePath, gamename, "") + else + GameLibrary.changeGameinfo(gameidl, targetExe) + end + Notifications.push_success("DODI Repacks", "Game Successfully Installed and Added to Library!") + else + Notifications.push_error("DODI Repacks", "Installed, but could not automatically locate the game executable.") + end + if not isSeedingEnabled then + local deleteAfter = menu.get_bool("Delete After Installation DODI Repacks") + if deleteAfter then + local downloadFolder = file.get_parent_path(cleanOrigin) + file.delete(downloadFolder) + end + end + file.delete(cleanOrigin) + settings.save() + end +end + +-- ============================================================================ +-- SUPPORT FUNCTIONS +-- ============================================================================ +local function oncfdone(cookie, url) + if url:find("dodi-repacks.site", 1, true) then + cf_cookie = cookie + session_headers["Cookie"] = "cf_clearance=" .. tostring(cf_cookie) + dodirepackssearch() + end +end + +local function onbrowserconsolemessage(browserID, message) + gldconsole.print("[JS BROWSER LOG] " .. tostring(message)) + if browserID == activeBrowserID and type(message) == "string" then + if message == "UP4EVER_SHOW_CAPTCHA" then + local activeBrowser = browser.GetBrowserByID(browserID) + if activeBrowser then browser.set_visible(true, activeBrowser.name) end + elseif message == "UP4EVER_HIDE_BROWSER" then + local activeBrowser = browser.GetBrowserByID(browserID) + if activeBrowser then browser.set_visible(false, activeBrowser.name) end + elseif message == "EXTEND_WATCHDOG_TIMER" then + watchdogTargetTime = utils.GetTimeUnix() + 25 + elseif message:find("WARN: Landed on a page with no recognizable download structures.", 1, true) then + activeQueueIndex = activeQueueIndex + 1 + processNextMirror() + end + end +end + +local function onpresent() + if isWatchdogActive and utils.GetTimeUnix() >= watchdogTargetTime then + isWatchdogActive = false + activeQueueIndex = activeQueueIndex + 1 + processNextMirror() + end + if isDodiInstalling and pendingOrigin ~= "" then + local currentTime = utils.GetTimeUnix() + if currentTime >= lastProcessCheckTime + 30 then + lastProcessCheckTime = currentTime + local checkCmd = 'tasklist /FI "IMAGENAME eq Setup_GLD_Unlocked.exe"' + local output = system_output(checkCmd) + if output and not output:find("Setup_GLD_Unlocked.exe") then + isDodiInstalling = false + onsetupcompleted(pendingOrigin, pendingDir) + pendingOrigin = "" + pendingDir = "" + end + end + end +end + +-- ============================================================================ +-- INITIALIZATION & EVENT REGISTRATION +-- ============================================================================ +if version < 7.00 then + Notifications.push_error("Lua Script", "Program is Outdated. Please Update to use this Script") +else + Notifications.push_success("Lua Script", "DODI Repacks Provider Active") + menu.add_text("=== DODI Repacks ===") + menu.add_input_text("DODI Repacks Dir") + menu.set_text("DODI Repacks Dir", defaultdir) + menu.add_check_box("Install After Download DODI Repacks") + if file.exists(configPath) then + local configData = file.read(configPath) + if configData and configData:find('"seedafterdownload":%s*true') then + isSeedingEnabled = true + end + end + if not isSeedingEnabled then + menu.add_check_box("Delete After Installation DODI Repacks") + end + menu.add_text("================") + settings.load() + + client.add_callback("on_scriptselected", dodirepackssearch) + client.add_callback("on_downloadclick", ondownloadclick) + client.add_callback("on_beforedownload", onbeforedownload) + client.add_callback("on_browserbeforeresourceload", onbrowserbeforeresourceload) + client.add_callback("on_browserloaded", onbrowserloaded) + client.add_callback("on_browserbeforedownload", onbrowserbeforedownload) + client.add_callback("on_downloadcompleted", ondownloadcompleted) + client.add_callback("on_setupcompleted", onsetupcompleted) + client.add_callback("on_cfdone", oncfdone) + client.add_callback("on_browserconsolemessage", onbrowserconsolemessage) + client.add_callback("on_present", onpresent) +end \ No newline at end of file