mirror of
https://github.com/Vita3K/Vita3KBot.git
synced 2024-11-23 05:29:45 +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