diff --git a/backend/app.js b/backend/app.js index d6ec687..16fd923 100644 --- a/backend/app.js +++ b/backend/app.js @@ -986,6 +986,7 @@ function registerFileDB(full_file_path, type) { db.get(`files.${type}`) .push(file_object) .write(); + return file_object['uid']; } function generateFileObject(id, type) { @@ -1328,6 +1329,7 @@ app.post('/api/tomp3', async function(req, res) { } youtubedl.exec(url, downloadConfig, {}, function(err, output) { + var uid = null; let new_date = Date.now(); let difference = (new_date - date)/1000; logger.debug(`Audio download delay: ${difference} seconds.`); @@ -1368,7 +1370,7 @@ app.post('/api/tomp3', async function(req, res) { if (!success) logger.error('Failed to apply ID3 tag to audio file ' + full_file_path); // registers file in DB - registerFileDB(full_file_path.substring(audioFolderPath.length, full_file_path.length), 'audio'); + uid = registerFileDB(full_file_path.substring(audioFolderPath.length, full_file_path.length), 'audio'); } else { logger.error('Download failed: Output mp3 does not exist'); } @@ -1389,7 +1391,8 @@ app.post('/api/tomp3', async function(req, res) { var audiopathEncoded = encodeURIComponent(file_names[0]); res.send({ audiopathEncoded: audiopathEncoded, - file_names: is_playlist ? file_names : null + file_names: is_playlist ? file_names : null, + uid: uid }); } }); @@ -1468,6 +1471,7 @@ app.post('/api/tomp4', async function(req, res) { } youtubedl.exec(url, downloadConfig, {}, function(err, output) { + var uid = null; let new_date = Date.now(); let difference = (new_date - date)/1000; logger.debug(`Video download delay: ${difference} seconds.`); @@ -1510,7 +1514,7 @@ app.post('/api/tomp4', async function(req, res) { } // registers file in DB - registerFileDB(full_file_path.substring(videoFolderPath.length, full_file_path.length), 'video'); + uid = registerFileDB(full_file_path.substring(videoFolderPath.length, full_file_path.length), 'video'); if (file_name) file_names.push(file_name); } @@ -1528,7 +1532,8 @@ app.post('/api/tomp4', async function(req, res) { var videopathEncoded = encodeURIComponent(file_names[0]); res.send({ videopathEncoded: videopathEncoded, - file_names: is_playlist ? file_names : null + file_names: is_playlist ? file_names : null, + uid: uid }); res.end("yes"); } @@ -1601,6 +1606,101 @@ app.post('/api/getMp4s', function(req, res) { res.end("yes"); }); +app.post('/api/getFile', function (req, res) { + var uid = req.body.uid; + var type = req.body.type; + + var file = null; + + 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) db.get(`files.${type}`).find({uid: uid}).value(); + + if (file) { + res.send({ + success: true, + file: file + }); + } else { + res.send({ + success: false + }); + } +}); + +// video sharing +app.post('/api/enableSharing', function(req, res) { + var type = req.body.type; + var uid = req.body.uid; + try { + success = true; + if (type === 'audio' || type === 'video') { + db.get(`files.${type}`) + .find({uid: uid}) + .assign({sharingEnabled: true}) + .write(); + } else if (type === 'playlist') { + db.get(`playlists.${type}`) + .find({id: uid}) + .assign({sharingEnabled: true}) + .write(); + } else if (type === 'subscription') { + // 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. + } else { + // error + success = false; + } + + } catch(err) { + success = false; + } + + res.send({ + success: success + }); +}); + +app.post('/api/disableSharing', function(req, res) { + var type = req.body.type; + var uid = req.body.uid; + try { + success = true; + if (type === 'audio' || type === 'video') { + db.get(`files.${type}`) + .find({uid: uid}) + .assign({sharingEnabled: false}) + .write(); + } else if (type === 'playlist') { + db.get(`playlists.${type}`) + .find({id: uid}) + .assign({sharingEnabled: false}) + .write(); + } else if (type === 'subscription') { + // 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. + } else { + // error + success = false; + } + + } catch(err) { + success = false; + } + + res.send({ + success: success + }); +}); + app.post('/api/subscribe', async (req, res) => { let name = req.body.name; let url = req.body.url; diff --git a/src/app/file-card/file-card.component.html b/src/app/file-card/file-card.component.html index 92116dc..f9f62a3 100644 --- a/src/app/file-card/file-card.component.html +++ b/src/app/file-card/file-card.component.html @@ -2,7 +2,7 @@
- {{title}} + {{title}}
ID: {{name}}
Count: {{count}}
diff --git a/src/app/main/main.component.ts b/src/app/main/main.component.ts index 3d0a66f..568b1ce 100644 --- a/src/app/main/main.component.ts +++ b/src/app/main/main.component.ts @@ -390,11 +390,11 @@ export class MainComponent implements OnInit { } } - public goToFile(name, isAudio) { + public goToFile(name, isAudio, uid) { if (isAudio) { - this.downloadHelperMp3(name, false, false); + this.downloadHelperMp3(name, uid, false, false); } else { - this.downloadHelperMp4(name, false, false); + this.downloadHelperMp4(name, uid, false, false); } } @@ -407,7 +407,7 @@ export class MainComponent implements OnInit { } else { localStorage.setItem('player_navigator', this.router.url); const fileNames = playlist.fileNames; - this.router.navigate(['/player', {fileNames: fileNames.join('|nvr|'), type: type, id: playlistID}]); + this.router.navigate(['/player', {fileNames: fileNames.join('|nvr|'), type: type, id: playlistID, uid: playlistID}]); } } else { // playlist not found @@ -463,7 +463,7 @@ export class MainComponent implements OnInit { // download helpers - downloadHelperMp3(name, is_playlist = false, forceView = false, new_download = null) { + downloadHelperMp3(name, uid, is_playlist = false, forceView = false, new_download = null) { this.downloadingfile = false; if (this.multiDownloadMode && !this.downloadOnlyMode) { @@ -482,7 +482,7 @@ export class MainComponent implements OnInit { if (is_playlist) { this.router.navigate(['/player', {fileNames: name.join('|nvr|'), type: 'audio'}]); } else { - this.router.navigate(['/player', {fileNames: name, type: 'audio'}]); + this.router.navigate(['/player', {fileNames: name, type: 'audio', uid: uid}]); } } } @@ -501,7 +501,7 @@ export class MainComponent implements OnInit { } } - downloadHelperMp4(name, is_playlist = false, forceView = false, new_download = null) { + downloadHelperMp4(name, uid, is_playlist = false, forceView = false, new_download = null) { this.downloadingfile = false; if (this.multiDownloadMode && !this.downloadOnlyMode) { // do nothing @@ -519,7 +519,7 @@ export class MainComponent implements OnInit { if (is_playlist) { this.router.navigate(['/player', {fileNames: name.join('|nvr|'), type: 'video'}]); } else { - this.router.navigate(['/player', {fileNames: name, type: 'video'}]); + this.router.navigate(['/player', {fileNames: name, type: 'video', uid: uid}]); } } } @@ -592,7 +592,7 @@ export class MainComponent implements OnInit { this.path = is_playlist ? posts['file_names'] : posts['audiopathEncoded']; if (this.path !== '-1') { - this.downloadHelperMp3(this.path, is_playlist, false, new_download); + this.downloadHelperMp3(this.path, posts['uid'], is_playlist, false, new_download); } }, error => { // can't access server or failed to download for other reasons this.downloadingfile = false; @@ -631,7 +631,7 @@ export class MainComponent implements OnInit { this.path = is_playlist ? posts['file_names'] : posts['videopathEncoded']; if (this.path !== '-1') { - this.downloadHelperMp4(this.path, is_playlist, false, new_download); + this.downloadHelperMp4(this.path, posts['uid'], is_playlist, false, new_download); } }, error => { // can't access server this.downloadingfile = false; diff --git a/src/app/player/player.component.html b/src/app/player/player.component.html index 10b9f56..30aac2b 100644 --- a/src/app/player/player.component.html +++ b/src/app/player/player.component.html @@ -1,4 +1,4 @@ -
+
diff --git a/src/app/player/player.component.ts b/src/app/player/player.component.ts index 61f2fe9..d89ee12 100644 --- a/src/app/player/player.component.ts +++ b/src/app/player/player.component.ts @@ -25,6 +25,8 @@ export class PlayerComponent implements OnInit { original_playlist: string = null; playlist_updating = false; + show_player = false; + currentIndex = 0; currentItem: IMedia = null; api: VgAPI; @@ -33,6 +35,7 @@ export class PlayerComponent implements OnInit { fileNames: string[]; type: string; id = null; // used for playlists (not subscription) + uid = null; // used for non-subscription files (audio, video, playlist) subscriptionName = null; subPlaylist = null; @@ -53,9 +56,9 @@ export class PlayerComponent implements OnInit { ngOnInit(): void { this.innerWidth = window.innerWidth; - this.fileNames = this.route.snapshot.paramMap.get('fileNames').split('|nvr|'); this.type = this.route.snapshot.paramMap.get('type'); this.id = this.route.snapshot.paramMap.get('id'); + this.uid = this.route.snapshot.paramMap.get('uid'); this.subscriptionName = this.route.snapshot.paramMap.get('subscriptionName'); this.subPlaylist = this.route.snapshot.paramMap.get('subPlaylist'); @@ -66,53 +69,16 @@ export class PlayerComponent implements OnInit { this.audioFolderPath = result['YoutubeDLMaterial']['Downloader']['path-audio']; this.videoFolderPath = result['YoutubeDLMaterial']['Downloader']['path-video']; this.subscriptionFolderPath = result['YoutubeDLMaterial']['Subscriptions']['subscriptions_base_path']; + this.fileNames = this.route.snapshot.paramMap.get('fileNames') ? this.route.snapshot.paramMap.get('fileNames').split('|nvr|') : null; - - let fileType = null; - if (this.type === 'audio') { - fileType = 'audio/mp3'; - } else if (this.type === 'video') { - fileType = 'video/mp4'; - } else if (this.type === 'subscription') { - // only supports mp4 for now - fileType = 'video/mp4'; - } else { - // error - console.error('Must have valid file type! Use \'audio\', \'video\', or \'subscription\'.'); + if (this.uid) { + this.getFile(); } - for (let i = 0; i < this.fileNames.length; i++) { - const fileName = this.fileNames[i]; - let baseLocation = null; - let fullLocation = null; - if (!this.subscriptionName) { - baseLocation = this.type + '/'; - fullLocation = this.baseStreamPath + baseLocation + encodeURIComponent(fileName); - } else { - // default to video but include subscription name param - baseLocation = 'video/'; - fullLocation = this.baseStreamPath + baseLocation + encodeURIComponent(fileName) + '?subName=' + this.subscriptionName + - '&subPlaylist=' + this.subPlaylist; - } - // if it has a slash (meaning it's in a directory), only get the file name for the label - let label = null; - const decodedName = decodeURIComponent(fileName); - const hasSlash = decodedName.includes('/') || decodedName.includes('\\'); - if (hasSlash) { - label = decodedName.replace(/^.*[\\\/]/, ''); - } else { - label = decodedName; - } - const mediaObject: IMedia = { - title: fileName, - src: fullLocation, - type: fileType, - label: label - } - this.playlist.push(mediaObject); + if (this.type === 'subscription' || this.fileNames) { + this.show_player = true; + this.parseFileNames(); } - this.currentItem = this.playlist[this.currentIndex]; - this.original_playlist = JSON.stringify(this.playlist); }); // this.getFileInfos(); @@ -124,6 +90,69 @@ export class PlayerComponent implements OnInit { } + getFile() { + this.postsService.getFile(this.uid, null).subscribe(res => { + if (!this.fileNames) { + // means it's a shared video + if (!this.id) { + // regular video/audio file (not playlist) + this.fileNames = [res['file']['id']]; + this.type = res['file']['isAudio'] ? 'audio' : 'video'; + this.parseFileNames(); + } + } + this.show_player = true; + }); + } + + parseFileNames() { + let fileType = null; + if (this.type === 'audio') { + fileType = 'audio/mp3'; + } else if (this.type === 'video') { + fileType = 'video/mp4'; + } else if (this.type === 'subscription') { + // only supports mp4 for now + fileType = 'video/mp4'; + } else { + // error + console.error('Must have valid file type! Use \'audio\', \'video\', or \'subscription\'.'); + } + + for (let i = 0; i < this.fileNames.length; i++) { + const fileName = this.fileNames[i]; + let baseLocation = null; + let fullLocation = null; + if (!this.subscriptionName) { + baseLocation = this.type + '/'; + fullLocation = this.baseStreamPath + baseLocation + encodeURIComponent(fileName); + } else { + // default to video but include subscription name param + baseLocation = 'video/'; + fullLocation = this.baseStreamPath + baseLocation + encodeURIComponent(fileName) + '?subName=' + this.subscriptionName + + '&subPlaylist=' + this.subPlaylist; + } + // if it has a slash (meaning it's in a directory), only get the file name for the label + let label = null; + const decodedName = decodeURIComponent(fileName); + const hasSlash = decodedName.includes('/') || decodedName.includes('\\'); + if (hasSlash) { + label = decodedName.replace(/^.*[\\\/]/, ''); + } else { + label = decodedName; + } + const mediaObject: IMedia = { + title: fileName, + src: fullLocation, + type: fileType, + label: label + } + this.playlist.push(mediaObject); + } + this.currentItem = this.playlist[this.currentIndex]; + this.original_playlist = JSON.stringify(this.playlist); + } + onPlayerReady(api: VgAPI) { this.api = api; diff --git a/src/app/posts.services.ts b/src/app/posts.services.ts index 66afcfd..e73e311 100644 --- a/src/app/posts.services.ts +++ b/src/app/posts.services.ts @@ -118,6 +118,10 @@ export class PostsService { return this.http.post(this.path + 'getMp4s', {}); } + getFile(uid, type) { + return this.http.post(this.path + 'getFile', {uid: uid, type: type}); + } + downloadFileFromServer(fileName, type, outputName = null, fullPathProvided = null) { return this.http.post(this.path + 'downloadFile', {fileNames: fileName, type: type, @@ -147,6 +151,14 @@ export class PostsService { return this.http.post(this.path + 'checkPin', {input_pin: unhashed_pin}); } + enableSharing(uid, type) { + return this.http.post(this.path + 'enableSharing', {uid: uid, type: type}); + } + + disableSharing(uid, type) { + return this.http.post(this.path + 'disableSharing', {uid: uid, type: type}); + } + createPlaylist(playlistName, fileNames, type, thumbnailURL) { return this.http.post(this.path + 'createPlaylist', {playlistName: playlistName, fileNames: fileNames,