commit
9e05e69cfb
6
.gitignore
vendored
6
.gitignore
vendored
@ -36,4 +36,8 @@ Tests/bin
|
||||
#!**/packages/repositories.config
|
||||
NadekoBot/bin/Debug/data/nadekobot.sqlite
|
||||
NadekoBot/bin/Debug/data/config.json
|
||||
NadekoBot/bin/Debug/data/ServerSpecificConfigs.json
|
||||
NadekoBot/bin/Debug/data/ServerSpecificConfigs.json
|
||||
NadekoBot.sln.iml
|
||||
.idea/workspace.xml
|
||||
.idea/vcs.xml
|
||||
.idea/modules.xml
|
@ -41,32 +41,32 @@ Global
|
||||
{7BFEF748-B934-4621-9B11-6302E3A9F6B3}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{7BFEF748-B934-4621-9B11-6302E3A9F6B3}.FullDebug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{7BFEF748-B934-4621-9B11-6302E3A9F6B3}.FullDebug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{7BFEF748-B934-4621-9B11-6302E3A9F6B3}.NadekoRelease|Any CPU.ActiveCfg = NadekoRelease|Any CPU
|
||||
{7BFEF748-B934-4621-9B11-6302E3A9F6B3}.NadekoRelease|Any CPU.Build.0 = NadekoRelease|Any CPU
|
||||
{7BFEF748-B934-4621-9B11-6302E3A9F6B3}.NadekoRelease|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{7BFEF748-B934-4621-9B11-6302E3A9F6B3}.NadekoRelease|Any CPU.Build.0 = Release|Any CPU
|
||||
{7BFEF748-B934-4621-9B11-6302E3A9F6B3}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{7BFEF748-B934-4621-9B11-6302E3A9F6B3}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
{8D71A857-879A-4A10-859E-5FF824ED6688}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{8D71A857-879A-4A10-859E-5FF824ED6688}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{8D71A857-879A-4A10-859E-5FF824ED6688}.FullDebug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{8D71A857-879A-4A10-859E-5FF824ED6688}.FullDebug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{8D71A857-879A-4A10-859E-5FF824ED6688}.NadekoRelease|Any CPU.ActiveCfg = NadekoRelease|Any CPU
|
||||
{8D71A857-879A-4A10-859E-5FF824ED6688}.NadekoRelease|Any CPU.Build.0 = NadekoRelease|Any CPU
|
||||
{8D71A857-879A-4A10-859E-5FF824ED6688}.NadekoRelease|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{8D71A857-879A-4A10-859E-5FF824ED6688}.NadekoRelease|Any CPU.Build.0 = Release|Any CPU
|
||||
{8D71A857-879A-4A10-859E-5FF824ED6688}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{8D71A857-879A-4A10-859E-5FF824ED6688}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
{3091164F-66AE-4543-A63D-167C1116241D}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{3091164F-66AE-4543-A63D-167C1116241D}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{3091164F-66AE-4543-A63D-167C1116241D}.FullDebug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{3091164F-66AE-4543-A63D-167C1116241D}.FullDebug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{3091164F-66AE-4543-A63D-167C1116241D}.NadekoRelease|Any CPU.ActiveCfg = NadekoRelease|Any CPU
|
||||
{3091164F-66AE-4543-A63D-167C1116241D}.NadekoRelease|Any CPU.Build.0 = NadekoRelease|Any CPU
|
||||
{3091164F-66AE-4543-A63D-167C1116241D}.NadekoRelease|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{3091164F-66AE-4543-A63D-167C1116241D}.NadekoRelease|Any CPU.Build.0 = Release|Any CPU
|
||||
{3091164F-66AE-4543-A63D-167C1116241D}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{3091164F-66AE-4543-A63D-167C1116241D}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
{1B5603B4-6F8F-4289-B945-7BAAE523D740}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{1B5603B4-6F8F-4289-B945-7BAAE523D740}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{1B5603B4-6F8F-4289-B945-7BAAE523D740}.FullDebug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{1B5603B4-6F8F-4289-B945-7BAAE523D740}.FullDebug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{1B5603B4-6F8F-4289-B945-7BAAE523D740}.NadekoRelease|Any CPU.ActiveCfg = NadekoRelease|Any CPU
|
||||
{1B5603B4-6F8F-4289-B945-7BAAE523D740}.NadekoRelease|Any CPU.Build.0 = NadekoRelease|Any CPU
|
||||
{1B5603B4-6F8F-4289-B945-7BAAE523D740}.NadekoRelease|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{1B5603B4-6F8F-4289-B945-7BAAE523D740}.NadekoRelease|Any CPU.Build.0 = Release|Any CPU
|
||||
{1B5603B4-6F8F-4289-B945-7BAAE523D740}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{1B5603B4-6F8F-4289-B945-7BAAE523D740}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
{45B2545D-C612-4919-B34C-D65EA1371C51}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
|
@ -32,7 +32,16 @@ namespace NadekoBot.Classes
|
||||
conn.CreateTable<SongInfo>();
|
||||
conn.CreateTable<PlaylistSongInfo>();
|
||||
conn.CreateTable<MusicPlaylist>();
|
||||
conn.CreateTable<Incident>();
|
||||
conn.Execute(Queries.TransactionTriggerQuery);
|
||||
try
|
||||
{
|
||||
conn.Execute(Queries.DeletePlaylistTriggerQuery);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Console.WriteLine(ex);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -94,6 +103,14 @@ namespace NadekoBot.Classes
|
||||
}
|
||||
}
|
||||
|
||||
internal void UpdateAll<T>(IEnumerable<T> objs) where T : IDataModel
|
||||
{
|
||||
using (var conn = new SQLiteConnection(FilePath))
|
||||
{
|
||||
conn.UpdateAll(objs);
|
||||
}
|
||||
}
|
||||
|
||||
internal HashSet<T> GetAllRows<T>() where T : IDataModel, new()
|
||||
{
|
||||
using (var conn = new SQLiteConnection(FilePath))
|
||||
@ -181,7 +198,7 @@ Limit 20 OFFSET ?", num * 20);
|
||||
{
|
||||
using (var conn = new SQLiteConnection(FilePath))
|
||||
{
|
||||
return conn.Table<CurrencyState>().Take(n).ToList().OrderBy(cs => -cs.Value);
|
||||
return conn.Table<CurrencyState>().OrderBy(cs => -cs.Value).Take(n).ToList();
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -197,7 +214,7 @@ public class PlaylistData
|
||||
|
||||
public static class Queries
|
||||
{
|
||||
public static string TransactionTriggerQuery = @"
|
||||
public const string TransactionTriggerQuery = @"
|
||||
CREATE TRIGGER IF NOT EXISTS OnTransactionAdded
|
||||
AFTER INSERT ON CurrencyTransaction
|
||||
BEGIN
|
||||
@ -208,4 +225,11 @@ INSERT OR REPLACE INTO CurrencyState (Id, UserId, Value, DateAdded)
|
||||
NEW.DateAdded);
|
||||
END
|
||||
";
|
||||
public const string DeletePlaylistTriggerQuery = @"
|
||||
CREATE TRIGGER IF NOT EXISTS music_playlist
|
||||
AFTER DELETE ON MusicPlaylist
|
||||
FOR EACH ROW
|
||||
BEGIN
|
||||
DELETE FROM PlaylistSongInfo WHERE PlaylistId = OLD.Id;
|
||||
END";
|
||||
}
|
||||
|
@ -215,7 +215,7 @@ namespace NadekoBot.Extensions
|
||||
sb.Append($"{ Format.Code(item.Key)}\n");
|
||||
sb.AppendLine(" `└─`" + Format.Bold(item.Value));
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
else
|
||||
{
|
||||
@ -224,7 +224,7 @@ namespace NadekoBot.Extensions
|
||||
sb.Append($"{ Format.Code(item.ToString())} \n");
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
return sb.ToString();
|
||||
}
|
||||
/// <summary>
|
||||
@ -352,5 +352,15 @@ namespace NadekoBot.Extensions
|
||||
await Task.Run(() => images.Merge(reverseScaleFactor)).ConfigureAwait(false);
|
||||
|
||||
public static string Unmention(this string str) => str.Replace("@", "ම");
|
||||
|
||||
public static Stream ToStream(this string str)
|
||||
{
|
||||
var sw = new StreamWriter(new MemoryStream());
|
||||
sw.Write(str);
|
||||
sw.Flush();
|
||||
sw.BaseStream.Position = 0;
|
||||
return sw.BaseStream;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
@ -1,15 +1,25 @@
|
||||
using System;
|
||||
using System.IO;
|
||||
using NadekoBot.DataModels;
|
||||
using System;
|
||||
|
||||
namespace NadekoBot.Classes {
|
||||
internal static class IncidentsHandler {
|
||||
public static void Add(ulong serverId, string text) {
|
||||
Directory.CreateDirectory("data/incidents");
|
||||
File.AppendAllText($"data/incidents/{serverId}.txt", text + "\n--------------------------\n");
|
||||
namespace NadekoBot.Classes
|
||||
{
|
||||
internal static class IncidentsHandler
|
||||
{
|
||||
public static void Add(ulong serverId, ulong channelId, string text)
|
||||
{
|
||||
var def = Console.ForegroundColor;
|
||||
Console.ForegroundColor = ConsoleColor.Red;
|
||||
Console.WriteLine($"INCIDENT: {text}");
|
||||
Console.ForegroundColor = def;
|
||||
var incident = new Incident
|
||||
{
|
||||
ChannelId = (long)channelId,
|
||||
ServerId = (long)serverId,
|
||||
Text = text,
|
||||
Read = false
|
||||
};
|
||||
|
||||
DbHandler.Instance.InsertData<Incident>(incident);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
204
NadekoBot/Classes/ObservableConcurrentDictionary.cs
Normal file
204
NadekoBot/Classes/ObservableConcurrentDictionary.cs
Normal file
@ -0,0 +1,204 @@
|
||||
//--------------------------------------------------------------------------
|
||||
//
|
||||
// Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
//
|
||||
// File: ObservableConcurrentDictionary.cs
|
||||
//
|
||||
//--------------------------------------------------------------------------
|
||||
|
||||
using System.Collections.Generic;
|
||||
using System.Collections.Specialized;
|
||||
using System.ComponentModel;
|
||||
using System.Diagnostics;
|
||||
using System.Threading;
|
||||
|
||||
namespace System.Collections.Concurrent
|
||||
{
|
||||
/// <summary>
|
||||
/// Provides a thread-safe dictionary for use with data binding.
|
||||
/// </summary>
|
||||
/// <typeparam name="TKey">Specifies the type of the keys in this collection.</typeparam>
|
||||
/// <typeparam name="TValue">Specifies the type of the values in this collection.</typeparam>
|
||||
[DebuggerDisplay("Count={Count}")]
|
||||
public class ObservableConcurrentDictionary<TKey, TValue> :
|
||||
ICollection<KeyValuePair<TKey, TValue>>, IDictionary<TKey, TValue>,
|
||||
INotifyCollectionChanged, INotifyPropertyChanged
|
||||
{
|
||||
private readonly SynchronizationContext _context;
|
||||
private readonly ConcurrentDictionary<TKey, TValue> _dictionary;
|
||||
|
||||
/// <summary>
|
||||
/// Initializes an instance of the ObservableConcurrentDictionary class.
|
||||
/// </summary>
|
||||
public ObservableConcurrentDictionary()
|
||||
{
|
||||
_context = AsyncOperationManager.SynchronizationContext;
|
||||
_dictionary = new ConcurrentDictionary<TKey, TValue>();
|
||||
}
|
||||
|
||||
/// <summary>Event raised when the collection changes.</summary>
|
||||
public event NotifyCollectionChangedEventHandler CollectionChanged;
|
||||
/// <summary>Event raised when a property on the collection changes.</summary>
|
||||
public event PropertyChangedEventHandler PropertyChanged;
|
||||
|
||||
/// <summary>
|
||||
/// Notifies observers of CollectionChanged or PropertyChanged of an update to the dictionary.
|
||||
/// </summary>
|
||||
private void NotifyObserversOfChange()
|
||||
{
|
||||
var collectionHandler = CollectionChanged;
|
||||
var propertyHandler = PropertyChanged;
|
||||
if (collectionHandler != null || propertyHandler != null)
|
||||
{
|
||||
_context.Post(s =>
|
||||
{
|
||||
if (collectionHandler != null)
|
||||
{
|
||||
collectionHandler(this, new NotifyCollectionChangedEventArgs(NotifyCollectionChangedAction.Reset));
|
||||
}
|
||||
if (propertyHandler != null)
|
||||
{
|
||||
propertyHandler(this, new PropertyChangedEventArgs("Count"));
|
||||
propertyHandler(this, new PropertyChangedEventArgs("Keys"));
|
||||
propertyHandler(this, new PropertyChangedEventArgs("Values"));
|
||||
}
|
||||
}, null);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>Attempts to add an item to the dictionary, notifying observers of any changes.</summary>
|
||||
/// <param name="item">The item to be added.</param>
|
||||
/// <returns>Whether the add was successful.</returns>
|
||||
private bool TryAddWithNotification(KeyValuePair<TKey, TValue> item)
|
||||
{
|
||||
return TryAddWithNotification(item.Key, item.Value);
|
||||
}
|
||||
|
||||
/// <summary>Attempts to add an item to the dictionary, notifying observers of any changes.</summary>
|
||||
/// <param name="key">The key of the item to be added.</param>
|
||||
/// <param name="value">The value of the item to be added.</param>
|
||||
/// <returns>Whether the add was successful.</returns>
|
||||
private bool TryAddWithNotification(TKey key, TValue value)
|
||||
{
|
||||
bool result = _dictionary.TryAdd(key, value);
|
||||
if (result) NotifyObserversOfChange();
|
||||
return result;
|
||||
}
|
||||
|
||||
/// <summary>Attempts to remove an item from the dictionary, notifying observers of any changes.</summary>
|
||||
/// <param name="key">The key of the item to be removed.</param>
|
||||
/// <param name="value">The value of the item removed.</param>
|
||||
/// <returns>Whether the removal was successful.</returns>
|
||||
private bool TryRemoveWithNotification(TKey key, out TValue value)
|
||||
{
|
||||
bool result = _dictionary.TryRemove(key, out value);
|
||||
if (result) NotifyObserversOfChange();
|
||||
return result;
|
||||
}
|
||||
|
||||
/// <summary>Attempts to add or update an item in the dictionary, notifying observers of any changes.</summary>
|
||||
/// <param name="key">The key of the item to be updated.</param>
|
||||
/// <param name="value">The new value to set for the item.</param>
|
||||
/// <returns>Whether the update was successful.</returns>
|
||||
private void UpdateWithNotification(TKey key, TValue value)
|
||||
{
|
||||
_dictionary[key] = value;
|
||||
NotifyObserversOfChange();
|
||||
}
|
||||
|
||||
#region ICollection<KeyValuePair<TKey,TValue>> Members
|
||||
void ICollection<KeyValuePair<TKey, TValue>>.Add(KeyValuePair<TKey, TValue> item)
|
||||
{
|
||||
TryAddWithNotification(item);
|
||||
}
|
||||
|
||||
void ICollection<KeyValuePair<TKey, TValue>>.Clear()
|
||||
{
|
||||
((ICollection<KeyValuePair<TKey, TValue>>)_dictionary).Clear();
|
||||
NotifyObserversOfChange();
|
||||
}
|
||||
|
||||
bool ICollection<KeyValuePair<TKey, TValue>>.Contains(KeyValuePair<TKey, TValue> item)
|
||||
{
|
||||
return ((ICollection<KeyValuePair<TKey, TValue>>)_dictionary).Contains(item);
|
||||
}
|
||||
|
||||
void ICollection<KeyValuePair<TKey, TValue>>.CopyTo(KeyValuePair<TKey, TValue>[] array, int arrayIndex)
|
||||
{
|
||||
((ICollection<KeyValuePair<TKey, TValue>>)_dictionary).CopyTo(array, arrayIndex);
|
||||
}
|
||||
|
||||
int ICollection<KeyValuePair<TKey, TValue>>.Count {
|
||||
get { return ((ICollection<KeyValuePair<TKey, TValue>>)_dictionary).Count; }
|
||||
}
|
||||
|
||||
bool ICollection<KeyValuePair<TKey, TValue>>.IsReadOnly {
|
||||
get { return ((ICollection<KeyValuePair<TKey, TValue>>)_dictionary).IsReadOnly; }
|
||||
}
|
||||
|
||||
bool ICollection<KeyValuePair<TKey, TValue>>.Remove(KeyValuePair<TKey, TValue> item)
|
||||
{
|
||||
TValue temp;
|
||||
return TryRemoveWithNotification(item.Key, out temp);
|
||||
}
|
||||
#endregion
|
||||
|
||||
#region IEnumerable<KeyValuePair<TKey,TValue>> Members
|
||||
IEnumerator<KeyValuePair<TKey, TValue>> IEnumerable<KeyValuePair<TKey, TValue>>.GetEnumerator()
|
||||
{
|
||||
return ((ICollection<KeyValuePair<TKey, TValue>>)_dictionary).GetEnumerator();
|
||||
}
|
||||
|
||||
IEnumerator IEnumerable.GetEnumerator()
|
||||
{
|
||||
return ((ICollection<KeyValuePair<TKey, TValue>>)_dictionary).GetEnumerator();
|
||||
}
|
||||
#endregion
|
||||
|
||||
#region IDictionary<TKey,TValue> Members
|
||||
public void Add(TKey key, TValue value)
|
||||
{
|
||||
TryAddWithNotification(key, value);
|
||||
}
|
||||
|
||||
public bool ContainsKey(TKey key)
|
||||
{
|
||||
return _dictionary.ContainsKey(key);
|
||||
}
|
||||
|
||||
public ICollection<TKey> Keys {
|
||||
get { return _dictionary.Keys; }
|
||||
}
|
||||
|
||||
public bool Remove(TKey key)
|
||||
{
|
||||
TValue temp;
|
||||
return TryRemoveWithNotification(key, out temp);
|
||||
}
|
||||
|
||||
public bool TryGetValue(TKey key, out TValue value)
|
||||
{
|
||||
return _dictionary.TryGetValue(key, out value);
|
||||
}
|
||||
|
||||
public bool TryAdd(TKey key, TValue value)
|
||||
{
|
||||
return TryAddWithNotification(key, value);
|
||||
}
|
||||
|
||||
public ICollection<TValue> Values {
|
||||
get { return _dictionary.Values; }
|
||||
}
|
||||
|
||||
public TValue this[TKey key] {
|
||||
get { return _dictionary[key]; }
|
||||
set { UpdateWithNotification(key, value); }
|
||||
}
|
||||
|
||||
public bool TryRemove(TKey key, out TValue value)
|
||||
{
|
||||
return TryRemoveWithNotification(key, out value);
|
||||
}
|
||||
#endregion
|
||||
}
|
||||
}
|
@ -176,6 +176,33 @@ namespace NadekoBot.Classes
|
||||
return null;
|
||||
}
|
||||
|
||||
public static async Task<string> GetRelatedVideoId(string id)
|
||||
{
|
||||
if (string.IsNullOrWhiteSpace(id))
|
||||
throw new ArgumentNullException(nameof(id));
|
||||
var match = new Regex("(?:youtu\\.be\\/|v=)(?<id>[\\da-zA-Z\\-_]*)").Match(id);
|
||||
if (match.Length > 1)
|
||||
{
|
||||
id = match.Groups["id"].Value;
|
||||
}
|
||||
var response = await GetResponseStringAsync(
|
||||
$"https://www.googleapis.com/youtube/v3/search?" +
|
||||
$"part=snippet&maxResults=1&type=video" +
|
||||
$"&relatedToVideoId={id}" +
|
||||
$"&key={NadekoBot.Creds.GoogleAPIKey}").ConfigureAwait(false);
|
||||
JObject obj = JObject.Parse(response);
|
||||
|
||||
var data = JsonConvert.DeserializeObject<YoutubeVideoSearch>(response);
|
||||
|
||||
if (data.items.Length > 0)
|
||||
{
|
||||
var toReturn = "http://www.youtube.com/watch?v=" + data.items[0].id.videoId.ToString();
|
||||
return toReturn;
|
||||
}
|
||||
else
|
||||
return null;
|
||||
}
|
||||
|
||||
public static async Task<string> GetPlaylistIdByKeyword(string query)
|
||||
{
|
||||
if (string.IsNullOrWhiteSpace(NadekoBot.Creds.GoogleAPIKey))
|
||||
@ -350,5 +377,13 @@ namespace NadekoBot.Classes
|
||||
return url;
|
||||
}
|
||||
}
|
||||
|
||||
public static string ShowInPrettyCode<T>(IEnumerable<T> items, Func<T, string> howToPrint, int cols = 3)
|
||||
{
|
||||
var i = 0;
|
||||
return "```xl\n" + string.Join("\n", items.GroupBy(item => (i++) / cols)
|
||||
.Select(ig => string.Join("", ig.Select(el => howToPrint(el)))))
|
||||
+ $"\n```";
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -66,6 +66,7 @@ namespace NadekoBot.Classes
|
||||
get { return voicePlusTextEnabled; }
|
||||
set {
|
||||
voicePlusTextEnabled = value;
|
||||
if (!SpecificConfigurations.Instantiated) return;
|
||||
OnPropertyChanged();
|
||||
}
|
||||
}
|
||||
@ -76,10 +77,50 @@ namespace NadekoBot.Classes
|
||||
get { return sendPrivateMessageOnMention; }
|
||||
set {
|
||||
sendPrivateMessageOnMention = value;
|
||||
if (!SpecificConfigurations.Instantiated) return;
|
||||
OnPropertyChanged();
|
||||
}
|
||||
}
|
||||
|
||||
[JsonProperty("LogChannel")]
|
||||
private ulong? logServerChannel = null;
|
||||
[JsonIgnore]
|
||||
public ulong? LogServerChannel {
|
||||
get { return logServerChannel; }
|
||||
set {
|
||||
logServerChannel = value;
|
||||
if (!SpecificConfigurations.Instantiated) return;
|
||||
OnPropertyChanged();
|
||||
}
|
||||
}
|
||||
|
||||
[JsonProperty("LogPresenceChannel")]
|
||||
private ulong? logPresenceChannel = null;
|
||||
[JsonIgnore]
|
||||
public ulong? LogPresenceChannel {
|
||||
get { return logPresenceChannel; }
|
||||
set {
|
||||
logPresenceChannel = value;
|
||||
if (!SpecificConfigurations.Instantiated) return;
|
||||
OnPropertyChanged();
|
||||
}
|
||||
}
|
||||
|
||||
[JsonIgnore]
|
||||
private ObservableConcurrentDictionary<ulong, ulong> voiceChannelLog;
|
||||
public ObservableConcurrentDictionary<ulong, ulong> VoiceChannelLog {
|
||||
get { return voiceChannelLog; }
|
||||
set {
|
||||
voiceChannelLog = value;
|
||||
if (value != null)
|
||||
voiceChannelLog.CollectionChanged += (s, e) =>
|
||||
{
|
||||
if (!SpecificConfigurations.Instantiated) return;
|
||||
OnPropertyChanged();
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
[JsonIgnore]
|
||||
private ObservableCollection<ulong> listOfSelfAssignableRoles;
|
||||
public ObservableCollection<ulong> ListOfSelfAssignableRoles {
|
||||
@ -106,6 +147,33 @@ namespace NadekoBot.Classes
|
||||
}
|
||||
}
|
||||
|
||||
[JsonIgnore]
|
||||
private ObservableCollection<ulong> generateCurrencyChannels;
|
||||
public ObservableCollection<ulong> GenerateCurrencyChannels {
|
||||
get { return generateCurrencyChannels; }
|
||||
set {
|
||||
generateCurrencyChannels = value;
|
||||
if (value != null)
|
||||
generateCurrencyChannels.CollectionChanged += (s, e) =>
|
||||
{
|
||||
if (!SpecificConfigurations.Instantiated) return;
|
||||
OnPropertyChanged();
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
[JsonIgnore]
|
||||
private bool autoDeleteMessagesOnCommand = false;
|
||||
public bool AutoDeleteMessagesOnCommand {
|
||||
get { return autoDeleteMessagesOnCommand; }
|
||||
set {
|
||||
autoDeleteMessagesOnCommand = value;
|
||||
if (!SpecificConfigurations.Instantiated) return;
|
||||
OnPropertyChanged();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
[JsonIgnore]
|
||||
private ObservableCollection<StreamNotificationConfig> observingStreams;
|
||||
public ObservableCollection<StreamNotificationConfig> ObservingStreams {
|
||||
@ -121,10 +189,23 @@ namespace NadekoBot.Classes
|
||||
}
|
||||
}
|
||||
|
||||
[JsonIgnore]
|
||||
private float defaultMusicVolume = 1f;
|
||||
public float DefaultMusicVolume {
|
||||
get { return defaultMusicVolume; }
|
||||
set {
|
||||
defaultMusicVolume = value;
|
||||
if (!SpecificConfigurations.Instantiated) return;
|
||||
OnPropertyChanged();
|
||||
}
|
||||
}
|
||||
|
||||
public ServerSpecificConfig()
|
||||
{
|
||||
ListOfSelfAssignableRoles = new ObservableCollection<ulong>();
|
||||
ObservingStreams = new ObservableCollection<StreamNotificationConfig>();
|
||||
GenerateCurrencyChannels = new ObservableCollection<ulong>();
|
||||
VoiceChannelLog = new ObservableConcurrentDictionary<ulong, ulong>();
|
||||
}
|
||||
|
||||
public event PropertyChangedEventHandler PropertyChanged = delegate { SpecificConfigurations.Default.Save(); };
|
||||
|
@ -6,8 +6,11 @@ using NadekoBot.DataModels;
|
||||
using NadekoBot.Extensions;
|
||||
using NadekoBot.Modules.Administration.Commands;
|
||||
using NadekoBot.Modules.Permissions.Classes;
|
||||
using Newtonsoft.Json;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace NadekoBot.Modules.Administration
|
||||
@ -24,11 +27,26 @@ namespace NadekoBot.Modules.Administration
|
||||
commands.Add(new VoicePlusTextCommand(this));
|
||||
commands.Add(new CrossServerTextChannel(this));
|
||||
commands.Add(new SelfAssignedRolesCommand(this));
|
||||
commands.Add(new Remind(this));
|
||||
commands.Add(new InfoCommands(this));
|
||||
commands.Add(new CustomReactionsCommands(this));
|
||||
commands.Add(new AutoAssignRole(this));
|
||||
commands.Add(new SelfCommands(this));
|
||||
commands.Add(new IncidentsCommands(this));
|
||||
|
||||
NadekoBot.Client.GetService<CommandService>().CommandExecuted += DeleteCommandMessage;
|
||||
}
|
||||
|
||||
private void DeleteCommandMessage(object sender, CommandEventArgs e)
|
||||
{
|
||||
if (e.Server == null || e.Channel.IsPrivate)
|
||||
return;
|
||||
var conf = SpecificConfigurations.Default.Of(e.Server.Id);
|
||||
if (!conf.AutoDeleteMessagesOnCommand)
|
||||
return;
|
||||
try
|
||||
{
|
||||
e.Message.Delete();
|
||||
}
|
||||
catch { }
|
||||
}
|
||||
|
||||
public override string Prefix { get; } = NadekoBot.Config.CommandPrefixes.Administration;
|
||||
@ -45,6 +63,21 @@ namespace NadekoBot.Modules.Administration
|
||||
|
||||
commands.ForEach(cmd => cmd.Init(cgb));
|
||||
|
||||
cgb.CreateCommand(Prefix + "delmsgoncmd")
|
||||
.Description("Toggles the automatic deletion of user's successful command message to prevent chat flood. Server Manager Only.")
|
||||
.AddCheck(SimpleCheckers.ManageServer())
|
||||
.Do(async e =>
|
||||
{
|
||||
var conf = SpecificConfigurations.Default.Of(e.Server.Id);
|
||||
conf.AutoDeleteMessagesOnCommand = !conf.AutoDeleteMessagesOnCommand;
|
||||
Classes.JSONModels.ConfigHandler.SaveConfig();
|
||||
if (conf.AutoDeleteMessagesOnCommand)
|
||||
await e.Channel.SendMessage("❗`Now automatically deleting successfull command invokations.`");
|
||||
else
|
||||
await e.Channel.SendMessage("❗`Stopped automatic deletion of successfull command invokations.`");
|
||||
|
||||
});
|
||||
|
||||
cgb.CreateCommand(Prefix + "restart")
|
||||
.Description("Restarts the bot. Might not work.")
|
||||
.AddCheck(SimpleCheckers.OwnerOnly())
|
||||
@ -262,25 +295,9 @@ namespace NadekoBot.Modules.Administration
|
||||
}
|
||||
});
|
||||
|
||||
cgb.CreateCommand(Prefix + "roles")
|
||||
.Description("List all roles on this server or a single user if specified.")
|
||||
.Parameter("user", ParameterType.Unparsed)
|
||||
.Do(async e =>
|
||||
{
|
||||
if (!string.IsNullOrWhiteSpace(e.GetArg("user")))
|
||||
{
|
||||
var usr = e.Server.FindUsers(e.GetArg("user")).FirstOrDefault();
|
||||
if (usr == null) return;
|
||||
|
||||
await e.Channel.SendMessage($"`List of roles for **{usr.Name}**:` \n• " + string.Join("\n• ", usr.Roles)).ConfigureAwait(false);
|
||||
return;
|
||||
}
|
||||
await e.Channel.SendMessage("`List of roles:` \n• " + string.Join("\n• ", e.Server.Roles)).ConfigureAwait(false);
|
||||
});
|
||||
|
||||
cgb.CreateCommand(Prefix + "ban").Alias(Prefix + "b")
|
||||
.Parameter("user", ParameterType.Required)
|
||||
.Parameter("msg", ParameterType.Optional)
|
||||
.Parameter("msg", ParameterType.Unparsed)
|
||||
.Description("Bans a user by id or name with an optional message.\n**Usage**: .b \"@some Guy\" Your behaviour is toxic.")
|
||||
.Do(async e =>
|
||||
{
|
||||
@ -315,7 +332,7 @@ namespace NadekoBot.Modules.Administration
|
||||
|
||||
cgb.CreateCommand(Prefix + "softban").Alias(Prefix + "sb")
|
||||
.Parameter("user", ParameterType.Required)
|
||||
.Parameter("msg", ParameterType.Optional)
|
||||
.Parameter("msg", ParameterType.Unparsed)
|
||||
.Description("Bans and then unbans a user by id or name with an optional message.\n**Usage**: .sb \"@some Guy\" Your behaviour is toxic.")
|
||||
.Do(async e =>
|
||||
{
|
||||
@ -599,40 +616,6 @@ namespace NadekoBot.Modules.Administration
|
||||
await e.Channel.SendMessage(":ok: **New channel name set.**").ConfigureAwait(false);
|
||||
});
|
||||
|
||||
cgb.CreateCommand(Prefix + "userid").Alias(Prefix + "uid")
|
||||
.Description("Shows user ID.")
|
||||
.Parameter("user", ParameterType.Unparsed)
|
||||
.Do(async e =>
|
||||
{
|
||||
var usr = e.User;
|
||||
if (!string.IsNullOrWhiteSpace(e.GetArg("user"))) usr = e.Channel.FindUsers(e.GetArg("user")).FirstOrDefault();
|
||||
if (usr == null)
|
||||
return;
|
||||
await e.Channel.SendMessage($"Id of the user { usr.Name } is { usr.Id }").ConfigureAwait(false);
|
||||
});
|
||||
|
||||
cgb.CreateCommand(Prefix + "channelid").Alias(Prefix + "cid")
|
||||
.Description("Shows current channel ID.")
|
||||
.Do(async e => await e.Channel.SendMessage("This channel's ID is " + e.Channel.Id).ConfigureAwait(false));
|
||||
|
||||
cgb.CreateCommand(Prefix + "serverid").Alias(Prefix + "sid")
|
||||
.Description("Shows current server ID.")
|
||||
.Do(async e => await e.Channel.SendMessage("This server's ID is " + e.Server.Id).ConfigureAwait(false));
|
||||
|
||||
cgb.CreateCommand(Prefix + "stats")
|
||||
.Description("Shows some basic stats for Nadeko.")
|
||||
.Do(async e =>
|
||||
{
|
||||
await e.Channel.SendMessage(await NadekoStats.Instance.GetStats());
|
||||
});
|
||||
|
||||
cgb.CreateCommand(Prefix + "dysyd")
|
||||
.Description("Shows some basic stats for Nadeko.")
|
||||
.Do(async e =>
|
||||
{
|
||||
await e.Channel.SendMessage((await NadekoStats.Instance.GetStats()).Matrix().TrimTo(1990)).ConfigureAwait(false);
|
||||
});
|
||||
|
||||
cgb.CreateCommand(Prefix + "heap")
|
||||
.Description("Shows allocated memory - **Bot Owner Only!**")
|
||||
.AddCheck(SimpleCheckers.OwnerOnly())
|
||||
@ -736,7 +719,7 @@ namespace NadekoBot.Modules.Administration
|
||||
|
||||
cgb.CreateCommand(Prefix + "newavatar")
|
||||
.Alias(Prefix + "setavatar")
|
||||
.Description("Sets a new avatar image for the NadekoBot. **Bot Owner Only!**")
|
||||
.Description("Sets a new avatar image for the NadekoBot. Argument is a direct link to an image. **Bot Owner Only!**\n**Usage**: `.setavatar https://i.ytimg.com/vi/WDudkR1eTMM/maxresdefault.jpg`")
|
||||
.Parameter("img", ParameterType.Unparsed)
|
||||
.AddCheck(SimpleCheckers.OwnerOnly())
|
||||
.Do(async e =>
|
||||
@ -766,80 +749,51 @@ namespace NadekoBot.Modules.Administration
|
||||
client.SetGame(e.GetArg("set_game"));
|
||||
});
|
||||
|
||||
cgb.CreateCommand(Prefix + "checkmyperms")
|
||||
.Description("Checks your userspecific permissions on this channel.")
|
||||
.Do(async e =>
|
||||
{
|
||||
var output = "```\n";
|
||||
foreach (var p in e.User.ServerPermissions.GetType().GetProperties().Where(p => !p.GetGetMethod().GetParameters().Any()))
|
||||
{
|
||||
output += p.Name + ": " + p.GetValue(e.User.ServerPermissions, null).ToString() + "\n";
|
||||
}
|
||||
output += "```";
|
||||
await e.User.SendMessage(output).ConfigureAwait(false);
|
||||
});
|
||||
|
||||
Server commsServer = null;
|
||||
User commsUser = null;
|
||||
Channel commsChannel = null;
|
||||
|
||||
cgb.CreateCommand(Prefix + "commsuser")
|
||||
.Description("Sets a user for through-bot communication. Only works if server is set. Resets commschannel. **Bot Owner Only!**")
|
||||
.Parameter("name", ParameterType.Unparsed)
|
||||
.AddCheck(SimpleCheckers.OwnerOnly())
|
||||
.Do(async e =>
|
||||
{
|
||||
commsUser = commsServer?.FindUsers(e.GetArg("name")).FirstOrDefault();
|
||||
if (commsUser != null)
|
||||
{
|
||||
commsChannel = null;
|
||||
await e.Channel.SendMessage("User for comms set.").ConfigureAwait(false);
|
||||
}
|
||||
else
|
||||
await e.Channel.SendMessage("No server specified or user.").ConfigureAwait(false);
|
||||
});
|
||||
|
||||
cgb.CreateCommand(Prefix + "commsserver")
|
||||
.Description("Sets a server for through-bot communication. **Bot Owner Only!**")
|
||||
.Parameter("server", ParameterType.Unparsed)
|
||||
.AddCheck(SimpleCheckers.OwnerOnly())
|
||||
.Do(async e =>
|
||||
{
|
||||
commsServer = client.FindServers(e.GetArg("server")).FirstOrDefault();
|
||||
if (commsServer != null)
|
||||
await e.Channel.SendMessage("Server for comms set.").ConfigureAwait(false);
|
||||
else
|
||||
await e.Channel.SendMessage("No such server.").ConfigureAwait(false);
|
||||
});
|
||||
|
||||
cgb.CreateCommand(Prefix + "commschannel")
|
||||
.Description("Sets a channel for through-bot communication. Only works if server is set. Resets commsuser. **Bot Owner Only!**")
|
||||
.Parameter("ch", ParameterType.Unparsed)
|
||||
.AddCheck(SimpleCheckers.OwnerOnly())
|
||||
.Do(async e =>
|
||||
{
|
||||
commsChannel = commsServer?.FindChannels(e.GetArg("ch"), ChannelType.Text).FirstOrDefault();
|
||||
if (commsChannel != null)
|
||||
{
|
||||
commsUser = null;
|
||||
await e.Channel.SendMessage("Server for comms set.").ConfigureAwait(false);
|
||||
}
|
||||
else
|
||||
await e.Channel.SendMessage("No server specified or channel is invalid.").ConfigureAwait(false);
|
||||
});
|
||||
|
||||
cgb.CreateCommand(Prefix + "send")
|
||||
.Description("Send a message to someone on a different server through the bot. **Bot Owner Only!**\n**Usage**: .send Message text multi word!")
|
||||
.Description("Send a message to someone on a different server through the bot. **Bot Owner Only!**\n**Usage**: `.send serverid|u:user_id Send this to a user!` or `.send serverid|c:channel_id Send this to a channel!`")
|
||||
.Parameter("ids", ParameterType.Required)
|
||||
.Parameter("msg", ParameterType.Unparsed)
|
||||
.AddCheck(SimpleCheckers.OwnerOnly())
|
||||
.Do(async e =>
|
||||
{
|
||||
if (commsUser != null)
|
||||
await commsUser.SendMessage(e.GetArg("msg")).ConfigureAwait(false);
|
||||
else if (commsChannel != null)
|
||||
await commsChannel.SendMessage(e.GetArg("msg")).ConfigureAwait(false);
|
||||
var msg = e.GetArg("msg")?.Trim();
|
||||
|
||||
if (string.IsNullOrWhiteSpace(msg))
|
||||
return;
|
||||
|
||||
var ids = e.GetArg("ids").Split('-');
|
||||
if (ids.Length != 2)
|
||||
return;
|
||||
var sid = ulong.Parse(ids[0]);
|
||||
var server = NadekoBot.Client.Servers.Where(s => s.Id == sid).FirstOrDefault();
|
||||
|
||||
if (server == null)
|
||||
return;
|
||||
|
||||
if (ids[1].ToUpperInvariant().StartsWith("C:"))
|
||||
{
|
||||
var cid = ulong.Parse(ids[1].Substring(2));
|
||||
var channel = server.TextChannels.Where(c => c.Id == cid).FirstOrDefault();
|
||||
if (channel == null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
await channel.SendMessage(msg);
|
||||
}
|
||||
else if (ids[1].ToUpperInvariant().StartsWith("U:"))
|
||||
{
|
||||
var uid = ulong.Parse(ids[1].Substring(2));
|
||||
var user = server.Users.Where(u => u.Id == uid).FirstOrDefault();
|
||||
if (user == null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
await user.SendMessage(msg);
|
||||
}
|
||||
else
|
||||
await e.Channel.SendMessage("Failed. Make sure you've specified server and [channel or user]").ConfigureAwait(false);
|
||||
{
|
||||
await e.Channel.SendMessage("`Invalid format.`");
|
||||
}
|
||||
});
|
||||
|
||||
cgb.CreateCommand(Prefix + "mentionrole")
|
||||
@ -874,37 +828,6 @@ namespace NadekoBot.Modules.Administration
|
||||
}).ConfigureAwait(false);
|
||||
});
|
||||
|
||||
cgb.CreateCommand(Prefix + "inrole")
|
||||
.Description("Lists every person from the provided role or roles (separated by a ',') on this server.")
|
||||
.Parameter("roles", ParameterType.Unparsed)
|
||||
.Do(async e =>
|
||||
{
|
||||
await Task.Run(async () =>
|
||||
{
|
||||
if (!e.User.ServerPermissions.MentionEveryone) return;
|
||||
var arg = e.GetArg("roles").Split(',').Select(r => r.Trim());
|
||||
string send = $"`Here is a list of users in a specfic role:`";
|
||||
foreach (var roleStr in arg.Where(str => !string.IsNullOrWhiteSpace(str)))
|
||||
{
|
||||
var role = e.Server.FindRoles(roleStr).FirstOrDefault();
|
||||
if (role == null) continue;
|
||||
send += $"\n`{role.Name}`\n";
|
||||
send += string.Join(", ", role.Members.Select(r => "**" + r.Name + "**#" + r.Discriminator));
|
||||
}
|
||||
|
||||
while (send.Length > 2000)
|
||||
{
|
||||
var curstr = send.Substring(0, 2000);
|
||||
await
|
||||
e.Channel.Send(curstr.Substring(0,
|
||||
curstr.LastIndexOf(", ", StringComparison.Ordinal) + 1)).ConfigureAwait(false);
|
||||
send = curstr.Substring(curstr.LastIndexOf(", ", StringComparison.Ordinal) + 1) +
|
||||
send.Substring(2000);
|
||||
}
|
||||
await e.Channel.Send(send).ConfigureAwait(false);
|
||||
}).ConfigureAwait(false);
|
||||
});
|
||||
|
||||
cgb.CreateCommand(Prefix + "unstuck")
|
||||
.Description("Clears the message queue. **Bot Owner Only!**")
|
||||
.AddCheck(SimpleCheckers.OwnerOnly())
|
||||
@ -967,27 +890,6 @@ namespace NadekoBot.Modules.Administration
|
||||
await e.Channel.SendMessage(":ok:").ConfigureAwait(false);
|
||||
});
|
||||
|
||||
cgb.CreateCommand(Prefix + "whoplays")
|
||||
.Description("Shows a list of users who are playing the specified game.")
|
||||
.Parameter("game", ParameterType.Unparsed)
|
||||
.Do(async e =>
|
||||
{
|
||||
var game = e.GetArg("game")?.Trim().ToUpperInvariant();
|
||||
if (string.IsNullOrWhiteSpace(game))
|
||||
return;
|
||||
var en = e.Server.Users
|
||||
.Where(u => u.CurrentGame?.Name?.ToUpperInvariant() == game)
|
||||
.Select(u => u.Name);
|
||||
|
||||
var arr = en as string[] ?? en.ToArray();
|
||||
|
||||
int i = 0;
|
||||
if (arr.Length == 0)
|
||||
await e.Channel.SendMessage("Nobody. (not 100% sure)").ConfigureAwait(false);
|
||||
else
|
||||
await e.Channel.SendMessage("```xl\n" + string.Join("\n", arr.GroupBy(item => (i++) / 3).Select(ig => string.Join("", ig.Select(el => $"• {el,-35}")))) + "\n```").ConfigureAwait(false);
|
||||
});
|
||||
|
||||
cgb.CreateCommand(Prefix + "leave")
|
||||
.Description("Leaves a server with a supplied ID.\n**Usage**: `.leave 493243292839`")
|
||||
.Parameter("num", ParameterType.Required)
|
||||
@ -1003,6 +905,33 @@ namespace NadekoBot.Modules.Administration
|
||||
await e.Channel.SendMessage("`Done.`").ConfigureAwait(false);
|
||||
});
|
||||
|
||||
cgb.CreateCommand(Prefix + "savechat")
|
||||
.Description("Saves a number of messages to a text file and sends it to you. **Bot Owner Only** | `.chatsave 150`")
|
||||
.Parameter("cnt", ParameterType.Required)
|
||||
.AddCheck(SimpleCheckers.OwnerOnly())
|
||||
.Do(async e =>
|
||||
{
|
||||
var cntstr = e.GetArg("cnt")?.Trim();
|
||||
int cnt;
|
||||
if (!int.TryParse(cntstr, out cnt))
|
||||
return;
|
||||
ulong? lastmsgId = null;
|
||||
var sb = new StringBuilder();
|
||||
var msgs = new List<Message>(cnt);
|
||||
while (cnt > 0)
|
||||
{
|
||||
var dlcnt = cnt < 100 ? cnt : 100;
|
||||
|
||||
var dledMsgs = await e.Channel.DownloadMessages(dlcnt, lastmsgId);
|
||||
if (!dledMsgs.Any())
|
||||
break;
|
||||
msgs.AddRange(dledMsgs);
|
||||
lastmsgId = msgs[msgs.Count - 1].Id;
|
||||
cnt -= 100;
|
||||
}
|
||||
await e.User.SendFile($"Chatlog-{e.Server.Name}/#{e.Channel.Name}-{DateTime.Now}.txt", JsonConvert.SerializeObject(new { Messages = msgs.Select(s => s.ToString()) }, Formatting.Indented).ToStream());
|
||||
});
|
||||
|
||||
});
|
||||
}
|
||||
}
|
||||
|
@ -2,6 +2,7 @@
|
||||
using Discord.Commands;
|
||||
using NadekoBot.Classes;
|
||||
using NadekoBot.Modules.Permissions.Classes;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
@ -45,14 +46,88 @@ namespace NadekoBot.Modules.Administration.Commands
|
||||
|
||||
cgb.CreateCommand(Prefix + "listcustreact")
|
||||
.Alias(Prefix + "lcr")
|
||||
.Description($"Lists all current custom reactions (paginated with 5 commands per page).\n**Usage**:{Prefix}lcr 1")
|
||||
.Description($"Lists all current custom reactions (paginated with 30 commands per page).\n**Usage**:{Prefix}lcr 1")
|
||||
.Parameter("num", ParameterType.Required)
|
||||
.Do(async e =>
|
||||
{
|
||||
int num;
|
||||
if (!int.TryParse(e.GetArg("num"), out num) || num <= 0) return;
|
||||
string result = GetCustomsOnPage(num - 1); //People prefer starting with 1
|
||||
await e.Channel.SendMessage(result).ConfigureAwait(false);
|
||||
if (!int.TryParse(e.GetArg("num"), out num) || num <= 0) num = 1;
|
||||
var cmds = GetCustomsOnPage(num - 1);
|
||||
if (!cmds.Any())
|
||||
{
|
||||
await e.Channel.SendMessage("");
|
||||
}
|
||||
else
|
||||
{
|
||||
string result = SearchHelper.ShowInPrettyCode<string>(cmds, s => $"{s,-25}"); //People prefer starting with 1
|
||||
await e.Channel.SendMessage($"`Showing page {num}:`\n" + result).ConfigureAwait(false);
|
||||
}
|
||||
});
|
||||
|
||||
cgb.CreateCommand(Prefix + "showcustreact")
|
||||
.Alias(Prefix + "scr")
|
||||
.Description($"Shows all possible responses from a single custom reaction.\n**Usage**:{Prefix}scr %mention% bb")
|
||||
.Parameter("name", ParameterType.Unparsed)
|
||||
.Do(async e =>
|
||||
{
|
||||
var name = e.GetArg("name")?.Trim();
|
||||
if (string.IsNullOrWhiteSpace(name))
|
||||
return;
|
||||
if (!NadekoBot.Config.CustomReactions.ContainsKey(name))
|
||||
{
|
||||
await e.Channel.SendMessage("`Can't find that custom reaction.`").ConfigureAwait(false);
|
||||
return;
|
||||
}
|
||||
var items = NadekoBot.Config.CustomReactions[name];
|
||||
var message = new StringBuilder($"Responses for {Format.Bold(name)}:\n");
|
||||
var last = items.Last();
|
||||
|
||||
int i = 1;
|
||||
foreach (var reaction in items)
|
||||
{
|
||||
message.AppendLine($"[{i++}] " + Format.Code(reaction));
|
||||
}
|
||||
await e.Channel.SendMessage(message.ToString());
|
||||
});
|
||||
|
||||
cgb.CreateCommand(Prefix + "editcustreact")
|
||||
.Alias(Prefix + "ecr")
|
||||
.Description("Edits a custom reaction, arguments are custom reactions name, index to change, and a (multiword) message **Bot Owner Only** | `.ecr \"%mention% disguise\" 2 Test 123`")
|
||||
.Parameter("name", ParameterType.Required)
|
||||
.Parameter("index", ParameterType.Required)
|
||||
.Parameter("message", ParameterType.Unparsed)
|
||||
.AddCheck(SimpleCheckers.OwnerOnly())
|
||||
.Do(async e =>
|
||||
{
|
||||
var name = e.GetArg("name")?.Trim();
|
||||
if (string.IsNullOrWhiteSpace(name))
|
||||
return;
|
||||
var indexstr = e.GetArg("index")?.Trim();
|
||||
if (string.IsNullOrWhiteSpace(indexstr))
|
||||
return;
|
||||
var msg = e.GetArg("message")?.Trim();
|
||||
if (string.IsNullOrWhiteSpace(msg))
|
||||
return;
|
||||
|
||||
|
||||
|
||||
if (!NadekoBot.Config.CustomReactions.ContainsKey(name))
|
||||
{
|
||||
await e.Channel.SendMessage("`Could not find given commandname`").ConfigureAwait(false);
|
||||
return;
|
||||
}
|
||||
|
||||
int index;
|
||||
if (!int.TryParse(indexstr, out index) || index < 1 || index > NadekoBot.Config.CustomReactions[name].Count)
|
||||
{
|
||||
await e.Channel.SendMessage("`Invalid index.`").ConfigureAwait(false);
|
||||
return;
|
||||
}
|
||||
index = index - 1;
|
||||
NadekoBot.Config.CustomReactions[name][index] = msg;
|
||||
|
||||
await Task.Run(() => Classes.JSONModels.ConfigHandler.SaveConfig()).ConfigureAwait(false);
|
||||
await e.Channel.SendMessage($"Edited response #{index + 1} from `{name}`").ConfigureAwait(false);
|
||||
});
|
||||
|
||||
cgb.CreateCommand(Prefix + "delcustreact")
|
||||
@ -99,19 +174,21 @@ namespace NadekoBot.Modules.Administration.Commands
|
||||
});
|
||||
}
|
||||
|
||||
private readonly int ItemsPerPage = 5;
|
||||
private readonly int ItemsPerPage = 30;
|
||||
|
||||
private string GetCustomsOnPage(int page)
|
||||
private IEnumerable<string> GetCustomsOnPage(int page)
|
||||
{
|
||||
var items = NadekoBot.Config.CustomReactions.Skip(page * ItemsPerPage).Take(ItemsPerPage);
|
||||
if (!items.Any())
|
||||
{
|
||||
return $"No items on page {page + 1}.";
|
||||
return Enumerable.Empty<string>();
|
||||
}
|
||||
return items.Select(kvp => kvp.Key);
|
||||
/*
|
||||
var message = new StringBuilder($"--- Custom reactions - page {page + 1} ---\n");
|
||||
foreach (var cr in items)
|
||||
{
|
||||
message.Append($"{ Format.Code(cr.Key)}\n");
|
||||
message.Append($"{Format.Code(cr.Key)}\n");
|
||||
int i = 1;
|
||||
var last = cr.Value.Last();
|
||||
foreach (var reaction in cr.Value)
|
||||
@ -123,6 +200,7 @@ namespace NadekoBot.Modules.Administration.Commands
|
||||
}
|
||||
}
|
||||
return message.ToString() + "\n";
|
||||
*/
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -0,0 +1,47 @@
|
||||
using Discord.Commands;
|
||||
using NadekoBot.Classes;
|
||||
using NadekoBot.DataModels;
|
||||
using NadekoBot.Modules.Permissions.Classes;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
|
||||
namespace NadekoBot.Modules.Administration.Commands
|
||||
{
|
||||
internal class IncidentsCommands : DiscordCommand
|
||||
{
|
||||
public IncidentsCommands(DiscordModule module) : base(module) { }
|
||||
internal override void Init(CommandGroupBuilder cgb)
|
||||
{
|
||||
cgb.CreateCommand(Module.Prefix + "listincidents")
|
||||
.Alias(Prefix + "lin")
|
||||
.Description("List all UNREAD incidents and flags them as read.")
|
||||
.AddCheck(SimpleCheckers.ManageServer())
|
||||
.Do(async e =>
|
||||
{
|
||||
var sid = (long)e.Server.Id;
|
||||
var incs = DbHandler.Instance.FindAll<Incident>(i => i.ServerId == sid && i.Read == false);
|
||||
DbHandler.Instance.UpdateAll<Incident>(incs.Select(i => { i.Read = true; return i; }));
|
||||
|
||||
await e.User.SendMessage(string.Join("\n----------------------", incs.Select(i => i.Text)));
|
||||
});
|
||||
|
||||
cgb.CreateCommand(Module.Prefix + "listallincidents")
|
||||
.Alias(Prefix + "lain")
|
||||
.Description("Sends you a file containing all incidents and flags them as read.")
|
||||
.AddCheck(SimpleCheckers.ManageServer())
|
||||
.Do(async e =>
|
||||
{
|
||||
var sid = (long)e.Server.Id;
|
||||
var incs = DbHandler.Instance.FindAll<Incident>(i => i.ServerId == sid);
|
||||
DbHandler.Instance.UpdateAll<Incident>(incs.Select(i => { i.Read = true; return i; }));
|
||||
var data = string.Join("\n----------------------\n", incs.Select(i => i.Text));
|
||||
MemoryStream ms = new MemoryStream();
|
||||
var sw = new StreamWriter(ms);
|
||||
sw.WriteLine(data);
|
||||
sw.Flush();
|
||||
sw.BaseStream.Position = 0;
|
||||
await e.User.SendFile("incidents.txt", sw.BaseStream);
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
@ -4,19 +4,12 @@ using NadekoBot.Classes;
|
||||
using NadekoBot.Extensions;
|
||||
using NadekoBot.Modules.Permissions.Classes;
|
||||
using System;
|
||||
using System.Collections.Concurrent;
|
||||
using System.Linq;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace NadekoBot.Modules.Administration.Commands
|
||||
{
|
||||
internal class LogCommand : DiscordCommand
|
||||
{
|
||||
|
||||
private readonly ConcurrentDictionary<Server, Channel> logs = new ConcurrentDictionary<Server, Channel>();
|
||||
private readonly ConcurrentDictionary<Server, Channel> loggingPresences = new ConcurrentDictionary<Server, Channel>();
|
||||
private readonly ConcurrentDictionary<Channel, Channel> voiceChannelLog = new ConcurrentDictionary<Channel, Channel>();
|
||||
|
||||
private string prettyCurrentTime => $"【{DateTime.Now:HH:mm:ss}】";
|
||||
|
||||
public LogCommand(DiscordModule module) : base(module)
|
||||
@ -58,8 +51,11 @@ namespace NadekoBot.Modules.Administration.Commands
|
||||
{
|
||||
try
|
||||
{
|
||||
var chId = SpecificConfigurations.Default.Of(e.Server.Id).LogServerChannel;
|
||||
if (chId == null)
|
||||
return;
|
||||
Channel ch;
|
||||
if (!logs.TryGetValue(e.Server, out ch))
|
||||
if ((ch = e.Server.TextChannels.Where(tc => tc.Id == chId).FirstOrDefault()) == null)
|
||||
return;
|
||||
if (e.Before.Name != e.After.Name)
|
||||
await ch.SendMessage($@"`{prettyCurrentTime}` **Channel Name Changed** `#{e.Before.Name}` (*{e.After.Id}*)
|
||||
@ -76,8 +72,11 @@ namespace NadekoBot.Modules.Administration.Commands
|
||||
{
|
||||
try
|
||||
{
|
||||
var chId = SpecificConfigurations.Default.Of(e.Server.Id).LogServerChannel;
|
||||
if (chId == null)
|
||||
return;
|
||||
Channel ch;
|
||||
if (!logs.TryGetValue(e.Server, out ch))
|
||||
if ((ch = e.Server.TextChannels.Where(tc => tc.Id == chId).FirstOrDefault()) == null)
|
||||
return;
|
||||
await ch.SendMessage($"❗`{prettyCurrentTime}`❗`Channel Deleted:` #{e.Channel.Name} (*{e.Channel.Id}*)").ConfigureAwait(false);
|
||||
}
|
||||
@ -88,8 +87,11 @@ namespace NadekoBot.Modules.Administration.Commands
|
||||
{
|
||||
try
|
||||
{
|
||||
var chId = SpecificConfigurations.Default.Of(e.Server.Id).LogServerChannel;
|
||||
if (chId == null)
|
||||
return;
|
||||
Channel ch;
|
||||
if (!logs.TryGetValue(e.Server, out ch))
|
||||
if ((ch = e.Server.TextChannels.Where(tc => tc.Id == chId).FirstOrDefault()) == null)
|
||||
return;
|
||||
await ch.SendMessage($"`{prettyCurrentTime}`🆕`Channel Created:` #{e.Channel.Mention} (*{e.Channel.Id}*)").ConfigureAwait(false);
|
||||
}
|
||||
@ -100,8 +102,11 @@ namespace NadekoBot.Modules.Administration.Commands
|
||||
{
|
||||
try
|
||||
{
|
||||
var chId = SpecificConfigurations.Default.Of(e.Server.Id).LogServerChannel;
|
||||
if (chId == null)
|
||||
return;
|
||||
Channel ch;
|
||||
if (!logs.TryGetValue(e.Server, out ch))
|
||||
if ((ch = e.Server.TextChannels.Where(tc => tc.Id == chId).FirstOrDefault()) == null)
|
||||
return;
|
||||
await ch.SendMessage($"`{prettyCurrentTime}`♻`User was unbanned:` **{e.User.Name}** ({e.User.Id})").ConfigureAwait(false);
|
||||
}
|
||||
@ -112,8 +117,11 @@ namespace NadekoBot.Modules.Administration.Commands
|
||||
{
|
||||
try
|
||||
{
|
||||
var chId = SpecificConfigurations.Default.Of(e.Server.Id).LogServerChannel;
|
||||
if (chId == null)
|
||||
return;
|
||||
Channel ch;
|
||||
if (!logs.TryGetValue(e.Server, out ch))
|
||||
if ((ch = e.Server.TextChannels.Where(tc => tc.Id == chId).FirstOrDefault()) == null)
|
||||
return;
|
||||
await ch.SendMessage($"`{prettyCurrentTime}`✅`User joined:` **{e.User.Name}** ({e.User.Id})").ConfigureAwait(false);
|
||||
}
|
||||
@ -124,8 +132,11 @@ namespace NadekoBot.Modules.Administration.Commands
|
||||
{
|
||||
try
|
||||
{
|
||||
var chId = SpecificConfigurations.Default.Of(e.Server.Id).LogServerChannel;
|
||||
if (chId == null)
|
||||
return;
|
||||
Channel ch;
|
||||
if (!logs.TryGetValue(e.Server, out ch))
|
||||
if ((ch = e.Server.TextChannels.Where(tc => tc.Id == chId).FirstOrDefault()) == null)
|
||||
return;
|
||||
await ch.SendMessage($"`{prettyCurrentTime}`❗`User left:` **{e.User.Name}** ({e.User.Id})").ConfigureAwait(false);
|
||||
}
|
||||
@ -136,35 +147,28 @@ namespace NadekoBot.Modules.Administration.Commands
|
||||
{
|
||||
try
|
||||
{
|
||||
var chId = SpecificConfigurations.Default.Of(e.Server.Id).LogServerChannel;
|
||||
if (chId == null)
|
||||
return;
|
||||
Channel ch;
|
||||
if (!logs.TryGetValue(e.Server, out ch))
|
||||
if ((ch = e.Server.TextChannels.Where(tc => tc.Id == chId).FirstOrDefault()) == null)
|
||||
return;
|
||||
await ch.SendMessage($"❗`{prettyCurrentTime}`❌`User banned:` **{e.User.Name}** ({e.User.Id})").ConfigureAwait(false);
|
||||
}
|
||||
catch { }
|
||||
}
|
||||
|
||||
public Func<CommandEventArgs, Task> DoFunc() => async e =>
|
||||
{
|
||||
Channel ch;
|
||||
if (!logs.TryRemove(e.Server, out ch))
|
||||
{
|
||||
logs.TryAdd(e.Server, e.Channel);
|
||||
await e.Channel.SendMessage($"❗**I WILL BEGIN LOGGING SERVER ACTIVITY IN THIS CHANNEL**❗").ConfigureAwait(false);
|
||||
return;
|
||||
}
|
||||
|
||||
await e.Channel.SendMessage($"❗**NO LONGER LOGGING IN {ch.Mention} CHANNEL**❗").ConfigureAwait(false);
|
||||
};
|
||||
|
||||
private async void MsgRecivd(object sender, MessageEventArgs e)
|
||||
{
|
||||
try
|
||||
{
|
||||
if (e.Server == null || e.Channel.IsPrivate || e.User.Id == NadekoBot.Client.CurrentUser.Id)
|
||||
return;
|
||||
var chId = SpecificConfigurations.Default.Of(e.Server.Id).LogServerChannel;
|
||||
if (chId == null || e.Channel.Id == chId)
|
||||
return;
|
||||
Channel ch;
|
||||
if (!logs.TryGetValue(e.Server, out ch) || e.Channel == ch)
|
||||
if ((ch = e.Server.TextChannels.Where(tc => tc.Id == chId).FirstOrDefault()) == null)
|
||||
return;
|
||||
if (!string.IsNullOrWhiteSpace(e.Message.Text))
|
||||
{
|
||||
@ -188,8 +192,11 @@ namespace NadekoBot.Modules.Administration.Commands
|
||||
{
|
||||
if (e.Server == null || e.Channel.IsPrivate || e.User?.Id == NadekoBot.Client.CurrentUser.Id)
|
||||
return;
|
||||
var chId = SpecificConfigurations.Default.Of(e.Server.Id).LogServerChannel;
|
||||
if (chId == null || e.Channel.Id == chId)
|
||||
return;
|
||||
Channel ch;
|
||||
if (!logs.TryGetValue(e.Server, out ch) || e.Channel == ch)
|
||||
if ((ch = e.Server.TextChannels.Where(tc => tc.Id == chId).FirstOrDefault()) == null)
|
||||
return;
|
||||
if (!string.IsNullOrWhiteSpace(e.Message.Text))
|
||||
{
|
||||
@ -212,8 +219,11 @@ namespace NadekoBot.Modules.Administration.Commands
|
||||
{
|
||||
if (e.Server == null || e.Channel.IsPrivate || e.User?.Id == NadekoBot.Client.CurrentUser.Id)
|
||||
return;
|
||||
var chId = SpecificConfigurations.Default.Of(e.Server.Id).LogServerChannel;
|
||||
if (chId == null || e.Channel.Id == chId)
|
||||
return;
|
||||
Channel ch;
|
||||
if (!logs.TryGetValue(e.Server, out ch) || e.Channel == ch)
|
||||
if ((ch = e.Server.TextChannels.Where(tc => tc.Id == chId).FirstOrDefault()) == null)
|
||||
return;
|
||||
await ch.SendMessage(
|
||||
$@"🕔`{prettyCurrentTime}` **Message** 📝 `#{e.Channel.Name}`
|
||||
@ -225,19 +235,28 @@ $@"🕔`{prettyCurrentTime}` **Message** 📝 `#{e.Channel.Name}`
|
||||
}
|
||||
private async void UsrUpdtd(object sender, UserUpdatedEventArgs e)
|
||||
{
|
||||
var config = SpecificConfigurations.Default.Of(e.Server.Id);
|
||||
try
|
||||
{
|
||||
Channel ch;
|
||||
if (loggingPresences.TryGetValue(e.Server, out ch))
|
||||
if (e.Before.Status != e.After.Status)
|
||||
var chId = config.LogServerChannel;
|
||||
if (chId != null)
|
||||
{
|
||||
Channel ch;
|
||||
if ((ch = e.Server.TextChannels.Where(tc => tc.Id == chId).FirstOrDefault()) != null)
|
||||
{
|
||||
await ch.SendMessage($"`{prettyCurrentTime}`**{e.Before.Name}** is now **{e.After.Status}**.").ConfigureAwait(false);
|
||||
if (e.Before.Status != e.After.Status)
|
||||
{
|
||||
await ch.SendMessage($"`{prettyCurrentTime}`**{e.Before.Name}** is now **{e.After.Status}**.").ConfigureAwait(false);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
catch { }
|
||||
|
||||
try
|
||||
{
|
||||
ulong notifyChBeforeId;
|
||||
ulong notifyChAfterId;
|
||||
Channel notifyChBefore = null;
|
||||
Channel notifyChAfter = null;
|
||||
var beforeVch = e.Before.VoiceChannel;
|
||||
@ -246,11 +265,11 @@ $@"🕔`{prettyCurrentTime}` **Message** 📝 `#{e.Channel.Name}`
|
||||
var notifyJoin = false;
|
||||
if ((beforeVch != null || afterVch != null) && (beforeVch != afterVch)) // this means we need to notify for sure.
|
||||
{
|
||||
if (beforeVch != null && voiceChannelLog.TryGetValue(beforeVch, out notifyChBefore))
|
||||
if (beforeVch != null && config.VoiceChannelLog.TryGetValue(beforeVch.Id, out notifyChBeforeId) && (notifyChBefore = e.Before.Server.TextChannels.FirstOrDefault(tc => tc.Id == notifyChBeforeId)) != null)
|
||||
{
|
||||
notifyLeave = true;
|
||||
}
|
||||
if (afterVch != null && voiceChannelLog.TryGetValue(afterVch, out notifyChAfter))
|
||||
if (afterVch != null && config.VoiceChannelLog.TryGetValue(afterVch.Id, out notifyChAfterId) && (notifyChAfter = e.After.Server.TextChannels.FirstOrDefault(tc => tc.Id == notifyChAfterId)) != null)
|
||||
{
|
||||
notifyJoin = true;
|
||||
}
|
||||
@ -272,8 +291,11 @@ $@"🕔`{prettyCurrentTime}` **Message** 📝 `#{e.Channel.Name}`
|
||||
|
||||
try
|
||||
{
|
||||
var chId = SpecificConfigurations.Default.Of(e.Server.Id).LogServerChannel;
|
||||
if (chId == null)
|
||||
return;
|
||||
Channel ch;
|
||||
if (!logs.TryGetValue(e.Server, out ch))
|
||||
if ((ch = e.Server.TextChannels.Where(tc => tc.Id == chId).FirstOrDefault()) == null)
|
||||
return;
|
||||
string str = $"🕔`{prettyCurrentTime}`";
|
||||
if (e.Before.Name != e.After.Name)
|
||||
@ -331,21 +353,34 @@ $@"🕔`{prettyCurrentTime}` **Message** 📝 `#{e.Channel.Name}`
|
||||
.Description("Toggles logging in this channel. Logs every message sent/deleted/edited on the server. **Bot Owner Only!**")
|
||||
.AddCheck(SimpleCheckers.OwnerOnly())
|
||||
.AddCheck(SimpleCheckers.ManageServer())
|
||||
.Do(DoFunc());
|
||||
.Do(async e =>
|
||||
{
|
||||
var chId = SpecificConfigurations.Default.Of(e.Server.Id).LogServerChannel;
|
||||
if (chId == null)
|
||||
{
|
||||
SpecificConfigurations.Default.Of(e.Server.Id).LogServerChannel = e.Channel.Id;
|
||||
await e.Channel.SendMessage($"❗**I WILL BEGIN LOGGING SERVER ACTIVITY IN THIS CHANNEL**❗").ConfigureAwait(false);
|
||||
return;
|
||||
}
|
||||
Channel ch;
|
||||
if ((ch = e.Server.TextChannels.Where(tc => tc.Id == chId).FirstOrDefault()) == null)
|
||||
return;
|
||||
await e.Channel.SendMessage($"❗**NO LONGER LOGGING IN {ch.Mention} CHANNEL**❗").ConfigureAwait(false);
|
||||
});
|
||||
|
||||
cgb.CreateCommand(Module.Prefix + "userpresence")
|
||||
.Description("Starts logging to this channel when someone from the server goes online/offline/idle.")
|
||||
.AddCheck(SimpleCheckers.ManageServer())
|
||||
.Do(async e =>
|
||||
{
|
||||
Channel ch;
|
||||
if (!loggingPresences.TryRemove(e.Server, out ch))
|
||||
var chId = SpecificConfigurations.Default.Of(e.Server.Id).LogServerChannel;
|
||||
if (chId == null)
|
||||
{
|
||||
loggingPresences.TryAdd(e.Server, e.Channel);
|
||||
SpecificConfigurations.Default.Of(e.Server.Id).LogServerChannel = e.Channel.Id;
|
||||
await e.Channel.SendMessage($"**User presence notifications enabled.**").ConfigureAwait(false);
|
||||
return;
|
||||
}
|
||||
|
||||
SpecificConfigurations.Default.Of(e.Server.Id).LogServerChannel = null;
|
||||
await e.Channel.SendMessage($"**User presence notifications disabled.**").ConfigureAwait(false);
|
||||
});
|
||||
|
||||
@ -356,11 +391,12 @@ $@"🕔`{prettyCurrentTime}` **Message** 📝 `#{e.Channel.Name}`
|
||||
.Do(async e =>
|
||||
{
|
||||
|
||||
var config = SpecificConfigurations.Default.Of(e.Server.Id);
|
||||
if (e.GetArg("all")?.ToLower() == "all")
|
||||
{
|
||||
foreach (var voiceChannel in e.Server.VoiceChannels)
|
||||
{
|
||||
voiceChannelLog.TryAdd(voiceChannel, e.Channel);
|
||||
config.VoiceChannelLog.TryAdd(voiceChannel.Id, e.Channel.Id);
|
||||
}
|
||||
await e.Channel.SendMessage("Started logging user presence for **ALL** voice channels!").ConfigureAwait(false);
|
||||
return;
|
||||
@ -371,10 +407,10 @@ $@"🕔`{prettyCurrentTime}` **Message** 📝 `#{e.Channel.Name}`
|
||||
await e.Channel.SendMessage("💢 You are not in a voice channel right now. If you are, please rejoin it.").ConfigureAwait(false);
|
||||
return;
|
||||
}
|
||||
Channel throwaway;
|
||||
if (!voiceChannelLog.TryRemove(e.User.VoiceChannel, out throwaway))
|
||||
ulong throwaway;
|
||||
if (!config.VoiceChannelLog.TryRemove(e.User.VoiceChannel.Id, out throwaway))
|
||||
{
|
||||
voiceChannelLog.TryAdd(e.User.VoiceChannel, e.Channel);
|
||||
config.VoiceChannelLog.TryAdd(e.User.VoiceChannel.Id, e.Channel.Id);
|
||||
await e.Channel.SendMessage($"`Logging user updates for` {e.User.VoiceChannel.Mention} `voice channel.`").ConfigureAwait(false);
|
||||
}
|
||||
else
|
||||
|
@ -51,11 +51,9 @@ namespace NadekoBot.Modules.Administration.Commands
|
||||
{
|
||||
if (PlayingPlaceholders.Count == 0
|
||||
|| NadekoBot.Config.RotatingStatuses.Count == 0
|
||||
|| i >= PlayingPlaceholders.Count
|
||||
|| i >= NadekoBot.Config.RotatingStatuses.Count)
|
||||
{
|
||||
i = -1;
|
||||
return;
|
||||
i = 0;
|
||||
}
|
||||
status = NadekoBot.Config.RotatingStatuses[i];
|
||||
status = PlayingPlaceholders.Aggregate(status,
|
||||
|
@ -1,62 +0,0 @@
|
||||
using Discord.Commands;
|
||||
using NadekoBot.Modules;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace NadekoBot.Classes.Conversations.Commands
|
||||
{
|
||||
internal class CopyCommand : DiscordCommand
|
||||
{
|
||||
private readonly HashSet<ulong> CopiedUsers = new HashSet<ulong>();
|
||||
|
||||
public CopyCommand(DiscordModule module) : base(module)
|
||||
{
|
||||
NadekoBot.Client.MessageReceived += Client_MessageReceived;
|
||||
}
|
||||
|
||||
private async void Client_MessageReceived(object sender, Discord.MessageEventArgs e)
|
||||
{
|
||||
if (e.User.Id == NadekoBot.Client.CurrentUser.Id) return;
|
||||
try
|
||||
{
|
||||
if (string.IsNullOrWhiteSpace(e.Message.Text))
|
||||
return;
|
||||
if (CopiedUsers.Contains(e.User.Id))
|
||||
{
|
||||
await e.Channel.SendMessage(e.Message.Text).ConfigureAwait(false);
|
||||
}
|
||||
}
|
||||
catch { }
|
||||
}
|
||||
|
||||
public Func<CommandEventArgs, Task> DoFunc() => async e =>
|
||||
{
|
||||
if (CopiedUsers.Contains(e.User.Id)) return;
|
||||
|
||||
CopiedUsers.Add(e.User.Id);
|
||||
await e.Channel.SendMessage(" I'll start copying you now.").ConfigureAwait(false);
|
||||
};
|
||||
|
||||
internal override void Init(CommandGroupBuilder cgb)
|
||||
{
|
||||
cgb.CreateCommand("copyme")
|
||||
.Alias("cm")
|
||||
.Description("Nadeko starts copying everything you say. Disable with cs")
|
||||
.Do(DoFunc());
|
||||
|
||||
cgb.CreateCommand("cs")
|
||||
.Alias("copystop")
|
||||
.Description("Nadeko stops copying you")
|
||||
.Do(StopCopy());
|
||||
}
|
||||
|
||||
private Func<CommandEventArgs, Task> StopCopy() => async e =>
|
||||
{
|
||||
if (!CopiedUsers.Contains(e.User.Id)) return;
|
||||
|
||||
CopiedUsers.Remove(e.User.Id);
|
||||
await e.Channel.SendMessage(" I wont copy anymore.").ConfigureAwait(false);
|
||||
};
|
||||
}
|
||||
}
|
@ -1,7 +1,6 @@
|
||||
using Discord;
|
||||
using Discord.Commands;
|
||||
using Discord.Modules;
|
||||
using NadekoBot.Classes.Conversations.Commands;
|
||||
using NadekoBot.DataModels;
|
||||
using NadekoBot.Extensions;
|
||||
using NadekoBot.Modules.Conversations.Commands;
|
||||
@ -19,7 +18,6 @@ namespace NadekoBot.Modules.Conversations
|
||||
private const string firestr = "🔥 ด้้้้้็็็็็้้้้้็็็็็้้้้้้้้็็็็็้้้้้็็ด้้้้้็็็็็้้้้้็็็็็้้้้้้้้็็็็็้้้้้็็็็็้้้้้้้้็็็ด้้้้้็็็็็้้้้้็็็็็้้้้้้้้็็็็็้้้้้็็็็็้้้้ 🔥";
|
||||
public Conversations()
|
||||
{
|
||||
commands.Add(new CopyCommand(this));
|
||||
commands.Add(new RipCommand(this));
|
||||
}
|
||||
|
||||
@ -255,21 +253,6 @@ namespace NadekoBot.Modules.Conversations
|
||||
await e.Channel.SendMessage(construct).ConfigureAwait(false);
|
||||
});
|
||||
|
||||
cgb.CreateCommand("av")
|
||||
.Alias("avatar")
|
||||
.Parameter("mention", ParameterType.Required)
|
||||
.Description("Shows a mentioned person's avatar.\n**Usage**: ~av @X")
|
||||
.Do(async e =>
|
||||
{
|
||||
var usr = e.Channel.FindUsers(e.GetArg("mention")).FirstOrDefault();
|
||||
if (usr == null)
|
||||
{
|
||||
await e.Channel.SendMessage("Invalid user specified.").ConfigureAwait(false);
|
||||
return;
|
||||
}
|
||||
await e.Channel.SendMessage(await usr.AvatarUrl.ShortenUrl()).ConfigureAwait(false);
|
||||
});
|
||||
|
||||
});
|
||||
}
|
||||
|
||||
|
@ -15,6 +15,11 @@ namespace NadekoBot.Classes
|
||||
/// </summary>
|
||||
protected DiscordModule Module { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Parent module's prefix
|
||||
/// </summary>
|
||||
protected string Prefix => Module.Prefix;
|
||||
|
||||
/// <summary>
|
||||
/// Creates a new instance of discord command,
|
||||
/// use ": base(module)" in the derived class'
|
||||
|
@ -79,7 +79,7 @@ namespace NadekoBot.Modules.Gambling
|
||||
await e.Channel.SendFile(images.Count + " cards.jpg", bitmap.ToStream()).ConfigureAwait(false);
|
||||
if (cardObjects.Count == 5)
|
||||
{
|
||||
await e.Channel.SendMessage(Cards.GetHandValue(cardObjects)).ConfigureAwait(false);
|
||||
await e.Channel.SendMessage($"{e.User.Mention} `{Cards.GetHandValue(cardObjects)}`").ConfigureAwait(false);
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
|
@ -1,10 +1,12 @@
|
||||
using Discord;
|
||||
using Discord.Commands;
|
||||
using NadekoBot.Classes;
|
||||
using NadekoBot.Modules.Permissions.Classes;
|
||||
using System;
|
||||
using System.Collections.Concurrent;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Security.Cryptography;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace NadekoBot.Modules.Games.Commands
|
||||
@ -18,11 +20,31 @@ namespace NadekoBot.Modules.Games.Commands
|
||||
/// </summary>
|
||||
class PlantPick : DiscordCommand
|
||||
{
|
||||
|
||||
private Random rng;
|
||||
public PlantPick(DiscordModule module) : base(module)
|
||||
{
|
||||
|
||||
NadekoBot.Client.MessageReceived += PotentialFlowerGeneration;
|
||||
rng = new Random();
|
||||
}
|
||||
|
||||
|
||||
private async void PotentialFlowerGeneration(object sender, Discord.MessageEventArgs e)
|
||||
{
|
||||
if (e.Server == null || e.Channel.IsPrivate)
|
||||
return;
|
||||
var config = Classes.SpecificConfigurations.Default.Of(e.Server.Id);
|
||||
if (config.GenerateCurrencyChannels.Contains(e.Channel.Id))
|
||||
{
|
||||
var rnd = Math.Abs(GetRandomNumber());
|
||||
if ((rnd % 50) == 0)
|
||||
{
|
||||
var msg = await e.Channel.SendFile(GetRandomCurrencyImagePath());
|
||||
await e.Channel.SendMessage($"❗ A random {NadekoBot.Config.CurrencyName} appeared! Pick it up by typing `>pick`");
|
||||
plantedFlowerChannels.AddOrUpdate(e.Channel.Id, msg, (u, m) => { m.Delete().GetAwaiter().GetResult(); return msg; });
|
||||
}
|
||||
}
|
||||
}
|
||||
//channelid/messageid pair
|
||||
ConcurrentDictionary<ulong, Message> plantedFlowerChannels = new ConcurrentDictionary<ulong, Message>();
|
||||
|
||||
@ -65,8 +87,7 @@ namespace NadekoBot.Modules.Games.Commands
|
||||
return;
|
||||
}
|
||||
|
||||
var rng = new Random();
|
||||
var file = Directory.GetFiles("data/currency_images").OrderBy(s => rng.Next()).FirstOrDefault();
|
||||
var file = GetRandomCurrencyImagePath();
|
||||
Message msg;
|
||||
//todo send message after, not in lock
|
||||
if (file == null)
|
||||
@ -80,6 +101,38 @@ namespace NadekoBot.Modules.Games.Commands
|
||||
await Task.Delay(20000).ConfigureAwait(false);
|
||||
await msg2.Delete().ConfigureAwait(false);
|
||||
});
|
||||
|
||||
cgb.CreateCommand(Prefix + "gencurrency")
|
||||
.Alias(Prefix + "gc")
|
||||
.Description($"Toggles currency generation on this channel. Every posted message will have 2% chance to spawn a {NadekoBot.Config.CurrencyName}. Requires Manage Messages permission. | `>gc`")
|
||||
.AddCheck(SimpleCheckers.ManageMessages())
|
||||
.Do(async e =>
|
||||
{
|
||||
var config = SpecificConfigurations.Default.Of(e.Server.Id);
|
||||
if (config.GenerateCurrencyChannels.Remove(e.Channel.Id))
|
||||
{
|
||||
await e.Channel.SendMessage("`Currency generation disabled on this channel.`");
|
||||
}
|
||||
else
|
||||
{
|
||||
config.GenerateCurrencyChannels.Add(e.Channel.Id);
|
||||
await e.Channel.SendMessage("`Currency generation enabled on this channel.`");
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
private string GetRandomCurrencyImagePath() =>
|
||||
Directory.GetFiles("data/currency_images").OrderBy(s => rng.Next()).FirstOrDefault();
|
||||
|
||||
int GetRandomNumber()
|
||||
{
|
||||
using (RNGCryptoServiceProvider rg = new RNGCryptoServiceProvider())
|
||||
{
|
||||
byte[] rno = new byte[4];
|
||||
rg.GetBytes(rno);
|
||||
int randomvalue = BitConverter.ToInt32(rno, 0);
|
||||
return randomvalue;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -86,7 +86,7 @@ Version: `{NadekoStats.Instance.BotVersion}`";
|
||||
.Description("Sends a readme and a guide links to the channel.")
|
||||
.Do(async e =>
|
||||
await e.Channel.SendMessage(
|
||||
@"**FULL README**: <https://github.com/Kwoth/NadekoBot/blob/master/README.md>
|
||||
@"**Wiki with all info**: <https://github.com/Kwoth/NadekoBot/wiki>
|
||||
|
||||
**WINDOWS SETUP GUIDE**: <https://github.com/Kwoth/NadekoBot/blob/master/ComprehensiveGuide.md>
|
||||
|
||||
|
@ -1,5 +1,6 @@
|
||||
using Discord.Commands;
|
||||
using Discord.Modules;
|
||||
using NadekoBot.Classes;
|
||||
using NadekoBot.Classes.Help.Commands;
|
||||
using NadekoBot.Extensions;
|
||||
using NadekoBot.Modules.Permissions.Classes;
|
||||
@ -54,10 +55,8 @@ namespace NadekoBot.Modules.Help
|
||||
}
|
||||
var i = 0;
|
||||
if (module != "customreactions" && module != "conversations")
|
||||
await e.Channel.SendMessage("`List Of Commands:`\n```xl\n" +
|
||||
string.Join("\n", cmdsArray.GroupBy(item => (i++) / 3)
|
||||
.Select(ig => string.Join("", ig.Select(el => $"{el.Text,-15}" + $"{"[" + el.Aliases.FirstOrDefault() + "]",-8}"))))
|
||||
+ $"\n```")
|
||||
await e.Channel.SendMessage("`List Of Commands:`\n" + SearchHelper.ShowInPrettyCode<Command>(cmdsArray,
|
||||
el => $"{el.Text,-15}{"[" + el.Aliases.FirstOrDefault() + "]",-8}"))
|
||||
.ConfigureAwait(false);
|
||||
else
|
||||
await e.Channel.SendMessage("`List Of Commands:`\n• " + string.Join("\n• ", cmdsArray.Select(c => $"{c.Text}")));
|
||||
|
@ -50,6 +50,7 @@ namespace NadekoBot.Modules.Music.Classes
|
||||
private bool Destroyed { get; set; } = false;
|
||||
public bool RepeatSong { get; private set; } = false;
|
||||
public bool RepeatPlaylist { get; private set; } = false;
|
||||
public bool Autoplay { get; private set; } = false;
|
||||
|
||||
public MusicPlayer(Channel startingVoiceChannel, float? defaultVolume)
|
||||
{
|
||||
@ -173,6 +174,7 @@ namespace NadekoBot.Modules.Music.Classes
|
||||
throw new ArgumentNullException(nameof(s));
|
||||
lock (playlistLock)
|
||||
{
|
||||
s.MusicPlayer = this;
|
||||
playlist.Add(s);
|
||||
}
|
||||
}
|
||||
@ -239,5 +241,7 @@ namespace NadekoBot.Modules.Music.Classes
|
||||
internal bool ToggleRepeatSong() => this.RepeatSong = !this.RepeatSong;
|
||||
|
||||
internal bool ToggleRepeatPlaylist() => this.RepeatPlaylist = !this.RepeatPlaylist;
|
||||
|
||||
internal bool ToggleAutoplay() => this.Autoplay = !this.Autoplay;
|
||||
}
|
||||
}
|
||||
|
@ -54,7 +54,7 @@ namespace NadekoBot.Modules.Music.Classes
|
||||
}
|
||||
}
|
||||
|
||||
private Song(SongInfo songInfo)
|
||||
public Song(SongInfo songInfo)
|
||||
{
|
||||
this.SongInfo = songInfo;
|
||||
}
|
||||
@ -67,6 +67,12 @@ namespace NadekoBot.Modules.Music.Classes
|
||||
return s;
|
||||
}
|
||||
|
||||
public Song SetMusicPlayer(MusicPlayer mp)
|
||||
{
|
||||
this.MusicPlayer = mp;
|
||||
return this;
|
||||
}
|
||||
|
||||
private Task BufferSong(CancellationToken cancelToken) =>
|
||||
Task.Factory.StartNew(async () =>
|
||||
{
|
||||
|
@ -1,4 +1,5 @@
|
||||
using NadekoBot.Classes;
|
||||
using Newtonsoft.Json;
|
||||
using System;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
@ -34,18 +35,22 @@ namespace NadekoBot.Modules.Music.Classes
|
||||
|
||||
public class SoundCloudVideo
|
||||
{
|
||||
public string Kind = "";
|
||||
public long Id = 0;
|
||||
public SoundCloudUser User = new SoundCloudUser();
|
||||
public string Title = "";
|
||||
public string Kind { get; set; } = "";
|
||||
public long Id { get; set; } = 0;
|
||||
public SoundCloudUser User { get; set; } = new SoundCloudUser();
|
||||
public string Title { get; set; } = "";
|
||||
[JsonIgnore]
|
||||
public string FullName => User.Name + " - " + Title;
|
||||
public bool Streamable = false;
|
||||
public bool Streamable { get; set; } = false;
|
||||
[JsonProperty("permalink_url")]
|
||||
public string TrackLink { get; set; } = "";
|
||||
[JsonIgnore]
|
||||
public string StreamLink => $"https://api.soundcloud.com/tracks/{Id}/stream?client_id={NadekoBot.Creds.SoundCloudClientID}";
|
||||
}
|
||||
public class SoundCloudUser
|
||||
{
|
||||
[Newtonsoft.Json.JsonProperty("username")]
|
||||
public string Name;
|
||||
public string Name { get; set; }
|
||||
}
|
||||
/*
|
||||
{"kind":"track",
|
||||
|
@ -6,6 +6,7 @@ using NadekoBot.DataModels;
|
||||
using NadekoBot.Extensions;
|
||||
using NadekoBot.Modules.Music.Classes;
|
||||
using NadekoBot.Modules.Permissions.Classes;
|
||||
using Newtonsoft.Json.Linq;
|
||||
using System;
|
||||
using System.Collections.Concurrent;
|
||||
using System.Collections.Generic;
|
||||
@ -19,7 +20,6 @@ namespace NadekoBot.Modules.Music
|
||||
{
|
||||
|
||||
public static ConcurrentDictionary<Server, MusicPlayer> MusicPlayers = new ConcurrentDictionary<Server, MusicPlayer>();
|
||||
public static ConcurrentDictionary<ulong, float> DefaultMusicVolumes = new ConcurrentDictionary<ulong, float>();
|
||||
|
||||
public MusicModule()
|
||||
{
|
||||
@ -53,30 +53,24 @@ namespace NadekoBot.Modules.Music
|
||||
cgb.CreateCommand("stop")
|
||||
.Alias("s")
|
||||
.Description("Stops the music and clears the playlist. Stays in the channel.\n**Usage**: `!m s`")
|
||||
.Do(async e =>
|
||||
.Do(e =>
|
||||
{
|
||||
await Task.Run(() =>
|
||||
{
|
||||
MusicPlayer musicPlayer;
|
||||
if (!MusicPlayers.TryGetValue(e.Server, out musicPlayer)) return;
|
||||
if (e.User.VoiceChannel == musicPlayer.PlaybackVoiceChannel)
|
||||
musicPlayer.Stop();
|
||||
}).ConfigureAwait(false);
|
||||
MusicPlayer musicPlayer;
|
||||
if (!MusicPlayers.TryGetValue(e.Server, out musicPlayer)) return;
|
||||
if (e.User.VoiceChannel == musicPlayer.PlaybackVoiceChannel)
|
||||
musicPlayer.Stop();
|
||||
});
|
||||
|
||||
cgb.CreateCommand("destroy")
|
||||
.Alias("d")
|
||||
.Description("Completely stops the music and unbinds the bot from the channel. " +
|
||||
"(may cause weird behaviour)\n**Usage**: `!m d`")
|
||||
.Do(async e =>
|
||||
.Do(e =>
|
||||
{
|
||||
await Task.Run(() =>
|
||||
{
|
||||
MusicPlayer musicPlayer;
|
||||
if (!MusicPlayers.TryRemove(e.Server, out musicPlayer)) return;
|
||||
if (e.User.VoiceChannel == musicPlayer.PlaybackVoiceChannel)
|
||||
musicPlayer.Destroy();
|
||||
}).ConfigureAwait(false);
|
||||
MusicPlayer musicPlayer;
|
||||
if (!MusicPlayers.TryRemove(e.Server, out musicPlayer)) return;
|
||||
if (e.User.VoiceChannel == musicPlayer.PlaybackVoiceChannel)
|
||||
musicPlayer.Destroy();
|
||||
});
|
||||
|
||||
cgb.CreateCommand("pause")
|
||||
@ -111,6 +105,21 @@ namespace NadekoBot.Modules.Music
|
||||
}
|
||||
});
|
||||
|
||||
//cgb.CreateCommand("soundcloudqueue")
|
||||
// .Alias("sq")
|
||||
// .Description("Queue a soundcloud song using keywords. Bot will join your voice channel." +
|
||||
// "**You must be in a voice channel**.\n**Usage**: `!m sq Dream Of Venice`")
|
||||
// .Parameter("query", ParameterType.Unparsed)
|
||||
// .Do(async e =>
|
||||
// {
|
||||
// await QueueSong(e.Channel, e.User.VoiceChannel, e.GetArg("query")).ConfigureAwait(false);
|
||||
// if (e.Server.CurrentUser.GetPermissions(e.Channel).ManageMessages)
|
||||
// {
|
||||
// await Task.Delay(10000).ConfigureAwait(false);
|
||||
// await e.Message.Delete().ConfigureAwait(false);
|
||||
// }
|
||||
// });
|
||||
|
||||
cgb.CreateCommand("listqueue")
|
||||
.Alias("lq")
|
||||
.Description("Lists 15 currently queued songs per page. Default page is 1.\n**Usage**: `!m lq` or `!m lq 2`")
|
||||
@ -200,7 +209,8 @@ namespace NadekoBot.Modules.Music
|
||||
await e.Channel.SendMessage("Volume number invalid.").ConfigureAwait(false);
|
||||
return;
|
||||
}
|
||||
DefaultMusicVolumes.AddOrUpdate(e.Server.Id, volume / 100, (key, newval) => volume / 100);
|
||||
var conf = SpecificConfigurations.Default.Of(e.Server.Id);
|
||||
conf.DefaultMusicVolume = volume / 100;
|
||||
await e.Channel.SendMessage($"🎵 `Default volume set to {volume}%`").ConfigureAwait(false);
|
||||
});
|
||||
|
||||
@ -302,6 +312,37 @@ namespace NadekoBot.Modules.Music
|
||||
await msg.Edit("🎵 `Playlist queue complete.`").ConfigureAwait(false);
|
||||
});
|
||||
|
||||
cgb.CreateCommand("soundcloudpl")
|
||||
.Alias("scpl")
|
||||
.Description("Queue a soundcloud playlist using a link. | `!m scpl https://soundcloud.com/saratology/sets/symphony`")
|
||||
.Parameter("pl", ParameterType.Unparsed)
|
||||
.Do(async e =>
|
||||
{
|
||||
var pl = e.GetArg("pl")?.Trim();
|
||||
|
||||
if (string.IsNullOrWhiteSpace(pl))
|
||||
return;
|
||||
|
||||
var scvids = JObject.Parse(await SearchHelper.GetResponseStringAsync($"http://api.soundcloud.com/resolve?url={pl}&client_id={NadekoBot.Creds.SoundCloudClientID}"))["tracks"].ToObject<SoundCloudVideo[]>();
|
||||
await QueueSong(e.Channel, e.User.VoiceChannel, scvids[0].TrackLink);
|
||||
|
||||
MusicPlayer mp;
|
||||
if (!MusicPlayers.TryGetValue(e.Server, out mp))
|
||||
return;
|
||||
|
||||
foreach (var svideo in scvids.Skip(1))
|
||||
{
|
||||
mp.AddSong(new Song(new Classes.SongInfo
|
||||
{
|
||||
Title = svideo.FullName,
|
||||
Provider = "SoundCloud",
|
||||
Uri = svideo.StreamLink,
|
||||
ProviderType = MusicType.Normal,
|
||||
Query = svideo.TrackLink,
|
||||
}));
|
||||
}
|
||||
});
|
||||
|
||||
cgb.CreateCommand("localplaylst")
|
||||
.Alias("lopl")
|
||||
.Description("Queues all songs from a directory. **Bot Owner Only!**\n**Usage**: `!m lopl C:/music/classical`")
|
||||
@ -430,7 +471,8 @@ namespace NadekoBot.Modules.Music
|
||||
|
||||
var s = playlist[n1 - 1];
|
||||
playlist.Insert(n2 - 1, s);
|
||||
playlist.RemoveAt(n1 - 1);
|
||||
var nn1 = n2 < n1 ? n1 : n1 - 1;
|
||||
playlist.RemoveAt(nn1);
|
||||
|
||||
await e.Channel.SendMessage($"🎵`Moved` {s.PrettyName} `from #{n1} to #{n2}`");
|
||||
|
||||
@ -609,6 +651,23 @@ namespace NadekoBot.Modules.Music
|
||||
e.Channel.SendMessage($"```js\n--- List of saved playlists ---\n\n" + string.Join("\n", result.Select(r => $"'{r.Name}-{r.Id}' by {r.Creator} ({r.SongCnt} songs)")) + $"\n\n --- Page {num} ---```");
|
||||
});
|
||||
|
||||
cgb.CreateCommand("deleteplaylist")
|
||||
.Alias("delpls")
|
||||
.Description("Deletes a saved playlist. Only if you made it or if you are the bot owner. | `!m delpls animu-5`")
|
||||
.Parameter("pl", ParameterType.Required)
|
||||
.Do(async e =>
|
||||
{
|
||||
var pl = e.GetArg("pl").Trim().Split('-')[1];
|
||||
if (string.IsNullOrWhiteSpace(pl))
|
||||
return;
|
||||
var plnum = int.Parse(pl);
|
||||
if (NadekoBot.IsOwner(e.User.Id))
|
||||
DbHandler.Instance.Delete<MusicPlaylist>(plnum);
|
||||
else
|
||||
DbHandler.Instance.DeleteWhere<MusicPlaylist>(mp => mp.Id == plnum && (long)e.User.Id == mp.CreatorId);
|
||||
await e.Channel.SendMessage("`Ok.` :ok:");
|
||||
});
|
||||
|
||||
cgb.CreateCommand("goto")
|
||||
.Description("Goes to a specific time in seconds in a song.")
|
||||
.Parameter("time")
|
||||
@ -659,10 +718,26 @@ namespace NadekoBot.Modules.Music
|
||||
return;
|
||||
await e.Channel.SendMessage($"🎶`Current song:` <{curSong.SongInfo.Query}>");
|
||||
});
|
||||
|
||||
cgb.CreateCommand("autoplay")
|
||||
.Alias("ap")
|
||||
.Description("Toggles autoplay - When the song is finished, automatically queue a related youtube song. (Works only for youtube songs and when queue is empty)")
|
||||
.Do(async e =>
|
||||
{
|
||||
|
||||
MusicPlayer musicPlayer;
|
||||
if (!MusicPlayers.TryGetValue(e.Server, out musicPlayer))
|
||||
return;
|
||||
|
||||
if (!musicPlayer.ToggleAutoplay())
|
||||
await e.Channel.SendMessage("🎶`Autoplay disabled.`");
|
||||
else
|
||||
await e.Channel.SendMessage("🎶`Autoplay enabled.`");
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
private async Task QueueSong(Channel textCh, Channel voiceCh, string query, bool silent = false, MusicType musicType = MusicType.Normal)
|
||||
public static async Task QueueSong(Channel textCh, Channel voiceCh, string query, bool silent = false, MusicType musicType = MusicType.Normal)
|
||||
{
|
||||
if (voiceCh == null || voiceCh.Server != textCh.Server)
|
||||
{
|
||||
@ -675,10 +750,7 @@ namespace NadekoBot.Modules.Music
|
||||
|
||||
var musicPlayer = MusicPlayers.GetOrAdd(textCh.Server, server =>
|
||||
{
|
||||
float? vol = null;
|
||||
float throwAway;
|
||||
if (DefaultMusicVolumes.TryGetValue(server.Id, out throwAway))
|
||||
vol = throwAway;
|
||||
float vol = SpecificConfigurations.Default.Of(server.Id).DefaultMusicVolume;
|
||||
var mp = new MusicPlayer(voiceCh, vol);
|
||||
|
||||
|
||||
@ -695,8 +767,15 @@ namespace NadekoBot.Modules.Music
|
||||
if (playingMessage != null)
|
||||
await playingMessage.Delete().ConfigureAwait(false);
|
||||
lastFinishedMessage = await textCh.SendMessage($"🎵`Finished`{song.PrettyName}").ConfigureAwait(false);
|
||||
if (mp.Autoplay && mp.Playlist.Count == 0 && song.SongInfo.Provider == "YouTube")
|
||||
{
|
||||
await QueueSong(textCh, voiceCh, await SearchHelper.GetRelatedVideoId(song.SongInfo.Query), silent, musicType).ConfigureAwait(false);
|
||||
}
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
Console.WriteLine(e);
|
||||
}
|
||||
catch { }
|
||||
}
|
||||
};
|
||||
mp.OnStarted += async (s, song) =>
|
||||
@ -719,22 +798,20 @@ namespace NadekoBot.Modules.Music
|
||||
return mp;
|
||||
});
|
||||
var resolvedSong = await Song.ResolveSong(query, musicType).ConfigureAwait(false);
|
||||
resolvedSong.MusicPlayer = musicPlayer;
|
||||
|
||||
musicPlayer.AddSong(resolvedSong);
|
||||
if (!silent)
|
||||
{
|
||||
var queuedMessage = await textCh.SendMessage($"🎵`Queued`{resolvedSong.PrettyName} **at** `#{musicPlayer.Playlist.Count}`").ConfigureAwait(false);
|
||||
#pragma warning disable CS4014 // Because this call is not awaited, execution of the current method continues before the call is completed
|
||||
Task.Run(async () =>
|
||||
{
|
||||
await Task.Delay(10000).ConfigureAwait(false);
|
||||
try
|
||||
{
|
||||
await queuedMessage.Delete().ConfigureAwait(false);
|
||||
}
|
||||
catch { }
|
||||
}).ConfigureAwait(false);
|
||||
{
|
||||
await Task.Delay(10000).ConfigureAwait(false);
|
||||
try
|
||||
{
|
||||
await queuedMessage.Delete().ConfigureAwait(false);
|
||||
}
|
||||
catch { }
|
||||
}).ConfigureAwait(false);
|
||||
#pragma warning restore CS4014 // Because this call is not awaited, execution of the current method continues before the call is completed
|
||||
}
|
||||
}
|
||||
|
@ -25,9 +25,9 @@ namespace NadekoBot.Modules.Permissions.Commands
|
||||
if (filterRegex.IsMatch(args.Message.RawText))
|
||||
{
|
||||
await args.Message.Delete().ConfigureAwait(false);
|
||||
IncidentsHandler.Add(args.Server.Id, $"User [{args.User.Name}/{args.User.Id}] posted " +
|
||||
$"INVITE LINK in [{args.Channel.Name}/{args.Channel.Id}] channel. " +
|
||||
$"Full message: [[{args.Message.Text}]]");
|
||||
IncidentsHandler.Add(args.Server.Id, args.Channel.Id, $"User [{args.User.Name}/{args.User.Id}] posted " +
|
||||
$"INVITE LINK in [{args.Channel.Name}/{args.Channel.Id}] channel.\n" +
|
||||
$"`Full message:` {args.Message.Text}");
|
||||
if (serverPerms.Verbose)
|
||||
await args.Channel.SendMessage($"{args.User.Mention} Invite links are not " +
|
||||
$"allowed on this channel.")
|
||||
|
@ -23,9 +23,9 @@ namespace NadekoBot.Modules.Permissions.Commands
|
||||
if (serverPerms.Words.Any(w => wordsInMessage.Contains(w)))
|
||||
{
|
||||
await args.Message.Delete().ConfigureAwait(false);
|
||||
IncidentsHandler.Add(args.Server.Id, $"User [{args.User.Name}/{args.User.Id}] posted " +
|
||||
$"BANNED WORD in [{args.Channel.Name}/{args.Channel.Id}] channel. " +
|
||||
$"Full message: [[{args.Message.Text}]]");
|
||||
IncidentsHandler.Add(args.Server.Id, args.Channel.Id, $"User [{args.User.Name}/{args.User.Id}] posted " +
|
||||
$"BANNED WORD in [{args.Channel.Name}/{args.Channel.Id}] channel.\n" +
|
||||
$"`Full message:` {args.Message.Text}");
|
||||
if (serverPerms.Verbose)
|
||||
await args.Channel.SendMessage($"{args.User.Mention} One or more of the words you used " +
|
||||
$"in that sentence are not allowed here.")
|
||||
|
46
NadekoBot/Modules/Searches/Commands/MemegenCommands.cs
Normal file
46
NadekoBot/Modules/Searches/Commands/MemegenCommands.cs
Normal file
@ -0,0 +1,46 @@
|
||||
using Discord.Commands;
|
||||
using NadekoBot.Classes;
|
||||
using Newtonsoft.Json;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
|
||||
namespace NadekoBot.Modules.Searches.Commands
|
||||
{
|
||||
class MemegenCommands : DiscordCommand
|
||||
{
|
||||
public MemegenCommands(DiscordModule module) : base(module)
|
||||
{
|
||||
}
|
||||
|
||||
internal override void Init(CommandGroupBuilder cgb)
|
||||
{
|
||||
cgb.CreateCommand(Prefix + "memelist")
|
||||
.Description("Pulls a list of memes you can use with `~memegen` from http://memegen.link/templates/")
|
||||
.Do(async e =>
|
||||
{
|
||||
int i = 0;
|
||||
await e.Channel.SendMessage("`List Of Commands:`\n```xl\n" +
|
||||
string.Join("\n", JsonConvert.DeserializeObject<Dictionary<string, string>>(await SearchHelper.GetResponseStringAsync("http://memegen.link/templates/"))
|
||||
.Select(kvp => Path.GetFileName(kvp.Value))
|
||||
.GroupBy(item => (i++) / 4)
|
||||
.Select(ig => string.Join("", ig.Select(el => $"{el,-17}"))))
|
||||
+ $"\n```").ConfigureAwait(false);
|
||||
});
|
||||
|
||||
cgb.CreateCommand(Prefix + "memegen")
|
||||
.Description("Generates a meme from memelist with top and bottom text. | `~memegen biw \"gets iced coffee\" \"in the winter\"`")
|
||||
.Parameter("meme", ParameterType.Required)
|
||||
.Parameter("toptext", ParameterType.Required)
|
||||
.Parameter("bottext", ParameterType.Required)
|
||||
.Do(async e =>
|
||||
{
|
||||
var meme = e.GetArg("meme");
|
||||
var top = Uri.EscapeDataString(e.GetArg("toptext").Replace(' ', '-'));
|
||||
var bot = Uri.EscapeDataString(e.GetArg("bottext").Replace(' ', '-'));
|
||||
await e.Channel.SendMessage($"http://memegen.link/{meme}/{top}/{bot}.jpg");
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
268
NadekoBot/Modules/Searches/Commands/OsuCommands.cs
Normal file
268
NadekoBot/Modules/Searches/Commands/OsuCommands.cs
Normal file
@ -0,0 +1,268 @@
|
||||
using Discord.Commands;
|
||||
using NadekoBot.Classes;
|
||||
using Newtonsoft.Json.Linq;
|
||||
using System;
|
||||
using System.IO;
|
||||
using System.Net;
|
||||
using System.Text.RegularExpressions;
|
||||
|
||||
namespace NadekoBot.Modules.Searches.Commands
|
||||
{
|
||||
internal class OsuCommands : DiscordCommand
|
||||
{
|
||||
public OsuCommands(DiscordModule module) : base(module)
|
||||
{
|
||||
}
|
||||
|
||||
internal override void Init(CommandGroupBuilder cgb)
|
||||
{
|
||||
cgb.CreateCommand(Module.Prefix + "osu")
|
||||
.Description("Shows osu stats for a player.\n**Usage**: `~osu Name` or `~osu Name taiko`")
|
||||
.Parameter("usr", ParameterType.Required)
|
||||
.Parameter("mode", ParameterType.Unparsed)
|
||||
.Do(async e =>
|
||||
{
|
||||
if (string.IsNullOrWhiteSpace(e.GetArg("usr")))
|
||||
return;
|
||||
|
||||
using (WebClient cl = new WebClient())
|
||||
{
|
||||
try
|
||||
{
|
||||
var m = 0;
|
||||
if (!string.IsNullOrWhiteSpace(e.GetArg("mode")))
|
||||
{
|
||||
m = ResolveGameMode(e.GetArg("mode"));
|
||||
}
|
||||
|
||||
cl.CachePolicy = new System.Net.Cache.RequestCachePolicy(System.Net.Cache.RequestCacheLevel.NoCacheNoStore);
|
||||
cl.Headers.Add(HttpRequestHeader.UserAgent, "Mozilla/5.0 (Windows NT 6.2; Win64; x64)");
|
||||
cl.DownloadDataAsync(new Uri($"http://lemmmy.pw/osusig/sig.php?uname={ e.GetArg("usr") }&flagshadow&xpbar&xpbarhex&pp=2&mode={m}"));
|
||||
cl.DownloadDataCompleted += async (s, cle) =>
|
||||
{
|
||||
try
|
||||
{
|
||||
await e.Channel.SendFile($"{e.GetArg("usr")}.png", new MemoryStream(cle.Result)).ConfigureAwait(false);
|
||||
await e.Channel.SendMessage($"`Profile Link:`https://osu.ppy.sh/u/{Uri.EscapeDataString(e.GetArg("usr"))}\n`Image provided by https://lemmmy.pw/osusig`").ConfigureAwait(false);
|
||||
}
|
||||
catch { }
|
||||
};
|
||||
}
|
||||
catch
|
||||
{
|
||||
await e.Channel.SendMessage("💢 Failed retrieving osu signature :\\").ConfigureAwait(false);
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
cgb.CreateCommand(Module.Prefix + "osu b")
|
||||
.Description("Shows information about an osu beatmap.\n**Usage**:~osu b https://osu.ppy.sh/s/127712")
|
||||
.Parameter("map", ParameterType.Unparsed)
|
||||
.Do(async e =>
|
||||
{
|
||||
if (string.IsNullOrWhiteSpace(NadekoBot.Creds.OsuAPIKey))
|
||||
{
|
||||
await e.Channel.SendMessage("💢 An osu! API key is required.").ConfigureAwait(false);
|
||||
return;
|
||||
}
|
||||
|
||||
if (string.IsNullOrWhiteSpace(e.GetArg("map")))
|
||||
return;
|
||||
|
||||
try
|
||||
{
|
||||
var mapId = ResolveMap(e.GetArg("map"));
|
||||
var reqString = $"https://osu.ppy.sh/api/get_beatmaps?k={NadekoBot.Creds.OsuAPIKey}&{mapId}";
|
||||
var obj = JArray.Parse(await SearchHelper.GetResponseStringAsync(reqString).ConfigureAwait(false))[0];
|
||||
var sb = new System.Text.StringBuilder();
|
||||
var starRating = Math.Round(Double.Parse($"{obj["difficultyrating"]}"), 2);
|
||||
var time = TimeSpan.FromSeconds(Double.Parse($"{obj["total_length"]}")).ToString(@"mm\:ss");
|
||||
sb.AppendLine($"{obj["artist"]} - {obj["title"]}, mapped by {obj["creator"]}. https://osu.ppy.sh/s/{obj["beatmapset_id"]}");
|
||||
sb.AppendLine($"{starRating} stars, {obj["bpm"]} BPM | AR{obj["diff_approach"]}, CS{obj["diff_size"]}, OD{obj["diff_overall"]} | Length: {time}");
|
||||
await e.Channel.SendMessage(sb.ToString()).ConfigureAwait(false);
|
||||
}
|
||||
catch
|
||||
{
|
||||
await e.Channel.SendMessage("Something went wrong.");
|
||||
}
|
||||
});
|
||||
|
||||
cgb.CreateCommand(Module.Prefix + "osu top5")
|
||||
.Description("Displays a user's top 5 plays. \n**Usage**:~osu top5 Name")
|
||||
.Parameter("usr", ParameterType.Required)
|
||||
.Parameter("mode", ParameterType.Unparsed)
|
||||
.Do(async e =>
|
||||
{
|
||||
if (string.IsNullOrWhiteSpace(NadekoBot.Creds.OsuAPIKey))
|
||||
{
|
||||
await e.Channel.SendMessage("💢 An osu! API key is required.").ConfigureAwait(false);
|
||||
return;
|
||||
}
|
||||
|
||||
if (string.IsNullOrWhiteSpace(e.GetArg("usr")))
|
||||
{
|
||||
await e.Channel.SendMessage("💢 Please provide a username.").ConfigureAwait(false);
|
||||
return;
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
var m = 0;
|
||||
if (!string.IsNullOrWhiteSpace(e.GetArg("mode")))
|
||||
{
|
||||
m = ResolveGameMode(e.GetArg("mode"));
|
||||
}
|
||||
|
||||
var reqString = $"https://osu.ppy.sh/api/get_user_best?k={NadekoBot.Creds.OsuAPIKey}&u={Uri.EscapeDataString(e.GetArg("usr"))}&type=string&limit=5&m={m}";
|
||||
var obj = JArray.Parse(await SearchHelper.GetResponseStringAsync(reqString).ConfigureAwait(false));
|
||||
var sb = new System.Text.StringBuilder($"`Top 5 plays for {e.GetArg("usr")}:`\n```xl" + Environment.NewLine);
|
||||
foreach (var item in obj)
|
||||
{
|
||||
var mapReqString = $"https://osu.ppy.sh/api/get_beatmaps?k={NadekoBot.Creds.OsuAPIKey}&b={item["beatmap_id"]}";
|
||||
var map = JArray.Parse(await SearchHelper.GetResponseStringAsync(mapReqString).ConfigureAwait(false))[0];
|
||||
var pp = Math.Round(Double.Parse($"{item["pp"]}"), 2);
|
||||
var acc = CalculateAcc(item, m);
|
||||
var mods = ResolveMods(Int32.Parse($"{item["enabled_mods"]}"));
|
||||
if (mods != "+")
|
||||
sb.AppendLine($"{pp + "pp",-7} | {acc + "%",-7} | {map["artist"] + "-" + map["title"] + " (" + map["version"],-40}) | **{mods,-10}** | /b/{item["beatmap_id"]}");
|
||||
else
|
||||
sb.AppendLine($"{pp + "pp",-7} | {acc + "%",-7} | {map["artist"] + "-" + map["title"] + " (" + map["version"],-40}) | /b/{item["beatmap_id"]}");
|
||||
}
|
||||
sb.Append("```");
|
||||
await e.Channel.SendMessage(sb.ToString()).ConfigureAwait(false);
|
||||
}
|
||||
catch
|
||||
{
|
||||
await e.Channel.SendMessage("Something went wrong.");
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
//https://osu.ppy.sh/wiki/Accuracy
|
||||
private static Double CalculateAcc(JToken play, int mode)
|
||||
{
|
||||
if (mode == 0)
|
||||
{
|
||||
var hitPoints = Double.Parse($"{play["count50"]}") * 50 + Double.Parse($"{play["count100"]}") * 100 + Double.Parse($"{play["count300"]}") * 300;
|
||||
var totalHits = Double.Parse($"{play["count50"]}") + Double.Parse($"{play["count100"]}") + Double.Parse($"{play["count300"]}") + Double.Parse($"{play["countmiss"]}");
|
||||
totalHits *= 300;
|
||||
return Math.Round(hitPoints / totalHits * 100, 2);
|
||||
}
|
||||
else if (mode == 1)
|
||||
{
|
||||
var hitPoints = Double.Parse($"{play["countmiss"]}") * 0 + Double.Parse($"{play["count100"]}") * 0.5 + Double.Parse($"{play["count300"]}") * 1;
|
||||
var totalHits = Double.Parse($"{play["countmiss"]}") + Double.Parse($"{play["count100"]}") + Double.Parse($"{play["count300"]}");
|
||||
hitPoints *= 300;
|
||||
totalHits *= 300;
|
||||
return Math.Round(hitPoints / totalHits * 100, 2);
|
||||
}
|
||||
else if (mode == 2)
|
||||
{
|
||||
var fruitsCaught = Double.Parse($"{play["count50"]}") + Double.Parse($"{play["count100"]}") + Double.Parse($"{play["count300"]}");
|
||||
var totalFruits = Double.Parse($"{play["countmiss"]}") + Double.Parse($"{play["count50"]}") + Double.Parse($"{play["count100"]}") + Double.Parse($"{play["count300"]}") + Double.Parse($"{play["countkatu"]}");
|
||||
return Math.Round(fruitsCaught / totalFruits * 100, 2);
|
||||
}
|
||||
else
|
||||
{
|
||||
var hitPoints = Double.Parse($"{play["count50"]}") * 50 + Double.Parse($"{play["count100"]}") * 100 + Double.Parse($"{play["countkatu"]}") * 200 + (Double.Parse($"{play["count300"]}") + Double.Parse($"{play["countgeki"]}")) * 300;
|
||||
var totalHits = Double.Parse($"{play["countmiss"]}") + Double.Parse($"{play["count50"]}") + Double.Parse($"{play["count100"]}") + Double.Parse($"{play["countkatu"]}") + Double.Parse($"{play["count300"]}") + Double.Parse($"{play["countgeki"]}");
|
||||
totalHits *= 300;
|
||||
return Math.Round(hitPoints / totalHits * 100, 2);
|
||||
}
|
||||
}
|
||||
|
||||
private static string ResolveMap(string mapLink)
|
||||
{
|
||||
Match s = new Regex(@"osu.ppy.sh\/s\/", RegexOptions.IgnoreCase).Match(mapLink);
|
||||
Match b = new Regex(@"osu.ppy.sh\/b\/", RegexOptions.IgnoreCase).Match(mapLink);
|
||||
Match p = new Regex(@"osu.ppy.sh\/p\/", RegexOptions.IgnoreCase).Match(mapLink);
|
||||
Match m = new Regex(@"&m=", RegexOptions.IgnoreCase).Match(mapLink);
|
||||
if (s.Success)
|
||||
{
|
||||
var mapId = mapLink.Substring(mapLink.IndexOf("/s/") + 3);
|
||||
return $"s={mapId}";
|
||||
}
|
||||
else if (b.Success)
|
||||
{
|
||||
if (m.Success)
|
||||
return $"b={mapLink.Substring(mapLink.IndexOf("/b/") + 3, mapLink.IndexOf("&m") - (mapLink.IndexOf("/b/") + 3))}";
|
||||
else
|
||||
return $"b={mapLink.Substring(mapLink.IndexOf("/b/") + 3)}";
|
||||
}
|
||||
else if (p.Success)
|
||||
{
|
||||
if (m.Success)
|
||||
return $"b={mapLink.Substring(mapLink.IndexOf("?b=") + 3, mapLink.IndexOf("&m") - (mapLink.IndexOf("?b=") + 3))}";
|
||||
else
|
||||
return $"b={mapLink.Substring(mapLink.IndexOf("?b=") + 3)}";
|
||||
}
|
||||
else
|
||||
{
|
||||
return $"s={mapLink}"; //just a default incase an ID number was provided by itself (non-url)?
|
||||
}
|
||||
}
|
||||
|
||||
private static int ResolveGameMode(string mode)
|
||||
{
|
||||
switch (mode.ToLower())
|
||||
{
|
||||
case "std":
|
||||
case "standard":
|
||||
return 0;
|
||||
case "taiko":
|
||||
return 1;
|
||||
case "ctb":
|
||||
case "catchthebeat":
|
||||
return 2;
|
||||
case "mania":
|
||||
case "osu!mania":
|
||||
return 3;
|
||||
default:
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
//https://github.com/ppy/osu-api/wiki#mods
|
||||
private static string ResolveMods(int mods)
|
||||
{
|
||||
var modString = $"+";
|
||||
|
||||
if (IsBitSet(mods, 0))
|
||||
modString += "NF";
|
||||
if (IsBitSet(mods, 1))
|
||||
modString += "EZ";
|
||||
if (IsBitSet(mods, 8))
|
||||
modString += "HT";
|
||||
|
||||
if (IsBitSet(mods, 3))
|
||||
modString += "HD";
|
||||
if (IsBitSet(mods, 4))
|
||||
modString += "HR";
|
||||
if (IsBitSet(mods, 6) && !IsBitSet(mods, 9))
|
||||
modString += "DT";
|
||||
if (IsBitSet(mods, 9))
|
||||
modString += "NC";
|
||||
if (IsBitSet(mods, 10))
|
||||
modString += "FL";
|
||||
|
||||
if (IsBitSet(mods, 5))
|
||||
modString += "SD";
|
||||
if (IsBitSet(mods, 14))
|
||||
modString += "PF";
|
||||
|
||||
if (IsBitSet(mods, 7))
|
||||
modString += "RX";
|
||||
if (IsBitSet(mods, 11))
|
||||
modString += "AT";
|
||||
if (IsBitSet(mods, 12))
|
||||
modString += "SO";
|
||||
return modString;
|
||||
}
|
||||
|
||||
private static bool IsBitSet(int mods, int pos)
|
||||
{
|
||||
return (mods & (1 << pos)) != 0;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
116
NadekoBot/Modules/Searches/Commands/PokemonSearchCommands.cs
Normal file
116
NadekoBot/Modules/Searches/Commands/PokemonSearchCommands.cs
Normal file
@ -0,0 +1,116 @@
|
||||
using Discord.Commands;
|
||||
using NadekoBot.Classes;
|
||||
using Newtonsoft.Json;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
|
||||
namespace NadekoBot.Modules.Searches.Commands
|
||||
{
|
||||
class PokemonSearchCommands : DiscordCommand
|
||||
{
|
||||
private static Dictionary<string, SearchPokemon> pokemons;
|
||||
private static Dictionary<string, SearchPokemonAbility> pokemonAbilities;
|
||||
|
||||
public PokemonSearchCommands(DiscordModule module) : base(module)
|
||||
{
|
||||
|
||||
pokemons = JsonConvert.DeserializeObject<Dictionary<string, SearchPokemon>>(File.ReadAllText("data/pokemon/pokemon_list.json"));
|
||||
pokemonAbilities = JsonConvert.DeserializeObject<Dictionary<string, SearchPokemonAbility>>(File.ReadAllText("data/pokemon/pokemon_abilities.json"));
|
||||
}
|
||||
|
||||
internal override void Init(CommandGroupBuilder cgb)
|
||||
{
|
||||
cgb.CreateCommand(Prefix + "pokemon")
|
||||
.Alias(Prefix + "poke")
|
||||
.Description("Searches for a pokemon.")
|
||||
.Parameter("pokemon", ParameterType.Unparsed)
|
||||
.Do(async e =>
|
||||
{
|
||||
var pok = e.GetArg("pokemon")?.Trim().ToUpperInvariant();
|
||||
if (string.IsNullOrWhiteSpace(pok))
|
||||
return;
|
||||
|
||||
foreach (var kvp in pokemons)
|
||||
{
|
||||
if (kvp.Key.ToUpperInvariant() == pok.ToUpperInvariant())
|
||||
{
|
||||
await e.Channel.SendMessage($"`Stats for \"{kvp.Key}\" pokemon:`\n{kvp.Value}");
|
||||
return;
|
||||
}
|
||||
}
|
||||
await e.Channel.SendMessage("`No pokemon found.`");
|
||||
});
|
||||
|
||||
cgb.CreateCommand(Prefix + "pokemonability")
|
||||
.Alias(Prefix + "pokab")
|
||||
.Description("Searches for a pokemon ability.")
|
||||
.Parameter("abil", ParameterType.Unparsed)
|
||||
.Do(async e =>
|
||||
{
|
||||
var ab = e.GetArg("abil")?.Trim().ToUpperInvariant();
|
||||
if (string.IsNullOrWhiteSpace(ab))
|
||||
return;
|
||||
foreach (var kvp in pokemonAbilities)
|
||||
{
|
||||
if (kvp.Key.ToUpperInvariant() == ab)
|
||||
{
|
||||
await e.Channel.SendMessage($"`Info for \"{kvp.Key}\" ability:`\n{kvp.Value}");
|
||||
return;
|
||||
}
|
||||
}
|
||||
await e.Channel.SendMessage("`No ability found.`");
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
public class SearchPokemon
|
||||
{
|
||||
public class GenderRatioClass
|
||||
{
|
||||
public float M { get; set; }
|
||||
public float F { get; set; }
|
||||
}
|
||||
public class BaseStatsClass
|
||||
{
|
||||
public int HP { get; set; }
|
||||
public int ATK { get; set; }
|
||||
public int DEF { get; set; }
|
||||
public int SPA { get; set; }
|
||||
public int SPD { get; set; }
|
||||
public int SPE { get; set; }
|
||||
|
||||
public override string ToString() => $@"
|
||||
**HP:** {HP,-4} **ATK:** {ATK,-4} **DEF:** {DEF,-4}
|
||||
**SPA:** {SPA,-4} **SPD:** {SPD,-4} **SPE:** {SPE,-4}";
|
||||
}
|
||||
public int Id { get; set; }
|
||||
public string Species { get; set; }
|
||||
public string[] Types { get; set; }
|
||||
public GenderRatioClass GenderRatio { get; set; }
|
||||
public BaseStatsClass BaseStats { get; set; }
|
||||
public Dictionary<string, string> Abilities { get; set; }
|
||||
public float HeightM { get; set; }
|
||||
public float WeightKg { get; set; }
|
||||
public string Color { get; set; }
|
||||
public string[] Evos { get; set; }
|
||||
public string[] EggGroups { get; set; }
|
||||
|
||||
public override string ToString() => $@"`Name:` {Species}
|
||||
`Types:` {string.Join(", ", Types)}
|
||||
`Stats:` {BaseStats}
|
||||
`Height:` {HeightM,4}m `Weight:` {WeightKg}kg
|
||||
`Abilities:` {string.Join(", ", Abilities.Values)}";
|
||||
|
||||
}
|
||||
|
||||
public class SearchPokemonAbility
|
||||
{
|
||||
public string Desc { get; set; }
|
||||
public string Name { get; set; }
|
||||
public float Rating { get; set; }
|
||||
|
||||
public override string ToString() => $@"`Name:` : {Name}
|
||||
`Rating:` {Rating}
|
||||
`Description:` {Desc}";
|
||||
}
|
||||
}
|
@ -73,7 +73,7 @@ namespace NadekoBot.Modules.Searches.Commands
|
||||
checkTimer.Start();
|
||||
}
|
||||
|
||||
private async Task<Tuple<bool, string>> GetStreamStatus(StreamNotificationConfig stream)
|
||||
private async Task<Tuple<bool, string>> GetStreamStatus(StreamNotificationConfig stream, bool checkCache = true)
|
||||
{
|
||||
bool isLive;
|
||||
string response;
|
||||
@ -83,7 +83,7 @@ namespace NadekoBot.Modules.Searches.Commands
|
||||
{
|
||||
case StreamNotificationConfig.StreamType.Hitbox:
|
||||
var hitboxUrl = $"https://api.hitbox.tv/media/status/{stream.Username}";
|
||||
if (cachedStatuses.TryGetValue(hitboxUrl, out result))
|
||||
if (checkCache && cachedStatuses.TryGetValue(hitboxUrl, out result))
|
||||
return result;
|
||||
response = await SearchHelper.GetResponseStringAsync(hitboxUrl).ConfigureAwait(false);
|
||||
data = JObject.Parse(response);
|
||||
@ -93,7 +93,7 @@ namespace NadekoBot.Modules.Searches.Commands
|
||||
return result;
|
||||
case StreamNotificationConfig.StreamType.Twitch:
|
||||
var twitchUrl = $"https://api.twitch.tv/kraken/streams/{Uri.EscapeUriString(stream.Username)}";
|
||||
if (cachedStatuses.TryGetValue(twitchUrl, out result))
|
||||
if (checkCache && cachedStatuses.TryGetValue(twitchUrl, out result))
|
||||
return result;
|
||||
response = await SearchHelper.GetResponseStringAsync(twitchUrl).ConfigureAwait(false);
|
||||
data = JObject.Parse(response);
|
||||
@ -103,7 +103,7 @@ namespace NadekoBot.Modules.Searches.Commands
|
||||
return result;
|
||||
case StreamNotificationConfig.StreamType.Beam:
|
||||
var beamUrl = $"https://beam.pro/api/v1/channels/{stream.Username}";
|
||||
if (cachedStatuses.TryGetValue(beamUrl, out result))
|
||||
if (checkCache && cachedStatuses.TryGetValue(beamUrl, out result))
|
||||
return result;
|
||||
response = await SearchHelper.GetResponseStringAsync(beamUrl).ConfigureAwait(false);
|
||||
data = JObject.Parse(response);
|
||||
@ -143,6 +143,93 @@ namespace NadekoBot.Modules.Searches.Commands
|
||||
.Parameter("username", ParameterType.Unparsed)
|
||||
.Do(TrackStream(StreamNotificationConfig.StreamType.Beam));
|
||||
|
||||
cgb.CreateCommand(Module.Prefix + "checkhitbox")
|
||||
.Alias(Module.Prefix + "chhb")
|
||||
.Description("Checks if a certain user is streaming on the hitbox platform." +
|
||||
"\n**Usage**: ~chhb SomeStreamer")
|
||||
.Parameter("username", ParameterType.Unparsed)
|
||||
.AddCheck(SimpleCheckers.ManageServer())
|
||||
.Do(async e =>
|
||||
{
|
||||
var stream = e.GetArg("username")?.Trim();
|
||||
if (string.IsNullOrWhiteSpace(stream))
|
||||
return;
|
||||
try
|
||||
{
|
||||
var streamStatus = (await GetStreamStatus(new StreamNotificationConfig
|
||||
{
|
||||
Username = stream,
|
||||
Type = StreamNotificationConfig.StreamType.Hitbox
|
||||
}));
|
||||
if (streamStatus.Item1)
|
||||
{
|
||||
await e.Channel.SendMessage($"`Streamer {streamStatus.Item2} is online.`");
|
||||
}
|
||||
}
|
||||
catch
|
||||
{
|
||||
await e.Channel.SendMessage("No channel found.");
|
||||
}
|
||||
});
|
||||
|
||||
cgb.CreateCommand(Module.Prefix + "checktwitch")
|
||||
.Alias(Module.Prefix + "chtw")
|
||||
.Description("Checks if a certain user is streaming on the twitch platform." +
|
||||
"\n**Usage**: ~chtw SomeStreamer")
|
||||
.AddCheck(SimpleCheckers.ManageServer())
|
||||
.Parameter("username", ParameterType.Unparsed)
|
||||
.Do(async e =>
|
||||
{
|
||||
var stream = e.GetArg("username")?.Trim();
|
||||
if (string.IsNullOrWhiteSpace(stream))
|
||||
return;
|
||||
try
|
||||
{
|
||||
var streamStatus = (await GetStreamStatus(new StreamNotificationConfig
|
||||
{
|
||||
Username = stream,
|
||||
Type = StreamNotificationConfig.StreamType.Twitch
|
||||
}));
|
||||
if (streamStatus.Item1)
|
||||
{
|
||||
await e.Channel.SendMessage($"`Streamer {streamStatus.Item2} is online.`");
|
||||
}
|
||||
}
|
||||
catch
|
||||
{
|
||||
await e.Channel.SendMessage("No channel found.");
|
||||
}
|
||||
});
|
||||
|
||||
cgb.CreateCommand(Module.Prefix + "checkbeam")
|
||||
.Alias(Module.Prefix + "chbm")
|
||||
.Description("Checks if a certain user is streaming on the beam platform." +
|
||||
"\n**Usage**: ~chbm SomeStreamer")
|
||||
.AddCheck(SimpleCheckers.ManageServer())
|
||||
.Parameter("username", ParameterType.Unparsed)
|
||||
.Do(async e =>
|
||||
{
|
||||
var stream = e.GetArg("username")?.Trim();
|
||||
if (string.IsNullOrWhiteSpace(stream))
|
||||
return;
|
||||
try
|
||||
{
|
||||
var streamStatus = (await GetStreamStatus(new StreamNotificationConfig
|
||||
{
|
||||
Username = stream,
|
||||
Type = StreamNotificationConfig.StreamType.Beam
|
||||
}));
|
||||
if (streamStatus.Item1)
|
||||
{
|
||||
await e.Channel.SendMessage($"`Streamer {streamStatus.Item2} is online.`");
|
||||
}
|
||||
}
|
||||
catch
|
||||
{
|
||||
await e.Channel.SendMessage("No channel found.");
|
||||
}
|
||||
});
|
||||
|
||||
cgb.CreateCommand(Module.Prefix + "removestream")
|
||||
.Alias(Module.Prefix + "rms")
|
||||
.Description("Removes notifications of a certain streamer on this channel." +
|
||||
|
@ -14,7 +14,6 @@ using System.Collections.Generic;
|
||||
using System.Drawing;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Net;
|
||||
using System.Net.Http;
|
||||
|
||||
namespace NadekoBot.Modules.Searches
|
||||
@ -30,6 +29,9 @@ namespace NadekoBot.Modules.Searches
|
||||
commands.Add(new RedditCommand(this));
|
||||
commands.Add(new WowJokeCommand(this));
|
||||
commands.Add(new CalcCommand(this));
|
||||
commands.Add(new OsuCommands(this));
|
||||
commands.Add(new PokemonSearchCommands(this));
|
||||
commands.Add(new MemegenCommands(this));
|
||||
rng = new Random();
|
||||
}
|
||||
|
||||
@ -183,29 +185,30 @@ $@"🌍 **Weather for** 【{obj["target"]}】
|
||||
cgb.CreateCommand(Prefix + "ir")
|
||||
.Description("Pulls a random image using a search parameter.\n**Usage**: ~ir cute kitten")
|
||||
.Parameter("query", ParameterType.Unparsed)
|
||||
.Do(async e =>
|
||||
{
|
||||
if (string.IsNullOrWhiteSpace(e.GetArg("query")))
|
||||
return;
|
||||
try
|
||||
{
|
||||
var reqString = $"https://www.googleapis.com/customsearch/v1?q={Uri.EscapeDataString(e.GetArg("query"))}&cx=018084019232060951019%3Ahs5piey28-e&num=50&searchType=image&start={ rng.Next(1, 50) }&fields=items%2Flink&key={NadekoBot.Creds.GoogleAPIKey}";
|
||||
var obj = JObject.Parse(await SearchHelper.GetResponseStringAsync(reqString).ConfigureAwait(false));
|
||||
var items = obj["items"] as JArray;
|
||||
await e.Channel.SendMessage(items[rng.Next(0, items.Count)]["link"].ToString()).ConfigureAwait(false);
|
||||
}
|
||||
catch (HttpRequestException exception)
|
||||
{
|
||||
if (exception.Message.Contains("403 (Forbidden)"))
|
||||
{
|
||||
await e.Channel.SendMessage("Daily limit reached!");
|
||||
}
|
||||
else
|
||||
{
|
||||
await e.Channel.SendMessage("Something went wrong.");
|
||||
}
|
||||
}
|
||||
});
|
||||
.Do(async e =>
|
||||
{
|
||||
if (string.IsNullOrWhiteSpace(e.GetArg("query")))
|
||||
return;
|
||||
try
|
||||
{
|
||||
var reqString = $"https://www.googleapis.com/customsearch/v1?q={Uri.EscapeDataString(e.GetArg("query"))}&cx=018084019232060951019%3Ahs5piey28-e&num=1&searchType=image&start={ rng.Next(1, 50) }&fields=items%2Flink&key={NadekoBot.Creds.GoogleAPIKey}";
|
||||
var obj = JObject.Parse(await SearchHelper.GetResponseStringAsync(reqString).ConfigureAwait(false));
|
||||
var items = obj["items"] as JArray;
|
||||
await e.Channel.SendMessage(items[0]["link"].ToString()).ConfigureAwait(false);
|
||||
}
|
||||
catch (HttpRequestException exception)
|
||||
{
|
||||
if (exception.Message.Contains("403 (Forbidden)"))
|
||||
{
|
||||
await e.Channel.SendMessage("Daily limit reached!");
|
||||
}
|
||||
else
|
||||
{
|
||||
await e.Channel.SendMessage("Something went wrong.");
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
cgb.CreateCommand(Prefix + "lmgtfy")
|
||||
.Description("Google something for an idiot.")
|
||||
.Parameter("ffs", ParameterType.Unparsed)
|
||||
@ -257,38 +260,6 @@ $@"🌍 **Weather for** 【{obj["target"]}】
|
||||
}
|
||||
});
|
||||
|
||||
cgb.CreateCommand(Prefix + "osu")
|
||||
.Description("Shows osu stats for a player.\n**Usage**:~osu Name")
|
||||
.Parameter("usr", ParameterType.Unparsed)
|
||||
.Do(async e =>
|
||||
{
|
||||
if (string.IsNullOrWhiteSpace(e.GetArg("usr")))
|
||||
return;
|
||||
|
||||
using (WebClient cl = new WebClient())
|
||||
{
|
||||
try
|
||||
{
|
||||
cl.CachePolicy = new System.Net.Cache.RequestCachePolicy(System.Net.Cache.RequestCacheLevel.NoCacheNoStore);
|
||||
cl.Headers.Add(HttpRequestHeader.UserAgent, "Mozilla/5.0 (Windows NT 6.2; Win64; x64)");
|
||||
cl.DownloadDataAsync(new Uri($"http://lemmmy.pw/osusig/sig.php?uname={ e.GetArg("usr") }&flagshadow&xpbar&xpbarhex&pp=2"));
|
||||
cl.DownloadDataCompleted += async (s, cle) =>
|
||||
{
|
||||
try
|
||||
{
|
||||
await e.Channel.SendFile($"{e.GetArg("usr")}.png", new MemoryStream(cle.Result)).ConfigureAwait(false);
|
||||
await e.Channel.SendMessage($"`Profile Link:`https://osu.ppy.sh/u/{Uri.EscapeDataString(e.GetArg("usr"))}\n`Image provided by https://lemmmy.pw/osusig`").ConfigureAwait(false);
|
||||
}
|
||||
catch { }
|
||||
};
|
||||
}
|
||||
catch
|
||||
{
|
||||
await e.Channel.SendMessage("💢 Failed retrieving osu signature :\\").ConfigureAwait(false);
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
cgb.CreateCommand(Prefix + "ud")
|
||||
.Description("Searches Urban Dictionary for a word.\n**Usage**:~ud Pineapple")
|
||||
.Parameter("query", ParameterType.Unparsed)
|
||||
@ -505,6 +476,22 @@ $@"🌍 **Weather for** 【{obj["target"]}】
|
||||
Console.WriteLine(ex);
|
||||
}
|
||||
});
|
||||
|
||||
cgb.CreateCommand(Prefix + "av")
|
||||
.Alias(Prefix + "avatar")
|
||||
.Parameter("mention", ParameterType.Required)
|
||||
.Description("Shows a mentioned person's avatar.\n**Usage**: ~av @X")
|
||||
.Do(async e =>
|
||||
{
|
||||
var usr = e.Channel.FindUsers(e.GetArg("mention")).FirstOrDefault();
|
||||
if (usr == null)
|
||||
{
|
||||
await e.Channel.SendMessage("Invalid user specified.").ConfigureAwait(false);
|
||||
return;
|
||||
}
|
||||
await e.Channel.SendMessage(await usr.AvatarUrl.ShortenUrl()).ConfigureAwait(false);
|
||||
});
|
||||
|
||||
});
|
||||
}
|
||||
}
|
||||
|
@ -2,10 +2,12 @@
|
||||
// License: Code Project Open License
|
||||
// http://www.codeproject.com/info/cpol10.aspx
|
||||
|
||||
using Newtonsoft.Json.Linq;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Net;
|
||||
using System.Net.Http;
|
||||
using System.Threading.Tasks;
|
||||
using System.Web;
|
||||
|
||||
namespace NadekoBot.Modules.Translator.Helpers
|
||||
@ -26,32 +28,6 @@ namespace NadekoBot.Modules.Translator.Helpers
|
||||
return GoogleTranslator._languageModeMap.Keys.OrderBy(p => p);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the time taken to perform the translation.
|
||||
/// </summary>
|
||||
public TimeSpan TranslationTime {
|
||||
get;
|
||||
private set;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the url used to speak the translation.
|
||||
/// </summary>
|
||||
/// <value>The url used to speak the translation.</value>
|
||||
public string TranslationSpeechUrl {
|
||||
get;
|
||||
private set;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the error.
|
||||
/// </summary>
|
||||
public Exception Error {
|
||||
get;
|
||||
private set;
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Public methods
|
||||
@ -63,92 +39,28 @@ namespace NadekoBot.Modules.Translator.Helpers
|
||||
/// <param name="sourceLanguage">The source language.</param>
|
||||
/// <param name="targetLanguage">The target language.</param>
|
||||
/// <returns>The translation.</returns>
|
||||
public string Translate
|
||||
public async Task<string> Translate
|
||||
(string sourceText,
|
||||
string sourceLanguage,
|
||||
string targetLanguage)
|
||||
{
|
||||
// Initialize
|
||||
this.Error = null;
|
||||
this.TranslationSpeechUrl = null;
|
||||
this.TranslationTime = TimeSpan.Zero;
|
||||
DateTime tmStart = DateTime.Now;
|
||||
string translation = string.Empty;
|
||||
string text = string.Empty;
|
||||
|
||||
try
|
||||
|
||||
// Download translation
|
||||
string url = string.Format("https://translate.googleapis.com/translate_a/single?client=gtx&sl={0}&tl={1}&dt=t&q={2}",
|
||||
GoogleTranslator.LanguageEnumToIdentifier(sourceLanguage),
|
||||
GoogleTranslator.LanguageEnumToIdentifier(targetLanguage),
|
||||
HttpUtility.UrlEncode(sourceText));
|
||||
using (HttpClient http = new HttpClient())
|
||||
{
|
||||
// Download translation
|
||||
string url = string.Format("https://translate.googleapis.com/translate_a/single?client=gtx&sl={0}&tl={1}&dt=t&q={2}",
|
||||
GoogleTranslator.LanguageEnumToIdentifier(sourceLanguage),
|
||||
GoogleTranslator.LanguageEnumToIdentifier(targetLanguage),
|
||||
HttpUtility.UrlEncode(sourceText));
|
||||
using (WebClient wc = new WebClient())
|
||||
{
|
||||
wc.Headers.Add("user-agent", "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/41.0.2228.0 Safari/537.36");
|
||||
text = wc.DownloadString(url);
|
||||
}
|
||||
|
||||
// Get translated text
|
||||
// Get phrase collection
|
||||
// string text = File.ReadAllText(outputFile);
|
||||
int index = text.IndexOf(string.Format(",,\"{0}\"", GoogleTranslator.LanguageEnumToIdentifier(sourceLanguage)));
|
||||
if (index == -1)
|
||||
{
|
||||
// Translation of single word
|
||||
int startQuote = text.IndexOf('\"');
|
||||
if (startQuote != -1)
|
||||
{
|
||||
int endQuote = text.IndexOf('\"', startQuote + 1);
|
||||
if (endQuote != -1)
|
||||
{
|
||||
translation = text.Substring(startQuote + 1, endQuote - startQuote - 1);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// Translation of phrase
|
||||
text = text.Substring(0, index);
|
||||
text = text.Replace("],[", ",");
|
||||
text = text.Replace("]", string.Empty);
|
||||
text = text.Replace("[", string.Empty);
|
||||
text = text.Replace("\",\"", "\"");
|
||||
|
||||
// Get translated phrases
|
||||
string[] phrases = text.Split(new[] { '\"' }, StringSplitOptions.RemoveEmptyEntries);
|
||||
for (int i = 0; (i < phrases.Count()); i += 2)
|
||||
{
|
||||
string translatedPhrase = phrases[i];
|
||||
if (translatedPhrase.StartsWith(",,"))
|
||||
{
|
||||
i--;
|
||||
continue;
|
||||
}
|
||||
translation += translatedPhrase + " ";
|
||||
}
|
||||
}
|
||||
|
||||
// Fix up translation
|
||||
translation = translation.Trim();
|
||||
translation = translation.Replace(" ?", "?");
|
||||
translation = translation.Replace(" !", "!");
|
||||
translation = translation.Replace(" ,", ",");
|
||||
translation = translation.Replace(" .", ".");
|
||||
translation = translation.Replace(" ;", ";");
|
||||
|
||||
// And translation speech URL
|
||||
this.TranslationSpeechUrl = string.Format("https://translate.googleapis.com/translate_tts?ie=UTF-8&q={0}&tl={1}&total=1&idx=0&textlen={2}&client=gtx",
|
||||
HttpUtility.UrlEncode(translation), GoogleTranslator.LanguageEnumToIdentifier(targetLanguage), translation.Length);
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
this.Error = ex;
|
||||
http.DefaultRequestHeaders.Add("user-agent", "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/41.0.2228.0 Safari/537.36");
|
||||
text = await http.GetStringAsync(url).ConfigureAwait(false);
|
||||
}
|
||||
|
||||
// Return result
|
||||
this.TranslationTime = DateTime.Now - tmStart;
|
||||
return translation;
|
||||
return JArray.Parse(text)[0][0][0].ToString();
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
@ -27,13 +27,17 @@ namespace NadekoBot.Modules.Translator
|
||||
await e.Channel.SendIsTyping().ConfigureAwait(false);
|
||||
string from = e.GetArg("langs").ToLowerInvariant().Split('>')[0];
|
||||
string to = e.GetArg("langs").ToLowerInvariant().Split('>')[1];
|
||||
var text = e.GetArg("text")?.Trim();
|
||||
if (string.IsNullOrWhiteSpace(text))
|
||||
return;
|
||||
|
||||
string translation = t.Translate(e.GetArg("text"), from, to);
|
||||
string translation = await t.Translate(text, from, to).ConfigureAwait(false);
|
||||
await e.Channel.SendMessage(translation).ConfigureAwait(false);
|
||||
}
|
||||
catch
|
||||
catch (Exception ex)
|
||||
{
|
||||
await e.Channel.SendMessage("Bad input format, or sth went wrong...").ConfigureAwait(false);
|
||||
Console.WriteLine(ex);
|
||||
await e.Channel.SendMessage("Bad input format, or something went wrong...").ConfigureAwait(false);
|
||||
}
|
||||
|
||||
};
|
||||
|
@ -6,7 +6,7 @@ using System;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
|
||||
namespace NadekoBot.Modules.Administration.Commands
|
||||
namespace NadekoBot.Modules.Utility.Commands
|
||||
{
|
||||
class InfoCommands : DiscordCommand
|
||||
{
|
@ -9,7 +9,7 @@ using System.Linq;
|
||||
using System.Text.RegularExpressions;
|
||||
using System.Timers;
|
||||
|
||||
namespace NadekoBot.Modules.Administration.Commands
|
||||
namespace NadekoBot.Modules.Utility.Commands
|
||||
{
|
||||
class Remind : DiscordCommand
|
||||
{
|
151
NadekoBot/Modules/Utility/UtilityModule.cs
Normal file
151
NadekoBot/Modules/Utility/UtilityModule.cs
Normal file
@ -0,0 +1,151 @@
|
||||
using Discord.Commands;
|
||||
using Discord.Modules;
|
||||
using NadekoBot.Extensions;
|
||||
using NadekoBot.Modules.Permissions.Classes;
|
||||
using NadekoBot.Modules.Utility.Commands;
|
||||
using System;
|
||||
using System.Linq;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace NadekoBot.Modules.Utility
|
||||
{
|
||||
internal class UtilityModule : DiscordModule
|
||||
{
|
||||
public UtilityModule()
|
||||
{
|
||||
commands.Add(new Remind(this));
|
||||
commands.Add(new InfoCommands(this));
|
||||
}
|
||||
|
||||
public override string Prefix => NadekoBot.Config.CommandPrefixes.Utility;
|
||||
|
||||
public override void Install(ModuleManager manager)
|
||||
{
|
||||
|
||||
manager.CreateCommands("", cgb =>
|
||||
{
|
||||
cgb.AddCheck(PermissionChecker.Instance);
|
||||
|
||||
var client = manager.Client;
|
||||
|
||||
commands.ForEach(cmd => cmd.Init(cgb));
|
||||
|
||||
cgb.CreateCommand(Prefix + "whoplays")
|
||||
.Description("Shows a list of users who are playing the specified game.")
|
||||
.Parameter("game", ParameterType.Unparsed)
|
||||
.Do(async e =>
|
||||
{
|
||||
var game = e.GetArg("game")?.Trim().ToUpperInvariant();
|
||||
if (string.IsNullOrWhiteSpace(game))
|
||||
return;
|
||||
var en = e.Server.Users
|
||||
.Where(u => u.CurrentGame?.Name?.ToUpperInvariant() == game)
|
||||
.Select(u => u.Name);
|
||||
|
||||
var arr = en as string[] ?? en.ToArray();
|
||||
|
||||
int i = 0;
|
||||
if (arr.Length == 0)
|
||||
await e.Channel.SendMessage("Nobody. (not 100% sure)").ConfigureAwait(false);
|
||||
else
|
||||
await e.Channel.SendMessage("```xl\n" + string.Join("\n", arr.GroupBy(item => (i++) / 3).Select(ig => string.Join("", ig.Select(el => $"• {el,-35}")))) + "\n```").ConfigureAwait(false);
|
||||
});
|
||||
|
||||
cgb.CreateCommand(Prefix + "inrole")
|
||||
.Description("Lists every person from the provided role or roles (separated by a ',') on this server.")
|
||||
.Parameter("roles", ParameterType.Unparsed)
|
||||
.Do(async e =>
|
||||
{
|
||||
await Task.Run(async () =>
|
||||
{
|
||||
if (!e.User.ServerPermissions.MentionEveryone) return;
|
||||
var arg = e.GetArg("roles").Split(',').Select(r => r.Trim());
|
||||
string send = $"`Here is a list of users in a specfic role:`";
|
||||
foreach (var roleStr in arg.Where(str => !string.IsNullOrWhiteSpace(str)))
|
||||
{
|
||||
var role = e.Server.FindRoles(roleStr).FirstOrDefault();
|
||||
if (role == null) continue;
|
||||
send += $"\n`{role.Name}`\n";
|
||||
send += string.Join(", ", role.Members.Select(r => "**" + r.Name + "**#" + r.Discriminator));
|
||||
}
|
||||
|
||||
while (send.Length > 2000)
|
||||
{
|
||||
var curstr = send.Substring(0, 2000);
|
||||
await
|
||||
e.Channel.Send(curstr.Substring(0,
|
||||
curstr.LastIndexOf(", ", StringComparison.Ordinal) + 1)).ConfigureAwait(false);
|
||||
send = curstr.Substring(curstr.LastIndexOf(", ", StringComparison.Ordinal) + 1) +
|
||||
send.Substring(2000);
|
||||
}
|
||||
await e.Channel.Send(send).ConfigureAwait(false);
|
||||
}).ConfigureAwait(false);
|
||||
});
|
||||
|
||||
cgb.CreateCommand(Prefix + "checkmyperms")
|
||||
.Description("Checks your userspecific permissions on this channel.")
|
||||
.Do(async e =>
|
||||
{
|
||||
var output = "```\n";
|
||||
foreach (var p in e.User.ServerPermissions.GetType().GetProperties().Where(p => !p.GetGetMethod().GetParameters().Any()))
|
||||
{
|
||||
output += p.Name + ": " + p.GetValue(e.User.ServerPermissions, null).ToString() + "\n";
|
||||
}
|
||||
output += "```";
|
||||
await e.User.SendMessage(output).ConfigureAwait(false);
|
||||
});
|
||||
|
||||
cgb.CreateCommand(Prefix + "stats")
|
||||
.Description("Shows some basic stats for Nadeko.")
|
||||
.Do(async e =>
|
||||
{
|
||||
await e.Channel.SendMessage(await NadekoStats.Instance.GetStats());
|
||||
});
|
||||
|
||||
cgb.CreateCommand(Prefix + "dysyd")
|
||||
.Description("Shows some basic stats for Nadeko.")
|
||||
.Do(async e =>
|
||||
{
|
||||
await e.Channel.SendMessage((await NadekoStats.Instance.GetStats()).Matrix().TrimTo(1990)).ConfigureAwait(false);
|
||||
});
|
||||
|
||||
cgb.CreateCommand(Prefix + "userid").Alias(Prefix + "uid")
|
||||
.Description("Shows user ID.")
|
||||
.Parameter("user", ParameterType.Unparsed)
|
||||
.Do(async e =>
|
||||
{
|
||||
var usr = e.User;
|
||||
if (!string.IsNullOrWhiteSpace(e.GetArg("user"))) usr = e.Channel.FindUsers(e.GetArg("user")).FirstOrDefault();
|
||||
if (usr == null)
|
||||
return;
|
||||
await e.Channel.SendMessage($"Id of the user { usr.Name } is { usr.Id }").ConfigureAwait(false);
|
||||
});
|
||||
|
||||
cgb.CreateCommand(Prefix + "channelid").Alias(Prefix + "cid")
|
||||
.Description("Shows current channel ID.")
|
||||
.Do(async e => await e.Channel.SendMessage("This channel's ID is " + e.Channel.Id).ConfigureAwait(false));
|
||||
|
||||
cgb.CreateCommand(Prefix + "serverid").Alias(Prefix + "sid")
|
||||
.Description("Shows current server ID.")
|
||||
.Do(async e => await e.Channel.SendMessage("This server's ID is " + e.Server.Id).ConfigureAwait(false));
|
||||
|
||||
cgb.CreateCommand(Prefix + "roles")
|
||||
.Description("List all roles on this server or a single user if specified.")
|
||||
.Parameter("user", ParameterType.Unparsed)
|
||||
.Do(async e =>
|
||||
{
|
||||
if (!string.IsNullOrWhiteSpace(e.GetArg("user")))
|
||||
{
|
||||
var usr = e.Server.FindUsers(e.GetArg("user")).FirstOrDefault();
|
||||
if (usr == null) return;
|
||||
|
||||
await e.Channel.SendMessage($"`List of roles for **{usr.Name}**:` \n• " + string.Join("\n• ", usr.Roles)).ConfigureAwait(false);
|
||||
return;
|
||||
}
|
||||
await e.Channel.SendMessage("`List of roles:` \n• " + string.Join("\n• ", e.Server.Roles)).ConfigureAwait(false);
|
||||
});
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -22,6 +22,7 @@ using NadekoBot.Modules.Pokemon;
|
||||
using NadekoBot.Modules.Searches;
|
||||
using NadekoBot.Modules.Translator;
|
||||
using NadekoBot.Modules.Trello;
|
||||
using NadekoBot.Modules.Utility;
|
||||
using Newtonsoft.Json;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
@ -105,6 +106,9 @@ namespace NadekoBot
|
||||
Console.WriteLine(string.IsNullOrWhiteSpace(Creds.SoundCloudClientID)
|
||||
? "No soundcloud Client ID found. Soundcloud streaming is disabled."
|
||||
: "SoundCloud streaming enabled.");
|
||||
Console.WriteLine(string.IsNullOrWhiteSpace(Creds.OsuAPIKey)
|
||||
? "No osu! api key found. Song & top score lookups will not work. User lookups still available."
|
||||
: "osu! API key provided.");
|
||||
|
||||
BotMention = $"<@{Creds.BotId}>";
|
||||
|
||||
@ -160,6 +164,7 @@ namespace NadekoBot
|
||||
//install modules
|
||||
modules.Add(new HelpModule(), "Help", ModuleFilter.None);
|
||||
modules.Add(new AdministrationModule(), "Administration", ModuleFilter.None);
|
||||
modules.Add(new UtilityModule(), "Utility", ModuleFilter.None);
|
||||
modules.Add(new PermissionModule(), "Permissions", ModuleFilter.None);
|
||||
modules.Add(new Conversations(), "Conversations", ModuleFilter.None);
|
||||
modules.Add(new GamblingModule(), "Gambling", ModuleFilter.None);
|
||||
|
@ -134,8 +134,10 @@
|
||||
<Reference Include="System.Xml" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<Compile Include="Classes\ObservableConcurrentDictionary.cs" />
|
||||
<Compile Include="Modules\Administration\Commands\AutoAssignRole.cs" />
|
||||
<Compile Include="Modules\Administration\Commands\CustomReactionsCommands.cs" />
|
||||
<Compile Include="Modules\Administration\Commands\SelfAssignedRolesCommand.cs" />
|
||||
<Compile Include="Modules\Administration\Commands\SelfCommands.cs" />
|
||||
<Compile Include="Modules\ClashOfClans\ClashOfClans.cs" />
|
||||
<Compile Include="Classes\DBHandler.cs" />
|
||||
@ -148,6 +150,11 @@
|
||||
<Compile Include="Modules\Searches\Commands\IMDB\ImdbMovie.cs" />
|
||||
<Compile Include="Modules\Searches\Commands\IMDB\ImdbScraper.cs" />
|
||||
<Compile Include="Classes\IncidentsHandler.cs" />
|
||||
<Compile Include="Modules\Searches\Commands\MemegenCommands.cs" />
|
||||
<Compile Include="Modules\Searches\Commands\OsuCommands.cs" />
|
||||
<Compile Include="Modules\Searches\Commands\PokemonSearchCommands.cs" />
|
||||
<Compile Include="Modules\Utility\UtilityModule.cs" />
|
||||
<Compile Include="_Models\DataModels\Incident.cs" />
|
||||
<Compile Include="_Models\JSONModels\AnimeResult.cs" />
|
||||
<Compile Include="_Models\JSONModels\Configuration.cs" />
|
||||
<Compile Include="Modules\Searches\Commands\WowJokes.cs" />
|
||||
@ -186,9 +193,9 @@
|
||||
<Compile Include="Modules\DiscordCommand.cs" />
|
||||
<Compile Include="Modules\Games\Commands\PlantPick.cs" />
|
||||
<Compile Include="Modules\Administration\Commands\CrossServerTextChannel.cs" />
|
||||
<Compile Include="Modules\Administration\Commands\InfoCommands.cs" />
|
||||
<Compile Include="Modules\Administration\Commands\Remind.cs" />
|
||||
<Compile Include="Modules\Administration\Commands\SelfAssignedRolesCommand.cs" />
|
||||
<Compile Include="Modules\Utility\Commands\InfoCommands.cs" />
|
||||
<Compile Include="Modules\Utility\Commands\Remind.cs" />
|
||||
<Compile Include="Modules\Administration\Commands\IncidentsCommands.cs" />
|
||||
<Compile Include="Modules\ClashOfClans\ClashOfClansModule.cs" />
|
||||
<Compile Include="Modules\Permissions\Commands\FilterWordsCommand.cs" />
|
||||
<Compile Include="Modules\Permissions\Commands\FilterInvitesCommand.cs" />
|
||||
@ -205,7 +212,6 @@
|
||||
<Compile Include="Modules\Games\Commands\SpeedTyping.cs" />
|
||||
<Compile Include="Modules\Gambling\Helpers\Cards.cs" />
|
||||
<Compile Include="Classes\Extensions.cs" />
|
||||
<Compile Include="Modules\Conversations\Commands\CopyCommand.cs" />
|
||||
<Compile Include="Modules\Gambling\DiceRollCommand.cs" />
|
||||
<Compile Include="Modules\Gambling\DrawCommand.cs" />
|
||||
<Compile Include="Modules\Gambling\FlipCoinCommand.cs" />
|
||||
@ -491,9 +497,10 @@
|
||||
</ProjectReference>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<Content Include="lib\ScaredFingers.UnitsConversion.dll" />
|
||||
<Content Include="Classes\lib\ScaredFingers.UnitsConversion.dll" />
|
||||
<None Include="resources\images\rose_overlay.png" />
|
||||
</ItemGroup>
|
||||
<ItemGroup />
|
||||
<Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
|
||||
<!-- To modify your build process, add your task inside one of the targets below and uncomment it.
|
||||
Other similar extension points exist, see Microsoft.Common.targets.
|
||||
|
10
NadekoBot/_Models/DataModels/Incident.cs
Normal file
10
NadekoBot/_Models/DataModels/Incident.cs
Normal file
@ -0,0 +1,10 @@
|
||||
namespace NadekoBot.DataModels
|
||||
{
|
||||
class Incident : IDataModel
|
||||
{
|
||||
public long ServerId { get; set; }
|
||||
public long ChannelId { get; set; }
|
||||
public string Text { get; set; }
|
||||
public bool Read { get; set; } = false;
|
||||
}
|
||||
}
|
@ -161,6 +161,7 @@ Nadeko Support Server: <https://discord.gg/0ehQwTK2RBjAxzEY>";
|
||||
public string Permissions { get; set; } = ";";
|
||||
public string Programming { get; set; } = "%";
|
||||
public string Pokemon { get; set; } = ">";
|
||||
public string Utility { get; set; } = ".";
|
||||
}
|
||||
|
||||
public static class ConfigHandler
|
||||
|
@ -16,6 +16,7 @@ namespace NadekoBot.Classes.JSONModels
|
||||
public string LOLAPIKey { get; set; } = "";
|
||||
public string TrelloAppKey { get; set; } = "";
|
||||
public string CarbonKey { get; set; } = "";
|
||||
public string OsuAPIKey { get; set; } = "";
|
||||
}
|
||||
[DebuggerDisplay("{items[0].id.playlistId}")]
|
||||
public class YoutubePlaylistSearch
|
||||
|
@ -11,5 +11,6 @@
|
||||
"MashapeKey": "",
|
||||
"LOLAPIKey": "",
|
||||
"TrelloAppKey": "",
|
||||
"CarbonKey": ""
|
||||
"CarbonKey": "",
|
||||
"OsuAPIKey": ""
|
||||
}
|
@ -87,7 +87,8 @@
|
||||
"Gambling": "$",
|
||||
"Permissions": ";",
|
||||
"Programming": "%",
|
||||
"Pokemon": ">"
|
||||
"Pokemon": ">",
|
||||
"Utility": "."
|
||||
},
|
||||
"ServerBlacklist": [],
|
||||
"ChannelBlacklist": [],
|
||||
|
125
commandlist.md
125
commandlist.md
@ -2,7 +2,7 @@
|
||||
######You can donate on paypal: `nadekodiscordbot@gmail.com` or Bitcoin `17MZz1JAqME39akMLrVT4XBPffQJ2n1EPa`
|
||||
|
||||
#NadekoBot List Of Commands
|
||||
Version: `NadekoBot v0.9.6015.37609`
|
||||
Version: `NadekoBot v0.9.6029.16666`
|
||||
### Help
|
||||
Command and aliases | Description | Usage
|
||||
----------------|--------------|-------
|
||||
@ -44,16 +44,16 @@ Command and aliases | Description | Usage
|
||||
`.lsar` | Lists all self-assignable roles.
|
||||
`.iam` | Adds a role to you that you choose. Role must be on a list of self-assignable roles. | .iam Gamer
|
||||
`.iamnot`, `.iamn` | Removes a role to you that you choose. Role must be on a list of self-assignable roles. | .iamn Gamer
|
||||
`.remind` | Sends a message to you or a channel after certain amount of time. First argument is me/here/'channelname'. Second argument is time in a descending order (mo>w>d>h>m) example: 1w5d3h10m. Third argument is a (multiword)message. | `.remind me 1d5h Do something` or `.remind #general Start now!`
|
||||
`.remindmsg` | Sets message for when the remind is triggered. Available placeholders are %user% - user who ran the command, %message% - Message specified in the remind, %target% - target channel of the remind. **Bot Owner Only!**
|
||||
`.serverinfo`, `.sinfo` | Shows info about the server the bot is on. If no channel is supplied, it defaults to current one. | .sinfo Some Server
|
||||
`.channelinfo`, `.cinfo` | Shows info about the channel. If no channel is supplied, it defaults to current one. | .cinfo #some-channel
|
||||
`.userinfo`, `.uinfo` | Shows info about the user. If no user is supplied, it defaults a user running the command. | .uinfo @SomeUser
|
||||
`.addcustreact`, `.acr` | Add a custom reaction. Guide here: <https://github.com/Kwoth/NadekoBot/wiki/Custom-Reactions> **Bot Owner Only!** | .acr "hello" I love saying hello to %user%
|
||||
`.listcustreact`, `.lcr` | Lists all current custom reactions (paginated with 5 commands per page). | .lcr 1
|
||||
`.listcustreact`, `.lcr` | Lists all current custom reactions (paginated with 30 commands per page). | .lcr 1
|
||||
`.showcustreact`, `.scr` | Shows all possible responses from a single custom reaction. | .scr %mention% bb
|
||||
`.editcustreact`, `.ecr` | Edits a custom reaction, arguments are custom reactions name, index to change, and a (multiword) message **Bot Owner Only** | `.ecr "%mention% disguise" 2 Test 123`
|
||||
`.delcustreact`, `.dcr` | Deletes a custom reaction with given name (and index)
|
||||
`.autoassignrole`, `.aar` | Automaticaly assigns a specified role to every user who joins the server. Type `.aar` to disable, `.aar Role Name` to enable
|
||||
`.leave` | Makes Nadeko leave the server. Either name or id required. | `.leave 123123123331`
|
||||
`.listincidents`, `.lin` | List all UNREAD incidents and flags them as read.
|
||||
`.listallincidents`, `.lain` | Sends you a file containing all incidents and flags them as read.
|
||||
`.delmsgoncmd` | Toggles the automatic deletion of user's successful command message to prevent chat flood. Server Manager Only.
|
||||
`.restart` | Restarts the bot. Might not work.
|
||||
`.setrole`, `.sr` | Sets a role for a given user. | .sr @User Guest
|
||||
`.removerole`, `.rr` | Removes a role from a given user. | .rr @User Admin
|
||||
@ -61,7 +61,6 @@ Command and aliases | Description | Usage
|
||||
`.removeallroles`, `.rar` | Removes all roles from a mentioned user. | .rar @User
|
||||
`.createrole`, `.cr` | Creates a role with a given name. | `.r Awesome Role`
|
||||
`.rolecolor`, `.rc` | Set a role's color to the hex or 0-255 rgb color value provided. | `.color Admin 255 200 100` or `.color Admin ffba55`
|
||||
`.roles` | List all roles on this server or a single user if specified.
|
||||
`.ban`, `.b` | Bans a user by id or name with an optional message. | .b "@some Guy" Your behaviour is toxic.
|
||||
`.softban`, `.sb` | Bans and then unbans a user by id or name with an optional message. | .sb "@some Guy" Your behaviour is toxic.
|
||||
`.kick`, `.k` | Kicks a mentioned user.
|
||||
@ -75,30 +74,38 @@ Command and aliases | Description | Usage
|
||||
`.creatxtchanl`, `.ctch` | Creates a new text channel with a given name.
|
||||
`.settopic`, `.st` | Sets a topic on the current channel. | `.st My new topic`
|
||||
`.setchanlname`, `.schn` | Changed the name of the current channel.
|
||||
`.userid`, `.uid` | Shows user ID.
|
||||
`.channelid`, `.cid` | Shows current channel ID.
|
||||
`.serverid`, `.sid` | Shows current server ID.
|
||||
`.stats` | Shows some basic stats for Nadeko.
|
||||
`.dysyd` | Shows some basic stats for Nadeko.
|
||||
`.heap` | Shows allocated memory - **Bot Owner Only!**
|
||||
`.prune`, `.clr` | `.prune` removes all nadeko's messages in the last 100 messages.`.prune X` removes last X messages from the channel (up to 100)`.prune @Someone` removes all Someone's messages in the last 100 messages.`.prune @Someone X` removes last X 'Someone's' messages in the channel. | `.prune` or `.prune 5` or `.prune @Someone` or `.prune @Someone X`
|
||||
`.die` | Shuts the bot down and notifies users about the restart. **Bot Owner Only!**
|
||||
`.setname`, `.newnm` | Give the bot a new name. **Bot Owner Only!**
|
||||
`.newavatar`, `.setavatar` | Sets a new avatar image for the NadekoBot. **Bot Owner Only!**
|
||||
`.newavatar`, `.setavatar` | Sets a new avatar image for the NadekoBot. Argument is a direct link to an image. **Bot Owner Only!** | `.setavatar https://i.ytimg.com/vi/WDudkR1eTMM/maxresdefault.jpg`
|
||||
`.setgame` | Sets the bots game. **Bot Owner Only!**
|
||||
`.checkmyperms` | Checks your userspecific permissions on this channel.
|
||||
`.commsuser` | Sets a user for through-bot communication. Only works if server is set. Resets commschannel. **Bot Owner Only!**
|
||||
`.commsserver` | Sets a server for through-bot communication. **Bot Owner Only!**
|
||||
`.commschannel` | Sets a channel for through-bot communication. Only works if server is set. Resets commsuser. **Bot Owner Only!**
|
||||
`.send` | Send a message to someone on a different server through the bot. **Bot Owner Only!** | .send Message text multi word!
|
||||
`.send` | Send a message to someone on a different server through the bot. **Bot Owner Only!** | `.send serverid|u:user_id Send this to a user!` or `.send serverid|c:channel_id Send this to a channel!`
|
||||
`.mentionrole`, `.menro` | Mentions every person from the provided role or roles (separated by a ',') on this server. Requires you to have mention everyone permission.
|
||||
`.inrole` | Lists every person from the provided role or roles (separated by a ',') on this server.
|
||||
`.unstuck` | Clears the message queue. **Bot Owner Only!**
|
||||
`.donators` | List of lovely people who donated to keep this project alive.
|
||||
`.donadd` | Add a donator to the database.
|
||||
`.announce` | Sends a message to all servers' general channel bot is connected to.**Bot Owner Only!** | .announce Useless spam
|
||||
`.whoplays` | Shows a list of users who are playing the specified game.
|
||||
`.leave` | Leaves a server with a supplied ID. | `.leave 493243292839`
|
||||
`.savechat` | Saves a number of messages to a text file and sends it to you. **Bot Owner Only** | `.chatsave 150`
|
||||
|
||||
### Utility
|
||||
Command and aliases | Description | Usage
|
||||
----------------|--------------|-------
|
||||
`.remind` | Sends a message to you or a channel after certain amount of time. First argument is me/here/'channelname'. Second argument is time in a descending order (mo>w>d>h>m) example: 1w5d3h10m. Third argument is a (multiword)message. | `.remind me 1d5h Do something` or `.remind #general Start now!`
|
||||
`.remindmsg` | Sets message for when the remind is triggered. Available placeholders are %user% - user who ran the command, %message% - Message specified in the remind, %target% - target channel of the remind. **Bot Owner Only!**
|
||||
`.serverinfo`, `.sinfo` | Shows info about the server the bot is on. If no channel is supplied, it defaults to current one. | .sinfo Some Server
|
||||
`.channelinfo`, `.cinfo` | Shows info about the channel. If no channel is supplied, it defaults to current one. | .cinfo #some-channel
|
||||
`.userinfo`, `.uinfo` | Shows info about the user. If no user is supplied, it defaults a user running the command. | .uinfo @SomeUser
|
||||
`.whoplays` | Shows a list of users who are playing the specified game.
|
||||
`.inrole` | Lists every person from the provided role or roles (separated by a ',') on this server.
|
||||
`.checkmyperms` | Checks your userspecific permissions on this channel.
|
||||
`.stats` | Shows some basic stats for Nadeko.
|
||||
`.dysyd` | Shows some basic stats for Nadeko.
|
||||
`.userid`, `.uid` | Shows user ID.
|
||||
`.channelid`, `.cid` | Shows current channel ID.
|
||||
`.serverid`, `.sid` | Shows current server ID.
|
||||
`.roles` | List all roles on this server or a single user if specified.
|
||||
|
||||
### Permissions
|
||||
Command and aliases | Description | Usage
|
||||
@ -145,8 +152,6 @@ Command and aliases | Description | Usage
|
||||
`..` | Adds a new quote with the specified name (single word) and message (no limit). | .. abc My message
|
||||
`...` | Shows a random quote with a specified name. | .. abc
|
||||
`..qdel`, `..quotedelete` | Deletes all quotes with the specified keyword. You have to either be bot owner or the creator of the quote to delete it. | `..qdel abc`
|
||||
`@BotName copyme`, `@BotName cm` | Nadeko starts copying everything you say. Disable with cs
|
||||
`@BotName cs`, `@BotName copystop` | Nadeko stops copying you
|
||||
`@BotName rip` | Shows a grave image of someone with a start year | @NadekoBot rip @Someone 2000
|
||||
`@BotName uptime` | Shows how long Nadeko has been running for.
|
||||
`@BotName die` | Works only for the owner. Shuts the bot down.
|
||||
@ -156,7 +161,6 @@ Command and aliases | Description | Usage
|
||||
`@BotName slm` | Shows the message where you were last mentioned in this channel (checks last 10k messages)
|
||||
`@BotName dump` | Dumps all of the invites it can to dump.txt.** Owner Only.**
|
||||
`@BotName ab` | Try to get 'abalabahaha'
|
||||
`@BotName av`, `@BotName avatar` | Shows a mentioned person's avatar. | ~av @X
|
||||
|
||||
### Gambling
|
||||
Command and aliases | Description | Usage
|
||||
@ -186,6 +190,7 @@ Command and aliases | Description | Usage
|
||||
`>pollend` | Stops active poll on this server and prints the results in this channel.
|
||||
`>pick` | Picks a flower planted in this channel.
|
||||
`>plant` | Spend a flower to plant it in this channel. (If bot is restarted or crashes, flower will be lost)
|
||||
`>gencurrency`, `>gc` | Toggles currency generation on this channel. Every posted message will have 2% chance to spawn a NadekoFlower. Requires Manage Messages permission. | `>gc`
|
||||
`>leet` | Converts a text to leetspeak with 6 (1-6) severity levels | >leet 3 Hello
|
||||
`>choose` | Chooses a thing from a list of things | >choose Get up;Sleep;Sleep more
|
||||
`>8ball` | Ask the 8ball a yes/no question.
|
||||
@ -195,34 +200,37 @@ Command and aliases | Description | Usage
|
||||
### Music
|
||||
Command and aliases | Description | Usage
|
||||
----------------|--------------|-------
|
||||
`!m next`, `!m n`, `!m skip` | Goes to the next song in the queue. You have to be in the same voice channel as the bot. | `!m n`
|
||||
`!m stop`, `!m s` | Stops the music and clears the playlist. Stays in the channel. | `!m s`
|
||||
`!m destroy`, `!m d` | Completely stops the music and unbinds the bot from the channel. (may cause weird behaviour) | `!m d`
|
||||
`!m pause`, `!m p` | Pauses or Unpauses the song. | `!m p`
|
||||
`!m queue`, `!m q`, `!m yq` | Queue a song using keywords or a link. Bot will join your voice channel.**You must be in a voice channel**. | `!m q Dream Of Venice`
|
||||
`!m listqueue`, `!m lq` | Lists up to 15 currently queued songs. | `!m lq`
|
||||
`!m nowplaying`, `!m np` | Shows the song currently playing. | `!m np`
|
||||
`!m volume`, `!m vol` | Sets the music volume 0-100% | `!m vol 50`
|
||||
`!m defvol`, `!m dv` | Sets the default music volume when music playback is started (0-100). Does not persist through restarts. | `!m dv 80`
|
||||
`!m mute`, `!m min` | Sets the music volume to 0% | `!m min`
|
||||
`!m max` | Sets the music volume to 100% (real max is actually 150%). | `!m max`
|
||||
`!m half` | Sets the music volume to 50%. | `!m half`
|
||||
`!m shuffle`, `!m sh` | Shuffles the current playlist. | `!m sh`
|
||||
`!m playlist`, `!m pl` | Queues up to 50 songs from a youtube playlist specified by a link, or keywords. | `!m pl playlist link or name`
|
||||
`!m localplaylst`, `!m lopl` | Queues all songs from a directory. **Bot Owner Only!** | `!m lopl C:/music/classical`
|
||||
`!m radio`, `!m ra` | Queues a radio stream from a link. It can be a direct mp3 radio stream, .m3u, .pls .asx or .xspf | `!m ra radio link here`
|
||||
`!m local`, `!m lo` | Queues a local file by specifying a full path. **Bot Owner Only!** | `!m lo C:/music/mysong.mp3`
|
||||
`!m move`, `!m mv` | Moves the bot to your voice channel. (works only if music is already playing) | `!m mv`
|
||||
`!m remove`, `!m rm` | Remove a song by its # in the queue, or 'all' to remove whole queue. | `!m rm 5`
|
||||
`!m movesong`, `!m ms` | Moves a song from one position to another. | `!m ms` 5>3
|
||||
`!m cleanup` | Cleans up hanging voice connections. **Bot Owner Only!** | `!m cleanup`
|
||||
`!m reptcursong`, `!m rcs` | Toggles repeat of current song. | `!m rcs`
|
||||
`!m rpeatplaylst`, `!m rpl` | Toggles repeat of all songs in the queue (every song that finishes is added to the end of the queue). | `!m rpl`
|
||||
`!m save` | Saves a playlist under a certain name. Name must be no longer than 20 characters and mustn't contain dashes. | `!m save classical1`
|
||||
`!m load` | Loads a playlist under a certain name. | `!m load classical-1`
|
||||
`!m playlists`, `!m pls` | Lists all playlists. Paginated. 20 per page. Default page is 0. | `!m pls 1`
|
||||
`!m goto` | Goes to a specific time in seconds in a song.
|
||||
`!m getlink`, `!m gl` | Shows a link to the currently playing song.
|
||||
`! next`, `! n`, `! skip` | Goes to the next song in the queue. You have to be in the same voice channel as the bot. | `!m n`
|
||||
`! stop`, `! s` | Stops the music and clears the playlist. Stays in the channel. | `!m s`
|
||||
`! destroy`, `! d` | Completely stops the music and unbinds the bot from the channel. (may cause weird behaviour) | `!m d`
|
||||
`! pause`, `! p` | Pauses or Unpauses the song. | `!m p`
|
||||
`! queue`, `! q`, `! yq` | Queue a song using keywords or a link. Bot will join your voice channel.**You must be in a voice channel**. | `!m q Dream Of Venice`
|
||||
`! listqueue`, `! lq` | Lists 15 currently queued songs per page. Default page is 1. | `!m lq` or `!m lq 2`
|
||||
`! nowplaying`, `! np` | Shows the song currently playing. | `!m np`
|
||||
`! volume`, `! vol` | Sets the music volume 0-100% | `!m vol 50`
|
||||
`! defvol`, `! dv` | Sets the default music volume when music playback is started (0-100). Does not persist through restarts. | `!m dv 80`
|
||||
`! mute`, `! min` | Sets the music volume to 0% | `!m min`
|
||||
`! max` | Sets the music volume to 100% (real max is actually 150%). | `!m max`
|
||||
`! half` | Sets the music volume to 50%. | `!m half`
|
||||
`! shuffle`, `! sh` | Shuffles the current playlist. | `!m sh`
|
||||
`! playlist`, `! pl` | Queues up to 50 songs from a youtube playlist specified by a link, or keywords. | `!m pl playlist link or name`
|
||||
`! soundcloudpl`, `! scpl` | Queue a soundcloud playlist using a link. | `!m scpl https://soundcloud.com/saratology/sets/symphony`
|
||||
`! localplaylst`, `! lopl` | Queues all songs from a directory. **Bot Owner Only!** | `!m lopl C:/music/classical`
|
||||
`! radio`, `! ra` | Queues a radio stream from a link. It can be a direct mp3 radio stream, .m3u, .pls .asx or .xspf | `!m ra radio link here`
|
||||
`! local`, `! lo` | Queues a local file by specifying a full path. **Bot Owner Only!** | `!m lo C:/music/mysong.mp3`
|
||||
`! move`, `! mv` | Moves the bot to your voice channel. (works only if music is already playing) | `!m mv`
|
||||
`! remove`, `! rm` | Remove a song by its # in the queue, or 'all' to remove whole queue. | `!m rm 5`
|
||||
`! movesong`, `! ms` | Moves a song from one position to another. | `! ms` 5>3
|
||||
`! cleanup` | Cleans up hanging voice connections. **Bot Owner Only!** | `!m cleanup`
|
||||
`! reptcursong`, `! rcs` | Toggles repeat of current song. | `!m rcs`
|
||||
`! rpeatplaylst`, `! rpl` | Toggles repeat of all songs in the queue (every song that finishes is added to the end of the queue). | `!m rpl`
|
||||
`! save` | Saves a playlist under a certain name. Name must be no longer than 20 characters and mustn't contain dashes. | `!m save classical1`
|
||||
`! load` | Loads a playlist under a certain name. | `!m load classical-1`
|
||||
`! playlists`, `! pls` | Lists all playlists. Paginated. 20 per page. Default page is 0. | `!m pls 1`
|
||||
`! deleteplaylist`, `! delpls` | Deletes a saved playlist. Only if you made it or if you are the bot owner. | `!m delpls animu-5`
|
||||
`! goto` | Goes to a specific time in seconds in a song.
|
||||
`! getlink`, `! gl` | Shows a link to the currently playing song.
|
||||
`! autoplay`, `! ap` | Toggles autoplay - When the song is finished, automatically queue a related youtube song. (Works only for youtube songs and when queue is empty)
|
||||
|
||||
### Searches
|
||||
Command and aliases | Description | Usage
|
||||
@ -232,13 +240,22 @@ Command and aliases | Description | Usage
|
||||
`~hitbox`, `~hb` | Notifies this channel when a certain user starts streaming. | ~hitbox SomeStreamer
|
||||
`~twitch`, `~tw` | Notifies this channel when a certain user starts streaming. | ~twitch SomeStreamer
|
||||
`~beam`, `~bm` | Notifies this channel when a certain user starts streaming. | ~beam SomeStreamer
|
||||
`~checkhitbox`, `~chhb` | Checks if a certain user is streaming on the hitbox platform. | ~chhb SomeStreamer
|
||||
`~checktwitch`, `~chtw` | Checks if a certain user is streaming on the twitch platform. | ~chtw SomeStreamer
|
||||
`~checkbeam`, `~chbm` | Checks if a certain user is streaming on the beam platform. | ~chbm SomeStreamer
|
||||
`~removestream`, `~rms` | Removes notifications of a certain streamer on this channel. | ~rms SomeGuy
|
||||
`~liststreams`, `~ls` | Lists all streams you are following on this server. | ~ls
|
||||
`~convert` | Convert quantities from>to. Like `~convert m>km 1000`
|
||||
`~convertlist` | List of the convertable dimensions and currencies.
|
||||
`~wowjoke` | Get one of Kwoth's penultimate WoW jokes.
|
||||
`~calculate`, `~calc` | Evaluate a mathematical expression. | ~calc 1+1
|
||||
`~wowjoke` | Get one of Kwoth's penultimate WoW jokes.
|
||||
`~osu` | Shows osu stats for a player. | `~osu Name` or `~osu Name taiko`
|
||||
`~osu b` | Shows information about an osu beatmap. | ~osu b https://osu.ppy.sh/s/127712
|
||||
`~osu top5` | Displays a user's top 5 plays. | ~osu top5 Name
|
||||
`~pokemon`, `~poke` | Searches for a pokemon.
|
||||
`~pokemonability`, `~pokab` | Searches for a pokemon ability.
|
||||
`~memelist` | Pulls a list of memes you can use with `~memegen` from http://memegen.link/templates/
|
||||
`~memegen` | Generates a meme from memelist with top and bottom text. | `~memegen biw "gets iced coffee" "in the winter"`
|
||||
`~we` | Shows weather data for a specified city and a country. BOTH ARE REQUIRED. Use country abbrevations. | ~we Moscow RF
|
||||
`~yt` | Searches youtubes and shows the first result
|
||||
`~ani`, `~anime`, `~aq` | Queries anilist for an anime and shows the first result.
|
||||
@ -249,7 +266,6 @@ Command and aliases | Description | Usage
|
||||
`~ir` | Pulls a random image using a search parameter. | ~ir cute kitten
|
||||
`~lmgtfy` | Google something for an idiot.
|
||||
`~hs` | Searches for a Hearthstone card and shows its image. Takes a while to complete. | ~hs Ysera
|
||||
`~osu` | Shows osu stats for a player. | ~osu Name
|
||||
`~ud` | Searches Urban Dictionary for a word. | ~ud Pineapple
|
||||
`~#` | Searches Tagdef.com for a hashtag. | ~# ff
|
||||
`~quote` | Shows a random quote.
|
||||
@ -264,6 +280,7 @@ Command and aliases | Description | Usage
|
||||
`~wiki` | Gives you back a wikipedia link
|
||||
`~clr` | Shows you what color corresponds to that hex. | `~clr 00ff00`
|
||||
`~videocall` | Creates a private <http://www.appear.in> video call link for you and other mentioned people. The link is sent to mentioned people via a private message.
|
||||
`~av`, `~avatar` | Shows a mentioned person's avatar. | ~av @X
|
||||
|
||||
### NSFW
|
||||
Command and aliases | Description | Usage
|
||||
|
Loading…
Reference in New Issue
Block a user