Skip to content

Commit d3d56b2

Browse files
committed
Added GetPublishedFileDetails endpoint.
* A custom converter is used to convert the response's awful tag format (list of dictionaries) to a list of the values of the dictionary. This seems to be safe because I've only seen the response be formatted in such way, with the keys always being the string "tag". * An itemcount greater than the size of the list of file ids will return null; processing the request would lead to HTTP 400 anyway. * Only the outer result value is accounted for, returning null when it is not equal to 1 i.e. k_EResultOK (Success). However, it seems to always be 1 anyway. * The inner result value i.e. inside publishedfiledetails is not checked. Therefore, every property of a given details object, excluding publishedfileid and result, may be null if the request fails (the JSON deserialiser is configured to ignore missing members). * These changes requires Steam.Models to include objects to map to: PublishedFileDetailsModel and enum PublishedFileVisibility.
1 parent 245e387 commit d3d56b2

5 files changed

Lines changed: 191 additions & 1 deletion

File tree

src/SteamWebAPI2/AutoMapperConfiguration.cs

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -108,6 +108,7 @@ public static void Initialize()
108108
CreateSteamWebResponseMap<AssetClassInfoResultContainer, AssetClassInfoResultModel>(x);
109109
CreateSteamWebResponseMap<AssetPriceResultContainer, AssetPriceResultModel>(x);
110110
CreateSteamWebResponseMap<SteamNewsResultContainer, SteamNewsResultModel>(x);
111+
CreateSteamWebResponseMap<PublishedFileDetailsResultContainer, IReadOnlyCollection<PublishedFileDetailsModel>>(x);
111112
CreateSteamWebResponseMap<UGCFileDetailsResultContainer, UGCFileDetailsModel>(x);
112113
CreateSteamWebResponseMap<PlayerSummaryResultContainer, PlayerSummaryModel>(x);
113114
CreateSteamWebResponseMap<PlayerSummaryResultContainer, IReadOnlyCollection<PlayerSummaryModel>>(x);
@@ -380,6 +381,14 @@ public static void Initialize()
380381

381382
#region Endpoint: SteamRemoteStorage
382383

