public static void PlayerThread()
 {
     Bridge.ALog("播放器已启动");
     while (!Vars.CallPlayerStop)
     {
         if (fileList.Count != 0)
         {
             Bridge.ALog("启动播放,剩余数目:" + fileList.Count);
             var fileName = fileList[0].Filename;
             try
             {
                 Play(fileName, true, fileList[0].DoNotDelete);
             }
             catch (Exception ex)
             {
                 Bridge.ALog($"无法读取/播放文件 {Path.GetFileName(fileName)}, 放弃: {ex.Message}");
             }
             if (fileList.Count > 0)
             {
                 fileList.RemoveAt(0);
             }
         }
         try { Thread.Sleep(100); } catch { }
     }
     Bridge.ALog("播放器已停止");
     Vars.CallPlayerStop = false;
 }
示例#2
0
        public async Task GiftRoute(object sender, ReceivedDanmakuArgs e)
        {
            // check user eligibility
            if (!Conf.CheckUserEligibility(e))
            {
                return;
            }
            // check gift eligibility
            if (!Conf.CheckGiftEligibility(e))
            {
                return;
            }
            Bridge.ALog("规则检查通过,准备朗读");
            if (Vars.CurrentConf.VoiceReplyFirst)
            {
                var hitAnyRule = await TTSPlayer.PlayVoiceReply(e.Danmaku);

                if (!hitAnyRule || !Vars.CurrentConf.IgnoreIfHitVoiceReply)
                {
                    await TTSPlayer.UnifiedPlay(ProcessGift(e));
                }
            }
            else
            {
                var hitAnyRule = Vars.CurrentConf.VoiceReplyRules.Any(x => x.Matches(e.Danmaku));
                if (!hitAnyRule || !Vars.CurrentConf.IgnoreIfHitVoiceReply)
                {
                    await TTSPlayer.UnifiedPlay(ProcessGift(e));
                }
                await TTSPlayer.PlayVoiceReply(e.Danmaku);
            }
        }
示例#3
0
        public static string Download(string content, string language)
        {
            var errorCount = 0;

Retry:
            try
            {
                var fileName = Path.Combine(Vars.CacheDir, Conf.GetRandomFileName() + "GOOG.mp3");
                Bridge.ALog("(E2) 正在下载 TTS, 文件名: " + fileName);
                var instance = new GoogleTTS(content, language);
                instance.WriteFile(fileName);
                // validate if file is playable
                using (var reader = new AudioFileReader(fileName)) { }
                return(fileName);
            }
            catch (Exception ex)
            {
                Bridge.ALog("(E2) TTS 下载失败: " + ex.Message);
                errorCount += 1;
                Vars.TotalFails++;
                if (errorCount <= Vars.CurrentConf.DownloadFailRetryCount)
                {
                    goto Retry;
                }
                return(null);
            }
        }
示例#4
0
        public async Task InteractRoute(object sender, ReceivedMessageArgs e)
        {
            // check user eligibility
            if (!Conf.CheckUserEligibility(e))
            {
                return;
            }
            Bridge.ALog("规则检查通过,正在朗读用户交互事件");

            string result;

            switch (e.Message.MsgType)
            {
            case MsgTypeEnum.UserEnter:
                result = ProcessInteract(e.Message, Vars.CurrentConf.OnInteractEnter);
                break;

            case MsgTypeEnum.LiveShare:
                result = ProcessInteract(e.Message, Vars.CurrentConf.OnInteractShare);
                break;

            default: return;
            }

            await TTSPlayer.UnifiedPlay(result);
        }
示例#5
0
        public static async Task <string> Download(string content)
        {
            {
                var errorCount = 0;
Retry:
                try
                {
                    var fileName = Path.Combine(Vars.CacheDir, Conf.GetRandomFileName() + "YODO.mp3");
                    Bridge.ALog("(E4) 正在下载 TTS, 文件名: " + fileName);
                    using (var downloader = new WebClient())
                    {
                        downloader.Headers.Add(HttpRequestHeader.AcceptEncoding, "identity;q=1, *;q=0");
                        downloader.Headers.Add(HttpRequestHeader.Referer, "http://fanyi.youdao.com/");
                        downloader.Headers.Add(HttpRequestHeader.UserAgent, "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/75.0.3770.100 Safari/537.36");
                        await downloader.DownloadFileTaskAsync(Vars.ApiYoudao.Replace("$TTSTEXT", content),
                                                               fileName);

                        // validate if file is playable
                        using (var reader = new AudioFileReader(fileName)) { }
                        return(fileName);
                    }
                }
                catch (Exception ex)
                {
                    Bridge.ALog("(E4) TTS 下载失败: " + ex.Message);
                    errorCount += 1;
                    Vars.TotalFails++;
                    if (errorCount <= Vars.CurrentConf.DownloadFailRetryCount)
                    {
                        goto Retry;
                    }
                    return(null);
                }
            }
        }
