diff --git a/package-lock.json b/package-lock.json
index 344251cc..8fdf9ba5 100644
--- a/package-lock.json
+++ b/package-lock.json
@@ -11136,6 +11136,14 @@
}
}
},
+ "javascript-time-ago": {
+ "version": "2.0.13",
+ "resolved": "https://registry.npmjs.org/javascript-time-ago/-/javascript-time-ago-2.0.13.tgz",
+ "integrity": "sha512-zH+obXUQ4vlc9UlERFe637rNJQaVYLizwODUfGzYN/cNW/owkk5wzb327gAfEXFpI4yhFcStEaoqoJtMGAmrAg==",
+ "requires": {
+ "relative-time-format": "^0.1.3"
+ }
+ },
"jest": {
"version": "26.4.2",
"resolved": "https://registry.npmjs.org/jest/-/jest-26.4.2.tgz",
@@ -16240,6 +16248,11 @@
"integrity": "sha1-VNvzd+UUQKypCkzSdGANP/LYiKk=",
"dev": true
},
+ "relative-time-format": {
+ "version": "0.1.3",
+ "resolved": "https://registry.npmjs.org/relative-time-format/-/relative-time-format-0.1.3.tgz",
+ "integrity": "sha512-0O6i4fKjsx8qhz57zorG+LrIDnF9pSvP5s7H9R1Nb5nSqih5dvRyKzNKs6MxhL3bv4iwsz4DuDwAyw+c47QFIA=="
+ },
"remove-trailing-separator": {
"version": "1.1.0",
"resolved": "https://registry.npmjs.org/remove-trailing-separator/-/remove-trailing-separator-1.1.0.tgz",
@@ -16522,6 +16535,31 @@
"sprintf-js": "^1.1.2"
}
},
+ "rss-parser": {
+ "version": "3.9.0",
+ "resolved": "https://registry.npmjs.org/rss-parser/-/rss-parser-3.9.0.tgz",
+ "integrity": "sha512-wlRSfGrotOXuWo19Dtl2KmQt7o9i5zzCExUrxpechE0O54BAx7JD+xhWyGumPPqiJj771ndflV3sE3bTHen0HQ==",
+ "requires": {
+ "entities": "^2.0.3",
+ "xml2js": "^0.4.19"
+ },
+ "dependencies": {
+ "entities": {
+ "version": "2.0.3",
+ "resolved": "https://registry.npmjs.org/entities/-/entities-2.0.3.tgz",
+ "integrity": "sha512-MyoZ0jgnLvB2X3Lg5HqpFmn1kybDiIfEQmKzTb5apr51Rb+T3KdmMiqa70T+bhGnyv7bQ6WMj2QMHpGMmlrUYQ=="
+ }
+ }
+ },
+ "rss-to-json": {
+ "version": "1.1.1",
+ "resolved": "https://registry.npmjs.org/rss-to-json/-/rss-to-json-1.1.1.tgz",
+ "integrity": "sha512-d+TwrFI5wAHbZ/fTd3Pvty14tadBjKHAjfMcUam9FWoWrC9g5rHJN9Slw10OZwk6Mey+hqdXwdmymO7d8ebVmw==",
+ "requires": {
+ "axios": "^0.19.2",
+ "xml2json": "^0.12.0"
+ }
+ },
"rsvp": {
"version": "4.8.5",
"resolved": "https://registry.npmjs.org/rsvp/-/rsvp-4.8.5.tgz",
@@ -20249,6 +20287,15 @@
"integrity": "sha512-A5CUptxDsvxKJEU3yO6DuWBSJz/qizqzJKOMIfUJHETbBw/sFaDxgd6fxm1ewUaM0jZ444Fc5vC5ROYurg/4Pw==",
"dev": true
},
+ "xml2js": {
+ "version": "0.4.23",
+ "resolved": "https://registry.npmjs.org/xml2js/-/xml2js-0.4.23.tgz",
+ "integrity": "sha512-ySPiMjM0+pLDftHgXY4By0uswI3SPKLDw/i3UXbnO8M/p28zqexCUoPmQFrYD+/1BzhGJSs2i1ERWKJAtiLrug==",
+ "requires": {
+ "sax": ">=0.6.0",
+ "xmlbuilder": "~11.0.0"
+ }
+ },
"xml2json": {
"version": "0.12.0",
"resolved": "https://registry.npmjs.org/xml2json/-/xml2json-0.12.0.tgz",
@@ -20259,6 +20306,11 @@
"node-expat": "^2.3.18"
}
},
+ "xmlbuilder": {
+ "version": "11.0.1",
+ "resolved": "https://registry.npmjs.org/xmlbuilder/-/xmlbuilder-11.0.1.tgz",
+ "integrity": "sha512-fDlsI/kFEx7gLvbecc0/ohLG50fugQp8ryHzMTuW9vSa1GJ0XYWKnhsUx7oie3G98+r56aTQIUB4kht42R3JvA=="
+ },
"xmlchars": {
"version": "2.2.0",
"resolved": "https://registry.npmjs.org/xmlchars/-/xmlchars-2.2.0.tgz",
diff --git a/package.json b/package.json
index 752f94ad..24fc7771 100644
--- a/package.json
+++ b/package.json
@@ -25,6 +25,7 @@
"mediaelement": "^4.2.16",
"nedb": "^1.8.0",
"opml-to-json": "0.0.3",
+ "rss-parser": "^3.9.0",
"video.js": "7.6.6",
"videojs-abloop": "^1.1.2",
"videojs-contrib-quality-levels": "^2.0.9",
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 d1117955..5ab2216d 100644
--- a/src/renderer/components/ft-list-video/ft-list-video.js
+++ b/src/renderer/components/ft-list-video/ft-list-video.js
@@ -255,7 +255,8 @@ export default Vue.extend({
liveStreamString: this.$t('Video.Watching'),
upcomingString: this.$t('Video.Published.Upcoming'),
isLive: this.isLive,
- isUpcoming: this.data.isUpcoming
+ isUpcoming: this.data.isUpcoming,
+ isRSS: this.data.isRSS
}).then((data) => {
this.uploadedTime = data
}).catch((error) => {
diff --git a/src/renderer/components/ft-profile-selector/ft-profile-selector.css b/src/renderer/components/ft-profile-selector/ft-profile-selector.css
index f630dc0c..1d4559f5 100644
--- a/src/renderer/components/ft-profile-selector/ft-profile-selector.css
+++ b/src/renderer/components/ft-profile-selector/ft-profile-selector.css
@@ -1,6 +1,6 @@
.colorOption {
- width: 50px;
- height: 50px;
+ width: 40px;
+ height: 40px;
margin: 10px;
cursor: pointer;
border-radius: 200px 200px 200px 200px;
@@ -8,10 +8,10 @@
}
.initial {
- font-size: 25px;
+ font-size: 20px;
text-align: center;
position: relative;
- bottom: 27px;
+ bottom: 30px;
}
#profileList {
@@ -39,10 +39,18 @@
.profile {
cursor: pointer;
+ height: 50px;
+ -webkit-transition: background 0.2s ease-out;
+ -moz-transition: background 0.2s ease-out;
+ -o-transition: background 0.2s ease-out;
+ transition: background 0.2s ease-out;
}
.profile:hover {
background-color: var(--side-nav-hover-color);
+ -moz-transition: background 0.2s ease-in;
+ -o-transition: background 0.2s ease-in;
+ transition: background 0.2s ease-in;
}
.profile .colorOption {
@@ -51,6 +59,10 @@
bottom: 5px;
}
+.profileName {
+ line-height: 50px;
+}
+
.profileListTitle {
position: absolute;
top: -15px;
diff --git a/src/renderer/components/ft-profile-selector/ft-profile-selector.js b/src/renderer/components/ft-profile-selector/ft-profile-selector.js
index f63d5aa0..218e7434 100644
--- a/src/renderer/components/ft-profile-selector/ft-profile-selector.js
+++ b/src/renderer/components/ft-profile-selector/ft-profile-selector.js
@@ -36,6 +36,16 @@ export default Vue.extend({
}
},
mounted: function () {
+ setTimeout(() => {
+ const profileIndex = this.profileList.findIndex((profile) => {
+ return profile._id === this.defaultProfile
+ })
+
+ if (profileIndex !== -1) {
+ this.updateActiveProfile(profileIndex)
+ }
+ }, 100)
+
$('#profileList').focusout(() => {
$('#profileList')[0].style.display = 'none'
})
@@ -65,8 +75,9 @@ export default Vue.extend({
return
}
this.updateActiveProfile(index)
+ const message = this.$t('Profile.$ is now the active profile').replace('$', profile.name)
this.showToast({
- message: `${profile.name} is now the active profile`
+ message: message
})
$('#profileList').focusout()
},
diff --git a/src/renderer/components/ft-profile-selector/ft-profile-selector.vue b/src/renderer/components/ft-profile-selector/ft-profile-selector.vue
index e8c864d3..8f865446 100644
--- a/src/renderer/components/ft-profile-selector/ft-profile-selector.vue
+++ b/src/renderer/components/ft-profile-selector/ft-profile-selector.vue
@@ -44,7 +44,9 @@
{{ profileInitials[index] }}
-
+
{{ profile.name }}
diff --git a/src/renderer/components/subscription-settings/subscription-settings.js b/src/renderer/components/subscription-settings/subscription-settings.js
index 7d5d2ef7..5c8fe9e0 100644
--- a/src/renderer/components/subscription-settings/subscription-settings.js
+++ b/src/renderer/components/subscription-settings/subscription-settings.js
@@ -1,4 +1,5 @@
import Vue from 'vue'
+import { mapActions } from 'vuex'
import FtCard from '../ft-card/ft-card.vue'
import FtToggleSwitch from '../ft-toggle-switch/ft-toggle-switch.vue'
import FtButton from '../ft-button/ft-button.vue'
@@ -27,9 +28,18 @@ export default Vue.extend({
]
}
},
- methods: {
- goToChannel: function () {
- console.log('TODO: Handle goToChannel')
+ computed: {
+ hideWatchedSubs: function () {
+ return this.$store.getters.getHideWatchedSubs
+ },
+ useRssFeeds: function () {
+ return this.$store.getters.getUseRssFeeds
}
+ },
+ methods: {
+ ...mapActions([
+ 'updateHideWatchedSubs',
+ 'updateUseRssFeeds'
+ ])
}
})
diff --git a/src/renderer/components/subscription-settings/subscription-settings.vue b/src/renderer/components/subscription-settings/subscription-settings.vue
index cdc82dc3..aa1c2e79 100644
--- a/src/renderer/components/subscription-settings/subscription-settings.vue
+++ b/src/renderer/components/subscription-settings/subscription-settings.vue
@@ -5,16 +5,24 @@
- {{ title }}
+ {{ $t("Settings.Subscription Settings.Subscription Settings") }}
+
diff --git a/src/renderer/store/modules/settings.js b/src/renderer/store/modules/settings.js
index ab3acbc4..f51346f1 100644
--- a/src/renderer/store/modules/settings.js
+++ b/src/renderer/store/modules/settings.js
@@ -57,6 +57,7 @@ const state = {
debugMode: false,
disctractionFreeMode: false,
hideWatchedSubs: false,
+ useRssFeeds: false,
usingElectron: true
}
@@ -157,13 +158,21 @@ const getters = {
return state.defaultQuality
},
+ getHideWatchedSubs: () => {
+ return state.hideWatchedSubs
+ },
+
+ getUseRssFeeds: () => {
+ return state.useRssFeeds
+ },
+
getUsingElectron: () => {
return state.usingElectron
}
}
const actions = {
- grabUserSettings ({ dispatch, commit }) {
+ grabUserSettings ({ dispatch, commit, rootState }) {
settingsDb.find({}, (err, results) => {
if (!err) {
console.log(results)
@@ -206,6 +215,12 @@ const actions = {
case 'barColor':
commit('setBarColor', result.value)
break
+ case 'hideWatchedSubs':
+ commit('setHideWatchedSubs', result.value)
+ break
+ case 'useRssFeeds':
+ commit('setUseRssFeeds', result.value)
+ break
case 'rememberHistory':
commit('setRememberHistory', result.value)
break
@@ -341,6 +356,22 @@ const actions = {
})
},
+ updateHideWatchedSubs ({ commit }, hideWatchedSubs) {
+ settingsDb.update({ _id: 'hideWatchedSubs' }, { _id: 'hideWatchedSubs', value: hideWatchedSubs }, { upsert: true }, (err, numReplaced) => {
+ if (!err) {
+ commit('setHideWatchedSubs', hideWatchedSubs)
+ }
+ })
+ },
+
+ updateUseRssFeeds ({ commit }, useRssFeeds) {
+ settingsDb.update({ _id: 'useRssFeeds' }, { _id: 'useRssFeeds', value: useRssFeeds }, { upsert: true }, (err, numReplaced) => {
+ if (!err) {
+ commit('setUseRssFeeds', useRssFeeds)
+ }
+ })
+ },
+
updateRememberHistory ({ commit }, history) {
settingsDb.update({ _id: 'rememberHistory' }, { _id: 'rememberHistory', value: history }, { upsert: true }, (err, numReplaced) => {
if (!err) {
@@ -546,6 +577,9 @@ const mutations = {
setHideWatchedSubs (state, hideWatchedSubs) {
state.hideWatchedSubs = hideWatchedSubs
},
+ setUseRssFeeds (state, useRssFeeds) {
+ state.useRssFeeds = useRssFeeds
+ },
setUsingElectron (state, usingElectron) {
state.usingElectron = usingElectron
},
diff --git a/src/renderer/store/modules/subscriptions.js b/src/renderer/store/modules/subscriptions.js
index 84e36201..6bbf944c 100644
--- a/src/renderer/store/modules/subscriptions.js
+++ b/src/renderer/store/modules/subscriptions.js
@@ -1,7 +1,5 @@
-import ytch from 'yt-channel-info'
-
const state = {
- subscriptions: [],
+ allSubscriptionsList: [],
profileSubscriptions: {
activeProfile: 0,
videoList: []
@@ -9,8 +7,8 @@ const state = {
}
const getters = {
- getSubscriptions: () => {
- return state.subscriptions
+ getAllSubscriptionsList: () => {
+ return state.allSubscriptionsList
},
getProfileSubscriptions: () => {
return state.profileSubscriptions
@@ -18,8 +16,8 @@ const getters = {
}
const actions = {
- updateSubscriptions ({ commit }, subscriptions) {
- commit('setSubscriptions', subscriptions)
+ updateAllSubscriptionsList ({ commit }, subscriptions) {
+ commit('setAllSubscriptionsList', subscriptions)
},
updateProfileSubscriptions ({ commit }, subscriptions) {
commit('setProfileSubscriptions', subscriptions)
@@ -27,8 +25,8 @@ const actions = {
}
const mutations = {
- setSubscriptions (state, subscriptions) {
- state.subscriptions = subscriptions
+ setAllSubscriptionsList (state, allSubscriptionsList) {
+ state.allSubscriptionsList = allSubscriptionsList
},
setProfileSubscriptions (state, profileSubscriptions) {
state.profileSubscriptions = profileSubscriptions
diff --git a/src/renderer/store/modules/utils.js b/src/renderer/store/modules/utils.js
index 2ecd99d4..bfa780fc 100644
--- a/src/renderer/store/modules/utils.js
+++ b/src/renderer/store/modules/utils.js
@@ -265,6 +265,8 @@ const actions = {
} else if (payload.isUpcoming || payload.publishText === null) {
// the check for null is currently just an inferring of knowledge, because there is no other possibility left
return payload.upcomingString
+ } else if (payload.isRSS) {
+ return payload.publishText
}
const strings = payload.publishText.split(' ')
const singular = (strings[0] === '1')
diff --git a/src/renderer/views/ProfileEdit/ProfileEdit.js b/src/renderer/views/ProfileEdit/ProfileEdit.js
index 28fdbf05..aece2bd6 100644
--- a/src/renderer/views/ProfileEdit/ProfileEdit.js
+++ b/src/renderer/views/ProfileEdit/ProfileEdit.js
@@ -63,7 +63,7 @@ export default Vue.extend({
this.isLoading = true
const profileType = this.$route.name
- this.deletePromptLabel = 'Are you sure you want to delete this profile? All subscriptions in this profile will also be deleted.'
+ this.deletePromptLabel = `${this.$t('Profile.Are you sure you want to delete this profile?')} ${this.$t('Profile["All subscriptions will also be deleted."]')}`
if (profileType === 'newProfile') {
this.isNew = true
@@ -78,7 +78,7 @@ export default Vue.extend({
this.grabProfileInfo(this.profileId).then((profile) => {
if (profile === null) {
this.showToast({
- message: 'Profile could not be found'
+ message: this.$t('Profile.Profile could not be found')
})
this.$router.push({
path: '/settings/profile/'
@@ -108,7 +108,7 @@ export default Vue.extend({
saveProfile: function () {
if (this.profileName === '') {
this.showToast({
- message: 'Your profile name cannot be empty'
+ message: this.$t('Profile.Your profile name cannot be empty')
})
return
}
@@ -129,34 +129,36 @@ export default Vue.extend({
if (this.isNew) {
this.showToast({
- message: 'Profile has been created'
+ message: this.$t('Profile.Profile has been created')
})
this.$router.push({
path: '/settings/profile/'
})
} else {
this.showToast({
- message: 'Profile has been updated'
+ message: this.$t('Profile.Profile has been updated')
})
}
},
setDefaultProfile: function () {
this.updateDefaultProfile(this.profileId)
+ const message = this.$t('Profile.Your default profile has been set to $').replace('$', this.profileName)
this.showToast({
- message: `Your default profile has been set to ${this.profileName}`
+ message: message
})
},
deleteProfile: function () {
this.removeProfile(this.profileId)
+ const message = this.$t('Profile.Removed $ from your profiles').replace('$', this.profileName)
this.showToast({
- message: `Removed ${this.profileName} from your profiles`
+ message: message
})
if (this.defaultProfile === this.profileId) {
this.updateDefaultProfile('allChannels')
this.showToast({
- message: 'Your default profile has been set your Primary profile'
+ message: this.$t('Profile.Your default profile has been changed to your primary profile')
})
}
if (this.activeProfile._id === this.profileId) {
diff --git a/src/renderer/views/ProfileSettings/ProfileSettings.vue b/src/renderer/views/ProfileSettings/ProfileSettings.vue
index b03cd6c4..b1e0b605 100644
--- a/src/renderer/views/ProfileSettings/ProfileSettings.vue
+++ b/src/renderer/views/ProfileSettings/ProfileSettings.vue
@@ -16,7 +16,7 @@
diff --git a/src/renderer/views/Settings/Settings.vue b/src/renderer/views/Settings/Settings.vue
index 665ad161..16f22727 100644
--- a/src/renderer/views/Settings/Settings.vue
+++ b/src/renderer/views/Settings/Settings.vue
@@ -3,6 +3,7 @@
+
diff --git a/src/renderer/views/Subscriptions/Subscriptions.css b/src/renderer/views/Subscriptions/Subscriptions.css
index b6db9095..76a3d760 100644
--- a/src/renderer/views/Subscriptions/Subscriptions.css
+++ b/src/renderer/views/Subscriptions/Subscriptions.css
@@ -8,6 +8,12 @@
color: var(--tertiary-text-color);
}
+.floatingTopButton {
+ position: absolute;
+ top: 70px;
+ right: 10px;
+}
+
@media only screen and (max-width: 680px) {
.card {
width: 90%;
diff --git a/src/renderer/views/Subscriptions/Subscriptions.js b/src/renderer/views/Subscriptions/Subscriptions.js
index 278a1d10..fc187453 100644
--- a/src/renderer/views/Subscriptions/Subscriptions.js
+++ b/src/renderer/views/Subscriptions/Subscriptions.js
@@ -2,16 +2,21 @@ import Vue from 'vue'
import { mapActions, mapMutations } from 'vuex'
import FtLoader from '../../components/ft-loader/ft-loader.vue'
import FtCard from '../../components/ft-card/ft-card.vue'
+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 ytch from 'yt-channel-info'
+import Parser from 'rss-parser'
export default Vue.extend({
name: 'Subscriptions',
components: {
'ft-loader': FtLoader,
'ft-card': FtCard,
+ 'ft-button': FtButton,
+ 'ft-icon-button': FtIconButton,
'ft-flex-box': FtFlexBox,
'ft-element-list': FtElementList
},
@@ -23,6 +28,10 @@ export default Vue.extend({
}
},
computed: {
+ usingElectron: function () {
+ return this.$store.getters.getUsingElectron
+ },
+
backendPreference: function () {
return this.$store.getters.getBackendPreference
},
@@ -31,10 +40,30 @@ export default Vue.extend({
return this.$store.getters.getBackendFallback
},
+ invidiousInstance: function () {
+ return this.$store.getters.getInvidiousInstance
+ },
+
+ hideWatchedSubs: function () {
+ return this.$store.getters.getHideWatchedSubs
+ },
+
+ useRssFeeds: function () {
+ return this.$store.getters.getUseRssFeeds
+ },
+
profileList: function () {
return this.$store.getters.getProfileList
},
+ activeVideoList: function () {
+ if (this.videoList.length < this.dataLimit) {
+ return this.videoList
+ } else {
+ return this.videoList.slice(0, this.dataLimit)
+ }
+ },
+
activeProfile: function () {
return this.$store.getters.getActiveProfile
},
@@ -43,50 +72,99 @@ export default Vue.extend({
return this.$store.getters.getProfileSubscriptions
},
+ allSubscriptionsList: function () {
+ return this.$store.getters.getAllSubscriptionsList
+ },
+
+ historyCache: function () {
+ return this.$store.getters.getHistoryCache
+ },
+
activeSubscriptionList: function () {
return this.profileList[this.activeProfile].subscriptions
- },
-
- allSubscriptionsList: function () {
- return this.profileList[0].subscriptions
- },
-
- sortedVideoList: function () {
- const profileSubscriptions = JSON.parse(JSON.stringify(this.profileSubscriptions))
- return profileSubscriptions.videoList.sort((a, b) => {
- if (a.title.toLowerCase() > b.title.toLowerCase()) {
- return -1
- }
-
- if (a.title.toLowerCase() < b.title.toLowerCase()) {
- return 1
- }
-
- console.log(a.title)
-
- return 0
- })
}
},
- mounted: function () {
- setTimeout(() => {
- this.fetchActiveSubscriptionsLocal()
- }, 1000)
+ watch: {
+ activeProfile: async function (val) {
+ if (this.allSubscriptionsList.length !== 0) {
+ this.isLoading = true
+ this.videoList = await Promise.all(this.allSubscriptionsList.filter((video) => {
+ const channelIndex = this.activeSubscriptionList.findIndex((x) => {
+ return x.id === video.authorId
+ })
+
+ const historyIndex = this.historyCache.findIndex((x) => {
+ return x.videoId === video.videoId
+ })
+
+ if (this.hideWatchedSubs) {
+ return channelIndex !== -1 && historyIndex === -1
+ } else {
+ return channelIndex !== -1
+ }
+ }))
+ this.isLoading = false
+ } else {
+ this.getSubscriptions()
+ }
+ }
+ },
+ mounted: async function () {
+ this.isLoading = true
+ const dataLimit = sessionStorage.getItem('subscriptionLimit')
+ if (dataLimit !== null) {
+ this.dataLimit = dataLimit
+ }
+ setTimeout(async () => {
+ if (this.profileSubscriptions.videoList.length === 0) {
+ this.getSubscriptions()
+ } else {
+ const subscriptionList = JSON.parse(JSON.stringify(this.profileSubscriptions))
+ if (this.hideWatchedSubs) {
+ this.videoList = await Promise.all(subscriptionList.videoList.filter((video) => {
+ const historyIndex = this.historyCache.findIndex((x) => {
+ return x.videoId === video.videoId
+ })
+
+ return historyIndex === -1
+ }))
+ } else {
+ this.videoList = subscriptionList.videoList
+ }
+ this.isLoading = false
+ }
+ }, 200)
},
methods: {
- fetchActiveSubscriptionsLocal: function () {
+ getSubscriptions: function () {
if (this.activeSubscriptionList.length === 0) {
+ this.isLoading = false
+ this.videoList = []
return
}
this.isLoading = true
this.updateShowProgressBar(true)
+ this.setProgressBarPercentage(0)
let videoList = []
let channelCount = 0
this.activeSubscriptionList.forEach(async (channel) => {
- const videos = await this.getChannelVideosLocalScraper(channel.id)
- console.log(videos)
+ let videos = []
+
+ if (!this.usingElectron || this.backendPreference === 'invidious') {
+ if (this.useRssFeeds) {
+ videos = await this.getChannelVideosInvidiousRSS(channel.id)
+ } else {
+ videos = await this.getChannelVideosInvidiousScraper(channel.id)
+ }
+ } else {
+ if (this.useRssFeeds) {
+ videos = await this.getChannelVideosLocalRSS(channel.id)
+ } else {
+ videos = await this.getChannelVideosLocalScraper(channel.id)
+ }
+ }
videoList = videoList.concat(videos)
channelCount++
@@ -103,9 +181,24 @@ export default Vue.extend({
videoList: videoList
}
+ this.videoList = await Promise.all(videoList.filter((video) => {
+ if (this.hideWatchedSubs) {
+ const historyIndex = this.historyCache.findIndex((x) => {
+ return x.videoId === video.videoId
+ })
+
+ return historyIndex === -1
+ } else {
+ return true
+ }
+ }))
this.updateProfileSubscriptions(profileSubscriptions)
this.isLoading = false
this.updateShowProgressBar(false)
+
+ if (this.activeProfile === 0) {
+ this.updateAllSubscriptionsList(profileSubscriptions.videoList)
+ }
}
})
},
@@ -135,25 +228,75 @@ export default Vue.extend({
},
getChannelVideosLocalRSS: function (channelId) {
- console.log('TODO')
- },
+ return new Promise((resolve, reject) => {
+ const parser = new Parser()
+ const feedUrl = `https://www.youtube.com/feeds/videos.xml?channel_id=${channelId}`
- fetchActiveSubscriptionsInvidious: function () {
- console.log('TODO')
+ parser.parseURL(feedUrl).then(async (feed) => {
+ resolve(await Promise.all(feed.items.map((video) => {
+ video.authorId = channelId
+ video.videoId = video.id.replace('yt:video:', '')
+ video.type = 'video'
+ video.publishedDate = new Date(video.pubDate)
+ video.publishedText = video.publishedDate.toLocaleString()
+ video.lengthSeconds = '0:00'
+ video.isRSS = true
+
+ return video
+ })))
+ }).catch((err) => {
+ console.log(err)
+ resolve([])
+ })
+ })
},
getChannelVideosInvidiousScraper: function (channelId) {
- console.log('TODO')
+ return new Promise((resolve, reject) => {
+ const subscriptionsPayload = {
+ resource: 'channels/latest',
+ id: channelId,
+ params: {}
+ }
+
+ this.invidiousAPICall(subscriptionsPayload).then((result) => {
+ resolve(result)
+ })
+ })
},
getChannelVideosInvidiousRSS: function (channelId) {
- console.log('TODO')
+ return new Promise((resolve, reject) => {
+ const parser = new Parser()
+ const feedUrl = `${this.invidiousInstance}/feed/channel/${channelId}`
+
+ parser.parseURL(feedUrl).then(async (feed) => {
+ resolve(await Promise.all(feed.items.map((video) => {
+ video.authorId = channelId
+ video.videoId = video.id.replace('yt:video:', '')
+ video.type = 'video'
+ video.publishedDate = new Date(video.pubDate)
+ video.publishedText = video.publishedDate.toLocaleString()
+ video.lengthSeconds = '0:00'
+ video.isRSS = true
+
+ return video
+ })))
+ })
+ })
+ },
+
+ increaseLimit: function () {
+ this.dataLimit += 100
+ sessionStorage.setItem('subscriptionLimit', this.dataLimit)
},
...mapActions([
'showToast',
+ 'invidiousAPICall',
'updateShowProgressBar',
'updateProfileSubscriptions',
+ 'updateAllSubscriptionsList',
'calculatePublishedDate'
]),
diff --git a/src/renderer/views/Subscriptions/Subscriptions.vue b/src/renderer/views/Subscriptions/Subscriptions.vue
index 4f31f6ce..85137098 100644
--- a/src/renderer/views/Subscriptions/Subscriptions.vue
+++ b/src/renderer/views/Subscriptions/Subscriptions.vue
@@ -10,20 +10,20 @@
>
{{ $t("Subscriptions.Subscriptions") }}
- {{ $t("History['Your history list is currently empty.']") }}
+ {{ $t("Subscriptions['Your Subscription list is currently empty. Start adding subscriptions to see them here.']") }}
+
diff --git a/static/locales/en-US.yaml b/static/locales/en-US.yaml
index 0769a239..99394fd8 100644
--- a/static/locales/en-US.yaml
+++ b/static/locales/en-US.yaml
@@ -70,7 +70,8 @@ Subscriptions:
Latest Subscriptions: Latest Subscriptions
'Your Subscription list is currently empty. Start adding subscriptions to see them here.': Your
Subscription list is currently empty. Start adding subscriptions to see them here.
- 'Getting Subscriptions. Please wait.': Getting Subscriptions. Please wait.
+ 'Getting Subscriptions. Please wait.': Getting Subscriptions. Please wait.
+ Refresh Subscriptions: Refresh Subscriptions
Trending: Trending
Most Popular: Most Popular
Playlists: Playlists
@@ -180,6 +181,7 @@ Settings:
Subscription Settings:
Subscription Settings: Subscription Settings
Hide Videos on Watch: Hide Videos on Watch
+ Fetch Feeds from RSS: Fetch Feeds from RSS
Subscriptions Export Format:
Subscriptions Export Format: Subscriptions Export Format
#& Freetube
@@ -260,6 +262,14 @@ Profile:
Delete Profile: Delete Profile
Are you sure you want to delete this profile?: Are you sure you want to delete this profile?
All subscriptions will also be deleted.: All subscriptions will also be deleted.
+ Profile could not be found: Profile could not be found
+ Your profile name cannot be empty: Your profile name cannot be empty
+ Profile has been created: Profile has been created
+ Profile has been updated: Profile has been updated
+ Your default profile has been set to $: Your default profile has been set to $
+ Removed $ from your profiles: Removed $ from your profiles
+ Your default profile has been changed to your primary profile: Your default profile has been changed to your primary profile
+ $ is now the active profile: $ is now the active profile
#On Channel Page
Channel:
Subscriber: Subscriber