Merge pull request #74 from Bililive/dev

Release v1.1.15
This commit is contained in:
Genteure 2019-11-24 10:35:46 +08:00 committed by GitHub
commit 133d3686db
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
21 changed files with 79 additions and 97 deletions

9
.editorconfig Normal file
View File

@ -0,0 +1,9 @@
# http://editorconfig.org/
# top-most EditorConfig file
root = true
# all files
[*]
indent_style = space
indent_size = 4

2
.gitignore vendored
View File

@ -261,5 +261,5 @@ paket-files/
__pycache__/
*.pyc
BililiveRecorder.WPF/BuildInfo.cs
**/BuildInfo.cs
BililiveRecorder.WPF/Nlog.config

View File

@ -1,7 +1,6 @@
using Newtonsoft.Json.Linq;
using NLog;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Net;
using System.Net.Http;
@ -134,11 +133,11 @@ namespace BililiveRecorder.Core
var withoutTxy = all.Where(x => !x.Contains("txy.")).ToArray();
if (withoutTxy.Length > 0)
{
return withoutTxy[random.Next(0, withoutTxy.Length - 1)];
return withoutTxy[random.Next(withoutTxy.Length)];
}
else if (attempt_left <= 0)
{
return all[random.Next(0, all.Length - 1)];
return all[random.Next(all.Length)];
}
}
else
@ -152,15 +151,11 @@ namespace BililiveRecorder.Core
// 随机选择一个 url
if ((await HttpGetJsonAsync(url))?["data"]?["durl"] is JArray array)
{
List<string> urls = new List<string>();
for (int i = 0; i < array.Count; i++)
{
urls.Add(array[i]?["url"]?.ToObject<string>());
}
var urls = array.Select(t => t?["url"]?.ToObject<string>());
var distinct = urls.Distinct().ToArray();
if (distinct.Length > 0)
{
return distinct[random.Next(0, distinct.Count() - 1)];
return distinct[random.Next(distinct.Length)];
}
}
throw new Exception("没有直播播放地址");

View File

@ -16,6 +16,9 @@
<DebugType>none</DebugType>
<DebugSymbols>false</DebugSymbols>
</PropertyGroup>
<ItemGroup>
<Compile Include="BuildInfo.cs" />
</ItemGroup>
<ItemGroup>
<PackageReference Include="Autofac" Version="4.8.1" />
<PackageReference Include="Newtonsoft.Json" Version="11.0.2" />
@ -24,4 +27,8 @@
<ItemGroup>
<ProjectReference Include="..\BililiveRecorder.FlvProcessor\BililiveRecorder.FlvProcessor.csproj" />
</ItemGroup>
<PropertyGroup>
<PreBuildEvent>cd $(SolutionDir)
powershell -ExecutionPolicy Bypass -File .\CI\patch_buildinfo.ps1 Core</PreBuildEvent>
</PropertyGroup>
</Project>

View File

@ -86,12 +86,6 @@ namespace BililiveRecorder.Core.Config
[JsonProperty("timing_watchdog_timeout")]
public uint TimingWatchdogTimeout { get => _timingWatchdogTimeout; set => SetField(ref _timingWatchdogTimeout, value); }
/// <summary>
/// 最大直播数据落后时间 毫秒
/// </summary>
[JsonProperty("timing_watchdog_behind")]
public uint TimingWatchdogBehind { get => _timingWatchdogBehind; set => SetField(ref _timingWatchdogBehind, value); }
/// <summary>
/// 请求 API 时使用的 Cookie
/// </summary>
@ -123,7 +117,6 @@ namespace BililiveRecorder.Core.Config
private string _workDirectory;
private uint _timingWatchdogTimeout = 10 * 1000;
private uint _timingWatchdogBehind = 10 * 1000;
private uint _timingStreamRetry = 6 * 1000;
private uint _timingStreamConnect = 3 * 1000;
private uint _timingDanmakuRetry = 2 * 1000;

View File

@ -17,7 +17,7 @@ namespace BililiveRecorder.Core
bool IsRecording { get; }
double DownloadSpeedPersentage { get; }
double DownloadSpeedKiBps { get; }
double DownloadSpeedMegaBitps { get; }
DateTime LastUpdateDateTime { get; }
void Clip();

