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.
This commit is contained in:
parent
d55be8dcc5
commit
40d7278383
|
@ -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'
|
||||
])
|
||||
}
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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) {
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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'
|
||||
}
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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() {
|
||||
|
|
|
@ -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'
|
||||
])
|
||||
|
|
|
@ -88,21 +88,47 @@
|
|||
</div>
|
||||
<ft-flex-box class="generalSettingsFlexBox">
|
||||
<ft-input
|
||||
:placeholder="$t('Settings.General Settings[\'Invidious Instance (Default is https://invidious.snopyta.org)\']')"
|
||||
:placeholder="$t('Settings.General Settings.Current Invidious Instance')"
|
||||
:show-arrow="false"
|
||||
:show-label="true"
|
||||
:value="invidiousInstance"
|
||||
:data-list="instanceValues"
|
||||
:value="currentInvidiousInstance"
|
||||
:data-list="invidiousInstancesList"
|
||||
:tooltip="$t('Tooltips.General Settings.Invidious Instance')"
|
||||
@input="handleInvidiousInstanceInput"
|
||||
/>
|
||||
</ft-flex-box>
|
||||
<ft-flex-box>
|
||||
<a
|
||||
href="https://api.invidious.io"
|
||||
>
|
||||
{{ $t('Settings.General Settings.View all Invidious instance information') }}
|
||||
</a>
|
||||
<div>
|
||||
<a
|
||||
href="https://api.invidious.io"
|
||||
>
|
||||
{{ $t('Settings.General Settings.View all Invidious instance information') }}
|
||||
</a>
|
||||
</div>
|
||||
</ft-flex-box>
|
||||
<p
|
||||
v-if="defaultInvidiousInstance !== ''"
|
||||
class="center"
|
||||
>
|
||||
{{ $t('Settings.General Settings.The currently set default instance is $').replace('$', defaultInvidiousInstance) }}
|
||||
</p>
|
||||
<template v-else>
|
||||
<p class="center">
|
||||
{{ $t('Settings.General Settings.No default instance has been set') }}
|
||||
</p>
|
||||
<p class="center">
|
||||
{{ $t('Settings.General Settings.Current instance will be randomized on startup') }}
|
||||
</p>
|
||||
</template>
|
||||
<ft-flex-box>
|
||||
<ft-button
|
||||
:label="$t('Settings.General Settings.Set Current Instance as Default')"
|
||||
@click="handleSetDefaultInstanceClick"
|
||||
/>
|
||||
<ft-button
|
||||
:label="$t('Settings.General Settings.Clear Default Instance')"
|
||||
@click="handleClearDefaultInstanceClick"
|
||||
/>
|
||||
</ft-flex-box>
|
||||
</ft-card>
|
||||
</template>
|
||||
|
|
|
@ -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':
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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 () {
|
||||
|
|
|
@ -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 {
|
||||
|
|
|
@ -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 () {
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -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) => {
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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'
|
||||
}
|
||||
|
|
|
@ -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) => {
|
||||
|
|
|
@ -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()
|
||||
|
|
|
@ -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'
|
||||
|
|
|
@ -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'
|
||||
|
||||
|
|
Loading…
Reference in New Issue