Created
July 24, 2026 12:12
-
-
Save cynthia2006/7ad73ed668e10f966c9f80d2b504bb87 to your computer and use it in GitHub Desktop.
HTTP/3 accelarated fastest Lolicon downloader
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| package main | |
| import ( | |
| "crypto/tls" | |
| "encoding/json" | |
| "io" | |
| "log" | |
| "net/http" | |
| "net/url" | |
| "os" | |
| "os/signal" | |
| "path" | |
| "sync" | |
| "time" | |
| "github.com/quic-go/quic-go" | |
| "github.com/quic-go/quic-go/http3" | |
| ) | |
| func newH3Client() (client *http.Client, tr *http3.Transport) { | |
| tr = &http3.Transport{ | |
| TLSClientConfig: &tls.Config{ | |
| // Set TLS ALPN to HTTP/3.0 | |
| NextProtos: []string{http3.NextProtoH3}, | |
| }, | |
| QUICConfig: &quic.Config{}, | |
| } | |
| client = &http.Client{ | |
| Transport: tr, | |
| } | |
| return | |
| } | |
| func downloadImage(client *http.Client, urls chan string) { | |
| for url := range urls { | |
| fileName := calcFileName(url) | |
| // O_EXCL, that is, if it exists do not open a new file | |
| file, err := os.OpenFile(fileName, os.O_RDWR|os.O_CREATE|os.O_EXCL, 0o666) | |
| if err != nil { | |
| log.Printf("Unable to create file %s: %v", fileName, err) | |
| continue | |
| } | |
| response, err := client.Get(url) | |
| if err != nil { | |
| log.Printf("Unable to download %s: %v", url, err) | |
| file.Close() | |
| continue | |
| } | |
| _, err = io.Copy(file, response.Body) | |
| if err != nil { | |
| log.Printf("Unable to stream into %s from %s: %v", fileName, url, err) | |
| } | |
| file.Close() | |
| response.Body.Close() | |
| } | |
| } | |
| func calcFileName(s string) (base string) { | |
| url, _ := url.Parse(s) | |
| base = path.Base(url.Path) | |
| return | |
| } | |
| func main() { | |
| client, tr := newH3Client() | |
| defer tr.Close() | |
| urls := make(chan string) | |
| interrupt := make(chan os.Signal, 1) | |
| // Notify if done. | |
| signal.Notify(interrupt, os.Interrupt) | |
| // 100 concurrent requests, baby! | |
| var wg sync.WaitGroup | |
| for range 100 { | |
| wg.Go(func() { | |
| downloadImage(client, urls) | |
| }) | |
| } | |
| for { | |
| stopNow := false | |
| select { | |
| case <-interrupt: | |
| stopNow = true | |
| default: | |
| } | |
| if stopNow { | |
| log.Println("Exit requested, but will download remaining files") | |
| break | |
| } | |
| var r struct { | |
| Data []struct { | |
| Urls struct { | |
| Original string | |
| } | |
| } | |
| } | |
| response, err := client.Get("https://api.lolicon.app/setu/v2?num=20") | |
| if err != nil { | |
| log.Fatalf("Unable to fetch a list: %v", err) | |
| } | |
| responseBody, _ := io.ReadAll(response.Body) | |
| response.Body.Close() | |
| json.Unmarshal(responseBody, &r) | |
| for _, entry := range r.Data { | |
| urls <- entry.Urls.Original | |
| } | |
| time.Sleep(5 * time.Second) | |
| } | |
| close(urls) | |
| wg.Wait() | |
| } |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment