diff --git a/DockerGuide.md b/DockerGuide.md new file mode 100644 index 00000000..b079c6f3 --- /dev/null +++ b/DockerGuide.md @@ -0,0 +1,47 @@ +## Docker guide with digitalocean + +#####Prerequisites: +- Digital ocean account (you can use my reflink to support the project and get 10$ after you register http://m.do.co/c/46b4d3d44795/ ) +- Putty (get it here http://www.chiark.greenend.org.uk/~sgtatham/putty/download.html) +- A bot account - (follow http://discord.kongslien.net/guide.html) +- Common sense + +Click on the create droplet button +![img](http://i.imgur.com/g2ayOcC.png) + +pick one click apps and select docker on 14.04 + +![img](http://imgur.com/065Xkme.png) + +- pick any droplet size you want (5$ will work ok-ish on a few servers) +- pick location closest to your discord server's location +- Pick a hostname +![img](http://imgur.com/ifPKB6p.png) + +- click create + +You will get an email from digitalocean with your creds now. + +Open putty and type ip adress **you got in your email** with port 22 + +![img](http://imgur.com/Mh5ehsh.png) + +console will open and you will be prompted for a username, type `root` +type in the password you got in the email +confirm the password you just typed in +type in the new password +confirm new password + +when you are successfully logged in, type +`docker run --name nadeko -v /nadeko:/config uirel/nadeko` + +wait for it to download and at one point it is going to start throwing errors due to credentials.json being empty +CTRL+C to exit that +type `docker stop nadeko` +type `nano /nadeko/credentials.json` and type in your credentials +CTRL+X then CTRL+Y to save +type `docker start nadeko` + +Your bot is running, enjoy + +*When you want to update the bot, just type `docker restart nadeko` as it always downloads latest prerelease* diff --git a/NadekoBot/Classes/SearchHelper.cs b/NadekoBot/Classes/SearchHelper.cs index 1db124e0..a0a59e9b 100644 --- a/NadekoBot/Classes/SearchHelper.cs +++ b/NadekoBot/Classes/SearchHelper.cs @@ -175,7 +175,7 @@ namespace NadekoBot.Classes return null; } - public static async Task GetRelatedVideoId(string id) + public static async Task> GetRelatedVideoIds(string id, int count = 1) { if (string.IsNullOrWhiteSpace(id)) throw new ArgumentNullException(nameof(id)); @@ -186,20 +186,14 @@ namespace NadekoBot.Classes } var response = await GetResponseStringAsync( $"https://www.googleapis.com/youtube/v3/search?" + - $"part=snippet&maxResults=1&type=video" + + $"part=snippet&maxResults={count}&type=video" + $"&relatedToVideoId={id}" + $"&key={NadekoBot.Creds.GoogleAPIKey}").ConfigureAwait(false); JObject obj = JObject.Parse(response); var data = JsonConvert.DeserializeObject(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; + return data.items.Select(v => "http://www.youtube.com/watch?v=" + v.id.videoId); } public static async Task GetPlaylistIdByKeyword(string query) diff --git a/NadekoBot/Modules/Administration/Commands/AutoAssignRole.cs b/NadekoBot/Modules/Administration/Commands/AutoAssignRole.cs index b1ed632c..7ccd0e0e 100644 --- a/NadekoBot/Modules/Administration/Commands/AutoAssignRole.cs +++ b/NadekoBot/Modules/Administration/Commands/AutoAssignRole.cs @@ -34,7 +34,7 @@ namespace NadekoBot.Modules.Administration.Commands { cgb.CreateCommand(Module.Prefix + "autoassignrole") .Alias(Module.Prefix + "aar") - .Description($"Automaticaly assigns a specified role to every user who joins the server. Type `{Prefix}aar` to disable, `{Prefix}aar Role Name` to enable") + .Description($"Automaticaly assigns a specified role to every user who joins the server. |`{Prefix}aar` to disable, `{Prefix}aar Role Name` to enable") .Parameter("role", ParameterType.Unparsed) .AddCheck(new SimpleCheckers.ManageRoles()) .Do(async e => diff --git a/NadekoBot/Modules/Administration/Commands/LogCommand.cs b/NadekoBot/Modules/Administration/Commands/LogCommand.cs index 08212b62..db693ae3 100644 --- a/NadekoBot/Modules/Administration/Commands/LogCommand.cs +++ b/NadekoBot/Modules/Administration/Commands/LogCommand.cs @@ -4,7 +4,10 @@ using NadekoBot.Classes; using NadekoBot.Extensions; using NadekoBot.Modules.Permissions.Classes; using System; +using System.Collections.Concurrent; +using System.Collections.Generic; using System.Linq; +using System.Threading.Tasks; namespace NadekoBot.Modules.Administration.Commands { @@ -12,6 +15,8 @@ namespace NadekoBot.Modules.Administration.Commands { private string prettyCurrentTime => $"ใ€{DateTime.Now:HH:mm:ss}ใ€‘"; + private ConcurrentBag> voicePresenceUpdates = new ConcurrentBag>(); + public LogCommand(DiscordModule module) : base(module) { NadekoBot.Client.MessageReceived += MsgRecivd; @@ -45,6 +50,36 @@ namespace NadekoBot.Modules.Administration.Commands } catch { } }; + + // start the userpresence queue + + NadekoBot.OnReady += () => Task.Run(async () => + { + while (true) + { + var toSend = new Dictionary(); + //take everything from the queue and merge the messages which are going to the same channel + KeyValuePair item; + while (voicePresenceUpdates.TryTake(out item)) + { + if (toSend.ContainsKey(item.Key)) + { + toSend[item.Key] = toSend[item.Key] + Environment.NewLine + item.Value; + } + else + { + toSend.Add(item.Key, item.Value); + } + } + //send merged messages to each channel + foreach (var k in toSend) + { + try { await k.Key.SendMessage(Environment.NewLine + k.Value).ConfigureAwait(false); } catch { } + } + + await Task.Delay(5000); + } + }); } private async void ChannelUpdated(object sender, ChannelUpdatedEventArgs e) @@ -177,13 +212,13 @@ namespace NadekoBot.Modules.Administration.Commands if (!string.IsNullOrWhiteSpace(e.Message.Text)) { await ch.SendMessage( - $@"๐Ÿ•”`{prettyCurrentTime}` **New Message** `#{e.Channel.Name}` + $@"๐Ÿ•”`{prettyCurrentTime}` **New Message** `#{e.Channel.Name}` ๐Ÿ‘ค`{e.User?.ToString() ?? ("NULL")}` {e.Message.Text.Unmention()}").ConfigureAwait(false); } else { await ch.SendMessage( - $@"๐Ÿ•”`{prettyCurrentTime}` **File Uploaded** `#{e.Channel.Name}` + $@"๐Ÿ•”`{prettyCurrentTime}` **File Uploaded** `#{e.Channel.Name}` ๐Ÿ‘ค`{e.User?.ToString() ?? ("NULL")}` {e.Message.Attachments.FirstOrDefault()?.ProxyUrl}").ConfigureAwait(false); } @@ -206,13 +241,13 @@ namespace NadekoBot.Modules.Administration.Commands if (!string.IsNullOrWhiteSpace(e.Message.Text)) { await ch.SendMessage( - $@"๐Ÿ•”`{prettyCurrentTime}` **Message** ๐Ÿšฎ `#{e.Channel.Name}` + $@"๐Ÿ•”`{prettyCurrentTime}` **Message** ๐Ÿšฎ `#{e.Channel.Name}` ๐Ÿ‘ค`{e.User?.ToString() ?? ("NULL")}` {e.Message.Text.Unmention()}").ConfigureAwait(false); } else { await ch.SendMessage( - $@"๐Ÿ•”`{prettyCurrentTime}` **File Deleted** `#{e.Channel.Name}` + $@"๐Ÿ•”`{prettyCurrentTime}` **File Deleted** `#{e.Channel.Name}` ๐Ÿ‘ค`{e.User?.ToString() ?? ("NULL")}` {e.Message.Attachments.FirstOrDefault()?.ProxyUrl}").ConfigureAwait(false); } } @@ -232,7 +267,7 @@ namespace NadekoBot.Modules.Administration.Commands if ((ch = e.Server.TextChannels.Where(tc => tc.Id == chId).FirstOrDefault()) == null) return; await ch.SendMessage( -$@"๐Ÿ•”`{prettyCurrentTime}` **Message** ๐Ÿ“ `#{e.Channel.Name}` + $@"๐Ÿ•”`{prettyCurrentTime}` **Message** ๐Ÿ“ `#{e.Channel.Name}` ๐Ÿ‘ค`{e.User?.ToString() ?? ("NULL")}` `Old:` {e.Before.Text.Unmention()} `New:` {e.After.Text.Unmention()}").ConfigureAwait(false); @@ -252,7 +287,7 @@ $@"๐Ÿ•”`{prettyCurrentTime}` **Message** ๐Ÿ“ `#{e.Channel.Name}` { if (e.Before.Status != e.After.Status) { - await ch.SendMessage($"`{prettyCurrentTime}`**{e.Before.Name}** is now **{e.After.Status}**.").ConfigureAwait(false); + voicePresenceUpdates.Add(new KeyValuePair(ch, $"`{prettyCurrentTime}`**{e.Before.Name}** is now **{e.After.Status}**.")); } } } @@ -371,8 +406,8 @@ $@"๐Ÿ•”`{prettyCurrentTime}` **Message** ๐Ÿ“ `#{e.Channel.Name}` Channel ch; if ((ch = e.Server.TextChannels.Where(tc => tc.Id == chId).FirstOrDefault()) == null) return; - - SpecificConfigurations.Default.Of (e.Server.Id).LogServerChannel = null; + + SpecificConfigurations.Default.Of(e.Server.Id).LogServerChannel = null; await e.Channel.SendMessage($"โ—**NO LONGER LOGGING IN {ch.Mention} CHANNEL**โ—").ConfigureAwait(false); }); diff --git a/NadekoBot/Modules/Administration/Commands/MessageRepeater.cs b/NadekoBot/Modules/Administration/Commands/MessageRepeater.cs index b26c2444..2ea4346d 100644 --- a/NadekoBot/Modules/Administration/Commands/MessageRepeater.cs +++ b/NadekoBot/Modules/Administration/Commands/MessageRepeater.cs @@ -57,7 +57,7 @@ namespace NadekoBot.Modules.Administration.Commands cgb.CreateCommand(Module.Prefix + "repeatinvoke") .Alias(Module.Prefix + "repinv") - .Description("Immediately shows the repeat message and restarts the timer. | `{Prefix}repinv`") + .Description($"Immediately shows the repeat message and restarts the timer. | `{Prefix}repinv`") .AddCheck(SimpleCheckers.ManageMessages()) .Do(async e => { diff --git a/NadekoBot/Modules/Games/Commands/BetrayGame.cs b/NadekoBot/Modules/Games/Commands/BetrayGame.cs index 604664a2..74b98bf6 100644 --- a/NadekoBot/Modules/Games/Commands/BetrayGame.cs +++ b/NadekoBot/Modules/Games/Commands/BetrayGame.cs @@ -20,7 +20,7 @@ namespace NadekoBot.Modules.Games.Commands cgb.CreateCommand(Module.Prefix + "betray") .Description("BETRAY GAME. Betray nadeko next turn." + "If Nadeko cooperates - you get extra points, nadeko loses a LOT." + - "If Nadeko betrays - you both lose some points. | `{Prefix}betray`") + $"If Nadeko betrays - you both lose some points. | `{Prefix}betray`") .Do(async e => { await ReceiveAnswer(e, Answers.Betray).ConfigureAwait(false); @@ -29,7 +29,7 @@ namespace NadekoBot.Modules.Games.Commands cgb.CreateCommand(Module.Prefix + "cooperate") .Description("BETRAY GAME. Cooperate with nadeko next turn." + "If Nadeko cooperates - you both get bonus points." + - "If Nadeko betrays - you lose A LOT, nadeko gets extra. | `{Prefix}cooperater`") + $"If Nadeko betrays - you lose A LOT, nadeko gets extra. | `{Prefix}cooperater`") .Do(async e => { diff --git a/NadekoBot/Modules/Help/Commands/HelpCommand.cs b/NadekoBot/Modules/Help/Commands/HelpCommand.cs index 6d6826a0..d0ba292b 100644 --- a/NadekoBot/Modules/Help/Commands/HelpCommand.cs +++ b/NadekoBot/Modules/Help/Commands/HelpCommand.cs @@ -48,12 +48,11 @@ namespace NadekoBot.Classes.Help.Commands public Action DoGitFunc() => e => { string helpstr = -$@"######For more information and how to setup your own NadekoBot, go to: **http://github.com/Kwoth/NadekoBot/** -######You can donate on patreon: `https://patreon.com/nadekobot` +$@"######For more information and how to setup your own NadekoBot, go to: +######You can donate on patreon: ######or paypal: `nadekodiscordbot@gmail.com` -#NadekoBot List Of Commands -Version: `{NadekoStats.Instance.BotVersion}`"; +#NadekoBot List Of Commands "; string lastCategory = ""; @@ -81,7 +80,7 @@ Version: `{NadekoStats.Instance.BotVersion}`"; { cgb.CreateCommand(Module.Prefix + "h") .Alias(Module.Prefix + "help", NadekoBot.BotMention + " help", NadekoBot.BotMention + " h", "~h") - .Description("Either shows a help for a single command, or PMs you help link if no arguments are specified. | `-h !m q` or just `-h` ") + .Description($"Either shows a help for a single command, or PMs you help link if no arguments are specified. | `{Prefix}h !m q` or just `{Prefix}h` ") .Parameter("command", ParameterType.Unparsed) .Do(HelpFunc()); cgb.CreateCommand(Module.Prefix + "hgit") @@ -103,7 +102,7 @@ Version: `{NadekoStats.Instance.BotVersion}`"; cgb.CreateCommand(Module.Prefix + "donate") .Alias("~donate") - .Description("Instructions for helping the project! | `{Prefix}donate` or `~donate`") + .Description($"Instructions for helping the project! | `{Prefix}donate` or `~donate`") .Do(async e => { await e.Channel.SendMessage( diff --git a/NadekoBot/Modules/Help/HelpModule.cs b/NadekoBot/Modules/Help/HelpModule.cs index 1e2afb23..45e4dc76 100644 --- a/NadekoBot/Modules/Help/HelpModule.cs +++ b/NadekoBot/Modules/Help/HelpModule.cs @@ -29,7 +29,7 @@ namespace NadekoBot.Modules.Help cgb.CreateCommand(Prefix + "modules") .Alias(".modules") - .Description("List all bot modules. | `{Prefix}modules` or `.modules`") + .Description($"List all bot modules. | `{Prefix}modules` or `.modules`") .Do(async e => { await e.Channel.SendMessage("`List of modules:` \nโ€ข " + string.Join("\nโ€ข ", NadekoBot.Client.GetService().Modules.Select(m => m.Name)) + $"\n`Type \"{Prefix}commands module_name\" to get a list of commands in that module.`") @@ -38,7 +38,7 @@ namespace NadekoBot.Modules.Help cgb.CreateCommand(Prefix + "commands") .Alias(".commands") - .Description("List all of the bot's commands from a certain module. | `{Prefix}commands` or `.commands`") + .Description($"List all of the bot's commands from a certain module. | `{Prefix}commands` or `.commands`") .Parameter("module", ParameterType.Unparsed) .Do(async e => { diff --git a/NadekoBot/Modules/Music/Classes/MusicControls.cs b/NadekoBot/Modules/Music/Classes/MusicControls.cs index 847070eb..e13239cf 100644 --- a/NadekoBot/Modules/Music/Classes/MusicControls.cs +++ b/NadekoBot/Modules/Music/Classes/MusicControls.cs @@ -34,7 +34,7 @@ namespace NadekoBot.Modules.Music.Classes public IReadOnlyCollection Playlist => playlist; public Song CurrentSong { get; private set; } - private CancellationTokenSource SongCancelSource { get; set; } + public CancellationTokenSource SongCancelSource { get; private set; } private CancellationToken cancelToken { get; set; } public bool Paused { get; set; } diff --git a/NadekoBot/Modules/Music/Classes/Song.cs b/NadekoBot/Modules/Music/Classes/Song.cs index 08be13b8..d235776a 100644 --- a/NadekoBot/Modules/Music/Classes/Song.cs +++ b/NadekoBot/Modules/Music/Classes/Song.cs @@ -32,7 +32,6 @@ namespace NadekoBot.Modules.Music.Classes public SongInfo SongInfo { get; } public string QueuerName { get; set; } - private bool bufferingCompleted { get; set; } = false; public MusicPlayer MusicPlayer { get; set; } public string PrettyCurrentTime() @@ -73,78 +72,22 @@ namespace NadekoBot.Modules.Music.Classes return this; } - private Task BufferSong(string filename, CancellationToken cancelToken) => - Task.Factory.StartNew(async () => - { - Process p = null; - try - { - p = Process.Start(new ProcessStartInfo - { - FileName = "ffmpeg", - Arguments = $"-ss {skipTo} -i {SongInfo.Uri} -f s16le -ar 48000 -ac 2 pipe:1 -loglevel quiet", - UseShellExecute = false, - RedirectStandardOutput = true, - RedirectStandardError = false, - CreateNoWindow = true, - }); - var prebufferSize = 100ul.MiB(); - using (var outStream = new FileStream(filename, FileMode.Append, FileAccess.Write, FileShare.Read)) - { - byte[] buffer = new byte[81920]; - int bytesRead; - while ((bytesRead = await p.StandardOutput.BaseStream.ReadAsync(buffer, 0, buffer.Length, cancelToken).ConfigureAwait(false)) != 0) - { - await outStream.WriteAsync(buffer, 0, bytesRead, cancelToken).ConfigureAwait(false); - while ((ulong)outStream.Length - bytesSent > prebufferSize) - await Task.Delay(100, cancelToken); - } - } - - bufferingCompleted = true; - } - catch (System.ComponentModel.Win32Exception) { - var oldclr = Console.ForegroundColor; - Console.ForegroundColor = ConsoleColor.Red; - Console.WriteLine(@"You have not properly installed or configured FFMPEG. -Please install and configure FFMPEG to play music. -Check the guides for your platform on how to setup ffmpeg correctly: - Windows Guide: https://goo.gl/SCv72y - Linux Guide: https://goo.gl/rRhjCp"); - Console.ForegroundColor = oldclr; - } - catch (Exception ex) - { - Console.WriteLine($"Buffering stopped: {ex.Message}"); - } - finally - { - Console.WriteLine($"Buffering done."); - if (p != null) - { - try - { - p.Kill(); - } - catch { } - p.Dispose(); - } - } - }, TaskCreationOptions.LongRunning); - internal async Task Play(IAudioClient voiceClient, CancellationToken cancelToken) { var filename = Path.Combine(MusicModule.MusicDataPath, DateTime.Now.UnixTimestamp().ToString()); - var bufferTask = BufferSong(filename, cancelToken).ConfigureAwait(false); + SongBuffer sb = new SongBuffer(filename, SongInfo, skipTo); + var bufferTask = sb.BufferSong(cancelToken).ConfigureAwait(false); - var inStream = new FileStream(filename, FileMode.OpenOrCreate, FileAccess.Read, FileShare.Write); + var inStream = new FileStream(sb.GetNextFile(), FileMode.OpenOrCreate, FileAccess.Read, FileShare.Write); ; bytesSent = 0; try { - var prebufferingTask = CheckPrebufferingAsync(inStream, cancelToken); + var attempt = 0; + + var prebufferingTask = CheckPrebufferingAsync(inStream, sb, cancelToken); var sw = new Stopwatch(); sw.Start(); var t = await Task.WhenAny(prebufferingTask, Task.Delay(5000, cancelToken)); @@ -162,7 +105,6 @@ Check the guides for your platform on how to setup ffmpeg correctly: Console.WriteLine("Prebuffering successfully completed in "+ sw.Elapsed); const int blockSize = 3840; - var attempt = 0; byte[] buffer = new byte[blockSize]; while (!cancelToken.IsCancellationRequested) { @@ -173,14 +115,31 @@ Check the guides for your platform on how to setup ffmpeg correctly: { bytesSent += (ulong)read; } - if (read == 0) - if (attempt++ == 20) + if (read < blockSize) + { + if (sb.IsNextFileReady()) { - voiceClient.Wait(); - break; + inStream.Dispose(); + inStream = new FileStream(sb.GetNextFile(), FileMode.Open, FileAccess.Read, FileShare.Write); + read += inStream.Read(buffer, read, buffer.Length - read); + attempt = 0; + } + if (read == 0) + { + if (sb.BufferingCompleted) + break; + if (attempt++ == 20) + { + voiceClient.Wait(); + MusicPlayer.SongCancelSource.Cancel(); + break; + } + else + await Task.Delay(100, cancelToken).ConfigureAwait(false); } else - await Task.Delay(100, cancelToken).ConfigureAwait(false); + attempt = 0; + } else attempt = 0; @@ -195,14 +154,16 @@ Check the guides for your platform on how to setup ffmpeg correctly: { await bufferTask; await Task.Run(() => voiceClient.Clear()); - inStream.Dispose(); - try { File.Delete(filename); } catch { } + if(inStream != null) + inStream.Dispose(); + Console.WriteLine("l"); + sb.CleanFiles(); } } - private async Task CheckPrebufferingAsync(Stream inStream, CancellationToken cancelToken) + private async Task CheckPrebufferingAsync(Stream inStream, SongBuffer sb, CancellationToken cancelToken) { - while (!bufferingCompleted && inStream.Length < 2.MiB()) + while (!sb.BufferingCompleted && inStream.Length < 2.MiB()) { await Task.Delay(100, cancelToken); } diff --git a/NadekoBot/Modules/Music/Classes/SongBuffer.cs b/NadekoBot/Modules/Music/Classes/SongBuffer.cs new file mode 100644 index 00000000..d9192940 --- /dev/null +++ b/NadekoBot/Modules/Music/Classes/SongBuffer.cs @@ -0,0 +1,159 @@ +๏ปฟusing NadekoBot.Extensions; +using System; +using System.Collections.Concurrent; +using System.Collections.Generic; +using System.Diagnostics; +using System.IO; +using System.Linq; +using System.Text; +using System.Threading; +using System.Threading.Tasks; + +namespace NadekoBot.Modules.Music.Classes +{ + /// + /// Create a buffer for a song file. It will create multiples files to ensure, that radio don't fill up disk space. + /// It also help for large music by deleting files that are already seen. + /// + class SongBuffer + { + + public SongBuffer(string basename, SongInfo songInfo, int skipTo) + { + Basename = basename; + SongInfo = songInfo; + SkipTo = skipTo; + } + + private string Basename; + + private SongInfo SongInfo; + + private int SkipTo; + + private static int MAX_FILE_SIZE = 20.MiB(); + + private long FileNumber = -1; + + private long NextFileToRead = 0; + + public bool BufferingCompleted { get; private set;} = false; + + private ulong CurrentBufferSize = 0; + + public Task BufferSong(CancellationToken cancelToken) => + Task.Factory.StartNew(async () => + { + Process p = null; + FileStream outStream = null; + try + { + p = Process.Start(new ProcessStartInfo + { + FileName = "ffmpeg", + Arguments = $"-ss {SkipTo} -i {SongInfo.Uri} -f s16le -ar 48000 -ac 2 pipe:1 -loglevel quiet", + UseShellExecute = false, + RedirectStandardOutput = true, + RedirectStandardError = false, + CreateNoWindow = true, + }); + + byte[] buffer = new byte[81920]; + int currentFileSize = 0; + ulong prebufferSize = 100ul.MiB(); + + outStream = new FileStream(Basename + "-" + ++FileNumber, FileMode.Append, FileAccess.Write, FileShare.Read); + while (!p.HasExited) //Also fix low bandwidth + { + int bytesRead = await p.StandardOutput.BaseStream.ReadAsync(buffer, 0, buffer.Length, cancelToken).ConfigureAwait(false); + if (currentFileSize >= MAX_FILE_SIZE) + { + try + { + outStream.Dispose(); + }catch { } + outStream = new FileStream(Basename + "-" + ++FileNumber, FileMode.Append, FileAccess.Write, FileShare.Read); + currentFileSize = bytesRead; + } + else + { + currentFileSize += bytesRead; + } + CurrentBufferSize += Convert.ToUInt64(bytesRead); + await outStream.WriteAsync(buffer, 0, bytesRead, cancelToken).ConfigureAwait(false); + while (CurrentBufferSize > prebufferSize) + await Task.Delay(100, cancelToken); + } + BufferingCompleted = true; + } + catch (System.ComponentModel.Win32Exception) + { + var oldclr = Console.ForegroundColor; + Console.ForegroundColor = ConsoleColor.Red; + Console.WriteLine(@"You have not properly installed or configured FFMPEG. +Please install and configure FFMPEG to play music. +Check the guides for your platform on how to setup ffmpeg correctly: + Windows Guide: https://goo.gl/SCv72y + Linux Guide: https://goo.gl/rRhjCp"); + Console.ForegroundColor = oldclr; + } + catch (Exception ex) + { + Console.WriteLine($"Buffering stopped: {ex.Message}"); + } + finally + { + if(outStream != null) + outStream.Dispose(); + Console.WriteLine($"Buffering done."); + if (p != null) + { + try + { + p.Kill(); + } + catch { } + p.Dispose(); + } + } + }, TaskCreationOptions.LongRunning); + + /// + /// Return the next file to read, and delete the old one + /// + /// Name of the file to read + public string GetNextFile() + { + string filename = Basename + "-" + NextFileToRead; + + if (NextFileToRead != 0) + { + try + { + CurrentBufferSize -= Convert.ToUInt64(new FileInfo(Basename + "-" + (NextFileToRead - 1)).Length); + File.Delete(Basename + "-" + (NextFileToRead - 1)); + } + catch { } + } + NextFileToRead++; + return filename; + } + + public bool IsNextFileReady() + { + return NextFileToRead <= FileNumber; + } + + public void CleanFiles() + { + for (long i = NextFileToRead - 1 ; i <= FileNumber; i++) + { + try + { + File.Delete(Basename + "-" + i); + } + catch { } + } + } + } +} diff --git a/NadekoBot/Modules/Music/MusicModule.cs b/NadekoBot/Modules/Music/MusicModule.cs index 77630fd7..eaf290ba 100644 --- a/NadekoBot/Modules/Music/MusicModule.cs +++ b/NadekoBot/Modules/Music/MusicModule.cs @@ -771,20 +771,22 @@ namespace NadekoBot.Modules.Music var selSong = musicPlayer.Playlist.DefaultIfEmpty(null).ElementAtOrDefault(index - 1); if (selSong == null) { - await e.Channel.SendMessage("Could not select song, likely wrong index"); - - } else + await e.Channel.SendMessage("Could not select song, likely wrong index"); + + } + else { await e.Channel.SendMessage($"๐ŸŽถ`Selected song {selSong.SongInfo.Title}:` <{selSong.SongInfo.Query}>").ConfigureAwait(false); } - } else + } + else { var curSong = musicPlayer.CurrentSong; if (curSong == null) return; await e.Channel.SendMessage($"๐ŸŽถ`Current song:` <{curSong.SongInfo.Query}>").ConfigureAwait(false); } - + }); cgb.CreateCommand(Prefix + "autoplay") @@ -837,7 +839,7 @@ namespace NadekoBot.Modules.Music lastFinishedMessage = await textCh.SendMessage($"๐ŸŽต`Finished`{song.PrettyName}").ConfigureAwait(false); if (mp.Autoplay && mp.Playlist.Count == 0 && song.SongInfo.Provider == "YouTube") { - await QueueSong(queuer, textCh, voiceCh, await SearchHelper.GetRelatedVideoId(song.SongInfo.Query), silent, musicType).ConfigureAwait(false); + await QueueSong(queuer.Server.CurrentUser, textCh, voiceCh, (await SearchHelper.GetRelatedVideoIds(song.SongInfo.Query, 4)).ToList().Shuffle().FirstOrDefault(), silent, musicType).ConfigureAwait(false); } } catch (Exception e) diff --git a/NadekoBot/Modules/Translator/ValidLanguagesCommand.cs b/NadekoBot/Modules/Translator/ValidLanguagesCommand.cs index fa3fc11c..438e77de 100644 --- a/NadekoBot/Modules/Translator/ValidLanguagesCommand.cs +++ b/NadekoBot/Modules/Translator/ValidLanguagesCommand.cs @@ -13,7 +13,7 @@ namespace NadekoBot.Modules.Translator internal override void Init(CommandGroupBuilder cgb) { cgb.CreateCommand(Module.Prefix + "translangs") - .Description("List the valid languages for translation. | `{Prefix}translangs` or `{Prefix}translangs language`") + .Description($"List the valid languages for translation. | `{Prefix}translangs` or `{Prefix}translangs language`") .Parameter("search", ParameterType.Optional) .Do(ListLanguagesFunc()); } diff --git a/NadekoBot/Modules/Trello/TrelloModule.cs b/NadekoBot/Modules/Trello/TrelloModule.cs index b144a2cf..14938aca 100644 --- a/NadekoBot/Modules/Trello/TrelloModule.cs +++ b/NadekoBot/Modules/Trello/TrelloModule.cs @@ -92,7 +92,7 @@ namespace NadekoBot.Modules.Trello }); cgb.CreateCommand(Prefix + "unbind") - .Description("Unbinds a bot from the channel and board.") + .Description($"Unbinds a bot from the channel and board. | `{Prefix}unbind`") .Do(async e => { if (!NadekoBot.IsOwner(e.User.Id)) return; @@ -106,7 +106,7 @@ namespace NadekoBot.Modules.Trello cgb.CreateCommand(Prefix + "lists") .Alias(Prefix + "list") - .Description("Lists all lists yo ;)") + .Description($"Lists all lists yo ;) | {Prefix}list") .Do(async e => { if (!NadekoBot.IsOwner(e.User.Id)) return; diff --git a/NadekoBot/NadekoBot.csproj b/NadekoBot/NadekoBot.csproj index 23852358..d332dad2 100644 --- a/NadekoBot/NadekoBot.csproj +++ b/NadekoBot/NadekoBot.csproj @@ -231,6 +231,7 @@ +