Download manager is now functional

Added UI support for new downloads schema

Implemented draft test for downloads

Cleaned up unused code snippets
download-manager
Isaac Abadi 4 years ago
parent 5a90be7703
commit 0360469c5a

@ -30,10 +30,11 @@ if (!fs.existsSync(CONSTS.DETAILS_BIN_PATH)) fs.writeJSONSync(CONSTS.DETAILS_BIN
const youtubedl = require('youtube-dl');
const logger = require('./logger');
var config_api = require('./config.js');
var subscriptions_api = require('./subscriptions')
var categories_api = require('./categories');
var twitch_api = require('./twitch');
const config_api = require('./config.js');
const downloader_api = require('./downloader');
const subscriptions_api = require('./subscriptions');
const categories_api = require('./categories');
const twitch_api = require('./twitch');
const is_windows = process.platform === 'win32';
@ -64,6 +65,7 @@ const admin_token = '4241b401-7236-493e-92b5-b72696b9d853';
config_api.initialize();
db_api.initialize(db, users_db);
auth_api.initialize(db_api);
downloader_api.initialize(db_api);
subscriptions_api.initialize(db_api);
categories_api.initialize(db_api);
@ -1479,9 +1481,10 @@ app.post('/api/downloadFile', optionalJwt, async function(req, res) {
cropFileSettings: req.body.cropFileSettings
}
let result_obj = await downloadFileByURL_exec(url, type, options, req.query.sessionID);
if (result_obj) {
res.send(result_obj);
const download = await downloader_api.createDownload(url, type, options);
if (download) {
res.send({download: download});
} else {
res.sendStatus(500);
}
@ -2294,18 +2297,12 @@ app.get('/api/thumbnail/:path', optionalJwt, async (req, res) => {
});
app.post('/api/download', async (req, res) => {
const session_id = req.body.session_id;
const download_id = req.body.download_id;
const session_downloads = downloads.find(potential_session_downloads => potential_session_downloads['session_id'] === session_id);
let found_download = null;
const download_uid = req.body.download_uid;
// find download
if (session_downloads && Object.keys(session_downloads)) {
found_download = Object.values(session_downloads).find(session_download => session_download['ui_uid'] === download_id);
}
const download = await db_api.getRecord('download_queue', {uid: download_uid});
if (found_download) {
res.send({download: found_download});
if (download) {
res.send({download: download});
} else {
res.send({download: null});
}

@ -134,7 +134,7 @@ exports.registerUser = async function(req, res) {
exports.login = async (username, password) => {
const user = await db_api.getRecord('users', {name: username});
if (!user) { logger.error(`User ${username} not found`); false }
if (!user) { logger.error(`User ${username} not found`); return false }
if (user.auth_method && user.auth_method !== 'internal') { return false }
return await bcrypt.compare(password, user.passhash) ? user : false;
}

@ -42,6 +42,10 @@ const tables = {
name: 'roles',
primary_key: 'key'
},
download_queue: {
name: 'download_queue',
primary_key: 'uid'
},
test: {
name: 'test'
}

@ -1,58 +1,114 @@
const fs = require('fs-extra');
const { uuid } = require('uuidv4');
const path = require('path');
const queue = require('queue');
const mergeFiles = require('merge-files');
const NodeID3 = require('node-id3')
const glob = require("glob")
const youtubedl = require('youtube-dl');
const logger = require('./logger');
const config_api = require('./config');
const twitch_api = require('./twitch');
const categories_api = require('./categories');
const utils = require('./utils');
let db_api = null;
let logger = null;
const STEP_INDEX_TO_LABEL = {
0: 'Creating download',
1: 'Getting info',
2: 'Downloading file'
}
const archivePath = path.join(__dirname, 'appdata', 'archives');
function setDB(input_db_api) { db_api = input_db_api }
function setLogger(input_logger) { logger = input_logger; }
exports.initialize = (input_db_api, input_logger) => {
exports.initialize = (input_db_api) => {
setDB(input_db_api);
setLogger(input_logger);
setInterval(checkDownloads, 10000);
categories_api.initialize(db_api);
// temporary
db_api.removeAllRecords('download_queue');
}
exports.createDownload = async (url, type, options) => {
const download = {
url: url,
type: type,
options: options,
uid: uuid(),
step_index: 0,
paused: false,
finished_step: true,
error: null,
percent_complete: null,
finished: false,
timestamp_start: Date.now()
};
await db_api.insertRecordIntoTable('download_queue', download);
return download;
}
exports.pauseDownload = () => {
}
// questions
// how do we want to manage queued downloads that errored in any step? do we set the index back and finished_step to true or let the manager do it?
async function checkDownloads() {
logger.verbose('Checking downloads');
const downloads = await db_api.getRecords('download_queue');
downloads.sort((download1, download2) => download1.timestamp_start - download2.timestamp_start);
downloads = downloads.filter(download => !download.paused);
for (let i = 0; i < downloads.length; i++) {
if (i === config_api.getConfigItem('ytdl_'))
const running_downloads = downloads.filter(download => !download.paused);
for (let i = 0; i < running_downloads.length; i++) {
const running_download = running_downloads[i];
if (i === 5/*config_api.getConfigItem('ytdl_max_concurrent_downloads')*/) break;
if (running_download['finished_step'] && !running_download['finished']) {
// move to next step
if (running_download['step_index'] === 0) {
collectInfo(running_download['uid']);
} else if (running_download['step_index'] === 1) {
downloadQueuedFile(running_download['uid']);
}
}
}
}
async function createDownload(url, type, options) {
const download = {url: url, type: type, options: options, uid: uuid()};
await db_api.insertRecord(download);
return download;
}
async function collectInfo(download_uid) {
const download = db_api.getRecord('download_queue', {uid: download_uid});
logger.verbose(`Collecting info for download ${download_uid}`);
await db_api.updateRecord('download_queue', {uid: download_uid}, {step_index: 1, finished_step: false});
const download = await db_api.getRecord('download_queue', {uid: download_uid});
const url = download['url'];
const type = download['type'];
const options = download['options'];
const args = download['args'];
if (options.user && !options.customFileFolderPath) {
let usersFileFolder = config_api.getConfigItem('ytdl_users_base_path');
const user_path = path.join(usersFileFolder, options.user, type);
options.customFileFolderPath = user_path + path.sep;
}
let args = await generateArgs(url, type, options);
// get video info prior to download
const info = await getVideoInfoByURL(url, args);
let info = await getVideoInfoByURL(url, args, download_uid);
if (!info) {
// info failed, record error and pause download
const error = 'Failed to get info, see server logs for specific error.';
await db_api.updateRecord('download_queue', {uid: download_uid}, {error: error, paused: true});
return;
}
let category = null;
// check if it fits into a category. If so, then get info again using new args
if (!Array.isArray(info) || config_api.getConfigItem('ytdl_allow_playlist_categorization')) category = await categories_api.categorize(info);
@ -61,22 +117,37 @@ async function collectInfo(download_uid) {
options.customOutput = category['custom_output'];
options.noRelativePath = true;
args = await generateArgs(url, type, options);
info = await getVideoInfoByURL(url, args);
// must update args
await db_api.updateRecord('download_queue', {uid: download_uid}, {args: args});
info = await getVideoInfoByURL(url, args, download_uid);
}
await db_api.updateRecord('download_queue', {uid: download_uid}, {remote_metadata: info});
}
// setup info required to calculate download progress
async function downloadQueuedFile(url, type, options) {
const expected_file_size = utils.getExpectedFileSize(info);
const files_to_check_for_progress = [];
// store info in download for future use
if (Array.isArray(info)) {
for (let info_obj of info) files_to_check_for_progress.push(utils.removeFileExtension(info_obj['_filename']));
} else {
files_to_check_for_progress.push(utils.removeFileExtension(info['_filename']));
}
await db_api.updateRecord('download_queue', {uid: download_uid}, {args: args,
finished_step: true,
options: options,
files_to_check_for_progress: files_to_check_for_progress,
expected_file_size: expected_file_size
});
}
async function downloadFileByURL_exec(url, type, options) {
return new Promise(resolve => {
const download = db_api.getRecord('download_queue', {uid: download_uid});
async function downloadQueuedFile(download_uid) {
logger.verbose(`Downloading ${download_uid}`);
return new Promise(async resolve => {
const audioFolderPath = config_api.getConfigItem('ytdl_audio_folder_path');
const videoFolderPath = config_api.getConfigItem('ytdl_video_folder_path');
await db_api.updateRecord('download_queue', {uid: download_uid}, {step_index: 2, finished_step: false});
const download = await db_api.getRecord('download_queue', {uid: download_uid});
const url = download['url'];
const type = download['type'];
@ -84,20 +155,22 @@ async function downloadFileByURL_exec(url, type, options) {
const args = download['args'];
const category = download['category'];
let fileFolderPath = type === 'audio' ? audioFolderPath : videoFolderPath; // TODO: fix
if (options.user) {
let usersFileFolder = config_api.getConfigItem('ytdl_users_base_path');
const user_path = path.join(usersFileFolder, options.user, type);
fs.ensureDirSync(user_path);
fileFolderPath = user_path + path.sep;
options.customFileFolderPath = fileFolderPath;
if (options.customFileFolderPath) {
fileFolderPath = options.customFileFolderPath;
}
fs.ensureDirSync(fileFolderPath);
const start_time = Date.now();
const download_checker = setInterval(() => checkDownloadPercent(download['uid']), 1000);
// download file
youtubedl.exec(url, args, {maxBuffer: Infinity}, async function(err, output) {
const file_objs = [];
let new_date = Date.now();
let difference = (new_date - date)/1000;
logger.debug(`${is_audio ? 'Audio' : 'Video'} download delay: ${difference} seconds.`);
let end_time = Date.now();
let difference = (end_time - start_time)/1000;
logger.debug(`${type === 'audio' ? 'Audio' : 'Video'} download delay: ${difference} seconds.`);
clearInterval(download_checker);
if (err) {
logger.error(err.stderr);
@ -107,7 +180,6 @@ async function downloadFileByURL_exec(url, type, options) {
if (output.length === 0 || output[0].length === 0) {
// ERROR!
logger.warn(`No output received for video download, check if it exists in your archive.`)
resolve(false);
return;
}
@ -127,11 +199,12 @@ async function downloadFileByURL_exec(url, type, options) {
// get filepath with no extension
const filepath_no_extension = utils.removeFileExtension(output_json['_filename']);
const ext = type === 'audio' ? '.mp3' : '.mp4';
var full_file_path = filepath_no_extension + ext;
var file_name = filepath_no_extension.substring(fileFolderPath.length, filepath_no_extension.length);
if (type === 'video' && url.includes('twitch.tv/videos/') && url.split('twitch.tv/videos/').length > 1
&& config.getConfigItem('ytdl_use_twitch_api') && config.getConfigItem('ytdl_twitch_auto_download_chat')) {
&& config_api.getConfigItem('ytdl_use_twitch_api') && config_api.getConfigItem('ytdl_twitch_auto_download_chat')) {
let vodId = url.split('twitch.tv/videos/')[1];
vodId = vodId.split('?')[0];
twitch_api.downloadTwitchChatByVODID(vodId, file_name, type, options.user);
@ -143,6 +216,7 @@ async function downloadFileByURL_exec(url, type, options) {
fs.renameSync(output_json['_filename'] + '.webm', output_json['_filename']);
logger.info('Renamed ' + file_name + '.webm to ' + file_name);
} catch(e) {
}
}
@ -156,7 +230,7 @@ async function downloadFileByURL_exec(url, type, options) {
}
if (options.cropFileSettings) {
await cropFile(full_file_path, options.cropFileSettings.cropFileStart, options.cropFileSettings.cropFileEnd, ext);
await utils.cropFile(full_file_path, options.cropFileSettings.cropFileStart, options.cropFileSettings.cropFileEnd, ext);
}
// registers file in DB
@ -184,10 +258,9 @@ async function downloadFileByURL_exec(url, type, options) {
logger.error('Downloaded file failed to result in metadata object.');
}
resolve({
file_uids: file_objs.map(file_obj => file_obj.uid),
container: container
});
const file_uids = file_objs.map(file_obj => file_obj.uid);
await db_api.updateRecord('download_queue', {uid: download_uid}, {finished_step: true, finished: true, percent_complete: 100, file_uids: file_uids, container: container});
resolve();
}
});
});
@ -196,17 +269,20 @@ async function downloadFileByURL_exec(url, type, options) {
// helper functions
async function generateArgs(url, type, options) {
const audioFolderPath = config_api.getConfigItem('ytdl_audio_folder_path');
const videoFolderPath = config_api.getConfigItem('ytdl_video_folder_path');
const videopath = config_api.getConfigItem('ytdl_default_file_output') ? config_api.getConfigItem('ytdl_default_file_output') : '%(title)s';
const globalArgs = config_api.getConfigItem('ytdl_custom_args');
const useCookies = config_api.getConfigItem('ytdl_use_cookies');
const is_audio = type === 'audio';
const fileFolderPath = is_audio ? audioFolderPath : videoFolderPath;
let fileFolderPath = is_audio ? audioFolderPath : videoFolderPath;
if (options.customFileFolderPath) fileFolderPath = options.customFileFolderPath;
const customArgs = options.customArgs;
const customOutput = options.customOutput;
let customOutput = options.customOutput;
const customQualityConfiguration = options.customQualityConfiguration;
// video-specific args
@ -246,7 +322,7 @@ async function generateArgs(url, type, options) {
downloadConfig = ['-o', path.join(fileFolderPath, videopath + (is_audio ? '.%(ext)s' : '.mp4')), '--write-info-json', '--print-json'];
}
if (qualityPath && options.downloading_method === 'exec') downloadConfig.push(...qualityPath);
if (qualityPath) downloadConfig.push(...qualityPath);
if (is_audio && !options.skip_audio_args) {
downloadConfig.push('-x');
@ -265,6 +341,8 @@ async function generateArgs(url, type, options) {
}
}
const useDefaultDownloadingAgent = config_api.getConfigItem('ytdl_use_default_downloading_agent');
const customDownloadingAgent = config_api.getConfigItem('ytdl_custom_downloading_agent');
if (!useDefaultDownloadingAgent && customDownloadingAgent) {
downloadConfig.splice(0, 0, '--external-downloader', customDownloadingAgent);
}
@ -284,7 +362,7 @@ async function generateArgs(url, type, options) {
await fs.ensureFile(merged_path);
// merges blacklist and regular archive
let inputPathList = [archive_path, blacklist_path];
let status = await mergeFiles(inputPathList, merged_path);
await mergeFiles(inputPathList, merged_path);
options.merged_string = await fs.readFile(merged_path, "utf8");
@ -324,7 +402,7 @@ async function generateArgs(url, type, options) {
return downloadConfig;
}
async function getVideoInfoByURL(url, args = [], download = null) {
async function getVideoInfoByURL(url, args = [], download_uid = null) {
return new Promise(resolve => {
// remove bad args
const new_args = [...args];
@ -334,21 +412,85 @@ async function getVideoInfoByURL(url, args = [], download = null) {
new_args.splice(archiveArgIndex, 2);
}
// actually get info
youtubedl.getInfo(url, new_args, (err, output) => {
new_args.push('--dump-json');
youtubedl.exec(url, new_args, {maxBuffer: Infinity}, async (err, output) => {
if (output) {
resolve(output);
let outputs = [];
try {
for (let i = 0; i < output.length; i++) {
let output_json = null;
try {
output_json = JSON.parse(output[i]);
} catch(e) {
output_json = null;
}
if (!output_json) {
continue;
}
outputs.push(output_json);
}
resolve(outputs.length === 1 ? outputs[0] : outputs);
} catch(e) {
logger.error(`Error while retrieving info on video with URL ${url} with the following message: output JSON could not be parsed. Output JSON: ${output}`);
if (download_uid) {
const error = 'Failed to get info, see server logs for specific error.';
await db_api.updateRecord('download_queue', {uid: download_uid}, {error: error, paused: true});
}
resolve(null);
}
} else {
logger.error(`Error while retrieving info on video with URL ${url} with the following message: ${err}`);
if (err.stderr) {
logger.error(`${err.stderr}`)
}
if (download) {
download['error'] = `Failed pre-check for video info: ${err}`;
updateDownloads();
if (download_uid) {
const error = 'Failed to get info, see server logs for specific error.';
await db_api.updateRecord('download_queue', {uid: download_uid}, {error: error, paused: true});
}
resolve(null);
}
});
});
}
function filterArgs(args, isAudio) {
const video_only_args = ['--add-metadata', '--embed-subs', '--xattrs'];
const audio_only_args = ['-x', '--extract-audio', '--embed-thumbnail'];
const args_to_remove = isAudio ? video_only_args : audio_only_args;
return args.filter(x => !args_to_remove.includes(x));
}
async function checkDownloadPercent(download_uid) {
/*
This is more of an art than a science, we're just selecting files that start with the file name,
thus capturing the parts being downloaded in files named like so: '<video title>.<format>.<ext>.part'.
Any file that starts with <video title> will be counted as part of the "bytes downloaded", which will
be divided by the "total expected bytes."
*/
const download = await db_api.getRecord('download_queue', {uid: download_uid});
const files_to_check_for_progress = download['files_to_check_for_progress'];
const resulting_file_size = download['expected_file_size'];
if (!resulting_file_size) return;
let sum_size = 0;
glob(`{${files_to_check_for_progress.join(',')}, }*`, async (err, files) => {
files.forEach(async file => {
try {
const file_stats = fs.statSync(file);
if (file_stats && file_stats.size) {
sum_size += file_stats.size;
}
} catch (e) {
}
});
const percent_complete = (sum_size/resulting_file_size * 100).toFixed(2);
await db_api.updateRecord('download_queue', {uid: download_uid}, {percent_complete: percent_complete});
});
}

@ -40,7 +40,7 @@ const subscriptions_api = require('../subscriptions');
const fs = require('fs-extra');
const { uuid } = require('uuidv4');
db_api.initialize(db, users_db, logger);
db_api.initialize(db, users_db);
describe('Database', async function() {
@ -286,40 +286,43 @@ describe('Multi User', async function() {
// assert(video_obj);
// });
// });
});
describe('Downloader', function() {
const url = '';
const options = {
ui_uid: uuid(),
user: 'admin'
}
const download = {
url: url,
options: options,
type: 'video'
}
describe('Downloader', function() {
const downloader_api = require('../downloader');
downloader_api.initialize(db_api);
const url = 'https://www.youtube.com/watch?v=dQw4w9WgXcQ';
const options = {
ui_uid: uuid(),
user: 'admin'
}
beforeEach(async function() {
await db_api.connectToDB();
await db_api.removeAllRecords('download_queue');
await db_api.insertRecordIntoTable('download_queue', download)
});
beforeEach(async function() {
await db_api.connectToDB();
await db_api.removeAllRecords('download_queue');
});
it('Get file info', async function() {
it('Get file info', async function() {
});
it('Download file', async function() {
});
});
it('Download file', async function() {
this.timeout(300000);
const returned_download = await downloader_api.createDownload(url, 'video', options);
console.log(returned_download);
await utils.wait(20000);
it('Queue file', async function() {
});
});
it('Queue file', async function() {
this.timeout(300000);
const returned_download = await downloader_api.createDownload(url, 'video', options);
console.log(returned_download);
await utils.wait(20000);
});
it('Pause file', async function() {
it('Pause file', async function() {
});
});
});
});

@ -184,10 +184,6 @@ function getExpectedFileSize(input_info_jsons) {
let expected_filesize = 0;
info_jsons.forEach(info_json => {
if (info_json['filesize']) {
expected_filesize += info_json['filesize'];
return;
}
const formats = info_json['format_id'].split('+');
let individual_expected_filesize = 0;
formats.forEach(format_id => {

@ -182,7 +182,7 @@
</mat-card>
</div>
<br/>
<div class="centered big" id="bar_div" *ngIf="current_download && current_download.downloading; else nofile">
<div class="centered big" id="bar_div" *ngIf="current_download; else nofile">
<div class="margined">
<div [ngClass]="(+percentDownloaded > 99)?'make-room-for-spinner':'equal-sizes'" style="display: inline-block; width: 100%; padding-left: 20px" *ngIf="current_download.percent_complete && current_download.percent_complete > 1;else indeterminateprogress">
<mat-progress-bar style="border-radius: 5px;" mode="determinate" value="{{percentDownloaded}}"></mat-progress-bar>

@ -274,9 +274,9 @@ export class MainComponent implements OnInit {
const customOutput = localStorage.getItem('customOutput');
const youtubeUsername = localStorage.getItem('youtubeUsername');
if (customArgs && customArgs !== 'null') { this.customArgs = customArgs };
if (customOutput && customOutput !== 'null') { this.customOutput = customOutput };
if (youtubeUsername && youtubeUsername !== 'null') { this.youtubeUsername = youtubeUsername };
if (customArgs && customArgs !== 'null') { this.customArgs = customArgs }
if (customOutput && customOutput !== 'null') { this.customOutput = customOutput }
if (youtubeUsername && youtubeUsername !== 'null') { this.youtubeUsername = youtubeUsername }
}
// get downloads routine
@ -343,7 +343,7 @@ export class MainComponent implements OnInit {
}
public goToFile(container, isAudio, uid) {
this.downloadHelper(container, isAudio ? 'audio' : 'video', false, false, null, true);
this.downloadHelper(container, isAudio ? 'audio' : 'video', false, false, true);
}
public goToPlaylist(playlistID, type) {
@ -375,7 +375,7 @@ export class MainComponent implements OnInit {
// download helpers
downloadHelper(container, type, is_playlist = false, force_view = false, new_download = null, navigate_mode = false) {
downloadHelper(container, type, is_playlist = false, force_view = false, navigate_mode = false) {
this.downloadingfile = false;
if (this.multiDownloadMode && !this.downloadOnlyMode && !navigate_mode) {
// do nothing
@ -399,8 +399,8 @@ export class MainComponent implements OnInit {
}
}
// remove download from current downloads
this.removeDownloadFromCurrentDownloads(new_download);
// // remove download from current downloads
// this.removeDownloadFromCurrentDownloads(new_download);
}
// download click handler
@ -432,21 +432,11 @@ export class MainComponent implements OnInit {
}
const type = this.audioOnly ? 'audio' : 'video';
// create download object
const new_download: Download = {
uid: uuid(),
type: type,
percent_complete: 0,
url: this.url,
downloading: true,
is_playlist: this.url.includes('playlist'),
error: false
};
this.downloads.push(new_download);
if (!this.current_download && !this.multiDownloadMode) { this.current_download = new_download };
// this.downloads.push(new_download);
// if (!this.current_download && !this.multiDownloadMode) { this.current_download = new_download };
this.downloadingfile = true;
let customQualityConfiguration = type === 'audio' ? this.getSelectedAudioFormat() : this.getSelectedVideoFormat();
const customQualityConfiguration = type === 'audio' ? this.getSelectedAudioFormat() : this.getSelectedVideoFormat();
let cropFileSettings = null;
@ -458,26 +448,19 @@ export class MainComponent implements OnInit {
}
this.postsService.downloadFile(this.url, type, (this.selectedQuality === '' ? null : this.selectedQuality),
customQualityConfiguration, customArgs, customOutput, youtubeUsername, youtubePassword, new_download.uid, cropFileSettings).subscribe(res => {
// update download object
new_download.downloading = false;
new_download.percent_complete = 100;
const container = res['container'];
const is_playlist = res['file_uids'].length > 1;
this.current_download = null;
this.downloadHelper(container, type, is_playlist, false, new_download);
customQualityConfiguration, customArgs, customOutput, youtubeUsername, youtubePassword, cropFileSettings).subscribe(res => {
console.log(res);
this.current_download = res['download'];
this.downloadingfile = true;
}, error => { // can't access server
this.downloadingfile = false;
this.current_download = null;
new_download['downloading'] = false;
// removes download from list of downloads
const downloads_index = this.downloads.indexOf(new_download);
if (downloads_index !== -1) {
this.downloads.splice(downloads_index)
}
// new_download['downloading'] = false;
// // removes download from list of downloads
// const downloads_index = this.downloads.indexOf(new_download);
// if (downloads_index !== -1) {
// this.downloads.splice(downloads_index)
// }
this.openSnackBar('Download failed!', 'OK.');
});
@ -934,12 +917,16 @@ export class MainComponent implements OnInit {
if (!this.current_download) {
return;
}
const ui_uid = this.current_download['ui_uid'] ? this.current_download['ui_uid'] : this.current_download['uid'];
this.postsService.getCurrentDownload(this.postsService.session_id, ui_uid).subscribe(res => {
this.postsService.getCurrentDownload(this.current_download['uid']).subscribe(res => {
if (res['download']) {
if (ui_uid === res['download']['ui_uid']) {
this.current_download = res['download'];
this.percentDownloaded = this.current_download.percent_complete;
this.current_download = res['download'];
this.percentDownloaded = this.current_download.percent_complete;
if (this.current_download['finished']) {
const container = this.current_download['container'];
const is_playlist = this.current_download['file_uids'].length > 1;
this.downloadHelper(container, this.current_download['type'], is_playlist, false);
this.current_download = null;
}
} else {
// console.log('failed to get new download');

@ -345,22 +345,6 @@ export class PlayerComponent implements OnInit, AfterViewInit, OnDestroy {
return JSON.stringify(this.playlist) !== this.original_playlist;
}
updatePlaylist() {
const fileNames = this.getFileNames();
this.playlist_updating = true;
this.postsService.updatePlaylistFiles(this.playlist_id, fileNames, this.type).subscribe(res => {
this.playlist_updating = false;
if (res['success']) {
const fileNamesEncoded = fileNames.join('|nvr|');
this.router.navigate(['/player', {fileNames: fileNamesEncoded, type: this.type, id: this.playlist_id}]);
this.openSnackBar('Successfully updated playlist.', '');
this.original_playlist = JSON.stringify(this.playlist);
} else {
this.openSnackBar('ERROR: Failed to update playlist.', '');
}
})
}
openShareDialog() {
const dialogRef = this.dialog.open(ShareMediaDialogComponent, {
data: {

@ -174,7 +174,7 @@ export class PostsService implements CanActivate {
}
// tslint:disable-next-line: max-line-length
downloadFile(url: string, type: string, selectedQuality: string, customQualityConfiguration: string, customArgs: string = null, customOutput: string = null, youtubeUsername: string = null, youtubePassword: string = null, ui_uid = null, cropFileSettings = null) {
downloadFile(url: string, type: string, selectedQuality: string, customQualityConfiguration: string, customArgs: string = null, customOutput: string = null, youtubeUsername: string = null, youtubePassword: string = null, cropFileSettings = null) {
return this.http.post(this.path + 'downloadFile', {url: url,
selectedHeight: selectedQuality,
customQualityConfiguration: customQualityConfiguration,
@ -182,7 +182,6 @@ export class PostsService implements CanActivate {
customOutput: customOutput,
youtubeUsername: youtubeUsername,
youtubePassword: youtubePassword,
ui_uid: ui_uid,
type: type,
cropFileSettings: cropFileSettings}, this.httpOptions);
}
@ -345,12 +344,6 @@ export class PostsService implements CanActivate {
return this.http.post(this.path + 'updatePlaylist', {playlist: playlist}, this.httpOptions);
}
updatePlaylistFiles(playlist_id, fileNames, type) {
return this.http.post(this.path + 'updatePlaylistFiles', {playlist_id: playlist_id,
fileNames: fileNames,
type: type}, this.httpOptions);
}
addFileToPlaylist(playlist_id, file_uid) {
return this.http.post(this.path + 'addFileToPlaylist', {playlist_id: playlist_id,
file_uid: file_uid},
@ -426,8 +419,8 @@ export class PostsService implements CanActivate {
}
// current download
getCurrentDownload(session_id, download_id) {
return this.http.post(this.path + 'download', {download_id: download_id, session_id: session_id}, this.httpOptions);
getCurrentDownload(download_uid) {
return this.http.post(this.path + 'download', {download_uid: download_uid}, this.httpOptions);
}
// clear downloads. download_id is optional, if it exists only 1 download will be cleared

Loading…
Cancel
Save