0
0
Fork 0
mirror of https://github.com/VueTubeApp/VueTube synced 2025-01-07 08:01:12 +00:00

feat: pagination, url handling, tracking

This commit is contained in:
Alex 2022-04-01 14:02:08 +13:00
parent 1db075c5ee
commit 6e565d66b7
9 changed files with 113 additions and 40 deletions

View file

@ -9,7 +9,6 @@
<a <a
@click="openExternal($rendererUtils.getNavigationEndpoints(text))" @click="openExternal($rendererUtils.getNavigationEndpoints(text))"
:key="index" :key="index"
class="link"
>{{ text.text }}</a >{{ text.text }}</a
> >
</template> </template>
@ -17,7 +16,6 @@
<a <a
@click="openInternal($rendererUtils.getNavigationEndpoints(text))" @click="openInternal($rendererUtils.getNavigationEndpoints(text))"
:key="index" :key="index"
class="link"
>{{ text.text }}</a >{{ text.text }}</a
> >
</template> </template>

View file

@ -0,0 +1,25 @@
<template>
<div class="observer" />
</template>
<script>
export default {
props: ["options"],
data: () => ({
observer: null,
}),
mounted() {
const options = this.options || {};
this.observer = new IntersectionObserver(([entry]) => {
if (entry && entry.isIntersecting) {
this.$emit("intersect");
}
}, options);
this.observer.observe(this.$el);
},
destroyed() {
this.observer.disconnect();
},
};
</script>

View file

