2016-08-21 22:37:39 +00:00
using Discord.Commands ;
using NadekoBot.Modules.Music.Classes ;
using System.Collections.Concurrent ;
using Discord.WebSocket ;
using NadekoBot.Services ;
using System.IO ;
using Discord ;
using System.Threading.Tasks ;
using NadekoBot.Attributes ;
using System ;
using System.Linq ;
using NadekoBot.Extensions ;
using System.Net.Http ;
using Newtonsoft.Json.Linq ;
using System.Collections.Generic ;
2016-08-30 01:11:25 +00:00
using NadekoBot.Services.Database ;
2016-10-01 03:49:05 +00:00
using NadekoBot.Services.Database.Models ;
2016-08-21 22:37:39 +00:00
namespace NadekoBot.Modules.Music
{
2016-10-12 04:29:15 +00:00
[NadekoModule("Music", "!!", AutoLoad = false)]
2016-08-21 22:47:06 +00:00
public partial class Music : DiscordModule
2016-08-21 22:37:39 +00:00
{
public static ConcurrentDictionary < ulong , MusicPlayer > MusicPlayers = new ConcurrentDictionary < ulong , MusicPlayer > ( ) ;
public const string MusicDataPath = "data/musicdata" ;
private IGoogleApiService _google ;
2016-09-30 03:58:44 +00:00
public Music ( ILocalization loc , CommandService cmds , ShardedDiscordClient client , IGoogleApiService google ) : base ( loc , cmds , client )
2016-08-21 22:37:39 +00:00
{
//it can fail if its currenctly opened or doesn't exist. Either way i don't care
try { Directory . Delete ( MusicDataPath , true ) ; } catch { }
Directory . CreateDirectory ( MusicDataPath ) ;
_google = google ;
}
2016-10-05 03:09:44 +00:00
[NadekoCommand, Usage, Description, Aliases]
2016-08-21 22:37:39 +00:00
[RequireContext(ContextType.Guild)]
2016-09-10 19:40:25 +00:00
public Task Next ( IUserMessage umsg )
2016-08-21 22:37:39 +00:00
{
2016-08-28 02:33:09 +00:00
var channel = ( ITextChannel ) umsg . Channel ;
2016-08-21 22:37:39 +00:00
MusicPlayer musicPlayer ;
2016-09-10 19:40:25 +00:00
if ( ! MusicPlayers . TryGetValue ( channel . Guild . Id , out musicPlayer ) ) return Task . CompletedTask ;
2016-08-28 02:33:09 +00:00
if ( musicPlayer . PlaybackVoiceChannel = = ( ( IGuildUser ) umsg . Author ) . VoiceChannel )
2016-08-21 22:37:39 +00:00
musicPlayer . Next ( ) ;
2016-09-10 19:40:25 +00:00
return Task . CompletedTask ;
2016-08-21 22:37:39 +00:00
}
2016-10-05 03:09:44 +00:00
[NadekoCommand, Usage, Description, Aliases]
2016-08-21 22:37:39 +00:00
[RequireContext(ContextType.Guild)]
2016-09-10 19:40:25 +00:00
public Task Stop ( IUserMessage umsg )
2016-08-21 22:37:39 +00:00
{
2016-08-28 02:33:09 +00:00
var channel = ( ITextChannel ) umsg . Channel ;
2016-08-21 22:37:39 +00:00
MusicPlayer musicPlayer ;
2016-09-10 19:40:25 +00:00
if ( ! MusicPlayers . TryGetValue ( channel . Guild . Id , out musicPlayer ) ) return Task . CompletedTask ;
2016-08-28 02:33:09 +00:00
if ( ( ( IGuildUser ) umsg . Author ) . VoiceChannel = = musicPlayer . PlaybackVoiceChannel )
2016-08-21 22:37:39 +00:00
{
musicPlayer . Autoplay = false ;
musicPlayer . Stop ( ) ;
}
2016-09-10 19:40:25 +00:00
return Task . CompletedTask ;
2016-08-21 22:37:39 +00:00
}
2016-10-05 03:09:44 +00:00
[NadekoCommand, Usage, Description, Aliases]
2016-08-21 22:37:39 +00:00
[RequireContext(ContextType.Guild)]
2016-09-10 19:40:25 +00:00
public Task Destroy ( IUserMessage umsg )
2016-08-21 22:37:39 +00:00
{
2016-08-28 02:33:09 +00:00
var channel = ( ITextChannel ) umsg . Channel ;
2016-08-21 22:37:39 +00:00
MusicPlayer musicPlayer ;
2016-10-15 23:37:29 +00:00
if ( ! MusicPlayers . TryGetValue ( channel . Guild . Id , out musicPlayer ) ) return Task . CompletedTask ;
2016-08-28 02:33:09 +00:00
if ( ( ( IGuildUser ) umsg . Author ) . VoiceChannel = = musicPlayer . PlaybackVoiceChannel )
2016-10-15 23:37:29 +00:00
if ( MusicPlayers . TryRemove ( channel . Guild . Id , out musicPlayer ) )
musicPlayer . Destroy ( ) ;
2016-09-10 19:40:25 +00:00
return Task . CompletedTask ;
2016-08-21 22:37:39 +00:00
}
2016-10-05 03:09:44 +00:00
[NadekoCommand, Usage, Description, Aliases]
2016-08-21 22:37:39 +00:00
[RequireContext(ContextType.Guild)]
2016-08-28 02:33:09 +00:00
public async Task Pause ( IUserMessage umsg )
2016-08-21 22:37:39 +00:00
{
2016-08-28 02:33:09 +00:00
var channel = ( ITextChannel ) umsg . Channel ;
2016-08-21 22:37:39 +00:00
MusicPlayer musicPlayer ;
if ( ! MusicPlayers . TryGetValue ( channel . Guild . Id , out musicPlayer ) ) return ;
2016-08-28 02:33:09 +00:00
if ( ( ( IGuildUser ) umsg . Author ) . VoiceChannel ! = musicPlayer . PlaybackVoiceChannel )
2016-08-21 22:37:39 +00:00
return ;
musicPlayer . TogglePause ( ) ;
if ( musicPlayer . Paused )
await channel . SendMessageAsync ( "🎵`Music Player paused.`" ) . ConfigureAwait ( false ) ;
else
await channel . SendMessageAsync ( "🎵`Music Player unpaused.`" ) . ConfigureAwait ( false ) ;
}
2016-10-05 03:09:44 +00:00
[NadekoCommand, Usage, Description, Aliases]
2016-08-21 22:37:39 +00:00
[RequireContext(ContextType.Guild)]
2016-08-28 02:33:09 +00:00
public async Task Queue ( IUserMessage umsg , [ Remainder ] string query )
2016-08-21 22:37:39 +00:00
{
2016-08-28 02:33:09 +00:00
var channel = ( ITextChannel ) umsg . Channel ;
2016-08-21 22:37:39 +00:00
2016-08-28 02:33:09 +00:00
await QueueSong ( ( ( IGuildUser ) umsg . Author ) , channel , ( ( IGuildUser ) umsg . Author ) . VoiceChannel , query ) . ConfigureAwait ( false ) ;
2016-08-21 22:37:39 +00:00
if ( channel . Guild . GetCurrentUser ( ) . GetPermissions ( channel ) . ManageMessages )
{
await Task . Delay ( 10000 ) . ConfigureAwait ( false ) ;
2016-08-28 02:33:09 +00:00
await ( ( IUserMessage ) umsg ) . DeleteAsync ( ) . ConfigureAwait ( false ) ;
2016-08-21 22:37:39 +00:00
}
}
2016-10-05 03:09:44 +00:00
[NadekoCommand, Usage, Description, Aliases]
2016-08-21 22:37:39 +00:00
[RequireContext(ContextType.Guild)]
2016-08-28 02:33:09 +00:00
public async Task SoundCloudQueue ( IUserMessage umsg , [ Remainder ] string query )
2016-08-21 22:37:39 +00:00
{
2016-08-28 02:33:09 +00:00
var channel = ( ITextChannel ) umsg . Channel ;
2016-08-21 22:37:39 +00:00
2016-08-28 02:33:09 +00:00
await QueueSong ( ( ( IGuildUser ) umsg . Author ) , channel , ( ( IGuildUser ) umsg . Author ) . VoiceChannel , query , musicType : MusicType . Soundcloud ) . ConfigureAwait ( false ) ;
2016-08-21 22:37:39 +00:00
if ( channel . Guild . GetCurrentUser ( ) . GetPermissions ( channel ) . ManageMessages )
{
await Task . Delay ( 10000 ) . ConfigureAwait ( false ) ;
2016-08-28 02:33:09 +00:00
await ( ( IUserMessage ) umsg ) . DeleteAsync ( ) . ConfigureAwait ( false ) ;
2016-08-21 22:37:39 +00:00
}
}
2016-10-05 03:09:44 +00:00
[NadekoCommand, Usage, Description, Aliases]
2016-08-21 22:37:39 +00:00
[RequireContext(ContextType.Guild)]
2016-08-28 02:33:09 +00:00
public async Task ListQueue ( IUserMessage umsg , int page = 1 )
2016-08-21 22:37:39 +00:00
{
2016-08-28 02:33:09 +00:00
var channel = ( ITextChannel ) umsg . Channel ;
2016-08-21 22:37:39 +00:00
MusicPlayer musicPlayer ;
if ( ! MusicPlayers . TryGetValue ( channel . Guild . Id , out musicPlayer ) )
{
await channel . SendMessageAsync ( "🎵 No active music player." ) . ConfigureAwait ( false ) ;
return ;
}
if ( page < = 0 )
return ;
var currentSong = musicPlayer . CurrentSong ;
if ( currentSong = = null )
return ;
var toSend = $"🎵`Now Playing` {currentSong.PrettyName} " + $"{currentSong.PrettyCurrentTime()}\n" ;
if ( musicPlayer . RepeatSong )
toSend + = "🔂" ;
else if ( musicPlayer . RepeatPlaylist )
toSend + = "🔁" ;
toSend + = $" **{musicPlayer.Playlist.Count}** `tracks currently queued. Showing page {page}` " ;
if ( musicPlayer . MaxQueueSize ! = 0 & & musicPlayer . Playlist . Count > = musicPlayer . MaxQueueSize )
toSend + = "**Song queue is full!**\n" ;
else
toSend + = "\n" ;
const int itemsPerPage = 15 ;
int startAt = itemsPerPage * ( page - 1 ) ;
var number = 1 + startAt ;
await channel . SendMessageAsync ( toSend + string . Join ( "\n" , musicPlayer . Playlist . Skip ( startAt ) . Take ( 15 ) . Select ( v = > $"`{number++}.` {v.PrettyName}" ) ) ) . ConfigureAwait ( false ) ;
}
2016-10-05 03:09:44 +00:00
[NadekoCommand, Usage, Description, Aliases]
2016-08-21 22:37:39 +00:00
[RequireContext(ContextType.Guild)]
2016-08-28 02:33:09 +00:00
public async Task NowPlaying ( IUserMessage umsg )
2016-08-21 22:37:39 +00:00
{
2016-08-28 02:33:09 +00:00
var channel = ( ITextChannel ) umsg . Channel ;
2016-08-21 22:37:39 +00:00
MusicPlayer musicPlayer ;
if ( ! MusicPlayers . TryGetValue ( channel . Guild . Id , out musicPlayer ) )
return ;
var currentSong = musicPlayer . CurrentSong ;
if ( currentSong = = null )
return ;
await channel . SendMessageAsync ( $"🎵`Now Playing` {currentSong.PrettyName} " +
$"{currentSong.PrettyCurrentTime()}" ) . ConfigureAwait ( false ) ;
}
2016-10-05 03:09:44 +00:00
[NadekoCommand, Usage, Description, Aliases]
2016-08-21 22:37:39 +00:00
[RequireContext(ContextType.Guild)]
2016-08-28 02:33:09 +00:00
public async Task Volume ( IUserMessage umsg , int val )
2016-08-21 22:37:39 +00:00
{
2016-08-28 02:33:09 +00:00
var channel = ( ITextChannel ) umsg . Channel ;
2016-08-21 22:37:39 +00:00
MusicPlayer musicPlayer ;
if ( ! MusicPlayers . TryGetValue ( channel . Guild . Id , out musicPlayer ) )
return ;
2016-08-28 02:33:09 +00:00
if ( ( ( IGuildUser ) umsg . Author ) . VoiceChannel ! = musicPlayer . PlaybackVoiceChannel )
2016-08-21 22:37:39 +00:00
return ;
if ( val < 0 )
return ;
var volume = musicPlayer . SetVolume ( val ) ;
await channel . SendMessageAsync ( $"🎵 `Volume set to {volume}%`" ) . ConfigureAwait ( false ) ;
}
2016-08-30 01:22:15 +00:00
2016-10-05 03:09:44 +00:00
[NadekoCommand, Usage, Description, Aliases]
2016-08-30 01:22:15 +00:00
[RequireContext(ContextType.Guild)]
public async Task Defvol ( IUserMessage umsg , [ Remainder ] int val )
{
var channel = ( ITextChannel ) umsg . Channel ;
if ( val < 0 | | val > 100 )
{
await channel . SendMessageAsync ( "Volume number invalid. Must be between 0 and 100" ) . ConfigureAwait ( false ) ;
return ;
}
using ( var uow = DbHandler . UnitOfWork ( ) )
{
uow . GuildConfigs . For ( channel . Guild . Id ) . DefaultMusicVolume = val / 100.0f ;
uow . Complete ( ) ;
}
await channel . SendMessageAsync ( $"🎵 `Default volume set to {val}%`" ) . ConfigureAwait ( false ) ;
}
2016-08-21 22:37:39 +00:00
2016-10-05 03:09:44 +00:00
[NadekoCommand, Usage, Description, Aliases]
2016-08-21 22:37:39 +00:00
[RequireContext(ContextType.Guild)]
2016-10-08 09:55:56 +00:00
public async Task ShufflePlaylist ( IUserMessage umsg )
2016-08-21 22:37:39 +00:00
{
2016-08-28 02:33:09 +00:00
var channel = ( ITextChannel ) umsg . Channel ;
2016-08-21 22:37:39 +00:00
MusicPlayer musicPlayer ;
if ( ! MusicPlayers . TryGetValue ( channel . Guild . Id , out musicPlayer ) )
return ;
2016-08-28 02:33:09 +00:00
if ( ( ( IGuildUser ) umsg . Author ) . VoiceChannel ! = musicPlayer . PlaybackVoiceChannel )
2016-08-21 22:37:39 +00:00
return ;
if ( musicPlayer . Playlist . Count < 2 )
{
await channel . SendMessageAsync ( "💢 Not enough songs in order to perform the shuffle." ) . ConfigureAwait ( false ) ;
return ;
}
musicPlayer . Shuffle ( ) ;
await channel . SendMessageAsync ( "🎵 `Songs shuffled.`" ) . ConfigureAwait ( false ) ;
}
2016-10-05 03:09:44 +00:00
[NadekoCommand, Usage, Description, Aliases]
2016-08-21 22:37:39 +00:00
[RequireContext(ContextType.Guild)]
2016-08-28 02:33:09 +00:00
public async Task Playlist ( IUserMessage umsg , [ Remainder ] string playlist )
2016-08-21 22:37:39 +00:00
{
2016-08-28 02:33:09 +00:00
var channel = ( ITextChannel ) umsg . Channel ;
2016-08-21 22:37:39 +00:00
var arg = playlist ;
if ( string . IsNullOrWhiteSpace ( arg ) )
return ;
2016-08-28 02:33:09 +00:00
if ( ( ( IGuildUser ) umsg . Author ) . VoiceChannel ? . Guild ! = channel . Guild )
2016-08-21 22:37:39 +00:00
{
await channel . SendMessageAsync ( "💢 You need to be in a voice channel on this server.\n If you are already in a voice channel, try rejoining it." ) . ConfigureAwait ( false ) ;
return ;
}
var plId = ( await _google . GetPlaylistIdsByKeywordsAsync ( arg ) . ConfigureAwait ( false ) ) . FirstOrDefault ( ) ;
if ( plId = = null )
{
await channel . SendMessageAsync ( "No search results for that query." ) ;
return ;
}
var ids = await _google . GetPlaylistTracksAsync ( plId , 500 ) . ConfigureAwait ( false ) ;
if ( ! ids . Any ( ) )
{
await channel . SendMessageAsync ( $"🎵 `Failed to find any songs.`" ) . ConfigureAwait ( false ) ;
return ;
}
var idArray = ids as string [ ] ? ? ids . ToArray ( ) ;
var count = idArray . Length ;
var msg =
await channel . SendMessageAsync ( $"🎵 `Attempting to queue {count} songs" . SnPl ( count ) + "...`" ) . ConfigureAwait ( false ) ;
foreach ( var id in idArray )
{
try
{
2016-08-28 02:33:09 +00:00
await QueueSong ( ( ( IGuildUser ) umsg . Author ) , channel , ( ( IGuildUser ) umsg . Author ) . VoiceChannel , id , true ) . ConfigureAwait ( false ) ;
2016-08-21 22:37:39 +00:00
}
catch ( PlaylistFullException )
{ break ; }
catch { }
}
await msg . ModifyAsync ( m = > m . Content = "🎵 `Playlist queue complete.`" ) . ConfigureAwait ( false ) ;
}
2016-10-05 03:09:44 +00:00
[NadekoCommand, Usage, Description, Aliases]
2016-08-21 22:37:39 +00:00
[RequireContext(ContextType.Guild)]
2016-08-28 02:33:09 +00:00
public async Task SoundCloudPl ( IUserMessage umsg , [ Remainder ] string pl )
2016-08-21 22:37:39 +00:00
{
2016-08-28 02:33:09 +00:00
var channel = ( ITextChannel ) umsg . Channel ;
2016-08-21 22:37:39 +00:00
pl = pl ? . Trim ( ) ;
if ( string . IsNullOrWhiteSpace ( pl ) )
return ;
using ( var http = new HttpClient ( ) )
{
var scvids = JObject . Parse ( await http . GetStringAsync ( $"http://api.soundcloud.com/resolve?url={pl}&client_id={NadekoBot.Credentials.SoundCloudClientId}" ) . ConfigureAwait ( false ) ) [ "tracks" ] . ToObject < SoundCloudVideo [ ] > ( ) ;
2016-08-28 02:33:09 +00:00
await QueueSong ( ( ( IGuildUser ) umsg . Author ) , channel , ( ( IGuildUser ) umsg . Author ) . VoiceChannel , scvids [ 0 ] . TrackLink ) . ConfigureAwait ( false ) ;
2016-08-21 22:37:39 +00:00
MusicPlayer mp ;
if ( ! MusicPlayers . TryGetValue ( channel . Guild . Id , out mp ) )
return ;
foreach ( var svideo in scvids . Skip ( 1 ) )
{
try
{
mp . AddSong ( new Song ( new Classes . SongInfo
{
Title = svideo . FullName ,
Provider = "SoundCloud" ,
Uri = svideo . StreamLink ,
ProviderType = MusicType . Normal ,
Query = svideo . TrackLink ,
2016-08-28 02:33:09 +00:00
} ) , ( ( IGuildUser ) umsg . Author ) . Username ) ;
2016-08-21 22:37:39 +00:00
}
catch ( PlaylistFullException ) { break ; }
}
}
}
2016-10-05 03:09:44 +00:00
[NadekoCommand, Usage, Description, Aliases]
2016-08-21 22:37:39 +00:00
[RequireContext(ContextType.Guild)]
2016-09-30 02:20:09 +00:00
[OwnerOnly]
2016-08-28 02:33:09 +00:00
public async Task LocalPl ( IUserMessage umsg , [ Remainder ] string directory )
2016-08-21 22:37:39 +00:00
{
2016-08-28 02:33:09 +00:00
var channel = ( ITextChannel ) umsg . Channel ;
2016-08-21 22:37:39 +00:00
var arg = directory ;
if ( string . IsNullOrWhiteSpace ( arg ) )
return ;
try
{
var fileEnum = new DirectoryInfo ( arg ) . GetFiles ( )
. Where ( x = > ! x . Attributes . HasFlag ( FileAttributes . Hidden | FileAttributes . System ) ) ;
foreach ( var file in fileEnum )
{
try
{
2016-08-28 02:33:09 +00:00
await QueueSong ( ( ( IGuildUser ) umsg . Author ) , channel , ( ( IGuildUser ) umsg . Author ) . VoiceChannel , file . FullName , true , MusicType . Local ) . ConfigureAwait ( false ) ;
2016-08-21 22:37:39 +00:00
}
catch ( PlaylistFullException )
{
break ;
}
catch { }
}
await channel . SendMessageAsync ( "🎵 `Directory queue complete.`" ) . ConfigureAwait ( false ) ;
}
catch { }
}
2016-10-05 03:09:44 +00:00
[NadekoCommand, Usage, Description, Aliases]
2016-08-21 22:37:39 +00:00
[RequireContext(ContextType.Guild)]
2016-08-28 02:33:09 +00:00
public async Task Radio ( IUserMessage umsg , string radio_link )
2016-08-21 22:37:39 +00:00
{
2016-08-28 02:33:09 +00:00
var channel = ( ITextChannel ) umsg . Channel ;
if ( ( ( IGuildUser ) umsg . Author ) . VoiceChannel ? . Guild ! = channel . Guild )
2016-08-21 22:37:39 +00:00
{
await channel . SendMessageAsync ( "💢 You need to be in a voice channel on this server.\n If you are already in a voice channel, try rejoining it." ) . ConfigureAwait ( false ) ;
return ;
}
2016-08-28 02:33:09 +00:00
await QueueSong ( ( ( IGuildUser ) umsg . Author ) , channel , ( ( IGuildUser ) umsg . Author ) . VoiceChannel , radio_link , musicType : MusicType . Radio ) . ConfigureAwait ( false ) ;
2016-08-21 22:37:39 +00:00
if ( channel . Guild . GetCurrentUser ( ) . GetPermissions ( channel ) . ManageMessages )
{
await Task . Delay ( 10000 ) . ConfigureAwait ( false ) ;
2016-08-28 02:33:09 +00:00
await ( ( IUserMessage ) umsg ) . DeleteAsync ( ) . ConfigureAwait ( false ) ;
2016-08-21 22:37:39 +00:00
}
}
2016-10-05 03:09:44 +00:00
[NadekoCommand, Usage, Description, Aliases]
2016-08-21 22:37:39 +00:00
[RequireContext(ContextType.Guild)]
2016-09-30 02:20:09 +00:00
[OwnerOnly]
2016-08-28 02:33:09 +00:00
public async Task Local ( IUserMessage umsg , [ Remainder ] string path )
2016-08-21 22:37:39 +00:00
{
2016-08-28 02:33:09 +00:00
var channel = ( ITextChannel ) umsg . Channel ;
2016-08-21 22:37:39 +00:00
var arg = path ;
if ( string . IsNullOrWhiteSpace ( arg ) )
return ;
2016-08-28 02:33:09 +00:00
await QueueSong ( ( ( IGuildUser ) umsg . Author ) , channel , ( ( IGuildUser ) umsg . Author ) . VoiceChannel , path , musicType : MusicType . Local ) . ConfigureAwait ( false ) ;
2016-08-21 22:37:39 +00:00
}
2016-10-05 03:09:44 +00:00
[NadekoCommand, Usage, Description, Aliases]
2016-08-21 22:37:39 +00:00
[RequireContext(ContextType.Guild)]
2016-08-28 02:33:09 +00:00
public async Task Move ( IUserMessage umsg )
2016-08-21 22:37:39 +00:00
{
2016-08-28 02:33:09 +00:00
var channel = ( ITextChannel ) umsg . Channel ;
2016-08-21 22:37:39 +00:00
MusicPlayer musicPlayer ;
2016-08-28 02:33:09 +00:00
var voiceChannel = ( ( IGuildUser ) umsg . Author ) . VoiceChannel ;
2016-08-21 22:37:39 +00:00
if ( voiceChannel = = null | | voiceChannel . Guild ! = channel . Guild | | ! MusicPlayers . TryGetValue ( channel . Guild . Id , out musicPlayer ) )
return ;
2016-09-10 19:40:25 +00:00
await musicPlayer . MoveToVoiceChannel ( voiceChannel ) ;
2016-08-21 22:37:39 +00:00
}
2016-10-05 03:09:44 +00:00
[NadekoCommand, Usage, Description, Aliases]
2016-08-21 22:37:39 +00:00
[RequireContext(ContextType.Guild)]
2016-08-28 02:33:09 +00:00
public async Task Remove ( IUserMessage umsg , int num )
2016-08-21 22:37:39 +00:00
{
2016-08-28 02:33:09 +00:00
var channel = ( ITextChannel ) umsg . Channel ;
2016-08-21 22:37:39 +00:00
MusicPlayer musicPlayer ;
if ( ! MusicPlayers . TryGetValue ( channel . Guild . Id , out musicPlayer ) )
{
return ;
}
2016-08-28 02:33:09 +00:00
if ( ( ( IGuildUser ) umsg . Author ) . VoiceChannel ! = musicPlayer . PlaybackVoiceChannel )
2016-08-21 22:37:39 +00:00
return ;
if ( num < = 0 | | num > musicPlayer . Playlist . Count )
return ;
var song = ( musicPlayer . Playlist as List < Song > ) ? [ num - 1 ] ;
musicPlayer . RemoveSongAt ( num - 1 ) ;
await channel . SendMessageAsync ( $"🎵**Track {song.PrettyName} at position `#{num}` has been removed.**" ) . ConfigureAwait ( false ) ;
}
2016-09-03 13:04:07 +00:00
2016-10-05 03:09:44 +00:00
[NadekoCommand, Usage, Description, Aliases]
2016-08-21 22:37:39 +00:00
[RequireContext(ContextType.Guild)]
2016-08-28 02:33:09 +00:00
public async Task Remove ( IUserMessage umsg , string all )
2016-08-21 22:37:39 +00:00
{
2016-08-28 02:33:09 +00:00
var channel = ( ITextChannel ) umsg . Channel ;
2016-08-21 22:37:39 +00:00
if ( all . Trim ( ) . ToUpperInvariant ( ) ! = "ALL" )
return ;
MusicPlayer musicPlayer ;
if ( ! MusicPlayers . TryGetValue ( channel . Guild . Id , out musicPlayer ) ) return ;
musicPlayer . ClearQueue ( ) ;
await channel . SendMessageAsync ( $"🎵`Queue cleared!`" ) . ConfigureAwait ( false ) ;
return ;
}
2016-10-05 03:09:44 +00:00
[NadekoCommand, Usage, Description, Aliases]
2016-08-21 22:37:39 +00:00
[RequireContext(ContextType.Guild)]
2016-08-28 02:33:09 +00:00
public async Task MoveSong ( IUserMessage umsg , [ Remainder ] string fromto )
2016-08-21 22:37:39 +00:00
{
2016-08-28 02:33:09 +00:00
var channel = ( ITextChannel ) umsg . Channel ;
2016-08-21 22:37:39 +00:00
MusicPlayer musicPlayer ;
if ( ! MusicPlayers . TryGetValue ( channel . Guild . Id , out musicPlayer ) )
{
return ;
}
fromto = fromto ? . Trim ( ) ;
var fromtoArr = fromto . Split ( '>' ) ;
int n1 ;
int n2 ;
var playlist = musicPlayer . Playlist as List < Song > ? ? musicPlayer . Playlist . ToList ( ) ;
if ( fromtoArr . Length ! = 2 | | ! int . TryParse ( fromtoArr [ 0 ] , out n1 ) | |
! int . TryParse ( fromtoArr [ 1 ] , out n2 ) | | n1 < 1 | | n2 < 1 | | n1 = = n2 | |
n1 > playlist . Count | | n2 > playlist . Count )
{
await channel . SendMessageAsync ( "`Invalid input.`" ) . ConfigureAwait ( false ) ;
return ;
}
var s = playlist [ n1 - 1 ] ;
playlist . Insert ( n2 - 1 , s ) ;
var nn1 = n2 < n1 ? n1 : n1 - 1 ;
playlist . RemoveAt ( nn1 ) ;
await channel . SendMessageAsync ( $"🎵`Moved` {s.PrettyName} `from #{n1} to #{n2}`" ) . ConfigureAwait ( false ) ;
}
2016-10-05 03:09:44 +00:00
[NadekoCommand, Usage, Description, Aliases]
2016-08-21 22:37:39 +00:00
[RequireContext(ContextType.Guild)]
2016-08-28 02:33:09 +00:00
public async Task SetMaxQueue ( IUserMessage umsg , uint size )
2016-08-21 22:37:39 +00:00
{
2016-08-28 02:33:09 +00:00
var channel = ( ITextChannel ) umsg . Channel ;
2016-08-21 22:37:39 +00:00
MusicPlayer musicPlayer ;
if ( ! MusicPlayers . TryGetValue ( channel . Guild . Id , out musicPlayer ) )
{
return ;
}
musicPlayer . MaxQueueSize = size ;
await channel . SendMessageAsync ( $"🎵 `Max queue set to {(size == 0 ? (" unlimited ") : size + " tracks ")}`" ) ;
}
2016-10-05 03:09:44 +00:00
[NadekoCommand, Usage, Description, Aliases]
2016-08-21 22:37:39 +00:00
[RequireContext(ContextType.Guild)]
2016-08-28 02:33:09 +00:00
public async Task ReptCurSong ( IUserMessage umsg )
2016-08-21 22:37:39 +00:00
{
2016-08-28 02:33:09 +00:00
var channel = ( ITextChannel ) umsg . Channel ;
2016-08-21 22:37:39 +00:00
MusicPlayer musicPlayer ;
if ( ! MusicPlayers . TryGetValue ( channel . Guild . Id , out musicPlayer ) )
return ;
var currentSong = musicPlayer . CurrentSong ;
if ( currentSong = = null )
return ;
var currentValue = musicPlayer . ToggleRepeatSong ( ) ;
await channel . SendMessageAsync ( currentValue ?
$"🎵🔂`Repeating track:`{currentSong.PrettyName}" :
$"🎵🔂`Current track repeat stopped.`" )
. ConfigureAwait ( false ) ;
}
2016-10-05 03:09:44 +00:00
[NadekoCommand, Usage, Description, Aliases]
2016-08-21 22:37:39 +00:00
[RequireContext(ContextType.Guild)]
2016-08-28 02:33:09 +00:00
public async Task RepeatPl ( IUserMessage umsg )
2016-08-21 22:37:39 +00:00
{
2016-08-28 02:33:09 +00:00
var channel = ( ITextChannel ) umsg . Channel ;
2016-08-21 22:37:39 +00:00
MusicPlayer musicPlayer ;
if ( ! MusicPlayers . TryGetValue ( channel . Guild . Id , out musicPlayer ) )
return ;
var currentValue = musicPlayer . ToggleRepeatPlaylist ( ) ;
await channel . SendMessageAsync ( $"🎵🔁`Repeat playlist {(currentValue ? " enabled " : " disabled ")}`" ) . ConfigureAwait ( false ) ;
}
2016-10-05 03:09:44 +00:00
[NadekoCommand, Usage, Description, Aliases]
2016-10-01 03:49:05 +00:00
[RequireContext(ContextType.Guild)]
public async Task Save ( IUserMessage umsg , [ Remainder ] string name )
{
var channel = ( ITextChannel ) umsg . Channel ;
MusicPlayer musicPlayer ;
if ( ! MusicPlayers . TryGetValue ( channel . Guild . Id , out musicPlayer ) )
return ;
2016-08-21 22:37:39 +00:00
2016-10-01 03:49:05 +00:00
var curSong = musicPlayer . CurrentSong ;
var songs = musicPlayer . Playlist . Append ( curSong )
. Select ( s = > new PlaylistSong ( ) {
Provider = s . SongInfo . Provider ,
ProviderType = s . SongInfo . ProviderType ,
Title = s . SongInfo . Title ,
Uri = s . SongInfo . Uri ,
Query = s . SongInfo . Query ,
} ) . ToList ( ) ;
2016-08-21 22:37:39 +00:00
2016-10-01 03:49:05 +00:00
MusicPlaylist playlist ;
using ( var uow = DbHandler . UnitOfWork ( ) )
{
playlist = new MusicPlaylist
{
Name = name ,
Author = umsg . Author . Username ,
2016-10-01 17:35:11 +00:00
AuthorId = umsg . Author . Id ,
2016-10-01 03:49:05 +00:00
Songs = songs ,
} ;
uow . MusicPlaylists . Add ( playlist ) ;
await uow . CompleteAsync ( ) . ConfigureAwait ( false ) ;
}
2016-08-21 22:37:39 +00:00
2016-10-01 03:49:05 +00:00
await channel . SendMessageAsync ( ( $"🎵 `Saved playlist as {name}.` `Id: {playlist.Id}`" ) ) . ConfigureAwait ( false ) ;
}
2016-08-21 22:37:39 +00:00
2016-10-05 03:09:44 +00:00
[NadekoCommand, Usage, Description, Aliases]
2016-10-01 03:49:05 +00:00
[RequireContext(ContextType.Guild)]
public async Task Load ( IUserMessage umsg , [ Remainder ] int id )
{
var channel = ( ITextChannel ) umsg . Channel ;
MusicPlaylist mpl ;
using ( var uow = DbHandler . UnitOfWork ( ) )
{
mpl = uow . MusicPlaylists . GetWithSongs ( id ) ;
}
if ( mpl = = null )
{
2016-10-02 01:00:03 +00:00
await channel . SendMessageAsync ( "`Can't find playlist with that ID`" ) . ConfigureAwait ( false ) ;
2016-10-01 03:49:05 +00:00
return ;
}
2016-10-05 05:01:19 +00:00
IUserMessage msg = null ;
try { msg = await channel . SendMessageAsync ( $"`Attempting to load {mpl.Songs.Count} songs...`" ) . ConfigureAwait ( false ) ; } catch ( Exception ex ) { _log . Warn ( ex ) ; }
2016-10-01 03:49:05 +00:00
foreach ( var item in mpl . Songs )
{
2016-10-05 05:01:19 +00:00
var usr = ( IGuildUser ) umsg . Author ;
2016-10-01 03:49:05 +00:00
try
{
await QueueSong ( usr , channel , usr . VoiceChannel , item . Query , true , item . ProviderType ) . ConfigureAwait ( false ) ;
}
catch { break ; }
}
2016-10-05 05:01:19 +00:00
if ( msg ! = null )
await msg . ModifyAsync ( m = > m . Content = $"`Done loading playlist {mpl.Name}.`" ) . ConfigureAwait ( false ) ;
2016-10-01 03:49:05 +00:00
}
2016-10-05 03:09:44 +00:00
[NadekoCommand, Usage, Description, Aliases]
2016-10-01 03:49:05 +00:00
[RequireContext(ContextType.Guild)]
public async Task Playlists ( IUserMessage umsg , [ Remainder ] int num = 1 )
{
var channel = ( ITextChannel ) umsg . Channel ;
if ( num < = 0 )
return ;
List < MusicPlaylist > playlists ;
using ( var uow = DbHandler . UnitOfWork ( ) )
{
playlists = uow . MusicPlaylists . GetPlaylistsOnPage ( num ) ;
}
await channel . SendMessageAsync ( $ @ "`Page {num} of saved playlists`
" + string.Join(" \ n ", playlists.Select(r => $" ` # { r . Id } ` - ` { r . Name } ` by { r . Author } - * * { r . Songs . Count } * * songs "))).ConfigureAwait(false);
}
2016-08-21 22:37:39 +00:00
2016-10-01 03:49:05 +00:00
//todo only author or owner
2016-10-05 03:09:44 +00:00
[NadekoCommand, Usage, Description, Aliases]
2016-10-01 17:35:11 +00:00
[RequireContext(ContextType.Guild)]
public async Task DeletePlaylist ( IUserMessage umsg , [ Remainder ] int id )
{
var channel = ( ITextChannel ) umsg . Channel ;
2016-08-21 22:37:39 +00:00
2016-10-01 17:35:11 +00:00
bool success = false ;
MusicPlaylist pl = null ;
2016-10-02 01:00:03 +00:00
try
2016-10-01 17:35:11 +00:00
{
2016-10-02 01:00:03 +00:00
using ( var uow = DbHandler . UnitOfWork ( ) )
2016-10-01 17:35:11 +00:00
{
2016-10-02 01:00:03 +00:00
pl = uow . MusicPlaylists . Get ( id ) ;
if ( pl ! = null )
2016-10-01 17:35:11 +00:00
{
2016-10-02 01:00:03 +00:00
if ( NadekoBot . Credentials . IsOwner ( umsg . Author ) | | pl . AuthorId = = umsg . Author . Id )
{
uow . MusicPlaylists . Remove ( pl ) ;
await uow . CompleteAsync ( ) . ConfigureAwait ( false ) ;
success = true ;
}
else
success = false ;
2016-10-01 17:35:11 +00:00
}
}
2016-10-02 01:00:03 +00:00
if ( ! success )
await channel . SendMessageAsync ( "Failed to delete that playlist. It either doesn't exist, or you are not its author." ) . ConfigureAwait ( false ) ;
else
await channel . SendMessageAsync ( "`Playlist successfully deleted.`" ) . ConfigureAwait ( false ) ;
}
catch ( Exception ex )
{
Console . WriteLine ( ex ) ;
}
2016-10-01 17:35:11 +00:00
}
2016-08-21 22:37:39 +00:00
2016-10-05 03:09:44 +00:00
[NadekoCommand, Usage, Description, Aliases]
2016-08-21 22:37:39 +00:00
[RequireContext(ContextType.Guild)]
2016-08-28 02:33:09 +00:00
public async Task Goto ( IUserMessage umsg , int time )
2016-08-21 22:37:39 +00:00
{
2016-08-28 02:33:09 +00:00
var channel = ( ITextChannel ) umsg . Channel ;
2016-08-21 22:37:39 +00:00
MusicPlayer musicPlayer ;
if ( ! MusicPlayers . TryGetValue ( channel . Guild . Id , out musicPlayer ) )
return ;
2016-08-28 02:33:09 +00:00
if ( ( ( IGuildUser ) umsg . Author ) . VoiceChannel ! = musicPlayer . PlaybackVoiceChannel )
2016-08-21 22:37:39 +00:00
return ;
if ( time < 0 )
return ;
var currentSong = musicPlayer . CurrentSong ;
if ( currentSong = = null )
return ;
//currentSong.PrintStatusMessage = false;
var gotoSong = currentSong . Clone ( ) ;
gotoSong . SkipTo = time ;
musicPlayer . AddSong ( gotoSong , 0 ) ;
musicPlayer . Next ( ) ;
var minutes = ( time / 60 ) . ToString ( ) ;
var seconds = ( time % 60 ) . ToString ( ) ;
if ( minutes . Length = = 1 )
minutes = "0" + minutes ;
if ( seconds . Length = = 1 )
seconds = "0" + seconds ;
await channel . SendMessageAsync ( $"`Skipped to {minutes}:{seconds}`" ) . ConfigureAwait ( false ) ;
}
2016-10-05 03:09:44 +00:00
[NadekoCommand, Usage, Description, Aliases]
2016-08-21 22:37:39 +00:00
[RequireContext(ContextType.Guild)]
2016-08-28 02:33:09 +00:00
public async Task GetLink ( IUserMessage umsg , int index = 0 )
2016-08-21 22:37:39 +00:00
{
2016-08-28 02:33:09 +00:00
var channel = ( ITextChannel ) umsg . Channel ;
2016-08-21 22:37:39 +00:00
MusicPlayer musicPlayer ;
if ( ! MusicPlayers . TryGetValue ( channel . Guild . Id , out musicPlayer ) )
return ;
if ( index < 0 )
return ;
if ( index > 0 )
{
var selSong = musicPlayer . Playlist . DefaultIfEmpty ( null ) . ElementAtOrDefault ( index - 1 ) ;
if ( selSong = = null )
{
await channel . SendMessageAsync ( "Could not select song, likely wrong index" ) ;
}
else
{
await channel . SendMessageAsync ( $"🎶`Selected song {selSong.SongInfo.Title}:` <{selSong.SongInfo.Query}>" ) . ConfigureAwait ( false ) ;
}
}
else
{
var curSong = musicPlayer . CurrentSong ;
if ( curSong = = null )
return ;
await channel . SendMessageAsync ( $"🎶`Current song:` <{curSong.SongInfo.Query}>" ) . ConfigureAwait ( false ) ;
}
}
2016-10-05 03:09:44 +00:00
[NadekoCommand, Usage, Description, Aliases]
2016-08-21 22:37:39 +00:00
[RequireContext(ContextType.Guild)]
2016-08-28 02:33:09 +00:00
public async Task Autoplay ( IUserMessage umsg )
2016-08-21 22:37:39 +00:00
{
2016-08-28 02:33:09 +00:00
var channel = ( ITextChannel ) umsg . Channel ;
2016-08-21 22:37:39 +00:00
MusicPlayer musicPlayer ;
if ( ! MusicPlayers . TryGetValue ( channel . Guild . Id , out musicPlayer ) )
return ;
if ( ! musicPlayer . ToggleAutoplay ( ) )
await channel . SendMessageAsync ( "🎶`Autoplay disabled.`" ) . ConfigureAwait ( false ) ;
else
await channel . SendMessageAsync ( "🎶`Autoplay enabled.`" ) . ConfigureAwait ( false ) ;
}
public static async Task QueueSong ( IGuildUser queuer , ITextChannel textCh , IVoiceChannel voiceCh , string query , bool silent = false , MusicType musicType = MusicType . Normal )
{
if ( voiceCh = = null | | voiceCh . Guild ! = textCh . Guild )
{
if ( ! silent )
await textCh . SendMessageAsync ( "💢 You need to be in a voice channel on this server.\n If you are already in a voice channel, try rejoining." ) . ConfigureAwait ( false ) ;
throw new ArgumentNullException ( nameof ( voiceCh ) ) ;
}
if ( string . IsNullOrWhiteSpace ( query ) | | query . Length < 3 )
throw new ArgumentException ( "💢 Invalid query for queue song." , nameof ( query ) ) ;
var musicPlayer = MusicPlayers . GetOrAdd ( textCh . Guild . Id , server = >
{
2016-08-26 01:25:55 +00:00
float vol = 1 ; // SpecificConfigurations.Default.Of(server.Id).DefaultMusicVolume;
2016-08-30 01:11:25 +00:00
using ( var uow = DbHandler . UnitOfWork ( ) )
{
vol = uow . GuildConfigs . For ( textCh . Guild . Id ) . DefaultMusicVolume ;
}
2016-08-21 22:37:39 +00:00
var mp = new MusicPlayer ( voiceCh , vol ) ;
2016-08-28 02:33:09 +00:00
IUserMessage playingMessage = null ;
IUserMessage lastFinishedMessage = null ;
2016-08-21 22:37:39 +00:00
mp . OnCompleted + = async ( s , song ) = >
{
if ( song . PrintStatusMessage )
{
try
{
if ( lastFinishedMessage ! = null )
await lastFinishedMessage . DeleteAsync ( ) . ConfigureAwait ( false ) ;
if ( playingMessage ! = null )
await playingMessage . DeleteAsync ( ) . ConfigureAwait ( false ) ;
2016-10-05 05:01:19 +00:00
try { lastFinishedMessage = await textCh . SendMessageAsync ( $"🎵`Finished`{song.PrettyName}" ) . ConfigureAwait ( false ) ; } catch { }
2016-08-21 22:37:39 +00:00
if ( mp . Autoplay & & mp . Playlist . Count = = 0 & & song . SongInfo . Provider = = "YouTube" )
{
await QueueSong ( queuer . Guild . GetCurrentUser ( ) , textCh , voiceCh , ( await NadekoBot . Google . GetRelatedVideosAsync ( song . SongInfo . Query , 4 ) ) . ToList ( ) . Shuffle ( ) . FirstOrDefault ( ) , silent , musicType ) . ConfigureAwait ( false ) ;
}
}
2016-10-05 05:01:19 +00:00
catch { }
2016-08-21 22:37:39 +00:00
}
} ;
mp . OnStarted + = async ( s , song ) = >
{
if ( song . PrintStatusMessage )
{
var sender = s as MusicPlayer ;
if ( sender = = null )
return ;
var msgTxt = $"🎵`Playing`{song.PrettyName} `Vol: {(int)(sender.Volume * 100)}%`" ;
2016-10-05 05:01:19 +00:00
try { playingMessage = await textCh . SendMessageAsync ( msgTxt ) . ConfigureAwait ( false ) ; } catch { }
2016-08-21 22:37:39 +00:00
}
} ;
return mp ;
} ) ;
Song resolvedSong ;
try
{
musicPlayer . ThrowIfQueueFull ( ) ;
resolvedSong = await Song . ResolveSong ( query , musicType ) . ConfigureAwait ( false ) ;
musicPlayer . AddSong ( resolvedSong , queuer . Username ) ;
}
catch ( PlaylistFullException )
{
2016-10-05 05:01:19 +00:00
try { await textCh . SendMessageAsync ( $"🎵 `Queue is full at {musicPlayer.MaxQueueSize}/{musicPlayer.MaxQueueSize}.` " ) ; } catch { }
2016-08-21 22:37:39 +00:00
throw ;
}
if ( ! silent )
{
2016-10-05 05:01:19 +00:00
try
2016-08-21 22:37:39 +00:00
{
2016-10-05 05:01:19 +00:00
var queuedMessage = await textCh . SendMessageAsync ( $"🎵`Queued`{resolvedSong.PrettyName} **at** `#{musicPlayer.Playlist.Count + 1}`" ) . ConfigureAwait ( false ) ;
var t = Task . Run ( async ( ) = >
2016-08-21 22:37:39 +00:00
{
2016-10-05 05:01:19 +00:00
await Task . Delay ( 10000 ) . ConfigureAwait ( false ) ;
try
{
await queuedMessage . DeleteAsync ( ) . ConfigureAwait ( false ) ;
}
catch { }
} ) . ConfigureAwait ( false ) ;
}
catch { } // if queued message sending fails, don't attempt to delete it
2016-08-21 22:37:39 +00:00
}
}
}
}