mirror of
https://github.com/amtoaer/bili-sync.git
synced 2026-05-22 00:30:59 +08:00
26 lines
24 KiB
HTML
26 lines
24 KiB
HTML
<!DOCTYPE html>
|
||
<html lang="zh-Hans" dir="ltr">
|
||
<head>
|
||
<meta charset="utf-8">
|
||
<meta name="viewport" content="width=device-width,initial-scale=1">
|
||
<title>工作原理 | bili-sync</title>
|
||
<meta name="description" content="由 Rust & Tokio 驱动的哔哩哔哩同步工具">
|
||
<meta name="generator" content="VitePress v1.2.3">
|
||
<link rel="preload stylesheet" href="/assets/style.C1nXIPB-.css" as="style">
|
||
<script type="module" src="/assets/chunks/metadata.ae73bf22.js"></script>
|
||
<script type="module" src="/assets/app.D7044GBf.js"></script>
|
||
<link rel="preload" href="/assets/inter-roman-latin.Di8DUHzh.woff2" as="font" type="font/woff2" crossorigin="">
|
||
<link rel="modulepreload" href="/assets/chunks/framework.Bsyxd66g.js">
|
||
<link rel="modulepreload" href="/assets/chunks/theme.CXiSjCOs.js">
|
||
<link rel="modulepreload" href="/assets/design.md.90q2hBns.lean.js">
|
||
<link rel="icon" type="image/svg+xml" href="/icon.svg">
|
||
<link rel="icon" type="image/png" href="/icon.png">
|
||
<script id="check-dark-mode">(()=>{const e=localStorage.getItem("vitepress-theme-appearance")||"auto",a=window.matchMedia("(prefers-color-scheme: dark)").matches;(!e||e==="auto"?a:e==="dark")&&document.documentElement.classList.add("dark")})();</script>
|
||
<script id="check-mac-os">document.documentElement.classList.toggle("mac",/Mac|iPhone|iPod|iPad/i.test(navigator.platform));</script>
|
||
</head>
|
||
<body>
|
||
<div id="app"><div class="Layout" data-v-d8b57b2d><!--[--><!--]--><!--[--><span tabindex="-1" data-v-c8291ffa></span><a href="#VPContent" class="VPSkipLink visually-hidden" data-v-c8291ffa> Skip to content </a><!--]--><!----><header class="VPNav" data-v-d8b57b2d data-v-7ad780c2><div class="VPNavBar has-sidebar top" data-v-7ad780c2 data-v-844edcde><div class="wrapper" data-v-844edcde><div class="container" data-v-844edcde><div class="title" data-v-844edcde><div class="VPNavBarTitle has-sidebar" data-v-844edcde data-v-0ad69264><a class="title" href="/" data-v-0ad69264><!--[--><!--]--><!----><span data-v-0ad69264>bili-sync</span><!--[--><!--]--></a></div></div><div class="content" data-v-844edcde><div class="content-body" data-v-844edcde><!--[--><!--]--><div class="VPNavBarSearch search" data-v-844edcde><!--[--><!----><div id="local-search"><button type="button" class="DocSearch DocSearch-Button" aria-label="Search"><span class="DocSearch-Button-Container"><span class="vp-icon DocSearch-Search-Icon"></span><span class="DocSearch-Button-Placeholder">Search</span></span><span class="DocSearch-Button-Keys"><kbd class="DocSearch-Button-Key"></kbd><kbd class="DocSearch-Button-Key">K</kbd></span></button></div><!--]--></div><nav aria-labelledby="main-nav-aria-label" class="VPNavBarMenu menu" data-v-844edcde data-v-f732b5d0><span id="main-nav-aria-label" class="visually-hidden" data-v-f732b5d0>Main Navigation</span><!--[--><!--[--><a class="VPLink link VPNavBarMenuLink" href="/" tabindex="0" data-v-f732b5d0 data-v-08fbf4b6><!--[--><span data-v-08fbf4b6>主页</span><!--]--></a><!--]--><!--[--><div class="VPFlyout VPNavBarMenuGroup" data-v-f732b5d0 data-v-af5898d3><button type="button" class="button" aria-haspopup="true" aria-expanded="false" data-v-af5898d3><span class="text" data-v-af5898d3><!----><span data-v-af5898d3>v2.11.1</span><span class="vpi-chevron-down text-icon" data-v-af5898d3></span></span></button><div class="menu" data-v-af5898d3><div class="VPMenu" data-v-af5898d3 data-v-e42ed9b3><div class="items" data-v-e42ed9b3><!--[--><!--[--><div class="VPMenuLink" data-v-e42ed9b3 data-v-f51f088d><a class="VPLink link vp-external-link-icon" href="https://github.com/amtoaer/bili-sync/releases" target="_blank" rel="noreferrer" data-v-f51f088d><!--[-->程序更新<!--]--></a></div><!--]--><!--[--><div class="VPMenuLink" data-v-e42ed9b3 data-v-f51f088d><a class="VPLink link vp-external-link-icon" href="https://github.com/search?q=repo:amtoaer/bili-sync+docs&type=commits" target="_blank" rel="noreferrer" data-v-f51f088d><!--[-->文档更新<!--]--></a></div><!--]--><!--]--></div><!--[--><!--]--></div></div></div><!--]--><!--]--></nav><!----><div class="VPNavBarAppearance appearance" data-v-844edcde data-v-283b26e9><button class="VPSwitch VPSwitchAppearance" type="button" role="switch" title="切换到深色模式" aria-checked="false" data-v-283b26e9 data-v-7df97737 data-v-b4ccac88><span class="check" data-v-b4ccac88><span class="icon" data-v-b4ccac88><!--[--><span class="vpi-sun sun" data-v-7df97737></span><span class="vpi-moon moon" data-v-7df97737></span><!--]--></span></span></button></div><div class="VPSocialLinks VPNavBarSocialLinks social-links" data-v-844edcde data-v-ef6192dc data-v-e71e869c><!--[--><a class="VPSocialLink no-icon" href="https://github.com/amtoaer/bili-sync" aria-label="github" target="_blank" rel="noopener" data-v-e71e869c data-v-358b6670><span class="vpi-social-github" /></a><!--]--></div><div class="VPFlyout VPNavBarExtra extra" data-v-844edcde data-v-8e87c032 data-v-af5898d3><button type="button" class="button" aria-haspopup="true" aria-expanded="false" aria-label="extra navigation" data-v-af5898d3><span class="vpi-more-horizontal icon" data-v-af5898d3></span></button><div class="menu" data-v-af5898d3><div class="VPMenu" data-v-af5898d3 data-v-e42ed9b3><!----><!--[--><!--[--><!----><div class="group" data-v-8e87c032><div class="item appearance" data-v-8e87c032><p class="label" data-v-8e87c032>主题</p><div class="appearance-action" data-v-8e87c032><button class="VPSwitch VPSwitchAppearance" type="button" role="switch" title="切换到深色模式" aria-checked="false" data-v-8e87c032 data-v-7df97737 data-v-b4ccac88><span class="check" data-v-b4ccac88><span class="icon" data-v-b4ccac88><!--[--><span class="vpi-sun sun" data-v-7df97737></span><span class="vpi-moon moon" data-v-7df97737></span><!--]--></span></span></button></div></div></div><div class="group" data-v-8e87c032><div class="item social-links" data-v-8e87c032><div class="VPSocialLinks social-links-list" data-v-8e87c032 data-v-e71e869c><!--[--><a class="VPSocialLink no-icon" href="https://github.com/amtoaer/bili-sync" aria-label="github" target="_blank" rel="noopener" data-v-e71e869c data-v-358b6670><span class="vpi-social-github" /></a><!--]--></div></div></div><!--]--><!--]--></div></div></div><!--[--><!--]--><button type="button" class="VPNavBarHamburger hamburger" aria-label="mobile navigation" aria-expanded="false" aria-controls="VPNavScreen" data-v-844edcde data-v-6bee1efd><span class="container" data-v-6bee1efd><span class="top" data-v-6bee1efd></span><span class="middle" data-v-6bee1efd></span><span class="bottom" data-v-6bee1efd></span></span></button></div></div></div></div><div class="divider" data-v-844edcde><div class="divider-line" data-v-844edcde></div></div></div><!----></header><div class="VPLocalNav has-sidebar empty" data-v-d8b57b2d data-v-2488c25a><div class="container" data-v-2488c25a><button class="menu" aria-expanded="false" aria-controls="VPSidebarNav" data-v-2488c25a><span class="vpi-align-left menu-icon" data-v-2488c25a></span><span class="menu-text" data-v-2488c25a>菜单</span></button><div class="VPLocalNavOutlineDropdown" style="--vp-vh:0px;" data-v-2488c25a data-v-883964e0><button data-v-883964e0>回到顶部</button><!----></div></div></div><aside class="VPSidebar" data-v-d8b57b2d data-v-4871f9f5><div class="curtain" data-v-4871f9f5></div><nav class="nav" id="VPSidebarNav" aria-labelledby="sidebar-aria-label" tabindex="-1" data-v-4871f9f5><span class="visually-hidden" id="sidebar-aria-label" data-v-4871f9f5> Sidebar Navigation </span><!--[--><!--]--><!--[--><div class="group" data-v-4871f9f5><section class="VPSidebarItem level-0" data-v-4871f9f5 data-v-c24f735a><div class="item" role="button" tabindex="0" data-v-c24f735a><div class="indicator" data-v-c24f735a></div><h2 class="text" data-v-c24f735a>简介</h2><!----></div><div class="items" data-v-c24f735a><!--[--><div class="VPSidebarItem level-1 is-link" data-v-c24f735a data-v-c24f735a><div class="item" data-v-c24f735a><div class="indicator" data-v-c24f735a></div><a class="VPLink link link" href="/introduction" data-v-c24f735a><!--[--><p class="text" data-v-c24f735a>什么是 bili-sync?</p><!--]--></a><!----></div><!----></div><div class="VPSidebarItem level-1 is-link" data-v-c24f735a data-v-c24f735a><div class="item" data-v-c24f735a><div class="indicator" data-v-c24f735a></div><a class="VPLink link link" href="/quick-start" data-v-c24f735a><!--[--><p class="text" data-v-c24f735a>快速开始</p><!--]--></a><!----></div><!----></div><!--]--></div></section></div><div class="group" data-v-4871f9f5><section class="VPSidebarItem level-0 has-active" data-v-4871f9f5 data-v-c24f735a><div class="item" role="button" tabindex="0" data-v-c24f735a><div class="indicator" data-v-c24f735a></div><h2 class="text" data-v-c24f735a>细节</h2><!----></div><div class="items" data-v-c24f735a><!--[--><div class="VPSidebarItem level-1 is-link" data-v-c24f735a data-v-c24f735a><div class="item" data-v-c24f735a><div class="indicator" data-v-c24f735a></div><a class="VPLink link link" href="/configuration" data-v-c24f735a><!--[--><p class="text" data-v-c24f735a>配置说明</p><!--]--></a><!----></div><!----></div><div class="VPSidebarItem level-1 is-link" data-v-c24f735a data-v-c24f735a><div class="item" data-v-c24f735a><div class="indicator" data-v-c24f735a></div><a class="VPLink link link" href="/args" data-v-c24f735a><!--[--><p class="text" data-v-c24f735a>命令行参数</p><!--]--></a><!----></div><!----></div><div class="VPSidebarItem level-1 is-link" data-v-c24f735a data-v-c24f735a><div class="item" data-v-c24f735a><div class="indicator" data-v-c24f735a></div><a class="VPLink link link" href="/design" data-v-c24f735a><!--[--><p class="text" data-v-c24f735a>工作原理</p><!--]--></a><!----></div><!----></div><!--]--></div></section></div><div class="group" data-v-4871f9f5><section class="VPSidebarItem level-0" data-v-4871f9f5 data-v-c24f735a><div class="item" role="button" tabindex="0" data-v-c24f735a><div class="indicator" data-v-c24f735a></div><h2 class="text" data-v-c24f735a>参考</h2><!----></div><div class="items" data-v-c24f735a><!--[--><div class="VPSidebarItem level-1 is-link" data-v-c24f735a data-v-c24f735a><div class="item" data-v-c24f735a><div class="indicator" data-v-c24f735a></div><a class="VPLink link link" href="/favorite" data-v-c24f735a><!--[--><p class="text" data-v-c24f735a>获取收藏夹信息</p><!--]--></a><!----></div><!----></div><div class="VPSidebarItem level-1 is-link" data-v-c24f735a data-v-c24f735a><div class="item" data-v-c24f735a><div class="indicator" data-v-c24f735a></div><a class="VPLink link link" href="/collection" data-v-c24f735a><!--[--><p class="text" data-v-c24f735a>获取合集/列表信息</p><!--]--></a><!----></div><!----></div><div class="VPSidebarItem level-1 is-link" data-v-c24f735a data-v-c24f735a><div class="item" data-v-c24f735a><div class="indicator" data-v-c24f735a></div><a class="VPLink link link" href="/submission" data-v-c24f735a><!--[--><p class="text" data-v-c24f735a>获取用户投稿信息</p><!--]--></a><!----></div><!----></div><!--]--></div></section></div><div class="group" data-v-4871f9f5><section class="VPSidebarItem level-0" data-v-4871f9f5 data-v-c24f735a><div class="item" role="button" tabindex="0" data-v-c24f735a><div class="indicator" data-v-c24f735a></div><h2 class="text" data-v-c24f735a>其它</h2><!----></div><div class="items" data-v-c24f735a><!--[--><div class="VPSidebarItem level-1 is-link" data-v-c24f735a data-v-c24f735a><div class="item" data-v-c24f735a><div class="indicator" data-v-c24f735a></div><a class="VPLink link link" href="/question" data-v-c24f735a><!--[--><p class="text" data-v-c24f735a>常见问题</p><!--]--></a><!----></div><!----></div><div class="VPSidebarItem level-1 is-link" data-v-c24f735a data-v-c24f735a><div class="item" data-v-c24f735a><div class="indicator" data-v-c24f735a></div><a class="VPLink link link" href="/frontend" data-v-c24f735a><!--[--><p class="text" data-v-c24f735a>管理页</p><!--]--></a><!----></div><!----></div><!--]--></div></section></div><!--]--><!--[--><!--]--></nav></aside><div class="VPContent has-sidebar" id="VPContent" data-v-d8b57b2d data-v-9a6c75ad><div class="VPDoc has-sidebar has-aside" data-v-9a6c75ad data-v-e6f2a212><!--[--><!--]--><div class="container" data-v-e6f2a212><div class="aside" data-v-e6f2a212><div class="aside-curtain" data-v-e6f2a212></div><div class="aside-container" data-v-e6f2a212><div class="aside-content" data-v-e6f2a212><div class="VPDocAside" data-v-e6f2a212 data-v-cb998dce><!--[--><!--]--><!--[--><!--]--><nav aria-labelledby="doc-outline-aria-label" class="VPDocAsideOutline" data-v-cb998dce data-v-f610f197><div class="content" data-v-f610f197><div class="outline-marker" data-v-f610f197></div><div aria-level="2" class="outline-title" id="doc-outline-aria-label" role="heading" data-v-f610f197>页面导航</div><ul class="VPDocOutlineItem root" data-v-f610f197 data-v-53c99d69><!--[--><!--]--></ul></div></nav><!--[--><!--]--><div class="spacer" data-v-cb998dce></div><!--[--><!--]--><!----><!--[--><!--]--><!--[--><!--]--></div></div></div></div><div class="content" data-v-e6f2a212><div class="content-container" data-v-e6f2a212><!--[--><!--]--><main class="main" data-v-e6f2a212><div style="position:relative;" class="vp-doc _design" data-v-e6f2a212><div><h1 id="工作原理" tabindex="-1">工作原理 <a class="header-anchor" href="#工作原理" aria-label="Permalink to "工作原理""></a></h1><p>本节会尽可能简单明了地介绍 <code>bili-sync</code> 的工作原理,让用户了解程序的整体执行过程。</p><h2 id="b-站的视频结构" tabindex="-1">b 站的视频结构 <a class="header-anchor" href="#b-站的视频结构" aria-label="Permalink to "b 站的视频结构""></a></h2><p>在了解程序工作原理之前,我们需要先对 b 站视频的组织结构有一个大概的了解。简单来说:</p><ul><li>收藏夹、稍后再看、视频合集、视频列表等结构都是由一系列视频构成的列表;</li><li>每个视频都有唯一的 bvid,包含了封面、描述和标签信息,并包含了一个或多个分页;</li><li>每个分页都有一个唯一的 cid,包含了封面、视频、音频、弹幕。</li></ul><p>为了描述方便,在后文会将收藏夹、稍后再看这类结构统称为 video source,将视频称为 video,将分页称为 page。不难看出这三者有着很明显的层级关系:<strong>video source 包含若干 video,video 包含若干 page</strong>。</p><p>一个非常容易混淆的点是视频合集/视频列表与多页视频的区别:</p><div class="note custom-block github-alert"><p class="custom-block-title">NOTE</p><p><img src="/assets/bili_collection.DiWdQ_1C.webp" alt="bili_collection"></p><p><img src="/assets/bili_video.AE-Vm7po.webp" alt="bili_video"></p></div><p>这两张图中,上图是视频合集,下图是多页视频。这两者在展示上区别较小,但在结构上有相当大的不同。结合上面对 b 站视频结构的介绍,这个区别可以简单总结为:</p><ul><li><p><strong>视频合集是由多个仅包含单个 page 的 video 组成的 video source</strong>;</p></li><li><p><strong>多页视频是由多个 page 组成的 video</strong>。</p></li></ul><p>这说明它们是处于两个不同层级的结构,因此程序对其的处理方式也有着相当大的不同。</p><h2 id="与-emby-媒体库的对应关系" tabindex="-1">与 EMBY 媒体库的对应关系 <a class="header-anchor" href="#与-emby-媒体库的对应关系" aria-label="Permalink to "与 EMBY 媒体库的对应关系""></a></h2><p>EMBY 的一般结构是: <code>媒体库 - 文件夹 - 电影/电视剧 - 分季/分集</code>,方便起见,我采用了如下的对应关系:</p><ol><li><strong>文件夹</strong>:对应 b 站的 video source;</li><li><strong>电视剧</strong>:对应 b 站的 video;</li><li><strong>第一季的所有分集</strong>:对应 b 站的 page。</li></ol><p>特别的,当 video 仅有一个 page 时,为了避免过多的层级,bili-sync 会将 page 展开到第二层级,变成与电视剧同级的电影。</p><p>因此,<strong>需要将媒体库类型设置为“混合内容”以支持在同个媒体库中同时显示电视剧与电影</strong>。</p><h3 id="单-page-的-video" tabindex="-1">单 page 的 video <a class="header-anchor" href="#单-page-的-video" aria-label="Permalink to "单 page 的 video""></a></h3><p><img src="/assets/single_page.jTeO_DvF.webp" alt="single_page"></p><h3 id="多-page-的-video" tabindex="-1">多 page 的 video <a class="header-anchor" href="#多-page-的-video" aria-label="Permalink to "多 page 的 video""></a></h3><p><img src="/assets/multi_page.tN1txa1M.webp" alt="multi_page"></p><p><img src="/assets/multi_page_detail.BYT8HIYs.webp" alt="multi_page_detail"></p><h2 id="数据库设计" tabindex="-1">数据库设计 <a class="header-anchor" href="#数据库设计" aria-label="Permalink to "数据库设计""></a></h2><div class="note custom-block github-alert"><p class="custom-block-title">NOTE</p><p>可以<a href="https://github.com/amtoaer/bili-sync/tree/main/crates/bili_sync_entity/src/entities" target="_blank" rel="noreferrer">前往此处</a>实时查看当前版本的数据库表结构。</p></div><p>既然拥有着明显的层级关系,那数据库表就很容易设计了。为了简化实现,程序没有额外考虑单个 video 被多个 video source 引用的情况(如一个视频同时在收藏夹和稍后再看中)。而是简单的将其设计为了不交叉的层级结构。</p><h3 id="video-source-表" tabindex="-1">video source 表 <a class="header-anchor" href="#video-source-表" aria-label="Permalink to "video source 表""></a></h3><p>从上面的介绍可以看出,video source 并不是一个具体的结构,而是拥有多种实现的抽象概念。我选择将其特化实现为多张表:</p><ol><li>favorite:收藏夹;</li><li>watch_later:稍后再看;</li><li>collection: 视频合集/视频列表;</li><li>....</li></ol><h3 id="video-表" tabindex="-1">video 表 <a class="header-anchor" href="#video-表" aria-label="Permalink to "video 表""></a></h3><p>video 表包含了 video 的基本信息,如 bvid、标题、封面、描述、标签等。此外,video 表还包含了与 video source 的关联。</p><p>具体来说,每一种 video source 都在 video 表中有一个对应的列,指向 video source 表中的 id,如 favorite_id、collection_id 等。接下来将这些键与 video 的 bvid 绑在一起建立唯一索引,就可以保证在同一个 video source 中不会有重复的 video。</p><h3 id="page-表" tabindex="-1">page 表 <a class="header-anchor" href="#page-表" aria-label="Permalink to "page 表""></a></h3><p>page 表包含了 page 的基本信息,如 cid、标题、封面等。与 video 类似但更简单,page 表仅包含了与 video 的关联。</p><h2 id="执行过程" tabindex="-1">执行过程 <a class="header-anchor" href="#执行过程" aria-label="Permalink to "执行过程""></a></h2><h3 id="初始化" tabindex="-1">初始化 <a class="header-anchor" href="#初始化" aria-label="Permalink to "初始化""></a></h3><p>程序启动时会读取配置文件、迁移数据库、初始化日志等操作。如果发现需要的文件不存在,程序会自动创建。</p><h3 id="扫描-video-source-获取新视频" tabindex="-1">扫描 video source 获取新视频 <a class="header-anchor" href="#扫描-video-source-获取新视频" aria-label="Permalink to "扫描 video source 获取新视频""></a></h3><div class="warning custom-block github-alert"><p class="custom-block-title">WARNING</p><p>b 站实现接口时为了节省资源,通过 video source 获取到的 video 列表通常是分页且不包含详细信息的。</p></div><p>程序会扫描所有配置文件中包含的 video source,获取其中包含的 video 的简单信息并填充到数据库。在实现时需要避免频繁的全量扫描。</p><p>具体到 bili-sync 的实现中,每个 video source 都有一个 <code>latest_row_at</code> 列,用于记录处理过的最新视频时间。程序在请求接口时会设置按时间排序,确保新视频位于前面。排序依据的时间根据 video source 的类型而定:收藏夹按收藏时间,投稿按照投稿时间...</p><p>拉取过程会逐页请求,程序会不断将获取到的视频保存到数据库中,直到发现第一个小于等于 <code>latest_row_at</code> 的视频时停止。接着将 <code>latest_row_at</code> 更新为最新的视频时间。</p><h3 id="填充-video-详情" tabindex="-1">填充 video 详情 <a class="header-anchor" href="#填充-video-详情" aria-label="Permalink to "填充 video 详情""></a></h3><p>将新增视频的简单信息写入数据库后,下一步会填充 video 详情。正如上文所述:<strong>通过 video source 获取到的 video 列表通常是不包含详细信息的</strong>,因此需要额外的请求来填充这些信息。</p><p>这一步会筛选出所有未完全填充信息的 video,逐个获取 video 的详细信息(如标签、包含的 page 等)并填充到数据库中。</p><p>在这个过程中,如果遇到 -404 错误码则说明视频无法被正常访问,程序会将该视频标记为无效并跳过。</p><h3 id="下载未处理的视频" tabindex="-1">下载未处理的视频 <a class="header-anchor" href="#下载未处理的视频" aria-label="Permalink to "下载未处理的视频""></a></h3><p>经过上面处理后,数据库中已经包含了所有需要的 video 和 page 信息,接下来只需要筛选其中“未完全下载”、“成功填充详细信息”的所有视频,并发下载即可。程序在 video 层级最多允许 3 个任务同时下载,page 层级最多允许 2 个任务同时下载。</p><p>数据库中的 status 字段用于标记 video 和 page 的下载状态,视频的各个部分(封面、视频、nfo 等)包含在 status 的不同位中。程序会根据 status 的不同位来判断视频的下载状态,以此来决定是否需要下载。</p><p>如果某些部分下载失败,status 字段会记录这些部分的失败次数,程序会在下次下载时重试。如果重试次数超过了设定的阈值,那么视频会被标记为下载失败,后续直接忽略。</p><p>此处程序对风控做了额外的处理,一般风控发生时接下来的所有请求都会失败,因此程序检测到风控时不会认为是某个视频下载失败,而是直接终止 video source 的全部下载任务,等待下次扫描时重试。</p></div></div></main><footer class="VPDocFooter" data-v-e6f2a212 data-v-5941af80><!--[--><!--]--><div class="edit-info" data-v-5941af80><!----><div class="last-updated" data-v-5941af80><p class="VPLastUpdated" data-v-5941af80 data-v-19a7ae4e>上次更新于: <time datetime="2026-05-07T06:47:45.000Z" data-v-19a7ae4e></time></p></div></div><nav class="prev-next" aria-labelledby="doc-footer-aria-label" data-v-5941af80><span class="visually-hidden" id="doc-footer-aria-label" data-v-5941af80>Pager</span><div class="pager" data-v-5941af80><a class="VPLink link pager-link prev" href="/args" data-v-5941af80><!--[--><span class="desc" data-v-5941af80>上一页</span><span class="title" data-v-5941af80>命令行参数</span><!--]--></a></div><div class="pager" data-v-5941af80><a class="VPLink link pager-link next" href="/favorite" data-v-5941af80><!--[--><span class="desc" data-v-5941af80>下一页</span><span class="title" data-v-5941af80>获取收藏夹信息</span><!--]--></a></div></nav></footer><!--[--><!--]--></div></div></div><!--[--><!--]--></div></div><!----><!--[--><!--]--></div></div>
|
||
|
||
|
||
</body>
|
||
</html> |