Removed module projects because it can't work like that atm. Commented out package commands.
This commit is contained in:
		
							
								
								
									
										239
									
								
								NadekoBot.Core/Modules/Music/Services/MusicService.cs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										239
									
								
								NadekoBot.Core/Modules/Music/Services/MusicService.cs
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,239 @@ | ||||
| using System.Collections.Concurrent; | ||||
| using System.Linq; | ||||
| using System.Threading.Tasks; | ||||
| using Discord; | ||||
| using NadekoBot.Extensions; | ||||
| using NadekoBot.Core.Services.Database.Models; | ||||
| using NLog; | ||||
| using System.IO; | ||||
| using Discord.Commands; | ||||
| using Discord.WebSocket; | ||||
| using NadekoBot.Common; | ||||
| using NadekoBot.Core.Services.Impl; | ||||
| using NadekoBot.Core.Services; | ||||
| using NadekoBot.Modules.Music.Common; | ||||
| using NadekoBot.Modules.Music.Common.Exceptions; | ||||
| using NadekoBot.Modules.Music.Common.SongResolver; | ||||
|  | ||||
| namespace NadekoBot.Modules.Music.Services | ||||
| { | ||||
|     public class MusicService : INService, IUnloadableService | ||||
|     { | ||||
|         public const string MusicDataPath = "data/musicdata"; | ||||
|  | ||||
|         private readonly IGoogleApiService _google; | ||||
|         private readonly NadekoStrings _strings; | ||||
|         private readonly ILocalization _localization; | ||||
|         private readonly DbService _db; | ||||
|         private readonly Logger _log; | ||||
|         private readonly SoundCloudApiService _sc; | ||||
|         private readonly IBotCredentials _creds; | ||||
|         private readonly ConcurrentDictionary<ulong, float> _defaultVolumes; | ||||
|         private readonly DiscordSocketClient _client; | ||||
|  | ||||
|         public ConcurrentDictionary<ulong, MusicPlayer> MusicPlayers { get; } = new ConcurrentDictionary<ulong, MusicPlayer>(); | ||||
|  | ||||
|         public MusicService(DiscordSocketClient client, IGoogleApiService google, | ||||
|             NadekoStrings strings, ILocalization localization, DbService db, | ||||
|             SoundCloudApiService sc, IBotCredentials creds, NadekoBot bot) | ||||
|         { | ||||
|             _client = client; | ||||
|             _google = google; | ||||
|             _strings = strings; | ||||
|             _localization = localization; | ||||
|             _db = db; | ||||
|             _sc = sc; | ||||
|             _creds = creds; | ||||
|             _log = LogManager.GetCurrentClassLogger(); | ||||
|  | ||||
|             _client.LeftGuild += _client_LeftGuild; | ||||
|  | ||||
|             try { Directory.Delete(MusicDataPath, true); } catch { } | ||||
|  | ||||
|             _defaultVolumes = new ConcurrentDictionary<ulong, float>( | ||||
|                 bot.AllGuildConfigs | ||||
|                     .ToDictionary(x => x.GuildId, x => x.DefaultMusicVolume)); | ||||
|  | ||||
|             Directory.CreateDirectory(MusicDataPath); | ||||
|         } | ||||
|  | ||||
|         public Task Unload() | ||||
|         { | ||||
|             _client.LeftGuild -= _client_LeftGuild; | ||||
|             return Task.CompletedTask; | ||||
|         } | ||||
|  | ||||
|         private Task _client_LeftGuild(SocketGuild arg) | ||||
|         { | ||||
|             var t = DestroyPlayer(arg.Id); | ||||
|             return Task.CompletedTask; | ||||
|         } | ||||
|  | ||||
|         public float GetDefaultVolume(ulong guildId) | ||||
|         { | ||||
|             return _defaultVolumes.GetOrAdd(guildId, (id) => | ||||
|             { | ||||
|                 using (var uow = _db.UnitOfWork) | ||||
|                 { | ||||
|                     return uow.GuildConfigs.For(guildId, set => set).DefaultMusicVolume; | ||||
|                 } | ||||
|             }); | ||||
|         } | ||||
|  | ||||
|         public Task<MusicPlayer> GetOrCreatePlayer(ICommandContext context) | ||||
|         { | ||||
|             var gUsr = (IGuildUser)context.User; | ||||
|             var txtCh = (ITextChannel)context.Channel; | ||||
|             var vCh = gUsr.VoiceChannel; | ||||
|             return GetOrCreatePlayer(context.Guild.Id, vCh, txtCh); | ||||
|         } | ||||
|  | ||||
|         public async Task<MusicPlayer> GetOrCreatePlayer(ulong guildId, IVoiceChannel voiceCh, ITextChannel textCh) | ||||
|         { | ||||
|             string GetText(string text, params object[] replacements) => | ||||
|                 _strings.GetText(text, _localization.GetCultureInfo(textCh.Guild), "Music".ToLowerInvariant(), replacements); | ||||
|  | ||||
|             _log.Info("Checks"); | ||||
|             if (voiceCh == null || voiceCh.Guild != textCh.Guild) | ||||
|             { | ||||
|                 if (textCh != null) | ||||
|                 { | ||||
|                     await textCh.SendErrorAsync(GetText("must_be_in_voice")).ConfigureAwait(false); | ||||
|                 } | ||||
|                 throw new NotInVoiceChannelException(); | ||||
|             } | ||||
|             _log.Info("Get or add"); | ||||
|             return MusicPlayers.GetOrAdd(guildId, _ => | ||||
|             { | ||||
|                 _log.Info("Getting default volume"); | ||||
|                 var vol = GetDefaultVolume(guildId); | ||||
|                 _log.Info("Creating musicplayer instance"); | ||||
|                 var mp = new MusicPlayer(this, _google, voiceCh, textCh, vol); | ||||
|  | ||||
|                 IUserMessage playingMessage = null; | ||||
|                 IUserMessage lastFinishedMessage = null; | ||||
|  | ||||
|                 _log.Info("Subscribing"); | ||||
|                 mp.OnCompleted += async (s, song) => | ||||
|                 { | ||||
|                     try | ||||
|                     { | ||||
|                         lastFinishedMessage?.DeleteAfter(0); | ||||
|  | ||||
|                         try | ||||
|                         { | ||||
|                             lastFinishedMessage = await mp.OutputTextChannel.EmbedAsync(new EmbedBuilder().WithOkColor() | ||||
|                                     .WithAuthor(eab => eab.WithName(GetText("finished_song")).WithMusicIcon()) | ||||
|                                     .WithDescription(song.PrettyName) | ||||
|                                     .WithFooter(ef => ef.WithText(song.PrettyInfo))) | ||||
|                                 .ConfigureAwait(false); | ||||
|                         } | ||||
|                         catch | ||||
|                         { | ||||
|                             // ignored | ||||
|                         } | ||||
|                     } | ||||
|                     catch | ||||
|                     { | ||||
|                         // ignored | ||||
|                     } | ||||
|                 }; | ||||
|                 mp.OnStarted += async (player, song) => | ||||
|                 { | ||||
|                     //try { await mp.UpdateSongDurationsAsync().ConfigureAwait(false); } | ||||
|                     //catch | ||||
|                     //{ | ||||
|                     //    // ignored | ||||
|                     //} | ||||
|                     var sender = player; | ||||
|                     if (sender == null) | ||||
|                         return; | ||||
|                     try | ||||
|                     { | ||||
|                         playingMessage?.DeleteAfter(0); | ||||
|  | ||||
|                         playingMessage = await mp.OutputTextChannel.EmbedAsync(new EmbedBuilder().WithOkColor() | ||||
|                                                     .WithAuthor(eab => eab.WithName(GetText("playing_song", song.Index + 1)).WithMusicIcon()) | ||||
|                                                     .WithDescription(song.Song.PrettyName) | ||||
|                                                     .WithFooter(ef => ef.WithText(mp.PrettyVolume + " | " + song.Song.PrettyInfo))) | ||||
|                                                     .ConfigureAwait(false); | ||||
|                     } | ||||
|                     catch | ||||
|                     { | ||||
|                         // ignored | ||||
|                     } | ||||
|                 }; | ||||
|                 mp.OnPauseChanged += async (player, paused) => | ||||
|                 { | ||||
|                     try | ||||
|                     { | ||||
|                         IUserMessage msg; | ||||
|                         if (paused) | ||||
|                             msg = await mp.OutputTextChannel.SendConfirmAsync(GetText("paused")).ConfigureAwait(false); | ||||
|                         else | ||||
|                             msg = await mp.OutputTextChannel.SendConfirmAsync(GetText("resumed")).ConfigureAwait(false); | ||||
|  | ||||
|                         msg?.DeleteAfter(10); | ||||
|                     } | ||||
|                     catch | ||||
|                     { | ||||
|                         // ignored | ||||
|                     } | ||||
|                 }; | ||||
|                 _log.Info("Done creating"); | ||||
|                 return mp; | ||||
|             }); | ||||
|         } | ||||
|  | ||||
|         public MusicPlayer GetPlayerOrDefault(ulong guildId) | ||||
|         { | ||||
|             if (MusicPlayers.TryGetValue(guildId, out var mp)) | ||||
|                 return mp; | ||||
|             else | ||||
|                 return null; | ||||
|         } | ||||
|  | ||||
|         public async Task TryQueueRelatedSongAsync(SongInfo song, ITextChannel txtCh, IVoiceChannel vch) | ||||
|         { | ||||
|             var related = (await _google.GetRelatedVideosAsync(song.VideoId, 4)).ToArray(); | ||||
|             if (!related.Any()) | ||||
|                 return; | ||||
|  | ||||
|             var si = await ResolveSong(related[new NadekoRandom().Next(related.Length)], _client.CurrentUser.ToString(), MusicType.YouTube); | ||||
|             if (si == null) | ||||
|                 throw new SongNotFoundException(); | ||||
|             var mp = await GetOrCreatePlayer(txtCh.GuildId, vch, txtCh); | ||||
|             mp.Enqueue(si); | ||||
|         } | ||||
|  | ||||
|         public async Task<SongInfo> ResolveSong(string query, string queuerName, MusicType? musicType = null) | ||||
|         { | ||||
|             query.ThrowIfNull(nameof(query)); | ||||
|  | ||||
|             ISongResolverFactory resolverFactory = new SongResolverFactory(_sc); | ||||
|             var strategy = await resolverFactory.GetResolveStrategy(query, musicType); | ||||
|             var sinfo = await strategy.ResolveSong(query); | ||||
|  | ||||
|             if (sinfo == null) | ||||
|                 return null; | ||||
|  | ||||
|             sinfo.QueuerName = queuerName; | ||||
|  | ||||
|             return sinfo; | ||||
|         } | ||||
|  | ||||
|         public async Task DestroyAllPlayers() | ||||
|         { | ||||
|             foreach (var key in MusicPlayers.Keys) | ||||
|             { | ||||
|                 await DestroyPlayer(key); | ||||
|             } | ||||
|         } | ||||
|  | ||||
|         public async Task DestroyPlayer(ulong id) | ||||
|         { | ||||
|             if (MusicPlayers.TryRemove(id, out var mp)) | ||||
|                 await mp.Destroy(); | ||||
|         } | ||||
|     } | ||||
| } | ||||
		Reference in New Issue
	
	Block a user