hugo-medialog/internal/games/api_igdb.go
2024-10-10 20:03:49 +02:00

236 lines
5.7 KiB
Go

package games
import (
"bytes"
"encoding/json"
"fmt"
"hugo-medialog/utils"
"io/ioutil"
"net/http"
"net/url"
"os"
"path/filepath"
"strings"
"time"
)
type TokenResponse struct {
AccessToken string `json:"access_token"`
ExpiresIn int `json:"expires_in"`
TokenType string `json:"token_type"`
}
func getAccessToken() (string, error) {
clientID := os.Getenv("TWITCH_CLIENT_ID")
clientSecret := os.Getenv("TWITCH_SECRET_ID")
authURL := "https://id.twitch.tv/oauth2/token"
data := url.Values{}
data.Set("client_id", clientID)
data.Set("client_secret", clientSecret)
data.Set("grant_type", "client_credentials")
req, err := http.NewRequest("POST", authURL, strings.NewReader(data.Encode()))
if err != nil {
return "", err
}
req.Header.Set("Content-Type", "application/x-www-form-urlencoded")
client := &http.Client{Timeout: 10 * time.Second}
resp, err := client.Do(req)
if err != nil {
return "", err
}
defer resp.Body.Close()
if resp.StatusCode != http.StatusOK {
return "", fmt.Errorf("error: non-200 response code: %d", resp.StatusCode)
}
var tokenResp TokenResponse
if err := json.NewDecoder(resp.Body).Decode(&tokenResp); err != nil {
return "", err
}
return tokenResp.AccessToken, nil
}
func SearchGameByTitle(title string, game *Game) error {
clientID := os.Getenv("TWITCH_CLIENT_ID")
accessToken, err := getAccessToken()
if err != nil {
fmt.Printf("Error getting access token: %v\n", err)
return err
}
url := "https://api.igdb.com/v4/games"
query := fmt.Sprintf("search \"%s\";\nfields id,name,slug,cover,artworks,first_release_date,genres,platforms,screenshots,slug,url;\n", title)
req, err := http.NewRequest("POST", url, bytes.NewBuffer([]byte(query)))
if err != nil {
return err
}
req.Header.Set("Client-ID", clientID)
req.Header.Set("Authorization", "Bearer "+accessToken)
req.Header.Set("Content-Type", "text/plain")
client := &http.Client{Timeout: 10 * time.Second}
resp, err := client.Do(req)
if err != nil {
return err
}
defer resp.Body.Close()
body, err := ioutil.ReadAll(resp.Body)
if err != nil {
return err
}
var games []map[string]interface{}
if err := json.Unmarshal(body, &games); err != nil {
return err
}
if len(games) == 0 {
return fmt.Errorf("No games found")
}
first_game := games[0]
// Timestamp
if timestamp, ok := first_game["first_release_date"].(float64); ok {
game.Year = time.Unix(int64(timestamp), 0).Format("2006")
game.Subtitle = game.Year
}
// Cover
coverID := first_game["cover"].(float64)
coverURL, err := makeRequest("covers", coverID)
if err != nil {
fmt.Printf("Err: %s", err)
}
game.Image = coverURL
// Artwork
if artworks, ok := first_game["artworks"].([]interface{}); ok && len(artworks) > 0 {
artworkURL, err := makeRequest("artworks", artworks[0].(float64))
if err != nil {
fmt.Printf("Err: %s", err)
}
game.Poster = artworkURL
}
// Screenshots
if screenshots, ok := first_game["screenshots"].([]interface{}); ok && len(screenshots) > 0 {
artworkURL, err := makeRequest("screenshots", screenshots[0].(float64))
if err != nil {
fmt.Printf("Err: %s", err)
}
game.Background = artworkURL
}
game.ID = int(first_game["id"].(float64))
game.Link = first_game["url"].(string)
return nil
}
func getImageURL(imageID int, size string) string {
return fmt.Sprintf("https://images.igdb.com/igdb/image/upload/t_%s/%d.jpg", size, imageID)
}
// Function to make requests to IGDB
func makeRequest(endpoint string, id float64) (string, error) {
clientID := os.Getenv("TWITCH_CLIENT_ID")
accessToken, err := getAccessToken()
if err != nil {
fmt.Printf("Error getting access token: %v\n", err)
return "", err
}
// Create the request body
idStr := fmt.Sprint(id)
body := fmt.Sprintf("fields id, image_id; where id = (%s);", idStr)
req, err := http.NewRequest("POST", "https://api.igdb.com/v4/"+endpoint, strings.NewReader(body))
if err != nil {
return "", err
}
// Add headers
req.Header.Add("Client-ID", clientID)
req.Header.Add("Authorization", "Bearer "+accessToken)
req.Header.Add("Content-Type", "application/x-www-form-urlencoded")
// Send the request
client := &http.Client{}
resp, err := client.Do(req)
if err != nil {
return "", err
}
defer resp.Body.Close()
// Read the response
responseData, err := ioutil.ReadAll(resp.Body)
if err != nil {
return "", err
}
// Parse the response
var coverResponse []map[string]interface{}
err = json.Unmarshal(responseData, &coverResponse)
if err != nil {
return "", err
}
// Get the image_id and construct the URL
if len(coverResponse) > 0 {
imageID := coverResponse[0]["image_id"].(string)
coverURL := fmt.Sprintf("https://images.igdb.com/igdb/image/upload/t_original/%s.jpg", imageID)
return coverURL, nil
}
return "", fmt.Errorf("no image found for ID %d", id)
}
func DownloadImage(url, slug, suffix string) error {
imageDir := filepath.Join(os.Getenv("MARKDOWN_OUTPUT_GAMES_DIR"), os.Getenv("IMAGES_OUTPUT_DIR"))
if err := utils.CreateDirIfNotExists(imageDir); err != nil {
return err
}
filename := fmt.Sprintf("%s%s.jpg", slug, suffix)
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
}