diff --git a/backend/app.js b/backend/app.js index 1376471..bcd24ae 100644 --- a/backend/app.js +++ b/backend/app.js @@ -61,7 +61,7 @@ const logger = winston.createLogger({ // new winston.transports.File({ filename: 'appdata/logs/error.log', level: 'error' }), new winston.transports.File({ filename: 'appdata/logs/combined.log' }), - new winston.transports.Console({level: !debugMode ? 'info' : 'debug'}) + new winston.transports.Console({level: !debugMode ? 'info' : 'debug', name: 'console'}) ] }); @@ -132,8 +132,6 @@ var archivePath = path.join(__dirname, 'appdata', 'archives'); var options = null; // encryption options var url_domain = null; var updaterStatus = null; -var last_downloads_check = null; -var downloads_check_interval = 1000; var timestamp_server_start = Date.now(); @@ -536,38 +534,7 @@ async function setConfigFromEnv() { async function loadConfig() { return new Promise(async resolve => { - url = !debugMode ? config_api.getConfigItem('ytdl_url') : 'http://localhost:4200'; - backendPort = config_api.getConfigItem('ytdl_port'); - usingEncryption = config_api.getConfigItem('ytdl_use_encryption'); - audioFolderPath = config_api.getConfigItem('ytdl_audio_folder_path'); - videoFolderPath = config_api.getConfigItem('ytdl_video_folder_path'); - downloadOnlyMode = config_api.getConfigItem('ytdl_download_only_mode'); - useDefaultDownloadingAgent = config_api.getConfigItem('ytdl_use_default_downloading_agent'); - customDownloadingAgent = config_api.getConfigItem('ytdl_custom_downloading_agent'); - allowSubscriptions = config_api.getConfigItem('ytdl_allow_subscriptions'); - subscriptionsCheckInterval = config_api.getConfigItem('ytdl_subscriptions_check_interval'); - - if (!useDefaultDownloadingAgent && validDownloadingAgents.indexOf(customDownloadingAgent) !== -1 ) { - logger.info(`Using non-default downloading agent \'${customDownloadingAgent}\'`) - } else { - customDownloadingAgent = null; - } - - if (usingEncryption) - { - var certFilePath = path.resolve(config_api.getConfigItem('ytdl_cert_file_path')); - var keyFilePath = path.resolve(config_api.getConfigItem('ytdl_key_file_path')); - - var certKeyFile = fs.readFileSync(keyFilePath); - var certFile = fs.readFileSync(certFilePath); - - options = { - key: certKeyFile, - cert: certFile - }; - } - - url_domain = new URL(url); + loadConfigValues(); // creates archive path if missing if (!fs.existsSync(archivePath)){ @@ -597,6 +564,51 @@ async function loadConfig() { } +function loadConfigValues() { + url = !debugMode ? config_api.getConfigItem('ytdl_url') : 'http://localhost:4200'; + backendPort = config_api.getConfigItem('ytdl_port'); + usingEncryption = config_api.getConfigItem('ytdl_use_encryption'); + audioFolderPath = config_api.getConfigItem('ytdl_audio_folder_path'); + videoFolderPath = config_api.getConfigItem('ytdl_video_folder_path'); + downloadOnlyMode = config_api.getConfigItem('ytdl_download_only_mode'); + useDefaultDownloadingAgent = config_api.getConfigItem('ytdl_use_default_downloading_agent'); + customDownloadingAgent = config_api.getConfigItem('ytdl_custom_downloading_agent'); + allowSubscriptions = config_api.getConfigItem('ytdl_allow_subscriptions'); + subscriptionsCheckInterval = config_api.getConfigItem('ytdl_subscriptions_check_interval'); + + if (!useDefaultDownloadingAgent && validDownloadingAgents.indexOf(customDownloadingAgent) !== -1 ) { + logger.info(`Using non-default downloading agent \'${customDownloadingAgent}\'`) + } else { + customDownloadingAgent = null; + } + + if (usingEncryption) + { + var certFilePath = path.resolve(config_api.getConfigItem('ytdl_cert_file_path')); + var keyFilePath = path.resolve(config_api.getConfigItem('ytdl_key_file_path')); + + var certKeyFile = fs.readFileSync(keyFilePath); + var certFile = fs.readFileSync(certFilePath); + + options = { + key: certKeyFile, + cert: certFile + }; + } + + url_domain = new URL(url); + + let logger_level = config_api.getConfigItem('ytdl_logger_level'); + const possible_levels = ['error', 'warn', 'info', 'verbose', 'debug']; + if (!possible_levels.includes(logger_level)) { + logger.error(`${logger_level} is not a valid logger level! Choose one of the following: ${possible_levels.join(', ')}.`) + logger_level = 'info'; + } + logger.level = logger_level; + winston.loggers.get('console').level = logger_level; + logger.transports[2].level = logger_level; +} + function calculateSubcriptionRetrievalDelay(amount) { // frequency is 5 mins let frequency_in_ms = subscriptionsCheckInterval * 1000; @@ -1517,11 +1529,9 @@ async function getUrlInfos(urls) { let result = []; return new Promise(resolve => { youtubedl.exec(urls.join(' '), ['--dump-json'], {}, (err, output) => { - if (debugMode) { - let new_date = Date.now(); - let difference = (new_date - startDate)/1000; - logger.info(`URL info retrieval delay: ${difference} seconds.`); - } + let new_date = Date.now(); + let difference = (new_date - startDate)/1000; + logger.debug(`URL info retrieval delay: ${difference} seconds.`); if (err) { logger.error('Error during parsing:' + err); resolve(null); @@ -1600,7 +1610,7 @@ function getDownloadPercent(download_obj) { async function startYoutubeDL() { // auto update youtube-dl - await autoUpdateYoutubeDL(); + if (!debugMode) await autoUpdateYoutubeDL(); } // auto updates the underlying youtube-dl binary, not YoutubeDL-Material @@ -1652,10 +1662,9 @@ async function autoUpdateYoutubeDL() { logger.error(`Failed to update youtube-dl - ${e}`); } downloader(binary_path, function error(err, done) { - 'use strict' if (err) { + logger.error(err); resolve(false); - throw err; } logger.info(`Binary successfully updated: ${current_version} -> ${latest_update_version}`); resolve(true); @@ -1777,6 +1786,7 @@ app.post('/api/setConfig', function(req, res) { let new_config_file = req.body.new_config_file; if (new_config_file && new_config_file['YoutubeDLMaterial']) { let success = config_api.setConfigFile(new_config_file); + loadConfigValues(); // reloads config values that exist as variables res.send({ success: success }); @@ -2651,12 +2661,6 @@ app.get('/api/audio/:id', optionalJwt, function(req , res){ // Downloads management app.get('/api/downloads', async (req, res) => { - /* - if (!last_downloads_check || Date.now() - last_downloads_check > downloads_check_interval) { - last_downloads_check = Date.now(); - updateDownloads(); - } - */ res.send({downloads: downloads}); }); diff --git a/backend/appdata/default.json b/backend/appdata/default.json index 4ed35ed..011a7ca 100644 --- a/backend/appdata/default.json +++ b/backend/appdata/default.json @@ -21,7 +21,8 @@ "allow_quality_select": true, "download_only_mode": false, "allow_multi_download_mode": true, - "settings_pin_required": false + "settings_pin_required": false, + "enable_downloads_manager": true }, "API": { "use_API_key": false, @@ -40,13 +41,15 @@ "subscriptions_use_youtubedl_archive": true }, "Users": { - "base_path": "users/" + "base_path": "users/", + "allow_registration": true }, "Advanced": { "use_default_downloading_agent": true, "custom_downloading_agent": "", "multi_user_mode": false, - "allow_advanced_download": false + "allow_advanced_download": false, + "logger_level": "info" } } } diff --git a/backend/appdata/encrypted.json b/backend/appdata/encrypted.json index 9817beb..2340e83 100644 --- a/backend/appdata/encrypted.json +++ b/backend/appdata/encrypted.json @@ -21,7 +21,8 @@ "allow_quality_select": true, "download_only_mode": false, "allow_multi_download_mode": true, - "settings_pin_required": false + "settings_pin_required": false, + "enable_downloads_manager": true }, "API": { "use_API_key": false, @@ -40,13 +41,15 @@ "subscriptions_use_youtubedl_archive": true }, "Users": { - "base_path": "users/" + "base_path": "users/", + "allow_registration": true }, "Advanced": { "use_default_downloading_agent": true, "custom_downloading_agent": "", "multi_user_mode": false, - "allow_advanced_download": false + "allow_advanced_download": false, + "logger_level": "info" } } } diff --git a/backend/authentication/auth.js b/backend/authentication/auth.js index 7ca09fa..6315255 100644 --- a/backend/authentication/auth.js +++ b/backend/authentication/auth.js @@ -81,6 +81,12 @@ exports.registerUser = function(req, res) { var userid = req.body.userid; var username = req.body.username; var plaintextPassword = req.body.password; + + if (userid !== 'admin' && !config_api.getConfigItem('ytdl_allow_registration')) { + res.sendStatus(409); + logger.error(`Registration failed for user ${userid}. Registration is disabled.`); + return; + } bcrypt.hash(plaintextPassword, saltRounds) .then(function(hash) { diff --git a/backend/config.js b/backend/config.js index a968ae2..402835a 100644 --- a/backend/config.js +++ b/backend/config.js @@ -140,10 +140,10 @@ module.exports = { DEFAULT_CONFIG = { "YoutubeDLMaterial": { - "Host": { - "url": "http://example.com", - "port": "17442" - }, + "Host": { + "url": "http://example.com", + "port": "17442" + }, "Encryption": { "use-encryption": false, "cert-file-path": "/etc/letsencrypt/live/example.com/fullchain.pem", @@ -156,12 +156,13 @@ DEFAULT_CONFIG = { "custom_args": "" }, "Extra": { - "title_top": "Youtube Downloader", + "title_top": "YoutubeDL-Material", "file_manager_enabled": true, "allow_quality_select": true, "download_only_mode": false, "allow_multi_download_mode": true, - "settings_pin_required": false + "settings_pin_required": false, + "enable_downloads_manager": true }, "API": { "use_API_key": false, @@ -180,13 +181,15 @@ DEFAULT_CONFIG = { "subscriptions_use_youtubedl_archive": true }, "Users": { - "base_path": "users/" + "base_path": "users/", + "allow_registration": true }, "Advanced": { "use_default_downloading_agent": true, "custom_downloading_agent": "", "multi_user_mode": false, - "allow_advanced_download": false + "allow_advanced_download": false, + "logger_level": "info" } } } diff --git a/backend/consts.js b/backend/consts.js index cb8dc0a..a1fc66b 100644 --- a/backend/consts.js +++ b/backend/consts.js @@ -66,6 +66,10 @@ let CONFIG_ITEMS = { 'key': 'ytdl_settings_pin_required', 'path': 'YoutubeDLMaterial.Extra.settings_pin_required' }, + 'ytdl_enable_downloads_manager': { + 'key': 'ytdl_enable_downloads_manager', + 'path': 'YoutubeDLMaterial.Extra.enable_downloads_manager' + }, // API 'ytdl_use_api_key': { @@ -122,6 +126,10 @@ let CONFIG_ITEMS = { 'key': 'ytdl_users_base_path', 'path': 'YoutubeDLMaterial.Users.base_path' }, + 'ytdl_allow_registration': { + 'key': 'ytdl_allow_registration', + 'path': 'YoutubeDLMaterial.Users.allow_registration' + }, // Advanced 'ytdl_use_default_downloading_agent': { @@ -140,6 +148,10 @@ let CONFIG_ITEMS = { 'key': 'ytdl_allow_advanced_download', 'path': 'YoutubeDLMaterial.Advanced.allow_advanced_download' }, + 'ytdl_logger_level': { + 'key': 'ytdl_logger_level', + 'path': 'YoutubeDLMaterial.Advanced.logger_level' + } }; AVAILABLE_PERMISSIONS = [ diff --git a/src/app/app.component.html b/src/app/app.component.html index 8f58860..bb832e5 100644 --- a/src/app/app.component.html +++ b/src/app/app.component.html @@ -42,7 +42,7 @@ Home Subscriptions - Downloads + Downloads diff --git a/src/app/app.component.ts b/src/app/app.component.ts index 3fa9207..ede2bc9 100644 --- a/src/app/app.component.ts +++ b/src/app/app.component.ts @@ -41,6 +41,7 @@ export class AppComponent implements OnInit { defaultTheme = null; allowThemeChange = null; allowSubscriptions = false; + enableDownloadsManager = false; // defaults to true to prevent attack settingsPinRequired = true; @@ -83,6 +84,7 @@ export class AppComponent implements OnInit { this.defaultTheme = themingExists ? this.postsService.config['Themes']['default_theme'] : 'default'; this.allowThemeChange = themingExists ? this.postsService.config['Themes']['allow_theme_change'] : true; this.allowSubscriptions = this.postsService.config['Subscriptions']['allow_subscriptions']; + this.enableDownloadsManager = this.postsService.config['Extra']['enable_downloads_manager']; // sets theme to config default if it doesn't exist if (!localStorage.getItem('theme')) { diff --git a/src/app/components/downloads/downloads.component.ts b/src/app/components/downloads/downloads.component.ts index 0cefc39..d182633 100644 --- a/src/app/components/downloads/downloads.component.ts +++ b/src/app/components/downloads/downloads.component.ts @@ -1,6 +1,7 @@ import { Component, OnInit, ViewChildren, QueryList, ElementRef } from '@angular/core'; import { PostsService } from 'app/posts.services'; import { trigger, transition, animateChild, stagger, query, style, animate } from '@angular/animations'; +import { Router } from '@angular/router'; @Component({ selector: 'app-downloads', @@ -40,13 +41,21 @@ export class DownloadsComponent implements OnInit { valid_sessions_length = 0; - constructor(public postsService: PostsService) { } + constructor(public postsService: PostsService, private router: Router) { } ngOnInit(): void { this.getCurrentDownloads(); setInterval(() => { this.getCurrentDownloads(); }, this.downloads_check_interval); + + this.postsService.service_initialized.subscribe(init => { + if (init) { + if (!this.postsService.config['Extra']['enable_downloads_manager']) { + this.router.navigate(['/home']); + } + } + }); } getCurrentDownloads() { diff --git a/src/app/components/login/login.component.ts b/src/app/components/login/login.component.ts index 0665ee0..4906efa 100644 --- a/src/app/components/login/login.component.ts +++ b/src/app/components/login/login.component.ts @@ -18,7 +18,7 @@ export class LoginComponent implements OnInit { loggingIn = false; // registration - registrationEnabled = true; + registrationEnabled = false; registrationUsernameInput = ''; registrationPasswordInput = ''; registrationPasswordConfirmationInput = ''; @@ -35,6 +35,7 @@ export class LoginComponent implements OnInit { if (!this.postsService.config['Advanced']['multi_user_mode']) { this.router.navigate(['/home']); } + this.registrationEnabled = this.postsService.config['Users'] && this.postsService.config['Users']['allow_registration']; } }); } diff --git a/src/app/components/modify-users/modify-users.component.html b/src/app/components/modify-users/modify-users.component.html index 036ad2b..2adaad5 100644 --- a/src/app/components/modify-users/modify-users.component.html +++ b/src/app/components/modify-users/modify-users.component.html @@ -1,7 +1,7 @@
-
+
diff --git a/src/app/components/modify-users/modify-users.component.scss b/src/app/components/modify-users/modify-users.component.scss index 558267e..d509a56 100644 --- a/src/app/components/modify-users/modify-users.component.scss +++ b/src/app/components/modify-users/modify-users.component.scss @@ -1,5 +1,5 @@ .edit-role { position: relative; - top: -80px; + top: -50px; left: 35px; } \ No newline at end of file diff --git a/src/app/settings/settings.component.html b/src/app/settings/settings.component.html index b2696d5..7143ea7 100644 --- a/src/app/settings/settings.component.html +++ b/src/app/settings/settings.component.html @@ -14,13 +14,13 @@
- + URL this app will be accessed from, without the port.
- + The desired port. Default is 17442. @@ -28,6 +28,20 @@
+
+
+
+ Multi-user mode +
+
+ + + Base path for users and their downloaded videos. + +
+
+
+
@@ -35,13 +49,13 @@
- +
- +
@@ -54,13 +68,13 @@ Allow subscriptions
- + Base path for videos from your subscribed channels and playlists. It is relative to YTDL-Material's root folder.
- + Unit is seconds, only include numbers. @@ -93,7 +107,7 @@
- + Language @@ -113,21 +127,21 @@
- + Path for audio only downloads. It is relative to YTDL-Material's root folder.
- + Path for video downloads. It is relative to YTDL-Material's root folder.
- + Global custom args for downloads on the home page. @@ -148,7 +162,7 @@
- + @@ -156,6 +170,9 @@
File manager enabled
+
+ Downloads manager enabled +
Allow quality select
@@ -163,7 +180,7 @@ Download only mode
- Allow multi-download mode + Allow multi-download mode
Require pin for settings @@ -179,7 +196,7 @@
- + View documentation @@ -197,7 +214,7 @@ Use YouTube API
- + Generating a key is easy! @@ -252,12 +269,21 @@
+
+ + Select a downloader + + Debug + Verbose + Info + Warn + Error + + +
Allow advanced download
-
- Multi-user mode -
@@ -267,6 +293,9 @@ +
+ Allow user registration +
diff --git a/src/app/settings/settings.component.scss b/src/app/settings/settings.component.scss index cef5714..678c315 100644 --- a/src/app/settings/settings.component.scss +++ b/src/app/settings/settings.component.scss @@ -20,4 +20,8 @@ .api-key-div { display: inline-block; +} + +.text-field { + min-width: 30%; } \ No newline at end of file diff --git a/src/assets/default.json b/src/assets/default.json index f1ed23a..329f192 100644 --- a/src/assets/default.json +++ b/src/assets/default.json @@ -21,7 +21,8 @@ "allow_quality_select": true, "download_only_mode": false, "allow_multi_download_mode": true, - "settings_pin_required": false + "settings_pin_required": false, + "enable_downloads_manager": true }, "API": { "use_API_key": false, @@ -40,13 +41,15 @@ "subscriptions_use_youtubedl_archive": true }, "Users": { - "base_path": "users/" + "base_path": "users/", + "allow_registration": true }, "Advanced": { "use_default_downloading_agent": true, "custom_downloading_agent": "", "multi_user_mode": true, - "allow_advanced_download": true + "allow_advanced_download": true, + "logger_level": "debug" } } } \ No newline at end of file