Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
9 changes: 8 additions & 1 deletion Stardrop/Models/Mod.cs
Original file line number Diff line number Diff line change
@@ -1,6 +1,10 @@
using Semver;
using Avalonia.Media.Imaging;
using Avalonia.Platform;
using Avalonia.Shared.PlatformSupport;
using Semver;
using Stardrop.Models.Data.Enums;
using Stardrop.Models.SMAPI;
using Stardrop.Utilities;
using System;
using System.Collections.Generic;
using System.ComponentModel;
Expand Down Expand Up @@ -42,6 +46,9 @@ public class Mod : INotifyPropertyChanged
private string _modPageUri { get; set; }
public string ModPageUri { get { return _modPageUri; } set { _modPageUri = value; NotifyPropertyChanged("ModPageUri"); } }
public int? NexusModId { get { return GetNexusId(); } }
private string? _nexusModThumbnailPath { get; set; }
public string? NexusModThumbnailPath { get { return _nexusModThumbnailPath; } set { _nexusModThumbnailPath = value; NexusModThumbnailFile = string.IsNullOrEmpty(value) ? null : new Bitmap(value); NotifyPropertyChanged("NexusModThumbnailFile"); } }
public Bitmap? NexusModThumbnailFile { get; set; }
private bool _isEnabled { get; set; }
public bool IsEnabled
{
Expand Down
3 changes: 3 additions & 0 deletions Stardrop/Models/Nexus/Web/ModDetails.cs
Original file line number Diff line number Diff line change
Expand Up @@ -6,5 +6,8 @@ public class ModDetails
{
[JsonPropertyName("name")]
public string? Name { get; set; }

[JsonPropertyName("picture_url")]
public string? ThumbnailUrl { get; set; }
}
}
1 change: 1 addition & 0 deletions Stardrop/Models/Settings.cs
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ public class Settings
/// </summary>
public bool AlwaysAskToDelete { get; set; } = true;
public bool ShouldAutomaticallySaveProfileChanges { get; set; } = true;
public bool ShowModThumbnails { get; set; }
public NexusServers PreferredNexusServer { get; set; } = NexusServers.NexusCDN;
public bool IsAskingBeforeAcceptingNXM { get; set; } = true;
public GameDetails GameDetails { get; set; }
Expand Down
3 changes: 3 additions & 0 deletions Stardrop/Program.cs
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
using Avalonia;
using Avalonia.ReactiveUI;
using Avalonia.Shared.PlatformSupport;
using CommandLine;
using Projektanker.Icons.Avalonia;
using Projektanker.Icons.Avalonia.MaterialDesign;
Expand Down Expand Up @@ -27,6 +28,7 @@ class Program
internal static Helper helper;
internal static Settings settings = new Settings();
internal static Translation translation = new Translation();
internal static AssetLoader assetLoader = new AssetLoader();

internal static bool onBootStartSMAPI = false;
internal static string? nxmLink = null;
Expand Down Expand Up @@ -88,6 +90,7 @@ public static void Main(string[] args)
Directory.CreateDirectory(Pathing.GetProfilesFolderPath());
Directory.CreateDirectory(Pathing.GetSelectedModsFolderPath());
Directory.CreateDirectory(Pathing.GetNexusPath());
Directory.CreateDirectory(Pathing.GetThumbnailsPath());
Directory.CreateDirectory(Pathing.GetSmapiUpgradeFolderPath());

// Verify the settings folder path is created
Expand Down
62 changes: 61 additions & 1 deletion Stardrop/Utilities/External/NexusClient.cs
Original file line number Diff line number Diff line change
Expand Up @@ -480,7 +480,6 @@ public async Task<List<Endorsement>> GetEndorsements()
return new List<Endorsement>();
}


