mirror of
https://github.com/BewlyBewly/BewlyBewly.git
synced 2025-04-14 13:15:29 +00:00
chore: just wanna push some code...
This commit is contained in:
@@ -1,9 +1,23 @@
|
||||
<script setup lang="ts">
|
||||
import RecommendContent from './components/RecommendContent.vue'
|
||||
import Following from './components/Following.vue'
|
||||
import emitter from '~/utils/mitt'
|
||||
import { settings } from '~/logic'
|
||||
|
||||
const recommendContentKey = ref<string>(`recommendContent${Number(new Date())}`)
|
||||
const activatedPage = ref<'RecommendContent' | 'Following'>('RecommendContent')
|
||||
const pages = { RecommendContent, Following }
|
||||
|
||||
const tabs = reactive<{ label: string; value: 'RecommendContent' | 'Following' }[]>([
|
||||
{
|
||||
label: 'For you',
|
||||
value: 'RecommendContent',
|
||||
},
|
||||
{
|
||||
label: 'Following',
|
||||
value: 'Following',
|
||||
},
|
||||
])
|
||||
|
||||
onMounted(() => {
|
||||
emitter.off('pageRefresh')
|
||||
@@ -39,8 +53,21 @@ onUnmounted(() => {
|
||||
:focused-character="settings.searchPageSearchBarFocusCharacter"
|
||||
/>
|
||||
</div>
|
||||
|
||||
<RecommendContent :key="recommendContentKey" />
|
||||
<header pos="sticky top-70px" z-10 mb-4>
|
||||
<ul flex="~ items-center gap-2">
|
||||
<li
|
||||
v-for="tab in tabs" :key="tab.value"
|
||||
px-4 lh-40px bg="$bew-elevated-2" backdrop-glass rounded="$bew-radius"
|
||||
cursor-pointer shadow="$bew-shadow-2"
|
||||
:style="{ backgroundColor: activatedPage === tab.value ? 'var(--bew-theme-color)' : null }"
|
||||
@click="activatedPage = tab.value"
|
||||
>
|
||||
{{ tab.label }}
|
||||
</li>
|
||||
</ul>
|
||||
</header>
|
||||
<Component :is="pages[activatedPage]" :key="recommendContentKey" />
|
||||
<!-- <RecommendContent :key="recommendContentKey" /> -->
|
||||
</div>
|
||||
</template>
|
||||
|
||||
|
||||
163
src/contentScripts/views/Home/components/Following.vue
Normal file
163
src/contentScripts/views/Home/components/Following.vue
Normal file
@@ -0,0 +1,163 @@
|
||||
<script setup lang="ts">
|
||||
import type { Ref } from 'vue'
|
||||
import type { AppVideoModel, VideoModel } from './types'
|
||||
import emitter from '~/utils/mitt'
|
||||
import { settings } from '~/logic'
|
||||
|
||||
const videoList = reactive<VideoModel[]>([])
|
||||
const appVideoList = reactive<AppVideoModel[]>([])
|
||||
const isLoading = ref<boolean>(false)
|
||||
const needToLoginFirst = ref<boolean>(false)
|
||||
const containerRef = ref<HTMLElement>() as Ref<HTMLElement>
|
||||
const offset = ref<string>()
|
||||
const updateBaseline = ref<string>()
|
||||
|
||||
watch(() => settings.value.recommendationMode, (newValue, oldValue) => {
|
||||
videoList.length = 0
|
||||
appVideoList.length = 0
|
||||
if (newValue === 'web')
|
||||
getRecommendVideos()
|
||||
})
|
||||
|
||||
onMounted(async () => {
|
||||
// Delay by 0.2 seconds to obtain the `settings.value.recommendationMode` value
|
||||
// otherwise the `settings.value.recommendationMode` value will be undefined
|
||||
// i have no idea to fix that...
|
||||
setTimeout(async () => {
|
||||
getRecommendVideos()
|
||||
}, 200)
|
||||
|
||||
emitter.off('reachBottom')
|
||||
emitter.on('reachBottom', async () => {
|
||||
if (!isLoading.value)
|
||||
getRecommendVideos()
|
||||
})
|
||||
})
|
||||
|
||||
onUnmounted(() => {
|
||||
emitter.off('reachBottom')
|
||||
})
|
||||
|
||||
async function getRecommendVideos() {
|
||||
isLoading.value = true
|
||||
try {
|
||||
const response = await browser.runtime.sendMessage({
|
||||
contentScriptQuery: 'getMoments',
|
||||
type: 'video',
|
||||
offset: offset.value,
|
||||
updateBaseline: updateBaseline.value,
|
||||
})
|
||||
|
||||
if (response.code === 0) {
|
||||
const resData = [] as VideoModel[]
|
||||
|
||||
response.data.item.forEach((item: VideoModel) => {
|
||||
resData.push(item)
|
||||
})
|
||||
|
||||
// when videoList has length property, it means it is the first time to load
|
||||
if (!videoList.length) {
|
||||
Object.assign(videoList, resData)
|
||||
}
|
||||
else {
|
||||
// else we concat the new data to the old data
|
||||
Object.assign(videoList, videoList.concat(resData))
|
||||
}
|
||||
}
|
||||
else if (response.code === 62011) {
|
||||
needToLoginFirst.value = true
|
||||
}
|
||||
}
|
||||
finally {
|
||||
isLoading.value = false
|
||||
}
|
||||
}
|
||||
|
||||
function jumpToLoginPage() {
|
||||
location.href = 'https://passport.bilibili.com/login'
|
||||
}
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<div>
|
||||
<Empty v-if="needToLoginFirst" mt-6 :description="$t('common.please_log_in_first')">
|
||||
<Button type="primary" @click="jumpToLoginPage()">
|
||||
{{ $t('common.login') }}
|
||||
</Button>
|
||||
</Empty>
|
||||
<div
|
||||
v-else
|
||||
ref="containerRef"
|
||||
m="b-0 t-0" relative w-full h-full
|
||||
grid="~ 2xl:cols-5 xl:cols-4 lg:cols-3 md:cols-2 gap-4"
|
||||
>
|
||||
<template v-if="settings.recommendationMode === 'web'">
|
||||
<VideoCard
|
||||
v-for="video in videoList"
|
||||
:id="video.id"
|
||||
:key="video.id"
|
||||
:duration="video.duration"
|
||||
:title="video.title"
|
||||
:cover="video.pic"
|
||||
:author="video.owner.name"
|
||||
:author-face="video.owner.face"
|
||||
:mid="video.owner.mid"
|
||||
:view="video.stat.view"
|
||||
:danmaku="video.stat.danmaku"
|
||||
:published-timestamp="video.pubdate"
|
||||
:bvid="video.bvid"
|
||||
/>
|
||||
</template>
|
||||
<template v-else>
|
||||
<VideoCard
|
||||
v-for="video in appVideoList"
|
||||
:id="video.args.aid"
|
||||
:key="video.args.aid"
|
||||
:duration-str="video.cover_right_text"
|
||||
:title="video.title"
|
||||
:cover="video.cover"
|
||||
:author="'avatar' in video.mask ? video.mask.avatar.text : ''"
|
||||
:author-face="'avatar' in video.mask ? video.mask.avatar.cover : ''"
|
||||
:mid="video.mask.avatar.up_id"
|
||||
:capsule-text="video.desc.split('·')[1]"
|
||||
:bvid="video.bvid"
|
||||
:view-str="video.cover_left_text_1"
|
||||
:danmaku-str="video.cover_left_text_2"
|
||||
/>
|
||||
</template>
|
||||
|
||||
<!-- skeleton -->
|
||||
<template v-for="item in 30" :key="item">
|
||||
<div
|
||||
v-if="isLoading"
|
||||
mb-8 pointer-events-none select-none
|
||||
>
|
||||
<div aspect-video bg="$bew-fill-4" rounded="$bew-radius" />
|
||||
<div flex mt-4>
|
||||
<div m="r-4" w="40px" h="40px" rounded="1/2" bg="$bew-fill-4" shrink-0 />
|
||||
<div w-full>
|
||||
<div grid gap-2>
|
||||
<div w-full h-5 bg="$bew-fill-3" />
|
||||
<div w="3/4" h-5 bg="$bew-fill-3" />
|
||||
</div>
|
||||
<div grid gap-2 mt-4>
|
||||
<div w="50%" h-4 bg="$bew-fill-2" />
|
||||
<div w="80%" h-4 bg="$bew-fill-2" />
|
||||
</div>
|
||||
<div text="transparent sm" inline-block mt-4 p="x-2 y-1" bg="$bew-fill-1" rounded-4>
|
||||
hello world
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
</div>
|
||||
|
||||
<Transition name="fade">
|
||||
<Loading v-if="isLoading" />
|
||||
</Transition>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
</style>
|
||||
@@ -104,3 +104,200 @@ export interface AppVideoModel {
|
||||
cover_left_icon_1: number
|
||||
cover_left_icon_2: number
|
||||
}
|
||||
|
||||
export interface MomentModel {
|
||||
|
||||
'basic': {
|
||||
'comment_id_str': string
|
||||
'comment_type': 1
|
||||
'like_icon': {
|
||||
'action_url': string
|
||||
'end_url': string
|
||||
'id': 0
|
||||
'start_url': string
|
||||
}
|
||||
'rid_str': string
|
||||
}
|
||||
'id_str': string
|
||||
'modules': {
|
||||
'module_author': {
|
||||
'avatar': {
|
||||
'container_size': {
|
||||
'height': 1.35
|
||||
'width': 1.35
|
||||
}
|
||||
'fallback_layers': {
|
||||
'is_critical_group': true
|
||||
'layers': [
|
||||
{
|
||||
'general_spec': {
|
||||
'pos_spec': {
|
||||
'axis_x': 0.675
|
||||
'axis_y': 0.675
|
||||
'coordinate_pos': 2
|
||||
}
|
||||
'render_spec': {
|
||||
'opacity': 1
|
||||
}
|
||||
'size_spec': {
|
||||
'height': 1
|
||||
'width': 1
|
||||
}
|
||||
}
|
||||
'layer_config': {
|
||||
'is_critical': true
|
||||
'tags': {
|
||||
'AVATAR_LAYER': {}
|
||||
'GENERAL_CFG': {
|
||||
'config_type': 1
|
||||
'general_config': {
|
||||
'web_css_style': {
|
||||
'borderRadius': '50%'
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
'resource': {
|
||||
'res_image': {
|
||||
'image_src': {
|
||||
'placeholder': 6
|
||||
'remote': {
|
||||
'bfs_style': string
|
||||
'url': string
|
||||
}
|
||||
'src_type': 1
|
||||
}
|
||||
}
|
||||
'res_type': 3
|
||||
}
|
||||
'visible': true
|
||||
},
|
||||
{
|
||||
'general_spec': {
|
||||
'pos_spec': {
|
||||
'axis_x': 0.8000000000000002
|
||||
'axis_y': 0.8000000000000002
|
||||
'coordinate_pos': 1
|
||||
}
|
||||
'render_spec': {
|
||||
'opacity': 1
|
||||
}
|
||||
'size_spec': {
|
||||
'height': 0.41666666666666663
|
||||
'width': 0.41666666666666663
|
||||
}
|
||||
}
|
||||
'layer_config': {
|
||||
'tags': {
|
||||
'GENERAL_CFG': {
|
||||
'config_type': 1
|
||||
'general_config': {
|
||||
'web_css_style': {
|
||||
'background-color': 'rgb(255,255,255)'
|
||||
'border': '2px solid rgba(255,255,255,1)'
|
||||
'borderRadius': '50%'
|
||||
'boxSizing': 'border-box'
|
||||
}
|
||||
}
|
||||
}
|
||||
'ICON_LAYER': {}
|
||||
}
|
||||
}
|
||||
'resource': {
|
||||
'res_image': {
|
||||
'image_src': {
|
||||
'local': 4
|
||||
'src_type': 2
|
||||
}
|
||||
}
|
||||
'res_type': 3
|
||||
}
|
||||
'visible': true
|
||||
},
|
||||
]
|
||||
}
|
||||
'mid': '928123'
|
||||
}
|
||||
'face': string
|
||||
'face_nft': false
|
||||
'following': true
|
||||
'jump_url': string
|
||||
'label': string
|
||||
'mid': 928123
|
||||
'name': string
|
||||
'official_verify': {
|
||||
'desc': string
|
||||
'type': 1
|
||||
}
|
||||
'pendant': {
|
||||
'expire': 0
|
||||
'image': string
|
||||
'image_enhance': string
|
||||
'image_enhance_frame': string
|
||||
'name': string
|
||||
'pid': 0
|
||||
}
|
||||
'pub_action': string
|
||||
'pub_location_text': string
|
||||
'pub_time': string
|
||||
'pub_ts': 1696609801
|
||||
'type': string
|
||||
}
|
||||
'module_dynamic': {
|
||||
'additional': null
|
||||
'desc': null
|
||||
'major': {
|
||||
'archive': {
|
||||
'aid': string
|
||||
'badge': {
|
||||
'bg_color': '#FB7299'
|
||||
'color': '#FFFFFF'
|
||||
'icon_url': null
|
||||
'text': '投稿视频'
|
||||
}
|
||||
'bvid': 'BV13w411y7E7'
|
||||
'cover': 'http://i0.hdslb.com/bfs/archive/15757cde3114b8f19d74ced14ba0694ce20ba1d8.png'
|
||||
'desc': '#14'
|
||||
'disable_preview': 0
|
||||
'duration_text': '23:37'
|
||||
'jump_url': '//www.bilibili.com/video/BV13w411y7E7/'
|
||||
'stat': {
|
||||
'danmaku': '16'
|
||||
'play': '2707'
|
||||
}
|
||||
'title': '【7月】主宰七魔剑 14【独家正版】'
|
||||
'type': 1
|
||||
}
|
||||
'type': 'MAJOR_TYPE_ARCHIVE'
|
||||
}
|
||||
'topic': null
|
||||
}
|
||||
'module_more': {
|
||||
'three_point_items': [
|
||||
{
|
||||
'label': string
|
||||
'type': string
|
||||
},
|
||||
]
|
||||
}
|
||||
'module_stat': {
|
||||
'comment': {
|
||||
'count': 12
|
||||
'forbidden': false
|
||||
}
|
||||
'forward': {
|
||||
'count': 0
|
||||
'forbidden': false
|
||||
}
|
||||
'like': {
|
||||
'count': 250
|
||||
'forbidden': false
|
||||
'status': false
|
||||
}
|
||||
}
|
||||
}
|
||||
'type': 'DYNAMIC_TYPE_AV'
|
||||
'visible': true
|
||||
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user