mirror of
https://github.com/the1812/Bilibili-Evolved.git
synced 2025-11-04 21:22:45 +08:00
Merge tag 'v2.8.9-preview' into preview-fixes
This commit is contained in:
commit
092cdbf866
@ -0,0 +1 @@
|
|||||||
|
将动态中左右切换式的图片改回传统的平铺展示. (在动态详情中可能稍有延迟)
|
||||||
45
registry/lib/components/feeds/legacy-image-viewer/index.ts
Normal file
45
registry/lib/components/feeds/legacy-image-viewer/index.ts
Normal file
@ -0,0 +1,45 @@
|
|||||||
|
import { defineComponentMetadata } from '@/components/define'
|
||||||
|
import { forEachFeedsCard, getVueData } from '@/components/feeds/api'
|
||||||
|
import { feedsUrls } from '@/core/utils/urls'
|
||||||
|
|
||||||
|
export const component = defineComponentMetadata({
|
||||||
|
name: 'legacyFeedsImageViewer',
|
||||||
|
displayName: '动态图片平铺展示',
|
||||||
|
tags: [componentsTags.feeds],
|
||||||
|
urlInclude: feedsUrls,
|
||||||
|
entry: () => {
|
||||||
|
forEachFeedsCard({
|
||||||
|
added: card => {
|
||||||
|
const vueData = getVueData(card.element)
|
||||||
|
|
||||||
|
// 普通动态
|
||||||
|
const path = 'data.modules.module_dynamic.major.opus.style'
|
||||||
|
const imageViewerStyle: number | null = lodash.get(vueData, path, null)
|
||||||
|
if (imageViewerStyle === 1) {
|
||||||
|
lodash.set(vueData, path, undefined)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// 动态详情
|
||||||
|
const modules = vueData?.data?.modules
|
||||||
|
if (Array.isArray(modules)) {
|
||||||
|
const moduleTop = modules.find(m => m.module_type === 'MODULE_TYPE_TOP')
|
||||||
|
const moduleContent = modules.find(m => m.module_type === 'MODULE_TYPE_CONTENT')
|
||||||
|
const album = moduleTop?.module_top?.display?.album
|
||||||
|
const paragraphs: any[] = moduleContent?.module_content?.paragraphs
|
||||||
|
if (album && paragraphs) {
|
||||||
|
modules.splice(modules.indexOf(moduleTop), 1)
|
||||||
|
paragraphs.push({
|
||||||
|
align: 0,
|
||||||
|
para_type: 2,
|
||||||
|
pic: {
|
||||||
|
pics: album.pics,
|
||||||
|
style: 1,
|
||||||
|
},
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
})
|
||||||
|
},
|
||||||
|
})
|
||||||
@ -11,7 +11,7 @@
|
|||||||
<script lang="ts">
|
<script lang="ts">
|
||||||
import { TabControl, VIcon } from '@/ui'
|
import { TabControl, VIcon } from '@/ui'
|
||||||
import { FeedsCardType, feedsCardTypes } from '@/components/feeds/api'
|
import { FeedsCardType, feedsCardTypes } from '@/components/feeds/api'
|
||||||
import { getNotifyCount } from '@/components/feeds/notify'
|
import { getNotifyCountByType } from '@/components/feeds/notify'
|
||||||
import { popperMixin } from '../mixins'
|
import { popperMixin } from '../mixins'
|
||||||
import { tabs } from './tabs/tabs'
|
import { tabs } from './tabs/tabs'
|
||||||
|
|
||||||
@ -49,7 +49,7 @@ export default Vue.extend({
|
|||||||
if (!feedsCardType.apiType) {
|
if (!feedsCardType.apiType) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
const count = await getNotifyCount(feedsCardType.apiType)
|
const count = await getNotifyCountByType(feedsCardType.apiType)
|
||||||
tab.count = count
|
tab.count = count
|
||||||
console.log(tab)
|
console.log(tab)
|
||||||
})
|
})
|
||||||
|
|||||||
@ -2,7 +2,7 @@
|
|||||||
<span
|
<span
|
||||||
title="稍后再看"
|
title="稍后再看"
|
||||||
class="watchlater be-outer-watchlater video-toolbar-left-item"
|
class="watchlater be-outer-watchlater video-toolbar-left-item"
|
||||||
:class="{ on }"
|
:class="{ on, ...displayModeClass }"
|
||||||
@click="toggle()"
|
@click="toggle()"
|
||||||
>
|
>
|
||||||
<VIcon class="icon" :size="28" icon="mdi-timetable"></VIcon>
|
<VIcon class="icon" :size="28" icon="mdi-timetable"></VIcon>
|
||||||
@ -14,14 +14,18 @@
|
|||||||
<script lang="ts">
|
<script lang="ts">
|
||||||
import { VIcon } from '@/ui'
|
import { VIcon } from '@/ui'
|
||||||
import { watchlaterList, toggleWatchlater } from '@/components/video/watchlater'
|
import { watchlaterList, toggleWatchlater } from '@/components/video/watchlater'
|
||||||
|
import { DisplayMode, Options } from './options'
|
||||||
|
import { addComponentListener, getComponentSettings } from '@/core/settings'
|
||||||
|
|
||||||
export default Vue.extend({
|
export default Vue.extend({
|
||||||
components: {
|
components: {
|
||||||
VIcon,
|
VIcon,
|
||||||
},
|
},
|
||||||
data() {
|
data() {
|
||||||
|
const { displayMode } = getComponentSettings<Options>('outerWatchlater').options
|
||||||
return {
|
return {
|
||||||
watchlaterList,
|
watchlaterList,
|
||||||
|
displayMode,
|
||||||
aid: unsafeWindow.aid,
|
aid: unsafeWindow.aid,
|
||||||
tipText: '',
|
tipText: '',
|
||||||
tipShowing: false,
|
tipShowing: false,
|
||||||
@ -33,6 +37,17 @@ export default Vue.extend({
|
|||||||
console.log(this.watchlaterList, this.aid, this.watchlaterList.includes(parseInt(this.aid)))
|
console.log(this.watchlaterList, this.aid, this.watchlaterList.includes(parseInt(this.aid)))
|
||||||
return this.watchlaterList.includes(parseInt(this.aid))
|
return this.watchlaterList.includes(parseInt(this.aid))
|
||||||
},
|
},
|
||||||
|
displayModeClass() {
|
||||||
|
return {
|
||||||
|
'icon-only': this.displayMode === DisplayMode.Icon,
|
||||||
|
'icon-and-text': this.displayMode === DisplayMode.IconAndText,
|
||||||
|
}
|
||||||
|
},
|
||||||
|
},
|
||||||
|
created() {
|
||||||
|
addComponentListener('outerWatchlater.displayMode', (value: DisplayMode) => {
|
||||||
|
this.displayMode = value
|
||||||
|
})
|
||||||
},
|
},
|
||||||
methods: {
|
methods: {
|
||||||
showTip(text: string) {
|
showTip(text: string) {
|
||||||
@ -62,12 +77,22 @@ export default Vue.extend({
|
|||||||
margin-right: 28px !important;
|
margin-right: 28px !important;
|
||||||
position: relative;
|
position: relative;
|
||||||
width: auto !important;
|
width: auto !important;
|
||||||
@media screen and (max-width: 1340px), (max-height: 750px) {
|
|
||||||
|
@mixin icon-only {
|
||||||
margin-right: max(calc(min(11vw, 11vh) - 117.2px), 6px) !important;
|
margin-right: max(calc(min(11vw, 11vh) - 117.2px), 6px) !important;
|
||||||
.text {
|
.text {
|
||||||
display: none;
|
display: none;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
&.icon-only {
|
||||||
|
@include icon-only();
|
||||||
|
}
|
||||||
|
&:not(.icon-and-text) {
|
||||||
|
@media screen and (max-width: 1340px), (max-height: 750px) {
|
||||||
|
@include icon-only();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
.tip {
|
.tip {
|
||||||
position: absolute;
|
position: absolute;
|
||||||
top: calc(100% + 8px);
|
top: calc(100% + 8px);
|
||||||
|
|||||||
@ -1,22 +1,10 @@
|
|||||||
import {
|
import { defineComponentMetadata } from '@/components/define'
|
||||||
defineComponentMetadata,
|
|
||||||
defineOptionsMetadata,
|
|
||||||
OptionsOfMetadata,
|
|
||||||
} from '@/components/define'
|
|
||||||
import { ComponentEntry } from '@/components/types'
|
import { ComponentEntry } from '@/components/types'
|
||||||
import { getUID, matchUrlPattern, mountVueComponent } from '@/core/utils'
|
import { getUID, matchUrlPattern, mountVueComponent } from '@/core/utils'
|
||||||
import { videoUrls, watchlaterUrls } from '@/core/utils/urls'
|
import { videoUrls, watchlaterUrls } from '@/core/utils/urls'
|
||||||
import { KeyBindingAction } from '../../utils/keymap/bindings'
|
import { KeyBindingAction } from '../../utils/keymap/bindings'
|
||||||
import { addVideoActionButton } from '@/components/video/video-actions'
|
import { addVideoActionButton } from '@/components/video/video-actions'
|
||||||
|
import { Options, options } from './options'
|
||||||
const options = defineOptionsMetadata({
|
|
||||||
showInWatchlaterPages: {
|
|
||||||
defaultValue: false,
|
|
||||||
displayName: '在稍后再看页面中仍然显示',
|
|
||||||
},
|
|
||||||
})
|
|
||||||
|
|
||||||
type Options = OptionsOfMetadata<typeof options>
|
|
||||||
|
|
||||||
const entry: ComponentEntry<Options> = async ({ settings }) => {
|
const entry: ComponentEntry<Options> = async ({ settings }) => {
|
||||||
if (watchlaterUrls.some(matchUrlPattern) && !settings.options.showInWatchlaterPages) {
|
if (watchlaterUrls.some(matchUrlPattern) && !settings.options.showInWatchlaterPages) {
|
||||||
|
|||||||
20
registry/lib/components/video/outer-watchlater/options.ts
Normal file
20
registry/lib/components/video/outer-watchlater/options.ts
Normal file
@ -0,0 +1,20 @@
|
|||||||
|
import { defineOptionsMetadata, OptionsOfMetadata } from '@/components/define'
|
||||||
|
|
||||||
|
export enum DisplayMode {
|
||||||
|
Auto = '自动',
|
||||||
|
Icon = '图标',
|
||||||
|
IconAndText = '图标 + 文字',
|
||||||
|
}
|
||||||
|
export const options = defineOptionsMetadata({
|
||||||
|
showInWatchlaterPages: {
|
||||||
|
defaultValue: false,
|
||||||
|
displayName: '在稍后再看页面中仍然显示',
|
||||||
|
},
|
||||||
|
displayMode: {
|
||||||
|
defaultValue: DisplayMode.Auto,
|
||||||
|
displayName: '显示方式',
|
||||||
|
dropdownEnum: DisplayMode,
|
||||||
|
},
|
||||||
|
})
|
||||||
|
|
||||||
|
export type Options = OptionsOfMetadata<typeof options>
|
||||||
@ -2,7 +2,7 @@
|
|||||||
<span
|
<span
|
||||||
class="quick-favorite be-quick-favorite video-toolbar-left-item"
|
class="quick-favorite be-quick-favorite video-toolbar-left-item"
|
||||||
title="快速收藏"
|
title="快速收藏"
|
||||||
:class="{ on: isFavorite }"
|
:class="{ on: isFavorite, ...displayModeClass }"
|
||||||
@click.left.self="toggle()"
|
@click.left.self="toggle()"
|
||||||
@click.right.prevent.self="listShowing = !listShowing"
|
@click.right.prevent.self="listShowing = !listShowing"
|
||||||
>
|
>
|
||||||
@ -33,12 +33,13 @@
|
|||||||
</span>
|
</span>
|
||||||
</template>
|
</template>
|
||||||
<script lang="ts">
|
<script lang="ts">
|
||||||
import { getComponentSettings } from '@/core/settings'
|
import { addComponentListener, getComponentSettings } from '@/core/settings'
|
||||||
import { getJsonWithCredentials, postTextWithCredentials } from '@/core/ajax'
|
import { getJsonWithCredentials, postTextWithCredentials } from '@/core/ajax'
|
||||||
import { getUID, getCsrf } from '@/core/utils'
|
import { getUID, getCsrf } from '@/core/utils'
|
||||||
import { logError } from '@/core/utils/log'
|
import { logError } from '@/core/utils/log'
|
||||||
import { Toast } from '@/core/toast'
|
import { Toast } from '@/core/toast'
|
||||||
import { VDropdown } from '@/ui'
|
import { VDropdown } from '@/ui'
|
||||||
|
import { DisplayMode, Options } from './options'
|
||||||
|
|
||||||
const { options } = getComponentSettings('quickFavorite')
|
const { options } = getComponentSettings('quickFavorite')
|
||||||
export default Vue.extend({
|
export default Vue.extend({
|
||||||
@ -46,6 +47,7 @@ export default Vue.extend({
|
|||||||
VDropdown,
|
VDropdown,
|
||||||
},
|
},
|
||||||
data() {
|
data() {
|
||||||
|
const { displayMode } = getComponentSettings<Options>('outerWatchlater').options
|
||||||
return {
|
return {
|
||||||
aid: unsafeWindow.aid,
|
aid: unsafeWindow.aid,
|
||||||
favoriteTitle: '',
|
favoriteTitle: '',
|
||||||
@ -56,8 +58,17 @@ export default Vue.extend({
|
|||||||
lists: [],
|
lists: [],
|
||||||
selectedFavorite: '<未选择>',
|
selectedFavorite: '<未选择>',
|
||||||
listShowing: false,
|
listShowing: false,
|
||||||
|
displayMode,
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
computed: {
|
||||||
|
displayModeClass() {
|
||||||
|
return {
|
||||||
|
'icon-only': this.displayMode === DisplayMode.Icon,
|
||||||
|
'icon-and-text': this.displayMode === DisplayMode.IconAndText,
|
||||||
|
}
|
||||||
|
},
|
||||||
|
},
|
||||||
watch: {
|
watch: {
|
||||||
selectedFavorite(value: string) {
|
selectedFavorite(value: string) {
|
||||||
if (this.lists.length === 0) {
|
if (this.lists.length === 0) {
|
||||||
@ -101,6 +112,9 @@ export default Vue.extend({
|
|||||||
},
|
},
|
||||||
created() {
|
created() {
|
||||||
this.syncFavoriteState()
|
this.syncFavoriteState()
|
||||||
|
addComponentListener('quickFavorite.displayMode', (value: DisplayMode) => {
|
||||||
|
this.displayMode = value
|
||||||
|
})
|
||||||
},
|
},
|
||||||
methods: {
|
methods: {
|
||||||
async syncFavoriteState() {
|
async syncFavoriteState() {
|
||||||
@ -192,12 +206,22 @@ export default Vue.extend({
|
|||||||
.text {
|
.text {
|
||||||
display: inline;
|
display: inline;
|
||||||
}
|
}
|
||||||
@media screen and (max-width: 1340px), (max-height: 750px) {
|
|
||||||
|
@mixin icon-only {
|
||||||
margin-right: max(calc(min(11vw, 11vh) - 117.2px), 6px) !important;
|
margin-right: max(calc(min(11vw, 11vh) - 117.2px), 6px) !important;
|
||||||
.text {
|
.text {
|
||||||
display: none;
|
display: none;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
&.icon-only {
|
||||||
|
@include icon-only();
|
||||||
|
}
|
||||||
|
&:not(.icon-and-text) {
|
||||||
|
@media screen and (max-width: 1340px), (max-height: 750px) {
|
||||||
|
@include icon-only();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
&-icon {
|
&-icon {
|
||||||
font-family: 'quick-favorite' !important;
|
font-family: 'quick-favorite' !important;
|
||||||
font-size: 28px;
|
font-size: 28px;
|
||||||
|
|||||||
@ -1,28 +1,11 @@
|
|||||||
import {
|
import { defineComponentMetadata } from '@/components/define'
|
||||||
defineComponentMetadata,
|
|
||||||
defineOptionsMetadata,
|
|
||||||
OptionsOfMetadata,
|
|
||||||
} from '@/components/define'
|
|
||||||
import { ComponentEntry } from '@/components/types'
|
import { ComponentEntry } from '@/components/types'
|
||||||
import { getUID, matchUrlPattern, mountVueComponent } from '@/core/utils'
|
import { getUID, matchUrlPattern, mountVueComponent } from '@/core/utils'
|
||||||
import { favoriteListUrls, videoUrls } from '@/core/utils/urls'
|
import { favoriteListUrls, videoUrls } from '@/core/utils/urls'
|
||||||
import { KeyBindingAction } from '../../utils/keymap/bindings'
|
import { KeyBindingAction } from '../../utils/keymap/bindings'
|
||||||
import { addVideoActionButton } from '@/components/video/video-actions'
|
import { addVideoActionButton } from '@/components/video/video-actions'
|
||||||
import { videoChange } from '@/core/observer'
|
import { videoChange } from '@/core/observer'
|
||||||
|
import { options, Options } from './options'
|
||||||
const options = defineOptionsMetadata({
|
|
||||||
favoriteFolderID: {
|
|
||||||
defaultValue: 0,
|
|
||||||
displayName: '快速收藏夹ID',
|
|
||||||
hidden: true,
|
|
||||||
},
|
|
||||||
showInFavoritePages: {
|
|
||||||
defaultValue: false,
|
|
||||||
displayName: '在收藏夹播放页面仍然显示',
|
|
||||||
},
|
|
||||||
})
|
|
||||||
|
|
||||||
type Options = OptionsOfMetadata<typeof options>
|
|
||||||
|
|
||||||
const entry: ComponentEntry<Options> = async ({ settings }) => {
|
const entry: ComponentEntry<Options> = async ({ settings }) => {
|
||||||
if (favoriteListUrls.some(matchUrlPattern) && !settings.options.showInFavoritePages) {
|
if (favoriteListUrls.some(matchUrlPattern) && !settings.options.showInFavoritePages) {
|
||||||
|
|||||||
25
registry/lib/components/video/quick-favorite/options.ts
Normal file
25
registry/lib/components/video/quick-favorite/options.ts
Normal file
@ -0,0 +1,25 @@
|
|||||||
|
import { defineOptionsMetadata, OptionsOfMetadata } from '@/components/define'
|
||||||
|
|
||||||
|
export enum DisplayMode {
|
||||||
|
Auto = '自动',
|
||||||
|
Icon = '图标',
|
||||||
|
IconAndText = '图标 + 文字',
|
||||||
|
}
|
||||||
|
export const options = defineOptionsMetadata({
|
||||||
|
favoriteFolderID: {
|
||||||
|
defaultValue: 0,
|
||||||
|
displayName: '快速收藏夹ID',
|
||||||
|
hidden: true,
|
||||||
|
},
|
||||||
|
showInFavoritePages: {
|
||||||
|
defaultValue: false,
|
||||||
|
displayName: '在收藏夹播放页面仍然显示',
|
||||||
|
},
|
||||||
|
displayMode: {
|
||||||
|
defaultValue: DisplayMode.Auto,
|
||||||
|
displayName: '显示方式',
|
||||||
|
dropdownEnum: DisplayMode,
|
||||||
|
},
|
||||||
|
})
|
||||||
|
|
||||||
|
export type Options = OptionsOfMetadata<typeof options>
|
||||||
1
registry/lib/plugins/feeds/filter/hide-goods/index.md
Normal file
1
registry/lib/plugins/feeds/filter/hide-goods/index.md
Normal file
@ -0,0 +1 @@
|
|||||||
|
移除动态里的商品带货动态 (UP主的推荐 · 来自 XX), 装有 `动态过滤器` 时生效.
|
||||||
24
registry/lib/plugins/feeds/filter/hide-goods/index.ts
Normal file
24
registry/lib/plugins/feeds/filter/hide-goods/index.ts
Normal file
@ -0,0 +1,24 @@
|
|||||||
|
import type { PluginMetadata } from '@/plugins/plugin'
|
||||||
|
|
||||||
|
export const plugin: PluginMetadata = {
|
||||||
|
name: 'feedsFilter.pluginBlocks.goods',
|
||||||
|
displayName: '动态过滤器 - 移除商品带货动态',
|
||||||
|
async setup() {
|
||||||
|
const { forEachFeedsCard, getVueData } = await import('@/components/feeds/api')
|
||||||
|
forEachFeedsCard({
|
||||||
|
added: card => {
|
||||||
|
const vueData = getVueData(card.element)
|
||||||
|
const additionalType: string | null = lodash.get(
|
||||||
|
vueData,
|
||||||
|
'data.modules.module_dynamic.additional.type',
|
||||||
|
null,
|
||||||
|
)
|
||||||
|
const isGoods = additionalType === 'ADDITIONAL_TYPE_GOODS'
|
||||||
|
if (!isGoods) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
card.element.classList.add('plugin-block')
|
||||||
|
},
|
||||||
|
})
|
||||||
|
},
|
||||||
|
}
|
||||||
64
registry/lib/plugins/video/download/wasm-output/database.ts
Normal file
64
registry/lib/plugins/video/download/wasm-output/database.ts
Normal file
@ -0,0 +1,64 @@
|
|||||||
|
const DB_NAME = 'bilibili-evolved-wasm-output'
|
||||||
|
const DB_VERSION = 124
|
||||||
|
|
||||||
|
export const storeNames = {
|
||||||
|
cache: 'cache',
|
||||||
|
} as const
|
||||||
|
|
||||||
|
async function database() {
|
||||||
|
return new Promise((reslove: (db: IDBDatabase) => void, reject) => {
|
||||||
|
const req = unsafeWindow.indexedDB.open(DB_NAME, DB_VERSION)
|
||||||
|
req.onerror = reject
|
||||||
|
req.onupgradeneeded = () => {
|
||||||
|
const db = req.result
|
||||||
|
for (const name of db.objectStoreNames) {
|
||||||
|
db.deleteObjectStore(name)
|
||||||
|
}
|
||||||
|
Object.values(storeNames).forEach(v => {
|
||||||
|
db.createObjectStore(v)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
req.onsuccess = () => reslove(req.result)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
async function objectStore(name: string, mode?: IDBTransactionMode) {
|
||||||
|
return database().then(
|
||||||
|
db =>
|
||||||
|
new Promise((reslove: (db: IDBObjectStore) => void, reject) => {
|
||||||
|
const tr = db.transaction(name, mode)
|
||||||
|
reslove(tr.objectStore(name))
|
||||||
|
tr.onerror = reject
|
||||||
|
}),
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
async function get(store: IDBObjectStore, key: IDBValidKey | IDBKeyRange) {
|
||||||
|
return new Promise((reslove: (db: any) => void, reject) => {
|
||||||
|
const res = store.get(key)
|
||||||
|
res.onerror = reject
|
||||||
|
res.onsuccess = () => reslove(res.result)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
async function put(store: IDBObjectStore, value: any, key?: IDBValidKey) {
|
||||||
|
return new Promise((reslove: (db: IDBValidKey) => void, reject) => {
|
||||||
|
const res = store.put(value, key)
|
||||||
|
res.onerror = reject
|
||||||
|
res.onsuccess = () => reslove(res.result)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
export async function getOrLoad<K extends keyof typeof storeNames, V>(
|
||||||
|
storeName: K,
|
||||||
|
key: IDBValidKey,
|
||||||
|
loader: (key: IDBValidKey) => V,
|
||||||
|
) {
|
||||||
|
const value: V = await objectStore(storeName).then(store => get(store, key))
|
||||||
|
if (value) {
|
||||||
|
return value
|
||||||
|
}
|
||||||
|
const newValue = await loader(key)
|
||||||
|
await objectStore(storeName, 'readwrite').then(store => put(store, newValue, key))
|
||||||
|
return newValue
|
||||||
|
}
|
||||||
@ -2,27 +2,36 @@ import { DownloadPackage } from '@/core/download'
|
|||||||
import { meta } from '@/core/meta'
|
import { meta } from '@/core/meta'
|
||||||
import { Toast } from '@/core/toast'
|
import { Toast } from '@/core/toast'
|
||||||
import { FFmpeg } from './ffmpeg'
|
import { FFmpeg } from './ffmpeg'
|
||||||
import { httpGet, toBlobUrl, toastProgress } from './utils'
|
import { getCacheOrGet, httpGet, toastProgress, toBlobUrl } from './utils'
|
||||||
|
|
||||||
const ffmpeg = new FFmpeg()
|
const ffmpeg = new FFmpeg()
|
||||||
|
|
||||||
async function load(toast: Toast) {
|
async function load(toast: Toast) {
|
||||||
await ffmpeg.load({
|
await ffmpeg.load({
|
||||||
workerLoadURL: await toBlobUrl(
|
workerLoadURL: toBlobUrl(
|
||||||
|
await getCacheOrGet(
|
||||||
|
'ffmpeg-worker',
|
||||||
meta.compilationInfo.altCdn.library.ffmpeg.worker,
|
meta.compilationInfo.altCdn.library.ffmpeg.worker,
|
||||||
'text/javascript',
|
|
||||||
toastProgress(toast, '正在加载 FFmpeg Worker'),
|
toastProgress(toast, '正在加载 FFmpeg Worker'),
|
||||||
),
|
),
|
||||||
coreURL: await toBlobUrl(
|
|
||||||
meta.compilationInfo.altCdn.library.ffmpeg.core,
|
|
||||||
'text/javascript',
|
'text/javascript',
|
||||||
|
),
|
||||||
|
coreURL: toBlobUrl(
|
||||||
|
await getCacheOrGet(
|
||||||
|
'ffmpeg-core',
|
||||||
|
meta.compilationInfo.altCdn.library.ffmpeg.core,
|
||||||
toastProgress(toast, '正在加载 FFmpeg Core'),
|
toastProgress(toast, '正在加载 FFmpeg Core'),
|
||||||
),
|
),
|
||||||
wasmURL: await toBlobUrl(
|
'text/javascript',
|
||||||
|
),
|
||||||
|
wasmURL: toBlobUrl(
|
||||||
|
await getCacheOrGet(
|
||||||
|
'ffmpeg-wasm',
|
||||||
meta.compilationInfo.altCdn.library.ffmpeg.wasm,
|
meta.compilationInfo.altCdn.library.ffmpeg.wasm,
|
||||||
'application/wasm',
|
|
||||||
toastProgress(toast, '正在加载 FFmpeg WASM'),
|
toastProgress(toast, '正在加载 FFmpeg WASM'),
|
||||||
),
|
),
|
||||||
|
'application/wasm',
|
||||||
|
),
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
export async function run(
|
export async function run(
|
||||||
|
|||||||
@ -1,5 +1,6 @@
|
|||||||
import { Toast } from '@/core/toast'
|
import { Toast } from '@/core/toast'
|
||||||
import { formatFileSize, formatPercent } from '@/core/utils/formatters'
|
import { formatFileSize, formatPercent } from '@/core/utils/formatters'
|
||||||
|
import { getOrLoad, storeNames } from './database'
|
||||||
|
|
||||||
type OnProgress = (received: number, length: number) => void
|
type OnProgress = (received: number, length: number) => void
|
||||||
|
|
||||||
@ -47,8 +48,11 @@ export async function httpGet(url: string, onprogress: OnProgress) {
|
|||||||
return chunksAll
|
return chunksAll
|
||||||
}
|
}
|
||||||
|
|
||||||
export async function toBlobUrl(url: string, mimeType: string, onprogress: OnProgress) {
|
export async function getCacheOrGet(key: string, url: string, loading: OnProgress) {
|
||||||
const buffer = await httpGet(url, onprogress)
|
return getOrLoad(storeNames.cache, key, async () => httpGet(url, loading))
|
||||||
|
}
|
||||||
|
|
||||||
|
export function toBlobUrl(buffer: Uint8Array, mimeType: string) {
|
||||||
const blob = new Blob([buffer], { type: mimeType })
|
const blob = new Blob([buffer], { type: mimeType })
|
||||||
return URL.createObjectURL(blob)
|
return URL.createObjectURL(blob)
|
||||||
}
|
}
|
||||||
|
|||||||
@ -32,7 +32,8 @@ export const updateLatestID = (cards: { id: string }[]) => {
|
|||||||
const [id] = [...cards.map(c => c.id)].sort(compareID).reverse()
|
const [id] = [...cards.map(c => c.id)].sort(compareID).reverse()
|
||||||
setLatestID(id)
|
setLatestID(id)
|
||||||
}
|
}
|
||||||
export const getNotifyCount = async (type = 'all'): Promise<number> => {
|
/** 按类型获取动态提醒数 */
|
||||||
|
export const getNotifyCountByType = async (type: string): Promise<number> => {
|
||||||
const api = `https://api.bilibili.com/x/polymer/web-dynamic/v1/feed/all/update?type=${type}&update_baseline=${getLatestID()}`
|
const api = `https://api.bilibili.com/x/polymer/web-dynamic/v1/feed/all/update?type=${type}&update_baseline=${getLatestID()}`
|
||||||
const json = await getJsonWithCredentials(api)
|
const json = await getJsonWithCredentials(api)
|
||||||
if (json.code !== 0) {
|
if (json.code !== 0) {
|
||||||
@ -40,3 +41,14 @@ export const getNotifyCount = async (type = 'all'): Promise<number> => {
|
|||||||
}
|
}
|
||||||
return lodash.get(json, 'data.update_num', 0)
|
return lodash.get(json, 'data.update_num', 0)
|
||||||
}
|
}
|
||||||
|
/** 获取所有类型的动态提醒数 (视频, 番剧, 专栏; 普通动态不算)
|
||||||
|
* @see https://github.com/the1812/Bilibili-Evolved/issues/4427
|
||||||
|
*/
|
||||||
|
export const getNotifyCount = async (): Promise<number> => {
|
||||||
|
const api = 'https://api.bilibili.com/x/web-interface/dynamic/entrance'
|
||||||
|
const json = await getJsonWithCredentials(api)
|
||||||
|
if (json.code !== 0) {
|
||||||
|
return 0
|
||||||
|
}
|
||||||
|
return lodash.get(json, 'data.update_info.item.count', 0)
|
||||||
|
}
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user