mirror of
https://github.com/Vita3K/Vita3KBot.git
synced 2024-11-26 23:10:29 +00:00
First commit.
This commit is contained in:
commit
e1489d4aa7
6
.gitignore
vendored
Normal file
6
.gitignore
vendored
Normal file
@ -0,0 +1,6 @@
|
|||||||
|
.idea
|
||||||
|
Vita3KBot/obj
|
||||||
|
Vita3KBot/bin
|
||||||
|
Vita3KBot/token.txt
|
||||||
|
Vita3KBot.sln.DotSettings.user
|
||||||
|
Vita3KBot.sln.DotSettings
|
16
Vita3KBot.sln
Normal file
16
Vita3KBot.sln
Normal file
@ -0,0 +1,16 @@
|
|||||||
|
|
||||||
|
Microsoft Visual Studio Solution File, Format Version 12.00
|
||||||
|
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Vita3KBot", "Vita3KBot\Vita3KBot.csproj", "{15AA3D43-CB5E-4F80-B03C-EAE8B1E40F2E}"
|
||||||
|
EndProject
|
||||||
|
Global
|
||||||
|
GlobalSection(SolutionConfigurationPlatforms) = preSolution
|
||||||
|
Debug|Any CPU = Debug|Any CPU
|
||||||
|
Release|Any CPU = Release|Any CPU
|
||||||
|
EndGlobalSection
|
||||||
|
GlobalSection(ProjectConfigurationPlatforms) = postSolution
|
||||||
|
{15AA3D43-CB5E-4F80-B03C-EAE8B1E40F2E}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||||
|
{15AA3D43-CB5E-4F80-B03C-EAE8B1E40F2E}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||||
|
{15AA3D43-CB5E-4F80-B03C-EAE8B1E40F2E}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||||
|
{15AA3D43-CB5E-4F80-B03C-EAE8B1E40F2E}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||||
|
EndGlobalSection
|
||||||
|
EndGlobal
|
51
Vita3KBot/Bot.cs
Normal file
51
Vita3KBot/Bot.cs
Normal file
@ -0,0 +1,51 @@
|
|||||||
|
using System;
|
||||||
|
using System.IO;
|
||||||
|
using System.Reflection;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
|
||||||
|
using Discord;
|
||||||
|
using Discord.Commands;
|
||||||
|
using Discord.WebSocket;
|
||||||
|
|
||||||
|
using Microsoft.Extensions.DependencyInjection;
|
||||||
|
|
||||||
|
namespace Vita3KBot {
|
||||||
|
public class Bot {
|
||||||
|
private readonly string _token;
|
||||||
|
|
||||||
|
private DiscordSocketClient _client;
|
||||||
|
private MessageHandler _handler;
|
||||||
|
|
||||||
|
// Initializes Discord.Net
|
||||||
|
private async Task Start() {
|
||||||
|
_client = new DiscordSocketClient();
|
||||||
|
_handler = new MessageHandler(_client);
|
||||||
|
|
||||||
|
await _handler.Init();
|
||||||
|
|
||||||
|
await _client.LoginAsync(TokenType.Bot, _token);
|
||||||
|
await _client.StartAsync();
|
||||||
|
|
||||||
|
await Task.Delay(-1);
|
||||||
|
}
|
||||||
|
|
||||||
|
private Bot(string token) {
|
||||||
|
_token = token;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void Main(string[] args) {
|
||||||
|
// Init command with token.
|
||||||
|
if (args.Length >= 2 && args[0] == "init") {
|
||||||
|
File.WriteAllText("token.txt", args[1]);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Start bot with token from "token.txt" in working folder.
|
||||||
|
try {
|
||||||
|
var bot = new Bot(File.ReadAllText("token.txt"));
|
||||||
|
bot.Start().GetAwaiter().GetResult();
|
||||||
|
} catch (IOException e) {
|
||||||
|
Console.WriteLine("Could not read from token.txt. Did you run `init <token>`?");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
144
Vita3KBot/Commands/Compatibility.cs
Normal file
144
Vita3KBot/Commands/Compatibility.cs
Normal file
@ -0,0 +1,144 @@
|
|||||||
|
using System;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Text;
|
||||||
|
|
||||||
|
using Discord;
|
||||||
|
using Discord.Commands;
|
||||||
|
|
||||||
|
using Octokit;
|
||||||
|
|
||||||
|
namespace Vita3KBot.Commands {
|
||||||
|
public class Compatibility: ModuleBase<SocketCommandContext> {
|
||||||
|
// Config
|
||||||
|
private const int MaxItemsToDisplay = 8;
|
||||||
|
|
||||||
|
private const string HomebrewRepo = "homebrew-compatibility";
|
||||||
|
private const string CommercialRepo = "compatibility";
|
||||||
|
|
||||||
|
private class TitleInfo {
|
||||||
|
private static readonly string[] StatusNames = {
|
||||||
|
// Priority, display when possible.
|
||||||
|
"Playable",
|
||||||
|
"Ingame",
|
||||||
|
"Intro",
|
||||||
|
"Crash",
|
||||||
|
"Nothing",
|
||||||
|
|
||||||
|
// Secondary, display if nothing else.
|
||||||
|
"Slow",
|
||||||
|
"Black Screen",
|
||||||
|
"NID Missing",
|
||||||
|
"Module Loading Bug",
|
||||||
|
"IO Bug",
|
||||||
|
"Softlock Bug",
|
||||||
|
"Graphics Bug",
|
||||||
|
"Shader Bug",
|
||||||
|
"Audio Bug",
|
||||||
|
"Input Bug",
|
||||||
|
"Touch Bug",
|
||||||
|
"Savedata Bug",
|
||||||
|
"Trophy Bug",
|
||||||
|
"Networking Bug",
|
||||||
|
|
||||||
|
// Invalid
|
||||||
|
"Invalid",
|
||||||
|
"Unknown",
|
||||||
|
};
|
||||||
|
|
||||||
|
private readonly Issue _issue;
|
||||||
|
public readonly bool IsHomebrew;
|
||||||
|
public readonly string Status;
|
||||||
|
public string LatestComment;
|
||||||
|
public string LatestProfileImage;
|
||||||
|
|
||||||
|
public async Task FetchCommentInfo(GitHubClient client) {
|
||||||
|
if (_issue.Comments == 0) return;
|
||||||
|
|
||||||
|
var comments = await client.Issue.Comment.GetAllForIssue("Vita3K",
|
||||||
|
IsHomebrew ? HomebrewRepo : CommercialRepo, _issue.Number);
|
||||||
|
var lastComment = comments[_issue.Comments - 1];
|
||||||
|
LatestComment = "**" + lastComment.User.Login + "**: " + lastComment.Body;
|
||||||
|
LatestProfileImage = lastComment.User.AvatarUrl;
|
||||||
|
}
|
||||||
|
|
||||||
|
public TitleInfo(Issue issue) {
|
||||||
|
_issue = issue;
|
||||||
|
// Repository object is sometimes null on searches. Just guess the repo by the URL.
|
||||||
|
IsHomebrew = issue.Url.Contains(HomebrewRepo);
|
||||||
|
Console.WriteLine(issue.CommentsUrl + " " + issue.Comments);
|
||||||
|
Status = "Unknown";
|
||||||
|
|
||||||
|
var foundStatus = false;
|
||||||
|
foreach (var label in issue.Labels) {
|
||||||
|
foreach (var name in StatusNames) {
|
||||||
|
if (name.ToLower().Equals(label.Name.ToLower())) {
|
||||||
|
Status = name;
|
||||||
|
foundStatus = true;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (foundStatus) break;
|
||||||
|
}
|
||||||
|
|
||||||
|
LatestComment = "*No updates on this title.*";
|
||||||
|
LatestProfileImage = "";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
[Command("compat")]
|
||||||
|
public async Task Compatability([Remainder]string keyword) {
|
||||||
|
var github = new GitHubClient(new ProductHeaderValue("Vita3KBot"));
|
||||||
|
|
||||||
|
var search = new SearchIssuesRequest(keyword) {
|
||||||
|
Repos = new RepositoryCollection {
|
||||||
|
"Vita3K/homebrew-compatibility",
|
||||||
|
"Vita3K/compatibility"
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
var result = await github.Search.SearchIssues(search);
|
||||||
|
switch (result.Items.Count) {
|
||||||
|
case 0:
|
||||||
|
await ReplyAsync("No games found for search term " + keyword + ".");
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 1: {
|
||||||
|
var issue = result.Items.First();
|
||||||
|
var info = new TitleInfo(issue);
|
||||||
|
await info.FetchCommentInfo(github);
|
||||||
|
var builder = new EmbedBuilder()
|
||||||
|
.WithTitle("*" + issue.Title + "* (" + (info.IsHomebrew ? "Homebrew" : "Commercial") + ")")
|
||||||
|
.WithDescription("Status: **" + info.Status + "**\n\n" + info.LatestComment)
|
||||||
|
.WithColor(Color.Red)
|
||||||
|
.WithUrl(issue.Url)
|
||||||
|
.WithCurrentTimestamp();
|
||||||
|
if (info.LatestProfileImage.Length > 0) builder.WithImageUrl(info.LatestProfileImage);
|
||||||
|
|
||||||
|
await ReplyAsync("", false, builder.Build());
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
default: {
|
||||||
|
var description = new StringBuilder();
|
||||||
|
for (var a = 0; a < Math.Min(result.Items.Count, MaxItemsToDisplay); a++) {
|
||||||
|
var issue = result.Items[a];
|
||||||
|
var info = new TitleInfo(issue);
|
||||||
|
description.Append("*" + issue.Title + "* (" + (info.IsHomebrew ? "Homebrew" : "Commercial")
|
||||||
|
+ "): **" + info.Status + "**\n");
|
||||||
|
}
|
||||||
|
if (result.Items.Count > MaxItemsToDisplay) description.Append("...");
|
||||||
|
|
||||||
|
var builder = new EmbedBuilder()
|
||||||
|
.WithTitle("Found " + result.Items.Count + " issues for search term " + keyword + ".")
|
||||||
|
.WithDescription(description.ToString())
|
||||||
|
.WithColor(Color.Orange)
|
||||||
|
.WithCurrentTimestamp();
|
||||||
|
|
||||||
|
await ReplyAsync("", false, builder.Build());
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
17
Vita3KBot/Commands/Debug.cs
Normal file
17
Vita3KBot/Commands/Debug.cs
Normal file
@ -0,0 +1,17 @@
|
|||||||
|
using System;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
|
||||||
|
using Discord.Commands;
|
||||||
|
using Discord.WebSocket;
|
||||||
|
|
||||||
|
namespace Vita3KBot.Commands {
|
||||||
|
public class Debug : ModuleBase<SocketCommandContext> {
|
||||||
|
|
||||||
|
// Get id for a role. Helpful when creating commands that might query, give, remove roles.
|
||||||
|
[Command("probe-role")]
|
||||||
|
public async Task ProbeRole([Remainder] string roleName) {
|
||||||
|
await ReplyAsync(roleName + ": " + Context.Guild.Roles.First(x => x.Name == roleName).Id);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
81
Vita3KBot/MessageHandler.cs
Normal file
81
Vita3KBot/MessageHandler.cs
Normal file
@ -0,0 +1,81 @@
|
|||||||
|
using System;
|
||||||
|
using System.Data;
|
||||||
|
using System.Reflection;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
|
||||||
|
using Discord;
|
||||||
|
using Discord.Commands;
|
||||||
|
using Discord.WebSocket;
|
||||||
|
|
||||||
|
using Microsoft.Extensions.DependencyInjection;
|
||||||
|
|
||||||
|
namespace Vita3KBot {
|
||||||
|
public class MessageHandler {
|
||||||
|
// Config
|
||||||
|
private const char Prefix = '-';
|
||||||
|
private const bool ShowStackTrace = true;
|
||||||
|
|
||||||
|
private readonly DiscordSocketClient _client;
|
||||||
|
|
||||||
|
private readonly CommandService _commands;
|
||||||
|
private readonly ServiceProvider _services;
|
||||||
|
|
||||||
|
// Called for each user message. Use it to collect stats, or silently observe stuff, etc.
|
||||||
|
private static async Task MonitorMessage(SocketUserMessage message) {
|
||||||
|
if (!(message.Author is SocketGuildUser user) || message.Author.IsBot) return;
|
||||||
|
|
||||||
|
//TODO: Put Persona 4 Golden monitoring here.
|
||||||
|
}
|
||||||
|
|
||||||
|
// Called by Discord.Net when it wants to log something.
|
||||||
|
private static Task Log(LogMessage message) {
|
||||||
|
Console.WriteLine(message.Message);
|
||||||
|
return Task.CompletedTask;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Called by Discord.Net when the bot receives a message.
|
||||||
|
private async Task CheckMessage(SocketMessage message) {
|
||||||
|
if (!(message is SocketUserMessage userMessage)) return;
|
||||||
|
|
||||||
|
await MonitorMessage(userMessage);
|
||||||
|
|
||||||
|
var prefixStart = 0;
|
||||||
|
|
||||||
|
if (userMessage.HasCharPrefix(Prefix, ref prefixStart)) {
|
||||||
|
// Create Context and Execute Commands
|
||||||
|
var context = new SocketCommandContext(_client, userMessage);
|
||||||
|
var result = await _commands.ExecuteAsync(context, prefixStart, _services);
|
||||||
|
|
||||||
|
// Handle any errors.
|
||||||
|
if (!result.IsSuccess && result.Error != CommandError.UnknownCommand) {
|
||||||
|
if (ShowStackTrace && result.Error == CommandError.Exception
|
||||||
|
&& result is ExecuteResult execution) {
|
||||||
|
await userMessage.Channel.SendMessageAsync(
|
||||||
|
Utils.Code(execution.Exception.Message + "\n\n" + execution.Exception.StackTrace));
|
||||||
|
} else {
|
||||||
|
await userMessage.Channel.SendMessageAsync(
|
||||||
|
"Halt! We've hit an error." + Utils.Code(result.ErrorReason));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Initializes the Message Handler, subscribe to events, etc.
|
||||||
|
public async Task Init() {
|
||||||
|
_client.Log += Log;
|
||||||
|
_client.MessageReceived += CheckMessage;
|
||||||
|
|
||||||
|
await _commands.AddModulesAsync(Assembly.GetEntryAssembly(), _services);
|
||||||
|
}
|
||||||
|
|
||||||
|
public MessageHandler(DiscordSocketClient client) {
|
||||||
|
_client = client;
|
||||||
|
|
||||||
|
_commands = new CommandService();
|
||||||
|
_services = new ServiceCollection()
|
||||||
|
.AddSingleton(_client)
|
||||||
|
.AddSingleton(_commands)
|
||||||
|
.BuildServiceProvider();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
31
Vita3KBot/Utils.cs
Normal file
31
Vita3KBot/Utils.cs
Normal file
@ -0,0 +1,31 @@
|
|||||||
|
using System;
|
||||||
|
using System.Net.Http;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
|
||||||
|
namespace Vita3KBot {
|
||||||
|
public static class Utils {
|
||||||
|
|
||||||
|
// Sends an HTTP Get request. Might not be the best solution.
|
||||||
|
public static async Task<string> HttpGet(string address, string parameters = "") {
|
||||||
|
var client = new HttpClient{ BaseAddress = new Uri(address) };
|
||||||
|
// Add User-Agent in header so Github API allows our requests.
|
||||||
|
client.DefaultRequestHeaders.Add("User-Agent", "Vita3KBot");
|
||||||
|
var response = await client.GetAsync(parameters);
|
||||||
|
|
||||||
|
if (response.IsSuccessStatusCode) {
|
||||||
|
var result = await response.Content.ReadAsStringAsync();
|
||||||
|
client.Dispose();
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
client.Dispose();
|
||||||
|
throw new Exception("Received " + response.StatusCode
|
||||||
|
+ " status code from " + address + parameters + ".");
|
||||||
|
}
|
||||||
|
|
||||||
|
// Discord Markdown Code.
|
||||||
|
public static string Code(string code, string lang = "") {
|
||||||
|
return "```" + lang + "\n" + code + "\n```";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
14
Vita3KBot/Vita3KBot.csproj
Normal file
14
Vita3KBot/Vita3KBot.csproj
Normal file
@ -0,0 +1,14 @@
|
|||||||
|
<Project Sdk="Microsoft.NET.Sdk">
|
||||||
|
|
||||||
|
<PropertyGroup>
|
||||||
|
<OutputType>Exe</OutputType>
|
||||||
|
<TargetFramework>netcoreapp2.1</TargetFramework>
|
||||||
|
</PropertyGroup>
|
||||||
|
|
||||||
|
<ItemGroup>
|
||||||
|
<PackageReference Include="Discord.Net" Version="2.0.1" />
|
||||||
|
<PackageReference Include="Newtonsoft.Json" Version="12.0.2" />
|
||||||
|
<PackageReference Include="Octokit" Version="0.32.0" />
|
||||||
|
</ItemGroup>
|
||||||
|
|
||||||
|
</Project>
|
Loading…
Reference in New Issue
Block a user