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); + } + }); +}