mirror of
https://github.com/the1812/Bilibili-Evolved.git
synced 2025-11-04 21:22:45 +08:00
commit
81cbb79dfd
207
registry/lib/components/utils/auto-like/blackList.vue
Normal file
207
registry/lib/components/utils/auto-like/blackList.vue
Normal file
@ -0,0 +1,207 @@
|
||||
<template>
|
||||
<VPopup
|
||||
ref="popup"
|
||||
v-model="isOpen"
|
||||
class="like-black-list"
|
||||
fixed
|
||||
:lazy="false"
|
||||
:trigger-element="triggerElement"
|
||||
>
|
||||
<div class="black-list-header">
|
||||
<VIcon class="title-icon" icon="mdi-sort" :size="24"></VIcon>
|
||||
<div class="title">添加黑名单</div>
|
||||
<div class="close" @click="isOpen = false">
|
||||
<VIcon icon="close" :size="18"></VIcon>
|
||||
</div>
|
||||
</div>
|
||||
<div class="black-list-content">
|
||||
<div class="black-list-section">
|
||||
<div class="black-list-section-title">添加到黑名单</div>
|
||||
<div class="black-list-section-input">
|
||||
<TextBox :text="name" @change="changeName" />
|
||||
<VButton @click="add">添加</VButton>
|
||||
</div>
|
||||
</div>
|
||||
<div class="black-list-section">
|
||||
<div class="black-list-section-title">黑名单列表</div>
|
||||
<div class="black-list-section-description">点击×图标可以删除名单.</div>
|
||||
<VLoading v-if="!isLoaded" />
|
||||
<div
|
||||
v-show="isLoaded"
|
||||
ref="black-listSortList"
|
||||
class="black-list-section-content black-list-sort-list"
|
||||
>
|
||||
<div v-for="item of list" :key="item" class="black-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,
|
||||
},
|
||||
titleName: {
|
||||
type: String,
|
||||
default: '',
|
||||
},
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
isOpen: false,
|
||||
isLoaded: false,
|
||||
name: '',
|
||||
}
|
||||
},
|
||||
async mounted() {
|
||||
this.isLoaded = true
|
||||
},
|
||||
methods: {
|
||||
toggle() {
|
||||
this.$refs.popup.toggle()
|
||||
},
|
||||
changeName(val: string) {
|
||||
this.name = val
|
||||
},
|
||||
add() {
|
||||
if (this.name.length && !this.list.includes(this.name)) {
|
||||
// eslint-disable-next-line vue/no-mutating-props
|
||||
this.list.push(this.name)
|
||||
}
|
||||
this.name = ''
|
||||
},
|
||||
toggleVisible(item: string) {
|
||||
// eslint-disable-next-line vue/no-mutating-props
|
||||
this.list.splice(this.list.indexOf(item), 1)
|
||||
},
|
||||
},
|
||||
})
|
||||
</script>
|
||||
|
||||
<style lang="scss">
|
||||
@import 'common';
|
||||
.like-black-list {
|
||||
@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);
|
||||
}
|
||||
.black-list-header {
|
||||
@include h-center();
|
||||
justify-content: space-between;
|
||||
.title {
|
||||
margin-left: 6px;
|
||||
font-size: 18px;
|
||||
@include semi-bold();
|
||||
}
|
||||
.grow {
|
||||
flex: 1;
|
||||
}
|
||||
.close {
|
||||
padding: 6px;
|
||||
cursor: pointer;
|
||||
transition: 0.2s ease-out;
|
||||
&:hover {
|
||||
color: var(--theme-color);
|
||||
}
|
||||
}
|
||||
}
|
||||
.black-list-content {
|
||||
.black-list-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;
|
||||
}
|
||||
.black-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);
|
||||
}
|
||||
&.black-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.black-list-hidden {
|
||||
opacity: 0.5;
|
||||
}
|
||||
.toggle-visible {
|
||||
margin-left: 6px;
|
||||
cursor: pointer;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
</style>
|
||||
@ -1 +1,4 @@
|
||||
进入视频 / 查看动态时, 自动点赞.
|
||||
进入视频 / 查看动态时, 自动点赞\
|
||||
无法触发未加载动态的点赞,当启用手动对动态点赞后可手动触发,启用后不会触发动态自动点赞\
|
||||
安装快捷键扩展后可以点击【l】键或【L】键触发\
|
||||
还可以添加动态点赞的黑名单\
|
||||
|
||||
@ -1,8 +1,11 @@
|
||||
import { defineComponentMetadata } from '@/components/define'
|
||||
import { forEachFeedsCard } from '@/components/feeds/api'
|
||||
import { select } from '@/core/spin-query'
|
||||
import { matchUrlPattern, playerReady } from '@/core/utils'
|
||||
import { feedsUrls, videoAndBangumiUrls } from '@/core/utils/urls'
|
||||
import { KeyBindingAction } from '../keymap/bindings'
|
||||
import { forEachFeedsCard } from '@/components/feeds/api'
|
||||
import { BlackListDataKey, loadlikeButton } from './vm'
|
||||
import { getData, registerData } from '@/plugins/data'
|
||||
|
||||
const feedsLikeQueue = [] as HTMLElement[]
|
||||
export const component = defineComponentMetadata({
|
||||
@ -10,6 +13,10 @@ export const component = defineComponentMetadata({
|
||||
displayName: '自动点赞',
|
||||
tags: [componentsTags.utils, componentsTags.feeds, componentsTags.video],
|
||||
urlInclude: [...videoAndBangumiUrls, ...feedsUrls],
|
||||
author: {
|
||||
name: 'CrazyboyQCD',
|
||||
link: 'https://github.com/CrazyboyQCD',
|
||||
},
|
||||
options: {
|
||||
video: {
|
||||
defaultValue: true,
|
||||
@ -19,7 +26,17 @@ export const component = defineComponentMetadata({
|
||||
defaultValue: true,
|
||||
displayName: '对动态点赞',
|
||||
},
|
||||
manualFeed: {
|
||||
defaultValue: true,
|
||||
displayName: '手动对动态点赞',
|
||||
},
|
||||
users: {
|
||||
displayName: '黑名单',
|
||||
defaultValue: [] as string[],
|
||||
hidden: true,
|
||||
},
|
||||
},
|
||||
extraOptions: () => import('./settings.vue').then(m => m.default),
|
||||
entry: async ({ settings: { options } }) => {
|
||||
if (options.video && videoAndBangumiUrls.some(url => matchUrlPattern(url))) {
|
||||
await playerReady()
|
||||
@ -32,22 +49,51 @@ export const component = defineComponentMetadata({
|
||||
likeButton.click()
|
||||
}
|
||||
if (options.feed && feedsUrls.some(url => matchUrlPattern(url))) {
|
||||
window.setInterval(() => {
|
||||
if (feedsLikeQueue.length === 0) {
|
||||
return
|
||||
}
|
||||
const button = feedsLikeQueue.shift()
|
||||
button?.click()
|
||||
}, 1000)
|
||||
forEachFeedsCard({
|
||||
added: card => {
|
||||
const likeButton = dq(card.element, '.bili-dyn-action.like') as HTMLElement
|
||||
if (!likeButton || likeButton.classList.contains('active')) {
|
||||
const blackListData = {
|
||||
users: options.users,
|
||||
}
|
||||
registerData(BlackListDataKey, blackListData)
|
||||
if (options.manualFeed) {
|
||||
loadlikeButton()
|
||||
} else {
|
||||
window.setInterval(() => {
|
||||
if (feedsLikeQueue.length === 0) {
|
||||
return
|
||||
}
|
||||
feedsLikeQueue.push(likeButton)
|
||||
},
|
||||
})
|
||||
const button = feedsLikeQueue.shift()
|
||||
button?.click()
|
||||
}, 1000)
|
||||
const blackList = getData(BlackListDataKey)
|
||||
forEachFeedsCard({
|
||||
added: card => {
|
||||
if (blackList.includes(card.username)) {
|
||||
return
|
||||
}
|
||||
const likeButtons = dq(card.element, '.bili-dyn-action.like') as HTMLElement
|
||||
if (!likeButtons || likeButtons.classList.contains('active')) {
|
||||
return
|
||||
}
|
||||
feedsLikeQueue.push(likeButtons)
|
||||
},
|
||||
})
|
||||
}
|
||||
}
|
||||
},
|
||||
plugin: {
|
||||
displayName: '点赞 - 手动',
|
||||
setup: ({ addData }) => {
|
||||
addData('keymap.actions', (actions: Record<string, KeyBindingAction>) => {
|
||||
actions.manuallike = {
|
||||
displayName: '手动触发对动态点赞',
|
||||
run: context => {
|
||||
const { clickElement } = context
|
||||
return clickElement('.manual-like', context)
|
||||
},
|
||||
}
|
||||
})
|
||||
addData('keymap.presets', (presetBase: Record<string, string>) => {
|
||||
presetBase.manuallike = 'l L'
|
||||
})
|
||||
},
|
||||
},
|
||||
})
|
||||
|
||||
84
registry/lib/components/utils/auto-like/like.vue
Normal file
84
registry/lib/components/utils/auto-like/like.vue
Normal file
@ -0,0 +1,84 @@
|
||||
<template>
|
||||
<VButton round class="manual-like" @click="like">
|
||||
<div id="text" :class="{ like: isLike }">正在点赞: {{ curLikeCnt }} / {{ totalLikeCnt }}</div>
|
||||
<VIcon v-show="!isLike" colored icon="like" :size="20" />
|
||||
</VButton>
|
||||
</template>
|
||||
|
||||
<script lang="ts">
|
||||
import { VButton, VIcon } from '@/ui'
|
||||
|
||||
export default Vue.extend({
|
||||
components: {
|
||||
VButton,
|
||||
VIcon,
|
||||
},
|
||||
props: {
|
||||
list: {
|
||||
type: Array,
|
||||
default: null,
|
||||
},
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
isClick: false,
|
||||
isLike: false,
|
||||
totalLikeCnt: 0,
|
||||
curLikeCnt: 0,
|
||||
feedsLikeQueue: [] as HTMLElement[],
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
like() {
|
||||
if (this.isClick) {
|
||||
return
|
||||
}
|
||||
this.isClick = true
|
||||
// forEachFeedsCard异步执行顺序有问题,不能及时同步,用dqa代替
|
||||
const likeButtons = (dqa('.bili-dyn-title__text') as HTMLElement[]).flatMap(e => {
|
||||
if (this.list.includes(e.textContent)) {
|
||||
return []
|
||||
}
|
||||
const likeButton = e.closest('.bili-dyn-item__main').querySelector('.bili-dyn-action.like')
|
||||
return likeButton && !likeButton.classList.contains('active') ? likeButton : []
|
||||
})
|
||||
this.feedsLikeQueue.push(...likeButtons)
|
||||
this.totalLikeCnt = this.feedsLikeQueue.length
|
||||
this.curLikeCnt = 0
|
||||
this.isLike = true
|
||||
const t = window.setInterval(() => {
|
||||
if (this.feedsLikeQueue.length === 0) {
|
||||
this.isLike = false
|
||||
this.isClick = false
|
||||
clearInterval(t)
|
||||
return
|
||||
}
|
||||
const button = this.feedsLikeQueue.shift()
|
||||
button?.click()
|
||||
this.curLikeCnt++
|
||||
}, 1200)
|
||||
},
|
||||
},
|
||||
})
|
||||
</script>
|
||||
|
||||
<style lang="scss">
|
||||
.manual-like {
|
||||
left: 5px;
|
||||
z-index: 1001;
|
||||
height: 30px;
|
||||
position: fixed;
|
||||
* {
|
||||
color: rgb(251, 114, 153);
|
||||
}
|
||||
#text {
|
||||
overflow: hidden;
|
||||
white-space: nowrap;
|
||||
max-width: 0px;
|
||||
transition: max-width 0.4s linear !important;
|
||||
&.like {
|
||||
max-width: 150px;
|
||||
}
|
||||
}
|
||||
}
|
||||
</style>
|
||||
50
registry/lib/components/utils/auto-like/settings.vue
Normal file
50
registry/lib/components/utils/auto-like/settings.vue
Normal file
@ -0,0 +1,50 @@
|
||||
<template>
|
||||
<div>
|
||||
<div class="custom-black-list-extra-options">
|
||||
<VButton ref="button" @mouseover="setBlackListProps" @click="toggleBlackList">
|
||||
黑名单
|
||||
<VIcon icon="right-arrow" :size="16" />
|
||||
</VButton>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
<script lang="ts">
|
||||
import { VIcon, VButton } from '@/ui'
|
||||
import { loadBlackList, setBlackListProps, toggleBlackList } from './vm'
|
||||
|
||||
export default Vue.extend({
|
||||
components: {
|
||||
VIcon,
|
||||
VButton,
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
isFirstLoad: false,
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
toggle() {
|
||||
this.$refs.popup.toggle()
|
||||
},
|
||||
async setBlackListProps() {
|
||||
if (this.isFirstLoad) {
|
||||
return
|
||||
}
|
||||
this.isFirstLoad = await loadBlackList()
|
||||
if (this.isFirstLoad) {
|
||||
const triggerButton = this.$refs.button.$el as HTMLElement
|
||||
setBlackListProps(triggerButton)
|
||||
}
|
||||
},
|
||||
toggleBlackList,
|
||||
},
|
||||
})
|
||||
</script>
|
||||
<style lang="scss">
|
||||
.custom-black-list-extra-options {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
margin-bottom: 20px;
|
||||
}
|
||||
</style>
|
||||
48
registry/lib/components/utils/auto-like/vm.ts
Normal file
48
registry/lib/components/utils/auto-like/vm.ts
Normal file
@ -0,0 +1,48 @@
|
||||
import { select } from '@/core/spin-query'
|
||||
import { mountVueComponent } from '@/core/utils'
|
||||
import { getData } from '@/plugins/data'
|
||||
|
||||
export const BlackListDataKey = 'like-black-List.data'
|
||||
|
||||
type SettingsVmType = Vue & {
|
||||
toggle: () => void
|
||||
triggerElement: HTMLElement
|
||||
list: string[]
|
||||
titleName: string
|
||||
}
|
||||
let blacklistVM: SettingsVmType = null
|
||||
|
||||
export const setBlackListProps = (element: HTMLElement) => {
|
||||
if (!blacklistVM) {
|
||||
return
|
||||
}
|
||||
blacklistVM.triggerElement = element
|
||||
const blackList = getData(BlackListDataKey)
|
||||
blacklistVM.list = blackList[0].users
|
||||
blacklistVM.titleName = '黑名单'
|
||||
}
|
||||
export const loadlikeButton = async () => {
|
||||
const LikeButton = await import('./like.vue').then(m => m.default)
|
||||
const blackList = getData(BlackListDataKey)
|
||||
const likebuttonVM: Vue & { list: string[] } = mountVueComponent(LikeButton)
|
||||
likebuttonVM.list = blackList[0].users
|
||||
const bg = (await select('#app')) as HTMLElement
|
||||
bg.insertAdjacentElement('afterbegin', likebuttonVM.$el)
|
||||
}
|
||||
|
||||
export const loadBlackList = async () => {
|
||||
if (blacklistVM) {
|
||||
return false
|
||||
}
|
||||
const blackList = await import('./blackList.vue').then(m => m.default)
|
||||
blacklistVM = mountVueComponent(blackList)
|
||||
document.body.insertAdjacentElement('beforeend', blacklistVM.$el)
|
||||
return true
|
||||
}
|
||||
|
||||
export const toggleBlackList = async () => {
|
||||
if (!blacklistVM) {
|
||||
await loadBlackList()
|
||||
}
|
||||
blacklistVM?.toggle()
|
||||
}
|
||||
Loading…
Reference in New Issue
Block a user