Skip to content

Commit

Permalink
finish bunkr downloads
Browse files Browse the repository at this point in the history
  • Loading branch information
sam-k0 committed Sep 28, 2024
1 parent 274674c commit 71858be
Show file tree
Hide file tree
Showing 10 changed files with 263 additions and 39 deletions.
139 changes: 139 additions & 0 deletions bunker.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,139 @@
package main

import (
"bufio"
"fmt"
"io"
"net/http"
"os"
"path/filepath"
"strings"

"github.com/anaskhan96/soup"
)

type BunkrAlbum struct {
AlbumName string
AlbumURL string
ImageUrls []string
VideoUrls []string
}

// Read the "bunkrlinks.txt" file and return the links
func ReadBunkrDownloadFile(fpath string) []string {
// Open the file
file, err := os.Open(fpath)
if err != nil {
panic(err)
}
defer file.Close()

// Read the file
links := []string{}
scanner := bufio.NewScanner(file)
for scanner.Scan() {
links = append(links, scanner.Text())
}
return links
}

// Get all images and videos from a Bunkr album
// albumUrl: The URL of the album
func GetBunkrAlbum(albumUrl string) BunkrAlbum {
// Make a GET request to the main page url
resp, err := http.Get(albumUrl)

if err != nil {
panic(err)
}

defer resp.Body.Close()

currentAlbum := BunkrAlbum{
AlbumURL: albumUrl,
}

// Read the response body
body, err := io.ReadAll(resp.Body)
if err != nil {
panic(err)
}

// Get all links from the page
medialinks := []string{}
doc := soup.HTMLParse(string(body))
links := doc.FindAll("a")
for _, link := range links {
// Save link if it contains a type of "https://bunkrrr.org/v" or "https://bunkrrr.org/i"
if strings.Contains(link.Attrs()["href"], "https://bunkrrr.org/v") ||
strings.Contains(link.Attrs()["href"], "https://bunkrrr.org/i") {
medialinks = append(medialinks, link.Attrs()["href"])
}
}

for _, link := range medialinks {
println("Found link ", link)
}

// Every of the links link to a page with the download link
for _, link := range medialinks {
resp, err := http.Get(link)
if err != nil {
panic(err)
}
defer resp.Body.Close()
body, err := io.ReadAll(resp.Body)
if err != nil {
panic(err)
}

// Get all video html tags
doc := soup.HTMLParse(string(body))
videos := doc.FindAll("video")
for _, video := range videos {
source := video.Find("source")
videourl := source.Attrs()["src"]
videotype := source.Attrs()["type"]
println("Adding video of type ", videotype, " with url ", videourl)
currentAlbum.VideoUrls = append(currentAlbum.VideoUrls, videourl)
}

// Find all image html tags with link of "*.bunkr.ru"
images := doc.FindAll("img")
for _, image := range images {
imageurl := image.Attrs()["src"]
if strings.Contains(imageurl, ".bunkr.ru") {
println("Adding image with url ", imageurl)
currentAlbum.ImageUrls = append(currentAlbum.ImageUrls, imageurl)
}
}

}
return currentAlbum
}

// Download a file from a URL and save it to a path
// album: The album to download
// path: The parent directory to save the album
func DownloadBunkrAlbum(album BunkrAlbum, path string) {
println("Downloading album ", album.AlbumURL)
path = filepath.Join(path, strings.Split(album.AlbumURL, "/")[4])
// Create the directory for the album
os.MkdirAll(path, os.ModePerm)

downloadpath := "" // Temporary variable to store the download path
for i, image := range album.ImageUrls {
downloadpath = filepath.Join(path, fmt.Sprintf("%d.jpg", i))
println("Downloading image ", image)
downloadFile(image, downloadpath)
}
for i, video := range album.VideoUrls {
// Get the format of the video
// The format is the last part of the URL
// Example: https://bunkrrr.org/v/1234.mp4
format := strings.Split(video, ".")
downloadpath = filepath.Join(path, fmt.Sprintf("%d.%s", i, format[len(format)-1]))
println("Downloading video ", video)
downloadFile(video, downloadpath)
}
}
Empty file added bunkr/.gitkeep
Empty file.
2 changes: 2 additions & 0 deletions bunkrlinks.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
https://bunkr.si/a/Yyi82pb0
https://bunkr.fi/a/kNfpAHc9
28 changes: 0 additions & 28 deletions download.go
Original file line number Diff line number Diff line change
@@ -1,13 +1,9 @@
package main

