diff --git a/NadekoBot/Classes/Extensions.cs b/NadekoBot/Classes/Extensions.cs
index 92fcdddc..5ab8cabf 100644
--- a/NadekoBot/Classes/Extensions.cs
+++ b/NadekoBot/Classes/Extensions.cs
@@ -29,7 +29,6 @@ namespace NadekoBot.Extensions {
if (letters[i] != ' ')
letters[i] = '_';
-
}
return "`"+string.Join(" ", letters)+"`";
}
@@ -153,7 +152,7 @@ namespace NadekoBot.Extensions {
///
///
///
- public static string ShortenUrl(this string str) => Searches.ShortenUrl(str);
+ public static async Task ShortenUrl(this string str) => await Searches.ShortenUrl(str);
///
/// Gets the program runtime
diff --git a/NadekoBot/Classes/Music/MusicControls.cs b/NadekoBot/Classes/Music/MusicControls.cs
index cc70a683..97e0bb03 100644
--- a/NadekoBot/Classes/Music/MusicControls.cs
+++ b/NadekoBot/Classes/Music/MusicControls.cs
@@ -15,6 +15,7 @@ namespace NadekoBot.Classes.Music {
public bool Pause = false;
public List SongQueue = new List();
public StreamRequest CurrentSong = null;
+ public float Volume { get; set; } = 1.0f;
public bool IsPaused { get; internal set; } = false;
public bool Stopped { get; private set; }
@@ -67,7 +68,7 @@ namespace NadekoBot.Classes.Music {
VoiceClient = await NadekoBot.client.Audio().Join(VoiceChannel);
Console.WriteLine($"Joined voicechannel [{DateTime.Now.Second}]");
}
- await CurrentSong.Start();
+ await Task.Factory.StartNew(async () => await CurrentSong.Start(), TaskCreationOptions.LongRunning).Unwrap();
} catch (Exception ex) {
Console.WriteLine($"Starting failed: {ex}");
CurrentSong?.Stop();
@@ -77,10 +78,6 @@ namespace NadekoBot.Classes.Music {
internal void Stop() {
Stopped = true;
- foreach (var kvp in SongQueue) {
- if (kvp != null)
- kvp.Stop();
- }
SongQueue.Clear();
CurrentSong?.Stop();
CurrentSong = null;
@@ -91,6 +88,14 @@ namespace NadekoBot.Classes.Music {
MusicModule.musicPlayers.TryRemove(_e.Server, out throwAwayValue);
}
+ public void SetVolume(int value) {
+ if (value < 0)
+ value = 0;
+ if (value > 150)
+ value = 150;
+ this.Volume = value/100f;
+ }
+
internal bool TogglePause() => IsPaused = !IsPaused;
}
}
diff --git a/NadekoBot/Classes/Music/StreamRequest.cs b/NadekoBot/Classes/Music/StreamRequest.cs
index 34bb1a7d..6b1449cf 100644
--- a/NadekoBot/Classes/Music/StreamRequest.cs
+++ b/NadekoBot/Classes/Music/StreamRequest.cs
@@ -36,6 +36,8 @@ namespace NadekoBot.Classes.Music {
public bool IsPaused => MusicControls.IsPaused;
+ public float Volume => MusicControls?.Volume ?? 1.0f;
+
public MusicControls MusicControls;
public StreamRequest(CommandEventArgs e, string query, MusicControls mc) {
@@ -50,17 +52,17 @@ namespace NadekoBot.Classes.Music {
mc.SongQueue.Add(this);
}
- private void ResolveStreamLink() {
+ private async void ResolveStreamLink() {
Video video = null;
try {
if (OnResolving != null)
OnResolving();
- Console.WriteLine("Resolving video link");
-
- video = YouTube.Default.GetAllVideos(Searches.FindYoutubeUrlByKeywords(Query))
- .Where(v => v.AdaptiveKind == AdaptiveKind.Audio)
- .OrderByDescending(v => v.AudioBitrate)
- .FirstOrDefault();
+ var links = await Searches.FindYoutubeUrlByKeywords(Query);
+ var videos = await YouTube.Default.GetAllVideosAsync(links);
+ video = videos
+ .Where(v => v.AdaptiveKind == AdaptiveKind.Audio)
+ .OrderByDescending(v => v.AudioBitrate)
+ .FirstOrDefault();
if (video == null) // do something with this error
throw new Exception("Could not load any video elements based on the query.");
@@ -77,7 +79,6 @@ namespace NadekoBot.Classes.Music {
musicStreamer = new MusicStreamer(this, video.Uri);
if (OnQueued != null)
OnQueued();
- return;
}
internal string PrintStats() => musicStreamer?.Stats();
@@ -98,14 +99,11 @@ namespace NadekoBot.Classes.Music {
}
internal async Task Start() {
- Console.WriteLine("Start called.");
-
int attemptsLeft = 4;
//wait for up to 4 seconds to resolve a link
try {
while (State == StreamState.Resolving) {
await Task.Delay(1000);
- Console.WriteLine("Resolving...");
if (--attemptsLeft == 0) {
throw new TimeoutException("Resolving timed out.");
}
@@ -137,7 +135,6 @@ namespace NadekoBot.Classes.Music {
this.parent = parent;
this.buffer = new DualStream();
this.Url = directUrl;
- Console.WriteLine("Created new streamer");
State = StreamState.Queued;
}
@@ -149,7 +146,6 @@ namespace NadekoBot.Classes.Music {
"--------------------------------\n";
private async Task BufferSong() {
- Console.WriteLine("Buffering...");
//start feeding the buffer
var p = Process.Start(new ProcessStartInfo {
FileName = "ffmpeg",
@@ -162,11 +158,11 @@ namespace NadekoBot.Classes.Music {
});
int attempt = 0;
while (true) {
-
+ int magickBuffer = 1;
//wait for the read pos to catch up with write pos
- while (buffer.writePos - buffer.readPos > 5.MB() && State != StreamState.Completed) {
+ while (buffer.writePos - buffer.readPos > 1.MB() && State != StreamState.Completed) {
prebufferingComplete = true;
- await Task.Delay(200);
+ await Task.Delay(150);
}
if (State == StreamState.Completed) {
@@ -178,10 +174,8 @@ namespace NadekoBot.Classes.Music {
return;
}
- if (buffer.readPos > 5.MiB()) { // if buffer is over 5 MiB, create new one
- Console.WriteLine("Buffer over 5 megs, clearing.");
-
- var skip = 5.MB(); //remove only 5 MB, just in case
+ if (buffer.readPos > 1.MiB() && buffer.writePos > 1.MiB()) { // if buffer is over 5 MiB, create new one
+ var skip = 1.MB(); //remove only 5 MB, just in case
var newBuffer = new DualStream();
lock (_bufferLock) {
@@ -225,7 +219,10 @@ namespace NadekoBot.Classes.Music {
State = StreamState.Playing;
if (parent.OnBuffering != null)
parent.OnBuffering();
- BufferSong();
+
+ Task.Factory.StartNew(async () => {
+ await BufferSong();
+ }, TaskCreationOptions.LongRunning).ConfigureAwait(false);
// prebuffering wait stuff start
int bufferAttempts = 0;
@@ -253,6 +250,8 @@ namespace NadekoBot.Classes.Music {
int attempt = 0;
while (!IsCanceled) {
int readCount = 0;
+ //adjust volume
+
lock (_bufferLock) {
readCount = buffer.Read(voiceBuffer, 0, voiceBuffer.Length);
}
@@ -272,7 +271,7 @@ namespace NadekoBot.Classes.Music {
Console.WriteLine("Canceled");
break;
}
-
+ voiceBuffer = adjustVolume(voiceBuffer, parent.Volume);
parent.MusicControls.VoiceClient.Send(voiceBuffer, 0, voiceBuffer.Length);
while (IsPaused) {
@@ -288,11 +287,36 @@ namespace NadekoBot.Classes.Music {
}
internal void Stop() {
- Console.WriteLine($"Stopping playback [{DateTime.Now.Second}]");
- if (State != StreamState.Completed) {
- State = StreamState.Completed;
- parent.OnCompleted();
+ if (State == StreamState.Completed) return;
+ var oldState = State;
+ State = StreamState.Completed;
+ if (oldState == StreamState.Playing)
+ if (parent.OnCompleted != null)
+ parent.OnCompleted();
+ }
+ //stackoverflow ftw
+ private byte[] adjustVolume(byte[] audioSamples, float volume) {
+ if (volume == 1.0f)
+ return audioSamples;
+ byte[] array = new byte[audioSamples.Length];
+ for (int i = 0; i < array.Length; i += 2) {
+
+ // convert byte pair to int
+ short buf1 = audioSamples[i + 1];
+ short buf2 = audioSamples[i];
+
+ buf1 = (short)((buf1 & 0xff) << 8);
+ buf2 = (short)(buf2 & 0xff);
+
+ short res = (short)(buf1 | buf2);
+ res = (short)(res * volume);
+
+ // convert back
+ array[i] = (byte)res;
+ array[i + 1] = (byte)(res >> 8);
+
}
+ return array;
}
}
diff --git a/NadekoBot/Modules/Conversations.cs b/NadekoBot/Modules/Conversations.cs
index 12b1d9ab..01572359 100644
--- a/NadekoBot/Modules/Conversations.cs
+++ b/NadekoBot/Modules/Conversations.cs
@@ -266,44 +266,6 @@ namespace NadekoBot.Modules {
await e.Send("Invalid code.");
}
});
-
- cgb.CreateCommand("save")
- .Description("Saves something for the owner in a file.")
- .Parameter("all", ParameterType.Unparsed)
- .Do(async e => {
- if (e.User.Id == NadekoBot.OwnerID) {
- string m = "";
- try {
- FileStream f = File.OpenWrite("saves.txt");
- m = e.Args[0];
- byte[] b = Encoding.ASCII.GetBytes(m + "\n");
- f.Seek(f.Length, SeekOrigin.Begin);
- f.Write(b, 0, b.Length);
- f.Close();
- } catch (Exception) {
- await e.Send("Error saving. Sorry :(");
- }
- if (m.Length > 0)
- await e.Send("I saved this for you: " + Environment.NewLine + "```" + m + "```");
- else
- await e.Send("No point in saving empty message...");
- } else await e.Send("Not for you, only my Master <3");
- });
-
- cgb.CreateCommand("ls")
- .Description("Shows all saved items.")
- .Do(async e => {
- FileStream f = File.OpenRead("saves.txt");
- if (f.Length == 0) {
- await e.Send("Saves are empty.");
- return;
- }
- byte[] b = new byte[f.Length / sizeof(byte)];
- f.Read(b, 0, b.Length);
- f.Close();
- string str = Encoding.ASCII.GetString(b);
- await e.User.Send("```" + (str.Length < 1950 ? str : str.Substring(0, 1950)) + "```");
- });
cgb.CreateCommand("slm")
.Description("Shows the message where you were last mentioned in this channel (checks last 10k messages)")
.Do(async e => {
@@ -331,12 +293,6 @@ namespace NadekoBot.Modules {
else
await e.Send("I can't find a message mentioning you.");
});
- cgb.CreateCommand("cs")
- .Description("Deletes all saves")
- .Do(async e => {
- File.Delete("saves.txt");
- await e.Send("Cleared all saves.");
- });
cgb.CreateCommand("bb")
.Description("Says bye to someone. **Usage**: @NadekoBot bb @X")
@@ -416,8 +372,7 @@ namespace NadekoBot.Modules {
await e.Send("Invalid user specified.");
return;
}
- string av = usr.AvatarUrl;
- await e.Send(Searches.ShortenUrl(av));
+ await e.Send(await usr.AvatarUrl.ShortenUrl());
});
//TODO add eval
diff --git a/NadekoBot/Modules/Gambling.cs b/NadekoBot/Modules/Gambling.cs
index dff0ffa6..b947fa09 100644
--- a/NadekoBot/Modules/Gambling.cs
+++ b/NadekoBot/Modules/Gambling.cs
@@ -20,10 +20,9 @@ namespace NadekoBot.Modules
commands.ForEach(com => com.Init(cgb));
cgb.CreateCommand("$raffle")
- .Description("Mentions a user from the online list from the (optional) role.")
+ .Description("Prints a name and ID of a random user from the online list from the (optional) role.")
.Parameter("role", ParameterType.Optional)
.Do(async e => {
- if (!e.User.ServerPermissions.MentionEveryone) return;
var arg = string.IsNullOrWhiteSpace(e.GetArg("role")) ? "@everyone" : e.GetArg("role");
var role = e.Server.FindRoles(arg).FirstOrDefault();
if (role == null) {
diff --git a/NadekoBot/Modules/Music.cs b/NadekoBot/Modules/Music.cs
index 0c0d4e22..674531eb 100644
--- a/NadekoBot/Modules/Music.cs
+++ b/NadekoBot/Modules/Music.cs
@@ -7,6 +7,7 @@ using NadekoBot.Extensions;
using System.Collections.Concurrent;
using NadekoBot.Classes.Music;
using Timer = System.Timers.Timer;
+using System.Threading.Tasks;
namespace NadekoBot.Modules {
class Music : DiscordModule {
@@ -20,19 +21,6 @@ namespace NadekoBot.Modules {
}
public Music() : base() {
- /*Timer cleaner = new Timer();
- cleaner.Elapsed += (s, e) => System.Threading.Tasks.Task.Run(() => CleanMusicPlayers());
- cleaner.Interval = 10000;
- cleaner.Start();
-
- Timer statPrinter = new Timer();
- NadekoBot.client.Connected += (s, e) => {
- if (statPrinter.Enabled) return;
- statPrinter.Elapsed += (se, ev) => { Console.WriteLine($"<<--Music-->> {musicPlayers.Count} songs playing."); musicPlayers.ForEach(kvp => Console.WriteLine(kvp.Value?.CurrentSong?.PrintStats())); Console.WriteLine("<<--Music END-->>"); };
- statPrinter.Interval = 5000;
- statPrinter.Start();
- };
- */
}
public override void Install(ModuleManager manager) {
@@ -45,9 +33,9 @@ namespace NadekoBot.Modules {
cgb.CreateCommand("n")
.Alias("next")
.Description("Goes to the next song in the queue.")
- .Do(e => {
+ .Do(async e => {
if (musicPlayers.ContainsKey(e.Server) == false) return;
- musicPlayers[e.Server].LoadNextSong();
+ await musicPlayers[e.Server].LoadNextSong();
});
cgb.CreateCommand("s")
@@ -73,67 +61,7 @@ namespace NadekoBot.Modules {
.Alias("yq")
.Description("Queue a song using keywords or link. **You must be in a voice channel**.\n**Usage**: `!m q Dream Of Venice`")
.Parameter("query", ParameterType.Unparsed)
- .Do(async e => {
- if (e.User.VoiceChannel?.Server != e.Server) {
- await e.Send(":anger: You need to be in the voice channel on this server.");
- return;
- }
- if (musicPlayers.ContainsKey(e.Server) == false)
- if (!musicPlayers.TryAdd(e.Server, new MusicControls(e.User.VoiceChannel, e))) {
- await e.Send("Failed to create a music player for this server");
- return;
- }
- if (e.GetArg("query") == null || e.GetArg("query").Length < 4)
- return;
-
- var player = musicPlayers[e.Server];
-
- if (player.SongQueue.Count > 25) {
- await e.Send("Music player supports up to 25 songs atm. Contant the owner if you think this is not enough :warning:");
- }
-
- try {
-
- Message qmsg = await e.Channel.SendMessage(":musical_note: **Searching...**");
-
- var sr = new StreamRequest(e, e.GetArg("query"), player);
-
- if (sr == null)
- throw new NullReferenceException("StreamRequest is null.");
- Message msg = null;
- sr.OnResolving += async () => {
- await qmsg.Edit($":musical_note: **Resolving**... \"{e.GetArg("query")}\"");
- };
- sr.OnResolvingFailed += async (err) => {
- await qmsg.Edit($":anger: :musical_note: **Resolving failed** for `{e.GetArg("query")}`");
- };
- sr.OnQueued += async () => {
- await qmsg.Edit($":musical_note:**Queued** {sr.Title.TrimTo(55)}");
- };
- sr.OnCompleted += async () => {
- MusicControls mc;
- if (musicPlayers.TryGetValue(e.Server, out mc)) {
- if (mc.SongQueue.Count == 0)
- mc.Stop();
- }
- await e.Send($":musical_note:**Finished playing** {sr.Title.TrimTo(55)}");
- };
- sr.OnStarted += async () => {
- if (msg == null)
- await e.Send($":musical_note:**Playing ** {sr.Title.TrimTo(55)}");
- else
- await msg.Edit($":musical_note:**Playing ** {sr.Title.TrimTo(55)}");
- qmsg?.Delete();
- };
- sr.OnBuffering += async () => {
- msg = await e.Send($":musical_note:**Buffering...** {sr.Title.TrimTo(55)}");
- };
- } catch (Exception ex) {
- Console.WriteLine();
- await e.Send($":anger: {ex.Message}");
- return;
- }
- });
+ .Do(async e => await QueueSong(e,e.GetArg("query")));
cgb.CreateCommand("lq")
.Alias("ls").Alias("lp")
@@ -141,8 +69,10 @@ namespace NadekoBot.Modules {
.Do(async e => {
if (musicPlayers.ContainsKey(e.Server) == false) await e.Send(":musical_note: No active music player.");
var player = musicPlayers[e.Server];
-
- await e.Send(":musical_note: " + player.SongQueue.Count + " videos currently queued.");
+ string toSend = ":musical_note: " + player.SongQueue.Count + " videos currently queued. ";
+ if (player.SongQueue.Count >= 25)
+ toSend += "**Song queue is full!**\n";
+ await e.Send(toSend);
int number = 1;
await e.Send(string.Join("\n", player.SongQueue.Select(v => $"**#{number++}** {v.Title.TrimTo(60)}").Take(10)));
});
@@ -156,6 +86,45 @@ namespace NadekoBot.Modules {
await e.Send($"Now Playing **{player.CurrentSong.Title}**");
});
+ cgb.CreateCommand("vol")
+ .Description("Sets the music volume 0-150%")
+ .Parameter("val", ParameterType.Required)
+ .Do(async e => {
+ if (musicPlayers.ContainsKey(e.Server) == false) return;
+ var player = musicPlayers[e.Server];
+ var arg = e.GetArg("val");
+ int volume;
+ if (!int.TryParse(arg, out volume)) {
+ await e.Send("Volume number invalid.");
+ return;
+ }
+ player.SetVolume(volume);
+ });
+
+ cgb.CreateCommand("min").Alias("mute")
+ .Description("Sets the music volume to 0%")
+ .Do(e => {
+ if (musicPlayers.ContainsKey(e.Server) == false) return;
+ var player = musicPlayers[e.Server];
+ player.SetVolume(0);
+ });
+
+ cgb.CreateCommand("max")
+ .Description("Sets the music volume to 100% (real max is actually 150%).")
+ .Do(e => {
+ if (musicPlayers.ContainsKey(e.Server) == false) return;
+ var player = musicPlayers[e.Server];
+ player.SetVolume(100);
+ });
+
+ cgb.CreateCommand("half")
+ .Description("Sets the music volume to 50%.")
+ .Do(e => {
+ if (musicPlayers.ContainsKey(e.Server) == false) return;
+ var player = musicPlayers[e.Server];
+ player.SetVolume(50);
+ });
+
cgb.CreateCommand("sh")
.Description("Shuffles the current playlist.")
.Do(async e => {
@@ -191,6 +160,19 @@ namespace NadekoBot.Modules {
await e.Send("Music status " + (setgameEnabled ? "enabled" : "disabled"));
});
+ cgb.CreateCommand("pl")
+ .Description("Queues up to 25 songs from a youtube playlist")
+ .Parameter("playlist", ParameterType.Unparsed)
+ .Do(async e => {
+ var ids = await Searches.GetVideoIDs(await Searches.GetPlaylistIdByKeyword(e.GetArg("playlist")));
+ //todo TEMPORARY SOLUTION, USE RESOLVE QUEUE IN THE FUTURE
+ await e.Send($"Attempting to queue {ids.Count} songs".SnPl(ids.Count));
+ foreach (var id in ids) {
+ Task.Run(async () => await QueueSong(e, id, true)).ConfigureAwait(false);
+ await Task.Delay(150);
+ }
+ });
+
cgb.CreateCommand("debug")
.Description("Writes some music data to console. **BOT OWNER ONLY**")
.Do(e => {
@@ -200,5 +182,67 @@ namespace NadekoBot.Modules {
});
});
}
+
+ private async Task QueueSong(CommandEventArgs e, string query, bool silent = false) {
+ if (e.User.VoiceChannel?.Server != e.Server) {
+ await e.Send(":anger: You need to be in the voice channel on this server.");
+ return;
+ }
+ if (musicPlayers.ContainsKey(e.Server) == false)
+ if (!musicPlayers.TryAdd(e.Server, new MusicControls(e.User.VoiceChannel, e))) {
+ await e.Send("Failed to create a music player for this server");
+ return;
+ }
+ if (query == null || query.Length < 4)
+ return;
+
+ var player = musicPlayers[e.Server];
+
+ if (player.SongQueue.Count >= 25) return;
+
+ try {
+ var sr = await Task.Run(() => new StreamRequest(e, query, player));
+
+ if (sr == null)
+ throw new NullReferenceException("StreamRequest is null.");
+
+ Message qmsg = null;
+ Message msg = null;
+ if (!silent) {
+ qmsg = await e.Channel.SendMessage(":musical_note: **Searching...**");
+ sr.OnResolving += async () => {
+ await qmsg.Edit($":musical_note: **Resolving**... \"{query}\"");
+ };
+ sr.OnResolvingFailed += async (err) => {
+ await qmsg.Edit($":anger: :musical_note: **Resolving failed** for `{query}`");
+ };
+ sr.OnQueued += async () => {
+ await qmsg.Edit($":musical_note:**Queued** {sr.Title.TrimTo(55)}");
+ };
+ }
+ sr.OnCompleted += async () => {
+ MusicControls mc;
+ if (musicPlayers.TryGetValue(e.Server, out mc)) {
+ if (mc.SongQueue.Count == 0)
+ mc.Stop();
+ }
+ await e.Send($":musical_note:**Finished playing** {sr.Title.TrimTo(55)}");
+ };
+ sr.OnStarted += async () => {
+ if (msg == null)
+ await e.Send($":musical_note:**Playing ** {sr.Title.TrimTo(55)} **Volume:** {(int)(player.Volume * 100)}%");
+ else
+ await msg.Edit($":musical_note:**Playing ** {sr.Title.TrimTo(55)} **Volume:** {(int)(player.Volume * 100)}%");
+ qmsg?.Delete();
+ };
+ sr.OnBuffering += async () => {
+ msg = await e.Send($":musical_note:**Buffering...** {sr.Title.TrimTo(55)}");
+ };
+ } catch (Exception ex) {
+ Console.WriteLine();
+ await e.Send($":anger: {ex.Message}");
+ return;
+ }
+ }
}
}
diff --git a/NadekoBot/Modules/Searches.cs b/NadekoBot/Modules/Searches.cs
index 8c9cac5c..8c203c34 100644
--- a/NadekoBot/Modules/Searches.cs
+++ b/NadekoBot/Modules/Searches.cs
@@ -24,12 +24,12 @@ namespace NadekoBot.Modules {
commands.ForEach(cmd => cmd.Init(cgb));
cgb.CreateCommand("~yt")
- .Parameter("query", Discord.Commands.ParameterType.Unparsed)
- .Description("Queries youtubes and embeds the first result")
+ .Parameter("query", ParameterType.Unparsed)
+ .Description("Searches youtubes and shows the first result")
.Do(async e => {
if (!(await ValidateQuery(e.Channel, e.GetArg("query")))) return;
- var str = ShortenUrl(FindYoutubeUrlByKeywords(e.GetArg("query")));
+ var str = await ShortenUrl(await FindYoutubeUrlByKeywords(e.GetArg("query")));
if (string.IsNullOrEmpty(str.Trim())) {
await e.Send("Query failed");
return;
@@ -39,12 +39,12 @@ namespace NadekoBot.Modules {
cgb.CreateCommand("~ani")
.Alias("~anime").Alias("~aq")
- .Parameter("query", Discord.Commands.ParameterType.Unparsed)
+ .Parameter("query", ParameterType.Unparsed)
.Description("Queries anilist for an anime and shows the first result.")
.Do(async e => {
if (!(await ValidateQuery(e.Channel, e.GetArg("query")))) return;
- var result = GetAnimeQueryResultLink(e.GetArg("query"));
+ var result = await GetAnimeQueryResultLink(e.GetArg("query"));
if (result == null) {
await e.Send("Failed to find that anime.");
return;
@@ -55,12 +55,12 @@ namespace NadekoBot.Modules {
cgb.CreateCommand("~mang")
.Alias("~manga").Alias("~mq")
- .Parameter("query", Discord.Commands.ParameterType.Unparsed)
+ .Parameter("query", ParameterType.Unparsed)
.Description("Queries anilist for a manga and shows the first result.")
.Do(async e => {
if (!(await ValidateQuery(e.Channel, e.GetArg("query")))) return;
- var result = GetMangaQueryResultLink(e.GetArg("query"));
+ var result = await GetMangaQueryResultLink(e.GetArg("query"));
if (result == null) {
await e.Send("Failed to find that anime.");
return;
@@ -105,8 +105,8 @@ namespace NadekoBot.Modules {
string tag = e.GetArg("tag");
if (tag == null)
tag = "";
- await e.Send(":heart: Gelbooru: " + GetGelbooruImageLink(tag));
- await e.Send(":heart: Danbooru: " + GetDanbooruImageLink(tag));
+ await e.Send(":heart: Gelbooru: " + await GetGelbooruImageLink(tag));
+ await e.Send(":heart: Danbooru: " + await GetDanbooruImageLink(tag));
});
cgb.CreateCommand("~danbooru")
.Description("Shows a random hentai image from danbooru with a given tag. Tag is optional but preffered.\n**Usage**: ~hentai yuri")
@@ -115,7 +115,7 @@ namespace NadekoBot.Modules {
string tag = e.GetArg("tag");
if (tag == null)
tag = "";
- await e.Send(GetDanbooruImageLink(tag));
+ await e.Send(await GetDanbooruImageLink(tag));
});
cgb.CreateCommand("~gelbooru")
.Description("Shows a random hentai image from gelbooru with a given tag. Tag is optional but preffered.\n**Usage**: ~hentai yuri")
@@ -124,7 +124,7 @@ namespace NadekoBot.Modules {
string tag = e.GetArg("tag");
if (tag == null)
tag = "";
- await e.Send(GetGelbooruImageLink(tag));
+ await e.Send(await GetGelbooruImageLink(tag));
});
cgb.CreateCommand("~cp")
.Description("We all know where this will lead you to.")
@@ -137,21 +137,21 @@ namespace NadekoBot.Modules {
.Parameter("ffs", ParameterType.Unparsed)
.Do(async e => {
if (e.GetArg("ffs") == null || e.GetArg("ffs").Length < 1) return;
- await e.Send($"http://lmgtfy.com/?q={ Uri.EscapeUriString(e.GetArg("ffs").ToString()) }".ShortenUrl());
+ await e.Send(await $"http://lmgtfy.com/?q={ Uri.EscapeUriString(e.GetArg("ffs").ToString()) }".ShortenUrl());
});
});
}
- public static string MakeRequestAndGetResponse(string v) =>
- new StreamReader(((HttpWebRequest)WebRequest.Create(v)).GetResponse().GetResponseStream()).ReadToEnd();
+ public static async Task GetResponseAsync(string v) =>
+ await new StreamReader((await ((HttpWebRequest)WebRequest.Create(v)).GetResponseAsync()).GetResponseStream()).ReadToEndAsync();
private string token = "";
- private AnimeResult GetAnimeQueryResultLink(string query) {
+ private async Task GetAnimeQueryResultLink(string query) {
try {
var cl = new RestSharp.RestClient("http://anilist.co/api");
var rq = new RestSharp.RestRequest("/auth/access_token", RestSharp.Method.POST);
- RefreshToken();
+ RefreshAnilistToken();
rq = new RestSharp.RestRequest("/anime/search/" + Uri.EscapeUriString(query));
rq.AddParameter("access_token", token);
@@ -160,15 +160,15 @@ namespace NadekoBot.Modules {
rq = new RestSharp.RestRequest("anime/" + smallObj["id"]);
rq.AddParameter("access_token", token);
- return JsonConvert.DeserializeObject(cl.Execute(rq).Content);
+ return await Task.Run(() => JsonConvert.DeserializeObject(cl.Execute(rq).Content));
} catch (Exception) {
return null;
}
}
-
- private MangaResult GetMangaQueryResultLink(string query) {
+ //todo kick out RestSharp and make it truly async
+ private async Task GetMangaQueryResultLink(string query) {
try {
- RefreshToken();
+ RefreshAnilistToken();
var cl = new RestSharp.RestClient("http://anilist.co/api");
var rq = new RestSharp.RestRequest("/auth/access_token", RestSharp.Method.POST);
@@ -179,27 +179,31 @@ namespace NadekoBot.Modules {
rq = new RestSharp.RestRequest("manga/" + smallObj["id"]);
rq.AddParameter("access_token", token);
- return JsonConvert.DeserializeObject(cl.Execute(rq).Content);
+ return await Task.Run(() => JsonConvert.DeserializeObject(cl.Execute(rq).Content));
} catch (Exception ex) {
Console.WriteLine(ex.ToString());
return null;
}
}
- private void RefreshToken() {
- var cl = new RestSharp.RestClient("http://anilist.co/api");
- var rq = new RestSharp.RestRequest("/auth/access_token", RestSharp.Method.POST);
- rq.AddParameter("grant_type", "client_credentials");
- rq.AddParameter("client_id", "kwoth-w0ki9");
- rq.AddParameter("client_secret", "Qd6j4FIAi1ZK6Pc7N7V4Z");
- var exec = cl.Execute(rq);
- /*
- Console.WriteLine($"Server gave me content: { exec.Content }\n{ exec.ResponseStatus } -> {exec.ErrorMessage} ");
- Console.WriteLine($"Err exception: {exec.ErrorException}");
- Console.WriteLine($"Inner: {exec.ErrorException.InnerException}");
- */
+ private void RefreshAnilistToken() {
+ try {
+ var cl = new RestSharp.RestClient("http://anilist.co/api");
+ var rq = new RestSharp.RestRequest("/auth/access_token", RestSharp.Method.POST);
+ rq.AddParameter("grant_type", "client_credentials");
+ rq.AddParameter("client_id", "kwoth-w0ki9");
+ rq.AddParameter("client_secret", "Qd6j4FIAi1ZK6Pc7N7V4Z");
+ var exec = cl.Execute(rq);
+ /*
+ Console.WriteLine($"Server gave me content: { exec.Content }\n{ exec.ResponseStatus } -> {exec.ErrorMessage} ");
+ Console.WriteLine($"Err exception: {exec.ErrorException}");
+ Console.WriteLine($"Inner: {exec.ErrorException.InnerException}");
+ */
- token = JObject.Parse(exec.Content)["access_token"].ToString();
+ token = JObject.Parse(exec.Content)["access_token"].ToString();
+ } catch (Exception ex) {
+ Console.WriteLine($"Failed refreshing anilist token:\n {ex}");
+ }
}
private static async Task ValidateQuery(Discord.Channel ch, string query) {
@@ -210,7 +214,7 @@ namespace NadekoBot.Modules {
return true;
}
- public static string FindYoutubeUrlByKeywords(string v) {
+ public static async Task FindYoutubeUrlByKeywords(string v) {
if (NadekoBot.GoogleAPIKey == "" || NadekoBot.GoogleAPIKey == null) {
Console.WriteLine("ERROR: No google api key found. Playing `Never gonna give you up`.");
return @"https://www.youtube.com/watch?v=dQw4w9WgXcQ";
@@ -223,21 +227,19 @@ namespace NadekoBot.Modules {
return str;
}
-
WebRequest wr = WebRequest.Create("https://www.googleapis.com/youtube/v3/search?part=snippet&maxResults=1&q=" + Uri.EscapeDataString(v) + "&key=" + NadekoBot.GoogleAPIKey);
- var sr = new StreamReader(wr.GetResponse().GetResponseStream());
+ var sr = new StreamReader((await wr.GetResponseAsync()).GetResponseStream());
- dynamic obj = JObject.Parse(sr.ReadToEnd());
- string toReturn = "http://www.youtube.com/watch?v=" + obj.items[0].id.videoId.ToString();
- return toReturn;
+ dynamic obj = JObject.Parse(await sr.ReadToEndAsync());
+ return "http://www.youtube.com/watch?v=" + obj.items[0].id.videoId.ToString();
} catch (Exception ex) {
Console.WriteLine($"Error in findyoutubeurl: {ex.Message}");
return string.Empty;
}
}
- public static string GetPlaylistIdByKeyword(string v) {
+ public static async Task GetPlaylistIdByKeyword(string v) {
if (NadekoBot.GoogleAPIKey == "" || NadekoBot.GoogleAPIKey == null) {
Console.WriteLine("ERROR: No google api key found. Playing `Never gonna give you up`.");
return string.Empty;
@@ -245,33 +247,32 @@ namespace NadekoBot.Modules {
try {
WebRequest wr = WebRequest.Create($"https://www.googleapis.com/youtube/v3/search?part=snippet&maxResults=1&q={Uri.EscapeDataString(v)}&type=playlist&key={NadekoBot.creds.GoogleAPIKey}");
- var sr = new StreamReader(wr.GetResponse().GetResponseStream());
+ var sr = new StreamReader((await wr.GetResponseAsync()).GetResponseStream());
- dynamic obj = JObject.Parse(sr.ReadToEnd());
- string toReturn = obj.items[0].id.playlistId.ToString();
- return toReturn;
+ dynamic obj = JObject.Parse(await sr.ReadToEndAsync());
+ return obj.items[0].id.playlistId.ToString();
} catch (Exception ex) {
Console.WriteLine($"Error in GetPlaylistId: {ex.Message}");
return string.Empty;
}
}
- public static List GetVideoIDs(string v) {
+ public static async Task> GetVideoIDs(string v) {
List toReturn = new List();
if (NadekoBot.GoogleAPIKey == "" || NadekoBot.GoogleAPIKey == null) {
Console.WriteLine("ERROR: No google api key found. Playing `Never gonna give you up`.");
return toReturn;
}
try {
-
- WebRequest wr = WebRequest.Create($"https://www.googleapis.com/youtube/v3/playlistItems?part=contentDetails&maxResults={25}&playlistId=PL8lZieNFgOdmrNGTqwjqYJpJ_2nw_O_M2&key={ NadekoBot.creds.GoogleAPIKey }");
- var sr = new StreamReader(wr.GetResponse().GetResponseStream());
+ WebRequest wr = WebRequest.Create($"https://www.googleapis.com/youtube/v3/playlistItems?part=contentDetails&maxResults={25}&playlistId={v}&key={ NadekoBot.creds.GoogleAPIKey }");
- dynamic obj = JObject.Parse(sr.ReadToEnd());
+ var sr = new StreamReader((await wr.GetResponseAsync()).GetResponseStream());
+
+ dynamic obj = JObject.Parse(await sr.ReadToEndAsync());
foreach (var item in obj.items) {
- toReturn.Add("http://www.youtube.com/watch?v=" + item.id.contentDetails.videoId);
+ toReturn.Add("http://www.youtube.com/watch?v=" + item.contentDetails.videoId);
}
return toReturn;
} catch (Exception ex) {
@@ -281,30 +282,30 @@ namespace NadekoBot.Modules {
}
- public string GetDanbooruImageLink(string tag) {
+ public async Task GetDanbooruImageLink(string tag) {
try {
var rng = new Random();
if (tag == "loli") //loli doesn't work for some reason atm
tag = "flat_chest";
- var webpage = MakeRequestAndGetResponse($"http://danbooru.donmai.us/posts?page={ rng.Next(0, 30) }&tags={ tag.Replace(" ", "_") }");
+ var webpage = await GetResponseAsync($"http://danbooru.donmai.us/posts?page={ rng.Next(0, 30) }&tags={ tag.Replace(" ", "_") }");
var matches = Regex.Matches(webpage, "data-large-file-url=\"(?.*?)\"");
- return $"http://danbooru.donmai.us{ matches[rng.Next(0, matches.Count)].Groups["id"].Value }".ShortenUrl();
+ return await $"http://danbooru.donmai.us{ matches[rng.Next(0, matches.Count)].Groups["id"].Value }".ShortenUrl();
} catch (Exception) {
return null;
}
}
- public string GetGelbooruImageLink(string tag) {
+ public async Task GetGelbooruImageLink(string tag) {
try {
var rng = new Random();
var url = $"http://gelbooru.com/index.php?page=post&s=list&pid={ rng.Next(0, 15) * 42 }&tags={ tag.Replace(" ", "_") }";
- var webpage = MakeRequestAndGetResponse(url); // first extract the post id and go to that posts page
+ var webpage = await GetResponseAsync(url); // first extract the post id and go to that posts page
var matches = Regex.Matches(webpage, "span id=\"s(?\\d*)\"");
var postLink = $"http://gelbooru.com/index.php?page=post&s=view&id={ matches[rng.Next(0, matches.Count)].Groups["id"].Value }";
- webpage = MakeRequestAndGetResponse(postLink);
+ webpage = await GetResponseAsync(postLink);
//now extract the image from post page
var match = Regex.Match(webpage, "\"(?http://simg4.gelbooru.com//images.*?)\"");
return match.Groups["url"].Value;
@@ -313,21 +314,21 @@ namespace NadekoBot.Modules {
}
}
- public static string ShortenUrl(string url) {
+ public static async Task ShortenUrl(string url) {
if (NadekoBot.GoogleAPIKey == null || NadekoBot.GoogleAPIKey == "") return url;
-
- var httpWebRequest = (HttpWebRequest)WebRequest.Create("https://www.googleapis.com/urlshortener/v1/url?key=" + NadekoBot.GoogleAPIKey);
- httpWebRequest.ContentType = "application/json";
- httpWebRequest.Method = "POST";
-
- using (var streamWriter = new StreamWriter(httpWebRequest.GetRequestStream())) {
- string json = "{\"longUrl\":\"" + url + "\"}";
- streamWriter.Write(json);
- }
try {
- var httpResponse = (HttpWebResponse)httpWebRequest.GetResponse();
+ var httpWebRequest = (HttpWebRequest)WebRequest.Create("https://www.googleapis.com/urlshortener/v1/url?key=" + NadekoBot.GoogleAPIKey);
+ httpWebRequest.ContentType = "application/json";
+ httpWebRequest.Method = "POST";
+
+ using (var streamWriter = new StreamWriter(await httpWebRequest.GetRequestStreamAsync())) {
+ string json = "{\"longUrl\":\"" + url + "\"}";
+ streamWriter.Write(json);
+ }
+
+ var httpResponse = (await httpWebRequest.GetResponseAsync()) as HttpWebResponse;
using (var streamReader = new StreamReader(httpResponse.GetResponseStream())) {
- var responseText = streamReader.ReadToEnd();
+ string responseText = await streamReader.ReadToEndAsync();
string MATCH_PATTERN = @"""id"": ?""(?.+)""";
return Regex.Match(responseText, MATCH_PATTERN).Groups["id"].Value;
}