mirror of https://github.com/FreeTubeApp/FreeTube
Refactor code and improve comments (#40)
* Refactor channels.js * Refactor templates/about.html * Refactor events.js, fix template bug * Improve comments in youtubeApi.js * Remove duplicated apiKeyBank in settings.js * Capitalize comments in init.js * Minor style changes in savedVideos.js * Refactor videos.js, rename displayVideos() to displayVideo() * Minor changes in layout.js and videos.js
This commit is contained in:
parent
d09138c1a6
commit
845aca3fc9
|
@ -33,9 +33,9 @@ along with FreeTube. If not, see <http://www.gnu.org/licenses/>.
|
|||
}*/
|
||||
|
||||
/**
|
||||
* View a channel page, displaying recent uplaods.
|
||||
* Display a channel page, showing latest uploads.
|
||||
*
|
||||
* @param {string} channelId - The channel ID to go to.
|
||||
* @param {string} channelId - The channel ID to display.
|
||||
*
|
||||
* @return {Void}
|
||||
*/
|
||||
|
@ -44,56 +44,34 @@ function goToChannel(channelId) {
|
|||
clearMainContainer();
|
||||
startLoadingAnimation();
|
||||
|
||||
|
||||
// Check if the user is subscribed to the channel. Display different text based on the information
|
||||
let subscribeText = '';
|
||||
const checkSubscription = isSubscribed(channelId);
|
||||
|
||||
checkSubscription.then((results) => {
|
||||
if(results === false){
|
||||
subscribeText = 'SUBSCRIBE';
|
||||
}
|
||||
else{
|
||||
subscribeText = 'UNSUBSCRIBE';
|
||||
}
|
||||
let subButtonText;
|
||||
// Setting subButtonText here as Mustache templates are logic-less.
|
||||
isSubscribed(channelId).then((subscribed) => {
|
||||
subButtonText = (subscribed ? "UNSUBSCRIBE" : "SUBSCRIBE");
|
||||
});
|
||||
|
||||
// Call YouTube API to grab channel information
|
||||
// Grab general channel information
|
||||
youtubeAPI('channels', {
|
||||
part: 'snippet, brandingSettings, statistics',
|
||||
part: 'snippet,brandingSettings,statistics',
|
||||
id: channelId,
|
||||
}, function (data){
|
||||
// Set variables of extracted information
|
||||
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'];
|
||||
const channelData = data.items[0];
|
||||
|
||||
// Channels normally have links in their channel description. This makes them clickable.
|
||||
const channelDescription = autolinker.link(brandingSettings['channel']['description']);
|
||||
|
||||
// Add commas to sub count to make them more readable.
|
||||
let subCount = statistics['subscriberCount'].toString().replace(/\B(?=(\d{3})+(?!\d))/g, ",");
|
||||
|
||||
// Grab the channelView.html template and fill it in with the above variables.
|
||||
const channelViewTemplate = require('./templates/channelView.html');
|
||||
mustache.parse(channelViewTemplate);
|
||||
const rendered = mustache.render(channelViewTemplate, {
|
||||
channelName: channelName,
|
||||
channelImage: channelImage,
|
||||
channelBanner: channelBanner,
|
||||
channelId: channelId,
|
||||
subCount: subCount,
|
||||
channelDescription: channelDescription,
|
||||
isSubscribed: subscribeText,
|
||||
channelName: channelData.brandingSettings.channel.title,
|
||||
channelBanner: channelData.brandingSettings.image.bannerImageUrl,
|
||||
channelImage: channelData.snippet.thumbnails.high.url,
|
||||
subCount: channelData.statistics.subscriberCount.toLocaleString(), //toLocaleString adds commas as thousands separators
|
||||
channelDescription: autolinker.link(channelData.brandingSettings.channel.description), //autolinker makes URLs clickable
|
||||
subButtonText: subButtonText,
|
||||
});
|
||||
// Render the template on to #main
|
||||
$('#main').html(rendered);
|
||||
stopLoadingAnimation();
|
||||
|
||||
// Grab the channel's latest upload. API forces a max of 50.
|
||||
// Grab the channel's latest uploads. API forces a max of 50.
|
||||
youtubeAPI('search', {
|
||||
part: 'snippet',
|
||||
channelId: channelId,
|
||||
|
@ -103,7 +81,7 @@ function goToChannel(channelId) {
|
|||
}, function (data) {
|
||||
// Display recent uploads to #main
|
||||
data['items'].forEach((video) => {
|
||||
displayVideos(video);
|
||||
displayVideo(video);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
|
|
@ -32,31 +32,26 @@ let showComments = function(event) {
|
|||
if (comments.css('display') === 'none') {
|
||||
comments.attr('loaded', 'true');
|
||||
|
||||
const commentsTemplate = require('./templates/comments.html');
|
||||
youtubeAPI('commentThreads', {
|
||||
'videoId': $('#comments').attr('data-video-id'),
|
||||
'part': 'snippet,replies',
|
||||
'maxResults': 100,
|
||||
}, function (data){
|
||||
let comments = [];
|
||||
let items = data.items;
|
||||
|
||||
commentsTemplate.done((template) => {
|
||||
youtubeAPI('commentThreads', {
|
||||
'videoId': $('#comments').attr('data-video-id'),
|
||||
'part': 'snippet,replies',
|
||||
'maxResults': 100,
|
||||
}, function (data){
|
||||
let comments = [];
|
||||
let items = data.items;
|
||||
items.forEach((object) => {
|
||||
let snippet = object.snippet.topLevelComment.snippet;
|
||||
|
||||
items.forEach((object) => {
|
||||
let snippet = object['snippet']['topLevelComment']['snippet'];
|
||||
let dateString = new Date(snippet.publishedAt);
|
||||
let publishedDate = dateFormat(dateString, "mmm dS, yyyy");
|
||||
snippet.publishedAt = dateFormat(new Date(snippet.publishedAt), "mmm dS, yyyy");
|
||||
|
||||
snippet.publishedAt = publishedDate;
|
||||
|
||||
comments.push(snippet);
|
||||
})
|
||||
const html = mustache.render(template, {
|
||||
comments: comments,
|
||||
});
|
||||
$('#comments').html(html);
|
||||
comments.push(snippet);
|
||||
})
|
||||
const commentsTemplate = require('./templates/comments.html');
|
||||
const html = mustache.render(commentsTemplate, {
|
||||
comments: comments,
|
||||
});
|
||||
$('#comments').html(html);
|
||||
});
|
||||
|
||||
comments.show();
|
||||
|
|
|
@ -82,7 +82,7 @@ function showHistory(){
|
|||
}, function (data) {
|
||||
createVideoListContainer('Watch History:');
|
||||
data['items'].forEach((video) => {
|
||||
displayVideos(video, 'history');
|
||||
displayVideo(video, 'history');
|
||||
});
|
||||
stopLoadingAnimation()
|
||||
});
|
||||
|
|
|
@ -28,7 +28,7 @@ let win;
|
|||
if(require('electron-squirrel-startup')) app.quit();
|
||||
|
||||
/**
|
||||
* initialize the electron application
|
||||
* Initialize the Electron application
|
||||
* 1. create the browser window
|
||||
* 2. load the index.html
|
||||
*/
|
||||
|
@ -93,14 +93,14 @@ let init = function() {
|
|||
};
|
||||
|
||||
/**
|
||||
* quit the application
|
||||
* Quit the application
|
||||
*/
|
||||
let allWindowsClosed = function() {
|
||||
app.quit();
|
||||
};
|
||||
|
||||
/**
|
||||
* on mac, when dock icon is clicked,
|
||||
* On Mac, when dock icon is clicked,
|
||||
* create a new window and launch the editor
|
||||
*/
|
||||
let active = function() {
|
||||
|
|
|
@ -23,10 +23,10 @@ along with FreeTube. If not, see <http://www.gnu.org/licenses/>.
|
|||
*/
|
||||
|
||||
// Add general variables. Please put all require statements here.
|
||||
const Datastore = require('nedb'); // Database logic
|
||||
const Datastore = require('nedb'); // database logic
|
||||
window.$ = window.jQuery = require('jquery');
|
||||
const mustache = require('mustache'); // Templating
|
||||
const dateFormat = require('dateformat'); // Formating Dates
|
||||
const mustache = require('mustache'); // templating
|
||||
const dateFormat = require('dateformat'); // formatting dates
|
||||
|
||||
// Used for finding links within text and making them clickable. Used mostly for video descriptions.
|
||||
const autolinker = require('autolinker');
|
||||
|
@ -41,6 +41,7 @@ const localDataStorage = electron.remote.app.getPath('userData'); // Grabs the u
|
|||
const clipboard = electron.clipboard;
|
||||
const getOpml = require('opml-to-json'); // Gets the file type for imported files.
|
||||
const fs = require('fs'); // Used to read files. Specifically in the settings page.
|
||||
|
||||
let currentTheme = '';
|
||||
let apiKey;
|
||||
let dialog = require('electron').remote.dialog; // Used for opening file browser to export / import subscriptions.
|
||||
|
@ -51,25 +52,21 @@ require.extensions['.html'] = function (module, filename) {
|
|||
module.exports = fs.readFileSync(filename, 'utf8');
|
||||
};
|
||||
|
||||
// Subscriptions database file
|
||||
const subDb = new Datastore({
|
||||
filename: localDataStorage + '/subscriptions.db',
|
||||
autoload: true
|
||||
});
|
||||
|
||||
// History database file
|
||||
const historyDb = new Datastore({
|
||||
filename: localDataStorage + '/videohistory.db',
|
||||
autoload: true
|
||||
});
|
||||
|
||||
// Saved videos database file
|
||||
const savedVidsDb = new Datastore({
|
||||
filename: localDataStorage + '/savedvideos.db',
|
||||
autoload: true
|
||||
});
|
||||
|
||||
// Settings database file.
|
||||
const settingsDb = new Datastore({
|
||||
filename: localDataStorage + 'settings.db',
|
||||
autoload: true
|
||||
|
@ -155,10 +152,10 @@ function startLoadingAnimation() {
|
|||
const searchBar = document.getElementById('search');
|
||||
const goToVideoInput = document.getElementById('jumpToInput');
|
||||
|
||||
loading.style.display = 'inherit';
|
||||
sideNavDisabled.style.display = 'inherit';
|
||||
searchBar.disabled = true;
|
||||
goToVideoInput.disabled = true;
|
||||
loading.style.display = 'inherit';
|
||||
sideNavDisabled.style.display = 'inherit';
|
||||
searchBar.disabled = true;
|
||||
goToVideoInput.disabled = true;
|
||||
}
|
||||
function stopLoadingAnimation() {
|
||||
const loading = document.getElementById('loading');
|
||||
|
@ -166,10 +163,10 @@ function stopLoadingAnimation() {
|
|||
const searchBar = document.getElementById('search');
|
||||
const goToVideoInput = document.getElementById('jumpToInput');
|
||||
|
||||
loading.style.display = 'none';
|
||||
sideNavDisabled.style.display = 'none';
|
||||
searchBar.disabled = false;
|
||||
goToVideoInput.disabled = false;
|
||||
loading.style.display = 'none';
|
||||
sideNavDisabled.style.display = 'none';
|
||||
searchBar.disabled = false;
|
||||
goToVideoInput.disabled = false;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -203,7 +200,6 @@ function showAbout(){
|
|||
clearMainContainer();
|
||||
startLoadingAnimation();
|
||||
|
||||
// Grab about.html to be used as a template
|
||||
const aboutTemplate = require('./templates/about.html')
|
||||
mustache.parse(aboutTemplate);
|
||||
$('#main').html(
|
||||
|
@ -215,10 +211,10 @@ function showAbout(){
|
|||
}
|
||||
|
||||
/**
|
||||
* Display a toast message in the bottom right corner of the page. Toast will
|
||||
* automatically disappear after 5 seconds.
|
||||
* Display a toast message in the bottom right corner of the page.
|
||||
* The toast automatically disappears after a timeout.
|
||||
*
|
||||
* @param {string} message - The message to be displayed in the toast.
|
||||
* @param {string} message - The toast message.
|
||||
*
|
||||
* @return {Void}
|
||||
*/
|
||||
|
@ -234,7 +230,7 @@ function showToast(message){
|
|||
toast.style.opacity = 0.9;
|
||||
|
||||
// Set the timer for the toast to be removed.
|
||||
toastTimeout = window.setTimeout(hideToast, 5000); // 5 seconds
|
||||
toastTimeout = window.setTimeout(hideToast, 5000);
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
@ -126,12 +126,12 @@ function showSavedVideos(){
|
|||
// TODO: Allow the app to show more than 50 saved videos.
|
||||
if(docs.length > 49){
|
||||
for (let i = 0; i < 49; i++) {
|
||||
videoList = videoList + ',' + docs[i]['videoId'];
|
||||
videoList = videoList + ',' + docs[i].videoId;
|
||||
}
|
||||
}
|
||||
else{
|
||||
docs.forEach((video) => {
|
||||
videoList = videoList + ',' + video['videoId'];
|
||||
videoList = videoList + ',' + video.videoId;
|
||||
});
|
||||
}
|
||||
|
||||
|
@ -143,8 +143,8 @@ function showSavedVideos(){
|
|||
}, function (data) {
|
||||
// Render the videos to the screen
|
||||
createVideoListContainer('Saved Videos:');
|
||||
data['items'].forEach((video) => {
|
||||
displayVideos(video, 'history');
|
||||
data.items.forEach((video) => {
|
||||
displayVideo(video, 'history');
|
||||
});
|
||||
stopLoadingAnimation();
|
||||
});
|
||||
|
|
|
@ -135,9 +135,6 @@ function updateSettings() {
|
|||
var themeSwitch = document.getElementById('themeSwitch').checked;
|
||||
var key = document.getElementById('api-key').value;
|
||||
|
||||
// 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'];
|
||||
|
||||
apiKey = apiKeyBank[Math.floor(Math.random() * apiKeyBank.length)];
|
||||
|
||||
if (themeSwitch == true) {
|
||||
|
|
|
@ -136,13 +136,13 @@ function loadSubscriptions() {
|
|||
if(videoList.length < 100){
|
||||
videoList.forEach((video) => {
|
||||
console.log('Getting all videos');
|
||||
displayVideos(video);
|
||||
displayVideo(video);
|
||||
});
|
||||
}
|
||||
else{
|
||||
console.log('Getting top 100 videos');
|
||||
for(let i = 0; i < 100; i++){
|
||||
displayVideos(videoList[i]);
|
||||
displayVideo(videoList[i]);
|
||||
}
|
||||
}
|
||||
stopLoadingAnimation()
|
||||
|
|
|
@ -17,10 +17,6 @@ along with FreeTube. If not, see <http://www.gnu.org/licenses/>.
|
|||
|
||||
|
||||
|
||||
/*
|
||||
* File for functions related to videos.
|
||||
*/
|
||||
|
||||
/**
|
||||
* Perform a search using the YouTube API. The search query is grabbed from the #search element.
|
||||
*
|
||||
|
@ -32,7 +28,6 @@ function search(nextPageToken = '') {
|
|||
const query = document.getElementById('search').value;
|
||||
|
||||
if (query === '') {
|
||||
showToast('Search Field empty. Please input a search term.');
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -44,7 +39,6 @@ function search(nextPageToken = '') {
|
|||
showToast('Fetching results. Please wait...');
|
||||
}
|
||||
|
||||
// Start API request
|
||||
youtubeAPI('search', {
|
||||
q: query,
|
||||
part: 'id, snippet',
|
||||
|
@ -52,12 +46,11 @@ function search(nextPageToken = '') {
|
|||
pageToken: nextPageToken,
|
||||
maxResults: 25,
|
||||
}, function (data){
|
||||
console.log(data);
|
||||
if (nextPageToken === '') {
|
||||
createVideoListContainer('Search Results:');
|
||||
createVideoListContainer('Search results:');
|
||||
stopLoadingAnimation();
|
||||
}
|
||||
data.items.forEach(displayVideos);
|
||||
data.items.forEach(displayVideo);
|
||||
addNextPage(data.nextPageToken);
|
||||
})
|
||||
}
|
||||
|
@ -71,47 +64,45 @@ function search(nextPageToken = '') {
|
|||
*
|
||||
* @return {Void}
|
||||
*/
|
||||
function displayVideos(video, listType = null) {
|
||||
function displayVideo(video, listType = null) {
|
||||
|
||||
const videoSnippet = video['snippet'];
|
||||
const videoSnippet = video.snippet;
|
||||
|
||||
// Grab the published date for the video and convert to a user readable state.
|
||||
const dateString = new Date(videoSnippet['publishedAt']);
|
||||
const dateString = new Date(videoSnippet.publishedAt);
|
||||
const publishedDate = dateFormat(dateString, "mmm dS, yyyy");
|
||||
let deleteHtml = '';
|
||||
let liveText = '';
|
||||
let videoId = video['id']['videoId'];
|
||||
let videoId = video.id.videoId;
|
||||
|
||||
const searchMenu = $('#videoListContainer').html();
|
||||
|
||||
// Include a remove icon in the list if the application is displaying the history list or saved videos.
|
||||
if (listType === 'saved') {
|
||||
videoId = video['id'];
|
||||
videoId = video.id;
|
||||
deleteHtml = '<i onclick="removeSavedVideo(\'' + videoId + '\'); showSavedVideos();" class="videoDelete fas fa-times"></i>';
|
||||
} else if (listType === 'history') {
|
||||
videoId = video['id'];
|
||||
videoId = video.id;
|
||||
deleteHtml = '<i onclick="removeFromHistory(\'' + videoId + '\'); showHistory()" class="videoDelete fas fa-times"></i>';
|
||||
}
|
||||
|
||||
let liveText = '';
|
||||
// Includes text if the video is live.
|
||||
if (videoSnippet['liveBroadcastContent'] === 'live') {
|
||||
if (videoSnippet.liveBroadcastContent === 'live') {
|
||||
liveText = 'LIVE NOW';
|
||||
}
|
||||
|
||||
// Grab the search template for the video.
|
||||
const videoListTemplate = require('./templates/videoList.html');
|
||||
|
||||
// Render / Manipulate the template. Replace variables with data from the video.
|
||||
mustache.parse(videoListTemplate);
|
||||
const rendered = mustache.render(videoListTemplate, {
|
||||
videoThumbnail: videoSnippet['thumbnails']['medium']['url'],
|
||||
videoTitle: videoSnippet['title'],
|
||||
channelName: videoSnippet['channelTitle'],
|
||||
videoDescription: videoSnippet['description'],
|
||||
videoId: videoId,
|
||||
videoThumbnail: videoSnippet.thumbnails.medium.url,
|
||||
videoTitle: videoSnippet.title,
|
||||
channelName: videoSnippet.channelTitle,
|
||||
videoDescription: videoSnippet.description,
|
||||
channelId: videoSnippet.channelId,
|
||||
publishedDate: publishedDate,
|
||||
liveText: liveText,
|
||||
videoId: videoId,
|
||||
channelId: videoSnippet['channelId'],
|
||||
deleteHtml: deleteHtml,
|
||||
});
|
||||
// Apply the render to the page
|
||||
|
@ -165,22 +156,16 @@ function showVideoRecommendations(videoId) {
|
|||
}, function (data){
|
||||
const recommendations = data.items;
|
||||
recommendations.forEach((data) => {
|
||||
const snippet = data['snippet'];
|
||||
const videoId = data['id']['videoId'];
|
||||
const videoTitle = snippet['title'];
|
||||
const channelName = snippet['channelTitle'];
|
||||
const videoThumbnail = snippet['thumbnails']['medium']['url'];
|
||||
const dateString = snippet['publishedAt'];
|
||||
const publishedDate = dateFormat(dateString, "mmm dS, yyyy");
|
||||
const snippet = data.snippet;
|
||||
|
||||
const recommTemplate = require('./templates/recommendations.html')
|
||||
mustache.parse(recommTemplate);
|
||||
const rendered = mustache.render(recommTemplate, {
|
||||
videoId: videoId,
|
||||
videoTitle: videoTitle,
|
||||
channelName: channelName,
|
||||
videoThumbnail: videoThumbnail,
|
||||
publishedDate: publishedDate,
|
||||
videoId: data.id.videoId,
|
||||
videoTitle: snippet.title,
|
||||
channelName: snippet.channelTitle,
|
||||
videoThumbnail: snippet.thumbnails.medium.url,
|
||||
publishedDate: dateFormat(snippet.publishedAt, "mmm dS, yyyy")
|
||||
});
|
||||
const recommendationHtml = $('#recommendations').html();
|
||||
$('#recommendations').html(recommendationHtml + rendered);
|
||||
|
@ -228,7 +213,6 @@ function showMostPopular() {
|
|||
// Get the date of 2 days ago.
|
||||
var d = new Date();
|
||||
d.setDate(d.getDate() - 2);
|
||||
console.log(d.toString());
|
||||
|
||||
// Grab all videos published 2 days ago and after and order them by view count.
|
||||
// These are the videos that are considered as 'most popular' and is how similar
|
||||
|
@ -243,7 +227,7 @@ function showMostPopular() {
|
|||
}, function (data){
|
||||
createVideoListContainer('Most Popular:');
|
||||
stopLoadingAnimation();
|
||||
data['items'].forEach(displayVideos);
|
||||
data.items.forEach(displayVideo);
|
||||
});
|
||||
}
|
||||
|
||||
|
@ -284,7 +268,6 @@ function getChannelAndPlayer(videoId) {
|
|||
resolve([embedHtml, data.items[0].snippet.channelId]);
|
||||
});
|
||||
});
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
@ -22,10 +22,10 @@ function youtubeAPI(resource, params, success) {
|
|||
}
|
||||
|
||||
/**
|
||||
* Use youtube-dl to get the info for a video.
|
||||
* Use youtube-dl to resolve a video.
|
||||
*
|
||||
* @param {string} videoId - The video Id to get info from.
|
||||
* @param {function} callback - The callback function when the call is finished.
|
||||
* @param {function} callback - The function called on success with the info.
|
||||
*
|
||||
* @return {Void}
|
||||
*/
|
||||
|
|
|
@ -1,7 +1,5 @@
|
|||
<h1 class='center'>FreeTube {{versionNumber}} Beta</h1>
|
||||
<br />
|
||||
<h2 class='center'>This software is FOSS and released under the <a href='https://www.gnu.org/licenses/quick-guide-gplv3.html'>GNU Public License v3</a></h2>
|
||||
<br />
|
||||
<p class='center'>
|
||||
Found a bug? Want to suggest a feature? Want to help out? Check out our <a href='https://github.com/FreeTubeApp/FreeTube'>GitHub</a> page. Pull requests are welcome.
|
||||
</p>
|
||||
<div class='center'>
|
||||
<h1>FreeTube {{versionNumber}} Beta</h1>
|
||||
<h2>This software is FOSS and released under the <a href='https://www.gnu.org/licenses/quick-guide-gplv3.html'>GNU Public License v3+</a>.</h2>
|
||||
Found a bug? Want to suggest a feature? Want to help out? Check out our <a href='https://github.com/FreeTubeApp/FreeTube'>GitHub</a> page. Pull requests are welcome.
|
||||
</div>
|
||||
|
|
|
@ -6,7 +6,7 @@
|
|||
<br />
|
||||
<span class='channelViewSubs'>{{subCount}} Subscribers</span>
|
||||
<div id='subscribeButton' class='channelSubButton' onclick='toggleSubscription("{{channelId}}");'>
|
||||
{{isSubscribed}}
|
||||
{{subButtonText}}
|
||||
</div>
|
||||
</div>
|
||||
<br />
|
||||
|
|
Loading…
Reference in New Issue