2022-08-25 18:44:35 +08:00
|
|
|
using System;
|
2022-08-26 16:15:45 +08:00
|
|
|
using System.Diagnostics;
|
2022-08-25 18:44:35 +08:00
|
|
|
using System.IO;
|
|
|
|
using System.Net.Http;
|
|
|
|
using System.Threading.Tasks;
|
2022-08-26 16:15:45 +08:00
|
|
|
using System.Windows;
|
|
|
|
using System.Windows.Threading;
|
2022-08-25 18:44:35 +08:00
|
|
|
using BililiveRecorder.Core;
|
2022-08-26 16:15:45 +08:00
|
|
|
using Hardcodet.Wpf.TaskbarNotification;
|
2022-08-25 18:44:35 +08:00
|
|
|
using Microsoft.Toolkit.Uwp.Notifications;
|
2022-08-26 16:15:45 +08:00
|
|
|
using Serilog;
|
2022-08-25 18:44:35 +08:00
|
|
|
|
|
|
|
#nullable enable
|
|
|
|
namespace BililiveRecorder.WPF
|
|
|
|
{
|
|
|
|
internal static class StreamStartedNotification
|
|
|
|
{
|
2022-08-26 16:15:45 +08:00
|
|
|
private static readonly ILogger logger = Log.ForContext(typeof(StreamStartedNotification));
|
|
|
|
|
|
|
|
private static INotificationApi notificationApi;
|
|
|
|
|
|
|
|
static StreamStartedNotification()
|
2022-08-25 18:44:35 +08:00
|
|
|
{
|
|
|
|
try
|
|
|
|
{
|
2022-08-26 16:15:45 +08:00
|
|
|
notificationApi = new NotificationCenterApi();
|
|
|
|
}
|
|
|
|
catch (Exception ex)
|
|
|
|
{
|
|
|
|
logger.Debug(ex, "构造 NotificationCenterApi 时发生错误");
|
|
|
|
notificationApi = new BalloonTipApi();
|
|
|
|
}
|
|
|
|
|
|
|
|
logger.Debug("使用通知API: {NotificationApi}", notificationApi.GetType().Name);
|
|
|
|
}
|
|
|
|
|
|
|
|
internal static Task ShowAsync(IRoom room) => notificationApi.ShowAsync(room);
|
|
|
|
|
|
|
|
internal static void Cleanup() => notificationApi.Cleanup();
|
|
|
|
|
|
|
|
|
|
|
|
internal interface INotificationApi
|
|
|
|
{
|
|
|
|
Task ShowAsync(IRoom room);
|
|
|
|
void Cleanup();
|
|
|
|
}
|
2022-08-25 18:44:35 +08:00
|
|
|
|
2022-08-26 16:15:45 +08:00
|
|
|
internal class BalloonTipApi : INotificationApi
|
|
|
|
{
|
|
|
|
public void Cleanup() { }
|
2022-08-25 18:44:35 +08:00
|
|
|
|
2022-08-26 16:15:45 +08:00
|
|
|
public Task ShowAsync(IRoom room)
|
|
|
|
{
|
|
|
|
_ = Application.Current.Dispatcher.BeginInvoke(DispatcherPriority.Normal, new Action(() =>
|
2022-08-25 18:44:35 +08:00
|
|
|
{
|
2022-08-26 16:15:45 +08:00
|
|
|
if (Application.Current.MainWindow is NewMainWindow nmw)
|
|
|
|
{
|
|
|
|
nmw.ShowBalloonTipCallback?.Invoke(room.Name + " 开播了", $"{room.Title}\n{room.AreaNameParent} · {room.AreaNameChild}", BalloonIcon.None);
|
|
|
|
}
|
|
|
|
}));
|
|
|
|
|
|
|
|
return Task.CompletedTask;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
internal class NotificationCenterApi : INotificationApi
|
|
|
|
{
|
|
|
|
private readonly string tempPath;
|
|
|
|
|
|
|
|
public NotificationCenterApi()
|
|
|
|
{
|
|
|
|
_ = ToastNotificationManagerCompat.History;
|
2022-08-25 18:44:35 +08:00
|
|
|
|
2022-08-26 16:15:45 +08:00
|
|
|
this.tempPath = Path.Combine(Path.GetTempPath(), "brec-notifi", Process.GetCurrentProcess().Id.ToString());
|
2022-08-25 18:44:35 +08:00
|
|
|
|
2022-08-26 16:15:45 +08:00
|
|
|
try
|
|
|
|
{
|
|
|
|
Directory.CreateDirectory(this.tempPath);
|
|
|
|
}
|
|
|
|
catch (Exception)
|
|
|
|
{
|
|
|
|
try
|
|
|
|
{
|
|
|
|
Directory.CreateDirectory(this.tempPath);
|
|
|
|
}
|
|
|
|
catch (Exception)
|
|
|
|
{ }
|
|
|
|
}
|
|
|
|
}
|
2022-08-25 18:44:35 +08:00
|
|
|
|
2022-08-26 16:15:45 +08:00
|
|
|
public void Cleanup()
|
|
|
|
{
|
|
|
|
ToastNotificationManagerCompat.Uninstall();
|
2022-08-25 18:44:35 +08:00
|
|
|
|
2022-08-26 16:15:45 +08:00
|
|
|
try
|
|
|
|
{
|
|
|
|
Directory.Delete(path: this.tempPath, recursive: true);
|
|
|
|
}
|
|
|
|
catch (Exception)
|
2022-08-25 18:44:35 +08:00
|
|
|
{
|
2022-08-26 16:15:45 +08:00
|
|
|
try
|
|
|
|
{
|
|
|
|
Directory.Delete(path: this.tempPath, recursive: true);
|
|
|
|
}
|
|
|
|
catch (Exception)
|
|
|
|
{ }
|
2022-08-25 18:44:35 +08:00
|
|
|
}
|
2022-08-26 16:15:45 +08:00
|
|
|
}
|
2022-08-25 18:44:35 +08:00
|
|
|
|
2022-08-26 16:15:45 +08:00
|
|
|
public async Task ShowAsync(IRoom room)
|
|
|
|
{
|
|
|
|
Uri? cover = null, face = null;
|
|
|
|
DateTime? time = null;
|
|
|
|
try
|
2022-08-25 18:44:35 +08:00
|
|
|
{
|
2022-08-26 16:15:45 +08:00
|
|
|
var json = room.RawBilibiliApiJsonData;
|
|
|
|
|
|
|
|
var live_start_time = json?["room_info"]?["live_start_time"]?.ToObject<long?>();
|
|
|
|
if (live_start_time.HasValue && live_start_time > 0)
|
|
|
|
{
|
|
|
|
time = DateTimeOffset.FromUnixTimeSeconds(live_start_time.Value).LocalDateTime;
|
|
|
|
}
|
|
|
|
|
|
|
|
var coverUrl = json?["room_info"]?["cover"]?.ToObject<string>();
|
|
|
|
var faceUrl = json?["anchor_info"]?["base_info"]?["face"]?.ToObject<string>();
|
|
|
|
|
|
|
|
var coverFile = Path.Combine(this.tempPath, Path.GetFileName(coverUrl));
|
|
|
|
var faceFile = Path.Combine(this.tempPath, Path.GetFileName(faceUrl));
|
|
|
|
|
|
|
|
using var client = new HttpClient();
|
|
|
|
client.Timeout = TimeSpan.FromSeconds(5);
|
|
|
|
client.DefaultRequestHeaders.Accept.Clear();
|
|
|
|
client.DefaultRequestHeaders.UserAgent.Clear();
|
|
|
|
|
|
|
|
if (!string.IsNullOrEmpty(faceUrl))
|
|
|
|
{
|
|
|
|
using var faceFs = new FileStream(faceFile, FileMode.Create, FileAccess.Write, FileShare.None);
|
|
|
|
await (await client.GetStreamAsync(faceUrl).ConfigureAwait(false)).CopyToAsync(faceFs).ConfigureAwait(false);
|
|
|
|
face = new Uri(faceFile);
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!string.IsNullOrWhiteSpace(coverUrl))
|
|
|
|
{
|
|
|
|
using var coverFs = new FileStream(coverFile, FileMode.Create, FileAccess.Write, FileShare.None);
|
|
|
|
await (await client.GetStreamAsync(coverUrl).ConfigureAwait(false)).CopyToAsync(coverFs).ConfigureAwait(false);
|
|
|
|
cover = new Uri(coverFile);
|
|
|
|
}
|
2022-08-25 18:44:35 +08:00
|
|
|
}
|
2022-08-26 16:15:45 +08:00
|
|
|
catch (Exception)
|
|
|
|
{ }
|
|
|
|
|
|
|
|
var roomUrl = new Uri("https://live.bilibili.com/" + room.RoomConfig.RoomId);
|
|
|
|
var builder = new ToastContentBuilder()
|
|
|
|
.AddHeader("BililiveRecorder-StreamStarted", "B站录播姬开播通知", "")
|
|
|
|
.AddText(room.Name + " 开播了")
|
|
|
|
.AddText(room.Title)
|
|
|
|
.AddText($"{room.AreaNameParent} · {room.AreaNameChild}")
|
|
|
|
.SetProtocolActivation(roomUrl)
|
|
|
|
.SetToastDuration(ToastDuration.Long)
|
|
|
|
.AddButton(new ToastButton().SetContent("打开直播间").SetProtocolActivation(roomUrl))
|
|
|
|
;
|
|
|
|
|
|
|
|
if (time.HasValue)
|
|
|
|
builder.AddCustomTimeStamp(time.Value);
|
|
|
|
|
|
|
|
if (face is not null)
|
|
|
|
builder.AddAppLogoOverride(face, ToastGenericAppLogoCrop.Circle);
|
|
|
|
|
|
|
|
if (cover is not null)
|
|
|
|
builder.AddInlineImage(cover);
|
|
|
|
|
|
|
|
builder.Show();
|
2022-08-25 18:44:35 +08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|