190 lines
4.8 KiB
Go
190 lines
4.8 KiB
Go
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
|
||
}
|