Skip to content

Commit

Permalink
Added GetPublishedFileDetails endpoint.
Browse files Browse the repository at this point in the history
* 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.
  • Loading branch information
MarkKoz committed Jan 15, 2018
1 parent 245e387 commit d3d56b2
Show file tree
Hide file tree
Showing 5 changed files with 191 additions and 1 deletion.
9 changes: 9 additions & 0 deletions src/SteamWebAPI2/AutoMapperConfiguration.cs
Original file line number Diff line number Diff line change
Expand Up @@ -108,6 +108,7 @@ public static void Initialize()
CreateSteamWebResponseMap<AssetClassInfoResultContainer, AssetClassInfoResultModel>(x);
CreateSteamWebResponseMap<AssetPriceResultContainer, AssetPriceResultModel>(x);
CreateSteamWebResponseMap<SteamNewsResultContainer, SteamNewsResultModel>(x);
CreateSteamWebResponseMap<PublishedFileDetailsResultContainer, IReadOnlyCollection<PublishedFileDetailsModel>>(x);
CreateSteamWebResponseMap<UGCFileDetailsResultContainer, UGCFileDetailsModel>(x);
CreateSteamWebResponseMap<PlayerSummaryResultContainer, PlayerSummaryModel>(x);
CreateSteamWebResponseMap<PlayerSummaryResultContainer, IReadOnlyCollection<PlayerSummaryModel>>(x);
Expand Down Expand Up @@ -380,6 +381,14 @@ public static void Initialize()

#region Endpoint: SteamRemoteStorage

x.CreateMap<uint, PublishedFileVisibility>();
x.CreateMap<PublishedFileDetails, PublishedFileDetailsModel>();
x.CreateMap<PublishedFileDetailsResultContainer, IReadOnlyCollection<PublishedFileDetailsModel>>()
.ConvertUsing(
src => Mapper.Map<IList<PublishedFileDetails>, IReadOnlyCollection<PublishedFileDetailsModel>>(
src.Result != null && src.Result.Result == 1 ? src.Result.Details : null)
);

