package realdebrid import ( "fmt" "os/exec" "sort" "strconv" "strings" "sync" "time" ) type IPInfo struct { Address string Hops int Latency time.Duration } func traceroute(ip string) (int, time.Duration, error) { cmd := exec.Command("traceroute", "-n", "-q", "1", "-w", "1", ip) out, err := cmd.CombinedOutput() if err != nil { return 0, 0, err } output := string(out) lines := strings.Split(output, "\n") hopCount := len(lines) - 1 var latency time.Duration if hopCount > 0 { lastLine := lines[hopCount-1] fmt.Printf("IP: %s, last hop: %s\n", ip, lastLine) parts := strings.Fields(lastLine) if len(parts) >= 3 { latencyValue, parseErr := strconv.ParseFloat(parts[2], 64) if parseErr == nil { latency = time.Duration(latencyValue * float64(time.Millisecond)) } } } return hopCount, latency, nil } func RunTest() { fmt.Println("Running network test...") ips := []string{"20.download.real-debrid.cloud", "20.download.real-debrid.com", "21.download.real-debrid.cloud", "21.download.real-debrid.com", "22.download.real-debrid.cloud", "22.download.real-debrid.com", "23.download.real-debrid.cloud", "23.download.real-debrid.com", "30.download.real-debrid.cloud", "30.download.real-debrid.com", "31.download.real-debrid.cloud", "31.download.real-debrid.com", "32.download.real-debrid.cloud", "32.download.real-debrid.com", "34.download.real-debrid.cloud", "34.download.real-debrid.com", "40.download.real-debrid.cloud", "40.download.real-debrid.com", "41.download.real-debrid.cloud", "41.download.real-debrid.com", "42.download.real-debrid.cloud", "42.download.real-debrid.com", "43.download.real-debrid.cloud", "43.download.real-debrid.com", "44.download.real-debrid.cloud", "44.download.real-debrid.com", "45.download.real-debrid.cloud", "45.download.real-debrid.com", "50.download.real-debrid.cloud", "50.download.real-debrid.com", "51.download.real-debrid.cloud", "51.download.real-debrid.com", "52.download.real-debrid.cloud", "52.download.real-debrid.com", "53.download.real-debrid.cloud", "53.download.real-debrid.com", "54.download.real-debrid.cloud", "54.download.real-debrid.com", "55.download.real-debrid.cloud", "55.download.real-debrid.com", "56.download.real-debrid.cloud", "56.download.real-debrid.com", "57.download.real-debrid.cloud", "57.download.real-debrid.com", "58.download.real-debrid.cloud", "58.download.real-debrid.com", "59.download.real-debrid.cloud", "59.download.real-debrid.com", "60.download.real-debrid.cloud", "60.download.real-debrid.com", "61.download.real-debrid.cloud", "61.download.real-debrid.com", "62.download.real-debrid.cloud", "62.download.real-debrid.com", "63.download.real-debrid.cloud", "63.download.real-debrid.com", "64.download.real-debrid.cloud", "64.download.real-debrid.com", "65.download.real-debrid.cloud", "65.download.real-debrid.com", "66.download.real-debrid.cloud", "66.download.real-debrid.com", "67.download.real-debrid.cloud", "67.download.real-debrid.com", "68.download.real-debrid.cloud", "68.download.real-debrid.com", "69.download.real-debrid.cloud", "69.download.real-debrid.com", "70.download.real-debrid.cloud", "70.download.real-debrid.com", "71.download.real-debrid.cloud", "71.download.real-debrid.com", "72.download.real-debrid.cloud", "72.download.real-debrid.com", "73.download.real-debrid.cloud", "73.download.real-debrid.com", "74.download.real-debrid.cloud", "74.download.real-debrid.com", "75.download.real-debrid.cloud", "75.download.real-debrid.com", "76.download.real-debrid.cloud", "76.download.real-debrid.com", "77.download.real-debrid.cloud", "77.download.real-debrid.com", "78.download.real-debrid.cloud", "78.download.real-debrid.com", "79.download.real-debrid.cloud", "79.download.real-debrid.com", "80.download.real-debrid.com", "ams1.download.real-debrid.com", "hkg1.download.real-debrid.com", "jkt1.download.real-debrid.com", "lax1.download.real-debrid.com", "lax2.download.real-debrid.com", "lax3.download.real-debrid.com", "lax4.download.real-debrid.com", "lax5.download.real-debrid.com", "lon1.download.real-debrid.com", "mum1.download.real-debrid.com", "sgp1.download.real-debrid.com", "tlv1.download.real-debrid.com", "tyo1.download.real-debrid.com"} var wg sync.WaitGroup infoChan := make(chan IPInfo, len(ips)) semaphore := make(chan struct{}, 10) for _, ip := range ips { wg.Add(1) semaphore <- struct{}{} go func(ip string) { defer wg.Done() hops, latency, err := traceroute(ip) if err != nil { fmt.Println("Error performing traceroute:", err) } else { infoChan <- IPInfo{Address: ip, Hops: hops, Latency: latency} } <-semaphore }(ip) } wg.Wait() close(semaphore) close(infoChan) fmt.Printf("Network test complete.\n\n") var ipInfos []IPInfo for info := range infoChan { ipInfos = append(ipInfos, info) } sort.Slice(ipInfos, func(i, j int) bool { return ipInfos[i].Latency < ipInfos[j].Latency }) const minResults = 10 const maxResults = 20 var okIPs []IPInfo if len(ipInfos) > 0 { // Start by adding the best IPs based on hops and latency up to the minResults for i := 0; i < min(len(ipInfos), minResults); i++ { okIPs = append(okIPs, ipInfos[i]) } // Find the highest latency in the current okIPs list highestLatency := okIPs[len(okIPs)-1].Latency // Add any additional IPs that have latency within a reasonable range of the highest latency for _, info := range ipInfos[minResults:] { if len(okIPs) >= maxResults { break // Stop adding IPs if maxResults is reached } if info.Latency <= highestLatency+(highestLatency/3) { okIPs = append(okIPs, info) } } } fmt.Printf("Here are the results, you can copy-paste the following to your config.yml:\n\n") fmt.Println("preferred_hosts:") for _, info := range okIPs { fmt.Printf(" - %s # hops: %d latency: %v\n", info.Address, info.Hops, info.Latency) } }