From 13e7870babd24bf505da89b5093b82d4d08859ff Mon Sep 17 00:00:00 2001 From: PikachuEXE Date: Tue, 28 May 2024 08:27:59 +0800 Subject: [PATCH 01/10] * Implement persistent subscription cache --- src/constants.js | 20 +- src/datastores/handlers/base.js | 52 +++++ src/datastores/handlers/electron.js | 66 ++++++- src/datastores/handlers/index.js | 3 +- src/datastores/handlers/web.js | 49 ++++- src/datastores/index.js | 1 + src/main/index.js | 78 ++++++++ src/renderer/App.js | 2 + .../subscriptions-community.js | 35 ++-- .../subscriptions-live/subscriptions-live.js | 37 ++-- .../subscriptions-shorts.js | 36 ++-- .../subscriptions-videos.js | 35 ++-- src/renderer/store/modules/profiles.js | 9 +- src/renderer/store/modules/settings.js | 34 ++++ src/renderer/store/modules/subscriptions.js | 185 +++++++++++++++--- 15 files changed, 554 insertions(+), 88 deletions(-) diff --git a/src/constants.js b/src/constants.js index 8eb0089b512e..fd6371e2bbae 100644 --- a/src/constants.js +++ b/src/constants.js @@ -17,11 +17,13 @@ const IpcChannels = { DB_HISTORY: 'db-history', DB_PROFILES: 'db-profiles', DB_PLAYLISTS: 'db-playlists', + DB_SUBSCRIPTIONS: 'db-subscriptions', SYNC_SETTINGS: 'sync-settings', SYNC_HISTORY: 'sync-history', SYNC_PROFILES: 'sync-profiles', SYNC_PLAYLISTS: 'sync-playlists', + SYNC_SUBSCRIPTIONS: 'sync-subscriptions', GET_REPLACE_HTTP_CACHE: 'get-replace-http-cache', TOGGLE_REPLACE_HTTP_CACHE: 'toggle-replace-http-cache', @@ -52,7 +54,14 @@ const DBActions = { DELETE_VIDEO_ID: 'db-action-playlists-delete-video-by-playlist-name', DELETE_VIDEO_IDS: 'db-action-playlists-delete-video-ids', DELETE_ALL_VIDEOS: 'db-action-playlists-delete-all-videos', - } + }, + + SUBSCRIPTIONS: { + UPDATE_VIDEOS_BY_CHANNEL: 'db-action-subscriptions-update-videos-by-channel', + UPDATE_LIVE_STREAMS_BY_CHANNEL: 'db-action-subscriptions-update-live-streams-by-channel', + UPDATE_SHORTS_BY_CHANNEL: 'db-action-subscriptions-update-shorts-by-channel', + UPDATE_COMMUNITY_POSTS_BY_CHANNEL: 'db-action-subscriptions-update-community-posts-by-channel', + }, } const SyncEvents = { @@ -71,7 +80,14 @@ const SyncEvents = { PLAYLISTS: { UPSERT_VIDEO: 'sync-playlists-upsert-video', DELETE_VIDEO: 'sync-playlists-delete-video', - } + }, + + SUBSCRIPTIONS: { + UPDATE_VIDEOS_BY_CHANNEL: 'sync-subscriptions-update-videos-by-channel', + UPDATE_LIVE_STREAMS_BY_CHANNEL: 'sync-subscriptions-update-live-streams-by-channel', + UPDATE_SHORTS_BY_CHANNEL: 'sync-subscriptions-update-shorts-by-channel', + UPDATE_COMMUNITY_POSTS_BY_CHANNEL: 'sync-subscriptions-update-community-posts-by-channel', + }, } // Utils diff --git a/src/datastores/handlers/base.js b/src/datastores/handlers/base.js index 7c2eb4ec0539..5cf4b66cc11a 100644 --- a/src/datastores/handlers/base.js +++ b/src/datastores/handlers/base.js @@ -183,12 +183,63 @@ class Playlists { } } +class Subscriptions { + static find() { + return db.subscriptions.findAsync({}) + } + + static updateVideosByChannelId({ channelId, entries, timestamp }) { + return db.subscriptions.updateAsync( + { _id: channelId }, + { $set: { videos: entries, videosTimestamp: timestamp } }, + { upsert: true } + ) + } + + static updateLiveStreamsByChannelId({ channelId, entries, timestamp }) { + return db.subscriptions.updateAsync( + { _id: channelId }, + { $set: { liveStreams: entries, liveStreamsTimestamp: timestamp } }, + { upsert: true } + ) + } + + static updateShortsByChannelId({ channelId, entries, timestamp }) { + return db.subscriptions.updateAsync( + { _id: channelId }, + { $set: { shorts: entries, shortsTimestamp: timestamp } }, + { upsert: true } + ) + } + + static updateCommunityPostsByChannelId({ channelId, entries, timestamp }) { + return db.subscriptions.updateAsync( + { _id: channelId }, + { $set: { communityPosts: entries, communityPostsTimestamp: timestamp } }, + { upsert: true } + ) + } + + static deleteMultipleChannels(channelIds) { + return db.subscriptions.removeAsync({ _id: { $in: channelIds } }, { multi: true }) + } + + static deleteAll() { + return db.subscriptions.removeAsync({}, { multi: true }) + } + + static persist() { + return db.subscriptions.compactDatafileAsync() + } +} + function compactAllDatastores() { return Promise.allSettled([ Settings.persist(), History.persist(), Profiles.persist(), Playlists.persist(), + Subscriptions.persist(), ]) } @@ -197,6 +248,7 @@ export { History as history, Profiles as profiles, Playlists as playlists, + Subscriptions as subscriptions, compactAllDatastores, } diff --git a/src/datastores/handlers/electron.js b/src/datastores/handlers/electron.js index 31e8c96305ec..79875683651d 100644 --- a/src/datastores/handlers/electron.js +++ b/src/datastores/handlers/electron.js @@ -205,9 +205,73 @@ class Playlists { } } +class Subscriptions { + static find() { + return ipcRenderer.invoke( + IpcChannels.DB_SUBSCRIPTIONS, + { action: DBActions.GENERAL.FIND } + ) + } + + static updateVideosByChannelId({ channelId, entries, timestamp }) { + return ipcRenderer.invoke( + IpcChannels.DB_SUBSCRIPTIONS, + { + action: DBActions.SUBSCRIPTIONS.UPDATE_VIDEOS_BY_CHANNEL, + data: { channelId, entries, timestamp }, + } + ) + } + + static updateLiveStreamsByChannelId({ channelId, entries, timestamp }) { + return ipcRenderer.invoke( + IpcChannels.DB_SUBSCRIPTIONS, + { + action: DBActions.SUBSCRIPTIONS.UPDATE_LIVE_STREAMS_BY_CHANNEL, + data: { channelId, entries, timestamp }, + } + ) + } + + static updateShortsByChannelId({ channelId, entries, timestamp }) { + return ipcRenderer.invoke( + IpcChannels.DB_SUBSCRIPTIONS, + { + action: DBActions.SUBSCRIPTIONS.UPDATE_SHORTS_BY_CHANNEL, + data: { channelId, entries, timestamp }, + } + ) + } + + static updateCommunityPostsByChannelId({ channelId, entries, timestamp }) { + return ipcRenderer.invoke( + IpcChannels.DB_SUBSCRIPTIONS, + { + action: DBActions.SUBSCRIPTIONS.UPDATE_COMMUNITY_POSTS_BY_CHANNEL, + data: { channelId, entries, timestamp }, + } + ) + } + + static deleteMultipleChannels(channelIds) { + return ipcRenderer.invoke( + IpcChannels.DB_SUBSCRIPTIONS, + { action: DBActions.GENERAL.DELETE_MULTIPLE, data: channelIds } + ) + } + + static deleteAll() { + return ipcRenderer.invoke( + IpcChannels.DB_SUBSCRIPTIONS, + { action: DBActions.GENERAL.DELETE_ALL } + ) + } +} + export { Settings as settings, History as history, Profiles as profiles, - Playlists as playlists + Playlists as playlists, + Subscriptions as subscriptions, } diff --git a/src/datastores/handlers/index.js b/src/datastores/handlers/index.js index df6ebffd9d80..a1c1050870d8 100644 --- a/src/datastores/handlers/index.js +++ b/src/datastores/handlers/index.js @@ -2,5 +2,6 @@ export { settings as DBSettingHandlers, history as DBHistoryHandlers, profiles as DBProfileHandlers, - playlists as DBPlaylistHandlers + playlists as DBPlaylistHandlers, + subscriptions as DBSubscriptionsHandlers, } from 'DB_HANDLERS_ELECTRON_RENDERER_OR_WEB' diff --git a/src/datastores/handlers/web.js b/src/datastores/handlers/web.js index d5feccc998d0..6f9d9cf879df 100644 --- a/src/datastores/handlers/web.js +++ b/src/datastores/handlers/web.js @@ -118,9 +118,56 @@ class Playlists { } } +class Subscriptions { + static find() { + return baseHandlers.subscriptions.find() + } + + static updateVideosByChannelId({ channelId, entries, timestamp }) { + return baseHandlers.subscriptions.updateVideosByChannelId({ + channelId, + entries, + timestamp, + }) + } + + static updateLiveStreamsByChannelId({ channelId, entries, timestamp }) { + return baseHandlers.subscriptions.updateLiveStreamsByChannelId({ + channelId, + entries, + timestamp, + }) + } + + static updateShortsByChannelId({ channelId, entries, timestamp }) { + return baseHandlers.subscriptions.updateShortsByChannelId({ + channelId, + entries, + timestamp, + }) + } + + static updateCommunityPostsByChannelId({ channelId, entries, timestamp }) { + return baseHandlers.subscriptions.updateCommunityPostsByChannelId({ + channelId, + entries, + timestamp, + }) + } + + static deleteMultipleChannels(channelIds) { + return baseHandlers.subscriptions.deleteMultipleChannels(channelIds) + } + + static deleteAll() { + return baseHandlers.subscriptions.deleteAll() + } +} + export { Settings as settings, History as history, Profiles as profiles, - Playlists as playlists + Playlists as playlists, + Subscriptions as subscriptions, } diff --git a/src/datastores/index.js b/src/datastores/index.js index 442fed6497bf..a2a16c870417 100644 --- a/src/datastores/index.js +++ b/src/datastores/index.js @@ -26,3 +26,4 @@ export const settings = new Datastore({ filename: dbPath('settings'), autoload: export const profiles = new Datastore({ filename: dbPath('profiles'), autoload: true }) export const playlists = new Datastore({ filename: dbPath('playlists'), autoload: true }) export const history = new Datastore({ filename: dbPath('history'), autoload: true }) +export const subscriptions = new Datastore({ filename: dbPath('subscriptions'), autoload: true }) diff --git a/src/main/index.js b/src/main/index.js index 90da8cbdfd08..85e41735dc51 100644 --- a/src/main/index.js +++ b/src/main/index.js @@ -1223,6 +1223,84 @@ function runApp() { // *********** // + // *********** // + // Profiles + ipcMain.handle(IpcChannels.DB_SUBSCRIPTIONS, async (event, { action, data }) => { + try { + switch (action) { + case DBActions.GENERAL.FIND: + return await baseHandlers.subscriptions.find() + + case DBActions.SUBSCRIPTIONS.UPDATE_VIDEOS_BY_CHANNEL: + await baseHandlers.subscriptions.updateVideosByChannelId(data) + syncOtherWindows( + IpcChannels.SYNC_SUBSCRIPTIONS, + event, + { event: SyncEvents.SUBSCRIPTIONS.UPDATE_VIDEOS_BY_CHANNEL, data } + ) + return null + + case DBActions.SUBSCRIPTIONS.UPDATE_LIVE_STREAMS_BY_CHANNEL: + await baseHandlers.subscriptions.updateLiveStreamsByChannelId(data) + syncOtherWindows( + IpcChannels.SYNC_SUBSCRIPTIONS, + event, + { event: SyncEvents.SUBSCRIPTIONS.UPDATE_LIVE_STREAMS_BY_CHANNEL, data } + ) + return null + + case DBActions.SUBSCRIPTIONS.UPDATE_SHORTS_BY_CHANNEL: + await baseHandlers.subscriptions.updateShortsByChannelId(data) + syncOtherWindows( + IpcChannels.SYNC_SUBSCRIPTIONS, + event, + { event: SyncEvents.SUBSCRIPTIONS.UPDATE_SHORTS_BY_CHANNEL, data } + ) + return null + + case DBActions.SUBSCRIPTIONS.UPDATE_COMMUNITY_POSTS_BY_CHANNEL: + await baseHandlers.subscriptions.updateCommunityPostsByChannelId(data) + syncOtherWindows( + IpcChannels.SYNC_SUBSCRIPTIONS, + event, + { event: SyncEvents.SUBSCRIPTIONS.UPDATE_COMMUNITY_POSTS_BY_CHANNEL, data } + ) + return null + + case DBActions.GENERAL.DELETE_MULTIPLE: + await baseHandlers.subscriptions.deleteMultipleChannels(data) + syncOtherWindows( + IpcChannels.SYNC_SUBSCRIPTIONS, + event, + { event: SyncEvents.GENERAL.DELETE_MULTIPLE, data } + ) + return null + + case DBActions.GENERAL.DELETE_ALL: + await baseHandlers.subscriptions.deleteAll() + syncOtherWindows( + IpcChannels.SYNC_SUBSCRIPTIONS, + event, + { event: SyncEvents.GENERAL.DELETE_ALL, data } + ) + return null + + case DBActions.GENERAL.PERSIST: + await baseHandlers.subscriptions.persist() + return null + + default: + // eslint-disable-next-line no-throw-literal + throw 'invalid subscriptions db action' + } + } catch (err) { + if (typeof err === 'string') throw err + else throw err.toString() + } + }) + + // *********** // + function syncOtherWindows(channel, event, payload) { const otherWindows = BrowserWindow.getAllWindows().filter((window) => { return window.webContents.id !== event.sender.id diff --git a/src/renderer/App.js b/src/renderer/App.js index c669960c5c88..f6a0b012e50c 100644 --- a/src/renderer/App.js +++ b/src/renderer/App.js @@ -178,6 +178,7 @@ export default defineComponent({ this.grabAllProfiles(this.$t('Profile.All Channels')).then(async () => { this.grabHistory() this.grabAllPlaylists() + this.grabAllSubscriptions() if (process.env.IS_ELECTRON) { ipcRenderer = require('electron').ipcRenderer @@ -560,6 +561,7 @@ export default defineComponent({ 'grabAllProfiles', 'grabHistory', 'grabAllPlaylists', + 'grabAllSubscriptions', 'getYoutubeUrlInfo', 'getExternalPlayerCmdArgumentsData', 'fetchInvidiousInstances', diff --git a/src/renderer/components/subscriptions-community/subscriptions-community.js b/src/renderer/components/subscriptions-community/subscriptions-community.js index e42510c49111..173b912684e5 100644 --- a/src/renderer/components/subscriptions-community/subscriptions-community.js +++ b/src/renderer/components/subscriptions-community/subscriptions-community.js @@ -39,6 +39,10 @@ export default defineComponent({ return this.activeProfile._id }, + subscriptionCacheReady: function () { + return this.$store.getters.getSubscriptionCacheReady + }, + cacheEntriesForAllActiveProfileChannels() { const entries = [] this.activeSubscriptionList.forEach((channel) => { @@ -51,7 +55,16 @@ export default defineComponent({ }, lastCommunityRefreshTimestamp: function () { - return getRelativeTimeFromDate(this.$store.getters.getLastCommunityRefreshTimestampByProfile(this.activeProfileId), true) + if (!this.postCacheForAllActiveProfileChannelsPresent) { return '' } + if (this.cacheEntriesForAllActiveProfileChannels.length === 0) { return '' } + + let minTimestamp = null + this.cacheEntriesForAllActiveProfileChannels.forEach((cacheEntry) => { + if (!minTimestamp || cacheEntry.timestamp.getTime() < minTimestamp.getTime()) { + minTimestamp = cacheEntry.timestamp + } + }) + return getRelativeTimeFromDate(minTimestamp, true) }, postCacheForAllActiveProfileChannelsPresent() { @@ -76,6 +89,10 @@ export default defineComponent({ this.isLoading = true this.loadPostsFromCacheSometimes() }, + + subscriptionCacheReady() { + this.loadVideosFromCacheSometimes() + }, }, mounted: async function () { this.isLoading = true @@ -84,23 +101,15 @@ export default defineComponent({ }, methods: { loadPostsFromCacheSometimes() { + // Can only load reliably when cache ready + if (!this.subscriptionCacheReady) { return } + // This method is called on view visible if (this.postCacheForAllActiveProfileChannelsPresent) { this.loadPostsFromCacheForAllActiveProfileChannels() - if (this.cacheEntriesForAllActiveProfileChannels.length > 0) { - let minTimestamp = null - this.cacheEntriesForAllActiveProfileChannels.forEach((cacheEntry) => { - if (!minTimestamp || cacheEntry.timestamp.getTime() < minTimestamp.getTime()) { - minTimestamp = cacheEntry.timestamp - } - }) - this.updateLastCommunityRefreshTimestampByProfile({ profileId: this.activeProfileId, timestamp: minTimestamp }) - } return } - // clear timestamp if not all entries are present in the cache - this.updateLastCommunityRefreshTimestampByProfile({ profileId: this.activeProfileId, timestamp: '' }) this.maybeLoadPostsForSubscriptionsFromRemote() }, @@ -184,7 +193,6 @@ export default defineComponent({ return posts }))).flatMap((o) => o) postList.push(...postListFromRemote) - this.updateLastCommunityRefreshTimestampByProfile({ profileId: this.activeProfileId, timestamp: new Date() }) postList.sort((a, b) => { return calculatePublishedDate(b.publishedText) - calculatePublishedDate(a.publishedText) }) @@ -260,7 +268,6 @@ export default defineComponent({ 'updateShowProgressBar', 'batchUpdateSubscriptionDetails', 'updateSubscriptionPostsCacheByChannel', - 'updateLastCommunityRefreshTimestampByProfile' ]), ...mapMutations([ diff --git a/src/renderer/components/subscriptions-live/subscriptions-live.js b/src/renderer/components/subscriptions-live/subscriptions-live.js index 808270ad8ad0..f416c265a659 100644 --- a/src/renderer/components/subscriptions-live/subscriptions-live.js +++ b/src/renderer/components/subscriptions-live/subscriptions-live.js @@ -44,6 +44,10 @@ export default defineComponent({ return this.activeProfile._id }, + subscriptionCacheReady: function () { + return this.$store.getters.getSubscriptionCacheReady + }, + cacheEntriesForAllActiveProfileChannels() { const entries = [] this.activeSubscriptionList.forEach((channel) => { @@ -72,14 +76,27 @@ export default defineComponent({ }, lastLiveRefreshTimestamp: function () { - return getRelativeTimeFromDate(this.$store.getters.getLastLiveRefreshTimestampByProfile(this.activeProfileId), true) - } + if (!this.videoCacheForAllActiveProfileChannelsPresent) { return '' } + if (this.cacheEntriesForAllActiveProfileChannels.length === 0) { return '' } + + let minTimestamp = null + this.cacheEntriesForAllActiveProfileChannels.forEach((cacheEntry) => { + if (!minTimestamp || cacheEntry.timestamp.getTime() < minTimestamp.getTime()) { + minTimestamp = cacheEntry.timestamp + } + }) + return getRelativeTimeFromDate(minTimestamp, true) + }, }, watch: { activeProfile: async function (_) { this.isLoading = true this.loadVideosFromCacheSometimes() }, + + subscriptionCacheReady() { + this.loadVideosFromCacheSometimes() + }, }, mounted: async function () { this.isLoading = true @@ -88,23 +105,15 @@ export default defineComponent({ }, methods: { loadVideosFromCacheSometimes() { + // Can only load reliably when cache ready + if (!this.subscriptionCacheReady) { return } + // This method is called on view visible if (this.videoCacheForAllActiveProfileChannelsPresent) { this.loadVideosFromCacheForAllActiveProfileChannels() - if (this.cacheEntriesForAllActiveProfileChannels.length > 0) { - let minTimestamp = null - this.cacheEntriesForAllActiveProfileChannels.forEach((cacheEntry) => { - if (!minTimestamp || cacheEntry.timestamp.getTime() < minTimestamp.getTime()) { - minTimestamp = cacheEntry.timestamp - } - }) - this.updateLastLiveRefreshTimestampByProfile({ profileId: this.activeProfileId, timestamp: minTimestamp }) - } return } - // clear timestamp if not all entries are present in the cache - this.updateLastLiveRefreshTimestampByProfile({ profileId: this.activeProfileId, timestamp: '' }) this.maybeLoadVideosForSubscriptionsFromRemote() }, @@ -183,7 +192,6 @@ export default defineComponent({ return videos }))).flatMap((o) => o) videoList.push(...videoListFromRemote) - this.updateLastLiveRefreshTimestampByProfile({ profileId: this.activeProfileId, timestamp: new Date() }) this.videoList = updateVideoListAfterProcessing(videoList) this.isLoading = false @@ -398,7 +406,6 @@ export default defineComponent({ 'batchUpdateSubscriptionDetails', 'updateShowProgressBar', 'updateSubscriptionLiveCacheByChannel', - 'updateLastLiveRefreshTimestampByProfile' ]), ...mapMutations([ diff --git a/src/renderer/components/subscriptions-shorts/subscriptions-shorts.js b/src/renderer/components/subscriptions-shorts/subscriptions-shorts.js index f24ae77c49ef..ed679be2855b 100644 --- a/src/renderer/components/subscriptions-shorts/subscriptions-shorts.js +++ b/src/renderer/components/subscriptions-shorts/subscriptions-shorts.js @@ -31,8 +31,21 @@ export default defineComponent({ return this.$store.getters.getCurrentInvidiousInstance }, + subscriptionCacheReady: function () { + return this.$store.getters.getSubscriptionCacheReady + }, + lastShortRefreshTimestamp: function () { - return getRelativeTimeFromDate(this.$store.getters.getLastShortRefreshTimestampByProfile(this.activeProfileId), true) + if (!this.videoCacheForAllActiveProfileChannelsPresent) { return '' } + if (this.cacheEntriesForAllActiveProfileChannels.length === 0) { return '' } + + let minTimestamp = null + this.cacheEntriesForAllActiveProfileChannels.forEach((cacheEntry) => { + if (!minTimestamp || cacheEntry.timestamp.getTime() < minTimestamp.getTime()) { + minTimestamp = cacheEntry.timestamp + } + }) + return getRelativeTimeFromDate(minTimestamp, true) }, activeProfile: function () { @@ -74,6 +87,10 @@ export default defineComponent({ this.isLoading = true this.loadVideosFromCacheSometimes() }, + + subscriptionCacheReady() { + this.loadVideosFromCacheSometimes() + }, }, mounted: async function () { this.isLoading = true @@ -82,24 +99,15 @@ export default defineComponent({ }, methods: { loadVideosFromCacheSometimes() { - // This method is called on view visible + // Can only load reliably when cache ready + if (!this.subscriptionCacheReady) { return } + // This method is called on view visible if (this.videoCacheForAllActiveProfileChannelsPresent) { this.loadVideosFromCacheForAllActiveProfileChannels() - if (this.cacheEntriesForAllActiveProfileChannels.length > 0) { - let minTimestamp = null - this.cacheEntriesForAllActiveProfileChannels.forEach((cacheEntry) => { - if (!minTimestamp || cacheEntry.timestamp.getTime() < minTimestamp.getTime()) { - minTimestamp = cacheEntry.timestamp - } - }) - this.updateLastShortRefreshTimestampByProfile({ profileId: this.activeProfileId, timestamp: minTimestamp }) - } return } - // clear timestamp if not all entries are present in the cache - this.updateLastShortRefreshTimestampByProfile({ profileId: this.activeProfileId, timestamp: '' }) this.maybeLoadVideosForSubscriptionsFromRemote() }, @@ -160,7 +168,6 @@ export default defineComponent({ return videos }))).flatMap((o) => o) videoList.push(...videoListFromRemote) - this.updateLastShortRefreshTimestampByProfile({ profileId: this.activeProfileId, timestamp: new Date() }) this.videoList = updateVideoListAfterProcessing(videoList) this.isLoading = false @@ -271,7 +278,6 @@ export default defineComponent({ 'batchUpdateSubscriptionDetails', 'updateShowProgressBar', 'updateSubscriptionShortsCacheByChannel', - 'updateLastShortRefreshTimestampByProfile' ]), ...mapMutations([ diff --git a/src/renderer/components/subscriptions-videos/subscriptions-videos.js b/src/renderer/components/subscriptions-videos/subscriptions-videos.js index b803f2724166..ee66b916d2df 100644 --- a/src/renderer/components/subscriptions-videos/subscriptions-videos.js +++ b/src/renderer/components/subscriptions-videos/subscriptions-videos.js @@ -33,12 +33,25 @@ export default defineComponent({ return this.$store.getters.getCurrentInvidiousInstance }, + subscriptionCacheReady: function () { + return this.$store.getters.getSubscriptionCacheReady + }, + currentLocale: function () { return this.$i18n.locale.replace('_', '-') }, lastVideoRefreshTimestamp: function () { - return getRelativeTimeFromDate(this.$store.getters.getLastVideoRefreshTimestampByProfile(this.activeProfileId), true) + if (!this.videoCacheForAllActiveProfileChannelsPresent) { return '' } + if (this.cacheEntriesForAllActiveProfileChannels.length === 0) { return '' } + + let minTimestamp = null + this.cacheEntriesForAllActiveProfileChannels.forEach((cacheEntry) => { + if (!minTimestamp || cacheEntry.timestamp.getTime() < minTimestamp.getTime()) { + minTimestamp = cacheEntry.timestamp + } + }) + return getRelativeTimeFromDate(minTimestamp, true) }, useRssFeeds: function () { @@ -84,6 +97,10 @@ export default defineComponent({ this.isLoading = true this.loadVideosFromCacheSometimes() }, + + subscriptionCacheReady() { + this.loadVideosFromCacheSometimes() + }, }, mounted: async function () { this.isLoading = true @@ -92,23 +109,15 @@ export default defineComponent({ }, methods: { loadVideosFromCacheSometimes() { + // Can only load reliably when cache ready + if (!this.subscriptionCacheReady) { return } + // This method is called on view visible if (this.videoCacheForAllActiveProfileChannelsPresent) { this.loadVideosFromCacheForAllActiveProfileChannels() - if (this.cacheEntriesForAllActiveProfileChannels.length > 0) { - let minTimestamp = null - this.cacheEntriesForAllActiveProfileChannels.forEach((cacheEntry) => { - if (!minTimestamp || cacheEntry.timestamp.getTime() < minTimestamp.getTime()) { - minTimestamp = cacheEntry.timestamp - } - }) - this.updateLastVideoRefreshTimestampByProfile({ profileId: this.activeProfileId, timestamp: minTimestamp }) - } return } - // clear timestamp if not all entries are present in the cache - this.updateLastVideoRefreshTimestampByProfile({ profileId: this.activeProfileId, timestamp: '' }) this.maybeLoadVideosForSubscriptionsFromRemote() }, @@ -187,7 +196,6 @@ export default defineComponent({ return videos }))).flatMap((o) => o) videoList.push(...videoListFromRemote) - this.updateLastVideoRefreshTimestampByProfile({ profileId: this.activeProfileId, timestamp: new Date() }) this.videoList = updateVideoListAfterProcessing(videoList) this.isLoading = false @@ -400,7 +408,6 @@ export default defineComponent({ 'batchUpdateSubscriptionDetails', 'updateShowProgressBar', 'updateSubscriptionVideosCacheByChannel', - 'updateLastVideoRefreshTimestampByProfile' ]), ...mapMutations([ diff --git a/src/renderer/store/modules/profiles.js b/src/renderer/store/modules/profiles.js index 188ad27d6086..c79312ad0eca 100644 --- a/src/renderer/store/modules/profiles.js +++ b/src/renderer/store/modules/profiles.js @@ -29,7 +29,14 @@ const getters = { profileById: (state) => (id) => { const profile = state.profileList.find(p => p._id === id) return profile - } + }, + + getSubscribedChannelIdSet: (state) => { + const mainProfile = state.profileList.find((profile) => { + return profile._id === MAIN_PROFILE_ID + }) + return mainProfile.subscriptions.reduce((set, channel) => set.add(channel.id), new Set()) + }, } function profileSort(a, b) { diff --git a/src/renderer/store/modules/settings.js b/src/renderer/store/modules/settings.js index cb5c46ffea5a..e8341177a659 100644 --- a/src/renderer/store/modules/settings.js +++ b/src/renderer/store/modules/settings.js @@ -568,6 +568,40 @@ const customActions = { console.error('playlists: invalid sync event received') } }) + + ipcRenderer.on(IpcChannels.SYNC_SUBSCRIPTIONS, (_, { event, data }) => { + switch (event) { + case SyncEvents.SUBSCRIPTIONS.UPDATE_VIDEOS_BY_CHANNEL: + commit('updateVideoCacheByChannel', data) + break + + case SyncEvents.SUBSCRIPTIONS.UPDATE_LIVE_STREAMS_BY_CHANNEL: + commit('updateLiveCacheByChannel', data) + break + + case SyncEvents.SUBSCRIPTIONS.UPDATE_SHORTS_BY_CHANNEL: + commit('updateShortsCacheByChannel', data) + break + + case SyncEvents.SUBSCRIPTIONS.UPDATE_COMMUNITY_POSTS_BY_CHANNEL: + commit('updatePostsCacheByChannel', data) + break + + case SyncEvents.GENERAL.DELETE_MULTIPLE: + commit('clearCachesForManyChannels', data) + break + + case SyncEvents.GENERAL.DELETE_ALL: + commit('clearVideoCache', data) + commit('clearShortsCache', data) + commit('clearLiveCache', data) + commit('clearPostsCache', data) + break + + default: + console.error('subscriptions: invalid sync event received') + } + }) } } } diff --git a/src/renderer/store/modules/subscriptions.js b/src/renderer/store/modules/subscriptions.js index f98f7881b797..939334040d68 100644 --- a/src/renderer/store/modules/subscriptions.js +++ b/src/renderer/store/modules/subscriptions.js @@ -1,11 +1,19 @@ +import { + DBSubscriptionsHandlers, +} from '../../../datastores/handlers/index' + const state = { videoCache: {}, liveCache: {}, shortsCache: {}, - postsCache: {} + postsCache: {}, + + subscriptionCacheReady: false, } const getters = { + getSubscriptionCacheReady: (state) => state.subscriptionCacheReady, + getVideoCache: (state) => { return state.videoCache }, @@ -40,49 +48,158 @@ const getters = { } const actions = { - updateSubscriptionVideosCacheByChannel: ({ commit }, payload) => { - commit('updateVideoCacheByChannel', payload) + async grabAllSubscriptions({ commit, dispatch, rootGetters }) { + try { + const payload = await DBSubscriptionsHandlers.find() + + const videos = {} + const liveStreams = {} + const shorts = {} + const communityPosts = {} + + const toBeRemovedChannelIds = [] + const subscribedChannelIdSet = rootGetters.getSubscribedChannelIdSet + + for (const dataEntry of payload) { + const channelId = dataEntry._id + if (!subscribedChannelIdSet.has(channelId)) { + // Clean up cache data for unsubscribed channels + toBeRemovedChannelIds.push(channelId) + // No need to load data for unsubscribed channels + continue + } + + let hasData = false + + if (Array.isArray(dataEntry.videos)) { + videos[channelId] = { videos: dataEntry.videos, timestamp: dataEntry.videosTimestamp } + hasData = true + } + if (Array.isArray(dataEntry.liveStreams)) { + liveStreams[channelId] = dataEntry.liveStreams + liveStreams[channelId] = { videos: dataEntry.liveStreams, timestamp: dataEntry.liveStreamsTimestamp } + hasData = true + } + if (Array.isArray(dataEntry.shorts)) { + shorts[channelId] = { videos: dataEntry.shorts, timestamp: dataEntry.shortsTimestamp } + hasData = true + } + if (Array.isArray(dataEntry.communityPosts)) { + communityPosts[channelId] = { posts: dataEntry.communityPosts, timestamp: dataEntry.communityPostsTimestamp } + hasData = true + } + + if (!hasData) { toBeRemovedChannelIds.push(channelId) } + } + + if (toBeRemovedChannelIds.length > 0) { + // Delete channels with no data + dispatch('clearSubscriptionsCacheForManyChannels', toBeRemovedChannelIds) + } + commit('setAllSubscriptions', { videos, liveStreams, shorts, communityPosts }) + commit('setSubscriptionCacheReady', true) + } catch (errMessage) { + console.error(errMessage) + } }, - updateSubscriptionShortsCacheByChannel: ({ commit }, payload) => { - commit('updateShortsCacheByChannel', payload) + async updateSubscriptionVideosCacheByChannel({ commit }, { channelId, videos, timestamp = new Date() }) { + try { + await DBSubscriptionsHandlers.updateVideosByChannelId({ + channelId, + entries: videos, + timestamp, + }) + commit('updateVideoCacheByChannel', { channelId, entries: videos, timestamp }) + } catch (errMessage) { + console.error(errMessage) + } }, - updateSubscriptionShortsCacheWithChannelPageShorts: ({ commit }, payload) => { - commit('updateShortsCacheWithChannelPageShorts', payload) + async updateSubscriptionShortsCacheByChannel({ commit }, { channelId, videos, timestamp = new Date() }) { + try { + await DBSubscriptionsHandlers.updateShortsByChannelId({ + channelId, + entries: videos, + timestamp, + }) + commit('updateShortsCacheByChannel', { channelId, entries: videos, timestamp }) + } catch (errMessage) { + console.error(errMessage) + } }, - updateSubscriptionLiveCacheByChannel: ({ commit }, payload) => { - commit('updateLiveCacheByChannel', payload) + async updateSubscriptionShortsCacheWithChannelPageShorts({ commit }, { channelId, videos, timestamp = new Date() }) { + try { + commit('updateShortsCacheWithChannelPageShorts', { channelId, videos, timestamp }) + } catch (errMessage) { + console.error(errMessage) + } + }, + + async updateSubscriptionLiveCacheByChannel({ commit }, { channelId, videos, timestamp = new Date() }) { + try { + await DBSubscriptionsHandlers.updateLiveStreamsByChannelId({ + channelId, + entries: videos, + timestamp, + }) + commit('updateLiveCacheByChannel', { channelId, entries: videos, timestamp }) + } catch (errMessage) { + console.error(errMessage) + } + }, + + async updateSubscriptionPostsCacheByChannel({ commit }, { channelId, posts, timestamp = new Date() }) { + try { + await DBSubscriptionsHandlers.updateCommunityPostsByChannelId({ + channelId, + entries: posts, + timestamp, + }) + commit('updatePostsCacheByChannel', { channelId, entries: posts, timestamp }) + } catch (errMessage) { + console.error(errMessage) + } }, - updateSubscriptionPostsCacheByChannel: ({ commit }, payload) => { - commit('updatePostsCacheByChannel', payload) + async clearSubscriptionsCacheForManyChannels({ commit }, channelIds) { + try { + await DBSubscriptionsHandlers.deleteMultipleChannels(channelIds) + commit('clearCachesForManyChannels', channelIds) + } catch (errMessage) { + console.error(errMessage) + } }, - clearSubscriptionsCache: ({ commit }, payload) => { - commit('clearVideoCache', payload) - commit('clearShortsCache', payload) - commit('clearLiveCache', payload) - commit('clearPostsCache', payload) + async clearSubscriptionsCache({ commit }, payload) { + try { + await DBSubscriptionsHandlers.deleteAll() + commit('clearVideoCache', payload) + commit('clearShortsCache', payload) + commit('clearLiveCache', payload) + commit('clearPostsCache', payload) + } catch (errMessage) { + console.error(errMessage) + } }, } const mutations = { - updateVideoCacheByChannel(state, { channelId, videos, timestamp = new Date() }) { + updateVideoCacheByChannel(state, { channelId, entries, timestamp = new Date() }) { const existingObject = state.videoCache[channelId] const newObject = existingObject ?? { videos: null } - if (videos != null) { newObject.videos = videos } + if (entries != null) { newObject.videos = entries } newObject.timestamp = timestamp state.videoCache[channelId] = newObject }, clearVideoCache(state) { state.videoCache = {} }, - updateShortsCacheByChannel(state, { channelId, videos, timestamp = new Date() }) { + updateShortsCacheByChannel(state, { channelId, entries, timestamp = new Date() }) { const existingObject = state.shortsCache[channelId] const newObject = existingObject ?? { videos: null } - if (videos != null) { newObject.videos = videos } + if (entries != null) { newObject.videos = entries } newObject.timestamp = timestamp state.shortsCache[channelId] = newObject }, @@ -114,26 +231,46 @@ const mutations = { clearShortsCache(state) { state.shortsCache = {} }, - updateLiveCacheByChannel(state, { channelId, videos, timestamp = new Date() }) { + updateLiveCacheByChannel(state, { channelId, entries, timestamp = new Date() }) { const existingObject = state.liveCache[channelId] const newObject = existingObject ?? { videos: null } - if (videos != null) { newObject.videos = videos } + if (entries != null) { newObject.videos = entries } newObject.timestamp = timestamp state.liveCache[channelId] = newObject }, clearLiveCache(state) { state.liveCache = {} }, - updatePostsCacheByChannel(state, { channelId, posts, timestamp = new Date() }) { + updatePostsCacheByChannel(state, { channelId, entries, timestamp = new Date() }) { const existingObject = state.postsCache[channelId] const newObject = existingObject ?? { posts: null } - if (posts != null) { newObject.posts = posts } + if (entries != null) { newObject.posts = entries } newObject.timestamp = timestamp state.postsCache[channelId] = newObject }, clearPostsCache(state) { state.postsCache = {} }, + + clearCachesForManyChannels(state, channelIds) { + channelIds.forEach((channelId) => { + state.videoCache[channelId] = null + state.liveCache[channelId] = null + state.shortsCache[channelId] = null + state.postsCache[channelId] = null + }) + }, + + setAllSubscriptions(state, { videos, liveStreams, shorts, communityPosts }) { + state.videoCache = videos + state.liveCache = liveStreams + state.shortsCache = shorts + state.postsCache = communityPosts + }, + + setSubscriptionCacheReady(state, payload) { + state.subscriptionCacheReady = payload + }, } export default { From 7c544c325c2a5f311e4a6c252ab64ff08759831a Mon Sep 17 00:00:00 2001 From: PikachuEXE Date: Wed, 29 May 2024 08:54:15 +0800 Subject: [PATCH 02/10] ! Fix method used in community tab component --- .../subscriptions-community/subscriptions-community.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/renderer/components/subscriptions-community/subscriptions-community.js b/src/renderer/components/subscriptions-community/subscriptions-community.js index 173b912684e5..a7bb398e534a 100644 --- a/src/renderer/components/subscriptions-community/subscriptions-community.js +++ b/src/renderer/components/subscriptions-community/subscriptions-community.js @@ -91,7 +91,7 @@ export default defineComponent({ }, subscriptionCacheReady() { - this.loadVideosFromCacheSometimes() + this.loadPostsFromCacheSometimes() }, }, mounted: async function () { From 63949d1dab13d9401f0ca17cb0ecdba2f258e3cd Mon Sep 17 00:00:00 2001 From: PikachuEXE Date: Wed, 29 May 2024 08:59:26 +0800 Subject: [PATCH 03/10] ! Fix community post vote count displayed differently in other windows/app restart --- src/renderer/helpers/api/local.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/renderer/helpers/api/local.js b/src/renderer/helpers/api/local.js index 8434202b2420..c46012dee637 100644 --- a/src/renderer/helpers/api/local.js +++ b/src/renderer/helpers/api/local.js @@ -1250,7 +1250,7 @@ function parseLocalCommunityPost(post) { postId: post.id, authorThumbnails: post.author.thumbnails, publishedText: post.published.text, - voteCount: post.vote_count, + voteCount: post.vote_count.text, postContent: parseLocalAttachment(post.attachment), commentCount: replyCount, author: post.author.name, From b0ec9b0c8322bdcc0f19387de517c26c8c5639b1 Mon Sep 17 00:00:00 2001 From: PikachuEXE Date: Wed, 29 May 2024 09:36:42 +0800 Subject: [PATCH 04/10] * Implement persistence for `updateSubscriptionShortsCacheWithChannelPageShorts` --- src/constants.js | 2 ++ src/datastores/handlers/base.js | 33 +++++++++++++++++++++ src/datastores/handlers/electron.js | 10 +++++++ src/datastores/handlers/web.js | 7 +++++ src/main/index.js | 9 ++++++ src/renderer/store/modules/settings.js | 4 +++ src/renderer/store/modules/subscriptions.js | 12 +++++--- 7 files changed, 73 insertions(+), 4 deletions(-) diff --git a/src/constants.js b/src/constants.js index fd6371e2bbae..0392f98ab116 100644 --- a/src/constants.js +++ b/src/constants.js @@ -60,6 +60,7 @@ const DBActions = { UPDATE_VIDEOS_BY_CHANNEL: 'db-action-subscriptions-update-videos-by-channel', UPDATE_LIVE_STREAMS_BY_CHANNEL: 'db-action-subscriptions-update-live-streams-by-channel', UPDATE_SHORTS_BY_CHANNEL: 'db-action-subscriptions-update-shorts-by-channel', + UPDATE_SHORTS_WITH_CHANNEL_PAGE_SHORTS_BY_CHANNEL: 'db-action-subscriptions-update-shorts-with-channel-page-shorts-by-channel', UPDATE_COMMUNITY_POSTS_BY_CHANNEL: 'db-action-subscriptions-update-community-posts-by-channel', }, } @@ -86,6 +87,7 @@ const SyncEvents = { UPDATE_VIDEOS_BY_CHANNEL: 'sync-subscriptions-update-videos-by-channel', UPDATE_LIVE_STREAMS_BY_CHANNEL: 'sync-subscriptions-update-live-streams-by-channel', UPDATE_SHORTS_BY_CHANNEL: 'sync-subscriptions-update-shorts-by-channel', + UPDATE_SHORTS_WITH_CHANNEL_PAGE_SHORTS_BY_CHANNEL: 'sync-subscriptions-update-shorts-with-channel-page-shorts-by-channel', UPDATE_COMMUNITY_POSTS_BY_CHANNEL: 'sync-subscriptions-update-community-posts-by-channel', }, } diff --git a/src/datastores/handlers/base.js b/src/datastores/handlers/base.js index 5cf4b66cc11a..f070680e566f 100644 --- a/src/datastores/handlers/base.js +++ b/src/datastores/handlers/base.js @@ -212,6 +212,39 @@ class Subscriptions { ) } + static updateShortsWithChannelPageShortsByChannelId({ channelId, entries }) { + return db.subscriptions.findOneAsync({ _id: channelId }, { shorts: 1 }).then((doc) => { + if (doc == null) { return } + + const shorts = doc.shorts + const cacheShorts = Array.isArray(shorts) ? shorts : [] + + cacheShorts.forEach(cachedVideo => { + const channelVideo = entries.find(short => cachedVideo.videoId === short.videoId) + if (!channelVideo) { return } + + // authorId probably never changes, so we don't need to update that + cachedVideo.title = channelVideo.title + cachedVideo.author = channelVideo.author + + // as the channel shorts page only has compact view counts for numbers above 1000 e.g. 12k + // and the RSS feeds include an exact value, we only want to overwrite it when the number is larger than the cached value + // 12345 vs 12000 => 12345 + // 12345 vs 15000 => 15000 + + if (channelVideo.viewCount > cachedVideo.viewCount) { + cachedVideo.viewCount = channelVideo.viewCount + } + }) + + return db.subscriptions.updateAsync( + { _id: channelId }, + { $set: { shorts: cacheShorts } }, + { upsert: true } + ) + }) + } + static updateCommunityPostsByChannelId({ channelId, entries, timestamp }) { return db.subscriptions.updateAsync( { _id: channelId }, diff --git a/src/datastores/handlers/electron.js b/src/datastores/handlers/electron.js index 79875683651d..1efe57c1d0d2 100644 --- a/src/datastores/handlers/electron.js +++ b/src/datastores/handlers/electron.js @@ -243,6 +243,16 @@ class Subscriptions { ) } + static updateShortsWithChannelPageShortsByChannelId({ channelId, entries }) { + return ipcRenderer.invoke( + IpcChannels.DB_SUBSCRIPTIONS, + { + action: DBActions.SUBSCRIPTIONS.UPDATE_SHORTS_WITH_CHANNEL_PAGE_SHORTS_BY_CHANNEL, + data: { channelId, entries }, + } + ) + } + static updateCommunityPostsByChannelId({ channelId, entries, timestamp }) { return ipcRenderer.invoke( IpcChannels.DB_SUBSCRIPTIONS, diff --git a/src/datastores/handlers/web.js b/src/datastores/handlers/web.js index 6f9d9cf879df..19bbed9cc26c 100644 --- a/src/datastores/handlers/web.js +++ b/src/datastores/handlers/web.js @@ -147,6 +147,13 @@ class Subscriptions { }) } + static updateShortsWithChannelPageShortsByChannelId({ channelId, entries }) { + return baseHandlers.subscriptions.updateShortsWithChannelPageShortsByChannelId({ + channelId, + entries, + }) + } + static updateCommunityPostsByChannelId({ channelId, entries, timestamp }) { return baseHandlers.subscriptions.updateCommunityPostsByChannelId({ channelId, diff --git a/src/main/index.js b/src/main/index.js index 85e41735dc51..dc5ca618ddca 100644 --- a/src/main/index.js +++ b/src/main/index.js @@ -1258,6 +1258,15 @@ function runApp() { ) return null + case DBActions.SUBSCRIPTIONS.UPDATE_SHORTS_WITH_CHANNEL_PAGE_SHORTS_BY_CHANNEL: + await baseHandlers.subscriptions.updateShortsWithChannelPageShortsByChannelId(data) + syncOtherWindows( + IpcChannels.SYNC_SUBSCRIPTIONS, + event, + { event: SyncEvents.SUBSCRIPTIONS.UPDATE_SHORTS_WITH_CHANNEL_PAGE_SHORTS_BY_CHANNEL, data } + ) + return null + case DBActions.SUBSCRIPTIONS.UPDATE_COMMUNITY_POSTS_BY_CHANNEL: await baseHandlers.subscriptions.updateCommunityPostsByChannelId(data) syncOtherWindows( diff --git a/src/renderer/store/modules/settings.js b/src/renderer/store/modules/settings.js index e8341177a659..54adf7a42241 100644 --- a/src/renderer/store/modules/settings.js +++ b/src/renderer/store/modules/settings.js @@ -583,6 +583,10 @@ const customActions = { commit('updateShortsCacheByChannel', data) break + case SyncEvents.SUBSCRIPTIONS.UPDATE_SHORTS_WITH_CHANNEL_PAGE_SHORTS_BY_CHANNEL: + commit('updateShortsCacheWithChannelPageShorts', data) + break + case SyncEvents.SUBSCRIPTIONS.UPDATE_COMMUNITY_POSTS_BY_CHANNEL: commit('updatePostsCacheByChannel', data) break diff --git a/src/renderer/store/modules/subscriptions.js b/src/renderer/store/modules/subscriptions.js index 939334040d68..6f2873ba8be6 100644 --- a/src/renderer/store/modules/subscriptions.js +++ b/src/renderer/store/modules/subscriptions.js @@ -129,9 +129,13 @@ const actions = { } }, - async updateSubscriptionShortsCacheWithChannelPageShorts({ commit }, { channelId, videos, timestamp = new Date() }) { + async updateSubscriptionShortsCacheWithChannelPageShorts({ commit }, { channelId, videos }) { try { - commit('updateShortsCacheWithChannelPageShorts', { channelId, videos, timestamp }) + await DBSubscriptionsHandlers.updateShortsWithChannelPageShortsByChannelId({ + channelId, + entries: videos, + }) + commit('updateShortsCacheWithChannelPageShorts', { channelId, entries: videos }) } catch (errMessage) { console.error(errMessage) } @@ -203,12 +207,12 @@ const mutations = { newObject.timestamp = timestamp state.shortsCache[channelId] = newObject }, - updateShortsCacheWithChannelPageShorts(state, { channelId, videos }) { + updateShortsCacheWithChannelPageShorts(state, { channelId, entries }) { const cachedObject = state.shortsCache[channelId] if (cachedObject && cachedObject.videos.length > 0) { cachedObject.videos.forEach(cachedVideo => { - const channelVideo = videos.find(short => cachedVideo.videoId === short.videoId) + const channelVideo = entries.find(short => cachedVideo.videoId === short.videoId) if (channelVideo) { // authorId probably never changes, so we don't need to update that From 80c322b28f09602124f00ea45a089840ce8e5022 Mon Sep 17 00:00:00 2001 From: PikachuEXE Date: Wed, 5 Jun 2024 14:31:22 +0800 Subject: [PATCH 05/10] ! Rename subscriptions to subscription cache & fix outdated mutation reference --- src/constants.js | 8 +-- src/datastores/handlers/base.js | 24 ++++----- src/datastores/handlers/electron.js | 30 +++++------ src/datastores/handlers/index.js | 2 +- src/datastores/handlers/web.js | 20 +++---- src/datastores/index.js | 2 +- src/main/index.js | 54 +++++++++---------- src/renderer/store/modules/index.js | 4 +- src/renderer/store/modules/settings.js | 19 +++---- ...subscriptions.js => subscription-cache.js} | 22 ++++---- 10 files changed, 91 insertions(+), 94 deletions(-) rename src/renderer/store/modules/{subscriptions.js => subscription-cache.js} (91%) diff --git a/src/constants.js b/src/constants.js index 340b4066f411..7463e358ee2e 100644 --- a/src/constants.js +++ b/src/constants.js @@ -28,13 +28,13 @@ const IpcChannels = { DB_HISTORY: 'db-history', DB_PROFILES: 'db-profiles', DB_PLAYLISTS: 'db-playlists', - DB_SUBSCRIPTIONS: 'db-subscriptions', + DB_SUBSCRIPTION_CACHE: 'db-subscription-cache', SYNC_SETTINGS: 'sync-settings', SYNC_HISTORY: 'sync-history', SYNC_PROFILES: 'sync-profiles', SYNC_PLAYLISTS: 'sync-playlists', - SYNC_SUBSCRIPTIONS: 'sync-subscriptions', + SYNC_SUBSCRIPTION_CACHE: 'sync-subscription-cache', GET_REPLACE_HTTP_CACHE: 'get-replace-http-cache', TOGGLE_REPLACE_HTTP_CACHE: 'toggle-replace-http-cache', @@ -68,7 +68,7 @@ const DBActions = { DELETE_ALL_VIDEOS: 'db-action-playlists-delete-all-videos', }, - SUBSCRIPTIONS: { + SUBSCRIPTION_CACHE: { UPDATE_VIDEOS_BY_CHANNEL: 'db-action-subscriptions-update-videos-by-channel', UPDATE_LIVE_STREAMS_BY_CHANNEL: 'db-action-subscriptions-update-live-streams-by-channel', UPDATE_SHORTS_BY_CHANNEL: 'db-action-subscriptions-update-shorts-by-channel', @@ -95,7 +95,7 @@ const SyncEvents = { DELETE_VIDEO: 'sync-playlists-delete-video', }, - SUBSCRIPTIONS: { + SUBSCRIPTION_CACHE: { UPDATE_VIDEOS_BY_CHANNEL: 'sync-subscriptions-update-videos-by-channel', UPDATE_LIVE_STREAMS_BY_CHANNEL: 'sync-subscriptions-update-live-streams-by-channel', UPDATE_SHORTS_BY_CHANNEL: 'sync-subscriptions-update-shorts-by-channel', diff --git a/src/datastores/handlers/base.js b/src/datastores/handlers/base.js index d73447b10eb2..a7cab8943781 100644 --- a/src/datastores/handlers/base.js +++ b/src/datastores/handlers/base.js @@ -167,13 +167,13 @@ class Playlists { } } -class Subscriptions { +class SubscriptionCache { static find() { - return db.subscriptions.findAsync({}) + return db.subscriptionCache.findAsync({}) } static updateVideosByChannelId({ channelId, entries, timestamp }) { - return db.subscriptions.updateAsync( + return db.subscriptionCache.updateAsync( { _id: channelId }, { $set: { videos: entries, videosTimestamp: timestamp } }, { upsert: true } @@ -181,7 +181,7 @@ class Subscriptions { } static updateLiveStreamsByChannelId({ channelId, entries, timestamp }) { - return db.subscriptions.updateAsync( + return db.subscriptionCache.updateAsync( { _id: channelId }, { $set: { liveStreams: entries, liveStreamsTimestamp: timestamp } }, { upsert: true } @@ -189,7 +189,7 @@ class Subscriptions { } static updateShortsByChannelId({ channelId, entries, timestamp }) { - return db.subscriptions.updateAsync( + return db.subscriptionCache.updateAsync( { _id: channelId }, { $set: { shorts: entries, shortsTimestamp: timestamp } }, { upsert: true } @@ -197,7 +197,7 @@ class Subscriptions { } static updateShortsWithChannelPageShortsByChannelId({ channelId, entries }) { - return db.subscriptions.findOneAsync({ _id: channelId }, { shorts: 1 }).then((doc) => { + return db.subscriptionCache.findOneAsync({ _id: channelId }, { shorts: 1 }).then((doc) => { if (doc == null) { return } const shorts = doc.shorts @@ -221,7 +221,7 @@ class Subscriptions { } }) - return db.subscriptions.updateAsync( + return db.subscriptionCache.updateAsync( { _id: channelId }, { $set: { shorts: cacheShorts } }, { upsert: true } @@ -230,7 +230,7 @@ class Subscriptions { } static updateCommunityPostsByChannelId({ channelId, entries, timestamp }) { - return db.subscriptions.updateAsync( + return db.subscriptionCache.updateAsync( { _id: channelId }, { $set: { communityPosts: entries, communityPostsTimestamp: timestamp } }, { upsert: true } @@ -238,11 +238,11 @@ class Subscriptions { } static deleteMultipleChannels(channelIds) { - return db.subscriptions.removeAsync({ _id: { $in: channelIds } }, { multi: true }) + return db.subscriptionCache.removeAsync({ _id: { $in: channelIds } }, { multi: true }) } static deleteAll() { - return db.subscriptions.removeAsync({}, { multi: true }) + return db.subscriptionCache.removeAsync({}, { multi: true }) } } @@ -252,7 +252,7 @@ function compactAllDatastores() { db.history.compactDatafileAsync(), db.profiles.compactDatafileAsync(), db.playlists.compactDatafileAsync(), - db.subscriptions.compactDatafileAsync(), + db.subscriptionCache.compactDatafileAsync(), ]) } @@ -261,7 +261,7 @@ export { History as history, Profiles as profiles, Playlists as playlists, - Subscriptions as subscriptions, + SubscriptionCache as subscriptionCache, compactAllDatastores, } diff --git a/src/datastores/handlers/electron.js b/src/datastores/handlers/electron.js index c204ffa92348..805d8097f2e7 100644 --- a/src/datastores/handlers/electron.js +++ b/src/datastores/handlers/electron.js @@ -191,19 +191,19 @@ class Playlists { } } -class Subscriptions { +class SubscriptionCache { static find() { return ipcRenderer.invoke( - IpcChannels.DB_SUBSCRIPTIONS, + IpcChannels.DB_SUBSCRIPTION_CACHE, { action: DBActions.GENERAL.FIND } ) } static updateVideosByChannelId({ channelId, entries, timestamp }) { return ipcRenderer.invoke( - IpcChannels.DB_SUBSCRIPTIONS, + IpcChannels.DB_SUBSCRIPTION_CACHE, { - action: DBActions.SUBSCRIPTIONS.UPDATE_VIDEOS_BY_CHANNEL, + action: DBActions.SUBSCRIPTION_CACHE.UPDATE_VIDEOS_BY_CHANNEL, data: { channelId, entries, timestamp }, } ) @@ -211,9 +211,9 @@ class Subscriptions { static updateLiveStreamsByChannelId({ channelId, entries, timestamp }) { return ipcRenderer.invoke( - IpcChannels.DB_SUBSCRIPTIONS, + IpcChannels.DB_SUBSCRIPTION_CACHE, { - action: DBActions.SUBSCRIPTIONS.UPDATE_LIVE_STREAMS_BY_CHANNEL, + action: DBActions.SUBSCRIPTION_CACHE.UPDATE_LIVE_STREAMS_BY_CHANNEL, data: { channelId, entries, timestamp }, } ) @@ -221,9 +221,9 @@ class Subscriptions { static updateShortsByChannelId({ channelId, entries, timestamp }) { return ipcRenderer.invoke( - IpcChannels.DB_SUBSCRIPTIONS, + IpcChannels.DB_SUBSCRIPTION_CACHE, { - action: DBActions.SUBSCRIPTIONS.UPDATE_SHORTS_BY_CHANNEL, + action: DBActions.SUBSCRIPTION_CACHE.UPDATE_SHORTS_BY_CHANNEL, data: { channelId, entries, timestamp }, } ) @@ -231,9 +231,9 @@ class Subscriptions { static updateShortsWithChannelPageShortsByChannelId({ channelId, entries }) { return ipcRenderer.invoke( - IpcChannels.DB_SUBSCRIPTIONS, + IpcChannels.DB_SUBSCRIPTION_CACHE, { - action: DBActions.SUBSCRIPTIONS.UPDATE_SHORTS_WITH_CHANNEL_PAGE_SHORTS_BY_CHANNEL, + action: DBActions.SUBSCRIPTION_CACHE.UPDATE_SHORTS_WITH_CHANNEL_PAGE_SHORTS_BY_CHANNEL, data: { channelId, entries }, } ) @@ -241,9 +241,9 @@ class Subscriptions { static updateCommunityPostsByChannelId({ channelId, entries, timestamp }) { return ipcRenderer.invoke( - IpcChannels.DB_SUBSCRIPTIONS, + IpcChannels.DB_SUBSCRIPTION_CACHE, { - action: DBActions.SUBSCRIPTIONS.UPDATE_COMMUNITY_POSTS_BY_CHANNEL, + action: DBActions.SUBSCRIPTION_CACHE.UPDATE_COMMUNITY_POSTS_BY_CHANNEL, data: { channelId, entries, timestamp }, } ) @@ -251,14 +251,14 @@ class Subscriptions { static deleteMultipleChannels(channelIds) { return ipcRenderer.invoke( - IpcChannels.DB_SUBSCRIPTIONS, + IpcChannels.DB_SUBSCRIPTION_CACHE, { action: DBActions.GENERAL.DELETE_MULTIPLE, data: channelIds } ) } static deleteAll() { return ipcRenderer.invoke( - IpcChannels.DB_SUBSCRIPTIONS, + IpcChannels.DB_SUBSCRIPTION_CACHE, { action: DBActions.GENERAL.DELETE_ALL } ) } @@ -269,5 +269,5 @@ export { History as history, Profiles as profiles, Playlists as playlists, - Subscriptions as subscriptions, + SubscriptionCache as subscriptionCache, } diff --git a/src/datastores/handlers/index.js b/src/datastores/handlers/index.js index a1c1050870d8..6d9b8ab729d4 100644 --- a/src/datastores/handlers/index.js +++ b/src/datastores/handlers/index.js @@ -3,5 +3,5 @@ export { history as DBHistoryHandlers, profiles as DBProfileHandlers, playlists as DBPlaylistHandlers, - subscriptions as DBSubscriptionsHandlers, + subscriptionCache as DBSubscriptionCacheHandlers, } from 'DB_HANDLERS_ELECTRON_RENDERER_OR_WEB' diff --git a/src/datastores/handlers/web.js b/src/datastores/handlers/web.js index 20fddbda017d..ad83b5159c13 100644 --- a/src/datastores/handlers/web.js +++ b/src/datastores/handlers/web.js @@ -110,13 +110,13 @@ class Playlists { } } -class Subscriptions { +class SubscriptionCache { static find() { - return baseHandlers.subscriptions.find() + return baseHandlers.subscriptionCache.find() } static updateVideosByChannelId({ channelId, entries, timestamp }) { - return baseHandlers.subscriptions.updateVideosByChannelId({ + return baseHandlers.subscriptionCache.updateVideosByChannelId({ channelId, entries, timestamp, @@ -124,7 +124,7 @@ class Subscriptions { } static updateLiveStreamsByChannelId({ channelId, entries, timestamp }) { - return baseHandlers.subscriptions.updateLiveStreamsByChannelId({ + return baseHandlers.subscriptionCache.updateLiveStreamsByChannelId({ channelId, entries, timestamp, @@ -132,7 +132,7 @@ class Subscriptions { } static updateShortsByChannelId({ channelId, entries, timestamp }) { - return baseHandlers.subscriptions.updateShortsByChannelId({ + return baseHandlers.subscriptionCache.updateShortsByChannelId({ channelId, entries, timestamp, @@ -140,14 +140,14 @@ class Subscriptions { } static updateShortsWithChannelPageShortsByChannelId({ channelId, entries }) { - return baseHandlers.subscriptions.updateShortsWithChannelPageShortsByChannelId({ + return baseHandlers.subscriptionCache.updateShortsWithChannelPageShortsByChannelId({ channelId, entries, }) } static updateCommunityPostsByChannelId({ channelId, entries, timestamp }) { - return baseHandlers.subscriptions.updateCommunityPostsByChannelId({ + return baseHandlers.subscriptionCache.updateCommunityPostsByChannelId({ channelId, entries, timestamp, @@ -155,11 +155,11 @@ class Subscriptions { } static deleteMultipleChannels(channelIds) { - return baseHandlers.subscriptions.deleteMultipleChannels(channelIds) + return baseHandlers.subscriptionCache.deleteMultipleChannels(channelIds) } static deleteAll() { - return baseHandlers.subscriptions.deleteAll() + return baseHandlers.subscriptionCache.deleteAll() } } @@ -168,5 +168,5 @@ export { History as history, Profiles as profiles, Playlists as playlists, - Subscriptions as subscriptions, + SubscriptionCache as subscriptionCache, } diff --git a/src/datastores/index.js b/src/datastores/index.js index a2a16c870417..7a3da53356f0 100644 --- a/src/datastores/index.js +++ b/src/datastores/index.js @@ -26,4 +26,4 @@ export const settings = new Datastore({ filename: dbPath('settings'), autoload: export const profiles = new Datastore({ filename: dbPath('profiles'), autoload: true }) export const playlists = new Datastore({ filename: dbPath('playlists'), autoload: true }) export const history = new Datastore({ filename: dbPath('history'), autoload: true }) -export const subscriptions = new Datastore({ filename: dbPath('subscriptions'), autoload: true }) +export const subscriptionCache = new Datastore({ filename: dbPath('subscription-cache'), autoload: true }) diff --git a/src/main/index.js b/src/main/index.js index 598305e5aeb2..f6a63b72d721 100644 --- a/src/main/index.js +++ b/src/main/index.js @@ -1217,70 +1217,70 @@ function runApp() { // *********** // // Profiles - ipcMain.handle(IpcChannels.DB_SUBSCRIPTIONS, async (event, { action, data }) => { + ipcMain.handle(IpcChannels.DB_SUBSCRIPTION_CACHE, async (event, { action, data }) => { try { switch (action) { case DBActions.GENERAL.FIND: - return await baseHandlers.subscriptions.find() + return await baseHandlers.subscriptionCache.find() - case DBActions.SUBSCRIPTIONS.UPDATE_VIDEOS_BY_CHANNEL: - await baseHandlers.subscriptions.updateVideosByChannelId(data) + case DBActions.SUBSCRIPTION_CACHE.UPDATE_VIDEOS_BY_CHANNEL: + await baseHandlers.subscriptionCache.updateVideosByChannelId(data) syncOtherWindows( - IpcChannels.SYNC_SUBSCRIPTIONS, + IpcChannels.SYNC_SUBSCRIPTION_CACHE, event, - { event: SyncEvents.SUBSCRIPTIONS.UPDATE_VIDEOS_BY_CHANNEL, data } + { event: SyncEvents.SUBSCRIPTION_CACHE.UPDATE_VIDEOS_BY_CHANNEL, data } ) return null - case DBActions.SUBSCRIPTIONS.UPDATE_LIVE_STREAMS_BY_CHANNEL: - await baseHandlers.subscriptions.updateLiveStreamsByChannelId(data) + case DBActions.SUBSCRIPTION_CACHE.UPDATE_LIVE_STREAMS_BY_CHANNEL: + await baseHandlers.subscriptionCache.updateLiveStreamsByChannelId(data) syncOtherWindows( - IpcChannels.SYNC_SUBSCRIPTIONS, + IpcChannels.SYNC_SUBSCRIPTION_CACHE, event, - { event: SyncEvents.SUBSCRIPTIONS.UPDATE_LIVE_STREAMS_BY_CHANNEL, data } + { event: SyncEvents.SUBSCRIPTION_CACHE.UPDATE_LIVE_STREAMS_BY_CHANNEL, data } ) return null - case DBActions.SUBSCRIPTIONS.UPDATE_SHORTS_BY_CHANNEL: - await baseHandlers.subscriptions.updateShortsByChannelId(data) + case DBActions.SUBSCRIPTION_CACHE.UPDATE_SHORTS_BY_CHANNEL: + await baseHandlers.subscriptionCache.updateShortsByChannelId(data) syncOtherWindows( - IpcChannels.SYNC_SUBSCRIPTIONS, + IpcChannels.SYNC_SUBSCRIPTION_CACHE, event, - { event: SyncEvents.SUBSCRIPTIONS.UPDATE_SHORTS_BY_CHANNEL, data } + { event: SyncEvents.SUBSCRIPTION_CACHE.UPDATE_SHORTS_BY_CHANNEL, data } ) return null - case DBActions.SUBSCRIPTIONS.UPDATE_SHORTS_WITH_CHANNEL_PAGE_SHORTS_BY_CHANNEL: - await baseHandlers.subscriptions.updateShortsWithChannelPageShortsByChannelId(data) + case DBActions.SUBSCRIPTION_CACHE.UPDATE_SHORTS_WITH_CHANNEL_PAGE_SHORTS_BY_CHANNEL: + await baseHandlers.subscriptionCache.updateShortsWithChannelPageShortsByChannelId(data) syncOtherWindows( - IpcChannels.SYNC_SUBSCRIPTIONS, + IpcChannels.SYNC_SUBSCRIPTION_CACHE, event, - { event: SyncEvents.SUBSCRIPTIONS.UPDATE_SHORTS_WITH_CHANNEL_PAGE_SHORTS_BY_CHANNEL, data } + { event: SyncEvents.SUBSCRIPTION_CACHE.UPDATE_SHORTS_WITH_CHANNEL_PAGE_SHORTS_BY_CHANNEL, data } ) return null - case DBActions.SUBSCRIPTIONS.UPDATE_COMMUNITY_POSTS_BY_CHANNEL: - await baseHandlers.subscriptions.updateCommunityPostsByChannelId(data) + case DBActions.SUBSCRIPTION_CACHE.UPDATE_COMMUNITY_POSTS_BY_CHANNEL: + await baseHandlers.subscriptionCache.updateCommunityPostsByChannelId(data) syncOtherWindows( - IpcChannels.SYNC_SUBSCRIPTIONS, + IpcChannels.SYNC_SUBSCRIPTION_CACHE, event, - { event: SyncEvents.SUBSCRIPTIONS.UPDATE_COMMUNITY_POSTS_BY_CHANNEL, data } + { event: SyncEvents.SUBSCRIPTION_CACHE.UPDATE_COMMUNITY_POSTS_BY_CHANNEL, data } ) return null case DBActions.GENERAL.DELETE_MULTIPLE: - await baseHandlers.subscriptions.deleteMultipleChannels(data) + await baseHandlers.subscriptionCache.deleteMultipleChannels(data) syncOtherWindows( - IpcChannels.SYNC_SUBSCRIPTIONS, + IpcChannels.SYNC_SUBSCRIPTION_CACHE, event, { event: SyncEvents.GENERAL.DELETE_MULTIPLE, data } ) return null case DBActions.GENERAL.DELETE_ALL: - await baseHandlers.subscriptions.deleteAll() + await baseHandlers.subscriptionCache.deleteAll() syncOtherWindows( - IpcChannels.SYNC_SUBSCRIPTIONS, + IpcChannels.SYNC_SUBSCRIPTION_CACHE, event, { event: SyncEvents.GENERAL.DELETE_ALL, data } ) @@ -1288,7 +1288,7 @@ function runApp() { default: // eslint-disable-next-line no-throw-literal - throw 'invalid subscriptions db action' + throw 'invalid subscriptionCache db action' } } catch (err) { if (typeof err === 'string') throw err diff --git a/src/renderer/store/modules/index.js b/src/renderer/store/modules/index.js index d556d9571d6e..62ac6cb3452e 100644 --- a/src/renderer/store/modules/index.js +++ b/src/renderer/store/modules/index.js @@ -8,7 +8,7 @@ import invidious from './invidious' import playlists from './playlists' import profiles from './profiles' import settings from './settings' -import subscriptions from './subscriptions' +import subscriptionCache from './subscription-cache' import utils from './utils' export default { @@ -17,6 +17,6 @@ export default { playlists, profiles, settings, - subscriptions, + subscriptionCache, utils } diff --git a/src/renderer/store/modules/settings.js b/src/renderer/store/modules/settings.js index 54adf7a42241..c5cbd4168a77 100644 --- a/src/renderer/store/modules/settings.js +++ b/src/renderer/store/modules/settings.js @@ -569,25 +569,25 @@ const customActions = { } }) - ipcRenderer.on(IpcChannels.SYNC_SUBSCRIPTIONS, (_, { event, data }) => { + ipcRenderer.on(IpcChannels.SYNC_SUBSCRIPTION_CACHE, (_, { event, data }) => { switch (event) { - case SyncEvents.SUBSCRIPTIONS.UPDATE_VIDEOS_BY_CHANNEL: + case SyncEvents.SUBSCRIPTION_CACHE.UPDATE_VIDEOS_BY_CHANNEL: commit('updateVideoCacheByChannel', data) break - case SyncEvents.SUBSCRIPTIONS.UPDATE_LIVE_STREAMS_BY_CHANNEL: + case SyncEvents.SUBSCRIPTION_CACHE.UPDATE_LIVE_STREAMS_BY_CHANNEL: commit('updateLiveCacheByChannel', data) break - case SyncEvents.SUBSCRIPTIONS.UPDATE_SHORTS_BY_CHANNEL: + case SyncEvents.SUBSCRIPTION_CACHE.UPDATE_SHORTS_BY_CHANNEL: commit('updateShortsCacheByChannel', data) break - case SyncEvents.SUBSCRIPTIONS.UPDATE_SHORTS_WITH_CHANNEL_PAGE_SHORTS_BY_CHANNEL: + case SyncEvents.SUBSCRIPTION_CACHE.UPDATE_SHORTS_WITH_CHANNEL_PAGE_SHORTS_BY_CHANNEL: commit('updateShortsCacheWithChannelPageShorts', data) break - case SyncEvents.SUBSCRIPTIONS.UPDATE_COMMUNITY_POSTS_BY_CHANNEL: + case SyncEvents.SUBSCRIPTION_CACHE.UPDATE_COMMUNITY_POSTS_BY_CHANNEL: commit('updatePostsCacheByChannel', data) break @@ -596,14 +596,11 @@ const customActions = { break case SyncEvents.GENERAL.DELETE_ALL: - commit('clearVideoCache', data) - commit('clearShortsCache', data) - commit('clearLiveCache', data) - commit('clearPostsCache', data) + commit('clearCaches', data) break default: - console.error('subscriptions: invalid sync event received') + console.error('subscription-cache: invalid sync event received') } }) } diff --git a/src/renderer/store/modules/subscriptions.js b/src/renderer/store/modules/subscription-cache.js similarity index 91% rename from src/renderer/store/modules/subscriptions.js rename to src/renderer/store/modules/subscription-cache.js index 9207bb69267b..b6e269defb2e 100644 --- a/src/renderer/store/modules/subscriptions.js +++ b/src/renderer/store/modules/subscription-cache.js @@ -1,5 +1,5 @@ import { - DBSubscriptionsHandlers, + DBSubscriptionCacheHandlers, } from '../../../datastores/handlers/index' const state = { @@ -50,7 +50,7 @@ const getters = { const actions = { async grabAllSubscriptions({ commit, dispatch, rootGetters }) { try { - const payload = await DBSubscriptionsHandlers.find() + const payload = await DBSubscriptionCacheHandlers.find() const videos = {} const liveStreams = {} @@ -96,7 +96,7 @@ const actions = { // Delete channels with no data dispatch('clearSubscriptionsCacheForManyChannels', toBeRemovedChannelIds) } - commit('setAllSubscriptions', { videos, liveStreams, shorts, communityPosts }) + commit('setCaches', { videos, liveStreams, shorts, communityPosts }) commit('setSubscriptionCacheReady', true) } catch (errMessage) { console.error(errMessage) @@ -105,7 +105,7 @@ const actions = { async updateSubscriptionVideosCacheByChannel({ commit }, { channelId, videos, timestamp = new Date() }) { try { - await DBSubscriptionsHandlers.updateVideosByChannelId({ + await DBSubscriptionCacheHandlers.updateVideosByChannelId({ channelId, entries: videos, timestamp, @@ -118,7 +118,7 @@ const actions = { async updateSubscriptionShortsCacheByChannel({ commit }, { channelId, videos, timestamp = new Date() }) { try { - await DBSubscriptionsHandlers.updateShortsByChannelId({ + await DBSubscriptionCacheHandlers.updateShortsByChannelId({ channelId, entries: videos, timestamp, @@ -131,7 +131,7 @@ const actions = { async updateSubscriptionShortsCacheWithChannelPageShorts({ commit }, { channelId, videos }) { try { - await DBSubscriptionsHandlers.updateShortsWithChannelPageShortsByChannelId({ + await DBSubscriptionCacheHandlers.updateShortsWithChannelPageShortsByChannelId({ channelId, entries: videos, }) @@ -143,7 +143,7 @@ const actions = { async updateSubscriptionLiveCacheByChannel({ commit }, { channelId, videos, timestamp = new Date() }) { try { - await DBSubscriptionsHandlers.updateLiveStreamsByChannelId({ + await DBSubscriptionCacheHandlers.updateLiveStreamsByChannelId({ channelId, entries: videos, timestamp, @@ -156,7 +156,7 @@ const actions = { async updateSubscriptionPostsCacheByChannel({ commit }, { channelId, posts, timestamp = new Date() }) { try { - await DBSubscriptionsHandlers.updateCommunityPostsByChannelId({ + await DBSubscriptionCacheHandlers.updateCommunityPostsByChannelId({ channelId, entries: posts, timestamp, @@ -169,7 +169,7 @@ const actions = { async clearSubscriptionsCacheForManyChannels({ commit }, channelIds) { try { - await DBSubscriptionsHandlers.deleteMultipleChannels(channelIds) + await DBSubscriptionCacheHandlers.deleteMultipleChannels(channelIds) commit('clearCachesForManyChannels', channelIds) } catch (errMessage) { console.error(errMessage) @@ -178,7 +178,7 @@ const actions = { async clearSubscriptionsCache({ commit }, payload) { try { - await DBSubscriptionsHandlers.deleteAll() + await DBSubscriptionCacheHandlers.deleteAll() commit('clearCaches') } catch (errMessage) { console.error(errMessage) @@ -257,7 +257,7 @@ const mutations = { }) }, - setAllSubscriptions(state, { videos, liveStreams, shorts, communityPosts }) { + setCaches(state, { videos, liveStreams, shorts, communityPosts }) { state.videoCache = videos state.liveCache = liveStreams state.shortsCache = shorts From 553b3fe146293ec21de9a9e8a7dc82a0e2ae3853 Mon Sep 17 00:00:00 2001 From: PikachuEXE Date: Sun, 8 Sep 2024 10:02:17 +0800 Subject: [PATCH 06/10] $- Remove useless line --- src/renderer/store/modules/subscription-cache.js | 1 - 1 file changed, 1 deletion(-) diff --git a/src/renderer/store/modules/subscription-cache.js b/src/renderer/store/modules/subscription-cache.js index b6e269defb2e..72d35f6361b1 100644 --- a/src/renderer/store/modules/subscription-cache.js +++ b/src/renderer/store/modules/subscription-cache.js @@ -76,7 +76,6 @@ const actions = { hasData = true } if (Array.isArray(dataEntry.liveStreams)) { - liveStreams[channelId] = dataEntry.liveStreams liveStreams[channelId] = { videos: dataEntry.liveStreams, timestamp: dataEntry.liveStreamsTimestamp } hasData = true } From 276ff38ba38be7a3868edc41b06e1f9df8fad2b4 Mon Sep 17 00:00:00 2001 From: PikachuEXE Date: Sun, 8 Sep 2024 10:04:46 +0800 Subject: [PATCH 07/10] $ Simplify code --- src/renderer/store/modules/profiles.js | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/src/renderer/store/modules/profiles.js b/src/renderer/store/modules/profiles.js index d932c3cfa686..66e7a8534352 100644 --- a/src/renderer/store/modules/profiles.js +++ b/src/renderer/store/modules/profiles.js @@ -27,14 +27,13 @@ const getters = { }, profileById: (state) => (id) => { - const profile = state.profileList.find(p => p._id === id) - return profile + return state.profileList.find(p => p._id === id) }, getSubscribedChannelIdSet: (state) => { - const mainProfile = state.profileList.find((profile) => { - return profile._id === MAIN_PROFILE_ID - }) + // The all channels profile is always the first profile in the array + const mainProfile = state.profileList[0] + return mainProfile.subscriptions.reduce((set, channel) => set.add(channel.id), new Set()) }, } From 07d796a1523fc9e605740b9811cf44e7806cf49d Mon Sep 17 00:00:00 2001 From: PikachuEXE Date: Sun, 8 Sep 2024 10:06:24 +0800 Subject: [PATCH 08/10] $- Remove unused functions --- src/renderer/store/modules/utils.js | 48 ----------------------------- 1 file changed, 48 deletions(-) diff --git a/src/renderer/store/modules/utils.js b/src/renderer/store/modules/utils.js index ce9e710e4863..d2d76eec043c 100644 --- a/src/renderer/store/modules/utils.js +++ b/src/renderer/store/modules/utils.js @@ -164,22 +164,6 @@ const getters = { getLastPopularRefreshTimestamp(state) { return state.lastPopularRefreshTimestamp }, - - getLastCommunityRefreshTimestampByProfile: (state) => (profileId) => { - return state.lastCommunityRefreshTimestampByProfile[profileId] - }, - - getLastShortRefreshTimestampByProfile: (state) => (profileId) => { - return state.lastShortRefreshTimestampByProfile[profileId] - }, - - getLastLiveRefreshTimestampByProfile: (state) => (profileId) => { - return state.lastLiveRefreshTimestampByProfile[profileId] - }, - - getLastVideoRefreshTimestampByProfile: (state) => (profileId) => { - return state.lastVideoRefreshTimestampByProfile[profileId] - }, } const actions = { @@ -775,22 +759,6 @@ const actions = { ipcRenderer.send(IpcChannels.OPEN_IN_EXTERNAL_PLAYER, { executable, args }) } }, - - updateLastCommunityRefreshTimestampByProfile ({ commit }, payload) { - commit('updateLastCommunityRefreshTimestampByProfile', payload) - }, - - updateLastShortRefreshTimestampByProfile ({ commit }, payload) { - commit('updateLastShortRefreshTimestampByProfile', payload) - }, - - updateLastLiveRefreshTimestampByProfile ({ commit }, payload) { - commit('updateLastLiveRefreshTimestampByProfile', payload) - }, - - updateLastVideoRefreshTimestampByProfile ({ commit }, payload) { - commit('updateLastVideoRefreshTimestampByProfile', payload) - } } const mutations = { @@ -894,22 +862,6 @@ const mutations = { state.lastPopularRefreshTimestamp = timestamp }, - updateLastCommunityRefreshTimestampByProfile (state, { profileId, timestamp }) { - vueSet(state.lastCommunityRefreshTimestampByProfile, profileId, timestamp) - }, - - updateLastShortRefreshTimestampByProfile (state, { profileId, timestamp }) { - vueSet(state.lastShortRefreshTimestampByProfile, profileId, timestamp) - }, - - updateLastLiveRefreshTimestampByProfile (state, { profileId, timestamp }) { - vueSet(state.lastLiveRefreshTimestampByProfile, profileId, timestamp) - }, - - updateLastVideoRefreshTimestampByProfile (state, { profileId, timestamp }) { - vueSet(state.lastVideoRefreshTimestampByProfile, profileId, timestamp) - }, - clearTrendingCache(state) { state.trendingCache = { default: null, From 26e2328063e606a6ffc8bf370eafef28b2a3c49d Mon Sep 17 00:00:00 2001 From: PikachuEXE Date: Mon, 9 Sep 2024 09:40:54 +0800 Subject: [PATCH 09/10] * Save community post publish time in absolute time not relative time text --- .../components/ft-community-post/ft-community-post.js | 9 +++++++-- .../subscriptions-community/subscriptions-community.js | 6 +++--- src/renderer/helpers/api/invidious.js | 8 ++++++-- src/renderer/helpers/api/local.js | 2 +- 4 files changed, 17 insertions(+), 8 deletions(-) diff --git a/src/renderer/components/ft-community-post/ft-community-post.js b/src/renderer/components/ft-community-post/ft-community-post.js index 51fa39bb1afe..661be5379059 100644 --- a/src/renderer/components/ft-community-post/ft-community-post.js +++ b/src/renderer/components/ft-community-post/ft-community-post.js @@ -7,7 +7,12 @@ import autolinker from 'autolinker' import { A11y, Navigation, Pagination } from 'swiper/modules' -import { createWebURL, deepCopy, toLocalePublicationString } from '../../helpers/utils' +import { + createWebURL, + deepCopy, + getRelativeTimeFromDate, + toLocalePublicationString, +} from '../../helpers/utils' import { youtubeImageUrlToInvidious } from '../../helpers/api/invidious' export default defineComponent({ @@ -121,7 +126,7 @@ export default defineComponent({ this.postContent = this.data.postContent this.postId = this.data.postId this.publishedText = toLocalePublicationString({ - publishText: this.data.publishedText, + publishText: getRelativeTimeFromDate(this.data.publishedTime), isLive: this.isLive, isUpcoming: this.isUpcoming, isRSS: this.data.isRSS diff --git a/src/renderer/components/subscriptions-community/subscriptions-community.js b/src/renderer/components/subscriptions-community/subscriptions-community.js index 00cc3ff68736..ecd9f31072b3 100644 --- a/src/renderer/components/subscriptions-community/subscriptions-community.js +++ b/src/renderer/components/subscriptions-community/subscriptions-community.js @@ -2,7 +2,7 @@ import { defineComponent } from 'vue' import { mapActions, mapMutations } from 'vuex' import SubscriptionsTabUI from '../subscriptions-tab-ui/subscriptions-tab-ui.vue' -import { calculatePublishedDate, copyToClipboard, getRelativeTimeFromDate, showToast } from '../../helpers/utils' +import { copyToClipboard, getRelativeTimeFromDate, showToast } from '../../helpers/utils' import { getLocalChannelCommunity } from '../../helpers/api/local' import { invidiousGetCommunityPosts } from '../../helpers/api/invidious' @@ -122,7 +122,7 @@ export default defineComponent({ }) postList.sort((a, b) => { - return calculatePublishedDate(b.publishedText) - calculatePublishedDate(a.publishedText) + return b.publishedTime - a.publishedTime }) this.postList = postList @@ -194,7 +194,7 @@ export default defineComponent({ }))).flatMap((o) => o) postList.push(...postListFromRemote) postList.sort((a, b) => { - return calculatePublishedDate(b.publishedText) - calculatePublishedDate(a.publishedText) + return b.publishedTime - a.publishedTime }) this.postList = postList diff --git a/src/renderer/helpers/api/invidious.js b/src/renderer/helpers/api/invidious.js index 17259c7f8158..b6d5b9dc6dac 100644 --- a/src/renderer/helpers/api/invidious.js +++ b/src/renderer/helpers/api/invidious.js @@ -1,5 +1,9 @@ import store from '../../store/index' -import { stripHTML, toLocalePublicationString } from '../utils' +import { + calculatePublishedDate, + stripHTML, + toLocalePublicationString, +} from '../utils' import { isNullOrEmpty } from '../strings' import autolinker from 'autolinker' import { FormatUtils, Misc, Player } from 'youtubei.js' @@ -208,7 +212,7 @@ function parseInvidiousCommunityData(data) { thumbnail.url = youtubeImageUrlToInvidious(thumbnail.url) return thumbnail }), - publishedText: data.publishedText, + publishedTime: calculatePublishedDate(data.publishedText), voteCount: data.likeCount, postContent: parseInvidiousCommunityAttachments(data.attachment), commentCount: data?.replyCount ?? 0, // https://github.com/iv-org/invidious/pull/3635/ diff --git a/src/renderer/helpers/api/local.js b/src/renderer/helpers/api/local.js index b173f1f96a0e..b11b6237ac2d 100644 --- a/src/renderer/helpers/api/local.js +++ b/src/renderer/helpers/api/local.js @@ -1415,7 +1415,7 @@ function parseLocalCommunityPost(post) { postText: post.content.isEmpty() ? '' : Autolinker.link(parseLocalTextRuns(post.content.runs, 16)), postId: post.id, authorThumbnails: post.author.thumbnails, - publishedText: post.published.text, + publishedTime: calculatePublishedDate(post.published.text), voteCount: post.vote_count.text, postContent: parseLocalAttachment(post.attachment), commentCount: replyCount, From 58c6b19ec1ef69d06b7837cda2409557b76bfe64 Mon Sep 17 00:00:00 2001 From: PikachuEXE Date: Tue, 17 Sep 2024 05:12:22 +0800 Subject: [PATCH 10/10] ! Fix no timestamp shown after manual refresh --- .../subscriptions-community/subscriptions-community.js | 7 +++++++ .../components/subscriptions-live/subscriptions-live.js | 7 +++++++ .../subscriptions-shorts/subscriptions-shorts.js | 7 +++++++ .../subscriptions-videos/subscriptions-videos.js | 7 +++++++ 4 files changed, 28 insertions(+) diff --git a/src/renderer/components/subscriptions-community/subscriptions-community.js b/src/renderer/components/subscriptions-community/subscriptions-community.js index 60ad5c5d889b..57c8e1967e4a 100644 --- a/src/renderer/components/subscriptions-community/subscriptions-community.js +++ b/src/renderer/components/subscriptions-community/subscriptions-community.js @@ -17,6 +17,7 @@ export default defineComponent({ postList: [], errorChannels: [], attemptedFetch: false, + lastRemoteRefreshSuccessTimestamp: null, } }, computed: { @@ -55,6 +56,10 @@ export default defineComponent({ }, lastCommunityRefreshTimestamp: function () { + // Cache is not ready when data is just loaded from remote + if (this.lastRemoteRefreshSuccessTimestamp) { + return getRelativeTimeFromDate(this.lastRemoteRefreshSuccessTimestamp, true) + } if (!this.postCacheForAllActiveProfileChannelsPresent) { return '' } if (this.cacheEntriesForAllActiveProfileChannels.length === 0) { return '' } @@ -86,6 +91,7 @@ export default defineComponent({ }, watch: { activeProfile: async function (_) { + this.lastRemoteRefreshSuccessTimestamp = null this.isLoading = true this.loadPostsFromCacheSometimes() }, @@ -196,6 +202,7 @@ export default defineComponent({ this.postList = postList this.isLoading = false this.updateShowProgressBar(false) + this.lastRemoteRefreshSuccessTimestamp = new Date() this.batchUpdateSubscriptionDetails(subscriptionUpdates) }, diff --git a/src/renderer/components/subscriptions-live/subscriptions-live.js b/src/renderer/components/subscriptions-live/subscriptions-live.js index cf758e813ca0..969ce7f070f1 100644 --- a/src/renderer/components/subscriptions-live/subscriptions-live.js +++ b/src/renderer/components/subscriptions-live/subscriptions-live.js @@ -24,6 +24,7 @@ export default defineComponent({ videoList: [], errorChannels: [], attemptedFetch: false, + lastRemoteRefreshSuccessTimestamp: null, } }, computed: { @@ -82,6 +83,10 @@ export default defineComponent({ }, lastLiveRefreshTimestamp: function () { + // Cache is not ready when data is just loaded from remote + if (this.lastRemoteRefreshSuccessTimestamp) { + return getRelativeTimeFromDate(this.lastRemoteRefreshSuccessTimestamp, true) + } if (!this.videoCacheForAllActiveProfileChannelsPresent) { return '' } if (this.cacheEntriesForAllActiveProfileChannels.length === 0) { return '' } @@ -96,6 +101,7 @@ export default defineComponent({ }, watch: { activeProfile: async function (_) { + this.lastRemoteRefreshSuccessTimestamp = null this.isLoading = true this.loadVideosFromCacheSometimes() }, @@ -202,6 +208,7 @@ export default defineComponent({ this.videoList = updateVideoListAfterProcessing(videoList) this.isLoading = false this.updateShowProgressBar(false) + this.lastRemoteRefreshSuccessTimestamp = new Date() this.batchUpdateSubscriptionDetails(subscriptionUpdates) }, diff --git a/src/renderer/components/subscriptions-shorts/subscriptions-shorts.js b/src/renderer/components/subscriptions-shorts/subscriptions-shorts.js index 427a314ef214..f63d488178ae 100644 --- a/src/renderer/components/subscriptions-shorts/subscriptions-shorts.js +++ b/src/renderer/components/subscriptions-shorts/subscriptions-shorts.js @@ -22,6 +22,7 @@ export default defineComponent({ videoList: [], errorChannels: [], attemptedFetch: false, + lastRemoteRefreshSuccessTimestamp: null, } }, computed: { @@ -42,6 +43,10 @@ export default defineComponent({ }, lastShortRefreshTimestamp: function () { + // Cache is not ready when data is just loaded from remote + if (this.lastRemoteRefreshSuccessTimestamp) { + return getRelativeTimeFromDate(this.lastRemoteRefreshSuccessTimestamp, true) + } if (!this.videoCacheForAllActiveProfileChannelsPresent) { return '' } if (this.cacheEntriesForAllActiveProfileChannels.length === 0) { return '' } @@ -90,6 +95,7 @@ export default defineComponent({ }, watch: { activeProfile: async function (_) { + this.lastRemoteRefreshSuccessTimestamp = null this.isLoading = true this.loadVideosFromCacheSometimes() }, @@ -178,6 +184,7 @@ export default defineComponent({ this.videoList = updateVideoListAfterProcessing(videoList) this.isLoading = false this.updateShowProgressBar(false) + this.lastRemoteRefreshSuccessTimestamp = new Date() this.batchUpdateSubscriptionDetails(subscriptionUpdates) }, diff --git a/src/renderer/components/subscriptions-videos/subscriptions-videos.js b/src/renderer/components/subscriptions-videos/subscriptions-videos.js index d48302d6b09c..6e69f9511d56 100644 --- a/src/renderer/components/subscriptions-videos/subscriptions-videos.js +++ b/src/renderer/components/subscriptions-videos/subscriptions-videos.js @@ -24,6 +24,7 @@ export default defineComponent({ videoList: [], errorChannels: [], attemptedFetch: false, + lastRemoteRefreshSuccessTimestamp: null, } }, computed: { @@ -48,6 +49,10 @@ export default defineComponent({ }, lastVideoRefreshTimestamp: function () { + // Cache is not ready when data is just loaded from remote + if (this.lastRemoteRefreshSuccessTimestamp) { + return getRelativeTimeFromDate(this.lastRemoteRefreshSuccessTimestamp, true) + } if (!this.videoCacheForAllActiveProfileChannelsPresent) { return '' } if (this.cacheEntriesForAllActiveProfileChannels.length === 0) { return '' } @@ -100,6 +105,7 @@ export default defineComponent({ }, watch: { activeProfile: async function (_) { + this.lastRemoteRefreshSuccessTimestamp = null this.isLoading = true this.loadVideosFromCacheSometimes() }, @@ -206,6 +212,7 @@ export default defineComponent({ this.videoList = updateVideoListAfterProcessing(videoList) this.isLoading = false this.updateShowProgressBar(false) + this.lastRemoteRefreshSuccessTimestamp = new Date() this.batchUpdateSubscriptionDetails(subscriptionUpdates) },