using IGDB; using IGDB.Models; using Microsoft.Extensions.Logging; using System.Text; using LANCommander.SDK.Enums; using LANCommander.Server.Services.Models; using Company = LANCommander.Server.Data.Models.Company; namespace LANCommander.Server.Services { public class IGDBService( ILogger logger, GameService gameService, EngineService engineService, CompanyService companyService, GenreService genreService, TagService tagService) : BaseService(logger), IDisposable { private const string DefaultFields = "*"; private IGDBClient Client; public bool Authenticated = false; private string ClientId { get; set; } private string ClientSecret { get; set; } public override void Initialize() { Authenticate(); } public void Authenticate() { ClientId = _settings.IGDBClientId; ClientSecret = _settings.IGDBClientSecret; try { if (String.IsNullOrWhiteSpace(ClientId) || String.IsNullOrWhiteSpace(ClientSecret)) throw new Exception("Invalid IGDB credentials"); Client = new IGDBClient(ClientId, ClientSecret); Authenticated = true; } catch (Exception ex) { Authenticated = false; } } public async Task GetAsync(long id, params string[] additionalFields) { var fields = DefaultFields.Split(',').ToList(); fields.AddRange(additionalFields); var games = await Client.QueryAsync(IGDBClient.Endpoints.Games, $"fields {String.Join(',', fields)}; where id = {id};"); if (games == null) return null; return games.FirstOrDefault(); } public async Task> SearchAsync(string input, int limit = 10, int offset = 0, params string[] additionalFields) { var fields = DefaultFields.Split(',').ToList(); fields.AddRange(additionalFields); int[] categories = new int[] { (int)Category.MainGame, (int)Category.Port, (int)Category.StandaloneExpansion, (int)Category.Expansion, (int)Category.Mod, (int)Category.Remake, (int)Category.Remaster }; var sb = new StringBuilder(); sb.Append($"search \"{input}\";"); sb.Append($"fields {String.Join(',', fields)};"); sb.Append($"limit {limit};"); sb.Append($"offset {offset};"); sb.Append($"where category = ({String.Join(',', categories)});"); var games = await Client.QueryAsync(IGDBClient.Endpoints.Games, sb.ToString()); return games.AsEnumerable(); } public async Task ImportGameAsync(GameLookupResult result, Data.Models.Game game) { var categoryMap = new Dictionary() { { IGDB.Models.Category.MainGame, GameType.MainGame }, { IGDB.Models.Category.Expansion, GameType.Expansion }, { IGDB.Models.Category.StandaloneExpansion, GameType.StandaloneExpansion }, { IGDB.Models.Category.Mod, GameType.Mod } }; game.IGDBId = result.IGDBMetadata.Id.GetValueOrDefault(); game.Title = result.IGDBMetadata.Name; game.Description = result.IGDBMetadata.Summary; game.ReleasedOn = result.IGDBMetadata.FirstReleaseDate.GetValueOrDefault().UtcDateTime; game.MultiplayerModes = result.MultiplayerModes.ToList(); if (categoryMap.Keys.Contains(result.IGDBMetadata.Category.GetValueOrDefault())) game.Type = categoryMap[result.IGDBMetadata.Category.GetValueOrDefault()]; if (result.IGDBMetadata.GameModes != null && result.IGDBMetadata.GameModes.Values != null) game.Singleplayer = result.IGDBMetadata.GameModes.Values.Any(gm => gm.Name == "Single player"); if (game.Id == Guid.Empty) game = await gameService.AddAsync(game); else game = await gameService.UpdateAsync(game); if (result.IGDBMetadata.ParentGame != null && result.IGDBMetadata.ParentGame.Id.HasValue) { var baseGame = await gameService.FirstOrDefaultAsync(g => g.IGDBId == result.IGDBMetadata.ParentGame.Id); if (baseGame != null) game.BaseGame = baseGame; } #region Engine if (result.IGDBMetadata.GameEngines != null && result.IGDBMetadata.GameEngines.Values != null) { var engineMetadata = result.IGDBMetadata.GameEngines.Values.FirstOrDefault(); var engine = await engineService.AddMissingAsync(e => e.Name == engineMetadata.Name, new Data.Models.Engine { Name = engineMetadata.Name }); game.Engine = engine.Value; } #endregion #region Companies if (result.IGDBMetadata.InvolvedCompanies != null && result.IGDBMetadata.InvolvedCompanies.Values != null) { var developers = result.IGDBMetadata.InvolvedCompanies.Values.Where(c => c.Developer.GetValueOrDefault()).Select(c => c.Company.Value.Name); var publishers = result.IGDBMetadata.InvolvedCompanies.Values.Where(c => c.Publisher.GetValueOrDefault()).Select(c => c.Company.Value.Name); var companies = developers.Concat(publishers).Distinct().ToList(); foreach (var company in companies) { var companyEntity = await companyService.FirstOrDefaultAsync(c => c.Name == company); if (companyEntity == null) { companyEntity = await companyService.AddAsync(new Company() { Name = company, }); } if (game.Developers == null) game.Developers = new List(); if (game.Publishers == null) game.Publishers = new List(); if (developers.Contains(company) && !game.Developers.Any(p => p.Id == companyEntity.Id)) game.Developers.Add(companyEntity); if (publishers.Contains(company) && !game.Publishers.Any(p => p.Id == companyEntity.Id)) game.Publishers.Add(companyEntity); } } #endregion #region Genres if (result.IGDBMetadata.Genres != null && result.IGDBMetadata.Genres.Values != null) { var genres = result.IGDBMetadata.Genres.Values.Select(g => g.Name); if (game.Genres == null) game.Genres = new List(); foreach (var genre in genres) { var genreEntity = await genreService.AddMissingAsync(g => g.Name == genre, new Data.Models.Genre { Name = genre }); if (!game.Genres.Any(g => g.Id == genreEntity.Value.Id)) game.Genres.Add(genreEntity.Value); } } #endregion #region Tags if (result.IGDBMetadata.Keywords != null && result.IGDBMetadata.Keywords.Values != null) { var tags = result.IGDBMetadata.Keywords.Values.Select(t => t.Name); if (game.Tags == null) game.Tags = new List(); foreach (var tag in tags) { var tagEntity = await tagService.AddMissingAsync(t => t.Name == tag, new Data.Models.Tag { Name = tag }); if (!game.Tags.Any(t => t.Id == tagEntity.Value.Id)) game.Tags.Add(tagEntity.Value); } } #endregion return await gameService.UpdateAsync(game); } public void Dispose() { } } }