├── .gitattributes ├── .gitignore ├── App.config ├── App.xaml ├── App.xaml.cs ├── BiliClass.cs ├── Bilibili_Client.csproj ├── Bilibili_Client.sln ├── Dictionary.xaml ├── Geometry.xaml ├── LICENSE ├── MainWindow.xaml ├── MainWindow.xaml.cs ├── PasswordBoxMonitor.cs ├── Properties ├── AssemblyInfo.cs ├── Resources.Designer.cs ├── Resources.resx ├── Settings.Designer.cs ├── Settings.settings ├── app.manifest ├── 分区.png ├── 动态.png ├── 历史记录.png ├── 收藏夹.png └── 首页.png ├── README.md ├── Space.xaml ├── Space.xaml.cs ├── geetest.xaml ├── geetest.xaml.cs ├── index.xaml ├── index.xaml.cs ├── login.xaml ├── login.xaml.cs ├── packages.config ├── packages.zip ├── resource ├── Web │ └── geetest-validator │ │ ├── css │ │ └── style.css │ │ ├── geetest.html │ │ └── js │ │ ├── gt.js │ │ └── jquery.js └── img │ ├── BILIBILI_LOGO-PINK.png │ ├── BILIBILI_LOGO.png │ ├── Bilibili_User_Cover.png │ ├── PILIPILI_LOGO.png │ ├── cover.jpg │ ├── exported_qrcode_image_600.png │ ├── preview1.png │ ├── preview2.png │ ├── preview3.png │ ├── preview4.png │ ├── 二维码.png │ ├── 头像.png │ ├── 弹幕数.png │ ├── 播放量.png │ ├── 收藏数.png │ ├── 点赞数.png │ ├── 硬币数.png │ ├── 评论数.png │ ├── 账号.png │ ├── 转发数.png │ ├── 返回.png │ └── 频道.png ├── video.xaml └── video.xaml.cs /.gitattributes: -------------------------------------------------------------------------------- 1 | # Auto detect text files and perform LF normalization 2 | * text=auto 3 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | ## Ignore Visual Studio temporary files, build results, and 2 | ## files generated by popular Visual Studio add-ons. 3 | ## 4 | ## Get latest from https://github.com/github/gitignore/blob/master/VisualStudio.gitignore 5 | 6 | # User-specific files 7 | *.rsuser 8 | *.suo 9 | *.user 10 | *.userosscache 11 | *.sln.docstates 12 | 13 | # User-specific files (MonoDevelop/Xamarin Studio) 14 | *.userprefs 15 | 16 | # Mono auto generated files 17 | mono_crash.* 18 | 19 | # Build results 20 | [Dd]ebug/ 21 | [Dd]ebugPublic/ 22 | [Rr]elease/ 23 | [Rr]eleases/ 24 | x64/ 25 | x86/ 26 | [Aa][Rr][Mm]/ 27 | [Aa][Rr][Mm]64/ 28 | bld/ 29 | [Bb]in/ 30 | [Oo]bj/ 31 | [Ll]og/ 32 | [Ll]ogs/ 33 | 34 | # Visual Studio 2015/2017 cache/options directory 35 | .vs/ 36 | # Uncomment if you have tasks that create the project's static files in wwwroot 37 | #wwwroot/ 38 | 39 | # Visual Studio 2017 auto generated files 40 | Generated\ Files/ 41 | 42 | # MSTest test Results 43 | [Tt]est[Rr]esult*/ 44 | [Bb]uild[Ll]og.* 45 | 46 | # NUnit 47 | *.VisualState.xml 48 | TestResult.xml 49 | nunit-*.xml 50 | 51 | # Build Results of an ATL Project 52 | [Dd]ebugPS/ 53 | [Rr]eleasePS/ 54 | dlldata.c 55 | 56 | # Benchmark Results 57 | BenchmarkDotNet.Artifacts/ 58 | 59 | # .NET Core 60 | project.lock.json 61 | project.fragment.lock.json 62 | artifacts/ 63 | 64 | # StyleCop 65 | StyleCopReport.xml 66 | 67 | # Files built by Visual Studio 68 | *_i.c 69 | *_p.c 70 | *_h.h 71 | *.ilk 72 | *.meta 73 | *.obj 74 | *.iobj 75 | *.pch 76 | *.pdb 77 | *.ipdb 78 | *.pgc 79 | *.pgd 80 | *.rsp 81 | *.sbr 82 | *.tlb 83 | *.tli 84 | *.tlh 85 | *.tmp 86 | *.tmp_proj 87 | *_wpftmp.csproj 88 | *.log 89 | *.vspscc 90 | *.vssscc 91 | .builds 92 | *.pidb 93 | *.svclog 94 | *.scc 95 | 96 | # Chutzpah Test files 97 | _Chutzpah* 98 | 99 | # Visual C++ cache files 100 | ipch/ 101 | *.aps 102 | *.ncb 103 | *.opendb 104 | *.opensdf 105 | *.sdf 106 | *.cachefile 107 | *.VC.db 108 | *.VC.VC.opendb 109 | 110 | # Visual Studio profiler 111 | *.psess 112 | *.vsp 113 | *.vspx 114 | *.sap 115 | 116 | # Visual Studio Trace Files 117 | *.e2e 118 | 119 | # TFS 2012 Local Workspace 120 | $tf/ 121 | 122 | # Guidance Automation Toolkit 123 | *.gpState 124 | 125 | # ReSharper is a .NET coding add-in 126 | _ReSharper*/ 127 | *.[Rr]e[Ss]harper 128 | *.DotSettings.user 129 | 130 | # JustCode is a .NET coding add-in 131 | .JustCode 132 | 133 | # TeamCity is a build add-in 134 | _TeamCity* 135 | 136 | # DotCover is a Code Coverage Tool 137 | *.dotCover 138 | 139 | # AxoCover is a Code Coverage Tool 140 | .axoCover/* 141 | !.axoCover/settings.json 142 | 143 | # Visual Studio code coverage results 144 | *.coverage 145 | *.coveragexml 146 | 147 | # NCrunch 148 | _NCrunch_* 149 | .*crunch*.local.xml 150 | nCrunchTemp_* 151 | 152 | # MightyMoose 153 | *.mm.* 154 | AutoTest.Net/ 155 | 156 | # Web workbench (sass) 157 | .sass-cache/ 158 | 159 | # Installshield output folder 160 | [Ee]xpress/ 161 | 162 | # DocProject is a documentation generator add-in 163 | DocProject/buildhelp/ 164 | DocProject/Help/*.HxT 165 | DocProject/Help/*.HxC 166 | DocProject/Help/*.hhc 167 | DocProject/Help/*.hhk 168 | DocProject/Help/*.hhp 169 | DocProject/Help/Html2 170 | DocProject/Help/html 171 | 172 | # Click-Once directory 173 | publish/ 174 | 175 | # Publish Web Output 176 | *.[Pp]ublish.xml 177 | *.azurePubxml 178 | # Note: Comment the next line if you want to checkin your web deploy settings, 179 | # but database connection strings (with potential passwords) will be unencrypted 180 | *.pubxml 181 | *.publishproj 182 | 183 | # Microsoft Azure Web App publish settings. Comment the next line if you want to 184 | # checkin your Azure Web App publish settings, but sensitive information contained 185 | # in these scripts will be unencrypted 186 | PublishScripts/ 187 | 188 | # NuGet Packages 189 | *.nupkg 190 | # NuGet Symbol Packages 191 | *.snupkg 192 | # The packages folder can be ignored because of Package Restore 193 | **/[Pp]ackages/* 194 | # except build/, which is used as an MSBuild target. 195 | !**/[Pp]ackages/build/ 196 | # Uncomment if necessary however generally it will be regenerated when needed 197 | #!**/[Pp]ackages/repositories.config 198 | # NuGet v3's project.json files produces more ignorable files 199 | *.nuget.props 200 | *.nuget.targets 201 | 202 | # Microsoft Azure Build Output 203 | csx/ 204 | *.build.csdef 205 | 206 | # Microsoft Azure Emulator 207 | ecf/ 208 | rcf/ 209 | 210 | # Windows Store app package directories and files 211 | AppPackages/ 212 | BundleArtifacts/ 213 | Package.StoreAssociation.xml 214 | _pkginfo.txt 215 | *.appx 216 | *.appxbundle 217 | *.appxupload 218 | 219 | # Visual Studio cache files 220 | # files ending in .cache can be ignored 221 | *.[Cc]ache 222 | # but keep track of directories ending in .cache 223 | !?*.[Cc]ache/ 224 | 225 | # Others 226 | ClientBin/ 227 | ~$* 228 | *~ 229 | *.dbmdl 230 | *.dbproj.schemaview 231 | *.jfm 232 | *.pfx 233 | *.publishsettings 234 | orleans.codegen.cs 235 | 236 | # Including strong name files can present a security risk 237 | # (https://github.com/github/gitignore/pull/2483#issue-259490424) 238 | #*.snk 239 | 240 | # Since there are multiple workflows, uncomment next line to ignore bower_components 241 | # (https://github.com/github/gitignore/pull/1529#issuecomment-104372622) 242 | #bower_components/ 243 | 244 | # RIA/Silverlight projects 245 | Generated_Code/ 246 | 247 | # Backup & report files from converting an old project file 248 | # to a newer Visual Studio version. Backup files are not needed, 249 | # because we have git ;-) 250 | _UpgradeReport_Files/ 251 | Backup*/ 252 | UpgradeLog*.XML 253 | UpgradeLog*.htm 254 | ServiceFabricBackup/ 255 | *.rptproj.bak 256 | 257 | # SQL Server files 258 | *.mdf 259 | *.ldf 260 | *.ndf 261 | 262 | # Business Intelligence projects 263 | *.rdl.data 264 | *.bim.layout 265 | *.bim_*.settings 266 | *.rptproj.rsuser 267 | *- [Bb]ackup.rdl 268 | *- [Bb]ackup ([0-9]).rdl 269 | *- [Bb]ackup ([0-9][0-9]).rdl 270 | 271 | # Microsoft Fakes 272 | FakesAssemblies/ 273 | 274 | # GhostDoc plugin setting file 275 | *.GhostDoc.xml 276 | 277 | # Node.js Tools for Visual Studio 278 | .ntvs_analysis.dat 279 | node_modules/ 280 | 281 | # Visual Studio 6 build log 282 | *.plg 283 | 284 | # Visual Studio 6 workspace options file 285 | *.opt 286 | 287 | # Visual Studio 6 auto-generated workspace file (contains which files were open etc.) 288 | *.vbw 289 | 290 | # Visual Studio LightSwitch build output 291 | **/*.HTMLClient/GeneratedArtifacts 292 | **/*.DesktopClient/GeneratedArtifacts 293 | **/*.DesktopClient/ModelManifest.xml 294 | **/*.Server/GeneratedArtifacts 295 | **/*.Server/ModelManifest.xml 296 | _Pvt_Extensions 297 | 298 | # Paket dependency manager 299 | .paket/paket.exe 300 | paket-files/ 301 | 302 | # FAKE - F# Make 303 | .fake/ 304 | 305 | # CodeRush personal settings 306 | .cr/personal 307 | 308 | # Python Tools for Visual Studio (PTVS) 309 | __pycache__/ 310 | *.pyc 311 | 312 | # Cake - Uncomment if you are using it 313 | # tools/** 314 | # !tools/packages.config 315 | 316 | # Tabs Studio 317 | *.tss 318 | 319 | # Telerik's JustMock configuration file 320 | *.jmconfig 321 | 322 | # BizTalk build output 323 | *.btp.cs 324 | *.btm.cs 325 | *.odx.cs 326 | *.xsd.cs 327 | 328 | # OpenCover UI analysis results 329 | OpenCover/ 330 | 331 | # Azure Stream Analytics local run output 332 | ASALocalRun/ 333 | 334 | # MSBuild Binary and Structured Log 335 | *.binlog 336 | 337 | # NVidia Nsight GPU debugger configuration file 338 | *.nvuser 339 | 340 | # MFractors (Xamarin productivity tool) working folder 341 | .mfractor/ 342 | 343 | # Local History for Visual Studio 344 | .localhistory/ 345 | 346 | # BeatPulse healthcheck temp database 347 | healthchecksdb 348 | 349 | # Backup folder for Package Reference Convert tool in Visual Studio 2017 350 | MigrationBackup/ 351 | 352 | # Ionide (cross platform F# VS Code tools) working folder 353 | .ionide/ 354 | -------------------------------------------------------------------------------- /App.config: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /App.xaml: -------------------------------------------------------------------------------- 1 |  6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | -------------------------------------------------------------------------------- /App.xaml.cs: -------------------------------------------------------------------------------- 1 | using HandyControl.Data; 2 | using HandyControl.Tools; 3 | using System; 4 | using System.Collections.Generic; 5 | using System.Configuration; 6 | using System.Data; 7 | using System.Linq; 8 | using System.Management; 9 | using System.Threading.Tasks; 10 | using System.Windows; 11 | using Unosquare.FFME; 12 | 13 | namespace Bilibili_Client 14 | { 15 | /// 16 | /// App.xaml 的交互逻辑 17 | /// 18 | public partial class App : Application 19 | { 20 | protected override void OnStartup(StartupEventArgs e) 21 | { 22 | //if (Environment.Is64BitProcess) 23 | // Library.FFmpegDirectory = @"resource\FFmpeg\x64"; 24 | //else 25 | // Library.FFmpegDirectory = @"resource\FFmpeg\x86"; 26 | Library.FFmpegDirectory = @"resource\FFmpeg\"; 27 | Library.LoadFFmpeg(); 28 | MediaElement.FFmpegMessageLogged += (s, ev) => 29 | { 30 | System.Diagnostics.Debug.WriteLine(ev.Message); 31 | }; 32 | base.OnStartup(e); 33 | 34 | } 35 | } 36 | 37 | } 38 | -------------------------------------------------------------------------------- /BiliClass.cs: -------------------------------------------------------------------------------- 1 | using Newtonsoft.Json; 2 | using Newtonsoft.Json.Linq; 3 | using RestSharp; 4 | using System; 5 | using System.Drawing.Imaging; 6 | using System.IO; 7 | using System.Linq; 8 | using System.Security.Cryptography; 9 | using System.Text; 10 | using System.Text.RegularExpressions; 11 | using System.Windows; 12 | using System.Windows.Media; 13 | using System.Windows.Media.Imaging; 14 | using System.Windows.Threading; 15 | namespace Bilibili_Client 16 | { 17 | public class Bilibili_Login//哔哩哔哩登录类 18 | 19 | { 20 | public DispatcherTimer Get_Scan_Login_Qrcode_status_Timer; 21 | public login Scan_login; 22 | public string Scan_oauthKey; 23 | 24 | //哔哩哔哩验证密钥类 25 | public class Verification_Key 26 | { 27 | public string gt; 28 | public string challenge; 29 | public string key; 30 | public string seccode; 31 | public string validate; 32 | public string tmp_code; 33 | public string phone; 34 | public int Sms_type = 0; 35 | } 36 | 37 | //哔哩哔哩Cookie类 38 | public class BiliCookie 39 | { 40 | public string DedeUserID; 41 | public string SESSDATA; 42 | public string bili_jct; 43 | } 44 | 45 | //获取结果的Cooie 46 | public BiliCookie Get_Cookie(string response) 47 | { 48 | BiliCookie biliCookie = new BiliCookie(); 49 | biliCookie.DedeUserID = new Regex(@"DedeUserID=(?.*?)[&|;]", RegexOptions.IgnoreCase).Match(response).Groups["DedeUserID"].Value; 50 | biliCookie.SESSDATA = new Regex(@"SESSDATA=(?.*?)[&|;]", RegexOptions.IgnoreCase).Match(response).Groups["SESSDATA"].Value; 51 | biliCookie.bili_jct = new Regex(@"bili_jct=(?.*?)[&|;]", RegexOptions.IgnoreCase).Match(response).Groups["bili_jct"].Value; 52 | return biliCookie; 53 | } 54 | 55 | //获取登录Hash 56 | public string Password_login_Get_Hash() 57 | { 58 | var client = new RestClient("http://passport.bilibili.com/login?act=getkey"); 59 | client.Timeout = -1; 60 | var request = new RestRequest(Method.GET); 61 | IRestResponse response = client.Execute(request); 62 | JObject recommend = (JObject)JsonConvert.DeserializeObject(response.Content); 63 | client = null; 64 | request = null; 65 | response = null; 66 | return recommend["hash"].ToString(); 67 | } 68 | 69 | //获取极验密钥 70 | public Verification_Key Get_Verification_Key(int plat) 71 | { 72 | Verification_Key verification_key = new Verification_Key(); 73 | var client = new RestClient("http://passport.bilibili.com/web/captcha/combine?plat=" + plat); 74 | client.Timeout = -1; 75 | var request = new RestRequest(Method.GET); 76 | IRestResponse response = client.Execute(request); 77 | JObject recommend = (JObject)JsonConvert.DeserializeObject(response.Content); 78 | verification_key.gt = recommend["data"]["result"]["gt"].ToString(); 79 | verification_key.challenge = recommend["data"]["result"]["challenge"].ToString(); 80 | verification_key.key = recommend["data"]["result"]["key"].ToString(); 81 | client = null; 82 | request = null; 83 | response = null; 84 | recommend = null; 85 | return verification_key; 86 | } 87 | 88 | //(网页接口)密码登录 89 | public void Password_login_Web(string username, string password, string hash, Verification_Key verification_key, login login) 90 | { 91 | 92 | Coding coding = new Coding(); 93 | var rsa = new RSACryptoServiceProvider(); 94 | var public_key = @"MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDjb4V7EidX/ym28t2ybo0U6t0n 95 | 6p4ej8VjqKHg100va6jkNbNTrLQqMCQCAYtXMXXp2Fwkk6WR+12N9zknLjf+C9sx 96 | /+l48mjUU8RqahiFD1XT/u2e0m2EN029OhCgkHx3Fc/KlFSIbak93EH/XlYis0w+ 97 | Xl69GV6klzgxW6d2xQIDAQAB"; 98 | rsa.FromX509PublicKey(Convert.FromBase64String(public_key)); 99 | var bytes = Convert.ToBase64String(rsa.Encrypt(Encoding.UTF8.GetBytes("mangohappy"), false)); 100 | var client = new RestClient("http://passport.bilibili.com/web/login/v2"); 101 | client.Timeout = -1; 102 | var request = new RestRequest(Method.POST); 103 | request.AddHeader("Content-Type", "application/x-www-form-urlencoded"); 104 | request.AddParameter("captchaType", "6"); 105 | request.AddParameter("username", username); 106 | request.AddParameter("password", Convert.ToBase64String(rsa.Encrypt(Encoding.UTF8.GetBytes(hash + password), false))); 107 | request.AddParameter("keep", "true"); 108 | request.AddParameter("key", verification_key.key); 109 | request.AddParameter("goUrl", coding.UrlEncode("https://www.bilibili.com/")); 110 | request.AddParameter("challenge", verification_key.challenge); 111 | request.AddParameter("validate", verification_key.validate); 112 | request.AddParameter("seccode", verification_key.seccode); 113 | IRestResponse response = client.Execute(request); 114 | JObject recommend = (JObject)JsonConvert.DeserializeObject(response.Content); 115 | string code = recommend["code"].ToString(); 116 | if (string.Equals(code, "-2111")) 117 | { 118 | MessageBox.Show("由于您已开启二次验证,二次验证API出了点问题,请改用扫码或者验证码登录,抱歉了"); 119 | /*Verification_Key Double_verification_key = Get_Verification_Key(7); 120 | Double_verification_key.Sms_type = 18; 121 | Double_verification_key.tmp_code = (recommend["data"].ToString()).Substring((recommend["data"].ToString()).IndexOf("tmp_token=") + 10, 32);*/ 122 | login.Password_Login.Visibility = Visibility.Hidden; 123 | login.Sms_Code_Login.Visibility = Visibility.Visible; 124 | /*login.phone_textbox.Text = Double_verification_key.tmp_code; 125 | login.phone_textbox.IsReadOnly = true; 126 | login.Sms_code_Send_buttons.Content = "请验证"; 127 | login.Sms_code_Send_buttons.IsEnabled = false; 128 | login.Sms_Login_button.Content = "请验证"; 129 | login.Sms_Login_button.IsEnabled = false; 130 | login.sendKey_To_Geetest_page(Double_verification_key);*/ 131 | 132 | } 133 | else if (string.Equals(code, "0")) 134 | { 135 | BiliCookie biliCookie = Get_Cookie(response.Content); 136 | Login_Success(biliCookie, login); 137 | 138 | } 139 | else 140 | { 141 | MessageBox.Show(response.Content); 142 | } 143 | client = null; 144 | request = null; 145 | response = null; 146 | recommend = null; 147 | code = null; 148 | } 149 | 150 | //发送手机验证码 151 | public void Send_Sms(Verification_Key verification_key, login login) 152 | { 153 | if (verification_key.Sms_type == 18)//二次验证 154 | { 155 | var client = new RestClient("https://api.bilibili.com/x/safecenter/sms/send"); 156 | client.Timeout = -1; 157 | var request = new RestRequest(Method.POST); 158 | request.AddParameter("application/x-www-form-urlencoded", 159 | "type=18&captchaType=7" + 160 | "&captcha_key=" + verification_key.key + 161 | "&challenge=" + verification_key.challenge + 162 | "&validate=" + verification_key.validate + 163 | "&seccode=" + verification_key.seccode + 164 | "&tmp_code=" + verification_key.tmp_code 165 | , ParameterType.RequestBody); 166 | IRestResponse response = client.Execute(request); 167 | MessageBox.Show(response.Content); 168 | JObject recommend = (JObject)JsonConvert.DeserializeObject(response.Content); 169 | string code = recommend["code"].ToString(); 170 | if (!string.Equals(code, "0")) 171 | { 172 | login.Sms_code_Send_buttons.Content = "失败"; 173 | } 174 | client = null; 175 | request = null; 176 | response = null; 177 | recommend = null; 178 | code = null; 179 | } 180 | else if (verification_key.Sms_type == 21)//验证码登录 181 | { 182 | var client = new RestClient("http://passport.bilibili.com/web/sms/general/v2/send"); 183 | client.Timeout = -1; 184 | var request = new RestRequest(Method.POST); 185 | request.AddParameter("application/x-www-form-urlencoded", 186 | "tel=" + verification_key.phone + 187 | "&cid=1&type=21&captchaType=6" + 188 | "&key=" + verification_key.key + 189 | "&challenge=" + verification_key.challenge + 190 | "&validate=" + verification_key.validate + 191 | "&seccode=" + verification_key.seccode, ParameterType.RequestBody); 192 | IRestResponse response = client.Execute(request); 193 | JObject recommend = (JObject)JsonConvert.DeserializeObject(response.Content); 194 | string code = recommend["code"].ToString(); 195 | if (!string.Equals(code, "0")) 196 | { 197 | MessageBox.Show(response.Content); 198 | login.Sms_code_Send_buttons.Content = "发送"; 199 | } 200 | else if (string.Equals(code, "0")) 201 | { 202 | login.Sms_code_Send_buttons.Content = "重发"; 203 | login.Sms_Login_button.IsEnabled = true; 204 | 205 | } 206 | client = null; 207 | request = null; 208 | response = null; 209 | recommend = null; 210 | code = null; 211 | 212 | } 213 | } 214 | 215 | //手机验证码登录 216 | public void Sms_login(string Sms_Code, string ID, login login) 217 | { 218 | var client = new RestClient("http://passport.bilibili.com/web/login/rapid"); 219 | client.Timeout = -1; 220 | var request = new RestRequest(Method.POST); 221 | request.AddHeader("Content-Type", "application/x-www-form-urlencoded"); 222 | request.AddHeader("Cookie", "sid=jd5w5fmn"); 223 | request.AddParameter("cid", 1); 224 | request.AddParameter("tel", ID); 225 | request.AddParameter("smsCode", Sms_Code); 226 | IRestResponse response = client.Execute(request); 227 | JObject recommend = (JObject)JsonConvert.DeserializeObject(response.Content); 228 | string code = recommend["code"].ToString(); 229 | if (!string.Equals(code, "0")) 230 | { 231 | MessageBox.Show(response.Content); 232 | } 233 | else if (string.Equals(code, "0")) 234 | { 235 | BiliCookie biliCookie = Get_Cookie(response.Headers[4].ToString()); 236 | Login_Success(biliCookie, login); 237 | 238 | } 239 | client = null; 240 | request = null; 241 | response = null; 242 | recommend = null; 243 | code = null; 244 | } 245 | 246 | //获取登录二维码 247 | public void Get_Login_Qrcode(login login) 248 | { 249 | var client = new RestClient("http://passport.bilibili.com/qrcode/getLoginUrl"); 250 | client.Timeout = -1; 251 | var request = new RestRequest(Method.GET); 252 | IRestResponse response = client.Execute(request); 253 | Console.WriteLine(response.Content); 254 | JObject recommend = (JObject)JsonConvert.DeserializeObject(response.Content); 255 | string url = recommend["data"]["url"].ToString(); 256 | string oauthKey = recommend["data"]["oauthKey"].ToString(); 257 | login.Qrcode_img.Source = login.NewQRCodeByThoughtWorks(url, ImageFormat.Png); 258 | Scan_login = login; 259 | Scan_oauthKey = oauthKey; 260 | Get_Scan_Login_Qrcode_status_Timer = new DispatcherTimer(); 261 | Get_Scan_Login_Qrcode_status_Timer.Tick += new EventHandler(Get_Scan_Login_Qrcode_status); 262 | Get_Scan_Login_Qrcode_status_Timer.Interval = new TimeSpan(0, 0, 0, 1); 263 | Get_Scan_Login_Qrcode_status_Timer.Start(); 264 | url = null; 265 | oauthKey = null; 266 | client = null; 267 | request = null; 268 | response = null; 269 | recommend = null; 270 | } 271 | 272 | //获取登录二维码的扫码状态 273 | public void Get_Scan_Login_Qrcode_status(object sender, EventArgs e) 274 | { 275 | 276 | var client = new RestClient("http://passport.bilibili.com/qrcode/getLoginInfo"); 277 | var request = new RestRequest(Method.POST); 278 | request.AddHeader("Content-Type", "application/x-www-form-urlencoded"); 279 | request.AddParameter("oauthKey", Scan_oauthKey); 280 | IRestResponse response = client.Execute(request); 281 | JObject recommend = (JObject)JsonConvert.DeserializeObject(response.Content); 282 | if (string.Equals(recommend["status"].ToString(), "True")) 283 | { 284 | BiliCookie biliCookie = Get_Cookie(recommend["data"]["url"].ToString()); 285 | Qrcode_Login(biliCookie, Scan_login); 286 | Get_Scan_Login_Qrcode_status_Timer.Stop(); 287 | Get_Scan_Login_Qrcode_status_Timer = null; 288 | } 289 | else if (string.Equals(recommend["status"].ToString(), "False")) 290 | { 291 | string data = recommend["data"].ToString(); 292 | if (string.Equals(data, "-5")) 293 | { 294 | Scan_login.Scan_status.Text = "扫描成功,请在手机上确认是否授权"; 295 | Scan_login.Scan_status.Foreground = new SolidColorBrush(System.Windows.Media.Color.FromRgb(33, 211, 97)); 296 | } 297 | else if (string.Equals(data, "-4")) 298 | { 299 | Scan_login.Scan_status.Text = "请使用 哔哩哔哩客户端 扫码登录"; 300 | Scan_login.Scan_status.Foreground = new SolidColorBrush(System.Windows.Media.Color.FromRgb(251, 114, 153)); 301 | } 302 | else if (string.Equals(data, "-2")) 303 | { 304 | Scan_login.Scan_status.Text = "二维码已失效,请点击二维码刷新"; 305 | Scan_login.Scan_status.Foreground = new SolidColorBrush(System.Windows.Media.Color.FromRgb(208, 2, 27)); 306 | Get_Scan_Login_Qrcode_status_Timer.Stop(); 307 | Get_Scan_Login_Qrcode_status_Timer =null; 308 | 309 | } 310 | } 311 | client = null; 312 | request = null; 313 | response = null; 314 | recommend = null; 315 | } 316 | 317 | //二维码登录 318 | public void Qrcode_Login(BiliCookie biliCookie, login login) 319 | { 320 | Login_Success(biliCookie, login); 321 | 322 | } 323 | 324 | //登录成功后的操作 325 | public void Login_Success(BiliCookie biliCookie, login login) 326 | { 327 | if (false == Directory.Exists(@"Data\User\Account\Cookie")) 328 | { 329 | Directory.CreateDirectory(@"Data\User\Account\Cookie"); 330 | } 331 | File.WriteAllText(@"Data\User\Account\Cookie\Login_User.Json", JsonConvert.SerializeObject(biliCookie), Encoding.UTF8); 332 | login.Login_Success(); 333 | 334 | } 335 | 336 | } 337 | 338 | public class Bilibili_Account//哔哩哔哩账户类 339 | { 340 | public class BiliCookie 341 | { 342 | public string DedeUserID; 343 | public string SESSDATA; 344 | public string bili_jct; 345 | } 346 | public bool Check_Login_status() 347 | { 348 | if (File.Exists(@"Data\User\Account\Cookie\Login_User.Json"))//如果存在用户数据文件 349 | { 350 | string Login_User_Json = File.ReadAllText(@"Data\User\Account\Cookie\Login_User.Json"); 351 | var client = new RestClient("http://api.bilibili.com/x/web-interface/nav"); 352 | var request = new RestRequest(Method.GET); 353 | request.AddCookie("SESSDATA", ((JObject)JsonConvert.DeserializeObject(Login_User_Json))["SESSDATA"].ToString()); 354 | IRestResponse response = client.Execute(request); 355 | if (string.Equals(((JObject)JsonConvert.DeserializeObject(response.Content))["code"].ToString(), "0")) 356 | { 357 | client = null; 358 | request = null; 359 | response = null; 360 | return true; 361 | } 362 | else 363 | { 364 | client = null; 365 | request = null; 366 | response = null; 367 | return false; 368 | } 369 | } 370 | else 371 | { 372 | return false; 373 | } 374 | 375 | } 376 | public void Set_User_Data(MainWindow mainWindow) 377 | { 378 | string Login_User_Json = File.ReadAllText(@"Data\User\Account\Cookie\Login_User.Json"); 379 | mainWindow.BiliCookie.SESSDATA = ((JObject)JsonConvert.DeserializeObject(Login_User_Json))["SESSDATA"].ToString(); 380 | mainWindow.BiliCookie.DedeUserID = ((JObject)JsonConvert.DeserializeObject(Login_User_Json))["DedeUserID"].ToString(); 381 | mainWindow.BiliCookie.bili_jct = ((JObject)JsonConvert.DeserializeObject(Login_User_Json))["bili_jct"].ToString(); 382 | var client = new RestClient("http://api.bilibili.com/x/web-interface/nav"); 383 | var request = new RestRequest(Method.GET); 384 | request.AddCookie("SESSDATA", mainWindow.BiliCookie.SESSDATA); 385 | IRestResponse response = client.Execute(request); 386 | JObject recommend = (JObject)JsonConvert.DeserializeObject(response.Content); 387 | JToken data = recommend["data"]; 388 | string User_Cover = data["face"].ToString(); 389 | string User_Name = data["uname"].ToString(); 390 | mainWindow.Login_Button.Visibility = Visibility.Hidden; 391 | mainWindow.User_Name_Grid.Visibility = Visibility.Visible; 392 | mainWindow.User_SideMenu.Visibility = Visibility.Visible; 393 | mainWindow.User_Name_Label.Text = User_Name; 394 | mainWindow.User_Cover_Img.Source = new BitmapImage(new Uri(User_Cover, UriKind.RelativeOrAbsolute)); 395 | mainWindow.User_Exp_Bar.Value = (data["level_info"]["current_exp"].ToObject() / data["level_info"]["current_min"].ToObject()) * 100; 396 | client = null; 397 | request = null; 398 | response = null; 399 | User_Name = null; 400 | User_Cover = null; 401 | data = null; 402 | recommend = null; 403 | } 404 | public string Get_User_Data(string str1, string str2, bool If_Doubel, MainWindow mainWindow) 405 | { 406 | string SESSDATA = mainWindow.BiliCookie.SESSDATA; 407 | if (If_Doubel) 408 | { 409 | var client = new RestClient("http://api.bilibili.com/x/web-interface/nav"); 410 | var request = new RestRequest(Method.GET); 411 | request.AddCookie("SESSDATA", SESSDATA); 412 | IRestResponse response = client.Execute(request); 413 | client = null; 414 | request = null; 415 | return ((JObject)JsonConvert.DeserializeObject(response.Content))["data"][str1][str2].ToString(); 416 | } 417 | else 418 | { 419 | var client = new RestClient("http://api.bilibili.com/x/web-interface/nav"); 420 | var request = new RestRequest(Method.GET); 421 | request.AddCookie("SESSDATA", SESSDATA); 422 | IRestResponse response = client.Execute(request); 423 | client = null; 424 | request = null; 425 | return ((JObject)JsonConvert.DeserializeObject(response.Content))["data"][str1].ToString(); 426 | } 427 | 428 | 429 | 430 | } 431 | 432 | 433 | } 434 | 435 | public class Bilibili_Video 436 | { 437 | public struct video_info 438 | { 439 | public bool Success; 440 | public string aid;//视频avID 441 | public string bvid;//视频bvID 442 | public int videos;//视频分P总数 443 | public int tid;//分区ID 444 | public string tname;//子分区名称 445 | public int copyright;//版权标志 1:自制 2:转载 446 | public string pic;//视频封面图片url 447 | public string title;//视频标题 448 | public string ctime;//视频审核通过时间 449 | public string desc;//视频简介 450 | public string mid;//UP主UID 451 | public string name;//UP主昵称 452 | public string face;//UP主头像 453 | public int view;//观看次数 普通:0 屏蔽时:-1 454 | public int danmaku;//弹幕数 455 | public int reply;//评论数 456 | public int favorite;//收藏数 457 | public int coin;//投币数 458 | public int share;//分享数 459 | public int like;//获赞数 460 | public pages[] pages; 461 | } 462 | public struct pages//视频分P列表 463 | { 464 | public string cid;//当前分P CID 465 | public int page;//当前分P 466 | public string part;//当前分P标题 467 | } 468 | public struct P_data 469 | { 470 | public bool Success; 471 | public string url; 472 | public string[] accept_description; 473 | public int[] accept_quality; 474 | } 475 | public video_info gets_video_info(string aid) 476 | { 477 | var client = new RestClient("http://api.bilibili.com/x/web-interface/view?aid=" + aid); 478 | client.Timeout = -1; 479 | var request = new RestRequest(Method.GET); 480 | IRestResponse response = client.Execute(request); 481 | JObject recommend = (JObject)JsonConvert.DeserializeObject(response.Content); 482 | video_info videoinfo = new video_info(); 483 | JToken data = recommend["data"]; 484 | if (Convert.ToInt32(recommend["code"]) == 0) 485 | { 486 | videoinfo.Success = true; 487 | videoinfo.aid = aid; 488 | videoinfo.bvid = data["bvid"].ToString(); 489 | videoinfo.videos = Convert.ToInt32(data["videos"]); 490 | videoinfo.tid= Convert.ToInt32(data["tid"]); 491 | videoinfo.tname = data["tname"].ToString(); 492 | videoinfo.copyright = Convert.ToInt32(data["copyright"]); 493 | videoinfo.pic = data["pic"].ToString(); 494 | videoinfo.title = data["title"].ToString(); 495 | videoinfo.ctime = data["ctime"].ToString(); 496 | videoinfo.desc = data["desc"].ToString(); 497 | videoinfo.mid= data["owner"]["mid"].ToString(); 498 | videoinfo.name = data["owner"]["name"].ToString(); 499 | videoinfo.face = data["owner"]["face"].ToString(); 500 | videoinfo.view = Convert.ToInt32(data["stat"]["view"]); 501 | videoinfo.danmaku = Convert.ToInt32(data["stat"]["danmaku"]); 502 | videoinfo.reply = Convert.ToInt32(data["stat"]["reply"]); 503 | videoinfo.favorite = Convert.ToInt32(data["stat"]["favorite"]); 504 | videoinfo.coin = Convert.ToInt32(data["stat"]["coin"]); 505 | videoinfo.share = Convert.ToInt32(data["stat"]["share"]); 506 | videoinfo.like = Convert.ToInt32(data["stat"]["like"]); 507 | videoinfo.pages = new pages[videoinfo.videos]; 508 | for(int i=0;i 2 | 3 | 4 | 5 | Debug 6 | AnyCPU 7 | {A871B3C0-D4C9-43ED-91D8-0F0770C8D282} 8 | WinExe 9 | Bilibili_Client 10 | Bilibili_Client 11 | v4.7.2 12 | 512 13 | {60dc8134-eba5-43b8-bcc9-bb4bc16c2548};{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC} 14 | 4 15 | true 16 | true 17 | false 18 | publish\ 19 | true 20 | Disk 21 | false 22 | Foreground 23 | 7 24 | Days 25 | false 26 | false 27 | true 28 | 1 29 | 1.0.0.%2a 30 | false 31 | true 32 | true 33 | 34 | 35 | AnyCPU 36 | false 37 | none 38 | true 39 | bin\Debug\ 40 | DEBUG;TRACE 41 | prompt 42 | 4 43 | Off 44 | true 45 | 46 | 47 | AnyCPU 48 | pdbonly 49 | true 50 | bin\Release\ 51 | TRACE 52 | prompt 53 | 4 54 | 55 | 56 | true 57 | bin\x64\Debug\ 58 | DEBUG;TRACE 59 | full 60 | x64 61 | 7.3 62 | prompt 63 | MinimumRecommendedRules.ruleset 64 | true 65 | 66 | 67 | bin\x64\Release\ 68 | TRACE 69 | true 70 | pdbonly 71 | x64 72 | 7.3 73 | prompt 74 | MinimumRecommendedRules.ruleset 75 | true 76 | 77 | 78 | Bilibili_Client.App 79 | 80 | 81 | 992250BCF539864B5D8D75A20EB695D5E851B07D 82 | 83 | 84 | Bilibili_Client_TemporaryKey.pfx 85 | 86 | 87 | true 88 | 89 | 90 | LocalIntranet 91 | 92 | 93 | 94 | true 95 | 96 | 97 | 98 | 99 | packages\CommonServiceLocator.2.0.2\lib\net47\CommonServiceLocator.dll 100 | 101 | 102 | packages\FFME.Windows.4.2.330\lib\net472\ffme.win.dll 103 | 104 | 105 | packages\FFmpeg.AutoGen.4.2.0\lib\net45\FFmpeg.AutoGen.dll 106 | 107 | 108 | packages\MvvmLightLibs.5.4.1.1\lib\net45\GalaSoft.MvvmLight.dll 109 | 110 | 111 | packages\MvvmLightLibs.5.4.1.1\lib\net45\GalaSoft.MvvmLight.Extras.dll 112 | 113 | 114 | packages\MvvmLightLibs.5.4.1.1\lib\net45\GalaSoft.MvvmLight.Platform.dll 115 | 116 | 117 | packages\HandyControl.2.5.0.2\lib\net47\HandyControl.dll 118 | False 119 | 120 | 121 | packages\Microsoft.Xaml.Behaviors.Wpf.1.1.19\lib\net45\Microsoft.Xaml.Behaviors.dll 122 | 123 | 124 | packages\Newtonsoft.Json.12.0.3\lib\net45\Newtonsoft.Json.dll 125 | 126 | 127 | packages\Prism.Core.7.2.0.1422\lib\net45\Prism.dll 128 | 129 | 130 | packages\RestSharp.106.11.4\lib\net452\RestSharp.dll 131 | 132 | 133 | 134 | packages\System.Buffers.4.4.0\lib\netstandard2.0\System.Buffers.dll 135 | 136 | 137 | 138 | 139 | packages\System.Extended.3.4.16.616\lib\net40\System.Extended.dll 140 | 141 | 142 | 143 | packages\System.Runtime.CompilerServices.Unsafe.4.5.2\lib\netstandard2.0\System.Runtime.CompilerServices.Unsafe.dll 144 | 145 | 146 | packages\System.ValueTuple.4.5.0\lib\net47\System.ValueTuple.dll 147 | 148 | 149 | 150 | 151 | packages\MvvmLightLibs.5.4.1.1\lib\net45\System.Windows.Interactivity.dll 152 | 153 | 154 | 155 | 156 | 157 | 158 | 159 | 160 | 4.0 161 | 162 | 163 | packages\ThoughtWorks.QRCode.1.1.0\lib\ThoughtWorks.QRCode.dll 164 | 165 | 166 | packages\Vlc.DotNet.Core.3.1.0\lib\net45\Vlc.DotNet.Core.dll 167 | 168 | 169 | packages\Vlc.DotNet.Core.Interops.3.1.0\lib\net45\Vlc.DotNet.Core.Interops.dll 170 | 171 | 172 | packages\Vlc.DotNet.Wpf.3.1.0\lib\net45\Vlc.DotNet.Wpf.dll 173 | 174 | 175 | 176 | 177 | 178 | 179 | 180 | MSBuild:Compile 181 | Designer 182 | 183 | 184 | 185 | geetest.xaml 186 | 187 | 188 | login.xaml 189 | 190 | 191 | 192 | Space.xaml 193 | 194 | 195 | video.xaml 196 | 197 | 198 | Designer 199 | MSBuild:Compile 200 | 201 | 202 | Designer 203 | MSBuild:Compile 204 | 205 | 206 | Designer 207 | MSBuild:Compile 208 | 209 | 210 | Designer 211 | MSBuild:Compile 212 | 213 | 214 | Designer 215 | MSBuild:Compile 216 | 217 | 218 | MSBuild:Compile 219 | Designer 220 | 221 | 222 | App.xaml 223 | Code 224 | 225 | 226 | index.xaml 227 | 228 | 229 | MainWindow.xaml 230 | Code 231 | 232 | 233 | Designer 234 | MSBuild:Compile 235 | 236 | 237 | Designer 238 | MSBuild:Compile 239 | 240 | 241 | 242 | 243 | Code 244 | 245 | 246 | True 247 | True 248 | Resources.resx 249 | 250 | 251 | True 252 | Settings.settings 253 | True 254 | 255 | 256 | ResXFileCodeGenerator 257 | Resources.Designer.cs 258 | 259 | 260 | 261 | 262 | 263 | SettingsSingleFileGenerator 264 | Settings.Designer.cs 265 | 266 | 267 | 268 | 269 | 270 | 271 | 272 | 273 | 274 | 275 | 276 | 277 | 278 | 279 | 280 | 281 | 282 | 283 | 284 | 285 | 286 | 287 | 288 | 289 | 290 | 291 | 292 | 293 | 294 | 295 | 296 | 297 | False 298 | Microsoft .NET Framework 4.7.2 %28x86 和 x64%29 299 | true 300 | 301 | 302 | False 303 | .NET Framework 3.5 SP1 304 | false 305 | 306 | 307 | 308 | 309 | 310 | 311 | 312 | 313 | 314 | 315 | 316 | 317 | 318 | 319 | 320 | 321 | 322 | 323 | 324 | 325 | 326 | 327 | 328 | 329 | 330 | Always 331 | 332 | 333 | Always 334 | 335 | 336 | Always 337 | 338 | 339 | Always 340 | 341 | 342 | 343 | -------------------------------------------------------------------------------- /Bilibili_Client.sln: -------------------------------------------------------------------------------- 1 |  2 | Microsoft Visual Studio Solution File, Format Version 12.00 3 | # Visual Studio Version 16 4 | VisualStudioVersion = 16.0.30320.27 5 | MinimumVisualStudioVersion = 10.0.40219.1 6 | Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Bilibili_Client", "Bilibili_Client.csproj", "{A871B3C0-D4C9-43ED-91D8-0F0770C8D282}" 7 | EndProject 8 | Global 9 | GlobalSection(SolutionConfigurationPlatforms) = preSolution 10 | Debug|Any CPU = Debug|Any CPU 11 | Debug|x64 = Debug|x64 12 | Release|Any CPU = Release|Any CPU 13 | Release|x64 = Release|x64 14 | EndGlobalSection 15 | GlobalSection(ProjectConfigurationPlatforms) = postSolution 16 | {A871B3C0-D4C9-43ED-91D8-0F0770C8D282}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 17 | {A871B3C0-D4C9-43ED-91D8-0F0770C8D282}.Debug|Any CPU.Build.0 = Debug|Any CPU 18 | {A871B3C0-D4C9-43ED-91D8-0F0770C8D282}.Debug|x64.ActiveCfg = Debug|x64 19 | {A871B3C0-D4C9-43ED-91D8-0F0770C8D282}.Debug|x64.Build.0 = Debug|x64 20 | {A871B3C0-D4C9-43ED-91D8-0F0770C8D282}.Release|Any CPU.ActiveCfg = Release|Any CPU 21 | {A871B3C0-D4C9-43ED-91D8-0F0770C8D282}.Release|Any CPU.Build.0 = Release|Any CPU 22 | {A871B3C0-D4C9-43ED-91D8-0F0770C8D282}.Release|x64.ActiveCfg = Release|x64 23 | {A871B3C0-D4C9-43ED-91D8-0F0770C8D282}.Release|x64.Build.0 = Release|x64 24 | EndGlobalSection 25 | GlobalSection(SolutionProperties) = preSolution 26 | HideSolutionNode = FALSE 27 | EndGlobalSection 28 | GlobalSection(ExtensibilityGlobals) = postSolution 29 | SolutionGuid = {A32B4097-557D-4F4E-837A-0C7143126E76} 30 | EndGlobalSection 31 | EndGlobal 32 | -------------------------------------------------------------------------------- /Dictionary.xaml: -------------------------------------------------------------------------------- 1 |  3 | 4 | -------------------------------------------------------------------------------- /MainWindow.xaml: -------------------------------------------------------------------------------- 1 |  17 | 18 | 19 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 50 | 51 | 52 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | 75 | 81 | 84 | 85 | 93 | 94 | 102 | 103 | 104 | 105 | 110 | 111 | 119 | 120 | 121 | 122 | 127 | 128 | 136 | 137 | 138 | 139 | 144 | 145 | 153 | 154 | 155 | 156 | 161 | 162 | 170 | 171 | 172 | 173 | 178 | 179 | 187 | 188 | 189 | 190 | 195 | 196 | 204 | 205 | 206 | 207 | 208 | 209 | 210 | 211 | 217 | 220 | 221 | 226 | 227 | 235 | 236 | 237 | 238 | 243 | 244 | 252 | 253 | 254 | 255 | 260 | 261 | 269 | 270 | 271 | 272 | 273 | 278 | 279 | 287 | 288 | 289 | 290 | 296 | 297 | 298 | 299 | 300 | 301 | 302 | 303 | 304 | 311 | 314 | 315 | 316 | 317 | 319 | 320 | 321 | 322 | 323 | 324 | 325 | 329 | 330 | 331 | 332 | 337 | 338 | 339 | 350 | 351 | 352 | 353 | 354 | 355 | 356 | 358 | 359 | 360 | 361 | 362 | 363 | 364 | 369 | 370 | 371 | 372 | 376 | 377 | 378 | 379 | 380 | 381 | 382 | 383 | -------------------------------------------------------------------------------- /MainWindow.xaml.cs: -------------------------------------------------------------------------------- 1 | using HandyControl.Controls; 2 | using Prism.Commands; 3 | using System; 4 | using System.ComponentModel; 5 | using System.IO; 6 | using System.Windows; 7 | using System.Windows.Input; 8 | using System.Windows.Media; 9 | using System.Windows.Threading; 10 | 11 | namespace Bilibili_Client 12 | { 13 | 14 | 15 | public partial class MainWindow : System.Windows.Window 16 | { 17 | 18 | // 实例化计时器 19 | private DispatcherTimer GCTimer = new DispatcherTimer(); 20 | index index_page = new index(); 21 | login login_page = new login(); 22 | Space space_page = new Space(); 23 | video video_page = new video(); 24 | geetest geetest_page = new geetest(); 25 | Bilibili_Account bilibili = new Bilibili_Account(); 26 | public Bilibili_Account.BiliCookie BiliCookie = new Bilibili_Account.BiliCookie(); 27 | public bool IsLogin = false; 28 | private delegate void MainWindow_SendMessage_To_Login_page();//主窗口发送给登录窗口类 29 | private MainWindow_SendMessage_To_Login_page mainWindow_SendMessage_To_Login_page; 30 | 31 | private delegate void MainWindow_Open_Video_page(string avid,MainWindow mainWindow);//主窗口发送给登录窗口类 32 | private MainWindow_Open_Video_page mainWindow_Open_Video_page; 33 | 34 | public MainWindow() 35 | { 36 | InitializeComponent(); 37 | initialization();//初始化内容 38 | Adaptive();//屏幕自适应 39 | Message();//建立信息槽 40 | Create_data();//创建文件夹 41 | 42 | } 43 | 44 | //初始化内容 45 | private void initialization() 46 | { 47 | //初始化定时器,定时强制GC回收 48 | GCTimer.Tick += new EventHandler(TimerGC); 49 | GCTimer.Interval = new TimeSpan(0, 0, 0, 1); 50 | GCTimer.Start(); 51 | middle_frame.Navigate(index_page);//默认打开主页 52 | if (bilibili.Check_Login_status())//判断是否登录 53 | { 54 | IsLogin = true; 55 | bilibili.Set_User_Data(this); 56 | } 57 | Last_sideMenuItem = Index_Button; 58 | Last_animationPath =(AnimationPath)Index_Button.Icon; 59 | Last_sideMenuItem.Foreground = new SolidColorBrush(Color.FromRgb(251, 114, 153)); 60 | Last_animationPath.Stroke = new SolidColorBrush(Color.FromRgb(251, 114, 153)); 61 | Last_animationPath.IsPlaying = true; 62 | } 63 | 64 | //屏幕自适应 65 | private void Adaptive() 66 | { 67 | WindowStartupLocation = WindowStartupLocation.CenterScreen;//显示位置屏幕居中 68 | 69 | } 70 | 71 | //建立信息槽 72 | private void Message() 73 | { 74 | login_page.Login_Success = Login_Success;//把登陆成功信号发给主窗口 75 | login_page.login_sendMessage_To_Mainwindow = MainWindow_Recevie_From_Login_Page;//把登录页面的发送函数和接受函数链接 76 | mainWindow_SendMessage_To_Login_page = login_page.Login_Recevie_From_Mainwindow;//把发送函数与登录页面的接收函数链接 77 | login_page.login_open_geetest_page = login_open_geetest_page;//登录页面控制主窗口打开验证页面 78 | geetest_page.geetest_SendKey_To_Login_page = login_page.Login_Recevie_Key_From_Geetest_page;//把验证页面的发送Key函数和登录页面接受Key函数链接 79 | geetest_page.geetest_SendSmsKey_To_Login_page = login_page.Login_Recevie_SmsKey_From_Geetest_page;//把验证页面的发送SmsKey函数和登录页面接受SmsKey函数链接 80 | login_page.sendKey_To_Geetest_page = geetest_page.Geetest_Get_Key_From_Login_Page;////把登录页面的发送函数和验证页面接受函数链接 81 | index_page.index_Page_Open_Video = Open_Video_Page; 82 | mainWindow_Open_Video_page=video_page.Open_New_Video; 83 | } 84 | 85 | //创建文件夹 86 | private void Create_data() 87 | { 88 | if (false == Directory.Exists(@"Data\Cache\Img\Cover")) 89 | { 90 | Directory.CreateDirectory(@"Data\Cache\Img\Cover"); 91 | } 92 | 93 | } 94 | //主窗口从登录页面传回来的数据 95 | private void MainWindow_Recevie_From_Login_Page() 96 | { 97 | 98 | 99 | } 100 | 101 | //登录成功后操作 102 | private void Login_Success() 103 | { 104 | IsLogin = true; 105 | bilibili.Set_User_Data(this); 106 | middle_frame.Navigate(space_page); 107 | middle_title.Text = bilibili.Get_User_Data("uname", "", false, this) + "的个人空间"; 108 | geetest_page.geetest_web.Dispose(); 109 | geetest_page.Close(); 110 | geetest_page = null; 111 | login_page = null; 112 | 113 | } 114 | //登录页面打开极验页面 115 | private void login_open_geetest_page() 116 | { 117 | geetest_page.Show(); 118 | } 119 | private void Open_Video_Page(string avid) 120 | { 121 | middle_frame.Navigate(video_page); 122 | mainWindow_Open_Video_page(avid,this); 123 | 124 | 125 | } 126 | private void Window_MouseMove(object sender, MouseEventArgs e)//移动窗口 127 | { 128 | if (e.LeftButton == MouseButtonState.Pressed) 129 | { 130 | this.DragMove(); 131 | } 132 | } 133 | 134 | //主页按钮 135 | private void Index_Refresh_button(object sender, RoutedEventArgs e) 136 | { 137 | 138 | mainWindow_SendMessage_To_Login_page(); 139 | } 140 | // 定时器 GC 141 | private void TimerGC(object sender, EventArgs e) 142 | { 143 | GC.Collect(); 144 | GC.WaitForPendingFinalizers(); 145 | } 146 | 147 | //点击头像 148 | private void Open_User_Space(object sender, MouseButtonEventArgs e) 149 | { 150 | if (IsLogin) 151 | { 152 | middle_frame.Navigate(space_page); 153 | middle_title.Text = bilibili.Get_User_Data("uname", "", false, this)+"的个人空间"; 154 | 155 | 156 | } 157 | else 158 | { 159 | middle_frame.Navigate(login_page); 160 | middle_title.Text ="登录"; 161 | } 162 | Last_sideMenuItem.Foreground = new SolidColorBrush(Color.FromRgb(0, 0, 0)); 163 | Last_animationPath.IsPlaying = false; 164 | Last_animationPath.Stroke = new SolidColorBrush(Color.FromRgb(0, 0, 0)); 165 | 166 | } 167 | //打开首页的按钮 168 | private void Open_Index(object sender, MouseButtonEventArgs e) 169 | { 170 | middle_frame.Navigate(index_page); 171 | middle_title.Text = "首页"; 172 | 173 | } 174 | 175 | 176 | //登录按钮 177 | private void Login_Button_Click(object sender, RoutedEventArgs e) 178 | { 179 | middle_frame.Navigate(login_page); 180 | middle_title.Text = "登录"; 181 | Last_sideMenuItem.Foreground = new SolidColorBrush(Color.FromRgb(0, 0, 0)); 182 | Last_animationPath.IsPlaying = false; 183 | Last_animationPath.Stroke = new SolidColorBrush(Color.FromRgb(0, 0, 0)); 184 | } 185 | 186 | //页面返回按钮 187 | private void Black(object sender, RoutedEventArgs e) 188 | { 189 | if (middle_frame.CanGoBack) 190 | { 191 | if (video_page.Media.IsPlaying) 192 | { 193 | var converter = TypeDescriptor.GetConverter(typeof(Geometry)); 194 | ((System.Windows.Shapes.Path)video_page.Pause_Button.Content).Data = (Geometry)(converter.ConvertFrom("M442.181818 709.818182c0 37.236364-30.254545 69.818182-69.818182 69.818182s-69.818182-30.254545-69.818181-69.818182v-395.636364c0-37.236364 30.254545-69.818182 69.818181-69.818182s69.818182 30.254545 69.818182 69.818182v395.636364z m279.272727 0c0 37.236364-30.254545 69.818182-69.818181 69.818182s-69.818182-30.254545-69.818182-69.818182v-395.636364c0-37.236364 30.254545-69.818182 69.818182-69.818182s69.818182 30.254545 69.818181 69.818182v395.636364z")); 195 | video_page.Media.Close(); 196 | middle_frame.GoBack(); 197 | 198 | }else 199 | middle_frame.GoBack(); 200 | } 201 | } 202 | 203 | private void Left_SideMenu_SelectionChanged(object sender, HandyControl.Data.FunctionEventArgs e) 204 | { 205 | 206 | 207 | 208 | } 209 | 210 | //在打开页面时判断页面是否能返回,从而显示和隐藏按钮 211 | 212 | private void middle_frame_Navigated(object sender, System.Windows.Navigation.NavigationEventArgs e) 213 | { 214 | if (middle_frame.CanGoBack) 215 | Back_Button.Visibility = Visibility.Visible; 216 | else 217 | Back_Button.Visibility = Visibility.Hidden; 218 | } 219 | SideMenuItem Last_sideMenuItem; 220 | AnimationPath Last_animationPath; 221 | 222 | private void Change_Middle_Title(object sender, ExecutedRoutedEventArgs e) 223 | { 224 | middle_title.Text =((SideMenuItem)e.Parameter).Header.ToString(); 225 | ((SideMenuItem)e.Parameter).Foreground = new SolidColorBrush(Color.FromRgb(251, 114, 153)); 226 | ((AnimationPath)((SideMenuItem)e.Parameter).Icon).Stroke = new SolidColorBrush(Color.FromRgb(251, 114, 153)); 227 | ((AnimationPath)((SideMenuItem)e.Parameter).Icon).IsPlaying = true; 228 | if (!string.Equals(Last_sideMenuItem.Header.ToString(), ((SideMenuItem)e.Parameter).Header.ToString())) 229 | { 230 | Last_sideMenuItem.Foreground = new SolidColorBrush(Color.FromRgb(0, 0, 0)); 231 | Last_sideMenuItem.FontSize = 14; 232 | Last_animationPath.IsPlaying = false; 233 | Last_animationPath.Stroke= new SolidColorBrush(Color.FromRgb(0, 0, 0)); 234 | 235 | } 236 | Last_sideMenuItem = (SideMenuItem)e.Parameter; 237 | Last_animationPath = ((AnimationPath)((SideMenuItem)e.Parameter).Icon); 238 | } 239 | 240 | } 241 | } 242 | -------------------------------------------------------------------------------- /PasswordBoxMonitor.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Text; 5 | using System.Threading.Tasks; 6 | using System.Windows; 7 | using System.Windows.Controls; 8 | 9 | namespace Bilibili_Client 10 | { 11 | public class PasswordBoxMonitor : DependencyObject 12 | { 13 | public static bool GetIsMonitoring(DependencyObject obj) 14 | { 15 | return (bool)obj.GetValue(IsMonitoringProperty); 16 | } 17 | 18 | public static void SetIsMonitoring(DependencyObject obj, bool value) 19 | { 20 | obj.SetValue(IsMonitoringProperty, value); 21 | } 22 | 23 | public static readonly DependencyProperty IsMonitoringProperty = 24 | DependencyProperty.RegisterAttached("IsMonitoring", typeof(bool), typeof(PasswordBoxMonitor), new UIPropertyMetadata(false, OnIsMonitoringChanged)); 25 | 26 | 27 | 28 | public static int GetPasswordLength(DependencyObject obj) 29 | { 30 | return (int)obj.GetValue(PasswordLengthProperty); 31 | } 32 | 33 | public static void SetPasswordLength(DependencyObject obj, int value) 34 | { 35 | obj.SetValue(PasswordLengthProperty, value); 36 | } 37 | 38 | public static readonly DependencyProperty PasswordLengthProperty = 39 | DependencyProperty.RegisterAttached("PasswordLength", typeof(int), typeof(PasswordBoxMonitor), new UIPropertyMetadata(0)); 40 | 41 | private static void OnIsMonitoringChanged(DependencyObject d, DependencyPropertyChangedEventArgs e) 42 | { 43 | var pb = d as PasswordBox; 44 | if (pb == null) 45 | { 46 | return; 47 | } 48 | if ((bool)e.NewValue) 49 | { 50 | pb.PasswordChanged += PasswordChanged; 51 | } 52 | else 53 | { 54 | pb.PasswordChanged -= PasswordChanged; 55 | } 56 | } 57 | 58 | static void PasswordChanged(object sender, RoutedEventArgs e) 59 | { 60 | var pb = sender as PasswordBox; 61 | if (pb == null) 62 | { 63 | return; 64 | } 65 | SetPasswordLength(pb, pb.Password.Length); 66 | } 67 | } 68 | } 69 | -------------------------------------------------------------------------------- /Properties/AssemblyInfo.cs: -------------------------------------------------------------------------------- 1 | using System.Reflection; 2 | using System.Resources; 3 | using System.Runtime.CompilerServices; 4 | using System.Runtime.InteropServices; 5 | using System.Windows; 6 | 7 | // 有关程序集的一般信息由以下 8 | // 控制。更改这些特性值可修改 9 | // 与程序集关联的信息。 10 | [assembly: AssemblyTitle("Bilibili_Client")] 11 | [assembly: AssemblyDescription("")] 12 | [assembly: AssemblyConfiguration("")] 13 | [assembly: AssemblyCompany("")] 14 | [assembly: AssemblyProduct("Bilibili_Client")] 15 | [assembly: AssemblyCopyright("Copyright © 2020")] 16 | [assembly: AssemblyTrademark("")] 17 | [assembly: AssemblyCulture("")] 18 | 19 | // 将 ComVisible 设置为 false 会使此程序集中的类型 20 | //对 COM 组件不可见。如果需要从 COM 访问此程序集中的类型 21 | //请将此类型的 ComVisible 特性设置为 true。 22 | [assembly: ComVisible(false)] 23 | 24 | //若要开始生成可本地化的应用程序,请设置 25 | //.csproj 文件中的 CultureYouAreCodingWith 26 | //例如,如果您在源文件中使用的是美国英语, 27 | //使用的是美国英语,请将 设置为 en-US。 然后取消 28 | //对以下 NeutralResourceLanguage 特性的注释。 更新 29 | //以下行中的“en-US”以匹配项目文件中的 UICulture 设置。 30 | 31 | //[assembly: NeutralResourcesLanguage("en-US", UltimateResourceFallbackLocation.Satellite)] 32 | 33 | 34 | [assembly: ThemeInfo( 35 | ResourceDictionaryLocation.None, //主题特定资源词典所处位置 36 | //(未在页面中找到资源时使用, 37 | //或应用程序资源字典中找到时使用) 38 | ResourceDictionaryLocation.SourceAssembly //常规资源词典所处位置 39 | //(未在页面中找到资源时使用, 40 | //、应用程序或任何主题专用资源字典中找到时使用) 41 | )] 42 | 43 | 44 | // 程序集的版本信息由下列四个值组成: 45 | // 46 | // 主版本 47 | // 次版本 48 | // 生成号 49 | // 修订号 50 | // 51 | //可以指定所有这些值,也可以使用“生成号”和“修订号”的默认值 52 | //通过使用 "*",如下所示: 53 | // [assembly: AssemblyVersion("1.0.*")] 54 | [assembly: AssemblyVersion("1.0.0.0")] 55 | [assembly: AssemblyFileVersion("1.0.0.0")] 56 | -------------------------------------------------------------------------------- /Properties/Resources.Designer.cs: -------------------------------------------------------------------------------- 1 | //------------------------------------------------------------------------------ 2 | // 3 | // 此代码由工具生成。 4 | // 运行时版本: 4.0.30319.42000 5 | // 6 | // 对此文件的更改可能导致不正确的行为,如果 7 | // 重新生成代码,则所做更改将丢失。 8 | // 9 | //------------------------------------------------------------------------------ 10 | 11 | namespace Bilibili_Client.Properties 12 | { 13 | 14 | 15 | /// 16 | /// 强类型资源类,用于查找本地化字符串等。 17 | /// 18 | // 此类是由 StronglyTypedResourceBuilder 19 | // 类通过类似于 ResGen 或 Visual Studio 的工具自动生成的。 20 | // 若要添加或删除成员,请编辑 .ResX 文件,然后重新运行 ResGen 21 | // (以 /str 作为命令选项),或重新生成 VS 项目。 22 | [global::System.CodeDom.Compiler.GeneratedCodeAttribute("System.Resources.Tools.StronglyTypedResourceBuilder", "4.0.0.0")] 23 | [global::System.Diagnostics.DebuggerNonUserCodeAttribute()] 24 | [global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()] 25 | internal class Resources 26 | { 27 | 28 | private static global::System.Resources.ResourceManager resourceMan; 29 | 30 | private static global::System.Globalization.CultureInfo resourceCulture; 31 | 32 | [global::System.Diagnostics.CodeAnalysis.SuppressMessageAttribute("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] 33 | internal Resources() 34 | { 35 | } 36 | 37 | /// 38 | /// 返回此类使用的缓存 ResourceManager 实例。 39 | /// 40 | [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)] 41 | internal static global::System.Resources.ResourceManager ResourceManager 42 | { 43 | get 44 | { 45 | if ((resourceMan == null)) 46 | { 47 | global::System.Resources.ResourceManager temp = new global::System.Resources.ResourceManager("Bilibili_Client.Properties.Resources", typeof(Resources).Assembly); 48 | resourceMan = temp; 49 | } 50 | return resourceMan; 51 | } 52 | } 53 | 54 | /// 55 | /// 覆盖当前线程的 CurrentUICulture 属性 56 | /// 使用此强类型的资源类的资源查找。 57 | /// 58 | [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)] 59 | internal static global::System.Globalization.CultureInfo Culture 60 | { 61 | get 62 | { 63 | return resourceCulture; 64 | } 65 | set 66 | { 67 | resourceCulture = value; 68 | } 69 | } 70 | } 71 | } 72 | -------------------------------------------------------------------------------- /Properties/Resources.resx: -------------------------------------------------------------------------------- 1 |  2 | 3 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | 75 | 76 | 77 | 78 | 79 | 80 | 81 | 82 | 83 | 84 | 85 | 86 | 87 | 88 | 89 | 90 | 91 | 92 | 93 | 94 | 95 | 96 | 97 | 98 | 99 | 100 | 101 | 102 | 103 | 104 | 105 | 106 | text/microsoft-resx 107 | 108 | 109 | 2.0 110 | 111 | 112 | System.Resources.ResXResourceReader, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 113 | 114 | 115 | System.Resources.ResXResourceWriter, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 116 | 117 | -------------------------------------------------------------------------------- /Properties/Settings.Designer.cs: -------------------------------------------------------------------------------- 1 | //------------------------------------------------------------------------------ 2 | // 3 | // This code was generated by a tool. 4 | // Runtime Version:4.0.30319.42000 5 | // 6 | // Changes to this file may cause incorrect behavior and will be lost if 7 | // the code is regenerated. 8 | // 9 | //------------------------------------------------------------------------------ 10 | 11 | namespace Bilibili_Client.Properties 12 | { 13 | 14 | 15 | [global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()] 16 | [global::System.CodeDom.Compiler.GeneratedCodeAttribute("Microsoft.VisualStudio.Editors.SettingsDesigner.SettingsSingleFileGenerator", "11.0.0.0")] 17 | internal sealed partial class Settings : global::System.Configuration.ApplicationSettingsBase 18 | { 19 | 20 | private static Settings defaultInstance = ((Settings)(global::System.Configuration.ApplicationSettingsBase.Synchronized(new Settings()))); 21 | 22 | public static Settings Default 23 | { 24 | get 25 | { 26 | return defaultInstance; 27 | } 28 | } 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /Properties/Settings.settings: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | 6 | 7 | -------------------------------------------------------------------------------- /Properties/app.manifest: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | 6 | 7 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 47 | 54 | 55 | 69 | -------------------------------------------------------------------------------- /Properties/分区.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/JonyanDunh/BilibiliClient/9974483a17f972d7469c17b4192709c3c958ff07/Properties/分区.png -------------------------------------------------------------------------------- /Properties/动态.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/JonyanDunh/BilibiliClient/9974483a17f972d7469c17b4192709c3c958ff07/Properties/动态.png -------------------------------------------------------------------------------- /Properties/历史记录.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/JonyanDunh/BilibiliClient/9974483a17f972d7469c17b4192709c3c958ff07/Properties/历史记录.png -------------------------------------------------------------------------------- /Properties/收藏夹.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/JonyanDunh/BilibiliClient/9974483a17f972d7469c17b4192709c3c958ff07/Properties/收藏夹.png -------------------------------------------------------------------------------- /Properties/首页.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/JonyanDunh/BilibiliClient/9974483a17f972d7469c17b4192709c3c958ff07/Properties/首页.png -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 |

