feat: implement all features for ranking page

This commit is contained in:
Hakadao
2023-10-20 00:20:43 +08:00
parent ef55debeb8
commit d595f04555
8 changed files with 113 additions and 50 deletions

View File

@@ -6,6 +6,7 @@ common:
viewWithoutNum:
danmaku: '{count} 弹幕'
danmakuWithoutNum: 弹幕
anime_follow_count: '{count}人关注'
year: 年前
month: 个月前
week: 个星期前
@@ -133,7 +134,7 @@ topbar:
logo_dropdown:
anime: 番剧
movies: 电影
chinese_anime: 国创
chinese_anime: 中国动画
tv_shows: 电视剧
variety_shows: 综艺
documentary_films: 纪录片
@@ -211,6 +212,11 @@ home:
not_interested_in: 对哪方面不感兴趣?
video_removed: 视频已移除
save_to_watch_later: 添加到稍后再看
ranking:
all: 全部
chinese_anime_related: 中国动画相关
original_content: 原创内容
debut_work: 新人作品
anime:
total_episodes: 全 {ep} 话
update_to_n_episodes: 更新至 {ep} 话

View File

@@ -6,6 +6,7 @@ common:
viewWithoutNum:
danmaku: '{count} 彈幕'
danmakuWithoutNum: 彈幕
anime_follow_count: '{count}人追蹤'
year: 年前
month: 個月前
week: 個禮拜前
@@ -210,6 +211,11 @@ dock:
home:
not_interested_in: 對哪方面不感興趣?
video_removed: 影片已移除
ranking:
all: 全部
chinese_anime_related: 中國動畫相關
original_content: 原創內容
debut_work: 新人作品
anime:
total_episodes: 全 {ep} 話
update_to_n_episodes: 更新至 {ep} 話

View File

@@ -6,6 +6,7 @@ common:
viewWithoutNum: ' views'
danmaku: no danmaku | {count} danmaku | {count} danmakus
danmakuWithoutNum: ' danmakus'
anime_follow_count: no follow | {count} follow | {count} follows
year: year ago | years ago
month: month ago | months ago
week: week ago | weeks ago
@@ -211,6 +212,11 @@ dock:
home:
not_interested_in: Not interested in...
video_removed: Video removed
ranking:
all: All
chinese_anime_related: Chinese Anime-related
original_content: Original Content
debut_work: Debut Work
anime:
total_episodes: EP {ep}
update_to_n_episodes: Update to EP {ep}

View File

@@ -6,6 +6,7 @@ common:
viewWithoutNum:
danmaku: '{count} 彈幕'
danmakuWithoutNum: 彈幕
anime_follow_count: '{count}人追緊'
year: 年前
month: 個月前
week: 個禮拜前
@@ -210,6 +211,11 @@ dock:
home:
not_interested_in: 對邊方面冇癮?
video_removed: 經已鏟咗條片
ranking:
all: 全部
chinese_anime_related: 中國動畫相關
original_content: 原創內容
debut_work: 新人作品
anime:
total_episodes: 共 {ep} 集
update_to_n_episodes: 更新到 {ep} 集

View File

