Filter feeds using user patterns (#584)

This commit is contained in:
the1812 2021-03-29 17:57:56 +08:00
parent 679b89d88a
commit d7a6257c98
6 changed files with 107 additions and 87 deletions

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View File

@ -387,6 +387,34 @@ class FeedsCardsManager extends EventTarget {
} }
export const feedsCardsManager = new FeedsCardsManager() export const feedsCardsManager = new FeedsCardsManager()
export const isCardBlocked = (card: Pick<FeedsCard, 'text' | 'username'>) => {
if (!settings.feedsFilter) {
return false
}
const testPattern = (pattern: Pattern, text: string) => {
if (pattern.startsWith('/') && pattern.endsWith('/')) {
return new RegExp(pattern.slice(1, pattern.length - 1)).test(text)
}
return text.includes(pattern)
}
return settings.feedsFilterPatterns.some(pattern => {
const upNameMatch = pattern.match(/(.+) up:([^ ]+)/)
if (upNameMatch) {
return (
testPattern(upNameMatch[1], card.text) &&
testPattern(upNameMatch[2], card.username)
)
}
return testPattern(pattern, card.text)
})
}
export const isVideoCardBlocked = (card: Pick<VideoCardInfo, 'title' | 'dynamic' | 'upName'>) => {
return isCardBlocked({
text: card.title + (card.dynamic ?? ''),
username: card.upName,
})
}
export const getVideoFeeds = async (type: 'video' | 'bangumi' = 'video'): Promise<VideoCardInfo[]> => { export const getVideoFeeds = async (type: 'video' | 'bangumi' = 'video'): Promise<VideoCardInfo[]> => {
if (!getUID()) { if (!getUID()) {
return [] return []
@ -397,69 +425,72 @@ export const getVideoFeeds = async (type: 'video' | 'bangumi' = 'video'): Promis
if (json.code !== 0) { if (json.code !== 0) {
throw new Error(json.message) throw new Error(json.message)
} }
if (type === 'video') { const cards = (() => {
return _.uniqBy(json.data.cards.map( const jsonCards = json.data.cards as any[]
(c: any): VideoCardInfo => { if (type === 'video') {
const card = JSON.parse(c.card) return _.uniqBy(jsonCards.map(
const topics = _.get(c, 'display.topic_info.topic_details', []).map( (c: any): VideoCardInfo => {
(it: any) => { const card = JSON.parse(c.card)
return { const topics = _.get(c, 'display.topic_info.topic_details', []).map(
id: it.topic_id, (it: any) => {
name: it.topic_name return {
id: it.topic_id,
name: it.topic_name
}
} }
} )
) return {
return { id: c.desc.dynamic_id_str,
id: c.desc.dynamic_id_str, aid: card.aid,
aid: card.aid, bvid: c.desc.bvid || card.bvid,
bvid: c.desc.bvid || card.bvid, title: card.title,
title: card.title, upID: c.desc.user_profile.info.uid,
upID: c.desc.user_profile.info.uid, upName: c.desc.user_profile.info.uname,
upName: c.desc.user_profile.info.uname, upFaceUrl: c.desc.user_profile.info.face,
upFaceUrl: c.desc.user_profile.info.face, coverUrl: card.pic,
coverUrl: card.pic, description: card.desc,
description: card.desc, timestamp: c.timestamp,
timestamp: c.timestamp, time: new Date(c.timestamp * 1000),
time: new Date(c.timestamp * 1000), topics,
topics, dynamic: card.dynamic,
dynamic: card.dynamic, like: formatCount(c.desc.like),
like: formatCount(c.desc.like), duration: card.duration,
duration: card.duration, durationText: formatDuration(card.duration, 0),
durationText: formatDuration(card.duration, 0), playCount: formatCount(card.stat.view),
playCount: formatCount(card.stat.view), danmakuCount: formatCount(card.stat.danmaku),
danmakuCount: formatCount(card.stat.danmaku), watchlater: store.state.watchlaterList.includes(card.aid)
watchlater: store.state.watchlaterList.includes(card.aid) } as VideoCardInfo
} }
} ), it => it.aid)
), it => it.aid) } else if (type === 'bangumi') {
} else if (type === 'bangumi') { return jsonCards.map(
return json.data.cards.map( (c: any): VideoCardInfo => {
(c: any): VideoCardInfo => { const card = JSON.parse(c.card)
const card = JSON.parse(c.card) return {
return { id: c.desc.dynamic_id_str,
id: c.desc.dynamic_id_str, aid: card.aid,
aid: card.aid, bvid: c.desc.bvid || card.bvid,
bvid: c.desc.bvid || card.bvid, epID: card.episode_id,
epID: card.episode_id, title: card.new_desc,
title: card.new_desc, upName: card.apiSeasonInfo.title,
upName: card.apiSeasonInfo.title, upFaceUrl: card.apiSeasonInfo.cover,
upFaceUrl: card.apiSeasonInfo.cover, coverUrl: card.cover,
coverUrl: card.cover, description: '',
description: '', timestamp: c.timestamp,
timestamp: c.timestamp, time: new Date(c.timestamp * 1000),
time: new Date(c.timestamp * 1000), like: formatCount(c.desc.like),
like: formatCount(c.desc.like), durationText: '',
durationText: '', playCount: formatCount(card.play_count),
playCount: formatCount(card.play_count), danmakuCount: formatCount(card.bullet_count),
danmakuCount: formatCount(card.bullet_count), watchlater: false,
watchlater: false, } as VideoCardInfo
} }
} )
) } else {
return []
} else { }
return [] })()
} return cards.filter(c => !isVideoCardBlocked(c))
} }
export const forEachFeedsCard = (callback: FeedsCardCallback) => { export const forEachFeedsCard = (callback: FeedsCardCallback) => {
@ -524,5 +555,7 @@ export default {
getVideoFeeds, getVideoFeeds,
forEachFeedsCard, forEachFeedsCard,
addMenuItem, addMenuItem,
isCardBlocked,
isVideoCardBlocked,
}, },
} }

View File

@ -110,26 +110,9 @@ export default {
} }
}, },
methods: { methods: {
updateCard(card: FeedsCard) { async updateCard(card: FeedsCard) {
const testPattern = (pattern: Pattern, text: string) => { const { isCardBlocked } = await import('../feeds-apis')
if (pattern.startsWith('/') && pattern.endsWith('/')) { if (isCardBlocked(card)) {
return new RegExp(pattern.slice(1, pattern.length - 1)).test(text)
}
return text.includes(pattern)
}
const block: boolean = (() => {
return settings.feedsFilterPatterns.some(pattern => {
const upNameMatch = pattern.match(/(.+) up:([^ ]+)/)
if (upNameMatch) {
return (
testPattern(upNameMatch[1], card.text) &&
testPattern(upNameMatch[2], card.username)
)
}
return testPattern(pattern, card.text)
})
})()
if (block) {
card.element.classList.add('pattern-block') card.element.classList.add('pattern-block')
} else { } else {
card.element.classList.remove('pattern-block') card.element.classList.remove('pattern-block')

View File

@ -163,6 +163,7 @@ export class Activities extends NavbarComponent {
this.setNotifyCount(json.data.update_num) this.setNotifyCount(json.data.update_num)
} }
async init() { async init() {
const { isVideoCardBlocked, isCardBlocked } = await import('../../../activity/feeds-apis')
Vue.component('activity-loading', { Vue.component('activity-loading', {
template: /*html*/` template: /*html*/`
<div v-if="loading" class="loading"> <div v-if="loading" class="loading">
@ -321,6 +322,7 @@ export class Activities extends NavbarComponent {
.sort((a, b) => { .sort((a, b) => {
return b.id > a.id ? 1 : -1 return b.id > a.id ? 1 : -1
}) })
.filter(c => !isVideoCardBlocked(c))
if (cards.length === 0) { if (cards.length === 0) {
this.hasMoreContent = false this.hasMoreContent = false
} }
@ -417,7 +419,7 @@ export class Activities extends NavbarComponent {
</div> </div>
`, `,
handleJson: async function (json) { handleJson: async function (json) {
const cards = _.get(json, 'data.cards', []).map((card: any) => { const cards = _.get<any[]>(json, 'data.cards', []).map((card: any) => {
const cardJson = JSON.parse(card.card) const cardJson = JSON.parse(card.card)
return { return {
title: cardJson.apiSeasonInfo.title, title: cardJson.apiSeasonInfo.title,
@ -428,11 +430,12 @@ export class Activities extends NavbarComponent {
id: card.desc.dynamic_id_str, id: card.desc.dynamic_id_str,
get new() { return Activities.isNewID(this.id) }, get new() { return Activities.isNewID(this.id) },
} }
}) as { id: string }[] })
this.cards = _.uniqBy(cards.concat(this.cards), it => it.id) this.cards = _.uniqBy(cards.concat(this.cards), it => it.id)
.sort((a, b) => { .sort((a, b) => {
return b.id > a.id ? 1 : -1 return b.id > a.id ? 1 : -1
}) })
.filter(c => !isCardBlocked({ text: c.epTitle, username: c.title }))
if (cards.length === 0) { if (cards.length === 0) {
this.hasMoreContent = false this.hasMoreContent = false
} }
@ -479,7 +482,7 @@ export class Activities extends NavbarComponent {
</div> </div>
`, `,
handleJson: async function (json) { handleJson: async function (json) {
const cards = _.get(json, 'data.cards', []).map((card: any) => { const cards = _.get<any[]>(json, 'data.cards', []).map((card: any) => {
const cardJson = JSON.parse(card.card) const cardJson = JSON.parse(card.card)
return { return {
covers: cardJson.image_urls, covers: cardJson.image_urls,
@ -493,11 +496,12 @@ export class Activities extends NavbarComponent {
id: card.desc.dynamic_id_str, id: card.desc.dynamic_id_str,
get new() { return Activities.isNewID(this.id) }, get new() { return Activities.isNewID(this.id) },
} }
}) as { id: string }[] })
this.cards = _.uniqBy(cards.concat(this.cards), it => it.id) this.cards = _.uniqBy(cards.concat(this.cards), it => it.id)
.sort((a, b) => { .sort((a, b) => {
return b.id > a.id ? 1 : -1 return b.id > a.id ? 1 : -1
}) })
.filter(c => !isVideoCardBlocked(c))
if (cards.length === 0) { if (cards.length === 0) {
this.hasMoreContent = false this.hasMoreContent = false
} }