Skip to content
Open
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
Original file line number Diff line number Diff line change
@@ -0,0 +1,119 @@
using SteamShortcuts.Domain.ValueObjects;
using SteamCommon;
using System.Threading;
using System.Threading.Tasks;
using SteamShortcuts.Infrastructure;
using System.Diagnostics;
using Playnite.SDK;

namespace SteamShortcuts.Application
{
public class DiscoverSupportedFeaturesService
{
private class ResponseCache
{
public string steamId;
public SupportedFeatures feature;

public ResponseCache() { }
public ResponseCache(string steamId, SupportedFeatures feature)
{
this.steamId = steamId;
this.feature = feature;
}
}

private static readonly object _lock = new object();
private static CancellationTokenSource _cts;
private static string _runningSteamId = null;
private static Task<ResponseCache> _runningRequestTask = Task.FromResult((ResponseCache)null);
private static ResponseCache _cache = new ResponseCache();

public SupportedFeatures GetCachedFeature(string steamId)
{
if (_cache is null)
{
return null;
}

if (steamId == _cache.steamId)
{
return _cache.feature;
}

return null;
}

public async Task<SupportedFeatures> GetFeatures(string steamId)
{
Task<ResponseCache> task;
lock (_lock)
{
if (_cache != null && steamId == _cache.steamId)
{
return _cache.feature;
}

CancellationToken cancelToken;
if (_runningRequestTask.IsCompleted || steamId != _runningSteamId)
{
_cts?.Cancel();
_cts?.Dispose();
_cts = new CancellationTokenSource();
cancelToken = _cts.Token;
_runningSteamId = steamId;
_runningRequestTask = SendRequest(steamId, cancelToken);
}

task = _runningRequestTask;
}

return (await task)?.feature;
}

private async Task<ResponseCache> SendRequest(string steamId, CancellationToken cancelToken)
{
var t1 = Task.Run(() => {
return SteamWeb.GetSteamAppDetails(steamId, cancelToken);
});

var t2 = QueryRewardItems.GetPointsShopCount(steamId, cancelToken);

var appDetails = await t1;
var pointsShopCount = await t2;

if (appDetails == null || pointsShopCount == null)
{
return null;
}

var achievements = false;
var workshop = false;

if (appDetails.success)
{
foreach (var category in appDetails.data.categories)
{
switch (category.id)
{
case 22:
achievements = true;
break;
case 30:
workshop = true;
break;
}
}
}

_cache = new ResponseCache(steamId, new SupportedFeatures
{
Achievements = achievements,
Workshop = workshop,
PointsShop = pointsShopCount.response.total_count > 0,
});

return _cache;
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,8 @@ public class SteamUriLauncherService
{ SteamUrlType.Guides, "https://steamcommunity.com/app/{0}/guides/" },
{ SteamUrlType.Achievements, "https://steamcommunity.com/stats/{0}/achievements/" },
{ SteamUrlType.News, "https://store.steampowered.com/news/?appids={0}" },
{ SteamUrlType.PointsShop, "https://store.steampowered.com/points/shop/app/{0}" }
{ SteamUrlType.PointsShop, "https://store.steampowered.com/points/shop/app/{0}" },
{ SteamUrlType.Workshop, "https://steamcommunity.com/app/{0}/workshop" }
};

private static readonly Dictionary<SteamComponentType, string> _steamComponentTemplates = new Dictionary<SteamComponentType, string>()
Expand Down
3 changes: 2 additions & 1 deletion source/Generic/SteamViewer/Domain/Enums/SteamUrlType.cs
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ public enum SteamUrlType
Guides,
Achievements,
News,
PointsShop
PointsShop,
Workshop
}
}
13 changes: 13 additions & 0 deletions source/Generic/SteamViewer/Domain/ValueObjects/PointsShopCount.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
namespace SteamShortcuts.Domain.ValueObjects
{
public class PointsShopCount
{
public class Response
{
public int total_count { get; set; }
public int count { get; set; }
}

public Response response;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
using SteamCommon.Models;

namespace SteamShortcuts.Domain.ValueObjects
{
public class SupportedFeatures
{
public bool Achievements { get; set; } = false;
public bool PointsShop { get; set; } = false;
public bool Workshop { get; set; } = false;

public static SupportedFeatures All = new SupportedFeatures
{
Achievements = true,
PointsShop = true,
Workshop = true,
};
}
}
27 changes: 27 additions & 0 deletions source/Generic/SteamViewer/Infrastructure/QueryRewardItems.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
using FlowHttp;
using Playnite.SDK.Data;
using SteamShortcuts.Domain.ValueObjects;
using System.Threading;
using System.Threading.Tasks;

namespace SteamShortcuts.Infrastructure
{
class QueryRewardItems
{
private const string queryUrl = @"https://api.steampowered.com/ILoyaltyRewardsService/QueryRewardItems/v1/?appids[0]={0}&count=1";

public static async Task<PointsShopCount> GetPointsShopCount(string appId, CancellationToken cancelToken = default)
{
var url = string.Format(queryUrl, appId);
var request = HttpRequestFactory.GetHttpRequest().WithUrl(url);
var downloadedString = await request.DownloadStringAsync(cancelToken);

if (downloadedString.IsSuccess)
{
return Serialization.FromJson<PointsShopCount>(downloadedString.Content);
}

return null;
}
}
}
1 change: 1 addition & 0 deletions source/Generic/SteamViewer/Localization/en_US.xaml
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@
<sys:String x:Key="LOCSteam_Viewer_MenuItemGameNewsDescription">News</sys:String>
<sys:String x:Key="LOCSteam_Viewer_MenuItemGameAchievementsDescription">Achievements</sys:String>
<sys:String x:Key="LOCSteam_Viewer_MenuItemGamePointsShopDescription">PointsShop</sys:String>
<sys:String x:Key="LOCSteam_Viewer_MenuItemGameWorkshopDescription">Workshop</sys:String>
<sys:String x:Key="LOCSteam_Viewer_MenuItemGameLibraryDescription">View in Steam Library</sys:String>
<sys:String x:Key="LOCSteam_Viewer_MenuItemGameLibraryDetails">Details</sys:String>
<sys:String x:Key="LOCSteam_Viewer_MenuItemGameSteamInput">Steam Input</sys:String>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -28,9 +28,10 @@
<MenuItem Header="{DynamicResource LOCSteam_Viewer_MenuItemGameCommunityHubDescription}" Click="OnCommunityHub"/>
<MenuItem Header="{DynamicResource LOCSteam_Viewer_MenuItemGameDiscussionsDescription}" Click="OnDiscussions"/>
<MenuItem Header="{DynamicResource LOCSteam_Viewer_MenuItemGameGuidesDescription}" Click="OnGuides"/>
<MenuItem Header="{DynamicResource LOCSteam_Viewer_MenuItemGameAchievementsDescription}" Click="OnAchievements"/>
<MenuItem Header="{DynamicResource LOCSteam_Viewer_MenuItemComponentNewsDescription}" Click="OnNews"/>
<MenuItem Header="{DynamicResource LOCSteam_Viewer_MenuItemGamePointsShopDescription}" Click="OnPointsShop"/>
<MenuItem x:Name="MenuItemGameAchievements" Visibility="Collapsed" Header="{DynamicResource LOCSteam_Viewer_MenuItemGameAchievementsDescription}" Click="OnAchievements"/>
<MenuItem x:Name="MenuItemGamePointsShop" Visibility="Collapsed" Header="{DynamicResource LOCSteam_Viewer_MenuItemGamePointsShopDescription}" Click="OnPointsShop"/>
<MenuItem x:Name="MenuItemGameWorkshop" Visibility="Collapsed" Header="{DynamicResource LOCSteam_Viewer_MenuItemGameWorkshopDescription}" Click="OnWorkshop"/>

</ContextMenu>
</Button.ContextMenu>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
using SteamCommon;
using SteamShortcuts.Application;
using SteamShortcuts.Domain.Enums;
using SteamShortcuts.Domain.ValueObjects;
using System;
using System.Collections.Generic;
using System.Linq;
Expand Down Expand Up @@ -33,17 +34,20 @@ public partial class SteamGameActionsLauncher : PluginUserControlBase
public SteamShortcutsSettingsViewModel SettingsModel { get; }

private readonly SteamUriLauncherService _launcher;
private readonly DiscoverSupportedFeaturesService _featuresService;
private string _steamId = string.Empty;
private bool _areBindingValuesDefault = true;

public SteamGameActionsLauncher(
SteamUriLauncherService steamUriLauncherService,
DiscoverSupportedFeaturesService discoverSupportedFeaturesSerivce,
SteamShortcutsSettingsViewModel settingsViewModel,
IPlayniteAPI playniteApi,
ILogger logger) : base(playniteApi)
{
InitializeComponent();
_launcher = steamUriLauncherService ?? throw new ArgumentNullException(nameof(steamUriLauncherService));
_featuresService = discoverSupportedFeaturesSerivce ?? throw new ArgumentNullException(nameof(discoverSupportedFeaturesSerivce));
_logger = logger ?? throw new ArgumentNullException(nameof(logger));
SettingsModel = settingsViewModel ?? throw new ArgumentNullException(nameof(settingsViewModel));
DataContext = this;
Expand Down Expand Up @@ -83,6 +87,23 @@ public override void GameContextChanged(Game oldContext, Game newContext)
}

_steamId = foundSteamId;
_ = _featuresService.GetFeatures(foundSteamId).ContinueWith(task =>
{
var features = SupportedFeatures.All;

if (task.Status == TaskStatus.RanToCompletion)
{
features = task.Result ?? SupportedFeatures.All;
}

PlayniteApi.MainView.UIDispatcher.Invoke(() =>
{
MenuItemGameAchievements.Visibility = features.Achievements ? Visibility.Visible : Visibility.Collapsed;
MenuItemGamePointsShop.Visibility = features.PointsShop ? Visibility.Visible : Visibility.Collapsed;
MenuItemGameWorkshop.Visibility = features.Workshop ? Visibility.Visible : Visibility.Collapsed;
});
});

Visibility = Visibility.Visible;
SettingsModel.Settings.IsControlVisible = true;
_areBindingValuesDefault = false;
Expand Down Expand Up @@ -138,6 +159,9 @@ private void OnNews(object sender, RoutedEventArgs e)
private void OnPointsShop(object sender, RoutedEventArgs e)
=> _launcher.LaunchSteamWebUrl(SteamUrlType.PointsShop, _steamId);

private void OnWorkshop(object sender, RoutedEventArgs e)
=> _launcher.LaunchSteamWebUrl(SteamUrlType.Workshop, _steamId);

#endregion

#region Global Steam
Expand Down
49 changes: 45 additions & 4 deletions source/Generic/SteamViewer/SteamShortcuts.cs
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
using SteamCommon;
using SteamShortcuts.Application;
using SteamShortcuts.Domain.Enums;
using SteamShortcuts.Domain.ValueObjects;
using SteamShortcuts.Presentation;
using System;
using System.Collections.Generic;
Expand All @@ -25,6 +26,7 @@ public class SteamShortcuts : GenericPlugin
public SteamShortcutsSettingsViewModel Settings { get; set; }
private readonly List<GameMenuItem> _steamComponentMenuItems;
private static readonly string _menuSection = ResourceProvider.GetString("LOCSteam_Viewer_SteamShortcutsLabel");
private readonly DiscoverSupportedFeaturesService _featuresService;

public override Guid Id { get; } = Guid.Parse("0a3edabb-065f-4056-a294-d6bc0656e2ac");

Expand All @@ -35,6 +37,7 @@ public SteamShortcuts(IPlayniteAPI api) : base(api)
Properties = new GenericPluginProperties { HasSettings = true };
_steamComponentMenuItems = GetSteamComponentMenuItems();
_steamUriLauncherService.LaunchUrlsInSteamClient = Settings.Settings.LaunchUrlsInSteamClient;
_featuresService = new DiscoverSupportedFeaturesService();

AddSettingsSupport(new AddSettingsSupportArgs
{
Expand All @@ -53,7 +56,7 @@ public override Control GetGameViewControl(GetGameViewControlArgs args)
{
if (args.Name == "SteamGameActionsLauncher")
{
return new SteamGameActionsLauncher(_steamUriLauncherService, Settings, PlayniteApi, _logger);
return new SteamGameActionsLauncher(_steamUriLauncherService, _featuresService, Settings, PlayniteApi, _logger);
}

return null;
Expand Down Expand Up @@ -113,10 +116,25 @@ private void AddSteamWebLinkMenuItems(List<GameMenuItem> menuItems, string steam
CreateSteamWebLinkMenuItem("LOCSteam_Viewer_MenuItemGameCommunityHubDescription", SteamUrlType.CommunityHub, steamId),
CreateSteamWebLinkMenuItem("LOCSteam_Viewer_MenuItemGameDiscussionsDescription", SteamUrlType.Discussions, steamId, '\uED44'),
CreateSteamWebLinkMenuItem("LOCSteam_Viewer_MenuItemGameGuidesDescription", SteamUrlType.Guides, steamId, '\uEF8B'),
CreateSteamWebLinkMenuItem("LOCSteam_Viewer_MenuItemGameAchievementsDescription", SteamUrlType.Achievements, steamId, '\uEDD7'),
CreateSteamWebLinkMenuItem("LOCSteam_Viewer_MenuItemGameNewsDescription", SteamUrlType.News, steamId, '\uEFA7'),
CreateSteamWebLinkMenuItem("LOCSteam_Viewer_MenuItemGamePointsShopDescription", SteamUrlType.PointsShop, steamId, '\uEFE7')
});

var feature = _featuresService.GetCachedFeature(steamId) ?? SupportedFeatures.All;

if (feature.Achievements)
{
menuItems.Add(CreateSteamWebLinkMenuItem("LOCSteam_Viewer_MenuItemGameAchievementsDescription", SteamUrlType.Achievements, steamId, '\uEDD7'));
}

if (feature.PointsShop)
{
menuItems.Add(CreateSteamWebLinkMenuItem("LOCSteam_Viewer_MenuItemGamePointsShopDescription", SteamUrlType.PointsShop, steamId, '\uEFE7'));
}

if (feature.Workshop)
{
menuItems.Add(CreateSteamWebLinkMenuItem("LOCSteam_Viewer_MenuItemGameWorkshopDescription", SteamUrlType.Workshop, steamId, '\uE9C4'));
}
}

private List<GameMenuItem> GetSteamComponentMenuItems()
Expand Down Expand Up @@ -174,6 +192,29 @@ public override UserControl GetSettingsView(bool firstRunSettings)
{
return new SteamShortcutsSettingsView();
}
}

public override void OnGameSelected(OnGameSelectedEventArgs args)
{
// Happens when transitioning to another layout (e.g., details to grid)
if (args.NewValue is null)
{
return;
}

if (args.NewValue.Count > 1)
{
return;
}

var game = args.NewValue[0];
string steamId = Steam.GetGameSteamId(game, Settings.Settings.AddWebLinksForNonSteam);

if (string.IsNullOrEmpty(steamId))
{
return;
}

_ = _featuresService.GetFeatures(steamId);
}
}
}
Loading