新建
This commit is contained in:
parent
a6058b84bc
commit
0da096d765
28
BaiduYunSync.sln
Normal file
28
BaiduYunSync.sln
Normal file
@ -0,0 +1,28 @@
|
||||
|
||||
Microsoft Visual Studio Solution File, Format Version 12.00
|
||||
# Visual Studio 2013
|
||||
VisualStudioVersion = 12.0.21005.1
|
||||
MinimumVisualStudioVersion = 10.0.40219.1
|
||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "BaiduYunSync", "BaiduYunSync\BaiduYunSync.csproj", "{F063180E-E354-4DB4-96F8-154D1D949240}"
|
||||
EndProject
|
||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "NetDisk", "NetDisk\NetDisk.csproj", "{74ECA1BF-6508-417D-BC57-DB00DAECA618}"
|
||||
EndProject
|
||||
Global
|
||||
GlobalSection(SolutionConfigurationPlatforms) = preSolution
|
||||
Debug|Any CPU = Debug|Any CPU
|
||||
Release|Any CPU = Release|Any CPU
|
||||
EndGlobalSection
|
||||
GlobalSection(ProjectConfigurationPlatforms) = postSolution
|
||||
{F063180E-E354-4DB4-96F8-154D1D949240}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{F063180E-E354-4DB4-96F8-154D1D949240}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{F063180E-E354-4DB4-96F8-154D1D949240}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{F063180E-E354-4DB4-96F8-154D1D949240}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
{74ECA1BF-6508-417D-BC57-DB00DAECA618}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{74ECA1BF-6508-417D-BC57-DB00DAECA618}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{74ECA1BF-6508-417D-BC57-DB00DAECA618}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{74ECA1BF-6508-417D-BC57-DB00DAECA618}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
EndGlobalSection
|
||||
GlobalSection(SolutionProperties) = preSolution
|
||||
HideSolutionNode = FALSE
|
||||
EndGlobalSection
|
||||
EndGlobal
|
134
BaiduYunSync/BaiduYunSync.csproj
Normal file
134
BaiduYunSync/BaiduYunSync.csproj
Normal file
@ -0,0 +1,134 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<Project ToolsVersion="12.0" DefaultTargets="Build" 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>{F063180E-E354-4DB4-96F8-154D1D949240}</ProjectGuid>
|
||||
<OutputType>WinExe</OutputType>
|
||||
<AppDesignerFolder>Properties</AppDesignerFolder>
|
||||
<RootNamespace>BaiduYunSync</RootNamespace>
|
||||
<AssemblyName>BaiduYunSync</AssemblyName>
|
||||
<TargetFrameworkVersion>v4.0</TargetFrameworkVersion>
|
||||
<FileAlignment>512</FileAlignment>
|
||||
</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>
|
||||
<ItemGroup>
|
||||
<Reference Include="LiteDB, Version=2.0.4.0, Culture=neutral, PublicKeyToken=4ee40123013c9f27, processorArchitecture=MSIL">
|
||||
<HintPath>..\packages\LiteDB.2.0.4\lib\net35\LiteDB.dll</HintPath>
|
||||
<Private>True</Private>
|
||||
</Reference>
|
||||
<Reference Include="log4net, Version=2.0.7.0, Culture=neutral, PublicKeyToken=669e0ddf0bb1aa2a, processorArchitecture=MSIL">
|
||||
<HintPath>..\packages\log4net.2.0.7\lib\net40-full\log4net.dll</HintPath>
|
||||
<Private>True</Private>
|
||||
</Reference>
|
||||
<Reference Include="System" />
|
||||
<Reference Include="System.Core" />
|
||||
<Reference Include="System.Xml.Linq" />
|
||||
<Reference Include="System.Data.DataSetExtensions" />
|
||||
<Reference Include="Microsoft.CSharp" />
|
||||
<Reference Include="System.Data" />
|
||||
<Reference Include="System.Deployment" />
|
||||
<Reference Include="System.Drawing" />
|
||||
<Reference Include="System.Windows.Forms" />
|
||||
<Reference Include="System.Xml" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<Compile Include="Encrypt3DS.cs" />
|
||||
<Compile Include="frmLogin.cs">
|
||||
<SubType>Form</SubType>
|
||||
</Compile>
|
||||
<Compile Include="frmLogin.Designer.cs">
|
||||
<DependentUpon>frmLogin.cs</DependentUpon>
|
||||
</Compile>
|
||||
<Compile Include="frmMain.cs">
|
||||
<SubType>Form</SubType>
|
||||
</Compile>
|
||||
<Compile Include="frmMain.Designer.cs">
|
||||
<DependentUpon>frmMain.cs</DependentUpon>
|
||||
</Compile>
|
||||
<Compile Include="frmReadLog.cs">
|
||||
<SubType>Form</SubType>
|
||||
</Compile>
|
||||
<Compile Include="frmReadLog.Designer.cs">
|
||||
<DependentUpon>frmReadLog.cs</DependentUpon>
|
||||
</Compile>
|
||||
<Compile Include="frmUploadList.cs">
|
||||
<SubType>Form</SubType>
|
||||
</Compile>
|
||||
<Compile Include="frmUploadList.Designer.cs">
|
||||
<DependentUpon>frmUploadList.cs</DependentUpon>
|
||||
</Compile>
|
||||
<Compile Include="LiteDbHelper.cs" />
|
||||
<Compile Include="LogSettings.cs" />
|
||||
<Compile Include="Program.cs" />
|
||||
<Compile Include="Properties\AssemblyInfo.cs" />
|
||||
<Compile Include="Sync.cs" />
|
||||
<Compile Include="SyncItemsDao.cs" />
|
||||
<Compile Include="UpdateInfoDao.cs" />
|
||||
<Compile Include="UserInfoDao.cs" />
|
||||
<EmbeddedResource Include="frmLogin.resx">
|
||||
<DependentUpon>frmLogin.cs</DependentUpon>
|
||||
</EmbeddedResource>
|
||||
<EmbeddedResource Include="frmMain.resx">
|
||||
<DependentUpon>frmMain.cs</DependentUpon>
|
||||
</EmbeddedResource>
|
||||
<EmbeddedResource Include="frmReadLog.resx">
|
||||
<DependentUpon>frmReadLog.cs</DependentUpon>
|
||||
</EmbeddedResource>
|
||||
<EmbeddedResource Include="frmUploadList.resx">
|
||||
<DependentUpon>frmUploadList.cs</DependentUpon>
|
||||
</EmbeddedResource>
|
||||
<EmbeddedResource Include="Properties\Resources.resx">
|
||||
<Generator>ResXFileCodeGenerator</Generator>
|
||||
<LastGenOutput>Resources.Designer.cs</LastGenOutput>
|
||||
<SubType>Designer</SubType>
|
||||
</EmbeddedResource>
|
||||
<Compile Include="Properties\Resources.Designer.cs">
|
||||
<AutoGen>True</AutoGen>
|
||||
<DependentUpon>Resources.resx</DependentUpon>
|
||||
</Compile>
|
||||
<None Include="packages.config" />
|
||||
<None Include="Properties\Settings.settings">
|
||||
<Generator>SettingsSingleFileGenerator</Generator>
|
||||
<LastGenOutput>Settings.Designer.cs</LastGenOutput>
|
||||
</None>
|
||||
<Compile Include="Properties\Settings.Designer.cs">
|
||||
<AutoGen>True</AutoGen>
|
||||
<DependentUpon>Settings.settings</DependentUpon>
|
||||
<DesignTimeSharedInput>True</DesignTimeSharedInput>
|
||||
</Compile>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="..\NetDisk\NetDisk.csproj">
|
||||
<Project>{74ECA1BF-6508-417D-BC57-DB00DAECA618}</Project>
|
||||
<Name>NetDisk</Name>
|
||||
</ProjectReference>
|
||||
</ItemGroup>
|
||||
<Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
|
||||
<!-- To modify your build process, add your task inside one of the targets below and uncomment it.
|
||||
Other similar extension points exist, see Microsoft.Common.targets.
|
||||
<Target Name="BeforeBuild">
|
||||
</Target>
|
||||
<Target Name="AfterBuild">
|
||||
</Target>
|
||||
-->
|
||||
</Project>
|
75
BaiduYunSync/Encrypt3DS.cs
Normal file
75
BaiduYunSync/Encrypt3DS.cs
Normal file
@ -0,0 +1,75 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Security.Cryptography;
|
||||
using System.Text;
|
||||
|
||||
namespace BaiduYunSync
|
||||
{
|
||||
class Encrypt3DS
|
||||
{
|
||||
//密钥
|
||||
private const string sKey = "qJzGEh6hESZDVJeCnFPGuxzaiB7NLQM3";
|
||||
//矢量,矢量可以为空
|
||||
private const string sIV = "qcDY6X+aPLw=";
|
||||
//构造一个对称算法
|
||||
private SymmetricAlgorithm mCSP = new TripleDESCryptoServiceProvider();
|
||||
|
||||
#region public string EncryptString(string Value)
|
||||
/// <summary>
|
||||
/// 加密字符串
|
||||
/// </summary>
|
||||
/// <param name="Value">输入的字符串</param>
|
||||
/// <returns>加密后的字符串</returns>
|
||||
public string EncryptString(string Value)
|
||||
{
|
||||
ICryptoTransform ct;
|
||||
MemoryStream ms;
|
||||
CryptoStream cs;
|
||||
byte[] byt;
|
||||
mCSP.Key = Convert.FromBase64String(sKey);
|
||||
mCSP.IV = Convert.FromBase64String(sIV);
|
||||
//指定加密的运算模式
|
||||
mCSP.Mode = System.Security.Cryptography.CipherMode.ECB;
|
||||
//获取或设置加密算法的填充模式
|
||||
mCSP.Padding = System.Security.Cryptography.PaddingMode.PKCS7;
|
||||
ct = mCSP.CreateEncryptor(mCSP.Key, mCSP.IV);
|
||||
byt = Encoding.UTF8.GetBytes(Value);
|
||||
ms = new MemoryStream();
|
||||
cs = new CryptoStream(ms, ct, CryptoStreamMode.Write);
|
||||
cs.Write(byt, 0, byt.Length);
|
||||
cs.FlushFinalBlock();
|
||||
cs.Close();
|
||||
return Convert.ToBase64String(ms.ToArray());
|
||||
}
|
||||
#endregion
|
||||
#region public string DecryptString(string Value)
|
||||
/// <summary>
|
||||
/// 解密字符串
|
||||
/// </summary>
|
||||
/// <param name="Value">加过密的字符串</param>
|
||||
/// <returns>解密后的字符串</returns>
|
||||
public string DecryptString(string Value)
|
||||
{
|
||||
ICryptoTransform ct;
|
||||
MemoryStream ms;
|
||||
CryptoStream cs;
|
||||
byte[] byt;
|
||||
mCSP.Key = Convert.FromBase64String(sKey);
|
||||
mCSP.IV = Convert.FromBase64String(sIV);
|
||||
mCSP.Mode = System.Security.Cryptography.CipherMode.ECB;
|
||||
mCSP.Padding = System.Security.Cryptography.PaddingMode.PKCS7;
|
||||
ct = mCSP.CreateDecryptor(mCSP.Key, mCSP.IV);
|
||||
byt = Convert.FromBase64String(Value);
|
||||
ms = new MemoryStream();
|
||||
cs = new CryptoStream(ms, ct, CryptoStreamMode.Write);
|
||||
cs.Write(byt, 0, byt.Length);
|
||||
cs.FlushFinalBlock();
|
||||
cs.Close();
|
||||
return Encoding.UTF8.GetString(ms.ToArray());
|
||||
}
|
||||
#endregion
|
||||
|
||||
}
|
||||
}
|
210
BaiduYunSync/LiteDbHelper.cs
Normal file
210
BaiduYunSync/LiteDbHelper.cs
Normal file
@ -0,0 +1,210 @@
|
||||
using LiteDB;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
|
||||
namespace BaiduYunSync
|
||||
{
|
||||
class LiteDbHelper
|
||||
{
|
||||
|
||||
private static string dbUrl = "db.db";
|
||||
|
||||
/// <summary>
|
||||
/// 本地保存更新信息,防止频繁读写文件
|
||||
/// </summary>
|
||||
private static List<UpdateInfoDao> updateInfoList;
|
||||
|
||||
/// <summary>
|
||||
/// 同步文件锁
|
||||
/// </summary>
|
||||
private static object updateInfoLocker = new object();
|
||||
|
||||
static LiteDbHelper()
|
||||
{
|
||||
Init();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 初始化数据库相关内容
|
||||
/// </summary>
|
||||
public static void Init()
|
||||
{
|
||||
if (updateInfoList == null)
|
||||
{
|
||||
using (var db = new LiteDatabase(dbUrl))
|
||||
{
|
||||
var col = db.GetCollection<UpdateInfoDao>("updateinfo");
|
||||
var list = col.FindAll();
|
||||
updateInfoList = (list == null ? new List<UpdateInfoDao>() : list.ToList());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private static UserInfoDao userInfo;
|
||||
|
||||
/// <summary>
|
||||
/// 获取或设置用户信息
|
||||
/// </summary>
|
||||
public static UserInfoDao UserInfo
|
||||
{
|
||||
get
|
||||
{
|
||||
if (userInfo == null)
|
||||
{
|
||||
using (var db = new LiteDatabase(dbUrl))
|
||||
{
|
||||
var col = db.GetCollection<UserInfoDao>("userinfo");
|
||||
userInfo = col.FindOne(Query.All());
|
||||
if (userInfo == null)
|
||||
{
|
||||
userInfo = new UserInfoDao();
|
||||
}
|
||||
}
|
||||
}
|
||||
return userInfo;
|
||||
}
|
||||
set
|
||||
{
|
||||
using (var db = new LiteDatabase(dbUrl))
|
||||
{
|
||||
var col = db.GetCollection<UserInfoDao>("userinfo");
|
||||
if (value.Id == 0)
|
||||
{
|
||||
col.Insert(value);
|
||||
}
|
||||
else
|
||||
{
|
||||
col.Update(value);
|
||||
}
|
||||
userInfo = value;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 插入或更新需要同步的文件夹
|
||||
/// </summary>
|
||||
/// <param name="dao"></param>
|
||||
public static void UpdateSyncItem(SyncItemsDao dao)
|
||||
{
|
||||
using (var db = new LiteDatabase(dbUrl))
|
||||
{
|
||||
var col = db.GetCollection<SyncItemsDao>("syncitem");
|
||||
if (dao.Id == 0)
|
||||
{
|
||||
col.Insert(dao);
|
||||
}
|
||||
else
|
||||
{
|
||||
col.Update(dao);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 获取需要同步的文件夹列表
|
||||
/// </summary>
|
||||
/// <returns>同步文件夹信息</returns>
|
||||
public static List<SyncItemsDao> GetAllSyncItems()
|
||||
{
|
||||
using (var db = new LiteDatabase(dbUrl))
|
||||
{
|
||||
var col = db.GetCollection<SyncItemsDao>("syncitem");
|
||||
return col.FindAll().ToList();
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 删除同步文件夹
|
||||
/// </summary>
|
||||
/// <param name="dao"></param>
|
||||
public static void DeleteSyncItem(SyncItemsDao dao)
|
||||
{
|
||||
using (var db = new LiteDatabase(dbUrl))
|
||||
{
|
||||
var col = db.GetCollection<SyncItemsDao>("syncitem");
|
||||
col.Delete(dao.Id);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 获取所有的更新信息
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
public static UpdateInfoDao[] GetAllUpdateInfos()
|
||||
{
|
||||
lock (updateInfoLocker)
|
||||
{
|
||||
return updateInfoList.ToArray();
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 插入新的更新信息
|
||||
/// </summary>
|
||||
/// <param name="dao"></param>
|
||||
public static void InsertUpdateInfo(UpdateInfoDao dao)
|
||||
{
|
||||
using (var db = new LiteDatabase(dbUrl))
|
||||
{
|
||||
var col = db.GetCollection<UpdateInfoDao>("updateinfo");
|
||||
col.Insert(dao);
|
||||
}
|
||||
lock (updateInfoLocker)
|
||||
updateInfoList.Add(dao);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 删除更新信息
|
||||
/// </summary>
|
||||
/// <param name="dao"></param>
|
||||
public static void DeleteUpdateInfo(UpdateInfoDao dao)
|
||||
{
|
||||
using (var db = new LiteDatabase(dbUrl))
|
||||
{
|
||||
var col = db.GetCollection<UpdateInfoDao>("updateinfo");
|
||||
col.Delete(dao.Id);
|
||||
}
|
||||
lock (updateInfoLocker)
|
||||
updateInfoList.Remove(dao);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 获取需更新数量
|
||||
/// </summary>
|
||||
/// <returns>数量</returns>
|
||||
public static int GetUpdateInfoCount()
|
||||
{
|
||||
lock (updateInfoLocker)
|
||||
return updateInfoList.Count();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 判断文件是否已存在
|
||||
/// </summary>
|
||||
/// <param name="path">文件全路径</param>
|
||||
/// <returns></returns>
|
||||
public static bool ContainsPath(string path)
|
||||
{
|
||||
lock (updateInfoLocker)
|
||||
return updateInfoList.Select(x => x.Path).Contains(path);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 根据路径获取对应的更新信息
|
||||
/// </summary>
|
||||
/// <param name="path"></param>
|
||||
/// <returns></returns>
|
||||
public static UpdateInfoDao GetUpdateInfoFormPath(string path)
|
||||
{
|
||||
if (!ContainsPath(path))
|
||||
{
|
||||
return null;
|
||||
}
|
||||
lock (updateInfoLocker)
|
||||
return updateInfoList.Where(x => x.Path == path).First();
|
||||
}
|
||||
}
|
||||
}
|
49
BaiduYunSync/LogSettings.cs
Normal file
49
BaiduYunSync/LogSettings.cs
Normal file
@ -0,0 +1,49 @@
|
||||
using log4net;
|
||||
using log4net.Appender;
|
||||
using log4net.Layout;
|
||||
using log4net.Repository.Hierarchy;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
|
||||
namespace BaiduYunSync
|
||||
{
|
||||
class LogSettings
|
||||
{
|
||||
static LogSettings()
|
||||
{
|
||||
string LOG_PATTERN = "%d [%t] %-5p %c [%x] - %m%n";
|
||||
string LOG_FILE_PATH = "log/job.log";
|
||||
Hierarchy hierarchy = (Hierarchy)LogManager.GetRepository();
|
||||
hierarchy.Name = "stdAdapter";
|
||||
TraceAppender tracer = new TraceAppender();
|
||||
|
||||
PatternLayout patternLayout = new PatternLayout();
|
||||
patternLayout.ConversionPattern = LOG_PATTERN;
|
||||
patternLayout.ActivateOptions();
|
||||
|
||||
tracer.Layout = patternLayout;
|
||||
tracer.ActivateOptions();
|
||||
hierarchy.Root.AddAppender(tracer);
|
||||
|
||||
RollingFileAppender roller = new RollingFileAppender();
|
||||
roller.Layout = patternLayout;
|
||||
roller.AppendToFile = true;
|
||||
roller.RollingStyle = RollingFileAppender.RollingMode.Size;
|
||||
roller.MaxSizeRollBackups = 10;
|
||||
roller.MaximumFileSize = "1MB";
|
||||
roller.StaticLogFileName = true;
|
||||
roller.File = LOG_FILE_PATH;
|
||||
roller.ActivateOptions();
|
||||
hierarchy.Root.AddAppender(roller);
|
||||
hierarchy.Root.Level = log4net.Core.Level.All;
|
||||
hierarchy.Configured = true;
|
||||
}
|
||||
|
||||
public static void StdInfo(string msg)
|
||||
{
|
||||
LogManager.GetLogger("stdAdapter").Info(msg);
|
||||
}
|
||||
}
|
||||
}
|
21
BaiduYunSync/Program.cs
Normal file
21
BaiduYunSync/Program.cs
Normal file
@ -0,0 +1,21 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Windows.Forms;
|
||||
|
||||
namespace BaiduYunSync
|
||||
{
|
||||
static class Program
|
||||
{
|
||||
/// <summary>
|
||||
/// 应用程序的主入口点。
|
||||
/// </summary>
|
||||
[STAThread]
|
||||
static void Main()
|
||||
{
|
||||
Application.EnableVisualStyles();
|
||||
Application.SetCompatibleTextRenderingDefault(false);
|
||||
Application.Run(new frmMain());
|
||||
}
|
||||
}
|
||||
}
|
36
BaiduYunSync/Properties/AssemblyInfo.cs
Normal file
36
BaiduYunSync/Properties/AssemblyInfo.cs
Normal file
@ -0,0 +1,36 @@
|
||||
using System.Reflection;
|
||||
using System.Runtime.CompilerServices;
|
||||
using System.Runtime.InteropServices;
|
||||
|
||||
// 有关程序集的常规信息通过以下
|
||||
// 特性集控制。更改这些特性值可修改
|
||||
// 与程序集关联的信息。
|
||||
[assembly: AssemblyTitle("BaiduYunSync")]
|
||||
[assembly: AssemblyDescription("")]
|
||||
[assembly: AssemblyConfiguration("")]
|
||||
[assembly: AssemblyCompany("")]
|
||||
[assembly: AssemblyProduct("BaiduYunSync")]
|
||||
[assembly: AssemblyCopyright("Copyright © 2017")]
|
||||
[assembly: AssemblyTrademark("")]
|
||||
[assembly: AssemblyCulture("")]
|
||||
|
||||
// 将 ComVisible 设置为 false 使此程序集中的类型
|
||||
// 对 COM 组件不可见。 如果需要从 COM 访问此程序集中的类型,
|
||||
// 则将该类型上的 ComVisible 特性设置为 true。
|
||||
[assembly: ComVisible(false)]
|
||||
|
||||
// 如果此项目向 COM 公开,则下列 GUID 用于类型库的 ID
|
||||
[assembly: Guid("4e80c253-7d19-44cc-a24b-8f92154fbc6e")]
|
||||
|
||||
// 程序集的版本信息由下面四个值组成:
|
||||
//
|
||||
// 主版本
|
||||
// 次版本
|
||||
// 生成号
|
||||
// 修订号
|
||||
//
|
||||
// 可以指定所有这些值,也可以使用“生成号”和“修订号”的默认值,
|
||||
// 方法是按如下所示使用“*”:
|
||||
// [assembly: AssemblyVersion("1.0.*")]
|
||||
[assembly: AssemblyVersion("1.0.0.0")]
|
||||
[assembly: AssemblyFileVersion("1.0.0.0")]
|
71
BaiduYunSync/Properties/Resources.Designer.cs
generated
Normal file
71
BaiduYunSync/Properties/Resources.Designer.cs
generated
Normal file
@ -0,0 +1,71 @@
|
||||
//------------------------------------------------------------------------------
|
||||
// <auto-generated>
|
||||
// 此代码由工具生成。
|
||||
// 运行时版本: 4.0.30319.42000
|
||||
//
|
||||
// 对此文件的更改可能会导致不正确的行为,并且如果
|
||||
// 重新生成代码,这些更改将丢失。
|
||||
// </auto-generated>
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
namespace BaiduYunSync.Properties
|
||||
{
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// 一个强类型的资源类,用于查找本地化的字符串等。
|
||||
/// </summary>
|
||||
// 此类是由 StronglyTypedResourceBuilder
|
||||
// 类通过类似于 ResGen 或 Visual Studio 的工具自动生成的。
|
||||
// 若要添加或移除成员,请编辑 .ResX 文件,然后重新运行 ResGen
|
||||
// (以 /str 作为命令选项),或重新生成 VS 项目。
|
||||
[global::System.CodeDom.Compiler.GeneratedCodeAttribute("System.Resources.Tools.StronglyTypedResourceBuilder", "4.0.0.0")]
|
||||
[global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
|
||||
[global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()]
|
||||
internal class Resources
|
||||
{
|
||||
|
||||
private static global::System.Resources.ResourceManager resourceMan;
|
||||
|
||||
private static global::System.Globalization.CultureInfo resourceCulture;
|
||||
|
||||
[global::System.Diagnostics.CodeAnalysis.SuppressMessageAttribute("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")]
|
||||
internal Resources()
|
||||
{
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 返回此类使用的、缓存的 ResourceManager 实例。
|
||||
/// </summary>
|
||||
[global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)]
|
||||
internal static global::System.Resources.ResourceManager ResourceManager
|
||||
{
|
||||
get
|
||||
{
|
||||
if ((resourceMan == null))
|
||||
{
|
||||
global::System.Resources.ResourceManager temp = new global::System.Resources.ResourceManager("BaiduYunSync.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;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
117
BaiduYunSync/Properties/Resources.resx
Normal file
117
BaiduYunSync/Properties/Resources.resx
Normal file
@ -0,0 +1,117 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<root>
|
||||
<!--
|
||||
Microsoft ResX Schema
|
||||
|
||||
Version 2.0
|
||||
|
||||
The primary goals of this format is to allow a simple XML format
|
||||
that is mostly human readable. The generation and parsing of the
|
||||
various data types are done through the TypeConverter classes
|
||||
associated with the data types.
|
||||
|
||||
Example:
|
||||
|
||||
... ado.net/XML headers & schema ...
|
||||
<resheader name="resmimetype">text/microsoft-resx</resheader>
|
||||
<resheader name="version">2.0</resheader>
|
||||
<resheader name="reader">System.Resources.ResXResourceReader, System.Windows.Forms, ...</resheader>
|
||||
<resheader name="writer">System.Resources.ResXResourceWriter, System.Windows.Forms, ...</resheader>
|
||||
<data name="Name1"><value>this is my long string</value><comment>this is a comment</comment></data>
|
||||
<data name="Color1" type="System.Drawing.Color, System.Drawing">Blue</data>
|
||||
<data name="Bitmap1" mimetype="application/x-microsoft.net.object.binary.base64">
|
||||
<value>[base64 mime encoded serialized .NET Framework object]</value>
|
||||
</data>
|
||||
<data name="Icon1" type="System.Drawing.Icon, System.Drawing" mimetype="application/x-microsoft.net.object.bytearray.base64">
|
||||
<value>[base64 mime encoded string representing a byte array form of the .NET Framework object]</value>
|
||||
<comment>This is a comment</comment>
|
||||
</data>
|
||||
|
||||
There are any number of "resheader" rows that contain simple
|
||||
name/value pairs.
|
||||
|
||||
Each data row contains a name, and value. The row also contains a
|
||||
type or mimetype. Type corresponds to a .NET class that support
|
||||
text/value conversion through the TypeConverter architecture.
|
||||
Classes that don't support this are serialized and stored with the
|
||||
mimetype set.
|
||||
|
||||
The mimetype is used for serialized objects, and tells the
|
||||
ResXResourceReader how to depersist the object. This is currently not
|
||||
extensible. For a given mimetype the value must be set accordingly:
|
||||
|
||||
Note - application/x-microsoft.net.object.binary.base64 is the format
|
||||
that the ResXResourceWriter will generate, however the reader can
|
||||
read any of the formats listed below.
|
||||
|
||||
mimetype: application/x-microsoft.net.object.binary.base64
|
||||
value : The object must be serialized with
|
||||
: System.Serialization.Formatters.Binary.BinaryFormatter
|
||||
: and then encoded with base64 encoding.
|
||||
|
||||
mimetype: application/x-microsoft.net.object.soap.base64
|
||||
value : The object must be serialized with
|
||||
: System.Runtime.Serialization.Formatters.Soap.SoapFormatter
|
||||
: and then encoded with base64 encoding.
|
||||
|
||||
mimetype: application/x-microsoft.net.object.bytearray.base64
|
||||
value : The object must be serialized into a byte array
|
||||
: using a System.ComponentModel.TypeConverter
|
||||
: and then encoded with base64 encoding.
|
||||
-->
|
||||
<xsd:schema id="root" xmlns="" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:msdata="urn:schemas-microsoft-com:xml-msdata">
|
||||
<xsd:element name="root" msdata:IsDataSet="true">
|
||||
<xsd:complexType>
|
||||
<xsd:choice maxOccurs="unbounded">
|
||||
<xsd:element name="metadata">
|
||||
<xsd:complexType>
|
||||
<xsd:sequence>
|
||||
<xsd:element name="value" type="xsd:string" minOccurs="0" />
|
||||
</xsd:sequence>
|
||||
<xsd:attribute name="name" type="xsd:string" />
|
||||
<xsd:attribute name="type" type="xsd:string" />
|
||||
<xsd:attribute name="mimetype" type="xsd:string" />
|
||||
</xsd:complexType>
|
||||
</xsd:element>
|
||||
<xsd:element name="assembly">
|
||||
<xsd:complexType>
|
||||
<xsd:attribute name="alias" type="xsd:string" />
|
||||
<xsd:attribute name="name" type="xsd:string" />
|
||||
</xsd:complexType>
|
||||
</xsd:element>
|
||||
<xsd:element name="data">
|
||||
<xsd:complexType>
|
||||
<xsd:sequence>
|
||||
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
|
||||
<xsd:element name="comment" type="xsd:string" minOccurs="0" msdata:Ordinal="2" />
|
||||
</xsd:sequence>
|
||||
<xsd:attribute name="name" type="xsd:string" msdata:Ordinal="1" />
|
||||
<xsd:attribute name="type" type="xsd:string" msdata:Ordinal="3" />
|
||||
<xsd:attribute name="mimetype" type="xsd:string" msdata:Ordinal="4" />
|
||||
</xsd:complexType>
|
||||
</xsd:element>
|
||||
<xsd:element name="resheader">
|
||||
<xsd:complexType>
|
||||
<xsd:sequence>
|
||||
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
|
||||
</xsd:sequence>
|
||||
<xsd:attribute name="name" type="xsd:string" use="required" />
|
||||
</xsd:complexType>
|
||||
</xsd:element>
|
||||
</xsd:choice>
|
||||
</xsd:complexType>
|
||||
</xsd:element>
|
||||
</xsd:schema>
|
||||
<resheader name="resmimetype">
|
||||
<value>text/microsoft-resx</value>
|
||||
</resheader>
|
||||
<resheader name="version">
|
||||
<value>2.0</value>
|
||||
</resheader>
|
||||
<resheader name="reader">
|
||||
<value>System.Resources.ResXResourceReader, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
|
||||
</resheader>
|
||||
<resheader name="writer">
|
||||
<value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
|
||||
</resheader>
|
||||
</root>
|
30
BaiduYunSync/Properties/Settings.Designer.cs
generated
Normal file
30
BaiduYunSync/Properties/Settings.Designer.cs
generated
Normal file
@ -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 BaiduYunSync.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;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
7
BaiduYunSync/Properties/Settings.settings
Normal file
7
BaiduYunSync/Properties/Settings.settings
Normal file
@ -0,0 +1,7 @@
|
||||
<?xml version='1.0' encoding='utf-8'?>
|
||||
<SettingsFile xmlns="http://schemas.microsoft.com/VisualStudio/2004/01/settings" CurrentProfile="(Default)">
|
||||
<Profiles>
|
||||
<Profile Name="(Default)" />
|
||||
</Profiles>
|
||||
<Settings />
|
||||
</SettingsFile>
|
294
BaiduYunSync/Sync.cs
Normal file
294
BaiduYunSync/Sync.cs
Normal file
@ -0,0 +1,294 @@
|
||||
using NetDisk;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading;
|
||||
|
||||
namespace BaiduYunSync
|
||||
{
|
||||
/// <summary>
|
||||
/// 同步类
|
||||
/// </summary>
|
||||
class Sync
|
||||
{
|
||||
|
||||
static Sync()
|
||||
{
|
||||
Operation.InitUploadFile += Operation_InitUploadFile;
|
||||
Operation.StartUploadBlock += Operation_StartUploadBlock;
|
||||
Operation.ComplateUploadBlock += Operation_ComplateUploadBlock;
|
||||
Operation.UpdateComplate += Operation_UpdateComplate;
|
||||
|
||||
}
|
||||
|
||||
private static void Operation_UpdateComplate(string filePath)
|
||||
{
|
||||
lock (locker)
|
||||
{
|
||||
LiteDbHelper.DeleteUpdateInfo(LiteDbHelper.GetAllUpdateInfos().Where(x => x.Path == filePath).First());
|
||||
}
|
||||
|
||||
LogSettings.StdInfo(filePath + "上传完成,从队列中删除");
|
||||
if (StatusModify != null)
|
||||
StatusModify(filePath, StatusEnum.Delete);
|
||||
mre.Set();
|
||||
}
|
||||
|
||||
private static void Operation_ComplateUploadBlock(string filePath, int endBlockNum, int totalBlockNum)
|
||||
{
|
||||
LiteDbHelper.GetAllUpdateInfos().Where(x => x.Path == filePath).ToList().ForEach(
|
||||
x =>
|
||||
{
|
||||
x.ComplateBlockNum = endBlockNum;
|
||||
});
|
||||
LogSettings.StdInfo(string.Format("{0}完成第{1}个块,共{2}个块", filePath, endBlockNum, totalBlockNum));
|
||||
if (StatusModify != null)
|
||||
StatusModify(filePath, StatusEnum.Modify);
|
||||
}
|
||||
|
||||
private static void Operation_StartUploadBlock(string filePath, int startBlockNum, int totalBlockNum)
|
||||
{
|
||||
LogSettings.StdInfo(string.Format("{0}开始上传第{1}个块,共{2}个块", filePath, startBlockNum, totalBlockNum));
|
||||
}
|
||||
|
||||
private static void Operation_InitUploadFile(string filePath, int fileBlockNum, int needUploadBlockNum)
|
||||
{
|
||||
LiteDbHelper.GetAllUpdateInfos().Where(x => x.Path == filePath).ToList().ForEach(
|
||||
x =>
|
||||
{
|
||||
x.Status = "正在上传";
|
||||
x.TotalBlockNum = fileBlockNum;
|
||||
});
|
||||
LogSettings.StdInfo(filePath + "准备开始上传");
|
||||
if (StatusModify != null)
|
||||
StatusModify(filePath, StatusEnum.Start);
|
||||
}
|
||||
|
||||
public static AutoResetEvent mre = new AutoResetEvent(false);
|
||||
|
||||
/// <summary>
|
||||
/// 任务
|
||||
/// </summary>
|
||||
private static AutoResetEvent taskmre = new AutoResetEvent(false);
|
||||
|
||||
|
||||
private static object locker = new object();
|
||||
|
||||
/// <summary>
|
||||
/// 开始新同步时发生
|
||||
/// </summary>
|
||||
/// <param name="folder">文件夹名称</param>
|
||||
public delegate void StartSyncHandle(string folder);
|
||||
|
||||
public static event StartSyncHandle StartSync;
|
||||
|
||||
/// <summary>
|
||||
/// 同步结束时发生
|
||||
/// </summary>
|
||||
/// <param name="folder"></param>
|
||||
public delegate void EndSyncHandle(SyncItemsDao folder);
|
||||
|
||||
public static event EndSyncHandle EndSync;
|
||||
|
||||
/// <summary>
|
||||
/// 文件上传状态改变
|
||||
/// </summary>
|
||||
/// <param name="path"></param>
|
||||
/// <param name="status"></param>
|
||||
public delegate void StatusModifyHandle(string path, StatusEnum status);
|
||||
|
||||
public static event StatusModifyHandle StatusModify;
|
||||
|
||||
/// <summary>
|
||||
/// 文件状态
|
||||
/// </summary>
|
||||
public enum StatusEnum
|
||||
{
|
||||
/// <summary>
|
||||
/// 添加新项
|
||||
/// </summary>
|
||||
Add,
|
||||
/// <summary>
|
||||
/// 开始上传
|
||||
/// </summary>
|
||||
Start,
|
||||
/// <summary>
|
||||
/// 上传状态改变
|
||||
/// </summary>
|
||||
Modify,
|
||||
/// <summary>
|
||||
/// 结束删除
|
||||
/// </summary>
|
||||
Delete
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 启动同步线程
|
||||
/// </summary>
|
||||
/// <param name="credential">身份信息</param>
|
||||
public static void SyncNow( Credential credential)
|
||||
{
|
||||
// 启动5个上传线程进行上传
|
||||
for (int i = 0; i < 5; i++)
|
||||
{
|
||||
var thread = new Thread(() => UpdateFile(credential));
|
||||
thread.IsBackground = true;
|
||||
thread.Start();
|
||||
}
|
||||
while (true)
|
||||
{
|
||||
// 如果队列中存在未完成的任务,则不进行下一轮扫描
|
||||
while (LiteDbHelper.GetUpdateInfoCount() > 0)
|
||||
{
|
||||
mre.WaitOne();
|
||||
}
|
||||
LogSettings.StdInfo("开始文件夹同步");
|
||||
// 查找距离上次同步时间超过6小时的文件夹
|
||||
var folderList = LiteDbHelper.GetAllSyncItems().Where(x => (DateTime.Now - x.LastSync).TotalHours > 6);
|
||||
foreach (var folder in folderList)
|
||||
{
|
||||
LogSettings.StdInfo("需要同步的文件夹为:" + folder.Folder);
|
||||
if (StartSync != null)
|
||||
{
|
||||
StartSync(folder.Folder);
|
||||
}
|
||||
SearchAllFile(folder.Folder, "/", credential);
|
||||
folder.LastSync = DateTime.Now;
|
||||
LiteDbHelper.UpdateSyncItem(folder);
|
||||
LogSettings.StdInfo(folder.Folder + "同步完成");
|
||||
if (EndSync != null)
|
||||
{
|
||||
EndSync(folder);
|
||||
}
|
||||
}
|
||||
LogSettings.StdInfo("同步结束");
|
||||
mre.WaitOne(new TimeSpan(6, 0, 0));
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 查找所有需要同步的文件
|
||||
/// </summary>
|
||||
/// <param name="folderPath">本地文件夹路径</param>
|
||||
/// <param name="serverPath">服务器路径(父路径)</param>
|
||||
/// <param name="credential">身份信息</param>
|
||||
private static void SearchAllFile(string folderPath, string serverPath, Credential credential)
|
||||
{
|
||||
// 获取服务器路径下文件列表
|
||||
var fileList = Operation.GetFileList(serverPath, credential);
|
||||
// 获取需要同步的文件夹名
|
||||
var folderName = Path.GetFileName(folderPath);
|
||||
// 组合成新服务器路径,由于windows文件路径为\分割,服务器为/分割,所以需要转换
|
||||
var newServerPath = Path.Combine(serverPath, folderName).Replace('\\', '/');
|
||||
if (fileList.list == null || !fileList.list.Select(x => x.server_filename).Contains(folderName))
|
||||
{
|
||||
Operation.CreateFolder(newServerPath, credential);
|
||||
LogSettings.StdInfo("创建文件夹" + newServerPath);
|
||||
}
|
||||
fileList = Operation.GetFileList(newServerPath, credential);
|
||||
var localFileList = Directory.GetFiles(folderPath);
|
||||
var localDirectoryList = Directory.GetDirectories(folderPath);
|
||||
foreach (var file in localFileList)
|
||||
{
|
||||
// 如果任务中存在该文件则放弃添加
|
||||
if (LiteDbHelper.ContainsPath(file))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
var updateInfo = new UpdateInfoDao();
|
||||
updateInfo.FileName = Path.GetFileName(file);
|
||||
updateInfo.FileLength = new FileInfo(file).Length;
|
||||
updateInfo.Path = file;
|
||||
if (updateInfo.FileLength == 0)
|
||||
{
|
||||
LogSettings.StdInfo(file + "大小为0,暂不支持上传");
|
||||
continue;
|
||||
}
|
||||
var fileEnumberable = fileList.list == null ? null : fileList.list.Where(x => x.server_filename == Path.GetFileName(file));
|
||||
FileInfo fi = new FileInfo(file);
|
||||
//如果有文件,因为文件名不能相同,所以只需要判断第一个文件是否与服务器相同即可
|
||||
if (fileEnumberable != null && fileEnumberable.Count() > 0)
|
||||
{
|
||||
// 服务器返回的MD5有时候好像有问题,会导致部分文件反复同步,所以删除
|
||||
if (fileEnumberable.ElementAt(0).size == fi.Length)// && fileEnumberable.ElementAt(0).md5 == GetMD5HashFromFile(file))
|
||||
{
|
||||
LogSettings.StdInfo("文件已存在:" + fileEnumberable.ElementAt(0).server_filename);
|
||||
continue;
|
||||
}
|
||||
updateInfo.NeedDelete = true;
|
||||
}
|
||||
if (!updateInfo.NeedDelete)
|
||||
{
|
||||
updateInfo.ServerPath = Path.Combine(newServerPath, Path.GetFileName(file)).Replace('\\', '/');
|
||||
}
|
||||
lock (locker)
|
||||
{
|
||||
LiteDbHelper.InsertUpdateInfo(updateInfo);
|
||||
LogSettings.StdInfo("添加文件:" + updateInfo.Path);
|
||||
}
|
||||
if (StatusModify != null)
|
||||
StatusModify(updateInfo.Path, StatusEnum.Add);
|
||||
taskmre.Set();
|
||||
}
|
||||
foreach (var directory in localDirectoryList)
|
||||
{
|
||||
SearchAllFile(directory, newServerPath, credential);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 上传文件
|
||||
/// </summary>
|
||||
/// <param name="credential">身份信息</param>
|
||||
private static void UpdateFile(Credential credential)
|
||||
{
|
||||
while (true)
|
||||
{
|
||||
UpdateInfoDao updateInfo;
|
||||
lock (locker)
|
||||
{
|
||||
// 查找第一个未开始同步的文件
|
||||
updateInfo = LiteDbHelper.GetAllUpdateInfos().Where(x => !x.IsUsed).FirstOrDefault();
|
||||
if (updateInfo != null)
|
||||
{
|
||||
updateInfo.IsUsed = true;
|
||||
}
|
||||
|
||||
}
|
||||
// 如果没有找到,则证明
|
||||
if (updateInfo == null)
|
||||
{
|
||||
taskmre.Reset();
|
||||
taskmre.WaitOne();
|
||||
continue;
|
||||
}
|
||||
if (updateInfo.NeedDelete)
|
||||
{
|
||||
var fileOperationResult = Operation.Delete(updateInfo.ServerPath, credential);
|
||||
if (!fileOperationResult.success)
|
||||
{
|
||||
|
||||
}
|
||||
LogSettings.StdInfo("删除文件:" + updateInfo.ServerPath);
|
||||
}
|
||||
for (int i = 0; i < 3; i++)
|
||||
{
|
||||
try
|
||||
{
|
||||
Operation.ChunkedUpload(updateInfo.Path, updateInfo.ServerPath, credential);
|
||||
LogSettings.StdInfo("上传文件成功:" + updateInfo.FileName);
|
||||
break;
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
LogSettings.StdInfo(string.Format("第{0}次上传失败,文件名:{1},失败原因:{2}", i, updateInfo.Path, ex));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
}
|
16
BaiduYunSync/SyncItemsDao.cs
Normal file
16
BaiduYunSync/SyncItemsDao.cs
Normal file
@ -0,0 +1,16 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
|
||||
namespace BaiduYunSync
|
||||
{
|
||||
public class SyncItemsDao
|
||||
{
|
||||
public int Id { get; set; }
|
||||
|
||||
public string Folder { get; set; }
|
||||
|
||||
public DateTime LastSync { get; set; }
|
||||
}
|
||||
}
|
61
BaiduYunSync/UpdateInfoDao.cs
Normal file
61
BaiduYunSync/UpdateInfoDao.cs
Normal file
@ -0,0 +1,61 @@
|
||||
using NetDisk;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
|
||||
namespace BaiduYunSync
|
||||
{
|
||||
/// <summary>
|
||||
/// 上传信息类
|
||||
/// </summary>
|
||||
public class UpdateInfoDao
|
||||
{
|
||||
public int Id { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 总共完成数量
|
||||
/// </summary>
|
||||
public int ComplateBlockNum { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 总块数
|
||||
/// </summary>
|
||||
public int TotalBlockNum { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 文件路径
|
||||
/// </summary>
|
||||
public string Path { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 服务器路径
|
||||
/// </summary>
|
||||
public string ServerPath { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 文件名
|
||||
/// </summary>
|
||||
public string FileName { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 当前状态
|
||||
/// </summary>
|
||||
public string Status { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 文件大小
|
||||
/// </summary>
|
||||
public long FileLength { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 是否需要先删除文件
|
||||
/// </summary>
|
||||
public bool NeedDelete { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 是否已经被使用
|
||||
/// </summary>
|
||||
public bool IsUsed { get; set; }
|
||||
}
|
||||
}
|
31
BaiduYunSync/UserInfoDao.cs
Normal file
31
BaiduYunSync/UserInfoDao.cs
Normal file
@ -0,0 +1,31 @@
|
||||
using NetDisk;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
|
||||
namespace BaiduYunSync
|
||||
{
|
||||
/// <summary>
|
||||
/// 用户信息类
|
||||
/// </summary>
|
||||
public class UserInfoDao
|
||||
{
|
||||
public int Id { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 用户名
|
||||
/// </summary>
|
||||
public string UserName { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 密码
|
||||
/// </summary>
|
||||
public string Password { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 用户凭据
|
||||
/// </summary>
|
||||
public string UserCredentialStr { get; set; }
|
||||
}
|
||||
}
|
153
BaiduYunSync/frmLogin.Designer.cs
generated
Normal file
153
BaiduYunSync/frmLogin.Designer.cs
generated
Normal file
@ -0,0 +1,153 @@
|
||||
namespace BaiduYunSync
|
||||
{
|
||||
partial class frmLogin
|
||||
{
|
||||
/// <summary>
|
||||
/// Required designer variable.
|
||||
/// </summary>
|
||||
private System.ComponentModel.IContainer components = null;
|
||||
|
||||
/// <summary>
|
||||
/// Clean up any resources being used.
|
||||
/// </summary>
|
||||
/// <param name="disposing">true if managed resources should be disposed; otherwise, false.</param>
|
||||
protected override void Dispose(bool disposing)
|
||||
{
|
||||
if (disposing && (components != null))
|
||||
{
|
||||
components.Dispose();
|
||||
}
|
||||
base.Dispose(disposing);
|
||||
}
|
||||
|
||||
#region Windows Form Designer generated code
|
||||
|
||||
/// <summary>
|
||||
/// Required method for Designer support - do not modify
|
||||
/// the contents of this method with the code editor.
|
||||
/// </summary>
|
||||
private void InitializeComponent()
|
||||
{
|
||||
this.btnLogin = new System.Windows.Forms.Button();
|
||||
this.pbVcode = new System.Windows.Forms.PictureBox();
|
||||
this.txtVCode = new System.Windows.Forms.TextBox();
|
||||
this.txtPassword = new System.Windows.Forms.TextBox();
|
||||
this.txtUserName = new System.Windows.Forms.TextBox();
|
||||
this.lbVcode = new System.Windows.Forms.Label();
|
||||
this.label2 = new System.Windows.Forms.Label();
|
||||
this.label1 = new System.Windows.Forms.Label();
|
||||
((System.ComponentModel.ISupportInitialize)(this.pbVcode)).BeginInit();
|
||||
this.SuspendLayout();
|
||||
//
|
||||
// btnLogin
|
||||
//
|
||||
this.btnLogin.Location = new System.Drawing.Point(15, 146);
|
||||
this.btnLogin.Name = "btnLogin";
|
||||
this.btnLogin.Size = new System.Drawing.Size(324, 28);
|
||||
this.btnLogin.TabIndex = 12;
|
||||
this.btnLogin.Text = "登录";
|
||||
this.btnLogin.UseVisualStyleBackColor = true;
|
||||
this.btnLogin.Click += new System.EventHandler(this.btnLogin_Click);
|
||||
//
|
||||
// pbVcode
|
||||
//
|
||||
this.pbVcode.Location = new System.Drawing.Point(241, 91);
|
||||
this.pbVcode.Name = "pbVcode";
|
||||
this.pbVcode.Size = new System.Drawing.Size(99, 44);
|
||||
this.pbVcode.SizeMode = System.Windows.Forms.PictureBoxSizeMode.StretchImage;
|
||||
this.pbVcode.TabIndex = 9;
|
||||
this.pbVcode.TabStop = false;
|
||||
this.pbVcode.Visible = false;
|
||||
this.pbVcode.Click += new System.EventHandler(this.pbVcode_Click);
|
||||
//
|
||||
// txtVCode
|
||||
//
|
||||
this.txtVCode.Location = new System.Drawing.Point(90, 97);
|
||||
this.txtVCode.Name = "txtVCode";
|
||||
this.txtVCode.Size = new System.Drawing.Size(119, 25);
|
||||
this.txtVCode.TabIndex = 11;
|
||||
this.txtVCode.Visible = false;
|
||||
//
|
||||
// txtPassword
|
||||
//
|
||||
this.txtPassword.Location = new System.Drawing.Point(90, 56);
|
||||
this.txtPassword.Name = "txtPassword";
|
||||
this.txtPassword.PasswordChar = '*';
|
||||
this.txtPassword.Size = new System.Drawing.Size(251, 25);
|
||||
this.txtPassword.TabIndex = 10;
|
||||
//
|
||||
// txtUserName
|
||||
//
|
||||
this.txtUserName.Location = new System.Drawing.Point(90, 14);
|
||||
this.txtUserName.Name = "txtUserName";
|
||||
this.txtUserName.Size = new System.Drawing.Size(251, 25);
|
||||
this.txtUserName.TabIndex = 8;
|
||||
this.txtUserName.Leave += new System.EventHandler(this.txtUserName_Leave);
|
||||
//
|
||||
// lbVcode
|
||||
//
|
||||
this.lbVcode.AutoSize = true;
|
||||
this.lbVcode.Location = new System.Drawing.Point(12, 100);
|
||||
this.lbVcode.Name = "lbVcode";
|
||||
this.lbVcode.Size = new System.Drawing.Size(67, 15);
|
||||
this.lbVcode.TabIndex = 5;
|
||||
this.lbVcode.Text = "验证码:";
|
||||
this.lbVcode.Visible = false;
|
||||
//
|
||||
// label2
|
||||
//
|
||||
this.label2.AutoSize = true;
|
||||
this.label2.Location = new System.Drawing.Point(12, 59);
|
||||
this.label2.Name = "label2";
|
||||
this.label2.Size = new System.Drawing.Size(52, 15);
|
||||
this.label2.TabIndex = 6;
|
||||
this.label2.Text = "密码:";
|
||||
//
|
||||
// label1
|
||||
//
|
||||
this.label1.AutoSize = true;
|
||||
this.label1.Location = new System.Drawing.Point(12, 18);
|
||||
this.label1.Name = "label1";
|
||||
this.label1.Size = new System.Drawing.Size(67, 15);
|
||||
this.label1.TabIndex = 7;
|
||||
this.label1.Text = "用户名:";
|
||||
//
|
||||
// frmLogin
|
||||
//
|
||||
this.AutoScaleDimensions = new System.Drawing.SizeF(8F, 15F);
|
||||
this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font;
|
||||
this.ClientSize = new System.Drawing.Size(362, 189);
|
||||
this.Controls.Add(this.btnLogin);
|
||||
this.Controls.Add(this.pbVcode);
|
||||
this.Controls.Add(this.txtVCode);
|
||||
this.Controls.Add(this.txtPassword);
|
||||
this.Controls.Add(this.txtUserName);
|
||||
this.Controls.Add(this.lbVcode);
|
||||
this.Controls.Add(this.label2);
|
||||
this.Controls.Add(this.label1);
|
||||
this.FormBorderStyle = System.Windows.Forms.FormBorderStyle.FixedDialog;
|
||||
this.MaximizeBox = false;
|
||||
this.MinimizeBox = false;
|
||||
this.Name = "frmLogin";
|
||||
this.StartPosition = System.Windows.Forms.FormStartPosition.CenterParent;
|
||||
this.Text = "登录";
|
||||
this.FormClosing += new System.Windows.Forms.FormClosingEventHandler(this.frmLogin_FormClosing);
|
||||
this.Load += new System.EventHandler(this.frmLogin_Load);
|
||||
((System.ComponentModel.ISupportInitialize)(this.pbVcode)).EndInit();
|
||||
this.ResumeLayout(false);
|
||||
this.PerformLayout();
|
||||
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
private System.Windows.Forms.Button btnLogin;
|
||||
private System.Windows.Forms.PictureBox pbVcode;
|
||||
private System.Windows.Forms.TextBox txtVCode;
|
||||
private System.Windows.Forms.TextBox txtPassword;
|
||||
private System.Windows.Forms.TextBox txtUserName;
|
||||
private System.Windows.Forms.Label lbVcode;
|
||||
private System.Windows.Forms.Label label2;
|
||||
private System.Windows.Forms.Label label1;
|
||||
}
|
||||
}
|
91
BaiduYunSync/frmLogin.cs
Normal file
91
BaiduYunSync/frmLogin.cs
Normal file
@ -0,0 +1,91 @@
|
||||
using NetDisk;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.ComponentModel;
|
||||
using System.Data;
|
||||
using System.Drawing;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Windows.Forms;
|
||||
|
||||
namespace BaiduYunSync
|
||||
{
|
||||
public partial class frmLogin : Form
|
||||
{
|
||||
public frmLogin()
|
||||
{
|
||||
InitializeComponent();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 返回内容
|
||||
/// </summary>
|
||||
public LoginResult result;
|
||||
|
||||
private LoginCheckResult lcr;
|
||||
|
||||
private void txtUserName_Leave(object sender, EventArgs e)
|
||||
{
|
||||
if (txtUserName.Text == "")
|
||||
{
|
||||
lcr = null;
|
||||
return;
|
||||
}
|
||||
lcr = Authentication.LoginCheck(txtUserName.Text);
|
||||
if (!lcr.success)
|
||||
{
|
||||
MessageBox.Show("错误:" + lcr.exception);
|
||||
return;
|
||||
}
|
||||
lbVcode.Visible = txtVCode.Visible = pbVcode.Visible = lcr.needVCode;
|
||||
txtVCode.Text = "";
|
||||
if (lcr.needVCode)
|
||||
{
|
||||
pbVcode.Image = ByteToImage(lcr.image);
|
||||
}
|
||||
}
|
||||
|
||||
private static Bitmap ByteToImage(byte[] blob)
|
||||
{
|
||||
MemoryStream mStream = new MemoryStream();
|
||||
byte[] pData = blob;
|
||||
mStream.Write(pData, 0, Convert.ToInt32(pData.Length));
|
||||
Bitmap bm = new Bitmap(mStream, false);
|
||||
mStream.Dispose();
|
||||
return bm;
|
||||
}
|
||||
|
||||
private void frmLogin_Load(object sender, EventArgs e)
|
||||
{
|
||||
txtUserName.Focus();
|
||||
}
|
||||
|
||||
private void btnLogin_Click(object sender, EventArgs e)
|
||||
{
|
||||
if (lcr == null) return;
|
||||
lcr.verifyCode = txtVCode.Text;
|
||||
result = Authentication.Login(txtUserName.Text, txtPassword.Text, lcr);
|
||||
if (!result.success)
|
||||
{
|
||||
MessageBox.Show("出现错误: " + result.exception);
|
||||
txtUserName_Leave(null, null);
|
||||
return;
|
||||
}
|
||||
var userInfo = LiteDbHelper.UserInfo;
|
||||
userInfo.UserName = txtUserName.Text;
|
||||
userInfo.UserCredentialStr = result.credential.Serialize();
|
||||
LiteDbHelper.UserInfo = userInfo;
|
||||
DialogResult = DialogResult.OK;
|
||||
}
|
||||
|
||||
private void pbVcode_Click(object sender, EventArgs e)
|
||||
{
|
||||
txtUserName_Leave(null, null);
|
||||
}
|
||||
|
||||
private void frmLogin_FormClosing(object sender, FormClosingEventArgs e)
|
||||
{
|
||||
}
|
||||
}
|
||||
}
|
120
BaiduYunSync/frmLogin.resx
Normal file
120
BaiduYunSync/frmLogin.resx
Normal file
@ -0,0 +1,120 @@
|
||||
<?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>
|
||||
</root>
|
179
BaiduYunSync/frmMain.Designer.cs
generated
Normal file
179
BaiduYunSync/frmMain.Designer.cs
generated
Normal file
@ -0,0 +1,179 @@
|
||||
namespace BaiduYunSync
|
||||
{
|
||||
partial class frmMain
|
||||
{
|
||||
/// <summary>
|
||||
/// 必需的设计器变量。
|
||||
/// </summary>
|
||||
private System.ComponentModel.IContainer components = null;
|
||||
|
||||
/// <summary>
|
||||
/// 清理所有正在使用的资源。
|
||||
/// </summary>
|
||||
/// <param name="disposing">如果应释放托管资源,为 true;否则为 false。</param>
|
||||
protected override void Dispose(bool disposing)
|
||||
{
|
||||
if (disposing && (components != null))
|
||||
{
|
||||
components.Dispose();
|
||||
}
|
||||
base.Dispose(disposing);
|
||||
}
|
||||
|
||||
#region Windows 窗体设计器生成的代码
|
||||
|
||||
/// <summary>
|
||||
/// 设计器支持所需的方法 - 不要
|
||||
/// 使用代码编辑器修改此方法的内容。
|
||||
/// </summary>
|
||||
private void InitializeComponent()
|
||||
{
|
||||
this.statusStrip1 = new System.Windows.Forms.StatusStrip();
|
||||
this.tsslQuota = new System.Windows.Forms.ToolStripStatusLabel();
|
||||
this.btnAddSync = new System.Windows.Forms.Button();
|
||||
this.lvSyncFolder = new System.Windows.Forms.ListView();
|
||||
this.columnHeader1 = ((System.Windows.Forms.ColumnHeader)(new System.Windows.Forms.ColumnHeader()));
|
||||
this.columnHeader2 = ((System.Windows.Forms.ColumnHeader)(new System.Windows.Forms.ColumnHeader()));
|
||||
this.columnHeader3 = ((System.Windows.Forms.ColumnHeader)(new System.Windows.Forms.ColumnHeader()));
|
||||
this.btnDelSync = new System.Windows.Forms.Button();
|
||||
this.fbdSyncFloder = new System.Windows.Forms.FolderBrowserDialog();
|
||||
this.txtReadLog = new System.Windows.Forms.Button();
|
||||
this.btnUploadList = new System.Windows.Forms.Button();
|
||||
this.statusStrip1.SuspendLayout();
|
||||
this.SuspendLayout();
|
||||
//
|
||||
// statusStrip1
|
||||
//
|
||||
this.statusStrip1.ImageScalingSize = new System.Drawing.Size(20, 20);
|
||||
this.statusStrip1.Items.AddRange(new System.Windows.Forms.ToolStripItem[] {
|
||||
this.tsslQuota});
|
||||
this.statusStrip1.Location = new System.Drawing.Point(0, 361);
|
||||
this.statusStrip1.Name = "statusStrip1";
|
||||
this.statusStrip1.Padding = new System.Windows.Forms.Padding(1, 0, 10, 0);
|
||||
this.statusStrip1.Size = new System.Drawing.Size(620, 22);
|
||||
this.statusStrip1.TabIndex = 3;
|
||||
this.statusStrip1.Text = "statusStrip1";
|
||||
//
|
||||
// tsslQuota
|
||||
//
|
||||
this.tsslQuota.Name = "tsslQuota";
|
||||
this.tsslQuota.Size = new System.Drawing.Size(131, 17);
|
||||
this.tsslQuota.Text = "toolStripStatusLabel1";
|
||||
this.tsslQuota.Click += new System.EventHandler(this.tsslQuota_Click);
|
||||
//
|
||||
// btnAddSync
|
||||
//
|
||||
this.btnAddSync.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Right)));
|
||||
this.btnAddSync.Location = new System.Drawing.Point(535, 10);
|
||||
this.btnAddSync.Name = "btnAddSync";
|
||||
this.btnAddSync.Size = new System.Drawing.Size(75, 23);
|
||||
this.btnAddSync.TabIndex = 0;
|
||||
this.btnAddSync.Text = "添加新同步";
|
||||
this.btnAddSync.UseVisualStyleBackColor = true;
|
||||
this.btnAddSync.Click += new System.EventHandler(this.btnAddSync_Click);
|
||||
//
|
||||
// lvSyncFolder
|
||||
//
|
||||
this.lvSyncFolder.Anchor = ((System.Windows.Forms.AnchorStyles)((((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Bottom)
|
||||
| System.Windows.Forms.AnchorStyles.Left)
|
||||
| System.Windows.Forms.AnchorStyles.Right)));
|
||||
this.lvSyncFolder.Columns.AddRange(new System.Windows.Forms.ColumnHeader[] {
|
||||
this.columnHeader1,
|
||||
this.columnHeader2,
|
||||
this.columnHeader3});
|
||||
this.lvSyncFolder.FullRowSelect = true;
|
||||
this.lvSyncFolder.GridLines = true;
|
||||
this.lvSyncFolder.Location = new System.Drawing.Point(0, 0);
|
||||
this.lvSyncFolder.Margin = new System.Windows.Forms.Padding(2, 2, 2, 2);
|
||||
this.lvSyncFolder.Name = "lvSyncFolder";
|
||||
this.lvSyncFolder.Size = new System.Drawing.Size(531, 362);
|
||||
this.lvSyncFolder.TabIndex = 4;
|
||||
this.lvSyncFolder.UseCompatibleStateImageBehavior = false;
|
||||
this.lvSyncFolder.View = System.Windows.Forms.View.Details;
|
||||
//
|
||||
// columnHeader1
|
||||
//
|
||||
this.columnHeader1.Text = "地址";
|
||||
this.columnHeader1.Width = 265;
|
||||
//
|
||||
// columnHeader2
|
||||
//
|
||||
this.columnHeader2.Text = "同步状态";
|
||||
this.columnHeader2.Width = 139;
|
||||
//
|
||||
// columnHeader3
|
||||
//
|
||||
this.columnHeader3.Text = "最后同步时间";
|
||||
this.columnHeader3.Width = 116;
|
||||
//
|
||||
// btnDelSync
|
||||
//
|
||||
this.btnDelSync.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Right)));
|
||||
this.btnDelSync.Location = new System.Drawing.Point(535, 53);
|
||||
this.btnDelSync.Name = "btnDelSync";
|
||||
this.btnDelSync.Size = new System.Drawing.Size(75, 23);
|
||||
this.btnDelSync.TabIndex = 5;
|
||||
this.btnDelSync.Text = "删除同步";
|
||||
this.btnDelSync.UseVisualStyleBackColor = true;
|
||||
this.btnDelSync.Click += new System.EventHandler(this.btnDelSync_Click);
|
||||
//
|
||||
// txtReadLog
|
||||
//
|
||||
this.txtReadLog.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Right)));
|
||||
this.txtReadLog.Location = new System.Drawing.Point(535, 137);
|
||||
this.txtReadLog.Name = "txtReadLog";
|
||||
this.txtReadLog.Size = new System.Drawing.Size(75, 23);
|
||||
this.txtReadLog.TabIndex = 6;
|
||||
this.txtReadLog.Text = "查看日志";
|
||||
this.txtReadLog.UseVisualStyleBackColor = true;
|
||||
this.txtReadLog.Click += new System.EventHandler(this.txtReadLog_Click);
|
||||
//
|
||||
// btnUploadList
|
||||
//
|
||||
this.btnUploadList.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Right)));
|
||||
this.btnUploadList.Location = new System.Drawing.Point(535, 97);
|
||||
this.btnUploadList.Name = "btnUploadList";
|
||||
this.btnUploadList.Size = new System.Drawing.Size(75, 23);
|
||||
this.btnUploadList.TabIndex = 7;
|
||||
this.btnUploadList.Text = "传输列表";
|
||||
this.btnUploadList.UseVisualStyleBackColor = true;
|
||||
this.btnUploadList.Click += new System.EventHandler(this.btnUploadList_Click);
|
||||
//
|
||||
// frmMain
|
||||
//
|
||||
this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 12F);
|
||||
this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font;
|
||||
this.ClientSize = new System.Drawing.Size(620, 383);
|
||||
this.Controls.Add(this.btnUploadList);
|
||||
this.Controls.Add(this.txtReadLog);
|
||||
this.Controls.Add(this.btnDelSync);
|
||||
this.Controls.Add(this.lvSyncFolder);
|
||||
this.Controls.Add(this.statusStrip1);
|
||||
this.Controls.Add(this.btnAddSync);
|
||||
this.Margin = new System.Windows.Forms.Padding(2, 2, 2, 2);
|
||||
this.Name = "frmMain";
|
||||
this.StartPosition = System.Windows.Forms.FormStartPosition.CenterScreen;
|
||||
this.Text = "百度云自动同步";
|
||||
this.Load += new System.EventHandler(this.frmMain_Load);
|
||||
this.statusStrip1.ResumeLayout(false);
|
||||
this.statusStrip1.PerformLayout();
|
||||
this.ResumeLayout(false);
|
||||
this.PerformLayout();
|
||||
|
||||
}
|
||||
|
||||
#endregion
|
||||
private System.Windows.Forms.StatusStrip statusStrip1;
|
||||
private System.Windows.Forms.ToolStripStatusLabel tsslQuota;
|
||||
private System.Windows.Forms.Button btnAddSync;
|
||||
private System.Windows.Forms.ListView lvSyncFolder;
|
||||
private System.Windows.Forms.ColumnHeader columnHeader1;
|
||||
private System.Windows.Forms.ColumnHeader columnHeader2;
|
||||
private System.Windows.Forms.Button btnDelSync;
|
||||
private System.Windows.Forms.FolderBrowserDialog fbdSyncFloder;
|
||||
private System.Windows.Forms.ColumnHeader columnHeader3;
|
||||
private System.Windows.Forms.Button txtReadLog;
|
||||
private System.Windows.Forms.Button btnUploadList;
|
||||
}
|
||||
}
|
||||
|
174
BaiduYunSync/frmMain.cs
Normal file
174
BaiduYunSync/frmMain.cs
Normal file
@ -0,0 +1,174 @@
|
||||
using NetDisk;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.ComponentModel;
|
||||
using System.Data;
|
||||
using System.Drawing;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading;
|
||||
using System.Windows.Forms;
|
||||
|
||||
namespace BaiduYunSync
|
||||
{
|
||||
public partial class frmMain : Form
|
||||
{
|
||||
public frmMain()
|
||||
{
|
||||
InitializeComponent();
|
||||
}
|
||||
|
||||
private void frmMain_Load(object sender, EventArgs e)
|
||||
{
|
||||
//var checkResult = Authentication.LoginCheck("2000208");
|
||||
//MessageBox.Show(checkResult.needVCode.ToString());
|
||||
if (!SetQuota())
|
||||
{
|
||||
var login = new frmLogin();
|
||||
if (login.ShowDialog() == DialogResult.OK)
|
||||
{
|
||||
if (!SetQuota())
|
||||
{
|
||||
Application.Exit();
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
Application.Exit();
|
||||
}
|
||||
}
|
||||
var items = LiteDbHelper.GetAllSyncItems();
|
||||
foreach (var item in items)
|
||||
{
|
||||
addListViewItem(item);
|
||||
}
|
||||
Sync.StartSync += Sync_StartSync;
|
||||
Sync.EndSync += Sync_EndSync;
|
||||
Thread thread = new Thread(() => { Sync.SyncNow(Credential.Deserialize(LiteDbHelper.UserInfo.UserCredentialStr)); });
|
||||
thread.IsBackground = true;
|
||||
thread.Start();
|
||||
}
|
||||
|
||||
private void Sync_EndSync(SyncItemsDao folder)
|
||||
{
|
||||
lvSyncFolder.BeginInvoke(new Action(
|
||||
() =>
|
||||
{
|
||||
var items = lvSyncFolder.Items.Cast<ListViewItem>().Where(x => x.Text == folder.Folder);
|
||||
if (items.Count() > 0)
|
||||
{
|
||||
items.ElementAt(0).SubItems[1].Text = "分析完成";
|
||||
items.ElementAt(0).SubItems[2].Text = folder.LastSync.ToString();
|
||||
}
|
||||
}
|
||||
), null);
|
||||
}
|
||||
|
||||
private void Sync_StartSync(string folder)
|
||||
{
|
||||
lvSyncFolder.BeginInvoke(new Action(
|
||||
() =>
|
||||
{
|
||||
var items = lvSyncFolder.Items.Cast<ListViewItem>().Where(x => x.Text == folder);
|
||||
if (items.Count() > 0)
|
||||
{
|
||||
items.ElementAt(0).SubItems[1].Text = "开始分析";
|
||||
}
|
||||
}
|
||||
), null);
|
||||
}
|
||||
|
||||
private bool SetQuota()
|
||||
{
|
||||
var userInfo = LiteDbHelper.UserInfo;
|
||||
if (userInfo == null || userInfo.UserCredentialStr == null)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
var quotaResult = Operation.GetQuota(Credential.Deserialize(userInfo.UserCredentialStr));
|
||||
if (!quotaResult.success)
|
||||
{
|
||||
MessageBox.Show("Error:" + quotaResult.exception);
|
||||
return false;
|
||||
}
|
||||
else if (quotaResult.errno != 0)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
tsslQuota.Text = "空间使用:已用" + GetGB(quotaResult.used) + "/总共" + GetGB(quotaResult.total);
|
||||
return true;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 将B转换为GB
|
||||
/// </summary>
|
||||
/// <param name="b"></param>
|
||||
/// <returns></returns>
|
||||
private string GetGB(long b)
|
||||
{
|
||||
var bb = (double)b;
|
||||
for (int i = 0; i < 3; i++)
|
||||
{
|
||||
bb /= 1024;
|
||||
}
|
||||
return bb.ToString("f2") + "GB";
|
||||
}
|
||||
|
||||
private void btnAddSync_Click(object sender, EventArgs e)
|
||||
{
|
||||
if (fbdSyncFloder.ShowDialog() == DialogResult.OK)
|
||||
{
|
||||
if (lvSyncFolder.Items.Cast<ListViewItem>().Select(x => (x.Tag as SyncItemsDao).Folder).Contains(fbdSyncFloder.SelectedPath))
|
||||
{
|
||||
MessageBox.Show("当前文件夹已在同步列表中,无需再次添加");
|
||||
return;
|
||||
}
|
||||
var dao = new SyncItemsDao();
|
||||
dao.Folder = fbdSyncFloder.SelectedPath;
|
||||
dao.LastSync = new DateTime(1970, 1, 1);
|
||||
LiteDbHelper.UpdateSyncItem(dao);
|
||||
addListViewItem(dao);
|
||||
Sync.mre.Set();
|
||||
}
|
||||
}
|
||||
|
||||
private void addListViewItem(SyncItemsDao dao)
|
||||
{
|
||||
var item = new ListViewItem(dao.Folder);
|
||||
item.SubItems.Add("准备同步");
|
||||
item.SubItems.Add(dao.LastSync.ToString());
|
||||
item.Tag = dao;
|
||||
item.ToolTipText = dao.Folder;
|
||||
lvSyncFolder.Items.Add(item);
|
||||
}
|
||||
|
||||
private void txtReadLog_Click(object sender, EventArgs e)
|
||||
{
|
||||
new frmReadLog().ShowDialog();
|
||||
}
|
||||
|
||||
private void tsslQuota_Click(object sender, EventArgs e)
|
||||
{
|
||||
SetQuota();
|
||||
}
|
||||
|
||||
private void btnDelSync_Click(object sender, EventArgs e)
|
||||
{
|
||||
foreach (ListViewItem item in lvSyncFolder.SelectedItems)
|
||||
{
|
||||
LiteDbHelper.DeleteSyncItem(item.Tag as SyncItemsDao);
|
||||
lvSyncFolder.Items.Remove(item);
|
||||
}
|
||||
}
|
||||
|
||||
frmUploadList updateListForm;
|
||||
private void btnUploadList_Click(object sender, EventArgs e)
|
||||
{
|
||||
if (updateListForm == null || updateListForm.IsDisposed)
|
||||
{
|
||||
updateListForm = new frmUploadList();
|
||||
}
|
||||
updateListForm.Show();
|
||||
}
|
||||
}
|
||||
}
|
126
BaiduYunSync/frmMain.resx
Normal file
126
BaiduYunSync/frmMain.resx
Normal file
@ -0,0 +1,126 @@
|
||||
<?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>
|
||||
<metadata name="statusStrip1.TrayLocation" type="System.Drawing.Point, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a">
|
||||
<value>17, 17</value>
|
||||
</metadata>
|
||||
<metadata name="fbdSyncFloder.TrayLocation" type="System.Drawing.Point, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a">
|
||||
<value>161, 17</value>
|
||||
</metadata>
|
||||
</root>
|
63
BaiduYunSync/frmReadLog.Designer.cs
generated
Normal file
63
BaiduYunSync/frmReadLog.Designer.cs
generated
Normal file
@ -0,0 +1,63 @@
|
||||
namespace BaiduYunSync
|
||||
{
|
||||
partial class frmReadLog
|
||||
{
|
||||
/// <summary>
|
||||
/// Required designer variable.
|
||||
/// </summary>
|
||||
private System.ComponentModel.IContainer components = null;
|
||||
|
||||
/// <summary>
|
||||
/// Clean up any resources being used.
|
||||
/// </summary>
|
||||
/// <param name="disposing">true if managed resources should be disposed; otherwise, false.</param>
|
||||
protected override void Dispose(bool disposing)
|
||||
{
|
||||
if (disposing && (components != null))
|
||||
{
|
||||
components.Dispose();
|
||||
}
|
||||
base.Dispose(disposing);
|
||||
}
|
||||
|
||||
#region Windows Form Designer generated code
|
||||
|
||||
/// <summary>
|
||||
/// Required method for Designer support - do not modify
|
||||
/// the contents of this method with the code editor.
|
||||
/// </summary>
|
||||
private void InitializeComponent()
|
||||
{
|
||||
this.txtLog = new System.Windows.Forms.TextBox();
|
||||
this.SuspendLayout();
|
||||
//
|
||||
// txtLog
|
||||
//
|
||||
this.txtLog.Dock = System.Windows.Forms.DockStyle.Fill;
|
||||
this.txtLog.Location = new System.Drawing.Point(0, 0);
|
||||
this.txtLog.Multiline = true;
|
||||
this.txtLog.Name = "txtLog";
|
||||
this.txtLog.ReadOnly = true;
|
||||
this.txtLog.ScrollBars = System.Windows.Forms.ScrollBars.Both;
|
||||
this.txtLog.Size = new System.Drawing.Size(554, 490);
|
||||
this.txtLog.TabIndex = 0;
|
||||
//
|
||||
// frmReadLog
|
||||
//
|
||||
this.AutoScaleDimensions = new System.Drawing.SizeF(8F, 15F);
|
||||
this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font;
|
||||
this.ClientSize = new System.Drawing.Size(554, 490);
|
||||
this.Controls.Add(this.txtLog);
|
||||
this.Name = "frmReadLog";
|
||||
this.Text = "frmReadLog";
|
||||
this.Load += new System.EventHandler(this.frmReadLog_Load);
|
||||
this.ResumeLayout(false);
|
||||
this.PerformLayout();
|
||||
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
private System.Windows.Forms.TextBox txtLog;
|
||||
}
|
||||
}
|
35
BaiduYunSync/frmReadLog.cs
Normal file
35
BaiduYunSync/frmReadLog.cs
Normal file
@ -0,0 +1,35 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.ComponentModel;
|
||||
using System.Data;
|
||||
using System.Drawing;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Windows.Forms;
|
||||
|
||||
namespace BaiduYunSync
|
||||
{
|
||||
public partial class frmReadLog : Form
|
||||
{
|
||||
public frmReadLog()
|
||||
{
|
||||
InitializeComponent();
|
||||
}
|
||||
|
||||
private void frmReadLog_Load(object sender, EventArgs e)
|
||||
{
|
||||
if (File.Exists("log/job.log"))
|
||||
{
|
||||
using (var fs = new FileStream("log/job.log", FileMode.Open, FileAccess.Read, FileShare.ReadWrite))
|
||||
{
|
||||
int fsLen = (int)fs.Length;
|
||||
byte[] heByte = new byte[fsLen];
|
||||
int r = fs.Read(heByte, 0, heByte.Length);
|
||||
string myStr = System.Text.Encoding.Default.GetString(heByte);
|
||||
txtLog.Text = myStr;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
120
BaiduYunSync/frmReadLog.resx
Normal file
120
BaiduYunSync/frmReadLog.resx
Normal file
@ -0,0 +1,120 @@
|
||||
<?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>
|
||||
</root>
|
140
BaiduYunSync/frmUploadList.Designer.cs
generated
Normal file
140
BaiduYunSync/frmUploadList.Designer.cs
generated
Normal file
@ -0,0 +1,140 @@
|
||||
namespace BaiduYunSync
|
||||
{
|
||||
partial class frmUploadList
|
||||
{
|
||||
/// <summary>
|
||||
/// Required designer variable.
|
||||
/// </summary>
|
||||
private System.ComponentModel.IContainer components = null;
|
||||
|
||||
/// <summary>
|
||||
/// Clean up any resources being used.
|
||||
/// </summary>
|
||||
/// <param name="disposing">true if managed resources should be disposed; otherwise, false.</param>
|
||||
protected override void Dispose(bool disposing)
|
||||
{
|
||||
if (disposing && (components != null))
|
||||
{
|
||||
components.Dispose();
|
||||
}
|
||||
base.Dispose(disposing);
|
||||
}
|
||||
|
||||
#region Windows Form Designer generated code
|
||||
|
||||
/// <summary>
|
||||
/// Required method for Designer support - do not modify
|
||||
/// the contents of this method with the code editor.
|
||||
/// </summary>
|
||||
private void InitializeComponent()
|
||||
{
|
||||
this.components = new System.ComponentModel.Container();
|
||||
this.lvList = new System.Windows.Forms.ListView();
|
||||
this.columnHeader1 = ((System.Windows.Forms.ColumnHeader)(new System.Windows.Forms.ColumnHeader()));
|
||||
this.columnHeader2 = ((System.Windows.Forms.ColumnHeader)(new System.Windows.Forms.ColumnHeader()));
|
||||
this.columnHeader3 = ((System.Windows.Forms.ColumnHeader)(new System.Windows.Forms.ColumnHeader()));
|
||||
this.columnHeader4 = ((System.Windows.Forms.ColumnHeader)(new System.Windows.Forms.ColumnHeader()));
|
||||
this.columnHeader5 = ((System.Windows.Forms.ColumnHeader)(new System.Windows.Forms.ColumnHeader()));
|
||||
this.columnHeader6 = ((System.Windows.Forms.ColumnHeader)(new System.Windows.Forms.ColumnHeader()));
|
||||
this.cmsUploadList = new System.Windows.Forms.ContextMenuStrip(this.components);
|
||||
this.删除选中任务ToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem();
|
||||
this.cmsUploadList.SuspendLayout();
|
||||
this.SuspendLayout();
|
||||
//
|
||||
// lvList
|
||||
//
|
||||
this.lvList.Columns.AddRange(new System.Windows.Forms.ColumnHeader[] {
|
||||
this.columnHeader1,
|
||||
this.columnHeader2,
|
||||
this.columnHeader3,
|
||||
this.columnHeader4,
|
||||
this.columnHeader5,
|
||||
this.columnHeader6});
|
||||
this.lvList.ContextMenuStrip = this.cmsUploadList;
|
||||
this.lvList.Dock = System.Windows.Forms.DockStyle.Fill;
|
||||
this.lvList.FullRowSelect = true;
|
||||
this.lvList.GridLines = true;
|
||||
this.lvList.Location = new System.Drawing.Point(0, 0);
|
||||
this.lvList.Margin = new System.Windows.Forms.Padding(2, 2, 2, 2);
|
||||
this.lvList.Name = "lvList";
|
||||
this.lvList.ShowItemToolTips = true;
|
||||
this.lvList.Size = new System.Drawing.Size(1023, 571);
|
||||
this.lvList.TabIndex = 0;
|
||||
this.lvList.UseCompatibleStateImageBehavior = false;
|
||||
this.lvList.View = System.Windows.Forms.View.Details;
|
||||
//
|
||||
// columnHeader1
|
||||
//
|
||||
this.columnHeader1.Text = "文件名";
|
||||
this.columnHeader1.Width = 138;
|
||||
//
|
||||
// columnHeader2
|
||||
//
|
||||
this.columnHeader2.Text = "传输状态";
|
||||
this.columnHeader2.Width = 129;
|
||||
//
|
||||
// columnHeader3
|
||||
//
|
||||
this.columnHeader3.Text = "文件大小";
|
||||
this.columnHeader3.Width = 128;
|
||||
//
|
||||
// columnHeader4
|
||||
//
|
||||
this.columnHeader4.Text = "分块信息";
|
||||
this.columnHeader4.Width = 137;
|
||||
//
|
||||
// columnHeader5
|
||||
//
|
||||
this.columnHeader5.Text = "传输信息";
|
||||
this.columnHeader5.Width = 140;
|
||||
//
|
||||
// columnHeader6
|
||||
//
|
||||
this.columnHeader6.Text = "绝对路径";
|
||||
this.columnHeader6.Width = 346;
|
||||
//
|
||||
// cmsUploadList
|
||||
//
|
||||
this.cmsUploadList.ImageScalingSize = new System.Drawing.Size(20, 20);
|
||||
this.cmsUploadList.Items.AddRange(new System.Windows.Forms.ToolStripItem[] {
|
||||
this.删除选中任务ToolStripMenuItem});
|
||||
this.cmsUploadList.Name = "cmsUploadList";
|
||||
this.cmsUploadList.Size = new System.Drawing.Size(149, 26);
|
||||
//
|
||||
// 删除选中任务ToolStripMenuItem
|
||||
//
|
||||
this.删除选中任务ToolStripMenuItem.Name = "删除选中任务ToolStripMenuItem";
|
||||
this.删除选中任务ToolStripMenuItem.Size = new System.Drawing.Size(148, 22);
|
||||
this.删除选中任务ToolStripMenuItem.Text = "删除选中任务";
|
||||
this.删除选中任务ToolStripMenuItem.Click += new System.EventHandler(this.删除选中任务ToolStripMenuItem_Click);
|
||||
//
|
||||
// frmUploadList
|
||||
//
|
||||
this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 12F);
|
||||
this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font;
|
||||
this.ClientSize = new System.Drawing.Size(1023, 571);
|
||||
this.Controls.Add(this.lvList);
|
||||
this.Margin = new System.Windows.Forms.Padding(2, 2, 2, 2);
|
||||
this.Name = "frmUploadList";
|
||||
this.StartPosition = System.Windows.Forms.FormStartPosition.CenterParent;
|
||||
this.Text = "frmUploadList";
|
||||
this.FormClosing += new System.Windows.Forms.FormClosingEventHandler(this.frmUploadList_FormClosing);
|
||||
this.Load += new System.EventHandler(this.frmUploadList_Load);
|
||||
this.cmsUploadList.ResumeLayout(false);
|
||||
this.ResumeLayout(false);
|
||||
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
private System.Windows.Forms.ListView lvList;
|
||||
private System.Windows.Forms.ColumnHeader columnHeader1;
|
||||
private System.Windows.Forms.ColumnHeader columnHeader2;
|
||||
private System.Windows.Forms.ColumnHeader columnHeader3;
|
||||
private System.Windows.Forms.ColumnHeader columnHeader4;
|
||||
private System.Windows.Forms.ColumnHeader columnHeader5;
|
||||
private System.Windows.Forms.ColumnHeader columnHeader6;
|
||||
private System.Windows.Forms.ContextMenuStrip cmsUploadList;
|
||||
private System.Windows.Forms.ToolStripMenuItem 删除选中任务ToolStripMenuItem;
|
||||
}
|
||||
}
|
173
BaiduYunSync/frmUploadList.cs
Normal file
173
BaiduYunSync/frmUploadList.cs
Normal file
@ -0,0 +1,173 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.ComponentModel;
|
||||
using System.Data;
|
||||
using System.Drawing;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Windows.Forms;
|
||||
|
||||
namespace BaiduYunSync
|
||||
{
|
||||
public partial class frmUploadList : Form
|
||||
{
|
||||
public frmUploadList()
|
||||
{
|
||||
InitializeComponent();
|
||||
}
|
||||
|
||||
private void modifyTitle(int listCount, int totalCount)
|
||||
{
|
||||
Text = string.Format("传输文件列表:当前显示{0}条/共{1}条", listCount, totalCount);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 将B转换为MB
|
||||
/// </summary>
|
||||
/// <param name="b"></param>
|
||||
/// <returns></returns>
|
||||
private string getMB(long b)
|
||||
{
|
||||
var bb = (double)b;
|
||||
for (int i = 0; i < 2; i++)
|
||||
{
|
||||
bb /= 1024;
|
||||
}
|
||||
return bb.ToString("f2") + "MB";
|
||||
}
|
||||
|
||||
private void initList()
|
||||
{
|
||||
lvList.Items.Clear();
|
||||
var updateInfoList = LiteDbHelper.GetAllUpdateInfos();
|
||||
var count = updateInfoList.Length > 99 ? 99 : updateInfoList.Length;
|
||||
for (int i = 0; i < count; i++)
|
||||
{
|
||||
var updateInfo = updateInfoList[i];
|
||||
addItem(updateInfo);
|
||||
}
|
||||
modifyTitle(count, updateInfoList.Length);
|
||||
}
|
||||
|
||||
private void addItem(UpdateInfoDao updateInfo, int position = -1)
|
||||
{
|
||||
ListViewItem item = new ListViewItem(updateInfo.FileName);
|
||||
item.Tag = updateInfo;
|
||||
item.ToolTipText = updateInfo.Path;
|
||||
item.SubItems.Add(updateInfo.Status == null ? "准备传输" : updateInfo.Status);
|
||||
item.SubItems.Add(getMB(updateInfo.FileLength));
|
||||
item.SubItems.Add(updateInfo.Status == null ? "" :
|
||||
string.Format("已完成{0}块/共{1}块", updateInfo.ComplateBlockNum, updateInfo.TotalBlockNum));
|
||||
item.SubItems.Add(updateInfo.Status == null ? "" :
|
||||
string.Format("已完成{0}/共{1}", updateInfo.ComplateBlockNum == updateInfo.TotalBlockNum ?
|
||||
getMB(updateInfo.FileLength) : updateInfo.ComplateBlockNum * 4 + "MB", getMB(updateInfo.FileLength)));
|
||||
item.SubItems.Add(updateInfo.Path);
|
||||
if (position == -1)
|
||||
{
|
||||
lvList.Items.Add(item);
|
||||
}
|
||||
else
|
||||
{
|
||||
lvList.Items.Insert(position, item);
|
||||
}
|
||||
}
|
||||
|
||||
private void removeItem(string path)
|
||||
{
|
||||
if (lvList.Items.Cast<ListViewItem>().Select(x => x.SubItems[5].Text).Contains(path))
|
||||
{
|
||||
lvList.Items.Cast<ListViewItem>().Where(x => x.SubItems[5].Text == path).First().Remove();
|
||||
}
|
||||
}
|
||||
|
||||
private void modifyItem(UpdateInfoDao updateInfo)
|
||||
{
|
||||
if (lvList.Items.Cast<ListViewItem>().Select(x => x.SubItems[5].Text).Contains(updateInfo.Path))
|
||||
{
|
||||
var item = lvList.Items.Cast<ListViewItem>().Where(x => x.SubItems[5].Text == updateInfo.Path).First();
|
||||
item.SubItems[1].Text = updateInfo.Status;
|
||||
item.SubItems[3].Text = updateInfo.Status == null ? "" :
|
||||
string.Format("已完成{0}块/共{1}块", updateInfo.ComplateBlockNum, updateInfo.TotalBlockNum);
|
||||
item.SubItems[4].Text = updateInfo.Status == null ? "" :
|
||||
string.Format("已完成{0}/共{1}", updateInfo.ComplateBlockNum == updateInfo.TotalBlockNum ?
|
||||
getMB(updateInfo.FileLength) : updateInfo.ComplateBlockNum * 4 + "MB", getMB(updateInfo.FileLength));
|
||||
item.Tag = updateInfo;
|
||||
}
|
||||
}
|
||||
|
||||
private void frmUploadList_Load(object sender, EventArgs e)
|
||||
{
|
||||
initList();
|
||||
Sync.StatusModify += Sync_StatusModify;
|
||||
}
|
||||
|
||||
private void Sync_StatusModify(string path, Sync.StatusEnum status)
|
||||
{
|
||||
lvList.BeginInvoke(new Action(
|
||||
() =>
|
||||
{
|
||||
UpdateInfoDao updateInfo;
|
||||
switch (status)
|
||||
{
|
||||
case Sync.StatusEnum.Add:
|
||||
if (lvList.Items.Count < 99)
|
||||
{
|
||||
updateInfo = LiteDbHelper.GetUpdateInfoFormPath(path);
|
||||
if (updateInfo != null)
|
||||
{
|
||||
addItem(LiteDbHelper.GetUpdateInfoFormPath(path));
|
||||
}
|
||||
|
||||
}
|
||||
break;
|
||||
case Sync.StatusEnum.Start:
|
||||
case Sync.StatusEnum.Modify:
|
||||
updateInfo = LiteDbHelper.GetUpdateInfoFormPath(path);
|
||||
if (updateInfo != null)
|
||||
{
|
||||
modifyItem(updateInfo);
|
||||
}
|
||||
|
||||
break;
|
||||
case Sync.StatusEnum.Delete:
|
||||
removeItem(path);
|
||||
var count = LiteDbHelper.GetUpdateInfoCount();
|
||||
if (count > 98)
|
||||
{
|
||||
addItem(LiteDbHelper.GetAllUpdateInfos()[98]);
|
||||
}
|
||||
modifyTitle(count > 99 ? 99 : lvList.Items.Count, count);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
), null);
|
||||
|
||||
}
|
||||
|
||||
private void 删除选中任务ToolStripMenuItem_Click(object sender, EventArgs e)
|
||||
{
|
||||
foreach (ListViewItem item in lvList.SelectedItems)
|
||||
{
|
||||
var updateInfo = item.Tag as UpdateInfoDao;
|
||||
if (updateInfo.Status != null)
|
||||
{
|
||||
MessageBox.Show(updateInfo.FileName + "正在传输,暂不支持移除", "提示");
|
||||
return;
|
||||
}
|
||||
LiteDbHelper.DeleteUpdateInfo(updateInfo);
|
||||
}
|
||||
initList();
|
||||
if (lvList.Items.Count == 0)
|
||||
{
|
||||
Sync.mre.Set();
|
||||
}
|
||||
}
|
||||
|
||||
private void frmUploadList_FormClosing(object sender, FormClosingEventArgs e)
|
||||
{
|
||||
Sync.StatusModify -= Sync_StatusModify;
|
||||
}
|
||||
}
|
||||
}
|
123
BaiduYunSync/frmUploadList.resx
Normal file
123
BaiduYunSync/frmUploadList.resx
Normal file
@ -0,0 +1,123 @@
|
||||
<?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>
|
||||
<metadata name="cmsUploadList.TrayLocation" type="System.Drawing.Point, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a">
|
||||
<value>17, 17</value>
|
||||
</metadata>
|
||||
</root>
|
5
BaiduYunSync/packages.config
Normal file
5
BaiduYunSync/packages.config
Normal file
@ -0,0 +1,5 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<packages>
|
||||
<package id="LiteDB" version="2.0.4" targetFramework="net40" />
|
||||
<package id="log4net" version="2.0.7" targetFramework="net40" />
|
||||
</packages>
|
104
NetDisk/Authentication.cs
Normal file
104
NetDisk/Authentication.cs
Normal file
@ -0,0 +1,104 @@
|
||||
using System;
|
||||
using System.Net;
|
||||
using System.Text;
|
||||
using System.Text.RegularExpressions;
|
||||
|
||||
namespace NetDisk
|
||||
{
|
||||
public static class Authentication
|
||||
{
|
||||
public static bool IsLoggedIn(Credential credential)
|
||||
{
|
||||
var res = Operation.GetQuota(credential);
|
||||
if (res == null || res.errno != 0) return false;
|
||||
else return true;
|
||||
}
|
||||
public static LoginResult Login(string username, string password, LoginCheckResult checkResult)
|
||||
{
|
||||
var result = new LoginResult();
|
||||
try
|
||||
{
|
||||
using (var wc = new CookieAwareWebClient())
|
||||
{
|
||||
wc.Cookies.Add(checkResult.baiduid);
|
||||
var ltoken = checkResult.ltoken;
|
||||
var lstr = "loginmerge=true&token=" + ltoken + "&tpl=netdisk&username=" + Uri.EscapeDataString(username) + "&password=" + Uri.EscapeDataString(password);
|
||||
if (checkResult.needVCode) lstr += "&codestring=" + checkResult.codeString + "&verifycode=" + Uri.EscapeDataString(checkResult.verifyCode);
|
||||
wc.Headers.Add(HttpRequestHeader.ContentType, "application/x-www-form-urlencoded");
|
||||
var str = Encoding.UTF8.GetString(wc.UploadData("https://passport.baidu.com/v2/api/?login", Encoding.UTF8.GetBytes(lstr)));
|
||||
var match = Regex.Match(str, "error=(\\d+)");
|
||||
var errno = match.Success ? int.Parse(match.Groups[1].Value) : 0;
|
||||
if (errno != 0)
|
||||
{
|
||||
result.exception = new Exception("Login returned error = " + errno);
|
||||
result.errno = errno;
|
||||
}
|
||||
else
|
||||
{
|
||||
str = wc.DownloadString("https://passport.baidu.com/v3/login/api/auth/?return_type=3&tpl=netdisk&u=http%3A%2F%2Fpan.baidu.com%2Fdisk%2Fhome");
|
||||
long uid = 0;
|
||||
match = Regex.Match(str, "\"uk\"\\s*:\\s*(\\d+)");
|
||||
if (match.Success) long.TryParse(match.Groups[1].Value, out uid);
|
||||
string baiduid = null, bduss = null, stoken = null;
|
||||
foreach (Cookie cookie in wc.Cookies.GetAllCookies())
|
||||
{
|
||||
if (cookie.Name.ToLower() == "baiduid") baiduid = cookie.Value;
|
||||
else if (cookie.Name.ToLower() == "bduss") bduss = cookie.Value;
|
||||
else if (cookie.Name.ToLower() == "stoken" && cookie.Domain.ToLower().Contains("pan.")) stoken = cookie.Value;
|
||||
}
|
||||
if (baiduid != null && bduss != null && stoken != null)
|
||||
{
|
||||
result.credential = new Credential(baiduid, bduss, stoken, uid);
|
||||
result.success = true;
|
||||
}
|
||||
else result.exception = new Exception("Cannot find required cookies.");
|
||||
}
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
result.exception = ex;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
public static LoginCheckResult LoginCheck(string username)
|
||||
{
|
||||
var result = new LoginCheckResult();
|
||||
try
|
||||
{
|
||||
using (var wc = new CookieAwareWebClient())
|
||||
{
|
||||
wc.DownloadData("http://pan.baidu.com/");
|
||||
Cookie baiduid = null;
|
||||
foreach (Cookie cookie in wc.Cookies.GetAllCookies())
|
||||
{
|
||||
if (cookie.Name.ToLower() == "baiduid") baiduid = cookie;
|
||||
}
|
||||
if (baiduid == null) throw new Exception("Cannot obtain BAIDUID.");
|
||||
result.baiduid = baiduid;
|
||||
var str = wc.DownloadString("https://passport.baidu.com/v2/api/?getapi&tpl=netdisk&subpro=netdisk_web&apiver=v3");
|
||||
var ltoken = Regex.Match(str, "\"token\"\\s*:\\s*\"(.+?)\"").Groups[1].Value;
|
||||
result.ltoken = ltoken;
|
||||
str = wc.DownloadString("https://passport.baidu.com/v2/api/?logincheck&token=" + ltoken + "&tpl=netdisk&subpro=netdisk_web&apiver=v3&username=" + Uri.EscapeDataString(username));
|
||||
var codeString = Regex.Match(str, "\"codeString\"\\s*:\\s*\"(.*?)\"").Groups[1].Value;
|
||||
if (codeString == "")
|
||||
{
|
||||
result.success = true;
|
||||
}
|
||||
else
|
||||
{
|
||||
result.image = wc.DownloadData("https://passport.baidu.com/cgi-bin/genimage?" + codeString);
|
||||
result.success = true;
|
||||
result.needVCode = true;
|
||||
result.codeString = codeString;
|
||||
}
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
result.exception = ex;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
}
|
||||
}
|
119
NetDisk/CRC32.cs
Normal file
119
NetDisk/CRC32.cs
Normal file
@ -0,0 +1,119 @@
|
||||
// Copyright (c) Damien Guard. All rights reserved.
|
||||
// Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0
|
||||
// Originally published at http://damieng.com/blog/2006/08/08/calculating_crc32_in_c_and_net
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Security.Cryptography;
|
||||
|
||||
namespace DamienG.Security.Cryptography
|
||||
{
|
||||
/// <summary>
|
||||
/// Implements a 32-bit CRC hash algorithm compatible with Zip etc.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// Crc32 should only be used for backward compatibility with older file formats
|
||||
/// and algorithms. It is not secure enough for new applications.
|
||||
/// If you need to call multiple times for the same data either use the HashAlgorithm
|
||||
/// interface or remember that the result of one Compute call needs to be ~ (XOR) before
|
||||
/// being passed in as the seed for the next Compute call.
|
||||
/// </remarks>
|
||||
public sealed class Crc32 : HashAlgorithm
|
||||
{
|
||||
public const UInt32 DefaultPolynomial = 0xedb88320u;
|
||||
public const UInt32 DefaultSeed = 0xffffffffu;
|
||||
|
||||
static UInt32[] defaultTable;
|
||||
|
||||
readonly UInt32 seed;
|
||||
readonly UInt32[] table;
|
||||
UInt32 hash;
|
||||
|
||||
public Crc32()
|
||||
: this(DefaultPolynomial, DefaultSeed)
|
||||
{
|
||||
}
|
||||
|
||||
public Crc32(UInt32 polynomial, UInt32 seed)
|
||||
{
|
||||
table = InitializeTable(polynomial);
|
||||
this.seed = hash = seed;
|
||||
}
|
||||
|
||||
public override void Initialize()
|
||||
{
|
||||
hash = seed;
|
||||
}
|
||||
|
||||
protected override void HashCore(byte[] array, int ibStart, int cbSize)
|
||||
{
|
||||
hash = CalculateHash(table, hash, array, ibStart, cbSize);
|
||||
}
|
||||
|
||||
protected override byte[] HashFinal()
|
||||
{
|
||||
var hashBuffer = UInt32ToBigEndianBytes(~hash);
|
||||
HashValue = hashBuffer;
|
||||
return hashBuffer;
|
||||
}
|
||||
|
||||
public override int HashSize { get { return 32; } }
|
||||
|
||||
public static UInt32 Compute(byte[] buffer)
|
||||
{
|
||||
return Compute(DefaultSeed, buffer);
|
||||
}
|
||||
|
||||
public static UInt32 Compute(UInt32 seed, byte[] buffer)
|
||||
{
|
||||
return Compute(DefaultPolynomial, seed, buffer);
|
||||
}
|
||||
|
||||
public static UInt32 Compute(UInt32 polynomial, UInt32 seed, byte[] buffer)
|
||||
{
|
||||
return ~CalculateHash(InitializeTable(polynomial), seed, buffer, 0, buffer.Length);
|
||||
}
|
||||
|
||||
static UInt32[] InitializeTable(UInt32 polynomial)
|
||||
{
|
||||
if (polynomial == DefaultPolynomial && defaultTable != null)
|
||||
return defaultTable;
|
||||
|
||||
var createTable = new UInt32[256];
|
||||
for (var i = 0; i < 256; i++)
|
||||
{
|
||||
var entry = (UInt32)i;
|
||||
for (var j = 0; j < 8; j++)
|
||||
if ((entry & 1) == 1)
|
||||
entry = (entry >> 1) ^ polynomial;
|
||||
else
|
||||
entry = entry >> 1;
|
||||
createTable[i] = entry;
|
||||
}
|
||||
|
||||
if (polynomial == DefaultPolynomial)
|
||||
defaultTable = createTable;
|
||||
|
||||
return createTable;
|
||||
}
|
||||
|
||||
static UInt32 CalculateHash(UInt32[] table, UInt32 seed, IList<byte> buffer, int start, int size)
|
||||
{
|
||||
var hash = seed;
|
||||
for (var i = start; i < start + size; i++)
|
||||
hash = (hash >> 8) ^ table[buffer[i] ^ hash & 0xff];
|
||||
return hash;
|
||||
}
|
||||
|
||||
static byte[] UInt32ToBigEndianBytes(UInt32 uint32)
|
||||
{
|
||||
var result = BitConverter.GetBytes(uint32);
|
||||
|
||||
if (BitConverter.IsLittleEndian)
|
||||
Array.Reverse(result);
|
||||
|
||||
return result;
|
||||
}
|
||||
}
|
||||
}
|
54
NetDisk/CookieAwareWebClient.cs
Normal file
54
NetDisk/CookieAwareWebClient.cs
Normal file
@ -0,0 +1,54 @@
|
||||
using System;
|
||||
using System.Net;
|
||||
|
||||
namespace NetDisk
|
||||
{
|
||||
public class CookieAwareWebClient : WebClient
|
||||
{
|
||||
public CookieContainer Cookies { get; set; }
|
||||
public Uri Uri { get; set; }
|
||||
Uri _responseUri;
|
||||
public Uri ResponseUri
|
||||
{
|
||||
get { return _responseUri; }
|
||||
}
|
||||
public CookieAwareWebClient()
|
||||
: this(new CookieContainer())
|
||||
{
|
||||
}
|
||||
|
||||
public CookieAwareWebClient(CookieContainer cookies)
|
||||
{
|
||||
this.Cookies = cookies;
|
||||
}
|
||||
|
||||
protected override WebRequest GetWebRequest(Uri address)
|
||||
{
|
||||
WebRequest request = base.GetWebRequest(address);
|
||||
if (request is HttpWebRequest)
|
||||
{
|
||||
ClearCookiesVersion();
|
||||
(request as HttpWebRequest).CookieContainer = this.Cookies;
|
||||
}
|
||||
HttpWebRequest httpRequest = (HttpWebRequest)request;
|
||||
httpRequest.AutomaticDecompression = DecompressionMethods.GZip | DecompressionMethods.Deflate;
|
||||
return httpRequest;
|
||||
}
|
||||
protected override WebResponse GetWebResponse(WebRequest request)
|
||||
{
|
||||
WebResponse response = base.GetWebResponse(request);
|
||||
_responseUri = response.ResponseUri;
|
||||
return response;
|
||||
}
|
||||
private void ClearCookiesVersion()
|
||||
{
|
||||
var cc = new CookieContainer();
|
||||
foreach (Cookie cookie in Cookies.GetAllCookies())
|
||||
{
|
||||
cookie.Version = 0;
|
||||
cc.Add(cookie);
|
||||
}
|
||||
Cookies = cc;
|
||||
}
|
||||
}
|
||||
}
|
74
NetDisk/Credential.cs
Normal file
74
NetDisk/Credential.cs
Normal file
@ -0,0 +1,74 @@
|
||||
using System.Net;
|
||||
|
||||
namespace NetDisk
|
||||
{
|
||||
public class Credential
|
||||
{
|
||||
private string baiduid;
|
||||
public string Baiduid
|
||||
{
|
||||
get
|
||||
{
|
||||
return baiduid;
|
||||
}
|
||||
}
|
||||
|
||||
private string bduss;
|
||||
public string Bduss
|
||||
{
|
||||
get
|
||||
{
|
||||
return bduss;
|
||||
}
|
||||
}
|
||||
|
||||
private string stoken;
|
||||
public string Stoken
|
||||
{
|
||||
get
|
||||
{
|
||||
return stoken;
|
||||
}
|
||||
}
|
||||
|
||||
private long uid;
|
||||
public long Uid
|
||||
{
|
||||
get
|
||||
{
|
||||
return uid;
|
||||
}
|
||||
}
|
||||
|
||||
private string cookieString;
|
||||
public Credential(string baiduid, string bduss, string stoken, long uid)
|
||||
{
|
||||
this.baiduid = baiduid;
|
||||
this.bduss = bduss;
|
||||
this.stoken = stoken;
|
||||
this.uid = uid;
|
||||
cookieString = "BAIDUID=" + baiduid + "; BDUSS=" + bduss + "; STOKEN=" + stoken;
|
||||
}
|
||||
public static implicit operator string(Credential credential)
|
||||
{
|
||||
return credential.cookieString;
|
||||
}
|
||||
public static implicit operator CookieCollection(Credential credential)
|
||||
{
|
||||
var c = new CookieCollection();
|
||||
c.Add(new Cookie("BAIDUID", credential.baiduid, "/", ".baidu.com"));
|
||||
c.Add(new Cookie("BDUSS", credential.bduss, "/", ".baidu.com"));
|
||||
c.Add(new Cookie("STOKEN", credential.stoken, "/", ".pan.baidu.com"));
|
||||
return c;
|
||||
}
|
||||
public string Serialize()
|
||||
{
|
||||
return baiduid + "$" + bduss + "$" + stoken + "$" + uid;
|
||||
}
|
||||
public static Credential Deserialize(string str)
|
||||
{
|
||||
var tokens = str.Split('$');
|
||||
return new Credential(tokens[0], tokens[1], tokens[2], long.Parse(tokens[3]));
|
||||
}
|
||||
}
|
||||
}
|
28
NetDisk/Extension.cs
Normal file
28
NetDisk/Extension.cs
Normal file
@ -0,0 +1,28 @@
|
||||
using System.Collections;
|
||||
using System.Linq;
|
||||
using System.Net;
|
||||
using System.Reflection;
|
||||
|
||||
namespace NetDisk
|
||||
{
|
||||
public static class Extension
|
||||
{
|
||||
public static CookieCollection GetAllCookies(this CookieContainer container)
|
||||
{
|
||||
var allCookies = new CookieCollection();
|
||||
var domainTableField = container.GetType().GetFields(BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Static).FirstOrDefault(x => x.Name == "m_domainTable");
|
||||
var domains = (IDictionary)domainTableField.GetValue(container);
|
||||
|
||||
foreach (var val in domains.Values)
|
||||
{
|
||||
var type = val.GetType().GetFields(BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Static).First(x => x.Name == "m_list");
|
||||
var values = (IDictionary)type.GetValue(val);
|
||||
foreach (CookieCollection cookies in values.Values)
|
||||
{
|
||||
allCookies.Add(cookies);
|
||||
}
|
||||
}
|
||||
return allCookies;
|
||||
}
|
||||
}
|
||||
}
|
79
NetDisk/NetDisk.csproj
Normal file
79
NetDisk/NetDisk.csproj
Normal file
@ -0,0 +1,79 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<Project ToolsVersion="14.0" DefaultTargets="Build" 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>{74ECA1BF-6508-417D-BC57-DB00DAECA618}</ProjectGuid>
|
||||
<OutputType>Library</OutputType>
|
||||
<AppDesignerFolder>Properties</AppDesignerFolder>
|
||||
<RootNamespace>NetDisk</RootNamespace>
|
||||
<AssemblyName>NetDisk</AssemblyName>
|
||||
<TargetFrameworkVersion>v4.0</TargetFrameworkVersion>
|
||||
<FileAlignment>512</FileAlignment>
|
||||
<TargetFrameworkProfile />
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
|
||||
<DebugSymbols>true</DebugSymbols>
|
||||
<DebugType>full</DebugType>
|
||||
<Optimize>false</Optimize>
|
||||
<OutputPath>bin\Debug\</OutputPath>
|
||||
<DefineConstants>DEBUG;TRACE</DefineConstants>
|
||||
<ErrorReport>prompt</ErrorReport>
|
||||
<WarningLevel>4</WarningLevel>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
|
||||
<DebugType>pdbonly</DebugType>
|
||||
<Optimize>true</Optimize>
|
||||
<OutputPath>bin\Release\</OutputPath>
|
||||
<DefineConstants>TRACE</DefineConstants>
|
||||
<ErrorReport>prompt</ErrorReport>
|
||||
<WarningLevel>4</WarningLevel>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup>
|
||||
<StartupObject />
|
||||
</PropertyGroup>
|
||||
<ItemGroup>
|
||||
<Reference Include="Newtonsoft.Json, Version=9.0.0.0, Culture=neutral, PublicKeyToken=30ad4fe6b2a6aeed, processorArchitecture=MSIL">
|
||||
<HintPath>..\packages\Newtonsoft.Json.9.0.1\lib\net40\Newtonsoft.Json.dll</HintPath>
|
||||
<Private>True</Private>
|
||||
</Reference>
|
||||
<Reference Include="System" />
|
||||
<Reference Include="System.Core" />
|
||||
<Reference Include="System.Runtime.Serialization" />
|
||||
<Reference Include="System.Web" />
|
||||
<Reference Include="System.Xml.Linq" />
|
||||
<Reference Include="System.Data.DataSetExtensions" />
|
||||
<Reference Include="Microsoft.CSharp" />
|
||||
<Reference Include="System.Data" />
|
||||
<Reference Include="System.Net.Http" />
|
||||
<Reference Include="System.Xml" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<Compile Include="Authentication.cs" />
|
||||
<Compile Include="CookieAwareWebClient.cs">
|
||||
<SubType>Component</SubType>
|
||||
</Compile>
|
||||
<Compile Include="CRC32.cs" />
|
||||
<Compile Include="Credential.cs" />
|
||||
<Compile Include="Extension.cs" />
|
||||
<Compile Include="Operation.cs" />
|
||||
<Compile Include="PatientWebClient.cs">
|
||||
<SubType>Component</SubType>
|
||||
</Compile>
|
||||
<Compile Include="Properties\AssemblyInfo.cs" />
|
||||
<Compile Include="Result.cs" />
|
||||
<Compile Include="UploadHelper.cs" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<None Include="packages.config" />
|
||||
</ItemGroup>
|
||||
<Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
|
||||
<!-- To modify your build process, add your task inside one of the targets below and uncomment it.
|
||||
Other similar extension points exist, see Microsoft.Common.targets.
|
||||
<Target Name="BeforeBuild">
|
||||
</Target>
|
||||
<Target Name="AfterBuild">
|
||||
</Target>
|
||||
-->
|
||||
</Project>
|
674
NetDisk/Operation.cs
Normal file
674
NetDisk/Operation.cs
Normal file
@ -0,0 +1,674 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Net;
|
||||
using System.Runtime.Serialization;
|
||||
using System.Text;
|
||||
using Newtonsoft.Json;
|
||||
using System.Text.RegularExpressions;
|
||||
using System.IO;
|
||||
using System.Web;
|
||||
|
||||
namespace NetDisk
|
||||
{
|
||||
public static class Operation
|
||||
{
|
||||
/// <summary>
|
||||
/// 块完成事件(顺序提交)
|
||||
/// </summary>
|
||||
/// <param name="filePath">文件名</param>
|
||||
/// <param name="endBlockNum">当前完成的块</param>
|
||||
/// <param name="totalBlockNum">总块数</param>
|
||||
public delegate void ComplateUploadBlockHandle(string filePath, int endBlockNum, int totalBlockNum);
|
||||
|
||||
public static event ComplateUploadBlockHandle ComplateUploadBlock;
|
||||
|
||||
/// <summary>
|
||||
/// 初始化上传
|
||||
/// </summary>
|
||||
/// <param name="filePath">文件名</param>
|
||||
/// <param name="fileBlockNum">文件所拥有的块数</param>
|
||||
/// <param name="totalBlockNum">服务器需要上传的块数</param>
|
||||
public delegate void InitUploadFileHandle(string filePath, int fileBlockNum, int needUploadBlockNum);
|
||||
|
||||
public static event InitUploadFileHandle InitUploadFile;
|
||||
|
||||
/// <summary>
|
||||
/// 开始上传块
|
||||
/// </summary>
|
||||
/// <param name="filePath">文件名</param>
|
||||
/// <param name="startBlockNum">当前开始的块</param>
|
||||
/// <param name="totalBlockNum">总块数</param>
|
||||
public delegate void StartUploadBlockHandle(string filePath, int startBlockNum, int totalBlockNum);
|
||||
|
||||
public static event StartUploadBlockHandle StartUploadBlock;
|
||||
|
||||
/// <summary>
|
||||
/// 上传完成
|
||||
/// </summary>
|
||||
/// <param name="filePath">文件名</param>
|
||||
public delegate void UpdateComplateHandle(string filePath);
|
||||
|
||||
public static event UpdateComplateHandle UpdateComplate;
|
||||
|
||||
|
||||
public static QuotaResult GetQuota(Credential credential)
|
||||
{
|
||||
try
|
||||
{
|
||||
using (var wc = new WebClient())
|
||||
{
|
||||
wc.Headers.Add(HttpRequestHeader.Cookie, credential);
|
||||
var res = wc.DownloadString("http://pan.baidu.com/api/quota?checkexpire=1&checkfree=1");
|
||||
var obj = JsonConvert.DeserializeObject<QuotaResult>(res);
|
||||
obj.success = true;
|
||||
return obj;
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
return new QuotaResult() { exception = ex };
|
||||
}
|
||||
}
|
||||
public static UserInfoResult GetUserInfo(Credential credential)
|
||||
{
|
||||
try
|
||||
{
|
||||
if (credential.Uid <= 0) throw new Exception("Invalid uid.");
|
||||
using (var wc = new WebClient())
|
||||
{
|
||||
wc.Headers.Add(HttpRequestHeader.Cookie, credential);
|
||||
var res = wc.DownloadString("http://pan.baidu.com/api/user/getinfo?user_list=[" + credential.Uid + "]");
|
||||
var obj = JsonConvert.DeserializeObject<UserInfoResult>(res);
|
||||
obj.success = true;
|
||||
return obj;
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
return new UserInfoResult() { exception = ex };
|
||||
}
|
||||
}
|
||||
public static FileListResult GetFileList(string path, Credential credential)
|
||||
{
|
||||
try
|
||||
{
|
||||
using (var wc = new WebClient())
|
||||
{
|
||||
wc.Headers.Add(HttpRequestHeader.Cookie, credential);
|
||||
var res = wc.DownloadString("http://pan.baidu.com/api/list?page=1&num=10000000&dir=" + HttpUtility.UrlEncode(path));
|
||||
var obj = JsonConvert.DeserializeObject<FileListResult>(res);
|
||||
obj.success = true;
|
||||
return obj;
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
return new FileListResult() { exception = ex };
|
||||
}
|
||||
}
|
||||
public static ThumbnailResult GetThumbnail(string path, Credential credential, int width = 125, int height = 90, int quality = 100)
|
||||
{
|
||||
try
|
||||
{
|
||||
using (var wc = new WebClient())
|
||||
{
|
||||
wc.Headers.Add(HttpRequestHeader.Cookie, credential);
|
||||
var res = wc.DownloadData("http://pcsdata.baidu.com/rest/2.0/pcs/thumbnail?app_id=250528&method=generate&path=" + HttpUtility.UrlEncode(path) + "&quality=" + quality + "&height=" + height + "&width=" + width);
|
||||
return new ThumbnailResult() { success = true, image = res };
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
return new ThumbnailResult() { exception = ex };
|
||||
}
|
||||
}
|
||||
public static GetDownloadResult GetDownload(string path, Credential credential)
|
||||
{
|
||||
try
|
||||
{
|
||||
using (var wc = new WebClient())
|
||||
{
|
||||
wc.Headers.Add(HttpRequestHeader.Cookie, credential);
|
||||
wc.Headers.Add(HttpRequestHeader.UserAgent, "netdisk;5.4.5.4;PC;PC-Windows;10.0.14393;WindowsBaiduYunGuanJia");
|
||||
var res = wc.DownloadString("http://d.pcs.baidu.com/rest/2.0/pcs/file?app_id=250528&method=locatedownload&ver=4.0&path=" + HttpUtility.UrlEncode(path));
|
||||
var obj = JsonConvert.DeserializeObject<GetDownloadResult>(res);
|
||||
obj.success = true;
|
||||
return obj;
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
return new GetDownloadResult() { exception = ex };
|
||||
}
|
||||
}
|
||||
public static FileOperationResult CreateFolder(string path, Credential credential)
|
||||
{
|
||||
try
|
||||
{
|
||||
using (var wc = new WebClient())
|
||||
{
|
||||
wc.Headers.Add(HttpRequestHeader.Cookie, credential);
|
||||
wc.Headers.Add(HttpRequestHeader.ContentType, "application/x-www-form-urlencoded");
|
||||
var str = "isdir=1&path=" + HttpUtility.UrlEncode(path);
|
||||
var res = wc.UploadData("http://pan.baidu.com/api/create?a=commit", Encoding.UTF8.GetBytes(str));
|
||||
var obj = JsonConvert.DeserializeObject<FileOperationResult>(Encoding.UTF8.GetString(res));
|
||||
obj.success = true;
|
||||
return obj;
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
return new FileOperationResult() { exception = ex };
|
||||
}
|
||||
}
|
||||
public static FileOperationResult Copy(string path, string dest, string newname, Credential credential)
|
||||
{
|
||||
var str = "filelist=[{\"path\":\"" + HttpUtility.UrlEncode(path) + "\",\"dest\":\"" + HttpUtility.UrlEncode(dest) + "\",\"newname\":\"" + HttpUtility.UrlEncode(newname) + "\"}]";
|
||||
return FileOp("http://pan.baidu.com/api/filemanager?opera=copy&clienttype=8", str, credential);
|
||||
}
|
||||
public static FileOperationResult Delete(string path, Credential credential)
|
||||
{
|
||||
var str = "filelist=[\"" + HttpUtility.UrlEncode(path) + "\"]";
|
||||
return FileOp("http://pan.baidu.com/api/filemanager?opera=delete&clienttype=8", str, credential);
|
||||
}
|
||||
public static FileOperationResult Move(string path, string dest, string newname, Credential credential)
|
||||
{
|
||||
var str = "filelist=[{\"path\":\"" + HttpUtility.UrlEncode(path) + "\",\"dest\":\"" + HttpUtility.UrlEncode(dest) + "\",\"newname\":\"" + HttpUtility.UrlEncode(newname) + "\"}]";
|
||||
return FileOp("http://pan.baidu.com/api/filemanager?opera=move&clienttype=8", str, credential);
|
||||
}
|
||||
public static FileOperationResult Rename(string path, string newname, Credential credential)
|
||||
{
|
||||
var str = "filelist=[{\"path\":\"" + HttpUtility.UrlEncode(path) + "\",\"newname\":\"" + HttpUtility.UrlEncode(newname) + "\"}]";
|
||||
return FileOp("http://pan.baidu.com/api/filemanager?opera=rename&clienttype=8", str, credential);
|
||||
}
|
||||
private static FileOperationResult FileOp(string url, string str, Credential credential)
|
||||
{
|
||||
try
|
||||
{
|
||||
using (var wc = new WebClient())
|
||||
{
|
||||
wc.Headers.Add(HttpRequestHeader.Cookie, credential);
|
||||
wc.Headers.Add(HttpRequestHeader.ContentType, "application/x-www-form-urlencoded");
|
||||
var res = wc.UploadData(url, Encoding.UTF8.GetBytes(str));
|
||||
var obj = JsonConvert.DeserializeObject<FileOpResult>(Encoding.UTF8.GetString(res));
|
||||
if (obj.info.Length == 0 && obj.errno != 0)
|
||||
return new FileOperationResult() { success = true, errno = obj.errno };
|
||||
else if (obj.info.Length == 0 || obj.errno != 0 && obj.info[0].errno == 0)
|
||||
throw new Exception("Response data malformat.");
|
||||
else
|
||||
return new FileOperationResult() { success = true, errno = obj.info[0].errno, path = obj.info[0].path };
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
return new FileOperationResult() { exception = ex };
|
||||
}
|
||||
}
|
||||
public static OfflineListResult GetOfflineList(Credential credential)
|
||||
{
|
||||
try
|
||||
{
|
||||
using (var wc = new WebClient())
|
||||
{
|
||||
wc.Headers.Add(HttpRequestHeader.Cookie, credential);
|
||||
var res1 = wc.DownloadString("http://pan.baidu.com/rest/2.0/services/cloud_dl?app_id=250528&method=list_task&need_task_info=1&status=255");
|
||||
var ltr = JsonConvert.DeserializeObject<ListTaskResult>(res1);
|
||||
if (ltr.task_info.Length == 0) return new OfflineListResult() { success = true, tasks = new OfflineListResult.Entry[0] };
|
||||
var str = "method=query_task&op_type=1&task_ids=" + HttpUtility.UrlEncode(string.Join(",", ltr.task_info.Select(e => e.task_id.ToString())));
|
||||
wc.Headers.Add(HttpRequestHeader.ContentType, "application/x-www-form-urlencoded");
|
||||
var res2 = wc.UploadData("http://pan.baidu.com/rest/2.0/services/cloud_dl?app_id=250528", Encoding.UTF8.GetBytes(str));
|
||||
var qtr = JsonConvert.DeserializeObject<QueryTaskResult>(Encoding.UTF8.GetString(res2));
|
||||
return new OfflineListResult()
|
||||
{
|
||||
tasks = ltr.task_info.Select(e =>
|
||||
{
|
||||
var ai = qtr.task_info[e.task_id.ToString()];
|
||||
return new OfflineListResult.Entry()
|
||||
{
|
||||
create_time = e.create_time,
|
||||
od_type = e.od_type,
|
||||
save_path = e.save_path,
|
||||
source_url = e.source_url,
|
||||
task_id = e.task_id,
|
||||
task_name = e.task_name,
|
||||
file_size = ai.file_size,
|
||||
finished_size = ai.finished_size,
|
||||
status = ai.status
|
||||
};
|
||||
}).ToArray(),
|
||||
success = true
|
||||
};
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
return new OfflineListResult() { exception = ex };
|
||||
}
|
||||
}
|
||||
public static Result CancelOfflineTask(long taskid, Credential credential)
|
||||
{
|
||||
return OfflineTaskOp(taskid, "cancel_task", credential);
|
||||
}
|
||||
public static Result DeleteOfflineTask(long taskid, Credential credential)
|
||||
{
|
||||
return OfflineTaskOp(taskid, "delete_task", credential);
|
||||
}
|
||||
public static Result ClearOfflineTask(Credential credential)
|
||||
{
|
||||
return OfflineTaskOp(0, "clear_task", credential);
|
||||
}
|
||||
private static Result OfflineTaskOp(long taskid, string oper, Credential credential)
|
||||
{
|
||||
try
|
||||
{
|
||||
using (var wc = new WebClient())
|
||||
{
|
||||
wc.Headers.Add(HttpRequestHeader.Cookie, credential);
|
||||
wc.DownloadData("http://pan.baidu.com/rest/2.0/services/cloud_dl?app_id=250528&method=" + oper + "&task_id=" + taskid);
|
||||
return new Result() { success = true };
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
return new Result() { exception = ex };
|
||||
}
|
||||
}
|
||||
public static QueryLinkResult QueryLinkFiles(string link, Credential credential)
|
||||
{
|
||||
try
|
||||
{
|
||||
using (var wc = new WebClient())
|
||||
{
|
||||
wc.Headers.Add(HttpRequestHeader.Cookie, credential);
|
||||
wc.Headers.Add(HttpRequestHeader.UserAgent, "netdisk;5.4.5.4;PC;PC-Windows;10.0.14393;WindowsBaiduYunGuanJia");
|
||||
if (link.StartsWith("magnet:", StringComparison.OrdinalIgnoreCase))
|
||||
{
|
||||
var res = wc.DownloadString("http://pan.baidu.com/rest/2.0/services/cloud_dl?app_id=250528&clienttype=8&method=query_magnetinfo&source_url=" + HttpUtility.UrlEncode(link));
|
||||
var obj = JsonConvert.DeserializeObject<QueryMagnetResult>(res);
|
||||
return new QueryLinkResult() { success = true, files = obj.magnet_info };
|
||||
}
|
||||
else if (link.EndsWith(".torrent", StringComparison.OrdinalIgnoreCase))
|
||||
{
|
||||
var res = wc.DownloadString("http://pan.baidu.com/rest/2.0/services/cloud_dl?app_id=250528&clienttype=8&method=query_sinfo&type=2&source_path=" + HttpUtility.UrlEncode(link));
|
||||
var obj = JsonConvert.DeserializeObject<QueryTorrentResult>(res);
|
||||
return new QueryLinkResult() { success = true, files = obj.torrent_info.file_info };
|
||||
}
|
||||
else throw new Exception("Not a magnet link or a torrent file.");
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
return new QueryLinkResult() { exception = ex };
|
||||
}
|
||||
}
|
||||
public static AddOfflineTaskResult AddOfflineTask(string link, string savepath, Credential credential, int[] selected = null, string sha1 = "")
|
||||
{
|
||||
try
|
||||
{
|
||||
var str = "method=add_task&save_path=" + HttpUtility.UrlEncode(savepath) + "&";
|
||||
if (link.StartsWith("http://", StringComparison.OrdinalIgnoreCase) || link.StartsWith("https://", StringComparison.OrdinalIgnoreCase))
|
||||
str += "type=0&source_url=" + HttpUtility.UrlEncode(link);
|
||||
else if (link.StartsWith("ed2k://", StringComparison.OrdinalIgnoreCase))
|
||||
str += "type=3&source_url=" + HttpUtility.UrlEncode(link);
|
||||
else if (link.StartsWith("magnet:", StringComparison.OrdinalIgnoreCase))
|
||||
str += "type=4&task_from=5&source_url=" + HttpUtility.UrlEncode(link) + "&selected_idx=" + string.Join(",", selected.Select(i => i.ToString()));
|
||||
else if (link.EndsWith(".torrent", StringComparison.OrdinalIgnoreCase))
|
||||
str += "type=2&task_from=5&file_sha1=" + sha1 + "&source_path=" + HttpUtility.UrlEncode(link) + "&selected_idx=" + string.Join(",", selected.Select(i => i.ToString()));
|
||||
else throw new Exception("Link invalid.");
|
||||
using (var wc = new WebClient())
|
||||
{
|
||||
wc.Headers.Add(HttpRequestHeader.Cookie, credential);
|
||||
wc.Headers.Add(HttpRequestHeader.ContentType, "application/x-www-form-urlencoded");
|
||||
wc.Headers.Add(HttpRequestHeader.UserAgent, "netdisk;5.4.5.4;PC;PC-Windows;10.0.14393;WindowsBaiduYunGuanJia");
|
||||
var res = wc.UploadData("http://pan.baidu.com/rest/2.0/services/cloud_dl?app_id=250528&clienttype=8", Encoding.UTF8.GetBytes(str));
|
||||
var obj = JsonConvert.DeserializeObject<AddOfflineTaskResult>(Encoding.UTF8.GetString(res));
|
||||
obj.success = true;
|
||||
return obj;
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
return new AddOfflineTaskResult() { exception = ex };
|
||||
}
|
||||
}
|
||||
public static ShareResult Share(string[] pathlist, Credential credential, string pwd = null)
|
||||
{
|
||||
try
|
||||
{
|
||||
if (pwd != null && pwd.Length != 4) throw new Exception("Length of pwd must be 4.");
|
||||
var str = "path_list=[" + string.Join(",", pathlist.Select(p => '"' + HttpUtility.UrlEncode(p) + '"')) + "]&channel_list=[]&shorturl=1&";
|
||||
if (pwd == null) str += "public=1&schannel=0";
|
||||
else str += "public=0&schannel=4&pwd=" + pwd;
|
||||
var rand = new Random();
|
||||
var logid = new string(Enumerable.Range(0, 100).Select(i => (char)('a' + rand.Next(26))).ToArray());
|
||||
using (var wc = new WebClient())
|
||||
{
|
||||
wc.Headers.Add(HttpRequestHeader.Cookie, credential);
|
||||
wc.Headers.Add(HttpRequestHeader.ContentType, "application/x-www-form-urlencoded");
|
||||
var res = wc.UploadData("http://pan.baidu.com/share/pset?clienttype=8&channel=00000000000000000000000000000000&version=5.4.5.4&devuid=123456&logid=" + logid, Encoding.UTF8.GetBytes(str));
|
||||
var obj = JsonConvert.DeserializeObject<ShareResult>(Encoding.UTF8.GetString(res));
|
||||
obj.success = true;
|
||||
return obj;
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
return new ShareResult() { exception = ex };
|
||||
}
|
||||
}
|
||||
public static TransferResult Transfer(string url, string path, Credential credential, string pwd = null)
|
||||
{
|
||||
try
|
||||
{
|
||||
using (var wc = new CookieAwareWebClient())
|
||||
{
|
||||
wc.Cookies.Add(credential);
|
||||
var str = wc.DownloadString(url);
|
||||
var rurl = wc.ResponseUri.ToString();
|
||||
string shareid = null, uk = null;
|
||||
if (rurl.Contains("/share/init"))
|
||||
{
|
||||
if (pwd == null) throw new Exception("Need password.");
|
||||
shareid = Regex.Match(rurl, "shareid=(\\d+)").Groups[1].Value;
|
||||
uk = Regex.Match(rurl, "uk=(\\d+)").Groups[1].Value;
|
||||
wc.Headers.Add(HttpRequestHeader.Referer, rurl);
|
||||
wc.Headers.Add(HttpRequestHeader.ContentType, "application/x-www-form-urlencoded");
|
||||
var res = wc.UploadData("http://pan.baidu.com/share/verify?shareid=" + shareid + "&uk=" + uk, Encoding.UTF8.GetBytes("vcode=&vcode_str=&pwd=" + pwd));
|
||||
var obj = JsonConvert.DeserializeObject<VerifyPwdResult>(Encoding.UTF8.GetString(res));
|
||||
if (obj.errno != 0) throw new Exception("Password verification returned errno = " + obj.errno);
|
||||
str = wc.DownloadString(url);
|
||||
}
|
||||
str = Regex.Match(str, "yunData.setData(.*)").Groups[1].Value.Trim();
|
||||
str = str.Substring(1, str.Length - 3);
|
||||
var obj2 = JsonConvert.DeserializeObject<SharePageData>(str);
|
||||
str = "path=" + HttpUtility.UrlEncode(path) + "&filelist=[" + string.Join(",", obj2.file_list.list.Select(e => "\"" + HttpUtility.UrlEncode(e.path) + "\"")) + "]";
|
||||
wc.Headers.Add(HttpRequestHeader.ContentType, "application/x-www-form-urlencoded");
|
||||
wc.Headers.Add(HttpRequestHeader.Referer, url);
|
||||
var rand = new Random();
|
||||
var logid = new string(Enumerable.Range(0, 100).Select(i => (char)('a' + rand.Next(26))).ToArray());
|
||||
var res2 = wc.UploadData("http://pan.baidu.com/share/transfer?channel=chunlei&clienttype=0&web=1&app_id=250528&ondup=newcopy&async=1&shareid=" + shareid + "&from=" + uk + "&logid=" + logid + "&bdstoken=" + obj2.bdstoken, Encoding.UTF8.GetBytes(str));
|
||||
var obj3 = JsonConvert.DeserializeObject<TransferResult>(Encoding.UTF8.GetString(res2));
|
||||
obj3.success = true;
|
||||
return obj3;
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
return new TransferResult() { exception = ex };
|
||||
}
|
||||
}
|
||||
public static CommitUploadResult SimpleUpload(string localpath, string remotepath, Credential credential, string host = "c.pcs.baidu.com")
|
||||
{
|
||||
try
|
||||
{
|
||||
var size = new FileInfo(localpath).Length;
|
||||
var mtime = (long)(new FileInfo(localpath).LastAccessTime.Subtract(new DateTime(1970, 1, 1))).TotalSeconds;
|
||||
var md5 = UploadHelper.GetMD5HashFromFile(localpath);
|
||||
var str = "path=" + remotepath + "&size=" + size + "&isdir=0&block_list=[\"" + md5 + "\"]&autoinit=1&local_mtime=" + mtime + "&method=post";
|
||||
using (var wc = new PatientWebClient())
|
||||
{
|
||||
wc.Headers.Add(HttpRequestHeader.Cookie, credential);
|
||||
wc.Headers.Add(HttpRequestHeader.ContentType, "application/x-www-form-urlencoded");
|
||||
var res = wc.UploadData("http://pan.baidu.com/api/precreate?clienttype=8", Encoding.UTF8.GetBytes(str));
|
||||
var obj = JsonConvert.DeserializeObject<InitUploadResult>(Encoding.UTF8.GetString(res));
|
||||
if (obj.errno != 0) throw new Exception("precreate had errno = " + obj.errno);
|
||||
var boundary = GetBoundary();
|
||||
wc.Headers.Add(HttpRequestHeader.ContentType, "multipart/form-data; boundary=" + boundary);
|
||||
str = "--" + boundary + "\r\nContent-Disposition: form-data; name=\"filename\"; filename=\"name\"\r\nContent-Type: application/octet-stream\r\n\r\n";
|
||||
var str2 = "\r\n--" + boundary + "--\r\n";
|
||||
var data = Encoding.UTF8.GetBytes(str).Concat(File.ReadAllBytes(localpath)).Concat(Encoding.UTF8.GetBytes(str2)).ToArray();
|
||||
res = wc.UploadData("http://" + host + "/rest/2.0/pcs/superfile2?app_id=250528&method=upload&path=" + HttpUtility.UrlEncode(remotepath) + "&uploadid=" + HttpUtility.UrlEncode(obj.uploadid) + "&partseq=0&partoffset=0", data);
|
||||
str = "path=" + remotepath + "&size=" + size + "&isdir=0&uploadid=" + HttpUtility.UrlEncode(obj.uploadid) + "&block_list=[\"" + md5 + "\"]&method=post&rtype=2&sequence=1&mode=1&local_mtime=" + mtime;
|
||||
res = wc.UploadData("http://pan.baidu.com/api/create?a=commit&clienttype=8", Encoding.UTF8.GetBytes(str));
|
||||
var obj2 = JsonConvert.DeserializeObject<CommitUploadResult>(Encoding.UTF8.GetString(res));
|
||||
obj2.success = true;
|
||||
return obj2;
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
return new CommitUploadResult() { exception = ex };
|
||||
}
|
||||
}
|
||||
public static RapidUploadResult RapidUpload(FileProperty prop, string path, Credential credential)
|
||||
{
|
||||
try
|
||||
{
|
||||
using (var wc = new WebClient())
|
||||
{
|
||||
wc.Headers.Add(HttpRequestHeader.Cookie, credential);
|
||||
wc.Headers.Add(HttpRequestHeader.ContentType, "application/x-www-form-urlencoded");
|
||||
var str = "path=" + HttpUtility.UrlEncode(path) + "&content-length=" + prop.size + "&content-md5=" + prop.md5 + "&slice-md5=" + prop.slice_md5 + "&content-crc32=" + prop.crc32 + "&local_mtime=" + prop.mtime + "&block_list=[" + string.Join(",", prop.blocks.Select(h => '"' + h + '"')) + "]&rtype=2";
|
||||
var res = wc.UploadData("http://pan.baidu.com/api/rapidupload?clienttype=8", Encoding.UTF8.GetBytes(str));
|
||||
var obj = JsonConvert.DeserializeObject<RapidUploadResult>(Encoding.UTF8.GetString(res));
|
||||
obj.success = true;
|
||||
return obj;
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
return new RapidUploadResult() { exception = ex };
|
||||
}
|
||||
}
|
||||
public static InitUploadResult InitUpload(FileProperty prop, string path, Credential credential)
|
||||
{
|
||||
try
|
||||
{
|
||||
using (var wc = new WebClient())
|
||||
{
|
||||
wc.Headers.Add(HttpRequestHeader.Cookie, credential);
|
||||
wc.Headers.Add(HttpRequestHeader.ContentType, "application/x-www-form-urlencoded");
|
||||
var str = "path=" + HttpUtility.UrlEncode(path) + "&size=" + prop.size + "&isdir=0&local_mtime=" + prop.mtime + "&block_list=[" + string.Join(",", prop.blocks.Select(h => '"' + h + '"')) + "]&autoinit=1&method=post";
|
||||
var res = wc.UploadData("http://pan.baidu.com/api/precreate?clienttype=8", Encoding.UTF8.GetBytes(str));
|
||||
var obj = JsonConvert.DeserializeObject<InitUploadResult>(Encoding.UTF8.GetString(res));
|
||||
obj.success = true;
|
||||
if (InitUploadFile != null && obj.errno == 0)
|
||||
{
|
||||
InitUploadFile(prop.path, prop.blocks.Length, obj.block_list.Length);
|
||||
}
|
||||
return obj;
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
return new InitUploadResult() { exception = ex };
|
||||
}
|
||||
}
|
||||
public static Result UploadBlock(FileProperty prop, string path, InitUploadResult session, FileStream stream, int blockid, string host, Credential credential)
|
||||
{
|
||||
try
|
||||
{
|
||||
using (var wc = new PatientWebClient())
|
||||
{
|
||||
if (StartUploadBlock != null)
|
||||
{
|
||||
StartUploadBlock(prop.path, blockid + 1, prop.blocks.Length);
|
||||
}
|
||||
var boundary = GetBoundary();
|
||||
wc.Headers.Add(HttpRequestHeader.Cookie, credential);
|
||||
wc.Headers.Add(HttpRequestHeader.ContentType, "multipart/form-data; boundary=" + boundary);
|
||||
var str = "--" + boundary + "\r\nContent-Disposition: form-data; name=\"filename\"; filename=\"name\"\r\nContent-Type: application/octet-stream\r\n\r\n";
|
||||
var str2 = "\r\n--" + boundary + "--\r\n";
|
||||
stream.Seek((long)blockid * 4 * 1024 * 1024, SeekOrigin.Begin);
|
||||
var fdata = new byte[4 * 1024 * 1024];
|
||||
var len = stream.Read(fdata, 0, fdata.Length);
|
||||
if (len < fdata.Length)
|
||||
{
|
||||
var arr = new byte[len];
|
||||
Array.Copy(fdata, arr, len);
|
||||
fdata = arr;
|
||||
}
|
||||
var data = Encoding.UTF8.GetBytes(str).Concat(fdata).Concat(Encoding.UTF8.GetBytes(str2)).ToArray();
|
||||
var res = wc.UploadData("http://" + host + "/rest/2.0/pcs/superfile2?app_id=250528&method=upload&path=" + HttpUtility.UrlEncode(path) + "&uploadid=" + HttpUtility.UrlEncode(session.uploadid) + "&partseq=" + blockid + "&partoffset=" + (long)blockid * 4 * 1024 * 1024, data);
|
||||
var obj = JsonConvert.DeserializeObject<SuperFileResponse>(Encoding.UTF8.GetString(res));
|
||||
if (obj.md5 != prop.blocks[blockid]) throw new Exception("MD5 mismatch.");
|
||||
if (ComplateUploadBlock != null)
|
||||
{
|
||||
ComplateUploadBlock(prop.path, blockid + 1, prop.blocks.Length);
|
||||
}
|
||||
return new Result() { success = true };
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
return new Result() { exception = ex };
|
||||
}
|
||||
}
|
||||
public static CommitUploadResult CommitUpload(FileProperty prop, string path, InitUploadResult session, Credential credential)
|
||||
{
|
||||
try
|
||||
{
|
||||
using (var wc = new WebClient())
|
||||
{
|
||||
wc.Headers.Add(HttpRequestHeader.Cookie, credential);
|
||||
wc.Headers.Add(HttpRequestHeader.ContentType, "application/x-www-form-urlencoded");
|
||||
var str = "path=" + HttpUtility.UrlEncode(path) + "&size=" + prop.size + "&isdir=0&uploadid=" + HttpUtility.UrlEncode(session.uploadid) + "&block_list=[" + string.Join(",", prop.blocks.Select(h => '"' + h + '"')) + "]&method=post&rtype=2&sequence=1&mode=1&local_mtime=" + prop.mtime;
|
||||
var res = wc.UploadData("http://pan.baidu.com/api/create?a=commit&clienttype=8", Encoding.UTF8.GetBytes(str));
|
||||
var obj = JsonConvert.DeserializeObject<CommitUploadResult>(Encoding.UTF8.GetString(res));
|
||||
obj.success = true;
|
||||
if (UpdateComplate != null)
|
||||
{
|
||||
UpdateComplate(prop.path);
|
||||
}
|
||||
return obj;
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
return new CommitUploadResult() { exception = ex };
|
||||
}
|
||||
}
|
||||
public static CommitUploadResult ChunkedUpload(string localpath, string remotepath, Credential credential)
|
||||
{
|
||||
try
|
||||
{
|
||||
|
||||
var servers = GetUploadServers(credential);
|
||||
if (!servers.success) throw servers.exception;
|
||||
var prop = UploadHelper.GetFileProperty(localpath);
|
||||
var session = InitUpload(prop, remotepath, credential);
|
||||
if (!session.success) throw session.exception;
|
||||
if (session.errno != 0) throw new Exception("Init upload returned errno = " + session.errno);
|
||||
using (var fs = new FileStream(localpath, FileMode.Open, FileAccess.Read, FileShare.ReadWrite))
|
||||
{
|
||||
for(int i = 0; i < prop.blocks.Length; i++)
|
||||
{
|
||||
var res = UploadBlock(prop, remotepath, session, fs, i, servers.servers[0], credential);
|
||||
if (!res.success) throw res.exception;
|
||||
}
|
||||
}
|
||||
var comres = CommitUpload(prop, remotepath, session, credential);
|
||||
if (!comres.success) throw comres.exception;
|
||||
if (comres.errno != 0) throw new Exception("Commit upload returned errno = " + comres.errno);
|
||||
return comres;
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
throw ex;
|
||||
}
|
||||
}
|
||||
public static GetUploadServersResult GetUploadServers(Credential credential)
|
||||
{
|
||||
try
|
||||
{
|
||||
using (var wc = new WebClient())
|
||||
{
|
||||
wc.Headers.Add(HttpRequestHeader.Cookie, credential);
|
||||
wc.Headers.Add(HttpRequestHeader.UserAgent, "netdisk;5.4.5.4;PC;PC-Windows;10.0.14393;WindowsBaiduYunGuanJia");
|
||||
var res = wc.DownloadString("http://d.pcs.baidu.com/rest/2.0/pcs/file?app_id=250528&method=locateupload&esl=1&ehps=0&upload_version=2.0");
|
||||
var obj = JsonConvert.DeserializeObject<LocateUploadResponse>(res);
|
||||
return new GetUploadServersResult() { success = true, servers = obj.servers.Select(s => Regex.Match(s.server, ":\\/\\/(.+)$").Groups[1].Value).ToArray() };
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
return new GetUploadServersResult() { exception = ex };
|
||||
}
|
||||
}
|
||||
private static string GetBoundary()
|
||||
{
|
||||
var rand = new Random();
|
||||
var sb = new StringBuilder();
|
||||
for (int i = 0; i < 28; i++) sb.Append('-');
|
||||
for (int i = 0; i < 15; i++) sb.Append((char)(rand.Next(0, 26) + 'a'));
|
||||
var boundary = sb.ToString();
|
||||
return boundary;
|
||||
}
|
||||
private class FileOpResult
|
||||
{
|
||||
public int errno;
|
||||
public Entry[] info;
|
||||
public class Entry
|
||||
{
|
||||
public int errno;
|
||||
public string path;
|
||||
}
|
||||
}
|
||||
private class ListTaskResult
|
||||
{
|
||||
public Entry[] task_info;
|
||||
public class Entry
|
||||
{
|
||||
public long create_time;
|
||||
public int od_type;
|
||||
public string save_path;
|
||||
public string source_url;
|
||||
public long task_id;
|
||||
public string task_name;
|
||||
}
|
||||
}
|
||||
private class QueryTaskResult
|
||||
{
|
||||
public Dictionary<string, Entry> task_info;
|
||||
public class Entry
|
||||
{
|
||||
public long file_size;
|
||||
public long finished_size;
|
||||
public int status;
|
||||
}
|
||||
}
|
||||
private class QueryTorrentResult
|
||||
{
|
||||
public TorrentInfo torrent_info;
|
||||
public class TorrentInfo
|
||||
{
|
||||
public QueryLinkResult.Entry[] file_info;
|
||||
public string sha1;
|
||||
}
|
||||
}
|
||||
private class QueryMagnetResult
|
||||
{
|
||||
public QueryLinkResult.Entry[] magnet_info;
|
||||
}
|
||||
private class VerifyPwdResult
|
||||
{
|
||||
public int errno;
|
||||
}
|
||||
private class SharePageData
|
||||
{
|
||||
public string bdstoken;
|
||||
public FileList file_list;
|
||||
public class FileList
|
||||
{
|
||||
public Entry[] list;
|
||||
public class Entry
|
||||
{
|
||||
public string path;
|
||||
}
|
||||
}
|
||||
}
|
||||
private class SuperFileResponse
|
||||
{
|
||||
public string md5;
|
||||
}
|
||||
private class LocateUploadResponse
|
||||
{
|
||||
public Entry[] servers;
|
||||
public class Entry
|
||||
{
|
||||
public string server;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
22
NetDisk/PatientWebClient.cs
Normal file
22
NetDisk/PatientWebClient.cs
Normal file
@ -0,0 +1,22 @@
|
||||
using System;
|
||||
using System.Net;
|
||||
|
||||
class PatientWebClient : WebClient
|
||||
{
|
||||
public int Timeout = 300000;
|
||||
public PatientWebClient(int Timeout): base()
|
||||
{
|
||||
this.Timeout = Timeout;
|
||||
}
|
||||
public PatientWebClient() : base()
|
||||
{
|
||||
|
||||
}
|
||||
protected override WebRequest GetWebRequest(Uri uri)
|
||||
{
|
||||
WebRequest w = base.GetWebRequest(uri);
|
||||
w.Timeout = Timeout;
|
||||
(w as HttpWebRequest).ReadWriteTimeout = Timeout;
|
||||
return w;
|
||||
}
|
||||
}
|
36
NetDisk/Properties/AssemblyInfo.cs
Normal file
36
NetDisk/Properties/AssemblyInfo.cs
Normal file
@ -0,0 +1,36 @@
|
||||
using System.Reflection;
|
||||
using System.Runtime.CompilerServices;
|
||||
using System.Runtime.InteropServices;
|
||||
|
||||
// 有关程序集的一般信息由以下
|
||||
// 控制。更改这些特性值可修改
|
||||
// 与程序集关联的信息。
|
||||
[assembly: AssemblyTitle("NetDisk")]
|
||||
[assembly: AssemblyDescription("")]
|
||||
[assembly: AssemblyConfiguration("")]
|
||||
[assembly: AssemblyCompany("")]
|
||||
[assembly: AssemblyProduct("NetDisk")]
|
||||
[assembly: AssemblyCopyright("Copyright © 2016")]
|
||||
[assembly: AssemblyTrademark("")]
|
||||
[assembly: AssemblyCulture("")]
|
||||
|
||||
//将 ComVisible 设置为 false 将使此程序集中的类型
|
||||
//对 COM 组件不可见。 如果需要从 COM 访问此程序集中的类型,
|
||||
//请将此类型的 ComVisible 特性设置为 true。
|
||||
[assembly: ComVisible(false)]
|
||||
|
||||
// 如果此项目向 COM 公开,则下列 GUID 用于类型库的 ID
|
||||
[assembly: Guid("74eca1bf-6508-417d-bc57-db00daeca618")]
|
||||
|
||||
// 程序集的版本信息由下列四个值组成:
|
||||
//
|
||||
// 主版本
|
||||
// 次版本
|
||||
// 生成号
|
||||
// 修订号
|
||||
//
|
||||
//可以指定所有这些值,也可以使用“生成号”和“修订号”的默认值,
|
||||
// 方法是按如下所示使用“*”: :
|
||||
// [assembly: AssemblyVersion("1.0.*")]
|
||||
[assembly: AssemblyVersion("1.0.0.0")]
|
||||
[assembly: AssemblyFileVersion("1.0.0.0")]
|
155
NetDisk/Result.cs
Normal file
155
NetDisk/Result.cs
Normal file
@ -0,0 +1,155 @@
|
||||
using System;
|
||||
using System.Net;
|
||||
|
||||
namespace NetDisk
|
||||
{
|
||||
public class Result
|
||||
{
|
||||
public bool success;
|
||||
public Exception exception;
|
||||
}
|
||||
public class QuotaResult : Result
|
||||
{
|
||||
public int errno;
|
||||
public long total;
|
||||
public long free;
|
||||
public bool expire;
|
||||
public long used;
|
||||
}
|
||||
public class UserInfoResult : Result
|
||||
{
|
||||
public int errno;
|
||||
public Entry[] records;
|
||||
public class Entry
|
||||
{
|
||||
public string avatar_url;
|
||||
public string uname;
|
||||
public string priority_name;
|
||||
}
|
||||
}
|
||||
public class FileListResult : Result
|
||||
{
|
||||
public int errno;
|
||||
public Entry[] list;
|
||||
public class Entry
|
||||
{
|
||||
public int isdir;
|
||||
public string path;
|
||||
public string server_filename;
|
||||
public long size;
|
||||
public long server_mtime;
|
||||
public string md5;
|
||||
}
|
||||
}
|
||||
public class ThumbnailResult : Result
|
||||
{
|
||||
public byte[] image;
|
||||
}
|
||||
public class GetDownloadResult : Result
|
||||
{
|
||||
public Entry[] urls;
|
||||
public class Entry
|
||||
{
|
||||
public int rank;
|
||||
public string url;
|
||||
}
|
||||
}
|
||||
public class FileOperationResult : Result
|
||||
{
|
||||
public int errno;
|
||||
public string path;
|
||||
}
|
||||
public class OfflineListResult : Result
|
||||
{
|
||||
public Entry[] tasks;
|
||||
public class Entry
|
||||
{
|
||||
public long create_time;
|
||||
public int od_type;
|
||||
public string save_path;
|
||||
public string source_url;
|
||||
public long task_id;
|
||||
public string task_name;
|
||||
public long file_size;
|
||||
public long finished_size;
|
||||
public int status;
|
||||
}
|
||||
}
|
||||
public class QueryLinkResult : Result
|
||||
{
|
||||
public Entry[] files;
|
||||
public string sha1;
|
||||
public class Entry
|
||||
{
|
||||
public string file_name;
|
||||
public long size;
|
||||
}
|
||||
}
|
||||
public class AddOfflineTaskResult : Result
|
||||
{
|
||||
public int rapid_download;
|
||||
public long task_id;
|
||||
}
|
||||
public class ShareResult : Result
|
||||
{
|
||||
public int errno;
|
||||
public long shareid;
|
||||
public string link;
|
||||
public string shorturl;
|
||||
}
|
||||
public class TransferResult : Result
|
||||
{
|
||||
public int errno;
|
||||
public Extra extra;
|
||||
public class Extra
|
||||
{
|
||||
public Entry[] list;
|
||||
public class Entry
|
||||
{
|
||||
public string from;
|
||||
public string to;
|
||||
}
|
||||
}
|
||||
}
|
||||
public class InitUploadResult : Result
|
||||
{
|
||||
public int[] block_list;
|
||||
public int errno;
|
||||
public string uploadid;
|
||||
}
|
||||
public class CommitUploadResult : Result
|
||||
{
|
||||
public long ctime;
|
||||
public int errno;
|
||||
public long fs_id;
|
||||
public int isdir;
|
||||
public string md5;
|
||||
public long mtime;
|
||||
public string name;
|
||||
public string path;
|
||||
public long size;
|
||||
}
|
||||
public class RapidUploadResult : Result
|
||||
{
|
||||
public int errno;
|
||||
public FileListResult.Entry info;
|
||||
}
|
||||
public class LoginResult : Result
|
||||
{
|
||||
public int errno;
|
||||
public Credential credential;
|
||||
}
|
||||
public class LoginCheckResult : Result
|
||||
{
|
||||
public bool needVCode;
|
||||
public string codeString;
|
||||
public string verifyCode;
|
||||
public byte[] image;
|
||||
public Cookie baiduid;
|
||||
public string ltoken;
|
||||
}
|
||||
public class GetUploadServersResult: Result
|
||||
{
|
||||
public string[] servers;
|
||||
}
|
||||
}
|
70
NetDisk/UploadHelper.cs
Normal file
70
NetDisk/UploadHelper.cs
Normal file
@ -0,0 +1,70 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Security.Cryptography;
|
||||
using System.Text;
|
||||
using DamienG.Security.Cryptography;
|
||||
|
||||
namespace NetDisk
|
||||
{
|
||||
public static class UploadHelper
|
||||
{
|
||||
public static FileProperty GetFileProperty(string path)
|
||||
{
|
||||
var ret = new FileProperty() { path = path };
|
||||
var info = new FileInfo(path);
|
||||
ret.size = info.Length;
|
||||
ret.mtime= (long)(info.LastAccessTime.Subtract(new DateTime(1970, 1, 1))).TotalSeconds;
|
||||
ret.md5 = GetMD5HashFromFile(path);
|
||||
using (var fs = new FileStream(path, FileMode.Open, FileAccess.Read, FileShare.ReadWrite))
|
||||
{
|
||||
var md5 = new MD5CryptoServiceProvider();
|
||||
var arr = new byte[4 * 1024 * 1024];
|
||||
var len = fs.Read(arr, 0, 256 * 1024);
|
||||
ret.slice_md5 = ByteArrayToHexString(md5.ComputeHash(arr, 0, len));
|
||||
fs.Seek(0, SeekOrigin.Begin);
|
||||
var blocks = new List<string>();
|
||||
while (true)
|
||||
{
|
||||
len = fs.Read(arr, 0, 4 * 1024 * 1024);
|
||||
if (len <= 0) break;
|
||||
blocks.Add(ByteArrayToHexString(md5.ComputeHash(arr, 0, len)));
|
||||
}
|
||||
ret.blocks = blocks.ToArray();
|
||||
fs.Seek(0, SeekOrigin.Begin);
|
||||
var crc32 = new Crc32();
|
||||
ret.crc32 = string.Empty;
|
||||
foreach (byte b in crc32.ComputeHash(fs)) ret.crc32 += b.ToString("x2").ToLower();
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
public static string GetMD5HashFromFile(string fileName)
|
||||
{
|
||||
using (var file = new FileStream(fileName, FileMode.Open))
|
||||
{
|
||||
var md5 = new MD5CryptoServiceProvider();
|
||||
var retVal = md5.ComputeHash(file);
|
||||
return ByteArrayToHexString(retVal);
|
||||
}
|
||||
}
|
||||
private static string ByteArrayToHexString(byte[] arr)
|
||||
{
|
||||
var sb = new StringBuilder();
|
||||
for (int i = 0; i < arr.Length; i++)
|
||||
{
|
||||
sb.Append(arr[i].ToString("x2"));
|
||||
}
|
||||
return sb.ToString();
|
||||
}
|
||||
}
|
||||
public class FileProperty
|
||||
{
|
||||
public string path;
|
||||
public long size;
|
||||
public string md5;
|
||||
public string slice_md5;
|
||||
public string crc32;
|
||||
public long mtime;
|
||||
public string[] blocks;
|
||||
}
|
||||
}
|
4
NetDisk/packages.config
Normal file
4
NetDisk/packages.config
Normal file
@ -0,0 +1,4 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<packages>
|
||||
<package id="Newtonsoft.Json" version="9.0.1" targetFramework="net40" />
|
||||
</packages>
|
Loading…
Reference in New Issue
Block a user