diff --git a/NUXT/components/videoPlayer.vue b/NUXT/components/videoPlayer.vue index 6c1f165..a5158ed 100644 --- a/NUXT/components/videoPlayer.vue +++ b/NUXT/components/videoPlayer.vue @@ -1,38 +1,35 @@ diff --git a/NUXT/pages/watch.vue b/NUXT/pages/watch.vue index 59e4e91..9dfa94c 100644 --- a/NUXT/pages/watch.vue +++ b/NUXT/pages/watch.vue @@ -4,6 +4,7 @@ @@ -95,6 +96,7 @@ import { Share } from "@capacitor/share"; import ShelfRenderer from "~/components/SectionRenderers/shelfRenderer.vue"; import VidLoadRenderer from "~/components/vidLoadRenderer.vue"; +import { getCpn } from "~/plugins/utils"; import SlimVideoDescriptionRenderer from "~/components/UtilRenderers/slimVideoDescriptionRenderer.vue"; export default { @@ -135,6 +137,7 @@ export default { views: null, recommends: null, loaded: false, + interval: null, }; }, watch: { @@ -144,18 +147,24 @@ export default { handler(newRt, oldRt) { if (newRt.query.v != oldRt.query.v) { // Exit fullscreen if currently in fullscreen - if (this.$refs.player) this.$refs.player.webkitExitFullscreen(); + // if (this.$refs.player) this.$refs.player.webkitExitFullscreen(); // Reset player and run getVideo function again this.vidSrc = ""; + this.startTime = Math.floor(Date.now() / 1000); + clearInterval(this.interval); this.getVideo(); } }, }, }, mounted() { - this.$youtube.saveApiStats("detailpage", this.$route.query.v, "streamingstats") + this.startTime = Math.floor(Date.now() / 1000); this.getVideo(); }, + + destroyed() { + clearInterval(this.interval); + }, methods: { getVideo() { this.likes = 100; @@ -186,6 +195,14 @@ export default { this.recommends = result.renderedData.recommendations; // .catch((error) => this.$logger("Watch", error, true)); console.log("recommendations:", this.recommends); + + //--- API WatchTime call ---// + this.playbackTracking = result.playbackTracking; + this.cpn = getCpn(); + this.initWatchTime().then(() => { + this.sendWatchTime(); + this.interval = setInterval(this.sendWatchTime, 30000); + }); }); this.$youtube.getReturnYoutubeDislike(this.$route.query.v, (data) => { @@ -208,6 +225,29 @@ export default { dialogTitle: "Share video", }); }, + sendWatchTime() { + const player = this.$refs.player.getPlayer(); + this.$youtube.saveApiStats( + { + cpn: this.cpn, + rt: Math.floor(Date.now() / 1000) - this.startTime, + et: player.currentTime, + state: player.paused ? "paused" : "playing", + volume: 100, + }, + this.playbackTracking.videostatsWatchtimeUrl.baseUrl + ); + }, + + async initWatchTime() { + await this.$youtube.saveApiStats( + { + cpn: this.cpn, + rt: Math.floor(Date.now() / 1000) - this.startTime, + }, + this.playbackTracking.videostatsPlaybackUrl.baseUrl + ); + }, }, }; diff --git a/NUXT/plugins/constants.js b/NUXT/plugins/constants.js index 81d03cb..97425c4 100644 --- a/NUXT/plugins/constants.js +++ b/NUXT/plugins/constants.js @@ -6,7 +6,6 @@ const url = { YT_MUSIC_URL: "https://music.youtube.com", YT_BASE_API: "https://www.youtube.com/youtubei/v1", YT_SUGGESTIONS: "https://suggestqueries.google.com/complete", - YT_API_STATS: "https://www.youtube.com/api/stats/atr", VT_GITHUB: "https://api.github.com/repos/Frontesque/VueTube", }; diff --git a/NUXT/plugins/innertube.js b/NUXT/plugins/innertube.js index b34006e..4716b26 100644 --- a/NUXT/plugins/innertube.js +++ b/NUXT/plugins/innertube.js @@ -189,20 +189,13 @@ class Innertube { } // WARNING: This is tracking the user's activity, but is required for recommendations to properly work - async apiStats(currentPageType, id, event) { - const params = { - key: this.key, - el: currentPageType, - ns: "yt", - docid: id, - event: event, - feature: "g-high-rec", - c: this.context.client.clientName, - volume: 100, - cver: this.context.client.clientVersion, - hl: this.context.client.hl, - }; - await Http.post({ url: constants.URLS.YT_API_STATS, params: params }); + async apiStats(params, url) { + console.log(params); + await Http.get({ + url: url, + params: params, + headers: this.header, + }); } // Static methods @@ -303,6 +296,7 @@ class Innertube { recommendationsContinuation: columnUI?.continuations[0].reloadContinuationData?.continuation, }, + playbackTracking: responseInfo.playbackTracking, }; console.log(vidData); diff --git a/NUXT/plugins/utils.js b/NUXT/plugins/utils.js index 92325bc..b918d2e 100644 --- a/NUXT/plugins/utils.js +++ b/NUXT/plugins/utils.js @@ -28,8 +28,18 @@ function rgbToHex(r, g, b) { return "#" + ((1 << 24) + (r << 16) + (g << 8) + b).toString(16).slice(1); } +function getCpn() { + const chars = + "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-_"; + let result = ""; + for (let i = 16; i > 0; --i) + result += chars[Math.round(Math.random() * (chars.length - 1))]; + return result; +} + module.exports = { getBetweenStrings, hexToRgb, rgbToHex, + getCpn, }; diff --git a/NUXT/plugins/youtube.js b/NUXT/plugins/youtube.js index 335fb81..53fa021 100644 --- a/NUXT/plugins/youtube.js +++ b/NUXT/plugins/youtube.js @@ -152,8 +152,8 @@ const innertubeModule = { } }, - async saveApiStats(currentPageType, id, event) { - await InnertubeAPI.apiStats(currentPageType, id, event); + async saveApiStats(query, url) { + await InnertubeAPI.apiStats(query, url); }, };