View File

@ -82,7 +82,7 @@ namespace BililiveRecorder.Core
public CancellationTokenSource cancellationTokenSource = null;
private double _DownloadSpeedPersentage = 0;
private double _DownloadSpeedKiBps = 0;
private double _DownloadSpeedMegaBitps = 0;
private long _lastUpdateSize = 0;
private int _lastUpdateTimestamp = 0;
public DateTime LastUpdateDateTime { get; private set; } = DateTime.Now;
@ -91,10 +91,10 @@ namespace BililiveRecorder.Core
get { return _DownloadSpeedPersentage; }
private set { if (value != _DownloadSpeedPersentage) { _DownloadSpeedPersentage = value; TriggerPropertyChanged(nameof(DownloadSpeedPersentage)); } }
}
public double DownloadSpeedKiBps
public double DownloadSpeedMegaBitps
{
get { return _DownloadSpeedKiBps; }
private set { if (value != _DownloadSpeedKiBps) { _DownloadSpeedKiBps = value; TriggerPropertyChanged(nameof(DownloadSpeedKiBps)); } }
get { return _DownloadSpeedMegaBitps; }
private set { if (value != _DownloadSpeedMegaBitps) { _DownloadSpeedMegaBitps = value; TriggerPropertyChanged(nameof(DownloadSpeedMegaBitps)); } }
}
public RecordedRoom(ConfigV1 config,
@ -192,7 +192,7 @@ namespace BililiveRecorder.Core
cancellationTokenSource.Cancel();
if (!(StreamDownloadTask?.Wait(TimeSpan.FromSeconds(2)) ?? true))
{
logger.Log(RoomId, LogLevel.Warn, "尝试强制关闭连接,请检查网络连接是否稳定");
logger.Log(RoomId, LogLevel.Warn, "停止录制超时,尝试强制关闭连接,请检查网络连接是否稳定");
_stream?.Close();
_stream?.Dispose();
@ -283,7 +283,7 @@ namespace BililiveRecorder.Core
},
{
"version",
"TEST"
BuildInfo.Version + " " + BuildInfo.HeadShaShort
},
{
"roomid",
@ -351,8 +351,8 @@ namespace BililiveRecorder.Core
}
logger.Log(RoomId, LogLevel.Info,
(token.IsCancellationRequested ? "用户操作" : "直播已结束") + ",停止录制。"
+ (_retry ? "将重试启动。" : ""));
(token.IsCancellationRequested ? "本地操作结束当前录制。" : "服务器关闭直播流,可能是直播已结束。")
+ (_retry ? "将重试启动。" : ""));
if (_retry)
{
StreamMonitor.Check(TriggerType.HttpApiRecheck, (int)_config.TimingStreamRetry);
@ -383,7 +383,7 @@ namespace BililiveRecorder.Core
_response = null;
_lastUpdateTimestamp = 0;
DownloadSpeedKiBps = 0d;
DownloadSpeedMegaBitps = 0d;
DownloadSpeedPersentage = 0d;
TriggerPropertyChanged(nameof(IsRecording));
}
@ -394,7 +394,7 @@ namespace BililiveRecorder.Core
_lastUpdateSize += bytesRead;
if (passedSeconds > 1.5)
{
DownloadSpeedKiBps = _lastUpdateSize / passedSeconds / 1024; // KiB per sec
DownloadSpeedMegaBitps = _lastUpdateSize / passedSeconds * 8d / 1_000_000d; // mega bit per second
DownloadSpeedPersentage = (DownloadSpeedPersentage / 2) + ((Processor.TotalMaxTimestamp - _lastUpdateTimestamp) / passedSeconds / 1000 / 2); // ((RecordedTime/1000) / RealTime)%
_lastUpdateTimestamp = Processor.TotalMaxTimestamp;
_lastUpdateSize = 0;

View File

@ -213,17 +213,7 @@ namespace BililiveRecorder.Core
{
if (DateTime.Now - room.LastUpdateDateTime > TimeSpan.FromMilliseconds(Config.TimingWatchdogTimeout))
{
logger.Warn("服务器停止提供 [{roomid}] 直播间的直播数据,通常是录制时网络不稳定导致,将会断开重连", room.RoomId);
room.StopRecord();
room.StartRecord();
}
else if (room.Processor != null &&
((DateTime.Now - room.Processor.StartDateTime).TotalMilliseconds
>
(room.Processor.TotalMaxTimestamp + Config.TimingWatchdogBehind))
)
{
logger.Warn("直播间 [{roomid}] 的下载速度达不到录制标准,将断开重连。请检查网络是否稳定", room.RoomId);
logger.Warn("服务器未断开连接但停止提供 [{roomid}] 直播间的直播数据,通常是录制侧网络不稳定导致,将会断开重连", room.RoomId);
room.StopRecord();
room.StartRecord();
}

View File

@ -16,8 +16,15 @@
<DebugType>none</DebugType>
<DebugSymbols>false</DebugSymbols>
</PropertyGroup>
<ItemGroup>
<Compile Include="BuildInfo.cs" />
</ItemGroup>
<ItemGroup>
<PackageReference Include="Autofac" Version="4.8.1" />
<PackageReference Include="NLog" Version="4.5.10" />
</ItemGroup>
<PropertyGroup>
<PreBuildEvent>cd $(SolutionDir)
powershell -ExecutionPolicy Bypass -File .\CI\patch_buildinfo.ps1 FlvProcessor</PreBuildEvent>
</PropertyGroup>
</Project>

View File

@ -249,7 +249,7 @@ namespace BililiveRecorder.FlvProcessor
{
if (_hasOffset)
{
tag.SetTimeStamp(Math.Max(0, tag.TimeStamp - _baseTimeStamp)); // 修复时间戳
tag.SetTimeStamp(tag.TimeStamp - _baseTimeStamp);
TotalMaxTimestamp = Math.Max(TotalMaxTimestamp, tag.TimeStamp);
}
else

View File

@ -77,8 +77,7 @@ namespace BililiveRecorder.FlvProcessor
var size = BitConverter.GetBytes(useDataSize ? Data.Length : TagSize).ToBE();
Buffer.BlockCopy(size, 1, tag, 1, 3);
byte[] timing = new byte[4];
Buffer.BlockCopy(BitConverter.GetBytes(Math.Max(0, TimeStamp - offset)).ToBE(), 0, timing, 0, timing.Length);
byte[] timing = BitConverter.GetBytes(TimeStamp - offset).ToBE();
Buffer.BlockCopy(timing, 1, tag, 4, 3);
Buffer.BlockCopy(timing, 0, tag, 7, 1);

View File

@ -196,7 +196,6 @@
<Generator>ResXFileCodeGenerator</Generator>
<LastGenOutput>Resources.Designer.cs</LastGenOutput>
</EmbeddedResource>
<None Include="BuildInfo.txt" />
<None Include="Properties\app.manifest" />
<Resource Include="ico.ico" />
<Content Include="NLog.config">
@ -225,7 +224,7 @@
<Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
<PropertyGroup>
<PreBuildEvent>cd $(SolutionDir)
PowerShell -ExecutionPolicy Bypass -File .\CI\patch_buildinfo.ps1
powershell -ExecutionPolicy Bypass -File .\CI\patch_buildinfo.ps1 WPF
copy /y .\BililiveRecorder.WPF\Nlog.$(ConfigurationName).config .\BililiveRecorder.WPF\NLog.config</PreBuildEvent>
</PropertyGroup>
<PropertyGroup>

View File

@ -95,7 +95,7 @@
<DataGridTextColumn Binding="{Binding StreamerName,Mode=OneWay}" Header="主播名字"/>
<DataGridTextColumn Binding="{Binding IsRecording,Converter={StaticResource RecordStatusConverter},Mode=OneWay}" Header="录制状态"/>
<DataGridTextColumn Binding="{Binding IsMonitoring,Converter={StaticResource MonitorStatusConverter},Mode=OneWay}" Header="是否自动录制"/>
<DataGridTextColumn Binding="{Binding DownloadSpeedKiBps,StringFormat=0.## KiB/s,Mode=OneWay}" Header="录制下载速度"/>
<DataGridTextColumn Binding="{Binding DownloadSpeedMegaBitps,StringFormat=0.## Mbps,Mode=OneWay}" Header="实时下载速度"/>
<DataGridTextColumn Binding="{Binding DownloadSpeedPersentage,StringFormat=0.## %,Mode=OneWay}" Header="录制速度比"/>
<DataGridTextColumn Binding="{Binding Processor.Clips.Count,Mode=OneWay}" Header="剪辑数量"/>
</DataGrid.Columns>
@ -156,8 +156,8 @@
<TextBlock Grid.Row="5" Grid.Column="0" VerticalAlignment="Center" HorizontalAlignment="Right">处理中剪辑数量:</TextBlock>
<TextBlock Grid.Row="5" Grid.Column="1" VerticalAlignment="Center" HorizontalAlignment="Left" Text="{Binding Processor.Clips.Count,Mode=OneWay}"/>
<TextBlock Grid.Row="6" Grid.Column="0" VerticalAlignment="Center" HorizontalAlignment="Right">录制下载速度:</TextBlock>
<TextBlock Grid.Row="6" Grid.Column="1" VerticalAlignment="Center" HorizontalAlignment="Left" Text="{Binding DownloadSpeedKiBps,StringFormat=0.## KiB/s,Mode=OneWay}"/>
<TextBlock Grid.Row="6" Grid.Column="0" VerticalAlignment="Center" HorizontalAlignment="Right">实时下载速度:</TextBlock>
<TextBlock Grid.Row="6" Grid.Column="1" VerticalAlignment="Center" HorizontalAlignment="Left" Text="{Binding DownloadSpeedMegaBitps,StringFormat=0.## Mbps,Mode=OneWay}"/>
<TextBlock Grid.Row="7" Grid.Column="0" VerticalAlignment="Center" HorizontalAlignment="Right">录制速度比:</TextBlock>
<TextBlock Grid.Row="7" Grid.Column="1" VerticalAlignment="Center" HorizontalAlignment="Left" Text="{Binding DownloadSpeedPersentage,StringFormat=0.## %,Mode=OneWay}"/>

View File

@ -39,7 +39,10 @@ namespace BililiveRecorder.WPF
"问题反馈邮箱: rec@danmuji.org",
"QQ群 689636812",
"",
"功能调整:删除直播间按钮调整了位置,从软件界面右侧移动到了列表右键菜单"
"删除直播间按钮在列表右键菜单里",
"",
"录制速度比 在 100% 左右说明跟上了主播直播的速度",
"小于 100% 说明录播电脑的下载带宽不够,跟不上录制直播"
};
public static void AddLog(string message) => _AddLog?.Invoke(message);

View File

@ -59,7 +59,7 @@
<ColumnDefinition Width="2*"/>
<ColumnDefinition Width="3*"/>
</Grid.ColumnDefinitions>
<TextBlock Grid.Row="0" Grid.Column="0">录制重间隔:</TextBlock>
<TextBlock Grid.Row="0" Grid.Column="0">录制重间隔:</TextBlock>
<Grid Grid.Row="0" Grid.Column="1" VerticalAlignment="Center">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="1*"/>
@ -130,7 +130,7 @@
</local:ClickSelectTextBox>
<TextBlock Grid.Column="1" Margin="5,0,10,0">毫秒</TextBlock>
</Grid>
<TextBlock Grid.Row="3" Grid.Column="0">录制超时时间</TextBlock>
<TextBlock Grid.Row="3" Grid.Column="0">接收数据超时</TextBlock>
<Grid Grid.Row="3" Grid.Column="1" VerticalAlignment="Center">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="1*"/>
@ -154,31 +154,6 @@
</local:ClickSelectTextBox>
<TextBlock Grid.Column="1" Margin="5,0,10,0">毫秒</TextBlock>
</Grid>
<TextBlock Grid.Row="4" Grid.Column="0">录制最长落后:</TextBlock>
<Grid Grid.Row="4" Grid.Column="1" VerticalAlignment="Center">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="1*"/>
<ColumnDefinition Width="Auto"/>
</Grid.ColumnDefinitions>
<local:ClickSelectTextBox Grid.Column="0" Text="{Binding TimingWatchdogBehind,Delay=500,UpdateSourceTrigger=PropertyChanged}">
<local:ClickSelectTextBox.ToolTip>
<ToolTip>
<StackPanel>
<StackPanel.Resources>
<Style TargetType="TextBlock">
<Setter Property="TextAlignment" Value="Left"/>
</Style>
</StackPanel.Resources>
<TextBlock FontWeight="Bold">注:</TextBlock>
<TextBlock>录制比主播直播落后一定时间后自动断开重连。</TextBlock>
<TextBlock>实际使用中如果发生了因为跟不上主播直播</TextBlock>
<TextBlock>的情况,说明录制电脑的网速不够。</TextBlock>
</StackPanel>
</ToolTip>
</local:ClickSelectTextBox.ToolTip>
</local:ClickSelectTextBox>
<TextBlock Grid.Column="1" Margin="5,0,10,0">毫秒</TextBlock>
</Grid>
<TextBlock Grid.Row="5" Grid.Column="0">开播检查间隔:</TextBlock>
<Grid Grid.Row="5" Grid.Column="1" VerticalAlignment="Center">
<Grid.ColumnDefinitions>

View File

@ -1,4 +1,4 @@
namespace BililiveRecorder.WPF
namespace BililiveRecorder.[PROJECT_NAME]
{
internal class BuildInfo
{

View File

@ -4,4 +4,6 @@ $isAppveyor = if ($env:APPVEYOR -eq $null) { "false" } else { $env:APPVEYOR }
$buildversion = if ($env:APPVEYOR_BUILD_VERSION -eq $null) { "本地编译" } else { $env:APPVEYOR_BUILD_VERSION }
$githash = git rev-parse --verify HEAD
(Get-Content .\BililiveRecorder.WPF\BuildInfo.txt).Replace('[APPVEYOR]', $isAppveyor.ToLower()).Replace('[VERSION]', $buildversion).Replace('[GIT_HASH]', $githash).Replace('[GIT_HASH_S]', $githash.Substring(0, 8)) | Set-Content .\BililiveRecorder.WPF\BuildInfo.cs
(Get-Content .\BuildInfo.txt).Replace('[PROJECT_NAME]', $args).Replace('[APPVEYOR]', $isAppveyor.ToLower()).Replace('[VERSION]', $buildversion).Replace('[GIT_HASH]', $githash).Replace('[GIT_HASH_S]', $githash.Substring(0, 8)) | Set-Content ".\BililiveRecorder.$args\BuildInfo.cs"
Write-Output "BuildInfo for $args patched"

View File

@ -19,19 +19,16 @@ See [rec.danmuji.org](https://rec.danmuji.org) (in Chinese)
## Feature
- Easy to use
- Fix timestamp automatically
- Reset timestamp to start from 0
- Writes duration info automatically when recoding session ends.
- Start recording when stream starts
- Record multiple stream at same time
- Have a "Clip" Feature (just like [Twitch's](https://help.twitch.tv/customer/portal/articles/2442508-how-to-use-clips))
- Pure C#, no native dependents
- Pure C#, no native dependency like ffmpeg
- Open source!
## Develop & Getting Started
You'll need:
- Visual Studio 2017 with .NET Core
- PowerShell
**Visual Studio 2017 with .NET Core** and **PowerShell** is required. Visual Studio 2019 *could* work but is not tested.
Some file are generated by [PreComplie Script](./CI/patch_buildinfo.ps1). Build project to clear errors shown by Visual Studio.
@ -50,6 +47,6 @@ You can start poking around from...
## Reference & Acknowledgements
- [coreyauger/flv-streamer-2-file](https://github.com/coreyauger/flv-streamer-2-file): An awesome library.
- [zyzsdy/biliroku](https://github.com/zyzsdy/biliroku): First BiliBili stream record tool.
- [Video File Format Specification Version 10.pdf](https://wwwimages2.adobe.com/content/dam/acom/en/devnet/flv/video_file_format_spec_v10.pdf)
- [Adobe Flash Video File Format Specification 10.1.2.01.pdf](https://www.adobe.com/content/dam/acom/en/devnet/flv/video_file_format_spec_v10_1.pdf)
- [coreyauger/flv-streamer-2-file](https://github.com/coreyauger/flv-streamer-2-file)
- [zyzsdy/biliroku](https://github.com/zyzsdy/biliroku) - (probably) first BiliBili stream recording tool.

View File

@ -13,11 +13,11 @@
## 功能
- 使用简单
- 自动修复视频时间戳
- 使录出的文件时间戳从 0 开始
- 录制结束后自动写入总时长信息
- 可以主播开播后自动录制
- 可以同时录制多个直播间
- 可以录制“即时回放剪辑”(类似 [Twitch 的 Clip](https://help.twitch.tv/customer/portal/articles/2442508-how-to-use-clips)
- 纯 C# 实现,无 Native 依赖
- 纯 C# 实现,无 ffmpeg 等 native 依赖
- 开源!
## 入门 & 开发
@ -34,7 +34,7 @@
BililiveRecorder.WPF | .NET Framework 4.6.2
BililiveRecorder.Core | .NET Standard 2.0
BililiveRecorder.FlvProcessor | .NET Standard 2.0
BililiveRecorder.Server | .NET Core 2.0 | 预留坑,将来填
BililiveRecorder.Server | .NET Core 2.0 | 预留坑,将来填(咕咕咕)
如果你想研究这个项目的源代码,或修改功能的话:
@ -42,8 +42,14 @@ BililiveRecorder.Server | .NET Core 2.0 | 预留坑,将来填
- 录制逻辑建议从 `BililiveRecorder.Core/Recorder.cs` 开始看
- FLV数据处理建议从 `BililiveRecorder.FlvProcessor/FlvStreamProcessor.cs` 开始看
## Server 版说明
本项目核心逻辑均与 WPF 界面分离,使用 .NET Standard 2.0 而不是 .NET Framework可以较轻松地改出可在 Linux 上运行的 .NET Core 版本,但因为本人没时间等原因一直没有做。
如果有有能人士有在 Linux 上运行本项目的需求的话可以自行 fork 修改(但我大概不会 merge 回来)
## 参考资料 & 鸣谢
- [coreyauger/flv-streamer-2-file](https://github.com/coreyauger/flv-streamer-2-file): 在FLV处理方面参考了很多
- [zyzsdy/biliroku](https://github.com/zyzsdy/biliroku): 第一个B站直播录播工具
- [Video File Format Specification Version 10.pdf](https://wwwimages2.adobe.com/content/dam/acom/en/devnet/flv/video_file_format_spec_v10.pdf): FLV视频文件格式规范
- [Adobe Flash Video File Format Specification 10.1.2.01.pdf](https://www.adobe.com/content/dam/acom/en/devnet/flv/video_file_format_spec_v10_1.pdf)
- [coreyauger/flv-streamer-2-file](https://github.com/coreyauger/flv-streamer-2-file)
- [zyzsdy/biliroku](https://github.com/zyzsdy/biliroku): (大概是)第一个B站直播录播工具

View File

@ -1 +1 @@
1.1.14
1.1.15

View File

@ -34,10 +34,10 @@ install:
before_build:
- nuget restore -Verbosity quiet
- msbuild /nologo /v:q /t:Clean
- msbuild /nologo /v:m /t:Clean
build_script:
- ps: msbuild /nologo /v:q /p:Configuration="$env:CONFIGURATION" /p:SquirrelBuildTarget="$env:DEPLOY_SITE_GIT\BililiveRecorder" /logger:"C:\Program Files\AppVeyor\BuildAgent\Appveyor.MSBuildLogger.dll"
- ps: msbuild /nologo /v:m /p:Configuration="$env:CONFIGURATION" /p:SquirrelBuildTarget="$env:DEPLOY_SITE_GIT\BililiveRecorder" /logger:"C:\Program Files\AppVeyor\BuildAgent\Appveyor.MSBuildLogger.dll"
for:
-