示例#6
0
 public static async Task WelcomeRoute(object sender, ReceivedDanmakuArgs e)
 {
     // check user eligibility
     if (!Conf.CheckUserEligibility(e))
     {
         return;
     }
     Bridge.ALog("规则检查通过,准备朗读");
     await TTSPlayer.UnifiedPlay(Vars.CurrentConf.OnWelcome
                                 .Replace("$USER", e.Danmaku.UserName)
                                 , true
                                 );
 }
示例#7
0
 public static async Task GuardBuyRoute(object sender, ReceivedDanmakuArgs e)
 {
     // check user eligibility
     if (!Conf.CheckUserEligibility(e))
     {
         return;
     }
     Bridge.ALog("规则检查通过,准备朗读");
     await TTSPlayer.UnifiedPlay(Vars.CurrentConf.OnGuardBuy
                                 .Replace("$COUNT", e.Danmaku.GiftCount.ToString())
                                 .Replace("$USER", e.Danmaku.UserName)
                                 , true
                                 );
 }
            public static async Task <string> Download(string content, SpeechPerson person)
            {
                var errorCount = 0;

Retry:
                try
                {
                    var fileName = Path.Combine(Vars.CacheDir, Conf.GetRandomFileName() + "BDAI.mp3");
                    using (var downloader = new WebClient())
                    {
                        if (string.IsNullOrEmpty(Vars.ApiBaiduAiAccessToken))
                        {
                            Bridge.ALog("(E6) 正在获取 Access token...");
                            var rawJson =
                                await downloader.DownloadStringTaskAsync(
                                    $"https://openapi.baidu.com/oauth/2.0/token?grant_type=client_credentials&client_id={Vars.ApiBaiduAiAppKey}&client_secret={Vars.ApiBaiduAiSecretKey}"
                                    );

                            Vars.ApiBaiduAiAccessToken = JObject.Parse(rawJson)["access_token"].ToString();
                            Bridge.ALog("(E6) Token 获取成功,本次运行时或 30 天内有效");
                        }
                        Bridge.ALog("(E6) 正在下载 TTS, 文件名: " + fileName);
                        downloader.Headers.Add(HttpRequestHeader.AcceptEncoding, "identity;q=1, *;q=0");
                        downloader.Headers.Add(HttpRequestHeader.UserAgent, "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/75.0.3770.100 Safari/537.36");
                        var url = Vars.ApiBaiduAi
                                  .Replace("$PERSON", ((int)person).ToString())
                                  .Replace("$SPEED", ConvertSpeed(Vars.CurrentConf.ReadSpeed).ToString())
                                  .Replace("$PITCH", ConvertSpeed(Vars.CurrentConf.SpeechPitch).ToString())
                                  .Replace("$TOKEN", Vars.ApiBaiduAiAccessToken)
                                  .Replace("$TTSTEXT", content);
                        await downloader.DownloadFileTaskAsync(url, fileName);

                        // validate if file is playable
                        using (var reader = new AudioFileReader(fileName)) { }
                        return(fileName);
                    }
                }
                catch (Exception ex)
                {
                    Bridge.ALog("(E6) TTS 下载失败: " + ex.Message);
                    errorCount += 1;
                    Vars.TotalFails++;
                    if (errorCount <= Vars.CurrentConf.DownloadFailRetryCount)
                    {
                        goto Retry;
                    }
                    return(null);
                }
            }
示例#9
0
 public async Task SuperChatRoute(object sender, ReceivedDanmakuArgs e)
 {
     // check user eligibility
     if (!Conf.CheckUserEligibility(e))
     {
         return;
     }
     // check content eligibility
     if (!Conf.CheckKeywordEligibility(e))
     {
         return;
     }
     // check length rule
     if (!Conf.CheckDanmakuLength(e))
     {
         return;
     }
     Bridge.ALog("规则检查通过,准备朗读");
     await TTSPlayer.UnifiedPlay(ProcessSuperChat(e), Vars.CurrentConf.SuperChatIgnoreRandomDitch);
 }
