mirror of
https://github.com/leiurayer/downkyi.git
synced 2026-10-19 16:16:50 +00:00
Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
dc4033cd8b | ||
|
|
844a110edf | ||
|
|
c95840c681 | ||
|
|
ade4c78190 | ||
|
|
8958cf46c4 | ||
|
|
b4d619eca9 | ||
|
|
05b678e2b8 | ||
|
|
60813ce903 | ||
|
|
4188daca72 | ||
|
|
84c3403a94 | ||
|
|
5ade29a4f6 | ||
|
|
4b36040f39 | ||
|
|
3eead3252e | ||
|
|
1c2cffccda | ||
|
|
47fe322244 | ||
|
|
79ccebf160 | ||
|
|
a95014cee5 | ||
|
|
aaae6352bc | ||
|
|
8b6e286d18 | ||
|
|
0356b94d71 | ||
|
|
0c5cc2d7ca | ||
|
|
0cb78dc396 | ||
|
|
e750a19f0f | ||
|
|
6c28569401 | ||
|
|
0dde0bceb5 | ||
|
|
a35d8a0334 | ||
|
|
74a0f7b96d | ||
|
|
3092033906 | ||
|
|
338d7d3c87 | ||
|
|
4c260854f3 | ||
|
|
bbe818d125 | ||
|
|
3b2d9d3bb3 | ||
|
|
aac78d508a | ||
|
|
4fdb1c3f16 | ||
|
|
6b3044e9f7 | ||
|
|
0fc08b12e9 | ||
|
|
755790aae0 | ||
|
|
e597596e66 | ||
|
|
80c1024b51 | ||
|
|
e268f731c4 | ||
|
|
78b247d4a1 | ||
|
|
049778b76f | ||
|
|
591ea2cf06 | ||
|
|
682e80ae0e | ||
|
|
c977ca928c | ||
|
|
2c11e4243e | ||
|
|
9ef5354e73 | ||
|
|
bb760b238d | ||
|
|
79b7fbeb7a | ||
|
|
9a932b8759 | ||
|
|
3f8a1f7fd3 | ||
|
|
6e6e5a4751 | ||
|
|
c7e4719152 | ||
|
|
39e5d28a2d | ||
|
|
6e6e17e10a | ||
|
|
32c892c380 | ||
|
|
34d242780c | ||
|
|
bb1637071f | ||
|
|
1dff44f9d4 | ||
|
|
516c4cc1bc | ||
|
|
4be9a74816 | ||
|
|
10ab358538 | ||
|
|
c4594cf4f7 | ||
|
|
ad5e3c2f70 | ||
|
|
e37b9d0e76 | ||
|
|
568851bfaa | ||
|
|
76c968ac39 | ||
|
|
588599e1cf | ||
|
|
bf87565165 | ||
|
|
040d236310 | ||
|
|
36b6b174e6 | ||
|
|
47e068e80c | ||
|
|
4d7ffe112f | ||
|
|
d449c42bec | ||
|
|
a0a1d659ec | ||
|
|
ebfba6a59f | ||
|
|
0c559a9bf0 | ||
|
|
363bf2ccce | ||
|
|
4733d1e1bf | ||
|
|
1027a9e702 | ||
|
|
f199f35247 | ||
|
|
8ec6c21505 | ||
|
|
ec8b03166f | ||
|
|
8a2274fc08 | ||
|
|
cb2a6055a4 | ||
|
|
19a11c6fe3 | ||
|
|
6392311d31 | ||
|
|
8dfd2e11f9 | ||
|
|
94237b5ee9 | ||
|
|
74a9450680 | ||
|
|
e64d27dc0a | ||
|
|
9b8e143135 | ||
|
|
cd1e6608d3 | ||
|
|
6cd1d58755 | ||
|
|
1dc0ef02bd | ||
|
|
ce9b292500 | ||
|
|
a5f7b1e7ac | ||
|
|
07dcba5714 | ||
|
|
6f67462ee9 | ||
|
|
0126c1b21f | ||
|
|
68025448b6 | ||
|
|
3938a3bfd2 | ||
|
|
023eff8e81 | ||
|
|
f0c4553997 | ||
|
|
796be050a5 | ||
|
|
73b2fa9739 | ||
|
|
59c75e3fdd | ||
|
|
dc199a4559 | ||
|
|
56db28c913 | ||
|
|
8317865b41 | ||
|
|
287b3b528d | ||
|
|
62deb1e40e | ||
|
|
e838202f43 | ||
|
|
08224774c3 | ||
|
|
fdba90ff1e | ||
|
|
127ffd5dc6 | ||
|
|
084d4ab363 | ||
|
|
5959088dfc | ||
|
|
7253a0ee12 | ||
|
|
e50159fdb6 | ||
|
|
42fbfaeb1f | ||
|
|
778d2829fa | ||
|
|
440ebff101 | ||
|
|
b0947151e7 | ||
|
|
99b3e5393d | ||
|
|
3a918a6e5c | ||
|
|
60880abb8b | ||
|
|
a7cc7d3ba1 | ||
|
|
c2b70c3ab1 | ||
|
|
f6536284e9 | ||
|
|
6f21977c8f | ||
|
|
9fda62b962 | ||
|
|
f7cd3c734c | ||
|
|
f93306509d | ||
|
|
6c8a738e02 | ||
|
|
4a3f0d43eb | ||
|
|
013c6f2fe7 | ||
|
|
52e36b0fd7 | ||
|
|
093652f0d6 | ||
|
|
d98730b64f | ||
|
|
a023935c7c | ||
|
|
1b0bacbd33 | ||
|
|
fbda4865af | ||
|
|
dcc54225db | ||
|
|
32aeb711ac | ||
|
|
012cb42042 | ||
|
|
d0b2f577c8 | ||
|
|
d4693f525e | ||
|
|
4ad4de5578 | ||
|
|
d5f4902663 | ||
|
|
efa01234cb | ||
|
|
062bb81589 | ||
|
|
9df0a74fe2 | ||
|
|
c1ea829215 | ||
|
|
0257df9fbe | ||
|
|
35e6d2e8c8 | ||
|
|
1ba868d613 | ||
|
|
4773a2b0c8 | ||
|
|
41a7d71a98 | ||
|
|
6ce7b69a56 | ||
|
|
ed180a0699 | ||
|
|
1a7c9cd6fc | ||
|
|
fea42637b2 | ||
|
|
62a0528112 | ||
|
|
7b8b6b9009 | ||
|
|
656b877cba | ||
|
|
e45107b635 | ||
|
|
7b5b7de1fb | ||
|
|
700b4df9da | ||
|
|
a9b84875c3 | ||
|
|
b6e993e1e3 | ||
|
|
f52230166d | ||
|
|
1d7e156c11 | ||
|
|
99a83b06a9 | ||
|
|
fe9c9ff415 | ||
|
|
b31c7830d4 | ||
|
|
4b1af53db7 | ||
|
|
30535c11cd | ||
|
|
dbc6804dca | ||
|
|
123b74d85f | ||
|
|
67400b45bf | ||
|
|
8f6553d401 | ||
|
|
c2351ae21b | ||
|
|
4c09ded9c1 | ||
|
|
0a37220fe9 | ||
|
|
c664ecd9f6 | ||
|
|
195838929e | ||
|
|
c552411b91 | ||
|
|
3f0457b7db | ||
|
|
994eb158b9 | ||
|
|
ab97c43a8f | ||
|
|
384b394014 | ||
|
|
3b2de59d0b | ||
|
|
ba1235669c | ||
|
|
a95070ffae | ||
|
|
1962150ec6 | ||
|
|
5ffdfcab77 | ||
|
|
fcf388870f | ||
|
|
fd7fabeaba | ||
|
|
bd61bd6dcf | ||
|
|
86de932f56 | ||
|
|
8715e4bb29 | ||
|
|
1880a2a806 | ||
|
|
f10c2d2d80 | ||
|
|
53be15c7ab | ||
|
|
fb0fcf1e7e | ||
|
|
158c77f951 | ||
|
|
2ffa86420a | ||
|
|
e06f3a51ce | ||
|
|
49380ee775 | ||
|
|
e0d02a2622 | ||
|
|
65f87c8517 | ||
|
|
59d9854611 | ||
|
|
580705652f | ||
|
|
71a4d657c1 | ||
|
|
3c2ef7cf1e | ||
|
|
31d82a9309 | ||
|
|
2ccdff96a8 | ||
|
|
251619a4ba | ||
|
|
7c43873e87 | ||
|
|
966b707165 | ||
|
|
6a3b1e96b5 | ||
|
|
a809245e95 | ||
|
|
e781c72d68 | ||
|
|
0a26704f2a | ||
|
|
be6b0d47a5 | ||
|
|
35fa8d6cd5 | ||
|
|
4d2590605e | ||
|
|
fee511cf33 | ||
|
|
c48ecc86c9 | ||
|
|
e0f3c978cd | ||
|
|
653aff5a02 | ||
|
|
9e685be6a2 | ||
|
|
88bf600c40 | ||
|
|
3699afe0fb | ||
|
|
0e9f12d3c6 | ||
|
|
5a58a2e284 | ||
|
|
c63597efbd | ||
|
|
c41c81db3d | ||
|
|
f5febf148a | ||
|
|
1e851ce1c2 | ||
|
|
58c67c86d2 | ||
|
|
7a0f3df4fb | ||
|
|
67e7f38f9d | ||
|
|
af5c453337 |
@@ -0,0 +1,2 @@
|
||||
!runtimes/x64
|
||||
!runtimes/x86
|
||||
@@ -0,0 +1,47 @@
|
||||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
|
||||
<PropertyGroup>
|
||||
<TargetFrameworks>net472;netstandard2.0</TargetFrameworks>
|
||||
<Version>2.1.1.0</Version>
|
||||
<GeneratePackageOnBuild>true</GeneratePackageOnBuild>
|
||||
<PackageId>Brotli.NET</PackageId>
|
||||
<Authors>Jinjun Xie</Authors>
|
||||
<Company>Jinjun Xie</Company>
|
||||
<Copyright>Copyright Jinjun Xie 2016</Copyright>
|
||||
<PackageLicenseUrl></PackageLicenseUrl>
|
||||
<PackageProjectUrl>https://github.com/XieJJ99/brotli.net</PackageProjectUrl>
|
||||
<PackageTags>Brotli Compress Decompress .NET Standard Stream</PackageTags>
|
||||
<PackageReleaseNotes>Add async stream support, update brotli core to v1.0.9</PackageReleaseNotes>
|
||||
<Description>Supported on dotnet standard2(Windows/Linux/OSX), provide similar interface to Google offical API.Quality and window control is supported.
|
||||
The library use the native runtime and its performance should be better than System.IO.Compress.BrotliStream.
|
||||
For more document,please visit https://github.com/XieJJ99/brotli.net.</Description>
|
||||
<PackageLicenseExpression>MIT</PackageLicenseExpression>
|
||||
<AssemblyVersion>2.1.1.0</AssemblyVersion>
|
||||
<Platforms>AnyCPU;x64;x86</Platforms>
|
||||
</PropertyGroup>
|
||||
<ItemGroup>
|
||||
<!-- <None Update="runtimes\**" Pack="true" PackagePath="." /> -->
|
||||
<None Include="runtimes\**">
|
||||
<PackagePath>runtimes</PackagePath>
|
||||
<Pack>true</Pack>
|
||||
</None>
|
||||
</ItemGroup>
|
||||
<Import Project="build\Brotli.NET.targets" />
|
||||
<ItemGroup>
|
||||
<None Remove="build\Brotli.NET.targets~RF6be2dbfa.TMP" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<!-- <None Update="runtimes\**" Pack="true" PackagePath="." /> -->
|
||||
<!-- <None Include="runtimes\**\*.dll">
|
||||
<PackagePath>build\runtimes</PackagePath>
|
||||
<Pack>true</Pack>
|
||||
</None> -->
|
||||
<None Include="build\Brotli.NET.targets">
|
||||
<PackagePath>build</PackagePath>
|
||||
<Pack>true</Pack>
|
||||
</None>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<PackageReference Include="System.Runtime.InteropServices.RuntimeInformation" Version="4.3.0" Condition=" '$(TargetFramework)' == 'net45' " />
|
||||
</ItemGroup>
|
||||
</Project>
|
||||
@@ -0,0 +1,12 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Text;
|
||||
|
||||
namespace Brotli
|
||||
{
|
||||
public enum BrotliDecoderParameter:int
|
||||
{
|
||||
DisableRingBufferReallocation=0,
|
||||
LargeWindow=1,
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,22 @@
|
||||
namespace Brotli
|
||||
{
|
||||
public enum BrotliDecoderResult:int
|
||||
{
|
||||
/// <summary>
|
||||
/// Decoding error, e.g. corrupt input or memory allocation problem
|
||||
/// </summary>
|
||||
Error = 0,
|
||||
/// <summary>
|
||||
/// Decoding successfully completed
|
||||
/// </summary>
|
||||
Success = 1,
|
||||
/// <summary>
|
||||
/// Partially done; should be called again with more input
|
||||
/// </summary>
|
||||
NeedsMoreInput = 2,
|
||||
/// <summary>
|
||||
/// Partially done; should be called again with more output
|
||||
/// </summary>
|
||||
NeedsMoreOutput = 3
|
||||
};
|
||||
}
|
||||
@@ -0,0 +1,26 @@
|
||||
namespace Brotli
|
||||
{
|
||||
public enum BrotliEncoderOperation : int
|
||||
{
|
||||
Process = 0,
|
||||
/// <summary>
|
||||
/// Request output stream to flush. Performed when input stream is depleted
|
||||
/// and there is enough space in output stream.
|
||||
/// </summary>
|
||||
Flush = 1,
|
||||
/// <summary>
|
||||
/// Request output stream to finish. Performed when input stream is depleted
|
||||
/// and there is enough space in output stream.
|
||||
/// </summary>
|
||||
Finish = 2,
|
||||
|
||||
/// <summary>
|
||||
/// Emits metadata block to stream. Stream is soft-flushed before metadata
|
||||
/// block is emitted. CAUTION: when operation is started, length of the input
|
||||
/// buffer is interpreted as length of a metadata block; changing operation,
|
||||
/// expanding or truncating input before metadata block is completely emitted
|
||||
/// will cause an error; metadata block must not be greater than 16MiB.
|
||||
/// </summary>
|
||||
EmitMetadata = 3
|
||||
};
|
||||
}
|
||||
@@ -0,0 +1,22 @@
|
||||
namespace Brotli
|
||||
{
|
||||
public enum BrotliEncoderParameter : int
|
||||
{
|
||||
Mode = 0,
|
||||
/// <summary>
|
||||
/// Controls the compression-speed vs compression-density tradeoffs. The higher
|
||||
/// the quality, the slower the compression. Range is 0 to 11.
|
||||
/// </summary>
|
||||
Quality = 1,
|
||||
/// <summary>
|
||||
/// Base 2 logarithm of the sliding window size. Range is 10 to 24.
|
||||
/// </summary>
|
||||
LGWin = 2,
|
||||
|
||||
/// <summary>
|
||||
/// Base 2 logarithm of the maximum input block size. Range is 16 to 24.
|
||||
/// If set to 0, the value will be set based on the quality.
|
||||
/// </summary>
|
||||
LGBlock = 3
|
||||
};
|
||||
}
|
||||
@@ -0,0 +1,25 @@
|
||||
using System;
|
||||
|
||||
namespace Brotli
|
||||
{
|
||||
public class BrotliDecodeException : BrotliException
|
||||
{
|
||||
public int Code { get; set; }
|
||||
public String ErrorText { get; set; }
|
||||
|
||||
|
||||
public BrotliDecodeException(int code, String errorText) : base() {
|
||||
Code = code;
|
||||
ErrorText = errorText;
|
||||
}
|
||||
|
||||
public BrotliDecodeException(String message, int code, String errorText) : base(message) {
|
||||
Code = code;
|
||||
ErrorText = errorText;
|
||||
}
|
||||
public BrotliDecodeException(String message, Exception innerException, int code, String errorText) : base(message, innerException) {
|
||||
Code = code;
|
||||
ErrorText = errorText;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
using System;
|
||||
|
||||
namespace Brotli
|
||||
{
|
||||
public class BrotliException:Exception
|
||||
{
|
||||
public BrotliException() : base() { }
|
||||
public BrotliException(String message) : base(message) { }
|
||||
public BrotliException(String message, Exception innerException) : base(message, innerException) { }
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,90 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace Brotli
|
||||
{
|
||||
public static class BrotliExtensions
|
||||
{
|
||||
/// <summary>
|
||||
/// Compress the data with brotli
|
||||
/// </summary>
|
||||
/// <param name="rawData">inputData</param>
|
||||
/// <param name="quality">quality,0~11</param>
|
||||
/// <param name="window">compress window(10~24)</param>
|
||||
/// <returns>compressed bytes</returns>
|
||||
public static byte[] CompressToBrotli(this byte[] rawData, uint quality = 5, uint window = 22)
|
||||
{
|
||||
if (rawData == null) throw new ArgumentNullException(nameof(rawData));
|
||||
using (var msInput = new System.IO.MemoryStream(rawData))
|
||||
{
|
||||
return CompressToBrotli(msInput, quality, window);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Compress the data with brotli
|
||||
/// </summary>
|
||||
/// <param name="inStream">input stream</param>
|
||||
/// <param name="quality">quality,0~11</param>
|
||||
/// <param name="window">compress window(10~24)</param>
|
||||
/// <returns>compressed bytes</returns>
|
||||
public static byte[] CompressToBrotli(this System.IO.Stream inStream, uint quality = 5, uint window = 22)
|
||||
{
|
||||
using (System.IO.MemoryStream msOutput = new System.IO.MemoryStream())
|
||||
{
|
||||
CompressToBrotli(inStream, msOutput, quality, window);
|
||||
var output = msOutput.ToArray();
|
||||
return output;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Compress the data with brotli
|
||||
/// </summary>
|
||||
/// <param name="inStream">input stream</param>
|
||||
/// <param name="destStream">dest output stream</param>
|
||||
/// <param name="quality">quality,0~11</param>
|
||||
/// <param name="window">compress window(10~24)</param>
|
||||
public static void CompressToBrotli(this System.IO.Stream inStream, System.IO.Stream destStream, uint quality = 5, uint window = 22)
|
||||
{
|
||||
using (BrotliStream bs = new BrotliStream(destStream, System.IO.Compression.CompressionMode.Compress))
|
||||
{
|
||||
bs.SetQuality(quality);
|
||||
bs.SetWindow(window);
|
||||
inStream.CopyTo(bs);
|
||||
bs.Close();
|
||||
}
|
||||
}
|
||||
|
||||
public static byte[] DecompressFromBrotli(this byte[] rawData)
|
||||
{
|
||||
if (rawData == null) throw new ArgumentNullException(nameof(rawData));
|
||||
using (var msInput = new System.IO.MemoryStream(rawData))
|
||||
{
|
||||
return DecompressFromBrotli(msInput);
|
||||
}
|
||||
}
|
||||
|
||||
public static byte[] DecompressFromBrotli(this System.IO.Stream inStream)
|
||||
{
|
||||
using (System.IO.MemoryStream msOutput = new System.IO.MemoryStream())
|
||||
{
|
||||
DecompressFromBrotli(inStream, msOutput);
|
||||
var output = msOutput.ToArray();
|
||||
return output;
|
||||
}
|
||||
}
|
||||
|
||||
public static void DecompressFromBrotli(this System.IO.Stream inStream,System.IO.Stream destStream)
|
||||
{
|
||||
using (BrotliStream bs = new BrotliStream(inStream, System.IO.Compression.CompressionMode.Decompress))
|
||||
{
|
||||
bs.CopyTo(destStream);
|
||||
destStream.Flush();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,67 @@
|
||||
using System;
|
||||
using System.Globalization;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace Brotli
|
||||
{
|
||||
internal class AsyncHelper
|
||||
{
|
||||
private static readonly TaskFactory _myTaskFactory = new
|
||||
TaskFactory(CancellationToken.None, TaskCreationOptions.None,
|
||||
TaskContinuationOptions.None, TaskScheduler.Default);
|
||||
|
||||
internal static void RunSync(Func<Task> func, bool await = false)
|
||||
{
|
||||
CultureInfo cultureUi = CultureInfo.CurrentUICulture;
|
||||
CultureInfo culture = CultureInfo.CurrentCulture;
|
||||
_myTaskFactory.StartNew(delegate
|
||||
{
|
||||
Thread.CurrentThread.CurrentCulture = culture;
|
||||
Thread.CurrentThread.CurrentUICulture = cultureUi;
|
||||
return func();
|
||||
}).Unwrap().ConfigureAwait(await).GetAwaiter().GetResult();
|
||||
}
|
||||
|
||||
// Microsoft.AspNet.Identity.AsyncHelper
|
||||
internal static TResult RunSync<TResult>(Func<Task<TResult>> func, bool await = false)
|
||||
{
|
||||
CultureInfo cultureUi = CultureInfo.CurrentUICulture;
|
||||
CultureInfo culture = CultureInfo.CurrentCulture;
|
||||
return _myTaskFactory.StartNew<Task<TResult>>(delegate
|
||||
{
|
||||
Thread.CurrentThread.CurrentCulture = culture;
|
||||
Thread.CurrentThread.CurrentUICulture = cultureUi;
|
||||
return func();
|
||||
}).Unwrap<TResult>().ConfigureAwait(await).GetAwaiter().GetResult();
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
internal static TResult RunSync<TResult>(Func<object, Task<TResult>> func, object state, bool await = false)
|
||||
{
|
||||
CultureInfo cultureUi = CultureInfo.CurrentUICulture;
|
||||
CultureInfo culture = CultureInfo.CurrentCulture;
|
||||
return _myTaskFactory.StartNew<Task<TResult>>(delegate
|
||||
{
|
||||
Thread.CurrentThread.CurrentCulture = culture;
|
||||
Thread.CurrentThread.CurrentUICulture = cultureUi;
|
||||
return func(state);
|
||||
}, state).Unwrap<TResult>().ConfigureAwait(await).GetAwaiter().GetResult();
|
||||
}
|
||||
|
||||
internal static TResult RunSync<TResult>(Func<object, Task<TResult>> func, object state, CancellationToken cancellationToken, bool await = false)
|
||||
{
|
||||
CultureInfo cultureUi = CultureInfo.CurrentUICulture;
|
||||
CultureInfo culture = CultureInfo.CurrentCulture;
|
||||
return _myTaskFactory.StartNew<Task<TResult>>(delegate
|
||||
{
|
||||
Thread.CurrentThread.CurrentCulture = culture;
|
||||
Thread.CurrentThread.CurrentUICulture = cultureUi;
|
||||
return func(state);
|
||||
}, state, cancellationToken).Unwrap<TResult>().ConfigureAwait(await).GetAwaiter().GetResult();
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,316 @@
|
||||
using System;
|
||||
using System.Diagnostics;
|
||||
using System.Runtime.InteropServices;
|
||||
|
||||
namespace Brotli
|
||||
{
|
||||
public class Brolib
|
||||
{
|
||||
static bool UseX86 = IntPtr.Size == 4;
|
||||
#region Encoder
|
||||
public static IntPtr BrotliEncoderCreateInstance()
|
||||
{
|
||||
if (UseX86)
|
||||
{
|
||||
return Brolib32.BrotliEncoderCreateInstance(IntPtr.Zero, IntPtr.Zero, IntPtr.Zero);
|
||||
}
|
||||
else
|
||||
{
|
||||
return Brolib64.BrotliEncoderCreateInstance(IntPtr.Zero, IntPtr.Zero, IntPtr.Zero);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public static IntPtr GetModuleHandle(String moduleName)
|
||||
{
|
||||
IntPtr r = IntPtr.Zero;
|
||||
foreach (ProcessModule mod in Process.GetCurrentProcess().Modules)
|
||||
{
|
||||
if (String.Compare(mod.ModuleName,moduleName,true)==0)
|
||||
{
|
||||
r = mod.BaseAddress;
|
||||
break;
|
||||
}
|
||||
}
|
||||
return r;
|
||||
}
|
||||
|
||||
public static void FreeLibrary()
|
||||
{
|
||||
|
||||
IntPtr libHandle = IntPtr.Zero;
|
||||
libHandle = GetModuleHandle(LibPathBootStrapper.LibPath);
|
||||
if (libHandle!=IntPtr.Zero)
|
||||
{
|
||||
NativeLibraryLoader.FreeLibrary(libHandle);
|
||||
}
|
||||
}
|
||||
|
||||
public static bool BrotliEncoderSetParameter(IntPtr state, BrotliEncoderParameter parameter, UInt32 value)
|
||||
{
|
||||
if (UseX86)
|
||||
{
|
||||
return Brolib32.BrotliEncoderSetParameter(state, parameter, value);
|
||||
}
|
||||
else
|
||||
{
|
||||
return Brolib64.BrotliEncoderSetParameter(state, parameter, value);
|
||||
}
|
||||
}
|
||||
|
||||
//@to rewrite using the following APIs
|
||||
//BrotliGetDictionary
|
||||
//BrotliGetTransforms
|
||||
//BrotliSetDictionaryData
|
||||
//BrotliTransformDictionaryWord
|
||||
//public static void BrotliEncoderSetCustomDictionary(IntPtr state, UInt32 size, IntPtr dict)
|
||||
//{
|
||||
// if (UseX86)
|
||||
// {
|
||||
// Brolib32.BrotliEncoderSetCustomDictionary(state, size, dict);
|
||||
// }
|
||||
// else
|
||||
// {
|
||||
// Brolib64.BrotliEncoderSetCustomDictionary(state, size, dict);
|
||||
// }
|
||||
//}
|
||||
|
||||
public static bool BrotliEncoderCompressStream(
|
||||
IntPtr state, BrotliEncoderOperation op, ref UInt32 availableIn,
|
||||
ref IntPtr nextIn, ref UInt32 availableOut, ref IntPtr nextOut, out UInt32 totalOut)
|
||||
{
|
||||
if (UseX86)
|
||||
{
|
||||
return Brolib32.BrotliEncoderCompressStream(state, op, ref availableIn, ref nextIn, ref availableOut, ref nextOut, out totalOut);
|
||||
}
|
||||
else
|
||||
{
|
||||
UInt64 availableInL = availableIn;
|
||||
UInt64 availableOutL = availableOut;
|
||||
UInt64 totalOutL = 0;
|
||||
var r = Brolib64.BrotliEncoderCompressStream(state, op, ref availableInL, ref nextIn, ref availableOutL, ref nextOut, out totalOutL);
|
||||
availableIn = (UInt32)availableInL;
|
||||
availableOut = (UInt32)availableOutL;
|
||||
totalOut = (UInt32)totalOutL;
|
||||
return r;
|
||||
}
|
||||
}
|
||||
|
||||
public static bool BrotliEncoderIsFinished(IntPtr state)
|
||||
{
|
||||
if (UseX86)
|
||||
{
|
||||
return Brolib32.BrotliEncoderIsFinished(state);
|
||||
}
|
||||
else
|
||||
{
|
||||
return Brolib64.BrotliEncoderIsFinished(state);
|
||||
}
|
||||
}
|
||||
|
||||
public static void BrotliEncoderDestroyInstance(IntPtr state)
|
||||
{
|
||||
if (UseX86)
|
||||
{
|
||||
Brolib32.BrotliEncoderDestroyInstance(state);
|
||||
}
|
||||
else
|
||||
{
|
||||
Brolib64.BrotliEncoderDestroyInstance(state);
|
||||
}
|
||||
}
|
||||
|
||||
public static UInt32 BrotliEncoderVersion()
|
||||
{
|
||||
if (UseX86)
|
||||
{
|
||||
return Brolib32.BrotliEncoderVersion();
|
||||
}
|
||||
else
|
||||
{
|
||||
return Brolib64.BrotliEncoderVersion();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public static IntPtr BrotliDecoderTakeOutput(IntPtr state, ref UInt32 size)
|
||||
{
|
||||
if (UseX86)
|
||||
{
|
||||
return Brolib32.BrotliDecoderTakeOutput(state, ref size);
|
||||
}
|
||||
else
|
||||
{
|
||||
UInt64 longSize = size;
|
||||
var r = Brolib64.BrotliDecoderTakeOutput(state, ref longSize);
|
||||
size = (UInt32)longSize;
|
||||
return r;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
#endregion
|
||||
#region Decoder
|
||||
public static IntPtr BrotliDecoderCreateInstance()
|
||||
{
|
||||
if (UseX86)
|
||||
{
|
||||
return Brolib32.BrotliDecoderCreateInstance(IntPtr.Zero, IntPtr.Zero, IntPtr.Zero);
|
||||
}
|
||||
else
|
||||
{
|
||||
return Brolib64.BrotliDecoderCreateInstance(IntPtr.Zero, IntPtr.Zero, IntPtr.Zero);
|
||||
}
|
||||
}
|
||||
|
||||
public static bool BrotliDecoderSetParameter(IntPtr state, BrotliDecoderParameter param, UInt32 value)
|
||||
{
|
||||
if (UseX86)
|
||||
{
|
||||
return Brolib32.BrotliDecoderSetParameter(state,param,value);
|
||||
}
|
||||
else
|
||||
{
|
||||
return Brolib64.BrotliDecoderSetParameter(state, param, value);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
//@to rewrite using the following APIs
|
||||
//BrotliGetDictionary
|
||||
//BrotliGetTransforms
|
||||
//BrotliSetDictionaryData
|
||||
//BrotliTransformDictionaryWord
|
||||
//public static void BrotliDecoderSetCustomDictionary(IntPtr state, UInt32 size, IntPtr dict)
|
||||
//{
|
||||
// if (UseX86)
|
||||
// {
|
||||
// Brolib32.BrotliDecoderSetCustomDictionary(state, size, dict);
|
||||
// }
|
||||
// else
|
||||
// {
|
||||
// Brolib64.BrotliDecoderSetCustomDictionary(state, size, dict);
|
||||
// }
|
||||
//}
|
||||
|
||||
public static BrotliDecoderResult BrotliDecoderDecompressStream(
|
||||
IntPtr state, ref UInt32 availableIn,
|
||||
ref IntPtr nextIn, ref UInt32 availableOut, ref IntPtr nextOut, out UInt32 totalOut)
|
||||
{
|
||||
if (UseX86)
|
||||
{
|
||||
return Brolib32.BrotliDecoderDecompressStream(state, ref availableIn, ref nextIn, ref availableOut, ref nextOut, out totalOut);
|
||||
}
|
||||
else
|
||||
{
|
||||
UInt64 availableInL = availableIn;
|
||||
UInt64 availableOutL = availableOut;
|
||||
UInt64 totalOutL = 0;
|
||||
var r = Brolib64.BrotliDecoderDecompressStream(state, ref availableInL, ref nextIn, ref availableOutL, ref nextOut, out totalOutL);
|
||||
availableIn = (UInt32)availableInL;
|
||||
availableOut = (UInt32)availableOutL;
|
||||
totalOut = (UInt32)totalOutL;
|
||||
return r;
|
||||
}
|
||||
}
|
||||
|
||||
public static void BrotliDecoderDestroyInstance(IntPtr state)
|
||||
{
|
||||
if (UseX86)
|
||||
{
|
||||
Brolib32.BrotliDecoderDestroyInstance(state);
|
||||
}
|
||||
else
|
||||
{
|
||||
Brolib64.BrotliDecoderDestroyInstance(state);
|
||||
}
|
||||
}
|
||||
|
||||
public static UInt32 BrotliDecoderVersion()
|
||||
{
|
||||
if (UseX86)
|
||||
{
|
||||
return Brolib32.BrotliDecoderVersion();
|
||||
}
|
||||
else
|
||||
{
|
||||
return Brolib64.BrotliDecoderVersion();
|
||||
}
|
||||
}
|
||||
|
||||
public static bool BrotliDecoderIsUsed(IntPtr state)
|
||||
{
|
||||
if (UseX86)
|
||||
{
|
||||
return Brolib32.BrotliDecoderIsUsed(state);
|
||||
}
|
||||
else
|
||||
{
|
||||
return Brolib64.BrotliDecoderIsUsed(state);
|
||||
}
|
||||
}
|
||||
public static bool BrotliDecoderIsFinished(IntPtr state)
|
||||
{
|
||||
if (UseX86)
|
||||
{
|
||||
return Brolib32.BrotliDecoderIsFinished(state);
|
||||
}
|
||||
else
|
||||
{
|
||||
return Brolib64.BrotliDecoderIsFinished(state);
|
||||
}
|
||||
|
||||
}
|
||||
public static Int32 BrotliDecoderGetErrorCode(IntPtr state)
|
||||
{
|
||||
if (UseX86)
|
||||
{
|
||||
return Brolib32.BrotliDecoderGetErrorCode(state);
|
||||
}
|
||||
else
|
||||
{
|
||||
return Brolib64.BrotliDecoderGetErrorCode(state);
|
||||
}
|
||||
}
|
||||
|
||||
public static String BrotliDecoderErrorString(Int32 code)
|
||||
{
|
||||
IntPtr r = IntPtr.Zero;
|
||||
if (UseX86)
|
||||
{
|
||||
r = Brolib32.BrotliDecoderErrorString(code);
|
||||
}
|
||||
else
|
||||
{
|
||||
r = Brolib64.BrotliDecoderErrorString(code);
|
||||
}
|
||||
|
||||
if (r != IntPtr.Zero)
|
||||
{
|
||||
return Marshal.PtrToStringAnsi(r);
|
||||
}
|
||||
return String.Empty;
|
||||
|
||||
|
||||
}
|
||||
|
||||
public static IntPtr BrotliEncoderTakeOutput(IntPtr state, ref UInt32 size)
|
||||
{
|
||||
if (UseX86)
|
||||
{
|
||||
return Brolib32.BrotliEncoderTakeOutput(state, ref size);
|
||||
}
|
||||
else
|
||||
{
|
||||
UInt64 longSize = size;
|
||||
var r = Brolib64.BrotliEncoderTakeOutput(state, ref longSize);
|
||||
size = (UInt32)longSize;
|
||||
return r;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
#endregion
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,443 @@
|
||||
using System;
|
||||
using System.IO;
|
||||
using System.IO.Compression;
|
||||
using System.Runtime.InteropServices;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace Brotli
|
||||
{
|
||||
public class BrotliStream : Stream
|
||||
{
|
||||
const int BufferSize = 64 * 1024;
|
||||
protected Stream _stream = null;
|
||||
protected MemoryStream _intermediateStream = new MemoryStream();
|
||||
protected CompressionMode _mode = CompressionMode.Compress;
|
||||
protected IntPtr _state = IntPtr.Zero;
|
||||
protected IntPtr _ptrInputBuffer = IntPtr.Zero;
|
||||
protected IntPtr _ptrOutputBuffer = IntPtr.Zero;
|
||||
|
||||
protected IntPtr _ptrNextInput = IntPtr.Zero;
|
||||
protected IntPtr _ptrNextOutput = IntPtr.Zero;
|
||||
protected UInt32 _availableIn = 0;
|
||||
protected UInt32 _availableOut = BufferSize;
|
||||
|
||||
protected Byte[] _managedBuffer;
|
||||
protected Boolean _endOfStream = false;
|
||||
protected int _readOffset = 0;
|
||||
protected BrotliDecoderResult _lastDecodeResult = BrotliDecoderResult.NeedsMoreInput;
|
||||
protected Boolean _leaveOpen = false;
|
||||
|
||||
public BrotliStream(Stream baseStream, CompressionMode mode,bool leaveOpen)
|
||||
{
|
||||
if (baseStream == null) throw new ArgumentNullException("baseStream");
|
||||
_mode = mode;
|
||||
_stream = baseStream;
|
||||
_leaveOpen = leaveOpen;
|
||||
if (_mode == CompressionMode.Compress)
|
||||
{
|
||||
_state = Brolib.BrotliEncoderCreateInstance();
|
||||
if (_state == IntPtr.Zero)
|
||||
{
|
||||
throw new BrotliException("Unable to create brotli encoder instance");
|
||||
}
|
||||
Brolib.BrotliEncoderSetParameter(_state, BrotliEncoderParameter.Quality, 5);
|
||||
Brolib.BrotliEncoderSetParameter(_state, BrotliEncoderParameter.LGWin, 22);
|
||||
}
|
||||
else
|
||||
{
|
||||
_state = Brolib.BrotliDecoderCreateInstance();
|
||||
if (_state == IntPtr.Zero)
|
||||
{
|
||||
throw new BrotliException("Unable to create brotli decoder instance");
|
||||
}
|
||||
//follow the brotli default standard
|
||||
var succ = Brolib.BrotliDecoderSetParameter(_state, BrotliDecoderParameter.LargeWindow, 1U);
|
||||
if (!succ)
|
||||
{
|
||||
throw new BrotliException("failed to set decoder parameter to large window");
|
||||
}
|
||||
}
|
||||
_ptrInputBuffer = Marshal.AllocHGlobal(BufferSize);
|
||||
_ptrOutputBuffer = Marshal.AllocHGlobal(BufferSize);
|
||||
_ptrNextInput = _ptrInputBuffer;
|
||||
_ptrNextOutput = _ptrOutputBuffer;
|
||||
|
||||
_managedBuffer = new Byte[BufferSize];
|
||||
}
|
||||
public BrotliStream(Stream baseStream, CompressionMode mode):this(baseStream,mode,false)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Set the compress quality(0~11)
|
||||
/// </summary>
|
||||
/// <param name="quality">compress quality</param>
|
||||
public void SetQuality(uint quality)
|
||||
{
|
||||
if (quality < 0 || quality > 11)
|
||||
{
|
||||
throw new ArgumentException("quality", "the range of quality is 0~11");
|
||||
}
|
||||
Brolib.BrotliEncoderSetParameter(_state, BrotliEncoderParameter.Quality, quality);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Set the compress LGWin(10~24)
|
||||
/// </summary>
|
||||
/// <param name="window">the window size</param>
|
||||
public void SetWindow(uint window)
|
||||
{
|
||||
if (window < 10 || window > 24)
|
||||
{
|
||||
throw new ArgumentException("window", "the range of window is 10~24");
|
||||
}
|
||||
Brolib.BrotliEncoderSetParameter(_state, BrotliEncoderParameter.LGWin, window);
|
||||
}
|
||||
|
||||
public override bool CanRead
|
||||
{
|
||||
get
|
||||
{
|
||||
if (_stream == null)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
return (_mode == System.IO.Compression.CompressionMode.Decompress && _stream.CanRead);
|
||||
}
|
||||
}
|
||||
|
||||
public override bool CanSeek
|
||||
{
|
||||
get
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
public override bool CanWrite
|
||||
{
|
||||
get
|
||||
{
|
||||
if (_stream == null)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
return (_mode == System.IO.Compression.CompressionMode.Compress && _stream.CanWrite);
|
||||
}
|
||||
}
|
||||
|
||||
public override long Length
|
||||
{
|
||||
get
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
}
|
||||
|
||||
public override long Position
|
||||
{
|
||||
get
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
|
||||
set
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
}
|
||||
|
||||
public override async Task FlushAsync(CancellationToken cancellationToken)
|
||||
{
|
||||
if (_stream == null)
|
||||
{
|
||||
throw new ObjectDisposedException(null, "Underlying stream is disposed");
|
||||
}
|
||||
if (_mode == CompressionMode.Compress)
|
||||
{
|
||||
await FlushBrotliStreamAsync(false).ConfigureAwait(false);
|
||||
}
|
||||
|
||||
}
|
||||
public override void Flush()
|
||||
{
|
||||
AsyncHelper.RunSync(() => FlushAsync());
|
||||
}
|
||||
|
||||
protected virtual async Task FlushBrotliStreamAsync(Boolean finished)
|
||||
{
|
||||
//test if the resource has been freed
|
||||
if (_state == IntPtr.Zero) return;
|
||||
if (Brolib.BrotliEncoderIsFinished(_state)) return;
|
||||
BrotliEncoderOperation op = finished ? BrotliEncoderOperation.Finish : BrotliEncoderOperation.Flush;
|
||||
UInt32 totalOut = 0;
|
||||
while (true)
|
||||
{
|
||||
var compressOK = Brolib.BrotliEncoderCompressStream(_state, op, ref _availableIn, ref _ptrNextInput, ref _availableOut, ref _ptrNextOutput, out totalOut);
|
||||
if (!compressOK) throw new BrotliException("Unable to finish encode stream");
|
||||
var extraData = _availableOut != BufferSize;
|
||||
if (extraData)
|
||||
{
|
||||
var bytesWrote = (int)(BufferSize - _availableOut);
|
||||
Marshal.Copy(_ptrOutputBuffer, _managedBuffer, 0, bytesWrote);
|
||||
await _stream.WriteAsync(_managedBuffer, 0, bytesWrote).ConfigureAwait(false);
|
||||
_availableOut = BufferSize;
|
||||
_ptrNextOutput = _ptrOutputBuffer;
|
||||
}
|
||||
if (Brolib.BrotliEncoderIsFinished(_state)) break;
|
||||
if (!extraData) break;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
protected virtual void FlushBrotliStream(Boolean finished)
|
||||
{
|
||||
|
||||
AsyncHelper.RunSync(() => FlushBrotliStreamAsync(finished));
|
||||
}
|
||||
|
||||
protected override void Dispose(bool disposing)
|
||||
{
|
||||
if (_mode == CompressionMode.Compress)
|
||||
{
|
||||
FlushBrotliStream(true);
|
||||
}
|
||||
base.Dispose(disposing);
|
||||
if (!_leaveOpen) _stream.Dispose();
|
||||
_intermediateStream.Dispose();
|
||||
if (_ptrInputBuffer!=IntPtr.Zero) Marshal.FreeHGlobal(_ptrInputBuffer);
|
||||
if (_ptrOutputBuffer != IntPtr.Zero) Marshal.FreeHGlobal(_ptrOutputBuffer);
|
||||
_managedBuffer = null;
|
||||
_ptrInputBuffer = IntPtr.Zero;
|
||||
_ptrOutputBuffer = IntPtr.Zero;
|
||||
if (_state != IntPtr.Zero)
|
||||
{
|
||||
if (_mode == CompressionMode.Compress)
|
||||
{
|
||||
Brolib.BrotliEncoderDestroyInstance(_state);
|
||||
}
|
||||
else
|
||||
{
|
||||
Brolib.BrotliDecoderDestroyInstance(_state);
|
||||
}
|
||||
_state = IntPtr.Zero;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public void TruncateBeginning(MemoryStream ms, int numberOfBytesToRemove)
|
||||
{
|
||||
#if NETSTANDARD2_0
|
||||
ArraySegment<byte> buf;
|
||||
if(ms.TryGetBuffer(out buf))
|
||||
{
|
||||
Buffer.BlockCopy(buf.Array, numberOfBytesToRemove, buf.Array, 0, (int)ms.Length - numberOfBytesToRemove);
|
||||
ms.SetLength(ms.Length - numberOfBytesToRemove);
|
||||
}
|
||||
else
|
||||
{
|
||||
throw new UnauthorizedAccessException();
|
||||
}
|
||||
#else
|
||||
byte[] buf = ms.GetBuffer();
|
||||
Buffer.BlockCopy(buf, numberOfBytesToRemove, buf, 0, (int)ms.Length - numberOfBytesToRemove);
|
||||
ms.SetLength(ms.Length - numberOfBytesToRemove);
|
||||
#endif
|
||||
}
|
||||
|
||||
public override async Task<int> ReadAsync(byte[] buffer, int offset, int count, CancellationToken cancellationToken)
|
||||
{
|
||||
if (_mode != CompressionMode.Decompress) throw new BrotliException("Can't read on this stream");
|
||||
|
||||
|
||||
int bytesRead = (int)(_intermediateStream.Length - _readOffset);
|
||||
uint totalCount = 0;
|
||||
Boolean endOfStream = false;
|
||||
Boolean errorDetected = false;
|
||||
while (bytesRead < count)
|
||||
{
|
||||
while (true)
|
||||
{
|
||||
if (_lastDecodeResult == BrotliDecoderResult.NeedsMoreInput)
|
||||
{
|
||||
_availableIn = (UInt32) await _stream.ReadAsync(_managedBuffer, 0, (int)BufferSize).ConfigureAwait(false);
|
||||
_ptrNextInput = _ptrInputBuffer;
|
||||
if (_availableIn <= 0)
|
||||
{
|
||||
endOfStream = true;
|
||||
break;
|
||||
}
|
||||
Marshal.Copy(_managedBuffer, 0, _ptrInputBuffer, (int)_availableIn);
|
||||
}
|
||||
else if (_lastDecodeResult == BrotliDecoderResult.NeedsMoreOutput)
|
||||
{
|
||||
Marshal.Copy(_ptrOutputBuffer, _managedBuffer, 0, BufferSize);
|
||||
await _intermediateStream.WriteAsync(_managedBuffer, 0, BufferSize).ConfigureAwait(false);
|
||||
bytesRead += BufferSize;
|
||||
_availableOut = BufferSize;
|
||||
_ptrNextOutput = _ptrOutputBuffer;
|
||||
}
|
||||
else
|
||||
{
|
||||
//Error or OK
|
||||
endOfStream = true;
|
||||
break;
|
||||
}
|
||||
_lastDecodeResult = Brolib.BrotliDecoderDecompressStream(_state, ref _availableIn, ref _ptrNextInput,
|
||||
ref _availableOut, ref _ptrNextOutput, out totalCount);
|
||||
if (bytesRead >= count) break;
|
||||
}
|
||||
if (endOfStream && !Brolib.BrotliDecoderIsFinished(_state))
|
||||
{
|
||||
errorDetected = true;
|
||||
}
|
||||
|
||||
if (_lastDecodeResult == BrotliDecoderResult.Error || errorDetected)
|
||||
{
|
||||
var error = Brolib.BrotliDecoderGetErrorCode(_state);
|
||||
var text = Brolib.BrotliDecoderErrorString(error);
|
||||
throw new BrotliDecodeException(String.Format("Unable to decode stream,possibly corrupt data.Code={0}({1})", error, text), error, text);
|
||||
}
|
||||
|
||||
if (endOfStream && !Brolib.BrotliDecoderIsFinished(_state) && _lastDecodeResult == BrotliDecoderResult.NeedsMoreInput)
|
||||
{
|
||||
throw new BrotliException("Unable to decode stream,unexpected EOF");
|
||||
}
|
||||
|
||||
if (endOfStream && _ptrNextOutput != _ptrOutputBuffer)
|
||||
{
|
||||
int remainBytes = (int)(_ptrNextOutput.ToInt64() - _ptrOutputBuffer.ToInt64());
|
||||
bytesRead += remainBytes;
|
||||
Marshal.Copy(_ptrOutputBuffer, _managedBuffer, 0, remainBytes);
|
||||
await _intermediateStream.WriteAsync(_managedBuffer, 0, remainBytes).ConfigureAwait(false);
|
||||
_ptrNextOutput = _ptrOutputBuffer;
|
||||
}
|
||||
if (endOfStream) break;
|
||||
}
|
||||
|
||||
if (_intermediateStream.Length - _readOffset >= count || endOfStream)
|
||||
{
|
||||
_intermediateStream.Seek(_readOffset, SeekOrigin.Begin);
|
||||
var bytesToRead = (int)(_intermediateStream.Length - _readOffset);
|
||||
if (bytesToRead > count) bytesToRead = count;
|
||||
await _intermediateStream.ReadAsync(buffer, offset, bytesToRead).ConfigureAwait(false);
|
||||
TruncateBeginning(_intermediateStream, _readOffset + bytesToRead);
|
||||
_readOffset = 0;
|
||||
return bytesToRead;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
public override int Read(byte[] buffer, int offset, int count)
|
||||
{
|
||||
async Task<int> task()
|
||||
{
|
||||
return await ReadAsync(buffer,offset,count).ConfigureAwait(false);
|
||||
|
||||
}
|
||||
return AsyncHelper.RunSync(task);
|
||||
}
|
||||
|
||||
public override long Seek(long offset, SeekOrigin origin)
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
|
||||
public override void SetLength(long value)
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
|
||||
static int totalWrote = 0;
|
||||
|
||||
public override async Task WriteAsync(byte[] buffer, int offset, int count, CancellationToken cancellationToken)
|
||||
{
|
||||
if (_mode != CompressionMode.Compress) throw new BrotliException("Can't write on this stream");
|
||||
totalWrote += count;
|
||||
//Console.WriteLine(String.Format("Write {0} bytes,total={1} bytes.", count, totalWrote));
|
||||
|
||||
UInt32 totalOut = 0;
|
||||
int bytesRemain = count;
|
||||
int currentOffset = offset;
|
||||
|
||||
Boolean compressOK = true;
|
||||
while (bytesRemain > 0)
|
||||
{
|
||||
int copyLen = bytesRemain > BufferSize ? BufferSize : bytesRemain;
|
||||
Marshal.Copy(buffer, currentOffset, _ptrInputBuffer, copyLen);
|
||||
bytesRemain -= copyLen;
|
||||
currentOffset += copyLen;
|
||||
_availableIn = (UInt32)copyLen;
|
||||
_ptrNextInput = _ptrInputBuffer;
|
||||
while (_availableIn > 0)
|
||||
{
|
||||
compressOK = Brolib.BrotliEncoderCompressStream(_state, BrotliEncoderOperation.Process, ref _availableIn, ref _ptrNextInput, ref _availableOut,
|
||||
ref _ptrNextOutput, out totalOut);
|
||||
if (!compressOK) throw new BrotliException("Unable to compress stream");
|
||||
if (_availableOut != BufferSize)
|
||||
{
|
||||
var bytesWrote = (int)(BufferSize - _availableOut);
|
||||
//Byte[] localBuffer = new Byte[bytesWrote];
|
||||
Marshal.Copy(_ptrOutputBuffer, _managedBuffer, 0, bytesWrote);
|
||||
await _stream.WriteAsync(_managedBuffer, 0, bytesWrote).ConfigureAwait(false);
|
||||
_availableOut = BufferSize;
|
||||
_ptrNextOutput = _ptrOutputBuffer;
|
||||
}
|
||||
}
|
||||
if (Brolib.BrotliEncoderIsFinished(_state)) break;
|
||||
}
|
||||
}
|
||||
|
||||
public override void Write(byte[] buffer, int offset, int count)
|
||||
{
|
||||
async Task task()
|
||||
{
|
||||
await WriteAsync(buffer,offset,count).ConfigureAwait(false);
|
||||
|
||||
}
|
||||
AsyncHelper.RunSync(task);
|
||||
}
|
||||
}
|
||||
|
||||
#if NET35
|
||||
/// <summary>
|
||||
/// Improve compability issue on FX35
|
||||
/// </summary>
|
||||
public static class StreamCopyExtension
|
||||
{
|
||||
public static void CopyTo(this Stream source,Stream destination, int bufferSize=4*1024)
|
||||
{
|
||||
if (source==null)
|
||||
{
|
||||
throw new ArgumentNullException(nameof(source));
|
||||
}
|
||||
if (destination==null)
|
||||
{
|
||||
throw new ArgumentNullException(nameof(destination));
|
||||
}
|
||||
if (!source.CanRead)
|
||||
{
|
||||
throw new InvalidOperationException("source stream is not readable");
|
||||
}
|
||||
if (!destination.CanWrite)
|
||||
{
|
||||
throw new InvalidOperationException("destination stream is not writeable");
|
||||
}
|
||||
if (bufferSize<=0)
|
||||
{
|
||||
throw new InvalidOperationException("buffer size should be greate than zero");
|
||||
}
|
||||
|
||||
|
||||
byte[] buffer = new byte[bufferSize];
|
||||
int read;
|
||||
while ((read = source.Read(buffer, 0, buffer.Length)) > 0)
|
||||
destination.Write(buffer, 0, read);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
}
|
||||
@@ -0,0 +1,62 @@
|
||||
using System;
|
||||
using System.Runtime.InteropServices;
|
||||
|
||||
namespace Brotli
|
||||
{
|
||||
class Brolib32
|
||||
{
|
||||
static Brolib32()
|
||||
{
|
||||
var path = LibPathBootStrapper.LibPath;
|
||||
NativeLibraryLoader nl = new NativeLibraryLoader(path);
|
||||
#region set encoder
|
||||
nl.FillDelegate(out BrotliEncoderCreateInstance);
|
||||
nl.FillDelegate(out BrotliEncoderSetParameter);
|
||||
nl.FillDelegate(out BrotliEncoderCompressStream);
|
||||
nl.FillDelegate(out BrotliEncoderIsFinished);
|
||||
nl.FillDelegate(out BrotliEncoderDestroyInstance);
|
||||
nl.FillDelegate(out BrotliEncoderVersion);
|
||||
nl.FillDelegate(out BrotliEncoderVersion);
|
||||
nl.FillDelegate(out BrotliEncoderTakeOutput);
|
||||
#endregion
|
||||
#region set decoder
|
||||
nl.FillDelegate(out BrotliDecoderCreateInstance);
|
||||
nl.FillDelegate(out BrotliDecoderSetParameter);
|
||||
nl.FillDelegate(out BrotliDecoderDecompressStream);
|
||||
nl.FillDelegate(out BrotliDecoderDestroyInstance);
|
||||
nl.FillDelegate(out BrotliDecoderVersion);
|
||||
nl.FillDelegate(out BrotliDecoderIsUsed);
|
||||
nl.FillDelegate(out BrotliDecoderIsFinished);
|
||||
nl.FillDelegate(out BrotliDecoderGetErrorCode);
|
||||
nl.FillDelegate(out BrotliDecoderErrorString);
|
||||
nl.FillDelegate(out BrotliDecoderTakeOutput);
|
||||
#endregion
|
||||
}
|
||||
#region Encoder
|
||||
internal static Delegate32.BrotliEncoderCreateInstanceDelegate BrotliEncoderCreateInstance;
|
||||
internal static Delegate32.BrotliEncoderSetParameterDelegate BrotliEncoderSetParameter;
|
||||
//internal static Delegate32.BrotliEncoderSetCustomDictionaryDelegate BrotliEncoderSetCustomDictionary;
|
||||
internal static Delegate32.BrotliEncoderCompressStreamDelegate BrotliEncoderCompressStream;
|
||||
internal static Delegate32.BrotliEncoderIsFinishedDelegate BrotliEncoderIsFinished;
|
||||
internal static Delegate32.BrotliEncoderDestroyInstanceDelegate BrotliEncoderDestroyInstance;
|
||||
internal static Delegate32.BrotliEncoderVersionDelegate BrotliEncoderVersion;
|
||||
internal static Delegate32.BrotliEncoderTakeOutputDelegate BrotliEncoderTakeOutput;
|
||||
#endregion
|
||||
#region Decoder
|
||||
internal static Delegate32.BrotliDecoderCreateInstanceDelegate BrotliDecoderCreateInstance;
|
||||
internal static Delegate32.BrotliDecoderSetParameter BrotliDecoderSetParameter;
|
||||
//internal static Delegate32.BrotliDecoderSetCustomDictionary BrotliDecoderSetCustomDictionary;
|
||||
internal static Delegate32.BrotliDecoderDecompressStreamDelegate BrotliDecoderDecompressStream;
|
||||
|
||||
internal static Delegate32.BrotliDecoderDestroyInstanceDelegate BrotliDecoderDestroyInstance;
|
||||
|
||||
internal static Delegate32.BrotliDecoderVersionDelegate BrotliDecoderVersion;
|
||||
internal static Delegate32.BrotliDecoderIsUsedDelegate BrotliDecoderIsUsed;
|
||||
internal static Delegate32.BrotliDecoderIsFinishedDelegate BrotliDecoderIsFinished;
|
||||
internal static Delegate32.BrotliDecoderGetErrorCodeDelegate BrotliDecoderGetErrorCode;
|
||||
internal static Delegate32.BrotliDecoderErrorStringDelegate BrotliDecoderErrorString;
|
||||
internal static Delegate32.BrotliDecoderTakeOutputDelegate BrotliDecoderTakeOutput;
|
||||
|
||||
#endregion
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,62 @@
|
||||
using System;
|
||||
using System.Runtime.InteropServices;
|
||||
|
||||
namespace Brotli
|
||||
{
|
||||
class Brolib64
|
||||
{
|
||||
static Brolib64()
|
||||
{
|
||||
var path = LibPathBootStrapper.LibPath;
|
||||
NativeLibraryLoader nl = new NativeLibraryLoader(path);
|
||||
#region set encoder
|
||||
nl.FillDelegate(out BrotliEncoderCreateInstance);
|
||||
nl.FillDelegate(out BrotliEncoderSetParameter);
|
||||
nl.FillDelegate(out BrotliEncoderCompressStream);
|
||||
nl.FillDelegate(out BrotliEncoderIsFinished);
|
||||
nl.FillDelegate(out BrotliEncoderDestroyInstance);
|
||||
nl.FillDelegate(out BrotliEncoderVersion);
|
||||
nl.FillDelegate(out BrotliEncoderVersion);
|
||||
nl.FillDelegate(out BrotliEncoderTakeOutput);
|
||||
#endregion
|
||||
#region set decoder
|
||||
nl.FillDelegate(out BrotliDecoderCreateInstance);
|
||||
nl.FillDelegate(out BrotliDecoderSetParameter);
|
||||
nl.FillDelegate(out BrotliDecoderDecompressStream);
|
||||
nl.FillDelegate(out BrotliDecoderDestroyInstance);
|
||||
nl.FillDelegate(out BrotliDecoderVersion);
|
||||
nl.FillDelegate(out BrotliDecoderIsUsed);
|
||||
nl.FillDelegate(out BrotliDecoderIsFinished);
|
||||
nl.FillDelegate(out BrotliDecoderGetErrorCode);
|
||||
nl.FillDelegate(out BrotliDecoderErrorString);
|
||||
nl.FillDelegate(out BrotliDecoderTakeOutput);
|
||||
#endregion
|
||||
}
|
||||
#region Encoder
|
||||
internal static Delegate64.BrotliEncoderCreateInstanceDelegate BrotliEncoderCreateInstance;
|
||||
internal static Delegate64.BrotliEncoderSetParameterDelegate BrotliEncoderSetParameter;
|
||||
//internal static Delegate64.BrotliEncoderSetCustomDictionaryDelegate BrotliEncoderSetCustomDictionary;
|
||||
internal static Delegate64.BrotliEncoderCompressStreamDelegate BrotliEncoderCompressStream;
|
||||
internal static Delegate64.BrotliEncoderIsFinishedDelegate BrotliEncoderIsFinished;
|
||||
internal static Delegate64.BrotliEncoderDestroyInstanceDelegate BrotliEncoderDestroyInstance;
|
||||
internal static Delegate64.BrotliEncoderVersionDelegate BrotliEncoderVersion;
|
||||
internal static Delegate64.BrotliEncoderTakeOutputDelegate BrotliEncoderTakeOutput;
|
||||
#endregion
|
||||
#region Decoder
|
||||
internal static Delegate64.BrotliDecoderCreateInstanceDelegate BrotliDecoderCreateInstance;
|
||||
internal static Delegate64.BrotliDecoderSetParameter BrotliDecoderSetParameter;
|
||||
//internal static Delegate64.BrotliDecoderSetCustomDictionary BrotliDecoderSetCustomDictionary;
|
||||
internal static Delegate64.BrotliDecoderDecompressStreamDelegate BrotliDecoderDecompressStream;
|
||||
|
||||
internal static Delegate64.BrotliDecoderDestroyInstanceDelegate BrotliDecoderDestroyInstance;
|
||||
|
||||
internal static Delegate64.BrotliDecoderVersionDelegate BrotliDecoderVersion;
|
||||
internal static Delegate64.BrotliDecoderIsUsedDelegate BrotliDecoderIsUsed;
|
||||
internal static Delegate64.BrotliDecoderIsFinishedDelegate BrotliDecoderIsFinished;
|
||||
internal static Delegate64.BrotliDecoderGetErrorCodeDelegate BrotliDecoderGetErrorCode;
|
||||
internal static Delegate64.BrotliDecoderErrorStringDelegate BrotliDecoderErrorString;
|
||||
internal static Delegate64.BrotliDecoderTakeOutputDelegate BrotliDecoderTakeOutput;
|
||||
|
||||
#endregion
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,72 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Runtime.InteropServices;
|
||||
using System.Text;
|
||||
|
||||
namespace Brotli
|
||||
{
|
||||
internal class Delegate32
|
||||
{
|
||||
#region Encoder
|
||||
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
|
||||
internal delegate IntPtr BrotliEncoderCreateInstanceDelegate(IntPtr allocFunc, IntPtr freeFunc, IntPtr opaque);
|
||||
|
||||
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
|
||||
internal delegate bool BrotliEncoderSetParameterDelegate(IntPtr state, BrotliEncoderParameter parameter, UInt32 value);
|
||||
|
||||
//delegate void BrotliEncoderSetCustomDictionary(IntPtr state, UInt32 size, IntPtr dict);
|
||||
|
||||
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
|
||||
internal delegate bool BrotliEncoderCompressStreamDelegate(
|
||||
IntPtr state, BrotliEncoderOperation op, ref UInt32 availableIn,
|
||||
ref IntPtr nextIn, ref UInt32 availableOut, ref IntPtr nextOut, out UInt32 totalOut);
|
||||
|
||||
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
|
||||
internal delegate bool BrotliEncoderIsFinishedDelegate(IntPtr state);
|
||||
|
||||
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
|
||||
internal delegate void BrotliEncoderDestroyInstanceDelegate(IntPtr state);
|
||||
|
||||
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
|
||||
internal delegate UInt32 BrotliEncoderVersionDelegate();
|
||||
|
||||
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
|
||||
internal delegate IntPtr BrotliEncoderTakeOutputDelegate(IntPtr state, ref UInt32 size);
|
||||
#endregion
|
||||
#region Decoder
|
||||
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
|
||||
internal delegate IntPtr BrotliDecoderCreateInstanceDelegate(IntPtr allocFunc, IntPtr freeFunc, IntPtr opaque);
|
||||
|
||||
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
|
||||
internal delegate bool BrotliDecoderSetParameter(IntPtr state, BrotliDecoderParameter param, UInt32 value);
|
||||
//delegate void BrotliDecoderSetCustomDictionary(IntPtr state, UInt32 size, IntPtr dict);
|
||||
|
||||
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
|
||||
internal delegate BrotliDecoderResult BrotliDecoderDecompressStreamDelegate(
|
||||
IntPtr state, ref UInt32 availableIn, ref IntPtr nextIn,
|
||||
ref UInt32 availableOut, ref IntPtr nextOut, out UInt32 totalOut);
|
||||
|
||||
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
|
||||
internal delegate void BrotliDecoderDestroyInstanceDelegate(IntPtr state);
|
||||
|
||||
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
|
||||
internal delegate UInt32 BrotliDecoderVersionDelegate();
|
||||
|
||||
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
|
||||
internal delegate bool BrotliDecoderIsUsedDelegate(IntPtr state);
|
||||
|
||||
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
|
||||
internal delegate bool BrotliDecoderIsFinishedDelegate(IntPtr state);
|
||||
|
||||
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
|
||||
internal delegate Int32 BrotliDecoderGetErrorCodeDelegate(IntPtr state);
|
||||
|
||||
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
|
||||
internal delegate IntPtr BrotliDecoderErrorStringDelegate(Int32 code);
|
||||
|
||||
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
|
||||
internal delegate IntPtr BrotliDecoderTakeOutputDelegate(IntPtr state, ref UInt32 size);
|
||||
|
||||
#endregion
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,73 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Runtime.InteropServices;
|
||||
using System.Text;
|
||||
|
||||
namespace Brotli
|
||||
{
|
||||
internal class Delegate64
|
||||
{
|
||||
#region Encoder
|
||||
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
|
||||
internal delegate IntPtr BrotliEncoderCreateInstanceDelegate(IntPtr allocFunc, IntPtr freeFunc, IntPtr opaque);
|
||||
|
||||
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
|
||||
internal delegate bool BrotliEncoderSetParameterDelegate(IntPtr state, BrotliEncoderParameter parameter, UInt32 value);
|
||||
|
||||
//delegate void BrotliEncoderSetCustomDictionary(IntPtr state, UInt32 size, IntPtr dict);
|
||||
|
||||
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
|
||||
internal delegate bool BrotliEncoderCompressStreamDelegate(
|
||||
IntPtr state, BrotliEncoderOperation op, ref UInt64 availableIn,
|
||||
ref IntPtr nextIn, ref UInt64 availableOut, ref IntPtr nextOut, out UInt64 totalOut);
|
||||
|
||||
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
|
||||
internal delegate bool BrotliEncoderIsFinishedDelegate(IntPtr state);
|
||||
|
||||
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
|
||||
internal delegate void BrotliEncoderDestroyInstanceDelegate(IntPtr state);
|
||||
|
||||
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
|
||||
internal delegate UInt32 BrotliEncoderVersionDelegate();
|
||||
|
||||
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
|
||||
internal delegate IntPtr BrotliEncoderTakeOutputDelegate(IntPtr state, ref UInt64 size);
|
||||
|
||||
#endregion
|
||||
#region Decoder
|
||||
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
|
||||
internal delegate IntPtr BrotliDecoderCreateInstanceDelegate(IntPtr allocFunc, IntPtr freeFunc, IntPtr opaque);
|
||||
|
||||
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
|
||||
internal delegate bool BrotliDecoderSetParameter(IntPtr state, BrotliDecoderParameter param, UInt32 value);
|
||||
//delegate void BrotliDecoderSetCustomDictionary(IntPtr state, UInt64 size, IntPtr dict);
|
||||
|
||||
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
|
||||
internal delegate BrotliDecoderResult BrotliDecoderDecompressStreamDelegate(
|
||||
IntPtr state, ref UInt64 availableIn, ref IntPtr nextIn,
|
||||
ref UInt64 availableOut, ref IntPtr nextOut, out UInt64 totalOut);
|
||||
|
||||
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
|
||||
internal delegate void BrotliDecoderDestroyInstanceDelegate(IntPtr state);
|
||||
|
||||
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
|
||||
internal delegate UInt32 BrotliDecoderVersionDelegate();
|
||||
|
||||
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
|
||||
internal delegate bool BrotliDecoderIsUsedDelegate(IntPtr state);
|
||||
|
||||
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
|
||||
internal delegate bool BrotliDecoderIsFinishedDelegate(IntPtr state);
|
||||
|
||||
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
|
||||
internal delegate Int32 BrotliDecoderGetErrorCodeDelegate(IntPtr state);
|
||||
|
||||
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
|
||||
internal delegate IntPtr BrotliDecoderErrorStringDelegate(Int32 code);
|
||||
|
||||
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
|
||||
internal delegate IntPtr BrotliDecoderTakeOutputDelegate(IntPtr state, ref UInt64 size);
|
||||
|
||||
#endregion
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,62 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Reflection;
|
||||
using System.Text;
|
||||
|
||||
namespace Brotli
|
||||
{
|
||||
internal class LibPathBootStrapper
|
||||
{
|
||||
internal static string LibPath { get; private set; }
|
||||
|
||||
static LibPathBootStrapper()
|
||||
{
|
||||
|
||||
|
||||
string fileName = null;
|
||||
if (NativeLibraryLoader.IsWindows)
|
||||
{
|
||||
if (NativeLibraryLoader.Is64Bit)
|
||||
{
|
||||
fileName = "brolib_x64.dll";
|
||||
}
|
||||
else
|
||||
{
|
||||
fileName = "brolib_x86.dll";
|
||||
}
|
||||
} else if (NativeLibraryLoader.IsLinux)
|
||||
{
|
||||
if (NativeLibraryLoader.Is64Bit)
|
||||
{
|
||||
fileName = "brolib_x64.so";
|
||||
}
|
||||
else
|
||||
{
|
||||
fileName = "brolib_x86.so";
|
||||
}
|
||||
} else if (NativeLibraryLoader.IsMacOSX)
|
||||
{
|
||||
if (NativeLibraryLoader.Is64Bit)
|
||||
{
|
||||
fileName = "brolib_x64.dylib";
|
||||
}
|
||||
}
|
||||
if (string.IsNullOrEmpty(fileName)) throw new NotSupportedException($"OS not supported:{Environment.OSVersion.ToString()}");
|
||||
var paths = NativeLibraryLoader.GetPossibleRuntimeDirectories();
|
||||
var libFound = false;
|
||||
foreach(var path in paths)
|
||||
{
|
||||
var fullPath = Path.Combine(path, fileName);
|
||||
if (System.IO.File.Exists(fullPath))
|
||||
{
|
||||
LibPath = fullPath;
|
||||
libFound = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (!libFound) throw new NotSupportedException($"Unable to find library {fileName}");
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,234 @@
|
||||
using System;
|
||||
using System.Linq;
|
||||
using System.Collections.Generic;
|
||||
using System.Diagnostics;
|
||||
using System.IO;
|
||||
using System.Reflection;
|
||||
using System.Runtime.InteropServices;
|
||||
using System.Text;
|
||||
|
||||
namespace Brotli
|
||||
{
|
||||
internal class NativeLibraryLoader
|
||||
{
|
||||
internal static bool IsWindows = false;
|
||||
internal static bool IsLinux = false;
|
||||
internal static bool IsMacOSX = false;
|
||||
internal static bool IsNetCore = false;
|
||||
internal static bool Is64Bit = false;
|
||||
static NativeLibraryLoader()
|
||||
{
|
||||
#if NET35 || NET40
|
||||
IsWindows=true;
|
||||
#else
|
||||
IsWindows = RuntimeInformation.IsOSPlatform(OSPlatform.Windows);
|
||||
IsLinux = RuntimeInformation.IsOSPlatform(OSPlatform.Linux);
|
||||
IsMacOSX = RuntimeInformation.IsOSPlatform(OSPlatform.OSX);
|
||||
IsNetCore = RuntimeInformation.FrameworkDescription.StartsWith(".NET Core");
|
||||
#endif
|
||||
if (!IsWindows && !IsLinux && !IsMacOSX)
|
||||
{
|
||||
throw new InvalidOperationException("Unsupported platform.");
|
||||
}
|
||||
Is64Bit = IntPtr.Size == 8;
|
||||
}
|
||||
|
||||
// dlopen flags
|
||||
const int RtldLazy = 1;
|
||||
const int RtldGlobal = 8;
|
||||
|
||||
readonly string _libraryPath;
|
||||
internal IntPtr Handle { get; private set; }
|
||||
|
||||
internal NativeLibraryLoader(string libraryPath)
|
||||
{
|
||||
_libraryPath = libraryPath;
|
||||
Handle = LoadLibrary(_libraryPath, out var errorMsg);
|
||||
if (!String.IsNullOrEmpty(errorMsg))
|
||||
{
|
||||
throw new BrotliException($"unable to load library {libraryPath}");
|
||||
}
|
||||
}
|
||||
|
||||
public static IntPtr GetWin32ModuleHandle(String moduleName)
|
||||
{
|
||||
IntPtr r = IntPtr.Zero;
|
||||
foreach (ProcessModule mod in Process.GetCurrentProcess().Modules)
|
||||
{
|
||||
if (mod.ModuleName == moduleName)
|
||||
{
|
||||
r = mod.BaseAddress;
|
||||
break;
|
||||
}
|
||||
}
|
||||
return r;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Loads method in the library
|
||||
/// </summary>
|
||||
/// <param name="symbolName">The methold of the library</param>
|
||||
/// <returns>method address</returns>
|
||||
private IntPtr LoadSymbol(string symbolName)
|
||||
{
|
||||
if (IsWindows)
|
||||
{
|
||||
return WindowsLoader.GetProcAddress(Handle, symbolName);
|
||||
}
|
||||
if (IsLinux)
|
||||
{
|
||||
|
||||
if (IsNetCore)
|
||||
{
|
||||
return CoreCLRLoader.dlsym(Handle, symbolName);
|
||||
}
|
||||
return LinuxLoader.dlsym(Handle, symbolName);
|
||||
}
|
||||
if (IsMacOSX)
|
||||
{
|
||||
return MacOSXLoader.dlsym(Handle, symbolName);
|
||||
}
|
||||
throw new InvalidOperationException("Unsupported platform.");
|
||||
}
|
||||
|
||||
public void FillDelegate<T>(out T delegateType) where T : class
|
||||
{
|
||||
var typeName = typeof(T).Name;
|
||||
var kt = "Delegate";
|
||||
if (typeName.EndsWith(kt))
|
||||
{
|
||||
typeName = typeName.Substring(0, typeName.Length - kt.Length);
|
||||
}
|
||||
delegateType = GetNativeMethodDelegate<T>(typeName);
|
||||
}
|
||||
|
||||
|
||||
public T GetNativeMethodDelegate<T>(string methodName) where T : class
|
||||
{
|
||||
var ptr = LoadSymbol(methodName);
|
||||
if (ptr == IntPtr.Zero)
|
||||
{
|
||||
throw new MissingMethodException(string.Format("The native method \"{0}\" does not exist", methodName));
|
||||
}
|
||||
|
||||
return Marshal.GetDelegateForFunctionPointer(ptr, typeof(T)) as T; // generic version not available in .NET45
|
||||
}
|
||||
|
||||
internal static string[] GetPossibleRuntimeDirectories()
|
||||
{
|
||||
#if NET35 || NET40
|
||||
var assemblyDirectory = Path.GetDirectoryName(typeof(LibPathBootStrapper).Assembly.Location);
|
||||
#else
|
||||
var assemblyDirectory = Path.GetDirectoryName(typeof(LibPathBootStrapper).GetTypeInfo().Assembly.Location);
|
||||
#endif
|
||||
//var platform = "win";
|
||||
//if (IsLinux)
|
||||
//{
|
||||
// platform= "linux";
|
||||
//}
|
||||
//if (IsMacOSX)
|
||||
//{
|
||||
// platform= "osx";
|
||||
//}
|
||||
//string runtimesDirectory = string.Format("runtimes/{0}/native", platform);
|
||||
string runtimesDirectory;
|
||||
if (Is64Bit)
|
||||
{
|
||||
runtimesDirectory = "x64"; // string.Format("x64/{0}", platform);
|
||||
}
|
||||
else
|
||||
{
|
||||
runtimesDirectory = "x86"; // string.Format("x86/{0}", platform);
|
||||
}
|
||||
|
||||
string runtimesFullDirectory = Path.Combine(assemblyDirectory,runtimesDirectory);
|
||||
var iisBaseDirectory = $"{AppDomain.CurrentDomain.BaseDirectory}bin/{runtimesDirectory}";
|
||||
var execAssemblyDirectory= System.IO.Path.GetDirectoryName(System.Reflection.Assembly.GetExecutingAssembly().GetName().CodeBase).Replace("file:\\","")+"/"+ runtimesDirectory;
|
||||
#if NET35
|
||||
var netCoreAppStyleDirectory = Path.Combine(Path.Combine(assemblyDirectory, "../.."), runtimesDirectory);
|
||||
#else
|
||||
var netCoreAppStyleDirectory = Path.Combine(assemblyDirectory, "../..", runtimesDirectory);
|
||||
#endif
|
||||
string[] paths = new[] { assemblyDirectory, runtimesFullDirectory, runtimesDirectory, netCoreAppStyleDirectory,iisBaseDirectory,execAssemblyDirectory };
|
||||
paths = paths.Select(v => v.Replace('/', Path.DirectorySeparatorChar)).ToArray();
|
||||
return paths;
|
||||
}
|
||||
|
||||
internal static bool FreeLibrary(IntPtr handle)
|
||||
{
|
||||
string errorMsg = null;
|
||||
if (IsWindows)
|
||||
{
|
||||
return WindowsLoader.FreeLibrary(handle);
|
||||
}
|
||||
if (IsLinux)
|
||||
{
|
||||
if (IsNetCore)
|
||||
{
|
||||
return UnloadLibraryPosix(CoreCLRLoader.dlclose, CoreCLRLoader.dlerror, handle, out errorMsg);
|
||||
}
|
||||
return UnloadLibraryPosix(LinuxLoader.dlclose, LinuxLoader.dlerror, handle, out errorMsg);
|
||||
}
|
||||
if (IsMacOSX)
|
||||
{
|
||||
return UnloadLibraryPosix(MacOSXLoader.dlclose, MacOSXLoader.dlerror, handle, out errorMsg);
|
||||
}
|
||||
throw new InvalidOperationException("Unsupported platform.");
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Load library
|
||||
/// </summary>
|
||||
internal static IntPtr LoadLibrary(string libraryPath, out string errorMsg)
|
||||
{
|
||||
if (IsWindows)
|
||||
{
|
||||
errorMsg = null;
|
||||
//var handle = GetWin32ModuleHandle(libraryPath);
|
||||
//if (handle != IntPtr.Zero) return handle;
|
||||
var handle= WindowsLoader.LoadLibrary(libraryPath);
|
||||
if (handle== IntPtr.Zero)
|
||||
{
|
||||
throw new System.ComponentModel.Win32Exception($"failed to load library {libraryPath}");
|
||||
}
|
||||
return handle;
|
||||
}
|
||||
if (IsLinux)
|
||||
{
|
||||
if (IsNetCore)
|
||||
{
|
||||
return LoadLibraryPosix(CoreCLRLoader.dlopen, CoreCLRLoader.dlerror, libraryPath, out errorMsg);
|
||||
}
|
||||
return LoadLibraryPosix(LinuxLoader.dlopen, LinuxLoader.dlerror, libraryPath, out errorMsg);
|
||||
}
|
||||
if (IsMacOSX)
|
||||
{
|
||||
return LoadLibraryPosix(MacOSXLoader.dlopen, MacOSXLoader.dlerror, libraryPath, out errorMsg);
|
||||
}
|
||||
throw new InvalidOperationException("Unsupported platform.");
|
||||
}
|
||||
|
||||
static IntPtr LoadLibraryPosix(Func<string, int, IntPtr> dlopenFunc, Func<IntPtr> dlerrorFunc, string libraryPath, out string errorMsg)
|
||||
{
|
||||
errorMsg = null;
|
||||
IntPtr ret = dlopenFunc(libraryPath, RtldGlobal + RtldLazy);
|
||||
if (ret == IntPtr.Zero)
|
||||
{
|
||||
errorMsg = Marshal.PtrToStringAnsi(dlerrorFunc());
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
static bool UnloadLibraryPosix(Func<IntPtr,int> dlcloseFunc, Func<IntPtr> dlerrorFunc, IntPtr handle,out string errorMsg)
|
||||
{
|
||||
errorMsg = null;
|
||||
var r = dlcloseFunc(handle);
|
||||
if (r!=0)
|
||||
{
|
||||
errorMsg= Marshal.PtrToStringAnsi(dlerrorFunc());
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,72 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Runtime.InteropServices;
|
||||
using System.Text;
|
||||
|
||||
namespace Brotli
|
||||
{
|
||||
|
||||
static class WindowsLoader
|
||||
{
|
||||
[DllImport("kernel32.dll", CharSet = CharSet.Unicode, SetLastError = true)]
|
||||
public static extern IntPtr LoadLibrary(string dllFilePath);
|
||||
|
||||
[DllImport("kernel32.dll", CharSet = CharSet.Ansi, SetLastError = true)]
|
||||
public static extern IntPtr GetProcAddress(IntPtr hModule, string procedureName);
|
||||
|
||||
[DllImport("kernel32.dll")]
|
||||
public static extern bool FreeLibrary(IntPtr hModule);
|
||||
}
|
||||
|
||||
static class LinuxLoader
|
||||
{
|
||||
[DllImport("libdl.so")]
|
||||
internal static extern IntPtr dlopen(string filename, int flags);
|
||||
|
||||
[DllImport("libdl.so")]
|
||||
internal static extern IntPtr dlerror();
|
||||
|
||||
[DllImport("libdl.so")]
|
||||
internal static extern IntPtr dlsym(IntPtr handle, string symbol);
|
||||
|
||||
[DllImport("libdl.so")]
|
||||
internal static extern int dlclose(IntPtr handle);
|
||||
}
|
||||
|
||||
static class MacOSXLoader
|
||||
{
|
||||
[DllImport("libSystem.dylib")]
|
||||
internal static extern IntPtr dlopen(string filename, int flags);
|
||||
|
||||
[DllImport("libSystem.dylib")]
|
||||
internal static extern IntPtr dlerror();
|
||||
|
||||
[DllImport("libSystem.dylib")]
|
||||
internal static extern IntPtr dlsym(IntPtr handle, string symbol);
|
||||
|
||||
[DllImport("libSystem.dylib")]
|
||||
internal static extern int dlclose(IntPtr handle);
|
||||
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Similarly as for Mono on Linux, we load symbols for
|
||||
/// dlopen and dlsym from the "libcoreclr.so",
|
||||
/// to avoid the dependency on libc-dev Linux.
|
||||
/// </summary>
|
||||
static class CoreCLRLoader
|
||||
{
|
||||
[DllImport("libcoreclr.so")]
|
||||
internal static extern IntPtr dlopen(string filename, int flags);
|
||||
|
||||
[DllImport("libcoreclr.so")]
|
||||
internal static extern IntPtr dlerror();
|
||||
|
||||
[DllImport("libcoreclr.so")]
|
||||
internal static extern IntPtr dlsym(IntPtr handle, string symbol);
|
||||
|
||||
[DllImport("libcoreclr.so")]
|
||||
internal static extern int dlclose(IntPtr handle);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,16 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<Project xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
|
||||
<ItemGroup>
|
||||
<NativeLibs Include="$(MSBuildThisFileDirectory)..\runtimes\**\*.*" />
|
||||
<None Include="@(NativeLibs)">
|
||||
<Link>%(RecursiveDir)%(FileName)%(Extension)</Link>
|
||||
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
||||
</None>
|
||||
</ItemGroup>
|
||||
<!--
|
||||
<NativePdbs Include="$(MSBuildThisFileDirectory)..\runtimes\**\*.pdb" />
|
||||
<None Include="@(NativePdbs)" Condition="$([System.Text.RegularExpressions.Regex]::IsMatch('$(AllowedReferenceRelatedFileExtensions)', '\.pdb'))">
|
||||
<Link>%(RecursiveDir)%(FileName)%(Extension)</Link>
|
||||
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
||||
</None> -->
|
||||
</Project>
|
||||
Binary file not shown.
Binary file not shown.
-238
@@ -1,238 +0,0 @@
|
||||
# 更新日志
|
||||
|
||||
## `2023/12/10` v1.6.1
|
||||
|
||||
* [优化] 如果存在下载完成列表,弹出选择框是否再次下载。
|
||||
* [修复] 更新wbi签名算法,解决无法解析下载视频的问题。
|
||||
|
||||
## `2023/12/09` v1.6.0
|
||||
|
||||
* [优化] 下载列表弹出框。
|
||||
* [优化] 添加任务栏图标。
|
||||
* [优化] 视频流API、视频详细信息API。
|
||||
* [修复] 文件名导致的闪退问题。
|
||||
* [修复] 程序反复读取设置文件的问题。
|
||||
* [修复] 修复扫码登录的问题。
|
||||
* [修复] 在下载设置窗口界面取消或关闭窗口之后导致的DownKyi闪退问题 #907。
|
||||
|
||||
## `2023/05/24` v1.5.9
|
||||
|
||||
* [新增] 下载完成系统提示。
|
||||
* [修复] UP主个人空间访问。
|
||||
|
||||
## `2023/04/30` v1.5.8
|
||||
|
||||
* [新增] 视频详情页搜索功能。
|
||||
* [优化] 确认下载路径之前检查盘符是否存在。
|
||||
* [优化] 弹出框的UI。
|
||||
* [优化] 音质描述【普通音质有3档质量,但不是固定的320K或192K,因此仅用高中低表述,以免产生误解】。
|
||||
* [修复] 下载管理在只下载音频的情况下点击打开文件夹无响应。
|
||||
* [修复] 解决tabId溢出的问题。
|
||||
|
||||
## `2023/02/18` v1.5.7
|
||||
|
||||
* [新增] 自定义UserAgent。
|
||||
* [新增] 程序检查更新。
|
||||
* [优化] 下载前检测无效的下载目录。
|
||||
* [优化] 更新依赖版本。
|
||||
* [优化] 输出Aria2错误信息到UI。
|
||||
* [修复] 默认编码为AVC,但画质为杜比视界时,不会自动选中HEVC编码的问题。
|
||||
* [修复] 删除下载项时内建下载器崩溃的问题。
|
||||
|
||||
## `2023/01/06` v1.5.6
|
||||
|
||||
* [修复] 文件名包含非法字符。
|
||||
* [修复] 多线程下载的bug。
|
||||
* [修复] 弹幕无法下载的bug。
|
||||
|
||||
## `2022/11/06` v1.5.5
|
||||
|
||||
* [优化] 更新分区列表。
|
||||
* [优化] 更新依赖包。
|
||||
* [新增] 关注和粉丝页面。
|
||||
* [修复] 命名格式无AV1编码的问题。
|
||||
* [修复] 优先解析视频编码顺序为AV1、HEVC、AVC。
|
||||
* [修复] 自定义aria服务器监听端口设置无效的问题。
|
||||
|
||||
## `2022/10/16` v1.5.4
|
||||
|
||||
* [新增] 支持AV1编码视频。
|
||||
* [新增] 支持Hi-Res无损音频格式。
|
||||
* [新增] 支持UP主用户空间的合集和列表。
|
||||
* [新增] 支持自定义aria服务器。
|
||||
* [新增] 音视频分离支持多选。
|
||||
* [修复] 视频无杜比视界时支持杜比全景声。
|
||||
|
||||
## `2022/06/05` v1.5.3
|
||||
|
||||
* [优化] 封面命名。
|
||||
* [新增] 启用https控制。
|
||||
* [新增] 支持出行分区。
|
||||
* [新增] 下载管理页面入口。
|
||||
* [修复] 批量操作时偶尔崩溃的问题。
|
||||
* [修复] 监听剪贴板失效的问题。
|
||||
|
||||
## `2022/05/09` v1.5.2
|
||||
|
||||
* [优化] 更新依赖版本。
|
||||
* [新增] 内建下载器。
|
||||
* [新增] 下载器切换设置。
|
||||
* [修复] 问题 SSL/TLS handshake failure。
|
||||
|
||||
---
|
||||
|
||||
* `2022/05/09` v1.5.1
|
||||
1. [优化] 当复制视频详情页的输入框中的字符时,不读取剪贴板内容。
|
||||
2. [优化] Aria下载器添加header。
|
||||
3. [新增] 向下载管理页面添加弹窗提示。
|
||||
4. [新增] 文件命名模块中序号格式设置。
|
||||
5. [新增] 支持WebP图像。
|
||||
6. [修复] 未获取到杜比全景声却仍然显示出此选项的问题。
|
||||
7. [修复] 运动分区无法显示的问题。
|
||||
8. [修复] 文件名异常导致的下载失败。
|
||||
9. [修复] 偶尔VideoSection重复的问题。
|
||||
|
||||
* `2022/04/04` v1.5.0
|
||||
1. [优化] 跳过数据库中的不完整数据。
|
||||
2. [优化] 文件命名格式设置支持拖拽。
|
||||
3. [修复] 下载完成后的动作设置无效的问题。
|
||||
4. [修复] 视频BV1rr4y1i74o无法加载的问题。
|
||||
5. [修复] 下载内容设置偶尔不生效的问题。
|
||||
|
||||
* `2022/03/26` v1.5.0-alpha7
|
||||
1. [优化] 批量下载时过滤UGC、其他季或花絮内容。
|
||||
2. [优化] 保存下载视频内容到设置。
|
||||
3. [优化] 更新ffmpeg为gpl版本。
|
||||
4. [优化] 默认的aria的文件预分配改为NONE。
|
||||
5. [新增] “解析后自动下载已解析视频”设置。
|
||||
6. [修复] 只下载音频失败的问题。
|
||||
7. [修复] Settings被占用无法读取的问题。
|
||||
8. [修复] 因路径导致无法下载的问题。
|
||||
9. [修复] 无法正确关闭数据库的问题。
|
||||
|
||||
* `2022/03/20` v1.5.0-alpha6
|
||||
1. [修复] 一些已知问题。
|
||||
|
||||
* `2022/03/19` v1.5.0-alpha5
|
||||
1. [优化] 文件命名格式中,时间格式可设置。
|
||||
2. [修复] 数据库异常锁定的问题。
|
||||
3. [修复] 视频标题和分P标题相同时找不到下载文件的问题。
|
||||
4. [修复] 150%缩放下的窗口不超出屏幕。
|
||||
5. [修复] 其他已知问题。
|
||||
|
||||
* `2022/03/13` v1.5.0-alpha4
|
||||
1. [优化] 配置文件目录改为当前程序目录。
|
||||
2. [修复] 部分UI显示。
|
||||
3. [修复] 因数据库中的重复内容导致的闪退问题。
|
||||
4. [修复] 其他已知问题。
|
||||
|
||||
* `2022/03/12` v1.5.0-alpha3
|
||||
1. [修复] 当用户性别为保密时,程序闪退的问题。
|
||||
2. [修复] 批量下载UP主视频时,程序偶尔闪退的问题。
|
||||
3. [修复] 其他已知问题。
|
||||
|
||||
* `2022/03/07` v1.5.0-alpha2
|
||||
1. [优化] 重构程序架构,解决一些已知问题。
|
||||
2. [优化] 界面UI的显示与操作。
|
||||
3. [新增] 文件命名格式:avid、bvid、cid、UP主信息、视频发布时间。
|
||||
4. [修复] 视频音质列表导致的闪退问题。
|
||||
5. [修复] 图片下载导致的闪退问题。
|
||||
|
||||
* `2022/03/05` v1.5.0-alpha1
|
||||
1. [优化] 重构程序架构,解决一些已知问题。
|
||||
2. [新增] 最高支持8K视频。
|
||||
3. [新增] 支持杜比全景声和杜比视界。
|
||||
4. [新增] 支持字幕下载。
|
||||
5. [新增] 支持部分短链接(如 <https://b23.tv/BV17x411w7KC> )。
|
||||
6. [新增] 下载内容可选,可根据需要选择下载视频、音频、弹幕、字幕、封面。
|
||||
7. [新增] 下载文件命名模块,可自主设置文件名。
|
||||
|
||||
* `2021/06/12` v1.4.0
|
||||
1. [修复] 视频无封面时崩溃的问题。
|
||||
2. [优化] 视频分区代码与图标。
|
||||
3. [优化] 屏蔽频道中的失效视频。
|
||||
4. [优化] 二维码登录逻辑。
|
||||
5. [新增] 弹幕下载(借鉴并重写于项目 [niconvert](https://github.com/muzuiget/niconvert))。
|
||||
6. [新增] 弹幕样式设置。
|
||||
7. [新增] 下载弹幕、下载封面的选项。
|
||||
|
||||
* `2021/04/27` v1.3.8
|
||||
1. [修复] FLV视频只有1个分段时下载失败的问题。
|
||||
2. [修复] UP主视频页面闪退的问题。
|
||||
3. [修复] 电视剧图标丢失的问题。
|
||||
4. [新增] UP主视频页面下载全部视频的按钮。
|
||||
|
||||
* `2021/03/28` v1.3.7
|
||||
1. [修复] 播放数为空白的视频存在时,整页视频列表无法加载的问题。
|
||||
2. [修复] 特殊字符(控制字符、末尾空格等)导致的下载失败。
|
||||
3. [修复] 由于某些封面图片metadata损坏导致的程序崩溃。
|
||||
4. [修复] 监听剪贴板数据异常报错的问题。
|
||||
5. [优化] 部分界面显示。
|
||||
6. [优化] 程序逻辑。
|
||||
7. [新增] 监听剪贴板和自动解析的设置持久化。
|
||||
8. [新增] 列表支持shift&ctrl多选。
|
||||
9. [新增] 下载中列表重试按钮。
|
||||
|
||||
* `2021/03/04` v1.3.6
|
||||
1. [修复] 下载FLV时失败的问题。
|
||||
2. [修复] 主页的登录信息更新不及时的问题。
|
||||
3. [优化] 主页下方按钮居中。
|
||||
4. [优化] 首页搜索框添加搜索按钮,点击可进行搜索。
|
||||
5. [新增] 监听剪贴板。
|
||||
6. [新增] 已下载视频列表排序。
|
||||
7. [新增] 下载管理页面增加全部暂停、全部开始、全部删除。
|
||||
|
||||
* `2021/02/21` v1.3.5
|
||||
1. [修复] 分P标题相同时会下载失败的问题。
|
||||
2. [修复] 个人空间中的头像可能显示不全的问题。
|
||||
3. [优化] 订阅页面采用分页显示。
|
||||
4. [优化] 增强程序健壮性。
|
||||
5. [优化] 部分界面UI。
|
||||
6. [优化] 视频详情页获取视频后不自动解析下载链接。
|
||||
7. [新增] 视频详情页“自动解析”选项,“解析视频”按钮,列表右键菜单“解析”。
|
||||
8. [新增] 视频详情页支持输入av号和BV号。
|
||||
9. [新增] 视频详情页的UP主头像增加进入用户空间的入口。
|
||||
10. [新增] 历史记录和稍后再看的up主头像增加进入用户空间的入口。
|
||||
|
||||
* `2021/02/10` v1.3.4
|
||||
1. [修复] 修复在未登录时进入UP主用户空间,程序崩溃的问题。
|
||||
2. [优化] 更新视频分区。
|
||||
3. [优化] 视频数为0的频道不显示。
|
||||
4. [优化] 部分界面UI。
|
||||
|
||||
* `2021/01/30` v1.3.3
|
||||
1. [修复] 输入avid和bvid可能无法解析的问题。
|
||||
2. [优化] 程序的一些显示。
|
||||
3. [优化] 程序核心代码结构。
|
||||
4. [新增] 访问用户空间。
|
||||
5. [新增] UP主投稿视频列表展示。
|
||||
6. [新增] UP主频道列表展示。
|
||||
7. [新增] 意见反馈入口,将进入github的issue页。
|
||||
|
||||
* `2021/01/05` v1.3.2 beta
|
||||
1. [修复] 向Aria添加下载时参数错误问题。
|
||||
2. [修复] 分P标题为空时,标题为总标题+数字。
|
||||
3. [优化] 更新视频分区。
|
||||
4. [优化] 文件夹、订阅、稍后再看的健壮性。
|
||||
|
||||
* `2021/01/01` v1.3.1 beta
|
||||
1. [修复] Aria2c下载时出现503错误的问题。
|
||||
2. [修复] 选择文件夹时,若取消选择仍然会添加到下载的问题。
|
||||
3. [修复] 标题中含有转义字符时的问题。
|
||||
4. [修复] 其他已知问题。
|
||||
5. [优化] 启动时先杀死以开启的Aria2c进程。
|
||||
6. [优化] 关于页面添加github链接。
|
||||
|
||||
* `2020/12/26` v1.3.0 beta
|
||||
1. [新增] 使用Aria下载器。
|
||||
2. [新增] 暂停、继续、删除下载项功能。
|
||||
3. [新增] 下载时自动下载视频封面。
|
||||
4. [新增] B站助手工具,包括av与bv互转,弹幕发送者查询。
|
||||
5. [优化] 工具箱页面的按钮的样式。
|
||||
6. [优化] 更新QRCoder版本到1.4.1。
|
||||
7. [新增] 在视频详情页添加解析后自动下载所有选项。
|
||||
8. [新增] 支持avid和bvid输入。
|
||||
9. [修复] 在没有解析完网址的时候粘贴新的网址会出现闪退的问题。
|
||||
10. [优化] 下载管理上方控制面板是否显示根据已下载视频数量动态变化。
|
||||
11. [新增] 下载列表的历史记录,重启程序后恢复下载。
|
||||
12. [新增] 视频详情页的封面增加右键菜单:复制封面图片、复制封面url。
|
||||
@@ -0,0 +1,9 @@
|
||||
<prism:PrismApplication x:Class="DatabaseManager.App"
|
||||
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
|
||||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||
xmlns:prism="http://prismlibrary.com/"
|
||||
xmlns:local="clr-namespace:DatabaseManager">
|
||||
<Application.Resources>
|
||||
|
||||
</Application.Resources>
|
||||
</prism:PrismApplication>
|
||||
@@ -0,0 +1,23 @@
|
||||
using DatabaseManager.Views;
|
||||
using Prism.Ioc;
|
||||
using System.Windows;
|
||||
|
||||
namespace DatabaseManager
|
||||
{
|
||||
/// <summary>
|
||||
/// Interaction logic for App.xaml
|
||||
/// </summary>
|
||||
public partial class App
|
||||
{
|
||||
protected override Window CreateShell()
|
||||
{
|
||||
return Container.Resolve<MainWindow>();
|
||||
}
|
||||
|
||||
protected override void RegisterTypes(IContainerRegistry containerRegistry)
|
||||
{
|
||||
containerRegistry.RegisterForNavigation<ViewCover>("Cover");
|
||||
containerRegistry.RegisterForNavigation<ViewHeader>("Header");
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,142 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<Project ToolsVersion="15.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
|
||||
<Import Project="$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props" Condition="Exists('$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props')" />
|
||||
<PropertyGroup>
|
||||
<Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
|
||||
<Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
|
||||
<ProjectGuid>{95F12C16-86B5-43D5-AF3E-D2489E2DB239}</ProjectGuid>
|
||||
<OutputType>WinExe</OutputType>
|
||||
<AppDesignerFolder>Properties</AppDesignerFolder>
|
||||
<RootNamespace>DatabaseManager</RootNamespace>
|
||||
<AssemblyName>DatabaseManager</AssemblyName>
|
||||
<TargetFrameworkVersion>v4.7.2</TargetFrameworkVersion>
|
||||
<FileAlignment>512</FileAlignment>
|
||||
<ProjectTypeGuids>{60dc8134-eba5-43b8-bcc9-bb4bc16c2548};{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}</ProjectTypeGuids>
|
||||
<WarningLevel>4</WarningLevel>
|
||||
<AutoGenerateBindingRedirects>true</AutoGenerateBindingRedirects>
|
||||
<RestoreProjectStyle>PackageReference</RestoreProjectStyle>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
|
||||
<PlatformTarget>AnyCPU</PlatformTarget>
|
||||
<DebugSymbols>true</DebugSymbols>
|
||||
<DebugType>full</DebugType>
|
||||
<Optimize>false</Optimize>
|
||||
<OutputPath>bin\Debug\</OutputPath>
|
||||
<DefineConstants>DEBUG;TRACE</DefineConstants>
|
||||
<ErrorReport>prompt</ErrorReport>
|
||||
<WarningLevel>4</WarningLevel>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
|
||||
<PlatformTarget>AnyCPU</PlatformTarget>
|
||||
<DebugType>pdbonly</DebugType>
|
||||
<Optimize>true</Optimize>
|
||||
<OutputPath>bin\Release\</OutputPath>
|
||||
<DefineConstants>TRACE</DefineConstants>
|
||||
<ErrorReport>prompt</ErrorReport>
|
||||
<WarningLevel>4</WarningLevel>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'Debug|x64'">
|
||||
<PlatformTarget>x64</PlatformTarget>
|
||||
<OutputPath>bin\x64\Debug\</OutputPath>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'Release|x64'">
|
||||
<PlatformTarget>x64</PlatformTarget>
|
||||
<OutputPath>bin\x64\Release\</OutputPath>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'Debug|x86'">
|
||||
<PlatformTarget>x86</PlatformTarget>
|
||||
<OutputPath>bin\x86\Debug\</OutputPath>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'Release|x86'">
|
||||
<PlatformTarget>x86</PlatformTarget>
|
||||
<OutputPath>bin\x86\Release\</OutputPath>
|
||||
</PropertyGroup>
|
||||
<ItemGroup>
|
||||
<Reference Include="System" />
|
||||
<Reference Include="System.Data" />
|
||||
<Reference Include="System.Xml" />
|
||||
<Reference Include="Microsoft.CSharp" />
|
||||
<Reference Include="System.Core" />
|
||||
<Reference Include="System.Xml.Linq" />
|
||||
<Reference Include="System.Data.DataSetExtensions" />
|
||||
<Reference Include="System.Net.Http" />
|
||||
<Reference Include="System.Xaml">
|
||||
<RequiredTargetFramework>4.0</RequiredTargetFramework>
|
||||
</Reference>
|
||||
<Reference Include="WindowsBase" />
|
||||
<Reference Include="PresentationCore" />
|
||||
<Reference Include="PresentationFramework" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ApplicationDefinition Include="App.xaml">
|
||||
<Generator>MSBuild:Compile</Generator>
|
||||
<SubType>Designer</SubType>
|
||||
</ApplicationDefinition>
|
||||
<Compile Include="Models\CoverModel.cs" />
|
||||
<Compile Include="ViewModels\ViewCoverViewModel.cs" />
|
||||
<Compile Include="ViewModels\ViewHeaderViewModel.cs" />
|
||||
<Compile Include="Views\ViewCover.xaml.cs">
|
||||
<DependentUpon>ViewCover.xaml</DependentUpon>
|
||||
</Compile>
|
||||
<Compile Include="Views\ViewHeader.xaml.cs">
|
||||
<DependentUpon>ViewHeader.xaml</DependentUpon>
|
||||
</Compile>
|
||||
<Page Include="Views\MainWindow.xaml">
|
||||
<Generator>MSBuild:Compile</Generator>
|
||||
<SubType>Designer</SubType>
|
||||
</Page>
|
||||
<Compile Include="App.xaml.cs">
|
||||
<DependentUpon>App.xaml</DependentUpon>
|
||||
<SubType>Code</SubType>
|
||||
</Compile>
|
||||
<Compile Include="ViewModels\MainWindowViewModel.cs" />
|
||||
<Compile Include="Views\MainWindow.xaml.cs">
|
||||
<DependentUpon>MainWindow.xaml</DependentUpon>
|
||||
<SubType>Code</SubType>
|
||||
</Compile>
|
||||
<Page Include="Views\ViewCover.xaml">
|
||||
<SubType>Designer</SubType>
|
||||
<Generator>MSBuild:Compile</Generator>
|
||||
</Page>
|
||||
<Page Include="Views\ViewHeader.xaml">
|
||||
<SubType>Designer</SubType>
|
||||
<Generator>MSBuild:Compile</Generator>
|
||||
</Page>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<Compile Include="Properties\AssemblyInfo.cs">
|
||||
<SubType>Code</SubType>
|
||||
</Compile>
|
||||
<Compile Include="Properties\Resources.Designer.cs">
|
||||
<AutoGen>True</AutoGen>
|
||||
<DesignTime>True</DesignTime>
|
||||
<DependentUpon>Resources.resx</DependentUpon>
|
||||
</Compile>
|
||||
<Compile Include="Properties\Settings.Designer.cs">
|
||||
<AutoGen>True</AutoGen>
|
||||
<DependentUpon>Settings.settings</DependentUpon>
|
||||
<DesignTimeSharedInput>True</DesignTimeSharedInput>
|
||||
</Compile>
|
||||
<EmbeddedResource Include="Properties\Resources.resx">
|
||||
<Generator>ResXFileCodeGenerator</Generator>
|
||||
<LastGenOutput>Resources.Designer.cs</LastGenOutput>
|
||||
</EmbeddedResource>
|
||||
<None Include="Properties\Settings.settings">
|
||||
<Generator>SettingsSingleFileGenerator</Generator>
|
||||
<LastGenOutput>Settings.Designer.cs</LastGenOutput>
|
||||
</None>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<PackageReference Include="Prism.DryIoc" Version="8.1.97" />
|
||||
<PackageReference Include="System.Data.SQLite.Core">
|
||||
<Version>1.0.112.2</Version>
|
||||
</PackageReference>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="..\DownKyi.Core\DownKyi.Core.csproj">
|
||||
<Project>{4fde0364-f65b-4812-bfe8-34e886624fbd}</Project>
|
||||
<Name>DownKyi.Core</Name>
|
||||
</ProjectReference>
|
||||
</ItemGroup>
|
||||
<Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
|
||||
</Project>
|
||||
@@ -0,0 +1,47 @@
|
||||
namespace DatabaseManager.Models
|
||||
{
|
||||
public class CoverModel
|
||||
{
|
||||
public long Avid { get; set; }
|
||||
public string Bvid { get; set; }
|
||||
public long Cid { get; set; }
|
||||
public string Url { get; set; }
|
||||
public string Md5 { get; set; }
|
||||
|
||||
|
||||
//private long avid;
|
||||
//public long Avid
|
||||
//{
|
||||
// get { return avid; }
|
||||
// set { SetProperty(ref avid, value); }
|
||||
//}
|
||||
|
||||
//private string bvid;
|
||||
//public string Bvid
|
||||
//{
|
||||
// get { return bvid; }
|
||||
// set { SetProperty(ref bvid, value); }
|
||||
//}
|
||||
|
||||
//private long cid;
|
||||
//public long Cid
|
||||
//{
|
||||
// get { return cid; }
|
||||
// set { SetProperty(ref cid, value); }
|
||||
//}
|
||||
|
||||
//private string url;
|
||||
//public string Url
|
||||
//{
|
||||
// get { return url; }
|
||||
// set { SetProperty(ref url, value); }
|
||||
//}
|
||||
|
||||
//private string md5;
|
||||
//public string Md5
|
||||
//{
|
||||
// get { return md5; }
|
||||
// set { SetProperty(ref md5, value); }
|
||||
//}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,55 @@
|
||||
using System.Reflection;
|
||||
using System.Resources;
|
||||
using System.Runtime.CompilerServices;
|
||||
using System.Runtime.InteropServices;
|
||||
using System.Windows;
|
||||
|
||||
// General Information about an assembly is controlled through the following
|
||||
// set of attributes. Change these attribute values to modify the information
|
||||
// associated with an assembly.
|
||||
[assembly: AssemblyTitle("DatabaseManager")]
|
||||
[assembly: AssemblyDescription("")]
|
||||
[assembly: AssemblyConfiguration("")]
|
||||
[assembly: AssemblyCompany("")]
|
||||
[assembly: AssemblyProduct("DatabaseManager")]
|
||||
[assembly: AssemblyCopyright("Copyright © 2017")]
|
||||
[assembly: AssemblyTrademark("")]
|
||||
[assembly: AssemblyCulture("")]
|
||||
|
||||
// Setting ComVisible to false makes the types in this assembly not visible
|
||||
// to COM components. If you need to access a type in this assembly from
|
||||
// COM, set the ComVisible attribute to true on that type.
|
||||
[assembly: ComVisible(false)]
|
||||
|
||||
//In order to begin building localizable applications, set
|
||||
//<UICulture>CultureYouAreCodingWith</UICulture> in your .csproj file
|
||||
//inside a <PropertyGroup>. For example, if you are using US english
|
||||
//in your source files, set the <UICulture> to en-US. Then uncomment
|
||||
//the NeutralResourceLanguage attribute below. Update the "en-US" in
|
||||
//the line below to match the UICulture setting in the project file.
|
||||
|
||||
//[assembly: NeutralResourcesLanguage("en-US", UltimateResourceFallbackLocation.Satellite)]
|
||||
|
||||
|
||||
[assembly: ThemeInfo(
|
||||
ResourceDictionaryLocation.None, //where theme specific resource dictionaries are located
|
||||
//(used if a resource is not found in the page,
|
||||
// or application resource dictionaries)
|
||||
ResourceDictionaryLocation.SourceAssembly //where the generic resource dictionary is located
|
||||
//(used if a resource is not found in the page,
|
||||
// app, or any theme specific resource dictionaries)
|
||||
)]
|
||||
|
||||
|
||||
// Version information for an assembly consists of the following four values:
|
||||
//
|
||||
// Major Version
|
||||
// Minor Version
|
||||
// Build Number
|
||||
// Revision
|
||||
//
|
||||
// You can specify all the values or you can default the Build and Revision Numbers
|
||||
// by using the '*' as shown below:
|
||||
// [assembly: AssemblyVersion("1.0.*")]
|
||||
[assembly: AssemblyVersion("1.0.0.0")]
|
||||
[assembly: AssemblyFileVersion("1.0.0.0")]
|
||||
+71
@@ -0,0 +1,71 @@
|
||||
//------------------------------------------------------------------------------
|
||||
// <auto-generated>
|
||||
// This code was generated by a tool.
|
||||
// Runtime Version:4.0.30319.42000
|
||||
//
|
||||
// Changes to this file may cause incorrect behavior and will be lost if
|
||||
// the code is regenerated.
|
||||
// </auto-generated>
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
namespace DatabaseManager.Properties
|
||||
{
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// A strongly-typed resource class, for looking up localized strings, etc.
|
||||
/// </summary>
|
||||
// This class was auto-generated by the StronglyTypedResourceBuilder
|
||||
// class via a tool like ResGen or Visual Studio.
|
||||
// To add or remove a member, edit your .ResX file then rerun ResGen
|
||||
// with the /str option, or rebuild your VS project.
|
||||
[global::System.CodeDom.Compiler.GeneratedCodeAttribute("System.Resources.Tools.StronglyTypedResourceBuilder", "4.0.0.0")]
|
||||
[global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
|
||||
[global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()]
|
||||
internal class Resources
|
||||
{
|
||||
|
||||
private static global::System.Resources.ResourceManager resourceMan;
|
||||
|
||||
private static global::System.Globalization.CultureInfo resourceCulture;
|
||||
|
||||
[global::System.Diagnostics.CodeAnalysis.SuppressMessageAttribute("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")]
|
||||
internal Resources()
|
||||
{
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Returns the cached ResourceManager instance used by this class.
|
||||
/// </summary>
|
||||
[global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)]
|
||||
internal static global::System.Resources.ResourceManager ResourceManager
|
||||
{
|
||||
get
|
||||
{
|
||||
if ((resourceMan == null))
|
||||
{
|
||||
global::System.Resources.ResourceManager temp = new global::System.Resources.ResourceManager("DatabaseManager.Properties.Resources", typeof(Resources).Assembly);
|
||||
resourceMan = temp;
|
||||
}
|
||||
return resourceMan;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Overrides the current thread's CurrentUICulture property for all
|
||||
/// resource lookups using this strongly typed resource class.
|
||||
/// </summary>
|
||||
[global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)]
|
||||
internal static global::System.Globalization.CultureInfo Culture
|
||||
{
|
||||
get
|
||||
{
|
||||
return resourceCulture;
|
||||
}
|
||||
set
|
||||
{
|
||||
resourceCulture = value;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,117 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<root>
|
||||
<!--
|
||||
Microsoft ResX Schema
|
||||
|
||||
Version 2.0
|
||||
|
||||
The primary goals of this format is to allow a simple XML format
|
||||
that is mostly human readable. The generation and parsing of the
|
||||
various data types are done through the TypeConverter classes
|
||||
associated with the data types.
|
||||
|
||||
Example:
|
||||
|
||||
... ado.net/XML headers & schema ...
|
||||
<resheader name="resmimetype">text/microsoft-resx</resheader>
|
||||
<resheader name="version">2.0</resheader>
|
||||
<resheader name="reader">System.Resources.ResXResourceReader, System.Windows.Forms, ...</resheader>
|
||||
<resheader name="writer">System.Resources.ResXResourceWriter, System.Windows.Forms, ...</resheader>
|
||||
<data name="Name1"><value>this is my long string</value><comment>this is a comment</comment></data>
|
||||
<data name="Color1" type="System.Drawing.Color, System.Drawing">Blue</data>
|
||||
<data name="Bitmap1" mimetype="application/x-microsoft.net.object.binary.base64">
|
||||
<value>[base64 mime encoded serialized .NET Framework object]</value>
|
||||
</data>
|
||||
<data name="Icon1" type="System.Drawing.Icon, System.Drawing" mimetype="application/x-microsoft.net.object.bytearray.base64">
|
||||
<value>[base64 mime encoded string representing a byte array form of the .NET Framework object]</value>
|
||||
<comment>This is a comment</comment>
|
||||
</data>
|
||||
|
||||
There are any number of "resheader" rows that contain simple
|
||||
name/value pairs.
|
||||
|
||||
Each data row contains a name, and value. The row also contains a
|
||||
type or mimetype. Type corresponds to a .NET class that support
|
||||
text/value conversion through the TypeConverter architecture.
|
||||
Classes that don't support this are serialized and stored with the
|
||||
mimetype set.
|
||||
|
||||
The mimetype is used for serialized objects, and tells the
|
||||
ResXResourceReader how to depersist the object. This is currently not
|
||||
extensible. For a given mimetype the value must be set accordingly:
|
||||
|
||||
Note - application/x-microsoft.net.object.binary.base64 is the format
|
||||
that the ResXResourceWriter will generate, however the reader can
|
||||
read any of the formats listed below.
|
||||
|
||||
mimetype: application/x-microsoft.net.object.binary.base64
|
||||
value : The object must be serialized with
|
||||
: System.Serialization.Formatters.Binary.BinaryFormatter
|
||||
: and then encoded with base64 encoding.
|
||||
|
||||
mimetype: application/x-microsoft.net.object.soap.base64
|
||||
value : The object must be serialized with
|
||||
: System.Runtime.Serialization.Formatters.Soap.SoapFormatter
|
||||
: and then encoded with base64 encoding.
|
||||
|
||||
mimetype: application/x-microsoft.net.object.bytearray.base64
|
||||
value : The object must be serialized into a byte array
|
||||
: using a System.ComponentModel.TypeConverter
|
||||
: and then encoded with base64 encoding.
|
||||
-->
|
||||
<xsd:schema id="root" xmlns="" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:msdata="urn:schemas-microsoft-com:xml-msdata">
|
||||
<xsd:element name="root" msdata:IsDataSet="true">
|
||||
<xsd:complexType>
|
||||
<xsd:choice maxOccurs="unbounded">
|
||||
<xsd:element name="metadata">
|
||||
<xsd:complexType>
|
||||
<xsd:sequence>
|
||||
<xsd:element name="value" type="xsd:string" minOccurs="0" />
|
||||
</xsd:sequence>
|
||||
<xsd:attribute name="name" type="xsd:string" />
|
||||
<xsd:attribute name="type" type="xsd:string" />
|
||||
<xsd:attribute name="mimetype" type="xsd:string" />
|
||||
</xsd:complexType>
|
||||
</xsd:element>
|
||||
<xsd:element name="assembly">
|
||||
<xsd:complexType>
|
||||
<xsd:attribute name="alias" type="xsd:string" />
|
||||
<xsd:attribute name="name" type="xsd:string" />
|
||||
</xsd:complexType>
|
||||
</xsd:element>
|
||||
<xsd:element name="data">
|
||||
<xsd:complexType>
|
||||
<xsd:sequence>
|
||||
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
|
||||
<xsd:element name="comment" type="xsd:string" minOccurs="0" msdata:Ordinal="2" />
|
||||
</xsd:sequence>
|
||||
<xsd:attribute name="name" type="xsd:string" msdata:Ordinal="1" />
|
||||
<xsd:attribute name="type" type="xsd:string" msdata:Ordinal="3" />
|
||||
<xsd:attribute name="mimetype" type="xsd:string" msdata:Ordinal="4" />
|
||||
</xsd:complexType>
|
||||
</xsd:element>
|
||||
<xsd:element name="resheader">
|
||||
<xsd:complexType>
|
||||
<xsd:sequence>
|
||||
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
|
||||
</xsd:sequence>
|
||||
<xsd:attribute name="name" type="xsd:string" use="required" />
|
||||
</xsd:complexType>
|
||||
</xsd:element>
|
||||
</xsd:choice>
|
||||
</xsd:complexType>
|
||||
</xsd:element>
|
||||
</xsd:schema>
|
||||
<resheader name="resmimetype">
|
||||
<value>text/microsoft-resx</value>
|
||||
</resheader>
|
||||
<resheader name="version">
|
||||
<value>2.0</value>
|
||||
</resheader>
|
||||
<resheader name="reader">
|
||||
<value>System.Resources.ResXResourceReader, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
|
||||
</resheader>
|
||||
<resheader name="writer">
|
||||
<value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
|
||||
</resheader>
|
||||
</root>
|
||||
+30
@@ -0,0 +1,30 @@
|
||||
//------------------------------------------------------------------------------
|
||||
// <auto-generated>
|
||||
// This code was generated by a tool.
|
||||
// Runtime Version:4.0.30319.42000
|
||||
//
|
||||
// Changes to this file may cause incorrect behavior and will be lost if
|
||||
// the code is regenerated.
|
||||
// </auto-generated>
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
namespace DatabaseManager.Properties
|
||||
{
|
||||
|
||||
|
||||
[global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()]
|
||||
[global::System.CodeDom.Compiler.GeneratedCodeAttribute("Microsoft.VisualStudio.Editors.SettingsDesigner.SettingsSingleFileGenerator", "11.0.0.0")]
|
||||
internal sealed partial class Settings : global::System.Configuration.ApplicationSettingsBase
|
||||
{
|
||||
|
||||
private static Settings defaultInstance = ((Settings)(global::System.Configuration.ApplicationSettingsBase.Synchronized(new Settings())));
|
||||
|
||||
public static Settings Default
|
||||
{
|
||||
get
|
||||
{
|
||||
return defaultInstance;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,47 @@
|
||||
using Prism.Commands;
|
||||
using Prism.Mvvm;
|
||||
using Prism.Regions;
|
||||
|
||||
namespace DatabaseManager.ViewModels
|
||||
{
|
||||
public class MainWindowViewModel : BindableBase
|
||||
{
|
||||
private readonly IRegionManager regionManager;
|
||||
|
||||
|
||||
private string _title = "DatabaseManager";
|
||||
public string Title
|
||||
{
|
||||
get { return _title; }
|
||||
set { SetProperty(ref _title, value); }
|
||||
}
|
||||
|
||||
public MainWindowViewModel(IRegionManager regionManager)
|
||||
{
|
||||
this.regionManager = regionManager;
|
||||
}
|
||||
|
||||
|
||||
|
||||
private DelegateCommand coverCommand;
|
||||
public DelegateCommand CoverCommand => coverCommand ?? (coverCommand = new DelegateCommand(ExecuteCoverCommand));
|
||||
|
||||
private void ExecuteCoverCommand()
|
||||
{
|
||||
regionManager.RequestNavigate("ContentRegion", "Cover");
|
||||
}
|
||||
|
||||
private DelegateCommand headerCommand;
|
||||
public DelegateCommand HeaderCommand => headerCommand ?? (headerCommand = new DelegateCommand(ExecuteHeaderCommand));
|
||||
|
||||
private void ExecuteHeaderCommand()
|
||||
{
|
||||
regionManager.RequestNavigate("ContentRegion", "Header");
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,66 @@
|
||||
using DownKyi.Core.Storage.Database;
|
||||
using Prism.Mvvm;
|
||||
using Prism.Regions;
|
||||
using System;
|
||||
using System.Collections.ObjectModel;
|
||||
using System.Threading.Tasks;
|
||||
using System.Windows;
|
||||
|
||||
namespace DatabaseManager.ViewModels
|
||||
{
|
||||
public class ViewCoverViewModel : BindableBase, INavigationAware
|
||||
{
|
||||
private ObservableCollection<Cover> coverList;
|
||||
public ObservableCollection<Cover> CoverList
|
||||
{
|
||||
get { return coverList; }
|
||||
set { SetProperty(ref coverList, value); }
|
||||
}
|
||||
|
||||
public ViewCoverViewModel()
|
||||
{
|
||||
CoverList = new ObservableCollection<Cover>();
|
||||
}
|
||||
|
||||
public async void OnNavigatedTo(NavigationContext navigationContext)
|
||||
{
|
||||
await Task.Run(() =>
|
||||
{
|
||||
CoverDb coverDb = new CoverDb();
|
||||
var covers = coverDb.QueryAll();
|
||||
if (covers == null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
Application.Current.Dispatcher.Invoke(new Action(() =>
|
||||
{
|
||||
CoverList.Clear();
|
||||
foreach (var cover in covers)
|
||||
{
|
||||
//CoverModel newCover = new CoverModel
|
||||
//{
|
||||
// Avid = cover.Avid,
|
||||
// Bvid = cover.Bvid,
|
||||
// Cid = cover.Cid,
|
||||
// Url = cover.Url,
|
||||
// Md5 = cover.Md5
|
||||
//};
|
||||
|
||||
CoverList.Add(cover);
|
||||
}
|
||||
}));
|
||||
|
||||
});
|
||||
}
|
||||
|
||||
public bool IsNavigationTarget(NavigationContext navigationContext)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
public void OnNavigatedFrom(NavigationContext navigationContext)
|
||||
{
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,57 @@
|
||||
using DownKyi.Core.Storage.Database;
|
||||
using Prism.Mvvm;
|
||||
using Prism.Regions;
|
||||
using System;
|
||||
using System.Collections.ObjectModel;
|
||||
using System.Threading.Tasks;
|
||||
using System.Windows;
|
||||
|
||||
namespace DatabaseManager.ViewModels
|
||||
{
|
||||
public class ViewHeaderViewModel : BindableBase, INavigationAware
|
||||
{
|
||||
private ObservableCollection<Header> headerList;
|
||||
public ObservableCollection<Header> HeaderList
|
||||
{
|
||||
get { return headerList; }
|
||||
set { SetProperty(ref headerList, value); }
|
||||
}
|
||||
|
||||
public ViewHeaderViewModel()
|
||||
{
|
||||
HeaderList = new ObservableCollection<Header>();
|
||||
}
|
||||
|
||||
public bool IsNavigationTarget(NavigationContext navigationContext)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
public void OnNavigatedFrom(NavigationContext navigationContext)
|
||||
{
|
||||
}
|
||||
|
||||
public async void OnNavigatedTo(NavigationContext navigationContext)
|
||||
{
|
||||
await Task.Run(() =>
|
||||
{
|
||||
HeaderDb headerDb = new HeaderDb();
|
||||
var headers = headerDb.QueryAll();
|
||||
if (headers == null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
Application.Current.Dispatcher.Invoke(new Action(() =>
|
||||
{
|
||||
HeaderList.Clear();
|
||||
foreach (var cover in headers)
|
||||
{
|
||||
HeaderList.Add(cover);
|
||||
}
|
||||
}));
|
||||
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,32 @@
|
||||
<Window x:Class="DatabaseManager.Views.MainWindow"
|
||||
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
|
||||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||
xmlns:prism="http://prismlibrary.com/" xmlns:i="http://schemas.microsoft.com/xaml/behaviors"
|
||||
prism:ViewModelLocator.AutoWireViewModel="True"
|
||||
Title="{Binding Title}" Height="700" Width="1200">
|
||||
<Grid>
|
||||
<Grid.ColumnDefinitions>
|
||||
<ColumnDefinition Width="100"/>
|
||||
<ColumnDefinition/>
|
||||
</Grid.ColumnDefinitions>
|
||||
|
||||
<ListBox Grid.Column="0" BorderThickness="0 0 1 0">
|
||||
<ListBoxItem Content="Cover">
|
||||
<i:Interaction.Triggers>
|
||||
<i:EventTrigger EventName="MouseLeftButtonUp">
|
||||
<i:InvokeCommandAction Command="{Binding CoverCommand}"/>
|
||||
</i:EventTrigger>
|
||||
</i:Interaction.Triggers>
|
||||
</ListBoxItem>
|
||||
<ListBoxItem Content="Header">
|
||||
<i:Interaction.Triggers>
|
||||
<i:EventTrigger EventName="MouseLeftButtonUp">
|
||||
<i:InvokeCommandAction Command="{Binding HeaderCommand}"/>
|
||||
</i:EventTrigger>
|
||||
</i:Interaction.Triggers>
|
||||
</ListBoxItem>
|
||||
</ListBox>
|
||||
|
||||
<ContentControl Grid.Column="1" prism:RegionManager.RegionName="ContentRegion" />
|
||||
</Grid>
|
||||
</Window>
|
||||
@@ -0,0 +1,15 @@
|
||||
using System.Windows;
|
||||
|
||||
namespace DatabaseManager.Views
|
||||
{
|
||||
/// <summary>
|
||||
/// Interaction logic for MainWindow.xaml
|
||||
/// </summary>
|
||||
public partial class MainWindow : Window
|
||||
{
|
||||
public MainWindow()
|
||||
{
|
||||
InitializeComponent();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,18 @@
|
||||
<UserControl x:Class="DatabaseManager.Views.ViewCover"
|
||||
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
|
||||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||
xmlns:prism="http://prismlibrary.com/"
|
||||
prism:ViewModelLocator.AutoWireViewModel="True">
|
||||
<Grid>
|
||||
<DataGrid ItemsSource="{Binding CoverList}" AutoGenerateColumns="False" >
|
||||
<DataGrid.Columns>
|
||||
<DataGridTextColumn Header="Avid" Binding="{Binding Avid}"/>
|
||||
<DataGridTextColumn Header="Bvid" Binding="{Binding Bvid}"/>
|
||||
<DataGridTextColumn Header="Cid" Binding="{Binding Cid}"/>
|
||||
<DataGridTextColumn Header="Url" Binding="{Binding Url}"/>
|
||||
<DataGridTextColumn Header="Md5" Binding="{Binding Md5}"/>
|
||||
</DataGrid.Columns>
|
||||
|
||||
</DataGrid>
|
||||
</Grid>
|
||||
</UserControl>
|
||||
@@ -0,0 +1,15 @@
|
||||
using System.Windows.Controls;
|
||||
|
||||
namespace DatabaseManager.Views
|
||||
{
|
||||
/// <summary>
|
||||
/// Interaction logic for ViewCover
|
||||
/// </summary>
|
||||
public partial class ViewCover : UserControl
|
||||
{
|
||||
public ViewCover()
|
||||
{
|
||||
InitializeComponent();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,17 @@
|
||||
<UserControl x:Class="DatabaseManager.Views.ViewHeader"
|
||||
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
|
||||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||
xmlns:prism="http://prismlibrary.com/"
|
||||
prism:ViewModelLocator.AutoWireViewModel="True">
|
||||
<Grid>
|
||||
<DataGrid ItemsSource="{Binding HeaderList}" AutoGenerateColumns="False" >
|
||||
<DataGrid.Columns>
|
||||
<DataGridTextColumn Header="Avid" Binding="{Binding Mid}"/>
|
||||
<DataGridTextColumn Header="Bvid" Binding="{Binding Name}"/>
|
||||
<DataGridTextColumn Header="Url" Binding="{Binding Url}"/>
|
||||
<DataGridTextColumn Header="Md5" Binding="{Binding Md5}"/>
|
||||
</DataGrid.Columns>
|
||||
|
||||
</DataGrid>
|
||||
</Grid>
|
||||
</UserControl>
|
||||
@@ -0,0 +1,15 @@
|
||||
using System.Windows.Controls;
|
||||
|
||||
namespace DatabaseManager.Views
|
||||
{
|
||||
/// <summary>
|
||||
/// Interaction logic for ViewHeader
|
||||
/// </summary>
|
||||
public partial class ViewHeader : UserControl
|
||||
{
|
||||
public ViewHeader()
|
||||
{
|
||||
InitializeComponent();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,175 @@
|
||||
using Brotli;
|
||||
using DownKyi.Core.BiliApi.Login;
|
||||
using DownKyi.Core.BiliApi.Models.Json;
|
||||
using DownKyi.Core.BiliApi.VideoStream;
|
||||
using Microsoft.VisualStudio.TestTools.UnitTesting;
|
||||
using Newtonsoft.Json;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.IO.Compression;
|
||||
using System.Net;
|
||||
using System.Text;
|
||||
|
||||
namespace DownKyi.Core.Test.BiliApi
|
||||
{
|
||||
[TestClass]
|
||||
public class UnitTest1
|
||||
{
|
||||
[TestMethod]
|
||||
public void TestMethod1()
|
||||
{
|
||||
var player = VideoStream.PlayerV2(464087531, "BV1HL411u765", 439599721);
|
||||
|
||||
foreach (var subtitle in player.Subtitle.Subtitles)
|
||||
{
|
||||
string referer = "https://www.bilibili.com";
|
||||
string response = RequestWeb($"https:{subtitle.SubtitleUrl}", referer);
|
||||
|
||||
try
|
||||
{
|
||||
//Console.WriteLine(subtitle.SubtitleUrl);
|
||||
|
||||
//string json = @"D:\test.json";
|
||||
//WebClient mywebclient = new WebClient();
|
||||
//mywebclient.DownloadFile($"https:{subtitle.SubtitleUrl}", json);
|
||||
|
||||
//StreamReader streamReader = File.OpenText(json);
|
||||
//string jsonWordTemplate = streamReader.ReadToEnd();
|
||||
//streamReader.Close();
|
||||
|
||||
var subtitleJson = JsonConvert.DeserializeObject<SubtitleJson>(response);
|
||||
if (subtitleJson == null) { return; }
|
||||
|
||||
string srt = subtitleJson.ToSubRip();
|
||||
File.WriteAllText($"D:/{subtitle.LanDoc}.srt", srt);
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
Utils.Debugging.Console.PrintLine("PlayerV2()发生异常: {0}", e);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
public string RequestWeb(string url, string referer = null, string method = "GET", Dictionary<string, string> parameters = null, int retry = 3)
|
||||
{
|
||||
// 重试次数
|
||||
if (retry <= 0) { return ""; }
|
||||
|
||||
// post请求,发送参数
|
||||
if (method == "POST" && parameters != null)
|
||||
{
|
||||
StringBuilder builder = new StringBuilder();
|
||||
int i = 0;
|
||||
foreach (var item in parameters)
|
||||
{
|
||||
if (i > 0)
|
||||
{
|
||||
builder.Append("&");
|
||||
}
|
||||
|
||||
builder.AppendFormat("{0}={1}", item.Key, item.Value);
|
||||
i++;
|
||||
}
|
||||
|
||||
url += "?" + builder.ToString();
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
HttpWebRequest request = (HttpWebRequest)WebRequest.Create(url);
|
||||
request.Method = method;
|
||||
request.Timeout = 30 * 1000;
|
||||
request.UserAgent = "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/91.0.4472.77 Safari/537.36";
|
||||
//request.ContentType = "application/json,text/html,application/xhtml+xml,application/xml;charset=UTF-8";
|
||||
request.Headers["accept-language"] = "zh-CN,zh;q=0.9,en-US;q=0.8,en;q=0.7";
|
||||
request.Headers["accept-encoding"] = "gzip, deflate, br";
|
||||
|
||||
// referer
|
||||
if (referer != null)
|
||||
{
|
||||
request.Referer = referer;
|
||||
}
|
||||
|
||||
// 构造cookie
|
||||
if (!url.Contains("getLogin"))
|
||||
{
|
||||
request.Headers["origin"] = "https://www.bilibili.com";
|
||||
|
||||
CookieContainer cookies = LoginHelper.GetLoginInfoCookies();
|
||||
if (cookies != null)
|
||||
{
|
||||
request.CookieContainer = cookies;
|
||||
}
|
||||
}
|
||||
|
||||
string html = string.Empty;
|
||||
using (HttpWebResponse response = (HttpWebResponse)request.GetResponse())
|
||||
{
|
||||
if (response.ContentEncoding.ToLower().Contains("gzip"))
|
||||
{
|
||||
using (GZipStream stream = new GZipStream(response.GetResponseStream(), CompressionMode.Decompress))
|
||||
{
|
||||
using (StreamReader reader = new StreamReader(stream, Encoding.UTF8))
|
||||
{
|
||||
html = reader.ReadToEnd();
|
||||
}
|
||||
}
|
||||
}
|
||||
else if (response.ContentEncoding.ToLower().Contains("deflate"))
|
||||
{
|
||||
using (DeflateStream stream = new DeflateStream(response.GetResponseStream(), CompressionMode.Decompress))
|
||||
{
|
||||
using (StreamReader reader = new StreamReader(stream, Encoding.UTF8))
|
||||
{
|
||||
html = reader.ReadToEnd();
|
||||
}
|
||||
}
|
||||
}
|
||||
else if (response.ContentEncoding.ToLower().Contains("br"))
|
||||
{
|
||||
using (BrotliStream stream = new BrotliStream(response.GetResponseStream(), CompressionMode.Decompress))
|
||||
{
|
||||
using (StreamReader reader = new StreamReader(stream, Encoding.UTF8))
|
||||
{
|
||||
html = reader.ReadToEnd();
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
using (Stream stream = response.GetResponseStream())
|
||||
{
|
||||
using (StreamReader reader = new StreamReader(stream, Encoding.UTF8))
|
||||
{
|
||||
html = reader.ReadToEnd();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return html;
|
||||
}
|
||||
catch (WebException e)
|
||||
{
|
||||
Console.WriteLine("RequestWeb()发生Web异常: {0}", e);
|
||||
Logging.LogManager.Error(e);
|
||||
return RequestWeb(url, referer, method, parameters, retry - 1);
|
||||
}
|
||||
catch (IOException e)
|
||||
{
|
||||
Console.WriteLine("RequestWeb()发生IO异常: {0}", e);
|
||||
Logging.LogManager.Error(e);
|
||||
return RequestWeb(url, referer, method, parameters, retry - 1);
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
Console.WriteLine("RequestWeb()发生其他异常: {0}", e);
|
||||
Logging.LogManager.Error(e);
|
||||
return RequestWeb(url, referer, method, parameters, retry - 1);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,35 @@
|
||||
using DownKyi.Core.BiliApi.Video;
|
||||
using DownKyi.Core.BiliApi.Video.Models;
|
||||
using Microsoft.VisualStudio.TestTools.UnitTesting;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace DownKyi.Core.Test.BiliApi.Video
|
||||
{
|
||||
[TestClass]
|
||||
public class DynamicTest
|
||||
{
|
||||
// 主分区tid
|
||||
private readonly int[] typeIdList = { 1, 13, 167, 3, 129, 4, 36, 234, 223, 160, 211, 217, 119, 155, 5, 181, 177, 23, 11 };
|
||||
|
||||
[TestMethod]
|
||||
public void TestRegionDynamicList()
|
||||
{
|
||||
foreach (var tid in typeIdList)
|
||||
{
|
||||
var time = DateTime.Now;
|
||||
Random random = new Random(time.GetHashCode());
|
||||
int ps = random.Next(1, 51);
|
||||
|
||||
var regionDynamicList = Dynamic.RegionDynamicList(tid, 1, ps);
|
||||
|
||||
Assert.IsInstanceOfType(regionDynamicList, typeof(List<DynamicVideoView>));
|
||||
Assert.IsInstanceOfType(regionDynamicList[0], typeof(DynamicVideoView));
|
||||
Assert.IsNotNull(regionDynamicList[0]);
|
||||
|
||||
Assert.AreEqual(regionDynamicList.Count, ps);
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,34 @@
|
||||
using DownKyi.Core.BiliApi.Video;
|
||||
using DownKyi.Core.BiliApi.Video.Models;
|
||||
using Microsoft.VisualStudio.TestTools.UnitTesting;
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace DownKyi.Core.Test.BiliApi.Video
|
||||
{
|
||||
[TestClass]
|
||||
public class RankingTest
|
||||
{
|
||||
// 主分区tid
|
||||
private readonly int[] typeIdList = { 1, 13, 167, 3, 129, 4, 36, 234, 223, 160, 211, 217, 119, 155, 5, 181, 177, 23, 11 };
|
||||
|
||||
[TestMethod]
|
||||
public void TestRegionRankingList()
|
||||
{
|
||||
|
||||
foreach (var tid in typeIdList)
|
||||
{
|
||||
var regionRankingList = Ranking.RegionRankingList(tid, 3);
|
||||
|
||||
Assert.IsInstanceOfType(regionRankingList, typeof(List<RankingVideoView>));
|
||||
Assert.IsInstanceOfType(regionRankingList[0], typeof(RankingVideoView));
|
||||
Assert.IsNotNull(regionRankingList[0]);
|
||||
|
||||
regionRankingList = Ranking.RegionRankingList(tid, 7);
|
||||
|
||||
Assert.IsInstanceOfType(regionRankingList, typeof(List<RankingVideoView>));
|
||||
Assert.IsInstanceOfType(regionRankingList[0], typeof(RankingVideoView));
|
||||
Assert.IsNotNull(regionRankingList[0]);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,42 @@
|
||||
using DownKyi.Core.BiliApi.Video;
|
||||
using DownKyi.Core.BiliApi.Video.Models;
|
||||
using Microsoft.VisualStudio.TestTools.UnitTesting;
|
||||
|
||||
namespace DownKyi.Core.Test.BiliApi.Video
|
||||
{
|
||||
[TestClass]
|
||||
public class VideoInfoTest
|
||||
{
|
||||
// 主分区tid
|
||||
private readonly int[] typeIdList = { 1, 13, 167, 3, 129, 4, 36, 234, 223, 160, 211, 217, 119, 155, 5, 181, 177, 23, 11 };
|
||||
|
||||
[TestMethod]
|
||||
public void TestVideoViewInfo()
|
||||
{
|
||||
foreach (var tid in typeIdList)
|
||||
{
|
||||
var regionDynamicList = Dynamic.RegionDynamicList(tid, 1, 12);
|
||||
Assert.IsNotNull(regionDynamicList);
|
||||
|
||||
foreach (var videoView in regionDynamicList)
|
||||
{
|
||||
long aid = videoView.Aid;
|
||||
string bvid = videoView.Bvid;
|
||||
|
||||
var bv = VideoInfo.VideoViewInfo(bvid, -1);
|
||||
Assert.IsNotNull(bv);
|
||||
Assert.IsInstanceOfType(bv, typeof(VideoView));
|
||||
Assert.IsNotNull(bv.Pages);
|
||||
|
||||
var av = VideoInfo.VideoViewInfo(null, aid);
|
||||
Assert.IsNotNull(av);
|
||||
Assert.IsInstanceOfType(av, typeof(VideoView));
|
||||
Assert.IsNotNull(av.Pages);
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,50 @@
|
||||
using DownKyi.Core.BiliApi.VideoStream;
|
||||
using DownKyi.Core.Storage.Database.Download;
|
||||
using DownKyi.Models;
|
||||
using Microsoft.VisualStudio.TestTools.UnitTesting;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace DownKyi.Core.Test.Database
|
||||
{
|
||||
[TestClass]
|
||||
public class BinaryTest
|
||||
{
|
||||
[TestMethod]
|
||||
public void TestMethod1()
|
||||
{
|
||||
Downloading downloading = new Downloading
|
||||
{
|
||||
Gid = "gid",
|
||||
PlayStreamType = PlayStreamType.VIDEO,
|
||||
DownloadContent = "视频",
|
||||
DownloadStatusTitle = "下载中",
|
||||
Progress = 50,
|
||||
DownloadingFileSize = "60MB/120MB",
|
||||
MaxSpeed = 123456,
|
||||
SpeedDisplay = "5MB/s",
|
||||
};
|
||||
|
||||
DownloadingDb db = new DownloadingDb();
|
||||
db.Insert("testId", downloading);
|
||||
}
|
||||
|
||||
[TestMethod]
|
||||
public void TestMethod2()
|
||||
{
|
||||
DownloadingDb db = new DownloadingDb();
|
||||
Dictionary<string, object> query = db.QueryAll();
|
||||
|
||||
Downloading downloading = (Downloading)query["testId"];
|
||||
|
||||
Console.WriteLine(downloading.Gid);
|
||||
Console.WriteLine(downloading.PlayStreamType);
|
||||
Console.WriteLine(downloading.DownloadContent);
|
||||
Console.WriteLine(downloading.DownloadStatusTitle);
|
||||
Console.WriteLine(downloading.Progress);
|
||||
Console.WriteLine(downloading.DownloadingFileSize);
|
||||
Console.WriteLine(downloading.MaxSpeed);
|
||||
Console.WriteLine(downloading.SpeedDisplay);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,113 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<Project ToolsVersion="15.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
|
||||
<Import Project="..\packages\MSTest.TestAdapter.2.2.10\build\net46\MSTest.TestAdapter.props" Condition="Exists('..\packages\MSTest.TestAdapter.2.2.10\build\net46\MSTest.TestAdapter.props')" />
|
||||
<Import Project="$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props" Condition="Exists('$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props')" />
|
||||
<PropertyGroup>
|
||||
<Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
|
||||
<Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
|
||||
<ProjectGuid>{81B9719E-DA29-444F-BB72-CBD5819A654D}</ProjectGuid>
|
||||
<OutputType>Library</OutputType>
|
||||
<AppDesignerFolder>Properties</AppDesignerFolder>
|
||||
<RootNamespace>DownKyi.Core.Test</RootNamespace>
|
||||
<AssemblyName>DownKyi.Core.Test</AssemblyName>
|
||||
<TargetFrameworkVersion>v4.7.2</TargetFrameworkVersion>
|
||||
<FileAlignment>512</FileAlignment>
|
||||
<ProjectTypeGuids>{3AC096D0-A1C2-E12C-1390-A8335801FDAB};{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}</ProjectTypeGuids>
|
||||
<VisualStudioVersion Condition="'$(VisualStudioVersion)' == ''">15.0</VisualStudioVersion>
|
||||
<VSToolsPath Condition="'$(VSToolsPath)' == ''">$(MSBuildExtensionsPath32)\Microsoft\VisualStudio\v$(VisualStudioVersion)</VSToolsPath>
|
||||
<ReferencePath>$(ProgramFiles)\Common Files\microsoft shared\VSTT\$(VisualStudioVersion)\UITestExtensionPackages</ReferencePath>
|
||||
<IsCodedUITest>False</IsCodedUITest>
|
||||
<TestProjectType>UnitTest</TestProjectType>
|
||||
<NuGetPackageImportStamp>
|
||||
</NuGetPackageImportStamp>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
|
||||
<DebugSymbols>true</DebugSymbols>
|
||||
<DebugType>full</DebugType>
|
||||
<Optimize>false</Optimize>
|
||||
<OutputPath>bin\Debug\</OutputPath>
|
||||
<DefineConstants>DEBUG;TRACE</DefineConstants>
|
||||
<ErrorReport>prompt</ErrorReport>
|
||||
<WarningLevel>4</WarningLevel>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
|
||||
<DebugType>pdbonly</DebugType>
|
||||
<Optimize>true</Optimize>
|
||||
<OutputPath>bin\Release\</OutputPath>
|
||||
<DefineConstants>TRACE</DefineConstants>
|
||||
<ErrorReport>prompt</ErrorReport>
|
||||
<WarningLevel>4</WarningLevel>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'Debug|x64'">
|
||||
<PlatformTarget>x64</PlatformTarget>
|
||||
<OutputPath>bin\x64\Debug\</OutputPath>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'Release|x64'">
|
||||
<PlatformTarget>x64</PlatformTarget>
|
||||
<OutputPath>bin\x64\Release\</OutputPath>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'Debug|x86'">
|
||||
<PlatformTarget>x86</PlatformTarget>
|
||||
<OutputPath>bin\x86\Debug\</OutputPath>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'Release|x86'">
|
||||
<PlatformTarget>x86</PlatformTarget>
|
||||
<OutputPath>bin\x86\Release\</OutputPath>
|
||||
</PropertyGroup>
|
||||
<ItemGroup>
|
||||
<Reference Include="Microsoft.VisualStudio.TestPlatform.TestFramework, Version=14.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a, processorArchitecture=MSIL">
|
||||
<HintPath>..\packages\MSTest.TestFramework.2.2.10\lib\net45\Microsoft.VisualStudio.TestPlatform.TestFramework.dll</HintPath>
|
||||
</Reference>
|
||||
<Reference Include="Microsoft.VisualStudio.TestPlatform.TestFramework.Extensions, Version=14.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a, processorArchitecture=MSIL">
|
||||
<HintPath>..\packages\MSTest.TestFramework.2.2.10\lib\net45\Microsoft.VisualStudio.TestPlatform.TestFramework.Extensions.dll</HintPath>
|
||||
</Reference>
|
||||
<Reference Include="Newtonsoft.Json, Version=13.0.0.0, Culture=neutral, PublicKeyToken=30ad4fe6b2a6aeed, processorArchitecture=MSIL">
|
||||
<HintPath>..\packages\Newtonsoft.Json.13.0.2\lib\net45\Newtonsoft.Json.dll</HintPath>
|
||||
</Reference>
|
||||
<Reference Include="PresentationCore" />
|
||||
<Reference Include="System" />
|
||||
<Reference Include="System.Core" />
|
||||
<Reference Include="System.Data.SQLite, Version=1.0.112.1, Culture=neutral, PublicKeyToken=db937bc2d44ff139, processorArchitecture=MSIL">
|
||||
<HintPath>..\packages\System.Data.SQLite.Core.1.0.112.2\lib\net40\System.Data.SQLite.dll</HintPath>
|
||||
</Reference>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<Compile Include="BiliApi\UnitTest1.cs" />
|
||||
<Compile Include="BiliApi\Video\DynamicTest.cs" />
|
||||
<Compile Include="BiliApi\Video\RankingTest.cs" />
|
||||
<Compile Include="BiliApi\Video\VideoInfoTest.cs" />
|
||||
<Compile Include="Database\BinaryTest.cs" />
|
||||
<Compile Include="Properties\AssemblyInfo.cs" />
|
||||
<Compile Include="Test\UnitTest1.cs" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<None Include="app.config" />
|
||||
<None Include="packages.config" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="..\Brotli.Core\Brotli.Core.csproj">
|
||||
<Project>{3107CD63-E257-455E-AE81-1FD3582B067A}</Project>
|
||||
<Name>Brotli.Core</Name>
|
||||
</ProjectReference>
|
||||
<ProjectReference Include="..\DownKyi.Core\DownKyi.Core.csproj">
|
||||
<Project>{4fde0364-f65b-4812-bfe8-34e886624fbd}</Project>
|
||||
<Name>DownKyi.Core</Name>
|
||||
</ProjectReference>
|
||||
<ProjectReference Include="..\DownKyi\DownKyi.csproj">
|
||||
<Project>{97075FCD-6E8F-4FF9-B73A-994197F3765A}</Project>
|
||||
<Name>DownKyi</Name>
|
||||
</ProjectReference>
|
||||
</ItemGroup>
|
||||
<Import Project="$(VSToolsPath)\TeamTest\Microsoft.TestTools.targets" Condition="Exists('$(VSToolsPath)\TeamTest\Microsoft.TestTools.targets')" />
|
||||
<Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
|
||||
<Target Name="EnsureNuGetPackageBuildImports" BeforeTargets="PrepareForBuild">
|
||||
<PropertyGroup>
|
||||
<ErrorText>这台计算机上缺少此项目引用的 NuGet 程序包。使用“NuGet 程序包还原”可下载这些程序包。有关更多信息,请参见 http://go.microsoft.com/fwlink/?LinkID=322105。缺少的文件是 {0}。</ErrorText>
|
||||
</PropertyGroup>
|
||||
<Error Condition="!Exists('..\packages\System.Data.SQLite.Core.1.0.112.2\build\net40\System.Data.SQLite.Core.targets')" Text="$([System.String]::Format('$(ErrorText)', '..\packages\System.Data.SQLite.Core.1.0.112.2\build\net40\System.Data.SQLite.Core.targets'))" />
|
||||
<Error Condition="!Exists('..\packages\MSTest.TestAdapter.2.2.10\build\net46\MSTest.TestAdapter.props')" Text="$([System.String]::Format('$(ErrorText)', '..\packages\MSTest.TestAdapter.2.2.10\build\net46\MSTest.TestAdapter.props'))" />
|
||||
<Error Condition="!Exists('..\packages\MSTest.TestAdapter.2.2.10\build\net46\MSTest.TestAdapter.targets')" Text="$([System.String]::Format('$(ErrorText)', '..\packages\MSTest.TestAdapter.2.2.10\build\net46\MSTest.TestAdapter.targets'))" />
|
||||
</Target>
|
||||
<Import Project="..\packages\System.Data.SQLite.Core.1.0.112.2\build\net40\System.Data.SQLite.Core.targets" Condition="Exists('..\packages\System.Data.SQLite.Core.1.0.112.2\build\net40\System.Data.SQLite.Core.targets')" />
|
||||
<Import Project="..\packages\MSTest.TestAdapter.2.2.10\build\net46\MSTest.TestAdapter.targets" Condition="Exists('..\packages\MSTest.TestAdapter.2.2.10\build\net46\MSTest.TestAdapter.targets')" />
|
||||
</Project>
|
||||
@@ -0,0 +1,20 @@
|
||||
using System.Reflection;
|
||||
using System.Runtime.CompilerServices;
|
||||
using System.Runtime.InteropServices;
|
||||
|
||||
[assembly: AssemblyTitle("DownKyi.Core.Test")]
|
||||
[assembly: AssemblyDescription("")]
|
||||
[assembly: AssemblyConfiguration("")]
|
||||
[assembly: AssemblyCompany("")]
|
||||
[assembly: AssemblyProduct("DownKyi.Core.Test")]
|
||||
[assembly: AssemblyCopyright("Copyright © 2021")]
|
||||
[assembly: AssemblyTrademark("")]
|
||||
[assembly: AssemblyCulture("")]
|
||||
|
||||
[assembly: ComVisible(false)]
|
||||
|
||||
[assembly: Guid("81b9719e-da29-444f-bb72-cbd5819a654d")]
|
||||
|
||||
// [assembly: AssemblyVersion("1.0.*")]
|
||||
[assembly: AssemblyVersion("1.0.0.0")]
|
||||
[assembly: AssemblyFileVersion("1.0.0.0")]
|
||||
@@ -0,0 +1,35 @@
|
||||
using DownKyi.Core.BiliApi.Danmaku;
|
||||
using Microsoft.VisualStudio.TestTools.UnitTesting;
|
||||
using System;
|
||||
using System.Net;
|
||||
|
||||
namespace DownKyi.Core.Test.Test
|
||||
{
|
||||
[TestClass]
|
||||
public class UnitTest1
|
||||
{
|
||||
[TestMethod]
|
||||
public void TestMethod1()
|
||||
{
|
||||
string url = "https://api.bilibili.com/x/v2/dm/web/seg.so?type=1&oid=421769791&pid=420986799&segment_index=1";
|
||||
string localFile = @"C:\Users\FlySelf\Desktop\test.proto";
|
||||
WebClient mywebclient = new WebClient();
|
||||
mywebclient.DownloadFile(url, localFile);
|
||||
|
||||
}
|
||||
|
||||
[TestMethod]
|
||||
public void TestMethod2()
|
||||
{
|
||||
var danmakus = DanmakuProtobuf.GetAllDanmakuProto(420986799, 421769791);
|
||||
|
||||
Console.WriteLine(danmakus.Count);
|
||||
|
||||
foreach (var dan in danmakus)
|
||||
{
|
||||
Console.WriteLine(dan.ToString());
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,18 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<configuration>
|
||||
<startup>
|
||||
<supportedRuntime version="v4.0" sku=".NETFramework,Version=v4.7.2" />
|
||||
</startup>
|
||||
<runtime>
|
||||
<assemblyBinding xmlns="urn:schemas-microsoft-com:asm.v1">
|
||||
<dependentAssembly>
|
||||
<assemblyIdentity name="System.Runtime.CompilerServices.Unsafe" publicKeyToken="b03f5f7f11d50a3a" culture="neutral" />
|
||||
<bindingRedirect oldVersion="0.0.0.0-6.0.0.0" newVersion="6.0.0.0" />
|
||||
</dependentAssembly>
|
||||
<dependentAssembly>
|
||||
<assemblyIdentity name="System.Memory" publicKeyToken="cc7b13ffcd2ddd51" culture="neutral" />
|
||||
<bindingRedirect oldVersion="0.0.0.0-4.0.1.2" newVersion="4.0.1.2" />
|
||||
</dependentAssembly>
|
||||
</assemblyBinding>
|
||||
</runtime>
|
||||
</configuration>
|
||||
@@ -0,0 +1,7 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<packages>
|
||||
<package id="MSTest.TestAdapter" version="2.2.10" targetFramework="net472" />
|
||||
<package id="MSTest.TestFramework" version="2.2.10" targetFramework="net472" />
|
||||
<package id="Newtonsoft.Json" version="13.0.2" targetFramework="net472" />
|
||||
<package id="System.Data.SQLite.Core" version="1.0.112.2" targetFramework="net472" />
|
||||
</packages>
|
||||
+11
-3
@@ -5,6 +5,8 @@ using System.Diagnostics;
|
||||
using System.IO;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
using System.Windows;
|
||||
using System.Windows.Controls;
|
||||
|
||||
namespace DownKyi.Core.Aria2cNet.Server
|
||||
{
|
||||
@@ -20,7 +22,7 @@ namespace DownKyi.Core.Aria2cNet.Server
|
||||
/// <param name="output"></param>
|
||||
/// <param name="window"></param>
|
||||
/// <returns></returns>
|
||||
public static async Task<bool> StartServerAsync(AriaConfig config, Action<string> action)
|
||||
public static async Task<bool> StartServerAsync(AriaConfig config, TextBox output = null, Window window = null)
|
||||
{
|
||||
// aria端口
|
||||
ListenPort = config.ListenPort;
|
||||
@@ -112,11 +114,17 @@ namespace DownKyi.Core.Aria2cNet.Server
|
||||
null, (s, e) =>
|
||||
{
|
||||
if (e.Data == null || e.Data == "" || e.Data.Replace(" ", "") == "") { return; }
|
||||
|
||||
Utils.Debugging.Console.PrintLine(e.Data);
|
||||
LogManager.Debug("AriaServer", e.Data);
|
||||
|
||||
action.Invoke(e.Data);
|
||||
if (output != null && window != null)
|
||||
{
|
||||
window.Dispatcher.Invoke(new Action(() =>
|
||||
{
|
||||
output.Text += e.Data + "\n";
|
||||
output.ScrollToEnd();
|
||||
}));
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user