private async Task <List <FileDownloadingInfo> > InitDownloadingAsync(IList <Video> videos, string directory, DownloadQuality quality, string audioExtForced) { List <FileDownloadingInfo> result = new List <FileDownloadingInfo>(); //_client.DownloadClosedCaptionTrackAsync(); //ThreadPool.SetMaxThreads(Environment.ProcessorCount, Environment.ProcessorCount); if (!Directory.Exists(directory)) { Directory.CreateDirectory(directory); } foreach (var vid in videos) { try { StreamManifest infoSet = await _client.Videos.Streams.GetManifestAsync(vid.Id); string vidTitle = RemoveProhibitedChars(vid.Title); switch (quality) { case DownloadQuality.Default: case DownloadQuality.MuxedBest: IEnumerable <MuxedStreamInfo> muxedStreams = infoSet.GetMuxedStreams(); IVideoStreamInfo muxedHighestQuality = muxedStreams.GetWithHighestVideoQuality(); string ext = muxedHighestQuality.Container.Name; //string ext = "mkv"; string path = directory + "/" + vidTitle + "." + ext; var file = new FileDownloadingInfo() { Name = vidTitle, StreamInfo = muxedHighestQuality }; InitStreamDownloading(file, path, vid); result.Add(file); break; case DownloadQuality.SeparateBest: IEnumerable <IVideoStreamInfo> videoStreams = infoSet.GetVideoStreams(); IEnumerable <IAudioStreamInfo> audioStreams = infoSet.GetAudioStreams(); IStreamInfo highestBitRate = audioStreams.GetWithHighestBitrate(); IStreamInfo videoHighestQuality = videoStreams.GetWithHighestVideoQuality(); string extVideo = videoHighestQuality.Container.Name; string pathVideo = directory + "/" + vidTitle + "." + extVideo; string extAudio = highestBitRate.Container.Name; string pathAudio = directory + "/" + vidTitle + "." + extAudio; if (audioExtForced == String.Empty) { if (pathAudio.Equals(pathVideo)) { pathAudio += ".audio." + extAudio; } } else { pathAudio += "." + audioExtForced; } FileDownloadingInfo audio = new FileDownloadingInfo() { Name = vidTitle + "(audio)", StreamInfo = highestBitRate }; FileDownloadingInfo video = new FileDownloadingInfo() { Name = vidTitle, StreamInfo = videoHighestQuality }; if (File.Exists(pathAudio)) { _logger.Log("File " + pathAudio + "already exists!. Consider removing or renaming."); } else { InitStreamDownloading(audio, pathAudio, vid); result.Add(audio); } if (File.Exists(pathVideo)) { _logger.Log("File " + pathVideo + "already exists!. Consider removing or renaming."); } else { InitStreamDownloading(video, pathVideo, vid); result.Add(video); } break; default: throw new ArgumentOutOfRangeException(nameof(quality), quality, null); } } catch (Exception ex) { _logger.Log(ex.InnerException?.Message); } } return(result); }
public async Task PlayAsync(ICommandContext Context, ITextChannel Channel = null, bool KeepCurrent = false, TimeSpan?SeekTo = null, bool AvoidState = false) { if (Channel == null) { Channel = Context.Channel as ITextChannel; } string lId = Channel.GetSettings().Language; LanguageEntry Language = Global.Languages.GetLanguage(lId); if (!AvoidState) { if (State == PlayerState.Playing || State == PlayerState.Paused) { await Channel.SendMessageAsync(Language.GetEntry("MusicHandler:AlreadyPlaying")); return; } } if (State == PlayerState.Disconnected) { bool Success = await ConnectAsync(Context); if (!Success) { return; } } if (!KeepCurrent || Current == null) { Current = Queue[QueueIndex]; } string Url = Current.UrlOrId; WebSocket ws = null; if (Current.IsYouTube) { YoutubeClient Client = new YoutubeClient(); StreamManifest sm = null; try { sm = await Client.Videos.Streams.GetManifestAsync(VideoId.TryParse(Current.UrlOrId).Value); } catch (Exception e) { File.WriteAllText("tempexceptionfrommusicplayer.json", JsonConvert.SerializeObject(e, Formatting.Indented)); await Global.Client.GetGuild(Global.Settings.DevServer.Id) .GetTextChannel(Global.Settings.DevServer.ErrorReportChannelId).SendFileAsync("tempexceptionfrommusicplayer.json", ""); File.Delete("tempexceptionfrommusicplayer.json"); } if (sm != null) { IEnumerable <IAudioStreamInfo> streamInfos = sm.GetAudioStreams(); if (streamInfos.Count() > 0) { IStreamInfo info = streamInfos.GetWithHighestBitrate(); Url = info.Url; } } if (Url == Current.UrlOrId) { Url = null; } } else { if (Current.IsListenMoe) { Url = Current.PublicUrl; ws = new WebSocket(Current.PublicUrl.Contains("kpop") ? "wss://listen.moe/kpop/gateway_v2" : "wss://listen.moe/gateway_v2"); Timer t = new Timer((state) => { try { ws.Send("{ \"op\": 9 }"); } catch { Logger.Log(LogType.WebSocket, ConsoleColor.Red, "Error", "Couldn't send heartbeat to LISTEN.moe!"); } }, null, -1, -1); ws.OnOpen += (s, e) => { ws.Send("{ \"op\": 0, \"d\": { \"auth\": \"\" } }"); // { op: 0, d: { auth: "" } } }; ws.OnMessage += (s, e) => { ListenMoe parsed = JsonConvert.DeserializeObject <ListenMoe>(e.Data); if (parsed.OpCode == 0) { t.Change(0, parsed.Data.HeartBeat); } else if (parsed.OpCode == 1 && parsed.Type == "TRACK_UPDATE") { ListenMoeStartTime = parsed.Data.StartTime; Current.Author = string.Join(" && ", parsed.Data.Song.Artists.Select(i => i.NameRomaji ?? i.Name)); Current.Duration = TimeSpan.FromSeconds(parsed.Data.Song.Duration); Current.Title = parsed.Data.Song.Title; Current.Thumbnail = null; foreach (ListenMoeAlbum album in parsed.Data.Song.Albums) { if (album.Image != null) { Current.Thumbnail = album.Image; break; } } if (State > PlayerState.Connected && State != PlayerState.Paused) { SendNowPlayingAsync(Context, Channel).GetAwaiter().GetResult(); } } }; ws.OnClose += (s, e) => { t.Change(Timeout.Infinite, Timeout.Infinite); t.Dispose(); }; ws.Connect(); } else if (Global.SoundCloud == null) { if (!IterateIndex(true)) { Current = null; await Channel.SendMessageAsync(Language.GetEntry("MusicHandler:SoundCloudNotAvailable")); } else { await Channel.SendMessageAsync(Language.GetEntry("MusicHandler:OnlySoundCloudTracks")); new Task(async() => await PlayAsync(Context, Channel, AvoidState: true)); } return; } else { Url += "?client_id=" + Global.SoundCloud.ClientId; } } if (Url == null) { if (!IterateIndex()) { Current = null; await Channel.SendMessageAsync(Language.GetEntry("MusicHandler:FinishedPlaying")); State = PlayerState.Connected; } else { new Task(async() => await PlayAsync(Context, Channel, AvoidState: true)).Start(); return; } } try { Reader = new FFmpegReader(Url); /* * switch (encoding.Name) * { * case "webm": * case "3gpp": * Stream s = await new HttpClient().GetStreamAsync(Url); * Reader = new NAudio.Vorbis.VorbisWaveReader(s); * break; * * default: * Reader = new MediaFoundationReader(Url); * break; * } */ } catch (Exception e) { System.Console.WriteLine(e); await Channel.SendMessageAsync(Language.GetEntry("MusicHandler:SongInaccessible", "SONGNAME", Current.Title)); if (!IterateIndex(Global.SoundCloud == null)) { Current = null; await Channel.SendMessageAsync(Language.GetEntry("MusicHandler:FinishedPlaying")); State = PlayerState.Connected; } else { new Task(async() => await PlayAsync(Context, Channel, AvoidState: true)).Start(); } return; } if (PCMStream == null || !PCMStream.CanWrite) { PCMStream = Client.CreatePCMStream(AudioApplication.Music, 128 * 1024, 200, 0); } //WaveFormat OutFormat = new WaveFormat(48000, 16, 2); /* * MediaFoundationResampler Resampler = new MediaFoundationResampler(Reader, OutFormat) * { * ResamplerQuality = 60 * }; */ //if (SeekTo.HasValue && !Current.IsListenMoe) Reader.CurrentTime = SeekTo.Value; if (SeekTo.HasValue && SeekTo != TimeSpan.Zero && !Current.IsListenMoe) { Reader.ReadUntil(SeekTo.Value); } BackupTime = TimeSpan.Zero; //int Size = OutFormat.AverageBytesPerSecond / 50; int Size = Reader.BufferSize(1); byte[] Buffer = new byte[Size]; int Count = 0; State = PlayerState.Playing; TextChannelId = Channel.Id; if (!Current.IsListenMoe) { await SendNowPlayingAsync(Context, Channel); } /*while (Reader.CanRead && (Count = Resampler.Read(Buffer, 0, Size)) > 0 * && Request == PlayerRequest.Idle && State > PlayerState.Connected)*/ while (Reader.CanRead && (Count = Reader.Read(Buffer, 0, Size)) > 0 && Request == PlayerRequest.Idle && State > PlayerState.Connected) { if (State == PlayerState.Paused) { await Channel.SendMessageAsync("", embed : new EmbedBuilder() { Title = Language.GetEntry("MusicHandler:Paused"), Color = Color }.Build()); while (State == PlayerState.Paused && Request == PlayerRequest.Idle) { Thread.Sleep(100); } string cId = Channel.GetSettings().Language; if (cId != lId) { Language = Global.Languages.GetLanguage(cId); } lId = cId; if (State == PlayerState.Playing) { await Channel.SendMessageAsync("", embed : new EmbedBuilder() { Title = Language.GetEntry("MusicHandler:Resumed"), Color = Color }.Build()); if (Current.IsListenMoe) { await SendNowPlayingAsync(Context, Channel); } } } if (Request > 0) { break; } if (CurrentTime.TotalSeconds % 10 == 0 && BackupTime.TotalSeconds != CurrentTime.TotalSeconds) { PropertyChanged?.Invoke(); BackupTime = CurrentTime; } try { if (State < PlayerState.Playing) { break; } ChangeVolume(Buffer, Volume / 100f); await PCMStream.WriteAsync(Buffer, 0, Count); } catch (Exception e) { if (State == PlayerState.Disconnected || Client.ConnectionState == ConnectionState.Disconnected || Client.ConnectionState == ConnectionState.Disconnecting) { break; } string cId = Channel.GetSettings().Language; if (cId != lId) { Language = Global.Languages.GetLanguage(cId); } lId = cId; await Channel.SendMessageAsync(Language.GetEntry("MusicHandler:PlaybackErrorOccured")); Request = PlayerRequest.Stop; Logger.Log(LogType.Music, ConsoleColor.Red, "Error", e.ToString()); if (Global.Settings.DevServer.ErrorReportChannelId != 0) { ITextChannel Report = Global.Client.GetChannel(Global.Settings.DevServer.ErrorReportChannelId) as ITextChannel; await Report.SendMessageAsync($"An error occured while playing on a server!\n```\n{ e }\n```\n" + $"Client:\n { JsonConvert.SerializeObject(this) }"); } break; } } if (ws != null && ws.IsAlive) { ws.Close(); } if (Request == PlayerRequest.Idle && State > PlayerState.Connected) { Request = PlayerRequest.Next; } //Resampler.Dispose(); Reader.Dispose(); Reader = null; //Resampler = null; try { await PCMStream.FlushAsync(); } catch { } // It may be disposed if (Request == PlayerRequest.Next) { Request = PlayerRequest.Idle; if (!IterateIndex(Global.SoundCloud == null)) { if (State != PlayerState.Connected && State != PlayerState.Disconnected) { State = PlayerState.Connected; } Current = null; string cId = Channel.GetSettings().Language; if (cId != lId) { Language = Global.Languages.GetLanguage(cId); } lId = cId; await Channel.SendMessageAsync(Language.GetEntry("MusicHandler:FinishedPlaying")); } } else if (Request == PlayerRequest.Stop) { Request = PlayerRequest.Idle; State = PlayerState.Connected; Current = null; } if (State > PlayerState.Connected) { new Task(async() => await PlayAsync(Context, Channel, AvoidState: true)).Start(); } }