├── .editorconfig ├── .gitattributes ├── .gitignore ├── .travis.yml ├── BilibiliLink.wl ├── BilibiliLinkLoader.m ├── Config ├── BundleInfo.m ├── DocInfo.m └── LoadInfo.m ├── Kernel ├── Format.wl ├── init.m └── scripts.m ├── LICENSE ├── Packages ├── !APIs.m ├── !Directories.m ├── BilibiliCore.m ├── BilibiliDDOS.m ├── BilibiliDataServer.m ├── BilibiliPhoto.m ├── BilibiliUI.m ├── BilibiliVideoSection.m ├── Crawlers │ ├── ArchiveCrawlers.nb │ └── TagCrawlers.nb ├── ObjectAlbum.m ├── ObjectDownload.m ├── ObjectVideoSection.m └── __Dev │ ├── !BilibiliColumns.m │ ├── Album.m │ ├── BilibiliSearch.m │ └── Proxy.m ├── PacletInfo.m ├── Readme.md ├── Resources └── ico │ ├── BilibiliAlbumObject.jpg │ ├── BilibiliDownloadObject.png │ ├── BilibiliVideoSectionObject.png │ └── Readme.md ├── docs ├── .vuepress │ ├── config.js │ └── override.styl ├── Crawler │ ├── Readme.md │ ├── Tag.md │ └── Video.md ├── Photo │ ├── Object.md │ └── Readme.md ├── Readme.md ├── Start │ ├── Design.md │ ├── Guide.md │ └── Readme.md ├── Toys │ └── Readme.md └── Video │ ├── CP.md │ ├── Object.md │ └── Readme.md ├── package.json └── yarn.lock /.editorconfig: -------------------------------------------------------------------------------- 1 | root = true 2 | 3 | [*] 4 | charset = utf-8 5 | indent_style = tab 6 | indent_size = 4 7 | end_of_line = CRLF 8 | insert_final_newline = true 9 | trim_trailing_whitespace = true 10 | -------------------------------------------------------------------------------- /.gitattributes: -------------------------------------------------------------------------------- 1 | * text=auto 2 | # 屏蔽文档与 build 文件统计 3 | Documentation/ linguist-documentation 4 | # make things fun, lol 5 | *.md linguist-language=vue 6 | *.wl linguist-language=bash 7 | Config/ linguist-language=perl 8 | BilibiliLinkLoader.m linguist-language=ruby 9 | Packages/__Dev/*.m linguist-language=mercury 10 | # lfs track notebook 11 | *.nb filter=lfs diff=lfs merge=lfs -text 12 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Idea Project 2 | *.iml 3 | .idea/ 4 | 5 | # yarn 6 | node_modules/ 7 | npm-debug.log* 8 | yarn-debug.log* 9 | yarn-error.log* 10 | 11 | # Build Temp 12 | .DS_Store 13 | docs/.build/ 14 | 15 | 16 | # Notebook 17 | # *.nb 18 | -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | sudo: required 2 | dist: trusty 3 | # 只需要自定义下面五个量 4 | env: 5 | global: 6 | - GITHUB_NAME: Gal@Builder # 瞎填都可以 7 | - GITHUB_MAIL: GAL@moe-net.tech # 瞎填都可以 8 | - GITHUB_USER: Moe-Net # 你的用户名 9 | - GITHUB_REPO: BilibiliLink # 你的项目名 10 | # 还有一个 TRAVIS_KEY 填在 travis settings 里! 11 | # 教程: https://github.com/settings/tokens 12 | before_script: 13 | - export TZ='Asia/Shanghai' 14 | - git config --global user.name "${GITHUB_NAME}" 15 | - git config --global user.email "${GITHUB_MAIL}" 16 | script: 17 | # 使用要求 10 次提交之类有 tag 存在, 名称必须为 v1.0.0 类似的形式 18 | - git clone --depth 10 --branch master --single-branch https://github.com/${GITHUB_USER}/${GITHUB_REPO} 19 | - cd ${GITHUB_REPO} 20 | - ver=`git describe --abbrev=0 --tags` 21 | - nVer=`echo $ver | awk -F. '{printf "%s.%s.%s\n",$1,$2,$3+1}'` 22 | - echo $nVer 23 | - cd .. 24 | before_deploy: 25 | - git tag -a "$nVer" -m "$(date +'%Y%m%d%H%M%S')-$(git log --format=%h -1)" 26 | - cd ${GITHUB_REPO} 27 | # 清理工程文件 28 | - rm -rf Packages/Crawlers 29 | - rm -rf Packages/__Dev 30 | - rm -rf docs 31 | - rm -f .gitignore 32 | - rm -f .gitattributes 33 | - rm -f .editorconfig 34 | - rm -f .travis.yml 35 | - rm -f *.json 36 | - rm -f yarn.lock 37 | # 清理文档(可选) 38 | # - rm -rf Documentation 39 | - ls && cd .. 40 | - tar -cJf ${GITHUB_REPO}.tar.xz ${GITHUB_REPO} 41 | deploy: 42 | provider: releases 43 | api_key: ${TRAVIS_KEY} 44 | name: AutoBuild-$nVer 45 | skip_cleanup: true 46 | file: 47 | - ${GITHUB_REPO}.tar.xz 48 | prerelease: true 49 | -------------------------------------------------------------------------------- /BilibiliLink.wl: -------------------------------------------------------------------------------- 1 | If[!TrueQ[BilibiliLink`PackageScope`Private`$LoadCompleted], 2 | << BilibiliLink`BilibiliLinkLoader` 3 | ] -------------------------------------------------------------------------------- /BilibiliLinkLoader.m: -------------------------------------------------------------------------------- 1 | (* ::Title:: *) 2 | (*BilibiliLink`*) 3 | 4 | 5 | (* ::Text::GrayLevel[0.5]:: *) 6 | (* Autogenerated BilibiliLink loader file *) 7 | 8 | 9 | Unprotect[BilibiliLink`PackageScope`Private`$TopLevelLoad]; 10 | BilibiliLink`PackageScope`Private`$TopLevelLoad = 11 | MemberQ[$ContextPath, "Global`"]; 12 | 13 | 14 | BeginPackage["BilibiliLink`"]; 15 | 16 | 17 | BilibiliLink::usage = 18 | "BilibiliLink is a manager head for the BilibiliLink package"; 19 | 20 | 21 | (* ::Subsubsection::Closed:: *) 22 | (*$ContextPath*) 23 | 24 | 25 | $ContextPath = 26 | Join[$ContextPath, 27 | "BilibiliLink`" <> 28 | StringReplace[ 29 | FileNameDrop[#, FileNameDepth@DirectoryName@$InputFileName], 30 | $PathnameSeparator -> "`" 31 | ]& /@ 32 | Select[ 33 | DirectoryQ@# && 34 | StringMatchQ[ 35 | StringReplace[ 36 | FileNameDrop[#, FileNameDepth@DirectoryName@$InputFileName], 37 | $PathnameSeparator -> "`" 38 | ], 39 | ("$" | WordCharacter).. 40 | ] 41 | &]@ 42 | FileNames["*", 43 | FileNameJoin@{ 44 | DirectoryName@$InputFileName, 45 | "Packages" 46 | }, 47 | Infinity 48 | ] 49 | ] 50 | 51 | 52 | (* ::Section:: *) 53 | (* Package Functions *) 54 | 55 | 56 | Unprotect["`PackageScope`Private`*"]; 57 | Begin["`PackageScope`Private`"]; 58 | 59 | 60 | Clear[BilibiliLink]; 61 | 62 | 63 | (* ::Subsection:: *) 64 | (*Constants*) 65 | 66 | 67 | (* ::Subsubsection::Closed:: *) 68 | (*Naming*) 69 | 70 | 71 | BilibiliLink["Directory"] := 72 | $PackageDirectory; 73 | $PackageDirectory = 74 | DirectoryName@$InputFileName; 75 | 76 | 77 | BilibiliLink["Name"] := 78 | $PackageName; 79 | $PackageName = 80 | "BilibiliLink"; 81 | 82 | 83 | (* ::Subsubsection::Closed:: *) 84 | (*Loading*) 85 | 86 | 87 | BilibiliLink["PackageListing"] := $PackageListing; 88 | $PackageListing = <||>; 89 | BilibiliLink["Contexts"] := $PackageContexts; 90 | $PackageContexts = { 91 | "BilibiliLink`", 92 | "BilibiliLink`PackageScope`Private`", 93 | "BilibiliLink`PackageScope`Package`" 94 | }; 95 | $PackageDeclared = 96 | TrueQ[$PackageDeclared]; 97 | 98 | 99 | (* ::Subsubsection::Closed:: *) 100 | (*Scoping*) 101 | 102 | 103 | BilibiliLink["FEScopedSymbols"] := $PackageFEHiddenSymbols; 104 | $PackageFEHiddenSymbols = {}; 105 | BilibiliLink["PackageScopedSymbols"] := $PackageScopedSymbols; 106 | $PackageScopedSymbols = {}; 107 | BilibiliLink["LoadingParameters"] := $PackageLoadSpecs 108 | $PackageLoadSpecs = 109 | Merge[ 110 | { 111 | With[ 112 | { 113 | f = 114 | Append[ 115 | FileNames[ 116 | "LoadInfo." ~~ "m" | "wl", 117 | FileNameJoin@{$PackageDirectory, "Config"} 118 | ], 119 | None 120 | ][[1]] 121 | }, 122 | Replace[ 123 | Quiet[ 124 | Import@f, 125 | { 126 | Import::nffil, 127 | Import::chtype 128 | } 129 | ], 130 | Except[KeyValuePattern[{}]] :> 131 | {} 132 | ] 133 | ], 134 | With[ 135 | { 136 | f = 137 | Append[ 138 | FileNames[ 139 | "LoadInfo." ~~ "m" | "wl", 140 | FileNameJoin@{$PackageDirectory, "Private", "Config"} 141 | ], 142 | None 143 | ][[1]]}, 144 | Replace[ 145 | Quiet[ 146 | Import@f, 147 | { 148 | Import::nffil, 149 | Import::chtype 150 | } 151 | ], 152 | Except[KeyValuePattern[{}]] :> 153 | {} 154 | ] 155 | ] 156 | }, 157 | Last 158 | ]; 159 | 160 | 161 | (* ::Subsubsection::Closed:: *) 162 | (*Allow flags*) 163 | 164 | 165 | BilibiliLink["AllowRescoping"] := $AllowPackageRescoping; 166 | $AllowPackageRescoping = 167 | Replace[ 168 | Lookup[$PackageLoadSpecs, "AllowRescoping"], 169 | Except[True | False] -> $TopLevelLoad 170 | ]; 171 | BilibiliLink["AllowRecoloring"] := $AllowPackageRecoloring; 172 | $AllowPackageRecoloring = 173 | Replace[ 174 | Lookup[$PackageLoadSpecs, "AllowRecoloring"], 175 | Except[True | False] -> $TopLevelLoad 176 | ]; 177 | BilibiliLink["AllowAutocompletions"] := $AllowPackageAutocompletions; 178 | $AllowPackageAutocompletions = 179 | Replace[ 180 | Lookup[$PackageLoadSpecs, "AllowAutocompletions"], 181 | Except[True | False] -> $TopLevelLoad 182 | ]; 183 | (* ::Subsection:: *) 184 | (*Paths*) 185 | 186 | 187 | (* ::Subsubsection::Closed:: *) 188 | (*PackageFilePath*) 189 | 190 | 191 | PackageFilePath[p__] := 192 | FileNameJoin[Flatten@{ 193 | $PackageDirectory, 194 | p 195 | }]; 196 | 197 | 198 | (* ::Subsubsection::Closed:: *) 199 | (*PackageFEFile*) 200 | 201 | 202 | PackageFEFile[p___, f_] := 203 | FrontEnd`FileName[ 204 | Evaluate@ 205 | Flatten@{ 206 | $PackageName, 207 | p 208 | }, 209 | f 210 | ]; 211 | 212 | 213 | (* ::Subsubsection::Closed:: *) 214 | (*PackagePathSymbol*) 215 | 216 | 217 | PackagePathSymbol[parts___String, sym_String] := 218 | ToExpression[StringRiffle[{$PackageName, parts, sym}, "`"], StandardForm, HoldPattern]; 219 | PackagePathSymbol[parts___String, sym_Symbol] := 220 | PackagePathSymbol[parts, Evaluate@SymbolName@Unevaluated[sym]]; 221 | PackagePathSymbol ~ SetAttributes ~ HoldRest; 222 | (* ::Subsection:: *) 223 | (*Loading*) 224 | 225 | 226 | (* ::Subsubsection:: *) 227 | (*Constants*) 228 | 229 | 230 | BilibiliLink["FileContexts"] := $PackageFileContexts; 231 | If[Not@AssociationQ@$PackageFileContexts, 232 | $PackageFileContexts = 233 | <||> 234 | ]; 235 | 236 | 237 | BilibiliLink["DeclaredPackages"] := $DeclaredPackages; 238 | If[Not@AssociationQ@$DeclaredPackages, 239 | $DeclaredPackages = 240 | <||> 241 | ]; 242 | 243 | 244 | BilibiliLink["LoadedPackages"] := $LoadedPackages; 245 | If[Not@ListQ@$LoadedPackages, 246 | $LoadedPackages = {} 247 | ]; 248 | 249 | 250 | (* ::Subsubsection::Closed:: *) 251 | (*PackageFileContext*) 252 | 253 | 254 | PackageFileContextPath[f_String?DirectoryQ] := 255 | FileNameSplit[FileNameDrop[f, FileNameDepth[$PackageDirectory] + 1]]; 256 | PackageFileContextPath[f_String?FileExistsQ] := 257 | PackageFileContextPath[DirectoryName@f]; 258 | 259 | 260 | PackageFileContext[f_String?DirectoryQ] := 261 | With[{s = PackageFileContextPath[f]}, 262 | StringRiffle[Append[""]@Prepend[s, BilibiliLink], "`"] 263 | ]; 264 | PackageFileContext[f_String?FileExistsQ] := 265 | PackageFileContext[DirectoryName[f]]; 266 | 267 | 268 | (* ::Subsubsection::Closed:: *) 269 | (*PackageExecute*) 270 | 271 | 272 | PackageExecute[expr_] := 273 | CompoundExpression[ 274 | Block[{$ContextPath = {"System`"}}, 275 | BeginPackage["BilibiliLink`"]; 276 | $ContextPath = 277 | DeleteDuplicates[ 278 | Join[$ContextPath, $PackageContexts] 279 | ]; 280 | CheckAbort[ 281 | With[{res = expr}, 282 | EndPackage[]; 283 | res 284 | ], 285 | EndPackage[] 286 | ] 287 | ] 288 | ]; 289 | PackageExecute ~ SetAttributes ~ HoldFirst 290 | 291 | 292 | (* ::Subsubsection::Closed:: *) 293 | (*PackagePullDeclarations*) 294 | 295 | 296 | PackagePullDeclarationsAction // Clear 297 | PackagePullDeclarationsAction[ 298 | Hold[ 299 | _Begin | _BeginPackage | 300 | CompoundExpression[_Begin | _BeginPackage, ___] 301 | ] 302 | ] := 303 | Throw[Begin]; 304 | PackagePullDeclarationsAction[ 305 | p : 306 | Hold[ 307 | _PackageFEHiddenBlock | _PackageScopeBlock | 308 | CompoundExpression[ 309 | _PackageFEHiddenBlock | _PackageScopeBlock, 310 | ___] 311 | ] 312 | ] /; TrueQ[$AllowPackageRecoloring] := 313 | ( 314 | ReleaseHold[p]; 315 | Sow[p]; 316 | ); 317 | PackagePullDeclarationsAction[e : Except[Hold[Expression]]] := 318 | Sow@e; 319 | 320 | 321 | PackagePullDeclarations[pkgFile_] := 322 | pkgFile -> 323 | Cases[ 324 | Reap[ 325 | With[{f = OpenRead[pkgFile]}, 326 | Catch@ 327 | Do[ 328 | If[ 329 | Length[ 330 | ReadList[ 331 | f, 332 | PackagePullDeclarationsAction@Hold[Expression], 333 | 1 334 | ] 335 | ] === 0, 336 | Throw[EndOfFile] 337 | ], 338 | Infinity 339 | ]; 340 | Close[f] 341 | ] 342 | ][[2, 1]], 343 | s_Symbol?( 344 | Function[Null, 345 | Quiet[Context[#] === $Context], 346 | HoldAllComplete 347 | ] 348 | ) :> 349 | HoldPattern[s], 350 | Infinity 351 | ] 352 | 353 | 354 | (* ::Subsubsection::Closed:: *) 355 | (*PackageLoadPackage*) 356 | 357 | 358 | PackageLoadPackage[heldSym_, context_, pkgFile_ -> syms_] := 359 | Block[{ 360 | $loadingChain = 361 | If[ListQ@$loadingChain, $loadingChain, {}], 362 | $inLoad = TrueQ[$inLoad], 363 | $ContextPath = $ContextPath 364 | }, 365 | If[!MemberQ[$loadingChain, pkgFile], 366 | With[{$$inLoad = $inLoad}, 367 | $inLoad = True; 368 | If[$AllowPackageRecoloring, 369 | Internal`SymbolList[False] 370 | ]; 371 | Replace[Thread[syms, HoldPattern], 372 | Verbatim[HoldPattern][{s__}] :> Clear[s] 373 | ]; 374 | If[Not@MemberQ[$ContextPath, context], 375 | $ContextPath = Prepend[$ContextPath, context]; 376 | ]; 377 | Block[{PackageFEHiddenBlock = Null}, 378 | PackageAppGet[context, pkgFile]; 379 | ]; 380 | Unprotect[$LoadedPackages]; 381 | AppendTo[$LoadedPackages, pkgFile]; 382 | Protect[$LoadedPackages]; 383 | If[!$$inLoad && $AllowPackageRecoloring, 384 | Internal`SymbolList[True] 385 | ]; 386 | ReleaseHold[heldSym] 387 | ] 388 | ] 389 | ]; 390 | 391 | 392 | (* ::Subsubsection::Closed:: *) 393 | (*PackageDeclarePackage*) 394 | 395 | 396 | PackageDeclarePackage[pkgFile_ -> syms_] := 397 | With[{c = $Context}, 398 | $DeclaredPackages[pkgFile] = syms; 399 | $PackageFileContexts[pkgFile] = c; 400 | Map[ 401 | If[True, 402 | # := PackageLoadPackage[#, c, pkgFile -> syms] 403 | ]&, 404 | syms 405 | ] 406 | ]; 407 | 408 | 409 | (* ::Subsubsection::Closed:: *) 410 | (*PackageLoadDeclare*) 411 | 412 | 413 | PackageLoadDeclare[pkgFile_String] := 414 | If[!MemberQ[$LoadedPackages, pkgFile], 415 | If[!KeyMemberQ[$DeclaredPackages, pkgFile], 416 | PackageDeclarePackage@ 417 | PackagePullDeclarations[pkgFile] 418 | ], 419 | PackageAppGet[pkgFile] 420 | ]; 421 | 422 | 423 | (* ::Subsubsection::Closed:: *) 424 | (*PackageAppLoad*) 425 | 426 | 427 | BilibiliLink["Load", args___] := 428 | PackageAppLoad[args] 429 | 430 | 431 | packageAppLoad[dir_, listing_] := 432 | With[ 433 | { 434 | fileNames = 435 | Select[ 436 | FileNames["*", dir], 437 | DirectoryQ@# || MatchQ[FileExtension[#], "m" | "wl"]& 438 | ] 439 | }, 440 | Replace[ 441 | Select[fileNames, 442 | StringMatchQ[ 443 | ToLowerCase@FileNameTake[#], 444 | "__pre__." ~~ ("m" | "wl") 445 | ]& 446 | ], 447 | {f_} :> Get[f] 448 | ]; 449 | PackageAppLoad[ 450 | $PackageListing[listing] = 451 | Select[fileNames, StringFreeQ["__"]@*FileBaseName] 452 | ]; 453 | Replace[ 454 | Select[fileNames, 455 | StringMatchQ[ 456 | ToLowerCase@FileNameTake[#], 457 | "__Post__." ~~ ("m" | "wl") 458 | ]& 459 | ], 460 | {f_} :> Get[f] 461 | ]; 462 | ]; 463 | 464 | 465 | PackageAppLoad[dir_String?DirectoryQ] := 466 | If[StringMatchQ[FileBaseName@dir, (WordCharacter | "$")..], 467 | Begin["`" <> FileBaseName[dir] <> "`"]; 468 | AppendTo[$PackageContexts, $Context]; 469 | packageAppLoad[dir, FileNameDrop[dir, FileNameDepth[$PackageDirectory] + 1]]; 470 | End[]; 471 | ]; 472 | PackageAppLoad[file_String?FileExistsQ] := 473 | PackageLoadDeclare[file]; 474 | PackageAppLoad[] := 475 | PackageExecute@ 476 | packageAppLoad[FileNameJoin@{$PackageDirectory, "Packages"}, $PackageName]; 477 | PackageAppLoad ~ SetAttributes ~ Listable; 478 | 479 | 480 | (* ::Subsubsection::Closed:: *) 481 | (*PackageAppGet*) 482 | 483 | 484 | BilibiliLink["Get", f__] := 485 | PackageAppGet[f]; 486 | PackageAppGet[f_] := 487 | PackageExecute@ 488 | With[{fBase = 489 | If[FileExistsQ@f, 490 | f, 491 | PackageFilePath["Packages", f <> ".m"] 492 | ] 493 | }, 494 | With[{cont = 495 | Most@ 496 | FileNameSplit[ 497 | FileNameDrop[fBase, FileNameDepth[PackageFilePath["Packages"]]] 498 | ]}, 499 | If[Length[cont] > 0, 500 | Begin[StringRiffle[Append[""]@Prepend[""]@cont, "`"]]; 501 | (End[];#)&@Get[fBase], 502 | Get[fBase] 503 | ] 504 | ] 505 | ]; 506 | PackageAppGet[c_, f_] := 507 | PackageExecute[ 508 | Begin[c]; 509 | (End[];#)&@ 510 | If[FileExistsQ@f, 511 | Get@f;, 512 | Get@PackageFilePath["Packages", f <> ".m"] 513 | ] 514 | ]; 515 | 516 | 517 | (* ::Subsubsection::Closed:: *) 518 | (*PackageAppNeeds*) 519 | 520 | 521 | BilibiliLink["Needs", f___] := 522 | PackageAppNeeds[f]; 523 | 524 | 525 | PackageAppNeeds[pkgFile_String?FileExistsQ] := 526 | If[!MemberQ[$LoadedPackages, pkgFile], 527 | If[KeyMemberQ[$DeclaredPackages, pkgFile], 528 | PackageLoadDeclare[pkgFile], 529 | Do[PackageLoadDeclare[pkgFile], 2] 530 | ]; 531 | ]; 532 | 533 | 534 | PackageAppNeeds[pkg_String] := 535 | If[FileExistsQ@PackageFilePath["Packages", pkg <> ".m"], 536 | PackageAppNeeds[PackageFilePath["Packages", pkg <> ".m"]], 537 | $Failed 538 | ]; 539 | 540 | 541 | (* ::Subsubsection::Closed:: *) 542 | (*PackageScopeBlock*) 543 | 544 | 545 | $PackageScopeBlockEvalExpr = TrueQ[$PackageScopeBlockEvalExpr]; 546 | PackageScopeBlock[ 547 | e_, 548 | scope : _String?(StringFreeQ["`"]) : "Package", 549 | context : _String?(StringEndsQ["`"]) : "`PackageScope`" 550 | ] /; TrueQ[$AllowPackageRescoping] := 551 | With[{ 552 | newcont = 553 | If[StringStartsQ[context, "`"], 554 | "BilibiliLink" <> context <> scope <> "`", 555 | context <> scope <> "`" 556 | ], 557 | res = If[$PackageScopeBlockEvalExpr, e] 558 | }, 559 | If[!MemberQ[$PackageContexts, newcont], 560 | Unprotect[$PackageContexts]; 561 | AppendTo[$PackageContexts, newcont]; 562 | ]; 563 | Replace[ 564 | Thread[ 565 | Cases[ 566 | HoldComplete[e], 567 | sym_Symbol?( 568 | Function[Null, 569 | MemberQ[$PackageContexts, Quiet[Context[#]]], 570 | HoldAllComplete 571 | ] 572 | ) :> 573 | HoldComplete[sym], 574 | \[Infinity] 575 | ], 576 | HoldComplete 577 | ], 578 | HoldComplete[{s__}] :> 579 | If[!$PackageDeclared && ListQ@$PackageScopedSymbols, 580 | $PackageScopedSymbols = 581 | { 582 | $PackageScopedSymbols, 583 | newcont -> 584 | HoldComplete[s] 585 | }, 586 | Block[{$AllowPackageRecoloring = True}, 587 | PackageFERehideSymbols[s] 588 | ]; 589 | Map[ 590 | Function[Null, 591 | Quiet[ 592 | Check[ 593 | Set[Context[#], newcont], 594 | Remove[#], 595 | Context::cxdup 596 | ], 597 | Context::cxdup 598 | ], 599 | HoldAllComplete 600 | ], 601 | HoldComplete[s] 602 | ] // ReleaseHold; 603 | ] 604 | ]; 605 | res 606 | ]; 607 | PackageScopeBlock[e_, scope_String : "Package"] /; Not@TrueQ[$AllowPackageRescoping] := 608 | If[$PackageScopeBlockEvalExpr, e]; 609 | PackageScopeBlock ~ SetAttributes ~ HoldFirst; 610 | 611 | 612 | (* ::Subsubsection::Closed:: *) 613 | (*PackageDecontext*) 614 | 615 | 616 | PackageDecontext[ 617 | pkgFile_String?(KeyMemberQ[$DeclaredPackages, #]&), 618 | scope : _String?(StringFreeQ["`"]) : "Package", 619 | context : _String?(StringEndsQ["`"]) : "`PackageScope`" 620 | ] /; TrueQ[$AllowPackageRescoping] := 621 | With[{ 622 | names = $DeclaredPackages[pkgFile], 623 | ctx = 624 | If[StringStartsQ[context, "`"], 625 | "BilibiliLink" <> context <> scope <> "`", 626 | context <> scope <> "`" 627 | ] 628 | }, 629 | Replace[names, 630 | Verbatim[HoldPattern][s_] :> 631 | Set[Context[s], ctx], 632 | 1 633 | ] 634 | ]; 635 | 636 | 637 | (* ::Subsubsection::Closed:: *) 638 | (*PackageRecontext*) 639 | 640 | 641 | PackageRecontext[ 642 | pkgFile_String?(KeyMemberQ[$DeclaredPackages, #]&) 643 | ] /; TrueQ[$AllowPackageRescoping] := 644 | With[{ 645 | names = $DeclaredPackages[pkgFile], 646 | ctx = PackageFileContext[pkgFile] 647 | }, 648 | Replace[names, 649 | Verbatim[HoldPattern][s_] :> 650 | Set[Context[s], ctx], 651 | 1 652 | ] 653 | ]; 654 | (* ::Subsection:: *) 655 | (*Dependencies*) 656 | 657 | 658 | BilibiliLink::nodep = "Couldn't load dependency `` of type ``"; 659 | 660 | 661 | (* ::Subsubsection::Closed:: *) 662 | (*PackageExtendContextPath*) 663 | 664 | 665 | PackageExtendContextPath[cp : {__String}] := 666 | ( 667 | Unprotect[$PackageContextPath]; 668 | $PackageContextPath = 669 | DeleteCases[ 670 | DeleteDuplicates@ 671 | Join[$PackageContextPath, cp], 672 | "System`" | "Global`" 673 | ]; 674 | (* Should I protect it again? *) 675 | ) 676 | 677 | 678 | (* ::Subsubsection::Closed:: *) 679 | (*PackageInstallPackageDependency*) 680 | 681 | 682 | Options[PackageInstallPackageDependency] = 683 | { 684 | "Permanent" -> False 685 | }; 686 | PackageInstallPackageDependency[dep_String, ops : OptionsPattern[]] := 687 | Block[{retcode, site, path, file, tmp}, 688 | path = 689 | StringSplit[StringTrim[dep, "`"] <> If[FileExtension[dep] == "", ".m", ""], "`"]; 690 | site = 691 | Replace[OptionValue["Site"], 692 | { 693 | s_String?( 694 | URLParse[#, "Domain"] === "github.com"& 695 | ) :> 696 | URLBuild@ 697 | <| 698 | "Scheme" -> "http", 699 | "Domain" -> "raw.githubusercontent.com", 700 | "Path" -> 701 | Function[If[Length[#] == 2, Append[#, "master"], #]]@ 702 | DeleteCases[""]@URLParse[s, "Path"] 703 | |>, 704 | _ -> 705 | "http://raw.githubusercontent.com/paclets/PackageServer/master/Listing" 706 | } 707 | ]; 708 | file = 709 | If[TrueQ@OptionValue["Permanent"], 710 | FileNameJoin@{$UserBaseDirectory, "Applications", Last@path}, 711 | FileNameJoin@{$TemporaryDirectory, "Applications", Last@path} 712 | ]; 713 | tmp = CreateFile[]; 714 | Monitor[ 715 | retcode = URLDownload[URLBuild[Prepend[site], path], tmp, "StatusCode"], 716 | Internal`LoadingPanel[ 717 | TemplateApply[ 718 | "Loading package `` from site ``", 719 | {URLBuild@path, site} 720 | ] 721 | ] 722 | ]; 723 | If[retcode < 300, 724 | CopyFile[tmp, file, 725 | OverwriteTarget -> Not@TrueQ@OptionValue["Permanent"] 726 | ]; 727 | DeleteFile[tmp]; 728 | file, 729 | Message[BilibiliLink::nodep, dep, "Package"]; 730 | DeleteFile[tmp]; 731 | $Failed 732 | ] 733 | ]; 734 | 735 | 736 | (* ::Subsubsection::Closed:: *) 737 | (*PackageLoadPackageDependency*) 738 | 739 | 740 | Options[PackageLoadPackageDependency] = 741 | Options[PackageInstallPackageDependency]; 742 | PackageLoadPackageDependency[dep_String, ops : OptionsPattern[]] := 743 | Internal`WithLocalSettings[ 744 | BeginPackage[dep];, 745 | If[Quiet@Check[Needs[dep], $Failed] === $Failed && 746 | Quiet@Check[ 747 | Get[FileNameJoin @@ 748 | StringSplit[ 749 | StringTrim[dep, "`"] <> If[FileExtension[dep] == "", ".m", ""], 750 | "`" 751 | ] 752 | ], 753 | $Failed] === $Failed, 754 | Replace[PackageInstallPacletDependency[dep, ops], 755 | f : _String | _File :> Get[f] 756 | ] 757 | ]; 758 | PackageExtendContextPath@ 759 | Select[$Packages, StringStartsQ[dep]];, 760 | EndPackage[]; 761 | ] 762 | 763 | 764 | (* ::Subsubsection::Closed:: *) 765 | (*PackageInstallPacletDependency*) 766 | 767 | 768 | Options[PackageInstallPacletDependency] = 769 | Options[PacletInstall]; 770 | PackageInstallPacletDependency[dep_String, ops : OptionsPattern[]] := 771 | Check[ 772 | Block[{site, pac}, 773 | pac = 774 | StringTrim[dep, "`"]; 775 | site = 776 | Replace[OptionValue["Site"], 777 | { 778 | s_String?( 779 | URLParse[#, "Domain"] === "github.com"& 780 | ) :> 781 | URLBuild@ 782 | <| 783 | "Scheme" -> "http", 784 | "Domain" -> "raw.githubusercontent.com", 785 | "Path" -> 786 | Function[If[Length[#] == 2, Append[#, "master"], #]]@ 787 | DeleteCases[""]@URLParse[s, "Path"] 788 | |>, 789 | None -> 790 | Automatic, 791 | _ -> 792 | "http://raw.githubusercontent.com/paclets/PacletServer/master" 793 | } 794 | ]; 795 | Monitor[ 796 | PacletInstall[ 797 | pac, 798 | "Site" -> site, 799 | ops 800 | ], 801 | Internal`LoadingPanel[ 802 | TemplateApply[ 803 | "Loading paclet `` from site ``", 804 | {pac, site} 805 | ] 806 | ] 807 | ] 808 | ], 809 | Message[BilibiliLink::nodep, dep, "Paclet"]; 810 | $Failed 811 | ] 812 | 813 | 814 | (* ::Subsubsection::Closed:: *) 815 | (*PackageLoadPacletDependency*) 816 | 817 | 818 | Options[PackageLoadPacletDependency] = 819 | Options[PackageInstallPacletDependency]; 820 | PackageLoadPacletDependency[dep_String?StringEndsQ["`"], ops : OptionsPattern[]] := 821 | Internal`WithLocalSettings[ 822 | BeginPackage[dep];, 823 | Quiet@ 824 | If[Check[Needs[dep], $Failed] === $Failed, 825 | Replace[PackageInstallPacletDependency[dep, ops], 826 | _PacletManager`Paclet :> Needs[dep] 827 | ] 828 | ]; 829 | PackageExtendContextPath@ 830 | Select[$Packages, StringStartsQ[dep]];, 831 | EndPackage[]; 832 | ] 833 | 834 | 835 | (* ::Subsubsection::Closed:: *) 836 | (*PackageLoadResourceDependency*) 837 | 838 | 839 | (* ::Text:: *) 840 | (*Nothing I've implemented yet, but could be very useful for installing resources for a paclet*) 841 | (* ::Subsection:: *) 842 | (*Exceptions*) 843 | 844 | 845 | (* ::Subsubsection::Closed:: *) 846 | (*PackageThrow*) 847 | 848 | 849 | PackageThrow[value_, tag : _String : "Failure"] := 850 | Throw[value, $PackageName <> tag]; 851 | 852 | 853 | (* ::Subsubsection::Closed:: *) 854 | (*PackageCatch*) 855 | 856 | 857 | $PackageCatchCallback = (#&); 858 | 859 | 860 | PackageCatch[expr_, tag : _String : "Failure", callback_ : Automatic] := 861 | Catch[expr, $PackageName <> tag, 862 | Replace[callback, Automatic :> $PackageCatchCallback] 863 | ]; 864 | PackageCatch ~ SetAttributes ~ HoldFirst 865 | 866 | 867 | (* ::Subsubsection:: *) 868 | (*PackageMessage*) 869 | 870 | 871 | $PackageErrorMessage = 872 | "BilibiliLink encountered exception ``"; 873 | 874 | 875 | Options[PackageMessage] = 876 | { 877 | "MessageParameters" :> {} 878 | }; 879 | PackageMessage[ 880 | msg_MessageName, 881 | body_String, 882 | ops : OptionsPattern[] 883 | ] := 884 | ( 885 | Set[msg, body]; 886 | Message[msg, Sequence @@ OptionValue["MessageParameters"]] 887 | ); 888 | PackageMessage[ 889 | tag_?StringQ, 890 | body_String, 891 | ops : OptionsPattern[] 892 | ] := 893 | PackageMessage[ 894 | MessageName[BilibiliLink, tag], 895 | body, 896 | ops 897 | ]; 898 | PackageMessage[ 899 | tag_?StringQ 900 | ] := 901 | PackageMessage[ 902 | MessageName[BilibiliLink, tag], 903 | $PackageErrorMessage, 904 | "MessageParameters" -> {tag} 905 | ]; 906 | PackageMessage ~ SetAttributes ~ HoldAll 907 | 908 | 909 | (* ::Subsubsection:: *) 910 | (*PackageCheck*) 911 | 912 | 913 | $PackageCheckMessage = 914 | "Check caught exceptions ``"; 915 | 916 | 917 | $PackageCheckCallback = 918 | Function[ 919 | PackageRaiseException[ 920 | "Check", 921 | $PackageCheckMessage, 922 | "MessageParameters" -> Thread[HoldForm[$MessageList]] 923 | ] 924 | ]; 925 | 926 | 927 | PackageCheck[ 928 | expr_, 929 | failexpr_ : Automatic, 930 | msg : {___String} : {} 931 | ] := 932 | Replace[ 933 | Thread[Map[Hold[MessageName[BilibiliLink, #]]&, msg], Hold], 934 | { 935 | {} :> 936 | Check[expr, 937 | Replace[failexpr, {Automatic :> $PackageCheckCallback[]}] 938 | ], 939 | Hold[msgs_] :> 940 | Check[expr, 941 | Replace[failexpr, {Automatic :> $PackageCheckCallback[]}], 942 | msgs 943 | ], 944 | _ :> 945 | Replace[failexpr, {Automatic :> $PackageCheckCallback[]}] 946 | } 947 | ]; 948 | PackageCheck ~ SetAttributes ~ HoldAll; 949 | 950 | 951 | (* ::Subsubsection:: *) 952 | (*PackageFailure*) 953 | 954 | 955 | Options[PackageFailure] = 956 | Join[ 957 | Options[PackageMessage], 958 | { 959 | "FailureTag" -> Automatic 960 | } 961 | ]; 962 | PackageFailure[ 963 | msg_MessageName, 964 | body_?StringQ, 965 | ops : OptionsPattern[] 966 | ] := 967 | Replace[ 968 | OptionValue[Automatic, Automatic, "MessageParameters", Hold], 969 | Hold[params_] :> 970 | Failure[ 971 | $PackageName <> 972 | Replace[OptionValue["FailureTag"], 973 | Automatic :> Hold[msg][[1, 2]] 974 | ], 975 | <| 976 | "MessageTemplate" :> 977 | msg, 978 | "MessageParameters" :> 979 | params 980 | |> 981 | ] 982 | ]; 983 | PackageFailure[ 984 | tag : _?StringQ : "Exception", 985 | body_?StringQ, 986 | ops : OptionsPattern[] 987 | ] := 988 | ( 989 | Set[MessageName[BilibiliLink, tag], body]; 990 | PackageFailure[ 991 | MessageName[BilibiliLink, tag], 992 | body, 993 | ops 994 | ] 995 | ); 996 | PackageFailure ~ SetAttributes ~ HoldFirst 997 | 998 | 999 | (* ::Subsubsection:: *) 1000 | (*PackageRaiseException*) 1001 | 1002 | 1003 | Options[PackageRaiseException] = 1004 | Options[PackageFailure] 1005 | PackageRaiseException[ 1006 | msg_MessageName, 1007 | body_?StringQ, 1008 | ops : OptionsPattern[] 1009 | ] := 1010 | ( 1011 | PackageMessage[msg, body, 1012 | FilterRules[{ops}, Options[PackageMessage]] 1013 | ]; 1014 | PackageThrow[ 1015 | PackageFailure[msg, body, ops] 1016 | ] 1017 | ); 1018 | PackageRaiseException[ 1019 | tag_?StringQ, 1020 | body_String, 1021 | ops : OptionsPattern[] 1022 | ] := 1023 | PackageRaiseException[ 1024 | MessageName[BilibiliLink, tag], 1025 | body, 1026 | ops 1027 | ]; 1028 | PackageRaiseException[tag_?StringQ] := 1029 | PackageRaiseException[ 1030 | tag, 1031 | $PackageErrorMessage, 1032 | "MessageParameters" -> {tag} 1033 | ]; 1034 | PackageRaiseException ~ SetAttributes ~ HoldFirst 1035 | (* ::Subsection:: *) 1036 | (*Autocompletion*) 1037 | 1038 | 1039 | (* ::Subsubsection::Closed:: *) 1040 | (*Formats*) 1041 | 1042 | 1043 | $PackageAutoCompletionFormats = 1044 | Alternatives @@ Join @@ { 1045 | Range[0, 9], 1046 | { 1047 | _String?(FileExtension[#] === "trie"&), 1048 | { 1049 | _String | (Alternatives @@ Range[0, 9]) | {__String}, 1050 | (("URI" | "DependsOnArgument") -> _)... 1051 | }, 1052 | { 1053 | _String | (Alternatives @@ Range[0, 9]) | {__String}, 1054 | (("URI" | "DependsOnArgument") -> _)..., 1055 | (_String | (Alternatives @@ Range[0, 9]) | {__String}) 1056 | }, 1057 | { 1058 | __String 1059 | } 1060 | }, 1061 | { 1062 | "codingNoteFontCom", 1063 | "ConvertersPath", 1064 | "ExternalDataCharacterEncoding", 1065 | "MenuListCellTags", 1066 | "MenuListConvertFormatTypes", 1067 | "MenuListDisplayAsFormatTypes", 1068 | "MenuListFonts", 1069 | "MenuListGlobalEvaluators", 1070 | "MenuListHelpWindows", 1071 | "MenuListNotebookEvaluators", 1072 | "MenuListNotebooksMenu", 1073 | "MenuListPackageWindows", 1074 | "MenuListPalettesMenu", 1075 | "MenuListPaletteWindows", 1076 | "MenuListPlayerWindows", 1077 | "MenuListPrintingStyleEnvironments", 1078 | "MenuListQuitEvaluators", 1079 | "MenuListScreenStyleEnvironments", 1080 | "MenuListStartEvaluators", 1081 | "MenuListStyleDefinitions", 1082 | "MenuListStyles", 1083 | "MenuListStylesheetWindows", 1084 | "MenuListTextWindows", 1085 | "MenuListWindows", 1086 | "PrintingStyleEnvironment", 1087 | "ScreenStyleEnvironment", 1088 | "Style" 1089 | } 1090 | }; 1091 | 1092 | 1093 | (* ::Subsubsection::Closed:: *) 1094 | (*AddAutocompletions Base*) 1095 | 1096 | 1097 | PackageAddAutocompletions[pats : {(_String -> {$PackageAutoCompletionFormats..})..}] /; 1098 | TrueQ[$PackageAllowAutocompletions] := 1099 | If[$Notebooks && 1100 | Internal`CachedSystemInformation["FrontEnd", "VersionNumber"] > 10.0, 1101 | FrontEndExecute@FrontEnd`Value@ 1102 | Map[ 1103 | FEPrivate`AddSpecialArgCompletion[#]&, 1104 | pats 1105 | ], 1106 | $Failed 1107 | ]; 1108 | PackageAddAutocompletions[pat : (_String -> {$PackageAutoCompletionFormats..})] /; 1109 | TrueQ[$PackageAllowAutocompletions] := 1110 | PackageAddAutocompletions[{pat}]; 1111 | 1112 | 1113 | (* ::Subsubsection::Closed:: *) 1114 | (*AddAutocompletions Helpers*) 1115 | 1116 | 1117 | $PackageAutocompletionAliases = 1118 | { 1119 | "None" | None | Normal -> 0, 1120 | "AbsoluteFileName" | AbsoluteFileName -> 2, 1121 | "FileName" | File | FileName -> 3, 1122 | "Color" | RGBColor | Hue | XYZColor -> 4, 1123 | "Package" | Package -> 7, 1124 | "Directory" | Directory -> 8, 1125 | "Interpreter" | Interpreter -> 9, 1126 | "Notebook" | Notebook -> "MenuListNotebooksMenu", 1127 | "StyleSheet" -> "MenuListStylesheetMenu", 1128 | "Palette" -> "MenuListPalettesMenu", 1129 | "Evaluator" | Evaluator -> "MenuListGlobalEvaluators", 1130 | "FontFamily" | FontFamily -> "MenuListFonts", 1131 | "CellTag" | CellTags -> "MenuListCellTags", 1132 | "FormatType" | FormatType -> "MenuListDisplayAsFormatTypes", 1133 | "ConvertFormatType" -> "MenuListConvertFormatTypes", 1134 | "DisplayAsFormatType" -> "MenuListDisplayAsFormatTypes", 1135 | "GlobalEvaluator" -> "MenuListGlobalEvaluators", 1136 | "HelpWindow" -> "MenuListHelpWindows", 1137 | "NotebookEvaluator" -> "MenuListNotebookEvaluators", 1138 | "PrintingStyleEnvironment" | PrintingStyleEnvironment -> 1139 | "PrintingStyleEnvironment", 1140 | "ScreenStyleEnvironment" | ScreenStyleEnvironment -> 1141 | ScreenStyleEnvironment, 1142 | "QuitEvaluator" -> "MenuListQuitEvaluators", 1143 | "StartEvaluator" -> "MenuListStartEvaluators", 1144 | "StyleDefinitions" | StyleDefinitions -> 1145 | "MenuListStyleDefinitions", 1146 | "CharacterEncoding" | CharacterEncoding | 1147 | ExternalDataCharacterEncoding -> 1148 | "ExternalDataCharacterEncoding", 1149 | "Style" | Style -> "Style", 1150 | "Window" -> "MenuListWindows" 1151 | }; 1152 | 1153 | 1154 | (* ::Subsubsection:: *) 1155 | (*AddAutocompletions Convenience*) 1156 | 1157 | 1158 | $PackageAutocompletionTable = { 1159 | f : $PackageAutoCompletionFormats :> f, 1160 | Sequence @@ $PackageAutocompletionAliases, 1161 | s_String :> {s} 1162 | }; 1163 | 1164 | 1165 | PackageAddAutocompletions[o : {__Rule}] /; ( 1166 | TrueQ[$PackageAllowAutocompletions] && !TrueQ@$recursionProtect 1167 | ) := 1168 | Block[{$recursionProtect = True}, 1169 | Replace[ 1170 | PackageAddAutocompletions@ 1171 | Replace[o, 1172 | (s_ -> v_) :> 1173 | (Replace[s, _Symbol :> SymbolName[s]] -> 1174 | Replace[ 1175 | Flatten[{v}, 1], 1176 | $PackageAutocompletionTable, 1177 | 1 1178 | ]), 1179 | 1 1180 | ], 1181 | _PackageAddAutocompletions -> $Failed 1182 | ] 1183 | ]; 1184 | PackageAddAutocompletions[s : Except[_List], v_] /; TrueQ[$PackageAllowAutocompletions] := 1185 | PackageAddAutocompletions[{s -> v}]; 1186 | PackageAddAutocompletions[l_, v_] /; TrueQ[$PackageAllowAutocompletions] := 1187 | PackageAddAutocompletions@ 1188 | Flatten@{ 1189 | Quiet@ 1190 | Check[ 1191 | Thread[l -> v], 1192 | Map[l -> #&, v] 1193 | ] 1194 | }; 1195 | 1196 | 1197 | (*PackageAddAutocompletions[PackageAddAutocompletions, 1198 | {None, 1199 | Join[ 1200 | Replace[Keys[$PackageAutocompletionAliases], 1201 | Verbatim[Alternatives][s_,___]:>s, 1202 | 1 1203 | ], 1204 | {FileName,AbsoluteFileName}/.$PackageAutocompletionAliases 1205 | ] 1206 | } 1207 | ]*) 1208 | 1209 | 1210 | (* ::Subsubsection::Closed:: *) 1211 | (* PackageSetAutocompletionData *) 1212 | 1213 | 1214 | PackageSetAutocompletionData[] := 1215 | If[DirectoryQ@ 1216 | FileNameJoin@{ 1217 | $PackageDirectory, 1218 | "Resources", 1219 | "FunctionalFrequency" 1220 | }, 1221 | CurrentValue[ 1222 | $FrontEndSession, 1223 | {PrivatePaths, "AutoCompletionData"} 1224 | ] = 1225 | DeleteDuplicates@ 1226 | Append[ 1227 | CurrentValue[ 1228 | $FrontEndSession, 1229 | {PrivatePaths, "AutoCompletionData"} 1230 | ], 1231 | FileNameJoin@{ 1232 | $PackageDirectory, 1233 | "Resources", 1234 | "FunctionalFrequency" 1235 | } 1236 | ] 1237 | ]; 1238 | (* ::Subsection:: *) 1239 | (*FrontEnd*) 1240 | 1241 | 1242 | (* ::Subsubsection::Closed:: *) 1243 | (*PackageFEInstallStylesheets *) 1244 | 1245 | 1246 | PackageFEInstallStylesheets[] := 1247 | With[{ 1248 | base = 1249 | FileNameJoin@{ 1250 | $PackageDirectory, 1251 | "FrontEnd", 1252 | "StyleSheets", 1253 | $PackageName 1254 | }, 1255 | target = 1256 | FileNameJoin@{ 1257 | $UserBaseDirectory, 1258 | "SystemFiles", 1259 | "FrontEnd", 1260 | "StyleSheets", 1261 | $PackageName} 1262 | }, 1263 | If[DirectoryQ@base, 1264 | Do[ 1265 | Quiet@ 1266 | CreateFile[ 1267 | FileNameJoin@{ 1268 | target, 1269 | FileNameDrop[f, FileNameDepth[base]] 1270 | }, 1271 | CreateIntermediateDirectories -> True 1272 | ]; 1273 | CopyFile[f, 1274 | FileNameJoin@{ 1275 | target, 1276 | FileNameDrop[f, FileNameDepth[base]] 1277 | }, 1278 | OverwriteTarget -> True], 1279 | {f, FileNames["*.nb", base, \[Infinity]]} 1280 | ] 1281 | ] 1282 | ]; 1283 | 1284 | 1285 | (* ::Subsubsection::Closed:: *) 1286 | (*PackageFEInstallPalettes *) 1287 | 1288 | 1289 | PackageFEInstallPalettes[] := 1290 | With[{ 1291 | base = 1292 | FileNameJoin@{ 1293 | $PackageDirectory, 1294 | "FrontEnd", 1295 | "Palettes", 1296 | $PackageName 1297 | }, 1298 | target = 1299 | FileNameJoin@{ 1300 | $UserBaseDirectory, 1301 | "SystemFiles", 1302 | "FrontEnd", 1303 | "Palettes", 1304 | $PackageName} 1305 | }, 1306 | If[DirectoryQ@base, 1307 | Do[ 1308 | Quiet@ 1309 | CreateFile[ 1310 | FileNameJoin@{ 1311 | target, 1312 | FileNameDrop[f, FileNameDepth[base]] 1313 | }, 1314 | CreateIntermediateDirectories -> True 1315 | ]; 1316 | CopyFile[f, 1317 | FileNameJoin@{ 1318 | target, 1319 | FileNameDrop[f, FileNameDepth[base]] 1320 | }, 1321 | OverwriteTarget -> True], 1322 | {f, FileNames["*.nb", base, \[Infinity]]} 1323 | ] 1324 | ] 1325 | ]; 1326 | 1327 | 1328 | (* ::Subsubsection::Closed:: *) 1329 | (*PackageFEHiddenBlock*) 1330 | 1331 | 1332 | $PackageFEHideExprSymbols = TrueQ[$PackageFEHideExprSymbols]; 1333 | $PackageFEHideEvalExpr = TrueQ[$PackageFEHideEvalExpr]; 1334 | PackageFEHiddenBlock[expr_, 1335 | hide : True | False | Automatic : Automatic, 1336 | eval : True | False | Automatic : Automatic 1337 | ] /; TrueQ[$AllowPackageRecoloring] := 1338 | If[!$PackageDeclared && ListQ@$PackageFEHiddenSymbols, 1339 | With[{ 1340 | s = 1341 | Cases[ 1342 | HoldComplete[expr], 1343 | sym_Symbol?( 1344 | Function[Null, 1345 | MemberQ[$PackageContexts, Quiet[Context[#]]], 1346 | HoldAllComplete 1347 | ] 1348 | ) :> 1349 | HoldPattern[sym], 1350 | \[Infinity] 1351 | ] 1352 | }, 1353 | $PackageFEHiddenSymbols = 1354 | { 1355 | $PackageFEHiddenSymbols, 1356 | s 1357 | } 1358 | ], 1359 | Block[{feBlockReturn}, 1360 | Internal`SymbolList[False]; 1361 | feBlockReturn = If[Replace[eval, Automatic :> $PackageFEHideEvalExpr], expr]; 1362 | If[Replace[hide, Automatic :> $PackageFEHideExprSymbols], 1363 | With[{ 1364 | s = 1365 | Cases[ 1366 | HoldComplete[expr], 1367 | sym_Symbol?( 1368 | Function[Null, 1369 | MemberQ[$PackageContexts, Quiet[Context[#]]], 1370 | HoldAllComplete 1371 | ] 1372 | ) :> 1373 | HoldPattern[sym], 1374 | \[Infinity] 1375 | ] 1376 | }, 1377 | Replace[Thread[s, HoldPattern], 1378 | Verbatim[HoldPattern][{sym__}] :> 1379 | PackageFERehideSymbols[sym] 1380 | ] 1381 | ] 1382 | ]; 1383 | Internal`SymbolList[True]; 1384 | feBlockReturn 1385 | ] 1386 | ]; 1387 | PackageFEHiddenBlock[expr_, 1388 | hide : True | False | Automatic : Automatic, 1389 | eval : True | False | Automatic : Automatic 1390 | ] /; Not@TrueQ[$AllowPackageRecoloring] := 1391 | If[eval, expr]; 1392 | PackageFEHiddenBlock ~ SetAttributes ~ HoldFirst 1393 | 1394 | 1395 | (* ::Subsubsection::Closed:: *) 1396 | (*PackageFEUnhideSymbols*) 1397 | 1398 | 1399 | PackageFEUnhideSymbols[syms__Symbol, 1400 | cpath : {__String} | Automatic : Automatic, 1401 | mode : "Update" | "Set" : "Update" 1402 | ] /; TrueQ[$AllowPackageRecoloring] := 1403 | With[{stuff = 1404 | Map[ 1405 | Function[Null, 1406 | {Context@#, SymbolName@Unevaluated@#}, 1407 | HoldAllComplete], 1408 | HoldComplete[syms] 1409 | ] // Apply[List] 1410 | }, 1411 | KeyValueMap[ 1412 | FrontEndExecute@ 1413 | If[mode === "Update", 1414 | FrontEnd`UpdateKernelSymbolContexts, 1415 | FrontEnd`SetKernelSymbolContexts 1416 | ][ 1417 | #, 1418 | Replace[cpath, Automatic -> $ContextPath], 1419 | {{#, {}, {}, #2, {}}} 1420 | ]&, 1421 | GroupBy[stuff, First -> Last] 1422 | ]; 1423 | ]; 1424 | PackageFEUnhideSymbols[names_String, 1425 | mode : "Update" | "Set" : "Update"] /; TrueQ[$AllowPackageRecoloring] := 1426 | Replace[ 1427 | Thread[ToExpression[Names@names, StandardForm, Hold], Hold], 1428 | Hold[{s__}] :> PackageFEUnhideSymbols[s, mode] 1429 | ]; 1430 | PackageFEUnhideSymbols ~ SetAttributes ~ HoldAllComplete; 1431 | 1432 | 1433 | (* ::Subsubsection::Closed:: *) 1434 | (*PackageFERehideSymbols*) 1435 | 1436 | 1437 | PackageFERehideSymbols[syms__Symbol, 1438 | cpath : {__String} | Automatic : Automatic, 1439 | mode : "Update" | "Set" : "Update"] /; TrueQ[$AllowPackageRecoloring] := 1440 | With[{stuff = 1441 | Map[ 1442 | Function[Null, 1443 | {Context@#, SymbolName@Unevaluated@#}, 1444 | HoldAllComplete], 1445 | HoldComplete[syms] 1446 | ] // Apply[List] 1447 | }, 1448 | KeyValueMap[ 1449 | FrontEndExecute@ 1450 | If[mode === "Update", 1451 | FrontEnd`UpdateKernelSymbolContexts, 1452 | FrontEnd`SetKernelSymbolContexts 1453 | ][ 1454 | #, 1455 | Replace[cpath, 1456 | Automatic -> $ContextPath 1457 | ], 1458 | {{#, {}, #2, {}, {}}} 1459 | ]&, 1460 | GroupBy[stuff, First -> Last] 1461 | ]; 1462 | ]; 1463 | PackageFERehideSymbols[names_String, 1464 | mode : "Update" | "Set" : "Update"] /; TrueQ[$AllowPackageRecoloring] := 1465 | Replace[ 1466 | Thread[ToExpression[Names@names, StandardForm, Hold], Hold], 1467 | Hold[{s__}] :> PackageFERehideSymbols[s, mode] 1468 | ]; 1469 | PackageFERehideSymbols ~ SetAttributes ~ HoldAllComplete; 1470 | 1471 | 1472 | (* ::Subsubsection::Closed:: *) 1473 | (*PackageFEUnhidePackage*) 1474 | 1475 | 1476 | PackageFEUnhidePackage[ 1477 | package_String?FileExistsQ, 1478 | a___ 1479 | ] /; TrueQ[$AllowPackageRecoloring] := 1480 | Replace[Thread[Lookup[$DeclaredPackages, package, {}], HoldPattern], 1481 | Verbatim[HoldPattern][{syms__}] :> 1482 | PackageFEUnhideSymbols[syms, a] 1483 | ]; 1484 | PackageFEUnhidePackage[spec : _String | _List, a___] /; TrueQ[$AllowPackageRecoloring] := 1485 | PackageFEUnhidePackage[PackageFilePath@Flatten@{"Packages", spec}, a]; 1486 | 1487 | 1488 | (* ::Subsubsection::Closed:: *) 1489 | (*PackageFERehidePackage*) 1490 | 1491 | 1492 | PackageFERehidePackage[ 1493 | package_String?FileExistsQ, 1494 | a___ 1495 | ] /; TrueQ[$AllowPackageRecoloring] := 1496 | Replace[Thread[Lookup[$DeclaredPackages, package, {}], HoldPattern], 1497 | Verbatim[HoldPattern][{syms__}] :> 1498 | PackageFERehideSymbols[syms, a] 1499 | ]; 1500 | PackageFERehidePackage[spec : _String | _List, a___] /; TrueQ[$AllowPackageRecoloring] := 1501 | PackageFERehidePackage[PackageFilePath@Flatten@{"Packages", spec}, a]; 1502 | 1503 | 1504 | (* ::Subsection:: *) 1505 | (*Post-Processing*) 1506 | 1507 | 1508 | (* ::Subsubsection::Closed:: *) 1509 | (*PrepFileName*) 1510 | 1511 | 1512 | PackagePostProcessFileNamePrep[fn_] := 1513 | Replace[ 1514 | FileNameSplit@ 1515 | FileNameDrop[fn, 1516 | FileNameDepth@ 1517 | PackageFilePath["Packages"] 1518 | ], { 1519 | {f_} :> 1520 | f | fn | StringTrim[f, ".m" | ".wl"], 1521 | {p__, f_} :> 1522 | FileNameJoin@{p, f} | fn | {p, StringTrim[f, ".m" | ".wl"]} 1523 | }] 1524 | 1525 | 1526 | (* ::Subsubsection::Closed:: *) 1527 | (*PrepSpecs*) 1528 | 1529 | 1530 | PackagePostProcessPrepSpecs[] := 1531 | ( 1532 | Unprotect[ 1533 | $PackagePreloadedPackages, 1534 | $PackageHiddenPackages, 1535 | $PackageHiddenContexts, 1536 | $PackageExposedContexts, 1537 | $PackageDecontextedPackages 1538 | ]; 1539 | If[FileExistsQ@PackageFilePath["Config", "LoadInfo.m"], 1540 | Replace[ 1541 | $PackageLoadSpecs, 1542 | specs : {__Rule} | _Association :> 1543 | CompoundExpression[ 1544 | $PackagePreloadedPackages = 1545 | Replace[ 1546 | Lookup[specs, "PreLoad"], 1547 | Except[{__String}] -> {} 1548 | ], 1549 | $PackageHiddenPackages = 1550 | Replace[ 1551 | Lookup[specs, "FEHidden"], 1552 | Except[{__String}] -> {} 1553 | ], 1554 | $PackageDecontextedPackages = 1555 | Replace[ 1556 | Lookup[specs, "PackageScope"], 1557 | Except[{__String}] -> {} 1558 | ], 1559 | $PackageExposedContexts = 1560 | Replace[ 1561 | Lookup[specs, "ExposedContexts"], 1562 | Except[{__String}] -> {} 1563 | ] 1564 | ] 1565 | ] 1566 | ] 1567 | ); 1568 | 1569 | 1570 | (* ::Subsubsection::Closed:: *) 1571 | (*ExposePackages*) 1572 | 1573 | 1574 | PackagePostProcessExposePackages[] /; TrueQ[$AllowPackageRecoloring] := 1575 | ( 1576 | PackageAppGet /@ 1577 | $PackagePreloadedPackages; 1578 | With[{ 1579 | syms = 1580 | If[ 1581 | !MemberQ[$PackageHiddenPackages, 1582 | PackagePostProcessFileNamePrep[#] 1583 | ], 1584 | $DeclaredPackages[#], 1585 | {} 1586 | ]& /@ Keys@$DeclaredPackages // Flatten 1587 | }, 1588 | Replace[ 1589 | Thread[ 1590 | If[ListQ@$PackageFEHiddenSymbols, 1591 | DeleteCases[syms, 1592 | Alternatives @@ 1593 | (Verbatim[HoldPattern] /@ Flatten@$PackageFEHiddenSymbols) 1594 | ], 1595 | syms 1596 | ], 1597 | HoldPattern], 1598 | Verbatim[HoldPattern][{s__}] :> 1599 | PackageFEUnhideSymbols[s] 1600 | ] 1601 | ] 1602 | ) 1603 | 1604 | 1605 | 1606 | 1607 | (* ::Subsubsection::Closed:: *) 1608 | (*Rehide Packages*) 1609 | 1610 | 1611 | PackagePostProcessRehidePackages[] /; TrueQ[$AllowPackageRecoloring] := 1612 | If[ 1613 | MemberQ[$PackageHiddenPackages, 1614 | PackagePostProcessFileNamePrep[#] 1615 | ], 1616 | PackageFERehidePackage@# 1617 | ]& /@ Keys@$DeclaredPackages 1618 | 1619 | 1620 | (* ::Subsubsection::Closed:: *) 1621 | (*Decontext*) 1622 | 1623 | 1624 | PackagePostProcessDecontextPackages[] /; TrueQ[$AllowPackageRecoloring] := 1625 | ( 1626 | If[ 1627 | MemberQ[$PackageDecontextedPackages, 1628 | PackagePostProcessFileNamePrep[#] 1629 | ], 1630 | PackageFERehidePackage@#; 1631 | PackageDecontext@# 1632 | ]& /@ Keys@$DeclaredPackages; 1633 | If[ListQ@$PackageScopedSymbols, 1634 | KeyValueMap[ 1635 | With[{newcont = #}, 1636 | Replace[Join @@ #2, 1637 | HoldComplete[s__] :> 1638 | ( 1639 | PackageFERehideSymbols[s]; 1640 | Map[ 1641 | Function[Null, 1642 | Quiet[ 1643 | Check[ 1644 | Set[Context[#], newcont], 1645 | Remove[#], 1646 | Context::cxdup 1647 | ], 1648 | Context::cxdup 1649 | ], 1650 | HoldAllComplete 1651 | ], 1652 | HoldComplete[s] 1653 | ] // ReleaseHold; 1654 | ) 1655 | ] 1656 | ]&, 1657 | GroupBy[Flatten@$PackageScopedSymbols, First -> Last] 1658 | ]; 1659 | ] 1660 | ) 1661 | 1662 | 1663 | 1664 | 1665 | (* ::Subsubsection::Closed:: *) 1666 | (*ContextPathReassign*) 1667 | 1668 | 1669 | PackagePostProcessContextPathReassign[] := 1670 | With[{cp = $ContextPath}, 1671 | If[MemberQ[cp], 1672 | "BilibiliLink`", 1673 | $ContextPath = 1674 | Join[ 1675 | Replace[ 1676 | Flatten@{$PackageExposedContexts}, 1677 | Except[_String?(StringEndsQ["`"])] -> Nothing, 1678 | 1 1679 | ], 1680 | $ContextPath 1681 | ]; 1682 | If[TrueQ[$AllowPackageRecoloring], 1683 | FrontEnd`Private`GetUpdatedSymbolContexts[] 1684 | ]; 1685 | ] 1686 | ] 1687 | 1688 | 1689 | (* ::Subsubsection:: *) 1690 | (*AttachMainAutocomplete*) 1691 | 1692 | 1693 | PackageAttachMainAutocomplete[] := 1694 | PackageAddAutocompletions[BilibiliLink, 1695 | Table[ 1696 | Replace[{} -> None]@ 1697 | Cases[ 1698 | DownValues[BilibiliLink], 1699 | Nest[ 1700 | Insert[#, _, {1, 1, 1}]&, 1701 | (HoldPattern[Verbatim[HoldPattern]][ 1702 | BilibiliLink[s_String, ___] 1703 | ] :> _), 1704 | n - 1 1705 | ] :> s, 1706 | Infinity 1707 | ], 1708 | {n, 5} 1709 | ] 1710 | ] 1711 | 1712 | 1713 | (* ::Subsection:: *) 1714 | (*End*) 1715 | 1716 | 1717 | End[]; 1718 | 1719 | 1720 | (* ::Section:: *) 1721 | (* Load *) 1722 | 1723 | 1724 | If[`PackageScope`Private`$AllowPackageRecoloring, 1725 | Internal`SymbolList[False] 1726 | ]; 1727 | 1728 | 1729 | (* ::Subsubsection:: *) 1730 | (*Basic Load*) 1731 | 1732 | 1733 | `PackageScope`Private`$loadAbort = False; 1734 | CheckAbort[ 1735 | `PackageScope`Private`PackageAppLoad[]; 1736 | `PackageScope`Private`$PackageFEHideExprSymbols = True; 1737 | `PackageScope`Private`$PackageFEHideEvalExpr = True; 1738 | `PackageScope`Private`$PackageScopeBlockEvalExpr = True; 1739 | `PackageScope`Private`$PackageDeclared = True;, 1740 | `PackageScope`Private`$loadAbort = True; 1741 | EndPackage[]; 1742 | ]; 1743 | Protect["`PackageScope`Private`*"]; 1744 | Unprotect[`PackageScope`Private`$loadAbort]; 1745 | 1746 | 1747 | (* ::Subsubsection:: *) 1748 | (*Post-Process*) 1749 | 1750 | 1751 | If[!`PackageScope`Private`$loadAbort, 1752 | `PackageScope`Private`PackagePostProcessPrepSpecs[]; 1753 | `PackageScope`Private`PackagePostProcessExposePackages[]; 1754 | `PackageScope`Private`PackagePostProcessRehidePackages[]; 1755 | `PackageScope`Private`PackagePostProcessDecontextPackages[]; 1756 | `PackageScope`Private`PackageAttachMainAutocomplete[]; 1757 | ] 1758 | 1759 | 1760 | Unprotect[`PackageScope`Private`$PackageFEHiddenSymbols]; 1761 | Clear[`PackageScope`Private`$PackageFEHiddenSymbols]; 1762 | Unprotect[`PackageScope`Private`$PackageScopedSymbols]; 1763 | Clear[`PackageScope`Private`$PackageScopedSymbols]; 1764 | 1765 | 1766 | (* ::Subsubsection:: *) 1767 | (*Preempt Shadowing*) 1768 | 1769 | 1770 | (* Hide `PackageScope`Private` shadowing *) 1771 | 1772 | 1773 | Replace[ 1774 | Hold[{`PackageScope`Private`m___}] :> 1775 | Off[`PackageScope`Private`m] 1776 | ]@ 1777 | Thread[ 1778 | ToExpression[ 1779 | Map[# <> "$"&, Names["`PackageScope`Private`*"] 1780 | ], 1781 | StandardForm, 1782 | Function[Null, 1783 | Hold[MessageName[#, "shdw"]], 1784 | HoldAllComplete 1785 | ] 1786 | ], 1787 | Hold 1788 | ] 1789 | 1790 | 1791 | (* ::Subsubsection:: *) 1792 | (*EndPackage / Reset $ContextPath*) 1793 | 1794 | 1795 | EndPackage[]; 1796 | 1797 | 1798 | If[ 1799 | (Clear@BilibiliLink`PackageScope`Private`$loadAbort;!#)&@ 1800 | BilibiliLink`PackageScope`Private`$loadAbort, 1801 | Unprotect[BilibiliLink`PackageScope`Private`$LoadCompleted]; 1802 | BilibiliLink`PackageScope`Private`$LoadCompleted = True; 1803 | BilibiliLink`PackageScope`Private`PackagePostProcessContextPathReassign[] 1804 | ] -------------------------------------------------------------------------------- /Config/BundleInfo.m: -------------------------------------------------------------------------------- 1 | (* Created with the Wolfram Language : www.wolfram.com *) 2 | { 3 | "RemovePaths" -> {"Private", "project", "GitHub", ".git"}, 4 | "RemovePatterns" -> {"Packages/*.nb", "Packages/*/*.nb", "Packages/*/*/*.nb", ".DS_Store"} 5 | } -------------------------------------------------------------------------------- /Config/DocInfo.m: -------------------------------------------------------------------------------- 1 | (* Created with the Wolfram Language : www.wolfram.com *) 2 | { 3 | "Usage" -> Automatic, 4 | "Functions" -> Automatic, 5 | "Details" -> Automatic, 6 | "Examples" -> Defer, 7 | "RelatedLinks" -> None, 8 | "GuideOptions" -> {}, 9 | "TutorialOptions" -> {} 10 | } -------------------------------------------------------------------------------- /Config/LoadInfo.m: -------------------------------------------------------------------------------- 1 | (* Created with the Wolfram Language : www.wolfram.com *) 2 | {"PreLoad" -> None, "FEHidden" -> {}, "PackageScope" -> None} 3 | -------------------------------------------------------------------------------- /Kernel/Format.wl: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ai4waifu/BilibiliLink/d5ad6bf72d56d112fd71c7b5a752fb01bb3c0b8d/Kernel/Format.wl -------------------------------------------------------------------------------- /Kernel/init.m: -------------------------------------------------------------------------------- 1 | If[$CharacterEncoding =!= "UTF-8", 2 | $CharacterEncoding = "UTF-8"; 3 | Print[{ 4 | Style["$CharacterEncoding has been changed to UTF-8 to avoid problems.", Red], 5 | Style["Because BilibiliLink only works under UTF-8"] 6 | } // TableForm]; 7 | st = OpenAppend[FindFile["init.m"]]; 8 | WriteString[st, "$CharacterEncoding=\"UTF-8\";"]; 9 | Close[st]; 10 | ]; 11 | Get["BilibiliLink`BilibiliLink`"]; -------------------------------------------------------------------------------- /Kernel/scripts.m: -------------------------------------------------------------------------------- 1 | (* ::Package:: *) 2 | 3 | BScript`Pack[] := Module[ 4 | {add, info, paclet}, 5 | add[v_] := Block[ 6 | {p, sp = StringSplit[v, "."]}, 7 | p = ToString[ToExpression[Last@sp] + 1]; 8 | StringRiffle[Append[Most@sp, p], "."] 9 | ]; 10 | info = FindFile["BilibiliLink/PacletInfo.m"]; 11 | paclet = Import[info] /. {("Version" -> v__) -> ("Version" -> Inactive[add][v])} // Activate; 12 | Export[info, StringReplace[ToString[paclet, InputForm], 13 | { 14 | "[" -> "[\n", "]" -> "\n]", 15 | "{" -> "{\n", "}" -> "\n}", 16 | "," -> ",\n" 17 | } 18 | ], "Text"]; 19 | PacletInformation[PackPaclet["BilibiliLink"]] 20 | ]; 21 | 22 | 23 | (* ::CodeText:: *) 24 | (*BScript`Pack[]*) 25 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Mozilla Public License Version 2.0 2 | ================================== 3 | 4 | 1. Definitions 5 | -------------- 6 | 7 | 1.1. "Contributor" 8 | means each individual or legal entity that creates, contributes to 9 | the creation of, or owns Covered Software. 10 | 11 | 1.2. "Contributor Version" 12 | means the combination of the Contributions of others (if any) used 13 | by a Contributor and that particular Contributor's Contribution. 14 | 15 | 1.3. "Contribution" 16 | means Covered Software of a particular Contributor. 17 | 18 | 1.4. "Covered Software" 19 | means Source Code Form to which the initial Contributor has attached 20 | the notice in Exhibit A, the Executable Form of such Source Code 21 | Form, and Modifications of such Source Code Form, in each case 22 | including portions thereof. 23 | 24 | 1.5. "Incompatible With Secondary Licenses" 25 | means 26 | 27 | (a) that the initial Contributor has attached the notice described 28 | in Exhibit B to the Covered Software; or 29 | 30 | (b) that the Covered Software was made available under the terms of 31 | version 1.1 or earlier of the License, but not also under the 32 | terms of a Secondary License. 33 | 34 | 1.6. "Executable Form" 35 | means any form of the work other than Source Code Form. 36 | 37 | 1.7. "Larger Work" 38 | means a work that combines Covered Software with other material, in 39 | a separate file or files, that is not Covered Software. 40 | 41 | 1.8. "License" 42 | means this document. 43 | 44 | 1.9. "Licensable" 45 | means having the right to grant, to the maximum extent possible, 46 | whether at the time of the initial grant or subsequently, any and 47 | all of the rights conveyed by this License. 48 | 49 | 1.10. "Modifications" 50 | means any of the following: 51 | 52 | (a) any file in Source Code Form that results from an addition to, 53 | deletion from, or modification of the contents of Covered 54 | Software; or 55 | 56 | (b) any new file in Source Code Form that contains any Covered 57 | Software. 58 | 59 | 1.11. "Patent Claims" of a Contributor 60 | means any patent claim(s), including without limitation, method, 61 | process, and apparatus claims, in any patent Licensable by such 62 | Contributor that would be infringed, but for the grant of the 63 | License, by the making, using, selling, offering for sale, having 64 | made, import, or transfer of either its Contributions or its 65 | Contributor Version. 66 | 67 | 1.12. "Secondary License" 68 | means either the GNU General Public License, Version 2.0, the GNU 69 | Lesser General Public License, Version 2.1, the GNU Affero General 70 | Public License, Version 3.0, or any later versions of those 71 | licenses. 72 | 73 | 1.13. "Source Code Form" 74 | means the form of the work preferred for making modifications. 75 | 76 | 1.14. "You" (or "Your") 77 | means an individual or a legal entity exercising rights under this 78 | License. For legal entities, "You" includes any entity that 79 | controls, is controlled by, or is under common control with You. For 80 | purposes of this definition, "control" means (a) the power, direct 81 | or indirect, to cause the direction or management of such entity, 82 | whether by contract or otherwise, or (b) ownership of more than 83 | fifty percent (50%) of the outstanding shares or beneficial 84 | ownership of such entity. 85 | 86 | 2. License Grants and Conditions 87 | -------------------------------- 88 | 89 | 2.1. Grants 90 | 91 | Each Contributor hereby grants You a world-wide, royalty-free, 92 | non-exclusive license: 93 | 94 | (a) under intellectual property rights (other than patent or trademark) 95 | Licensable by such Contributor to use, reproduce, make available, 96 | modify, display, perform, distribute, and otherwise exploit its 97 | Contributions, either on an unmodified basis, with Modifications, or 98 | as part of a Larger Work; and 99 | 100 | (b) under Patent Claims of such Contributor to make, use, sell, offer 101 | for sale, have made, import, and otherwise transfer either its 102 | Contributions or its Contributor Version. 103 | 104 | 2.2. Effective Date 105 | 106 | The licenses granted in Section 2.1 with respect to any Contribution 107 | become effective for each Contribution on the date the Contributor first 108 | distributes such Contribution. 109 | 110 | 2.3. Limitations on Grant Scope 111 | 112 | The licenses granted in this Section 2 are the only rights granted under 113 | this License. No additional rights or licenses will be implied from the 114 | distribution or licensing of Covered Software under this License. 115 | Notwithstanding Section 2.1(b) above, no patent license is granted by a 116 | Contributor: 117 | 118 | (a) for any code that a Contributor has removed from Covered Software; 119 | or 120 | 121 | (b) for infringements caused by: (i) Your and any other third party's 122 | modifications of Covered Software, or (ii) the combination of its 123 | Contributions with other software (except as part of its Contributor 124 | Version); or 125 | 126 | (c) under Patent Claims infringed by Covered Software in the absence of 127 | its Contributions. 128 | 129 | This License does not grant any rights in the trademarks, service marks, 130 | or logos of any Contributor (except as may be necessary to comply with 131 | the notice requirements in Section 3.4). 132 | 133 | 2.4. Subsequent Licenses 134 | 135 | No Contributor makes additional grants as a result of Your choice to 136 | distribute the Covered Software under a subsequent version of this 137 | License (see Section 10.2) or under the terms of a Secondary License (if 138 | permitted under the terms of Section 3.3). 139 | 140 | 2.5. Representation 141 | 142 | Each Contributor represents that the Contributor believes its 143 | Contributions are its original creation(s) or it has sufficient rights 144 | to grant the rights to its Contributions conveyed by this License. 145 | 146 | 2.6. Fair Use 147 | 148 | This License is not intended to limit any rights You have under 149 | applicable copyright doctrines of fair use, fair dealing, or other 150 | equivalents. 151 | 152 | 2.7. Conditions 153 | 154 | Sections 3.1, 3.2, 3.3, and 3.4 are conditions of the licenses granted 155 | in Section 2.1. 156 | 157 | 3. Responsibilities 158 | ------------------- 159 | 160 | 3.1. Distribution of Source Form 161 | 162 | All distribution of Covered Software in Source Code Form, including any 163 | Modifications that You create or to which You contribute, must be under 164 | the terms of this License. You must inform recipients that the Source 165 | Code Form of the Covered Software is governed by the terms of this 166 | License, and how they can obtain a copy of this License. You may not 167 | attempt to alter or restrict the recipients' rights in the Source Code 168 | Form. 169 | 170 | 3.2. Distribution of Executable Form 171 | 172 | If You distribute Covered Software in Executable Form then: 173 | 174 | (a) such Covered Software must also be made available in Source Code 175 | Form, as described in Section 3.1, and You must inform recipients of 176 | the Executable Form how they can obtain a copy of such Source Code 177 | Form by reasonable means in a timely manner, at a charge no more 178 | than the cost of distribution to the recipient; and 179 | 180 | (b) You may distribute such Executable Form under the terms of this 181 | License, or sublicense it under different terms, provided that the 182 | license for the Executable Form does not attempt to limit or alter 183 | the recipients' rights in the Source Code Form under this License. 184 | 185 | 3.3. Distribution of a Larger Work 186 | 187 | You may create and distribute a Larger Work under terms of Your choice, 188 | provided that You also comply with the requirements of this License for 189 | the Covered Software. If the Larger Work is a combination of Covered 190 | Software with a work governed by one or more Secondary Licenses, and the 191 | Covered Software is not Incompatible With Secondary Licenses, this 192 | License permits You to additionally distribute such Covered Software 193 | under the terms of such Secondary License(s), so that the recipient of 194 | the Larger Work may, at their option, further distribute the Covered 195 | Software under the terms of either this License or such Secondary 196 | License(s). 197 | 198 | 3.4. Notices 199 | 200 | You may not remove or alter the substance of any license notices 201 | (including copyright notices, patent notices, disclaimers of warranty, 202 | or limitations of liability) contained within the Source Code Form of 203 | the Covered Software, except that You may alter any license notices to 204 | the extent required to remedy known factual inaccuracies. 205 | 206 | 3.5. Application of Additional Terms 207 | 208 | You may choose to offer, and to charge a fee for, warranty, support, 209 | indemnity or liability obligations to one or more recipients of Covered 210 | Software. However, You may do so only on Your own behalf, and not on 211 | behalf of any Contributor. You must make it absolutely clear that any 212 | such warranty, support, indemnity, or liability obligation is offered by 213 | You alone, and You hereby agree to indemnify every Contributor for any 214 | liability incurred by such Contributor as a result of warranty, support, 215 | indemnity or liability terms You offer. You may include additional 216 | disclaimers of warranty and limitations of liability specific to any 217 | jurisdiction. 218 | 219 | 4. Inability to Comply Due to Statute or Regulation 220 | --------------------------------------------------- 221 | 222 | If it is impossible for You to comply with any of the terms of this 223 | License with respect to some or all of the Covered Software due to 224 | statute, judicial order, or regulation then You must: (a) comply with 225 | the terms of this License to the maximum extent possible; and (b) 226 | describe the limitations and the code they affect. Such description must 227 | be placed in a text file included with all distributions of the Covered 228 | Software under this License. Except to the extent prohibited by statute 229 | or regulation, such description must be sufficiently detailed for a 230 | recipient of ordinary skill to be able to understand it. 231 | 232 | 5. Termination 233 | -------------- 234 | 235 | 5.1. The rights granted under this License will terminate automatically 236 | if You fail to comply with any of its terms. However, if You become 237 | compliant, then the rights granted under this License from a particular 238 | Contributor are reinstated (a) provisionally, unless and until such 239 | Contributor explicitly and finally terminates Your grants, and (b) on an 240 | ongoing basis, if such Contributor fails to notify You of the 241 | non-compliance by some reasonable means prior to 60 days after You have 242 | come back into compliance. Moreover, Your grants from a particular 243 | Contributor are reinstated on an ongoing basis if such Contributor 244 | notifies You of the non-compliance by some reasonable means, this is the 245 | first time You have received notice of non-compliance with this License 246 | from such Contributor, and You become compliant prior to 30 days after 247 | Your receipt of the notice. 248 | 249 | 5.2. If You initiate litigation against any entity by asserting a patent 250 | infringement claim (excluding declaratory judgment actions, 251 | counter-claims, and cross-claims) alleging that a Contributor Version 252 | directly or indirectly infringes any patent, then the rights granted to 253 | You by any and all Contributors for the Covered Software under Section 254 | 2.1 of this License shall terminate. 255 | 256 | 5.3. In the event of termination under Sections 5.1 or 5.2 above, all 257 | end user license agreements (excluding distributors and resellers) which 258 | have been validly granted by You or Your distributors under this License 259 | prior to termination shall survive termination. 260 | 261 | ************************************************************************ 262 | * * 263 | * 6. Disclaimer of Warranty * 264 | * ------------------------- * 265 | * * 266 | * Covered Software is provided under this License on an "as is" * 267 | * basis, without warranty of any kind, either expressed, implied, or * 268 | * statutory, including, without limitation, warranties that the * 269 | * Covered Software is free of defects, merchantable, fit for a * 270 | * particular purpose or non-infringing. The entire risk as to the * 271 | * quality and performance of the Covered Software is with You. * 272 | * Should any Covered Software prove defective in any respect, You * 273 | * (not any Contributor) assume the cost of any necessary servicing, * 274 | * repair, or correction. This disclaimer of warranty constitutes an * 275 | * essential part of this License. No use of any Covered Software is * 276 | * authorized under this License except under this disclaimer. * 277 | * * 278 | ************************************************************************ 279 | 280 | ************************************************************************ 281 | * * 282 | * 7. Limitation of Liability * 283 | * -------------------------- * 284 | * * 285 | * Under no circumstances and under no legal theory, whether tort * 286 | * (including negligence), contract, or otherwise, shall any * 287 | * Contributor, or anyone who distributes Covered Software as * 288 | * permitted above, be liable to You for any direct, indirect, * 289 | * special, incidental, or consequential damages of any character * 290 | * including, without limitation, damages for lost profits, loss of * 291 | * goodwill, work stoppage, computer failure or malfunction, or any * 292 | * and all other commercial damages or losses, even if such party * 293 | * shall have been informed of the possibility of such damages. This * 294 | * limitation of liability shall not apply to liability for death or * 295 | * personal injury resulting from such party's negligence to the * 296 | * extent applicable law prohibits such limitation. Some * 297 | * jurisdictions do not allow the exclusion or limitation of * 298 | * incidental or consequential damages, so this exclusion and * 299 | * limitation may not apply to You. * 300 | * * 301 | ************************************************************************ 302 | 303 | 8. Litigation 304 | ------------- 305 | 306 | Any litigation relating to this License may be brought only in the 307 | courts of a jurisdiction where the defendant maintains its principal 308 | place of business and such litigation shall be governed by laws of that 309 | jurisdiction, without reference to its conflict-of-law provisions. 310 | Nothing in this Section shall prevent a party's ability to bring 311 | cross-claims or counter-claims. 312 | 313 | 9. Miscellaneous 314 | ---------------- 315 | 316 | This License represents the complete agreement concerning the subject 317 | matter hereof. If any provision of this License is held to be 318 | unenforceable, such provision shall be reformed only to the extent 319 | necessary to make it enforceable. Any law or regulation which provides 320 | that the language of a contract shall be construed against the drafter 321 | shall not be used to construe this License against a Contributor. 322 | 323 | 10. Versions of the License 324 | --------------------------- 325 | 326 | 10.1. New Versions 327 | 328 | Mozilla Foundation is the license steward. Except as provided in Section 329 | 10.3, no one other than the license steward has the right to modify or 330 | publish new versions of this License. Each version will be given a 331 | distinguishing version number. 332 | 333 | 10.2. Effect of New Versions 334 | 335 | You may distribute the Covered Software under the terms of the version 336 | of the License under which You originally received the Covered Software, 337 | or under the terms of any subsequent version published by the license 338 | steward. 339 | 340 | 10.3. Modified Versions 341 | 342 | If you create software not governed by this License, and you want to 343 | create a new license for such software, you may create and use a 344 | modified version of this License if you rename the license and remove 345 | any references to the name of the license steward (except to note that 346 | such modified license differs from this License). 347 | 348 | 10.4. Distributing Source Code Form that is Incompatible With Secondary 349 | Licenses 350 | 351 | If You choose to distribute Source Code Form that is Incompatible With 352 | Secondary Licenses under the terms of this version of the License, the 353 | notice described in Exhibit B of this License must be attached. 354 | 355 | Exhibit A - Source Code Form License Notice 356 | ------------------------------------------- 357 | 358 | This Source Code Form is subject to the terms of the Mozilla Public 359 | License, v. 2.0. If a copy of the MPL was not distributed with this 360 | file, You can obtain one at http://mozilla.org/MPL/2.0/. 361 | 362 | If it is not possible or desirable to put the notice in a particular 363 | file, then You may include the notice in a location (such as a LICENSE 364 | file in a relevant directory) where a recipient would be likely to look 365 | for such a notice. 366 | 367 | You may add additional accurate notices of copyright ownership. 368 | 369 | Exhibit B - "Incompatible With Secondary Licenses" Notice 370 | --------------------------------------------------------- 371 | 372 | This Source Code Form is "Incompatible With Secondary Licenses", as 373 | defined by the Mozilla Public License, v. 2.0. -------------------------------------------------------------------------------- /Packages/!APIs.m: -------------------------------------------------------------------------------- 1 | $BilibiliLinkUA::usage = ""; 2 | BilibiliLink`ㄑAPIs::usage = ""; 3 | BilibiliLink`ㄑAPIs[___] := ""; 4 | Begin["`APIs`"]; 5 | 6 | 7 | $RawAPIs = <| 8 | "archive" -> <| 9 | "url" -> StringTemplate["https://api.bilibili.com/x/web-interface/archive/stat?aid=`aid`"], 10 | "detail" -> "" 11 | |>, 12 | "arch" -> <| 13 | "url" -> StringTemplate["https://api.bilibili.com/archive_stat/stat?aid=`aid`"], 14 | "detail" -> "效果和archive接口相同." 15 | |>, 16 | "cid" -> <| 17 | "url" -> StringTemplate["http://www.bilibilijj.com/Api/AvToCid/`aid`/0"], 18 | "detail" -> "哔哩哔哩唧唧的cid查询端口, 本机必须使用apikeys或cookies才能得到." 19 | |>, 20 | "photohot" -> <| 21 | "url" -> <| 22 | "illustration" -> StringTemplate["https://api.vc.bilibili.com/link_draw/v2/Doc/list?category=illustration&type=hot&page_num=`page`&page_size=20"], 23 | "comic" -> StringTemplate["https://api.vc.bilibili.com/link_draw/v2/Doc/list?category=comic&type=hot&page_num=`page`&page_size=20"], 24 | "draw" -> StringTemplate["https://api.vc.bilibili.com/link_draw/v2/Doc/list?category=draw&type=hot&page_num=`page`&page_size=20"], 25 | "all" -> StringTemplate["https://api.vc.bilibili.com/link_draw/v2/Doc/list?category=all&type=hot&page_num=`page`&page_size=20"], 26 | "cos" -> StringTemplate["https://api.vc.bilibili.com/link_draw/v2/Photo/list?category=cos&type=hot&page_num=`page`&page_size=20"], 27 | "sifu" -> StringTemplate["https://api.vc.bilibili.com/link_draw/v2/Photo/list?category=sifu&type=hot&page_num=`page`&page_size=20"] 28 | |>, 29 | "detail" -> "h.bilibili.com的热门作品. 可选参数 page, 从0到24." 30 | |>, 31 | "photorank" -> <| 32 | "url" -> <| 33 | 1 -> StringTemplate["https://api.vc.bilibili.com/link_draw/v2/Doc/ranklist?biz=1&rank_type=`time`&page_size=50"], 34 | 2 -> StringTemplate["https://api.vc.bilibili.com/link_draw/v2/Doc/ranklist?biz=2&category=cos&rank_type=`time`&page_size=50"], 35 | 3 -> StringTemplate["https://api.vc.bilibili.com/link_draw/v2/Doc/ranklist?biz=2&category=sifu&rank_type=`time`&page_size=50"] 36 | |>, 37 | "detail" -> "h.bilibili.com的排行榜. 可选参数 time, 有day, week, month三种取值." 38 | |>, 39 | "webshow" -> <| 40 | "url" -> <| 41 | "id" -> StringTemplate["https://api.bilibili.com/x/web-show/res/locs?pf=0&id=`id`"] 42 | "ids" -> StringTemplate["https://api.bilibili.com/x/web-show/res/locs?pf=0&ids=`ids`"] 43 | |>, 44 | "detail" -> "不明,可选参数见$LocPF0." 45 | |>, 46 | "vs" -> <| 47 | "url" -> StringTemplate["http://api.bilibili.com/x/web-interface/newlist?rid=`rid`"], 48 | "detail" -> "VideoSection, B站视频分区, rid 为分区编号, 详见下表 $RidList." 49 | |>, 50 | "vspage" -> <| 51 | "url" -> StringTemplate["http://api.bilibili.com/x/web-interface/newlist?rid=`rid`&pn=`pn`&ps=20&type=0"], 52 | "detail" -> "VideoSectionPage, pn 为页数, ps 为单页显示条目数, 锁死 20, tpye 用途不明" 53 | |>, 54 | "ar" -> <| 55 | "url" -> StringTemplate["https://api.bilibili.com/x/article/rank/list?cid=`cid`"], 56 | "detail" -> "ArticleRank, 专栏文章全站排名, cid 为时段, 可选值有四个:1, 月榜, 2, 周榜, 3, 昨日, 4, 前天", 57 | "from" -> "https://www.bilibili.com/read/ranking" 58 | |>, 59 | "captcha" -> <| 60 | "url" -> "https://passport.bilibili.com/captcha", 61 | "detail" -> "返回验证码" 62 | |> 63 | |>; 64 | 65 | (*未整理的API 66 | 67 | 68 | 69 | 70 | 71 | 72 | https://api.bilibili.com/x/article/rank/list?cid=4 73 | 74 | // tag用 75 | URLExecute["https://api.bilibili.com/x/tag/ranking/archives?tag_id=6776132&rid=47&type=0&pn=1&ps=100","RawJson"]["data"] 76 | https://api.bilibili.com/x/web-interface/ranking/tag?rid=47&tag_id=6776132 77 | 78 | 79 | // 手机载入页面 80 | http://app.bilibili.com/x/splash?plat=0&width=1080&height=1920 81 | //IPHONE 和安卓一样 82 | http://app.bilibili.com/x/splash?channel=appstore&height=1334&plat=1&width=750 83 | //IPAD 84 | http://app.bilibili.com/x/splash?channel=appstore&height=1536&plat=1&width=2048 85 | *) 86 | 87 | 88 | 89 | (* ::Subsection::Closed:: *) 90 | (*Secret*) 91 | (*https://github.com/Vespa314/bilibili-api/blob/master/api.md*) 92 | $RidList = <| 93 | 0 -> <| 94 | "name" -> "根目录", 95 | "url" -> "http://www.bilibili.com", 96 | "parent" -> Missing 97 | |>, 98 | 1 -> <| 99 | "name" -> "动画", 100 | "url" -> "http://www.bilibili.com/video/douga.html", 101 | "parent" -> 0 102 | |>, 103 | 3 -> <| 104 | "name" -> "音乐", 105 | "url" -> "http://www.bilibili.com/video/music.html", 106 | "parent" -> 0 107 | |>, 108 | 4 -> <| 109 | "name" -> "游戏", 110 | "url" -> "http://www.bilibili.com/video/game.html", 111 | "parent" -> 0 112 | |>, 113 | 5 -> <| 114 | "name" -> "娱乐", 115 | "url" -> "http://www.bilibili.com/video/ent.html", 116 | "parent" -> 0 117 | |>, 118 | 9 -> <| 119 | "name" -> "意见留言簿", 120 | "url" -> "http://www.bilibili.complus/guestbook.php", 121 | "parent" -> 0 122 | |>, 123 | 11 -> <| 124 | "name" -> "电视剧", 125 | "url" -> "http://www.bilibili.com/video/teleplay.html", 126 | "parent" -> 0 127 | |>, 128 | 12 -> <| 129 | "name" -> "公告", 130 | "url" -> "http://www.bilibili.com/list.php?tid=", 131 | "parent" -> 0 132 | |>, 133 | 13 -> <| 134 | "name" -> "番剧", 135 | "url" -> "http://www.bilibili.com/video/bangumi.html", 136 | "parent" -> 0 137 | |>, 138 | 15 -> <| 139 | "name" -> "连载剧集", 140 | "url" -> "http://www.bilibili.com/video/soap-three-1.html", 141 | "parent" -> 11 142 | |>, 143 | 16 -> <| 144 | "name" -> "flash游戏", 145 | "url" -> "http://www.bilibili.com/video/game-flash-1.html", 146 | "parent" -> 116 147 | |>, 148 | 17 -> <| 149 | "name" -> "单机联机", 150 | "url" -> "http://www.bilibili.com/video/game-video-1.html", 151 | "parent" -> 116 152 | |>, 153 | 18 -> <| 154 | "name" -> "游戏攻略\[CenterDot]解说", 155 | "url" -> "http://www.bilibili.com/video/game-ctary-1.html", 156 | "parent" -> 116 157 | |>, 158 | 19 -> <| 159 | "name" -> "Mugen", 160 | "url" -> "http://www.bilibili.com/video/game-mugen-1.html", 161 | "parent" -> 116 162 | |>, 163 | 20 -> <| 164 | "name" -> "ACG相关舞蹈", 165 | "url" -> "http://www.bilibili.com/video/dance-1.html", 166 | "parent" -> 129 167 | |>, 168 | 21 -> <| 169 | "name" -> "生活", 170 | "url" -> "http://www.bilibili.com/video/ent-life-1.html", 171 | "parent" -> 5 172 | |>, 173 | 22 -> <| 174 | "name" -> "三次元鬼畜", 175 | "url" -> "http://www.bilibili.com/video/ent-Kichiku-1.html", 176 | "parent" -> 119 177 | |>, 178 | 23 -> <| 179 | "name" -> "电影", 180 | "url" -> "http://www.bilibili.com/video/movie.html", 181 | "parent" -> 0 182 | |>, 183 | 24 -> <| 184 | "name" -> "MAD\[CenterDot]AMV", 185 | "url" -> "http://www.bilibili.com/video/douga-mad-1.html", 186 | "parent" -> 1 187 | |>, 188 | 25 -> <| 189 | "name" -> "MMD\[CenterDot]3D", 190 | "url" -> "http://www.bilibili.com/video/douga-mmd-1.html", 191 | "parent" -> 1 192 | |>, 193 | 26 -> <| 194 | "name" -> "二次元鬼畜", 195 | "url" -> "http://www.bilibili.com/video/douga-kichiku-1.html", 196 | "parent" -> 119 197 | |>, 198 | 27 -> <| 199 | "name" -> "综合", 200 | "url" -> "http://www.bilibili.com/video/douga-else-1.html", 201 | "parent" -> 1 202 | |>, 203 | 28 -> <| 204 | "name" -> "同人音乐", 205 | "url" -> "http://www.bilibili.com/video/music-video-1.html", 206 | "parent" -> 117 207 | |>, 208 | 29 -> <| 209 | "name" -> "三次元音乐", 210 | "url" -> "http://www.bilibili.com/video/music-coordinate-1.html", 211 | "parent" -> 117 212 | |>, 213 | 30 -> <| 214 | "name" -> "VOCALOID\[CenterDot]UTAU", 215 | "url" -> "http://www.bilibili.com/video/music-vocaloid-1.html", 216 | "parent" -> 117 217 | |>, 218 | 31 -> <| 219 | "name" -> "翻唱", 220 | "url" -> "http://www.bilibili.com/video/music-Cover-1.html", 221 | "parent" -> 117 222 | |>, 223 | 32 -> <| 224 | "name" -> "完结动画", 225 | "url" -> "http://www.bilibili.com/video/part-twoelement-1.html", 226 | "parent" -> 13 227 | |>, 228 | 33 -> <| 229 | "name" -> "连载动画", 230 | "url" -> "http://www.bilibili.com/video/bangumi-two-1.html", 231 | "parent" -> 13 232 | |>, 233 | 34 -> <| 234 | "name" -> "完结剧集", 235 | "url" -> "http://www.bilibili.com/video/tv-drama-1.html", 236 | "parent" -> 11 237 | |>, 238 | 36 -> <| 239 | "name" -> "科技", 240 | "url" -> "http://www.bilibili.com/video/technology.html", 241 | "parent" -> 0 242 | |>, 243 | 37 -> <| 244 | "name" -> "纪录片", 245 | "url" -> "http://www.bilibili.com/video/tech-popular-science-1.html", 246 | "parent" -> 36 247 | |>, 248 | 39 -> <| 249 | "name" -> "演讲\[Bullet]公开课", 250 | "url" -> "http://www.bilibili.com/video/speech-course-1.html", 251 | "parent" -> 36 252 | |>, 253 | 40 -> <| 254 | "name" -> "技术宅", 255 | "url" -> "http://www.bilibili.com/video/tech-otaku-1.html", 256 | "parent" -> 122 257 | |>, 258 | 41 -> <| 259 | "name" -> "暂置区", 260 | "url" -> "http://www.bilibili.com/video/index.html", 261 | "parent" -> 12 262 | |>, 263 | 43 -> <| 264 | "name" -> "舞蹈MMD", 265 | "url" -> "http://www.bilibili.com/video/mmd-dance-1.html", 266 | "parent" -> 25 267 | |>, 268 | 44 -> <| 269 | "name" -> "剧情MMD", 270 | "url" -> "http://www.bilibili.com/video/mmd-story-1.html", 271 | "parent" -> 25 272 | |>, 273 | 45 -> <| 274 | "name" -> "原创模型", 275 | "url" -> "http://www.bilibili.com/video/mmd-original-1.html", 276 | "parent" -> 25 277 | |>, 278 | 46 -> <| 279 | "name" -> "其他视频", 280 | "url" -> "http://www.bilibili.com/video/index.html", 281 | "parent" -> 25 282 | |>, 283 | 47 -> <| 284 | "name" -> "动画短片", 285 | "url" -> "http://www.bilibili.com/video/douga-voice-1.html", 286 | "parent" -> 1 287 | |>, 288 | 48 -> <| 289 | "name" -> "原创动画", 290 | "url" -> "http://www.bilibili.com/video/douga-voice-original-1.html", 291 | "parent" -> 47 292 | |>, 293 | 49 -> <| 294 | "name" -> "ACG配音", 295 | "url" -> "http://www.bilibili.com/video/douga-voice-translate-1.html", 296 | "parent" -> 27 297 | |>, 298 | 50 -> <| 299 | "name" -> "手书", 300 | "url" -> "http://www.bilibili.com/video/douga-else-handwriting-1.html", 301 | "parent" -> 27 302 | |>, 303 | 51 -> <| 304 | "name" -> "资讯", 305 | "url" -> "http://www.bilibili.com/video/douga-else-information-1.html", 306 | "parent" -> 13 307 | |>, 308 | 52 -> <| 309 | "name" -> "动漫杂谈", 310 | "url" -> "http://www.bilibili.com/video/douga-else-tattle-1.html", 311 | "parent" -> 27 312 | |>, 313 | 53 -> <| 314 | "name" -> "其他动漫", 315 | "url" -> "http://www.bilibili.com/video/douga-else-other-1.html", 316 | "parent" -> 27 317 | |>, 318 | 54 -> <| 319 | "name" -> "OP/ED/OST", 320 | "url" -> "http://www.bilibili.com/video/music-oped-1.html", 321 | "parent" -> 117 322 | |>, 323 | 55 -> <| 324 | "name" -> "其他音乐", 325 | "url" -> "http://www.bilibili.com/video/music-video-other-1.html", 326 | "parent" -> 28 327 | |>, 328 | 56 -> <| 329 | "name" -> "VOCALOID", 330 | "url" -> "http://www.bilibili.com/video/music-vocaloid-vocaloid-1.html", 331 | "parent" -> 30 332 | |>, 333 | 57 -> <| 334 | "name" -> "UTAU", 335 | "url" -> "http://www.bilibili.com/video/music-vocaloid-utau-1.html", 336 | "parent" -> 30 337 | |>, 338 | 58 -> <| 339 | "name" -> "VOCALOID中文曲", 340 | "url" -> "http://www.bilibili.com/video/music-vocaloid-chinese-1.html", 341 | "parent" -> 30 342 | |>, 343 | 59 -> <| 344 | "name" -> "演奏", 345 | "url" -> "http://www.bilibili.com/video/music-perform-1.html", 346 | "parent" -> 117 347 | |>, 348 | 60 -> <| 349 | "name" -> "电子竞技", 350 | "url" -> "http://www.bilibili.com/video/game-fight-1.html", 351 | "parent" -> 116 352 | |>, 353 | 61 -> <| 354 | "name" -> "预告资讯", 355 | "url" -> "http://www.bilibili.com/video/game-presentation-1.html", 356 | "parent" -> 17 357 | |>, 358 | 63 -> <| 359 | "name" -> "实况解说", 360 | "url" -> "http://www.bilibili.com/video/game-video-other-1.html", 361 | "parent" -> 17 362 | |>, 363 | 64 -> <| 364 | "name" -> "游戏杂谈", 365 | "url" -> "http://www.bilibili.com/video/game-ctary-standalone-1.html", 366 | "parent" -> 17 367 | |>, 368 | 65 -> <| 369 | "name" -> "网络游戏", 370 | "url" -> "http://www.bilibili.com/video/game-ctary-network-1.html", 371 | "parent" -> 116 372 | |>, 373 | 66 -> <| 374 | "name" -> "游戏集锦", 375 | "url" -> "http://www.bilibili.com/video/game-ctary-handheld-1.html", 376 | "parent" -> 17 377 | |>, 378 | 67 -> <| 379 | "name" -> "其他游戏", 380 | "url" -> "http://www.bilibili.com/video/game-ctary-other-1.html", 381 | "parent" -> 17 382 | |>, 383 | 68 -> <| 384 | "name" -> "电竞赛事", 385 | "url" -> "http://www.bilibili.com/video/game-fight-matches-1.html", 386 | "parent" -> 60 387 | |>, 388 | 69 -> <| 389 | "name" -> "实况解说", 390 | "url" -> "http://www.bilibili.com/video/game-fight-explain-1.html", 391 | "parent" -> 60 392 | |>, 393 | 70 -> <| 394 | "name" -> "游戏集锦", 395 | "url" -> "http://www.bilibili.com/video/game-fight-other-1.html", 396 | "parent" -> 60 397 | |>, 398 | 71 -> <| 399 | "name" -> "综艺", 400 | "url" -> "http://www.bilibili.com/video/ent-variety-1.html", 401 | "parent" -> 5 402 | |>, 403 | 72 -> <| 404 | "name" -> "运动", 405 | "url" -> "http://www.bilibili.com/video/ent-sports-1.html", 406 | "parent" -> 21 407 | |>, 408 | 73 -> <| 409 | "name" -> "影视剪影", 410 | "url" -> "http://www.bilibili.com/video/ent-silhouette-1.html", 411 | "parent" -> 128 412 | |>, 413 | 74 -> <| 414 | "name" -> "日常", 415 | "url" -> "http://www.bilibili.com/video/ent-life-other-1.html", 416 | "parent" -> 21 417 | |>, 418 | 75 -> <| 419 | "name" -> "动物圈", 420 | "url" -> "http://www.bilibili.com/video/ent-animal-1.html", 421 | "parent" -> 5 422 | |>, 423 | 76 -> <| 424 | "name" -> "美食圈", 425 | "url" -> "http://www.bilibili.com/video/ent-food-1.html", 426 | "parent" -> 5 427 | |>, 428 | 77 -> <| 429 | "name" -> "喵星人", 430 | "url" -> "http://www.bilibili.com/video/ent-animal-cat-1.html", 431 | "parent" -> 75 432 | |>, 433 | 78 -> <| 434 | "name" -> "汪星人", 435 | "url" -> "http://www.bilibili.com/video/ent-animal-dog-1.html", 436 | "parent" -> 75 437 | |>, 438 | 79 -> <| 439 | "name" -> "其他动物", 440 | "url" -> "http://www.bilibili.com/video/ent-animal-other-1.html", 441 | "parent" -> 75 442 | |>, 443 | 80 -> <| 444 | "name" -> "美食视频", 445 | "url" -> "http://www.bilibili.com/video/ent-food-video-1.html", 446 | "parent" -> 76 447 | |>, 448 | 81 -> <| 449 | "name" -> "料理制作", 450 | "url" -> "http://www.bilibili.com/video/ent-food-course-1.html", 451 | "parent" -> 76 452 | |>, 453 | 82 -> <| 454 | "name" -> "电影相关", 455 | "url" -> "http://www.bilibili.com/video/movie-presentation-1.html", 456 | "parent" -> 23 457 | |>, 458 | 83 -> <| 459 | "name" -> "其他国家", 460 | "url" -> "http://www.bilibili.com/video/movie-movie-1.html", 461 | "parent" -> 23 462 | |>, 463 | 85 -> <| 464 | "name" -> "短片", 465 | "url" -> "http://www.bilibili.com/video/tv-micromovie-1.html", 466 | "parent" -> 23 467 | |>, 468 | 86 -> <| 469 | "name" -> "特摄\[CenterDot]布袋", 470 | "url" -> "http://www.bilibili.com/video/tv-sfx-1.html", 471 | "parent" -> 11 472 | |>, 473 | 87 -> <| 474 | "name" -> "国产", 475 | "url" -> "http://www.bilibili.com/video/tv-drama-cn-1.html", 476 | "parent" -> 34 477 | |>, 478 | 88 -> <| 479 | "name" -> "日剧", 480 | "url" -> "http://www.bilibili.com/video/tv-drama-jp-1.html", 481 | "parent" -> 34 482 | |>, 483 | 89 -> <| 484 | "name" -> "美剧", 485 | "url" -> "http://www.bilibili.com/video/tv-drama-us-1.html", 486 | "parent" -> 34 487 | |>, 488 | 90 -> <| 489 | "name" -> "其他TV", 490 | "url" -> "http://www.bilibili.com/video/tv-drama-other-1.html", 491 | "parent" -> 34 492 | |>, 493 | 91 -> <| 494 | "name" -> "特摄", 495 | "url" -> "http://www.bilibili.com/video/tv-sfx-sfx-1.html", 496 | "parent" -> 86 497 | |>, 498 | 92 -> <| 499 | "name" -> "布袋戏", 500 | "url" -> "http://www.bilibili.com/video/tv-sfx-pili-1.html", 501 | "parent" -> 86 502 | |>, 503 | 94 -> <| 504 | "name" -> "剧场版", 505 | "url" -> "http://www.bilibili.com/video/bangumi-ova-1.html", 506 | "parent" -> 32 507 | |>, 508 | 95 -> <| 509 | "name" -> "数码", 510 | "url" -> "http://www.bilibili.com/video/tech-future-digital-1.html", 511 | "parent" -> 36 512 | |>, 513 | 96 -> <| 514 | "name" -> "军事", 515 | "url" -> "http://www.bilibili.com/video/tech-future-military-1.html", 516 | "parent" -> 36 517 | |>, 518 | 97 -> <| 519 | "name" -> "手机评测", 520 | "url" -> "http://www.bilibili.com/video/tech-future-mobile-1.html", 521 | "parent" -> 95 522 | |>, 523 | 98 -> <| 524 | "name" -> "机械", 525 | "url" -> "http://www.bilibili.com/video/tech-future-other-1.html", 526 | "parent" -> 36 527 | |>, 528 | 99 -> <| 529 | "name" -> "BBC纪录片", 530 | "url" -> "http://www.bilibili.com/video/tech-geo-bbc-1.html", 531 | "parent" -> 37 532 | |>, 533 | 100 -> <| 534 | "name" -> "探索频道", 535 | "url" -> "http://www.bilibili.com/video/tech-geo-discovery-1.html", 536 | "parent" -> 37 537 | |>, 538 | 101 -> <| 539 | "name" -> "国家地理", 540 | "url" -> "http://www.bilibili.com/video/tech-geo-national-1.html", 541 | "parent" -> 37 542 | |>, 543 | 102 -> <| 544 | "name" -> "NHK", 545 | "url" -> "http://www.bilibili.com/video/tech-geo-nhk-1.html", 546 | "parent" -> 37 547 | |>, 548 | 103 -> <| 549 | "name" -> "演讲", 550 | "url" -> "http://www.bilibili.com/video/speech-1.html", 551 | "parent" -> 39 552 | |>, 553 | 104 -> <| 554 | "name" -> "公开课", 555 | "url" -> "http://www.bilibili.com/video/course-1.html", 556 | "parent" -> 39 557 | |>, 558 | 105 -> <| 559 | "name" -> "演示", 560 | "url" -> "http://www.bilibili.com/video/tech-geo-course-1.html", 561 | "parent" -> 122 562 | |>, 563 | 107 -> <| 564 | "name" -> "科技人文", 565 | "url" -> "http://www.bilibili.com/video/tech-humanity-1.html", 566 | "parent" -> 124 567 | |>, 568 | 108 -> <| 569 | "name" -> "趣味短片", 570 | "url" -> "http://www.bilibili.com/video/tech-funvideo-1.html", 571 | "parent" -> 124 572 | |>, 573 | 110 -> <| 574 | "name" -> "国产", 575 | "url" -> "http://www.bilibili.com/video/soap-three-cn-1.html", 576 | "parent" -> 15 577 | |>, 578 | 111 -> <| 579 | "name" -> "日剧", 580 | "url" -> "http://www.bilibili.com/video/soap-three-jp-1.html", 581 | "parent" -> 15 582 | |>, 583 | 112 -> <| 584 | "name" -> "美剧", 585 | "url" -> "http://www.bilibili.com/video/soap-three-us-1.html", 586 | "parent" -> 15 587 | |>, 588 | 113 -> <| 589 | "name" -> "其他电视剧", 590 | "url" -> "http://www.bilibili.com/video/soap-three-oth-1.html", 591 | "parent" -> 15 592 | |>, 593 | 114 -> <| 594 | "name" -> "国内综艺", 595 | "url" -> "http://www.bilibili.com/video/index.html", 596 | "parent" -> 71 597 | |>, 598 | 115 -> <| 599 | "name" -> "国外综艺", 600 | "url" -> "http://www.bilibili.com/video/index.html", 601 | "parent" -> 71 602 | |>, 603 | 116 -> <| 604 | "name" -> "游戏", 605 | "url" -> "http://www.bilibili.com/video/index.html", 606 | "parent" -> 12 607 | |>, 608 | 117 -> <| 609 | "name" -> "音乐", 610 | "url" -> "http://www.bilibili.com/video/index.html", 611 | "parent" -> 12 612 | |>, 613 | 118 -> <| 614 | "name" -> "其他", 615 | "url" -> "http://www.bilibili.com/video/index.html", 616 | "parent" -> 12 617 | |>, 618 | 119 -> <| 619 | "name" -> "鬼畜", 620 | "url" -> "http://www.bilibili.com/video/kichiku.html", 621 | "parent" -> 0 622 | |>, 623 | 120 -> <| 624 | "name" -> "剧场版", 625 | "url" -> "http://www.bilibili.com/video/newbangumi-ova-1.html", 626 | "parent" -> 33 627 | |>, 628 | 121 -> <| 629 | "name" -> "GMV", 630 | "url" -> "http://www.bilibili.com/video/gmv-1.html", 631 | "parent" -> 116 632 | |>, 633 | 122 -> <| 634 | "name" -> "野生技术协会", 635 | "url" -> "http://www.bilibili.com/video/tech-wild-1.html", 636 | "parent" -> 36 637 | |>, 638 | 123 -> <| 639 | "name" -> "手办模型", 640 | "url" -> "http://www.bilibili.com/video/figure-1.html", 641 | "parent" -> 122 642 | |>, 643 | 124 -> <| 644 | "name" -> "趣味科普人文", 645 | "url" -> "http://www.bilibili.com/video/tech-fun-1.html", 646 | "parent" -> 36 647 | |>, 648 | 125 -> <| 649 | "name" -> "其他", 650 | "url" -> "http://www.bilibili.com/video/tech-geo-other-1.html", 651 | "parent" -> 37 652 | |>, 653 | 126 -> <| 654 | "name" -> "人力VOCALOID", 655 | "url" -> "http://www.bilibili.com/video/kichiku-manual_vocaloid-1.html", 656 | "parent" -> 119 657 | |>, 658 | 127 -> <| 659 | "name" -> "教程演示", 660 | "url" -> "http://www.bilibili.com/video/kichiku-course-1.html", 661 | "parent" -> 119 662 | |>, 663 | 128 -> <| 664 | "name" -> "电视剧相关", 665 | "url" -> "http://www.bilibili.com/video/tv-presentation-1.html", 666 | "parent" -> 11 667 | |>, 668 | 129 -> <| 669 | "name" -> "舞蹈", 670 | "url" -> "http://www.bilibili.com/video/dance.html", 671 | "parent" -> 0 672 | |>, 673 | 130 -> <| 674 | "name" -> "音乐选集", 675 | "url" -> "http://www.bilibili.com/video/music-collection-1.html", 676 | "parent" -> 117 677 | |>, 678 | 131 -> <| 679 | "name" -> "Korea相关", 680 | "url" -> "http://www.bilibili.com/video/ent-korea-1.html", 681 | "parent" -> 5 682 | |>, 683 | 132 -> <| 684 | "name" -> "Korea音乐舞蹈", 685 | "url" -> "http://www.bilibili.com/video/ent-korea-music-dance-1.html", 686 | "parent" -> 131 687 | |>, 688 | 133 -> <| 689 | "name" -> "Korea综艺", 690 | "url" -> "http://www.bilibili.com/video/ent-korea-variety-1.html", 691 | "parent" -> 131 692 | |>, 693 | 134 -> <| 694 | "name" -> "其他", 695 | "url" -> "http://www.bilibili.com/video/ent-korea-other-1.html", 696 | "parent" -> 131 697 | |>, 698 | 135 -> <| 699 | "name" -> "活动", 700 | "url" -> "http://www.bilibili.com/video/video/activities.html", 701 | "parent" -> 0 702 | |>, 703 | 136 -> <| 704 | "name" -> "音游", 705 | "url" -> "http://www.bilibili.com/video/music-game-1.html", 706 | "parent" -> 116 707 | |>, 708 | 137 -> <| 709 | "name" -> "娱乐圈", 710 | "url" -> "http://www.bilibili.com/video/ent-circle-1.html", 711 | "parent" -> 5 712 | |>, 713 | 138 -> <| 714 | "name" -> "搞笑", 715 | "url" -> "http://www.bilibili.com/video/ent_funny_1.html", 716 | "parent" -> 5 717 | |>, 718 | 139 -> <| 719 | "name" -> "实况解说", 720 | "url" -> "http://www.bilibili.com/video/list__1.html", 721 | "parent" -> 65 722 | |>, 723 | 140 -> <| 724 | "name" -> "游戏杂谈", 725 | "url" -> "http://www.bilibili.com/video/list__1.html", 726 | "parent" -> 65 727 | |>, 728 | 141 -> <| 729 | "name" -> "游戏集锦", 730 | "url" -> "http://www.bilibili.com/video/list__1.html", 731 | "parent" -> 65 732 | |>, 733 | 142 -> <| 734 | "name" -> "漫展", 735 | "url" -> "http://www.bilibili.com/video/list__1.html", 736 | "parent" -> 21 737 | |>, 738 | 143 -> <| 739 | "name" -> "COSPLAY", 740 | "url" -> "http://www.bilibili.com/video/list__1.html", 741 | "parent" -> 21 742 | |>, 743 | 144 -> <| 744 | "name" -> "综艺剪辑", 745 | "url" -> "http://www.bilibili.com/video/list__1.html", 746 | "parent" -> 71 747 | |>, 748 | 145 -> <| 749 | "name" -> "欧美电影", 750 | "url" -> "http://www.bilibili.com/video/movie_west_1.html", 751 | "parent" -> 23 752 | |>, 753 | 146 -> <| 754 | "name" -> "日本电影", 755 | "url" -> "http://www.bilibili.com/video/movie_japan_1.html", 756 | "parent" -> 23 757 | |>, 758 | 147 -> <| 759 | "name" -> "国产电影", 760 | "url" -> "http://www.bilibili.com/video/movie_chinese_1.html", 761 | "parent" -> 23 762 | |>, 763 | 148 -> <| 764 | "name" -> "TV动画", 765 | "url" -> "http://www.bilibili.com/video/list__1.html", 766 | "parent" -> 33 767 | |>, 768 | 149 -> <| 769 | "name" -> "OVA\[CenterDot]OAD", 770 | "url" -> "http://www.bilibili.com/video/list__1.html", 771 | "parent" -> 33 772 | |>, 773 | 150 -> <| 774 | "name" -> "TV动画", 775 | "url" -> "http://www.bilibili.com/video/list__1.html", 776 | "parent" -> 32 777 | |>, 778 | 151 -> <| 779 | "name" -> "OVA\[CenterDot]OAD", 780 | "url" -> "http://www.bilibili.com/video/list__1.html", 781 | "parent" -> 32 782 | |>, 783 | 152 -> <| 784 | "name" -> "官方延伸", 785 | "url" -> "http://www.bilibili.com/video/bagumi_offical_1.html", 786 | "parent" -> 13 787 | |>, 788 | 153 -> <| 789 | "name" -> "国产动画", 790 | "url" -> "http://www.bilibili.com/video/bangumi_chinese_1.html", 791 | "parent" -> 13 792 | |>, 793 | 154 -> <| 794 | "name" -> "三次元舞蹈", 795 | "url" -> "http://www.bilibili.com/video/three-dimension-dance-1.html", 796 | "parent" -> 129 797 | |> 798 | |>; 799 | 800 | (* 编号全靠口胡, 服气 801 | URLExecute["https://api.bilibili.com/x/web-show/res/locs?pf=0&ids="<>StringJoin@StringRiffle[ToString /@ Range[1, 10000], ","], "RawJSON"] 802 | StringRiffle[Keys[%["data"]], ","] // Sort*) 803 | $LocPF0 = "21,23,29,31,34,40,42,44,52,58,64,70,76,82,88,94, 804 | 100,106,112,118,124,126,128,130,132,134,136,138,142, 805 | 148,151,152,153,160,162,243,245,247,249,251,253,255, 806 | 257,259,261,263,265,267,269,271,273,275,277,279,281, 807 | 283,285,287,289,291,293,295,395,403,405,406,412,413, 808 | 414,415,417,418,419,1466,1550,1554,1556,1558,1560,1562, 809 | 1564,1566,1568,1570,1572,1574,1576,1578,1580,1582,1584, 810 | 1586,1588,1590,1592,1594,1596,1598,1600,1602,1604,1606, 811 | 1608,1610,1612,1614,1616,1618,1620,1622,1624,1626,1628, 812 | 1630,1632,1634,1636,1660,1666,1670,1674,1680,1682,1919, 813 | 1920,1921,1922,1923,1966,2034,2047,2048,2057,2058,2061, 814 | 2062,2065,2066,2067,2078,2079,2207,2210,2211,2212,2213, 815 | 2214,2257,2260,2261,2262,2263,2264,2307,2308,2309,2319, 816 | 2341,2343,2345,2403,2452,2453,2462,2463,2472,2473,2482, 817 | 2483,2492,2493,2503"; 818 | 819 | (* ::Subsection::Closed:: *) 820 | (*Secret*) 821 | $Secrets::usage = "官方key注册通道已经关闭\r 822 | 虽然可以用黑科技注入, 但是已经搞不到高权限的key了\r 823 | 所以只能用现有的开源方案来搞了, 这些key来自\r 824 | https://github.com/search?q=bilibili+appkey&type=Code"; 825 | $Secrets = { 826 | <| 827 | "AppKey" -> "84956560bc028eb7", 828 | "Source" -> "soimort/you-get", 829 | "LastTest" -> "No Test" 830 | |>, 831 | <| 832 | "AppKey" -> "f3bb208b3d081dc8", 833 | "Secret" -> "1c15888dc316e05a15fdd0a02ed6584f" 834 | "Source" -> "MoePlayer/DPlayer-API", 835 | "LastTest" -> "Success when 20180513" 836 | |> 837 | 838 | }; 839 | 840 | 841 | 842 | $APIs = <| 843 | "PhotoHot" -> Function[Table[$RawAPIs["photohot", "url", #][<|"page" -> i|>], {i, 0, 24}]], 844 | "PhotoRank" -> Function[Through[Values[$RawAPIs["photorank", "url"]][<|"time" -> #|>]]], 845 | "RidList" -> $RidList, 846 | "VideoSection" -> Function[$RawAPIs["vs"]["rid" -> #]] 847 | |>; 848 | 849 | $BilibiliLinkUA = { 850 | "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1; AcooBrowser; .NET CLR 1.1.4322; .NET CLR 2.0.50727)", 851 | "Mozilla/4.0 (compatible; MSIE 7.0; Windows NT 6.0; Acoo Browser; SLCC1; .NET CLR 2.0.50727; Media Center PC 5.0; .NET CLR 3.0.04506)", 852 | "Mozilla/4.0 (compatible; MSIE 7.0; AOL 9.5; AOLBuild 4337.35; Windows NT 5.1; .NET CLR 1.1.4322; .NET CLR 2.0.50727)", 853 | "Mozilla/5.0 (Windows; U; MSIE 9.0; Windows NT 9.0; en-US)", 854 | "Mozilla/5.0 (compatible; MSIE 9.0; Windows NT 6.1; Win64; x64; Trident/5.0; .NET CLR 3.5.30729; .NET CLR 3.0.30729; .NET CLR 2.0.50727; Media Center PC 6.0)", 855 | "Mozilla/5.0 (compatible; MSIE 8.0; Windows NT 6.0; Trident/4.0; WOW64; Trident/4.0; SLCC2; .NET CLR 2.0.50727; .NET CLR 3.5.30729; .NET CLR 3.0.30729; .NET CLR 1.0.3705; .NET CLR 1.1.4322)", 856 | "Mozilla/4.0 (compatible; MSIE 7.0b; Windows NT 5.2; .NET CLR 1.1.4322; .NET CLR 2.0.50727; InfoPath.2; .NET CLR 3.0.04506.30)", 857 | "Mozilla/5.0 (Windows; U; Windows NT 5.1; zh-CN) AppleWebKit/523.15 (KHTML, like Gecko, Safari/419.3) Arora/0.3 (Change: 287 c9dfb30)", 858 | "Mozilla/5.0 (X11; U; Linux; en-US) AppleWebKit/527+ (KHTML, like Gecko, Safari/419.3) Arora/0.6", 859 | "Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.8.1.2pre) Gecko/20070215 K-Ninja/2.1.1", 860 | "Mozilla/5.0 (Windows; U; Windows NT 5.1; zh-CN; rv:1.9) Gecko/20080705 Firefox/3.0 Kapiko/3.0", 861 | "Mozilla/5.0 (X11; Linux i686; U;) Gecko/20070322 Kazehakase/0.4.5", 862 | "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.9.0.8) Gecko Fedora/1.9.0.8-1.fc10 Kazehakase/0.5.6", 863 | "Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/535.11 (KHTML, like Gecko) Chrome/17.0.963.56 Safari/535.11", 864 | "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_7_3) AppleWebKit/535.20 (KHTML, like Gecko) Chrome/19.0.1036.7 Safari/535.20", 865 | "Opera/9.80 (Macintosh; Intel Mac OS X 10.6.8; U; fr) Presto/2.9.168 Version/11.52", 866 | "Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/536.11 (KHTML, like Gecko) Chrome/20.0.1132.11 TaoBrowser/2.0 Safari/536.11", 867 | "Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.1 (KHTML, like Gecko) Chrome/21.0.1180.71 Safari/537.1 LBBROWSER", 868 | "Mozilla/5.0 (compatible; MSIE 9.0; Windows NT 6.1; WOW64; Trident/5.0; SLCC2; .NET CLR 2.0.50727; .NET CLR 3.5.30729; .NET CLR 3.0.30729; Media Center PC 6.0; .NET4.0C; .NET4.0E; LBBROWSER)", 869 | "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1; QQDownload 732; .NET4.0C; .NET4.0E; LBBROWSER)", 870 | "Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/535.11 (KHTML, like Gecko) Chrome/17.0.963.84 Safari/535.11 LBBROWSER", 871 | "Mozilla/4.0 (compatible; MSIE 7.0; Windows NT 6.1; WOW64; Trident/5.0; SLCC2; .NET CLR 2.0.50727; .NET CLR 3.5.30729; .NET CLR 3.0.30729; Media Center PC 6.0; .NET4.0C; .NET4.0E)", 872 | "Mozilla/5.0 (compatible; MSIE 9.0; Windows NT 6.1; WOW64; Trident/5.0; SLCC2; .NET CLR 2.0.50727; .NET CLR 3.5.30729; .NET CLR 3.0.30729; Media Center PC 6.0; .NET4.0C; .NET4.0E; QQBrowser/7.0.3698.400)", 873 | "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1; QQDownload 732; .NET4.0C; .NET4.0E)", 874 | "Mozilla/4.0 (compatible; MSIE 7.0; Windows NT 5.1; Trident/4.0; SV1; QQDownload 732; .NET4.0C; .NET4.0E; 360SE)", 875 | "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1; QQDownload 732; .NET4.0C; .NET4.0E)", 876 | "Mozilla/4.0 (compatible; MSIE 7.0; Windows NT 6.1; WOW64; Trident/5.0; SLCC2; .NET CLR 2.0.50727; .NET CLR 3.5.30729; .NET CLR 3.0.30729; Media Center PC 6.0; .NET4.0C; .NET4.0E)", 877 | "Mozilla/5.0 (Windows NT 5.1) AppleWebKit/537.1 (KHTML, like Gecko) Chrome/21.0.1180.89 Safari/537.1", 878 | "Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.1 (KHTML, like Gecko) Chrome/21.0.1180.89 Safari/537.1", 879 | "Mozilla/5.0 (iPad; U; CPU OS 4_2_1 like Mac OS X; zh-cn) AppleWebKit/533.17.9 (KHTML, like Gecko) Version/5.0.2 Mobile/8C148 Safari/6533.18.5", 880 | "Mozilla/5.0 (Windows NT 6.1; Win64; x64; rv:2.0b13pre) Gecko/20110307 Firefox/4.0b13pre", 881 | "Mozilla/5.0 (X11; Ubuntu; Linux x86_64; rv:16.0) Gecko/20100101 Firefox/16.0", 882 | "Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.11 (KHTML, like Gecko) Chrome/23.0.1271.64 Safari/537.11", 883 | "Mozilla/5.0 (X11; U; Linux x86_64; zh-CN; rv:1.9.2.10) Gecko/20100922 Ubuntu/10.10 (maverick) Firefox/3.6.10" 884 | }; 885 | 886 | 887 | 888 | SetAttributes[ 889 | {$RawAPIs, $RidList, $APIs}, 890 | {Protected, ReadProtected} 891 | ]; 892 | End[]; 893 | -------------------------------------------------------------------------------- /Packages/!Directories.m: -------------------------------------------------------------------------------- 1 | $BilibiliLinkDirectory::usage = "BilibiliLink 的安装路径."; 2 | $BilibiliLinkIcons::usage = "BilibiliLink 的图标映射."; 3 | $BilibiliLinkData::usage = "BilibiliLink 的数据存放位置."; 4 | BilibiliLink`ㄑDirectories::usage = ""; 5 | BilibiliLink`ㄑDirectories[___] := ""; 6 | Begin["`Directories`"]; 7 | 8 | 9 | $BilibiliLinkDirectory = DirectoryName[FindFile["BilibiliLink`Kernel`"], 2]; 10 | $BilibiliLinkData = FileNameJoin[{$UserBaseDirectory, "ApplicationData", "BilibiliLink"}]; 11 | 12 | 13 | 14 | $BLID::usage = "BilibiliLinkIconsDirectory,BilibiliLink 图片图标的存放路径."; 15 | $BLID = FileNameJoin[{$BilibiliLinkDirectory, "Resources", "ico"}]; 16 | $BilibiliLinkIcons[name_] := $BilibiliLinkIcons[name] = Switch[name, 17 | "BilibiliAlbumObject", 18 | Image[Import[FileNameJoin[{$BLID, "BilibiliAlbumObject.jpg"}], "jpg"], ImageSize -> {Automatic, 140}], 19 | "BilibiliVideoSectionObject", 20 | Image[Import[FileNameJoin[{$BLID, "BilibiliVideoSectionObject.png"}], "png"], ImageSize -> {Automatic, 53}], 21 | "BilibiliDownloadObject", 22 | Image[Import[FileNameJoin[{$BLID, "BilibiliDownloadObject.png"}], "png"], ImageSize -> {Automatic, 64}] 23 | ]; 24 | 25 | 26 | SetAttributes[ 27 | {$BLID}, 28 | {Protected, ReadProtected} 29 | ]; 30 | End[]; 31 | -------------------------------------------------------------------------------- /Packages/BilibiliCore.m: -------------------------------------------------------------------------------- 1 | AbortableMap::usage = ""; 2 | BilibiliLink`ㄑFunctions::usage = ""; 3 | BilibiliLink`ㄑFunctions[___] := ""; 4 | Begin["`Functions`"]; 5 | timeLeft[start_, frac_] := With[{past = AbsoluteTime[] - start}, If[frac == 0 || past < 1, "-", Floor[past / frac - past]]]; 6 | AbortableMap[func_, list_, ker_ : $KernelCount] := DynamicModule[ 7 | {len, bag, size, lastresults, starttime, n, results, t}, 8 | len = Length[list]; size = 0; starttime = AbsoluteTime[]; 9 | results = {}; SetSharedVariable[results, size]; 10 | Monitor[ 11 | t = Table[ParallelSubmit[{i}, 12 | With[ 13 | {r = func[list[[i]]]}, 14 | size += ByteCount[r]; 15 | AppendTo[results, {i, r}] 16 | ] 17 | ], {i, Range[len]}]; 18 | CheckAbort[WaitAll[t], AbortKernels[]]; 19 | SortBy[results, First], 20 | Dynamic@Refresh[Panel @ Column[{ 21 | ProgressIndicator[Length[results] / len, ImageSize -> 350], 22 | Row[{Button["Abort", Abort[]], 23 | Grid[{{"Tasks", "Memory (kB)", "Time left (s)"}, 24 | {StringForm["``/``", Length[results], len], 25 | ToString @ NumberForm[size / 2.^10, {3, 2}], 26 | ToString @ timeLeft[starttime, Length[results] / len]} 27 | }, Spacings -> {1, 1}, ItemSize -> {10, 1}, Dividers -> Center 28 | ]}, Spacer[5]] 29 | }], UpdateInterval -> 1, TrackedSymbols -> {} 30 | ] 31 | ] 32 | ]; 33 | WriteCSV[file_String, matrix_] := With[ 34 | { 35 | str = OpenWrite[file, PageWidth -> Infinity], 36 | len = Length[First@matrix] 37 | }, 38 | Scan[Write[str, 39 | Sequence @@ (Flatten[ 40 | Table[{FortranForm[#[[i]]], OutputForm[","]}, {i, len - 1}] 41 | ]) ~ Join ~ {FortranForm[#[[len]]]}]&, matrix 42 | ]; 43 | Close[str]; 44 | ]; 45 | SetAttributes[ 46 | {}, 47 | {Protected, ReadProtected} 48 | ]; 49 | End[] 50 | -------------------------------------------------------------------------------- /Packages/BilibiliDDOS.m: -------------------------------------------------------------------------------- 1 | VipEmoji::usage = "xxx"; 2 | IndexIcon::usage = "xxx"; 3 | ErrorPage::usage = "xxx"; 4 | HeaderBanner::usage = "xxx"; 5 | HeaderLogo::usage = "xxx"; 6 | BilibiliLink`ㄑDDOS::usage = ""; 7 | BilibiliLink`ㄑDDOS[___] := ""; 8 | Begin["`DDOS`"]; 9 | VipEmojiReshape[line_] := Block[ 10 | {drop = KeyDrop[line["emojis"], {"state", "remark"}]}, 11 | Append[ 12 | <|"ID" -> #["id"], "URL" -> #["url"], "Name" -> StringTake[#["name"], 2 ;; -2]|>& /@ drop, 13 | <|"ID" -> line["pid"], "URL" -> line["purl"], "Name" -> line["pname"]|> 14 | ]]; 15 | Options[VipEmoji] = {Path -> FileNameJoin[{$BilibiliLinkData, "Image", "Emoji"}]}; 16 | VipEmoji[___, OptionsPattern[]] := Block[ 17 | {get = URLExecute["http://api.bilibili.com/x/v2/reply/emojis", "RawJSON"]["data"]}, 18 | BilibiliDownloadObject[<| 19 | "Date" -> Now, 20 | "Category" -> "Bilibili Vip Emoji", 21 | "Data" -> SortBy[Flatten[VipEmojiReshape /@ get], "ID"], 22 | "Path" -> OptionValue[Path], 23 | "Size" -> 5021696. 24 | |> 25 | ]]; 26 | VipEmoji["Raw"] := URLExecute["http://api.bilibili.com/x/v2/reply/emojis", "RawJSON"]["data"]; 27 | 28 | 29 | 30 | IndexIconReshape[line_] := <| 31 | "ID" -> line["id"], 32 | "Name" -> line["title"], 33 | "URL" -> line["icon"] 34 | |>; 35 | Options[IndexIcon] = {Path -> FileNameJoin[{$BilibiliLinkData, "Image", "Icon"}]}; 36 | IndexIcon[___, OptionsPattern[]] := Block[ 37 | {get = URLExecute["https://www.bilibili.com/index/index-icon.json", "RawJSON"]["fix"]}, 38 | BilibiliDownloadObject[<| 39 | "Date" -> Now, 40 | "Category" -> "Bilibili Index Icon", 41 | "Data" -> SortBy[Flatten[IndexIconReshape /@ get], "ID"], 42 | "Path" -> OptionValue[Path], 43 | "Size" -> 8015872. 44 | |> 45 | ]]; 46 | IndexIcon["Raw"] := URLExecute["https://www.bilibili.com/index/index-icon.json", "RawJSON"]["fix"]; 47 | tsLine[doc_] := { 48 | "#### Title: " <> doc["id"] <> "_" <> doc["title"], 49 | "##### Date: " <> DateString[FromUnixTime[ToExpression@doc["sttime"]]], 50 | "##### Link: " <> StringDelete[URLDecode@URLDecode@First@doc["links"], " "], 51 | "![" <> First@doc["links"] <> "](https:" <> doc["icon"] <> ")", 52 | "---" 53 | }; 54 | IndexIcon["Markdown", OptionsPattern[]] := Block[ 55 | {get = IndexIcon["Raw"], file = OptionValue[Path], name}, 56 | name = FileNameJoin[{file, "IndexIcon.md"}]; 57 | If[!FileExistsQ[file], CreateFile[file]]; 58 | If[FileExistsQ[name], DeleteFile[name]]; 59 | Export[name, StringJoin@Riffle[Flatten[tsLine /@ SortBy[get, ToExpression[#["id"]]&]], "\r"], "Text"] 60 | ]; 61 | 62 | 63 | $ErrorPageExtension = { 64 | "https://static.hdslb.com/error/400.png", 65 | "https://static.hdslb.com/error/403.png", 66 | "https://static.hdslb.com/error/404.png", 67 | "https://static.hdslb.com/error/444.png", 68 | "https://static.hdslb.com/error/500.png", 69 | "https://static.hdslb.com/error/502.png", 70 | "https://static.hdslb.com/error/503.png", 71 | "https://static.hdslb.com/error/504.png", 72 | "https://activity.hdslb.com/zzjs/cartoon/errorPage-manga-1.png", 73 | "https://activity.hdslb.com/zzjs/cartoon/errorPage-manga-2.png", 74 | "https://activity.hdslb.com/zzjs/cartoon/errorPage-manga-3.png", 75 | "https://activity.hdslb.com/zzjs/cartoon/errorPage-manga-4.png", 76 | "https://activity.hdslb.com/zzjs/cartoon/errorPage-manga-5.png", 77 | "https://activity.hdslb.com/zzjs/cartoon/errorPage-manga-6.png", 78 | "https://activity.hdslb.com/zzjs/cartoon/errorPage-manga-7.png", 79 | "https://static.hdslb.com/images/error/no_video_login.png", 80 | "https://static.hdslb.com/images/error/wait_for_review.png", 81 | "https://static.hdslb.com/images/error/wait_for_release.png", 82 | "https://static.hdslb.com/images/error/no_video.png", 83 | "https://static.hdslb.com/images/error/video_conflict.png" 84 | }; 85 | ErrorPageExtensionReshape[url_, {id_}] := <| 86 | "ID" -> id, 87 | "Name" -> StringSplit[url, {"/", "."}][[-2]], 88 | "URL" -> url 89 | |>; 90 | ErrorPageReshape[line_] := <| 91 | "ID" -> line["id"], 92 | "Name" -> StringJoin["error_cover_", line["id"]], 93 | "URL" -> line["data", "img"] 94 | |>; 95 | Options[ErrorPage] = {Path -> FileNameJoin[{$BilibiliLinkData, "Image", "Icon"}]}; 96 | ErrorPage[___, OptionsPattern[]] := Block[ 97 | {get = URLExecute["www.bilibili.com/activity/web/view/data/31", "RawJSON"]["data", "list"], data}, 98 | data = Join[ErrorPageReshape /@ get, MapIndexed[ErrorPageExtensionReshape, $ErrorPageExtension]]; 99 | BilibiliDownloadObject[<| 100 | "Date" -> Now, 101 | "Category" -> "Bilibili Error Page", 102 | "Data" -> SortBy[data, "ID"], 103 | "Path" -> OptionValue[Path], 104 | "Size" -> 58363904. 105 | |>] 106 | ]; 107 | 108 | 109 | HeaderReshape[asc_] := Module[ 110 | {name, banner, icon, c = asc["c"]}, 111 | If[c === {}, Return[Nothing]]; 112 | name = If[KeyExistsQ[asc["c"], "title"], c["title"], c["name"]]; 113 | icon = If[ 114 | KeyExistsQ[asc["c"], "logo"], 115 | Last@StringSplit[c["logo"], "/"], 116 | Last@StringSplit[c["litpic"], "/"] 117 | ]; 118 | banner = If[ 119 | KeyExistsQ[asc["c"], "pic"], 120 | Last@StringSplit[c["pic"], "/"], 121 | Last@StringSplit[c["background"], "/"] 122 | ]; 123 | <| 124 | "Title" -> c["name"], 125 | "Date" -> First@StringSplit[asc["n"], {"_", "-"}], 126 | "Banner" -> "https://i0.hdslb.com/headers/" <> banner, 127 | "Logo" -> "https://i0.hdslb.com/headers/" <> icon, 128 | "Link" -> c["url"] 129 | |> 130 | ]; 131 | GetHeader[] := GetHeader[] = Block[ 132 | {get, json, list}, 133 | get = URLFetch["https://www.biliplus.com/task/banner_fetch/"]; 134 | json = First@StringCases[get, "var items=" ~~ json__ ~~ "}}];" :> json <> "}}]"]; 135 | list = ImportString[ToString[json, CharacterEncoding -> "UTF8"], "RawJSON"]; 136 | HeaderReshape /@ list 137 | ]; 138 | 139 | HeaderBannerReshape[line_, {index_}] := <|"ID" -> index, "Name" -> StringSplit[line["Banner"], {"/", "."}][[-2]], "URL" -> line["Banner"]|>; 140 | Options[HeaderBanner] = {Path -> FileNameJoin[{$BilibiliLinkData, "Image", "Banner"}]}; 141 | HeaderBanner[___, OptionsPattern[]] := Block[ 142 | {get = GetHeader[], data}, 143 | data = MapIndexed[HeaderBannerReshape, get]; 144 | BilibiliDownloadObject[<| 145 | "Date" -> Now, 146 | "Category" -> "Bilibili Header Banner", 147 | "Data" -> SortBy[data, "ID"], 148 | "Path" -> OptionValue[Path], 149 | "Size" -> 118206806. 150 | |>] 151 | ]; 152 | HeaderLogoReshape[line_, {index_}] := <|"ID" -> index, "Name" -> StringSplit[line["Logo"], {"/", "."}][[-2]], "URL" -> line["Logo"]|>; 153 | Options[HeaderLogo] = {Path -> FileNameJoin[{$BilibiliLinkData, "Image", "Logo"}]}; 154 | HeaderLogo[___, OptionsPattern[]] := Block[ 155 | {get = GetHeader[], data}, 156 | data = MapIndexed[HeaderLogoReshape, get]; 157 | BilibiliDownloadObject[<| 158 | "Date" -> Now, 159 | "Category" -> "Bilibili Header Logo", 160 | "Data" -> SortBy[data, "ID"], 161 | "Path" -> OptionValue[Path], 162 | "Size" -> 17955498. 163 | |>] 164 | ]; 165 | 166 | SetAttributes[ 167 | {}, 168 | {Protected, ReadProtected} 169 | ]; 170 | End[] 171 | -------------------------------------------------------------------------------- /Packages/BilibiliDataServer.m: -------------------------------------------------------------------------------- 1 | $BilibiliServer::usage = "远程数据服务器"; 2 | BilibiliLink`ㄑRemote::usage = ""; 3 | BilibiliLink`ㄑRemote[___] := ""; 4 | Needs["MongoLink`"]; 5 | Begin["`Remote`"]; 6 | $BilibiliServer = "https://m.vers.site"; 7 | $DatabaseServer = "mongodb://biliman:readonly@45.32.68.44:37017/bilispider"; 8 | DatabaseClient=MongoLink`MongoConnect[$DatabaseServer]; 9 | TracedMemberDB=MongoLink`MongoGetCollection[DatabaseClient,"bilispider","trace_member_info"]; 10 | TracedVideoDB=MongoLink`MongoGetCollection[DatabaseClient,"bilispider","trace_video_stat"]; 11 | 12 | 13 | 14 | 15 | 16 | GetTraceRemote[id_]:=Block[ 17 | {cursor,data}, 18 | cursor=MongoLink`MongoCollectionFind[ 19 | TracedVideoDB, 20 | <|"aid"->id|>, 21 | <|"_id"->False,"aid"->False|> 22 | ]; 23 | data=MongoLink`MongoCursorToArray[cursor] 24 | ]; 25 | 26 | 27 | 28 | SetAttributes[ 29 | {}, 30 | {Protected, ReadProtected} 31 | ]; 32 | End[] 33 | -------------------------------------------------------------------------------- /Packages/BilibiliPhoto.m: -------------------------------------------------------------------------------- 1 | PhotosIndex::usage = ""; 2 | PhotosRange::usage = ""; 3 | PhotosHot::usage = ""; 4 | PhotosNew::usage = ""; 5 | PhotosRank::usage = ""; 6 | BilibiliLink`ㄑPhoto::usage = ""; 7 | BilibiliLink`ㄑPhoto[___] := ""; 8 | Begin["`Photo`"]; 9 | $PhotoKeyMap = <| 10 | 1 -> <|"Name" -> "插画", "Alias" -> "Illustration", "Key" -> "illustration", "Url" -> "https://h.bilibili.com/eden/draw_area#/illustration"|>, 11 | 2 -> <|"Name" -> "漫画", "Alias" -> "Comic", "Key" -> "comic", "Url" -> "https://h.bilibili.com/eden/draw_area#/comic"|>, 12 | 3 -> <|"Name" -> "其他画作", "Alias" -> "OtherDraw", "Key" -> "draw", "Url" -> "https://h.bilibili.com/eden/draw_area#/other"|>, 13 | 4 -> <|"Name" -> "全部画作", "Alias" -> "DrawAll", "Key" -> "alld", "Url" -> "https://h.bilibili.com/eden/draw_area#/all"|>, 14 | 5 -> <|"Name" -> "Cosplay", "Alias" -> "Cosplay", "Key" -> "cos", "Url" -> "https://h.bilibili.com/eden/picture_area#/cos"|>, 15 | 6 -> <|"Name" -> "其他摄影", "Alias" -> "OtherPhoto", "Key" -> "sifu", "Url" -> "https://h.bilibili.com/eden/picture_area#/sifu"|>, 16 | 7 -> <|"Name" -> "全部摄影", "Alias" -> "PhotoAll", "Key" -> "allp", "Url" -> "https://h.bilibili.com/eden/picture_area#/all"|>, 17 | 8 -> <|"Name" -> "日榜/新人榜", "Alias" -> "DayLeader", "Key" -> "day", "Url" -> "https://h.bilibili.com/common/rank#/photo"|>, 18 | 9 -> <|"Name" -> "周榜", "Alias" -> "WeekLeader", "Key" -> "week", "Url" -> "https://h.bilibili.com/common/rank#/photo"|>, 19 | 10 -> <|"Name" -> "月榜", "Alias" -> "MonthLeader", "Key" -> "month", "Url" -> "https://h.bilibili.com/common/rank#/photo"|> 20 | |>; 21 | $PhotosAPI = <| 22 | "Home" -> "https://api.vc.bilibili.com/link_draw/v2/Doc/home", 23 | "Range" -> StringTemplate["https://api.vc.bilibili.com/link_draw/v1/doc/detail?doc_id=`id`"], 24 | "Detail" -> StringTemplate["https://api.vc.bilibili.com/link_draw/v1/doc/detail?doc_id=`id`"], 25 | "Author" -> StringTemplate["https://api.vc.bilibili.com/link_draw/v1/doc/doc_list?uid=`id`&page_num=`page`&page_size=100"], 26 | "AuthorCount" -> StringTemplate["https://api.vc.bilibili.com/link_draw/v1/doc/upload_count?uid=`id`"], 27 | "AuthorDetail" -> StringTemplate["https://api.vc.bilibili.com/user_ex/v1/user/detail?user[]=info&user[]=level&room[]=live_status&room[]=room_link&feed[]=fans_count&feed[]=feed_count&feed[]=is_followed&uid=`id`"], 28 | "New" -> Function[Switch[#, 29 | "illustration", StringTemplate["https://api.vc.bilibili.com/link_draw/v2/Doc/list?category=illustration&type=new&page_num=`p`&page_size=20"], 30 | "comic", StringTemplate["https://api.vc.bilibili.com/link_draw/v2/Doc/list?category=comic&type=new&page_num=`p`&page_size=20"], 31 | "draw", StringTemplate["https://api.vc.bilibili.com/link_draw/v2/Doc/list?category=draw&type=new&page_num=`p`&page_size=20"], 32 | "alld", StringTemplate["https://api.vc.bilibili.com/link_draw/v2/Doc/list?category=all&type=new&page_num=`p`&page_size=20"], 33 | "cos", StringTemplate["https://api.vc.bilibili.com/link_draw/v2/Photo/list?category=cos&type=new&page_num=`p`&page_size=20"], 34 | "sifu", StringTemplate["https://api.vc.bilibili.com/link_draw/v2/Photo/list?category=sifu&type=new&page_num=`p`&page_size=20"], 35 | "allp", StringTemplate["https://api.vc.bilibili.com/link_draw/v2/Photo/list?category=all&type=new&page_num=`p`&page_size=20"] 36 | ]], 37 | "Hot" -> Function[Switch[#, 38 | "illustration", StringTemplate["https://api.vc.bilibili.com/link_draw/v2/Doc/list?category=illustration&type=hot&page_num=`p`&page_size=20"], 39 | "comic", StringTemplate["https://api.vc.bilibili.com/link_draw/v2/Doc/list?category=comic&type=hot&page_num=`p`&page_size=20"], 40 | "draw", StringTemplate["https://api.vc.bilibili.com/link_draw/v2/Doc/list?category=draw&type=hot&page_num=`p`&page_size=20"], 41 | "alld", StringTemplate["https://api.vc.bilibili.com/link_draw/v2/Doc/list?category=all&type=hot&page_num=`p`&page_size=20"], 42 | "cos", StringTemplate["https://api.vc.bilibili.com/link_draw/v2/Photo/list?category=cos&type=hot&page_num=`p`&page_size=20"], 43 | "sifu", StringTemplate["https://api.vc.bilibili.com/link_draw/v2/Photo/list?category=sifu&type=hot&page_num=`p`&page_size=20"], 44 | "allp", StringTemplate["https://api.vc.bilibili.com/link_draw/v2/Photo/list?category=all&type=hot&page_num=`p`&page_size=20"] 45 | ]], 46 | "Recommend" -> Function[{ 47 | StringTemplate["https://api.vc.bilibili.com/link_draw/v2/Doc/index?type=recommend&page_num=`p`&page_size=20"][#], 48 | StringTemplate["https://api.vc.bilibili.com/link_draw/v2/Photo/index?type=recommend&page_num=`p`&page_size=20"][#] 49 | }], 50 | "Rank" -> Function[{ 51 | StringTemplate["https://api.vc.bilibili.com/link_draw/v2/Doc/ranklist?biz=1&rank_type=`time`&page_size=50"][#], 52 | StringTemplate["https://api.vc.bilibili.com/link_draw/v2/Doc/ranklist?biz=2&category=cos&rank_type=`time`&page_size=50"][#], 53 | StringTemplate["https://api.vc.bilibili.com/link_draw/v2/Doc/ranklist?biz=2&category=sifu&rank_type=`time`&page_size=50"][#] 54 | }] 55 | |>; 56 | 57 | 58 | 59 | PhotosRangeReshape::usage = "PhotosRange的数据清洗."; 60 | PhotosRangeReshape[doc_Association] := <| 61 | "uid" -> doc["user", "uid"], 62 | "author" -> doc["user", "name"], 63 | "did" -> doc["item", "doc_id"], 64 | "title" -> If[doc["item", "title"] != "", 65 | doc["item", "title"], 66 | "无名_" <> ToString[doc["item", "doc_id"]] 67 | ], 68 | "time" -> DateObject[doc["item", "upload_time"]], 69 | "imgs" -> ("img_src" /. doc["item", "pictures"]), 70 | "size" -> If[KeyExistsQ[First@doc["item", "pictures"], "img_size"], 71 | Total["img_size" /. doc["item", "pictures"]], 72 | Missing 73 | ] 74 | |>; 75 | Options[PhotosRange] = {RawData -> False}; 76 | PhotosRange[n_Integer, ops : OptionsPattern[]] := PhotosRange[Range[n], ops]; 77 | PhotosRange[a_Integer, b_Integer, ops : OptionsPattern[]] := PhotosRange[Range[a, b], ops]; 78 | PhotosRange[input_List, OptionsPattern[]] := Module[ 79 | {$now = Now, urls, raw, data, count, size}, 80 | urls = Table[$PhotosAPI["Range"][<|"id" -> i|>], {i, input}]; 81 | raw = #["data"]& /@ Select[ParallelMap[URLExecute[#, "RawJSON"]&, urls], #["code"] == 0&]; 82 | If[OptionValue[RawData], Return[raw]]; 83 | data = PhotosRangeReshape /@ raw; 84 | If[data == {}, 85 | count = 0;size = 0, 86 | count = Length@Flatten["imgs" /. data]; 87 | size = Total@DeleteCases["size" /. data, Missing] 88 | ]; 89 | BilibiliAlbumObject[<| 90 | "Data" -> data, 91 | "Category" -> "PhotosRange", 92 | "Repo" -> ToString[Length@input] <> " of ???", 93 | "Count" -> count, 94 | "Size" -> size, 95 | "Time" -> Now - $now, 96 | "Date" -> $now 97 | |>] 98 | ]; 99 | 100 | 101 | PhotosIndex[] := Module[ 102 | {$now = Now, get, bg, size, imgs}, 103 | get = URLExecute[$PhotosAPI["Home"], "RawJSON"]["data"]; 104 | bg = <|"Name" -> ToString[Now // UnixTime] <> "_0", "URL" -> get["bg_img"]|>; 105 | size = Total@DeleteCases["img_size" /. get["items"], "img_size"]; 106 | imgs = Prepend["img_src" /. get["items"], bg]; 107 | BilibiliAlbumObject[<| 108 | "Data" -> {<| 109 | "uid" -> 12076317, 110 | "author" -> "BilibiliHomePage", 111 | "did" -> 0, 112 | "title" -> "HomePage " <> DateString[$now], 113 | "time" -> $now, 114 | "imgs" -> imgs, 115 | "size" -> size 116 | |>}, 117 | "Category" -> "PhotosHomePage", 118 | "Repo" -> "0 of 0", 119 | "Count" -> Length@imgs, 120 | "Size" -> size, 121 | "Time" -> Now - $now, 122 | "Date" -> $now 123 | |>] 124 | ]; 125 | 126 | 127 | PhotosHotReshape::usage = "内部函数, 用于数据清洗"; 128 | PhotosHotReshape[doc_Association] := <| 129 | "uid" -> doc["user", "uid"], 130 | "author" -> doc["user", "name"], 131 | "did" -> doc["item", "doc_id"], 132 | "title" -> If[doc["item", "title"] != "", 133 | doc["item", "title"], 134 | "无名_" <> ToString[doc["item", "doc_id"]] 135 | ], 136 | "time" -> FromUnixTime[doc["item", "upload_time"]], 137 | "imgs" -> ("img_src" /. doc["item", "pictures"]), 138 | "size" -> If[ 139 | KeyExistsQ[First@doc["item", "pictures"], "img_size"], 140 | Total["img_size" /. doc["item", "pictures"]], 141 | Missing 142 | ] 143 | |>; 144 | Options[PhotosHot] = {UpTo -> 100, RawData -> False}; 145 | PhotosHot[typenum_, OptionsPattern[]] := Module[ 146 | {$now = Now, api, map, raw, data}, 147 | api = $PhotosAPI["Hot"][$PhotoKeyMap[typenum]["Key"]]; 148 | map = Table[api[<|"p" -> i|>], {i, 0, Quotient[Min[OptionValue[UpTo] - 1, 500], 20]}]; 149 | raw = Flatten[URLExecute[#, "RawJSON"]["data", "items"]& /@ map]; 150 | If[OptionValue[RawData], Return[raw]]; 151 | data = PhotosHotReshape /@ raw; 152 | BilibiliAlbumObject[<| 153 | "Data" -> data, 154 | "Category" -> "PhotosHot" <> $PhotoKeyMap[typenum]["Alias"], 155 | "Repo" -> ToString[OptionValue[UpTo]] <> " of 500", 156 | "Count" -> Length@Flatten["imgs" /. data], 157 | "Size" -> Total@DeleteCases["size" /. data, Missing], 158 | "Time" -> Now - $now, 159 | "Date" -> $now 160 | |>] 161 | ]; 162 | 163 | 164 | PhotosNewFindMax::usage = "找到某一图片分类的总数."; 165 | SetAttributes[PhotosNewFindMax, Listable]; 166 | Options[PhotosNewFindMax] = {Max -> RandomInteger[{20000, 21000}], Count -> True}; 167 | PhotosNewFindMax[type_String, OptionsPattern[]] := Module[ 168 | {max, min, try, api}, 169 | {min, max} = {1, OptionValue[Max]}; 170 | api = $PhotosAPI["New"][type]; 171 | try = URLExecute[api[<|"p" -> #|>], "RawJSON"]["data"]&; 172 | While[max - min > 1, If[try[Floor[(min + max) / 2]]["total_count"] > 0, min = Floor[(min + max) / 2], max = Floor[(min + max) / 2]]]; 173 | If[OptionValue[Count], Return[Length[try[min]["items"]] + 20(min - 1)], min] 174 | ]; 175 | PhotosNewReshape::usage = "内部函数, 用于数据清洗"; 176 | PhotosNewReshape[doc_Association] := <| 177 | "uid" -> doc["user", "uid"], 178 | "author" -> doc["user", "name"], 179 | "did" -> doc["item", "doc_id"], 180 | "title" -> If[doc["item", "title"] != "", 181 | doc["item", "title"], 182 | "无名_" <> ToString[doc["item", "doc_id"]] 183 | ], 184 | "time" -> FromUnixTime[doc["item", "upload_time"]], 185 | "imgs" -> ("img_src" /. doc["item", "pictures"]), 186 | "size" -> If[ 187 | KeyExistsQ[First@doc["item", "pictures"], "img_size"], 188 | Total["img_size" /. doc["item", "pictures"]], 189 | Missing] 190 | |>; 191 | 192 | 193 | Options[PhotosNew] = {UpTo -> 100, RawData -> False, Count -> False, All -> False}; 194 | PhotosNew[typenum_, OptionsPattern[]] := Module[ 195 | {$now = Now, api, all, map, raw, data}, 196 | api = $PhotosAPI["New"][$PhotoKeyMap[typenum]["Key"]]; 197 | If[OptionValue[Count], 198 | all = ToString[PhotosNewFindMax[$PhotoKeyMap[typenum]["Key"]]], 199 | all = "???" 200 | ]; 201 | If[OptionValue[All], 202 | all = ToString[PhotosNewFindMax[$PhotoKeyMap[typenum]["Key"]]]; 203 | map = Table[api[<|"p" -> i|>], {i, 0, Quotient[ToExpression[all] - 1, 20]}], 204 | map = Table[api[<|"p" -> i|>], {i, 0, Quotient[OptionValue[UpTo] - 1, 20]}] 205 | ]; 206 | raw = Flatten[URLExecute[#, "RawJSON"]["data", "items"]& /@ map]; 207 | If[OptionValue[RawData], Return[raw]]; 208 | data = PhotosNewReshape /@ raw; 209 | BilibiliAlbumObject[<| 210 | "Data" -> data, 211 | "Category" -> "PhotosNew" <> $PhotoKeyMap[typenum]["Alias"], 212 | "Repo" -> ToString[OptionValue[UpTo]] <> " of " <> all, 213 | "Count" -> Length@Flatten["imgs" /. data], 214 | "Size" -> Total@DeleteCases["size" /. data, Missing], 215 | "Time" -> Now - $now, 216 | "Date" -> $now 217 | |>] 218 | ]; 219 | 220 | PhotosAuthorReshape::usage = "内部函数, 用于数据清洗"; 221 | PhotosAuthorReshape[doc_Association] := <| 222 | "uid" -> doc["poster_uid"], 223 | "author" -> doc["description"], 224 | "did" -> doc["doc_id"], 225 | "title" -> If[doc["item", "title"] != "", 226 | doc["item", "title"], 227 | "无名_" <> ToString[doc["item", "doc_id"]] 228 | ], 229 | "time" -> FromUnixTime[doc["ctime"]], 230 | "imgs" -> ("img_src" /. doc["pictures"]), 231 | "size" -> If[ 232 | KeyExistsQ[First@doc["pictures"], "img_size"], 233 | Total["img_size" /. doc["pictures"]], 234 | Missing 235 | ] 236 | |>; 237 | PhotosAuthor[id_] := Module[ 238 | {$now = Now, count, api, raw, data}, 239 | count = URLExecute[$PhotosAPI["AuthorCount"][<|"id" -> id|>], "RawJSON"]["data"]; 240 | api = URLExecute[$PhotosAPI["Author"][<|"id" -> id, "page" -> #|>], "RawJSON"]["data", "items"]&; 241 | raw = Flatten@Table[api[i], {i, 0, Quotient[count["all_count"] - 1, 100]}]; 242 | data = PhotosAuthorReshape /@ raw; 243 | BilibiliAlbumObject[<| 244 | "Data" -> data, 245 | "Category" -> "PhotosAuthor " <> ToString[id], 246 | "Repo" -> ToString[raw // Length] <> " of " <> ToString[count["all_count"]], 247 | "Count" -> Length@Flatten["imgs" /. data], 248 | "Size" -> Total@DeleteCases["size" /. data, Missing], 249 | "Time" -> Now - $now, 250 | "Date" -> $now 251 | |>] 252 | ]; 253 | 254 | 255 | PhotosRankReshape::usage = "内部函数, 用于数据清洗"; 256 | PhotosRankReshape[doc_Association] := <| 257 | "uid" -> doc["user", "uid"], 258 | "author" -> doc["user", "name"], 259 | "did" -> doc["item", "doc_id"], 260 | "title" -> If[doc["item", "title"] != "", 261 | doc["item", "title"], 262 | "无名_" <> ToString[doc["item", "doc_id"]] 263 | ], 264 | "time" -> FromUnixTime[doc["item", "upload_time"]], 265 | "imgs" -> ("img_src" /. doc["item", "pictures"]), 266 | "size" -> If[KeyExistsQ[First@doc["item", "pictures"], "img_size"], 267 | Total["img_size" /. doc["item", "pictures"]], 268 | Missing 269 | ] 270 | |>; 271 | 272 | Options[PhotosRank] = {RawData -> False}; 273 | PhotosRank[typenum_, OptionsPattern[]] := Module[ 274 | {$now = Now, api, raw, data}, 275 | api = $PhotosAPI["Rank"][<|"time" -> $PhotoKeyMap[typenum]["Key"]|>]; 276 | raw = Flatten[URLExecute[#, "RawJSON"]["data", "items"]& /@ api]; 277 | If[OptionValue[RawData], Return[raw]]; 278 | data = PhotosRankReshape /@ raw; 279 | BilibiliAlbumObject[<| 280 | "Data" -> data, 281 | "Category" -> "PhotosRank" <> $PhotoKeyMap[typenum]["Alias"], 282 | "Repo" -> "150 of 150", 283 | "Count" -> Length@Flatten["imgs" /. data], 284 | "Size" -> Total@DeleteCases["size" /. data, Missing], 285 | "Time" -> Now - $now, 286 | "Date" -> $now 287 | |>] 288 | ]; 289 | 290 | SetAttributes[ 291 | {}, 292 | {Protected, ReadProtected} 293 | ]; 294 | End[] 295 | -------------------------------------------------------------------------------- /Packages/BilibiliUI.m: -------------------------------------------------------------------------------- 1 | PhotosHelp::usage = "xxx"; 2 | BilibiliLink`ㄑUI::usage = ""; 3 | BilibiliLink`ㄑUI[___] := ""; 4 | Begin["`UI`"]; 5 | 6 | 7 | 8 | BLine[length_] := Panel["", Appearance -> Image[ 9 | RawArray["UnsignedInteger8", { 10 | {{0, 0, 0, 0}, {0, 0, 0, 255}, {0, 0, 0, 0}}, 11 | {{0, 0, 0, 0}, {255, 255, 255, 255}, {0, 0, 0, 255}}, 12 | {{0, 0, 0, 255}, {250, 250, 250, 255}, {0, 0, 0, 255}}, 13 | {{0, 0, 0, 255}, {249, 249, 249, 255}, {0, 0, 0, 255}}, 14 | {{0, 0, 0, 255}, {249, 249, 249, 255}, {0, 0, 0, 255}}, 15 | {{0, 0, 0, 255}, {249, 249, 249, 255}, {0, 0, 0, 255}}, 16 | {{0, 0, 0, 255}, {248, 248, 248, 255}, {0, 0, 0, 255}}, 17 | {{0, 0, 0, 255}, {248, 248, 248, 255}, {0, 0, 0, 255}}, 18 | {{0, 0, 0, 255}, {247, 247, 247, 255}, {0, 0, 0, 255}}, 19 | {{0, 0, 0, 255}, {246, 246, 246, 255}, {0, 0, 0, 255}}, 20 | {{0, 0, 0, 255}, {246, 246, 246, 255}, {0, 0, 0, 255}}, 21 | {{0, 0, 0, 255}, {245, 245, 245, 255}, {0, 0, 0, 255}}, 22 | {{0, 0, 0, 255}, {245, 245, 245, 255}, {0, 0, 0, 255}}, 23 | {{0, 0, 0, 255}, {244, 244, 244, 255}, {0, 0, 0, 255}}, 24 | {{0, 0, 0, 255}, {243, 243, 243, 255}, {0, 0, 0, 255}}, 25 | {{0, 0, 0, 255}, {243, 243, 243, 255}, {0, 0, 0, 255}}, 26 | {{0, 0, 0, 255}, {242, 242, 242, 255}, {0, 0, 0, 255}}, 27 | {{0, 0, 0, 255}, {241, 241, 241, 255}, {0, 0, 0, 255}}, 28 | {{0, 0, 0, 255}, {241, 241, 241, 255}, {0, 0, 0, 255}}, 29 | {{0, 0, 0, 255}, {240, 240, 240, 255}, {0, 0, 0, 255}}, 30 | {{0, 0, 0, 255}, {239, 239, 239, 255}, {0, 0, 0, 255}}, 31 | {{0, 0, 0, 255}, {239, 239, 239, 255}, {0, 0, 0, 255}}, 32 | {{0, 0, 0, 255}, {238, 238, 238, 255}, {0, 0, 0, 255}}, 33 | {{0, 0, 0, 255}, {237, 237, 237, 255}, {0, 0, 0, 255}}, 34 | {{0, 0, 0, 255}, {237, 237, 237, 255}, {0, 0, 0, 255}}, 35 | {{0, 0, 0, 255}, {236, 236, 236, 255}, {0, 0, 0, 255}}, 36 | {{0, 0, 0, 255}, {236, 236, 236, 255}, {0, 0, 0, 255}}, 37 | {{0, 0, 0, 255}, {235, 235, 235, 255}, {0, 0, 0, 255}}, 38 | {{0, 0, 0, 255}, {234, 234, 234, 255}, {0, 0, 0, 255}}, 39 | {{0, 0, 0, 255}, {234, 234, 234, 255}, {0, 0, 0, 255}}, 40 | {{0, 0, 0, 255}, {233, 233, 233, 255}, {0, 0, 0, 255}}, 41 | {{0, 0, 0, 255}, {233, 233, 233, 255}, {0, 0, 0, 255}}, 42 | {{0, 0, 0, 255}, {233, 233, 233, 255}, {0, 0, 0, 255}}, 43 | {{0, 0, 0, 255}, {232, 232, 232, 255}, {0, 0, 0, 255}}, 44 | {{0, 0, 0, 0}, {179, 179, 179, 255}, {0, 0, 0, 0}}, 45 | {{0, 0, 0, 0}, {0, 0, 0, 255}, {0, 0, 0, 0}} 46 | }], "Byte", ColorSpace -> "RGB", Interleaving -> True 47 | ], ImageMargins -> 5, ImageSize -> {length, 1} 48 | ]; 49 | 50 | SetAttributes[Temp1, HoldAll]; 51 | Temp1[text_String, fun_] := {{ 52 | TextCell[text, "Text"], 53 | Row[{ 54 | Button["Copy", CopyToClipboard[Defer@fun]], 55 | Button["Run", CellPrint[ExpressionCell[fun, "Output"]]] 56 | }] 57 | }, 58 | {InputField[Defer[fun]], SpanFromLeft}, 59 | {BLine[300], SpanFromLeft} 60 | }; 61 | 62 | pHot = Grid[Most@Join[ 63 | Temp1["1.热门插画", PhotosHot[1]], 64 | Temp1["2.热门漫画", PhotosHot[2]], 65 | Temp1["3.其他画作", PhotosHot[3]], 66 | Temp1["4.全部画作", PhotosHot[4]], 67 | Temp1["5.Cosplay", PhotosHot[5]], 68 | Temp1["6.其他摄影", PhotosHot[6]], 69 | Temp1["7.全部摄影", PhotosHot[7]] 70 | ], Alignment -> {{Left, Right}}, Selectable -> False 71 | ]; 72 | pNew = Grid[Most@Join[ 73 | Temp1["1.热门插画", PhotosNew[1]], 74 | Temp1["2.热门漫画", PhotosNew[2]], 75 | Temp1["3.其他画作", PhotosNew[3]], 76 | Temp1["4.全部画作", PhotosNew[4]], 77 | Temp1["5.Cosplay", PhotosNew[5]], 78 | Temp1["6.其他摄影", PhotosNew[6]], 79 | Temp1["7.全部摄影", PhotosNew[7]] 80 | ], Alignment -> {{Left, Right}}, Selectable -> False 81 | ]; 82 | pRec = "未完成"; 83 | pSearch = "未完成"; 84 | pRank = Grid[Join[ 85 | Temp1["1.日榜/新人榜", PhotosRank[8]], 86 | Temp1["2.周榜", PhotosRank[9]], 87 | Temp1["3.月榜", PhotosRank[10]] 88 | ], Alignment -> {{Left, Right}}, Selectable -> False 89 | ]; 90 | PhotosHelp[___] := Module[ 91 | { 92 | tb = Text /@ {"最新", "热门", "推荐", "排行", "搜索"}, 93 | st = {pNew, pHot, pRec, pRank, pSearch} 94 | }, 95 | TabView[Thread[tb -> st], ControlPlacement -> Left, Alignment -> Left, AutoAction -> True] 96 | ]; 97 | 98 | 99 | 100 | SetAttributes[ 101 | {}, 102 | {Protected, ReadProtected} 103 | ]; 104 | End[] 105 | -------------------------------------------------------------------------------- /Packages/BilibiliVideoSection.m: -------------------------------------------------------------------------------- 1 | (* ::Package:: *) 2 | (* ::Title:: *) 3 | (*Example(样板包)*) 4 | (* ::Subchapter:: *) 5 | (*程序包介绍*) 6 | (* ::Text:: *) 7 | (*Mathematica Package*) 8 | (*Created by Mathematica Plugin for IntelliJ IDEA*) 9 | (*Establish from GalAster's template*) 10 | (**) 11 | (* ::Text:: *) 12 | (*Author:我是作者*) 13 | (*Creation Date:我是创建日期*) 14 | (*Copyright: Mozilla Public License Version 2.0*) 15 | (* ::Program:: *) 16 | (*1.软件产品再发布时包含一份原始许可声明和版权声明。*) 17 | (*2.提供快速的专利授权。*) 18 | (*3.不得使用其原始商标。*) 19 | (*4.如果修改了源代码,包含一份代码修改说明。*) 20 | (**) 21 | (* ::Section:: *) 22 | (*函数说明*) 23 | VideoSectionQ::usage = ""; 24 | VideoSection::usage = ""; 25 | VideoIDsRange::usage = "遍历所有ID"; 26 | VideoIDsList::usage = "遍历指定ID"; 27 | VideoIDsPack::usage = "打包缓存"; 28 | VideoIDsInsertDB::usage = "插入数据库"; 29 | TagInfo::usage = "TagInfo[id] 获取tag详细信息"; 30 | (* ::Section:: *) 31 | (*程序包正体*) 32 | (* ::Subsection::Closed:: *) 33 | (*主设置*) 34 | BilibiliLink`ㄑVideo::usage = ""; 35 | BilibiliLink`ㄑVideo[___] := ""; 36 | Begin["`Video`"]; 37 | (* ::Subsection:: *) 38 | (*功能块 2*) 39 | timeLeft[start_, frac_] := With[{past = AbsoluteTime[] - start}, If[frac == 0 || past < 1, "-", Floor[past / frac - past]]]; 40 | (* ::Subsection:: *) 41 | (*功能块 2*) 42 | VideoSectionQ = MemberQ[$APIs["RidList"] // Keys // Rest, #]&; 43 | VideoSection[id_Integer] := Module[ 44 | {get = URLExecute[$APIs["VideoSection"][id], "RawJson"]}, 45 | If[!VideoSectionQ[id], Echo[Text@"编号不存在!", "Warning: "];Return@$Failed]; 46 | BilibiliVideoSectionObject[<| 47 | "Me" -> $APIs["RidList"][id], 48 | "Parent" -> $APIs["RidList"][$APIs["RidList"][id, "parent"]], 49 | "Count" -> get["data", "page", "count"], 50 | "Date" -> Now 51 | |>] 52 | ]; 53 | 54 | 55 | 56 | (* ::Subsection:: *) 57 | (*功能块 2*) 58 | Options[DownloadIDsRange] = { 59 | "Path" -> FileNameJoin[{$BilibiliLinkData, "VideoDataRaw"}], 60 | "Overwrite" -> False, 61 | "Format" -> "WXF", 62 | "LimitTime" -> 10 63 | }; 64 | DownloadIDsRange[ps_, OptionsPattern[]] := Block[ 65 | {file, do, data, fail}, 66 | file = FileNameJoin[{OptionValue["Path"], 67 | StringRiffle[{100(First@ps - 1) + 1, 100Last[ps]}, "-"] <> "." <> OptionValue["Format"]} 68 | ]; 69 | If[ 70 | OptionValue["Overwrite"], 71 | If[FileExistsQ@file, DeleteFile[file]], 72 | If[FileExistsQ@file, Return[Nothing]] 73 | ]; 74 | do = URLExecute[HTTPRequest["https://api.bilibili.com/x/article/archives?ids=" <> 75 | StringRiffle[Range[100(# - 1) + 1, 100#], ","], TimeConstraint -> OptionValue["LimitTime"] 76 | ], "RawJson"]["data"]&; 77 | {data, fail} = Quiet@Reap@Flatten[List @@@ Map[Check[do[#], Sow[#]]&, ps]]; 78 | Export[file, Flatten[data], PerformanceGoal -> "Size"]; 79 | Return[fail] 80 | ]; 81 | VideoMaxID[] := Module[ 82 | {get, case}, 83 | get = URLExecute["http://www.jijidown.com/new/video", {"HTML", "XMLObject"}]; 84 | case = Cases[get, XMLElement["img", {__, "src" -> u_, __}, __] :> u, Infinity]; 85 | Max@StringCases[case, "av=" ~~ id__ ~~ "&url" :> ToExpression[id]] 86 | ]; 87 | Options[VideoIDsRange] = { 88 | "Path" -> Automatic, 89 | "LimitTime" -> 4, 90 | "Overwrite" -> False, 91 | "Format" -> "WXF", 92 | "BlockSize" -> 10000, 93 | "Min" -> 1 94 | }; 95 | VideoIDsRange[max_Integer : 0, OptionsPattern[]] := Module[ 96 | {m, path, do, r, funs, fail, log}, 97 | m = If[max == 0, VideoMaxID[], max]; 98 | path = If[OptionValue["Path"] === Automatic, 99 | FileNameJoin[{$BilibiliLinkData, "VideoData", 100 | DateString[{"Year", "Month", "Day", "Hour", "Minute", "Second"}] 101 | }], 102 | OptionValue["Path"] 103 | ]; 104 | If[!FileExistsQ@path, CreateDirectory[path]]; 105 | do = Inactive[DownloadIDsRange][#, 106 | "Path" -> path, 107 | "Overwrite" -> OptionValue["Overwrite"], 108 | "Format" -> OptionValue["Format"], 109 | "LimitTime" -> OptionValue["LimitTime"] 110 | ]&; 111 | r = Range[Ceiling[OptionValue["Min"] / 100], Ceiling[m / 100]]; 112 | funs = do /@ Partition[r, UpTo[Ceiling[OptionValue["BlockSize"] / 100]]]; 113 | fail = AbortableMap[Activate, funs]; 114 | log = FileNameJoin[{path, DateString[{"Year", "Month", "Day", "-", "Hour", "Minute", "Second"}] <> ".log.m"}]; 115 | Export[log, <| 116 | "Date" -> Now, 117 | "FailedIDs" -> Flatten[fail[[-2, All, 2]]], 118 | "RetryFunction" -> "BilibiliLink`Video`DownloadIDsRange[...]" 119 | |>] 120 | ]; 121 | DistributeDefinitions[VideoIDsRange]; 122 | (* ::Subsection:: *) 123 | (*功能块 2*) 124 | Options[DownloadIDsList] = { 125 | "Path" -> FileNameJoin[{$BilibiliLinkData, "VideoDataRaw"}], 126 | "Overwrite" -> False, 127 | "Format" -> "WXF", 128 | "LimitTime" -> 10 129 | }; 130 | DownloadIDsList[ls_, OptionsPattern[]] := Block[ 131 | {file, group, do, data, fail}, 132 | file = FileNameJoin[{OptionValue["Path"], Hash[ls, "MD5", "HexString"] <> "." <> OptionValue["Format"]}]; 133 | If[ 134 | OptionValue["Overwrite"], 135 | If[FileExistsQ@file, DeleteFile[file]], 136 | If[FileExistsQ@file, Return[Nothing]] 137 | ]; 138 | group = Partition[ls, UpTo[100]]; 139 | do = URLExecute[HTTPRequest["https://api.bilibili.com/x/article/archives?ids=" <> 140 | StringRiffle[#, ","], TimeConstraint -> OptionValue["LimitTime"] 141 | ], "RawJson"]["data"]&; 142 | {data, fail} = Quiet@Reap@Flatten[List @@@ Map[Check[do[#], Sow[#]]&, group]]; 143 | Export[file, Flatten[data], PerformanceGoal -> "Size"]; 144 | Return[fail] 145 | ]; 146 | Options[VideoIDsList] = { 147 | "Path" -> Automatic, 148 | "LimitTime" -> 4, 149 | "Overwrite" -> False, 150 | "Format" -> "WXF", 151 | "BlockSize" -> 10000 152 | }; 153 | VideoIDsList[ls_, OptionsPattern[]] := Block[ 154 | {path, do, fail, funs, log}, 155 | path = If[OptionValue["Path"] === Automatic, 156 | FileNameJoin[{$BilibiliLinkData, "VideoData", 157 | DateString[{"Year", "Month", "Day", "Hour", "Minute", "Second"}]} 158 | ], 159 | OptionValue["Path"] 160 | ]; 161 | If[!FileExistsQ@path, CreateDirectory[path]]; 162 | do = Inactive[DownloadIDsList][#, 163 | "Path" -> path, 164 | "Overwrite" -> OptionValue["Overwrite"], 165 | "Format" -> OptionValue["Format"], 166 | "LimitTime" -> OptionValue["LimitTime"] 167 | ]&; 168 | funs = do /@ Partition[ls, UpTo[Ceiling[OptionValue["BlockSize"] / 100]]]; 169 | fail = AbortableMap[Activate, funs]; 170 | log = FileNameJoin[{path, DateString[{"Year", "Month", "Day", "-", "Hour", "Minute", "Second"}] <> ".log.m"}]; 171 | Export[log, <| 172 | "Date" -> Now; 173 | "FailedIDs" -> Flatten[fail] 174 | |>] 175 | ]; 176 | DistributeDefinitions[VideoIDsList]; 177 | 178 | 179 | 180 | (* ::Subsection:: *) 181 | (*功能块 2*) 182 | VideoIdsFormat[asc_] := <| 183 | "VideoID" -> asc["aid"], 184 | "Title" -> asc["title"], 185 | "Date" -> FromUnixTime[asc["pubdate"]], 186 | "Length" -> asc["duration"], 187 | "Pages" -> asc["videos"], 188 | "Region" -> asc["tid"], 189 | "CID" -> asc["cid"], 190 | "OwnerID" -> asc["owner", "mid"], 191 | "OwnerName" -> asc["owner", "name"], 192 | "View" -> asc["stat", "view"], 193 | "Favorite" -> asc["stat", "favorite"], 194 | "Coin" -> asc["stat", "coin"], 195 | "Share" -> asc["stat", "share"], 196 | "Like" -> asc["stat", "like"], 197 | "Dislike" -> asc["stat", "dislike"], 198 | "Comment" -> asc["stat", "reply"], 199 | "HighestRank" -> asc["stat", "his_rank"] 200 | |>; 201 | (* ::Subsection:: *) 202 | (*功能块 2*) 203 | Options[VideoIDsPack] = { 204 | "Pack" -> 1000, 205 | "Path" -> FileNameJoin[{$BilibiliLinkData, "VideoDataRaw"}], 206 | "Format" -> "WXF" 207 | }; 208 | VideoIDsPack[fs_List, {num_ : 0}, OptionsPattern[]] := Block[ 209 | {data, file, fmt}, 210 | file = FileNameJoin[{OptionValue["Path"], "Block_" <> ToString[num] <> ".WXF"}]; 211 | If[FileExistsQ@file, Return[Nothing]]; 212 | data = Select[Flatten[Import /@ fs], AssociationQ]; 213 | fmt = SortBy[VideoIdsFormat /@ data, #["VideoID"]&] /. {Missing[__] :> ""}; 214 | Export[file, Dataset@fmt, PerformanceGoal -> "Size"]; 215 | Length@fmt 216 | ]; 217 | VideoIDsPack[dir_String, ops : OptionsPattern[]] := Block[ 218 | {all}, 219 | If[!DirectoryQ[OptionValue["Path"]], VideoIDsPack[{dir}]]; 220 | If[!FileExistsQ[OptionValue["Path"]], CreateDirectory[OptionValue["Path"]]]; 221 | all = SortBy[FileNames[{"*.WXF", "*.Json"}, dir], ToExpression[StringSplit[#, {"\\", "-"}][[-2]]]&]; 222 | MapIndexed[AbsoluteTiming@VideoIDsPack[#, ops]&, Partition[all, UpTo[OptionValue["Pack"]]]] 223 | ]; 224 | 225 | 226 | (* ::Subsection:: *) 227 | (*功能块 2*) 228 | VideoIDsInsertPack[fs_, co_] := Block[ 229 | {in = Select[Flatten[Import /@ fs], AssociationQ]}, 230 | MongoLink`MongoCollectionInsert[co, Map[VideoIdsFormat, in] /. Missing[__] :> ""]; 231 | Length[in] 232 | ] // AbsoluteTiming; 233 | Options[VideoIDsInsertDB] = {"BatchSize" -> 1}; 234 | VideoIDsInsertDB[dir_String, db_, OptionsPattern[]] := Block[ 235 | {client, all, pt, tasks, ans, i = 0, j = 0, now = Now}, 236 | all = SortBy[FileNames[{"*.WXF", "*.Json"}, dir], ToExpression[StringSplit[#, {"\\", "-"}][[-2]]]&]; 237 | pt = Partition[all, UpTo[OptionValue["BatchSize"]]]; 238 | ans = With[ 239 | {table = MongoLink`MongoGetCollection[db, StringJoin["VideoData_", 240 | DateString[{"Year", "Month", "Day", "Hour", "Minute", "Second"}] 241 | ]]}, 242 | Monitor[Map[ 243 | Reap[Check[i++;VideoIDsInsertPack[#, table], j++; Sow[#]] 244 | ]& , pt], 245 | Grid[{ 246 | {Text[Style["Transforming :", Darker@Blue]], ProgressIndicator[i, {0, Length[pt]}]}, 247 | { 248 | Text[Style["Error Cases : ", Darker@Red]], 249 | StringJoin[ToString /@ {j, " --- Time Left: ", timeLeft[AbsoluteTime[now], (i + j ) / Length[pt]]}] 250 | } 251 | }, 252 | Alignment -> Left, 253 | Dividers -> Center 254 | ] 255 | ] 256 | ]; 257 | Echo[Quantity[Total[ans[[All, 1, 2]]] / Total[ans[[All, 1, 1]]], "Kilobytes" / "Seconds"], "Speed: "]; 258 | <|"Failed" -> Flatten[ans[[All, -1]]]|> 259 | ]; 260 | 261 | 262 | 263 | 264 | 265 | 266 | 267 | 268 | 269 | 270 | 271 | 272 | 273 | 274 | 275 | 276 | TagInfoFormat[asc_] := <| 277 | "ID" -> asc["tag_id"], 278 | "Name" -> asc["tag_name"], 279 | "Detail" -> asc["content"], 280 | "Date" -> FromUnixTime[asc["ctime"]], 281 | "Count" -> asc["count", "use"], 282 | "Watch" -> asc["count", "atten"] 283 | |>; 284 | (* 285 | 屏蔽字段 286 | - tag 图标 "Icon"->asc["cover"] 287 | - type, 意义不明 288 | *) 289 | TagInfo[id_] := TagInfoFormat[URLExecute["https://api.bilibili.com/x/tag/info?tag_id=" <> ToString[id], "RawJSON"]["data"]]; 290 | 291 | 292 | 293 | 294 | 295 | 296 | 297 | 298 | 299 | 300 | 301 | 302 | (* ::Subsection::Closed:: *) 303 | (*附加设置*) 304 | SetAttributes[{TagInfo}, Listable]; 305 | SetAttributes[ 306 | { }, 307 | {Protected, ReadProtected} 308 | ]; 309 | End[] 310 | -------------------------------------------------------------------------------- /Packages/Crawlers/ArchiveCrawlers.nb: -------------------------------------------------------------------------------- 1 | version https://git-lfs.github.com/spec/v1 2 | oid sha256:3c479a2cd6e4355ae8458f395fbc9a065ecd72d457284b9d91b422586c494276 3 | size 48448 4 | -------------------------------------------------------------------------------- /Packages/Crawlers/TagCrawlers.nb: -------------------------------------------------------------------------------- 1 | version https://git-lfs.github.com/spec/v1 2 | oid sha256:8a18f5b8e3898318e6182e41724c7aed68913805a3e2a08613f9a051af35fe4d 3 | size 32735 4 | -------------------------------------------------------------------------------- /Packages/ObjectAlbum.m: -------------------------------------------------------------------------------- 1 | BilibiliAlbumObject::usage = "内部函数, 图片地址对象."; 2 | BilibiliLink`ㄑAlbum::usage = ""; 3 | BilibiliLink`ㄑAlbum[___] := ""; 4 | Begin["`Object`"]; 5 | (*BilibiliAlbumObject*) 6 | BilibiliAlbumObjectQ::usage = "BilibiliAlbumObject 合法性检测"; 7 | BilibiliAlbumObjectQ[asc_?AssociationQ] := AllTrue[{"Count", "Date"}, KeyExistsQ[asc, #]&]; 8 | BilibiliAlbumObjectQ[_] := False; 9 | 10 | Format[BilibiliAlbumObjectQ[___], OutputForm] := "BilibiliDownloadObject[>_<]"; 11 | Format[BilibiliAlbumObjectQ[___], InputForm] := "BilibiliDownloadObject[>_<]"; 12 | BilibiliAlbumObject /: MakeBoxes[obj : BilibiliAlbumObject[asc_?BilibiliAlbumObjectQ], form : (StandardForm | TraditionalForm)] := Module[ 13 | {above, below}, 14 | above = { 15 | {BoxForm`SummaryItem[{"Type: ", "PicturesPack"}]}, 16 | {BoxForm`SummaryItem[{"Category: ", asc["Category"]}]}, 17 | {BoxForm`SummaryItem[{"Date: ", DateString[asc["Date"]]}]}, 18 | {BoxForm`SummaryItem[{"Repo: ", asc["Repo"]}]}, 19 | {BoxForm`SummaryItem[{"Count: ", asc["Count"]}]}, 20 | {BoxForm`SummaryItem[{"Size: ", AlbumSizeConvert[asc["Size"]]}]}, 21 | {BoxForm`SummaryItem[{"Time: ", asc["Time"]}]} 22 | }; 23 | below = {}; 24 | BoxForm`ArrangeSummaryBox[ 25 | "BilibiliLink", obj, 26 | $BilibiliLinkIcons["BilibiliAlbumObject"], 27 | above, below, form, 28 | "Interpretable" -> Automatic 29 | ] 30 | ]; 31 | (*Aid Functions*) 32 | AlbumSizeConvert[x_Integer] := N@Piecewise[{ 33 | {Quantity[x, "Kilobytes"], x < 1024 / 2}, 34 | {Quantity[x / 1024, "Megabytes"], 1024^2 / 2 > x >= 1024 / 2}, 35 | {Quantity[x / 1024^2, "Gigabytes"], x >= 1024^2 / 2} 36 | }]; 37 | Options[ImageSizeConvert] = {Format -> "webp"}; 38 | ImageSizeConvert[size_, OptionsPattern[]] := Switch[ 39 | size, 40 | Tiny, "@125w_125h_1e." <> OptionValue[Format], 41 | Small, "@250w_250h_1e." <> OptionValue[Format], 42 | Normal, "@500w_500h_1e." <> OptionValue[Format], 43 | Large, "@1000w_1000h_1e." <> OptionValue[Format], 44 | RawData, "", 45 | _, size 46 | ]; 47 | MapMonitored[f_, args_List] := Module[ 48 | {x = 0}, 49 | Monitor[ 50 | MapIndexed[(x = #2[[1]];f[#1])&, args], 51 | ProgressIndicator[x / Length[args]] 52 | ] 53 | ]; 54 | 55 | 56 | 57 | 58 | (*Interface*) 59 | BilibiliAlbumObject[ass_][func_String] := Switch[ 60 | func, 61 | "d", BilibiliAlbumObject[ass]["Data"], 62 | "Data", Lookup[ass, "Data"], 63 | "i", BilibiliAlbumObject[ass]["Image"], 64 | "Image", Flatten["imgs" /. Lookup[ass, "Data"]], 65 | "m", BilibiliAlbumObject[ass]["Markdown"], 66 | "Markdown", PicturesPackMarkdownExport[ass], 67 | "do", AlbumDownload[ass]["Download"], 68 | "Download", AlbumDownload[ass], 69 | _, BilibiliAlbumObjectHelp[] 70 | ]; 71 | BilibiliAlbumObject[ass_][func_String, {para__}] := Switch[ 72 | func, 73 | "Download", AlbumDownload[ass, para], 74 | _, BilibiliAlbumObjectHelp[] 75 | ]; 76 | BilibiliAlbumObject[ass_][___] := BilibiliAlbumObjectHelp[]; 77 | 78 | 79 | (*Method*) 80 | PicturesPackMarkdownExport[ass_] := Block[ 81 | {text = PicturesPack2MD[Lookup[ass, "Data"]], name, file}, 82 | name = DateString[Lookup[ass, "Date"], {"Year", "-", "Month", "-", "Day", "-"}] <> ToString[Hash@text] <> ".md"; 83 | file = FileNameJoin[{$BilibiliLinkData, "Markdown", name}]; 84 | If[FileExistsQ[file], Return[file], CreateFile[file]]; 85 | Export[file, text, "Text"] 86 | ]; 87 | PicturesPack2MD::usage = "将Album对象中的数据导出为Markdown格式."; 88 | PicturesPack2MD[docs_List] := StringJoin[PicturesPack2MD /@ docs]; 89 | PicturesPack2MD[doc_Association] := StringJoin@Riffle[Join[ 90 | { 91 | "### 作者: " <> doc["author"], 92 | "### 主页: " <> "https://space.bilibili.com/" <> ToString[doc["uid"]] <> "/#/album", 93 | "### 标题: " <> doc["title"], 94 | "### 日期: " <> DateString@doc["time"], 95 | "### 链接: " <> "https://h.bilibili.com/" <> ToString[doc["did"]] 96 | }, 97 | "![](" <> # <> ")"& /@ doc["imgs"], 98 | {"\r---\r\r"} 99 | ], "\r"]; 100 | 101 | Options[AlbumCollage] = { 102 | Max -> 25, 103 | ItemSize -> Small, 104 | ImageSize -> Automatic, 105 | AspectRatio -> GoldenRatio 106 | }; 107 | AlbumCollage[ass_, OptionsPattern[]] := Module[ 108 | {imgs, get, fliter, $now = Now, ar = OptionValue[AspectRatio]}, 109 | imgs = RandomSample[Flatten["imgs" /. ass["Data"]], UpTo[OptionValue[Max]]]; 110 | get = MapMonitored[URLExecute[# <> ImageSizeConvert[OptionValue[ItemSize]]]&, imgs]; 111 | fliter = Select[get, 1 / ar < ImageAspectRatio[#] < ar&]; 112 | Echo[Now - $now, "Time Used:"]; 113 | ImageCollage[fliter, Background -> Transparent, Method -> "Rows", ImageSize -> OptionValue[ImageSize]] 114 | ]; 115 | Options[AlbumDownload] = { 116 | ImageSize -> RawData, 117 | Format -> "webp", 118 | Path -> FileNameJoin[{$BilibiliLinkData, "Image", ass["Category"]}] 119 | }; 120 | AlbumDownload[ass_, OptionsPattern[]] := Module[ 121 | {data}, 122 | data = Function[doc, 123 | <|"Name" -> Last@StringSplit[#, "/"], "URL" -> #|>& /@ 124 | (# <> ImageSizeConvert[OptionValue[ImageSize], Format -> OptionValue[Format]]& /@ doc["imgs"]) 125 | ][Flatten[reshape /@ ass["Data"]]]; 126 | BilibiliDownloadObject[<| 127 | "Date" -> ass["Date"], 128 | "Category" -> ass["Category"], 129 | "Data" -> data, 130 | "Path" -> OptionValue[Path], 131 | "Size" -> ass["Size"] 132 | |>] 133 | ]; 134 | 135 | 136 | 137 | SetAttributes[ 138 | {}, 139 | {Protected, ReadProtected} 140 | ]; 141 | End[] 142 | -------------------------------------------------------------------------------- /Packages/ObjectDownload.m: -------------------------------------------------------------------------------- 1 | BilibiliDownload::usage = ""; 2 | BilibiliDownloadObject::usage = ToString[Column[{ 3 | Row[{"初始化下载对象, ",Style["obj = BilibiliLink[...,Type->DownloadObject]",Blue]}], 4 | Row[{Style["\t快速下载: ",Bold],"obj@\"do\""}], 5 | Row[{Style["\t转换为md格式: ",Bold],"obj@\"m\""}], 6 | Row[{Style["\t提取原始数据: ",Bold],"obj@\"d\""}], 7 | Row[{Style["完整指令: ",Red,Bold],"简令: 指令 - 函数"}], 8 | "\td: Data", 9 | "\tm: MarkDown", 10 | "\tdo: Download - BilibiliDownload" 11 | }],StandardForm]; 12 | BilibiliLink`ㄑDownload::usage = ""; 13 | BilibiliLink`ㄑDownload[___] := ""; 14 | Begin["`Object`"]; 15 | BilibiliDownloadObjectQ::usage = "BilibiliDownloadObject 合法性检测"; 16 | BilibiliDownloadObjectQ[asc_?AssociationQ] := AllTrue[{"Path", "Data"}, KeyExistsQ[asc, #]&]; 17 | BilibiliDownloadObjectQ[_] := False; 18 | Format[BilibiliDownloadObject[___], OutputForm] := "BilibiliDownloadObject[<>]"; 19 | Format[BilibiliDownloadObject[___], InputForm] := "BilibiliDownloadObject[<>]"; 20 | BilibiliDownloadObject /: MakeBoxes[obj : BilibiliDownloadObject[asc_?BilibiliDownloadObjectQ], form : (StandardForm | TraditionalForm)] := Module[ 21 | {above, below}, 22 | above = { 23 | {BoxForm`SummaryItem[{"Type: ", "DownloadObject"}]}, 24 | {BoxForm`SummaryItem[{"Category: ", asc["Category"]}]}, 25 | {BoxForm`SummaryItem[{"Count: ", Length@asc["Data"]}]}, 26 | {BoxForm`SummaryItem[{"Size: ", DownloadSizeConvert[asc["Size"]]}]} 27 | }; 28 | below = { 29 | {BoxForm`SummaryItem[{"Date: ", DateString[asc["Date"]]}]}, 30 | {BoxForm`SummaryItem[{"Path: ", File[asc["Path"]]}]} 31 | }; 32 | BoxForm`ArrangeSummaryBox[ 33 | "BilibiliLink", obj, 34 | $BilibiliLinkIcons["BilibiliDownloadObject"], 35 | above, below, form, 36 | "Interpretable" -> Automatic 37 | ] 38 | ]; 39 | 40 | (*Aid Functions*) 41 | DownloadSizeConvert[x_] := N@Piecewise[{ 42 | {Quantity[x / 1024^0, "Bytes"], x < 1024 / 2}, 43 | {Quantity[x / 1024^1, "Kilobytes"], 1024^2 / 2 > x >= 1024^1 / 2}, 44 | {Quantity[x / 1024^2, "Megabytes"], 1024^3 / 2 > x >= 1024^2 / 2}, 45 | {Quantity[x / 1024^3, "Gigabytes"], x >= 1024^3 / 2} 46 | }]; 47 | 48 | 49 | BilibiliDownloadObject[ass_][func_String] := Switch[ 50 | func, 51 | "do", BilibiliDownload[ass], 52 | "Download", BilibiliDownload[ass], 53 | "d", Dataset[ass["Data"]], 54 | "Data", Dataset[ass["Data"]], 55 | _, Information[BilibiliDownloadObject] 56 | ]; 57 | BilibiliDownloadObject[ass_][func_String, {para__}] := Switch[ 58 | func, 59 | "Download", BilibiliDownload[ass, para], 60 | _, Information[BilibiliDownloadObject] 61 | ]; 62 | BilibiliDownloadObject[ass_][___] := BilibiliDownloadHelp[]; 63 | 64 | BilibiliDownload[BilibiliDownloadObject[ass_]] := BilibiliDownload[ass]; 65 | 66 | 67 | Options[BilibiliDownloadLine] = {Path -> $TemporaryDirectory, Method -> URLDownloadSubmit}; 68 | BilibiliDownloadLine[line_, OptionsPattern[]] := Block[ 69 | {path = OptionValue[Path], file}, 70 | file = FileNameJoin[{path, line["Name"] <> "." <> Last@StringSplit[line["URL"], "."]}]; 71 | If[FileExistsQ@file, Return[]]; 72 | OptionValue[Method][line["URL"], file] 73 | ]; 74 | Options[BilibiliDownload] = { 75 | Path -> Automatic, 76 | Method -> URLDownloadSubmit, 77 | Return -> True 78 | }; 79 | BilibiliDownload[ass_, OptionsPattern[]] := Block[ 80 | {data = ass["Data"], path}, 81 | path = If[OptionValue[Path] == Automatic, ass["Path"], OptionValue[Path]]; 82 | If[!FileExistsQ[path], CreateDirectory[path]]; 83 | BilibiliDownloadLine[#, Path -> path, Method -> OptionValue[Method]]& /@ data; 84 | If[OptionValue[Return], Return[ass["Path"]]]; 85 | ]; 86 | 87 | 88 | SetAttributes[ 89 | {}, 90 | {Protected, ReadProtected} 91 | ]; 92 | End[] 93 | -------------------------------------------------------------------------------- /Packages/ObjectVideoSection.m: -------------------------------------------------------------------------------- 1 | BilibiliVideoSectionObject::usage = ""; 2 | BilibiliLink`ㄑVideoSectionObject::usage = ""; 3 | BilibiliLink`ㄑVideoSectionObject[___] := ""; 4 | Begin["`Object`"]; 5 | BilibiliVideoSectionObjectQ::usage = "BilibiliVideoSectionObject 合法性检测"; 6 | BilibiliVideoSectionObjectQ[asc_?AssociationQ] := AllTrue[{"Me", "Parent", "Count", "Date"}, KeyExistsQ[asc, #]&]; 7 | BilibiliVideoSectionObjectQ[_] = False; 8 | Format[BilibiliVideoSectionObject[___], OutputForm] := "BilibiliVideoSectionObject[<>]"; 9 | Format[BilibiliVideoSectionObject[___], InputForm] := "BilibiliVideoSectionObject[<>]"; 10 | BilibiliVideoSectionObject /: MakeBoxes[obj : BilibiliVideoSectionObject[asc_?BilibiliVideoSectionObjectQ], form : (StandardForm | TraditionalForm)] := Module[ 11 | {above, below}, 12 | above = { 13 | {BoxForm`SummaryItem[{"Type: ", "VideoSection"}]}, 14 | {BoxForm`SummaryItem[{"Section: ", asc["Me"]["name"]}]}, 15 | {BoxForm`SummaryItem[{"Link: ", Hyperlink[StringSplit[#["url"], {"/", "."}][[-2]], #["url"]]&[asc["Me"]]}]} 16 | }; 17 | below = { 18 | {BoxForm`SummaryItem[{"Count: ", asc["Count"]}]}, 19 | {BoxForm`SummaryItem[{"Parent: ", Hyperlink[#["name"], #["url"]]&[asc["Parent"]]}]}, 20 | {BoxForm`SummaryItem[{"Date: ", DateString[asc["Date"]]}]} 21 | }; 22 | BoxForm`ArrangeSummaryBox[ 23 | "BilibiliLink", 24 | obj, 25 | $BilibiliLinkIcons["BilibiliVideoSectionObject"], 26 | above, 27 | below, 28 | form, 29 | "Interpretable" -> Automatic] 30 | ]; 31 | SetAttributes[ 32 | {BilibiliVideoSectionObject}, 33 | {Protected, ReadProtected} 34 | ]; 35 | End[]; 36 | -------------------------------------------------------------------------------- /Packages/__Dev/!BilibiliColumns.m: -------------------------------------------------------------------------------- 1 | BilibiliArticle::usage = "将HTML转化为Markdown格式."; 2 | (* ::Section:: *) 3 | (*程序包正体*) 4 | Begin["`Columns`"]; 5 | (* ::Subsection::Closed:: *) 6 | (*主体代码*) 7 | (* ::Subsubsection:: *) 8 | (*下载并转化专栏*) 9 | Options[BilibiliArticle] = {Debug -> False}; 10 | BilibiliArticle[cv_, OptionsPattern[]] := Block[ 11 | { 12 | xml, pre, body, 13 | raw = Import["https://www.bilibili.com/read/cv" <> ToString@cv, {"HTML", "XMLObject"}] 14 | }, 15 | xml = Flatten@Cases[raw, XMLElement["div", {"class" -> "article-holder"}, t___] :> t, Infinity, 1]; 16 | pre = xml /. { 17 | XMLElement["h1", {}, {h__}] :> StringJoin["\n# ", h, "\n"], 18 | XMLElement["h2", {}, {h__}] :> StringJoin["\n## ", h, "\n"], 19 | XMLElement["h3", {}, {h__}] :> StringJoin["\n### ", h, "\n"], 20 | XMLElement["h4", {}, {h__}] :> StringJoin["\n#### ", h, "\n"], 21 | XMLElement["h5", {}, {h__}] :> StringJoin["\n##### ", h, "\n"], 22 | XMLElement["h6", {}, {h__}] :> StringJoin["\n###### ", h, "\n"], 23 | XMLElement["strong", {}, {b_}] :> StringJoin["**", b, "**"], (*粗体标识*) 24 | XMLElement["div", ___, {text___}] :> text, 25 | XMLElement["figure", err___] :> Nothing, (*错误解析, 直接删除*) 26 | XMLElement["figcaption", err___] :> Nothing, (*错误解析, 直接删除*) 27 | XMLElement["img", {"data-src" -> img_, __}, {}] :> StringJoin["![](", img, ")"], 28 | XMLElement["img", {"class" -> _, "data-src" -> img_}, {}] :> StringJoin["![](", img, ")"], 29 | XMLElement["img", {"class" -> "video-card nomal", "data-src" -> img_, __, "aid" -> aid_, __}, {}] :> StringTemplate[ 30 | "[![](`img`)](www.bilibili.com/blackboard/player.html?aid=`aid`)" 31 | ][<|"img" -> img, "aid" -> aid|>], 32 | XMLElement["hr", ___] :> "\n---\n" 33 | }; 34 | body = pre /. { 35 | XMLElement["p", {}, {para___}] :> StringJoin["\n", para, "\n"], (*段落标识*) 36 | XMLElement["blockquote", {}, q_] :> StringJoin@Riffle[q, "> ", {1, -1, 3}], 37 | XMLElement["ul", {}, {ul__}] :> StringJoin["\n", ul, "\n"], 38 | XMLElement["li", {}, {li__}] :> StringJoin["> ", li, "\n"] 39 | }; 40 | If[OptionValue[Debug], Return[body], StringJoin[ToString /@ body]] 41 | ]; 42 | (*(*读入预处理*) 43 | text=URLExecute["https://www.bilibili.com/read/cv423670","Text",CharacterEncoding->"UTF8"]; 44 | raw=ImportString[StringReplace[text,Thread[{"span","br"}->"div"]],{"HTML","XMLObject"}]; 45 | *) 46 | (*(*span替换*) 47 | $ColorMapArticle=<| 48 | "color-blue-01"\[Rule]"#56c1fe","color-lblue-01"\[Rule]"#73fdea","color-green-01"\[Rule]"#89fa4e","color-yellow-01"\[Rule]"#fff359","color-pink-01"\[Rule]"#ff968d","color-purple-01"\[Rule]"#ff8cc6","color-blue-02"\[Rule]"#02a2ff","color-lblue-02"\[Rule]"#18e7cf","color-green-02"\[Rule]"#60d837","color-yellow-02"\[Rule]"#fbe231","color-pink-02"\[Rule]"#ff654e","color-purple-02"\[Rule]"#ef5fa8","color-blue-03"\[Rule]"#0176ba","color-lblue-03"\[Rule]"#068f86","color-green-03"\[Rule]"#1db100","color-yellow-03"\[Rule]"#f8ba00","color-pink-03"\[Rule]"#ee230d","color-purple-03"\[Rule]"#cb297a","color-blue-04"\[Rule]"#004e80","color-lblue-04"\[Rule]"#017c76","color-green-04"\[Rule]"#017001","color-yellow-04"\[Rule]"#ff9201","color-pink-04"\[Rule]"#b41700","color-purple-04"\[Rule]"#99195e","color-gray-01"\[Rule]"#d6d5d5","color-gray-02"\[Rule]"#929292","color-gray-03"\[Rule]"#5f5f5f","color-default"\[Rule]"#222" 49 | |>; 50 | XMLElement["span",{"class"\[Rule]class_},{text_}]\[RuleDelayed]StringTemplate[ 51 | "`text`"][Association[ 52 | "color"\[Rule]First[StringSplit["color-pink-03 font-size-20"," "]/.\[VeryThinSpace]$ColorMapArticle]],"text"\[Rule]text 53 | ] 54 | *) 55 | 56 | (* ::Subsection::Closed:: *) 57 | (*附加设置*) 58 | SetAttributes[ 59 | {}, 60 | {Protected, ReadProtected} 61 | ]; 62 | End[] -------------------------------------------------------------------------------- /Packages/__Dev/Album.m: -------------------------------------------------------------------------------- 1 | PhotosLeaderboard::usage = "h.bilibili.com 图片作品排行榜."; 2 | 3 | 4 | BilibiliAlbumIndex::usage = ""; 5 | BilibiliAlbumIndex[] := Module[ 6 | {$now = Now, get, bg, imgs, data}, 7 | get = URLExecute[$PhotosAPI["Home"], "RawJSON"]["data"]; 8 | bg = <|"Name" -> ToString[Now // UnixTime] <> "_0", "URL" -> get["bg_img"]|>; 9 | imgs = MapIndexed[<|"Name" -> StringJoin[ToString /@ {UnixTime@Now, _, First@#2}], "URL" -> #1|>&, "img_src" /. get["items"]]; 10 | data = <| 11 | "DataType" -> "AlbumIndexPage", 12 | "ImageList" -> Prepend[imgs, bg] 13 | |>; 14 | BilibiliAlbumObject[<| 15 | "Data" -> data, 16 | "Category" -> "Album Index Page", 17 | "Repo" -> Length[get["items"]] + 1, 18 | "Count" -> Length[get["items"]] + 1, 19 | "Size" -> Total@Select["img_size" /. get["items"], IntegerQ], 20 | "Time" -> Now - $now, 21 | "Date" -> $now 22 | |>] 23 | ]; 24 | 25 | 26 | 27 | 28 | 29 | (* ::Subsection::Closed:: *) 30 | (*PhotosLeaderboard*) 31 | PictureDataRebuild::usage = "内部函数, 用于数据清洗"; 32 | PictureDataRebuild[doc_Association] := <| 33 | "uid" -> doc["user", "uid"], 34 | "author" -> doc["user", "name"], 35 | "did" -> doc["item", "doc_id"], 36 | "title" -> doc["item", "title"], 37 | "time" -> FromUnixTime[doc["item", "upload_time"]], 38 | "imgs" -> ("img_src" /. doc["item", "pictures"]), 39 | "size" -> If[KeyExistsQ[First@doc["item", "pictures"], "img_size"], 40 | Quantity[Total["img_size" /. doc["item", "pictures"]] / 1024.0, "Megabytes"], 41 | Missing 42 | ] 43 | |>; 44 | $PhotoMap = <|"Cosplay" -> "cos", "其他服饰" -> "sifu", "插画" -> "illustration", "漫画" -> "comic", "其他画作" -> "draw", "全部画作" -> "all"|>; 45 | PhotosLeaderboard[cat_] := Module[ 46 | {$now = Now, map, raw, data}, 47 | map = Switch[cat, 48 | "Cosplay", $APIs["PhotoHot"]["cos"], 49 | "其他服饰", $APIs["PhotoHot"]["sifu"], 50 | "插画作品", $APIs["PhotoHot"]["illustration"], 51 | "漫画作品", $APIs["PhotoHot"]["comic"], 52 | "其他画作", $APIs["PhotoHot"]["draw"], 53 | "全部画作", $APIs["PhotoHot"]["all"], 54 | "日榜", $APIs["PhotoRank"]["day"], 55 | "周榜", $APIs["PhotoRank"]["week"], 56 | "月榜", $APIs["PhotoRank"]["month"], 57 | _, Echo[Text@"可选参数:Cosplay,其他服饰,插画作品,漫画作品,其他画作,全部画作,日榜,周榜,月榜"];Return[$Failed] 58 | ]; 59 | raw = URLExecute[HTTPRequest[#, TimeConstraint -> 10], "RawJSON"]["data", "items"]& /@ map; 60 | data = PictureDataRebuild /@ Flatten[raw]; 61 | BilibiliPicturePackObject[<| 62 | "Data" -> data, 63 | "Category" -> Text@cat, 64 | "Repo" -> Length@data, 65 | "Count" -> Length@Flatten["imgs" /. data], 66 | "Size" -> Total@DeleteCases["size" /. data, Missing], 67 | "Time" -> Now - $now, 68 | "Date" -> $now 69 | |>] 70 | ]; 71 | 72 | AlbumDownload[raw_] := Switch[ 73 | raw["Data", "DataType"], 74 | "AlbumIndexPage", AlbumIndexPageDownload[raw] 75 | 76 | 77 | 78 | ]; 79 | 80 | 81 | Options[AlbumIndexPageDownload] = {ImageSize -> Full, Defer -> False}; 82 | AlbumIndexPageDownload[ass_, OptionsPattern[]] := Block[ 83 | {size = OptionValue[ImageSize], obj, resize}, 84 | resize = <|"Name" -> #["Name"] <> ToString[size], "URL" -> #["URL"] <> ImageSizeConvert[size]|>&; 85 | obj = BilibiliDownloadObject[<| 86 | "Date" -> ass["Date"], 87 | "Category" -> ass["Data", "DataType"], 88 | "Data" -> (resize /@ ass["Data", "ImageList"]), 89 | "Path" -> FileNameJoin[{$BilibiliLinkData, "Image", "Album", "Index"}], 90 | "Size" -> Quantity[ass["Size"] / 1024., "Megabytes"] 91 | |>]; 92 | If[OptionValue[Defer], Return[obj], obj["Download"]] 93 | ]; 94 | -------------------------------------------------------------------------------- /Packages/__Dev/BilibiliSearch.m: -------------------------------------------------------------------------------- 1 | tttttt = 1; 2 | Begin["`Search`"]; 3 | tttttt = 1; 4 | End[]; -------------------------------------------------------------------------------- /Packages/__Dev/Proxy.m: -------------------------------------------------------------------------------- 1 | (* Mathematica Package *) 2 | (* Created by Mathematica Plugin for IntelliJ IDEA *) 3 | 4 | (* :Title: Proxy *) 5 | (* :Context: Proxy` *) 6 | (* :Author: Aster *) 7 | (* :Date: 2018-07-22 *) 8 | 9 | (* :Package Version: 0.1 *) 10 | (* :Mathematica Version: *) 11 | (* :Copyright: (c) 2018 Aster *) 12 | (* :Keywords: *) 13 | (* :Discussion: *) 14 | 15 | BeginPackage["Proxy`"] 16 | (* Exported symbols added here with SymbolName::usage *) 17 | 18 | 19 | TagURL[id_] := HTTPRequest[ 20 | "http://api.bilibili.com/tags/info_description?id=" <> ToString[id], 21 | TimeConstraint -> 5 22 | ]; 23 | 24 | 25 | Begin["`Private`"] 26 | TagFormat[asc_] := <| 27 | "ID" -> asc["tag_id"], 28 | "Name" -> asc["tag_name"], 29 | "Detail" -> asc["content"], 30 | "Date" -> FromUnixTime[asc["ctime"]], 31 | "Count" -> asc["count", "use"], 32 | "Watch" -> asc["count", "atten"] 33 | |>; 34 | 35 | TagDown[i_, try_] := Block[ 36 | {get}, 37 | If[try <= 0, AppendTo[i, failure]]; 38 | get = URLExecute[HTTPRequest["http://api.bilibili.com/x/tag/info?tag_id=" <> ToString[i], TimeConstraint -> 5], "RawJSON"]; 39 | If[ 40 | Or[FailureQ@get, get["code"] != 0], 41 | AppendTo[$Tasks, Inactive[TagDown][i, try - 1]]; 42 | retry++;Return[Nothing] 43 | ]; 44 | finish++; 45 | TagFormat[get["data"]] 46 | ]; 47 | 48 | 49 | GetMemberRequest[mid_] := HTTPRequest[ 50 | "https://space.bilibili.com/ajax/member/GetInfo", 51 | <| 52 | "Method" -> "POST", 53 | "Headers" -> { 54 | "content-type" -> "application/x-www-form-urlencoded;charset=UTF-8", 55 | "user-agent" -> "Mozilla/5.0 (X11;Linux i686) AppleWebKit/534.24 (KHTML,like Gecko) Chrome/11.0.696.68 Safari/534.24", 56 | "Referer" -> "https://space.bilibili.com/" <> ToString[mid] 57 | }, 58 | "Body" -> "mid=" <> ToString[mid] <> "&csrf=" 59 | |>, 60 | TimeConstraint -> 10 61 | ]; 62 | GetReg[id_] := Quiet@Block[ 63 | {get = URLExecute[GetMemberRequest[id], "RawJSON"]}, 64 | DateString[FromUnixTime[get["data", "regtime"]], {"Year", "Month", "Day"}] -> id 65 | ] 66 | 67 | End[] (* `Private` *) 68 | 69 | EndPackage[] 70 | -------------------------------------------------------------------------------- /PacletInfo.m: -------------------------------------------------------------------------------- 1 | Paclet[ 2 | Name -> "BilibiliLink", 3 | Version -> "0.4.0", 4 | BuildNumber -> "20180715", 5 | WolframVersion -> "11.3+", 6 | Creator -> "GalAster", 7 | Description -> "", 8 | Category -> "", 9 | Loading -> Manual, 10 | Extensions -> { 11 | { 12 | "Kernel", 13 | Root -> ".", 14 | Context -> { 15 | "BilibiliLink`" 16 | } 17 | } 18 | } 19 | ] 20 | -------------------------------------------------------------------------------- /Readme.md: -------------------------------------------------------------------------------- 1 | # BilibiliLink — 乾杯 - ( ゜ᴗ ゜)つロ 2 | 3 | [![Build Status](https://travis-ci.org/Moe-Net/BilibiliLink.svg?branch=master)](https://travis-ci.org/Moe-Net/BilibiliLink) 4 | [![Mathematica](https://img.shields.io/badge/Mathematica-%3E%3D11.3-brightgreen.svg)](https://www.wolfram.com/mathematica/) 5 | [![Release Vision](https://img.shields.io/badge/release-v0.4.x-ff69b4.svg)](https://github.com/Moe-Net/BilibiliLink/releases) 6 | [![Repo Size](https://img.shields.io/github/repo-size/Moe-Net/BilibiliLink.svg)](https://github.com/Moe-Net/BilibiliLink.git) 7 | 8 | ![](https://i.loli.net/2018/05/20/5b0170b1f1494.png) 9 | 10 | BilibiliLink 提供了一系列获取B站数据的方法, 计划中的内容有, 文章下载, 文章评论下载, 画师画作下载, 评论下载, cosplay下载, 视频跟踪等等. 11 | 12 | 有什么想要的功能也可以在 github issue 中提出哦! 13 | 14 | 但并非所有页面上的东西都能获得, 有些看着是文字, 其实是图片, 那就没法抓取了. 15 | 16 | [详细文档](https://bilibililink.netlify.com/) 17 | 18 | ## Install 19 | ![](https://i.loli.net/2018/05/20/5b0170a0f01f9.png) 20 | 21 | 第一条命令安装, 第二条命令更新, 第三条命令卸载 22 | ```mma 23 | PacletInstall["BilibilliLink","Site"->"http://m.vers.site/"] 24 | PacletUpdate["BilibilliLink","Site"->"http://m.vers.site/"] 25 | PacletUninstall["BilibilliLink"] 26 | ``` 27 | 28 | 对于开发者建议使用 [手动安装](https://github.com/Moe-Net/BilibiliLink/wiki/For-Developers). 29 | 30 | ## Show Time 31 | ![](https://i.loli.net/2018/05/20/5b01707e154e2.png) 32 | 33 | ```mma 34 | << "BilibiliLink` 35 | PhotosLeaderboard["help"] 36 | link = PhotosLeaderboard["日榜"] 37 | link["Markdown"] 38 | ``` 39 | 40 | ## Todo List 41 | ![](https://i.loli.net/2018/05/20/5b01706ac512c.png) 42 | 43 | - 反正很多就是了 44 | 45 | ## Ideas 46 | ![](https://i.loli.net/2018/05/20/5b0170466d4df.png) 47 | 1. 任何创意欢迎 git pull request, 或联系知乎[酱紫君](https://www.zhihu.com/people/GalAster). 48 | 2. 任何的意见和建议, 提交 github issue 或者加QQ群1014125反馈. 49 | 50 | |知乎主页|QQ群聊| 51 | |:-:|:-:| 52 | |[知乎链接](https://www.zhihu.com/people/GalAster)|[QQ链接](https://jq.qq.com/?_wv=1027&k=5BqFya1) 53 | 54 | - Copyrights of all pictures belong to **©bilibili.com** 55 | - License of this project under **@Mozilla Public License Version 2.0** 56 | -------------------------------------------------------------------------------- /Resources/ico/BilibiliAlbumObject.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ai4waifu/BilibiliLink/d5ad6bf72d56d112fd71c7b5a752fb01bb3c0b8d/Resources/ico/BilibiliAlbumObject.jpg -------------------------------------------------------------------------------- /Resources/ico/BilibiliDownloadObject.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ai4waifu/BilibiliLink/d5ad6bf72d56d112fd71c7b5a752fb01bb3c0b8d/Resources/ico/BilibiliDownloadObject.png -------------------------------------------------------------------------------- /Resources/ico/BilibiliVideoSectionObject.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ai4waifu/BilibiliLink/d5ad6bf72d56d112fd71c7b5a752fb01bb3c0b8d/Resources/ico/BilibiliVideoSectionObject.png -------------------------------------------------------------------------------- /Resources/ico/Readme.md: -------------------------------------------------------------------------------- 1 | ## 创始四图 2 | ![](https://i.loli.net/2018/05/12/5af6f45da50ab.jpg) 3 | 4 | Bilibili.us第一年用的四张壁纸, 我认为是本人考古的最高成就. 5 | 6 | ```mma 7 | { 8 | "http://i0.hdslb.com/Wallpaper/bilibili_chun.jpg", 9 | "http://i0.hdslb.com/Wallpaper/summer2_2011_1920.jpg", 10 | "http://i0.hdslb.com/Wallpaper/2011-autumn.jpg", 11 | "http://i0.hdslb.com/Wallpaper/2011-dong.png" 12 | }//URLExecute//ImageCollage 13 | ``` 14 | --- 15 | 16 | ## Logos 17 | **hash:** [58c71871161412e2ad656485c9a89ecc](https://i0.hdslb.com/headers/58c71871161412e2ad656485c9a89ecc.png) 18 | ![](https://i.loli.net/2018/05/12/5af6f45d30b44.png) 19 | 20 | **hash:** [dd4053d635b32234e84ce58fb59206f3](https://i0.hdslb.com/headers/dd4053d635b32234e84ce58fb59206f3.png) 21 | ![](https://i.loli.net/2018/05/12/5af6f45d3091a.png) 22 | 23 | **hash:** [bdddec22494b50d792487028c17ece76](https://i0.hdslb.com/headers/bdddec22494b50d792487028c17ece76.png) 24 | ![](https://i.loli.net/2018/05/12/5af7053144be1.png) 25 | 26 | **hash:** [0944e505703d74c2fee96fe2bdc48d4d](https://i0.hdslb.com/headers/0944e505703d74c2fee96fe2bdc48d4d.png) 27 | ![](https://i.loli.net/2018/05/12/5af7052b04f12.png) 28 | 29 | **hash:** [5b2a8933b2ed2a46d2e12ff9f4e4bc0b2cec45bf](https://i0.hdslb.com/bfs/archive/5b2a8933b2ed2a46d2e12ff9f4e4bc0b2cec45bf.png) 30 | ![](https://i.loli.net/2018/05/12/5af7052b544d5.png) 31 | 32 | **hash:** [e07cbe482a00fef231688ece24ab459e8ff44b3f](https://i0.hdslb.com/bfs/archive/e07cbe482a00fef231688ece24ab459e8ff44b3f.png) 33 | ![](https://i.loli.net/2018/05/12/5af7052b53d33.png) 34 | 35 | **hash:** [2fc95e205a40652ddc04ca7ed8ead57324fc68cd](https://i0.hdslb.com/bfs/archive/2fc95e205a40652ddc04ca7ed8ead57324fc68cd.png) 36 | ![](https://i.loli.net/2018/05/12/5af7052b05c16.png) 37 | 38 | **hash:** [2fc95e205a40652ddc04ca7ed8ead57324fc68cd](https://i0.hdslb.com/bfs/archive/44a6c7979dfd332542c549513acabf907af06d2b.png) 39 | ![](https://i.loli.net/2018/05/12/5af7052b8faf4.png) 40 | 41 | --- 42 | 43 | 44 | 一些记载: 45 | 46 | 这个吧真是非常有趣 47 | http://dq.tieba.com/f?kw=bilibili%E7%9B%90&ie=utf-8 48 | 49 | 时光机: 50 | https://archive.li/drawyoo.hdslb.com 51 | https://archive.li/i0.hdslb.com 52 | 53 | 版头与Logo: 54 | https://www.biliplus.com/task/banner_fetch/ -------------------------------------------------------------------------------- /docs/.vuepress/config.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | dest: 'docs/.build', 3 | locales: { 4 | '/': { 5 | lang: 'zh-CN', 6 | title: 'BBLink', 7 | description: 'Bilibili Connection Established!' 8 | } 9 | }, 10 | serviceWorker: true, 11 | themeConfig: { 12 | repo: 'Moe-Net/BilibiliLink', 13 | editLinks: true, 14 | docsDir: 'docs', 15 | markdown: { 16 | lineNumbers: true 17 | }, 18 | sidebar: [ 19 | { 20 | title: '简介', 21 | children: [ 22 | '/Start/', 23 | '/Start/Design.md', 24 | '/Start/Guide.md' 25 | ] 26 | }, 27 | { 28 | title: '画友站', 29 | children: [ 30 | '/Photo/', 31 | '/Photo/Object.md' 32 | ] 33 | }, 34 | { 35 | title: '视频站', 36 | children: [ 37 | '/Video/', 38 | '/Video/Object.md' 39 | ] 40 | }, 41 | { 42 | title: '小功能', 43 | children: [ 44 | '/Toys/' 45 | ] 46 | }, 47 | { 48 | title: '全站爬虫', 49 | children: [ 50 | '/Crawler/', 51 | '/Crawler/Video.md', 52 | '/Crawler/Tag.md' 53 | 54 | ] 55 | } 56 | ] 57 | } 58 | }; 59 | -------------------------------------------------------------------------------- /docs/.vuepress/override.styl: -------------------------------------------------------------------------------- 1 | $accentColor = #3eaf7c 2 | $textColor = #2c3e50 3 | $borderColor = #eaecef 4 | $codeBgColor = #282c34 5 | // 代码库重置 6 | .content pre{ margin: 0!important;} 7 | -------------------------------------------------------------------------------- /docs/Crawler/Readme.md: -------------------------------------------------------------------------------- 1 | ## 全站爬虫简介 2 | 3 | 虽然 BBLink 本身并不是为了爬虫设计的, 而个人实际上也没有爬虫需要的大量硬盘、 内存、 时间、 代理资源. 4 | 5 | 但如果用户想获得大量的数据来研究的话, BBLink 也做得到. 6 | 7 | BBLink 可以从远程FTP服务器下载一些爬虫限制很死的信息, 同时可以自主抓取那些不是那么严格反爬的信息. 8 | 9 | ## 全站爬虫分类 10 | 11 | 12 | - AV 号遍历 13 | - UID 遍历 14 | 15 | 16 | 17 | 18 | -------------------------------------------------------------------------------- /docs/Crawler/Tag.md: -------------------------------------------------------------------------------- 1 | # Tag 抓取日志 2 | 3 | 2018年7月9日执行了一次反查爬虫 4 | 已发现的最大 tid 为 7758024 5 | 其中有效 tid 有 3752764 个 6 | 预计遗漏 15% - 20% 7 | -------------------------------------------------------------------------------- /docs/Crawler/Video.md: -------------------------------------------------------------------------------- 1 | # Video 抓取日志 2 | 3 | 全站视频爬虫依据 AV 号遍历所有视频. 4 | 5 | 当然你也可以不指定, 不指定会直接塞进 `$UserBaseDirectory`, 提醒你一下这个文件夹一般是在C盘的... 6 | 7 | 截止2018年上半年, B站视频ID总计有2600W, 其中有效ID号大约1800W. 8 | 9 | ![文件大小.png](https://i.loli.net/2018/07/15/5b4ad7fd497f9.png) 10 | 11 | CPU的内核数记为 X , 开启的内核越多速度越快, 但是相应每个内核的效率就越低 12 | 13 | 一般使用 4X 的内核, 6X 仍然能有少量提升, 但是内存占用就很高了, 8X 的话基本就得不偿失了. 14 | 15 | 一般来说要爬取一个小时左右, 速度大约是每秒 5400 条记录. 16 | 17 | 18 | 19 | ![运行时间](https://i.loli.net/2018/07/15/5b4ad7fd5112a.png) 20 | 21 | ## Database 22 | 23 | 24 | 当然这还没完, 只是下载了所有页面而已, 一般来说你得读进内存才能操作. 25 | 26 | 读取的话直接 `Import[path]` 即可, 但是问题在于全部读取需要约 20G 内存. 我想大多数人是没这么大内存了, 所以需要导入数据库. 27 | 28 | 29 | 30 | 把额外的内核全关了, 因为 mongodb 的端口就那点带宽, 线程开了好几个也是堵着. 31 | 32 | ![插入速度](https://i.loli.net/2018/07/15/5b4ad7fd51a0e.png) 33 | 34 | -------------------------------------------------------------------------------- /docs/Photo/Object.md: -------------------------------------------------------------------------------- 1 | # Object 2 | 3 | ## PhotosHelp 4 | 5 | 6 | 7 | ## PhotosObject 8 | 9 | 现在名为 `BilibiliAlbumObject` 10 | -------------------------------------------------------------------------------- /docs/Photo/Readme.md: -------------------------------------------------------------------------------- 1 | # Functions 2 | 3 | 4 | ## PhotosRange 5 | 参数: list, 从一个pid列表中获取数据. 6 | 7 | 返回: AlbumObject对象 8 | 9 | 简写: 单个整数n表示`Range[1,n]`, 两个整数n则表示`Range[a,b]` 10 | 11 | ### 选项: 12 | - RawData->False 13 | - 是否不转化为AlbumObject而返回接受到的原始数据 14 | --- 15 | ## PhotosIndex 16 | 1. 参数: 无 17 | 获得画友首页的推荐拼图 18 | 2. 返回: AlbumObject对象 19 | 20 | **无选项** 21 | 22 | ## PhotosNew 23 | - 参数: `Integer` 24 | 25 | - 返回: `BilibiliAlbumObject` 26 | 27 | - 选项 28 | - UpTo: `100` 29 | - Count: `False` 30 | - All: `False` 31 | 严重bug, 勿用 32 | - RawData `False` 33 | Debug , 不转换生成 Object, 直接返回原始读入. 34 | 35 | ## PhotosHot 36 | 37 | 38 | ## PhotosRank 39 | 40 | ## PhotosRecommend 41 | 42 | ## PhotosTag 43 | 44 | ## PhotosAuthor 45 | 46 | ## PhotosSearch 47 | 48 | ## PhotosTrace 49 | 50 | ## PhotosDetail 51 | 52 | 53 | 54 | 55 | 具体实现参考 https://github.com/Moe-Net/BilibiliLink/issues/7 56 | 57 | 58 | ### Bug 59 | 60 | ![](/Readme/20180715090728449.png) 61 | 62 | 已知错误 -------------------------------------------------------------------------------- /docs/Readme.md: -------------------------------------------------------------------------------- 1 | --- 2 | home: true 3 | actionText: Get Started → 4 | actionLink: /Start/ 5 | footer: MPL2.0 Licensed | Copyright © 2018-2018 GalAster 6 | --- 7 | 8 | ### 一键安装 9 | 10 | ```haskell 11 | PacletInstall["BilibilliLink","Site"->"http://math.owo.site/"] 12 | ``` 13 | 14 | 当然更新和卸载也是一键搞定 15 | 16 | ```haskell 17 | PacletUpdate["BilibilliLink","Site"->"http://math.owo.site/"] 18 | PacletUninstall["BilibilliLink"] 19 | ``` 20 | 21 | ::: warning 兼容性要求 22 | [![Release Vision](https://img.shields.io/badge/release-v0.3.x-ff69b4.svg)](https://github.com/Moe-Net/BilibiliLink/releases) 23 | [![Mathematica](https://img.shields.io/badge/Mathematica-%3E%3D11.3-brightgreen.svg)](https://www.wolfram.com/mathematica/) 24 | [![Mathematica](https://img.shields.io/badge/Encode-UTF8-red.svg)](https://www.wolfram.com/mathematica/) 25 | ::: 26 | -------------------------------------------------------------------------------- /docs/Start/Design.md: -------------------------------------------------------------------------------- 1 | # 设计模式 2 | 3 | ## Install 4 | 5 | 如果你是开发者, 那么按照如下方式安装, 同时卸载用户版, 以免造成干扰. 6 | 7 | 接着打开如下或任意 `$Path` 目录 8 | ```haskell 9 | PacletUninstall["BilibilliLink"] 10 | SystemOpen[FileNameJoin@{$UserBaseDirectory, "Applications"}] 11 | ``` 12 | 接着使用git下载以下, 或任意fork项目即可 13 | ```bash 14 | git clone git@github.com:Moe-Net/BilibiliLink.git --depth 1 15 | ``` 16 | 17 | 使用 `git pull` 同步, 使用`rm -rf BilibiliLink`命令删除即可卸载. 18 | 19 | ### Encoding 20 | 21 | 在开始一切之前, 请务必检查编码, 运行如下代码自动纠正编码. 22 | 23 | ```haskell 24 | If[$CharacterEncoding=!="UTF-8", 25 | $CharacterEncoding="UTF-8"; 26 | Print[{ 27 | Style["$CharacterEncoding has changed to UTF-8 to avoid problems.",Red], 28 | Style["Because BilibiliLink only works under UTF-8"] 29 | }//TableForm]; 30 | st=OpenAppend[FindFile["init.m"]]; 31 | WriteString[st,"$CharacterEncoding=\"UTF-8\";"]; 32 | Close[st]; 33 | ]; 34 | ``` 35 | 36 | 37 | --- 38 | ## Dev 39 | 40 | BBLink的核心部分就是`Package`目录, 所有**直接**在该目录下的 `*.m` 文件会被惰性加载, 也就是说 `__Feature__` 文件夹下的任何程序包都不会被默认加载, 所以一般测试功能, 过期功能都可以放里面 41 | 所有 `*.m` 文件都应该满足如下形式: 42 | ```haskell 43 | TestFunction1::usage="测试函数, 最终函数名BillibiliLink`TestFunction1."; 44 | Begin["`Test`"]; 45 | TestFunction1:="Test"; 46 | TestFunction2::usage="测试函数, 最终函数名BillibiliLink`Test`TestFunction2."; 47 | TestFunction2:="Test"; 48 | End[] 49 | ``` 50 | 也就是说所有在Begin前的声明会加载进整个包的上下文, 且能在不同的 `*.m` 文件中被共享, 在整个项目里被读取. 51 | 而Begin之后函数名则是局部的, 需要使用相对引用才能读取. 52 | 使用同名上下文惰性加载后会被识别为同一程序包, 请务必避免同名上下文里写同名函数. 53 | *** 54 | 55 | ## Test 56 | 57 | BBLink对于单个单位使用函数(Function)操作, 对于多个单位使用对象(Object)操作. 例如对于单个视频, 有一系列的函数接收vid并返回相应的返回值, 而对于多个视频则采用BilibiliVideoSectionObject对象来封装. 58 | 59 | 面对对象的部分通常名字相当长, 但是不用担心, 一般不需要手动操作那个部分, BBLink 提供了一些UI来简化操作. 60 | 61 | 首先我们加载BBLink查看所有全局函数 62 | ```haskell 63 | << "BilibiliLink`" 64 | ?? BilibiliLink`* 65 | (*?? BilibiliLink`*`**) 66 | ``` 67 | 68 | ![TIM截图20180525112728.png](https://i.loli.net/2018/05/25/5b07835647a60.png) 69 | 70 | 然后查看Help函数, 最终会有一个BilibiliHelp 函数给出一个完整的UI封装, 现在将就用这个 71 | 72 | ![TIM截图20180525112739.png](https://i.loli.net/2018/05/25/5b078355eee98.png) 73 | 74 | 点击Copy, 然后传给`obj`, 运行后`obj`就相当于是一个函数, 能够接受参数 75 | 小写开头的字符串是短码, 短码不接受额外选项. 76 | 大写开头的是长码, 那就能和正常函数一样使用了. 77 | 78 | ![TIM截图20180525112806.png](https://i.loli.net/2018/05/25/5b0783567c456.png) 79 | 80 | 我们可以看到UI是Object的整合, Object是Function的整合, 所以其实熟练以后完全可以只用Function. 81 | -------------------------------------------------------------------------------- /docs/Start/Guide.md: -------------------------------------------------------------------------------- 1 | # 文档编写指南 2 | 3 | 本文档使用 vuepress 编写 4 | 5 | 注意使用CRLF 6 | -------------------------------------------------------------------------------- /docs/Start/Readme.md: -------------------------------------------------------------------------------- 1 | # 功能展示 2 | 3 | ## 图片下载 4 | 5 | 6 | 7 | ## 页面抓取 8 | 9 | 10 | 11 | ## 数据分析 12 | -------------------------------------------------------------------------------- /docs/Toys/Readme.md: -------------------------------------------------------------------------------- 1 | # 其他图片类功能 2 | 3 | ## Logo 4 | 5 | #### `HeaderLogo[]` 6 | 7 | 文件名为哈希 8 | 9 | ![Logo.png](https://i.loli.net/2018/07/16/5b4c8b58a92ba.png) 10 | 11 | #### `HeaderBanner[path_String]` 12 | 13 | path 为上面输出的路径, 将下载的版头制成拼图. 14 | 15 | 可选项 `Path`, 指定输出目录 16 | 17 | ## Banner 18 | 19 | #### `HeaderBanner[]` 20 | 21 | 获取版头 22 | 23 | 可选项 `Path`, 指定输出目录 24 | 25 | ![Banner.png](https://i.loli.net/2018/07/16/5b4c8b5979070.png) 26 | 27 | #### `HeaderBanner[path_String]` 28 | 29 | path 为上面输出的路径, 将下载的版头制成拼图. 30 | 31 | 可选项 `Path`, 指定输出目录 32 | 33 | ## IndexIcon 34 | 35 | 36 | #### `IndexIcon[]` 37 | ![IndexIcon.png](https://i.loli.net/2018/07/16/5b4c8b587b59e.png) 38 | 39 | 40 | #### `IndexIcon["Markdown"]` 41 | 42 | 导出一个 markdown 文档 43 | 44 | ![IndexIcon.png](https://i.loli.net/2018/07/16/5b4c8b5761336.png) 45 | 46 | ## ErrorPage 47 | 48 | #### `ErrorPage[]` 49 | 50 | 51 | ## Emoji 52 | 53 | #### `VipEmoji[]` 54 | 55 | 56 | ![Emoji.png](https://i.loli.net/2018/07/16/5b4c8b597585a.png) 57 | -------------------------------------------------------------------------------- /docs/Video/CP.md: -------------------------------------------------------------------------------- 1 | 全站视频爬虫依据 AV 号遍历所有视频. 2 | 3 | 当然你也可以不指定, 不指定会直接塞进 `$UserBaseDirectory`, 提醒你一下这个文件夹一般是在C盘的... 4 | 5 | 截止2018年上半年, B站视频ID总计有2600W, 其中有效ID号大约1800W. 6 | 7 | ![文件大小.png](https://i.loli.net/2018/07/15/5b4ad7fd497f9.png) 8 | 9 | CPU的内核数记为 X , 开启的内核越多速度越快, 但是相应每个内核的效率就越低 10 | 11 | 一般使用 4X 的内核, 6X 仍然能有少量提升, 但是内存占用就很高了, 8X 的话基本就得不偿失了. 12 | 13 | 一般来说要爬取一个小时左右, 速度大约是每秒 5400 条记录. 14 | 15 | 16 | 17 | ![运行时间](https://i.loli.net/2018/07/15/5b4ad7fd5112a.png) 18 | 19 | ## Database 20 | 21 | 22 | 当然这还没完, 只是下载了所有页面而已, 一般来说你得读进内存才能操作. 23 | 24 | 读取的话直接 `Import[path]` 即可, 但是问题在于全部读取需要约 20G 内存. 我想大多数人是没这么大内存了, 所以需要导入数据库. 25 | 26 | 27 | 28 | 把额外的内核全关了, 因为 mongodb 的端口就那点带宽, 线程开了好几个也是堵着. 29 | 30 | ![插入速度](https://i.loli.net/2018/07/15/5b4ad7fd51a0e.png) 31 | 32 | -------------------------------------------------------------------------------- /docs/Video/Object.md: -------------------------------------------------------------------------------- 1 | # Object 2 | 3 | 4 | 5 | -------------------------------------------------------------------------------- /docs/Video/Readme.md: -------------------------------------------------------------------------------- 1 | # Functions 2 | 3 | 4 | ## TagInfo 5 | 6 | ### 参数 7 | 1. Integer, 代表需要查询的标签 id 8 | 2. List, 代表标签 id 列表 9 | 10 | ### 选项 11 | 无 12 | 13 | ### 返回值 14 | 15 | ```haskell 16 | <| 17 | "ID"->"tag ID 简称 tid", 18 | "Name"->"tag 的名字", 19 | "Detail"->"tag 的描述, 没有的话为空", 20 | "Date"->"tag 的创建日期", 21 | "Count"->"使用了该 tag 的视频数", 22 | "Watch"->"关注了该 tag 的人数" 23 | |> 24 | ``` 25 | 26 | 27 | ::: tip ### 压力测试 28 | 每分钟 378 次请求后被封 ip 10 分钟 29 | 30 | 建议爬取速度, 每 ip 每分钟 240 次. 31 | ::: 32 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "devDependencies": { 3 | "vuepress": "^0.10.2" 4 | }, 5 | "scripts": { 6 | "docs:dev": "vuepress dev docs", 7 | "docs:build": "vuepress build docs" 8 | }, 9 | "dependencies": { 10 | } 11 | } 12 | --------------------------------------------------------------------------------