add code
This commit is contained in:
parent
477e223e93
commit
f67fdbe537
|
@ -0,0 +1,3 @@
|
|||
.vs/*
|
||||
*/bin/*
|
||||
*/obj/*
|
|
@ -0,0 +1,25 @@
|
|||
|
||||
Microsoft Visual Studio Solution File, Format Version 12.00
|
||||
# Visual Studio Version 17
|
||||
VisualStudioVersion = 17.4.33205.214
|
||||
MinimumVisualStudioVersion = 10.0.40219.1
|
||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "PluralRichPresence", "PluralRichPresnce\PluralRichPresence.csproj", "{F0DA03B7-E669-48A4-85E5-3B3080552BFF}"
|
||||
EndProject
|
||||
Global
|
||||
GlobalSection(SolutionConfigurationPlatforms) = preSolution
|
||||
Debug|Any CPU = Debug|Any CPU
|
||||
Release|Any CPU = Release|Any CPU
|
||||
EndGlobalSection
|
||||
GlobalSection(ProjectConfigurationPlatforms) = postSolution
|
||||
{F0DA03B7-E669-48A4-85E5-3B3080552BFF}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{F0DA03B7-E669-48A4-85E5-3B3080552BFF}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{F0DA03B7-E669-48A4-85E5-3B3080552BFF}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{F0DA03B7-E669-48A4-85E5-3B3080552BFF}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
EndGlobalSection
|
||||
GlobalSection(SolutionProperties) = preSolution
|
||||
HideSolutionNode = FALSE
|
||||
EndGlobalSection
|
||||
GlobalSection(ExtensibilityGlobals) = postSolution
|
||||
SolutionGuid = {2D6CBC9C-96A6-4B89-ABC7-46DA68F481B8}
|
||||
EndGlobalSection
|
||||
EndGlobal
|
|
@ -0,0 +1,33 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace PluralRichPresence
|
||||
{
|
||||
public class ConfigReader
|
||||
{
|
||||
const string CFG_NAME = "plurality.cfg";
|
||||
const char SEPERATOR = ':';
|
||||
|
||||
public static string ReadString(string key)
|
||||
{
|
||||
StreamReader txtReader = new StreamReader(File.OpenRead(CFG_NAME));
|
||||
|
||||
for (string? line = txtReader.ReadLine(); line is not null; line = txtReader.ReadLine())
|
||||
{
|
||||
line = line.Trim().ReplaceLineEndings(String.Empty);
|
||||
if (!line.Contains(SEPERATOR)) continue;
|
||||
string[] configOptions = line.Split(SEPERATOR);
|
||||
|
||||
if (configOptions[0].Trim() == key)
|
||||
return configOptions[1].Trim();
|
||||
}
|
||||
|
||||
return "";
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
}
|
|
@ -0,0 +1,45 @@
|
|||
using DiscordRPC;
|
||||
using DiscordRPC.Logging;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Reflection.Emit;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace PluralRichPresence
|
||||
{
|
||||
|
||||
public class DiscordRPC
|
||||
{
|
||||
private DiscordRpcClient client;
|
||||
|
||||
public DiscordRPC()
|
||||
{
|
||||
client = new DiscordRpcClient(ConfigReader.ReadString("APPLICATION_ID"));
|
||||
|
||||
client.Logger = new ConsoleLogger() { Level = LogLevel.Warning };
|
||||
|
||||
client.OnReady += (sender, e) => {};
|
||||
|
||||
client.OnPresenceUpdate += (sender, e) => {};
|
||||
|
||||
client.Initialize();
|
||||
}
|
||||
|
||||
public void SetFronter(string user, string pronouns, string profile)
|
||||
{
|
||||
client.SetPresence(new RichPresence()
|
||||
{
|
||||
Details = user,
|
||||
State = pronouns,
|
||||
Assets = new Assets()
|
||||
{
|
||||
LargeImageKey = profile,
|
||||
LargeImageText = user + " - " +pronouns,
|
||||
SmallImageKey = "plural"
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,15 @@
|
|||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
|
||||
<PropertyGroup>
|
||||
<OutputType>Exe</OutputType>
|
||||
<TargetFramework>net7.0</TargetFramework>
|
||||
<ImplicitUsings>enable</ImplicitUsings>
|
||||
<Nullable>enable</Nullable>
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<PackageReference Include="DiscordRichPresence" Version="1.2.1.24" />
|
||||
<PackageReference Include="Newtonsoft.Json" Version="13.0.3" />
|
||||
</ItemGroup>
|
||||
|
||||
</Project>
|
|
@ -0,0 +1,51 @@
|
|||
using DiscordRPC;
|
||||
using DiscordRPC.Logging;
|
||||
using Newtonsoft.Json;
|
||||
using PluralRichPresence.SimplyPlural;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Dynamic;
|
||||
using System.Linq;
|
||||
using System.Net.WebSockets;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
using static System.Net.Mime.MediaTypeNames;
|
||||
|
||||
namespace PluralRichPresence
|
||||
{
|
||||
internal class Program
|
||||
{
|
||||
private static ManualResetEvent waitHandle = new ManualResetEvent(false);
|
||||
private static DiscordRPC discordRpc = new DiscordRPC();
|
||||
public static System system;
|
||||
public static async Task UpdateFronterStatus()
|
||||
{
|
||||
// get fronting members
|
||||
Member[] frontingMembers = await system.GetCurrentFronterInfo();
|
||||
if (frontingMembers.Length > 0)
|
||||
{
|
||||
Member fronter = frontingMembers.First();
|
||||
discordRpc.SetFronter(fronter.Name, fronter.Pronouns, (fronter.AvatarURL is null) ? "plural" : fronter.AvatarURL);
|
||||
}
|
||||
else
|
||||
{
|
||||
discordRpc.SetFronter("No one is fronting.", "This doesn't make much sense?", "plural");
|
||||
}
|
||||
}
|
||||
public static void Main(string[] args)
|
||||
{
|
||||
|
||||
system = new System(ConfigReader.ReadString("SIMPLY_PLURAL_TOKEN"));
|
||||
|
||||
system.FronterChanged += onFronterChanged;
|
||||
_ = UpdateFronterStatus();
|
||||
|
||||
waitHandle.WaitOne();
|
||||
}
|
||||
|
||||
private static void onFronterChanged(object? sender, EventArgs e)
|
||||
{
|
||||
_ = UpdateFronterStatus();
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,19 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<!--
|
||||
https://go.microsoft.com/fwlink/?LinkID=208121.
|
||||
-->
|
||||
<Project>
|
||||
<PropertyGroup>
|
||||
<Configuration>Release</Configuration>
|
||||
<Platform>Any CPU</Platform>
|
||||
<PublishDir>bin\Release\net7.0\publish\win-x86\</PublishDir>
|
||||
<PublishProtocol>FileSystem</PublishProtocol>
|
||||
<_TargetId>Folder</_TargetId>
|
||||
<TargetFramework>net7.0</TargetFramework>
|
||||
<RuntimeIdentifier>win-x86</RuntimeIdentifier>
|
||||
<SelfContained>true</SelfContained>
|
||||
<PublishSingleFile>true</PublishSingleFile>
|
||||
<PublishReadyToRun>true</PublishReadyToRun>
|
||||
<PublishTrimmed>true</PublishTrimmed>
|
||||
</PropertyGroup>
|
||||
</Project>
|
|
@ -0,0 +1,6 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<!--
|
||||
https://go.microsoft.com/fwlink/?LinkID=208121.
|
||||
-->
|
||||
<Project>
|
||||
</Project>
|
|
@ -0,0 +1,18 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace PluralRichPresence.SimplyPlural
|
||||
{
|
||||
public class ApiType
|
||||
{
|
||||
internal string token;
|
||||
|
||||
public ApiType(string token)
|
||||
{
|
||||
this.token = token;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,38 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
using static System.Net.WebRequestMethods;
|
||||
|
||||
namespace PluralRichPresence.SimplyPlural
|
||||
{
|
||||
public class Member
|
||||
{
|
||||
public string Name;
|
||||
public string Pronouns;
|
||||
public string? AvatarURL;
|
||||
public string Id;
|
||||
public string SystemId;
|
||||
|
||||
public Member(string systemId,
|
||||
string name,
|
||||
string pronouns,
|
||||
string id,
|
||||
string? avatarUUID,
|
||||
string? avatarURL)
|
||||
{
|
||||
this.Name = name;
|
||||
this.Pronouns = pronouns;
|
||||
|
||||
if ((avatarURL == "" || avatarURL is null) &&
|
||||
(avatarUUID != "" || avatarUUID is not null))
|
||||
{
|
||||
this.AvatarURL = "https://spaces.apparyllis.com/avatars/" + systemId + "/" + avatarUUID;
|
||||
}
|
||||
|
||||
this.Id = id;
|
||||
this.SystemId = systemId;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,78 @@
|
|||
using Newtonsoft.Json;
|
||||
using Newtonsoft.Json.Linq;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace PluralRichPresence.SimplyPlural
|
||||
{
|
||||
public class Rest : ApiType
|
||||
{
|
||||
private HttpClient client = new HttpClient();
|
||||
private const string HOST = "https://api.apparyllis.com";
|
||||
|
||||
private async Task<dynamic> get(string apiEndpoint)
|
||||
{
|
||||
HttpResponseMessage response = await client.GetAsync(HOST + apiEndpoint);
|
||||
string responseText = Encoding.UTF8.GetString(await response.Content.ReadAsByteArrayAsync());
|
||||
Console.WriteLine("HTTP: " + responseText);
|
||||
dynamic? result = JsonConvert.DeserializeObject(responseText);
|
||||
return (result is null) ? new JObject() : (dynamic)result;
|
||||
}
|
||||
|
||||
public async Task<string> GetSystemId()
|
||||
{
|
||||
dynamic system = await get("/v1/me");
|
||||
return system.id;
|
||||
}
|
||||
|
||||
public async Task<string[]> GetCurrentFronters()
|
||||
{
|
||||
dynamic fronters = await get("/v1/fronters");
|
||||
List<string> userIdList = new List<string>();
|
||||
|
||||
for (int i = 0; i < fronters.Count; i++)
|
||||
{
|
||||
bool fronterExist = fronters[i].exists;
|
||||
if (!fronterExist) continue;
|
||||
|
||||
string fronterMemberId = fronters[i].content.member;
|
||||
userIdList.Add(fronterMemberId);
|
||||
}
|
||||
|
||||
return userIdList.ToArray();
|
||||
}
|
||||
|
||||
|
||||
public async Task<Member[]> GetMembers(string systemId)
|
||||
{
|
||||
dynamic members = await get("/v1/members/" + systemId);
|
||||
List<Member> memberList = new List<Member>();
|
||||
|
||||
for(int i = 0; i < members.Count; i++)
|
||||
{
|
||||
bool sysMemberExist = members[i].exists;
|
||||
if (!sysMemberExist) continue;
|
||||
|
||||
string sysMemberId = members[i].id;
|
||||
string sysMemberSystemId = members[i].content.uid;
|
||||
string sysMemberName = members[i].content.name;
|
||||
string sysMemberPronouns = members[i].content.pronouns;
|
||||
string sysMemberAvaUrl = members[i].content.avatarUrl;
|
||||
string sysMemberAvaUid = members[i].content.avatarUuid;
|
||||
|
||||
memberList.Add(new Member(sysMemberSystemId, sysMemberName, sysMemberPronouns, sysMemberId, sysMemberAvaUid, sysMemberAvaUrl));
|
||||
}
|
||||
|
||||
return memberList.ToArray();
|
||||
}
|
||||
|
||||
public Rest(string token) : base(token)
|
||||
{
|
||||
client.DefaultRequestHeaders.TryAddWithoutValidation("User-Agent", "Plural Rich Presence/1.0;");
|
||||
client.DefaultRequestHeaders.TryAddWithoutValidation("Authorization", token);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,117 @@
|
|||
using Newtonsoft.Json.Linq;
|
||||
using Newtonsoft.Json;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Dynamic;
|
||||
using System.Linq;
|
||||
using System.Net.WebSockets;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace PluralRichPresence.SimplyPlural
|
||||
{
|
||||
public class Socket : ApiType
|
||||
{
|
||||
public event EventHandler FronterChanged;
|
||||
ClientWebSocket wss = new ClientWebSocket();
|
||||
Timer? keepAliveTimer = null;
|
||||
|
||||
private void onFronterChanged(dynamic fronterChangedEventData)
|
||||
{
|
||||
if(FronterChanged is not null)
|
||||
{
|
||||
FronterChanged(this, new EventArgs());
|
||||
}
|
||||
}
|
||||
private async Task<string> receiveMessageText()
|
||||
{
|
||||
byte[] byteArray = await receiveMessageBytes();
|
||||
return Encoding.UTF8.GetString(byteArray);
|
||||
}
|
||||
private async Task<byte[]> receiveMessageBytes()
|
||||
{
|
||||
List<byte> totalPayload = new List<byte>();
|
||||
byte[] buffer = new byte[0x8000];
|
||||
|
||||
while (wss.State == WebSocketState.Open)
|
||||
{
|
||||
WebSocketReceiveResult result = await wss.ReceiveAsync(buffer, CancellationToken.None);
|
||||
|
||||
for (int i = 0; i < result.Count; i++)
|
||||
totalPayload.Add(buffer[i]);
|
||||
|
||||
if (result.EndOfMessage)
|
||||
return totalPayload.ToArray();
|
||||
}
|
||||
|
||||
return totalPayload.ToArray();
|
||||
}
|
||||
|
||||
private async Task doUpdate(dynamic jsonData)
|
||||
{
|
||||
string target = jsonData.target;
|
||||
switch (target)
|
||||
{
|
||||
case "frontHistory":
|
||||
onFronterChanged(jsonData);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
private async Task receiveTask()
|
||||
{
|
||||
while (wss.State == WebSocketState.Open)
|
||||
{
|
||||
string message = await receiveMessageText();
|
||||
if (message == "pong") continue;
|
||||
Console.WriteLine("< " + message);
|
||||
|
||||
try
|
||||
{
|
||||
dynamic? jsonData = JsonConvert.DeserializeObject(message);
|
||||
if (jsonData is null) continue;
|
||||
string type = jsonData.msg;
|
||||
if(type == "update")
|
||||
{
|
||||
await doUpdate(jsonData);
|
||||
}
|
||||
}
|
||||
catch (Exception) { };
|
||||
}
|
||||
}
|
||||
|
||||
private async Task connect()
|
||||
{
|
||||
await wss.ConnectAsync(new Uri("wss://api.apparyllis.com/v1/socket"), CancellationToken.None);
|
||||
_ = receiveTask();
|
||||
keepAliveTimer = new Timer((TimerCallback) => { _ = sendKeepAlive(); }, null, 0, 10 * 1000);
|
||||
}
|
||||
|
||||
private async Task sendText(string text)
|
||||
{
|
||||
if (wss.State != WebSocketState.Open)
|
||||
await connect();
|
||||
|
||||
Console.WriteLine("> " + text);
|
||||
await wss.SendAsync(Encoding.UTF8.GetBytes(text), WebSocketMessageType.Text, true, CancellationToken.None);
|
||||
}
|
||||
private async Task sendKeepAlive()
|
||||
{
|
||||
await sendText("ping");
|
||||
}
|
||||
private async Task sendLogin()
|
||||
{
|
||||
dynamic data = new ExpandoObject();
|
||||
data.op = "authenticate";
|
||||
data.token = token;
|
||||
string authenticateJson = JsonConvert.SerializeObject(data);
|
||||
await sendText(authenticateJson);
|
||||
}
|
||||
|
||||
public Socket(string token) : base(token)
|
||||
{
|
||||
_ = sendLogin();
|
||||
}
|
||||
|
||||
}
|
||||
}
|
|
@ -0,0 +1,71 @@
|
|||
using Newtonsoft.Json.Linq;
|
||||
using PluralRichPresence.SimplyPlural;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Runtime.InteropServices;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace PluralRichPresence
|
||||
{
|
||||
public class System
|
||||
{
|
||||
public event EventHandler FronterChanged;
|
||||
string token;
|
||||
|
||||
public Member[] Members;
|
||||
public string SystemId;
|
||||
|
||||
private Socket sock;
|
||||
private Rest rest;
|
||||
|
||||
private ManualResetEvent waitHandle = new ManualResetEvent(false);
|
||||
public Member? LookupMember(string memberId)
|
||||
{
|
||||
foreach(Member member in this.Members)
|
||||
if (member.Id == memberId) return member;
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
|
||||
public async Task<Member[]> GetCurrentFronterInfo()
|
||||
{
|
||||
string[] fronters = await rest.GetCurrentFronters();
|
||||
|
||||
List<Member> members = new List<Member>();
|
||||
|
||||
foreach (string fronter in fronters)
|
||||
{
|
||||
Member? frontingMember = LookupMember(fronter);
|
||||
if (frontingMember is not null) members.Add(frontingMember);
|
||||
}
|
||||
|
||||
return members.ToArray();
|
||||
}
|
||||
private async Task setup()
|
||||
{
|
||||
this.SystemId = await rest.GetSystemId();
|
||||
this.Members = await rest.GetMembers(this.SystemId);
|
||||
this.sock.FronterChanged += OnFronterChange;
|
||||
|
||||
waitHandle.Set();
|
||||
}
|
||||
|
||||
private void OnFronterChange(object? sender, EventArgs e)
|
||||
{
|
||||
if (FronterChanged is not null)
|
||||
FronterChanged(sender, e);
|
||||
}
|
||||
|
||||
public System(string simplyPluralToken)
|
||||
{
|
||||
this.token = simplyPluralToken;
|
||||
this.rest = new Rest(this.token);
|
||||
this.sock = new Socket(this.token);
|
||||
_ = setup();
|
||||
waitHandle.WaitOne();
|
||||
}
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue