From 40d7278383ce8cd6402ea7aa4d643f371e177d85 Mon Sep 17 00:00:00 2001 From: Svallinn <41585298+Svallinn@users.noreply.github.com> Date: Sat, 3 Jul 2021 02:55:56 +0100 Subject: [PATCH] Invidious: Randomize instance on startup There are now two separate settings related to Invidious instances: - currentInvidiousInstance - defaultInvidiousInstance 'currentInvidiousInstance' is a value that exists solely in memory and it's the value used by the app to make the API calls, while 'defaultInvidiousInstance' is the value that can be persisted in the database by user action and will be used to initiate the 'currentInvidiousInstance' on startup. If the user has not saved a default value to the database, 'currentInvidiousInstance' is randomized from a fetched list of viable candidates. --- src/renderer/App.js | 18 +++- .../components/data-settings/data-settings.js | 4 +- .../ft-list-channel/ft-list-channel.js | 6 +- .../ft-list-playlist/ft-list-playlist.js | 6 +- .../components/ft-list-video/ft-list-video.js | 10 +-- .../ft-profile-channel-list.js | 8 +- .../ft-profile-filter-channels-list.js | 8 +- .../ft-share-button/ft-share-button.js | 8 +- .../general-settings/general-settings.js | 86 ++++++++++--------- .../general-settings/general-settings.vue | 42 +++++++-- .../components/playlist-info/playlist-info.js | 6 +- src/renderer/components/side-nav/side-nav.js | 6 +- src/renderer/components/top-nav/top-nav.js | 4 +- .../watch-video-comments.js | 8 +- .../watch-video-info/watch-video-info.js | 4 +- src/renderer/sass-partials/_settings.sass | 3 + src/renderer/store/modules/invidious.js | 61 +++++++++++-- src/renderer/store/modules/settings.js | 10 ++- src/renderer/views/Channel/Channel.js | 10 +-- src/renderer/views/Playlist/Playlist.js | 6 +- .../views/Subscriptions/Subscriptions.js | 6 +- src/renderer/views/Trending/Trending.js | 4 +- src/renderer/views/Watch/Watch.js | 18 ++-- static/locales/en-US.yaml | 12 ++- 24 files changed, 234 insertions(+), 120 deletions(-) diff --git a/src/renderer/App.js b/src/renderer/App.js index 3e2074cd3..e44fdaced 100644 --- a/src/renderer/App.js +++ b/src/renderer/App.js @@ -1,5 +1,5 @@ import Vue from 'vue' -import { mapActions } from 'vuex' +import { mapActions, mapMutations } from 'vuex' import { ObserveVisibility } from 'vue-observe-visibility' import FtFlexBox from './components/ft-flex-box/ft-flex-box.vue' import TopNav from './components/top-nav/top-nav.vue' @@ -79,10 +79,18 @@ export default Vue.extend({ }, externalPlayer: function () { return this.$store.getters.getExternalPlayer + }, + defaultInvidiousInstance: function () { + return this.$store.getters.getDefaultInvidiousInstance } }, mounted: function () { - this.grabUserSettings().then(() => { + this.grabUserSettings().then(async () => { + await this.fetchInvidiousInstances() + if (this.defaultInvidiousInstance === '') { + await this.setRandomCurrentInvidiousInstance() + } + this.grabAllProfiles(this.$t('Profile.All Channels')).then(async () => { this.grabHistory() this.grabAllPlaylists() @@ -378,6 +386,10 @@ export default Vue.extend({ } }, + ...mapMutations([ + 'setInvidiousInstancesList' + ]), + ...mapActions([ 'showToast', 'openExternalLink', @@ -387,6 +399,8 @@ export default Vue.extend({ 'grabAllPlaylists', 'getYoutubeUrlInfo', 'getExternalPlayerCmdArgumentsData', + 'fetchInvidiousInstances', + 'setRandomCurrentInvidiousInstance', 'setupListenerToSyncWindows' ]) } diff --git a/src/renderer/components/data-settings/data-settings.js b/src/renderer/components/data-settings/data-settings.js index 8c3487626..a7c7f3775 100644 --- a/src/renderer/components/data-settings/data-settings.js +++ b/src/renderer/components/data-settings/data-settings.js @@ -46,8 +46,8 @@ export default Vue.extend({ backendFallback: function () { return this.$store.getters.getBackendFallback }, - invidiousInstance: function () { - return this.$store.getters.getInvidiousInstance + currentInvidiousInstance: function () { + return this.$store.getters.getCurrentInvidiousInstance }, profileList: function () { return this.$store.getters.getProfileList diff --git a/src/renderer/components/ft-list-channel/ft-list-channel.js b/src/renderer/components/ft-list-channel/ft-list-channel.js index 93f0b1170..51639d56e 100644 --- a/src/renderer/components/ft-list-channel/ft-list-channel.js +++ b/src/renderer/components/ft-list-channel/ft-list-channel.js @@ -24,8 +24,8 @@ export default Vue.extend({ } }, computed: { - invidiousInstance: function () { - return this.$store.getters.getInvidiousInstance + currentInvidiousInstance: function () { + return this.$store.getters.getCurrentInvidiousInstance }, listType: function () { return this.$store.getters.getListType @@ -66,7 +66,7 @@ export default Vue.extend({ }, parseInvidiousData: function () { - this.thumbnail = this.data.authorThumbnails[2].url.replace('https://yt3.ggpht.com', `${this.invidiousInstance}/ggpht/`) + this.thumbnail = this.data.authorThumbnails[2].url.replace('https://yt3.ggpht.com', `${this.currentInvidiousInstance}/ggpht/`) this.channelName = this.data.author this.id = this.data.authorId if (this.hideChannelSubscriptions) { diff --git a/src/renderer/components/ft-list-playlist/ft-list-playlist.js b/src/renderer/components/ft-list-playlist/ft-list-playlist.js index 1d941d12f..d6305b9ec 100644 --- a/src/renderer/components/ft-list-playlist/ft-list-playlist.js +++ b/src/renderer/components/ft-list-playlist/ft-list-playlist.js @@ -29,8 +29,8 @@ export default Vue.extend({ } }, computed: { - invidiousInstance: function () { - return this.$store.getters.getInvidiousInstance + currentInvidiousInstance: function () { + return this.$store.getters.getCurrentInvidiousInstance }, listType: function () { @@ -79,7 +79,7 @@ export default Vue.extend({ parseInvidiousData: function () { this.title = this.data.title - this.thumbnail = this.data.playlistThumbnail.replace('https://i.ytimg.com', this.invidiousInstance).replace('hqdefault', 'mqdefault') + this.thumbnail = this.data.playlistThumbnail.replace('https://i.ytimg.com', this.currentInvidiousInstance).replace('hqdefault', 'mqdefault') this.channelName = this.data.author this.channelLink = this.data.authorUrl this.playlistLink = this.data.playlistId diff --git a/src/renderer/components/ft-list-video/ft-list-video.js b/src/renderer/components/ft-list-video/ft-list-video.js index b791d94c4..b114947dc 100644 --- a/src/renderer/components/ft-list-video/ft-list-video.js +++ b/src/renderer/components/ft-list-video/ft-list-video.js @@ -92,8 +92,8 @@ export default Vue.extend({ return this.$store.getters.getBackendPreference }, - invidiousInstance: function () { - return this.$store.getters.getInvidiousInstance + currentInvidiousInstance: function () { + return this.$store.getters.getCurrentInvidiousInstance }, inHistory: function () { @@ -103,11 +103,11 @@ export default Vue.extend({ }, invidiousUrl: function () { - return `${this.invidiousInstance}/watch?v=${this.id}` + return `${this.currentInvidiousInstance}/watch?v=${this.id}` }, invidiousChannelUrl: function () { - return `${this.invidiousInstance}/channel/${this.channelId}` + return `${this.currentInvidiousInstance}/channel/${this.channelId}` }, youtubeUrl: function () { @@ -156,7 +156,7 @@ export default Vue.extend({ thumbnail: function () { let baseUrl if (this.backendPreference === 'invidious') { - baseUrl = this.invidiousInstance + baseUrl = this.currentInvidiousInstance } else { baseUrl = 'https://i.ytimg.com' } diff --git a/src/renderer/components/ft-profile-channel-list/ft-profile-channel-list.js b/src/renderer/components/ft-profile-channel-list/ft-profile-channel-list.js index d5740bcb6..be061a479 100644 --- a/src/renderer/components/ft-profile-channel-list/ft-profile-channel-list.js +++ b/src/renderer/components/ft-profile-channel-list/ft-profile-channel-list.js @@ -42,8 +42,8 @@ export default Vue.extend({ backendPreference: function () { return this.$store.getters.getBackendPreference }, - invidiousInstance: function () { - return this.$store.getters.getInvidiousInstance + currentInvidiousInstance: function () { + return this.$store.getters.getCurrentInvidiousInstance }, profileList: function () { return this.$store.getters.getProfileList @@ -80,7 +80,7 @@ export default Vue.extend({ return 0 }).map((channel) => { if (this.backendPreference === 'invidious') { - channel.thumbnail = channel.thumbnail.replace('https://yt3.ggpht.com', `${this.invidiousInstance}/ggpht/`) + channel.thumbnail = channel.thumbnail.replace('https://yt3.ggpht.com', `${this.currentInvidiousInstance}/ggpht/`) } channel.selected = false return channel @@ -101,7 +101,7 @@ export default Vue.extend({ return 0 }).map((channel) => { if (this.backendPreference === 'invidious') { - channel.thumbnail = channel.thumbnail.replace('https://yt3.ggpht.com', `${this.invidiousInstance}/ggpht/`) + channel.thumbnail = channel.thumbnail.replace('https://yt3.ggpht.com', `${this.currentInvidiousInstance}/ggpht/`) } channel.selected = false return channel diff --git a/src/renderer/components/ft-profile-filter-channels-list/ft-profile-filter-channels-list.js b/src/renderer/components/ft-profile-filter-channels-list/ft-profile-filter-channels-list.js index 6ab9fdba2..9fe3146ae 100644 --- a/src/renderer/components/ft-profile-filter-channels-list/ft-profile-filter-channels-list.js +++ b/src/renderer/components/ft-profile-filter-channels-list/ft-profile-filter-channels-list.js @@ -35,8 +35,8 @@ export default Vue.extend({ backendPreference: function () { return this.$store.getters.getBackendPreference }, - invidiousInstance: function () { - return this.$store.getters.getInvidiousInstance + currentInvidiousInstance: function () { + return this.$store.getters.getCurrentInvidiousInstance }, profileList: function () { return this.$store.getters.getProfileList @@ -73,7 +73,7 @@ export default Vue.extend({ return index === -1 }).map((channel) => { if (this.backendPreference === 'invidious') { - channel.thumbnail = channel.thumbnail.replace('https://yt3.ggpht.com', `${this.invidiousInstance}/ggpht/`) + channel.thumbnail = channel.thumbnail.replace('https://yt3.ggpht.com', `${this.currentInvidiousInstance}/ggpht/`) } channel.selected = false return channel @@ -100,7 +100,7 @@ export default Vue.extend({ return index === -1 }).map((channel) => { if (this.backendPreference === 'invidious') { - channel.thumbnail = channel.thumbnail.replace('https://yt3.ggpht.com', `${this.invidiousInstance}/ggpht/`) + channel.thumbnail = channel.thumbnail.replace('https://yt3.ggpht.com', `${this.currentInvidiousInstance}/ggpht/`) } channel.selected = false return channel diff --git a/src/renderer/components/ft-share-button/ft-share-button.js b/src/renderer/components/ft-share-button/ft-share-button.js index 8ca4700c0..0efc7f15c 100644 --- a/src/renderer/components/ft-share-button/ft-share-button.js +++ b/src/renderer/components/ft-share-button/ft-share-button.js @@ -34,12 +34,12 @@ export default Vue.extend({ } }, computed: { - invidiousInstance: function () { - return this.$store.getters.getInvidiousInstance + currentInvidiousInstance: function () { + return this.$store.getters.getCurrentInvidiousInstance }, invidiousURL() { - let videoUrl = `${this.invidiousInstance}/watch?v=${this.id}` + let videoUrl = `${this.currentInvidiousInstance}/watch?v=${this.id}` // `playlistId` can be undefined if (this.playlistId && this.playlistId.length !== 0) { // `index` seems can be ignored @@ -49,7 +49,7 @@ export default Vue.extend({ }, invidiousEmbedURL() { - return `${this.invidiousInstance}/embed/${this.id}` + return `${this.currentInvidiousInstance}/embed/${this.id}` }, youtubeURL() { diff --git a/src/renderer/components/general-settings/general-settings.js b/src/renderer/components/general-settings/general-settings.js index bb74a52c1..8082da5a7 100644 --- a/src/renderer/components/general-settings/general-settings.js +++ b/src/renderer/components/general-settings/general-settings.js @@ -1,11 +1,11 @@ import Vue from 'vue' -import $ from 'jquery' -import { mapActions } from 'vuex' +import { mapActions, mapMutations } from 'vuex' import FtCard from '../ft-card/ft-card.vue' import FtSelect from '../ft-select/ft-select.vue' import FtInput from '../ft-input/ft-input.vue' import FtToggleSwitch from '../ft-toggle-switch/ft-toggle-switch.vue' import FtFlexBox from '../ft-flex-box/ft-flex-box.vue' +import FtButton from '../ft-button/ft-button.vue' import debounce from 'lodash.debounce' @@ -16,11 +16,11 @@ export default Vue.extend({ 'ft-select': FtSelect, 'ft-input': FtInput, 'ft-toggle-switch': FtToggleSwitch, - 'ft-flex-box': FtFlexBox + 'ft-flex-box': FtFlexBox, + 'ft-button': FtButton }, data: function () { return { - showInvidiousInstances: false, instanceNames: [], instanceValues: [], backendValues: [ @@ -62,8 +62,8 @@ export default Vue.extend({ return this.$store.getters.getUsingElectron }, - invidiousInstance: function () { - return this.$store.getters.getInvidiousInstance + currentInvidiousInstance: function () { + return this.$store.getters.getCurrentInvidiousInstance }, enableSearchSuggestions: function () { return this.$store.getters.getEnableSearchSuggestions @@ -101,6 +101,12 @@ export default Vue.extend({ regionValues: function () { return this.$store.getters.getRegionValues }, + invidiousInstancesList: function () { + return this.$store.getters.getInvidiousInstancesList + }, + defaultInvidiousInstance: function () { + return this.$store.getters.getDefaultInvidiousInstance + }, localeOptions: function () { return ['system'].concat(Object.keys(this.$i18n.messages)) @@ -147,44 +153,42 @@ export default Vue.extend({ } }, mounted: function () { - const requestUrl = 'https://api.invidious.io/instances.json' - $.getJSON(requestUrl, (response) => { - console.log(response) - const instances = response.filter((instance) => { - if (instance[0].includes('.onion') || instance[0].includes('.i2p') || instance[0].includes('yewtu.be')) { - return false - } else { - return true - } - }) - - this.instanceNames = instances.map((instance) => { - return instance[0] - }) - - this.instanceValues = instances.map((instance) => { - return instance[1].uri.replace(/\/$/, '') - }) - - this.showInvidiousInstances = true - }).fail((xhr, textStatus, error) => { - console.log(xhr) - console.log(textStatus) - console.log(requestUrl) - console.log(error) - }) - - this.updateInvidiousInstanceBounce = debounce(this.updateInvidiousInstance, 500) + this.setCurrentInvidiousInstanceBounce = + debounce(this.setCurrentInvidiousInstance, 500) }, beforeDestroy: function () { - if (this.invidiousInstance === '') { - this.updateInvidiousInstance('https://invidious.snopyta.org') + if (this.currentInvidiousInstance === '') { + // FIXME: If we call an action from here, there's no guarantee it will finish + // before the component is destroyed, which could bring up some problems + // Since I can't see any way to await it (because lifecycle hooks must be + // synchronous), unfortunately, we have to copy/paste the logic + // from the `setRandomCurrentInvidiousInstance` action onto here + const instanceList = this.invidiousInstancesList + const randomIndex = Math.floor(Math.random() * instanceList.length) + this.setCurrentInvidiousInstance(instanceList[randomIndex]) } }, methods: { handleInvidiousInstanceInput: function (input) { - const invidiousInstance = input.replace(/\/$/, '') - this.updateInvidiousInstanceBounce(invidiousInstance) + const instance = input.replace(/\/$/, '') + this.setCurrentInvidiousInstanceBounce(instance) + }, + + handleSetDefaultInstanceClick: function () { + const instance = this.currentInvidiousInstance + this.updateDefaultInvidiousInstance(instance) + + const message = this.$t('Default Invidious instance has been set to $') + this.showToast({ + message: message.replace('$', instance) + }) + }, + + handleClearDefaultInstanceClick: function () { + this.updateDefaultInvidiousInstance('') + this.showToast({ + message: this.$t('Default Invidious instance has been cleared') + }) }, handlePreferredApiBackend: function (backend) { @@ -196,6 +200,10 @@ export default Vue.extend({ } }, + ...mapMutations([ + 'setCurrentInvidiousInstance' + ]), + ...mapActions([ 'showToast', 'updateEnableSearchSuggestions', @@ -204,11 +212,11 @@ export default Vue.extend({ 'updateCheckForBlogPosts', 'updateBarColor', 'updateBackendPreference', + 'updateDefaultInvidiousInstance', 'updateLandingPage', 'updateRegion', 'updateListType', 'updateThumbnailPreference', - 'updateInvidiousInstance', 'updateForceLocalBackendForLegacy', 'updateCurrentLocale' ]) diff --git a/src/renderer/components/general-settings/general-settings.vue b/src/renderer/components/general-settings/general-settings.vue index c6d945536..cc4b26fb1 100644 --- a/src/renderer/components/general-settings/general-settings.vue +++ b/src/renderer/components/general-settings/general-settings.vue @@ -88,21 +88,47 @@ - - {{ $t('Settings.General Settings.View all Invidious instance information') }} - +
+ + {{ $t('Settings.General Settings.View all Invidious instance information') }} + +
+
+

+ {{ $t('Settings.General Settings.The currently set default instance is $').replace('$', defaultInvidiousInstance) }} +

+ + + + diff --git a/src/renderer/components/playlist-info/playlist-info.js b/src/renderer/components/playlist-info/playlist-info.js index d94b35993..e2234343b 100644 --- a/src/renderer/components/playlist-info/playlist-info.js +++ b/src/renderer/components/playlist-info/playlist-info.js @@ -35,8 +35,8 @@ export default Vue.extend({ } }, computed: { - invidiousInstance: function () { - return this.$store.getters.getInvidiousInstance + currentInvidiousInstance: function () { + return this.$store.getters.getCurrentInvidiousInstance }, listType: function () { @@ -95,7 +95,7 @@ export default Vue.extend({ methods: { sharePlaylist: function (method) { const youtubeUrl = `https://youtube.com/playlist?list=${this.id}` - const invidiousUrl = `${this.invidiousInstance}/playlist?list=${this.id}` + const invidiousUrl = `${this.currentInvidiousInstance}/playlist?list=${this.id}` switch (method) { case 'copyYoutube': diff --git a/src/renderer/components/side-nav/side-nav.js b/src/renderer/components/side-nav/side-nav.js index 9d74e4677..d5a52d416 100644 --- a/src/renderer/components/side-nav/side-nav.js +++ b/src/renderer/components/side-nav/side-nav.js @@ -15,8 +15,8 @@ export default Vue.extend({ backendPreference: function () { return this.$store.getters.getBackendPreference }, - invidiousInstance: function () { - return this.$store.getters.getInvidiousInstance + currentInvidiousInstance: function () { + return this.$store.getters.getCurrentInvidiousInstance }, profileList: function () { return this.$store.getters.getProfileList @@ -38,7 +38,7 @@ export default Vue.extend({ return 0 }).map((channel) => { if (this.backendPreference === 'invidious') { - channel.thumbnail = channel.thumbnail.replace('https://yt3.ggpht.com', `${this.invidiousInstance}/ggpht/`) + channel.thumbnail = channel.thumbnail.replace('https://yt3.ggpht.com', `${this.currentInvidiousInstance}/ggpht/`) } return channel diff --git a/src/renderer/components/top-nav/top-nav.js b/src/renderer/components/top-nav/top-nav.js index 380ebfe20..4279455ac 100644 --- a/src/renderer/components/top-nav/top-nav.js +++ b/src/renderer/components/top-nav/top-nav.js @@ -44,8 +44,8 @@ export default Vue.extend({ return this.$store.getters.getBarColor }, - invidiousInstance: function () { - return this.$store.getters.getInvidiousInstance + currentInvidiousInstance: function () { + return this.$store.getters.getCurrentInvidiousInstance }, backendFallback: function () { diff --git a/src/renderer/components/watch-video-comments/watch-video-comments.js b/src/renderer/components/watch-video-comments/watch-video-comments.js index c6f60db44..b4e468860 100644 --- a/src/renderer/components/watch-video-comments/watch-video-comments.js +++ b/src/renderer/components/watch-video-comments/watch-video-comments.js @@ -50,8 +50,8 @@ export default Vue.extend({ return this.$store.getters.getBackendFallback }, - invidiousInstance: function () { - return this.$store.getters.getInvidiousInstance + currentInvidiousInstance: function () { + return this.$store.getters.getCurrentInvidiousInstance }, hideCommentLikes: function () { return this.$store.getters.getHideCommentLikes @@ -276,7 +276,7 @@ export default Vue.extend({ const commentData = response.comments.map((comment) => { comment.showReplies = false comment.authorLink = comment.authorId - comment.authorThumb = comment.authorThumbnails[1].url.replace('https://yt3.ggpht.com', `${this.invidiousInstance}/ggpht/`) + comment.authorThumb = comment.authorThumbnails[1].url.replace('https://yt3.ggpht.com', `${this.currentInvidiousInstance}/ggpht/`) if (this.hideCommentLikes) { comment.likes = null } else { @@ -342,7 +342,7 @@ export default Vue.extend({ const commentData = response.comments.map((comment) => { comment.showReplies = false comment.authorLink = comment.authorId - comment.authorThumb = comment.authorThumbnails[1].url.replace('https://yt3.ggpht.com', `${this.invidiousInstance}/ggpht/`) + comment.authorThumb = comment.authorThumbnails[1].url.replace('https://yt3.ggpht.com', `${this.currentInvidiousInstance}/ggpht/`) if (this.hideCommentLikes) { comment.likes = null } else { diff --git a/src/renderer/components/watch-video-info/watch-video-info.js b/src/renderer/components/watch-video-info/watch-video-info.js index ef307690a..918d901ed 100644 --- a/src/renderer/components/watch-video-info/watch-video-info.js +++ b/src/renderer/components/watch-video-info/watch-video-info.js @@ -126,8 +126,8 @@ export default Vue.extend({ } }, computed: { - invidiousInstance: function () { - return this.$store.getters.getInvidiousInstance + currentInvidiousInstance: function () { + return this.$store.getters.getCurrentInvidiousInstance }, profileList: function () { diff --git a/src/renderer/sass-partials/_settings.sass b/src/renderer/sass-partials/_settings.sass index b9c523975..1a9cdf3cf 100644 --- a/src/renderer/sass-partials/_settings.sass +++ b/src/renderer/sass-partials/_settings.sass @@ -24,6 +24,9 @@ @media only screen and (max-width: 680px) width: 90% +.center + text-align: center + @media only screen and (max-width: 460px) .generalSettingsFlexBox, .playerSettingsFlexBox, .externalPlayerSettingsFlexBox justify-content: flex-start diff --git a/src/renderer/store/modules/invidious.js b/src/renderer/store/modules/invidious.js index 3ca523920..88380f53c 100644 --- a/src/renderer/store/modules/invidious.js +++ b/src/renderer/store/modules/invidious.js @@ -1,19 +1,58 @@ import $ from 'jquery' const state = { + currentInvidiousInstance: '', + invidiousInstancesList: null, isGetChannelInfoRunning: false } const getters = { - getIsGetChannelInfoRunning (state) { + getIsGetChannelInfoRunning(state) { return state.isGetChannelInfoRunning + }, + + getCurrentInvidiousInstance(state) { + return state.currentInvidiousInstance + }, + + getInvidiousInstancesList(state) { + return state.invidiousInstancesList } } const actions = { - invidiousAPICall ({ rootState }, payload) { + async fetchInvidiousInstances({ commit }) { + const requestUrl = 'https://api.invidious.io/instances.json' + + let response + try { + response = await $.getJSON(requestUrl) + } catch (err) { + console.log(err) + } + + const instances = response.filter((instance) => { + if (instance[0].includes('.onion') || instance[0].includes('.i2p') || instance[0].includes('yewtu.be')) { + return false + } else { + return true + } + }).map((instance) => { + return instance[1].uri.replace(/\/$/, '') + }) + + commit('setInvidiousInstancesList', instances) + }, + + setRandomCurrentInvidiousInstance({ commit, state }) { + const instanceList = state.invidiousInstancesList + const randomIndex = Math.floor(Math.random() * instanceList.length) + commit('setCurrentInvidiousInstance', instanceList[randomIndex]) + }, + + invidiousAPICall({ state }, payload) { return new Promise((resolve, reject) => { - const requestUrl = rootState.settings.invidiousInstance + '/api/v1/' + payload.resource + '/' + payload.id + '?' + $.param(payload.params) + const requestUrl = state.currentInvidiousInstance + '/api/v1/' + payload.resource + '/' + payload.id + '?' + $.param(payload.params) $.getJSON(requestUrl, (response) => { resolve(response) @@ -27,7 +66,7 @@ const actions = { }) }, - invidiousGetChannelInfo ({ commit, dispatch }, channelId) { + invidiousGetChannelInfo({ commit, dispatch }, channelId) { return new Promise((resolve, reject) => { commit('toggleIsGetChannelInfoRunning') @@ -48,7 +87,7 @@ const actions = { }) }, - invidiousGetPlaylistInfo ({ commit, dispatch }, payload) { + invidiousGetPlaylistInfo({ commit, dispatch }, payload) { return new Promise((resolve, reject) => { dispatch('invidiousAPICall', payload).then((response) => { resolve(response) @@ -61,7 +100,7 @@ const actions = { }) }, - invidiousGetVideoInformation ({ dispatch }, videoId) { + invidiousGetVideoInformation({ dispatch }, videoId) { return new Promise((resolve, reject) => { const payload = { resource: 'videos', @@ -81,8 +120,16 @@ const actions = { } const mutations = { - toggleIsGetChannelInfoRunning (state) { + toggleIsGetChannelInfoRunning(state) { state.isGetChannelInfoRunning = !state.isGetChannelInfoRunning + }, + + setCurrentInvidiousInstance(state, value) { + state.currentInvidiousInstance = value + }, + + setInvidiousInstancesList(state, value) { + state.invidiousInstancesList = value } } diff --git a/src/renderer/store/modules/settings.js b/src/renderer/store/modules/settings.js index cdf943a5d..62c951cb7 100644 --- a/src/renderer/store/modules/settings.js +++ b/src/renderer/store/modules/settings.js @@ -194,7 +194,6 @@ const state = { hideVideoLikesAndDislikes: false, hideVideoViews: false, hideWatchedSubs: false, - invidiousInstance: 'https://invidious.snopyta.org', landingPage: 'subscriptions', listType: 'grid', playNextVideo: false, @@ -250,6 +249,15 @@ const stateWithSideEffects = { } }, + defaultInvidiousInstance: { + defaultValue: '', + sideEffectsHandler: ({ commit, getters }, value) => { + if (value !== '' && getters.getCurrentInvidiousInstance !== value) { + commit('setCurrentInvidiousInstance', value) + } + } + }, + defaultVolume: { defaultValue: 1, sideEffectsHandler: (_, value) => { diff --git a/src/renderer/views/Channel/Channel.js b/src/renderer/views/Channel/Channel.js index 74a8f3c79..76577b3cf 100644 --- a/src/renderer/views/Channel/Channel.js +++ b/src/renderer/views/Channel/Channel.js @@ -73,8 +73,8 @@ export default Vue.extend({ return this.$store.getters.getBackendFallback }, - invidiousInstance: function () { - return this.$store.getters.getInvidiousInstance + currentInvidiousInstance: function () { + return this.$store.getters.getCurrentInvidiousInstance }, sessionSearchHistory: function () { @@ -350,17 +350,17 @@ export default Vue.extend({ } else { this.subCount = response.subCount } - this.thumbnailUrl = response.authorThumbnails[3].url.replace('https://yt3.ggpht.com', `${this.invidiousInstance}/ggpht/`) + this.thumbnailUrl = response.authorThumbnails[3].url.replace('https://yt3.ggpht.com', `${this.currentInvidiousInstance}/ggpht/`) this.channelDescription = autolinker.link(response.description) this.relatedChannels = response.relatedChannels.map((channel) => { - channel.authorThumbnails[channel.authorThumbnails.length - 1].url = channel.authorThumbnails[channel.authorThumbnails.length - 1].url.replace('https://yt3.ggpht.com', `${this.invidiousInstance}/ggpht/`) + channel.authorThumbnails[channel.authorThumbnails.length - 1].url = channel.authorThumbnails[channel.authorThumbnails.length - 1].url.replace('https://yt3.ggpht.com', `${this.currentInvidiousInstance}/ggpht/`) return channel }) this.latestVideos = response.latestVideos if (typeof (response.authorBanners) !== 'undefined') { - this.bannerUrl = response.authorBanners[0].url.replace('https://yt3.ggpht.com', `${this.invidiousInstance}/ggpht/`) + this.bannerUrl = response.authorBanners[0].url.replace('https://yt3.ggpht.com', `${this.currentInvidiousInstance}/ggpht/`) } this.isLoading = false diff --git a/src/renderer/views/Playlist/Playlist.js b/src/renderer/views/Playlist/Playlist.js index 725f5f487..d40a91bc0 100644 --- a/src/renderer/views/Playlist/Playlist.js +++ b/src/renderer/views/Playlist/Playlist.js @@ -34,8 +34,8 @@ export default Vue.extend({ backendFallback: function () { return this.$store.getters.getBackendFallback }, - invidiousInstance: function () { - return this.$store.getters.getInvidiousInstance + currentInvidiousInstance: function () { + return this.$store.getters.getCurrentInvidiousInstance } }, watch: { @@ -131,7 +131,7 @@ export default Vue.extend({ viewCount: result.viewCount, videoCount: result.videoCount, channelName: result.author, - channelThumbnail: result.authorThumbnails[2].url.replace('https://yt3.ggpht.com', `${this.invidiousInstance}/ggpht/`), + channelThumbnail: result.authorThumbnails[2].url.replace('https://yt3.ggpht.com', `${this.currentInvidiousInstance}/ggpht/`), channelId: result.authorId, infoSource: 'invidious' } diff --git a/src/renderer/views/Subscriptions/Subscriptions.js b/src/renderer/views/Subscriptions/Subscriptions.js index e0b6ae56a..619107cc3 100644 --- a/src/renderer/views/Subscriptions/Subscriptions.js +++ b/src/renderer/views/Subscriptions/Subscriptions.js @@ -40,8 +40,8 @@ export default Vue.extend({ return this.$store.getters.getBackendFallback }, - invidiousInstance: function () { - return this.$store.getters.getInvidiousInstance + currentInvidiousInstance: function () { + return this.$store.getters.getCurrentInvidiousInstance }, hideWatchedSubs: function () { @@ -378,7 +378,7 @@ export default Vue.extend({ getChannelVideosInvidiousRSS: function (channel, failedAttempts = 0) { return new Promise((resolve, reject) => { const parser = new Parser() - const feedUrl = `${this.invidiousInstance}/feed/channel/${channel.id}` + const feedUrl = `${this.currentInvidiousInstance}/feed/channel/${channel.id}` parser.parseURL(feedUrl).then(async (feed) => { resolve(await Promise.all(feed.items.map((video) => { diff --git a/src/renderer/views/Trending/Trending.js b/src/renderer/views/Trending/Trending.js index 8581acf69..2b8a23535 100644 --- a/src/renderer/views/Trending/Trending.js +++ b/src/renderer/views/Trending/Trending.js @@ -31,8 +31,8 @@ export default Vue.extend({ backendFallback: function () { return this.$store.getters.getBackendFallback }, - invidiousInstance: function () { - return this.$store.getters.getInvidiousInstance + currentInvidiousInstance: function () { + return this.$store.getters.getCurrentInvidiousInstance }, region: function () { return this.$store.getters.getRegion.toUpperCase() diff --git a/src/renderer/views/Watch/Watch.js b/src/renderer/views/Watch/Watch.js index 4058802f4..eeab21f9b 100644 --- a/src/renderer/views/Watch/Watch.js +++ b/src/renderer/views/Watch/Watch.js @@ -103,8 +103,8 @@ export default Vue.extend({ backendFallback: function () { return this.$store.getters.getBackendFallback }, - invidiousInstance: function () { - return this.$store.getters.getInvidiousInstance + currentInvidiousInstance: function () { + return this.$store.getters.getCurrentInvidiousInstance }, proxyVideos: function () { return this.$store.getters.getProxyVideos @@ -514,7 +514,7 @@ export default Vue.extend({ } this.dashSrc = this.createInvidiousDashManifest() - this.videoStoryboardSrc = `${this.invidiousInstance}/api/v1/storyboards/${this.videoId}?height=90` + this.videoStoryboardSrc = `${this.currentInvidiousInstance}/api/v1/storyboards/${this.videoId}?height=90` this.invidiousGetVideoInformation(this.videoId) .then(result => { @@ -540,14 +540,14 @@ export default Vue.extend({ } this.channelId = result.authorId this.channelName = result.author - this.channelThumbnail = result.authorThumbnails[1] ? result.authorThumbnails[1].url.replace('https://yt3.ggpht.com', `${this.invidiousInstance}/ggpht/`) : '' + this.channelThumbnail = result.authorThumbnails[1] ? result.authorThumbnails[1].url.replace('https://yt3.ggpht.com', `${this.currentInvidiousInstance}/ggpht/`) : '' this.videoPublished = result.published * 1000 this.videoDescriptionHtml = result.descriptionHtml this.recommendedVideos = result.recommendedVideos this.adaptiveFormats = result.adaptiveFormats this.isLive = result.liveNow this.captionHybridList = result.captions.map(caption => { - caption.url = this.invidiousInstance + caption.url + caption.url = this.currentInvidiousInstance + caption.url caption.type = '' caption.dataSource = 'invidious' return caption @@ -555,13 +555,13 @@ export default Vue.extend({ switch (this.thumbnailPreference) { case 'start': - this.thumbnail = `${this.invidiousInstance}/vi/${this.videoId}/maxres1.jpg` + this.thumbnail = `${this.currentInvidiousInstance}/vi/${this.videoId}/maxres1.jpg` break case 'middle': - this.thumbnail = `${this.invidiousInstance}/vi/${this.videoId}/maxres2.jpg` + this.thumbnail = `${this.currentInvidiousInstance}/vi/${this.videoId}/maxres2.jpg` break case 'end': - this.thumbnail = `${this.invidiousInstance}/vi/${this.videoId}/maxres3.jpg` + this.thumbnail = `${this.currentInvidiousInstance}/vi/${this.videoId}/maxres3.jpg` break default: this.thumbnail = result.videoThumbnails[0].url @@ -1033,7 +1033,7 @@ export default Vue.extend({ }, createInvidiousDashManifest: function () { - let url = `${this.invidiousInstance}/api/manifest/dash/id/${this.videoId}.mpd` + let url = `${this.currentInvidiousInstance}/api/manifest/dash/id/${this.videoId}.mpd` if (this.proxyVideos || !this.usingElectron) { url = url + '?local=true' diff --git a/static/locales/en-US.yaml b/static/locales/en-US.yaml index e543dde0a..8762ff98a 100644 --- a/static/locales/en-US.yaml +++ b/static/locales/en-US.yaml @@ -128,8 +128,13 @@ Settings: Beginning: Beginning Middle: Middle End: End - 'Invidious Instance (Default is https://invidious.snopyta.org)': Invidious Instance - (Default is https://invidious.snopyta.org) + Current Invidious Instance: Current Invidious Instance + # $ is replaced with the default Invidious instance + The currently set default instance is $: The currently set default instance is $ + No default instance has been set: No default instance has been set + Current instance will be randomized on startup: Current instance will be randomized on startup + Set Current Instance as Default: Set Current Instance as Default + Clear Default Instance: Clear Default Instance View all Invidious instance information: View all Invidious instance information Region for Trending: Region for Trending #! List countries @@ -647,6 +652,9 @@ Playing Next Video: Playing Next Video Playing Previous Video: Playing Previous Video Playing Next Video Interval: Playing next video in no time. Click to cancel. | Playing next video in {nextVideoInterval} second. Click to cancel. | Playing next video in {nextVideoInterval} seconds. Click to cancel. Canceled next video autoplay: Canceled next video autoplay +# $ is replaced with the default Invidious instance +Default Invidious instance has been set to $: Default Invidious instance has been set to $ +Default Invidious instance has been cleared: Default Invidious instance has been cleared 'The playlist has ended. Enable loop to continue playing': 'The playlist has ended. Enable loop to continue playing'