@ -231,7 +231,7 @@ async function runFilesToDBMigration() {
const file _already _in _db = db . get ( 'files.audio' ) . find ( { id : file _obj . id } ) . value ( ) ;
if ( ! file _already _in _db ) {
logger . verbose ( ` Migrating file ${ file _obj . id } ` ) ;
await db _api . registerFileDB ( file _obj . id + '.mp3' , 'audio' ) ;
db _api . registerFileDB ( file _obj . id + '.mp3' , 'audio' ) ;
}
}
@ -240,7 +240,7 @@ async function runFilesToDBMigration() {
const file _already _in _db = db . get ( 'files.video' ) . find ( { id : file _obj . id } ) . value ( ) ;
if ( ! file _already _in _db ) {
logger . verbose ( ` Migrating file ${ file _obj . id } ` ) ;
await db _api . registerFileDB ( file _obj . id + '.mp4' , 'video' ) ;
db _api . registerFileDB ( file _obj . id + '.mp4' , 'video' ) ;
}
}
@ -837,87 +837,6 @@ function getVideoFormatID(name)
}
}
// TODO: add to db_api and support multi-user mode
async function deleteFile ( uid , uuid = null , blacklistMode = false ) {
const file _obj = await db _api . getVideo ( uid , uuid ) ;
const type = file _obj . isAudio ? 'audio' : 'video' ;
const folderPath = path . dirname ( file _obj . path ) ;
const ext = type === 'audio' ? 'mp3' : 'mp4' ;
const name = file _obj . id ;
const filePathNoExtension = utils . removeFileExtension ( file _obj . path ) ;
var jsonPath = ` ${ file _obj . path } .info.json ` ;
var altJSONPath = ` ${ filePathNoExtension } .info.json ` ;
var thumbnailPath = ` ${ filePathNoExtension } .webp ` ;
var altThumbnailPath = ` ${ filePathNoExtension } .jpg ` ;
jsonPath = path . join ( _ _dirname , jsonPath ) ;
altJSONPath = path . join ( _ _dirname , altJSONPath ) ;
let jsonExists = await fs . pathExists ( jsonPath ) ;
let thumbnailExists = await fs . pathExists ( thumbnailPath ) ;
if ( ! jsonExists ) {
if ( await fs . pathExists ( altJSONPath ) ) {
jsonExists = true ;
jsonPath = altJSONPath ;
}
}
if ( ! thumbnailExists ) {
if ( await fs . pathExists ( altThumbnailPath ) ) {
thumbnailExists = true ;
thumbnailPath = altThumbnailPath ;
}
}
let fileExists = await fs . pathExists ( file _obj . path ) ;
if ( config _api . descriptors [ name ] ) {
try {
for ( let i = 0 ; i < config _api . descriptors [ name ] . length ; i ++ ) {
config _api . descriptors [ name ] [ i ] . destroy ( ) ;
}
} catch ( e ) {
}
}
let useYoutubeDLArchive = config _api . getConfigItem ( 'ytdl_use_youtubedl_archive' ) ;
if ( useYoutubeDLArchive ) {
const archive _path = path . join ( archivePath , ` archive_ ${ type } .txt ` ) ;
// get ID from JSON
var jsonobj = await ( type === 'audio' ? utils . getJSONMp3 ( name , folderPath ) : utils . getJSONMp4 ( name , folderPath ) ) ;
let id = null ;
if ( jsonobj ) id = jsonobj . id ;
// use subscriptions API to remove video from the archive file, and write it to the blacklist
if ( await fs . pathExists ( archive _path ) ) {
const line = id ? await subscriptions _api . removeIDFromArchive ( archive _path , id ) : null ;
if ( blacklistMode && line ) await writeToBlacklist ( type , line ) ;
} else {
logger . info ( 'Could not find archive file for audio files. Creating...' ) ;
await fs . close ( await fs . open ( archive _path , 'w' ) ) ;
}
}
if ( jsonExists ) await fs . unlink ( jsonPath ) ;
if ( thumbnailExists ) await fs . unlink ( thumbnailPath ) ;
if ( fileExists ) {
await fs . unlink ( file _obj . path ) ;
if ( await fs . pathExists ( jsonPath ) || await fs . pathExists ( file _obj . path ) ) {
return false ;
} else {
return true ;
}
} else {
// TODO: tell user that the file didn't exist
return true ;
}
}
/ * *
* @ param { 'audio' | 'video' } type
* @ param { string [ ] } fileNames
@ -1036,7 +955,7 @@ async function downloadFileByURL_exec(url, type, options, sessionID = null) {
download [ 'downloading' ] = false ;
download [ 'timestamp_end' ] = Date . now ( ) ;
var file _ uid = null ;
var file _ objs = [ ] ;
let new _date = Date . now ( ) ;
let difference = ( new _date - date ) / 1000 ;
logger . debug ( ` ${ is _audio ? 'Audio' : 'Video' } download delay: ${ difference } seconds. ` ) ;
@ -1108,9 +1027,12 @@ async function downloadFileByURL_exec(url, type, options, sessionID = null) {
}
// registers file in DB
file _uid = db _api . registerFileDB ( file _path , type , multiUserMode , null , customPath , category , options . cropFileSettings ) ;
const file _obj = db _api . registerFileDB ( file _path , type , multiUserMode , null , customPath , category , options . cropFileSettings ) ;
// TODO: remove the following line
if ( file _name ) file _names . push ( file _name ) ;
file _objs . push ( file _obj ) ;
}
let is _playlist = file _names . length > 1 ;
@ -1126,12 +1048,22 @@ async function downloadFileByURL_exec(url, type, options, sessionID = null) {
download [ 'fileNames' ] = is _playlist ? file _names : [ full _file _path ]
updateDownloads ( ) ;
var videopathEncoded = encodeURIComponent ( file _names [ 0 ] ) ;
let container = null ;
if ( file _objs . length > 1 ) {
// create playlist
const playlist _name = file _objs . map ( file _obj => file _obj . title ) . join ( ', ' ) ;
const duration = file _objs . reduce ( ( a , b ) => a + utils . durationStringToNumber ( b . duration ) , 0 ) ;
container = await db _api . createPlaylist ( playlist _name , file _objs . map ( file _obj => file _obj . uid ) , type , file _objs [ 0 ] [ 'thumbnailURL' ] , options . user ) ;
} else if ( file _objs . length === 1 ) {
container = file _objs [ 0 ] ;
} else {
logger . error ( 'Downloaded file failed to result in metadata object.' ) ;
}
resolve ( {
[ ( type === 'audio' ) ? 'audiopathEncoded' : 'videopathEncoded' ] : videopathEncoded ,
file _names : is _playlist ? file _names : null ,
uid : file _uid
file _uids : file _objs . map ( file _obj => file _obj . uid ) ,
container : container
} ) ;
}
} ) ;
@ -1260,7 +1192,7 @@ async function downloadFileByURL_normal(url, type, options, sessionID = null) {
videopathEncoded = encodeURIComponent ( utils . removeFileExtension ( base _file _name ) ) ;
resolve ( {
[ is _audio ? 'audiopathEncoded' : 'videopathEncoded' ] : videopathEncoded ,
encodedPath : videopathEncoded ,
file _names : /*is_playlist ? file_names :*/ null , // playlist support is not ready
uid : file _uid
} ) ;
@ -1727,18 +1659,18 @@ app.use(function(req, res, next) {
app . use ( compression ( ) ) ;
const optionalJwt = function ( req , res , next ) {
const optionalJwt = async function ( req , res , next ) {
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' ) ||
req . path . includes ( '/api/stream' ) ||
req . path . includes ( '/api/getPlaylist' ) ||
req . path . includes ( '/api/downloadFile ') ) ) {
req . path . includes ( '/api/downloadFile FromServer ') ) ) {
// check if shared video
const using _body = req . body && req . body . uuid ;
const uuid = using _body ? req . body . uuid : req . query . uuid ;
const uid = using _body ? req . body . uid : req . query . uid ;
const playlist _id = using _body ? req . body . playlist _id : req . query . playlist _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 , true ) : await db _api . getPlaylist ( playlist _id , uuid , true ) ;
if ( file ) {
req . can _watch = true ;
return next ( ) ;
@ -1783,38 +1715,10 @@ app.post('/api/restartServer', optionalJwt, (req, res) => {
res . send ( { success : true } ) ;
} ) ;
app . post ( '/api/tomp3' , optionalJwt , async function ( req , res ) {
var url = req . body . url ;
var options = {
customArgs : req . body . customArgs ,
customOutput : req . body . customOutput ,
maxBitrate : req . body . maxBitrate ,
customQualityConfiguration : req . body . customQualityConfiguration ,
youtubeUsername : req . body . youtubeUsername ,
youtubePassword : req . body . youtubePassword ,
ui _uid : req . body . ui _uid ,
user : req . isAuthenticated ( ) ? req . user . uid : null
}
const safeDownloadOverride = config _api . getConfigItem ( 'ytdl_safe_download_override' ) || config _api . globalArgsRequiresSafeDownload ( ) ;
if ( safeDownloadOverride ) logger . verbose ( 'Download is running with the safe download override.' ) ;
const is _playlist = url . includes ( 'playlist' ) ;
let result _obj = null ;
if ( true || safeDownloadOverride || is _playlist || options . customQualityConfiguration || options . customArgs || options . maxBitrate )
result _obj = await downloadFileByURL _exec ( url , 'audio' , options , req . query . sessionID ) ;
else
result _obj = await downloadFileByURL _normal ( url , 'audio' , options , req . query . sessionID ) ;
if ( result _obj ) {
res . send ( result _obj ) ;
} else {
res . sendStatus ( 500 ) ;
}
} ) ;
app . post ( '/api/tomp4' , optionalJwt , async function ( req , res ) {
app . post ( '/api/downloadFile' , optionalJwt , async function ( req , res ) {
req . setTimeout ( 0 ) ; // remove timeout in case of long videos
var url = req . body . url ;
const url = req . body . url ;
const type = req . body . type ;
var options = {
customArgs : req . body . customArgs ,
customOutput : req . body . customOutput ,
@ -1833,7 +1737,7 @@ app.post('/api/tomp4', optionalJwt, async function(req, res) {
let result _obj = null ;
if ( true || safeDownloadOverride || is _playlist || options . customQualityConfiguration || options . customArgs || options . selectedHeight || ! url . includes ( 'youtu' ) )
result _obj = await downloadFileByURL _exec ( url , 'video' , options , req . query . sessionID ) ;
result _obj = await downloadFileByURL _exec ( url , type , options , req . query . sessionID ) ;
else
result _obj = await downloadFileByURL _normal ( url , 'video' , options , req . query . sessionID ) ;
if ( result _obj ) {
@ -1936,43 +1840,22 @@ app.post('/api/getAllFiles', optionalJwt, async function (req, res) {
// these are returned
let files = null ;
let playlists = null ;
const uuid = req . isAuthenticated ( ) ? req . user . uid : null ;
let subscriptions = config _api . getConfigItem ( 'ytdl_allow_subscriptions' ) ? ( subscriptions _api . getSubscriptions ( req . isAuthenticated ( ) ? req . user . uid : null ) ) : [ ] ;
// get basic info depending on multi-user mode being enabled
if ( req. isAuthenticated ( ) ) {
if ( uuid ) {
files = auth _api . getUserVideos ( req . user . uid ) ;
playlists = auth _api . getUserPlaylists ( req . user . uid , files ) ;
} else {
files = db . get ( 'files' ) . value ( ) ;
playlists = JSON . parse ( JSON . stringify ( db . get ( 'playlists' ) . value ( ) ) ) ;
const categories = db . get ( 'categories' ) . value ( ) ;
if ( categories ) {
categories . forEach ( category => {
const audio _files = files && files . filter ( file => file . category && file . category . uid === category . uid && file . isAudio ) ;
const video _files = files && files . filter ( file => file . category && file . category . uid === category . uid && ! file . isAudio ) ;
if ( audio _files && audio _files . length > 0 ) {
playlists . push ( {
name : category [ 'name' ] ,
thumbnailURL : audio _files [ 0 ] . thumbnailURL ,
thumbnailPath : audio _files [ 0 ] . thumbnailPath ,
fileNames : audio _files . map ( file => file . id ) ,
type : 'audio' ,
auto : true
} ) ;
}
if ( video _files && video _files . length > 0 ) {
playlists . push ( {
name : category [ 'name' ] ,
thumbnailURL : video _files [ 0 ] . thumbnailURL ,
thumbnailPath : video _files [ 0 ] . thumbnailPath ,
fileNames : video _files . map ( file => file . id ) ,
type : 'video' ,
auto : true
} ) ;
}
} ) ;
}
}
const categories = categories _api . getCategoriesAsPlaylists ( files ) ;
if ( categories ) {
playlists = playlists . concat ( categories ) ;
}
// loop through subscriptions and add videos
@ -2439,26 +2322,8 @@ app.post('/api/createPlaylist', optionalJwt, async (req, res) => {
let uids = req . body . uids ;
let type = req . body . type ;
let thumbnailURL = req . body . thumbnailURL ;
let duration = req . body . duration ;
let new _playlist = {
name : playlistName ,
uids : uids ,
id : shortid . generate ( ) ,
thumbnailURL : thumbnailURL ,
type : type ,
registered : Date . now ( ) ,
duration : duration
} ;
if ( req . isAuthenticated ( ) ) {
auth _api . addPlaylist ( req . user . uid , new _playlist , type ) ;
} else {
db . get ( ` playlists ` )
. push ( new _playlist )
. write ( ) ;
}
const new _playlist = await db _api . createPlaylist ( playlistName , uids , type , thumbnailURL , req . isAuthenticated ( ) ? req . user . uid : null ) ;
res . send ( {
new _playlist : new _playlist ,
@ -2517,7 +2382,7 @@ app.post('/api/updatePlaylistFiles', optionalJwt, async (req, res) => {
app . post ( '/api/updatePlaylist' , optionalJwt , async ( req , res ) => {
let playlist = req . body . playlist ;
let success = db _api . updatePlaylist ( playlist , req . user && req . user . uid ) ;
let success = await db _api . updatePlaylist ( playlist , req . user && req . user . uid ) ;
res . send ( {
success : success
} ) ;
@ -2551,20 +2416,14 @@ app.post('/api/deletePlaylist', optionalJwt, async (req, res) => {
app . post ( '/api/deleteFile' , optionalJwt , async ( req , res ) => {
const uid = req . body . uid ;
const blacklistMode = req . body . blacklistMode ;
if ( req . isAuthenticated ( ) ) {
let success = await auth _api . deleteUserFile ( req . user . uid , uid , blacklistMode ) ;
res . send ( success ) ;
return ;
}
const uuid = req . isAuthenticated ( ) ? req . user . uid : null ;
let wasDeleted = false ;
wasDeleted = await deleteFile ( uid , null , blacklistMode ) ;
db . get ( 'files' ) . remove ( { uid : uid } ) . write ( ) ;
wasDeleted = await db _api . deleteFile ( uid , uuid , blacklistMode ) ;
res . send ( wasDeleted ) ;
} ) ;
app . post ( '/api/downloadFile ', optionalJwt , async ( req , res ) => {
app . post ( '/api/downloadFile FromServer ', optionalJwt , async ( req , res ) => {
let uid = req . body . uid ;
let uuid = req . body . uuid ;
let playlist _id = req . body . playlist _id ;