示例#10
0
 public static async Task <bool> PlayVoiceReply(MessageModel e, VoiceReplyRule rule, bool alwaysMatch = false, bool overrideReadInQueue = false)
 {
     if (alwaysMatch || rule.Matches(e))
     {
         if ((VoiceReplyRule.ReplyMode)rule.ReplyingMode != VoiceReplyRule.ReplyMode.VoiceGeneration)
         {
             // play specific file:
             try
             {
                 if (Vars.CurrentConf.InstantVoiceReply || overrideReadInQueue)
                 {
                     Play(rule.ReplyContent, false, true);
                 }
                 else
                 {
                     // add the file to queue
                     fileList.Add(new TTSEntry(rule.ReplyContent, true));
                 }
             }
             catch (Exception ex)
             {
                 Bridge.ALog($"无法读出语音答复: {ex.Message}");
             }
         }
         else
         {
             // play by voice generation (and by default)
             // caution: different types of voice reply have different variables available
             await UnifiedPlay(
                 Main.ProcessVoiceReply(e, rule),
                 true,
                 Vars.CurrentConf.InstantVoiceReply || overrideReadInQueue
                 );
         }
         return(true);
     }
     else
     {
         return(false);
     }
 }
示例#11
0
        public async Task InteractRoute(object sender, ReceivedDanmakuArgs e)
        {
            // check user eligibility
            if (!Conf.CheckUserEligibility(e))
            {
                return;
            }
            Bridge.ALog("规则检查通过,正在朗读用户交互事件");

            string result;

            switch (e.Danmaku.InteractType)
            {
            case InteractTypeEnum.Enter:
                result = ProcessInteract(e.Danmaku, Vars.CurrentConf.OnInteractEnter);
                break;

            case InteractTypeEnum.Follow:
                result = ProcessInteract(e.Danmaku, Vars.CurrentConf.OnInteractFollow);
                break;

            case InteractTypeEnum.MutualFollow:
                result = ProcessInteract(e.Danmaku, Vars.CurrentConf.OnInteractMutualFollow);
                break;

            case InteractTypeEnum.Share:
                result = ProcessInteract(e.Danmaku, Vars.CurrentConf.OnInteractShare);
                break;

            case InteractTypeEnum.SpecialFollow:
                result = ProcessInteract(e.Danmaku, Vars.CurrentConf.OnInteractSpecialFollow);
                break;

            default: return;
            }

            await TTSPlayer.UnifiedPlay(result);
        }
示例#12
0
        public async Task CommentRoute(object sender, ReceivedMessageArgs e)
        {
            // check user eligibility
            if (!Conf.CheckUserEligibility(e))
            {
                return;
            }
            // check content eligibility
            if (!Conf.CheckKeywordEligibility(e))
            {
                return;
            }
            // check length rule
            if (!Conf.CheckDanmakuLength(e))
            {
                return;
            }
            Bridge.ALog("规则检查通过,准备朗读");
            if (Vars.CurrentConf.VoiceReplyFirst)
            {
                var hitAnyRule = await TTSPlayer.PlayVoiceReply(e.Message);

                if (!hitAnyRule || !Vars.CurrentConf.IgnoreIfHitVoiceReply)
                {
                    await TTSPlayer.UnifiedPlay(ProcessDanmaku(e));
                }
            }
            else
            {
                var hitAnyRule = Vars.CurrentConf.VoiceReplyRules.Any(x => x.Matches(e.Message));
                if (!hitAnyRule || !Vars.CurrentConf.IgnoreIfHitVoiceReply)
                {
                    await TTSPlayer.UnifiedPlay(ProcessDanmaku(e));
                }
                await TTSPlayer.PlayVoiceReply(e.Message);
            }
        }
