mirror of
https://github.com/the1812/Bilibili-Evolved.git
synced 2025-11-04 21:22:45 +08:00
Merge pull request #3537 from snowraincloud/preview-features
up主黑名单,删除首页的黑名单up主封面、名称、标题
This commit is contained in:
commit
fa11994611
242
registry/lib/components/utils/black-list/BlockListSettings.vue
Normal file
242
registry/lib/components/utils/black-list/BlockListSettings.vue
Normal file
@ -0,0 +1,242 @@
|
||||
<template>
|
||||
<VPopup
|
||||
ref="popup"
|
||||
v-model="open"
|
||||
class="custom-block-list-settings"
|
||||
fixed
|
||||
:lazy="false"
|
||||
:trigger-element="triggerElement"
|
||||
>
|
||||
<div class="block-list-settings-header">
|
||||
<VIcon class="title-icon" icon="mdi-sort" :size="24"></VIcon>
|
||||
<div class="title">
|
||||
{{ titleName }}黑名单设置
|
||||
</div>
|
||||
<div class="grow"></div>
|
||||
<div class="close" @click="open = false">
|
||||
<VIcon icon="close" :size="18"></VIcon>
|
||||
</div>
|
||||
</div>
|
||||
<div class="block-list-settings-content">
|
||||
<div class="block-list-settings-section">
|
||||
<div class="block-list-settings-section-title">
|
||||
添加到黑名单
|
||||
</div>
|
||||
<div class="block-list-settings-section-input">
|
||||
<TextBox :text="name" @change="changeName" />
|
||||
<VButton @click="add">添加</VButton>
|
||||
</div>
|
||||
</div>
|
||||
<div class="block-list-settings-section">
|
||||
<div class="block-list-settings-section-title">
|
||||
黑名单列表
|
||||
</div>
|
||||
<div
|
||||
class="block-list-settings-section-description"
|
||||
>
|
||||
点击×图标可以删除名单.
|
||||
</div>
|
||||
<VLoading v-if="!loaded" />
|
||||
<div
|
||||
v-show="loaded"
|
||||
ref="block-listSortList"
|
||||
class="block-list-settings-section-content block-list-sort-list"
|
||||
>
|
||||
<div
|
||||
v-for="item of list"
|
||||
:key="item"
|
||||
class="block-list-sort-item"
|
||||
:data-name="item"
|
||||
>
|
||||
<div class="item-name">
|
||||
{{ item }}
|
||||
</div>
|
||||
<div class="toggle-visible">
|
||||
<VIcon
|
||||
:size="18"
|
||||
icon="close"
|
||||
@click="toggleVisible(item)"
|
||||
></VIcon>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</VPopup>
|
||||
</template>
|
||||
<script lang="ts">
|
||||
import {
|
||||
VPopup,
|
||||
TextBox,
|
||||
VIcon,
|
||||
VButton,
|
||||
} from '@/ui'
|
||||
|
||||
export default Vue.extend({
|
||||
components: {
|
||||
VPopup,
|
||||
TextBox,
|
||||
VIcon,
|
||||
VButton,
|
||||
},
|
||||
props: {
|
||||
triggerElement: {
|
||||
type: HTMLElement,
|
||||
default: null,
|
||||
},
|
||||
list: {
|
||||
type: Array,
|
||||
default: null,
|
||||
},
|
||||
save: {
|
||||
type: Function,
|
||||
default: undefined,
|
||||
},
|
||||
titleName: {
|
||||
type: String,
|
||||
default: '',
|
||||
},
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
open: false,
|
||||
loaded: false,
|
||||
name: '',
|
||||
}
|
||||
},
|
||||
watch: {
|
||||
open(newVal:boolean) {
|
||||
if (!newVal) {
|
||||
this.save(this.list)
|
||||
}
|
||||
},
|
||||
},
|
||||
async mounted() {
|
||||
this.loaded = true
|
||||
},
|
||||
methods: {
|
||||
toggle() {
|
||||
this.$refs.popup.toggle()
|
||||
},
|
||||
changeName(val: string) {
|
||||
this.name = val
|
||||
},
|
||||
add() {
|
||||
// eslint-disable-next-line vue/no-mutating-props
|
||||
this.list.push(this.name)
|
||||
// eslint-disable-next-line vue/no-mutating-props
|
||||
this.list = lodash.uniq(this.list)
|
||||
this.name = ''
|
||||
},
|
||||
toggleVisible(item: any) {
|
||||
// eslint-disable-next-line vue/no-mutating-props
|
||||
this.list.splice(this.list.indexOf(item), 1)
|
||||
},
|
||||
},
|
||||
})
|
||||
</script>
|
||||
<style lang="scss">
|
||||
@import "common";
|
||||
.custom-block-list-settings {
|
||||
@include popup();
|
||||
width: 400px;
|
||||
font-size: 14px;
|
||||
padding: 12px 12px 12px 18px;
|
||||
left: 50%;
|
||||
top: 50%;
|
||||
transform: translateX(-50%) translateY(-50%) scale(0.95);
|
||||
transition: 0.2s ease-out;
|
||||
z-index: 100002;
|
||||
&.open {
|
||||
transform: translateX(-50%) translateY(-50%) scale(1);
|
||||
}
|
||||
.block-list-settings-header {
|
||||
@include h-center();
|
||||
justify-content: space-between;
|
||||
.title {
|
||||
margin-left: 6px;
|
||||
font-size: 18px;
|
||||
font-weight: bold;
|
||||
}
|
||||
.grow {
|
||||
flex: 1;
|
||||
}
|
||||
.close {
|
||||
padding: 6px;
|
||||
cursor: pointer;
|
||||
transition: 0.2s ease-out;
|
||||
&:hover {
|
||||
color: var(--theme-color);
|
||||
}
|
||||
}
|
||||
}
|
||||
.block-list-settings-content {
|
||||
.block-list-settings-section {
|
||||
margin-top: 12px;
|
||||
> :not(:last-child) {
|
||||
margin-bottom: 6px;
|
||||
}
|
||||
&-title {
|
||||
font-size: 14px;
|
||||
}
|
||||
&-input {
|
||||
display: flex;
|
||||
div {
|
||||
margin: 0 10px;
|
||||
}
|
||||
}
|
||||
&-description {
|
||||
font-size: 12px;
|
||||
opacity: 0.6;
|
||||
line-height: 1.5;
|
||||
}
|
||||
&-content {
|
||||
@include h-center();
|
||||
flex-wrap: wrap;
|
||||
.be-slider {
|
||||
margin: 0 4px;
|
||||
flex: 1;
|
||||
}
|
||||
.padding-value {
|
||||
margin-left: 12px;
|
||||
width: 50px;
|
||||
text-align: end;
|
||||
}
|
||||
.block-list-sort-item {
|
||||
@include card();
|
||||
@include h-center();
|
||||
transition: none;
|
||||
white-space: nowrap;
|
||||
padding: 6px;
|
||||
padding-left: 8px;
|
||||
margin: 0 4px 4px 0;
|
||||
cursor: move;
|
||||
&:hover {
|
||||
border-color: var(--theme-color);
|
||||
}
|
||||
&.block-list-hidden {
|
||||
opacity: 0.5;
|
||||
}
|
||||
&.sortable-ghost {
|
||||
opacity: 0;
|
||||
}
|
||||
&.sortable-chosen {
|
||||
box-shadow: 0 4px 16px 0 rgb(0 0 0 / 16%);
|
||||
transform: scale(1.05);
|
||||
}
|
||||
&.sortable-drag {
|
||||
opacity: 1;
|
||||
}
|
||||
&.sortable-drag.block-list-hidden {
|
||||
opacity: 0.5;
|
||||
}
|
||||
.toggle-visible {
|
||||
margin-left: 6px;
|
||||
cursor: pointer;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
</style>
|
||||
67
registry/lib/components/utils/black-list/Settings.vue
Normal file
67
registry/lib/components/utils/black-list/Settings.vue
Normal file
@ -0,0 +1,67 @@
|
||||
<template>
|
||||
<div>
|
||||
<div class="custom-block-list-extra-options">
|
||||
<VButton
|
||||
v-if="login"
|
||||
ref="button"
|
||||
@mouseover="loadNameBlockListSettings()"
|
||||
@click="toggleNameSettings()"
|
||||
>
|
||||
精确匹配列表<VIcon icon="right-arrow" :size="16"></VIcon>
|
||||
</VButton>
|
||||
</div>
|
||||
<div class="custom-block-list-extra-options">
|
||||
<VButton
|
||||
v-if="login"
|
||||
ref="button"
|
||||
@mouseover="loadRegexBlockListSettings()"
|
||||
@click="toggleRegexSettings()"
|
||||
>
|
||||
正则匹配列表<VIcon icon="right-arrow" :size="16"></VIcon>
|
||||
</VButton>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
<script lang="ts">
|
||||
import { getUID } from '@/core/utils'
|
||||
import { VIcon, VButton } from '@/ui'
|
||||
import { loadNameSettings, loadRegexSettings, setNameProps, setRegexProps, toggleNameSettings, toggleRegexSettings } from './vm'
|
||||
|
||||
export default Vue.extend({
|
||||
components: {
|
||||
VIcon,
|
||||
VButton,
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
login: Boolean(getUID()),
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
async loadNameBlockListSettings() {
|
||||
const isFirstLoad = await loadNameSettings()
|
||||
if (isFirstLoad) {
|
||||
const triggerButton = this.$refs.button.$el as HTMLElement
|
||||
setNameProps(triggerButton)
|
||||
}
|
||||
},
|
||||
toggleNameSettings,
|
||||
async loadRegexBlockListSettings() {
|
||||
const isFirstLoad = await loadRegexSettings()
|
||||
if (isFirstLoad) {
|
||||
const triggerButton = this.$refs.button.$el as HTMLElement
|
||||
setRegexProps(triggerButton)
|
||||
}
|
||||
},
|
||||
toggleRegexSettings,
|
||||
},
|
||||
})
|
||||
</script>
|
||||
<style lang="scss">
|
||||
.custom-block-list-extra-options {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
margin-bottom: 20px;
|
||||
}
|
||||
</style>
|
||||
1
registry/lib/components/utils/black-list/common.ts
Normal file
1
registry/lib/components/utils/black-list/common.ts
Normal file
@ -0,0 +1 @@
|
||||
export const BlockListDataKey = 'blokList.data'
|
||||
80
registry/lib/components/utils/black-list/index.ts
Normal file
80
registry/lib/components/utils/black-list/index.ts
Normal file
@ -0,0 +1,80 @@
|
||||
import { ComponentMetadata } from '@/components/types'
|
||||
import { mainSiteUrls } from '@/core/utils/urls'
|
||||
import { allMutationsOn } from '@/core/observer'
|
||||
import { selectAll } from '@/core/spin-query'
|
||||
import { registerData, getData } from '@/plugins/data'
|
||||
import { BlockListDataKey } from './common'
|
||||
|
||||
const name = 'blackList'
|
||||
|
||||
const entry = async ({ settings: { options } }) => {
|
||||
const blockListData = {
|
||||
up: options.up,
|
||||
upRegex: options.upRegex,
|
||||
}
|
||||
|
||||
registerData(BlockListDataKey, blockListData)
|
||||
const billGrid = await selectAll('.bili-grid')
|
||||
allMutationsOn(billGrid, async () => {
|
||||
const videos = await selectAll('.bili-video-card')
|
||||
if (!videos) {
|
||||
return
|
||||
}
|
||||
const blockList = getData(BlockListDataKey)
|
||||
const upRegex = blockList[0].upRegex.map(e => new RegExp(e))
|
||||
videos.forEach(video => {
|
||||
const authorElement = (video as unknown as HTMLElement).querySelector('.bili-video-card__info--author')
|
||||
const titleElement = (video as unknown as HTMLElement).querySelector('.bili-video-card__info--tit > a')
|
||||
if (authorElement != null) {
|
||||
const author = authorElement.innerHTML
|
||||
if (blockList[0].up.indexOf(author) !== -1) {
|
||||
const image = (video as unknown as HTMLElement).querySelector('.v-img.bili-video-card__cover')
|
||||
image.innerHTML = ''
|
||||
authorElement.innerHTML = ''
|
||||
titleElement.innerHTML = ''
|
||||
} else {
|
||||
for (const i in upRegex) {
|
||||
if (upRegex[i].test(author)) {
|
||||
const image = (video as unknown as HTMLElement).querySelector('.v-img.bili-video-card__cover')
|
||||
image.innerHTML = ''
|
||||
authorElement.innerHTML = ''
|
||||
titleElement.innerHTML = ''
|
||||
break
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
})
|
||||
})
|
||||
}
|
||||
|
||||
export const component: ComponentMetadata = {
|
||||
name,
|
||||
entry,
|
||||
// reload: entry,
|
||||
extraOptions: () => import('./Settings.vue').then(m => m.default),
|
||||
options: {
|
||||
up: {
|
||||
displayName: 'up主名称',
|
||||
defaultValue: [],
|
||||
hidden: true,
|
||||
},
|
||||
upRegex: {
|
||||
displayName: '正则匹配up主名称',
|
||||
defaultValue: [],
|
||||
hidden: true,
|
||||
},
|
||||
},
|
||||
displayName: '屏蔽黑名单up主',
|
||||
tags: [
|
||||
componentsTags.utils,
|
||||
],
|
||||
description: {
|
||||
'zh-CN': '屏蔽黑名单up主',
|
||||
},
|
||||
author: {
|
||||
name: 'snowraincloud',
|
||||
link: 'https://github.com/snowraincloud',
|
||||
},
|
||||
urlInclude: mainSiteUrls,
|
||||
}
|
||||
83
registry/lib/components/utils/black-list/vm.ts
Normal file
83
registry/lib/components/utils/black-list/vm.ts
Normal file
@ -0,0 +1,83 @@
|
||||
import { getComponentSettings } from '@/core/settings'
|
||||
import { mountVueComponent } from '@/core/utils'
|
||||
import { addData, getData } from '@/plugins/data'
|
||||
import { BlockListDataKey } from './common'
|
||||
|
||||
type SettingsVmType = Vue & {
|
||||
toggle: () => void
|
||||
triggerElement: HTMLElement
|
||||
list : string[]
|
||||
save : (items:string[]) => void
|
||||
titleName: string
|
||||
}
|
||||
let nameSettingsVM: SettingsVmType
|
||||
let regexSettingsVm: SettingsVmType
|
||||
|
||||
const blackListOptions = getComponentSettings('blackList').options as {
|
||||
up: string[]
|
||||
upRegex: string[]
|
||||
}
|
||||
|
||||
export const setNameProps = (element: HTMLElement) => {
|
||||
if (!nameSettingsVM) {
|
||||
return
|
||||
}
|
||||
nameSettingsVM.triggerElement = element
|
||||
const blockList = getData(BlockListDataKey)
|
||||
nameSettingsVM.list = lodash.cloneDeep(blockList[0].up)
|
||||
nameSettingsVM.save = (items:string[]) => {
|
||||
addData(BlockListDataKey, data => {
|
||||
data.up = items
|
||||
})
|
||||
blackListOptions.up = items
|
||||
}
|
||||
nameSettingsVM.titleName = '精确匹配'
|
||||
}
|
||||
export const setRegexProps = (element: HTMLElement) => {
|
||||
if (!regexSettingsVm) {
|
||||
return
|
||||
}
|
||||
regexSettingsVm.triggerElement = element
|
||||
const blockList = getData(BlockListDataKey)
|
||||
regexSettingsVm.list = lodash.cloneDeep(blockList[0].upRegex)
|
||||
regexSettingsVm.save = (items:string[]) => {
|
||||
addData(BlockListDataKey, data => {
|
||||
data.upRegex = items
|
||||
})
|
||||
blackListOptions.upRegex = items
|
||||
}
|
||||
regexSettingsVm.titleName = '正则匹配'
|
||||
}
|
||||
|
||||
export const loadNameSettings = async () => {
|
||||
if (nameSettingsVM) {
|
||||
return false
|
||||
}
|
||||
const blockListSettings = await import('./BlockListSettings.vue').then(m => m.default)
|
||||
nameSettingsVM = mountVueComponent(blockListSettings)
|
||||
document.body.insertAdjacentElement('beforeend', nameSettingsVM.$el)
|
||||
return true
|
||||
}
|
||||
|
||||
export const loadRegexSettings = async () => {
|
||||
if (regexSettingsVm) {
|
||||
return false
|
||||
}
|
||||
const blockListSettings = await import('./BlockListSettings.vue').then(m => m.default)
|
||||
regexSettingsVm = mountVueComponent(blockListSettings)
|
||||
document.body.insertAdjacentElement('beforeend', regexSettingsVm.$el)
|
||||
return true
|
||||
}
|
||||
export const toggleNameSettings = async () => {
|
||||
if (!nameSettingsVM) {
|
||||
await loadNameSettings()
|
||||
}
|
||||
nameSettingsVM?.toggle()
|
||||
}
|
||||
|
||||
export const toggleRegexSettings = async () => {
|
||||
if (!regexSettingsVm) {
|
||||
await loadRegexSettings()
|
||||
}
|
||||
regexSettingsVm?.toggle()
|
||||
}
|
||||
Loading…
Reference in New Issue
Block a user