Files
SteamEmuUtility/ViewModels/DlcManagerViewModels.cs
2025-03-24 20:06:57 +07:00

385 lines
12 KiB
C#

using ImageCommon;
using Playnite.SDK;
using Playnite.SDK.Data;
using Playnite.SDK.Models;
using PluginsCommon;
using SteamCommon;
using SteamCommon.Models;
using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.IO;
using System.Linq;
using System.Threading;
using System.Threading.Tasks;
using System.Windows.Media.Imaging;
namespace SteamEmuUtility.ViewModels
{
class DlcManagerViewModels : ObservableObject, IDisposable
{
private object _dlcListLock = new object();
private bool disposed = false;
public void Dispose()
{
Dispose(true);
GC.SuppressFinalize(this);
}
protected virtual void Dispose(bool disposing)
{
if (disposed)
return;
if (disposing)
{
if (DLCList.Any())
{
FileSystem.WriteStringToFile(dlcPath, Serialization.ToJson(DLCList, true));
}
cancellationTokenSource.Cancel();
taskRunning = false;
lock (_dlcListLock)
{
foreach (var item in DLCList)
{
item.Dispose();
}
DLCList.Clear(); // Clear the DLCList
}
steam.Callbacks.OnAppCallback -= onAppCallback;
steam.Callbacks.OnProgressUpdate -= onProgressUpdate;
steam.Dispose();
cancellationTokenSource.Dispose();
}
disposed = true;
}
~DlcManagerViewModels()
{
Dispose(false);
}
private const string steamItemAssetsUrl = "https://shared.cloudflare.steamstatic.com/store_item_assets/steam/apps/{0}";
private CancellationTokenSource cancellationTokenSource;
private SteamService steam;
private string dlcPath;
private readonly Game game;
private readonly IPlayniteAPI PlayniteApi;
private readonly string apiKey;
private readonly string pluginPath;
private bool taskRunning;
public DlcManagerViewModels(IPlayniteAPI api, Game game, string apiKey, string pluginPath)
{
EmptyImage = ImageUtilites.CreateQuestionMarkImage(231, 87);
DLCList = new ObservableCollection<DlcInfo>();
cancellationTokenSource = new CancellationTokenSource();
PlayniteApi = api;
this.game = game;
this.apiKey = apiKey;
this.pluginPath = pluginPath;
dlcPath = Path.Combine(pluginPath, "GamesInfo", $"{game.GameId}.json");
steam = new SteamService();
steam.Callbacks.OnAppCallback += onAppCallback;
steam.Callbacks.OnProgressUpdate += onProgressUpdate;
LoadDlcListAsync();
}
private bool enableAll;
public bool EnableAll
{
get => enableAll;
set
{
if (enableAll != value)
{
enableAll = value;
OnPropertyChanged();
DLCList.ForEach(x => x.Enable = value);
}
}
}
private int totalItems;
private int currentProgress;
private double progressPercentage;
private string progressText;
public string ProgressText
{
get => progressText;
set
{
progressText = value;
OnPropertyChanged();
}
}
private bool isProgressBarVisible = true;
public bool IsProgressBarVisible
{
get => isProgressBarVisible;
set
{
isProgressBarVisible = value;
OnPropertyChanged();
}
}
public int TotalItems
{
get => totalItems;
set
{
totalItems = value;
OnPropertyChanged();
}
}
public int CurrentProgress
{
get => currentProgress;
set
{
currentProgress = value;
OnPropertyChanged();
UpdateProgressPercentage();
}
}
public double ProgressPercentage
{
get => progressPercentage;
set
{
progressPercentage = value;
OnPropertyChanged();
}
}
private bool isIndeterminate = true;
public bool IsIndeterminate
{
get { return isIndeterminate; }
set
{
OnPropertyChanged();
isIndeterminate = value;
}
}
private BitmapImage EmptyImage { get; }
private ObservableCollection<DlcInfo> _dlcList;
public ObservableCollection<DlcInfo> DLCList
{
get => _dlcList;
set
{
_dlcList = value;
OnPropertyChanged();
}
}
void ProcessDLCAsync()
{
taskRunning = true;
IsIndeterminate = false;
TotalItems = DLCList.Count;
CurrentProgress = 0;
IEnumerable<DlcInfo> app = null;
lock (_dlcListLock)
{
app = new ObservableCollection<DlcInfo>(DLCList);
}
foreach (var x in app)
{
if (cancellationTokenSource.IsCancellationRequested)
{
taskRunning = false;
break;
}
var thedlc = DLCList.FirstOrDefault(s => s.Appid == x.Appid);
if (string.IsNullOrEmpty(thedlc.ImageURL))
{
thedlc.Image = EmptyImage;
}
else
{
ProgressText = string.Format(ResourceProvider.GetString("LOCSEU_FetchingImages"), thedlc.Name);
string imagePath = Path.Combine(pluginPath, "GamesInfo", "Assets", game.GameId, $"{thedlc.Appid.ToString()}.jpg");
if (FileSystem.FileExists(imagePath))
{
// dont call UIDispatcher to invoke, since LoadImageFromFile do bitmap.Freeze which thread-safe
thedlc.Image = ImageUtilites.LoadImageFromFile(imagePath);
continue;
}
else
{
string url = string.Format(steamItemAssetsUrl, thedlc.Appid + "//" + thedlc.ImageURL);
var image = ImageUtilites.DownloadImage(url);
ImageUtilites.SaveImage(imagePath, image);
thedlc.Image = image;
thedlc.ImagePath = imagePath;
}
}
CurrentProgress++;
}
IsProgressBarVisible = false;
taskRunning = false;
}
void onAppCallback(App app)
{
string name = !string.IsNullOrEmpty(app?.Name) ? app.Name : "Unknown App";
var newDlc = new DlcInfo
{
Appid = app.Appid,
Name = name,
Image = EmptyImage
};
PlayniteApi.MainView.UIDispatcher.Invoke(() =>
{
lock (_dlcListLock)
{
DLCList.Add(newDlc);
ProgressText = string.Format(ResourceProvider.GetString("LOCSEU_Adding"), name);
}
});
if (!string.IsNullOrEmpty(app?.SmallCapsuleImage?.English))
{
string filePath = Path.Combine(pluginPath, "GamesInfo", "Assets", game.GameId, $"{app.Appid}.jpg");
newDlc.ImageURL = app.SmallCapsuleImage?.English;
newDlc.ImagePath = filePath;
}
}
void onProgressUpdate(string text)
{
ProgressText = text;
}
private void LoadDlcListAsync()
{
Task.Run(() =>
{
if (FileSystem.FileExists(dlcPath))
{
if (Serialization.TryFromJsonFile(dlcPath, out ObservableCollection<DlcInfo> result) && result?.Count >= 1)
{
result.ForEach(x => x.Image = EmptyImage);
DLCList = result;
ProcessDLCAsync();
return;
}
else if (Serialization.TryFromJsonFile(dlcPath, out dynamic dynamicdata))
{
// use try-catch block if json is present but empty key is missing or json is modified
try
{
if (dynamicdata.empty != null)
{
IsProgressBarVisible = false;
return;
}
}
catch { }
}
}
GetDLCList();
}, cancellationTokenSource.Token);
}
private void GetDLCList()
{
taskRunning = true;
IsProgressBarVisible = true;
IsIndeterminate = true;
uint appid = uint.Parse(game.GameId);
ProgressText = ResourceProvider.GetString("LOCSEU_GettingDlcList");
var DLCs = SteamUtilities.GetDLC(game.GameId, steam, apiKey: apiKey, pluginPath: pluginPath).ToList();
TotalItems = DLCs.Count;
CurrentProgress = 0;
ProgressText = ResourceProvider.GetString("LOCSEU_GettingDlcInfo");
SteamUtilities.GetApp(DLCs, steam);
if (DLCList.Any())
{
FileSystem.WriteStringToFile(dlcPath, Serialization.ToJson(DLCList, true));
}
else
{
var empty = new
{
empty = string.Empty,
};
FileSystem.WriteStringToFile(dlcPath, Serialization.ToJson(empty, true));
}
ProcessDLCAsync();
}
private void UpdateProgressPercentage()
{
if (TotalItems > 0)
{
ProgressPercentage = Math.Round((double)CurrentProgress / TotalItems * 100, 2);
}
else
{
ProgressPercentage = 0;
}
}
public RelayCommand Refresh
{
get => new RelayCommand(async () =>
{
if (!steam.connected)
{
steam.Callbacks.OnAppCallback -= onAppCallback;
steam.Callbacks.OnProgressUpdate -= onProgressUpdate;
steam.Dispose();
steam = new SteamService();
steam.Callbacks.OnAppCallback += onAppCallback;
steam.Callbacks.OnProgressUpdate += onProgressUpdate;
}
IsProgressBarVisible = false;
cancellationTokenSource.Cancel();
while (taskRunning)
{
await Task.Delay(2000);
}
cancellationTokenSource = new CancellationTokenSource();
DLCList?.Clear();
await Task.Run(() =>
{
GetDLCList();
}, cancellationTokenSource.Token);
});
}
}
}