2 |

BilibiliClient

3 |

4 | 哔哩哔哩客户端C# WPF版本,用HandyControl做的UI,支持免登录播放4k视频、哔哩哔哩云盘、上传动态封面等功能。 5 |
6 |
7 |

8 | 9 |

10 | 11 | ![Contributors](https://img.shields.io/github/contributors/JonyanDunh/BilibiliClient?color=dark-green) ![Forks](https://img.shields.io/github/forks/JonyanDunh/BilibiliClient?style=social) ![Stargazers](https://img.shields.io/github/stars/JonyanDunh/BilibiliClient?style=social) ![Issues](https://img.shields.io/github/issues/JonyanDunh/BilibiliClient) ![License](https://img.shields.io/github/license/JonyanDunh/BilibiliClient) 12 | 13 | ## 项目截图 14 | 15 | ![preview1.png](https://github.com/JonyanDunh/BilibiliClient/blob/master/resource/img/preview1.png?raw=true) 16 | 17 | ## 项目引用 18 | 19 | * [WPF](https://github.com/dotnet/wpf) 20 | * [ HandyControl](https://github.com/HandyOrg/HandyControl) 21 | -------------------------------------------------------------------------------- /Space.xaml: -------------------------------------------------------------------------------- 1 |  10 | 11 | 12 | 17 | 18 | 19 | -------------------------------------------------------------------------------- /Space.xaml.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Text; 5 | using System.Threading.Tasks; 6 | using System.Windows; 7 | using System.Windows.Controls; 8 | using System.Windows.Data; 9 | using System.Windows.Documents; 10 | using System.Windows.Input; 11 | using System.Windows.Media; 12 | using System.Windows.Media.Imaging; 13 | using System.Windows.Navigation; 14 | using System.Windows.Shapes; 15 | 16 | namespace Bilibili_Client 17 | { 18 | /// 19 | /// Space.xaml 的交互逻辑 20 | /// 21 | public partial class Space : Page 22 | { 23 | public Space() 24 | { 25 | InitializeComponent(); 26 | } 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /geetest.xaml: -------------------------------------------------------------------------------- 1 |  12 | 13 | 14 | 15 | 17 | 18 | 19 | 20 | 21 | 22 | -------------------------------------------------------------------------------- /geetest.xaml.cs: -------------------------------------------------------------------------------- 1 | using Microsoft.Win32; 2 | using System; 3 | using System.Collections.Generic; 4 | using System.ComponentModel; 5 | using System.Linq; 6 | using System.Runtime.InteropServices; 7 | using System.Security.Permissions; 8 | using System.Text; 9 | using System.Threading.Tasks; 10 | using System.Windows; 11 | using System.Windows.Controls; 12 | using System.Windows.Data; 13 | using System.Windows.Documents; 14 | using System.Windows.Input; 15 | using System.Windows.Media; 16 | using System.Windows.Media.Imaging; 17 | using System.Windows.Shapes; 18 | 19 | namespace Bilibili_Client 20 | { 21 | /// 22 | /// geetest.xaml 的交互逻辑 23 | /// 24 | /// 25 | [PermissionSet(SecurityAction.Demand, Name = "FullTrust")] 26 | [ComVisible(true)] 27 | 28 | public class ObjectForScriptingHelper 29 | { 30 | geetest page; 31 | public ObjectForScriptingHelper(geetest main) 32 | { 33 | page = main; 34 | } 35 | public void SendKey(string validateg, string seccode)//网页回调 36 | { 37 | page.verification_keys.validate = validateg; 38 | page.verification_keys.seccode = seccode; 39 | 40 | if (page.verification_keys.Sms_type == 0) 41 | { 42 | this.page.Hide(); 43 | page.geetest_SendKey_To_Login_page(page.verification_keys); 44 | } 45 | else 46 | { 47 | this.page.Hide(); 48 | page.geetest_SendSmsKey_To_Login_page(page.verification_keys); 49 | } 50 | 51 | } 52 | } 53 | public partial class geetest : Window 54 | { 55 | public delegate void Geetest_SendKey_To_Login_page(Bilibili_Login.Verification_Key verification_key); 56 | public Geetest_SendKey_To_Login_page geetest_SendKey_To_Login_page; 57 | public Geetest_SendKey_To_Login_page geetest_SendSmsKey_To_Login_page; 58 | 59 | public Bilibili_Login.Verification_Key verification_keys = new Bilibili_Login.Verification_Key(); 60 | public geetest() 61 | { 62 | InitializeComponent(); 63 | WindowStartupLocation = WindowStartupLocation.CenterScreen;//显示位置屏幕居中 64 | SetWebBrowserFeatures();//IE11 65 | } 66 | public void Geetest_Get_Key_From_Login_Page(Bilibili_Login.Verification_Key verification_key) 67 | { 68 | verification_keys = verification_key; 69 | ObjectForScriptingHelper helper = new ObjectForScriptingHelper(this); 70 | geetest_web.ObjectForScripting = helper; 71 | geetest_web.Source = new Uri(@"pack://siteoforigin:,,,/resource/Web/geetest-validator/geetest.html?challenge=" + verification_keys.challenge + ">=" + verification_keys.gt); 72 | } 73 | static void SetWebBrowserFeatures() 74 | { 75 | if (LicenseManager.UsageMode != LicenseUsageMode.Runtime) 76 | return; 77 | var appName = System.IO.Path.GetFileName(System.Diagnostics.Process.GetCurrentProcess().MainModule.FileName); 78 | UInt32 ieMode = (UInt32)11001; 79 | var featureControlRegKey = @"HKEY_CURRENT_USER\Software\Microsoft\Internet Explorer\Main\FeatureControl\"; 80 | Registry.SetValue(featureControlRegKey + "FEATURE_BROWSER_EMULATION", 81 | appName, ieMode, RegistryValueKind.DWord); 82 | Registry.SetValue(featureControlRegKey + "FEATURE_ENABLE_CLIPCHILDREN_OPTIMIZATION", 83 | appName, 1, RegistryValueKind.DWord); 84 | } 85 | } 86 | } 87 | -------------------------------------------------------------------------------- /index.xaml: -------------------------------------------------------------------------------- 1 |  12 | 13 | 15 | 16 | 18 | 19 | 20 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 32 | 33 | 34 | 35 | 42 | 43 | 44 | 45 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 58 | 80 | 81 | 82 | 86 | 92 | 93 | 94 | 95 | 96 | 100 | 101 | 102 | 103 | 104 | 105 | 106 | 107 | 108 | 116 | 117 | 118 | 119 | 120 | 121 | 122 | 123 | 124 | 125 | 126 | 127 | 128 | 129 | 136 | 137 | 145 | 146 | 147 | 148 | 149 | 156 | 157 | 165 | 166 | 167 | 168 | 174 | 175 | 176 | 177 | 178 | 179 | 180 | 187 | 188 | 191 | 192 | 193 | 194 | 201 | 202 | 203 | 204 | 205 | 206 | 207 | 208 | 209 | 210 | 211 | 212 | 213 | 214 | 215 | 216 | 217 | 218 | 219 | 220 | 221 | 222 | 223 | -------------------------------------------------------------------------------- /index.xaml.cs: -------------------------------------------------------------------------------- 1 | using HandyControl.Controls; 2 | using Newtonsoft.Json; 3 | using Newtonsoft.Json.Linq; 4 | using RestSharp; 5 | using System; 6 | using System.Collections.Generic; 7 | using System.ComponentModel; 8 | using System.IO; 9 | using System.Linq; 10 | using System.Net; 11 | using System.Threading; 12 | using System.Threading.Tasks; 13 | using System.Windows; 14 | using System.Windows.Controls; 15 | using System.Windows.Input; 16 | using System.Windows.Media.Media3D; 17 | using System.Windows.Threading; 18 | 19 | 20 | 21 | namespace Bilibili_Client 22 | { 23 | /// 24 | /// index.xaml 的交互逻辑 25 | /// 26 | 27 | 28 | public partial class index : Page 29 | { 30 | public delegate void Index_Page_Open_Video(string avid);//主窗口发送给登录窗口类 31 | public Index_Page_Open_Video index_Page_Open_Video; 32 | ManualResetEvent Thread_blocking = new ManualResetEvent(true);//线程阻塞 33 | CoverFlow coverFlow = new CoverFlow(); 34 | int Download_Complete = 0; 35 | public index() 36 | { 37 | 38 | InitializeComponent(); 39 | Thread Updata_Index_Featured_Video_Thread = new Thread(Updata_Index);//加载推荐视频的函数加入一个新的子线程 40 | Updata_Index_Featured_Video_Thread.Name = "Updata_Index_Featured_Video_Thread"; 41 | Updata_Index_Featured_Video_Thread.Start();//线程开始 42 | Thread ADD_Homepage_Ad_Thread = new Thread(ADD_Homepage_Ad);//加载推荐视频的函数加入一个新的子线程 43 | ADD_Homepage_Ad_Thread.Name = "ADD_Homepage_Ad_Thread"; 44 | ADD_Homepage_Ad_Thread.Start();//线程开始 45 | CoverFlow coverFlow = new CoverFlow(); 46 | coverFlow.Margin = new Thickness(32); 47 | coverFlow.Width = 800; 48 | coverFlow.Height = 260; 49 | coverFlow.Loop = true; 50 | Index_Grid.Children.Add(coverFlow); 51 | } 52 | private readonly TaskScheduler _syncContextTaskScheduler = TaskScheduler.FromCurrentSynchronizationContext(); 53 | 54 | //主页广告 55 | private void ADD_Homepage_Ad() 56 | { 57 | 58 | var client = new RestClient("https://app.bilibili.com/x/v2/feed/index?idx=0&flush=0&column=4&device=pad&pull=true&build=5520400&appkey=4ebafd7c4951b366&mobi_app=iphone&platform=ios&ts=1596754509&access_key=71626a38ce02b8a18b9a8b0dd8add481&sign=5d3bbfa008082c409bf56603278ea7a8"); 59 | var request = new RestRequest(Method.GET); 60 | IRestResponse response = client.Execute(request); 61 | JObject recommend = (JObject)JsonConvert.DeserializeObject(response.Content); 62 | JToken items = recommend["data"]["items"][0]["banner_item"]; 63 | for (int i = 0; i <= items.Count() - 1; i++) 64 | { 65 | 66 | if (File.Exists(@"Data\Cache\Img\Cover\" + items[i]["id"].ToString() + ".jpg")) 67 | { 68 | coverFlow.Add(new Uri(@"Data\Cache\Img\Cover\" + items[i]["id"].ToString() + ".jpg", UriKind.Relative)); 69 | Download_Complete++; 70 | } 71 | else 72 | { 73 | 74 | WebClient Client = new WebClient(); 75 | Uri uri = new Uri(items[i]["image"].ToString()); 76 | Client.DownloadFileCompleted += Down_Cover_Completed; 77 | Client.DownloadFileAsync(uri, @"Data\Cache\Img\Cover\" + items[i]["id"].ToString() + ".jpg", @"Data\Cache\Img\Cover\" + items[i]["id"].ToString() + ".jpg"); 78 | 79 | } 80 | } 81 | 82 | Thread AD_Cover_Download_Completed_Thread=new Thread((obj) => 83 | { 84 | while (true) 85 | { 86 | if (Download_Complete == (int)obj) 87 | { 88 | this.Dispatcher.BeginInvoke(DispatcherPriority.Normal, (ThreadStart)delegate () 89 | { 90 | coverFlow.JumpTo(1); 91 | Index_Grid.Children.Add(coverFlow); 92 | }); 93 | break; 94 | } 95 | } 96 | }); 97 | AD_Cover_Download_Completed_Thread.Name = "AD_Cover_Download_Completed_Thread"; 98 | AD_Cover_Download_Completed_Thread.Start(items.Count()); 99 | client = null; 100 | request = null; 101 | response = null; 102 | recommend = null; 103 | } 104 | 105 | //广告封面下载完成 106 | private void Down_Cover_Completed(object sender, AsyncCompletedEventArgs e) 107 | { 108 | 109 | if (e.UserState != null) 110 | { 111 | coverFlow.Add(new Uri(e.UserState.ToString(), UriKind.Relative)); 112 | Download_Complete++; 113 | } 114 | } 115 | bool IsCompleted = false; 116 | bool first = true; 117 | List double_row_videos = new List(); 118 | JToken items; 119 | int last_count = 1; 120 | //主页推荐 121 | private void Updata_Index() 122 | { 123 | var client = new RestClient("https://app.bilibili.com/x/v2/feed/index?device=pad&mobi_app=iphone"); 124 | IRestResponse response; 125 | JObject recommend; 126 | while (true) 127 | { 128 | Thread_blocking.WaitOne(); 129 | if (last_count == 19 | last_count == 1) 130 | { 131 | var request = new RestRequest(Method.GET); 132 | response = client.Execute(request); 133 | recommend = (JObject)JsonConvert.DeserializeObject(response.Content); 134 | items = recommend["data"]["items"]; 135 | last_count = 1; 136 | } 137 | IsCompleted = Parallel.For(last_count, first ? 18 : last_count + 3, (obj, loopstate) => 138 | { 139 | double_row_videos.Add 140 | ( 141 | new double_row_video( 142 | items[obj]["avatar"]["cover"].ToString() + "@20w_20h_1q.jpg",//up头像 143 | items[obj]["desc"].ToString(),//up名字 144 | items[obj]["cover"].ToString() + "@288w_180h_1q.jpg",//封面 145 | items[obj]["cover_left_text_1"].ToString(),//时长 146 | items[obj]["title"].ToString(),//标题 147 | items[obj]["args"]["rname"].ToString(),//分区 148 | items[obj]["cover_left_text_2"].ToString(),//播放量 149 | items[obj]["cover_left_text_3"].ToString(),//弹幕数 150 | items[obj]["param"].ToString()//AV号 151 | ) 152 | ); 153 | }).IsCompleted; 154 | Parallel_IsCompleted = IsCompleted; 155 | if (!first) 156 | { 157 | Thread_blocking.Reset(); 158 | 159 | } 160 | else 161 | first = false; 162 | } 163 | } 164 | public bool Parallel_IsCompleted 165 | { 166 | get 167 | { 168 | return IsCompleted; 169 | } 170 | set 171 | { 172 | if (IsCompleted) 173 | this.Dispatcher.BeginInvoke(DispatcherPriority.Normal, (ThreadStart)delegate () 174 | { 175 | for (int i = 0; i < double_row_videos.Count; i++) 176 | content_box.Items.Add(double_row_videos[i]);//按照模板加入一个item 177 | double_row_videos.Clear(); 178 | last_count += 3; 179 | }); 180 | } 181 | } 182 | public class double_row_video 183 | { 184 | public string head_img_url { get; private set; } 185 | public string video_cover { get; private set; } 186 | public string video_up { get; private set; } 187 | public string video_title { get; private set; } 188 | public string video_play_volume { get; private set; } 189 | public string video_barrages { get; private set; } 190 | public string video_duration { get; private set; } 191 | public string video_partition { get; private set; } 192 | public string Avid { get; private set; } 193 | 194 | 195 | public double_row_video( 196 | string up_head, //up头像 197 | string up,//up名字 198 | string cover,//封面 199 | string duration,//时长 200 | string title,//标题 201 | string partition,//分区 202 | string play_volume, //播放量 203 | string barrages, //弹幕数 204 | string avid//AV号 205 | ) 206 | { 207 | head_img_url = up_head;//up头像 208 | video_up = up;//up名字 209 | video_cover = cover;//封面 210 | video_duration = duration;//时长 211 | video_title = title;//标题 212 | video_partition = partition;//分区 213 | video_play_volume = play_volume;//播放量 214 | video_barrages = barrages;//弹幕数 215 | Avid = avid; 216 | 217 | } 218 | } 219 | double last_ContentVerticalOffset = 0; 220 | private void ScrollChanged(object sender, ScrollChangedEventArgs e) 221 | { 222 | if (index_scrollViewer.ContentVerticalOffset - last_ContentVerticalOffset > 10 && index_scrollViewer.ScrollableHeight - index_scrollViewer.ContentVerticalOffset < 2000) 223 | { 224 | Thread_blocking.Set(); 225 | last_ContentVerticalOffset = index_scrollViewer.ContentVerticalOffset; 226 | } 227 | 228 | 229 | } 230 | 231 | private void content_box_PreviewMouseWheel(object sender, MouseWheelEventArgs e) 232 | { 233 | var eventArg = new MouseWheelEventArgs(e.MouseDevice, e.Timestamp, e.Delta) 234 | { 235 | RoutedEvent = UIElement.MouseWheelEvent, 236 | Source = sender 237 | }; 238 | this.content_box.RaiseEvent(eventArg); 239 | } 240 | 241 | 242 | private void Goto_Video_Page(object sender, ExecutedRoutedEventArgs e) 243 | { 244 | string avid = ((Button)e.Parameter).Uid.ToString(); 245 | 246 | index_Page_Open_Video(avid); 247 | 248 | } 249 | } 250 | } 251 | -------------------------------------------------------------------------------- /login.xaml: -------------------------------------------------------------------------------- 1 |  13 | 14 | 15 | 16 | 17 | 18 | 19 | 22 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 32 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 49 | 50 | 51 | 55 | 56 | 57 | 58 | 69 | 70 | 71 | 72 | 73 | 74 | 79 | 85 | 91 | 92 | 93 | 94 | 95 | 96 | 97 | 98 | 99 | 102 | 104 | 105 | 106 | 107 | 108 | 109 | 110 | 112 | 116 | 117 | 118 | 119 | 120 | 121 | 122 | 123 | 124 | 125 | 129 | 136 | 137 | 138 | 142 | 143 | 144 | 145 | 156 | 157 | 158 | 159 | 160 | 161 | 166 | 172 | 178 | 179 | 180 | 181 | 182 | 183 | 184 | 185 | 186 | 189 | 193 | 194 | 195 | 196 | 197 | 198 | 199 | 201 | 205 | 206 | 207 | 208 | 209 | 210 | 211 | 212 | 213 | 217 | 218 | 219 | 224 | 225 | 226 | 227 | 228 | 229 | 230 | 235 | 241 | 247 | 248 | 249 | 250 | 251 | 252 | 253 | 254 | 255 | 256 | 257 | -------------------------------------------------------------------------------- /login.xaml.cs: -------------------------------------------------------------------------------- 1 | using System.Drawing; 2 | using System.Drawing.Imaging; 3 | using System.IO; 4 | using System.Security.Cryptography; 5 | using System.Text; 6 | using System.Web; 7 | using System.Windows; 8 | using System.Windows.Controls; 9 | using System.Windows.Input; 10 | using System.Windows.Media; 11 | using System.Windows.Media.Imaging; 12 | using ThoughtWorks.QRCode.Codec; 13 | 14 | namespace Bilibili_Client 15 | { 16 | 17 | public class Coding 18 | { 19 | 20 | public string MD5Encoding(string rawPass) 21 | { 22 | MD5 md5 = MD5.Create(); 23 | byte[] bs = Encoding.UTF8.GetBytes(rawPass); 24 | byte[] hs = md5.ComputeHash(bs); 25 | StringBuilder stb = new StringBuilder(); 26 | foreach (byte b in hs) 27 | { 28 | // 以十六进制格式格式化 29 | stb.Append(b.ToString("x2")); 30 | } 31 | bs = null; 32 | hs = null; 33 | md5 = null; 34 | md5.Dispose(); 35 | return stb.ToString(); 36 | } 37 | 38 | public string UrlEncode(string str) 39 | { 40 | StringBuilder builder = new StringBuilder(); 41 | foreach (char c in str) 42 | { 43 | if (HttpUtility.UrlEncode(c.ToString()).Length > 1) 44 | { 45 | builder.Append(HttpUtility.UrlEncode(c.ToString()).ToUpper()); 46 | } 47 | else 48 | { 49 | builder.Append(c); 50 | } 51 | } 52 | return builder.ToString(); 53 | } 54 | 55 | 56 | }//加密函数 57 | 58 | 59 | 60 | public partial class login : Page 61 | { 62 | public delegate void Login_SendMessage_To_Mainwindow(); 63 | public Login_SendMessage_To_Mainwindow login_sendMessage_To_Mainwindow; 64 | public Login_SendMessage_To_Mainwindow login_open_geetest_page; 65 | public Login_SendMessage_To_Mainwindow Login_Success; 66 | 67 | public delegate void SendKey_To_Geetest_page(Bilibili_Login.Verification_Key verification_key); 68 | public SendKey_To_Geetest_page sendKey_To_Geetest_page; 69 | 70 | Bilibili_Login bilibili = new Bilibili_Login(); 71 | public login() 72 | { 73 | InitializeComponent(); 74 | 75 | } 76 | 77 | //从主窗口接收信息 78 | public void Login_Recevie_From_Mainwindow() 79 | { 80 | 81 | } 82 | 83 | //从验证页面接收信息 84 | public void Login_Recevie_Key_From_Geetest_page(Bilibili_Login.Verification_Key verification_key) 85 | { 86 | 87 | bilibili.Password_login_Web(account_textbox.Text, password_textbox.Password, bilibili.Password_login_Get_Hash(), verification_key, this); 88 | } 89 | 90 | //从验证页面接收Key 91 | public void Login_Recevie_SmsKey_From_Geetest_page(Bilibili_Login.Verification_Key verification_key) 92 | { 93 | bilibili.Send_Sms(verification_key, this); 94 | } 95 | 96 | //密码登录按钮 97 | private void Password_Login_buttons_Click(object sender, RoutedEventArgs e) 98 | { 99 | login_open_geetest_page(); 100 | sendKey_To_Geetest_page(bilibili.Get_Verification_Key(6)); 101 | } 102 | 103 | //验证码登录发送验证码 104 | private void Sms_code_Send(object sender, RoutedEventArgs e) 105 | { 106 | login_open_geetest_page(); 107 | Bilibili_Login.Verification_Key verification_key = bilibili.Get_Verification_Key(6); 108 | verification_key.Sms_type = 21; 109 | 110 | verification_key.phone = phone_textbox.Text; 111 | sendKey_To_Geetest_page(verification_key); 112 | 113 | } 114 | 115 | //验证码登录按钮 116 | private void Sms_code_Login(object sender, RoutedEventArgs e) 117 | { 118 | bilibili.Sms_login(smscode_textbox.Password, phone_textbox.Text,this); 119 | } 120 | 121 | //点击二维码刷新二维码 122 | private void Refresh_Qrcode(object sender, MouseButtonEventArgs e) 123 | { 124 | bilibili.Get_Scan_Login_Qrcode_status_Timer.Stop(); 125 | bilibili.Get_Login_Qrcode(this); 126 | Scan_status.Text = "请使用 哔哩哔哩客户端 扫码登录"; 127 | Scan_status.Foreground = new SolidColorBrush(System.Windows.Media.Color.FromRgb(251, 114, 153)); 128 | } 129 | 130 | //切换到密码登录页面 131 | private void Password(object sender, MouseButtonEventArgs e) 132 | { 133 | if (QrCode_Login.Visibility == Visibility.Visible) 134 | bilibili.Get_Scan_Login_Qrcode_status_Timer.Stop(); 135 | Password_Login.Visibility = Visibility.Visible; 136 | Sms_Code_Login.Visibility = Visibility.Hidden; 137 | QrCode_Login.Visibility = Visibility.Hidden; 138 | 139 | } 140 | 141 | //切换到验证码登录页面 142 | private void Sms(object sender, MouseButtonEventArgs e) 143 | { 144 | if (QrCode_Login.Visibility == Visibility.Visible) 145 | bilibili.Get_Scan_Login_Qrcode_status_Timer.Stop(); 146 | Password_Login.Visibility = Visibility.Hidden; 147 | Sms_Code_Login.Visibility = Visibility.Visible; 148 | QrCode_Login.Visibility = Visibility.Hidden; 149 | } 150 | 151 | //切换到二维码登录页面 152 | private void Qrcode(object sender, MouseButtonEventArgs e) 153 | { 154 | Password_Login.Visibility = Visibility.Hidden; 155 | Sms_Code_Login.Visibility = Visibility.Hidden; 156 | QrCode_Login.Visibility = Visibility.Visible; 157 | bilibili.Get_Login_Qrcode(this); 158 | } 159 | 160 | //生成二维码函数 161 | public BitmapImage NewQRCodeByThoughtWorks(string codeContent, ImageFormat imgType) 162 | { 163 | QRCodeEncoder encoder = new QRCodeEncoder(); 164 | encoder.QRCodeEncodeMode = QRCodeEncoder.ENCODE_MODE.BYTE;//编码方式(注意:BYTE能支持中文,ALPHA_NUMERIC扫描出来的都是数字) 165 | encoder.QRCodeScale = 10;//大小(值越大生成的二维码图片像素越高) 166 | encoder.QRCodeVersion = 0;//版本(注意:设置为0主要是防止编码的字符串太长时发生错误) 167 | encoder.QRCodeErrorCorrect = QRCodeEncoder.ERROR_CORRECTION.M;//错误效验、错误更正(有4个等级) 168 | encoder.QRCodeBackgroundColor = System.Drawing.Color.White; 169 | encoder.QRCodeForegroundColor = System.Drawing.Color.FromArgb(251, 114, 153); 170 | 171 | Bitmap bcodeBitmap = encoder.Encode(codeContent); 172 | BitmapImage bitmapImage = BitmapToBitmapImage(bcodeBitmap); 173 | bcodeBitmap.Dispose(); 174 | encoder = null; 175 | return bitmapImage; 176 | } 177 | 178 | //Bitmap转BitmapImage 179 | public BitmapImage BitmapToBitmapImage(Bitmap bitmap) 180 | { 181 | Bitmap bitmapSource = new Bitmap(bitmap.Width, bitmap.Height); 182 | int i, j; 183 | for (i = 0; i < bitmap.Width; i++) 184 | for (j = 0; j < bitmap.Height; j++) 185 | { 186 | System.Drawing.Color pixelColor = bitmap.GetPixel(i, j); 187 | System.Drawing.Color newColor = System.Drawing.Color.FromArgb(pixelColor.R, pixelColor.G, pixelColor.B); 188 | bitmapSource.SetPixel(i, j, newColor); 189 | } 190 | MemoryStream ms = new MemoryStream(); 191 | bitmapSource.Save(ms, ImageFormat.Bmp); 192 | BitmapImage bitmapImage = new BitmapImage(); 193 | bitmapImage.BeginInit(); 194 | bitmapImage.StreamSource = new MemoryStream(ms.ToArray()); 195 | bitmapImage.EndInit(); 196 | 197 | bitmapSource.Dispose(); 198 | ms.Dispose(); 199 | bitmap.Dispose(); 200 | 201 | 202 | return bitmapImage; 203 | } 204 | 205 | } 206 | 207 | } 208 | -------------------------------------------------------------------------------- /packages.config: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | -------------------------------------------------------------------------------- /packages.zip: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/JonyanDunh/BilibiliClient/9974483a17f972d7469c17b4192709c3c958ff07/packages.zip -------------------------------------------------------------------------------- /resource/Web/geetest-validator/css/style.css: -------------------------------------------------------------------------------- 1 | body { 2 | margin: 50px 0; 3 | text-align: center; 4 | font-family: "PingFangSC-Regular", "Open Sans", Arial, "Hiragino Sans GB", "Microsoft YaHei", "STHeiti", "WenQuanYi Micro Hei", SimSun, sans-serif; 5 | } 6 | 7 | .inp { 8 | border: 1px solid #cccccc; 9 | border-radius: 2px; 10 | padding: 0 10px; 11 | width: 320px; 12 | height: 40px; 13 | font-size: 18px; 14 | } 15 | 16 | .btn { 17 | display: inline-block; 18 | box-sizing: border-box; 19 | border: 1px solid #cccccc; 20 | border-radius: 2px; 21 | width: 100px; 22 | height: 40px; 23 | line-height: 40px; 24 | font-size: 16px; 25 | color: #666; 26 | cursor: pointer; 27 | background: white linear-gradient(180deg, #ffffff 0%, #f3f3f3 100%); 28 | } 29 | 30 | .btn:hover { 31 | background: white linear-gradient(0deg, #ffffff 0%, #f3f3f3 100%) 32 | } 33 | 34 | #captcha { 35 | width: 300px; 36 | display: inline-block; 37 | } 38 | 39 | label { 40 | vertical-align: top; 41 | display: inline-block; 42 | width: 120px; 43 | text-align: right; 44 | } 45 | 46 | #text { 47 | height: 42px; 48 | width: 298px; 49 | text-align: center; 50 | border-radius: 2px; 51 | background-color: #F3F3F3; 52 | color: #BBBBBB; 53 | font-size: 14px; 54 | letter-spacing: 0.1px; 55 | line-height: 42px; 56 | } 57 | 58 | #wait { 59 | display: none; 60 | height: 42px; 61 | width: 298px; 62 | text-align: center; 63 | border-radius: 2px; 64 | background-color: #F3F3F3; 65 | } 66 | 67 | .loading { 68 | margin: auto; 69 | width: 70px; 70 | height: 20px; 71 | } 72 | 73 | .loading-dot { 74 | float: left; 75 | width: 8px; 76 | height: 8px; 77 | margin: 18px 4px; 78 | background: #ccc; 79 | 80 | -webkit-border-radius: 50%; 81 | -moz-border-radius: 50%; 82 | border-radius: 50%; 83 | 84 | opacity: 0; 85 | 86 | -webkit-box-shadow: 0 0 2px black; 87 | -moz-box-shadow: 0 0 2px black; 88 | -ms-box-shadow: 0 0 2px black; 89 | -o-box-shadow: 0 0 2px black; 90 | box-shadow: 0 0 2px black; 91 | 92 | -webkit-animation: loadingFade 1s infinite; 93 | -moz-animation: loadingFade 1s infinite; 94 | animation: loadingFade 1s infinite; 95 | } 96 | 97 | .loading-dot:nth-child(1) { 98 | -webkit-animation-delay: 0s; 99 | -moz-animation-delay: 0s; 100 | animation-delay: 0s; 101 | } 102 | 103 | .loading-dot:nth-child(2) { 104 | -webkit-animation-delay: 0.1s; 105 | -moz-animation-delay: 0.1s; 106 | animation-delay: 0.1s; 107 | } 108 | 109 | .loading-dot:nth-child(3) { 110 | -webkit-animation-delay: 0.2s; 111 | -moz-animation-delay: 0.2s; 112 | animation-delay: 0.2s; 113 | } 114 | 115 | .loading-dot:nth-child(4) { 116 | -webkit-animation-delay: 0.3s; 117 | -moz-animation-delay: 0.3s; 118 | animation-delay: 0.3s; 119 | } 120 | 121 | @-webkit-keyframes loadingFade { 122 | 0% { opacity: 0; } 123 | 50% { opacity: 0.8; } 124 | 100% { opacity: 0; } 125 | } 126 | 127 | @-moz-keyframes loadingFade { 128 | 0% { opacity: 0; } 129 | 50% { opacity: 0.8; } 130 | 100% { opacity: 0; } 131 | } 132 | 133 | @keyframes loadingFade { 134 | 0% { opacity: 0; } 135 | 50% { opacity: 0.8; } 136 | 100% { opacity: 0; } 137 | } -------------------------------------------------------------------------------- /resource/Web/geetest-validator/geetest.html: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | 6 | 7 | Document 8 | 9 | 10 | 11 | 12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 | 25 | 26 | 27 | 77 | 78 | 79 | -------------------------------------------------------------------------------- /resource/Web/geetest-validator/js/gt.js: -------------------------------------------------------------------------------- 1 | "v0.4.8 Geetest Inc."; 2 | 3 | (function (window) { 4 | "use strict"; 5 | if (typeof window === 'undefined') { 6 | throw new Error('Geetest requires browser environment'); 7 | } 8 | 9 | var document = window.document; 10 | var Math = window.Math; 11 | var head = document.getElementsByTagName("head")[0]; 12 | 13 | function _Object(obj) { 14 | this._obj = obj; 15 | } 16 | 17 | _Object.prototype = { 18 | _each: function (process) { 19 | var _obj = this._obj; 20 | for (var k in _obj) { 21 | if (_obj.hasOwnProperty(k)) { 22 | process(k, _obj[k]); 23 | } 24 | } 25 | return this; 26 | } 27 | }; 28 | 29 | function Config(config) { 30 | var self = this; 31 | new _Object(config)._each(function (key, value) { 32 | self[key] = value; 33 | }); 34 | } 35 | 36 | Config.prototype = { 37 | api_server: 'api.geetest.com', 38 | protocol: 'http://', 39 | typePath: '/gettype.php', 40 | fallback_config: { 41 | slide: { 42 | static_servers: ["static.geetest.com", "dn-staticdown.qbox.me"], 43 | type: 'slide', 44 | slide: '/static/js/geetest.0.0.0.js' 45 | }, 46 | fullpage: { 47 | static_servers: ["static.geetest.com", "dn-staticdown.qbox.me"], 48 | type: 'fullpage', 49 | fullpage: '/static/js/fullpage.0.0.0.js' 50 | } 51 | }, 52 | _get_fallback_config: function () { 53 | var self = this; 54 | if (isString(self.type)) { 55 | return self.fallback_config[self.type]; 56 | } else if (self.new_captcha) { 57 | return self.fallback_config.fullpage; 58 | } else { 59 | return self.fallback_config.slide; 60 | } 61 | }, 62 | _extend: function (obj) { 63 | var self = this; 64 | new _Object(obj)._each(function (key, value) { 65 | self[key] = value; 66 | }) 67 | } 68 | }; 69 | var isNumber = function (value) { 70 | return (typeof value === 'number'); 71 | }; 72 | var isString = function (value) { 73 | return (typeof value === 'string'); 74 | }; 75 | var isBoolean = function (value) { 76 | return (typeof value === 'boolean'); 77 | }; 78 | var isObject = function (value) { 79 | return (typeof value === 'object' && value !== null); 80 | }; 81 | var isFunction = function (value) { 82 | return (typeof value === 'function'); 83 | }; 84 | var MOBILE = /Mobi/i.test(navigator.userAgent); 85 | var pt = MOBILE ? 3 : 0; 86 | 87 | var callbacks = {}; 88 | var status = {}; 89 | 90 | var nowDate = function () { 91 | var date = new Date(); 92 | var year = date.getFullYear(); 93 | var month = date.getMonth() + 1; 94 | var day = date.getDate(); 95 | var hours = date.getHours(); 96 | var minutes = date.getMinutes(); 97 | var seconds = date.getSeconds(); 98 | 99 | if (month >= 1 && month <= 9) { 100 | month = '0' + month; 101 | } 102 | if (day >= 0 && day <= 9) { 103 | day = '0' + day; 104 | } 105 | if (hours >= 0 && hours <= 9) { 106 | hours = '0' + hours; 107 | } 108 | if (minutes >= 0 && minutes <= 9) { 109 | minutes = '0' + minutes; 110 | } 111 | if (seconds >= 0 && seconds <= 9) { 112 | seconds = '0' + seconds; 113 | } 114 | var currentdate = year + '-' + month + '-' + day + " " + hours + ":" + minutes + ":" + seconds; 115 | return currentdate; 116 | } 117 | 118 | var random = function () { 119 | return parseInt(Math.random() * 10000) + (new Date()).valueOf(); 120 | }; 121 | 122 | var loadScript = function (url, cb) { 123 | var script = document.createElement("script"); 124 | script.charset = "UTF-8"; 125 | script.async = true; 126 | 127 | // 对geetest的静态资源添加 crossOrigin 128 | if ( /static\.geetest\.com/g.test(url)) { 129 | script.crossOrigin = "anonymous"; 130 | } 131 | 132 | script.onerror = function () { 133 | cb(true); 134 | }; 135 | var loaded = false; 136 | script.onload = script.onreadystatechange = function () { 137 | if (!loaded && 138 | (!script.readyState || 139 | "loaded" === script.readyState || 140 | "complete" === script.readyState)) { 141 | 142 | loaded = true; 143 | setTimeout(function () { 144 | cb(false); 145 | }, 0); 146 | } 147 | }; 148 | script.src = url; 149 | head.appendChild(script); 150 | }; 151 | 152 | var normalizeDomain = function (domain) { 153 | // special domain: uems.sysu.edu.cn/jwxt/geetest/ 154 | // return domain.replace(/^https?:\/\/|\/.*$/g, ''); uems.sysu.edu.cn 155 | return domain.replace(/^https?:\/\/|\/$/g, ''); // uems.sysu.edu.cn/jwxt/geetest 156 | }; 157 | var normalizePath = function (path) { 158 | path = path.replace(/\/+/g, '/'); 159 | if (path.indexOf('/') !== 0) { 160 | path = '/' + path; 161 | } 162 | return path; 163 | }; 164 | var normalizeQuery = function (query) { 165 | if (!query) { 166 | return ''; 167 | } 168 | var q = '?'; 169 | new _Object(query)._each(function (key, value) { 170 | if (isString(value) || isNumber(value) || isBoolean(value)) { 171 | q = q + encodeURIComponent(key) + '=' + encodeURIComponent(value) + '&'; 172 | } 173 | }); 174 | if (q === '?') { 175 | q = ''; 176 | } 177 | return q.replace(/&$/, ''); 178 | }; 179 | var makeURL = function (protocol, domain, path, query) { 180 | domain = normalizeDomain(domain); 181 | 182 | var url = normalizePath(path) + normalizeQuery(query); 183 | if (domain) { 184 | url = protocol + domain + url; 185 | } 186 | 187 | return url; 188 | }; 189 | 190 | var load = function (config, send, protocol, domains, path, query, cb) { 191 | var tryRequest = function (at) { 192 | 193 | var url = makeURL(protocol, domains[at], path, query); 194 | loadScript(url, function (err) { 195 | if (err) { 196 | if (at >= domains.length - 1) { 197 | cb(true); 198 | // report gettype error 199 | if (send) { 200 | config.error_code = 508; 201 | var url = protocol + domains[at] + path; 202 | reportError(config, url); 203 | } 204 | } else { 205 | tryRequest(at + 1); 206 | } 207 | } else { 208 | cb(false); 209 | } 210 | }); 211 | }; 212 | tryRequest(0); 213 | }; 214 | 215 | 216 | var jsonp = function (domains, path, config, callback) { 217 | if (isObject(config.getLib)) { 218 | config._extend(config.getLib); 219 | callback(config); 220 | return; 221 | } 222 | if (config.offline) { 223 | callback(config._get_fallback_config()); 224 | return; 225 | } 226 | 227 | var cb = "geetest_" + random(); 228 | window[cb] = function (data) { 229 | if (data.status == 'success') { 230 | callback(data.data); 231 | } else if (!data.status) { 232 | callback(data); 233 | } else { 234 | callback(config._get_fallback_config()); 235 | } 236 | window[cb] = undefined; 237 | try { 238 | delete window[cb]; 239 | } catch (e) { 240 | } 241 | }; 242 | load(config, true, config.protocol, domains, path, { 243 | gt: config.gt, 244 | callback: cb 245 | }, function (err) { 246 | if (err) { 247 | callback(config._get_fallback_config()); 248 | } 249 | }); 250 | }; 251 | 252 | var reportError = function (config, url) { 253 | load(config, false, config.protocol, ['monitor.geetest.com'], '/monitor/send', { 254 | time: nowDate(), 255 | captcha_id: config.gt, 256 | challenge: config.challenge, 257 | pt: pt, 258 | exception_url: url, 259 | error_code: config.error_code 260 | }, function (err) {}) 261 | } 262 | 263 | var throwError = function (errorType, config) { 264 | var errors = { 265 | networkError: '网络错误', 266 | gtTypeError: 'gt字段不是字符串类型' 267 | }; 268 | if (typeof config.onError === 'function') { 269 | config.onError(errors[errorType]); 270 | } else { 271 | throw new Error(errors[errorType]); 272 | } 273 | }; 274 | 275 | var detect = function () { 276 | return window.Geetest || document.getElementById("gt_lib"); 277 | }; 278 | 279 | if (detect()) { 280 | status.slide = "loaded"; 281 | } 282 | 283 | window.initGeetest = function (userConfig, callback) { 284 | 285 | var config = new Config(userConfig); 286 | 287 | if (userConfig.https) { 288 | config.protocol = 'https://'; 289 | } else if (!userConfig.protocol) { 290 | config.protocol = window.location.protocol + '//'; 291 | } 292 | 293 | // for KFC 294 | if (userConfig.gt === '050cffef4ae57b5d5e529fea9540b0d1' || 295 | userConfig.gt === '3bd38408ae4af923ed36e13819b14d42') { 296 | config.apiserver = 'yumchina.geetest.com/'; // for old js 297 | config.api_server = 'yumchina.geetest.com'; 298 | } 299 | 300 | if(userConfig.gt){ 301 | window.GeeGT = userConfig.gt 302 | } 303 | 304 | if(userConfig.challenge){ 305 | window.GeeChallenge = userConfig.challenge 306 | } 307 | 308 | if (isObject(userConfig.getType)) { 309 | config._extend(userConfig.getType); 310 | } 311 | jsonp([config.api_server || config.apiserver], config.typePath, config, function (newConfig) { 312 | var type = newConfig.type; 313 | var init = function () { 314 | config._extend(newConfig); 315 | callback(new window.Geetest(config)); 316 | }; 317 | 318 | callbacks[type] = callbacks[type] || []; 319 | var s = status[type] || 'init'; 320 | if (s === 'init') { 321 | status[type] = 'loading'; 322 | 323 | callbacks[type].push(init); 324 | 325 | load(config, true, config.protocol, newConfig.static_servers || newConfig.domains, newConfig[type] || newConfig.path, null, function (err) { 326 | if (err) { 327 | status[type] = 'fail'; 328 | throwError('networkError', config); 329 | } else { 330 | status[type] = 'loaded'; 331 | var cbs = callbacks[type]; 332 | for (var i = 0, len = cbs.length; i < len; i = i + 1) { 333 | var cb = cbs[i]; 334 | if (isFunction(cb)) { 335 | cb(); 336 | } 337 | } 338 | callbacks[type] = []; 339 | } 340 | }); 341 | } else if (s === "loaded") { 342 | init(); 343 | } else if (s === "fail") { 344 | throwError('networkError', config); 345 | } else if (s === "loading") { 346 | callbacks[type].push(init); 347 | } 348 | }); 349 | 350 | }; 351 | 352 | 353 | })(window); 354 | 355 | -------------------------------------------------------------------------------- /resource/img/BILIBILI_LOGO-PINK.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/JonyanDunh/BilibiliClient/9974483a17f972d7469c17b4192709c3c958ff07/resource/img/BILIBILI_LOGO-PINK.png -------------------------------------------------------------------------------- /resource/img/BILIBILI_LOGO.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/JonyanDunh/BilibiliClient/9974483a17f972d7469c17b4192709c3c958ff07/resource/img/BILIBILI_LOGO.png -------------------------------------------------------------------------------- /resource/img/Bilibili_User_Cover.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/JonyanDunh/BilibiliClient/9974483a17f972d7469c17b4192709c3c958ff07/resource/img/Bilibili_User_Cover.png -------------------------------------------------------------------------------- /resource/img/PILIPILI_LOGO.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/JonyanDunh/BilibiliClient/9974483a17f972d7469c17b4192709c3c958ff07/resource/img/PILIPILI_LOGO.png -------------------------------------------------------------------------------- /resource/img/cover.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/JonyanDunh/BilibiliClient/9974483a17f972d7469c17b4192709c3c958ff07/resource/img/cover.jpg -------------------------------------------------------------------------------- /resource/img/exported_qrcode_image_600.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/JonyanDunh/BilibiliClient/9974483a17f972d7469c17b4192709c3c958ff07/resource/img/exported_qrcode_image_600.png -------------------------------------------------------------------------------- /resource/img/preview1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/JonyanDunh/BilibiliClient/9974483a17f972d7469c17b4192709c3c958ff07/resource/img/preview1.png -------------------------------------------------------------------------------- /resource/img/preview2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/JonyanDunh/BilibiliClient/9974483a17f972d7469c17b4192709c3c958ff07/resource/img/preview2.png -------------------------------------------------------------------------------- /resource/img/preview3.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/JonyanDunh/BilibiliClient/9974483a17f972d7469c17b4192709c3c958ff07/resource/img/preview3.png -------------------------------------------------------------------------------- /resource/img/preview4.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/JonyanDunh/BilibiliClient/9974483a17f972d7469c17b4192709c3c958ff07/resource/img/preview4.png -------------------------------------------------------------------------------- /resource/img/二维码.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/JonyanDunh/BilibiliClient/9974483a17f972d7469c17b4192709c3c958ff07/resource/img/二维码.png -------------------------------------------------------------------------------- /resource/img/头像.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/JonyanDunh/BilibiliClient/9974483a17f972d7469c17b4192709c3c958ff07/resource/img/头像.png -------------------------------------------------------------------------------- /resource/img/弹幕数.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/JonyanDunh/BilibiliClient/9974483a17f972d7469c17b4192709c3c958ff07/resource/img/弹幕数.png -------------------------------------------------------------------------------- /resource/img/播放量.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/JonyanDunh/BilibiliClient/9974483a17f972d7469c17b4192709c3c958ff07/resource/img/播放量.png -------------------------------------------------------------------------------- /resource/img/收藏数.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/JonyanDunh/BilibiliClient/9974483a17f972d7469c17b4192709c3c958ff07/resource/img/收藏数.png -------------------------------------------------------------------------------- /resource/img/点赞数.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/JonyanDunh/BilibiliClient/9974483a17f972d7469c17b4192709c3c958ff07/resource/img/点赞数.png -------------------------------------------------------------------------------- /resource/img/硬币数.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/JonyanDunh/BilibiliClient/9974483a17f972d7469c17b4192709c3c958ff07/resource/img/硬币数.png -------------------------------------------------------------------------------- /resource/img/评论数.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/JonyanDunh/BilibiliClient/9974483a17f972d7469c17b4192709c3c958ff07/resource/img/评论数.png -------------------------------------------------------------------------------- /resource/img/账号.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/JonyanDunh/BilibiliClient/9974483a17f972d7469c17b4192709c3c958ff07/resource/img/账号.png -------------------------------------------------------------------------------- /resource/img/转发数.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/JonyanDunh/BilibiliClient/9974483a17f972d7469c17b4192709c3c958ff07/resource/img/转发数.png -------------------------------------------------------------------------------- /resource/img/返回.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/JonyanDunh/BilibiliClient/9974483a17f972d7469c17b4192709c3c958ff07/resource/img/返回.png -------------------------------------------------------------------------------- /resource/img/频道.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/JonyanDunh/BilibiliClient/9974483a17f972d7469c17b4192709c3c958ff07/resource/img/频道.png -------------------------------------------------------------------------------- /video.xaml: -------------------------------------------------------------------------------- 1 |  14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 44 | 50 | 53 | 55 | 56 | 60 | 61 | 62 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 88 | 94 | 95 | 96 | 97 | 98 | 100 | 101 | 102 | 103 | 104 | 116 | 117 | 118 | 124 | 125 | 126 | 127 | 128 | 141 | 145 | 149 | 153 | 157 | 161 | 165 | 166 | 184 | 185 | 202 | 203 | 220 | 221 | 222 | 223 | 224 | 225 | 226 | 227 | 228 | 229 | 230 | 231 | 232 | 235 | 250 | 265 | 266 | 267 | 268 | 269 | 270 | 271 | 272 | 273 | 274 | 275 | 276 | 277 | 278 | 279 | -------------------------------------------------------------------------------- /video.xaml.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.ComponentModel; 4 | using System.Globalization; 5 | using System.IO; 6 | using System.Text.RegularExpressions; 7 | using System.Threading; 8 | using System.Windows; 9 | using System.Windows.Controls; 10 | using System.Windows.Data; 11 | using System.Windows.Media; 12 | using System.Windows.Threading; 13 | using Unosquare.FFME.Common; 14 | using static Bilibili_Client.Bilibili_Video; 15 | 16 | namespace Bilibili_Client 17 | { 18 | /// 19 | /// video.xaml 的交互逻辑 20 | /// 21 | /// 22 | 23 | public class TimeConver : IValueConverter 24 | { 25 | public object Convert(object value, Type targetType, object parameter, CultureInfo culture) 26 | { 27 | 28 | if (value == null) 29 | return DependencyProperty.UnsetValue; 30 | return new Regex(@"(?