mirror of
https://github.com/advplyr/audiobookshelf.git
synced 2025-04-25 01:16:40 +02:00
Update:HLS router request validation, smooth out transcode reset logic
This commit is contained in:
parent
c98fac30b6
commit
dcdd4bb20b
@ -101,7 +101,6 @@ class Stream extends EventEmitter {
|
|||||||
return 'mpegts'
|
return 'mpegts'
|
||||||
}
|
}
|
||||||
get segmentBasename() {
|
get segmentBasename() {
|
||||||
if (this.hlsSegmentType === 'fmp4') return 'output-%d.m4s'
|
|
||||||
return 'output-%d.ts'
|
return 'output-%d.ts'
|
||||||
}
|
}
|
||||||
get segmentStartNumber() {
|
get segmentStartNumber() {
|
||||||
@ -142,20 +141,22 @@ class Stream extends EventEmitter {
|
|||||||
|
|
||||||
async checkSegmentNumberRequest(segNum) {
|
async checkSegmentNumberRequest(segNum) {
|
||||||
const segStartTime = segNum * this.segmentLength
|
const segStartTime = segNum * this.segmentLength
|
||||||
if (this.startTime > segStartTime) {
|
if (this.segmentStartNumber > segNum) {
|
||||||
Logger.warn(`[STREAM] Segment #${segNum} Request @${secondsToTimestamp(segStartTime)} is before start time (${secondsToTimestamp(this.startTime)}) - Reset Transcode`)
|
Logger.warn(`[STREAM] Segment #${segNum} Request is before starting segment number #${this.segmentStartNumber} - Reset Transcode`)
|
||||||
await this.reset(segStartTime - (this.segmentLength * 2))
|
await this.reset(segStartTime - (this.segmentLength * 5))
|
||||||
return segStartTime
|
return segStartTime
|
||||||
} else if (this.isTranscodeComplete) {
|
} else if (this.isTranscodeComplete) {
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (this.furthestSegmentCreated) {
|
||||||
const distanceFromFurthestSegment = segNum - this.furthestSegmentCreated
|
const distanceFromFurthestSegment = segNum - this.furthestSegmentCreated
|
||||||
if (distanceFromFurthestSegment > 10) {
|
if (distanceFromFurthestSegment > 10) {
|
||||||
Logger.info(`Segment #${segNum} requested is ${distanceFromFurthestSegment} segments from latest (${secondsToTimestamp(segStartTime)}) - Reset Transcode`)
|
Logger.info(`Segment #${segNum} requested is ${distanceFromFurthestSegment} segments from latest (${secondsToTimestamp(segStartTime)}) - Reset Transcode`)
|
||||||
await this.reset(segStartTime - (this.segmentLength * 2))
|
await this.reset(segStartTime - (this.segmentLength * 5))
|
||||||
return segStartTime
|
return segStartTime
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
@ -171,7 +172,7 @@ class Stream extends EventEmitter {
|
|||||||
var files = await fs.readdir(this.streamPath)
|
var files = await fs.readdir(this.streamPath)
|
||||||
files.forEach((file) => {
|
files.forEach((file) => {
|
||||||
var extname = Path.extname(file)
|
var extname = Path.extname(file)
|
||||||
if (extname === '.ts' || extname === '.m4s') {
|
if (extname === '.ts') {
|
||||||
var basename = Path.basename(file, extname)
|
var basename = Path.basename(file, extname)
|
||||||
var num_part = basename.split('-')[1]
|
var num_part = basename.split('-')[1]
|
||||||
var part_num = Number(num_part)
|
var part_num = Number(num_part)
|
||||||
@ -251,6 +252,7 @@ class Stream extends EventEmitter {
|
|||||||
Logger.info(`[STREAM] START STREAM - Num Segments: ${this.numSegments}`)
|
Logger.info(`[STREAM] START STREAM - Num Segments: ${this.numSegments}`)
|
||||||
|
|
||||||
this.ffmpeg = Ffmpeg()
|
this.ffmpeg = Ffmpeg()
|
||||||
|
this.furthestSegmentCreated = 0
|
||||||
|
|
||||||
var adjustedStartTime = Math.max(this.startTime - this.maxSeekBackTime, 0)
|
var adjustedStartTime = Math.max(this.startTime - this.maxSeekBackTime, 0)
|
||||||
var trackStartTime = await writeConcatFile(this.tracks, this.concatFilesPath, adjustedStartTime)
|
var trackStartTime = await writeConcatFile(this.tracks, this.concatFilesPath, adjustedStartTime)
|
||||||
|
@ -27,28 +27,60 @@ class HlsRouter {
|
|||||||
return Number(num_part)
|
return Number(num_part)
|
||||||
}
|
}
|
||||||
|
|
||||||
async streamFileRequest(req, res) {
|
/**
|
||||||
var streamId = req.params.stream
|
* Ensure filepath is inside streamDir
|
||||||
var fullFilePath = Path.join(this.playbackSessionManager.StreamsPath, streamId, req.params.file)
|
* Used to prevent arbitrary file reads
|
||||||
|
* @see https://nodejs.org/api/path.html#pathrelativefrom-to
|
||||||
|
*
|
||||||
|
* @param {string} streamDir
|
||||||
|
* @param {string} filepath
|
||||||
|
* @returns {boolean}
|
||||||
|
*/
|
||||||
|
validateStreamFilePath(streamDir, filepath) {
|
||||||
|
const relative = Path.relative(streamDir, filepath)
|
||||||
|
return relative && !relative.startsWith('..') && !Path.isAbsolute(relative)
|
||||||
|
}
|
||||||
|
|
||||||
var exists = await fs.pathExists(fullFilePath)
|
/**
|
||||||
if (!exists) {
|
* GET /hls/:stream/:file
|
||||||
|
* File must have extname .ts or .m3u8
|
||||||
|
*
|
||||||
|
* @param {express.Request} req
|
||||||
|
* @param {express.Response} res
|
||||||
|
*/
|
||||||
|
async streamFileRequest(req, res) {
|
||||||
|
const streamId = req.params.stream
|
||||||
|
// Ensure stream is open
|
||||||
|
const stream = this.playbackSessionManager.getStream(streamId)
|
||||||
|
if (!stream) {
|
||||||
|
Logger.error(`[HlsRouter] Stream "${streamId}" does not exist`)
|
||||||
|
return res.sendStatus(404)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Ensure stream filepath is valid
|
||||||
|
const streamDir = Path.join(this.playbackSessionManager.StreamsPath, streamId)
|
||||||
|
const fullFilePath = Path.join(streamDir, req.params.file)
|
||||||
|
if (!this.validateStreamFilePath(streamDir, fullFilePath)) {
|
||||||
|
Logger.error(`[HlsRouter] Invalid file parameter "${req.params.file}"`)
|
||||||
|
return res.sendStatus(400)
|
||||||
|
}
|
||||||
|
|
||||||
|
const fileExt = Path.extname(req.params.file)
|
||||||
|
if (fileExt !== '.ts' && fileExt !== '.m3u8') {
|
||||||
|
Logger.error(`[HlsRouter] Invalid file parameter "${req.params.file}" extname. Must be .ts or .m3u8`)
|
||||||
|
return res.sendStatus(400)
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!(await fs.pathExists(fullFilePath))) {
|
||||||
Logger.warn('File path does not exist', fullFilePath)
|
Logger.warn('File path does not exist', fullFilePath)
|
||||||
|
|
||||||
var fileExt = Path.extname(req.params.file)
|
if (fileExt === '.ts') {
|
||||||
if (fileExt === '.ts' || fileExt === '.m4s') {
|
const segNum = this.parseSegmentFilename(req.params.file)
|
||||||
var segNum = this.parseSegmentFilename(req.params.file)
|
|
||||||
var stream = this.playbackSessionManager.getStream(streamId)
|
|
||||||
if (!stream) {
|
|
||||||
Logger.error(`[HlsRouter] Stream ${streamId} does not exist`)
|
|
||||||
return res.sendStatus(500)
|
|
||||||
}
|
|
||||||
|
|
||||||
if (stream.isResetting) {
|
if (stream.isResetting) {
|
||||||
Logger.info(`[HlsRouter] Stream ${streamId} is currently resetting`)
|
Logger.info(`[HlsRouter] Stream ${streamId} is currently resetting`)
|
||||||
return res.sendStatus(404)
|
|
||||||
} else {
|
} else {
|
||||||
var startTimeForReset = await stream.checkSegmentNumberRequest(segNum)
|
const startTimeForReset = await stream.checkSegmentNumberRequest(segNum)
|
||||||
if (startTimeForReset) {
|
if (startTimeForReset) {
|
||||||
// HLS.js will restart the stream at the new time
|
// HLS.js will restart the stream at the new time
|
||||||
Logger.info(`[HlsRouter] Resetting Stream - notify client @${startTimeForReset}s`)
|
Logger.info(`[HlsRouter] Resetting Stream - notify client @${startTimeForReset}s`)
|
||||||
@ -56,13 +88,12 @@ class HlsRouter {
|
|||||||
startTime: startTimeForReset,
|
startTime: startTimeForReset,
|
||||||
streamId: stream.id
|
streamId: stream.id
|
||||||
})
|
})
|
||||||
return res.sendStatus(500)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
return res.sendStatus(404)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Logger.info('Sending file', fullFilePath)
|
|
||||||
res.sendFile(fullFilePath)
|
res.sendFile(fullFilePath)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user