Skip to content

Commit

Permalink
PlayerInfo Crawler Plugin
Browse files Browse the repository at this point in the history
  • Loading branch information
Deliay committed Aug 2, 2020
1 parent 9fd67b7 commit 4963c57
Show file tree
Hide file tree
Showing 12 changed files with 388 additions and 1 deletion.
9 changes: 8 additions & 1 deletion EmberTools.sln
Original file line number Diff line number Diff line change
Expand Up @@ -61,7 +61,9 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Statistic.Outputs", "src\pl
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Statistic.Outputs.Web", "src\plugins\statistic\Statistic.Outputs.Web\Statistic.Outputs.Web.csproj", "{E5B66599-C70E-41D9-B5D8-C91BCDCF23D1}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "SimpleHttpServer", "src\share\SimpleHttpServer\SimpleHttpServer.csproj", "{0B2DCD29-AC36-4A4C-982C-826BFE5656D9}"
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "SimpleHttpServer", "src\share\SimpleHttpServer\SimpleHttpServer.csproj", "{0B2DCD29-AC36-4A4C-982C-826BFE5656D9}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "CurrentPlayerInformation", "src\plugins\osu\CurrentPlayerInformation\CurrentPlayerInformation.csproj", "{EED93CAE-6FA6-470F-8478-45B18B341487}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Expand Down Expand Up @@ -161,6 +163,10 @@ Global
{0B2DCD29-AC36-4A4C-982C-826BFE5656D9}.Debug|Any CPU.Build.0 = Debug|Any CPU
{0B2DCD29-AC36-4A4C-982C-826BFE5656D9}.Release|Any CPU.ActiveCfg = Release|Any CPU
{0B2DCD29-AC36-4A4C-982C-826BFE5656D9}.Release|Any CPU.Build.0 = Release|Any CPU
{EED93CAE-6FA6-470F-8478-45B18B341487}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{EED93CAE-6FA6-470F-8478-45B18B341487}.Debug|Any CPU.Build.0 = Debug|Any CPU
{EED93CAE-6FA6-470F-8478-45B18B341487}.Release|Any CPU.ActiveCfg = Release|Any CPU
{EED93CAE-6FA6-470F-8478-45B18B341487}.Release|Any CPU.Build.0 = Release|Any CPU
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
Expand Down Expand Up @@ -194,6 +200,7 @@ Global
{43E56927-682C-4677-9589-352C20E8A28C} = {0E09347E-63CE-4D05-A401-8B80A2449F74}
{E5B66599-C70E-41D9-B5D8-C91BCDCF23D1} = {0E09347E-63CE-4D05-A401-8B80A2449F74}
{0B2DCD29-AC36-4A4C-982C-826BFE5656D9} = {239B3BE6-770D-4BAD-AA11-FD91A2D62D02}
{EED93CAE-6FA6-470F-8478-45B18B341487} = {9AECDFA1-D8A9-4189-A390-625ADB7D06E8}
EndGlobalSection
GlobalSection(ExtensibilityGlobals) = postSolution
SolutionGuid = {57B800AC-CFE3-4081-8EC4-9BD1C74869B0}
Expand Down
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);
}
}
}
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&#xD;&#xA;mkdir $(SolutionDir)build\$(ConfigurationName)\plugins\$(ProjectName)&#xD;&#xA;copy $(OutDir)\* $(SolutionDir)build\$(ConfigurationName)\plugins\$(ProjectName)" />
</Target>

</Project>
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;
}
}
}
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; }
}
}
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; }
}
}
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,
};
}
}
}
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; }
}
}
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 src/plugins/osu/CurrentPlayerInformation/Models/PlayerRank.cs
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 src/plugins/osu/CurrentPlayerInformation/Models/PlayerStatistic.cs
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; }
}
}
Loading

0 comments on commit 4963c57

Please sign in to comment.