新建
This commit is contained in:
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>
|
||||
Reference in New Issue
Block a user