import (
"fmt"
"io"
"net/http"
"os"
"path/filepath"
"strconv"
"time"
)

// Download a file from a URL and save it to a path
Expand All @@ -32,27 +28,3 @@ func downloadFile(url string, path string) {
panic(err)
}
}

// Download a whole hentai
// hentai: The hentai to download
// path: The directory to save the hentai, will be populated with the cover and pages
func DownloadHentai(hentai HentaiDict, path string) string {
path = filepath.Join(path, strconv.Itoa(hentai.ID))
// Check if the directory exists
if _, err := os.Stat(path); err == nil {
fmt.Println("Hentai already downloaded")
return path
}

println("Downloading hentai")
os.MkdirAll(path, os.ModePerm)
// Download the pages
for i, page := range hentai.Images.Pages {
downloadFile(page.Url, fmt.Sprintf("%s/%d.jpg", path, i))
// Sleep for a bit to avoid rate limiting
time.Sleep(time.Millisecond * 100)

println("Downloaded", i, "of", len(hentai.Images.Pages))
}
return path
}
3 changes: 3 additions & 0 deletions go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,10 @@ module archivist_go
go 1.23

require (
github.com/anaskhan96/soup v1.2.5 // indirect
github.com/phpdave11/gofpdi v1.0.14-0.20211212211723-1f10f9844311 // indirect
github.com/pkg/errors v0.9.1 // indirect
github.com/signintech/gopdf v0.27.0 // indirect
golang.org/x/net v0.0.0-20200114155413-6afb5195e5aa // indirect
golang.org/x/text v0.3.0 // indirect
)
14 changes: 14 additions & 0 deletions go.sum
Original file line number Diff line number Diff line change
@@ -1,7 +1,21 @@
github.com/anaskhan96/soup v1.2.5 h1:V/FHiusdTrPrdF4iA1YkVxsOpdNcgvqT1hG+YtcZ5hM=
github.com/anaskhan96/soup v1.2.5/go.mod h1:6YnEp9A2yywlYdM4EgDz9NEHclocMepEtku7wg6Cq3s=
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/phpdave11/gofpdi v1.0.14-0.20211212211723-1f10f9844311 h1:zyWXQ6vu27ETMpYsEMAsisQ+GqJ4e1TPvSNfdOPF0no=
github.com/phpdave11/gofpdi v1.0.14-0.20211212211723-1f10f9844311/go.mod h1:vBmVV0Do6hSBHC8uKUQ71JGW+ZGQq74llk/7bXwjDoI=
github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4=
github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
github.com/signintech/gopdf v0.27.0 h1:GEpWcZ2Gdk74+eHYINXWjs51j10r63/HxIFL9X5S7r0=
github.com/signintech/gopdf v0.27.0/go.mod h1:d23eO35GpEliSrF22eJ4bsM3wVeQJTjXTHq5x5qGKjA=
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
github.com/stretchr/testify v1.6.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
golang.org/x/net v0.0.0-20200114155413-6afb5195e5aa h1:F+8P+gmewFQYRk6JoLQLwjBCTu3mcIURZfNkVweuRKA=
golang.org/x/net v0.0.0-20200114155413-6afb5195e5aa/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/text v0.3.0 h1:g61tztE5qeGQ89tm6NTjjM9VPIm088od1l6aSorWRWg=
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
Empty file added hentainumbers.txt
Empty file.
52 changes: 45 additions & 7 deletions main.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,16 +2,54 @@ package main

import (
"os"
"strconv"
)

func setup() {
println("Setup...")
// Check if directories exist
if _, err := os.Stat("temp"); os.IsNotExist(err) {
os.Mkdir("temp", os.ModePerm)
}
if _, err := os.Stat("out"); os.IsNotExist(err) {
os.Mkdir("out", os.ModePerm)
}
if _, err := os.Stat("bunkr"); os.IsNotExist(err) {
os.Mkdir("bunkr", os.ModePerm)
}
print("Setup done.")
}

