private void YoutubeLiveCheckTimer(IEnumerable <VtuberEntity> vtubers) { var threadPool = new SimpleThreadPool() { MaxThread = 20 }; foreach (var vtuber in vtubers.Where(v => !string.IsNullOrEmpty(v.YoutubeChannelId))) { threadPool.Actions.Enqueue(() => { if (!LastCheckYoutubeLiveStatus.ContainsKey(vtuber)) { LastCheckYoutubeLiveStatus.Add(vtuber, new YoutubeVideo()); } var onLive = YoutubeApi.NowLive(vtuber.YoutubeChannelId).GetAwaiter().GetResult(); if (onLive) { var channelInfo = YoutubeApi.GetYoutubeChannelAsync(vtuber.YoutubeChannelId).GetAwaiter().GetResult(); if (!LastCheckYoutubeLiveStatus[vtuber].IsLive || channelInfo.LiveVideoId != LastCheckYoutubeLiveStatus[vtuber].VideoId) { var live = YoutubeApi.GetYoutubeVideoAsync(channelInfo.LiveVideoId).GetAwaiter().GetResult(); if (!live.IsLive) { return; } if (!LastCheckYoutubeLiveStatus[vtuber].IsLive) { LastCheckYoutubeLiveStatus[vtuber] = live; var recorder = new YoutubeLiveChatRecorder(live.LiveDetails.LiveChatId, vtuber, live.VideoId) { VtuberList = vtubers.ToList() }; recorder.StartRecord(); recorder.LiveStoppedEvent += (id, sender) => { LogHelper.Info($"{vtuber.OriginalName} 已停止直播,正在保存评论数据"); live = YoutubeApi.GetYoutubeVideoAsync(channelInfo.LiveVideoId).Retry(5).GetAwaiter().GetResult() ?? live; var info = new YoutubeLiveInfo() { Title = live.Title, Channel = live.ChannelId, BeginTime = live.LiveDetails?.ActualStartTime ?? default(DateTime), EndTime = live.LiveDetails?.ActualEndTime ?? DateTime.Now, VideoId = live.VideoId }; _youtubeLiveCollection.ReplaceOne(v => v.VideoId == live.VideoId, info, new UpdateOptions() { IsUpsert = true }); LogHelper.Info("保存完毕"); VtuberStoppedYoutubeLiveEvent?.Invoke(vtuber, live); }; recorder.VtuberCommentedEvent += (author, message, sender) => VtuberCommentedYoutubeLiveEvent?.Invoke(author, sender.Vtuber, message, live); VtuberBeginYoutubeLiveEvent?.Invoke(vtuber, live); } } } if (!onLive) { LastCheckYoutubeLiveStatus[vtuber] = new YoutubeVideo(); } }); } threadPool.Run(); }
public LocalVtuberBot(ISendMessageService service, IServerMessageSubject transponder, QQUser user) : base(service, transponder, user) { _youtubeLiveCollection = Program.Database.GetCollection <YoutubeLiveInfo>("youtube-live-details"); _biliLiveCollection = Program.Database.GetCollection <BiliBiliLiveInfo>("bili-live-details"); _tweetCollection = Program.Database.GetCollection <TweetInfo>("tweet-details"); CacheManager.Manager.VtuberBeginLiveEvent += (vtuber, video) => { var info = YoutubeApi.GetYoutubeVideo(video.VideoId); LogHelper.Info($"Vtuber {vtuber.OriginalName} 开始了直播 {video.VideoLink}"); foreach (var(key, value) in Config.DefaultConfig.Subscribes) { var config = value.FirstOrDefault(v => string.Equals(v.VtuberName, vtuber.OriginalName, StringComparison.CurrentCultureIgnoreCase)); if (config?.BeginLive ?? false) { _service.SendToGroup(key, $"{vtuber.OriginalName} 在 {info.LiveDetails.ActualStartTime.ToUniversalTime().AddHours(8):yyyy-MM-dd HH:mm:ss} 开始直播 {video.Title}\r\n" + $"链接: {video.VideoLink}\r\n当前观众数量: {info.LiveDetails.ViewersCount}\r\n" + $"原定直播时间: {info.LiveDetails.ScheduledStartTime.ToUniversalTime().AddHours(8):yyyy-MM-dd HH:mm:ss}\r\n" + $"实际开播时间: {info.LiveDetails.ActualStartTime.ToUniversalTime().AddHours(8):yyyy-MM-dd HH:mm:ss}"); } } var recorder = new LiveChatRecorder(info.LiveDetails.LiveChatId, vtuber, video.VideoId); recorder.StartRecord(); recorder.LiveStoppedEvent += (id, recder) => { LogHelper.Info($"{vtuber.OriginalName} 已停止直播, 正在保存评论数据..."); info = YoutubeApi.GetYoutubeVideo(video.VideoId) ?? info; var live = new YoutubeLiveInfo() { Title = info.Title, Channel = info.ChannelId, BeginTime = info.LiveDetails?.ActualStartTime ?? default(DateTime), EndTime = info.LiveDetails?.ActualEndTime ?? DateTime.Now, VideoId = video.VideoId }; _youtubeLiveCollection.ReplaceOne(v => v.VideoId == live.VideoId, live, new UpdateOptions() { IsUpsert = true }); LogHelper.Info("保存完毕"); }; }; CacheManager.Manager.VtuberUploadVideoEvent += (vtuber, video) => { LogHelper.Info($"Vtuber {vtuber.OriginalName} 上传了视频 {video.Title}"); foreach (var(key, value) in Config.DefaultConfig.Subscribes) { var config = value.FirstOrDefault(v => string.Equals(v.VtuberName, vtuber.OriginalName, StringComparison.CurrentCultureIgnoreCase)); if (config?.UploadVideo ?? false) { _service.SendToGroup(key, $"{vtuber.OriginalName} 在 {video.PublishTime.ToUniversalTime().AddHours(8):yyyy-MM-dd HH:mm:ss} 上传了视频 {video.Title}\r\n" + $"链接: {video.VideoLink}"); } } }; CacheManager.Manager.VtuberPublishTweetEvent += (vtuber, tweet) => { LogHelper.Info($"Vtuber {vtuber.OriginalName} 发布了新的推特 {tweet.Content.Substring(0, 5)}...."); foreach (var(key, value) in Config.DefaultConfig.Subscribes) { var config = value.FirstOrDefault(v => string.Equals(v.VtuberName, vtuber.OriginalName, StringComparison.CurrentCultureIgnoreCase)); if (config?.PublishTweet ?? false) { _service.SendToGroup(key, $"{vtuber.OriginalName} 在 {tweet.CreateTime.ToUniversalTime().AddHours(8):yyyy-MM-dd HH:mm:ss} 发布了:\r\n" + $"{(tweet.Content.Length > 255 ? tweet.Content.Substring(0, 255) : tweet.Content)}"); } } try { _tweetCollection.InsertOne(tweet); } catch (Exception ex) { LogHelper.Error("Insert object error", true, ex); } }; CacheManager.Manager.VtuberReplyTweetEvent += (vtuber, tweet) => { LogHelper.Info($"Vtuber {vtuber.OriginalName} 回复了 {tweet.ReplyScreenname} 的推特 {tweet.Content.Substring(0, 5)}...."); foreach (var(key, value) in Config.DefaultConfig.Subscribes) { var config = value.FirstOrDefault(v => string.Equals(v.VtuberName, vtuber.OriginalName, StringComparison.CurrentCultureIgnoreCase)); if (config?.ReplyTweet ?? false) { _service.SendToGroup(key, $"{vtuber.OriginalName} 在 {tweet.CreateTime.ToUniversalTime().AddHours(8):yyyy-MM-dd HH:mm:ss} 回复了 {tweet.RetweetedTweet}:\r\n" + $"{(tweet.Content.Length > 255 ? tweet.Content.Substring(0, 255) : tweet.Content)}"); } } try { _tweetCollection.InsertOne(tweet); } catch (Exception ex) { LogHelper.Error("Insert object error", true, ex); } }; CacheManager.Manager.VtuberRetweetedEvent += (vtuber, tweet) => { LogHelper.Info($"Vtuber {vtuber.OriginalName} 转发了 {tweet.RetweetedTweet.User.Name} 的推特: {tweet.Content.Substring(0, 5)}...."); foreach (var(key, value) in Config.DefaultConfig.Subscribes) { var config = value.FirstOrDefault(v => string.Equals(v.VtuberName, vtuber.OriginalName, StringComparison.CurrentCultureIgnoreCase)); if (config?.Retweeted ?? false) { _service.SendToGroup(key, $"{vtuber.OriginalName} 在 {tweet.CreateTime.ToUniversalTime().AddHours(8):yyyy-MM-dd HH:mm:ss} 转发了 {tweet.RetweetedTweet.User.Name} 的推:\r\n" + $"{(tweet.Content.Length > 255 ? tweet.Content.Substring(0, 255) : tweet.Content)}"); } } try { _tweetCollection.InsertOne(tweet); } catch (Exception ex) { LogHelper.Error("Insert object error", true, ex); } }; CacheManager.Manager.VtuberBeginLiveBilibiliEvent += (vtuber, bUser) => { var beginTime = DateTime.Now; LogHelper.Info($"Vtuber {vtuber.OriginalName} 在B站开始了直播 {bUser.LiveUrl}"); foreach (var(key, value) in Config.DefaultConfig.Subscribes) { var config = value.FirstOrDefault(v => string.Equals(v.VtuberName, vtuber.OriginalName, StringComparison.CurrentCultureIgnoreCase)); if (config?.BilibiliBeginLive ?? false) { _service.SendToGroup(key, $"{vtuber.OriginalName} 在B站开始了直播 {bUser.LiveTitle}\r\n" + $"链接: {bUser.LiveUrl}"); } } var liveId = StringTools.RandomString; var liveInfo = new BiliBiliLiveInfo() { LiveId = liveId, Title = bUser.LiveTitle, BeginTime = beginTime, EndTime = beginTime, MaxPopularity = 0 }; var live = _biliLiveCollection.FindAsync(v => v.MaxPopularity == 0 && v.Title == bUser.LiveTitle) .GetAwaiter().GetResult().FirstOrDefault(); if (live != null) { liveId = live.LiveId; } else { _biliLiveCollection.InsertOne(liveInfo); } var recorder = new DanmakuRecorder(bUser.LiveRoomId, liveId, vtuber); recorder.StartRecord(); recorder.LiveStoppedEvent += info => { LogHelper.Info($"{vtuber.OriginalName} 已停止在B站的直播."); liveInfo = new BiliBiliLiveInfo() { LiveId = liveId, Title = bUser.LiveTitle, BeginTime = beginTime, EndTime = DateTime.Now, MaxPopularity = recorder.Client.MaxPopularity }; _biliLiveCollection.ReplaceOne(v => v.LiveId == liveInfo.LiveId, liveInfo, new UpdateOptions() { IsUpsert = true }); }; }; }