-
- - - - + - {
+ let parsedData = JSON.parse(data);
+
+ let newSubscription = {
+ channelId: parsedData.channelId,
+ channelName: parsedData.channelName,
+ channelThumbnail: parsedData.channelThumbnail,
+ }
+
+ if (typeof (parsedData.profile) !== 'undefined') {
+ let profileList = [];
+ parsedData.profile.forEach((profile) => {
+ if (profileList.indexOf(profile.value) !== -1) {
+ console.log('found duplicate');
+ return;
+ }
+
+ profileList.push(profile.value);
+
+ // Sometimes adding the same channel to the database too fast
+ // will duplicate the channel in the wrong profile. The wait
+ // time to add to the database is randomized to prevent this.
+ let randomNumber = Math.floor((Math.random() * 10000) + 1);
+ window.setTimeout(() => {
+ let existingProfileIndex = profileSelectView.profileList.findIndex(x => x.name === profile);
+ if (existingProfileIndex === -1) {
+ // User doesn't have this profile, let's create it.
+
+ let colorPaletteKeys = Object.keys(colorPalette);
+ let randomColor = colorPalette[colorPaletteKeys[colorPaletteKeys.length * Math.random() << 0]];
+ editProfileView.isNewProfile = true;
+ editProfileView.newProfileColor = randomColor;
+ editProfileView.newProfileName = profile.value;
+ editProfileView.updateProfile(false);
+ }
+ addSubscription(newSubscription, true, profile.value);
+ displaySubs();
+ }, randomNumber);
+ });
+ } else {
+ let randomNumber = Math.floor((Math.random() * 1000) + 1);
+ window.setTimeout(() => {
+ addSubscription(newSubscription)
+ }, randomNumber);
}
- showToast('Susbcriptions have been successfully imported. Please restart FreeTube for the changes to take effect.');
});
+
+ window.setTimeout(() => {
+ displaySubs()
+ }, 8000);
})
});
}
@@ -829,42 +938,42 @@ function exportSubscriptions() {
}
const dateYear = date.getFullYear();
- const dateString = 'freetube-subscriptions-' + dateYear + '-' + dateMonth + '-' + dateDay;
+ const dateString = 'freetube-subscriptions-' + dateYear + '-' + dateMonth + '-' + dateDay + '.db';
switch (document.querySelector('#exportSelect').value) {
- case "NewPipe":
- exportNewpipeSubscriptions(dateYear, dateMonth, dateDay);
- break;
- case "OPML":
- exportOpmlSubscriptions(dateYear, dateMonth, dateDay);
- break;
- default:
- // Open user file browser. User gives location of file to be created.
- dialog.showSaveDialog({
- defaultPath: dateString,
- filters: [{
- name: 'Database File',
- extensions: ['db']
- }, ]
- }, function(fileLocation) {
- ft.log(fileLocation);
- if (typeof(fileLocation) === 'undefined') {
- ft.log('Export Aborted');
- return;
+ case "NewPipe":
+ exportNewpipeSubscriptions(dateYear, dateMonth, dateDay);
+ break;
+ case "OPML":
+ exportOpmlSubscriptions(dateYear, dateMonth, dateDay);
+ break;
+ default:
+ // Open user file browser. User gives location of file to be created.
+ dialog.showSaveDialog({
+ defaultPath: dateString,
+ filters: [{
+ name: 'Database File',
+ extensions: ['db']
+ }, ]
+ }, function (fileLocation) {
+ ft.log(fileLocation);
+ if (typeof (fileLocation) === 'undefined') {
+ ft.log('Export Aborted');
+ return;
+ }
+ fs.readFile(appDatabaseFile, function (readErr, data) {
+ if (readErr) {
+ throw readErr;
}
- fs.readFile(appDatabaseFile, function(readErr, data) {
- if (readErr) {
- throw readErr;
+ fs.writeFile(fileLocation, data, function (writeErr) {
+ if (writeErr) {
+ throw writeErr;
}
- fs.writeFile(fileLocation, data, function(writeErr) {
- if (writeErr) {
- throw writeErr;
- }
- showToast('Susbcriptions have been successfully exported');
- });
- })
- });
+ showToast('Susbcriptions have been successfully exported');
+ });
+ })
+ });
}
}
/**
@@ -882,9 +991,9 @@ function exportNewpipeSubscriptions(dateYear, dateMonth, dateDay) {
name: 'JSON',
extensions: ['json']
}, ]
- }, function(fileLocation) {
+ }, function (fileLocation) {
ft.log(fileLocation);
- if (typeof(fileLocation) === 'undefined') {
+ if (typeof (fileLocation) === 'undefined') {
ft.log('Export Aborted');
return;
}
@@ -905,7 +1014,7 @@ function exportNewpipeSubscriptions(dateYear, dateMonth, dateDay) {
newpipe.subscriptions.push(subs);
}
- fs.writeFile(fileLocation, JSON.stringify(newpipe), function(writeErr) {
+ fs.writeFile(fileLocation, JSON.stringify(newpipe), function (writeErr) {
if (writeErr) {
throw writeErr;
} else {
@@ -931,9 +1040,9 @@ function exportOpmlSubscriptions(dateYear, dateMonth, dateDay) {
name: 'OPML',
extensions: ['opml']
}, ]
- }, function(fileLocation) {
+ }, function (fileLocation) {
ft.log(fileLocation);
- if (typeof(fileLocation) === 'undefined') {
+ if (typeof (fileLocation) === 'undefined') {
ft.log('Export Aborted');
return;
}
@@ -952,7 +1061,7 @@ function exportOpmlSubscriptions(dateYear, dateMonth, dateDay) {
opml += subs;
}
- fs.writeFile(fileLocation, opml, function(writeErr) {
+ fs.writeFile(fileLocation, opml, function (writeErr) {
if (writeErr) {
throw writeErr;
}
@@ -974,22 +1083,22 @@ function clearFile(type, showMessage = true) {
let dataBaseFile;
switch (type) {
- case 'subscriptions':
- dataBaseFile = localDataStorage + '/subscriptions.db';
- break;
- case 'history':
- dataBaseFile = localDataStorage + '/videohistory.db';
- break;
- case 'saved':
- dataBaseFile = localDataStorage + '/savedvideos.db';
- break;
- default:
- showToast('Unknown file: ' + type)
- return
+ case 'subscriptions':
+ dataBaseFile = localDataStorage + '/subscriptions.db';
+ break;
+ case 'history':
+ dataBaseFile = localDataStorage + '/videohistory.db';
+ break;
+ case 'saved':
+ dataBaseFile = localDataStorage + '/savedvideos.db';
+ break;
+ default:
+ showToast('Unknown file: ' + type)
+ return
}
// Replace data with an empty string.
- fs.writeFile(dataBaseFile, '', function(err) {
+ fs.writeFile(dataBaseFile, '', function (err) {
if (err) {
throw err;
}
@@ -1001,11 +1110,11 @@ function clearFile(type, showMessage = true) {
}
function showSettingsConfirm() {
- $('#confirmSettings').get(0).style.opacity = 0.9;
+ $('#confirmSettings').get(0).style.opacity = 0.9;
}
function hideSettingsConfirm() {
- $('#confirmSettings').get(0).style.opacity = 0;
+ $('#confirmSettings').get(0).style.opacity = 0;
}
checkDefaultSettings();
diff --git a/src/js/subscriptions.js b/src/js/subscriptions.js
index fa2d0b9c1..a91acb0dd 100644
--- a/src/js/subscriptions.js
+++ b/src/js/subscriptions.js
@@ -25,6 +25,7 @@ let subscriptionTimer;
let forceTimer;
let checkSubscriptions = true;
let forceSubs = true;
+let displaySubsLock = false;
/**
* Add a channel to the user's subscription database.
@@ -33,15 +34,46 @@ let forceSubs = true;
*
* @return {Void}
*/
-function addSubscription(data, useToast = true) {
+function addSubscription(data, useToast = true, profile = '') {
ft.log('Channel Data: ', data);
- // Refresh the list of subscriptions on the side navigation bar.
- subDb.insert(data, (err, newDoc) => {
- if (useToast) {
- showToast('Added ' + data.channelName + ' to subscriptions.');
+ let newSubscription = data;
+ newSubscription.profile = [{
+ value: profile
+ }];
+
+ if (profile === '') {
+ newSubscription.profile = [{
+ value: profileSelectView.activeProfile.name
+ }];
+ }
+
+ subDb.find({
+ channelId: data.channelId
+ }, (err, docs) => {
+ if (jQuery.isEmptyObject(docs)) {
+ subDb.insert(newSubscription, (err, newDoc) => {
+ if (useToast) {
+ showToast('Added ' + newSubscription.channelName + ' to subscriptions.');
+ }
+ // Refresh the list of subscriptions on the side navigation bar.
+ displaySubs();
+ });
+ } else {
+ subDb.update({
+ channelId: data.channelId,
+ }, {
+ $push: {
+ profile: {
+ value: newSubscription.profile[0].value
+ }
+ }
+ }, (err, numAdded) => {
+ // Refresh the list of subscriptions on the side navigation bar.
+ displaySubs();
+ showToast('Added ' + data.channelName + ' to subscriptions.');
+ });
}
- displaySubs();
});
}
@@ -53,12 +85,32 @@ function addSubscription(data, useToast = true) {
* @return {Void}
*/
function removeSubscription(channelId) {
- subDb.remove({
+ subDb.find({
channelId: channelId
- }, {}, (err, numRemoved) => {
- // Refresh the list of subscriptions on the side navigation bar.
- displaySubs();
- showToast('Removed channel from subscriptions.');
+ }, (err, docs) => {
+ if (docs[0].profile.length > 1) {
+ subDb.update({
+ channelId: channelId,
+ }, {
+ $pull: {
+ profile: {
+ value: profileSelectView.activeProfile.name
+ }
+ }
+ }, (err, numAdded) => {
+ // Refresh the list of subscriptions on the side navigation bar.
+ displaySubs();
+ showToast('Removed channel from subscriptions.');
+ });
+ } else {
+ subDb.remove({
+ channelId: channelId
+ }, {}, (err, numRemoved) => {
+ // Refresh the list of subscriptions on the side navigation bar.
+ displaySubs();
+ showToast('Removed channel from subscriptions.');
+ });
+ }
});
}
@@ -95,15 +147,17 @@ function loadSubscriptions() {
invidiousAPI('channels/latest', channelId, {}, (data) => {
data.forEach((video, index) => {
- data[index].author = results[i]['channelName'];
- historyDb.findOne({ videoId: video.videoId }, function (err, doc) {
- if(doc === null) {
- data[index].watched = false
- }
- else {
- data[index].watched = true;
- }
- });
+ data[index].author = results[i]['channelName'];
+ data[index].profile = results[i]['profile'];
+ historyDb.findOne({
+ videoId: video.videoId
+ }, function (err, doc) {
+ if (doc === null) {
+ data[index].watched = false
+ } else {
+ data[index].watched = true;
+ }
+ });
});
videoList = videoList.concat(data);
counter = counter + 1;
@@ -139,11 +193,15 @@ function addSubsToView(videoList) {
});
if (hideWatchedSubs) {
- videoList = videoList.filter(a => {
- return !a.watched;
- });
+ videoList = videoList.filter(a => {
+ return !a.watched;
+ });
}
+ videoList = videoList.filter(a => {
+ return a.profile.map(x => x.value).indexOf(profileSelectView.activeProfile.name) !== -1
+ });
+
videoList.sort((a, b) => {
return b.published - a.published;
});
@@ -209,12 +267,24 @@ function returnSubscriptions() {
* @return {Void}
*/
function displaySubs() {
+ if (displaySubsLock) {
+ return;
+ }
+
+ displaySubsLock = true;
+
const subList = document.getElementById('subscriptions');
subList.innerHTML = '';
// Sort alphabetically
- subDb.find({}).sort({
+ subDb.find({
+ profile: {
+ $elemMatch: {
+ value: profileSelectView.activeProfile.name
+ }
+ }
+ }).sort({
channelName: 1
}).exec((err, subs) => {
subs.forEach((channel) => {
@@ -230,6 +300,8 @@ function displaySubs() {
const subscriptionsHtml = $('#subscriptions').html();
$('#subscriptions').html(subscriptionsHtml + rendered);
});
+
+ displaySubsLock = false;
});
// Add onclick function
@@ -268,10 +340,20 @@ function toggleSubscription(data) {
*
* @return {promise} - A boolean value if the channel is currently subscribed or not.
*/
-function isSubscribed(channelId) {
+function isSubscribed(channelId, profile = profileSelectView.activeProfile.name) {
return new Promise((resolve, reject) => {
subDb.find({
- channelId: channelId
+ $and: [{
+ channelId: channelId
+ },
+ {
+ profile: {
+ $elemMatch: {
+ value: profile
+ }
+ }
+ },
+ ]
}, (err, docs) => {
if (jQuery.isEmptyObject(docs)) {
resolve(false);
diff --git a/src/js/templates.js b/src/js/templates.js
index 08039753d..5c25ff29c 100644
--- a/src/js/templates.js
+++ b/src/js/templates.js
@@ -23,837 +23,1456 @@ const playerTemplate = require('./templates/player.html');
const channelTemplate = require('./templates/channelView.html');
const progressViewTemplate = require('./templates/progressView.html');
const playlistViewTemplate = require('./templates/playlistView.html');
+const currentProfileViewTemplate = require('./templates/currentProfileView.html');
+const profileSelectViewTemplate = require('./templates/profileSelectView.html');
+const subscriptionManagerViewTemplate = require('./templates/subscriptionManagerView.html');
+const editProfileViewTemplate = require('./templates/editProfileView.html');
/*
-* Progress view
-*
-* Shows progress bar on bottom of application.
-*
-* seen: Toggles visibility of view
-* progressWidth: sets width of the progress bar
-*/
+ * 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
+ el: '#progressView',
+ data: {
+ seen: true,
+ progressWidth: 0
+ },
+ template: progressViewTemplate
});
let loadingView = new Vue({
- el: '#loading',
- data: {
- seen: false
- }
+ el: '#loading',
+ data: {
+ seen: false
+ }
});
let searchFilter = new Vue({
- el: '#searchFilter',
- data: {
- seen: false
- }
+ el: '#searchFilter',
+ data: {
+ seen: false
+ }
});
let noSubscriptions = new Vue({
- el: '#noSubscriptions',
- data: {
- seen: false
- }
+ el: '#noSubscriptions',
+ data: {
+ seen: false
+ }
});
let sideNavBar = new Vue({
- el: '#sideNav',
- data: {
- distractionFreeMode: false
- },
- methods: {
- subscriptions: (event) => {
- hideViews();
- if(subscriptionView.videoList.length === 0){
- loadingView.seen = true;
- }
- headerView.seen = true;
- headerView.title = 'Latest Subscriptions';
- subscriptionView.seen = true;
- loadSubscriptions();
+ el: '#sideNav',
+ data: {
+ distractionFreeMode: false
},
- popular: (event) => {
- hideViews();
- if (loadingView.seen !== false){
- loadingView.seen = false;
- }
- if(popularView.videoList.length === 0){
- loadingView.seen = true;
- }
- headerView.seen = true;
- headerView.title = 'Most Popular';
- popularView.seen = true;
- showMostPopular();
- },
- trending: (event) => {
- hideViews();
- if (loadingView.seen !== false){
- loadingView.seen = false;
- }
- if(trendingView.videoList.length === 0){
- loadingView.seen = true;
- }
- headerView.seen = true;
- headerView.title = 'Trending';
- trendingView.seen = true;
- showTrending();
- },
- saved: (event) => {
- hideViews();
- if (loadingView.seen !== false){
- loadingView.seen = false;
- }
- else{
- loadingView.seen = true;
- }
- headerView.seen = true;
- headerView.title = 'Favorited Videos';
- savedView.seen = true;
- showSavedVideos();
- },
- history: (event) => {
- hideViews();
- if (loadingView.seen !== false){
- loadingView.seen = false;
- }
- else{
- loadingView.seen = true;
- }
- headerView.seen = true;
- headerView.title = 'Video History';
- historyView.seen = true;
- showHistory();
- },
- settings: (event) => {
- hideViews();
- if (loadingView.seen !== false){
- loadingView.seen = false;
- }
- settingsView.seen = true;
- updateSettingsView();
- },
- about: (event) => {
- hideViews();
- if (loadingView.seen !== false){
- loadingView.seen = false;
- }
- aboutView.seen = true;
+ methods: {
+ 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 (loadingView.seen !== false) {
+ loadingView.seen = false;
+ }
+ if (popularView.videoList.length === 0) {
+ loadingView.seen = true;
+ }
+ headerView.seen = true;
+ headerView.title = 'Most Popular';
+ popularView.seen = true;
+ showMostPopular();
+ },
+ trending: (event) => {
+ hideViews();
+ if (loadingView.seen !== false) {
+ loadingView.seen = false;
+ }
+ if (trendingView.videoList.length === 0) {
+ loadingView.seen = true;
+ }
+ headerView.seen = true;
+ headerView.title = 'Trending';
+ trendingView.seen = true;
+ showTrending();
+ },
+ saved: (event) => {
+ hideViews();
+ if (loadingView.seen !== false) {
+ loadingView.seen = false;
+ } else {
+ loadingView.seen = true;
+ }
+ headerView.seen = true;
+ headerView.title = 'Favorited Videos';
+ savedView.seen = true;
+ showSavedVideos();
+ },
+ history: (event) => {
+ hideViews();
+ if (loadingView.seen !== false) {
+ loadingView.seen = false;
+ } else {
+ loadingView.seen = true;
+ }
+ headerView.seen = true;
+ headerView.title = 'Video History';
+ historyView.seen = true;
+ showHistory();
+ },
+ settings: (event) => {
+ hideViews();
+ if (loadingView.seen !== false) {
+ loadingView.seen = false;
+ }
+ settingsView.seen = true;
+ updateSettingsView();
+ },
+ about: (event) => {
+ hideViews();
+ if (loadingView.seen !== false) {
+ loadingView.seen = false;
+ }
+ aboutView.seen = true;
+ }
}
- }
});
let headerView = new Vue({
- el: '#mainHeaderView',
- data: {
- seen: true,
- title: 'Latest Subscriptions'
- },
- template: mainHeaderTemplate
+ el: '#mainHeaderView',
+ data: {
+ seen: true,
+ title: 'Latest Subscriptions'
+ },
+ template: mainHeaderTemplate
});
let subscriptionView = new Vue({
- el: '#subscriptionView',
- data: {
- seen: true,
- isSearch: false,
- videoList: [],
- fullVideoList: [],
- },
- methods: {
- play: (videoId) => {
- loadingView.seen = true;
- playVideo(videoId);
+ el: '#subscriptionView',
+ data: {
+ seen: true,
+ isSearch: false,
+ videoList: [],
+ fullVideoList: [],
},
- channel: (channelId) => {
- goToChannel(channelId);
+ methods: {
+ play: (videoId) => {
+ loadingView.seen = true;
+ playVideo(videoId);
+ },
+ channel: (channelId) => {
+ goToChannel(channelId);
+ },
+ toggleSave: (videoId) => {
+ addSavedVideo(videoId);
+ },
+ copyYouTube: (videoId) => {
+ const url = 'https://youtube.com/watch?v=' + videoId;
+ clipboard.writeText(url);
+ showToast('URL has been copied to the clipboard');
+ },
+ copyInvidious: (videoId) => {
+ const url = invidiousInstance + '/watch?v=' + videoId;
+ clipboard.writeText(url);
+ showToast('URL has been copied to the clipboard');
+ },
+ history: (videoId) => {
+ removeFromHistory(videoId);
+ },
+ miniPlayer: (videoId) => {
+ ft.log(videoId);
+ clickMiniPlayer(videoId);
+ }
},
- toggleSave: (videoId) => {
- addSavedVideo(videoId);
- },
- copyYouTube: (videoId) => {
- const url = 'https://youtube.com/watch?v=' + videoId;
- clipboard.writeText(url);
- showToast('URL has been copied to the clipboard');
- },
- copyInvidious: (videoId) => {
- const url = invidiousInstance + '/watch?v=' + videoId;
- clipboard.writeText(url);
- showToast('URL has been copied to the clipboard');
- },
- history: (videoId) => {
- removeFromHistory(videoId);
- },
- miniPlayer: (videoId) => {
- ft.log(videoId);
- clickMiniPlayer(videoId);
- }
- },
- template: videoListTemplate
+ template: videoListTemplate
});
let popularView = new Vue({
- el: '#popularView',
- data: {
- seen: false,
- isSearch: false,
- videoList: []
- },
- methods: {
- play: (videoId) => {
- loadingView.seen = true;
- playVideo(videoId);
+ el: '#popularView',
+ data: {
+ seen: false,
+ isSearch: false,
+ videoList: []
},
- channel: (channelId) => {
- goToChannel(channelId);
+ methods: {
+ play: (videoId) => {
+ loadingView.seen = true;
+ playVideo(videoId);
+ },
+ channel: (channelId) => {
+ goToChannel(channelId);
+ },
+ toggleSave: (videoId) => {
+ addSavedVideo(videoId);
+ },
+ copyYouTube: (videoId) => {
+ const url = 'https://youtube.com/watch?v=' + videoId;
+ clipboard.writeText(url);
+ showToast('URL has been copied to the clipboard');
+ },
+ copyInvidious: (videoId) => {
+ const url = invidiousInstance + '/watch?v=' + videoId;
+ clipboard.writeText(url);
+ showToast('URL has been copied to the clipboard');
+ },
+ history: (videoId) => {
+ removeFromHistory(videoId);
+ },
+ miniPlayer: (videoId) => {
+ clickMiniPlayer(videoId);
+ }
},
- toggleSave: (videoId) => {
- addSavedVideo(videoId);
- },
- copyYouTube: (videoId) => {
- const url = 'https://youtube.com/watch?v=' + videoId;
- clipboard.writeText(url);
- showToast('URL has been copied to the clipboard');
- },
- copyInvidious: (videoId) => {
- const url = invidiousInstance + '/watch?v=' + videoId;
- clipboard.writeText(url);
- showToast('URL has been copied to the clipboard');
- },
- history: (videoId) => {
- removeFromHistory(videoId);
- },
- miniPlayer: (videoId) => {
- clickMiniPlayer(videoId);
- }
- },
- template: videoListTemplate
+ template: videoListTemplate
});
let trendingView = new Vue({
- el: '#trendingView',
- data: {
- seen: false,
- isSearch: false,
- videoList: []
- },
- methods: {
- play: (videoId) => {
- loadingView.seen = true;
- playVideo(videoId);
+ el: '#trendingView',
+ data: {
+ seen: false,
+ isSearch: false,
+ videoList: []
},
- channel: (channelId) => {
- goToChannel(channelId);
+ methods: {
+ play: (videoId) => {
+ loadingView.seen = true;
+ playVideo(videoId);
+ },
+ channel: (channelId) => {
+ goToChannel(channelId);
+ },
+ toggleSave: (videoId) => {
+ addSavedVideo(videoId);
+ },
+ copyYouTube: (videoId) => {
+ const url = 'https://youtube.com/watch?v=' + videoId;
+ clipboard.writeText(url);
+ showToast('URL has been copied to the clipboard');
+ },
+ copyInvidious: (videoId) => {
+ const url = invidiousInstance + '/watch?v=' + videoId;
+ clipboard.writeText(url);
+ showToast('URL has been copied to the clipboard');
+ },
+ history: (videoId) => {
+ removeFromHistory(videoId);
+ },
+ miniPlayer: (videoId) => {
+ clickMiniPlayer(videoId);
+ }
},
- toggleSave: (videoId) => {
- addSavedVideo(videoId);
- },
- copyYouTube: (videoId) => {
- const url = 'https://youtube.com/watch?v=' + videoId;
- clipboard.writeText(url);
- showToast('URL has been copied to the clipboard');
- },
- copyInvidious: (videoId) => {
- const url = invidiousInstance + '/watch?v=' + videoId;
- clipboard.writeText(url);
- showToast('URL has been copied to the clipboard');
- },
- history: (videoId) => {
- removeFromHistory(videoId);
- },
- miniPlayer: (videoId) => {
- clickMiniPlayer(videoId);
- }
- },
- template: videoListTemplate
+ template: videoListTemplate
});
let savedView = new Vue({
- el: '#savedView',
- data: {
- seen: false,
- isSearch: false,
- videoList: []
- },
- methods: {
- play: (videoId) => {
- loadingView.seen = true;
- playVideo(videoId);
+ el: '#savedView',
+ data: {
+ seen: false,
+ isSearch: false,
+ videoList: []
},
- channel: (channelId) => {
- goToChannel(channelId);
+ methods: {
+ play: (videoId) => {
+ loadingView.seen = true;
+ playVideo(videoId);
+ },
+ channel: (channelId) => {
+ goToChannel(channelId);
+ },
+ toggleSave: (videoId) => {
+ toggleSavedVideo(videoId);
+ },
+ copyYouTube: (videoId) => {
+ const url = 'https://youtube.com/watch?v=' + videoId;
+ clipboard.writeText(url);
+ showToast('URL has been copied to the clipboard');
+ },
+ copyInvidious: (videoId) => {
+ const url = invidiousInstance + '/watch?v=' + videoId;
+ clipboard.writeText(url);
+ showToast('URL has been copied to the clipboard');
+ },
+ history: (videoId) => {
+ removeFromHistory(videoId);
+ },
+ miniPlayer: (videoId) => {
+ clickMiniPlayer(videoId);
+ }
},
- toggleSave: (videoId) => {
- toggleSavedVideo(videoId);
- },
- copyYouTube: (videoId) => {
- const url = 'https://youtube.com/watch?v=' + videoId;
- clipboard.writeText(url);
- showToast('URL has been copied to the clipboard');
- },
- copyInvidious: (videoId) => {
- const url = invidiousInstance + '/watch?v=' + videoId;
- clipboard.writeText(url);
- showToast('URL has been copied to the clipboard');
- },
- history: (videoId) => {
- removeFromHistory(videoId);
- },
- miniPlayer: (videoId) => {
- clickMiniPlayer(videoId);
- }
- },
- template: videoListTemplate
+ template: videoListTemplate
});
let historyView = new Vue({
- el: '#historyView',
- data: {
- seen: false,
- isSearch: false,
- videoList: []
- },
- methods: {
- play: (videoId) => {
- loadingView.seen = true;
- playVideo(videoId);
+ el: '#historyView',
+ data: {
+ seen: false,
+ isSearch: false,
+ videoList: []
},
- channel: (channelId) => {
- goToChannel(channelId);
+ methods: {
+ play: (videoId) => {
+ loadingView.seen = true;
+ playVideo(videoId);
+ },
+ channel: (channelId) => {
+ goToChannel(channelId);
+ },
+ toggleSave: (videoId) => {
+ addSavedVideo(videoId);
+ },
+ copyYouTube: (videoId) => {
+ const url = 'https://youtube.com/watch?v=' + videoId;
+ clipboard.writeText(url);
+ showToast('URL has been copied to the clipboard');
+ },
+ copyInvidious: (videoId) => {
+ const url = invidiousInstance + '/watch?v=' + videoId;
+ clipboard.writeText(url);
+ showToast('URL has been copied to the clipboard');
+ },
+ history: (videoId) => {
+ removeFromHistory(videoId);
+ },
+ miniPlayer: (videoId) => {
+ clickMiniPlayer(videoId);
+ }
},
- toggleSave: (videoId) => {
- addSavedVideo(videoId);
- },
- copyYouTube: (videoId) => {
- const url = 'https://youtube.com/watch?v=' + videoId;
- clipboard.writeText(url);
- showToast('URL has been copied to the clipboard');
- },
- copyInvidious: (videoId) => {
- const url = invidiousInstance + '/watch?v=' + videoId;
- clipboard.writeText(url);
- showToast('URL has been copied to the clipboard');
- },
- history: (videoId) => {
- removeFromHistory(videoId);
- },
- miniPlayer: (videoId) => {
- clickMiniPlayer(videoId);
- }
- },
- template: videoListTemplate
+ template: videoListTemplate
});
let playlistView = new Vue({
- el: '#playlistView',
- data: {
- seen: false,
- playlistId: '',
- channelName: '',
- channelId: '',
- thumbnail: '',
- title: '',
- videoCount: '',
- viewCount: '',
- description: '',
- lastUpdated: '',
- videoList: []
- },
- methods: {
- play: (videoId) => {
- loadingView.seen = true;
- playVideo(videoId, playlistView.playlistId);
+ el: '#playlistView',
+ data: {
+ seen: false,
+ playlistId: '',
+ channelName: '',
+ channelId: '',
+ thumbnail: '',
+ title: '',
+ videoCount: '',
+ viewCount: '',
+ description: '',
+ lastUpdated: '',
+ videoList: []
+ },
+ methods: {
+ play: (videoId) => {
+ loadingView.seen = true;
+ playVideo(videoId, playlistView.playlistId);
- backButtonView.lastView = playlistView
- },
- channel: (channelId) => {
- goToChannel(channelId);
+ backButtonView.lastView = playlistView
+ },
+ channel: (channelId) => {
+ goToChannel(channelId);
- backButtonView.lastView = playlistView
+ backButtonView.lastView = playlistView
+ },
+ toggleSave: (videoId) => {
+ addSavedVideo(videoId);
+ },
+ copyYouTube: (videoId) => {
+ const url = 'https://youtube.com/watch?v=' + videoId;
+ clipboard.writeText(url);
+ showToast('URL has been copied to the clipboard');
+ },
+ copyInvidious: (videoId) => {
+ const url = invidiousInstance + '/watch?v=' + videoId;
+ clipboard.writeText(url);
+ showToast('URL has been copied to the clipboard');
+ },
+ history: (videoId) => {
+ removeFromHistory(videoId);
+ }
},
- toggleSave: (videoId) => {
- addSavedVideo(videoId);
- },
- copyYouTube: (videoId) => {
- const url = 'https://youtube.com/watch?v=' + videoId;
- clipboard.writeText(url);
- showToast('URL has been copied to the clipboard');
- },
- copyInvidious: (videoId) => {
- const url = invidiousInstance + '/watch?v=' + videoId;
- clipboard.writeText(url);
- showToast('URL has been copied to the clipboard');
- },
- history: (videoId) => {
- removeFromHistory(videoId);
- }
- },
- template: playlistViewTemplate
+ template: playlistViewTemplate
});
let aboutView = new Vue({
- el: '#aboutView',
- data: {
- seen: false,
- rssFeed: [],
- versionNumber: electron.remote.app.getVersion()
- },
- template: aboutTemplate
+ el: '#aboutView',
+ data: {
+ seen: false,
+ rssFeed: [],
+ versionNumber: electron.remote.app.getVersion()
+ },
+ template: aboutTemplate
});
let settingsView = new Vue({
- el: '#settingsView',
- data: {
- seen: false,
- useTheme: false,
- useTor: false,
- apiKey: '',
- history: true,
- autoplay: true,
- autoplayPlaylists: true,
- playNextVideo: false,
- subtitles: false,
- updates: true,
- localScrape: true,
- region: 'US',
- proxyAddress: false,
- invidiousInstance: 'https://invidio.us',
- checkProxyResult: false,
- proxyTestLoading: false,
- debugMode: false,
- distractionFreeMode: false,
- defaultVolume: 1,
- defaultVideoSpeed: 1,
- subWatched: false,
- videoView: 'grid',
- },
- methods: {
- checkProxy() {
- this.checkProxyResult = false;
- this.proxyTestLoading = true;
- let data = {
- proxyAddress: this.proxyAddress,
- };
- electron.ipcRenderer.send("setProxy", data);
+ el: '#settingsView',
+ data: {
+ seen: false,
+ useTheme: false,
+ useTor: false,
+ apiKey: '',
+ history: true,
+ autoplay: true,
+ autoplayPlaylists: true,
+ playNextVideo: false,
+ subtitles: false,
+ updates: true,
+ localScrape: true,
+ region: 'US',
+ proxyAddress: false,
+ invidiousInstance: 'https://invidio.us',
+ checkProxyResult: false,
+ proxyTestLoading: false,
+ hideWatchedSubs: false,
+ debugMode: false,
+ distractionFreeMode: false,
+ defaultVolume: 1,
+ defaultVideoSpeed: 1,
+ subWatched: false,
+ videoView: 'grid',
+ defaultProfile: 'Default',
+ },
+ methods: {
+ checkProxy() {
+ this.checkProxyResult = false;
+ this.proxyTestLoading = true;
+ electron.ipcRenderer.send("setProxy", this.proxyAddress);
- proxyRequest(() => {
- $.ajax({
- url: "https://ipinfo.io/json",
- dataType: 'json',
- }).done(response => {
- console.log(response);
- this.checkProxyResult = response;
- })
- .fail((xhr, textStatus, error) => {
- console.log(xhr);
- console.log(textStatus);
- showToast('Proxy test failed');
- }).always(() =>{
- this.proxyTestLoading = false;
- if (!useTor) {
- electron.ipcRenderer.send("setProxy", {});
- }
- });
- })
+ proxyRequest(() => {
+ $.ajax({
+ url: "https://ipinfo.io/json",
+ dataType: 'json',
+ }).done(response => {
+ console.log(response);
+ this.checkProxyResult = response;
+ })
+ .fail((xhr, textStatus, error) => {
+ console.log(xhr);
+ console.log(textStatus);
+ showToast('Proxy test failed');
+ }).always(() => {
+ this.proxyTestLoading = false;
+ if (!useTor) {
+ electron.ipcRenderer.send("setProxy", {});
+ }
+ });
+ })
+ },
+ setDistractionFreeMode(setting) {
+ settingsView.distractionFreeMode = setting;
+ sideNavBar.distractionFreeMode = setting;
+ channelView.distractionFreeMode = setting;
+ playerView.distractionFreeMode = setting;
+ },
},
- setDistractionFreeMode(setting) {
- settingsView.distractionFreeMode = setting;
- sideNavBar.distractionFreeMode = setting;
- channelView.distractionFreeMode = setting;
- playerView.distractionFreeMode = setting;
+ computed: {
+ proxyTestButtonText() {
+ return this.proxyTestLoading ? "LOADING..." : "TEST PROXY"
+ },
+ volumeHtml() {
+ return Math.round(this.defaultVolume * 100);
+ }
},
- },
- computed: {
- proxyTestButtonText() {
- return this.proxyTestLoading ? "LOADING..." : "TEST PROXY"
- },
- volumeHtml() {
- return Math.round(this.defaultVolume * 100);
- }
- },
- template: settingsTemplate
+ template: settingsTemplate
});
let searchView = new Vue({
- el: '#searchView',
- data: {
- seen: false,
- isSearch: true,
- page: 1,
- videoList: []
- },
- methods: {
- play: (videoId) => {
- loadingView.seen = true;
- playVideo(videoId);
+ el: '#searchView',
+ data: {
+ seen: false,
+ isSearch: true,
+ page: 1,
+ videoList: []
+ },
+ methods: {
+ play: (videoId) => {
+ loadingView.seen = true;
+ playVideo(videoId);
- backButtonView.lastView = searchView
- },
- channel: (channelId) => {
- goToChannel(channelId);
+ backButtonView.lastView = searchView
+ },
+ channel: (channelId) => {
+ goToChannel(channelId);
- backButtonView.lastView = searchView
- },
- toggleSave: (videoId) => {
- addSavedVideo(videoId);
- },
- copyYouTube: (videoId) => {
- const url = 'https://youtube.com/watch?v=' + videoId;
- clipboard.writeText(url);
- showToast('URL has been copied to the clipboard');
- },
- copyInvidious: (videoId) => {
- const url = invidiousInstance + '/watch?v=' + videoId;
- clipboard.writeText(url);
- showToast('URL has been copied to the clipboard');
- },
- nextPage: () => {
- ft.log(searchView.page);
- search(searchView.page);
- },
- playlist: (playlistId) => {
- showPlaylist(playlistId);
+ backButtonView.lastView = searchView
+ },
+ toggleSave: (videoId) => {
+ addSavedVideo(videoId);
+ },
+ copyYouTube: (videoId) => {
+ const url = 'https://youtube.com/watch?v=' + videoId;
+ clipboard.writeText(url);
+ showToast('URL has been copied to the clipboard');
+ },
+ copyInvidious: (videoId) => {
+ const url = invidiousInstance + '/watch?v=' + videoId;
+ clipboard.writeText(url);
+ showToast('URL has been copied to the clipboard');
+ },
+ nextPage: () => {
+ ft.log(searchView.page);
+ search(searchView.page);
+ },
+ playlist: (playlistId) => {
+ showPlaylist(playlistId);
- backButtonView.lastView = searchView
+ backButtonView.lastView = searchView
+ },
+ miniPlayer: (videoId) => {
+ clickMiniPlayer(videoId);
+ }
},
- miniPlayer: (videoId) => {
- clickMiniPlayer(videoId);
- }
- },
- template: videoListTemplate
+ template: videoListTemplate
});
let channelView = new Vue({
- el: '#channelView',
- data: {
- seen: false,
- id: '',
- name: '',
- icon: '',
- baner: '',
- subCount: '',
- subButtonText: '',
- description: '',
- distractionFreeMode: false
- },
- methods: {
- subscription: (channelId) => {
- let channelData = {
- channelId: channelView.id,
- channelName: channelView.name,
- channelThumbnail: channelView.icon
- };
- toggleSubscription(channelData);
+ el: '#channelView',
+ data: {
+ seen: false,
+ id: '',
+ name: '',
+ icon: '',
+ baner: '',
+ subCount: '',
+ subButtonText: '',
+ description: '',
+ distractionFreeMode: false
},
- },
- template: channelTemplate
+ methods: {
+ subscription: (channelId) => {
+ let channelData = {
+ channelId: channelView.id,
+ channelName: channelView.name,
+ channelThumbnail: channelView.icon
+ };
+ toggleSubscription(channelData);
+ },
+ },
+ template: channelTemplate
});
let channelVideosView = new Vue({
- el: '#channelVideosView',
- data: {
- seen: false,
- channelId: '',
- isSearch: true,
- page: 2,
- videoList: []
- },
- methods: {
- play: (videoId) => {
- loadingView.seen = true;
- playVideo(videoId);
+ el: '#channelVideosView',
+ data: {
+ seen: false,
+ channelId: '',
+ isSearch: true,
+ page: 2,
+ videoList: []
},
- channel: (channelId) => {
- goToChannel(channelId);
+ methods: {
+ play: (videoId) => {
+ loadingView.seen = true;
+ playVideo(videoId);
+ },
+ channel: (channelId) => {
+ goToChannel(channelId);
+ },
+ toggleSave: (videoId) => {
+ addSavedVideo(videoId);
+ },
+ nextPage: () => {
+ channelNextPage();
+ },
+ copyYouTube: (videoId) => {
+ const url = 'https://youtube.com/watch?v=' + videoId;
+ clipboard.writeText(url);
+ showToast('URL has been copied to the clipboard');
+ },
+ copyInvidious: (videoId) => {
+ const url = invidiousInstance + '/watch?v=' + videoId;
+ clipboard.writeText(url);
+ showToast('URL has been copied to the clipboard');
+ },
+ history: (videoId) => {
+ removeFromHistory(videoId);
+ },
+ miniPlayer: (videoId) => {
+ clickMiniPlayer(videoId);
+ }
},
- toggleSave: (videoId) => {
- addSavedVideo(videoId);
- },
- nextPage: () => {
- channelNextPage();
- },
- copyYouTube: (videoId) => {
- const url = 'https://youtube.com/watch?v=' + videoId;
- clipboard.writeText(url);
- showToast('URL has been copied to the clipboard');
- },
- copyInvidious: (videoId) => {
- const url = invidiousInstance + '/watch?v=' + videoId;
- clipboard.writeText(url);
- showToast('URL has been copied to the clipboard');
- },
- history: (videoId) => {
- removeFromHistory(videoId);
- },
- miniPlayer: (videoId) => {
- clickMiniPlayer(videoId);
- }
- },
- template: videoListTemplate
+ template: videoListTemplate
});
let playerView = new Vue({
- el: '#playerView',
- data: {
- seen: false,
- playlistSeen: false,
- legacySeen: false,
- firstLoad: true,
- currentTime: undefined,
- publishedDate: '',
- videoUrl: '',
- videoId: '',
- channelId: '',
- channelIcon: '',
- channelName: '',
- subscribedText: '',
- subscriptionCount: '',
- savedText: '',
- savedIconType: 'far',
- description: '',
- videoThumbnail: '',
- subtitleHtml: '',
- currentQuality: '',
- videoAudio: '',
- validAudio: false,
- video360p: '',
- valid360p: false,
- video720p: '',
- valid720p: false,
- videoDash: '',
- validDash: true,
- videoLive: '',
- validLive: false,
- embededHtml: '',
- currentSpeed: 1,
- lengthSeconds: 0,
- videoTitle: '',
- videoViews: '',
- likePercentage: 0,
- videoLikes: 0,
- videoDislikes: 0,
- playerSeen: true,
- playlistTitle: '',
- playlistChannelName: '',
- playlistIndex: 1,
- playlistTotal: 1,
- playlistLoop: false,
- playlistShuffle: false,
- playlistShowList: true,
- recommendedVideoList: [],
- playlistVideoList: [],
- distractionFreeMode: false
- },
- methods: {
- channel: (channelId) => {
- goToChannel(channelId);
+ el: '#playerView',
+ data: {
+ seen: false,
+ playlistSeen: false,
+ legacySeen: false,
+ firstLoad: true,
+ currentTime: undefined,
+ publishedDate: '',
+ videoUrl: '',
+ videoId: '',
+ channelId: '',
+ channelIcon: '',
+ channelName: '',
+ subscribedText: '',
+ subscriptionCount: '',
+ savedText: '',
+ savedIconType: 'far',
+ description: '',
+ videoThumbnail: '',
+ subtitleHtml: '',
+ currentQuality: '',
+ videoAudio: '',
+ validAudio: false,
+ video360p: '',
+ valid360p: false,
+ video720p: '',
+ valid720p: false,
+ videoDash: '',
+ validDash: true,
+ videoLive: '',
+ validLive: false,
+ embededHtml: '',
+ currentSpeed: 1,
+ lengthSeconds: 0,
+ videoTitle: '',
+ videoViews: '',
+ likePercentage: 0,
+ videoLikes: 0,
+ videoDislikes: 0,
+ playerSeen: true,
+ playlistTitle: '',
+ playlistChannelName: '',
+ playlistIndex: 1,
+ playlistTotal: 1,
+ playlistLoop: false,
+ playlistShuffle: false,
+ playlistShowList: true,
+ recommendedVideoList: [],
+ playlistVideoList: [],
+ distractionFreeMode: false
},
- subscription: () => {
- let channelData = {
- channelId: playerView.channelId,
- channelName: playerView.channelName,
- channelThumbnail: playerView.channelIcon
- };
- toggleSubscription(channelData);
- },
- quality: (url, qualityText) => {
- ft.log(url);
- ft.log(qualityText);
- if(playerView.legacySeen === true){
- // Update time to new url
- const currentPlayBackTime = $('.videoPlayer').get(0).currentTime;
- ft.log(currentPlayBackTime);
- playerView.videoUrl = url;
- playerView.currentQuality = qualityText;
- setTimeout(() => {$('.videoPlayer').get(0).currentTime = currentPlayBackTime; $('.videoPlayer').get(0).play();}, 100);
- }
- },
- embededPlayer: () => {
- playerView.playerSeen = false;
- playerView.legacySeen = false;
- playerView.currentTime = undefined;
- checkedVideoSettings = false;
- },
- legacyFormats: () => {
- if (typeof(player) !== 'undefined') {
- playerView.currentTime = player.currentTime;
- }
+ methods: {
+ channel: (channelId) => {
+ goToChannel(channelId);
+ },
+ subscription: () => {
+ let channelData = {
+ channelId: playerView.channelId,
+ channelName: playerView.channelName,
+ channelThumbnail: playerView.channelIcon
+ };
+ toggleSubscription(channelData);
+ },
+ quality: (url, qualityText) => {
+ ft.log(url);
+ ft.log(qualityText);
+ if (playerView.legacySeen === true) {
+ // Update time to new url
+ const currentPlayBackTime = $('.videoPlayer').get(0).currentTime;
+ ft.log(currentPlayBackTime);
+ playerView.videoUrl = url;
+ playerView.currentQuality = qualityText;
+ setTimeout(() => {
+ $('.videoPlayer').get(0).currentTime = currentPlayBackTime;
+ $('.videoPlayer').get(0).play();
+ }, 100);
+ }
+ },
+ embededPlayer: () => {
+ playerView.playerSeen = false;
+ playerView.legacySeen = false;
+ playerView.currentTime = undefined;
+ checkedVideoSettings = false;
+ },
+ legacyFormats: () => {
+ if (typeof (player) !== 'undefined') {
+ playerView.currentTime = player.currentTime;
+ }
- checkedVideoSettings = false;
+ checkedVideoSettings = false;
- playerView.playerSeen = false;
- playerView.legacySeen = true;
- },
- dashFormats: () => {
- if (typeof($('#legacyPlayer').get(0)) !== 'undefined') {
- playerView.currentTime = $('#legacyPlayer').get(0).currentTime;
- }
- checkedVideoSettings = false;
+ playerView.playerSeen = false;
+ playerView.legacySeen = true;
+ },
+ dashFormats: () => {
+ if (typeof ($('#legacyPlayer').get(0)) !== 'undefined') {
+ playerView.currentTime = $('#legacyPlayer').get(0).currentTime;
+ }
+ checkedVideoSettings = false;
- playerView.legacySeen = false;
- playerView.playerSeen = true;
- },
- copyYouTube: (videoId) => {
- const url = 'https://youtube.com/watch?v=' + videoId;
- clipboard.writeText(url);
- showToast('URL has been copied to the clipboard');
- },
- openYouTube: (videoId) => {
- shell.openExternal('https://youtube.com/watch?v=' + videoId);
- },
- copyInvidious: (videoId) => {
- const url = invidiousInstance + '/watch?v=' + videoId;
- clipboard.writeText(url);
- showToast('URL has been copied to the clipboard');
- },
- openInvidious: (videoId) => {
- shell.openExternal(invidiousInstance + '/watch?v=' + videoId);
- },
- save: (videoId) => {
- toggleSavedVideo(videoId);
- },
- play: (videoId, playlistId = '') => {
- loadingView.seen = true;
- playVideo(videoId, playlistId);
- },
- loop: () => {
- let legacyPlayer = $('.videoPlayer').get(0);
+ playerView.legacySeen = false;
+ playerView.playerSeen = true;
+ },
+ copyYouTube: (videoId) => {
+ const url = 'https://youtube.com/watch?v=' + videoId;
+ clipboard.writeText(url);
+ showToast('URL has been copied to the clipboard');
+ },
+ openYouTube: (videoId) => {
+ shell.openExternal('https://youtube.com/watch?v=' + videoId);
+ },
+ copyInvidious: (videoId) => {
+ const url = invidiousInstance + '/watch?v=' + videoId;
+ clipboard.writeText(url);
+ showToast('URL has been copied to the clipboard');
+ },
+ openInvidious: (videoId) => {
+ shell.openExternal(invidiousInstance + '/watch?v=' + videoId);
+ },
+ save: (videoId) => {
+ toggleSavedVideo(videoId);
+ },
+ play: (videoId, playlistId = '') => {
+ loadingView.seen = true;
+ playVideo(videoId, playlistId);
+ },
+ loop: () => {
+ let legacyPlayer = $('.videoPlayer').get(0);
- if (legacyPlayer.loop === false) {
- legacyPlayer.loop = true;
- showToast('Video loop has been turned on.');
- }
- else{
- legacyPlayer.loop = false;
- showToast('Video loop has been turned off.')
- }
+ if (legacyPlayer.loop === false) {
+ legacyPlayer.loop = true;
+ showToast('Video loop has been turned on.');
+ } else {
+ legacyPlayer.loop = false;
+ showToast('Video loop has been turned off.')
+ }
+ },
+ playlist: (playlistId) => {
+ showPlaylist(playlistId);
+ },
+ playlistLoopToggle: () => {
+ if (playerView.playlistLoop !== false) {
+ showToast('Playlist will no longer loop');
+ playerView.playlistLoop = false;
+ } else {
+ showToast('Playlist will now loop');
+ playerView.playlistLoop = true;
+ }
+ },
+ playlistShuffleToggle: () => {
+ if (playerView.playlistShuffle !== false) {
+ showToast('Playlist will no longer shuffle');
+ playerView.playlistShuffle = false;
+ } else {
+ showToast('Playlist will now shuffle');
+ playerView.playlistShuffle = true;
+ }
+ },
},
- playlist: (playlistId) => {
- showPlaylist(playlistId);
+ computed: {
+ thumbnailInterval: function () {
+ if (this.lengthSeconds < 120) {
+ return 1;
+ } else if (this.lengthSeconds < 300) {
+ return 2;
+ } else if (this.lengthSeconds < 900) {
+ return 5;
+ } else {
+ return 10;
+ }
+ },
+ storyBoardUrl: function () {
+ return invidiousInstance + '/api/v1/storyboards/' + this.videoId + '?height=90';
+ }
},
- playlistLoopToggle: () => {
- if (playerView.playlistLoop !== false) {
- showToast('Playlist will no longer loop');
- playerView.playlistLoop = false;
- }
- else {
- showToast('Playlist will now loop');
- playerView.playlistLoop = true;
- }
- },
- playlistShuffleToggle: () => {
- if (playerView.playlistShuffle !== false) {
- showToast('Playlist will no longer shuffle');
- playerView.playlistShuffle = false;
- }
- else{
- showToast('Playlist will now shuffle');
- playerView.playlistShuffle = true;
- }
- },
- },
- computed: {
- thumbnailInterval: function() {
- if (this.lengthSeconds < 120) {
- return 1;
- } else if (this.lengthSeconds < 300) {
- return 2;
- } else if (this.lengthSeconds < 900) {
- return 5;
- } else {
- return 10;
- }
- },
- storyBoardUrl: function() {
- return invidiousInstance + '/api/v1/storyboards/' + this.videoId + '?height=90';
- }
- },
- template: playerTemplate
+ template: playerTemplate
});
let backButtonView = new Vue({
- el: '#backButton',
- data: {
- lastView: false
- },
- methods: {
- back: function() {
- // variable here because this.lastView gets reset in hideViews()
- const isSearch = this.lastView.$options.el === "#searchView";
+ el: '#backButton',
+ data: {
+ lastView: false
+ },
+ methods: {
+ back: function () {
+ // variable here because this.lastView gets reset in hideViews()
+ const isSearch = this.lastView.$options.el === "#searchView";
- hideViews();
- loadingView.seen = false;
+ hideViews();
+ loadingView.seen = false;
- // Check if lastView was search
- if(isSearch) {
- // Change back to searchView
- headerView.seen = true;
- headerView.title = 'Search Results';
- searchView.seen = true;
+ // Check if lastView was search
+ if (isSearch) {
+ // Change back to searchView
+ headerView.seen = true;
+ headerView.title = 'Search Results';
+ searchView.seen = true;
- // reset this.lastView
- this.lastView = false;
- } else {
- // if not search then this.lastView has to be playlistView
+ // reset this.lastView
+ this.lastView = false;
+ } else {
+ // if not search then this.lastView has to be playlistView
- // Change back to playlistView
- playlistView.seen = true;
+ // Change back to playlistView
+ playlistView.seen = true;
- // Check if searchView has videos if it does set this.lastView as searchView
- this.lastView = searchView.videoList.length > 0 ? searchView : false;
- }
- }
- },
- computed: {
- canShowBackButton: function() {
- // this.lastView can be either searchView or playlistView
- return !!this.lastView && !this.lastView.seen && this.lastView.videoList.length > 0;
- }
- },
+ // Check if searchView has videos if it does set this.lastView as searchView
+ this.lastView = searchView.videoList.length > 0 ? searchView : false;
+ }
+ }
+ },
+ computed: {
+ canShowBackButton: function () {
+ // this.lastView can be either searchView or playlistView
+ return !!this.lastView && !this.lastView.seen && this.lastView.videoList.length > 0;
+ }
+ },
+});
+
+let profileSelectView = new Vue({
+ el: '#profileSelectView',
+ data: {
+ seen: false,
+ activeProfile: [],
+ activeProfileInitial: '',
+ activeProfileInitialColor: '#000000',
+ profileList: [],
+ },
+ methods: {
+ showSubscriptionManager: function () {
+ hideViews();
+ subscriptionManagerView.seen = true;
+ },
+ setActiveProfile: function (index) {
+ this.activeProfile = this.profileList[index];
+ this.activeProfileInitial = this.profileInitials[index];
+ this.activeProfileInitialColor = this.profileTextColor[index];
+ this.seen = false;
+ displaySubs();
+ addSubsToView(subscriptionView.fullVideoList);
+
+ if (playerView.seen !== false || channelView.seen !== false) {
+ let checkSubscription;
+ if (playerView.seen !== false) {
+ checkSubscription = isSubscribed(playerView.channelId);
+ } else {
+ checkSubscription = isSubscribed(channelView.channelId);
+ }
+
+ checkSubscription.then((results) => {
+ if (results === false) {
+ channelView.subButtonText = 'SUBSCRIBE';
+ playerView.subscribedText = 'SUBSCRIBE';
+ } else {
+ channelView.subButtonText = 'UNSUBSCRIBE';
+ playerView.subscribedText = 'UNSUBSCRIBE';
+ }
+ });
+ }
+ }
+ },
+ computed: {
+ profileInitials: function () {
+ let initials = [];
+ if (this.profileList.length > 0) {
+ this.profileList.forEach((profile) => {
+ initials.push(profile.name.charAt(0));
+ });
+ }
+ return initials;
+ },
+ profileTextColor: function () {
+ let colors = [];
+ if (this.profileList.length > 0) {
+ this.profileList.forEach((profile) => {
+ let cutHex = (profile.color.charAt(0) == "#") ? profile.color.substring(1, 7) : h;
+ let colorValueR = parseInt(cutHex.substring(0, 2), 16);
+ let colorValueG = parseInt(cutHex.substring(2, 4), 16);
+ let colorValueB = parseInt(cutHex.substring(4, 6), 16);
+
+ let luminance = (0.299 * colorValueR + 0.587 * colorValueG + 0.114 * colorValueB) / 255;
+
+ if (luminance > 0.5) {
+ colors.push('#000000');
+ } else {
+ colors.push('#FFFFFF');
+ }
+ });
+ }
+ return colors;
+ }
+ },
+ template: profileSelectViewTemplate
+});
+
+let currentProfileView = new Vue({
+ el: '#currentProfileView',
+ data: {},
+ computed: {
+ activeProfile: function () {
+ return profileSelectView.activeProfile;
+ },
+ activeProfileInitial: function () {
+ return profileSelectView.activeProfileInitial;
+ },
+ activeProfileInitialColor: function () {
+ return profileSelectView.activeProfileInitialColor;
+ }
+ },
+ template: currentProfileViewTemplate
+});
+
+let subscriptionManagerView = new Vue({
+ el: '#subscriptionManagerView',
+ data: {
+ seen: false,
+ },
+ methods: {
+ editProfile: function (isNewProfile, index) {
+ hideViews();
+ editProfileView.isNewProfile = isNewProfile;
+ if (isNewProfile) {
+ editProfileView.profileName = '';
+ editProfileView.profileColor = '';
+ editProfileView.newProfileName = '';
+ editProfileView.newProfileColor = '';
+ editProfileView.subscriptionList = [];
+ } else {
+ editProfileView.profileName = this.profileList[index].name;
+ editProfileView.profileColor = this.profileList[index].color;
+ editProfileView.newProfileName = this.profileList[index].name;
+ editProfileView.newProfileColor = this.profileList[index].color;
+ // Sort alphabetically
+ subDb.find({
+ profile: {
+ $elemMatch: {
+ value: this.profileList[index].name
+ }
+ }
+ }).sort({
+ channelName: 1
+ }).exec((err, subs) => {
+ let list = [];
+ subs.forEach((sub) => {
+ sub.checked = false;
+ list.push(sub);
+ });
+ editProfileView.subscriptionList = list;
+ });
+ }
+ editProfileView.seen = true;
+ //backButtonView.lastView = subscriptionManagerView;
+ }
+ },
+ computed: {
+ profileList: function () {
+ return profileSelectView.profileList;
+ },
+ profileInitials: function () {
+ return profileSelectView.profileInitials;
+ },
+ profileTextColor: function () {
+ return profileSelectView.profileTextColor;
+ }
+ },
+ template: subscriptionManagerViewTemplate
+});
+
+let editProfileView = new Vue({
+ el: '#editProfileView',
+ data: {
+ seen: false,
+ isNewProfile: false,
+ subscriptionList: [],
+ profileName: '',
+ profileColor: '',
+ newProfileName: '',
+ newProfileColor: '',
+ selectedProfile: '',
+ colorPalette: {
+ red: '#d50000',
+ pink: '#C51162',
+ purple: '#AA00FF',
+ deepPurple: '#6200EA',
+ indigo: '#304FFE',
+ blue: '#2962FF',
+ lightBlue: '#0091EA',
+ cyan: '#00B8D4',
+ teal: '#00BFA5',
+ green: '#00C853',
+ lightGreen: '#64DD17',
+ lime: '#AEEA00',
+ yellow: '#FFD600',
+ amber: '#FFAB00',
+ orange: '#FF6D00',
+ deepOrange: '#DD2C00',
+ },
+ },
+ methods: {
+ changeProfileColor: function (value) {
+ this.newProfileColor = value;
+ },
+ selectAll: function () {
+ this.subscriptionList.forEach(channel => {
+ channel.checked = true;
+ });
+ },
+ selectNone: function () {
+ this.subscriptionList.forEach((channel) => {
+ channel.checked = false;
+ });
+ },
+ defaultProfile: function () {
+ settingsDb.update({
+ _id: 'defaultProfile'
+ }, {
+ value: editProfileView.profileName
+ }, {}, function (err, numUpdated) {
+ showToast(editProfileView.profileName + ' is now your default profile.');
+ settingsView.defaultProfile = editProfileView.profileName;
+ });
+ },
+ deleteProfile: function () {
+ if (this.profileName === settingsView.defaultProfile) {
+ showToast('You cannot delete your default profile.');
+ return;
+ }
+
+ let confirmString = 'Are you sure you want to delete this profile? Any subscriptions will also be deleted.';
+
+ confirmFunction(confirmString, () => {
+ settingsDb.find({
+ _id: 'profileList'
+ }, (err, docs) => {
+ let profiles = docs[0].value;
+ let nameIndex = profiles.findIndex(x => x.name === this.profileName);
+
+ profiles.splice(nameIndex, 1);
+
+ settingsDb.update({
+ _id: 'profileList'
+ }, {
+ value: profiles
+ }, {}, function (err, numUpdated) {});
+
+ subDb.update({
+ profile: {
+ $elemMatch: {
+ value: editProfileView.profileName
+ }
+ },
+ }, {
+ $pull: {
+ profile: {
+ value: editProfileView.profileName
+ }
+ }
+ }, {
+ multi: true
+ }, (err, numRemoved) => {
+ if (err) {
+ console.log(err);
+ }
+
+ let subMap = subscriptionView.fullVideoList.map(x => x.profile.map(x => x.value).indexOf(editProfileView.profileName) !== -1);
+
+ for (let i = 0; i < subMap.length; i++) {
+ if (subMap[i]) {
+ let subProfileIndex = subscriptionView.fullVideoList[i].profile.findIndex(x => x.value === editProfileView.profileName);
+ subscriptionView.fullVideoList[i].profile.splice(subProfileIndex, 1);
+ }
+ }
+
+ let profileIndex = profileSelectView.profileList.findIndex(x => x.name === editProfileView.profileName);
+ profileSelectView.profileList.splice(profileIndex, 1);
+
+ if (profileSelectView.activeProfile.name === this.profileName) {
+ profileSelectView.setActiveProfile(0);
+ }
+
+ hideViews();
+ subscriptionManagerView.seen = true;
+ showToast('Profile has been successfully deleted');
+ });
+ });
+ });
+ },
+ updateProfile: function (updateView = true) {
+ let patt = new RegExp("^#([A-Fa-f0-9]{6}|[A-Fa-f0-9]{3})$");
+ if (patt.test(this.newProfileColor)) {
+ if (this.isNewProfile) {
+ let newNameIndex = this.profileList.findIndex(x => x.name === this.newProfileName);
+ if (newNameIndex !== -1 && this.profileName !== this.newProfileName) {
+ showToast('Profile name already exists. Please choose a different profile name.');
+ return;
+ }
+ // Create new profile
+ settingsDb.find({
+ _id: 'profileList'
+ }, (err, docs) => {
+ let profiles = docs[0].value;
+ let newNameIndex = profiles.findIndex(x => x.name === this.newProfileName);
+ if (newNameIndex !== -1 && this.profileName !== this.newProfileName) {
+ showToast('Profile name already exists. Please choose a different profile name.');
+ return;
+ } else {
+ let newProfile = {
+ name: this.newProfileName,
+ color: this.newProfileColor
+ };
+
+ profiles.push(newProfile);
+
+ settingsDb.update({
+ _id: 'profileList'
+ }, {
+ value: profiles
+ }, {}, function (err, numUpdated) {
+ profileSelectView.profileList.push(newProfile);
+ if (updateView) {
+ hideViews();
+ subscriptionManagerView.seen = true;
+ showToast('The' + newProfile.name + ' profile has been added!');
+ }
+ });
+ }
+ });
+ } else {
+ // Update existing profile
+ settingsDb.find({
+ _id: 'profileList'
+ }, (err, docs) => {
+ let profiles = docs[0].value;
+ let newNameIndex = profiles.findIndex(x => x.name === this.newProfileName);
+ if (newNameIndex !== -1 && this.profileName !== this.newProfileName) {
+ showToast('Profile name already exists. Please choose a different profile name.');
+ return;
+ } else {
+ let oldNameIndex = profiles.findIndex(x => x.name === this.profileName);
+ profiles[oldNameIndex].name = this.newProfileName;
+ profiles[oldNameIndex].color = this.newProfileColor;
+ settingsDb.update({
+ _id: 'profileList'
+ }, {
+ value: profiles
+ }, {}, function (err, numUpdated) {
+ if (editProfileView.profileName === settingsView.defaultProfile) {
+ settingsDb.update({
+ _id: 'defaultProfile',
+ }, {
+ $set: {
+ value: editProfileView.newProfileName
+ }
+ }, (err, numRemoved) => {
+ console.log(numRemoved);
+ });
+ }
+
+ subDb.update({
+ profile: {
+ $elemMatch: {
+ value: editProfileView.profileName
+ }
+ },
+ }, {
+ $push: {
+ profile: {
+ value: editProfileView.newProfileName
+ }
+ }
+ }, {
+ multi: true
+ }, (err, numRemoved) => {
+ if (err) {
+ console.log(err);
+ }
+
+ let profileIndex = profileSelectView.profileList.findIndex(x => x.name === editProfileView.profileName);
+
+ profileSelectView.profileList[profileIndex].name = editProfileView.newProfileName;
+ profileSelectView.profileList[profileIndex].color = editProfileView.newProfileColor;
+ profileSelectView.setActiveProfile(profileIndex);
+
+ let subMap = subscriptionView.fullVideoList.map(x => x.profile.map(x => x.value).indexOf(editProfileView.profileName) !== -1);
+
+ for (let i = 0; i < subMap.length; i++) {
+ if (subMap[i]) {
+ let subProfileIndex = subscriptionView.fullVideoList[i].profile.findIndex(x => x.value === editProfileView.profileName);
+ subscriptionView.fullVideoList[i].profile.splice(subProfileIndex, 1);
+ subscriptionView.fullVideoList[i].profile.push(editProfileView.newProfileName);
+ }
+ }
+
+ if (editProfileView.profileName !== editProfileView.newProfileName) {
+ subDb.update({
+ profile: {
+ $elemMatch: {
+ value: editProfileView.profileName
+ }
+ },
+ }, {
+ $pull: {
+ profile: {
+ value: editProfileView.profileName
+ }
+ }
+ }, {
+ multi: true
+ }, (err, numRemoved) => {
+ if (err) {
+ console.log(err);
+ }
+ });
+ }
+
+ editProfileView.profileName = editProfileView.newProfileName;
+ editProfileView.profileColor = editProfileView.newProfileColor;
+ window.setTimeout(() => {
+ // Refresh the list of subscriptions on the side navigation bar and subscriptions view.
+ displaySubs();
+ addSubsToView(subscriptionView.fullVideoList);
+ showToast('Profile has been successfully updated!');
+ }, 100);
+ });
+ });
+ }
+ });
+ }
+ } else {
+ showToast('The current HEX value is not valid, please fix and try again.');
+ }
+ },
+ move: function () {
+ if (this.amountSelected === 0) {
+ showToast('A channel must be selected before it can be moved.');
+ return;
+ }
+ if (this.selectedProfile === '') {
+ showToast('A profile must be selected first before channels can be moved.');
+ return;
+ }
+ if (this.selectedProfile === this.profileName) {
+ showToast('Select a profile other than the one being edited.');
+ return;
+ }
+ let confirmString = 'Would you like to move the selected channels to the ' + this.selectedProfile + ' profile?';
+ confirmFunction(confirmString, () => {
+ let amountRemoved = 0;
+ this.subscriptionList.forEach(channel => {
+ if (channel.checked) {
+ subDb.update({
+ channelId: channel.channelId,
+ }, {
+ $push: {
+ profile: {
+ value: this.selectedProfile
+ }
+ }
+ }, (err, numRemoved) => {
+ if (err) {
+ console.log(err);
+ }
+ });
+
+ channel.profile = this.selectedProfile;
+ amountRemoved++;
+
+ subDb.update({
+ channelId: channel.channelId,
+ }, {
+ $pull: {
+ profile: {
+ value: this.profileName
+ }
+ }
+ }, (err, numRemoved) => {
+ if (err) {
+ console.log(err);
+ }
+ let subMap = subscriptionView.fullVideoList.map(x => x.author === channel.channelName && x.profile.map(x => x.value).indexOf(this.profileName) !== -1);
+
+ for (let i = 0; i < subMap.length; i++) {
+ if (subMap[i] !== false) {
+ subscriptionView.fullVideoList[i].profile.push({
+ value: this.selectedProfile
+ });
+ let profileIndex = subscriptionView.fullVideoList[i].profile.findIndex(x => x.value === this.profileName);
+
+ subscriptionView.fullVideoList[i].profile.splice(profileIndex, 1);
+ }
+ }
+
+ let index = this.subscriptionList.findIndex(x => x.channelName === channel.channelName);
+
+ this.subscriptionList.splice(index, 1);
+ });
+ }
+ });
+ window.setTimeout(() => {
+ // Refresh the list of subscriptions on the side navigation bar and subscriptions view.
+ displaySubs();
+ addSubsToView(subscriptionView.fullVideoList);
+ showToast('Moved ' + amountRemoved + ' channel(s) to the ' + this.selectedProfile + ' profile.');
+ }, 500);
+ });
+ },
+ copy: function () {
+ if (this.amountSelected === 0) {
+ showToast('A channel must be selected before it can be moved.');
+ return;
+ }
+ if (this.selectedProfile === '') {
+ showToast('A profile must be selected first before channels can be moved.');
+ return;
+ }
+ if (this.selectedProfile === this.profileName) {
+ showToast('Select a profile other than the one being edited.');
+ return;
+ }
+ let confirmString = 'Would you like to copy the selected channels to the ' + this.selectedProfile + ' profile?';
+ confirmFunction(confirmString, () => {
+ let amountCopied = 0;
+ this.subscriptionList.forEach(channel => {
+ if (channel.checked) {
+ subDb.find({
+ channelId: channel.channelId,
+ profile: {
+ $elemMatch: {
+ value: this.selectedProfile
+ }
+ }
+ }, {}, (err, subs) => {
+ if (subs.length === 0) {
+ channel.profile.push(this.selectedProfile);
+ subDb.update({
+ channelId: channel.channelId,
+ }, {
+ $push: {
+ profile: {
+ value: this.selectedProfile
+ }
+ }
+ }, (err, numAdded) => {
+ if (err) {
+ console.log(err);
+ }
+ let subMap = subscriptionView.fullVideoList.map(x => x.author === channel.channelName);
+
+ for (let i = 0; i < subMap.length; i++) {
+ if (subMap[i] !== false) {
+ subscriptionView.fullVideoList[i].profile.push({
+ value: this.selectedProfile
+ });
+ }
+ }
+ amountCopied++;
+ });
+ }
+ });
+ }
+ });
+ window.setTimeout(() => {
+ // Refresh the list of subscriptions on the side navigation bar and subscriptions view.
+ displaySubs();
+ addSubsToView(subscriptionView.fullVideoList);
+ showToast('Copied ' + amountCopied + ' channel(s) to the ' + this.selectedProfile + ' profile.');
+ }, 500);
+ });
+ },
+ deleteChannel: function () {
+ let confirmString = 'Are you sure you want to delete the selected channels from this profile?';
+ let amountDeleted = 0;
+
+ confirmFunction(confirmString, () => {
+ this.subscriptionList.forEach((channel, index) => {
+ if (channel.checked) {
+ subDb.update({
+ channelId: channel.channelId,
+ }, {
+ $pull: {
+ profile: {
+ value: editProfileView.profileName
+ }
+ }
+ }, {
+ multi: true
+ }, (err, numRemoved) => {
+ if (err) {
+ console.log(err);
+ }
+
+ let subMap = subscriptionView.fullVideoList.map(x => x.author === channel.channelName);
+
+ for (let i = 0; i < subMap.length; i++) {
+ if (subMap[i]) {
+ let subProfileIndex = subscriptionView.fullVideoList[i].profile.findIndex(x => x.value === editProfileView.profileName);
+ subscriptionView.fullVideoList[i].profile.splice(subProfileIndex, 1);
+ }
+ }
+
+ editProfileView.subscriptionList.splice(index, 1);
+ });
+
+ amountDeleted++;
+ }
+ });
+ window.setTimeout(() => {
+ // Refresh the list of subscriptions on the side navigation bar and subscriptions view.
+ displaySubs();
+ addSubsToView(subscriptionView.fullVideoList);
+ showToast(amountDeleted + ' channel(s) have been deleted from this profile.');
+ }, 500);
+ });
+ },
+ },
+ computed: {
+ isDefaultProfile: function () {
+ return settingsView.defaultProfile === this.profileName;
+ },
+ profileList: function () {
+ return profileSelectView.profileList;
+ },
+ amountSelected: function () {
+ let amount = 0;
+ this.subscriptionList.forEach((item) => {
+ if (item.checked) {
+ amount++;
+ }
+ });
+ return amount;
+ }
+ },
+ template: editProfileViewTemplate
});
function hideViews() {
- if (playerView.seen !== false && (playerView.playerSeen || playerView.legacySeen)) {
- let lengthSeconds = 0;
- let duration = 0;
+ if (playerView.seen !== false && (playerView.playerSeen || playerView.legacySeen)) {
+ let lengthSeconds = 0;
+ let duration = 0;
- if (playerView.legacySeen === false) {
- lengthSeconds = player.currentTime;
- duration = player.duration;
- }
- else {
- lengthSeconds = $('.videoPlayer').get(0).currentTime;
- duration = $('.videoPlayer').get(0).duration;
+ if (playerView.legacySeen === false) {
+ lengthSeconds = player.currentTime;
+ duration = player.duration;
+ } else {
+ lengthSeconds = $('.videoPlayer').get(0).currentTime;
+ duration = $('.videoPlayer').get(0).duration;
+ }
+
+ updateWatchProgress(playerView.videoId, lengthSeconds);
+
+ let videoIndex = subscriptionView.videoList.findIndex(x => x.id === playerView.videoId);
+
+ if (videoIndex !== -1) {
+ subscriptionView.videoList[videoIndex].watched = true;
+ subscriptionView.videoList[videoIndex].progressPercentage = (lengthSeconds / duration) * 100;
+ }
}
- updateWatchProgress(playerView.videoId, lengthSeconds);
-
- let videoIndex = subscriptionView.videoList.findIndex(x => x.id === playerView.videoId);
-
- if (videoIndex !== -1) {
- subscriptionView.videoList[videoIndex].watched = true;
- subscriptionView.videoList[videoIndex].progressPercentage = (lengthSeconds / duration) * 100;
- }
- }
-
- subscriptionView.seen = false;
- noSubscriptions.seen = false;
- aboutView.seen = false;
- headerView.seen = false;
- searchView.seen = false;
- settingsView.seen = false;
- popularView.seen = false;
- trendingView.seen = false;
- savedView.seen = false;
- historyView.seen = false;
- playlistView.seen = false;
- playerView.seen = false;
- channelView.seen = false;
- channelVideosView.seen = false;
- backButtonView.lastView = false;
+ subscriptionView.seen = false;
+ noSubscriptions.seen = false;
+ aboutView.seen = false;
+ headerView.seen = false;
+ searchView.seen = false;
+ settingsView.seen = false;
+ popularView.seen = false;
+ trendingView.seen = false;
+ savedView.seen = false;
+ historyView.seen = false;
+ playlistView.seen = false;
+ playerView.seen = false;
+ channelView.seen = false;
+ channelVideosView.seen = false;
+ profileSelectView.seen = false;
+ subscriptionManagerView.seen = false;
+ editProfileView.seen = false;
+ backButtonView.lastView = false;
}
diff --git a/src/style/darkTheme.css b/src/style/darkTheme.css
index 29af5a291..8b64c21a5 100644
--- a/src/style/darkTheme.css
+++ b/src/style/darkTheme.css
@@ -211,6 +211,22 @@ input[type=text] {
color: white;
}
+.profile:hover {
+ background-color: #616161;
+}
+
+.profileEditSelected {
+ background-color: #424242;
+}
+
+.profileSelectSettings {
+ background-color: #9E9E9E;
+}
+
+.profileEditPadding:hover {
+ background-color: #616161;
+}
+
#main {
color: #EEEEEE;
}
@@ -291,3 +307,12 @@ input[type=text] {
#miniPL {
background-color: #424242;
}
+
+#profileSelect {
+ background-color: #424242;
+ color: white;
+}
+
+#profileSelectHeader span:hover {
+ background-color: #616161;
+}
diff --git a/src/style/lightTheme.css b/src/style/lightTheme.css
index c5d764f08..dbaf9a711 100644
--- a/src/style/lightTheme.css
+++ b/src/style/lightTheme.css
@@ -180,6 +180,22 @@ body {
color: black;
}
+.profile:hover {
+ background-color: #e0e0e0;
+}
+
+.profileEditSelected {
+ background-color: #424242;
+}
+
+.profileSelectSettings {
+ background-color: #9E9E9E;
+}
+
+.profileEditPadding:hover {
+ background-color: #e0e0e0;
+}
+
#subscriptions img {
border: 0px solid #000000;
}
@@ -229,3 +245,11 @@ body {
#miniPL {
background-color: white;
}
+
+#profileSelect {
+ background-color: white;
+}
+
+#profileSelectHeader span:hover {
+ background-color: #e0e0e0;
+}
diff --git a/src/style/main.css b/src/style/main.css
index 89b6a5f51..aeaaf2a37 100644
--- a/src/style/main.css
+++ b/src/style/main.css
@@ -43,20 +43,20 @@ a {
}
.link {
- color: #2196F3;
- cursor: pointer;
- font-weight: bold;
- font-decoration-line: 'underline';
+ color: #2196F3;
+ cursor: pointer;
+ font-weight: bold;
+ font-decoration-line: 'underline';
}
-#progressBar{
- height: 3px;
- background-color: #f44336;
- display: block;
- position: fixed;
- bottom: 0;
- left: 0;
- z-index: 1;
+#progressBar {
+ height: 3px;
+ background-color: #f44336;
+ display: block;
+ position: fixed;
+ bottom: 0;
+ left: 0;
+ z-index: 1;
}
.center {
@@ -86,7 +86,7 @@ a {
font-size: 20px;
margin-left: 20px;
position: relative;
- top: 3px;
+ bottom: 10px;
}
#reloadButton {
@@ -101,30 +101,230 @@ a {
font-size: 20px;
margin-left: 20px;
position: relative;
- top: 3px;
+ bottom: 10px;
}
#menuIcon {
width: 25px;
position: relative;
- top: 15px;
- right: 120px;
- float: right;
+ left: 20px;
+ bottom: 5px;
}
#menuText {
width: 100px;
position: relative;
- top: 5px;
- left: 10px;
+ top: 7px;
+ left: 15px;
+}
+
+#currentProfile {
+ width: 40px;
+ height: 40px;
+ position: absolute;
+ right: 10px;
+ top: 10px;
+ cursor: pointer;
+ border-radius: 200px 200px 200px 200px;
+ -webkit-border-radius: 200px 200px 200px 200px;
+}
+
+#currentInitial {
+ font-size: 22px;
+ text-align: center;
+ position: relative;
+ left: 13px;
+ bottom: 10px;
+}
+
+#profileSelect {
+ width: 275px;
+ position: absolute;
+ right: 30px;
+ top: 50px;
+ -webkit-box-shadow: -15px 25px 50px -30px rgba(0, 0, 0, 0.75);
+ -moz-box-shadow: -15px 25px 50px -30px rgba(0, 0, 0, 0.75);
+ box-shadow: -15px 25px 50px -30px rgba(0, 0, 0, 0.75);
+}
+
+#profileSelectHeader {
+ height: 55px;
+ margin-top: 0px;
+ margin-bottom: 0px;
+ line-height: 55px;
+ padding-left: 10px;
+}
+
+#profileSelectHeader span {
float: right;
+ width: 40px;
+ height: 40px;
+ margin-right: 10px;
+ margin-top: 5px;
+ cursor: pointer;
+ border-radius: 200px 200px 200px 200px;
+ -webkit-border-radius: 200px 200px 200px 200px;
+ -webkit-transition: background 0.2s ease-out;
+ -moz-transition: background 0.2s ease-out;
+ -o-transition: background 0.2s ease-out;
+ transition: background 0.2s ease-out;
+}
+
+#profileSelectHeader span:hover {
+ -moz-transition: background 0.2s ease-in;
+ -o-transition: background 0.2s ease-in;
+ transition: background 0.2s ease-in;
+}
+
+#profileSelectHeader i {
+ font-size: 15px;
+ position: relative;
+ left: 11px;
+ top: 8px;
+}
+
+#profileSelectList {
+ overflow-y: auto;
+ overflow-x: hidden;
+ max-height: 400px;
+}
+
+.profile {
+ width: 265px;
+ height: 30px;
+ padding-top: 10px;
+ padding-left: 10px;
+ padding-bottom: 10px;
+ cursor: pointer;
+ -webkit-transition: background 0.2s ease-out;
+ -moz-transition: background 0.2s ease-out;
+ -o-transition: background 0.2s ease-out;
+ transition: background 0.2s ease-out;
+}
+
+.profile:hover {
+ -moz-transition: background 0.2s ease-in;
+ -o-transition: background 0.2s ease-in;
+ transition: background 0.2s ease-in;
+}
+
+.profileBackground {
+ display: inline-block;
+ width: 30px;
+ height: 30px;
+ float: left;
+ border-radius: 200px 200px 200px 200px;
+ -webkit-border-radius: 200px 200px 200px 200px;
+}
+
+.profileEditSelected {
+ display: inline-block;
+ width: 50px;
+ height: 50px;
+ float: left;
+ position: absolute;
+ margin-left: -50px;
+ opacity: 0.8;
+ border-radius: 200px 200px 200px 200px;
+ -webkit-border-radius: 200px 200px 200px 200px;
+}
+
+.profileEditSelected i {
+ font-size: 22px;
+ position: relative;
+ top: 16px;
+}
+
+.profileInitial {
+ font-size: 15px;
+ display: inline-block;
+ position: relative;
+ left: 10px;
+ bottom: 16px;
+}
+
+.profileName {
+ display: inline-block;
+ position: relative;
+ bottom: 30px;
+ left: 10px;
+}
+
+.profileSelectSettings {
+ margin: 0 auto;
+ line-height: 55px;
+}
+
+.profileSelectSettings i {
+ position: relative;
+ left: 15px;
+ bottom: 2px;
+}
+
+.colorPicker {
+ display: inline-block;
+ width: 80px;
+ height: 80px;
+ border-radius: 200px 200px 200px 200px;
+ -webkit-border-radius: 200px 200px 200px 200px;
+}
+
+.colorPicker span {
+ position: relative;
+ top: 15px;
+}
+
+.colorPickerPadding {
+ display: inline-block;
+ width: 80px;
+ height: 80px;
+ padding: 10px;
+}
+
+.profileEdit {
+ display: inline-block;
+ width: 50px;
+ height: 50px;
+ margin-bottom: 5px;
+ border-radius: 200px 200px 200px 200px;
+ -webkit-border-radius: 200px 200px 200px 200px;
+}
+
+.profileEditInitial {
+ font-size: 25px;
+ position: relative;
+ top: 11px;
+}
+
+.profileEditName {
+ font-size: 13px;
+ height: 60px;
+ overflow: hidden;
+}
+
+.profileEditPadding {
+ display: inline-block;
+ width: 100px;
+ height: 115px;
+ padding: 10px;
+ cursor: pointer;
+ -webkit-transition: background 0.2s ease-out;
+ -moz-transition: background 0.2s ease-out;
+ -o-transition: background 0.2s ease-out;
+ transition: background 0.2s ease-out;
+}
+
+.profileEditPadding:hover {
+ -moz-transition: background 0.2s ease-in;
+ -o-transition: background 0.2s ease-in;
+ transition: background 0.2s ease-in;
}
.searchBar {
position: absolute;
- right: 30px;
+ right: -75px;
top: 0;
- width: 800px;
+ width: 750px;
}
.searchBar input {
@@ -133,10 +333,10 @@ a {
}
#searchFilter {
- width: 90%;
- padding: 10px;
- margin-bottom: 20px;
- -webkit-box-shadow: 4px -2px 51px -6px rgba(0, 0, 0, 0.75);
+ width: 90%;
+ padding: 10px;
+ margin-bottom: 20px;
+ -webkit-box-shadow: 4px -2px 51px -6px rgba(0, 0, 0, 0.75);
}
.searchButton {
@@ -145,18 +345,18 @@ a {
}
.filterButton {
- text-decoration: none;
- margin-right: 10px;
- cursor: pointer;
+ text-decoration: none;
+ margin-right: 10px;
+ cursor: pointer;
}
.filter {
- width: 180px;
- height: 295px;
- padding: 10px;
- border-right: 1px solid #f44336;
- display: inline-block;
- text-align: left;
+ width: 180px;
+ height: 295px;
+ padding: 10px;
+ border-right: 1px solid #f44336;
+ display: inline-block;
+ text-align: left;
}
#sideNav {
@@ -241,14 +441,14 @@ a {
}
#loading {
- width: 75%;
- height: 20%;
- margin: auto;
- position: absolute;
- top: 0;
- left: 5;
- bottom: 0;
- right: 0;
+ width: 75%;
+ height: 20%;
+ margin: auto;
+ position: absolute;
+ top: 0;
+ left: 5;
+ bottom: 0;
+ right: 0;
}
.settingsInput {
@@ -257,27 +457,27 @@ a {
}
.settingsSlider {
- padding: 30px;
+ padding: 30px;
}
#confirmSettings {
- position: fixed;
- margin-left: 250px;
- margin-right: auto;
- left: 4%;
- right: 4%;
- bottom: 20px;
- height: 50px;
- background-color: #212121;
- color: #f5f5f5;
- padding: 10px;
- opacity: 0;
- z-index: 1;
- -webkit-box-shadow: 4px -2px 51px -6px rgba(0, 0, 0, 0.75);
- -webkit-transition: opacity 0.4s ease-in-out;
- -moz-transition: opacity 0.4s ease-in-out;
- -ms-transition: opacity 0.4s ease-in-out;
- -o-transition: opacity 0.4s ease-in-out;
+ position: fixed;
+ margin-left: 250px;
+ margin-right: auto;
+ left: 4%;
+ right: 4%;
+ bottom: 20px;
+ height: 50px;
+ background-color: #212121;
+ color: #f5f5f5;
+ padding: 10px;
+ opacity: 0;
+ z-index: 1;
+ -webkit-box-shadow: 4px -2px 51px -6px rgba(0, 0, 0, 0.75);
+ -webkit-transition: opacity 0.4s ease-in-out;
+ -moz-transition: opacity 0.4s ease-in-out;
+ -ms-transition: opacity 0.4s ease-in-out;
+ -o-transition: opacity 0.4s ease-in-out;
}
.input-text-settings input {
@@ -315,14 +515,14 @@ a {
}
.card {
- margin: 0 auto;
- width: 90%;
- text-align: center;
- padding: 10px;
- margin-bottom: 30px;
- -webkit-box-shadow: 4px 4px 10px 0px rgba(0, 0, 0, 0.75);
- -moz-box-shadow: 4px 4px 10px 0px rgba(0, 0, 0, 0.75);
- box-shadow: 4px 4px 10px 0px rgba(0, 0, 0, 0.75);
+ margin: 0 auto;
+ width: 90%;
+ text-align: center;
+ padding: 10px;
+ margin-bottom: 30px;
+ -webkit-box-shadow: 4px 4px 10px 0px rgba(0, 0, 0, 0.75);
+ -moz-box-shadow: 4px 4px 10px 0px rgba(0, 0, 0, 0.75);
+ box-shadow: 4px 4px 10px 0px rgba(0, 0, 0, 0.75);
}
.help {
@@ -413,15 +613,15 @@ a {
}
.blogFeed a {
- font-size: 20px;
- font-weight: bold;
+ font-size: 20px;
+ font-weight: bold;
}
@media only screen and (max-width: 900px) {
- .searchBar {
- width: 500px;
- right: 80px;
- }
+ .searchBar {
+ width: 500px;
+ right: -15px;
+ }
}
/* Thanks to Guus Lieben for the Material Design Switch */
diff --git a/src/style/player.css b/src/style/player.css
index a695c0307..211054c4d 100644
--- a/src/style/player.css
+++ b/src/style/player.css
@@ -28,14 +28,15 @@ iframe {
.videoPlayer {
width: 100%;
height: 100%;
+ touch-action: none;
}
#player {
- min-width: 100%;
+ min-width: 100%;
}
#legacyPlayer {
- max-height: 80vh;
+ max-height: 80vh;
}
.statistics {
diff --git a/src/templates/currentProfileView.html b/src/templates/currentProfileView.html
new file mode 100644
index 000000000..6846de9bb
--- /dev/null
+++ b/src/templates/currentProfileView.html
@@ -0,0 +1,5 @@
+
Search Filters
-- - - - + -
-
+
+
+
-
+
@@ -192,4 +195,5 @@
+
diff --git a/src/js/events.js b/src/js/events.js
index 3da07e5df..008ab69c6 100644
--- a/src/js/events.js
+++ b/src/js/events.js
@@ -31,28 +31,28 @@ let showComments = function (event, continuation = '') {
comments.attr('loaded', 'true');
invidiousAPI('comments', $('#comments').attr('data-video-id'), {}, (data) => {
- ft.log(data);
+ ft.log(data);
- let comments = [];
+ let comments = [];
- data.comments.forEach((object) => {
+ data.comments.forEach((object) => {
- let snippet = {
- author: object.author,
- authorId: object.authorId,
- authorThumbnail: object.authorThumbnails[0].url,
- published: object.publishedText,
- authorComment: object.content,
- }
+ let snippet = {
+ author: object.author,
+ authorId: object.authorId,
+ authorThumbnail: object.authorThumbnails[0].url,
+ published: object.publishedText,
+ authorComment: object.content,
+ }
- comments.push(snippet);
- })
- const commentsTemplate = require('./templates/comments.html');
- const html = mustache.render(commentsTemplate, {
- comments: comments,
- });
+ comments.push(snippet);
+ })
+ const commentsTemplate = require('./templates/comments.html');
+ const html = mustache.render(commentsTemplate, {
+ comments: comments,
+ });
- $('#comments').html(html);
+ $('#comments').html(html);
});
comments.show();
@@ -67,49 +67,47 @@ let showComments = function (event, continuation = '') {
let playPauseVideo = function (event) {
let el = event.currentTarget;
if (el.paused && $('.videoPlayer').is(':hover')) {
- $('.videoPlayer')[0].style.cursor = 'none';
+ $('.videoPlayer')[0].style.cursor = 'none';
}
};
/**
-* Handle keyboard shortcut commands.
-*/
+ * Handle keyboard shortcut commands.
+ */
let videoShortcutHandler = function (event) {
let videoPlayer;
if (event.which == 68 && event.altKey === true) {
- $('#search').focus();
+ $('#search').focus();
}
if (event.which == 82 && event.shiftKey === false && event.ctrlKey === true && !$('#jumpToInput').is(':focus') && !$('#search').is(':focus')) {
- event.stopPropagation();
- event.preventDefault();
- forceSubscriptions();
+ event.stopPropagation();
+ event.preventDefault();
+ forceSubscriptions();
}
- if ((typeof(playerView) !== 'undefined' && playerView.legacySeen) || (typeof(miniPlayerView) !== 'undefined' && miniPlayerView.legacySeen)) {
- videoPlayer = $('.videoPlayer').get(0);
- }
- else {
- videoPlayer = $('#player').get(0);
+ if ((typeof (playerView) !== 'undefined' && playerView.legacySeen) || (typeof (miniPlayerView) !== 'undefined' && miniPlayerView.legacySeen)) {
+ videoPlayer = $('.videoPlayer').get(0);
+ } else {
+ videoPlayer = $('#player').get(0);
}
- if (typeof(videoPlayer) !== 'undefined' && !$('#jumpToInput').is(':focus') && !$('#search').is(':focus')) {
+ if (typeof (videoPlayer) !== 'undefined' && !$('#jumpToInput').is(':focus') && !$('#search').is(':focus')) {
switch (event.which) {
case 32:
// Space Bar
event.preventDefault();
if ($('.videoPlayer').is(':focus')) {
- return;
+ return;
}
if (videoPlayer.paused) {
- videoPlayer.play();
- if($('.videoPlayer').is(':hover')) {
- $('.videoPlayer')[0].style.cursor = 'none';
- }
- }
- else {
- videoPlayer.pause();
+ videoPlayer.play();
+ if ($('.videoPlayer').is(':hover')) {
+ $('.videoPlayer')[0].style.cursor = 'none';
+ }
+ } else {
+ videoPlayer.pause();
}
break;
case 74:
@@ -121,13 +119,12 @@ let videoShortcutHandler = function (event) {
// K Key
event.preventDefault();
if (videoPlayer.paused) {
- videoPlayer.play();
- if($('.videoPlayer').is(':hover')) {
- $('.videoPlayer')[0].style.cursor = 'none';
- }
- }
- else {
- videoPlayer.pause();
+ videoPlayer.play();
+ if ($('.videoPlayer').is(':hover')) {
+ $('.videoPlayer')[0].style.cursor = 'none';
+ }
+ } else {
+ videoPlayer.pause();
}
break;
case 76:
@@ -138,19 +135,19 @@ let videoShortcutHandler = function (event) {
case 79:
// O Key
event.preventDefault();
- if (videoPlayer.playbackRate > 0.25){
- let rate = videoPlayer.playbackRate - 0.25;
- videoPlayer.playbackRate = rate;
- changeVideoSpeed(rate);
+ if (videoPlayer.playbackRate > 0.25) {
+ let rate = videoPlayer.playbackRate - 0.25;
+ videoPlayer.playbackRate = rate;
+ changeVideoSpeed(rate);
}
break;
case 80:
// P Key
event.preventDefault();
- if (videoPlayer.playbackRate < 2){
- let rate = videoPlayer.playbackRate + 0.25;
- videoPlayer.playbackRate = rate;
- changeVideoSpeed(rate);
+ if (videoPlayer.playbackRate < 2) {
+ let rate = videoPlayer.playbackRate + 0.25;
+ videoPlayer.playbackRate = rate;
+ changeVideoSpeed(rate);
}
break;
case 70:
@@ -172,22 +169,20 @@ let videoShortcutHandler = function (event) {
case 67:
// C Key
if (playerView.legacySeen) {
- let subtitleMode = videoPlayer.textTracks[0].mode;
- if (subtitleMode === 'hidden') {
- videoPlayer.textTracks[0].mode = 'showing'
- } else {
- videoPlayer.textTracks[0].mode = 'hidden'
- }
- }
- else {
- let captionOptions = $('.mejs__captions-selector-input').get();
+ let subtitleMode = videoPlayer.textTracks[0].mode;
+ if (subtitleMode === 'hidden') {
+ videoPlayer.textTracks[0].mode = 'showing'
+ } else {
+ videoPlayer.textTracks[0].mode = 'hidden'
+ }
+ } else {
+ let captionOptions = $('.mejs__captions-selector-input').get();
- if (!captionOptions[0].labels[0].className.includes('mejs__captions-selected')) {
- captionOptions[0].click();
- }
- else {
- captionOptions[1].click();
- }
+ if (!captionOptions[0].labels[0].className.includes('mejs__captions-selected')) {
+ captionOptions[0].click();
+ } else {
+ captionOptions[1].click();
+ }
}
break;
case 38:
@@ -265,31 +260,30 @@ let videoShortcutHandler = function (event) {
};
let fullscreenVideo = function (event) {
- if (playerView.legacySeen) {
- if (document.webkitFullscreenElement !== null) {
- document.webkitExitFullscreen();
+ if (playerView.legacySeen) {
+ if (document.webkitFullscreenElement !== null) {
+ document.webkitExitFullscreen();
+ } else {
+ $('.videoPlayer').get(0).webkitRequestFullscreen();
+ }
} else {
- $('.videoPlayer').get(0).webkitRequestFullscreen();
- }
- }
- else {
- $('.mejs__fullscreen-button').click();
+ $('.mejs__fullscreen-button').click();
- if (document.webkitFullscreenElement !== null) {
- console.log('changing screen size...');
- const currentWindow = electron.remote.getCurrentWindow();
- let bounds = currentWindow.getBounds();
- let newBounds = {
- height: bounds.height,
- width: bounds.width + 1,
- x: bounds.x,
- y: bounds.y,
- }
+ if (document.webkitFullscreenElement !== null) {
+ console.log('changing screen size...');
+ const currentWindow = electron.remote.getCurrentWindow();
+ let bounds = currentWindow.getBounds();
+ let newBounds = {
+ height: bounds.height,
+ width: bounds.width + 1,
+ x: bounds.x,
+ y: bounds.y,
+ }
- currentWindow.setBounds(newBounds);
- currentWindow.setBounds(bounds);
+ currentWindow.setBounds(newBounds);
+ currentWindow.setBounds(bounds);
+ }
}
- }
}
/**
@@ -310,24 +304,38 @@ $(document).on('click', '#confirmNo', hideConfirmFunction);
// Open links externally by default
$(document).on('click', 'a[href^="http"]', (event) => {
- let el = event.currentTarget;
- if (!el.href.includes('freetube://')) {
- event.preventDefault();
- shell.openExternal(el.href);
- }
- else{
- search(el.href);
- }
+ let el = event.currentTarget;
+ if (!el.href.includes('freetube://')) {
+ event.preventDefault();
+ shell.openExternal(el.href);
+ } else {
+ search(el.href);
+ }
});
// Open links externally on middle click.
$(document).on('auxclick', 'a[href^="http"]', (event) => {
- let el = event.currentTarget;
- if (!el.href.includes('freetube://')) {
- event.preventDefault();
- shell.openExternal(el.href);
- }
- else{
- search(el.href);
- }
+ let el = event.currentTarget;
+ if (!el.href.includes('freetube://')) {
+ event.preventDefault();
+ shell.openExternal(el.href);
+ } else {
+ search(el.href);
+ }
+});
+
+window.addEventListener('mousewheel', function (event) {
+ if (playerView.seen !== false && $('.mejs__volume-slider').is(':hover')) {
+ event.stopPropagation();
+ event.preventDefault();
+ if (event.deltaY <= 0) {
+ // Scroll up
+ changeVolume(0.05);
+ } else {
+ // Scroll down
+ changeVolume(-0.05);
+ }
+ }
+}, {
+ passive: false
});
diff --git a/src/js/init.js b/src/js/init.js
index 86c0c8f00..b6f1aa279 100644
--- a/src/js/init.js
+++ b/src/js/init.js
@@ -72,7 +72,7 @@ let init = function () {
height: 800,
autoHideMenuBar: true,
webPreferences: {
- nodeIntegration: true,
+ nodeIntegration: true,
},
icon: path.join(__dirname, '..', 'icons', 'iconColor.png')
});
@@ -85,11 +85,11 @@ let init = function () {
let monitorList = screen.getAllDisplays();
let width = 0;
for (let i = 0; i < monitorList.length - 1; i++) {
- width = width + monitorList[i].size.width;
+ width = width + monitorList[i].size.width;
}
if (width <= doc.value.x) {
- win.setBounds(doc.value);
+ win.setBounds(doc.value);
}
}
}
@@ -103,22 +103,21 @@ let init = function () {
_id: 'proxy'
}, (err, doc) => {
if (doc !== null) {
- win.webContents.session.setProxy({
- proxyRules: doc.value
- }, function () {
- win.loadURL(url.format({
- pathname: path.join(__dirname, '../index.html'),
- protocol: 'file:',
- slashes: true,
- }));
- });
- }
- else {
- win.loadURL(url.format({
- pathname: path.join(__dirname, '../index.html'),
- protocol: 'file:',
- slashes: true,
- }));
+ win.webContents.session.setProxy({
+ proxyRules: doc.value
+ }, function () {
+ win.loadURL(url.format({
+ pathname: path.join(__dirname, '../index.html'),
+ protocol: 'file:',
+ slashes: true,
+ }));
+ });
+ } else {
+ win.loadURL(url.format({
+ pathname: path.join(__dirname, '../index.html'),
+ protocol: 'file:',
+ slashes: true,
+ }));
}
});
} else {
@@ -267,8 +266,8 @@ let init = function () {
*/
let allWindowsClosed = function () {
if (win !== null) {
- win.webContents.session.clearStorageData([], (data) => {});
- win.webContents.session.clearCache((data) => {});
+ win.webContents.session.clearStorageData([], (data) => {});
+ win.webContents.session.clearCache((data) => {});
}
app.quit();
};
@@ -284,20 +283,20 @@ let active = function () {
};
if (!gotTheLock) {
- app.quit()
+ app.quit()
} else {
- app.on('second-instance', (event, commandLine, workingDirectory) => {
- // Someone tried to run a second instance, we should focus our window.
- if (win) {
- if (win.isMinimized()) win.restore()
- win.focus()
+ app.on('second-instance', (event, commandLine, workingDirectory) => {
+ // Someone tried to run a second instance, we should focus our window.
+ if (win) {
+ if (win.isMinimized()) win.restore()
+ win.focus()
- win.webContents.send('ping', commandLine)
- }
- })
+ win.webContents.send('ping', commandLine)
+ }
+ })
- // Create myWindow, load the rest of the app, etc...
- app.on('ready', init);
+ // Create myWindow, load the rest of the app, etc...
+ app.on('ready', init);
}
/**
diff --git a/src/js/layout.js b/src/js/layout.js
index a816fed29..9b2f8033b 100644
--- a/src/js/layout.js
+++ b/src/js/layout.js
@@ -45,14 +45,14 @@ let dialog = electron.remote.dialog; // Used for opening file browser to export
let toastTimeout; // Timeout for toast notifications.
let mouseTimeout; // Timeout for hiding the mouse cursor on video playback
-require.extensions['.html'] = function(module, filename) {
+require.extensions['.html'] = function (module, filename) {
module.exports = fs.readFileSync(filename, 'utf8');
};
// Grabs the default settings from the settings database file. Makes defaults if
// none are found.
-electron.ipcRenderer.on('ping', function(event, message) {
+electron.ipcRenderer.on('ping', function (event, message) {
ft.log(message);
let url = message[message.length - 1];
if (url) {
@@ -63,7 +63,7 @@ electron.ipcRenderer.on('ping', function(event, message) {
});
// Listens for proxy to be set in main process
-electron.ipcRenderer.on('proxyAvailable', function(event, message) {
+electron.ipcRenderer.on('proxyAvailable', function (event, message) {
proxyAvailable = true;
});
@@ -88,39 +88,38 @@ $(document).ready(() => {
_id: 'invidious'
}]
}, (err, docs) => {
- if (typeof(docs[0]) !== 'undefined') {
- invidiousInstance = docs[0].value;
+ if (typeof (docs[0]) !== 'undefined') {
+ invidiousInstance = docs[0].value;
}
loadingView.seen = true;
- if (typeof(docs[1]) !== 'undefined') {
+ if (typeof (docs[1]) !== 'undefined') {
switch (docs[1].value) {
- case 'subscriptions':
- sideNavBar.subscriptions();
- break;
- case 'trending':
- sideNavBar.trending();
- break;
- case 'popular':
- sideNavBar.popular();
- break;
- case 'favorites':
- sideNavBar.saved();
- break;
- case 'history':
- sideNavBar.history();
- break;
+ case 'subscriptions':
+ sideNavBar.subscriptions();
+ break;
+ case 'trending':
+ sideNavBar.trending();
+ break;
+ case 'popular':
+ sideNavBar.popular();
+ break;
+ case 'favorites':
+ sideNavBar.saved();
+ break;
+ case 'history':
+ sideNavBar.history();
+ break;
}
- }
- else {
- sideNavBar.subscriptions();
+ } else {
+ sideNavBar.subscriptions();
}
});
- $.get('https://write.as/freetube/feed/', function(data) {
+ $.get('https://write.as/freetube/feed/', function (data) {
aboutView.rssFeed = [];
- $(data).find("item").each(function() {
+ $(data).find("item").each(function () {
let el = $(this);
let rssData = {
title: el.find("title").text(),
@@ -147,31 +146,31 @@ function toggleSideNavigation() {
sideNav.style.display = 'inline';
mainContainer.style.marginLeft = '250px';
if (confirmSettings !== null) {
- confirmSettings.style.marginLeft = '250px';
+ confirmSettings.style.marginLeft = '250px';
}
} else {
sideNav.style.display = 'none';
mainContainer.style.marginLeft = '0px';
if (confirmSettings !== null) {
- confirmSettings.style.marginLeft = '0px';
+ confirmSettings.style.marginLeft = '0px';
}
}
if (playerView.playerSeen) {
- // This is a really dumb way to fix the issue of the video player
- // not resizing properly when the side bar is toggled.
+ // This is a really dumb way to fix the issue of the video player
+ // not resizing properly when the side bar is toggled.
- const currentWindow = electron.remote.getCurrentWindow();
- let bounds = currentWindow.getBounds();
- let newBounds = {
- height: bounds.height,
- width: bounds.width + 1,
- x: bounds.x,
- y: bounds.y,
- }
+ const currentWindow = electron.remote.getCurrentWindow();
+ let bounds = currentWindow.getBounds();
+ let newBounds = {
+ height: bounds.height,
+ width: bounds.width + 1,
+ x: bounds.x,
+ y: bounds.y,
+ }
- currentWindow.setBounds(newBounds);
- currentWindow.setBounds(bounds);
+ currentWindow.setBounds(newBounds);
+ currentWindow.setBounds(bounds);
}
}
@@ -220,20 +219,25 @@ function hideToast() {
* @return {Void}
*/
function confirmFunction(message, performFunction, parameters = '') {
+ let confirmYes = document.getElementById('confirmYes');
let confirmContainer = document.getElementById('confirmFunction');
let confirmMessage = document.getElementById('confirmMessage');
+ confirmYes.removeAttribute("onclick");
+
confirmMessage.innerHTML = message;
confirmContainer.style.visibility = 'visible';
- $(document).on('click', '#confirmYes', (event) => {
+ confirmYes.onclick = function (event) {
+ event.preventDefault();
+ event.stopPropagation();
if (parameters != '') {
performFunction(parameters);
} else {
performFunction();
}
hideConfirmFunction();
- });
+ };
}
/**
@@ -255,7 +259,7 @@ function hideConfirmFunction() {
function hideMouseTimeout() {
$('.videoPlayer')[0].style.cursor = 'default';
clearTimeout(mouseTimeout);
- mouseTimeout = window.setTimeout(function() {
+ mouseTimeout = window.setTimeout(function () {
$('.videoPlayer')[0].style.cursor = 'none';
}, 2650);
}
@@ -287,7 +291,7 @@ function proxyRequest(callback) {
let counter = 0;
// Wait for proxy to become available
- proxyCheckingInterval = setInterval(function() {
+ proxyCheckingInterval = setInterval(function () {
if (proxyAvailable) {
clearInterval(proxyCheckingInterval)
diff --git a/src/js/settings.js b/src/js/settings.js
index d47cbb523..228549bab 100644
--- a/src/js/settings.js
+++ b/src/js/settings.js
@@ -41,6 +41,24 @@ let invidiousInstance = 'https://invidio.us';
let checkedSettings = false; // Used to prevent data leak when using self-hosted Invidious Instance
let debugMode = false;
let defaultPage = 'subscriptions';
+const colorPalette = {
+ red: '#d50000',
+ pink: '#C51162',
+ purple: '#AA00FF',
+ deepPurple: '#6200EA',
+ indigo: '#304FFE',
+ blue: '#2962FF',
+ lightBlue: '#0091EA',
+ cyan: '#00B8D4',
+ teal: '#00BFA5',
+ green: '#00C853',
+ lightGreen: '#64DD17',
+ lime: '#AEEA00',
+ yellow: '#FFD600',
+ amber: '#FFAB00',
+ orange: '#FF6D00',
+ deepOrange: '#DD2C00',
+};
/**
* Display the settings screen to the user.
@@ -56,10 +74,10 @@ function updateSettingsView() {
settingsDb.find({}, (err, docs) => {
docs.forEach((setting) => {
switch (setting['_id']) {
- case 'theme':
- if (currentTheme == '') {
- currentTheme = setting['value'];
- }
+ case 'theme':
+ if (currentTheme == '') {
+ currentTheme = setting['value'];
+ }
}
});
@@ -137,6 +155,9 @@ function checkDefaultSettings() {
let newSetting;
+ let colorPaletteKeys = Object.keys(colorPalette);
+ let randomColor = colorPalette[colorPaletteKeys[colorPaletteKeys.length * Math.random() << 0]];
+
let settingDefaults = {
'theme': 'light',
'useTor': false,
@@ -159,6 +180,11 @@ function checkDefaultSettings() {
'distractionFreeMode': false,
'hideWatchedSubs': false,
'videoView': 'grid',
+ 'profileList': [{
+ name: 'Default',
+ color: randomColor
+ }, ],
+ 'defaultProfile': 'Default',
};
ft.log(settingDefaults);
@@ -180,95 +206,130 @@ function checkDefaultSettings() {
}
if (key == 'videoView') {
- enableGridView();
+ enableGridView();
+ }
+
+ if (key == 'profileList') {
+ profileSelectView.profileList = settingDefaults.profileList;
+ profileSelectView.setActiveProfile(0);
+
+ subDb.find({}, (err, docs) => {
+ if (!jQuery.isEmptyObject(docs)) {
+ docs.forEach((doc) => {
+ subDb.update({
+ channelId: doc.channelId
+ }, {
+ $set: {
+ profile: [{
+ value: 'Default'
+ }]
+ }
+ }, {}, (err, newDoc) => {
+ profileSelectView.setActiveProfile(0);
+ });
+ });
+ }
+ });
}
} else {
switch (docs[0]['_id']) {
- case 'theme':
- setTheme(docs[0]['value']);
- break;
- case 'useTor':
- useTor = docs[0]['value'];
- break;
- case 'history':
- rememberHistory = docs[0]['value'];
- break;
- case 'autoplay':
- autoplay = docs[0]['value'];
- break;
- case 'autoplayPlaylists':
- settingsView.autoplayPlaylists = docs[0]['value'];
- break;
- case 'playNextVideo':
- settingsView.playNextVideo = docs[0]['value'];
- break;
- case 'subtitles':
- enableSubtitles = docs[0]['value'];
- break;
- case 'updates':
- checkForUpdates = docs[0]['value'];
+ case 'theme':
+ setTheme(docs[0]['value']);
+ break;
+ case 'useTor':
+ useTor = docs[0]['value'];
+ break;
+ case 'history':
+ rememberHistory = docs[0]['value'];
+ break;
+ case 'autoplay':
+ autoplay = docs[0]['value'];
+ break;
+ case 'autoplayPlaylists':
+ settingsView.autoplayPlaylists = docs[0]['value'];
+ break;
+ case 'playNextVideo':
+ settingsView.playNextVideo = docs[0]['value'];
+ break;
+ case 'subtitles':
+ enableSubtitles = docs[0]['value'];
+ break;
+ case 'updates':
+ checkForUpdates = docs[0]['value'];
- if (checkForUpdates) {
- checkForNewUpdate();
- }
- break;
- case 'player':
- defaultPlayer = docs[0]['value'];
- break;
- case 'quality':
- defaultQuality = docs[0]['value'];
- break;
- case 'volume':
- defaultVolume = docs[0]['value'];
- currentVolume = docs[0]['value'];
- break;
- case 'rate':
- defaultPlaybackRate = docs[0]['value'];
- break;
- case 'proxy':
- defaultProxy = docs[0]['value'];
+ if (checkForUpdates) {
+ checkForNewUpdate();
+ }
+ break;
+ case 'player':
+ defaultPlayer = docs[0]['value'];
+ break;
+ case 'quality':
+ defaultQuality = docs[0]['value'];
+ break;
+ case 'volume':
+ defaultVolume = docs[0]['value'];
+ currentVolume = docs[0]['value'];
+ break;
+ case 'rate':
+ defaultPlaybackRate = docs[0]['value'];
+ break;
+ case 'proxy':
+ defaultProxy = docs[0]['value'];
- if (useTor && defaultProxy) {
- electron.ipcRenderer.send("setProxy", defaultProxy);
- }
- break;
- case 'invidious':
- invidiousInstance = docs[0]['value'].replace(/\/$/, '');
- settingsView.invidiousInstance = invidiousInstance;
- break;
- case 'region':
- defaultRegion = docs[0]['value'];
- settingsView.region = docs[0]['value'];
- break;
- case 'localScrape':
- getVideosLocally = docs[0]['value'];
- settingsView.localScrape = docs[0]['value'];
- break;
- case 'debugMode':
- debugMode = docs[0]['value'];
- settingsView.debugMode = docs[0]['value'];
- break;
- case 'startScreen':
- defaultPage = docs[0]['value'];
- break;
- case 'distractionFreeMode':
- settingsView.setDistractionFreeMode(docs[0]['value']);
- break;
- case 'hideWatchedSubs':
- hideWatchedSubs = docs[0]['value'];
- settingsView.hideWatchedSubs = docs[0]['value'];
- break;
- case 'videoView':
- settingsView.videoView = docs[0]['value'];
- if (settingsView.videoView == 'grid') {
- enableGridView();
- }
- else {
- enableListView();
- }
- break;
- default:
- break;
+ if (useTor && defaultProxy) {
+ electron.ipcRenderer.send("setProxy", defaultProxy);
+ }
+ break;
+ case 'invidious':
+ invidiousInstance = docs[0]['value'].replace(/\/$/, '');
+ settingsView.invidiousInstance = invidiousInstance;
+ break;
+ case 'region':
+ defaultRegion = docs[0]['value'];
+ settingsView.region = docs[0]['value'];
+ break;
+ case 'localScrape':
+ getVideosLocally = docs[0]['value'];
+ settingsView.localScrape = docs[0]['value'];
+ break;
+ case 'debugMode':
+ debugMode = docs[0]['value'];
+ settingsView.debugMode = docs[0]['value'];
+ break;
+ case 'startScreen':
+ defaultPage = docs[0]['value'];
+ break;
+ case 'distractionFreeMode':
+ settingsView.setDistractionFreeMode(docs[0]['value']);
+ break;
+ case 'hideWatchedSubs':
+ hideWatchedSubs = docs[0]['value'];
+ settingsView.hideWatchedSubs = docs[0]['value'];
+ break;
+ case 'videoView':
+ settingsView.videoView = docs[0]['value'];
+ if (settingsView.videoView == 'grid') {
+ enableGridView();
+ } else {
+ enableListView();
+ }
+ break;
+ case 'profileList':
+ profileSelectView.profileList = docs[0]['value'];
+ break;
+ case 'defaultProfile':
+ let profileIndex = profileSelectView.profileList.findIndex(x => x.name === docs[0]['value']);
+ settingsView.defaultProfile = docs[0]['value'];
+
+ if (profileIndex === -1) {
+ profileSelectView.setActiveProfile(0);
+ } else {
+ profileSelectView.setActiveProfile(profileIndex);
+ }
+ break;
+ default:
+ break;
}
}
});
@@ -334,7 +395,7 @@ function updateSettings() {
_id: 'theme'
}, {
value: theme
- }, {}, function(err, numReplaced) {
+ }, {}, function (err, numReplaced) {
ft.log(err);
ft.log(numReplaced);
});
@@ -344,7 +405,7 @@ function updateSettings() {
_id: 'useTor'
}, {
value: torSwitch
- }, {}, function(err, numReplaced) {
+ }, {}, function (err, numReplaced) {
ft.log(err);
ft.log(numReplaced);
useTor = torSwitch;
@@ -355,7 +416,7 @@ function updateSettings() {
_id: 'proxy'
}, {
value: proxyAddress
- }, {}, function(err, numReplaced) {
+ }, {}, function (err, numReplaced) {
ft.log(err);
ft.log(numReplaced);
defaultProxy = proxyAddress;
@@ -366,7 +427,7 @@ function updateSettings() {
_id: 'invidious'
}, {
value: invidious
- }, {}, function(err, numReplaced) {
+ }, {}, function (err, numReplaced) {
ft.log(err);
ft.log(numReplaced);
settingsView.invidiousInstance = invidious;
@@ -378,7 +439,7 @@ function updateSettings() {
_id: 'history'
}, {
value: historySwitch
- }, {}, function(err, numReplaced) {
+ }, {}, function (err, numReplaced) {
ft.log(err);
ft.log(numReplaced);
rememberHistory = historySwitch;
@@ -389,7 +450,7 @@ function updateSettings() {
_id: 'autoplay'
}, {
value: autoplaySwitch
- }, {}, function(err, numReplaced) {
+ }, {}, function (err, numReplaced) {
ft.log(err);
ft.log(numReplaced);
autoplay = autoplaySwitch;
@@ -400,7 +461,7 @@ function updateSettings() {
_id: 'autoplayPlaylists'
}, {
value: autoplayPlaylistsSwitch
- }, {}, function(err, numReplaced) {
+ }, {}, function (err, numReplaced) {
ft.log(err);
ft.log(numReplaced);
settingsView.autoplayPlaylists = autoplayPlaylistsSwitch;
@@ -411,7 +472,7 @@ function updateSettings() {
_id: 'playNextVideo'
}, {
value: playNextVideoSwitch
- }, {}, function(err, numReplaced) {
+ }, {}, function (err, numReplaced) {
ft.log(err);
ft.log(numReplaced);
settingsView.playNextVideo = playNextVideoSwitch;
@@ -422,7 +483,7 @@ function updateSettings() {
_id: 'localScrape'
}, {
value: localSwitch
- }, {}, function(err, numReplaced) {
+ }, {}, function (err, numReplaced) {
ft.log(err);
ft.log(numReplaced);
getVideosLocally = localSwitch;
@@ -433,7 +494,7 @@ function updateSettings() {
_id: 'subtitles'
}, {
value: subtitlesSwitch
- }, {}, function(err, numReplaced) {
+ }, {}, function (err, numReplaced) {
ft.log(err);
ft.log(numReplaced);
enableSubtitles = subtitlesSwitch;
@@ -444,7 +505,7 @@ function updateSettings() {
_id: 'updates'
}, {
value: updatesSwitch
- }, {}, function(err, numReplaced) {
+ }, {}, function (err, numReplaced) {
ft.log(err);
ft.log(numReplaced);
checkForUpdates = updatesSwitch;
@@ -455,7 +516,7 @@ function updateSettings() {
_id: 'player'
}, {
value: playerSelect
- }, {}, function(err, numReplaced) {
+ }, {}, function (err, numReplaced) {
ft.log(err);
ft.log(numReplaced);
defaultPlayer = playerSelect;
@@ -466,7 +527,7 @@ function updateSettings() {
_id: 'quality'
}, {
value: qualitySelect
- }, {}, function(err, numReplaced) {
+ }, {}, function (err, numReplaced) {
ft.log(err);
ft.log(numReplaced);
defaultQuality = qualitySelect;
@@ -477,7 +538,7 @@ function updateSettings() {
_id: 'volume'
}, {
value: volumeSelect
- }, {}, function(err, numReplaced) {
+ }, {}, function (err, numReplaced) {
ft.log(err);
ft.log(numReplaced);
defaultVolume = volumeSelect;
@@ -489,7 +550,7 @@ function updateSettings() {
_id: 'rate'
}, {
value: rateSelect
- }, {}, function(err, numReplaced) {
+ }, {}, function (err, numReplaced) {
ft.log(err);
ft.log(numReplaced);
defaultPlaybackRate = rateSelect;
@@ -500,7 +561,7 @@ function updateSettings() {
_id: 'region'
}, {
value: regionSelect
- }, {}, function(err, numReplaced) {
+ }, {}, function (err, numReplaced) {
ft.log(err);
ft.log(numReplaced);
settingsView.region = regionSelect;
@@ -511,7 +572,7 @@ function updateSettings() {
_id: 'debugMode'
}, {
value: debugMode
- }, {}, function(err, numReplaced) {
+ }, {}, function (err, numReplaced) {
ft.log(err);
ft.log(numReplaced);
settingsView.debugMode = debugMode;
@@ -522,7 +583,7 @@ function updateSettings() {
_id: 'startScreen'
}, {
value: pageSelect
- }, {}, function(err, numReplaced) {
+ }, {}, function (err, numReplaced) {
ft.log(err);
ft.log(numReplaced);
});
@@ -532,7 +593,7 @@ function updateSettings() {
_id: 'distractionFreeMode'
}, {
value: distractionFreeMode
- }, {}, function(err, numReplaced) {
+ }, {}, function (err, numReplaced) {
ft.log(err);
ft.log(numReplaced);
});
@@ -542,7 +603,7 @@ function updateSettings() {
_id: 'hideWatchedSubs'
}, {
value: hideSubs
- }, {}, function(err, numReplaced) {
+ }, {}, function (err, numReplaced) {
ft.log(err);
ft.log(numReplaced);
hideWatchedSubs = hideSubs;
@@ -554,14 +615,13 @@ function updateSettings() {
_id: 'videoView'
}, {
value: videoViewType
- }, {}, function(err, numReplaced) {
+ }, {}, function (err, numReplaced) {
ft.log(err);
ft.log(numReplaced);
if (settingsView.videoView == 'grid') {
- enableGridView();
- }
- else {
- enableListView();
+ enableGridView();
+ } else {
+ enableListView();
}
});
@@ -614,24 +674,24 @@ function setTheme(option) {
// Grab the css file to be used.
switch (option) {
- case 'light':
- cssFile = './style/lightTheme.css';
- document.getElementById('menuText').src = 'icons/textBlackSmall.png';
- document.getElementById('menuIcon').src = 'icons/iconBlackSmall.png';
- document.getElementById('menuButton').style.color = 'black';
- document.getElementById('reloadButton').style.color = 'black';
- break;
- case 'dark':
- cssFile = './style/darkTheme.css';
- document.getElementById('menuText').src = 'icons/textColorSmall.png';
- document.getElementById('menuIcon').src = 'icons/iconColorSmall.png';
- document.getElementById('menuButton').style.color = 'white';
- document.getElementById('reloadButton').style.color = 'white';
- break;
- default:
- // Default to the light theme
- cssFile = './style/lightTheme.css';
- break;
+ case 'light':
+ cssFile = './style/lightTheme.css';
+ document.getElementById('menuText').src = 'icons/textBlackSmall.png';
+ document.getElementById('menuIcon').src = 'icons/iconBlackSmall.png';
+ document.getElementById('menuButton').style.color = 'black';
+ document.getElementById('reloadButton').style.color = 'black';
+ break;
+ case 'dark':
+ cssFile = './style/darkTheme.css';
+ document.getElementById('menuText').src = 'icons/textColorSmall.png';
+ document.getElementById('menuIcon').src = 'icons/iconColorSmall.png';
+ document.getElementById('menuButton').style.color = 'white';
+ document.getElementById('reloadButton').style.color = 'white';
+ break;
+ default:
+ // Default to the light theme
+ cssFile = './style/lightTheme.css';
+ break;
}
newTheme.setAttribute("href", cssFile);
@@ -640,31 +700,31 @@ function setTheme(option) {
}
function enableGridView() {
- let cssFile;
- const currentView = document.getElementsByTagName("link").item(2);
+ let cssFile;
+ const currentView = document.getElementsByTagName("link").item(2);
- // Create a link element
- const newView = document.createElement("link");
- newView.setAttribute("rel", "stylesheet");
- newView.setAttribute("type", "text/css");
- newView.setAttribute("href", './style/videoGrid.css');
+ // Create a link element
+ const newView = document.createElement("link");
+ newView.setAttribute("rel", "stylesheet");
+ newView.setAttribute("type", "text/css");
+ newView.setAttribute("href", './style/videoGrid.css');
- // Replace the current theme with the new theme
- document.getElementsByTagName("head").item(0).replaceChild(newView, currentView);
+ // Replace the current theme with the new theme
+ document.getElementsByTagName("head").item(0).replaceChild(newView, currentView);
}
function enableListView() {
- let cssFile;
- const currentView = document.getElementsByTagName("link").item(2);
+ let cssFile;
+ const currentView = document.getElementsByTagName("link").item(2);
- // Create a link element
- const newView = document.createElement("link");
- newView.setAttribute("rel", "stylesheet");
- newView.setAttribute("type", "text/css");
- newView.setAttribute("href", './style/videoList.css');
+ // Create a link element
+ const newView = document.createElement("link");
+ newView.setAttribute("rel", "stylesheet");
+ newView.setAttribute("type", "text/css");
+ newView.setAttribute("href", './style/videoList.css');
- // Replace the current theme with the new theme
- document.getElementsByTagName("head").item(0).replaceChild(newView, currentView);
+ // Replace the current theme with the new theme
+ document.getElementsByTagName("head").item(0).replaceChild(newView, currentView);
}
/**
@@ -725,8 +785,8 @@ function importSubscriptions() {
name: 'Database File',
extensions: ['*']
}, ]
- }, function(fileLocation) {
- if (typeof(fileLocation) === 'undefined') {
+ }, function (fileLocation) {
+ if (typeof (fileLocation) === 'undefined') {
ft.log('Import Aborted');
return;
}
@@ -735,14 +795,14 @@ function importSubscriptions() {
let fileType = (i < 0) ? '' : fileLocation[0].substr(i);
ft.log(fileType);
- fs.readFile(fileLocation[0], function(readErr, data) {
+ fs.readFile(fileLocation[0], function (readErr, data) {
if (readErr) {
showToast('Unable to read file. File may be corrupt or have invalid permissions.');
throw readErr;
}
if (data.includes("
+
+
+
+ Search Filters
+
+
+
+
+
+
+
+
Your Subscription list is currently empty. Start adding subscriptions
to see them here.
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+
+
+ + + + +
+ Search Filters
++ + + + +
+
Your Subscription list is currently empty. Start adding subscriptions
to see them here.
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
Your Subscription list is currently empty. Start adding subscriptions
to see them here.
+
+
diff --git a/src/templates/editProfileView.html b/src/templates/editProfileView.html
new file mode 100644
index 000000000..758773e50
--- /dev/null
+++ b/src/templates/editProfileView.html
@@ -0,0 +1,75 @@
+
+ {{activeProfileInitial}}
+
+
+
diff --git a/src/templates/profileSelectView.html b/src/templates/profileSelectView.html
new file mode 100644
index 000000000..ae6262df1
--- /dev/null
+++ b/src/templates/profileSelectView.html
@@ -0,0 +1,11 @@
+
+
+
+
+ Subscription List for {{profileName}} Profile
+{{amountSelected}} Selected
++
+
+
+
+
+
{{channel.channelName}}
+ +
+
+
+
+
+
+
+
+
+ SELECT ALL
+
+
+ SELECT NONE
+
+
+ MOVE SELECTED
+
+
+ COPY SELECTED
+
+
+ DELETE SELECTED
+
+
+
+
+
+Add New Profile
+Edit Profile Attributes
+
+
+
+ Color Picker
+
+
+
+ +
+
+
+ +
New Profile Color
+
+
+
+
+
+
+ ADD PROFILE
+
+
+
+
+ UPDATE PROFILE
+
+
+ MAKE DEFAULT PROFILE
+
+
+ DELETE PROFILE
+
+
+
diff --git a/src/templates/settings.html b/src/templates/settings.html
index 4cf5b8763..eb793cb8d 100644
--- a/src/templates/settings.html
+++ b/src/templates/settings.html
@@ -349,6 +349,9 @@
Profile Select
+
+
+
+
+
+ {{profileInitials[index]}}
+
+ {{profile.name}}
+
+
+ MANAGE SUBSCRIPTIONS
+
IMPORT SUBSCRIPTIONS
@@ -397,13 +400,13 @@
-
+
CLEAR HISTORY
-
+
CLEAR FAVORITED VIDEOS
-
+
diff --git a/src/templates/subscriptionManagerView.html b/src/templates/subscriptionManagerView.html
new file mode 100644
index 000000000..e95c40b07
--- /dev/null
+++ b/src/templates/subscriptionManagerView.html
@@ -0,0 +1,18 @@
+
CLEAR SUBSCRIPTIONS
+
+
+
+Subscription / Profile Manager
++
+
+
+ {{profileInitials[index]}}
+
+ {{profile.name}}
+
+
+
+
+
+ Add New Profile
+