Skip to content

Instantly share code, notes, and snippets.

@cynthia2006
Created July 24, 2026 12:12
Show Gist options
  • Select an option

  • Save cynthia2006/7ad73ed668e10f966c9f80d2b504bb87 to your computer and use it in GitHub Desktop.

Select an option

Save cynthia2006/7ad73ed668e10f966c9f80d2b504bb87 to your computer and use it in GitHub Desktop.
HTTP/3 accelarated fastest Lolicon downloader
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