mirror of
https://github.com/Tzahi12345/YoutubeDL-Material.git
synced 2026-03-07 12:00:01 +03:00
added API endpoint to get file from database
video/audio files can now be retrieved by just uid, allowing for easy sharing added API endpoints for sharing/unsharing a video (no UI support yet)
This commit is contained in:
108
backend/app.js
108
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;
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
<div style="padding:5px">
|
||||
<div style="height: 52px;">
|
||||
<div>
|
||||
<b><a class="file-link" href="javascript:void(0)" (click)="!isPlaylist ? mainComponent.goToFile(name, isAudio) : mainComponent.goToPlaylist(name, type)">{{title}}</a></b>
|
||||
<b><a class="file-link" href="javascript:void(0)" (click)="!isPlaylist ? mainComponent.goToFile(name, isAudio, uid) : mainComponent.goToPlaylist(name, type)">{{title}}</a></b>
|
||||
</div>
|
||||
<span class="max-two-lines"><ng-container i18n="File or playlist ID">ID:</ng-container> {{name}}</span>
|
||||
<div *ngIf="isPlaylist"><ng-container i18n="Playlist video count">Count:</ng-container> {{count}}</div>
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
<div *ngIf="playlist.length > 0">
|
||||
<div *ngIf="playlist.length > 0 && show_player">
|
||||
<div [ngClass]="(type === 'audio') ? null : 'container-video'" class="container">
|
||||
<div style="max-width: 100%; margin-left: 0px;" class="row">
|
||||
<div [ngClass]="(type === 'audio') ? 'my-2 px-1' : 'video-col'" class="col">
|
||||
|
||||
@@ -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;
|
||||
|
||||
|
||||
@@ -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,
|
||||
|
||||
Reference in New Issue
Block a user