AnthoLume/search/search.go

200 lines
4.4 KiB
Go
Raw Normal View History

2023-10-07 01:25:56 +00:00
package search
import (
2024-01-22 22:43:47 +00:00
"crypto/tls"
"fmt"
2023-10-07 01:25:56 +00:00
"io"
"net/http"
"net/url"
"os"
"time"
log "github.com/sirupsen/logrus"
)
2024-08-14 02:32:16 +00:00
const userAgent string = "Mozilla/5.0 (Macintosh; Intel Mac OS X 10.15; rv:127.0) Gecko/20100101 Firefox/127.0"
2024-01-22 22:43:47 +00:00
2023-10-07 01:25:56 +00:00
type Cadence string
const (
CADENCE_TOP_YEAR Cadence = "y"
CADENCE_TOP_MONTH Cadence = "m"
2023-10-07 01:25:56 +00:00
)
type BookType int
const (
BOOK_FICTION BookType = iota
BOOK_NON_FICTION
)
type Source string
const (
SOURCE_ANNAS_ARCHIVE Source = "Annas Archive"
SOURCE_LIBGEN_FICTION Source = "LibGen Fiction"
SOURCE_LIBGEN_NON_FICTION Source = "LibGen Non-fiction"
)
2023-10-07 01:25:56 +00:00
type SearchItem struct {
ID string
Title string
Author string
Language string
Series string
FileType string
FileSize string
UploadDate string
}
type sourceDef struct {
searchURL string
downloadURL string
parseSearchFunc func(io.ReadCloser) ([]SearchItem, error)
parseDownloadFunc func(io.ReadCloser) (string, error)
2023-10-07 01:25:56 +00:00
}
var sourceDefs = map[Source]sourceDef{
SOURCE_ANNAS_ARCHIVE: {
searchURL: "https://annas-archive.org/search?index=&q=%s&ext=epub&sort=&lang=en",
2024-08-14 02:32:16 +00:00
downloadURL: "http://libgen.li/ads.php?md5=%s",
parseSearchFunc: parseAnnasArchive,
2024-08-14 02:32:16 +00:00
parseDownloadFunc: parseAnnasArchiveDownloadURL,
},
SOURCE_LIBGEN_FICTION: {
searchURL: "https://libgen.is/fiction/?q=%s&language=English&format=epub",
2024-08-14 02:32:16 +00:00
downloadURL: "http://libgen.li/ads.php?md5=%s",
parseSearchFunc: parseLibGenFiction,
2024-08-14 02:32:16 +00:00
parseDownloadFunc: parseAnnasArchiveDownloadURL,
},
SOURCE_LIBGEN_NON_FICTION: {
searchURL: "https://libgen.is/search.php?req=%s",
2024-08-14 02:32:16 +00:00
downloadURL: "http://libgen.li/ads.php?md5=%s",
parseSearchFunc: parseLibGenNonFiction,
2024-08-14 02:32:16 +00:00
parseDownloadFunc: parseAnnasArchiveDownloadURL,
},
2023-10-07 01:25:56 +00:00
}
func SearchBook(query string, source Source) ([]SearchItem, error) {
def := sourceDefs[source]
log.Debug("Source: ", def)
url := fmt.Sprintf(def.searchURL, url.QueryEscape(query))
body, err := getPage(url)
2023-10-26 10:20:56 +00:00
if err != nil {
return nil, err
2023-10-26 10:20:56 +00:00
}
return def.parseSearchFunc(body)
2023-10-07 01:25:56 +00:00
}
func SaveBook(id string, source Source) (string, error) {
def := sourceDefs[source]
log.Debug("Source: ", def)
url := fmt.Sprintf(def.downloadURL, id)
2023-10-07 01:25:56 +00:00
body, err := getPage(url)
2023-10-26 10:20:56 +00:00
if err != nil {
return "", err
}
bookURL, err := def.parseDownloadFunc(body)
2023-10-26 10:20:56 +00:00
if err != nil {
log.Error("Parse Download URL Error: ", err)
return "", fmt.Errorf("Download Failure")
2023-10-26 10:20:56 +00:00
}
2023-10-07 01:25:56 +00:00
// Create File
tempFile, err := os.CreateTemp("", "book")
if err != nil {
log.Error("File Create Error: ", err)
return "", fmt.Errorf("File Failure")
2023-10-07 01:25:56 +00:00
}
defer tempFile.Close()
// Download File
log.Info("Downloading Book: ", bookURL)
2024-01-22 22:43:47 +00:00
resp, err := downloadBook(bookURL)
2023-10-07 01:25:56 +00:00
if err != nil {
os.Remove(tempFile.Name())
log.Error("Book URL API Failure: ", err)
return "", fmt.Errorf("API Failure")
2023-10-07 01:25:56 +00:00
}
defer resp.Body.Close()
// Copy File to Disk
log.Info("Saving Book")
2023-10-07 01:25:56 +00:00
_, err = io.Copy(tempFile, resp.Body)
if err != nil {
os.Remove(tempFile.Name())
log.Error("File Copy Error: ", err)
return "", fmt.Errorf("File Failure")
2023-10-07 01:25:56 +00:00
}
return tempFile.Name(), nil
}
func GetBookURL(id string, bookType BookType) (string, error) {
// Derive Info URL
var infoURL string
if bookType == BOOK_FICTION {
infoURL = "http://library.lol/fiction/" + id
} else if bookType == BOOK_NON_FICTION {
infoURL = "http://library.lol/main/" + id
}
// Parse & Derive Download URL
body, err := getPage(infoURL)
if err != nil {
return "", err
}
// downloadURL := parseLibGenDownloadURL(body)
return parseLibGenDownloadURL(body)
}
2023-10-26 10:20:56 +00:00
func getPage(page string) (io.ReadCloser, error) {
log.Debug("URL: ", page)
2023-10-26 10:20:56 +00:00
// Set 10s Timeout
2024-08-14 02:32:16 +00:00
client := http.Client{Timeout: 10 * time.Second}
// Start Request
req, err := http.NewRequest("GET", page, nil)
if err != nil {
return nil, err
2023-10-26 10:20:56 +00:00
}
2024-08-14 02:32:16 +00:00
// Set User-Agent
req.Header.Set("User-Agent", userAgent)
// Do Request
resp, err := client.Do(req)
2023-10-26 10:20:56 +00:00
if err != nil {
return nil, err
}
// Return Body
return resp.Body, err
2023-10-07 01:25:56 +00:00
}
2024-01-22 22:43:47 +00:00
func downloadBook(bookURL string) (*http.Response, error) {
2024-08-14 02:32:16 +00:00
log.Debug("URL: ", bookURL)
2024-01-22 22:43:47 +00:00
// Allow Insecure
2024-08-14 02:32:16 +00:00
client := &http.Client{
Transport: &http.Transport{
TLSClientConfig: &tls.Config{InsecureSkipVerify: true},
},
}
2024-01-22 22:43:47 +00:00
// Start Request
req, err := http.NewRequest("GET", bookURL, nil)
if err != nil {
return nil, err
}
2024-08-14 02:32:16 +00:00
// Set User-Agent
2024-01-22 22:43:47 +00:00
req.Header.Set("User-Agent", userAgent)
return client.Do(req)
}