@ -83,16 +83,6 @@ db_api.initialize(db, users_db, logger);
subscriptions _api . initialize ( db , users _db , logger , db _api ) ;
categories _api . initialize ( db , users _db , logger , db _api ) ;
async function test ( ) {
const test _cat = await categories _api . categorize ( fs . readJSONSync ( 'video/Claire Lost Her First Tooth!.info.json' ) ) ;
console . log ( test _cat ) ;
}
test ( ) ;
// var GithubContent = require('github-content');
// Set some defaults
db . defaults (
{
@ -184,7 +174,6 @@ const subscription_timeouts = {};
// don't overwrite config if it already happened.. NOT
// let alreadyWritten = db.get('configWriteFlag').value();
let writeConfigMode = process . env . write _ytdl _config ;
var config = null ;
// checks if config exists, if not, a config is auto generated
config _api . configExistsCheck ( ) ;
@ -1221,7 +1210,7 @@ async function downloadFileByURL_exec(url, type, options, sessionID = null) {
} catch ( e ) {
output _json = null ;
}
var modified _file _name = output _json ? output _json [ 'title' ] : null ;
if ( ! output _json ) {
continue ;
}
@ -1250,8 +1239,11 @@ async function downloadFileByURL_exec(url, type, options, sessionID = null) {
if ( ! success ) logger . error ( 'Failed to apply ID3 tag to audio file ' + output _json [ '_filename' ] ) ;
}
const file _path = options . noRelativePath ? path . basename ( full _file _path ) : full _file _path . substring ( fileFolderPath . length , full _file _path . length ) ;
const customPath = options . noRelativePath ? path . dirname ( full _file _path ) . split ( path . sep ) . pop ( ) : null ;
// registers file in DB
file _uid = db _api . registerFileDB ( full _file _path . substring ( fileFolderPath . length , full _file _path . length ) , type , multiUserMode ) ;
file _uid = db _api . registerFileDB ( f ile_path , type , multiUserMode , null , customPath ) ;
if ( file _name ) file _names . push ( file _name ) ;
}
@ -1795,7 +1787,7 @@ app.use(function(req, res, next) {
next ( ) ;
} else if ( req . query . apiKey && config _api . getConfigItem ( 'ytdl_use_api_key' ) && req . query . apiKey === config _api . getConfigItem ( 'ytdl_api_key' ) ) {
next ( ) ;
} else if ( req . path . includes ( '/api/ video/') || req . path . includes ( '/api/audio /') ) {
} else if ( req . path . includes ( '/api/ stream /') ) {
next ( ) ;
} else {
logger . verbose ( ` Rejecting request - invalid API use for endpoint: ${ req . path } . API key received: ${ req . query . apiKey } ` ) ;
@ -1808,15 +1800,14 @@ app.use(compression());
const optionalJwt = 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/audio' ) ||
req . path . includes ( '/api/video' ) ||
req . path . includes ( '/api/stream' ) ||
req . path . includes ( '/api/downloadFile' ) ) ) {
// 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 type = using _body ? req . body . type : req . query . type ;
const file = ! req . query . id ? auth _api . getUserVideo ( uuid , uid , type , true , req . body ) : auth _api . getUserPlaylist ( uuid , req . query . id , null , true ) ;
const file = ! req . query . id ? auth _api . getUserVideo ( uuid , uid , type , true , ! ! req . body ) : auth _api . getUserPlaylist ( uuid , req . query . id , null , true ) ;
const is _shared = file ? file [ 'sharingEnabled' ] : false ;
if ( is _shared ) {
req . can _watch = true ;
@ -2184,6 +2175,16 @@ app.post('/api/createCategory', optionalJwt, async (req, res) => {
} ) ;
} ) ;
app . post ( '/api/deleteCategory' , optionalJwt , async ( req , res ) => {
const category _uid = req . body . category _uid ;
db . get ( 'categories' ) . remove ( { uid : category _uid } ) . write ( ) ;
res . send ( {
success : true
} ) ;
} ) ;
app . post ( '/api/updateCategory' , optionalJwt , async ( req , res ) => {
const category = req . body . category ;
db . get ( 'categories' ) . find ( { uid : category . uid } ) . assign ( category ) . write ( ) ;
@ -2282,10 +2283,17 @@ app.post('/api/deleteSubscriptionFile', optionalJwt, async (req, res) => {
app . post ( '/api/getSubscription' , optionalJwt , async ( req , res ) => {
let subID = req . body . id ;
let subName = req . body . name ; // if included, subID is optional
let user _uid = req . isAuthenticated ( ) ? req . user . uid : null ;
// get sub from db
let subscription = subscriptions _api . getSubscription ( subID , user _uid ) ;
let subscription = null ;
if ( subID ) {
subscription = subscriptions _api . getSubscription ( subID , user _uid )
} else if ( subName ) {
subscription = subscriptions _api . getSubscriptionByName ( subName , user _uid )
}
if ( ! subscription ) {
// failed to get subscription from db, send 400 error
@ -2708,25 +2716,33 @@ app.post('/api/generateNewAPIKey', function (req, res) {
// Streaming API calls
app . get ( '/api/video/:id' , optionalJwt , function ( req , res ) {
app . get ( '/api/stream/:id' , optionalJwt , ( req , res ) => {
const type = req . query . type ;
const ext = type === 'audio' ? '.mp3' : '.mp4' ;
const mimetype = type === 'audio' ? 'audio/mp3' : 'video/mp4' ;
var head ;
let optionalParams = url _api . parse ( req . url , true ) . query ;
let id = decodeURIComponent ( req . params . id ) ;
let file _path = videoFolderPath + id + '.mp4' ;
if ( req . isAuthenticated ( ) || req . can _watch ) {
let file _path = req. query . file _path ? decodeURIComponent ( req . query . file _path ) : 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 + '.mp4' )
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 , 'video' , id + '.mp4' ) ;
file _path = path . join ( usersFileFolder , req . query . uuid ? req . query . uuid : req . user . uid , type , id + ext ) ;
}
} else if ( optionalParams [ 'subName' ] ) {
} 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 + '.mp4' ;
file _path = basePath + optionalParams [ 'subName' ] + '/' + id + ext ;
}
if ( ! file _path ) {
file _path = path . join ( videoFolderPath , id + ext ) ;
}
const stat = fs . statSync ( file _path )
const fileSize = stat . size
const range = req . headers . range
@ -2749,77 +2765,20 @@ app.get('/api/video/:id', optionalJwt, function(req , res){
'Content-Range' : ` bytes ${ start } - ${ end } / ${ fileSize } ` ,
'Accept-Ranges' : 'bytes' ,
'Content-Length' : chunksize ,
'Content-Type' : 'video/mp4' ,
'Content-Type' : mimetype ,
}
res . writeHead ( 206 , head ) ;
file . pipe ( res ) ;
} else {
head = {
'Content-Length' : fileSize ,
'Content-Type' : 'video/mp4' ,
'Content-Type' : mimetype ,
}
res . writeHead ( 200 , head )
fs . createReadStream ( file _path ) . pipe ( res )
}
} ) ;
app . get ( '/api/audio/:id' , optionalJwt , function ( req , res ) {
var head ;
let id = decodeURIComponent ( req . params . id ) ;
let file _path = "audio/" + id + '.mp3' ;
let usersFileFolder = config _api . getConfigItem ( 'ytdl_users_base_path' ) ;
let optionalParams = url _api . parse ( req . url , true ) . query ;
if ( req . isAuthenticated ( ) ) {
if ( optionalParams [ 'subName' ] ) {
const isPlaylist = optionalParams [ 'subPlaylist' ] ;
file _path = path . join ( usersFileFolder , req . user . uid , 'subscriptions' , ( isPlaylist === 'true' ? 'playlists/' : 'channels/' ) , optionalParams [ 'subName' ] , id + '.mp3' )
} else {
let usersFileFolder = config _api . getConfigItem ( 'ytdl_users_base_path' ) ;
file _path = path . join ( usersFileFolder , req . user . uid , 'audio' , id + '.mp3' ) ;
}
} else if ( 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 + '.mp3' ;
}
file _path = file _path . replace ( /\"/g , '\'' ) ;
const stat = fs . statSync ( file _path )
const fileSize = stat . size
const range = req . headers . range
if ( range ) {
const parts = range . replace ( /bytes=/ , "" ) . split ( "-" )
const start = parseInt ( parts [ 0 ] , 10 )
const end = parts [ 1 ]
? parseInt ( parts [ 1 ] , 10 )
: fileSize - 1
const chunksize = ( end - start ) + 1
const file = fs . createReadStream ( file _path , { start , end } ) ;
if ( config _api . descriptors [ id ] ) config _api . descriptors [ id ] . push ( file ) ;
else config _api . descriptors [ id ] = [ file ] ;
file . on ( 'close' , function ( ) {
let index = config _api . descriptors [ id ] . indexOf ( file ) ;
config _api . descriptors [ id ] . splice ( index , 1 ) ;
logger . debug ( 'Successfully closed stream and removed file reference.' ) ;
} ) ;
head = {
'Content-Range' : ` bytes ${ start } - ${ end } / ${ fileSize } ` ,
'Accept-Ranges' : 'bytes' ,
'Content-Length' : chunksize ,
'Content-Type' : 'audio/mp3' ,
}
res . writeHead ( 206 , head ) ;
file . pipe ( res ) ;
} else {
head = {
'Content-Length' : fileSize ,
'Content-Type' : 'audio/mp3' ,
}
res . writeHead ( 200 , head )
fs . createReadStream ( file _path ) . pipe ( res )
}
} ) ;
// Downloads management
app . get ( '/api/downloads' , async ( req , res ) => {