From c51a3a828efa03e6d9bb3190ea2d9a804428638e Mon Sep 17 00:00:00 2001 From: Bnyro <82752168+Bnyro@users.noreply.github.com> Date: Mon, 1 Aug 2022 16:16:06 +0200 Subject: [PATCH] unauthenticated subscriptions (#1270) * hmm * unauthenticated feed * unauthenticated rss * Small improvements to code. * add unauthenticated subscriptions * cleanup * Sort subs locally. * Fix some bugs and small improvements. Co-authored-by: Kavin <20838718+FireMasterK@users.noreply.github.com> --- src/components/ChannelPage.vue | 29 +++++++++++-------- src/components/FeedPage.vue | 29 +++++++++++-------- src/components/ImportPage.vue | 42 ++++++++++++++++++---------- src/components/NavBar.vue | 4 +-- src/components/SubscriptionsPage.vue | 29 +++++++++++-------- src/components/WatchVideo.vue | 28 +++++++++++-------- src/main.js | 21 ++++++++++++++ 7 files changed, 118 insertions(+), 64 deletions(-) diff --git a/src/components/ChannelPage.vue b/src/components/ChannelPage.vue index 3755f54d..42dceb4d 100644 --- a/src/components/ChannelPage.vue +++ b/src/components/ChannelPage.vue @@ -14,7 +14,6 @@ </p> <button - v-if="authenticated" class="btn" @click="subscribeHandler" v-t="{ @@ -50,7 +49,7 @@ export default { data() { return { channel: null, - subscribed: false, + subscribed: this.authenticated ? false : this.isSubscribedLocally(this.channelId), }; }, mounted() { @@ -69,6 +68,8 @@ export default { }, methods: { async fetchSubscribedStatus() { + if (!this.channelId || !this.authenticated) return; + this.fetchJson( this.authApiUrl() + "/subscribed", { @@ -113,16 +114,20 @@ export default { } }, subscribeHandler() { - this.fetchJson(this.authApiUrl() + (this.subscribed ? "/unsubscribe" : "/subscribe"), null, { - method: "POST", - body: JSON.stringify({ - channelId: this.channel.id, - }), - headers: { - Authorization: this.getAuthToken(), - "Content-Type": "application/json", - }, - }); + if (this.authenticated) { + this.fetchJson(this.authApiUrl() + (this.subscribed ? "/unsubscribe" : "/subscribe"), null, { + method: "POST", + body: JSON.stringify({ + channelId: this.channel.id, + }), + headers: { + Authorization: this.getAuthToken(), + "Content-Type": "application/json", + }, + }); + } else { + this.handleLocalSubscriptions(this.channel.id); + } this.subscribed = !this.subscribed; }, }, diff --git a/src/components/FeedPage.vue b/src/components/FeedPage.vue index 66c8b6d6..fea59f56 100644 --- a/src/components/FeedPage.vue +++ b/src/components/FeedPage.vue @@ -1,7 +1,7 @@ <template> <h1 v-t="'titles.feed'" class="font-bold text-center my-4" /> - <button v-if="authenticated" class="btn mr-2" @click="exportHandler"> + <button class="btn mr-2" @click="exportHandler"> <router-link to="/subscriptions">Subscriptions</router-link> </button> @@ -41,17 +41,16 @@ export default { }, computed: { getRssUrl(_this) { - return _this.authApiUrl() + "/feed/rss?authToken=" + _this.getAuthToken(); + if (_this.authenticated) return _this.authApiUrl() + "/feed/rss?authToken=" + _this.getAuthToken(); + else return _this.authApiUrl() + "/feed/unauthenticated/rss?channels=" + _this.getUnauthenticatedChannels(); }, }, mounted() { - if (this.authenticated) - this.fetchFeed().then(videos => { - this.videosStore = videos; - this.loadMoreVideos(); - this.updateWatched(this.videos); - }); - else this.$router.push("/login"); + this.fetchFeed().then(videos => { + this.videosStore = videos; + this.loadMoreVideos(); + this.updateWatched(this.videos); + }); }, activated() { document.title = this.$t("titles.feed") + " - Piped"; @@ -66,9 +65,15 @@ export default { }, methods: { async fetchFeed() { - return await this.fetchJson(this.authApiUrl() + "/feed", { - authToken: this.getAuthToken(), - }); + if (this.authenticated) { + return await this.fetchJson(this.authApiUrl() + "/feed", { + authToken: this.getAuthToken(), + }); + } else { + return await this.fetchJson(this.authApiUrl() + "/feed/unauthenticated", { + channels: this.getUnauthenticatedChannels(), + }); + } }, loadMoreVideos() { this.currentVideoCount = Math.min(this.currentVideoCount + this.videoStep, this.videosStore.length); diff --git a/src/components/ImportPage.vue b/src/components/ImportPage.vue index dcc354b0..4d8791d8 100644 --- a/src/components/ImportPage.vue +++ b/src/components/ImportPage.vue @@ -69,7 +69,6 @@ export default { }, }, activated() { - if (!this.authenticated) this.$router.push("/login"); document.title = "Import - Piped"; }, methods: { @@ -132,21 +131,34 @@ export default { }); }, handleImport() { - this.fetchJson( - this.authApiUrl() + "/import", - { - override: this.override, - }, - { - method: "POST", - headers: { - Authorization: this.getAuthToken(), + if (this.authenticated) { + this.fetchJson( + this.authApiUrl() + "/import", + { + override: this.override, }, - body: JSON.stringify(this.subscriptions), - }, - ).then(json => { - if (json.message === "ok") window.location = "/feed"; - }); + { + method: "POST", + headers: { + Authorization: this.getAuthToken(), + }, + body: JSON.stringify(this.subscriptions), + }, + ).then(json => { + if (json.message === "ok") window.location = "/feed"; + }); + } else { + this.importSubscriptionsLocally(this.subscriptions); + window.location = "/feed"; + } + }, + importSubscriptionsLocally(newChannels) { + const subscriptions = this.override + ? [...new Set(newChannels)] + : [...new Set(this.getLocalSubscriptions().concat(newChannels))]; + // Sort for better cache hits + subscriptions.sort(); + localStorage.setItem("localSubscriptions", JSON.stringify(subscriptions)); }, }, }; diff --git a/src/components/NavBar.vue b/src/components/NavBar.vue index aa3707df..31787bac 100644 --- a/src/components/NavBar.vue +++ b/src/components/NavBar.vue @@ -52,7 +52,7 @@ <li v-if="authenticated"> <router-link v-t="'titles.playlists'" to="/playlists" /> </li> - <li v-if="authenticated && !shouldShowTrending"> + <li v-if="!shouldShowTrending"> <router-link v-t="'titles.feed'" to="/feed" /> </li> </ul> @@ -81,7 +81,7 @@ <li v-if="authenticated"> <router-link v-t="'titles.playlists'" to="/playlists" /> </li> - <li v-if="authenticated && !shouldShowTrending"> + <li v-if="!shouldShowTrending"> <router-link v-t="'titles.feed'" to="/feed" /> </li> </ul> diff --git a/src/components/SubscriptionsPage.vue b/src/components/SubscriptionsPage.vue index 793e8288..4d7affaf 100644 --- a/src/components/SubscriptionsPage.vue +++ b/src/components/SubscriptionsPage.vue @@ -1,7 +1,7 @@ <template> <h1 class="font-bold text-center my-4" v-t="'titles.subscriptions'" /> - <div v-if="authenticated" class="flex justify-between w-full"> + <div class="flex justify-between w-full"> <div class="flex"> <button class="btn mx-1"> <router-link to="/import" v-t="'actions.import_from_json'" /> @@ -40,21 +40,28 @@ export default { }; }, mounted() { - if (this.authenticated) - this.fetchJson(this.authApiUrl() + "/subscriptions", null, { - headers: { - Authorization: this.getAuthToken(), - }, - }).then(json => { - this.subscriptions = json; - this.subscriptions.forEach(subscription => (subscription.subscribed = true)); - }); - else this.$router.push("/login"); + this.fetchSubscriptions().then(json => { + this.subscriptions = json; + this.subscriptions.forEach(subscription => (subscription.subscribed = true)); + }); }, activated() { document.title = "Subscriptions - Piped"; }, methods: { + async fetchSubscriptions() { + if (this.authenticated) { + return await this.fetchJson(this.authApiUrl() + "/subscriptions", null, { + headers: { + Authorization: this.getAuthToken(), + }, + }); + } else { + return await this.fetchJson(this.authApiUrl() + "/subscriptions/unauthenticated", { + channels: this.getUnauthenticatedChannels(), + }); + } + }, handleButton(subscription) { this.fetchJson(this.authApiUrl() + (subscription.subscribed ? "/unsubscribe" : "/subscribe"), null, { method: "POST", diff --git a/src/components/WatchVideo.vue b/src/components/WatchVideo.vue index c9a562c9..deb65dae 100644 --- a/src/components/WatchVideo.vue +++ b/src/components/WatchVideo.vue @@ -80,7 +80,6 @@ </button> <button class="btn" - v-if="authenticated" @click="subscribeHandler" v-t="{ path: `actions.${subscribed ? 'unsubscribe' : 'subscribe'}`, @@ -427,7 +426,8 @@ export default { this.fetchComments().then(data => (this.comments = data)); }, async fetchSubscribedStatus() { - if (!this.channelId || !this.authenticated) return; + if (!this.channelId) return; + if (!this.authenticated) this.subscribed = this.isSubscribedLocally(this.channelId); this.fetchJson( this.authApiUrl() + "/subscribed", @@ -444,16 +444,20 @@ export default { }); }, subscribeHandler() { - this.fetchJson(this.authApiUrl() + (this.subscribed ? "/unsubscribe" : "/subscribe"), null, { - method: "POST", - body: JSON.stringify({ - channelId: this.channelId, - }), - headers: { - Authorization: this.getAuthToken(), - "Content-Type": "application/json", - }, - }); + if (this.authenticated) { + this.fetchJson(this.authApiUrl() + (this.subscribed ? "/unsubscribe" : "/subscribe"), null, { + method: "POST", + body: JSON.stringify({ + channelId: this.channelId, + }), + headers: { + Authorization: this.getAuthToken(), + "Content-Type": "application/json", + }, + }); + } else { + this.handleLocalSubscriptions(this.channelId); + } this.subscribed = !this.subscribed; }, handleScroll() { diff --git a/src/main.js b/src/main.js index 7e64637b..171e6a33 100644 --- a/src/main.js +++ b/src/main.js @@ -199,6 +199,27 @@ const mixin = { }); } }, + getLocalSubscriptions() { + return JSON.parse(localStorage.getItem("localSubscriptions")); + }, + isSubscribedLocally(channelId) { + const localSubscriptions = this.getLocalSubscriptions(); + if (localSubscriptions == null) return false; + return localSubscriptions.includes(channelId); + }, + handleLocalSubscriptions(channelId) { + var localSubscriptions = this.getLocalSubscriptions() ?? []; + if (localSubscriptions.includes(channelId)) + localSubscriptions.splice(localSubscriptions.indexOf(channelId)); + else localSubscriptions.push(channelId); + // Sort for better cache hits + localSubscriptions.sort(); + localStorage.setItem("localSubscriptions", JSON.stringify(localSubscriptions)); + }, + getUnauthenticatedChannels() { + const localSubscriptions = this.getLocalSubscriptions(); + return localSubscriptions.join(","); + }, }, computed: { theme() {