-
Notifications
You must be signed in to change notification settings - Fork 4
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
* Use typescript and export types * Refactor playlist reading to `hls-playlist-reader` module * Split processing into segment-reader and segment-streamer * Preliminary HLS server control and LL-HLS support * More tests * Drop Travis
- Loading branch information
Showing
21 changed files
with
3,405 additions
and
1,679 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1 @@ | ||
/test/fixtures/** |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,6 +1,58 @@ | ||
'use strict'; | ||
|
||
const EslintPluginHapi = require('@hapi/eslint-plugin'); | ||
const TypescriptRules = require('@typescript-eslint/eslint-plugin').rules; | ||
|
||
|
||
const tsifyRules = function (from) { | ||
|
||
const rules = {}; | ||
|
||
for (const rule in from) { | ||
if (TypescriptRules[rule]) { | ||
rules[rule] = 'off'; | ||
rules[`@typescript-eslint/${rule}`] = from[rule]; | ||
} | ||
} | ||
|
||
return rules; | ||
}; | ||
|
||
|
||
module.exports = { | ||
extends: '@hapi/eslint-config-hapi', | ||
root: true, | ||
extends: [ | ||
'plugin:@hapi/recommended', | ||
'plugin:@typescript-eslint/eslint-recommended' | ||
], | ||
plugins: [ | ||
'@typescript-eslint' | ||
], | ||
parserOptions: { | ||
ecmaVersion: 2018 | ||
} | ||
} | ||
ecmaVersion: 2019 | ||
}, | ||
ignorePatterns: ['/lib/*.js', '/lib/*.d.ts'], | ||
overrides: [{ | ||
files: ['lib/**/*.ts'], | ||
extends: [ | ||
'plugin:@typescript-eslint/recommended' | ||
], | ||
parser: '@typescript-eslint/parser', | ||
parserOptions: { | ||
sourceType: 'module', | ||
project: './tsconfig.json', | ||
tsconfigRootDir: __dirname | ||
}, | ||
rules: { | ||
...tsifyRules(EslintPluginHapi.configs.recommended.rules), | ||
'@typescript-eslint/no-explicit-any': 'off', | ||
'@typescript-eslint/no-non-null-assertion': 'off', | ||
|
||
'@typescript-eslint/member-delimiter-style': 'warn', | ||
'@typescript-eslint/no-throw-literal': 'error', | ||
'@typescript-eslint/prefer-for-of': 'warn', | ||
'@typescript-eslint/type-annotation-spacing': 'warn', | ||
'@typescript-eslint/unified-signatures': 'warn' | ||
} | ||
}] | ||
}; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,2 +1,4 @@ | ||
/node_modules/ | ||
/lib/*.js | ||
/lib/*.d.ts | ||
coverage.html |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,7 @@ | ||
'use strict'; | ||
|
||
module.exports = { | ||
transform: require.resolve('./build/transform-typescript'), | ||
sourcemaps: true, | ||
flat: true | ||
}; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,3 +1,3 @@ | ||
* | ||
!lib/** | ||
!.npmignore | ||
!lib/**/*.js | ||
!lib/**/*.d.ts |
This file was deleted.
Oops, something went wrong.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,61 @@ | ||
'use strict'; | ||
|
||
const Ts = require('typescript'); | ||
|
||
const cache = new Map(); | ||
|
||
const tsify = function (content, fileName) { | ||
|
||
const searchPath = Ts.normalizePath(Ts.sys.getCurrentDirectory()); | ||
const configFileName = process.env.TSCONFIG || Ts.findConfigFile(searchPath, Ts.sys.fileExists); | ||
|
||
const compilerOptions = getCompilerOptionsViaCache(configFileName); | ||
compilerOptions.sourceMap = false; | ||
compilerOptions.inlineSourceMap = true; | ||
|
||
const { outputText/*, diagnostics*/ } = Ts.transpileModule(content, { | ||
fileName, | ||
compilerOptions, | ||
reportDiagnostics: false | ||
}); | ||
|
||
const splicePoint = outputText.indexOf('Object.defineProperty(exports, "__esModule", { value: true })'); | ||
if (splicePoint !== -1) { | ||
return '/* $lab:coverage:off$ */' + outputText.slice(0, splicePoint) + '/* $lab:coverage:on$ */' + outputText.slice(splicePoint); | ||
} | ||
|
||
return outputText; | ||
}; | ||
|
||
const getCompilerOptionsViaCache = function (configFileName) { | ||
|
||
let options; | ||
|
||
if (!(options = cache[configFileName])) { | ||
options = cache[configFileName] = getCompilerOptions(configFileName); | ||
} | ||
|
||
return options; | ||
}; | ||
|
||
const getCompilerOptions = function (configFileName) { | ||
|
||
const { config, error } = Ts.readConfigFile(configFileName, Ts.sys.readFile); | ||
if (error) { | ||
throw new Error(`TS config error in ${configFileName}: ${error.messageText}`); | ||
} | ||
|
||
const { options } = Ts.parseJsonConfigFileContent( | ||
config, | ||
Ts.sys, | ||
Ts.getDirectoryPath(configFileName), | ||
{}, | ||
configFileName); | ||
|
||
return options; | ||
}; | ||
|
||
module.exports = [{ | ||
ext: '.ts', | ||
transform: tsify | ||
}]; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,25 @@ | ||
import { HlsPlaylistReader, HlsPlaylistReaderOptions } from 'hls-playlist-reader'; | ||
import { HlsSegmentReader, HlsSegmentReaderOptions } from './segment-reader'; | ||
import { HlsSegmentStreamer, HlsSegmentStreamerOptions } from './segment-streamer'; | ||
|
||
export { HlsReaderObject } from './segment-reader'; | ||
export type { HlsIndexMeta } from 'hls-playlist-reader'; | ||
export { HlsStreamerObject } from './segment-streamer'; | ||
|
||
const createSimpleReader = function (uri: string, options: HlsSegmentReaderOptions & HlsSegmentStreamerOptions = {}): HlsSegmentStreamer { | ||
|
||
const reader = new HlsSegmentReader(uri, options); | ||
|
||
options.withData ??= false; | ||
|
||
const streamer = new HlsSegmentStreamer(reader, options); | ||
|
||
reader.on('problem', (err) => streamer.emit('problem', err)); | ||
|
||
return streamer; | ||
}; | ||
|
||
export { createSimpleReader, HlsPlaylistReader, HlsSegmentReader, HlsSegmentStreamer }; | ||
export type { HlsPlaylistReaderOptions, HlsSegmentReaderOptions, HlsSegmentStreamerOptions }; | ||
|
||
export default createSimpleReader; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,88 @@ | ||
import type { URL } from 'url'; | ||
import type { Byterange } from 'hls-playlist-reader/lib/helpers'; | ||
|
||
import { finished } from 'stream'; | ||
import { promisify } from 'util'; | ||
|
||
import { applyToDefaults, assert } from '@hapi/hoek'; | ||
|
||
import { performFetch } from 'hls-playlist-reader/lib/helpers'; | ||
|
||
|
||
const internals = { | ||
defaults: { | ||
probe: false | ||
}, | ||
streamFinished: promisify(finished) | ||
}; | ||
|
||
|
||
// eslint-disable-next-line @typescript-eslint/ban-types | ||
type FetchToken = object | string | number; | ||
|
||
export class SegmentDownloader { | ||
|
||
probe: boolean; | ||
|
||
#fetches = new Map<FetchToken, ReturnType<typeof performFetch>>(); | ||
|
||
constructor(options: { probe?: boolean }) { | ||
|
||
options = applyToDefaults(internals.defaults, options); | ||
|
||
this.probe = !!options.probe; | ||
} | ||
|
||
fetchSegment(token: FetchToken, uri: URL, byterange?: Required<Byterange>, { tries = 3 } = {}): ReturnType<typeof performFetch> { | ||
|
||
const promise = performFetch(uri, { byterange, probe: this.probe, retries: tries - 1 }); | ||
this._startTracking(token, promise); | ||
return promise; | ||
} | ||
|
||
/** | ||
* Stops any fetch not in token list | ||
* | ||
* @param {Set<FetchToken>} tokens | ||
*/ | ||
setValid(tokens = new Set()): void { | ||
|
||
for (const [token, fetch] of this.#fetches) { | ||
|
||
if (!tokens.has(token)) { | ||
this._stopTracking(token); | ||
fetch.abort(); | ||
} | ||
} | ||
} | ||
|
||
private _startTracking(token: FetchToken, promise: ReturnType<typeof performFetch>) { | ||
|
||
assert(!this.#fetches.has(token), 'A token can only be tracked once'); | ||
|
||
// Setup auto-untracking | ||
|
||
promise.then(({ stream }) => { | ||
|
||
if (!stream) { | ||
return this._stopTracking(token); | ||
} | ||
|
||
if (!this.#fetches.has(token)) { | ||
return; // It has already been aborted | ||
} | ||
|
||
finished(stream, () => this._stopTracking(token)); | ||
}).catch((/*err*/) => { | ||
|
||
this._stopTracking(token); | ||
}); | ||
|
||
this.#fetches.set(token, promise); | ||
} | ||
|
||
private _stopTracking(token: FetchToken) { | ||
|
||
this.#fetches.delete(token); | ||
} | ||
} |
Oops, something went wrong.