236 lines
5.7 KiB
Go
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
|
||
|
}
|