mirror of https://github.com/FreeTubeApp/FreeTube
Committing second batch of Vue.js implementation
This commit is contained in:
parent
97ade6e392
commit
979d2b85f7
|
@ -15,7 +15,7 @@
|
|||
</head>
|
||||
|
||||
<body>
|
||||
<div id='loading'>
|
||||
<div v-if='seen' id='loading'>
|
||||
<div class="spinner">
|
||||
<div class="double-bounce1"></div>
|
||||
<div class="double-bounce2"></div>
|
||||
|
@ -44,14 +44,14 @@
|
|||
<div class="sideNavContainer">
|
||||
<ul>
|
||||
<li v-on:click='subscriptions'><i class="fas fa-rss"></i> Subscriptions</li>
|
||||
<li onclick='showMostPopular()'><i class="fas fa-users"></i> Most Popular</li>
|
||||
<li onclick='showSavedVideos()'><i class="fas fa-star"></i> Saved</li>
|
||||
<li onclick='showHistory()'><i class="fas fa-history"></i> History</li>
|
||||
<li v-on:click='popular'><i class="fas fa-users"></i> Most Popular</li>
|
||||
<li v-on:click='saved'><i class="fas fa-star"></i> Saved</li>
|
||||
<li v-on:click='history'><i class="fas fa-history"></i> History</li>
|
||||
</ul>
|
||||
<hr />
|
||||
<ul>
|
||||
<li onclick='showSettings()'><i class="fas fa-sliders-h"></i> Settings</li>
|
||||
<li v-on:click='about' ><i class="fas fa-info-circle"></i> About</li>
|
||||
<li v-on:click='settings'><i class="fas fa-sliders-h"></i> Settings</li>
|
||||
<li v-on:click='about'><i class="fas fa-info-circle"></i> About</li>
|
||||
</ul>
|
||||
<hr />
|
||||
<ul id='subscriptions'>
|
||||
|
@ -59,18 +59,26 @@
|
|||
</div>
|
||||
</div>
|
||||
<div id="main">
|
||||
<div id='channelView'></div>
|
||||
<div id='mainHeaderView'></div>
|
||||
<div id='aboutView'></div>
|
||||
<div id='subscriptionView'></div>
|
||||
<div id='channelVideosView'></div>
|
||||
<div id='searchView'></div>
|
||||
<div id='subscriptionView'></div>
|
||||
<div id='popularView'></div>
|
||||
<div id='savedView'></div>
|
||||
<div id='historyView'></div>
|
||||
<div id='aboutView'></div>
|
||||
<div id='settingsView'></div>
|
||||
<div id='playerView'></div>
|
||||
</div>
|
||||
<div id='progressView'></div>
|
||||
</body>
|
||||
<script src="js/youtubeApi.js"></script>
|
||||
<script src="js/settings.js"></script>
|
||||
<script src="js/updates.js"></script>
|
||||
<script src="js/db.js"></script>
|
||||
<script src="js/layout.js"></script>
|
||||
<script src="js/templates.js"></script>
|
||||
<script src="js/settings.js"></script>
|
||||
<script src="js/videos.js"></script>
|
||||
<script src="js/player.js"></script>
|
||||
<script src="js/subscriptions.js"></script>
|
||||
|
|
|
@ -40,14 +40,18 @@ along with FreeTube. If not, see <http://www.gnu.org/licenses/>.
|
|||
* @return {Void}
|
||||
*/
|
||||
function goToChannel(channelId) {
|
||||
event.stopPropagation();
|
||||
clearMainContainer();
|
||||
startLoadingAnimation();
|
||||
//event.stopPropagation();
|
||||
//clearMainContainer();
|
||||
//startLoadingAnimation();
|
||||
|
||||
let subButtonText;
|
||||
headerView.title = 'Latest Uploads';
|
||||
hideViews();
|
||||
loadingView.seen = true;
|
||||
|
||||
//let subButtonText;
|
||||
// Setting subButtonText here as Mustache templates are logic-less.
|
||||
isSubscribed(channelId).then((subscribed) => {
|
||||
subButtonText = (subscribed ? "UNSUBSCRIBE" : "SUBSCRIBE");
|
||||
channelView.subButtonText = (subscribed ? "UNSUBSCRIBE" : "SUBSCRIBE");
|
||||
});
|
||||
|
||||
// Grab general channel information
|
||||
|
@ -57,7 +61,14 @@ function goToChannel(channelId) {
|
|||
}, (data) => {
|
||||
const channelData = data.items[0];
|
||||
|
||||
const channelViewTemplate = require('./templates/channelView.html');
|
||||
channelView.id = channelId;
|
||||
channelView.name = channelData.brandingSettings.channel.title;
|
||||
channelView.banner = channelData.brandingSettings.image.bannerImageUrl;
|
||||
channelView.icon = channelData.snippet.thumbnails.high.url;
|
||||
channelView.subCount = channelData.statistics.subscriberCount.toLocaleString(); //toLocaleString adds commas as thousands separators
|
||||
channelView.description = autolinker.link(channelData.brandingSettings.channel.description); //autolinker makes URLs clickable
|
||||
|
||||
/*const channelViewTemplate = require('./templates/channelView.html');
|
||||
mustache.parse(channelViewTemplate);
|
||||
const rendered = mustache.render(channelViewTemplate, {
|
||||
channelId: channelId,
|
||||
|
@ -69,7 +80,7 @@ function goToChannel(channelId) {
|
|||
subButtonText: subButtonText,
|
||||
});
|
||||
$('#main').html(rendered);
|
||||
stopLoadingAnimation();
|
||||
stopLoadingAnimation();*/
|
||||
|
||||
// Grab the channel's latest uploads. API forces a max of 50.
|
||||
youtubeAPI('search', {
|
||||
|
@ -83,8 +94,12 @@ function goToChannel(channelId) {
|
|||
let grabDuration = getDuration(data.items);
|
||||
|
||||
grabDuration.then((videoList) => {
|
||||
channelView.seen = true;
|
||||
channelVideosView.videoList = [];
|
||||
channelVideosView.seen = true;
|
||||
loadingView.seen = false;
|
||||
videoList.items.forEach((video) => {
|
||||
displayVideo(video);
|
||||
displayVideo(video, 'channel');
|
||||
});
|
||||
});
|
||||
});
|
||||
|
|
|
@ -54,8 +54,8 @@ function removeFromHistory(videoId){
|
|||
* @return {Void}
|
||||
*/
|
||||
function showHistory(){
|
||||
clearMainContainer();
|
||||
startLoadingAnimation();
|
||||
//clearMainContainer();
|
||||
//startLoadingAnimation();
|
||||
console.log('checking history');
|
||||
|
||||
let videoList = '';
|
||||
|
@ -80,15 +80,17 @@ function showHistory(){
|
|||
id: videoList,
|
||||
maxResults: 50,
|
||||
}, function (data) {
|
||||
createVideoListContainer('Watch History:');
|
||||
//createVideoListContainer('Watch History:');
|
||||
let grabDuration = getDuration(data.items);
|
||||
|
||||
grabDuration.then((videoList) => {
|
||||
historyView.videoList = [];
|
||||
loadingView.seen = false;
|
||||
videoList.items.forEach((video) => {
|
||||
displayVideo(video, 'history');
|
||||
});
|
||||
});
|
||||
stopLoadingAnimation()
|
||||
//stopLoadingAnimation()
|
||||
});
|
||||
});
|
||||
}
|
||||
|
|
|
@ -45,7 +45,6 @@ const fs = require('fs'); // Used to read files. Specifically in the settings pa
|
|||
const tor = require('tor-request');
|
||||
|
||||
let currentTheme = '';
|
||||
let apiKey;
|
||||
let useTor = false;
|
||||
let dialog = electron.remote.dialog; // Used for opening file browser to export / import subscriptions.
|
||||
let toastTimeout; // Timeout for toast notifications.
|
||||
|
@ -57,7 +56,7 @@ require.extensions['.html'] = function(module, filename) {
|
|||
|
||||
// Grabs the default settings from the settings database file. Makes defaults if
|
||||
// none are found.
|
||||
checkDefaultSettings();
|
||||
//checkDefaultSettings();
|
||||
|
||||
electron.ipcRenderer.on('ping', function(event, message) {
|
||||
console.log(message);
|
||||
|
|
|
@ -30,14 +30,18 @@ along with FreeTube. If not, see <http://www.gnu.org/licenses/>.
|
|||
*/
|
||||
function playVideo(videoId, videoThumbnail = '', useWindowPlayer = false) {
|
||||
if (useWindowPlayer === false){
|
||||
clearMainContainer();
|
||||
startLoadingAnimation();
|
||||
//clearMainContainer();
|
||||
//startLoadingAnimation();
|
||||
}
|
||||
else{
|
||||
showToast('Getting video information. Please wait...')
|
||||
}
|
||||
|
||||
let subscribeText = '';
|
||||
hideViews();
|
||||
playerView.videoId = videoId;
|
||||
playerView.embededHtml = "<iframe width='560' height='315' src='https://www.youtube-nocookie.com/embed/" + videoId + "?rel=0' frameborder='0' allow='autoplay; encrypted-media' allowfullscreen></iframe>";
|
||||
|
||||
/*let subscribeText = '';
|
||||
let savedText = '';
|
||||
let savedIconClass = '';
|
||||
let savedIconColor = '';
|
||||
|
@ -60,18 +64,18 @@ function playVideo(videoId, videoThumbnail = '', useWindowPlayer = false) {
|
|||
let videoLikes;
|
||||
let videoDislikes;
|
||||
let totalLikes;
|
||||
let likePercentage;
|
||||
let likePercentage;*/
|
||||
|
||||
const checkSavedVideo = videoIsSaved(videoId);
|
||||
|
||||
// Change the save button icon and text depending on if the user has saved the video or not.
|
||||
checkSavedVideo.then((results) => {
|
||||
if (results === false) {
|
||||
savedText = 'SAVE';
|
||||
savedIconClass = 'far unsaved';
|
||||
playerView.savedText = 'SAVE';
|
||||
playerView.savedIconType = 'far unsaved';
|
||||
} else {
|
||||
savedText = 'SAVED';
|
||||
savedIconClass = 'fas saved';
|
||||
playerView.savedText = 'SAVED';
|
||||
playerView.savedIconType = 'fas saved';
|
||||
}
|
||||
});
|
||||
|
||||
|
@ -82,10 +86,10 @@ function playVideo(videoId, videoThumbnail = '', useWindowPlayer = false) {
|
|||
console.log(data);
|
||||
|
||||
// Figure out the width for the like/dislike bar.
|
||||
videoLikes = data['items'][0]['statistics']['likeCount'];
|
||||
videoDislikes = data['items'][0]['statistics']['dislikeCount'];
|
||||
totalLikes = parseInt(videoLikes) + parseInt(videoDislikes);
|
||||
likePercentage = parseInt((videoLikes / totalLikes) * 100);
|
||||
playerView.videoLikes = data['items'][0]['statistics']['likeCount'];
|
||||
playerView.videoDislikes = data['items'][0]['statistics']['dislikeCount'];
|
||||
let totalLikes = parseInt(playerView.videoLikes) + parseInt(playerView.videoDislikes);
|
||||
playerView.likePercentage = parseInt((playerView.videoLikes / totalLikes) * 100);
|
||||
});
|
||||
|
||||
/*
|
||||
|
@ -94,62 +98,66 @@ function playVideo(videoId, videoThumbnail = '', useWindowPlayer = false) {
|
|||
youtubedlGetInfo(videoId, (info) => {
|
||||
console.log(info);
|
||||
|
||||
console.log(videoLikes);
|
||||
//console.log(videoLikes);
|
||||
|
||||
channelId = info['author']['id'];
|
||||
let channelThumbnail = info['author']['avatar'];
|
||||
playerView.videoTitle = info['title'];
|
||||
playerView.channelName = info['author']['name'];
|
||||
playerView.channelId = info['author']['id'];
|
||||
playerView.channelIcon = info['author']['avatar'];
|
||||
|
||||
let videoUrls = info['formats'];
|
||||
|
||||
// Add commas to the video view count.
|
||||
const videoViews = info['view_count'].toString().replace(/\B(?=(\d{3})+(?!\d))/g, ",");
|
||||
playerView.videoViews = info['view_count'].toString().replace(/\B(?=(\d{3})+(?!\d))/g, ",");
|
||||
|
||||
videoThumbnail = info['player_response']['videoDetails']['thumbnail']['thumbnails'][3]['url'];
|
||||
playerView.videoThumbnail = info['player_response']['videoDetails']['thumbnail']['thumbnails'][3]['url'];
|
||||
|
||||
// Format the date to a more readable format.
|
||||
let dateString = new Date(info['published']);
|
||||
dateString.setDate(dateString.getDate() + 1);
|
||||
const publishedDate = dateFormat(dateString, "mmm dS, yyyy");
|
||||
playerView.publishedDate = dateFormat(dateString, "mmm dS, yyyy");
|
||||
|
||||
let description = info['description'];
|
||||
// Adds clickable links to the description.
|
||||
description = autolinker.link(description);
|
||||
playerView.description = autolinker.link(description);
|
||||
|
||||
// Search through the returned object to get the 480p and 720p video URLs (If available)
|
||||
Object.keys(videoUrls).forEach((key) => {
|
||||
switch (videoUrls[key]['itag']) {
|
||||
case '18':
|
||||
video480p = decodeURIComponent(videoUrls[key]['url']);
|
||||
console.log(video480p);
|
||||
playerView.video480p = decodeURIComponent(videoUrls[key]['url']);
|
||||
//console.log(video480p);
|
||||
break;
|
||||
case '22':
|
||||
video720p = decodeURIComponent(videoUrls[key]['url']);
|
||||
console.log(video720p);
|
||||
playerView.video720p = decodeURIComponent(videoUrls[key]['url']);
|
||||
//console.log(video720p);
|
||||
break;
|
||||
}
|
||||
});
|
||||
|
||||
// Default to the embeded player if the URLs cannot be found.
|
||||
if (typeof(video720p) === 'undefined' && typeof(video480p) === 'undefined') {
|
||||
useEmbedPlayer = true;
|
||||
defaultQuality = 'EMBED';
|
||||
videoHtml = embedPlayer.replace(/\"\;/g, '"');
|
||||
if (typeof(playerView.video720p) === 'undefined' && typeof(playerView.video480p) === 'undefined') {
|
||||
//useEmbedPlayer = true;
|
||||
playerView.currentQuality = 'EMBED';
|
||||
playerView.videoUrl = embedPlayer.replace(/\"\;/g, '"');
|
||||
showToast('Unable to get video file. Reverting to embeded player.');
|
||||
} else if (typeof(video720p) === 'undefined' && typeof(video480p) !== 'undefined') {
|
||||
// Default to the 480p video if the 720p URL cannot be found.
|
||||
defaultUrl = video480p;
|
||||
defaultQuality = '480p';
|
||||
playerView.videoUrl = playerView.video480p;
|
||||
playerView.currentQuality = '480p';
|
||||
} else {
|
||||
// Default to the 720p video.
|
||||
defaultUrl = video720p;
|
||||
defaultQuality = '720p';
|
||||
playerView.videoUrl = playerView.video720p;
|
||||
playerView.currentQuality = '720p';
|
||||
// Force the embeded player if needed.
|
||||
//videoHtml = embedPlayer;
|
||||
}
|
||||
|
||||
let useEmbedPlayer = false;
|
||||
|
||||
if (!useEmbedPlayer) {
|
||||
//videoHtml = '<video class="videoPlayer" type="application/x-mpegURL" onmousemove="hideMouseTimeout()" onmouseleave="removeMouseTimeout()" controls="" src="' + defaultUrl + '" poster="' + videoThumbnail + '" autoplay>';
|
||||
|
||||
let videoHtml = '';
|
||||
|
||||
if (typeof(info.player_response.captions) === 'object') {
|
||||
if (typeof(info.player_response.captions.playerCaptionsTracklistRenderer.captionTracks) === 'object') {
|
||||
|
@ -168,28 +176,33 @@ function playVideo(videoId, videoThumbnail = '', useWindowPlayer = false) {
|
|||
}
|
||||
}
|
||||
|
||||
//videoHtml = videoHtml + '</video>';
|
||||
playerView.subtitleHtml = videoHtml;
|
||||
}
|
||||
|
||||
const checkSubscription = isSubscribed(channelId);
|
||||
const checkSubscription = isSubscribed(playerView.channelId);
|
||||
|
||||
// Change the subscribe button text depending on if the user has subscribed to the channel or not.
|
||||
|
||||
checkSubscription.then((results) => {
|
||||
const subscribeButton = document.getElementById('subscribeButton');
|
||||
|
||||
if (results === false) {
|
||||
if (subscribeButton != null) {
|
||||
subscribeButton.innerHTML = 'SUBSCRIBE';
|
||||
playerView.subscribedText = 'SUBSCRIBE';
|
||||
}
|
||||
} else {
|
||||
if (subscribeButton != null) {
|
||||
subscribeButton.innerHTML = 'UNSUBSCRIBE';
|
||||
playerView.subscribedText = 'UNSUBSCRIBE';
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
const playerTemplate = require('./templates/player.html')
|
||||
showVideoRecommendations(videoId);
|
||||
|
||||
loadingView.seen = false;
|
||||
playerView.seen = true;
|
||||
|
||||
addToHistory(videoId);
|
||||
|
||||
/*const playerTemplate = require('./templates/player.html')
|
||||
mustache.parse(playerTemplate);
|
||||
const rendered = mustache.render(playerTemplate, {
|
||||
videoQuality: defaultQuality,
|
||||
|
@ -253,14 +266,14 @@ function playVideo(videoId, videoThumbnail = '', useWindowPlayer = false) {
|
|||
textTracks[track].mode = 'hidden';
|
||||
});
|
||||
}
|
||||
}
|
||||
}*/
|
||||
|
||||
// Sometimes a video URL is found, but the video will not play. I believe the issue is
|
||||
// that the video has yet to render for that quality, as the video will be available at a later time.
|
||||
// This will check the URLs and switch video sources if there is an error.
|
||||
//checkVideoUrls(video480p, video720p);
|
||||
|
||||
window.setTimeout(checkVideoUrls, 5000, video480p, video720p);
|
||||
//window.setTimeout(checkVideoUrls, 5000, video480p, video720p);
|
||||
|
||||
});
|
||||
}
|
||||
|
@ -272,7 +285,7 @@ function playVideo(videoId, videoThumbnail = '', useWindowPlayer = false) {
|
|||
*
|
||||
* @return {Void}
|
||||
*/
|
||||
function openMiniPlayer(videoThumbnail) {
|
||||
function openMiniPlayer() {
|
||||
let lastTime;
|
||||
let videoHtml;
|
||||
|
||||
|
@ -299,7 +312,7 @@ function openMiniPlayer(videoThumbnail) {
|
|||
mustache.parse(template);
|
||||
const rendered = mustache.render(template, {
|
||||
videoHtml: videoHtml,
|
||||
videoThumbnail: videoThumbnail,
|
||||
videoThumbnail: playerView.thumbnail,
|
||||
startTime: lastTime,
|
||||
});
|
||||
// Render the template to the new browser window.
|
||||
|
|
|
@ -74,23 +74,15 @@ function toggleSavedVideo(videoId) {
|
|||
event.stopPropagation();
|
||||
|
||||
const checkIfSaved = videoIsSaved(videoId);
|
||||
const saveIcon = document.getElementById('saveIcon');
|
||||
const savedText = document.getElementById('savedText');
|
||||
|
||||
checkIfSaved.then((results) => {
|
||||
if (results === false) {
|
||||
savedText.innerHTML = 'SAVED';
|
||||
saveIcon.classList.remove('far');
|
||||
saveIcon.classList.remove('unsaved');
|
||||
saveIcon.classList.add('fas');
|
||||
saveIcon.classList.add('saved');
|
||||
playerView.savedText = 'SAVED';
|
||||
playerView.savedIconType = 'fas saved';
|
||||
addSavedVideo(videoId);
|
||||
} else {
|
||||
savedText.innerHTML = 'SAVE';
|
||||
saveIcon.classList.remove('fas');
|
||||
saveIcon.classList.remove('saved');
|
||||
saveIcon.classList.add('far');
|
||||
saveIcon.classList.add('unsaved');
|
||||
playerView.savedText = 'SAVE';
|
||||
playerView.savedIconType = 'far unsaved';
|
||||
removeSavedVideo(videoId);
|
||||
}
|
||||
});
|
||||
|
@ -121,8 +113,8 @@ function videoIsSaved(videoId) {
|
|||
* @return {Void}
|
||||
*/
|
||||
function showSavedVideos(){
|
||||
clearMainContainer();
|
||||
startLoadingAnimation();
|
||||
//clearMainContainer();
|
||||
//startLoadingAnimation();
|
||||
console.log('checking saved videos');
|
||||
|
||||
let videoList = '';
|
||||
|
@ -151,14 +143,16 @@ function showSavedVideos(){
|
|||
maxResults: 50,
|
||||
}, (data) => {
|
||||
// Render the videos to the screen
|
||||
createVideoListContainer('Saved Videos:');
|
||||
//createVideoListContainer('Saved Videos:');
|
||||
let grabDuration = getDuration(data.items);
|
||||
grabDuration.then((videoList) => {
|
||||
savedView.videoList = [];
|
||||
loadingView.seen = false;
|
||||
videoList.items.forEach((video) => {
|
||||
displayVideo(video, 'saved');
|
||||
});
|
||||
});
|
||||
stopLoadingAnimation();
|
||||
//stopLoadingAnimation();
|
||||
});
|
||||
});
|
||||
}
|
||||
|
|
|
@ -29,12 +29,12 @@ const apiKeyBank = ['AIzaSyC9E579nh_qqxg6BH4xIce3k_7a9mT4uQc', 'AIzaSyCKplYT6hZI
|
|||
*
|
||||
* @return {Void}
|
||||
*/
|
||||
function showSettings() {
|
||||
clearMainContainer();
|
||||
startLoadingAnimation();
|
||||
function updateSettingsView() {
|
||||
//clearMainContainer();
|
||||
//startLoadingAnimation();
|
||||
|
||||
let isChecked = '';
|
||||
let key = '';
|
||||
//let isChecked = '';
|
||||
//let key = '';
|
||||
|
||||
/*
|
||||
* Check the settings database for the user's current settings. This is so the
|
||||
|
@ -45,7 +45,7 @@ function showSettings() {
|
|||
switch (setting['_id']) {
|
||||
case 'apiKey':
|
||||
if (apiKeyBank.indexOf(setting['value']) == -1) {
|
||||
key = setting['value'];
|
||||
settingsView.apiKey = setting['value'];
|
||||
}
|
||||
break;
|
||||
case 'theme':
|
||||
|
@ -56,7 +56,7 @@ function showSettings() {
|
|||
});
|
||||
|
||||
// Grab the settings.html template to prepare for rendering
|
||||
const settingsTemplate = require('./templates/settings.html')
|
||||
/*const settingsTemplate = require('./templates/settings.html')
|
||||
mustache.parse(settingsTemplate);
|
||||
const rendered = mustache.render(settingsTemplate, {
|
||||
isChecked: isChecked,
|
||||
|
@ -64,19 +64,19 @@ function showSettings() {
|
|||
});
|
||||
// Render template to application
|
||||
$('#main').html(rendered);
|
||||
stopLoadingAnimation();
|
||||
stopLoadingAnimation();*/
|
||||
|
||||
// Check / uncheck the switch depending on the user's settings.
|
||||
if (currentTheme === 'light') {
|
||||
document.getElementById('themeSwitch').checked = false;
|
||||
settingsView.useTheme = false;
|
||||
} else {
|
||||
document.getElementById('themeSwitch').checked = true;
|
||||
settingsView.useTheme = true;
|
||||
}
|
||||
|
||||
if (useTor) {
|
||||
document.getElementById('torSwitch').checked = true;
|
||||
settingsView.useTor = true;
|
||||
} else {
|
||||
document.getElementById('torSwitch').checked = false;
|
||||
settingsView.useTor = false;
|
||||
}
|
||||
});
|
||||
}
|
||||
|
@ -89,12 +89,12 @@ function showSettings() {
|
|||
function checkDefaultSettings() {
|
||||
|
||||
// Grab a random API Key.
|
||||
apiKey = apiKeyBank[Math.floor(Math.random() * apiKeyBank.length)];
|
||||
settingsView.apiKey = apiKeyBank[Math.floor(Math.random() * apiKeyBank.length)];
|
||||
let newSetting;
|
||||
|
||||
let settingDefaults = {
|
||||
'theme': 'light',
|
||||
'apiKey': apiKey,
|
||||
'apiKey': settingsView.apiKey,
|
||||
'useTor': false
|
||||
};
|
||||
|
||||
|
@ -121,7 +121,7 @@ function checkDefaultSettings() {
|
|||
break;
|
||||
case 'apiKey':
|
||||
if (apiKeyBank.indexOf(docs[0]['value']) == -1) {
|
||||
apiKey = docs[0]['value'];
|
||||
settingsView.apiKey = docs[0]['value'];
|
||||
}
|
||||
break;
|
||||
case 'useTor':
|
||||
|
@ -146,7 +146,7 @@ function updateSettings() {
|
|||
let key = document.getElementById('api-key').value;
|
||||
let theme = 'light';
|
||||
|
||||
apiKey = apiKeyBank[Math.floor(Math.random() * apiKeyBank.length)];
|
||||
settingsView.apiKey = apiKeyBank[Math.floor(Math.random() * apiKeyBank.length)];
|
||||
|
||||
console.log(themeSwitch);
|
||||
|
||||
|
@ -188,7 +188,7 @@ function updateSettings() {
|
|||
settingsDb.update({
|
||||
_id: 'apiKey'
|
||||
}, {
|
||||
value: apiKey
|
||||
value: settingsView.apiKey
|
||||
}, {});
|
||||
}
|
||||
|
||||
|
@ -424,3 +424,5 @@ function clearFile(type, showMessage = true){
|
|||
}
|
||||
})
|
||||
}
|
||||
|
||||
checkDefaultSettings();
|
||||
|
|
|
@ -21,6 +21,9 @@ along with FreeTube. If not, see <http://www.gnu.org/licenses/>.
|
|||
* File for all functions related to subscriptions.
|
||||
*/
|
||||
|
||||
let subscriptionTimer;
|
||||
let checkSubscriptions = true;
|
||||
|
||||
/**
|
||||
* Add a channel to the user's subscription database.
|
||||
*
|
||||
|
@ -78,8 +81,16 @@ function removeSubscription(channelId) {
|
|||
* @return {Void}
|
||||
*/
|
||||
function loadSubscriptions() {
|
||||
showToast('Getting Subscriptions. Please wait...');
|
||||
const loading = document.getElementById('loading');
|
||||
if (checkSubscriptions === false){
|
||||
console.log('Will not load subscriptions. Timer still on.');
|
||||
return;
|
||||
}
|
||||
else{
|
||||
showToast('Refreshing Subscription List. Please wait...');
|
||||
checkSubscriptions = false;
|
||||
}
|
||||
|
||||
//const loading = document.getElementById('loading');
|
||||
|
||||
//startLoadingAnimation()
|
||||
|
||||
|
@ -87,7 +98,6 @@ function loadSubscriptions() {
|
|||
|
||||
const subscriptions = returnSubscriptions();
|
||||
|
||||
// Welcome to callback hell, we hope you enjoy your stay.
|
||||
subscriptions.then((results) => {
|
||||
let channelId = '';
|
||||
let videoList = [];
|
||||
|
@ -108,6 +118,7 @@ function loadSubscriptions() {
|
|||
console.log(data);
|
||||
videoList = videoList.concat(data.items);
|
||||
counter++;
|
||||
progressView.progressWidth = (counter / results.length) * 100;
|
||||
if (counter === results.length) {
|
||||
videoList.sort((a, b) => {
|
||||
const date1 = Date.parse(a.snippet.publishedAt);
|
||||
|
@ -129,7 +140,9 @@ function loadSubscriptions() {
|
|||
list.items.forEach((video) => {
|
||||
displayVideo(video, 'subscriptions');
|
||||
});
|
||||
stopLoadingAnimation();
|
||||
loadingView.seen = false;
|
||||
progressView.seen = false;
|
||||
progressView.progressWidth = 0;
|
||||
});
|
||||
} else {
|
||||
console.log(videoList);
|
||||
|
@ -147,7 +160,12 @@ function loadSubscriptions() {
|
|||
finishedList.forEach((video) => {
|
||||
displayVideo(video, 'subscriptions');
|
||||
});
|
||||
stopLoadingAnimation();
|
||||
loadingView.seen = false;
|
||||
progressView.seen = false;
|
||||
progressView.progressWidth = 0;
|
||||
subscriptionTimer = window.setTimeout(() => {
|
||||
checkSubscriptions = true;
|
||||
}, 60000);
|
||||
});
|
||||
});
|
||||
}
|
||||
|
@ -160,7 +178,7 @@ function loadSubscriptions() {
|
|||
} else {
|
||||
// User has no subscriptions. Display message.
|
||||
const container = document.getElementById('main');
|
||||
stopLoadingAnimation();
|
||||
//stopLoadingAnimation();
|
||||
|
||||
container.innerHTML = `<h2 class="message">Your Subscription list is currently empty. Start adding subscriptions
|
||||
to see them here.<br /><br /><i class="far fa-frown" style="font-size: 200px"></i></h2>`;
|
||||
|
|
|
@ -19,22 +19,88 @@ import Vue from './js/vue.js';
|
|||
|
||||
const mainHeaderTemplate = require('./templates/mainHeader.html');
|
||||
const aboutTemplate = require('./templates/about.html');
|
||||
const settingsTemplate = require('./templates/settings.html');
|
||||
const videoListTemplate = require('./templates/videoTemplate.html');
|
||||
const nextPageTemplate = require('./templates/searchNextPage.html');
|
||||
const playerTemplate = require('./templates/player.html');
|
||||
const channelTemplate = require('./templates/channelView.html');
|
||||
const progressViewTemplate = require('./templates/progressView.html');
|
||||
|
||||
/*
|
||||
* Progress view
|
||||
*
|
||||
* Shows progress bar on bottom of application.
|
||||
*
|
||||
* seen: Toggles visibility of view
|
||||
* progressWidth: sets width of the progress bar
|
||||
*/
|
||||
let progressView = new Vue({
|
||||
el: '#progressView',
|
||||
data: {
|
||||
seen: true,
|
||||
progressWidth: 0
|
||||
},
|
||||
template: progressViewTemplate
|
||||
});
|
||||
|
||||
let loadingView = new Vue({
|
||||
el: '#loading',
|
||||
data: {
|
||||
seen: false
|
||||
}
|
||||
});
|
||||
|
||||
let sideNavBar = new Vue({
|
||||
el: '#sideNav',
|
||||
methods: {
|
||||
about: (event) => {
|
||||
hideViews();
|
||||
aboutView.seen = true;
|
||||
},
|
||||
subscriptions: (event) => {
|
||||
hideViews();
|
||||
if(subscriptionView.videoList.length === 0){
|
||||
loadingView.seen = true;
|
||||
}
|
||||
headerView.seen = true;
|
||||
headerView.title = 'Latest Subscriptions';
|
||||
subscriptionView.seen = true;
|
||||
loadSubscriptions();
|
||||
},
|
||||
popular: (event) => {
|
||||
hideViews();
|
||||
if(popularView.videoList.length === 0){
|
||||
loadingView.seen = true;
|
||||
}
|
||||
headerView.seen = true;
|
||||
headerView.title = 'Most Popular';
|
||||
popularView.seen = true;
|
||||
showMostPopular();
|
||||
},
|
||||
saved: (event) => {
|
||||
hideViews();
|
||||
if(savedView.videoList.length === 0){
|
||||
loadingView.seen = true;
|
||||
}
|
||||
headerView.seen = true;
|
||||
headerView.title = 'Saved Videos';
|
||||
savedView.seen = true;
|
||||
showSavedVideos();
|
||||
},
|
||||
history: (event) => {
|
||||
hideViews();
|
||||
if(historyView.videoList.length === 0){
|
||||
loadingView.seen = true;
|
||||
}
|
||||
headerView.seen = true;
|
||||
headerView.title = 'Video History';
|
||||
historyView.seen = true;
|
||||
showHistory();
|
||||
},
|
||||
settings: (event) => {
|
||||
hideViews();
|
||||
settingsView.seen = true;
|
||||
updateSettingsView();
|
||||
},
|
||||
about: (event) => {
|
||||
hideViews();
|
||||
aboutView.seen = true;
|
||||
}
|
||||
}
|
||||
});
|
||||
|
@ -57,33 +123,68 @@ let subscriptionView = new Vue({
|
|||
},
|
||||
methods: {
|
||||
play: (videoId) => {
|
||||
loadingView.seen = true;
|
||||
playVideo(videoId);
|
||||
},
|
||||
channel: (channelId) => {
|
||||
goToChannel(channelId)
|
||||
goToChannel(channelId);
|
||||
}
|
||||
},
|
||||
template: videoListTemplate
|
||||
});
|
||||
|
||||
let searchView = new Vue({
|
||||
el: '#searchView',
|
||||
let popularView = new Vue({
|
||||
el: '#popularView',
|
||||
data: {
|
||||
seen: false,
|
||||
isSearch: true,
|
||||
nextPageToken: '',
|
||||
isSearch: false,
|
||||
videoList: []
|
||||
},
|
||||
methods: {
|
||||
play: (videoId) => {
|
||||
loadingView.seen = true;
|
||||
playVideo(videoId);
|
||||
},
|
||||
channel: (channelId) => {
|
||||
goToChannel(channelId)
|
||||
goToChannel(channelId);
|
||||
}
|
||||
},
|
||||
template: videoListTemplate
|
||||
});
|
||||
|
||||
let savedView = new Vue({
|
||||
el: '#savedView',
|
||||
data: {
|
||||
seen: false,
|
||||
isSearch: false,
|
||||
videoList: []
|
||||
},
|
||||
methods: {
|
||||
play: (videoId) => {
|
||||
loadingView.seen = true;
|
||||
playVideo(videoId);
|
||||
},
|
||||
nextPage: (nextPageToken) => {
|
||||
console.log(searchView.nextPageToken);
|
||||
search(searchView.nextPageToken);
|
||||
channel: (channelId) => {
|
||||
goToChannel(channelId);
|
||||
}
|
||||
},
|
||||
template: videoListTemplate
|
||||
});
|
||||
|
||||
let historyView = new Vue({
|
||||
el: '#historyView',
|
||||
data: {
|
||||
seen: false,
|
||||
isSearch: false,
|
||||
videoList: []
|
||||
},
|
||||
methods: {
|
||||
play: (videoId) => {
|
||||
loadingView.seen = true;
|
||||
playVideo(videoId);
|
||||
},
|
||||
channel: (channelId) => {
|
||||
goToChannel(channelId);
|
||||
}
|
||||
},
|
||||
template: videoListTemplate
|
||||
|
@ -98,9 +199,145 @@ let aboutView = new Vue({
|
|||
template: aboutTemplate
|
||||
});
|
||||
|
||||
let settingsView = new Vue({
|
||||
el: '#settingsView',
|
||||
data: {
|
||||
seen: false,
|
||||
useTheme: false,
|
||||
useTor: false,
|
||||
apiKey: ''
|
||||
},
|
||||
template: settingsTemplate
|
||||
});
|
||||
|
||||
let searchView = new Vue({
|
||||
el: '#searchView',
|
||||
data: {
|
||||
seen: false,
|
||||
isSearch: true,
|
||||
nextPageToken: '',
|
||||
videoList: []
|
||||
},
|
||||
methods: {
|
||||
play: (videoId) => {
|
||||
loadingView.seen = true;
|
||||
playVideo(videoId);
|
||||
},
|
||||
channel: (channelId) => {
|
||||
goToChannel(channelId);
|
||||
},
|
||||
nextPage: (nextPageToken) => {
|
||||
console.log(searchView.nextPageToken);
|
||||
search(searchView.nextPageToken);
|
||||
}
|
||||
},
|
||||
template: videoListTemplate
|
||||
});
|
||||
|
||||
let channelView = new Vue({
|
||||
el: '#channelView',
|
||||
data: {
|
||||
seen: false,
|
||||
id: '',
|
||||
name: '',
|
||||
icon: '',
|
||||
baner: '',
|
||||
subCount: '',
|
||||
subButtonText: '',
|
||||
description: ''
|
||||
},
|
||||
methods: {
|
||||
subscription: (channelId) => {
|
||||
toggleSubscription(channelId);
|
||||
}
|
||||
},
|
||||
template: channelTemplate
|
||||
});
|
||||
|
||||
let channelVideosView = new Vue({
|
||||
el: '#channelVideosView',
|
||||
data: {
|
||||
seen: false,
|
||||
isSearch: false,
|
||||
videoList: []
|
||||
},
|
||||
method: {
|
||||
play: (videoId) => {
|
||||
loadingView.seen = true;
|
||||
playVideo(videoId);
|
||||
},
|
||||
channel: (channelId) => {
|
||||
goToChannel(channelId);
|
||||
}
|
||||
},
|
||||
template: videoListTemplate
|
||||
});
|
||||
|
||||
let playerView = new Vue({
|
||||
el: '#playerView',
|
||||
data: {
|
||||
seen: false,
|
||||
publishedDate: '',
|
||||
videoUrl: '',
|
||||
videoId: '',
|
||||
channelId: '',
|
||||
channelIcon: '',
|
||||
channelName: '',
|
||||
subscribedText: '',
|
||||
savedText: '',
|
||||
savedIconType: 'far',
|
||||
description: '',
|
||||
videoThumbnail: '',
|
||||
subtitleHtml: '',
|
||||
currentQuality: '',
|
||||
video480p: '',
|
||||
video720p: '',
|
||||
embededHtml: '',
|
||||
currentSpeed: 1,
|
||||
videoTitle: '',
|
||||
videoViews: '',
|
||||
likePercentage: 0,
|
||||
videoLikes: 0,
|
||||
videoDislikes: 0,
|
||||
recommendedVideoList: []
|
||||
},
|
||||
methods: {
|
||||
channel: (channelId) => {
|
||||
goToChannel(channelId);
|
||||
},
|
||||
subscription: (videoId) => {
|
||||
toggleSubscription(videoId);
|
||||
},
|
||||
quality: (url, qualityText) => {
|
||||
console.log(url);
|
||||
console.log(qualityText);
|
||||
},
|
||||
copy: (site, videoId) => {
|
||||
const url = 'https://' + site + '.com/watch?v=' + videoId;
|
||||
clipboard.writeText(url);
|
||||
showToast('URL has been copied to the clipboard');
|
||||
},
|
||||
save: (videoId) => {
|
||||
toggleSavedVideo(videoId);
|
||||
},
|
||||
play: (videoId) => {
|
||||
loadingView.seen = true;
|
||||
playVideo(videoId);
|
||||
}
|
||||
},
|
||||
template: playerTemplate
|
||||
});
|
||||
|
||||
function hideViews(){
|
||||
subscriptionView.seen = false;
|
||||
aboutView.seen = false;
|
||||
headerView.seen = false;
|
||||
searchView.seen = false;
|
||||
settingsView.seen = false;
|
||||
popularView.seen = false;
|
||||
savedView.seen = false;
|
||||
historyView.seen = false;
|
||||
playerView.seen = false;
|
||||
channelView.seen = false;
|
||||
channelVideosView.seen = false;
|
||||
}
|
||||
|
|
|
@ -188,6 +188,18 @@ function displayVideo(videoData, listType = '') {
|
|||
case 'search':
|
||||
searchView.videoList = searchView.videoList.concat(video);
|
||||
break;
|
||||
case 'popular':
|
||||
popularView.videoList = popularView.videoList.concat(video);
|
||||
break;
|
||||
case 'saved':
|
||||
savedView.videoList = savedView.videoList.concat(video);
|
||||
break;
|
||||
case 'history':
|
||||
historyView.videoList = historyView.videoList.concat(video);
|
||||
break;
|
||||
case 'channel':
|
||||
channelVideosView.videoList = channelVideosView.videoList.concat(video);
|
||||
break;
|
||||
}
|
||||
|
||||
|
||||
|
@ -347,6 +359,8 @@ function addNextPage(nextPageToken) {
|
|||
* @param {string} videoId - The video ID of the video to get recommendations from.
|
||||
*/
|
||||
function showVideoRecommendations(videoId) {
|
||||
playerView.recommendedVideoList = [];
|
||||
|
||||
youtubeAPI('search', {
|
||||
part: 'id',
|
||||
type: 'video',
|
||||
|
@ -356,10 +370,18 @@ function showVideoRecommendations(videoId) {
|
|||
let grabDuration = getDuration(data.items);
|
||||
grabDuration.then((videoList) => {
|
||||
videoList.items.forEach((video) => {
|
||||
let data = {}
|
||||
const snippet = video.snippet;
|
||||
const videoDuration = parseVideoDuration(video.contentDetails.duration);
|
||||
|
||||
const recommTemplate = require('./templates/recommendations.html')
|
||||
data.duration = parseVideoDuration(video.contentDetails.duration);
|
||||
data.id = video.id;
|
||||
data.title = snippet.title;
|
||||
data.channelName = snippet.channelTitle;
|
||||
data.thumbnail = snippet.thumbnails.medium.url;
|
||||
data.publishedDate = dateFormat(snippet.publishedAt, "mmm dS, yyyy");
|
||||
|
||||
playerView.recommendedVideoList = playerView.recommendedVideoList.concat(data);
|
||||
/*const recommTemplate = require('./templates/recommendations.html')
|
||||
mustache.parse(recommTemplate);
|
||||
const rendered = mustache.render(recommTemplate, {
|
||||
videoId: video.id,
|
||||
|
@ -370,7 +392,7 @@ function showVideoRecommendations(videoId) {
|
|||
publishedDate: dateFormat(snippet.publishedAt, "mmm dS, yyyy")
|
||||
});
|
||||
const recommendationHtml = $('#recommendations').html();
|
||||
$('#recommendations').html(recommendationHtml + rendered);
|
||||
$('#recommendations').html(recommendationHtml + rendered);*/
|
||||
});
|
||||
});
|
||||
});
|
||||
|
@ -465,8 +487,8 @@ function parseVideoDuration(durationString) {
|
|||
* @return {Void}
|
||||
*/
|
||||
function showMostPopular() {
|
||||
clearMainContainer();
|
||||
startLoadingAnimation();
|
||||
//clearMainContainer();
|
||||
//startLoadingAnimation();
|
||||
|
||||
// Get the date of 2 days ago.
|
||||
var d = new Date();
|
||||
|
@ -483,15 +505,19 @@ function showMostPopular() {
|
|||
publishedAfter: d.toISOString(),
|
||||
maxResults: 50,
|
||||
}, function(data) {
|
||||
createVideoListContainer('Most Popular:');
|
||||
//createVideoListContainer('Most Popular:');
|
||||
console.log(data);
|
||||
let grabDuration = getDuration(data.items);
|
||||
|
||||
grabDuration.then((videoList) => {
|
||||
console.log(videoList);
|
||||
videoList.items.forEach(displayVideo);
|
||||
popularView.videoList = [];
|
||||
loadingView.seen = false;
|
||||
videoList.items.forEach((video) => {
|
||||
displayVideo(video, 'popular');
|
||||
});
|
||||
});
|
||||
stopLoadingAnimation();
|
||||
//stopLoadingAnimation();
|
||||
});
|
||||
}
|
||||
|
||||
|
|
|
@ -9,7 +9,7 @@
|
|||
*/
|
||||
|
||||
function youtubeAPI(resource, params, success) {
|
||||
params.key = apiKey;
|
||||
params.key = settingsView.apiKey;
|
||||
|
||||
if (useTor) {
|
||||
tor.request('https://www.googleapis.com/youtube/v3/' + resource + '?' + $.param(params), function(err, res, body) {
|
||||
|
|
|
@ -25,6 +25,16 @@ a {
|
|||
color: #2196F3;
|
||||
}
|
||||
|
||||
#progressBar{
|
||||
height: 3px;
|
||||
background-color: #f44336;
|
||||
display: block;
|
||||
position: absolute;
|
||||
bottom: 0;
|
||||
left: 0;
|
||||
z-index: 1;
|
||||
}
|
||||
|
||||
.center {
|
||||
text-align: center;
|
||||
margin: 0 auto;
|
||||
|
@ -176,7 +186,6 @@ a {
|
|||
left: 5;
|
||||
bottom: 0;
|
||||
right: 0;
|
||||
display: none;
|
||||
}
|
||||
|
||||
.settingsInput {
|
||||
|
|
|
@ -1,21 +1,20 @@
|
|||
<img class='channelViewBanner' src='{{channelBanner}}' />
|
||||
<br />
|
||||
<div class='channelViewTitle'>
|
||||
<img class='channelViewImage' src='{{channelImage}}' />
|
||||
<span class='channelViewName'>{{channelName}}</span>
|
||||
<div v-if='seen'>
|
||||
<img class='channelViewBanner' :src='banner' />
|
||||
<br />
|
||||
<span class='channelViewSubs'>{{subCount}} Subscribers</span>
|
||||
<div id='subscribeButton' class='channelSubButton' onclick='toggleSubscription("{{channelId}}");'>
|
||||
{{subButtonText}}
|
||||
<div class='channelViewTitle'>
|
||||
<img class='channelViewImage' :src='icon' />
|
||||
<span class='channelViewName'>{{name}}</span>
|
||||
<br />
|
||||
<span class='channelViewSubs'>{{subCount}} Subscribers</span>
|
||||
<div id='subscribeButton' class='channelSubButton' v-on:click='subscription(channelId);'>
|
||||
{{subButtonText}}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<br />
|
||||
<hr />
|
||||
<div class='channelViewDescription'>
|
||||
{{{channelDescription}}}
|
||||
</div>
|
||||
<br />
|
||||
<hr />
|
||||
<div id='videoListContainer'>
|
||||
<h2>Latest Uploads</h2>
|
||||
<br />
|
||||
<hr />
|
||||
<div class='channelViewDescription'>
|
||||
<span v-html='description'></span>
|
||||
</div>
|
||||
<br />
|
||||
<hr />
|
||||
</div>
|
||||
|
|
|
@ -1,82 +1,95 @@
|
|||
<video class="videoPlayer" type="application/x-mpegURL" onmousemove="hideMouseTimeout()" onmouseleave="removeMouseTimeout()" controls="" src="{{defaultUrl}}" poster="{{videoThumbnail}}" autoplay>
|
||||
{{{subtitleHtml}}}
|
||||
</video>
|
||||
<div class='statistics'>
|
||||
<div class='smallButton' onclick="openMiniPlayer('{{videoThumbnail}}')">
|
||||
MINI PLAYER <i class="fas fa-external-link-alt"></i>
|
||||
</div>
|
||||
<div class='smallButton videoQuality'>
|
||||
<span id='currentQuality'>{{videoQuality}}</span> <i class="fas fa-angle-down"></i>
|
||||
<div class='qualityTypes'>
|
||||
<ul>
|
||||
<li id='quality480p' onclick='changeQuality("{{video480p}}", "480p")'>480p</li>
|
||||
<li id='quality720p' onclick='changeQuality("{{video720p}}", "720p")'>720p</li>
|
||||
<li id='qualityEmbed' onclick='changeQuality("{{embedPlayer}}", "EMBED", true)'>EMBED</li>
|
||||
</ul>
|
||||
<div v-if='seen'>
|
||||
<video class="videoPlayer" type="application/x-mpegURL" onmousemove="hideMouseTimeout()" onmouseleave="removeMouseTimeout()" controls="" :src='videoUrl' :poster="videoThumbnail" v-html="subtitleHtml" autoplay>
|
||||
</video>
|
||||
<div class='statistics'>
|
||||
<div onclick='openMiniPlayer()' class='smallButton' >
|
||||
MINI PLAYER <i class="fas fa-external-link-alt"></i>
|
||||
</div>
|
||||
</div>
|
||||
<div class='smallButton videoSpeed'>
|
||||
<span id='currentSpeed'>1</span>x <i class="fas fa-angle-down"></i>
|
||||
<div class='speedTypes'>
|
||||
<ul>
|
||||
<li onclick='changeVideoSpeed(0.25)'>0.25x</li>
|
||||
<li onclick='changeVideoSpeed(0.5)'>0.5x</li>
|
||||
<li onclick='changeVideoSpeed(0.75)'>0.75x</li>
|
||||
<li onclick='changeVideoSpeed(1)'>1x</li>
|
||||
<li onclick='changeVideoSpeed(1.25)'>1.25x</li>
|
||||
<li onclick='changeVideoSpeed(1.5)'>1.5x</li>
|
||||
<li onclick='changeVideoSpeed(1.75)'>1.75x</li>
|
||||
<li onclick='changeVideoSpeed(2)'>2x</li>
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
<div onclick='toggleSavedVideo("{{videoId}}")' class='smallButton'>
|
||||
<i id='saveIcon' style='color: {{savedIconColor}};' class="{{savedIconClass}} fa-star"></i> <span id='savedText'>{{savedText}}</span>
|
||||
</div>
|
||||
<div class='smallButton' onclick='copyLink("youtube", "{{videoId}}")'>
|
||||
COPY YOUTUBE LINK
|
||||
</div>
|
||||
<a href='https://youtube.com/watch?v={{videoId}}'>
|
||||
<div class='smallButton'>
|
||||
OPEN IN YOUTUBE
|
||||
</div>
|
||||
</a>
|
||||
<div class='smallButton' onclick='copyLink("hooktube", "{{videoId}}")'>
|
||||
COPY HOOKTUBE LINK
|
||||
</div>
|
||||
<a href='https://hooktube.com/watch?v={{videoId}}'>
|
||||
<div class='smallButton'>
|
||||
OPEN IN HOOKTUBE
|
||||
</div>
|
||||
</a>
|
||||
<br />
|
||||
<p class='title'>{{videoTitle}}</p>
|
||||
<p class='views'>{{videoViews}} views</p>
|
||||
<div class='likeContainer'>
|
||||
<div class='dislikeBar'>
|
||||
<div class='likeBar' style='width: {{likePercentage}}%;'>
|
||||
<div class='smallButton videoQuality'>
|
||||
<span id='currentQuality'>{{currentQuality}}</span> <i class="fas fa-angle-down"></i>
|
||||
<div class='qualityTypes'>
|
||||
<ul>
|
||||
<li id='quality480p' v-on:click='quality(video480p, "480p")'>480p</li>
|
||||
<li id='quality720p' v-on:click='quality(video720p, "720p")'>720p</li>
|
||||
<li id='qualityEmbed' v-on:click='quality(embededPlayer, "EMBED")'>EMBED</li>
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
<span class='likes'><i class="fas fa-thumbs-up"></i> {{videoLikes}}</span><span class='dislikes'><i class="fas fa-thumbs-down"></i> {{videoDislikes}}</span>
|
||||
<div class='smallButton videoSpeed'>
|
||||
<span id='currentSpeed'>{{currentSpeed}}</span>x <i class="fas fa-angle-down"></i>
|
||||
<div class='speedTypes'>
|
||||
<ul>
|
||||
<li onclick='changeVideoSpeed(0.25)'>0.25x</li>
|
||||
<li onclick='changeVideoSpeed(0.5)'>0.5x</li>
|
||||
<li onclick='changeVideoSpeed(0.75)'>0.75x</li>
|
||||
<li onclick='changeVideoSpeed(1)'>1x</li>
|
||||
<li onclick='changeVideoSpeed(1.25)'>1.25x</li>
|
||||
<li onclick='changeVideoSpeed(1.5)'>1.5x</li>
|
||||
<li onclick='changeVideoSpeed(1.75)'>1.75x</li>
|
||||
<li onclick='changeVideoSpeed(2)'>2x</li>
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
<div class='smallButton' v-on:click='save(videoId)'>
|
||||
<i id='saveIcon' :class='savedIconType' class="fa-star"></i> <span id='savedText'>{{savedText}}</span>
|
||||
</div>
|
||||
<div class='smallButton' v-on:click='copy("youtube", videoId)'>
|
||||
COPY YOUTUBE LINK
|
||||
</div>
|
||||
<a :href='"https://youtube.com/watch?v=" + videoId'>
|
||||
<div class='smallButton'>
|
||||
OPEN IN YOUTUBE
|
||||
</div>
|
||||
</a>
|
||||
<div class='smallButton' v-on:click='copy("hooktube", videoId)'>
|
||||
COPY HOOKTUBE LINK
|
||||
</div>
|
||||
<a :href='"https://hooktube.com/watch?v=" + videoId'>
|
||||
<div class='smallButton'>
|
||||
OPEN IN HOOKTUBE
|
||||
</div>
|
||||
</a>
|
||||
<br />
|
||||
<p class='title'>{{videoTitle}}</p>
|
||||
<p class='views'>{{videoViews}} views</p>
|
||||
<div class='likeContainer'>
|
||||
<div class='dislikeBar'>
|
||||
<div class='likeBar' :style='{width: likePercentage + "%"}'>
|
||||
</div>
|
||||
</div>
|
||||
<span class='likes'><i class="fas fa-thumbs-up"></i> {{videoLikes}}</span><span class='dislikes'><i class="fas fa-thumbs-down"></i> {{videoDislikes}}</span>
|
||||
</div>
|
||||
</div>
|
||||
<div class="details">
|
||||
<img id='channelIcon' v-on:click='channel(channelId)' :src="channelIcon" />
|
||||
<p id='channelName' v-on:click='channel(channelId)'>{{channelName}}</p>
|
||||
<p id='publishDate'>Published on {{publishedDate}}</p>
|
||||
<div id='subscribeButton' class='playerSubButton' v-on:click='subscription(channelId)'>{{subscribedText}}</div>
|
||||
<br /><br />
|
||||
<div id='description'>
|
||||
<span v-html="description"></span>
|
||||
</div>
|
||||
</div>
|
||||
<div id='showComments'>
|
||||
Show Comments <i class="far fa-comments"></i> (Max of 100)
|
||||
</div>
|
||||
|
||||
<div id='comments' :data-video-id="videoId">
|
||||
</div>
|
||||
|
||||
<div id='recommendations'>
|
||||
<strong>Recommendations</strong>
|
||||
<div v-for='video in recommendedVideoList'>
|
||||
<div class='recommendVideo' v-on:click='play(video.id)'>
|
||||
<div class='recommendThumbnail'>
|
||||
<img :src='video.thumbnail'></img>
|
||||
<p v-on:click='play(video.id)' class='videoDuration'>{{video.duration}}</p>
|
||||
</div>
|
||||
<p class='recommendTitle'>{{video.title}}</p>
|
||||
<p class='recommendChannel'>{{video.channelName}}</p>
|
||||
<p class='recommendDate'>{{video.publishedDate}}</p>
|
||||
</div>
|
||||
<hr />
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="details">
|
||||
<img id='channelIcon' onclick='goToChannel("{{channelId}}")' src="{{channelIcon}}" />
|
||||
<p id='channelName' onclick='goToChannel("{{channelId}}")'>{{channelName}}</p>
|
||||
<p id='publishDate'>Published on {{publishedDate}}</p>
|
||||
<div id='subscribeButton' class='playerSubButton' onclick='toggleSubscription("{{channelId}}")'>{{isSubscribed}}</div>
|
||||
<br /><br />
|
||||
<div id='description'>
|
||||
{{{description}}}
|
||||
</div>
|
||||
</div>
|
||||
<div id='showComments'>
|
||||
Show Comments <i class="far fa-comments"></i> (Max of 100)
|
||||
</div>
|
||||
|
||||
<div id='comments' data-video-id="{{videoId}}">
|
||||
</div>
|
||||
|
||||
<div id='recommendations'>
|
||||
<strong>Recommendations</strong>
|
||||
</div>
|
||||
|
|
|
@ -0,0 +1,3 @@
|
|||
<div v-if='seen'>
|
||||
<span id='progressBar' :style='{ width: progressWidth + "%" }'></span>
|
||||
</div>
|
|
@ -1,35 +1,37 @@
|
|||
<h1 class="center">Settings</h1>
|
||||
<div class='center'>
|
||||
<input type='text' name='api-key' id='api-key' class='settingsInput' value='{{key}}' placeholder='API Key' />
|
||||
<br />
|
||||
<label for='api-key'>Set API Key: Leave blank to use default</label>
|
||||
<br />
|
||||
<input type="checkbox" id="themeSwitch" name="set-name" class="switch-input" onchange='toggleTheme(this)' {{isChecked}}>
|
||||
<label for="themeSwitch" class="switch-label">Use Dark Theme</label>
|
||||
<input type="checkbox" id="torSwitch" name="set-name" class="switch-input" {{isChecked}}>
|
||||
<label for="torSwitch" class="switch-label">Use Tor for API calls</label>
|
||||
</div>
|
||||
<div class='center'>
|
||||
<div onclick='importSubscriptions()' class='settingsButton'>
|
||||
IMPORT SUBSCRIPTIONS
|
||||
<div v-if="seen">
|
||||
<h1 class="center">Settings</h1>
|
||||
<div class='center'>
|
||||
<input type='text' name='api-key' id='api-key' class='settingsInput' :value='apiKey' placeholder='API Key' />
|
||||
<br />
|
||||
<label for='api-key'>Set API Key: Leave blank to use default</label>
|
||||
<br />
|
||||
<input type="checkbox" id="themeSwitch" name="set-name" class="switch-input" onchange='toggleTheme(this)' :checked='useTheme'>
|
||||
<label for="themeSwitch" class="switch-label">Use Dark Theme</label>
|
||||
<input type="checkbox" id="torSwitch" name="set-name" class="switch-input" :checked='useTor'>
|
||||
<label for="torSwitch" class="switch-label">Use Tor for API calls</label>
|
||||
</div>
|
||||
<div onclick='exportSubscriptions();' class='settingsButton'>
|
||||
EXPORT SUBSCRIPTIONS
|
||||
<div class='center'>
|
||||
<div onclick='importSubscriptions()' class='settingsButton'>
|
||||
IMPORT SUBSCRIPTIONS
|
||||
</div>
|
||||
<div onclick='exportSubscriptions();' class='settingsButton'>
|
||||
EXPORT SUBSCRIPTIONS
|
||||
</div>
|
||||
</div>
|
||||
<br /><br />
|
||||
<div class='center'>
|
||||
<div onclick='confirmFunction("Are you sure you want to delete your history?", clearFile, "history")' class='settingsButton'>
|
||||
CLEAR HISTORY
|
||||
</div>
|
||||
<div onclick='confirmFunction("Are you sure you want to remove all saved videos?", clearFile, "saved")' class='settingsButton'>
|
||||
CLEAR SAVED VIDEOS
|
||||
</div>
|
||||
<div onclick='confirmFunction("Are you sure you want to remove all subscriptions?", clearFile, "subscriptions")' class='settingsButton'>
|
||||
CLEAR SUBSCRIPTIONS
|
||||
</div>
|
||||
</div>
|
||||
<br /><br />
|
||||
<div onclick='updateSettings()' class='center settingsSubmit'>
|
||||
SAVE SETTINGS
|
||||
</div>
|
||||
</div>
|
||||
<br /><br />
|
||||
<div class='center'>
|
||||
<div onclick='confirmFunction("Are you sure you want to delete your history?", clearFile, "history")' class='settingsButton'>
|
||||
CLEAR HISTORY
|
||||
</div>
|
||||
<div onclick='confirmFunction("Are you sure you want to remove all saved videos?", clearFile, "saved")' class='settingsButton'>
|
||||
CLEAR SAVED VIDEOS
|
||||
</div>
|
||||
<div onclick='confirmFunction("Are you sure you want to remove all subscriptions?", clearFile, "subscriptions")' class='settingsButton'>
|
||||
CLEAR SUBSCRIPTIONS
|
||||
</div>
|
||||
</div>
|
||||
<br /><br />
|
||||
<div onclick='updateSettings()' class='center settingsSubmit'>
|
||||
SAVE SETTINGS
|
||||
</div>
|
||||
|
|
Loading…
Reference in New Issue