Fix issues from Vue.js Merge

This commit is contained in:
PrestonN 2018-08-02 22:18:08 -04:00
parent 860d384fbd
commit 6ccb6de22e
11 changed files with 466 additions and 468 deletions

View File

@ -1,61 +1,79 @@
{ {
"name": "FreeTube", "name": "FreeTube",
"productName": "FreeTube", "productName": "FreeTube",
"version": "0.3.2", "version": "0.3.2",
"description": "An Open Source YouTube app for privacy.", "description": "An Open Source YouTube app for privacy.",
"main": "src/js/init.js", "main": "src/js/init.js",
"scripts": { "scripts": {
"start": "electron-forge start", "start": "electron-forge start",
"package": "electron-forge package", "package": "electron-forge package",
"make": "electron-forge make", "make": "electron-forge make",
"publish": "electron-forge publish", "publish": "electron-forge publish",
"make:all": "npm run make:mac && npm run make:linux:x86 && npm run make:linux:arm && npm run make:win", "make:all": "npm run make:mac && npm run make:linux:x86 && npm run make:linux:arm && npm run make:win",
"make:mac": "electron-forge make --platform=darwin", "make:mac": "electron-forge make --platform=darwin",
"make:win": "electron-forge make --platform=win32", "make:win": "electron-forge make --platform=win32",
"make:win:zip": "electron-forge make --platform=win32 --targets=zip", "make:win:zip": "electron-forge make --platform=win32 --targets=zip",
"make:linux:x86": "electron-forge make --platform=linux --arch x64", "make:linux:x86": "electron-forge make --platform=linux --arch x64",
"make:linux:x86:zip": "electron-forge make --platform=linux --targets=zip --arch x64", "make:linux:x86:zip": "electron-forge make --platform=linux --targets=zip --arch x64",
"make:linux:x86:deb": "electron-forge make --platform=linux --targets=deb --arch x64", "make:linux:x86:deb": "electron-forge make --platform=linux --targets=deb --arch x64",
"make:linux:x86:rpm": "electron-forge make --platform=linux --targets=rpm --arch x64", "make:linux:x86:rpm": "electron-forge make --platform=linux --targets=rpm --arch x64",
"make:linux:x86:snap": "electron-forge package && electron-installer-snap --src=out/FreeTube-linux-x64 --arch x64", "make:linux:x86:snap": "electron-forge package && electron-installer-snap --src=out/FreeTube-linux-x64 --arch x64",
"make:linux:x86:flatpak": "electron-installer-flatpak --src out/FreeTube-linux-x64/ --dest out/make --arch x64", "make:linux:x86:flatpak": "electron-installer-flatpak --src out/FreeTube-linux-x64/ --dest out/make --arch x64",
"make:linux:x86:appimage": "electron-forge make --platform=linux --targets=electron-forge-maker-appimage --arch x64", "make:linux:x86:appimage": "electron-forge make --platform=linux --targets=electron-forge-maker-appimage --arch x64",
"make:linux:arm": "electron-forge make --platform=linux --arch arm64", "make:linux:arm": "electron-forge make --platform=linux --arch arm64",
"make:linux:arm:zip": "electron-forge make --platform=linux --targets=zip --arch arm64", "make:linux:arm:zip": "electron-forge make --platform=linux --targets=zip --arch arm64",
"make:linux:arm:deb": "electron-forge make --platform=linux --targets=deb --arch arm64", "make:linux:arm:deb": "electron-forge make --platform=linux --targets=deb --arch arm64",
"make:linux:arm:rpm": "electron-forge make --platform=linux --targets=rpm --arch arm64", "make:linux:arm:rpm": "electron-forge make --platform=linux --targets=rpm --arch arm64",
"make:linux:arm:appimage": "electron-forge make --platform=linux --targets=electron-forge-maker-appimage --arch arm64" "make:linux:arm:appimage": "electron-forge make --platform=linux --targets=electron-forge-maker-appimage --arch arm64"
}, },
"keywords": [], "keywords": [],
"author": { "author": {
"name": "PrestonN", "name": "PrestonN",
"email": "FreeTubeApp@protonmail.com", "email": "FreeTubeApp@protonmail.com",
"url": "https://github.com/FreeTubeApp/FreeTube" "url": "https://github.com/FreeTubeApp/FreeTube"
}, },
"license": "GPL-3.0-or-later", "license": "GPL-3.0-or-later",
"config": { "config": {
"forge": { "forge": {
"make_targets": { "make_targets": {
"win32": [ "win32": [
"squirrel" "squirrel"
], ],
"darwin": [ "darwin": [
"zip" "zip"
], ],
"linux": [ "linux": [
"deb", "deb",
"rpm", "rpm",
"electron-forge-maker-appimage", "electron-forge-maker-appimage",
"zip" "zip"
] ]
}, },
"protocols": [ "protocols": [
{ {
"name": "freetube", "name": "freetube",
"role": "Viewer", "role": "Viewer",
"schemes": [ "schemes": [
"freetube" "freetube"
] ]
}
],
"electronPackagerConfig": {
"packageManager": "yarn",
"icon": "./src/icons/iconColor.icns"
},
"electronWinstallerConfig": {
"name": "freetube",
"iconUrl": "https://raw.githubusercontent.com/FreeTubeApp/FreeTubeApp.github.io/master/images/iconColor.ico",
"setupIcon": "./src/icons/iconColor.ico"
},
"electronInstallerDebian": {
"icon": "src/icons/iconColor.png"
},
"repository": {
"type": "git",
"url": "https://github.com/FreeTubeApp/FreeTube"
}
} }
}, },
"devDependencies": { "devDependencies": {

View File

@ -20,10 +20,21 @@
<div class="double-bounce1"></div> <div class="double-bounce1"></div>
<div class="double-bounce2"></div> <div class="double-bounce2"></div>
</div> </div>
<div id='confirmFunction'> </div>
<span id='confirmMessage'>Would you like to perform the function?</span> <div id='confirmFunction'>
<div class='confirmButton' id='confirmYes'>Yes</div> <span id='confirmMessage'>Would you like to perform the function?</span>
<div class='confirmButton' id='confirmNo'>No</div> <div class='confirmButton' id='confirmYes'>Yes</div>
<div class='confirmButton' id='confirmNo'>No</div>
</div>
<div id='toast'>
<span id='toastMessage'></span>
<i onclick='hideToast()' class="closeToast fas fa-times"></i>
</div>
<div class="topNav">
<i onclick='toggleSideNavigation()' class="fas fa-bars" id='menuButton'></i>
<div class="searchBar">
<input id='search' class="search" type="text" placeholder="Search / Go to URL">
<i onclick='parseSearchText()' class="fas fa-search searchButton" style='margin-right: -10px; cursor: pointer'></i>
</div> </div>
<img src='icons/iconBlack.png' id='menuIcon' /> &nbsp; <img src='icons/iconBlack.png' id='menuIcon' /> &nbsp;
<img src='icons/textBlack.png' id='menuText' /> <img src='icons/textBlack.png' id='menuText' />
@ -70,6 +81,7 @@
</div> </div>
<div id='progressView'></div> <div id='progressView'></div>
</body> </body>
<script src="js/general.js"></script>
<script src="js/youtubeApi.js"></script> <script src="js/youtubeApi.js"></script>
<script src="js/updates.js"></script> <script src="js/updates.js"></script>
<script src="js/db.js"></script> <script src="js/db.js"></script>

View File

@ -62,7 +62,7 @@ function goToChannel(channelId) {
maxResults: 50, maxResults: 50,
order: 'date', order: 'date',
}, function (data) { }, function (data) {
const channelData = data.items[0]; let grabDuration = getDuration(data.items);
grabDuration.then((videoList) => { grabDuration.then((videoList) => {
channelView.seen = true; channelView.seen = true;
@ -72,8 +72,6 @@ function goToChannel(channelId) {
videoList.items.forEach((video) => { videoList.items.forEach((video) => {
displayVideo(video, 'channel'); displayVideo(video, 'channel');
}); });
$('#main').html(rendered);
stopLoadingAnimation();
// Grab the channel's latest uploads. API forces a max of 50. // Grab the channel's latest uploads. API forces a max of 50.
youtubeAPI('search', { youtubeAPI('search', {
@ -92,5 +90,7 @@ function goToChannel(channelId) {
}); });
}); });
}); });
});
}); });
} });
}

