Merge pull request #4343 from CrazyboyQCD/preview-features

增强点赞功能
This commit is contained in:
Grant Howard 2023-07-25 23:58:16 +08:00 committed by GitHub
commit 81cbb79dfd
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
6 changed files with 454 additions and 16 deletions

View 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>

View File

@ -1 +1,4 @@
进入视频 / 查看动态时, 自动点赞.
进入视频 / 查看动态时, 自动点赞\
无法触发未加载动态的点赞,当启用手动对动态点赞后可手动触发,启用后不会触发动态自动点赞\
安装快捷键扩展后可以点击【l】键或【L】键触发\
还可以添加动态点赞的黑名单\

View File

@ -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'
})
},
},
})

View 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
// forEachFeedsCarddqa
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>

View 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>

View 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()
}