├── .browserslistrc ├── .editorconfig ├── .eslintignore ├── .eslintrc.js ├── .gitattributes ├── .github-json ├── README.md ├── data │ ├── DISCUSSION_TEMPLATE │ │ └── 功能建议-ideas.json │ ├── FUNDING.json │ ├── ISSUE_TEMPLATE │ │ ├── bug_report.json │ │ └── config.json │ └── workflows │ │ ├── build.json │ │ └── pull-request-check.json └── index.ts ├── .github ├── DISCUSSION_TEMPLATE │ └── 功能建议-ideas.yml ├── FUNDING.yml ├── ISSUE_TEMPLATE │ ├── bug_report.yml │ └── config.yml ├── pull_request_template.md └── workflows │ ├── build.yml │ └── pull-request-check.yml ├── .gitignore ├── .prettierrc ├── .vscode ├── dynamic-import.code-snippets ├── html-in-js.code-snippets ├── launch.json ├── settings.json ├── tasks.json ├── ui-import.code-snippets └── vue-import.code-snippets ├── CHANGELOG.md ├── CODE_OF_CONDUCT.md ├── CONTRIBUTING.md ├── LICENCE.md ├── README.md ├── bilibili-evolved.offline.user.js ├── dev-tools ├── dev-server │ ├── config.ts │ ├── core-watcher.ts │ ├── design.md │ ├── index.ts │ ├── payload.ts │ ├── registry-watcher.ts │ ├── server.ts │ ├── tsconfig.json │ ├── watcher-common.ts │ └── web-socket-server.ts └── donate-table │ ├── index.ts │ ├── package.json │ ├── pnpm-lock.yaml │ └── tsconfig.json ├── dist ├── bilibili-evolved.preview.user.js └── bilibili-evolved.user.js ├── doc ├── aria2-notice.md ├── cdn.md ├── donate.md ├── features │ ├── features.json │ ├── features.md │ └── pack │ │ ├── pack.json │ │ └── pack.md ├── issue-rules.md ├── release-checklist.md ├── rollback.md └── v1-migrate.md ├── docs ├── README.md └── static │ └── mdi │ ├── mdi.css │ └── mdi.woff2 ├── images ├── bilibili-evolved-wide-color.svg ├── bilibili-evolved-wide-dark.svg ├── bilibili-evolved-wide.svg ├── compressed │ ├── afdian.jpg │ └── wechat.jpg ├── logo-small.png ├── logo.png └── v2 │ ├── about-panel.jpg │ ├── manage-panel.jpg │ ├── settings-panel.jpg │ └── side-panel.jpg ├── package.json ├── pnpm-lock.yaml ├── registry ├── dist │ ├── components │ │ ├── feeds │ │ │ ├── copy-link.js │ │ │ ├── del-feeds.js │ │ │ ├── disable-details.js │ │ │ ├── extend-live.js │ │ │ ├── filter.js │ │ │ ├── fixed-sidebars.js │ │ │ ├── fold-comments.js │ │ │ ├── full-content.js │ │ │ ├── full-title.js │ │ │ ├── hide-comment-preview.js │ │ │ ├── image-auto-back-to-top.js │ │ │ ├── legacy-image-viewer.js │ │ │ ├── translate.js │ │ │ └── unfold.js │ │ ├── live │ │ │ ├── badge-helper.js │ │ │ ├── chat-panel-fit.js │ │ │ ├── danmaku-sendbar.js │ │ │ ├── download-records.js │ │ │ ├── gift-box.js │ │ │ ├── hide-gift-fullscreen.js │ │ │ ├── hide-player-blur.js │ │ │ ├── home-mute.js │ │ │ ├── liveroom-username-link.js │ │ │ ├── original.js │ │ │ ├── remove-mask-panel.js │ │ │ ├── remove-watermark.js │ │ │ ├── showgirl.js │ │ │ └── side-bar.js │ │ ├── style │ │ │ ├── always-show-duration.js │ │ │ ├── auto-hide-sidebar.js │ │ │ ├── clear-home.js │ │ │ ├── custom-font-family.js │ │ │ ├── custom-navbar.js │ │ │ ├── dark-mode.js │ │ │ ├── dark-mode │ │ │ │ ├── follow-system.js │ │ │ │ └── schedule.js │ │ │ ├── hide │ │ │ │ ├── bangumi │ │ │ │ │ ├── reviews.js │ │ │ │ │ └── sponsors.js │ │ │ │ ├── banner.js │ │ │ │ ├── home-carousel.js │ │ │ │ ├── trending-search.js │ │ │ │ ├── user-card.js │ │ │ │ ├── user-pendent.js │ │ │ │ └── video │ │ │ │ │ ├── notes.js │ │ │ │ │ ├── recommended-live.js │ │ │ │ │ ├── related-videos.js │ │ │ │ │ ├── report.js │ │ │ │ │ ├── share.js │ │ │ │ │ └── top-mask.js │ │ │ ├── home-redesign │ │ │ │ ├── fresh.js │ │ │ │ └── minimal.js │ │ │ ├── player-on-top-new.js │ │ │ ├── player-on-top.js │ │ │ ├── player-shadow.js │ │ │ ├── scrollbar.js │ │ │ ├── sidebar-offset.js │ │ │ ├── simplify │ │ │ │ ├── comments.js │ │ │ │ ├── home.js │ │ │ │ └── live.js │ │ │ ├── special-danmaku.js │ │ │ └── v1-panel.js │ │ ├── touch │ │ │ ├── combo-like.js │ │ │ ├── double-click-control.js │ │ │ ├── mini-player.js │ │ │ ├── player-control.js │ │ │ └── player-gestures.js │ │ ├── utils │ │ │ ├── album-time-show.js │ │ │ ├── auto-like.js │ │ │ ├── black-list.js │ │ │ ├── change-update-urls.js │ │ │ ├── check-in-center.js │ │ │ ├── column-unlock.js │ │ │ ├── comments │ │ │ │ ├── content-replace.js │ │ │ │ ├── content-replace │ │ │ │ │ └── handlers.js │ │ │ │ ├── copy-link.js │ │ │ │ ├── disable-search-link.js │ │ │ │ └── translate.js │ │ │ ├── dev-client.js │ │ │ ├── download-audio.js │ │ │ ├── image-exporter.js │ │ │ ├── image-resolution.js │ │ │ ├── import-series.js │ │ │ ├── ip-show.js │ │ │ ├── keymap.js │ │ │ ├── remove-promotions.js │ │ │ ├── subscribe-time-show.js │ │ │ ├── url-params-clean.js │ │ │ ├── v1-migrate.js │ │ │ ├── view-cover.js │ │ │ └── watchlater-redirect.js │ │ └── video │ │ │ ├── auto-remove-watchlater.js │ │ │ ├── av-url.js │ │ │ ├── biliplus-redirect.js │ │ │ ├── bvid-convert.js │ │ │ ├── danmaku │ │ │ ├── airborne.js │ │ │ ├── download.js │ │ │ ├── expand.js │ │ │ └── unescape.js │ │ │ ├── default-location.js │ │ │ ├── download.js │ │ │ ├── full-description.js │ │ │ ├── full-episode-title.js │ │ │ ├── metadata.js │ │ │ ├── outer-watchlater.js │ │ │ ├── player │ │ │ ├── auto-light.js │ │ │ ├── common │ │ │ │ ├── mini-rxjs.js │ │ │ │ └── mini-rxjs │ │ │ │ │ └── operators │ │ │ │ │ └── util.js │ │ │ ├── control-background.js │ │ │ ├── default-mode.js │ │ │ ├── disable-double-click-fullscreen.js │ │ │ ├── disable-scroll-volume.js │ │ │ ├── double-click-fullscreen.js │ │ │ ├── extend-speed.js │ │ │ ├── focus.js │ │ │ ├── intersection-actions.js │ │ │ ├── invert-scroll-volume.js │ │ │ ├── legacy-auto-play.js │ │ │ ├── preserve-danmaku-input.js │ │ │ ├── remember-speed.js │ │ │ ├── remove-popup.js │ │ │ ├── screenshot.js │ │ │ ├── seek-by-frames.js │ │ │ ├── show-cover.js │ │ │ ├── show-upload-time.js │ │ │ └── skip-charge-list.js │ │ │ ├── quick-favorite.js │ │ │ ├── seo-redirect.js │ │ │ └── subtitle │ │ │ └── download.js │ └── plugins │ │ ├── feeds │ │ └── filter │ │ │ ├── hide-charge-feeds.js │ │ │ └── hide-goods.js │ │ ├── i18n │ │ ├── en-US.js │ │ └── ja-JP.js │ │ ├── launch-bar │ │ ├── audio-search.js │ │ ├── bangumi-search.js │ │ ├── cv-search.js │ │ ├── number-search.js │ │ ├── trending-search.js │ │ └── uid-search.js │ │ ├── settings-panel │ │ └── recent-components.js │ │ ├── style │ │ ├── custom-navbar-channel.js │ │ ├── custom-navbar-dark-mode.js │ │ └── custom-navbar-pgc.js │ │ ├── utils │ │ ├── keymap-dark-mode.js │ │ ├── keymap-empty-action.ts.js │ │ ├── keymap-toggle-danmaku-list.js │ │ ├── keymap-toggle-player-light.js │ │ └── keymap-toggle-subtitle.js │ │ ├── v-loading │ │ └── reimu.js │ │ └── video │ │ ├── download │ │ ├── aria2-output.js │ │ ├── empty-output.js │ │ ├── idm-output.js │ │ ├── manual-input.js │ │ ├── motrix-output.js │ │ ├── mpv-output-ex.js │ │ ├── mpv-output-playlist.js │ │ ├── mpv-output.js │ │ └── wasm-output.js │ │ └── player │ │ └── speed.js ├── lib │ ├── components │ │ ├── feeds │ │ │ ├── _feeds-panel-shared.scss │ │ │ ├── copy-link │ │ │ │ └── index.ts │ │ │ ├── del-feeds │ │ │ │ ├── Widget.vue │ │ │ │ ├── check-in-item.ts │ │ │ │ ├── index.md │ │ │ │ └── index.ts │ │ │ ├── disable-details │ │ │ │ ├── disable-details.scss │ │ │ │ ├── index.ts │ │ │ │ └── init.scss │ │ │ ├── extend-live │ │ │ │ ├── LiveList.vue │ │ │ │ ├── extend-feeds-live.scss │ │ │ │ ├── index.md │ │ │ │ └── index.ts │ │ │ ├── filter │ │ │ │ ├── FeedsFilterCard.vue │ │ │ │ ├── FilterTypeSwitch.vue │ │ │ │ ├── _blocker.scss │ │ │ │ ├── feeds-filter.md │ │ │ │ ├── index.md │ │ │ │ ├── index.ts │ │ │ │ ├── options.ts │ │ │ │ ├── pattern.ts │ │ │ │ └── plugin.ts │ │ │ ├── fixed-sidebars │ │ │ │ ├── fixed-sidebars.scss │ │ │ │ └── index.ts │ │ │ ├── fold-comments │ │ │ │ ├── fold-comment-shadow.scss │ │ │ │ ├── fold-comment.scss │ │ │ │ └── index.ts │ │ │ ├── full-content │ │ │ │ ├── full-content.scss │ │ │ │ ├── index.md │ │ │ │ └── index.ts │ │ │ ├── full-title │ │ │ │ ├── full-feeds-title.scss │ │ │ │ └── index.ts │ │ │ ├── hide-comment-preview │ │ │ │ ├── hide-comment-preview.scss │ │ │ │ ├── index.md │ │ │ │ └── index.ts │ │ │ ├── image-auto-back-to-top │ │ │ │ ├── index.md │ │ │ │ └── index.ts │ │ │ ├── legacy-image-viewer │ │ │ │ ├── index.md │ │ │ │ └── index.ts │ │ │ └── unfold │ │ │ │ └── index.ts │ │ ├── live │ │ │ ├── badge-helper │ │ │ │ ├── BadgeHelper.vue │ │ │ │ ├── auto-match.ts │ │ │ │ ├── badge.ts │ │ │ │ ├── index.md │ │ │ │ ├── index.ts │ │ │ │ └── options.ts │ │ │ ├── chat-panel-fit │ │ │ │ ├── ChatPanelFitDragger.vue │ │ │ │ ├── chat-panel-fit.scss │ │ │ │ ├── index.md │ │ │ │ ├── index.ts │ │ │ │ └── options.ts │ │ │ ├── danmaku-sendbar │ │ │ │ ├── DanmakuSendbar.vue │ │ │ │ ├── index.ts │ │ │ │ └── original-elements.ts │ │ │ ├── gift-box │ │ │ │ ├── gift-box.scss │ │ │ │ └── index.ts │ │ │ ├── hide-gift-fullscreen │ │ │ │ ├── hide-full-screen-gift.css │ │ │ │ └── index.ts │ │ │ ├── hide-player-blur │ │ │ │ ├── hide-player-blur.scss │ │ │ │ ├── index.md │ │ │ │ └── index.ts │ │ │ ├── home-mute │ │ │ │ └── index.ts │ │ │ ├── liveroom-username-link │ │ │ │ └── index.ts │ │ │ ├── original │ │ │ │ ├── Widget.vue │ │ │ │ ├── get-original-liveroom-url.ts │ │ │ │ └── index.ts │ │ │ ├── remove-mask-panel │ │ │ │ └── index.ts │ │ │ ├── remove-watermark │ │ │ │ ├── index.ts │ │ │ │ └── remove-watermark.scss │ │ │ ├── showgirl │ │ │ │ └── index.ts │ │ │ └── side-bar │ │ │ │ ├── index.ts │ │ │ │ └── side-bar.scss │ │ ├── style │ │ │ ├── always-show-duration │ │ │ │ ├── always-show-duration.scss │ │ │ │ └── index.ts │ │ │ ├── auto-hide-sidebar │ │ │ │ ├── auto-hide-sidebar.scss │ │ │ │ └── index.ts │ │ │ ├── clear-home │ │ │ │ └── index.ts │ │ │ ├── custom-font-family │ │ │ │ ├── data.ts │ │ │ │ ├── disable-title-punctuation-text-indent.scss │ │ │ │ ├── extra-options │ │ │ │ │ ├── Entry.vue │ │ │ │ │ ├── ExtraOptionsPanel.vue │ │ │ │ │ ├── Panel.vue │ │ │ │ │ ├── SwitchOptionsMin.vue │ │ │ │ │ ├── extra-options-panel.scss │ │ │ │ │ ├── extra-options-panel.ts │ │ │ │ │ └── vm.ts │ │ │ │ ├── index.md │ │ │ │ ├── index.ts │ │ │ │ └── set-font-family.scss │ │ │ ├── custom-navbar │ │ │ │ ├── CustomNavbar.vue │ │ │ │ ├── CustomNavbarItem.vue │ │ │ │ ├── CustomNavbarLink.vue │ │ │ │ ├── _nav-link.scss │ │ │ │ ├── _popup.scss │ │ │ │ ├── _scroll-animation.scss │ │ │ │ ├── built-in-items.ts │ │ │ │ ├── custom-navbar-item.ts │ │ │ │ ├── entry.ts │ │ │ │ ├── favorites │ │ │ │ │ ├── FavoritesFolderSelect.vue │ │ │ │ │ ├── NavbarFavorites.vue │ │ │ │ │ ├── favorites-folder.ts │ │ │ │ │ └── favorites.ts │ │ │ │ ├── feeds │ │ │ │ │ ├── NavbarFeeds.vue │ │ │ │ │ ├── feeds.ts │ │ │ │ │ └── tabs │ │ │ │ │ │ ├── BangumiFeeds.vue │ │ │ │ │ │ ├── ColumnFeeds.vue │ │ │ │ │ │ ├── LiveFeeds.vue │ │ │ │ │ │ ├── VideoFeeds.vue │ │ │ │ │ │ ├── bangumi-mockup.ts │ │ │ │ │ │ ├── live-feed-item.ts │ │ │ │ │ │ ├── next-page.ts │ │ │ │ │ │ └── tabs.ts │ │ │ │ ├── flexible-blank │ │ │ │ │ └── flexible-blank.ts │ │ │ │ ├── hide-original.scss │ │ │ │ ├── history │ │ │ │ │ ├── NavbarHistory.vue │ │ │ │ │ ├── history.ts │ │ │ │ │ └── types.ts │ │ │ │ ├── home │ │ │ │ │ ├── NavbarHome.vue │ │ │ │ │ └── home.ts │ │ │ │ ├── iframe │ │ │ │ │ ├── IframePopup.vue │ │ │ │ │ └── iframe.ts │ │ │ │ ├── index.md │ │ │ │ ├── index.ts │ │ │ │ ├── link-popup-content-align-style.ts │ │ │ │ ├── logo │ │ │ │ │ ├── NavbarLogo.vue │ │ │ │ │ └── logo.ts │ │ │ │ ├── messages │ │ │ │ │ ├── NavbarMessages.vue │ │ │ │ │ └── messages.ts │ │ │ │ ├── mixins.ts │ │ │ │ ├── notify-style.ts │ │ │ │ ├── ranking │ │ │ │ │ ├── NavbarRanking.vue │ │ │ │ │ └── ranking.ts │ │ │ │ ├── search │ │ │ │ │ ├── NavbarSearch.vue │ │ │ │ │ └── search.ts │ │ │ │ ├── settings │ │ │ │ │ ├── ExtraOptions.vue │ │ │ │ │ ├── NavbarSettings.vue │ │ │ │ │ ├── Widget.vue │ │ │ │ │ ├── orders.ts │ │ │ │ │ └── vm.ts │ │ │ │ ├── simple-links │ │ │ │ │ └── simple-links.ts │ │ │ │ ├── subscriptions │ │ │ │ │ ├── BangumiSubscriptions.vue │ │ │ │ │ ├── CinemaSubscriptions.vue │ │ │ │ │ ├── Content.vue │ │ │ │ │ ├── NavbarSubscriptions.vue │ │ │ │ │ ├── SubscriptionsList.vue │ │ │ │ │ ├── subscriptions.ts │ │ │ │ │ └── types.ts │ │ │ │ ├── transparent-fill.ts │ │ │ │ ├── upload │ │ │ │ │ ├── NavbarUpload.vue │ │ │ │ │ ├── UploadPopup.vue │ │ │ │ │ └── upload.ts │ │ │ │ ├── urls.ts │ │ │ │ ├── user-info │ │ │ │ │ ├── UserFace.vue │ │ │ │ │ ├── UserInfoPopup.vue │ │ │ │ │ ├── akari.jpg │ │ │ │ │ └── user-info.ts │ │ │ │ └── watchlater │ │ │ │ │ ├── NavbarWatchlater.vue │ │ │ │ │ └── watchlater.ts │ │ │ ├── dark-mode │ │ │ │ ├── README.md │ │ │ │ ├── _dark-definitions.scss │ │ │ │ ├── dark-mode.important.scss │ │ │ │ ├── dark-mode.scss │ │ │ │ ├── dark-navbar.scss │ │ │ │ ├── dark-shadow-dom.scss │ │ │ │ ├── dark-slice-10.scss │ │ │ │ ├── dark-slice-11.scss │ │ │ │ ├── dark-slice-12.scss │ │ │ │ ├── dark-slice-13.scss │ │ │ │ ├── dark-slice-14.scss │ │ │ │ ├── dark-slice-15.scss │ │ │ │ ├── dark-slice-16.scss │ │ │ │ ├── dark-slice-17.scss │ │ │ │ ├── dark-slice-18.scss │ │ │ │ ├── dark-slice-19.scss │ │ │ │ ├── dark-slice-9.scss │ │ │ │ ├── dark-urls.ts │ │ │ │ ├── dark-variables.scss │ │ │ │ ├── follow-system │ │ │ │ │ └── index.ts │ │ │ │ ├── index.ts │ │ │ │ ├── old │ │ │ │ │ ├── dark-slice-1.css │ │ │ │ │ ├── dark-slice-2.css │ │ │ │ │ ├── dark-slice-3.css │ │ │ │ │ ├── dark-slice-4.css │ │ │ │ │ ├── dark-slice-5.css │ │ │ │ │ ├── dark-slice-6.css │ │ │ │ │ ├── dark-slice-7.css │ │ │ │ │ └── dark-slice-8.css │ │ │ │ └── schedule │ │ │ │ │ └── index.ts │ │ │ ├── hide │ │ │ │ ├── bangumi │ │ │ │ │ ├── reviews │ │ │ │ │ │ ├── index.ts │ │ │ │ │ │ └── reviews.scss │ │ │ │ │ └── sponsors │ │ │ │ │ │ ├── index.ts │ │ │ │ │ │ └── sponsors.scss │ │ │ │ ├── banner │ │ │ │ │ ├── banner.scss │ │ │ │ │ └── index.ts │ │ │ │ ├── home-carousel │ │ │ │ │ ├── hide-home-carousel.scss │ │ │ │ │ ├── index.md │ │ │ │ │ └── index.ts │ │ │ │ ├── trending-search │ │ │ │ │ ├── hide-trending-search.scss │ │ │ │ │ ├── index.md │ │ │ │ │ └── index.ts │ │ │ │ ├── user-card │ │ │ │ │ ├── index.ts │ │ │ │ │ └── user-card.scss │ │ │ │ ├── user-pendent │ │ │ │ │ ├── index.md │ │ │ │ │ ├── index.ts │ │ │ │ │ ├── user-pendent-shadow.scss │ │ │ │ │ └── user-pendent.scss │ │ │ │ └── video │ │ │ │ │ ├── notes │ │ │ │ │ ├── hide-video-notes.scss │ │ │ │ │ ├── index.md │ │ │ │ │ └── index.ts │ │ │ │ │ ├── recommended-live │ │ │ │ │ ├── index.ts │ │ │ │ │ └── recommended-live.scss │ │ │ │ │ ├── related-videos │ │ │ │ │ ├── index.md │ │ │ │ │ ├── index.ts │ │ │ │ │ └── related-videos.scss │ │ │ │ │ ├── report │ │ │ │ │ ├── hide-video-report.scss │ │ │ │ │ ├── index.md │ │ │ │ │ └── index.ts │ │ │ │ │ ├── share │ │ │ │ │ ├── hide-video-share.scss │ │ │ │ │ ├── index.md │ │ │ │ │ └── index.ts │ │ │ │ │ └── top-mask │ │ │ │ │ ├── index.ts │ │ │ │ │ └── top-mask.scss │ │ │ ├── home-redesign │ │ │ │ ├── HomeRedesignBase.vue │ │ │ │ ├── fresh │ │ │ │ │ ├── ExtraOptions.vue │ │ │ │ │ ├── FreshHome.vue │ │ │ │ │ ├── FreshLayoutItem.vue │ │ │ │ │ ├── SubHeader.vue │ │ │ │ │ ├── VideoCardWrapper.vue │ │ │ │ │ ├── VideoList.vue │ │ │ │ │ ├── index.md │ │ │ │ │ ├── index.ts │ │ │ │ │ ├── init-dropdown-options │ │ │ │ │ │ └── area-primary-title-color.ts │ │ │ │ │ ├── layouts │ │ │ │ │ │ ├── areas │ │ │ │ │ │ │ ├── Areas.vue │ │ │ │ │ │ │ ├── areas.ts │ │ │ │ │ │ │ ├── black-room.svg │ │ │ │ │ │ │ ├── column.jpg │ │ │ │ │ │ │ ├── live.svg │ │ │ │ │ │ │ └── topic.svg │ │ │ │ │ │ ├── blackboard │ │ │ │ │ │ │ ├── Blackboard.vue │ │ │ │ │ │ │ ├── api.ts │ │ │ │ │ │ │ └── blackboard.ts │ │ │ │ │ │ ├── categories │ │ │ │ │ │ │ ├── Categories.vue │ │ │ │ │ │ │ ├── categories.ts │ │ │ │ │ │ │ ├── content │ │ │ │ │ │ │ │ ├── Bangumi.vue │ │ │ │ │ │ │ │ ├── BangumiTimeline.vue │ │ │ │ │ │ │ │ ├── CompactRankList.vue │ │ │ │ │ │ │ │ ├── Default.vue │ │ │ │ │ │ │ │ ├── RankList.vue │ │ │ │ │ │ │ │ ├── VideoSlides.vue │ │ │ │ │ │ │ │ ├── _rank-list.scss │ │ │ │ │ │ │ │ ├── content.ts │ │ │ │ │ │ │ │ └── rank-list.ts │ │ │ │ │ │ │ ├── filter.ts │ │ │ │ │ │ │ └── supported-names.json │ │ │ │ │ │ ├── feeds │ │ │ │ │ │ │ ├── Feeds.vue │ │ │ │ │ │ │ └── feeds.ts │ │ │ │ │ │ ├── fresh-layout-item.ts │ │ │ │ │ │ ├── layouts.ts │ │ │ │ │ │ └── trending │ │ │ │ │ │ │ ├── Trending.vue │ │ │ │ │ │ │ └── trending.ts │ │ │ │ │ ├── options.ts │ │ │ │ │ ├── scroll-mask.ts │ │ │ │ │ └── types.ts │ │ │ │ ├── hide-original.scss │ │ │ │ ├── minimal │ │ │ │ │ ├── MinimalHome.vue │ │ │ │ │ ├── MinimalHomeOperations.vue │ │ │ │ │ ├── index.md │ │ │ │ │ ├── index.ts │ │ │ │ │ ├── options.ts │ │ │ │ │ ├── tabs │ │ │ │ │ │ ├── Feeds.vue │ │ │ │ │ │ └── Trending.vue │ │ │ │ │ └── types.ts │ │ │ │ ├── mixin.ts │ │ │ │ ├── trending.ts │ │ │ │ └── urls.ts │ │ │ ├── player-on-top-new │ │ │ │ └── index.ts │ │ │ ├── player-on-top │ │ │ │ ├── index.ts │ │ │ │ └── player-on-top.scss │ │ │ ├── player-shadow │ │ │ │ ├── index.ts │ │ │ │ └── player-shadow.scss │ │ │ ├── scrollbar │ │ │ │ ├── index.ts │ │ │ │ └── scrollbar.scss │ │ │ ├── sidebar-offset │ │ │ │ ├── index.ts │ │ │ │ └── sidebar-offset.scss │ │ │ ├── simplify │ │ │ │ ├── comments │ │ │ │ │ ├── comments-v2.scss │ │ │ │ │ ├── comments-v3-firefox │ │ │ │ │ │ ├── base.scss │ │ │ │ │ │ ├── decorate-and-time.scss │ │ │ │ │ │ ├── event-banner.scss │ │ │ │ │ │ ├── fans-medal.scss │ │ │ │ │ │ ├── reply-editor.scss │ │ │ │ │ │ ├── sub-reply-new-line.scss │ │ │ │ │ │ └── user-level.scss │ │ │ │ │ ├── comments-v3.scss │ │ │ │ │ ├── comments.scss │ │ │ │ │ ├── index.md │ │ │ │ │ └── index.ts │ │ │ │ └── live │ │ │ │ │ ├── index.ts │ │ │ │ │ ├── live.scss │ │ │ │ │ └── skin.ts │ │ │ ├── special-danmaku │ │ │ │ ├── index.md │ │ │ │ ├── index.ts │ │ │ │ └── special-danmaku.scss │ │ │ └── v1-panel │ │ │ │ ├── index.ts │ │ │ │ └── v1-panel.scss │ │ ├── touch │ │ │ ├── combo-like │ │ │ │ └── index.ts │ │ │ ├── double-click-control │ │ │ │ ├── _default-state.scss │ │ │ │ ├── _fullscreen.scss │ │ │ │ ├── _hover-state.scss │ │ │ │ ├── _pbp.scss │ │ │ │ ├── _subtitle.scss │ │ │ │ ├── double-click-control.scss │ │ │ │ ├── index.md │ │ │ │ └── index.ts │ │ │ ├── mini-player │ │ │ │ ├── index.ts │ │ │ │ ├── live.ts │ │ │ │ ├── mini-player.scss │ │ │ │ ├── touch-move.ts │ │ │ │ └── video.ts │ │ │ ├── player-control │ │ │ │ ├── index.ts │ │ │ │ └── player-control.scss │ │ │ └── player-gestures │ │ │ │ ├── GesturePreview.vue │ │ │ │ ├── brightness.ts │ │ │ │ ├── desc.md │ │ │ │ ├── entry.ts │ │ │ │ ├── gesture-preview.ts │ │ │ │ ├── index.ts │ │ │ │ ├── progress.ts │ │ │ │ ├── swiper.ts │ │ │ │ ├── videoshot.ts │ │ │ │ └── volume.ts │ │ ├── utils │ │ │ ├── album-time-show │ │ │ │ ├── album-time.scss │ │ │ │ └── index.ts │ │ │ ├── auto-like │ │ │ │ ├── blackList.vue │ │ │ │ ├── index.md │ │ │ │ ├── index.ts │ │ │ │ ├── like.vue │ │ │ │ ├── settings.vue │ │ │ │ └── vm.ts │ │ │ ├── black-list │ │ │ │ ├── BlackListSettings.vue │ │ │ │ ├── Settings.vue │ │ │ │ ├── common.ts │ │ │ │ ├── index.ts │ │ │ │ └── vm.ts │ │ │ ├── change-update-urls │ │ │ │ ├── Widget.vue │ │ │ │ └── index.ts │ │ │ ├── check-in-center │ │ │ │ ├── Widget.vue │ │ │ │ ├── check-in-item.ts │ │ │ │ └── index.ts │ │ │ ├── column-unlock │ │ │ │ ├── index.md │ │ │ │ └── index.ts │ │ │ ├── comments │ │ │ │ ├── content-replace │ │ │ │ │ ├── handlers │ │ │ │ │ │ ├── emoticon-to-emoticon.ts │ │ │ │ │ │ ├── emoticon-to-text.ts │ │ │ │ │ │ ├── index.ts │ │ │ │ │ │ ├── node-content-replacer.ts │ │ │ │ │ │ ├── recursive.ts │ │ │ │ │ │ ├── text-to-emoticon.ts │ │ │ │ │ │ ├── text-to-text.ts │ │ │ │ │ │ └── types.ts │ │ │ │ │ ├── index.md │ │ │ │ │ ├── index.ts │ │ │ │ │ ├── options.ts │ │ │ │ │ ├── settings │ │ │ │ │ │ ├── ContentReplaceRow.vue │ │ │ │ │ │ ├── ExtraOptions.vue │ │ │ │ │ │ └── row.ts │ │ │ │ │ └── utils.ts │ │ │ │ ├── copy-link │ │ │ │ │ └── index.ts │ │ │ │ └── disable-search-link │ │ │ │ │ ├── disable-search-link-shadow.scss │ │ │ │ │ ├── disable-search-link.scss │ │ │ │ │ ├── index.md │ │ │ │ │ └── index.ts │ │ │ ├── dev-client │ │ │ │ ├── Action.vue │ │ │ │ ├── Widget.vue │ │ │ │ ├── client.ts │ │ │ │ ├── converter.ts │ │ │ │ ├── index.md │ │ │ │ ├── index.ts │ │ │ │ ├── options.ts │ │ │ │ ├── plugin.ts │ │ │ │ └── update-method.ts │ │ │ ├── download-audio │ │ │ │ ├── DownloadAudio.vue │ │ │ │ ├── audio-downloader.ts │ │ │ │ └── index.ts │ │ │ ├── image-exporter │ │ │ │ ├── Widget.vue │ │ │ │ ├── feed.ts │ │ │ │ ├── index.md │ │ │ │ └── index.ts │ │ │ ├── image-resolution │ │ │ │ ├── fix.scss │ │ │ │ ├── index.md │ │ │ │ ├── index.ts │ │ │ │ └── resolution.ts │ │ │ ├── import-series │ │ │ │ ├── index.ts │ │ │ │ └── logic.ts │ │ │ ├── ip-show │ │ │ │ └── index.ts │ │ │ ├── keymap │ │ │ │ ├── actions.ts │ │ │ │ ├── bindings.ts │ │ │ │ ├── help.md │ │ │ │ ├── index.ts │ │ │ │ ├── playback-tip.scss │ │ │ │ ├── presets.ts │ │ │ │ └── settings │ │ │ │ │ ├── ExtraOptions.vue │ │ │ │ │ ├── KeymapSettings.vue │ │ │ │ │ ├── KeymapSettingsRow.vue │ │ │ │ │ └── vm.ts │ │ │ ├── remove-promotions │ │ │ │ ├── index.md │ │ │ │ ├── index.ts │ │ │ │ └── remove-promotions.scss │ │ │ ├── subscribe-time-show │ │ │ │ ├── index.ts │ │ │ │ └── subscribe-time.scss │ │ │ ├── url-params-clean │ │ │ │ ├── index.md │ │ │ │ └── index.ts │ │ │ ├── v1-migrate │ │ │ │ ├── index.ts │ │ │ │ └── migrate.ts │ │ │ ├── view-cover │ │ │ │ ├── Plugin.vue │ │ │ │ ├── ViewCover.vue │ │ │ │ ├── index.ts │ │ │ │ └── types.ts │ │ │ └── watchlater-redirect │ │ │ │ ├── index.md │ │ │ │ └── index.ts │ │ └── video │ │ │ ├── auto-remove-watchlater │ │ │ ├── index.md │ │ │ └── index.ts │ │ │ ├── av-url │ │ │ └── index.ts │ │ │ ├── biliplus-redirect │ │ │ ├── BiliplusRedirect.vue │ │ │ └── index.ts │ │ │ ├── bvid-convert │ │ │ ├── BvidConvert.vue │ │ │ └── index.ts │ │ │ ├── danmaku │ │ │ ├── airborne │ │ │ │ ├── airborne.scss │ │ │ │ └── index.ts │ │ │ ├── converter │ │ │ │ ├── ass-danmaku.ts │ │ │ │ ├── danmaku-converter.md │ │ │ │ ├── danmaku-converter.ts │ │ │ │ ├── danmaku-data.ts │ │ │ │ ├── danmaku-segment.ts │ │ │ │ ├── danmaku-stack.ts │ │ │ │ ├── danmaku-type.ts │ │ │ │ └── xml-danmaku.ts │ │ │ ├── download │ │ │ │ ├── DownloadDanmaku.vue │ │ │ │ ├── Plugin.vue │ │ │ │ ├── danmaku.svg │ │ │ │ ├── index.ts │ │ │ │ ├── options.ts │ │ │ │ └── utils.ts │ │ │ ├── expand │ │ │ │ ├── index.md │ │ │ │ └── index.ts │ │ │ └── unescape │ │ │ │ ├── index.md │ │ │ │ └── index.ts │ │ │ ├── default-location │ │ │ ├── Advanced.vue │ │ │ ├── ExtendBox.vue │ │ │ ├── Options.vue │ │ │ ├── PageTypeSelector.vue │ │ │ ├── _bar.scss │ │ │ ├── _form.scss │ │ │ ├── desc.md │ │ │ └── index.ts │ │ │ ├── download │ │ │ ├── DownloadVideo.vue │ │ │ ├── Widget.vue │ │ │ ├── apis │ │ │ │ ├── dash.ts │ │ │ │ ├── flv.ts │ │ │ │ └── url.ts │ │ │ ├── error.ts │ │ │ ├── index.md │ │ │ ├── index.ts │ │ │ ├── inputs │ │ │ │ ├── EpisodesPicker.vue │ │ │ │ ├── bangumi │ │ │ │ │ └── batch.ts │ │ │ │ ├── episode-item.ts │ │ │ │ └── video │ │ │ │ │ ├── SingleVideoInfo.vue │ │ │ │ │ ├── batch.ts │ │ │ │ │ └── input.ts │ │ │ ├── outputs │ │ │ │ └── stream-saver.ts │ │ │ └── types.ts │ │ │ ├── full-description │ │ │ ├── full-description.scss │ │ │ └── index.ts │ │ │ ├── full-episode-title │ │ │ ├── full-episode-title.scss │ │ │ ├── index.md │ │ │ └── index.ts │ │ │ ├── metadata │ │ │ ├── Plugin.vue │ │ │ ├── SaveMetadata.vue │ │ │ ├── index.ts │ │ │ ├── metadata.ts │ │ │ └── options.ts │ │ │ ├── outer-watchlater │ │ │ ├── OuterWatchlater.vue │ │ │ ├── index.ts │ │ │ └── options.ts │ │ │ ├── player │ │ │ ├── auto-light │ │ │ │ ├── animation.ts │ │ │ │ └── index.ts │ │ │ ├── common │ │ │ │ ├── mini-rxjs │ │ │ │ │ ├── create.ts │ │ │ │ │ ├── index.ts │ │ │ │ │ ├── operators │ │ │ │ │ │ ├── bufferSet.ts │ │ │ │ │ │ ├── combineLatest.ts │ │ │ │ │ │ ├── debounceTime.ts │ │ │ │ │ │ ├── distinctUntilChanged.ts │ │ │ │ │ │ ├── filter.ts │ │ │ │ │ │ ├── map.ts │ │ │ │ │ │ ├── observeOn.ts │ │ │ │ │ │ ├── pairwise.ts │ │ │ │ │ │ ├── startWith.ts │ │ │ │ │ │ ├── tap.ts │ │ │ │ │ │ └── util │ │ │ │ │ │ │ └── index.ts │ │ │ │ │ ├── subject.ts │ │ │ │ │ ├── utils.ts │ │ │ │ │ └── utils │ │ │ │ │ │ ├── firstValueFrom.ts │ │ │ │ │ │ └── loadStyle.ts │ │ │ │ ├── speed.ts │ │ │ │ └── speed │ │ │ │ │ ├── context.ts │ │ │ │ │ └── utils.ts │ │ │ ├── control-background │ │ │ │ ├── control-background.scss │ │ │ │ └── index.ts │ │ │ ├── default-mode │ │ │ │ └── index.ts │ │ │ ├── disable-double-click-fullscreen │ │ │ │ ├── index.md │ │ │ │ └── index.ts │ │ │ ├── disable-scroll-volume │ │ │ │ ├── index.md │ │ │ │ └── index.ts │ │ │ ├── extend-speed │ │ │ │ ├── component.ts │ │ │ │ └── index.ts │ │ │ ├── focus │ │ │ │ ├── desc.md │ │ │ │ └── index.ts │ │ │ ├── intersection-actions │ │ │ │ └── index.ts │ │ │ ├── invert-scroll-volume │ │ │ │ ├── index.md │ │ │ │ └── index.ts │ │ │ ├── legacy-auto-play │ │ │ │ └── index.ts │ │ │ ├── preserve-danmaku-input │ │ │ │ ├── danmaku-input.scss │ │ │ │ └── index.ts │ │ │ ├── remember-speed │ │ │ │ ├── component.ts │ │ │ │ └── index.ts │ │ │ ├── remove-popup │ │ │ │ ├── index.md │ │ │ │ ├── index.ts │ │ │ │ └── remove-popup.scss │ │ │ ├── screenshot │ │ │ │ ├── VideoScreenshot.vue │ │ │ │ ├── VideoScreenshotContainer.vue │ │ │ │ ├── desc.md │ │ │ │ ├── index.ts │ │ │ │ └── screenshot.ts │ │ │ ├── seek-by-frames │ │ │ │ ├── desc.md │ │ │ │ ├── index.ts │ │ │ │ ├── seek-left.svg │ │ │ │ └── seek-right.svg │ │ │ ├── show-cover │ │ │ │ ├── cover.scss │ │ │ │ └── index.ts │ │ │ ├── show-upload-time │ │ │ │ ├── desc.md │ │ │ │ ├── index.ts │ │ │ │ └── show-upload-time.scss │ │ │ └── skip-charge-list │ │ │ │ ├── charge-list.scss │ │ │ │ └── index.ts │ │ │ ├── quick-favorite │ │ │ ├── QuickFavorite.vue │ │ │ ├── _font.scss │ │ │ ├── index.ts │ │ │ └── options.ts │ │ │ ├── seo-redirect │ │ │ └── index.ts │ │ │ └── subtitle │ │ │ ├── download │ │ │ ├── DownloadSubtitle.vue │ │ │ ├── Plugin.vue │ │ │ ├── cc-subtitle.svg │ │ │ ├── index.md │ │ │ ├── index.ts │ │ │ └── utils.ts │ │ │ └── subtitle-converter.ts │ ├── deprecated │ │ ├── README.md │ │ ├── auto-continue │ │ │ └── index.ts │ │ ├── auto-draw │ │ │ └── index.ts │ │ ├── comments-translate │ │ │ └── index.ts │ │ ├── download-records │ │ │ ├── DownloadRecords.vue │ │ │ └── index.ts │ │ ├── feeds-translate │ │ │ └── index.ts │ │ ├── i18n │ │ │ ├── en-US │ │ │ │ ├── data.ts │ │ │ │ └── index.ts │ │ │ └── ja-JP │ │ │ │ ├── data.ts │ │ │ │ └── index.ts │ │ ├── live-default-quality │ │ │ └── index.ts │ │ ├── pip │ │ │ ├── LivePip.vue │ │ │ └── index.ts │ │ ├── record-danmaku │ │ │ ├── DanmakuRecorder.vue │ │ │ ├── RecordDanmaku.vue │ │ │ └── index.ts │ │ ├── restore-floors │ │ │ └── index.ts │ │ ├── simplify-home │ │ │ ├── home.scss │ │ │ └── index.ts │ │ ├── turn-off-danmaku │ │ │ └── index.ts │ │ └── video-default-quality │ │ │ └── index.ts │ ├── docs │ │ ├── components-doc.ts │ │ ├── index.ts │ │ ├── packages-doc.ts │ │ ├── packages │ │ │ ├── cleaner.ts │ │ │ ├── downloader.ts │ │ │ └── starter.ts │ │ ├── plugins-doc.ts │ │ └── third-party.ts │ ├── id.ts │ └── plugins │ │ ├── feeds │ │ └── filter │ │ │ ├── hide-charge-feeds │ │ │ ├── index.md │ │ │ └── index.ts │ │ │ └── hide-goods │ │ │ ├── index.md │ │ │ └── index.ts │ │ ├── launch-bar │ │ ├── audio-search │ │ │ ├── index.md │ │ │ └── index.ts │ │ ├── bangumi-search │ │ │ ├── index.md │ │ │ └── index.ts │ │ ├── common.ts │ │ ├── cv-search │ │ │ ├── index.md │ │ │ └── index.ts │ │ ├── number-search │ │ │ ├── index.md │ │ │ └── index.ts │ │ ├── trending-search │ │ │ └── index.ts │ │ └── uid-search │ │ │ ├── index.md │ │ │ └── index.ts │ │ ├── settings-panel │ │ └── recent-components │ │ │ └── index.ts │ │ ├── style │ │ ├── custom-navbar-channel │ │ │ ├── NavbarChannel.vue │ │ │ └── index.ts │ │ ├── custom-navbar-dark-mode │ │ │ ├── NavbarDarkMode.vue │ │ │ └── index.ts │ │ └── custom-navbar-pgc │ │ │ └── index.ts │ │ ├── utils │ │ ├── keymap-dark-mode │ │ │ └── index.ts │ │ ├── keymap-empty-action.ts │ │ │ └── index.ts │ │ ├── keymap-toggle-danmaku-list │ │ │ └── index.ts │ │ ├── keymap-toggle-player-light │ │ │ └── index.ts │ │ └── keymap-toggle-subtitle │ │ │ └── index.ts │ │ ├── v-loading │ │ └── reimu │ │ │ ├── ReimuLoading.vue │ │ │ ├── image.css │ │ │ └── index.ts │ │ └── video │ │ ├── download │ │ ├── aria2-output │ │ │ ├── RpcConfig.vue │ │ │ ├── aria2-input.ts │ │ │ ├── aria2-rpc.ts │ │ │ ├── index.ts │ │ │ └── rpc-profiles.ts │ │ ├── empty-output │ │ │ ├── index.md │ │ │ └── index.ts │ │ ├── idm-output │ │ │ └── index.ts │ │ ├── manual-input │ │ │ ├── ManualInput.vue │ │ │ └── index.ts │ │ ├── motrix-output │ │ │ └── index.ts │ │ ├── mpv-output-ex │ │ │ ├── Config.vue │ │ │ ├── handler.ts │ │ │ ├── index.ts │ │ │ └── type.d.ts │ │ ├── mpv-output-playlist │ │ │ ├── MpvConfig.vue │ │ │ ├── index.ts │ │ │ └── mpv-playlist.ts │ │ ├── mpv-output │ │ │ └── index.ts │ │ └── wasm-output │ │ │ ├── Config.vue │ │ │ ├── database.ts │ │ │ ├── ffmpeg.ts │ │ │ ├── handler.ts │ │ │ ├── index.ts │ │ │ └── utils.ts │ │ └── player │ │ └── speed │ │ └── index.ts ├── package.json ├── pnpm-lock.yaml ├── tsconfig.json └── webpack │ ├── all.ts │ ├── build.ts │ ├── components.ts │ ├── config.ts │ ├── docs.ts │ └── plugins.ts ├── src ├── client │ ├── bilibili-evolved.meta.json │ ├── bilibili-evolved.preview.meta.json │ ├── bilibili-evolved.ts │ ├── check-iframes.ts │ ├── common.meta.json │ ├── compatibility.ts │ ├── init-vue.ts │ └── init.ts ├── components │ ├── SwitchOptions.vue │ ├── api.ts │ ├── auto-update │ │ ├── ExtraOptions.vue │ │ ├── checker.ts │ │ ├── index.ts │ │ └── utils.ts │ ├── bisector │ │ ├── DialogContent.vue │ │ ├── DialogTitle.vue │ │ ├── ResultToastContent.vue │ │ ├── api.ts │ │ ├── bisect.ts │ │ ├── index.ts │ │ └── options.ts │ ├── built-in-components.ts │ ├── compatibilities │ │ ├── index.md │ │ └── index.ts │ ├── component.ts │ ├── define.ts │ ├── description.ts │ ├── feeds │ │ ├── BangumiCard.vue │ │ ├── ColumnCard.vue │ │ ├── UpInfo.vue │ │ ├── VideoCard.vue │ │ ├── api │ │ │ ├── index.ts │ │ │ ├── manager │ │ │ │ ├── adaptor.ts │ │ │ │ ├── base.ts │ │ │ │ ├── index.ts │ │ │ │ ├── v1.ts │ │ │ │ └── v2.ts │ │ │ └── types.ts │ │ ├── bangumi-card.ts │ │ ├── column-card.ts │ │ ├── disable-profile-popup.ts │ │ ├── notify.ts │ │ └── video-card.ts │ ├── i18n │ │ ├── dom-translator.ts │ │ ├── helpers.ts │ │ ├── index.ts │ │ ├── machine-translator │ │ │ ├── MachineTranslator.vue │ │ │ └── translators.ts │ │ └── types.ts │ ├── launch-bar │ │ ├── ActionItem.vue │ │ ├── GlobalLaunchBar.vue │ │ ├── LaunchBar.vue │ │ ├── focus-target.ts │ │ ├── history-provider.ts │ │ ├── index.ts │ │ ├── launch-bar-action.ts │ │ ├── plugin.ts │ │ ├── search-provider.ts │ │ └── toggle.ts │ ├── live │ │ ├── live-control-bar.ts │ │ └── live-socket.ts │ ├── notify-new-version │ │ ├── ReleaseContent.vue │ │ ├── index.ts │ │ └── release-content.ts │ ├── settings-panel │ │ ├── ComponentDescription.vue │ │ ├── ComponentDetail.vue │ │ ├── ComponentOption.vue │ │ ├── ComponentSettings.vue │ │ ├── ComponentTags.vue │ │ ├── SettingsContainer.vue │ │ ├── SettingsPanel.vue │ │ ├── TagRing.vue │ │ ├── WidgetsPanel.vue │ │ ├── component-actions │ │ │ ├── ComponentAction.vue │ │ │ └── component-actions.ts │ │ ├── dock.ts │ │ ├── dock │ │ │ ├── _center.scss │ │ │ ├── _left.scss │ │ │ └── _right.scss │ │ ├── dropdown.ts │ │ ├── external-actions.ts │ │ ├── index.en-US.md │ │ ├── index.en-US.ts │ │ ├── index.md │ │ ├── index.ts │ │ ├── mixins.ts │ │ ├── search-bar-actions.ts │ │ ├── sub-pages │ │ │ ├── AboutPage.vue │ │ │ ├── UserComponentsPage.vue │ │ │ ├── UserPluginsPage.vue │ │ │ ├── UserStylesPage.vue │ │ │ ├── about-page.ts │ │ │ ├── index.ts │ │ │ ├── manage-panel │ │ │ │ ├── ManageItem.vue │ │ │ │ ├── ManagePanel.vue │ │ │ │ ├── UserItem.vue │ │ │ │ └── manage-panel.ts │ │ │ └── online-registry │ │ │ │ ├── OnlineRegistry.vue │ │ │ │ ├── OnlineRegistryButton.vue │ │ │ │ ├── RegistryItem.vue │ │ │ │ ├── item-filter.ts │ │ │ │ ├── third-party.ts │ │ │ │ └── vm.ts │ │ └── tag-filter.ts │ ├── styled-component.ts │ ├── switch-options-old.ts │ ├── switch-options.ts │ ├── types.ts │ ├── user-component.ts │ ├── utils │ │ ├── categories │ │ │ ├── data.ts │ │ │ ├── icons.svg │ │ │ ├── raw.json │ │ │ ├── tid-v2.json │ │ │ └── updater.ts │ │ ├── comment-apis.ts │ │ └── comment │ │ │ ├── areas │ │ │ ├── base.ts │ │ │ ├── dom.ts │ │ │ ├── v1.ts │ │ │ ├── v2.ts │ │ │ └── v3.ts │ │ │ ├── comment-area-manager.ts │ │ │ ├── comment-area.ts │ │ │ ├── comment-item.ts │ │ │ ├── reply-item.ts │ │ │ ├── types.ts │ │ │ └── vnode-manager.ts │ ├── video │ │ ├── VideoControlBar.vue │ │ ├── ass-utils.ts │ │ ├── player-adaptor │ │ │ ├── bpx.ts │ │ │ ├── events.ts │ │ │ ├── index.ts │ │ │ ├── v2.ts │ │ │ ├── v3.ts │ │ │ └── v4.ts │ │ ├── player-agent │ │ │ ├── bangumi-player.ts │ │ │ ├── base.ts │ │ │ ├── bpx.ts │ │ │ ├── index.ts │ │ │ ├── live-player.ts │ │ │ ├── types.ts │ │ │ ├── video-player-v2.ts │ │ │ └── video-player.ts │ │ ├── player-light.ts │ │ ├── video-actions.ts │ │ ├── video-context-menu.ts │ │ ├── video-control-bar.ts │ │ ├── video-cover.ts │ │ ├── video-danmaku.ts │ │ ├── video-info.ts │ │ ├── video-quality.ts │ │ ├── watchlater.ts │ │ └── xml-utils.ts │ └── widget.ts ├── core │ ├── ajax.ts │ ├── cdn-types.ts │ ├── common-types.ts │ ├── container-query.ts │ ├── core-apis.ts │ ├── dialog │ │ ├── Dialog.vue │ │ └── index.ts │ ├── download-mode.ts │ ├── download.ts │ ├── external-input │ │ ├── index.ts │ │ └── load-feature-code.ts │ ├── file-picker.ts │ ├── horizontal-scroll.ts │ ├── install-feature.ts │ ├── life-cycle.ts │ ├── loading-mode.ts │ ├── local-storage.ts │ ├── meta.ts │ ├── observer.ts │ ├── performance │ │ ├── component-trace.ts │ │ ├── plugin-trace.ts │ │ ├── promise-trace.ts │ │ └── stats.ts │ ├── reorder.ts │ ├── runtime-library.ts │ ├── settings │ │ ├── helpers.ts │ │ ├── index.ts │ │ ├── internal-state.ts │ │ ├── listener.ts │ │ ├── proxy.ts │ │ ├── read.ts │ │ ├── types.ts │ │ └── write.ts │ ├── shadow-root │ │ ├── dom-entry.ts │ │ ├── dom-observer.ts │ │ ├── index.ts │ │ ├── root-observer.ts │ │ ├── styles.ts │ │ └── types.ts │ ├── spin-query.ts │ ├── style.ts │ ├── text-color.ts │ ├── theme-color │ │ ├── image-filter.ts │ │ ├── index.ts │ │ └── palette.json │ ├── toast │ │ ├── MiniToast.vue │ │ ├── ToastCard.vue │ │ ├── ToastCardContainer.vue │ │ ├── index.ts │ │ ├── mini.scss │ │ └── mini.ts │ ├── user-info.ts │ ├── utils │ │ ├── constants.ts │ │ ├── formatters.ts │ │ ├── i18n.ts │ │ ├── index.ts │ │ ├── lazy-panel.ts │ │ ├── log.ts │ │ ├── sort.ts │ │ ├── title.ts │ │ └── urls.ts │ └── version.ts ├── global.d.ts ├── plugins │ ├── api.ts │ ├── data.ts │ ├── hook.ts │ ├── id-search │ │ ├── index.ts │ │ └── types.ts │ ├── plugin.ts │ └── style.ts ├── shims.d.ts ├── third-party │ └── pako-inflate │ │ ├── index.d.ts │ │ └── index.js └── ui │ ├── AsyncButton.vue │ ├── CheckBox.vue │ ├── ColorPicker.vue │ ├── DefaultWidget.vue │ ├── DpiImage.vue │ ├── ImagePicker.vue │ ├── ImageViewer.vue │ ├── InfiniteScroll.vue │ ├── ProgressBar.vue │ ├── ProgressRing.vue │ ├── RadioButton.vue │ ├── RangeInput.vue │ ├── ScrollTrigger.vue │ ├── SwitchBox.vue │ ├── TabControl.vue │ ├── TextArea.vue │ ├── TextBox.vue │ ├── VButton.vue │ ├── VDropdown.vue │ ├── VEmpty.vue │ ├── VLoading.vue │ ├── VPopup.vue │ ├── VSlider.vue │ ├── _common.scss │ ├── _effects.scss │ ├── _markdown.scss │ ├── _tabs.scss │ ├── color-picker-wrapper.ts │ ├── icon │ ├── VIcon.vue │ ├── _bilifont.scss │ ├── _vanfont.scss │ ├── custom │ │ ├── biliplus.svg │ │ ├── lv6-plus.svg │ │ ├── settings-outline.svg │ │ └── widgets.svg │ └── index.ts │ ├── image-store.ts │ ├── image-viewer.ts │ ├── index.ts │ ├── mdi │ ├── index.ts │ ├── mdi.css │ └── mdi.woff2 │ ├── range.ts │ ├── tab-mapping.ts │ ├── text-control.ts │ ├── v-empty.ts │ └── v-loading.ts ├── tsconfig.json ├── tsconfig.type-check.json └── webpack ├── cdn ├── github.ts ├── index.ts ├── jsdelivr.ts └── types.ts ├── compilation-info ├── git.ts ├── index.ts ├── runtime.ts └── source-diff.ts ├── inject-metadata ├── core-info.ts ├── description.ts ├── i18n.ts ├── index.ts └── types.ts ├── loaders ├── style-loaders.ts └── ts-loader.ts ├── webpack.config.ts ├── webpack.dev.ts └── webpack.prod.ts /.browserslistrc: -------------------------------------------------------------------------------- 1 | > 1% 2 | last 2 versions 3 | not dead 4 | chrome > 105 5 | edge > 105 6 | firefox > 127 7 | safari > 15.4 8 | not and_chr > 0 9 | not and_ff > 0 10 | not and_qq > 0 11 | not and_uc > 0 12 | not android > 0 13 | not baidu > 0 14 | not ios_saf > 0 15 | not kaios > 0 16 | not op_mob > 0 17 | not op_mini all 18 | not samsung > 0 19 | not ie > 0 -------------------------------------------------------------------------------- /.editorconfig: -------------------------------------------------------------------------------- 1 | # EditorConfig is awesome: https://EditorConfig.org 2 | 3 | # top-most EditorConfig file 4 | root = true 5 | 6 | # Tab indentation 7 | [*] 8 | indent_style = space 9 | indent_size = 2 10 | end_of_line = lf 11 | charset = utf-8 12 | trim_trailing_whitespace = true 13 | quote_type = single -------------------------------------------------------------------------------- /.eslintignore: -------------------------------------------------------------------------------- 1 | packages/ 2 | typings/ 3 | **/dist/ 4 | dev/ 5 | node_modules/ 6 | !.github-json/ 7 | .eslintrc.* 8 | -------------------------------------------------------------------------------- /.gitattributes: -------------------------------------------------------------------------------- 1 | * text=auto -------------------------------------------------------------------------------- /.github-json/README.md: -------------------------------------------------------------------------------- 1 | # Fuck YAML 2 | 3 | 在项目根目录使用 `pnpm build-github-config` 来生成 GitHub 相关配置. 4 | -------------------------------------------------------------------------------- /.github-json/data/FUNDING.json: -------------------------------------------------------------------------------- 1 | { 2 | "github": null, 3 | "patreon": null, 4 | "open_collective": null, 5 | "ko_fi": null, 6 | "tidelift": null, 7 | "community_bridge": null, 8 | "liberapay": null, 9 | "issuehunt": null, 10 | "otechie": null, 11 | "lfx_crowdfunding": null, 12 | "custom": [ 13 | "https://github.com/the1812/Bilibili-Evolved/blob/preview/doc/donate.md" 14 | ] 15 | } -------------------------------------------------------------------------------- /.github/DISCUSSION_TEMPLATE/功能建议-ideas.yml: -------------------------------------------------------------------------------- 1 | title: 功能建议 2 | labels: [] 3 | body: 4 | - type: markdown 5 | attributes: 6 | value: | 7 | 默认您已阅读 [常见问题解答](https://github.com/the1812/Bilibili-Evolved/discussions/1301) 8 | 请勿重复发起, 发之前记得搜索一下. 如果需要反馈 Bug, 请前往 [Issues](https://github.com/the1812/Bilibili-Evolved/issues) 发起. 9 | - type: textarea 10 | id: description 11 | attributes: 12 | label: 期望的效果 13 | description: 描述你遇到的问题, 以及建议的解决方式 14 | placeholder: 请输入 15 | validations: 16 | required: true 17 | - type: input 18 | id: script-version 19 | attributes: 20 | label: 脚本版本 21 | description: 可在设置面板的关于弹窗中找到脚本版本信息 22 | placeholder: 请输入 23 | validations: 24 | required: true 25 | -------------------------------------------------------------------------------- /.github/FUNDING.yml: -------------------------------------------------------------------------------- 1 | github: 2 | patreon: 3 | open_collective: 4 | ko_fi: 5 | tidelift: 6 | community_bridge: 7 | liberapay: 8 | issuehunt: 9 | otechie: 10 | lfx_crowdfunding: 11 | custom: 12 | - https://github.com/the1812/Bilibili-Evolved/blob/preview/doc/donate.md 13 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/config.yml: -------------------------------------------------------------------------------- 1 | blank_issues_enabled: false 2 | contact_links: 3 | - name: 转到讨论区 4 | url: https://github.com/the1812/Bilibili-Evolved/discussions 5 | about: Issues 用于反馈 Bug, 新的功能建议和提问答疑请到讨论区发起 6 | - name: 查看 Issues 须知 7 | url: https://github.com/the1812/Bilibili-Evolved/blob/preview/doc/issue-rules.md 8 | about: 默认所有 Issues 发起者均已了解此处的内容 9 | - name: 查看讨论区指南 10 | url: https://github.com/the1812/Bilibili-Evolved/discussions/1297 11 | about: 默认所有讨论发起者均已了解此处的内容 12 | - name: 查看置顶问题 13 | url: https://github.com/the1812/Bilibili-Evolved/issues 14 | about: 在 Pinned issues 中会包含一些近期常见问题, 已有的其他问题也会在下面列出, 请务必查看避免重复发起 15 | - name: 查看常见问题 16 | url: https://github.com/the1812/Bilibili-Evolved/discussions/1301 17 | about: 一些老生常谈的问题, 或许里面就有你想问的 18 | -------------------------------------------------------------------------------- /.github/pull_request_template.md: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /.github/workflows/pull-request-check.yml: -------------------------------------------------------------------------------- 1 | name: Pull Request Check 2 | on: 3 | - pull_request 4 | jobs: 5 | check: 6 | runs-on: ubuntu-latest 7 | steps: 8 | - uses: actions/checkout@v3 9 | with: 10 | ref: ${{ github.event.pull_request.head.sha }} 11 | - name: Install dependencies 12 | uses: pnpm/action-setup@v4 13 | with: 14 | run_install: true 15 | - name: Type check 16 | run: pnpm run type 17 | - name: ESLint check 18 | run: pnpm run lint-check 19 | - name: Build core 20 | run: pnpm run build-core 21 | - name: Build features 22 | run: | 23 | cd registry 24 | pnpm install 25 | cd ../ 26 | pnpm run build-features 27 | - name: Log 28 | run: echo Check complete. 29 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | .DS_Store 2 | node_modules/ 3 | *.backup.* 4 | dev/ 5 | *.log 6 | dist/stats.html 7 | dist/profile.json 8 | dist/bilibili-evolved.dev.user.js 9 | registry/dist/doc.js 10 | dev-tools/**/dist/ 11 | .idea 12 | -------------------------------------------------------------------------------- /.prettierrc: -------------------------------------------------------------------------------- 1 | { 2 | "semi": false, 3 | "singleQuote": true, 4 | "trailingComma": "all", 5 | "arrowParens": "avoid", 6 | "endOfLine": "auto", 7 | "printWidth": 100 8 | } -------------------------------------------------------------------------------- /.vscode/launch.json: -------------------------------------------------------------------------------- 1 | { 2 | // Use IntelliSense to learn about possible attributes. 3 | // Hover to view descriptions of existing attributes. 4 | // For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387 5 | "version": "0.2.0", 6 | "configurations": [ 7 | ] 8 | } -------------------------------------------------------------------------------- /dev-tools/dev-server/config.ts: -------------------------------------------------------------------------------- 1 | import { readFileSync, existsSync } from 'fs' 2 | 3 | interface DevServerConfig { 4 | port?: number 5 | maxWatchers?: number 6 | } 7 | const configFile = (path: string) => () => 8 | existsSync(path) ? JSON.parse(readFileSync(path, { encoding: 'utf-8' })) : {} 9 | const configSource: (() => DevServerConfig)[] = [ 10 | () => ({ 11 | port: 23333, 12 | maxWatchers: 16, 13 | }), 14 | configFile('dev/dev-server.json'), 15 | ] 16 | export const devServerConfig = configSource.reduce( 17 | (previous, current) => ({ ...previous, ...current() }), 18 | {} as DevServerConfig, 19 | ) 20 | -------------------------------------------------------------------------------- /dev-tools/dev-server/index.ts: -------------------------------------------------------------------------------- 1 | import { startDevServer } from './server' 2 | import { startCoreWatcher } from './core-watcher' 3 | import { startWebSocketServer } from './web-socket-server' 4 | 5 | startDevServer().then(server => { 6 | startCoreWatcher() 7 | startWebSocketServer(server) 8 | }) 9 | -------------------------------------------------------------------------------- /dev-tools/dev-server/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "../../tsconfig.json", 3 | "compilerOptions": { 4 | "module": "CommonJS", 5 | "noEmit": true, 6 | } 7 | } -------------------------------------------------------------------------------- /dev-tools/donate-table/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "donate-table", 3 | "version": "1.0.0", 4 | "main": "index.ts", 5 | "author": "Grant Howard", 6 | "license": "MIT", 7 | "private": true, 8 | "dependencies": { 9 | "csv-parse": "5.6.0" 10 | }, 11 | "devDependencies": { 12 | "@types/node": "^22", 13 | "tsx": "4.19.4", 14 | "typescript": "5.8.3" 15 | }, 16 | "packageManager": "pnpm@10.3.0+sha512.ee592eda8815a8a293c206bb0917c4bb0ff274c50def7cbc17be05ec641fc2d1b02490ce660061356bd0d126a4d7eb2ec8830e6959fb8a447571c631d5a2442d", 17 | "pnpm": { 18 | "onlyBuiltDependencies": [ 19 | "esbuild" 20 | ] 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /dev-tools/donate-table/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "target": "ESNext", 4 | "esModuleInterop": true, 5 | "module": "commonjs", 6 | "strict": true, 7 | "sourceMap": false, 8 | "skipLibCheck": true 9 | }, 10 | "include": [ 11 | "index.ts" 12 | ] 13 | } 14 | -------------------------------------------------------------------------------- /doc/release-checklist.md: -------------------------------------------------------------------------------- 1 | # 发版流程 2 | 3 | ## 正式版 4 | - 编写 change log 5 | - 更新版本号, 打上 tag 6 | - 更新 donate.md 7 | - 生成文档 8 | - 带 tag 推送 9 | - 测下 Firefox + Violentmonkey 10 | 11 | ## 预览版 12 | - 更新版本号, 打上 tag 13 | - 生成文档 14 | - 带 tag 推送 15 | - 测下 Edge + Tampermonkey 16 | -------------------------------------------------------------------------------- /docs/README.md: -------------------------------------------------------------------------------- 1 | **预留给 Github Pages 的文件夹** 2 | 3 | 文档请放至 `doc` 文件夹 -------------------------------------------------------------------------------- /docs/static/mdi/mdi.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/the1812/Bilibili-Evolved/3bfd9f583104b986298a46722e40401f505d4076/docs/static/mdi/mdi.woff2 -------------------------------------------------------------------------------- /images/compressed/afdian.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/the1812/Bilibili-Evolved/3bfd9f583104b986298a46722e40401f505d4076/images/compressed/afdian.jpg -------------------------------------------------------------------------------- /images/compressed/wechat.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/the1812/Bilibili-Evolved/3bfd9f583104b986298a46722e40401f505d4076/images/compressed/wechat.jpg -------------------------------------------------------------------------------- /images/logo-small.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/the1812/Bilibili-Evolved/3bfd9f583104b986298a46722e40401f505d4076/images/logo-small.png -------------------------------------------------------------------------------- /images/logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/the1812/Bilibili-Evolved/3bfd9f583104b986298a46722e40401f505d4076/images/logo.png -------------------------------------------------------------------------------- /images/v2/about-panel.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/the1812/Bilibili-Evolved/3bfd9f583104b986298a46722e40401f505d4076/images/v2/about-panel.jpg -------------------------------------------------------------------------------- /images/v2/manage-panel.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/the1812/Bilibili-Evolved/3bfd9f583104b986298a46722e40401f505d4076/images/v2/manage-panel.jpg -------------------------------------------------------------------------------- /images/v2/settings-panel.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/the1812/Bilibili-Evolved/3bfd9f583104b986298a46722e40401f505d4076/images/v2/settings-panel.jpg -------------------------------------------------------------------------------- /images/v2/side-panel.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/the1812/Bilibili-Evolved/3bfd9f583104b986298a46722e40401f505d4076/images/v2/side-panel.jpg -------------------------------------------------------------------------------- /registry/dist/components/video/player/common/mini-rxjs.js: -------------------------------------------------------------------------------- 1 | !function(e,o){"object"==typeof exports&&"object"==typeof module?module.exports=o():"function"==typeof define&&define.amd?define([],o):"object"==typeof exports?exports["video/player/common/mini-rxjs"]=o():e["video/player/common/mini-rxjs"]=o()}(globalThis,(()=>(()=>{"use strict";var e={};coreApis.settings;return e=e.component})())); -------------------------------------------------------------------------------- /registry/dist/components/video/player/common/mini-rxjs/operators/util.js: -------------------------------------------------------------------------------- 1 | !function(e,o){"object"==typeof exports&&"object"==typeof module?module.exports=o():"function"==typeof define&&define.amd?define([],o):"object"==typeof exports?exports["video/player/common/mini-rxjs/operators/util"]=o():e["video/player/common/mini-rxjs/operators/util"]=o()}(globalThis,(()=>(()=>{"use strict";var e={};return e=e.component})())); -------------------------------------------------------------------------------- /registry/dist/components/video/seo-redirect.js: -------------------------------------------------------------------------------- 1 | !function(e,o){"object"==typeof exports&&"object"==typeof module?module.exports=o():"function"==typeof define&&define.amd?define([],o):"object"==typeof exports?exports["video/seo-redirect"]=o():e["video/seo-redirect"]=o()}(globalThis,(()=>(()=>{"use strict";var e={d:(o,t)=>{for(var i in t)e.o(t,i)&&!e.o(o,i)&&Object.defineProperty(o,i,{enumerable:!0,get:t[i]})},o:(e,o)=>Object.prototype.hasOwnProperty.call(e,o)},o={};e.d(o,{component:()=>t});const t=(0,coreApis.componentApis.define.defineComponentMetadata)({name:"seoRedirect",displayName:"SEO 页面重定向",entry:()=>{window.location.assign(document.URL.replace("/s/","/"))},urlInclude:["//www.bilibili.com/s/video/"],tags:[componentsTags.video],description:{"zh-CN":"进入 SEO 视频页面时 (`https://www.bilibili.com/s/video/`) 自动跳转到原视频页面."},commitHash:"e4dd22d0dc497b9ba31e5bd374117e68c52eb0cb",coreVersion:"2.10.2"});return o=o.component})())); -------------------------------------------------------------------------------- /registry/dist/plugins/utils/keymap-dark-mode.js: -------------------------------------------------------------------------------- 1 | !function(e,o){"object"==typeof exports&&"object"==typeof module?module.exports=o():"function"==typeof define&&define.amd?define([],o):"object"==typeof exports?exports["utils/keymap-dark-mode"]=o():e["utils/keymap-dark-mode"]=o()}(globalThis,(()=>(()=>{"use strict";var e={d:(o,t)=>{for(var d in t)e.o(t,d)&&!e.o(o,d)&&Object.defineProperty(o,d,{enumerable:!0,get:t[d]})},o:(e,o)=>Object.prototype.hasOwnProperty.call(e,o)},o={};e.d(o,{plugin:()=>t});const t={name:"keymap.actions.darkMode",displayName:"快捷键扩展 - 夜间模式",description:'在快捷键的动作列表里添加一个 "夜间模式", 可以通过快捷键切换夜间模式',setup:e=>{let{addData:o,coreApis:{settings:t}}=e;o("keymap.actions",(e=>{e.darkMode={displayName:"夜间模式",run:()=>{const e=t.getComponentSettings("darkMode");e.enabled=!e.enabled}}})),o("keymap.presets",(e=>{e.darkMode=""}))},commitHash:"e4dd22d0dc497b9ba31e5bd374117e68c52eb0cb",coreVersion:"2.10.2"};return o=o.plugin})())); -------------------------------------------------------------------------------- /registry/dist/plugins/utils/keymap-empty-action.ts.js: -------------------------------------------------------------------------------- 1 | !function(e,t){"object"==typeof exports&&"object"==typeof module?module.exports=t():"function"==typeof define&&define.amd?define([],t):"object"==typeof exports?exports["utils/keymap-empty-action.ts"]=t():e["utils/keymap-empty-action.ts"]=t()}(globalThis,(()=>(()=>{"use strict";var e={d:(t,o)=>{for(var p in o)e.o(o,p)&&!e.o(t,p)&&Object.defineProperty(t,p,{enumerable:!0,get:o[p]})},o:(e,t)=>Object.prototype.hasOwnProperty.call(e,t)},t={};e.d(t,{plugin:()=>o});const o={name:"keymap.actions.empty",displayName:"快捷键扩展 - 无动作",description:'在快捷键的动作列表里添加一个 "无动作", 将按键绑定到这个上面就可以阻止原有的快捷键行为.',setup:e=>{let{addData:t}=e;t("keymap.actions",(e=>{e.empty={displayName:"无动作",prevent:!0,run:none}})),t("keymap.presets",(e=>{e.empty=""}))},commitHash:"e4dd22d0dc497b9ba31e5bd374117e68c52eb0cb",coreVersion:"2.10.2"};return t=t.plugin})())); -------------------------------------------------------------------------------- /registry/lib/components/feeds/_feeds-panel-shared.scss: -------------------------------------------------------------------------------- 1 | @import 'common'; 2 | 3 | .live-up-list { 4 | // 默认状态 5 | max-height: calc(100vh - 315px); 6 | // 开启过滤器 7 | body.enable-feeds-filter & { 8 | max-height: calc(100vh - 370px); 9 | } 10 | // 禁掉 profile 后 11 | body.feeds-filter-side-block-profile & { 12 | max-height: calc(100vh - 180px); 13 | } 14 | } 15 | .bili-dyn-live-users { 16 | display: flex !important; 17 | flex-direction: column !important; 18 | } 19 | .bili-dyn-live-users__body { 20 | @include no-scrollbar(); 21 | margin: 0px -16px -16px -16px; 22 | padding: 0px 16px 4px 16px; 23 | // 默认状态 24 | max-height: calc(100vh - 318px); 25 | // 开启过滤器 26 | body.enable-feeds-filter & { 27 | max-height: calc(100vh - 374px); 28 | } 29 | // 禁掉 profile 后 30 | body.feeds-filter-side-block-profile & { 31 | max-height: calc(100vh - 178px); 32 | } 33 | } 34 | -------------------------------------------------------------------------------- /registry/lib/components/feeds/del-feeds/index.md: -------------------------------------------------------------------------------- 1 | 删除动态, 可选转发抽奖, 和全部删除. 2 | -------------------------------------------------------------------------------- /registry/lib/components/feeds/del-feeds/index.ts: -------------------------------------------------------------------------------- 1 | import { defineComponentMetadata } from '@/components/define' 2 | import { getUID } from '@/core/utils' 3 | 4 | export const component = defineComponentMetadata({ 5 | name: 'deleteFeeds', 6 | displayName: '删除动态', 7 | tags: [componentsTags.feeds], 8 | description: { 9 | 'zh-CN': `删除动态, 可选转发抽奖(不会删除自己中奖的动态), 和全部删除.`, 10 | }, 11 | entry: none, 12 | urlInclude: [`https://space.bilibili.com/${getUID()}/dynamic`], 13 | widget: { 14 | component: () => import('./Widget.vue').then(m => m.default), 15 | }, 16 | }) 17 | -------------------------------------------------------------------------------- /registry/lib/components/feeds/disable-details/disable-details.scss: -------------------------------------------------------------------------------- 1 | @mixin details() { 2 | .details { 3 | color: #222; 4 | font-size: 12px; 5 | opacity: 0.6; 6 | cursor: pointer; 7 | display: block; 8 | line-height: 22px; 9 | body.dark & { 10 | color: #eee; 11 | } 12 | } 13 | } 14 | [data-module='desc'][data-orig], 15 | .card[data-did] .content { 16 | cursor: text; 17 | @include details(); 18 | } 19 | .bili-rich-text-module { 20 | &.at { 21 | cursor: pointer; 22 | } 23 | } 24 | 25 | .dyn-card-opus { 26 | &__summary { 27 | cursor: text; 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /registry/lib/components/feeds/disable-details/init.scss: -------------------------------------------------------------------------------- 1 | .card[data-did] .content .details { 2 | display: none; 3 | } 4 | -------------------------------------------------------------------------------- /registry/lib/components/feeds/extend-live/extend-feeds-live.scss: -------------------------------------------------------------------------------- 1 | .live-up-list, 2 | .bili-dyn-home--member .bili-dyn-live-users { 3 | display: none !important; 4 | } 5 | -------------------------------------------------------------------------------- /registry/lib/components/feeds/extend-live/index.md: -------------------------------------------------------------------------------- 1 | 替换动态的 `正在直播` 面板, 能够显示超过 10 个的直播间. 2 | -------------------------------------------------------------------------------- /registry/lib/components/feeds/filter/index.md: -------------------------------------------------------------------------------- 1 | 按照类型或者关键词过滤动态首页的内容, 也可以移除动态页的一些侧边卡片. 详细设置请前往[动态首页](https://t.bilibili.com/)查看. 2 | 3 | > 侧边卡片的 `正在直播` 指原版的板块, 如果你使用了 `直播信息扩充`, 则需要关闭该功能才能生效. 4 | -------------------------------------------------------------------------------- /registry/lib/components/feeds/filter/options.ts: -------------------------------------------------------------------------------- 1 | import { OptionsOfMetadata, defineOptionsMetadata } from '@/components/define' 2 | 3 | export const options = defineOptionsMetadata({ 4 | types: { 5 | defaultValue: [] as number[], 6 | displayName: '过滤动态类型', 7 | hidden: true, 8 | }, 9 | patterns: { 10 | defaultValue: [] as string[], 11 | displayName: '过滤关键词', 12 | hidden: true, 13 | }, 14 | sideCards: { 15 | /** FIXME: 虽然代码里按照`number[]`, 但其实存进去的是`string[]`? */ 16 | defaultValue: [] as number[], 17 | displayName: '过滤侧边栏', 18 | hidden: true, 19 | }, 20 | specialTypes: { 21 | defaultValue: [] as number[], 22 | displayName: '过滤特殊动态类型', 23 | hidden: true, 24 | }, 25 | }) 26 | 27 | export type FeedsFilterOptions = OptionsOfMetadata 28 | -------------------------------------------------------------------------------- /registry/lib/components/feeds/filter/pattern.ts: -------------------------------------------------------------------------------- 1 | const testPattern = (pattern: string, text: string) => { 2 | if (!pattern || !text) { 3 | return false 4 | } 5 | if (pattern.startsWith('/') && pattern.endsWith('/')) { 6 | return new RegExp(pattern.slice(1, pattern.length - 1)).test(text) 7 | } 8 | return text.includes(pattern) 9 | } 10 | export interface BlockableCard { 11 | text: string 12 | username: string 13 | // [key: string]: string 14 | } 15 | export const hasBlockedPattern = (pattern: string, card: BlockableCard) => { 16 | const upNameMatch = pattern.match(/(.+) up:([^ ]+)/) 17 | if (upNameMatch) { 18 | return testPattern(upNameMatch[1], card.text) && testPattern(upNameMatch[2], card.username) 19 | } 20 | return testPattern(pattern, card.text) 21 | } 22 | -------------------------------------------------------------------------------- /registry/lib/components/feeds/fixed-sidebars/index.ts: -------------------------------------------------------------------------------- 1 | import { defineComponentMetadata } from '@/components/define' 2 | 3 | const id = 'fixed-sidebars-style' 4 | const entry = async () => { 5 | const { disableProfilePopup } = await import('@/components/feeds/disable-profile-popup') 6 | disableProfilePopup() 7 | } 8 | 9 | export const component = defineComponentMetadata({ 10 | name: 'fixedFeedsSidebars', 11 | instantStyles: [ 12 | { 13 | name: id, 14 | style: () => import('./fixed-sidebars.scss'), 15 | important: true, 16 | }, 17 | ], 18 | displayName: '强制固定动态侧栏', 19 | description: { 20 | 'zh-CN': '强制固定动态主页的顶栏和所有侧栏.', 21 | }, 22 | tags: [componentsTags.feeds], 23 | entry, 24 | urlInclude: [/^https:\/\/t\.bilibili\.com\/$/], 25 | }) 26 | -------------------------------------------------------------------------------- /registry/lib/components/feeds/fold-comments/fold-comment-shadow.scss: -------------------------------------------------------------------------------- 1 | :host(bili-comments) { 2 | #end .bottombar { 3 | padding-bottom: 8px !important; 4 | } 5 | } 6 | -------------------------------------------------------------------------------- /registry/lib/components/feeds/full-content/full-content.scss: -------------------------------------------------------------------------------- 1 | .bili-rich-text__content.folded { 2 | -webkit-line-clamp: unset !important; 3 | display: block !important; 4 | height: auto !important; 5 | max-height: unset !important; 6 | ~ .bili-rich-text__action { 7 | display: none !important; 8 | } 9 | } 10 | .card .main-content { 11 | .expand-btn, 12 | .content-ellipsis { 13 | display: none !important; 14 | } 15 | .content-full { 16 | -webkit-line-clamp: unset !important; 17 | display: block !important; 18 | height: auto !important; 19 | max-height: unset !important; 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /registry/lib/components/feeds/full-content/index.md: -------------------------------------------------------------------------------- 1 | 不管内容多长, 总是完全展开动态的内容. (专栏不算) 2 | -------------------------------------------------------------------------------- /registry/lib/components/feeds/full-content/index.ts: -------------------------------------------------------------------------------- 1 | import { defineComponentMetadata } from '@/components/define' 2 | import { feedsUrlsWithoutDetail } from '@/core/utils/urls' 3 | 4 | export const component = defineComponentMetadata({ 5 | name: 'fullFeedsContent', 6 | instantStyles: [ 7 | { 8 | name: 'full-feeds-content', 9 | style: () => import('./full-content.scss'), 10 | }, 11 | ], 12 | displayName: '展开动态内容', 13 | tags: [componentsTags.style, componentsTags.feeds], 14 | urlInclude: feedsUrlsWithoutDetail, 15 | entry: none, 16 | }) 17 | -------------------------------------------------------------------------------- /registry/lib/components/feeds/full-title/full-feeds-title.scss: -------------------------------------------------------------------------------- 1 | .custom-navbar .video-card .title { 2 | max-height: unset !important; 3 | display: block !important; 4 | } 5 | -------------------------------------------------------------------------------- /registry/lib/components/feeds/full-title/index.ts: -------------------------------------------------------------------------------- 1 | import { defineComponentMetadata } from '@/components/define' 2 | import { toggleStyle } from '@/components/styled-component' 3 | 4 | export const component = defineComponentMetadata({ 5 | ...toggleStyle('fullFeedsTitle', () => import('./full-feeds-title.scss')), 6 | displayName: '展开动态标题', 7 | description: { 8 | 'zh-CN': '在顶栏的视频动态中, 无论标题多长总是完全展开.', 9 | }, 10 | tags: [componentsTags.feeds, componentsTags.style], 11 | }) 12 | -------------------------------------------------------------------------------- /registry/lib/components/feeds/hide-comment-preview/hide-comment-preview.scss: -------------------------------------------------------------------------------- 1 | .bili-dyn-item__interaction { 2 | display: none !important; 3 | } 4 | -------------------------------------------------------------------------------- /registry/lib/components/feeds/hide-comment-preview/index.md: -------------------------------------------------------------------------------- 1 | 隐藏动态评论按钮上方的精选评论预览. (详细可看 [#3322](https://github.com/the1812/Bilibili-Evolved/discussions/3322)) 2 | -------------------------------------------------------------------------------- /registry/lib/components/feeds/hide-comment-preview/index.ts: -------------------------------------------------------------------------------- 1 | import { defineComponentMetadata } from '@/components/define' 2 | 3 | const name = 'hideFeedsCommentPreview' 4 | export const component = defineComponentMetadata({ 5 | name, 6 | tags: [componentsTags.feeds, componentsTags.style], 7 | displayName: '隐藏动态评论预览', 8 | entry: none, 9 | instantStyles: [ 10 | { 11 | style: () => import('./hide-comment-preview.scss'), 12 | name, 13 | }, 14 | ], 15 | }) 16 | -------------------------------------------------------------------------------- /registry/lib/components/feeds/image-auto-back-to-top/index.md: -------------------------------------------------------------------------------- 1 | 在动态里查看图片详情时 (非全屏), 切换图片自动回到图片顶部; 退出查看图片模式时, 自动将动态移入视图内. 2 | -------------------------------------------------------------------------------- /registry/lib/components/feeds/legacy-image-viewer/index.md: -------------------------------------------------------------------------------- 1 | 将动态中左右切换式的图片改回传统的平铺展示. (在动态详情中可能稍有延迟) 2 | -------------------------------------------------------------------------------- /registry/lib/components/live/badge-helper/index.md: -------------------------------------------------------------------------------- 1 | 在直播区中, 可从功能面板中直接切换勋章和头衔. 默认显示 256 个 (同时也是上限), 可在选项中修改. 2 | -------------------------------------------------------------------------------- /registry/lib/components/live/badge-helper/index.ts: -------------------------------------------------------------------------------- 1 | import { defineComponentMetadata } from '@/components/define' 2 | import { getUID, none } from '@/core/utils' 3 | import { autoMatchMedal } from './auto-match' 4 | import { badgeHelperOptions } from './options' 5 | 6 | export const component = defineComponentMetadata({ 7 | name: 'badgeHelper', 8 | displayName: '直播勋章快速更换', 9 | entry: () => autoMatchMedal(), 10 | reload: none, 11 | unload: none, 12 | tags: [componentsTags.live], 13 | widget: { 14 | component: () => import('./BadgeHelper.vue').then(m => m.default), 15 | condition: () => Boolean(getUID()), 16 | }, 17 | options: badgeHelperOptions, 18 | urlInclude: ['//live.bilibili.com'], 19 | }) 20 | -------------------------------------------------------------------------------- /registry/lib/components/live/badge-helper/options.ts: -------------------------------------------------------------------------------- 1 | import { OptionsOfMetadata, defineOptionsMetadata } from '@/components/define' 2 | import { getNumberValidator } from '@/core/utils' 3 | 4 | export const badgeHelperOptions = defineOptionsMetadata({ 5 | autoMatchMedal: { 6 | defaultValue: true, 7 | displayName: '自动佩戴当前直播间勋章', 8 | }, 9 | maxBadgeCount: { 10 | defaultValue: 256, 11 | displayName: '最大显示数量', 12 | validator: getNumberValidator(1, 256), 13 | }, 14 | defaultMedalID: { 15 | displayName: '默认勋章ID', 16 | hidden: true, 17 | defaultValue: 0, 18 | }, 19 | grayEffect: { 20 | displayName: '显示勋章的未点亮状态', 21 | defaultValue: true, 22 | }, 23 | }) 24 | export type BadgeHelperOptions = OptionsOfMetadata 25 | -------------------------------------------------------------------------------- /registry/lib/components/live/chat-panel-fit/index.md: -------------------------------------------------------------------------------- 1 | 在直播网页全屏时, 自动调整侧边栏的宽度, 使得视频区域的比例和视频源相匹配, 达到无黑边的效果. 2 | 如果在侧边栏的边缘拖动, 可以自定义侧边栏的固定宽度, 双击边缘可以还原到自动宽度. 3 | 4 | - `侧边栏最大宽度 (px)`: 限制侧边栏可被拉伸到的最大宽度. (最小宽度固定为 190px, 再小的话布局就要出问题了) 5 | 6 | > 注意, 由于有最大宽度和最小宽度的限制, 部分窗口尺寸下仍然无法做到无黑边. 7 | -------------------------------------------------------------------------------- /registry/lib/components/live/chat-panel-fit/options.ts: -------------------------------------------------------------------------------- 1 | import { OptionsOfMetadata, defineOptionsMetadata } from '@/components/define' 2 | import { getNumberValidator } from '@/core/utils' 3 | 4 | export const ChatPanelFitOptionsMinWidth = 190 5 | export const chatPanelFitOptions = defineOptionsMetadata({ 6 | customWidth: { 7 | hidden: true, 8 | defaultValue: 0, 9 | }, 10 | maxWidth: { 11 | defaultValue: 1000, 12 | displayName: '侧边栏最大宽度 (px)', 13 | validator: getNumberValidator(ChatPanelFitOptionsMinWidth), 14 | }, 15 | }) 16 | export type ChatPanelFitOptions = OptionsOfMetadata 17 | -------------------------------------------------------------------------------- /registry/lib/components/live/danmaku-sendbar/original-elements.ts: -------------------------------------------------------------------------------- 1 | export const originalTextAreaSelector = '.control-panel-ctnr .chat-input-ctnr .chat-input' 2 | export const sendButtonSelector = 3 | '.control-panel-ctnr .chat-input-ctnr ~ .bottom-actions .bl-button--primary' 4 | export const leftControllerSelector = '.left-area' 5 | -------------------------------------------------------------------------------- /registry/lib/components/live/hide-gift-fullscreen/hide-full-screen-gift.css: -------------------------------------------------------------------------------- 1 | #full-screen-interactive-wrap { 2 | display: none !important 3 | } 4 | 5 | #fullscreen-danmaku-vm .fullscreen-danmaku { 6 | bottom: 5px !important 7 | } -------------------------------------------------------------------------------- /registry/lib/components/live/hide-gift-fullscreen/index.ts: -------------------------------------------------------------------------------- 1 | import { defineComponentMetadata } from '@/components/define' 2 | import { liveUrls } from '@/core/utils/urls' 3 | 4 | export const component = defineComponentMetadata({ 5 | name: 'hide-fullscreen-gift-bar', 6 | displayName: '全屏直播礼物简化', 7 | description: '移除全屏观看直播时的底部礼物栏', 8 | author: { 9 | name: 'TimmyOVO', 10 | link: 'https://github.com/TimmyOVO', 11 | }, 12 | instantStyles: [ 13 | { 14 | name: 'hide-fullscreen-gift', 15 | style: () => import('./hide-full-screen-gift.css'), 16 | }, 17 | ], 18 | entry: none, 19 | tags: [componentsTags.live, componentsTags.style], 20 | urlInclude: liveUrls, 21 | }) 22 | -------------------------------------------------------------------------------- /registry/lib/components/live/hide-player-blur/hide-player-blur.scss: -------------------------------------------------------------------------------- 1 | #web-player-module-area-mask-panel { 2 | z-index: -100 !important; 3 | } 4 | -------------------------------------------------------------------------------- /registry/lib/components/live/hide-player-blur/index.md: -------------------------------------------------------------------------------- 1 | 移除直播画面中的马赛克区域. 2 | -------------------------------------------------------------------------------- /registry/lib/components/live/hide-player-blur/index.ts: -------------------------------------------------------------------------------- 1 | import { defineComponentMetadata } from '@/components/define' 2 | import { liveUrls } from '@/core/utils/urls' 3 | 4 | export const component = defineComponentMetadata({ 5 | name: 'hideLivePlayerBlur', 6 | displayName: '隐藏直播马赛克', 7 | entry: none, 8 | tags: [componentsTags.live, componentsTags.style], 9 | urlInclude: [...liveUrls], 10 | instantStyles: [{ name: 'hideLivePlayerBlur', style: () => import('./hide-player-blur.scss') }], 11 | }) 12 | -------------------------------------------------------------------------------- /registry/lib/components/live/original/Widget.vue: -------------------------------------------------------------------------------- 1 | 6 | 21 | -------------------------------------------------------------------------------- /registry/lib/components/live/original/get-original-liveroom-url.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * 如果成功从参数 url 中捕获到直播间号,那么返回原版直播间页面链接,否则返回参数 url 3 | * @param url 直播间页面链接 4 | */ 5 | export const getOriginalLiveroomUrl = (url: string): string => { 6 | const match = url.match(/^https:\/\/live\.bilibili\.com\/([\d]+)/) 7 | return match ? `https://live.bilibili.com/blanc/${match[1]}` : url 8 | } 9 | -------------------------------------------------------------------------------- /registry/lib/components/live/remove-watermark/index.ts: -------------------------------------------------------------------------------- 1 | import { defineComponentMetadata } from '@/components/define' 2 | import { toggleStyle } from '@/components/styled-component' 3 | import { liveUrls } from '@/core/utils/urls' 4 | 5 | export const component = defineComponentMetadata({ 6 | ...toggleStyle('removeLiveWatermark', () => import('./remove-watermark.scss')), 7 | displayName: '删除直播水印', 8 | tags: [componentsTags.live, componentsTags.style], 9 | description: { 10 | 'zh-CN': '删除观看直播时角落的水印.', 11 | }, 12 | urlInclude: liveUrls, 13 | }) 14 | -------------------------------------------------------------------------------- /registry/lib/components/live/remove-watermark/remove-watermark.scss: -------------------------------------------------------------------------------- 1 | .live-player-ctnr .web-player-icon-roomStatus, 2 | .bilibili-live-player-video-logo 3 | { 4 | display: none !important; 5 | } 6 | -------------------------------------------------------------------------------- /registry/lib/components/live/side-bar/index.ts: -------------------------------------------------------------------------------- 1 | import { defineComponentMetadata } from '@/components/define' 2 | import { liveUrls } from '@/core/utils/urls' 3 | 4 | export const component = defineComponentMetadata({ 5 | name: 'collapseLiveSideBar', 6 | entry: none, 7 | instantStyles: [ 8 | { 9 | name: 'collapseLiveSideBar', 10 | style: () => import('./side-bar.scss'), 11 | }, 12 | ], 13 | displayName: '自动收起直播侧栏', 14 | description: '自动收起直播间右边偏下的侧栏. (上面有个 "关注" 的面板)', 15 | tags: [componentsTags.live, componentsTags.style], 16 | urlInclude: liveUrls, 17 | }) 18 | -------------------------------------------------------------------------------- /registry/lib/components/style/always-show-duration/always-show-duration.scss: -------------------------------------------------------------------------------- 1 | .watchlater-card, 2 | .time-group-item, 3 | .favorite-card, 4 | .video-card { 5 | .duration { 6 | opacity: 1 !important; 7 | } 8 | } 9 | -------------------------------------------------------------------------------- /registry/lib/components/style/always-show-duration/index.ts: -------------------------------------------------------------------------------- 1 | import { toggleStyle } from '@/components/styled-component' 2 | import { defineComponentMetadata } from '@/components/define' 3 | 4 | export const component = defineComponentMetadata({ 5 | ...toggleStyle('alwaysShowDuration', () => import('./always-show-duration.scss')), 6 | displayName: '总是显示视频时长', 7 | description: { 8 | 'zh-CN': '使脚本展示的各种视频卡片中的时长无需鼠标经过也能一直显示.', 9 | }, 10 | tags: [componentsTags.video, componentsTags.style], 11 | }) 12 | -------------------------------------------------------------------------------- /registry/lib/components/style/auto-hide-sidebar/auto-hide-sidebar.scss: -------------------------------------------------------------------------------- 1 | body { 2 | .be-settings { 3 | &::before { 4 | content: ""; 5 | position: fixed; 6 | width: var(--auto-hide-sidebar-width, 8px); 7 | height: 100vh; 8 | top: 0; 9 | left: 0; 10 | } 11 | 12 | > .sidebar { 13 | transition: transform 0.2s ease-out; 14 | } 15 | &:not(:hover) > .sidebar { 16 | transform: translateX(calc(-100% * var(--direction))) translateY(-50%); 17 | } 18 | } 19 | 20 | &.settings-panel-dock-right .be-settings::before { 21 | left: unset; 22 | right: 0; 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /registry/lib/components/style/custom-font-family/data.ts: -------------------------------------------------------------------------------- 1 | export const fontFamilyDefaultValue = 2 | 'Microsoft Yahei, Helvetica Neue, Helvetica, Arial, Hiragino Sans GB, Heiti SC, Malgun Gothic' 3 | 4 | export const coverOptionsName = [ 5 | { camel: 'coverOrnament', kebab: 'cover-ornament', display: '装扮字体' }, 6 | { camel: 'coverFansMedal', kebab: 'cover-fans-medal', display: '粉丝勋章字体' }, 7 | { camel: 'coverDanmaku', kebab: 'cover-danmaku', display: '弹幕字体' }, 8 | { camel: 'coverIconFont', kebab: 'cover-icon-font', display: '图标字体' }, 9 | { camel: 'coverColumn', kebab: 'cover-column', display: '专栏自定义字体' }, 10 | { camel: 'coverScore', kebab: 'cover-score', display: '评分字体' }, 11 | ] 12 | 13 | export const coverOptionsDefaultValue = { 14 | coverOrnament: false, 15 | coverFansMedal: false, 16 | coverDanmaku: false, 17 | coverIconFont: false, 18 | coverColumn: false, 19 | coverScore: false, 20 | } 21 | -------------------------------------------------------------------------------- /registry/lib/components/style/custom-font-family/disable-title-punctuation-text-indent.scss: -------------------------------------------------------------------------------- 1 | $name: 'custom-font-family'; 2 | 3 | html[#{$name}--options--disable-title-punctuation-text-indent='true'] 4 | :is( 5 | p[title^='「'], 6 | p[title^='『'], 7 | p[title^='【'], 8 | h1[title^='「'], 9 | h1[title^='『'], 10 | h1[title^='【'], 11 | h3[title^='「'], 12 | h3[title^='『'], 13 | h3[title^='【'], 14 | p[title^='~'], 15 | h3[title^='~'], 16 | p[title^='《'], 17 | h3[title^='《'], 18 | p[title^='“'], 19 | h3[title^='“'], 20 | p[title^='~'], 21 | h3[title^='~'], 22 | p[title^='《'], 23 | h3[title^='《'] 24 | ) { 25 | text-indent: initial !important; 26 | } 27 | -------------------------------------------------------------------------------- /registry/lib/components/style/custom-font-family/extra-options/Entry.vue: -------------------------------------------------------------------------------- 1 | 8 | 9 | 26 | 27 | 34 | -------------------------------------------------------------------------------- /registry/lib/components/style/custom-font-family/extra-options/vm.ts: -------------------------------------------------------------------------------- 1 | import { mountVueComponent } from '@/core/utils' 2 | 3 | let panelVm: Vue & { 4 | toggleDisplay: () => void 5 | } 6 | 7 | const getPanelLoadState = () => { 8 | return Boolean(panelVm) 9 | } 10 | 11 | const mountPanel = async () => { 12 | const panel = await import('./Panel.vue').then(m => m.default) 13 | panelVm = mountVueComponent(panel) 14 | document.body.insertAdjacentElement('beforeend', panelVm.$el) 15 | } 16 | 17 | export const loadPanel = async () => { 18 | const isLoaded = getPanelLoadState() 19 | if (!isLoaded) { 20 | await mountPanel() 21 | } 22 | } 23 | 24 | export const togglePanelDisplay = async () => { 25 | panelVm.toggleDisplay() 26 | } 27 | -------------------------------------------------------------------------------- /registry/lib/components/style/custom-font-family/index.md: -------------------------------------------------------------------------------- 1 | 使用组件提供的字体设置覆盖原版的主站字体,并使主站字体可被自定义。 2 | 3 | 当组件被启用后,几乎所有的元素会立即应用组件提供的字体设置。 4 | 5 | 选项说明: 6 | - `禁用标题标点符号缩进`: 在新版视频页中,推荐视频栏中的视频标题,如果首个字符是特定的标点符号,则文本会缩入左侧。这个选项可以禁用这种样式 7 | - `更多选项`: 8 | - `自定义字体`: 设置自定义字体。写法请参考 [MDN](https://developer.mozilla.org/zh-CN/docs/Web/CSS/font-family)、默认设置与设置说明。 9 | - `覆盖选项`: 相当于一个白名单,使用了特殊字体的元素会被加入其中。默认情况下这些元素不会应用组件提供的字体设置,只有在启用对应的选项后才会应用。 -------------------------------------------------------------------------------- /registry/lib/components/style/custom-navbar/CustomNavbarLink.vue: -------------------------------------------------------------------------------- 1 | 6 | 16 | -------------------------------------------------------------------------------- /registry/lib/components/style/custom-navbar/_popup.scss: -------------------------------------------------------------------------------- 1 | @mixin navbar-popup-height { 2 | height: 600px; 3 | min-height: 200px; 4 | max-height: calc(100vh - var(--navbar-height) - 12px); 5 | } 6 | -------------------------------------------------------------------------------- /registry/lib/components/style/custom-navbar/favorites/favorites-folder.ts: -------------------------------------------------------------------------------- 1 | /** 收藏夹信息, 供`FavoritesFolderSelect.vue`使用 */ 2 | export interface FavoritesFolder { 3 | id: number 4 | /** 名称 */ 5 | name: string 6 | /** 视频数量 */ 7 | count: number 8 | } 9 | /** 未选择时的初始状态 */ 10 | export const notSelectedFolder: FavoritesFolder = { 11 | id: 0, 12 | name: '加载中...', 13 | count: 0, 14 | } 15 | -------------------------------------------------------------------------------- /registry/lib/components/style/custom-navbar/favorites/favorites.ts: -------------------------------------------------------------------------------- 1 | import { getUID } from '@/core/utils' 2 | import { CustomNavbarItemInit } from '../custom-navbar-item' 3 | 4 | const href = `https://space.bilibili.com/${getUID()}/favlist` 5 | export const favorites: CustomNavbarItemInit = { 6 | name: 'favorites', 7 | displayName: '收藏', 8 | content: '收藏', 9 | 10 | href, 11 | touch: true, 12 | active: document.URL.replace(/\?.*$/, '') === href, 13 | loginRequired: true, 14 | 15 | boundingWidth: 380, 16 | noPopupPadding: true, 17 | popupContent: () => import('./NavbarFavorites.vue').then(m => m.default), 18 | } 19 | -------------------------------------------------------------------------------- /registry/lib/components/style/custom-navbar/feeds/tabs/live-feed-item.ts: -------------------------------------------------------------------------------- 1 | /** 直播项目 */ 2 | export interface LiveFeedItem { 3 | /** 房间号 */ 4 | id: number 5 | /** 标题 */ 6 | title: string 7 | /** up主名字 */ 8 | upName: string 9 | /** up主头像 */ 10 | upFaceUrl: string 11 | /** 直播间链接 */ 12 | url: string 13 | /** 直播间封面 */ 14 | coverUrl?: string 15 | } 16 | -------------------------------------------------------------------------------- /registry/lib/components/style/custom-navbar/flexible-blank/flexible-blank.ts: -------------------------------------------------------------------------------- 1 | import { CustomNavbarItemInit } from '../custom-navbar-item' 2 | 3 | const count = 4 4 | export const blanks: CustomNavbarItemInit[] = new Array(count).fill(0).map((_, index) => ({ 5 | name: `blank${index + 1}`, 6 | displayName: `弹性空白${index + 1}`, 7 | content: '', 8 | 9 | disabled: true, 10 | flexStyle: '1 0 auto', 11 | })) 12 | -------------------------------------------------------------------------------- /registry/lib/components/style/custom-navbar/history/history.ts: -------------------------------------------------------------------------------- 1 | import { CustomNavbarItemInit } from '../custom-navbar-item' 2 | 3 | const href = 'https://www.bilibili.com/history' 4 | export const history: CustomNavbarItemInit = { 5 | name: 'history', 6 | displayName: '历史', 7 | content: '历史', 8 | 9 | href, 10 | touch: true, 11 | active: document.URL.replace(/\?.*$/, '') === href, 12 | loginRequired: true, 13 | 14 | boundingWidth: 400, 15 | noPopupPadding: true, 16 | popupContent: () => import('./NavbarHistory.vue').then(m => m.default), 17 | } 18 | -------------------------------------------------------------------------------- /registry/lib/components/style/custom-navbar/home/home.ts: -------------------------------------------------------------------------------- 1 | import { CustomNavbarItemInit } from '../custom-navbar-item' 2 | 3 | export const home: CustomNavbarItemInit = { 4 | name: 'home', 5 | displayName: '主站', 6 | content: '主站', 7 | 8 | href: 'https://www.bilibili.com/', 9 | touch: true, 10 | 11 | boundingWidth: 366, 12 | popupContent: () => import('./NavbarHome.vue').then(m => m.default), 13 | } 14 | -------------------------------------------------------------------------------- /registry/lib/components/style/custom-navbar/iframe/IframePopup.vue: -------------------------------------------------------------------------------- 1 | 4 | 5 | 22 | -------------------------------------------------------------------------------- /registry/lib/components/style/custom-navbar/index.md: -------------------------------------------------------------------------------- 1 | 使用脚本提供的顶栏替换原版的主站顶栏 (非主站不替换). 2 | 3 | 启用后还可以在反广告插件 (例如 ABP) 中配置禁止原版顶栏的消息 iframe 以提升性能: 4 | - *://message.bilibili.com/pages/nav/index_new_pc_sync 5 | - *://message.bilibili.com/pages/nav/index_new_sync 6 | 7 | 选项说明: 8 | - `全局固定`: 将顶栏固定显示, 即使页面向下滚动也仍然可见. (除了一部分有 b 站定制顶栏的页面会忽略此选项) 9 | - `主题色填充`: 使用通用设置中的主题颜色填充顶栏的背景. 10 | - `透明填充`: 在首页和主站的部分页面中, 当存在顶部横幅图片时, 顶栏背景将变为透明 + 阴影的样式. 11 | - `背景模糊`: 启用背景模糊效果, 会使背景颜色变得半透明, 注意这个效果非常非常消耗图形性能, 慎用. 12 | - `投影`: 在顶栏下方增加一小段投影效果. 13 | - `使用季节 Logo`: 使用 b 站首页的特殊 Logo 图片替换顶栏的 Logo 图, 通常会对应当前季节, 特殊活动期间可能会有变化导致看不清. (比如搞了个全白的 Logo, 而顶栏正好也是白色的) 14 | - `触摸模式`: 启用后顶栏的一级入口点击时不进行跳转, 方便触屏使用. 15 | - `新标签页打开`: 控制顶栏内链接是否在新标签页打开. 16 | - `自动刷新数据`: 启用后, 部分有弹窗的顶栏入口在鼠标经过时会自动刷新数据. 17 | - `顶栏高度`: 自定义顶栏的高度 (b 站原版的为 64px) 18 | - `消息提醒样式`: 自定义顶栏入口的消息提醒样式. 19 | - `搜索栏宽度`: 自定义搜索栏占顶栏的比例. 20 | - `链接对齐样式`: 自定义纯链接弹窗内链接文字的对齐样式. 21 | -------------------------------------------------------------------------------- /registry/lib/components/style/custom-navbar/link-popup-content-align-style.ts: -------------------------------------------------------------------------------- 1 | import { addComponentListener } from '@/core/settings' 2 | 3 | export enum NavbarLinkPopupContentAlignStyle { 4 | Left = '左侧对齐', 5 | Center = '居中对齐', 6 | Right = '右侧对齐', 7 | } 8 | 9 | export const setupLinkPopupContentAlignStyle = () => { 10 | const map = { 11 | [NavbarLinkPopupContentAlignStyle.Left]: 'left', 12 | [NavbarLinkPopupContentAlignStyle.Center]: 'center', 13 | [NavbarLinkPopupContentAlignStyle.Right]: 'right', 14 | } 15 | addComponentListener( 16 | 'customNavbar.linkPopupContentAlignStyle', 17 | (value: NavbarLinkPopupContentAlignStyle) => { 18 | document.documentElement.setAttribute( 19 | 'data-navbar-link-popup-content-align-style', 20 | map[value], 21 | ) 22 | }, 23 | true, 24 | ) 25 | } 26 | -------------------------------------------------------------------------------- /registry/lib/components/style/custom-navbar/logo/logo.ts: -------------------------------------------------------------------------------- 1 | import { CustomNavbarItemInit } from '../custom-navbar-item' 2 | 3 | export const logo: CustomNavbarItemInit = { 4 | name: 'logo', 5 | displayName: 'Logo', 6 | content: () => import('./NavbarLogo.vue').then(m => m.default), 7 | 8 | href: 'https://www.bilibili.com/', 9 | } 10 | -------------------------------------------------------------------------------- /registry/lib/components/style/custom-navbar/messages/messages.ts: -------------------------------------------------------------------------------- 1 | import { CustomNavbarItemInit } from '../custom-navbar-item' 2 | 3 | const messagesUrl = 'https://message.bilibili.com/' 4 | export const messages: CustomNavbarItemInit = { 5 | name: 'messages', 6 | displayName: '消息', 7 | content: '消息', 8 | 9 | href: messagesUrl, 10 | active: document.URL.startsWith(messagesUrl), 11 | loginRequired: true, 12 | touch: true, 13 | 14 | popupContent: () => import('./NavbarMessages.vue').then(m => m.default), 15 | lazy: false, 16 | } 17 | -------------------------------------------------------------------------------- /registry/lib/components/style/custom-navbar/mixins.ts: -------------------------------------------------------------------------------- 1 | import { CustomNavbarItem } from './custom-navbar-item' 2 | 3 | export const popperMixin = Vue.extend({ 4 | props: { 5 | item: { 6 | type: CustomNavbarItem, 7 | required: true, 8 | }, 9 | container: { 10 | type: HTMLElement, 11 | required: true, 12 | }, 13 | }, 14 | mounted() { 15 | const navBarItem = this.item as CustomNavbarItem 16 | const containerElement = this.container as HTMLElement 17 | if (containerElement) { 18 | navBarItem?.usePopper(containerElement, this.$el.parentElement) 19 | } 20 | }, 21 | methods: { 22 | popupShow() { 23 | const navBarItem = this.item as CustomNavbarItem 24 | navBarItem?.popper?.update() 25 | }, 26 | }, 27 | }) 28 | -------------------------------------------------------------------------------- /registry/lib/components/style/custom-navbar/notify-style.ts: -------------------------------------------------------------------------------- 1 | import { addComponentListener } from '@/core/settings' 2 | 3 | export enum NavbarNotifyStyle { 4 | Number = '数字', 5 | Hidden = '隐藏', 6 | Dot = '点状', 7 | } 8 | 9 | export const setupNotifyStyle = () => { 10 | const map = { 11 | [NavbarNotifyStyle.Number]: 'number', 12 | [NavbarNotifyStyle.Hidden]: 'hidden', 13 | [NavbarNotifyStyle.Dot]: 'dot', 14 | } 15 | addComponentListener( 16 | 'customNavbar.notifyStyle', 17 | (value: NavbarNotifyStyle) => { 18 | document.documentElement.setAttribute('data-navbar-notify-style', map[value]) 19 | }, 20 | true, 21 | ) 22 | } 23 | -------------------------------------------------------------------------------- /registry/lib/components/style/custom-navbar/ranking/ranking.ts: -------------------------------------------------------------------------------- 1 | import { CustomNavbarItemInit } from '../custom-navbar-item' 2 | 3 | const rankingUrl = 'https://www.bilibili.com/v/popular/rank/' 4 | export const ranking: CustomNavbarItemInit = { 5 | name: 'ranking', 6 | displayName: '排行', 7 | content: '排行', 8 | 9 | href: `${rankingUrl}all`, 10 | active: document.URL.startsWith(rankingUrl), 11 | touch: true, 12 | 13 | popupContent: () => import('./NavbarRanking.vue').then(m => m.default), 14 | } 15 | -------------------------------------------------------------------------------- /registry/lib/components/style/custom-navbar/search/search.ts: -------------------------------------------------------------------------------- 1 | import { CustomNavbarItemInit } from '../custom-navbar-item' 2 | 3 | export const search: CustomNavbarItemInit = { 4 | name: 'search', 5 | displayName: '搜索', 6 | content: () => import('./NavbarSearch.vue').then(m => m.default), 7 | 8 | // 禁用元素本身的 hover 效果之类的, 作为 content 的 NavbarSearch 是依然能够响应的 9 | disabled: true, 10 | } 11 | -------------------------------------------------------------------------------- /registry/lib/components/style/custom-navbar/settings/Widget.vue: -------------------------------------------------------------------------------- 1 | 9 | 25 | -------------------------------------------------------------------------------- /registry/lib/components/style/custom-navbar/settings/vm.ts: -------------------------------------------------------------------------------- 1 | import { mountVueComponent } from '@/core/utils' 2 | 3 | let navbarSettingsVM: Vue & { 4 | toggle: () => void 5 | triggerElement: HTMLElement 6 | } 7 | export const setTriggerElement = (element: HTMLElement) => { 8 | if (!navbarSettingsVM) { 9 | return 10 | } 11 | navbarSettingsVM.triggerElement = element 12 | } 13 | export const loadNavbarSettings = async () => { 14 | if (navbarSettingsVM) { 15 | return false 16 | } 17 | const NavbarSettings = await import('./NavbarSettings.vue').then(m => m.default) 18 | navbarSettingsVM = mountVueComponent(NavbarSettings) 19 | document.body.insertAdjacentElement('beforeend', navbarSettingsVM.$el) 20 | return true 21 | } 22 | export const toggleNavbarSettings = async () => { 23 | if (!navbarSettingsVM) { 24 | await loadNavbarSettings() 25 | } 26 | navbarSettingsVM?.toggle() 27 | } 28 | -------------------------------------------------------------------------------- /registry/lib/components/style/custom-navbar/subscriptions/BangumiSubscriptions.vue: -------------------------------------------------------------------------------- 1 | 4 | 19 | -------------------------------------------------------------------------------- /registry/lib/components/style/custom-navbar/subscriptions/CinemaSubscriptions.vue: -------------------------------------------------------------------------------- 1 | 4 | 19 | -------------------------------------------------------------------------------- /registry/lib/components/style/custom-navbar/subscriptions/types.ts: -------------------------------------------------------------------------------- 1 | export enum SubscriptionStatus { 2 | ToView = 1, 3 | Viewing, 4 | Viewed, 5 | } 6 | export interface SubscriptionStatusFilter { 7 | viewAll: boolean 8 | status: SubscriptionStatus 9 | } 10 | export interface SubscriptionItem { 11 | title: string 12 | coverUrl: string 13 | latest: number 14 | progress: string 15 | id: string 16 | status: SubscriptionStatus 17 | statusText: string 18 | playUrl: string 19 | mediaUrl: string 20 | } 21 | -------------------------------------------------------------------------------- /registry/lib/components/style/custom-navbar/upload/NavbarUpload.vue: -------------------------------------------------------------------------------- 1 | 7 | 16 | 27 | -------------------------------------------------------------------------------- /registry/lib/components/style/custom-navbar/upload/upload.ts: -------------------------------------------------------------------------------- 1 | import { CustomNavbarItemInit } from '../custom-navbar-item' 2 | 3 | export const upload: CustomNavbarItemInit = { 4 | name: 'upload', 5 | displayName: '投稿', 6 | content: () => import('./NavbarUpload.vue').then(m => m.default), 7 | 8 | touch: true, 9 | href: 'https://member.bilibili.com/platform/upload/video/frame', 10 | 11 | popupContent: () => import('./UploadPopup.vue').then(m => m.default), 12 | } 13 | -------------------------------------------------------------------------------- /registry/lib/components/style/custom-navbar/user-info/akari.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/the1812/Bilibili-Evolved/3bfd9f583104b986298a46722e40401f505d4076/registry/lib/components/style/custom-navbar/user-info/akari.jpg -------------------------------------------------------------------------------- /registry/lib/components/style/custom-navbar/user-info/user-info.ts: -------------------------------------------------------------------------------- 1 | import { getUID } from '@/core/utils' 2 | import { CustomNavbarItemInit } from '../custom-navbar-item' 3 | 4 | export const userInfo: CustomNavbarItemInit = { 5 | name: 'userInfo', 6 | displayName: '个人信息', 7 | content: () => import('./UserFace.vue').then(m => m.default), 8 | 9 | href: getUID() ? 'https://space.bilibili.com' : null, 10 | touch: true, 11 | 12 | popupContent: () => import('./UserInfoPopup.vue').then(m => m.default), 13 | lazy: false, 14 | noPopupPadding: true, 15 | boundingWidth: 240, 16 | } 17 | -------------------------------------------------------------------------------- /registry/lib/components/style/custom-navbar/watchlater/watchlater.ts: -------------------------------------------------------------------------------- 1 | import { CustomNavbarItemInit } from '../custom-navbar-item' 2 | 3 | export const watchlater: CustomNavbarItemInit = { 4 | name: 'watchlater', 5 | displayName: '稍后再看', 6 | content: '稍后再看', 7 | 8 | href: 'https://www.bilibili.com/watchlater/#/list', 9 | touch: true, 10 | active: document.URL.startsWith('https://www.bilibili.com/watchlater/'), 11 | loginRequired: true, 12 | 13 | boundingWidth: 380, 14 | noPopupPadding: true, 15 | popupContent: () => import('./NavbarWatchlater.vue').then(m => m.default), 16 | } 17 | -------------------------------------------------------------------------------- /registry/lib/components/style/dark-mode/dark-mode.scss: -------------------------------------------------------------------------------- 1 | @import "./old/dark-slice-1.css"; 2 | @import "./old/dark-slice-2.css"; 3 | @import "./old/dark-slice-3.css"; 4 | @import "./old/dark-slice-4.css"; 5 | @import "./old/dark-slice-5.css"; 6 | @import "./old/dark-slice-6.css"; 7 | @import "./old/dark-slice-7.css"; 8 | @import "./old/dark-slice-8.css"; 9 | @import "./dark-slice-9.scss"; 10 | @import "./dark-slice-10.scss"; 11 | @import "./dark-slice-11.scss"; 12 | @import "./dark-slice-12.scss"; 13 | @import "./dark-slice-13.scss"; 14 | @import "./dark-slice-14.scss"; 15 | @import "./dark-slice-15.scss"; 16 | @import "./dark-slice-16.scss"; 17 | @import "./dark-slice-17.scss"; 18 | @import "./dark-slice-18.scss"; 19 | @import "./dark-slice-19.scss"; 20 | @import "./dark-navbar.scss"; 21 | @import "./dark-variables.scss"; 22 | -------------------------------------------------------------------------------- /registry/lib/components/style/dark-mode/dark-urls.ts: -------------------------------------------------------------------------------- 1 | export const darkExcludes = [ 2 | '//member.bilibili.com/v2', 3 | '//member.bilibili.com/platform', 4 | '//member.bilibili.com/video/upload.html', 5 | '//member.bilibili.com/article-text/home', 6 | '//www.bilibili.com/audio/submit/', 7 | '//member.bilibili.com/studio/bs-editor/projects', 8 | '//www.bilibili.com/s/video/', 9 | '//member.bilibili.com/platform', 10 | '//live.bilibili.com/p/html/live-lottery/anchor-join.html', 11 | '//account.bilibili.com/subtitle/edit/#/editor', 12 | // 创作中心-收益管理-充电计划 13 | '/york/allowance-charge', 14 | // 创作中心-收益管理-悬赏计划 15 | '//cm.bilibili.com/quests/#/task', 16 | '//live.bilibili.com/activity/live-activity-full/full-next/index.html', 17 | '//gf.bilibili.com/', 18 | ] 19 | -------------------------------------------------------------------------------- /registry/lib/components/style/hide/bangumi/reviews/index.ts: -------------------------------------------------------------------------------- 1 | import { defineComponentMetadata } from '@/components/define' 2 | import { toggleStyle } from '@/components/styled-component' 3 | import { bangumiUrls } from '@/core/utils/urls' 4 | 5 | export const component = defineComponentMetadata({ 6 | displayName: '隐藏番剧点评', 7 | tags: [componentsTags.style], 8 | ...toggleStyle('hideBangumiReviews', () => import('./reviews.scss')), 9 | urlInclude: bangumiUrls, 10 | description: { 11 | 'zh-CN': '隐藏番剧播放页面里的点评板块.', 12 | }, 13 | }) 14 | -------------------------------------------------------------------------------- /registry/lib/components/style/hide/bangumi/reviews/reviews.scss: -------------------------------------------------------------------------------- 1 | #review_module { 2 | display: none !important; 3 | } -------------------------------------------------------------------------------- /registry/lib/components/style/hide/bangumi/sponsors/index.ts: -------------------------------------------------------------------------------- 1 | import { defineComponentMetadata } from '@/components/define' 2 | import { toggleStyle } from '@/components/styled-component' 3 | import { bangumiUrls } from '@/core/utils/urls' 4 | 5 | export const component = defineComponentMetadata({ 6 | displayName: '隐藏番剧承包', 7 | tags: [componentsTags.style], 8 | ...toggleStyle('hideBangumiSponsors', () => import('./sponsors.scss')), 9 | urlInclude: bangumiUrls, 10 | description: { 11 | 'zh-CN': '隐藏番剧页面下方的承包榜, 以及右边的承包按钮.', 12 | }, 13 | }) 14 | -------------------------------------------------------------------------------- /registry/lib/components/style/hide/bangumi/sponsors/sponsors.scss: -------------------------------------------------------------------------------- 1 | #sponsor_module, #paybar_module { 2 | display: none !important; 3 | } -------------------------------------------------------------------------------- /registry/lib/components/style/hide/banner/index.ts: -------------------------------------------------------------------------------- 1 | import { defineComponentMetadata } from '@/components/define' 2 | import { mainSiteUrls } from '@/core/utils/urls' 3 | 4 | export const component = defineComponentMetadata({ 5 | name: 'hideBanner', 6 | entry: none, 7 | displayName: '隐藏顶部横幅', 8 | instantStyles: [ 9 | { 10 | name: 'hideBanner', 11 | style: () => import('./banner.scss'), 12 | }, 13 | ], 14 | tags: [componentsTags.style], 15 | description: { 16 | 'zh-CN': '隐藏首页顶部横幅.', 17 | }, 18 | urlInclude: mainSiteUrls, 19 | }) 20 | -------------------------------------------------------------------------------- /registry/lib/components/style/hide/home-carousel/hide-home-carousel.scss: -------------------------------------------------------------------------------- 1 | .recommended-swipe.grid-anchor { 2 | display: none !important; 3 | } 4 | -------------------------------------------------------------------------------- /registry/lib/components/style/hide/home-carousel/index.md: -------------------------------------------------------------------------------- 1 | 隐藏首页的轮播图区域. 2 | -------------------------------------------------------------------------------- /registry/lib/components/style/hide/home-carousel/index.ts: -------------------------------------------------------------------------------- 1 | import { defineComponentMetadata } from '@/components/define' 2 | 3 | export const component = defineComponentMetadata({ 4 | name: 'hideHomeCarousel', 5 | displayName: '隐藏首页轮播图', 6 | entry: none, 7 | tags: [componentsTags.style], 8 | urlInclude: [/^https:\/\/www\.bilibili\.com\/$/, /^https:\/\/www\.bilibili\.com\/index\.html$/], 9 | instantStyles: [ 10 | { 11 | name: 'hide-home-carousel', 12 | style: () => import('./hide-home-carousel.scss'), 13 | }, 14 | ], 15 | }) 16 | -------------------------------------------------------------------------------- /registry/lib/components/style/hide/trending-search/hide-trending-search.scss: -------------------------------------------------------------------------------- 1 | .search-panel { 2 | 3 | > .trending { 4 | display: none !important; 5 | } 6 | 7 | &:not(:has(.history)) { 8 | padding: 0 !important; 9 | border: none !important; 10 | } 11 | } 12 | 13 | #nav-searchform.is-focus { 14 | /* 搜索框 focusing 且有关键字列表 or 历史记录列表时不显示低边框*/ 15 | &:not(:has(+ .search-panel > .suggestions), :has(+ .search-panel > .history)) { 16 | border-radius: 8px !important; 17 | } 18 | } -------------------------------------------------------------------------------- /registry/lib/components/style/hide/trending-search/index.md: -------------------------------------------------------------------------------- 1 | 隐藏搜索栏和搜索页面中的 `bilibili 热搜`. 请注意这只是视觉上的隐藏, 如果不输入任何关键词就点 Enter 或搜索按钮, 仍然会跳转至推荐的热搜词. -------------------------------------------------------------------------------- /registry/lib/components/style/hide/user-card/index.ts: -------------------------------------------------------------------------------- 1 | import { defineComponentMetadata } from '@/components/define' 2 | import { toggleStyle } from '@/components/styled-component' 3 | 4 | const name = 'hideUserCard' 5 | 6 | export const component = defineComponentMetadata({ 7 | displayName: '隐藏用户信息卡片', 8 | description: { 9 | 'zh-CN': '隐藏鼠标指向用户名或用户头像时弹出的浮动用户信息卡片', 10 | }, 11 | author: { 12 | name: 'WakelessSloth56', 13 | link: 'https://github.com/WakelessSloth56', 14 | }, 15 | tags: [componentsTags.style], 16 | ...toggleStyle(name, () => import('./user-card.scss')), 17 | }) 18 | -------------------------------------------------------------------------------- /registry/lib/components/style/hide/user-card/user-card.scss: -------------------------------------------------------------------------------- 1 | .user-card, 2 | .user-card-m-exp, 3 | .bili-user-profile { 4 | display: none !important; 5 | } 6 | -------------------------------------------------------------------------------- /registry/lib/components/style/hide/user-pendent/index.md: -------------------------------------------------------------------------------- 1 | 隐藏页面中用户的头像框 (包括角标), 目前支持动态和视频页面. 2 | -------------------------------------------------------------------------------- /registry/lib/components/style/hide/user-pendent/index.ts: -------------------------------------------------------------------------------- 1 | import { defineComponentMetadata } from '@/components/define' 2 | 3 | export const component = defineComponentMetadata({ 4 | name: 'hideUserPendent', 5 | displayName: '隐藏头像框', 6 | entry: none, 7 | tags: [componentsTags.style], 8 | instantStyles: [ 9 | { 10 | name: 'hide-user-pendent', 11 | style: () => import('./user-pendent.scss'), 12 | }, 13 | { 14 | name: 'hide-user-pendent', 15 | style: () => import('./user-pendent-shadow.scss'), 16 | shadowDom: true, 17 | }, 18 | ], 19 | }) 20 | -------------------------------------------------------------------------------- /registry/lib/components/style/hide/user-pendent/user-pendent-shadow.scss: -------------------------------------------------------------------------------- 1 | :host(bili-avatar) { 2 | container-type: size; 3 | container-name: avatar; 4 | // .layers:first-child, 5 | .layer:not(:first-child), 6 | .layer:not(:has(picture [src*="/face/"]), :has([style*="/face/"])) { 7 | display: none; 8 | } 9 | .layer:is(:has(picture [src*="/face/"]), :has([style*="/face/"])) { 10 | min-width: 100cqw; 11 | min-height: 100cqh; 12 | max-width: 100cqw; 13 | max-height: 100cqh; 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /registry/lib/components/style/hide/user-pendent/user-pendent.scss: -------------------------------------------------------------------------------- 1 | .b-avatar { 2 | container-type: size; 3 | container-name: avatar; 4 | &__layers:not(:first-child), 5 | &__layer:not(:first-child) { 6 | display: none !important; 7 | } 8 | &__layer:first-child { 9 | min-width: 100cqw; 10 | min-height: 100cqh; 11 | } 12 | } 13 | .up-avatar { 14 | container-type: size; 15 | container-name: avatar; 16 | .bili-avatar { 17 | min-width: 100cqw; 18 | min-height: 100cqh; 19 | transform: none !important; 20 | } 21 | } 22 | .bili-avatar { 23 | &-icon, 24 | &-pendent-dom { 25 | display: none !important; 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /registry/lib/components/style/hide/video/notes/hide-video-notes.scss: -------------------------------------------------------------------------------- 1 | .video-toolbar-container .video-note .video-note-inner { 2 | display: none !important; 3 | } 4 | -------------------------------------------------------------------------------- /registry/lib/components/style/hide/video/notes/index.md: -------------------------------------------------------------------------------- 1 | 隐藏视频页面中的 "记笔记" 按钮. 2 | -------------------------------------------------------------------------------- /registry/lib/components/style/hide/video/notes/index.ts: -------------------------------------------------------------------------------- 1 | import { defineComponentMetadata } from '@/components/define' 2 | 3 | const name = 'hideVideoNotes' 4 | export const component = defineComponentMetadata({ 5 | name, 6 | displayName: '隐藏记笔记', 7 | tags: [componentsTags.video, componentsTags.style], 8 | entry: none, 9 | instantStyles: [ 10 | { 11 | name, 12 | style: () => import('./hide-video-notes.scss'), 13 | }, 14 | ], 15 | }) 16 | -------------------------------------------------------------------------------- /registry/lib/components/style/hide/video/recommended-live/index.ts: -------------------------------------------------------------------------------- 1 | import { defineComponentMetadata } from '@/components/define' 2 | import { videoUrls } from '@/core/utils/urls' 3 | 4 | export const component = defineComponentMetadata({ 5 | name: 'hideRecommendedLive', 6 | entry: none, 7 | instantStyles: [ 8 | { 9 | name: 'hideRecommendedLive', 10 | style: () => import('./recommended-live.scss'), 11 | }, 12 | ], 13 | displayName: '隐藏直播推荐', 14 | tags: [componentsTags.style, componentsTags.video], 15 | description: { 16 | 'zh-CN': '隐藏视频页面右侧下方的直播推荐.', 17 | }, 18 | urlInclude: videoUrls, 19 | }) 20 | -------------------------------------------------------------------------------- /registry/lib/components/style/hide/video/recommended-live/recommended-live.scss: -------------------------------------------------------------------------------- 1 | #live_recommand_report, // b站以前写的recommand, 后来改对了 2 | #live_recommend_report, 3 | .video-container-v1 .pop-live-small-mode { 4 | display: none !important; 5 | } 6 | -------------------------------------------------------------------------------- /registry/lib/components/style/hide/video/related-videos/index.md: -------------------------------------------------------------------------------- 1 | 隐藏番剧和视频页面右侧的推荐视频列表. 注意: 如果你想关闭 b 站的自动连播 (自动播放下一个推荐视频) 功能, 需要先取消隐藏视频推荐才能看到开关. 2 | -------------------------------------------------------------------------------- /registry/lib/components/style/hide/video/related-videos/index.ts: -------------------------------------------------------------------------------- 1 | import { defineComponentMetadata } from '@/components/define' 2 | import { videoAndBangumiUrls } from '@/core/utils/urls' 3 | 4 | export const component = defineComponentMetadata({ 5 | name: 'hideRelatedVideos', 6 | displayName: '隐藏视频推荐', 7 | entry: none, 8 | instantStyles: [ 9 | { 10 | name: 'hideRelatedVideos', 11 | style: () => import('./related-videos.scss'), 12 | }, 13 | ], 14 | tags: [componentsTags.style, componentsTags.video], 15 | urlInclude: videoAndBangumiUrls, 16 | }) 17 | -------------------------------------------------------------------------------- /registry/lib/components/style/hide/video/related-videos/related-videos.scss: -------------------------------------------------------------------------------- 1 | #recom_module, 2 | #reco_list, 3 | .bilibili-player-ending-panel-box-videos, 4 | .r-con .rcmd-list, 5 | .playlist-container .recommend-list-container, 6 | .bpx-player-ending-related, 7 | .plp-r [class*="recommend_wrap"], 8 | .video-container-v1 .recommend-list-v1 { 9 | display: none !important; 10 | } 11 | .bilibili-player-ending-panel-box-functions .bilibili-player-upinfo-spans { 12 | position: static !important; 13 | } 14 | .bilibili-player-ending-panel-box, 15 | .bpx-player-ending-content { 16 | display: flex !important; 17 | justify-content: center !important; 18 | flex-direction: column !important; 19 | } 20 | -------------------------------------------------------------------------------- /registry/lib/components/style/hide/video/report/hide-video-report.scss: -------------------------------------------------------------------------------- 1 | .video-toolbar-container .video-complaint { 2 | display: none !important; 3 | } 4 | -------------------------------------------------------------------------------- /registry/lib/components/style/hide/video/report/index.md: -------------------------------------------------------------------------------- 1 | 隐藏视频页面中的 "稿件投诉" 按钮. 2 | -------------------------------------------------------------------------------- /registry/lib/components/style/hide/video/report/index.ts: -------------------------------------------------------------------------------- 1 | import { defineComponentMetadata } from '@/components/define' 2 | 3 | const name = 'hideVideoReport' 4 | export const component = defineComponentMetadata({ 5 | name, 6 | displayName: '隐藏稿件投诉', 7 | tags: [componentsTags.video, componentsTags.style], 8 | entry: none, 9 | instantStyles: [ 10 | { 11 | name, 12 | style: () => import('./hide-video-report.scss'), 13 | }, 14 | ], 15 | }) 16 | -------------------------------------------------------------------------------- /registry/lib/components/style/hide/video/share/hide-video-share.scss: -------------------------------------------------------------------------------- 1 | .video-toolbar-v1 { 2 | .share-wrap { 3 | display: none !important; 4 | } 5 | } 6 | .video-toolbar-container { 7 | .video-share-wrap { 8 | display: none !important; 9 | } 10 | } 11 | .player-left-components { 12 | [class*="toolbar_share_info"] { 13 | display: none !important; 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /registry/lib/components/style/hide/video/share/index.md: -------------------------------------------------------------------------------- 1 | 隐藏视频和番剧播放器下方的分享按钮. 2 | -------------------------------------------------------------------------------- /registry/lib/components/style/hide/video/share/index.ts: -------------------------------------------------------------------------------- 1 | import { defineComponentMetadata } from '@/components/define' 2 | 3 | export const component = defineComponentMetadata({ 4 | name: 'hideVideoShare', 5 | displayName: '隐藏视频分享', 6 | tags: [componentsTags.style, componentsTags.video], 7 | instantStyles: [ 8 | { 9 | name: 'hideVideoShare', 10 | style: () => import('./hide-video-share.scss'), 11 | }, 12 | ], 13 | entry: none, 14 | }) 15 | -------------------------------------------------------------------------------- /registry/lib/components/style/hide/video/top-mask/index.ts: -------------------------------------------------------------------------------- 1 | import { defineComponentMetadata } from '@/components/define' 2 | import { playerUrls } from '@/core/utils/urls' 3 | 4 | const name = 'hideVideoTopMask' 5 | export const component = defineComponentMetadata({ 6 | name, 7 | displayName: '隐藏视频标题层', 8 | entry: none, 9 | instantStyles: [ 10 | { 11 | name, 12 | style: () => import('./top-mask.scss'), 13 | }, 14 | ], 15 | tags: [componentsTags.style, componentsTags.video], 16 | description: { 17 | 'zh-CN': '隐藏视频里鼠标经过时出现在右上角的覆盖层.', 18 | }, 19 | urlInclude: playerUrls, 20 | }) 21 | -------------------------------------------------------------------------------- /registry/lib/components/style/hide/video/top-mask/top-mask.scss: -------------------------------------------------------------------------------- 1 | .bpx-player-top-wrap, 2 | .bilibili-player-video-top { 3 | display: none !important; 4 | } 5 | -------------------------------------------------------------------------------- /registry/lib/components/style/home-redesign/fresh/SubHeader.vue: -------------------------------------------------------------------------------- 1 | 7 | 20 | -------------------------------------------------------------------------------- /registry/lib/components/style/home-redesign/fresh/index.md: -------------------------------------------------------------------------------- 1 | 使用重新设计的清爽风格首页替换原本的首页. 2 | 3 | 请注意: 4 | - 此功能与 `极简首页` 互斥, 请勿同时使用. 5 | - 此功能会禁用首页的[悬浮视频](https://github.com/the1812/Bilibili-Evolved/discussions/4404), 变为直接跳转到视频页面. 6 | 7 | 选项说明: 8 | - 个性化推荐: 启用时展示推荐视频, 禁用时展示热门视频. 9 | - 启用横向滚动: 在可以横向滚动的列表中, 使鼠标滚轮可以做出横向滚动的效果, 请注意这会禁用卡片的边缘吸附效果. 10 | -------------------------------------------------------------------------------- /registry/lib/components/style/home-redesign/fresh/init-dropdown-options/area-primary-title-color.ts: -------------------------------------------------------------------------------- 1 | import { addComponentListener } from '@/core/settings' 2 | 3 | export enum areaPrimaryTitleColorEnum { 4 | Dark = '深色', 5 | Light = '浅色', 6 | } 7 | 8 | const map = { 9 | [areaPrimaryTitleColorEnum.Dark]: 'dark', 10 | [areaPrimaryTitleColorEnum.Light]: 'light', 11 | } 12 | 13 | addComponentListener( 14 | 'freshHome.areaPrimaryTitleColor', 15 | (value: areaPrimaryTitleColorEnum) => { 16 | document.documentElement.setAttribute( 17 | 'fresh-home--options--area-primary-title-color', 18 | map[value], 19 | ) 20 | }, 21 | true, 22 | ) 23 | -------------------------------------------------------------------------------- /registry/lib/components/style/home-redesign/fresh/layouts/areas/areas.ts: -------------------------------------------------------------------------------- 1 | import { FreshLayoutItem } from '../fresh-layout-item' 2 | 3 | export const areas: FreshLayoutItem = { 4 | name: 'areas', 5 | displayName: '栏目', 6 | component: () => import('./Areas.vue').then(m => m.default), 7 | } 8 | -------------------------------------------------------------------------------- /registry/lib/components/style/home-redesign/fresh/layouts/areas/column.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/the1812/Bilibili-Evolved/3bfd9f583104b986298a46722e40401f505d4076/registry/lib/components/style/home-redesign/fresh/layouts/areas/column.jpg -------------------------------------------------------------------------------- /registry/lib/components/style/home-redesign/fresh/layouts/blackboard/api.ts: -------------------------------------------------------------------------------- 1 | import { getJson } from '@/core/ajax' 2 | 3 | export interface Blackboard { 4 | url: string 5 | title: string 6 | isAd: boolean 7 | imageUrl: string 8 | } 9 | export const getBlackboards = async (): Promise => { 10 | const locId = 4694 11 | const api = `https://api.bilibili.com/x/web-show/res/locs?pf=0&ids=${locId}` 12 | const { code, message, data } = await getJson(api) 13 | if (code !== 0) { 14 | throw new Error(`获取活动卡片失败: ${message}`) 15 | } 16 | const list: any[] = data[locId] 17 | return list.map( 18 | it => 19 | ({ 20 | url: it.url, 21 | title: it.name, 22 | // isAd: it.is_ad_loc, 23 | isAd: it.res_id !== locId, 24 | imageUrl: it.pic, 25 | } as Blackboard), 26 | ) 27 | } 28 | -------------------------------------------------------------------------------- /registry/lib/components/style/home-redesign/fresh/layouts/blackboard/blackboard.ts: -------------------------------------------------------------------------------- 1 | import { FreshLayoutItem } from '../fresh-layout-item' 2 | 3 | export const blackboard: FreshLayoutItem = { 4 | name: 'blackboard', 5 | displayName: '活动', 6 | component: () => import('./Blackboard.vue').then(m => m.default), 7 | } 8 | -------------------------------------------------------------------------------- /registry/lib/components/style/home-redesign/fresh/layouts/categories/categories.ts: -------------------------------------------------------------------------------- 1 | import { FreshLayoutItem } from '../fresh-layout-item' 2 | 3 | export const categories: FreshLayoutItem = { 4 | name: 'categories', 5 | displayName: '分区', 6 | grow: true, 7 | component: () => import('./Categories.vue').then(m => m.default), 8 | } 9 | -------------------------------------------------------------------------------- /registry/lib/components/style/home-redesign/fresh/layouts/categories/content/_rank-list.scss: -------------------------------------------------------------------------------- 1 | @mixin rank-list-common { 2 | & &-loading-container { 3 | @include v-center(); 4 | justify-content: center; 5 | padding: var(--padding); 6 | border-radius: var(--home-card-radius); 7 | border: 2px dashed #8884; 8 | height: 100%; 9 | } 10 | & &-empty { 11 | @include v-center(12px); 12 | justify-content: center; 13 | .be-button { 14 | padding: 4px 10px 4px 6px !important; 15 | &:hover .be-icon { 16 | transform: rotate(1turn); 17 | } 18 | } 19 | .be-icon { 20 | margin-right: 6px; 21 | transition: 0.5s ease-out; 22 | } 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /registry/lib/components/style/home-redesign/fresh/layouts/categories/content/content.ts: -------------------------------------------------------------------------------- 1 | const bangumiNames = ['番剧', '国创'] 2 | export const getContent = (tabName: string) => { 3 | console.log('getContent', tabName) 4 | if (bangumiNames.includes(tabName)) { 5 | return () => import('./Bangumi.vue').then(m => m.default) 6 | } 7 | return () => import('./Default.vue').then(m => m.default) 8 | } 9 | -------------------------------------------------------------------------------- /registry/lib/components/style/home-redesign/fresh/layouts/categories/filter.ts: -------------------------------------------------------------------------------- 1 | import { categories } from '@/components/utils/categories/data' 2 | import supportedNames from './supported-names.json' 3 | 4 | const excludedNames = [ 5 | '推广', 6 | '正在直播', 7 | '番剧动态', 8 | '国产原创相关', 9 | '漫画', 10 | '课堂', 11 | '专栏', 12 | '特别推荐', 13 | ] 14 | export const supportedCategories = Object.fromEntries( 15 | Object.entries(categories).filter(([name]) => { 16 | if (excludedNames.includes(name)) { 17 | return false 18 | } 19 | if (!(supportedNames as string[]).includes(name)) { 20 | return false 21 | } 22 | return true 23 | }), 24 | ) 25 | -------------------------------------------------------------------------------- /registry/lib/components/style/home-redesign/fresh/layouts/categories/supported-names.json: -------------------------------------------------------------------------------- 1 | [ 2 | "推广", 3 | "正在直播", 4 | "动画", 5 | "番剧", 6 | "番剧动态", 7 | "国创", 8 | "国产原创相关", 9 | "漫画", 10 | "音乐", 11 | "舞蹈", 12 | "游戏", 13 | "知识", 14 | "课堂", 15 | "科技", 16 | "运动", 17 | "汽车", 18 | "生活", 19 | "美食", 20 | "动物圈", 21 | "鬼畜", 22 | "时尚", 23 | "资讯", 24 | "娱乐", 25 | "专栏", 26 | "电影", 27 | "电视剧", 28 | "影视", 29 | "纪录片", 30 | "特别推荐" 31 | ] -------------------------------------------------------------------------------- /registry/lib/components/style/home-redesign/fresh/layouts/feeds/feeds.ts: -------------------------------------------------------------------------------- 1 | import { FreshLayoutItem } from '../fresh-layout-item' 2 | 3 | export const feeds: FreshLayoutItem = { 4 | name: 'feeds', 5 | displayName: '动态', 6 | grow: true, 7 | component: () => import('./Feeds.vue').then(m => m.default), 8 | } 9 | -------------------------------------------------------------------------------- /registry/lib/components/style/home-redesign/fresh/layouts/fresh-layout-item.ts: -------------------------------------------------------------------------------- 1 | import { Executable, VueModule, WithName } from '@/core/common-types' 2 | 3 | export interface FreshLayoutItem extends WithName { 4 | component: Executable 5 | grow?: boolean 6 | } 7 | export interface FreshLayoutItemSettings { 8 | linebreak: boolean 9 | order: number 10 | hidden: boolean 11 | } 12 | -------------------------------------------------------------------------------- /registry/lib/components/style/home-redesign/fresh/layouts/layouts.ts: -------------------------------------------------------------------------------- 1 | import { registerAndGetData } from '@/plugins/data' 2 | import { areas } from './areas/areas' 3 | import { blackboard } from './blackboard/blackboard' 4 | import { categories } from './categories/categories' 5 | import { feeds } from './feeds/feeds' 6 | import { trending } from './trending/trending' 7 | 8 | const builtInLayouts = [blackboard, trending, feeds, areas, categories] 9 | export const [layouts] = registerAndGetData('homeRedesign.fresh.layouts', [...builtInLayouts]) 10 | -------------------------------------------------------------------------------- /registry/lib/components/style/home-redesign/fresh/layouts/trending/trending.ts: -------------------------------------------------------------------------------- 1 | import { FreshLayoutItem } from '../fresh-layout-item' 2 | 3 | export const trending: FreshLayoutItem = { 4 | name: 'trending', 5 | displayName: '热门视频', 6 | grow: true, 7 | component: () => import('./Trending.vue').then(m => m.default), 8 | } 9 | -------------------------------------------------------------------------------- /registry/lib/components/style/home-redesign/fresh/options.ts: -------------------------------------------------------------------------------- 1 | import { OptionsOfMetadata } from '@/components/define' 2 | import { getComponentSettings } from '@/core/settings' 3 | import { freshHomeOptionsMetadata } from './types' 4 | 5 | export const freshHomeOptions = 6 | getComponentSettings>('freshHome').options 7 | -------------------------------------------------------------------------------- /registry/lib/components/style/home-redesign/minimal/index.md: -------------------------------------------------------------------------------- 1 | 使用重新设计的极简首页替换原本的首页. 2 | 3 | 请注意: 4 | - 此功能与 `清爽首页` 互斥, 请勿同时使用. 5 | - 此功能会禁用首页的[悬浮视频](https://github.com/the1812/Bilibili-Evolved/discussions/4404), 变为直接跳转到视频页面. 6 | 7 | 选项说明: 8 | - 个性化推荐: 启用时展示推荐视频, 禁用时展示热门视频 9 | - 自定义列数: 为 `0` 时根据视图宽度推断, 大于 `0` 的值将作为固定的列数 -------------------------------------------------------------------------------- /registry/lib/components/style/home-redesign/minimal/options.ts: -------------------------------------------------------------------------------- 1 | import { OptionsOfMetadata } from '@/components/define' 2 | import { getComponentSettings } from '@/core/settings' 3 | import type { minimalHomeOptionsMetadata } from '.' 4 | 5 | export const minimalHomeOptions = 6 | getComponentSettings>('minimalHome').options 7 | -------------------------------------------------------------------------------- /registry/lib/components/style/home-redesign/minimal/types.ts: -------------------------------------------------------------------------------- 1 | export enum MinimalHomeTabOption { 2 | Feeds = '动态', 3 | Trending = '热门 / 推荐', 4 | } 5 | -------------------------------------------------------------------------------- /registry/lib/components/style/home-redesign/urls.ts: -------------------------------------------------------------------------------- 1 | export const homeUrls = [ 2 | /^https:\/\/www\.bilibili\.com\/$/, 3 | /^https:\/\/www\.bilibili\.com\/index\.html$/, 4 | ] 5 | -------------------------------------------------------------------------------- /registry/lib/components/style/player-on-top/index.ts: -------------------------------------------------------------------------------- 1 | import { defineComponentMetadata } from '@/components/define' 2 | 3 | export const component = defineComponentMetadata({ 4 | name: 'playerOnTop', 5 | displayName: '播放器置顶', 6 | description: { 7 | 'zh-CN': '在视频页面中将播放器放在页面最上方.', 8 | }, 9 | instantStyles: [ 10 | { 11 | name: 'playerOnTop', 12 | style: () => import('./player-on-top.scss'), 13 | }, 14 | ], 15 | tags: [componentsTags.style, componentsTags.video], 16 | entry: none, 17 | }) 18 | -------------------------------------------------------------------------------- /registry/lib/components/style/player-on-top/player-on-top.scss: -------------------------------------------------------------------------------- 1 | .v-wrap { 2 | .l-con, 3 | .r-con { 4 | display: flex; 5 | flex-direction: column; 6 | margin-top: 24px; 7 | } 8 | .l-con { 9 | .player-wrap { 10 | order: -1; 11 | } 12 | .video-info { 13 | margin: 20px 0 0 0 !important; 14 | padding: 0 !important; 15 | height: auto !important; 16 | .video-data { 17 | .argue, 18 | .copyright { 19 | overflow: hidden; 20 | text-overflow: ellipsis; 21 | } 22 | } 23 | } 24 | } 25 | .r-con { 26 | .danmaku-box { 27 | order: -1; 28 | } 29 | .up-info { 30 | padding-top: 0 !important; 31 | } 32 | } 33 | } 34 | -------------------------------------------------------------------------------- /registry/lib/components/style/player-shadow/index.ts: -------------------------------------------------------------------------------- 1 | import { defineComponentMetadata } from '@/components/define' 2 | import { allVideoUrls } from '@/core/utils/urls' 3 | 4 | export const component = defineComponentMetadata({ 5 | name: 'playerShadow', 6 | displayName: '播放器投影', 7 | entry: none, 8 | instantStyles: [ 9 | { 10 | name: 'playerShadow', 11 | style: () => import('./player-shadow.scss'), 12 | }, 13 | ], 14 | tags: [componentsTags.style, componentsTags.video], 15 | description: { 16 | 'zh-CN': '为播放器添加主题色投影.', 17 | }, 18 | urlInclude: allVideoUrls, 19 | }) 20 | -------------------------------------------------------------------------------- /registry/lib/components/style/player-shadow/player-shadow.scss: -------------------------------------------------------------------------------- 1 | #bilibili-player, 2 | #bilibili-player.mini-player::before { 3 | box-shadow: 0px 2px 8px 0px var(--theme-color-30) !important; 4 | body.dark & { 5 | box-shadow: 0px 2px 8px 0px var(--theme-color-20) !important; 6 | } 7 | } 8 | #bilibili-player-placeholder, 9 | .bpx-player-container { 10 | box-shadow: none !important; 11 | } 12 | -------------------------------------------------------------------------------- /registry/lib/components/style/scrollbar/index.ts: -------------------------------------------------------------------------------- 1 | import { defineComponentMetadata } from '@/components/define' 2 | 3 | export const component = defineComponentMetadata({ 4 | name: 'elegantScrollbar', 5 | entry: none, 6 | displayName: '使用细滚动条', 7 | description: 8 | '使用浏览器的滚动条风格替代系统的滚动条, 不过 macOS 系统滚动条比浏览器做得好一些, 因此不建议 macOS 使用此功能.', 9 | tags: [componentsTags.style, componentsTags.general], 10 | instantStyles: [ 11 | { 12 | name: 'elegant-scrollbar', 13 | style: () => import('./scrollbar.scss'), 14 | }, 15 | ], 16 | }) 17 | -------------------------------------------------------------------------------- /registry/lib/components/style/scrollbar/scrollbar.scss: -------------------------------------------------------------------------------- 1 | html { 2 | ::-webkit-scrollbar { 3 | width: 5px !important; 4 | height: 5px !important; 5 | } 6 | ::-webkit-scrollbar-corner, 7 | ::-webkit-scrollbar-track { 8 | background: transparent !important; 9 | } 10 | ::-webkit-resizer, 11 | ::-webkit-scrollbar-thumb { 12 | background: #aaa; 13 | border-radius: 3px; 14 | } 15 | ::-webkit-scrollbar-thumb:hover { 16 | background: #888; 17 | } 18 | &, 19 | * { 20 | scrollbar-color: #aaa transparent; 21 | scrollbar-width: thin !important; 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /registry/lib/components/style/sidebar-offset/sidebar-offset.scss: -------------------------------------------------------------------------------- 1 | .be-settings > .sidebar { 2 | top: calc(50% + var(--be-sidebar-offset, 0)) !important; 3 | } 4 | -------------------------------------------------------------------------------- /registry/lib/components/style/simplify/comments/comments-v3-firefox/base.scss: -------------------------------------------------------------------------------- 1 | :host(bili-rich-text) { 2 | #contents img, 3 | #contents a i { 4 | max-width: 1.4em; 5 | max-height: 1.4em; 6 | } 7 | } 8 | -------------------------------------------------------------------------------- /registry/lib/components/style/simplify/comments/comments-v3-firefox/decorate-and-time.scss: -------------------------------------------------------------------------------- 1 | :host(bili-comment-renderer) { 2 | bili-comment-user-sailing-card { 3 | display: none; 4 | } 5 | } 6 | -------------------------------------------------------------------------------- /registry/lib/components/style/simplify/comments/comments-v3-firefox/event-banner.scss: -------------------------------------------------------------------------------- 1 | :host(bili-comments-header-renderer) { 2 | bili-comments-notice { 3 | display: none; 4 | } 5 | } 6 | -------------------------------------------------------------------------------- /registry/lib/components/style/simplify/comments/comments-v3-firefox/fans-medal.scss: -------------------------------------------------------------------------------- 1 | :host(bili-comment-user-info) { 2 | bili-comment-user-medal { 3 | display: none; 4 | } 5 | } 6 | -------------------------------------------------------------------------------- /registry/lib/components/style/simplify/comments/comments-v3-firefox/reply-editor.scss: -------------------------------------------------------------------------------- 1 | :host(bili-comment-box) { 2 | #pub button { 3 | font-size: 14px; 4 | } 5 | } 6 | :host(bili-checkbox) { 7 | #label { 8 | font-size: 15px; 9 | } 10 | } 11 | :host(bili-comment-textarea) { 12 | #input { 13 | font-size: 13px; 14 | } 15 | #input, 16 | #input::placeholder { 17 | line-height: normal; 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /registry/lib/components/style/simplify/comments/comments-v3-firefox/sub-reply-new-line.scss: -------------------------------------------------------------------------------- 1 | :host(bili-comment-reply-renderer) { 2 | bili-comment-user-info { 3 | display: block; 4 | } 5 | } 6 | -------------------------------------------------------------------------------- /registry/lib/components/style/simplify/comments/comments-v3-firefox/user-level.scss: -------------------------------------------------------------------------------- 1 | :host(bili-comment-user-info) { 2 | #user-level { 3 | display: none; 4 | } 5 | } 6 | -------------------------------------------------------------------------------- /registry/lib/components/style/simplify/comments/index.md: -------------------------------------------------------------------------------- 1 | 去除或优化评论区内的元素, 可配置以下选项 (描述的是勾选时的效果): 2 | 3 | > 配置项仅对新版评论区有效 4 | 5 | - `用户等级`: 隐藏用户等级标识. (隐藏后, 可以通过鼠标停留在头像上, 在弹出的资料卡小窗中查看) 6 | - `装扮 & 时间`: 隐藏装扮图片, 并把发送时间移动到装扮的位置. 7 | - `头像框`: 隐藏头像框. 8 | - `回复换行`: 9 | - 楼中楼回复也另起一行显示, 和一级回复保持一致. 10 | - `热评`, `UP 主点赞` 等标记和点赞栏放在同一行. 11 | - `编辑框`: 将提示文本居上, 符合用户实际输入文字的位置, 并将发布按钮的字号略微调小. 12 | - `粉丝勋章`: 隐藏用户的粉丝勋章. 13 | - `小喇叭横幅`: 隐藏评论区顶部的小喇叭横幅 14 | -------------------------------------------------------------------------------- /registry/lib/components/style/simplify/live/skin.ts: -------------------------------------------------------------------------------- 1 | import { addComponentListener } from '@/core/settings' 2 | import { select } from '@/core/spin-query' 3 | 4 | export const setupSkinSimplify = async () => { 5 | addComponentListener( 6 | 'simplifyLiveroom.switch-skin', 7 | async (disable: boolean) => { 8 | const skinCss = (await select('#skin-css')) as HTMLStyleElement 9 | if (!skinCss) { 10 | return 11 | } 12 | skinCss.media = disable ? 'none' : 'all' 13 | }, 14 | true, 15 | ) 16 | } 17 | -------------------------------------------------------------------------------- /registry/lib/components/style/special-danmaku/index.md: -------------------------------------------------------------------------------- 1 | 移除高亮弹幕或 UP 主弹幕的特殊样式, 弹幕内容不会移除. -------------------------------------------------------------------------------- /registry/lib/components/style/v1-panel/index.ts: -------------------------------------------------------------------------------- 1 | import { defineComponentMetadata } from '@/components/define' 2 | 3 | export const component = defineComponentMetadata({ 4 | name: 'v1PanelStyle', 5 | displayName: 'v1 风格设置面板', 6 | tags: [componentsTags.style], 7 | entry: none, 8 | description: { 9 | 'zh-CN': '使用 v1 风格的设置面板样式', 10 | }, 11 | instantStyles: [ 12 | { 13 | name: 'v1PanelStyle', 14 | style: () => import('./v1-panel.scss'), 15 | }, 16 | ], 17 | }) 18 | -------------------------------------------------------------------------------- /registry/lib/components/touch/double-click-control/double-click-control.scss: -------------------------------------------------------------------------------- 1 | @import "./default-state"; 2 | @import "./hover-state"; 3 | @import "./pbp"; 4 | @import "./subtitle"; 5 | 6 | .disable-original-hover { 7 | @include default-state(); 8 | @include hover-state(); 9 | @include pbp(); 10 | @include subtitle(); 11 | } 12 | @import "./fullscreen"; 13 | -------------------------------------------------------------------------------- /registry/lib/components/touch/double-click-control/index.md: -------------------------------------------------------------------------------- 1 | 将视频播放器的操作方式更改为: 单击显示 / 隐藏控制栏, 双击播放 / 暂停. 2 | -------------------------------------------------------------------------------- /registry/lib/components/touch/mini-player/live.ts: -------------------------------------------------------------------------------- 1 | import { select } from '@/core/spin-query' 2 | 3 | export const touchLiveMiniPlayer = async (enable: boolean) => { 4 | const player = (await select('.live-player-ctnr')) as HTMLDivElement 5 | if (!player) { 6 | console.warn('mini player touch move: player not found') 7 | return 8 | } 9 | const { enableTouchMove, disableTouchMove } = await import('./touch-move') 10 | if (enable) { 11 | enableTouchMove(player, { 12 | minMoveDistance: 10, 13 | }) 14 | } else { 15 | disableTouchMove(player) 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /registry/lib/components/touch/mini-player/mini-player.scss: -------------------------------------------------------------------------------- 1 | #bilibili-player.mini-player { 2 | .drag-bar { 3 | touch-action: none !important; 4 | height: 40px !important; 5 | line-height: 40px !important; 6 | top: -40px !important; 7 | i:last-child { 8 | margin: 10px !important; 9 | } 10 | } 11 | } 12 | -------------------------------------------------------------------------------- /registry/lib/components/touch/mini-player/video.ts: -------------------------------------------------------------------------------- 1 | import { select } from '@/core/spin-query' 2 | import { addStyle, removeStyle } from '@/core/style' 3 | import miniPlayerStyle from './mini-player.scss' 4 | 5 | export const touchVideoMiniPlayer = async (enable: boolean) => { 6 | const player = (await select('#bilibili-player')) as HTMLDivElement 7 | if (!player) { 8 | console.warn('mini player touch move: player not found') 9 | return 10 | } 11 | const { enableTouchMove, disableTouchMove } = await import('./touch-move') 12 | const id = 'touch-mini-player' 13 | if (enable) { 14 | addStyle(miniPlayerStyle, id) 15 | enableTouchMove(player) 16 | } else { 17 | removeStyle(id) 18 | disableTouchMove(player) 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /registry/lib/components/touch/player-control/index.ts: -------------------------------------------------------------------------------- 1 | import { defineComponentMetadata } from '@/components/define' 2 | import { playerUrls } from '@/core/utils/urls' 3 | 4 | const id = 'touch-player-control' 5 | const entry = async () => { 6 | document.body.classList.add(id) 7 | } 8 | export const component = defineComponentMetadata({ 9 | name: 'touchPlayerControl', 10 | displayName: '控制栏触摸优化', 11 | description: { 12 | 'zh-CN': '增大播放器控制栏里按钮的间距, 方便触屏使用.', 13 | }, 14 | tags: [componentsTags.touch, componentsTags.style], 15 | enabledByDefault: navigator.maxTouchPoints > 0, 16 | urlInclude: playerUrls, 17 | instantStyles: [ 18 | { 19 | name: id, 20 | style: () => import('./player-control.scss'), 21 | }, 22 | ], 23 | entry, 24 | reload: entry, 25 | unload: () => { 26 | document.body.classList.remove(id) 27 | }, 28 | }) 29 | -------------------------------------------------------------------------------- /registry/lib/components/touch/player-gestures/brightness.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * 设置视频的亮度(会与从播放器中设置的亮度叠加) 3 | */ 4 | export const setBrightness = (video: HTMLElement, brightness: number) => { 5 | let b = brightness 6 | if (b < 0) { 7 | b = 0 8 | } 9 | 10 | video.style.filter = `brightness(${b})` 11 | } 12 | -------------------------------------------------------------------------------- /registry/lib/components/touch/player-gestures/desc.md: -------------------------------------------------------------------------------- 1 | 为播放器启用触摸手势支持: 2 | - 左右滑动可调整进度 3 | - 上下滑动可调整音量 4 | - 进度调整可在左上角和右上角取消 5 | - 进度调整时在不同位置滑动, 可以使用3档不同的灵敏度. -------------------------------------------------------------------------------- /registry/lib/components/touch/player-gestures/gesture-preview.ts: -------------------------------------------------------------------------------- 1 | /** 进度调整模式(灵敏度) */ 2 | export enum ProgressSeekMode { 3 | Fast = '高速', 4 | Medium = '中速', 5 | Slow = '低速', 6 | } 7 | /** 手势操作预览参数 */ 8 | export interface GesturePreviewParams { 9 | /** 亮度调整 */ 10 | brightness?: number 11 | /** 音量调整 */ 12 | volume?: number 13 | /** 进度调整 */ 14 | progress?: number 15 | } 16 | -------------------------------------------------------------------------------- /registry/lib/components/touch/player-gestures/index.ts: -------------------------------------------------------------------------------- 1 | import { defineComponentMetadata } from '@/components/define' 2 | import { playerUrls } from '@/core/utils/urls' 3 | import desc from './desc.md' 4 | import { entry } from './entry' 5 | 6 | export const component = defineComponentMetadata({ 7 | name: 'touchPlayerGestures', 8 | displayName: '播放器触摸手势', 9 | enabledByDefault: navigator.maxTouchPoints > 0, 10 | tags: [componentsTags.touch], 11 | description: { 12 | 'zh-CN': desc, 13 | }, 14 | entry, 15 | urlInclude: playerUrls, 16 | options: { 17 | swiperDistance: { 18 | displayName: '手势触发最小距离', 19 | defaultValue: 10, 20 | hidden: true, 21 | }, 22 | }, 23 | }) 24 | -------------------------------------------------------------------------------- /registry/lib/components/touch/player-gestures/progress.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * 设置视频的进度 3 | * @param video 视频元素 4 | * @param progress 目标进度 5 | */ 6 | export const setProgress = (video: HTMLVideoElement, progress: number) => { 7 | let p = progress 8 | if (p > video.duration) { 9 | p = video.duration 10 | } else if (p < 0) { 11 | p = 0 12 | } 13 | unsafeWindow.player.seek(p, video.paused) 14 | } 15 | -------------------------------------------------------------------------------- /registry/lib/components/touch/player-gestures/volume.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * 更新音频 UI (如果需要) 3 | */ 4 | export const syncVolumeUI = (volume: number) => { 5 | unsafeWindow.player?.volume(volume) 6 | } 7 | /** 8 | * 设置视频的音量, 更新播放器的状态, 并保存这个音量 9 | * @param video 视频元素 10 | * @param volume 目标音量(0~1) 11 | */ 12 | export const setVolume = async (video: HTMLVideoElement, volume: number) => { 13 | let v = volume 14 | if (v > 1) { 15 | v = 1 16 | } else if (v < 0) { 17 | v = 0 18 | } 19 | 20 | video.volume = v 21 | } 22 | -------------------------------------------------------------------------------- /registry/lib/components/utils/album-time-show/album-time.scss: -------------------------------------------------------------------------------- 1 | /* 保持相簿元素高度 */ 2 | .album-card { 3 | margin-bottom: 21px; 4 | } 5 | 6 | /* 上移原互动数据 */ 7 | .album-card .album-card__info { 8 | margin-top: -5px; 9 | } 10 | 11 | /* 相簿发布时间样式 */ 12 | .album-pub-time { 13 | color: #99a2aa; 14 | 15 | body.dark & { 16 | color: #aaa; 17 | } 18 | 19 | position: absolute; 20 | margin-top: -5px; 21 | } -------------------------------------------------------------------------------- /registry/lib/components/utils/auto-like/index.md: -------------------------------------------------------------------------------- 1 | 进入视频 / 查看动态时, 自动点赞\ 2 | 无法触发未加载动态的点赞,当启用手动对动态点赞后可手动触发,启用后不会触发动态自动点赞\ 3 | 安装快捷键扩展后可以点击【l】键或【L】键触发\ 4 | 还可以添加动态点赞的黑名单\ 5 | -------------------------------------------------------------------------------- /registry/lib/components/utils/black-list/common.ts: -------------------------------------------------------------------------------- 1 | export const BlackListDataKey = 'blackList.data' 2 | -------------------------------------------------------------------------------- /registry/lib/components/utils/change-update-urls/index.ts: -------------------------------------------------------------------------------- 1 | import { defineComponentMetadata } from '@/components/define' 2 | 3 | export const component = defineComponentMetadata({ 4 | name: 'changeUpdateUrls', 5 | displayName: '更新链接替换', 6 | description: '批量更换已安装功能的更新链接的分支, 对本地安装的功能无效.', 7 | entry: none, 8 | tags: [componentsTags.utils], 9 | widget: { 10 | component: () => import('./Widget.vue').then(m => m.default), 11 | }, 12 | }) 13 | -------------------------------------------------------------------------------- /registry/lib/components/utils/check-in-center/index.ts: -------------------------------------------------------------------------------- 1 | import { defineComponentMetadata } from '@/components/define' 2 | import { getUID } from '@/core/utils' 3 | 4 | export const component = defineComponentMetadata({ 5 | name: 'checkInCenter', 6 | displayName: '签到助手', 7 | description: { 8 | 'zh-CN': '在功能面板中提供一些可以每日进行的操作.', 9 | }, 10 | tags: [componentsTags.utils], 11 | entry: none, 12 | widget: { 13 | component: () => import('./Widget.vue').then(m => m.default), 14 | condition: () => Boolean(getUID()), 15 | }, 16 | }) 17 | -------------------------------------------------------------------------------- /registry/lib/components/utils/column-unlock/index.md: -------------------------------------------------------------------------------- 1 | (原名: 专栏文字选择, 现在专栏已经不限制选中文字了) 2 | 3 | 避免专栏的文字复制后在最后带上出处信息, 更贴近原生的复制行为. 4 | -------------------------------------------------------------------------------- /registry/lib/components/utils/comments/content-replace/handlers/emoticon-to-emoticon.ts: -------------------------------------------------------------------------------- 1 | import { isUrl } from '../utils' 2 | import { NodeContentReplacer } from './node-content-replacer' 3 | 4 | export class EmoticonToEmoticonReplacer extends NodeContentReplacer { 5 | isKeywordMatch(node: Node, keyword: string, target: string) { 6 | if (node instanceof HTMLImageElement) { 7 | return node.alt === keyword && isUrl(target) 8 | } 9 | return false 10 | } 11 | replaceContent(node: Node, keyword: string, target: string): Node[] { 12 | if (!(node instanceof HTMLImageElement)) { 13 | return [] 14 | } 15 | node.src = target 16 | return [] 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /registry/lib/components/utils/comments/content-replace/handlers/emoticon-to-text.ts: -------------------------------------------------------------------------------- 1 | import { NodeContentReplacer } from './node-content-replacer' 2 | 3 | export class EmoticonToTextReplacer extends NodeContentReplacer { 4 | isKeywordMatch(node: Node, keyword: string) { 5 | if (node instanceof HTMLImageElement) { 6 | return node.alt === keyword 7 | } 8 | return false 9 | } 10 | replaceContent(node: Node, keyword: string, target: string): Node[] { 11 | if (!(node instanceof HTMLImageElement)) { 12 | return [] 13 | } 14 | if (target === '') { 15 | node.remove() 16 | } else { 17 | node.replaceWith(new Text(target)) 18 | } 19 | return [] 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /registry/lib/components/utils/comments/content-replace/handlers/node-content-replacer.ts: -------------------------------------------------------------------------------- 1 | export abstract class NodeContentReplacer { 2 | abstract isKeywordMatch(node: Node, keyword: string, target: string): boolean 3 | abstract replaceContent(node: Node, keyword: string, target: string): Node[] 4 | } 5 | -------------------------------------------------------------------------------- /registry/lib/components/utils/comments/content-replace/handlers/recursive.ts: -------------------------------------------------------------------------------- 1 | import { NodeContentReplacer } from './node-content-replacer' 2 | 3 | export class RecursiveReplacer extends NodeContentReplacer { 4 | isKeywordMatch() { 5 | return true 6 | } 7 | replaceContent(node: Node): Node[] { 8 | return Array.from(node.childNodes) 9 | } 10 | } 11 | -------------------------------------------------------------------------------- /registry/lib/components/utils/comments/content-replace/handlers/text-to-text.ts: -------------------------------------------------------------------------------- 1 | import { NodeContentReplacer } from './node-content-replacer' 2 | 3 | export class TextToTextReplacer extends NodeContentReplacer { 4 | isKeywordMatch(node: Node, keyword: string) { 5 | if (node instanceof Text) { 6 | return node.textContent.includes(keyword) 7 | } 8 | return false 9 | } 10 | replaceContent(node: Node, keyword: string, target: string): Node[] { 11 | const index = node.textContent.indexOf(keyword) 12 | if (index === -1) { 13 | return [] 14 | } 15 | const leftPart = node.textContent.substring(0, index) 16 | const rightPart = node.textContent.substring(index + keyword.length) 17 | node.textContent = `${leftPart}${target}${rightPart}` 18 | return [] 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /registry/lib/components/utils/comments/content-replace/handlers/types.ts: -------------------------------------------------------------------------------- 1 | import type { CommentItem } from '@/components/utils/comment-apis' 2 | 3 | export interface CommentContentReplaceContext { 4 | commentItem: CommentItem 5 | content: Node[] 6 | } 7 | export type CommentContentReplaceHandler = ( 8 | context: CommentContentReplaceContext, 9 | ) => void | Promise 10 | -------------------------------------------------------------------------------- /registry/lib/components/utils/comments/content-replace/index.md: -------------------------------------------------------------------------------- 1 | 替换评论中的内容. 2 | 3 | 可以添加多个替换配置, 每项配置可将一个关键词替换为其他文本. 若替换的目标是一个链接, 则视作替换为表情, 留空则会移除命中的关键词. 4 | -------------------------------------------------------------------------------- /registry/lib/components/utils/comments/content-replace/options.ts: -------------------------------------------------------------------------------- 1 | import { defineOptionsMetadata, OptionsOfMetadata } from '@/components/define' 2 | 3 | export const commentContentReplaceOptions = defineOptionsMetadata({ 4 | replaceMap: { 5 | defaultValue: {} as Record, 6 | hidden: true, 7 | }, 8 | }) 9 | 10 | export type CommentContentReplaceOptions = OptionsOfMetadata 11 | -------------------------------------------------------------------------------- /registry/lib/components/utils/comments/content-replace/settings/row.ts: -------------------------------------------------------------------------------- 1 | import { getRandomId } from '@/core/utils' 2 | 3 | export class CommentContentReplaceRow { 4 | key = getRandomId() 5 | constructor(public from = '', public to = '') {} 6 | } 7 | -------------------------------------------------------------------------------- /registry/lib/components/utils/comments/content-replace/utils.ts: -------------------------------------------------------------------------------- 1 | export const createEmoticonImage = (src: string, alt: string) => { 2 | const element = document.createElement('img') 3 | element.src = src 4 | element.alt = alt 5 | element.loading = 'lazy' 6 | element.style.width = '50px' 7 | element.style.height = '50px' 8 | return element 9 | } 10 | 11 | export const isUrl = (text: string) => { 12 | try { 13 | const url = new URL(text) 14 | return Boolean(url) 15 | } catch (error) { 16 | return false 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /registry/lib/components/utils/comments/disable-search-link/disable-search-link-shadow.scss: -------------------------------------------------------------------------------- 1 | :host(bili-rich-text) { 2 | #contents a[data-type='search'] { 3 | color: inherit !important; 4 | cursor: inherit !important; 5 | display: contents !important; 6 | img { 7 | display: none; 8 | } 9 | } 10 | } 11 | -------------------------------------------------------------------------------- /registry/lib/components/utils/comments/disable-search-link/disable-search-link.scss: -------------------------------------------------------------------------------- 1 | .search-word { 2 | &.icon { 3 | display: none !important; 4 | } 5 | // 需要比夜间模式的优先级高 6 | .reply-warp .reply-item &.jump-link { 7 | color: inherit !important; 8 | cursor: text !important; 9 | } 10 | } -------------------------------------------------------------------------------- /registry/lib/components/utils/comments/disable-search-link/index.md: -------------------------------------------------------------------------------- 1 | 禁用评论区的搜索词链接. -------------------------------------------------------------------------------- /registry/lib/components/utils/dev-client/index.md: -------------------------------------------------------------------------------- 1 | 本地开发工具, 提供自动更新功能和样式热重载的能力, 需要与 DevServer 配合使用. (DevServer 的使用方式见 [CONTRIBUTING.md](https://github.com/the1812/Bilibili-Evolved/blob/preview/CONTRIBUTING.md)) 2 | 3 | `自动连接` 开启时, 每次进入网页都会自动尝试连接到 DevServer, 如果关闭则需要手动操作连接. 4 | 5 | `刷新策略` 决定了收到本体或者功能更新的消息时是否刷新: 6 | - **总是刷新**: 收到更新时立即刷新页面 7 | - 不刷新: 收到更新时不刷新页面 8 | 9 | `热重载策略` 决定了是否开启热重载功能, 只要成功触发热重载, 就不刷新页面: 10 | - **开启热重载**: 功能带有 `instantStyles` 时, 热重载 `instantStyles` 中的样式 11 | - 关闭热重载: 收到更新时按 `刷新策略` 执行 12 | 13 | > 目前就这两个选项, 将来可能会支持对 `entry` 的热重载 14 | -------------------------------------------------------------------------------- /registry/lib/components/utils/dev-client/update-method.ts: -------------------------------------------------------------------------------- 1 | export enum HotReloadMethod { 2 | Enabled = '开启热重载', 3 | // TODO: 实现 entry 热重载 4 | // StylesOnly = '仅样式', 5 | Disabled = '关闭热重载', 6 | } 7 | export enum RefreshMethod { 8 | AlwaysRefresh = '总是刷新', 9 | DoNotRefresh = '不刷新', 10 | } 11 | -------------------------------------------------------------------------------- /registry/lib/components/utils/download-audio/index.ts: -------------------------------------------------------------------------------- 1 | import { defineComponentMetadata } from '@/components/define' 2 | 3 | export const component = defineComponentMetadata({ 4 | name: 'downloadAudio', 5 | displayName: '下载音频', 6 | entry: none, 7 | tags: [componentsTags.utils], 8 | description: { 9 | 'zh-CN': ` 10 | 开启音频下载支持, 音频页面中可以在功能面板中下载当前音频. 11 | 12 | > 需要进入音频的详细信息页面才能下载, 在其他页面中此按钮将不可点击. 13 | `.trim(), 14 | }, 15 | widget: { 16 | component: () => import('./DownloadAudio.vue').then(m => m.default), 17 | }, 18 | urlInclude: ['//www.bilibili.com/audio/'], 19 | }) 20 | -------------------------------------------------------------------------------- /registry/lib/components/utils/image-resolution/fix.scss: -------------------------------------------------------------------------------- 1 | .favInfo-box .collection-cover img, 2 | .favInfo-box .favInfo-cover img { 3 | width: 100% !important; 4 | object-position: left !important; 5 | } 6 | .bb-comment .sailing .sailing-img, 7 | .comment-bilibili-fold .sailing .sailing-img { 8 | width: 288px; 9 | } 10 | -------------------------------------------------------------------------------- /registry/lib/components/utils/image-resolution/index.md: -------------------------------------------------------------------------------- 1 | 对 200% 以上的屏幕 DPI 缩放请求更高分辨率的图片, 加载时间也会相应变长一些. (也会导致某些浏览器里出现图片闪动, 因为本质上是更换了图片源) 2 | 3 | 由于 b 站在很多地方没有设置图片维持原比例, 如果计算后的图片尺寸超出原图尺寸则会产生错误的比例, 可以考虑在选项中手动降低缩放级别. 4 | 5 | `缩放级别` 选项: 6 | - `auto`: 根据 DPI 缩放超出 200% 的比例自动计算, 例如 250% 的缩放下会请求 1.5 倍尺寸的图片. 7 | - `数字`: 自定义尺寸的缩放倍率. 8 | -------------------------------------------------------------------------------- /registry/lib/components/utils/image-resolution/index.ts: -------------------------------------------------------------------------------- 1 | import { 2 | defineComponentMetadata, 3 | defineOptionsMetadata, 4 | OptionsOfMetadata, 5 | } from '@/components/define' 6 | import { startResolution } from './resolution' 7 | 8 | const options = defineOptionsMetadata({ 9 | scale: { 10 | displayName: '缩放级别', 11 | defaultValue: 'auto', 12 | }, 13 | originalImageInArticles: { 14 | displayName: '在专栏中请求原图', 15 | defaultValue: false, 16 | }, 17 | }) 18 | 19 | export type Options = OptionsOfMetadata 20 | 21 | export const component = defineComponentMetadata({ 22 | name: 'imageResolution', 23 | displayName: '高分辨率图片', 24 | tags: [componentsTags.utils], 25 | enabledByDefault: window.devicePixelRatio > 1, 26 | entry: startResolution, 27 | options, 28 | }) 29 | -------------------------------------------------------------------------------- /registry/lib/components/utils/import-series/index.ts: -------------------------------------------------------------------------------- 1 | import { defineComponentMetadata } from '@/components/define' 2 | import { realEntry } from './logic' 3 | 4 | export const component = defineComponentMetadata({ 5 | name: 'importSeries', 6 | author: { 7 | name: 'aiden', 8 | link: 'https://github.com/swhoro', 9 | }, 10 | displayName: '批量导入合集', 11 | tags: [componentsTags.utils], 12 | entry: realEntry, 13 | description: { 14 | 'zh-CN': '在合集页面制作一个批量导入按钮,可以新增所有合集内视频至同名收藏夹', 15 | }, 16 | urlInclude: [/^https:\/\/space\.bilibili\.com\//], 17 | }) 18 | -------------------------------------------------------------------------------- /registry/lib/components/utils/keymap/playback-tip.scss: -------------------------------------------------------------------------------- 1 | // 自定义提示框 2 | .keymap-tip-container { 3 | position: absolute; 4 | left: 50%; 5 | top: 50%; 6 | transform: translate(-50%, -50%); 7 | padding: 8px 16px; 8 | background-color: #000a; 9 | color: white; 10 | pointer-events: none; 11 | opacity: 0; 12 | z-index: 100; 13 | display: flex; 14 | align-items: center; 15 | font-size: 14pt; 16 | border-radius: 4px; 17 | transition: 0.2s ease-out; 18 | body.player-mode-blackmask & { 19 | z-index: 10017; 20 | } 21 | &.show { 22 | opacity: 1; 23 | } 24 | i { 25 | line-height: 1; 26 | margin-right: 8px; 27 | font-size: 18pt; 28 | } 29 | } 30 | // b 站的提示框 31 | .bilibili-player .bilibili-player-area .bilibili-player-video-wrap .bilibili-player-volumeHint { 32 | &-icon { 33 | line-height: 1; 34 | } 35 | background-color: #000a; 36 | color: white; 37 | } 38 | -------------------------------------------------------------------------------- /registry/lib/components/utils/keymap/settings/vm.ts: -------------------------------------------------------------------------------- 1 | import { mountVueComponent } from '@/core/utils' 2 | 3 | let settingsVM: Vue & { 4 | popupOpen: boolean 5 | triggerElement: HTMLElement 6 | } 7 | 8 | export const loadKeymapSettings = async (button?: HTMLElement) => { 9 | if (settingsVM) { 10 | return 11 | } 12 | const KeymapSettings = await import('./KeymapSettings.vue').then(m => m.default) 13 | settingsVM = mountVueComponent(KeymapSettings) 14 | if (button) { 15 | settingsVM.triggerElement = button 16 | } 17 | document.body.insertAdjacentElement('beforeend', settingsVM.$el) 18 | } 19 | export const toggleKeymapSettings = async (button?: HTMLElement) => { 20 | if (!settingsVM) { 21 | await loadKeymapSettings(button) 22 | } 23 | settingsVM.popupOpen = !settingsVM.popupOpen 24 | } 25 | -------------------------------------------------------------------------------- /registry/lib/components/utils/remove-promotions/index.md: -------------------------------------------------------------------------------- 1 | 删除站内的各种广告. 包括首页的推广模块, 手机 app 推荐, 视频页面右侧的广告等. 注意: 首页推广模块删除后留下空白区域是正常现象, 如果觉得怪可以开启 \`占位文本\` 选项. 2 | 3 | - \`占位文本\`: 删除首页推广模块的广告后显示"🚫已屏蔽广告"来替代空白区域. 4 | - \`保留活动横幅\`: 保留视频页面的活动横幅. 5 | -------------------------------------------------------------------------------- /registry/lib/components/utils/subscribe-time-show/subscribe-time.scss: -------------------------------------------------------------------------------- 1 | /* 上移原名称 */ 2 | #page-follows .list-item .content .title { 3 | margin-top: -9px; 4 | } 5 | 6 | /* 上移原简介/官方认证 */ 7 | #page-follows .list-item .content p { 8 | margin-top: -1px; 9 | } 10 | 11 | /* 修复关注时间元素的高度带来的布局影响 */ 12 | .subscribe-time-fix { 13 | margin-bottom: -10px; 14 | } 15 | -------------------------------------------------------------------------------- /registry/lib/components/utils/url-params-clean/index.md: -------------------------------------------------------------------------------- 1 | 自动删除网址中的多余跟踪参数。请注意这会导致浏览器历史记录出现重复的标题(分别是转换前后的网址),并可能导致后退要多退几次。 2 | -------------------------------------------------------------------------------- /registry/lib/components/utils/view-cover/types.ts: -------------------------------------------------------------------------------- 1 | export type CoverDownloadType = 'jpg' 2 | -------------------------------------------------------------------------------- /registry/lib/components/utils/watchlater-redirect/index.md: -------------------------------------------------------------------------------- 1 | 将稍后再看的链接重定向为普通播放网址. 2 | - `重定向页面`: 对稍后再看列表页面里的链接重定向. 3 | - `重定向顶栏`: 对 `自定义顶栏` 里的稍后再看链接重定向. 4 | -------------------------------------------------------------------------------- /registry/lib/components/video/auto-remove-watchlater/index.md: -------------------------------------------------------------------------------- 1 | 在稍后再看页面播放结束时, 自动将当前视频移出稍后再看. 2 | 注意: 3 | - 一定要播放结束, 快结束时手动切走不算 4 | - b 站的稍后再看列表不会实时刷新 5 | -------------------------------------------------------------------------------- /registry/lib/components/video/biliplus-redirect/index.ts: -------------------------------------------------------------------------------- 1 | import { defineComponentMetadata } from '@/components/define' 2 | import { videoAndBangumiUrls } from '@/core/utils/urls' 3 | 4 | export const component = defineComponentMetadata({ 5 | name: 'biliplusRedirect', 6 | displayName: 'BiliPlus 跳转支持', 7 | description: { 8 | 'zh-CN': '在视频 / 番剧 / 空间中, 可以从功能中的按钮点击转到 BiliPlus 上对应的页面.', 9 | }, 10 | urlInclude: [...videoAndBangumiUrls, '//space.bilibili.com'], 11 | entry: none, 12 | tags: [componentsTags.video, componentsTags.utils], 13 | widget: { 14 | component: () => import('./BiliplusRedirect.vue').then(m => m.default), 15 | }, 16 | }) 17 | -------------------------------------------------------------------------------- /registry/lib/components/video/danmaku/airborne/airborne.scss: -------------------------------------------------------------------------------- 1 | .bili-dm, 2 | .b-danmaku, 3 | .bili-danmaku-x-dm { 4 | &.airborne { 5 | text-decoration: underline; 6 | cursor: pointer; 7 | pointer-events: initial; 8 | } 9 | } 10 | -------------------------------------------------------------------------------- /registry/lib/components/video/danmaku/converter/danmaku-data.ts: -------------------------------------------------------------------------------- 1 | import { DanmakuType } from './danmaku-type' 2 | 3 | export interface BasicDanmakuData { 4 | content: string 5 | time: string 6 | type: string 7 | fontSize: string 8 | color: string 9 | } 10 | export class Danmaku { 11 | content: string 12 | time: string 13 | startTime: number 14 | type: DanmakuType 15 | fontSize: number 16 | color: number 17 | constructor({ content, time, type, fontSize, color }: BasicDanmakuData) { 18 | this.content = content 19 | this.time = time 20 | this.startTime = parseFloat(time) 21 | this.type = parseInt(type) 22 | this.fontSize = parseFloat(fontSize) 23 | this.color = parseInt(color) 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /registry/lib/components/video/danmaku/converter/danmaku-type.ts: -------------------------------------------------------------------------------- 1 | export enum DanmakuType { 2 | Normal = 1, 3 | Normal2, 4 | Normal3, 5 | Bottom, 6 | Top, 7 | Reversed, 8 | Special, 9 | Special2, 10 | } 11 | -------------------------------------------------------------------------------- /registry/lib/components/video/danmaku/download/danmaku.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /registry/lib/components/video/danmaku/download/options.ts: -------------------------------------------------------------------------------- 1 | import { defineOptionsMetadata, OptionsOfMetadata } from '@/components/define' 2 | 3 | export const downloadDanmakuOptions = defineOptionsMetadata({ 4 | speed: { 5 | defaultValue: 'auto' as 'auto' | number, 6 | hidden: true, 7 | }, 8 | }) 9 | 10 | export type DownloadDanmakuOptions = OptionsOfMetadata 11 | -------------------------------------------------------------------------------- /registry/lib/components/video/danmaku/expand/index.md: -------------------------------------------------------------------------------- 1 | 每次加载视频时自动展开弹幕列表, 如果弹幕装载量超过 `最大弹幕数量`, 则不展开以免对页面造成卡顿. (`最大弹幕数量` 是和视频的总弹幕量对比, 不一定和播放器实际装载的弹幕量相等) 2 | -------------------------------------------------------------------------------- /registry/lib/components/video/danmaku/unescape/index.md: -------------------------------------------------------------------------------- 1 | 将弹幕中的 `\n` 或 `/n` 替换为真实的换行, 注意这可能导致原先不重叠的弹幕发生重叠. 2 | -------------------------------------------------------------------------------- /registry/lib/components/video/default-location/_bar.scss: -------------------------------------------------------------------------------- 1 | @mixin title-container { 2 | height: 24px; 3 | line-height: 24px; 4 | padding: 0 8px; 5 | } 6 | 7 | @mixin icon-container { 8 | display: flex; 9 | align-items: center; 10 | justify-content: center; 11 | height: 24px; 12 | width: 24px; 13 | color: #888a; 14 | } 15 | -------------------------------------------------------------------------------- /registry/lib/components/video/default-location/_form.scss: -------------------------------------------------------------------------------- 1 | .video-default-location-form-line { 2 | display: flex; 3 | flex-wrap: wrap; 4 | align-items: center; 5 | column-gap: 10px; 6 | } 7 | 8 | .video-default-location-form-item-grow { 9 | flex: 1 auto; 10 | } 11 | 12 | .video-default-location-form-item-not-grow { 13 | flex: 0 auto; 14 | } 15 | 16 | .video-default-location-vertical-space { 17 | height: 8px; 18 | } 19 | -------------------------------------------------------------------------------- /registry/lib/components/video/default-location/desc.md: -------------------------------------------------------------------------------- 1 | 打开视频/番剧时自动定位到指定位置 2 | 3 | 位置:距离页面顶部的像素距离\ 4 | 默认位置:打开视频时自动定位到此处\ 5 | 位置测试:查看、调整当前页面所在位置 6 | 7 | 当前版本限制默认位置的最大值为 4000。\ 8 | 若有其他希望支持的页面,请提交反馈。\ 9 | 脚本不会等待评论完全加载,因此较大的默认位置将无法正确定位。 10 | -------------------------------------------------------------------------------- /registry/lib/components/video/download/apis/url.ts: -------------------------------------------------------------------------------- 1 | export const videoApi = (params: string) => `https://api.bilibili.com/x/player/playurl?${params}` 2 | export const bangumiApi = (params: string) => 3 | `https://api.bilibili.com/pgc/player/web/playurl?${params}` 4 | -------------------------------------------------------------------------------- /registry/lib/components/video/download/index.md: -------------------------------------------------------------------------------- 1 | 在功能面板中添加下载视频支持. 请注意: 2 | - 不能下载超出账号权限的视频, 例如非大会员下载大会员清晰度视频, 或者大陆地区网络下载港澳台地区番剧, 都是不可以的. 3 | - 请勿短时间进行大量下载, 以免遭到 b 站 IP 封禁. 4 | 5 | 在使用视频 (非番剧) 批量下载时, 文件的批量命名格式中可以使用以下额外变量: 6 | - `user`: UP 主用户名 7 | - `userID`: UP 主用户 ID 8 | - 视频发布时间: 9 | - `publishYear` 10 | - `publishMonth` 11 | - `publishDay` 12 | - `publishHour` 13 | - `publishMinute` 14 | - `publishSecond` 15 | - `publishMillisecond` 16 | -------------------------------------------------------------------------------- /registry/lib/components/video/download/inputs/episode-item.ts: -------------------------------------------------------------------------------- 1 | import { DownloadVideoInputItem } from '../types' 2 | import EpisodesPicker from './EpisodesPicker.vue' 3 | 4 | export interface EpisodeItem { 5 | key: string 6 | title: string 7 | isChecked: boolean 8 | inputItem: DownloadVideoInputItem 9 | durationText?: string 10 | } 11 | export const createEpisodesPicker = ( 12 | fetchEpisodeItems: (instance: any) => Promise, 13 | ) => 14 | Vue.extend({ 15 | computed: { 16 | checkedInputItems() { 17 | return this.$refs.picker.checkedInputItems 18 | }, 19 | }, 20 | render(createElement) { 21 | return createElement(EpisodesPicker, { 22 | props: { api: fetchEpisodeItems }, 23 | ref: 'picker', 24 | }) 25 | }, 26 | }) 27 | -------------------------------------------------------------------------------- /registry/lib/components/video/download/inputs/video/input.ts: -------------------------------------------------------------------------------- 1 | import { getFriendlyTitle } from '@/core/utils/title' 2 | import { videoUrls } from '@/core/utils/urls' 3 | import { DownloadVideoInput } from '../../types' 4 | 5 | export const videoSingleInput: DownloadVideoInput = { 6 | name: 'video', 7 | displayName: '当前视频', 8 | match: videoUrls, 9 | getInputs: async () => [ 10 | { 11 | aid: unsafeWindow.aid, 12 | cid: unsafeWindow.cid, 13 | title: getFriendlyTitle(true), 14 | }, 15 | ], 16 | component: () => import('./SingleVideoInfo.vue').then(m => m.default), 17 | } 18 | -------------------------------------------------------------------------------- /registry/lib/components/video/full-description/full-description.scss: -------------------------------------------------------------------------------- 1 | .video-desc .info, 2 | .video-desc .desc-info, 3 | .video-desc-v1 .desc-info, 4 | .video-desc-container .basic-desc-info, 5 | .play-up-info .play-up-self { 6 | height: auto !important; 7 | } 8 | .video-desc .btn, 9 | .video-desc .toggle-btn, 10 | .video-desc-container .toggle-btn, 11 | .video-desc-v1 .toggle-btn, 12 | .play-up-info .play-up-self-btn { 13 | display: none !important; 14 | } 15 | -------------------------------------------------------------------------------- /registry/lib/components/video/full-episode-title/index.md: -------------------------------------------------------------------------------- 1 | 提供一些视频选集区域的优化, 对番剧无效. 2 | - `展开选集标题`: 总是完全展开视频选集列表项的标题, 若为传统分 P 列表, 还会恢复显示分 P 数的前缀. 3 | - `展开选集列表`: 总是完全展开视频选集列表 4 | 5 | 打开 `展开选集列表` 时, 在选集区域的标题上按住 Alt 键点击可以临时切换此组件的效果. 6 | -------------------------------------------------------------------------------- /registry/lib/components/video/metadata/options.ts: -------------------------------------------------------------------------------- 1 | import { defineOptionsMetadata, OptionsOfMetadata } from '@/components/define' 2 | 3 | export enum FieldsMode { 4 | ALL = '全部', 5 | Standard = '仅标准字段', 6 | } 7 | 8 | export const options = defineOptionsMetadata({ 9 | fieldsMode: { 10 | defaultValue: FieldsMode.ALL, 11 | displayName: 'FFMETADATA 字段', 12 | dropdownEnum: FieldsMode, 13 | }, 14 | }) 15 | 16 | export type Options = OptionsOfMetadata 17 | -------------------------------------------------------------------------------- /registry/lib/components/video/outer-watchlater/options.ts: -------------------------------------------------------------------------------- 1 | import { defineOptionsMetadata, OptionsOfMetadata } from '@/components/define' 2 | 3 | export enum DisplayMode { 4 | Auto = '自动', 5 | Icon = '图标', 6 | IconAndText = '图标 + 文字', 7 | } 8 | export const options = defineOptionsMetadata({ 9 | showInWatchlaterPages: { 10 | defaultValue: false, 11 | displayName: '在稍后再看页面中仍然显示', 12 | }, 13 | displayMode: { 14 | defaultValue: DisplayMode.Auto, 15 | displayName: '显示方式', 16 | dropdownEnum: DisplayMode, 17 | }, 18 | }) 19 | 20 | export type Options = OptionsOfMetadata 21 | -------------------------------------------------------------------------------- /registry/lib/components/video/player/common/mini-rxjs/index.ts: -------------------------------------------------------------------------------- 1 | export * from './create' 2 | export * from './subject' 3 | export * from './utils' 4 | -------------------------------------------------------------------------------- /registry/lib/components/video/player/common/mini-rxjs/operators/bufferSet.ts: -------------------------------------------------------------------------------- 1 | import { PublishContext } from '../subject' 2 | 3 | export const bufferSet = 4 | (predicate: (value: T) => boolean) => 5 | ({ subscribe, next }: PublishContext) => { 6 | const set = new Set() 7 | subscribe(value => { 8 | const oldSize = set.size 9 | if (predicate(value)) { 10 | set.add(value) 11 | } else { 12 | set.delete(value) 13 | } 14 | set.size !== oldSize && next([...set]) 15 | }) 16 | return () => { 17 | set.clear() 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /registry/lib/components/video/player/common/mini-rxjs/operators/debounceTime.ts: -------------------------------------------------------------------------------- 1 | import { PublishContext } from '../subject' 2 | 3 | export const debounceTime = 4 | (wait: number) => 5 | ({ subscribe, next, error }: PublishContext) => { 6 | subscribe( 7 | lodash.debounce(value => { 8 | try { 9 | next(value) 10 | } catch (err) { 11 | error(err) 12 | } 13 | }, wait), 14 | ) 15 | } 16 | -------------------------------------------------------------------------------- /registry/lib/components/video/player/common/mini-rxjs/operators/distinctUntilChanged.ts: -------------------------------------------------------------------------------- 1 | import { PublishContext } from '../subject' 2 | 3 | export const distinctUntilChanged = 4 | () => 5 | ({ subscribe, next }: PublishContext) => { 6 | let firstVisited = true 7 | let previous 8 | 9 | subscribe(value => { 10 | if (firstVisited || previous !== value) { 11 | firstVisited = false 12 | previous = value 13 | next(value) 14 | } 15 | }) 16 | } 17 | -------------------------------------------------------------------------------- /registry/lib/components/video/player/common/mini-rxjs/operators/filter.ts: -------------------------------------------------------------------------------- 1 | import { PublishContext } from '../subject' 2 | 3 | export const filter = 4 | (predicate: (value: T) => boolean) => 5 | ({ subscribe, next }: PublishContext) => { 6 | subscribe(value => { 7 | predicate(value) && next(value) 8 | }) 9 | } 10 | -------------------------------------------------------------------------------- /registry/lib/components/video/player/common/mini-rxjs/operators/map.ts: -------------------------------------------------------------------------------- 1 | import { PublishContext } from '../subject' 2 | 3 | export const map = 4 | (mapper: (value: T) => R) => 5 | ({ subscribe, next }: PublishContext) => { 6 | subscribe(value => { 7 | next(mapper(value)) 8 | }) 9 | } 10 | -------------------------------------------------------------------------------- /registry/lib/components/video/player/common/mini-rxjs/operators/observeOn.ts: -------------------------------------------------------------------------------- 1 | import { PublishContext } from '../subject' 2 | 3 | export const observeOn = 4 | scheduler => 5 | ({ subscribe, next, complete, error }: PublishContext) => { 6 | subscribe( 7 | lodash.mapValues( 8 | { 9 | next, 10 | complete, 11 | error, 12 | }, 13 | action => scheduler(action), 14 | ), 15 | ) 16 | } 17 | 18 | export const asapScheduler = 19 | action => 20 | (...args) => { 21 | Promise.resolve().then(() => action(...args)) 22 | } 23 | -------------------------------------------------------------------------------- /registry/lib/components/video/player/common/mini-rxjs/operators/pairwise.ts: -------------------------------------------------------------------------------- 1 | import { PublishContext } from '../subject' 2 | 3 | export const pairwise = 4 | () => 5 | ({ subscribe, next }: Pick, 'subscribe' | 'next'>) => { 6 | const buffer = [] 7 | 8 | subscribe(value => { 9 | if (buffer.length === 2) { 10 | buffer.shift() 11 | } 12 | buffer.push(value) 13 | if (buffer.length === 2) { 14 | next(buffer.slice()) 15 | } 16 | }) 17 | 18 | return () => { 19 | buffer.length = 0 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /registry/lib/components/video/player/common/mini-rxjs/operators/startWith.ts: -------------------------------------------------------------------------------- 1 | import { PublishContext } from '../subject' 2 | 3 | export const startWith = 4 | (...values: any[]) => 5 | ({ next, subscribe }: PublishContext) => { 6 | let seen = false 7 | subscribe(value => { 8 | if (!seen) { 9 | values.forEach(v => next(v)) 10 | } 11 | next(value) 12 | seen = true 13 | }) 14 | } 15 | -------------------------------------------------------------------------------- /registry/lib/components/video/player/common/mini-rxjs/operators/tap.ts: -------------------------------------------------------------------------------- 1 | import { Observer, PublishContext, toStandardizedObserver } from '../subject' 2 | 3 | export const tap = 4 | (observer: Observer) => 5 | ({ subscribe, next, error, complete }: PublishContext) => { 6 | const standardizedObserver = toStandardizedObserver(observer) 7 | 8 | subscribe( 9 | lodash.mapValues({ next, error, complete }, (v, k) => (value?: T | Error) => { 10 | standardizedObserver[k]?.(value) 11 | v.call(null, value) 12 | }), 13 | ) 14 | } 15 | -------------------------------------------------------------------------------- /registry/lib/components/video/player/common/mini-rxjs/operators/util/index.ts: -------------------------------------------------------------------------------- 1 | import { TeardownLogic } from '../../subject' 2 | 3 | export const withTeardownLogic = ( 4 | cb: ( 5 | addTeardownLogic: (teardownLogicList: TeardownLogic | TeardownLogic[] | any) => void, 6 | ) => void, 7 | ) => { 8 | const teardownLogicSet = new Set() 9 | 10 | cb(teardownLogicList => { 11 | lodash.castArray(teardownLogicList).forEach(teardownLogic => { 12 | teardownLogicSet.add(teardownLogic) 13 | }) 14 | }) 15 | 16 | return () => { 17 | teardownLogicSet.forEach(teardownLogic => { 18 | teardownLogic() 19 | }) 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /registry/lib/components/video/player/common/mini-rxjs/utils.ts: -------------------------------------------------------------------------------- 1 | import { Subject as SubjectReturnType } from './subject' 2 | 3 | export const firstValueFrom = (subject: SubjectReturnType) => 4 | new Promise((resolve, reject) => { 5 | const unsubscribe = subject.subscribe({ 6 | next: (value: T) => { 7 | resolve(value) 8 | unsubscribe() 9 | }, 10 | error: () => { 11 | reject() 12 | unsubscribe() 13 | }, 14 | complete: () => { 15 | reject() 16 | unsubscribe() 17 | }, 18 | }) 19 | }) 20 | -------------------------------------------------------------------------------- /registry/lib/components/video/player/common/mini-rxjs/utils/firstValueFrom.ts: -------------------------------------------------------------------------------- 1 | import { Subject } from '../subject' 2 | 3 | export const firstValueFrom = (subject: Subject) => 4 | new Promise((resolve, reject) => { 5 | const unsubscribe = subject.subscribe({ 6 | next: (value: T) => { 7 | resolve(value) 8 | unsubscribe() 9 | }, 10 | error: () => { 11 | reject() 12 | unsubscribe() 13 | }, 14 | complete: () => { 15 | reject() 16 | unsubscribe() 17 | }, 18 | }) 19 | }) 20 | -------------------------------------------------------------------------------- /registry/lib/components/video/player/common/mini-rxjs/utils/loadStyle.ts: -------------------------------------------------------------------------------- 1 | import { addStyle } from '@/core/style' 2 | 3 | export interface LoadStyleOptions { 4 | style: string | ((dep: D) => any) 5 | name?: string 6 | container?: HTMLElement 7 | } 8 | 9 | export const loadStyle = ({ style, name, container }: LoadStyleOptions) => { 10 | let styleElement 11 | const complete = () => styleElement?.remove() 12 | const next = (dep: D) => { 13 | complete() 14 | const styleText = typeof style === 'function' ? style(dep) : style 15 | if (!styleText) { 16 | return 17 | } 18 | styleElement = addStyle(styleText, name, container) 19 | } 20 | return { 21 | next, 22 | complete, 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /registry/lib/components/video/player/disable-double-click-fullscreen/index.md: -------------------------------------------------------------------------------- 1 | 禁用播放器的双击全屏功能. 2 | -------------------------------------------------------------------------------- /registry/lib/components/video/player/disable-double-click-fullscreen/index.ts: -------------------------------------------------------------------------------- 1 | import { defineComponentMetadata } from '@/components/define' 2 | import { select } from '@/core/spin-query' 3 | import { preventEvent } from '@/core/utils' 4 | import { playerUrls } from '@/core/utils/urls' 5 | 6 | let dispose: (() => void) | undefined 7 | const entry = async () => { 8 | const layer = (await select('.bpx-player-video-perch')) as HTMLElement 9 | if (!layer) { 10 | return 11 | } 12 | dispose = preventEvent(layer, 'dblclick') 13 | } 14 | export const component = defineComponentMetadata({ 15 | name: 'disableDoubleClickFullscreen', 16 | displayName: '禁用双击全屏', 17 | entry, 18 | reload: entry, 19 | unload: () => { 20 | dispose?.() 21 | }, 22 | tags: [componentsTags.video], 23 | urlInclude: playerUrls, 24 | }) 25 | -------------------------------------------------------------------------------- /registry/lib/components/video/player/disable-scroll-volume/index.md: -------------------------------------------------------------------------------- 1 | 在网页全屏 / 全屏模式下, 禁止鼠标滚轮控制播放器的音量. 请注意不能和 `反转滚轮调音量` 一同使用. 2 | -------------------------------------------------------------------------------- /registry/lib/components/video/player/focus/desc.md: -------------------------------------------------------------------------------- 1 | 进入视频 / 番剧页面时, 自动定位到播放器. 注意: 不能和其他影响定位的功能一同使用, 例如自动宽屏. (相关讨论: [#483](https://github.com/the1812/Bilibili-Evolved/issues/483)) 2 | 3 | 可设置定位时的竖直偏移量, 单位为像素(px). -------------------------------------------------------------------------------- /registry/lib/components/video/player/invert-scroll-volume/index.md: -------------------------------------------------------------------------------- 1 | 反转在网页全屏 / 全屏模式下使用滚轮调节音量的方向, 使其更符合使用触控板时的操作方向. 请注意不能和 `禁止滚轮调音量` 一同使用. 2 | 3 | - 手指向上推时, 增加音量 4 | - 手指向下推时, 减少音量 5 | - 可以自定义 `灵敏度`, 同样的滚动幅度下, 灵敏度越高变化的音量越多 -------------------------------------------------------------------------------- /registry/lib/components/video/player/preserve-danmaku-input/danmaku-input.scss: -------------------------------------------------------------------------------- 1 | @import 'common'; 2 | 3 | @media screen and (max-width: 1200px) { 4 | .bpx-player-video-inputbar, 5 | .bilibili-player-video-inputbar { 6 | @include on-fullscreen { 7 | display: flex !important; 8 | } 9 | } 10 | } 11 | -------------------------------------------------------------------------------- /registry/lib/components/video/player/preserve-danmaku-input/index.ts: -------------------------------------------------------------------------------- 1 | import { defineComponentMetadata } from '@/components/define' 2 | import { playerUrls } from '@/core/utils/urls' 3 | 4 | const name = 'preserveDanmakuInput' 5 | export const component = defineComponentMetadata({ 6 | name, 7 | displayName: '强制保留弹幕发送栏', 8 | entry: none, 9 | instantStyles: [ 10 | { 11 | name, 12 | style: () => import('./danmaku-input.scss'), 13 | }, 14 | ], 15 | tags: [componentsTags.style, componentsTags.video], 16 | description: { 17 | 'zh-CN': 18 | '在视频播放器网页全屏时, 即使宽度过小也强制保留弹幕发送栏, 注意这可能导致右侧的功能按钮挤出边界.', 19 | }, 20 | urlInclude: playerUrls, 21 | }) 22 | -------------------------------------------------------------------------------- /registry/lib/components/video/player/remove-popup/index.md: -------------------------------------------------------------------------------- 1 | 删除视频播放器中出现的各种弹窗, 类别可在选项中分别选择. 如果之前点了收起弹窗, 则收起后的小弹窗则会直接删除. (不受类别选择影响) 2 | -------------------------------------------------------------------------------- /registry/lib/components/video/player/screenshot/desc.md: -------------------------------------------------------------------------------- 1 | 启用视频快速截图, 将在播放器的时间右边增加一个截图按钮. 装有 `快捷键扩展` 时支持键盘快捷键Ctrl+Alt+C. -------------------------------------------------------------------------------- /registry/lib/components/video/player/seek-by-frames/desc.md: -------------------------------------------------------------------------------- 1 | 在播放器的时间右边增加两个按钮, 用于**较精细**调整视频时间. 装有 `快捷键扩展` 时支持键盘快捷键Shift+/. 2 | 3 | > 注: `视频的实际播放帧率`跟`视频本身的帧率`和`显示器的刷新率`有关, 很难计算一个精准的数值, 部分视频仍然会有暂停不到那种一闪而过的图的情况. -------------------------------------------------------------------------------- /registry/lib/components/video/player/seek-by-frames/seek-left.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 5 | 6 | 8 | 9 | 10 | 11 | -------------------------------------------------------------------------------- /registry/lib/components/video/player/seek-by-frames/seek-right.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 5 | 6 | 8 | 9 | 10 | 11 | -------------------------------------------------------------------------------- /registry/lib/components/video/player/show-cover/cover.scss: -------------------------------------------------------------------------------- 1 | .bpx-player-video-wrap::after, 2 | .bilibili-player-video::after { 3 | position: absolute; 4 | content: ""; 5 | top: 0; 6 | left: 0; 7 | width: 100%; 8 | height: 100%; 9 | display: none; 10 | background: black var(--cover-url) center no-repeat; 11 | background-size: contain; 12 | pointer-events: none; 13 | z-index: 10; 14 | } 15 | .bpx-player-container.bpx-state-paused { 16 | .bpx-player-video-wrap::after { 17 | display: block; 18 | } 19 | } 20 | .bilibili-player-area.video-state-pause { 21 | .bilibili-player-video::after { 22 | display: block; 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /registry/lib/components/video/player/show-upload-time/desc.md: -------------------------------------------------------------------------------- 1 | 为视频播放页面的推荐列表中的视频添加显示视频投稿时间. 2 | 3 | `时间格式` 替换up名的文本格式 (默认为'up · yyyy-MM-dd'): 4 | - y: 年 5 | - M: 月 6 | - d: 日 7 | - h: 时 8 | - m: 分 9 | - s: 秒 10 | - q: 季度 11 | - up: up名 12 | - \r: 回车符 13 | - \n:换行符 14 | - \t:制表符 -------------------------------------------------------------------------------- /registry/lib/components/video/player/show-upload-time/show-upload-time.scss: -------------------------------------------------------------------------------- 1 | // 旧版css 2 | .video-page-card .card-box .info .count.up { 3 | white-space: pre !important; 4 | display: flex !important; 5 | height: auto !important; 6 | } 7 | // 2023.04.30 版本css 8 | .video-page-card-small .card-box .info .upname { 9 | height: auto !important; 10 | a .name { 11 | -webkit-line-clamp: unset !important; 12 | white-space: pre !important; 13 | } 14 | } 15 | // 2024.10.17 版本css 16 | .video-page-operator-card-small .card-box .info .upname { 17 | height: auto !important; 18 | a .name { 19 | -webkit-line-clamp: unset !important; 20 | white-space: pre !important; 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /registry/lib/components/video/player/skip-charge-list/charge-list.scss: -------------------------------------------------------------------------------- 1 | body:not(.skip-charge-list-disable) .bilibili-player .bilibili-player-electric-panel, 2 | body:not(.skip-charge-list-disable) #bilibili-player .bpx-player-electric-panel { 3 | display: none !important; 4 | } -------------------------------------------------------------------------------- /registry/lib/components/video/quick-favorite/options.ts: -------------------------------------------------------------------------------- 1 | import { defineOptionsMetadata, OptionsOfMetadata } from '@/components/define' 2 | 3 | export enum DisplayMode { 4 | Auto = '自动', 5 | Icon = '图标', 6 | IconAndText = '图标 + 文字', 7 | } 8 | export const options = defineOptionsMetadata({ 9 | favoriteFolderID: { 10 | defaultValue: 0, 11 | displayName: '快速收藏夹ID', 12 | hidden: true, 13 | }, 14 | showInFavoritePages: { 15 | defaultValue: false, 16 | displayName: '在收藏夹播放页面仍然显示', 17 | }, 18 | displayMode: { 19 | defaultValue: DisplayMode.Auto, 20 | displayName: '显示方式', 21 | dropdownEnum: DisplayMode, 22 | }, 23 | }) 24 | 25 | export type Options = OptionsOfMetadata 26 | -------------------------------------------------------------------------------- /registry/lib/components/video/seo-redirect/index.ts: -------------------------------------------------------------------------------- 1 | import { defineComponentMetadata } from '@/components/define' 2 | 3 | export const component = defineComponentMetadata({ 4 | name: 'seoRedirect', 5 | displayName: 'SEO 页面重定向', 6 | entry: () => { 7 | window.location.assign(document.URL.replace('/s/', '/')) 8 | }, 9 | urlInclude: ['//www.bilibili.com/s/video/'], 10 | tags: [componentsTags.video], 11 | description: { 12 | 'zh-CN': '进入 SEO 视频页面时 (`https://www.bilibili.com/s/video/`) 自动跳转到原视频页面.', 13 | }, 14 | }) 15 | -------------------------------------------------------------------------------- /registry/lib/components/video/subtitle/download/cc-subtitle.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /registry/lib/components/video/subtitle/download/index.md: -------------------------------------------------------------------------------- 1 | 启用下载字幕支持, 在视频页面中可从功能面板里下载字幕. (AI 生成的不可下载) 2 | -------------------------------------------------------------------------------- /registry/lib/deprecated/README.md: -------------------------------------------------------------------------------- 1 | 包含一些曾经存在的功能, 因 b 站更新现已废弃. 2 | -------------------------------------------------------------------------------- /registry/lib/deprecated/download-records/index.ts: -------------------------------------------------------------------------------- 1 | import { defineComponentMetadata } from '@/components/define' 2 | 3 | export const component = defineComponentMetadata({ 4 | name: 'downloadLiveRecords', 5 | displayName: '直播录像下载', 6 | description: { 7 | 'zh-CN': '在直播录像页面 `live.bilibili.com/record/` 中添加下载支持.', 8 | }, 9 | tags: [componentsTags.live], 10 | entry: none, 11 | widget: { 12 | component: () => import('./DownloadRecords.vue').then(m => m.default), 13 | }, 14 | urlInclude: [/^https:\/\/live\.bilibili\.com\/record\/(.+)/], 15 | }) 16 | -------------------------------------------------------------------------------- /registry/lib/deprecated/i18n/en-US/index.ts: -------------------------------------------------------------------------------- 1 | import { PluginMetadata } from '@/plugins/plugin' 2 | 3 | export const plugin: PluginMetadata = { 4 | name: 'i18n.language.english', 5 | displayName: '英语语言包', 6 | setup: async ({ registerData, addData }) => { 7 | addData('i18n', (languages: Record) => { 8 | languages['en-US'] = 'English' 9 | }) 10 | const { map, regex } = await import('./data') 11 | registerData('i18n.en-US', map, regex) 12 | }, 13 | } 14 | -------------------------------------------------------------------------------- /registry/lib/deprecated/i18n/ja-JP/index.ts: -------------------------------------------------------------------------------- 1 | import { PluginMetadata } from '@/plugins/plugin' 2 | 3 | export const plugin: PluginMetadata = { 4 | name: 'i18n.language.japanese', 5 | displayName: '日语语言包', 6 | setup: async ({ registerData, addData }) => { 7 | addData('i18n', (languages: Record) => { 8 | languages['ja-JP'] = '日本語' 9 | }) 10 | const { map, regex } = await import('./data') 11 | registerData('i18n.ja-JP', map, regex) 12 | }, 13 | } 14 | -------------------------------------------------------------------------------- /registry/lib/deprecated/pip/LivePip.vue: -------------------------------------------------------------------------------- 1 | 9 | 10 | 28 | 29 | 34 | -------------------------------------------------------------------------------- /registry/lib/deprecated/pip/index.ts: -------------------------------------------------------------------------------- 1 | import { defineComponentMetadata } from '@/components/define' 2 | import { liveUrls } from '@/core/utils/urls' 3 | 4 | export const component = defineComponentMetadata({ 5 | name: 'livePip', 6 | displayName: '直播画中画', 7 | description: { 8 | 'zh-CN': 9 | '在直播间的功能面板中启用画中画支持, 不过现在好像 b 站已经直接支持了, 后续可能会删掉这个功能.', 10 | }, 11 | entry: none, 12 | tags: [componentsTags.live], 13 | widget: { 14 | component: () => import('./LivePip.vue').then(m => m.default), 15 | condition: () => 'requestPictureInPicture' in HTMLVideoElement.prototype, 16 | }, 17 | urlInclude: liveUrls, 18 | }) 19 | -------------------------------------------------------------------------------- /registry/lib/deprecated/record-danmaku/index.ts: -------------------------------------------------------------------------------- 1 | import { defineComponentMetadata } from '@/components/define' 2 | import { none } from '@/core/utils' 3 | import { liveUrls } from '@/core/utils/urls' 4 | 5 | export const component = defineComponentMetadata({ 6 | name: 'recordLiveDanmaku', 7 | displayName: '直播弹幕记录器', 8 | description: { 9 | 'zh-CN': '在功能中添加直播弹幕记录器, 可以记录直播弹幕并导出XML.', 10 | }, 11 | entry: none, 12 | tags: [componentsTags.live], 13 | widget: { 14 | component: () => import('./RecordDanmaku.vue').then(m => m.default), 15 | }, 16 | urlInclude: liveUrls, 17 | }) 18 | -------------------------------------------------------------------------------- /registry/lib/deprecated/turn-off-danmaku/index.ts: -------------------------------------------------------------------------------- 1 | import { defineComponentMetadata } from '@/components/define' 2 | import { playerUrls } from '@/core/utils/urls' 3 | 4 | const entry = async () => { 5 | const { select } = await import('@/core/spin-query') 6 | const { raiseEvent } = await import('@/core/utils') 7 | const input = (await select('.bilibili-player-video-danmaku-switch>input')) as HTMLInputElement 8 | if (input === null) { 9 | return 10 | } 11 | input.checked = false 12 | raiseEvent(input, 'change') 13 | } 14 | export const component = defineComponentMetadata({ 15 | name: 'turnOffDanmaku', 16 | displayName: '默认关闭弹幕', 17 | tags: [componentsTags.video], 18 | entry, 19 | urlInclude: playerUrls, 20 | }) 21 | -------------------------------------------------------------------------------- /registry/lib/docs/packages/cleaner.ts: -------------------------------------------------------------------------------- 1 | import { Package } from '..' 2 | 3 | export const pack: Package = { 4 | name: 'cleaner', 5 | displayName: '简洁至上', 6 | description: '简化各种多余界面元素, 专注于内容本身.', 7 | components: [ 8 | 'removePromotions', 9 | 'removeLiveWatermark', 10 | 'removePlayerPopup', 11 | 'disableSpecialDanmaku', 12 | 'simplifyComments', 13 | 'simplifyLiveroom', 14 | 'collapseLiveSideBar', 15 | 'hideRelatedVideos', 16 | 'hideRecommendedLive', 17 | 'hideVideoTopMask', 18 | ], 19 | } 20 | -------------------------------------------------------------------------------- /registry/lib/docs/packages/downloader.ts: -------------------------------------------------------------------------------- 1 | import { Package } from '..' 2 | 3 | export const pack: Package = { 4 | name: 'downloader', 5 | displayName: '下载器', 6 | description: '支持下载各种内容.', 7 | components: ['downloadVideo', 'downloadSubtitle', 'downloadDanmaku', 'downloadAudio'], 8 | } 9 | -------------------------------------------------------------------------------- /registry/lib/docs/packages/starter.ts: -------------------------------------------------------------------------------- 1 | import { Package } from '..' 2 | 3 | export const pack: Package = { 4 | name: 'starter', 5 | displayName: '常用功能包', 6 | description: '提供一些常用功能.', 7 | components: [ 8 | 'elegantScrollbar', 9 | 'customNavbar', 10 | 'removePromotions', 11 | 'columnUnlock', 12 | 'urlParamsClean', 13 | 'keymap', 14 | 'viewCover', 15 | 'bvidConvert', 16 | 'removeLiveWatermark', 17 | 'liveDanmakuSendbar', 18 | 'liveGiftBox', 19 | 'fullFeedsContent', 20 | 'unfoldFeeds', 21 | 'foldComments', 22 | 'disableFeedsDetails', 23 | 'fullVideoDescription', 24 | ], 25 | plugins: ['settingsPanel.tagFilters.recentComponents'], 26 | } 27 | -------------------------------------------------------------------------------- /registry/lib/id.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * Runs both in Node.js and browser (without path module). 3 | * Paths are case-sensitive. 4 | */ 5 | 6 | /** 7 | * Generate id from relative path and remove filename 8 | * @example getId('folder1/', 'folder1/folder2/index.ts') -> 'folder2' 9 | */ 10 | export const getId = (root: string, entry: string) => { 11 | const relative = entry.replace(root, '').replace(/\\/g, '/') 12 | return relative.replace(/\/[^\/]+$/, '') 13 | } 14 | 15 | /** 16 | * Reverse method for `getId` 17 | * @example getId('folder1/', 'folder2') -> 'folder1/folder2/index.ts' 18 | */ 19 | export const fromId = (root: string, id: string, filename = 'index.ts') => 20 | `${root.replace(/\\/g, '/')}${id.replace(/\\/g, '/')}/${filename}` 21 | -------------------------------------------------------------------------------- /registry/lib/plugins/feeds/filter/hide-charge-feeds/index.md: -------------------------------------------------------------------------------- 1 | 移除动态里的充电专属动态, 装有 `动态过滤器` 时生效. 2 | -------------------------------------------------------------------------------- /registry/lib/plugins/feeds/filter/hide-goods/index.md: -------------------------------------------------------------------------------- 1 | 移除动态里的商品带货动态 (UP主的推荐 · 来自 XX), 装有 `动态过滤器` 时生效. 2 | -------------------------------------------------------------------------------- /registry/lib/plugins/feeds/filter/hide-goods/index.ts: -------------------------------------------------------------------------------- 1 | import type { PluginMetadata } from '@/plugins/plugin' 2 | 3 | export const plugin: PluginMetadata = { 4 | name: 'feedsFilter.pluginBlocks.goods', 5 | displayName: '动态过滤器 - 移除商品带货动态', 6 | async setup() { 7 | const { forEachFeedsCard, getVueData } = await import('@/components/feeds/api') 8 | forEachFeedsCard({ 9 | added: card => { 10 | const vueData = getVueData(card.element) 11 | const additionalType: string | null = lodash.get( 12 | vueData, 13 | 'data.modules.module_dynamic.additional.type', 14 | null, 15 | ) 16 | const isGoods = additionalType === 'ADDITIONAL_TYPE_GOODS' 17 | if (!isGoods) { 18 | return 19 | } 20 | card.element.classList.add('plugin-block') 21 | }, 22 | }) 23 | }, 24 | } 25 | -------------------------------------------------------------------------------- /registry/lib/plugins/launch-bar/audio-search/index.md: -------------------------------------------------------------------------------- 1 | 在输入音频的 au 号或播放列表的 am 号时, 提供对应的跳转选项. 2 | -------------------------------------------------------------------------------- /registry/lib/plugins/launch-bar/bangumi-search/index.md: -------------------------------------------------------------------------------- 1 | 在输入番剧的 ss 号 / ep 号, 或番剧详情的 md 号时, 提供对应的跳转选项. 2 | -------------------------------------------------------------------------------- /registry/lib/plugins/launch-bar/cv-search/index.md: -------------------------------------------------------------------------------- 1 | 在输入专栏的 cv 号或专栏文集的 rl 号时, 提供对应的跳转选项. 2 | -------------------------------------------------------------------------------- /registry/lib/plugins/launch-bar/number-search/index.md: -------------------------------------------------------------------------------- 1 | 在输入纯数字时, 提供以下选项: 2 | - 跳转至相应的视频 (视为 av 号) 3 | - 跳转至相应的专栏 (视为 cv 号) 4 | -------------------------------------------------------------------------------- /registry/lib/plugins/launch-bar/uid-search/index.md: -------------------------------------------------------------------------------- 1 | 在输入 UID (用户 ID) 时, 提供对应的跳转选项. 2 | -------------------------------------------------------------------------------- /registry/lib/plugins/style/custom-navbar-channel/NavbarChannel.vue: -------------------------------------------------------------------------------- 1 | 4 | 5 | 25 | -------------------------------------------------------------------------------- /registry/lib/plugins/utils/keymap-dark-mode/index.ts: -------------------------------------------------------------------------------- 1 | import { KeyBindingAction } from 'registry/lib/components/utils/keymap/bindings' 2 | import { PluginMetadata } from '@/plugins/plugin' 3 | 4 | export const plugin: PluginMetadata = { 5 | name: 'keymap.actions.darkMode', 6 | displayName: '快捷键扩展 - 夜间模式', 7 | description: '在快捷键的动作列表里添加一个 "夜间模式", 可以通过快捷键切换夜间模式', 8 | setup: ({ addData, coreApis: { settings } }) => { 9 | addData('keymap.actions', (actions: Record) => { 10 | actions.darkMode = { 11 | displayName: '夜间模式', 12 | run: () => { 13 | const darkMode = settings.getComponentSettings('darkMode') 14 | darkMode.enabled = !darkMode.enabled 15 | }, 16 | } 17 | }) 18 | addData('keymap.presets', (presetBase: Record) => { 19 | presetBase.darkMode = '' 20 | }) 21 | }, 22 | } 23 | -------------------------------------------------------------------------------- /registry/lib/plugins/utils/keymap-empty-action.ts/index.ts: -------------------------------------------------------------------------------- 1 | import { KeyBindingAction } from 'registry/lib/components/utils/keymap/bindings' 2 | import { PluginMetadata } from '@/plugins/plugin' 3 | 4 | export const plugin: PluginMetadata = { 5 | name: 'keymap.actions.empty', 6 | displayName: '快捷键扩展 - 无动作', 7 | description: 8 | '在快捷键的动作列表里添加一个 "无动作", 将按键绑定到这个上面就可以阻止原有的快捷键行为.', 9 | setup: ({ addData }) => { 10 | addData('keymap.actions', (actions: Record) => { 11 | actions.empty = { 12 | displayName: '无动作', 13 | prevent: true, 14 | run: none, 15 | } 16 | }) 17 | addData('keymap.presets', (presetBase: Record) => { 18 | presetBase.empty = '' 19 | }) 20 | }, 21 | } 22 | -------------------------------------------------------------------------------- /registry/lib/plugins/utils/keymap-toggle-player-light/index.ts: -------------------------------------------------------------------------------- 1 | import { KeyBindingAction } from 'registry/lib/components/utils/keymap/bindings' 2 | import { PluginMetadata } from '@/plugins/plugin' 3 | import { toggleLight } from '@/components/video/player-light' 4 | 5 | export const plugin: PluginMetadata = { 6 | name: 'keymap.actions.togglePlayerLight', 7 | displayName: '快捷键扩展 - 开关灯', 8 | description: '在快捷键的动作列表里添加一个 "开关灯".', 9 | setup: ({ addData }) => { 10 | addData('keymap.actions', (actions: Record) => { 11 | actions.togglePlayerLight = { 12 | displayName: '开关灯', 13 | run: async () => { 14 | toggleLight() 15 | }, 16 | } 17 | }) 18 | addData('keymap.presets', (presetBase: Record) => { 19 | presetBase.togglePlayerLight = 'shift l' 20 | }) 21 | }, 22 | } 23 | -------------------------------------------------------------------------------- /registry/lib/plugins/v-loading/reimu/ReimuLoading.vue: -------------------------------------------------------------------------------- 1 | 7 | 15 | -------------------------------------------------------------------------------- /registry/lib/plugins/v-loading/reimu/index.ts: -------------------------------------------------------------------------------- 1 | import { Executable, VueModule } from '@/core/common-types' 2 | import { PluginMetadata } from '@/plugins/plugin' 3 | 4 | export const plugin: PluginMetadata = { 5 | name: 'vLoading.reimu', 6 | displayName: '加载提示 - 灵梦油库里', 7 | description: 8 | '用灵梦油库里代替脚本的所有 "加载中" 提示, 油库里素材来自[东方我乐多从志](https://cn.touhougarakuta.com/).', 9 | setup: ({ addData }) => { 10 | addData('vLoading', (config: { content: Executable | string }) => { 11 | config.content = () => import('./ReimuLoading.vue').then(m => m.default) 12 | }) 13 | }, 14 | } 15 | -------------------------------------------------------------------------------- /registry/lib/plugins/video/download/aria2-output/index.ts: -------------------------------------------------------------------------------- 1 | import { PluginMetadata } from '@/plugins/plugin' 2 | import { DownloadVideoOutput } from '../../../../components/video/download/types' 3 | import { aria2Input } from './aria2-input' 4 | import { aria2Rpc } from './aria2-rpc' 5 | 6 | export const plugin: PluginMetadata = { 7 | name: 'downloadVideo.outputs.aria2', 8 | displayName: '下载视频 - aria2 输出支持', 9 | description: '为下载视频增加 aria2 文件导出和 RPC 输出支持.', 10 | setup: ({ addData }) => { 11 | addData('downloadVideo.outputs', (outputs: DownloadVideoOutput[]) => { 12 | outputs.push(aria2Input) 13 | outputs.push(aria2Rpc) 14 | }) 15 | }, 16 | } 17 | -------------------------------------------------------------------------------- /registry/lib/plugins/video/download/aria2-output/rpc-profiles.ts: -------------------------------------------------------------------------------- 1 | export interface Aria2RpcProfile { 2 | name: string 3 | secretKey: string 4 | dir: string 5 | host: string 6 | port: string 7 | method: string 8 | other: string 9 | } 10 | export const defaultProfile: Aria2RpcProfile = { 11 | name: '未命名', 12 | secretKey: '', 13 | dir: '', 14 | host: '127.0.0.1', 15 | port: '6800', 16 | method: 'get', 17 | other: '', 18 | } 19 | -------------------------------------------------------------------------------- /registry/lib/plugins/video/download/empty-output/index.md: -------------------------------------------------------------------------------- 1 | 提供一个 "空" 的输出选项, 只想获取下载视频的附带产物 (弹幕, 字幕等) 时可以使用此插件. 2 | -------------------------------------------------------------------------------- /registry/lib/plugins/video/download/empty-output/index.ts: -------------------------------------------------------------------------------- 1 | import { PluginMetadata } from '@/plugins/plugin' 2 | import { DownloadVideoOutput } from '../../../../components/video/download/types' 3 | 4 | export const plugin: PluginMetadata = { 5 | name: 'downloadVideo.outputs.empty', 6 | displayName: '下载视频 - 空输出', 7 | setup: ({ addData }) => { 8 | addData('downloadVideo.outputs', (outputs: DownloadVideoOutput[]) => { 9 | outputs.push({ 10 | name: 'empty', 11 | displayName: '空', 12 | description: '不输出视频本身, 仅获取下载视频的附带产物.', 13 | runAction: async () => lodash.noop(), 14 | }) 15 | }) 16 | }, 17 | } 18 | -------------------------------------------------------------------------------- /registry/lib/plugins/video/download/mpv-output-ex/index.ts: -------------------------------------------------------------------------------- 1 | import { PluginMetadata } from '@/plugins/plugin' 2 | import { DownloadVideoOutput } from '../../../../components/video/download/types' 3 | import { MPV_Ex } from './handler' 4 | 5 | export const plugin: PluginMetadata = { 6 | name: 'downloadVideo.outputs.mpv-ex', 7 | displayName: '下载视频 - MPV 输出支持加强版', 8 | author: { 9 | name: 'asuaaa', 10 | link: 'https://github.com/Asukaaaaaa', 11 | }, 12 | description: 13 | '为下载视频增加 MPV 输出,支持导出列表, 配置方式请参考 [README](https://github.com/Asukaaaaaa/tricks/blob/main/Bilibili-Evolved%20mpv-ex%20%E6%8F%92%E4%BB%B6.md)', 14 | setup: ({ addData }) => { 15 | addData('downloadVideo.outputs', (outputs: DownloadVideoOutput[]) => { 16 | outputs.push(MPV_Ex) 17 | }) 18 | }, 19 | } 20 | -------------------------------------------------------------------------------- /registry/lib/plugins/video/download/mpv-output-ex/type.d.ts: -------------------------------------------------------------------------------- 1 | type ConfigDataType = { 2 | api_dev_key: string 3 | api_user_key: string 4 | } 5 | -------------------------------------------------------------------------------- /registry/lib/plugins/video/download/mpv-output-playlist/index.ts: -------------------------------------------------------------------------------- 1 | import { PluginMetadata } from '@/plugins/plugin' 2 | import { DownloadVideoOutput } from '../../../../components/video/download/types' 3 | import { mpvPlaylist } from './mpv-playlist' 4 | 5 | export const plugin: PluginMetadata = { 6 | name: 'downloadVideo.outputs.mpv-playlist', 7 | displayName: '下载视频 - MPV 播放支持(列表)', 8 | author: { 9 | name: 'wuliic', 10 | link: 'https://github.com/wullic', 11 | }, 12 | description: 13 | '为下载视频增加 MPV 输出支持,支持列表播放,配置方式请参考 [playwithmpv](https://github.com/videoanywhere/playwithmpv)', 14 | setup: ({ addData }) => { 15 | addData('downloadVideo.outputs', (outputs: DownloadVideoOutput[]) => { 16 | outputs.push(mpvPlaylist) 17 | }) 18 | }, 19 | } 20 | -------------------------------------------------------------------------------- /registry/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "@bevo/components", 3 | "version": "0.0.1", 4 | "description": "Components registry for Bilibili Evolved", 5 | "author": "Grant Howard", 6 | "license": "MIT", 7 | "devDependencies": { 8 | "@types/sortablejs": "^1.10.7", 9 | "enquirer": "^2.3.6", 10 | "glob": "^7.1.7" 11 | }, 12 | "packageManager": "pnpm@10.3.0+sha512.ee592eda8815a8a293c206bb0917c4bb0ff274c50def7cbc17be05ec641fc2d1b02490ce660061356bd0d126a4d7eb2ec8830e6959fb8a447571c631d5a2442d" 13 | } 14 | -------------------------------------------------------------------------------- /registry/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "../tsconfig.json", 3 | "compilerOptions": { 4 | "paths": { 5 | "@/*": [ 6 | "src/*" 7 | ] 8 | } 9 | }, 10 | "include": [ 11 | "../src/**/*.d.ts", 12 | "lib/**/*.ts" 13 | ], 14 | } -------------------------------------------------------------------------------- /registry/webpack/all.ts: -------------------------------------------------------------------------------- 1 | import { builders } from './build' 2 | 3 | export default async () => [ 4 | ...(await builders.component({ buildAll: true })), 5 | ...(await builders.plugin({ buildAll: true })), 6 | ] 7 | -------------------------------------------------------------------------------- /registry/webpack/components.ts: -------------------------------------------------------------------------------- 1 | import { builders } from './build' 2 | 3 | export default builders.component() 4 | -------------------------------------------------------------------------------- /registry/webpack/docs.ts: -------------------------------------------------------------------------------- 1 | import path from 'path' 2 | import { builders } from './build' 3 | 4 | export default builders.doc().then(configs => 5 | configs.map(config => { 6 | config.output.path = path.resolve('./registry/dist/') 7 | config.output.filename = 'doc.js' 8 | return config 9 | }), 10 | ) 11 | -------------------------------------------------------------------------------- /registry/webpack/plugins.ts: -------------------------------------------------------------------------------- 1 | import { builders } from './build' 2 | 3 | export default builders.plugin() 4 | -------------------------------------------------------------------------------- /src/client/bilibili-evolved.meta.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "Bilibili Evolved", 3 | "description": "强大的哔哩哔哩增强脚本", 4 | "updateURL": "[altCdn.stableClient]", 5 | "downloadURL": "[altCdn.stableClient]" 6 | } -------------------------------------------------------------------------------- /src/client/bilibili-evolved.preview.meta.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "Bilibili Evolved (Preview)", 3 | "description": "Bilibili Evolved 的预览版, 可以抢先体验新功能.", 4 | "updateURL": "[altCdn.previewClient]", 5 | "downloadURL": "[altCdn.previewClient]" 6 | } -------------------------------------------------------------------------------- /src/client/bilibili-evolved.ts: -------------------------------------------------------------------------------- 1 | import { init } from './init' 2 | 3 | init() 4 | -------------------------------------------------------------------------------- /src/client/check-iframes.ts: -------------------------------------------------------------------------------- 1 | const redundantFrames = [ 2 | 'https://message.bilibili.com/pages/nav/index_new_sync', 3 | 'https://message.bilibili.com/pages/nav/index_new_pc_sync', 4 | 'https://t.bilibili.com/h5/dynamic/specification', 5 | ] 6 | export const checkIframes = () => { 7 | if (redundantFrames.includes(document.URL)) { 8 | console.log(`Skipped