public async Task<EndorsementResponse> SetModEndorsement(int modId, bool isEndorsed)
{
try
Expand Down Expand Up @@ -542,6 +541,67 @@ public async Task<EndorsementResponse> SetModEndorsement(int modId, bool isEndor
return EndorsementResponse.Unknown;
}

public async Task<string?> DownloadThumbnail(int modId)
{
try
{
var response = await _client.GetAsync($"games/stardewvalley/mods/{modId}.json");
if (response.StatusCode == System.Net.HttpStatusCode.OK && response.Content is not null)
{
string content = await response.Content.ReadAsStringAsync();
ModDetails modDetails = JsonSerializer.Deserialize<ModDetails>(content, new JsonSerializerOptions { PropertyNameCaseInsensitive = true });

if (modDetails is null)
{
Program.helper.Log($"Unable to get mod thumbnail for the mod {modId} on Nexus Mods");
Program.helper.Log($"Response from Nexus Mods:\n{content}");

return null;
}

UpdateRequestCounts(response.Headers);

if (string.IsNullOrEmpty(modDetails.ThumbnailUrl))
{
Program.helper.Log($"The mod {modId} does not have a valid thumbnail image available on Nexus Mods");
Program.helper.Log($"Response from Nexus Mods:\n{content}");
return null;
}

// Download the thumbnail
var thumbnailPath = Path.Combine(Pathing.GetThumbnailsPath(), $"{modId}{Path.GetExtension(modDetails.ThumbnailUrl)}");
using var fileStream = new FileStream(thumbnailPath, FileMode.Create, FileAccess.Write, FileShare.None, bufferSize: 8192, useAsync: true);
using var downloadStream = await _client.GetStreamAsync(modDetails.ThumbnailUrl);

await downloadStream.CopyToAsync(fileStream);
await fileStream.FlushAsync();

return thumbnailPath;
}
else
{
if (response.StatusCode != System.Net.HttpStatusCode.OK)
{
Program.helper.Log($"Bad status given from Nexus Mods: {response.StatusCode}");
if (response.Content is not null)
{
Program.helper.Log($"Response from Nexus Mods:\n{await response.Content.ReadAsStringAsync()}");
}
}
else if (response.Content is null)
{
Program.helper.Log($"No response from Nexus Mods!");
}
}
}
catch (Exception ex)
{
Program.helper.Log($"Unable to get mod thumbnail for the mod {modId} on Nexus Mods: {ex}", Helper.Status.Alert);
}

return null;
}

private void UpdateRequestCounts(HttpResponseHeaders headers)
{
if (headers.TryGetValues("x-rl-daily-limit", out var limitValues) && Int32.TryParse(limitValues.First(), out int dailyLimit))
Expand Down
5 changes: 5 additions & 0 deletions Stardrop/Utilities/Pathing.cs
Original file line number Diff line number Diff line change
Expand Up @@ -106,6 +106,11 @@ public static string GetNexusPath()
return Path.Combine(defaultHomePath, "Nexus");
}

public static string GetThumbnailsPath()
{
return Path.Combine(defaultHomePath, "Thumbnails", "Nexus");
}

public static string GetSmapiUpgradeFolderPath()
{
return Path.Combine(defaultHomePath, "SMAPI");
Expand Down
31 changes: 31 additions & 0 deletions Stardrop/ViewModels/MainWindowViewModel.cs
Original file line number Diff line number Diff line change
Expand Up @@ -75,6 +75,8 @@ public class MainWindowViewModel : ViewModelBase
public bool ShowSaveProfileChanges { get { return _showSaveProfileChanges; } set { this.RaiseAndSetIfChanged(ref _showSaveProfileChanges, value); } }
private bool _showSaveProfileChanges;
public bool AreModGroupsEnabled { get { return Program.settings.ModGroupingMethod != ModGrouping.None; } }
public bool ShowModThumbnails { get { return _showModThumbnails; } set { this.RaiseAndSetIfChanged(ref _showModThumbnails, value); } }
private bool _showModThumbnails = Program.settings.ShowModThumbnails;

public MainWindowViewModel(string modsFilePath, string version)
{
Expand Down Expand Up @@ -349,6 +351,11 @@ public void DiscoverMods(string modsFilePath)
}
}

if (Program.settings.ShowModThumbnails)
{
UpdateThumbnails();
}

// Update the local data
var modInstallData = new List<ModInstallData>();
foreach (var mod in Mods.Where(m => m is not null))
Expand Down Expand Up @@ -563,6 +570,30 @@ internal async void UpdateEndorsements()
}
}

