mirror of
https://github.com/Tzahi12345/YoutubeDL-Material.git
synced 2026-04-20 21:23:21 +03:00
Refactored player component to utilize uids instead of fileNames to improve maintainability, consistency, and reliability
Playlists now use uids instead of fileNames Added generic getPlaylist and updatePlaylist functions
This commit is contained in:
164
backend/app.js
164
backend/app.js
@@ -139,6 +139,8 @@ var updaterStatus = null;
|
|||||||
|
|
||||||
var timestamp_server_start = Date.now();
|
var timestamp_server_start = Date.now();
|
||||||
|
|
||||||
|
const concurrentStreams = {};
|
||||||
|
|
||||||
if (debugMode) logger.info('YTDL-Material in debug mode!');
|
if (debugMode) logger.info('YTDL-Material in debug mode!');
|
||||||
|
|
||||||
// check if just updated
|
// check if just updated
|
||||||
@@ -1849,14 +1851,14 @@ const optionalJwt = function (req, res, next) {
|
|||||||
const multiUserMode = config_api.getConfigItem('ytdl_multi_user_mode');
|
const multiUserMode = config_api.getConfigItem('ytdl_multi_user_mode');
|
||||||
if (multiUserMode && ((req.body && req.body.uuid) || (req.query && req.query.uuid)) && (req.path.includes('/api/getFile') ||
|
if (multiUserMode && ((req.body && req.body.uuid) || (req.query && req.query.uuid)) && (req.path.includes('/api/getFile') ||
|
||||||
req.path.includes('/api/stream') ||
|
req.path.includes('/api/stream') ||
|
||||||
|
req.path.includes('/api/getPlaylist') ||
|
||||||
req.path.includes('/api/downloadFile'))) {
|
req.path.includes('/api/downloadFile'))) {
|
||||||
// check if shared video
|
// check if shared video
|
||||||
const using_body = req.body && req.body.uuid;
|
const using_body = req.body && req.body.uuid;
|
||||||
const uuid = using_body ? req.body.uuid : req.query.uuid;
|
const uuid = using_body ? req.body.uuid : req.query.uuid;
|
||||||
const uid = using_body ? req.body.uid : req.query.uid;
|
const uid = using_body ? req.body.uid : req.query.uid;
|
||||||
const type = using_body ? req.body.type : req.query.type;
|
const playlist_id = using_body ? req.body.playlist_id : req.query.playlist_id;
|
||||||
const playlist_id = using_body ? req.body.id : req.query.id;
|
const file = !playlist_id ? auth_api.getUserVideo(uuid, uid, true) : db_api.getPlaylist(playlist_id, uuid, true);
|
||||||
const file = !playlist_id ? auth_api.getUserVideo(uuid, uid, type, true, req.body) : auth_api.getUserPlaylist(uuid, playlist_id, null, false);
|
|
||||||
if (file) {
|
if (file) {
|
||||||
req.can_watch = true;
|
req.can_watch = true;
|
||||||
return next();
|
return next();
|
||||||
@@ -2118,6 +2120,34 @@ app.post('/api/getAllFiles', optionalJwt, async function (req, res) {
|
|||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
app.post('/api/checkConcurrentStream', async (req, res) => {
|
||||||
|
const uid = req.body.uid;
|
||||||
|
|
||||||
|
const DEAD_SERVER_THRESHOLD = 10;
|
||||||
|
|
||||||
|
if (concurrentStreams[uid] && Date.now()/1000 - concurrentStreams[uid]['unix_timestamp'] > DEAD_SERVER_THRESHOLD) {
|
||||||
|
logger.verbose( `Killing dead stream on ${uid}`);
|
||||||
|
delete concurrentStreams[uid];
|
||||||
|
}
|
||||||
|
|
||||||
|
res.send({stream: concurrentStreams[uid]})
|
||||||
|
});
|
||||||
|
|
||||||
|
app.post('/api/updateConcurrentStream', optionalJwt, async (req, res) => {
|
||||||
|
const uid = req.body.uid;
|
||||||
|
const playback_timestamp = req.body.playback_timestamp;
|
||||||
|
const unix_timestamp = req.body.unix_timestamp;
|
||||||
|
const playing = req.body.playing;
|
||||||
|
|
||||||
|
concurrentStreams[uid] = {
|
||||||
|
playback_timestamp: playback_timestamp,
|
||||||
|
unix_timestamp: unix_timestamp,
|
||||||
|
playing: playing
|
||||||
|
}
|
||||||
|
|
||||||
|
res.send({stream: concurrentStreams[uid]})
|
||||||
|
});
|
||||||
|
|
||||||
app.post('/api/getFullTwitchChat', optionalJwt, async (req, res) => {
|
app.post('/api/getFullTwitchChat', optionalJwt, async (req, res) => {
|
||||||
var id = req.body.id;
|
var id = req.body.id;
|
||||||
var type = req.body.type;
|
var type = req.body.type;
|
||||||
@@ -2174,7 +2204,7 @@ app.post('/api/enableSharing', optionalJwt, function(req, res) {
|
|||||||
// single-user mode
|
// single-user mode
|
||||||
try {
|
try {
|
||||||
success = true;
|
success = true;
|
||||||
if (!is_playlist && type !== 'subscription') {
|
if (!is_playlist) {
|
||||||
db.get(`files`)
|
db.get(`files`)
|
||||||
.find({uid: uid})
|
.find({uid: uid})
|
||||||
.assign({sharingEnabled: true})
|
.assign({sharingEnabled: true})
|
||||||
@@ -2184,7 +2214,7 @@ app.post('/api/enableSharing', optionalJwt, function(req, res) {
|
|||||||
.find({id: uid})
|
.find({id: uid})
|
||||||
.assign({sharingEnabled: true})
|
.assign({sharingEnabled: true})
|
||||||
.write();
|
.write();
|
||||||
} else if (type === 'subscription') {
|
} else if (false) {
|
||||||
// TODO: Implement. Main blocker right now is subscription videos are not stored in the DB, they are searched for every
|
// TODO: Implement. Main blocker right now is subscription videos are not stored in the DB, they are searched for every
|
||||||
// time they are requested from the subscription directory.
|
// time they are requested from the subscription directory.
|
||||||
} else {
|
} else {
|
||||||
@@ -2193,6 +2223,7 @@ app.post('/api/enableSharing', optionalJwt, function(req, res) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
} catch(err) {
|
} catch(err) {
|
||||||
|
logger.error(err);
|
||||||
success = false;
|
success = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -2525,14 +2556,14 @@ app.post('/api/getSubscriptions', optionalJwt, async (req, res) => {
|
|||||||
|
|
||||||
app.post('/api/createPlaylist', optionalJwt, async (req, res) => {
|
app.post('/api/createPlaylist', optionalJwt, async (req, res) => {
|
||||||
let playlistName = req.body.playlistName;
|
let playlistName = req.body.playlistName;
|
||||||
let fileNames = req.body.fileNames;
|
let uids = req.body.uids;
|
||||||
let type = req.body.type;
|
let type = req.body.type;
|
||||||
let thumbnailURL = req.body.thumbnailURL;
|
let thumbnailURL = req.body.thumbnailURL;
|
||||||
let duration = req.body.duration;
|
let duration = req.body.duration;
|
||||||
|
|
||||||
let new_playlist = {
|
let new_playlist = {
|
||||||
name: playlistName,
|
name: playlistName,
|
||||||
fileNames: fileNames,
|
uids: uids,
|
||||||
id: shortid.generate(),
|
id: shortid.generate(),
|
||||||
thumbnailURL: thumbnailURL,
|
thumbnailURL: thumbnailURL,
|
||||||
type: type,
|
type: type,
|
||||||
@@ -2556,15 +2587,19 @@ app.post('/api/createPlaylist', optionalJwt, async (req, res) => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
app.post('/api/getPlaylist', optionalJwt, async (req, res) => {
|
app.post('/api/getPlaylist', optionalJwt, async (req, res) => {
|
||||||
let playlistID = req.body.playlistID;
|
let playlist_id = req.body.playlist_id;
|
||||||
let uuid = req.body.uuid;
|
let uuid = req.body.uuid ? req.body.uuid : (req.user && req.user.uid ? req.user.uid : null);
|
||||||
|
let include_file_metadata = req.body.include_file_metadata;
|
||||||
|
|
||||||
let playlist = null;
|
const playlist = await db_api.getPlaylist(playlist_id, uuid);
|
||||||
|
|
||||||
if (req.isAuthenticated()) {
|
if (playlist && include_file_metadata) {
|
||||||
playlist = auth_api.getUserPlaylist(uuid ? uuid : req.user.uid, playlistID);
|
playlist['file_objs'] = [];
|
||||||
} else {
|
for (let i = 0; i < playlist['uids'].length; i++) {
|
||||||
playlist = db.get(`playlists`).find({id: playlistID}).value();
|
const uid = playlist['uids'][i];
|
||||||
|
const file_obj = await db_api.getVideo(uid, uuid);
|
||||||
|
playlist['file_objs'].push(file_obj);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
res.send({
|
res.send({
|
||||||
@@ -2576,16 +2611,16 @@ app.post('/api/getPlaylist', optionalJwt, async (req, res) => {
|
|||||||
|
|
||||||
app.post('/api/updatePlaylistFiles', optionalJwt, async (req, res) => {
|
app.post('/api/updatePlaylistFiles', optionalJwt, async (req, res) => {
|
||||||
let playlistID = req.body.playlistID;
|
let playlistID = req.body.playlistID;
|
||||||
let fileNames = req.body.fileNames;
|
let uids = req.body.uids;
|
||||||
|
|
||||||
let success = false;
|
let success = false;
|
||||||
try {
|
try {
|
||||||
if (req.isAuthenticated()) {
|
if (req.isAuthenticated()) {
|
||||||
auth_api.updatePlaylistFiles(req.user.uid, playlistID, fileNames);
|
auth_api.updatePlaylistFiles(req.user.uid, playlistID, uids);
|
||||||
} else {
|
} else {
|
||||||
db.get(`playlists`)
|
db.get(`playlists`)
|
||||||
.find({id: playlistID})
|
.find({id: playlistID})
|
||||||
.assign({fileNames: fileNames})
|
.assign({uids: uids})
|
||||||
.write();
|
.write();
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -2664,51 +2699,36 @@ app.post('/api/deleteFile', optionalJwt, async (req, res) => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
app.post('/api/downloadFile', optionalJwt, async (req, res) => {
|
app.post('/api/downloadFile', optionalJwt, async (req, res) => {
|
||||||
let fileNames = req.body.fileNames;
|
let uid = req.body.uid;
|
||||||
let zip_mode = req.body.zip_mode;
|
let is_playlist = req.body.is_playlist;
|
||||||
let type = req.body.type;
|
let uuid = req.body.uuid;
|
||||||
let outputName = req.body.outputName;
|
|
||||||
let fullPathProvided = req.body.fullPathProvided;
|
|
||||||
let subscriptionName = req.body.subscriptionName;
|
|
||||||
let subscriptionPlaylist = req.body.subPlaylist;
|
|
||||||
let file = null;
|
|
||||||
if (!zip_mode) {
|
|
||||||
fileNames = decodeURIComponent(fileNames);
|
|
||||||
const is_audio = type === 'audio';
|
|
||||||
const fileFolderPath = is_audio ? audioFolderPath : videoFolderPath;
|
|
||||||
const ext = is_audio ? '.mp3' : '.mp4';
|
|
||||||
|
|
||||||
let base_path = fileFolderPath;
|
let file_path_to_download = null;
|
||||||
let usersFileFolder = null;
|
|
||||||
const multiUserMode = config_api.getConfigItem('ytdl_multi_user_mode');
|
|
||||||
if (multiUserMode && (req.body.uuid || req.user.uid)) {
|
|
||||||
usersFileFolder = config_api.getConfigItem('ytdl_users_base_path');
|
|
||||||
base_path = path.join(usersFileFolder, req.body.uuid ? req.body.uuid : req.user.uid, type);
|
|
||||||
}
|
|
||||||
if (!subscriptionName) {
|
|
||||||
file = path.join(__dirname, base_path, fileNames + ext);
|
|
||||||
} else {
|
|
||||||
let basePath = null;
|
|
||||||
if (usersFileFolder)
|
|
||||||
basePath = path.join(usersFileFolder, req.user.uid, 'subscriptions');
|
|
||||||
else
|
|
||||||
basePath = config_api.getConfigItem('ytdl_subscriptions_base_path');
|
|
||||||
|
|
||||||
file = path.join(__dirname, basePath, (subscriptionPlaylist === true || subscriptionPlaylist === 'true' ? 'playlists' : 'channels'), subscriptionName, fileNames + ext);
|
if (!uuid && req.user) uuid = req.user.uid;
|
||||||
|
if (is_playlist) {
|
||||||
|
const playlist_files_to_download = [];
|
||||||
|
const playlist = db_api.getPlaylist(uid, uuid);
|
||||||
|
for (let i = 0; i < playlist['uids'].length; i++) {
|
||||||
|
const uid = playlist['uids'][i];
|
||||||
|
const file_obj = await db_api.getVideo(uid, uuid);
|
||||||
|
playlist_files_to_download.push(file_obj.path);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// generate zip
|
||||||
|
file_path_to_download = await createPlaylistZipFile(playlist_files_to_download, playlist.type, playlist.name);
|
||||||
} else {
|
} else {
|
||||||
for (let i = 0; i < fileNames.length; i++) {
|
const file_obj = await db_api.getVideo(uid, uuid)
|
||||||
fileNames[i] = decodeURIComponent(fileNames[i]);
|
file_path_to_download = file_obj.path;
|
||||||
}
|
|
||||||
file = await createPlaylistZipFile(fileNames, type, outputName, fullPathProvided, req.body.uuid || req.user.uid);
|
|
||||||
if (!path.isAbsolute(file)) file = path.join(__dirname, file);
|
|
||||||
}
|
}
|
||||||
res.sendFile(file, function (err) {
|
if (!path.isAbsolute(file_path_to_download)) file_path_to_download = path.join(__dirname, file_path_to_download);
|
||||||
|
res.sendFile(file_path_to_download, function (err) {
|
||||||
if (err) {
|
if (err) {
|
||||||
logger.error(err);
|
logger.error(err);
|
||||||
} else if (fullPathProvided) {
|
} else if (is_playlist) {
|
||||||
try {
|
try {
|
||||||
fs.unlinkSync(file);
|
// delete generated zip file
|
||||||
|
fs.unlinkSync(file_path_to_download);
|
||||||
} catch(e) {
|
} catch(e) {
|
||||||
logger.error("Failed to remove file", file);
|
logger.error("Failed to remove file", file);
|
||||||
}
|
}
|
||||||
@@ -2783,31 +2803,21 @@ app.post('/api/generateNewAPIKey', function (req, res) {
|
|||||||
|
|
||||||
// Streaming API calls
|
// Streaming API calls
|
||||||
|
|
||||||
app.get('/api/stream/:id', optionalJwt, (req, res) => {
|
app.get('/api/stream', optionalJwt, async (req, res) => {
|
||||||
const type = req.query.type;
|
const type = req.query.type;
|
||||||
const ext = type === 'audio' ? '.mp3' : '.mp4';
|
const ext = type === 'audio' ? '.mp3' : '.mp4';
|
||||||
const mimetype = type === 'audio' ? 'audio/mp3' : 'video/mp4';
|
const mimetype = type === 'audio' ? 'audio/mp3' : 'video/mp4';
|
||||||
var head;
|
var head;
|
||||||
let optionalParams = url_api.parse(req.url,true).query;
|
let optionalParams = url_api.parse(req.url,true).query;
|
||||||
let id = decodeURIComponent(req.params.id);
|
let uid = decodeURIComponent(req.query.uid);
|
||||||
let file_path = req.query.file_path ? decodeURIComponent(req.query.file_path.split('?')[0]) : null;
|
|
||||||
if (!file_path && (req.isAuthenticated() || req.can_watch)) {
|
|
||||||
let usersFileFolder = config_api.getConfigItem('ytdl_users_base_path');
|
|
||||||
if (optionalParams['subName']) {
|
|
||||||
const isPlaylist = optionalParams['subPlaylist'];
|
|
||||||
file_path = path.join(usersFileFolder, req.user.uid, 'subscriptions', (isPlaylist === 'true' ? 'playlists/' : 'channels/'),optionalParams['subName'], id + ext)
|
|
||||||
} else {
|
|
||||||
file_path = path.join(usersFileFolder, req.query.uuid ? req.query.uuid : req.user.uid, type, id + ext);
|
|
||||||
}
|
|
||||||
} else if (!file_path && optionalParams['subName']) {
|
|
||||||
let basePath = config_api.getConfigItem('ytdl_subscriptions_base_path');
|
|
||||||
const isPlaylist = optionalParams['subPlaylist'];
|
|
||||||
basePath += (isPlaylist === 'true' ? 'playlists/' : 'channels/');
|
|
||||||
file_path = basePath + optionalParams['subName'] + '/' + id + ext;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!file_path) {
|
let file_path = null;
|
||||||
file_path = path.join(type === 'audio' ? audioFolderPath : videoFolderPath, id + ext);
|
|
||||||
|
const multiUserMode = config_api.getConfigItem('ytdl_multi_user_mode');
|
||||||
|
if (!multiUserMode || req.isAuthenticated() || req.can_watch) {
|
||||||
|
const file_obj = await db_api.getVideo(uid, req.query.uuid ? req.query.uuid : (req.user ? req.user.uid : null), req.query.sub_id);
|
||||||
|
if (file_obj) file_path = file_obj['path'];
|
||||||
|
else file_path = null;
|
||||||
}
|
}
|
||||||
|
|
||||||
const stat = fs.statSync(file_path)
|
const stat = fs.statSync(file_path)
|
||||||
@@ -2821,11 +2831,11 @@ app.get('/api/stream/:id', optionalJwt, (req, res) => {
|
|||||||
: fileSize-1
|
: fileSize-1
|
||||||
const chunksize = (end-start)+1
|
const chunksize = (end-start)+1
|
||||||
const file = fs.createReadStream(file_path, {start, end})
|
const file = fs.createReadStream(file_path, {start, end})
|
||||||
if (config_api.descriptors[id]) config_api.descriptors[id].push(file);
|
if (config_api.descriptors[uid]) config_api.descriptors[uid].push(file);
|
||||||
else config_api.descriptors[id] = [file];
|
else config_api.descriptors[uid] = [file];
|
||||||
file.on('close', function() {
|
file.on('close', function() {
|
||||||
let index = config_api.descriptors[id].indexOf(file);
|
let index = config_api.descriptors[uid].indexOf(file);
|
||||||
config_api.descriptors[id].splice(index, 1);
|
config_api.descriptors[uid].splice(index, 1);
|
||||||
logger.debug('Successfully closed stream and removed file reference.');
|
logger.debug('Successfully closed stream and removed file reference.');
|
||||||
});
|
});
|
||||||
head = {
|
head = {
|
||||||
|
|||||||
@@ -10,12 +10,12 @@ var users_db = null;
|
|||||||
function setDB(input_db, input_users_db) { db = input_db; users_db = input_users_db }
|
function setDB(input_db, input_users_db) { db = input_db; users_db = input_users_db }
|
||||||
function setLogger(input_logger) { logger = input_logger; }
|
function setLogger(input_logger) { logger = input_logger; }
|
||||||
|
|
||||||
function initialize(input_db, input_users_db, input_logger) {
|
exports.initialize = (input_db, input_users_db, input_logger) => {
|
||||||
setDB(input_db, input_users_db);
|
setDB(input_db, input_users_db);
|
||||||
setLogger(input_logger);
|
setLogger(input_logger);
|
||||||
}
|
}
|
||||||
|
|
||||||
function registerFileDB(file_path, type, multiUserMode = null, sub = null, customPath = null, category = null, cropFileSettings = null) {
|
exports.registerFileDB = (file_path, type, multiUserMode = null, sub = null, customPath = null, category = null, cropFileSettings = null) => {
|
||||||
let db_path = null;
|
let db_path = null;
|
||||||
const file_id = utils.removeFileExtension(file_path);
|
const file_id = utils.removeFileExtension(file_path);
|
||||||
const file_object = generateFileObject(file_id, type, customPath || multiUserMode && multiUserMode.file_path, sub);
|
const file_object = generateFileObject(file_id, type, customPath || multiUserMode && multiUserMode.file_path, sub);
|
||||||
@@ -107,23 +107,11 @@ function generateFileObject(id, type, customPath = null, sub = null) {
|
|||||||
return file_obj;
|
return file_obj;
|
||||||
}
|
}
|
||||||
|
|
||||||
function updatePlaylist(playlist, user_uid) {
|
|
||||||
let playlistID = playlist.id;
|
|
||||||
let db_loc = null;
|
|
||||||
if (user_uid) {
|
|
||||||
db_loc = users_db.get('users').find({uid: user_uid}).get(`playlists`).find({id: playlistID});
|
|
||||||
} else {
|
|
||||||
db_loc = db.get(`playlists`).find({id: playlistID});
|
|
||||||
}
|
|
||||||
db_loc.assign(playlist).write();
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
function getAppendedBasePathSub(sub, base_path) {
|
function getAppendedBasePathSub(sub, base_path) {
|
||||||
return path.join(base_path, (sub.isPlaylist ? 'playlists/' : 'channels/'), sub.name);
|
return path.join(base_path, (sub.isPlaylist ? 'playlists/' : 'channels/'), sub.name);
|
||||||
}
|
}
|
||||||
|
|
||||||
function getFileDirectoriesAndDBs() {
|
exports.getFileDirectoriesAndDBs = () => {
|
||||||
let dirs_to_check = [];
|
let dirs_to_check = [];
|
||||||
let subscriptions_to_check = [];
|
let subscriptions_to_check = [];
|
||||||
const subscriptions_base_path = config_api.getConfigItem('ytdl_subscriptions_base_path'); // only for single-user mode
|
const subscriptions_base_path = config_api.getConfigItem('ytdl_subscriptions_base_path'); // only for single-user mode
|
||||||
@@ -192,8 +180,8 @@ function getFileDirectoriesAndDBs() {
|
|||||||
return dirs_to_check;
|
return dirs_to_check;
|
||||||
}
|
}
|
||||||
|
|
||||||
async function importUnregisteredFiles() {
|
exports.importUnregisteredFiles = async () => {
|
||||||
const dirs_to_check = getFileDirectoriesAndDBs();
|
const dirs_to_check = exports.getFileDirectoriesAndDBs();
|
||||||
|
|
||||||
// run through check list and check each file to see if it's missing from the db
|
// run through check list and check each file to see if it's missing from the db
|
||||||
for (const dir_to_check of dirs_to_check) {
|
for (const dir_to_check of dirs_to_check) {
|
||||||
@@ -213,7 +201,7 @@ async function importUnregisteredFiles() {
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
async function preimportUnregisteredSubscriptionFile(sub, appendedBasePath) {
|
exports.preimportUnregisteredSubscriptionFile = async (sub, appendedBasePath) => {
|
||||||
const preimported_file_paths = [];
|
const preimported_file_paths = [];
|
||||||
|
|
||||||
let dbPath = null;
|
let dbPath = null;
|
||||||
@@ -236,13 +224,60 @@ async function preimportUnregisteredSubscriptionFile(sub, appendedBasePath) {
|
|||||||
return preimported_file_paths;
|
return preimported_file_paths;
|
||||||
}
|
}
|
||||||
|
|
||||||
async function getVideo(file_uid, uuid, sub_id) {
|
exports.getPlaylist = async (playlist_id, user_uid = null, require_sharing = false) => {
|
||||||
|
let playlist = null
|
||||||
|
if (user_uid) {
|
||||||
|
playlist = users_db.get('users').find({uid: user_uid}).get(`playlists`).find({id: playlist_id}).value();
|
||||||
|
|
||||||
|
// prevent unauthorized users from accessing the file info
|
||||||
|
if (require_sharing && !playlist['sharingEnabled']) return null;
|
||||||
|
} else {
|
||||||
|
playlist = db.get(`playlists`).find({id: playlist_id}).value();
|
||||||
|
}
|
||||||
|
|
||||||
|
// converts playlists to new UID-based schema
|
||||||
|
if (playlist && playlist['fileNames'] && !playlist['uids']) {
|
||||||
|
playlist['uids'] = [];
|
||||||
|
logger.verbose(`Converting playlist ${playlist['name']} to new UID-based schema.`);
|
||||||
|
for (let i = 0; i < playlist['fileNames'].length; i++) {
|
||||||
|
const fileName = playlist['fileNames'][i];
|
||||||
|
const uid = exports.getVideoUIDByID(fileName, user_uid);
|
||||||
|
if (uid) playlist['uids'].push(uid);
|
||||||
|
else logger.warn(`Failed to convert file with name ${fileName} to its UID while converting playlist ${playlist['name']} to the new UID-based schema. The original file is likely missing/deleted and it will be skipped.`);
|
||||||
|
}
|
||||||
|
delete playlist['fileNames'];
|
||||||
|
exports.updatePlaylist(playlist, user_uid);
|
||||||
|
}
|
||||||
|
|
||||||
|
return playlist;
|
||||||
|
}
|
||||||
|
|
||||||
|
exports.updatePlaylist = (playlist, user_uid = null) => {
|
||||||
|
let playlistID = playlist.id;
|
||||||
|
let db_loc = null;
|
||||||
|
if (user_uid) {
|
||||||
|
db_loc = users_db.get('users').find({uid: user_uid}).get(`playlists`).find({id: playlistID});
|
||||||
|
} else {
|
||||||
|
db_loc = db.get(`playlists`).find({id: playlistID});
|
||||||
|
}
|
||||||
|
db_loc.assign(playlist).write();
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Video ID is basically just the file name without the base path and file extension - this method helps us get away from that
|
||||||
|
exports.getVideoUIDByID = (file_id, uuid = null) => {
|
||||||
|
const base_db_path = uuid ? users_db.get('users').find({uid: uuid}) : db;
|
||||||
|
const file_obj = base_db_path.get('files').find({id: file_id}).value();
|
||||||
|
return file_obj ? file_obj['uid'] : null;
|
||||||
|
}
|
||||||
|
|
||||||
|
exports.getVideo = async (file_uid, uuid, sub_id) => {
|
||||||
const base_db_path = uuid ? users_db.get('users').find({uid: uuid}) : db;
|
const base_db_path = uuid ? users_db.get('users').find({uid: uuid}) : db;
|
||||||
const sub_db_path = sub_id ? base_db_path.get('subscriptions').find({id: sub_id}).get('videos') : base_db_path.get('files');
|
const sub_db_path = sub_id ? base_db_path.get('subscriptions').find({id: sub_id}).get('videos') : base_db_path.get('files');
|
||||||
return sub_db_path.find({uid: file_uid}).value();
|
return sub_db_path.find({uid: file_uid}).value();
|
||||||
}
|
}
|
||||||
|
|
||||||
async function setVideoProperty(file_uid, assignment_obj, uuid, sub_id) {
|
exports.setVideoProperty = async (file_uid, assignment_obj, uuid, sub_id) => {
|
||||||
const base_db_path = uuid ? users_db.get('users').find({uid: uuid}) : db;
|
const base_db_path = uuid ? users_db.get('users').find({uid: uuid}) : db;
|
||||||
const sub_db_path = sub_id ? base_db_path.get('subscriptions').find({id: sub_id}).get('videos') : base_db_path.get('files');
|
const sub_db_path = sub_id ? base_db_path.get('subscriptions').find({id: sub_id}).get('videos') : base_db_path.get('files');
|
||||||
const file_db_path = sub_db_path.find({uid: file_uid});
|
const file_db_path = sub_db_path.find({uid: file_uid});
|
||||||
@@ -251,14 +286,3 @@ async function setVideoProperty(file_uid, assignment_obj, uuid, sub_id) {
|
|||||||
}
|
}
|
||||||
sub_db_path.find({uid: file_uid}).assign(assignment_obj).write();
|
sub_db_path.find({uid: file_uid}).assign(assignment_obj).write();
|
||||||
}
|
}
|
||||||
|
|
||||||
module.exports = {
|
|
||||||
initialize: initialize,
|
|
||||||
registerFileDB: registerFileDB,
|
|
||||||
updatePlaylist: updatePlaylist,
|
|
||||||
getFileDirectoriesAndDBs: getFileDirectoriesAndDBs,
|
|
||||||
importUnregisteredFiles: importUnregisteredFiles,
|
|
||||||
preimportUnregisteredSubscriptionFile: preimportUnregisteredSubscriptionFile,
|
|
||||||
getVideo: getVideo,
|
|
||||||
setVideoProperty: setVideoProperty
|
|
||||||
}
|
|
||||||
|
|||||||
@@ -57,12 +57,11 @@ export class CustomPlaylistsComponent implements OnInit {
|
|||||||
|
|
||||||
if (playlist) {
|
if (playlist) {
|
||||||
if (this.postsService.config['Extra']['download_only_mode']) {
|
if (this.postsService.config['Extra']['download_only_mode']) {
|
||||||
this.downloading_content[type][playlistID] = true;
|
this.downloadPlaylist(playlist.id, playlist.name);
|
||||||
this.downloadPlaylist(playlist.fileNames, type, playlist.name, playlistID);
|
|
||||||
} else {
|
} else {
|
||||||
localStorage.setItem('player_navigator', this.router.url);
|
localStorage.setItem('player_navigator', this.router.url);
|
||||||
const fileNames = playlist.fileNames;
|
const fileNames = playlist.fileNames;
|
||||||
this.router.navigate(['/player', {fileNames: fileNames.join('|nvr|'), type: type, id: playlistID, uid: playlistID, auto: playlist.auto}]);
|
this.router.navigate(['/player', {playlist_id: playlistID, auto: playlist.auto}]);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
// playlist not found
|
// playlist not found
|
||||||
@@ -70,11 +69,12 @@ export class CustomPlaylistsComponent implements OnInit {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
downloadPlaylist(fileNames, type, zipName = null, playlistID = null) {
|
downloadPlaylist(playlist_id, playlist_name) {
|
||||||
this.postsService.downloadFileFromServer(fileNames, type, zipName).subscribe(res => {
|
this.downloading_content[playlist_id] = true;
|
||||||
if (playlistID) { this.downloading_content[type][playlistID] = false };
|
this.postsService.downloadPlaylistFromServer(playlist_id).subscribe(res => {
|
||||||
const blob: Blob = res;
|
this.downloading_content[playlist_id] = false;
|
||||||
saveAs(blob, zipName + '.zip');
|
const blob: any = res;
|
||||||
|
saveAs(blob, playlist_name + '.zip');
|
||||||
});
|
});
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -201,8 +201,7 @@ export class RecentVideosComponent implements OnInit {
|
|||||||
const type = file.isAudio ? 'audio' : 'video';
|
const type = file.isAudio ? 'audio' : 'video';
|
||||||
const ext = type === 'audio' ? '.mp3' : '.mp4'
|
const ext = type === 'audio' ? '.mp3' : '.mp4'
|
||||||
const sub = this.postsService.getSubscriptionByID(file.sub_id);
|
const sub = this.postsService.getSubscriptionByID(file.sub_id);
|
||||||
this.postsService.downloadFileFromServer(file.id, type, null, null, sub.name, sub.isPlaylist,
|
this.postsService.downloadFileFromServer(file.uid).subscribe(res => {
|
||||||
this.postsService.user ? this.postsService.user.uid : null, null).subscribe(res => {
|
|
||||||
const blob: Blob = res;
|
const blob: Blob = res;
|
||||||
saveAs(blob, file.id + ext);
|
saveAs(blob, file.id + ext);
|
||||||
}, err => {
|
}, err => {
|
||||||
@@ -215,7 +214,7 @@ export class RecentVideosComponent implements OnInit {
|
|||||||
const ext = type === 'audio' ? '.mp3' : '.mp4'
|
const ext = type === 'audio' ? '.mp3' : '.mp4'
|
||||||
const name = file.id;
|
const name = file.id;
|
||||||
this.downloading_content[type][name] = true;
|
this.downloading_content[type][name] = true;
|
||||||
this.postsService.downloadFileFromServer(name, type).subscribe(res => {
|
this.postsService.downloadFileFromServer(file.uid).subscribe(res => {
|
||||||
this.downloading_content[type][name] = false;
|
this.downloading_content[type][name] = false;
|
||||||
const blob: Blob = res;
|
const blob: Blob = res;
|
||||||
saveAs(blob, decodeURIComponent(name) + ext);
|
saveAs(blob, decodeURIComponent(name) + ext);
|
||||||
|
|||||||
@@ -19,7 +19,7 @@
|
|||||||
<mat-label *ngIf="type === 'audio'"><ng-container i18n="Audio files title">Audio files</ng-container></mat-label>
|
<mat-label *ngIf="type === 'audio'"><ng-container i18n="Audio files title">Audio files</ng-container></mat-label>
|
||||||
<mat-label *ngIf="type === 'video'"><ng-container i18n="Videos title">Videos</ng-container></mat-label>
|
<mat-label *ngIf="type === 'video'"><ng-container i18n="Videos title">Videos</ng-container></mat-label>
|
||||||
<mat-select [formControl]="filesSelect" multiple required aria-required>
|
<mat-select [formControl]="filesSelect" multiple required aria-required>
|
||||||
<ng-container *ngIf="filesToSelectFrom"><mat-option *ngFor="let file of filesToSelectFrom" [value]="file.id">{{file.id}}</mat-option></ng-container>
|
<ng-container *ngIf="filesToSelectFrom"><mat-option *ngFor="let file of filesToSelectFrom" [value]="file.uid">{{file.id}}</mat-option></ng-container>
|
||||||
<ng-container *ngIf="audiosToSelectFrom && type === 'audio'"><mat-option *ngFor="let file of audiosToSelectFrom" [value]="file.id">{{file.id}}</mat-option></ng-container>
|
<ng-container *ngIf="audiosToSelectFrom && type === 'audio'"><mat-option *ngFor="let file of audiosToSelectFrom" [value]="file.id">{{file.id}}</mat-option></ng-container>
|
||||||
<ng-container *ngIf="videosToSelectFrom && type === 'video'"><mat-option *ngFor="let file of videosToSelectFrom" [value]="file.id">{{file.id}}</mat-option></ng-container>
|
<ng-container *ngIf="videosToSelectFrom && type === 'video'"><mat-option *ngFor="let file of videosToSelectFrom" [value]="file.id">{{file.id}}</mat-option></ng-container>
|
||||||
</mat-select>
|
</mat-select>
|
||||||
|
|||||||
@@ -33,7 +33,7 @@ export class ShareMediaDialogComponent implements OnInit {
|
|||||||
this.is_playlist = this.data.is_playlist;
|
this.is_playlist = this.data.is_playlist;
|
||||||
this.current_timestamp = (this.data.current_timestamp / 1000).toFixed(2);
|
this.current_timestamp = (this.data.current_timestamp / 1000).toFixed(2);
|
||||||
|
|
||||||
const arg = (this.is_playlist ? ';id=' : ';uid=');
|
const arg = (this.is_playlist ? ';playlist_id=' : ';uid=');
|
||||||
this.default_share_url = window.location.href.split(';')[0] + arg + this.uid;
|
this.default_share_url = window.location.href.split(';')[0] + arg + this.uid;
|
||||||
if (this.uuid) {
|
if (this.uuid) {
|
||||||
this.default_share_url += ';uuid=' + this.uuid;
|
this.default_share_url += ';uuid=' + this.uuid;
|
||||||
|
|||||||
@@ -355,7 +355,7 @@ export class MainComponent implements OnInit {
|
|||||||
if (playlist) {
|
if (playlist) {
|
||||||
if (this.downloadOnlyMode) {
|
if (this.downloadOnlyMode) {
|
||||||
this.downloading_content[type][playlistID] = true;
|
this.downloading_content[type][playlistID] = true;
|
||||||
this.downloadPlaylist(playlist.fileNames, type, playlist.name, playlistID);
|
this.downloadPlaylist(playlist);
|
||||||
} else {
|
} else {
|
||||||
localStorage.setItem('player_navigator', this.router.url);
|
localStorage.setItem('player_navigator', this.router.url);
|
||||||
const fileNames = playlist.fileNames;
|
const fileNames = playlist.fileNames;
|
||||||
@@ -626,41 +626,41 @@ export class MainComponent implements OnInit {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
downloadAudioFile(name) {
|
downloadAudioFile(file) {
|
||||||
this.downloading_content['audio'][name] = true;
|
this.downloading_content['audio'][file.id] = true;
|
||||||
this.postsService.downloadFileFromServer(name, 'audio').subscribe(res => {
|
this.postsService.downloadFileFromServer(file.uid).subscribe(res => {
|
||||||
this.downloading_content['audio'][name] = false;
|
this.downloading_content['audio'][file.id] = false;
|
||||||
const blob: Blob = res;
|
const blob: Blob = res;
|
||||||
saveAs(blob, decodeURIComponent(name) + '.mp3');
|
saveAs(blob, decodeURIComponent(file.id) + '.mp3');
|
||||||
|
|
||||||
if (!this.fileManagerEnabled) {
|
if (!this.fileManagerEnabled) {
|
||||||
// tell server to delete the file once downloaded
|
// tell server to delete the file once downloaded
|
||||||
this.postsService.deleteFile(name, 'video').subscribe(delRes => {
|
this.postsService.deleteFile(file.uid).subscribe(delRes => {
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
downloadVideoFile(name) {
|
downloadVideoFile(file) {
|
||||||
this.downloading_content['video'][name] = true;
|
this.downloading_content['video'][file.id] = true;
|
||||||
this.postsService.downloadFileFromServer(name, 'video').subscribe(res => {
|
this.postsService.downloadFileFromServer(file.uid).subscribe(res => {
|
||||||
this.downloading_content['video'][name] = false;
|
this.downloading_content['video'][file.id] = false;
|
||||||
const blob: Blob = res;
|
const blob: Blob = res;
|
||||||
saveAs(blob, decodeURIComponent(name) + '.mp4');
|
saveAs(blob, decodeURIComponent(file.id) + '.mp4');
|
||||||
|
|
||||||
if (!this.fileManagerEnabled) {
|
if (!this.fileManagerEnabled) {
|
||||||
// tell server to delete the file once downloaded
|
// tell server to delete the file once downloaded
|
||||||
this.postsService.deleteFile(name, 'audio').subscribe(delRes => {
|
this.postsService.deleteFile(file.uid).subscribe(delRes => {
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
downloadPlaylist(fileNames, type, zipName = null, playlistID = null) {
|
downloadPlaylist(playlist) {
|
||||||
this.postsService.downloadFileFromServer(fileNames, type, zipName).subscribe(res => {
|
this.postsService.downloadFileFromServer(playlist.id, null, true).subscribe(res => {
|
||||||
if (playlistID) { this.downloading_content[type][playlistID] = false };
|
if (playlist.id) { this.downloading_content[playlist.type][playlist.id] = false };
|
||||||
const blob: Blob = res;
|
const blob: Blob = res;
|
||||||
saveAs(blob, zipName + '.zip');
|
saveAs(blob, playlist.name + '.zip');
|
||||||
});
|
});
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -29,12 +29,11 @@
|
|||||||
<div class="col-2">
|
<div class="col-2">
|
||||||
<ng-container *ngIf="playlist.length > 1">
|
<ng-container *ngIf="playlist.length > 1">
|
||||||
<button (click)="downloadContent()" [disabled]="downloading" mat-icon-button><mat-icon>save</mat-icon><mat-spinner *ngIf="downloading" class="spinner" [diameter]="35"></mat-spinner></button>
|
<button (click)="downloadContent()" [disabled]="downloading" mat-icon-button><mat-icon>save</mat-icon><mat-spinner *ngIf="downloading" class="spinner" [diameter]="35"></mat-spinner></button>
|
||||||
<button *ngIf="!id" (click)="namePlaylistDialog()" mat-icon-button><mat-icon>favorite</mat-icon></button>
|
<button *ngIf="!postsService.isLoggedIn || postsService.permissions.includes('sharing')" (click)="openShareDialog()" mat-icon-button><mat-icon>share</mat-icon></button>
|
||||||
<button *ngIf="!is_shared && id && (!postsService.isLoggedIn || postsService.permissions.includes('sharing'))" (click)="openShareDialog()" mat-icon-button><mat-icon>share</mat-icon></button>
|
|
||||||
</ng-container>
|
</ng-container>
|
||||||
<ng-container *ngIf="playlist.length === 1">
|
<ng-container *ngIf="playlist.length === 1">
|
||||||
<button (click)="downloadFile()" [disabled]="downloading" mat-icon-button><mat-icon>save</mat-icon><mat-spinner *ngIf="downloading" class="spinner" [diameter]="35"></mat-spinner></button>
|
<button (click)="downloadFile()" [disabled]="downloading" mat-icon-button><mat-icon>save</mat-icon><mat-spinner *ngIf="downloading" class="spinner" [diameter]="35"></mat-spinner></button>
|
||||||
<button *ngIf="!is_shared && uid && uid !== 'false' && type !== 'subscription' && (!postsService.isLoggedIn || postsService.permissions.includes('sharing'))" (click)="openShareDialog()" mat-icon-button><mat-icon>share</mat-icon></button>
|
<button *ngIf="type !== 'subscription' && (!postsService.isLoggedIn || postsService.permissions.includes('sharing'))" (click)="openShareDialog()" mat-icon-button><mat-icon>share</mat-icon></button>
|
||||||
<button (click)="openFileInfoDialog()" *ngIf="db_file" mat-icon-button><mat-icon>info</mat-icon></button>
|
<button (click)="openFileInfoDialog()" *ngIf="db_file" mat-icon-button><mat-icon>info</mat-icon></button>
|
||||||
</ng-container>
|
</ng-container>
|
||||||
<button *ngIf="db_file && db_file.url.includes('twitch.tv/videos/') && postsService['config']['API']['use_twitch_API']" (click)="drawer.toggle()" mat-icon-button><mat-icon>chat</mat-icon></button>
|
<button *ngIf="db_file && db_file.url.includes('twitch.tv/videos/') && postsService['config']['API']['use_twitch_API']" (click)="drawer.toggle()" mat-icon-button><mat-icon>chat</mat-icon></button>
|
||||||
@@ -47,6 +46,9 @@
|
|||||||
<mat-button-toggle cdkDrag *ngFor="let playlist_item of playlist; let i = index" [checked]="currentItem.title === playlist_item.title" (click)="onClickPlaylistItem(playlist_item, i)" class="toggle-button" [value]="playlist_item.title">{{playlist_item.label}}</mat-button-toggle>
|
<mat-button-toggle cdkDrag *ngFor="let playlist_item of playlist; let i = index" [checked]="currentItem.title === playlist_item.title" (click)="onClickPlaylistItem(playlist_item, i)" class="toggle-button" [value]="playlist_item.title">{{playlist_item.label}}</mat-button-toggle>
|
||||||
</mat-button-toggle-group>
|
</mat-button-toggle-group>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
<app-concurrent-stream *ngIf="db_file && api && postsService.config" (setPlaybackRate)="setPlaybackRate($event)" (togglePlayback)="togglePlayback($event)" (setPlaybackTimestamp)="setPlaybackTimestamp($event)" [playing]="api.state === 'playing'" [uid]="uid" [playback_timestamp]="api.time.current/1000" [server_mode]="!postsService.config.Advanced.multi_user_mode || postsService.isLoggedIn"></app-concurrent-stream>
|
||||||
|
|
||||||
<mat-drawer #drawer class="example-sidenav" mode="side" position="end" [opened]="db_file && db_file['chat_exists'] && postsService['config']['API']['use_twitch_API']">
|
<mat-drawer #drawer class="example-sidenav" mode="side" position="end" [opened]="db_file && db_file['chat_exists'] && postsService['config']['API']['use_twitch_API']">
|
||||||
<ng-container *ngIf="api_ready && db_file && db_file.url.includes('twitch.tv/videos/')">
|
<ng-container *ngIf="api_ready && db_file && db_file.url.includes('twitch.tv/videos/')">
|
||||||
<app-twitch-chat #twitchchat [db_file]="db_file" [current_timestamp]="api.currentTime" [sub]="subscription"></app-twitch-chat>
|
<app-twitch-chat #twitchchat [db_file]="db_file" [current_timestamp]="api.currentTime" [sub]="subscription"></app-twitch-chat>
|
||||||
|
|||||||
@@ -36,18 +36,16 @@ export class PlayerComponent implements OnInit, AfterViewInit, OnDestroy {
|
|||||||
api_ready = false;
|
api_ready = false;
|
||||||
|
|
||||||
// params
|
// params
|
||||||
fileNames: string[];
|
uids: string[];
|
||||||
type: string;
|
type: string;
|
||||||
id = null; // used for playlists (not subscription)
|
playlist_id = null; // used for playlists (not subscription)
|
||||||
uid = null; // used for non-subscription files (audio, video, playlist)
|
uid = null; // used for non-subscription files (audio, video, playlist)
|
||||||
subscription = null;
|
subscription = null;
|
||||||
subscriptionName = null;
|
sub_id = null;
|
||||||
subPlaylist = null;
|
subPlaylist = null;
|
||||||
uuid = null; // used for sharing in multi-user mode, uuid is the user that downloaded the video
|
uuid = null; // used for sharing in multi-user mode, uuid is the user that downloaded the video
|
||||||
timestamp = null;
|
timestamp = null;
|
||||||
|
|
||||||
is_shared = false;
|
|
||||||
|
|
||||||
db_playlist = null;
|
db_playlist = null;
|
||||||
db_file = null;
|
db_file = null;
|
||||||
|
|
||||||
@@ -56,8 +54,6 @@ export class PlayerComponent implements OnInit, AfterViewInit, OnDestroy {
|
|||||||
videoFolderPath = null;
|
videoFolderPath = null;
|
||||||
subscriptionFolderPath = null;
|
subscriptionFolderPath = null;
|
||||||
|
|
||||||
sharingEnabled = null;
|
|
||||||
|
|
||||||
// url-mode params
|
// url-mode params
|
||||||
url = null;
|
url = null;
|
||||||
name = null;
|
name = null;
|
||||||
@@ -79,11 +75,9 @@ export class PlayerComponent implements OnInit, AfterViewInit, OnDestroy {
|
|||||||
ngOnInit(): void {
|
ngOnInit(): void {
|
||||||
this.innerWidth = window.innerWidth;
|
this.innerWidth = window.innerWidth;
|
||||||
|
|
||||||
this.type = this.route.snapshot.paramMap.get('type');
|
this.playlist_id = this.route.snapshot.paramMap.get('playlist_id');
|
||||||
this.id = this.route.snapshot.paramMap.get('id');
|
|
||||||
this.uid = this.route.snapshot.paramMap.get('uid');
|
this.uid = this.route.snapshot.paramMap.get('uid');
|
||||||
this.subscriptionName = this.route.snapshot.paramMap.get('subscriptionName');
|
this.sub_id = this.route.snapshot.paramMap.get('sub_id');
|
||||||
this.subPlaylist = this.route.snapshot.paramMap.get('subPlaylist');
|
|
||||||
this.url = this.route.snapshot.paramMap.get('url');
|
this.url = this.route.snapshot.paramMap.get('url');
|
||||||
this.name = this.route.snapshot.paramMap.get('name');
|
this.name = this.route.snapshot.paramMap.get('name');
|
||||||
this.uuid = this.route.snapshot.paramMap.get('uuid');
|
this.uuid = this.route.snapshot.paramMap.get('uuid');
|
||||||
@@ -120,18 +114,13 @@ export class PlayerComponent implements OnInit, AfterViewInit, OnDestroy {
|
|||||||
this.audioFolderPath = this.postsService.config['Downloader']['path-audio'];
|
this.audioFolderPath = this.postsService.config['Downloader']['path-audio'];
|
||||||
this.videoFolderPath = this.postsService.config['Downloader']['path-video'];
|
this.videoFolderPath = this.postsService.config['Downloader']['path-video'];
|
||||||
this.subscriptionFolderPath = this.postsService.config['Subscriptions']['subscriptions_base_path'];
|
this.subscriptionFolderPath = this.postsService.config['Subscriptions']['subscriptions_base_path'];
|
||||||
this.fileNames = this.route.snapshot.paramMap.get('fileNames') ? this.route.snapshot.paramMap.get('fileNames').split('|nvr|') : null;
|
|
||||||
|
|
||||||
if (!this.fileNames && !this.type) {
|
if (this.sub_id) {
|
||||||
this.is_shared = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (this.uid && !this.id) {
|
|
||||||
this.getFile();
|
|
||||||
} else if (this.id) {
|
|
||||||
this.getPlaylistFiles();
|
|
||||||
} else if (this.subscriptionName) {
|
|
||||||
this.getSubscription();
|
this.getSubscription();
|
||||||
|
} else if (this.playlist_id) {
|
||||||
|
this.getPlaylistFiles();
|
||||||
|
} else if (this.uid) {
|
||||||
|
this.getFile();
|
||||||
}
|
}
|
||||||
|
|
||||||
if (this.url) {
|
if (this.url) {
|
||||||
@@ -147,14 +136,10 @@ export class PlayerComponent implements OnInit, AfterViewInit, OnDestroy {
|
|||||||
this.currentItem = this.playlist[0];
|
this.currentItem = this.playlist[0];
|
||||||
this.currentIndex = 0;
|
this.currentIndex = 0;
|
||||||
this.show_player = true;
|
this.show_player = true;
|
||||||
} else if (this.fileNames && !this.subscriptionName) {
|
|
||||||
this.show_player = true;
|
|
||||||
this.parseFileNames();
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
getFile() {
|
getFile() {
|
||||||
const already_has_filenames = !!this.fileNames;
|
|
||||||
this.postsService.getFile(this.uid, null, this.uuid).subscribe(res => {
|
this.postsService.getFile(this.uid, null, this.uuid).subscribe(res => {
|
||||||
this.db_file = res['file'];
|
this.db_file = res['file'];
|
||||||
if (!this.db_file) {
|
if (!this.db_file) {
|
||||||
@@ -165,45 +150,32 @@ export class PlayerComponent implements OnInit, AfterViewInit, OnDestroy {
|
|||||||
console.error('Failed to increment view count');
|
console.error('Failed to increment view count');
|
||||||
console.error(err);
|
console.error(err);
|
||||||
});
|
});
|
||||||
this.sharingEnabled = this.db_file.sharingEnabled;
|
// regular video/audio file (not playlist)
|
||||||
if (!this.fileNames) {
|
this.uids = [this.db_file['uid']];
|
||||||
// means it's a shared video
|
this.type = this.db_file['isAudio'] ? 'audio' : 'video';
|
||||||
if (!this.id) {
|
this.parseFileNames();
|
||||||
// regular video/audio file (not playlist)
|
|
||||||
this.fileNames = [this.db_file['id']];
|
|
||||||
this.type = this.db_file['isAudio'] ? 'audio' : 'video';
|
|
||||||
if (!already_has_filenames) { this.parseFileNames(); }
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (this.db_file['sharingEnabled'] || !this.uuid) {
|
|
||||||
this.show_player = true;
|
|
||||||
} else if (!already_has_filenames) {
|
|
||||||
this.openSnackBar('Error: Sharing has been disabled for this video!', 'Dismiss');
|
|
||||||
}
|
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
getSubscription() {
|
getSubscription() {
|
||||||
this.postsService.getSubscription(null, this.subscriptionName).subscribe(res => {
|
this.postsService.getSubscription(this.sub_id).subscribe(res => {
|
||||||
const subscription = res['subscription'];
|
const subscription = res['subscription'];
|
||||||
this.subscription = subscription;
|
this.subscription = subscription;
|
||||||
if (this.fileNames) {
|
this.type === this.subscription.type;
|
||||||
subscription.videos.forEach(video => {
|
subscription.videos.forEach(video => {
|
||||||
if (video['id'] === this.fileNames[0]) {
|
if (video['uid'] === this.uid) {
|
||||||
this.db_file = video;
|
this.db_file = video;
|
||||||
this.postsService.incrementViewCount(this.db_file['uid'], this.subscription['id'], this.uuid).subscribe(res => {}, err => {
|
this.postsService.incrementViewCount(this.db_file['uid'], this.sub_id, this.uuid).subscribe(res => {}, err => {
|
||||||
console.error('Failed to increment view count');
|
console.error('Failed to increment view count');
|
||||||
console.error(err);
|
console.error(err);
|
||||||
});
|
});
|
||||||
this.show_player = true;
|
this.uids = this.db_file['uid'];
|
||||||
this.parseFileNames();
|
this.show_player = true;
|
||||||
}
|
this.parseFileNames();
|
||||||
});
|
}
|
||||||
} else {
|
});
|
||||||
console.log('no file name specified');
|
|
||||||
}
|
|
||||||
}, err => {
|
}, err => {
|
||||||
this.openSnackBar(`Failed to find subscription ${this.subscriptionName}`, 'Dismiss');
|
this.openSnackBar(`Failed to find subscription ${this.sub_id}`, 'Dismiss');
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -212,10 +184,10 @@ export class PlayerComponent implements OnInit, AfterViewInit, OnDestroy {
|
|||||||
this.show_player = true;
|
this.show_player = true;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
this.postsService.getPlaylist(this.id, null, this.uuid).subscribe(res => {
|
this.postsService.getPlaylist(this.playlist_id, this.uuid, true).subscribe(res => {
|
||||||
if (res['playlist']) {
|
if (res['playlist']) {
|
||||||
this.db_playlist = res['playlist'];
|
this.db_playlist = res['playlist'];
|
||||||
this.fileNames = this.db_playlist['fileNames'];
|
this.uids = this.db_playlist.uids;
|
||||||
this.type = res['type'];
|
this.type = res['type'];
|
||||||
this.show_player = true;
|
this.show_player = true;
|
||||||
this.parseFileNames();
|
this.parseFileNames();
|
||||||
@@ -231,60 +203,43 @@ export class PlayerComponent implements OnInit, AfterViewInit, OnDestroy {
|
|||||||
let fileType = null;
|
let fileType = null;
|
||||||
if (this.type === 'audio') {
|
if (this.type === 'audio') {
|
||||||
fileType = 'audio/mp3';
|
fileType = 'audio/mp3';
|
||||||
} else if (this.type === 'video') {
|
|
||||||
fileType = 'video/mp4';
|
|
||||||
} else {
|
} else {
|
||||||
// error
|
fileType = 'video/mp4';
|
||||||
console.error('Must have valid file type! Use \'audio\', \'video\', or \'subscription\'.');
|
|
||||||
}
|
}
|
||||||
this.playlist = [];
|
this.playlist = [];
|
||||||
for (let i = 0; i < this.fileNames.length; i++) {
|
for (let i = 0; i < this.uids.length; i++) {
|
||||||
const fileName = this.fileNames[i];
|
const uid = this.uids[i];
|
||||||
let baseLocation = null;
|
|
||||||
let fullLocation = null;
|
|
||||||
|
|
||||||
// adds user token if in multi-user-mode
|
const file_obj = this.playlist_id ? this.db_playlist['file_objs'][i] : this.db_file;
|
||||||
const uuid_str = this.uuid ? `&uuid=${this.uuid}` : '';
|
|
||||||
const uid_str = (this.id || !this.db_file) ? '' : `&uid=${this.db_file.uid}`;
|
|
||||||
const type_str = (this.type || !this.db_file) ? `&type=${this.type}` : `&type=${this.db_file.type}`
|
|
||||||
const id_str = this.id ? `&id=${this.id}` : '';
|
|
||||||
const file_path_str = (!this.db_file) ? '' : `&file_path=${encodeURIComponent(this.db_file.path)}`;
|
|
||||||
|
|
||||||
if (!this.subscriptionName) {
|
let baseLocation = 'stream/';
|
||||||
baseLocation = 'stream/';
|
let fullLocation = this.baseStreamPath + baseLocation + `?test=test&uid=${file_obj['uid']}`;
|
||||||
fullLocation = this.baseStreamPath + baseLocation + encodeURIComponent(fileName) + `?test=test${type_str}${file_path_str}`;
|
|
||||||
} else {
|
|
||||||
// default to video but include subscription name param
|
|
||||||
baseLocation = 'stream/';
|
|
||||||
fullLocation = this.baseStreamPath + baseLocation + encodeURIComponent(fileName) + '?subName=' + this.subscriptionName +
|
|
||||||
'&subPlaylist=' + this.subPlaylist + `${file_path_str}${type_str}`;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (this.postsService.isLoggedIn) {
|
if (this.postsService.isLoggedIn) {
|
||||||
fullLocation += (this.subscriptionName ? '&' : '&') + `jwt=${this.postsService.token}`;
|
fullLocation += `&jwt=${this.postsService.token}`;
|
||||||
if (this.is_shared) { fullLocation += `${uuid_str}${uid_str}${type_str}${id_str}`; }
|
|
||||||
} else if (this.is_shared) {
|
|
||||||
fullLocation += (this.subscriptionName ? '&' : '?') + `test=test${uuid_str}${uid_str}${type_str}${id_str}`;
|
|
||||||
}
|
}
|
||||||
// if it has a slash (meaning it's in a directory), only get the file name for the label
|
|
||||||
let label = null;
|
if (this.uuid) {
|
||||||
const decodedName = decodeURIComponent(fileName);
|
fullLocation += `&uuid=${this.uuid}`;
|
||||||
const hasSlash = decodedName.includes('/') || decodedName.includes('\\');
|
|
||||||
if (hasSlash) {
|
|
||||||
label = decodedName.replace(/^.*[\\\/]/, '');
|
|
||||||
} else {
|
|
||||||
label = decodedName;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (this.sub_id) {
|
||||||
|
fullLocation += `&sub_id=${this.sub_id}`;
|
||||||
|
} else if (this.playlist_id) {
|
||||||
|
fullLocation += `&playlist_id=${this.playlist_id}`;
|
||||||
|
}
|
||||||
|
|
||||||
const mediaObject: IMedia = {
|
const mediaObject: IMedia = {
|
||||||
title: fileName,
|
title: file_obj['title'],
|
||||||
src: fullLocation,
|
src: fullLocation,
|
||||||
type: fileType,
|
type: fileType,
|
||||||
label: label
|
label: file_obj['title']
|
||||||
}
|
}
|
||||||
this.playlist.push(mediaObject);
|
this.playlist.push(mediaObject);
|
||||||
}
|
}
|
||||||
this.currentItem = this.playlist[this.currentIndex];
|
this.currentItem = this.playlist[this.currentIndex];
|
||||||
this.original_playlist = JSON.stringify(this.playlist);
|
this.original_playlist = JSON.stringify(this.playlist);
|
||||||
|
this.show_player = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
onPlayerReady(api: VgApiService) {
|
onPlayerReady(api: VgApiService) {
|
||||||
@@ -361,8 +316,7 @@ export class PlayerComponent implements OnInit, AfterViewInit, OnDestroy {
|
|||||||
|
|
||||||
const zipName = fileNames[0].split(' ')[0] + fileNames[1].split(' ')[0];
|
const zipName = fileNames[0].split(' ')[0] + fileNames[1].split(' ')[0];
|
||||||
this.downloading = true;
|
this.downloading = true;
|
||||||
this.postsService.downloadFileFromServer(fileNames, this.type, zipName, null, null, null, null,
|
this.postsService.downloadFileFromServer(this.playlist_id, this.uuid, true).subscribe(res => {
|
||||||
!this.uuid ? this.postsService.user.uid : this.uuid, this.id).subscribe(res => {
|
|
||||||
this.downloading = false;
|
this.downloading = false;
|
||||||
const blob: Blob = res;
|
const blob: Blob = res;
|
||||||
saveAs(blob, zipName + '.zip');
|
saveAs(blob, zipName + '.zip');
|
||||||
@@ -376,8 +330,7 @@ export class PlayerComponent implements OnInit, AfterViewInit, OnDestroy {
|
|||||||
const ext = (this.type === 'audio') ? '.mp3' : '.mp4';
|
const ext = (this.type === 'audio') ? '.mp3' : '.mp4';
|
||||||
const filename = this.playlist[0].title;
|
const filename = this.playlist[0].title;
|
||||||
this.downloading = true;
|
this.downloading = true;
|
||||||
this.postsService.downloadFileFromServer(filename, this.type, null, null, this.subscriptionName, this.subPlaylist,
|
this.postsService.downloadFileFromServer(this.uid, this.uuid, false).subscribe(res => {
|
||||||
this.is_shared ? this.db_file['uid'] : null, this.uuid).subscribe(res => {
|
|
||||||
this.downloading = false;
|
this.downloading = false;
|
||||||
const blob: Blob = res;
|
const blob: Blob = res;
|
||||||
saveAs(blob, filename + ext);
|
saveAs(blob, filename + ext);
|
||||||
@@ -387,50 +340,10 @@ export class PlayerComponent implements OnInit, AfterViewInit, OnDestroy {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
namePlaylistDialog() {
|
|
||||||
const done = new EventEmitter<any>();
|
|
||||||
const dialogRef = this.dialog.open(InputDialogComponent, {
|
|
||||||
width: '300px',
|
|
||||||
data: {
|
|
||||||
inputTitle: 'Name the playlist',
|
|
||||||
inputPlaceholder: 'Name',
|
|
||||||
submitText: 'Favorite',
|
|
||||||
doneEmitter: done
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
done.subscribe(name => {
|
|
||||||
|
|
||||||
// Eventually do additional checks on name
|
|
||||||
if (name) {
|
|
||||||
const fileNames = this.getFileNames();
|
|
||||||
this.postsService.createPlaylist(name, fileNames, this.type, null).subscribe(res => {
|
|
||||||
if (res['success']) {
|
|
||||||
dialogRef.close();
|
|
||||||
const new_playlist = res['new_playlist'];
|
|
||||||
this.db_playlist = new_playlist;
|
|
||||||
this.openSnackBar('Playlist \'' + name + '\' successfully created!', '')
|
|
||||||
this.playlistPostCreationHandler(new_playlist.id);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
createPlaylist(name) {
|
|
||||||
this.postsService.createPlaylist(name, this.fileNames, this.type, null).subscribe(res => {
|
|
||||||
if (res['success']) {
|
|
||||||
console.log('Success!');
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
*/
|
|
||||||
|
|
||||||
playlistPostCreationHandler(playlistID) {
|
playlistPostCreationHandler(playlistID) {
|
||||||
// changes the route without moving from the current view or
|
// changes the route without moving from the current view or
|
||||||
// triggering a navigation event
|
// triggering a navigation event
|
||||||
this.id = playlistID;
|
this.playlist_id = playlistID;
|
||||||
this.router.navigateByUrl(this.router.url + ';id=' + playlistID);
|
this.router.navigateByUrl(this.router.url + ';id=' + playlistID);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -445,11 +358,11 @@ export class PlayerComponent implements OnInit, AfterViewInit, OnDestroy {
|
|||||||
updatePlaylist() {
|
updatePlaylist() {
|
||||||
const fileNames = this.getFileNames();
|
const fileNames = this.getFileNames();
|
||||||
this.playlist_updating = true;
|
this.playlist_updating = true;
|
||||||
this.postsService.updatePlaylistFiles(this.id, fileNames, this.type).subscribe(res => {
|
this.postsService.updatePlaylistFiles(this.playlist_id, fileNames, this.type).subscribe(res => {
|
||||||
this.playlist_updating = false;
|
this.playlist_updating = false;
|
||||||
if (res['success']) {
|
if (res['success']) {
|
||||||
const fileNamesEncoded = fileNames.join('|nvr|');
|
const fileNamesEncoded = fileNames.join('|nvr|');
|
||||||
this.router.navigate(['/player', {fileNames: fileNamesEncoded, type: this.type, id: this.id}]);
|
this.router.navigate(['/player', {fileNames: fileNamesEncoded, type: this.type, id: this.playlist_id}]);
|
||||||
this.openSnackBar('Successfully updated playlist.', '');
|
this.openSnackBar('Successfully updated playlist.', '');
|
||||||
this.original_playlist = JSON.stringify(this.playlist);
|
this.original_playlist = JSON.stringify(this.playlist);
|
||||||
} else {
|
} else {
|
||||||
@@ -461,10 +374,10 @@ export class PlayerComponent implements OnInit, AfterViewInit, OnDestroy {
|
|||||||
openShareDialog() {
|
openShareDialog() {
|
||||||
const dialogRef = this.dialog.open(ShareMediaDialogComponent, {
|
const dialogRef = this.dialog.open(ShareMediaDialogComponent, {
|
||||||
data: {
|
data: {
|
||||||
uid: this.id ? this.id : this.uid,
|
uid: this.playlist_id ? this.playlist_id : this.uid,
|
||||||
type: this.type,
|
type: this.type,
|
||||||
sharing_enabled: this.id ? this.db_playlist.sharingEnabled : this.db_file.sharingEnabled,
|
sharing_enabled: this.playlist_id ? this.db_playlist.sharingEnabled : this.db_file.sharingEnabled,
|
||||||
is_playlist: !!this.id,
|
is_playlist: !!this.playlist_id,
|
||||||
uuid: this.postsService.isLoggedIn ? this.postsService.user.uid : null,
|
uuid: this.postsService.isLoggedIn ? this.postsService.user.uid : null,
|
||||||
current_timestamp: this.api.time.current
|
current_timestamp: this.api.time.current
|
||||||
},
|
},
|
||||||
@@ -472,7 +385,7 @@ export class PlayerComponent implements OnInit, AfterViewInit, OnDestroy {
|
|||||||
});
|
});
|
||||||
|
|
||||||
dialogRef.afterClosed().subscribe(res => {
|
dialogRef.afterClosed().subscribe(res => {
|
||||||
if (!this.id) {
|
if (!this.playlist_id) {
|
||||||
this.getFile();
|
this.getFile();
|
||||||
} else {
|
} else {
|
||||||
this.getPlaylistFiles();
|
this.getPlaylistFiles();
|
||||||
@@ -489,6 +402,22 @@ export class PlayerComponent implements OnInit, AfterViewInit, OnDestroy {
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
setPlaybackTimestamp(time) {
|
||||||
|
this.api.seekTime(time);
|
||||||
|
}
|
||||||
|
|
||||||
|
togglePlayback(to_play) {
|
||||||
|
if (to_play) {
|
||||||
|
this.api.play();
|
||||||
|
} else {
|
||||||
|
this.api.pause();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
setPlaybackRate(speed) {
|
||||||
|
this.api.playbackRate = speed;
|
||||||
|
}
|
||||||
|
|
||||||
// snackbar helper
|
// snackbar helper
|
||||||
public openSnackBar(message: string, action: string) {
|
public openSnackBar(message: string, action: string) {
|
||||||
this.snackBar.open(message, action, {
|
this.snackBar.open(message, action, {
|
||||||
|
|||||||
@@ -219,8 +219,8 @@ export class PostsService implements CanActivate {
|
|||||||
return this.http.post(this.path + 'setConfig', {new_config_file: config}, this.httpOptions);
|
return this.http.post(this.path + 'setConfig', {new_config_file: config}, this.httpOptions);
|
||||||
}
|
}
|
||||||
|
|
||||||
deleteFile(uid: string, type: string, blacklistMode = false) {
|
deleteFile(uid: string, blacklistMode = false) {
|
||||||
return this.http.post(this.path + 'deleteFile', {uid: uid, type: type, blacklistMode: blacklistMode}, this.httpOptions);
|
return this.http.post(this.path + 'deleteFile', {uid: uid, blacklistMode: blacklistMode}, this.httpOptions);
|
||||||
}
|
}
|
||||||
|
|
||||||
getMp3s() {
|
getMp3s() {
|
||||||
@@ -247,22 +247,30 @@ export class PostsService implements CanActivate {
|
|||||||
return this.http.post(this.path + 'downloadTwitchChatByVODID', {id: id, type: type, vodId: vodId, uuid: uuid, sub: sub}, this.httpOptions);
|
return this.http.post(this.path + 'downloadTwitchChatByVODID', {id: id, type: type, vodId: vodId, uuid: uuid, sub: sub}, this.httpOptions);
|
||||||
}
|
}
|
||||||
|
|
||||||
downloadFileFromServer(fileName, type, outputName = null, fullPathProvided = null, subscriptionName = null, subPlaylist = null,
|
downloadFileFromServer(uid, uuid = null, is_playlist = false) {
|
||||||
uid = null, uuid = null, id = null) {
|
return this.http.post(this.path + 'downloadFile', {
|
||||||
return this.http.post(this.path + 'downloadFile', {fileNames: fileName,
|
|
||||||
type: type,
|
|
||||||
zip_mode: Array.isArray(fileName),
|
|
||||||
outputName: outputName,
|
|
||||||
fullPathProvided: fullPathProvided,
|
|
||||||
subscriptionName: subscriptionName,
|
|
||||||
subPlaylist: subPlaylist,
|
|
||||||
uuid: uuid,
|
|
||||||
uid: uid,
|
uid: uid,
|
||||||
id: id
|
uuid: uuid,
|
||||||
|
is_playlist: is_playlist
|
||||||
},
|
},
|
||||||
{responseType: 'blob', params: this.httpOptions.params});
|
{responseType: 'blob', params: this.httpOptions.params});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
downloadPlaylistFromServer(playlist_id, uuid = null) {
|
||||||
|
return this.http.post(this.path + 'downloadPlaylist', {playlist_id: playlist_id, uuid: uuid});
|
||||||
|
}
|
||||||
|
|
||||||
|
checkConcurrentStream(uid) {
|
||||||
|
return this.http.post(this.path + 'checkConcurrentStream', {uid: uid}, this.httpOptions);
|
||||||
|
}
|
||||||
|
|
||||||
|
updateConcurrentStream(uid, playback_timestamp, unix_timestamp, playing) {
|
||||||
|
return this.http.post(this.path + 'updateConcurrentStream', {uid: uid,
|
||||||
|
playback_timestamp: playback_timestamp,
|
||||||
|
unix_timestamp: unix_timestamp,
|
||||||
|
playing: playing}, this.httpOptions);
|
||||||
|
}
|
||||||
|
|
||||||
uploadCookiesFile(fileFormData) {
|
uploadCookiesFile(fileFormData) {
|
||||||
return this.http.post(this.path + 'uploadCookies', fileFormData, this.httpOptions);
|
return this.http.post(this.path + 'uploadCookies', fileFormData, this.httpOptions);
|
||||||
}
|
}
|
||||||
@@ -299,17 +307,18 @@ export class PostsService implements CanActivate {
|
|||||||
return this.http.post(this.path + 'disableSharing', {uid: uid, type: type, is_playlist: is_playlist}, this.httpOptions);
|
return this.http.post(this.path + 'disableSharing', {uid: uid, type: type, is_playlist: is_playlist}, this.httpOptions);
|
||||||
}
|
}
|
||||||
|
|
||||||
createPlaylist(playlistName, fileNames, type, thumbnailURL, duration = null) {
|
createPlaylist(playlistName, uids, type, thumbnailURL, duration = null) {
|
||||||
return this.http.post(this.path + 'createPlaylist', {playlistName: playlistName,
|
return this.http.post(this.path + 'createPlaylist', {playlistName: playlistName,
|
||||||
fileNames: fileNames,
|
uids: uids,
|
||||||
type: type,
|
type: type,
|
||||||
thumbnailURL: thumbnailURL,
|
thumbnailURL: thumbnailURL,
|
||||||
duration: duration}, this.httpOptions);
|
duration: duration}, this.httpOptions);
|
||||||
}
|
}
|
||||||
|
|
||||||
getPlaylist(playlistID, type, uuid = null) {
|
getPlaylist(playlist_id, uuid = null, include_file_metadata = false) {
|
||||||
return this.http.post(this.path + 'getPlaylist', {playlistID: playlistID,
|
return this.http.post(this.path + 'getPlaylist', {playlist_id: playlist_id,
|
||||||
type: type, uuid: uuid}, this.httpOptions);
|
uuid: uuid,
|
||||||
|
include_file_metadata: include_file_metadata}, this.httpOptions);
|
||||||
}
|
}
|
||||||
|
|
||||||
updatePlaylist(playlist) {
|
updatePlaylist(playlist) {
|
||||||
|
|||||||
@@ -42,7 +42,7 @@ export class SubscriptionFileCardComponent implements OnInit {
|
|||||||
|
|
||||||
goToFile() {
|
goToFile() {
|
||||||
const emit_obj = {
|
const emit_obj = {
|
||||||
name: this.file.id,
|
uid: this.file.uid,
|
||||||
url: this.file.requested_formats ? this.file.requested_formats[0].url : this.file.url
|
url: this.file.requested_formats ? this.file.requested_formats[0].url : this.file.url
|
||||||
}
|
}
|
||||||
this.goToFileEmit.emit(emit_obj);
|
this.goToFileEmit.emit(emit_obj);
|
||||||
|
|||||||
@@ -103,15 +103,14 @@ export class SubscriptionComponent implements OnInit, OnDestroy {
|
|||||||
}
|
}
|
||||||
|
|
||||||
goToFile(emit_obj) {
|
goToFile(emit_obj) {
|
||||||
const name = emit_obj['name'];
|
const uid = emit_obj['uid'];
|
||||||
const url = emit_obj['url'];
|
const url = emit_obj['url'];
|
||||||
localStorage.setItem('player_navigator', this.router.url);
|
localStorage.setItem('player_navigator', this.router.url);
|
||||||
if (this.subscription.streamingOnly) {
|
if (this.subscription.streamingOnly) {
|
||||||
this.router.navigate(['/player', {name: name, url: url}]);
|
this.router.navigate(['/player', {uid: uid, url: url}]);
|
||||||
} else {
|
} else {
|
||||||
this.router.navigate(['/player', {fileNames: name,
|
this.router.navigate(['/player', {uid: uid,
|
||||||
type: this.subscription.type ? this.subscription.type : 'video', subscriptionName: this.subscription.name,
|
sub_id: this.subscription.id}]);
|
||||||
subPlaylist: this.subscription.isPlaylist}]);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -154,14 +153,15 @@ export class SubscriptionComponent implements OnInit, OnDestroy {
|
|||||||
}
|
}
|
||||||
|
|
||||||
this.downloading = true;
|
this.downloading = true;
|
||||||
this.postsService.downloadFileFromServer(fileNames, 'video', this.subscription.name, true).subscribe(res => {
|
// TODO: add download subscription route
|
||||||
|
/*this.postsService.downloadFileFromServer(fileNames, 'video', this.subscription.name, true).subscribe(res => {
|
||||||
this.downloading = false;
|
this.downloading = false;
|
||||||
const blob: Blob = res;
|
const blob: Blob = res;
|
||||||
saveAs(blob, this.subscription.name + '.zip');
|
saveAs(blob, this.subscription.name + '.zip');
|
||||||
}, err => {
|
}, err => {
|
||||||
console.log(err);
|
console.log(err);
|
||||||
this.downloading = false;
|
this.downloading = false;
|
||||||
});
|
});*/
|
||||||
}
|
}
|
||||||
|
|
||||||
editSubscription() {
|
editSubscription() {
|
||||||
|
|||||||
Reference in New Issue
Block a user