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 fe17ca5..e06e3aa 100644
--- a/NUXT/pages/home.vue
+++ b/NUXT/pages/home.vue
@@ -1,24 +1,68 @@
// Buttons and methods for testing and demonstration purposes only. Uncomment them to see how it works. Remove to actually implement a implementation
-
-
-
Page Under Construction
-
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..e5bbbb3 100644
--- a/NUXT/pages/index.vue
+++ b/NUXT/pages/index.vue
@@ -11,8 +11,9 @@
diff --git a/NUXT/plugins/innertube.js b/NUXT/plugins/innertube.js
index 05b1139..789565a 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,24 @@ class Innertube {
};
}
- async getVidInfo(id) {
+ 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 }
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 +108,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..1568fe1 100644
--- a/NUXT/plugins/youtube.js
+++ b/NUXT/plugins/youtube.js
@@ -128,23 +128,33 @@ 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() {
+ if (!InnertubeAPI) {
+ InnertubeAPI = await Innertube.createAsync((message, isError) => { logger("Innertube", message, isError); })
+ }
+ return InnertubeAPI;
+ },
async getVid(id) {
- console.log(this.recommendAPI)
- return this.recommendAPI.getVidInfo(id);
+ return InnertubeAPI.getVidInfoAsync(id).data;
},
async recommend() {
- return this.recommendAPI.getRecommendations();
+ 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 8ccfee3..3e4d1c9 100644
--- a/NUXT/static/constants.js
+++ b/NUXT/static/constants.js
@@ -1,11 +1,53 @@
// 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,
+ "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
}
}
\ No newline at end of file