Allow Unsubscribing from Deleted Channels (#2283)

* unsub from deleted

* reset error message on invidious channel load

* fix error channels not showing

* Use errorMessage instead of isErrorMessage

Co-authored-by: absidue <48293849+absidue@users.noreply.github.com>

* Change "Error Channels" to "Channels with Errors"

Co-authored-by: absidue <48293849+absidue@users.noreply.github.com>

* use find instead of find index

Co-Authored-By: absidue <48293849+absidue@users.noreply.github.com>
Co-Authored-By: PikachuEXE <pikachuexe@gmail.com>

Co-authored-by: absidue <48293849+absidue@users.noreply.github.com>
Co-authored-by: PikachuEXE <pikachuexe@gmail.com>
This commit is contained in:
ChunkyProgrammer 2022-06-03 10:04:50 -04:00 committed by GitHub
parent 74dc309803
commit da095adc8c
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
7 changed files with 131 additions and 60 deletions

View File

@ -4,7 +4,8 @@ const state = {
allSubscriptionsList: [],
profileSubscriptions: {
activeProfile: MAIN_PROFILE_ID,
videoList: []
videoList: [],
errorChannels: []
}
}

View File

@ -50,6 +50,7 @@ export default Vue.extend({
searchResults: [],
shownElementList: [],
apiUsed: '',
errorMessage: '',
videoSelectValues: [
'newest',
'oldest',
@ -90,16 +91,14 @@ export default Vue.extend({
return this.$store.getters.getActiveProfile
},
isSubscribed: function () {
const subIndex = this.activeProfile.subscriptions.findIndex((channel) => {
subscriptionInfo: function () {
return this.activeProfile.subscriptions.find((channel) => {
return channel.id === this.id
})
}) ?? null
},
if (subIndex === -1) {
return false
} else {
return true
}
isSubscribed: function () {
return this.subscriptionInfo !== null
},
subscribedText: function () {
@ -251,6 +250,11 @@ export default Vue.extend({
this.apiUsed = 'local'
const expectedId = this.id
ytch.getChannelInfo({ channelId: expectedId }).then((response) => {
if (response.alertMessage) {
this.setErrorMessage(response.alertMessage)
return
}
this.errorMessage = ''
if (expectedId !== this.id) {
return
}
@ -401,8 +405,10 @@ export default Vue.extend({
this.bannerUrl = null
}
this.errorMessage = ''
this.isLoading = false
}).catch((err) => {
this.setErrorMessage(err.responseJSON.error)
console.log(err)
const errorMessage = this.$t('Invidious API Error (Click to copy)')
this.showToast({
@ -645,6 +651,16 @@ export default Vue.extend({
}
},
setErrorMessage: function (errorMessage) {
this.isLoading = false
this.errorMessage = errorMessage
this.id = this.subscriptionInfo.id
this.channelName = this.subscriptionInfo.name
this.thumbnailUrl = this.subscriptionInfo.thumbnail
this.bannerUrl = null
this.subCount = null
},
handleFetchMore: function () {
switch (this.currentTab) {
case 'videos':

View File

@ -3,7 +3,7 @@
ref="search"
>
<ft-loader
v-if="isLoading"
v-if="isLoading && !errorMessage"
:fullscreen="true"
/>
<ft-card
@ -61,6 +61,7 @@
</div>
<ft-flex-box
v-if="!errorMessage"
class="channelInfoTabs"
>
<div
@ -112,7 +113,7 @@
</div>
</ft-card>
<ft-card
v-if="!isLoading"
v-if="!isLoading && !errorMessage"
class="card"
>
<div
@ -194,6 +195,14 @@
</div>
</div>
</ft-card>
<ft-card
v-if="errorMessage"
class="card"
>
<p>
{{ errorMessage }}
</p>
</ft-card>
</div>
</template>

View File

@ -14,6 +14,10 @@
right: 10px;
}
.channelBubble {
display: inline-block;
}
@media only screen and (max-width: 350px) {
.floatingTopButton {
position: absolute

View File

@ -6,6 +6,7 @@ import FtButton from '../../components/ft-button/ft-button.vue'
import FtIconButton from '../../components/ft-icon-button/ft-icon-button.vue'
import FtFlexBox from '../../components/ft-flex-box/ft-flex-box.vue'
import FtElementList from '../../components/ft-element-list/ft-element-list.vue'
import FtChannelBubble from '../../components/ft-channel-bubble/ft-channel-bubble.vue'
import ytch from 'yt-channel-info'
import Parser from 'rss-parser'
@ -19,13 +20,15 @@ export default Vue.extend({
'ft-button': FtButton,
'ft-icon-button': FtIconButton,
'ft-flex-box': FtFlexBox,
'ft-element-list': FtElementList
'ft-element-list': FtElementList,
'ft-channel-bubble': FtChannelBubble
},
data: function () {
return {
isLoading: false,
dataLimit: 100,
videoList: []
videoList: [],
errorChannels: []
}
},
computed: {
@ -110,6 +113,7 @@ export default Vue.extend({
}))
} else {
this.videoList = subscriptionList.videoList
this.errorChannels = subscriptionList.errorChannels
}
} else {
this.getProfileSubscriptions()
@ -123,6 +127,10 @@ export default Vue.extend({
}
},
methods: {
goToChannel: function (id) {
this.$router.push({ path: `/channel/${id}` })
},
getSubscriptions: function () {
if (this.activeSubscriptionList.length === 0) {
this.isLoading = false
@ -144,10 +152,9 @@ export default Vue.extend({
let videoList = []
let channelCount = 0
this.errorChannels = []
this.activeSubscriptionList.forEach(async (channel) => {
let videos = []
if (!this.usingElectron || this.backendPreference === 'invidious') {
if (useRss) {
videos = await this.getChannelVideosInvidiousRSS(channel)
@ -174,7 +181,8 @@ export default Vue.extend({
const profileSubscriptions = {
activeProfile: this.activeProfile._id,
videoList: videoList
videoList: videoList,
errorChannels: this.errorChannels
}
this.videoList = await Promise.all(videoList.filter((video) => {
@ -226,6 +234,11 @@ export default Vue.extend({
getChannelVideosLocalScraper: function (channel, failedAttempts = 0) {
return new Promise((resolve, reject) => {
ytch.getChannelVideos({ channelId: channel.id, sortBy: 'latest' }).then(async (response) => {
if (response.alertMessage) {
this.errorChannels.push(channel)
resolve([])
return
}
const videos = await Promise.all(response.items.map(async (video) => {
if (video.liveNow) {
video.publishedDate = new Date().getTime()
@ -297,33 +310,38 @@ export default Vue.extend({
resolve(items)
}).catch((err) => {
console.log(err)
const errorMessage = this.$t('Local API Error (Click to copy)')
this.showToast({
message: `${errorMessage}: ${err}`,
time: 10000,
action: () => {
navigator.clipboard.writeText(err)
}
})
switch (failedAttempts) {
case 0:
resolve(this.getChannelVideosLocalScraper(channel, failedAttempts + 1))
break
case 1:
if (this.backendFallback) {
this.showToast({
message: this.$t('Falling back to Invidious API')
})
resolve(this.getChannelVideosInvidiousRSS(channel, failedAttempts + 1))
} else {
resolve([])
if (err.toString().match(/404/)) {
this.errorChannels.push(channel)
resolve([])
} else {
const errorMessage = this.$t('Local API Error (Click to copy)')
this.showToast({
message: `${errorMessage}: ${err}`,
time: 10000,
action: () => {
navigator.clipboard.writeText(err)
}
break
case 2:
resolve(this.getChannelVideosLocalScraper(channel, failedAttempts + 1))
break
default:
resolve([])
})
switch (failedAttempts) {
case 0:
resolve(this.getChannelVideosLocalScraper(channel, failedAttempts + 1))
break
case 1:
if (this.backendFallback) {
this.showToast({
message: this.$t('Falling back to Invidious API')
})
resolve(this.getChannelVideosInvidiousRSS(channel, failedAttempts + 1))
} else {
resolve([])
}
break
case 2:
resolve(this.getChannelVideosLocalScraper(channel, failedAttempts + 1))
break
default:
resolve([])
}
}
})
})
@ -403,25 +421,30 @@ export default Vue.extend({
navigator.clipboard.writeText(err)
}
})
switch (failedAttempts) {
case 0:
resolve(this.getChannelVideosInvidiousScraper(channel, failedAttempts + 1))
break
case 1:
if (this.backendFallback) {
this.showToast({
message: this.$t('Falling back to the local API')
})
resolve(this.getChannelVideosLocalRSS(channel, failedAttempts + 1))
} else {
if (err.toString().match(/500/)) {
this.errorChannels.push(channel)
resolve([])
} else {
switch (failedAttempts) {
case 0:
resolve(this.getChannelVideosInvidiousScraper(channel, failedAttempts + 1))
break
case 1:
if (this.backendFallback) {
this.showToast({
message: this.$t('Falling back to the local API')
})
resolve(this.getChannelVideosLocalRSS(channel, failedAttempts + 1))
} else {
resolve([])
}
break
case 2:
resolve(this.getChannelVideosInvidiousScraper(channel, failedAttempts + 1))
break
default:
resolve([])
}
break
case 2:
resolve(this.getChannelVideosInvidiousScraper(channel, failedAttempts + 1))
break
default:
resolve([])
}
}
})
})

View File

@ -8,6 +8,22 @@
v-else
class="card"
>
<div
v-if="errorChannels.length !== 0"
>
<h3> {{ $t("Subscriptions.Error Channels") }}</h3>
<div>
<ft-channel-bubble
v-for="(channel, index) in errorChannels"
:key="index"
:channel-name="channel.name"
:channel-id="channel.id"
:channel-thumbnail="channel.thumbnail"
class="channelBubble"
@click="goToChannel(channel.id)"
/>
</div>
</div>
<h3>{{ $t("Subscriptions.Subscriptions") }}</h3>
<ft-flex-box
v-if="activeVideoList.length === 0"

View File

@ -78,6 +78,8 @@ Search Filters:
Subscriptions:
# On Subscriptions Page
Subscriptions: Subscriptions
# channels that were likely deleted
Error Channels: Channels with Errors
Latest Subscriptions: Latest Subscriptions
This profile has a large number of subscriptions. Forcing RSS to avoid rate limiting: This
profile has a large number of subscriptions. Forcing RSS to avoid rate limiting