-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Showing
12 changed files
with
388 additions
and
1 deletion.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
97 changes: 97 additions & 0 deletions
97
src/plugins/osu/CurrentPlayerInformation/Components/PlayerInformationCrawler.cs
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,97 @@ | ||
using CurrentPlayerInformation.Models; | ||
using CurrentPlayerInformation.Util; | ||
using EmberKernel.Plugins.Components; | ||
using EmberKernel.Services.EventBus; | ||
using EmberKernel.Services.EventBus.Handlers; | ||
using EmberMemoryReader.Abstract.Data; | ||
using EmberMemoryReader.Abstract.Events; | ||
using Microsoft.Extensions.Logging; | ||
using System; | ||
using System.Collections.Generic; | ||
using System.Net.Http; | ||
using System.Text.Json; | ||
using System.Threading.Tasks; | ||
|
||
namespace CurrentPlayerInformation.Components | ||
{ | ||
public class PlayerInformationCrawler : IComponent, | ||
IEventHandler<OsuProcessMatchedEvent>, | ||
IEventHandler<PlayingInfo> | ||
{ | ||
public ILogger<PlayerInformationCrawler> Logger { get; set; } | ||
public IEventBus EventBus { get; set; } | ||
private readonly HttpClient _requestor = new HttpClient(); | ||
private readonly Dictionary<string, (PlayerInformation, DateTime)> _informationCache = new Dictionary<string, (PlayerInformation, DateTime)>(); | ||
private string lastPlayerName = null; | ||
|
||
private readonly static JsonSerializerOptions SerializerOptions = new JsonSerializerOptions() | ||
{ | ||
PropertyNamingPolicy = SnakeCase.Policy, | ||
}; | ||
|
||
private class SnakeCase : JsonNamingPolicy | ||
{ | ||
public readonly static SnakeCase Policy = new SnakeCase(); | ||
public override string ConvertName(string name) | ||
{ | ||
return name.ToSnakeCase(); | ||
} | ||
} | ||
|
||
private async ValueTask<(bool, PlayerInformation)> TryCrawlerPlayerInformation(string playerName) | ||
{ | ||
Logger.LogInformation($"Start crawl the information of player {playerName}"); | ||
if (_informationCache.ContainsKey(playerName)) | ||
{ | ||
var (cachedInfo, crawledAt) = _informationCache[playerName]; | ||
if ((DateTime.Now - crawledAt).TotalMinutes < 30) | ||
return (true, cachedInfo); | ||
} | ||
using var res = await _requestor.GetAsync($"https://osu.ppy.sh/users/{playerName}"); | ||
if (!res.IsSuccessStatusCode) { return (false, null); } | ||
var rawHtml = await res.Content.ReadAsStringAsync(); | ||
var userJsonStartPos = rawHtml.IndexOf(">", rawHtml.LastIndexOf("json-user")) + 1; | ||
var userJsonEndPos = rawHtml.IndexOf("</script>", userJsonStartPos); | ||
var userJson = rawHtml[userJsonStartPos..userJsonEndPos]; | ||
|
||
var info = JsonSerializer.Deserialize<PlayerInformation>(userJson, SerializerOptions); | ||
_informationCache[playerName] = (info, DateTime.Now); | ||
return (true, info); | ||
} | ||
|
||
public async ValueTask ProcessCurrentPlayerName(string playerName) | ||
{ | ||
if (playerName == null) return; | ||
if (lastPlayerName != playerName) | ||
{ | ||
lastPlayerName = playerName; | ||
var (succeed, info) = await TryCrawlerPlayerInformation(playerName); | ||
if (succeed) | ||
{ | ||
EventBus.Publish(PlayerInformationEvent.FromPlayerInformation(info)); | ||
return; | ||
} | ||
else | ||
{ | ||
Logger.LogInformation($"Crawl failed! May player {playerName} not exist."); | ||
} | ||
} | ||
} | ||
|
||
public ValueTask Handle(OsuProcessMatchedEvent @event) | ||
{ | ||
_ = ProcessCurrentPlayerName(@event.UserName); | ||
return default; | ||
} | ||
|
||
public void Dispose() | ||
{ | ||
_requestor.Dispose(); | ||
} | ||
|
||
public ValueTask Handle(PlayingInfo @event) | ||
{ | ||
return ProcessCurrentPlayerName(@event.CurrentPlayerName); | ||
} | ||
} | ||
} |
18 changes: 18 additions & 0 deletions
18
src/plugins/osu/CurrentPlayerInformation/CurrentPlayerInformation.csproj
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,18 @@ | ||
<Project Sdk="Microsoft.NET.Sdk"> | ||
|
||
<PropertyGroup> | ||
<TargetFramework>netstandard2.1</TargetFramework> | ||
</PropertyGroup> | ||
|
||
<ItemGroup> | ||
<ProjectReference Include="..\..\..\EmberKernel\EmberKernel.csproj"> | ||
<Private>false</Private> | ||
</ProjectReference> | ||
<ProjectReference Include="..\EmberMemoryReader.Abstract\EmberMemoryReader.Abstract.csproj" /> | ||
</ItemGroup> | ||
|
||
<Target Name="PostBuild" AfterTargets="PostBuildEvent"> | ||
<Exec Command="move $(OutDir)\$(TargetFileName) $(OutDir)\$(TargetName).dll
mkdir $(SolutionDir)build\$(ConfigurationName)\plugins\$(ProjectName)
copy $(OutDir)\* $(SolutionDir)build\$(ConfigurationName)\plugins\$(ProjectName)" /> | ||
</Target> | ||
|
||
</Project> |
41 changes: 41 additions & 0 deletions
41
src/plugins/osu/CurrentPlayerInformation/CurrentPlayerInformationPlugin.cs
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,41 @@ | ||
using Autofac; | ||
using CurrentPlayerInformation.Components; | ||
using CurrentPlayerInformation.Models; | ||
using EmberKernel; | ||
using EmberKernel.Plugins; | ||
using EmberKernel.Plugins.Attributes; | ||
using EmberKernel.Plugins.Components; | ||
using EmberKernel.Services.Statistic.Extension; | ||
using EmberMemoryReader.Abstract.Data; | ||
using EmberMemoryReader.Abstract.Events; | ||
using System.Threading.Tasks; | ||
|
||
namespace CurrentPlayerInformation | ||
{ | ||
|
||
[EmberPlugin(Author = "Deliay", Name = "CurrentPlayerInformationPlugin", Version = "0.0.1")] | ||
public class CurrentPlayerInformationPlugin : Plugin | ||
{ | ||
public override void BuildComponents(IComponentBuilder builder) | ||
{ | ||
builder.ConfigureEventStatistic<PlayerInformationEvent>(); | ||
builder.ConfigureComponent<PlayerInformationCrawler>().SingleInstance().PropertiesAutowired(); | ||
} | ||
|
||
public override ValueTask Initialize(ILifetimeScope scope) | ||
{ | ||
scope.Subscription<OsuProcessMatchedEvent, PlayerInformationCrawler>(); | ||
scope.Subscription<PlayingInfo, PlayerInformationCrawler>(); | ||
scope.Track<PlayerInformationEvent>(); | ||
return default; | ||
} | ||
|
||
public override ValueTask Uninitialize(ILifetimeScope scope) | ||
{ | ||
scope.Untrack<PlayerInformationEvent>(); | ||
scope.Unsubscription<OsuProcessMatchedEvent, PlayerInformationCrawler>(); | ||
scope.Unsubscription<PlayingInfo, PlayerInformationCrawler>(); | ||
return default; | ||
} | ||
} | ||
} |
11 changes: 11 additions & 0 deletions
11
src/plugins/osu/CurrentPlayerInformation/Models/PlayerGradeCount.cs
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,11 @@ | ||
namespace CurrentPlayerInformation.Models | ||
{ | ||
public class PlayerGradeCount | ||
{ | ||
public int SS { get; set; } | ||
public int Ssh { get; set; } | ||
public int S { get; set; } | ||
public int Sh{ get; set; } | ||
public int A { get; set; } | ||
} | ||
} |
17 changes: 17 additions & 0 deletions
17
src/plugins/osu/CurrentPlayerInformation/Models/PlayerInformation.cs
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,17 @@ | ||
using System; | ||
using System.Collections.Generic; | ||
|
||
namespace CurrentPlayerInformation.Models | ||
{ | ||
public class PlayerInformation | ||
{ | ||
public string AvatarUrl { get; set; } | ||
public string CoverUrl { get; set; } | ||
public string CountryCode { get; set; } | ||
public bool IsOnline { get; set; } | ||
public DateTimeOffset JoinDate { get; set; } | ||
public string Username { get; set; } | ||
public List<PlayerMonthlyPlayCount> MonthlyPlaycounts { get; set; } | ||
public PlayerStatistic Statistics { get; set; } | ||
} | ||
} |
88 changes: 88 additions & 0 deletions
88
src/plugins/osu/CurrentPlayerInformation/Models/PlayerInformationEvent.cs
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,88 @@ | ||
using EmberKernel.Services.EventBus; | ||
using EmberKernel.Services.Statistic.DataSource.Variables; | ||
using System; | ||
|
||
namespace CurrentPlayerInformation.Models | ||
{ | ||
public class PlayerInformationEvent : Event<PlayerInformationEvent> | ||
{ | ||
[DataSourceVariable] | ||
public string AvatarUrl { get; set; } | ||
[DataSourceVariable] | ||
public string CoverUrl { get; set; } | ||
[DataSourceVariable] | ||
public string CountryCode { get; set; } | ||
[DataSourceVariable] | ||
public bool IsOnline { get; set; } | ||
[DataSourceVariable] | ||
public DateTimeOffset JoinDate { get; set; } | ||
[DataSourceVariable] | ||
public string Username { get; set; } | ||
[DataSourceVariable] | ||
public int SS { get; set; } | ||
[DataSourceVariable] | ||
public int Ssh { get; set; } | ||
[DataSourceVariable] | ||
public int S { get; set; } | ||
[DataSourceVariable] | ||
public int Sh { get; set; } | ||
[DataSourceVariable] | ||
public int A { get; set; } | ||
[DataSourceVariable] | ||
public int CurrentLevel { get; set; } | ||
[DataSourceVariable] | ||
public int LevelProgress { get; set; } | ||
[DataSourceVariable] | ||
public double PP { get; set; } | ||
[DataSourceVariable] | ||
public int PPRank { get; set; } | ||
[DataSourceVariable] | ||
public long RankedScore { get; set; } | ||
[DataSourceVariable] | ||
public double HitAccuracy { get; set; } | ||
[DataSourceVariable] | ||
public int PlayCount { get; set; } | ||
[DataSourceVariable] | ||
public int PlayTime { get; set; } | ||
[DataSourceVariable] | ||
public long TotalScore { get; set; } | ||
[DataSourceVariable] | ||
public int TotalHit { get; set; } | ||
[DataSourceVariable] | ||
public int MaximumCombo { get; set; } | ||
[DataSourceVariable] | ||
public int ReaplysWatchedByOthers { get; set; } | ||
[DataSourceVariable] | ||
public bool IsRanked { get; set; } | ||
public static PlayerInformationEvent FromPlayerInformation(PlayerInformation information) | ||
{ | ||
return new PlayerInformationEvent() | ||
{ | ||
A = information.Statistics.GradeCounts.A, | ||
SS = information.Statistics.GradeCounts.SS, | ||
S = information.Statistics.GradeCounts.S, | ||
Sh = information.Statistics.GradeCounts.Sh, | ||
Ssh = information.Statistics.GradeCounts.Ssh, | ||
AvatarUrl = information.AvatarUrl, | ||
CountryCode = information.CountryCode, | ||
CoverUrl = information.CoverUrl, | ||
CurrentLevel = information.Statistics.Level.Current, | ||
LevelProgress = information.Statistics.Level.Progress, | ||
PP = information.Statistics.PP, | ||
PPRank = information.Statistics.PPRank, | ||
RankedScore = information.Statistics.RankedScore, | ||
HitAccuracy = information.Statistics.HitAccuracy, | ||
PlayCount = information.Statistics.PlayCount, | ||
PlayTime = information.Statistics.PlayTime, | ||
TotalScore = information.Statistics.TotalScore, | ||
TotalHit = information.Statistics.TotalHit, | ||
MaximumCombo = information.Statistics.MaximumCombo, | ||
ReaplysWatchedByOthers = information.Statistics.ReaplysWatchedByOthers, | ||
IsRanked = information.Statistics.IsRanked, | ||
Username = information.Username, | ||
IsOnline = information.IsOnline, | ||
JoinDate = information.JoinDate, | ||
}; | ||
} | ||
} | ||
} |
8 changes: 8 additions & 0 deletions
8
src/plugins/osu/CurrentPlayerInformation/Models/PlayerLevel.cs
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,8 @@ | ||
namespace CurrentPlayerInformation.Models | ||
{ | ||
public class PlayerLevel | ||
{ | ||
public int Current { get; set; } | ||
public int Progress { get; set; } | ||
} | ||
} |
8 changes: 8 additions & 0 deletions
8
src/plugins/osu/CurrentPlayerInformation/Models/PlayerMonthlyPlayCount.cs
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,8 @@ | ||
namespace CurrentPlayerInformation.Models | ||
{ | ||
public class PlayerMonthlyPlayCount | ||
{ | ||
public string StartDate { get; set; } | ||
public int Count { get; set; } | ||
} | ||
} |
8 changes: 8 additions & 0 deletions
8
src/plugins/osu/CurrentPlayerInformation/Models/PlayerRank.cs
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,8 @@ | ||
namespace CurrentPlayerInformation.Models | ||
{ | ||
public class PlayerRank | ||
{ | ||
public int Global { get; set; } | ||
public int Country { get; set; } | ||
} | ||
} |
19 changes: 19 additions & 0 deletions
19
src/plugins/osu/CurrentPlayerInformation/Models/PlayerStatistic.cs
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,19 @@ | ||
namespace CurrentPlayerInformation.Models | ||
{ | ||
public class PlayerStatistic | ||
{ | ||
public PlayerLevel Level { get; set; } | ||
public double PP { get; set; } | ||
public int PPRank{ get; set; } | ||
public long RankedScore { get; set; } | ||
public double HitAccuracy { get; set; } | ||
public int PlayCount { get; set; } | ||
public int PlayTime { get; set; } | ||
public long TotalScore { get; set; } | ||
public int TotalHit { get; set; } | ||
public int MaximumCombo { get; set; } | ||
public int ReaplysWatchedByOthers { get; set; } | ||
public bool IsRanked { get; set; } | ||
public PlayerGradeCount GradeCounts { get; set; } | ||
} | ||
} |
Oops, something went wrong.