mirror of
https://github.com/BewlyBewly/BewlyBewly.git
synced 2025-04-14 13:15:29 +00:00
Merge branch 'main' into dev
This commit is contained in:
@@ -13,16 +13,17 @@ import API_USER from './user'
|
||||
import API_VIDEO from './video'
|
||||
import API_WATCHLATER from './watchLater'
|
||||
|
||||
// Merge all API objects into one
|
||||
const FullAPI = Object.assign({}, API_AUTH, API_ANIME, API_HISTORY, API_FAVORITE, API_MOMENT, API_NOTIFICATION, API_RANKING, API_SEARCH, API_USER, API_VIDEO, API_WATCHLATER)
|
||||
// Create a message listener for each API
|
||||
const handleMessage = apiListenerFactory(FullAPI)
|
||||
|
||||
export function setupAllMsgLstnrs() {
|
||||
browser.runtime.onConnect.removeListener(handleConnect)
|
||||
browser.runtime.onConnect.addListener(handleConnect)
|
||||
|
||||
function handleConnect() {
|
||||
// Merge all API objects into one
|
||||
const FullAPI = Object.assign({}, API_AUTH, API_ANIME, API_HISTORY, API_FAVORITE, API_MOMENT, API_NOTIFICATION, API_RANKING, API_SEARCH, API_USER, API_VIDEO, API_WATCHLATER)
|
||||
// Create a message listener for each API
|
||||
const handleMessage = apiListenerFactory(FullAPI)
|
||||
browser.runtime.onMessage.removeListener(handleMessage)
|
||||
browser.runtime.onMessage.addListener(handleMessage)
|
||||
}
|
||||
}
|
||||
|
||||
function handleConnect() {
|
||||
browser.runtime.onMessage.removeListener(handleMessage)
|
||||
browser.runtime.onMessage.addListener(handleMessage)
|
||||
}
|
||||
|
||||
@@ -10,30 +10,19 @@ const API_MOMENT: APIMAP = {
|
||||
params: {},
|
||||
afterHandle: AHS.J_D,
|
||||
},
|
||||
getTopBarNewMoments: {
|
||||
url: 'https://api.vc.bilibili.com/dynamic_svr/v1/dynamic_svr/dynamic_new',
|
||||
getTopBarMoments: {
|
||||
url: 'https://api.bilibili.com/x/polymer/web-dynamic/v1/feed/nav',
|
||||
_fetch: {
|
||||
method: 'get',
|
||||
},
|
||||
params: {
|
||||
uid: '',
|
||||
type_list: '268435455',
|
||||
type: 'video',
|
||||
update_baseline: '',
|
||||
offset: '',
|
||||
},
|
||||
afterHandle: AHS.J_D,
|
||||
},
|
||||
getTopbarHistoryMoments: {
|
||||
url: 'https://api.vc.bilibili.com/dynamic_svr/v1/dynamic_svr/dynamic_history',
|
||||
_fetch: {
|
||||
method: 'get',
|
||||
},
|
||||
params: {
|
||||
uid: '',
|
||||
type_list: '268435455',
|
||||
offset_dynamic_id: '',
|
||||
},
|
||||
afterHandle: AHS.J_D,
|
||||
},
|
||||
getTopbarLiveMoments: {
|
||||
getTopBarLiveMoments: {
|
||||
url: 'https://api.live.bilibili.com/xlive/web-ucenter/v1/xfetter/FeedList',
|
||||
_fetch: {
|
||||
method: 'get',
|
||||
|
||||
@@ -28,9 +28,8 @@ enum HISTORY {
|
||||
}
|
||||
enum MOMENT {
|
||||
GET_TOP_BAR_NEW_MOMENTS_COUNT = 'getTopBarNewMomentsCount',
|
||||
GET_TOP_BAR_NEW_MOMENTS = 'getTopBarNewMoments',
|
||||
GET_TOP_BAR_HISTORY_MOMENTS = 'getTopbarHistoryMoments',
|
||||
GET_TOP_BAR_LIVE_MOMENTS = 'getTopbarLiveMoments',
|
||||
GET_TOP_BAR_MOMENTS = 'getTopBarMoments',
|
||||
GET_TOP_BAR_LIVE_MOMENTS = 'getTopBarLiveMoments',
|
||||
GET_MOMENTS = 'getMoments',
|
||||
}
|
||||
enum NOTIFICATION {
|
||||
|
||||
@@ -61,7 +61,7 @@ function apiListenerFactory(API_MAP: APIMAP) {
|
||||
const contentScriptQuery = message.contentScriptQuery
|
||||
// 检测是否有contentScriptQuery
|
||||
if (!contentScriptQuery || !API_MAP[contentScriptQuery])
|
||||
return console.error('no contentScriptQuery')
|
||||
return console.error(`Cannot find this contentScriptQuery: ${contentScriptQuery}`)
|
||||
if (API_MAP[contentScriptQuery] instanceof Function)
|
||||
return (API_MAP[contentScriptQuery] as APIFunction)(message, sender, sendResponse)
|
||||
|
||||
|
||||
@@ -85,7 +85,7 @@ const notifications = useDelayedHover({
|
||||
const moments = useDelayedHover({
|
||||
enter: () => {
|
||||
showMomentsPop.value = true
|
||||
momentsPopRef.value && momentsPopRef.value.initData()
|
||||
momentsPopRef.value && momentsPopRef.value.checkIfHasNewMomentsThenUpdateMoments()
|
||||
},
|
||||
leave: () => showMomentsPop.value = false,
|
||||
})
|
||||
@@ -383,7 +383,7 @@ defineExpose({
|
||||
|
||||
<Transition name="slide-in">
|
||||
<ChannelsPop
|
||||
v-if="showChannelsPop"
|
||||
v-show="showChannelsPop"
|
||||
class="bew-popover"
|
||||
pos="!left-0 !top-70px"
|
||||
transform="!translate-x-0"
|
||||
|
||||
@@ -1,43 +1,55 @@
|
||||
<script setup lang="ts">
|
||||
import { useI18n } from 'vue-i18n'
|
||||
import type { Ref } from 'vue'
|
||||
import { onMounted, reactive, ref, watch } from 'vue'
|
||||
import { isNewArticle, isNewVideo, setLastestOffsetID } from '../notify'
|
||||
import { MomentType } from '../types'
|
||||
import type { MomentItem } from '../types'
|
||||
import { getCSRF, getUserID, isHomePage, smoothScrollToTop } from '~/utils/main'
|
||||
import { calcTimeSince } from '~/utils/dataFormatter'
|
||||
|
||||
// import { isNewArticle, setLastOffsetID, setLastestOffsetID } from '../notify'
|
||||
|
||||
import type { TopBarMomentResult } from '~/models/moment/topBarMoment'
|
||||
import type { TopBarLiveMomentResult } from '~/models/moment/topBarLiveMoment'
|
||||
import { getCSRF, isHomePage, smoothScrollToTop } from '~/utils/main'
|
||||
import API from '~/background/msg.define'
|
||||
|
||||
type MomentType = 'video' | 'live' | 'article'
|
||||
interface MomentTab { type: MomentType, name: any }
|
||||
interface MomentCard {
|
||||
type: MomentType
|
||||
title: string
|
||||
author: string
|
||||
authorFace: string
|
||||
pubTime?: string
|
||||
cover: string
|
||||
link: string
|
||||
rid?: number
|
||||
}
|
||||
|
||||
const { t } = useI18n()
|
||||
|
||||
const moments = reactive<MomentItem[]>([])
|
||||
const moments = reactive<MomentCard[]>([])
|
||||
const addedWatchLaterList = reactive<number[]>([])
|
||||
const momentTabs = reactive([
|
||||
const momentTabs = reactive<MomentTab[]>([
|
||||
{
|
||||
id: 0,
|
||||
type: 'video',
|
||||
name: t('topbar.moments_dropdown.tabs.videos'),
|
||||
isSelected: true,
|
||||
},
|
||||
{
|
||||
id: 1,
|
||||
type: 'live',
|
||||
name: t('topbar.moments_dropdown.tabs.live'),
|
||||
isSelected: false,
|
||||
},
|
||||
{
|
||||
id: 2,
|
||||
type: 'article',
|
||||
name: t('topbar.moments_dropdown.tabs.articles'),
|
||||
isSelected: false,
|
||||
},
|
||||
])
|
||||
const selectedTab = ref<number>(0)
|
||||
const selectedMomentTab = ref<MomentTab>(momentTabs[0])
|
||||
const isLoading = ref<boolean>(false)
|
||||
// when noMoreContent is true, the user can't scroll down to load more content
|
||||
const noMoreContent = ref<boolean>(false)
|
||||
const noMoreContent = ref<boolean>(false) // when noMoreContent is true, the user can't scroll down to load more content
|
||||
const livePage = ref<number>(1)
|
||||
const momentsWrap = ref<HTMLElement>() as Ref<HTMLElement>
|
||||
const momentsWrap = ref()
|
||||
const momentUpdateBaseline = ref<string>('')
|
||||
const momentOffset = ref<string>('')
|
||||
const newMomentsCount = ref<number>(0)
|
||||
|
||||
watch(selectedTab, (newVal, oldVal) => {
|
||||
watch(() => selectedMomentTab.value.type, (newVal, oldVal) => {
|
||||
if (newVal === oldVal)
|
||||
return
|
||||
|
||||
@@ -55,205 +67,168 @@ onMounted(() => {
|
||||
>= momentsWrap.value.scrollHeight - 20
|
||||
&& moments.length > 0
|
||||
&& !isLoading.value
|
||||
) {
|
||||
if (selectedTab.value === 0 && !noMoreContent.value)
|
||||
getTopbarHistoryMoments([MomentType.Video, MomentType.Bangumi])
|
||||
else if (selectedTab.value === 1 && !noMoreContent.value)
|
||||
getTopbarLiveMoments(livePage.value)
|
||||
else if (selectedTab.value === 2 && !noMoreContent.value)
|
||||
getTopbarHistoryMoments([MomentType.Article])
|
||||
}
|
||||
)
|
||||
getData()
|
||||
})
|
||||
}
|
||||
})
|
||||
|
||||
function onClickTab(tabId: number) {
|
||||
function onClickTab(tab: MomentTab) {
|
||||
// Prevent changing tab when loading, cuz it will cause a bug
|
||||
if (isLoading.value || tabId === selectedTab.value)
|
||||
if (isLoading.value || tab.type === selectedMomentTab.value.type)
|
||||
return
|
||||
|
||||
selectedTab.value = tabId
|
||||
moments.length = 0
|
||||
momentTabs.forEach((tab) => {
|
||||
tab.isSelected = tab.id === tabId
|
||||
})
|
||||
selectedMomentTab.value = tab
|
||||
initData()
|
||||
}
|
||||
|
||||
async function initData() {
|
||||
if (selectedTab.value === 0) {
|
||||
await getTopBarNewMoments([MomentType.Video, MomentType.Bangumi])
|
||||
}
|
||||
else if (selectedTab.value === 1) {
|
||||
livePage.value = 1
|
||||
getTopbarLiveMoments(livePage.value)
|
||||
}
|
||||
else if (selectedTab.value === 2) {
|
||||
await getTopBarNewMoments([MomentType.Article])
|
||||
}
|
||||
moments.length = 0
|
||||
momentUpdateBaseline.value = ''
|
||||
momentOffset.value = ''
|
||||
newMomentsCount.value = 0
|
||||
livePage.value = 1
|
||||
|
||||
getData()
|
||||
}
|
||||
|
||||
async function getTopBarNewMoments(type_list: number[]) {
|
||||
isLoading.value = true
|
||||
try {
|
||||
const res = await browser.runtime
|
||||
.sendMessage({
|
||||
contentScriptQuery: API.MOMENT.GET_TOP_BAR_NEW_MOMENTS,
|
||||
uid: getUserID(),
|
||||
type_list,
|
||||
})
|
||||
|
||||
if (res.code === 0) {
|
||||
// If there are no new moments, do not change the data to record the scroll position
|
||||
if (moments.length !== 0) {
|
||||
if (res.data.new_num === 0)
|
||||
return
|
||||
}
|
||||
|
||||
moments.length = 0
|
||||
|
||||
if (Array.isArray(res.data.cards) && res.data.cards.length > 0) {
|
||||
res.data.cards.forEach((item: any) => {
|
||||
pushItemIntoMoments(item)
|
||||
})
|
||||
}
|
||||
|
||||
if (moments.length !== 0 && res.data.cards.length < 20) {
|
||||
isLoading.value = false
|
||||
noMoreContent.value = true
|
||||
return
|
||||
}
|
||||
|
||||
// set this lastest offset id, which will clear the new moment's marker point
|
||||
// after you watch these moments.
|
||||
if (selectedTab.value === 0)
|
||||
setLastestOffsetID(MomentType.Video, moments[0].id)
|
||||
else if (selectedTab.value === 2)
|
||||
setLastestOffsetID(MomentType.Article, moments[0].id)
|
||||
|
||||
noMoreContent.value = false
|
||||
}
|
||||
}
|
||||
finally {
|
||||
isLoading.value = false
|
||||
}
|
||||
function getData() {
|
||||
if (selectedMomentTab.value.type !== 'live')
|
||||
getTopBarMoments()
|
||||
else
|
||||
getTopBarLiveMoments()
|
||||
}
|
||||
|
||||
function getTopbarHistoryMoments(type_list: number[]) {
|
||||
isLoading.value = true
|
||||
browser.runtime
|
||||
.sendMessage({
|
||||
contentScriptQuery: API.MOMENT.GET_TOP_BAR_HISTORY_MOMENTS,
|
||||
uid: getUserID(),
|
||||
type_list,
|
||||
offset_dynamic_id: moments[moments.length - 1].dynamic_id_str,
|
||||
})
|
||||
.then((res) => {
|
||||
function checkIfHasNewMomentsThenUpdateMoments() {
|
||||
if (selectedMomentTab.value.type === 'live')
|
||||
return
|
||||
|
||||
browser.runtime.sendMessage({
|
||||
contentScriptQuery: API.MOMENT.GET_TOP_BAR_MOMENTS,
|
||||
type: selectedMomentTab.value.type,
|
||||
update_baseline: momentUpdateBaseline.value || undefined,
|
||||
})
|
||||
.then((res: TopBarMomentResult) => {
|
||||
if (res.code === 0) {
|
||||
if (res.data.has_more === 0) {
|
||||
isLoading.value = false
|
||||
const { has_more, items, update_baseline, update_num } = res.data
|
||||
|
||||
if (!has_more) {
|
||||
noMoreContent.value = true
|
||||
return
|
||||
}
|
||||
if (update_num === 0)
|
||||
return
|
||||
|
||||
for (let i = update_num - 1; i >= 0; i--) {
|
||||
moments.unshift({
|
||||
type: selectedMomentTab.value.type,
|
||||
title: items[i].title,
|
||||
author: items[i].author.name,
|
||||
authorFace: items[i].author.face,
|
||||
pubTime: items[i].pub_time,
|
||||
cover: items[i].cover,
|
||||
link: items[i].jump_url,
|
||||
rid: items[i].rid,
|
||||
})
|
||||
}
|
||||
|
||||
newMomentsCount.value = update_num
|
||||
momentUpdateBaseline.value = update_baseline
|
||||
// newMomentsCount.value = update_num
|
||||
// setLastOffsetID('video', offset)
|
||||
}
|
||||
})
|
||||
.finally(() => isLoading.value = false)
|
||||
}
|
||||
|
||||
function getTopBarMoments() {
|
||||
if (isLoading.value)
|
||||
return
|
||||
isLoading.value = true
|
||||
browser.runtime.sendMessage({
|
||||
contentScriptQuery: API.MOMENT.GET_TOP_BAR_MOMENTS,
|
||||
type: selectedMomentTab.value.type,
|
||||
update_baseline: momentUpdateBaseline.value || undefined,
|
||||
offset: momentOffset.value || undefined,
|
||||
})
|
||||
.then((res: TopBarMomentResult) => {
|
||||
if (res.code === 0) {
|
||||
const { has_more, items, offset, update_baseline, update_num } = res.data
|
||||
|
||||
if (!has_more) {
|
||||
noMoreContent.value = true
|
||||
return
|
||||
}
|
||||
|
||||
res.data.cards.forEach((item: any) => {
|
||||
pushItemIntoMoments(item)
|
||||
})
|
||||
noMoreContent.value = false
|
||||
newMomentsCount.value = update_num
|
||||
momentUpdateBaseline.value = update_baseline
|
||||
momentOffset.value = offset
|
||||
|
||||
// set this lastest offset id, which will clear the new moment's marker point
|
||||
// after you watch these moments.
|
||||
|
||||
// setLastOffsetID('video', offset)
|
||||
|
||||
moments.push(
|
||||
...items.map(item => ({
|
||||
type: selectedMomentTab.value.type,
|
||||
title: item.title,
|
||||
author: item.author.name,
|
||||
authorFace: item.author.face,
|
||||
pubTime: item.pub_time,
|
||||
cover: item.cover,
|
||||
link: item.jump_url,
|
||||
rid: item.rid,
|
||||
}),
|
||||
),
|
||||
)
|
||||
}
|
||||
isLoading.value = false
|
||||
})
|
||||
.finally(() => isLoading.value = false)
|
||||
}
|
||||
|
||||
function getTopbarLiveMoments(page: number) {
|
||||
function isNewMoment(index: number) {
|
||||
return index < newMomentsCount.value
|
||||
}
|
||||
|
||||
function getTopBarLiveMoments() {
|
||||
isLoading.value = true
|
||||
browser.runtime
|
||||
.sendMessage({
|
||||
contentScriptQuery: API.MOMENT.GET_TOP_BAR_LIVE_MOMENTS,
|
||||
page,
|
||||
page: livePage.value,
|
||||
pagesize: 10,
|
||||
})
|
||||
.then((res) => {
|
||||
.then((res: TopBarLiveMomentResult) => {
|
||||
if (res.code === 0) {
|
||||
// if the length of this list is less then the pageSize, it means that it have no more contents
|
||||
if (moments.length !== 0 && res.data.list.length < 10) {
|
||||
isLoading.value = false
|
||||
noMoreContent.value = true
|
||||
const { list, pagesize } = res.data
|
||||
|
||||
// if the length of this list is less then the pageSize, it means that it have no more contents
|
||||
if (moments.length !== 0 && list.length < Number(pagesize)) {
|
||||
noMoreContent.value = true
|
||||
return
|
||||
}
|
||||
|
||||
// if the length of this list is equal to the pageSize, this means that it may have the next page.
|
||||
if (res.data.list.length === 10)
|
||||
if (list.length === Number(pagesize))
|
||||
livePage.value++
|
||||
res.data.list.forEach((item: any) => {
|
||||
moments.push({
|
||||
id: item.roomid,
|
||||
uid: item.uid,
|
||||
name: item.uname,
|
||||
face: item.face,
|
||||
url: item.link,
|
||||
|
||||
moments.push(
|
||||
...list.map(item => ({
|
||||
type: selectedMomentTab.value.type,
|
||||
title: item.title,
|
||||
author: item.uname,
|
||||
authorFace: item.face,
|
||||
cover: item.pic,
|
||||
} as MomentItem)
|
||||
})
|
||||
link: item.link,
|
||||
}),
|
||||
),
|
||||
)
|
||||
|
||||
noMoreContent.value = false
|
||||
}
|
||||
isLoading.value = false
|
||||
})
|
||||
}
|
||||
|
||||
function pushItemIntoMoments(item: any) {
|
||||
const card = JSON.parse(item.card)
|
||||
|
||||
if (item.desc.type === MomentType.Video) {
|
||||
// if this is a video moment
|
||||
moments.push({
|
||||
type: item.desc.type,
|
||||
id: item.desc.dynamic_id,
|
||||
uid: item.desc.uid,
|
||||
name: item.desc.user_profile.info.uname,
|
||||
face: item.desc.user_profile.info.face,
|
||||
aid: card.aid,
|
||||
bvid: item.desc.bvid,
|
||||
url: card.short_link_v2 || `https://www.bilibili.com/video/${item.desc.bvid}`,
|
||||
ctime: card.ctime,
|
||||
title: card.title,
|
||||
cover: card.pic,
|
||||
dynamic_id_str: item.desc.dynamic_id_str,
|
||||
isNew: isNewVideo(item.desc.dynamic_id),
|
||||
} as MomentItem)
|
||||
}
|
||||
else if (item.desc.type === MomentType.Bangumi) {
|
||||
// bangumi moment
|
||||
moments.push({
|
||||
type: item.desc.type,
|
||||
id: item.desc.dynamic_id,
|
||||
name: card.apiSeasonInfo.title,
|
||||
face: card.apiSeasonInfo.cover,
|
||||
episode_id: card.episode_id,
|
||||
url: card.url,
|
||||
title: card.new_desc,
|
||||
cover: card.cover,
|
||||
dynamic_id_str: item.desc.dynamic_id_str,
|
||||
isNew: isNewVideo(item.desc.dynamic_id),
|
||||
} as MomentItem)
|
||||
}
|
||||
else if (item.desc.type === MomentType.Article) {
|
||||
// article moment
|
||||
moments.push({
|
||||
type: item.desc.type,
|
||||
id: item.desc.dynamic_id,
|
||||
uid: item.desc.uid,
|
||||
name: item.desc.user_profile.info.uname,
|
||||
face: item.desc.user_profile.info.face,
|
||||
url: `https://www.bilibili.com/read/cv${card.id}`,
|
||||
ctime: card.publish_time,
|
||||
title: card.title,
|
||||
cover: card.image_urls[0],
|
||||
dynamic_id_str: item.desc.dynamic_id_str,
|
||||
isNew: isNewArticle(item.desc.dynamic_id),
|
||||
} as MomentItem)
|
||||
}
|
||||
.finally(() => isLoading.value = false)
|
||||
}
|
||||
|
||||
function toggleWatchLater(aid: number) {
|
||||
@@ -286,7 +261,7 @@ function toggleWatchLater(aid: number) {
|
||||
}
|
||||
|
||||
defineExpose({
|
||||
initData,
|
||||
checkIfHasNewMomentsThenUpdateMoments,
|
||||
})
|
||||
</script>
|
||||
|
||||
@@ -314,13 +289,13 @@ defineExpose({
|
||||
<div flex="~">
|
||||
<div
|
||||
v-for="tab in momentTabs"
|
||||
:key="tab.id"
|
||||
:key="tab.type"
|
||||
m="r-4"
|
||||
transition="all duration-300"
|
||||
class="tab"
|
||||
:class="tab.isSelected ? 'tab-selected' : ''"
|
||||
:class="tab.type === selectedMomentTab.type ? 'tab-selected' : ''"
|
||||
cursor="pointer"
|
||||
@click="onClickTab(tab.id)"
|
||||
@click="onClickTab(tab)"
|
||||
>
|
||||
{{ tab.name }}
|
||||
</div>
|
||||
@@ -354,11 +329,12 @@ defineExpose({
|
||||
/>
|
||||
|
||||
<!-- moments -->
|
||||
|
||||
<TransitionGroup name="list">
|
||||
<a
|
||||
v-for="(moment, index) in moments"
|
||||
:key="index"
|
||||
:href="moment.url" :target="isHomePage() ? '_blank' : '_self'" rel="noopener noreferrer"
|
||||
:href="moment.link" :target="isHomePage() ? '_blank' : '_self'" rel="noopener noreferrer"
|
||||
flex="~ justify-between"
|
||||
m="b-2 first:t-50px" p="2"
|
||||
rounded="$bew-radius"
|
||||
@@ -368,7 +344,7 @@ defineExpose({
|
||||
>
|
||||
<!-- new moment dot -->
|
||||
<div
|
||||
v-if="moment.isNew"
|
||||
v-if="isNewMoment(index)"
|
||||
rounded="full"
|
||||
w="8px"
|
||||
h="8px"
|
||||
@@ -377,17 +353,12 @@ defineExpose({
|
||||
pos="absolute -top-12px -left-12px"
|
||||
style="box-shadow: 0 0 4px var(--bew-theme-color)"
|
||||
/>
|
||||
|
||||
<a
|
||||
:href="
|
||||
moment.type === MomentType.Video
|
||||
? `https://space.bilibili.com/${moment.uid}`
|
||||
: moment.url
|
||||
"
|
||||
:href="moment.link"
|
||||
:target="isHomePage() ? '_blank' : '_self'" rel="noopener noreferrer"
|
||||
>
|
||||
<img
|
||||
:src="`${moment.face}@50w_50h_1c`"
|
||||
:src="`${moment.authorFace}@50w_50h_1c`"
|
||||
rounded="1/2"
|
||||
w="40px"
|
||||
h="40px"
|
||||
@@ -399,27 +370,22 @@ defineExpose({
|
||||
<div>
|
||||
<!-- <span v-if="selectedTab !== 1">{{ `${moment.name} ${t('topbar.moments_dropdown.uploaded')}` }}</span> -->
|
||||
<!-- <span v-else>{{ `${moment.name} ${t('topbar.moments_dropdown.now_streaming')}` }}</span> -->
|
||||
<span font-bold>{{ moment.name }}</span>
|
||||
<span font-bold>{{ moment.author }}</span>
|
||||
<div overflow-hidden text-ellipsis break-anywhere>
|
||||
{{ moment.title }}
|
||||
</div>
|
||||
<div
|
||||
v-if="moment.type !== MomentType.Bangumi"
|
||||
text="$bew-text-2 sm"
|
||||
m="y-2"
|
||||
>
|
||||
<!-- Videos and articles -->
|
||||
<div v-if="selectedTab === 0 || selectedTab === 2">
|
||||
{{
|
||||
moment.ctime
|
||||
? calcTimeSince(new Date(moment.ctime * 1000))
|
||||
: moment.ctime
|
||||
}}
|
||||
<!-- publish time -->
|
||||
<div v-if="selectedMomentTab.type !== 'live'">
|
||||
{{ moment.pubTime }}
|
||||
</div>
|
||||
|
||||
<!-- Live -->
|
||||
<div
|
||||
v-else-if="selectedTab === 1"
|
||||
v-else
|
||||
text="$bew-theme-color"
|
||||
font="bold"
|
||||
flex="~"
|
||||
@@ -442,14 +408,14 @@ defineExpose({
|
||||
rounded="$bew-radius-half"
|
||||
>
|
||||
<div
|
||||
v-if="moment.type === MomentType.Video"
|
||||
|
||||
opacity-0 group-hover:opacity-100
|
||||
pos="absolute" duration-300 bg="black opacity-60"
|
||||
rounded="$bew-radius-half" p-1
|
||||
z-1 color-white
|
||||
@click.prevent="toggleWatchLater(moment.aid ?? 0)"
|
||||
@click.prevent="toggleWatchLater(moment.rid || 0)"
|
||||
>
|
||||
<Tooltip v-if="!addedWatchLaterList.includes(moment.aid ?? 0)" :content="$t('common.save_to_watch_later')" placement="bottom" type="dark">
|
||||
<Tooltip v-if="!addedWatchLaterList.includes(moment.rid || 0)" :content="$t('common.save_to_watch_later')" placement="bottom" type="dark">
|
||||
<mingcute:carplay-line />
|
||||
</Tooltip>
|
||||
<Tooltip v-else :content="$t('common.added')" placement="bottom" type="dark">
|
||||
|
||||
@@ -1,30 +1,29 @@
|
||||
import { MomentType } from './types'
|
||||
import { getCookie, getUserID, setCookie } from '~/utils/main'
|
||||
// https://github.dev/the1812/Bilibili-Evolved/blob/8a4e422612a7bd0b42da9aa50c21c7bf3ea401b8/src/components/feeds/notify.ts#L1
|
||||
|
||||
// import { getCookie, getUserID, setCookie } from '~/utils/main'
|
||||
|
||||
/** Update the time interval of topbar notifications and moments counts */
|
||||
export const updateInterval = 1000 * 60 * 5 // Updated every 5 minutes
|
||||
|
||||
const getVideoOffsetID = (): number => Number.parseInt(`${getCookie(`bp_video_offset_${getUserID()}`)}`, 10) || 0
|
||||
const getArticleOffsetID = (): number => Number.parseInt(`${getCookie(`bp_article_offset_${getUserID()}`)}`, 10) || 0
|
||||
// const getLastID = (): string => `${getCookie(`bp_t_offset_${getUserID()}`)}`
|
||||
|
||||
function compareOffsetID(currentOffsetID: number, lastestOffsetID: number): boolean {
|
||||
if (currentOffsetID === lastestOffsetID)
|
||||
return false
|
||||
else if (currentOffsetID > lastestOffsetID)
|
||||
return true
|
||||
else
|
||||
return false
|
||||
}
|
||||
// function compareID(currentID: string, lastOffsetID: string): boolean {
|
||||
// if (currentID === lastOffsetID)
|
||||
// return false
|
||||
// else if (Number(currentID) > Number(lastOffsetID))
|
||||
// return true
|
||||
// else
|
||||
// return false
|
||||
// }
|
||||
|
||||
export function setLastestOffsetID(type: MomentType, offsetID: number) {
|
||||
if (offsetID === null || offsetID === undefined)
|
||||
return
|
||||
// export function setLastId(id: string) {
|
||||
// if (id === null || id === undefined)
|
||||
// return
|
||||
|
||||
if (type === MomentType.Video || type === MomentType.Bangumi)
|
||||
setCookie(`bp_video_offset_${getUserID()}`, offsetID.toString(), 30)
|
||||
else if (type === MomentType.Article)
|
||||
setCookie(`bp_article_offset_${getUserID()}`, offsetID.toString(), 30)
|
||||
}
|
||||
// if (compareID(id))
|
||||
// return
|
||||
|
||||
export const isNewVideo = (currentOffsetID: number): boolean => compareOffsetID(currentOffsetID, getVideoOffsetID())
|
||||
export const isNewArticle = (currentOffsetID: number): boolean => compareOffsetID(currentOffsetID, getArticleOffsetID())
|
||||
// setCookie(`bp_t_offset_${getUserID()}`, id, 30)
|
||||
// }
|
||||
|
||||
// export const isNewId = (id: string): boolean => compareID(id, getLastID())
|
||||
|
||||
@@ -58,23 +58,6 @@ export enum MomentType {
|
||||
Documentary = 4101,
|
||||
}
|
||||
|
||||
export interface MomentItem {
|
||||
type?: MomentType
|
||||
id: number
|
||||
uid: number
|
||||
name: string
|
||||
face: string
|
||||
aid?: number
|
||||
bvid?: string
|
||||
episode_id?: number
|
||||
url: string
|
||||
ctime?: number
|
||||
title: string
|
||||
cover: string
|
||||
dynamic_id_str?: string
|
||||
isNew: boolean
|
||||
}
|
||||
|
||||
// https://github.com/SocialSisterYi/bilibili-API-collect/blob/master/docs/history&toview/history.md#%E8%8E%B7%E5%8F%96%E5%8E%86%E5%8F%B2%E8%AE%B0%E5%BD%95%E5%88%97%E8%A1%A8_web%E7%AB%AF
|
||||
export enum HistoryType {
|
||||
Archive = 'archive', // archive:稿件
|
||||
|
||||
29
src/models/moment/topBarLiveMoment.ts
Normal file
29
src/models/moment/topBarLiveMoment.ts
Normal file
@@ -0,0 +1,29 @@
|
||||
// https://app.quicktype.io/?l=ts
|
||||
|
||||
export interface TopBarLiveMomentResult {
|
||||
code: number
|
||||
message: string
|
||||
ttl: number
|
||||
data: Data
|
||||
}
|
||||
|
||||
export interface Data {
|
||||
results: number
|
||||
page: string
|
||||
pagesize: string
|
||||
list: List[]
|
||||
}
|
||||
|
||||
export interface List {
|
||||
cover: string
|
||||
face: string
|
||||
uname: string
|
||||
title: string
|
||||
roomid: number
|
||||
pic: string
|
||||
online: number
|
||||
link: string
|
||||
uid: number
|
||||
parent_area_id: number
|
||||
area_id: number
|
||||
}
|
||||
108
src/models/moment/topBarMoment.ts
Normal file
108
src/models/moment/topBarMoment.ts
Normal file
@@ -0,0 +1,108 @@
|
||||
// https://app.quicktype.io/?l=ts
|
||||
|
||||
export interface TopBarMomentResult {
|
||||
code: number
|
||||
message: string
|
||||
ttl: number
|
||||
data: Data
|
||||
}
|
||||
|
||||
export interface Data {
|
||||
has_more: boolean
|
||||
items: Item[]
|
||||
offset: string
|
||||
update_baseline: string
|
||||
update_num: number
|
||||
}
|
||||
|
||||
export interface Item {
|
||||
author: Author
|
||||
cover: string
|
||||
id_str: string
|
||||
jump_url: string
|
||||
pub_time: string
|
||||
rid: number
|
||||
title: string
|
||||
type: number
|
||||
visible: boolean
|
||||
}
|
||||
|
||||
export interface Author {
|
||||
face: string
|
||||
jump_url: string
|
||||
mid: number
|
||||
name: string
|
||||
official: Official
|
||||
vip: Vip
|
||||
}
|
||||
|
||||
export interface Official {
|
||||
desc: string
|
||||
role: number
|
||||
title: string
|
||||
type: number
|
||||
}
|
||||
|
||||
export interface Vip {
|
||||
avatar_icon: AvatarIcon
|
||||
avatar_subscript: number
|
||||
avatar_subscript_url: string
|
||||
due_date: number
|
||||
label: Label
|
||||
nickname_color: Color
|
||||
role: number
|
||||
status: number
|
||||
theme_type: number
|
||||
tv_due_date: number
|
||||
tv_vip_pay_type: number
|
||||
tv_vip_status: number
|
||||
type: number
|
||||
vip_pay_type: number
|
||||
}
|
||||
|
||||
export interface AvatarIcon {
|
||||
icon_resource: IconResource
|
||||
icon_type?: number
|
||||
}
|
||||
|
||||
export interface IconResource {
|
||||
type?: number
|
||||
url?: string
|
||||
}
|
||||
|
||||
export interface Label {
|
||||
bg_color: Color
|
||||
bg_style: number
|
||||
border_color: string
|
||||
img_label_uri_hans: string
|
||||
img_label_uri_hans_static: string
|
||||
img_label_uri_hant: string
|
||||
img_label_uri_hant_static: string
|
||||
label_theme: LabelTheme
|
||||
path: string
|
||||
text: Text
|
||||
text_color: TextColor
|
||||
use_img_label: boolean
|
||||
}
|
||||
|
||||
export enum Color {
|
||||
Empty = '',
|
||||
Fb7299 = '#FB7299',
|
||||
}
|
||||
|
||||
export enum LabelTheme {
|
||||
AnnualVip = 'annual_vip',
|
||||
Empty = '',
|
||||
Vip = 'vip',
|
||||
}
|
||||
|
||||
export enum Text {
|
||||
Empty = '',
|
||||
大会员 = '大会员',
|
||||
年度大会员 = '年度大会员',
|
||||
}
|
||||
|
||||
export enum TextColor {
|
||||
Empty = '',
|
||||
Ffffff = '#FFFFFF',
|
||||
}
|
||||
Reference in New Issue
Block a user