示例#13
0
        /// <summary>
        /// Play something, other options are defined by current configurations
        /// </summary>
        /// <param name="content">Final TTS Content</param>
        /// <param name="ignoreRandomDitch">Specify true to ignore random ditching</param>
        public static async Task UnifiedPlay(string content, bool ignoreRandomDitch = false, bool overrideReadInQueue = false)
        {
            if (string.IsNullOrWhiteSpace(content))
            {
                Bridge.ALog("放弃: 内容为空");
                return;
            }
            Bridge.ALog("尝试朗读: " + content);
            if (!Conf.GetRandomBool(Vars.CurrentConf.ReadPossibility) && !ignoreRandomDitch)
            {
                Bridge.ALog("放弃: 已随机丢弃");
                return;
            }
            string fileName;

            if (Vars.CurrentConf.EnableUrlEncode)
            {
                content = HttpUtility.UrlEncode(content);
                Bridge.ALog("URL 编码完成: " + content);
            }
            switch (Vars.CurrentConf.Engine)
            {
            default:
                fileName = await BaiduTTS.Download(content);

                break;

            case 1:
                if (!Vars.SystemSpeechAvailable)
                {
                    Bridge.Log(".NET 框架引擎在此系统上不可用,无法朗读");
                    return;
                }
                fileName = FrameworkTTS.Download(content);
                break;

            case 2:
                fileName = GoogleTTS.Download(content, "zh-CN");
                break;

            case 3:
                fileName = await BaiduTTS.Download(content, true);

                break;

            case 4:
                fileName = await YoudaoTTS.Download(content);

                break;

            case 5:
                fileName = await CustomTTS.Download(content);

                break;

            case 6:
                fileName = await BaiduTTS.AiApi.Download(content, BaiduTTS.AiApi.ParseToSpeechPerson(Vars.CurrentConf.SpeechPerson));

                break;
            }
            if (fileName == null)
            {
                Bridge.ALog("下载失败,丢弃");
                return;
            }
            if (Vars.CurrentConf.ReadInQueue && !overrideReadInQueue)
            {
                Bridge.ALog($"正在添加下列文件到播放列表: {fileName}");
                fileList.Add(new TTSEntry(fileName));
            }
            else
            {
                Bridge.ALog($"正在直接播放: {fileName}");
                Play(fileName, false);
            }
        }
示例#14
0
        public static void Play(string filename, bool wait = true, bool forceKeepCache = false)
        {
            var frame  = new DispatcherFrame();
            var thread = new Thread(() =>
            {
                try
                {
                    using (var reader = new AudioFileReader(filename))
                    {
                        bool exists      = false;
                        var targetDevice = Vars.CurrentConf.DeviceGuid;
                        foreach (var dev in DirectSoundOut.Devices)
                        {
                            if (dev.Guid == Vars.CurrentConf.DeviceGuid)
                            {
                                exists = true;
                                break;
                            }
                        }
                        if (!exists)
                        {
                            if (Vars.CurrentConf.AutoFallback)
                            {
                                Bridge.ALog($"设备 {Vars.CurrentConf.DeviceGuid} 不存在,正在自动回落到默认设备。");
                                targetDevice = Conf.DefaultDeviceGuid;
                            }
                            else
                            {
                                throw new ArgumentOutOfRangeException($"设备 {Vars.CurrentConf.DeviceGuid} 不存在。");
                            }
                        }
                        using (var waveOut = new DirectSoundOut(targetDevice))
                        {
                            waveOut.Init(reader);
                            reader.Volume = Volume;
                            Bridge.ALog($"音量设置为: {Volume}");
                            waveOut.Play();
                            Vars.TotalPlayed++;
                            if (!wait)
                            {
                                frame.Continue = false;
                            }
                            while (waveOut.PlaybackState != PlaybackState.Stopped)
                            {
                                if (Vars.CallPlayerStop)
                                {
                                    waveOut.Stop();
                                }
                                if (!reader.Volume.IsNearEnough(Volume, 0.02f))
                                {
                                    Bridge.ALog($"同步音量: {Volume}");
                                    reader.Volume = Volume;
                                }
                                Thread.Sleep(50);
                            }
                        }
                    }
                }
                catch (Exception ex)
                {
                    Bridge.ALog($"播放过程中发生错误: {Path.GetFileName(filename)}: {ex.Message}");
                }
                finally
                {
                    try
                    {
                        if (Vars.CurrentConf.DoNotKeepCache && !forceKeepCache)
                        {
                            Bridge.ALog($"正在删除缓存文件: {filename}");
                            File.Delete(filename);
                        }
                    }
                    catch (Exception ex)
                    {
                        Bridge.ALog($"无法删除缓存文件 {filename}: {ex.Message}");
                    }
                }
                frame.Continue = false;
            });

            thread.SetApartmentState(ApartmentState.STA);
            thread.Start();
            Dispatcher.PushFrame(frame);
        }
示例#15
0
 public void OnReceivedRoomCount(object sender, ReceivedRoomCountArgs e)
 {
     Vars.RoomCount = e.UserCount;
     Bridge.ALog("OnReceivedRoomCount: " + e.UserCount);
 }