internal async void UpdateThumbnails()
{
// Get all existing thumbnails
IEnumerable<FileInfo> nexusModThumbnails = new List<FileInfo>();
var thumbnailDirectory = new DirectoryInfo(Pathing.GetThumbnailsPath());
if (thumbnailDirectory.Exists)
{
nexusModThumbnails = thumbnailDirectory.EnumerateFiles();
}

foreach (var mod in Mods.Where(m => m.NexusModId is not null))
{
var thumbnail = nexusModThumbnails.FirstOrDefault(t => mod.NexusModId is not null && Path.GetFileNameWithoutExtension(t.Name).Equals(mod.NexusModId.ToString(), StringComparison.OrdinalIgnoreCase));
if (thumbnail is not null)
{
mod.NexusModThumbnailPath = thumbnail.FullName;
}
else if (Nexus.Client is not null && mod.NexusModThumbnailPath is null)
{
mod.NexusModThumbnailPath = await Nexus.Client.DownloadThumbnail((int)mod.NexusModId);
}
}
}

internal void ReadModConfigs(Profile profile)
{
ReadModConfigs(profile, GetPendingConfigUpdates(profile));
Expand Down
3 changes: 3 additions & 0 deletions Stardrop/ViewModels/SettingsWindowViewModel.cs
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ public class SettingsWindowViewModel : ViewModelBase
public bool EnableModsOnAdd { get { return Program.settings.EnableModsOnAdd; } set { Program.settings.EnableModsOnAdd = value; } }
public bool AlwaysAskToDelete { get { return Program.settings.AlwaysAskToDelete; } set { Program.settings.AlwaysAskToDelete = value; } }
public bool ShouldAutomaticallySaveProfileChanges { get { return Program.settings.ShouldAutomaticallySaveProfileChanges; } set { Program.settings.ShouldAutomaticallySaveProfileChanges = value; } }
public bool ShowModThumbnails { get { return Program.settings.ShowModThumbnails; } set { Program.settings.ShowModThumbnails = value; } }

// Tooltips
public string ToolTip_SMAPI { get; set; }
Expand All @@ -31,6 +32,7 @@ public class SettingsWindowViewModel : ViewModelBase
public string ToolTip_EnableProfileSpecificModConfigs { get; set; }
public string ToolTip_EnableModsOnAdd { get; set; }
public string ToolTip_ShouldAutomaticallySaveProfileChanges { get; set; }
public string ToolTip_ShowModThumbnails { get; set; }
public string ToolTip_Save { get; set; }
public string ToolTip_Cancel { get; set; }

Expand All @@ -54,6 +56,7 @@ public SettingsWindowViewModel()
ToolTip_EnableProfileSpecificModConfigs = Program.translation.Get("ui.settings_window.tooltips.enable_profile_specific_configs");
ToolTip_EnableModsOnAdd = Program.translation.Get("ui.settings_window.tooltips.enable_mods_on_add");
ToolTip_ShouldAutomaticallySaveProfileChanges = Program.translation.Get("ui.settings_window.tooltips.automatically_save_profile_changes");
ToolTip_ShowModThumbnails = Program.translation.Get("ui.settings_window.tooltips.show_mod_thumbnails");
ToolTip_Save = Program.translation.Get("ui.settings_window.tooltips.save_changes");
ToolTip_Cancel = Program.translation.Get("ui.settings_window.tooltips.cancel_changes");

Expand Down
7 changes: 7 additions & 0 deletions Stardrop/Views/MainWindow.axaml
Original file line number Diff line number Diff line change
Expand Up @@ -502,6 +502,13 @@
</Style>
</DataGrid.Styles>
<DataGrid.Columns>
<DataGridTemplateColumn IsVisible="{Binding ShowModThumbnails}" Header="" Width="150" CanUserResize="False" CanUserSort="False">
<DataGridTemplateColumn.CellTemplate>
<DataTemplate>
<Image Height="125" Width="125" Source="{Binding NexusModThumbnailFile}" Stretch="Uniform" />
</DataTemplate>
</DataGridTemplateColumn.CellTemplate>
</DataGridTemplateColumn>
<DataGridTemplateColumn Header="{i18n:Translate ui.main_window.menu_headers.enabled}" Width="25" CanUserResize="False" CanUserSort="True" SortMemberPath="IsEnabled">
<DataGridTemplateColumn.CellTemplate>
<DataTemplate>
Expand Down
7 changes: 7 additions & 0 deletions Stardrop/Views/MainWindow.axaml.cs
Original file line number Diff line number Diff line change
Expand Up @@ -1247,6 +1247,7 @@ private async Task DisplaySettingsWindow()
await HandleModListRefresh();

_viewModel.ShowSaveProfileChanges = !Program.settings.ShouldAutomaticallySaveProfileChanges;
_viewModel.ShowModThumbnails = Program.settings.ShowModThumbnails;
}
}