@@ -3,7 +3,7 @@ import browser from 'webextension-polyfill'
function handleMessage(message: any) {
// https://github.com/SocialSisterYi/bilibili-API-collect/blob/7873a79022a5606e2391d93b411a05576a0df111/docs/video_ranking/ranking.md#%E8%8E%B7%E5%8F%96%E5%88%86%E5%8C%BA%E8%A7%86%E9%A2%91%E6%8E%92%E8%A1%8C%E6%A6%9C%E5%88%97%E8%A1%A8
if (message.contentScriptQuery === 'getRankingVideos') {
const url = `https://api.bilibili.com/x/web-interface/ranking/v2?rid=${message.rid ?? 0}&type=all`
const url = `https://api.bilibili.com/x/web-interface/ranking/v2?rid=${message.rid ?? 0}&type=${message.type ?? 'all'}`
return fetch(url)
.then(response => response.json())
.then(data => data)

View File

@@ -1,5 +1,6 @@
<script setup lang="ts">
import { removeHttpFromUrl } from '~/utils/main'
import { numFormatter } from '~/utils/dataFormatter'
defineProps<{
url: string
@@ -10,6 +11,8 @@ defineProps<{
desc: string
capsuleText?: string
rank?: number
view?: number
follow?: number
horizontal?: boolean
}>()
</script>
@@ -18,24 +21,23 @@ defineProps<{
<div
:style="{
display: horizontal ? 'flex' : 'block',
}" gap-4
}"
gap-4
class="group"
>
<!-- Cover -->
<a
:style="{ width: horizontal ? '250px' : '100%' }"
rounded="$bew-radius" w-full aspect="12/16" overflow-hidden mb-4 bg="$bew-fill-4" relative
class="group" shrink-0
:style="{ width: horizontal ? '170px' : '100%' }"
:href="url" target="_blank" tabindex="-1"
rounded="$bew-radius" w-full bg="$bew-fill-4" relative shrink-0
group-hover:shadow group-hover:transform="translate--4px"
transition="all ease-in-out 300"
style="--un-shadow:
0 0 0 4px var(--bew-theme-color),
8px 8px 0 2px var(--bew-theme-color-60),
14px 14px 0 2px var(--bew-theme-color-40)"
>
<div
group-hover:shadow group-hover:transform="translate--4px"
transition="all ease-in-out 300" rounded="$bew-radius"
style="--un-shadow:
0 0 0 4px var(--bew-theme-color),
8px 8px 0 2px var(--bew-theme-color-60),
14px 14px 0 2px var(--bew-theme-color-40)"
>
<div aspect="12/16" overflow-hidden rounded="$bew-radius">
<div
v-if="rank"
w-full
@@ -55,7 +57,6 @@ defineProps<{
overflow-hidden
rounded="$bew-radius"
aspect="12/16"
mb-4
pos="relative"
bg="$bew-fill-3"
>
@@ -121,8 +122,13 @@ defineProps<{
</div>
</div>
</a>
<div flex-1>
<p un-text="lg" my-4>
<div
flex-1
:style="{
marginTop: horizontal ? '0' : '1rem',
}"
>
<p un-text="lg" mb-4>
<a
:href="url"
target="_blank"
@@ -132,6 +138,10 @@ defineProps<{
{{ title }}
</a>
</p>
<p v-if="view || follow" text="$bew-text-2" mb-2>
<span v-if="view" mr-4>{{ $t('common.view', { count: numFormatter(view) }, view) }}</span>
<span v-if="follow">{{ $t('common.anime_follow_count', { count: numFormatter(follow) }, follow) }}</span>
</p>
<div text="$bew-text-2" flex flex-wrap gap-2 items-center>
<div
v-if="capsuleText"

View File

@@ -1,16 +1,31 @@
<script setup lang="ts">
defineProps<{
horizontal?: boolean
}>()
</script>
<template>
<div>
<div
:style="{
display: horizontal ? 'flex' : 'block',
}"
gap-4
>
<div
rounded="$bew-radius" aspect="12/16" overflow-hidden mb-4 bg="$bew-fill-4"
shrink-0
:style="{ width: horizontal ? '170px' : '100%' }"
/>
<p w-full h-5 my-2 my-4 bg="$bew-fill-3" />
<div text="$bew-fill-2" mb-10 flex items-center>
<div
text="transparent" bg="$bew-fill-2" p="x-3 y-1" mr-2 h-27px rounded-4
>
0.0
<div w-full>
<p w-full h-5 my-2 my-4 bg="$bew-fill-3" />
<div text="$bew-fill-2" mb-10 flex items-center>
<div
text="transparent" bg="$bew-fill-2" p="x-3 y-1" mr-2 h-27px rounded-4
>
0.0
</div>
<div w="60%" h-4 bg="$bew-fill-2" />
</div>
<div w="60%" h-4 bg="$bew-fill-2" />
</div>
</div>
</template>

View File

@@ -9,10 +9,10 @@ const handleBackToTop = inject('handleBackToTop') as (targetScrollTop: number) =
const rankingTypes = computed((): RankingType[] => {
return [
{ id: 1, name: 'All', rid: 0 },
{ id: 1, name: t('ranking.all'), rid: 0 },
{ id: 2, name: t('topbar.logo_dropdown.anime'), seasonType: 1 },
{ id: 3, name: t('topbar.logo_dropdown.chinese_anime'), seasonType: 4 },
{ id: 4, name: `${t('topbar.logo_dropdown.chinese_anime')} relative`, rid: 168 },
{ id: 4, name: t('ranking.chinese_anime_related'), rid: 168 },
{ id: 5, name: t('topbar.logo_dropdown.documentary_films'), seasonType: 3 },
{ id: 6, name: t('topbar.logo_dropdown.animations'), rid: 1 },
{ id: 7, name: t('topbar.logo_dropdown.music'), rid: 3 },
@@ -32,19 +32,20 @@ const rankingTypes = computed((): RankingType[] => {
{ id: 21, name: t('topbar.logo_dropdown.movies'), seasonType: 2 },
{ id: 22, name: t('topbar.logo_dropdown.tv_shows'), seasonType: 5 },
{ id: 23, name: t('topbar.logo_dropdown.variety_shows'), seasonType: 7 },
{ id: 24, name: 'Original', rid: 0, type: 'origin' },
{ id: 25, name: 'Newest Uploader', rid: 0, type: 'rookie' },
{ id: 24, name: t('ranking.original_content'), rid: 0, type: 'origin' },
{ id: 25, name: t('ranking.debut_work'), rid: 0, type: 'rookie' },
]
})
const isLoading = ref<boolean>(false)
const activatedRankingType = reactive<RankingType>({ ...rankingTypes.value[0] })
const activatedRankingType = ref<RankingType>({ ...rankingTypes.value[0] })
const videoList = reactive<RankingVideoModel[]>([])
const PgcList = reactive<PgcModel[]>([])
watch(() => activatedRankingType.id, () => {
watch(() => activatedRankingType.value.id, () => {
handleBackToTop(settings.value.useSearchPageModeOnHomePage ? 510 : 0)
if (activatedRankingType.seasonType)
if ('seasonType' in activatedRankingType.value)
getRankingPgc()
else
getRankingVideos()
@@ -59,7 +60,8 @@ function getRankingVideos() {
isLoading.value = true
browser.runtime.sendMessage({
contentScriptQuery: 'getRankingVideos',
rid: activatedRankingType.rid,
rid: activatedRankingType.value.rid,
type: 'type' in activatedRankingType.value ? activatedRankingType.value.type : 'all',
}).then((response) => {
if (response.code === 0) {
const { list } = response.data
@@ -73,7 +75,7 @@ function getRankingPgc() {
isLoading.value = true
browser.runtime.sendMessage({
contentScriptQuery: 'getRankingPgc',
seasonType: activatedRankingType.seasonType,
seasonType: activatedRankingType.value.seasonType,
}).then((response) => {
if (response.code === 0)
Object.assign(PgcList, response.result.list)
@@ -92,7 +94,7 @@ function getRankingPgc() {
block rounded="$bew-radius" cursor-pointer transition="all 300 ease-out"
hover:scale-105 un-text="$bew-text-2 hover:$bew-text-1"
:class="{ active: activatedRankingType.id === rankingType.id }"
@click="Object.assign(activatedRankingType, rankingType)"
@click="activatedRankingType = rankingType"
>{{ rankingType.name }}</a>
</li>
</ul>
@@ -100,7 +102,7 @@ function getRankingPgc() {
</aside>
<main w-full>
<template v-if="!activatedRankingType.seasonType">
<template v-if="!('seasonType' in activatedRankingType)">
<VideoCard
v-for="(video, index) in videoList"
:id="Number(video.aid)"
@@ -122,22 +124,34 @@ function getRankingPgc() {
/>
</template>
<template v-else>
<LongCoverCard
v-for="pgc in PgcList"
:key="pgc.url"
:url="pgc.url"
:cover="pgc.cover"
:title="pgc.title"
:desc="pgc.new_ep.index_show"
:rank="pgc.rank"
:capsule-text="pgc.rating.replace('', '')"
horizontal
/>
<div grid="~ cols-2 gap-4">
<LongCoverCard
v-for="pgc in PgcList"
:key="pgc.url"
:url="pgc.url"
:cover="pgc.cover"
:title="pgc.title"
:desc="pgc.new_ep.index_show"
:view="pgc.stat.view"
:follow="pgc.stat.follow"
:rank="pgc.rank"
:capsule-text="pgc.rating.replace('', '')"
horizontal
mb-8
/>
</div>
</template>
<!-- skeleton -->
<template v-if="isLoading">
<VideoCardSkeleton v-for="item in 30" :key="item" horizontal />
<template v-if="!('seasonType' in activatedRankingType)">
<VideoCardSkeleton v-for="item in 30" :key="item" horizontal />
</template>
<template v-else>
<div grid="~ cols-2 gap-4">
<LongCoverCardSkeleton v-for="item in 30" :key="item" horizontal />
</div>
</template>
</template>
</main>
</div>
@@ -145,6 +159,6 @@ function getRankingPgc() {
<style lang="scss" scoped>
.active {
--at-apply: scale-110 bg-white text-black shadow-$bew-shadow-2;
--at-apply: scale-110 bg-$bew-theme-color dark:bg-white text-white dark:text-black shadow-$bew-shadow-2;
}
</style>