384+
x.CreateMap<uint, PublishedFileVisibility>();
385+
x.CreateMap<PublishedFileDetails, PublishedFileDetailsModel>();
386+
x.CreateMap<PublishedFileDetailsResultContainer, IReadOnlyCollection<PublishedFileDetailsModel>>()
387+
.ConvertUsing(
388+
src => Mapper.Map<IList<PublishedFileDetails>, IReadOnlyCollection<PublishedFileDetailsModel>>(
389+
src.Result != null && src.Result.Result == 1 ? src.Result.Details : null)
390+
);
391+
383392
x.CreateMap<UGCFileDetails, UGCFileDetailsModel>();
384393
x.CreateMap<UGCFileDetailsResultContainer, UGCFileDetailsModel>().ConvertUsing(
385394
src => Mapper.Map<UGCFileDetails, UGCFileDetailsModel>(src.Result)

src/SteamWebAPI2/Interfaces/ISteamRemoteStorage.cs

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,8 +4,12 @@
44

55
namespace SteamWebAPI2.Interfaces
66
{
7+
using System.Collections.Generic;
8+
79
public interface ISteamRemoteStorage
810
{
11+
Task<ISteamWebResponse<IReadOnlyCollection<PublishedFileDetailsModel>>> GetPublishedFileDetailsAsync(uint itemCount, IList<ulong> publishedFileIds);
12+
913
Task<ISteamWebResponse<UGCFileDetailsModel>> GetUGCFileDetailsAsync(ulong ugcId, uint appId, ulong? steamId = null);
1014
}
1115
}

src/SteamWebAPI2/Interfaces/SteamRemoteStorage.cs

Lines changed: 35 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,40 @@ public SteamRemoteStorage(string steamWebApiKey, ISteamWebInterface steamWebInte
2323
: steamWebInterface;
2424
}
2525

26+
/// <summary>
27+
/// Retrieves information about published files such as workshop items and screenshots.
28+
/// </summary>
29+
/// <param name="itemCount">The quantity of items for which to retrieve details.
30+
/// This can be smaller than the amount of items in <paramref name="publishedFileIds"/>, but not larger.</param>
31+
/// <param name="publishedFileIds">The list of ids of files for which to retrieve details.</param>
32+
/// <returns>A collection of the details of the files or <c>null</c> if the request failed.</returns>
33+
public async Task<ISteamWebResponse<IReadOnlyCollection<PublishedFileDetailsModel>>> GetPublishedFileDetailsAsync(uint itemCount, IList<ulong> publishedFileIds) {
34+
Debug.Assert(itemCount <= publishedFileIds.Count);
35+
36+
List<SteamWebRequestParameter> parameters = new List<SteamWebRequestParameter>();
37+
parameters.AddIfHasValue(itemCount, "itemcount");
38+
39+
for (int i = 0; i < publishedFileIds.Count; ++i)
40+
{
41+
parameters.AddIfHasValue(publishedFileIds[i], $"publishedfileids[{i}]");
42+
}
43+
44+
try
45+
{
46+
var steamWebResponse = await steamWebInterface.PostAsync<PublishedFileDetailsResultContainer>("GetPublishedFileDetails", 1, parameters);
47+
48+
var steamWebResponseModel = AutoMapperConfiguration.Mapper.Map<
49+
ISteamWebResponse<PublishedFileDetailsResultContainer>,
50+
ISteamWebResponse<IReadOnlyCollection<PublishedFileDetailsModel>>>(steamWebResponse);
51+
52+
return steamWebResponseModel;
53+
}
54+
catch (HttpRequestException)
55+
{
56+
return null;
57+
}
58+
}
59+
2660
/// <summary>
2761
/// Returns information about how to download a user generated content based on a UGC ID, App ID, and Steam ID.
2862
/// </summary>
@@ -45,7 +79,7 @@ public async Task<ISteamWebResponse<UGCFileDetailsModel>> GetUGCFileDetailsAsync
4579
var steamWebResponse = await steamWebInterface.GetAsync<UGCFileDetailsResultContainer>("GetUGCFileDetails", 1, parameters);
4680

4781
var steamWebResponseModel = AutoMapperConfiguration.Mapper.Map<
48-
ISteamWebResponse<UGCFileDetailsResultContainer>,
82+
ISteamWebResponse<UGCFileDetailsResultContainer>,
4983
ISteamWebResponse<UGCFileDetailsModel>>(steamWebResponse);
5084

5185
return steamWebResponseModel;
Lines changed: 105 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,105 @@
1+
using System;
2+
using System.Collections.Generic;
3+
4+
using Newtonsoft.Json;
5+
6+
namespace SteamWebAPI2.Models
7+
{
8+
using SteamWebAPI2.Utilities.JsonConverters;
9+
10+
internal class PublishedFileDetailsResultContainer
11+
{
12+
[JsonProperty("response")]
13+
public PublishedFileDetailsResult Result { get; set; }
14+
}
15+
16+
internal class PublishedFileDetailsResult
17+
{
18+
[JsonProperty("result")]
19+
public uint Result { get; set; }
20+
21+
[JsonProperty("resultcount")]
22+
public uint Count { get; set; }
23+
24+
[JsonProperty("publishedfiledetails")]
25+
public IList<PublishedFileDetails> Details { get; set; }
26+
}
27+
28+
internal class PublishedFileDetails
29+
{
30+
[JsonProperty("publishedfileid")]
31+
public ulong PublishedFileId { get; set; }
32+
33+
[JsonProperty("result")]
34+
public uint Result { get; set; }
35+
36+
[JsonProperty("creator")]
37+
public ulong Creator { get; set; }
38+
39+
[JsonProperty("creator_app_id")]
40+
public uint CreatorAppId { get; set; }
41+
42+
[JsonProperty("consumer_app_id")]
43+
public uint ConsumerAppId { get; set; }
44+
45+
[JsonProperty("filename")]
46+
public string FileName { get; set; }
47+
48+
[JsonProperty("file_size")]
49+
public uint FileSize { get; set; }
50+
51+
[JsonProperty("file_url")]
52+
public string FileUrl { get; set; }
53+
54+
[JsonProperty("hcontent_file")]
55+
public ulong FileContentHandle { get; set; }
56+
57+
[JsonProperty("preview_url")]
58+
public string PreviewUrl { get; set; }
59+
60+
[JsonProperty("hcontent_preview")]
61+
public ulong PreviewContentHandle { get; set; }
62+
63+
[JsonProperty("title")]
64+
public string Title { get; set; }
65+
66+
[JsonProperty("description")]
67+
public string Description { get; set; }
68+
69+
[JsonProperty("time_created")]
70+
[JsonConverter(typeof(UnixTimeJsonConverter))]
71+
public DateTime TimeCreated { get; set; }
72+
73+
[JsonProperty("time_updated")]
74+
[JsonConverter(typeof(UnixTimeJsonConverter))]
75+
public DateTime TimeUpdated { get; set; }
76+
77+
[JsonProperty("visibility")]
78+
public uint Visibility { get; set; }
79+
80+
[JsonProperty("banned")]
81+
public bool Banned { get; set; }
82+
83+
[JsonProperty("ban_reason")]
84+
public string BanReason { get; set; }
85+
86+
[JsonProperty("subscriptions")]
87+
public ulong Subscriptions { get; set; }
88+
89+
[JsonProperty("favorited")]
90+
public ulong Favorited { get; set; }
91+
92+
[JsonProperty("lifetime_subscriptions")]
93+
public ulong LifetimeSubscriptions { get; set; }
94+
95+
[JsonProperty("lifetime_favorited")]
96+
public ulong LifetimeFavorited { get; set; }
97+
98+
[JsonProperty("views")]
99+
public ulong Views { get; set; }
100+
101+
[JsonProperty("tags")]
102+
[JsonConverter(typeof(TagsJsonConverter))]
103+
public IList<string> Tags { get; set; }
104+
}
105+
}
Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,38 @@
1+
using System;
2+
using System.Collections.Generic;
3+
using System.Reflection;
4+
5+
using Newtonsoft.Json;
6+
7+
namespace SteamWebAPI2.Utilities.JsonConverters
8+
{
9+
/// <inheritdoc />
10+
/// <summary>
11+
/// Converts the tags stored in a list of dictionaries to a list of the values of the dictionary.
12+
/// <remarks>The keys seem to always be the string "tag".</remarks>
13+
/// </summary>
14+
internal class TagsJsonConverter : JsonConverter
15+
{
16+
public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer)
17+
{
18+
throw new NotImplementedException();
19+
}
20+
21+
public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer)
22+
{
23+
var original = serializer.Deserialize<List<Dictionary<string, string>>>(reader);
24+
var tags = new List<string>();
25+
26+
original.ForEach(tag => tags.AddRange(tag.Values));
27+
28+
return tags;
29+
}
30+
31+
public override bool CanWrite => false;
32+
33+
public override bool CanConvert(Type objectType)
34+
{
35+
return typeof(IList<IDictionary<string, string>>).GetTypeInfo().IsAssignableFrom(objectType.GetTypeInfo());
36+
}
37+
}
38+
}

0 commit comments

Comments
 (0)