From c2e40360804277859b299b451e77f9e27fb9596e Mon Sep 17 00:00:00 2001 From: Alex Date: Fri, 18 Mar 2022 19:15:19 +1300 Subject: [PATCH 1/2] refactor: changed how the API is called --- .gitignore | 1 + NUXT/pages/home.vue | 59 +++++++++++++++++++++++++++++++++------ NUXT/pages/index.vue | 4 ++- NUXT/plugins/innertube.js | 56 +++++++++++++++++++------------------ NUXT/plugins/youtube.js | 19 +++++++++---- NUXT/static/constants.js | 50 +++++++++++++++++++++++++++++---- 6 files changed, 142 insertions(+), 47 deletions(-) diff --git a/.gitignore b/.gitignore index 033de71..fe525ee 100644 --- a/.gitignore +++ b/.gitignore @@ -4,3 +4,4 @@ dist package-lock.json temp.js temp.json +.vscode/settings.json diff --git a/NUXT/pages/home.vue b/NUXT/pages/home.vue index ca19e42..84e186b 100644 --- a/NUXT/pages/home.vue +++ b/NUXT/pages/home.vue @@ -7,18 +7,61 @@

Please read the VueTube FAQ for more information.

+
+
+ +
+ + + + +
+ +

+

+
+
+ + + +
\ No newline at end of file diff --git a/NUXT/pages/index.vue b/NUXT/pages/index.vue index 549fb07..ce8e597 100644 --- a/NUXT/pages/index.vue +++ b/NUXT/pages/index.vue @@ -12,7 +12,9 @@ export default { layout: "empty", mounted() { - this.$router.push(`/${localStorage.getItem("startPage") || "home"}`); + this.$youtube.getAPI().then( + this.$router.push(`/${localStorage.getItem("startPage") || "home"}`) + ); } } diff --git a/NUXT/plugins/innertube.js b/NUXT/plugins/innertube.js index 05b1139..28abf0a 100644 --- a/NUXT/plugins/innertube.js +++ b/NUXT/plugins/innertube.js @@ -18,37 +18,37 @@ class Innertube { return typeof this.ErrorCallback === "function" } - init() { - Http.get({ url: constants.URLS.YT_URL, params: { hl: "en" } }) - .then(result => { - if (result instanceof Error && this.checkErrorCallback) this.ErrorCallback(result.message, true); - try { - const data = JSON.parse(getBetweenStrings(result.data, 'ytcfg.set(', ');')); - if (data.INNERTUBE_CONTEXT) { - this.key = data.INNERTUBE_API_KEY; - this.context = data.INNERTUBE_CONTEXT; - this.context.client.clientName = "ANDROID"; - this.context.client.clientVersion = "16.25"; - } - - } catch (err) { - console.log(err) - if (this.checkErrorCallback) this.ErrorCallback(err, true) - if (this.retry_count >= 10) { this.init() } else { if (this.checkErrorCallback) this.ErrorCallback("Failed to retrieve Innertube session", true); } + async initAsync() { + const html = await Http.get({ url: constants.URLS.YT_URL, params: { hl: "en" } }).catch((error) => error); + try { + if (html instanceof Error && this.checkErrorCallback) this.ErrorCallback(html.message, true); + try { + const data = JSON.parse(getBetweenStrings(html.data, 'ytcfg.set(', ');')); + if (data.INNERTUBE_CONTEXT) { + this.key = data.INNERTUBE_API_KEY; + this.context = data.INNERTUBE_CONTEXT; + this.context.client = constants.INNERTUBE_CLIENT(this.context.client) } - }) - .catch((error) => error); + + } catch (err) { + console.log(err) + if (this.checkErrorCallback) this.ErrorCallback(err, true) + if (this.retry_count >= 10) { this.initAsync() } else { if (this.checkErrorCallback) this.ErrorCallback("Failed to retrieve Innertube session", true); } + } + } catch (error) { + this.ErrorCallback(error, true) + }; }; - static create(ErrorCallback) { + static async createAsync(ErrorCallback) { const created = new Innertube(ErrorCallback); - created.init(); + await created.initAsync(); return created; } //--- API Calls ---// - async browse(action_type) { + async browseAsync(action_type) { let data = { context: this.context } switch (action_type) { @@ -69,7 +69,7 @@ class Innertube { headers: { "Content-Type": "application/json" } }).catch((error) => error); - if (response instanceof Error) return { success: false, status_code: response.response.status, message: response.message }; + if (response instanceof Error) return { success: false, status_code: response.status, message: response.message }; return { success: true, @@ -78,13 +78,13 @@ class Innertube { }; } - async getVidInfo(id) { + async getVidInfoAsync(id) { let data = { context: this.context, videoId: id } const response = await Http.post({ url: `${constants.URLS.YT_BASE_API}/player?key=${this.key}`, data: data, - headers: { "Content-Type": "application/json" } + headers: constants.INNERTUBE_HEADER(this.context) }).catch((error) => error); if (response instanceof Error) return { success: false, status_code: response.response.status, message: response.message }; @@ -97,8 +97,10 @@ class Innertube { } // Simple Wrappers - async getRecommendations() { - return await this.browse("recommendations") + async getRecommendationsAsync() { + const rec = await this.browseAsync("recommendations"); + console.log(rec.data) + return rec.data; } diff --git a/NUXT/plugins/youtube.js b/NUXT/plugins/youtube.js index 3f94c12..a090973 100644 --- a/NUXT/plugins/youtube.js +++ b/NUXT/plugins/youtube.js @@ -128,23 +128,32 @@ const searchModule = { //--- Recommendations --// -// Immediately create an Innertube object. This will be the object used in all future Inntertube API calls +let InnertubeAPI; + +// Lazy loads Innertube object. This will be the object used in all future Innertube API calls. Code provided by Lightfire228 (https://github.com/Lightfire228) // These are just a way for the backend Javascript to communicate with the front end Vue scripts. Essentially a wrapper inside a wrapper const recommendationModule = { - recommendAPI: Innertube.create((message, isError) => { logger("Innertube", message, isError); }), // There's definitely a better way to do this, but it's 2 am and I just can't anymore + + async getAPI() { + InnertubeAPI = await Innertube.createAsync((message, isError) => { logger("Innertube", message, isError); }) + console.log(InnertubeAPI) + return InnertubeAPI; + }, async getVid(id) { - console.log(this.recommendAPI) - return this.recommendAPI.getVidInfo(id); + console.log(InnertubeAPI) + return InnertubeAPI.getVidInfoAsync(id).data; }, async recommend() { - return this.recommendAPI.getRecommendations(); + console.log(InnertubeAPI) + return InnertubeAPI.getRecommendationsAsync(); }, } //--- Start ---// export default ({ app }, inject) => { inject('youtube', {...searchModule, ...recommendationModule }) + inject("logger", logger) } logger("Initialize", "Program Started"); \ No newline at end of file diff --git a/NUXT/static/constants.js b/NUXT/static/constants.js index 8ccfee3..976a335 100644 --- a/NUXT/static/constants.js +++ b/NUXT/static/constants.js @@ -1,11 +1,49 @@ // To centeralize certain values and URLs as for easier debugging and refactoring +const url = { + YT_URL: 'https://www.youtube.com', + YT_MUSIC_URL: 'https://music.youtube.com', + YT_BASE_API: 'https://www.youtube.com/youtubei/v1', + YT_SUGGESTIONS: "https://suggestqueries.google.com/complete", + VT_GITHUB: "https://api.github.com/repos/Frontesque/VueTube", +} + +const ytApiVal = { + VERSION: "16.25", + CLIENTNAME: "ANDROID", +} + module.exports = { - URLS: { - YT_URL: 'https://www.youtube.com', - YT_MUSIC_URL: 'https://music.youtube.com', - YT_BASE_API: 'https://www.youtube.com/youtubei/v1', - YT_SUGGESTIONS: "https://suggestqueries.google.com/complete", - VT_GITHUB: "https://api.github.com/repos/Frontesque/VueTube", + URLS: url, + YT_API_VALUES: ytApiVal, + + INNERTUBE_HEADER: (info) => { + let headers = { + 'accept': '*/*', + 'user-agent': info.client.userAgent, + 'content-type': 'application/json', + 'x-goog-authuser': 0, + 'x-youtube-client-name': 2, + 'x-youtube-client-version': info.client.clientVersion, + 'x-youtube-chrome-connected': 'source=Chrome,mode=0,enable_account_consistency=true,supervised=false,consistency_enabled_by_default=false', + }; + return headers + }, + + INNERTUBE_CLIENT: (info) => { + let client = { + "gl": info.gl, + "hl": info.hl, + "deviceMake": info.deviceMake, + "deviceModel": info.deviceModel, + "userAgent": info.userAgent, + "clientName": ytApiVal.CLIENTNAME, + "clientVersion": ytApiVal.VERSION, + "osName": info.osName, + "osVersion": info.osVersion, + "platform": "MOBILE", + "originalUrl": info.originalUrl + }; + return client } } \ No newline at end of file From 65c1b12ed0d371302635f6ad4572e7f369ef6dfe Mon Sep 17 00:00:00 2001 From: Alex Date: Sat, 19 Mar 2022 00:50:44 +1300 Subject: [PATCH 2/2] feat: Recommendations API fully online. There is now a home page. --- NUXT/pages/home.vue | 41 ++++++++++++++++++++------------------- NUXT/pages/index.vue | 7 +++---- NUXT/plugins/innertube.js | 11 +++++++++++ NUXT/plugins/youtube.js | 11 ++++++----- NUXT/static/constants.js | 6 +++++- 5 files changed, 46 insertions(+), 30 deletions(-) diff --git a/NUXT/pages/home.vue b/NUXT/pages/home.vue index 84e186b..e06e3aa 100644 --- a/NUXT/pages/home.vue +++ b/NUXT/pages/home.vue @@ -1,13 +1,8 @@ // Buttons and methods for testing and demonstration purposes only. Uncomment them to see how it works. Remove to actually implement a implementation \ No newline at end of file diff --git a/NUXT/pages/index.vue b/NUXT/pages/index.vue index ce8e597..e5bbbb3 100644 --- a/NUXT/pages/index.vue +++ b/NUXT/pages/index.vue @@ -11,10 +11,9 @@ diff --git a/NUXT/plugins/innertube.js b/NUXT/plugins/innertube.js index 28abf0a..789565a 100644 --- a/NUXT/plugins/innertube.js +++ b/NUXT/plugins/innertube.js @@ -78,6 +78,17 @@ class Innertube { }; } + static getThumbnail(id, resolution) { + switch (resolution) { + case "min": + return `https://img.youtube.com/vi/${id}/mqdefault.jpg` + case "mid": + return `https://img.youtube.com/vi/${id}/hqdefault.jpg` + default: + return `https://img.youtube.com/vi/${id}/maxresdefault.jpg` + } + } + async getVidInfoAsync(id) { let data = { context: this.context, videoId: id } diff --git a/NUXT/plugins/youtube.js b/NUXT/plugins/youtube.js index a090973..1568fe1 100644 --- a/NUXT/plugins/youtube.js +++ b/NUXT/plugins/youtube.js @@ -135,25 +135,26 @@ let InnertubeAPI; const recommendationModule = { async getAPI() { - InnertubeAPI = await Innertube.createAsync((message, isError) => { logger("Innertube", message, isError); }) - console.log(InnertubeAPI) + if (!InnertubeAPI) { + InnertubeAPI = await Innertube.createAsync((message, isError) => { logger("Innertube", message, isError); }) + } return InnertubeAPI; }, async getVid(id) { - console.log(InnertubeAPI) return InnertubeAPI.getVidInfoAsync(id).data; }, async recommend() { - console.log(InnertubeAPI) return InnertubeAPI.getRecommendationsAsync(); }, + + getThumbnail: (id, resolution) => Innertube.getThumbnail(id, resolution) } //--- Start ---// export default ({ app }, inject) => { - inject('youtube', {...searchModule, ...recommendationModule }) + inject('youtube', {...searchModule, ...recommendationModule, }) inject("logger", logger) } logger("Initialize", "Program Started"); \ No newline at end of file diff --git a/NUXT/static/constants.js b/NUXT/static/constants.js index 976a335..3e4d1c9 100644 --- a/NUXT/static/constants.js +++ b/NUXT/static/constants.js @@ -42,7 +42,11 @@ module.exports = { "osName": info.osName, "osVersion": info.osVersion, "platform": "MOBILE", - "originalUrl": info.originalUrl + "originalUrl": info.originalUrl, + "configInfo": info.configInfo, + "remoteHost": info.remoteHost, + "visitorData": info.visitorData, + // This is, by all accounts, a horrible implementation, but this is currently the only solution besides }; return client }