Update vld-windows

This commit is contained in:
the1812 2019-05-30 20:15:19 +08:00
parent bc02751fd5
commit cafd260b97
13 changed files with 192 additions and 33 deletions

View File

@ -7,7 +7,7 @@ namespace VideoLinkDownloader.Core
public class Video
{
public string Title { get; set; }
public int TotalSize { get; set; }
public long TotalSize { get; set; }
public VideoFragment[] Fragments { get; set; }
public static (bool success, IEnumerable<Video> videos) Parse(string json)
{

View File

@ -5,6 +5,8 @@ using System.Threading.Tasks;
using System.Linq;
using System.IO;
using System.Net;
using System.Net.Http;
using System.Net.Http.Headers;
namespace VideoLinkDownloader.Core
{
@ -18,13 +20,24 @@ namespace VideoLinkDownloader.Core
{
public Video Video { get; private set; }
public VideoDownloaderConfig Config { get; set; } = VideoDownloaderConfig.Default;
public ICollection<Action<double>> ProgressUpdate { get; } = new List<Action<double>>();
public List<Action<double>> ProgressUpdate { get; } = new List<Action<double>>();
public long DownloadedBytes
{
get
{
var entires = taskMap.ToArray();
return entires.Select(it => it.Value).Sum();
}
}
public double Progress => (double)DownloadedBytes / Video.TotalSize;
public bool Downloading { get; private set; } = false;
public VideoDownloader(Video video)
{
Video = video;
}
public async Task<IEnumerable<VideoDownloadResult>> Download()
{
taskMap = new Dictionary<Task, long>();
var results = await Task.WhenAll(from fragment in Video.Fragments select downloadFragment(fragment));
await Task.WhenAll(from fragment in Video.Fragments select mergeParts(fragment));
return results;
@ -33,10 +46,10 @@ namespace VideoLinkDownloader.Core
{
return Video.Fragments.Length == 1 ? Video.Title : $"{Video.Title} - {Array.IndexOf(Video.Fragments, fragment) + 1}";
}
private Dictionary<Task, double> taskMap = new Dictionary<Task, double>();
private Dictionary<Task, long> taskMap = new Dictionary<Task, long>();
private void updateProgress()
{
ProgressUpdate.ForEach(it => it(Progress));
}
private async Task<VideoDownloadResult> downloadFragment(VideoFragment fragment)
{
@ -49,7 +62,6 @@ namespace VideoLinkDownloader.Core
}
var startByte = 0;
var part = 0;
taskMap = new Dictionary<Task, double>();
while (startByte < fragment.Size)
{
var partFilename = $"{title}.part{part}";
@ -57,34 +69,51 @@ namespace VideoLinkDownloader.Core
{
var endByte = Math.Min(fragment.Size, startByte + partialLength) - 1;
var range = $"bytes={startByte}-{endByte}";
using (var webclient = new WebClient())
var client = new HttpClient();
client.DefaultRequestHeaders.Range = new RangeHeaderValue(startByte, endByte);
client.DefaultRequestHeaders.Referrer = new Uri("https://www.bilibili.com", UriKind.Absolute);
client.DefaultRequestHeaders.Add("Origin", "https://www.bilibili.com");
client.DefaultRequestHeaders.Add("User-Agent", "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/73.0.3683.103 Safari/537.36");
//client.Headers[HttpRequestHeader.Range] = range;
//client.Headers[HttpRequestHeader.Referer] = "https://www.bilibili.com";
//client.Headers[HttpRequestHeader.UserAgent] = "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/73.0.3683.103 Safari/537.36";
//client.Headers["Origin"] = "https://www.bilibili.com";
Task task = null;
try
{
webclient.Headers[HttpRequestHeader.Range] = range;
webclient.Headers[HttpRequestHeader.Referer] = "https://www.bilibili.com";
webclient.Headers[HttpRequestHeader.UserAgent] = "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/73.0.3683.103 Safari/537.36";
webclient.Headers["Origin"] = "https://www.bilibili.com";
Task task = null;
try
task = Task.Run(async () =>
{
task = webclient.DownloadFileTaskAsync(fragment.Url, partFilename);
webclient.DownloadProgressChanged += (s, e) =>
using (var response = await client.GetStreamAsync(fragment.Url))
using (var file = File.OpenWrite(partFilename))
{
taskMap[task] = e.BytesReceived;
};
taskMap.Add(task, 0.0);
}
catch (Exception ex)
when (ex is WebException || ex is InvalidOperationException)
{
// TODO: handle web errors
return VideoDownloadResult.Failed;
}
while (response.CanRead)
{
file.WriteByte((byte)response.ReadByte());
taskMap[task]++;
updateProgress();
}
}
});
//task = client.DownloadFileTaskAsync(fragment.Url, partFilename);
//client.DownloadProgressChanged += (s, e) =>
//{
// taskMap[task] = e.BytesReceived;
//};
taskMap.Add(task, 0L);
}
catch (Exception ex)
when (ex is WebException || ex is InvalidOperationException)
{
// TODO: handle web errors
return VideoDownloadResult.Failed;
}
}
part++;
startByte = startByte + partialLength;
}
Downloading = true;
await Task.WhenAll(taskMap.Select(it => it.Key));
Downloading = false;
return VideoDownloadResult.Success;
}
private async Task mergeParts(VideoFragment fragment)

View File

@ -4,4 +4,8 @@
<TargetFramework>netstandard2.0</TargetFramework>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="Newtonsoft.Json" Version="12.0.2" />
</ItemGroup>
</Project>

View File

@ -10,6 +10,9 @@
<ResourceDictionary
Source="Theme.Dark.xaml" />
</ResourceDictionary.MergedDictionaries>
<SolidColorBrush
x:Key="ThemeColor"
Color="#26a69a" />
</ResourceDictionary>
</Application.Resources>
</Application>

View File

@ -15,7 +15,8 @@ namespace VideoLinkDownloader
{
base.OnStartup(e);
var registry = Registry.CurrentUser.OpenSubKey(@"Software\Microsoft\Windows\CurrentVersion\Themes\Personalize");
if (registry is null || (int) registry.GetValue("AppsUseLightTheme", 0) == 1)
// if (registry is null || (int) registry.GetValue("AppsUseLightTheme", 0) == 1)
if (true)
{
Resources.MergedDictionaries.Remove(new ResourceDictionary
{

View File

@ -0,0 +1,32 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace VideoLinkDownloader
{
static class Extensions
{
public static string ToFileSize(this long size)
{
string[] units = { "B", "KB", "MB", "GB", "TB", "PB", "EB" };
if (size == 0)
{
return "0" + units[0];
}
var bytes = Math.Abs(size);
var place = Convert.ToInt32(Math.Floor(Math.Log(bytes, 1024)));
var num = Math.Round(bytes / Math.Pow(1024, place), 1);
return (Math.Sign(size) * num).ToString() + units[place];
}
public static void ForEach<T>(this IEnumerable<T> collection, Action<T> action)
{
foreach (var item in collection)
{
action(item);
}
}
}
}

View File

@ -8,9 +8,10 @@
mc:Ignorable="d"
Background="{DynamicResource Background}"
Foreground="{DynamicResource Foreground}"
Title="MainWindow"
Height="450"
Width="800">
WindowStartupLocation="CenterScreen"
Title="Bilibili Evolved Video Link Downloader"
Height="800"
Width="600">
<WindowChrome.WindowChrome>
<WindowChrome
GlassFrameThickness="1"

View File

@ -11,6 +11,59 @@
Title="MainPage">
<Grid>
<ItemsControl
Margin="30"
ItemsSource="{Binding VideoTasks}">
<ItemsControl.ItemTemplate>
<DataTemplate>
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="6*" />
<ColumnDefinition />
</Grid.ColumnDefinitions>
<Grid.RowDefinitions>
<RowDefinition />
<RowDefinition />
</Grid.RowDefinitions>
<Grid.Resources>
<Style
TargetType="TextBlock">
<Setter
Property="Foreground"
Value="{StaticResource Foreground}" />
<Setter
Property="HorizontalAlignment"
Value="Center" />
<Setter
Property="VerticalAlignment"
Value="Center" />
<Setter
Property="TextWrapping"
Value="Wrap" />
</Style>
</Grid.Resources>
<TextBlock
Text="{Binding Title}" />
<TextBlock
Grid.Row="1"
Grid.Column="1"
Text="{Binding PercentProgress}" />
<TextBlock
Grid.Column="1"
Text="{Binding SizeProgress}" />
<ProgressBar
Grid.Row="1"
Maximum="1"
Minimum="0"
Height="2"
Margin="12,0"
BorderThickness="0"
Background="#4888"
Foreground="{StaticResource ThemeColor}"
Value="{Binding Progress}" />
</Grid>
</DataTemplate>
</ItemsControl.ItemTemplate>
</ItemsControl>
</Grid>
</Page>

View File

@ -12,17 +12,16 @@ using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Navigation;
using System.Windows.Shapes;
using VideoLinkDownloader.Pages.Main;
namespace VideoLinkDownloader.Pages
{
/// <summary>
/// MainPage.xaml 的交互逻辑
/// </summary>
public partial class MainPage : Page
{
public MainPage()
{
InitializeComponent();
DataContext = new MainPageViewModel();
}
}
}

View File

@ -1,13 +1,29 @@
using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;
using VideoLinkDownloader.Core;
namespace VideoLinkDownloader.Pages.Main
{
class MainPageViewModel : NotificationObject
{
public MainPageViewModel()
{
if (Clipboard.ContainsText())
{
var text = Clipboard.GetText();
var (success, videos) = Video.Parse(text);
if (success)
{
videos.ForEach(video => VideoTasks.Add(new VideoTask(video)));
}
}
VideoTasks.ForEach(async it => await it.Download());
}
public ObservableCollection<VideoTask> VideoTasks { get; } = new ObservableCollection<VideoTask>();
}
}

View File

@ -41,8 +41,12 @@
<ApplicationIcon>Bilibili-Evolved.ico</ApplicationIcon>
</PropertyGroup>
<ItemGroup>
<Reference Include="Newtonsoft.Json, Version=12.0.0.0, Culture=neutral, PublicKeyToken=30ad4fe6b2a6aeed, processorArchitecture=MSIL">
<HintPath>..\packages\Newtonsoft.Json.12.0.2\lib\net45\Newtonsoft.Json.dll</HintPath>
</Reference>
<Reference Include="System" />
<Reference Include="System.Data" />
<Reference Include="System.Windows.Forms" />
<Reference Include="System.Xml" />
<Reference Include="Microsoft.CSharp" />
<Reference Include="System.Core" />
@ -61,6 +65,8 @@
<Generator>MSBuild:Compile</Generator>
<SubType>Designer</SubType>
</ApplicationDefinition>
<Compile Include="Extensions.cs" />
<Compile Include="VideoTask.cs" />
<Page Include="MainWindow.xaml">
<Generator>MSBuild:Compile</Generator>
<SubType>Designer</SubType>
@ -84,9 +90,11 @@
</Page>
</ItemGroup>
<ItemGroup>
<Compile Include="NotificationObject.cs" />
<Compile Include="Pages\Main\MainPage.xaml.cs">
<DependentUpon>MainPage.xaml</DependentUpon>
</Compile>
<Compile Include="Pages\Main\MainPageViewModel.cs" />
<Compile Include="Properties\AssemblyInfo.cs">
<SubType>Code</SubType>
</Compile>
@ -104,6 +112,7 @@
<Generator>ResXFileCodeGenerator</Generator>
<LastGenOutput>Resources.Designer.cs</LastGenOutput>
</EmbeddedResource>
<None Include="packages.config" />
<None Include="Properties\Settings.settings">
<Generator>SettingsSingleFileGenerator</Generator>
<LastGenOutput>Settings.Designer.cs</LastGenOutput>

View File

@ -12,6 +12,10 @@ namespace VideoLinkDownloader
public VideoTask(Video video)
{
Downloader = new VideoDownloader(video);
Downloader.ProgressUpdate.Add(progress =>
{
Progress = progress;
});
}
public VideoDownloader Downloader { get; private set; }
@ -23,8 +27,12 @@ namespace VideoLinkDownloader
{
progress = value;
OnPropertyChanged(nameof(Progress));
OnPropertyChanged(nameof(SizeProgress));
}
}
public string Title => Downloader.Video.Title;
public string PercentProgress => $"{Math.Floor(Progress * 1000) / 10}%";
public string SizeProgress => $"{Downloader.DownloadedBytes.ToFileSize()} / {Downloader.Video.TotalSize.ToFileSize()}";
public async Task Download()
{
await Downloader.Download();

View File

@ -0,0 +1,4 @@
<?xml version="1.0" encoding="utf-8"?>
<packages>
<package id="Newtonsoft.Json" version="12.0.2" targetFramework="net472" />
</packages>