@ -77,18 +77,20 @@ export default {
methods: { methods: {
refreshRecommendations() { refreshRecommendations() {
this.$emit("scroll-to-top"); this.$emit("scroll-to-top");
const continuations = this.$store.state.recommendedVideos.continuations; const continuations =
this.$store.state.recommendedVideos[
this.$store.state.recommendedVideos.length - 1
].continuations;
this.$store.commit("updateRecommendedVideos", []); this.$store.commit("updateRecommendedVideos", []);
this.$youtube this.$youtube
.continuation( .recommendContinuation(
continuations[1].reloadContinuationData.continuation, continuations.find((element) => element.reloadContinuationData)
.reloadContinuationData.continuation,
"browse" "browse"
) )
.then((result) => { .then((result) => {
if (result) console.log(result);
this.$youtube.recommend(result).then((result) => { if (result) this.$store.commit("updateRecommendedVideos", [result]);
if (result) this.$store.commit("updateRecommendedVideos", result);
});
}) })
.catch((error) => this.$logger("Home Page (Nav Refresh)", error, true)); .catch((error) => this.$logger("Home Page (Nav Refresh)", error, true));
}, },

View file

@ -1,7 +1,10 @@
// this is an loading animation for videos // this is an loading animation for videos
<template> <template>
<center> <div>
<v-skeleton-loader type="card-avatar, article, actions" /> <v-skeleton-loader
<v-skeleton-loader type="card-avatar, article, actions" /> v-for="i in 10"
</center> :key="i"
type="image, list-item-avatar-two-line"
/>
</div>
</template> </template>

View file

@ -124,6 +124,15 @@ export default {
window.history.back(); window.history.back();
} }
}); });
CapacitorApp.addListener("appUrlOpen", (event) => {
const slug = new URL(event.url);
// We only push to the route if there is a slug present
if (slug) {
console.log(slug.pathname + slug.search);
this.$router.push(slug.pathname + slug.search);
}
});
}, },
methods: { methods: {

View file

@ -7,16 +7,20 @@
<div> <div>
<!-- Video Loading Animation --> <!-- Video Loading Animation -->
<vid-load-renderer v-if="!recommends.contents" /> <vid-load-renderer v-if="recommends.length == 0" />
<horizontal-list-renderer v-else :render="recommends.contents[0]" /> <div v-for="(section, index) in recommends" :key="index">
<horizontal-list-renderer :render="section.contents[0]" />
</div>
<observer @intersect="paginate" />
</div> </div>
</template> </template>
<script> <script>
import horizontalListRenderer from "~/components/ListRenderers/horizontalListRenderer.vue"; import horizontalListRenderer from "~/components/ListRenderers/horizontalListRenderer.vue";
import VidLoadRenderer from "~/components/vidLoadRenderer.vue"; import VidLoadRenderer from "~/components/vidLoadRenderer.vue";
import Observer from "~/components/observer.vue";
export default { export default {
components: { horizontalListRenderer, VidLoadRenderer }, components: { horizontalListRenderer, VidLoadRenderer, Observer },
computed: { computed: {
recommends: { recommends: {
@ -29,12 +33,29 @@ export default {
}, },
}, },
methods: {
paginate() {
if (this.recommends) {
this.$youtube
.recommendContinuation(
this.recommends[this.recommends.length - 1].continuations.find(
(element) => element.nextContinuationData
).nextContinuationData.continuation,
"browse"
)
.then((result) => {
this.recommends.push(result);
});
}
},
},
mounted() { mounted() {
if (!this.recommends.items || !this.recommends.items.length) { if (!this.recommends.length) {
this.$youtube this.$youtube
.recommend() .recommend()
.then((result) => { .then((result) => {
if (result) this.recommends = result; if (result) this.recommends = [result];
}) })
.catch((error) => this.$logger("Home Page", error, true)); .catch((error) => this.$logger("Home Page", error, true));
} }

View file

@ -97,19 +97,19 @@ class Innertube {
async getContinuationsAsync(continuation, type) { async getContinuationsAsync(continuation, type) {
let data = { context: this.context, continuation: continuation }; let data = { context: this.context, continuation: continuation };
let url let url;
switch (type) { switch (type) {
case "browse": case "browse":
url = `${constants.URLS.YT_BASE_API}/browse?key=${this.key}`; url = `${constants.URLS.YT_BASE_API}/browse?key=${this.key}`;
break break;
case "search": case "search":
url = `${constants.URLS.YT_BASE_API}/search?key=${this.key}`; url = `${constants.URLS.YT_BASE_API}/search?key=${this.key}`;
break break;
case "next": case "next":
url = `${constants.URLS.YT_BASE_API}/next?key=${this.key}`; url = `${constants.URLS.YT_BASE_API}/next?key=${this.key}`;
break break;
default: default:
throw ("Invalid type") throw "Invalid type";
} }
const response = await Http.post({ const response = await Http.post({
@ -234,9 +234,11 @@ class Innertube {
response.data.output?.playabilityStatus?.status == ("ERROR" || undefined) response.data.output?.playabilityStatus?.status == ("ERROR" || undefined)
) )
throw new Error( throw new Error(
`Could not get information for video: ${response.status_code || `Could not get information for video: ${
response.data.output?.playabilityStatus?.status response.status_code ||
} - ${response.message || response.data.output?.playabilityStatus?.reason response.data.output?.playabilityStatus?.status
} - ${
response.message || response.data.output?.playabilityStatus?.reason
}` }`
); );
const responseInfo = response.data.output; const responseInfo = response.data.output;

View file

@ -108,7 +108,6 @@ const innertubeModule = {
async recommend() { async recommend() {
const response = await InnertubeAPI.getRecommendationsAsync(); const response = await InnertubeAPI.getRecommendationsAsync();
if (!response.success) if (!response.success)
throw new Error("An error occurred and innertube failed to respond"); throw new Error("An error occurred and innertube failed to respond");
@ -120,30 +119,30 @@ const innertubeModule = {
if (video) return video; if (video) return video;
}); });
const continuations = response.data.contents.singleColumnBrowseResultsRenderer.tabs[0] const continuations =
.tabRenderer.content.sectionListRenderer.continuations response.data.contents.singleColumnBrowseResultsRenderer.tabs[0]
.tabRenderer.content.sectionListRenderer.continuations;
console.log({ continuations: continuations, contents: final }); console.log({ continuations: continuations, contents: final });
return { continuations: continuations, contents: final }; return { continuations: continuations, contents: final };
}, },
async recommendContinuation(response) { async recommendContinuation(continuation, endpoint) {
const contents = response.continuationContents.sectionListContinuation.contents; const response = await InnertubeAPI.getContinuationsAsync(
continuation,
endpoint
);
const contents =
response.data.continuationContents.sectionListContinuation.contents;
const final = contents.map((shelves) => { const final = contents.map((shelves) => {
const video = shelves.shelfRenderer?.content?.horizontalListRenderer; const video = shelves.shelfRenderer?.content?.horizontalListRenderer;
if (video) return video; if (video) return video;
}); });
const continuations = response.continuationContents.sectionListContinuation.continuations const continuations =
response.data.continuationContents.sectionListContinuation.continuations;
return { continuations: continuations, contents: final }; return { continuations: continuations, contents: final };
}, },
async continuation(continuation, endpoint) {
const response = await InnertubeAPI.getContinuationsAsync(continuation, endpoint);
console.log(response)
if (!response.success) throw new Error("An error occurred and innertube failed to respond");
return response
},
async search(query) { async search(query) {
try { try {
const response = await InnertubeAPI.getSearchAsync(query); const response = await InnertubeAPI.getSearchAsync(query);

View file

@ -21,7 +21,21 @@
<intent-filter> <intent-filter>
<action android:name="android.intent.action.MAIN" /> <action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" /> <category android:name="android.intent.category.LAUNCHER" />>
</intent-filter>
<intent-filter>
<action android:name="android.intent.action.VIEW" />
<category android:name="android.intent.category.DEFAULT" />
<category android:name="android.intent.category.BROWSABLE" />
<data android:scheme="http" />
<data android:scheme="https" />
<data android:host="youtu.be" />
<data android:host="m.youtube.com" />
<data android:host="youtube.com" />
<data android:host="www.youtube.com" />
<data android:pathPattern="/.*" />
</intent-filter> </intent-filter>
</activity> </activity>