diff --git a/package.json b/package.json index 36e7963c..eb3faabb 100644 --- a/package.json +++ b/package.json @@ -16,32 +16,32 @@ "buffer": "6.0.3", "dompurify": "2.4.0", "hotkeys-js": "3.10.0", - "javascript-time-ago": "2.5.7", + "javascript-time-ago": "2.5.9", "mux.js": "6.2.0", - "shaka-player": "4.2.2", + "shaka-player": "4.2.3", "stream-browserify": "3.0.0", "vue": "3.2.41", "vue-i18n": "9.2.2", - "vue-router": "4.1.5", + "vue-router": "4.1.6", "xml-js": "1.6.11" }, "devDependencies": { - "@iconify/json": "2.1.124", + "@iconify/json": "2.1.132", "@intlify/vite-plugin-vue-i18n": "6.0.3", - "@unocss/preset-icons": "0.45.30", - "@unocss/preset-web-fonts": "0.45.30", - "@unocss/transformer-directives": "0.45.30", - "@unocss/transformer-variant-group": "0.45.30", - "@vitejs/plugin-legacy": "2.2.0", - "@vitejs/plugin-vue": "3.1.2", + "@unocss/preset-icons": "0.46.3", + "@unocss/preset-web-fonts": "0.46.3", + "@unocss/transformer-directives": "0.46.3", + "@unocss/transformer-variant-group": "0.46.3", + "@vitejs/plugin-legacy": "2.3.0", + "@vitejs/plugin-vue": "3.2.0", "@vue/compiler-sfc": "3.2.41", - "eslint": "8.25.0", + "eslint": "8.26.0", "eslint-config-prettier": "8.5.0", "eslint-plugin-prettier": "4.2.1", - "eslint-plugin-vue": "9.6.0", + "eslint-plugin-vue": "9.7.0", "prettier": "2.7.1", - "unocss": "0.45.30", - "vite": "3.1.8", + "unocss": "0.46.3", + "vite": "3.2.2", "vite-plugin-eslint": "1.8.1", "vite-plugin-pwa": "0.13.1" }, diff --git a/src/App.vue b/src/App.vue index c7add02f..080127e1 100644 --- a/src/App.vue +++ b/src/App.vue @@ -131,11 +131,13 @@ export default { const defaultLang = await App.defaultLangage; const locale = App.getPreferenceString("hl", defaultLang); if (locale !== App.TimeAgoConfig.locale) { - const localeTime = await import(`../node_modules/javascript-time-ago/locale/${locale}.json`).then( - module => module.default, - ); - App.TimeAgo.addLocale(localeTime); - App.TimeAgoConfig.locale = locale; + const localeTime = await import(`../node_modules/javascript-time-ago/locale/${locale}.json`) + .catch(() => null) + .then(module => module?.default); + if (localeTime) { + App.TimeAgo.addLocale(localeTime); + App.TimeAgoConfig.locale = locale; + } } if (window.i18n.global.locale.value !== locale) { if (!window.i18n.global.availableLocales.includes(locale)) { diff --git a/src/components/ChannelItem.vue b/src/components/ChannelItem.vue new file mode 100644 index 00000000..84557629 --- /dev/null +++ b/src/components/ChannelItem.vue @@ -0,0 +1,34 @@ + + + diff --git a/src/components/ChannelPage.vue b/src/components/ChannelPage.vue index cfe89f1b..9d82f411 100644 --- a/src/components/ChannelPage.vue +++ b/src/components/ChannelPage.vue @@ -35,13 +35,25 @@ +
+ +
+
- import ErrorHandler from "./ErrorHandler.vue"; -import VideoItem from "./VideoItem.vue"; +import ContentItem from "./ContentItem.vue"; export default { components: { ErrorHandler, - VideoItem, + ContentItem, }, data() { return { channel: null, subscribed: false, + tabs: [], + selectedTab: 0, + contentItems: [], }; }, mounted() { @@ -111,25 +126,58 @@ export default { .then(() => { if (!this.channel.error) { document.title = this.channel.name + " - Piped"; + this.contentItems = this.channel.relatedStreams; this.fetchSubscribedStatus(); this.updateWatched(this.channel.relatedStreams); + this.tabs.push({ + translatedName: this.$t("video.videos"), + }); + for (let i = 0; i < this.channel.tabs.length; i++) { + let tab = this.channel.tabs[i]; + tab.translatedName = this.getTranslatedTabName(tab.name); + this.tabs.push(tab); + } } }); }, handleScroll() { - if (this.loading || !this.channel || !this.channel.nextpage) return; + if ( + this.loading || + !this.channel || + !this.channel.nextpage || + (this.selectedTab != 0 && !this.tabs[this.selectedTab].tabNextPage) + ) + return; if (window.innerHeight + window.scrollY >= document.body.offsetHeight - window.innerHeight) { this.loading = true; - this.fetchJson(this.apiUrl() + "/nextpage/channel/" + this.channel.id, { - nextpage: this.channel.nextpage, - }).then(json => { - this.channel.nextpage = json.nextpage; - this.loading = false; - this.updateWatched(json.relatedStreams); - json.relatedStreams.map(stream => this.channel.relatedStreams.push(stream)); - }); + if (this.selectedTab == 0) { + this.fetchChannelNextPage(); + } else { + this.fetchChannelTabNextPage(); + } } }, + fetchChannelNextPage() { + this.fetchJson(this.apiUrl() + "/nextpage/channel/" + this.channel.id, { + nextpage: this.channel.nextpage, + }).then(json => { + this.channel.nextpage = json.nextpage; + this.loading = false; + this.updateWatched(json.relatedStreams); + json.relatedStreams.map(stream => this.contentItems.push(stream)); + }); + }, + fetchChannelTabNextPage() { + this.fetchJson(this.apiUrl() + "/channels/tabs", { + data: this.tabs[this.selectedTab].data, + nextpage: this.tabs[this.selectedTab].tabNextPage, + }).then(json => { + this.tabs[this.selectedTab].tabNextPage = json.nextpage; + this.loading = false; + json.content.map(item => this.contentItems.push(item)); + this.tabs[this.selectedTab].content = this.contentItems; + }); + }, subscribeHandler() { if (this.authenticated) { this.fetchJson(this.authApiUrl() + (this.subscribed ? "/unsubscribe" : "/subscribe"), null, { @@ -147,6 +195,50 @@ export default { } this.subscribed = !this.subscribed; }, + getTranslatedTabName(tabName) { + let translatedTabName = tabName; + switch (tabName) { + case "Livestreams": + translatedTabName = this.$t("titles.livestreams"); + break; + case "Playlists": + translatedTabName = this.$t("titles.playlists"); + break; + case "Channels": + translatedTabName = this.$t("titles.channels"); + break; + case "Shorts": + translatedTabName = this.$t("video.shorts"); + break; + default: + console.error(`Tab name "${tabName}" is not translated yet!`); + break; + } + return translatedTabName; + }, + loadTab(index) { + this.selectedTab = index; + if (index == 0) { + this.contentItems = this.channel.relatedStreams; + return; + } + if (this.tabs[index].content) { + this.contentItems = this.tabs[index].content; + return; + } + this.fetchJson(this.apiUrl() + "/channels/tabs", { + data: this.tabs[index].data, + }).then(tab => { + this.contentItems = this.tabs[index].content = tab.content; + this.tabs[this.selectedTab].tabNextPage = tab.nextpage; + }); + }, }, }; + + diff --git a/src/components/CommentItem.vue b/src/components/CommentItem.vue index 04cfb473..f6529d61 100644 --- a/src/components/CommentItem.vue +++ b/src/components/CommentItem.vue @@ -25,6 +25,11 @@
+ diff --git a/src/components/WatchVideo.vue b/src/components/WatchVideo.vue index 3b1ad962..46bb6074 100644 --- a/src/components/WatchVideo.vue +++ b/src/components/WatchVideo.vue @@ -47,11 +47,11 @@