View File

@ -1,53 +1,48 @@
/* /*
This file is part of FreeTube. This file is part of FreeTube.
FreeTube is free software: you can redistribute it and/or modify
FreeTube is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by
it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or
the Free Software Foundation, either version 3 of the License, or (at your option) any later version.
(at your option) any later version. FreeTube is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
FreeTube is distributed in the hope that it will be useful, MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
but WITHOUT ANY WARRANTY; without even the implied warranty of GNU General Public License for more details.
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the You should have received a copy of the GNU General Public License
GNU General Public License for more details. along with FreeTube. If not, see <http://www.gnu.org/licenses/>.
You should have received a copy of the GNU General Public License
along with FreeTube. If not, see <http://www.gnu.org/licenses/>.
*/ */
/* /*
* File used for functions related to video history. * File used for functions related to video history.
*/ */
/** /**
* Add a video to the history database file * Add a video to the history database file
* *
* @param {string} videoId - The video ID of the video to be saved. * @param {string} videoId - The video ID of the video to be saved.
* *
* @return {Void} * @return {Void}
*/ */
function addToHistory(videoId) { function addToHistory(videoId){
const data = { const data = {
videoId: videoId, videoId: videoId,
timeWatched: new Date().getTime(), timeWatched: new Date().getTime(),
}; };
historyDb.insert(data, (err, newDoc) => {}); historyDb.insert(data, (err, newDoc) => {});
} }
/** /**
* Remove a video from the history database file * Remove a video from the history database file
* *
* @param {string} videoId - The video ID of the video to be removed. * @param {string} videoId - The video ID of the video to be removed.
* *
* @return {Void} * @return {Void}
*/ */
function removeFromHistory(videoId) { function removeFromHistory(videoId){
const data = { const data = {videoId: videoId};
videoId: videoId historyDb.remove(data, {}, (err, numRemoved) => {});
};
historyDb.remove(data, {}, (err, numRemoved) => {});
} }
/** /**
@ -60,21 +55,22 @@ function showHistory(){
//startLoadingAnimation(); //startLoadingAnimation();
console.log('checking history'); console.log('checking history');
let videoList = ''; let videoList = '';
historyDb.find({}).sort({ historyDb.find({}).sort({
timeWatched: -1 timeWatched: -1
}).exec((err, docs) => { }).exec((err, docs) => {
if (docs.length > 49) { if(docs.length > 49){
// The YouTube API limits the search to 50 videos, so grab 50 most recent. // The YouTube API limits the search to 50 videos, so grab 50 most recent.
for (let i = 0; i < 49; i++) { for (let i = 0; i < 49; i++) {
videoList = videoList + ',' + docs[i]['videoId']; videoList = videoList + ',' + docs[i]['videoId'];
} }
} else { }
docs.forEach((video) => { else{
videoList = videoList + ',' + video['videoId']; docs.forEach((video) => {
}); videoList = videoList + ',' + video['videoId'];
} });
}
youtubeAPI('videos', { youtubeAPI('videos', {
part: 'snippet', part: 'snippet',
@ -91,4 +87,5 @@ function showHistory(){
}); });
}); });
}); });
} });
}

View File

@ -17,19 +17,17 @@
import { import {comment} from "./comment.model";
comment
} from "./comment.model";
/** /**
* Entire Comment Threads for a Video * Entire Comment Threads for a Video
*/ */
export class commentThread { export class commentThread {
videoId; videoId: ?string;
nextPageToken; nextPageToken: ?string;
pageInfo = { pageInfo: {
totalResults, totalResults: number,
resultsPerPage resultsPerPage: number
}; };
items; items: comment[];
} }

