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