func main() {
if len(os.Args) < 2 {
println("Usage: go run main.go <id>")
os.Exit(1)
setup() // Create directories if not exist

if len(os.Args) == 2 {
println("Single argument mode: A single nhentai or bunkr album will be downloaded.")
arg := os.Args[1]
// decide if it is a nhentai or bunkr album, if its only numbers, its nhentai
if _, err := strconv.Atoi(arg); err == nil {
hentai := getByID(arg)
path := DownloadHentai(hentai, "temp")
CompilePdf(path, "out")
} else {
album := GetBunkrAlbum(arg)
DownloadBunkrAlbum(album, "bunkr")
}
return
}
println("Batch mode: nhentai and bunkr albums will be downloaded from the links in the files.")
// Download bunkr albums
links := ReadBunkrDownloadFile("bunkrlinks.txt")
for _, link := range links {
album := GetBunkrAlbum(link)
DownloadBunkrAlbum(album, "bunkr")
}

id := os.Args[1]
hentai := getByID(id)
path := DownloadHentai(hentai, "temp")
CompilePdf(path, "out")
// Download nhentai albums
links = ReadHentaiDownloadFile("hentailinks.txt")
for _, link := range links {
hentai := getByID(link)
path := DownloadHentai(hentai, "temp")
CompilePdf(path, "out")
}
}
46 changes: 46 additions & 0 deletions nhentai.go
Original file line number Diff line number Diff line change
@@ -1,10 +1,15 @@
package main

import (
"bufio"
"encoding/json"
"fmt"
"io"
"net/http"
"os"
"path/filepath"
"strconv"
"time"
)

type HentaiDict struct {
Expand Down Expand Up @@ -49,6 +54,23 @@ type HentaiDict struct {
NumFavorites int `json:"num_favorites"`
}

func ReadHentaiDownloadFile(fpath string) []string {
// Open the file
file, err := os.Open(fpath)
if err != nil {
panic(err)
}
defer file.Close()

// Read the file
links := []string{}
scanner := bufio.NewScanner(file)
for scanner.Scan() {
links = append(links, scanner.Text())
}
return links
}

func getByID(id string) HentaiDict {
// Perform a GET request
resp, err := http.Get("http://nhentai.net/api/gallery/" + id)
Expand Down Expand Up @@ -77,3 +99,27 @@ func getByID(id string) HentaiDict {
hentai.Images.Thumbnail.Url = fmt.Sprintf("https://t.nhentai.net/galleries/%s/thumb.jpg", hentai.MediaID)
return hentai
}

// Download a whole hentai
// hentai: The hentai to download
// path: The directory to save the hentai, will be populated with the cover and pages
func DownloadHentai(hentai HentaiDict, path string) string {
path = filepath.Join(path, strconv.Itoa(hentai.ID))
// Check if the directory exists
if _, err := os.Stat(path); err == nil {
fmt.Println("Hentai already downloaded")
return path
}

println("Downloading hentai")
os.MkdirAll(path, os.ModePerm)
// Download the pages
for i, page := range hentai.Images.Pages {
downloadFile(page.Url, fmt.Sprintf("%s/%d.jpg", path, i))
// Sleep for a bit to avoid rate limiting
time.Sleep(time.Millisecond * 100)

println("Downloaded", i, "of", len(hentai.Images.Pages))
}
return path
}
18 changes: 14 additions & 4 deletions readme.md
Original file line number Diff line number Diff line change
@@ -1,15 +1,24 @@
# archivist go
[![Go](https://github.com/sam-k0/archivistgo/actions/workflows/go.yml/badge.svg)](https://github.com/sam-k0/archivistgo/actions/workflows/go.yml)

nhentai.net downloader written in go.
nhentai.net and bunkr.ru downloader and pdf compiler.

## Usage

For the single album mode, pass an nhentaiID or bunkr-album link as an argument.
```sh
./archivist_go <id>
./archivistgo <id/bunkrlink>
```

Will download <id> and compile to pdf.
In case of an nhentai ID, the program will download the album and compile it into a pdf.
In case of a bunkr link, the program will download the album's images and videos.

For the batch mode, populate the files `hentainumbers.txt`and `bunkrlinks.txt` with the respective IDs and links
and then run the progam without any arguments.
* For bunkr links, please add the album link, and not the direct link to the image or videos.
```sh
./archivistgo
```

## Build

Expand All @@ -19,4 +28,5 @@ go build

## Dependencies

- github.com/signintech/gopdf
- github.com/signintech/gopdf
- github.com/anaskhan96/soup

0 comments on commit 71858be

Please sign in to comment.