mirror of
https://github.com/Tzahi12345/YoutubeDL-Material.git
synced 2026-03-17 02:00:56 +03:00
Added description to player component and simplified the database by un-splitting videos and playlists by type
This commit is contained in:
150
backend/app.js
150
backend/app.js
@@ -13,7 +13,7 @@ var express = require("express");
|
||||
var bodyParser = require("body-parser");
|
||||
var archiver = require('archiver');
|
||||
var unzipper = require('unzipper');
|
||||
var db_api = require('./db')
|
||||
var db_api = require('./db');
|
||||
var utils = require('./utils')
|
||||
var mergeFiles = require('merge-files');
|
||||
const low = require('lowdb')
|
||||
@@ -87,14 +87,8 @@ categories_api.initialize(db, users_db, logger, db_api);
|
||||
// Set some defaults
|
||||
db.defaults(
|
||||
{
|
||||
playlists: {
|
||||
audio: [],
|
||||
video: []
|
||||
},
|
||||
files: {
|
||||
audio: [],
|
||||
video: []
|
||||
},
|
||||
playlists: [],
|
||||
files: [],
|
||||
configWriteFlag: false,
|
||||
downloads: {},
|
||||
subscriptions: [],
|
||||
@@ -218,10 +212,12 @@ async function checkMigrations() {
|
||||
|
||||
// 4.1->4.2 migration
|
||||
|
||||
const add_description_migration_complete = false; // db.get('add_description_migration_complete').value();
|
||||
const add_description_migration_complete = db.get('add_description_migration_complete').value();
|
||||
if (!add_description_migration_complete) {
|
||||
logger.info('Beginning migration: 4.1->4.2+')
|
||||
const success = await addMetadataPropertyToDB('description');
|
||||
let success = await simplifyDBFileStructure();
|
||||
success = success && await addMetadataPropertyToDB('view_count');
|
||||
success = success && await addMetadataPropertyToDB('description');
|
||||
if (success) { logger.info('4.1->4.2+ migration complete!'); }
|
||||
else { logger.error('Migration failed: 4.1->4.2+'); }
|
||||
}
|
||||
@@ -229,6 +225,7 @@ async function checkMigrations() {
|
||||
return true;
|
||||
}
|
||||
|
||||
/*
|
||||
async function runFilesToDBMigration() {
|
||||
try {
|
||||
let mp3s = await getMp3s();
|
||||
@@ -260,6 +257,37 @@ async function runFilesToDBMigration() {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
*/
|
||||
|
||||
async function simplifyDBFileStructure() {
|
||||
let users = users_db.get('users').value();
|
||||
for (let i = 0; i < users.length; i++) {
|
||||
const user = users[i];
|
||||
if (user['files']['video'] !== undefined && user['files']['audio'] !== undefined) {
|
||||
const user_files = user['files']['video'].concat(user['files']['audio']);
|
||||
const user_db_path = users_db.get('users').find({uid: user['uid']});
|
||||
user_db_path.assign({files: user_files}).write();
|
||||
}
|
||||
if (user['playlists']['video'] !== undefined && user['playlists']['audio'] !== undefined) {
|
||||
const user_playlists = user['playlists']['video'].concat(user['playlists']['audio']);
|
||||
const user_db_path = users_db.get('users').find({uid: user['uid']});
|
||||
user_db_path.assign({playlists: user_playlists}).write();
|
||||
}
|
||||
}
|
||||
|
||||
if (db.get('files.video').value() !== undefined && db.get('files.audio').value() !== undefined) {
|
||||
const files = db.get('files.video').value().concat(db.get('files.audio'));
|
||||
db.assign({files: files}).write();
|
||||
}
|
||||
|
||||
if (db.get('playlists.video').value() !== undefined && db.get('playlists.audio').value() !== undefined) {
|
||||
const playlists = db.get('playlists.video').value().concat(db.get('playlists.audio'));
|
||||
db.assign({playlists: playlists}).write();
|
||||
}
|
||||
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
async function addMetadataPropertyToDB(property_key) {
|
||||
try {
|
||||
@@ -592,6 +620,9 @@ async function loadConfig() {
|
||||
// creates archive path if missing
|
||||
await fs.ensureDir(archivePath);
|
||||
|
||||
// check migrations
|
||||
await checkMigrations();
|
||||
|
||||
// now this is done here due to youtube-dl's repo takedown
|
||||
await startYoutubeDL();
|
||||
|
||||
@@ -606,9 +637,6 @@ async function loadConfig() {
|
||||
|
||||
db_api.importUnregisteredFiles();
|
||||
|
||||
// check migrations
|
||||
await checkMigrations();
|
||||
|
||||
// load in previous downloads
|
||||
downloads = db.get('downloads').value();
|
||||
|
||||
@@ -1994,7 +2022,7 @@ async function addThumbnails(files) {
|
||||
|
||||
// gets all download mp3s
|
||||
app.get('/api/getMp3s', optionalJwt, async function(req, res) {
|
||||
var mp3s = db.get('files.audio').value(); // getMp3s();
|
||||
var mp3s = db.get('files').chain().find({isAudio: true}).value(); // getMp3s();
|
||||
var playlists = db.get('playlists.audio').value();
|
||||
const is_authenticated = req.isAuthenticated();
|
||||
if (is_authenticated) {
|
||||
@@ -2020,8 +2048,8 @@ app.get('/api/getMp3s', optionalJwt, async function(req, res) {
|
||||
|
||||
// gets all download mp4s
|
||||
app.get('/api/getMp4s', optionalJwt, async function(req, res) {
|
||||
var mp4s = db.get('files.video').value(); // getMp4s();
|
||||
var playlists = db.get('playlists.video').value();
|
||||
var mp4s = db.get('files').chain().find({isAudio: false}).value(); // getMp4s();
|
||||
var playlists = db.get('playlists').value();
|
||||
|
||||
const is_authenticated = req.isAuthenticated();
|
||||
if (is_authenticated) {
|
||||
@@ -2052,21 +2080,11 @@ app.post('/api/getFile', optionalJwt, function (req, res) {
|
||||
var file = null;
|
||||
|
||||
if (req.isAuthenticated()) {
|
||||
file = auth_api.getUserVideo(req.user.uid, uid, type);
|
||||
file = auth_api.getUserVideo(req.user.uid, uid);
|
||||
} else if (uuid) {
|
||||
file = auth_api.getUserVideo(uuid, uid, type, true);
|
||||
file = auth_api.getUserVideo(uuid, uid, true);
|
||||
} else {
|
||||
if (!type) {
|
||||
file = db.get('files.audio').find({uid: uid}).value();
|
||||
if (!file) {
|
||||
file = db.get('files.video').find({uid: uid}).value();
|
||||
if (file) type = 'video';
|
||||
} else {
|
||||
type = 'audio';
|
||||
}
|
||||
}
|
||||
|
||||
if (!file && type) file = db.get(`files.${type}`).find({uid: uid}).value();
|
||||
file = db.get('files').find({uid: uid}).value();
|
||||
}
|
||||
|
||||
// check if chat exists for twitch videos
|
||||
@@ -2086,32 +2104,20 @@ app.post('/api/getFile', optionalJwt, function (req, res) {
|
||||
|
||||
app.post('/api/getAllFiles', optionalJwt, async function (req, res) {
|
||||
// these are returned
|
||||
let files = [];
|
||||
let playlists = [];
|
||||
let subscription_files = [];
|
||||
let files = null;
|
||||
let playlists = null;
|
||||
|
||||
let videos = null;
|
||||
let audios = null;
|
||||
let audio_playlists = null;
|
||||
let video_playlists = null;
|
||||
let subscriptions = config_api.getConfigItem('ytdl_allow_subscriptions') ? (subscriptions_api.getAllSubscriptions(req.isAuthenticated() ? req.user.uid : null)) : [];
|
||||
|
||||
// get basic info depending on multi-user mode being enabled
|
||||
if (req.isAuthenticated()) {
|
||||
videos = auth_api.getUserVideos(req.user.uid, 'video');
|
||||
audios = auth_api.getUserVideos(req.user.uid, 'audio');
|
||||
audio_playlists = auth_api.getUserPlaylists(req.user.uid, 'audio');
|
||||
video_playlists = auth_api.getUserPlaylists(req.user.uid, 'video');
|
||||
files = auth_api.getUserVideos(req.user.uid);
|
||||
playlists = auth_api.getUserPlaylists(req.user.uid);
|
||||
} else {
|
||||
videos = db.get('files.audio').value();
|
||||
audios = db.get('files.video').value();
|
||||
audio_playlists = db.get('playlists.audio').value();
|
||||
video_playlists = db.get('playlists.video').value();
|
||||
files = db.get('files').value();
|
||||
playlists = db.get('playlists').value();
|
||||
}
|
||||
|
||||
files = videos.concat(audios);
|
||||
playlists = video_playlists.concat(audio_playlists);
|
||||
|
||||
// loop through subscriptions and add videos
|
||||
for (let i = 0; i < subscriptions.length; i++) {
|
||||
sub = subscriptions[i];
|
||||
@@ -2187,14 +2193,13 @@ app.post('/api/downloadTwitchChatByVODID', optionalJwt, async (req, res) => {
|
||||
|
||||
// video sharing
|
||||
app.post('/api/enableSharing', optionalJwt, function(req, res) {
|
||||
var type = req.body.type;
|
||||
var uid = req.body.uid;
|
||||
var is_playlist = req.body.is_playlist;
|
||||
let success = false;
|
||||
// multi-user mode
|
||||
if (req.isAuthenticated()) {
|
||||
// if multi user mode, use this method instead
|
||||
success = auth_api.changeSharingMode(req.user.uid, uid, type, is_playlist, true);
|
||||
success = auth_api.changeSharingMode(req.user.uid, uid, is_playlist, true);
|
||||
res.send({success: success});
|
||||
return;
|
||||
}
|
||||
@@ -2203,12 +2208,12 @@ app.post('/api/enableSharing', optionalJwt, function(req, res) {
|
||||
try {
|
||||
success = true;
|
||||
if (!is_playlist && type !== 'subscription') {
|
||||
db.get(`files.${type}`)
|
||||
db.get(`files`)
|
||||
.find({uid: uid})
|
||||
.assign({sharingEnabled: true})
|
||||
.write();
|
||||
} else if (is_playlist) {
|
||||
db.get(`playlists.${type}`)
|
||||
db.get(`playlists`)
|
||||
.find({id: uid})
|
||||
.assign({sharingEnabled: true})
|
||||
.write();
|
||||
@@ -2237,7 +2242,7 @@ app.post('/api/disableSharing', optionalJwt, function(req, res) {
|
||||
// multi-user mode
|
||||
if (req.isAuthenticated()) {
|
||||
// if multi user mode, use this method instead
|
||||
success = auth_api.changeSharingMode(req.user.uid, uid, type, is_playlist, false);
|
||||
success = auth_api.changeSharingMode(req.user.uid, uid, is_playlist, false);
|
||||
res.send({success: success});
|
||||
return;
|
||||
}
|
||||
@@ -2246,12 +2251,12 @@ app.post('/api/disableSharing', optionalJwt, function(req, res) {
|
||||
try {
|
||||
success = true;
|
||||
if (!is_playlist && type !== 'subscription') {
|
||||
db.get(`files.${type}`)
|
||||
db.get(`files`)
|
||||
.find({uid: uid})
|
||||
.assign({sharingEnabled: false})
|
||||
.write();
|
||||
} else if (is_playlist) {
|
||||
db.get(`playlists.${type}`)
|
||||
db.get(`playlists`)
|
||||
.find({id: uid})
|
||||
.assign({sharingEnabled: false})
|
||||
.write();
|
||||
@@ -2544,7 +2549,7 @@ app.post('/api/createPlaylist', optionalJwt, async (req, res) => {
|
||||
if (req.isAuthenticated()) {
|
||||
auth_api.addPlaylist(req.user.uid, new_playlist, type);
|
||||
} else {
|
||||
db.get(`playlists.${type}`)
|
||||
db.get(`playlists`)
|
||||
.push(new_playlist)
|
||||
.write();
|
||||
}
|
||||
@@ -2558,26 +2563,15 @@ app.post('/api/createPlaylist', optionalJwt, async (req, res) => {
|
||||
|
||||
app.post('/api/getPlaylist', optionalJwt, async (req, res) => {
|
||||
let playlistID = req.body.playlistID;
|
||||
let type = req.body.type;
|
||||
let uuid = req.body.uuid;
|
||||
|
||||
let playlist = null;
|
||||
|
||||
if (req.isAuthenticated()) {
|
||||
playlist = auth_api.getUserPlaylist(uuid ? uuid : req.user.uid, playlistID, type);
|
||||
playlist = auth_api.getUserPlaylist(uuid ? uuid : req.user.uid, playlistID);
|
||||
type = playlist.type;
|
||||
} else {
|
||||
if (!type) {
|
||||
playlist = db.get('playlists.audio').find({id: playlistID}).value();
|
||||
if (!playlist) {
|
||||
playlist = db.get('playlists.video').find({id: playlistID}).value();
|
||||
if (playlist) type = 'video';
|
||||
} else {
|
||||
type = 'audio';
|
||||
}
|
||||
}
|
||||
|
||||
if (!playlist) playlist = db.get(`playlists.${type}`).find({id: playlistID}).value();
|
||||
playlist = db.get(`playlists`).find({id: playlistID}).value();
|
||||
}
|
||||
|
||||
res.send({
|
||||
@@ -2590,14 +2584,13 @@ app.post('/api/getPlaylist', optionalJwt, async (req, res) => {
|
||||
app.post('/api/updatePlaylistFiles', optionalJwt, async (req, res) => {
|
||||
let playlistID = req.body.playlistID;
|
||||
let fileNames = req.body.fileNames;
|
||||
let type = req.body.type;
|
||||
|
||||
let success = false;
|
||||
try {
|
||||
if (req.isAuthenticated()) {
|
||||
auth_api.updatePlaylistFiles(req.user.uid, playlistID, fileNames, type);
|
||||
auth_api.updatePlaylistFiles(req.user.uid, playlistID, fileNames);
|
||||
} else {
|
||||
db.get(`playlists.${type}`)
|
||||
db.get(`playlists`)
|
||||
.find({id: playlistID})
|
||||
.assign({fileNames: fileNames})
|
||||
.write();
|
||||
@@ -2623,15 +2616,14 @@ app.post('/api/updatePlaylist', optionalJwt, async (req, res) => {
|
||||
|
||||
app.post('/api/deletePlaylist', optionalJwt, async (req, res) => {
|
||||
let playlistID = req.body.playlistID;
|
||||
let type = req.body.type;
|
||||
|
||||
let success = null;
|
||||
try {
|
||||
if (req.isAuthenticated()) {
|
||||
auth_api.removePlaylist(req.user.uid, playlistID, type);
|
||||
auth_api.removePlaylist(req.user.uid, playlistID);
|
||||
} else {
|
||||
// removes playlist from playlists
|
||||
db.get(`playlists.${type}`)
|
||||
db.get(`playlists`)
|
||||
.remove({id: playlistID})
|
||||
.write();
|
||||
}
|
||||
@@ -2653,23 +2645,23 @@ app.post('/api/deleteFile', optionalJwt, async (req, res) => {
|
||||
var blacklistMode = req.body.blacklistMode;
|
||||
|
||||
if (req.isAuthenticated()) {
|
||||
let success = auth_api.deleteUserFile(req.user.uid, uid, type, blacklistMode);
|
||||
let success = auth_api.deleteUserFile(req.user.uid, uid, blacklistMode);
|
||||
res.send(success);
|
||||
return;
|
||||
}
|
||||
|
||||
var file_obj = db.get(`files.${type}`).find({uid: uid}).value();
|
||||
var file_obj = db.get(`files`).find({uid: uid}).value();
|
||||
var name = file_obj.id;
|
||||
var fullpath = file_obj ? file_obj.path : null;
|
||||
var wasDeleted = false;
|
||||
if (await fs.pathExists(fullpath))
|
||||
{
|
||||
wasDeleted = type === 'audio' ? await deleteAudioFile(name, path.basename(fullpath), blacklistMode) : await deleteVideoFile(name, path.basename(fullpath), blacklistMode);
|
||||
db.get('files.video').remove({uid: uid}).write();
|
||||
db.get('files').remove({uid: uid}).write();
|
||||
// wasDeleted = true;
|
||||
res.send(wasDeleted);
|
||||
} else if (video_obj) {
|
||||
db.get('files.video').remove({uid: uid}).write();
|
||||
db.get('files').remove({uid: uid}).write();
|
||||
wasDeleted = true;
|
||||
res.send(wasDeleted);
|
||||
} else {
|
||||
|
||||
@@ -281,24 +281,13 @@ exports.adminExists = function() {
|
||||
|
||||
// video stuff
|
||||
|
||||
exports.getUserVideos = function(user_uid, type) {
|
||||
exports.getUserVideos = function(user_uid) {
|
||||
const user = users_db.get('users').find({uid: user_uid}).value();
|
||||
return user['files'][type];
|
||||
return user['files'];
|
||||
}
|
||||
|
||||
exports.getUserVideo = function(user_uid, file_uid, type, requireSharing = false) {
|
||||
let file = null;
|
||||
if (!type) {
|
||||
file = users_db.get('users').find({uid: user_uid}).get(`files.audio`).find({uid: file_uid}).value();
|
||||
if (!file) {
|
||||
file = users_db.get('users').find({uid: user_uid}).get(`files.video`).find({uid: file_uid}).value();
|
||||
if (file) type = 'video';
|
||||
} else {
|
||||
type = 'audio';
|
||||
}
|
||||
}
|
||||
|
||||
if (!file && type) file = users_db.get('users').find({uid: user_uid}).get(`files.${type}`).find({uid: file_uid}).value();
|
||||
exports.getUserVideo = function(user_uid, file_uid, requireSharing = false) {
|
||||
let file = users_db.get('users').find({uid: user_uid}).get(`files`).find({uid: file_uid}).value();
|
||||
|
||||
// prevent unauthorized users from accessing the file info
|
||||
if (file && !file['sharingEnabled'] && requireSharing) file = null;
|
||||
@@ -306,38 +295,28 @@ exports.getUserVideo = function(user_uid, file_uid, type, requireSharing = false
|
||||
return file;
|
||||
}
|
||||
|
||||
exports.addPlaylist = function(user_uid, new_playlist, type) {
|
||||
users_db.get('users').find({uid: user_uid}).get(`playlists.${type}`).push(new_playlist).write();
|
||||
exports.addPlaylist = function(user_uid, new_playlist) {
|
||||
users_db.get('users').find({uid: user_uid}).get(`playlists`).push(new_playlist).write();
|
||||
return true;
|
||||
}
|
||||
|
||||
exports.updatePlaylistFiles = function(user_uid, playlistID, new_filenames, type) {
|
||||
users_db.get('users').find({uid: user_uid}).get(`playlists.${type}`).find({id: playlistID}).assign({fileNames: new_filenames});
|
||||
exports.updatePlaylistFiles = function(user_uid, playlistID, new_filenames) {
|
||||
users_db.get('users').find({uid: user_uid}).get(`playlists`).find({id: playlistID}).assign({fileNames: new_filenames});
|
||||
return true;
|
||||
}
|
||||
|
||||
exports.removePlaylist = function(user_uid, playlistID, type) {
|
||||
users_db.get('users').find({uid: user_uid}).get(`playlists.${type}`).remove({id: playlistID}).write();
|
||||
exports.removePlaylist = function(user_uid, playlistID) {
|
||||
users_db.get('users').find({uid: user_uid}).get(`playlists`).remove({id: playlistID}).write();
|
||||
return true;
|
||||
}
|
||||
|
||||
exports.getUserPlaylists = function(user_uid, type) {
|
||||
exports.getUserPlaylists = function(user_uid) {
|
||||
const user = users_db.get('users').find({uid: user_uid}).value();
|
||||
return user['playlists'][type];
|
||||
return user['playlists'];
|
||||
}
|
||||
|
||||
exports.getUserPlaylist = function(user_uid, playlistID, type, requireSharing = false) {
|
||||
let playlist = null;
|
||||
if (!type) {
|
||||
playlist = users_db.get('users').find({uid: user_uid}).get(`playlists.audio`).find({id: playlistID}).value();
|
||||
if (!playlist) {
|
||||
playlist = users_db.get('users').find({uid: user_uid}).get(`playlists.video`).find({id: playlistID}).value();
|
||||
if (playlist) type = 'video';
|
||||
} else {
|
||||
type = 'audio';
|
||||
}
|
||||
}
|
||||
if (!playlist) playlist = users_db.get('users').find({uid: user_uid}).get(`playlists.${type}`).find({id: playlistID}).value();
|
||||
exports.getUserPlaylist = function(user_uid, playlistID, requireSharing = false) {
|
||||
let playlist = users_db.get('users').find({uid: user_uid}).get(`playlists`).find({id: playlistID}).value();
|
||||
|
||||
// prevent unauthorized users from accessing the file info
|
||||
if (requireSharing && !playlist['sharingEnabled']) playlist = null;
|
||||
@@ -345,21 +324,22 @@ exports.getUserPlaylist = function(user_uid, playlistID, type, requireSharing =
|
||||
return playlist;
|
||||
}
|
||||
|
||||
exports.registerUserFile = function(user_uid, file_object, type) {
|
||||
users_db.get('users').find({uid: user_uid}).get(`files.${type}`)
|
||||
exports.registerUserFile = function(user_uid, file_object) {
|
||||
users_db.get('users').find({uid: user_uid}).get(`files`)
|
||||
.remove({
|
||||
path: file_object['path']
|
||||
}).write();
|
||||
|
||||
users_db.get('users').find({uid: user_uid}).get(`files.${type}`)
|
||||
users_db.get('users').find({uid: user_uid}).get(`files`)
|
||||
.push(file_object)
|
||||
.write();
|
||||
}
|
||||
|
||||
exports.deleteUserFile = async function(user_uid, file_uid, type, blacklistMode = false) {
|
||||
exports.deleteUserFile = async function(user_uid, file_uid, blacklistMode = false) {
|
||||
let success = false;
|
||||
const file_obj = users_db.get('users').find({uid: user_uid}).get(`files.${type}`).find({uid: file_uid}).value();
|
||||
const file_obj = users_db.get('users').find({uid: user_uid}).get(`files`).find({uid: file_uid}).value();
|
||||
if (file_obj) {
|
||||
const type = file_obj.isAudio ? 'audio' : 'video';
|
||||
const usersFileFolder = config_api.getConfigItem('ytdl_users_base_path');
|
||||
const ext = type === 'audio' ? '.mp3' : '.mp4';
|
||||
|
||||
@@ -375,7 +355,7 @@ exports.deleteUserFile = async function(user_uid, file_uid, type, blacklistMode
|
||||
}
|
||||
|
||||
const full_path = path.join(usersFileFolder, user_uid, type, file_obj.id + ext);
|
||||
users_db.get('users').find({uid: user_uid}).get(`files.${type}`)
|
||||
users_db.get('users').find({uid: user_uid}).get(`files`)
|
||||
.remove({
|
||||
uid: file_uid
|
||||
}).write();
|
||||
@@ -424,11 +404,11 @@ exports.deleteUserFile = async function(user_uid, file_uid, type, blacklistMode
|
||||
return success;
|
||||
}
|
||||
|
||||
exports.changeSharingMode = function(user_uid, file_uid, type, is_playlist, enabled) {
|
||||
exports.changeSharingMode = function(user_uid, file_uid, is_playlist, enabled) {
|
||||
let success = false;
|
||||
const user_db_obj = users_db.get('users').find({uid: user_uid});
|
||||
if (user_db_obj.value()) {
|
||||
const file_db_obj = is_playlist ? user_db_obj.get(`playlists.${type}`).find({id: file_uid}) : user_db_obj.get(`files.${type}`).find({uid: file_uid});
|
||||
const file_db_obj = is_playlist ? user_db_obj.get(`playlists`).find({id: file_uid}) : user_db_obj.get(`files`).find({uid: file_uid});
|
||||
if (file_db_obj.value()) {
|
||||
success = true;
|
||||
file_db_obj.assign({sharingEnabled: enabled}).write();
|
||||
|
||||
@@ -32,9 +32,9 @@ function registerFileDB(file_path, type, multiUserMode = null, sub = null, custo
|
||||
if (!sub) {
|
||||
if (multiUserMode) {
|
||||
const user_uid = multiUserMode.user;
|
||||
db_path = users_db.get('users').find({uid: user_uid}).get(`files.${type}`);
|
||||
db_path = users_db.get('users').find({uid: user_uid}).get(`files`);
|
||||
} else {
|
||||
db_path = db.get(`files.${type}`)
|
||||
db_path = db.get(`files`);
|
||||
}
|
||||
} else {
|
||||
if (multiUserMode) {
|
||||
@@ -94,18 +94,18 @@ function generateFileObject(id, type, customPath = null, sub = null) {
|
||||
var thumbnail = jsonobj.thumbnail;
|
||||
var duration = jsonobj.duration;
|
||||
var isaudio = type === 'audio';
|
||||
var file_obj = new utils.File(id, title, thumbnail, isaudio, duration, url, uploader, size, file_path, upload_date);
|
||||
var description = jsonobj.description;
|
||||
var file_obj = new utils.File(id, title, thumbnail, isaudio, duration, url, uploader, size, file_path, upload_date, description);
|
||||
return file_obj;
|
||||
}
|
||||
|
||||
function updatePlaylist(playlist, user_uid) {
|
||||
let playlistID = playlist.id;
|
||||
let type = playlist.type;
|
||||
let db_loc = null;
|
||||
if (user_uid) {
|
||||
db_loc = users_db.get('users').find({uid: user_uid}).get(`playlists.${type}`).find({id: playlistID});
|
||||
db_loc = users_db.get('users').find({uid: user_uid}).get(`playlists`).find({id: playlistID});
|
||||
} else {
|
||||
db_loc = db.get(`playlists.${type}`).find({id: playlistID});
|
||||
db_loc = db.get(`playlists`).find({id: playlistID});
|
||||
}
|
||||
db_loc.assign(playlist).write();
|
||||
return true;
|
||||
@@ -132,14 +132,14 @@ function getFileDirectoriesAndDBs() {
|
||||
// add user's audio dir to check list
|
||||
dirs_to_check.push({
|
||||
basePath: path.join(usersFileFolder, user.uid, 'audio'),
|
||||
dbPath: users_db.get('users').find({uid: user.uid}).get('files.audio'),
|
||||
dbPath: users_db.get('users').find({uid: user.uid}).get('files'),
|
||||
type: 'audio'
|
||||
});
|
||||
|
||||
// add user's video dir to check list
|
||||
dirs_to_check.push({
|
||||
basePath: path.join(usersFileFolder, user.uid, 'video'),
|
||||
dbPath: users_db.get('users').find({uid: user.uid}).get('files.video'),
|
||||
dbPath: users_db.get('users').find({uid: user.uid}).get('files'),
|
||||
type: 'video'
|
||||
});
|
||||
}
|
||||
@@ -153,14 +153,14 @@ function getFileDirectoriesAndDBs() {
|
||||
// add audio dir to check list
|
||||
dirs_to_check.push({
|
||||
basePath: audioFolderPath,
|
||||
dbPath: db.get('files.audio'),
|
||||
dbPath: db.get('files'),
|
||||
type: 'audio'
|
||||
});
|
||||
|
||||
// add video dir to check list
|
||||
dirs_to_check.push({
|
||||
basePath: videoFolderPath,
|
||||
dbPath: db.get('files.video'),
|
||||
dbPath: db.get('files'),
|
||||
type: 'video'
|
||||
});
|
||||
}
|
||||
|
||||
@@ -189,7 +189,7 @@ async function recFindByExt(base,ext,files,result)
|
||||
|
||||
// objects
|
||||
|
||||
function File(id, title, thumbnailURL, isAudio, duration, url, uploader, size, path, upload_date) {
|
||||
function File(id, title, thumbnailURL, isAudio, duration, url, uploader, size, path, upload_date, description) {
|
||||
this.id = id;
|
||||
this.title = title;
|
||||
this.thumbnailURL = thumbnailURL;
|
||||
@@ -200,6 +200,7 @@ function File(id, title, thumbnailURL, isAudio, duration, url, uploader, size, p
|
||||
this.size = size;
|
||||
this.path = path;
|
||||
this.upload_date = upload_date;
|
||||
this.description = description;
|
||||
}
|
||||
|
||||
module.exports = {
|
||||
|
||||
@@ -81,6 +81,7 @@ import { EditSubscriptionDialogComponent } from './dialogs/edit-subscription-dia
|
||||
import { CustomPlaylistsComponent } from './components/custom-playlists/custom-playlists.component';
|
||||
import { EditCategoryDialogComponent } from './dialogs/edit-category-dialog/edit-category-dialog.component';
|
||||
import { TwitchChatComponent } from './components/twitch-chat/twitch-chat.component';
|
||||
import { LinkifyPipe, SeeMoreComponent } from './components/see-more/see-more.component';
|
||||
|
||||
registerLocaleData(es, 'es');
|
||||
|
||||
@@ -107,6 +108,7 @@ export function isVisible({ event, element, scrollContainer, offset }: IsVisible
|
||||
VideoInfoDialogComponent,
|
||||
ArgModifierDialogComponent,
|
||||
HighlightPipe,
|
||||
LinkifyPipe,
|
||||
UpdaterComponent,
|
||||
UpdateProgressDialogComponent,
|
||||
ShareMediaDialogComponent,
|
||||
@@ -127,7 +129,8 @@ export function isVisible({ event, element, scrollContainer, offset }: IsVisible
|
||||
EditSubscriptionDialogComponent,
|
||||
CustomPlaylistsComponent,
|
||||
EditCategoryDialogComponent,
|
||||
TwitchChatComponent
|
||||
TwitchChatComponent,
|
||||
SeeMoreComponent
|
||||
],
|
||||
imports: [
|
||||
CommonModule,
|
||||
@@ -188,7 +191,8 @@ export function isVisible({ event, element, scrollContainer, offset }: IsVisible
|
||||
PostsService
|
||||
],
|
||||
exports: [
|
||||
HighlightPipe
|
||||
HighlightPipe,
|
||||
LinkifyPipe
|
||||
],
|
||||
bootstrap: [AppComponent]
|
||||
})
|
||||
|
||||
11
src/app/components/see-more/see-more.component.html
Normal file
11
src/app/components/see-more/see-more.component.html
Normal file
@@ -0,0 +1,11 @@
|
||||
<span class="text" [ngStyle]="{'-webkit-line-clamp': !see_more_active ? line_limit : null}" [innerHTML]="text | linkify"></span>
|
||||
<span>
|
||||
<a [routerLink]="" (click)="toggleSeeMore()">
|
||||
<ng-container *ngIf="!see_more_active" i18n="See more">
|
||||
See more.
|
||||
</ng-container>
|
||||
<ng-container *ngIf="see_more_active" i18n="See less">
|
||||
See less.
|
||||
</ng-container>
|
||||
</a>
|
||||
</span>
|
||||
7
src/app/components/see-more/see-more.component.scss
Normal file
7
src/app/components/see-more/see-more.component.scss
Normal file
@@ -0,0 +1,7 @@
|
||||
.text {
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
display: -webkit-box;
|
||||
-webkit-box-orient: vertical;
|
||||
word-wrap: break-word;
|
||||
}
|
||||
25
src/app/components/see-more/see-more.component.spec.ts
Normal file
25
src/app/components/see-more/see-more.component.spec.ts
Normal file
@@ -0,0 +1,25 @@
|
||||
import { async, ComponentFixture, TestBed } from '@angular/core/testing';
|
||||
|
||||
import { SeeMoreComponent } from './see-more.component';
|
||||
|
||||
describe('SeeMoreComponent', () => {
|
||||
let component: SeeMoreComponent;
|
||||
let fixture: ComponentFixture<SeeMoreComponent>;
|
||||
|
||||
beforeEach(async(() => {
|
||||
TestBed.configureTestingModule({
|
||||
declarations: [ SeeMoreComponent ]
|
||||
})
|
||||
.compileComponents();
|
||||
}));
|
||||
|
||||
beforeEach(() => {
|
||||
fixture = TestBed.createComponent(SeeMoreComponent);
|
||||
component = fixture.componentInstance;
|
||||
fixture.detectChanges();
|
||||
});
|
||||
|
||||
it('should create', () => {
|
||||
expect(component).toBeTruthy();
|
||||
});
|
||||
});
|
||||
60
src/app/components/see-more/see-more.component.ts
Normal file
60
src/app/components/see-more/see-more.component.ts
Normal file
@@ -0,0 +1,60 @@
|
||||
import { Component, Input, OnInit, Pipe, PipeTransform } from '@angular/core';
|
||||
import { DomSanitizer } from '@angular/platform-browser';
|
||||
|
||||
@Pipe({ name: 'linkify' })
|
||||
export class LinkifyPipe implements PipeTransform {
|
||||
|
||||
constructor(private _domSanitizer: DomSanitizer) {}
|
||||
|
||||
transform(value: any, args?: any): any {
|
||||
return this._domSanitizer.bypassSecurityTrustHtml(this.stylize(value));
|
||||
}
|
||||
|
||||
// Modify this method according to your custom logic
|
||||
private stylize(text: string): string {
|
||||
let stylizedText: string = '';
|
||||
if (text && text.length > 0) {
|
||||
for (let line of text.split("\n")) {
|
||||
for (let t of line.split(" ")) {
|
||||
if (t.startsWith("http") && t.length>7) {
|
||||
stylizedText += `<a target="_blank" href="${t}">${t}</a> `;
|
||||
}
|
||||
else
|
||||
stylizedText += t + " ";
|
||||
}
|
||||
stylizedText += '<br>';
|
||||
}
|
||||
return stylizedText;
|
||||
}
|
||||
else return text;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@Component({
|
||||
selector: 'app-see-more',
|
||||
templateUrl: './see-more.component.html',
|
||||
providers: [LinkifyPipe],
|
||||
styleUrls: ['./see-more.component.scss']
|
||||
})
|
||||
export class SeeMoreComponent implements OnInit {
|
||||
|
||||
see_more_active = false;
|
||||
|
||||
@Input() text = '';
|
||||
@Input() line_limit = 2;
|
||||
|
||||
constructor() { }
|
||||
|
||||
ngOnInit(): void {
|
||||
}
|
||||
|
||||
toggleSeeMore() {
|
||||
this.see_more_active = !this.see_more_active;
|
||||
}
|
||||
|
||||
parseText() {
|
||||
return this.text.replace(/(http.*?\s)/, "<a href=\"$1\">$1</a>")
|
||||
}
|
||||
|
||||
}
|
||||
@@ -8,14 +8,28 @@
|
||||
</video>
|
||||
</vg-player>
|
||||
</div>
|
||||
<div *ngIf="file_obj" style="height: fit-content; width: 100%; margin-top: 10px;">
|
||||
<div *ngIf="db_file" style="height: fit-content; width: 100%; margin-top: 10px;">
|
||||
<div class="container">
|
||||
<div class="row">
|
||||
<div class="col">
|
||||
<ng-container *ngIf="file_obj">{{file_obj['local_play_count'] ? file_obj['local_play_count'] : 0}} <ng-container i18n="View count label">views</ng-container></ng-container>
|
||||
<div class="col-2 col-lg-1">
|
||||
<ng-container *ngIf="db_file">{{db_file['local_view_count'] ? db_file['local_view_count'] : 0}} <ng-container i18n="View count label">views</ng-container></ng-container>
|
||||
</div>
|
||||
<div class="col">
|
||||
|
||||
<div style="white-space: pre-line;" class="col-9 col-lg-10">
|
||||
<ng-container *ngIf="db_file && db_file['description']">
|
||||
<p>
|
||||
<app-see-more [text]="db_file['description']"></app-see-more>
|
||||
</p>
|
||||
</ng-container>
|
||||
<ng-container *ngIf="!db_file || !db_file['description']">
|
||||
<p style="text-align: center;">
|
||||
No description available.
|
||||
</p>
|
||||
</ng-container>
|
||||
</div>
|
||||
<div class="col-1">
|
||||
<div *ngIf="db_file && db_file.url.includes('twitch.tv/videos/') && postsService['config']['API']['use_twitch_API']">
|
||||
<button (click)="drawer.toggle()" mat-icon-button><mat-icon>chat</mat-icon></button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@@ -25,15 +39,11 @@
|
||||
<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>
|
||||
</div>
|
||||
<mat-drawer #drawer class="example-sidenav" mode="side" position="end" [opened]="db_file && db_file['chat_exists']">
|
||||
<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/')">
|
||||
<app-twitch-chat #twitchchat [db_file]="db_file" [current_timestamp]="api.currentTime"></app-twitch-chat>
|
||||
</ng-container>
|
||||
</mat-drawer>
|
||||
|
||||
<div *ngIf="db_file && db_file.url.includes('twitch.tv/videos/') && postsService['config']['API']['use_twitch_API']" style="position: absolute; right: 0px">
|
||||
<button style="right: 0px; top: -46px;" (click)="drawer.toggle()" mat-icon-button><mat-icon>chat</mat-icon></button>
|
||||
</div>
|
||||
|
||||
<div class="update-playlist-button-div" *ngIf="id && playlistChanged()">
|
||||
<div class="spinner-div">
|
||||
|
||||
Reference in New Issue
Block a user