View File

@ -127,27 +127,25 @@ function playVideo(videoId) {
if (typeof(info.player_response.captions.playerCaptionsTracklistRenderer.captionTracks) === 'object') { if (typeof(info.player_response.captions.playerCaptionsTracklistRenderer.captionTracks) === 'object') {
const videoSubtitles = info.player_response.captions.playerCaptionsTracklistRenderer.captionTracks; const videoSubtitles = info.player_response.captions.playerCaptionsTracklistRenderer.captionTracks;
if (subtitle.kind == 'asr') { videoSubtitles.forEach((subtitle) => {
//subtitleUrl = subtitle.baseUrl; let subtitleUrl = 'https://www.youtube.com/api/timedtext?lang=' + subtitle.languageCode + '&fmt=vtt&name=&v=' + videoId;
return;
}
videoHtml = videoHtml + '<track kind="subtitles" src="' + subtitleUrl + '" srclang="' + subtitle.languageCode + '" label="' + subtitle.name.simpleText + '">'; if (subtitle.kind == 'asr') {
}); //subtitleUrl = subtitle.baseUrl;
} return;
} }
//videoHtml = videoHtml + '</video>'; videoHtml = videoHtml + '<track kind="subtitles" src="' + subtitleUrl + '" srclang="' + subtitle.languageCode + '" label="' + subtitle.name.simpleText + '">';
});
} }
}
playerView.subtitleHtml = videoHtml; playerView.subtitleHtml = videoHtml;
} }
const checkSubscription = isSubscribed(playerView.channelId); const checkSubscription = isSubscribed(playerView.channelId);
checkSubscription.then((results) => {
const subscribeButton = document.getElementById('subscribeButton');
checkSubscription.then((results) => { checkSubscription.then((results) => {
if (results === false) { if (results === false) {
if (subscribeButton != null) { if (subscribeButton != null) {
@ -181,10 +179,7 @@ function playVideo(videoId) {
}); });
} }
window.setTimeout(checkVideoUrls, 5000, video480p, video720p);
window.setTimeout(checkVideoUrls, 5000, playerView.video480p, playerView.video720p); window.setTimeout(checkVideoUrls, 5000, playerView.video480p, playerView.video720p);
}); });
} }
@ -225,6 +220,7 @@ function openMiniPlayer() {
videoThumbnail: playerView.thumbnail, videoThumbnail: playerView.thumbnail,
startTime: lastTime, startTime: lastTime,
}); });
});
} }
/** /**
@ -340,4 +336,4 @@ function changeDurationBySeconds(seconds) {
function changeDurationByPercentage(percentage) { function changeDurationByPercentage(percentage) {
const videoPlayer = $('.videoPlayer').get(0); const videoPlayer = $('.videoPlayer').get(0);
videoPlayer.currentTime = videoPlayer.duration * percentage; videoPlayer.currentTime = videoPlayer.duration * percentage;
} }

View File

@ -152,4 +152,5 @@ function showSavedVideos(){
}); });
}); });
}); });
} });
}

View File

@ -1,18 +1,15 @@
/* /*
This file is part of FreeTube. This file is part of FreeTube.
FreeTube is free software: you can redistribute it and/or modify
FreeTube is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by
it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or
the Free Software Foundation, either version 3 of the License, or (at your option) any later version.
(at your option) any later version. FreeTube is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
FreeTube is distributed in the hope that it will be useful, MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
but WITHOUT ANY WARRANTY; without even the implied warranty of GNU General Public License for more details.
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the You should have received a copy of the GNU General Public License
GNU General Public License for more details. along with FreeTube. If not, see <http://www.gnu.org/licenses/>.
You should have received a copy of the GNU General Public License
along with FreeTube. If not, see <http://www.gnu.org/licenses/>.
*/ */
@ -81,19 +78,17 @@ function checkDefaultSettings() {
'useTor': false 'useTor': false
}; };
ft.log('Default Settings: ', settingDefaults); console.log(settingDefaults);
for (let key in settingDefaults) { for (let key in settingDefaults){
settingsDb.find({ settingsDb.find({_id: key}, (err, docs) => {
_id: key if (jQuery.isEmptyObject(docs)) {
}, (err, docs) => { newSetting = {
if (jQuery.isEmptyObject(docs)) { _id: key,
newSetting = { value: settingDefaults[key]
_id: key, };
value: settingDefaults[key]
};
settingsDb.insert(newSetting); settingsDb.insert(newSetting);
if (key == 'theme'){ if (key == 'theme'){
setTheme('light'); setTheme('light');
@ -129,20 +124,25 @@ function checkDefaultSettings() {
* @return {Void} * @return {Void}
*/ */
function updateSettings() { function updateSettings() {
let themeSwitch = document.getElementById('themeSwitch').checked; let themeSwitch = document.getElementById('themeSwitch').checked;
let torSwitch = document.getElementById('torSwitch').checked; let torSwitch = document.getElementById('torSwitch').checked;
let key = document.getElementById('api-key').value; let key = document.getElementById('api-key').value;
let theme = 'light'; let theme = 'light';
settingsView.apiKey = apiKeyBank[Math.floor(Math.random() * apiKeyBank.length)]; if (apiKeyBank.indexOf(key) == -1 && key !== '') {
settingsView.apiKey = key;
}
else{
settingsView.apiKey = apiKeyBank[Math.floor(Math.random() * apiKeyBank.length)];
}
ft.log('(Is the theme switch checked) themeSwitch: ', themeSwitch); console.log(themeSwitch);
if (themeSwitch === true) { if (themeSwitch === true) {
theme = 'dark'; theme = 'dark';
} }
ft.log('Theme: ', theme); console.log(theme);
// Update default theme // Update default theme
settingsDb.update({ settingsDb.update({
@ -165,40 +165,14 @@ function updateSettings() {
useTor = torSwitch; useTor = torSwitch;
}); });
if (key !== '') { // To any third party devs that fork the project, please be ethical and change the API key.
settingsDb.update({ settingsDb.update({
_id: 'theme' _id: 'apiKey'
}, { }, {
value: theme value: settingsView.apiKey
}, {}, function (err, numReplaced) { }, {});
ft.log('Error while updating theme: ', err);
ft.log('Number replaced: ', numReplaced); showToast('Settings have been saved.');
});
// Update tor usage.
settingsDb.update({
_id: 'useTor'
}, {
value: settingsView.apiKey
}, {});
}
if (key != '') {
settingsDb.update({
_id: 'apiKey'
}, {
value: key
}, {});
} else {
// To any third party devs that fork the project, please be ethical and change the API key.
settingsDb.update({
_id: 'apiKey'
}, {
value: apiKey
}, {});
}
showToast('Settings have been saved.');
} }
/** /**
@ -209,13 +183,13 @@ function updateSettings() {
* @return {Void} * @return {Void}
*/ */
function toggleTheme(themeValue) { function toggleTheme(themeValue) {
if (themeValue.checked === true) { if (themeValue.checked === true) {
setTheme('dark'); setTheme('dark');
currentTheme = 'dark'; currentTheme = 'dark';
} else { } else {
setTheme('light'); setTheme('light');
currentTheme = 'light'; currentTheme = 'light';
} }
} }
/** /**
@ -226,86 +200,85 @@ function toggleTheme(themeValue) {
* @return {Void} * @return {Void}
*/ */
function setTheme(option) { function setTheme(option) {
let cssFile; let cssFile;
const currentTheme = document.getElementsByTagName("link").item(1); const currentTheme = document.getElementsByTagName("link").item(1);
// Create a link element // Create a link element
const newTheme = document.createElement("link"); const newTheme = document.createElement("link");
newTheme.setAttribute("rel", "stylesheet"); newTheme.setAttribute("rel", "stylesheet");
newTheme.setAttribute("type", "text/css"); newTheme.setAttribute("type", "text/css");
// Grab the css file to be used. // Grab the css file to be used.
switch (option) { switch (option) {
case 'light': case 'light':
cssFile = './style/lightTheme.css'; cssFile = './style/lightTheme.css';
document.getElementById('menuText').src = 'icons/textBlack.png'; document.getElementById('menuText').src = 'icons/textBlack.png';
document.getElementById('menuIcon').src = 'icons/iconBlack.png'; document.getElementById('menuIcon').src = 'icons/iconBlack.png';
document.getElementById('menuButton').style.color = 'black'; document.getElementById('menuButton').style.color = 'black';
break; break;
case 'dark': case 'dark':
cssFile = './style/darkTheme.css'; cssFile = './style/darkTheme.css';
document.getElementById('menuText').src = 'icons/textColor.png'; document.getElementById('menuText').src = 'icons/textColor.png';
document.getElementById('menuIcon').src = 'icons/iconColor.png'; document.getElementById('menuIcon').src = 'icons/iconColor.png';
document.getElementById('menuButton').style.color = 'white'; document.getElementById('menuButton').style.color = 'white';
break; break;
default: default:
// Default to the light theme // Default to the light theme
cssFile = './style/lightTheme.css'; cssFile = './style/lightTheme.css';
break; break;
} }
newTheme.setAttribute("href", cssFile); newTheme.setAttribute("href", cssFile);
// Replace the current theme with the new theme // Replace the current theme with the new theme
document.getElementsByTagName("head").item(0).replaceChild(newTheme, currentTheme); document.getElementsByTagName("head").item(0).replaceChild(newTheme, currentTheme);
} }
/** /**
* Import Subscriptions from an OPML file. * Import Subscriptions from an OPML file.
* *
* @param {string} subFile - The file location of the OPML file. * @param {string} subFile - The file location of the OPML file.
* *
* @return {Void} * @return {Void}
*/ */
function importOpmlSubs(json) { function importOpmlSubs(json){
if (!json[0]['folder'].includes('YouTube')) { if(!json[0]['folder'].includes('YouTube')){
showToast('Invalid OPML File. Import is unsuccessful.'); showToast('Invalid OPML File. Import is unsuccessful.');
return;
}
json.forEach((channel) => {
let channelId = channel['xmlurl'].replace('https://www.youtube.com/feeds/videos.xml?channel_id=', '');
addSubscription(channelId, false);
});
window.setTimeout(displaySubs, 1000);
showToast('Subscriptions have been imported!');
return; return;
}
json.forEach((channel) => {
let channelId = channel['xmlurl'].replace('https://www.youtube.com/feeds/videos.xml?channel_id=', '');
addSubscription(channelId, false);
});
window.setTimeout(displaySubs, 1000);
showToast('Subscriptions have been imported!');
return;
} }
/** /**
* Import a subscriptions file that the user provides. * Import a subscriptions file that the user provides.
* *
* @return {Void} * @return {Void}
*/ */
function importSubscriptions() { function importSubscriptions(){
const appDatabaseFile = localDataStorage + '/subscriptions.db'; const appDatabaseFile = localDataStorage + '/subscriptions.db';
// Open user's file browser. Only show .db files. // Open user's file browser. Only show .db files.
dialog.showOpenDialog({ dialog.showOpenDialog({
properties: ['openFile'], properties: ['openFile'],
filters: [{ filters: [
name: 'Database File', {name: 'Database File', extensions: ['*']},
extensions: ['*'] ]
}, ] }, function(fileLocation){
}, function (fileLocation) { if(typeof(fileLocation) === 'undefined'){
if (typeof (fileLocation) === 'undefined') { console.log('Import Aborted');
ft.log('Import Aborted'); return;
return; }
} console.log(fileLocation);
ft.log('File Location: ', fileLocation); let i = fileLocation[0].lastIndexOf('.');
let i = fileLocation[0].lastIndexOf('.'); let fileType = (i < 0) ? '' : fileLocation[0].substr(i);
let fileType = (i < 0) ? '' : fileLocation[0].substr(i); console.log(fileType);
ft.log('File Type: ', fileType);
fs.readFile(fileLocation[0], function(readErr, data){ fs.readFile(fileLocation[0], function(readErr, data){
if(readErr){ if(readErr){
@ -313,30 +286,31 @@ function importSubscriptions() {
throw readErr; throw readErr;
} }
if (data.includes("<opml")) { if (data.includes("<opml")){
getOpml(data, function (error, json) { getOpml(data, function (error, json){
if (!error) { if (!error){
clearFile('subscriptions', false);
importOpmlSubs(json['children'][0]['children']);
}
});
return;
} else if (fileType !== '.db') {
showToast('Incorrect file type. Import unsuccessful.');
return;
}
clearFile('subscriptions', false); clearFile('subscriptions', false);
importOpmlSubs(json['children'][0]['children']);
}
});
return;
}
else if (fileType !== '.db'){
showToast('Incorrect file type. Import unsuccessful.');
return;
}
fs.writeFile(appDatabaseFile, data, function (writeErr) { clearFile('subscriptions', false);
if (writeErr) {
showToast('Unable to create file. Please check your permissions and try again.'); fs.writeFile(appDatabaseFile, data, function(writeErr){
throw writeErr; if(writeErr){
} showToast('Unable to create file. Please check your permissions and try again.');
showToast('Susbcriptions have been successfully imported. Please restart FreeTube for the changes to take effect.'); throw writeErr;
}); }
}) showToast('Susbcriptions have been successfully imported. Please restart FreeTube for the changes to take effect.');
}); });
})
});
} }
/** /**
@ -345,79 +319,85 @@ function importSubscriptions() {
* @return {Void} * @return {Void}
*/ */
function exportSubscriptions() { function exportSubscriptions() {
const appDatabaseFile = localDataStorage + '/subscriptions.db'; const appDatabaseFile = localDataStorage + '/subscriptions.db';
const date = new Date(); const date = new Date();
let dateMonth = date.getMonth() + 1; let dateMonth = date.getMonth() + 1;
if (dateMonth < 10) { if (dateMonth < 10){
dateMonth = '0' + dateMonth; dateMonth = '0' + dateMonth;
}
let dateDay = date.getDate();
if (dateDay < 10){
dateDay = '0' + dateDay;
}
const dateYear = date.getFullYear();
const dateString = 'freetube-subscriptions-' + dateYear + '-' + dateMonth + '-' + dateDay;
// Open user file browser. User gives location of file to be created.
dialog.showSaveDialog({
defaultPath: dateString,
filters: [{
name: 'Database File',
extensions: ['db']
}, ]
}, function(fileLocation) {
console.log(fileLocation);
if (typeof(fileLocation) === 'undefined') {
console.log('Export Aborted');
return;
} }
fs.readFile(appDatabaseFile, function(readErr, data) {
let dateDay = date.getDate(); if (readErr) {
throw readErr;
if (dateDay < 10) { }
dateDay = '0' + dateDay; fs.writeFile(fileLocation, data, function(writeErr) {
} if (writeErr) {
throw writeErr;
const dateYear = date.getFullYear();
const dateString = 'freetube-subscriptions-' + dateYear + '-' + dateMonth + '-' + dateDay;
// 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('File Location: ', fileLocation);
if (typeof (fileLocation) === 'undefined') {
ft.log('Export Aborted');
return;
} }
fs.readFile(appDatabaseFile, function (readErr, data) { showToast('Susbcriptions have been successfully exported');
if (readErr) { });
throw readErr; })
} });
fs.writeFile(fileLocation, data, function (writeErr) {
if (writeErr) {
throw writeErr;
}
showToast('Susbcriptions have been successfully exported');
});
})
});
} }
/** /**
* Clear out the data in a file. * Clear out the data in a file.
* *
* @param {string} type - The type of file to be cleared. * @param {string} type - The type of file to be cleared.
*/ */
function clearFile(type, showMessage = true) { function clearFile(type, showMessage = true){
ft.log('File Type: ', type); console.log(type);
let dataBaseFile; let dataBaseFile;
switch (type) { switch (type) {
case 'subscriptions': case 'subscriptions':
dataBaseFile = localDataStorage + '/subscriptions.db'; dataBaseFile = localDataStorage + '/subscriptions.db';
break; break;
case 'history': case 'history':
dataBaseFile = localDataStorage + '/videohistory.db'; dataBaseFile = localDataStorage + '/videohistory.db';
break; break;
case 'saved': case 'saved':
dataBaseFile = localDataStorage + '/savedvideos.db'; dataBaseFile = localDataStorage + '/savedvideos.db';
break; break;
default: default:
showToast('Unknown file: ' + type) showToast('Unknown file: ' + type)
return return
}
// Replace data with an empty string.
fs.writeFile(dataBaseFile, '', function(err) {
if (err) {
throw err;
} }
// Replace data with an empty string. if (showMessage){
fs.writeFile(dataBaseFile, '', function (err) { showToast('File has been cleared. Restart FreeTube to see the changes');
if (err) { }
throw err; })
} }
checkDefaultSettings(); checkDefaultSettings();

View File

@ -80,113 +80,103 @@ function removeSubscription(channelId) {
* *
* @return {Void} * @return {Void}
*/ */
function loadSubscriptions() { function loadSubscriptions() {
if (checkSubscriptions === false && subscriptionView.videoList.length > 0){ if (checkSubscriptions === false && subscriptionView.videoList.length > 0){
console.log('Will not load subscriptions. Timer still on.'); console.log('Will not load subscriptions. Timer still on.');
loadingView.seen = false; loadingView.seen = false;
return; return;
} }
else{ else{
showToast('Refreshing Subscription List. Please wait...'); showToast('Refreshing Subscription List. Please wait...');
checkSubscriptions = false; checkSubscriptions = false;
} }
let videoList = []; let videoList = [];
const subscriptions = returnSubscriptions(); const subscriptions = returnSubscriptions();
subscriptions.then((results) => { subscriptions.then((results) => {
let channelId = ''; let channelId = '';
let videoList = []; let videoList = [];
if (results.length > 0) { if (results.length > 0) {
let counter = 0; let counter = 0;
for (let i = 0; i < results.length; i++) {
channelId = results[i]['channelId'];
youtubeAPI('search', { for (let i = 0; i < results.length; i++) {
part: 'snippet', channelId = results[i]['channelId'];
channelId: channelId,
type: 'video',
maxResults: 15,
order: 'date',
}, (data) => {
youtubeAPI('search', { youtubeAPI('search', {
part: 'snippet', part: 'snippet',
channelId: channelId, channelId: channelId,
type: 'video', type: 'video',
maxResults: 15, maxResults: 15,
order: 'date', order: 'date',
}, (data) => { }, (data) => {
console.log(data); console.log(data);
videoList = videoList.concat(data.items); videoList = videoList.concat(data.items);
counter++; counter++;
progressView.progressWidth = (counter / results.length) * 100; progressView.progressWidth = (counter / results.length) * 100;
if (counter === results.length) { if (counter === results.length) {
videoList.sort((a, b) => { videoList.sort((a, b) => {
const date1 = Date.parse(a.snippet.publishedAt); const date1 = Date.parse(a.snippet.publishedAt);
const date2 = Date.parse(b.snippet.publishedAt); const date2 = Date.parse(b.snippet.publishedAt);
return date2.valueOf() - date1.valueOf(); return date2.valueOf() - date1.valueOf();
}); });
// The YouTube website limits the subscriptions to 100 before grabbing more so we only show 100 // The YouTube website limits the subscriptions to 100 before grabbing more so we only show 100
// to keep the app running at a good speed. // to keep the app running at a good speed.
if (videoList.length < 50) { if (videoList.length < 50) {
let grabDuration = getDuration(videoList.slice(0, 49)); let grabDuration = getDuration(videoList.slice(0, 49));
grabDuration.then((list) => { grabDuration.then((list) => {
subscriptionView.videoList = []; subscriptionView.videoList = [];
list.items.forEach((video) => { list.items.forEach((video) => {
displayVideo(video, 'subscriptions'); displayVideo(video, 'subscriptions');
}); });
loadingView.seen = false; loadingView.seen = false;
progressView.seen = false; progressView.seen = false;
progressView.progressWidth = 0; progressView.progressWidth = 0;
}); });
} else { } else {
console.log(videoList); console.log(videoList);
let finishedList = []; let finishedList = [];
let firstBatchDuration = getDuration(videoList.slice(0, 49)); let firstBatchDuration = getDuration(videoList.slice(0, 49));
grabDuration.then((list) => { firstBatchDuration.then((list1) => {
list.items.forEach((video) => { finishedList = finishedList.concat(list1.items);
displayVideo(video); let secondBatchDuration = getDuration(videoList.slice(50, 99));
});
stopLoadingAnimation();
});
} else {
secondBatchDuration.then((list2) => { secondBatchDuration.then((list2) => {
finishedList = finishedList.concat(list2.items); finishedList = finishedList.concat(list2.items);
console.log(finishedList); console.log(finishedList);
subscriptionView.videoList = []; subscriptionView.videoList = [];
finishedList.forEach((video) => { finishedList.forEach((video) => {
displayVideo(video, 'subscriptions'); displayVideo(video, 'subscriptions');
}); });
loadingView.seen = false; loadingView.seen = false;
progressView.seen = false; progressView.seen = false;
progressView.progressWidth = 0; progressView.progressWidth = 0;
subscriptionTimer = window.setTimeout(() => { subscriptionTimer = window.setTimeout(() => {
checkSubscriptions = true; checkSubscriptions = true;
}, 60000); }, 60000);
}); });
}); });
} }
} }
} }
);
}
} else { } else {
// User has no subscriptions. Display message. // User has no subscriptions. Display message.
loadingView.seen = false; loadingView.seen = false;
headerView.seen = false; headerView.seen = false;
noSubscriptions.seen = true; noSubscriptions.seen = true;
} }
}); });
} }
/** /**
* Get the list of subscriptions from the user's subscription database. * Get the list of subscriptions from the user's subscription database.
@ -281,4 +271,4 @@ function isSubscribed(channelId) {
} }
}); });
}); });
} }

View File

@ -180,6 +180,11 @@ let popularView = new Vue({
}, },
toggleSave: (videoId) => { toggleSave: (videoId) => {
addSavedVideo(videoId); addSavedVideo(videoId);
},
copy: (site, videoId) => {
const url = 'https://' + site + '/watch?v=' + videoId;
clipboard.writeText(url);
showToast('URL has been copied to the clipboard');
} }
}, },
template: videoListTemplate template: videoListTemplate

View File

@ -220,7 +220,6 @@ function displayChannels(channels) {
}, function (data) { }, function (data) {
ft.log('Channel Data: ', data); ft.log('Channel Data: ', data);
let items = data['items'].reverse(); let items = data['items'].reverse();
const videoListTemplate = require('./templates/channelList.html');
ft.log('Channel Items: ', items); ft.log('Channel Items: ', items);
@ -240,6 +239,7 @@ function displayChannels(channels) {
searchView.videoList = searchView.videoList.concat(channelData); searchView.videoList = searchView.videoList.concat(channelData);
}); });
});
} }
function displayPlaylists(playlists) { function displayPlaylists(playlists) {
@ -343,6 +343,7 @@ function showVideoRecommendations(videoId) {
playerView.recommendedVideoList = playerView.recommendedVideoList.concat(data); playerView.recommendedVideoList = playerView.recommendedVideoList.concat(data);
}); });
}); });
});
} }
/** /**
@ -404,7 +405,7 @@ function parseSearchText(url = '') {
* @return {string} - The formated string. Ex: 12:34:56 * @return {string} - The formated string. Ex: 12:34:56
*/ */
function parseVideoDuration(durationString) { function parseVideoDuration(durationString) {
let match = durationString.match(/PT(\d+H)?(\d+M)?(\d+S)?/); let match = durationString.match(/P.*T(\d+H)?(\d+M)?(\d+S)?/);
let duration = ''; let duration = '';
match = match.slice(1).map(function (x) { match = match.slice(1).map(function (x) {
@ -602,4 +603,4 @@ function checkVideoUrls(video480p, video720p) {
} }
}); });
} }
} }