SteamGameTimeTrack/API/Tracker.cs

228 lines
7.8 KiB
C#

using System.Globalization;
using log4net;
using SQLiteEF;
using SteamApiWrapper.ReturnTypes;
using SteamGame = SteamApiWrapper.ReturnTypes.Game;
using Player = SQLiteEF.Player;
using SteamPlayer = SteamApiWrapper.ReturnTypes.Player;
using Steam = SteamApiWrapper.SteamApiWrapper;
namespace API;
public class Tracker : IDisposable
{
private readonly Thread _trackerThread;
private bool _running = true;
private ILog Log { get; } = LogManager.GetLogger(typeof(Tracker));
private TimeSpan Interval { get; init; }
public Tracker(IServiceProvider serviceProvider, IConfiguration configuration)
{
Interval = TimeSpan.Parse(configuration.GetValue<string>("UpdateInterval")!, CultureInfo.InvariantCulture);
_trackerThread = new (TrackerLoop);
_trackerThread.Start(serviceProvider);
}
internal void UpdatePlayers(Context context)
{
Log.Info("Updating Players");
Player[] dbPlayers = context.Players.ToArray();
SteamPlayer[] summaries = Steam.GetPlayerSummaries(dbPlayers.Select(p => p.SteamId).ToArray());
foreach (Player dbPlayer in dbPlayers)
{
if(summaries.All(summaryPlayer => summaryPlayer.steamid != dbPlayer.SteamId))
continue;
SteamPlayer summaryPlayer = summaries.First(summaryPlayer => summaryPlayer.steamid == dbPlayer.SteamId);
try
{
dbPlayer.Name = summaryPlayer.personaname;
dbPlayer.AvatarUrl = summaryPlayer.avatar;
dbPlayer.ProfileUrl = summaryPlayer.profileurl;
dbPlayer.UpdatedAt = DateTime.UtcNow;
context.SaveChanges();
}
catch (Exception e)
{
Log.Error(e);
}
}
}
internal void UpdatePlayer(Context context, Player player)
{
SteamPlayer[] summaries = Steam.GetPlayerSummaries([player.SteamId]);
if(summaries.All(summaryPlayer => summaryPlayer.steamid != player.SteamId))
return;
SteamPlayer summaryPlayer = summaries.First(summaryPlayer => summaryPlayer.steamid == player.SteamId);
try
{
player.Name = summaryPlayer.personaname;
player.AvatarUrl = summaryPlayer.avatar;
player.ProfileUrl = summaryPlayer.profileurl;
player.UpdatedAt = DateTime.UtcNow;
context.SaveChanges();
}
catch (Exception e)
{
Log.Error(e);
}
}
internal void UpdateOwnedGames(Context context)
{
Log.Info("Updating Owned Games");
Player[] players = context.Players.ToArray();
foreach (Player player in players)
{
UpdateOwnedGamesPlayer(context, player);
}
}
internal void UpdateOwnedGamesPlayer(Context context, Player player)
{
Log.Debug($"Updating owned games for player {player}");
SteamGame[] ownedGames = Steam.GetOwnedGames(player.SteamId);
foreach (SteamGame ownedGame in ownedGames)
{
string? iconUrlStr = ownedGame.img_icon_url is not null
? $"http://media.steampowered.com/steamcommunity/public/images/apps/{ownedGame.appid}/{ownedGame.img_icon_url}.jpg"
: null;
string? logoUrlStr = ownedGame.img_logo_url is not null
? $"http://media.steampowered.com/steamcommunity/public/images/apps/{ownedGame.appid}/{ownedGame.img_logo_url}.jpg"
: null;
if (context.Games.Find(ownedGame.appid) is not { } game)
{
game = new(ownedGame.appid, ownedGame.name, iconUrlStr, logoUrlStr);
context.Games.Add(game);
}
else
{
game.Name = ownedGame.name;
game.IconUrl = iconUrlStr;
game.LogoUrl = logoUrlStr;
}
if (!player.Games.Contains(game))
{
context.Entry(player).Collection(p => p.Games).Load();
player.Games.Add(game);
context.Entry(game).Collection(g => g.PlayedBy).Load();
game.PlayedBy.Add(player);
context.Entry(player).Collection(p => p.TrackedTimes).Load();
player.TrackedTimes.Add(new (game, player, ownedGame.playtime_forever));
}
try
{
context.SaveChanges();
}
catch (Exception e)
{
Log.Error(e);
}
}
}
internal void UpdateGameTimes(Context context)
{
Log.Info("Updating Game Times");
Player[] players = context.Players.ToArray();
foreach (Player player in players)
{
UpdateGameTimesPlayer(context, player);
}
}
internal void UpdateGameTimesPlayer(Context context, Player player)
{
Log.Debug($"Updating game times for player {player}");
GetRecentlyPlayedGames recentlyPlayed = Steam.GetRecentlyPlayedGames(player.SteamId);
if (recentlyPlayed.total_count < 1)
return;
foreach (SteamGame recentlyPlayedGame in recentlyPlayed.games)
{
string? iconUrlStr = recentlyPlayedGame.img_icon_url is not null
? $"http://media.steampowered.com/steamcommunity/public/images/apps/{recentlyPlayedGame.appid}/{recentlyPlayedGame.img_icon_url}.jpg"
: null;
string? logoUrlStr = recentlyPlayedGame.img_logo_url is not null
? $"http://media.steampowered.com/steamcommunity/public/images/apps/{recentlyPlayedGame.appid}/{recentlyPlayedGame.img_logo_url}.jpg"
: null;
if (context.Games.Find(recentlyPlayedGame.appid) is not { } game)
{
game = new(recentlyPlayedGame.appid, recentlyPlayedGame.name, iconUrlStr, logoUrlStr);
context.Games.Add(game);
}
else
{
game.Name = recentlyPlayedGame.name;
game.IconUrl = iconUrlStr;
game.LogoUrl = logoUrlStr;
}
if (!player.Games.Contains(game))
{
context.Entry(player).Collection(p => p.Games).Load();
player.Games.Add(game);
context.Entry(game).Collection(g => g.PlayedBy).Load();
game.PlayedBy.Add(player);
}
context.Entry(player).Collection(p => p.TrackedTimes).Load();
player.TrackedTimes.Add(new (game, player, recentlyPlayedGame.playtime_forever));
try
{
context.SaveChanges();
}
catch (Exception e)
{
Log.Error(e);
}
}
}
private void TrackerLoop(object? obj)
{
if (obj is not IServiceProvider serviceProvider)
{
Log.Fatal("Tracker loop wasn't started.");
return;
}
while (_running)
{
IServiceScope scope = serviceProvider.CreateScope();
Context context = scope.ServiceProvider.GetRequiredService<Context>();
UpdatePlayers(context);
UpdateOwnedGames(context);
UpdateGameTimes(context);
scope.Dispose();
try
{
Thread.Sleep(Interval);
}
catch (ThreadInterruptedException)
{
Log.Debug("Thread interrupted");
}
catch (ThreadAbortException)
{
_running = false;
}
}
Log.Info("Thread exited");
}
public void ForceLoop()
{
_trackerThread.Interrupt();
}
public void Dispose()
{
_running = false;
_trackerThread.Interrupt();
}
}