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/ContentItem.vue b/src/components/ContentItem.vue
new file mode 100644
index 00000000..4a9dd6c8
--- /dev/null
+++ b/src/components/ContentItem.vue
@@ -0,0 +1,35 @@
+
+
+
+
+
diff --git a/src/components/FeedPage.vue b/src/components/FeedPage.vue
index 5d797be0..950a6852 100644
--- a/src/components/FeedPage.vue
+++ b/src/components/FeedPage.vue
@@ -16,7 +16,7 @@
-
+
diff --git a/src/components/HistoryPage.vue b/src/components/HistoryPage.vue
index f41c8a4a..a0b344d9 100644
--- a/src/components/HistoryPage.vue
+++ b/src/components/HistoryPage.vue
@@ -14,7 +14,7 @@
-
+
diff --git a/src/components/PlaylistItem.vue b/src/components/PlaylistItem.vue
new file mode 100644
index 00000000..84557629
--- /dev/null
+++ b/src/components/PlaylistItem.vue
@@ -0,0 +1,34 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/src/components/PlaylistPage.vue b/src/components/PlaylistPage.vue
index 37d505c9..bb42503a 100644
--- a/src/components/PlaylistPage.vue
+++ b/src/components/PlaylistPage.vue
@@ -32,7 +32,7 @@
-
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 @@