mirror of
https://github.com/ppy/osu.git
synced 2025-01-13 22:22:55 +08:00
Merge branch 'master' into i-working-beatmap/difficulty-calculator
This commit is contained in:
commit
f9e3d9bb92
@ -93,6 +93,11 @@ namespace osu.Desktop
|
|||||||
|
|
||||||
protected override UpdateManager CreateUpdateManager()
|
protected override UpdateManager CreateUpdateManager()
|
||||||
{
|
{
|
||||||
|
string packageManaged = Environment.GetEnvironmentVariable("OSU_EXTERNAL_UPDATE_PROVIDER");
|
||||||
|
|
||||||
|
if (!string.IsNullOrEmpty(packageManaged))
|
||||||
|
return new NoActionUpdateManager();
|
||||||
|
|
||||||
switch (RuntimeInfo.OS)
|
switch (RuntimeInfo.OS)
|
||||||
{
|
{
|
||||||
case RuntimeInfo.Platform.Windows:
|
case RuntimeInfo.Platform.Windows:
|
||||||
|
@ -7,6 +7,7 @@ using System.Linq;
|
|||||||
using NUnit.Framework;
|
using NUnit.Framework;
|
||||||
using osu.Framework.Testing;
|
using osu.Framework.Testing;
|
||||||
using osu.Game.Beatmaps;
|
using osu.Game.Beatmaps;
|
||||||
|
using osu.Game.Extensions;
|
||||||
using osu.Game.Online.API;
|
using osu.Game.Online.API;
|
||||||
using osu.Game.Online.API.Requests;
|
using osu.Game.Online.API.Requests;
|
||||||
using osu.Game.Online.API.Requests.Responses;
|
using osu.Game.Online.API.Requests.Responses;
|
||||||
@ -102,8 +103,8 @@ namespace osu.Game.Tests.Visual.SongSelect
|
|||||||
{
|
{
|
||||||
BeatmapSetInfo catchSet = null, mixedSet = null;
|
BeatmapSetInfo catchSet = null, mixedSet = null;
|
||||||
|
|
||||||
AddStep("create catch beatmapset", () => catchSet = importBeatmapSet(0, new[] { new CatchRuleset().RulesetInfo }));
|
AddStep("create catch beatmapset", () => catchSet = importBeatmapSet(1, new[] { new CatchRuleset().RulesetInfo }));
|
||||||
AddStep("create mixed beatmapset", () => mixedSet = importBeatmapSet(1,
|
AddStep("create mixed beatmapset", () => mixedSet = importBeatmapSet(2,
|
||||||
new[] { new TaikoRuleset().RulesetInfo, new CatchRuleset().RulesetInfo, new ManiaRuleset().RulesetInfo }));
|
new[] { new TaikoRuleset().RulesetInfo, new CatchRuleset().RulesetInfo, new ManiaRuleset().RulesetInfo }));
|
||||||
|
|
||||||
AddAssert("all sets imported", () => ensureAllBeatmapSetsImported(new[] { catchSet, mixedSet }));
|
AddAssert("all sets imported", () => ensureAllBeatmapSetsImported(new[] { catchSet, mixedSet }));
|
||||||
@ -120,8 +121,8 @@ namespace osu.Game.Tests.Visual.SongSelect
|
|||||||
{
|
{
|
||||||
BeatmapSetInfo osuSet = null, mixedSet = null;
|
BeatmapSetInfo osuSet = null, mixedSet = null;
|
||||||
|
|
||||||
AddStep("create osu! beatmapset", () => osuSet = importBeatmapSet(0, new[] { new OsuRuleset().RulesetInfo }));
|
AddStep("create osu! beatmapset", () => osuSet = importBeatmapSet(1, new[] { new OsuRuleset().RulesetInfo }));
|
||||||
AddStep("create mixed beatmapset", () => mixedSet = importBeatmapSet(1,
|
AddStep("create mixed beatmapset", () => mixedSet = importBeatmapSet(2,
|
||||||
new[] { new TaikoRuleset().RulesetInfo, new CatchRuleset().RulesetInfo, new ManiaRuleset().RulesetInfo }));
|
new[] { new TaikoRuleset().RulesetInfo, new CatchRuleset().RulesetInfo, new ManiaRuleset().RulesetInfo }));
|
||||||
|
|
||||||
AddAssert("all sets imported", () => ensureAllBeatmapSetsImported(new[] { osuSet, mixedSet }));
|
AddAssert("all sets imported", () => ensureAllBeatmapSetsImported(new[] { osuSet, mixedSet }));
|
||||||
@ -138,8 +139,8 @@ namespace osu.Game.Tests.Visual.SongSelect
|
|||||||
{
|
{
|
||||||
BeatmapSetInfo osuSet = null, mixedSet = null;
|
BeatmapSetInfo osuSet = null, mixedSet = null;
|
||||||
|
|
||||||
AddStep("create osu! beatmapset", () => osuSet = importBeatmapSet(0, new[] { new OsuRuleset().RulesetInfo }));
|
AddStep("create osu! beatmapset", () => osuSet = importBeatmapSet(1, new[] { new OsuRuleset().RulesetInfo }));
|
||||||
AddStep("create mixed beatmapset", () => mixedSet = importBeatmapSet(1,
|
AddStep("create mixed beatmapset", () => mixedSet = importBeatmapSet(2,
|
||||||
new[] { new TaikoRuleset().RulesetInfo, new CatchRuleset().RulesetInfo, new TaikoRuleset().RulesetInfo }));
|
new[] { new TaikoRuleset().RulesetInfo, new CatchRuleset().RulesetInfo, new TaikoRuleset().RulesetInfo }));
|
||||||
|
|
||||||
AddAssert("all sets imported", () => ensureAllBeatmapSetsImported(new[] { osuSet, mixedSet }));
|
AddAssert("all sets imported", () => ensureAllBeatmapSetsImported(new[] { osuSet, mixedSet }));
|
||||||
@ -156,8 +157,8 @@ namespace osu.Game.Tests.Visual.SongSelect
|
|||||||
{
|
{
|
||||||
BeatmapSetInfo osuSet = null, maniaSet = null;
|
BeatmapSetInfo osuSet = null, maniaSet = null;
|
||||||
|
|
||||||
AddStep("create osu! beatmapset", () => osuSet = importBeatmapSet(0, new[] { new OsuRuleset().RulesetInfo }));
|
AddStep("create osu! beatmapset", () => osuSet = importBeatmapSet(1, new[] { new OsuRuleset().RulesetInfo }));
|
||||||
AddStep("create mania beatmapset", () => maniaSet = importBeatmapSet(1, Enumerable.Repeat(new ManiaRuleset().RulesetInfo, 10)));
|
AddStep("create mania beatmapset", () => maniaSet = importBeatmapSet(2, Enumerable.Repeat(new ManiaRuleset().RulesetInfo, 10)));
|
||||||
|
|
||||||
AddAssert("all sets imported", () => ensureAllBeatmapSetsImported(new[] { osuSet, maniaSet }));
|
AddAssert("all sets imported", () => ensureAllBeatmapSetsImported(new[] { osuSet, maniaSet }));
|
||||||
|
|
||||||
@ -203,11 +204,7 @@ namespace osu.Game.Tests.Visual.SongSelect
|
|||||||
AddStep("present beatmap", () => Game.PresentBeatmap(getImport()));
|
AddStep("present beatmap", () => Game.PresentBeatmap(getImport()));
|
||||||
|
|
||||||
AddUntilStep("wait for song select", () => Game.ScreenStack.CurrentScreen is Screens.Select.SongSelect);
|
AddUntilStep("wait for song select", () => Game.ScreenStack.CurrentScreen is Screens.Select.SongSelect);
|
||||||
AddUntilStep("recommended beatmap displayed", () =>
|
AddUntilStep("recommended beatmap displayed", () => Game.Beatmap.Value.BeatmapInfo.MatchesOnlineID(getImport().Beatmaps[expectedDiff - 1]));
|
||||||
{
|
|
||||||
int? expectedID = getImport().Beatmaps[expectedDiff - 1].OnlineID;
|
|
||||||
return Game.Beatmap.Value.BeatmapInfo.OnlineID == expectedID;
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -10,6 +10,7 @@ using Newtonsoft.Json.Converters;
|
|||||||
using osu.Game.Beatmaps;
|
using osu.Game.Beatmaps;
|
||||||
using osu.Game.Online.API;
|
using osu.Game.Online.API;
|
||||||
using osu.Game.Online.API.Requests.Responses;
|
using osu.Game.Online.API.Requests.Responses;
|
||||||
|
using osu.Game.Rulesets;
|
||||||
using osu.Game.Rulesets.Mods;
|
using osu.Game.Rulesets.Mods;
|
||||||
using osu.Game.Rulesets.Scoring;
|
using osu.Game.Rulesets.Scoring;
|
||||||
using osu.Game.Scoring;
|
using osu.Game.Scoring;
|
||||||
@ -62,7 +63,7 @@ namespace osu.Game.Online.Rooms
|
|||||||
[CanBeNull]
|
[CanBeNull]
|
||||||
public MultiplayerScoresAround ScoresAround { get; set; }
|
public MultiplayerScoresAround ScoresAround { get; set; }
|
||||||
|
|
||||||
public ScoreInfo CreateScoreInfo(PlaylistItem playlistItem, [NotNull] BeatmapInfo beatmap)
|
public ScoreInfo CreateScoreInfo(RulesetStore rulesets, PlaylistItem playlistItem, [NotNull] BeatmapInfo beatmap)
|
||||||
{
|
{
|
||||||
var rulesetInstance = playlistItem.Ruleset.Value.CreateInstance();
|
var rulesetInstance = playlistItem.Ruleset.Value.CreateInstance();
|
||||||
|
|
||||||
@ -73,7 +74,7 @@ namespace osu.Game.Online.Rooms
|
|||||||
MaxCombo = MaxCombo,
|
MaxCombo = MaxCombo,
|
||||||
BeatmapInfo = beatmap,
|
BeatmapInfo = beatmap,
|
||||||
BeatmapInfoID = playlistItem.BeatmapID,
|
BeatmapInfoID = playlistItem.BeatmapID,
|
||||||
Ruleset = playlistItem.Ruleset.Value,
|
Ruleset = rulesets.GetRuleset(playlistItem.RulesetID),
|
||||||
RulesetID = playlistItem.RulesetID,
|
RulesetID = playlistItem.RulesetID,
|
||||||
Statistics = Statistics,
|
Statistics = Statistics,
|
||||||
User = User,
|
User = User,
|
||||||
|
@ -34,7 +34,7 @@ namespace osu.Game.Online.Rooms
|
|||||||
public readonly Bindable<IBeatmapInfo> Beatmap = new Bindable<IBeatmapInfo>();
|
public readonly Bindable<IBeatmapInfo> Beatmap = new Bindable<IBeatmapInfo>();
|
||||||
|
|
||||||
[JsonIgnore]
|
[JsonIgnore]
|
||||||
public readonly Bindable<RulesetInfo> Ruleset = new Bindable<RulesetInfo>();
|
public readonly Bindable<IRulesetInfo> Ruleset = new Bindable<IRulesetInfo>();
|
||||||
|
|
||||||
[JsonIgnore]
|
[JsonIgnore]
|
||||||
public readonly BindableList<Mod> AllowedMods = new BindableList<Mod>();
|
public readonly BindableList<Mod> AllowedMods = new BindableList<Mod>();
|
||||||
@ -66,7 +66,7 @@ namespace osu.Game.Online.Rooms
|
|||||||
public PlaylistItem()
|
public PlaylistItem()
|
||||||
{
|
{
|
||||||
Beatmap.BindValueChanged(beatmap => BeatmapID = beatmap.NewValue?.OnlineID ?? -1);
|
Beatmap.BindValueChanged(beatmap => BeatmapID = beatmap.NewValue?.OnlineID ?? -1);
|
||||||
Ruleset.BindValueChanged(ruleset => RulesetID = ruleset.NewValue?.ID ?? 0);
|
Ruleset.BindValueChanged(ruleset => RulesetID = ruleset.NewValue?.OnlineID ?? 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void MapObjects(RulesetStore rulesets)
|
public void MapObjects(RulesetStore rulesets)
|
||||||
|
@ -46,7 +46,7 @@ namespace osu.Game.Screens.OnlinePlay
|
|||||||
private ModDisplay modDisplay;
|
private ModDisplay modDisplay;
|
||||||
|
|
||||||
private readonly Bindable<IBeatmapInfo> beatmap = new Bindable<IBeatmapInfo>();
|
private readonly Bindable<IBeatmapInfo> beatmap = new Bindable<IBeatmapInfo>();
|
||||||
private readonly Bindable<RulesetInfo> ruleset = new Bindable<RulesetInfo>();
|
private readonly Bindable<IRulesetInfo> ruleset = new Bindable<IRulesetInfo>();
|
||||||
private readonly BindableList<Mod> requiredMods = new BindableList<Mod>();
|
private readonly BindableList<Mod> requiredMods = new BindableList<Mod>();
|
||||||
|
|
||||||
public readonly PlaylistItem Item;
|
public readonly PlaylistItem Item;
|
||||||
|
@ -18,6 +18,7 @@ using osu.Game.Beatmaps;
|
|||||||
using osu.Game.Online.Rooms;
|
using osu.Game.Online.Rooms;
|
||||||
using osu.Game.Overlays;
|
using osu.Game.Overlays;
|
||||||
using osu.Game.Overlays.Mods;
|
using osu.Game.Overlays.Mods;
|
||||||
|
using osu.Game.Rulesets;
|
||||||
using osu.Game.Rulesets.Mods;
|
using osu.Game.Rulesets.Mods;
|
||||||
using osu.Game.Screens.OnlinePlay.Match.Components;
|
using osu.Game.Screens.OnlinePlay.Match.Components;
|
||||||
|
|
||||||
@ -59,6 +60,9 @@ namespace osu.Game.Screens.OnlinePlay.Match
|
|||||||
[Resolved]
|
[Resolved]
|
||||||
private BeatmapManager beatmapManager { get; set; }
|
private BeatmapManager beatmapManager { get; set; }
|
||||||
|
|
||||||
|
[Resolved]
|
||||||
|
private RulesetStore rulesets { get; set; }
|
||||||
|
|
||||||
[Resolved(canBeNull: true)]
|
[Resolved(canBeNull: true)]
|
||||||
protected OnlinePlayScreen ParentScreen { get; private set; }
|
protected OnlinePlayScreen ParentScreen { get; private set; }
|
||||||
|
|
||||||
@ -344,7 +348,7 @@ namespace osu.Game.Screens.OnlinePlay.Match
|
|||||||
|
|
||||||
UpdateMods();
|
UpdateMods();
|
||||||
|
|
||||||
Ruleset.Value = selected.Ruleset.Value;
|
Ruleset.Value = rulesets.GetRuleset(selected.RulesetID);
|
||||||
|
|
||||||
if (!selected.AllowedMods.Any())
|
if (!selected.AllowedMods.Any())
|
||||||
{
|
{
|
||||||
|
@ -12,6 +12,7 @@ using osu.Framework.Graphics.Containers;
|
|||||||
using osu.Game.Graphics.UserInterface;
|
using osu.Game.Graphics.UserInterface;
|
||||||
using osu.Game.Online.API;
|
using osu.Game.Online.API;
|
||||||
using osu.Game.Online.Rooms;
|
using osu.Game.Online.Rooms;
|
||||||
|
using osu.Game.Rulesets;
|
||||||
using osu.Game.Scoring;
|
using osu.Game.Scoring;
|
||||||
using osu.Game.Screens.Ranking;
|
using osu.Game.Screens.Ranking;
|
||||||
|
|
||||||
@ -35,6 +36,9 @@ namespace osu.Game.Screens.OnlinePlay.Playlists
|
|||||||
[Resolved]
|
[Resolved]
|
||||||
private ScoreManager scoreManager { get; set; }
|
private ScoreManager scoreManager { get; set; }
|
||||||
|
|
||||||
|
[Resolved]
|
||||||
|
private RulesetStore rulesets { get; set; }
|
||||||
|
|
||||||
public PlaylistsResultsScreen(ScoreInfo score, long roomId, PlaylistItem playlistItem, bool allowRetry, bool allowWatchingReplay = true)
|
public PlaylistsResultsScreen(ScoreInfo score, long roomId, PlaylistItem playlistItem, bool allowRetry, bool allowWatchingReplay = true)
|
||||||
: base(score, allowRetry, allowWatchingReplay)
|
: base(score, allowRetry, allowWatchingReplay)
|
||||||
{
|
{
|
||||||
@ -169,7 +173,7 @@ namespace osu.Game.Screens.OnlinePlay.Playlists
|
|||||||
/// <param name="pivot">An optional pivot around which the scores were retrieved.</param>
|
/// <param name="pivot">An optional pivot around which the scores were retrieved.</param>
|
||||||
private void performSuccessCallback([NotNull] Action<IEnumerable<ScoreInfo>> callback, [NotNull] List<MultiplayerScore> scores, [CanBeNull] MultiplayerScores pivot = null)
|
private void performSuccessCallback([NotNull] Action<IEnumerable<ScoreInfo>> callback, [NotNull] List<MultiplayerScore> scores, [CanBeNull] MultiplayerScores pivot = null)
|
||||||
{
|
{
|
||||||
var scoreInfos = scores.Select(s => s.CreateScoreInfo(playlistItem, Beatmap.Value.BeatmapInfo)).ToArray();
|
var scoreInfos = scores.Select(s => s.CreateScoreInfo(rulesets, playlistItem, Beatmap.Value.BeatmapInfo)).ToArray();
|
||||||
|
|
||||||
// Score panels calculate total score before displaying, which can take some time. In order to count that calculation as part of the loading spinner display duration,
|
// Score panels calculate total score before displaying, which can take some time. In order to count that calculation as part of the loading spinner display duration,
|
||||||
// calculate the total scores locally before invoking the success callback.
|
// calculate the total scores locally before invoking the success callback.
|
||||||
|
16
osu.Game/Updater/GitHubAsset.cs
Normal file
16
osu.Game/Updater/GitHubAsset.cs
Normal file
@ -0,0 +1,16 @@
|
|||||||
|
// Copyright (c) ppy Pty Ltd <contact@ppy.sh>. Licensed under the MIT Licence.
|
||||||
|
// See the LICENCE file in the repository root for full licence text.
|
||||||
|
|
||||||
|
using Newtonsoft.Json;
|
||||||
|
|
||||||
|
namespace osu.Game.Updater
|
||||||
|
{
|
||||||
|
public class GitHubAsset
|
||||||
|
{
|
||||||
|
[JsonProperty("name")]
|
||||||
|
public string Name { get; set; }
|
||||||
|
|
||||||
|
[JsonProperty("browser_download_url")]
|
||||||
|
public string BrowserDownloadUrl { get; set; }
|
||||||
|
}
|
||||||
|
}
|
20
osu.Game/Updater/GitHubRelease.cs
Normal file
20
osu.Game/Updater/GitHubRelease.cs
Normal file
@ -0,0 +1,20 @@
|
|||||||
|
// Copyright (c) ppy Pty Ltd <contact@ppy.sh>. Licensed under the MIT Licence.
|
||||||
|
// See the LICENCE file in the repository root for full licence text.
|
||||||
|
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using Newtonsoft.Json;
|
||||||
|
|
||||||
|
namespace osu.Game.Updater
|
||||||
|
{
|
||||||
|
public class GitHubRelease
|
||||||
|
{
|
||||||
|
[JsonProperty("html_url")]
|
||||||
|
public string HtmlUrl { get; set; }
|
||||||
|
|
||||||
|
[JsonProperty("tag_name")]
|
||||||
|
public string TagName { get; set; }
|
||||||
|
|
||||||
|
[JsonProperty("assets")]
|
||||||
|
public List<GitHubAsset> Assets { get; set; }
|
||||||
|
}
|
||||||
|
}
|
67
osu.Game/Updater/NoActionUpdateManager.cs
Normal file
67
osu.Game/Updater/NoActionUpdateManager.cs
Normal file
@ -0,0 +1,67 @@
|
|||||||
|
// Copyright (c) ppy Pty Ltd <contact@ppy.sh>. Licensed under the MIT Licence.
|
||||||
|
// See the LICENCE file in the repository root for full licence text.
|
||||||
|
|
||||||
|
using System.Linq;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
using osu.Framework.Allocation;
|
||||||
|
using osu.Framework.Graphics.Sprites;
|
||||||
|
using osu.Framework.Platform;
|
||||||
|
using osu.Game.Online.API;
|
||||||
|
using osu.Game.Overlays.Notifications;
|
||||||
|
|
||||||
|
namespace osu.Game.Updater
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// An update manager that shows notifications if a newer release is detected.
|
||||||
|
/// This is a case where updates are handled externally by a package manager or other means, so no action is performed on clicking the notification.
|
||||||
|
/// </summary>
|
||||||
|
public class NoActionUpdateManager : UpdateManager
|
||||||
|
{
|
||||||
|
private string version;
|
||||||
|
|
||||||
|
[Resolved]
|
||||||
|
private GameHost host { get; set; }
|
||||||
|
|
||||||
|
[BackgroundDependencyLoader]
|
||||||
|
private void load(OsuGameBase game)
|
||||||
|
{
|
||||||
|
version = game.Version;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected override async Task<bool> PerformUpdateCheck()
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
var releases = new OsuJsonWebRequest<GitHubRelease>("https://api.github.com/repos/ppy/osu/releases/latest");
|
||||||
|
|
||||||
|
await releases.PerformAsync().ConfigureAwait(false);
|
||||||
|
|
||||||
|
var latest = releases.ResponseObject;
|
||||||
|
|
||||||
|
// avoid any discrepancies due to build suffixes for now.
|
||||||
|
// eventually we will want to support release streams and consider these.
|
||||||
|
version = version.Split('-').First();
|
||||||
|
string latestTagName = latest.TagName.Split('-').First();
|
||||||
|
|
||||||
|
if (latestTagName != version)
|
||||||
|
{
|
||||||
|
Notifications.Post(new SimpleNotification
|
||||||
|
{
|
||||||
|
Text = $"A newer release of osu! has been found ({version} → {latestTagName}).\n\n"
|
||||||
|
+ "Check with your package manager / provider to bring osu! up-to-date!",
|
||||||
|
Icon = FontAwesome.Solid.Upload,
|
||||||
|
});
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
catch
|
||||||
|
{
|
||||||
|
// we shouldn't crash on a web failure. or any failure for the matter.
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -2,10 +2,8 @@
|
|||||||
// See the LICENCE file in the repository root for full licence text.
|
// See the LICENCE file in the repository root for full licence text.
|
||||||
|
|
||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
using Newtonsoft.Json;
|
|
||||||
using osu.Framework;
|
using osu.Framework;
|
||||||
using osu.Framework.Allocation;
|
using osu.Framework.Allocation;
|
||||||
using osu.Framework.Graphics.Sprites;
|
using osu.Framework.Graphics.Sprites;
|
||||||
@ -104,26 +102,5 @@ namespace osu.Game.Updater
|
|||||||
|
|
||||||
return bestAsset?.BrowserDownloadUrl ?? release.HtmlUrl;
|
return bestAsset?.BrowserDownloadUrl ?? release.HtmlUrl;
|
||||||
}
|
}
|
||||||
|
|
||||||
public class GitHubRelease
|
|
||||||
{
|
|
||||||
[JsonProperty("html_url")]
|
|
||||||
public string HtmlUrl { get; set; }
|
|
||||||
|
|
||||||
[JsonProperty("tag_name")]
|
|
||||||
public string TagName { get; set; }
|
|
||||||
|
|
||||||
[JsonProperty("assets")]
|
|
||||||
public List<GitHubAsset> Assets { get; set; }
|
|
||||||
}
|
|
||||||
|
|
||||||
public class GitHubAsset
|
|
||||||
{
|
|
||||||
[JsonProperty("name")]
|
|
||||||
public string Name { get; set; }
|
|
||||||
|
|
||||||
[JsonProperty("browser_download_url")]
|
|
||||||
public string BrowserDownloadUrl { get; set; }
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user