From 46d26c0c6de4ae57c5508952a584f5d2b0ce3ea1 Mon Sep 17 00:00:00 2001 From: Larivact Date: Wed, 7 Mar 2018 07:04:47 +0100 Subject: [PATCH 01/14] Ditch googleApi.js, use request instead; refactor code --- package.json | 3 +- src/index.html | 2 +- src/js/channels.js | 35 +++++++++------------- src/js/events.js | 6 ++-- src/js/googleApi.js | 18 ------------ src/js/history.js | 12 ++++---- src/js/init.js | 2 +- src/js/layout.js | 38 +++++++----------------- src/js/savedVideos.js | 13 ++++----- src/js/settings.js | 15 ++++------ src/js/subscriptions.js | 33 +++++++-------------- src/js/videos.js | 64 ++++++++++++++++------------------------- src/js/youtubeApi.js | 17 +++++++++++ 13 files changed, 97 insertions(+), 161 deletions(-) delete mode 100644 src/js/googleApi.js create mode 100644 src/js/youtubeApi.js diff --git a/package.json b/package.json index 0251bd2d5..8d2a12e0b 100644 --- a/package.json +++ b/package.json @@ -66,6 +66,7 @@ "mustache": "^2.3.0", "nedb": "^1.8.0", "node-async-loop": "^1.2.2", - "opml-to-json": "0.0.3" + "opml-to-json": "0.0.3", + "requests": "^0.2.2" } } diff --git a/src/index.html b/src/index.html index 15852a2bf..33971f4af 100644 --- a/src/index.html +++ b/src/index.html @@ -11,7 +11,7 @@ - + diff --git a/src/js/channels.js b/src/js/channels.js index dd7e44048..9db836c64 100644 --- a/src/js/channels.js +++ b/src/js/channels.js @@ -24,14 +24,11 @@ along with FreeTube. If not, see . /*function getChannelThumbnail(channelId, callback) { let url = ''; - let request = gapi.client.youtube.channels.list({ + youtubeAPI('channels', { 'id': channelId, 'part': 'snippet', - }); - - request.execute((response) => { - url = response['items'][0]['snippet']['thumbnails']['high']['url']; - callback(url); + }, function (data){ + callback(data.items[0].snippet.thumbnails.high.url); }); }*/ @@ -45,7 +42,7 @@ along with FreeTube. If not, see . function goToChannel(channelId) { event.stopPropagation(); clearMainContainer(); - toggleLoading(); + startLoadingAnimation(); // Check if the user is subscribed to the channel. Display different text based on the information @@ -62,17 +59,14 @@ function goToChannel(channelId) { }); // Call YouTube API to grab channel information - let request = gapi.client.youtube.channels.list({ + youtubeAPI('channels', { part: 'snippet, brandingSettings, statistics', id: channelId, - }); - - // Perform API Execution - request.execute((response) => { + }, function (data){ // Set variables of extracted information - const brandingSettings = response['items'][0]['brandingSettings']; - const statistics = response['items'][0]['statistics']; - const snippet = response['items'][0]['snippet']; + const brandingSettings = data['items'][0]['brandingSettings']; + const statistics = data['items'][0]['statistics']; + const snippet = data['items'][0]['snippet']; const channelName = brandingSettings['channel']['title']; const channelBanner = brandingSettings['image']['bannerImageUrl']; const channelImage = snippet['thumbnails']['high']['url']; @@ -97,22 +91,19 @@ function goToChannel(channelId) { }); // Render the template on to #main $('#main').html(rendered); - toggleLoading(); + stopLoadingAnimation(); }); // Grab the channel's latest upload. API forces a max of 50. - let request = gapi.client.youtube.search.list({ + youtubeAPI('search', { part: 'snippet', channelId: channelId, type: 'video', maxResults: 50, order: 'date', - }); - - // Execute API request - request.execute((response) => { + }, function (data) { // Display recent uploads to #main - response['items'].forEach((video) => { + data['items'].forEach((video) => { displayVideos(video); }); }); diff --git a/src/js/events.js b/src/js/events.js index b96b178c6..f15656208 100644 --- a/src/js/events.js +++ b/src/js/events.js @@ -35,13 +35,11 @@ along with FreeTube. If not, see . let commentsTemplate = $.get('templates/comments.html'); commentsTemplate.done((template) => { - let request = gapi.client.youtube.commentThreads.list({ + youtubeAPI('commentThreads', { 'videoId': $('#comments').attr('data-video-id'), 'part': 'snippet,replies', 'maxResults': 100, - }); - - request.execute((data) => { + }, function (data){ let comments = []; let items = data.items; diff --git a/src/js/googleApi.js b/src/js/googleApi.js deleted file mode 100644 index 7d177d869..000000000 --- a/src/js/googleApi.js +++ /dev/null @@ -1,18 +0,0 @@ -// File was downloaded to prevent dependency on website. -// You can find this file at https://apis.google.com/js/api.js -// -// This file is not covered by GPL v3. If the owners of this file would like to have -// this file removed from FreeTube, please contact me at FreeTubeApp@protonmail.com - -var gapi=window.gapi=window.gapi||{};gapi._bs=new Date().getTime();(function(){/* - gapi.loader.OBJECT_CREATE_TEST_OVERRIDE &&*/ -var g=window,h=document,m=g.location,n=function(){},q=/\[native code\]/,u=function(a,b,c){return a[b]=a[b]||c},aa=function(a){a=a.sort();for(var b=[],c=void 0,d=0;df}f&&c.push(e)}return c},U=function(){var a=A.nonce;if(void 0!==a)return a&&a===String(a)&&a.match(S)?a:A.nonce=null;var b=u(A,"us",[]);if(!b||!b.length)return A.nonce=null;for(var c=h.getElementsByTagName(R),d=0,e=c.length;d")}},V=function(a){var b=h.createElement(R);b.setAttribute("src",a);a=U();null!==a&&b.setAttribute("nonce",a);b.async="true";(a=h.getElementsByTagName(R)[0])?a.parentNode.insertBefore(b,a):(h.head||h.body||h.documentElement).appendChild(b)},qa=function(a, -b){var c=b&&b._c;if(c)for(var d=0;d { + }, function (data) { createVideoListContainer('Watch History:'); - response['items'].forEach((video) => { + data['items'].forEach((video) => { displayVideos(video, 'history'); }); - toggleLoading(); + stopLoadingAnimation() }); }); } diff --git a/src/js/init.js b/src/js/init.js index 99a7a7696..8e5ef0e78 100644 --- a/src/js/init.js +++ b/src/js/init.js @@ -20,7 +20,7 @@ along with FreeTube. If not, see . /* * File used to initializing the application */ -const {app, BrowserWindow} = require('electron'); +const {app, BrowserWindow, dialog} = require('electron'); const path = require('path'); const url = require('url'); let win; diff --git a/src/js/layout.js b/src/js/layout.js index 7aa3058f5..cf9ed7eac 100644 --- a/src/js/layout.js +++ b/src/js/layout.js @@ -115,23 +115,6 @@ $(document).ready(() => { loadSubscriptions(); }); -/** -* Start the YouTube API. -* -* @return {Void} -*/ -function start() { - // Initializes the client with the API key and the Translate API. - gapi.client.init({ - 'apiKey': apiKey, - }) - - gapi.client.load('youtube', 'v3', () => { - let isLoad = true; - }); -} - - /** * Toggle the ability to view the side navigation bar. * @@ -161,28 +144,27 @@ function clearMainContainer() { hideConfirmFunction(); } -/** -* Show the loading animation before / after a function runs. Also disables / enables input -* -* @return {Void} -*/ -function toggleLoading() { +function startLoadingAnimation() { const loading = document.getElementById('loading'); const sideNavDisabled = document.getElementById('sideNavDisabled'); const searchBar = document.getElementById('search'); const goToVideoInput = document.getElementById('jumpToInput'); - if (loading.style.display === 'none' || loading.style.display === '') { loading.style.display = 'inherit'; sideNavDisabled.style.display = 'inherit'; searchBar.disabled = true; goToVideoInput.disabled = true; - } else { +} +function stopLoadingAnimation() { + const loading = document.getElementById('loading'); + const sideNavDisabled = document.getElementById('sideNavDisabled'); + const searchBar = document.getElementById('search'); + const goToVideoInput = document.getElementById('jumpToInput'); + loading.style.display = 'none'; sideNavDisabled.style.display = 'none'; searchBar.disabled = false; goToVideoInput.disabled = false; - } } /** @@ -214,7 +196,7 @@ function createVideoListContainer(headerLabel = '') { function showAbout(){ // Remove current information and display loading animation clearMainContainer(); - toggleLoading(); + startLoadingAnimation(); // Grab about.html to be used as a template $.get('templates/about.html', (template) => { @@ -224,7 +206,7 @@ function showAbout(){ }); // Render to #main and remove loading animation $('#main').html(rendered); - toggleLoading(); + stopLoadingAnimation(); }); } diff --git a/src/js/savedVideos.js b/src/js/savedVideos.js index 0b491a403..85f7535dc 100644 --- a/src/js/savedVideos.js +++ b/src/js/savedVideos.js @@ -113,7 +113,7 @@ function videoIsSaved(videoId) { */ function showSavedVideos(){ clearMainContainer(); - toggleLoading(); + startLoadingAnimation(); console.log('checking saved videos'); let videoList = ''; @@ -136,20 +136,17 @@ function showSavedVideos(){ } // Call the YouTube API - let request = gapi.client.youtube.videos.list({ + youtubeAPI('videos', { part: 'snippet', id: videoList, maxResults: 50, - }); - - // Execute the API request - request.execute((response) => { + }, function (data) { // Render the videos to the screen createVideoListContainer('Saved Videos:'); - response['items'].forEach((video) => { + data['items'].forEach((video) => { displayVideos(video, 'history'); }); - toggleLoading(); + stopLoadingAnimation(); }); }); } diff --git a/src/js/settings.js b/src/js/settings.js index b818ac9e8..9ca1dc11b 100644 --- a/src/js/settings.js +++ b/src/js/settings.js @@ -21,6 +21,10 @@ along with FreeTube. If not, see . * A file for functions used for settings. */ +// To any third party devs that fork the project, please be ethical and change the API keys. +const apiKeyBank = ['AIzaSyDjszXMCw44W_k-pdNoOxUHFyKGtU_ejwE', 'AIzaSyA0CkT2lS1q9HHaFYGNGM4Ycjl1kmRy22s', 'AIzaSyAiKgR75e3XAznCcb1cj4NUJ5rR_y3uB8E', 'AIzaSyDPy5jq2l1Bgv3-MbpGdZd3W3ik1BMZeDc', 'AIzaSyBeQ-Jd0lyMmul-K1QMZ2S4GSlnGFdCd3M']; + + /** * Display the settings screen to the user. * @@ -28,14 +32,11 @@ along with FreeTube. If not, see . */ function showSettings() { clearMainContainer(); - toggleLoading(); + startLoadingAnimation(); let isChecked = ''; let key = ''; - // To any third party devs that fork the project, please be ethical and change the API keys. - const apiKeyBank = ['AIzaSyDjszXMCw44W_k-pdNoOxUHFyKGtU_ejwE', 'AIzaSyA0CkT2lS1q9HHaFYGNGM4Ycjl1kmRy22s', 'AIzaSyAiKgR75e3XAznCcb1cj4NUJ5rR_y3uB8E', 'AIzaSyDPy5jq2l1Bgv3-MbpGdZd3W3ik1BMZeDc', 'AIzaSyBeQ-Jd0lyMmul-K1QMZ2S4GSlnGFdCd3M']; - /* * Check the settings database for the user's current settings. This is so the * settings page has the correct toggles related when it is rendered. @@ -64,7 +65,7 @@ function showSettings() { }); // Render template to application $('#main').html(rendered); - toggleLoading(); + stopLoadingAnimation(); // Check / uncheck the switch depending on the user's settings. if (currentTheme === 'light') { @@ -82,9 +83,6 @@ function showSettings() { * @return {Void} */ function checkDefaultSettings() { - // To any third party devs that fork the project, please be ethical and change the API keys. - const apiKeyBank = ['AIzaSyDjszXMCw44W_k-pdNoOxUHFyKGtU_ejwE', 'AIzaSyA0CkT2lS1q9HHaFYGNGM4Ycjl1kmRy22s', 'AIzaSyAiKgR75e3XAznCcb1cj4NUJ5rR_y3uB8E', 'AIzaSyDPy5jq2l1Bgv3-MbpGdZd3W3ik1BMZeDc', 'AIzaSyBeQ-Jd0lyMmul-K1QMZ2S4GSlnGFdCd3M']; - // Grab a random API Key. apiKey = apiKeyBank[Math.floor(Math.random() * apiKeyBank.length)]; @@ -129,7 +127,6 @@ function checkDefaultSettings() { console.log("Using API key: " + apiKey); // Loads the JavaScript client library and invokes `start` afterwards. - gapi.load('client', start); }); } diff --git a/src/js/subscriptions.js b/src/js/subscriptions.js index cfcc589b2..78ef841a8 100644 --- a/src/js/subscriptions.js +++ b/src/js/subscriptions.js @@ -31,25 +31,22 @@ along with FreeTube. If not, see . function addSubscription(channelId, useToast = true) { console.log(channelId); // Request YouTube API - let request = gapi.client.youtube.channels.list({ + youtubeAPI('channels', { part: 'snippet', id: channelId, - }); - - // Execute API request - request.execute((response) => { - const channelInfo = response['items'][0]['snippet']; + }, function (data){ + const channelInfo = data['items'][0]['snippet']; const channelName = channelInfo['title']; const thumbnail = channelInfo['thumbnails']['high']['url']; - const data = { + const channel = { channelId: channelId, channelName: channelName, channelThumbnail: thumbnail, }; // Refresh the list of subscriptions on the side navigation bar. - subDb.insert(data, (err, newDoc) => { + subDb.insert(channel, (err, newDoc) => { if (useToast){ showToast('Added ' + channelName + ' to subscriptions.'); displaySubs(); @@ -84,13 +81,7 @@ function loadSubscriptions() { clearMainContainer(); const loading = document.getElementById('loading'); - /* - * It is possible for the function to be called several times. This prevents the loading - * from being turned off when the situation occurs. - */ - if (loading.style.display !== 'inherit'){ - toggleLoading(); - } + startLoadingAnimation() let videoList = []; @@ -118,16 +109,14 @@ function loadSubscriptions() { * This number can be changed if we feel necessary. */ try { - let request = gapi.client.youtube.search.list({ + youtubeAPI('search', { part: 'snippet', channelId: channelId, type: 'video', maxResults: 15, order: 'date', - }); - - request.execute((response) => { - videoList = videoList.concat(response['items']); + }, function (error, response, data){ + videoList = videoList.concat(data['items']); // Iterate through the next object in the loop. next(); }); @@ -165,12 +154,12 @@ function loadSubscriptions() { displayVideos(videoList[i]); } } - toggleLoading(); + stopLoadingAnimation() }); } else { // User has no subscriptions. Display message. const container = document.getElementById('main'); - toggleLoading(); + stopLoadingAnimation() container.innerHTML = `

Your Subscription list is currently empty. Start adding subscriptions to see them here.

`; diff --git a/src/js/videos.js b/src/js/videos.js index 9ac84561e..5a55210de 100644 --- a/src/js/videos.js +++ b/src/js/videos.js @@ -39,31 +39,27 @@ function search(nextPageToken = '') { if (nextPageToken === '') { clearMainContainer(); - toggleLoading(); + startLoadingAnimation(); } else { console.log(nextPageToken); showToast('Fetching results. Please wait...'); } // Start API request - let request = gapi.client.youtube.search.list({ + youtubeAPI('search', { q: query, part: 'id, snippet', type: 'video', pageToken: nextPageToken, maxResults: 25, - }); - - // Execute API Request - request.execute((response) => { - console.log(response); + }, function (data){ if (nextPageToken === '') { createVideoListContainer('Search Results:'); - toggleLoading(); + stopLoadingAnimation(); } - response['items'].forEach(displayVideos); - addNextPage(response['result']['nextPageToken']); - }); + data.items.forEach(displayVideos); + addNextPage(data.result.nextPageToken); + }) } /** @@ -162,7 +158,7 @@ function addNextPage(nextPageToken) { */ function playVideo(videoId) { clearMainContainer(); - toggleLoading(); + startLoadingAnimation(); let subscribeText = ''; let savedText = ''; @@ -187,7 +183,7 @@ function playVideo(videoId) { }); } catch (ex) { showToast('Video not found. ID may be invalid.'); - toggleLoading(); + stopLoadingAnimation(); return; } @@ -285,15 +281,11 @@ function playVideo(videoId) { description = autolinker.link(description); // API Request - let request = gapi.client.youtube.channels.list({ + youtubeAPI('channels', { 'id': channelId, 'part': 'snippet,contentDetails,statistics' - }); - - // Execute request - request.execute((response) => { - console.log(response); - const channelThumbnail = response['items'][0]['snippet']['thumbnails']['high']['url']; + }, function (data){ + const channelThumbnail = data['items'][0]['snippet']['thumbnails']['high']['url']; $.get('templates/player.html', (template) => { mustache.parse(template); @@ -321,7 +313,7 @@ function playVideo(videoId) { embedPlayer: embedPlayer, }); $('#main').html(rendered); - toggleLoading(); + stopLoadingAnimation(); showVideoRecommendations(videoId); console.log('done'); }); @@ -343,15 +335,13 @@ function playVideo(videoId) { * @param {string} videoId - The video ID of the video to get recommendations from. */ function showVideoRecommendations(videoId) { - let request = gapi.client.youtube.search.list({ + youtubeAPI('search', { part: 'snippet', type: 'video', relatedToVideoId: videoId, maxResults: 15, - }); - - request.execute((response) => { - const recommendations = response['items']; + }, function (data){ + const recommendations = data.items; recommendations.forEach((data) => { const snippet = data['snippet']; const videoId = data['id']['videoId']; @@ -454,7 +444,7 @@ function parseVideoLink() { */ function showMostPopular() { clearMainContainer(); - toggleLoading(); + startLoadingAnimation(); // Get the date of 2 days ago. var d = new Date(); @@ -465,19 +455,16 @@ function showMostPopular() { // These are the videos that are considered as 'most popular' and is how similar // Applications grab these. Videos in the 'Trending' tab on YouTube will be different. // And there is no way to grab those videos. - let request = gapi.client.youtube.search.list({ + youtubeAPI('search', { part: 'snippet', order: 'viewCount', type: 'video', publishedAfter: d.toISOString(), maxResults: 50, - }); - - request.execute((response) => { - console.log(response); + }, function (data){ createVideoListContainer('Most Popular:'); - toggleLoading(); - response['items'].forEach(displayVideos); + stopLoadingAnimation(); + data['items'].forEach(displayVideos); }); } @@ -506,14 +493,11 @@ function copyLink(website, videoId) { function getEmbedPlayer(videoId) { console.log(videoId); return new Promise((resolve, reject) => { - let request = gapi.client.youtube.videos.list({ + youtubeAPI('videos', { part: 'player', id: videoId, - }); - - request.execute((response) => { - console.log(response); - let embedHtml = response['items'][0]['player']['embedHtml']; + }, function (data){ + let embedHtml = data.items[0].player.embedHtml; embedHtml = embedHtml.replace('src="', 'src="https:'); embedHtml = embedHtml.replace('width="480px"', ''); embedHtml = embedHtml.replace('height="270px"', ''); diff --git a/src/js/youtubeApi.js b/src/js/youtubeApi.js new file mode 100644 index 000000000..add2b4130 --- /dev/null +++ b/src/js/youtubeApi.js @@ -0,0 +1,17 @@ +var request = require("request"); +function youtubeAPI (path, qs, callback) { + qs.key = apiKey; + request({'url': "https://www.googleapis.com/youtube/v3/"+path, 'qs': qs, 'json': true}, + function (error, response, body){ + console.log([error, response, body]); + if (error){ + dialog.showErrorBox('YouTube API HTTP error', JSON.stringify(error)) + stopLoadingAnimation() + } else if (response.statusCode != 200){ + dialog.showErrorBox('YouTube API error', JSON.stringify(body)) + stopLoadingAnimation() + } else { + callback(body); + } + }); +} From bb36906583a5eab9ab8704876f21669410f755d6 Mon Sep 17 00:00:00 2001 From: Larivact Date: Wed, 7 Mar 2018 07:15:02 +0100 Subject: [PATCH 02/14] Update README.md, the Google API script is no longer used --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 9696416b3..d602e090b 100644 --- a/README.md +++ b/README.md @@ -1,7 +1,7 @@ # FreeTube FreeTube is an Open Source Desktop YouTube player built with privacy in mind. Watch your favorite YouTube videos ad free as well as prevent Google from tracking what you watch. Available for Windows / Mac / Linux -Please note that FreeTube is currently in Beta and using the proprietary and obfuscated [Google API script](https://apis.google.com/js/api.js) (bundled as `src/js/googleApi.js`), which is planned to be ditched in the future. Video URLs are resolved using the [HookTube](https://hooktube.com/) HTTP API. +Please note that FreeTube is currently in Beta and uses the proprietary [YouTube HTTP API](https://developers.google.com/youtube/v3/). Video URLs are resolved using the [HookTube](https://hooktube.com/) HTTP API. Download From cde9175d54f3c36eadac22071b0ee36e492dfeb1 Mon Sep 17 00:00:00 2001 From: Larivact Date: Wed, 7 Mar 2018 07:35:08 +0100 Subject: [PATCH 03/14] Cleanup leftovers --- src/js/settings.js | 2 -- src/js/subscriptions.js | 2 +- 2 files changed, 1 insertion(+), 3 deletions(-) diff --git a/src/js/settings.js b/src/js/settings.js index 9ca1dc11b..375132d78 100644 --- a/src/js/settings.js +++ b/src/js/settings.js @@ -24,7 +24,6 @@ along with FreeTube. If not, see . // To any third party devs that fork the project, please be ethical and change the API keys. const apiKeyBank = ['AIzaSyDjszXMCw44W_k-pdNoOxUHFyKGtU_ejwE', 'AIzaSyA0CkT2lS1q9HHaFYGNGM4Ycjl1kmRy22s', 'AIzaSyAiKgR75e3XAznCcb1cj4NUJ5rR_y3uB8E', 'AIzaSyDPy5jq2l1Bgv3-MbpGdZd3W3ik1BMZeDc', 'AIzaSyBeQ-Jd0lyMmul-K1QMZ2S4GSlnGFdCd3M']; - /** * Display the settings screen to the user. * @@ -126,7 +125,6 @@ function checkDefaultSettings() { } console.log("Using API key: " + apiKey); - // Loads the JavaScript client library and invokes `start` afterwards. }); } diff --git a/src/js/subscriptions.js b/src/js/subscriptions.js index 78ef841a8..988d7ee10 100644 --- a/src/js/subscriptions.js +++ b/src/js/subscriptions.js @@ -115,7 +115,7 @@ function loadSubscriptions() { type: 'video', maxResults: 15, order: 'date', - }, function (error, response, data){ + }, function (data){ videoList = videoList.concat(data['items']); // Iterate through the next object in the loop. next(); From 4cb4871f34cdfeef075a6412600784fd82d24318 Mon Sep 17 00:00:00 2001 From: Larivact Date: Wed, 7 Mar 2018 07:58:08 +0100 Subject: [PATCH 04/14] Fix request dependency in package.json --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 8d2a12e0b..f5624abeb 100644 --- a/package.json +++ b/package.json @@ -67,6 +67,6 @@ "nedb": "^1.8.0", "node-async-loop": "^1.2.2", "opml-to-json": "0.0.3", - "requests": "^0.2.2" + "request": "^2.83.0" } } From 1e3a505b4e9ccf27f74a1ab9cc500c1455e37de4 Mon Sep 17 00:00:00 2001 From: Larivact Date: Thu, 8 Mar 2018 06:22:12 +0100 Subject: [PATCH 05/14] Update API keys --- src/js/settings.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/js/settings.js b/src/js/settings.js index 375132d78..5c16caff1 100644 --- a/src/js/settings.js +++ b/src/js/settings.js @@ -22,7 +22,7 @@ along with FreeTube. If not, see . */ // To any third party devs that fork the project, please be ethical and change the API keys. -const apiKeyBank = ['AIzaSyDjszXMCw44W_k-pdNoOxUHFyKGtU_ejwE', 'AIzaSyA0CkT2lS1q9HHaFYGNGM4Ycjl1kmRy22s', 'AIzaSyAiKgR75e3XAznCcb1cj4NUJ5rR_y3uB8E', 'AIzaSyDPy5jq2l1Bgv3-MbpGdZd3W3ik1BMZeDc', 'AIzaSyBeQ-Jd0lyMmul-K1QMZ2S4GSlnGFdCd3M']; +const apiKeyBank = ['AIzaSyC9E579nh_qqxg6BH4xIce3k_7a9mT4uQc', 'AIzaSyCKplYT6hZIlm2O9FbWTi1G7rkpsLNTq78', 'AIzaSyAE5xzh5GcA_tEDhXmMFd1pEzrL-W7z51E', 'AIzaSyDoFzqwuO9l386eF6BmNkVapjiTJ93CBy4', 'AIzaSyBljfZFPioB0TRJAj-0LS4tlIKl2iucyY4']; /** * Display the settings screen to the user. From ec4fb19f243a23e36687329c08481ceeacc31e9e Mon Sep 17 00:00:00 2001 From: Larivact Date: Thu, 8 Mar 2018 06:23:09 +0100 Subject: [PATCH 06/14] Update youtubeApi.js to use HTTP keep-alive for performance --- src/js/youtubeApi.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/js/youtubeApi.js b/src/js/youtubeApi.js index add2b4130..82b2047f3 100644 --- a/src/js/youtubeApi.js +++ b/src/js/youtubeApi.js @@ -1,7 +1,7 @@ var request = require("request"); function youtubeAPI (path, qs, callback) { qs.key = apiKey; - request({'url': "https://www.googleapis.com/youtube/v3/"+path, 'qs': qs, 'json': true}, + request({'url': "https://www.googleapis.com/youtube/v3/"+path, 'qs': qs, 'json': true, 'forever': true}, function (error, response, body){ console.log([error, response, body]); if (error){ From 2b2fe4016e131531117b14b14df330d1567b8bd3 Mon Sep 17 00:00:00 2001 From: Larivact Date: Sat, 10 Mar 2018 08:46:58 +0100 Subject: [PATCH 07/14] Fix indentation to two spaces --- src/js/channels.js | 2 +- src/js/savedVideos.js | 2 +- src/js/youtubeApi.js | 28 ++++++++++++++-------------- 3 files changed, 16 insertions(+), 16 deletions(-) diff --git a/src/js/channels.js b/src/js/channels.js index 9db836c64..c2bfd0bd3 100644 --- a/src/js/channels.js +++ b/src/js/channels.js @@ -95,7 +95,7 @@ function goToChannel(channelId) { }); // Grab the channel's latest upload. API forces a max of 50. - youtubeAPI('search', { + youtubeAPI('search', { part: 'snippet', channelId: channelId, type: 'video', diff --git a/src/js/savedVideos.js b/src/js/savedVideos.js index 85f7535dc..d99c5c496 100644 --- a/src/js/savedVideos.js +++ b/src/js/savedVideos.js @@ -136,7 +136,7 @@ function showSavedVideos(){ } // Call the YouTube API - youtubeAPI('videos', { + youtubeAPI('videos', { part: 'snippet', id: videoList, maxResults: 50, diff --git a/src/js/youtubeApi.js b/src/js/youtubeApi.js index 82b2047f3..81945e8b5 100644 --- a/src/js/youtubeApi.js +++ b/src/js/youtubeApi.js @@ -1,17 +1,17 @@ var request = require("request"); function youtubeAPI (path, qs, callback) { - qs.key = apiKey; - request({'url': "https://www.googleapis.com/youtube/v3/"+path, 'qs': qs, 'json': true, 'forever': true}, - function (error, response, body){ - console.log([error, response, body]); - if (error){ - dialog.showErrorBox('YouTube API HTTP error', JSON.stringify(error)) - stopLoadingAnimation() - } else if (response.statusCode != 200){ - dialog.showErrorBox('YouTube API error', JSON.stringify(body)) - stopLoadingAnimation() - } else { - callback(body); - } - }); + qs.key = apiKey; + request({'url': "https://www.googleapis.com/youtube/v3/"+path, 'qs': qs, 'json': true, 'forever': true}, + function (error, response, body){ + console.log([error, response, body]); + if (error){ + dialog.showErrorBox('YouTube API HTTP error', JSON.stringify(error)) + stopLoadingAnimation() + } else if (response.statusCode != 200){ + dialog.showErrorBox('YouTube API error', JSON.stringify(body)) + stopLoadingAnimation() + } else { + callback(body); + } + }); } From 76d98500f6f8196e5f369d0af6e07402cafc9c3c Mon Sep 17 00:00:00 2001 From: Larivact Date: Sat, 10 Mar 2018 11:06:34 +0100 Subject: [PATCH 08/14] Fix endless loop in subscriptions.js: loadSubscriptions() --- src/js/subscriptions.js | 31 +++++++++++-------------------- 1 file changed, 11 insertions(+), 20 deletions(-) diff --git a/src/js/subscriptions.js b/src/js/subscriptions.js index c1fb16ce8..30ccc51f3 100644 --- a/src/js/subscriptions.js +++ b/src/js/subscriptions.js @@ -108,26 +108,17 @@ function loadSubscriptions() { * Grab the channels 15 most recent uploads. Typically this should be enough. * This number can be changed if we feel necessary. */ - try { - youtubeAPI('search', { - part: 'snippet', // Try getting content details for video duration in the near future. - channelId: channelId, - type: 'video', - maxResults: 15, - order: 'date', - }, function (data){ - videoList = videoList.concat(data['items']); - // Iterate through the next object in the loop. - next(); - }); - } catch (err) { - /* - * The above API requests sometimes forces an error for some reason. Restart - * the function to prevent this. This should be changed if possible. - */ - loadSubscriptions(); - return; - } + youtubeAPI('search', { + part: 'snippet', // Try getting content details for video duration in the near future. + channelId: channelId, + type: 'video', + maxResults: 15, + order: 'date', + }, function (data){ + videoList = videoList.concat(data['items']); + // Iterate through the next object in the loop. + next(); + }); }, (err) => { // Sort the videos by date videoList.sort((a, b) => { From 8733cec79cdd1941e48a3d25a898602e273e2799 Mon Sep 17 00:00:00 2001 From: Larivact Date: Sat, 10 Mar 2018 11:08:06 +0100 Subject: [PATCH 09/14] Use jquery.getJSON() instead of request module --- package.json | 3 +-- src/js/youtubeApi.js | 35 ++++++++++++++++++++--------------- 2 files changed, 21 insertions(+), 17 deletions(-) diff --git a/package.json b/package.json index 1a6af9c05..dc66f3123 100644 --- a/package.json +++ b/package.json @@ -66,7 +66,6 @@ "mustache": "^2.3.0", "nedb": "^1.8.0", "node-async-loop": "^1.2.2", - "opml-to-json": "0.0.3", - "request": "^2.83.0" + "opml-to-json": "0.0.3" } } diff --git a/src/js/youtubeApi.js b/src/js/youtubeApi.js index 81945e8b5..96c845c01 100644 --- a/src/js/youtubeApi.js +++ b/src/js/youtubeApi.js @@ -1,17 +1,22 @@ -var request = require("request"); -function youtubeAPI (path, qs, callback) { - qs.key = apiKey; - request({'url': "https://www.googleapis.com/youtube/v3/"+path, 'qs': qs, 'json': true, 'forever': true}, - function (error, response, body){ - console.log([error, response, body]); - if (error){ - dialog.showErrorBox('YouTube API HTTP error', JSON.stringify(error)) - stopLoadingAnimation() - } else if (response.statusCode != 200){ - dialog.showErrorBox('YouTube API error', JSON.stringify(body)) - stopLoadingAnimation() - } else { - callback(body); - } +/** +* List a YouTube HTTP API resource. +* +* @param {string} resource - The path of the resource. +* @param {object} params - The API parameters. +* @param {function} success - The function to be called on success. +* +* @return {Void} +*/ +function youtubeAPI(resource, params, success) { + params.key = apiKey; + console.log(resource, params, success) + $.getJSON( + 'https://www.googleapis.com/youtube/v3/' + resource, + params, + success + ).fail((xhr, textStatus, error) => { + showToast('There was an error calling the YouTube API.'); + console.log(error); + stopLoadingAnimation(); }); } From 2c161f040485b7b7d1a33a926b47bae7598a27c3 Mon Sep 17 00:00:00 2001 From: Preston Date: Sat, 10 Mar 2018 16:33:33 +0000 Subject: [PATCH 10/14] Create CONTRIBUTING.md --- CONTRIBUTING.md | 21 +++++++++++++++++++++ 1 file changed, 21 insertions(+) create mode 100644 CONTRIBUTING.md diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md new file mode 100644 index 000000000..139823c67 --- /dev/null +++ b/CONTRIBUTING.md @@ -0,0 +1,21 @@ +# API Keys + +When you are testing and working on FreeTube, PLEASE use your own API Key. The keys included in the project are in use by the userbase and testing can cause these keys to max out. Please do not risk degrading the experience for other users and use your own key if at all possible. Thank you for your cooperation. + +# Code Contributions + +Please follow these guidlines before sending your pull request and making contributions. + +* When you submit a pull request, you agree that your code is published under the [GNU General Public License](https://www.gnu.org/licenses/gpl.html) +* Do not include non-free software or modules with your code. +* Make sure your pull request is setup to merge your branch to FreeTube's development branch. +* Make sure your branch is up to date with the development branch before submitting your pull request. +* Stick to a similar style of code already in the project. Please look at current code to get an idea on how to do this. +* Follow [ES6](http://es6-features.org/) standards in your code. Ex: Use `let` and `const` instead of `var`. Do not use `function(response){//code}` for callbacks, use `(response) => {//code}`. +* Comment your code when necessary. Follow the [JavaScript Documentation and Comments Standard](https://www.drupal.org/docs/develop/standards/javascript/javascript-api-documentation-and-comment-standards) for functions. +* Please test your code. Make sure new features work as well as core features such as watching videos or loading subscriptions. +* Please limit the amount of Node Modules that you introduce into the project. Only include them when absolutely necessary for your code to work (Ex: Using nedb for databases) or if a module provides similar functionality to what you are trying to achieve (Ex: Using autolinker to create links to outside URLs instead of writing the functionality myself). +* If using a new Node Module, please include the `require` statement in `layout.js` to keep them together. +* Please try to stay involved with the community and maintain your code. I am only one person and I work on FreeTube only in my spare time. I do not have time to work on everything and it would be nice if you can maintain your code when necessary. + +I will update this document when necessary. Anyone who has questions or suggestions on this document are welcome to create an issue or pull request. From 888bb30b434fd0da45d7f625a0daaa2d328ccccb Mon Sep 17 00:00:00 2001 From: Preston Date: Sat, 10 Mar 2018 16:44:18 +0000 Subject: [PATCH 11/14] Create PULL_REQUEST_TEMPLATE.md --- PULL_REQUEST_TEMPLATE.md | 13 +++++++++++++ 1 file changed, 13 insertions(+) create mode 100644 PULL_REQUEST_TEMPLATE.md diff --git a/PULL_REQUEST_TEMPLATE.md b/PULL_REQUEST_TEMPLATE.md new file mode 100644 index 000000000..a2fd36065 --- /dev/null +++ b/PULL_REQUEST_TEMPLATE.md @@ -0,0 +1,13 @@ +- [ ] I have read and agree to the [Contribution Guidelines](https://github.com/FreeTubeApp/FreeTube/blob/master/CONTRIBUTING.md) +- [ ] I can maintain / support my code if issues arise. + +**Does your change relate to a current issue? Please list it here if applicable.** + + +**Please list out the changes you've made** + + +**Does your change include any new Node Modules? If yes, what modules and what are they licensed under?** + + +**Other Comments** From a62d3e9fc44b30569cb9f354576c0ad7bf368808 Mon Sep 17 00:00:00 2001 From: Preston Date: Sat, 10 Mar 2018 16:50:27 +0000 Subject: [PATCH 12/14] Update CONTRIBUTING.md --- CONTRIBUTING.md | 36 ++++++++++++++++++++++++++++++++++++ 1 file changed, 36 insertions(+) diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 139823c67..0e69c35c9 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -18,4 +18,40 @@ Please follow these guidlines before sending your pull request and making contri * If using a new Node Module, please include the `require` statement in `layout.js` to keep them together. * Please try to stay involved with the community and maintain your code. I am only one person and I work on FreeTube only in my spare time. I do not have time to work on everything and it would be nice if you can maintain your code when necessary. +# Setting up Your Environment + +Here's how to get your environment setup. You will need Git and NPM installed on your system. + +Clone down the repositoy: +``` +git clone https://github.com/FreeTubeApp/FreeTube.git +``` + +Install Dependencies: +``` +npm install +``` + +Run the application: +``` +npm start +``` + +Make / Package application: + +Windows (Requires Wine on Linux): +``` +npm run make:win32 +``` + +Mac: +``` +npm run make:darwin +``` + +Linux (Requires deb and rpm to be installed): +``` +npm run make:linux +``` + I will update this document when necessary. Anyone who has questions or suggestions on this document are welcome to create an issue or pull request. From 8a605b4458944bd1be6b5c22ac84c46cece30e07 Mon Sep 17 00:00:00 2001 From: Preston Date: Sat, 10 Mar 2018 16:51:38 +0000 Subject: [PATCH 13/14] Update README.md --- README.md | 33 +-------------------------------- 1 file changed, 1 insertion(+), 32 deletions(-) diff --git a/README.md b/README.md index 509e69a33..f890530e3 100644 --- a/README.md +++ b/README.md @@ -30,38 +30,7 @@ While I believe that FreeTube should work well for most users, there will probab # I'd like to help! If you have an idea or if you found a bug, please create an issue so that we can track it. Please check the current issues and make sure that someone else hasn't mentioned it already before submitting an issue. -If you like to get your hands dirty and want to contribute, we would love to have your help. Send a pull request and someone will review your code. Proper contribution guidelines will be included soon, but in the meantime here's how to get start: - -After you pull down the code: - -Install Dependencies: -``` -npm install -``` - -Run the application: -``` -npm start -``` - -Make / Package application: - -Windows (Requires Wine on Linux): -``` -npm run make:win32 -``` - -Mac: -``` -npm run make:darwin -``` - -Linux (Requires deb and rpm): -``` -npm run make:linux -``` - -The bundled application will then be located in the "/out" folder in your project directory. +If you like to get your hands dirty and want to contribute, we would love to have your help. Send a pull request and someone will review your code. Please follow the [Contribution Guidelines](https://github.com/FreeTubeApp/FreeTube/blob/master/CONTRIBUTING.md) before sending your pull request. # License [![GNU GPLv3 Image](https://www.gnu.org/graphics/gplv3-127x51.png)](http://www.gnu.org/licenses/gpl-3.0.en.html) From a73b82429532bf9c28a07d09cf749770f27f86ba Mon Sep 17 00:00:00 2001 From: Larivact Date: Sat, 10 Mar 2018 22:03:32 +0100 Subject: [PATCH 14/14] Replace proprietary googleApi.js with HTTP Requests (#21) * Ditch googleApi.js, use request instead; refactor code * Update README.md, the Google API script is no longer used * Cleanup leftovers * Fix request dependency in package.json * Update API keys * Update youtubeApi.js to use HTTP keep-alive for performance * Fix indentation to two spaces * Fix endless loop in subscriptions.js: loadSubscriptions() * Use jquery.getJSON() instead of request module --- README.md | 2 +- src/index.html | 2 +- src/js/channels.js | 35 ++++++++----------- src/js/events.js | 6 ++-- src/js/googleApi.js | 18 ---------- src/js/history.js | 12 +++---- src/js/init.js | 2 +- src/js/layout.js | 38 ++++++--------------- src/js/savedVideos.js | 13 +++----- src/js/settings.js | 15 +++------ src/js/subscriptions.js | 58 +++++++++++--------------------- src/js/videos.js | 74 +++++++++++++++-------------------------- src/js/youtubeApi.js | 22 ++++++++++++ 13 files changed, 110 insertions(+), 187 deletions(-) delete mode 100644 src/js/googleApi.js create mode 100644 src/js/youtubeApi.js diff --git a/README.md b/README.md index f890530e3..f75f357fa 100644 --- a/README.md +++ b/README.md @@ -1,7 +1,7 @@ # FreeTube FreeTube is an Open Source Desktop YouTube player built with privacy in mind. Watch your favorite YouTube videos ad free as well as prevent Google from tracking what you watch. Available for Windows / Mac / Linux -Please note that FreeTube is currently in Beta and using the proprietary and obfuscated [Google API script](https://apis.google.com/js/api.js) (bundled as `src/js/googleApi.js`), which is planned to be ditched in the future. Video URLs are resolved using the [youtube-dl](https://github.com/jaimeMF/youtube-dl-api-server) HTTP API. +Please note that FreeTube is currently in Beta and uses the proprietary [YouTube HTTP API](https://developers.google.com/youtube/v3/). Video URLs are resolved using a [youtube-dl-api-server](https://github.com/jaimeMF/youtube-dl-api-server). Download diff --git a/src/index.html b/src/index.html index 15852a2bf..33971f4af 100644 --- a/src/index.html +++ b/src/index.html @@ -11,7 +11,7 @@ - + diff --git a/src/js/channels.js b/src/js/channels.js index dd7e44048..c2bfd0bd3 100644 --- a/src/js/channels.js +++ b/src/js/channels.js @@ -24,14 +24,11 @@ along with FreeTube. If not, see . /*function getChannelThumbnail(channelId, callback) { let url = ''; - let request = gapi.client.youtube.channels.list({ + youtubeAPI('channels', { 'id': channelId, 'part': 'snippet', - }); - - request.execute((response) => { - url = response['items'][0]['snippet']['thumbnails']['high']['url']; - callback(url); + }, function (data){ + callback(data.items[0].snippet.thumbnails.high.url); }); }*/ @@ -45,7 +42,7 @@ along with FreeTube. If not, see . function goToChannel(channelId) { event.stopPropagation(); clearMainContainer(); - toggleLoading(); + startLoadingAnimation(); // Check if the user is subscribed to the channel. Display different text based on the information @@ -62,17 +59,14 @@ function goToChannel(channelId) { }); // Call YouTube API to grab channel information - let request = gapi.client.youtube.channels.list({ + youtubeAPI('channels', { part: 'snippet, brandingSettings, statistics', id: channelId, - }); - - // Perform API Execution - request.execute((response) => { + }, function (data){ // Set variables of extracted information - const brandingSettings = response['items'][0]['brandingSettings']; - const statistics = response['items'][0]['statistics']; - const snippet = response['items'][0]['snippet']; + const brandingSettings = data['items'][0]['brandingSettings']; + const statistics = data['items'][0]['statistics']; + const snippet = data['items'][0]['snippet']; const channelName = brandingSettings['channel']['title']; const channelBanner = brandingSettings['image']['bannerImageUrl']; const channelImage = snippet['thumbnails']['high']['url']; @@ -97,22 +91,19 @@ function goToChannel(channelId) { }); // Render the template on to #main $('#main').html(rendered); - toggleLoading(); + stopLoadingAnimation(); }); // Grab the channel's latest upload. API forces a max of 50. - let request = gapi.client.youtube.search.list({ + youtubeAPI('search', { part: 'snippet', channelId: channelId, type: 'video', maxResults: 50, order: 'date', - }); - - // Execute API request - request.execute((response) => { + }, function (data) { // Display recent uploads to #main - response['items'].forEach((video) => { + data['items'].forEach((video) => { displayVideos(video); }); }); diff --git a/src/js/events.js b/src/js/events.js index b96b178c6..f15656208 100644 --- a/src/js/events.js +++ b/src/js/events.js @@ -35,13 +35,11 @@ along with FreeTube. If not, see . let commentsTemplate = $.get('templates/comments.html'); commentsTemplate.done((template) => { - let request = gapi.client.youtube.commentThreads.list({ + youtubeAPI('commentThreads', { 'videoId': $('#comments').attr('data-video-id'), 'part': 'snippet,replies', 'maxResults': 100, - }); - - request.execute((data) => { + }, function (data){ let comments = []; let items = data.items; diff --git a/src/js/googleApi.js b/src/js/googleApi.js deleted file mode 100644 index 7d177d869..000000000 --- a/src/js/googleApi.js +++ /dev/null @@ -1,18 +0,0 @@ -// File was downloaded to prevent dependency on website. -// You can find this file at https://apis.google.com/js/api.js -// -// This file is not covered by GPL v3. If the owners of this file would like to have -// this file removed from FreeTube, please contact me at FreeTubeApp@protonmail.com - -var gapi=window.gapi=window.gapi||{};gapi._bs=new Date().getTime();(function(){/* - gapi.loader.OBJECT_CREATE_TEST_OVERRIDE &&*/ -var g=window,h=document,m=g.location,n=function(){},q=/\[native code\]/,u=function(a,b,c){return a[b]=a[b]||c},aa=function(a){a=a.sort();for(var b=[],c=void 0,d=0;df}f&&c.push(e)}return c},U=function(){var a=A.nonce;if(void 0!==a)return a&&a===String(a)&&a.match(S)?a:A.nonce=null;var b=u(A,"us",[]);if(!b||!b.length)return A.nonce=null;for(var c=h.getElementsByTagName(R),d=0,e=c.length;d")}},V=function(a){var b=h.createElement(R);b.setAttribute("src",a);a=U();null!==a&&b.setAttribute("nonce",a);b.async="true";(a=h.getElementsByTagName(R)[0])?a.parentNode.insertBefore(b,a):(h.head||h.body||h.documentElement).appendChild(b)},qa=function(a, -b){var c=b&&b._c;if(c)for(var d=0;d { + }, function (data) { createVideoListContainer('Watch History:'); - response['items'].forEach((video) => { + data['items'].forEach((video) => { displayVideos(video, 'history'); }); - toggleLoading(); + stopLoadingAnimation() }); }); } diff --git a/src/js/init.js b/src/js/init.js index 3e35f6218..c549a9a05 100644 --- a/src/js/init.js +++ b/src/js/init.js @@ -20,7 +20,7 @@ along with FreeTube. If not, see . /* * File used to initializing the application */ -const {app, BrowserWindow} = require('electron'); +const {app, BrowserWindow, dialog} = require('electron'); const path = require('path'); const url = require('url'); let win; diff --git a/src/js/layout.js b/src/js/layout.js index 7aa3058f5..cf9ed7eac 100644 --- a/src/js/layout.js +++ b/src/js/layout.js @@ -115,23 +115,6 @@ $(document).ready(() => { loadSubscriptions(); }); -/** -* Start the YouTube API. -* -* @return {Void} -*/ -function start() { - // Initializes the client with the API key and the Translate API. - gapi.client.init({ - 'apiKey': apiKey, - }) - - gapi.client.load('youtube', 'v3', () => { - let isLoad = true; - }); -} - - /** * Toggle the ability to view the side navigation bar. * @@ -161,28 +144,27 @@ function clearMainContainer() { hideConfirmFunction(); } -/** -* Show the loading animation before / after a function runs. Also disables / enables input -* -* @return {Void} -*/ -function toggleLoading() { +function startLoadingAnimation() { const loading = document.getElementById('loading'); const sideNavDisabled = document.getElementById('sideNavDisabled'); const searchBar = document.getElementById('search'); const goToVideoInput = document.getElementById('jumpToInput'); - if (loading.style.display === 'none' || loading.style.display === '') { loading.style.display = 'inherit'; sideNavDisabled.style.display = 'inherit'; searchBar.disabled = true; goToVideoInput.disabled = true; - } else { +} +function stopLoadingAnimation() { + const loading = document.getElementById('loading'); + const sideNavDisabled = document.getElementById('sideNavDisabled'); + const searchBar = document.getElementById('search'); + const goToVideoInput = document.getElementById('jumpToInput'); + loading.style.display = 'none'; sideNavDisabled.style.display = 'none'; searchBar.disabled = false; goToVideoInput.disabled = false; - } } /** @@ -214,7 +196,7 @@ function createVideoListContainer(headerLabel = '') { function showAbout(){ // Remove current information and display loading animation clearMainContainer(); - toggleLoading(); + startLoadingAnimation(); // Grab about.html to be used as a template $.get('templates/about.html', (template) => { @@ -224,7 +206,7 @@ function showAbout(){ }); // Render to #main and remove loading animation $('#main').html(rendered); - toggleLoading(); + stopLoadingAnimation(); }); } diff --git a/src/js/savedVideos.js b/src/js/savedVideos.js index 0b491a403..d99c5c496 100644 --- a/src/js/savedVideos.js +++ b/src/js/savedVideos.js @@ -113,7 +113,7 @@ function videoIsSaved(videoId) { */ function showSavedVideos(){ clearMainContainer(); - toggleLoading(); + startLoadingAnimation(); console.log('checking saved videos'); let videoList = ''; @@ -136,20 +136,17 @@ function showSavedVideos(){ } // Call the YouTube API - let request = gapi.client.youtube.videos.list({ + youtubeAPI('videos', { part: 'snippet', id: videoList, maxResults: 50, - }); - - // Execute the API request - request.execute((response) => { + }, function (data) { // Render the videos to the screen createVideoListContainer('Saved Videos:'); - response['items'].forEach((video) => { + data['items'].forEach((video) => { displayVideos(video, 'history'); }); - toggleLoading(); + stopLoadingAnimation(); }); }); } diff --git a/src/js/settings.js b/src/js/settings.js index da89966b2..17dbaa098 100644 --- a/src/js/settings.js +++ b/src/js/settings.js @@ -21,6 +21,9 @@ along with FreeTube. If not, see . * A file for functions used for settings. */ +// To any third party devs that fork the project, please be ethical and change the API keys. +const apiKeyBank = ['AIzaSyC9E579nh_qqxg6BH4xIce3k_7a9mT4uQc', 'AIzaSyCKplYT6hZIlm2O9FbWTi1G7rkpsLNTq78', 'AIzaSyAE5xzh5GcA_tEDhXmMFd1pEzrL-W7z51E', 'AIzaSyDoFzqwuO9l386eF6BmNkVapjiTJ93CBy4', 'AIzaSyBljfZFPioB0TRJAj-0LS4tlIKl2iucyY4']; + /** * Display the settings screen to the user. * @@ -28,14 +31,11 @@ along with FreeTube. If not, see . */ function showSettings() { clearMainContainer(); - toggleLoading(); + startLoadingAnimation(); let isChecked = ''; let key = ''; - // To any third party devs that fork the project, please be ethical and change the API keys. - const apiKeyBank = ['AIzaSyC9E579nh_qqxg6BH4xIce3k_7a9mT4uQc', 'AIzaSyCKplYT6hZIlm2O9FbWTi1G7rkpsLNTq78', 'AIzaSyAE5xzh5GcA_tEDhXmMFd1pEzrL-W7z51E', 'AIzaSyDoFzqwuO9l386eF6BmNkVapjiTJ93CBy4', 'AIzaSyBljfZFPioB0TRJAj-0LS4tlIKl2iucyY4']; - /* * Check the settings database for the user's current settings. This is so the * settings page has the correct toggles related when it is rendered. @@ -64,7 +64,7 @@ function showSettings() { }); // Render template to application $('#main').html(rendered); - toggleLoading(); + stopLoadingAnimation(); // Check / uncheck the switch depending on the user's settings. if (currentTheme === 'light') { @@ -82,8 +82,6 @@ function showSettings() { * @return {Void} */ function checkDefaultSettings() { - // To any third party devs that fork the project, please be ethical and change the API keys. - const apiKeyBank = ['AIzaSyC9E579nh_qqxg6BH4xIce3k_7a9mT4uQc', 'AIzaSyCKplYT6hZIlm2O9FbWTi1G7rkpsLNTq78', 'AIzaSyAE5xzh5GcA_tEDhXmMFd1pEzrL-W7z51E', 'AIzaSyDoFzqwuO9l386eF6BmNkVapjiTJ93CBy4', 'AIzaSyBljfZFPioB0TRJAj-0LS4tlIKl2iucyY4']; // Grab a random API Key. apiKey = apiKeyBank[Math.floor(Math.random() * apiKeyBank.length)]; @@ -126,9 +124,6 @@ function checkDefaultSettings() { } }); } - - // Loads the JavaScript client library and invokes `start` afterwards. - gapi.load('client', start); }); } diff --git a/src/js/subscriptions.js b/src/js/subscriptions.js index a164c4fc0..30ccc51f3 100644 --- a/src/js/subscriptions.js +++ b/src/js/subscriptions.js @@ -31,25 +31,22 @@ along with FreeTube. If not, see . function addSubscription(channelId, useToast = true) { console.log(channelId); // Request YouTube API - let request = gapi.client.youtube.channels.list({ + youtubeAPI('channels', { part: 'snippet', id: channelId, - }); - - // Execute API request - request.execute((response) => { - const channelInfo = response['items'][0]['snippet']; + }, function (data){ + const channelInfo = data['items'][0]['snippet']; const channelName = channelInfo['title']; const thumbnail = channelInfo['thumbnails']['high']['url']; - const data = { + const channel = { channelId: channelId, channelName: channelName, channelThumbnail: thumbnail, }; // Refresh the list of subscriptions on the side navigation bar. - subDb.insert(data, (err, newDoc) => { + subDb.insert(channel, (err, newDoc) => { if (useToast){ showToast('Added ' + channelName + ' to subscriptions.'); displaySubs(); @@ -84,13 +81,7 @@ function loadSubscriptions() { clearMainContainer(); const loading = document.getElementById('loading'); - /* - * It is possible for the function to be called several times. This prevents the loading - * from being turned off when the situation occurs. - */ - if (loading.style.display !== 'inherit'){ - toggleLoading(); - } + startLoadingAnimation() let videoList = []; @@ -117,28 +108,17 @@ function loadSubscriptions() { * Grab the channels 15 most recent uploads. Typically this should be enough. * This number can be changed if we feel necessary. */ - try { - let request = gapi.client.youtube.search.list({ - part: 'snippet', // Try getting content details for video duration in the near future. - channelId: channelId, - type: 'video', - maxResults: 15, - order: 'date', - }); - - request.execute((response) => { - videoList = videoList.concat(response['items']); - // Iterate through the next object in the loop. - next(); - }); - } catch (err) { - /* - * The above API requests sometimes forces an error for some reason. Restart - * the function to prevent this. This should be changed if possible. - */ - loadSubscriptions(); - return; - } + youtubeAPI('search', { + part: 'snippet', // Try getting content details for video duration in the near future. + channelId: channelId, + type: 'video', + maxResults: 15, + order: 'date', + }, function (data){ + videoList = videoList.concat(data['items']); + // Iterate through the next object in the loop. + next(); + }); }, (err) => { // Sort the videos by date videoList.sort((a, b) => { @@ -165,12 +145,12 @@ function loadSubscriptions() { displayVideos(videoList[i]); } } - toggleLoading(); + stopLoadingAnimation() }); } else { // User has no subscriptions. Display message. const container = document.getElementById('main'); - toggleLoading(); + stopLoadingAnimation() container.innerHTML = `

Your Subscription list is currently empty. Start adding subscriptions to see them here.

`; diff --git a/src/js/videos.js b/src/js/videos.js index 042ef98b5..50b881610 100644 --- a/src/js/videos.js +++ b/src/js/videos.js @@ -39,31 +39,27 @@ function search(nextPageToken = '') { if (nextPageToken === '') { clearMainContainer(); - toggleLoading(); + startLoadingAnimation(); } else { console.log(nextPageToken); showToast('Fetching results. Please wait...'); } // Start API request - let request = gapi.client.youtube.search.list({ + youtubeAPI('search', { q: query, part: 'id, snippet', type: 'video', pageToken: nextPageToken, maxResults: 25, - }); - - // Execute API Request - request.execute((response) => { - console.log(response); + }, function (data){ if (nextPageToken === '') { createVideoListContainer('Search Results:'); - toggleLoading(); + stopLoadingAnimation(); } - response['items'].forEach(displayVideos); - addNextPage(response['result']['nextPageToken']); - }); + data.items.forEach(displayVideos); + addNextPage(data.result.nextPageToken); + }) } /** @@ -162,7 +158,7 @@ function addNextPage(nextPageToken) { */ function playVideo(videoId) { clearMainContainer(); - toggleLoading(); + startLoadingAnimation(); let subscribeText = ''; let savedText = ''; @@ -191,7 +187,7 @@ function playVideo(videoId) { }); } catch (ex) { showToast('Video not found. ID may be invalid.'); - toggleLoading(); + stopLoadingAnimation(); return; } @@ -282,15 +278,11 @@ function playVideo(videoId) { } // API Request - let request = gapi.client.youtube.channels.list({ + youtubeAPI('channels', { 'id': channelId, 'part': 'snippet' - }); - - // Execute request - request.execute((response) => { - console.log(response); - const channelThumbnail = response['items'][0]['snippet']['thumbnails']['high']['url']; + }, function (data){ + const channelThumbnail = data['items'][0]['snippet']['thumbnails']['high']['url']; $.get('templates/player.html', (template) => { mustache.parse(template); @@ -318,7 +310,7 @@ function playVideo(videoId) { embedPlayer: embedPlayer, }); $('#main').html(rendered); - toggleLoading(); + stopLoadingAnimation(); showVideoRecommendations(videoId); console.log('done'); }); @@ -340,15 +332,13 @@ function playVideo(videoId) { * @param {string} videoId - The video ID of the video to get recommendations from. */ function showVideoRecommendations(videoId) { - let request = gapi.client.youtube.search.list({ + youtubeAPI('search', { part: 'snippet', type: 'video', relatedToVideoId: videoId, maxResults: 15, - }); - - request.execute((response) => { - const recommendations = response['items']; + }, function (data){ + const recommendations = data.items; recommendations.forEach((data) => { const snippet = data['snippet']; const videoId = data['id']['videoId']; @@ -451,7 +441,7 @@ function parseVideoLink() { */ function showMostPopular() { clearMainContainer(); - toggleLoading(); + startLoadingAnimation(); // Get the date of 2 days ago. var d = new Date(); @@ -462,19 +452,16 @@ function showMostPopular() { // These are the videos that are considered as 'most popular' and is how similar // Applications grab these. Videos in the 'Trending' tab on YouTube will be different. // And there is no way to grab those videos. - let request = gapi.client.youtube.search.list({ + youtubeAPI('search', { part: 'snippet', order: 'viewCount', type: 'video', publishedAfter: d.toISOString(), maxResults: 50, - }); - - request.execute((response) => { - console.log(response); + }, function (data){ createVideoListContainer('Most Popular:'); - toggleLoading(); - response['items'].forEach(displayVideos); + stopLoadingAnimation(); + data['items'].forEach(displayVideos); }); } @@ -503,25 +490,16 @@ function copyLink(website, videoId) { function getChannelAndPlayer(videoId) { console.log(videoId); return new Promise((resolve, reject) => { - let data = []; - - let request = gapi.client.youtube.videos.list({ - part: 'snippet, player', + youtubeAPI('videos', { + part: 'snippet,player', id: videoId, - }); - - request.execute((response) => { - console.log(response); - let embedHtml = response['items'][0]['player']['embedHtml']; + }, function (data){ + let embedHtml = data.items[0].player.embedHtml; embedHtml = embedHtml.replace('src="', 'src="https:'); embedHtml = embedHtml.replace('width="480px"', ''); embedHtml = embedHtml.replace('height="270px"', ''); embedHtml = embedHtml.replace(/\"/g, '"'); - data[0] = embedHtml; - data[1] = response['items'][0]['snippet']['channelId']; - - - resolve(data); + resolve([embedHtml, data.items[0].snippet.channelId]); }); }); diff --git a/src/js/youtubeApi.js b/src/js/youtubeApi.js new file mode 100644 index 000000000..96c845c01 --- /dev/null +++ b/src/js/youtubeApi.js @@ -0,0 +1,22 @@ +/** +* List a YouTube HTTP API resource. +* +* @param {string} resource - The path of the resource. +* @param {object} params - The API parameters. +* @param {function} success - The function to be called on success. +* +* @return {Void} +*/ +function youtubeAPI(resource, params, success) { + params.key = apiKey; + console.log(resource, params, success) + $.getJSON( + 'https://www.googleapis.com/youtube/v3/' + resource, + params, + success + ).fail((xhr, textStatus, error) => { + showToast('There was an error calling the YouTube API.'); + console.log(error); + stopLoadingAnimation(); + }); +}