@ -3,7 +3,8 @@ const assert = require('assert');
const low = require ( 'lowdb' )
const winston = require ( 'winston' ) ;
const path = require ( 'path' ) ;
const util = require ( 'util' ) ;
const exec = util . promisify ( require ( 'child_process' ) . exec ) ;
const FileSync = require ( 'lowdb/adapters/FileSync' ) ;
@ -41,11 +42,13 @@ const subscriptions_api = require('../subscriptions');
const archive _api = require ( '../archive' ) ;
const categories _api = require ( '../categories' ) ;
const files _api = require ( '../files' ) ;
const youtubedl _api = require ( '../youtube-dl' ) ;
const config _api = require ( '../config' ) ;
const fs = require ( 'fs-extra' ) ;
const { uuid } = require ( 'uuidv4' ) ;
const NodeID3 = require ( 'node-id3' ) ;
db _api . initialize ( db , users _db );
db _api . initialize ( db , users _db , 'local_db_test.json' );
const sample _video _json = {
id : "Sample Video" ,
@ -68,9 +71,9 @@ const sample_video_json = {
}
describe ( 'Database' , async function ( ) {
describe ('Import' , async function ( ) {
describe .skip ('Import' , async function ( ) {
// it('Migrate', async function() {
// await db_api.connectToDB();
// // await db_api.connectToDB();
// await db_api.removeAllRecords();
// const success = await db_api.importJSONToDB(db.value(), users_db.value());
// assert(success);
@ -86,7 +89,7 @@ describe('Database', async function() {
} ) ;
it ( 'Transfer to local' , async function ( ) {
await db _api . connectToDB ( ) ;
// await db_api.connectToDB();
await db _api . removeAllRecords ( 'test' ) ;
await db _api . insertRecordIntoTable ( 'test' , { test : 'test' } ) ;
@ -114,7 +117,8 @@ describe('Database', async function() {
for ( const local _db _mode of local _db _modes ) {
let use _local _db = local _db _mode ;
describe ( ` Use local DB - ${ use _local _db } ` , async function ( ) {
const describe _skippable = use _local _db ? describe : describe . skip ;
describe _skippable ( ` Use local DB - ${ use _local _db } ` , async function ( ) {
beforeEach ( async function ( ) {
if ( ! use _local _db ) {
this . timeout ( 120000 ) ;
@ -167,7 +171,7 @@ describe('Database', async function() {
] ;
await db _api . insertRecordsIntoTable ( 'test' , test _duplicates ) ;
const duplicates = await db _api . findDuplicatesByKey ( 'test' , 'test' ) ;
console. log ( duplicates ) ;
assert( duplicates && duplicates . length === 2 && duplicates [ 0 ] [ 'key' ] === '2' && duplicates [ 1 ] [ 'key' ] === '4' )
} ) ;
it ( 'Update record' , async function ( ) {
@ -279,7 +283,7 @@ describe('Database', async function() {
assert ( stats ) ;
} ) ;
it ('Query speed' , async function ( ) {
it .skip ('Query speed' , async function ( ) {
this . timeout ( 120000 ) ;
const NUM _RECORDS _TO _ADD = 300004 ; // max batch ops is 1000
const test _records = [ ] ;
@ -337,12 +341,13 @@ describe('Database', async function() {
} ) ;
describe ( 'Multi User' , async function ( ) {
this . timeout ( 120000 ) ;
const user _to _test = 'test_user' ;
const user _password = 'test_pass' ;
const sub _to _test = '' ;
const playlist _to _test = '' ;
beforeEach ( async function ( ) {
await db _api . connectToDB ( ) ;
// await db_api.connectToDB();
await auth _api . deleteUser ( user _to _test ) ;
} ) ;
describe ( 'Basic' , function ( ) {
@ -369,17 +374,17 @@ describe('Multi User', async function() {
it ( 'Video access - disallowed' , async function ( ) {
await db _api . setVideoProperty ( video _to _test , { sharingEnabled : false } ) ;
const video _obj = auth _api . getUserVideo ( user _to _test , video _to _test , true ) ;
const video _obj = await auth _api . getUserVideo ( user _to _test , video _to _test , true ) ;
assert ( ! video _obj ) ;
} ) ;
it ( 'Video access - allowed' , async function ( ) {
await db _api . setVideoProperty ( video _to _test , { sharingEnabled : true } , user _to _test ) ;
const video _obj = auth _api . getUserVideo ( user _to _test , video _to _test , true ) ;
const video _obj = await auth _api . getUserVideo ( user _to _test , video _to _test , true ) ;
assert ( video _obj ) ;
} ) ;
} ) ;
describe ('Zip generators' , function ( ) {
describe .skip ('Zip generators' , function ( ) {
it ( 'Playlist zip generator' , async function ( ) {
const playlist = await files _api . getPlaylist ( playlist _to _test , user _to _test ) ;
assert ( playlist ) ;
@ -435,35 +440,50 @@ describe('Multi User', async function() {
describe ( 'Downloader' , function ( ) {
const downloader _api = require ( '../downloader' ) ;
const url = 'https://www.youtube.com/watch?v= dQw4w9WgXcQ ';
const url = 'https://www.youtube.com/watch?v= hpigjnKl7nI ';
const sub _id = 'dc834388-3454-41bf-a618-e11cb8c7de1c' ;
const options = {
ui _uid : uuid ( ) ,
user : 'admin'
ui _uid : uuid ( )
}
before ( async function ( ) {
const update _available = await youtubedl _api . checkForYoutubeDLUpdate ( ) ;
if ( update _available ) await youtubedl _api . updateYoutubeDL ( update _available ) ;
config _api . setConfigItem ( 'ytdl_max_concurrent_downloads' , 0 ) ;
} ) ;
beforeEach ( async function ( ) {
await db _api . connectToDB ( ) ;
// await db_api.connectToDB();
await db _api . removeAllRecords ( 'download_queue' ) ;
} ) ;
it ( 'Get file info' , async function ( ) {
this . timeout ( 300000 ) ;
const info = await downloader _api . getVideoInfoByURL ( url ) ;
assert ( ! ! info ) ;
assert ( ! ! info && info . length > 0 ) ;
} ) ;
it ( 'Download file' , async function ( ) {
this . timeout ( 300000 ) ;
this . timeout ( 300000 ) ;
await downloader _api . setupDownloads ( ) ;
const args = await downloader _api . generateArgs ( url , 'video' , options , null , true ) ;
const [ info ] = await downloader _api . getVideoInfoByURL ( url , args ) ;
if ( fs . existsSync ( info [ '_filename' ] ) ) fs . unlinkSync ( info [ '_filename' ] ) ;
const returned _download = await downloader _api . createDownload ( url , 'video' , options ) ;
console . log ( returned _download ) ;
await utils . wait ( 20000 ) ;
assert ( returned _download ) ;
const custom _download _method = async ( url , args , options , callback ) => {
fs . writeJSONSync ( utils . getTrueFileName ( info [ '_filename' ] , 'video' , '.info.json' ) , info ) ;
await generateEmptyVideoFile ( info [ '_filename' ] ) ;
return await callback ( null , [ JSON . stringify ( info ) ] ) ;
}
const success = await downloader _api . downloadQueuedFile ( returned _download [ 'uid' ] , custom _download _method ) ;
assert ( success ) ;
} ) ;
it ( 'Tag file' , async function ( ) {
const audio _path = './test/sample.mp3' ;
const sample _json = fs . readJSONSync ( './test/sample.info.json' ) ;
const success = await generateEmptyAudioFile ( 'test/sample_mp3.mp3' ) ;
const audio _path = './test/sample_mp3.mp3' ;
const sample _json = fs . readJSONSync ( './test/sample_mp3.info.json' ) ;
const tags = {
title : sample _json [ 'title' ] ,
artist : sample _json [ 'artist' ] ? sample _json [ 'artist' ] : sample _json [ 'uploader' ] ,
@ -471,14 +491,13 @@ describe('Downloader', function() {
}
NodeID3 . write ( tags , audio _path ) ;
const written _tags = NodeID3 . read ( audio _path ) ;
assert ( written_tags [ 'raw' ] [ 'TRCK' ] === '27' ) ;
assert ( success && written_tags [ 'raw' ] [ 'TRCK' ] === '27' ) ;
} ) ;
it ( 'Queue file' , async function ( ) {
this . timeout ( 300000 ) ;
const returned _download = await downloader _api . createDownload ( url , 'video' , options ) ;
console . log ( returned _download ) ;
await utils . wait ( 20000 ) ;
const returned _download = await downloader _api . createDownload ( url , 'video' , options , null , null , null , null , true ) ;
assert ( returned _download ) ;
} ) ;
it ( 'Pause file' , async function ( ) {
@ -493,7 +512,7 @@ describe('Downloader', function() {
assert ( args . length > 0 ) ;
} ) ;
it ('Generate args - subscription' , async function ( ) {
it .skip ('Generate args - subscription' , async function ( ) {
const sub = await subscriptions _api . getSubscription ( sub _id ) ;
const sub _options = subscriptions _api . generateOptionsForSubscriptionDownload ( sub , 'admin' ) ;
const args _normal = await downloader _api . generateArgs ( url , 'video' , options ) ;
@ -506,7 +525,7 @@ describe('Downloader', function() {
if ( fs . existsSync ( nfo _file _path ) ) {
fs . unlinkSync ( nfo _file _path ) ;
}
const sample _json = fs . readJSONSync ( './test/sample .info.json') ;
const sample _json = fs . readJSONSync ( './test/sample _mp4 .info.json') ;
downloader _api . generateNFOFile ( sample _json , nfo _file _path ) ;
assert ( fs . existsSync ( nfo _file _path ) , true ) ;
fs . unlinkSync ( nfo _file _path ) ;
@ -534,10 +553,18 @@ describe('Downloader', function() {
describe ( 'Twitch' , async function ( ) {
const twitch _api = require ( '../twitch' ) ;
const example _vod = '1710641401' ;
it ( 'Download VOD' , async function ( ) {
it ( 'Download VOD chat' , async function ( ) {
this . timeout ( 300000 ) ;
if ( ! fs . existsSync ( 'TwitchDownloaderCLI' ) ) {
try {
await exec ( 'sh ../docker-utils/fetch-twitchdownloader.sh' ) ;
fs . copyFileSync ( '../docker-utils/TwitchDownloaderCLI' , 'TwitchDownloaderCLI' ) ;
} catch ( e ) {
logger . info ( 'TwitchDownloaderCLI fetch failed, file may exist regardless.' ) ;
}
}
const sample _path = path . join ( 'test' , 'sample.twitch_chat.json' ) ;
if ( fs . existsSync ( sample _path ) ) fs . unlinkSync ( sample _path ) ;
this . timeout ( 300000 ) ;
await twitch _api . downloadTwitchChatByVODID ( example _vod , 'sample' , null , null , null , './test' ) ;
assert ( fs . existsSync ( sample _path ) ) ;
@ -550,7 +577,7 @@ describe('Downloader', function() {
describe ( 'Tasks' , function ( ) {
const tasks _api = require ( '../tasks' ) ;
beforeEach ( async function ( ) {
await db _api . connectToDB ( ) ;
// await db_api.connectToDB();
await db _api . removeAllRecords ( 'tasks' ) ;
const dummy _task = {
@ -569,7 +596,7 @@ describe('Tasks', function() {
await tasks _api . executeTask ( 'backup_local_db' ) ;
const backups _new = await utils . recFindByExt ( 'appdata' , 'bak' ) ;
const new _length = backups _new . length ;
assert ( original _length , new _length - 1 ) ;
assert ( original _length === new _length - 1 ) ;
} ) ;
it ( 'Check for missing files' , async function ( ) {
@ -579,7 +606,7 @@ describe('Tasks', function() {
await db _api . insertRecordIntoTable ( 'files' , test _missing _file ) ;
await tasks _api . executeTask ( 'missing_files_check' ) ;
const missing _file _db _record = await db _api . getRecord ( 'files' , { uid : 'test' } ) ;
assert ( ! missing _file _db _record , true );
assert ( ! missing _file _db _record );
} ) ;
it ( 'Check for duplicate files' , async function ( ) {
@ -599,27 +626,29 @@ describe('Tasks', function() {
await tasks _api . executeTask ( 'duplicate_files_check' ) ;
const duplicated _record _count = await db _api . getRecords ( 'files' , { path : 'test/missing_file.mp4' } , true ) ;
assert ( duplicated _record _count == 1 , true ) ;
assert ( duplicated _record _count == = 1 ) ;
} ) ;
it ( 'Import unregistered files' , async function ( ) {
this . timeout ( 300000 ) ;
const success = await generateEmptyVideoFile ( 'test/sample_mp4.mp4' ) ;
// pre-test cleanup
await db _api . removeAllRecords ( 'files' , { title : 'Sample File' } ) ;
if ( fs . existsSync ( 'video/sample .info.json') ) fs . unlinkSync ( 'video/sample .info.json') ;
if ( fs . existsSync ( 'video/sample .mp4') ) fs . unlinkSync ( 'video/sample .mp4') ;
if ( fs . existsSync ( 'video/sample _mp4 .info.json') ) fs . unlinkSync ( 'video/sample _mp4 .info.json') ;
if ( fs . existsSync ( 'video/sample _mp4 .mp4') ) fs . unlinkSync ( 'video/sample _mp4 .mp4') ;
// copies in files
fs . copyFileSync ( 'test/sample .info.json', 'video/sample .info.json') ;
fs . copyFileSync ( 'test/sample .mp4', 'video/sample .mp4') ;
fs . copyFileSync ( 'test/sample _mp4 .info.json', 'video/sample _mp4 .info.json') ;
fs . copyFileSync ( 'test/sample _mp4 .mp4', 'video/sample _mp4 .mp4') ;
await tasks _api . executeTask ( 'missing_db_records' ) ;
const imported _file = await db _api . getRecord ( 'files' , { title : 'Sample File' } ) ;
assert ( ! ! imported _fil e === tru e) ;
assert ( success && ! ! imported _fil e) ;
// post-test cleanup
if ( fs . existsSync ( 'video/sample .info.json') ) fs . unlinkSync ( 'video/sample .info.json') ;
if ( fs . existsSync ( 'video/sample .mp4') ) fs . unlinkSync ( 'video/sample .mp4') ;
if ( fs . existsSync ( 'video/sample _mp4 .info.json') ) fs . unlinkSync ( 'video/sample _mp4 .info.json') ;
if ( fs . existsSync ( 'video/sample _mp4 .mp4') ) fs . unlinkSync ( 'video/sample _mp4 .mp4') ;
} ) ;
it ( 'Schedule and cancel task' , async function ( ) {
@ -659,12 +688,12 @@ describe('Tasks', function() {
describe ( 'Archive' , async function ( ) {
beforeEach ( async function ( ) {
await db _api . connectToDB ( ) ;
await db _api . removeAllRecords ( 'archives' , { user _uid : 'test_user' } );
// await db_api.connectToDB();
await db _api . removeAllRecords ( 'archives' );
} ) ;
afterEach ( async function ( ) {
await db _api . removeAllRecords ( 'archives' , { user _uid : 'test_user' } );
await db _api . removeAllRecords ( 'archives' );
} ) ;
it ( 'Import archive' , async function ( ) {
@ -678,7 +707,6 @@ describe('Archive', async function() {
const count = await archive _api . importArchiveFile ( archive _text , 'video' , 'test_user' , 'test_sub' ) ;
assert ( count === 4 )
const archive _items = await db _api . getRecords ( 'archives' , { user _uid : 'test_user' , sub _id : 'test_sub' } ) ;
console . log ( archive _items ) ;
assert ( archive _items . length === 4 ) ;
assert ( archive _items . filter ( archive _item => archive _item . extractor === 'testextractor2' ) . length === 1 ) ;
assert ( archive _items . filter ( archive _item => archive _item . extractor === 'testextractor1' ) . length === 3 ) ;
@ -709,9 +737,9 @@ describe('Archive', async function() {
} ) ;
it ( 'Remove from archive' , async function ( ) {
await archive _api . addToArchive ( 'testextractor1' , 'testing1' , 'video' , 'test_ user') ;
await archive _api . addToArchive ( 'testextractor2' , 'testing1' , 'video' , 'test_ user') ;
await archive _api . addToArchive ( 'testextractor2' , 'testing2' , 'video' , 'test_ user') ;
await archive _api . addToArchive ( 'testextractor1' , 'testing1' , 'video' , 'test_ title', 'test_ user') ;
await archive _api . addToArchive ( 'testextractor2' , 'testing1' , 'video' , 'test_ title', 'test_ user') ;
await archive _api . addToArchive ( 'testextractor2' , 'testing2' , 'video' , 'test_ title', 'test_ user') ;
const success = await archive _api . removeFromArchive ( 'testextractor2' , 'testing1' , 'video' , 'test_user' ) ;
assert ( success ) ;
@ -757,7 +785,7 @@ describe('Utils', async function() {
describe ( 'Categories' , async function ( ) {
beforeEach ( async function ( ) {
await db _api . connectToDB ( ) ;
// await db_api.connectToDB();
const new _category = {
name : 'test_category' ,
uid : uuid ( ) ,
@ -805,7 +833,6 @@ describe('Categories', async function() {
} ) ;
const category = await categories _api . categorize ( [ sample _video _json ] ) ;
console . log ( category ) ;
assert ( category && category . name === 'test_category' ) ;
} ) ;
@ -858,4 +885,14 @@ describe('Categories', async function() {
const category = await categories _api . categorize ( [ sample _video _json ] ) ;
assert ( category ) ;
} ) ;
} ) ;
} ) ;
const generateEmptyVideoFile = async ( file _path ) => {
if ( fs . existsSync ( file _path ) ) fs . unlinkSync ( file _path ) ;
return await exec ( ` ffmpeg -t 1 -f lavfi -i color=c=black:s=640x480 -c:v libx264 -tune stillimage -pix_fmt yuv420p " ${ file _path } " ` ) ;
}
const generateEmptyAudioFile = async ( file _path ) => {
if ( fs . existsSync ( file _path ) ) fs . unlinkSync ( file _path ) ;
return await exec ( ` ffmpeg -f lavfi -i anullsrc=r=44100:cl=mono -t 1 -q:a 9 -acodec libmp3lame ${ file _path } ` ) ;
}