diff --git a/src/renderer/components/side-nav/side-nav.vue b/src/renderer/components/side-nav/side-nav.vue
index ac0b5ad0..4c55b918 100644
--- a/src/renderer/components/side-nav/side-nav.vue
+++ b/src/renderer/components/side-nav/side-nav.vue
@@ -32,6 +32,30 @@
{{ $t("Subscriptions.Subscriptions") }}
+ {
+ return a.name.localeCompare(b.name, this.locale)
+ })
+ },
+
+ handleInput: function(input) {
+ this.query = input
+ this.filterChannels()
+ },
+
+ filterChannels: function () {
+ if (this.query === '') {
+ this.filteredChannels = []
+ return
+ }
+
+ const escapedQuery = this.query.replace(/[.*+?^${}()|[\]\\]/g, '\\$&')
+ const re = new RegExp(escapedQuery, 'i')
+ this.filteredChannels = this.subscribedChannels.filter(channel => {
+ return re.test(channel.name)
+ })
+ },
+
+ handleUnsubscribeButtonClick: function(channel) {
+ this.channelToUnsubscribe = channel
+ this.showUnsubscribePrompt = true
+ },
+
+ handleUnsubscribePromptClick: function(value) {
+ this.showUnsubscribePrompt = false
+ if (value !== 'yes') {
+ this.channelToUnsubscribe = null
+ return
+ }
+ this.unsubscribeChannel()
+ },
+
+ unsubscribeChannel: function () {
+ const currentProfile = JSON.parse(JSON.stringify(this.activeProfile))
+ let index = currentProfile.subscriptions.findIndex(channel => {
+ return channel.id === this.channelToUnsubscribe.id
+ })
+ currentProfile.subscriptions.splice(index, 1)
+
+ this.updateProfile(currentProfile)
+ this.showToast({
+ message: this.$t('Channels.Unsubscribed').replace('$', this.channelToUnsubscribe.name)
+ })
+
+ index = this.subscribedChannels.findIndex(channel => {
+ return channel.id === this.channelToUnsubscribe.id
+ })
+ this.subscribedChannels.splice(index, 1)
+
+ index = this.filteredChannels.findIndex(channel => {
+ return channel.id === this.channelToUnsubscribe.id
+ })
+ if (index !== -1) {
+ this.filteredChannels.splice(index, 1)
+ }
+
+ this.channelToUnsubscribe = null
+ },
+
+ thumbnailURL: function(originalURL) {
+ let newURL = originalURL
+ if (originalURL.indexOf('ggpht.com') > -1) {
+ if (this.backendPreference === 'invidious') { // YT to IV
+ newURL = originalURL.replace(this.re.ytToIv, `${this.currentInvidiousInstance}/ggpht/$1`)
+ }
+ } else {
+ if (this.backendPreference === 'local') { // IV to YT
+ newURL = originalURL.replace(this.re.ivToYt, `${this.ytBaseURL}/$1`)
+ } else { // IV to IV
+ newURL = originalURL.replace(this.re.ivToIv, `${this.currentInvidiousInstance}/$1`)
+ }
+ }
+
+ return newURL.replace(this.re.url, `$1${this.thumbnailSize}$2`)
+ },
+
+ updateThumbnail: function(channel) {
+ this.errorCount += 1
+ if (this.backendPreference === 'local') {
+ // avoid too many concurrent requests
+ setTimeout(() => {
+ ytch.getChannelInfo({ channelId: channel.id }).then(response => {
+ this.updateSubscriptionDetails({
+ channelThumbnailUrl: this.thumbnailURL(response.authorThumbnails[0].url),
+ channelName: channel.name,
+ channelId: channel.id
+ })
+ })
+ }, this.errorCount * 500)
+ } else {
+ setTimeout(() => {
+ this.invidiousGetChannelInfo(channel.id).then(response => {
+ this.updateSubscriptionDetails({
+ channelThumbnailUrl: this.thumbnailURL(response.authorThumbnails[0].url),
+ channelName: channel.name,
+ channelId: channel.id
+ })
+ })
+ }, this.errorCount * 500)
+ }
+ },
+
+ goToChannel: function (id) {
+ this.$router.push({ path: `/channel/${id}` })
+ },
+
+ ...mapActions([
+ 'showToast',
+ 'updateProfile',
+ 'updateSubscriptionDetails',
+ 'invidiousGetChannelInfo'
+ ])
+ }
+})
diff --git a/src/renderer/views/SubscribedChannels/SubscribedChannels.vue b/src/renderer/views/SubscribedChannels/SubscribedChannels.vue
new file mode 100644
index 00000000..288f9715
--- /dev/null
+++ b/src/renderer/views/SubscribedChannels/SubscribedChannels.vue
@@ -0,0 +1,70 @@
+
+
+
+ {{ $t('Channels.Title') }}
+
+
+
+ {{ $t('Channels.Empty') }}
+
+
+
+
+ {{ $t('Channels.Count').replace('$', channelList.length) }}
+
+
+
+
+
+
+
+ {{ channel.name }}
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/static/locales/en-US.yaml b/static/locales/en-US.yaml
index 8bbe8052..2dd9ca96 100644
--- a/static/locales/en-US.yaml
+++ b/static/locales/en-US.yaml
@@ -90,6 +90,15 @@ Subscriptions:
Refresh Subscriptions: Refresh Subscriptions
Load More Videos: Load More Videos
More: More
+Channels:
+ Channels: Channels
+ Title: Channel List
+ Search bar placeholder: Search Channels
+ Count: $ channel(s) found.
+ Empty: Your channel list is currently empty.
+ Unsubscribe: Unsubscribe
+ Unsubscribed: $ has been removed from your subscriptions
+ Unsubscribe Prompt: Are you sure you want to unsubscribe from "$"?
Trending:
Trending: Trending
Default: Default