mirror of
https://github.com/the1812/Bilibili-Evolved.git
synced 2025-11-04 21:22:45 +08:00
Merge branch 'preview-features' of https://github.com/the1812/Bilibili-Evolved into preview
This commit is contained in:
commit
8486b3dc4f
@ -48,10 +48,6 @@
|
|||||||
"name": "Build features",
|
"name": "Build features",
|
||||||
"run": "cd registry\npnpm install\ncd ../\npnpm run build-features\n"
|
"run": "cd registry\npnpm install\ncd ../\npnpm run build-features\n"
|
||||||
},
|
},
|
||||||
{
|
|
||||||
"name": "Build GitHub config",
|
|
||||||
"run": "pnpm run build-github-config"
|
|
||||||
},
|
|
||||||
{
|
{
|
||||||
"name": "Git commit",
|
"name": "Git commit",
|
||||||
"id": "commit",
|
"id": "commit",
|
||||||
|
|||||||
2
.github/workflows/build.yml
vendored
2
.github/workflows/build.yml
vendored
@ -36,8 +36,6 @@ jobs:
|
|||||||
pnpm install
|
pnpm install
|
||||||
cd ../
|
cd ../
|
||||||
pnpm run build-features
|
pnpm run build-features
|
||||||
- name: Build GitHub config
|
|
||||||
run: pnpm run build-github-config
|
|
||||||
- name: Git commit
|
- name: Git commit
|
||||||
id: commit
|
id: commit
|
||||||
run: |
|
run: |
|
||||||
|
|||||||
@ -10,7 +10,7 @@
|
|||||||
</template>
|
</template>
|
||||||
<script lang="ts">
|
<script lang="ts">
|
||||||
import { TabControl, VIcon } from '@/ui'
|
import { TabControl, VIcon } from '@/ui'
|
||||||
import { feedsCardTypes } from '@/components/feeds/api'
|
import { FeedsCardType, feedsCardTypes } from '@/components/feeds/api'
|
||||||
import { getNotifyCount } from '@/components/feeds/notify'
|
import { getNotifyCount } from '@/components/feeds/notify'
|
||||||
import { popperMixin } from '../mixins'
|
import { popperMixin } from '../mixins'
|
||||||
import { tabs } from './tabs/tabs'
|
import { tabs } from './tabs/tabs'
|
||||||
@ -45,7 +45,11 @@ export default Vue.extend({
|
|||||||
if (tab.name === 'live') {
|
if (tab.name === 'live') {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
const count = await getNotifyCount(feedsCardTypes[tab.name].id.toString())
|
const feedsCardType = feedsCardTypes[tab.name] as FeedsCardType
|
||||||
|
if (!feedsCardType.apiType) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
const count = await getNotifyCount(feedsCardType.apiType)
|
||||||
tab.count = count
|
tab.count = count
|
||||||
console.log(tab)
|
console.log(tab)
|
||||||
})
|
})
|
||||||
|
|||||||
@ -23,14 +23,15 @@ export default Vue.extend({
|
|||||||
},
|
},
|
||||||
mixins: [
|
mixins: [
|
||||||
nextPageMixin(feedsCardTypes.bangumi, (card: any) => {
|
nextPageMixin(feedsCardTypes.bangumi, (card: any) => {
|
||||||
const cardJson = JSON.parse(card.card)
|
const pgc = lodash.get(card, 'modules.module_dynamic.major.pgc')
|
||||||
|
const author = lodash.get(card, 'modules.module_author')
|
||||||
return {
|
return {
|
||||||
id: card.desc.dynamic_id_str,
|
id: card.id_str,
|
||||||
title: cardJson.apiSeasonInfo.title,
|
title: author.name,
|
||||||
coverUrl: cardJson.apiSeasonInfo.cover,
|
coverUrl: author.face,
|
||||||
epCoverUrl: cardJson.cover,
|
epCoverUrl: pgc.cover,
|
||||||
epTitle: cardJson.new_desc,
|
epTitle: pgc.title.replace(new RegExp(`^${author.name}:`), ''),
|
||||||
url: cardJson.url,
|
url: pgc.jump_url,
|
||||||
get new() {
|
get new() {
|
||||||
return isNewID(this.id)
|
return isNewID(this.id)
|
||||||
},
|
},
|
||||||
|
|||||||
@ -23,17 +23,18 @@ export default Vue.extend({
|
|||||||
},
|
},
|
||||||
mixins: [
|
mixins: [
|
||||||
nextPageMixin(feedsCardTypes.column, (card: any) => {
|
nextPageMixin(feedsCardTypes.column, (card: any) => {
|
||||||
const cardJson = JSON.parse(card.card)
|
const article = lodash.get(card, 'modules.module_dynamic.major.article')
|
||||||
|
const author = lodash.get(card, 'modules.module_author')
|
||||||
return {
|
return {
|
||||||
id: card.desc.dynamic_id_str,
|
id: card.id_str,
|
||||||
cvID: cardJson.id,
|
cvID: article.id.toString(),
|
||||||
title: cardJson.title,
|
title: article.title,
|
||||||
upName: cardJson.author.name,
|
upName: author.name,
|
||||||
upFaceUrl: cardJson.author.face,
|
upFaceUrl: author.face,
|
||||||
upID: cardJson.author.mid,
|
upID: author.mid,
|
||||||
description: cardJson.summary,
|
description: article.desc,
|
||||||
covers: cardJson.image_urls,
|
covers: article.covers,
|
||||||
originalCovers: cardJson.origin_image_urls,
|
originalCovers: article.covers,
|
||||||
get new() {
|
get new() {
|
||||||
return isNewID(this.id)
|
return isNewID(this.id)
|
||||||
},
|
},
|
||||||
|
|||||||
@ -31,7 +31,7 @@
|
|||||||
</template>
|
</template>
|
||||||
<script lang="ts">
|
<script lang="ts">
|
||||||
import { VideoCard } from '@/components/feeds/video-card'
|
import { VideoCard } from '@/components/feeds/video-card'
|
||||||
import { formatDuration, formatCount } from '@/core/utils/formatters'
|
import { formatDuration, formatCount, parseDuration } from '@/core/utils/formatters'
|
||||||
import { isNewID } from '@/components/feeds/notify'
|
import { isNewID } from '@/components/feeds/notify'
|
||||||
import { feedsCardTypes, groupVideoFeeds } from '@/components/feeds/api'
|
import { feedsCardTypes, groupVideoFeeds } from '@/components/feeds/api'
|
||||||
import VideoCardComponent from '@/components/feeds/VideoCard.vue'
|
import VideoCardComponent from '@/components/feeds/VideoCard.vue'
|
||||||
@ -80,24 +80,25 @@ export default Vue.extend({
|
|||||||
},
|
},
|
||||||
mixins: [
|
mixins: [
|
||||||
nextPageMixin(feedsCardTypes.video, (card: any) => {
|
nextPageMixin(feedsCardTypes.video, (card: any) => {
|
||||||
const cardJson = JSON.parse(card.card)
|
const archive = lodash.get(card, 'modules.module_dynamic.major.archive')
|
||||||
|
const author = lodash.get(card, 'modules.module_author')
|
||||||
return {
|
return {
|
||||||
id: card.desc.dynamic_id_str,
|
id: card.id_str,
|
||||||
aid: cardJson.aid,
|
aid: archive.aid,
|
||||||
bvid: card.desc.bvid,
|
bvid: archive.bvid,
|
||||||
videoUrl: `https://www.bilibili.com/${card.desc.bvid}`,
|
videoUrl: `https://www.bilibili.com/${archive.bvid}`,
|
||||||
coverUrl: cardJson.pic,
|
coverUrl: archive.cover,
|
||||||
title: cardJson.title,
|
title: archive.title,
|
||||||
duration: cardJson.duration,
|
duration: parseDuration(archive.duration_text),
|
||||||
durationText: formatDuration(cardJson.duration),
|
durationText: formatDuration(parseDuration(archive.duration_text)),
|
||||||
description: cardJson.desc,
|
description: archive.desc,
|
||||||
pubTime: formatPubTime(cardJson.pubdate * 1000),
|
pubTime: formatPubTime(author.pub_ts * 1000),
|
||||||
pubTimeText: formatPubTimeText(cardJson.pubdate * 1000),
|
pubTimeText: formatPubTimeText(author.pub_ts * 1000),
|
||||||
upFaceUrl: card.desc.user_profile.info.face,
|
upFaceUrl: author.face,
|
||||||
upName: card.desc.user_profile.info.uname,
|
upName: author.name,
|
||||||
upID: card.desc.user_profile.info.uid,
|
upID: author.mid,
|
||||||
watchlater: true,
|
watchlater: true,
|
||||||
playCount: formatCount(cardJson.stat.view),
|
playCount: formatCount(archive.stat.play),
|
||||||
get new() {
|
get new() {
|
||||||
return isNewID(this.id)
|
return isNewID(this.id)
|
||||||
},
|
},
|
||||||
|
|||||||
@ -4,7 +4,7 @@ import {
|
|||||||
applyContentFilter,
|
applyContentFilter,
|
||||||
isPreOrderedVideo,
|
isPreOrderedVideo,
|
||||||
} from '@/components/feeds/api'
|
} from '@/components/feeds/api'
|
||||||
import { descendingStringSort } from '@/core/utils/sort'
|
import { descendingBigIntSort } from '@/core/utils/sort'
|
||||||
import { logError } from '@/core/utils/log'
|
import { logError } from '@/core/utils/log'
|
||||||
import { setLatestID } from '@/components/feeds/notify'
|
import { setLatestID } from '@/components/feeds/notify'
|
||||||
import { VLoading, VEmpty, ScrollTrigger } from '@/ui'
|
import { VLoading, VEmpty, ScrollTrigger } from '@/ui'
|
||||||
@ -33,7 +33,7 @@ export const nextPageMixin = <MappedItem extends { id: string }, RawItem>(
|
|||||||
},
|
},
|
||||||
computed: {
|
computed: {
|
||||||
sortedCards() {
|
sortedCards() {
|
||||||
return ([...this.cards] as MappedItem[]).sort(descendingStringSort(it => it.id))
|
return ([...this.cards] as MappedItem[]).sort(descendingBigIntSort(it => it.id))
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
async created() {
|
async created() {
|
||||||
@ -56,12 +56,12 @@ export const nextPageMixin = <MappedItem extends { id: string }, RawItem>(
|
|||||||
this.hasMorePage = false
|
this.hasMorePage = false
|
||||||
throw new Error(json.message)
|
throw new Error(json.message)
|
||||||
}
|
}
|
||||||
const jsonCards = lodash.get(json, 'data.cards', []).map(jsonMapper) as MappedItem[]
|
const jsonCards = lodash.get(json, 'data.items', []).map(jsonMapper) as MappedItem[]
|
||||||
|
|
||||||
let concatCards = applyContentFilter(
|
let concatCards = applyContentFilter(
|
||||||
cards
|
cards
|
||||||
.concat(jsonCards)
|
.concat(jsonCards)
|
||||||
.sort(descendingStringSort(it => it.id))
|
.sort(descendingBigIntSort(it => it.id))
|
||||||
.filter(card => !isPreOrderedVideo(card)),
|
.filter(card => !isPreOrderedVideo(card)),
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|||||||
@ -38,7 +38,7 @@
|
|||||||
:title="topic.name"
|
:title="topic.name"
|
||||||
class="topic"
|
class="topic"
|
||||||
target="_blank"
|
target="_blank"
|
||||||
:href="'https://t.bilibili.com/topic/name/' + topic.name + '/feed'"
|
:href="topic.url || 'https://t.bilibili.com/topic/name/' + topic.name + '/feed'"
|
||||||
>
|
>
|
||||||
<VIcon icon="mdi-tag-outline" :size="14" />
|
<VIcon icon="mdi-tag-outline" :size="14" />
|
||||||
<div class="topic-name">
|
<div class="topic-name">
|
||||||
|
|||||||
@ -1,6 +1,6 @@
|
|||||||
import { getUID, pascalCase } from '@/core/utils'
|
import { getUID, pascalCase } from '@/core/utils'
|
||||||
import { getJsonWithCredentials } from '@/core/ajax'
|
import { getJsonWithCredentials } from '@/core/ajax'
|
||||||
import { formatCount, formatDuration } from '@/core/utils/formatters'
|
import { formatCount, formatDuration, parseDuration } from '@/core/utils/formatters'
|
||||||
import { watchlaterList } from '@/components/video/watchlater'
|
import { watchlaterList } from '@/components/video/watchlater'
|
||||||
import { getData, registerData } from '@/plugins/data'
|
import { getData, registerData } from '@/plugins/data'
|
||||||
import { descendingStringSort } from '@/core/utils/sort'
|
import { descendingStringSort } from '@/core/utils/sort'
|
||||||
@ -66,15 +66,19 @@ export const withContentFilter =
|
|||||||
* @param afterID 返回指定ID之前的动态历史, 省略则返回最新的动态
|
* @param afterID 返回指定ID之前的动态历史, 省略则返回最新的动态
|
||||||
*/
|
*/
|
||||||
export const getFeedsUrl = (type: FeedsCardType | string, afterID?: string | number) => {
|
export const getFeedsUrl = (type: FeedsCardType | string, afterID?: string | number) => {
|
||||||
|
const params = new URLSearchParams()
|
||||||
if (typeof type === 'string') {
|
if (typeof type === 'string') {
|
||||||
return `https://api.vc.bilibili.com/dynamic_svr/v1/dynamic_svr/dynamic_new?uid=${getUID()}&type_list=${type}`
|
params.set('type', type)
|
||||||
|
} else if (type.apiType) {
|
||||||
|
params.set('type', type.apiType)
|
||||||
|
} else {
|
||||||
|
console.warn(`unknown apiType for ${type.name}`)
|
||||||
|
params.set('type', 'all')
|
||||||
}
|
}
|
||||||
const id = type.id.toString()
|
|
||||||
let api = `https://api.vc.bilibili.com/dynamic_svr/v1/dynamic_svr/dynamic_new?uid=${getUID()}&type_list=${id}`
|
|
||||||
if (afterID) {
|
if (afterID) {
|
||||||
api = `https://api.vc.bilibili.com/dynamic_svr/v1/dynamic_svr/dynamic_history?uid=${getUID()}&offset_dynamic_id=${afterID}&type=${id}`
|
params.set('offset', afterID.toString())
|
||||||
}
|
}
|
||||||
return api
|
return `https://api.bilibili.com/x/polymer/web-dynamic/v1/feed/all?${params.toString()}`
|
||||||
}
|
}
|
||||||
/**
|
/**
|
||||||
* 获取动态
|
* 获取动态
|
||||||
@ -100,59 +104,68 @@ export const getVideoFeeds = withContentFilter(
|
|||||||
if (json.code !== 0) {
|
if (json.code !== 0) {
|
||||||
throw new Error(json.message)
|
throw new Error(json.message)
|
||||||
}
|
}
|
||||||
const dataCards = json.data.cards as any[]
|
const dataCards = json.data.items as any[]
|
||||||
const dataCardsWithoutPreOrder = dataCards.filter(it => !isPreOrderedVideo(JSON.parse(it.card)))
|
|
||||||
if (type === 'video') {
|
if (type === 'video') {
|
||||||
return groupVideoFeeds(
|
return groupVideoFeeds(
|
||||||
dataCards.map((c: any): VideoCard => {
|
dataCards.map((card: any): VideoCard => {
|
||||||
const card = JSON.parse(c.card)
|
const archive = lodash.get(card, 'modules.module_dynamic.major.archive')
|
||||||
const topics = lodash.get(c, 'display.topic_info.topic_details', []).map((it: any) => ({
|
const author = lodash.get(card, 'modules.module_author')
|
||||||
id: it.topic_id,
|
const dynamic = lodash.get(card, 'modules.module_dynamic.desc.text', '')
|
||||||
name: it.topic_name,
|
const stat = lodash.get(card, 'modules.module_stat')
|
||||||
}))
|
const topics = (
|
||||||
|
lodash.get(card, 'modules.module_dynamic.desc.rich_text_nodes', []) as any[]
|
||||||
|
)
|
||||||
|
.filter(node => node.type === 'RICH_TEXT_NODE_TYPE_TOPIC')
|
||||||
|
.map(node => {
|
||||||
return {
|
return {
|
||||||
id: c.desc.dynamic_id_str,
|
id: node.text,
|
||||||
aid: card.aid,
|
name: node.text,
|
||||||
bvid: c.desc.bvid || card.bvid,
|
url: node.jump_url,
|
||||||
title: card.title,
|
}
|
||||||
upID: c.desc.user_profile.info.uid,
|
})
|
||||||
upName: c.desc.user_profile.info.uname,
|
return {
|
||||||
upFaceUrl: c.desc.user_profile.info.face,
|
id: card.id_str,
|
||||||
coverUrl: card.pic,
|
aid: archive.aid,
|
||||||
description: card.desc,
|
bvid: archive.bvid,
|
||||||
timestamp: c.timestamp,
|
title: archive.title,
|
||||||
time: new Date(c.timestamp * 1000),
|
upFaceUrl: author.face,
|
||||||
|
upName: author.name,
|
||||||
|
upID: author.mid,
|
||||||
|
coverUrl: archive.cover,
|
||||||
|
description: archive.desc,
|
||||||
|
timestamp: author.pub_ts * 1000,
|
||||||
|
time: new Date(author.pub_ts * 1000),
|
||||||
topics,
|
topics,
|
||||||
dynamic: card.dynamic,
|
dynamic,
|
||||||
like: formatCount(c.desc.like),
|
like: formatCount(stat.like.count),
|
||||||
duration: card.duration,
|
duration: parseDuration(archive.duration_text),
|
||||||
durationText: formatDuration(card.duration, 0),
|
durationText: formatDuration(parseDuration(archive.duration_text)),
|
||||||
playCount: formatCount(card.stat.view),
|
playCount: formatCount(archive.stat.play),
|
||||||
danmakuCount: formatCount(card.stat.danmaku),
|
danmakuCount: formatCount(archive.stat.danmaku),
|
||||||
watchlater: watchlaterList.includes(card.aid),
|
watchlater: watchlaterList.includes(archive.aid),
|
||||||
}
|
}
|
||||||
}),
|
}),
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
if (type === 'bangumi') {
|
if (type === 'bangumi') {
|
||||||
return dataCardsWithoutPreOrder.map((c: any): VideoCard => {
|
return dataCards.map((card: any): VideoCard => {
|
||||||
const card = JSON.parse(c.card)
|
const pgc = lodash.get(card, 'modules.module_dynamic.major.pgc')
|
||||||
|
const author = lodash.get(card, 'modules.module_author')
|
||||||
|
const stat = lodash.get(card, 'modules.module_stat')
|
||||||
return {
|
return {
|
||||||
id: c.desc.dynamic_id_str,
|
id: card.id_str,
|
||||||
aid: card.aid,
|
epID: pgc.epid,
|
||||||
bvid: c.desc.bvid || card.bvid,
|
title: pgc.title.replace(new RegExp(`^${author.name}:`), ''),
|
||||||
epID: card.episode_id,
|
upName: author.name,
|
||||||
title: card.new_desc,
|
upFaceUrl: author.face,
|
||||||
upName: card.apiSeasonInfo.title,
|
coverUrl: pgc.cover,
|
||||||
upFaceUrl: card.apiSeasonInfo.cover,
|
|
||||||
coverUrl: card.cover,
|
|
||||||
description: '',
|
description: '',
|
||||||
timestamp: c.timestamp,
|
timestamp: author.pub_ts * 1000,
|
||||||
time: new Date(c.timestamp * 1000),
|
time: new Date(author.pub_ts * 1000),
|
||||||
like: formatCount(c.desc.like),
|
like: formatCount(stat.like.count),
|
||||||
durationText: '',
|
durationText: '',
|
||||||
playCount: formatCount(card.play_count),
|
playCount: formatCount(pgc.stat.play),
|
||||||
danmakuCount: formatCount(card.bullet_count),
|
danmakuCount: formatCount(pgc.stat.danmaku),
|
||||||
watchlater: false,
|
watchlater: false,
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|||||||
@ -4,6 +4,8 @@
|
|||||||
export interface FeedsCardType {
|
export interface FeedsCardType {
|
||||||
id: number
|
id: number
|
||||||
name: string
|
name: string
|
||||||
|
/** 用于新版动态 API 的 type (/x/polymer/web-dynamic/), 各种动态类型对应的 type 还不完善 */
|
||||||
|
apiType?: string
|
||||||
}
|
}
|
||||||
/**
|
/**
|
||||||
* 转发类型的动态卡片
|
* 转发类型的动态卡片
|
||||||
@ -16,68 +18,71 @@ export const feedsCardTypes = {
|
|||||||
repost: {
|
repost: {
|
||||||
id: 1,
|
id: 1,
|
||||||
name: '转发',
|
name: '转发',
|
||||||
} as FeedsCardType,
|
},
|
||||||
textWithImages: {
|
textWithImages: {
|
||||||
id: 2,
|
id: 2,
|
||||||
name: '图文',
|
name: '图文',
|
||||||
} as FeedsCardType,
|
},
|
||||||
text: {
|
text: {
|
||||||
id: 4,
|
id: 4,
|
||||||
name: '文字',
|
name: '文字',
|
||||||
} as FeedsCardType,
|
},
|
||||||
video: {
|
video: {
|
||||||
id: 8,
|
id: 8,
|
||||||
name: '视频',
|
name: '视频',
|
||||||
} as FeedsCardType,
|
apiType: 'video',
|
||||||
|
},
|
||||||
miniVideo: {
|
miniVideo: {
|
||||||
id: 16,
|
id: 16,
|
||||||
name: '小视频',
|
name: '小视频',
|
||||||
} as FeedsCardType,
|
},
|
||||||
column: {
|
column: {
|
||||||
id: 64,
|
id: 64,
|
||||||
name: '专栏',
|
name: '专栏',
|
||||||
} as FeedsCardType,
|
apiType: 'article',
|
||||||
|
},
|
||||||
audio: {
|
audio: {
|
||||||
id: 256,
|
id: 256,
|
||||||
name: '音频',
|
name: '音频',
|
||||||
} as FeedsCardType,
|
},
|
||||||
bangumi: {
|
bangumi: {
|
||||||
id: 512,
|
id: 512,
|
||||||
name: '番剧',
|
name: '番剧',
|
||||||
} as FeedsCardType,
|
apiType: 'pgc',
|
||||||
|
},
|
||||||
share: {
|
share: {
|
||||||
id: 2048,
|
id: 2048,
|
||||||
name: '分享',
|
name: '分享',
|
||||||
} as FeedsCardType,
|
},
|
||||||
manga: {
|
manga: {
|
||||||
id: 2049,
|
id: 2049,
|
||||||
name: '漫画',
|
name: '漫画',
|
||||||
} as FeedsCardType,
|
},
|
||||||
film: {
|
film: {
|
||||||
id: 4098,
|
id: 4098,
|
||||||
name: '电影',
|
name: '电影',
|
||||||
} as FeedsCardType,
|
},
|
||||||
tv: {
|
tv: {
|
||||||
id: 4099,
|
id: 4099,
|
||||||
name: 'TV剧',
|
name: 'TV剧',
|
||||||
} as FeedsCardType,
|
},
|
||||||
chinese: {
|
chinese: {
|
||||||
id: 4100,
|
id: 4100,
|
||||||
name: '国创',
|
name: '国创',
|
||||||
} as FeedsCardType,
|
},
|
||||||
documentary: {
|
documentary: {
|
||||||
id: 4101,
|
id: 4101,
|
||||||
name: '纪录片',
|
name: '纪录片',
|
||||||
} as FeedsCardType,
|
},
|
||||||
mediaList: {
|
mediaList: {
|
||||||
id: 4300,
|
id: 4300,
|
||||||
name: '收藏夹',
|
name: '收藏夹',
|
||||||
} as FeedsCardType,
|
},
|
||||||
liveRecord: {
|
liveRecord: {
|
||||||
id: 2047, // FIXME: 暂时随便写个 id 了, 这个东西目前找不到 type
|
id: 2047, // FIXME: 暂时随便写个 id 了, 这个东西目前找不到 type
|
||||||
name: '开播记录',
|
name: '开播记录',
|
||||||
} as FeedsCardType,
|
},
|
||||||
}
|
} satisfies Record<string, FeedsCardType>
|
||||||
/** 是否是转发类型的卡片, 额外能够读取被转发动态的信息 */
|
/** 是否是转发类型的卡片, 额外能够读取被转发动态的信息 */
|
||||||
export const isRepostType = (card: FeedsCard): card is RepostFeedsCard =>
|
export const isRepostType = (card: FeedsCard): card is RepostFeedsCard =>
|
||||||
card.type === feedsCardTypes.repost
|
card.type === feedsCardTypes.repost
|
||||||
|
|||||||
@ -1,6 +1,5 @@
|
|||||||
import { getCookieValue, getUID } from '@/core/utils'
|
import { getCookieValue, getUID } from '@/core/utils'
|
||||||
import { getJsonWithCredentials } from '@/core/ajax'
|
import { getJsonWithCredentials } from '@/core/ajax'
|
||||||
import { navbarFeedsTypeList } from './api'
|
|
||||||
|
|
||||||
export const updateInterval = 5 * 60 * 1000 // 每5分钟更新1次动态提醒数字
|
export const updateInterval = 5 * 60 * 1000 // 每5分钟更新1次动态提醒数字
|
||||||
export const getLatestID = () => getCookieValue(`bp_t_offset_${getUID()}`)
|
export const getLatestID = () => getCookieValue(`bp_t_offset_${getUID()}`)
|
||||||
@ -33,10 +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 (typeList?: string): Promise<number> => {
|
export const getNotifyCount = async (type = 'all'): Promise<number> => {
|
||||||
const api = `https://api.vc.bilibili.com/dynamic_svr/v1/dynamic_svr/dynamic_num?rsp_type=1&uid=${getUID()}&update_num_dy_id=${getLatestID()}&type_list=${
|
const api = `https://api.bilibili.com/x/polymer/web-dynamic/v1/feed/all/update?type=${type}&update_baseline=${getLatestID()}`
|
||||||
typeList || navbarFeedsTypeList
|
|
||||||
}`
|
|
||||||
const json = await getJsonWithCredentials(api)
|
const json = await getJsonWithCredentials(api)
|
||||||
if (json.code !== 0) {
|
if (json.code !== 0) {
|
||||||
return 0
|
return 0
|
||||||
|
|||||||
@ -23,6 +23,7 @@ export interface VideoCard {
|
|||||||
topics?: {
|
topics?: {
|
||||||
id: number
|
id: number
|
||||||
name: string
|
name: string
|
||||||
|
url?: string
|
||||||
}[]
|
}[]
|
||||||
type?: string
|
type?: string
|
||||||
points?: number
|
points?: number
|
||||||
|
|||||||
@ -19,9 +19,27 @@ export const formatFileSize = (bytes: number, fixed = 1) => {
|
|||||||
*/
|
*/
|
||||||
export const formatPercent = (percent: number, fixed = 1) =>
|
export const formatPercent = (percent: number, fixed = 1) =>
|
||||||
`${Math.round(percent * 100 * 10 ** fixed) / 10 ** fixed}%`
|
`${Math.round(percent * 100 * 10 ** fixed) / 10 ** fixed}%`
|
||||||
/** 格式化时长为`H:mm:ss.F`, 不足1小时则为`mm:ss.F`
|
|
||||||
* @param time 时长
|
/**
|
||||||
* @param fixed 保留的小数位(毫秒), 默认不保留
|
* 将时长文本转换为秒数
|
||||||
|
* @param durationText 时长文本
|
||||||
|
*/
|
||||||
|
export const parseDuration = (durationText: string) => {
|
||||||
|
const parts = durationText.split(':')
|
||||||
|
let result = 0
|
||||||
|
parts.forEach((part, index) => {
|
||||||
|
const isLastPart = index === parts.length - 1
|
||||||
|
const partNumber = isLastPart ? parseFloat(part) : parseInt(part)
|
||||||
|
if (Number.isNaN(partNumber)) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
result += partNumber * 60 ** (parts.length - 1 - index)
|
||||||
|
})
|
||||||
|
return result
|
||||||
|
}
|
||||||
|
/** 格式化时长为 `H:mm:ss.F`, 不足1小时则为 `mm:ss.F`
|
||||||
|
* @param time 时长 (秒)
|
||||||
|
* @param fixed 保留的小数位 (毫秒), 默认不保留
|
||||||
*/
|
*/
|
||||||
export const formatDuration = (time: number, fixed = 0) => {
|
export const formatDuration = (time: number, fixed = 0) => {
|
||||||
const second = (time % 60).toFixed(fixed)
|
const second = (time % 60).toFixed(fixed)
|
||||||
|
|||||||
@ -9,6 +9,17 @@ export const ascendingStringSort =
|
|||||||
<T>(itemProp: (obj: T) => string = selfSorter) =>
|
<T>(itemProp: (obj: T) => string = selfSorter) =>
|
||||||
(a: T, b: T) =>
|
(a: T, b: T) =>
|
||||||
itemProp(a).localeCompare(itemProp(b))
|
itemProp(a).localeCompare(itemProp(b))
|
||||||
|
/** 字符串大数字升序排序 */
|
||||||
|
export const ascendingBigIntSort =
|
||||||
|
<T>(itemProp: (obj: T) => string = selfSorter) =>
|
||||||
|
(a: T, b: T) => {
|
||||||
|
const numberA = BigInt(itemProp(a))
|
||||||
|
const numberB = BigInt(itemProp(b))
|
||||||
|
if (numberA === numberB) {
|
||||||
|
return 0
|
||||||
|
}
|
||||||
|
return numberA > numberB ? 1 : -1
|
||||||
|
}
|
||||||
/** 降序排序 */
|
/** 降序排序 */
|
||||||
export const descendingSort =
|
export const descendingSort =
|
||||||
<T>(itemProp: (obj: T) => number = selfSorter) =>
|
<T>(itemProp: (obj: T) => number = selfSorter) =>
|
||||||
@ -19,3 +30,8 @@ export const descendingStringSort =
|
|||||||
<T>(itemProp: (obj: T) => string = selfSorter) =>
|
<T>(itemProp: (obj: T) => string = selfSorter) =>
|
||||||
(a: T, b: T) =>
|
(a: T, b: T) =>
|
||||||
itemProp(b).localeCompare(itemProp(a))
|
itemProp(b).localeCompare(itemProp(a))
|
||||||
|
/** 字符串大数字降序排序 */
|
||||||
|
export const descendingBigIntSort =
|
||||||
|
<T>(itemProp: (obj: T) => string = selfSorter) =>
|
||||||
|
(a: T, b: T) =>
|
||||||
|
-ascendingBigIntSort(itemProp)(a, b)
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user