Expand Down Expand Up @@ -2012,6 +2013,12 @@ private async Task CheckForNexusConnection()
// Show endorsements
_viewModel.ShowEndorsements = true;

// Show thumbnails
if (Program.settings.ShowModThumbnails)
{
_viewModel.UpdateThumbnails();
}

// Show Nexus mod download column, if user is premium
_viewModel.ShowInstalls = Program.settings.NexusDetails.IsPremium;
}
Expand Down
1 change: 1 addition & 0 deletions Stardrop/Views/SettingsWindow.axaml
Original file line number Diff line number Diff line change
Expand Up @@ -218,6 +218,7 @@
<CheckBox Name="enableModsOnAdd" IsChecked="{Binding EnableModsOnAdd}" Content="{i18n:Translate ui.settings_window.buttons.enable_mods_on_add}" ToolTip.Tip="{Binding ToolTip_EnableModsOnAdd}" VerticalAlignment="Center" HorizontalAlignment="Left" Foreground="{DynamicResource ThemeForegroundBrush}" />
<CheckBox Name="alwaysAskToDelete" IsChecked="{Binding AlwaysAskToDelete}" Content="{i18n:Translate ui.settings_window.buttons.always_ask_to_delete}" ToolTip.Tip="{Binding ToolTip_AlwaysAskToDelete}" VerticalAlignment="Center" HorizontalAlignment="Left" Foreground="{DynamicResource ThemeForegroundBrush}" />
<CheckBox Name="automaticallySaveProfileChanges" IsChecked="{Binding ShouldAutomaticallySaveProfileChanges}" Content="{i18n:Translate ui.settings_window.buttons.automatically_save_profile_changes}" ToolTip.Tip="{Binding ToolTip_ShouldAutomaticallySaveProfileChanges}" VerticalAlignment="Center" HorizontalAlignment="Left" Foreground="{DynamicResource ThemeForegroundBrush}" />
<CheckBox Name="showModThumbnails" IsChecked="{Binding ShowModThumbnails}" Content="{i18n:Translate ui.settings_window.buttons.show_mod_thumbnails}" ToolTip.Tip="{Binding ToolTip_ShowModThumbnails}" VerticalAlignment="Center" HorizontalAlignment="Left" Foreground="{DynamicResource ThemeForegroundBrush}" />
</StackPanel>
</StackPanel>
</ScrollViewer>
Expand Down
2 changes: 2 additions & 0 deletions Stardrop/i18n/default.json
Original file line number Diff line number Diff line change
Expand Up @@ -115,6 +115,7 @@
"ui.settings_window.buttons.enable_mods_on_add": "Automatically Enable Mods On Install",
"ui.settings_window.buttons.always_ask_to_delete": "Always Ask To Delete Mod Files On Update",
"ui.settings_window.buttons.automatically_save_profile_changes": "Automatically Save Profile Changes",
"ui.settings_window.buttons.show_mod_thumbnails": "Show Mod Thumbnails",
"ui.settings_window.buttons.always_ask_for_NXM_installs": "Always Ask Before Installing NXM Files",
"ui.settings_window.buttons.register_nxm_association": "Register NXM Association",

Expand All @@ -132,6 +133,7 @@
"ui.settings_window.tooltips.enable_mods_on_add": "If checked, Stardrop will automatically enable newly added or updated mods",
"ui.settings_window.tooltips.always_ask_to_delete": "If checked, Stardrop will always ask whether to delete mod files when updating the mod",
"ui.settings_window.tooltips.automatically_save_profile_changes": "If checked, Stardrop will automatically save changes made to the profile",
"ui.settings_window.tooltips.show_mod_thumbnails": "If checked, displays the mod's thumbnail from Nexus Mods (where applicable).\n\nRequires a Stardrop API key from Nexus Mods.'",
"ui.settings_window.tooltips.preferred_server": "Sets your preferred server to use when downloading from Nexus Mods",
"ui.settings_window.tooltips.save_changes": "Save Changes",
"ui.settings_window.tooltips.cancel_changes": "Cancel",
Expand Down
Loading