game-crawler/crawler/game.go
2024-12-28 00:10:06 +08:00

190 lines
4.8 KiB
Go
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

package crawler
import (
"errors"
"fmt"
"regexp"
"strings"
"time"
"game-crawler/db"
"game-crawler/model"
"game-crawler/utils"
"go.mongodb.org/mongo-driver/bson/primitive"
"go.mongodb.org/mongo-driver/mongo"
)
// GenerateGameInfo generates game info based on the platform and ID.
func GenerateGameInfo(platform string, id int) (*model.GameInfo, error) {
switch platform {
case "steam":
return GenerateSteamGameInfo(id)
case "igdb":
return GenerateIGDBGameInfo(id)
default:
return nil, errors.New("invalid platform type")
}
}
// OrganizeGameItem organizes the given game item and saves its associated game info to the database.
func OrganizeGameItem(game *model.GameItem) error {
hasOrganized := db.HasGameItemOrganized(game.ID)
if hasOrganized {
return nil
}
item, err := OrganizeGameItemWithIGDB(game)
if err != nil {
return err
}
// Attempt to supplement SteamID if missing
if item.SteamID == 0 {
steamID, err := GetSteamIDByIGDBID(item.IGDBID)
if err == nil {
item.SteamID = steamID
}
}
// Save the organized game info to the database
if err := db.SaveGameInfo(item); err != nil {
return err
}
return nil
}
// AddGameInfoManually manually adds a game info entry to the database.
func AddGameInfoManually(gameID primitive.ObjectID, platform string, platformID int) (*model.GameInfo, error) {
info, err := GenerateGameInfo(platform, platformID)
if err != nil {
return nil, err
}
info.GameIDs = utils.Unique(append(info.GameIDs, gameID))
if err := db.SaveGameInfo(info); err != nil {
return nil, err
}
return info, nil
}
// OrganizeGameItemManually organizes a game item manually based on the platform and platform ID.
func OrganizeGameItemManually(gameID primitive.ObjectID, platform string, platformID int) (*model.GameInfo, error) {
info, err := db.GetGameInfoByPlatformID(platform, platformID)
if err != nil {
if errors.Is(err, mongo.ErrNoDocuments) {
info, err = AddGameInfoManually(gameID, platform, platformID)
if err != nil {
return nil, err
}
} else {
return nil, err
}
}
info.GameIDs = utils.Unique(append(info.GameIDs, gameID))
// Supplement missing platform IDs
if platform == "igdb" && info.SteamID == 0 {
steamID, err := GetSteamIDByIGDBID(platformID)
if err == nil {
info.SteamID = steamID
}
}
if platform == "steam" && info.IGDBID == 0 {
igdbID, err := GetIGDBIDBySteamAppID(platformID)
if err == nil {
info.IGDBID = igdbID
}
}
if err := db.SaveGameInfo(info); err != nil {
return nil, err
}
return info, nil
}
// FormatName formats a raw game name into a clean and consistent format.
func FormatName(name string) string {
name = regexp.MustCompile(`(?i)[\w'-]+\s(Edition|Vision|Collection|Bundle|Pack|Deluxe)`).ReplaceAllString(name, " ")
name = regexp.MustCompile(`(?i)GOTY`).ReplaceAllString(name, "")
name = regexp.MustCompile(`(?i)nsw for pc`).ReplaceAllString(name, "")
name = regexp.MustCompile(`\([^)]+\)`).ReplaceAllString(name, "")
name = regexp.MustCompile(`\s+`).ReplaceAllString(name, " ")
name = strings.Replace(name, ": Remastered", "", -1)
name = strings.Replace(name, ": Remaster", "", -1)
name = strings.TrimSpace(name)
name = strings.Trim(name, ":")
return name
}
// SupplementPlatformIDToGameInfo supplements missing platform IDs (SteamID or IGDBID) for all game info entries.
func SupplementPlatformIDToGameInfo() error {
infos, err := db.GetAllGameInfos()
if err != nil {
return fmt.Errorf("failed to fetch game infos: %w", err)
}
for _, info := range infos {
changed := false
// Supplement SteamID using IGDBID
if info.IGDBID != 0 && info.SteamID == 0 {
steamID, err := GetSteamIDByIGDBID(info.IGDBID)
time.Sleep(100 * time.Millisecond)
if err == nil {
info.SteamID = steamID
changed = true
}
}
// Supplement IGDBID using SteamID
if info.SteamID != 0 && info.IGDBID == 0 {
igdbID, err := GetIGDBIDBySteamAppID(info.SteamID)
time.Sleep(100 * time.Millisecond)
if err == nil {
info.IGDBID = igdbID
changed = true
}
}
if changed {
if err := db.SaveGameInfo(info); err != nil {
return fmt.Errorf("failed to save game info: %w", err)
}
}
}
return nil
}
// UpdateGameInfo updates outdated game info entries and returns a channel to monitor updates.
func UpdateGameInfo(num int) (chan *model.GameInfo, error) {
infos, err := db.GetOutdatedGameInfos(num)
if err != nil {
return nil, fmt.Errorf("failed to fetch outdated game infos: %w", err)
}
updateChan := make(chan *model.GameInfo)
go func() {
defer close(updateChan)
for _, info := range infos {
if info.IGDBID != 0 {
newInfo, err := GenerateIGDBGameInfo(info.IGDBID)
if err != nil {
continue
}
db.MergeGameInfo(info, newInfo)
if err := db.SaveGameInfo(newInfo); err != nil {
continue
}
updateChan <- newInfo
}
}
}()
return updateChan, nil
}