diff --git a/src/renderer/components/distraction-settings/distraction-settings.js b/src/renderer/components/distraction-settings/distraction-settings.js index 659409d12f84c..7f5e3741fc962 100644 --- a/src/renderer/components/distraction-settings/distraction-settings.js +++ b/src/renderer/components/distraction-settings/distraction-settings.js @@ -92,6 +92,9 @@ export default defineComponent({ hideSubscriptionsLive: function () { return this.$store.getters.getHideSubscriptionsLive }, + hideSubscriptionsCommunity: function() { + return this.$store.getters.getHideSubscriptionsCommunity + }, showDistractionFreeTitles: function () { return this.$store.getters.getShowDistractionFreeTitles }, @@ -155,6 +158,7 @@ export default defineComponent({ 'updateHideSubscriptionsVideos', 'updateHideSubscriptionsShorts', 'updateHideSubscriptionsLive', + 'updateHideSubscriptionsCommunity', 'updateBlurThumbnails' ]) } diff --git a/src/renderer/components/distraction-settings/distraction-settings.vue b/src/renderer/components/distraction-settings/distraction-settings.vue index 4989782c0eda3..5b6f06db4a4a1 100644 --- a/src/renderer/components/distraction-settings/distraction-settings.vue +++ b/src/renderer/components/distraction-settings/distraction-settings.vue @@ -66,6 +66,12 @@ :tooltip="hideLiveStreams ? hideSubscriptionsLiveTooltip : ''" v-on="!hideLiveStreams ? { change: updateHideSubscriptionsLive } : {}" /> +

{ + authorThumbnails.forEach(thumbnail => { thumbnail.url = youtubeImageUrlToInvidious(thumbnail.url) - return thumbnail }) } else { - authorThumbnails = authorThumbnails.map(thumbnail => { + authorThumbnails.forEach(thumbnail => { if (thumbnail.url.startsWith('//')) { thumbnail.url = 'https:' + thumbnail.url } - return thumbnail }) } this.authorThumbnails = authorThumbnails @@ -104,6 +103,7 @@ export default defineComponent({ this.commentCount = this.data.commentCount this.type = (this.data.postContent !== null && this.data.postContent !== undefined) ? this.data.postContent.type : 'text' this.author = this.data.author + this.authorId = this.data.authorId this.isLoading = false }, diff --git a/src/renderer/components/ft-community-post/ft-community-post.scss b/src/renderer/components/ft-community-post/ft-community-post.scss index 1f15d6d6ae529..7c7a6a8470ac4 100644 --- a/src/renderer/components/ft-community-post/ft-community-post.scss +++ b/src/renderer/components/ft-community-post/ft-community-post.scss @@ -34,6 +34,10 @@ font-weight: bold; margin-block: 5px 0; margin-inline: 5px 6px; + .authorNameLink { + color: inherit; + text-decoration: none; + } } .publishedText { diff --git a/src/renderer/components/ft-community-post/ft-community-post.vue b/src/renderer/components/ft-community-post/ft-community-post.vue index 870a66807e553..986591cf6f23c 100644 --- a/src/renderer/components/ft-community-post/ft-community-post.vue +++ b/src/renderer/components/ft-community-post/ft-community-post.vue @@ -8,16 +8,43 @@
- + + +

- {{ author }} + + {{ author }} + +

{ + const cacheEntry = this.$store.getters.getPostsCacheByChannel(channel.id) + if (cacheEntry == null) { return } + + entries.push(cacheEntry) + }) + return entries + }, + postCacheForAllActiveProfileChannelsPresent() { + if (this.cacheEntriesForAllActiveProfileChannels.length === 0) { return false } + if (this.cacheEntriesForAllActiveProfileChannels.length < this.activeSubscriptionList.length) { return false } + + return this.cacheEntriesForAllActiveProfileChannels.every((cacheEntry) => { + return cacheEntry.posts != null + }) + }, + + activeSubscriptionList: function () { + return this.activeProfile.subscriptions + }, + + fetchSubscriptionsAutomatically: function() { + return this.$store.getters.getFetchSubscriptionsAutomatically + }, + }, + watch: { + activeProfile: async function (_) { + this.isLoading = true + this.loadpostsFromCacheSometimes() + }, + }, + mounted: async function () { + this.isLoading = true + + this.loadpostsFromCacheSometimes() + }, + methods: { + loadpostsFromCacheSometimes() { + // This method is called on view visible + if (this.postCacheForAllActiveProfileChannelsPresent) { + this.loadPostsFromCacheForAllActiveProfileChannels() + return + } + + this.maybeLoadPostsForSubscriptionsFromRemote() + }, + + async loadPostsFromCacheForAllActiveProfileChannels() { + const postList = [] + this.activeSubscriptionList.forEach((channel) => { + const channelCacheEntry = this.$store.getters.getPostsCacheByChannel(channel.id) + + postList.push(...channelCacheEntry.posts) + }) + + postList.sort((a, b) => { + return calculatePublishedDate(b.publishedText) - calculatePublishedDate(a.publishedText) + }) + + this.postList = postList + this.isLoading = false + }, + + loadPostsForSubscriptionsFromRemote: async function () { + if (this.activeSubscriptionList.length === 0) { + this.isLoading = false + this.postList = [] + return + } + + const channelsToLoadFromRemote = this.activeSubscriptionList + const postList = [] + let channelCount = 0 + this.isLoading = true + + this.updateShowProgressBar(true) + this.setProgressBarPercentage(0) + this.attemptedFetch = true + + this.errorChannels = [] + const postListFromRemote = (await Promise.all(channelsToLoadFromRemote.map(async (channel) => { + let posts = [] + if (!process.env.IS_ELECTRON || this.backendPreference === 'invidious') { + posts = await this.getChannelPostsInvidious(channel) + } else { + posts = await this.getChannelPostsLocal(channel) + } + + channelCount++ + const percentageComplete = (channelCount / channelsToLoadFromRemote.length) * 100 + this.setProgressBarPercentage(percentageComplete) + + this.updateSubscriptionPostsCacheByChannel({ + channelId: channel.id, + posts: posts, + }) + return posts + }))).flatMap((o) => o) + postList.push(...postListFromRemote) + postList.sort((a, b) => { + return calculatePublishedDate(b.publishedText) - calculatePublishedDate(a.publishedText) + }) + + this.postList = postList + this.isLoading = false + this.updateShowProgressBar(false) + }, + + maybeLoadPostsForSubscriptionsFromRemote: async function () { + if (this.fetchSubscriptionsAutomatically) { + // `this.isLoading = false` is called inside `loadPostsForSubscriptionsFromRemote` when needed + await this.loadPostsForSubscriptionsFromRemote() + } else { + this.postList = [] + this.attemptedFetch = false + this.isLoading = false + } + }, + + getChannelPostsLocal: async function (channel) { + try { + const entries = await getLocalChannelCommunity(channel.id) + + if (entries === null) { + this.errorChannels.push(channel) + return [] + } + entries.forEach(post => { + post.authorId = channel.id + }) + return entries + } catch (err) { + console.error(err) + const errorMessage = this.$t('Local API Error (Click to copy)') + showToast(`${errorMessage}: ${err}`, 10000, () => { + copyToClipboard(err) + }) + if (this.backendPreference === 'local' && this.backendFallback) { + showToast(this.$t('Falling back to Invidious API')) + return await this.getChannelPostsInvidious(channel) + } + return [] + } + }, + + getChannelPostsInvidious: function (channel) { + return new Promise((resolve, reject) => { + invidiousGetCommunityPosts(channel.id).then(result => { + result.posts.forEach(post => { + post.authorId = channel.id + }) + resolve(result.posts) + }).catch((err) => { + console.error(err) + const errorMessage = this.$t('Invidious API Error (Click to copy)') + showToast(`${errorMessage}: ${err}`, 10000, () => { + copyToClipboard(err) + }) + if (process.env.IS_ELECTRON && this.backendPreference === 'invidious' && this.backendFallback) { + showToast(this.$t('Falling back to the local API')) + resolve(this.getChannelPostsLocal(channel)) + } else { + resolve([]) + } + }) + }) + }, + + ...mapActions([ + 'updateShowProgressBar', + 'updateSubscriptionPostsCacheByChannel', + ]), + + ...mapMutations([ + 'setProgressBarPercentage' + ]) + } +}) diff --git a/src/renderer/components/subscriptions-community/subscriptions-community.vue b/src/renderer/components/subscriptions-community/subscriptions-community.vue new file mode 100644 index 0000000000000..8c2e504c25ef1 --- /dev/null +++ b/src/renderer/components/subscriptions-community/subscriptions-community.vue @@ -0,0 +1,13 @@ + + +