示例#16
0
        public static async Task <string> Download(string content)
        {
            var errorCount = 0;

Retry:
            try
            {
                var fileName = Path.Combine(Vars.CacheDir, Conf.GetRandomFileName() + "USER.mp3");
                Bridge.ALog($"(E5) 正在下载 TTS, 文件名: {fileName}, 方法: {Vars.CurrentConf.ReqType}");
                if (Vars.CurrentConf.ReqType == RequestType.ApplicationXWwwFormUrlencoded || Vars.CurrentConf.ReqType == RequestType.TextPlain)
                {
                    Bridge.ALog("POST 模式: text/plain / application/x-www-form-urlencoded");
                    // 配置 Headers
                    var uploader = WebRequest.CreateHttp(Vars.CurrentConf.CustomEngineURL);
                    uploader.Method = "POST";
                    if (Vars.CurrentConf.HttpAuth)
                    {
                        uploader.Credentials     = new NetworkCredential(Vars.CurrentConf.HttpAuthUsername, Vars.CurrentConf.HttpAuthPassword);
                        uploader.PreAuthenticate = true;
                    }
                    foreach (var header in Vars.CurrentConf.Headers)
                    {
                        Bridge.ALog($"添加 Header: {header.Name}, 值 {header.Value}");
                        uploader.Headers.Add(header.Name, header.Value);
                    }
                    uploader.ContentType = Vars.CurrentConf.ReqType == RequestType.ApplicationXWwwFormUrlencoded ? "application/x-www-form-urlencoded" : "text/plain";

                    // 准备数据
                    var data       = Encoding.UTF8.GetBytes(Vars.CurrentConf.PostData);
                    var dataStream = uploader.GetRequestStream();
                    dataStream.Write(data, 0, data.Length);
                    dataStream.Close();
                    uploader.ContentLength = data.Length;

                    // 等响应
                    using (var res = uploader.GetResponse())
                    {
                        // 写数据
                        using (var writer = new StreamWriter(File.OpenWrite(fileName))
                        {
                            AutoFlush = true
                        })
                        {
                            byte[] responseData = new byte[res.ContentLength];
                            res.GetResponseStream().Read(responseData, 0, responseData.Length);
                            writer.Write(responseData);
                        }
                    }
                }
                else if (Vars.CurrentConf.ReqType == RequestType.MultipartFormData)
                {
                    using (var httpClient = new HttpClient())
                    {
                        var form = new MultipartFormDataContent();
                        // 配置 Headers
                        if (Vars.CurrentConf.HttpAuth)
                        {
                            var authArray = Encoding.UTF8.GetBytes($"{Vars.CurrentConf.HttpAuthUsername}:{Vars.CurrentConf.HttpAuthPassword}");
                            httpClient.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Basic", Convert.ToBase64String(authArray));
                        }
                        foreach (var header in Vars.CurrentConf.Headers)
                        {
                            Bridge.ALog($"添加 Header: {header.Name}, 值 {header.Value}");
                            httpClient.DefaultRequestHeaders.Add(header.Name, header.Value);
                        }
                        // 转换数据
                        var postItems = JsonConvert.DeserializeObject <List <Header> >(Vars.CurrentConf.PostData);
                        foreach (var item in postItems)
                        {
                            var data = Convert.FromBase64String(item.Value);
                            form.Add(new ByteArrayContent(data, 0, data.Length), item.Name);
                        }
                        // 抓结果
                        using (var res = await httpClient.PostAsync(Vars.CurrentConf.CustomEngineURL, form))
                        {
                            res.EnsureSuccessStatusCode();
                            // 写数据
                            using (var writer = new StreamWriter(File.OpenWrite(fileName))
                            {
                                AutoFlush = true
                            })
                            {
                                var responseData = await res.Content.ReadAsByteArrayAsync();

                                writer.Write(responseData);
                            }
                        }
                    }
                }
                else
                {
                    Bridge.ALog("GET 模式");
                    using (var downloader = new WebClient())
                    {
                        downloader.Headers.Add(HttpRequestHeader.UserAgent, "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/75.0.3770.100 Safari/537.36");
                        foreach (var header in Vars.CurrentConf.Headers)
                        {
                            Bridge.ALog($"添加 Header: {header.Name}, 值 {header.Value}");
                            downloader.Headers.Add(header.Name, header.Value);
                        }
                        if (Vars.CurrentConf.HttpAuth)
                        {
                            downloader.Credentials = new NetworkCredential(Vars.CurrentConf.HttpAuthUsername, Vars.CurrentConf.HttpAuthPassword);
                        }
                        await downloader.DownloadFileTaskAsync(Vars.CurrentConf.CustomEngineURL.Replace("$TTSTEXT", content), fileName);
                    }
                }
                // validate if file is playable
                using (var reader = new AudioFileReader(fileName)) { }
                return(fileName);
            }
            catch (Exception ex)
            {
                Bridge.ALog($"(E5) TTS 下载失败: {ex.Message}");
                errorCount += 1;
                Vars.TotalFails++;
                if (errorCount <= Vars.CurrentConf.DownloadFailRetryCount)
                {
                    goto Retry;
                }
                return(null);
            }
        }