package books import ( "encoding/json" "fmt" "hugo-medialog/utils" "io/ioutil" "net/http" "net/url" "os" "path/filepath" "strconv" ) const googleBooksAPIBaseURL = "https://www.googleapis.com/books/v1/volumes?q=intitle:%s&key=%s" // Function to search for a book by title func SearchBookByTitle(title string, book *Book) error { apiKey := os.Getenv("GOOGLE_BOOKS_API_KEY") url := fmt.Sprintf(googleBooksAPIBaseURL, url.QueryEscape(title), apiKey) resp, err := http.Get(url) if err != nil { return err } defer resp.Body.Close() var result map[string]interface{} if err := json.NewDecoder(resp.Body).Decode(&result); err != nil { return err } items := result["items"].([]interface{}) if len(items) == 0 { return fmt.Errorf("Book %s not found", title) } // Get the ISBN from any of the results isbn, err := extractISBNFromResults(items) if err != nil { fmt.Printf("ISBN not found\n", isbn) } else { book.ISBN = isbn } bookInfo := items[0].(map[string]interface{})["volumeInfo"].(map[string]interface{}) book.ID = items[0].(map[string]interface{})["id"].(string) book.Title = bookInfo["title"].(string) book.Author = bookInfo["authors"].([]interface{})[0].(string) book.Link = items[0].(map[string]interface{})["selfLink"].(string) if pageCount, ok := bookInfo["pageCount"].(float64); ok { book.Pages = int(pageCount) } if publishedDate, ok := bookInfo["publishedDate"].(string); ok { if len(publishedDate) >= 4 { book.Year, _ = strconv.Atoi(publishedDate[:4]) } } book.Image = getBookCoverByTitle(title) if err != nil { fmt.Printf("Image not found: %s\n", err) } return nil } func extractISBNFromResults(items []interface{}) (string, error) { // Loop over all the results and returns first ISBN found (ISBN_13 or // ISBN_10) for _, item := range items { bookInfo := item.(map[string]interface{})["volumeInfo"].(map[string]interface{}) industryIdentifiers, ok := bookInfo["industryIdentifiers"].([]interface{}) if !ok { continue } var isbn string for _, identifier := range industryIdentifiers { id := identifier.(map[string]interface{}) // Primero intentamos con ISBN_13 if id["type"] == "ISBN_13" { isbn = id["identifier"].(string) return isbn, nil } else if id["type"] == "ISBN_10" && isbn == "" { // Si no hay ISBN_13, intentamos con ISBN_10 isbn = id["identifier"].(string) return isbn, nil } } } return "", fmt.Errorf("no ISBN found in any result") } func getBookCoverByISBN(isbn string) string { openLibraryURL := fmt.Sprintf("https://covers.openlibrary.org/b/isbn/%s-L.jpg", isbn) if checkImageExists(openLibraryURL) { return openLibraryURL } amazonURL := fmt.Sprintf("https://images-na.ssl-images-amazon.com/images/P/%s.jpg", isbn) if checkImageExists(amazonURL) { return amazonURL } return "" } func getBookCoverByTitle(title string) string { apiKey := os.Getenv("GOOGLE_CUSTOM_SEARCH_ENGINE_API_KEY") cx := os.Getenv("GOOGLE_CX") searchURL := fmt.Sprintf("https://www.googleapis.com/customsearch/v1?q=%s+book+cover&key=%s&searchType=image&num=1&cx=%s", url.QueryEscape(title), apiKey, cx) resp, err := http.Get(searchURL) if err != nil { fmt.Printf("Error fetching cover from Google Images API: %s\n", err) return "default-cover.jpg" } defer resp.Body.Close() if resp.StatusCode != http.StatusOK { fmt.Printf("Error fetching cover, status code: %d\n", resp.StatusCode) return "default-cover.jpg" } var result map[string]interface{} if err := json.NewDecoder(resp.Body).Decode(&result); err != nil { fmt.Printf("Error decoding JSON response: %s\n", err) return "default-cover.jpg" } if items, ok := result["items"].([]interface{}); ok && len(items) > 0 { if link, ok := items[0].(map[string]interface{})["link"].(string); ok { return link } } return "default-cover.jpg" } func checkImageExists(imageURL string) bool { resp, err := http.Head(imageURL) if err != nil || resp.StatusCode != http.StatusOK { return false } return true } func DownloadImage(url, slug string) error { imageDir := filepath.Join(os.Getenv("MARKDOWN_OUTPUT_BOOKS_DIR"), os.Getenv("IMAGES_OUTPUT_DIR")) if err := utils.CreateDirIfNotExists(imageDir); err != nil { return err } filename := fmt.Sprintf("%s.jpg", slug) filePath := filepath.Join(imageDir, filename) resp, err := http.Get(url) if err != nil { return fmt.Errorf("error downloading image: %w", err) } defer resp.Body.Close() if resp.StatusCode != http.StatusOK { return fmt.Errorf("non-200 response while downloading image: %d", resp.StatusCode) } file, err := os.Create(filePath) if err != nil { return fmt.Errorf("error creating image file: %w", err) } defer file.Close() body, err := ioutil.ReadAll(resp.Body) if err != nil { return fmt.Errorf("error reading image data: %w", err) } _, err = file.Write(body) if err != nil { return fmt.Errorf("error writing image data: %w", err) } fmt.Printf(" - Image saved successfully at: %s\n", filePath) return nil }