491 lines
14 KiB
JavaScript
491 lines
14 KiB
JavaScript
import 'dotenv/config'
|
|
import Voddo from '../src/Voddo.js'
|
|
import chai, { expect } from 'chai'
|
|
import sinon from 'sinon'
|
|
import YoutubeDlWrap from 'youtube-dl-wrap'
|
|
import {
|
|
AbortController
|
|
} from "node-abort-controller";
|
|
import {
|
|
EventEmitter
|
|
} from 'events'
|
|
import debugFactory from 'debug'
|
|
import { join, dirname } from 'path';
|
|
import { fileURLToPath } from 'url';
|
|
import sinonChai from 'sinon-chai'
|
|
import sinonTest from "sinon-test";
|
|
import path from 'path'
|
|
|
|
chai.use(sinonChai);
|
|
|
|
const test = sinonTest(sinon, {
|
|
toFake: ["setTimeout", "setInterval"],
|
|
shouldAdvanceTime: false
|
|
});
|
|
const debug = debugFactory('voddo')
|
|
const __dirname = dirname(fileURLToPath(import.meta.url));
|
|
|
|
|
|
|
|
|
|
|
|
describe('Voddo', function() {
|
|
|
|
|
|
describe('groupStreamSegments', function () {
|
|
it('should separate two stream data objects', function () {
|
|
const fixture = [{
|
|
"startTime": 1675386000000,
|
|
"file": "projektmelody 2023-02-02 17_00-projektmelody.mp4",
|
|
"size": 550799038,
|
|
"endTime": 1675391400000,
|
|
}, {
|
|
"startTime": 1675391405000,
|
|
"file": "projektmelody 2023-02-02 18_30-projektmelody.mp4",
|
|
"size": 6556534941,
|
|
"endTime": 1675396800000
|
|
}, {
|
|
"startTime": 1675368000000,
|
|
"file": "projektmelody 2023-02-02 12_00-projektmelody.mp4",
|
|
"size": 6556534941,
|
|
"endTime": 1675378800000
|
|
}]
|
|
|
|
const streams = Voddo.groupStreamSegments(fixture)
|
|
expect(streams).to.deep.equal([
|
|
[
|
|
{
|
|
"startTime": 1675368000000,
|
|
"file": "projektmelody 2023-02-02 12_00-projektmelody.mp4",
|
|
"size": 6556534941,
|
|
"endTime": 1675378800000
|
|
}
|
|
],
|
|
[
|
|
{
|
|
"startTime": 1675386000000,
|
|
"file": "projektmelody 2023-02-02 17_00-projektmelody.mp4",
|
|
"size": 550799038,
|
|
"endTime": 1675391400000,
|
|
}, {
|
|
"startTime": 1675391405000,
|
|
"file": "projektmelody 2023-02-02 18_30-projektmelody.mp4",
|
|
"size": 6556534941,
|
|
"endTime": 1675396800000
|
|
}
|
|
]
|
|
])
|
|
})
|
|
})
|
|
|
|
|
|
// let clock;
|
|
|
|
// beforeEach(function() {
|
|
// clock = sinon.useFakeTimers({
|
|
// toFake: ["setTimeout", "setInterval"],
|
|
// shouldAdvanceTime: false
|
|
// });
|
|
// })
|
|
|
|
// afterEach(() => {
|
|
// sinon.restore()
|
|
// })
|
|
|
|
|
|
|
|
// Something faulty with Voddo or sinon or mocha, not sure.
|
|
// When running by itself, test succeeds. When running with 'should start and stop stream download',
|
|
// voddo.stats gets set to whatever that test sets it to. So bizarre, it's like the same Voddo class instance
|
|
// exists in two different tests even though they are named differently.
|
|
// Even though they are not in global scope. Even though each was called with `new Voddo(...)`
|
|
// Doesn't matter if I wrap both in sinon-test. Same leaky problem.
|
|
// Doesn't matter if I sinon.restore() afterEach. Same leaky problem.
|
|
// Doesn't matter if I manually set up a sinon sandbox. Same leaky problem.
|
|
// Fuck event emitters. I love their utility but I don't know how the fuck they are supposed to be tested.
|
|
// Solution might just call for a rewrite of Voddo, or perhaps deleting Voddo in favor of Capture
|
|
// For now, I'm moving forward because Voddo works even though this test does not.
|
|
describe('getRecordedSegments', function() {
|
|
xit('should populate it\'s log if log is empty', async function () {
|
|
const voddo = new Voddo({
|
|
url: 'https://example.com',
|
|
cwd: join(__dirname, 'fixtures')
|
|
})
|
|
const streams = await voddo.getRecordedSegments()
|
|
console.log(streams)
|
|
expect(streams.length).to.equal(3)
|
|
expect(streams[0]).to.have.property('startTime')
|
|
expect(streams[0]).to.have.property('file')
|
|
expect(streams[0]).to.have.property('size')
|
|
})
|
|
xit('should use Voddo\'s stats history to get filenames of only the most recent stream', async function() {
|
|
const sb = sinon.createSandbox()
|
|
const viddo = new Voddo({
|
|
url: 'https://example.com',
|
|
cwd: '~/Downloads'
|
|
})
|
|
sb.stub(viddo, 'stats').value({
|
|
segments: [{
|
|
startTime: 1674147647000,
|
|
size: 192627,
|
|
file: 'projektmelody 2023-01-19 17_00-projektmelody.mp4'
|
|
}, {
|
|
startTime: 1674151247000,
|
|
size: 192627,
|
|
file: 'projektmelody 2023-01-19 18_00-projektmelody.mp4'
|
|
}, {
|
|
startTime: 1674154847000,
|
|
size: 192627,
|
|
file: 'projektmelody 2023-01-19 19_00-projektmelody.mp4'
|
|
}, {
|
|
file: 'projektmelody 2023-01-20 20_10-projektmelody.mp4',
|
|
size: 192627,
|
|
startTime: 1674245400000,
|
|
}, {
|
|
file: 'projektmelody 2023-01-20 21_10-projektmelody.mp4',
|
|
size: 192627,
|
|
startTime: 1674249000000,
|
|
}, {
|
|
file: 'projektmelody 2023-01-20 22_10-projektmelody.mp4',
|
|
size: 192627,
|
|
startTime: 1674252600000,
|
|
}]
|
|
})
|
|
|
|
const filenames = await viddo.getRecordedSegments()
|
|
sb.restore()
|
|
expect(filenames).to.have.lengthOf(3)
|
|
expect(filenames).to.deep.equal([{
|
|
file: 'projektmelody 2023-01-20 20_10-projektmelody.mp4',
|
|
size: 192627,
|
|
startTime: 1674245400000,
|
|
}, {
|
|
file: 'projektmelody 2023-01-20 21_10-projektmelody.mp4',
|
|
size: 192627,
|
|
startTime: 1674249000000,
|
|
}, {
|
|
file: 'projektmelody 2023-01-20 22_10-projektmelody.mp4',
|
|
size: 192627,
|
|
startTime: 1674252600000,
|
|
}])
|
|
})
|
|
})
|
|
|
|
|
|
xit('should keep a log of the files downloaded', function(done) {
|
|
const ee = new EventEmitter()
|
|
|
|
|
|
const ytdl = sinon.createStubInstance(YoutubeDlWrap)
|
|
ytdl.exec.returns(ee)
|
|
|
|
|
|
const times = [
|
|
1000, // start
|
|
1000 * 60 * 60 * 1, // stop
|
|
1000 * 60 * 60 * 1 + 1, // start
|
|
1000 * 60 * 60 * 2, // stop
|
|
1000 * 60 * 60 * 3 + 1, // start
|
|
1000 * 60 * 60 * 4 // stop
|
|
]
|
|
|
|
clock.setTimeout(() => {
|
|
ee.emit('youtubeDlEvent', 'download', ' Destination: projektmelody 2023-01-18 21_10-projektmelody.mp4')
|
|
}, times[0])
|
|
|
|
clock.setTimeout(() => {
|
|
ee.emit('close')
|
|
}, times[1])
|
|
|
|
clock.setTimeout(() => {
|
|
ee.emit('youtubeDlEvent', 'download', ' Destination: projektmelody 2023-01-18 22_10-projektmelody.mp4')
|
|
}, times[2])
|
|
|
|
clock.setTimeout(() => {
|
|
ee.emit('close')
|
|
}, times[3])
|
|
|
|
clock.setTimeout(() => {
|
|
ee.emit('youtubeDlEvent', 'download', ' Destination: projektmelody 2023-01-18 23_10-projektmelody.mp4')
|
|
}, times[4])
|
|
|
|
clock.setTimeout(() => {
|
|
ee.emit('close')
|
|
}, times[5])
|
|
|
|
|
|
let url = `https://chaturbate.com/projektmelody`
|
|
let cwd = process.env.FUTUREPORN_WORKDIR || '/tmp'
|
|
const voddo = new Voddo({
|
|
url: url,
|
|
format: 'best',
|
|
cwd: cwd,
|
|
ytdl
|
|
})
|
|
|
|
voddo.once('start', (data) => {
|
|
expect(data).to.have.property('file')
|
|
expect(data).to.have.property('timestamp')
|
|
|
|
voddo.once('start', (data) => {
|
|
expect(data).to.have.property('file')
|
|
expect(data).to.have.property('timestamp')
|
|
|
|
voddo.once('start', (data) => {
|
|
expect(data).to.have.property('file')
|
|
expect(data).to.have.property('timestamp')
|
|
|
|
voddo.once('stop', function(report) {
|
|
debug(report)
|
|
expect(report).to.have.property('stats')
|
|
expect(report.stats).to.have.property('files')
|
|
expect(report.stats.files).to.have.lengthOf(3)
|
|
debug(report.stats.files)
|
|
expect(report.stats.files[0]).to.include({
|
|
file: 'projektmelody 2023-01-18 21_10-projektmelody.mp4'
|
|
})
|
|
|
|
expect(ytdl.exec).calledThrice
|
|
|
|
console.log('>>WE ARE DONE')
|
|
expect(this.clock.countTimers()).to.equal(0)
|
|
done()
|
|
})
|
|
clock.tick(times[5]) // stop
|
|
|
|
})
|
|
clock.tick(times[3]) // stop
|
|
clock.tick(times[4]) // start
|
|
|
|
})
|
|
clock.tick(times[1]) // stop
|
|
clock.tick(times[2]) // start
|
|
|
|
})
|
|
|
|
|
|
voddo.start()
|
|
expect(ytdl.exec).calledOnce
|
|
|
|
clock.tick(times[0])
|
|
|
|
|
|
|
|
|
|
})
|
|
|
|
xit('should keep a log of the files downloaded', function(done) {
|
|
this.timeout(5000)
|
|
// https://github.com/insanity54/futureporn/issues/13
|
|
const ytdlStub = sinon.createStubInstance(YoutubeDlWrap)
|
|
ytdlStub.exec
|
|
.onCall(0)
|
|
.callsFake(function(args, opts, aborter) {
|
|
let ee = new EventEmitter()
|
|
clock.setTimeout(() => {
|
|
ee.emit('youtubeDlEvent', 'download', ' Destination: projektmelody 2023-01-18 21_10-projektmelody.mp4')
|
|
}, 50)
|
|
clock.setTimeout(() => {
|
|
ee.emit('close')
|
|
}, 100)
|
|
return ee
|
|
})
|
|
.onCall(1)
|
|
.callsFake(function(args, opts, aborter) {
|
|
let ee = new EventEmitter()
|
|
clock.setTimeout(() => {
|
|
ee.emit('youtubeDlEvent', 'download', ' Destination: projektmelody 2023-01-18 22_10-projektmelody.mp4')
|
|
}, 50)
|
|
clock.setTimeout(() => {
|
|
ee.emit('close')
|
|
}, 100)
|
|
return ee
|
|
})
|
|
.onCall(2)
|
|
.callsFake(function(args, opts, aborter) {
|
|
let ee = new EventEmitter()
|
|
clock.setTimeout(() => {
|
|
ee.emit('youtubeDlEvent', 'download', ' Destination: projektmelody 2023-01-18 23_10-projektmelody.mp4')
|
|
}, 50)
|
|
clock.setTimeout(() => {
|
|
ee.emit('close')
|
|
}, 100)
|
|
return ee
|
|
})
|
|
let url = `https://chaturbate.com/projektmelody`
|
|
let cwd = process.env.FUTUREPORN_WORKDIR || '/tmp'
|
|
|
|
const voddo = new Voddo({
|
|
url: url,
|
|
format: 'best',
|
|
cwd: cwd,
|
|
ytdl: ytdlStub
|
|
})
|
|
|
|
// expect(clock.countTimers()).to.equal(0)
|
|
voddo.once('start', function(data) {
|
|
expect(data).to.have.property('file')
|
|
expect(data).to.have.property('timestamp')
|
|
|
|
clock.next()
|
|
clock.next()
|
|
voddo.once('start', function(data) {
|
|
expect(data).to.have.property('file')
|
|
expect(data).to.have.property('timestamp')
|
|
|
|
voddo.once('start', function(data) {
|
|
debug('fake start?')
|
|
expect(data).to.have.property('file')
|
|
expect(data).to.have.property('timestamp')
|
|
|
|
voddo.once('stop', function(report) {
|
|
debug(report)
|
|
expect(report).to.have.property('stats')
|
|
expect(report.stats).to.have.property('files')
|
|
expect(report.stats.files).to.have.lengthOf(3)
|
|
debug(report.stats.files)
|
|
expect(report.stats.files[0]).to.include({
|
|
file: 'projektmelody 2023-01-18 21_10-projektmelody.mp4'
|
|
})
|
|
|
|
sinon.assert.calledThrice(ytdlStub.exec)
|
|
expect(this.clock.countTimers()).to.equal(0)
|
|
done()
|
|
})
|
|
|
|
|
|
})
|
|
})
|
|
})
|
|
|
|
voddo.start()
|
|
})
|
|
|
|
|
|
it('should start and stop stream download', test(function(done) {
|
|
|
|
const sandbox = this
|
|
|
|
const ee = new EventEmitter()
|
|
|
|
const ytdl = this.createStubInstance(YoutubeDlWrap);
|
|
ytdl.exec.returns(ee)
|
|
|
|
|
|
const url = 'https://chaturbate.com/projektmelody'
|
|
const format = 'best'
|
|
const cwd = '/tmp'
|
|
const v = new Voddo({
|
|
url,
|
|
format,
|
|
cwd,
|
|
ytdl
|
|
})
|
|
console.log(v.stats)
|
|
|
|
v.once('stop', function(data) {
|
|
console.log('ffffff')
|
|
console.log(this)
|
|
expect(this.abortController.signal.aborted, 'abortController did not abort').to.be.true
|
|
expect(sandbox.clock.countTimers()).to.equal(0)
|
|
done()
|
|
})
|
|
v.once('start', function(data) {
|
|
console.log('STARRRRRT')
|
|
expect(data).to.have.property('file')
|
|
expect(data).to.have.property('timestamp')
|
|
expect(this).to.have.property('abortController')
|
|
console.log('ey cool, voddo started')
|
|
})
|
|
v.start()
|
|
|
|
const times = [
|
|
500,
|
|
1000,
|
|
2000
|
|
]
|
|
|
|
this.clock.setTimeout(() => {
|
|
ee.emit('youtubeDlEvent', 'download', ' Destination: projektmelody 2023-01-18 21_10-projektmelody.mp4')
|
|
}, times[0])
|
|
|
|
this.clock.setTimeout(() => {
|
|
v.stop()
|
|
}, times[1])
|
|
|
|
this.clock.setTimeout(() => {
|
|
ee.emit('close')
|
|
}, times[2])
|
|
|
|
this.clock.tick(times[0]) // start
|
|
this.clock.tick(times[1]) // stop
|
|
this.clock.tick(times[2]) // close
|
|
|
|
}))
|
|
|
|
|
|
xit('should retry when a stream closes', function(done) {
|
|
|
|
const ytdlStub = sinon.createStubInstance(YoutubeDlWrap);
|
|
ytdlStub.exec
|
|
.onCall(0)
|
|
.callsFake(function(args, opts, aborter) {
|
|
debug(' [test] callsFake 0')
|
|
let ee = new EventEmitter()
|
|
setTimeout(() => {
|
|
console.log('should retry when a stream closes -- emission')
|
|
ee.emit('youtubeDlEvent', 'download', ' Destination: projektmelody 2023-01-17 19_39-projektmelody.mp4')
|
|
}, 100)
|
|
setTimeout(() => {
|
|
console.log('should retry when a stream closes -- emission')
|
|
// this simulates youtube-dl closing
|
|
// (NOT Voddo closing)
|
|
ee.emit('close')
|
|
}, 550)
|
|
return ee
|
|
})
|
|
.onCall(1)
|
|
.callsFake(function(args, opts, aborter) {
|
|
debug(' [test] callsFake 1')
|
|
let ee = new EventEmitter()
|
|
setTimeout(() => {
|
|
ee.emit('youtubeDlEvent', 'download', ' Destination: projektmelody 2023-01-17 19_45-projektmelody.mp4')
|
|
}, 100)
|
|
return ee
|
|
})
|
|
let url = `https://chaturbate.com/projektmelody`
|
|
let cwd = process.env.FUTUREPORN_WORKDIR || '/tmp'
|
|
let abortController = new AbortController()
|
|
|
|
const voddo = new Voddo({
|
|
url: url,
|
|
format: 'best',
|
|
cwd: cwd,
|
|
ytdl: ytdlStub
|
|
})
|
|
|
|
voddo.once('start', function(data) {
|
|
debug(' [test] voddo <<<<<-----')
|
|
expect(data).to.have.property('file')
|
|
expect(data).to.have.property('timestamp')
|
|
|
|
voddo.once('start', function(data) {
|
|
debug(' [test] restarted after dl close! (expected) <<<<<-----')
|
|
|
|
sinon.assert.calledTwice(ytdlStub.exec)
|
|
expect(this.clock.countTimers()).to.equal(0)
|
|
done()
|
|
})
|
|
})
|
|
|
|
voddo.start()
|
|
|
|
clock.next()
|
|
clock.next()
|
|
clock.next()
|
|
clock.next()
|
|
clock.next()
|
|
|
|
})
|
|
|
|
}) |