x.CreateMap<UGCFileDetails, UGCFileDetailsModel>();
x.CreateMap<UGCFileDetailsResultContainer, UGCFileDetailsModel>().ConvertUsing(
src => Mapper.Map<UGCFileDetails, UGCFileDetailsModel>(src.Result)
Expand Down
4 changes: 4 additions & 0 deletions src/SteamWebAPI2/Interfaces/ISteamRemoteStorage.cs
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,12 @@

namespace SteamWebAPI2.Interfaces
{
using System.Collections.Generic;

public interface ISteamRemoteStorage
{
Task<ISteamWebResponse<IReadOnlyCollection<PublishedFileDetailsModel>>> GetPublishedFileDetailsAsync(uint itemCount, IList<ulong> publishedFileIds);

Task<ISteamWebResponse<UGCFileDetailsModel>> GetUGCFileDetailsAsync(ulong ugcId, uint appId, ulong? steamId = null);
}
}
36 changes: 35 additions & 1 deletion src/SteamWebAPI2/Interfaces/SteamRemoteStorage.cs
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,40 @@ public SteamRemoteStorage(string steamWebApiKey, ISteamWebInterface steamWebInte
: steamWebInterface;
}

/// <summary>
/// Retrieves information about published files such as workshop items and screenshots.
/// </summary>
/// <param name="itemCount">The quantity of items for which to retrieve details.
/// This can be smaller than the amount of items in <paramref name="publishedFileIds"/>, but not larger.</param>
/// <param name="publishedFileIds">The list of ids of files for which to retrieve details.</param>
/// <returns>A collection of the details of the files or <c>null</c> if the request failed.</returns>
public async Task<ISteamWebResponse<IReadOnlyCollection<PublishedFileDetailsModel>>> GetPublishedFileDetailsAsync(uint itemCount, IList<ulong> publishedFileIds) {
Debug.Assert(itemCount <= publishedFileIds.Count);

List<SteamWebRequestParameter> parameters = new List<SteamWebRequestParameter>();
parameters.AddIfHasValue(itemCount, "itemcount");

for (int i = 0; i < publishedFileIds.Count; ++i)
{
parameters.AddIfHasValue(publishedFileIds[i], $"publishedfileids[{i}]");
}

try
{
var steamWebResponse = await steamWebInterface.PostAsync<PublishedFileDetailsResultContainer>("GetPublishedFileDetails", 1, parameters);

var steamWebResponseModel = AutoMapperConfiguration.Mapper.Map<
ISteamWebResponse<PublishedFileDetailsResultContainer>,
ISteamWebResponse<IReadOnlyCollection<PublishedFileDetailsModel>>>(steamWebResponse);

return steamWebResponseModel;
}
catch (HttpRequestException)
{
return null;
}
}

/// <summary>
/// Returns information about how to download a user generated content based on a UGC ID, App ID, and Steam ID.
/// </summary>
Expand All @@ -45,7 +79,7 @@ public async Task<ISteamWebResponse<UGCFileDetailsModel>> GetUGCFileDetailsAsync
var steamWebResponse = await steamWebInterface.GetAsync<UGCFileDetailsResultContainer>("GetUGCFileDetails", 1, parameters);

var steamWebResponseModel = AutoMapperConfiguration.Mapper.Map<
ISteamWebResponse<UGCFileDetailsResultContainer>,
ISteamWebResponse<UGCFileDetailsResultContainer>,
ISteamWebResponse<UGCFileDetailsModel>>(steamWebResponse);

return steamWebResponseModel;
Expand Down
105 changes: 105 additions & 0 deletions src/SteamWebAPI2/Models/PublishedFileDetailsResultContainer.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,105 @@
using System;
using System.Collections.Generic;

using Newtonsoft.Json;

namespace SteamWebAPI2.Models
{
using SteamWebAPI2.Utilities.JsonConverters;

internal class PublishedFileDetailsResultContainer
{
[JsonProperty("response")]
public PublishedFileDetailsResult Result { get; set; }
}

internal class PublishedFileDetailsResult
{
[JsonProperty("result")]
public uint Result { get; set; }

[JsonProperty("resultcount")]
public uint Count { get; set; }

[JsonProperty("publishedfiledetails")]
public IList<PublishedFileDetails> Details { get; set; }
}

internal class PublishedFileDetails
{
[JsonProperty("publishedfileid")]
public ulong PublishedFileId { get; set; }

[JsonProperty("result")]
public uint Result { get; set; }

[JsonProperty("creator")]
public ulong Creator { get; set; }

[JsonProperty("creator_app_id")]
public uint CreatorAppId { get; set; }

[JsonProperty("consumer_app_id")]
public uint ConsumerAppId { get; set; }

[JsonProperty("filename")]
public string FileName { get; set; }

[JsonProperty("file_size")]
public uint FileSize { get; set; }

[JsonProperty("file_url")]
public string FileUrl { get; set; }

[JsonProperty("hcontent_file")]
public ulong FileContentHandle { get; set; }

[JsonProperty("preview_url")]
public string PreviewUrl { get; set; }

[JsonProperty("hcontent_preview")]
public ulong PreviewContentHandle { get; set; }

[JsonProperty("title")]
public string Title { get; set; }

[JsonProperty("description")]
public string Description { get; set; }

[JsonProperty("time_created")]
[JsonConverter(typeof(UnixTimeJsonConverter))]
public DateTime TimeCreated { get; set; }

[JsonProperty("time_updated")]
[JsonConverter(typeof(UnixTimeJsonConverter))]
public DateTime TimeUpdated { get; set; }

[JsonProperty("visibility")]
public uint Visibility { get; set; }

[JsonProperty("banned")]
public bool Banned { get; set; }

[JsonProperty("ban_reason")]
public string BanReason { get; set; }

[JsonProperty("subscriptions")]
public ulong Subscriptions { get; set; }

[JsonProperty("favorited")]
public ulong Favorited { get; set; }

[JsonProperty("lifetime_subscriptions")]
public ulong LifetimeSubscriptions { get; set; }

[JsonProperty("lifetime_favorited")]
public ulong LifetimeFavorited { get; set; }

[JsonProperty("views")]
public ulong Views { get; set; }

[JsonProperty("tags")]
[JsonConverter(typeof(TagsJsonConverter))]
public IList<string> Tags { get; set; }
}
}
38 changes: 38 additions & 0 deletions src/SteamWebAPI2/Utilities/JsonConverters/TagsJsonConverter.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
using System;
using System.Collections.Generic;
using System.Reflection;

using Newtonsoft.Json;

namespace SteamWebAPI2.Utilities.JsonConverters
{
/// <inheritdoc />
/// <summary>
/// Converts the tags stored in a list of dictionaries to a list of the values of the dictionary.
/// <remarks>The keys seem to always be the string "tag".</remarks>
/// </summary>
internal class TagsJsonConverter : JsonConverter
{
public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer)
{
throw new NotImplementedException();
}

public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer)
{
var original = serializer.Deserialize<List<Dictionary<string, string>>>(reader);
var tags = new List<string>();

original.ForEach(tag => tags.AddRange(tag.Values));

return tags;
}

public override bool CanWrite => false;

public override bool CanConvert(Type objectType)
{
return typeof(IList<IDictionary<string, string>>).GetTypeInfo().IsAssignableFrom(objectType.GetTypeInfo());
}
}
}

0 comments on commit d3d56b2

Please sign in to comment.