mirror of
https://github.com/VueTorrent/VueTorrent.git
synced 2025-03-14 12:10:18 +03:00
perf(rss): Improve duplicate RSS article handling (#1191)
This commit is contained in:
parent
3f34cfcfdb
commit
ee01382771
3 changed files with 57 additions and 47 deletions
|
@ -52,7 +52,7 @@ function downloadArticle(item: RssArticle) {
|
|||
}
|
||||
|
||||
async function markAsRead(item: RssArticle) {
|
||||
await rssStore.markArticleAsRead(item)
|
||||
await rssStore.markArticleAsRead(item.id)
|
||||
}
|
||||
|
||||
async function markAllAsRead() {
|
||||
|
@ -121,28 +121,28 @@ onUnmounted(() => {
|
|||
|
||||
<v-list-item>
|
||||
<v-list>
|
||||
<template v-for="(feed, index) in paginatedResults">
|
||||
<template v-for="(article, index) in paginatedResults">
|
||||
<v-divider v-if="index > 0" color="white" />
|
||||
|
||||
<v-list-item :class="{ 'rss-read': feed.isRead }" @click="showDescription(feed)">
|
||||
<v-list-item :class="{ 'rss-read': article.isRead }" @click="showDescription(article)">
|
||||
<div class="d-flex">
|
||||
<div>
|
||||
<v-list-item-title class="text-wrap">{{ feed.title }}</v-list-item-title>
|
||||
<v-list-item-title class="text-wrap">{{ article.title }}</v-list-item-title>
|
||||
|
||||
<v-list-item-subtitle class="d-block">
|
||||
<div>{{ feed.parsedDate.toLocaleString() }}</div>
|
||||
<div v-if="feed.feedName">{{ t('rssArticles.item.feedName', { name: feed.feedName }) }}</div>
|
||||
<div v-if="feed.author">{{ t('rssArticles.item.author', { author: feed.author }) }}</div>
|
||||
<div v-if="feed.category">{{ t('rssArticles.item.category', { category: feed.category }) }}</div>
|
||||
<div>{{ article.parsedDate.toLocaleString() }}</div>
|
||||
<div>{{ t('rssArticles.item.feedName', { name: rssStore.getFeedNames(article.id).join(' | ') }) }}</div>
|
||||
<div v-if="article.author">{{ t('rssArticles.item.author', { author: article.author }) }}</div>
|
||||
<div v-if="article.category">{{ t('rssArticles.item.category', { category: article.category }) }}</div>
|
||||
</v-list-item-subtitle>
|
||||
</div>
|
||||
|
||||
<v-spacer />
|
||||
|
||||
<div class="d-flex flex-column">
|
||||
<v-btn icon="mdi-open-in-new" variant="text" @click.stop="openLink(feed.link)" />
|
||||
<v-btn color="accent" icon="mdi-check" variant="text" @click.stop="markAsRead(feed)" />
|
||||
<v-btn icon="mdi-download" variant="text" @click.stop="downloadArticle(feed)" />
|
||||
<v-btn icon="mdi-open-in-new" variant="text" @click.stop="openLink(article.link)" />
|
||||
<v-btn color="accent" icon="mdi-check" variant="text" @click.stop="markAsRead(article)" />
|
||||
<v-btn icon="mdi-download" variant="text" @click.stop="downloadArticle(article)" />
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
|
|
@ -2,7 +2,7 @@ import { qbit } from '@/services'
|
|||
import { Feed, FeedRule } from '@/types/qbit/models'
|
||||
import { RssArticle } from '@/types/vuetorrent'
|
||||
import { defineStore } from 'pinia'
|
||||
import { computed, reactive, ref } from 'vue'
|
||||
import { computed, reactive, ref, shallowRef, triggerRef } from 'vue'
|
||||
|
||||
export const useRssStore = defineStore(
|
||||
'rss',
|
||||
|
@ -10,32 +10,16 @@ export const useRssStore = defineStore(
|
|||
const feeds = ref<Feed[]>([])
|
||||
const rules = ref<FeedRule[]>([])
|
||||
|
||||
const _articles = shallowRef<RssArticle[]>([])
|
||||
const keyMap = shallowRef<Record<string, string[]>>({})
|
||||
|
||||
const filters = reactive({
|
||||
title: '',
|
||||
unread: false
|
||||
})
|
||||
|
||||
const articles = computed(() => {
|
||||
const articles: RssArticle[] = []
|
||||
const keySet = new Set<string>()
|
||||
|
||||
feeds.value.forEach((feed: Feed) => {
|
||||
if (!feed.articles) return
|
||||
|
||||
feed.articles.forEach(article => {
|
||||
if (keySet.has(article.id) || (filters.unread && article.isRead)) return
|
||||
|
||||
keySet.add(article.id)
|
||||
articles.push({
|
||||
feedName: feed.name,
|
||||
parsedDate: new Date(article.date),
|
||||
...article
|
||||
})
|
||||
})
|
||||
})
|
||||
|
||||
return articles
|
||||
})
|
||||
const unreadArticles = computed(() => _articles.value.filter(article => !article.isRead))
|
||||
const articles = computed(() => filters.unread ? unreadArticles.value : _articles.value)
|
||||
|
||||
async function refreshFeed(feedName: string) {
|
||||
await qbit.refreshFeed(feedName)
|
||||
|
@ -67,25 +51,50 @@ export const useRssStore = defineStore(
|
|||
|
||||
async function fetchFeeds() {
|
||||
feeds.value = await qbit.getFeeds(true)
|
||||
|
||||
_articles.value = []
|
||||
keyMap.value = {}
|
||||
|
||||
feeds.value.forEach((feed: Feed) => {
|
||||
if (!feed.articles) return
|
||||
|
||||
feed.articles.forEach(article => {
|
||||
if (keyMap.value[article.id]) {
|
||||
keyMap.value[article.id].push(feed.name)
|
||||
} else {
|
||||
keyMap.value[article.id] = [feed.name]
|
||||
_articles.value.push({
|
||||
parsedDate: new Date(article.date),
|
||||
...article
|
||||
})
|
||||
}
|
||||
})
|
||||
})
|
||||
|
||||
triggerRef(_articles)
|
||||
triggerRef(keyMap)
|
||||
}
|
||||
|
||||
async function markArticleAsRead(article: RssArticle) {
|
||||
await qbit.markAsRead(article.feedName, article.id)
|
||||
function getFeedNames(articleId: string) {
|
||||
return keyMap.value[articleId]
|
||||
}
|
||||
|
||||
const feed = feeds.value.find(feed => feed.name === article.feedName)
|
||||
if (!feed || !feed.articles) return
|
||||
const art = feed.articles.find(a => a.id === article.id)
|
||||
if (!art) return
|
||||
art.isRead = true
|
||||
async function markArticleAsRead(articleId: string) {
|
||||
const feedNames = keyMap.value[articleId]
|
||||
if (!feedNames) return
|
||||
|
||||
const promises: Promise<any>[] = []
|
||||
feedNames.forEach(feedName => promises.push(qbit.markAsRead(feedName, articleId)))
|
||||
await Promise.all(promises)
|
||||
|
||||
_articles.value.forEach(article => {
|
||||
if (article.id === articleId) article.isRead = true
|
||||
})
|
||||
triggerRef(_articles)
|
||||
}
|
||||
|
||||
async function markAllAsRead() {
|
||||
feeds.value.forEach(feed => {
|
||||
if (!feed.articles) return
|
||||
feed.articles.forEach(async article => {
|
||||
article.isRead || (await qbit.markAsRead(feed.name, article.id))
|
||||
})
|
||||
})
|
||||
await Promise.all(unreadArticles.value.map(article => article.id).map(markArticleAsRead))
|
||||
await fetchFeeds()
|
||||
}
|
||||
|
||||
|
@ -102,6 +111,7 @@ export const useRssStore = defineStore(
|
|||
rules,
|
||||
filters,
|
||||
articles,
|
||||
unreadArticles,
|
||||
refreshFeed,
|
||||
createFeed,
|
||||
setRule,
|
||||
|
@ -110,6 +120,7 @@ export const useRssStore = defineStore(
|
|||
deleteFeed,
|
||||
deleteRule,
|
||||
fetchFeeds,
|
||||
getFeedNames,
|
||||
markArticleAsRead,
|
||||
markAllAsRead,
|
||||
fetchRules,
|
||||
|
|
|
@ -1,6 +1,5 @@
|
|||
import { FeedArticle } from '@/types/qbit/models'
|
||||
|
||||
export interface RssArticle extends FeedArticle {
|
||||
feedName: string
|
||||
parsedDate: Date
|
||||
}
|
||||
|
|
Loading…
Add table
Reference in a new issue