mirror of
https://github.com/the1812/Bilibili-Evolved.git
synced 2025-11-04 21:22:45 +08:00
parent
c658cd67e5
commit
9dc2ad58f4
@ -155,6 +155,8 @@ export default Vue.extend({
|
|||||||
</script>
|
</script>
|
||||||
|
|
||||||
<style lang="scss">
|
<style lang="scss">
|
||||||
|
@import 'common';
|
||||||
|
|
||||||
.custom-navbar-item {
|
.custom-navbar-item {
|
||||||
color: inherit;
|
color: inherit;
|
||||||
position: relative;
|
position: relative;
|
||||||
@ -216,7 +218,7 @@ export default Vue.extend({
|
|||||||
}
|
}
|
||||||
|
|
||||||
&.active .main-content {
|
&.active .main-content {
|
||||||
font-weight: bold;
|
@include semi-bold();
|
||||||
font-size: 11pt;
|
font-size: 11pt;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -409,7 +409,7 @@ export default Vue.extend({
|
|||||||
.title {
|
.title {
|
||||||
grid-area: title;
|
grid-area: title;
|
||||||
font-size: 13px;
|
font-size: 13px;
|
||||||
font-weight: bold;
|
@include semi-bold();
|
||||||
@include max-line(2);
|
@include max-line(2);
|
||||||
-webkit-box-align: start;
|
-webkit-box-align: start;
|
||||||
margin: 0;
|
margin: 0;
|
||||||
|
|||||||
@ -25,15 +25,15 @@
|
|||||||
<div class="row-title">过滤:</div>
|
<div class="row-title">过滤:</div>
|
||||||
<div class="type-filters">
|
<div class="type-filters">
|
||||||
<div v-for="t of types" :key="t.name" class="type-filter">
|
<div v-for="t of types" :key="t.name" class="type-filter">
|
||||||
<VButton
|
<RadioButton
|
||||||
round
|
|
||||||
:title="(t.checked ? '不显示' : '显示') + t.displayName"
|
:title="(t.checked ? '不显示' : '显示') + t.displayName"
|
||||||
:class="{ checked: t.checked }"
|
:class="{ checked: t.checked }"
|
||||||
@click="toggleTypeFilter(t)"
|
:checked="t.checked"
|
||||||
|
:disabled="loading"
|
||||||
|
@change="toggleTypeFilter(t)"
|
||||||
>
|
>
|
||||||
<VIcon :icon="t.icon" :size="18"></VIcon>
|
|
||||||
{{ t.displayName }}
|
{{ t.displayName }}
|
||||||
</VButton>
|
</RadioButton>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@ -108,14 +108,24 @@
|
|||||||
import { bilibiliApi, getJsonWithCredentials, postTextWithCredentials } from '@/core/ajax'
|
import { bilibiliApi, getJsonWithCredentials, postTextWithCredentials } from '@/core/ajax'
|
||||||
import { formData, getCsrf } from '@/core/utils'
|
import { formData, getCsrf } from '@/core/utils'
|
||||||
import { descendingSort } from '@/core/utils/sort'
|
import { descendingSort } from '@/core/utils/sort'
|
||||||
import { VButton, VIcon, TextBox, VLoading, VEmpty, ScrollTrigger, DpiImage } from '@/ui'
|
import {
|
||||||
|
VButton,
|
||||||
|
VIcon,
|
||||||
|
RadioButton,
|
||||||
|
TextBox,
|
||||||
|
VLoading,
|
||||||
|
VEmpty,
|
||||||
|
ScrollTrigger,
|
||||||
|
DpiImage,
|
||||||
|
} from '@/ui'
|
||||||
import { popperMixin } from '../mixins'
|
import { popperMixin } from '../mixins'
|
||||||
import { types, TypeFilter, HistoryItem, getHistoryItems, group } from './types'
|
import { types, TypeFilter, HistoryItem, getHistoryItems, group, HistoryType } from './types'
|
||||||
|
|
||||||
export default Vue.extend({
|
export default Vue.extend({
|
||||||
components: {
|
components: {
|
||||||
VButton,
|
VButton,
|
||||||
VIcon,
|
VIcon,
|
||||||
|
RadioButton,
|
||||||
TextBox,
|
TextBox,
|
||||||
VLoading,
|
VLoading,
|
||||||
VEmpty,
|
VEmpty,
|
||||||
@ -137,17 +147,12 @@ export default Vue.extend({
|
|||||||
},
|
},
|
||||||
computed: {
|
computed: {
|
||||||
canNextPage() {
|
canNextPage() {
|
||||||
return (
|
return this.search === '' && !this.loading && this.hasMorePage
|
||||||
this.search === '' &&
|
|
||||||
!this.loading &&
|
|
||||||
this.hasMorePage &&
|
|
||||||
this.types.every((t: TypeFilter) => t.checked)
|
|
||||||
)
|
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
watch: {
|
watch: {
|
||||||
search: lodash.debounce(function search() {
|
search: lodash.debounce(function search() {
|
||||||
this.updateGroups()
|
this.reloadHistoryItems()
|
||||||
}, 200),
|
}, 200),
|
||||||
},
|
},
|
||||||
async created() {
|
async created() {
|
||||||
@ -159,11 +164,22 @@ export default Vue.extend({
|
|||||||
},
|
},
|
||||||
methods: {
|
methods: {
|
||||||
toggleTypeFilter(typeFilter: TypeFilter) {
|
toggleTypeFilter(typeFilter: TypeFilter) {
|
||||||
typeFilter.checked = !typeFilter.checked
|
types.forEach(t => (t.checked = t.name === typeFilter.name))
|
||||||
this.updateGroups()
|
this.reloadHistoryItems()
|
||||||
|
},
|
||||||
|
async reloadHistoryItems() {
|
||||||
|
this.viewTime = 0
|
||||||
|
this.hasMorePage = true
|
||||||
|
this.loading = true
|
||||||
|
try {
|
||||||
|
await this.nextPage()
|
||||||
|
} finally {
|
||||||
|
this.loading = false
|
||||||
|
}
|
||||||
},
|
},
|
||||||
filterFunc(item: HistoryItem) {
|
filterFunc(item: HistoryItem) {
|
||||||
if (types.some(t => t.name === item.type && !t.checked)) {
|
const isAllType = types.find(it => it.name === HistoryType.All).checked
|
||||||
|
if (!isAllType && types.some(t => t.name === item.type && !t.checked)) {
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
if (
|
if (
|
||||||
@ -178,7 +194,10 @@ export default Vue.extend({
|
|||||||
this.groups = group(this.cards.filter(this.filterFunc))
|
this.groups = group(this.cards.filter(this.filterFunc))
|
||||||
},
|
},
|
||||||
async nextPage() {
|
async nextPage() {
|
||||||
const items = await getHistoryItems(this.viewTime)
|
const items = await getHistoryItems(
|
||||||
|
this.viewTime,
|
||||||
|
types.find(t => t.checked),
|
||||||
|
)
|
||||||
const cards: HistoryItem[] = lodash.uniqBy(
|
const cards: HistoryItem[] = lodash.uniqBy(
|
||||||
this.cards.concat(items).sort(descendingSort((item: HistoryItem) => item.viewAt)),
|
this.cards.concat(items).sort(descendingSort((item: HistoryItem) => item.viewAt)),
|
||||||
item => item.id,
|
item => item.id,
|
||||||
@ -188,7 +207,10 @@ export default Vue.extend({
|
|||||||
if (cards.length > 0) {
|
if (cards.length > 0) {
|
||||||
this.viewTime = lodash.last(cards).viewAt
|
this.viewTime = lodash.last(cards).viewAt
|
||||||
}
|
}
|
||||||
this.hasMorePage = cards.length !== 0
|
this.hasMorePage = items.length !== 0
|
||||||
|
if (this.hasMorePage && this.groups.length === 0) {
|
||||||
|
await this.nextPage()
|
||||||
|
}
|
||||||
},
|
},
|
||||||
async updateHistoryPauseState() {
|
async updateHistoryPauseState() {
|
||||||
const result = await bilibiliApi(
|
const result = await bilibiliApi(
|
||||||
@ -223,7 +245,7 @@ export default Vue.extend({
|
|||||||
@import '../popup';
|
@import '../popup';
|
||||||
|
|
||||||
.custom-navbar-history-list {
|
.custom-navbar-history-list {
|
||||||
width: 350px;
|
width: 400px;
|
||||||
@include navbar-popup-height();
|
@include navbar-popup-height();
|
||||||
font-size: 12px;
|
font-size: 12px;
|
||||||
padding: 0;
|
padding: 0;
|
||||||
@ -251,23 +273,22 @@ export default Vue.extend({
|
|||||||
margin: 16px 12px 4px 12px;
|
margin: 16px 12px 4px 12px;
|
||||||
.header-row {
|
.header-row {
|
||||||
@include h-stretch(8px);
|
@include h-stretch(8px);
|
||||||
justify-content: space-between;
|
|
||||||
.row-title {
|
.row-title {
|
||||||
@include h-center();
|
@include h-center();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
.type-filters {
|
.type-filters {
|
||||||
@include h-center(8px);
|
@include h-center(6px);
|
||||||
.type-filter {
|
.type-filter {
|
||||||
.be-button {
|
.be-button {
|
||||||
padding: 4px 8px 4px 6px;
|
padding: 4px 8px 4px 6px;
|
||||||
color: #8888;
|
// color: #8888;
|
||||||
.be-icon {
|
// .be-icon {
|
||||||
margin-right: 6px;
|
// margin-right: 6px;
|
||||||
}
|
// }
|
||||||
&.checked {
|
// &.checked {
|
||||||
color: inherit;
|
// color: inherit;
|
||||||
}
|
// }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -402,8 +423,8 @@ export default Vue.extend({
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
.title {
|
.title {
|
||||||
|
@include semi-bold();
|
||||||
grid-area: title;
|
grid-area: title;
|
||||||
font-weight: bold;
|
|
||||||
white-space: nowrap;
|
white-space: nowrap;
|
||||||
overflow: hidden;
|
overflow: hidden;
|
||||||
text-overflow: ellipsis;
|
text-overflow: ellipsis;
|
||||||
|
|||||||
@ -11,7 +11,7 @@ export const history: CustomNavbarItemInit = {
|
|||||||
active: document.URL.replace(/\?.*$/, '') === href,
|
active: document.URL.replace(/\?.*$/, '') === href,
|
||||||
loginRequired: true,
|
loginRequired: true,
|
||||||
|
|
||||||
boundingWidth: 350,
|
boundingWidth: 400,
|
||||||
noPopupPadding: true,
|
noPopupPadding: true,
|
||||||
popupContent: () => import('./NavbarHistory.vue').then(m => m.default),
|
popupContent: () => import('./NavbarHistory.vue').then(m => m.default),
|
||||||
}
|
}
|
||||||
|
|||||||
@ -4,6 +4,7 @@ import { formatDuration } from '@/core/utils/formatters'
|
|||||||
|
|
||||||
/** 历史项目类型, 值为 API 中的 `history.business` */
|
/** 历史项目类型, 值为 API 中的 `history.business` */
|
||||||
export enum HistoryType {
|
export enum HistoryType {
|
||||||
|
All = 'all',
|
||||||
Video = 'archive',
|
Video = 'archive',
|
||||||
Live = 'live',
|
Live = 'live',
|
||||||
Article = 'article',
|
Article = 'article',
|
||||||
@ -48,32 +49,44 @@ export interface TypeFilter {
|
|||||||
displayName: string
|
displayName: string
|
||||||
icon: string
|
icon: string
|
||||||
checked: boolean
|
checked: boolean
|
||||||
|
apiType: string
|
||||||
}
|
}
|
||||||
/** 所有的历史记录类型 */
|
/** 所有的历史记录类型 */
|
||||||
export const types = [
|
export const types = [
|
||||||
|
{
|
||||||
|
name: HistoryType.All,
|
||||||
|
displayName: '全部',
|
||||||
|
icon: '',
|
||||||
|
checked: true,
|
||||||
|
apiType: '',
|
||||||
|
},
|
||||||
{
|
{
|
||||||
name: HistoryType.Video,
|
name: HistoryType.Video,
|
||||||
displayName: '视频',
|
displayName: '视频',
|
||||||
icon: 'mdi-play-circle-outline',
|
icon: 'mdi-play-circle-outline',
|
||||||
checked: true,
|
checked: false,
|
||||||
|
apiType: 'archive',
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: HistoryType.Bangumi,
|
name: HistoryType.Bangumi,
|
||||||
displayName: '番剧',
|
displayName: '番剧',
|
||||||
icon: 'mdi-television-classic',
|
icon: 'mdi-television-classic',
|
||||||
checked: true,
|
checked: false,
|
||||||
|
apiType: 'archive',
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: HistoryType.Live,
|
name: HistoryType.Live,
|
||||||
displayName: '直播',
|
displayName: '直播',
|
||||||
icon: 'mdi-video-wireless-outline',
|
icon: 'mdi-video-wireless-outline',
|
||||||
checked: true,
|
checked: false,
|
||||||
|
apiType: 'live',
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: HistoryType.Article,
|
name: HistoryType.Article,
|
||||||
displayName: '专栏',
|
displayName: '专栏',
|
||||||
icon: 'mdi-newspaper-variant-outline',
|
icon: 'mdi-newspaper-variant-outline',
|
||||||
checked: true,
|
checked: false,
|
||||||
|
apiType: 'article',
|
||||||
},
|
},
|
||||||
] as TypeFilter[]
|
] as TypeFilter[]
|
||||||
|
|
||||||
@ -188,12 +201,17 @@ const parseHistoryItem = (item: any): HistoryItem => {
|
|||||||
* 获取指定观看时间之前的一页历史记录, 不指定则返回最新的历史记录
|
* 获取指定观看时间之前的一页历史记录, 不指定则返回最新的历史记录
|
||||||
* @param viewTime 观看时间
|
* @param viewTime 观看时间
|
||||||
*/
|
*/
|
||||||
export const getHistoryItems = async (viewTime?: number) => {
|
export const getHistoryItems = async (viewTime?: number, type?: TypeFilter) => {
|
||||||
let api = 'https://api.bilibili.com/x/web-interface/history/cursor'
|
const api = 'https://api.bilibili.com/x/web-interface/history/cursor'
|
||||||
|
const params = new URLSearchParams()
|
||||||
if (viewTime) {
|
if (viewTime) {
|
||||||
api += `?view_at=${Math.round(viewTime / 1000)}`
|
params.set('view_at', Math.round(viewTime / 1000).toString())
|
||||||
}
|
}
|
||||||
const { list } = await bilibiliApi(getJsonWithCredentials(api), '获取历史记录失败')
|
params.set('type', type?.apiType ?? '')
|
||||||
|
const { list } = await bilibiliApi(
|
||||||
|
getJsonWithCredentials(`${api}?${params.toString()}`),
|
||||||
|
'获取历史记录失败',
|
||||||
|
)
|
||||||
if (!Array.isArray(list)) {
|
if (!Array.isArray(list)) {
|
||||||
return []
|
return []
|
||||||
}
|
}
|
||||||
|
|||||||
@ -186,7 +186,7 @@ export default Vue.extend({
|
|||||||
.title {
|
.title {
|
||||||
margin-left: 6px;
|
margin-left: 6px;
|
||||||
font-size: 18px;
|
font-size: 18px;
|
||||||
font-weight: bold;
|
@include semi-bold();
|
||||||
}
|
}
|
||||||
.grow {
|
.grow {
|
||||||
flex: 1;
|
flex: 1;
|
||||||
|
|||||||
@ -233,7 +233,7 @@ export default Vue.extend({
|
|||||||
}
|
}
|
||||||
.title {
|
.title {
|
||||||
font-size: 14px;
|
font-size: 14px;
|
||||||
font-weight: bold;
|
@include semi-bold();
|
||||||
padding-top: 4px;
|
padding-top: 4px;
|
||||||
color: inherit;
|
color: inherit;
|
||||||
white-space: nowrap;
|
white-space: nowrap;
|
||||||
|
|||||||
@ -325,6 +325,8 @@ export default Vue.extend({
|
|||||||
</script>
|
</script>
|
||||||
|
|
||||||
<style lang="scss">
|
<style lang="scss">
|
||||||
|
@import 'common';
|
||||||
|
|
||||||
.user-info-panel {
|
.user-info-panel {
|
||||||
border-radius: 8px;
|
border-radius: 8px;
|
||||||
overflow: hidden;
|
overflow: hidden;
|
||||||
@ -441,7 +443,7 @@ export default Vue.extend({
|
|||||||
.welcome,
|
.welcome,
|
||||||
.name {
|
.name {
|
||||||
font-size: 16px;
|
font-size: 16px;
|
||||||
font-weight: bold;
|
@include semi-bold();
|
||||||
margin: 46px 0 16px 0;
|
margin: 46px 0 16px 0;
|
||||||
text-align: center;
|
text-align: center;
|
||||||
color: inherit;
|
color: inherit;
|
||||||
@ -495,7 +497,7 @@ export default Vue.extend({
|
|||||||
color: var(--theme-color) !important;
|
color: var(--theme-color) !important;
|
||||||
}
|
}
|
||||||
.stats-number {
|
.stats-number {
|
||||||
font-weight: bold;
|
@include semi-bold();
|
||||||
margin-bottom: 4px;
|
margin-bottom: 4px;
|
||||||
font-size: 14px;
|
font-size: 14px;
|
||||||
transition: none;
|
transition: none;
|
||||||
|
|||||||
@ -326,7 +326,7 @@ export default Vue.extend({
|
|||||||
.title {
|
.title {
|
||||||
grid-area: title;
|
grid-area: title;
|
||||||
font-size: 13px;
|
font-size: 13px;
|
||||||
font-weight: bold;
|
@include semi-bold();
|
||||||
margin: 0;
|
margin: 0;
|
||||||
margin-top: 8px;
|
margin-top: 8px;
|
||||||
padding: 0 10px;
|
padding: 0 10px;
|
||||||
|
|||||||
@ -91,7 +91,7 @@ export default Vue.extend({
|
|||||||
&.left-icon {
|
&.left-icon {
|
||||||
.icon-container {
|
.icon-container {
|
||||||
order: -1;
|
order: -1;
|
||||||
margin: 2px 8px 2px 0;
|
margin: 2px 6px 2px 0;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user