mirror of
https://github.com/BililiveRecorder/BililiveRecorder.git
synced 2024-11-16 11:42:22 +08:00
新配置文件
This commit is contained in:
parent
155bd8a2ef
commit
27b3728035
|
@ -11,7 +11,8 @@
|
|||
|
||||
<ItemGroup>
|
||||
<PackageReference Include="Autofac" Version="4.8.1" />
|
||||
<PackageReference Include="NLog" Version="4.5.0-rc07" />
|
||||
<PackageReference Include="Newtonsoft.Json" Version="11.0.2" />
|
||||
<PackageReference Include="NLog" Version="4.5.10" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
|
|
81
BililiveRecorder.Core/Config/ConfigParser.cs
Normal file
81
BililiveRecorder.Core/Config/ConfigParser.cs
Normal file
|
@ -0,0 +1,81 @@
|
|||
using Newtonsoft.Json;
|
||||
using System;
|
||||
using System.IO;
|
||||
|
||||
namespace BililiveRecorder.Core.Config
|
||||
{
|
||||
public static class ConfigParser
|
||||
{
|
||||
public static bool Load(string directory, ConfigV1 config = null)
|
||||
{
|
||||
var filepath = Path.Combine(directory, "config.json");
|
||||
if (File.Exists(filepath))
|
||||
{
|
||||
try
|
||||
{
|
||||
var cw = JsonConvert.DeserializeObject<ConfigWrapper>(File.ReadAllText(filepath));
|
||||
switch (cw.Version)
|
||||
{
|
||||
case 1:
|
||||
{
|
||||
var v1 = JsonConvert.DeserializeObject<ConfigV1>(cw.Data);
|
||||
v1.CopyPropertiesTo(config);
|
||||
return true;
|
||||
// (v1.ToV2()).CopyPropertiesTo(config);
|
||||
}
|
||||
/**
|
||||
* case 2:
|
||||
* {
|
||||
* var v2 = JsonConvert.DeserializeObject<ConfigV2>(cw.Data);
|
||||
* v2.CopyPropertiesTo(config);
|
||||
* return true;
|
||||
* }
|
||||
* */
|
||||
default:
|
||||
// version not supported
|
||||
// TODO: return status enum
|
||||
return false;
|
||||
}
|
||||
}
|
||||
catch (Exception)
|
||||
{
|
||||
// TODO: Log Exception
|
||||
return false;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
new ConfigV1().CopyPropertiesTo(config);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
public static bool Save(string directory, ConfigV1 config = null)
|
||||
{
|
||||
if (config == null) { config = new ConfigV1(); }
|
||||
if (!Directory.Exists(directory))
|
||||
{
|
||||
// User should create the directory
|
||||
// TODO: return enum
|
||||
return false;
|
||||
}
|
||||
var filepath = Path.Combine(directory, "config.json");
|
||||
try
|
||||
{
|
||||
var data = JsonConvert.SerializeObject(config);
|
||||
var cw = JsonConvert.SerializeObject(new ConfigWrapper()
|
||||
{
|
||||
Version = 1,
|
||||
Data = data
|
||||
});
|
||||
File.WriteAllText(filepath, cw);
|
||||
return true;
|
||||
}
|
||||
catch (Exception)
|
||||
{
|
||||
return false;
|
||||
// TODO: Log Exception
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
61
BililiveRecorder.Core/Config/ConfigV1.cs
Normal file
61
BililiveRecorder.Core/Config/ConfigV1.cs
Normal file
|
@ -0,0 +1,61 @@
|
|||
using BililiveRecorder.FlvProcessor;
|
||||
using Newtonsoft.Json;
|
||||
using NLog;
|
||||
using System.Collections.Generic;
|
||||
using System.ComponentModel;
|
||||
using System.Runtime.CompilerServices;
|
||||
|
||||
namespace BililiveRecorder.Core.Config
|
||||
{
|
||||
[JsonObject(memberSerialization: MemberSerialization.OptIn)]
|
||||
public class ConfigV1 : INotifyPropertyChanged
|
||||
{
|
||||
private static readonly Logger logger = LogManager.GetCurrentClassLogger();
|
||||
|
||||
/// <summary>
|
||||
/// 当前工作目录
|
||||
/// </summary>
|
||||
[JsonIgnore]
|
||||
[Utils.DoNotCopyProperty]
|
||||
public string WorkDirectory { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 房间号列表
|
||||
/// </summary>
|
||||
[JsonProperty("roomlist")]
|
||||
public List<RoomV1> RoomList { get; set; } = new List<RoomV1>();
|
||||
|
||||
/// <summary>
|
||||
/// 启用的功能
|
||||
/// </summary>
|
||||
[JsonProperty("feature")]
|
||||
public EnabledFeature EnabledFeature { get => _enabledFeature; set => SetField(ref _enabledFeature, value); }
|
||||
|
||||
/// <summary>
|
||||
/// 剪辑-过去的时长(秒)
|
||||
/// </summary>
|
||||
[JsonProperty("clip_length_future")]
|
||||
public uint ClipLengthFuture { get => _clipLengthFuture; set => SetField(ref _clipLengthFuture, value); }
|
||||
|
||||
/// <summary>
|
||||
/// 剪辑-将来的时长(秒)
|
||||
/// </summary>
|
||||
[JsonProperty("clip_length_past")]
|
||||
public uint ClipLengthPast { get => _clipLengthPast; set => SetField(ref _clipLengthPast, value); }
|
||||
|
||||
#region INotifyPropertyChanged
|
||||
public event PropertyChangedEventHandler PropertyChanged;
|
||||
protected virtual void OnPropertyChanged(string propertyName) => PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
|
||||
protected bool SetField<T>(ref T field, T value, [CallerMemberName] string propertyName = "")
|
||||
{
|
||||
if (EqualityComparer<T>.Default.Equals(field, value)) { return false; }
|
||||
logger.Debug("设置 [{0}] 的值已从 [{1}] 修改到 [{2}]", propertyName, field, value);
|
||||
field = value; OnPropertyChanged(propertyName); return true;
|
||||
}
|
||||
#endregion
|
||||
|
||||
private uint _clipLengthPast = 20;
|
||||
private uint _clipLengthFuture = 10;
|
||||
private EnabledFeature _enabledFeature = EnabledFeature.Both;
|
||||
}
|
||||
}
|
20
BililiveRecorder.Core/Config/ConfigWrapper.cs
Normal file
20
BililiveRecorder.Core/Config/ConfigWrapper.cs
Normal file
|
@ -0,0 +1,20 @@
|
|||
using Newtonsoft.Json;
|
||||
|
||||
namespace BililiveRecorder.Core.Config
|
||||
{
|
||||
[JsonObject(MemberSerialization = MemberSerialization.OptIn)]
|
||||
internal class ConfigWrapper
|
||||
{
|
||||
/// <summary>
|
||||
/// Config Version
|
||||
/// </summary>
|
||||
[JsonProperty("version")]
|
||||
public int Version { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Config Data String
|
||||
/// </summary>
|
||||
[JsonProperty("data")]
|
||||
public string Data { get; set; }
|
||||
}
|
||||
}
|
14
BililiveRecorder.Core/Config/RoomV1.cs
Normal file
14
BililiveRecorder.Core/Config/RoomV1.cs
Normal file
|
@ -0,0 +1,14 @@
|
|||
using Newtonsoft.Json;
|
||||
|
||||
namespace BililiveRecorder.Core.Config
|
||||
{
|
||||
[JsonObject(MemberSerialization = MemberSerialization.OptIn)]
|
||||
public class RoomV1
|
||||
{
|
||||
[JsonProperty("id")]
|
||||
public int Roomid { get; set; }
|
||||
|
||||
[JsonProperty("enabled")]
|
||||
public bool Enabled { get; set; }
|
||||
}
|
||||
}
|
|
@ -1,4 +1,5 @@
|
|||
using Autofac;
|
||||
using BililiveRecorder.Core.Config;
|
||||
using System.Net.Sockets;
|
||||
|
||||
namespace BililiveRecorder.Core
|
||||
|
@ -12,7 +13,7 @@ namespace BililiveRecorder.Core
|
|||
|
||||
protected override void Load(ContainerBuilder builder)
|
||||
{
|
||||
builder.RegisterType<Settings>().As<ISettings>().InstancePerMatchingLifetimeScope("recorder_root");
|
||||
builder.RegisterType<ConfigV1>().AsSelf().InstancePerMatchingLifetimeScope("recorder_root");
|
||||
builder.RegisterType<TcpClient>().AsSelf().ExternallyOwned();
|
||||
builder.RegisterType<DanmakuReceiver>().As<IDanmakuReceiver>();
|
||||
builder.RegisterType<StreamMonitor>().As<IStreamMonitor>();
|
||||
|
|
|
@ -1,4 +1,5 @@
|
|||
using System;
|
||||
using BililiveRecorder.Core.Config;
|
||||
using System;
|
||||
using System.IO;
|
||||
|
||||
namespace BililiveRecorder.Core
|
||||
|
@ -7,8 +8,8 @@ namespace BililiveRecorder.Core
|
|||
{
|
||||
private static readonly Random random = new Random();
|
||||
|
||||
private ISettings Settings { get; }
|
||||
public string SavePath { get => Settings.SavePath; }
|
||||
private ConfigV1 Config { get; }
|
||||
public string SavePath { get => Config.WorkDirectory; }
|
||||
|
||||
public string StreamFilePrefix { get; set; } = "录制";
|
||||
public string ClipFilePrefix { get; set; } = "剪辑";
|
||||
|
@ -31,10 +32,10 @@ namespace BililiveRecorder.Core
|
|||
return name;
|
||||
}
|
||||
|
||||
public RecordInfo(string name, ISettings settings)
|
||||
public RecordInfo(string name, ConfigV1 config)
|
||||
{
|
||||
StreamName = name;
|
||||
Settings = settings;
|
||||
Config = config;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -1,4 +1,5 @@
|
|||
using BililiveRecorder.FlvProcessor;
|
||||
using BililiveRecorder.Core.Config;
|
||||
using BililiveRecorder.FlvProcessor;
|
||||
using NLog;
|
||||
using System;
|
||||
using System.Collections.ObjectModel;
|
||||
|
@ -71,7 +72,7 @@ namespace BililiveRecorder.Core
|
|||
private ObservableCollection<IFlvClipProcessor> Clips { get; set; } = new ObservableCollection<IFlvClipProcessor>();
|
||||
|
||||
public IStreamMonitor StreamMonitor { get; }
|
||||
private ISettings _settings { get; }
|
||||
private ConfigV1 _config { get; }
|
||||
|
||||
private Task StartupTask = null;
|
||||
public Task StreamDownloadTask = null;
|
||||
|
@ -87,7 +88,7 @@ namespace BililiveRecorder.Core
|
|||
public DateTime LastUpdateDateTime { get; private set; } = DateTime.Now;
|
||||
public long LastUpdateSize { get; private set; } = 0;
|
||||
|
||||
public RecordedRoom(ISettings settings,
|
||||
public RecordedRoom(ConfigV1 config,
|
||||
Func<string, IRecordInfo> newIRecordInfo,
|
||||
Func<int, IStreamMonitor> newIStreamMonitor,
|
||||
Func<IFlvStreamProcessor> newIFlvStreamProcessor,
|
||||
|
@ -95,7 +96,7 @@ namespace BililiveRecorder.Core
|
|||
{
|
||||
this.newIFlvStreamProcessor = newIFlvStreamProcessor;
|
||||
|
||||
_settings = settings;
|
||||
_config = config;
|
||||
|
||||
Roomid = roomid;
|
||||
|
||||
|
@ -193,9 +194,9 @@ namespace BililiveRecorder.Core
|
|||
triggerType = TriggerType.HttpApi;
|
||||
}
|
||||
|
||||
Processor = newIFlvStreamProcessor().Initialize(RecordInfo.GetStreamFilePath, RecordInfo.GetClipFilePath, _settings.Feature);
|
||||
Processor.ClipLengthFuture = _settings.Clip_Future;
|
||||
Processor.ClipLengthPast = _settings.Clip_Past;
|
||||
Processor = newIFlvStreamProcessor().Initialize(RecordInfo.GetStreamFilePath, RecordInfo.GetClipFilePath, _config.EnabledFeature);
|
||||
Processor.ClipLengthFuture = _config.ClipLengthFuture;
|
||||
Processor.ClipLengthPast = _config.ClipLengthPast;
|
||||
|
||||
stream = response.GetResponseStream();
|
||||
|
||||
|
|
|
@ -1,4 +1,5 @@
|
|||
using NLog;
|
||||
using BililiveRecorder.Core.Config;
|
||||
using NLog;
|
||||
using System;
|
||||
using System.Collections.ObjectModel;
|
||||
using System.Linq;
|
||||
|
@ -12,22 +13,88 @@ namespace BililiveRecorder.Core
|
|||
private static readonly Logger logger = LogManager.GetCurrentClassLogger();
|
||||
|
||||
public ObservableCollection<IRecordedRoom> Rooms { get; } = new ObservableCollection<IRecordedRoom>();
|
||||
public ISettings Settings { get; }
|
||||
public ConfigV1 Config { get; }
|
||||
|
||||
private readonly Func<int, IRecordedRoom> newIRecordedRoom;
|
||||
private CancellationTokenSource tokenSource;
|
||||
|
||||
public Recorder(ISettings settings, Func<int, IRecordedRoom> iRecordedRoom)
|
||||
private bool _valid = false;
|
||||
|
||||
public Recorder(ConfigV1 config, Func<int, IRecordedRoom> iRecordedRoom)
|
||||
{
|
||||
Settings = settings;
|
||||
Config = config;
|
||||
newIRecordedRoom = iRecordedRoom;
|
||||
|
||||
tokenSource = new CancellationTokenSource();
|
||||
Repeat.Interval(TimeSpan.FromSeconds(6), DownloadWatchdog, tokenSource.Token);
|
||||
}
|
||||
|
||||
public bool Initialize(string workdir)
|
||||
{
|
||||
if (ConfigParser.Load(directory: workdir, config: Config))
|
||||
{
|
||||
_valid = true;
|
||||
Config.WorkDirectory = workdir;
|
||||
if ((Config.RoomList?.Count ?? 0) > 0)
|
||||
{
|
||||
Config.RoomList.ForEach((r) => AddRoom(r.Roomid, r.Enabled));
|
||||
}
|
||||
ConfigParser.Save(Config.WorkDirectory, Config);
|
||||
return true;
|
||||
}
|
||||
else
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 添加直播间到录播姬
|
||||
/// </summary>
|
||||
/// <param name="roomid">房间号(支持短号)</param>
|
||||
/// <exception cref="ArgumentOutOfRangeException"/>
|
||||
public void AddRoom(int roomid, bool enabled = false)
|
||||
{
|
||||
if (!_valid) { throw new InvalidOperationException("Not Initialized"); }
|
||||
if (roomid <= 0)
|
||||
{
|
||||
throw new ArgumentOutOfRangeException(nameof(roomid), "房间号需要大于0");
|
||||
}
|
||||
// var rr = new RecordedRoom(Settings, roomid);
|
||||
var rr = newIRecordedRoom(roomid);
|
||||
if (enabled)
|
||||
{
|
||||
Task.Run(() => rr.Start());
|
||||
}
|
||||
|
||||
Rooms.Add(rr);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 从录播姬移除直播间
|
||||
/// </summary>
|
||||
/// <param name="rr">直播间</param>
|
||||
public void RemoveRoom(IRecordedRoom rr)
|
||||
{
|
||||
if (!_valid) { throw new InvalidOperationException("Not Initialized"); }
|
||||
rr.Shutdown();
|
||||
Rooms.Remove(rr);
|
||||
}
|
||||
|
||||
public void Shutdown()
|
||||
{
|
||||
if (!_valid) { throw new InvalidOperationException("Not Initialized"); }
|
||||
tokenSource.Cancel();
|
||||
|
||||
Rooms.ToList().ForEach(rr =>
|
||||
{
|
||||
rr.Shutdown();
|
||||
});
|
||||
}
|
||||
|
||||
private void DownloadWatchdog()
|
||||
{
|
||||
if (!_valid) { return; }
|
||||
try
|
||||
{
|
||||
Rooms.ToList().ForEach(room =>
|
||||
|
@ -49,45 +116,5 @@ namespace BililiveRecorder.Core
|
|||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 添加直播间到录播姬
|
||||
/// </summary>
|
||||
/// <param name="roomid">房间号(支持短号)</param>
|
||||
/// <exception cref="ArgumentOutOfRangeException"/>
|
||||
public void AddRoom(int roomid, bool enabled = false)
|
||||
{
|
||||
if (roomid <= 0)
|
||||
{
|
||||
throw new ArgumentOutOfRangeException(nameof(roomid), "房间号需要大于0");
|
||||
}
|
||||
// var rr = new RecordedRoom(Settings, roomid);
|
||||
var rr = newIRecordedRoom(roomid);
|
||||
if (enabled)
|
||||
{
|
||||
Task.Run(() => rr.Start());
|
||||
}
|
||||
|
||||
Rooms.Add(rr);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 从录播姬移除直播间
|
||||
/// </summary>
|
||||
/// <param name="rr">直播间</param>
|
||||
public void RemoveRoom(IRecordedRoom rr)
|
||||
{
|
||||
rr.Shutdown();
|
||||
Rooms.Remove(rr);
|
||||
}
|
||||
|
||||
public void Shutdown()
|
||||
{
|
||||
tokenSource.Cancel();
|
||||
|
||||
Rooms.ToList().ForEach(rr =>
|
||||
{
|
||||
rr.Shutdown();
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -39,18 +39,28 @@ namespace BililiveRecorder.Core
|
|||
}
|
||||
}
|
||||
|
||||
public static void ApplyTo(this ISettings val1, ISettings val2)
|
||||
public static bool CopyPropertiesTo<T>(this T val1, T val2) where T : class
|
||||
{
|
||||
if (val1 == null || val2 == null || val1 == val2) { return false; }
|
||||
foreach (var p in val1.GetType().GetProperties())
|
||||
{
|
||||
if (Attribute.IsDefined(p, typeof(DoNotCopyProperty)))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
var val = p.GetValue(val1);
|
||||
if (!val.Equals(p.GetValue(val2)))
|
||||
{
|
||||
p.SetValue(val2, val);
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
[AttributeUsage(AttributeTargets.Property, AllowMultiple = false, Inherited = true)]
|
||||
public class DoNotCopyProperty : Attribute { }
|
||||
|
||||
internal static void Log(this Logger logger, int id, LogLevel level, string message, Exception exception = null)
|
||||
{
|
||||
var log = new LogEventInfo()
|
||||
|
|
|
@ -11,7 +11,7 @@
|
|||
|
||||
<ItemGroup>
|
||||
<PackageReference Include="Autofac" Version="4.8.1" />
|
||||
<PackageReference Include="NLog" Version="4.5.0-rc07" />
|
||||
<PackageReference Include="NLog" Version="4.5.10" />
|
||||
</ItemGroup>
|
||||
|
||||
</Project>
|
||||
|
|
|
@ -84,8 +84,11 @@
|
|||
<Reference Include="Microsoft.WindowsAPICodePack.Shell, Version=1.1.0.0, Culture=neutral, processorArchitecture=MSIL">
|
||||
<HintPath>..\packages\WindowsAPICodePack-Shell.1.1.1\lib\Microsoft.WindowsAPICodePack.Shell.dll</HintPath>
|
||||
</Reference>
|
||||
<Reference Include="Newtonsoft.Json, Version=11.0.0.0, Culture=neutral, PublicKeyToken=30ad4fe6b2a6aeed, processorArchitecture=MSIL">
|
||||
<HintPath>..\packages\Newtonsoft.Json.11.0.2\lib\net45\Newtonsoft.Json.dll</HintPath>
|
||||
</Reference>
|
||||
<Reference Include="NLog, Version=4.0.0.0, Culture=neutral, PublicKeyToken=5120e14c03d0593c, processorArchitecture=MSIL">
|
||||
<HintPath>..\packages\NLog.4.5.0-rc07\lib\net45\NLog.dll</HintPath>
|
||||
<HintPath>..\packages\NLog.4.5.10\lib\net45\NLog.dll</HintPath>
|
||||
</Reference>
|
||||
<Reference Include="System" />
|
||||
<Reference Include="System.Configuration" />
|
||||
|
@ -126,6 +129,9 @@
|
|||
<Compile Include="UpdateBarUserControl.xaml.cs">
|
||||
<DependentUpon>UpdateBarUserControl.xaml</DependentUpon>
|
||||
</Compile>
|
||||
<Compile Include="WorkDirectoryWindow.xaml.cs">
|
||||
<DependentUpon>WorkDirectoryWindow.xaml</DependentUpon>
|
||||
</Compile>
|
||||
<Page Include="ClickSelectTextBox.xaml">
|
||||
<SubType>Designer</SubType>
|
||||
<Generator>MSBuild:Compile</Generator>
|
||||
|
@ -150,6 +156,10 @@
|
|||
<SubType>Designer</SubType>
|
||||
<Generator>MSBuild:Compile</Generator>
|
||||
</Page>
|
||||
<Page Include="WorkDirectoryWindow.xaml">
|
||||
<SubType>Designer</SubType>
|
||||
<Generator>MSBuild:Compile</Generator>
|
||||
</Page>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<Compile Include="Properties\AssemblyInfo.cs">
|
||||
|
@ -172,7 +182,7 @@
|
|||
<None Include="BuildInfo.txt" />
|
||||
<Resource Include="ico.ico" />
|
||||
<Content Include="NLog.config">
|
||||
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
|
||||
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
||||
</Content>
|
||||
<None Include="Nlog.Release.config" />
|
||||
<None Include="NLog.Debug.config">
|
||||
|
|
|
@ -42,32 +42,51 @@ namespace BililiveRecorder.WPF
|
|||
|
||||
public MainWindow()
|
||||
{
|
||||
Title += " 版本号: " + BuildInfo.Version + " " + BuildInfo.HeadShaShort;
|
||||
_AddLog = (message) => Log.Dispatcher.Invoke(() => { Logs.Add(message); while (Logs.Count > MAX_LOG_ROW) { Logs.RemoveAt(0); } });
|
||||
|
||||
var builder = new ContainerBuilder();
|
||||
builder.RegisterModule<FlvProcessorModule>();
|
||||
builder.RegisterModule<CoreModule>();
|
||||
Container = builder.Build();
|
||||
RootScope = Container.BeginLifetimeScope("recorder_root");
|
||||
|
||||
_AddLog = (message) => Log.Dispatcher.Invoke(() => { Logs.Add(message); while (Logs.Count > MAX_LOG_ROW) { Logs.RemoveAt(0); } });
|
||||
Recorder = RootScope.Resolve<Recorder>();
|
||||
|
||||
InitializeComponent();
|
||||
|
||||
Recorder = RootScope.Resolve<Recorder>();
|
||||
DataContext = this;
|
||||
|
||||
|
||||
Title += " 版本号: " + BuildInfo.Version + " " + BuildInfo.HeadShaShort;
|
||||
}
|
||||
|
||||
|
||||
private void Window_Loaded(object sender, RoutedEventArgs e)
|
||||
{
|
||||
InitSettings();
|
||||
|
||||
if (string.IsNullOrWhiteSpace(Recorder.Settings.SavePath) || (ApplicationDeployment.IsNetworkDeployed && ApplicationDeployment.CurrentDeployment.IsFirstRun))
|
||||
//if (string.IsNullOrWhiteSpace(Recorder.Config.WorkDirectory) || (ApplicationDeployment.IsNetworkDeployed && ApplicationDeployment.CurrentDeployment.IsFirstRun))
|
||||
//{
|
||||
// ShowSettingsWindow();
|
||||
//}
|
||||
string workdir;
|
||||
var wdw = new WorkDirectoryWindow()
|
||||
{
|
||||
ShowSettingsWindow();
|
||||
Owner = this
|
||||
};
|
||||
if (wdw.ShowDialog() == true)
|
||||
{
|
||||
workdir = wdw.WorkPath;
|
||||
}
|
||||
else
|
||||
{
|
||||
Environment.Exit(-1);
|
||||
return;
|
||||
}
|
||||
|
||||
if (!Recorder.Initialize(workdir))
|
||||
{
|
||||
MessageBox.Show("初始化错误", "录播姬", MessageBoxButton.OK, MessageBoxImage.Error);
|
||||
Environment.Exit(-2);
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
Task.Run(() => CheckVersion());
|
||||
}
|
||||
|
@ -187,58 +206,6 @@ namespace BililiveRecorder.WPF
|
|||
|
||||
#endregion
|
||||
|
||||
|
||||
private void InitSettings()
|
||||
{
|
||||
var s = Recorder.Settings;
|
||||
|
||||
if (ps.UpgradeRequired)
|
||||
{
|
||||
ps.Upgrade();
|
||||
ps.UpgradeRequired = false;
|
||||
ps.Save();
|
||||
}
|
||||
|
||||
s.Clip_Future = ps.Clip_Future;
|
||||
s.Clip_Past = ps.Clip_Past;
|
||||
s.SavePath = ps.SavePath;
|
||||
s.Feature = (EnabledFeature)ps.Feature;
|
||||
s.PropertyChanged += (sender, e) =>
|
||||
{
|
||||
switch (e.PropertyName)
|
||||
{
|
||||
case nameof(s.Clip_Future):
|
||||
ps.Clip_Future = s.Clip_Future;
|
||||
break;
|
||||
case nameof(s.Clip_Past):
|
||||
ps.Clip_Past = s.Clip_Past;
|
||||
break;
|
||||
case nameof(s.SavePath):
|
||||
ps.SavePath = s.SavePath;
|
||||
break;
|
||||
case nameof(s.Feature):
|
||||
ps.Feature = (int)s.Feature;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
ps.RoomIDs.Split(';').ToList().ForEach(rs =>
|
||||
{
|
||||
var r = rs.Split(',');
|
||||
if (int.TryParse(r[0], out int roomid) && bool.TryParse(r[1], out bool enabled))
|
||||
{
|
||||
if (roomid > 0)
|
||||
{
|
||||
Recorder.AddRoom(roomid, enabled);
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
}
|
||||
|
||||
private void TextBlock_MouseRightButtonUp(object sender, MouseButtonEventArgs e)
|
||||
{
|
||||
if (sender is TextBlock textBlock)
|
||||
|
@ -395,10 +362,10 @@ namespace BililiveRecorder.WPF
|
|||
|
||||
private void ShowSettingsWindow()
|
||||
{
|
||||
var sw = new SettingsWindow(this, Recorder.Settings);
|
||||
var sw = new SettingsWindow(this, Recorder.Config);
|
||||
if (sw.ShowDialog() == true)
|
||||
{
|
||||
sw.Settings.ApplyTo(Recorder.Settings);
|
||||
sw.Config.CopyPropertiesTo(Recorder.Config);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -32,6 +32,7 @@
|
|||
<layout xsi:type="JsonLayout">
|
||||
<attribute name='time' layout='${longdate}' />
|
||||
<attribute name='level' layout='${level:upperCase=true}'/>
|
||||
<attribute name='pid' layout='${processid}'/>
|
||||
<attribute name='logger' layout='${logger}'/>
|
||||
<attribute name='roomid' layout='${event-properties:item=roomid}'/>
|
||||
<attribute name='message' layout='${message}'/>
|
||||
|
|
|
@ -1174,6 +1174,12 @@
|
|||
<xs:element name="maxArchiveFiles" minOccurs="0" maxOccurs="1" type="xs:integer" />
|
||||
<xs:element name="writeFooterOnArchivingOnly" minOccurs="0" maxOccurs="1" type="xs:boolean" />
|
||||
<xs:element name="maxLogFilenames" minOccurs="0" maxOccurs="1" type="xs:integer" />
|
||||
<xs:element name="fileNameKind" minOccurs="0" maxOccurs="1" type="NLog.Targets.FilePathKind" />
|
||||
<xs:element name="forceManaged" minOccurs="0" maxOccurs="1" type="xs:boolean" />
|
||||
<xs:element name="forceMutexConcurrentWrites" minOccurs="0" maxOccurs="1" type="xs:boolean" />
|
||||
<xs:element name="replaceFileContentsOnEachWrite" minOccurs="0" maxOccurs="1" type="xs:boolean" />
|
||||
<xs:element name="writeBom" minOccurs="0" maxOccurs="1" type="xs:boolean" />
|
||||
<xs:element name="enableFileDelete" minOccurs="0" maxOccurs="1" type="xs:boolean" />
|
||||
<xs:element name="fileName" minOccurs="0" maxOccurs="1" type="Layout" />
|
||||
<xs:element name="archiveDateFormat" minOccurs="0" maxOccurs="1" type="xs:string" />
|
||||
<xs:element name="archiveOldFileOnStartup" minOccurs="0" maxOccurs="1" type="xs:boolean" />
|
||||
|
@ -1181,23 +1187,18 @@
|
|||
<xs:element name="createDirs" minOccurs="0" maxOccurs="1" type="xs:boolean" />
|
||||
<xs:element name="deleteOldFileOnStartup" minOccurs="0" maxOccurs="1" type="xs:boolean" />
|
||||
<xs:element name="fileAttributes" minOccurs="0" maxOccurs="1" type="NLog.Targets.Win32FileAttributes" />
|
||||
<xs:element name="writeBom" minOccurs="0" maxOccurs="1" type="xs:boolean" />
|
||||
<xs:element name="enableFileDelete" minOccurs="0" maxOccurs="1" type="xs:boolean" />
|
||||
<xs:element name="replaceFileContentsOnEachWrite" minOccurs="0" maxOccurs="1" type="xs:boolean" />
|
||||
<xs:element name="forceMutexConcurrentWrites" minOccurs="0" maxOccurs="1" type="xs:boolean" />
|
||||
<xs:element name="forceManaged" minOccurs="0" maxOccurs="1" type="xs:boolean" />
|
||||
<xs:element name="fileNameKind" minOccurs="0" maxOccurs="1" type="NLog.Targets.FilePathKind" />
|
||||
<xs:element name="concurrentWrites" minOccurs="0" maxOccurs="1" type="xs:boolean" />
|
||||
<xs:element name="discardAll" minOccurs="0" maxOccurs="1" type="xs:boolean" />
|
||||
<xs:element name="concurrentWriteAttemptDelay" minOccurs="0" maxOccurs="1" type="xs:integer" />
|
||||
<xs:element name="networkWrites" minOccurs="0" maxOccurs="1" type="xs:boolean" />
|
||||
<xs:element name="openFileCacheSize" minOccurs="0" maxOccurs="1" type="xs:integer" />
|
||||
<xs:element name="openFileCacheTimeout" minOccurs="0" maxOccurs="1" type="xs:integer" />
|
||||
<xs:element name="optimizeBufferReuse" minOccurs="0" maxOccurs="1" type="xs:boolean" />
|
||||
<xs:element name="bufferSize" minOccurs="0" maxOccurs="1" type="xs:integer" />
|
||||
<xs:element name="autoFlush" minOccurs="0" maxOccurs="1" type="xs:boolean" />
|
||||
<xs:element name="concurrentWriteAttempts" minOccurs="0" maxOccurs="1" type="xs:integer" />
|
||||
<xs:element name="networkWrites" minOccurs="0" maxOccurs="1" type="xs:boolean" />
|
||||
<xs:element name="openFileCacheTimeout" minOccurs="0" maxOccurs="1" type="xs:integer" />
|
||||
<xs:element name="openFileCacheSize" minOccurs="0" maxOccurs="1" type="xs:integer" />
|
||||
<xs:element name="keepFileOpen" minOccurs="0" maxOccurs="1" type="xs:boolean" />
|
||||
<xs:element name="discardAll" minOccurs="0" maxOccurs="1" type="xs:boolean" />
|
||||
<xs:element name="concurrentWrites" minOccurs="0" maxOccurs="1" type="xs:boolean" />
|
||||
<xs:element name="concurrentWriteAttempts" minOccurs="0" maxOccurs="1" type="xs:integer" />
|
||||
<xs:element name="concurrentWriteAttemptDelay" minOccurs="0" maxOccurs="1" type="xs:integer" />
|
||||
<xs:element name="bufferSize" minOccurs="0" maxOccurs="1" type="xs:integer" />
|
||||
<xs:element name="openFileFlushTimeout" minOccurs="0" maxOccurs="1" type="xs:integer" />
|
||||
<xs:element name="autoFlush" minOccurs="0" maxOccurs="1" type="xs:boolean" />
|
||||
</xs:choice>
|
||||
<xs:attribute name="name" type="xs:string">
|
||||
<xs:annotation>
|
||||
|
@ -1274,6 +1275,36 @@
|
|||
<xs:documentation>Maximum number of log filenames that should be stored as existing.</xs:documentation>
|
||||
</xs:annotation>
|
||||
</xs:attribute>
|
||||
<xs:attribute name="fileNameKind" type="NLog.Targets.FilePathKind">
|
||||
<xs:annotation>
|
||||
<xs:documentation>Is the an absolute or relative path?</xs:documentation>
|
||||
</xs:annotation>
|
||||
</xs:attribute>
|
||||
<xs:attribute name="forceManaged" type="xs:boolean">
|
||||
<xs:annotation>
|
||||
<xs:documentation>Gets or set a value indicating whether a managed file stream is forced, instead of using the native implementation.</xs:documentation>
|
||||
</xs:annotation>
|
||||
</xs:attribute>
|
||||
<xs:attribute name="forceMutexConcurrentWrites" type="xs:boolean">
|
||||
<xs:annotation>
|
||||
<xs:documentation>Value indicationg whether file creation calls should be synchronized by a system global mutex.</xs:documentation>
|
||||
</xs:annotation>
|
||||
</xs:attribute>
|
||||
<xs:attribute name="replaceFileContentsOnEachWrite" type="xs:boolean">
|
||||
<xs:annotation>
|
||||
<xs:documentation>Indicates whether to replace file contents on each write instead of appending log message at the end.</xs:documentation>
|
||||
</xs:annotation>
|
||||
</xs:attribute>
|
||||
<xs:attribute name="writeBom" type="xs:boolean">
|
||||
<xs:annotation>
|
||||
<xs:documentation>Indicates whether to write BOM (byte order mark) in created files</xs:documentation>
|
||||
</xs:annotation>
|
||||
</xs:attribute>
|
||||
<xs:attribute name="enableFileDelete" type="xs:boolean">
|
||||
<xs:annotation>
|
||||
<xs:documentation>Indicates whether to enable log file(s) to be deleted.</xs:documentation>
|
||||
</xs:annotation>
|
||||
</xs:attribute>
|
||||
<xs:attribute name="fileName" type="SimpleLayoutAttribute">
|
||||
<xs:annotation>
|
||||
<xs:documentation>Name of the file to write to.</xs:documentation>
|
||||
|
@ -1309,49 +1340,9 @@
|
|||
<xs:documentation>File attributes (Windows only).</xs:documentation>
|
||||
</xs:annotation>
|
||||
</xs:attribute>
|
||||
<xs:attribute name="writeBom" type="xs:boolean">
|
||||
<xs:attribute name="optimizeBufferReuse" type="xs:boolean">
|
||||
<xs:annotation>
|
||||
<xs:documentation>Indicates whether to write BOM (byte order mark) in created files</xs:documentation>
|
||||
</xs:annotation>
|
||||
</xs:attribute>
|
||||
<xs:attribute name="enableFileDelete" type="xs:boolean">
|
||||
<xs:annotation>
|
||||
<xs:documentation>Indicates whether to enable log file(s) to be deleted.</xs:documentation>
|
||||
</xs:annotation>
|
||||
</xs:attribute>
|
||||
<xs:attribute name="replaceFileContentsOnEachWrite" type="xs:boolean">
|
||||
<xs:annotation>
|
||||
<xs:documentation>Indicates whether to replace file contents on each write instead of appending log message at the end.</xs:documentation>
|
||||
</xs:annotation>
|
||||
</xs:attribute>
|
||||
<xs:attribute name="forceMutexConcurrentWrites" type="xs:boolean">
|
||||
<xs:annotation>
|
||||
<xs:documentation>Value indicationg whether file creation calls should be synchronized by a system global mutex.</xs:documentation>
|
||||
</xs:annotation>
|
||||
</xs:attribute>
|
||||
<xs:attribute name="forceManaged" type="xs:boolean">
|
||||
<xs:annotation>
|
||||
<xs:documentation>Gets or set a value indicating whether a managed file stream is forced, instead of using the native implementation.</xs:documentation>
|
||||
</xs:annotation>
|
||||
</xs:attribute>
|
||||
<xs:attribute name="fileNameKind" type="NLog.Targets.FilePathKind">
|
||||
<xs:annotation>
|
||||
<xs:documentation>Is the an absolute or relative path?</xs:documentation>
|
||||
</xs:annotation>
|
||||
</xs:attribute>
|
||||
<xs:attribute name="concurrentWrites" type="xs:boolean">
|
||||
<xs:annotation>
|
||||
<xs:documentation>Indicates whether concurrent writes to the log file by multiple processes on the same host.</xs:documentation>
|
||||
</xs:annotation>
|
||||
</xs:attribute>
|
||||
<xs:attribute name="discardAll" type="xs:boolean">
|
||||
<xs:annotation>
|
||||
<xs:documentation>Whether or not this target should just discard all data that its asked to write. Mostly used for when testing NLog Stack except final write</xs:documentation>
|
||||
</xs:annotation>
|
||||
</xs:attribute>
|
||||
<xs:attribute name="concurrentWriteAttemptDelay" type="xs:integer">
|
||||
<xs:annotation>
|
||||
<xs:documentation>Delay in milliseconds to wait before attempting to write to the file again.</xs:documentation>
|
||||
<xs:documentation>Target supports reuse of internal buffers, and doesn't have to constantly allocate new buffers Required for legacy NLog-targets, that expects buffers to remain stable after Write-method exit</xs:documentation>
|
||||
</xs:annotation>
|
||||
</xs:attribute>
|
||||
<xs:attribute name="networkWrites" type="xs:boolean">
|
||||
|
@ -1359,29 +1350,29 @@
|
|||
<xs:documentation>Indicates whether concurrent writes to the log file by multiple processes on different network hosts.</xs:documentation>
|
||||
</xs:annotation>
|
||||
</xs:attribute>
|
||||
<xs:attribute name="openFileCacheSize" type="xs:integer">
|
||||
<xs:annotation>
|
||||
<xs:documentation>Number of files to be kept open. Setting this to a higher value may improve performance in a situation where a single File target is writing to many files (such as splitting by level or by logger).</xs:documentation>
|
||||
</xs:annotation>
|
||||
</xs:attribute>
|
||||
<xs:attribute name="openFileCacheTimeout" type="xs:integer">
|
||||
<xs:annotation>
|
||||
<xs:documentation>Maximum number of seconds that files are kept open. If this number is negative the files are not automatically closed after a period of inactivity.</xs:documentation>
|
||||
</xs:annotation>
|
||||
</xs:attribute>
|
||||
<xs:attribute name="optimizeBufferReuse" type="xs:boolean">
|
||||
<xs:attribute name="openFileCacheSize" type="xs:integer">
|
||||
<xs:annotation>
|
||||
<xs:documentation>Target supports reuse of internal buffers, and doesn't have to constantly allocate new buffers Required for legacy NLog-targets, that expects buffers to remain stable after Write-method exit</xs:documentation>
|
||||
<xs:documentation>Number of files to be kept open. Setting this to a higher value may improve performance in a situation where a single File target is writing to many files (such as splitting by level or by logger).</xs:documentation>
|
||||
</xs:annotation>
|
||||
</xs:attribute>
|
||||
<xs:attribute name="bufferSize" type="xs:integer">
|
||||
<xs:attribute name="keepFileOpen" type="xs:boolean">
|
||||
<xs:annotation>
|
||||
<xs:documentation>Log file buffer size in bytes.</xs:documentation>
|
||||
<xs:documentation>Indicates whether to keep log file open instead of opening and closing it on each logging event.</xs:documentation>
|
||||
</xs:annotation>
|
||||
</xs:attribute>
|
||||
<xs:attribute name="autoFlush" type="xs:boolean">
|
||||
<xs:attribute name="discardAll" type="xs:boolean">
|
||||
<xs:annotation>
|
||||
<xs:documentation>Indicates whether to automatically flush the file buffers after each log message.</xs:documentation>
|
||||
<xs:documentation>Whether or not this target should just discard all data that its asked to write. Mostly used for when testing NLog Stack except final write</xs:documentation>
|
||||
</xs:annotation>
|
||||
</xs:attribute>
|
||||
<xs:attribute name="concurrentWrites" type="xs:boolean">
|
||||
<xs:annotation>
|
||||
<xs:documentation>Indicates whether concurrent writes to the log file by multiple processes on the same host.</xs:documentation>
|
||||
</xs:annotation>
|
||||
</xs:attribute>
|
||||
<xs:attribute name="concurrentWriteAttempts" type="xs:integer">
|
||||
|
@ -1389,9 +1380,24 @@
|
|||
<xs:documentation>Number of times the write is appended on the file before NLog discards the log message.</xs:documentation>
|
||||
</xs:annotation>
|
||||
</xs:attribute>
|
||||
<xs:attribute name="keepFileOpen" type="xs:boolean">
|
||||
<xs:attribute name="concurrentWriteAttemptDelay" type="xs:integer">
|
||||
<xs:annotation>
|
||||
<xs:documentation>Indicates whether to keep log file open instead of opening and closing it on each logging event.</xs:documentation>
|
||||
<xs:documentation>Delay in milliseconds to wait before attempting to write to the file again.</xs:documentation>
|
||||
</xs:annotation>
|
||||
</xs:attribute>
|
||||
<xs:attribute name="bufferSize" type="xs:integer">
|
||||
<xs:annotation>
|
||||
<xs:documentation>Log file buffer size in bytes.</xs:documentation>
|
||||
</xs:annotation>
|
||||
</xs:attribute>
|
||||
<xs:attribute name="openFileFlushTimeout" type="xs:integer">
|
||||
<xs:annotation>
|
||||
<xs:documentation>Maximum number of seconds before open files are flushed. If this number is negative or zero the files are not flushed by timer.</xs:documentation>
|
||||
</xs:annotation>
|
||||
</xs:attribute>
|
||||
<xs:attribute name="autoFlush" type="xs:boolean">
|
||||
<xs:annotation>
|
||||
<xs:documentation>Indicates whether to automatically flush the file buffers after each log message.</xs:documentation>
|
||||
</xs:annotation>
|
||||
</xs:attribute>
|
||||
</xs:extension>
|
||||
|
|
|
@ -21,6 +21,7 @@
|
|||
<layout xsi:type="JsonLayout">
|
||||
<attribute name='time' layout='${longdate}' />
|
||||
<attribute name='level' layout='${level:upperCase=true}'/>
|
||||
<attribute name='pid' layout='${processid}'/>
|
||||
<attribute name='logger' layout='${logger}'/>
|
||||
<attribute name='roomid' layout='${event-properties:item=roomid}'/>
|
||||
<attribute name='message' layout='${message}'/>
|
||||
|
|
|
@ -40,7 +40,7 @@
|
|||
</Style>
|
||||
</ResourceDictionary>
|
||||
</Grid.Resources>
|
||||
|
||||
<!--
|
||||
<TextBlock Grid.Row="0" Grid.Column="0">保存位置:</TextBlock>
|
||||
<Grid Grid.Row="0" Grid.Column="1" VerticalAlignment="Center">
|
||||
<Grid.ColumnDefinitions>
|
||||
|
@ -50,8 +50,8 @@
|
|||
<local:ClickSelectTextBox Grid.Column="0" Text="{Binding SavePath}"/>
|
||||
<Button Grid.Column="1" Click="Button_Click">浏览...</Button>
|
||||
</Grid>
|
||||
|
||||
<TextBlock Grid.Row="1" Grid.Column="0">剪辑回放时长:</TextBlock>
|
||||
-->
|
||||
<TextBlock Grid.Row="1" Grid.Column="0">剪辑过去时长:</TextBlock>
|
||||
<Grid Grid.Row="1" Grid.Column="1" VerticalAlignment="Center">
|
||||
<Grid.ColumnDefinitions>
|
||||
<ColumnDefinition Width="1*"/>
|
||||
|
@ -61,7 +61,7 @@
|
|||
<TextBlock Grid.Column="1" Margin="5,0,10,0">秒</TextBlock>
|
||||
</Grid>
|
||||
|
||||
<TextBlock Grid.Row="2" Grid.Column="0">剪辑录制时长:</TextBlock>
|
||||
<TextBlock Grid.Row="2" Grid.Column="0">剪辑将来时长:</TextBlock>
|
||||
<Grid Grid.Row="2" Grid.Column="1" VerticalAlignment="Center">
|
||||
<Grid.ColumnDefinitions>
|
||||
<ColumnDefinition Width="1*"/>
|
||||
|
|
|
@ -1,18 +1,6 @@
|
|||
using BililiveRecorder.Core;
|
||||
using Microsoft.WindowsAPICodePack.Dialogs;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
using BililiveRecorder.Core.Config;
|
||||
using System.Windows;
|
||||
using System.Windows.Controls;
|
||||
using System.Windows.Data;
|
||||
using System.Windows.Documents;
|
||||
using System.Windows.Input;
|
||||
using System.Windows.Media;
|
||||
using System.Windows.Media.Imaging;
|
||||
using System.Windows.Shapes;
|
||||
|
||||
namespace BililiveRecorder.WPF
|
||||
{
|
||||
|
@ -21,55 +9,63 @@ namespace BililiveRecorder.WPF
|
|||
/// </summary>
|
||||
public partial class SettingsWindow : Window
|
||||
{
|
||||
public ISettings Settings { get; set; } = new Settings();
|
||||
public ConfigV1 Config { get; set; } = new ConfigV1();
|
||||
|
||||
public SettingsWindow(MainWindow mainWindow, ISettings settings)
|
||||
public SettingsWindow(MainWindow mainWindow, ConfigV1 config)
|
||||
{
|
||||
Owner = mainWindow;
|
||||
settings.ApplyTo(Settings);
|
||||
DataContext = Settings;
|
||||
config.CopyPropertiesTo(Config);
|
||||
DataContext = Config;
|
||||
InitializeComponent();
|
||||
}
|
||||
|
||||
private void Save(object sender, RoutedEventArgs e)
|
||||
{
|
||||
if (!_CheckSavePath()) return;
|
||||
// if (!_CheckSavePath())
|
||||
// {
|
||||
// return;
|
||||
// }
|
||||
|
||||
DialogResult = true;
|
||||
Close();
|
||||
}
|
||||
|
||||
private bool _CheckSavePath()
|
||||
{
|
||||
if (string.IsNullOrWhiteSpace(Settings.SavePath))
|
||||
{
|
||||
MessageBox.Show("请设置一个录像保存路径", "保存路径不能为空", MessageBoxButton.OK, MessageBoxImage.Warning);
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
// private bool _CheckSavePath()
|
||||
// {
|
||||
// if (string.IsNullOrWhiteSpace(Config.SavePath))
|
||||
// {
|
||||
// MessageBox.Show("请设置一个录像保存路径", "保存路径不能为空", MessageBoxButton.OK, MessageBoxImage.Warning);
|
||||
// return false;
|
||||
// }
|
||||
// return true;
|
||||
// }
|
||||
|
||||
private void Cancel(object sender, RoutedEventArgs e)
|
||||
{
|
||||
if (!_CheckSavePath()) return;
|
||||
// if (!_CheckSavePath())
|
||||
// {
|
||||
// return;
|
||||
// }
|
||||
|
||||
Close();
|
||||
}
|
||||
|
||||
private void Button_Click(object sender, RoutedEventArgs e)
|
||||
{
|
||||
var fileDialog = new CommonOpenFileDialog()
|
||||
{
|
||||
IsFolderPicker = true,
|
||||
Multiselect = false,
|
||||
Title = "选择录制路径",
|
||||
AddToMostRecentlyUsedList = false,
|
||||
EnsurePathExists = true,
|
||||
NavigateToShortcut = true,
|
||||
InitialDirectory = Settings.SavePath,
|
||||
};
|
||||
if (fileDialog.ShowDialog(this) == CommonFileDialogResult.Ok)
|
||||
{
|
||||
Settings.SavePath = fileDialog.FileName;
|
||||
}
|
||||
// var fileDialog = new CommonOpenFileDialog()
|
||||
// {
|
||||
// IsFolderPicker = true,
|
||||
// Multiselect = false,
|
||||
// Title = "选择录制路径",
|
||||
// AddToMostRecentlyUsedList = false,
|
||||
// EnsurePathExists = true,
|
||||
// NavigateToShortcut = true,
|
||||
// InitialDirectory = Config.SavePath,
|
||||
// };
|
||||
// if (fileDialog.ShowDialog(this) == CommonFileDialogResult.Ok)
|
||||
// {
|
||||
// Config.SavePath = fileDialog.FileName;
|
||||
// }
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
65
BililiveRecorder.WPF/WorkDirectoryWindow.xaml
Normal file
65
BililiveRecorder.WPF/WorkDirectoryWindow.xaml
Normal file
|
@ -0,0 +1,65 @@
|
|||
<Window x:Class="BililiveRecorder.WPF.WorkDirectoryWindow"
|
||||
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
|
||||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
|
||||
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
|
||||
xmlns:local="clr-namespace:BililiveRecorder.WPF"
|
||||
mc:Ignorable="d" ResizeMode="NoResize"
|
||||
Title="录播姬 - 选择工作目录" Height="300" Width="400">
|
||||
<Grid Margin="15">
|
||||
<Grid.RowDefinitions>
|
||||
<RowDefinition Height="3*"/>
|
||||
<RowDefinition Height="Auto"/>
|
||||
<RowDefinition Height="5*"/>
|
||||
<RowDefinition Height="4*"/>
|
||||
</Grid.RowDefinitions>
|
||||
<TextBlock FontSize="26" HorizontalAlignment="Center" TextAlignment="Center" VerticalAlignment="Center">选择工作目录</TextBlock>
|
||||
<StackPanel Grid.Row="1">
|
||||
<StackPanel.Resources>
|
||||
<Style TargetType="TextBlock">
|
||||
<Setter Property="TextAlignment" Value="Center"/>
|
||||
</Style>
|
||||
</StackPanel.Resources>
|
||||
<TextBlock>所有数据都会保存在这个目录中</TextBlock>
|
||||
<TextBlock>包括:软件配置、录制的视频文件</TextBlock>
|
||||
</StackPanel>
|
||||
<Grid Grid.Row="2" Margin="7">
|
||||
<Grid.ColumnDefinitions>
|
||||
<ColumnDefinition Width="*"/>
|
||||
<ColumnDefinition Width="Auto"/>
|
||||
</Grid.ColumnDefinitions>
|
||||
<Grid.RowDefinitions>
|
||||
<RowDefinition Height="Auto"/>
|
||||
<RowDefinition Height="7*"/>
|
||||
</Grid.RowDefinitions>
|
||||
<TextBox VerticalAlignment="Center" FontSize="14" Text="{Binding WorkPath,Delay=800,UpdateSourceTrigger=PropertyChanged}"/>
|
||||
<Button Grid.Column="1" Margin="5,0,0,0" Click="Button_Click">浏览...</Button>
|
||||
<TextBlock Grid.Row="1" Grid.ColumnSpan="2" FontSize="18" Text="{Binding StatusText}" Foreground="{Binding StatusColor}"
|
||||
VerticalAlignment="Center" TextAlignment="Center" HorizontalAlignment="Center" FontWeight="Bold">
|
||||
<TextBlock.Effect>
|
||||
<DropShadowEffect Opacity="0.3" ShadowDepth="1"/>
|
||||
</TextBlock.Effect>
|
||||
</TextBlock>
|
||||
</Grid>
|
||||
<Grid Grid.Row="3">
|
||||
<Grid.ColumnDefinitions>
|
||||
<ColumnDefinition Width="1*"/>
|
||||
<ColumnDefinition Width="1*"/>
|
||||
</Grid.ColumnDefinitions>
|
||||
<Grid.Resources>
|
||||
<Style TargetType="Button">
|
||||
<Setter Property="VerticalAlignment" Value="Center"/>
|
||||
<Setter Property="HorizontalAlignment" Value="Center"/>
|
||||
<Setter Property="Padding" Value="20,10"/>
|
||||
<Setter Property="FontSize" Value="16"/>
|
||||
</Style>
|
||||
</Grid.Resources>
|
||||
<Button IsEnabled="{Binding ConfirmEnabled}" IsDefault="True" Click="Button_Click_1">
|
||||
确认
|
||||
</Button>
|
||||
<Button Grid.Column="1" IsCancel="True" Click="Button_Click_2">
|
||||
退出
|
||||
</Button>
|
||||
</Grid>
|
||||
</Grid>
|
||||
</Window>
|
148
BililiveRecorder.WPF/WorkDirectoryWindow.xaml.cs
Normal file
148
BililiveRecorder.WPF/WorkDirectoryWindow.xaml.cs
Normal file
|
@ -0,0 +1,148 @@
|
|||
using Microsoft.WindowsAPICodePack.Dialogs;
|
||||
using Newtonsoft.Json.Linq;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.ComponentModel;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Runtime.CompilerServices;
|
||||
using System.Windows;
|
||||
using System.Windows.Media;
|
||||
|
||||
namespace BililiveRecorder.WPF
|
||||
{
|
||||
/// <summary>
|
||||
/// WorkDirectoryWindow.xaml 的交互逻辑
|
||||
/// </summary>
|
||||
public partial class WorkDirectoryWindow : Window, INotifyPropertyChanged
|
||||
{
|
||||
public static readonly SolidColorBrush Red = new SolidColorBrush(Color.FromArgb(0xFF, 0xF7, 0x1B, 0x1B));
|
||||
public static readonly SolidColorBrush Green = new SolidColorBrush(Color.FromArgb(0xFF, 0x0B, 0xB4, 0x22));
|
||||
|
||||
public WorkDirectoryWindow()
|
||||
{
|
||||
DataContext = this;
|
||||
InitializeComponent();
|
||||
PropertyChanged += WorkDirectoryWindow_PropertyChanged;
|
||||
//DialogResult = false;
|
||||
}
|
||||
|
||||
private void WorkDirectoryWindow_PropertyChanged(object sender, PropertyChangedEventArgs e)
|
||||
{
|
||||
if (e.PropertyName == nameof(ConfirmEnabled))
|
||||
{
|
||||
if (ConfirmEnabled)
|
||||
{
|
||||
StatusColor = Green;
|
||||
}
|
||||
else
|
||||
{
|
||||
StatusColor = Red;
|
||||
}
|
||||
}
|
||||
else if (e.PropertyName == nameof(WorkPath))
|
||||
{
|
||||
CheckPath();
|
||||
}
|
||||
}
|
||||
|
||||
private void CheckPath()
|
||||
{
|
||||
var c = WorkPath;
|
||||
if (Directory.Exists(c))
|
||||
{
|
||||
if (Directory.EnumerateFiles(c).Any())
|
||||
{
|
||||
string config = Path.Combine(c, "config.json");
|
||||
if (File.Exists(config))
|
||||
{
|
||||
try
|
||||
{
|
||||
var text = File.ReadAllText(config);
|
||||
var j = JObject.Parse(text);
|
||||
if (j["version"] == null || j["data"] == null)
|
||||
{
|
||||
StatusText = "配置文件不是录播姬文件";
|
||||
ConfirmEnabled = false;
|
||||
}
|
||||
else
|
||||
{
|
||||
StatusText = "已有录播姬目录";
|
||||
ConfirmEnabled = true;
|
||||
}
|
||||
}
|
||||
catch (Exception)
|
||||
{
|
||||
StatusText = "读取配置文件出错";
|
||||
ConfirmEnabled = false;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
StatusText = "此文件夹已有其他文件";
|
||||
ConfirmEnabled = false;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
StatusText = "可用的空文件夹";
|
||||
ConfirmEnabled = true;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
StatusText = "目录不存在";
|
||||
ConfirmEnabled = false;
|
||||
}
|
||||
}
|
||||
|
||||
private string _workPath;
|
||||
public string WorkPath { get => _workPath; set => SetField(ref _workPath, value); }
|
||||
|
||||
private string _statusText;
|
||||
public string StatusText { get => _statusText; set => SetField(ref _statusText, value); }
|
||||
|
||||
private SolidColorBrush _statusColor;
|
||||
public SolidColorBrush StatusColor { get => _statusColor; set => SetField(ref _statusColor, value); }
|
||||
|
||||
private bool _confirmEnabled;
|
||||
public bool ConfirmEnabled { get => _confirmEnabled; set => SetField(ref _confirmEnabled, value); }
|
||||
|
||||
private void Button_Click(object sender, RoutedEventArgs e)
|
||||
{
|
||||
var fileDialog = new CommonOpenFileDialog()
|
||||
{
|
||||
IsFolderPicker = true,
|
||||
Multiselect = false,
|
||||
Title = "选择录播姬工作目录路径",
|
||||
AddToMostRecentlyUsedList = false,
|
||||
EnsurePathExists = true,
|
||||
NavigateToShortcut = true,
|
||||
InitialDirectory = WorkPath,
|
||||
};
|
||||
if (fileDialog.ShowDialog(this) == CommonFileDialogResult.Ok)
|
||||
{
|
||||
WorkPath = fileDialog.FileName;
|
||||
}
|
||||
}
|
||||
|
||||
public event PropertyChangedEventHandler PropertyChanged;
|
||||
protected virtual void OnPropertyChanged(string propertyName) => PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
|
||||
protected bool SetField<T>(ref T field, T value, [CallerMemberName] string propertyName = "")
|
||||
{
|
||||
if (EqualityComparer<T>.Default.Equals(field, value)) { return false; }
|
||||
field = value; OnPropertyChanged(propertyName); return true;
|
||||
}
|
||||
|
||||
private void Button_Click_1(object sender, RoutedEventArgs e)
|
||||
{
|
||||
DialogResult = true;
|
||||
Close();
|
||||
}
|
||||
|
||||
private void Button_Click_2(object sender, RoutedEventArgs e)
|
||||
{
|
||||
Close();
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,9 +1,10 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<packages>
|
||||
<package id="Autofac" version="4.8.1" targetFramework="net462" />
|
||||
<package id="NLog" version="4.5.0-rc07" targetFramework="net462" />
|
||||
<package id="NLog.Config" version="4.5.0-rc07" targetFramework="net462" />
|
||||
<package id="NLog.Schema" version="4.5.0-rc07" targetFramework="net462" />
|
||||
<package id="Newtonsoft.Json" version="11.0.2" targetFramework="net462" />
|
||||
<package id="NLog" version="4.5.10" targetFramework="net462" />
|
||||
<package id="NLog.Config" version="4.5.10" targetFramework="net462" />
|
||||
<package id="NLog.Schema" version="4.5.10" targetFramework="net462" />
|
||||
<package id="WindowsAPICodePack-Core" version="1.1.2" targetFramework="net462" />
|
||||
<package id="WindowsAPICodePack-Shell" version="1.1.1" targetFramework="net462" />
|
||||
</packages>
|
Loading…
Reference in New Issue
Block a user