DownKyi主程序部分代码

pull/252/head
flyself 3 years ago
parent 56f24eb4a1
commit 961a5b66c3

@ -0,0 +1,34 @@

Microsoft Visual Studio Solution File, Format Version 12.00
# Visual Studio Version 16
VisualStudioVersion = 16.0.31019.35
MinimumVisualStudioVersion = 10.0.40219.1
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "DownKyi", "DownKyi\DownKyi.csproj", "{97075FCD-6E8F-4FF9-B73A-994197F3765A}"
ProjectSection(ProjectDependencies) = postProject
{4FDE0364-F65B-4812-BFE8-34E886624FBD} = {4FDE0364-F65B-4812-BFE8-34E886624FBD}
EndProjectSection
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "DownKyi.Core", "DownKyi.Core\DownKyi.Core.csproj", "{4FDE0364-F65B-4812-BFE8-34E886624FBD}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU
Release|Any CPU = Release|Any CPU
EndGlobalSection
GlobalSection(ProjectConfigurationPlatforms) = postSolution
{97075FCD-6E8F-4FF9-B73A-994197F3765A}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{97075FCD-6E8F-4FF9-B73A-994197F3765A}.Debug|Any CPU.Build.0 = Debug|Any CPU
{97075FCD-6E8F-4FF9-B73A-994197F3765A}.Release|Any CPU.ActiveCfg = Release|Any CPU
{97075FCD-6E8F-4FF9-B73A-994197F3765A}.Release|Any CPU.Build.0 = Release|Any CPU
{4FDE0364-F65B-4812-BFE8-34E886624FBD}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{4FDE0364-F65B-4812-BFE8-34E886624FBD}.Debug|Any CPU.Build.0 = Debug|Any CPU
{4FDE0364-F65B-4812-BFE8-34E886624FBD}.Release|Any CPU.ActiveCfg = Release|Any CPU
{4FDE0364-F65B-4812-BFE8-34E886624FBD}.Release|Any CPU.Build.0 = Release|Any CPU
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
EndGlobalSection
GlobalSection(ExtensibilityGlobals) = postSolution
SolutionGuid = {B8FC6858-6EAD-46C9-AC9A-01E6DEBA32BC}
EndGlobalSection
EndGlobal

@ -0,0 +1,15 @@
<prism:PrismApplication
x:Class="DownKyi.App"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="clr-namespace:DownKyi"
xmlns:prism="http://prismlibrary.com/">
<Application.Resources>
<ResourceDictionary>
<ResourceDictionary.MergedDictionaries>
<ResourceDictionary Source="Themes/ThemeDefault.xaml" />
<ResourceDictionary Source="Languages/Default.xaml" />
</ResourceDictionary.MergedDictionaries>
</ResourceDictionary>
</Application.Resources>
</prism:PrismApplication>

@ -0,0 +1,81 @@
using DownKyi.Utils;
using DownKyi.ViewModels;
using DownKyi.ViewModels.Dialogs;
using DownKyi.ViewModels.DownloadManager;
using DownKyi.ViewModels.Settings;
using DownKyi.ViewModels.Toolbox;
using DownKyi.Views;
using DownKyi.Views.Dialogs;
using DownKyi.Views.DownloadManager;
using DownKyi.Views.Settings;
using DownKyi.Views.Toolbox;
using Prism.Ioc;
using System;
using System.Windows;
namespace DownKyi
{
/// <summary>
/// Interaction logic for App.xaml
/// </summary>
public partial class App
{
protected override Window CreateShell()
{
// 设置主题
DictionaryResource.LoadTheme("ThemeDefault");
//DictionaryResource.LoadTheme("ThemeDiy");
// 切换语言
DictionaryResource.LoadLanguage("Default");
//DictionaryResource.LoadLanguage("en_US");
return Container.Resolve<MainWindow>();
}
protected override void RegisterTypes(IContainerRegistry containerRegistry)
{
// pages
containerRegistry.RegisterForNavigation<ViewIndex>(ViewIndexViewModel.Tag);
containerRegistry.RegisterForNavigation<ViewLogin>(ViewLoginViewModel.Tag);
containerRegistry.RegisterForNavigation<ViewVideoDetail>(ViewVideoDetailViewModel.Tag);
containerRegistry.RegisterForNavigation<ViewSettings>(ViewSettingsViewModel.Tag);
containerRegistry.RegisterForNavigation<ViewDownloadManager>(ViewDownloadManagerViewModel.Tag);
containerRegistry.RegisterForNavigation<ViewToolbox>(ViewToolboxViewModel.Tag);
containerRegistry.RegisterForNavigation<ViewUserSpace>(ViewUserSpaceViewModel.Tag);
containerRegistry.RegisterForNavigation<ViewMySpace>(ViewMySpaceViewModel.Tag);
containerRegistry.RegisterForNavigation<ViewPublicFavorites>(ViewPublicFavoritesViewModel.Tag);
// downloadManager pages
containerRegistry.RegisterForNavigation<ViewDownloading>(ViewDownloadingViewModel.Tag);
containerRegistry.RegisterForNavigation<ViewDownloadFinished>(ViewDownloadFinishedViewModel.Tag);
// settings pages
containerRegistry.RegisterForNavigation<ViewBasic>(ViewBasicViewModel.Tag);
containerRegistry.RegisterForNavigation<ViewNetwork>(ViewNetworkViewModel.Tag);
containerRegistry.RegisterForNavigation<ViewVideo>(ViewVideoViewModel.Tag);
containerRegistry.RegisterForNavigation<ViewDanmaku>(ViewDanmakuViewModel.Tag);
containerRegistry.RegisterForNavigation<ViewAbout>(ViewAboutViewModel.Tag);
// tools pages
containerRegistry.RegisterForNavigation<ViewBiliHelper>(ViewBiliHelperViewModel.Tag);
containerRegistry.RegisterForNavigation<ViewDelogo>(ViewDelogoViewModel.Tag);
containerRegistry.RegisterForNavigation<ViewExtractMedia>(ViewExtractMediaViewModel.Tag);
// dialogs
containerRegistry.RegisterDialog<ViewDirectorySelector>(ViewDirectorySelectorViewModel.Tag);
containerRegistry.RegisterDialog<ViewParsingSelector>(ViewParsingSelectorViewModel.Tag);
}
/// <summary>
/// 异步修改绑定到UI的属性
/// </summary>
/// <param name="callback"></param>
public static void PropertyChangeAsync(Action callback)
{
Current.Dispatcher.Invoke(callback);
}
}
}

@ -0,0 +1,103 @@
using System;
using System.Drawing;
using System.Runtime.InteropServices;
using System.Windows.Interop;
using System.Windows.Media.Imaging;
using System.Windows.Threading;
namespace DownKyi.CustomControl
{
public class GifImage : System.Windows.Controls.Image
{
/// <summary>
/// gif动画的System.Drawing.Bitmap
/// </summary>
private Bitmap gifBitmap;
/// <summary>
/// 用于显示每一帧的BitmapSource
/// </summary>
private BitmapSource bitmapSource;
public GifImage(string gifPath)
{
gifBitmap = new Bitmap(gifPath);
bitmapSource = GetBitmapSource();
Source = bitmapSource;
}
public GifImage(Bitmap gifBitmap)
{
this.gifBitmap = gifBitmap;
bitmapSource = GetBitmapSource();
Source = bitmapSource;
}
/// <summary>
/// 从System.Drawing.Bitmap中获得用于显示的那一帧图像的BitmapSource
/// </summary>
/// <returns></returns>
private BitmapSource GetBitmapSource()
{
IntPtr handle = IntPtr.Zero;
try
{
handle = gifBitmap.GetHbitmap();
bitmapSource = Imaging.CreateBitmapSourceFromHBitmap(handle, IntPtr.Zero, System.Windows.Int32Rect.Empty, BitmapSizeOptions.FromEmptyOptions());
}
finally
{
if (handle != IntPtr.Zero)
{
DeleteObject(handle);
}
}
return bitmapSource;
}
/// <summary>
/// Start animation
/// </summary>
public void StartAnimate()
{
ImageAnimator.Animate(gifBitmap, OnFrameChanged);
}
/// <summary>
/// Stop animation
/// </summary>
public void StopAnimate()
{
ImageAnimator.StopAnimate(gifBitmap, OnFrameChanged);
}
/// <summary>
/// Event handler for the frame changed
/// </summary>
private void OnFrameChanged(object sender, EventArgs e)
{
Dispatcher.BeginInvoke(DispatcherPriority.Normal, new Action(() =>
{
ImageAnimator.UpdateFrames(); // 更新到下一帧
if (bitmapSource != null)
{
bitmapSource.Freeze();
}
//// Convert the bitmap to BitmapSource that can be display in WPF Visual Tree
bitmapSource = GetBitmapSource();
Source = bitmapSource;
InvalidateVisual();
}));
}
/// <summary>
/// Delete local bitmap resource
/// Reference: http://msdn.microsoft.com/en-us/library/dd183539(VS.85).aspx
/// </summary>
[DllImport("gdi32.dll", CharSet = CharSet.Auto, SetLastError = true)]
[return: MarshalAs(UnmanagedType.Bool)]
static extern bool DeleteObject(IntPtr hObject);
}
}

@ -0,0 +1,447 @@
<?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>{97075FCD-6E8F-4FF9-B73A-994197F3765A}</ProjectGuid>
<OutputType>WinExe</OutputType>
<AppDesignerFolder>Properties</AppDesignerFolder>
<RootNamespace>DownKyi</RootNamespace>
<AssemblyName>DownKyi</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>
<PublishUrl>publish\</PublishUrl>
<Install>true</Install>
<InstallFrom>Disk</InstallFrom>
<UpdateEnabled>false</UpdateEnabled>
<UpdateMode>Foreground</UpdateMode>
<UpdateInterval>7</UpdateInterval>
<UpdateIntervalUnits>Days</UpdateIntervalUnits>
<UpdatePeriodically>false</UpdatePeriodically>
<UpdateRequired>false</UpdateRequired>
<MapFileExtensions>true</MapFileExtensions>
<ApplicationRevision>0</ApplicationRevision>
<ApplicationVersion>1.0.0.%2a</ApplicationVersion>
<IsWebBootstrapper>false</IsWebBootstrapper>
<UseApplicationTrust>false</UseApplicationTrust>
<BootstrapperEnabled>true</BootstrapperEnabled>
</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>
<ApplicationIcon>Resources\favicon.ico</ApplicationIcon>
</PropertyGroup>
<PropertyGroup>
<ApplicationManifest>app.manifest</ApplicationManifest>
</PropertyGroup>
<ItemGroup>
<Reference Include="System" />
<Reference Include="System.Data" />
<Reference Include="System.Drawing" />
<Reference Include="System.Windows.Forms" />
<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="CustomControl\GifImage.cs" />
<Compile Include="Events\MessageEvent.cs" />
<Compile Include="Events\NavigationEvent.cs" />
<Compile Include="Events\NavigationParam.cs" />
<Compile Include="Images\ButtonIcon.cs" />
<Compile Include="Images\LogoIcon.cs" />
<Compile Include="Images\NavigationIcon.cs" />
<Compile Include="Images\NormalIcon.cs" />
<Compile Include="Models\ParseScopeDisplay.cs" />
<Compile Include="Models\Resolution.cs" />
<Compile Include="Models\TabHeader.cs" />
<Compile Include="Models\VideoQuality.cs" />
<Compile Include="Models\VideoInfoView.cs" />
<Compile Include="Models\VideoPage.cs" />
<Compile Include="Models\VideoSection.cs" />
<Compile Include="Services\BangumiInfoService.cs" />
<Compile Include="Services\CheeseInfoService.cs" />
<Compile Include="Services\IInfoService.cs" />
<Compile Include="Services\IResolutionService.cs" />
<Compile Include="Services\ResolutionService.cs" />
<Compile Include="Services\Utils.cs" />
<Compile Include="Services\VideoInfoService.cs" />
<Compile Include="Utils\ClipboardHooker.cs" />
<Compile Include="Utils\DialogUtils.cs" />
<Compile Include="Utils\DictionaryResource.cs" />
<Compile Include="ViewModels\BaseViewModel.cs" />
<Compile Include="ViewModels\Dialogs\ViewDirectorySelectorViewModel.cs" />
<Compile Include="ViewModels\Dialogs\BaseDialogViewModel.cs" />
<Compile Include="ViewModels\Settings\ViewBasicViewModel.cs" />
<Compile Include="ViewModels\Settings\ViewAboutViewModel.cs" />
<Compile Include="ViewModels\Settings\ViewDanmakuViewModel.cs" />
<Compile Include="ViewModels\DownloadManager\ViewDownloadFinishedViewModel.cs" />
<Compile Include="ViewModels\DownloadManager\ViewDownloadingViewModel.cs" />
<Compile Include="ViewModels\Toolbox\ViewBiliHelperViewModel.cs" />
<Compile Include="ViewModels\Toolbox\ViewDelogoViewModel.cs" />
<Compile Include="ViewModels\ViewDownloadManagerViewModel.cs" />
<Compile Include="ViewModels\Toolbox\ViewExtractMediaViewModel.cs" />
<Compile Include="ViewModels\ViewIndexViewModel.cs" />
<Compile Include="ViewModels\ViewLoginViewModel.cs" />
<Compile Include="ViewModels\Settings\ViewNetworkViewModel.cs" />
<Compile Include="ViewModels\Dialogs\ViewParsingSelectorViewModel.cs" />
<Compile Include="ViewModels\ViewMySpaceViewModel.cs" />
<Compile Include="ViewModels\ViewPublicFavoritesViewModel.cs" />
<Compile Include="ViewModels\ViewSettingsViewModel.cs" />
<Compile Include="ViewModels\ViewToolboxViewModel.cs" />
<Compile Include="ViewModels\ViewUserSpaceViewModel.cs" />
<Compile Include="ViewModels\ViewVideoDetailViewModel.cs" />
<Compile Include="ViewModels\Settings\ViewVideoViewModel.cs" />
<Compile Include="Views\Dialogs\ViewDirectorySelector.xaml.cs">
<DependentUpon>ViewDirectorySelector.xaml</DependentUpon>
</Compile>
<Compile Include="Views\Dialogs\ViewParsingSelector.xaml.cs">
<DependentUpon>ViewParsingSelector.xaml</DependentUpon>
</Compile>
<Compile Include="Views\DownloadManager\ViewDownloadFinished.xaml.cs">
<DependentUpon>ViewDownloadFinished.xaml</DependentUpon>
</Compile>
<Compile Include="Views\DownloadManager\ViewDownloading.xaml.cs">
<DependentUpon>ViewDownloading.xaml</DependentUpon>
</Compile>
<Compile Include="Views\Settings\ViewAbout.xaml.cs">
<DependentUpon>ViewAbout.xaml</DependentUpon>
</Compile>
<Compile Include="Views\Settings\ViewBasic.xaml.cs">
<DependentUpon>ViewBasic.xaml</DependentUpon>
</Compile>
<Compile Include="Views\Settings\ViewDanmaku.xaml.cs">
<DependentUpon>ViewDanmaku.xaml</DependentUpon>
</Compile>
<Compile Include="Views\Settings\ViewNetwork.xaml.cs">
<DependentUpon>ViewNetwork.xaml</DependentUpon>
</Compile>
<Compile Include="Views\Settings\ViewVideo.xaml.cs">
<DependentUpon>ViewVideo.xaml</DependentUpon>
</Compile>
<Compile Include="Views\Toolbox\ViewBiliHelper.xaml.cs">
<DependentUpon>ViewBiliHelper.xaml</DependentUpon>
</Compile>
<Compile Include="Views\Toolbox\ViewDelogo.xaml.cs">
<DependentUpon>ViewDelogo.xaml</DependentUpon>
</Compile>
<Compile Include="Views\Toolbox\ViewExtractMedia.xaml.cs">
<DependentUpon>ViewExtractMedia.xaml</DependentUpon>
</Compile>
<Compile Include="Views\ViewDownloadManager.xaml.cs">
<DependentUpon>ViewDownloadManager.xaml</DependentUpon>
</Compile>
<Compile Include="Views\ViewIndex.xaml.cs">
<DependentUpon>ViewIndex.xaml</DependentUpon>
</Compile>
<Compile Include="Views\ViewLogin.xaml.cs">
<DependentUpon>ViewLogin.xaml</DependentUpon>
</Compile>
<Compile Include="Views\ViewMySpace.xaml.cs">
<DependentUpon>ViewMySpace.xaml</DependentUpon>
</Compile>
<Compile Include="Views\ViewPublicFavorites.xaml.cs">
<DependentUpon>ViewPublicFavorites.xaml</DependentUpon>
</Compile>
<Compile Include="Views\ViewSettings.xaml.cs">
<DependentUpon>ViewSettings.xaml</DependentUpon>
</Compile>
<Compile Include="Views\ViewToolbox.xaml.cs">
<DependentUpon>ViewToolbox.xaml</DependentUpon>
</Compile>
<Compile Include="Views\ViewUserSpace.xaml.cs">
<DependentUpon>ViewUserSpace.xaml</DependentUpon>
</Compile>
<Compile Include="Views\ViewVideoDetail.xaml.cs">
<DependentUpon>ViewVideoDetail.xaml</DependentUpon>
</Compile>
<Page Include="Languages\en_US.xaml">
<Generator>MSBuild:Compile</Generator>
<SubType>Designer</SubType>
</Page>
<Page Include="Languages\zh_TW.xaml">
<Generator>MSBuild:Compile</Generator>
<SubType>Designer</SubType>
</Page>
<Page Include="Languages\zh_CN.xaml">
<Generator>MSBuild:Compile</Generator>
<SubType>Designer</SubType>
</Page>
<Page Include="Languages\Default.xaml">
<SubType>Designer</SubType>
<Generator>MSBuild:Compile</Generator>
</Page>
<Page Include="Themes\ColorBrush.xaml">
<SubType>Designer</SubType>
<Generator>MSBuild:Compile</Generator>
</Page>
<Page Include="Themes\Colors\ColorDiy.xaml">
<Generator>MSBuild:Compile</Generator>
<SubType>Designer</SubType>
</Page>
<Page Include="Themes\Colors\ColorDefault.xaml">
<SubType>Designer</SubType>
<Generator>MSBuild:Compile</Generator>
</Page>
<Page Include="Themes\Styles\StyleListBox.xaml">
<SubType>Designer</SubType>
<Generator>MSBuild:Compile</Generator>
</Page>
<Page Include="Themes\Styles\StyleListView.xaml">
<Generator>MSBuild:Compile</Generator>
<SubType>Designer</SubType>
</Page>
<Page Include="Themes\Styles\StyleCheckBox.xaml">
<Generator>MSBuild:Compile</Generator>
<SubType>Designer</SubType>
</Page>
<Page Include="Themes\Styles\StyleBtn.xaml">
<Generator>MSBuild:Compile</Generator>
<SubType>Designer</SubType>
</Page>
<Page Include="Themes\Styles\StyleImageBtn.xaml">
<SubType>Designer</SubType>
<Generator>MSBuild:Compile</Generator>
</Page>
<Page Include="Themes\Styles\StyleRadio.xaml">
<SubType>Designer</SubType>
<Generator>MSBuild:Compile</Generator>
</Page>
<Page Include="Themes\Styles\StyleSystemBtn.xaml">
<SubType>Designer</SubType>
<Generator>MSBuild:Compile</Generator>
</Page>
<Page Include="Themes\ThemeDiy.xaml">
<Generator>MSBuild:Compile</Generator>
<SubType>Designer</SubType>
</Page>
<Page Include="Themes\ThemeDefault.xaml">
<SubType>Designer</SubType>
<Generator>MSBuild:Compile</Generator>
</Page>
<Page Include="Views\Dialogs\ViewDirectorySelector.xaml">
<SubType>Designer</SubType>
<Generator>MSBuild:Compile</Generator>
</Page>
<Page Include="Views\Dialogs\ViewParsingSelector.xaml">
<SubType>Designer</SubType>
<Generator>MSBuild:Compile</Generator>
</Page>
<Page Include="Views\DownloadManager\ViewDownloadFinished.xaml">
<SubType>Designer</SubType>
<Generator>MSBuild:Compile</Generator>
</Page>
<Page Include="Views\DownloadManager\ViewDownloading.xaml">
<SubType>Designer</SubType>
<Generator>MSBuild:Compile</Generator>
</Page>
<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="Images\SystemIcon.cs" />
<Compile Include="Images\VectorImage.cs" />
<Compile Include="Models\AppInfo.cs" />
<Compile Include="ViewModels\MainWindowViewModel.cs" />
<Compile Include="Views\MainWindow.xaml.cs">
<DependentUpon>MainWindow.xaml</DependentUpon>
<SubType>Code</SubType>
</Compile>
<Page Include="Views\Settings\ViewAbout.xaml">
<SubType>Designer</SubType>
<Generator>MSBuild:Compile</Generator>
</Page>
<Page Include="Views\Settings\ViewBasic.xaml">
<SubType>Designer</SubType>
<Generator>MSBuild:Compile</Generator>
</Page>
<Page Include="Views\Settings\ViewDanmaku.xaml">
<SubType>Designer</SubType>
<Generator>MSBuild:Compile</Generator>
</Page>
<Page Include="Views\Settings\ViewNetwork.xaml">
<SubType>Designer</SubType>
<Generator>MSBuild:Compile</Generator>
</Page>
<Page Include="Views\Settings\ViewVideo.xaml">
<SubType>Designer</SubType>
<Generator>MSBuild:Compile</Generator>
</Page>
<Page Include="Views\Toolbox\ViewBiliHelper.xaml">
<SubType>Designer</SubType>
<Generator>MSBuild:Compile</Generator>
</Page>
<Page Include="Views\Toolbox\ViewDelogo.xaml">
<SubType>Designer</SubType>
<Generator>MSBuild:Compile</Generator>
</Page>
<Page Include="Views\Toolbox\ViewExtractMedia.xaml">
<SubType>Designer</SubType>
<Generator>MSBuild:Compile</Generator>
</Page>
<Page Include="Views\ViewDownloadManager.xaml">
<SubType>Designer</SubType>
<Generator>MSBuild:Compile</Generator>
</Page>
<Page Include="Views\ViewIndex.xaml">
<SubType>Designer</SubType>
<Generator>MSBuild:Compile</Generator>
</Page>
<Page Include="Views\ViewLogin.xaml">
<SubType>Designer</SubType>
<Generator>MSBuild:Compile</Generator>
</Page>
<Page Include="Views\ViewMySpace.xaml">
<SubType>Designer</SubType>
<Generator>MSBuild:Compile</Generator>
</Page>
<Page Include="Views\ViewPublicFavorites.xaml">
<SubType>Designer</SubType>
<Generator>MSBuild:Compile</Generator>
</Page>
<Page Include="Views\ViewSettings.xaml">
<SubType>Designer</SubType>
<Generator>MSBuild:Compile</Generator>
</Page>
<Page Include="Views\ViewToolbox.xaml">
<SubType>Designer</SubType>
<Generator>MSBuild:Compile</Generator>
</Page>
<Page Include="Views\ViewUserSpace.xaml">
<SubType>Designer</SubType>
<Generator>MSBuild:Compile</Generator>
</Page>
<Page Include="Views\ViewVideoDetail.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="app.config" />
<None Include="app.manifest" />
<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>
<Resource Include="Resources\favicon.ico" />
</ItemGroup>
<ItemGroup>
<Resource Include="Resources\default_header.jpg" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\DownKyi.Core\DownKyi.Core.csproj">
<Project>{4fde0364-f65b-4812-bfe8-34e886624fbd}</Project>
<Name>DownKyi.Core</Name>
</ProjectReference>
</ItemGroup>
<ItemGroup>
<Resource Include="Resources\login\login_top_bar.png" />
<Resource Include="Resources\login\qrcode_login_2233.png" />
<Resource Include="Resources\login\qrcode_login_tip.png" />
<Resource Include="Resources\login\scan_succeed.png" />
</ItemGroup>
<ItemGroup>
<BootstrapperPackage Include=".NETFramework,Version=v4.7.2">
<Visible>False</Visible>
<ProductName>Microsoft .NET Framework 4.7.2 %28x86 和 x64%29</ProductName>
<Install>true</Install>
</BootstrapperPackage>
<BootstrapperPackage Include="Microsoft.Net.Framework.3.5.SP1">
<Visible>False</Visible>
<ProductName>.NET Framework 3.5 SP1</ProductName>
<Install>false</Install>
</BootstrapperPackage>
</ItemGroup>
<ItemGroup>
<Resource Include="Resources\loading\loading.gif" />
</ItemGroup>
<ItemGroup>
<Resource Include="Resources\no-data.png" />
</ItemGroup>
<ItemGroup>
<Content Include="aria2c.exe">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</Content>
<Content Include="aria2_COPYING.txt">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</Content>
<Content Include="ffmpeg.exe">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</Content>
<Content Include="FFmpeg_LICENSE.txt">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</Content>
<Content Include="打不开DownKyi请点我.txt">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</Content>
</ItemGroup>
<ItemGroup />
<Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
<Target Name="AfterCompile">
<Exec Command="echo &quot;&quot;" />
</Target>
</Project>

@ -0,0 +1,13 @@
<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="Current" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<PropertyGroup>
<PublishUrlHistory />
<InstallUrlHistory />
<SupportUrlHistory />
<UpdateUrlHistory />
<BootstrapperUrlHistory />
<ErrorReportUrlHistory />
<FallbackCulture>zh-CN</FallbackCulture>
<VerifyUploadedFiles>false</VerifyUploadedFiles>
</PropertyGroup>
</Project>

@ -0,0 +1,6 @@
using Prism.Events;
namespace DownKyi.Events
{
public class MessageEvent : PubSubEvent<string> { }
}

@ -0,0 +1,6 @@
using Prism.Events;
namespace DownKyi.Events
{
public class NavigationEvent : PubSubEvent<NavigationParam> { }
}

@ -0,0 +1,9 @@
namespace DownKyi.Events
{
public class NavigationParam
{
public string ViewName { get; set; }
public string ParentViewName { get; set; }
public object Parameter { get; set; }
}
}

@ -0,0 +1,674 @@
GNU GENERAL PUBLIC LICENSE
Version 3, 29 June 2007
Copyright (C) 2007 Free Software Foundation, Inc. <https://fsf.org/>
Everyone is permitted to copy and distribute verbatim copies
of this license document, but changing it is not allowed.
Preamble
The GNU General Public License is a free, copyleft license for
software and other kinds of works.
The licenses for most software and other practical works are designed
to take away your freedom to share and change the works. By contrast,
the GNU General Public License is intended to guarantee your freedom to
share and change all versions of a program--to make sure it remains free
software for all its users. We, the Free Software Foundation, use the
GNU General Public License for most of our software; it applies also to
any other work released this way by its authors. You can apply it to
your programs, too.
When we speak of free software, we are referring to freedom, not
price. Our General Public Licenses are designed to make sure that you
have the freedom to distribute copies of free software (and charge for
them if you wish), that you receive source code or can get it if you
want it, that you can change the software or use pieces of it in new
free programs, and that you know you can do these things.
To protect your rights, we need to prevent others from denying you
these rights or asking you to surrender the rights. Therefore, you have
certain responsibilities if you distribute copies of the software, or if
you modify it: responsibilities to respect the freedom of others.
For example, if you distribute copies of such a program, whether
gratis or for a fee, you must pass on to the recipients the same
freedoms that you received. You must make sure that they, too, receive
or can get the source code. And you must show them these terms so they
know their rights.
Developers that use the GNU GPL protect your rights with two steps:
(1) assert copyright on the software, and (2) offer you this License
giving you legal permission to copy, distribute and/or modify it.
For the developers' and authors' protection, the GPL clearly explains
that there is no warranty for this free software. For both users' and
authors' sake, the GPL requires that modified versions be marked as
changed, so that their problems will not be attributed erroneously to
authors of previous versions.
Some devices are designed to deny users access to install or run
modified versions of the software inside them, although the manufacturer
can do so. This is fundamentally incompatible with the aim of
protecting users' freedom to change the software. The systematic
pattern of such abuse occurs in the area of products for individuals to
use, which is precisely where it is most unacceptable. Therefore, we
have designed this version of the GPL to prohibit the practice for those
products. If such problems arise substantially in other domains, we
stand ready to extend this provision to those domains in future versions
of the GPL, as needed to protect the freedom of users.
Finally, every program is threatened constantly by software patents.
States should not allow patents to restrict development and use of
software on general-purpose computers, but in those that do, we wish to
avoid the special danger that patents applied to a free program could
make it effectively proprietary. To prevent this, the GPL assures that
patents cannot be used to render the program non-free.
The precise terms and conditions for copying, distribution and
modification follow.
TERMS AND CONDITIONS
0. Definitions.
"This License" refers to version 3 of the GNU General Public License.
"Copyright" also means copyright-like laws that apply to other kinds of
works, such as semiconductor masks.
"The Program" refers to any copyrightable work licensed under this
License. Each licensee is addressed as "you". "Licensees" and
"recipients" may be individuals or organizations.
To "modify" a work means to copy from or adapt all or part of the work
in a fashion requiring copyright permission, other than the making of an
exact copy. The resulting work is called a "modified version" of the
earlier work or a work "based on" the earlier work.
A "covered work" means either the unmodified Program or a work based
on the Program.
To "propagate" a work means to do anything with it that, without
permission, would make you directly or secondarily liable for
infringement under applicable copyright law, except executing it on a
computer or modifying a private copy. Propagation includes copying,
distribution (with or without modification), making available to the
public, and in some countries other activities as well.
To "convey" a work means any kind of propagation that enables other
parties to make or receive copies. Mere interaction with a user through
a computer network, with no transfer of a copy, is not conveying.
An interactive user interface displays "Appropriate Legal Notices"
to the extent that it includes a convenient and prominently visible
feature that (1) displays an appropriate copyright notice, and (2)
tells the user that there is no warranty for the work (except to the
extent that warranties are provided), that licensees may convey the
work under this License, and how to view a copy of this License. If
the interface presents a list of user commands or options, such as a
menu, a prominent item in the list meets this criterion.
1. Source Code.
The "source code" for a work means the preferred form of the work
for making modifications to it. "Object code" means any non-source
form of a work.
A "Standard Interface" means an interface that either is an official
standard defined by a recognized standards body, or, in the case of
interfaces specified for a particular programming language, one that
is widely used among developers working in that language.
The "System Libraries" of an executable work include anything, other
than the work as a whole, that (a) is included in the normal form of
packaging a Major Component, but which is not part of that Major
Component, and (b) serves only to enable use of the work with that
Major Component, or to implement a Standard Interface for which an
implementation is available to the public in source code form. A
"Major Component", in this context, means a major essential component
(kernel, window system, and so on) of the specific operating system
(if any) on which the executable work runs, or a compiler used to
produce the work, or an object code interpreter used to run it.
The "Corresponding Source" for a work in object code form means all
the source code needed to generate, install, and (for an executable
work) run the object code and to modify the work, including scripts to
control those activities. However, it does not include the work's
System Libraries, or general-purpose tools or generally available free
programs which are used unmodified in performing those activities but
which are not part of the work. For example, Corresponding Source
includes interface definition files associated with source files for
the work, and the source code for shared libraries and dynamically
linked subprograms that the work is specifically designed to require,
such as by intimate data communication or control flow between those
subprograms and other parts of the work.
The Corresponding Source need not include anything that users
can regenerate automatically from other parts of the Corresponding
Source.
The Corresponding Source for a work in source code form is that
same work.
2. Basic Permissions.
All rights granted under this License are granted for the term of
copyright on the Program, and are irrevocable provided the stated
conditions are met. This License explicitly affirms your unlimited
permission to run the unmodified Program. The output from running a
covered work is covered by this License only if the output, given its
content, constitutes a covered work. This License acknowledges your
rights of fair use or other equivalent, as provided by copyright law.
You may make, run and propagate covered works that you do not
convey, without conditions so long as your license otherwise remains
in force. You may convey covered works to others for the sole purpose
of having them make modifications exclusively for you, or provide you
with facilities for running those works, provided that you comply with
the terms of this License in conveying all material for which you do
not control copyright. Those thus making or running the covered works
for you must do so exclusively on your behalf, under your direction
and control, on terms that prohibit them from making any copies of
your copyrighted material outside their relationship with you.
Conveying under any other circumstances is permitted solely under
the conditions stated below. Sublicensing is not allowed; section 10
makes it unnecessary.
3. Protecting Users' Legal Rights From Anti-Circumvention Law.
No covered work shall be deemed part of an effective technological
measure under any applicable law fulfilling obligations under article
11 of the WIPO copyright treaty adopted on 20 December 1996, or
similar laws prohibiting or restricting circumvention of such
measures.
When you convey a covered work, you waive any legal power to forbid
circumvention of technological measures to the extent such circumvention
is effected by exercising rights under this License with respect to
the covered work, and you disclaim any intention to limit operation or
modification of the work as a means of enforcing, against the work's
users, your or third parties' legal rights to forbid circumvention of
technological measures.
4. Conveying Verbatim Copies.
You may convey verbatim copies of the Program's source code as you
receive it, in any medium, provided that you conspicuously and
appropriately publish on each copy an appropriate copyright notice;
keep intact all notices stating that this License and any
non-permissive terms added in accord with section 7 apply to the code;
keep intact all notices of the absence of any warranty; and give all
recipients a copy of this License along with the Program.
You may charge any price or no price for each copy that you convey,
and you may offer support or warranty protection for a fee.
5. Conveying Modified Source Versions.
You may convey a work based on the Program, or the modifications to
produce it from the Program, in the form of source code under the
terms of section 4, provided that you also meet all of these conditions:
a) The work must carry prominent notices stating that you modified
it, and giving a relevant date.
b) The work must carry prominent notices stating that it is
released under this License and any conditions added under section
7. This requirement modifies the requirement in section 4 to
"keep intact all notices".
c) You must license the entire work, as a whole, under this
License to anyone who comes into possession of a copy. This
License will therefore apply, along with any applicable section 7
additional terms, to the whole of the work, and all its parts,
regardless of how they are packaged. This License gives no
permission to license the work in any other way, but it does not
invalidate such permission if you have separately received it.
d) If the work has interactive user interfaces, each must display
Appropriate Legal Notices; however, if the Program has interactive
interfaces that do not display Appropriate Legal Notices, your
work need not make them do so.
A compilation of a covered work with other separate and independent
works, which are not by their nature extensions of the covered work,
and which are not combined with it such as to form a larger program,
in or on a volume of a storage or distribution medium, is called an
"aggregate" if the compilation and its resulting copyright are not
used to limit the access or legal rights of the compilation's users
beyond what the individual works permit. Inclusion of a covered work
in an aggregate does not cause this License to apply to the other
parts of the aggregate.
6. Conveying Non-Source Forms.
You may convey a covered work in object code form under the terms
of sections 4 and 5, provided that you also convey the
machine-readable Corresponding Source under the terms of this License,
in one of these ways:
a) Convey the object code in, or embodied in, a physical product
(including a physical distribution medium), accompanied by the
Corresponding Source fixed on a durable physical medium
customarily used for software interchange.
b) Convey the object code in, or embodied in, a physical product
(including a physical distribution medium), accompanied by a
written offer, valid for at least three years and valid for as
long as you offer spare parts or customer support for that product
model, to give anyone who possesses the object code either (1) a
copy of the Corresponding Source for all the software in the
product that is covered by this License, on a durable physical
medium customarily used for software interchange, for a price no
more than your reasonable cost of physically performing this
conveying of source, or (2) access to copy the
Corresponding Source from a network server at no charge.
c) Convey individual copies of the object code with a copy of the
written offer to provide the Corresponding Source. This
alternative is allowed only occasionally and noncommercially, and
only if you received the object code with such an offer, in accord
with subsection 6b.
d) Convey the object code by offering access from a designated
place (gratis or for a charge), and offer equivalent access to the
Corresponding Source in the same way through the same place at no
further charge. You need not require recipients to copy the
Corresponding Source along with the object code. If the place to
copy the object code is a network server, the Corresponding Source
may be on a different server (operated by you or a third party)
that supports equivalent copying facilities, provided you maintain
clear directions next to the object code saying where to find the
Corresponding Source. Regardless of what server hosts the
Corresponding Source, you remain obligated to ensure that it is
available for as long as needed to satisfy these requirements.
e) Convey the object code using peer-to-peer transmission, provided
you inform other peers where the object code and Corresponding
Source of the work are being offered to the general public at no
charge under subsection 6d.
A separable portion of the object code, whose source code is excluded
from the Corresponding Source as a System Library, need not be
included in conveying the object code work.
A "User Product" is either (1) a "consumer product", which means any
tangible personal property which is normally used for personal, family,
or household purposes, or (2) anything designed or sold for incorporation
into a dwelling. In determining whether a product is a consumer product,
doubtful cases shall be resolved in favor of coverage. For a particular
product received by a particular user, "normally used" refers to a
typical or common use of that class of product, regardless of the status
of the particular user or of the way in which the particular user
actually uses, or expects or is expected to use, the product. A product
is a consumer product regardless of whether the product has substantial
commercial, industrial or non-consumer uses, unless such uses represent
the only significant mode of use of the product.
"Installation Information" for a User Product means any methods,
procedures, authorization keys, or other information required to install
and execute modified versions of a covered work in that User Product from
a modified version of its Corresponding Source. The information must
suffice to ensure that the continued functioning of the modified object
code is in no case prevented or interfered with solely because
modification has been made.
If you convey an object code work under this section in, or with, or
specifically for use in, a User Product, and the conveying occurs as
part of a transaction in which the right of possession and use of the
User Product is transferred to the recipient in perpetuity or for a
fixed term (regardless of how the transaction is characterized), the
Corresponding Source conveyed under this section must be accompanied
by the Installation Information. But this requirement does not apply
if neither you nor any third party retains the ability to install
modified object code on the User Product (for example, the work has
been installed in ROM).
The requirement to provide Installation Information does not include a
requirement to continue to provide support service, warranty, or updates
for a work that has been modified or installed by the recipient, or for
the User Product in which it has been modified or installed. Access to a
network may be denied when the modification itself materially and
adversely affects the operation of the network or violates the rules and
protocols for communication across the network.
Corresponding Source conveyed, and Installation Information provided,
in accord with this section must be in a format that is publicly
documented (and with an implementation available to the public in
source code form), and must require no special password or key for
unpacking, reading or copying.
7. Additional Terms.
"Additional permissions" are terms that supplement the terms of this
License by making exceptions from one or more of its conditions.
Additional permissions that are applicable to the entire Program shall
be treated as though they were included in this License, to the extent
that they are valid under applicable law. If additional permissions
apply only to part of the Program, that part may be used separately
under those permissions, but the entire Program remains governed by
this License without regard to the additional permissions.
When you convey a copy of a covered work, you may at your option
remove any additional permissions from that copy, or from any part of
it. (Additional permissions may be written to require their own
removal in certain cases when you modify the work.) You may place
additional permissions on material, added by you to a covered work,
for which you have or can give appropriate copyright permission.
Notwithstanding any other provision of this License, for material you
add to a covered work, you may (if authorized by the copyright holders of
that material) supplement the terms of this License with terms:
a) Disclaiming warranty or limiting liability differently from the
terms of sections 15 and 16 of this License; or
b) Requiring preservation of specified reasonable legal notices or
author attributions in that material or in the Appropriate Legal
Notices displayed by works containing it; or
c) Prohibiting misrepresentation of the origin of that material, or
requiring that modified versions of such material be marked in
reasonable ways as different from the original version; or
d) Limiting the use for publicity purposes of names of licensors or
authors of the material; or
e) Declining to grant rights under trademark law for use of some
trade names, trademarks, or service marks; or
f) Requiring indemnification of licensors and authors of that
material by anyone who conveys the material (or modified versions of
it) with contractual assumptions of liability to the recipient, for
any liability that these contractual assumptions directly impose on
those licensors and authors.
All other non-permissive additional terms are considered "further
restrictions" within the meaning of section 10. If the Program as you
received it, or any part of it, contains a notice stating that it is
governed by this License along with a term that is a further
restriction, you may remove that term. If a license document contains
a further restriction but permits relicensing or conveying under this
License, you may add to a covered work material governed by the terms
of that license document, provided that the further restriction does
not survive such relicensing or conveying.
If you add terms to a covered work in accord with this section, you
must place, in the relevant source files, a statement of the
additional terms that apply to those files, or a notice indicating
where to find the applicable terms.
Additional terms, permissive or non-permissive, may be stated in the
form of a separately written license, or stated as exceptions;
the above requirements apply either way.
8. Termination.
You may not propagate or modify a covered work except as expressly
provided under this License. Any attempt otherwise to propagate or
modify it is void, and will automatically terminate your rights under
this License (including any patent licenses granted under the third
paragraph of section 11).
However, if you cease all violation of this License, then your
license from a particular copyright holder is reinstated (a)
provisionally, unless and until the copyright holder explicitly and
finally terminates your license, and (b) permanently, if the copyright
holder fails to notify you of the violation by some reasonable means
prior to 60 days after the cessation.
Moreover, your license from a particular copyright holder is
reinstated permanently if the copyright holder notifies you of the
violation by some reasonable means, this is the first time you have
received notice of violation of this License (for any work) from that
copyright holder, and you cure the violation prior to 30 days after
your receipt of the notice.
Termination of your rights under this section does not terminate the
licenses of parties who have received copies or rights from you under
this License. If your rights have been terminated and not permanently
reinstated, you do not qualify to receive new licenses for the same
material under section 10.
9. Acceptance Not Required for Having Copies.
You are not required to accept this License in order to receive or
run a copy of the Program. Ancillary propagation of a covered work
occurring solely as a consequence of using peer-to-peer transmission
to receive a copy likewise does not require acceptance. However,
nothing other than this License grants you permission to propagate or
modify any covered work. These actions infringe copyright if you do
not accept this License. Therefore, by modifying or propagating a
covered work, you indicate your acceptance of this License to do so.
10. Automatic Licensing of Downstream Recipients.
Each time you convey a covered work, the recipient automatically
receives a license from the original licensors, to run, modify and
propagate that work, subject to this License. You are not responsible
for enforcing compliance by third parties with this License.
An "entity transaction" is a transaction transferring control of an
organization, or substantially all assets of one, or subdividing an
organization, or merging organizations. If propagation of a covered
work results from an entity transaction, each party to that
transaction who receives a copy of the work also receives whatever
licenses to the work the party's predecessor in interest had or could
give under the previous paragraph, plus a right to possession of the
Corresponding Source of the work from the predecessor in interest, if
the predecessor has it or can get it with reasonable efforts.
You may not impose any further restrictions on the exercise of the
rights granted or affirmed under this License. For example, you may
not impose a license fee, royalty, or other charge for exercise of
rights granted under this License, and you may not initiate litigation
(including a cross-claim or counterclaim in a lawsuit) alleging that
any patent claim is infringed by making, using, selling, offering for
sale, or importing the Program or any portion of it.
11. Patents.
A "contributor" is a copyright holder who authorizes use under this
License of the Program or a work on which the Program is based. The
work thus licensed is called the contributor's "contributor version".
A contributor's "essential patent claims" are all patent claims
owned or controlled by the contributor, whether already acquired or
hereafter acquired, that would be infringed by some manner, permitted
by this License, of making, using, or selling its contributor version,
but do not include claims that would be infringed only as a
consequence of further modification of the contributor version. For
purposes of this definition, "control" includes the right to grant
patent sublicenses in a manner consistent with the requirements of
this License.
Each contributor grants you a non-exclusive, worldwide, royalty-free
patent license under the contributor's essential patent claims, to
make, use, sell, offer for sale, import and otherwise run, modify and
propagate the contents of its contributor version.
In the following three paragraphs, a "patent license" is any express
agreement or commitment, however denominated, not to enforce a patent
(such as an express permission to practice a patent or covenant not to
sue for patent infringement). To "grant" such a patent license to a
party means to make such an agreement or commitment not to enforce a
patent against the party.
If you convey a covered work, knowingly relying on a patent license,
and the Corresponding Source of the work is not available for anyone
to copy, free of charge and under the terms of this License, through a
publicly available network server or other readily accessible means,
then you must either (1) cause the Corresponding Source to be so
available, or (2) arrange to deprive yourself of the benefit of the
patent license for this particular work, or (3) arrange, in a manner
consistent with the requirements of this License, to extend the patent
license to downstream recipients. "Knowingly relying" means you have
actual knowledge that, but for the patent license, your conveying the
covered work in a country, or your recipient's use of the covered work
in a country, would infringe one or more identifiable patents in that
country that you have reason to believe are valid.
If, pursuant to or in connection with a single transaction or
arrangement, you convey, or propagate by procuring conveyance of, a
covered work, and grant a patent license to some of the parties
receiving the covered work authorizing them to use, propagate, modify
or convey a specific copy of the covered work, then the patent license
you grant is automatically extended to all recipients of the covered
work and works based on it.
A patent license is "discriminatory" if it does not include within
the scope of its coverage, prohibits the exercise of, or is
conditioned on the non-exercise of one or more of the rights that are
specifically granted under this License. You may not convey a covered
work if you are a party to an arrangement with a third party that is
in the business of distributing software, under which you make payment
to the third party based on the extent of your activity of conveying
the work, and under which the third party grants, to any of the
parties who would receive the covered work from you, a discriminatory
patent license (a) in connection with copies of the covered work
conveyed by you (or copies made from those copies), or (b) primarily
for and in connection with specific products or compilations that
contain the covered work, unless you entered into that arrangement,
or that patent license was granted, prior to 28 March 2007.
Nothing in this License shall be construed as excluding or limiting
any implied license or other defenses to infringement that may
otherwise be available to you under applicable patent law.
12. No Surrender of Others' Freedom.
If conditions are imposed on you (whether by court order, agreement or
otherwise) that contradict the conditions of this License, they do not
excuse you from the conditions of this License. If you cannot convey a
covered work so as to satisfy simultaneously your obligations under this
License and any other pertinent obligations, then as a consequence you may
not convey it at all. For example, if you agree to terms that obligate you
to collect a royalty for further conveying from those to whom you convey
the Program, the only way you could satisfy both those terms and this
License would be to refrain entirely from conveying the Program.
13. Use with the GNU Affero General Public License.
Notwithstanding any other provision of this License, you have
permission to link or combine any covered work with a work licensed
under version 3 of the GNU Affero General Public License into a single
combined work, and to convey the resulting work. The terms of this
License will continue to apply to the part which is the covered work,
but the special requirements of the GNU Affero General Public License,
section 13, concerning interaction through a network will apply to the
combination as such.
14. Revised Versions of this License.
The Free Software Foundation may publish revised and/or new versions of
the GNU General Public License from time to time. Such new versions will
be similar in spirit to the present version, but may differ in detail to
address new problems or concerns.
Each version is given a distinguishing version number. If the
Program specifies that a certain numbered version of the GNU General
Public License "or any later version" applies to it, you have the
option of following the terms and conditions either of that numbered
version or of any later version published by the Free Software
Foundation. If the Program does not specify a version number of the
GNU General Public License, you may choose any version ever published
by the Free Software Foundation.
If the Program specifies that a proxy can decide which future
versions of the GNU General Public License can be used, that proxy's
public statement of acceptance of a version permanently authorizes you
to choose that version for the Program.
Later license versions may give you additional or different
permissions. However, no additional obligations are imposed on any
author or copyright holder as a result of your choosing to follow a
later version.
15. Disclaimer of Warranty.
THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY
APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT
HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY
OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO,
THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM
IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF
ALL NECESSARY SERVICING, REPAIR OR CORRECTION.
16. Limitation of Liability.
IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS
THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY
GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE
USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF
DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD
PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS),
EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF
SUCH DAMAGES.
17. Interpretation of Sections 15 and 16.
If the disclaimer of warranty and limitation of liability provided
above cannot be given local legal effect according to their terms,
reviewing courts shall apply local law that most closely approximates
an absolute waiver of all civil liability in connection with the
Program, unless a warranty or assumption of liability accompanies a
copy of the Program in return for a fee.
END OF TERMS AND CONDITIONS
How to Apply These Terms to Your New Programs
If you develop a new program, and you want it to be of the greatest
possible use to the public, the best way to achieve this is to make it
free software which everyone can redistribute and change under these terms.
To do so, attach the following notices to the program. It is safest
to attach them to the start of each source file to most effectively
state the exclusion of warranty; and each file should have at least
the "copyright" line and a pointer to where the full notice is found.
<one line to give the program's name and a brief idea of what it does.>
Copyright (C) <year> <name of author>
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <https://www.gnu.org/licenses/>.
Also add information on how to contact you by electronic and paper mail.
If the program does terminal interaction, make it output a short
notice like this when it starts in an interactive mode:
<program> Copyright (C) <year> <name of author>
This program comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
This is free software, and you are welcome to redistribute it
under certain conditions; type `show c' for details.
The hypothetical commands `show w' and `show c' should show the appropriate
parts of the General Public License. Of course, your program's commands
might be different; for a GUI interface, you would use an "about box".
You should also get your employer (if you work as a programmer) or school,
if any, to sign a "copyright disclaimer" for the program, if necessary.
For more information on this, and how to apply and follow the GNU GPL, see
<https://www.gnu.org/licenses/>.
The GNU General Public License does not permit incorporating your program
into proprietary programs. If your program is a subroutine library, you
may consider it more useful to permit linking proprietary applications with
the library. If this is what you want to do, use the GNU Lesser General
Public License instead of this License. But first, please read
<https://www.gnu.org/licenses/why-not-lgpl.html>.

@ -0,0 +1,79 @@
namespace DownKyi.Images
{
public class ButtonIcon
{
private static ButtonIcon instance;
public static ButtonIcon Instance()
{
if (instance == null)
{
instance = new ButtonIcon();
}
return instance;
}
public ButtonIcon()
{
GeneralSearch = new VectorImage
{
Height = 20,
Width = 20,
Data = @"M697.91 755.7 q-132.36 103.48 -290.59 98.06 q-158.23 -5.41 -278.56 -120.92 q-127.54 -133.56 -128.75 -304.43
q-1.21 -170.86 120.33 -304.43 q127.55 -126.34 297.21 -123.94 q169.66 2.41 303.22 123.94 q110.71 114.31 122.14 263.52
q11.43 149.21 -75.21 275.55 l238.25 239.45 q18.05 18.05 18.05 42.12 q0 24.06 -18.05 41.51 q-18.05 17.45 -42.12 17.45
q-24.07 0 -42.12 -16.85 l-223.81 -231.03 ZM643.76 647.41 q92.66 -96.26 92.66 -219 q0 -122.73 -92.66 -218.99 q-96.26 -92.66 -219 -92.66
q-122.74 0 -218.99 92.66 q-92.65 96.26 -92.65 218.99 q0 122.74 92.65 219 q96.26 92.65 218.99 90.25 q122.74 -2.4 219 -90.25 Z",
Fill = "#FF000000"
};
Settings = new VectorImage
{
Height = 32,
Width = 32,
Data = @"M19.4,13c0-0.3,0.1-0.6,0.1-1s0-0.7-0.1-1l2.1-1.7c0.2-0.2,0.2-0.4,0.1-0.6l-2-3.5C19.5,5,19.3,5,19,5l-2.5,1
c-0.5-0.4-1.1-0.7-1.7-1l-0.4-2.7C14.5,2.2,14.3,2,14,2h-4C9.8,2,9.5,2.2,9.5,2.4L9.1,5.1C8.5,5.3,8,5.7,7.4,6L5,5
C4.7,5,4.5,5,4.3,5.3l-2,3.5C2.2,9,2.3,9.2,2.5,9.4L4.6,11c0,0.3-0.1,0.6-0.1,1s0,0.7,0.1,1l-2.1,1.7c-0.2,0.1-0.2,0.4-0.1,0.6
l2,3.5C4.5,19,4.7,19,5,19l2.5-1c0.5,0.4,1.1,0.7,1.7,1l0.4,2.7c0,0.2,0.2,0.4,0.5,0.4h4c0.3,0,0.5-0.2,0.5-0.4l0.4-2.7
c0.6-0.3,1.2-0.6,1.7-1l2.5,1c0.2,0.1,0.5,0,0.6-0.2l2-3.5c0.1-0.2,0.1-0.5-0.1-0.6L19.4,13z M12,15.5c-1.9,0-3.5-1.6-3.5-3.5
s1.6-3.5,3.5-3.5s3.5,1.6,3.5,3.5S13.9,15.5,12,15.5z",
Fill = "#FF000000"
};
DownloadManage = new VectorImage
{
Height = 27,
Width = 32,
//Height = 20,
//Width = 24,
Data = @"M24,34c-2.4,0-4.9,0-7.3,0c-2.8,0-4.6-1.9-4.6-4.7c0-3.5,0-7,0-10.5c0-2.9,1.9-4.7,4.6-4.7c1.3,0,2.6,0,3.9,0
c1.1-0.1,2,0.4,2.7,1.3c1.1,1.7,2.6,2.3,4.6,2.1c1.3-0.2,2.6-0.1,4,0c2.5,0.2,4,1.7,4.2,4.3c0.2,2.7,0.2,5.5,0,8.3
c-0.2,2.4-2,4-4.3,4C29,34,26.5,34,24,34L24,34z
M23.9,32.6c2.5,0,5,0,7.5,0c1.7,0,2.9-1,3-2.7c0.2-2.8,0.2-5.6,0-8.5
c-0.1-1.5-1.1-2.4-2.5-2.6c-1.3-0.2-2.6-0.1-3.9-0.1c-4.1-0.1-3,0.5-6-2.6c-0.5-0.5-1-0.8-1.7-0.8c-1.3,0-2.5,0-3.8,0
c-2,0-3.2,1.2-3.3,3.2c0,3.6,0,7.1,0,10.7c0,2,1.2,3.2,3.2,3.2C19,32.6,21.5,32.6,23.9,32.6L23.9,32.6z
M29.9,14.2h3.3c0.5,0,0.9,0,0.9,0.7c0,0.7-0.4,0.8-0.9,0.8c-2.2,0-4.5,0-6.7,0c-0.5,0-0.9-0.1-0.9-0.7
s0.4-0.7,0.9-0.7C27.6,14.2,28.7,14.2,29.9,14.2L29.9,14.2z M23.3,27.6v-5.4c0-0.5,0-1.1,0.7-1.1c0.7,0,0.6,0.6,0.6,1v5.2
c0.7-0.7,1.2-1.2,1.7-1.7c0.3-0.4,0.7-0.7,1.2-0.2c0.5,0.5,0.1,0.9-0.2,1.2c-0.9,1-1.8,1.9-2.7,2.8c-0.4,0.5-0.8,0.5-1.3,0.1
c-1-1-2-2.1-3-3.1c-0.3-0.3-0.4-0.7-0.1-1c0.3-0.4,0.7-0.3,1,0.1C22,26.1,22.6,26.7,23.3,27.6L23.3,27.6z",
Fill = "#FF000000"
};
Toolbox = new VectorImage
{
Height = 28, // 21
Width = 32, // 24
Data = @"M20.2,14.5c-0.8,2.3-3.4,3.6-5.7,2.7c-1.3-0.5-2.3-1.5-2.7-2.7H5.5V13h21v1.5H20.2z M18.6,14.5h-5.2
c0.8,1.4,2.7,1.9,4.1,1.1C18,15.3,18.3,15,18.6,14.5L18.6,14.5z M10,8.5V7c0-0.8,0.7-1.5,1.5-1.5h9C21.3,5.5,22,6.2,22,7v1.5h4.5
c0.8,0,1.5,0.7,1.5,1.5v15c0,0.8-0.7,1.5-1.5,1.5l0,0h-21C4.7,26.5,4,25.8,4,25l0,0V10c0-0.8,0.7-1.5,1.5-1.5H10z M11.5,8.5h9V7h-9
V8.5z M5.5,10v15h21V10H5.5z",
Fill = "#FF000000"
};
}
public VectorImage GeneralSearch { get; private set; }
public VectorImage Settings { get; private set; }
public VectorImage DownloadManage { get; private set; }
public VectorImage Toolbox { get; private set; }
}
}

@ -0,0 +1,54 @@
namespace DownKyi.Images
{
class LogoIcon
{
private static LogoIcon instance;
public static LogoIcon Instance()
{
if (instance == null)
{
instance = new LogoIcon();
}
return instance;
}
private LogoIcon()
{
TextLogo = new VectorImage
{
Height = 100,
Width = 336,
Data = @"M602.247902 495.326917q0-146.045116 60.22479-219.820484a198.13956 198.13956 0 0 1 308.953174 0q61.73041
74.076492 62.031534 213.798005 0 150.561976-60.22479 225.54184a198.13956 198.13956 0 0 1-309.254298 0Q602.247902 640.468662
602.247902 495.326917z m80.098971 0A273.721671 273.721671 0 0 0 722.697482 657.331603a120.44958 120.44958 0 0 0 98.467532
53.298939 115.029349 115.029349 0 0 0 94.251797-53.901187 273.420548 273.420548 0 0 0 39.447238-161.703562 271.011556
271.011556 0 0 0-39.748362-162.004685 120.44958 120.44958 0 0 0-98.467532-53.29894A114.125977 114.125977 0 0 0 722.697482
333.322232a271.011556 271.011556 0 0 0-39.748361 161.703561zM1212.023903 776.275564L1070.194522 214.077147h80.701219l73.474244
324.611619 27.101155 120.449581 24.391041-116.836093L1349.035301 214.077147h80.701218l68.656261 326.117239 23.186545 107.501251
26.498907-108.705747L1626.069336 214.077147h76.184359l-143.335001 562.198417h-81.303466l-73.474244-336.656578-17.46519-95.757416L1294.832989
776.275564zM1768.500964 776.275564V214.077147h70.463005v79.496723a180.674371 180.674371 0 0 1 62.031534-69.258509 154.476587
154.476587 0 0 1 84.314706-22.88542 161.703562 161.703562 0 0 1 68.355137 14.45395 140.624885 140.624885 0 0 1 50.588824
38.242742 153.874339 153.874339 0 0 1 30.112395 60.22479 509.802849 509.802849 0 0 1 9.635966
115.330473v346.593668h-79.195599V433.897631a279.141903 279.141903 0 0 0-10.539338-90.337185 87.62707 87.62707 0 0
0-85.218078-60.22479 109.00687 109.00687 0 0 0-90.337186 41.856229q-33.424759 42.157353-33.424758 143.636125v307.447554zM2270.775715
776.275564V0.279142h84.314706v384.836409L2670.969446 0.279142h114.427101l-267.096945 314.674529 278.539655
461.321893h-111.114738l-225.842963-391.461137-104.791135 123.46082v268.903689zM2853.149436 993.98818l-8.732595-90.337185a146.34624
146.34624 0 0 0 44.566345 8.431471 78.292227 78.292227 0 0 0 41.253981-9.937091 76.786608 76.786608 0 0 0 26.498908-30.112395c2.710116-5.119107
12.94833-36.134874 30.112395-93.348425L2812.196579 214.077147h84.314706l96.359664 325.514991c12.044958 40.350609
22.88542 83.712458 33.123635 130.085547 9.033719-43.662973 19.573057-86.422574 31.919139-127.977679l98.467532-327.622859h78.292227l-174.953016
572.135507a1012.679847 1012.679847 0 0 1-54.202311 147.550736 141.227133 141.227133 0 0 1-45.168592 53.600063 103.285515 103.285515 0 0
1-56.912427 16.561818 132.494538 132.494538 0 0 1-50.2877-9.937091zM3300.318503 109.88826V0.279142h77.68998v109.609118z
m0 666.387304V214.077147h77.68998v562.198417zM0 776.275564V0.279142h219.51936a417.357796 417.357796 0 0 1 124.063068
14.152826 210.786766 210.786766 0 0 1 96.359664 67.752889 358.337502 358.337502 0 0 1 63.537154 124.364191 616.400728 616.400728 0 0 1
22.584296 177.362008 579.663606 579.663606 0 0 1-38.543865 223.735095 273.420548 273.420548 0 0 1-99.370904 130.386671 294.1981
294.1981 0 0 1-158.391198 38.242742zM463.730885 391.740278q10.840462-7.528099
0-16.260693l-51.79332-30.112395q-136.40915-82.507963-276.431787-150.561976l-13.249454-6.624727a22.283172 22.283172
0 0 0-16.561817 0v405.613962a18.669685 18.669685 0 0 0 14.755073-4.817983q148.152984-76.786608 296.607092-164.413677c15.357322-10.238214
31.015767-21.379801 46.674213-32.822511z",
Fill = "#FF000000"
};
}
public VectorImage TextLogo { get; private set; }
}
}

@ -0,0 +1,29 @@
namespace DownKyi.Images
{
public class NavigationIcon
{
private static NavigationIcon instance;
public static NavigationIcon Instance()
{
if (instance == null)
{
instance = new NavigationIcon();
}
return instance;
}
public NavigationIcon()
{
ArrowBack = new VectorImage
{
Height = 24,
Width = 24,
Data = @"M16.62 2.99c-.49-.49-1.28-.49-1.77 0L6.54 11.3c-.39.39-.39 1.02 0 1.41l8.31 8.31c.49.49 1.28.49 1.77
0s.49-1.28 0-1.77L9.38 12l7.25-7.25c.48-.48.48-1.28-.01-1.76z",
Fill = "#FF000000"
};
}
public VectorImage ArrowBack { get; private set; }
}
}

@ -0,0 +1,68 @@
namespace DownKyi.Images
{
public class NormalIcon
{
private static NormalIcon instance;
public static NormalIcon Instance()
{
if (instance == null)
{
instance = new NormalIcon();
}
return instance;
}
public NormalIcon()
{
CloudDownload = new VectorImage
{
Height = 32,
Width = 48,
Data = @"M19.4,10c-0.7-3.4-3.7-6-7.4-6C9.1,4,6.6,5.6,5.3,8C2.3,8.4,0,10.9,0,14c0,3.3,2.7,6,6,6h13c2.8,0,5-2.2,5-5
C24,12.4,22,10.2,19.4,10z M19,18H6c-2.2,0-4-1.8-4-4c0-2.1,1.5-3.8,3.6-4l1.1-0.1L7.1,9C8.1,7.1,9.9,6,12,6c2.6,0,4.9,1.9,5.4,4.4
l0.3,1.5l1.5,0.1c1.6,0.1,2.8,1.4,2.8,3C22,16.6,20.6,18,19,18z M13.4,10h-2.9v3H8l4,4l4-4h-2.6V10z",
Fill = "#FF000000"
};
Folder = new VectorImage
{
Height = 32,
Width = 40,
Data = @"M20 6h-8l-2-2H4c-1.1 0-1.99.9-1.99 2L2 18c0 1.1.9 2 2 2h16c1.1 0 2-.9 2-2V8c0-1.1-.9-2-2-2zm0 12H4V8h16v10z",
Fill = "#FF000000"
};
Downloading = new VectorImage
{
Height = 16,
Width = 16,
Data = @"M1,11.7c0.6,0,1,0.5,1,1V24H1.4C0.6,24,0,23.4,0,22.6c0,0,0,0,0,0v-9.9C0,12.1,0.5,11.7,1,11.7C1,11.7,1,11.7,1,11.7z
M0,21.9h24v0.7c0,0.8-0.6,1.4-1.3,1.4H1.4C0.6,24,0,23.4,0,22.6V21.9z
M23,11.7c0.6,0,1,0.5,1,1v9.9c0,0.8-0.6,1.4-1.3,1.4H22V12.7C22,12.1,22.5,11.7,23,11.7C23,11.7,23,11.7,23,11.7z M13,17.4
h-2V1c0-0.6,0.4-1,1-1s1,0.5,1,1c0,0,0,0,0,0V17.4z
M6.9,12.5c0.4-0.4,1-0.4,1.4,0l4.9,5.1L12.8,18c-0.5,0.5-1.4,0.5-1.9,0l-4-4.1C6.5,13.5,6.5,12.9,6.9,12.5L6.9,12.5z
M16.8,12.5c0.4,0.4,0.4,1.1,0,1.5l-4,4.1c-0.5,0.5-1.4,0.5-1.9,0l-0.5-0.5l4.9-5.1C15.8,12.1,16.4,12.1,16.8,12.5L16.8,12.5z",
Fill = "#FF000000"
};
DownloadFinished = new VectorImage
{
Height = 16,
Width = 16,
Data = @"M12,0C8.6,0.1,5.8,1.3,3.5,3.5S0.1,8.6,0,12c0.1,3.4,1.3,6.2,3.5,8.5S8.6,23.9,12,24c3.4-0.1,6.2-1.3,8.5-3.5
s3.4-5.1,3.5-8.5c-0.1-3.4-1.3-6.2-3.5-8.5S15.4,0.1,12,0z M12,22.5c-3-0.1-5.5-1.1-7.4-3.1S1.6,15,1.5,12c0.1-3,1.1-5.5,3.1-7.4
S9,1.6,12,1.5c3,0.1,5.5,1.1,7.4,3.1s3,4.4,3.1,7.4c-0.1,3-1.1,5.5-3.1,7.4S15,22.4,12,22.5z
M16.5,8.1c0.2-0.2,0.4-0.2,0.6-0.2c0.5,0,0.9,0.4,0.9,0.9c0,0.2-0.1,0.5-0.2,0.6l-6.5,6.5
c-0.2,0.2-0.4,0.3-0.6,0.3c-0.2,0-0.5-0.1-0.7-0.3l-3.8-3.7C6.1,12,6,11.7,6,11.5c0-0.2,0.1-0.5,0.3-0.6c0.2-0.2,0.4-0.3,0.6-0.3
c0.2,0,0.5,0.1,0.6,0.2l3.1,3.1L16.5,8.1L16.5,8.1z",
Fill = "#FF000000"
};
}
public VectorImage CloudDownload { get; private set; }
public VectorImage Folder { get; private set; }
public VectorImage Downloading { get; private set; }
public VectorImage DownloadFinished { get; private set; }
}
}

@ -0,0 +1,76 @@
namespace DownKyi.Images
{
public class SystemIcon
{
private static SystemIcon instance;
public static SystemIcon Instance()
{
if (instance == null)
{
instance = new SystemIcon();
}
return instance;
}
private SystemIcon()
{
Close = new VectorImage
{
Height = 12,
Width = 12,
Data = @"M25,23.9l-6.6-6.6c-0.3-0.3-0.9-0.3-1.1,0c-0.3,0.3-0.3,0.9,0,1.1l0,0l6.6,6.6l-6.6,6.6c-0.3,0.3-0.3,0.9,0,1.1
c0.3,0.3,0.9,0.3,1.1,0l0,0l6.6-6.6l6.6,6.6c0.3,0.3,0.9,0.3,1.1,0.1c0.3-0.3,0.3-0.9,0.1-1.1c0,0,0,0-0.1-0.1L26.1,25l6.6-6.6
c0.3-0.3,0.3-0.9,0-1.1c-0.3-0.3-0.9-0.3-1.1,0l0,0L25,23.9L25,23.9z",
Fill = "#FF000000"
};
Maximize = new VectorImage
{
Height = 12,
Width = 12,
Data = @"M31.1,33H18.9c-1,0-1.9-0.9-1.9-1.9V18.9c0-1,0.9-1.9,1.9-1.9h12.3c1,0,1.9,0.9,1.9,1.9v12.3C33,32.1,32.1,33,31.1,33z
M18.9,18.3c-0.3,0-0.6,0.3-0.6,0.6v12.3c0,0.3,0.3,0.6,0.6,0.6h12.3c0.3,0,0.6-0.3,0.6-0.6V18.9c0-0.3-0.3-0.6-0.6-0.6
C31.1,18.3,18.9,18.3,18.9,18.3z",
Fill = "#FF000000"
};
Minimize = new VectorImage
{
Height = 1.2,
Width = 12,
Data = @"M17.8,25.8c-0.5,0-0.8-0.3-0.8-0.8s0.3-0.8,0.8-0.8h14.4c0.5,0,0.8,0.3,0.8,0.8s-0.3,0.8-0.8,0.8H17.8z",
Fill = "#FF000000"
};
Restore = new VectorImage
{
Height = 12,
Width = 12,
Data = @"M29,33H18.3c-0.7,0-1.3-0.6-1.3-1.3V21c0-0.7,0.6-1.3,1.3-1.3H29c0.7,0,1.3,0.6,1.3,1.3v10.7C30.4,32.4,29.8,33,29,33z
M18.3,20.9c-0.1,0-0.1,0.1-0.1,0.1v10.7c0,0.1,0.1,0.1,0.1,0.1H29c0.1,0,0.1-0.1,0.1-0.1V21c0-0.1-0.1-0.1-0.1-0.1H18.3z
M31.7,30.4h-1.9v-1.2h1.9c0.1,0,0.1-0.1,0.1-0.1V18.3c0-0.1-0.1-0.1-0.1-0.1H21c-0.1,0-0.1,0.1-0.1,0.1v1.9h-1.2v-1.9
c0-0.7,0.6-1.3,1.3-1.3h10.7c0.7,0,1.3,0.6,1.3,1.3v10.7C33,29.8,32.4,30.4,31.7,30.4z",
Fill = "#FF000000"
};
Skin = new VectorImage
{
Height = 12,
Width = 12,
Data = @"M29.1,18.1l2.7,3.2l-1.3,1.6c-0.1-0.1-0.3-0.1-0.5-0.1c-0.6,0-1,0.5-1,1.2v8.1h-8.2v-8.1c0-0.7-0.5-1.2-1-1.2
c-0.1,0-0.3,0-0.5,0.1l-1.3-1.6l2.7-3.2h0.8c0.7,0.9,2.4,1.5,3.3,1.5c0.9,0,2.6-0.4,3.3-1.5H29.1 M29.2,17h-0.9
c-0.2,0-0.5,0.1-0.7,0.4c-0.5,0.5-1.8,1.1-2.6,1.1c-0.8,0-2.2-0.5-2.6-1.2c-0.2-0.1-0.5-0.3-0.7-0.3h-0.9c-0.2,0-0.5,0.1-0.6,0.3
l-3.1,3.6c-0.1,0.3-0.1,0.7,0,0.8l1.8,2.2C19,24,19.3,24,19.4,24s0.2,0,0.3-0.1v-0.1h0.1c0,0,0.1,0,0.1,0.1v8.2
c0,0.5,0.3,0.9,0.8,0.9h8.6c0.5,0,0.8-0.4,0.8-0.9v-8.2c0-0.1,0-0.1,0.1-0.1h0.1l0.1,0.1c0.1,0.1,0.2,0.1,0.3,0.1s0.2,0,0.3-0.1
l1.8-2.2c0-0.1,0-0.5-0.1-0.8l-3.1-3.6C29.7,17.1,29.5,17,29.2,17z",
Fill = "#FF000000"
};
}
public VectorImage Close { get; private set; }
public VectorImage Maximize { get; private set; }
public VectorImage Minimize { get; private set; }
public VectorImage Restore { get; private set; }
public VectorImage Skin { get; private set; }
}
}

@ -0,0 +1,36 @@
using Prism.Mvvm;
namespace DownKyi.Images
{
public class VectorImage : BindableBase
{
private double width;
public double Width
{
get { return width; }
set { SetProperty(ref width, value); }
}
private double height;
public double Height
{
get { return height; }
set { SetProperty(ref height, value); }
}
private string data;
public string Data
{
get { return data; }
set { SetProperty(ref data, value); }
}
private string fill;
public string Fill
{
get { return fill; }
set { SetProperty(ref fill, value); }
}
}
}

@ -0,0 +1,199 @@
<ResourceDictionary
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="clr-namespace:DownKyi.Languages"
xmlns:system="clr-namespace:System;assembly=mscorlib">
<!-- App -->
<system:String x:Key="AppName">哔哩下载姬</system:String>
<system:String x:Key="Unknown">未知</system:String>
<!-- 系统 -->
<system:String x:Key="Close">关闭</system:String>
<system:String x:Key="Maximize">最大化</system:String>
<system:String x:Key="Minimize">最小化</system:String>
<system:String x:Key="Restore">还原</system:String>
<system:String x:Key="Skin">皮肤</system:String>
<!-- Index -->
<system:String x:Key="Login">登录</system:String>
<system:String x:Key="IndexHintText">请输入B站网址链接或av、BV号等……</system:String>
<system:String x:Key="IndexHintTextSimple">请输入B站视频播放地址……</system:String>
<system:String x:Key="Settings">设置</system:String>
<system:String x:Key="DownloadManager">下载管理</system:String>
<system:String x:Key="Toolbox">工具箱</system:String>
<!-- Login -->
<system:String x:Key="ScanToLogin">扫描二维码登录</system:String>
<system:String x:Key="ScanLoginTip" xml:space="preserve">请使用哔哩哔哩客户端&#x000A;扫码登录&#x000A;或扫码下载APP</system:String>
<system:String x:Key="GetLoginUrlFailed">获取登录链接失败!</system:String>
<system:String x:Key="LoginKeyError">密钥错误!尝试重新获取!</system:String>
<system:String x:Key="LoginTimeOut">已超时!尝试重新获取二维码!</system:String>
<system:String x:Key="LoginSuccessful">登录成功!(3秒后自动回到主页)</system:String>
<system:String x:Key="LoginFailed">未保存登录信息!(3秒后自动回到主页)</system:String>
<!-- VideoDetail -->
<system:String x:Key="CopyCover">复制封面图片</system:String>
<system:String x:Key="CopyCoverUrl">复制封面URL</system:String>
<system:String x:Key="Play">播放</system:String>
<system:String x:Key="Danmaku">弹幕</system:String>
<system:String x:Key="Like">点赞</system:String>
<system:String x:Key="Coin">投币</system:String>
<system:String x:Key="Favorite">收藏</system:String>
<system:String x:Key="Share">分享</system:String>
<system:String x:Key="Reply">评论</system:String>
<system:String x:Key="Anime">番剧</system:String>
<system:String x:Key="Movie">电影</system:String>
<system:String x:Key="Documentary">纪录片</system:String>
<system:String x:Key="Guochuang">国创</system:String>
<system:String x:Key="TV">电视剧</system:String>
<system:String x:Key="Entertainment">综艺</system:String>
<system:String x:Key="Cheese">课程</system:String>
<system:String x:Key="Order">序号</system:String>
<system:String x:Key="Name">名称</system:String>
<system:String x:Key="Duration">时长</system:String>
<system:String x:Key="AudioQuality">音质</system:String>
<system:String x:Key="VideoQuality">画质</system:String>
<system:String x:Key="VideoCodec">视频编码</system:String>
<system:String x:Key="SelectAll">全选</system:String>
<system:String x:Key="Parse">解析</system:String>
<system:String x:Key="ParseVideo">解析视频</system:String>
<system:String x:Key="DownloadSelected">下载选中项</system:String>
<!-- DownloadManager -->
<system:String x:Key="Downloading">正在下载</system:String>
<system:String x:Key="DownloadFinished">已下载</system:String>
<!-- Settings -->
<system:String x:Key="PressEnterToApplySettingTip">按回车键应用设置</system:String>
<system:String x:Key="Basic">基本</system:String>
<system:String x:Key="AfterDownloadOperation">下载完成后的动作:</system:String>
<system:String x:Key="AfterDownloadOperationNone">无</system:String>
<system:String x:Key="AfterDownloadOperationCloseApp">关闭程序</system:String>
<system:String x:Key="AfterDownloadOperationCloseSystem">关闭计算机</system:String>
<system:String x:Key="ListenClipboard">监听剪贴板</system:String>
<system:String x:Key="VideoAutoParse">视频自动解析</system:String>
<system:String x:Key="VideoParseScope">视频解析范围:</system:String>
<system:String x:Key="Network">网络</system:String>
<system:String x:Key="AriaServerPort">Aria服务器端口</system:String>
<system:String x:Key="AriaLogLevel">Aria日志等级</system:String>
<system:String x:Key="AriaMaxConcurrentDownloads">Aria同时下载数</system:String>
<system:String x:Key="AriaSplit">Aria最大线程数</system:String>
<system:String x:Key="AriaDownloadLimit">Aria下载速度限制(KB/s)</system:String>
<system:String x:Key="AriaMaxOverallDownloadLimit">全局下载速度限制[0: 无限制]</system:String>
<system:String x:Key="AriaMaxDownloadLimit">单任务下载速度限制[0: 无限制]</system:String>
<system:String x:Key="IsAriaHttpProxy">使用Http代理</system:String>
<system:String x:Key="AriaHttpProxy">代理地址:</system:String>
<system:String x:Key="AriaHttpProxyPort">端口:</system:String>
<system:String x:Key="AriaFileAllocation">Aria文件预分配</system:String>
<system:String x:Key="Video">视频</system:String>
<system:String x:Key="FirstVideoCodecs">优先下载的视频编码:</system:String>
<system:String x:Key="FirstVideoQuality">优先下载的视频画质:</system:String>
<system:String x:Key="IsAddVideoOrder">启用视频编号</system:String>
<system:String x:Key="IsAddVideoOrderTip">勾选后,将为下载完成的视频的文件名添加上序号</system:String>
<system:String x:Key="IsTranscodingFlvToMp4">下载FLV视频后转码为mp4</system:String>
<system:String x:Key="IsUseDefaultDirectory">使用默认下载目录</system:String>
<system:String x:Key="DefaultDirectory">默认下载目录:</system:String>
<system:String x:Key="DefaultDirectoryTip">默认将文件下载到该文件夹中</system:String>
<system:String x:Key="ChangeDirectory">更改目录</system:String>
<system:String x:Key="IsCreateFolderForMedia">为不同视频分别创建文件夹</system:String>
<system:String x:Key="IsDownloadDanmaku">在下载视频的同时下载弹幕</system:String>
<system:String x:Key="IsDownloadCover">在下载视频的同时下载封面</system:String>
<system:String x:Key="SettingDanmaku">弹幕</system:String>
<system:String x:Key="FilterType">按类型屏蔽</system:String>
<system:String x:Key="TopFilter">顶部</system:String>
<system:String x:Key="BottomFilter">底部</system:String>
<system:String x:Key="ScrollFilter">滚动</system:String>
<system:String x:Key="Resolution">分辨率:</system:String>
<system:String x:Key="FontName">字体名称:</system:String>
<system:String x:Key="FontSize">字体大小:</system:String>
<system:String x:Key="LineCount">限制行数:</system:String>
<system:String x:Key="LayoutAlgorithm">布局算法:</system:String>
<system:String x:Key="LayoutAlgorithmSync">速度同步</system:String>
<system:String x:Key="LayoutAlgorithmSyncTip">每一条滚动弹幕的移动速度都是相同的</system:String>
<system:String x:Key="LayoutAlgorithmAsync">速度异步</system:String>
<system:String x:Key="LayoutAlgorithmAsyncTip">弹幕滚动速度取决于它的文本长度</system:String>
<system:String x:Key="About">关于</system:String>
<system:String x:Key="GotoHomepage">访问主页</system:String>
<system:String x:Key="CurrentAppVersion">当前版本:</system:String>
<system:String x:Key="CheckUpdate">检查更新</system:String>
<system:String x:Key="Feedback">意见反馈</system:String>
<system:String x:Key="ReceiveBetaVersion">接收测试版更新</system:String>
<system:String x:Key="AutoUpdateWhenLaunch">启动时检查更新</system:String>
<system:String x:Key="TipSettingUpdated">设置已更新~</system:String>
<system:String x:Key="TipSettingFailed">设置失败!</system:String>
<system:String x:Key="ThirdParty">第三方</system:String>
<system:String x:Key="ThirdPartyName">名称</system:String>
<system:String x:Key="ThirdPartyAuthor">作者</system:String>
<system:String x:Key="ThirdPartyVersion">版本</system:String>
<system:String x:Key="ThirdPartyLicense">许可证</system:String>
<system:String x:Key="Disclaimer">免责申明</system:String>
<system:String x:Key="Disclaimer1">1. 本软件只提供视频解析,不提供任何资源上传、存储到服务器的功能。</system:String>
<system:String x:Key="Disclaimer2">2. 本软件仅解析来自B站的内容不会对解析到的音视频进行二次编码部分视频会进行有限的格式转换、拼接等操作。</system:String>
<system:String x:Key="Disclaimer3">3. 本软件解析得到的所有内容均来自B站UP主上传、分享其版权均归原作者所有。内容提供者、上传者UP主应对其提供、上传的内容承担全部责任。</system:String>
<system:String x:Key="Disclaimer4">4. 本软件提供的所有资源仅可用作学习交流使用未经原作者授权禁止用于其他用途。请在下载24小时内删除。为尊重作者版权请前往资源的原始发布网站观看支持原创谢谢。</system:String>
<system:String x:Key="Disclaimer5">5. 任何涉及商业盈利目的均不得使用,否则产生的一切后果将由您自己承担。</system:String>
<system:String x:Key="Disclaimer6">6. 因使用本软件产生的版权问题,软件作者概不负责。</system:String>
<!-- Toolbox -->
<system:String x:Key="BiliHelper">B站助手</system:String>
<system:String x:Key="AvidAndBvidConversion">AV和BV互转</system:String>
<system:String x:Key="AvidAndBvidConversionTip">AV号形如&quot;av123&quot;BV号形如&quot;BVxxx&quot;。</system:String>
<system:String x:Key="Avid">AVID:</system:String>
<system:String x:Key="Bvid">BVID:</system:String>
<system:String x:Key="GotoWeb">访问网页</system:String>
<system:String x:Key="DanmakuUserID">弹幕中的userID:</system:String>
<system:String x:Key="FindDanmakuSender">查询弹幕发送者-&gt;</system:String>
<system:String x:Key="Delogo">去水印</system:String>
<system:String x:Key="VideoFilePath">视频地址:</system:String>
<system:String x:Key="SelectVideo">选择视频</system:String>
<system:String x:Key="LogoSizeAndLocation">水印尺寸与位置(左上角为原点,单位:像素)</system:String>
<system:String x:Key="LogoWidth">宽:</system:String>
<system:String x:Key="LogoHeight">高:</system:String>
<system:String x:Key="LogoX">X</system:String>
<system:String x:Key="LogoY">Y</system:String>
<system:String x:Key="TipWaitTaskFinished">请等待当前任务完成!</system:String>
<system:String x:Key="TipNoSeletedVideo">没有选择视频!</system:String>
<system:String x:Key="TipInputRightLogoWidth">请输入正确的宽度(正整数)!</system:String>
<system:String x:Key="TipInputRightLogoHeight">请输入正确的高度(正整数)!</system:String>
<system:String x:Key="TipInputRightLogoX">请输入正确的X正整数</system:String>
<system:String x:Key="TipInputRightLogoY">请输入正确的Y正整数</system:String>
<system:String x:Key="OutputInfo">输出信息:</system:String>
<system:String x:Key="ExtractMedia">音视频分离</system:String>
<system:String x:Key="ExtractAudio">提取音频</system:String>
<system:String x:Key="ExtractVideo">提取视频</system:String>
<!-- Dialog -->
<system:String x:Key="Cancel">取消</system:String>
<system:String x:Key="SelectDirectory">请选择文件夹</system:String>
<!-- ViewDirectorySelector -->
<system:String x:Key="DownloadDirectorySelector">设置下载文件夹</system:String>
<system:String x:Key="Location">位置:</system:String>
<system:String x:Key="Browse">浏览</system:String>
<system:String x:Key="HardDiskFreeSpace">盘剩余空间:</system:String>
<system:String x:Key="IsDefaultDownloadDirectory">设此文件夹为默认下载文件夹</system:String>
<system:String x:Key="IsDefaultDownloadDirectoryTip">选中后下次将不会弹出此窗口</system:String>
<system:String x:Key="Download">下载</system:String>
<system:String x:Key="WarningNullDirectory">文件夹路径不能为空</system:String>
<!-- ViewParsingSelector -->
<system:String x:Key="ParsingSelector">选择解析项</system:String>
<system:String x:Key="ParseNone">无</system:String>
<system:String x:Key="ParseSelectedItem">解析选中项</system:String>
<system:String x:Key="ParseCurrentSection">解析当前页视频</system:String>
<system:String x:Key="ParseAll">解析所有视频</system:String>
<system:String x:Key="SetParseDefault">设为默认,下次不再弹出</system:String>
</ResourceDictionary>

@ -0,0 +1,173 @@
<ResourceDictionary
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="clr-namespace:DownKyi.Languages"
xmlns:system="clr-namespace:System;assembly=mscorlib">
<!-- App -->
<system:String x:Key="AppName">DownKyi</system:String>
<system:String x:Key="Unknown">Unknown</system:String>
<!-- 系统 -->
<system:String x:Key="Close">Close</system:String>
<system:String x:Key="Maximize">Maximize</system:String>
<system:String x:Key="Minimize">Minimize</system:String>
<system:String x:Key="Restore">Restore</system:String>
<system:String x:Key="Skin">Skin</system:String>
<!-- Index -->
<system:String x:Key="Login">Login</system:String>
<system:String x:Key="IndexHintText">Please input the Bilibili url, av id, and BV id etc.</system:String>
<system:String x:Key="Settings">Settings</system:String>
<system:String x:Key="DownloadManager">Download Manager</system:String>
<system:String x:Key="Toolbox">Toolbox</system:String>
<!-- Login -->
<system:String x:Key="ScanToLogin">Scan to Login</system:String>
<system:String x:Key="ScanLoginTip" xml:space="preserve">请使用哔哩哔哩客户端&#x000A;扫码登录&#x000A;或扫码下载APP</system:String>
<system:String x:Key="GetLoginUrlFailed">获取登录链接失败!</system:String>
<system:String x:Key="LoginKeyError">密钥错误!尝试重新获取!</system:String>
<system:String x:Key="LoginTimeOut">已超时!尝试重新获取二维码!</system:String>
<system:String x:Key="LoginSuccessful">登录成功!(3秒后自动回到主页)</system:String>
<system:String x:Key="LoginFailed">未保存登录信息!(3秒后自动回到主页)</system:String>
<!-- VideoDetail -->
<system:String x:Key="CopyCover">复制封面图片</system:String>
<system:String x:Key="CopyCoverUrl">复制封面URL</system:String>
<system:String x:Key="Play">播放</system:String>
<system:String x:Key="Danmaku">弹幕</system:String>
<system:String x:Key="Like">点赞</system:String>
<system:String x:Key="Coin">投币</system:String>
<system:String x:Key="Favorite">收藏</system:String>
<system:String x:Key="Share">分享</system:String>
<system:String x:Key="Reply">评论</system:String>
<system:String x:Key="Anime">番剧</system:String>
<system:String x:Key="Movie">电影</system:String>
<system:String x:Key="Documentary">纪录片</system:String>
<system:String x:Key="Guochuang">国创</system:String>
<system:String x:Key="TV">电视剧</system:String>
<system:String x:Key="Entertainment">综艺</system:String>
<system:String x:Key="Cheese">课程</system:String>
<system:String x:Key="Order">序号</system:String>
<system:String x:Key="Name">名称</system:String>
<system:String x:Key="Duration">时长</system:String>
<system:String x:Key="AudioQuality">音质</system:String>
<system:String x:Key="VideoQuality">画质</system:String>
<system:String x:Key="VideoCodec">视频编码</system:String>
<system:String x:Key="SelectAll">全选</system:String>
<system:String x:Key="Parse">解析</system:String>
<system:String x:Key="ParseVideo">解析视频</system:String>
<system:String x:Key="DownloadSelected">下载选中项</system:String>
<!-- DownloadManager -->
<system:String x:Key="Downloading">正在下载</system:String>
<system:String x:Key="DownloadFinished">已下载</system:String>
<!-- Settings -->
<system:String x:Key="PressEnterToApplySettingTip">按回车键应用设置</system:String>
<system:String x:Key="Basic">基本</system:String>
<system:String x:Key="AfterDownloadOperation">下载完成后的动作:</system:String>
<system:String x:Key="AfterDownloadOperationNone">无</system:String>
<system:String x:Key="AfterDownloadOperationCloseApp">关闭程序</system:String>
<system:String x:Key="AfterDownloadOperationCloseSystem">关闭计算机</system:String>
<system:String x:Key="ListenClipboard">监听剪贴板</system:String>
<system:String x:Key="VideoAutoParse">视频自动解析</system:String>
<system:String x:Key="VideoParseScope">视频解析范围:</system:String>
<system:String x:Key="Network">网络</system:String>
<system:String x:Key="AriaServerPort">Aria服务器端口</system:String>
<system:String x:Key="AriaLogLevel">Aria日志等级</system:String>
<system:String x:Key="AriaMaxConcurrentDownloads">Aria同时下载数</system:String>
<system:String x:Key="AriaSplit">Aria最大线程数</system:String>
<system:String x:Key="AriaDownloadLimit">Aria下载速度限制(KB/s)</system:String>
<system:String x:Key="AriaMaxOverallDownloadLimit">全局下载速度限制[0: 无限制]</system:String>
<system:String x:Key="AriaMaxDownloadLimit">单任务下载速度限制[0: 无限制]</system:String>
<system:String x:Key="IsAriaHttpProxy">使用Http代理</system:String>
<system:String x:Key="AriaHttpProxy">代理地址:</system:String>
<system:String x:Key="AriaHttpProxyPort">端口:</system:String>
<system:String x:Key="AriaFileAllocation">Aria文件预分配</system:String>
<system:String x:Key="Video">视频</system:String>
<system:String x:Key="FirstVideoCodecs">优先下载的视频编码:</system:String>
<system:String x:Key="FirstVideoQuality">优先下载的视频画质:</system:String>
<system:String x:Key="IsAddVideoOrder">启用视频编号</system:String>
<system:String x:Key="IsAddVideoOrderTip">勾选后,将为下载完成的视频的文件名添加上序号</system:String>
<system:String x:Key="IsTranscodingFlvToMp4">下载FLV视频后转码为mp4</system:String>
<system:String x:Key="IsUseDefaultDirectory">使用默认下载目录</system:String>
<system:String x:Key="DefaultDirectory">默认下载目录:</system:String>
<system:String x:Key="DefaultDirectoryTip">默认将文件下载到该文件夹中</system:String>
<system:String x:Key="ChangeDirectory">更改目录</system:String>
<system:String x:Key="IsCreateFolderForMedia">为不同视频分别创建文件夹</system:String>
<system:String x:Key="IsDownloadDanmaku">在下载视频的同时下载弹幕</system:String>
<system:String x:Key="IsDownloadCover">在下载视频的同时下载封面</system:String>
<system:String x:Key="SettingDanmaku">弹幕</system:String>
<system:String x:Key="FilterType">按类型屏蔽</system:String>
<system:String x:Key="TopFilter">顶部</system:String>
<system:String x:Key="BottomFilter">底部</system:String>
<system:String x:Key="ScrollFilter">滚动</system:String>
<system:String x:Key="Resolution">分辨率:</system:String>
<system:String x:Key="FontName">字体名称:</system:String>
<system:String x:Key="FontSize">字体大小:</system:String>
<system:String x:Key="LineCount">限制行数:</system:String>
<system:String x:Key="LayoutAlgorithm">布局算法:</system:String>
<system:String x:Key="LayoutAlgorithmSync">速度同步</system:String>
<system:String x:Key="LayoutAlgorithmSyncTip">每一条滚动弹幕的移动速度都是相同的</system:String>
<system:String x:Key="LayoutAlgorithmAsync">速度异步</system:String>
<system:String x:Key="LayoutAlgorithmAsyncTip">弹幕滚动速度取决于它的文本长度</system:String>
<system:String x:Key="About">关于</system:String>
<system:String x:Key="GotoHomepage">访问主页</system:String>
<system:String x:Key="CurrentAppVersion">当前版本:</system:String>
<system:String x:Key="CheckUpdate">检查更新</system:String>
<system:String x:Key="Feedback">意见反馈</system:String>
<system:String x:Key="ReceiveBetaVersion">接收测试版更新</system:String>
<system:String x:Key="AutoUpdateWhenLaunch">启动时检查更新</system:String>
<system:String x:Key="TipSettingUpdated">设置已更新~</system:String>
<system:String x:Key="TipSettingFailed">设置失败!</system:String>
<system:String x:Key="ThirdParty">第三方</system:String>
<system:String x:Key="ThirdPartyName">名称</system:String>
<system:String x:Key="ThirdPartyAuthor">作者</system:String>
<system:String x:Key="ThirdPartyVersion">版本</system:String>
<system:String x:Key="ThirdPartyLicense">许可证</system:String>
<system:String x:Key="Disclaimer">免责申明</system:String>
<system:String x:Key="Disclaimer1">1. 本软件只提供视频解析,不提供任何资源上传、存储到服务器的功能。</system:String>
<system:String x:Key="Disclaimer2">2. 本软件仅解析来自B站的内容不会对解析到的音视频进行二次编码部分视频会进行有限的格式转换、拼接等操作。</system:String>
<system:String x:Key="Disclaimer3">3. 本软件解析得到的所有内容均来自B站UP主上传、分享其版权均归原作者所有。内容提供者、上传者UP主应对其提供、上传的内容承担全部责任。</system:String>
<system:String x:Key="Disclaimer4">4. 本软件提供的所有资源仅可用作学习交流使用未经原作者授权禁止用于其他用途。请在下载24小时内删除。为尊重作者版权请前往资源的原始发布网站观看支持原创谢谢。</system:String>
<system:String x:Key="Disclaimer5">5. 任何涉及商业盈利目的均不得使用,否则产生的一切后果将由您自己承担。</system:String>
<system:String x:Key="Disclaimer6">6. 因使用本软件产生的版权问题,软件作者概不负责。</system:String>
<!-- Tools -->
<system:String x:Key="BiliHelper">B站助手</system:String>
<system:String x:Key="Delogo">去水印</system:String>
<system:String x:Key="ExtractMedia">音视频分离</system:String>
<!-- Dialog -->
<system:String x:Key="Cancel">取消</system:String>
<system:String x:Key="SelectDirectory">请选择文件夹</system:String>
<!-- ViewDirectorySelector -->
<system:String x:Key="DownloadDirectorySelector">设置下载文件夹</system:String>
<system:String x:Key="Location">位置:</system:String>
<system:String x:Key="Browse">浏览</system:String>
<system:String x:Key="HardDiskFreeSpace">盘剩余空间:</system:String>
<system:String x:Key="IsDefaultDownloadDirectory">设此文件夹为默认下载文件夹</system:String>
<system:String x:Key="IsDefaultDownloadDirectoryTip">选中后下次将不会弹出此窗口</system:String>
<system:String x:Key="Download">下载</system:String>
<system:String x:Key="WarningNullDirectory">文件夹路径不能为空</system:String>
<!-- ViewParsingSelector -->
<system:String x:Key="ParsingSelector">选择解析项</system:String>
<system:String x:Key="ParseNone">无</system:String>
<system:String x:Key="ParseSelectedItem">解析选中项</system:String>
<system:String x:Key="ParseCurrentSection">解析当前页视频</system:String>
<system:String x:Key="ParseAll">解析所有视频</system:String>
<system:String x:Key="SetParseDefault">设为默认,下次不再弹出</system:String>
</ResourceDictionary>

@ -0,0 +1,174 @@
<ResourceDictionary
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="clr-namespace:DownKyi.Languages"
xmlns:system="clr-namespace:System;assembly=mscorlib">
<!-- App -->
<system:String x:Key="AppName">哔哩下载姬</system:String>
<system:String x:Key="Unknown">未知</system:String>
<!-- 系统 -->
<system:String x:Key="Close">关闭</system:String>
<system:String x:Key="Maximize">最大化</system:String>
<system:String x:Key="Minimize">最小化</system:String>
<system:String x:Key="Restore">还原</system:String>
<system:String x:Key="Skin">皮肤</system:String>
<!-- Index -->
<system:String x:Key="Login">登录</system:String>
<system:String x:Key="IndexHintText">请输入B站网址链接或av、BV号等……</system:String>
<system:String x:Key="IndexHintTextSimple">请输入B站视频播放地址……</system:String>
<system:String x:Key="Settings">设置</system:String>
<system:String x:Key="DownloadManager">下载管理</system:String>
<system:String x:Key="Toolbox">工具箱</system:String>
<!-- Login -->
<system:String x:Key="ScanToLogin">扫描二维码登录</system:String>
<system:String x:Key="ScanLoginTip" xml:space="preserve">请使用哔哩哔哩客户端&#x000A;扫码登录&#x000A;或扫码下载APP</system:String>
<system:String x:Key="GetLoginUrlFailed">获取登录链接失败!</system:String>
<system:String x:Key="LoginKeyError">密钥错误!尝试重新获取!</system:String>
<system:String x:Key="LoginTimeOut">已超时!尝试重新获取二维码!</system:String>
<system:String x:Key="LoginSuccessful">登录成功!(3秒后自动回到主页)</system:String>
<system:String x:Key="LoginFailed">未保存登录信息!(3秒后自动回到主页)</system:String>
<!-- VideoDetail -->
<system:String x:Key="CopyCover">复制封面图片</system:String>
<system:String x:Key="CopyCoverUrl">复制封面URL</system:String>
<system:String x:Key="Play">播放</system:String>
<system:String x:Key="Danmaku">弹幕</system:String>
<system:String x:Key="Like">点赞</system:String>
<system:String x:Key="Coin">投币</system:String>
<system:String x:Key="Favorite">收藏</system:String>
<system:String x:Key="Share">分享</system:String>
<system:String x:Key="Reply">评论</system:String>
<system:String x:Key="Anime">番剧</system:String>
<system:String x:Key="Movie">电影</system:String>
<system:String x:Key="Documentary">纪录片</system:String>
<system:String x:Key="Guochuang">国创</system:String>
<system:String x:Key="TV">电视剧</system:String>
<system:String x:Key="Entertainment">综艺</system:String>
<system:String x:Key="Cheese">课程</system:String>
<system:String x:Key="Order">序号</system:String>
<system:String x:Key="Name">名称</system:String>
<system:String x:Key="Duration">时长</system:String>
<system:String x:Key="AudioQuality">音质</system:String>
<system:String x:Key="VideoQuality">画质</system:String>
<system:String x:Key="VideoCodec">视频编码</system:String>
<system:String x:Key="SelectAll">全选</system:String>
<system:String x:Key="Parse">解析</system:String>
<system:String x:Key="ParseVideo">解析视频</system:String>
<system:String x:Key="DownloadSelected">下载选中项</system:String>
<!-- DownloadManager -->
<system:String x:Key="Downloading">正在下载</system:String>
<system:String x:Key="DownloadFinished">已下载</system:String>
<!-- Settings -->
<system:String x:Key="PressEnterToApplySettingTip">按回车键应用设置</system:String>
<system:String x:Key="Basic">基本</system:String>
<system:String x:Key="AfterDownloadOperation">下载完成后的动作:</system:String>
<system:String x:Key="AfterDownloadOperationNone">无</system:String>
<system:String x:Key="AfterDownloadOperationCloseApp">关闭程序</system:String>
<system:String x:Key="AfterDownloadOperationCloseSystem">关闭计算机</system:String>
<system:String x:Key="ListenClipboard">监听剪贴板</system:String>
<system:String x:Key="VideoAutoParse">视频自动解析</system:String>
<system:String x:Key="VideoParseScope">视频解析范围:</system:String>
<system:String x:Key="Network">网络</system:String>
<system:String x:Key="AriaServerPort">Aria服务器端口</system:String>
<system:String x:Key="AriaLogLevel">Aria日志等级</system:String>
<system:String x:Key="AriaMaxConcurrentDownloads">Aria同时下载数</system:String>
<system:String x:Key="AriaSplit">Aria最大线程数</system:String>
<system:String x:Key="AriaDownloadLimit">Aria下载速度限制(KB/s)</system:String>
<system:String x:Key="AriaMaxOverallDownloadLimit">全局下载速度限制[0: 无限制]</system:String>
<system:String x:Key="AriaMaxDownloadLimit">单任务下载速度限制[0: 无限制]</system:String>
<system:String x:Key="IsAriaHttpProxy">使用Http代理</system:String>
<system:String x:Key="AriaHttpProxy">代理地址:</system:String>
<system:String x:Key="AriaHttpProxyPort">端口:</system:String>
<system:String x:Key="AriaFileAllocation">Aria文件预分配</system:String>
<system:String x:Key="Video">视频</system:String>
<system:String x:Key="FirstVideoCodecs">优先下载的视频编码:</system:String>
<system:String x:Key="FirstVideoQuality">优先下载的视频画质:</system:String>
<system:String x:Key="IsAddVideoOrder">启用视频编号</system:String>
<system:String x:Key="IsAddVideoOrderTip">勾选后,将为下载完成的视频的文件名添加上序号</system:String>
<system:String x:Key="IsTranscodingFlvToMp4">下载FLV视频后转码为mp4</system:String>
<system:String x:Key="IsUseDefaultDirectory">使用默认下载目录</system:String>
<system:String x:Key="DefaultDirectory">默认下载目录:</system:String>
<system:String x:Key="DefaultDirectoryTip">默认将文件下载到该文件夹中</system:String>
<system:String x:Key="ChangeDirectory">更改目录</system:String>
<system:String x:Key="IsCreateFolderForMedia">为不同视频分别创建文件夹</system:String>
<system:String x:Key="IsDownloadDanmaku">在下载视频的同时下载弹幕</system:String>
<system:String x:Key="IsDownloadCover">在下载视频的同时下载封面</system:String>
<system:String x:Key="SettingDanmaku">弹幕</system:String>
<system:String x:Key="FilterType">按类型屏蔽</system:String>
<system:String x:Key="TopFilter">顶部</system:String>
<system:String x:Key="BottomFilter">底部</system:String>
<system:String x:Key="ScrollFilter">滚动</system:String>
<system:String x:Key="Resolution">分辨率:</system:String>
<system:String x:Key="FontName">字体名称:</system:String>
<system:String x:Key="FontSize">字体大小:</system:String>
<system:String x:Key="LineCount">限制行数:</system:String>
<system:String x:Key="LayoutAlgorithm">布局算法:</system:String>
<system:String x:Key="LayoutAlgorithmSync">速度同步</system:String>
<system:String x:Key="LayoutAlgorithmSyncTip">每一条滚动弹幕的移动速度都是相同的</system:String>
<system:String x:Key="LayoutAlgorithmAsync">速度异步</system:String>
<system:String x:Key="LayoutAlgorithmAsyncTip">弹幕滚动速度取决于它的文本长度</system:String>
<system:String x:Key="About">关于</system:String>
<system:String x:Key="GotoHomepage">访问主页</system:String>
<system:String x:Key="CurrentAppVersion">当前版本:</system:String>
<system:String x:Key="CheckUpdate">检查更新</system:String>
<system:String x:Key="Feedback">意见反馈</system:String>
<system:String x:Key="ReceiveBetaVersion">接收测试版更新</system:String>
<system:String x:Key="AutoUpdateWhenLaunch">启动时检查更新</system:String>
<system:String x:Key="TipSettingUpdated">设置已更新~</system:String>
<system:String x:Key="TipSettingFailed">设置失败!</system:String>
<system:String x:Key="ThirdParty">第三方</system:String>
<system:String x:Key="ThirdPartyName">名称</system:String>
<system:String x:Key="ThirdPartyAuthor">作者</system:String>
<system:String x:Key="ThirdPartyVersion">版本</system:String>
<system:String x:Key="ThirdPartyLicense">许可证</system:String>
<system:String x:Key="Disclaimer">免责申明</system:String>
<system:String x:Key="Disclaimer1">1. 本软件只提供视频解析,不提供任何资源上传、存储到服务器的功能。</system:String>
<system:String x:Key="Disclaimer2">2. 本软件仅解析来自B站的内容不会对解析到的音视频进行二次编码部分视频会进行有限的格式转换、拼接等操作。</system:String>
<system:String x:Key="Disclaimer3">3. 本软件解析得到的所有内容均来自B站UP主上传、分享其版权均归原作者所有。内容提供者、上传者UP主应对其提供、上传的内容承担全部责任。</system:String>
<system:String x:Key="Disclaimer4">4. 本软件提供的所有资源仅可用作学习交流使用未经原作者授权禁止用于其他用途。请在下载24小时内删除。为尊重作者版权请前往资源的原始发布网站观看支持原创谢谢。</system:String>
<system:String x:Key="Disclaimer5">5. 任何涉及商业盈利目的均不得使用,否则产生的一切后果将由您自己承担。</system:String>
<system:String x:Key="Disclaimer6">6. 因使用本软件产生的版权问题,软件作者概不负责。</system:String>
<!-- Tools -->
<system:String x:Key="BiliHelper">B站助手</system:String>
<system:String x:Key="Delogo">去水印</system:String>
<system:String x:Key="ExtractMedia">音视频分离</system:String>
<!-- Dialog -->
<system:String x:Key="Cancel">取消</system:String>
<system:String x:Key="SelectDirectory">请选择文件夹</system:String>
<!-- ViewDirectorySelector -->
<system:String x:Key="DownloadDirectorySelector">设置下载文件夹</system:String>
<system:String x:Key="Location">位置:</system:String>
<system:String x:Key="Browse">浏览</system:String>
<system:String x:Key="HardDiskFreeSpace">盘剩余空间:</system:String>
<system:String x:Key="IsDefaultDownloadDirectory">设此文件夹为默认下载文件夹</system:String>
<system:String x:Key="IsDefaultDownloadDirectoryTip">选中后下次将不会弹出此窗口</system:String>
<system:String x:Key="Download">下载</system:String>
<system:String x:Key="WarningNullDirectory">文件夹路径不能为空</system:String>
<!-- ViewParsingSelector -->
<system:String x:Key="ParsingSelector">选择解析项</system:String>
<system:String x:Key="ParseNone">无</system:String>
<system:String x:Key="ParseSelectedItem">解析选中项</system:String>
<system:String x:Key="ParseCurrentSection">解析当前页视频</system:String>
<system:String x:Key="ParseAll">解析所有视频</system:String>
<system:String x:Key="SetParseDefault">设为默认,下次不再弹出</system:String>
</ResourceDictionary>

@ -0,0 +1,174 @@
<ResourceDictionary
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="clr-namespace:DownKyi.Languages"
xmlns:system="clr-namespace:System;assembly=mscorlib">
<!-- App -->
<system:String x:Key="AppName">哔哩下载姬</system:String>
<system:String x:Key="Unknown">未知</system:String>
<!-- 系统 -->
<system:String x:Key="Close">关闭</system:String>
<system:String x:Key="Maximize">最大化</system:String>
<system:String x:Key="Minimize">最小化</system:String>
<system:String x:Key="Restore">还原</system:String>
<system:String x:Key="Skin">皮肤</system:String>
<!-- Index -->
<system:String x:Key="Login">登录</system:String>
<system:String x:Key="IndexHintText">请输入B站网址链接或av、BV号等……</system:String>
<system:String x:Key="IndexHintTextSimple">请输入B站视频播放地址……</system:String>
<system:String x:Key="Settings">设置</system:String>
<system:String x:Key="DownloadManager">下载管理</system:String>
<system:String x:Key="Toolbox">工具箱</system:String>
<!-- Login -->
<system:String x:Key="ScanToLogin">扫描二维码登录</system:String>
<system:String x:Key="ScanLoginTip" xml:space="preserve">请使用哔哩哔哩客户端&#x000A;扫码登录&#x000A;或扫码下载APP</system:String>
<system:String x:Key="GetLoginUrlFailed">获取登录链接失败!</system:String>
<system:String x:Key="LoginKeyError">密钥错误!尝试重新获取!</system:String>
<system:String x:Key="LoginTimeOut">已超时!尝试重新获取二维码!</system:String>
<system:String x:Key="LoginSuccessful">登录成功!(3秒后自动回到主页)</system:String>
<system:String x:Key="LoginFailed">未保存登录信息!(3秒后自动回到主页)</system:String>
<!-- VideoDetail -->
<system:String x:Key="CopyCover">复制封面图片</system:String>
<system:String x:Key="CopyCoverUrl">复制封面URL</system:String>
<system:String x:Key="Play">播放</system:String>
<system:String x:Key="Danmaku">弹幕</system:String>
<system:String x:Key="Like">点赞</system:String>
<system:String x:Key="Coin">投币</system:String>
<system:String x:Key="Favorite">收藏</system:String>
<system:String x:Key="Share">分享</system:String>
<system:String x:Key="Reply">评论</system:String>
<system:String x:Key="Anime">番剧</system:String>
<system:String x:Key="Movie">电影</system:String>
<system:String x:Key="Documentary">纪录片</system:String>
<system:String x:Key="Guochuang">国创</system:String>
<system:String x:Key="TV">电视剧</system:String>
<system:String x:Key="Entertainment">综艺</system:String>
<system:String x:Key="Cheese">课程</system:String>
<system:String x:Key="Order">序号</system:String>
<system:String x:Key="Name">名称</system:String>
<system:String x:Key="Duration">时长</system:String>
<system:String x:Key="AudioQuality">音质</system:String>
<system:String x:Key="VideoQuality">画质</system:String>
<system:String x:Key="VideoCodec">视频编码</system:String>
<system:String x:Key="SelectAll">全选</system:String>
<system:String x:Key="Parse">解析</system:String>
<system:String x:Key="ParseVideo">解析视频</system:String>
<system:String x:Key="DownloadSelected">下载选中项</system:String>
<!-- DownloadManager -->
<system:String x:Key="Downloading">正在下载</system:String>
<system:String x:Key="DownloadFinished">已下载</system:String>
<!-- Settings -->
<system:String x:Key="PressEnterToApplySettingTip">按回车键应用设置</system:String>
<system:String x:Key="Basic">基本</system:String>
<system:String x:Key="AfterDownloadOperation">下载完成后的动作:</system:String>
<system:String x:Key="AfterDownloadOperationNone">无</system:String>
<system:String x:Key="AfterDownloadOperationCloseApp">关闭程序</system:String>
<system:String x:Key="AfterDownloadOperationCloseSystem">关闭计算机</system:String>
<system:String x:Key="ListenClipboard">监听剪贴板</system:String>
<system:String x:Key="VideoAutoParse">视频自动解析</system:String>
<system:String x:Key="VideoParseScope">视频解析范围:</system:String>
<system:String x:Key="Network">网络</system:String>
<system:String x:Key="AriaServerPort">Aria服务器端口</system:String>
<system:String x:Key="AriaLogLevel">Aria日志等级</system:String>
<system:String x:Key="AriaMaxConcurrentDownloads">Aria同时下载数</system:String>
<system:String x:Key="AriaSplit">Aria最大线程数</system:String>
<system:String x:Key="AriaDownloadLimit">Aria下载速度限制(KB/s)</system:String>
<system:String x:Key="AriaMaxOverallDownloadLimit">全局下载速度限制[0: 无限制]</system:String>
<system:String x:Key="AriaMaxDownloadLimit">单任务下载速度限制[0: 无限制]</system:String>
<system:String x:Key="IsAriaHttpProxy">使用Http代理</system:String>
<system:String x:Key="AriaHttpProxy">代理地址:</system:String>
<system:String x:Key="AriaHttpProxyPort">端口:</system:String>
<system:String x:Key="AriaFileAllocation">Aria文件预分配</system:String>
<system:String x:Key="Video">视频</system:String>
<system:String x:Key="FirstVideoCodecs">优先下载的视频编码:</system:String>
<system:String x:Key="FirstVideoQuality">优先下载的视频画质:</system:String>
<system:String x:Key="IsAddVideoOrder">启用视频编号</system:String>
<system:String x:Key="IsAddVideoOrderTip">勾选后,将为下载完成的视频的文件名添加上序号</system:String>
<system:String x:Key="IsTranscodingFlvToMp4">下载FLV视频后转码为mp4</system:String>
<system:String x:Key="IsUseDefaultDirectory">使用默认下载目录</system:String>
<system:String x:Key="DefaultDirectory">默认下载目录:</system:String>
<system:String x:Key="DefaultDirectoryTip">默认将文件下载到该文件夹中</system:String>
<system:String x:Key="ChangeDirectory">更改目录</system:String>
<system:String x:Key="IsCreateFolderForMedia">为不同视频分别创建文件夹</system:String>
<system:String x:Key="IsDownloadDanmaku">在下载视频的同时下载弹幕</system:String>
<system:String x:Key="IsDownloadCover">在下载视频的同时下载封面</system:String>
<system:String x:Key="SettingDanmaku">弹幕</system:String>
<system:String x:Key="FilterType">按类型屏蔽</system:String>
<system:String x:Key="TopFilter">顶部</system:String>
<system:String x:Key="BottomFilter">底部</system:String>
<system:String x:Key="ScrollFilter">滚动</system:String>
<system:String x:Key="Resolution">分辨率:</system:String>
<system:String x:Key="FontName">字体名称:</system:String>
<system:String x:Key="FontSize">字体大小:</system:String>
<system:String x:Key="LineCount">限制行数:</system:String>
<system:String x:Key="LayoutAlgorithm">布局算法:</system:String>
<system:String x:Key="LayoutAlgorithmSync">速度同步</system:String>
<system:String x:Key="LayoutAlgorithmSyncTip">每一条滚动弹幕的移动速度都是相同的</system:String>
<system:String x:Key="LayoutAlgorithmAsync">速度异步</system:String>
<system:String x:Key="LayoutAlgorithmAsyncTip">弹幕滚动速度取决于它的文本长度</system:String>
<system:String x:Key="About">关于</system:String>
<system:String x:Key="GotoHomepage">访问主页</system:String>
<system:String x:Key="CurrentAppVersion">当前版本:</system:String>
<system:String x:Key="CheckUpdate">检查更新</system:String>
<system:String x:Key="Feedback">意见反馈</system:String>
<system:String x:Key="ReceiveBetaVersion">接收测试版更新</system:String>
<system:String x:Key="AutoUpdateWhenLaunch">启动时检查更新</system:String>
<system:String x:Key="TipSettingUpdated">设置已更新~</system:String>
<system:String x:Key="TipSettingFailed">设置失败!</system:String>
<system:String x:Key="ThirdParty">第三方</system:String>
<system:String x:Key="ThirdPartyName">名称</system:String>
<system:String x:Key="ThirdPartyAuthor">作者</system:String>
<system:String x:Key="ThirdPartyVersion">版本</system:String>
<system:String x:Key="ThirdPartyLicense">许可证</system:String>
<system:String x:Key="Disclaimer">免责申明</system:String>
<system:String x:Key="Disclaimer1">1. 本软件只提供视频解析,不提供任何资源上传、存储到服务器的功能。</system:String>
<system:String x:Key="Disclaimer2">2. 本软件仅解析来自B站的内容不会对解析到的音视频进行二次编码部分视频会进行有限的格式转换、拼接等操作。</system:String>
<system:String x:Key="Disclaimer3">3. 本软件解析得到的所有内容均来自B站UP主上传、分享其版权均归原作者所有。内容提供者、上传者UP主应对其提供、上传的内容承担全部责任。</system:String>
<system:String x:Key="Disclaimer4">4. 本软件提供的所有资源仅可用作学习交流使用未经原作者授权禁止用于其他用途。请在下载24小时内删除。为尊重作者版权请前往资源的原始发布网站观看支持原创谢谢。</system:String>
<system:String x:Key="Disclaimer5">5. 任何涉及商业盈利目的均不得使用,否则产生的一切后果将由您自己承担。</system:String>
<system:String x:Key="Disclaimer6">6. 因使用本软件产生的版权问题,软件作者概不负责。</system:String>
<!-- Tools -->
<system:String x:Key="BiliHelper">B站助手</system:String>
<system:String x:Key="Delogo">去水印</system:String>
<system:String x:Key="ExtractMedia">音视频分离</system:String>
<!-- Dialog -->
<system:String x:Key="Cancel">取消</system:String>
<system:String x:Key="SelectDirectory">请选择文件夹</system:String>
<!-- ViewDirectorySelector -->
<system:String x:Key="DownloadDirectorySelector">设置下载文件夹</system:String>
<system:String x:Key="Location">位置:</system:String>
<system:String x:Key="Browse">浏览</system:String>
<system:String x:Key="HardDiskFreeSpace">盘剩余空间:</system:String>
<system:String x:Key="IsDefaultDownloadDirectory">设此文件夹为默认下载文件夹</system:String>
<system:String x:Key="IsDefaultDownloadDirectoryTip">选中后下次将不会弹出此窗口</system:String>
<system:String x:Key="Download">下载</system:String>
<system:String x:Key="WarningNullDirectory">文件夹路径不能为空</system:String>
<!-- ViewParsingSelector -->
<system:String x:Key="ParsingSelector">选择解析项</system:String>
<system:String x:Key="ParseNone">无</system:String>
<system:String x:Key="ParseSelectedItem">解析选中项</system:String>
<system:String x:Key="ParseCurrentSection">解析当前页视频</system:String>
<system:String x:Key="ParseAll">解析所有视频</system:String>
<system:String x:Key="SetParseDefault">设为默认,下次不再弹出</system:String>
</ResourceDictionary>

@ -0,0 +1,9 @@
namespace DownKyi.Models
{
public class AppInfo
{
public string Name { get; } = "哔哩下载姬";
public string VersionName { get; } = "1.5.0-alpha1";
public int VersionCode { get; } = 500;
}
}

@ -0,0 +1,10 @@
using DownKyi.Core.Settings;
namespace DownKyi.Models
{
public class ParseScopeDisplay
{
public string Name { get; set; }
public ParseScope ParseScope { get; set; }
}
}

@ -0,0 +1,8 @@
namespace DownKyi.Models
{
public class Resolution
{
public string Name { get; set; }
public int Id { get; set; }
}
}

@ -0,0 +1,37 @@
using DownKyi.Images;
using Prism.Mvvm;
namespace DownKyi.Models
{
public class TabHeader : BindableBase
{
private int id;
public int Id
{
get { return id; }
set { SetProperty(ref id, value); }
}
private VectorImage image;
public VectorImage Image
{
get { return image; }
set { SetProperty(ref image, value); }
}
private string title;
public string Title
{
get { return title; }
set { SetProperty(ref title, value); }
}
private string subTitle;
public string SubTitle
{
get { return subTitle; }
set { SetProperty(ref subTitle, value); }
}
}
}

@ -0,0 +1,111 @@
using Prism.Mvvm;
using System;
using System.Windows.Media.Imaging;
namespace DownKyi.Models
{
[Serializable]
public class VideoInfoView : BindableBase
{
public string CoverUrl { get; set; }
private BitmapImage cover;
public BitmapImage Cover
{
get { return cover; }
set { SetProperty(ref cover, value); }
}
private string title;
public string Title
{
get { return title; }
set { SetProperty(ref title, value); }
}
private string videoZone;
public string VideoZone
{
get { return videoZone; }
set { SetProperty(ref videoZone, value); }
}
private string createTime;
public string CreateTime
{
get { return createTime; }
set { SetProperty(ref createTime, value); }
}
private string playNumber;
public string PlayNumber
{
get { return playNumber; }
set { SetProperty(ref playNumber, value); }
}
private string danmakuNumber;
public string DanmakuNumber
{
get { return danmakuNumber; }
set { SetProperty(ref danmakuNumber, value); }
}
private string likeNumber;
public string LikeNumber
{
get { return likeNumber; }
set { SetProperty(ref likeNumber, value); }
}
private string coinNumber;
public string CoinNumber
{
get { return coinNumber; }
set { SetProperty(ref coinNumber, value); }
}
private string favoriteNumber;
public string FavoriteNumber
{
get { return favoriteNumber; }
set { SetProperty(ref favoriteNumber, value); }
}
private string shareNumber;
public string ShareNumber
{
get { return shareNumber; }
set { SetProperty(ref shareNumber, value); }
}
private string replyNumber;
public string ReplyNumber
{
get { return replyNumber; }
set { SetProperty(ref replyNumber, value); }
}
private string description;
public string Description
{
get { return description; }
set { SetProperty(ref description, value); }
}
private string upName;
public string UpName
{
get { return upName; }
set { SetProperty(ref upName, value); }
}
private BitmapImage upHeader;
public BitmapImage UpHeader
{
get { return upHeader; }
set { SetProperty(ref upHeader, value); }
}
}
}

@ -0,0 +1,73 @@
using DownKyi.Core.BiliApi.VideoStream.Models;
using Prism.Mvvm;
using System.Collections.Generic;
namespace DownKyi.Models
{
public class VideoPage : BindableBase
{
public PlayUrl PlayUrl { get; set; }
public long Avid { get; set; }
public string Bvid { get; set; }
public long Cid { get; set; }
public long EpisodeId { get; set; }
private bool isSelected;
public bool IsSelected
{
get { return isSelected; }
set { SetProperty(ref isSelected, value); }
}
private int order;
public int Order
{
get { return order; }
set { SetProperty(ref order, value); }
}
private string name;
public string Name
{
get { return name; }
set { SetProperty(ref name, value); }
}
private string duration;
public string Duration
{
get { return duration; }
set { SetProperty(ref duration, value); }
}
private List<string> audioQualityFormatList;
public List<string> AudioQualityFormatList
{
get { return audioQualityFormatList; }
set { SetProperty(ref audioQualityFormatList, value); }
}
private string audioQualityFormat;
public string AudioQualityFormat
{
get { return audioQualityFormat; }
set { SetProperty(ref audioQualityFormat, value); }
}
private List<VideoQuality> videoQualityList;
public List<VideoQuality> VideoQualityList
{
get { return videoQualityList; }
set { SetProperty(ref videoQualityList, value); }
}
private VideoQuality videoQuality;
public VideoQuality VideoQuality
{
get { return videoQuality; }
set { SetProperty(ref videoQuality, value); }
}
}
}

@ -0,0 +1,37 @@
using Prism.Mvvm;
using System.Collections.Generic;
namespace DownKyi.Models
{
public class VideoQuality : BindableBase
{
private int quality;
public int Quality
{
get { return quality; }
set { SetProperty(ref quality, value); }
}
private string qualityFormat;
public string QualityFormat
{
get { return qualityFormat; }
set { SetProperty(ref qualityFormat, value); }
}
private List<string> videoCodecList;
public List<string> VideoCodecList
{
get { return videoCodecList; }
set { SetProperty(ref videoCodecList, value); }
}
private string selectedVideoCodec;
public string SelectedVideoCodec
{
get { return selectedVideoCodec; }
set { SetProperty(ref selectedVideoCodec, value); }
}
}
}

@ -0,0 +1,31 @@
using Prism.Mvvm;
using System.Collections.Generic;
namespace DownKyi.Models
{
public class VideoSection : BindableBase
{
public long Id { get; set; }
private string title;
public string Title
{
get { return title; }
set { SetProperty(ref title, value); }
}
private bool isSelected;
public bool IsSelected
{
get { return isSelected; }
set { SetProperty(ref isSelected, value); }
}
private List<VideoPage> videoPages;
public List<VideoPage> VideoPages
{
get { return videoPages; }
set { SetProperty(ref videoPages, 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("DownKyi")]
[assembly: AssemblyDescription("DownKyi")]
[assembly: AssemblyConfiguration("")]
[assembly: AssemblyCompany("DownKyi")]
[assembly: AssemblyProduct("DownKyi")]
[assembly: AssemblyCopyright("Copyright © Downkyi 2020-2021")]
[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.5.0.0")]
[assembly: AssemblyFileVersion("1.5.0.0")]

@ -0,0 +1,73 @@
//------------------------------------------------------------------------------
// <auto-generated>
// 此代码由工具生成。
// 运行时版本:4.0.30319.42000
//
// 对此文件的更改可能会导致不正确的行为,并且如果
// 重新生成代码,这些更改将会丢失。
// </auto-generated>
//------------------------------------------------------------------------------
namespace DownKyi.Properties {
using System;
/// <summary>
/// 一个强类型的资源类,用于查找本地化的字符串等。
/// </summary>
// 此类是由 StronglyTypedResourceBuilder
// 类通过类似于 ResGen 或 Visual Studio 的工具自动生成的。
// 若要添加或移除成员,请编辑 .ResX 文件,然后重新运行 ResGen
// (以 /str 作为命令选项),或重新生成 VS 项目。
[global::System.CodeDom.Compiler.GeneratedCodeAttribute("System.Resources.Tools.StronglyTypedResourceBuilder", "16.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>
/// 返回此类使用的缓存的 ResourceManager 实例。
/// </summary>
[global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)]
internal static global::System.Resources.ResourceManager ResourceManager {
get {
if (object.ReferenceEquals(resourceMan, null)) {
global::System.Resources.ResourceManager temp = new global::System.Resources.ResourceManager("DownKyi.Properties.Resources", typeof(Resources).Assembly);
resourceMan = temp;
}
return resourceMan;
}
}
/// <summary>
/// 重写当前线程的 CurrentUICulture 属性,对
/// 使用此强类型资源类的所有资源查找执行重写。
/// </summary>
[global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)]
internal static global::System.Globalization.CultureInfo Culture {
get {
return resourceCulture;
}
set {
resourceCulture = value;
}
}
/// <summary>
/// 查找 System.Drawing.Bitmap 类型的本地化资源。
/// </summary>
internal static System.Drawing.Bitmap loading {
get {
object obj = ResourceManager.GetObject("loading", resourceCulture);
return ((System.Drawing.Bitmap)(obj));
}
}
}
}

@ -0,0 +1,124 @@
<?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.Runtime.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:import namespace="http://www.w3.org/XML/1998/namespace" />
<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" use="required" type="xsd:string" />
<xsd:attribute name="type" type="xsd:string" />
<xsd:attribute name="mimetype" type="xsd:string" />
<xsd:attribute ref="xml:space" />
</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" use="required" msdata:Ordinal="1" />
<xsd:attribute name="type" type="xsd:string" msdata:Ordinal="3" />
<xsd:attribute name="mimetype" type="xsd:string" msdata:Ordinal="4" />
<xsd:attribute ref="xml:space" />
</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=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
</resheader>
<resheader name="writer">
<value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
</resheader>
<assembly alias="System.Windows.Forms" name="System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089" />
<data name="loading" type="System.Resources.ResXFileRef, System.Windows.Forms">
<value>..\resources\loading\loading.gif;System.Drawing.Bitmap, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a</value>
</data>
</root>

@ -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 DownKyi.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,7 @@
<?xml version='1.0' encoding='utf-8'?>
<SettingsFile xmlns="uri:settings" CurrentProfile="(Default)">
<Profiles>
<Profile Name="(Default)" />
</Profiles>
<Settings />
</SettingsFile>

Binary file not shown.

After

Width:  |  Height:  |  Size: 8.8 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 66 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 20 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 44 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 52 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 62 KiB

@ -0,0 +1,240 @@
using DownKyi.Core.BiliApi.Bangumi;
using DownKyi.Core.BiliApi.Bangumi.Models;
using DownKyi.Core.BiliApi.BiliUtils;
using DownKyi.Core.BiliApi.VideoStream;
using DownKyi.Core.Storage;
using DownKyi.Core.Utils;
using DownKyi.Models;
using DownKyi.Utils;
using System;
using System.Collections.Generic;
using System.Windows.Media.Imaging;
namespace DownKyi.Services
{
public class BangumiInfoService : IInfoService
{
private readonly BangumiSeason bangumiSeason;
public BangumiInfoService(string input)
{
if (input == null)
{
return;
}
if (ParseEntrance.IsBangumiSeasonId(input) || ParseEntrance.IsBangumiSeasonUrl(input))
{
long seasonId = ParseEntrance.GetBangumiSeasonId(input);
bangumiSeason = BangumiInfo.BangumiSeasonInfo(seasonId);
}
if (ParseEntrance.IsBangumiEpisodeId(input) || ParseEntrance.IsBangumiEpisodeUrl(input))
{
long episodeId = ParseEntrance.GetBangumiEpisodeId(input);
bangumiSeason = BangumiInfo.BangumiSeasonInfo(-1, episodeId);
}
if (ParseEntrance.IsBangumiMediaId(input) || ParseEntrance.IsBangumiMediaUrl(input))
{
long mediaId = ParseEntrance.GetBangumiMediaId(input);
var bangumiMedia = BangumiInfo.BangumiMediaInfo(mediaId);
bangumiSeason = BangumiInfo.BangumiSeasonInfo(bangumiMedia.SeasonId);
}
}
/// <summary>
/// 获取视频剧集
/// </summary>
/// <returns></returns>
public List<VideoPage> GetVideoPages()
{
List<VideoPage> pages = new List<VideoPage>();
if (bangumiSeason == null) { return pages; }
if (bangumiSeason.Episodes == null) { return pages; }
if (bangumiSeason.Episodes.Count == 0) { return pages; }
int order = 0;
foreach (var episode in bangumiSeason.Episodes)
{
order++;
// 标题
string name;
// 判断title是否为数字如果是则将share_copy作为name否则将title作为name
if (int.TryParse(episode.Title, out int result))
{
name = episode.ShareCopy;
}
else
{
if (episode.LongTitle != null && episode.LongTitle != "")
{
name = $"{episode.Title} {episode.LongTitle}";
}
else
{
name = episode.Title;
}
}
VideoPage page = new VideoPage
{
Avid = episode.Aid,
Bvid = episode.Bvid,
Cid = episode.Cid,
EpisodeId = -1,
Order = order,
Name = name,
Duration = "N/A"
};
pages.Add(page);
}
return pages;
}
/// <summary>
/// 获取视频章节与剧集
/// </summary>
/// <returns></returns>
public List<VideoSection> GetVideoSections()
{
if (bangumiSeason == null) { return null; }
if (bangumiSeason.Section == null) { return null; }
if (bangumiSeason.Section.Count == 0) { return null; }
List<VideoSection> videoSections = new List<VideoSection>
{
new VideoSection
{
Id = bangumiSeason.Positive.Id,
Title = bangumiSeason.Positive.Title,
IsSelected = true,
VideoPages = GetVideoPages()
}
};
foreach (var section in bangumiSeason.Section)
{
List<VideoPage> pages = new List<VideoPage>();
int order = 0;
foreach (var episode in section.Episodes)
{
order++;
// 标题
string name;
if (episode.LongTitle != null && episode.LongTitle != "")
{
name = $"{episode.Title} {episode.LongTitle}";
}
else
{
name = episode.Title;
}
VideoPage page = new VideoPage
{
Avid = episode.Aid,
Bvid = episode.Bvid,
Cid = episode.Cid,
EpisodeId = -1,
Order = order,
Name = name,
Duration = "N/A"
};
pages.Add(page);
}
VideoSection videoSection = new VideoSection
{
Id = section.Id,
Title = section.Title,
VideoPages = pages
};
videoSections.Add(videoSection);
}
return videoSections;
}
/// <summary>
/// 获取视频流的信息从VideoPage返回
/// </summary>
/// <param name="page"></param>
public void GetVideoStream(VideoPage page)
{
var playUrl = VideoStream.GetBangumiPlayUrl(page.Avid, page.Bvid, page.Cid);
Utils.VideoPageInfo(playUrl, page);
}
/// <summary>
/// 获取视频信息
/// </summary>
/// <returns></returns>
public VideoInfoView GetVideoView()
{
if (bangumiSeason == null) { return null; }
// 查询、保存封面
// 将SeasonId保存到avid字段中
// 每集封面的cid保存到cid字段EpisodeId保存到bvid字段中
StorageCover storageCover = new StorageCover();
string coverUrl = bangumiSeason.Cover;
string cover = storageCover.GetCover(bangumiSeason.SeasonId, "", -1, coverUrl);
// 获取用户头像
string upName;
string header;
if (bangumiSeason.UpInfo != null)
{
upName = bangumiSeason.UpInfo.Name;
StorageHeader storageHeader = new StorageHeader();
header = storageHeader.GetHeader(bangumiSeason.UpInfo.Mid, bangumiSeason.UpInfo.Name, bangumiSeason.UpInfo.Avatar);
}
else
{
upName = "";
header = null;
}
// 为videoInfoView赋值
VideoInfoView videoInfoView = new VideoInfoView();
App.PropertyChangeAsync(new Action(() =>
{
videoInfoView.CoverUrl = coverUrl;
videoInfoView.Cover = new BitmapImage(new Uri(cover));
videoInfoView.Title = bangumiSeason.Title;
videoInfoView.VideoZone = DictionaryResource.GetString(BangumiType.Type[bangumiSeason.Type]);
videoInfoView.PlayNumber = Format.FormatNumber(bangumiSeason.Stat.Views);
videoInfoView.DanmakuNumber = Format.FormatNumber(bangumiSeason.Stat.Danmakus);
videoInfoView.LikeNumber = Format.FormatNumber(bangumiSeason.Stat.Likes);
videoInfoView.CoinNumber = Format.FormatNumber(bangumiSeason.Stat.Coins);
videoInfoView.FavoriteNumber = Format.FormatNumber(bangumiSeason.Stat.Favorites);
videoInfoView.ShareNumber = Format.FormatNumber(bangumiSeason.Stat.Share);
videoInfoView.ReplyNumber = Format.FormatNumber(bangumiSeason.Stat.Reply);
videoInfoView.Description = bangumiSeason.Evaluate;
videoInfoView.UpName = upName;
if (header != null)
{
StorageHeader storageHeader = new StorageHeader();
videoInfoView.UpHeader = storageHeader.GetHeaderThumbnail(header, 48, 48);
}
else
{
videoInfoView.UpHeader = null;
}
}));
return videoInfoView;
}
}
}

@ -0,0 +1,160 @@
using DownKyi.Core.BiliApi.BiliUtils;
using DownKyi.Core.BiliApi.Cheese;
using DownKyi.Core.BiliApi.Cheese.Models;
using DownKyi.Core.BiliApi.VideoStream;
using DownKyi.Core.Storage;
using DownKyi.Core.Utils;
using DownKyi.Models;
using DownKyi.Utils;
using System;
using System.Collections.Generic;
using System.Windows.Media.Imaging;
namespace DownKyi.Services
{
public class CheeseInfoService : IInfoService
{
private readonly CheeseView cheeseView;
public CheeseInfoService(string input)
{
if (input == null)
{
return;
}
if (ParseEntrance.IsCheeseSeasonUrl(input))
{
long seasonId = ParseEntrance.GetCheeseSeasonId(input);
cheeseView = CheeseInfo.CheeseViewInfo(seasonId);
}
if (ParseEntrance.IsCheeseEpisodeUrl(input))
{
long episodeId = ParseEntrance.GetCheeseEpisodeId(input);
cheeseView = CheeseInfo.CheeseViewInfo(-1, episodeId);
}
}
/// <summary>
/// 获取视频剧集
/// </summary>
/// <returns></returns>
public List<VideoPage> GetVideoPages()
{
List<VideoPage> pages = new List<VideoPage>();
if (cheeseView == null) { return pages; }
if (cheeseView.Episodes == null) { return pages; }
if (cheeseView.Episodes.Count == 0) { return pages; }
int order = 0;
foreach (var episode in cheeseView.Episodes)
{
order++;
string name = episode.Title;
string duration = Format.FormatDuration(episode.Duration - 1);
VideoPage page = new VideoPage
{
Avid = episode.Aid,
Bvid = null,
Cid = episode.Cid,
EpisodeId = episode.Id,
Order = order,
Name = name,
Duration = "N/A"
};
pages.Add(page);
}
return pages;
}
/// <summary>
/// 获取视频章节与剧集
/// </summary>
/// <returns></returns>
public List<VideoSection> GetVideoSections()
{
return null;
}
/// <summary>
/// 获取视频流的信息从VideoPage返回
/// </summary>
/// <param name="page"></param>
public void GetVideoStream(VideoPage page)
{
var playUrl = VideoStream.GetCheesePlayUrl(page.Avid, page.Bvid, page.Cid, page.EpisodeId);
Utils.VideoPageInfo(playUrl, page);
}
/// <summary>
/// 获取视频信息
/// </summary>
/// <returns></returns>
public VideoInfoView GetVideoView()
{
if (cheeseView == null) { return null; }
// 查询、保存封面
// 将SeasonId保存到avid字段中
// 每集封面的cid保存到cid字段EpisodeId保存到bvid字段中
StorageCover storageCover = new StorageCover();
string coverUrl = cheeseView.Cover;
string cover = storageCover.GetCover(cheeseView.SeasonId, "", -1, coverUrl);
// 获取用户头像
string upName;
string header;
if (cheeseView.UpInfo != null)
{
upName = cheeseView.UpInfo.Name;
StorageHeader storageHeader = new StorageHeader();
header = storageHeader.GetHeader(cheeseView.UpInfo.Mid, cheeseView.UpInfo.Name, cheeseView.UpInfo.Avatar);
}
else
{
upName = "";
header = null;
}
// 为videoInfoView赋值
VideoInfoView videoInfoView = new VideoInfoView();
App.PropertyChangeAsync(new Action(() =>
{
videoInfoView.CoverUrl = coverUrl;
videoInfoView.Cover = new BitmapImage(new Uri(cover));
videoInfoView.Title = cheeseView.Title;
videoInfoView.VideoZone = DictionaryResource.GetString("Cheese");
videoInfoView.CreateTime = "";
videoInfoView.PlayNumber = Format.FormatNumber(cheeseView.Stat.Play);
videoInfoView.DanmakuNumber = Format.FormatNumber(0);
videoInfoView.LikeNumber = Format.FormatNumber(0);
videoInfoView.CoinNumber = Format.FormatNumber(0);
videoInfoView.FavoriteNumber = Format.FormatNumber(0);
videoInfoView.ShareNumber = Format.FormatNumber(0);
videoInfoView.ReplyNumber = Format.FormatNumber(0);
videoInfoView.Description = cheeseView.Subtitle;
videoInfoView.UpName = upName;
if (header != null)
{
StorageHeader storageHeader = new StorageHeader();
videoInfoView.UpHeader = storageHeader.GetHeaderThumbnail(header, 48, 48);
}
else
{
videoInfoView.UpHeader = null;
}
}));
return videoInfoView;
}
}
}

@ -0,0 +1,16 @@
using DownKyi.Models;
using System.Collections.Generic;
namespace DownKyi.Services
{
public interface IInfoService
{
VideoInfoView GetVideoView();
List<VideoSection> GetVideoSections();
List<VideoPage> GetVideoPages();
void GetVideoStream(VideoPage page);
}
}

@ -0,0 +1,10 @@
using DownKyi.Models;
using System.Collections.Generic;
namespace DownKyi.Services
{
public interface IResolutionService
{
List<Resolution> GetResolution();
}
}

@ -0,0 +1,26 @@
using DownKyi.Models;
using System.Collections.Generic;
namespace DownKyi.Services
{
public class ResolutionService : IResolutionService
{
public List<Resolution> GetResolution()
{
List<Resolution> resolutions = new List<Resolution>
{
new Resolution { Name = "HDR 真彩", Id = 125 },
new Resolution { Name = "4K 超清", Id = 120 },
new Resolution { Name = "1080P 60帧", Id = 116 },
new Resolution { Name = "1080P 高码率", Id = 112 },
new Resolution { Name = "1080P 高清", Id = 80 },
new Resolution { Name = "720P 60帧", Id = 74 },
new Resolution { Name = "720P 高清", Id = 64 },
new Resolution { Name = "480P 清晰", Id = 32 },
new Resolution { Name = "360P 流畅", Id = 16 }
};
return resolutions;
}
}
}

@ -0,0 +1,210 @@
using DownKyi.Core.BiliApi.VideoStream.Models;
using DownKyi.Core.Settings;
using DownKyi.Core.Settings.Models;
using DownKyi.Core.Utils;
using DownKyi.Models;
using System.Collections.Generic;
using System.Linq;
namespace DownKyi.Services
{
internal static class Utils
{
/// <summary>
/// 从视频流更新VideoPage
/// </summary>
/// <param name="playUrl"></param>
/// <param name="page"></param>
internal static void VideoPageInfo(PlayUrl playUrl, VideoPage page)
{
if (playUrl == null)
{
return;
}
// 视频流信息
page.PlayUrl = playUrl;
// 获取设置
var userInfo = SettingsManager.GetInstance().GetUserInfo();
int defaultQuality = SettingsManager.GetInstance().GetQuality();
var videoCodecs = SettingsManager.GetInstance().GetVideoCodecs();
int defaultAudioQuality = SettingsManager.GetInstance().GetAudioQuality();
// 未登录时最高仅720P
if (userInfo.Mid == -1)
{
if (defaultQuality > 64)
{
defaultQuality = 64;
}
}
// 非大会员账户登录时如果设置的画质高于1080P则这里限制为1080P
if (!userInfo.IsVip)
{
if (defaultQuality > 80)
{
defaultQuality = 80;
}
}
if (playUrl.Durl != null)
{
// 音质
// 画质
// 视频编码
// 时长
return;
}
if (playUrl.Dash != null)
{
// 如果video列表或者audio列表没有内容则返回false
if (playUrl.Dash.Video == null) { return; }
if (playUrl.Dash.Video.Count == 0) { return; }
// 音质
page.AudioQualityFormatList = GetAudioQualityFormatList(playUrl, defaultAudioQuality);
if (page.AudioQualityFormatList.Count > 0)
{
page.AudioQualityFormat = page.AudioQualityFormatList[0];
}
// 画质 & 视频编码
page.VideoQualityList = GetVideoQualityList(playUrl, userInfo, defaultQuality, videoCodecs);
if (page.VideoQualityList.Count > 0)
{
page.VideoQuality = page.VideoQualityList[0];
}
// 时长
page.Duration = Format.FormatDuration(playUrl.Dash.Duration);
}
}
/// <summary>
/// 设置音质
/// </summary>
/// <param name="playUrl"></param>
/// <param name="defaultAudioQuality"></param>
/// <returns></returns>
private static List<string> GetAudioQualityFormatList(PlayUrl playUrl, int defaultAudioQuality)
{
List<string> audioQualityFormatList = new List<string>();
foreach (var audio in playUrl.Dash.Audio)
{
// 音质id大于设置画质时跳过
if (audio.Id > defaultAudioQuality) { continue; }
if (Core.BiliApi.BiliUtils.Constant.AudioQuality.ContainsKey(audio.Id))
{
ListHelper.AddUnique(audioQualityFormatList, Core.BiliApi.BiliUtils.Constant.AudioQuality[audio.Id]);
}
}
audioQualityFormatList.Sort(new StringLogicalComparer<string>());
audioQualityFormatList.Reverse();
return audioQualityFormatList;
}
/// <summary>
/// 设置画质 & 视频编码
/// </summary>
/// <param name="playUrl"></param>
/// <param name="defaultQuality"></param>
/// <param name="userInfo"></param>
/// <param name="videoCodecs"></param>
/// <returns></returns>
private static List<VideoQuality> GetVideoQualityList(PlayUrl playUrl, UserInfoSettings userInfo, int defaultQuality, VideoCodecs videoCodecs)
{
List<VideoQuality> videoQualityList = new List<VideoQuality>();
foreach (var video in playUrl.Dash.Video)
{
// 画质id大于设置画质时跳过
if (video.Id > defaultQuality) { continue; }
// 非大会员账户登录时
if (!userInfo.IsVip)
{
// 如果画质为720P60跳过
if (video.Id == 74) { continue; }
}
string qualityFormat = string.Empty;
var selectedQuality = playUrl.SupportFormats.FirstOrDefault(t => t.Quality == video.Id);
if (selectedQuality != null)
{
qualityFormat = selectedQuality.NewDescription;
}
// 寻找是否已存在这个画质
// 不存在则添加,存在则修改
string codecName = GetVideoCodecName(video.Codecs);
var videoQualityExist = videoQualityList.FirstOrDefault(t => t.Quality == video.Id);
if (videoQualityExist == null)
{
var videoCodecList = new List<string>();
ListHelper.AddUnique(videoCodecList, codecName);
var videoQuality = new VideoQuality()
{
Quality = video.Id,
QualityFormat = qualityFormat,
VideoCodecList = videoCodecList
};
videoQualityList.Add(videoQuality);
}
else
{
if (!videoQualityList[videoQualityList.IndexOf(videoQualityExist)].VideoCodecList.Exists(t => t.Equals(codecName)))
{
videoQualityList[videoQualityList.IndexOf(videoQualityExist)].VideoCodecList.Add(codecName);
}
}
// 设置选中的视频编码
var selectedVideoQuality = videoQualityList.FirstOrDefault(t => t.Quality == video.Id);
switch (videoCodecs)
{
case VideoCodecs.AVC:
if (videoQualityList[videoQualityList.IndexOf(selectedVideoQuality)].VideoCodecList.Contains("H.264/AVC"))
{
videoQualityList[videoQualityList.IndexOf(selectedVideoQuality)].SelectedVideoCodec = "H.264/AVC";
}
break;
case VideoCodecs.HEVC:
if (videoQualityList[videoQualityList.IndexOf(selectedVideoQuality)].VideoCodecList.Contains("H.265/HEVC"))
{
videoQualityList[videoQualityList.IndexOf(selectedVideoQuality)].SelectedVideoCodec = "H.265/HEVC";
}
break;
}
if (videoQualityList[videoQualityList.IndexOf(selectedVideoQuality)].VideoCodecList.Count == 1)
{
// 当获取的视频没有设置的视频编码时,执行
videoQualityList[videoQualityList.IndexOf(selectedVideoQuality)].SelectedVideoCodec = videoQualityList[videoQualityList.IndexOf(selectedVideoQuality)].VideoCodecList[0];
}
}
return videoQualityList;
}
/// <summary>
/// 根据输入的字符串判断是AVC还是HEVC
/// </summary>
/// <param name="origin"></param>
/// <returns></returns>
private static string GetVideoCodecName(string origin)
{
return origin.Contains("avc") ? "H.264/AVC" : origin.Contains("hev") ? "H.265/HEVC" : "";
}
}
}

@ -0,0 +1,236 @@
using DownKyi.Core.BiliApi.BiliUtils;
using DownKyi.Core.BiliApi.Video;
using DownKyi.Core.BiliApi.Video.Models;
using DownKyi.Core.BiliApi.VideoStream;
using DownKyi.Core.Storage;
using DownKyi.Core.Utils;
using DownKyi.Models;
using System;
using System.Collections.Generic;
using System.Windows.Media.Imaging;
namespace DownKyi.Services
{
public class VideoInfoService : IInfoService
{
private readonly VideoView videoView;
public VideoInfoService(string input)
{
if (input == null)
{
return;
}
if (ParseEntrance.IsAvId(input) || ParseEntrance.IsAvUrl(input))
{
long avid = ParseEntrance.GetAvId(input);
videoView = VideoInfo.VideoViewInfo(null, avid);
}
if (ParseEntrance.IsBvId(input) || ParseEntrance.IsBvUrl(input))
{
string bvid = ParseEntrance.GetBvId(input);
videoView = VideoInfo.VideoViewInfo(bvid);
}
}
/// <summary>
/// 获取视频剧集
/// </summary>
/// <returns></returns>
public List<Models.VideoPage> GetVideoPages()
{
if (videoView == null) { return null; }
if (videoView.Pages == null) { return null; }
if (videoView.Pages.Count == 0) { return null; }
List<Models.VideoPage> videoPages = new List<Models.VideoPage>();
int order = 0;
foreach (var page in videoView.Pages)
{
order++;
// 标题
string name;
if (videoView.Pages.Count == 1)
{
name = videoView.Title;
}
else
{
//name = page.part;
if (page.Part == "")
{
// 如果page.part为空字符串
name = $"{videoView.Title}-P{order}";
}
else
{
name = page.Part;
}
}
Models.VideoPage videoPage = new Models.VideoPage
{
Avid = videoView.Aid,
Bvid = videoView.Bvid,
Cid = page.Cid,
EpisodeId = -1,
Order = order,
Name = name,
Duration = "N/A"
};
videoPages.Add(videoPage);
}
return videoPages;
}
/// <summary>
/// 获取视频章节与剧集
/// </summary>
/// <returns></returns>
public List<VideoSection> GetVideoSections()
{
if (videoView == null) { return null; }
if (videoView.UgcSeason == null) { return null; }
if (videoView.UgcSeason.Sections == null) { return null; }
if (videoView.UgcSeason.Sections.Count == 0) { return null; }
List<VideoSection> videoSections = new List<VideoSection>();
foreach (var section in videoView.UgcSeason.Sections)
{
List<Models.VideoPage> pages = new List<Models.VideoPage>();
int order = 0;
foreach (var episode in section.Episodes)
{
order++;
Models.VideoPage page = new Models.VideoPage
{
Avid = episode.Aid,
Bvid = episode.Bvid,
Cid = episode.Cid,
EpisodeId = -1,
Order = order,
Name = episode.Title,
Duration = "N/A"
};
pages.Add(page);
}
VideoSection videoSection = new VideoSection
{
Id = section.Id,
Title = section.Title,
VideoPages = pages
};
videoSections.Add(videoSection);
}
videoSections[0].IsSelected = true;
return videoSections;
}
/// <summary>
/// 获取视频流的信息从VideoPage返回
/// </summary>
/// <param name="page"></param>
public void GetVideoStream(Models.VideoPage page)
{
var playUrl = VideoStream.GetVideoPlayUrl(page.Avid, page.Bvid, page.Cid);
Utils.VideoPageInfo(playUrl, page);
}
/// <summary>
/// 获取视频信息
/// </summary>
/// <returns></returns>
public VideoInfoView GetVideoView()
{
if (videoView == null) { return null; }
// 查询、保存封面
StorageCover storageCover = new StorageCover();
string coverUrl = videoView.Pic;
string cover = storageCover.GetCover(videoView.Aid, videoView.Bvid, videoView.Cid, coverUrl);
// 分区
string videoZone = string.Empty;
var zoneList = Core.BiliApi.Zone.VideoZone.Instance().GetZone();
var zone = zoneList.Find(it => it.Id == videoView.Tid);
if (zone != null)
{
var zoneParent = zoneList.Find(it => it.Id == zone.ParentId);
if (zoneParent != null)
{
videoZone = zoneParent.Name + ">" + zone.Name;
}
else
{
videoZone = zone.Name;
}
}
else
{
videoZone = videoView.Tname;
}
// 获取用户头像
string upName;
string header;
if (videoView.Owner != null)
{
upName = videoView.Owner.Name;
StorageHeader storageHeader = new StorageHeader();
header = storageHeader.GetHeader(videoView.Owner.Mid, videoView.Owner.Name, videoView.Owner.Face);
}
else
{
upName = "";
header = null;
}
// 为videoInfoView赋值
VideoInfoView videoInfoView = new VideoInfoView();
App.PropertyChangeAsync(new Action(() =>
{
videoInfoView.CoverUrl = coverUrl;
videoInfoView.Cover = new BitmapImage(new Uri(cover));
videoInfoView.Title = videoView.Title;
videoInfoView.VideoZone = videoZone;
DateTime startTime = TimeZone.CurrentTimeZone.ToLocalTime(new DateTime(1970, 1, 1)); // 当地时区
DateTime dateTime = startTime.AddSeconds(videoView.Pubdate);
videoInfoView.CreateTime = dateTime.ToString("yyyy-MM-dd HH:mm:ss");
videoInfoView.PlayNumber = Format.FormatNumber(videoView.Stat.View);
videoInfoView.DanmakuNumber = Format.FormatNumber(videoView.Stat.Danmaku);
videoInfoView.LikeNumber = Format.FormatNumber(videoView.Stat.Like);
videoInfoView.CoinNumber = Format.FormatNumber(videoView.Stat.Coin);
videoInfoView.FavoriteNumber = Format.FormatNumber(videoView.Stat.Favorite);
videoInfoView.ShareNumber = Format.FormatNumber(videoView.Stat.Share);
videoInfoView.ReplyNumber = Format.FormatNumber(videoView.Stat.Reply);
videoInfoView.Description = videoView.Desc;
videoInfoView.UpName = upName;
if (header != null)
{
StorageHeader storageHeader = new StorageHeader();
videoInfoView.UpHeader = storageHeader.GetHeaderThumbnail(header, 48, 48);
}
else
{
videoInfoView.UpHeader = null;
}
}));
return videoInfoView;
}
}
}

@ -0,0 +1,43 @@
<ResourceDictionary
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="clr-namespace:DownKyi.Themes">
<SolidColorBrush x:Key="BrushWindowBorder" Color="{DynamicResource ColorWindowBorder}" />
<SolidColorBrush x:Key="BrushCaptionForeground" Color="{DynamicResource ColorCaptionForeground}" />
<SolidColorBrush x:Key="BrushCaptionBackground" Color="{DynamicResource ColorCaptionBackground}" />
<SolidColorBrush x:Key="BrushSystemBtnTint" Color="{DynamicResource ColorSystemBtnTint}" />
<SolidColorBrush x:Key="BrushSystemBtnTintDark" Color="{DynamicResource ColorSystemBtnTintDark}" />
<SolidColorBrush x:Key="BrushSystemBtnHover" Color="{DynamicResource ColorSystemBtnHover}" />
<SolidColorBrush x:Key="BrushSystemBtnPressed" Color="{DynamicResource ColorSystemBtnPressed}" />
<SolidColorBrush x:Key="BrushCloseBtnHover" Color="{DynamicResource ColorCloseBtnHover}" />
<SolidColorBrush x:Key="BrushCloseBtnPressed" Color="{DynamicResource ColorCloseBtnPressed}" />
<SolidColorBrush x:Key="BrushPrimary" Color="{DynamicResource ColorPrimary}" />
<SolidColorBrush x:Key="BrushPrimaryTranslucent" Color="{DynamicResource ColorPrimaryTranslucent}" />
<SolidColorBrush x:Key="BrushPrimaryTranslucent2" Color="{DynamicResource ColorPrimaryTranslucent2}" />
<SolidColorBrush x:Key="BrushPrimaryTranslucent3" Color="{DynamicResource ColorPrimaryTranslucent3}" />
<SolidColorBrush x:Key="BrushForeground" Color="{DynamicResource ColorForeground}" />
<SolidColorBrush x:Key="BrushBackground" Color="{DynamicResource ColorBackground}" />
<SolidColorBrush x:Key="BrushForegroundDark" Color="{DynamicResource ColorForegroundDark}" />
<SolidColorBrush x:Key="BrushBackgroundDark" Color="{DynamicResource ColorBackgroundDark}" />
<SolidColorBrush x:Key="BrushForegroundGrey" Color="{DynamicResource ColorForegroundGrey}" />
<SolidColorBrush x:Key="BrushBackgroundGrey" Color="{DynamicResource ColorBackgroundGrey}" />
<SolidColorBrush x:Key="BrushBackgroundGreyTranslucent" Color="{DynamicResource ColorBackgroundGreyTranslucent}" />
<SolidColorBrush x:Key="BrushBackgroundGreyTranslucent2" Color="{DynamicResource ColorBackgroundGreyTranslucent2}" />
<SolidColorBrush x:Key="BrushBackgroundGreyTranslucent3" Color="{DynamicResource ColorBackgroundGreyTranslucent3}" />
<SolidColorBrush x:Key="BrushTabHeaderGrey" Color="{DynamicResource ColorTabHeaderGrey}" />
<SolidColorBrush x:Key="BrushHeaderGrey" Color="{DynamicResource ColorHeaderGrey}" />
<SolidColorBrush x:Key="BrushBorder" Color="{DynamicResource ColorBorder}" />
<SolidColorBrush x:Key="BrushImageBorder" Color="{DynamicResource ColorImageBorder}" />
<SolidColorBrush x:Key="BrushImageBackground" Color="{DynamicResource ColorImageBackground}" />
<SolidColorBrush x:Key="BrushText" Color="{DynamicResource ColorText}" />
<SolidColorBrush x:Key="BrushTextDark" Color="{DynamicResource ColorTextDark}" />
<SolidColorBrush x:Key="BrushTextGrey" Color="{DynamicResource ColorTextGrey}" />
</ResourceDictionary>

@ -0,0 +1,43 @@
<ResourceDictionary
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="clr-namespace:DownKyi.Themes.Colors">
<Color x:Key="ColorWindowBorder">Black</Color>
<Color x:Key="ColorCaptionForeground">Black</Color>
<Color x:Key="ColorCaptionBackground">white</Color>
<Color x:Key="ColorSystemBtnTint">white</Color>
<Color x:Key="ColorSystemBtnTintDark">black</Color>
<Color x:Key="ColorSystemBtnHover">#FF6ECEF8</Color>
<Color x:Key="ColorSystemBtnPressed">#FF30B8F6</Color>
<Color x:Key="ColorCloseBtnHover">#FFE81123</Color>
<Color x:Key="ColorCloseBtnPressed">#FFF1707A</Color>
<Color x:Key="ColorPrimary">#FF00A1D6</Color>
<Color x:Key="ColorPrimaryTranslucent">#C800A1D6</Color>
<Color x:Key="ColorPrimaryTranslucent2">#7F00A1D6</Color>
<Color x:Key="ColorPrimaryTranslucent3">#3300A1D6</Color>
<Color x:Key="ColorForeground">#FF00A1D6</Color>
<Color x:Key="ColorBackground">#FFFFFFFF</Color>
<Color x:Key="ColorForegroundDark">#FFFFFFFF</Color>
<Color x:Key="ColorBackgroundDark">#FF00A1D6</Color>
<Color x:Key="ColorForegroundGrey">#FFBDBDBD</Color>
<Color x:Key="ColorBackgroundGrey">#FFBDBDBD</Color>
<Color x:Key="ColorBackgroundGreyTranslucent">#C8BDBDBD</Color>
<Color x:Key="ColorBackgroundGreyTranslucent2">#7FBDBDBD</Color>
<Color x:Key="ColorBackgroundGreyTranslucent3">#33BDBDBD</Color>
<Color x:Key="ColorTabHeaderGrey">#FFF4F4F4</Color>
<Color x:Key="ColorHeaderGrey">#FFF4F4F4</Color>
<Color x:Key="ColorBorder">#FF999999</Color>
<Color x:Key="ColorImageBorder">#7FD0D0D0</Color>
<Color x:Key="ColorImageBackground">#7FD0D0D0</Color>
<Color x:Key="ColorText">white</Color>
<Color x:Key="ColorTextDark">black</Color>
<Color x:Key="ColorTextGrey">#FF999999</Color>
</ResourceDictionary>

@ -0,0 +1,29 @@
<ResourceDictionary
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="clr-namespace:DownKyi.Themes.Colors">
<Color x:Key="ColorWindowBorder">Black</Color>
<Color x:Key="ColorCaptionForeground">Black</Color>
<Color x:Key="ColorCaptionBackground">#7FD0D0D0</Color>
<Color x:Key="ColorSystemBtnTint">white</Color>
<Color x:Key="ColorSystemBtnTintDark">black</Color>
<Color x:Key="ColorSystemBtnHover">#FF6ECEF8</Color>
<Color x:Key="ColorSystemBtnPressed">#FF30B8F6</Color>
<Color x:Key="ColorCloseBtnHover">#FFF1707A</Color>
<Color x:Key="ColorCloseBtnPressed">#FFE81123</Color>
<Color x:Key="ColorPrimary">#FF00A1D6</Color>
<Color x:Key="ColorForeground">#FF00A1D6</Color>
<Color x:Key="ColorBackground">#FFFFFFFF</Color>
<Color x:Key="ColorForegroundDark">#FFFFFFFF</Color>
<Color x:Key="ColorBackgroundDark">#FF00A1D6</Color>
<Color x:Key="ColorImageBorder">#7FD0D0D0</Color>
<Color x:Key="ColorImageBackground">#7FD0D0D0</Color>
<Color x:Key="ColorText">white</Color>
<Color x:Key="ColorTextDark">black</Color>
</ResourceDictionary>

@ -0,0 +1,73 @@
<ResourceDictionary
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="clr-namespace:DownKyi.Themes.Styles">
<Style x:Key="BtnStyle" TargetType="{x:Type Button}">
<Setter Property="OverridesDefaultStyle" Value="True" />
<Setter Property="Cursor" Value="Hand" />
<Setter Property="Background" Value="Transparent" />
<Setter Property="BorderThickness" Value="0" />
<Setter Property="BorderBrush" Value="{x:Null}" />
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type Button}">
<Border
Padding="10,5"
Background="{TemplateBinding Background}"
BorderBrush="{TemplateBinding BorderBrush}"
BorderThickness="{TemplateBinding BorderThickness}"
CornerRadius="5">
<ContentPresenter
Name="content"
HorizontalAlignment="Center"
VerticalAlignment="Center" />
</Border>
<ControlTemplate.Triggers>
<Trigger Property="IsMouseOver" Value="True">
<Setter Property="Background" Value="{DynamicResource BrushPrimaryTranslucent}" />
</Trigger>
<Trigger Property="IsMouseOver" Value="False">
<Setter Property="Background" Value="{DynamicResource BrushPrimary}" />
</Trigger>
</ControlTemplate.Triggers>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
<Style x:Key="BtnBorderStyle" TargetType="{x:Type Button}">
<Setter Property="OverridesDefaultStyle" Value="True" />
<Setter Property="Cursor" Value="Hand" />
<Setter Property="Background" Value="{DynamicResource BrushBackground}" />
<Setter Property="BorderThickness" Value="1" />
<Setter Property="BorderBrush" Value="{x:Null}" />
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type Button}">
<Border
Padding="10,5"
Background="{TemplateBinding Background}"
BorderBrush="{DynamicResource BrushPrimary}"
BorderThickness="{TemplateBinding BorderThickness}"
CornerRadius="5">
<ContentPresenter
Name="content"
HorizontalAlignment="Center"
VerticalAlignment="Center" />
</Border>
<ControlTemplate.Triggers>
<Trigger Property="IsMouseOver" Value="True">
<Setter Property="Background" Value="{DynamicResource BrushPrimaryTranslucent3}" />
</Trigger>
</ControlTemplate.Triggers>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
</ResourceDictionary>

@ -0,0 +1,78 @@
<ResourceDictionary
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="clr-namespace:DownKyi.Themes.Styles">
<DrawingImage x:Key="CheckBox.UncheckedDrawingImage">
<DrawingImage.Drawing>
<DrawingGroup ClipGeometry="M0,0 V1024 H1024 V0 H0 Z">
<DrawingGroup.Transform>
<TranslateTransform X="4.2632564145606011E-14" Y="4.2632564145606011E-14" />
</DrawingGroup.Transform>
<GeometryDrawing Brush="#FF000000" Geometry="F1 M1024,1024z M0,0z M170.67,85.33Q134.67,86.67 110.67,110.67 86.67,134.67 85.33,170.67L85.33,853.33Q86.67,889.33 110.67,913.33 134.67,937.33 170.67,938.67L853.33,938.67Q889.33,937.33 913.33,913.33 937.33,889.33 938.67,853.33L938.67,170.67Q937.33,134.67 913.33,110.67 889.33,86.67 853.33,85.33L170.67,85.33z M170.67,0L853.33,0Q925.33,1.33 974,50 1022.67,98.67 1024,170.67L1024,853.33Q1022.67,925.33 974,974 925.33,1022.67 853.33,1024L170.67,1024Q98.67,1022.67 50,974 1.32999999999996,925.33 -4.2632564145606E-14,853.33L-4.2632564145606E-14,170.67Q1.32999999999996,98.67 50,50 98.67,1.32999999999996 170.67,-4.2632564145606E-14z" />
</DrawingGroup>
</DrawingImage.Drawing>
</DrawingImage>
<DrawingImage x:Key="CheckBox.CheckedDrawingImage">
<DrawingImage.Drawing>
<DrawingGroup ClipGeometry="M0,0 V1024 H1024 V0 H0 Z">
<DrawingGroup.Transform>
<TranslateTransform X="4.2632564145606011E-14" Y="4.2632564145606011E-14" />
</DrawingGroup.Transform>
<GeometryDrawing Brush="#FF00A1D6" Geometry="F1 M1024,1024z M0,0z M384,608L306.67,530.67Q286.67,512 259.34,512 232,512 212,531.34 192,550.67 192,576.67 192,602.67 210.67,626.67L333.33,749.33Q354.67,769.33 384,769.33 413.33,769.33 434.67,749.33L813.33,370.67Q832,350.67 832,323.34 832,296 812,276 792,256 764.66,256 737.33,256 717.33,274.67L384,608z M170.67,0L853.33,0Q925.33,1.33 974,50 1022.67,98.67 1024,170.67L1024,853.33Q1022.67,925.33 974,974 925.33,1022.67 853.33,1024L170.67,1024Q98.67,1022.67 50,974 1.32999999999996,925.33 -4.2632564145606E-14,853.33L-4.2632564145606E-14,170.67Q1.32999999999996,98.67 50,50 98.67,1.32999999999996 170.67,-4.2632564145606E-14z" />
</DrawingGroup>
</DrawingImage.Drawing>
</DrawingImage>
<Style x:Key="CheckBoxStyle" TargetType="{x:Type CheckBox}">
<Setter Property="OverridesDefaultStyle" Value="True" />
<Setter Property="Cursor" Value="Hand" />
<Setter Property="Background" Value="Transparent" />
<Setter Property="BorderThickness" Value="0" />
<Setter Property="BorderBrush" Value="{x:Null}" />
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type CheckBox}">
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition />
<ColumnDefinition />
</Grid.ColumnDefinitions>
<Border
Grid.Column="0"
Padding="0,0,5,0"
Background="{TemplateBinding Background}"
BorderBrush="{TemplateBinding BorderBrush}"
BorderThickness="{TemplateBinding BorderThickness}">
<Image
x:Name="nameIcon"
Width="14"
Height="14"
Margin="0,3"
HorizontalAlignment="Left"
VerticalAlignment="Center" />
</Border>
<ContentPresenter
Name="content"
Grid.Column="1"
HorizontalAlignment="Center"
VerticalAlignment="Center" />
</Grid>
<ControlTemplate.Triggers>
<Trigger Property="IsChecked" Value="True">
<Setter TargetName="nameIcon" Property="Source" Value="{StaticResource CheckBox.CheckedDrawingImage}" />
</Trigger>
<Trigger Property="IsChecked" Value="False">
<Setter TargetName="nameIcon" Property="Source" Value="{StaticResource CheckBox.UncheckedDrawingImage}" />
</Trigger>
</ControlTemplate.Triggers>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
</ResourceDictionary>

@ -0,0 +1,30 @@
<ResourceDictionary
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="clr-namespace:DownKyi.Themes.Styles">
<Style x:Key="ImageBtnStyle" TargetType="{x:Type Button}">
<Setter Property="OverridesDefaultStyle" Value="True" />
<Setter Property="Cursor" Value="Hand" />
<Setter Property="Background" Value="Transparent" />
<Setter Property="BorderThickness" Value="0" />
<Setter Property="BorderBrush" Value="{x:Null}" />
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type Button}">
<Border
Background="{TemplateBinding Background}"
BorderBrush="{TemplateBinding BorderBrush}"
BorderThickness="{TemplateBinding BorderThickness}">
<ContentPresenter
Name="content"
HorizontalAlignment="Center"
VerticalAlignment="Center" />
</Border>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
</ResourceDictionary>

@ -0,0 +1,84 @@
<ResourceDictionary xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
<Style x:Key="LeftTabHeaderItemStyle" TargetType="{x:Type ListBoxItem}">
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type ListBoxItem}">
<Grid x:Name="panel" Height="60">
<StackPanel
Margin="20,0,0,0"
HorizontalAlignment="Left"
VerticalAlignment="Center"
Orientation="Horizontal">
<ContentControl
Width="24"
Height="24"
Margin="0,0,5,0">
<ContentControl.Style>
<Style TargetType="{x:Type ContentControl}">
<Setter Property="Visibility" Value="Visible" />
<Style.Triggers>
<DataTrigger Binding="{Binding Image}" Value="{x:Null}">
<Setter Property="Visibility" Value="Collapsed" />
</DataTrigger>
</Style.Triggers>
</Style>
</ContentControl.Style>
<Path
x:Name="image"
Width="{Binding Image.Width}"
Height="{Binding Image.Height}"
Data="{Binding Image.Data}"
Fill="{Binding Image.Fill}"
Stretch="UniformToFill" />
</ContentControl>
<TextBlock
x:Name="text"
VerticalAlignment="Center"
FontSize="12"
Text="{Binding Title}" />
</StackPanel>
</Grid>
<ControlTemplate.Triggers>
<Trigger Property="IsMouseOver" Value="False">
<Setter TargetName="panel" Property="Background" Value="{DynamicResource BrushTabHeaderGrey}" />
<Setter TargetName="text" Property="Foreground" Value="{DynamicResource BrushTextDark}" />
<Setter TargetName="image" Property="Fill" Value="{Binding Image.Fill}" />
</Trigger>
<Trigger Property="IsMouseOver" Value="true">
<Setter TargetName="panel" Property="Background" Value="{DynamicResource BrushBackgroundGreyTranslucent2}" />
<Setter TargetName="text" Property="Foreground" Value="{DynamicResource BrushPrimary}" />
<Setter TargetName="image" Property="Fill" Value="{DynamicResource BrushPrimary}" />
</Trigger>
<Trigger Property="Selector.IsSelected" Value="true">
<Setter TargetName="panel" Property="Background" Value="{DynamicResource BrushBackground}" />
<Setter TargetName="text" Property="Foreground" Value="{DynamicResource BrushPrimary}" />
<Setter TargetName="image" Property="Fill" Value="{DynamicResource BrushPrimary}" />
</Trigger>
</ControlTemplate.Triggers>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
<Style x:Key="LeftTabHeaderStyle" TargetType="{x:Type ListBox}">
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="ListBox">
<Border
Padding="0"
Background="{DynamicResource BrushTabHeaderGrey}"
BorderBrush="{TemplateBinding BorderBrush}"
BorderThickness="{TemplateBinding BorderThickness}">
<ScrollViewer Focusable="False">
<ItemsPresenter />
</ScrollViewer>
</Border>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
</ResourceDictionary>

@ -0,0 +1,4 @@
<ResourceDictionary
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="clr-namespace:DownKyi.Themes.Styles" />

@ -0,0 +1,69 @@
<ResourceDictionary xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
<DrawingImage x:Key="Radio.UnselectedDrawingImage">
<DrawingImage.Drawing>
<DrawingGroup ClipGeometry="M0,0 V1024 H1024 V0 H0 Z">
<GeometryDrawing Brush="#FF000000" Geometry="F1 M1024,1024z M0,0z M512,0Q295,6 150.5,150.5 6,295 0,512 6,729 150.5,873.5 295,1018 512,1024 729,1018 873.5,873.5 1018,729 1024,512 1018,295 873.5,150.5 729,6 512,0z M512,960Q320,955 194.5,829.5 69,704 64,512 69,320 194.5,194.5 320,69 512,64 704,69 829.5,194.5 955,320 960,512 955,704 829.5,829.5 704,955 512,960z" />
</DrawingGroup>
</DrawingImage.Drawing>
</DrawingImage>
<DrawingImage x:Key="Radio.SelectedDrawingImage">
<DrawingImage.Drawing>
<DrawingGroup ClipGeometry="M0,0 V1024 H1024 V0 H0 Z">
<GeometryDrawing Brush="#FF00A1D6" Geometry="F1 M1024,1024z M0,0z M512,0Q295,6 150.5,150.5 6,295 0,512 6,729 150.5,873.5 295,1018 512,1024 729,1018 873.5,873.5 1018,729 1024,512 1018,295 873.5,150.5 729,6 512,0z M512,960Q320,955 194.5,829.5 69,704 64,512 69,320 194.5,194.5 320,69 512,64 704,69 829.5,194.5 955,320 960,512 955,704 829.5,829.5 704,955 512,960z M256,512Q259,621 331,693 403,765 512,768 621,765 693,693 765,621 768,512 765,403 693,331 621,259 512,256 403,259 331,331 259,403 256,512z" />
</DrawingGroup>
</DrawingImage.Drawing>
</DrawingImage>
<Style x:Key="RadioStyle" TargetType="{x:Type RadioButton}">
<Setter Property="OverridesDefaultStyle" Value="True" />
<Setter Property="Cursor" Value="Hand" />
<Setter Property="Background" Value="Transparent" />
<Setter Property="BorderThickness" Value="0" />
<Setter Property="BorderBrush" Value="{x:Null}" />
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type RadioButton}">
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition />
<ColumnDefinition />
</Grid.ColumnDefinitions>
<Border
Grid.Column="0"
Padding="0,0,5,0"
Background="{TemplateBinding Background}"
BorderBrush="{TemplateBinding BorderBrush}"
BorderThickness="{TemplateBinding BorderThickness}">
<Image
x:Name="nameIcon"
Width="14"
Height="14"
Margin="0,3"
HorizontalAlignment="Left"
VerticalAlignment="Center" />
</Border>
<ContentPresenter
Name="content"
Grid.Column="1"
HorizontalAlignment="Center"
VerticalAlignment="Center" />
</Grid>
<ControlTemplate.Triggers>
<Trigger Property="IsChecked" Value="True">
<Setter TargetName="nameIcon" Property="Source" Value="{StaticResource Radio.SelectedDrawingImage}" />
</Trigger>
<Trigger Property="IsChecked" Value="False">
<Setter TargetName="nameIcon" Property="Source" Value="{StaticResource Radio.UnselectedDrawingImage}" />
</Trigger>
</ControlTemplate.Triggers>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
</ResourceDictionary>

@ -0,0 +1,68 @@
<ResourceDictionary
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="clr-namespace:DownKyi.Themes.Styles">
<Style x:Key="SystemBtnStyle" TargetType="{x:Type Button}">
<Setter Property="OverridesDefaultStyle" Value="True" />
<Setter Property="Cursor" Value="Hand" />
<Setter Property="Background" Value="Transparent" />
<Setter Property="BorderThickness" Value="0" />
<Setter Property="BorderBrush" Value="{x:Null}" />
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type Button}">
<Border
Background="{TemplateBinding Background}"
BorderBrush="{TemplateBinding BorderBrush}"
BorderThickness="{TemplateBinding BorderThickness}">
<ContentPresenter
Name="content"
HorizontalAlignment="Center"
VerticalAlignment="Center" />
</Border>
<ControlTemplate.Triggers>
<Trigger Property="IsMouseOver" Value="True">
<Setter Property="Background" Value="{DynamicResource BrushSystemBtnHover}" />
</Trigger>
<Trigger Property="IsPressed" Value="True">
<Setter Property="Background" Value="{DynamicResource BrushSystemBtnPressed}" />
</Trigger>
</ControlTemplate.Triggers>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
<Style
x:Key="CloseBtnStyle"
BasedOn="{StaticResource SystemBtnStyle}"
TargetType="{x:Type Button}">
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type Button}">
<Border
Background="{TemplateBinding Background}"
BorderBrush="{TemplateBinding BorderBrush}"
BorderThickness="{TemplateBinding BorderThickness}">
<ContentPresenter
Name="content"
HorizontalAlignment="Center"
VerticalAlignment="Center" />
</Border>
<ControlTemplate.Triggers>
<Trigger Property="IsMouseOver" Value="True">
<Setter Property="Background" Value="{DynamicResource BrushCloseBtnHover}" />
</Trigger>
<Trigger Property="IsPressed" Value="True">
<Setter Property="Background" Value="{DynamicResource BrushCloseBtnPressed}" />
</Trigger>
</ControlTemplate.Triggers>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
</ResourceDictionary>

@ -0,0 +1,28 @@
<ResourceDictionary
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="clr-namespace:DownKyi.Themes">
<ResourceDictionary.MergedDictionaries>
<!-- 每个主题都相同 -->
<ResourceDictionary Source="ColorBrush.xaml" />
<!-- 根据实际需要调整 -->
<ResourceDictionary Source="Colors/ColorDefault.xaml" />
<ResourceDictionary Source="Styles/StyleBtn.xaml" />
<ResourceDictionary Source="Styles/StyleImageBtn.xaml" />
<ResourceDictionary Source="Styles/StyleSystemBtn.xaml" />
<ResourceDictionary Source="Styles/StyleCheckBox.xaml" />
<ResourceDictionary Source="Styles/StyleListBox.xaml" />
<ResourceDictionary Source="Styles/StyleListView.xaml" />
<ResourceDictionary Source="Styles/StyleRadio.xaml" />
</ResourceDictionary.MergedDictionaries>
<!-- 设置字体 -->
<Style TargetType="{x:Type TextElement}">
<Setter Property="FontFamily" Value="Microsoft YaHei UI, Source Han Sans Normal" />
</Style>
<Style TargetType="{x:Type TextBlock}">
<Setter Property="FontFamily" Value="Microsoft YaHei UI, Source Han Sans Normal" />
</Style>
</ResourceDictionary>

@ -0,0 +1,28 @@
<ResourceDictionary
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="clr-namespace:DownKyi.Themes">
<ResourceDictionary.MergedDictionaries>
<!-- 每个主题都相同 -->
<ResourceDictionary Source="ColorBrush.xaml" />
<!-- 根据实际需要调整 -->
<ResourceDictionary Source="Colors/ColorDiy.xaml" />
<ResourceDictionary Source="Styles/StyleBtn.xaml" />
<ResourceDictionary Source="Styles/StyleImageBtn.xaml" />
<ResourceDictionary Source="Styles/StyleSystemBtn.xaml" />
<ResourceDictionary Source="Styles/StyleCheckBox.xaml" />
<ResourceDictionary Source="Styles/StyleListBox.xaml" />
<ResourceDictionary Source="Styles/StyleListView.xaml" />
<ResourceDictionary Source="Styles/StyleRadio.xaml" />
</ResourceDictionary.MergedDictionaries>
<!-- 设置字体 -->
<Style TargetType="{x:Type TextElement}">
<Setter Property="FontFamily" Value="Microsoft YaHei UI, Source Han Sans Normal" />
</Style>
<Style TargetType="{x:Type TextBlock}">
<Setter Property="FontFamily" Value="Microsoft YaHei UI, Source Han Sans Normal" />
</Style>
</ResourceDictionary>

@ -0,0 +1,45 @@
using System;
using System.Runtime.InteropServices;
using System.Windows;
using System.Windows.Interop;
namespace DownKyi.Utils
{
public class ClipboardHooker : IDisposable
{
private const int WM_CLIPBOARDUPDATE = 0x031D;
[DllImport("User32.dll")]
private static extern bool AddClipboardFormatListener(IntPtr hwnd);
private readonly HwndSource _hwndSource = null;
public void Dispose()
{
_hwndSource?.Dispose();
}
public ClipboardHooker(Window window)
{
WindowInteropHelper helper = new WindowInteropHelper(window);
_hwndSource = HwndSource.FromHwnd(helper.Handle);
bool r = AddClipboardFormatListener(_hwndSource.Handle);
if (r)
{
_hwndSource.AddHook(new HwndSourceHook(OnHooked));
}
}
private IntPtr OnHooked(IntPtr hwnd, int msg, IntPtr wParam, IntPtr lParam, ref bool handled)
{
if (msg == WM_CLIPBOARDUPDATE)
{
ClipboardUpdated?.Invoke(this, EventArgs.Empty);
return IntPtr.Zero;
}
return IntPtr.Zero;
}
public event EventHandler ClipboardUpdated;
}
}

@ -0,0 +1,26 @@
using System.Windows.Forms;
namespace DownKyi.Utils
{
public static class DialogUtils
{
/// <summary>
/// 弹出选择文件夹弹窗
/// </summary>
/// <returns></returns>
public static string SetDownloadDirectory()
{
// 选择文件夹
FolderBrowserDialog dialog = new FolderBrowserDialog
{
Description = DictionaryResource.GetString("SelectDirectory")
};
DialogResult showDialog = dialog.ShowDialog();
return showDialog == DialogResult.OK || showDialog == DialogResult.Yes
? string.IsNullOrEmpty(dialog.SelectedPath) ? "" : dialog.SelectedPath : "";
}
}
}

@ -0,0 +1,83 @@
using System;
using System.Collections.Generic;
using System.Windows;
using System.Windows.Media;
namespace DownKyi.Utils
{
public static class DictionaryResource
{
/// <summary>
/// 从资源获取颜色的16进制字符串
/// </summary>
/// <param name="resourceKey"></param>
/// <returns></returns>
public static string GetColor(string resourceKey)
{
Color color = (Color)Application.Current.Resources[resourceKey];
return color.ToString();
}
/// <summary>
/// 从资源获取字符串
/// </summary>
/// <param name="resourceKey"></param>
/// <returns></returns>
public static string GetString(string resourceKey)
{
return (string)Application.Current.Resources[resourceKey];
}
/// <summary>
/// 根据languageCode切换界面语言
/// </summary>
/// <param name="languageCode">语言-国家代码</param>
public static void LoadLanguage(string languageCode)
{
LoadXamlDictionary(languageCode, "Languages");
}
/// <summary>
/// 切换主题
/// </summary>
/// <param name="theme">主题</param>
public static void LoadTheme(string theme)
{
LoadXamlDictionary(theme, "Themes");
}
/// <summary>
/// 更换xaml资源字典
/// </summary>
/// <param name="fileName">xaml文件名不包含扩展名</param>
/// <param name="package">文件所在包(路径)</param>
private static void LoadXamlDictionary(string fileName, string package)
{
if (string.IsNullOrEmpty(fileName) == false)
{
var dictionariesToRemove = new List<ResourceDictionary>();
foreach (var dictionary in Application.Current.Resources.MergedDictionaries)
{
if (dictionary.Source.ToString().Contains($"{package}"))
{
dictionariesToRemove.Add(dictionary);
}
}
foreach (var item in dictionariesToRemove)
{
Application.Current.Resources.MergedDictionaries.Remove(item);
}
var languageDictionary = new ResourceDictionary()
{
Source = new Uri($"pack://application:,,,/DownKyi;component/{package}/{fileName}.xaml")
};
Application.Current.Resources.MergedDictionaries.Add(languageDictionary);
}
}
}
}

@ -0,0 +1,48 @@
using Prism.Events;
using Prism.Mvvm;
using Prism.Regions;
using System;
using System.Windows;
namespace DownKyi.ViewModels
{
public class BaseViewModel : BindableBase, INavigationAware
{
protected readonly IEventAggregator eventAggregator;
protected string ParentView = string.Empty;
public BaseViewModel(IEventAggregator eventAggregator)
{
this.eventAggregator = eventAggregator;
}
public bool IsNavigationTarget(NavigationContext navigationContext)
{
return true;
}
public virtual void OnNavigatedFrom(NavigationContext navigationContext)
{
}
public virtual void OnNavigatedTo(NavigationContext navigationContext)
{
string viewName = navigationContext.Parameters.GetValue<string>("Parent");
if (viewName != null)
{
ParentView = viewName;
}
}
/// <summary>
/// 异步修改绑定到UI的属性
/// </summary>
/// <param name="callback"></param>
protected void PropertyChangeAsync(Action callback)
{
Application.Current.Dispatcher.Invoke(callback);
}
}
}

@ -0,0 +1,134 @@
using DownKyi.Images;
using DownKyi.Models;
using DownKyi.Utils;
using Prism.Commands;
using Prism.Mvvm;
using Prism.Services.Dialogs;
using System;
namespace DownKyi.ViewModels.Dialogs
{
public class BaseDialogViewModel : BindableBase, IDialogAware
{
#region 页面属性申明
private string title;
public string Title
{
get { return title; }
set { SetProperty(ref title, value); }
}
private VectorImage closeIcon;
public VectorImage CloseIcon
{
get { return closeIcon; }
set { SetProperty(ref closeIcon, value); }
}
#endregion
public BaseDialogViewModel()
{
#region 属性初始化
Title = new AppInfo().Name;
CloseIcon = new VectorImage
{
Height = SystemIcon.Instance().Close.Height,
Width = SystemIcon.Instance().Close.Width,
Data = SystemIcon.Instance().Close.Data,
Fill = SystemIcon.Instance().Close.Fill
};
#endregion
}
#region 命令申明
// 鼠标进入关闭按钮事件
private DelegateCommand closeEnterCommand;
public DelegateCommand CloseEnterCommand => closeEnterCommand ?? (closeEnterCommand = new DelegateCommand(ExecuteCloseEnterCommand));
/// <summary>
/// 鼠标进入关闭按钮事件
/// </summary>
private void ExecuteCloseEnterCommand()
{
SetEnterStyle(CloseIcon);
}
// 鼠标离开关闭按钮事件
private DelegateCommand closeLeaveCommand;
public DelegateCommand CloseLeaveCommand => closeLeaveCommand ?? (closeLeaveCommand = new DelegateCommand(ExecuteCloseLeaveCommand));
/// <summary>
/// 鼠标离开关闭按钮事件
/// </summary>
private void ExecuteCloseLeaveCommand()
{
SetLeaveStyle(CloseIcon);
}
// 关闭窗口事件
private DelegateCommand closeCommand;
public DelegateCommand CloseCommand => closeCommand ?? (closeCommand = new DelegateCommand(ExecuteCloseCommand));
/// <summary>
/// 关闭窗口事件
/// </summary>
private void ExecuteCloseCommand()
{
ButtonResult result = ButtonResult.Cancel;
RaiseRequestClose(new DialogResult(result));
}
#endregion
/// <summary>
/// 鼠标进入系统按钮时的图标样式
/// </summary>
/// <param name="icon">图标</param>
private void SetEnterStyle(VectorImage icon)
{
icon.Fill = DictionaryResource.GetColor("ColorSystemBtnTint");
}
/// <summary>
/// 鼠标离开系统按钮时的图标样式
/// </summary>
/// <param name="icon">图标</param>
private void SetLeaveStyle(VectorImage icon)
{
icon.Fill = DictionaryResource.GetColor("ColorSystemBtnTintDark");
}
#region 接口实现
//触发窗体关闭事件
public virtual void RaiseRequestClose(IDialogResult dialogResult)
{
RequestClose?.Invoke(dialogResult);
}
public event Action<IDialogResult> RequestClose;
public bool CanCloseDialog()
{
return true;
}
public void OnDialogClosed()
{
}
public void OnDialogOpened(IDialogParameters parameters)
{
}
#endregion
}
}

@ -0,0 +1,203 @@
using DownKyi.Core.Settings;
using DownKyi.Core.Utils;
using DownKyi.Events;
using DownKyi.Images;
using DownKyi.Utils;
using Prism.Commands;
using Prism.Events;
using Prism.Services.Dialogs;
using System.Collections.Generic;
namespace DownKyi.ViewModels.Dialogs
{
public class ViewDirectorySelectorViewModel : BaseDialogViewModel
{
public const string Tag = "DialogDirectorySelector";
private readonly IEventAggregator eventAggregator;
// 历史文件夹的数量
private readonly int maxDirectoryListCount = 20;
#region 页面属性申明
private VectorImage cloudDownloadIcon;
public VectorImage CloudDownloadIcon
{
get { return cloudDownloadIcon; }
set { SetProperty(ref cloudDownloadIcon, value); }
}
private VectorImage folderIcon;
public VectorImage FolderIcon
{
get { return folderIcon; }
set { SetProperty(ref folderIcon, value); }
}
private bool isDefaultDownloadDirectory;
public bool IsDefaultDownloadDirectory
{
get { return isDefaultDownloadDirectory; }
set { SetProperty(ref isDefaultDownloadDirectory, value); }
}
private List<string> directoryList;
public List<string> DirectoryList
{
get { return directoryList; }
set { SetProperty(ref directoryList, value); }
}
private string directory;
public string Directory
{
get { return directory; }
set
{
SetProperty(ref directory, value);
DriveName = directory.Substring(0, 1).ToUpper();
DriveNameFreeSpace = Format.FormatFileSize(HardDisk.GetHardDiskFreeSpace(DriveName));
}
}
private string driveName;
public string DriveName
{
get { return driveName; }
set { SetProperty(ref driveName, value); }
}
private string driveNameFreeSpace;
public string DriveNameFreeSpace
{
get { return driveNameFreeSpace; }
set { SetProperty(ref driveNameFreeSpace, value); }
}
#endregion
public ViewDirectorySelectorViewModel(IEventAggregator eventAggregator)
{
this.eventAggregator = eventAggregator;
#region 属性初始化
Title = DictionaryResource.GetString("DownloadDirectorySelector");
CloudDownloadIcon = NormalIcon.Instance().CloudDownload;
CloudDownloadIcon.Fill = DictionaryResource.GetColor("ColorPrimary");
FolderIcon = NormalIcon.Instance().Folder;
FolderIcon.Fill = DictionaryResource.GetColor("ColorPrimary");
#endregion
// 历史下载目录
DirectoryList = SettingsManager.GetInstance().GetHistoryVideoRootPaths();
string directory = SettingsManager.GetInstance().GetSaveVideoRootPath();
if (!DirectoryList.Contains(directory))
{
ListHelper.InsertUnique(DirectoryList, directory, 0);
}
Directory = directory;
// 是否使用默认下载目录
IsDefaultDownloadDirectory = SettingsManager.GetInstance().IsUseSaveVideoRootPath() == AllowStatus.YES;
}
#region 命令申明
// 浏览文件夹事件
private DelegateCommand browseCommand;
public DelegateCommand BrowseCommand => browseCommand ?? (browseCommand = new DelegateCommand(ExecuteBrowseCommand));
/// <summary>
/// 浏览文件夹事件
/// </summary>
private void ExecuteBrowseCommand()
{
string directory = SetDirectory();
if (directory == null)
{
eventAggregator.GetEvent<MessageEvent>().Publish(DictionaryResource.GetString("WarningNullDirectory"));
Directory = string.Empty;
}
else
{
ListHelper.InsertUnique(DirectoryList, directory, 0);
Directory = directory;
if (DirectoryList.Count > maxDirectoryListCount)
{
DirectoryList.RemoveAt(maxDirectoryListCount);
}
}
}
// 确认下载事件
private DelegateCommand downloadCommand;
public DelegateCommand DownloadCommand => downloadCommand ?? (downloadCommand = new DelegateCommand(ExecuteDownloadCommand));
/// <summary>
/// 确认下载事件
/// </summary>
private void ExecuteDownloadCommand()
{
if (Directory == null || Directory == string.Empty)
{
return;
}
// 设此文件夹为默认下载文件夹
if (IsDefaultDownloadDirectory)
{
SettingsManager.GetInstance().IsUseSaveVideoRootPath(AllowStatus.YES);
}
else
{
SettingsManager.GetInstance().IsUseSaveVideoRootPath(AllowStatus.NO);
}
// 将Directory移动到第一项
// 如果直接在ComboBox中选择的就需要
// 否则选中项不会在下次出现在第一项
ListHelper.InsertUnique(DirectoryList, Directory, 0);
// 将更新后的DirectoryList写入历史中
SettingsManager.GetInstance().SetSaveVideoRootPath(Directory);
SettingsManager.GetInstance().SetHistoryVideoRootPaths(DirectoryList);
ButtonResult result = ButtonResult.OK;
IDialogParameters parameters = new DialogParameters
{
{ "directory", Directory }
};
RaiseRequestClose(new DialogResult(result, parameters));
}
#endregion
/// <summary>
/// 设置下载路径
/// </summary>
/// <returns></returns>
private string SetDirectory()
{
// 下载目录
string path;
// 弹出选择下载目录的窗口
path = DialogUtils.SetDownloadDirectory();
if (path == null || path == "")
{
return null;
}
return path;
}
}
}

@ -0,0 +1,120 @@
using DownKyi.Core.Settings;
using DownKyi.Utils;
using Prism.Commands;
using Prism.Services.Dialogs;
using System;
using System.Windows;
namespace DownKyi.ViewModels.Dialogs
{
public class ViewParsingSelectorViewModel : BaseDialogViewModel
{
public const string Tag = "DialogParsingSelector";
#region 页面属性申明
private bool isParseDefault;
public bool IsParseDefault
{
get { return isParseDefault; }
set { SetProperty(ref isParseDefault, value); }
}
#endregion
public ViewParsingSelectorViewModel()
{
#region 属性初始化
Title = DictionaryResource.GetString("ParsingSelector");
// 解析范围
ParseScope parseScope = SettingsManager.GetInstance().GetParseScope();
IsParseDefault = parseScope != ParseScope.NONE;
#endregion
}
#region 命令申明
// 解析当前项事件
private DelegateCommand parseSelectedItemCommand;
public DelegateCommand ParseSelectedItemCommand => parseSelectedItemCommand ?? (parseSelectedItemCommand = new DelegateCommand(ExecuteParseSelectedItemCommand));
/// <summary>
/// 解析当前项事件
/// </summary>
private void ExecuteParseSelectedItemCommand()
{
SetParseScopeSetting(ParseScope.SELECTED_ITEM);
ButtonResult result = ButtonResult.OK;
IDialogParameters parameters = new DialogParameters
{
{ "parseScope", ParseScope.SELECTED_ITEM }
};
RaiseRequestClose(new DialogResult(result, parameters));
}
// 解析当前页视频事件
private DelegateCommand parseCurrentSectionCommand;
public DelegateCommand ParseCurrentSectionCommand => parseCurrentSectionCommand ?? (parseCurrentSectionCommand = new DelegateCommand(ExecuteParseCurrentSectionCommand));
/// <summary>
/// 解析当前页视频事件
/// </summary>
private void ExecuteParseCurrentSectionCommand()
{
SetParseScopeSetting(ParseScope.CURRENT_SECTION);
ButtonResult result = ButtonResult.OK;
IDialogParameters parameters = new DialogParameters
{
{ "parseScope", ParseScope.CURRENT_SECTION }
};
RaiseRequestClose(new DialogResult(result, parameters));
}
// 解析所有视频事件
private DelegateCommand parseAllCommand;
public DelegateCommand ParseAllCommand => parseAllCommand ?? (parseAllCommand = new DelegateCommand(ExecuteParseAllCommand));
/// <summary>
/// 解析所有视频事件
/// </summary>
private void ExecuteParseAllCommand()
{
SetParseScopeSetting(ParseScope.ALL);
ButtonResult result = ButtonResult.OK;
IDialogParameters parameters = new DialogParameters
{
{ "parseScope", ParseScope.ALL }
};
RaiseRequestClose(new DialogResult(result, parameters));
}
#endregion
/// <summary>
/// 写入设置
/// </summary>
/// <param name="parseScope"></param>
private void SetParseScopeSetting(ParseScope parseScope)
{
if (IsParseDefault)
{
SettingsManager.GetInstance().SetParseScope(parseScope);
}
else
{
SettingsManager.GetInstance().SetParseScope(ParseScope.NONE);
}
}
}
}

@ -0,0 +1,19 @@
using Prism.Commands;
using Prism.Events;
using Prism.Mvvm;
using System;
using System.Collections.Generic;
using System.Linq;
namespace DownKyi.ViewModels.DownloadManager
{
public class ViewDownloadFinishedViewModel : BaseViewModel
{
public const string Tag = "PageDownloadManagerDownloadFinished";
public ViewDownloadFinishedViewModel(IEventAggregator eventAggregator) : base(eventAggregator)
{
}
}
}

@ -0,0 +1,19 @@
using Prism.Commands;
using Prism.Events;
using Prism.Mvvm;
using System;
using System.Collections.Generic;
using System.Linq;
namespace DownKyi.ViewModels.DownloadManager
{
public class ViewDownloadingViewModel : BaseViewModel
{
public const string Tag = "PageDownloadManagerDownloading";
public ViewDownloadingViewModel(IEventAggregator eventAggregator) : base(eventAggregator)
{
}
}
}

@ -0,0 +1,385 @@
using DownKyi.Core.BiliApi.BiliUtils;
using DownKyi.Core.Logging;
using DownKyi.Core.Settings;
using DownKyi.Events;
using DownKyi.Images;
using DownKyi.Utils;
using Prism.Commands;
using Prism.Events;
using Prism.Mvvm;
using Prism.Regions;
using System;
using System.Threading;
using System.Windows;
using System.Windows.Threading;
namespace DownKyi.ViewModels
{
public class MainWindowViewModel : BindableBase
{
private readonly IEventAggregator eventAggregator;
private ClipboardHooker clipboardHooker;
#region 页面属性申明
private string title;
public string Title
{
get { return title; }
set { SetProperty(ref title, value); }
}
private WindowState winState;
public WindowState WinState
{
get { return winState; }
set
{
if (value == WindowState.Maximized)
{
ResizeIcon = SystemIcon.Instance().Restore;
}
else
{
ResizeIcon = SystemIcon.Instance().Maximize;
}
SetLeaveStyle(ResizeIcon);
SetProperty(ref winState, value);
}
}
private VectorImage minimizeIcon;
public VectorImage MinimizeIcon
{
get { return minimizeIcon; }
set { SetProperty(ref minimizeIcon, value); }
}
private VectorImage resizeIcon;
public VectorImage ResizeIcon
{
get { return resizeIcon; }
set { SetProperty(ref resizeIcon, value); }
}
private VectorImage closeIcon;
public VectorImage CloseIcon
{
get { return closeIcon; }
set { SetProperty(ref closeIcon, value); }
}
private VectorImage skinIcon;
public VectorImage SkinIcon
{
get { return skinIcon; }
set { SetProperty(ref skinIcon, value); }
}
private Visibility messageVisibility = Visibility.Hidden;
public Visibility MessageVisibility
{
get { return messageVisibility; }
set { SetProperty(ref messageVisibility, value); }
}
private string message;
public string Message
{
get { return message; }
set { SetProperty(ref message, value); }
}
#endregion
public MainWindowViewModel(IRegionManager regionManager, IEventAggregator eventAggregator)
{
this.eventAggregator = eventAggregator;
#region 属性初始化
Window mainWindow = Application.Current.MainWindow;
WinState = WindowState.Normal;
MinimizeIcon = SystemIcon.Instance().Minimize;
ResizeIcon = SystemIcon.Instance().Maximize;
CloseIcon = SystemIcon.Instance().Close;
SkinIcon = SystemIcon.Instance().Skin;
#endregion
#region 订阅
// 订阅导航事件
eventAggregator.GetEvent<NavigationEvent>().Subscribe((view) =>
{
var param = new NavigationParameters
{
{ "Parent", view.ParentViewName },
{ "Parameter", view.Parameter }
};
regionManager.RequestNavigate("ContentRegion", view.ViewName, param);
});
// 订阅消息发送事件
string oldMessage;
eventAggregator.GetEvent<MessageEvent>().Subscribe((message) =>
{
MessageVisibility = Visibility.Visible;
oldMessage = Message;
Message = message;
int sleep = 2000;
if (oldMessage == Message) { sleep = 1500; }
Thread.Sleep(sleep);
MessageVisibility = Visibility.Hidden;
}, ThreadOption.BackgroundThread);
#endregion
#region 命令定义
// window加载后执行的事件
LoadedCommand = new DelegateCommand(() =>
{
clipboardHooker = new ClipboardHooker(Application.Current.MainWindow);
clipboardHooker.ClipboardUpdated += OnClipboardUpdated;
var param = new NavigationParameters
{
{ "Parent", "" },
{ "Parameter", "start" }
};
regionManager.RequestNavigate("ContentRegion", ViewIndexViewModel.Tag, param);
});
// 顶部caption栏的点击事件包括双击和拖动
int times = 0;
DragMoveCommand = new DelegateCommand(() =>
{
// caption 双击事件
times += 1;
DispatcherTimer timer = new DispatcherTimer
{
Interval = new TimeSpan(0, 0, 0, 0, 300)
};
timer.Tick += (s, e) => { timer.IsEnabled = false; times = 0; };
timer.IsEnabled = true;
if (times % 2 == 0)
{
timer.IsEnabled = false;
times = 0;
WinState = WinState == WindowState.Maximized ? WindowState.Normal : WindowState.Maximized;
}
// caption 拖动事件
try
{
mainWindow.DragMove();
}
catch { }
});
// 最小化窗口事件
MinimizeCommand = new DelegateCommand(() =>
{
mainWindow.WindowState = WindowState.Minimized;
});
MinimizeEnterCommand = new DelegateCommand(() =>
{
SetEnterStyle(MinimizeIcon);
});
MinimizeLeaveCommand = new DelegateCommand(() =>
{
SetLeaveStyle(MinimizeIcon);
});
// 最大化/还原窗口事件
ResizeCommand = new DelegateCommand(() =>
{
WinState = WinState == WindowState.Maximized ? WindowState.Normal : WindowState.Maximized;
});
ResizeEnterCommand = new DelegateCommand(() =>
{
SetEnterStyle(ResizeIcon);
});
ResizeLeaveCommand = new DelegateCommand(() =>
{
SetLeaveStyle(ResizeIcon);
});
// 关闭窗口事件
CloseCommand = new DelegateCommand(() =>
{
if (clipboardHooker != null)
{
clipboardHooker.ClipboardUpdated -= OnClipboardUpdated;
clipboardHooker.Dispose();
}
mainWindow.Close();
});
CloseEnterCommand = new DelegateCommand(() =>
{
SetEnterStyle(CloseIcon);
});
CloseLeaveCommand = new DelegateCommand(() =>
{
SetLeaveStyle(CloseIcon);
});
// 皮肤按钮点击事件
SkinCommand = new DelegateCommand(() =>
{
// 设置主题
DictionaryResource.LoadTheme("ThemeDiy");
// 切换语言
DictionaryResource.LoadLanguage("en_US");
});
SkinEnterCommand = new DelegateCommand(() =>
{
SetEnterStyle(SkinIcon);
});
SkinLeaveCommand = new DelegateCommand(() =>
{
SetLeaveStyle(SkinIcon);
});
#endregion
}
#region 命令申明
public DelegateCommand LoadedCommand { get; private set; }
public DelegateCommand DragMoveCommand { get; private set; }
public DelegateCommand MinimizeCommand { get; private set; }
public DelegateCommand MinimizeEnterCommand { get; private set; }
public DelegateCommand MinimizeLeaveCommand { get; private set; }
public DelegateCommand ResizeCommand { get; private set; }
public DelegateCommand ResizeEnterCommand { get; private set; }
public DelegateCommand ResizeLeaveCommand { get; private set; }
public DelegateCommand CloseCommand { get; private set; }
public DelegateCommand CloseEnterCommand { get; private set; }
public DelegateCommand CloseLeaveCommand { get; private set; }
public DelegateCommand SkinCommand { get; private set; }
public DelegateCommand SkinEnterCommand { get; private set; }
public DelegateCommand SkinLeaveCommand { get; private set; }
#endregion
/// <summary>
/// 鼠标进入系统按钮时的图标样式
/// </summary>
/// <param name="icon">图标</param>
private void SetEnterStyle(VectorImage icon)
{
icon.Fill = DictionaryResource.GetColor("ColorSystemBtnTint");
}
/// <summary>
/// 鼠标离开系统按钮时的图标样式
/// </summary>
/// <param name="icon">图标</param>
private void SetLeaveStyle(VectorImage icon)
{
icon.Fill = DictionaryResource.GetColor("ColorSystemBtnTintDark");
}
private void OnClipboardUpdated(object sender, EventArgs e)
{
AllowStatus isListenClipboard = SettingsManager.GetInstance().IsListenClipboard();
if (isListenClipboard != AllowStatus.YES)
{
return;
}
string input;
try
{
IDataObject data = Clipboard.GetDataObject();
string[] fs = data.GetFormats();
input = data.GetData(fs[0]).ToString();
}
catch (Exception exc)
{
Console.WriteLine("OnClipboardUpdated()发生异常: {0}", exc);
LogManager.Error("OnClipboardUpdated", exc);
return;
}
// 视频
if (ParseEntrance.IsAvId(input))
{
NavigationView(ViewVideoDetailViewModel.Tag, $"{ParseEntrance.VideoUrl}{input.ToLower()}");
}
else if (ParseEntrance.IsAvUrl(input))
{
NavigationView(ViewVideoDetailViewModel.Tag, input);
}
else if (ParseEntrance.IsBvId(input))
{
NavigationView(ViewVideoDetailViewModel.Tag, $"{ParseEntrance.VideoUrl}{input}");
}
else if (ParseEntrance.IsBvUrl(input))
{
NavigationView(ViewVideoDetailViewModel.Tag, input);
}
// 番剧(电影、电视剧)
else if (ParseEntrance.IsBangumiSeasonId(input))
{
NavigationView(ViewVideoDetailViewModel.Tag, $"{ParseEntrance.BangumiUrl}{input.ToLower()}");
}
else if (ParseEntrance.IsBangumiSeasonUrl(input))
{
NavigationView(ViewVideoDetailViewModel.Tag, input);
}
else if (ParseEntrance.IsBangumiEpisodeId(input))
{
NavigationView(ViewVideoDetailViewModel.Tag, $"{ParseEntrance.BangumiUrl}{input.ToLower()}");
}
else if (ParseEntrance.IsBangumiEpisodeUrl(input))
{
NavigationView(ViewVideoDetailViewModel.Tag, input);
}
else if (ParseEntrance.IsBangumiMediaId(input))
{
NavigationView(ViewVideoDetailViewModel.Tag, $"{ParseEntrance.BangumiMediaUrl}{input.ToLower()}");
}
else if (ParseEntrance.IsBangumiMediaUrl(input))
{
NavigationView(ViewVideoDetailViewModel.Tag, input);
}
// 课程
else if (ParseEntrance.IsCheeseSeasonUrl(input) || ParseEntrance.IsCheeseEpisodeUrl(input))
{
NavigationView(ViewVideoDetailViewModel.Tag, input);
}
}
/// <summary>
/// 导航到其他页面
/// </summary>
/// <param name="viewName"></param>
/// <param name="param"></param>
private void NavigationView(string viewName, string param)
{
LogManager.Debug("OnClipboardUpdated", $"NavigationView: {viewName}, Parameter: {param}");
NavigationParam parameter = new NavigationParam
{
ViewName = viewName,
ParentViewName = ViewIndexViewModel.Tag,
Parameter = param
};
eventAggregator.GetEvent<NavigationEvent>().Publish(parameter);
}
}
}

@ -0,0 +1,269 @@
using DownKyi.Core.Settings;
using DownKyi.Events;
using DownKyi.Models;
using DownKyi.Utils;
using Prism.Commands;
using Prism.Events;
using Prism.Regions;
namespace DownKyi.ViewModels.Settings
{
public class ViewAboutViewModel : BaseViewModel
{
public const string Tag = "PageSettingsAbout";
private bool isOnNavigatedTo;
#region 页面属性申明
private string appName;
public string AppName
{
get { return appName; }
set { SetProperty(ref appName, value); }
}
private string appVersion;
public string AppVersion
{
get { return appVersion; }
set { SetProperty(ref appVersion, value); }
}
private bool isReceiveBetaVersion;
public bool IsReceiveBetaVersion
{
get { return isReceiveBetaVersion; }
set { SetProperty(ref isReceiveBetaVersion, value); }
}
private bool autoUpdateWhenLaunch;
public bool AutoUpdateWhenLaunch
{
get { return autoUpdateWhenLaunch; }
set { SetProperty(ref autoUpdateWhenLaunch, value); }
}
#endregion
public ViewAboutViewModel(IEventAggregator eventAggregator) : base(eventAggregator)
{
#region 属性初始化
AppInfo app = new AppInfo();
AppName = app.Name;
AppVersion = app.VersionName;
#endregion
}
/// <summary>
/// 导航到VideoDetail页面时执行
/// </summary>
/// <param name="navigationContext"></param>
public override void OnNavigatedTo(NavigationContext navigationContext)
{
base.OnNavigatedTo(navigationContext);
isOnNavigatedTo = true;
// 是否接收测试版更新
var isReceiveBetaVersion = SettingsManager.GetInstance().IsReceiveBetaVersion();
IsReceiveBetaVersion = isReceiveBetaVersion == AllowStatus.YES;
// 是否在启动时自动检查更新
var isAutoUpdateWhenLaunch = SettingsManager.GetInstance().GetAutoUpdateWhenLaunch();
AutoUpdateWhenLaunch = isAutoUpdateWhenLaunch == AllowStatus.YES;
isOnNavigatedTo = false;
}
#region 命令申明
// 访问主页事件
private DelegateCommand appNameCommand;
public DelegateCommand AppNameCommand => appNameCommand ?? (appNameCommand = new DelegateCommand(ExecuteAppNameCommand));
/// <summary>
/// 访问主页事件
/// </summary>
private void ExecuteAppNameCommand()
{
System.Diagnostics.Process.Start("https://github.com/leiurayer/downkyi");
}
// 检查更新事件
private DelegateCommand checkUpdateCommand;
public DelegateCommand CheckUpdateCommand => checkUpdateCommand ?? (checkUpdateCommand = new DelegateCommand(ExecuteCheckUpdateCommand));
/// <summary>
/// 检查更新事件
/// </summary>
private void ExecuteCheckUpdateCommand()
{
//eventAggregator.GetEvent<MessageEvent>().Publish("开始查找更新,请稍后~");
eventAggregator.GetEvent<MessageEvent>().Publish("请前往主页下载最新版~");
}
// 意见反馈事件
private DelegateCommand feedbackCommand;
public DelegateCommand FeedbackCommand => feedbackCommand ?? (feedbackCommand = new DelegateCommand(ExecuteFeedbackCommand));
/// <summary>
/// 意见反馈事件
/// </summary>
private void ExecuteFeedbackCommand()
{
System.Diagnostics.Process.Start("https://github.com/leiurayer/downkyi/issues");
}
// 是否接收测试版更新事件
private DelegateCommand receiveBetaVersionCommand;
public DelegateCommand ReceiveBetaVersionCommand => receiveBetaVersionCommand ?? (receiveBetaVersionCommand = new DelegateCommand(ExecuteReceiveBetaVersionCommand));
/// <summary>
/// 是否接收测试版更新事件
/// </summary>
private void ExecuteReceiveBetaVersionCommand()
{
AllowStatus isReceiveBetaVersion = IsReceiveBetaVersion ? AllowStatus.YES : AllowStatus.NO;
bool isSucceed = SettingsManager.GetInstance().IsReceiveBetaVersion(isReceiveBetaVersion);
PublishTip(isSucceed);
}
// 是否在启动时自动检查更新事件
private DelegateCommand autoUpdateWhenLaunchCommand;
public DelegateCommand AutoUpdateWhenLaunchCommand => autoUpdateWhenLaunchCommand ?? (autoUpdateWhenLaunchCommand = new DelegateCommand(ExecuteAutoUpdateWhenLaunchCommand));
/// <summary>
/// 是否在启动时自动检查更新事件
/// </summary>
private void ExecuteAutoUpdateWhenLaunchCommand()
{
AllowStatus isAutoUpdateWhenLaunch = AutoUpdateWhenLaunch ? AllowStatus.YES : AllowStatus.NO;
bool isSucceed = SettingsManager.GetInstance().SetAutoUpdateWhenLaunch(isAutoUpdateWhenLaunch);
PublishTip(isSucceed);
}
// Brotli.NET许可证查看事件
private DelegateCommand brotliLicenseCommand;
public DelegateCommand BrotliLicenseCommand => brotliLicenseCommand ?? (brotliLicenseCommand = new DelegateCommand(ExecuteBrotliLicenseCommand));
/// <summary>
/// Brotli.NET许可证查看事件
/// </summary>
private void ExecuteBrotliLicenseCommand()
{
System.Diagnostics.Process.Start("https://licenses.nuget.org/MIT");
}
// Google.Protobuf许可证查看事件
private DelegateCommand protobufLicenseCommand;
public DelegateCommand ProtobufLicenseCommand => protobufLicenseCommand ?? (protobufLicenseCommand = new DelegateCommand(ExecuteProtobufLicenseCommand));
/// <summary>
/// Google.Protobuf许可证查看事件
/// </summary>
private void ExecuteProtobufLicenseCommand()
{
System.Diagnostics.Process.Start("https://github.com/protocolbuffers/protobuf/blob/master/LICENSE");
}
// Newtonsoft.Json许可证查看事件
private DelegateCommand newtonsoftLicenseCommand;
public DelegateCommand NewtonsoftLicenseCommand => newtonsoftLicenseCommand ?? (newtonsoftLicenseCommand = new DelegateCommand(ExecuteNewtonsoftLicenseCommand));
/// <summary>
/// Newtonsoft.Json许可证查看事件
/// </summary>
private void ExecuteNewtonsoftLicenseCommand()
{
System.Diagnostics.Process.Start("https://licenses.nuget.org/MIT");
}
// Prism.DryIoc许可证查看事件
private DelegateCommand prismLicenseCommand;
public DelegateCommand PrismLicenseCommand => prismLicenseCommand ?? (prismLicenseCommand = new DelegateCommand(ExecutePrismLicenseCommand));
/// <summary>
/// Prism.DryIoc许可证查看事件
/// </summary>
private void ExecutePrismLicenseCommand()
{
System.Diagnostics.Process.Start("https://www.nuget.org/packages/Prism.DryIoc/8.1.97/license");
}
// QRCoder许可证查看事件
private DelegateCommand qRCoderLicenseCommand;
public DelegateCommand QRCoderLicenseCommand => qRCoderLicenseCommand ?? (qRCoderLicenseCommand = new DelegateCommand(ExecuteQRCoderLicenseCommand));
/// <summary>
/// QRCoder许可证查看事件
/// </summary>
private void ExecuteQRCoderLicenseCommand()
{
System.Diagnostics.Process.Start("https://licenses.nuget.org/MIT");
}
// System.Data.SQLite.Core许可证查看事件
private DelegateCommand sQLiteLicenseCommand;
public DelegateCommand SQLiteLicenseCommand => sQLiteLicenseCommand ?? (sQLiteLicenseCommand = new DelegateCommand(ExecuteSQLiteLicenseCommand));
/// <summary>
/// System.Data.SQLite.Core许可证查看事件
/// </summary>
private void ExecuteSQLiteLicenseCommand()
{
System.Diagnostics.Process.Start("https://www.sqlite.org/copyright.html");
}
// Aria2c许可证查看事件
private DelegateCommand ariaLicenseCommand;
public DelegateCommand AriaLicenseCommand => ariaLicenseCommand ?? (ariaLicenseCommand = new DelegateCommand(ExecuteAriaLicenseCommand));
/// <summary>
/// Aria2c许可证查看事件
/// </summary>
private void ExecuteAriaLicenseCommand()
{
System.Diagnostics.Process.Start("aria2_COPYING.txt");
}
// FFmpeg许可证查看事件
private DelegateCommand fFmpegLicenseCommand;
public DelegateCommand FFmpegLicenseCommand => fFmpegLicenseCommand ?? (fFmpegLicenseCommand = new DelegateCommand(ExecuteFFmpegLicenseCommand));
/// <summary>
/// FFmpeg许可证查看事件
/// </summary>
private void ExecuteFFmpegLicenseCommand()
{
System.Diagnostics.Process.Start("FFmpeg_LICENSE.txt");
}
#endregion
/// <summary>
/// 发送需要显示的tip
/// </summary>
/// <param name="isSucceed"></param>
private void PublishTip(bool isSucceed)
{
if (isOnNavigatedTo) { return; }
if (isSucceed)
{
eventAggregator.GetEvent<MessageEvent>().Publish(DictionaryResource.GetString("TipSettingUpdated"));
}
else
{
eventAggregator.GetEvent<MessageEvent>().Publish(DictionaryResource.GetString("TipSettingFailed"));
}
}
}
}

@ -0,0 +1,239 @@
using DownKyi.Core.Settings;
using DownKyi.Events;
using DownKyi.Models;
using DownKyi.Utils;
using Prism.Commands;
using Prism.Events;
using Prism.Regions;
using System.Collections.Generic;
using System.Linq;
namespace DownKyi.ViewModels.Settings
{
public class ViewBasicViewModel : BaseViewModel
{
public const string Tag = "PageSettingsBasic";
private bool isOnNavigatedTo;
#region 页面属性申明
private bool none;
public bool None
{
get { return none; }
set { SetProperty(ref none, value); }
}
private bool closeApp;
public bool CloseApp
{
get { return closeApp; }
set { SetProperty(ref closeApp, value); }
}
private bool closeSystem;
public bool CloseSystem
{
get { return closeSystem; }
set { SetProperty(ref closeSystem, value); }
}
private bool listenClipboard;
public bool ListenClipboard
{
get { return listenClipboard; }
set { SetProperty(ref listenClipboard, value); }
}
private bool autoParseVideo;
public bool AutoParseVideo
{
get { return autoParseVideo; }
set { SetProperty(ref autoParseVideo, value); }
}
private List<ParseScopeDisplay> parseScopes;
public List<ParseScopeDisplay> ParseScopes
{
get { return parseScopes; }
set { SetProperty(ref parseScopes, value); }
}
private ParseScopeDisplay selectedParseScope;
public ParseScopeDisplay SelectedParseScope
{
get { return selectedParseScope; }
set { SetProperty(ref selectedParseScope, value); }
}
#endregion
public ViewBasicViewModel(IEventAggregator eventAggregator) : base(eventAggregator)
{
#region 属性初始化
// 解析范围
ParseScopes = new List<ParseScopeDisplay>()
{
new ParseScopeDisplay{ Name =DictionaryResource.GetString("ParseNone"),ParseScope=ParseScope.NONE},
new ParseScopeDisplay{ Name =DictionaryResource.GetString("ParseSelectedItem"),ParseScope=ParseScope.SELECTED_ITEM},
new ParseScopeDisplay{ Name =DictionaryResource.GetString("ParseCurrentSection"),ParseScope=ParseScope.CURRENT_SECTION},
new ParseScopeDisplay{ Name =DictionaryResource.GetString("ParseAll"),ParseScope=ParseScope.ALL}
};
#endregion
}
/// <summary>
/// 导航到VideoDetail页面时执行
/// </summary>
/// <param name="navigationContext"></param>
public override void OnNavigatedTo(NavigationContext navigationContext)
{
base.OnNavigatedTo(navigationContext);
isOnNavigatedTo = true;
// 下载完成后的操作
AfterDownloadOperation afterDownload = SettingsManager.GetInstance().GetAfterDownloadOperation();
SetAfterDownloadOperation(afterDownload);
// 是否监听剪贴板
AllowStatus isListenClipboard = SettingsManager.GetInstance().IsListenClipboard();
ListenClipboard = isListenClipboard == AllowStatus.YES;
// 是否自动解析视频
AllowStatus isAutoParseVideo = SettingsManager.GetInstance().IsAutoParseVideo();
AutoParseVideo = isAutoParseVideo == AllowStatus.YES;
// 解析范围
ParseScope parseScope = SettingsManager.GetInstance().GetParseScope();
SelectedParseScope = ParseScopes.FirstOrDefault(t => { return t.ParseScope == parseScope; });
isOnNavigatedTo = false;
}
#region 命令申明
// 下载完成后的操作事件
private DelegateCommand<string> afterDownloadOperationCommand;
public DelegateCommand<string> AfterDownloadOperationCommand => afterDownloadOperationCommand ?? (afterDownloadOperationCommand = new DelegateCommand<string>(ExecuteAfterDownloadOperationCommand));
/// <summary>
/// 下载完成后的操作事件
/// </summary>
private void ExecuteAfterDownloadOperationCommand(string parameter)
{
AfterDownloadOperation afterDownload;
switch (parameter)
{
case "None":
afterDownload = AfterDownloadOperation.NONE;
break;
case "CloseApp":
afterDownload = AfterDownloadOperation.CLOSE_APP;
break;
case "CloseSystem":
afterDownload = AfterDownloadOperation.CLOSE_SYSTEM;
break;
default:
afterDownload = AfterDownloadOperation.NONE;
break;
}
bool isSucceed = SettingsManager.GetInstance().SetAfterDownloadOperation(afterDownload);
PublishTip(isSucceed);
}
// 是否监听剪贴板事件
private DelegateCommand listenClipboardCommand;
public DelegateCommand ListenClipboardCommand => listenClipboardCommand ?? (listenClipboardCommand = new DelegateCommand(ExecuteListenClipboardCommand));
/// <summary>
/// 是否监听剪贴板事件
/// </summary>
private void ExecuteListenClipboardCommand()
{
AllowStatus isListenClipboard = ListenClipboard ? AllowStatus.YES : AllowStatus.NO;
bool isSucceed = SettingsManager.GetInstance().IsListenClipboard(isListenClipboard);
PublishTip(isSucceed);
}
private DelegateCommand autoParseVideoCommand;
public DelegateCommand AutoParseVideoCommand => autoParseVideoCommand ?? (autoParseVideoCommand = new DelegateCommand(ExecuteAutoParseVideoCommand));
/// <summary>
/// 是否自动解析视频
/// </summary>
private void ExecuteAutoParseVideoCommand()
{
AllowStatus isAutoParseVideo = AutoParseVideo ? AllowStatus.YES : AllowStatus.NO;
bool isSucceed = SettingsManager.GetInstance().IsAutoParseVideo(isAutoParseVideo);
PublishTip(isSucceed);
}
// 解析范围事件
private DelegateCommand<object> parseScopesCommand;
public DelegateCommand<object> ParseScopesCommand => parseScopesCommand ?? (parseScopesCommand = new DelegateCommand<object>(ExecuteParseScopesCommand));
/// <summary>
/// 解析范围事件
/// </summary>
/// <param name="parameter"></param>
private void ExecuteParseScopesCommand(object parameter)
{
if (!(parameter is ParseScopeDisplay parseScope)) { return; }
bool isSucceed = SettingsManager.GetInstance().SetParseScope(parseScope.ParseScope);
PublishTip(isSucceed);
}
#endregion
/// <summary>
/// 设置下载完成后的操作
/// </summary>
/// <param name="afterDownload"></param>
private void SetAfterDownloadOperation(AfterDownloadOperation afterDownload)
{
switch (afterDownload)
{
case AfterDownloadOperation.NONE:
None = true;
break;
case AfterDownloadOperation.OPEN_FOLDER:
break;
case AfterDownloadOperation.CLOSE_APP:
CloseApp = true;
break;
case AfterDownloadOperation.CLOSE_SYSTEM:
CloseSystem = true;
break;
}
}
/// <summary>
/// 发送需要显示的tip
/// </summary>
/// <param name="isSucceed"></param>
private void PublishTip(bool isSucceed)
{
if (isOnNavigatedTo) { return; }
if (isSucceed)
{
eventAggregator.GetEvent<MessageEvent>().Publish(DictionaryResource.GetString("TipSettingUpdated"));
}
else
{
eventAggregator.GetEvent<MessageEvent>().Publish(DictionaryResource.GetString("TipSettingFailed"));
}
}
}
}

@ -0,0 +1,374 @@
using DownKyi.Core.Settings;
using DownKyi.Core.Utils.Validator;
using DownKyi.Events;
using DownKyi.Utils;
using Prism.Commands;
using Prism.Events;
using Prism.Regions;
using System.Collections.Generic;
using System.Drawing.Text;
namespace DownKyi.ViewModels.Settings
{
public class ViewDanmakuViewModel : BaseViewModel
{
public const string Tag = "PageSettingsDanmaku";
private bool isOnNavigatedTo;
#region 页面属性申明
private bool topFilter;
public bool TopFilter
{
get { return topFilter; }
set { SetProperty(ref topFilter, value); }
}
private bool bottomFilter;
public bool BottomFilter
{
get { return bottomFilter; }
set { SetProperty(ref bottomFilter, value); }
}
private bool scrollFilter;
public bool ScrollFilter
{
get { return scrollFilter; }
set { SetProperty(ref scrollFilter, value); }
}
private int screenWidth;
public int ScreenWidth
{
get { return screenWidth; }
set { SetProperty(ref screenWidth, value); }
}
private int screenHeight;
public int ScreenHeight
{
get { return screenHeight; }
set { SetProperty(ref screenHeight, value); }
}
private List<string> fonts;
public List<string> Fonts
{
get { return fonts; }
set { SetProperty(ref fonts, value); }
}
private string selectedFont;
public string SelectedFont
{
get { return selectedFont; }
set { SetProperty(ref selectedFont, value); }
}
private int fontSize;
public int FontSize
{
get { return fontSize; }
set { SetProperty(ref fontSize, value); }
}
private int lineCount;
public int LineCount
{
get { return lineCount; }
set { SetProperty(ref lineCount, value); }
}
private bool sync;
public bool Sync
{
get { return sync; }
set { SetProperty(ref sync, value); }
}
private bool async;
public bool Async
{
get { return async; }
set { SetProperty(ref async, value); }
}
#endregion
public ViewDanmakuViewModel(IEventAggregator eventAggregator) : base(eventAggregator)
{
#region 属性初始化
// 弹幕字体
Fonts = new List<string>();
var fontCollection = new InstalledFontCollection();
foreach (var font in fontCollection.Families)
{
Fonts.Add(font.Name);
}
#endregion
}
/// <summary>
/// 导航到VideoDetail页面时执行
/// </summary>
/// <param name="navigationContext"></param>
public override void OnNavigatedTo(NavigationContext navigationContext)
{
base.OnNavigatedTo(navigationContext);
isOnNavigatedTo = true;
// 屏蔽顶部弹幕
AllowStatus danmakuTopFilter = SettingsManager.GetInstance().GetDanmakuTopFilter();
TopFilter = danmakuTopFilter == AllowStatus.YES;
// 屏蔽底部弹幕
AllowStatus danmakuBottomFilter = SettingsManager.GetInstance().GetDanmakuBottomFilter();
BottomFilter = danmakuBottomFilter == AllowStatus.YES;
// 屏蔽滚动弹幕
AllowStatus danmakuScrollFilter = SettingsManager.GetInstance().GetDanmakuScrollFilter();
ScrollFilter = danmakuScrollFilter == AllowStatus.YES;
// 分辨率-宽
ScreenWidth = SettingsManager.GetInstance().GetDanmakuScreenWidth();
// 分辨率-高
ScreenHeight = SettingsManager.GetInstance().GetDanmakuScreenHeight();
// 弹幕字体
string danmakuFont = SettingsManager.GetInstance().GetDanmakuFontName();
if (Fonts.Contains(danmakuFont))
{
// 只有系统中存在当前设置的字体,才能显示
SelectedFont = danmakuFont;
}
// 弹幕字体大小
FontSize = SettingsManager.GetInstance().GetDanmakuFontSize();
// 弹幕限制行数
LineCount = SettingsManager.GetInstance().GetDanmakuLineCount();
// 弹幕布局算法
DanmakuLayoutAlgorithm layoutAlgorithm = SettingsManager.GetInstance().GetDanmakuLayoutAlgorithm();
SetLayoutAlgorithm(layoutAlgorithm);
isOnNavigatedTo = false;
}
#region 命令申明
// 屏蔽顶部弹幕事件
private DelegateCommand topFilterCommand;
public DelegateCommand TopFilterCommand => topFilterCommand ?? (topFilterCommand = new DelegateCommand(ExecuteTopFilterCommand));
/// <summary>
/// 屏蔽顶部弹幕事件
/// </summary>
private void ExecuteTopFilterCommand()
{
AllowStatus isTopFilter = TopFilter ? AllowStatus.YES : AllowStatus.NO;
bool isSucceed = SettingsManager.GetInstance().SetDanmakuTopFilter(isTopFilter);
PublishTip(isSucceed);
}
// 屏蔽底部弹幕事件
private DelegateCommand bottomFilterCommand;
public DelegateCommand BottomFilterCommand => bottomFilterCommand ?? (bottomFilterCommand = new DelegateCommand(ExecuteBottomFilterCommand));
/// <summary>
/// 屏蔽底部弹幕事件
/// </summary>
private void ExecuteBottomFilterCommand()
{
AllowStatus isBottomFilter = BottomFilter ? AllowStatus.YES : AllowStatus.NO;
bool isSucceed = SettingsManager.GetInstance().SetDanmakuBottomFilter(isBottomFilter);
PublishTip(isSucceed);
}
// 屏蔽滚动弹幕事件
private DelegateCommand scrollFilterCommand;
public DelegateCommand ScrollFilterCommand => scrollFilterCommand ?? (scrollFilterCommand = new DelegateCommand(ExecuteScrollFilterCommand));
/// <summary>
/// 屏蔽滚动弹幕事件
/// </summary>
private void ExecuteScrollFilterCommand()
{
AllowStatus isScrollFilter = ScrollFilter ? AllowStatus.YES : AllowStatus.NO;
bool isSucceed = SettingsManager.GetInstance().SetDanmakuScrollFilter(isScrollFilter);
PublishTip(isSucceed);
}
// 设置分辨率-宽事件
private DelegateCommand<string> screenWidthCommand;
public DelegateCommand<string> ScreenWidthCommand => screenWidthCommand ?? (screenWidthCommand = new DelegateCommand<string>(ExecuteScreenWidthCommand));
/// <summary>
/// 设置分辨率-宽事件
/// </summary>
/// <param name="parameter"></param>
private void ExecuteScreenWidthCommand(string parameter)
{
int width = (int)Number.GetInt(parameter);
ScreenWidth = width;
bool isSucceed = SettingsManager.GetInstance().SetDanmakuScreenWidth(ScreenWidth);
PublishTip(isSucceed);
}
// 设置分辨率-高事件
private DelegateCommand<string> screenHeightCommand;
public DelegateCommand<string> ScreenHeightCommand => screenHeightCommand ?? (screenHeightCommand = new DelegateCommand<string>(ExecuteScreenHeightCommand));
/// <summary>
/// 设置分辨率-高事件
/// </summary>
/// <param name="parameter"></param>
private void ExecuteScreenHeightCommand(string parameter)
{
int height = (int)Number.GetInt(parameter);
ScreenHeight = height;
bool isSucceed = SettingsManager.GetInstance().SetDanmakuScreenHeight(ScreenHeight);
PublishTip(isSucceed);
}
// 弹幕字体选择事件
private DelegateCommand<string> fontSelectCommand;
public DelegateCommand<string> FontSelectCommand => fontSelectCommand ?? (fontSelectCommand = new DelegateCommand<string>(ExecuteFontSelectCommand));
/// <summary>
/// 弹幕字体选择事件
/// </summary>
/// <param name="parameter"></param>
private void ExecuteFontSelectCommand(string parameter)
{
bool isSucceed = SettingsManager.GetInstance().SetDanmakuFontName(parameter);
PublishTip(isSucceed);
}
// 弹幕字体大小事件
private DelegateCommand<string> fontSizeCommand;
public DelegateCommand<string> FontSizeCommand => fontSizeCommand ?? (fontSizeCommand = new DelegateCommand<string>(ExecuteFontSizeCommand));
/// <summary>
/// 弹幕字体大小事件
/// </summary>
/// <param name="parameter"></param>
private void ExecuteFontSizeCommand(string parameter)
{
int fontSize = (int)Number.GetInt(parameter);
FontSize = fontSize;
bool isSucceed = SettingsManager.GetInstance().SetDanmakuFontSize(FontSize);
PublishTip(isSucceed);
}
// 弹幕限制行数事件
private DelegateCommand<string> lineCountCommand;
public DelegateCommand<string> LineCountCommand => lineCountCommand ?? (lineCountCommand = new DelegateCommand<string>(ExecuteLineCountCommand));
/// <summary>
/// 弹幕限制行数事件
/// </summary>
/// <param name="parameter"></param>
private void ExecuteLineCountCommand(string parameter)
{
int lineCount = (int)Number.GetInt(parameter);
LineCount = lineCount;
bool isSucceed = SettingsManager.GetInstance().SetDanmakuLineCount(LineCount);
PublishTip(isSucceed);
}
// 弹幕布局算法事件
private DelegateCommand<string> layoutAlgorithmCommand;
public DelegateCommand<string> LayoutAlgorithmCommand => layoutAlgorithmCommand ?? (layoutAlgorithmCommand = new DelegateCommand<string>(ExecuteLayoutAlgorithmCommand));
/// <summary>
/// 弹幕布局算法事件
/// </summary>
/// <param name="parameter"></param>
private void ExecuteLayoutAlgorithmCommand(string parameter)
{
DanmakuLayoutAlgorithm layoutAlgorithm;
switch (parameter)
{
case "Sync":
layoutAlgorithm = DanmakuLayoutAlgorithm.SYNC;
break;
case "Async":
layoutAlgorithm = DanmakuLayoutAlgorithm.ASYNC;
break;
default:
layoutAlgorithm = DanmakuLayoutAlgorithm.SYNC;
break;
}
bool isSucceed = SettingsManager.GetInstance().SetDanmakuLayoutAlgorithm(layoutAlgorithm);
PublishTip(isSucceed);
if (isSucceed)
{
SetLayoutAlgorithm(layoutAlgorithm);
}
}
#endregion
/// <summary>
/// 设置弹幕同步算法
/// </summary>
/// <param name="layoutAlgorithm"></param>
private void SetLayoutAlgorithm(DanmakuLayoutAlgorithm layoutAlgorithm)
{
switch (layoutAlgorithm)
{
case DanmakuLayoutAlgorithm.SYNC:
Sync = true;
Async = false;
break;
case DanmakuLayoutAlgorithm.ASYNC:
Sync = false;
Async = true;
break;
case DanmakuLayoutAlgorithm.NONE:
Sync = false;
Async = false;
break;
default:
break;
}
}
/// <summary>
/// 发送需要显示的tip
/// </summary>
/// <param name="isSucceed"></param>
private void PublishTip(bool isSucceed)
{
if (isOnNavigatedTo) { return; }
if (isSucceed)
{
eventAggregator.GetEvent<MessageEvent>().Publish(DictionaryResource.GetString("TipSettingUpdated"));
}
else
{
eventAggregator.GetEvent<MessageEvent>().Publish(DictionaryResource.GetString("TipSettingFailed"));
}
}
}
}

@ -0,0 +1,422 @@
using DownKyi.Core.Aria2cNet.Server;
using DownKyi.Core.Settings;
using DownKyi.Core.Utils.Validator;
using DownKyi.Events;
using DownKyi.Utils;
using Prism.Commands;
using Prism.Events;
using Prism.Regions;
using System.Collections.Generic;
namespace DownKyi.ViewModels.Settings
{
public class ViewNetworkViewModel : BaseViewModel
{
public const string Tag = "PageSettingsNetwork";
private bool isOnNavigatedTo;
#region 页面属性申明
private int ariaListenPort;
public int AriaListenPort
{
get { return ariaListenPort; }
set { SetProperty(ref ariaListenPort, value); }
}
private List<string> ariaLogLevels;
public List<string> AriaLogLevels
{
get { return ariaLogLevels; }
set { SetProperty(ref ariaLogLevels, value); }
}
private string selectedAriaLogLevel;
public string SelectedAriaLogLevel
{
get { return selectedAriaLogLevel; }
set { SetProperty(ref selectedAriaLogLevel, value); }
}
private List<int> ariaMaxConcurrentDownloads;
public List<int> AriaMaxConcurrentDownloads
{
get { return ariaMaxConcurrentDownloads; }
set { SetProperty(ref ariaMaxConcurrentDownloads, value); }
}
private int selectedAriaMaxConcurrentDownload;
public int SelectedAriaMaxConcurrentDownload
{
get { return selectedAriaMaxConcurrentDownload; }
set { SetProperty(ref selectedAriaMaxConcurrentDownload, value); }
}
private List<int> ariaSplits;
public List<int> AriaSplits
{
get { return ariaSplits; }
set { SetProperty(ref ariaSplits, value); }
}
private int selectedAriaSplit;
public int SelectedAriaSplit
{
get { return selectedAriaSplit; }
set { SetProperty(ref selectedAriaSplit, value); }
}
private int ariaMaxOverallDownloadLimit;
public int AriaMaxOverallDownloadLimit
{
get { return ariaMaxOverallDownloadLimit; }
set { SetProperty(ref ariaMaxOverallDownloadLimit, value); }
}
private int ariaMaxDownloadLimit;
public int AriaMaxDownloadLimit
{
get { return ariaMaxDownloadLimit; }
set { SetProperty(ref ariaMaxDownloadLimit, value); }
}
private bool isAriaHttpProxy;
public bool IsAriaHttpProxy
{
get { return isAriaHttpProxy; }
set { SetProperty(ref isAriaHttpProxy, value); }
}
private string ariaHttpProxy;
public string AriaHttpProxy
{
get { return ariaHttpProxy; }
set { SetProperty(ref ariaHttpProxy, value); }
}
private int ariaHttpProxyPort;
public int AriaHttpProxyPort
{
get { return ariaHttpProxyPort; }
set { SetProperty(ref ariaHttpProxyPort, value); }
}
private List<string> ariaFileAllocations;
public List<string> AriaFileAllocations
{
get { return ariaFileAllocations; }
set { SetProperty(ref ariaFileAllocations, value); }
}
private string selectedAriaFileAllocation;
public string SelectedAriaFileAllocation
{
get { return selectedAriaFileAllocation; }
set { SetProperty(ref selectedAriaFileAllocation, value); }
}
#endregion
public ViewNetworkViewModel(IEventAggregator eventAggregator) : base(eventAggregator)
{
#region 属性初始化
// Aria的日志等级
AriaLogLevels = new List<string>
{
"DEBUG",
"INFO",
"NOTICE",
"WARN",
"ERROR"
};
// Aria同时下载数
AriaMaxConcurrentDownloads = new List<int>();
for (int i = 1; i <= 10; i++) { AriaMaxConcurrentDownloads.Add(i); }
// Aria最大线程数
AriaSplits = new List<int>();
for (int i = 1; i <= 10; i++) { AriaSplits.Add(i); }
// Aria文件预分配
AriaFileAllocations = new List<string>
{
"NONE",
"PREALLOC",
"FALLOC"
};
#endregion
}
/// <summary>
/// 导航到VideoDetail页面时执行
/// </summary>
/// <param name="navigationContext"></param>
public override void OnNavigatedTo(NavigationContext navigationContext)
{
base.OnNavigatedTo(navigationContext);
isOnNavigatedTo = true;
// Aria服务器端口
AriaListenPort = SettingsManager.GetInstance().GetAriaListenPort();
// Aria的日志等级
AriaConfigLogLevel ariaLogLevel = SettingsManager.GetInstance().GetAriaLogLevel();
SelectedAriaLogLevel = ariaLogLevel.ToString("G");
// Aria同时下载数
SelectedAriaMaxConcurrentDownload = SettingsManager.GetInstance().GetAriaMaxConcurrentDownloads();
// Aria最大线程数
SelectedAriaSplit = SettingsManager.GetInstance().GetAriaSplit();
// Aria下载速度限制
AriaMaxOverallDownloadLimit = SettingsManager.GetInstance().GetAriaMaxOverallDownloadLimit();
// Aria下载单文件速度限制
AriaMaxDownloadLimit = SettingsManager.GetInstance().GetAriaMaxDownloadLimit();
// 是否开启Aria http代理
AllowStatus isAriaHttpProxy = SettingsManager.GetInstance().IsAriaHttpProxy();
IsAriaHttpProxy = isAriaHttpProxy == AllowStatus.YES;
// Aria的http代理的地址
AriaHttpProxy = SettingsManager.GetInstance().GetAriaHttpProxy();
// Aria的http代理的端口
AriaHttpProxyPort = SettingsManager.GetInstance().GetAriaHttpProxyListenPort();
// Aria文件预分配
AriaConfigFileAllocation ariaFileAllocation = SettingsManager.GetInstance().GetAriaFileAllocation();
SelectedAriaFileAllocation = ariaFileAllocation.ToString("G");
isOnNavigatedTo = false;
}
#region 命令申明
// Aria服务器端口事件
private DelegateCommand<string> ariaListenPortCommand;
public DelegateCommand<string> AriaListenPortCommand => ariaListenPortCommand ?? (ariaListenPortCommand = new DelegateCommand<string>(ExecuteAriaListenPortCommand));
/// <summary>
/// Aria服务器端口事件
/// </summary>
/// <param name="parameter"></param>
private void ExecuteAriaListenPortCommand(string parameter)
{
int listenPort = (int)Number.GetInt(parameter);
AriaListenPort = listenPort;
bool isSucceed = SettingsManager.GetInstance().SetAriaListenPort(AriaListenPort);
PublishTip(isSucceed);
}
// Aria的日志等级事件
private DelegateCommand<string> ariaLogLevelsCommand;
public DelegateCommand<string> AriaLogLevelsCommand => ariaLogLevelsCommand ?? (ariaLogLevelsCommand = new DelegateCommand<string>(ExecuteAriaLogLevelsCommand));
/// <summary>
/// Aria的日志等级事件
/// </summary>
/// <param name="parameter"></param>
private void ExecuteAriaLogLevelsCommand(string parameter)
{
AriaConfigLogLevel ariaLogLevel;
switch (parameter)
{
case "DEBUG":
ariaLogLevel = AriaConfigLogLevel.DEBUG;
break;
case "INFO":
ariaLogLevel = AriaConfigLogLevel.INFO;
break;
case "NOTICE":
ariaLogLevel = AriaConfigLogLevel.NOTICE;
break;
case "WARN":
ariaLogLevel = AriaConfigLogLevel.WARN;
break;
case "ERROR":
ariaLogLevel = AriaConfigLogLevel.ERROR;
break;
default:
ariaLogLevel = AriaConfigLogLevel.INFO;
break;
}
bool isSucceed = SettingsManager.GetInstance().SetAriaLogLevel(ariaLogLevel);
PublishTip(isSucceed);
}
// Aria同时下载数事件
private DelegateCommand<object> ariaMaxConcurrentDownloadsCommand;
public DelegateCommand<object> AriaMaxConcurrentDownloadsCommand => ariaMaxConcurrentDownloadsCommand ?? (ariaMaxConcurrentDownloadsCommand = new DelegateCommand<object>(ExecuteAriaMaxConcurrentDownloadsCommand));
/// <summary>
/// Aria同时下载数事件
/// </summary>
/// <param name="parameter"></param>
private void ExecuteAriaMaxConcurrentDownloadsCommand(object parameter)
{
SelectedAriaMaxConcurrentDownload = (int)parameter;
bool isSucceed = SettingsManager.GetInstance().SetAriaMaxConcurrentDownloads(SelectedAriaMaxConcurrentDownload);
PublishTip(isSucceed);
}
// Aria最大线程数事件
private DelegateCommand<object> ariaSplitsCommand;
public DelegateCommand<object> AriaSplitsCommand => ariaSplitsCommand ?? (ariaSplitsCommand = new DelegateCommand<object>(ExecuteAriaSplitsCommand));
/// <summary>
/// Aria最大线程数事件
/// </summary>
/// <param name="parameter"></param>
private void ExecuteAriaSplitsCommand(object parameter)
{
SelectedAriaSplit = (int)parameter;
bool isSucceed = SettingsManager.GetInstance().SetAriaSplit(SelectedAriaSplit);
PublishTip(isSucceed);
}
// Aria下载速度限制事件
private DelegateCommand<string> ariaMaxOverallDownloadLimitCommand;
public DelegateCommand<string> AriaMaxOverallDownloadLimitCommand => ariaMaxOverallDownloadLimitCommand ?? (ariaMaxOverallDownloadLimitCommand = new DelegateCommand<string>(ExecuteAriaMaxOverallDownloadLimitCommand));
/// <summary>
/// Aria下载速度限制事件
/// </summary>
/// <param name="parameter"></param>
private void ExecuteAriaMaxOverallDownloadLimitCommand(string parameter)
{
int downloadLimit = (int)Number.GetInt(parameter);
AriaMaxOverallDownloadLimit = downloadLimit;
bool isSucceed = SettingsManager.GetInstance().SetAriaMaxOverallDownloadLimit(AriaMaxOverallDownloadLimit);
PublishTip(isSucceed);
}
// Aria下载单文件速度限制事件
private DelegateCommand<string> ariaMaxDownloadLimitCommand;
public DelegateCommand<string> AriaMaxDownloadLimitCommand => ariaMaxDownloadLimitCommand ?? (ariaMaxDownloadLimitCommand = new DelegateCommand<string>(ExecuteAriaMaxDownloadLimitCommand));
/// <summary>
/// Aria下载单文件速度限制事件
/// </summary>
/// <param name="parameter"></param>
private void ExecuteAriaMaxDownloadLimitCommand(string parameter)
{
int downloadLimit = (int)Number.GetInt(parameter);
AriaMaxDownloadLimit = downloadLimit;
bool isSucceed = SettingsManager.GetInstance().SetAriaMaxDownloadLimit(AriaMaxDownloadLimit);
PublishTip(isSucceed);
}
// 是否开启Aria http代理事件
private DelegateCommand isAriaHttpProxyCommand;
public DelegateCommand IsAriaHttpProxyCommand => isAriaHttpProxyCommand ?? (isAriaHttpProxyCommand = new DelegateCommand(ExecuteIsAriaHttpProxyCommand));
/// <summary>
/// 是否开启Aria http代理事件
/// </summary>
private void ExecuteIsAriaHttpProxyCommand()
{
AllowStatus isAriaHttpProxy = IsAriaHttpProxy ? AllowStatus.YES : AllowStatus.NO;
bool isSucceed = SettingsManager.GetInstance().IsAriaHttpProxy(isAriaHttpProxy);
PublishTip(isSucceed);
}
// Aria的http代理的地址事件
private DelegateCommand<string> ariaHttpProxyCommand;
public DelegateCommand<string> AriaHttpProxyCommand => ariaHttpProxyCommand ?? (ariaHttpProxyCommand = new DelegateCommand<string>(ExecuteAriaHttpProxyCommand));
/// <summary>
/// Aria的http代理的地址事件
/// </summary>
/// <param name="parameter"></param>
private void ExecuteAriaHttpProxyCommand(string parameter)
{
bool isSucceed = SettingsManager.GetInstance().SetAriaHttpProxy(parameter);
PublishTip(isSucceed);
}
// Aria的http代理的端口事件
private DelegateCommand<string> ariaHttpProxyPortCommand;
public DelegateCommand<string> AriaHttpProxyPortCommand => ariaHttpProxyPortCommand ?? (ariaHttpProxyPortCommand = new DelegateCommand<string>(ExecuteAriaHttpProxyPortCommand));
/// <summary>
/// Aria的http代理的端口事件
/// </summary>
/// <param name="parameter"></param>
private void ExecuteAriaHttpProxyPortCommand(string parameter)
{
int httpProxyPort = (int)Number.GetInt(parameter);
AriaHttpProxyPort = httpProxyPort;
bool isSucceed = SettingsManager.GetInstance().SetAriaHttpProxyListenPort(AriaHttpProxyPort);
PublishTip(isSucceed);
}
// Aria文件预分配事件
private DelegateCommand<string> ariaFileAllocationsCommand;
public DelegateCommand<string> AriaFileAllocationsCommand => ariaFileAllocationsCommand ?? (ariaFileAllocationsCommand = new DelegateCommand<string>(ExecuteAriaFileAllocationsCommand));
/// <summary>
/// Aria文件预分配事件
/// </summary>
/// <param name="parameter"></param>
private void ExecuteAriaFileAllocationsCommand(string parameter)
{
AriaConfigFileAllocation ariaFileAllocation;
switch (parameter)
{
case "NONE":
ariaFileAllocation = AriaConfigFileAllocation.NONE;
break;
case "PREALLOC":
ariaFileAllocation = AriaConfigFileAllocation.PREALLOC;
break;
case "FALLOC":
ariaFileAllocation = AriaConfigFileAllocation.FALLOC;
break;
default:
ariaFileAllocation = AriaConfigFileAllocation.PREALLOC;
break;
}
bool isSucceed = SettingsManager.GetInstance().SetAriaFileAllocation(ariaFileAllocation);
PublishTip(isSucceed);
}
#endregion
/// <summary>
/// 发送需要显示的tip
/// </summary>
/// <param name="isSucceed"></param>
private void PublishTip(bool isSucceed)
{
if (isOnNavigatedTo) { return; }
if (isSucceed)
{
eventAggregator.GetEvent<MessageEvent>().Publish(DictionaryResource.GetString("TipSettingUpdated"));
}
else
{
eventAggregator.GetEvent<MessageEvent>().Publish(DictionaryResource.GetString("TipSettingFailed"));
}
}
}
}

@ -0,0 +1,383 @@
using DownKyi.Core.Settings;
using DownKyi.Events;
using DownKyi.Models;
using DownKyi.Services;
using DownKyi.Utils;
using Prism.Commands;
using Prism.Events;
using Prism.Regions;
using System.Collections.Generic;
using System.Linq;
namespace DownKyi.ViewModels.Settings
{
public class ViewVideoViewModel : BaseViewModel
{
public const string Tag = "PageSettingsVideo";
private bool isOnNavigatedTo;
#region 页面属性申明
private List<string> videoCodecs;
public List<string> VideoCodecs
{
get { return videoCodecs; }
set { SetProperty(ref videoCodecs, value); }
}
private string selectedVideoCodec;
public string SelectedVideoCodec
{
get { return selectedVideoCodec; }
set { SetProperty(ref selectedVideoCodec, value); }
}
private List<Resolution> videoQualityList;
public List<Resolution> VideoQualityList
{
get { return videoQualityList; }
set { SetProperty(ref videoQualityList, value); }
}
private Resolution selectedVideoQuality;
public Resolution SelectedVideoQuality
{
get { return selectedVideoQuality; }
set { SetProperty(ref selectedVideoQuality, value); }
}
private bool isAddVideoOrder;
public bool IsAddVideoOrder
{
get { return isAddVideoOrder; }
set { SetProperty(ref isAddVideoOrder, value); }
}
private bool isTranscodingFlvToMp4;
public bool IsTranscodingFlvToMp4
{
get { return isTranscodingFlvToMp4; }
set { SetProperty(ref isTranscodingFlvToMp4, value); }
}
private bool isUseDefaultDirectory;
public bool IsUseDefaultDirectory
{
get { return isUseDefaultDirectory; }
set { SetProperty(ref isUseDefaultDirectory, value); }
}
private string saveVideoDirectory;
public string SaveVideoDirectory
{
get { return saveVideoDirectory; }
set { SetProperty(ref saveVideoDirectory, value); }
}
private bool isCreateFolderForMedia;
public bool IsCreateFolderForMedia
{
get { return isCreateFolderForMedia; }
set { SetProperty(ref isCreateFolderForMedia, value); }
}
private bool isDownloadDanmaku;
public bool IsDownloadDanmaku
{
get { return isDownloadDanmaku; }
set { SetProperty(ref isDownloadDanmaku, value); }
}
private bool isDownloadCover;
public bool IsDownloadCover
{
get { return isDownloadCover; }
set { SetProperty(ref isDownloadCover, value); }
}
#endregion
public ViewVideoViewModel(IEventAggregator eventAggregator) : base(eventAggregator)
{
#region 属性初始化
// 优先下载的视频编码
VideoCodecs = new List<string>
{
"H.264/AVC",
"H.265/HEVC"
};
// 优先下载画质
VideoQualityList = new ResolutionService().GetResolution();
#endregion
}
/// <summary>
/// 导航到VideoDetail页面时执行
/// </summary>
/// <param name="navigationContext"></param>
public override void OnNavigatedTo(NavigationContext navigationContext)
{
base.OnNavigatedTo(navigationContext);
isOnNavigatedTo = true;
// 优先下载的视频编码
VideoCodecs videoCodecs = SettingsManager.GetInstance().GetVideoCodecs();
SelectedVideoCodec = GetVideoCodecsString(videoCodecs);
// 优先下载画质
int quality = SettingsManager.GetInstance().GetQuality();
SelectedVideoQuality = VideoQualityList.FirstOrDefault(t => { return t.Id == quality; });
// 是否在下载的视频前增加序号
AllowStatus isAddOrder = SettingsManager.GetInstance().IsAddOrder();
IsAddVideoOrder = isAddOrder == AllowStatus.YES;
// 是否下载flv视频后转码为mp4
AllowStatus isTranscodingFlvToMp4 = SettingsManager.GetInstance().IsTranscodingFlvToMp4();
IsTranscodingFlvToMp4 = isTranscodingFlvToMp4 == AllowStatus.YES;
// 是否使用默认下载目录
AllowStatus isUseSaveVideoRootPath = SettingsManager.GetInstance().IsUseSaveVideoRootPath();
IsUseDefaultDirectory = isUseSaveVideoRootPath == AllowStatus.YES;
// 默认下载目录
SaveVideoDirectory = SettingsManager.GetInstance().GetSaveVideoRootPath();
// 是否为不同视频分别创建文件夹
AllowStatus isCreateFolderForMedia = SettingsManager.GetInstance().IsCreateFolderForMedia();
IsCreateFolderForMedia = isCreateFolderForMedia == AllowStatus.YES;
// 是否在下载视频的同时下载弹幕
AllowStatus isDownloadDanmaku = SettingsManager.GetInstance().IsDownloadDanmaku();
IsDownloadDanmaku = isDownloadDanmaku == AllowStatus.YES;
// 是否在下载视频的同时下载封面
AllowStatus isDownloadCover = SettingsManager.GetInstance().IsDownloadCover();
IsDownloadCover = isDownloadCover == AllowStatus.YES;
isOnNavigatedTo = false;
}
#region 命令申明
// 优先下载的视频编码事件
private DelegateCommand<string> videoCodecsCommand;
public DelegateCommand<string> VideoCodecsCommand => videoCodecsCommand ?? (videoCodecsCommand = new DelegateCommand<string>(ExecuteVideoCodecsCommand));
/// <summary>
/// 优先下载的视频编码事件
/// </summary>
/// <param name="parameter"></param>
private void ExecuteVideoCodecsCommand(string parameter)
{
VideoCodecs videoCodecs = GetVideoCodecs(parameter);
bool isSucceed = SettingsManager.GetInstance().SetVideoCodecs(videoCodecs);
PublishTip(isSucceed);
}
// 优先下载画质事件
private DelegateCommand<object> videoQualityCommand;
public DelegateCommand<object> VideoQualityCommand => videoQualityCommand ?? (videoQualityCommand = new DelegateCommand<object>(ExecuteVideoQualityCommand));
/// <summary>
/// 优先下载画质事件
/// </summary>
/// <param name="parameter"></param>
private void ExecuteVideoQualityCommand(object parameter)
{
if (!(parameter is Resolution resolution)) { return; }
bool isSucceed = SettingsManager.GetInstance().SetQuality(resolution.Id);
PublishTip(isSucceed);
}
// 是否在下载的视频前增加序号事件
private DelegateCommand IisAddVideoOrderCommand;
public DelegateCommand IsAddVideoOrderCommand => IisAddVideoOrderCommand ?? (IisAddVideoOrderCommand = new DelegateCommand(ExecuteIsAddVideoOrderCommand));
/// <summary>
/// 是否在下载的视频前增加序号事件
/// </summary>
private void ExecuteIsAddVideoOrderCommand()
{
AllowStatus isAddOrder = IsAddVideoOrder ? AllowStatus.YES : AllowStatus.NO;
bool isSucceed = SettingsManager.GetInstance().IsAddOrder(isAddOrder);
PublishTip(isSucceed);
}
// 是否下载flv视频后转码为mp4事件
private DelegateCommand isTranscodingFlvToMp4Command;
public DelegateCommand IsTranscodingFlvToMp4Command => isTranscodingFlvToMp4Command ?? (isTranscodingFlvToMp4Command = new DelegateCommand(ExecuteIsTranscodingFlvToMp4Command));
/// <summary>
/// 是否下载flv视频后转码为mp4事件
/// </summary>
private void ExecuteIsTranscodingFlvToMp4Command()
{
AllowStatus isTranscodingFlvToMp4 = IsTranscodingFlvToMp4 ? AllowStatus.YES : AllowStatus.NO;
bool isSucceed = SettingsManager.GetInstance().IsTranscodingFlvToMp4(isTranscodingFlvToMp4);
PublishTip(isSucceed);
}
// 是否使用默认下载目录事件
private DelegateCommand isUseDefaultDirectoryCommand;
public DelegateCommand IsUseDefaultDirectoryCommand => isUseDefaultDirectoryCommand ?? (isUseDefaultDirectoryCommand = new DelegateCommand(ExecuteIsUseDefaultDirectoryCommand));
/// <summary>
/// 是否使用默认下载目录事件
/// </summary>
private void ExecuteIsUseDefaultDirectoryCommand()
{
AllowStatus isUseDefaultDirectory = IsUseDefaultDirectory ? AllowStatus.YES : AllowStatus.NO;
bool isSucceed = SettingsManager.GetInstance().IsUseSaveVideoRootPath(isUseDefaultDirectory);
PublishTip(isSucceed);
}
// 修改默认下载目录事件
private DelegateCommand changeSaveVideoDirectoryCommand;
public DelegateCommand ChangeSaveVideoDirectoryCommand => changeSaveVideoDirectoryCommand ?? (changeSaveVideoDirectoryCommand = new DelegateCommand(ExecuteChangeSaveVideoDirectoryCommand));
/// <summary>
/// 修改默认下载目录事件
/// </summary>
private void ExecuteChangeSaveVideoDirectoryCommand()
{
string directory = DialogUtils.SetDownloadDirectory();
if (directory == "") { return; }
bool isSucceed = SettingsManager.GetInstance().SetSaveVideoRootPath(directory);
PublishTip(isSucceed);
if (isSucceed)
{
SaveVideoDirectory = directory;
}
}
// 是否为不同视频分别创建文件夹事件
private DelegateCommand isCreateFolderForMediaCommand;
public DelegateCommand IsCreateFolderForMediaCommand => isCreateFolderForMediaCommand ?? (isCreateFolderForMediaCommand = new DelegateCommand(ExecuteIsCreateFolderForMediaCommand));
/// <summary>
/// 是否为不同视频分别创建文件夹事件
/// </summary>
private void ExecuteIsCreateFolderForMediaCommand()
{
AllowStatus isCreateFolderForMedia = IsCreateFolderForMedia ? AllowStatus.YES : AllowStatus.NO;
bool isSucceed = SettingsManager.GetInstance().IsCreateFolderForMedia(isCreateFolderForMedia);
PublishTip(isSucceed);
}
// 是否在下载视频的同时下载弹幕事件
private DelegateCommand isDownloadDanmakuCommand;
public DelegateCommand IsDownloadDanmakuCommand => isDownloadDanmakuCommand ?? (isDownloadDanmakuCommand = new DelegateCommand(ExecuteIsDownloadDanmakuCommand));
/// <summary>
/// 是否在下载视频的同时下载弹幕事件
/// </summary>
private void ExecuteIsDownloadDanmakuCommand()
{
AllowStatus isDownloadDanmaku = IsDownloadDanmaku ? AllowStatus.YES : AllowStatus.NO;
bool isSucceed = SettingsManager.GetInstance().IsDownloadDanmaku(isDownloadDanmaku);
PublishTip(isSucceed);
}
// 是否在下载视频的同时下载封面事件
private DelegateCommand isDownloadCoverCommand;
public DelegateCommand IsDownloadCoverCommand => isDownloadCoverCommand ?? (isDownloadCoverCommand = new DelegateCommand(ExecuteIsDownloadCoverCommand));
/// <summary>
/// 是否在下载视频的同时下载封面事件
/// </summary>
private void ExecuteIsDownloadCoverCommand()
{
AllowStatus isDownloadCover = IsDownloadCover ? AllowStatus.YES : AllowStatus.NO;
bool isSucceed = SettingsManager.GetInstance().IsDownloadCover(isDownloadCover);
PublishTip(isSucceed);
}
#endregion
/// <summary>
/// 返回VideoCodecs的字符串
/// </summary>
/// <param name="videoCodecs"></param>
/// <returns></returns>
private string GetVideoCodecsString(VideoCodecs videoCodecs)
{
string codec;
switch (videoCodecs)
{
case Core.Settings.VideoCodecs.NONE:
codec = "";
break;
case Core.Settings.VideoCodecs.AVC:
codec = "H.264/AVC";
break;
case Core.Settings.VideoCodecs.HEVC:
codec = "H.265/HEVC";
break;
default:
codec = "";
break;
}
return codec;
}
/// <summary>
/// 返回VideoCodecs
/// </summary>
/// <param name="str"></param>
/// <returns></returns>
private VideoCodecs GetVideoCodecs(string str)
{
VideoCodecs videoCodecs;
switch (str)
{
case "H.264/AVC":
videoCodecs = Core.Settings.VideoCodecs.AVC;
break;
case "H.265/HEVC":
videoCodecs = Core.Settings.VideoCodecs.HEVC;
break;
default:
videoCodecs = Core.Settings.VideoCodecs.NONE;
break;
}
return videoCodecs;
}
/// <summary>
/// 发送需要显示的tip
/// </summary>
/// <param name="isSucceed"></param>
private void PublishTip(bool isSucceed)
{
if (isOnNavigatedTo) { return; }
if (isSucceed)
{
eventAggregator.GetEvent<MessageEvent>().Publish(DictionaryResource.GetString("TipSettingUpdated"));
}
else
{
eventAggregator.GetEvent<MessageEvent>().Publish(DictionaryResource.GetString("TipSettingFailed"));
}
}
}
}

@ -0,0 +1,151 @@
using DownKyi.Core.BiliApi.BiliUtils;
using DownKyi.Core.Logging;
using Prism.Commands;
using Prism.Events;
using System;
using System.Threading.Tasks;
namespace DownKyi.ViewModels.Toolbox
{
public class ViewBiliHelperViewModel : BaseViewModel
{
public const string Tag = "PageToolboxBiliHelper";
#region 页面属性申明
private string avid;
public string Avid
{
get { return avid; }
set { SetProperty(ref avid, value); }
}
private string bvid;
public string Bvid
{
get { return bvid; }
set { SetProperty(ref bvid, value); }
}
private string danmakuUserID;
public string DanmakuUserID
{
get { return danmakuUserID; }
set { SetProperty(ref danmakuUserID, value); }
}
private string userMid;
public string UserMid
{
get { return userMid; }
set { SetProperty(ref userMid, value); }
}
#endregion
public ViewBiliHelperViewModel(IEventAggregator eventAggregator) : base(eventAggregator)
{
#region 属性初始化
#endregion
}
#region 命令申明
// 输入avid事件
private DelegateCommand<string> avidCommand;
public DelegateCommand<string> AvidCommand => avidCommand ?? (avidCommand = new DelegateCommand<string>(ExecuteAvidCommand));
/// <summary>
/// 输入avid事件
/// </summary>
private async void ExecuteAvidCommand(string parameter)
{
if (parameter == null) { return; }
if (!ParseEntrance.IsAvId(parameter)) { return; }
long avid = ParseEntrance.GetAvId(parameter);
if (avid == -1) { return; }
await Task.Run(() =>
{
Bvid = BvId.Av2Bv((ulong)avid);
});
}
// 输入bvid事件
private DelegateCommand<string> bvidCommand;
public DelegateCommand<string> BvidCommand => bvidCommand ?? (bvidCommand = new DelegateCommand<string>(ExecuteBvidCommand));
/// <summary>
/// 输入bvid事件
/// </summary>
/// <param name="parameter"></param>
private async void ExecuteBvidCommand(string parameter)
{
if (parameter == null) { return; }
if (!ParseEntrance.IsBvId(parameter)) { return; }
await Task.Run(() =>
{
ulong avid = BvId.Bv2Av(parameter);
Avid = $"av{avid}";
});
}
// 访问网页事件
private DelegateCommand gotoWebCommand;
public DelegateCommand GotoWebCommand => gotoWebCommand ?? (gotoWebCommand = new DelegateCommand(ExecuteGotoWebCommand));
/// <summary>
/// 访问网页事件
/// </summary>
private void ExecuteGotoWebCommand()
{
string baseUrl = "https://www.bilibili.com/video/";
System.Diagnostics.Process.Start(baseUrl + Bvid);
}
// 查询弹幕发送者事件
private DelegateCommand findDanmakuSenderCommand;
public DelegateCommand FindDanmakuSenderCommand => findDanmakuSenderCommand ?? (findDanmakuSenderCommand = new DelegateCommand(ExecuteFindDanmakuSenderCommand));
/// <summary>
/// 查询弹幕发送者事件
/// </summary>
private async void ExecuteFindDanmakuSenderCommand()
{
await Task.Run(() =>
{
try
{
UserMid = DanmakuSender.FindDanmakuSender(DanmakuUserID);
}
catch (Exception e)
{
UserMid = null;
Core.Utils.Debug.Console.PrintLine("FindDanmakuSenderCommand()发生异常: {0}", e);
LogManager.Error(Tag, e);
}
});
}
// 访问用户空间事件
private DelegateCommand visitUserSpaceCommand;
public DelegateCommand VisitUserSpaceCommand => visitUserSpaceCommand ?? (visitUserSpaceCommand = new DelegateCommand(ExecuteVisitUserSpaceCommand));
/// <summary>
/// 访问用户空间事件
/// </summary>
private void ExecuteVisitUserSpaceCommand()
{
if (UserMid == null) { return; }
string baseUrl = "https://space.bilibili.com/";
System.Diagnostics.Process.Start(baseUrl + UserMid);
}
#endregion
}
}

@ -0,0 +1,195 @@
using DownKyi.Core.FFmpeg;
using DownKyi.Events;
using DownKyi.Utils;
using Prism.Commands;
using Prism.Events;
using System;
using System.Threading.Tasks;
using System.Windows.Controls;
namespace DownKyi.ViewModels.Toolbox
{
public class ViewDelogoViewModel : BaseViewModel
{
public const string Tag = "PageToolboxDelogo";
// 是否正在执行去水印任务
private bool isDelogo = false;
#region 页面属性申明
private string videoPath;
public string VideoPath
{
get { return videoPath; }
set { SetProperty(ref videoPath, value); }
}
private int logoWidth;
public int LogoWidth
{
get { return logoWidth; }
set { SetProperty(ref logoWidth, value); }
}
private int logoHeight;
public int LogoHeight
{
get { return logoHeight; }
set { SetProperty(ref logoHeight, value); }
}
private int logoX;
public int LogoX
{
get { return logoX; }
set { SetProperty(ref logoX, value); }
}
private int logoY;
public int LogoY
{
get { return logoY; }
set { SetProperty(ref logoY, value); }
}
private string status;
public string Status
{
get { return status; }
set { SetProperty(ref status, value); }
}
#endregion
public ViewDelogoViewModel(IEventAggregator eventAggregator) : base(eventAggregator)
{
#region 属性初始化
VideoPath = string.Empty;
LogoWidth = -1;
LogoHeight = -1;
LogoX = -1;
LogoY = -1;
#endregion
}
#region 命令申明
// 选择视频事件
private DelegateCommand selectVideoCommand;
public DelegateCommand SelectVideoCommand => selectVideoCommand ?? (selectVideoCommand = new DelegateCommand(ExecuteSelectVideoCommand));
/// <summary>
/// 选择视频事件
/// </summary>
private void ExecuteSelectVideoCommand()
{
if (isDelogo)
{
eventAggregator.GetEvent<MessageEvent>().Publish(DictionaryResource.GetString("TipWaitTaskFinished"));
return;
}
VideoPath = SelectVideoFile();
}
// 去水印事件
private DelegateCommand delogoCommand;
public DelegateCommand DelogoCommand => delogoCommand ?? (delogoCommand = new DelegateCommand(ExecuteDelogoCommand));
/// <summary>
/// 去水印事件
/// </summary>
private async void ExecuteDelogoCommand()
{
if (isDelogo)
{
eventAggregator.GetEvent<MessageEvent>().Publish(DictionaryResource.GetString("TipWaitTaskFinished"));
return;
}
if (VideoPath == "")
{
eventAggregator.GetEvent<MessageEvent>().Publish(DictionaryResource.GetString("TipNoSeletedVideo"));
return;
}
if (LogoWidth == -1)
{
eventAggregator.GetEvent<MessageEvent>().Publish(DictionaryResource.GetString("TipInputRightLogoWidth"));
return;
}
if (LogoHeight == -1)
{
eventAggregator.GetEvent<MessageEvent>().Publish(DictionaryResource.GetString("TipInputRightLogoHeight"));
return;
}
if (LogoX == -1)
{
eventAggregator.GetEvent<MessageEvent>().Publish(DictionaryResource.GetString("TipInputRightLogoX"));
return;
}
if (LogoY == -1)
{
eventAggregator.GetEvent<MessageEvent>().Publish(DictionaryResource.GetString("TipInputRightLogoY"));
return;
}
// 新文件名
string newFileName = VideoPath.Insert(VideoPath.Length - 4, "_delogo");
Status = string.Empty;
await Task.Run(() =>
{
// 执行去水印程序
isDelogo = true;
FFmpegHelper.Delogo(VideoPath, newFileName, LogoX, LogoY, LogoWidth, LogoHeight, new Action<string>((output) =>
{
Status += output + "\n";
}));
isDelogo = false;
});
}
// Status改变事件
private DelegateCommand<object> statusCommand;
public DelegateCommand<object> StatusCommand => statusCommand ?? (statusCommand = new DelegateCommand<object>(ExecuteStatusCommand));
/// <summary>
/// Status改变事件
/// </summary>
/// <param name="parameter"></param>
private void ExecuteStatusCommand(object parameter)
{
if (!(parameter is TextBox output)) { return; }
// TextBox滚动到底部
output.ScrollToEnd();
}
#endregion
/// <summary>
/// 选择视频dialog
/// </summary>
/// <returns></returns>
private string SelectVideoFile()
{
// 选择文件
var dialog = new Microsoft.Win32.OpenFileDialog
{
Filter = "mp4 (*.mp4)|*.mp4"
};
var showDialog = dialog.ShowDialog();
if (showDialog == true)
{
return dialog.FileName;
}
else { return ""; }
}
}
}

@ -0,0 +1,178 @@
using DownKyi.Core.FFmpeg;
using DownKyi.Events;
using DownKyi.Utils;
using Prism.Commands;
using Prism.Events;
using System;
using System.Threading.Tasks;
using System.Windows.Controls;
namespace DownKyi.ViewModels.Toolbox
{
public class ViewExtractMediaViewModel : BaseViewModel
{
public const string Tag = "PageToolboxExtractMedia";
// 是否正在执行任务
private bool isExtracting = false;
#region 页面属性申明
private string videoPath;
public string VideoPath
{
get { return videoPath; }
set { SetProperty(ref videoPath, value); }
}
private string status;
public string Status
{
get { return status; }
set { SetProperty(ref status, value); }
}
#endregion
public ViewExtractMediaViewModel(IEventAggregator eventAggregator) : base(eventAggregator)
{
#region 属性初始化
VideoPath = string.Empty;
#endregion
}
#region 命令申明
// 选择视频事件
private DelegateCommand selectVideoCommand;
public DelegateCommand SelectVideoCommand => selectVideoCommand ?? (selectVideoCommand = new DelegateCommand(ExecuteSelectVideoCommand));
/// <summary>
/// 选择视频事件
/// </summary>
private void ExecuteSelectVideoCommand()
{
if (isExtracting)
{
eventAggregator.GetEvent<MessageEvent>().Publish(DictionaryResource.GetString("TipWaitTaskFinished"));
return;
}
VideoPath = SelectVideoFile();
}
// 提取音频事件
private DelegateCommand extractAudioCommand;
public DelegateCommand ExtractAudioCommand => extractAudioCommand ?? (extractAudioCommand = new DelegateCommand(ExecuteExtractAudioCommand));
/// <summary>
/// 提取音频事件
/// </summary>
private async void ExecuteExtractAudioCommand()
{
if (isExtracting)
{
eventAggregator.GetEvent<MessageEvent>().Publish(DictionaryResource.GetString("TipWaitTaskFinished"));
return;
}
if (VideoPath == "")
{
eventAggregator.GetEvent<MessageEvent>().Publish(DictionaryResource.GetString("TipNoSeletedVideo"));
return;
}
// 音频文件名
string audioFileName = VideoPath.Remove(VideoPath.Length - 4, 4) + ".aac";
Status = string.Empty;
await Task.Run(() =>
{
// 执行提取音频程序
isExtracting = true;
FFmpegHelper.ExtractAudio(VideoPath, audioFileName, new Action<string>((output) =>
{
Status += output + "\n";
}));
isExtracting = false;
});
}
// 提取视频事件
private DelegateCommand extractVideoCommand;
public DelegateCommand ExtractVideoCommand => extractVideoCommand ?? (extractVideoCommand = new DelegateCommand(ExecuteExtractVideoCommand));
/// <summary>
/// 提取视频事件
/// </summary>
private async void ExecuteExtractVideoCommand()
{
if (isExtracting)
{
eventAggregator.GetEvent<MessageEvent>().Publish(DictionaryResource.GetString("TipWaitTaskFinished"));
return;
}
if (VideoPath == "")
{
eventAggregator.GetEvent<MessageEvent>().Publish(DictionaryResource.GetString("TipNoSeletedVideo"));
return;
}
// 视频文件名
string videoFileName = VideoPath.Remove(VideoPath.Length - 4, 4) + "_onlyVideo.mp4";
Status = string.Empty;
await Task.Run(() =>
{
// 执行提取视频程序
isExtracting = true;
FFmpegHelper.ExtractVideo(VideoPath, videoFileName, new Action<string>((output) =>
{
Status += output + "\n";
}));
isExtracting = false;
});
}
// Status改变事件
private DelegateCommand<object> statusCommand;
public DelegateCommand<object> StatusCommand => statusCommand ?? (statusCommand = new DelegateCommand<object>(ExecuteStatusCommand));
/// <summary>
/// Status改变事件
/// </summary>
/// <param name="parameter"></param>
private void ExecuteStatusCommand(object parameter)
{
if (!(parameter is TextBox output)) { return; }
// TextBox滚动到底部
output.ScrollToEnd();
}
#endregion
/// <summary>
/// 选择视频dialog
/// </summary>
/// <returns></returns>
private string SelectVideoFile()
{
// 选择文件
var dialog = new Microsoft.Win32.OpenFileDialog
{
Filter = "mp4 (*.mp4)|*.mp4"
};
var showDialog = dialog.ShowDialog();
if (showDialog == true)
{
return dialog.FileName;
}
else { return ""; }
}
}
}

@ -0,0 +1,125 @@
using DownKyi.Events;
using DownKyi.Images;
using DownKyi.Models;
using DownKyi.Utils;
using DownKyi.ViewModels.DownloadManager;
using Prism.Commands;
using Prism.Events;
using Prism.Regions;
using System.Collections.Generic;
namespace DownKyi.ViewModels
{
public class ViewDownloadManagerViewModel : BaseViewModel
{
public const string Tag = "PageDownloadManager";
private readonly IRegionManager regionManager;
#region 页面属性申明
private VectorImage arrowBack;
public VectorImage ArrowBack
{
get { return arrowBack; }
set { SetProperty(ref arrowBack, value); }
}
private List<TabHeader> tabHeaders;
public List<TabHeader> TabHeaders
{
get { return tabHeaders; }
set { SetProperty(ref tabHeaders, value); }
}
private int selectTabId;
public int SelectTabId
{
get { return selectTabId; }
set { SetProperty(ref selectTabId, value); }
}
#endregion
public ViewDownloadManagerViewModel(IRegionManager regionManager, IEventAggregator eventAggregator) : base(eventAggregator)
{
this.regionManager = regionManager;
#region 属性初始化
ArrowBack = NavigationIcon.Instance().ArrowBack;
ArrowBack.Fill = DictionaryResource.GetColor("ColorTextDark");
TabHeaders = new List<TabHeader>
{
new TabHeader { Id = 0, Image = NormalIcon.Instance().Downloading, Title = DictionaryResource.GetString("Downloading") },
new TabHeader { Id = 1, Image = NormalIcon.Instance().DownloadFinished, Title = DictionaryResource.GetString("DownloadFinished") }
};
#endregion
}
#region 命令申明
// 返回事件
private DelegateCommand backSpaceCommand;
public DelegateCommand BackSpaceCommand => backSpaceCommand ?? (backSpaceCommand = new DelegateCommand(ExecuteBackSpace));
/// <summary>
/// 返回事件
/// </summary>
private void ExecuteBackSpace()
{
NavigationParam parameter = new NavigationParam
{
ViewName = ParentView,
ParentViewName = null,
Parameter = null
};
eventAggregator.GetEvent<NavigationEvent>().Publish(parameter);
}
// 左侧tab点击事件
private DelegateCommand<object> leftTabHeadersCommand;
public DelegateCommand<object> LeftTabHeadersCommand => leftTabHeadersCommand ?? (leftTabHeadersCommand = new DelegateCommand<object>(ExecuteLeftTabHeadersCommand));
/// <summary>
/// 左侧tab点击事件
/// </summary>
/// <param name="parameter"></param>
private void ExecuteLeftTabHeadersCommand(object parameter)
{
if (!(parameter is TabHeader tabHeader)) { return; }
NavigationParameters param = new NavigationParameters();
switch (tabHeader.Id)
{
case 0:
regionManager.RequestNavigate("DownloadManagerContentRegion", ViewDownloadingViewModel.Tag, param);
break;
case 1:
regionManager.RequestNavigate("DownloadManagerContentRegion", ViewDownloadFinishedViewModel.Tag, param);
break;
default:
break;
}
}
#endregion
/// <summary>
/// 导航到VideoDetail页面时执行
/// </summary>
/// <param name="navigationContext"></param>
public override void OnNavigatedTo(NavigationContext navigationContext)
{
base.OnNavigatedTo(navigationContext);
//// 进入设置页面时显示的设置项
SelectTabId = 0;
regionManager.RequestNavigate("DownloadManagerContentRegion", ViewDownloadingViewModel.Tag, new NavigationParameters());
}
}
}

@ -0,0 +1,439 @@
using DownKyi.Core.BiliApi.BiliUtils;
using DownKyi.Core.BiliApi.Login;
using DownKyi.Core.Logging;
using DownKyi.Core.Settings;
using DownKyi.Core.Settings.Models;
using DownKyi.Core.Storage;
using DownKyi.Events;
using DownKyi.Images;
using DownKyi.Utils;
using Prism.Commands;
using Prism.Events;
using Prism.Regions;
using System;
using System.IO;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Media.Imaging;
namespace DownKyi.ViewModels
{
public class ViewIndexViewModel : BaseViewModel
{
public const string Tag = "PageIndex";
#region 页面属性申明
private Visibility loginPanelVisibility;
public Visibility LoginPanelVisibility
{
get { return loginPanelVisibility; }
set { SetProperty(ref loginPanelVisibility, value); }
}
private string userName;
public string UserName
{
get { return userName; }
set { SetProperty(ref userName, value); }
}
private BitmapImage header;
public BitmapImage Header
{
get { return header; }
set { SetProperty(ref header, value); }
}
private VectorImage textLogo;
public VectorImage TextLogo
{
get { return textLogo; }
set { SetProperty(ref textLogo, value); }
}
private string inputText;
public string InputText
{
get { return inputText; }
set { SetProperty(ref inputText, value); }
}
private VectorImage generalSearch;
public VectorImage GeneralSearch
{
get { return generalSearch; }
set { SetProperty(ref generalSearch, value); }
}
private VectorImage settings;
public VectorImage Settings
{
get { return settings; }
set { SetProperty(ref settings, value); }
}
private VectorImage downloadManager;
public VectorImage DownloadManager
{
get { return downloadManager; }
set { SetProperty(ref downloadManager, value); }
}
private VectorImage toolbox;
public VectorImage Toolbox
{
get { return toolbox; }
set { SetProperty(ref toolbox, value); }
}
#endregion
public ViewIndexViewModel(IEventAggregator eventAggregator) : base(eventAggregator)
{
#region 属性初始化
Header = new BitmapImage(new Uri("pack://application:,,,/Resources/default_header.jpg"));
TextLogo = LogoIcon.Instance().TextLogo;
TextLogo.Fill = DictionaryResource.GetColor("ColorPrimary");
GeneralSearch = ButtonIcon.Instance().GeneralSearch;
GeneralSearch.Fill = DictionaryResource.GetColor("ColorPrimary");
Settings = ButtonIcon.Instance().Settings;
Settings.Fill = DictionaryResource.GetColor("ColorPrimary");
DownloadManager = ButtonIcon.Instance().DownloadManage;
DownloadManager.Fill = DictionaryResource.GetColor("ColorPrimary");
Toolbox = ButtonIcon.Instance().Toolbox;
Toolbox.Fill = DictionaryResource.GetColor("ColorPrimary");
#endregion
}
#region 命令申明
// View加载后执行的事件
public DelegateCommand loadedCommand;
public DelegateCommand LoadedCommand => loadedCommand ?? (loadedCommand = new DelegateCommand(ExecuteViewLoaded));
/// <summary>
/// View加载后执行
/// </summary>
private void ExecuteViewLoaded() { }
// 输入确认事件
public DelegateCommand inputCommand;
public DelegateCommand InputCommand => inputCommand ?? (inputCommand = new DelegateCommand(ExecuteInput));
/// <summary>
/// 处理输入事件
/// </summary>
private void ExecuteInput()
{
EnterBili();
}
// 登录事件
private DelegateCommand loginCommand;
public DelegateCommand LoginCommand => loginCommand ?? (loginCommand = new DelegateCommand(ExecuteLogin));
/// <summary>
/// 进入登录页面
/// </summary>
private void ExecuteLogin()
{
if (UserName == null)
{
NavigationView(ViewLoginViewModel.Tag, null);
}
else
{
// 进入用户空间
var userInfo = SettingsManager.GetInstance().GetUserInfo();
if (userInfo != null && userInfo.Mid != -1)
{
NavigationView(ViewMySpaceViewModel.Tag, userInfo.Mid);
}
}
}
// 进入设置页面
private DelegateCommand settingsCommand;
public DelegateCommand SettingsCommand => settingsCommand ?? (settingsCommand = new DelegateCommand(ExecuteSettingsCommand));
/// <summary>
/// 进入设置页面
/// </summary>
private void ExecuteSettingsCommand()
{
NavigationView(ViewSettingsViewModel.Tag, null);
}
// 进入下载管理页面
private DelegateCommand downloadManagerCommand;
public DelegateCommand DownloadManagerCommand => downloadManagerCommand ?? (downloadManagerCommand = new DelegateCommand(ExecuteDownloadManagerCommand));
/// <summary>
/// 进入下载管理页面
/// </summary>
private void ExecuteDownloadManagerCommand()
{
NavigationView(ViewDownloadManagerViewModel.Tag, null);
}
// 进入工具箱页面
private DelegateCommand toolboxCommand;
public DelegateCommand ToolboxCommand => toolboxCommand ?? (toolboxCommand = new DelegateCommand(ExecuteToolboxCommand));
/// <summary>
/// 进入工具箱页面
/// </summary>
private void ExecuteToolboxCommand()
{
NavigationView(ViewToolboxViewModel.Tag, null);
}
#endregion
#region 业务逻辑
/// <summary>
/// 进入B站链接的处理逻辑
/// 只负责处理输入,并跳转到视频详情页。<para/>
/// 不是支持的格式,则进入搜索页面。
/// 支持的格式有:<para/>
/// av号av170001, AV170001, https://www.bilibili.com/video/av170001 <para/>
/// BV号BV17x411w7KC, https://www.bilibili.com/video/BV17x411w7KC <para/>
/// 番剧电影、电视剧ss号ss32982, SS32982, https://www.bilibili.com/bangumi/play/ss32982 <para/>
/// 番剧电影、电视剧ep号ep317925, EP317925, https://www.bilibili.com/bangumi/play/ep317925 <para/>
/// 番剧电影、电视剧md号md28228367, MD28228367, https://www.bilibili.com/bangumi/media/md28228367 <para/>
/// 课程ss号https://www.bilibili.com/cheese/play/ss205 <para/>
/// 课程ep号https://www.bilibili.com/cheese/play/ep3489 <para/>
/// 收藏夹ml1329019876, ML1329019876, https://www.bilibili.com/medialist/detail/ml1329019876 <para/>
/// 用户空间uid928123, UID928123, uid:928123, UID:928123, https://space.bilibili.com/928123
/// </summary>
private void EnterBili()
{
if (InputText == null || InputText == string.Empty) { return; }
LogManager.Debug(Tag, $"InputText: {InputText}");
// 视频
if (ParseEntrance.IsAvId(InputText))
{
NavigationView(ViewVideoDetailViewModel.Tag, $"{ParseEntrance.VideoUrl}{InputText.ToLower()}");
}
else if (ParseEntrance.IsAvUrl(InputText))
{
NavigationView(ViewVideoDetailViewModel.Tag, InputText);
}
else if (ParseEntrance.IsBvId(InputText))
{
NavigationView(ViewVideoDetailViewModel.Tag, $"{ParseEntrance.VideoUrl}{InputText}");
}
else if (ParseEntrance.IsBvUrl(InputText))
{
NavigationView(ViewVideoDetailViewModel.Tag, InputText);
}
// 番剧(电影、电视剧)
else if (ParseEntrance.IsBangumiSeasonId(InputText))
{
NavigationView(ViewVideoDetailViewModel.Tag, $"{ParseEntrance.BangumiUrl}{InputText.ToLower()}");
}
else if (ParseEntrance.IsBangumiSeasonUrl(InputText))
{
NavigationView(ViewVideoDetailViewModel.Tag, InputText);
}
else if (ParseEntrance.IsBangumiEpisodeId(InputText))
{
NavigationView(ViewVideoDetailViewModel.Tag, $"{ParseEntrance.BangumiUrl}{InputText.ToLower()}");
}
else if (ParseEntrance.IsBangumiEpisodeUrl(InputText))
{
NavigationView(ViewVideoDetailViewModel.Tag, InputText);
}
else if (ParseEntrance.IsBangumiMediaId(InputText))
{
NavigationView(ViewVideoDetailViewModel.Tag, $"{ParseEntrance.BangumiMediaUrl}{InputText.ToLower()}");
}
else if (ParseEntrance.IsBangumiMediaUrl(InputText))
{
NavigationView(ViewVideoDetailViewModel.Tag, InputText);
}
// 课程
else if (ParseEntrance.IsCheeseSeasonUrl(InputText) || ParseEntrance.IsCheeseEpisodeUrl(InputText))
{
NavigationView(ViewVideoDetailViewModel.Tag, InputText);
}
// 用户参数传入mid
else if (ParseEntrance.IsUserId(InputText))
{
NavigateToViewUserSpace(ParseEntrance.GetUserId(InputText));
}
else if (ParseEntrance.IsUserUrl(InputText))
{
NavigateToViewUserSpace(ParseEntrance.GetUserId(InputText));
}
// 收藏夹
else if (ParseEntrance.IsFavoritesId(InputText))
{
NavigationView(ViewPublicFavoritesViewModel.Tag, ParseEntrance.GetFavoritesId(InputText));
}
else if (ParseEntrance.IsFavoritesUrl(InputText))
{
NavigationView(ViewPublicFavoritesViewModel.Tag, ParseEntrance.GetFavoritesId(InputText));
}
// TODO 关键词搜索
else
{
}
InputText = string.Empty;
}
/// <summary>
/// 导航到用户空间,
/// 如果传入的mid与本地登录的mid一致
/// 则进入我的用户空间。
/// </summary>
/// <param name="mid"></param>
private void NavigateToViewUserSpace(long mid)
{
var userInfo = SettingsManager.GetInstance().GetUserInfo();
if (userInfo != null && userInfo.Mid == mid)
{
NavigationView(ViewMySpaceViewModel.Tag, mid);
}
else
{
NavigationView(ViewUserSpaceViewModel.Tag, mid);
}
}
/// <summary>
/// 导航到其他页面
/// </summary>
/// <param name="viewName"></param>
/// <param name="param"></param>
private void NavigationView(string viewName, object param)
{
LogManager.Debug(Tag, $"NavigationView: {viewName}, Parameter: {param}");
NavigationParam parameter = new NavigationParam
{
ViewName = viewName,
ParentViewName = Tag,
Parameter = param
};
eventAggregator.GetEvent<NavigationEvent>().Publish(parameter);
}
/// <summary>
/// 更新用户登录信息
/// </summary>
private async void UpdateUserInfo()
{
LoginPanelVisibility = Visibility.Hidden;
// 检查本地是否存在login文件没有则说明未登录
if (!File.Exists(StorageManager.GetLogin()))
{
LoginPanelVisibility = Visibility.Visible;
Header = new BitmapImage(new Uri("pack://application:,,,/Resources/default_header.jpg"));
UserName = null;
return;
}
await Task.Run(new Action(() =>
{
// 获取用户信息
var userInfo = LoginInfo.GetUserInfoForNavigation();
if (userInfo != null)
{
SettingsManager.GetInstance().SetUserInfo(new UserInfoSettings
{
Mid = userInfo.Mid,
Name = userInfo.Name,
IsLogin = userInfo.IsLogin,
IsVip = userInfo.VipStatus == 1
});
}
else
{
SettingsManager.GetInstance().SetUserInfo(new UserInfoSettings
{
Mid = -1,
Name = "",
IsLogin = false,
IsVip = false
});
}
PropertyChangeAsync(new Action(() =>
{
LoginPanelVisibility = Visibility.Visible;
if (userInfo != null)
{
if (userInfo.Face != null)
{
Header = new StorageHeader().GetHeaderThumbnail(userInfo.Mid, userInfo.Name, userInfo.Face, 36, 36);
}
else
{
Header = new BitmapImage(new Uri("pack://application:,,,/Resources/default_header.jpg"));
}
UserName = userInfo.Name;
}
else
{
Header = new BitmapImage(new Uri("pack://application:,,,/Resources/default_header.jpg"));
UserName = null;
}
}));
}));
}
#endregion
public override void OnNavigatedTo(NavigationContext navigationContext)
{
base.OnNavigatedTo(navigationContext);
DownloadManager = ButtonIcon.Instance().DownloadManage;
DownloadManager.Height = 27;
DownloadManager.Width = 32;
DownloadManager.Fill = DictionaryResource.GetColor("ColorPrimary");
// 根据传入参数不同执行不同任务
string parameter = navigationContext.Parameters.GetValue<string>("Parameter");
if (parameter == null)
{
return;
}
// 启动
if (parameter == "start")
{
UpdateUserInfo();
}
// 从登录页面返回
if (parameter == "login")
{
UpdateUserInfo();
}
// 注销
if (parameter == "logout")
{
UpdateUserInfo();
}
}
}
}

@ -0,0 +1,251 @@
using DownKyi.Core.BiliApi.Login;
using DownKyi.Core.Logging;
using DownKyi.Events;
using DownKyi.Images;
using DownKyi.Utils;
using Prism.Commands;
using Prism.Events;
using Prism.Regions;
using System;
using System.Threading;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Media.Imaging;
namespace DownKyi.ViewModels
{
public class ViewLoginViewModel : BaseViewModel
{
public const string Tag = "PageLogin";
private CancellationTokenSource tokenSource;
#region 页面属性申明
private VectorImage arrowBack;
public VectorImage ArrowBack
{
get { return arrowBack; }
set { SetProperty(ref arrowBack, value); }
}
private BitmapImage loginQRCode;
public BitmapImage LoginQRCode
{
get { return loginQRCode; }
set { SetProperty(ref loginQRCode, value); }
}
private double loginQRCodeOpacity;
public double LoginQRCodeOpacity
{
get { return loginQRCodeOpacity; }
set { SetProperty(ref loginQRCodeOpacity, value); }
}
private Visibility loginQRCodeStatus;
public Visibility LoginQRCodeStatus
{
get { return loginQRCodeStatus; }
set { SetProperty(ref loginQRCodeStatus, value); }
}
#endregion
public ViewLoginViewModel(IEventAggregator eventAggregator) : base(eventAggregator)
{
#region 属性初始化
ArrowBack = NavigationIcon.Instance().ArrowBack;
ArrowBack.Fill = DictionaryResource.GetColor("ColorTextDark");
#endregion
}
#region 命令申明
// 返回
private DelegateCommand backSpaceCommand;
public DelegateCommand BackSpaceCommand => backSpaceCommand ?? (backSpaceCommand = new DelegateCommand(ExecuteBackSpace));
/// <summary>
/// 返回
/// </summary>
private void ExecuteBackSpace()
{
// 初始化状态
InitStatus();
// 结束任务
tokenSource.Cancel();
NavigationParam parameter = new NavigationParam
{
ViewName = ParentView,
ParentViewName = null,
Parameter = "login"
};
eventAggregator.GetEvent<NavigationEvent>().Publish(parameter);
}
#endregion
#region 业务逻辑
/// <summary>
/// 登录
/// </summary>
private void Login()
{
var loginUrl = LoginQR.GetLoginUrl();
if (loginUrl == null) { return; }
if (loginUrl.Status != true)
{
ExecuteBackSpace();
return;
}
if (loginUrl.Data == null || loginUrl.Data.Url == null)
{
eventAggregator.GetEvent<MessageEvent>().Publish(DictionaryResource.GetString("GetLoginUrlFailed"));
return;
}
PropertyChangeAsync(new Action(() => { LoginQRCode = LoginQR.GetLoginQRCode(loginUrl.Data.Url); }));
Core.Utils.Debug.Console.PrintLine(loginUrl.Data.Url + "\n");
LogManager.Debug(Tag, loginUrl.Data.Url);
GetLoginStatus(loginUrl.Data.OauthKey);
}
/// <summary>
/// 循环查询登录状态
/// </summary>
/// <param name="oauthKey"></param>
private void GetLoginStatus(string oauthKey)
{
CancellationToken cancellationToken = tokenSource.Token;
while (true)
{
Thread.Sleep(1000);
var loginStatus = LoginQR.GetLoginStatus(oauthKey);
if (loginStatus == null) { continue; }
Core.Utils.Debug.Console.PrintLine(loginStatus.Code + "\n" + loginStatus.Message + "\n" + loginStatus.Url + "\n");
switch (loginStatus.Code)
{
case -1:
// 没有这个oauthKey
// 发送通知
eventAggregator.GetEvent<MessageEvent>().Publish(DictionaryResource.GetString("LoginKeyError"));
LogManager.Info(Tag, DictionaryResource.GetString("LoginKeyError"));
// 取消任务
tokenSource.Cancel();
// 创建新任务
PropertyChangeAsync(new Action(() => { Task.Run(Login, (tokenSource = new CancellationTokenSource()).Token); }));
break;
case -2:
// 不匹配的oauthKey超时或已确认的oauthKey
// 发送通知
eventAggregator.GetEvent<MessageEvent>().Publish(DictionaryResource.GetString("LoginTimeOut"));
LogManager.Info(Tag, DictionaryResource.GetString("LoginTimeOut"));
// 取消任务
tokenSource.Cancel();
// 创建新任务
PropertyChangeAsync(new Action(() => { Task.Run(Login, (tokenSource = new CancellationTokenSource()).Token); }));
break;
case -4:
// 未扫码
break;
case -5:
// 已扫码,未确认
PropertyChangeAsync(new Action(() =>
{
LoginQRCodeStatus = Visibility.Visible;
LoginQRCodeOpacity = 0.3;
}));
break;
case 0:
// 确认登录
// 发送通知
eventAggregator.GetEvent<MessageEvent>().Publish(DictionaryResource.GetString("LoginSuccessful"));
LogManager.Info(Tag, DictionaryResource.GetString("LoginSuccessful"));
// 保存登录信息
try
{
bool isSucceed = LoginHelper.SaveLoginInfoCookies(loginStatus.Url);
if (!isSucceed)
{
eventAggregator.GetEvent<MessageEvent>().Publish(DictionaryResource.GetString("LoginFailed"));
LogManager.Error(Tag, DictionaryResource.GetString("LoginFailed"));
}
}
catch (Exception e)
{
Core.Utils.Debug.Console.PrintLine("PageLogin 保存登录信息发生异常: {0}", e);
LogManager.Error(e);
eventAggregator.GetEvent<MessageEvent>().Publish(DictionaryResource.GetString("LoginFailed"));
}
// TODO 其他操作
// 取消任务
Thread.Sleep(3000);
PropertyChangeAsync(new Action(() => { ExecuteBackSpace(); }));
break;
}
// 判断是否该结束线程若为true跳出while循环
if (cancellationToken.IsCancellationRequested)
{
Core.Utils.Debug.Console.PrintLine("停止Login线程跳出while循环");
LogManager.Debug(Tag, "登录操作结束");
break;
}
}
}
/// <summary>
/// 初始化状态
/// </summary>
private void InitStatus()
{
LoginQRCode = null;
LoginQRCodeOpacity = 1;
LoginQRCodeStatus = Visibility.Hidden;
}
#endregion
/// <summary>
/// 导航到Login页面时执行
/// </summary>
/// <param name="navigationContext"></param>
public override void OnNavigatedTo(NavigationContext navigationContext)
{
base.OnNavigatedTo(navigationContext);
// 初始化状态
InitStatus();
Task.Run(Login, (tokenSource = new CancellationTokenSource()).Token);
//await loginTask;
}
}
}

@ -0,0 +1,40 @@
using Prism.Commands;
using Prism.Events;
using Prism.Mvvm;
using Prism.Regions;
using System;
using System.Collections.Generic;
using System.Linq;
namespace DownKyi.ViewModels
{
public class ViewMySpaceViewModel : BaseViewModel
{
public const string Tag = "PageMySpace";
// mid
private long mid;
public ViewMySpaceViewModel(IEventAggregator eventAggregator) : base(eventAggregator)
{
}
/// <summary>
/// 接收mid参数
/// </summary>
/// <param name="navigationContext"></param>
public override void OnNavigatedTo(NavigationContext navigationContext)
{
base.OnNavigatedTo(navigationContext);
// 根据传入参数不同执行不同任务
long parameter = navigationContext.Parameters.GetValue<long>("Parameter");
if (parameter == 0)
{
return;
}
mid = parameter;
}
}
}

@ -0,0 +1,39 @@
using Prism.Commands;
using Prism.Events;
using Prism.Mvvm;
using Prism.Regions;
using System;
using System.Collections.Generic;
using System.Linq;
namespace DownKyi.ViewModels
{
public class ViewPublicFavoritesViewModel : BaseViewModel
{
public const string Tag = "PagePublicFavorites";
// 收藏夹id
private long favoritesId;
public ViewPublicFavoritesViewModel(IEventAggregator eventAggregator) : base(eventAggregator)
{
}
/// <summary>
/// 接收收藏夹id参数
/// </summary>
/// <param name="navigationContext"></param>
public override void OnNavigatedTo(NavigationContext navigationContext)
{
base.OnNavigatedTo(navigationContext);
// 根据传入参数不同执行不同任务
long parameter = navigationContext.Parameters.GetValue<long>("Parameter");
if (parameter == 0)
{
return;
}
favoritesId = parameter;
}
}
}

@ -0,0 +1,137 @@
using DownKyi.Events;
using DownKyi.Images;
using DownKyi.Models;
using DownKyi.Utils;
using DownKyi.ViewModels.Settings;
using Prism.Commands;
using Prism.Events;
using Prism.Regions;
using System.Collections.Generic;
namespace DownKyi.ViewModels
{
public class ViewSettingsViewModel : BaseViewModel
{
public const string Tag = "PageSettings";
private readonly IRegionManager regionManager;
#region 页面属性申明
private VectorImage arrowBack;
public VectorImage ArrowBack
{
get { return arrowBack; }
set { SetProperty(ref arrowBack, value); }
}
private List<TabHeader> tabHeaders;
public List<TabHeader> TabHeaders
{
get { return tabHeaders; }
set { SetProperty(ref tabHeaders, value); }
}
private int selectTabId;
public int SelectTabId
{
get { return selectTabId; }
set { SetProperty(ref selectTabId, value); }
}
#endregion
public ViewSettingsViewModel(IRegionManager regionManager, IEventAggregator eventAggregator) : base(eventAggregator)
{
this.regionManager = regionManager;
#region 属性初始化
ArrowBack = NavigationIcon.Instance().ArrowBack;
ArrowBack.Fill = DictionaryResource.GetColor("ColorTextDark");
TabHeaders = new List<TabHeader>
{
new TabHeader { Id = 0, Title = DictionaryResource.GetString("Basic") },
new TabHeader { Id = 1, Title = DictionaryResource.GetString("Network") },
new TabHeader { Id = 2, Title = DictionaryResource.GetString("Video") },
new TabHeader { Id = 3, Title = DictionaryResource.GetString("SettingDanmaku") },
new TabHeader { Id = 4, Title = DictionaryResource.GetString("About") }
};
#endregion
}
#region 命令申明
// 返回事件
private DelegateCommand backSpaceCommand;
public DelegateCommand BackSpaceCommand => backSpaceCommand ?? (backSpaceCommand = new DelegateCommand(ExecuteBackSpace));
/// <summary>
/// 返回事件
/// </summary>
private void ExecuteBackSpace()
{
NavigationParam parameter = new NavigationParam
{
ViewName = ParentView,
ParentViewName = null,
Parameter = null
};
eventAggregator.GetEvent<NavigationEvent>().Publish(parameter);
}
// 左侧tab点击事件
private DelegateCommand<object> leftTabHeadersCommand;
public DelegateCommand<object> LeftTabHeadersCommand => leftTabHeadersCommand ?? (leftTabHeadersCommand = new DelegateCommand<object>(ExecuteLeftTabHeadersCommand));
/// <summary>
/// 左侧tab点击事件
/// </summary>
/// <param name="parameter"></param>
private void ExecuteLeftTabHeadersCommand(object parameter)
{
if (!(parameter is TabHeader tabHeader)) { return; }
NavigationParameters param = new NavigationParameters();
switch (tabHeader.Id)
{
case 0:
regionManager.RequestNavigate("SettingsContentRegion", ViewBasicViewModel.Tag, param);
break;
case 1:
regionManager.RequestNavigate("SettingsContentRegion", ViewNetworkViewModel.Tag, param);
break;
case 2:
regionManager.RequestNavigate("SettingsContentRegion", ViewVideoViewModel.Tag, param);
break;
case 3:
regionManager.RequestNavigate("SettingsContentRegion", ViewDanmakuViewModel.Tag, param);
break;
case 4:
regionManager.RequestNavigate("SettingsContentRegion", ViewAboutViewModel.Tag, param);
break;
}
}
#endregion
/// <summary>
/// 导航到VideoDetail页面时执行
/// </summary>
/// <param name="navigationContext"></param>
public override void OnNavigatedTo(NavigationContext navigationContext)
{
base.OnNavigatedTo(navigationContext);
// 进入设置页面时显示的设置项
SelectTabId = 0;
regionManager.RequestNavigate("SettingsContentRegion", ViewBasicViewModel.Tag, new NavigationParameters());
}
}
}

@ -0,0 +1,128 @@
using DownKyi.Events;
using DownKyi.Images;
using DownKyi.Models;
using DownKyi.Utils;
using DownKyi.ViewModels.Toolbox;
using Prism.Commands;
using Prism.Events;
using Prism.Regions;
using System.Collections.Generic;
namespace DownKyi.ViewModels
{
public class ViewToolboxViewModel : BaseViewModel
{
public const string Tag = "PageToolbox";
private readonly IRegionManager regionManager;
#region 页面属性申明
private VectorImage arrowBack;
public VectorImage ArrowBack
{
get { return arrowBack; }
set { SetProperty(ref arrowBack, value); }
}
private List<TabHeader> tabHeaders;
public List<TabHeader> TabHeaders
{
get { return tabHeaders; }
set { SetProperty(ref tabHeaders, value); }
}
private int selectTabId;
public int SelectTabId
{
get { return selectTabId; }
set { SetProperty(ref selectTabId, value); }
}
#endregion
public ViewToolboxViewModel(IRegionManager regionManager, IEventAggregator eventAggregator) : base(eventAggregator)
{
this.regionManager = regionManager;
#region 属性初始化
ArrowBack = NavigationIcon.Instance().ArrowBack;
ArrowBack.Fill = DictionaryResource.GetColor("ColorTextDark");
TabHeaders = new List<TabHeader>
{
new TabHeader { Id = 0, Title = DictionaryResource.GetString("BiliHelper") },
new TabHeader { Id = 1, Title = DictionaryResource.GetString("Delogo") },
new TabHeader { Id = 2, Title = DictionaryResource.GetString("ExtractMedia") }
};
#endregion
}
#region 命令申明
// 返回事件
private DelegateCommand backSpaceCommand;
public DelegateCommand BackSpaceCommand => backSpaceCommand ?? (backSpaceCommand = new DelegateCommand(ExecuteBackSpace));
/// <summary>
/// 返回事件
/// </summary>
private void ExecuteBackSpace()
{
NavigationParam parameter = new NavigationParam
{
ViewName = ParentView,
ParentViewName = null,
Parameter = null
};
eventAggregator.GetEvent<NavigationEvent>().Publish(parameter);
}
// 左侧tab点击事件
private DelegateCommand<object> leftTabHeadersCommand;
public DelegateCommand<object> LeftTabHeadersCommand => leftTabHeadersCommand ?? (leftTabHeadersCommand = new DelegateCommand<object>(ExecuteLeftTabHeadersCommand));
/// <summary>
/// 左侧tab点击事件
/// </summary>
/// <param name="parameter"></param>
private void ExecuteLeftTabHeadersCommand(object parameter)
{
if (!(parameter is TabHeader tabHeader)) { return; }
NavigationParameters param = new NavigationParameters();
switch (tabHeader.Id)
{
case 0:
regionManager.RequestNavigate("ToolboxContentRegion", ViewBiliHelperViewModel.Tag, param);
break;
case 1:
regionManager.RequestNavigate("ToolboxContentRegion", ViewDelogoViewModel.Tag, param);
break;
case 2:
regionManager.RequestNavigate("ToolboxContentRegion", ViewExtractMediaViewModel.Tag, param);
break;
}
}
#endregion
/// <summary>
/// 导航到VideoDetail页面时执行
/// </summary>
/// <param name="navigationContext"></param>
public override void OnNavigatedTo(NavigationContext navigationContext)
{
base.OnNavigatedTo(navigationContext);
// 进入设置页面时显示的设置项
SelectTabId = 0;
regionManager.RequestNavigate("ToolboxContentRegion", ViewBiliHelperViewModel.Tag, new NavigationParameters());
}
}
}

@ -0,0 +1,40 @@
using Prism.Commands;
using Prism.Events;
using Prism.Mvvm;
using Prism.Regions;
using System;
using System.Collections.Generic;
using System.Linq;
namespace DownKyi.ViewModels
{
public class ViewUserSpaceViewModel : BaseViewModel
{
public const string Tag = "PageUserSpace";
// mid
private long mid;
public ViewUserSpaceViewModel(IEventAggregator eventAggregator) : base(eventAggregator)
{
}
/// <summary>
/// 接收mid参数
/// </summary>
/// <param name="navigationContext"></param>
public override void OnNavigatedTo(NavigationContext navigationContext)
{
base.OnNavigatedTo(navigationContext);
// 根据传入参数不同执行不同任务
long parameter = navigationContext.Parameters.GetValue<long>("Parameter");
if (parameter == 0)
{
return;
}
mid = parameter;
}
}
}

@ -0,0 +1,664 @@
using DownKyi.Core.BiliApi.BiliUtils;
using DownKyi.Core.Logging;
using DownKyi.Core.Settings;
using DownKyi.CustomControl;
using DownKyi.Events;
using DownKyi.Images;
using DownKyi.Models;
using DownKyi.Services;
using DownKyi.Utils;
using DownKyi.ViewModels.Dialogs;
using Prism.Commands;
using Prism.Events;
using Prism.Regions;
using Prism.Services.Dialogs;
using System;
using System.Collections.ObjectModel;
using System.IO;
using System.Linq;
using System.Threading.Tasks;
using System.Windows;
namespace DownKyi.ViewModels
{
public class ViewVideoDetailViewModel : BaseViewModel
{
public const string Tag = "PageVideoDetail";
private readonly IDialogService dialogService;
#region 页面属性申明
private VectorImage arrowBack;
public VectorImage ArrowBack
{
get { return arrowBack; }
set { SetProperty(ref arrowBack, value); }
}
private string inputText;
public string InputText
{
get { return inputText; }
set { SetProperty(ref inputText, value); }
}
private GifImage loading;
public GifImage Loading
{
get { return loading; }
set { SetProperty(ref loading, value); }
}
private Visibility loadingVisibility;
public Visibility LoadingVisibility
{
get { return loadingVisibility; }
set { SetProperty(ref loadingVisibility, value); }
}
private VectorImage downloadManage;
public VectorImage DownloadManage
{
get { return downloadManage; }
set { SetProperty(ref downloadManage, value); }
}
private VideoInfoView videoInfoView;
public VideoInfoView VideoInfoView
{
get { return videoInfoView; }
set { SetProperty(ref videoInfoView, value); }
}
private ObservableCollection<VideoSection> videoSections;
public ObservableCollection<VideoSection> VideoSections
{
get { return videoSections; }
set { SetProperty(ref videoSections, value); }
}
private bool isSelectAll;
public bool IsSelectAll
{
get { return isSelectAll; }
set { SetProperty(ref isSelectAll, value); }
}
private Visibility contentVisibility;
public Visibility ContentVisibility
{
get { return contentVisibility; }
set { SetProperty(ref contentVisibility, value); }
}
private Visibility noDataVisibility;
public Visibility NoDataVisibility
{
get { return noDataVisibility; }
set { SetProperty(ref noDataVisibility, value); }
}
#endregion
public ViewVideoDetailViewModel(IEventAggregator eventAggregator, IDialogService dialogService) : base(eventAggregator)
{
this.dialogService = dialogService;
#region 属性初始化
Loading = new GifImage(Properties.Resources.loading);
Loading.StartAnimate();
LoadingVisibility = Visibility.Collapsed;
ArrowBack = NavigationIcon.Instance().ArrowBack;
ArrowBack.Fill = DictionaryResource.GetColor("ColorTextDark");
DownloadManage = ButtonIcon.Instance().DownloadManage;
DownloadManage.Height = 24;
DownloadManage.Width = 24;
DownloadManage.Fill = DictionaryResource.GetColor("ColorPrimary");
VideoSections = new ObservableCollection<VideoSection>();
#endregion
}
#region 命令申明
// 返回
private DelegateCommand backSpaceCommand;
public DelegateCommand BackSpaceCommand => backSpaceCommand ?? (backSpaceCommand = new DelegateCommand(ExecuteBackSpace));
/// <summary>
/// 返回
/// </summary>
private void ExecuteBackSpace()
{
InitView();
NavigationParam parameter = new NavigationParam
{
ViewName = ParentView,
ParentViewName = null,
Parameter = null
};
eventAggregator.GetEvent<NavigationEvent>().Publish(parameter);
}
// 前往下载管理页面
private DelegateCommand downloadManagerCommand;
public DelegateCommand DownloadManagerCommand => downloadManagerCommand ?? (downloadManagerCommand = new DelegateCommand(ExecuteDownloadManagerCommand));
/// <summary>
/// 前往下载管理页面
/// </summary>
private void ExecuteDownloadManagerCommand()
{
NavigationParam parameter = new NavigationParam
{
ViewName = ViewDownloadManagerViewModel.Tag,
ParentViewName = Tag,
Parameter = null
};
eventAggregator.GetEvent<NavigationEvent>().Publish(parameter);
}
// 输入确认事件
private DelegateCommand inputCommand;
public DelegateCommand InputCommand => inputCommand ?? (inputCommand = new DelegateCommand(ExecuteInputCommand, CanExecuteInputCommand));
/// <summary>
/// 处理输入事件
/// </summary>
private async void ExecuteInputCommand()
{
InitView();
try
{
await Task.Run(() =>
{
if (InputText == null || InputText == string.Empty) { return; }
LogManager.Debug(Tag, $"InputText: {InputText}");
// 更新页面
UnityUpdateView(UpdateView, InputText, null);
// 是否自动解析视频
if (SettingsManager.GetInstance().IsAutoParseVideo() == AllowStatus.YES)
{
PropertyChangeAsync(ExecuteParseAllVideoCommand);
}
});
}
catch (Exception e)
{
Core.Utils.Debug.Console.PrintLine("InputCommand()发生异常: {0}", e);
LogManager.Error(Tag, e);
LoadingVisibility = Visibility.Collapsed;
ContentVisibility = Visibility.Collapsed;
NoDataVisibility = Visibility.Visible;
}
}
/// <summary>
/// 输入事件是否允许执行
/// </summary>
/// <returns></returns>
private bool CanExecuteInputCommand()
{
return LoadingVisibility != Visibility.Visible;
}
// 复制封面事件
private DelegateCommand copyCoverCommand;
public DelegateCommand CopyCoverCommand => copyCoverCommand ?? (copyCoverCommand = new DelegateCommand(ExecuteCopyCoverCommand));
/// <summary>
/// 复制封面事件
/// </summary>
private void ExecuteCopyCoverCommand()
{
// 复制封面图片到剪贴板
Clipboard.SetImage(VideoInfoView.Cover);
LogManager.Info(Tag, "复制封面图片到剪贴板");
}
// 复制封面URL事件
private DelegateCommand copyCoverUrlCommand;
public DelegateCommand CopyCoverUrlCommand => copyCoverUrlCommand ?? (copyCoverUrlCommand = new DelegateCommand(ExecuteCopyCoverUrlCommand));
/// <summary>
/// 复制封面URL事件
/// </summary>
private void ExecuteCopyCoverUrlCommand()
{
// 复制封面url到剪贴板
Clipboard.SetText(VideoInfoView.CoverUrl);
LogManager.Info(Tag, "复制封面url到剪贴板");
}
// 视频章节选择事件
private DelegateCommand<object> videoSectionsCommand;
public DelegateCommand<object> VideoSectionsCommand => videoSectionsCommand ?? (videoSectionsCommand = new DelegateCommand<object>(ExecuteVideoSectionsCommand));
/// <summary>
/// 视频章节选择事件
/// </summary>
/// <param name="parameter"></param>
private void ExecuteVideoSectionsCommand(object parameter)
{
if (!(parameter is VideoSection section)) { return; }
bool isSelectAll = true;
foreach (var page in section.VideoPages)
{
if (!page.IsSelected)
{
isSelectAll = false;
break;
}
}
IsSelectAll = section.VideoPages.Count != 0 && isSelectAll;
}
// 视频page选择事件
private DelegateCommand<object> videoPagesCommand;
public DelegateCommand<object> VideoPagesCommand => videoPagesCommand ?? (videoPagesCommand = new DelegateCommand<object>(ExecuteVideoPagesCommand));
/// <summary>
/// 视频page选择事件
/// </summary>
/// <param name="parameter"></param>
private void ExecuteVideoPagesCommand(object parameter)
{
if (!(parameter is ObservableCollection<object> videoPages)) { return; }
VideoSection section = VideoSections.FirstOrDefault(item => item.IsSelected);
if (section == null) { return; }
IsSelectAll = section.VideoPages.Count == videoPages.Count && section.VideoPages.Count != 0;
}
// Ctrl+A 全选事件
private DelegateCommand<object> keySelectAllCommand;
public DelegateCommand<object> KeySelectAllCommand => keySelectAllCommand ?? (keySelectAllCommand = new DelegateCommand<object>(ExecuteKeySelectAllCommand));
/// <summary>
/// Ctrl+A 全选事件
/// </summary>
private void ExecuteKeySelectAllCommand(object parameter)
{
if (!(parameter is VideoSection section)) { return; }
foreach (var page in section.VideoPages)
{
page.IsSelected = true;
}
}
// 全选事件
private DelegateCommand<object> selectAllCommand;
public DelegateCommand<object> SelectAllCommand => selectAllCommand ?? (selectAllCommand = new DelegateCommand<object>(ExecuteSelectAllCommand));
/// <summary>
/// 全选事件
/// </summary>
/// <param name="parameter"></param>
private void ExecuteSelectAllCommand(object parameter)
{
if (!(parameter is VideoSection section)) { return; }
if (IsSelectAll)
{
foreach (var page in section.VideoPages)
{
page.IsSelected = true;
}
}
else
{
foreach (var page in section.VideoPages)
{
page.IsSelected = false;
}
}
}
// 解析视频流事件
private DelegateCommand<object> parseCommand;
public DelegateCommand<object> ParseCommand => parseCommand ?? (parseCommand = new DelegateCommand<object>(ExecuteParseCommand, CanExecuteParseCommand));
/// <summary>
/// 解析视频流事件
/// </summary>
/// <param name="parameter"></param>
private async void ExecuteParseCommand(object parameter)
{
if (!(parameter is VideoPage videoPage))
{
return;
}
LoadingVisibility = Visibility.Visible;
try
{
await Task.Run(() =>
{
LogManager.Debug(Tag, $"Video Page: {videoPage.Cid}");
UnityUpdateView(ParseVideo, null, videoPage);
});
}
catch (Exception e)
{
Core.Utils.Debug.Console.PrintLine("ParseCommand()发生异常: {0}", e);
LogManager.Error(Tag, e);
LoadingVisibility = Visibility.Collapsed;
}
LoadingVisibility = Visibility.Collapsed;
}
/// <summary>
/// 解析视频流事件是否允许执行
/// </summary>
/// <param name="parameter"></param>
/// <returns></returns>
private bool CanExecuteParseCommand(object parameter)
{
return LoadingVisibility != Visibility.Visible;
}
// 解析所有视频流事件
private DelegateCommand parseAllVideoCommand;
public DelegateCommand ParseAllVideoCommand => parseAllVideoCommand ?? (parseAllVideoCommand = new DelegateCommand(ExecuteParseAllVideoCommand, CanExecuteParseAllVideoCommand));
/// <summary>
/// 解析所有视频流事件
/// </summary>
private async void ExecuteParseAllVideoCommand()
{
LoadingVisibility = Visibility.Visible;
// 解析范围
ParseScope parseScope = SettingsManager.GetInstance().GetParseScope();
// 是否选择了解析范围
if (parseScope == ParseScope.NONE)
{
// 打开解析选择器
dialogService.ShowDialog(ViewParsingSelectorViewModel.Tag, null, result =>
{
if (result.Result == ButtonResult.OK)
{
// 选择的解析范围
parseScope = result.Parameters.GetValue<ParseScope>("parseScope");
}
});
}
LogManager.Debug(Tag, $"ParseScope: {parseScope:G}");
try
{
await Task.Run(() =>
{
LogManager.Debug(Tag, "Parse video");
switch (parseScope)
{
case ParseScope.NONE:
break;
case ParseScope.SELECTED_ITEM:
foreach (var section in VideoSections)
{
foreach (var page in section.VideoPages)
{
var videoPage = section.VideoPages.FirstOrDefault(t => t == page);
if (videoPage.IsSelected)
{
// 执行解析任务
UnityUpdateView(ParseVideo, null, videoPage);
}
}
}
break;
case ParseScope.CURRENT_SECTION:
foreach (var section in VideoSections)
{
if (section.IsSelected)
{
foreach (var page in section.VideoPages)
{
var videoPage = section.VideoPages.FirstOrDefault(t => t == page);
// 执行解析任务
UnityUpdateView(ParseVideo, null, videoPage);
}
}
}
break;
case ParseScope.ALL:
foreach (var section in VideoSections)
{
foreach (var page in section.VideoPages)
{
var videoPage = section.VideoPages.FirstOrDefault(t => t == page);
// 执行解析任务
UnityUpdateView(ParseVideo, null, videoPage);
}
}
break;
default:
break;
}
});
}
catch (Exception e)
{
Core.Utils.Debug.Console.PrintLine("ParseCommand()发生异常: {0}", e);
LogManager.Error(Tag, e);
LoadingVisibility = Visibility.Collapsed;
}
LoadingVisibility = Visibility.Collapsed;
}
/// <summary>
/// 解析所有视频流事件是否允许执行
/// </summary>
/// <returns></returns>
private bool CanExecuteParseAllVideoCommand()
{
return LoadingVisibility != Visibility.Visible;
}
// 添加到下载列表事件
private DelegateCommand addToDownloadCommand;
public DelegateCommand AddToDownloadCommand => addToDownloadCommand ?? (addToDownloadCommand = new DelegateCommand(ExecuteAddToDownloadCommand, CanExecuteAddToDownloadCommand));
/// <summary>
/// 添加到下载列表事件
/// </summary>
private void ExecuteAddToDownloadCommand()
{
// 选择的下载文件夹
string directory = string.Empty;
// 是否使用默认下载目录
if (SettingsManager.GetInstance().IsUseSaveVideoRootPath() == AllowStatus.YES)
{
directory = SettingsManager.GetInstance().GetSaveVideoRootPath();
}
else
{
// 打开文件夹选择器
dialogService.ShowDialog(ViewDirectorySelectorViewModel.Tag, null, result =>
{
if (result.Result == ButtonResult.OK)
{
// 选择的下载文件夹
directory = result.Parameters.GetValue<string>("directory");
// 文件夹不存在则创建
if (!Directory.Exists(directory))
{
Directory.CreateDirectory(directory);
}
// 添加到下载
eventAggregator.GetEvent<MessageEvent>().Publish(directory);
}
});
}
}
/// <summary>
/// 添加到下载列表事件是否允许执行
/// </summary>
/// <returns></returns>
private bool CanExecuteAddToDownloadCommand()
{
return LoadingVisibility != Visibility.Visible;
}
#endregion
#region 业务逻辑
/// <summary>
/// 初始化页面元素
/// </summary>
private void InitView()
{
LogManager.Debug(Tag, "初始化页面元素");
LoadingVisibility = Visibility.Visible;
ContentVisibility = Visibility.Collapsed;
NoDataVisibility = Visibility.Collapsed;
VideoSections.Clear();
}
/// <summary>
/// 更新页面的统一方法
/// </summary>
/// <param name="action"></param>
/// <param name="input"></param>
/// <param name="page"></param>
private void UnityUpdateView(Action<IInfoService, VideoPage> action, string input, VideoPage page)
{
// 视频
if (ParseEntrance.IsAvUrl(InputText) || ParseEntrance.IsBvUrl(InputText))
{
action(new VideoInfoService(input), page);
}
// 番剧(电影、电视剧)
if (ParseEntrance.IsBangumiSeasonUrl(InputText) || ParseEntrance.IsBangumiEpisodeUrl(InputText) || ParseEntrance.IsBangumiMediaUrl(InputText))
{
action(new BangumiInfoService(input), page);
}
// 课程
if (ParseEntrance.IsCheeseSeasonUrl(InputText) || ParseEntrance.IsCheeseEpisodeUrl(InputText))
{
action(new CheeseInfoService(input), page);
}
}
/// <summary>
/// 更新页面
/// </summary>
/// <param name="videoInfoService"></param>
private void UpdateView(IInfoService videoInfoService, VideoPage param)
{
VideoInfoView = videoInfoService.GetVideoView();
if (VideoInfoView == null)
{
LogManager.Debug(Tag, "VideoInfoView is null.");
LoadingVisibility = Visibility.Collapsed;
ContentVisibility = Visibility.Collapsed;
NoDataVisibility = Visibility.Visible;
return;
}
else
{
LoadingVisibility = Visibility.Collapsed;
ContentVisibility = Visibility.Visible;
}
var videoSections = videoInfoService.GetVideoSections();
if (videoSections == null)
{
LogManager.Debug(Tag, "videoSections is not exist.");
var pages = videoInfoService.GetVideoPages();
PropertyChangeAsync(new Action(() =>
{
VideoSections.Add(new VideoSection
{
Id = 0,
Title = "default",
IsSelected = true,
VideoPages = pages
});
}));
}
else
{
PropertyChangeAsync(new Action(() =>
{
VideoSections.AddRange(videoSections);
}));
}
}
/// <summary>
/// 解析视频流
/// </summary>
/// <param name="videoInfoService"></param>
private void ParseVideo(IInfoService videoInfoService, VideoPage videoPage)
{
videoInfoService.GetVideoStream(videoPage);
}
#endregion
/// <summary>
/// 导航到VideoDetail页面时执行
/// </summary>
/// <param name="navigationContext"></param>
public override void OnNavigatedTo(NavigationContext navigationContext)
{
base.OnNavigatedTo(navigationContext);
DownloadManage = ButtonIcon.Instance().DownloadManage;
DownloadManage.Height = 24;
DownloadManage.Width = 24;
DownloadManage.Fill = DictionaryResource.GetColor("ColorPrimary");
// Parent参数为null时表示是从下一个页面返回到本页面不需要执行任务
if (navigationContext.Parameters.GetValue<string>("Parent") != null)
{
// 正在执行任务时不开启新任务
if (LoadingVisibility != Visibility.Visible)
{
InputText = navigationContext.Parameters.GetValue<string>("Parameter");
PropertyChangeAsync(ExecuteInputCommand);
}
}
}
}
}

@ -0,0 +1,240 @@
<UserControl
x:Class="DownKyi.Views.Dialogs.ViewDirectorySelector"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:i="http://schemas.microsoft.com/xaml/behaviors"
xmlns:prism="http://prismlibrary.com/"
prism:ViewModelLocator.AutoWireViewModel="True">
<prism:Dialog.WindowStyle>
<Style TargetType="Window">
<Setter Property="prism:Dialog.WindowStartupLocation" Value="CenterOwner" />
<Setter Property="ResizeMode" Value="NoResize" />
<Setter Property="ShowInTaskbar" Value="False" />
<Setter Property="SizeToContent" Value="WidthAndHeight" />
<Setter Property="WindowStyle" Value="None" />
</Style>
</prism:Dialog.WindowStyle>
<Border BorderBrush="{DynamicResource BrushWindowBorder}" BorderThickness="1,1,1,0.6">
<Grid Background="{DynamicResource BrushBackground}">
<Grid.RowDefinitions>
<RowDefinition Height="40" />
<RowDefinition />
</Grid.RowDefinitions>
<Grid
Grid.Row="0"
Background="{DynamicResource BrushCaptionBackground}"
KeyboardNavigation.TabNavigation="None">
<i:Interaction.Triggers>
<i:EventTrigger EventName="MouseLeftButtonDown">
<i:InvokeCommandAction Command="{Binding DragMoveCommand}" />
</i:EventTrigger>
</i:Interaction.Triggers>
<Grid.ColumnDefinitions>
<ColumnDefinition />
<ColumnDefinition Width="50" />
<ColumnDefinition Width="*" />
<ColumnDefinition Width="50" />
</Grid.ColumnDefinitions>
<TextBlock
Grid.Column="0"
Margin="10,0"
VerticalAlignment="Center"
FontSize="12"
Foreground="{DynamicResource BrushCaptionForeground}"
Text="{Binding Title}" />
<Button
Grid.Column="4"
Command="{Binding CloseCommand}"
Style="{StaticResource CloseBtnStyle}"
ToolTip="{DynamicResource Close}">
<Path
Width="{Binding CloseIcon.Width}"
Height="{Binding CloseIcon.Height}"
Data="{Binding CloseIcon.Data}"
Fill="{Binding CloseIcon.Fill}"
Stretch="UniformToFill" />
<i:Interaction.Triggers>
<i:EventTrigger EventName="MouseEnter">
<i:InvokeCommandAction Command="{Binding CloseEnterCommand}" />
</i:EventTrigger>
<i:EventTrigger EventName="MouseLeave">
<i:InvokeCommandAction Command="{Binding CloseLeaveCommand}" />
</i:EventTrigger>
</i:Interaction.Triggers>
</Button>
</Grid>
<Grid
Grid.Row="1"
MinWidth="600"
Margin="15,10">
<Grid.RowDefinitions>
<RowDefinition />
<RowDefinition />
<RowDefinition />
</Grid.RowDefinitions>
<Grid Grid.Row="0" Margin="0,30,0,0">
<Grid.ColumnDefinitions>
<ColumnDefinition />
<ColumnDefinition />
<ColumnDefinition />
<ColumnDefinition />
<ColumnDefinition />
</Grid.ColumnDefinitions>
<ContentControl
Grid.Column="1"
HorizontalAlignment="Center"
VerticalAlignment="Bottom">
<Path
Width="{Binding CloudDownloadIcon.Width}"
Height="{Binding CloudDownloadIcon.Height}"
Data="{Binding CloudDownloadIcon.Data}"
Fill="{Binding CloudDownloadIcon.Fill}"
Stretch="UniformToFill" />
</ContentControl>
<TextBlock
Grid.Column="2"
VerticalAlignment="Center"
FontSize="18"
Foreground="{DynamicResource BrushPrimary}"
Text="&gt;&gt;&gt;&gt;&gt;&gt;&gt;&gt;&gt;&gt;&gt;&gt;&gt;&gt;&gt;&gt;" />
<ContentControl
Grid.Column="3"
HorizontalAlignment="Center"
VerticalAlignment="Bottom">
<Path
Width="{Binding FolderIcon.Width}"
Height="{Binding FolderIcon.Height}"
Data="{Binding FolderIcon.Data}"
Fill="{Binding FolderIcon.Fill}"
Stretch="UniformToFill" />
</ContentControl>
</Grid>
<Grid Grid.Row="1" Margin="0,30,0,0">
<Grid.RowDefinitions>
<RowDefinition />
<RowDefinition />
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="auto" />
<ColumnDefinition Width="*" />
<ColumnDefinition Width="auto" />
</Grid.ColumnDefinitions>
<TextBlock
Grid.Row="0"
Grid.Column="0"
HorizontalAlignment="Left"
VerticalAlignment="Center"
FontSize="12"
Foreground="{DynamicResource BrushTextDark}"
Text="{DynamicResource Location}" />
<ComboBox
Grid.Row="0"
Grid.Column="1"
Height="25"
Margin="10,0"
VerticalAlignment="Center"
VerticalContentAlignment="Center"
ItemsSource="{Binding DirectoryList, Mode=TwoWay}"
SelectedValue="{Binding Directory, Mode=TwoWay}" />
<Button
Grid.Row="0"
Grid.Column="2"
HorizontalAlignment="Right"
VerticalAlignment="Center"
Command="{Binding BrowseCommand}"
Content="{DynamicResource Browse}"
FontSize="12"
Foreground="{DynamicResource BrushText}"
Style="{StaticResource BtnStyle}" />
<StackPanel
Grid.Row="1"
Grid.Column="1"
Margin="10,10,10,0"
Orientation="Horizontal">
<StackPanel.Style>
<Style TargetType="{x:Type StackPanel}">
<Style.Triggers>
<DataTrigger Binding="{Binding Directory}" Value="">
<Setter Property="Visibility" Value="Hidden" />
</DataTrigger>
<DataTrigger Binding="{Binding Directory}" Value="{x:Null}">
<Setter Property="Visibility" Value="Hidden" />
</DataTrigger>
</Style.Triggers>
</Style>
</StackPanel.Style>
<TextBlock
FontSize="12"
Foreground="{DynamicResource BrushTextDark}"
Text="{Binding DriveName}" />
<TextBlock
FontSize="12"
Foreground="{DynamicResource BrushTextDark}"
Text="{DynamicResource HardDiskFreeSpace}" />
<TextBlock
FontSize="12"
Foreground="{DynamicResource BrushTextDark}"
Text="{Binding DriveNameFreeSpace}" />
</StackPanel>
</Grid>
<Grid Grid.Row="2" Margin="0,30,0,0">
<Grid.ColumnDefinitions>
<ColumnDefinition />
<ColumnDefinition />
<ColumnDefinition Width="100" />
<ColumnDefinition Width="100" />
</Grid.ColumnDefinitions>
<CheckBox
Grid.Column="0"
HorizontalAlignment="Left"
VerticalAlignment="Bottom"
Content="{DynamicResource IsDefaultDownloadDirectory}"
Foreground="{DynamicResource BrushTextDark}"
IsChecked="{Binding IsDefaultDownloadDirectory, Mode=TwoWay}"
Style="{StaticResource CheckBoxStyle}"
ToolTip="{DynamicResource IsDefaultDownloadDirectoryTip}" />
<Button
Grid.Column="2"
Width="75"
HorizontalAlignment="Right"
VerticalAlignment="Bottom"
Command="{Binding DownloadCommand}"
Content="{DynamicResource Download}"
FontSize="12"
Foreground="{DynamicResource BrushText}"
Style="{StaticResource BtnStyle}" />
<Button
Grid.Column="3"
Width="75"
HorizontalAlignment="Right"
VerticalAlignment="Bottom"
Command="{Binding CloseCommand}"
Content="{DynamicResource Cancel}"
FontSize="12"
Foreground="{DynamicResource BrushText}"
Style="{StaticResource BtnStyle}" />
</Grid>
</Grid>
</Grid>
</Border>
</UserControl>

@ -0,0 +1,15 @@
using System.Windows.Controls;
namespace DownKyi.Views.Dialogs
{
/// <summary>
/// Interaction logic for ViewDirectorySelector
/// </summary>
public partial class ViewDirectorySelector : UserControl
{
public ViewDirectorySelector()
{
InitializeComponent();
}
}
}

@ -0,0 +1,126 @@
<UserControl
x:Class="DownKyi.Views.Dialogs.ViewParsingSelector"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:i="http://schemas.microsoft.com/xaml/behaviors"
xmlns:prism="http://prismlibrary.com/"
prism:ViewModelLocator.AutoWireViewModel="True">
<prism:Dialog.WindowStyle>
<Style TargetType="Window">
<Setter Property="prism:Dialog.WindowStartupLocation" Value="CenterOwner" />
<Setter Property="ResizeMode" Value="NoResize" />
<Setter Property="ShowInTaskbar" Value="False" />
<Setter Property="SizeToContent" Value="WidthAndHeight" />
<Setter Property="WindowStyle" Value="None" />
</Style>
</prism:Dialog.WindowStyle>
<Border BorderBrush="{DynamicResource BrushWindowBorder}" BorderThickness="1,1,1,0.6">
<Grid Background="{DynamicResource BrushBackground}">
<Grid.RowDefinitions>
<RowDefinition Height="40" />
<RowDefinition />
</Grid.RowDefinitions>
<Grid
Grid.Row="0"
Background="{DynamicResource BrushCaptionBackground}"
KeyboardNavigation.TabNavigation="None">
<i:Interaction.Triggers>
<i:EventTrigger EventName="MouseLeftButtonDown">
<i:InvokeCommandAction Command="{Binding DragMoveCommand}" />
</i:EventTrigger>
</i:Interaction.Triggers>
<Grid.ColumnDefinitions>
<ColumnDefinition />
<ColumnDefinition Width="50" />
<ColumnDefinition Width="*" />
<ColumnDefinition Width="50" />
</Grid.ColumnDefinitions>
<TextBlock
Grid.Column="0"
Margin="10,0"
VerticalAlignment="Center"
FontSize="12"
Foreground="{DynamicResource BrushCaptionForeground}"
Text="{Binding Title}" />
<Button
Grid.Column="4"
Command="{Binding CloseCommand}"
Style="{StaticResource CloseBtnStyle}"
ToolTip="{DynamicResource Close}">
<Path
Width="{Binding CloseIcon.Width}"
Height="{Binding CloseIcon.Height}"
Data="{Binding CloseIcon.Data}"
Fill="{Binding CloseIcon.Fill}"
Stretch="UniformToFill" />
<i:Interaction.Triggers>
<i:EventTrigger EventName="MouseEnter">
<i:InvokeCommandAction Command="{Binding CloseEnterCommand}" />
</i:EventTrigger>
<i:EventTrigger EventName="MouseLeave">
<i:InvokeCommandAction Command="{Binding CloseLeaveCommand}" />
</i:EventTrigger>
</i:Interaction.Triggers>
</Button>
</Grid>
<StackPanel
Grid.Row="1"
MinWidth="250"
Margin="15,10"
Orientation="Vertical">
<Button
Width="160"
Height="35"
Margin="0,10,0,0"
HorizontalAlignment="Center"
VerticalAlignment="Center"
Command="{Binding ParseSelectedItemCommand}"
Content="{DynamicResource ParseSelectedItem}"
FontSize="12"
Foreground="{DynamicResource BrushText}"
Style="{StaticResource BtnStyle}" />
<Button
Width="160"
Height="35"
Margin="0,30,0,0"
HorizontalAlignment="Center"
VerticalAlignment="Center"
Command="{Binding ParseCurrentSectionCommand}"
Content="{DynamicResource ParseCurrentSection}"
FontSize="12"
Foreground="{DynamicResource BrushText}"
Style="{StaticResource BtnStyle}" />
<Button
Width="160"
Height="35"
Margin="0,30,0,0"
HorizontalAlignment="Center"
VerticalAlignment="Center"
Command="{Binding ParseAllCommand}"
Content="{DynamicResource ParseAll}"
FontSize="12"
Foreground="{DynamicResource BrushText}"
Style="{StaticResource BtnStyle}" />
<CheckBox
Margin="0,30,0,0"
HorizontalAlignment="Center"
VerticalAlignment="Center"
Content="{DynamicResource SetParseDefault}"
Foreground="{DynamicResource BrushTextDark}"
IsChecked="{Binding IsParseDefault, Mode=TwoWay}"
Style="{StaticResource CheckBoxStyle}" />
</StackPanel>
</Grid>
</Border>
</UserControl>

@ -0,0 +1,15 @@
using System.Windows.Controls;
namespace DownKyi.Views.Dialogs
{
/// <summary>
/// Interaction logic for ViewParsingSelector
/// </summary>
public partial class ViewParsingSelector : UserControl
{
public ViewParsingSelector()
{
InitializeComponent();
}
}
}

@ -0,0 +1,10 @@
<UserControl
x:Class="DownKyi.Views.DownloadManager.ViewDownloadFinished"
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>
<TextBlock>已下载</TextBlock>
</Grid>
</UserControl>

@ -0,0 +1,15 @@
using System.Windows.Controls;
namespace DownKyi.Views.DownloadManager
{
/// <summary>
/// Interaction logic for ViewDownloadFinished
/// </summary>
public partial class ViewDownloadFinished : UserControl
{
public ViewDownloadFinished()
{
InitializeComponent();
}
}
}

@ -0,0 +1,10 @@
<UserControl
x:Class="DownKyi.Views.DownloadManager.ViewDownloading"
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>
<TextBlock>正在下载</TextBlock>
</Grid>
</UserControl>

@ -0,0 +1,15 @@
using System.Windows.Controls;
namespace DownKyi.Views.DownloadManager
{
/// <summary>
/// Interaction logic for ViewDownloading
/// </summary>
public partial class ViewDownloading : UserControl
{
public ViewDownloading()
{
InitializeComponent();
}
}
}

@ -0,0 +1,203 @@
<Window
x:Class="DownKyi.Views.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:i="http://schemas.microsoft.com/xaml/behaviors"
xmlns:prism="http://prismlibrary.com/"
Title="{DynamicResource AppName}"
Width="1100"
Height="750"
MinWidth="1100"
MinHeight="750"
prism:ViewModelLocator.AutoWireViewModel="True"
ResizeMode="CanResize"
WindowStartupLocation="CenterScreen"
WindowState="{Binding WinState}">
<WindowChrome.WindowChrome>
<WindowChrome
CaptionHeight="0"
CornerRadius="0"
GlassFrameThickness="0"
NonClientFrameEdges="None"
ResizeBorderThickness="4"
UseAeroCaptionButtons="False" />
</WindowChrome.WindowChrome>
<i:Interaction.Triggers>
<i:EventTrigger EventName="Loaded">
<i:InvokeCommandAction Command="{Binding LoadedCommand}" />
</i:EventTrigger>
</i:Interaction.Triggers>
<Border BorderBrush="{DynamicResource BrushWindowBorder}" BorderThickness="1">
<Border.Style>
<Style TargetType="{x:Type Border}">
<Style.Triggers>
<DataTrigger Binding="{Binding WindowState, RelativeSource={RelativeSource AncestorType=Window}}" Value="Maximized">
<Setter Property="Margin" Value="7,7" />
</DataTrigger>
<DataTrigger Binding="{Binding WindowState, RelativeSource={RelativeSource AncestorType=Window}}" Value="Normal">
<Setter Property="Margin" Value="0" />
</DataTrigger>
</Style.Triggers>
</Style>
</Border.Style>
<Grid Background="{DynamicResource BrushBackground}">
<Grid.RowDefinitions>
<RowDefinition Height="40" />
<RowDefinition />
</Grid.RowDefinitions>
<Grid
Grid.Row="0"
Background="{DynamicResource BrushCaptionBackground}"
KeyboardNavigation.TabNavigation="None">
<i:Interaction.Triggers>
<i:EventTrigger EventName="MouseLeftButtonDown">
<i:InvokeCommandAction Command="{Binding DragMoveCommand}" />
</i:EventTrigger>
</i:Interaction.Triggers>
<Grid.ColumnDefinitions>
<ColumnDefinition />
<ColumnDefinition Width="50" />
<ColumnDefinition Width="50" />
<ColumnDefinition Width="50" />
<ColumnDefinition Width="50" />
</Grid.ColumnDefinitions>
<StackPanel
Grid.Column="0"
Margin="10,0"
Orientation="Horizontal">
<Image
Width="20"
Height="20"
Source="/DownKyi;component/Resources/favicon.ico" />
<TextBlock
Grid.Column="0"
Margin="10,0,0,0"
VerticalAlignment="Center"
FontSize="12"
Foreground="{DynamicResource BrushCaptionForeground}"
Text="{DynamicResource AppName}" />
</StackPanel>
<Button
Grid.Column="1"
Command="{Binding SkinCommand}"
Style="{StaticResource SystemBtnStyle}"
ToolTip="{DynamicResource Skin}"
Visibility="Collapsed">
<Path
Width="{Binding SkinIcon.Width}"
Height="{Binding SkinIcon.Height}"
Data="{Binding SkinIcon.Data}"
Fill="{Binding SkinIcon.Fill}"
Stretch="UniformToFill" />
<i:Interaction.Triggers>
<i:EventTrigger EventName="MouseEnter">
<i:InvokeCommandAction Command="{Binding SkinEnterCommand}" />
</i:EventTrigger>
<i:EventTrigger EventName="MouseLeave">
<i:InvokeCommandAction Command="{Binding SkinLeaveCommand}" />
</i:EventTrigger>
</i:Interaction.Triggers>
</Button>
<Button
Grid.Column="2"
Command="{Binding MinimizeCommand}"
Style="{StaticResource SystemBtnStyle}"
ToolTip="{DynamicResource Minimize}">
<Path
Width="{Binding MinimizeIcon.Width}"
Height="{Binding MinimizeIcon.Height}"
Data="{Binding MinimizeIcon.Data}"
Fill="{Binding MinimizeIcon.Fill}"
Stretch="UniformToFill" />
<i:Interaction.Triggers>
<i:EventTrigger EventName="MouseEnter">
<i:InvokeCommandAction Command="{Binding MinimizeEnterCommand}" />
</i:EventTrigger>
<i:EventTrigger EventName="MouseLeave">
<i:InvokeCommandAction Command="{Binding MinimizeLeaveCommand}" />
</i:EventTrigger>
</i:Interaction.Triggers>
</Button>
<Button Grid.Column="3" Command="{Binding ResizeCommand}">
<Path
Width="{Binding ResizeIcon.Width}"
Height="{Binding ResizeIcon.Height}"
Data="{Binding ResizeIcon.Data}"
Fill="{Binding ResizeIcon.Fill}"
Stretch="UniformToFill" />
<i:Interaction.Triggers>
<i:EventTrigger EventName="MouseEnter">
<i:InvokeCommandAction Command="{Binding ResizeEnterCommand}" />
</i:EventTrigger>
<i:EventTrigger EventName="MouseLeave">
<i:InvokeCommandAction Command="{Binding ResizeLeaveCommand}" />
</i:EventTrigger>
</i:Interaction.Triggers>
<Button.Style>
<Style BasedOn="{StaticResource SystemBtnStyle}" TargetType="{x:Type Button}">
<Style.Triggers>
<DataTrigger Binding="{Binding WindowState, RelativeSource={RelativeSource AncestorType=Window}}" Value="Maximized">
<Setter Property="ToolTip" Value="{DynamicResource Restore}" />
</DataTrigger>
<DataTrigger Binding="{Binding WindowState, RelativeSource={RelativeSource AncestorType=Window}}" Value="Normal">
<Setter Property="ToolTip" Value="{DynamicResource Maximize}" />
</DataTrigger>
</Style.Triggers>
</Style>
</Button.Style>
</Button>
<Button
Grid.Column="4"
Command="{Binding CloseCommand}"
Style="{StaticResource CloseBtnStyle}"
ToolTip="{DynamicResource Close}">
<Path
Width="{Binding CloseIcon.Width}"
Height="{Binding CloseIcon.Height}"
Data="{Binding CloseIcon.Data}"
Fill="{Binding CloseIcon.Fill}"
Stretch="UniformToFill" />
<i:Interaction.Triggers>
<i:EventTrigger EventName="MouseEnter">
<i:InvokeCommandAction Command="{Binding CloseEnterCommand}" />
</i:EventTrigger>
<i:EventTrigger EventName="MouseLeave">
<i:InvokeCommandAction Command="{Binding CloseLeaveCommand}" />
</i:EventTrigger>
</i:Interaction.Triggers>
</Button>
</Grid>
<ContentControl Grid.Row="1" prism:RegionManager.RegionName="ContentRegion" />
<Border
Grid.Row="1"
MinHeight="30"
Margin="0,0,0,20"
HorizontalAlignment="Center"
VerticalAlignment="Bottom"
Background="{DynamicResource BrushBackgroundDark}"
CornerRadius="15"
Visibility="{Binding MessageVisibility}">
<TextBlock
Margin="15,5,15,5"
HorizontalAlignment="Center"
VerticalAlignment="Center"
Background="{x:Null}"
FontSize="12"
Foreground="{DynamicResource BrushForegroundDark}"
Text="{Binding Message}"
TextAlignment="Center" />
</Border>
</Grid>
</Border>
</Window>

@ -0,0 +1,16 @@
using System.Windows;
namespace DownKyi.Views
{
/// <summary>
/// Interaction logic for MainWindow.xaml
/// </summary>
public partial class MainWindow : Window
{
public MainWindow()
{
InitializeComponent();
}
}
}

@ -0,0 +1,408 @@
<UserControl
x:Class="DownKyi.Views.Settings.ViewAbout"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:i="http://schemas.microsoft.com/xaml/behaviors"
xmlns:prism="http://prismlibrary.com/"
prism:ViewModelLocator.AutoWireViewModel="True">
<ScrollViewer HorizontalScrollBarVisibility="Disabled" VerticalScrollBarVisibility="Auto">
<StackPanel Margin="50,0" Orientation="Vertical">
<StackPanel Margin="0,20,0,0" Orientation="Horizontal">
<TextBlock
FontSize="18"
Foreground="{DynamicResource BrushTextDark}"
Text="{DynamicResource About}" />
<TextBlock
Cursor="Hand"
FontSize="18"
Foreground="{DynamicResource BrushPrimary}"
Text="{Binding AppName}"
ToolTip="{DynamicResource GotoHomepage}">
<i:Interaction.Triggers>
<i:EventTrigger EventName="MouseLeftButtonUp">
<i:InvokeCommandAction Command="{Binding AppNameCommand}" />
</i:EventTrigger>
</i:Interaction.Triggers>
</TextBlock>
</StackPanel>
<StackPanel Margin="0,20,0,0" Orientation="Horizontal">
<TextBlock
VerticalAlignment="Center"
FontSize="12"
Foreground="{DynamicResource BrushTextDark}"
Text="{DynamicResource CurrentAppVersion}" />
<TextBlock
VerticalAlignment="Center"
FontSize="12"
Foreground="{DynamicResource BrushTextDark}"
Text="{Binding AppVersion}" />
<Button
Width="75"
Margin="30,0,0,0"
Command="{Binding CheckUpdateCommand}"
Content="{DynamicResource CheckUpdate}"
FontSize="12"
Style="{StaticResource BtnBorderStyle}" />
<Button
Width="75"
Margin="20,0,0,0"
Command="{Binding FeedbackCommand}"
Content="{DynamicResource Feedback}"
FontSize="12"
Style="{StaticResource BtnBorderStyle}" />
</StackPanel>
<CheckBox
Grid.Column="0"
Margin="0,20,0,0"
HorizontalAlignment="Left"
VerticalAlignment="Top"
Command="{Binding ReceiveBetaVersionCommand}"
Content="{DynamicResource ReceiveBetaVersion}"
Foreground="{DynamicResource BrushTextDark}"
IsChecked="{Binding IsReceiveBetaVersion, Mode=TwoWay}"
Style="{StaticResource CheckBoxStyle}" />
<CheckBox
Grid.Column="0"
Margin="0,20,0,0"
HorizontalAlignment="Left"
VerticalAlignment="Top"
Command="{Binding AutoUpdateWhenLaunchCommand}"
Content="{DynamicResource AutoUpdateWhenLaunch}"
Foreground="{DynamicResource BrushTextDark}"
IsChecked="{Binding AutoUpdateWhenLaunch, Mode=TwoWay}"
Style="{StaticResource CheckBoxStyle}" />
<StackPanel Margin="0,20,0,0" Orientation="Vertical">
<TextBlock
Margin="0,0,0,10"
FontSize="14"
FontWeight="Bold"
Foreground="{DynamicResource BrushTextDark}"
Text="{DynamicResource ThirdParty}" />
<Border
Padding="5"
HorizontalAlignment="Left"
BorderBrush="{DynamicResource BrushBorder}"
BorderThickness="1"
CornerRadius="5">
<Grid>
<Grid.Resources>
<Style TargetType="TextBlock">
<Setter Property="VerticalAlignment" Value="Center" />
</Style>
</Grid.Resources>
<Grid.RowDefinitions>
<RowDefinition Height="30" />
<RowDefinition Height="20" />
<RowDefinition Height="20" />
<RowDefinition Height="20" />
<RowDefinition Height="20" />
<RowDefinition Height="20" />
<RowDefinition Height="20" />
<RowDefinition Height="20" />
<RowDefinition Height="20" />
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="200" />
<ColumnDefinition Width="200" />
<ColumnDefinition Width="100" />
<ColumnDefinition Width="100" />
</Grid.ColumnDefinitions>
<TextBlock
Grid.Row="0"
Grid.Column="0"
FontSize="12"
FontWeight="Bold"
Foreground="{DynamicResource BrushTextDark}"
Text="{DynamicResource ThirdPartyName}" />
<TextBlock
Grid.Row="0"
Grid.Column="1"
FontSize="12"
FontWeight="Bold"
Foreground="{DynamicResource BrushTextDark}"
Text="{DynamicResource ThirdPartyAuthor}" />
<TextBlock
Grid.Row="0"
Grid.Column="2"
FontSize="12"
FontWeight="Bold"
Foreground="{DynamicResource BrushTextDark}"
Text="{DynamicResource ThirdPartyVersion}" />
<TextBlock
Grid.Row="0"
Grid.Column="3"
FontSize="12"
FontWeight="Bold"
Foreground="{DynamicResource BrushTextDark}"
Text="{DynamicResource ThirdPartyLicense}" />
<TextBlock
Grid.Row="1"
Grid.Column="0"
FontSize="12"
Foreground="{DynamicResource BrushTextDark}"
Text="Brotli.NET" />
<TextBlock
Grid.Row="1"
Grid.Column="1"
FontSize="12"
Foreground="{DynamicResource BrushTextDark}"
Text="Jinjun Xie" />
<TextBlock
Grid.Row="1"
Grid.Column="2"
FontSize="12"
Foreground="{DynamicResource BrushTextDark}"
Text="2.1.1" />
<TextBlock
Grid.Row="1"
Grid.Column="3"
FontSize="12">
<Hyperlink Command="{Binding BrotliLicenseCommand}">
<TextBlock Text="MIT" />
</Hyperlink>
</TextBlock>
<TextBlock
Grid.Row="2"
Grid.Column="0"
FontSize="12"
Foreground="{DynamicResource BrushTextDark}"
Text="Google.Protobuf" />
<TextBlock
Grid.Row="2"
Grid.Column="1"
FontSize="12"
Foreground="{DynamicResource BrushTextDark}"
Text="Google Inc." />
<TextBlock
Grid.Row="2"
Grid.Column="2"
FontSize="12"
Foreground="{DynamicResource BrushTextDark}"
Text="3.17.3" />
<TextBlock
Grid.Row="2"
Grid.Column="3"
FontSize="12">
<Hyperlink Command="{Binding ProtobufLicenseCommand}">
<TextBlock Text="LICENSE" />
</Hyperlink>
</TextBlock>
<TextBlock
Grid.Row="3"
Grid.Column="0"
FontSize="12"
Foreground="{DynamicResource BrushTextDark}"
Text="Newtonsoft.Json" />
<TextBlock
Grid.Row="3"
Grid.Column="1"
FontSize="12"
Foreground="{DynamicResource BrushTextDark}"
Text="James Newton-King" />
<TextBlock
Grid.Row="3"
Grid.Column="2"
FontSize="12"
Foreground="{DynamicResource BrushTextDark}"
Text="13.0.1" />
<TextBlock
Grid.Row="3"
Grid.Column="3"
FontSize="12">
<Hyperlink Command="{Binding NewtonsoftLicenseCommand}">
<TextBlock Text="MIT" />
</Hyperlink>
</TextBlock>
<TextBlock
Grid.Row="4"
Grid.Column="0"
FontSize="12"
Foreground="{DynamicResource BrushTextDark}"
Text="Prism.DryIoc" />
<TextBlock
Grid.Row="4"
Grid.Column="1"
FontSize="12"
Foreground="{DynamicResource BrushTextDark}"
Text="Brian Lagunas,Dan Siegel" />
<TextBlock
Grid.Row="4"
Grid.Column="2"
FontSize="12"
Foreground="{DynamicResource BrushTextDark}"
Text="8.1.97" />
<TextBlock
Grid.Row="4"
Grid.Column="3"
FontSize="12">
<Hyperlink Command="{Binding PrismLicenseCommand}">
<TextBlock Text="LICENSE" />
</Hyperlink>
</TextBlock>
<TextBlock
Grid.Row="5"
Grid.Column="0"
FontSize="12"
Foreground="{DynamicResource BrushTextDark}"
Text="QRCoder" />
<TextBlock
Grid.Row="5"
Grid.Column="1"
FontSize="12"
Foreground="{DynamicResource BrushTextDark}"
Text="Raffael Herrmann" />
<TextBlock
Grid.Row="5"
Grid.Column="2"
FontSize="12"
Foreground="{DynamicResource BrushTextDark}"
Text="1.4.1" />
<TextBlock
Grid.Row="5"
Grid.Column="3"
FontSize="12">
<Hyperlink Command="{Binding QRCoderLicenseCommand}">
<TextBlock Text="MIT" />
</Hyperlink>
</TextBlock>
<TextBlock
Grid.Row="6"
Grid.Column="0"
FontSize="12"
Foreground="{DynamicResource BrushTextDark}"
Text="System.Data.SQLite.Core" />
<TextBlock
Grid.Row="6"
Grid.Column="1"
FontSize="12"
Foreground="{DynamicResource BrushTextDark}"
Text="SQLite Development Team" />
<TextBlock
Grid.Row="6"
Grid.Column="2"
FontSize="12"
Foreground="{DynamicResource BrushTextDark}"
Text="1.0.112.2" />
<TextBlock
Grid.Row="6"
Grid.Column="3"
FontSize="12">
<Hyperlink Command="{Binding SQLiteLicenseCommand}">
<TextBlock Text="LICENSE" />
</Hyperlink>
</TextBlock>
<TextBlock
Grid.Row="7"
Grid.Column="0"
FontSize="12"
Foreground="{DynamicResource BrushTextDark}"
Text="Aria2c" />
<TextBlock
Grid.Row="7"
Grid.Column="1"
FontSize="12"
Foreground="{DynamicResource BrushTextDark}"
Text="Aria2" />
<TextBlock
Grid.Row="7"
Grid.Column="2"
FontSize="12"
Foreground="{DynamicResource BrushTextDark}"
Text="1.35.0" />
<TextBlock
Grid.Row="7"
Grid.Column="3"
FontSize="12">
<Hyperlink Command="{Binding AriaLicenseCommand}">
<TextBlock Text="GPL 2.0" />
</Hyperlink>
</TextBlock>
<TextBlock
Grid.Row="8"
Grid.Column="0"
FontSize="12"
Foreground="{DynamicResource BrushTextDark}"
Text="FFmpeg" />
<TextBlock
Grid.Row="8"
Grid.Column="1"
FontSize="12"
Foreground="{DynamicResource BrushTextDark}"
Text="FFmpeg" />
<TextBlock
Grid.Row="8"
Grid.Column="2"
FontSize="12"
Foreground="{DynamicResource BrushTextDark}"
Text="4.3.1" />
<TextBlock
Grid.Row="8"
Grid.Column="3"
FontSize="12">
<Hyperlink Command="{Binding FFmpegLicenseCommand}">
<TextBlock Text="GPL 3.0" />
</Hyperlink>
</TextBlock>
</Grid>
</Border>
</StackPanel>
<!-- 免责申明 -->
<StackPanel Margin="0,20,0,0" Orientation="Vertical">
<TextBlock
Margin="0,0,0,10"
FontSize="14"
FontWeight="Bold"
Foreground="{DynamicResource BrushTextDark}"
Text="{DynamicResource Disclaimer}" />
<TextBlock
FontSize="12"
Foreground="{DynamicResource BrushTextDark}"
Text="{DynamicResource Disclaimer1}"
TextWrapping="WrapWithOverflow" />
<TextBlock
FontSize="12"
Foreground="{DynamicResource BrushTextDark}"
Text="{DynamicResource Disclaimer2}"
TextWrapping="WrapWithOverflow" />
<TextBlock
FontSize="12"
Foreground="{DynamicResource BrushTextDark}"
Text="{DynamicResource Disclaimer3}"
TextWrapping="WrapWithOverflow" />
<TextBlock
FontSize="12"
Foreground="{DynamicResource BrushTextDark}"
Text="{DynamicResource Disclaimer4}"
TextWrapping="WrapWithOverflow" />
<TextBlock
FontSize="12"
Foreground="{DynamicResource BrushTextDark}"
Text="{DynamicResource Disclaimer5}"
TextWrapping="WrapWithOverflow" />
<TextBlock
FontSize="12"
Foreground="{DynamicResource BrushTextDark}"
Text="{DynamicResource Disclaimer6}"
TextWrapping="WrapWithOverflow" />
</StackPanel>
</StackPanel>
</ScrollViewer>
</UserControl>

@ -0,0 +1,15 @@
using System.Windows.Controls;
namespace DownKyi.Views.Settings
{
/// <summary>
/// Interaction logic for ViewAbout
/// </summary>
public partial class ViewAbout : UserControl
{
public ViewAbout()
{
InitializeComponent();
}
}
}

Some files were not shown because too many files have changed in this diff Show More

Loading…
Cancel
Save