These files should not be added

This commit is contained in:
Gabe Kangas
2020-10-19 22:22:33 -07:00
parent 226242f07b
commit 205ef8926e
6368 changed files with 0 additions and 603959 deletions

File diff suppressed because it is too large Load Diff

View File

@@ -1,13 +0,0 @@
Copyright Brightcove, Inc.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.

View File

@@ -1,160 +0,0 @@
![Video.js logo][logo]
# [Video.js - HTML5 Video Player][vjs]
[![Build Status][travis-icon]][travis-link]
[![Coverage Status][coveralls-icon]][coveralls-link]
[![Greenkeeper badge](https://badges.greenkeeper.io/videojs/video.js.svg)](https://greenkeeper.io/)
[![Slack Status][slack-icon]][slack-link]
[![NPM][npm-icon]][npm-link]
> Video.js is a web video player built from the ground up for an HTML5 world. It supports HTML5 and Flash video, as well as YouTube and Vimeo (through [plugins][plugins]). It supports video playback on desktops and mobile devices. This project was started mid 2010, and the player is now used on over ~~50,000~~ ~~100,000~~ ~~200,000~~ [400,000 websites][builtwith].
## Table of Contents
* [Quick Start](#quick-start)
* [Contributing](#contributing)
* [Code of Conduct](#code-of-conduct)
* [License](#license)
## Quick Start
Thanks to the awesome folks over at [Fastly][fastly], there's a free, CDN hosted version of Video.js that anyone can use. Add these tags to your document's `<head>`:
```html
<link href="//vjs.zencdn.net/7.3.0/video-js.min.css" rel="stylesheet">
<script src="//vjs.zencdn.net/7.3.0/video.min.js"></script>
```
> For the latest version of video.js and URLs to use, check out the [Getting Started][getting-started] page on our website.
Video.js version 7 (and newer) CDN builds do not send any data to Google Analytics.
In older versions of Video.js (6 and earlier), in the `vjs.zencdn.net` CDN-hosted versions we include a [stripped down Google Analytics pixel](https://github.com/videojs/cdn/blob/master/src/analytics.js) that tracks a random sampling (currently 1%) of players loaded from the CDN. This allows us to see (roughly) what browsers are in use in the wild, along with other useful metrics such as OS and device. If you'd like to disable analytics, you can simply include the following global before including Video.js via the free CDN:
```html
<script>window.HELP_IMPROVE_VIDEOJS = false;</script>
```
Alternatively, you can include Video.js by getting it from [npm](https://videojs.com/getting-started/#download-npm), downloading from [GitHub releases](https://github.com/videojs/video.js/releases) or by including it via [unpkg](https://unpkg.com) or another JavaScript CDN like CDNjs. These releases _do not_ include Google Analytics tracking at all.
```html
<!-- unpkg : use the latest version of Video.js -->
<link href="https://unpkg.com/video.js/dist/video-js.min.css" rel="stylesheet">
<script src="https://unpkg.com/video.js/dist/video.min.js"></script>
<!-- unpkg : use a specific version of Video.js (change the version numbers as necessary) -->
<link href="https://unpkg.com/video.js@6.11.0/dist/video-js.min.css" rel="stylesheet">
<script src="https://unpkg.com/video.js@6.11.0/dist/video.min.js"></script>
<!-- cdnjs : use a specific version of Video.js (change the version numbers as necessary) -->
<link href="https://cdnjs.cloudflare.com/ajax/libs/video.js/6.7.3/video-js.min.css" rel="stylesheet">
<script src="https://cdnjs.cloudflare.com/ajax/libs/video.js/6.7.3/video.min.js"></script>
```
Next, using Video.js is as simple as creating a `<video>` element, but with an additional `data-setup` attribute. At a minimum, this attribute must have a value of `'{}'`, but it can include any Video.js [options][options] - just make sure it contains valid JSON!
```html
<video
id="my-player"
class="video-js"
controls
preload="auto"
poster="//vjs.zencdn.net/v/oceans.png"
data-setup='{}'>
<source src="//vjs.zencdn.net/v/oceans.mp4" type="video/mp4"></source>
<source src="//vjs.zencdn.net/v/oceans.webm" type="video/webm"></source>
<source src="//vjs.zencdn.net/v/oceans.ogv" type="video/ogg"></source>
<p class="vjs-no-js">
To view this video please enable JavaScript, and consider upgrading to a
web browser that
<a href="https://videojs.com/html5-video-support/" target="_blank">
supports HTML5 video
</a>
</p>
</video>
```
When the page loads, Video.js will find this element and automatically setup a player in its place.
If you don't want to use automatic setup, you can leave off the `data-setup` attribute and initialize a `<video>` element manually using the `videojs` function:
```js
var player = videojs('my-player');
```
The `videojs` function also accepts an `options` object and a callback to be invoked
when the player is ready:
```js
var options = {};
var player = videojs('my-player', options, function onPlayerReady() {
videojs.log('Your player is ready!');
// In this context, `this` is the player that was created by Video.js.
this.play();
// How about an event listener?
this.on('ended', function() {
videojs.log('Awww...over so soon?!');
});
});
```
If you're ready to dive in, the [Getting Started][getting-started] page and [documentation][docs] are the best places to go for more information. If you get stuck, head over to our [Slack channel][slack-link]!
## Contributing
Video.js is a free and open source library, and we appreciate any help you're willing to give - whether it's fixing bugs, improving documentation, or suggesting new features. Check out the [contributing guide][contributing] for more!
_Video.js uses [BrowserStack][browserstack] for compatibility testing._
## [Code of Conduct][coc]
Please note that this project is released with a [Contributor Code of Conduct][coc]. By participating in this project you agree to abide by its terms.
## [License][license]
Video.js is [licensed][license] under the Apache License, Version 2.0.
[browserstack]: https://browserstack.com
[builtwith]: https://trends.builtwith.com/media/VideoJS
[contributing]: CONTRIBUTING.md
[coveralls-icon]: https://coveralls.io/repos/github/videojs/video.js/badge.svg?branch=master
[coveralls-link]: https://coveralls.io/github/videojs/video.js?branch=master
[docs]: https://docs.videojs.com
[fastly]: https://www.fastly.com/
[getting-started]: https://videojs.com/getting-started/
[license]: LICENSE
[logo]: https://videojs.com/logo-white.png
[npm-icon]: https://nodei.co/npm/video.js.png?downloads=true&downloadRank=true
[npm-link]: https://nodei.co/npm/video.js/
[options]: docs/guides/options.md
[plugins]: https://videojs.com/plugins/
[slack-icon]: http://slack.videojs.com/badge.svg
[slack-link]: http://slack.videojs.com
[travis-icon]: https://travis-ci.org/videojs/video.js.svg?branch=master
[travis-link]: https://travis-ci.org/videojs/video.js
[vjs]: https://videojs.com
[coc]: CODE_OF_CONDUCT.md

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@@ -1,522 +0,0 @@
<a name="1.13.2"></a>
## [1.13.2](https://github.com/videojs/http-streaming/compare/v1.13.1...v1.13.2) (2020-03-30)
### Bug Fixes
* dispose workers on dispose ([#788](https://github.com/videojs/http-streaming/issues/788)) ([03ddb4e](https://github.com/videojs/http-streaming/commit/03ddb4e))
<a name="1.13.1"></a>
## [1.13.1](https://github.com/videojs/http-streaming/compare/v1.13.0...v1.13.1) (2020-03-28)
### Bug Fixes
* put devicePixelRatio behind useDevicePixelRatio option ([#785](https://github.com/videojs/http-streaming/issues/785)) ([57335d9](https://github.com/videojs/http-streaming/commit/57335d9))
<a name="1.13.0"></a>
# [1.13.0](https://github.com/videojs/http-streaming/compare/v1.12.3...v1.13.0) (2020-03-26)
### Bug Fixes
* null check return value of selectPlaylist ([#779](https://github.com/videojs/http-streaming/issues/779)) ([90a0215](https://github.com/videojs/http-streaming/commit/90a0215))
* take devicePixelRatio into account during ABR ([#784](https://github.com/videojs/http-streaming/issues/784)) ([bd63e57](https://github.com/videojs/http-streaming/commit/bd63e57)), closes [#744](https://github.com/videojs/http-streaming/issues/744)
### Chores
* port index page from master ([#774](https://github.com/videojs/http-streaming/issues/774)) ([808c3b1](https://github.com/videojs/http-streaming/commit/808c3b1))
### Reverts
* "fix: Use middleware and a wrapped function for seeking instead of relying on unreliable 'seeking' events ([#161](https://github.com/videojs/http-streaming/issues/161))" ([#777](https://github.com/videojs/http-streaming/issues/777)) ([1a4fc1e](https://github.com/videojs/http-streaming/commit/1a4fc1e)), closes [#378](https://github.com/videojs/http-streaming/issues/378) [videojs/video.js#6444](https://github.com/videojs/video.js/issues/6444)
<a name="1.12.3"></a>
## [1.12.3](https://github.com/videojs/http-streaming/compare/v1.12.2...v1.12.3) (2020-03-16)
### Bug Fixes
* **segment-loader:** resetEverything should remove through Infinity ([#754](https://github.com/videojs/http-streaming/issues/754)) ([#758](https://github.com/videojs/http-streaming/issues/758)) ([6ba1800](https://github.com/videojs/http-streaming/commit/6ba1800))
* add native cues when using native text tracks ([#769](https://github.com/videojs/http-streaming/issues/769)) ([10d25d1](https://github.com/videojs/http-streaming/commit/10d25d1)), closes [videojs/video.js#6410](https://github.com/videojs/video.js/issues/6410)
### Tests
* skip flaky test ([#771](https://github.com/videojs/http-streaming/issues/771)) ([99bf807](https://github.com/videojs/http-streaming/commit/99bf807))
<a name="1.12.2"></a>
## [1.12.2](https://github.com/videojs/http-streaming/compare/v1.12.1...v1.12.2) (2020-02-18)
### Bug Fixes
* add dispose functions and fix memory leaks [#643](https://github.com/videojs/http-streaming/issues/643) for 1.x ([#734](https://github.com/videojs/http-streaming/issues/734)) ([89ab859](https://github.com/videojs/http-streaming/commit/89ab859))
* resume live DASH playlist refreshes after pausing and loading DASH playlist loader ([#736](https://github.com/videojs/http-streaming/issues/736)) ([e966e9c](https://github.com/videojs/http-streaming/commit/e966e9c))
* trim 30s back from playhead even for VOD and LIVE DVR content ([#740](https://github.com/videojs/http-streaming/issues/740)) ([886f592](https://github.com/videojs/http-streaming/commit/886f592))
<a name="1.12.1"></a>
## [1.12.1](https://github.com/videojs/http-streaming/compare/v1.12.0...v1.12.1) (2020-02-11)
### Bug Fixes
* update to mux.js 5.5.1 ([#733](https://github.com/videojs/http-streaming/issues/733)) ([aa22f31](https://github.com/videojs/http-streaming/commit/aa22f31))
### Code Refactoring
* add semicolon and move variable closer to usage ([#729](https://github.com/videojs/http-streaming/issues/729)) ([675b1e9](https://github.com/videojs/http-streaming/commit/675b1e9))
<a name="1.12.0"></a>
# [1.12.0](https://github.com/videojs/http-streaming/compare/v1.11.3...v1.12.0) (2020-02-04)
### Features
* support suggestedPresentationDelay in DASH manifests ([#698](https://github.com/videojs/http-streaming/issues/698)) ([c14fb43](https://github.com/videojs/http-streaming/commit/c14fb43))
<a name="1.11.3"></a>
## [1.11.3](https://github.com/videojs/http-streaming/compare/v1.11.2...v1.11.3) (2020-01-17)
### Bug Fixes
* consider `hidden` tracks as active ([#564](https://github.com/videojs/http-streaming/issues/564)) ([6acdd20](https://github.com/videojs/http-streaming/commit/6acdd20))
* live startup failures when play happens before playlist is downloaded ([#700](https://github.com/videojs/http-streaming/issues/700)) ([92c93a7](https://github.com/videojs/http-streaming/commit/92c93a7)), closes [#464](https://github.com/videojs/http-streaming/issues/464) [#496](https://github.com/videojs/http-streaming/issues/496) [#500](https://github.com/videojs/http-streaming/issues/500)
* race condition preventing qualityLevels from being populating ([#707](https://github.com/videojs/http-streaming/issues/707)) ([8c4a11f](https://github.com/videojs/http-streaming/commit/8c4a11f)), closes [#677](https://github.com/videojs/http-streaming/issues/677)
* support multiple stream-inf with same URI ([#672](https://github.com/videojs/http-streaming/issues/672)) ([095515c](https://github.com/videojs/http-streaming/commit/095515c))
### Chores
* **stats:** add liveui option and various fixes ([#695](https://github.com/videojs/http-streaming/issues/695)) ([a0f6c8b](https://github.com/videojs/http-streaming/commit/a0f6c8b))
<a name="1.11.2"></a>
## [1.11.2](https://github.com/videojs/http-streaming/compare/v1.11.1...v1.11.2) (2019-11-12)
### Bug Fixes
* only do ondemand eme key initialization on non-ie11 browsers ([#682](https://github.com/videojs/http-streaming/issues/682)) ([fbfe68f](https://github.com/videojs/http-streaming/commit/fbfe68f))
<a name="1.11.1"></a>
## [1.11.1](https://github.com/videojs/http-streaming/compare/v1.11.0...v1.11.1) (2019-10-07)
### Bug Fixes
* improve timestampOffset calculation for fmp4s ([#666](https://github.com/videojs/http-streaming/issues/666)) ([bedc824](https://github.com/videojs/http-streaming/commit/bedc824))
<a name="1.11.0"></a>
# [1.11.0](https://github.com/videojs/http-streaming/compare/v1.11.0-0...v1.11.0) (2019-09-25)
<a name="1.10.6"></a>
## [1.10.6](https://github.com/videojs/http-streaming/compare/v1.10.5...v1.10.6) (2019-08-28)
### Bug Fixes
* fix anamorphic video with chrome ([#648](https://github.com/videojs/http-streaming/issues/648)) ([50b5992](https://github.com/videojs/http-streaming/commit/50b5992)), closes [#312](https://github.com/videojs/http-streaming/issues/312)
### Performance Improvements
* save 15430 gzipped bytes with better mux.js imports ([#628](https://github.com/videojs/http-streaming/issues/628)) ([4e69d21](https://github.com/videojs/http-streaming/commit/4e69d21))
<a name="1.10.5"></a>
## [1.10.5](https://github.com/videojs/http-streaming/compare/v1.10.5-1...v1.10.5) (2019-08-16)
### Chores
* **package:** update to mux.js 5.2.0 ([#636](https://github.com/videojs/http-streaming/issues/636)) ([0a793b0](https://github.com/videojs/http-streaming/commit/0a793b0))
### Tests
* **zero-length:** update segment and unskip test ([#635](https://github.com/videojs/http-streaming/issues/635)) ([665b526](https://github.com/videojs/http-streaming/commit/665b526))
<a name="1.10.4"></a>
## [1.10.4](https://github.com/videojs/http-streaming/compare/v1.10.3...v1.10.4) (2019-06-27)
### Bug Fixes
* verify sidx is present before doing anything related to it ([#561](https://github.com/videojs/http-streaming/issues/561)) ([15d753c](https://github.com/videojs/http-streaming/commit/15d753c)), closes [#457](https://github.com/videojs/http-streaming/issues/457) [#557](https://github.com/videojs/http-streaming/issues/557)
### Chores
* update package-lock ([1559930](https://github.com/videojs/http-streaming/commit/1559930))
<a name="1.10.3"></a>
## [1.10.3](https://github.com/videojs/http-streaming/compare/v1.10.2...v1.10.3) (2019-05-30)
### Bug Fixes
* only reset syncController if we passed a discontinuity ([#502](https://github.com/videojs/http-streaming/issues/502)) ([409634f](https://github.com/videojs/http-streaming/commit/409634f))
### Chores
* **package:** update mux.js to version 5.1.3 🚀 ([#510](https://github.com/videojs/http-streaming/issues/510)) ([55d764a](https://github.com/videojs/http-streaming/commit/55d764a))
<a name="1.10.2"></a>
## [1.10.2](https://github.com/videojs/http-streaming/compare/v1.10.1...v1.10.2) (2019-05-13)
### Bug Fixes
* clear the blacklist for other playlists if final rendition errors ([#479](https://github.com/videojs/http-streaming/issues/479)) ([fe3b378](https://github.com/videojs/http-streaming/commit/fe3b378)), closes [#396](https://github.com/videojs/http-streaming/issues/396) [#471](https://github.com/videojs/http-streaming/issues/471)
* **development:** rollup watch, via `npm run watch`, should work for es/cjs ([#484](https://github.com/videojs/http-streaming/issues/484)) ([ad6f292](https://github.com/videojs/http-streaming/commit/ad6f292))
* **HLSe:** slice keys properly on IE11 ([#506](https://github.com/videojs/http-streaming/issues/506)) ([681cd6f](https://github.com/videojs/http-streaming/commit/681cd6f))
* **package:** update mpd-parser to version 0.8.1 🚀 ([#490](https://github.com/videojs/http-streaming/issues/490)) ([a49ad3a](https://github.com/videojs/http-streaming/commit/a49ad3a))
* **package:** update mux.js to version 5.1.2 🚀 ([#477](https://github.com/videojs/http-streaming/issues/477)) ([57a38e9](https://github.com/videojs/http-streaming/commit/57a38e9)), closes [#503](https://github.com/videojs/http-streaming/issues/503) [#504](https://github.com/videojs/http-streaming/issues/504)
* **source-updater:** run callbacks after setting timestampOffset ([#480](https://github.com/videojs/http-streaming/issues/480)) ([6ecf859](https://github.com/videojs/http-streaming/commit/6ecf859))
* livestream timeout issues ([#469](https://github.com/videojs/http-streaming/issues/469)) ([cf3fafc](https://github.com/videojs/http-streaming/commit/cf3fafc)), closes [segment#16](https://github.com/segment/issues/16) [segment#15](https://github.com/segment/issues/15) [segment#16](https://github.com/segment/issues/16) [segment#15](https://github.com/segment/issues/15) [segment#16](https://github.com/segment/issues/16)
* remove both vttjs listeners to prevent leaking one of them ([#495](https://github.com/videojs/http-streaming/issues/495)) ([1db1e72](https://github.com/videojs/http-streaming/commit/1db1e72))
### Performance Improvements
* don't enable captionParser for audio or subtitle loaders ([#487](https://github.com/videojs/http-streaming/issues/487)) ([358877f](https://github.com/videojs/http-streaming/commit/358877f))
<a name="1.10.1"></a>
## [1.10.1](https://github.com/videojs/http-streaming/compare/v1.10.0...v1.10.1) (2019-04-16)
### Bug Fixes
* **dash-playlist-loader:** clear out timers on dispose ([#472](https://github.com/videojs/http-streaming/issues/472)) ([2f1c222](https://github.com/videojs/http-streaming/commit/2f1c222))
### Reverts
* "fix: clear the blacklist for other playlists if final rendition errors ([#396](https://github.com/videojs/http-streaming/issues/396))" ([#471](https://github.com/videojs/http-streaming/issues/471)) ([dd55028](https://github.com/videojs/http-streaming/commit/dd55028))
<a name="1.10.0"></a>
# [1.10.0](https://github.com/videojs/http-streaming/compare/v1.9.3...v1.10.0) (2019-04-12)
### Features
* add option to cache encrpytion keys in the player ([#446](https://github.com/videojs/http-streaming/issues/446)) ([599b94d](https://github.com/videojs/http-streaming/commit/599b94d)), closes [#140](https://github.com/videojs/http-streaming/issues/140)
* add support for dash manifests describing sidx boxes ([#455](https://github.com/videojs/http-streaming/issues/455)) ([80dde16](https://github.com/videojs/http-streaming/commit/80dde16))
### Bug Fixes
* clear the blacklist for other playlists if final rendition errors ([#396](https://github.com/videojs/http-streaming/issues/396)) ([6e6c8c2](https://github.com/videojs/http-streaming/commit/6e6c8c2))
* on dispose, don't call abort on SourceBuffer until after remove() has finished ([3806750](https://github.com/videojs/http-streaming/commit/3806750))
### Documentation
* **README:** update broken link to full docs ([#440](https://github.com/videojs/http-streaming/issues/440)) ([fbd615c](https://github.com/videojs/http-streaming/commit/fbd615c))
<a name="1.9.3"></a>
## [1.9.3](https://github.com/videojs/http-streaming/compare/v1.9.2...v1.9.3) (2019-03-21)
### Bug Fixes
* **id3:** ignore unsupported id3 frames ([#437](https://github.com/videojs/http-streaming/issues/437)) ([7040b7d](https://github.com/videojs/http-streaming/commit/7040b7d)), closes [videojs/video.js#5823](https://github.com/videojs/video.js/issues/5823)
### Documentation
* add diagrams for playlist loaders ([#426](https://github.com/videojs/http-streaming/issues/426)) ([52201f9](https://github.com/videojs/http-streaming/commit/52201f9))
<a name="1.9.2"></a>
## [1.9.2](https://github.com/videojs/http-streaming/compare/v1.9.1...v1.9.2) (2019-03-14)
### Bug Fixes
* expose `custom` segment property in the segment metadata track ([#429](https://github.com/videojs/http-streaming/issues/429)) ([17510da](https://github.com/videojs/http-streaming/commit/17510da))
<a name="1.9.1"></a>
## [1.9.1](https://github.com/videojs/http-streaming/compare/v1.9.0...v1.9.1) (2019-03-05)
### Bug Fixes
* fix for streams that would occasionally never fire an `ended` event ([fc09926](https://github.com/videojs/http-streaming/commit/fc09926))
* Fix video playback freezes caused by not using absolute current time ([#401](https://github.com/videojs/http-streaming/issues/401)) ([957ecfd](https://github.com/videojs/http-streaming/commit/957ecfd))
* only fire seekablechange when values of seekable ranges actually change ([#415](https://github.com/videojs/http-streaming/issues/415)) ([a4c056e](https://github.com/videojs/http-streaming/commit/a4c056e))
* Prevent infinite buffering at the start of looped video on edge ([#392](https://github.com/videojs/http-streaming/issues/392)) ([b6d1b97](https://github.com/videojs/http-streaming/commit/b6d1b97))
### Code Refactoring
* align DashPlaylistLoader closer to PlaylistLoader states ([#386](https://github.com/videojs/http-streaming/issues/386)) ([5d80fe7](https://github.com/videojs/http-streaming/commit/5d80fe7))
<a name="1.9.0"></a>
# [1.9.0](https://github.com/videojs/http-streaming/compare/v1.8.0...v1.9.0) (2019-02-07)
### Features
* Use exposed transmuxer time modifications for more accurate conversion between program and player times ([#371](https://github.com/videojs/http-streaming/issues/371)) ([41df5c0](https://github.com/videojs/http-streaming/commit/41df5c0))
### Bug Fixes
* m3u8 playlist is not updating when only endList changes ([#373](https://github.com/videojs/http-streaming/issues/373)) ([c7d1306](https://github.com/videojs/http-streaming/commit/c7d1306))
* Prevent exceptions from being thrown by the MediaSource ([#389](https://github.com/videojs/http-streaming/issues/389)) ([8c06366](https://github.com/videojs/http-streaming/commit/8c06366))
### Chores
* Update mux.js to the latest version 🚀 ([#397](https://github.com/videojs/http-streaming/issues/397)) ([38ec2a5](https://github.com/videojs/http-streaming/commit/38ec2a5))
### Tests
* added test for playlist not updating when only endList changes ([#394](https://github.com/videojs/http-streaming/issues/394)) ([39d0be2](https://github.com/videojs/http-streaming/commit/39d0be2))
<a name="1.8.0"></a>
# [1.8.0](https://github.com/videojs/http-streaming/compare/v1.7.0...v1.8.0) (2019-01-10)
### Features
* expose custom M3U8 mapper API ([#325](https://github.com/videojs/http-streaming/issues/325)) ([609beb3](https://github.com/videojs/http-streaming/commit/609beb3))
### Bug Fixes
* **id3:** cuechange event not being triggered on audio-only HLS streams ([#334](https://github.com/videojs/http-streaming/issues/334)) ([bab70fd](https://github.com/videojs/http-streaming/commit/bab70fd)), closes [#130](https://github.com/videojs/http-streaming/issues/130)
<a name="1.7.0"></a>
# [1.7.0](https://github.com/videojs/http-streaming/compare/v1.6.0...v1.7.0) (2019-01-04)
### Features
* expose custom M3U8 parser API ([#331](https://github.com/videojs/http-streaming/issues/331)) ([b0643a4](https://github.com/videojs/http-streaming/commit/b0643a4))
<a name="1.6.0"></a>
# [1.6.0](https://github.com/videojs/http-streaming/compare/v1.5.1...v1.6.0) (2018-12-21)
### Features
* Add allowSeeksWithinUnsafeLiveWindow property ([#320](https://github.com/videojs/http-streaming/issues/320)) ([74b28e8](https://github.com/videojs/http-streaming/commit/74b28e8))
### Chores
* add clock.ticks to now async operations in tests ([#315](https://github.com/videojs/http-streaming/issues/315)) ([895c86a](https://github.com/videojs/http-streaming/commit/895c86a))
### Documentation
* Add README entry on DRM and videojs-contrib-eme ([#307](https://github.com/videojs/http-streaming/issues/307)) ([93b6167](https://github.com/videojs/http-streaming/commit/93b6167))
<a name="1.5.1"></a>
## [1.5.1](https://github.com/videojs/http-streaming/compare/v1.5.0...v1.5.1) (2018-12-06)
### Bug Fixes
* added missing manifest information on to segments (EXT-X-PROGRAM-DATE-TIME) ([#236](https://github.com/videojs/http-streaming/issues/236)) ([a35dd09](https://github.com/videojs/http-streaming/commit/a35dd09))
* remove player props on dispose to stop middleware ([#229](https://github.com/videojs/http-streaming/issues/229)) ([cd13f9f](https://github.com/videojs/http-streaming/commit/cd13f9f))
### Documentation
* add dash to package.json description ([#267](https://github.com/videojs/http-streaming/issues/267)) ([3296c68](https://github.com/videojs/http-streaming/commit/3296c68))
* add documentation for reloadSourceOnError ([#266](https://github.com/videojs/http-streaming/issues/266)) ([7448b37](https://github.com/videojs/http-streaming/commit/7448b37))
<a name="1.5.0"></a>
# [1.5.0](https://github.com/videojs/http-streaming/compare/v1.4.2...v1.5.0) (2018-11-13)
### Features
* Add useBandwidthFromLocalStorage option ([#275](https://github.com/videojs/http-streaming/issues/275)) ([60c88ae](https://github.com/videojs/http-streaming/commit/60c88ae))
### Bug Fixes
* don't wait for requests to finish when encountering an error in media-segment-request ([#286](https://github.com/videojs/http-streaming/issues/286)) ([970e3ce](https://github.com/videojs/http-streaming/commit/970e3ce))
* throttle final playlist reloads when using DASH ([#277](https://github.com/videojs/http-streaming/issues/277)) ([1c2887a](https://github.com/videojs/http-streaming/commit/1c2887a))
<a name="1.4.2"></a>
## [1.4.2](https://github.com/videojs/http-streaming/compare/v1.4.1...v1.4.2) (2018-11-01)
### Chores
* pin to node 8 for now ([#279](https://github.com/videojs/http-streaming/issues/279)) ([f900dc4](https://github.com/videojs/http-streaming/commit/f900dc4))
* update mux.js to 5.0.1 ([#282](https://github.com/videojs/http-streaming/issues/282)) ([af6ee4f](https://github.com/videojs/http-streaming/commit/af6ee4f))
<a name="1.4.1"></a>
## [1.4.1](https://github.com/videojs/http-streaming/compare/v1.4.0...v1.4.1) (2018-10-25)
### Bug Fixes
* **subtitles:** set default property if default and autoselect are both enabled ([#239](https://github.com/videojs/http-streaming/issues/239)) ([ee594e5](https://github.com/videojs/http-streaming/commit/ee594e5))
<a name="1.4.0"></a>
# [1.4.0](https://github.com/videojs/http-streaming/compare/v1.3.1...v1.4.0) (2018-10-24)
### Features
* limited experimental DASH multiperiod support ([#268](https://github.com/videojs/http-streaming/issues/268)) ([a213807](https://github.com/videojs/http-streaming/commit/a213807))
* smoothQualityChange flag ([#235](https://github.com/videojs/http-streaming/issues/235)) ([0e4fdf9](https://github.com/videojs/http-streaming/commit/0e4fdf9))
### Bug Fixes
* immediately setup EME if available ([#263](https://github.com/videojs/http-streaming/issues/263)) ([7577e90](https://github.com/videojs/http-streaming/commit/7577e90))
<a name="1.3.1"></a>
## [1.3.1](https://github.com/videojs/http-streaming/compare/v1.3.0...v1.3.1) (2018-10-15)
### Bug Fixes
* ensure content loops ([#259](https://github.com/videojs/http-streaming/issues/259)) ([26300df](https://github.com/videojs/http-streaming/commit/26300df))
<a name="1.3.0"></a>
# [1.3.0](https://github.com/videojs/http-streaming/compare/v1.2.6...v1.3.0) (2018-10-05)
### Features
* add an option to ignore player size in selection logic ([#238](https://github.com/videojs/http-streaming/issues/238)) ([7ae42b1](https://github.com/videojs/http-streaming/commit/7ae42b1))
### Documentation
* Update CONTRIBUTING.md ([#242](https://github.com/videojs/http-streaming/issues/242)) ([9d83e9d](https://github.com/videojs/http-streaming/commit/9d83e9d))
<a name="1.2.6"></a>
## [1.2.6](https://github.com/videojs/http-streaming/compare/v1.2.5...v1.2.6) (2018-09-21)
### Bug Fixes
* stutter after fast quality change in IE/Edge ([#213](https://github.com/videojs/http-streaming/issues/213)) ([2c0d9b2](https://github.com/videojs/http-streaming/commit/2c0d9b2))
### Documentation
* update issue template to link to the troubleshooting guide ([#215](https://github.com/videojs/http-streaming/issues/215)) ([413f0e8](https://github.com/videojs/http-streaming/commit/413f0e8))
* update README notes for video.js 7 ([#200](https://github.com/videojs/http-streaming/issues/200)) ([d68ce0c](https://github.com/videojs/http-streaming/commit/d68ce0c))
* update troubleshooting guide for Edge/mobile Chrome ([#216](https://github.com/videojs/http-streaming/issues/216)) ([21e5335](https://github.com/videojs/http-streaming/commit/21e5335))
<a name="1.2.5"></a>
## [1.2.5](https://github.com/videojs/http-streaming/compare/v1.2.4...v1.2.5) (2018-08-24)
### Bug Fixes
* fix replay functionality ([#204](https://github.com/videojs/http-streaming/issues/204)) ([fd6be83](https://github.com/videojs/http-streaming/commit/fd6be83))
<a name="1.2.4"></a>
## [1.2.4](https://github.com/videojs/http-streaming/compare/v1.2.3...v1.2.4) (2018-08-13)
### Bug Fixes
* Remove buffered data on fast quality switches ([#113](https://github.com/videojs/http-streaming/issues/113)) ([bc94fbb](https://github.com/videojs/http-streaming/commit/bc94fbb))
<a name="1.2.3"></a>
## [1.2.3](https://github.com/videojs/http-streaming/compare/v1.2.2...v1.2.3) (2018-08-09)
### Chores
* link to minified example in main page ([#189](https://github.com/videojs/http-streaming/issues/189)) ([15a7f92](https://github.com/videojs/http-streaming/commit/15a7f92))
* use netlify for easier testing ([#188](https://github.com/videojs/http-streaming/issues/188)) ([d2e0d35](https://github.com/videojs/http-streaming/commit/d2e0d35))
<a name="1.2.2"></a>
## [1.2.2](https://github.com/videojs/http-streaming/compare/v1.2.1...v1.2.2) (2018-08-07)
### Bug Fixes
* typeof minification ([#182](https://github.com/videojs/http-streaming/issues/182)) ([7c68335](https://github.com/videojs/http-streaming/commit/7c68335))
* Use middleware and a wrapped function for seeking instead of relying on unreliable 'seeking' events ([#161](https://github.com/videojs/http-streaming/issues/161)) ([6c68761](https://github.com/videojs/http-streaming/commit/6c68761))
### Chores
* add logo ([#184](https://github.com/videojs/http-streaming/issues/184)) ([a55626c](https://github.com/videojs/http-streaming/commit/a55626c))
### Documentation
* add note for Safari captions error ([#174](https://github.com/videojs/http-streaming/issues/174)) ([7b03530](https://github.com/videojs/http-streaming/commit/7b03530))
### Tests
* add support for real segments in tests ([#178](https://github.com/videojs/http-streaming/issues/178)) ([2b07fca](https://github.com/videojs/http-streaming/commit/2b07fca))
<a name="1.2.1"></a>
## [1.2.1](https://github.com/videojs/http-streaming/compare/v1.2.0...v1.2.1) (2018-07-17)
### Bug Fixes
* convert non-latin characters in IE ([#157](https://github.com/videojs/http-streaming/issues/157)) ([17678fb](https://github.com/videojs/http-streaming/commit/17678fb))
<a name="1.2.0"></a>
# [1.2.0](https://github.com/videojs/http-streaming/compare/v1.1.0...v1.2.0) (2018-07-16)
### Features
* **captions:** write in-band captions from DASH fmp4 segments to the textTrack API ([#108](https://github.com/videojs/http-streaming/issues/108)) ([7c11911](https://github.com/videojs/http-streaming/commit/7c11911))
### Chores
* add welcome bot config from video.js ([#150](https://github.com/videojs/http-streaming/issues/150)) ([922cfee](https://github.com/videojs/http-streaming/commit/922cfee))
<a name="1.1.0"></a>
# [1.1.0](https://github.com/videojs/http-streaming/compare/v1.0.2...v1.1.0) (2018-06-06)
### Features
* Utilize option to override native on tech ([#76](https://github.com/videojs/http-streaming/issues/76)) ([5c7ab4c](https://github.com/videojs/http-streaming/commit/5c7ab4c))
### Chores
* update tests and pages for video.js 7 ([#102](https://github.com/videojs/http-streaming/issues/102)) ([d6f5005](https://github.com/videojs/http-streaming/commit/d6f5005))
<a name="1.0.2"></a>
## [1.0.2](https://github.com/videojs/http-streaming/compare/v1.0.1...v1.0.2) (2018-05-17)
### Bug Fixes
* make project Video.js 7 ready ([#92](https://github.com/videojs/http-streaming/issues/92)) ([decad87](https://github.com/videojs/http-streaming/commit/decad87))
* make sure that es build is babelified ([#97](https://github.com/videojs/http-streaming/issues/97)) ([5f0428d](https://github.com/videojs/http-streaming/commit/5f0428d))
### Documentation
* update documentation with a glossary and intro page, added DASH background ([#94](https://github.com/videojs/http-streaming/issues/94)) ([4b0fde9](https://github.com/videojs/http-streaming/commit/4b0fde9))
<a name="1.0.1"></a>
## [1.0.1](https://github.com/videojs/http-streaming/compare/v1.0.0...v1.0.1) (2018-04-12)
### Bug Fixes
* minified build ([#84](https://github.com/videojs/http-streaming/issues/84)) ([2402ac6](https://github.com/videojs/http-streaming/commit/2402ac6))
<a name="1.0.0"></a>
# [1.0.0](https://github.com/videojs/http-streaming/compare/v0.9.0...v1.0.0) (2018-04-10)
### Chores
* sync videojs-contrib-hls updates ([#75](https://github.com/videojs/http-streaming/issues/75)) ([9223588](https://github.com/videojs/http-streaming/commit/9223588))
* update the aes-decrypter ([#71](https://github.com/videojs/http-streaming/issues/71)) ([27ed914](https://github.com/videojs/http-streaming/commit/27ed914))
### Documentation
* update docs for overrideNative ([#77](https://github.com/videojs/http-streaming/issues/77)) ([98ca6d3](https://github.com/videojs/http-streaming/commit/98ca6d3))
* update known issues for fmp4 captions ([#79](https://github.com/videojs/http-streaming/issues/79)) ([c418301](https://github.com/videojs/http-streaming/commit/c418301))
<a name="0.9.0"></a>
# [0.9.0](https://github.com/videojs/http-streaming/compare/v0.8.0...v0.9.0) (2018-03-30)
### Features
* support in-manifest DRM data ([#60](https://github.com/videojs/http-streaming/issues/60)) ([a1cad82](https://github.com/videojs/http-streaming/commit/a1cad82))
<a name="0.8.0"></a>
# [0.8.0](https://github.com/videojs/http-streaming/compare/v0.7.2...v0.8.0) (2018-03-30)
### Code Refactoring
* export corrections ([#68](https://github.com/videojs/http-streaming/issues/68)) ([aab3b90](https://github.com/videojs/http-streaming/commit/aab3b90))
* use rollup for build ([#69](https://github.com/videojs/http-streaming/issues/69)) ([c28c25c](https://github.com/videojs/http-streaming/commit/c28c25c))
# 0.7.0
* feat: Live support for DASH
# 0.6.1
* use webwackify for webworkers to support webpack bundle ([#50](https://github.com/videojs/http-streaming/pull/45))
# 0.5.3
* fix: program date time handling ([#45](https://github.com/videojs/http-streaming/pull/45))
* update m3u8-parser to v4.2.0
* use segment program date time info
* feat: Adding support for segments in Period and Representation ([#47](https://github.com/videojs/http-streaming/pull/47))
* wait for both main and audio loaders for endOfStream if main starting media unknown ([#44](https://github.com/videojs/http-streaming/pull/44))
# 0.5.2
* add debug logging statement for seekable updates ([#40](https://github.com/videojs/http-streaming/pull/40))
# 0.5.1
* Fix audio only streams with EXT-X-MEDIA tags ([#34](https://github.com/videojs/http-streaming/pull/34))
* Merge videojs-contrib-hls master into http-streaming master ([#35](https://github.com/videojs/http-streaming/pull/35))
* Update sinon to 1.10.3=
* Update videojs-contrib-quality-levels to ^2.0.4
* Fix test for event handler cleanup on dispose by calling event handling methods
* fix: Don't reset eme options ([#32](https://github.com/videojs/http-streaming/pull/32))
# 0.5.0
* update mpd-parser to support more segment list types ([#27](https://github.com/videojs/http-streaming/issues/27))
# 0.4.0
* Removed Flash support ([#15](https://github.com/videojs/http-streaming/issues/15))
* Blacklist playlists not supported by browser media source before initial selection ([#17](https://github.com/videojs/http-streaming/issues/17))
# 0.3.1
* Skip flash-based source handler with DASH sources ([#14](https://github.com/videojs/http-streaming/issues/14))
# 0.3.0
* Added additional properties to the stats object ([#10](https://github.com/videojs/http-streaming/issues/10))
# 0.2.1
* Updated the mpd-parser to fix IE11 DASH support ([#12](https://github.com/videojs/http-streaming/issues/12))
# 0.2.0
* Initial DASH Support ([#8](https://github.com/videojs/http-streaming/issues/8))
# 0.1.0
* Initial release, based on [videojs-contrib-hls 5.12.2](https://github.com/videojs/videojs-contrib-hls)

View File

@@ -1,49 +0,0 @@
Copyright 2013 Brightcove
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
The AES decryption implementation in this project is derived from the
Stanford Javascript Cryptography Library
(http://bitwiseshiftleft.github.io/sjcl/). That work is covered by the
following copyright and permission notice:
Copyright 2009-2010 Emily Stark, Mike Hamburg, Dan Boneh.
All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are
met:
1. Redistributions of source code must retain the above copyright
notice, this list of conditions and the following disclaimer.
2. Redistributions in binary form must reproduce the above
copyright notice, this list of conditions and the following
disclaimer in the documentation and/or other materials provided
with the distribution.
THIS SOFTWARE IS PROVIDED BY THE AUTHORS ``AS IS'' AND ANY EXPRESS OR
IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
DISCLAIMED. IN NO EVENT SHALL <COPYRIGHT HOLDER> OR CONTRIBUTORS BE
LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
The views and conclusions contained in the software and documentation
are those of the authors and should not be interpreted as representing
official policies, either expressed or implied, of the authors.

View File

@@ -1,835 +0,0 @@
<img width=300 src="./logo.svg" alt="VHS Logo consisting of a VHS tape, the Video.js logo and the words VHS" />
# videojs-http-streaming (VHS)
[![Build Status][travis-icon]][travis-link]
[![Slack Status][slack-icon]][slack-link]
[![Greenkeeper badge][greenkeeper-icon]][greenkeeper-link]
Play HLS, DASH, and future HTTP streaming protocols with video.js, even where they're not
natively supported.
Included in video.js 7 by default! See the [video.js 7 blog post](https://blog.videojs.com/video-js-7-is-here/)
Maintenance Status: Stable
Video.js Compatibility: 6.0, 7.0
<!-- START doctoc generated TOC please keep comment here to allow auto update -->
<!-- DON'T EDIT THIS SECTION, INSTEAD RE-RUN doctoc TO UPDATE -->
**Table of Contents** *generated with [DocToc](https://github.com/thlorenz/doctoc)*
- [Installation](#installation)
- [NPM](#npm)
- [CDN](#cdn)
- [Releases](#releases)
- [Manual Build](#manual-build)
- [Contributing](#contributing)
- [Troubleshooting](#troubleshooting)
- [Talk to us](#talk-to-us)
- [Getting Started](#getting-started)
- [Compatibility](#compatibility)
- [Via MSE](#via-mse)
- [Native only](#native-only)
- [Flash Support](#flash-support)
- [DRM](#drm)
- [Documentation](#documentation)
- [Options](#options)
- [How to use](#how-to-use)
- [Initialization](#initialization)
- [Source](#source)
- [List](#list)
- [withCredentials](#withcredentials)
- [handleManifestRedirects](#handlemanifestredirects)
- [useCueTags](#usecuetags)
- [overrideNative](#overridenative)
- [blacklistDuration](#blacklistduration)
- [bandwidth](#bandwidth)
- [useBandwidthFromLocalStorage](#usebandwidthfromlocalstorage)
- [enableLowInitialPlaylist](#enablelowinitialplaylist)
- [limitRenditionByPlayerDimensions](#limitrenditionbyplayerdimensions)
- [smoothQualityChange](#smoothqualitychange)
- [allowSeeksWithinUnsafeLiveWindow](#allowseekswithinunsafelivewindow)
- [customTagParsers](#customtagparsers)
- [customTagMappers](#customtagmappers)
- [cacheEncryptionKeys](#cacheencryptionkeys)
- [Runtime Properties](#runtime-properties)
- [hls.playlists.master](#hlsplaylistsmaster)
- [hls.playlists.media](#hlsplaylistsmedia)
- [hls.systemBandwidth](#hlssystembandwidth)
- [hls.bandwidth](#hlsbandwidth)
- [hls.throughput](#hlsthroughput)
- [hls.selectPlaylist](#hlsselectplaylist)
- [hls.representations](#hlsrepresentations)
- [hls.xhr](#hlsxhr)
- [hls.stats](#hlsstats)
- [Events](#events)
- [loadedmetadata](#loadedmetadata)
- [HLS Usage Events](#hls-usage-events)
- [Presence Stats](#presence-stats)
- [Use Stats](#use-stats)
- [In-Band Metadata](#in-band-metadata)
- [Segment Metadata](#segment-metadata)
- [Hosting Considerations](#hosting-considerations)
- [Known Issues](#known-issues)
- [Fragmented MP4 Support](#fragmented-mp4-support)
- [Testing](#testing)
- [Debugging](#debugging)
- [Release History](#release-history)
- [Building](#building)
- [Development](#development)
- [Tools](#tools)
- [Commands](#commands)
<!-- END doctoc generated TOC please keep comment here to allow auto update -->
## Installation
### NPM
To install `videojs-http-streaming` with npm run
```bash
npm install --save @videojs/http-streaming
```
### CDN
Select a version of VHS from the [CDN](https://unpkg.com/@videojs/http-streaming/dist/)
### Releases
Download a release of [videojs-http-streaming](https://github.com/videojs/http-streaming/releases)
### Manual Build
Download a copy of this git repository and then follow the steps in [Building](#building)
## Contributing
See [CONTRIBUTING.md](/CONTRIBUTING.md)
## Troubleshooting
See [our troubleshooting guide](/docs/troubleshooting.md)
## Talk to us
Drop by our slack channel (#playback) on the [Video.js slack][slack-link].
## Getting Started
This library is included in video.js 7 by default, if you are using an older version of video.js then
get a copy of [videojs-http-streaming](#installation) and include it in your page along with video.js:
```html
<video-js id=vid1 width=600 height=300 class="vjs-default-skin" controls>
<source
src="https://example.com/index.m3u8"
type="application/x-mpegURL">
</video-js>
<script src="video.js"></script>
<script src="videojs-http-streaming.min.js"></script>
<script>
var player = videojs('vid1');
player.play();
</script>
```
Check out our [live example](https://jsbin.com/gejugat/edit?html,output) if you're having trouble.
Is it recommended to use the `<video-js>` element or load a source with `player.src(sourceObject)` in order to prevent the video element from playing the source natively where HLS is supported.
## Compatibility
### Via MSE
- Chrome
- Firefox
- Internet Explorer 11 Windows 10 or 8.1
Using the [overrideNative](#overridenative) option
- Chrome Android
- Edge
### Native only
- Mac Safari
- iOS Safari
### Flash Support
This plugin does not support Flash playback. Instead, it is recommended that users use the [videojs-flashls-source-handler](https://github.com/brightcove/videojs-flashls-source-handler) plugin as a fallback option for browsers that don't have a native
[HLS](https://caniuse.com/#feat=http-live-streaming)/[DASH](https://caniuse.com/#feat=mpeg-dash) player or support for [Media Source Extensions](http://caniuse.com/#feat=mediasource).
### DRM
DRM is supported through [videojs-contrib-eme](https://github.com/videojs/videojs-contrib-eme). In order to use DRM, include the videojs-contrib-eme plug, [initialize it](https://github.com/videojs/videojs-contrib-eme#initialization), and add options to either the [plugin](https://github.com/videojs/videojs-contrib-eme#plugin-options) or the [source](https://github.com/videojs/videojs-contrib-eme#source-options).
Detailed option information can be found in the [videojs-contrib-eme README](https://github.com/videojs/videojs-contrib-eme/blob/master/README.md).
## Documentation
[HTTP Live Streaming](https://developer.apple.com/streaming/) (HLS) has
become a de-facto standard for streaming video on mobile devices
thanks to its native support on iOS and Android. There are a number of
reasons independent of platform to recommend the format, though:
- Supports (client-driven) adaptive bitrate selection
- Delivered over standard HTTP ports
- Simple, text-based manifest format
- No proprietary streaming servers required
Unfortunately, all the major desktop browsers except for Safari are
missing HLS support. That leaves web developers in the unfortunate
position of having to maintain alternate renditions of the same video
and potentially having to forego HTML-based video entirely to provide
the best desktop viewing experience.
This project addresses that situation by providing a polyfill for HLS
on browsers that have support for [Media Source
Extensions](http://caniuse.com/#feat=mediasource).
You can deploy a single HLS stream, code against the
regular HTML5 video APIs, and create a fast, high-quality video
experience across all the big web device categories.
Check out the [full documentation](docs/README.md) for details on how HLS works
and advanced configuration. A description of the [adaptive switching
behavior](docs/bitrate-switching.md) is available, too.
videojs-http-streaming supports a bunch of HLS features. Here
are some highlights:
- video-on-demand and live playback modes
- backup or redundant streams
- mid-segment quality switching
- AES-128 segment encryption
- CEA-608 captions are automatically translated into standard HTML5
[caption text tracks][0]
- In-Manifest WebVTT subtitles are automatically translated into standard HTML5
subtitle tracks
- Timed ID3 Metadata is automatically translated into HTML5 metedata
text tracks
- Highly customizable adaptive bitrate selection
- Automatic bandwidth tracking
- Cross-domain credentials support with CORS
- Tight integration with video.js and a philosophy of exposing as much
as possible with standard HTML APIs
- Stream with multiple audio tracks and switching to those audio tracks
(see the docs folder) for info
- Media content in
[fragmented MP4s](https://developer.apple.com/videos/play/wwdc2016/504/)
instead of the MPEG2-TS container format.
[0]: https://developer.mozilla.org/en-US/docs/Web/HTML/Element/track
### Options
#### How to use
##### Initialization
You may pass in an options object to the hls source handler at player
initialization. You can pass in options just like you would for other
parts of video.js:
```javascript
// html5 for html hls
videojs(video, {
html5: {
hls: {
withCredentials: true
}
}
});
```
##### Source
Some options, such as `withCredentials` can be passed in to hls during
`player.src`
```javascript
var player = videojs('some-video-id');
player.src({
src: 'https://d2zihajmogu5jn.cloudfront.net/bipbop-advanced/bipbop_16x9_variant.m3u8',
type: 'application/x-mpegURL',
withCredentials: true
});
```
#### List
##### withCredentials
* Type: `boolean`
* can be used as a source option
* can be used as an initialization option
When the `withCredentials` property is set to `true`, all XHR requests for
manifests and segments would have `withCredentials` set to `true` as well. This
enables storing and passing cookies from the server that the manifests and
segments live on. This has some implications on CORS because when set, the
`Access-Control-Allow-Origin` header cannot be set to `*`, also, the response
headers require the addition of `Access-Control-Allow-Credentials` header which
is set to `true`.
See html5rocks's [article](http://www.html5rocks.com/en/tutorials/cors/)
for more info.
##### handleManifestRedirects
* Type: `boolean`
* Default: `false`
* can be used as a source option
* can be used as an initialization option
When the `handleManifestRedirects` property is set to `true`, manifest requests
which are redirected will have their URL updated to the new URL for future
requests.
##### useCueTags
* Type: `boolean`
* can be used as an initialization option
When the `useCueTags` property is set to `true,` a text track is created with
label 'ad-cues' and kind 'metadata'. The track is then added to
`player.textTracks()`. Changes in active cue may be
tracked by following the Video.js cue points API for text tracks. For example:
```javascript
lettextTracks = player.textTracks();
letcuesTrack;
for (let i = 0; i < textTracks.length; i++) {
if (textTracks[i].label === 'ad-cues') {
cuesTrack = textTracks[i];
}
}
cuesTrack.addEventListener('cuechange', function() {
letactiveCues = cuesTrack.activeCues;
for (let i = 0; i < activeCues.length; i++) {
let activeCue = activeCues[i];
console.log('Cue runs from ' + activeCue.startTime +
' to ' + activeCue.endTime);
}
});
```
##### overrideNative
* Type: `boolean`
* can be used as an initialization option
Try to use videojs-http-streaming even on platforms that provide some
level of HLS support natively. There are a number of platforms that
*technically* play back HLS content but aren't very reliable or are
missing features like CEA-608 captions support. When `overrideNative`
is true, if the platform supports Media Source Extensions
videojs-http-streaming will take over HLS playback to provide a more
consistent experience.
```javascript
// via the constructor
var player = videojs('playerId', {
html5: {
hls: {
overrideNative: true
}
}
});
// via the source
var player = videojs('playerId');
player.src({
src: 'https://example.com/index.m3u8',
type: 'application/x-mpegURL',
overrideNative: true
});
```
##### blacklistDuration
* Type: `number`
* can be used as an initialization option
When the `blacklistDuration` property is set to a time duration in seconds,
if a playlist is blacklisted, it will be blacklisted for a period of that
customized duration. This enables the blacklist duration to be configured
by the user.
##### bandwidth
* Type: `number`
* can be used as an initialization option
When the `bandwidth` property is set (bits per second), it will be used in
the calculation for initial playlist selection, before more bandwidth
information is seen by the player.
##### useBandwidthFromLocalStorage
* Type: `boolean`
* can be used as an initialization option
If true, `bandwidth` and `throughput` values are stored in and retrieved from local
storage on startup (for initial rendition selection). This setting is `false` by default.
##### enableLowInitialPlaylist
* Type: `boolean`
* can be used as an initialization option
When `enableLowInitialPlaylist` is set to true, it will be used to select
the lowest bitrate playlist initially. This helps to decrease playback start time.
This setting is `false` by default.
##### limitRenditionByPlayerDimensions
* Type: `boolean`
* can be used as an initialization option
##### useDevicePixelRatio
* Type: `boolean`
* can be used as an initialization option.
If true, this will take the device pixel ratio into account when doing rendition switching. This means that if you have a player with the width of `540px` in a high density display with a device pixel ratio of 2, a rendition of `1080p` will be allowed.
This setting is `false` by default.
When `limitRenditionByPlayerDimensions` is set to true, rendition
selection logic will take into account the player size and rendition
resolutions when making a decision.
This setting is `true` by default.
##### smoothQualityChange
* Type: `boolean`
* can be used as a source option
* can be used as an initialization option
When the `smoothQualityChange` property is set to `true`, a manual quality
change triggered via the [representations API](#hlsrepresentations) will use
smooth quality switching rather than the default fast (buffer-ejecting)
quality switching. Using smooth quality switching will mean no loading spinner
will appear during quality switches, but will cause quality switches to only
be visible after a few seconds.
Note that this _only_ affects quality changes triggered via the representations
API; automatic quality switches based on available bandwidth will always be
smooth switches.
##### allowSeeksWithinUnsafeLiveWindow
* Type: `boolean`
* can be used as a source option
When `allowSeeksWithinUnsafeLiveWindow` is set to `true`, if the active playlist is live
and a seek is made to a time between the safe live point (end of manifest minus three
times the target duration,
see [the hls spec](https://tools.ietf.org/html/draft-pantos-http-live-streaming-23#section-6.3.3)
for details) and the end of the playlist, the seek is allowed, rather than corrected to
the safe live point.
This option can help in instances where the live stream's target duration is greater than
the segment durations, playback ends up in the unsafe live window, and there are gaps in
the content. In this case the player will attempt to seek past the gaps but end up seeking
inside of the unsafe range, leading to a correction and seek back into a previously played
content.
The property defaults to `false`.
##### customTagParsers
* Type: `Array`
* can be used as a source option
With `customTagParsers` you can pass an array of custom m3u8 tag parser objects. See https://github.com/videojs/m3u8-parser#custom-parsers
##### customTagMappers
* Type: `Array`
* can be used as a source option
Similar to `customTagParsers`, with `customTagMappers` you can pass an array of custom m3u8 tag mapper objects. See https://github.com/videojs/m3u8-parser#custom-parsers
##### cacheEncryptionKeys
* Type: `boolean`
* can be used as a source option
* can be used as an initialization option
This option forces the player to cache AES-128 encryption keys internally instead of requesting the key alongside every segment request.
This option defaults to `false`.
### Runtime Properties
Runtime properties are attached to the tech object when HLS is in
use. You can get a reference to the HLS source handler like this:
```javascript
var hls = player.tech().hls;
```
If you *were* thinking about modifying runtime properties in a
video.js plugin, we'd recommend you avoid it. Your plugin won't work
with videos that don't use videojs-http-streaming and the best plugins
work across all the media types that video.js supports. If you're
deploying videojs-http-streaming on your own website and want to make a
couple tweaks though, go for it!
#### hls.playlists.master
Type: `object`
An object representing the parsed master playlist. If a media playlist
is loaded directly, a master playlist with only one entry will be
created.
#### hls.playlists.media
Type: `function`
A function that can be used to retrieve or modify the currently active
media playlist. The active media playlist is referred to when
additional video data needs to be downloaded. Calling this function
with no arguments returns the parsed playlist object for the active
media playlist. Calling this function with a playlist object from the
master playlist or a URI string as specified in the master playlist
will kick off an asynchronous load of the specified media
playlist. Once it has been retreived, it will become the active media
playlist.
#### hls.systemBandwidth
Type: `number`
`systemBandwidth` is a combination of two serial processes' bitrates. The first
is the network bitrate provided by `bandwidth` and the second is the bitrate of
the entire process after that (decryption, transmuxing, and appending) provided
by `throughput`. This value is used by the default implementation of `selectPlaylist`
to select an appropriate bitrate to play.
Since the two process are serial, the overall system bandwidth is given by:
`systemBandwidth = 1 / (1 / bandwidth + 1 / throughput)`
#### hls.bandwidth
Type: `number`
The number of bits downloaded per second in the last segment download.
Before the first video segment has been downloaded, it's hard to
estimate bandwidth accurately. The HLS tech uses a starting value of 4194304 or 0.5 MB/s. If you
have a more accurate source of bandwidth information, you can override
this value as soon as the HLS tech has loaded to provide an initial
bandwidth estimate.
#### hls.throughput
Type: `number`
The number of bits decrypted, transmuxed, and appended per second as a cumulative average across active processing time.
#### hls.selectPlaylist
Type: `function`
A function that returns the media playlist object to use to download
the next segment. It is invoked by the tech immediately before a new
segment is downloaded. You can override this function to provide your
adaptive streaming logic. You must, however, be sure to return a valid
media playlist object that is present in `player.hls.master`.
Overridding this function with your own is very powerful but is overkill
for many purposes. Most of the time, you should use the much simpler
function below to selectively enable or disable a playlist from the
adaptive streaming logic.
#### hls.representations
Type: `function`
It is recommended to include the [videojs-contrib-quality-levels](https://github.com/videojs/videojs-contrib-quality-levels) plugin to your page so that videojs-http-streaming will automatically populate the QualityLevelList exposed on the player by the plugin. You can access this list by calling `player.qualityLevels()`. See the [videojs-contrib-quality-levels project page](https://github.com/videojs/videojs-contrib-quality-levels) for more information on how to use the api.
Example, only enabling representations with a width greater than or equal to 720:
```javascript
var qualityLevels = player.qualityLevels();
for (var i = 0; i < qualityLevels.length; i++) {
var quality = qualityLevels[i];
if (quality.width >= 720) {
quality.enabled = true;
} else {
quality.enabled = false;
}
}
```
If including [videojs-contrib-quality-levels](https://github.com/videojs/videojs-contrib-quality-levels) is not an option, you can use the representations api. To get all of the available representations, call the `representations()` method on `player.hls`. This will return a list of plain objects, each with `width`, `height`, `bandwidth`, and `id` properties, and an `enabled()` method.
```javascript
player.hls.representations();
```
To see whether the representation is enabled or disabled, call its `enabled()` method with no arguments. To set whether it is enabled/disabled, call its `enabled()` method and pass in a boolean value. Calling `<representation>.enabled(true)` will allow the adaptive bitrate algorithm to select the representation while calling `<representation>.enabled(false)` will disallow any selection of that representation.
Example, only enabling representations with a width greater than or equal to 720:
```javascript
player.hls.representations().forEach(function(rep) {
if (rep.width >= 720) {
rep.enabled(true);
} else {
rep.enabled(false);
}
});
```
#### hls.xhr
Type: `function`
The xhr function that is used by HLS internally is exposed on the per-
player `hls` object. While it is possible, we do not recommend replacing
the function with your own implementation. Instead, the `xhr` provides
the ability to specify a `beforeRequest` function that will be called
with an object containing the options that will be used to create the
xhr request.
Example:
```javascript
player.hls.xhr.beforeRequest = function(options) {
options.uri = options.uri.replace('example.com', 'foo.com');
return options;
};
```
The global `videojs.Hls` also exposes an `xhr` property. Specifying a
`beforeRequest` function on that will allow you to intercept the options
for *all* requests in every player on a page. For consistency across
browsers the video source should be set at runtime once the video player
is ready.
Example
```javascript
videojs.Hls.xhr.beforeRequest = function(options) {
/*
* Modifications to requests that will affect every player.
*/
return options;
};
var player = videojs('video-player-id');
player.ready(function() {
this.src({
src: 'https://d2zihajmogu5jn.cloudfront.net/bipbop-advanced/bipbop_16x9_variant.m3u8',
type: 'application/x-mpegURL',
});
});
```
For information on the type of options that you can modify see the
documentation at [https://github.com/Raynos/xhr](https://github.com/Raynos/xhr).
#### hls.stats
Type: `object`
This object contains a summary of HLS and player related stats.
| Property Name | Type | Description |
| --------------------- | ------ | ----------- |
| bandwidth | number | Rate of the last segment download in bits/second |
| mediaRequests | number | Total number of media segment requests |
| mediaRequestsAborted | number | Total number of aborted media segment requests |
| mediaRequestsTimedout | number | Total number of timedout media segment requests |
| mediaRequestsErrored | number | Total number of errored media segment requests |
| mediaTransferDuration | number | Total time spent downloading media segments in milliseconds |
| mediaBytesTransferred | number | Total number of content bytes downloaded |
| mediaSecondsLoaded | number | Total number of content seconds downloaded |
| buffered | array | List of time ranges of content that are in the SourceBuffer |
| currentTime | number | The current position of the player |
| currentSource | object | The source object. Has the structure `{src: 'url', type: 'mimetype'}` |
| currentTech | string | The name of the tech in use |
| duration | number | Duration of the video in seconds |
| master | object | The [master playlist object](#hlsplaylistsmaster) |
| playerDimensions | object | Contains the width and height of the player |
| seekable | array | List of time ranges that the player can seek to |
| timestamp | number | Timestamp of when `hls.stats` was accessed |
| videoPlaybackQuality | object | Media playback quality metrics as specified by the [W3C's Media Playback Quality API](https://wicg.github.io/media-playback-quality/) |
### Events
Standard HTML video events are handled by video.js automatically and
are triggered on the player object.
#### loadedmetadata
Fired after the first segment is downloaded for a playlist. This will not happen
until playback if video.js's `metadata` setting is `none`
### HLS Usage Events
Usage tracking events are fired when we detect a certain HLS feature, encoding setting,
or API is used. These can be helpful for analytics, and to pinpoint the cause of HLS errors.
For instance, if errors are being fired in tandem with a usage event indicating that the
player was playing an AES encrypted stream, then we have a possible avenue to explore when
debugging the error.
Note that although these usage events are listed below, they may change at any time without
a major version change.
HLS usage events are triggered on the tech with the exception of the 3 hls-reload-error
events, which are triggered on the player.
#### Presence Stats
Each of the following usage events are fired once per source if (and when) detected:
| Name | Description |
| ------------- | ------------- |
| hls-webvtt | master manifest has at least one segmented WebVTT playlist |
| hls-aes | a playlist is AES encrypted |
| hls-fmp4 | a playlist used fMP4 segments |
| hls-demuxed | audio and video are demuxed by default |
| hls-alternate-audio | alternate audio available in the master manifest |
| hls-playlist-cue-tags | a playlist used cue tags (see useCueTags(#usecuetags) for details) |
| hls-bandwidth-from-local-storage | starting bandwidth was retrieved from local storage (see useBandwidthFromLocalStorage(#useBandwidthFromLocalStorage) for details) |
| hls-throughput-from-local-storage | starting throughput was retrieved from local storage (see useBandwidthFromLocalStorage(#useBandwidthFromLocalStorage) for details) |
#### Use Stats
Each of the following usage events are fired per use:
| Name | Description |
| ------------- | ------------- |
| hls-gap-skip | player skipped a gap in the buffer |
| hls-player-access | player.hls was accessed |
| hls-audio-change | a user selected an alternate audio stream |
| hls-rendition-disabled | a rendition was disabled |
| hls-rendition-enabled | a rendition was enabled |
| hls-rendition-blacklisted | a rendition was blacklisted |
| hls-timestamp-offset | a timestamp offset was set in HLS (can identify discontinuities) |
| hls-unknown-waiting | the player stopped for an unknown reason and we seeked to current time try to address it |
| hls-live-resync | playback fell off the back of a live playlist and we resynced to the live point |
| hls-video-underflow | we seeked to current time to address video underflow |
| hls-error-reload-initialized | the reloadSourceOnError plugin was initialized |
| hls-error-reload | the reloadSourceOnError plugin reloaded a source |
| hls-error-reload-canceled | an error occurred too soon after the last reload, so we didn't reload again (to prevent error loops) |
### In-Band Metadata
The HLS tech supports [timed
metadata](https://developer.apple.com/library/ios/#documentation/AudioVideo/Conceptual/HTTP_Live_Streaming_Metadata_Spec/Introduction/Introduction.html)
embedded as [ID3 tags](http://id3.org/id3v2.3.0). When a stream is
encountered with embedded metadata, an [in-band metadata text
track](https://html.spec.whatwg.org/multipage/embedded-content.html#text-track-in-band-metadata-track-dispatch-type)
will automatically be created and populated with cues as they are
encountered in the stream. UTF-8 encoded
[TXXX](http://id3.org/id3v2.3.0#User_defined_text_information_frame)
and [WXXX](http://id3.org/id3v2.3.0#User_defined_URL_link_frame) ID3
frames are mapped to cue points and their values set as the cue
text. Cues are created for all other frame types and the data is
attached to the generated cue:
```javascript
cue.value.data
```
There are lots of guides and references to using text tracks [around
the web](http://www.html5rocks.com/en/tutorials/track/basics/).
### Segment Metadata
You can get metadata about the segments currently in the buffer by using the `segment-metadata`
text track. You can get the metadata of the currently rendered segment by looking at the
track's `activeCues` array. The metadata will be attached to the `cue.value` property and
will have this structure
```javascript
cue.value = {
byteLength, // The size of the segment in bytes
bandwidth, // The peak bitrate reported by the segment's playlist
resolution, // The resolution reported by the segment's playlist
codecs, // The codecs reported by the segment's playlist
uri, // The Segment uri
timeline, // Timeline of the segment for detecting discontinuities
playlist, // The Playlist uri
start, // Segment start time
end // Segment end time
};
```
Example:
Detect when a change in quality is rendered on screen
```javascript
let tracks = player.textTracks();
let segmentMetadataTrack;
for (let i = 0; i < tracks.length; i++) {
if (tracks[i].label === 'segment-metadata') {
segmentMetadataTrack = tracks[i];
}
}
let previousPlaylist;
if (segmentMetadataTrack) {
segmentMetadataTrack.on('cuechange', function() {
let activeCue = segmentMetadataTrack.activeCues[0];
if (activeCue) {
if (previousPlaylist !== activeCue.value.playlist) {
console.log('Switched from rendition ' + previousPlaylist +
' to rendition ' + activeCue.value.playlist);
}
previousPlaylist = activeCue.value.playlist;
}
});
}
```
## Hosting Considerations
Unlike a native HLS implementation, the HLS tech has to comply with
the browser's security policies. That means that all the files that
make up the stream must be served from the same domain as the page
hosting the video player or from a server that has appropriate [CORS
headers](https://developer.mozilla.org/en-US/docs/HTTP/Access_control_CORS)
configured. Easy [instructions are
available](http://enable-cors.org/server.html) for popular webservers
and most CDNs should have no trouble turning CORS on for your account.
## Known Issues
Issues that are currenty known. If you want to
help find a solution that would be appreciated!
### Fragmented MP4 Support
Edge has native support for HLS but only in the MPEG2-TS container. If
you attempt to play an HLS stream with fragmented MP4 segments, Edge
will stall. Fragmented MP4s are only supported on browser that have
[Media Source Extensions](http://caniuse.com/#feat=mediasource) available.
## Testing
For testing, you run `npm run test`. You will need Chrome and Firefox for running the tests.
_videojs-http-streaming uses [BrowserStack](https://browserstack.com) for compatibility testing._
## Debugging
videojs-http-streaming makes use of `videojs.log` for debug logging. You can enable these logs
by setting the log level to `debug` using `videojs.log.level('debug')`. You can access a complete
history of the logs using `videojs.log.history()`. This history is maintained even when the
log level is not set to `debug`.
`hls.stats` can also be helpful when debugging. Accessing this object will give you
a snapshot summary of various HLS and player stats. See [hls.stats](#hlsstats) for details
about what this object contains.
__NOTE__: The `debug` level is only available in video.js v6.6.0+. With earlier versions of
video.js, no debug messages will be logged to console.
## Release History
Check out the [changelog](CHANGELOG.md) for a summary of each release.
## Building
To build a copy of videojs-http-streaming run the following commands
```bash
git clone https://github.com/videojs/http-streaming
cd http-streaming
npm i
npm run build
```
videojs-http-streaming will have created all of the files for using it in a dist folder
## Development
### Tools
* Download stream locally with the [HLS Fetcher](https://github.com/videojs/hls-fetcher)
* Simulate errors with [Murphy](https://github.com/videojs/murphy)
* Inspect content with [Thumbcoil](http://thumb.co.il)
### Commands
All commands for development are listed in the `package.json` file and are run using
```bash
npm run <command>
```
[slack-icon]: http://slack.videojs.com/badge.svg
[slack-link]: http://slack.videojs.com
[travis-icon]: https://travis-ci.org/videojs/http-streaming.svg?branch=master
[travis-link]: https://travis-ci.org/videojs/http-streaming
[issue-stats-link]: http://issuestats.com/github/videojs/http-streaming
[issue-stats-pr-icon]: http://issuestats.com/github/videojs/http-streaming/badge/pr
[issue-stats-issues-icon]: http://issuestats.com/github/videojs/http-streaming/badge/issue
[greenkeeper-icon]: https://badges.greenkeeper.io/videojs/http-streaming.svg
[greenkeeper-link]: https://greenkeeper.io/

View File

@@ -1,161 +0,0 @@
{
"_args": [
[
"@videojs/http-streaming@1.13.2",
"/home/runner/work/owncast/owncast/build/javascript"
]
],
"_from": "@videojs/http-streaming@1.13.2",
"_id": "@videojs/http-streaming@1.13.2",
"_inBundle": false,
"_integrity": "sha512-U4Xhh+HxGpRBx9Gm0LlEadq85k9BwckzFgZmyhacauhK/27Mz0goKKFAt+BpxBNp2oHVdAdk8NHfneinsqni3Q==",
"_location": "/video.js/@videojs/http-streaming",
"_phantomChildren": {},
"_requested": {
"type": "version",
"registry": true,
"raw": "@videojs/http-streaming@1.13.2",
"name": "@videojs/http-streaming",
"escapedName": "@videojs%2fhttp-streaming",
"scope": "@videojs",
"rawSpec": "1.13.2",
"saveSpec": null,
"fetchSpec": "1.13.2"
},
"_requiredBy": [
"/video.js"
],
"_resolved": "https://registry.npmjs.org/@videojs/http-streaming/-/http-streaming-1.13.2.tgz",
"_spec": "1.13.2",
"_where": "/home/runner/work/owncast/owncast/build/javascript",
"author": {
"name": "Brightcove, Inc"
},
"bugs": {
"url": "https://github.com/videojs/http-streaming/issues"
},
"dependencies": {
"aes-decrypter": "3.0.0",
"global": "^4.3.0",
"m3u8-parser": "4.4.0",
"mpd-parser": "0.10.0",
"mux.js": "5.5.1",
"url-toolkit": "^2.1.3",
"video.js": "^6.8.0 || ^7.0.0"
},
"description": "Play back HLS and DASH with Video.js, even where it's not natively supported",
"devDependencies": {
"@gkatsev/rollup-plugin-bundle-worker": "^1.0.2",
"babel-core": "^6.26.0",
"babel-plugin-external-helpers": "^6.22.0",
"babel-preset-env": "^1.6.1",
"chg": "^0.3.3",
"connect": "^3.6.6",
"conventional-changelog-cli": "^1.3.20",
"conventional-changelog-videojs": "^3.0.0",
"cowsay": "^1.3.0",
"d3": "^3.4.8",
"doctoc": "^0.15.0",
"in-publish": "^2.0.0",
"jsdoc": "^3.4.0",
"karma": "^1.7.1",
"karma-browserstack-launcher": "~1.4.0",
"karma-chrome-launcher": "^2.2.0",
"karma-coverage": "^1.1.1",
"karma-detect-browsers": "^2.2.6",
"karma-firefox-launcher": "^1.1.0",
"karma-qunit": "^1.2.1",
"karma-safari-launcher": "^1.0.0",
"karma-safaritechpreview-launcher": "0.0.6",
"karma-spec-reporter": "0.0.32",
"lodash": "^4.17.4",
"lodash-compat": "^3.10.0",
"nomnoml": "^0.3.0",
"npm-run-all": "^4.1.5",
"portscanner": "^2.1.1",
"qunitjs": "^2.0.1",
"rollup": "^0.57.1",
"rollup-plugin-babel": "^3.0.3",
"rollup-plugin-commonjs": "^9.1.0",
"rollup-plugin-json": "^2.3.0",
"rollup-plugin-multi-entry": "^2.0.2",
"rollup-plugin-node-resolve": "^3.3.0",
"rollup-plugin-uglify": "^3.0.0",
"rollup-watch": "^4.3.1",
"semver": "^5.5.0",
"serve-static": "^1.13.2",
"shelljs": "^0.8.2",
"sinon": "~1.10.3",
"uglify-es": "^3.3.9",
"videojs-contrib-eme": "^3.2.0",
"videojs-contrib-quality-levels": "^2.0.4",
"videojs-standard": "^4.0.3"
},
"files": [
"dist/"
],
"homepage": "https://github.com/videojs/http-streaming#readme",
"keywords": [
"videojs",
"videojs-plugin"
],
"license": "Apache-2.0",
"main": "dist/videojs-http-streaming.cjs.js",
"module": "dist/videojs-http-streaming.es.js",
"name": "@videojs/http-streaming",
"repository": {
"type": "git",
"url": "git+ssh://git@github.com/videojs/http-streaming.git"
},
"scripts": {
"build": "run-s build:webworker build:js",
"build:js": "rollup -c scripts/rollup.config.js",
"build:test:js": "rollup -c scripts/test.rollup.config.js",
"build:test:manifest": "node -e \"var b=require('./scripts/manifest-data.js'); b.build();\"",
"build:test:segments": "node -e \"var b=require('./scripts/segments-data.js'); b.build();\"",
"build:webworker": "rollup -c scripts/webworker.rollup.config.js",
"clean": "run-p clean:dist clean:test",
"clean:dist": "rimraf dist dist-test",
"clean:test": "node scripts/clean-tests.js",
"docs": "run-p docs:*",
"docs:api": "jsdoc src -r -d docs/api",
"docs:nomnoml:build": "node -e \"var b=require('./scripts/nomnoml.js'); b.build();\"",
"docs:toc": "doctoc README.md",
"lint": "vjsstandard | grep -v \"maximum\\|todo\\|loop\"",
"netlify": "node scripts/netlify.js",
"postclean": "mkdirp dist",
"prebuild": "npm run clean",
"prebuild:test:js": "run-s build:webworker build:test:manifest build:test:segments",
"prenetlify": "npm run build",
"prepublish": "in-publish && npm run build || not-in-publish",
"prestart": "npm run build",
"pretest": "run-s lint build:test:js",
"preversion": "npm test",
"start": "run-p start:server watch",
"start:server": "node scripts/server.js",
"test": "karma start test/karma.conf.js",
"version": "node scripts/version.js",
"watch": "run-p watch:js watch:test:manifest watch:test:segments watch:test:js watch:js:switcher watch:js-webworker",
"watch:js": "rollup -c scripts/rollup.config.js -w",
"watch:js-webworker": "rollup -c scripts/webworker.rollup.config.js -w",
"watch:js:switcher": "rollup -c scripts/switcher.rollup.config.js -w",
"watch:test:js": "rollup -c scripts/test.rollup.config.js -w",
"watch:test:manifest": "node -e \"var b=require('./scripts/manifest-data.js'); b.watch();\"",
"watch:test:segments": "node -e \"var b=require('./scripts/segments-data.js'); b.watch();\""
},
"version": "1.13.2",
"vjsstandard": {
"ignore": [
"es5",
"dist",
"dist-test",
"docs",
"test/karma.conf.js",
"scripts",
"utils",
"test/test-manifests.js",
"test/test-segments.js",
"*.worker.*"
]
}
}

View File

@@ -1,36 +0,0 @@
<a name="1.3.0"></a>
# [1.3.0](https://github.com/videojs/vhs-utils/compare/v1.2.1...v1.3.0) (2020-02-05)
### Features
* add forEachMediaGroup in media-groups module (#8) ([a1eacf4](https://github.com/videojs/vhs-utils/commit/a1eacf4)), closes [#8](https://github.com/videojs/vhs-utils/issues/8)
<a name="1.2.1"></a>
## [1.2.1](https://github.com/videojs/vhs-utils/compare/v1.2.0...v1.2.1) (2020-01-15)
### Bug Fixes
* include videojs in VHS JSON media type (#7) ([da072f0](https://github.com/videojs/vhs-utils/commit/da072f0)), closes [#7](https://github.com/videojs/vhs-utils/issues/7)
<a name="1.2.0"></a>
# [1.2.0](https://github.com/videojs/vhs-utils/compare/v1.1.0...v1.2.0) (2019-12-06)
### Features
* add media-types module with simpleTypeFromSourceType function (#4) ([d3ebd3f](https://github.com/videojs/vhs-utils/commit/d3ebd3f)), closes [#4](https://github.com/videojs/vhs-utils/issues/4)
* add VHS codec parsing and translation functions (#5) ([4fe0e22](https://github.com/videojs/vhs-utils/commit/4fe0e22)), closes [#5](https://github.com/videojs/vhs-utils/issues/5)
<a name="1.1.0"></a>
# [1.1.0](https://github.com/videojs/stream/compare/v1.0.0...v1.1.0) (2019-08-30)
### Features
* node support and more stream tests ([315ab8d](https://github.com/videojs/stream/commit/315ab8d))
<a name="1.0.0"></a>
# 1.0.0 (2019-08-21)
### Features
* clones from mpd-parser, m3u8-parser, mux.js, aes-decrypter, and vhs ([5e89042](https://github.com/videojs/stream/commit/5e89042))

View File

@@ -1,30 +0,0 @@
# CONTRIBUTING
We welcome contributions from everyone!
## Getting Started
Make sure you have Node.js 8 or higher and npm installed.
1. Fork this repository and clone your fork
1. Install dependencies: `npm install`
1. Run a development server: `npm start`
### Making Changes
Refer to the [video.js plugin conventions][conventions] for more detail on best practices and tooling for video.js plugin authorship.
When you've made your changes, push your commit(s) to your fork and issue a pull request against the original repository.
### Running Tests
Testing is a crucial part of any software project. For all but the most trivial changes (typos, etc) test cases are expected. Tests are run in actual browsers using [Karma][karma].
- In all available and supported browsers: `npm test`
- In a specific browser: `npm run test:chrome`, `npm run test:firefox`, etc.
- While development server is running (`npm start`), navigate to [`http://localhost:9999/test/`][local]
[karma]: http://karma-runner.github.io/
[local]: http://localhost:9999/test/
[conventions]: https://github.com/videojs/generator-videojs-plugin/blob/master/docs/conventions.md

View File

@@ -1,19 +0,0 @@
Copyright (c) brandonocasey <brandonocasey@gmail.com>
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.

View File

@@ -1,29 +0,0 @@
<!-- START doctoc generated TOC please keep comment here to allow auto update -->
<!-- DON'T EDIT THIS SECTION, INSTEAD RE-RUN doctoc TO UPDATE -->
- [@videojs/vhs-utils](#videojsvhs-utils)
- [Installation](#installation)
- [Usage](#usage)
<!-- END doctoc generated TOC please keep comment here to allow auto update -->
# @videojs/vhs-utils
vhs-utils serves two purposes:
1. It extracts objects and functions shared throughout @videojs/http-streaming code to save on package size. See [the original @videojs/http-streaming PR](https://github.com/videojs/http-streaming/pull/637) for details.
2. It exports generic functions from VHS that may be useful to plugin authors.
## Installation
```sh
npm install --save @videojs/vhs-utils
```
## Usage
All utility functions are published under dist and can be required/imported like so:
`import resolveUrl from '@videojs/vhs-utils/dist/resolve-url';`
`const resolveUrl = require('@videojs/vhs-utils/dist/resolve-url');`

View File

@@ -1,27 +0,0 @@
<!doctype html>
<html>
<head>
<meta charset="utf-8">
<title>videojs-stream Demo</title>
<link href="node_modules/video.js/dist/video-js.css" rel="stylesheet">
</head>
<body>
<video id="videojs-stream-player" class="video-js vjs-default-skin" controls>
<source src="//vjs.zencdn.net/v/oceans.mp4" type='video/mp4'>
<source src="//vjs.zencdn.net/v/oceans.webm" type='video/webm'>
</video>
<ul>
<li><a href="/test/debug.html">Run unit tests in browser.</a></li>
</ul>
<script src="node_modules/video.js/dist/video.js"></script>
<script src="dist/videojs-stream.js"></script>
<script>
(function(window, videojs) {
var examplePlayer = window.examplePlayer = videojs('videojs-stream-player');
var stream = window.stream = examplePlayer.stream();
}(window, window.videojs));
</script>
</body>
</html>

View File

@@ -1,120 +0,0 @@
{
"_args": [
[
"@videojs/vhs-utils@1.3.0",
"/home/runner/work/owncast/owncast/build/javascript"
]
],
"_from": "@videojs/vhs-utils@1.3.0",
"_id": "@videojs/vhs-utils@1.3.0",
"_inBundle": false,
"_integrity": "sha512-oiqXDtHQqDPun7JseWkirUHGrgdYdeF12goUut5z7vwAj4DmUufEPFJ4xK5hYGXGFDyDhk2rSFOR122Ze6qXyQ==",
"_location": "/video.js/@videojs/vhs-utils",
"_phantomChildren": {},
"_requested": {
"type": "version",
"registry": true,
"raw": "@videojs/vhs-utils@1.3.0",
"name": "@videojs/vhs-utils",
"escapedName": "@videojs%2fvhs-utils",
"scope": "@videojs",
"rawSpec": "1.3.0",
"saveSpec": null,
"fetchSpec": "1.3.0"
},
"_requiredBy": [
"/video.js/mpd-parser"
],
"_resolved": "https://registry.npmjs.org/@videojs/vhs-utils/-/vhs-utils-1.3.0.tgz",
"_spec": "1.3.0",
"_where": "/home/runner/work/owncast/owncast/build/javascript",
"author": {
"name": "brandonocasey",
"email": "brandonocasey@gmail.com"
},
"browserslist": [
"defaults",
"ie 11"
],
"dependencies": {
"@babel/runtime": "^7.5.5",
"global": "^4.3.2",
"url-toolkit": "^2.1.6"
},
"description": "Objects and functions shared throughtout @videojs/http-streaming code",
"devDependencies": {
"@videojs/generator-helpers": "~1.2.0",
"karma": "^4.0.0",
"rollup": "^1.12.0",
"sinon": "^7.2.2",
"videojs-generate-karma-config": "~5.3.0",
"videojs-generate-rollup-config": "~5.0.0",
"videojs-generator-verify": "~1.2.0",
"videojs-standard": "^8.0.3"
},
"engines": {
"node": ">=8",
"npm": ">=5"
},
"files": [
"CONTRIBUTING.md",
"dist/",
"docs/",
"index.html",
"scripts/",
"src/",
"test/"
],
"generator-videojs-plugin": {
"version": "7.7.1"
},
"husky": {
"hooks": {
"pre-commit": "lint-staged"
}
},
"keywords": [
"videojs",
"videojs-plugin"
],
"license": "MIT",
"lint-staged": {
"*.js": [
"vjsstandard --fix",
"git add"
],
"README.md": [
"doctoc --notitle",
"git add"
]
},
"name": "@videojs/vhs-utils",
"scripts": {
"build": "npm-run-all -s clean -p build:*",
"build-prod": "cross-env-shell NO_TEST_BUNDLE=1 'npm run build'",
"build-test": "cross-env-shell TEST_BUNDLE_ONLY=1 'npm run build'",
"build:js": "rollup -c scripts/rollup.config.js",
"clean": "shx rm -rf ./dist ./test/dist && shx mkdir -p ./dist ./test/dist",
"lint": "vjsstandard",
"posttest": "shx cat test/dist/coverage/text.txt",
"prepublishOnly": "npm-run-all build-prod && vjsverify --verbose --skip-es-check",
"preversion": "npm test",
"server": "karma start scripts/karma.conf.js --singleRun=false --auto-watch",
"start": "npm-run-all -p server watch",
"test": "npm-run-all lint build-test && npm-run-all test:*",
"test:browser": "karma start scripts/karma.conf.js",
"test:node": "qunit test/dist/bundle.js",
"update-changelog": "conventional-changelog -p videojs -i CHANGELOG.md -s",
"version": "is-prerelease || npm run update-changelog && git add CHANGELOG.md",
"watch": "npm-run-all -p watch:*",
"watch:js": "npm run build:js -- -w"
},
"version": "1.3.0",
"vjsstandard": {
"ignore": [
"dist",
"docs",
"test/dist"
]
}
}

View File

@@ -1,12 +0,0 @@
const generate = require('videojs-generate-karma-config');
module.exports = function(config) {
// see https://github.com/videojs/videojs-generate-karma-config
// for options
const options = {};
config = generate(config, options);
// any other custom stuff not supported by options here!
};

View File

@@ -1,42 +0,0 @@
const generate = require('videojs-generate-rollup-config');
const fs = require('fs');
const path = require('path');
const BASE_DIR = path.join(__dirname, '..');
const SRC_DIR = path.join(BASE_DIR, 'src');
const files = fs.readdirSync(SRC_DIR);
const shared = {
externals(defaults) {
defaults.module.push('url-toolkit');
return defaults;
}
};
const builds = [];
files.forEach(function(file, i) {
const config = generate(Object.assign({}, shared, {
input: path.relative(BASE_DIR, path.join(SRC_DIR, file)),
distName: path.basename(file, path.extname(file))
}));
// gaurd against test only builds
if (config.builds.module) {
const module = config.builds.module;
module.output = module.output.filter((o) => o.format === 'cjs');
module.output[0].file = module.output[0].file.replace('.cjs.js', '.js');
builds.push(module);
}
// gaurd against production only builds
// only add the last test bundle we generate as they are all the same
if (i === (files.length - 1) && config.builds.test) {
builds.push(config.builds.test);
}
});
// export the builds to rollup
export default builds;

View File

@@ -1,130 +0,0 @@
/**
* Replace the old apple-style `avc1.<dd>.<dd>` codec string with the standard
* `avc1.<hhhhhh>`
*
* @param {string} codec
* Codec string to translate
* @return {string}
* The translated codec string
*/
export const translateLegacyCodec = function(codec) {
if (!codec) {
return codec;
}
return codec.replace(/avc1\.(\d+)\.(\d+)/i, function(orig, profile, avcLevel) {
const profileHex = ('00' + Number(profile).toString(16)).slice(-2);
const avcLevelHex = ('00' + Number(avcLevel).toString(16)).slice(-2);
return 'avc1.' + profileHex + '00' + avcLevelHex;
});
};
/**
* Replace the old apple-style `avc1.<dd>.<dd>` codec strings with the standard
* `avc1.<hhhhhh>`
*
* @param {string[]} codecs
* An array of codec strings to translate
* @return {string[]}
* The translated array of codec strings
*/
export const translateLegacyCodecs = function(codecs) {
return codecs.map(translateLegacyCodec);
};
/**
* Replace codecs in the codec string with the old apple-style `avc1.<dd>.<dd>` to the
* standard `avc1.<hhhhhh>`.
*
* @param {string} codecString
* The codec string
* @return {string}
* The codec string with old apple-style codecs replaced
*
* @private
*/
export const mapLegacyAvcCodecs = function(codecString) {
return codecString.replace(/avc1\.(\d+)\.(\d+)/i, (match) => {
return translateLegacyCodecs([match])[0];
});
};
/**
* @typedef {Object} ParsedCodecInfo
* @property {number} codecCount
* Number of codecs parsed
* @property {string} [videoCodec]
* Parsed video codec (if found)
* @property {string} [videoObjectTypeIndicator]
* Video object type indicator (if found)
* @property {string|null} audioProfile
* Audio profile
*/
/**
* Parses a codec string to retrieve the number of codecs specified, the video codec and
* object type indicator, and the audio profile.
*
* @param {string} [codecs]
* The codec string to parse
* @return {ParsedCodecInfo}
* Parsed codec info
*/
export const parseCodecs = function(codecs = '') {
const result = {
codecCount: 0
};
result.codecCount = codecs.split(',').length;
result.codecCount = result.codecCount || 2;
// parse the video codec
const parsed = (/(^|\s|,)+(avc[13])([^ ,]*)/i).exec(codecs);
if (parsed) {
result.videoCodec = parsed[2];
result.videoObjectTypeIndicator = parsed[3];
}
// parse the last field of the audio codec
result.audioProfile =
(/(^|\s|,)+mp4a.[0-9A-Fa-f]+\.([0-9A-Fa-f]+)/i).exec(codecs);
result.audioProfile = result.audioProfile && result.audioProfile[2];
return result;
};
/**
* Returns a ParsedCodecInfo object for the default alternate audio playlist if there is
* a default alternate audio playlist for the provided audio group.
*
* @param {Object} master
* The master playlist
* @param {string} audioGroupId
* ID of the audio group for which to find the default codec info
* @return {ParsedCodecInfo}
* Parsed codec info
*/
export const audioProfileFromDefault = (master, audioGroupId) => {
if (!master.mediaGroups.AUDIO || !audioGroupId) {
return null;
}
const audioGroup = master.mediaGroups.AUDIO[audioGroupId];
if (!audioGroup) {
return null;
}
for (const name in audioGroup) {
const audioType = audioGroup[name];
if (audioType.default && audioType.playlists) {
// codec should be the same for all playlists within the audio type
return parseCodecs(audioType.playlists[0].attributes.CODECS).audioProfile;
}
}
return null;
};

View File

@@ -1,13 +0,0 @@
import window from 'global/window';
const atob = (s) => window.atob ? window.atob(s) : Buffer.from(s, 'base64').toString('binary');
export default function decodeB64ToUint8Array(b64Text) {
const decodedString = atob(b64Text);
const array = new Uint8Array(decodedString.length);
for (let i = 0; i < decodedString.length; i++) {
array[i] = decodedString.charCodeAt(i);
}
return array;
}

View File

@@ -1,22 +0,0 @@
/**
* Loops through all supported media groups in master and calls the provided
* callback for each group
*
* @param {Object} master
* The parsed master manifest object
* @param {string[]} groups
* The media groups to call the callback for
* @param {Function} callback
* Callback to call for each media group
*/
export const forEachMediaGroup = (master, groups, callback) => {
groups.forEach((mediaType) => {
for (const groupKey in master.mediaGroups[mediaType]) {
for (const labelKey in master.mediaGroups[mediaType][groupKey]) {
const mediaProperties = master.mediaGroups[mediaType][groupKey][labelKey];
callback(mediaProperties, mediaType, groupKey, labelKey);
}
}
});
};

View File

@@ -1,36 +0,0 @@
const MPEGURL_REGEX = /^(audio|video|application)\/(x-|vnd\.apple\.)?mpegurl/i;
const DASH_REGEX = /^application\/dash\+xml/i;
/**
* Returns a string that describes the type of source based on a video source object's
* media type.
*
* @see {@link https://dev.w3.org/html5/pf-summary/video.html#dom-source-type|Source Type}
*
* @param {string} type
* Video source object media type
* @return {('hls'|'dash'|'vhs-json'|null)}
* VHS source type string
*/
export const simpleTypeFromSourceType = (type) => {
if (MPEGURL_REGEX.test(type)) {
return 'hls';
}
if (DASH_REGEX.test(type)) {
return 'dash';
}
// Denotes the special case of a manifest object passed to http-streaming instead of a
// source URL.
//
// See https://en.wikipedia.org/wiki/Media_type for details on specifying media types.
//
// In this case, vnd stands for vendor, video.js for the organization, VHS for this
// project, and the +json suffix identifies the structure of the media type.
if (type === 'application/vnd.videojs.vhs+json') {
return 'vhs-json';
}
return null;
};

View File

@@ -1,18 +0,0 @@
import URLToolkit from 'url-toolkit';
import window from 'global/window';
const resolveUrl = (baseUrl, relativeUrl) => {
// return early if we don't need to resolve
if ((/^[a-z]+:/i).test(relativeUrl)) {
return relativeUrl;
}
// if the base URL is relative then combine with the current location
if (!(/\/\//i).test(baseUrl)) {
baseUrl = URLToolkit.buildAbsoluteURL(window.location && window.location.href || '', baseUrl);
}
return URLToolkit.buildAbsoluteURL(baseUrl, relativeUrl);
};
export default resolveUrl;

View File

@@ -1,108 +0,0 @@
/**
* @file stream.js
*/
/**
* A lightweight readable stream implemention that handles event dispatching.
*
* @class Stream
*/
export default class Stream {
constructor() {
this.listeners = {};
}
/**
* Add a listener for a specified event type.
*
* @param {string} type the event name
* @param {Function} listener the callback to be invoked when an event of
* the specified type occurs
*/
on(type, listener) {
if (!this.listeners[type]) {
this.listeners[type] = [];
}
this.listeners[type].push(listener);
}
/**
* Remove a listener for a specified event type.
*
* @param {string} type the event name
* @param {Function} listener a function previously registered for this
* type of event through `on`
* @return {boolean} if we could turn it off or not
*/
off(type, listener) {
if (!this.listeners[type]) {
return false;
}
const index = this.listeners[type].indexOf(listener);
// TODO: which is better?
// In Video.js we slice listener functions
// on trigger so that it does not mess up the order
// while we loop through.
//
// Here we slice on off so that the loop in trigger
// can continue using it's old reference to loop without
// messing up the order.
this.listeners[type] = this.listeners[type].slice(0);
this.listeners[type].splice(index, 1);
return index > -1;
}
/**
* Trigger an event of the specified type on this stream. Any additional
* arguments to this function are passed as parameters to event listeners.
*
* @param {string} type the event name
*/
trigger(type) {
const callbacks = this.listeners[type];
if (!callbacks) {
return;
}
// Slicing the arguments on every invocation of this method
// can add a significant amount of overhead. Avoid the
// intermediate object creation for the common case of a
// single callback argument
if (arguments.length === 2) {
const length = callbacks.length;
for (let i = 0; i < length; ++i) {
callbacks[i].call(this, arguments[1]);
}
} else {
const args = Array.prototype.slice.call(arguments, 1);
const length = callbacks.length;
for (let i = 0; i < length; ++i) {
callbacks[i].apply(this, args);
}
}
}
/**
* Destroys the stream and cleans up.
*/
dispose() {
this.listeners = {};
}
/**
* Forwards all `data` events on this stream to the destination stream. The
* destination stream should provide a method `push` to receive the data
* events as they arrive.
*
* @param {Stream} destination the stream that will receive all `data` events
* @see http://nodejs.org/api/stream.html#stream_readable_pipe_destination_options
*/
pipe(destination) {
this.on('data', function(data) {
destination.push(data);
});
}
}

View File

@@ -1,242 +0,0 @@
import QUnit from 'qunit';
import {
mapLegacyAvcCodecs,
translateLegacyCodecs,
parseCodecs,
audioProfileFromDefault
} from '../src/codecs';
QUnit.module('Legacy Codecs');
QUnit.test('maps legacy AVC codecs', function(assert) {
assert.equal(
mapLegacyAvcCodecs('avc1.deadbeef'),
'avc1.deadbeef',
'does nothing for non legacy pattern'
);
assert.equal(
mapLegacyAvcCodecs('avc1.dead.beef, mp4a.something'),
'avc1.dead.beef, mp4a.something',
'does nothing for non legacy pattern'
);
assert.equal(
mapLegacyAvcCodecs('avc1.dead.beef,mp4a.something'),
'avc1.dead.beef,mp4a.something',
'does nothing for non legacy pattern'
);
assert.equal(
mapLegacyAvcCodecs('mp4a.something,avc1.dead.beef'),
'mp4a.something,avc1.dead.beef',
'does nothing for non legacy pattern'
);
assert.equal(
mapLegacyAvcCodecs('mp4a.something, avc1.dead.beef'),
'mp4a.something, avc1.dead.beef',
'does nothing for non legacy pattern'
);
assert.equal(
mapLegacyAvcCodecs('avc1.42001e'),
'avc1.42001e',
'does nothing for non legacy pattern'
);
assert.equal(
mapLegacyAvcCodecs('avc1.4d0020,mp4a.40.2'),
'avc1.4d0020,mp4a.40.2',
'does nothing for non legacy pattern'
);
assert.equal(
mapLegacyAvcCodecs('mp4a.40.2,avc1.4d0020'),
'mp4a.40.2,avc1.4d0020',
'does nothing for non legacy pattern'
);
assert.equal(
mapLegacyAvcCodecs('mp4a.40.40'),
'mp4a.40.40',
'does nothing for non video codecs'
);
assert.equal(
mapLegacyAvcCodecs('avc1.66.30'),
'avc1.42001e',
'translates legacy video codec alone'
);
assert.equal(
mapLegacyAvcCodecs('avc1.66.30, mp4a.40.2'),
'avc1.42001e, mp4a.40.2',
'translates legacy video codec when paired with audio'
);
assert.equal(
mapLegacyAvcCodecs('mp4a.40.2, avc1.66.30'),
'mp4a.40.2, avc1.42001e',
'translates video codec when specified second'
);
});
QUnit.test('translates legacy codecs', function(assert) {
assert.deepEqual(
translateLegacyCodecs(['avc1.66.30', 'avc1.66.30']),
['avc1.42001e', 'avc1.42001e'],
'translates legacy avc1.66.30 codec'
);
assert.deepEqual(
translateLegacyCodecs(['avc1.42C01E', 'avc1.42C01E']),
['avc1.42C01E', 'avc1.42C01E'],
'does not translate modern codecs'
);
assert.deepEqual(
translateLegacyCodecs(['avc1.42C01E', 'avc1.66.30']),
['avc1.42C01E', 'avc1.42001e'],
'only translates legacy codecs when mixed'
);
assert.deepEqual(
translateLegacyCodecs(['avc1.4d0020', 'avc1.100.41', 'avc1.77.41',
'avc1.77.32', 'avc1.77.31', 'avc1.77.30',
'avc1.66.30', 'avc1.66.21', 'avc1.42C01e']),
['avc1.4d0020', 'avc1.640029', 'avc1.4d0029',
'avc1.4d0020', 'avc1.4d001f', 'avc1.4d001e',
'avc1.42001e', 'avc1.420015', 'avc1.42C01e'],
'translates a whole bunch'
);
});
QUnit.module('parseCodecs');
QUnit.test('parses video only codec string', function(assert) {
assert.deepEqual(
parseCodecs('avc1.42001e'),
{
codecCount: 1,
videoCodec: 'avc1',
videoObjectTypeIndicator: '.42001e',
audioProfile: null
},
'parsed video only codec string'
);
});
QUnit.test('parses audio only codec string', function(assert) {
assert.deepEqual(
parseCodecs('mp4a.40.2'),
{
codecCount: 1,
audioProfile: '2'
},
'parsed audio only codec string'
);
});
QUnit.test('parses video and audio codec string', function(assert) {
assert.deepEqual(
parseCodecs('avc1.42001e, mp4a.40.2'),
{
codecCount: 2,
videoCodec: 'avc1',
videoObjectTypeIndicator: '.42001e',
audioProfile: '2'
},
'parsed video and audio codec string'
);
});
QUnit.module('audioProfileFromDefault');
QUnit.test('returns falsey when no audio group ID', function(assert) {
assert.notOk(
audioProfileFromDefault(
{ mediaGroups: { AUDIO: {} } },
'',
),
'returns falsey when no audio group ID'
);
});
QUnit.test('returns falsey when no matching audio group', function(assert) {
assert.notOk(
audioProfileFromDefault(
{
mediaGroups: {
AUDIO: {
au1: {
en: {
default: false,
playlists: [{
attributes: { CODECS: 'mp4a.40.2' }
}]
},
es: {
default: true,
playlists: [{
attributes: { CODECS: 'mp4a.40.5' }
}]
}
}
}
}
},
'au2'
),
'returned falsey when no matching audio group'
);
});
QUnit.test('returns falsey when no default for audio group', function(assert) {
assert.notOk(
audioProfileFromDefault(
{
mediaGroups: {
AUDIO: {
au1: {
en: {
default: false,
playlists: [{
attributes: { CODECS: 'mp4a.40.2' }
}]
},
es: {
default: false,
playlists: [{
attributes: { CODECS: 'mp4a.40.5' }
}]
}
}
}
}
},
'au1'
),
'returned falsey when no default for audio group'
);
});
QUnit.test('returns audio profile for default in audio group', function(assert) {
assert.deepEqual(
audioProfileFromDefault(
{
mediaGroups: {
AUDIO: {
au1: {
en: {
default: false,
playlists: [{
attributes: { CODECS: 'mp4a.40.2' }
}]
},
es: {
default: true,
playlists: [{
attributes: { CODECS: 'mp4a.40.5' }
}]
}
}
}
}
},
'au1'
),
'5',
'returned parsed codec audio profile'
);
});

View File

@@ -1,13 +0,0 @@
import QUnit from 'qunit';
import decodeB64ToUint8Array from '../src/decode-b64-to-uint8-array.js';
QUnit.module('decodeB64ToUint8Array');
// slightly modified version of m3u8 test
// 'parses Widevine #EXT-X-KEY attributes and attaches to manifest'
QUnit.test('can decode', function(assert) {
const b64 = 'AAAAPnBzc2gAAAAA7e+LqXnWSs6jyCfc1R0h7QAAAB4iFnNoYWthX2NlYzJmNjRhYTc4OTBhMTFI49yVmwY';
const result = decodeB64ToUint8Array(b64);
assert.deepEqual(result.byteLength, 62, 'decoded');
});

View File

@@ -1,171 +0,0 @@
import QUnit from 'qunit';
import { forEachMediaGroup } from '../src/media-groups';
QUnit.module('forEachMediaGroup');
QUnit.test('runs callback for each audio media group', function(assert) {
const master = {
mediaGroups: {
AUDIO: {
au1: {
en: { en: 'en' },
es: { es: 'es' }
},
au2: {
de: { de: 'de' },
fr: { fr: 'fr' }
}
},
OTHER: {
other1: {
other11: { other11: 'other11' },
other12: { other12: 'other12' }
},
other2: {
other21: { other21: 'other21' },
other22: { other22: 'other22' }
}
}
}
};
const iteratedMediaGroups = [];
forEachMediaGroup(
master,
['AUDIO'],
(mediaGroup) => iteratedMediaGroups.push(mediaGroup)
);
assert.deepEqual(
iteratedMediaGroups,
[
{ en: 'en' },
{ es: 'es' },
{ de: 'de' },
{ fr: 'fr' }
],
'iterated audio media groups'
);
});
QUnit.test('runs callback for each subtitle media group', function(assert) {
const master = {
mediaGroups: {
SUBTITLES: {
sub1: {
en: { en: 'en' },
es: { es: 'es' }
},
sub2: {
de: { de: 'de' },
fr: { fr: 'fr' }
}
},
OTHER: {
other1: {
other11: { other11: 'other11' },
other12: { other12: 'other12' }
},
other2: {
other21: { other21: 'other21' },
other22: { other22: 'other22' }
}
}
}
};
const iteratedMediaGroups = [];
forEachMediaGroup(
master,
['SUBTITLES'],
(mediaGroup) => iteratedMediaGroups.push(mediaGroup)
);
assert.deepEqual(
iteratedMediaGroups,
[
{ en: 'en' },
{ es: 'es' },
{ de: 'de' },
{ fr: 'fr' }
],
'iterated subtitles media groups'
);
});
QUnit.test('runs callback for each audio and subtitles media group', function(assert) {
const master = {
mediaGroups: {
AUDIO: {
au1: {
en: { en: 'en' },
es: { es: 'es' }
},
au2: {
de: { de: 'de' },
fr: { fr: 'fr' }
}
},
SUBTITLES: {
sub1: {
enS: { enS: 'enS' },
esS: { esS: 'esS' }
},
sub2: {
deS: { deS: 'deS' },
frS: { frS: 'frS' }
}
},
OTHER: {
other1: {
other11: { other11: 'other11' },
other12: { other12: 'other12' }
},
other2: {
other21: { other21: 'other21' },
other22: { other22: 'other22' }
}
}
}
};
const iteratedMediaGroups = [];
forEachMediaGroup(
master,
['AUDIO', 'SUBTITLES'],
(mediaGroup) => iteratedMediaGroups.push(mediaGroup)
);
assert.deepEqual(
iteratedMediaGroups,
[
{ en: 'en' },
{ es: 'es' },
{ de: 'de' },
{ fr: 'fr' },
{ enS: 'enS' },
{ esS: 'esS' },
{ deS: 'deS' },
{ frS: 'frS' }
],
'iterated audio and subtitles media groups'
);
});
QUnit.test('does not run callback for non specified media groups', function(assert) {
const master = {
mediaGroups: {
'VIDEO': { v1: { en: { en: 'en' } } },
'CLOSED-CAPTIONS': { cc1: { en: { en: 'en' } } }
}
};
const iteratedMediaGroups = [];
forEachMediaGroup(
master,
['AUDIO', 'SUBTITLES'],
(mediaGroup) => iteratedMediaGroups.push(mediaGroup)
);
assert.deepEqual(iteratedMediaGroups, [], 'did not iterate non specified media groups');
});

View File

@@ -1,41 +0,0 @@
import QUnit from 'qunit';
import { simpleTypeFromSourceType } from '../src/media-types';
QUnit.module('simpleTypeFromSourceType');
QUnit.test('simpleTypeFromSourceType converts HLS mime types to hls', function(assert) {
assert.equal(
simpleTypeFromSourceType('aPplicatiOn/x-MPegUrl'),
'hls',
'supports application/x-mpegurl'
);
assert.equal(
simpleTypeFromSourceType('aPplicatiOn/VnD.aPPle.MpEgUrL'),
'hls',
'supports application/vnd.apple.mpegurl'
);
});
QUnit.test('simpleTypeFromSourceType converts DASH mime type to dash', function(assert) {
assert.equal(
simpleTypeFromSourceType('aPplication/dAsh+xMl'),
'dash',
'supports application/dash+xml'
);
});
QUnit.test(
'simpleTypeFromSourceType does not convert non HLS/DASH mime types',
function(assert) {
assert.notOk(simpleTypeFromSourceType('video/mp4'), 'does not support video/mp4');
assert.notOk(simpleTypeFromSourceType('video/x-flv'), 'does not support video/x-flv');
}
);
QUnit.test('simpleTypeFromSourceType converts VHS media type to vhs-json', function(assert) {
assert.equal(
simpleTypeFromSourceType('application/vnd.videojs.vhs+json'),
'vhs-json',
'supports application/vnd.videojs.vhs+json'
);
});

View File

@@ -1,28 +0,0 @@
import QUnit from 'qunit';
import window from 'global/window';
import resolveUrl from '../src/resolve-url';
// A modified subset of tests from https://github.com/tjenkinson/url-toolkit
QUnit.module('URL resolver');
QUnit.test('works with a selection of valid urls', function(assert) {
let currentLocation = '';
if (window.location && window.location.protocol) {
currentLocation = window.location.protocol + '//' + window.location.host;
}
assert.equal(
resolveUrl('http://a.com/b/cd/e.m3u8', 'https://example.com/z.ts'),
'https://example.com/z.ts'
);
assert.equal(resolveUrl('http://a.com/b/cd/e.m3u8', 'z.ts'), 'http://a.com/b/cd/z.ts');
assert.equal(resolveUrl('//a.com/b/cd/e.m3u8', 'z.ts'), '//a.com/b/cd/z.ts');
assert.equal(
resolveUrl('/a/b/cd/e.m3u8', 'https://example.com:8080/z.ts'),
'https://example.com:8080/z.ts'
);
assert.equal(resolveUrl('/a/b/cd/e.m3u8', 'z.ts'), currentLocation + '/a/b/cd/z.ts');
assert.equal(resolveUrl('/a/b/cd/e.m3u8', '../../../z.ts'), currentLocation + '/z.ts');
});

View File

@@ -1,51 +0,0 @@
import QUnit from 'qunit';
import Stream from '../src/stream';
QUnit.module('stream', {
beforeEach() {
this.stream = new Stream();
},
afterEach() {
this.stream.dispose();
}
});
QUnit.test('trigger calls listeners', function(assert) {
const args = [];
this.stream.on('test', function(data) {
args.push(data);
});
this.stream.trigger('test', 1);
this.stream.trigger('test', 2);
assert.deepEqual(args, [1, 2]);
});
QUnit.test('callbacks can remove themselves', function(assert) {
const args1 = [];
const args2 = [];
const args3 = [];
const arg2Fn = (event) => {
args2.push(event);
this.stream.off('test', arg2Fn);
};
this.stream.on('test', (event) => {
args1.push(event);
});
this.stream.on('test', arg2Fn);
this.stream.on('test', (event) => {
args3.push(event);
});
this.stream.trigger('test', 1);
this.stream.trigger('test', 2);
assert.deepEqual(args1, [1, 2], 'first callback ran all times');
assert.deepEqual(args2, [1], 'second callback removed after first run');
assert.deepEqual(args3, [1, 2], 'third callback ran all times');
});

View File

@@ -1,35 +0,0 @@
<a name="3.0.0"></a>
# [3.0.0](https://github.com/videojs/aes-decrypter/compare/v2.0.0...v3.0.0) (2017-07-24)
### Features
* Use Rollup for packaging ([bda57ab](https://github.com/videojs/aes-decrypter/commit/bda57ab))
### Chores
* prepare CHANGELOG for new process ([1a5175c](https://github.com/videojs/aes-decrypter/commit/1a5175c))
### BREAKING CHANGES
* revert to 1.x and stop using web crypto.
## 2.0.0 (2016-11-15)
* Use webcrypto for aes-cbc segment decryption when supported (#4)
* Lock the linter to a specific version
## 1.1.1 (2016-11-17)
* version to revert 1.1.0
## 1.0.3 (2016-06-16)
* dont do browserify-shim globally since we only use it in tests (#1)
## 1.0.2 (2016-06-16)
* specify browserify transform globally
## 1.0.1 (2016-06-16)
* fixing the build pipeline
## 1.0.0 (2016-06-16)
* initial

View File

@@ -1,30 +0,0 @@
# CONTRIBUTING
We welcome contributions from everyone!
## Getting Started
Make sure you have NodeJS 0.10 or higher and npm installed.
1. Fork this repository and clone your fork
1. Install dependencies: `npm install`
1. Run a development server: `npm start`
### Making Changes
Refer to the [video.js plugin conventions][conventions] for more detail on best practices and tooling for video.js plugin authorship.
When you've made your changes, push your commit(s) to your fork and issue a pull request against the original repository.
### Running Tests
Testing is a crucial part of any software project. For all but the most trivial changes (typos, etc) test cases are expected. Tests are run in actual browsers using [Karma][karma].
- In all available and supported browsers: `npm test`
- In a specific browser: `npm run test:chrome`, `npm run test:firefox`, etc.
- While development server is running (`npm start`), navigate to [`http://localhost:9999/test/`][local]
[karma]: http://karma-runner.github.io/
[local]: http://localhost:9999/test/
[conventions]: https://github.com/videojs/generator-videojs-plugin/blob/master/docs/conventions.md

View File

@@ -1,13 +0,0 @@
Copyright Brightcove, Inc.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.

View File

@@ -1,63 +0,0 @@
# decrypter
## Table of Contents
<!-- START doctoc -->
<!-- END doctoc -->
## Installation
```sh
npm install --save aes-decrypter
```
Also available to install globally:
```sh
npm install --global aes-decrypter
```
The npm installation is preferred, but Bower works, too.
```sh
bower install --save aes-decrypter
```
## Usage
To include decrypter on your website or npm application, use any of the following methods.
```js
var Decrypter = require('aes-decrypter').Decrypter;
var fs = require('fs');
var keyContent = fs.readFileSync('something.key');
var encryptedBytes = fs.readFileSync('somithing.txt');
// keyContent is a string of the aes-keys content
var keyContent = fs.readFileSync(keyFile);
var view = new DataView(keyContent.buffer);
var key.bytes = new Uint32Array([
view.getUint32(0),
view.getUint32(4),
view.getUint32(8),
view.getUint32(12)
]);
key.iv = new Uint32Array([
0, 0, 0, 0
]);
var d = new Decrypter(
encryptedBytes,
key.bytes,
key.iv,
function(err, decryptedBytes) {
// err always null
});
```
## [License](LICENSE)
Apache-2.0. Copyright (c) Brightcove, Inc.

View File

@@ -1,15 +0,0 @@
<!doctype html>
<html>
<head>
<meta charset="utf-8">
<title>aes-decrypter Demo</title>
<script src="dist/aes-decrypter.js"></script>
</head>
<body>
<p>To test this out, open up your developer console.</p>
<ul>
<li><a href="test/">Run unit tests in browser.</a></li>
<li><a href="docs/api/">Read generated docs.</a></li>
</ul>
</body>
</html>

View File

@@ -1,176 +0,0 @@
{
"_args": [
[
"aes-decrypter@3.0.0",
"/home/runner/work/owncast/owncast/build/javascript"
]
],
"_from": "aes-decrypter@3.0.0",
"_id": "aes-decrypter@3.0.0",
"_inBundle": false,
"_integrity": "sha1-eEihwUW5/b9Xrj4rWxvHzwZEqPs=",
"_location": "/video.js/aes-decrypter",
"_phantomChildren": {},
"_requested": {
"type": "version",
"registry": true,
"raw": "aes-decrypter@3.0.0",
"name": "aes-decrypter",
"escapedName": "aes-decrypter",
"rawSpec": "3.0.0",
"saveSpec": null,
"fetchSpec": "3.0.0"
},
"_requiredBy": [
"/video.js/@videojs/http-streaming"
],
"_resolved": "https://registry.npmjs.org/aes-decrypter/-/aes-decrypter-3.0.0.tgz",
"_spec": "3.0.0",
"_where": "/home/runner/work/owncast/owncast/build/javascript",
"author": {
"name": "Brightcove, Inc."
},
"browserify-shim": {
"qunit": "global:QUnit",
"sinon": "global:sinon"
},
"bugs": {
"url": "https://github.com/videojs/aes-decrypter/issues"
},
"contributors": [
{
"name": "gkatsev"
},
{
"name": "imbcmdth"
},
{
"name": "dmlap"
},
{
"name": "bcasey"
}
],
"dependencies": {
"commander": "^2.9.0",
"global": "^4.3.2",
"pkcs7": "^1.0.2"
},
"description": "decrypt aes-128 content using a key",
"devDependencies": {
"babel-cli": "^6.24.1",
"babel-plugin-external-helpers": "^6.22.0",
"babel-plugin-transform-object-assign": "^6.8.0",
"babel-preset-es2015": "^6.14.0",
"babel-preset-es3": "^1.0.1",
"babelify": "^7.3.0",
"bannerize": "^1.0.2",
"bluebird": "^3.2.2",
"browserify": "^12.0.2",
"browserify-shim": "^3.8.12",
"budo": "^8.0.4",
"chg": "^0.3.2",
"cli-table": "^0.3.1",
"conventional-changelog-cli": "^1.3.1",
"conventional-changelog-videojs": "^3.0.0",
"doctoc": "^0.15.0",
"filesize": "^3.5.10",
"glob": "^6.0.3",
"jsdoc": "^3.4.0",
"karma": "^1.7.0",
"karma-chrome-launcher": "^2.1.1",
"karma-detect-browsers": "^2.2.5",
"karma-firefox-launcher": "^1.0.1",
"karma-ie-launcher": "^1.0.0",
"karma-qunit": "^1.2.1",
"karma-safari-launcher": "^1.0.0",
"klaw-sync": "^2.1.0",
"mkdirp": "^0.5.1",
"node-static": "^0.7.9",
"npm-run-all": "^4.0.2",
"qunitjs": "^2.3.2",
"rimraf": "^2.6.1",
"rollup": "^0.41.6",
"rollup-plugin-babel": "^2.7.1",
"rollup-plugin-commonjs": "^8.0.2",
"rollup-plugin-json": "^2.1.1",
"rollup-plugin-multi-entry": "^2.0.1",
"rollup-plugin-node-resolve": "^3.0.0",
"rollup-watch": "^3.2.2",
"semver": "^5.3.0",
"sinon": "^2.2.0",
"uglify-js": "^3.0.7",
"videojs-standard": "^6.0.0"
},
"directories": {
"test": "test"
},
"files": [
"CONTRIBUTING.md",
"dist/",
"docs/",
"index.html",
"scripts/",
"src/",
"test/"
],
"generator-videojs-plugin": {
"version": "5.0.0"
},
"homepage": "https://github.com/videojs/aes-decrypter#readme",
"license": "Apache-2.0",
"main": "dist/aes-decrypter.cjs.js",
"module": "dist/aes-decrypter.es.js",
"name": "aes-decrypter",
"repository": {
"type": "git",
"url": "git+https://github.com/videojs/aes-decrypter.git"
},
"scripts": {
"assets": "babel-node scripts/assets.js",
"build": "npm-run-all -p build:*",
"build:js": "npm-run-all build:js:rollup-modules build:js:rollup-umd build:js:bannerize build:js:uglify",
"build:js:babel": "babel src -d es5",
"build:js:bannerize": "bannerize dist/aes-decrypter.js --banner=scripts/banner.ejs",
"build:js:browserify": "browserify . -s aes-decrypter -o dist/aes-decrypter.js",
"build:js:rollup-modules": "rollup -c scripts/modules.rollup.config.js",
"build:js:rollup-umd": "rollup -c scripts/umd.rollup.config.js",
"build:js:uglify": "uglifyjs dist/aes-decrypter.js --comments --mangle --compress -o dist/aes-decrypter.min.js",
"build:test": "rollup -c scripts/test.rollup.config.js",
"change": "chg add",
"clean": "rimraf dist test/dist",
"docs": "npm-run-all docs:*",
"docs:api": "jsdoc src -r -d docs/api",
"docs:toc": "doctoc README.md",
"lint": "vjsstandard",
"postclean": "mkdirp dist test/dist",
"prebuild": "npm run clean",
"prepublish": "npm run build",
"prestart": "npm run build",
"pretest": "npm-run-all lint build",
"preversion": "npm test",
"start": "npm-run-all -p start:server watch",
"start:server": "static -a 0.0.0.0 -p 9999 -H '{\"Cache-Control\": \"no-cache, must-revalidate\"}' .",
"test": "karma start test/karma.conf.js",
"test:chrome": "npm run pretest && karma start test/karma.conf.js --browsers Chrome",
"test:firefox": "npm run pretest && karma start test/karma.conf.js --browsers Firefox",
"test:ie": "npm run pretest && karma start test/karma.conf.js --browsers IE",
"test:safari": "npm run pretest && karma start test/karma.conf.js --browsers Safari",
"version": "node scripts/version.js",
"watch": "npm-run-all -p watch:*",
"watch:js-modules": "rollup -c scripts/modules.rollup.config.js -w",
"watch:js-umd": "rollup -c scripts/umd.rollup.config.js -w",
"watch:test": "rollup -c scripts/test.rollup.config.js -w"
},
"version": "3.0.0",
"vjsstandard": {
"ignore": [
"dist",
"docs",
"test/dist",
"test/karma.conf.js",
"scripts",
"src/aes.js"
]
}
}

View File

@@ -1,65 +0,0 @@
const fs = require('fs');
const zlib = require('zlib');
const Promise = require('bluebird');
const klawSync = require('klaw-sync');
const filesize = require('filesize');
const Table = require('cli-table');
const files = klawSync('dist/', {
ignore: ['examples', 'lang', 'font', 'ie8', '*.zip', '*.gz'],
nodir: true
});
Promise.all(files.map(gzipAndStat))
.then(mapFiles)
.then(function(files) {
logTable(files);
return files;
})
.then(cleanup)
.catch(function(err) {
console.error(err.stack);
});
function cleanup(files) {
files.forEach(function(file) {
fs.unlinkSync('dist/' + file[0] + '.gz');
});
}
function mapFiles(files) {
return files.map(function(file) {
const path = file[0].path;
const fileStat = file[0].stats;
const gzStat = file[1];
return [file[0].path.split('dist/')[1], filesize(fileStat.size), filesize(gzStat.size)];
});
}
function gzipAndStat(file) {
return new Promise(function(resolve, reject) {
const readStream = fs.createReadStream(file.path);
const writeStream = fs.createWriteStream(file.path + '.gz');
const gzip = zlib.createGzip();
readStream.pipe(gzip).pipe(writeStream).on('close', function() {
const gzStat = fs.statSync(file.path + '.gz');
resolve([file, gzStat]);
})
.on('error', reject);
});
}
function logTable(files) {
const table = new Table({
head: ['filename', 'size', 'gzipped'],
colAligns: ['left', 'right', 'right'],
style: {
border: ['white']
}
});
table.push.apply(table, files);
console.log(table.toString());
}

View File

@@ -1,6 +0,0 @@
/**
* <%- pkg.name %>
* @version <%- pkg.version %>
* @copyright <%- date.getFullYear() %> <%- pkg.author %>
* @license <%- pkg.license %>
*/

View File

@@ -1,16 +0,0 @@
import browserify from 'browserify';
import fs from 'fs';
import glob from 'glob';
/* eslint no-console: 0 */
glob('test/**/*.test.js', (err, files) => {
if (err) {
throw err;
}
browserify(files)
.transform('babelify')
.transform('browserify-shim')
.bundle()
.pipe(fs.createWriteStream('test/dist/bundle.js'));
});

View File

@@ -1,41 +0,0 @@
/**
* Rollup configuration for packaging the plugin in a module that is consumable
* by either CommonJS (e.g. Node or Browserify) or ECMAScript (e.g. Rollup).
*
* These modules DO NOT include their dependencies as we expect those to be
* handled by the module system.
*/
import babel from 'rollup-plugin-babel';
import json from 'rollup-plugin-json';
export default {
moduleName: 'aesDecrypter',
entry: 'src/index.js',
legacy: true,
external: ['global/window'],
globals: {
'global/window': 'window'
},
plugins: [
json(),
babel({
babelrc: false,
exclude: 'node_modules/**',
presets: [
'es3',
['es2015', {
loose: true,
modules: false
}]
],
plugins: [
'external-helpers',
'transform-object-assign'
]
})
],
targets: [
{dest: 'dist/aes-decrypter.cjs.js', format: 'cjs'},
{dest: 'dist/aes-decrypter.es.js', format: 'es'}
]
};

View File

@@ -1,57 +0,0 @@
/**
* Rollup configuration for packaging the plugin in a test bundle.
*
* This includes all dependencies for both the plugin and its tests.
*/
import babel from 'rollup-plugin-babel';
import commonjs from 'rollup-plugin-commonjs';
import json from 'rollup-plugin-json';
import multiEntry from 'rollup-plugin-multi-entry';
import resolve from 'rollup-plugin-node-resolve';
export default {
moduleName: 'aesDecrypterTests',
entry: 'test/**/*.test.js',
dest: 'test/dist/bundle.js',
format: 'iife',
external: [
'qunit',
'qunitjs',
'sinon'
],
globals: {
qunit: 'QUnit',
qunitjs: 'QUnit',
sinon: 'sinon'
},
legacy: true,
plugins: [
multiEntry({
exports: false
}),
resolve({
browser: true,
main: true,
jsnext: true
}),
json(),
commonjs({
sourceMap: false
}),
babel({
babelrc: false,
exclude: 'node_modules/**',
presets: [
'es3',
['es2015', {
loose: true,
modules: false
}]
],
plugins: [
'external-helpers',
'transform-object-assign'
]
})
]
};

View File

@@ -1,48 +0,0 @@
/**
* Rollup configuration for packaging the plugin in a module that is consumable
* as the `src` of a `script` tag or via AMD or similar client-side loading.
*
* This module DOES include its dependencies.
*/
import babel from 'rollup-plugin-babel';
import commonjs from 'rollup-plugin-commonjs';
import json from 'rollup-plugin-json';
import resolve from 'rollup-plugin-node-resolve';
export default {
moduleName: 'aesDecrypter',
entry: 'src/index.js',
dest: 'dist/aes-decrypter.js',
format: 'umd',
legacy: true,
external: ['global/window'],
globals: {
'global/window': 'window'
},
plugins: [
resolve({
browser: true,
main: true,
jsnext: true
}),
json(),
commonjs({
sourceMap: false
}),
babel({
babelrc: false,
exclude: 'node_modules/**',
presets: [
'es3',
['es2015', {
loose: true,
modules: false
}]
],
plugins: [
'external-helpers',
'transform-object-assign'
]
})
]
};

View File

@@ -1,10 +0,0 @@
const execSync = require('child_process').execSync;
const path = require('path');
const semver = require('semver');
const pkg = require('../package.json');
if (!semver.prerelease(pkg.version)) {
process.chdir(path.resolve(__dirname, '..'));
execSync('conventional-changelog -p videojs -i CHANGELOG.md -s');
execSync('git add CHANGELOG.md');
}

View File

@@ -1,259 +0,0 @@
/**
* @file aes.js
*
* This file contains an adaptation of the AES decryption algorithm
* from the Standford Javascript Cryptography Library. That work is
* covered by the following copyright and permissions notice:
*
* Copyright 2009-2010 Emily Stark, Mike Hamburg, Dan Boneh.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are
* met:
*
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
*
* 2. Redistributions in binary form must reproduce the above
* copyright notice, this list of conditions and the following
* disclaimer in the documentation and/or other materials provided
* with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHORS ``AS IS'' AND ANY EXPRESS OR
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL <COPYRIGHT HOLDER> OR CONTRIBUTORS BE
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
* BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
* WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
* OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
* IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
* The views and conclusions contained in the software and documentation
* are those of the authors and should not be interpreted as representing
* official policies, either expressed or implied, of the authors.
*/
/**
* Expand the S-box tables.
*
* @private
*/
const precompute = function() {
let tables = [[[], [], [], [], []], [[], [], [], [], []]];
let encTable = tables[0];
let decTable = tables[1];
let sbox = encTable[4];
let sboxInv = decTable[4];
let i;
let x;
let xInv;
let d = [];
let th = [];
let x2;
let x4;
let x8;
let s;
let tEnc;
let tDec;
// Compute double and third tables
for (i = 0; i < 256; i++) {
th[(d[i] = i << 1 ^ (i >> 7) * 283) ^ i] = i;
}
for (x = xInv = 0; !sbox[x]; x ^= x2 || 1, xInv = th[xInv] || 1) {
// Compute sbox
s = xInv ^ xInv << 1 ^ xInv << 2 ^ xInv << 3 ^ xInv << 4;
s = s >> 8 ^ s & 255 ^ 99;
sbox[x] = s;
sboxInv[s] = x;
// Compute MixColumns
x8 = d[x4 = d[x2 = d[x]]];
tDec = x8 * 0x1010101 ^ x4 * 0x10001 ^ x2 * 0x101 ^ x * 0x1010100;
tEnc = d[s] * 0x101 ^ s * 0x1010100;
for (i = 0; i < 4; i++) {
encTable[i][x] = tEnc = tEnc << 24 ^ tEnc >>> 8;
decTable[i][s] = tDec = tDec << 24 ^ tDec >>> 8;
}
}
// Compactify. Considerable speedup on Firefox.
for (i = 0; i < 5; i++) {
encTable[i] = encTable[i].slice(0);
decTable[i] = decTable[i].slice(0);
}
return tables;
};
let aesTables = null;
/**
* Schedule out an AES key for both encryption and decryption. This
* is a low-level class. Use a cipher mode to do bulk encryption.
*
* @class AES
* @param key {Array} The key as an array of 4, 6 or 8 words.
*/
export default class AES {
constructor(key) {
/**
* The expanded S-box and inverse S-box tables. These will be computed
* on the client so that we don't have to send them down the wire.
*
* There are two tables, _tables[0] is for encryption and
* _tables[1] is for decryption.
*
* The first 4 sub-tables are the expanded S-box with MixColumns. The
* last (_tables[01][4]) is the S-box itself.
*
* @private
*/
// if we have yet to precompute the S-box tables
// do so now
if (!aesTables) {
aesTables = precompute();
}
// then make a copy of that object for use
this._tables = [[aesTables[0][0].slice(),
aesTables[0][1].slice(),
aesTables[0][2].slice(),
aesTables[0][3].slice(),
aesTables[0][4].slice()],
[aesTables[1][0].slice(),
aesTables[1][1].slice(),
aesTables[1][2].slice(),
aesTables[1][3].slice(),
aesTables[1][4].slice()]];
let i;
let j;
let tmp;
let encKey;
let decKey;
let sbox = this._tables[0][4];
let decTable = this._tables[1];
let keyLen = key.length;
let rcon = 1;
if (keyLen !== 4 && keyLen !== 6 && keyLen !== 8) {
throw new Error('Invalid aes key size');
}
encKey = key.slice(0);
decKey = [];
this._key = [encKey, decKey];
// schedule encryption keys
for (i = keyLen; i < 4 * keyLen + 28; i++) {
tmp = encKey[i - 1];
// apply sbox
if (i % keyLen === 0 || (keyLen === 8 && i % keyLen === 4)) {
tmp = sbox[tmp >>> 24] << 24 ^
sbox[tmp >> 16 & 255] << 16 ^
sbox[tmp >> 8 & 255] << 8 ^
sbox[tmp & 255];
// shift rows and add rcon
if (i % keyLen === 0) {
tmp = tmp << 8 ^ tmp >>> 24 ^ rcon << 24;
rcon = rcon << 1 ^ (rcon >> 7) * 283;
}
}
encKey[i] = encKey[i - keyLen] ^ tmp;
}
// schedule decryption keys
for (j = 0; i; j++, i--) {
tmp = encKey[j & 3 ? i : i - 4];
if (i <= 4 || j < 4) {
decKey[j] = tmp;
} else {
decKey[j] = decTable[0][sbox[tmp >>> 24 ]] ^
decTable[1][sbox[tmp >> 16 & 255]] ^
decTable[2][sbox[tmp >> 8 & 255]] ^
decTable[3][sbox[tmp & 255]];
}
}
}
/**
* Decrypt 16 bytes, specified as four 32-bit words.
*
* @param {Number} encrypted0 the first word to decrypt
* @param {Number} encrypted1 the second word to decrypt
* @param {Number} encrypted2 the third word to decrypt
* @param {Number} encrypted3 the fourth word to decrypt
* @param {Int32Array} out the array to write the decrypted words
* into
* @param {Number} offset the offset into the output array to start
* writing results
* @return {Array} The plaintext.
*/
decrypt(encrypted0, encrypted1, encrypted2, encrypted3, out, offset) {
let key = this._key[1];
// state variables a,b,c,d are loaded with pre-whitened data
let a = encrypted0 ^ key[0];
let b = encrypted3 ^ key[1];
let c = encrypted2 ^ key[2];
let d = encrypted1 ^ key[3];
let a2;
let b2;
let c2;
// key.length === 2 ?
let nInnerRounds = key.length / 4 - 2;
let i;
let kIndex = 4;
let table = this._tables[1];
// load up the tables
let table0 = table[0];
let table1 = table[1];
let table2 = table[2];
let table3 = table[3];
let sbox = table[4];
// Inner rounds. Cribbed from OpenSSL.
for (i = 0; i < nInnerRounds; i++) {
a2 = table0[a >>> 24] ^
table1[b >> 16 & 255] ^
table2[c >> 8 & 255] ^
table3[d & 255] ^
key[kIndex];
b2 = table0[b >>> 24] ^
table1[c >> 16 & 255] ^
table2[d >> 8 & 255] ^
table3[a & 255] ^
key[kIndex + 1];
c2 = table0[c >>> 24] ^
table1[d >> 16 & 255] ^
table2[a >> 8 & 255] ^
table3[b & 255] ^
key[kIndex + 2];
d = table0[d >>> 24] ^
table1[a >> 16 & 255] ^
table2[b >> 8 & 255] ^
table3[c & 255] ^
key[kIndex + 3];
kIndex += 4;
a = a2; b = b2; c = c2;
}
// Last round.
for (i = 0; i < 4; i++) {
out[(3 & -i) + offset] =
sbox[a >>> 24] << 24 ^
sbox[b >> 16 & 255] << 16 ^
sbox[c >> 8 & 255] << 8 ^
sbox[d & 255] ^
key[kIndex++];
a2 = a; a = b; b = c; c = d; d = a2;
}
}
}

View File

@@ -1,49 +0,0 @@
/**
* @file async-stream.js
*/
import Stream from './stream';
/**
* A wrapper around the Stream class to use setTiemout
* and run stream "jobs" Asynchronously
*
* @class AsyncStream
* @extends Stream
*/
export default class AsyncStream extends Stream {
constructor() {
super(Stream);
this.jobs = [];
this.delay = 1;
this.timeout_ = null;
}
/**
* process an async job
*
* @private
*/
processJob_() {
this.jobs.shift()();
if (this.jobs.length) {
this.timeout_ = setTimeout(this.processJob_.bind(this),
this.delay);
} else {
this.timeout_ = null;
}
}
/**
* push a job into the stream
*
* @param {Function} job the job to push into the stream
*/
push(job) {
this.jobs.push(job);
if (!this.timeout_) {
this.timeout_ = setTimeout(this.processJob_.bind(this),
this.delay);
}
}
}

View File

@@ -1,171 +0,0 @@
/**
* @file decrypter.js
*
* An asynchronous implementation of AES-128 CBC decryption with
* PKCS#7 padding.
*/
import AES from './aes';
import AsyncStream from './async-stream';
import {unpad} from 'pkcs7';
/**
* Convert network-order (big-endian) bytes into their little-endian
* representation.
*/
const ntoh = function(word) {
return (word << 24) |
((word & 0xff00) << 8) |
((word & 0xff0000) >> 8) |
(word >>> 24);
};
/**
* Decrypt bytes using AES-128 with CBC and PKCS#7 padding.
*
* @param {Uint8Array} encrypted the encrypted bytes
* @param {Uint32Array} key the bytes of the decryption key
* @param {Uint32Array} initVector the initialization vector (IV) to
* use for the first round of CBC.
* @return {Uint8Array} the decrypted bytes
*
* @see http://en.wikipedia.org/wiki/Advanced_Encryption_Standard
* @see http://en.wikipedia.org/wiki/Block_cipher_mode_of_operation#Cipher_Block_Chaining_.28CBC.29
* @see https://tools.ietf.org/html/rfc2315
*/
const decrypt = function(encrypted, key, initVector) {
// word-level access to the encrypted bytes
const encrypted32 = new Int32Array(encrypted.buffer,
encrypted.byteOffset,
encrypted.byteLength >> 2);
const decipher = new AES(Array.prototype.slice.call(key));
// byte and word-level access for the decrypted output
const decrypted = new Uint8Array(encrypted.byteLength);
const decrypted32 = new Int32Array(decrypted.buffer);
// temporary variables for working with the IV, encrypted, and
// decrypted data
let init0;
let init1;
let init2;
let init3;
let encrypted0;
let encrypted1;
let encrypted2;
let encrypted3;
// iteration variable
let wordIx;
// pull out the words of the IV to ensure we don't modify the
// passed-in reference and easier access
init0 = initVector[0];
init1 = initVector[1];
init2 = initVector[2];
init3 = initVector[3];
// decrypt four word sequences, applying cipher-block chaining (CBC)
// to each decrypted block
for (wordIx = 0; wordIx < encrypted32.length; wordIx += 4) {
// convert big-endian (network order) words into little-endian
// (javascript order)
encrypted0 = ntoh(encrypted32[wordIx]);
encrypted1 = ntoh(encrypted32[wordIx + 1]);
encrypted2 = ntoh(encrypted32[wordIx + 2]);
encrypted3 = ntoh(encrypted32[wordIx + 3]);
// decrypt the block
decipher.decrypt(encrypted0,
encrypted1,
encrypted2,
encrypted3,
decrypted32,
wordIx);
// XOR with the IV, and restore network byte-order to obtain the
// plaintext
decrypted32[wordIx] = ntoh(decrypted32[wordIx] ^ init0);
decrypted32[wordIx + 1] = ntoh(decrypted32[wordIx + 1] ^ init1);
decrypted32[wordIx + 2] = ntoh(decrypted32[wordIx + 2] ^ init2);
decrypted32[wordIx + 3] = ntoh(decrypted32[wordIx + 3] ^ init3);
// setup the IV for the next round
init0 = encrypted0;
init1 = encrypted1;
init2 = encrypted2;
init3 = encrypted3;
}
return decrypted;
};
/**
* The `Decrypter` class that manages decryption of AES
* data through `AsyncStream` objects and the `decrypt`
* function
*
* @param {Uint8Array} encrypted the encrypted bytes
* @param {Uint32Array} key the bytes of the decryption key
* @param {Uint32Array} initVector the initialization vector (IV) to
* @param {Function} done the function to run when done
* @class Decrypter
*/
class Decrypter {
constructor(encrypted, key, initVector, done) {
const step = Decrypter.STEP;
const encrypted32 = new Int32Array(encrypted.buffer);
const decrypted = new Uint8Array(encrypted.byteLength);
let i = 0;
this.asyncStream_ = new AsyncStream();
// split up the encryption job and do the individual chunks asynchronously
this.asyncStream_.push(this.decryptChunk_(encrypted32.subarray(i, i + step),
key,
initVector,
decrypted));
for (i = step; i < encrypted32.length; i += step) {
initVector = new Uint32Array([ntoh(encrypted32[i - 4]),
ntoh(encrypted32[i - 3]),
ntoh(encrypted32[i - 2]),
ntoh(encrypted32[i - 1])]);
this.asyncStream_.push(this.decryptChunk_(encrypted32.subarray(i, i + step),
key,
initVector,
decrypted));
}
// invoke the done() callback when everything is finished
this.asyncStream_.push(function() {
// remove pkcs#7 padding from the decrypted bytes
done(null, unpad(decrypted));
});
}
/**
* a getter for step the maximum number of bytes to process at one time
*
* @return {Number} the value of step 32000
*/
static get STEP() {
// 4 * 8000;
return 32000;
}
/**
* @private
*/
decryptChunk_(encrypted, key, initVector, decrypted) {
return function() {
const bytes = decrypt(encrypted, key, initVector);
decrypted.set(bytes, encrypted.byteOffset);
};
}
}
export {
Decrypter,
decrypt
};

View File

@@ -1,18 +0,0 @@
/**
* @file index.js
*
* Index module to easily import the primary components of AES-128
* decryption. Like this:
*
* ```js
* import {Decrypter, decrypt, AsyncStream} from 'aes-decrypter';
* ```
*/
import {decrypt, Decrypter} from './decrypter';
import AsyncStream from './async-stream';
export {
decrypt,
Decrypter,
AsyncStream
};

View File

@@ -1,99 +0,0 @@
/**
* @file stream.js
*/
/**
* A lightweight readable stream implemention that handles event dispatching.
*
* @class Stream
*/
export default class Stream {
constructor() {
this.listeners = {};
}
/**
* Add a listener for a specified event type.
*
* @param {String} type the event name
* @param {Function} listener the callback to be invoked when an event of
* the specified type occurs
*/
on(type, listener) {
if (!this.listeners[type]) {
this.listeners[type] = [];
}
this.listeners[type].push(listener);
}
/**
* Remove a listener for a specified event type.
*
* @param {String} type the event name
* @param {Function} listener a function previously registered for this
* type of event through `on`
* @return {Boolean} if we could turn it off or not
*/
off(type, listener) {
if (!this.listeners[type]) {
return false;
}
const index = this.listeners[type].indexOf(listener);
this.listeners[type].splice(index, 1);
return index > -1;
}
/**
* Trigger an event of the specified type on this stream. Any additional
* arguments to this function are passed as parameters to event listeners.
*
* @param {String} type the event name
*/
trigger(type) {
const callbacks = this.listeners[type];
if (!callbacks) {
return;
}
// Slicing the arguments on every invocation of this method
// can add a significant amount of overhead. Avoid the
// intermediate object creation for the common case of a
// single callback argument
if (arguments.length === 2) {
const length = callbacks.length;
for (let i = 0; i < length; ++i) {
callbacks[i].call(this, arguments[1]);
}
} else {
const args = Array.prototype.slice.call(arguments, 1);
const length = callbacks.length;
for (let i = 0; i < length; ++i) {
callbacks[i].apply(this, args);
}
}
}
/**
* Destroys the stream and cleans up.
*/
dispose() {
this.listeners = {};
}
/**
* Forwards all `data` events on this stream to the destination stream. The
* destination stream should provide a method `push` to receive the data
* events as they arrive.
*
* @param {Stream} destination the stream that will receive all `data` events
* @see http://nodejs.org/api/stream.html#stream_readable_pipe_destination_options
*/
pipe(destination) {
this.on('data', function(data) {
destination.push(data);
});
}
}

View File

@@ -1,185 +0,0 @@
// see docs/hlse.md for instructions on how test data was generated
import QUnit from 'qunit';
import {unpad} from 'pkcs7';
import sinon from 'sinon';
import {decrypt, Decrypter, AsyncStream} from '../src';
// see docs/hlse.md for instructions on how test data was generated
const stringFromBytes = function(bytes) {
let result = '';
for (let i = 0; i < bytes.length; i++) {
result += String.fromCharCode(bytes[i]);
}
return result;
};
QUnit.module('Decryption');
QUnit.test('decrypts a single AES-128 with PKCS7 block', function(assert) {
const key = new Uint32Array([0, 0, 0, 0]);
const initVector = key;
// the string "howdy folks" encrypted
const encrypted = new Uint8Array([
0xce, 0x90, 0x97, 0xd0,
0x08, 0x46, 0x4d, 0x18,
0x4f, 0xae, 0x01, 0x1c,
0x82, 0xa8, 0xf0, 0x67
]);
assert.deepEqual('howdy folks',
stringFromBytes(unpad(decrypt(encrypted, key, initVector))),
'decrypted with a byte array key'
);
});
QUnit.test('decrypts multiple AES-128 blocks with CBC', function(assert) {
const key = new Uint32Array([0, 0, 0, 0]);
const initVector = key;
// the string "0123456789abcdef01234" encrypted
const encrypted = new Uint8Array([
0x14, 0xf5, 0xfe, 0x74,
0x69, 0x66, 0xf2, 0x92,
0x65, 0x1c, 0x22, 0x88,
0xbb, 0xff, 0x46, 0x09,
0x0b, 0xde, 0x5e, 0x71,
0x77, 0x87, 0xeb, 0x84,
0xa9, 0x54, 0xc2, 0x45,
0xe9, 0x4e, 0x29, 0xb3
]);
assert.deepEqual('0123456789abcdef01234',
stringFromBytes(unpad(decrypt(encrypted, key, initVector))),
'decrypted multiple blocks');
});
QUnit.test(
'verify that the deepcopy works by doing two decrypts in the same test',
function(assert) {
const key = new Uint32Array([0, 0, 0, 0]);
const initVector = key;
// the string "howdy folks" encrypted
const pkcs7Block = new Uint8Array([
0xce, 0x90, 0x97, 0xd0,
0x08, 0x46, 0x4d, 0x18,
0x4f, 0xae, 0x01, 0x1c,
0x82, 0xa8, 0xf0, 0x67
]);
assert.deepEqual('howdy folks',
stringFromBytes(unpad(decrypt(pkcs7Block, key, initVector))),
'decrypted with a byte array key'
);
// the string "0123456789abcdef01234" encrypted
const cbcBlocks = new Uint8Array([
0x14, 0xf5, 0xfe, 0x74,
0x69, 0x66, 0xf2, 0x92,
0x65, 0x1c, 0x22, 0x88,
0xbb, 0xff, 0x46, 0x09,
0x0b, 0xde, 0x5e, 0x71,
0x77, 0x87, 0xeb, 0x84,
0xa9, 0x54, 0xc2, 0x45,
0xe9, 0x4e, 0x29, 0xb3
]);
assert.deepEqual('0123456789abcdef01234',
stringFromBytes(unpad(decrypt(cbcBlocks, key, initVector))),
'decrypted multiple blocks');
});
QUnit.module('Incremental Processing', {
beforeEach() {
this.clock = sinon.useFakeTimers();
},
afterEach() {
this.clock.restore();
}
});
QUnit.test('executes a callback after a timeout', function(assert) {
const asyncStream = new AsyncStream();
let calls = '';
asyncStream.push(function() {
calls += 'a';
});
this.clock.tick(asyncStream.delay);
assert.equal(calls, 'a', 'invoked the callback once');
this.clock.tick(asyncStream.delay);
assert.equal(calls, 'a', 'only invoked the callback once');
});
QUnit.test('executes callback in series', function(assert) {
const asyncStream = new AsyncStream();
let calls = '';
asyncStream.push(function() {
calls += 'a';
});
asyncStream.push(function() {
calls += 'b';
});
this.clock.tick(asyncStream.delay);
assert.equal(calls, 'a', 'invoked the first callback');
this.clock.tick(asyncStream.delay);
assert.equal(calls, 'ab', 'invoked the second');
});
QUnit.module('Incremental Decryption', {
beforeEach() {
this.clock = sinon.useFakeTimers();
},
afterEach() {
this.clock.restore();
}
});
QUnit.test('asynchronously decrypts a 4-word block', function(assert) {
const key = new Uint32Array([0, 0, 0, 0]);
const initVector = key;
// the string "howdy folks" encrypted
const encrypted = new Uint8Array([0xce, 0x90, 0x97, 0xd0,
0x08, 0x46, 0x4d, 0x18,
0x4f, 0xae, 0x01, 0x1c,
0x82, 0xa8, 0xf0, 0x67]);
let decrypted;
const decrypter = new Decrypter(encrypted,
key,
initVector,
function(error, result) {
if (error) {
throw new Error(error);
}
decrypted = result;
});
assert.ok(!decrypted, 'asynchronously decrypts');
this.clock.tick(decrypter.asyncStream_.delay * 2);
assert.ok(decrypted, 'completed decryption');
assert.deepEqual('howdy folks',
stringFromBytes(decrypted),
'decrypts and unpads the result');
});
QUnit.test('breaks up input greater than the step value', function(assert) {
const encrypted = new Int32Array(Decrypter.STEP + 4);
let done = false;
const decrypter = new Decrypter(encrypted,
new Uint32Array(4),
new Uint32Array(4),
function() {
done = true;
});
this.clock.tick(decrypter.asyncStream_.delay * 2);
assert.ok(!done, 'not finished after two ticks');
this.clock.tick(decrypter.asyncStream_.delay);
assert.ok(done, 'finished after the last chunk is decrypted');
});

View File

@@ -1,15 +0,0 @@
<!doctype html>
<html>
<head>
<meta charset="utf-8">
<title>aes-decrypter Unit Tests</title>
<link rel="stylesheet" href="../node_modules/qunitjs/qunit/qunit.css">
</head>
<body>
<div id="qunit"></div>
<div id="qunit-fixture"></div>
<script src="../node_modules/sinon/pkg/sinon.js"></script>
<script src="../node_modules/qunitjs/qunit/qunit.js"></script>
<script src="../test/dist/bundle.js"></script>
</body>
</html>

View File

@@ -1,39 +0,0 @@
module.exports = function(config) {
var detectBrowsers = {
enabled: false,
usePhantomJS: false
};
// On Travis CI, we can only run in Firefox and Chrome; so, enforce that.
if (process.env.TRAVIS) {
config.browsers = ['Firefox', 'travisChrome'];
}
// If no browsers are specified, we enable `karma-detect-browsers`
// this will detect all browsers that are available for testing
if (!config.browsers.length) {
detectBrowsers.enabled = true;
}
config.set({
basePath: '..',
frameworks: ['qunit', 'detectBrowsers'],
files: [
'node_modules/sinon/pkg/sinon.js',
'test/dist/bundle.js'
],
customLaunchers: {
travisChrome: {
base: 'Chrome',
flags: ['--no-sandbox']
}
},
detectBrowsers: detectBrowsers,
reporters: ['dots'],
port: 9876,
colors: true,
autoWatch: false,
singleRun: true,
concurrency: Infinity
});
};

View File

@@ -1,419 +0,0 @@
2.20.3 / 2019-10-11
==================
* Support Node.js 0.10 (Revert #1059)
* Ran "npm unpublish commander@2.20.2". There is no 2.20.2.
2.20.1 / 2019-09-29
==================
* Improve executable subcommand tracking
* Update dev dependencies
2.20.0 / 2019-04-02
==================
* fix: resolve symbolic links completely when hunting for subcommands (#935)
* Update index.d.ts (#930)
* Update Readme.md (#924)
* Remove --save option as it isn't required anymore (#918)
* Add link to the license file (#900)
* Added example of receiving args from options (#858)
* Added missing semicolon (#882)
* Add extension to .eslintrc (#876)
2.19.0 / 2018-10-02
==================
* Removed newline after Options and Commands headers (#864)
* Bugfix - Error output (#862)
* Fix to change default value to string (#856)
2.18.0 / 2018-09-07
==================
* Standardize help output (#853)
* chmod 644 travis.yml (#851)
* add support for execute typescript subcommand via ts-node (#849)
2.17.1 / 2018-08-07
==================
* Fix bug in command emit (#844)
2.17.0 / 2018-08-03
==================
* fixed newline output after help information (#833)
* Fix to emit the action even without command (#778)
* npm update (#823)
2.16.0 / 2018-06-29
==================
* Remove Makefile and `test/run` (#821)
* Make 'npm test' run on Windows (#820)
* Add badge to display install size (#807)
* chore: cache node_modules (#814)
* chore: remove Node.js 4 (EOL), add Node.js 10 (#813)
* fixed typo in readme (#812)
* Fix types (#804)
* Update eslint to resolve vulnerabilities in lodash (#799)
* updated readme with custom event listeners. (#791)
* fix tests (#794)
2.15.0 / 2018-03-07
==================
* Update downloads badge to point to graph of downloads over time instead of duplicating link to npm
* Arguments description
2.14.1 / 2018-02-07
==================
* Fix typing of help function
2.14.0 / 2018-02-05
==================
* only register the option:version event once
* Fixes issue #727: Passing empty string for option on command is set to undefined
* enable eqeqeq rule
* resolves #754 add linter configuration to project
* resolves #560 respect custom name for version option
* document how to override the version flag
* document using options per command
2.13.0 / 2018-01-09
==================
* Do not print default for --no-
* remove trailing spaces in command help
* Update CI's Node.js to LTS and latest version
* typedefs: Command and Option types added to commander namespace
2.12.2 / 2017-11-28
==================
* fix: typings are not shipped
2.12.1 / 2017-11-23
==================
* Move @types/node to dev dependency
2.12.0 / 2017-11-22
==================
* add attributeName() method to Option objects
* Documentation updated for options with --no prefix
* typings: `outputHelp` takes a string as the first parameter
* typings: use overloads
* feat(typings): update to match js api
* Print default value in option help
* Fix translation error
* Fail when using same command and alias (#491)
* feat(typings): add help callback
* fix bug when description is add after command with options (#662)
* Format js code
* Rename History.md to CHANGELOG.md (#668)
* feat(typings): add typings to support TypeScript (#646)
* use current node
2.11.0 / 2017-07-03
==================
* Fix help section order and padding (#652)
* feature: support for signals to subcommands (#632)
* Fixed #37, --help should not display first (#447)
* Fix translation errors. (#570)
* Add package-lock.json
* Remove engines
* Upgrade package version
* Prefix events to prevent conflicts between commands and options (#494)
* Removing dependency on graceful-readlink
* Support setting name in #name function and make it chainable
* Add .vscode directory to .gitignore (Visual Studio Code metadata)
* Updated link to ruby commander in readme files
2.10.0 / 2017-06-19
==================
* Update .travis.yml. drop support for older node.js versions.
* Fix require arguments in README.md
* On SemVer you do not start from 0.0.1
* Add missing semi colon in readme
* Add save param to npm install
* node v6 travis test
* Update Readme_zh-CN.md
* Allow literal '--' to be passed-through as an argument
* Test subcommand alias help
* link build badge to master branch
* Support the alias of Git style sub-command
* added keyword commander for better search result on npm
* Fix Sub-Subcommands
* test node.js stable
* Fixes TypeError when a command has an option called `--description`
* Update README.md to make it beginner friendly and elaborate on the difference between angled and square brackets.
* Add chinese Readme file
2.9.0 / 2015-10-13
==================
* Add option `isDefault` to set default subcommand #415 @Qix-
* Add callback to allow filtering or post-processing of help text #434 @djulien
* Fix `undefined` text in help information close #414 #416 @zhiyelee
2.8.1 / 2015-04-22
==================
* Back out `support multiline description` Close #396 #397
2.8.0 / 2015-04-07
==================
* Add `process.execArg` support, execution args like `--harmony` will be passed to sub-commands #387 @DigitalIO @zhiyelee
* Fix bug in Git-style sub-commands #372 @zhiyelee
* Allow commands to be hidden from help #383 @tonylukasavage
* When git-style sub-commands are in use, yet none are called, display help #382 @claylo
* Add ability to specify arguments syntax for top-level command #258 @rrthomas
* Support multiline descriptions #208 @zxqfox
2.7.1 / 2015-03-11
==================
* Revert #347 (fix collisions when option and first arg have same name) which causes a bug in #367.
2.7.0 / 2015-03-09
==================
* Fix git-style bug when installed globally. Close #335 #349 @zhiyelee
* Fix collisions when option and first arg have same name. Close #346 #347 @tonylukasavage
* Add support for camelCase on `opts()`. Close #353 @nkzawa
* Add node.js 0.12 and io.js to travis.yml
* Allow RegEx options. #337 @palanik
* Fixes exit code when sub-command failing. Close #260 #332 @pirelenito
* git-style `bin` files in $PATH make sense. Close #196 #327 @zhiyelee
2.6.0 / 2014-12-30
==================
* added `Command#allowUnknownOption` method. Close #138 #318 @doozr @zhiyelee
* Add application description to the help msg. Close #112 @dalssoft
2.5.1 / 2014-12-15
==================
* fixed two bugs incurred by variadic arguments. Close #291 @Quentin01 #302 @zhiyelee
2.5.0 / 2014-10-24
==================
* add support for variadic arguments. Closes #277 @whitlockjc
2.4.0 / 2014-10-17
==================
* fixed a bug on executing the coercion function of subcommands option. Closes #270
* added `Command.prototype.name` to retrieve command name. Closes #264 #266 @tonylukasavage
* added `Command.prototype.opts` to retrieve all the options as a simple object of key-value pairs. Closes #262 @tonylukasavage
* fixed a bug on subcommand name. Closes #248 @jonathandelgado
* fixed function normalize doesnt honor option terminator. Closes #216 @abbr
2.3.0 / 2014-07-16
==================
* add command alias'. Closes PR #210
* fix: Typos. Closes #99
* fix: Unused fs module. Closes #217
2.2.0 / 2014-03-29
==================
* add passing of previous option value
* fix: support subcommands on windows. Closes #142
* Now the defaultValue passed as the second argument of the coercion function.
2.1.0 / 2013-11-21
==================
* add: allow cflag style option params, unit test, fixes #174
2.0.0 / 2013-07-18
==================
* remove input methods (.prompt, .confirm, etc)
1.3.2 / 2013-07-18
==================
* add support for sub-commands to co-exist with the original command
1.3.1 / 2013-07-18
==================
* add quick .runningCommand hack so you can opt-out of other logic when running a sub command
1.3.0 / 2013-07-09
==================
* add EACCES error handling
* fix sub-command --help
1.2.0 / 2013-06-13
==================
* allow "-" hyphen as an option argument
* support for RegExp coercion
1.1.1 / 2012-11-20
==================
* add more sub-command padding
* fix .usage() when args are present. Closes #106
1.1.0 / 2012-11-16
==================
* add git-style executable subcommand support. Closes #94
1.0.5 / 2012-10-09
==================
* fix `--name` clobbering. Closes #92
* fix examples/help. Closes #89
1.0.4 / 2012-09-03
==================
* add `outputHelp()` method.
1.0.3 / 2012-08-30
==================
* remove invalid .version() defaulting
1.0.2 / 2012-08-24
==================
* add `--foo=bar` support [arv]
* fix password on node 0.8.8. Make backward compatible with 0.6 [focusaurus]
1.0.1 / 2012-08-03
==================
* fix issue #56
* fix tty.setRawMode(mode) was moved to tty.ReadStream#setRawMode() (i.e. process.stdin.setRawMode())
1.0.0 / 2012-07-05
==================
* add support for optional option descriptions
* add defaulting of `.version()` to package.json's version
0.6.1 / 2012-06-01
==================
* Added: append (yes or no) on confirmation
* Added: allow node.js v0.7.x
0.6.0 / 2012-04-10
==================
* Added `.prompt(obj, callback)` support. Closes #49
* Added default support to .choose(). Closes #41
* Fixed the choice example
0.5.1 / 2011-12-20
==================
* Fixed `password()` for recent nodes. Closes #36
0.5.0 / 2011-12-04
==================
* Added sub-command option support [itay]
0.4.3 / 2011-12-04
==================
* Fixed custom help ordering. Closes #32
0.4.2 / 2011-11-24
==================
* Added travis support
* Fixed: line-buffered input automatically trimmed. Closes #31
0.4.1 / 2011-11-18
==================
* Removed listening for "close" on --help
0.4.0 / 2011-11-15
==================
* Added support for `--`. Closes #24
0.3.3 / 2011-11-14
==================
* Fixed: wait for close event when writing help info [Jerry Hamlet]
0.3.2 / 2011-11-01
==================
* Fixed long flag definitions with values [felixge]
0.3.1 / 2011-10-31
==================
* Changed `--version` short flag to `-V` from `-v`
* Changed `.version()` so it's configurable [felixge]
0.3.0 / 2011-10-31
==================
* Added support for long flags only. Closes #18
0.2.1 / 2011-10-24
==================
* "node": ">= 0.4.x < 0.7.0". Closes #20
0.2.0 / 2011-09-26
==================
* Allow for defaults that are not just boolean. Default peassignment only occurs for --no-*, optional, and required arguments. [Jim Isaacs]
0.1.0 / 2011-08-24
==================
* Added support for custom `--help` output
0.0.5 / 2011-08-18
==================
* Changed: when the user enters nothing prompt for password again
* Fixed issue with passwords beginning with numbers [NuckChorris]
0.0.4 / 2011-08-15
==================
* Fixed `Commander#args`
0.0.3 / 2011-08-15
==================
* Added default option value support
0.0.2 / 2011-08-15
==================
* Added mask support to `Command#password(str[, mask], fn)`
* Added `Command#password(str, fn)`
0.0.1 / 2010-01-03
==================
* Initial release

View File

@@ -1,22 +0,0 @@
(The MIT License)
Copyright (c) 2011 TJ Holowaychuk <tj@vision-media.ca>
Permission is hereby granted, free of charge, to any person obtaining
a copy of this software and associated documentation files (the
'Software'), to deal in the Software without restriction, including
without limitation the rights to use, copy, modify, merge, publish,
distribute, sublicense, and/or sell copies of the Software, and to
permit persons to whom the Software is furnished to do so, subject to
the following conditions:
The above copyright notice and this permission notice shall be
included in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND,
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.

View File

@@ -1,428 +0,0 @@
# Commander.js
[![Build Status](https://api.travis-ci.org/tj/commander.js.svg?branch=master)](http://travis-ci.org/tj/commander.js)
[![NPM Version](http://img.shields.io/npm/v/commander.svg?style=flat)](https://www.npmjs.org/package/commander)
[![NPM Downloads](https://img.shields.io/npm/dm/commander.svg?style=flat)](https://npmcharts.com/compare/commander?minimal=true)
[![Install Size](https://packagephobia.now.sh/badge?p=commander)](https://packagephobia.now.sh/result?p=commander)
[![Join the chat at https://gitter.im/tj/commander.js](https://badges.gitter.im/Join%20Chat.svg)](https://gitter.im/tj/commander.js?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge)
The complete solution for [node.js](http://nodejs.org) command-line interfaces, inspired by Ruby's [commander](https://github.com/commander-rb/commander).
[API documentation](http://tj.github.com/commander.js/)
## Installation
$ npm install commander
## Option parsing
Options with commander are defined with the `.option()` method, also serving as documentation for the options. The example below parses args and options from `process.argv`, leaving remaining args as the `program.args` array which were not consumed by options.
```js
#!/usr/bin/env node
/**
* Module dependencies.
*/
var program = require('commander');
program
.version('0.1.0')
.option('-p, --peppers', 'Add peppers')
.option('-P, --pineapple', 'Add pineapple')
.option('-b, --bbq-sauce', 'Add bbq sauce')
.option('-c, --cheese [type]', 'Add the specified type of cheese [marble]', 'marble')
.parse(process.argv);
console.log('you ordered a pizza with:');
if (program.peppers) console.log(' - peppers');
if (program.pineapple) console.log(' - pineapple');
if (program.bbqSauce) console.log(' - bbq');
console.log(' - %s cheese', program.cheese);
```
Short flags may be passed as a single arg, for example `-abc` is equivalent to `-a -b -c`. Multi-word options such as "--template-engine" are camel-cased, becoming `program.templateEngine` etc.
Note that multi-word options starting with `--no` prefix negate the boolean value of the following word. For example, `--no-sauce` sets the value of `program.sauce` to false.
```js
#!/usr/bin/env node
/**
* Module dependencies.
*/
var program = require('commander');
program
.option('--no-sauce', 'Remove sauce')
.parse(process.argv);
console.log('you ordered a pizza');
if (program.sauce) console.log(' with sauce');
else console.log(' without sauce');
```
To get string arguments from options you will need to use angle brackets <> for required inputs or square brackets [] for optional inputs.
e.g. ```.option('-m --myarg [myVar]', 'my super cool description')```
Then to access the input if it was passed in.
e.g. ```var myInput = program.myarg```
**NOTE**: If you pass a argument without using brackets the example above will return true and not the value passed in.
## Version option
Calling the `version` implicitly adds the `-V` and `--version` options to the command.
When either of these options is present, the command prints the version number and exits.
$ ./examples/pizza -V
0.0.1
If you want your program to respond to the `-v` option instead of the `-V` option, simply pass custom flags to the `version` method using the same syntax as the `option` method.
```js
program
.version('0.0.1', '-v, --version')
```
The version flags can be named anything, but the long option is required.
## Command-specific options
You can attach options to a command.
```js
#!/usr/bin/env node
var program = require('commander');
program
.command('rm <dir>')
.option('-r, --recursive', 'Remove recursively')
.action(function (dir, cmd) {
console.log('remove ' + dir + (cmd.recursive ? ' recursively' : ''))
})
program.parse(process.argv)
```
A command's options are validated when the command is used. Any unknown options will be reported as an error. However, if an action-based command does not define an action, then the options are not validated.
## Coercion
```js
function range(val) {
return val.split('..').map(Number);
}
function list(val) {
return val.split(',');
}
function collect(val, memo) {
memo.push(val);
return memo;
}
function increaseVerbosity(v, total) {
return total + 1;
}
program
.version('0.1.0')
.usage('[options] <file ...>')
.option('-i, --integer <n>', 'An integer argument', parseInt)
.option('-f, --float <n>', 'A float argument', parseFloat)
.option('-r, --range <a>..<b>', 'A range', range)
.option('-l, --list <items>', 'A list', list)
.option('-o, --optional [value]', 'An optional value')
.option('-c, --collect [value]', 'A repeatable value', collect, [])
.option('-v, --verbose', 'A value that can be increased', increaseVerbosity, 0)
.parse(process.argv);
console.log(' int: %j', program.integer);
console.log(' float: %j', program.float);
console.log(' optional: %j', program.optional);
program.range = program.range || [];
console.log(' range: %j..%j', program.range[0], program.range[1]);
console.log(' list: %j', program.list);
console.log(' collect: %j', program.collect);
console.log(' verbosity: %j', program.verbose);
console.log(' args: %j', program.args);
```
## Regular Expression
```js
program
.version('0.1.0')
.option('-s --size <size>', 'Pizza size', /^(large|medium|small)$/i, 'medium')
.option('-d --drink [drink]', 'Drink', /^(coke|pepsi|izze)$/i)
.parse(process.argv);
console.log(' size: %j', program.size);
console.log(' drink: %j', program.drink);
```
## Variadic arguments
The last argument of a command can be variadic, and only the last argument. To make an argument variadic you have to
append `...` to the argument name. Here is an example:
```js
#!/usr/bin/env node
/**
* Module dependencies.
*/
var program = require('commander');
program
.version('0.1.0')
.command('rmdir <dir> [otherDirs...]')
.action(function (dir, otherDirs) {
console.log('rmdir %s', dir);
if (otherDirs) {
otherDirs.forEach(function (oDir) {
console.log('rmdir %s', oDir);
});
}
});
program.parse(process.argv);
```
An `Array` is used for the value of a variadic argument. This applies to `program.args` as well as the argument passed
to your action as demonstrated above.
## Specify the argument syntax
```js
#!/usr/bin/env node
var program = require('commander');
program
.version('0.1.0')
.arguments('<cmd> [env]')
.action(function (cmd, env) {
cmdValue = cmd;
envValue = env;
});
program.parse(process.argv);
if (typeof cmdValue === 'undefined') {
console.error('no command given!');
process.exit(1);
}
console.log('command:', cmdValue);
console.log('environment:', envValue || "no environment given");
```
Angled brackets (e.g. `<cmd>`) indicate required input. Square brackets (e.g. `[env]`) indicate optional input.
## Git-style sub-commands
```js
// file: ./examples/pm
var program = require('commander');
program
.version('0.1.0')
.command('install [name]', 'install one or more packages')
.command('search [query]', 'search with optional query')
.command('list', 'list packages installed', {isDefault: true})
.parse(process.argv);
```
When `.command()` is invoked with a description argument, no `.action(callback)` should be called to handle sub-commands, otherwise there will be an error. This tells commander that you're going to use separate executables for sub-commands, much like `git(1)` and other popular tools.
The commander will try to search the executables in the directory of the entry script (like `./examples/pm`) with the name `program-command`, like `pm-install`, `pm-search`.
Options can be passed with the call to `.command()`. Specifying `true` for `opts.noHelp` will remove the subcommand from the generated help output. Specifying `true` for `opts.isDefault` will run the subcommand if no other subcommand is specified.
If the program is designed to be installed globally, make sure the executables have proper modes, like `755`.
### `--harmony`
You can enable `--harmony` option in two ways:
* Use `#! /usr/bin/env node --harmony` in the sub-commands scripts. Note some os version dont support this pattern.
* Use the `--harmony` option when call the command, like `node --harmony examples/pm publish`. The `--harmony` option will be preserved when spawning sub-command process.
## Automated --help
The help information is auto-generated based on the information commander already knows about your program, so the following `--help` info is for free:
```
$ ./examples/pizza --help
Usage: pizza [options]
An application for pizzas ordering
Options:
-h, --help output usage information
-V, --version output the version number
-p, --peppers Add peppers
-P, --pineapple Add pineapple
-b, --bbq Add bbq sauce
-c, --cheese <type> Add the specified type of cheese [marble]
-C, --no-cheese You do not want any cheese
```
## Custom help
You can display arbitrary `-h, --help` information
by listening for "--help". Commander will automatically
exit once you are done so that the remainder of your program
does not execute causing undesired behaviors, for example
in the following executable "stuff" will not output when
`--help` is used.
```js
#!/usr/bin/env node
/**
* Module dependencies.
*/
var program = require('commander');
program
.version('0.1.0')
.option('-f, --foo', 'enable some foo')
.option('-b, --bar', 'enable some bar')
.option('-B, --baz', 'enable some baz');
// must be before .parse() since
// node's emit() is immediate
program.on('--help', function(){
console.log('')
console.log('Examples:');
console.log(' $ custom-help --help');
console.log(' $ custom-help -h');
});
program.parse(process.argv);
console.log('stuff');
```
Yields the following help output when `node script-name.js -h` or `node script-name.js --help` are run:
```
Usage: custom-help [options]
Options:
-h, --help output usage information
-V, --version output the version number
-f, --foo enable some foo
-b, --bar enable some bar
-B, --baz enable some baz
Examples:
$ custom-help --help
$ custom-help -h
```
## .outputHelp(cb)
Output help information without exiting.
Optional callback cb allows post-processing of help text before it is displayed.
If you want to display help by default (e.g. if no command was provided), you can use something like:
```js
var program = require('commander');
var colors = require('colors');
program
.version('0.1.0')
.command('getstream [url]', 'get stream URL')
.parse(process.argv);
if (!process.argv.slice(2).length) {
program.outputHelp(make_red);
}
function make_red(txt) {
return colors.red(txt); //display the help text in red on the console
}
```
## .help(cb)
Output help information and exit immediately.
Optional callback cb allows post-processing of help text before it is displayed.
## Custom event listeners
You can execute custom actions by listening to command and option events.
```js
program.on('option:verbose', function () {
process.env.VERBOSE = this.verbose;
});
// error on unknown commands
program.on('command:*', function () {
console.error('Invalid command: %s\nSee --help for a list of available commands.', program.args.join(' '));
process.exit(1);
});
```
## Examples
```js
var program = require('commander');
program
.version('0.1.0')
.option('-C, --chdir <path>', 'change the working directory')
.option('-c, --config <path>', 'set config path. defaults to ./deploy.conf')
.option('-T, --no-tests', 'ignore test hook');
program
.command('setup [env]')
.description('run setup commands for all envs')
.option("-s, --setup_mode [mode]", "Which setup mode to use")
.action(function(env, options){
var mode = options.setup_mode || "normal";
env = env || 'all';
console.log('setup for %s env(s) with %s mode', env, mode);
});
program
.command('exec <cmd>')
.alias('ex')
.description('execute the given remote cmd')
.option("-e, --exec_mode <mode>", "Which exec mode to use")
.action(function(cmd, options){
console.log('exec "%s" using %s mode', cmd, options.exec_mode);
}).on('--help', function() {
console.log('');
console.log('Examples:');
console.log('');
console.log(' $ deploy exec sequential');
console.log(' $ deploy exec async');
});
program
.command('*')
.action(function(env){
console.log('deploying "%s"', env);
});
program.parse(process.argv);
```
More Demos can be found in the [examples](https://github.com/tj/commander.js/tree/master/examples) directory.
## License
[MIT](https://github.com/tj/commander.js/blob/master/LICENSE)

File diff suppressed because it is too large Load Diff

View File

@@ -1,73 +0,0 @@
{
"_args": [
[
"commander@2.20.3",
"/home/runner/work/owncast/owncast/build/javascript"
]
],
"_from": "commander@2.20.3",
"_id": "commander@2.20.3",
"_inBundle": false,
"_integrity": "sha512-GpVkmM8vF2vQUkj2LvZmD35JxeJOLCwJ9cUkugyk2nuhbv3+mJvpLYYt+0+USMxE+oj+ey/lJEnhZw75x/OMcQ==",
"_location": "/video.js/commander",
"_phantomChildren": {},
"_requested": {
"type": "version",
"registry": true,
"raw": "commander@2.20.3",
"name": "commander",
"escapedName": "commander",
"rawSpec": "2.20.3",
"saveSpec": null,
"fetchSpec": "2.20.3"
},
"_requiredBy": [
"/video.js/aes-decrypter"
],
"_resolved": "https://registry.npmjs.org/commander/-/commander-2.20.3.tgz",
"_spec": "2.20.3",
"_where": "/home/runner/work/owncast/owncast/build/javascript",
"author": {
"name": "TJ Holowaychuk",
"email": "tj@vision-media.ca"
},
"bugs": {
"url": "https://github.com/tj/commander.js/issues"
},
"dependencies": {},
"description": "the complete solution for node.js command-line programs",
"devDependencies": {
"@types/node": "^12.7.8",
"eslint": "^6.4.0",
"should": "^13.2.3",
"sinon": "^7.5.0",
"standard": "^14.3.1",
"ts-node": "^8.4.1",
"typescript": "^3.6.3"
},
"files": [
"index.js",
"typings/index.d.ts"
],
"homepage": "https://github.com/tj/commander.js#readme",
"keywords": [
"commander",
"command",
"option",
"parser"
],
"license": "MIT",
"main": "index",
"name": "commander",
"repository": {
"type": "git",
"url": "git+https://github.com/tj/commander.js.git"
},
"scripts": {
"lint": "eslint index.js",
"test": "node test/run.js && npm run test-typings",
"test-typings": "tsc -p tsconfig.json"
},
"typings": "typings/index.d.ts",
"version": "2.20.3"
}

View File

@@ -1,310 +0,0 @@
// Type definitions for commander 2.11
// Project: https://github.com/visionmedia/commander.js
// Definitions by: Alan Agius <https://github.com/alan-agius4>, Marcelo Dezem <https://github.com/mdezem>, vvakame <https://github.com/vvakame>, Jules Randolph <https://github.com/sveinburne>
// Definitions: https://github.com/DefinitelyTyped/DefinitelyTyped
declare namespace local {
class Option {
flags: string;
required: boolean;
optional: boolean;
bool: boolean;
short?: string;
long: string;
description: string;
/**
* Initialize a new `Option` with the given `flags` and `description`.
*
* @param {string} flags
* @param {string} [description]
*/
constructor(flags: string, description?: string);
}
class Command extends NodeJS.EventEmitter {
[key: string]: any;
args: string[];
/**
* Initialize a new `Command`.
*
* @param {string} [name]
*/
constructor(name?: string);
/**
* Set the program version to `str`.
*
* This method auto-registers the "-V, --version" flag
* which will print the version number when passed.
*
* @param {string} str
* @param {string} [flags]
* @returns {Command} for chaining
*/
version(str: string, flags?: string): Command;
/**
* Add command `name`.
*
* The `.action()` callback is invoked when the
* command `name` is specified via __ARGV__,
* and the remaining arguments are applied to the
* function for access.
*
* When the `name` is "*" an un-matched command
* will be passed as the first arg, followed by
* the rest of __ARGV__ remaining.
*
* @example
* program
* .version('0.0.1')
* .option('-C, --chdir <path>', 'change the working directory')
* .option('-c, --config <path>', 'set config path. defaults to ./deploy.conf')
* .option('-T, --no-tests', 'ignore test hook')
*
* program
* .command('setup')
* .description('run remote setup commands')
* .action(function() {
* console.log('setup');
* });
*
* program
* .command('exec <cmd>')
* .description('run the given remote command')
* .action(function(cmd) {
* console.log('exec "%s"', cmd);
* });
*
* program
* .command('teardown <dir> [otherDirs...]')
* .description('run teardown commands')
* .action(function(dir, otherDirs) {
* console.log('dir "%s"', dir);
* if (otherDirs) {
* otherDirs.forEach(function (oDir) {
* console.log('dir "%s"', oDir);
* });
* }
* });
*
* program
* .command('*')
* .description('deploy the given env')
* .action(function(env) {
* console.log('deploying "%s"', env);
* });
*
* program.parse(process.argv);
*
* @param {string} name
* @param {string} [desc] for git-style sub-commands
* @param {CommandOptions} [opts] command options
* @returns {Command} the new command
*/
command(name: string, desc?: string, opts?: commander.CommandOptions): Command;
/**
* Define argument syntax for the top-level command.
*
* @param {string} desc
* @returns {Command} for chaining
*/
arguments(desc: string): Command;
/**
* Parse expected `args`.
*
* For example `["[type]"]` becomes `[{ required: false, name: 'type' }]`.
*
* @param {string[]} args
* @returns {Command} for chaining
*/
parseExpectedArgs(args: string[]): Command;
/**
* Register callback `fn` for the command.
*
* @example
* program
* .command('help')
* .description('display verbose help')
* .action(function() {
* // output help here
* });
*
* @param {(...args: any[]) => void} fn
* @returns {Command} for chaining
*/
action(fn: (...args: any[]) => void): Command;
/**
* Define option with `flags`, `description` and optional
* coercion `fn`.
*
* The `flags` string should contain both the short and long flags,
* separated by comma, a pipe or space. The following are all valid
* all will output this way when `--help` is used.
*
* "-p, --pepper"
* "-p|--pepper"
* "-p --pepper"
*
* @example
* // simple boolean defaulting to false
* program.option('-p, --pepper', 'add pepper');
*
* --pepper
* program.pepper
* // => Boolean
*
* // simple boolean defaulting to true
* program.option('-C, --no-cheese', 'remove cheese');
*
* program.cheese
* // => true
*
* --no-cheese
* program.cheese
* // => false
*
* // required argument
* program.option('-C, --chdir <path>', 'change the working directory');
*
* --chdir /tmp
* program.chdir
* // => "/tmp"
*
* // optional argument
* program.option('-c, --cheese [type]', 'add cheese [marble]');
*
* @param {string} flags
* @param {string} [description]
* @param {((arg1: any, arg2: any) => void) | RegExp} [fn] function or default
* @param {*} [defaultValue]
* @returns {Command} for chaining
*/
option(flags: string, description?: string, fn?: ((arg1: any, arg2: any) => void) | RegExp, defaultValue?: any): Command;
option(flags: string, description?: string, defaultValue?: any): Command;
/**
* Allow unknown options on the command line.
*
* @param {boolean} [arg] if `true` or omitted, no error will be thrown for unknown options.
* @returns {Command} for chaining
*/
allowUnknownOption(arg?: boolean): Command;
/**
* Parse `argv`, settings options and invoking commands when defined.
*
* @param {string[]} argv
* @returns {Command} for chaining
*/
parse(argv: string[]): Command;
/**
* Parse options from `argv` returning `argv` void of these options.
*
* @param {string[]} argv
* @returns {ParseOptionsResult}
*/
parseOptions(argv: string[]): commander.ParseOptionsResult;
/**
* Return an object containing options as key-value pairs
*
* @returns {{[key: string]: any}}
*/
opts(): { [key: string]: any };
/**
* Set the description to `str`.
*
* @param {string} str
* @param {{[argName: string]: string}} argsDescription
* @return {(Command | string)}
*/
description(str: string, argsDescription?: {[argName: string]: string}): Command;
description(): string;
/**
* Set an alias for the command.
*
* @param {string} alias
* @return {(Command | string)}
*/
alias(alias: string): Command;
alias(): string;
/**
* Set or get the command usage.
*
* @param {string} str
* @return {(Command | string)}
*/
usage(str: string): Command;
usage(): string;
/**
* Set the name of the command.
*
* @param {string} str
* @return {Command}
*/
name(str: string): Command;
/**
* Get the name of the command.
*
* @return {string}
*/
name(): string;
/**
* Output help information for this command.
*
* @param {(str: string) => string} [cb]
*/
outputHelp(cb?: (str: string) => string): void;
/** Output help information and exit.
*
* @param {(str: string) => string} [cb]
*/
help(cb?: (str: string) => string): never;
}
}
declare namespace commander {
type Command = local.Command
type Option = local.Option
interface CommandOptions {
noHelp?: boolean;
isDefault?: boolean;
}
interface ParseOptionsResult {
args: string[];
unknown: string[];
}
interface CommanderStatic extends Command {
Command: typeof local.Command;
Option: typeof local.Option;
CommandOptions: CommandOptions;
ParseOptionsResult: ParseOptionsResult;
}
}
declare const commander: commander.CommanderStatic;
export = commander;

View File

@@ -1,15 +0,0 @@
.DS_Store
.monitor
.*.swp
.nodemonignore
releases
*.log
*.err
fleet.json
public/browserify
bin/*.json
.bin
build
compile
.lock-wscript
node_modules

View File

@@ -1,4 +0,0 @@
language: node_js
node_js:
- 0.8
- 0.9

View File

@@ -1,19 +0,0 @@
Copyright (c) 2012 Colingo.
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.

View File

@@ -1,30 +0,0 @@
# global
<!-- [![build status][1]][2]
[![browser support][3]][4] -->
Require global variables
## Example
```js
var global = require("global")
var document = require("global/document")
var window = require("global/window")
```
## Installation
`npm install global`
## Contributors
- Raynos
## MIT Licenced
[1]: https://secure.travis-ci.org/Colingo/global.png
[2]: http://travis-ci.org/Colingo/global
[3]: http://ci.testling.com/Colingo/global.png
[4]: http://ci.testling.com/Colingo/global

View File

@@ -1 +0,0 @@
module.exports = console;

View File

@@ -1,17 +0,0 @@
var topLevel = typeof global !== 'undefined' ? global :
typeof window !== 'undefined' ? window : {}
var minDoc = require('min-document');
var doccy;
if (typeof document !== 'undefined') {
doccy = document;
} else {
doccy = topLevel['__GLOBAL_DOCUMENT_CACHE@4'];
if (!doccy) {
doccy = topLevel['__GLOBAL_DOCUMENT_CACHE@4'] = minDoc;
}
}
module.exports = doccy;

View File

@@ -1,102 +0,0 @@
{
"_args": [
[
"global@4.3.2",
"/home/runner/work/owncast/owncast/build/javascript"
]
],
"_from": "global@4.3.2",
"_id": "global@4.3.2",
"_inBundle": false,
"_integrity": "sha1-52mJJopsdMOJCLEwWxD8DjlOnQ8=",
"_location": "/video.js/global",
"_phantomChildren": {},
"_requested": {
"type": "version",
"registry": true,
"raw": "global@4.3.2",
"name": "global",
"escapedName": "global",
"rawSpec": "4.3.2",
"saveSpec": null,
"fetchSpec": "4.3.2"
},
"_requiredBy": [
"/video.js",
"/video.js/@videojs/http-streaming",
"/video.js/@videojs/vhs-utils",
"/video.js/aes-decrypter",
"/video.js/m3u8-parser",
"/video.js/mpd-parser"
],
"_resolved": "https://registry.npmjs.org/global/-/global-4.3.2.tgz",
"_spec": "4.3.2",
"_where": "/home/runner/work/owncast/owncast/build/javascript",
"author": {
"name": "Raynos",
"email": "raynos2@gmail.com"
},
"browser": {
"min-document": false,
"individual": false
},
"bugs": {
"url": "https://github.com/Raynos/global/issues",
"email": "raynos2@gmail.com"
},
"contributors": [
{
"name": "Raynos"
}
],
"dependencies": {
"min-document": "^2.19.0",
"process": "~0.5.1"
},
"description": "Require global variables",
"devDependencies": {
"tape": "^2.12.0"
},
"homepage": "https://github.com/Raynos/global",
"keywords": [],
"license": "MIT",
"main": "window.js",
"name": "global",
"repository": {
"type": "git",
"url": "git://github.com/Raynos/global.git"
},
"scripts": {
"build": "browserify test/index.js -o test/static/bundle.js",
"test": "node ./test",
"testem": "testem"
},
"testling": {
"files": "test/index.js",
"browsers": {
"ie": [
"8",
"9",
"10"
],
"firefox": [
"16",
"17",
"nightly"
],
"chrome": [
"22",
"23",
"canary"
],
"opera": [
"12",
"next"
],
"safari": [
"5.1"
]
}
},
"version": "4.3.2"
}

View File

@@ -1 +0,0 @@
module.exports = require('process');

View File

@@ -1,13 +0,0 @@
var win;
if (typeof window !== "undefined") {
win = window;
} else if (typeof global !== "undefined") {
win = global;
} else if (typeof self !== "undefined"){
win = self;
} else {
win = {};
}
module.exports = win;

View File

@@ -1,82 +0,0 @@
<a name="4.4.0"></a>
# [4.4.0](https://github.com/videojs/m3u8-parser/compare/v4.3.0...v4.4.0) (2019-06-25)
### Features
* parse key attributes for Widevine HLS ([#88](https://github.com/videojs/m3u8-parser/issues/88)) ([d835fa8](https://github.com/videojs/m3u8-parser/commit/d835fa8))
### Chores
* **package:** update all dev dependencies ([#89](https://github.com/videojs/m3u8-parser/issues/89)) ([e991447](https://github.com/videojs/m3u8-parser/commit/e991447))
<a name="4.3.0"></a>
# [4.3.0](https://github.com/videojs/m3u8-parser/compare/v4.2.0...v4.3.0) (2019-01-10)
### Features
* custom tag mapping ([#73](https://github.com/videojs/m3u8-parser/issues/73)) ([0ef040a](https://github.com/videojs/m3u8-parser/commit/0ef040a))
### Chores
* Update to plugin generator 7 standards ([#53](https://github.com/videojs/m3u8-parser/issues/53)) ([35ff471](https://github.com/videojs/m3u8-parser/commit/35ff471))
* **package:** update rollup to version 0.66.0 ([#55](https://github.com/videojs/m3u8-parser/issues/55)) ([2407466](https://github.com/videojs/m3u8-parser/commit/2407466))
* Update videojs-generate-karma-config to the latest version 🚀 ([#59](https://github.com/videojs/m3u8-parser/issues/59)) ([023c6c9](https://github.com/videojs/m3u8-parser/commit/023c6c9))
* Update videojs-generate-karma-config to the latest version 🚀 ([#60](https://github.com/videojs/m3u8-parser/issues/60)) ([2773819](https://github.com/videojs/m3u8-parser/commit/2773819))
* Update videojs-generate-rollup-config to the latest version 🚀 ([#58](https://github.com/videojs/m3u8-parser/issues/58)) ([8c28a8b](https://github.com/videojs/m3u8-parser/commit/8c28a8b))
<a name="4.2.0"></a>
# [4.2.0](https://github.com/videojs/m3u8-parser/compare/v4.1.0...v4.2.0) (2018-02-23)
### Features
* add program-date-time tag info to parsed segments ([#27](https://github.com/videojs/m3u8-parser/issues/27)) ([44fc6f8](https://github.com/videojs/m3u8-parser/commit/44fc6f8))
<a name="4.1.0"></a>
# [4.1.0](https://github.com/videojs/m3u8-parser/compare/v4.0.0...v4.1.0) (2018-01-24)
<a name="4.0.0"></a>
# [4.0.0](https://github.com/videojs/m3u8-parser/compare/v3.0.0...v4.0.0) (2017-11-21)
### Features
* added ability to parse EXT-X-START tags [#31](https://github.com/videojs/m3u8-parser/pull/31)
### BREAKING CHANGES
* camel case module name in rollup config to work with latest rollup [#32](https://github.com/videojs/m3u8-parser/pull/32)
<a name="3.0.0"></a>
# 3.0.0 (2017-06-09)
### Features
* Rollup ([#24](https://github.com/videojs/m3u8-parser/issues/24)) ([47ef11f](https://github.com/videojs/m3u8-parser/commit/47ef11f))
### BREAKING CHANGES
* drop bower support.
## 2.1.0 (2017-02-23)
* parse FORCED attribute of media-groups [#15](https://github.com/videojs/m3u8-parser/pull/15)
* Pass any CHARACTERISTICS value of a track with the track object [#14](https://github.com/videojs/m3u8-parser/pull/14)
## 2.0.1 (2017-01-20)
* Fix: Include the babel ES3 tranform to support IE8 [#13](https://github.com/videojs/m3u8-parser/pull/13)
## 2.0.0 (2017-01-13)
* Manifest object is now initialized with an empty segments arrays
* moved to latest videojs-standard version, brought code into
compliance with the latest eslint rules.
## 1.0.2 (2016-06-07)
* fix the build pipeline
* removed video.js css/js inclusion during tests
## 1.0.1 (2016-06-07)
* remove dependence on video.js
* added contributors to package.json
## 1.0.0 (2016-06-03)
Initial Release

View File

@@ -1,30 +0,0 @@
# CONTRIBUTING
We welcome contributions from everyone!
## Getting Started
Make sure you have Node.js 4.8 or higher and npm installed.
1. Fork this repository and clone your fork
1. Install dependencies: `npm install`
1. Run a development server: `npm start`
### Making Changes
Refer to the [video.js plugin conventions][conventions] for more detail on best practices and tooling for video.js plugin authorship.
When you've made your changes, push your commit(s) to your fork and issue a pull request against the original repository.
### Running Tests
Testing is a crucial part of any software project. For all but the most trivial changes (typos, etc) test cases are expected. Tests are run in actual browsers using [Karma][karma].
- In all available and supported browsers: `npm test`
- In a specific browser: `npm run test:chrome`, `npm run test:firefox`, etc.
- While development server is running (`npm start`), navigate to [`http://localhost:9999/test/`][local]
[karma]: http://karma-runner.github.io/
[local]: http://localhost:9999/test/
[conventions]: https://github.com/videojs/generator-videojs-plugin/blob/master/docs/conventions.md

View File

@@ -1,13 +0,0 @@
Copyright Brightcove, Inc
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.

View File

@@ -1,388 +0,0 @@
# m3u8-parser
[![Build Status](https://travis-ci.org/videojs/m3u8-parser.svg?branch=master)](https://travis-ci.org/videojs/m3u8-parser)
[![Greenkeeper badge](https://badges.greenkeeper.io/videojs/m3u8-parser.svg)](https://greenkeeper.io/)
[![Slack Status](http://slack.videojs.com/badge.svg)](http://slack.videojs.com)
[![NPM](https://nodei.co/npm/m3u8-parser.png?downloads=true&downloadRank=true)](https://nodei.co/npm/m3u8-parser/)
m3u8 parser
<!-- START doctoc generated TOC please keep comment here to allow auto update -->
<!-- DON'T EDIT THIS SECTION, INSTEAD RE-RUN doctoc TO UPDATE -->
- [Installation](#installation)
- [Usage](#usage)
- [Parsed Output](#parsed-output)
- [Supported Tags](#supported-tags)
- [Basic Playlist Tags](#basic-playlist-tags)
- [Media Segment Tags](#media-segment-tags)
- [Media Playlist Tags](#media-playlist-tags)
- [Master Playlist Tags](#master-playlist-tags)
- [Experimental Tags](#experimental-tags)
- [EXT-X-CUE-OUT](#ext-x-cue-out)
- [EXT-X-CUE-OUT-CONT](#ext-x-cue-out-cont)
- [EXT-X-CUE-IN](#ext-x-cue-in)
- [Not Yet Supported](#not-yet-supported)
- [Custom Parsers](#custom-parsers)
- [Including the Parser](#including-the-parser)
- [`<script>` Tag](#script-tag)
- [Browserify](#browserify)
- [RequireJS/AMD](#requirejsamd)
- [License](#license)
<!-- END doctoc generated TOC please keep comment here to allow auto update -->
## Installation
```sh
npm install --save m3u8-parser
```
The npm installation is preferred, but Bower works, too.
```sh
bower install --save m3u8-parser
```
## Usage
```js
var manifest = [
'#EXTM3U',
'#EXT-X-VERSION:3',
'#EXT-X-TARGETDURATION:6',
'#EXT-X-MEDIA-SEQUENCE:0',
'#EXT-X-DISCONTINUITY-SEQUENCE:0',
'#EXTINF:6,',
'0.ts',
'#EXTINF:6,',
'1.ts',
'#EXTINF:6,',
'2.ts',
'#EXT-X-ENDLIST'
].join('\n');
var parser = new m3u8Parser.Parser();
parser.push(manifest);
parser.end();
var parsedManifest = parser.manifest;
```
### Parsed Output
The parser ouputs a plain javascript object with the following structure:
```js
Manifest {
allowCache: boolean,
endList: boolean,
mediaSequence: number,
discontinuitySequence: number,
playlistType: string,
custom: {},
playlists: [
{
attributes: {},
Manifest
}
],
mediaGroups: {
AUDIO: {
'GROUP-ID': {
NAME: {
default: boolean,
autoselect: boolean,
language: string,
uri: string,
instreamId: string,
characteristics: string,
forced: boolean
}
}
},
VIDEO: {},
'CLOSED-CAPTIONS': {},
SUBTITLES: {}
},
dateTimeString: string,
dateTimeObject: Date,
targetDuration: number,
totalDuration: number,
discontinuityStarts: [number],
segments: [
{
byterange: {
length: number,
offset: number
},
duration: number,
attributes: {},
discontinuity: number,
uri: string,
timeline: number,
key: {
method: string,
uri: string,
iv: string
},
map: {
uri: string,
byterange: {
length: number,
offset: number
}
},
'cue-out': string,
'cue-out-cont': string,
'cue-in': string,
custom: {}
}
]
}
```
## Supported Tags
### Basic Playlist Tags
* [EXTM3U](http://tools.ietf.org/html/draft-pantos-http-live-streaming#section-4.3.1.1)
* [EXT-X-VERSION](http://tools.ietf.org/html/draft-pantos-http-live-streaming#section-4.3.1.2)
### Media Segment Tags
* [EXTINF](http://tools.ietf.org/html/draft-pantos-http-live-streaming#section-4.3.2.1)
* [EXT-X-BYTERANGE](http://tools.ietf.org/html/draft-pantos-http-live-streaming#section-4.3.2.2)
* [EXT-X-DISCONTINUITY](http://tools.ietf.org/html/draft-pantos-http-live-streaming#section-4.3.2.3)
* [EXT-X-KEY](http://tools.ietf.org/html/draft-pantos-http-live-streaming#section-4.3.2.4)
* [EXT-X-MAP](http://tools.ietf.org/html/draft-pantos-http-live-streaming#section-4.3.2.5)
* [EXT-X-PROGRAM-DATE-TIME](http://tools.ietf.org/html/draft-pantos-http-live-streaming#section-4.3.2.6)
### Media Playlist Tags
* [EXT-X-TARGETDURATION](http://tools.ietf.org/html/draft-pantos-http-live-streaming#section-4.3.3.1)
* [EXT-X-MEDIA-SEQUENCE](http://tools.ietf.org/html/draft-pantos-http-live-streaming#section-4.3.3.2)
* [EXT-X-DISCONTINUITY-SEQUENCE](http://tools.ietf.org/html/draft-pantos-http-live-streaming#section-4.3.3.3)
* [EXT-X-ENDLIST](http://tools.ietf.org/html/draft-pantos-http-live-streaming#section-4.3.3.4)
* [EXT-X-PLAYLIST-TYPE](http://tools.ietf.org/html/draft-pantos-http-live-streaming#section-4.3.3.5)
* [EXT-X-START](http://tools.ietf.org/html/draft-pantos-http-live-streaming#section-4.3.5.2)
### Master Playlist Tags
* [EXT-X-MEDIA](http://tools.ietf.org/html/draft-pantos-http-live-streaming#section-4.3.4.1)
* [EXT-X-STREAM-INF](http://tools.ietf.org/html/draft-pantos-http-live-streaming#section-4.3.4.2)
### Experimental Tags
m3u8-parser supports 3 additional **Media Segment Tags** not present in the HLS specification.
#### EXT-X-CUE-OUT
The `EXT-X-CUE-OUT` indicates that the following media segment is a break in main content and the start of interstitial content. Its format is:
```
#EXT-X-CUE-OUT:<duration>
```
where `duration` is a decimal-floating-point or decimal-integer number that specifies the total duration of the interstitial in seconds.
#### EXT-X-CUE-OUT-CONT
The `EXT-X-CUE-OUT-CONT` indicates that the following media segment is a part of interstitial content and not the main content. Every media segment following a media segment with an `EXT-X-CUE-OUT` tag *SHOULD* have an `EXT-X-CUE-OUT-CONT` applied to it until there is an `EXT-X-CUE-IN` tag. A media segment between a `EXT-X-CUE-OUT` and `EXT-X-CUE-IN` segment without a `EXT-X-CUE-OUT-CONT` is assumed to be part of the interstitial. Its format is:
```
#EXT-X-CUE-OUT-CONT:<n>/<duration>
```
where `n` is a decimal-floating-point or decimal-integer number that specifies the time in seconds the first sample of the media segment lies within the interstitial content and `duration` is a decimal-floating-point or decimal-integer number that specifies the total duration of the interstitial in seconds. `n` *SHOULD* be the sum of `EXTINF` durations for all preceding media segments up to the `EXT-X-CUE-OUT` tag for the current interstitial. `duration` *SHOULD* match the `duration` specified in the `EXT-X-CUE-OUT` tag for the current interstitial.'
#### EXT-X-CUE-IN
The `EXT-X-CUE-IN` indicates the end of the interstitial and the return of the main content. Its format is:
```
#EXT-X-CUE-IN
```
There *SHOULD* be a closing `EXT-X-CUE-IN` tag for every `EXT-X-CUE-OUT` tag. If a second `EXT-X-CUE-OUT` tag is encountered before an `EXT-X-CUE-IN` tag, the client *MAY* choose to ignore the `EXT-X-CUE-OUT` and treat it as part of the interstitial, or reject the playlist.
Example media playlist using `EXT-X-CUE-` tags.
```
#EXTM3U
#EXT-X-VERSION:3
#EXT-X-TARGETDURATION:10
#EXTINF:10,
0.ts
#EXTINF:10,
1.ts
#EXT-X-CUE-OUT:30
#EXTINF:10,
2.ts
#EXT-X-CUE-OUT-CONT:10/30
#EXTINF:10,
3.ts
#EXT-X-CUE-OUT-CONT:20/30
#EXTINF:10,
4.ts
#EXT-X-CUE-IN
#EXTINF:10,
5.ts
#EXTINF:10,
6.ts
#EXT-X-ENDLIST
```
### Not Yet Supported
* [EXT-X-DATERANGE](http://tools.ietf.org/html/draft-pantos-http-live-streaming#section-4.3.2.7)
* [EXT-X-I-FRAMES-ONLY](http://tools.ietf.org/html/draft-pantos-http-live-streaming#section-4.3.3.6)
* [EXT-X-I-FRAME-STREAM-INF](http://tools.ietf.org/html/draft-pantos-http-live-streaming#section-4.3.4.3)
* [EXT-X-SESSION-DATA](http://tools.ietf.org/html/draft-pantos-http-live-streaming#section-4.3.4.4)
* [EXT-X-SESSION-KEY](http://tools.ietf.org/html/draft-pantos-http-live-streaming#section-4.3.4.5)
* [EXT-X-INDEPENDENT-SEGMENTS](http://tools.ietf.org/html/draft-pantos-http-live-streaming#section-4.3.5.1)
### Custom Parsers
To add a parser for a non-standard tag the parser object allows for the specification of custom tags using regular expressions. If a custom parser is specified, a `custom` object is appended to the manifest object.
```js
const manifest = [
'#EXTM3U',
'#EXT-X-VERSION:3',
'#VOD-FRAMERATE:29.97',
''
].join('\n');
const parser = new m3u8Parser.Parser();
parser.addParser({
expression: /^#VOD-FRAMERATE/,
customType: 'framerate'
});
parser.push(manifest);
parser.end();
parser.manifest.custom.framerate // "#VOD-FRAMERATE:29.97"
```
Custom parsers may additionally be provided a data parsing function that take a line and return a value.
```js
const manifest = [
'#EXTM3U',
'#EXT-X-VERSION:3',
'#VOD-FRAMERATE:29.97',
''
].join('\n');
const parser = new m3u8Parser.Parser();
parser.addParser({
expression: /^#VOD-FRAMERATE/,
customType: 'framerate',
dataParser: function(line) {
return parseFloat(line.split(':')[1]);
}
});
parser.push(manifest);
parser.end();
parser.manifest.custom.framerate // 29.97
```
Custom parsers may also extract data at a segment level by passing `segment: true` to the options object. Having a segment level custom parser will add a `custom` object to the segment data.
```js
const manifest = [
'#EXTM3U',
'#VOD-TIMING:1511816599485',
'#EXTINF:8.0,',
'ex1.ts',
''
].join('\n');
const parser = new m3u8Parser.Parser();
parser.addParser({
expression: /#VOD-TIMING/,
customType: 'vodTiming',
segment: true
});
parser.push(manifest);
parser.end();
parser.manifest.segments[0].custom.vodTiming // #VOD-TIMING:1511816599485
```
Custom parsers may also map a tag to another tag. The old tag will not be replaced and all matching registered mappers and parsers will be executed.
```js
const manifest = [
'#EXTM3U',
'#EXAMPLE',
'#EXTINF:8.0,',
'ex1.ts',
''
].join('\n');
const parser = new m3u8Parser.Parser();
parser.addTagMapper({
expression: /#EXAMPLE/,
map(line) {
return `#NEW-TAG:123`;
}
});
parser.addParser({
expression: /#NEW-TAG/,
customType: 'mappingExample',
segment: true
});
parser.push(manifest);
parser.end();
parser.manifest.segments[0].custom.mappingExample // #NEW-TAG:123
```
## Including the Parser
To include m3u8-parser on your website or web application, use any of the following methods.
### `<script>` Tag
This is the simplest case. Get the script in whatever way you prefer and include it on your page.
```html
<script src="//path/to/m3u8-parser.min.js"></script>
<script>
var parser = new m3u8Parser.Parser();
</script>
```
### Browserify
When using with Browserify, install m3u8-parser via npm and `require` the parser as you would any other module.
```js
var m3u8Parser = require('m3u8-parser');
var parser = new m3u8Parser.Parser();
```
With ES6:
```js
import { Parser } from 'm3u8-parser';
const parser = new Parser();
```
### RequireJS/AMD
When using with RequireJS (or another AMD library), get the script in whatever way you prefer and `require` the parser as you normally would:
```js
require(['m3u8-parser'], function(m3u8Parser) {
var parser = new m3u8Parser.Parser();
});
```
## License
Apache-2.0. Copyright (c) Brightcove, Inc

View File

@@ -1,15 +0,0 @@
<!doctype html>
<html>
<head>
<meta charset="utf-8">
<title>m3u8-parser Demo</title>
</head>
<body>
<p>Open dev tools to try it out</p>
<ul>
<li><a href="test/debug.html">Run unit tests in browser.</a></li>
<li><a href="docs/api/">Read generated docs.</a></li>
</ul>
<script src="dist/m3u8-parser.js"></script>
</body>
</html>

View File

@@ -1,146 +0,0 @@
{
"_args": [
[
"m3u8-parser@4.4.0",
"/home/runner/work/owncast/owncast/build/javascript"
]
],
"_from": "m3u8-parser@4.4.0",
"_id": "m3u8-parser@4.4.0",
"_inBundle": false,
"_integrity": "sha512-iH2AygTFILtato+XAgnoPYzLHM4R3DjATj7Ozbk7EHdB2XoLF2oyOUguM7Kc4UVHbQHHL/QPaw98r7PbWzG0gg==",
"_location": "/video.js/m3u8-parser",
"_phantomChildren": {},
"_requested": {
"type": "version",
"registry": true,
"raw": "m3u8-parser@4.4.0",
"name": "m3u8-parser",
"escapedName": "m3u8-parser",
"rawSpec": "4.4.0",
"saveSpec": null,
"fetchSpec": "4.4.0"
},
"_requiredBy": [
"/video.js/@videojs/http-streaming"
],
"_resolved": "https://registry.npmjs.org/m3u8-parser/-/m3u8-parser-4.4.0.tgz",
"_spec": "4.4.0",
"_where": "/home/runner/work/owncast/owncast/build/javascript",
"author": {
"name": "Brightcove, Inc"
},
"browserslist": [
"defaults",
"ie 11"
],
"bugs": {
"url": "https://github.com/videojs/m3u8-parser/issues"
},
"contributors": [
{
"name": "gkatsev"
},
{
"name": "imbcmdth"
},
{
"name": "dmlap"
}
],
"dependencies": {
"global": "^4.3.2"
},
"description": "m3u8 parser",
"devDependencies": {
"conventional-changelog-cli": "^2.0.22",
"conventional-changelog-videojs": "^3.0.0",
"doctoc": "^1.4.0",
"husky": "^2.5.0",
"jsdoc": "git+https://github.com/BrandonOCasey/jsdoc.git#feat/plugin-from-cli",
"karma": "^4.1.0",
"lint-staged": "^8.2.1",
"not-prerelease": "^1.0.1",
"npm-merge-driver-install": "^1.1.1",
"npm-run-all": "^4.1.5",
"pkg-ok": "^2.3.1",
"rollup": "^1.16.2",
"shx": "^0.3.2",
"sinon": "^7.3.2",
"videojs-generate-karma-config": "^5.3.0",
"videojs-generate-rollup-config": "^3.2.0",
"videojs-generator-verify": "^1.2.0",
"videojs-standard": "^8.0.3"
},
"files": [
"CONTRIBUTING.md",
"dist/",
"docs/",
"index.html",
"scripts/",
"src/",
"test/"
],
"generator-videojs-plugin": {
"version": "7.3.2"
},
"homepage": "https://github.com/videojs/m3u8-parser#readme",
"husky": {
"hooks": {
"pre-commit": "lint-staged"
}
},
"keywords": [
"videojs",
"videojs-plugin"
],
"license": "Apache-2.0",
"lint-staged": {
"*.js": [
"vjsstandard --fix",
"git add"
],
"README.md": [
"npm run docs:toc",
"git add"
]
},
"main": "dist/m3u8-parser.cjs.js",
"module": "dist/m3u8-parser.es.js",
"name": "m3u8-parser",
"repository": {
"type": "git",
"url": "git+ssh://git@github.com/videojs/m3u8-parser.git"
},
"scripts": {
"build": "npm-run-all -p build:*",
"build:js": "rollup -c scripts/rollup.config.js",
"clean": "shx rm -rf ./dist ./test/dist",
"docs": "npm-run-all docs:*",
"docs:api": "jsdoc src -g plugins/markdown -r -d docs/api",
"docs:toc": "doctoc README.md",
"lint": "vjsstandard",
"postclean": "shx mkdir -p ./dist ./test/dist",
"posttest": "shx cat test/dist/coverage/text.txt",
"prebuild": "npm-run-all clean test-data",
"prepublishOnly": "npm run build && vjsverify",
"pretest": "npm-run-all lint build",
"preversion": "npm test",
"server": "karma start scripts/karma.conf.js --singleRun=false --auto-watch",
"start": "npm-run-all -p server watch",
"test": "karma start scripts/karma.conf.js",
"test-data": "node scripts/m3u8.js",
"update-changelog": "conventional-changelog -p videojs -i CHANGELOG.md -s",
"version": "is-prerelease || npm run update-changelog && git add CHANGELOG.md",
"watch": "npm-run-all -p watch:*",
"watch:js": "npm run build:js -- -w"
},
"version": "4.4.0",
"vjsstandard": {
"ignore": [
"dist",
"docs",
"test/dist"
]
}
}

View File

@@ -1,83 +0,0 @@
'use strict';
/* eslint no-console: 0 */
const fs = require('fs');
const path = require('path');
const basePath = path.resolve(__dirname, '..');
const testDataDir = path.join(basePath, 'test');
const manifestDir = path.join(basePath, 'test', 'fixtures', 'm3u8');
const manifestFilepath = path.join(testDataDir, 'dist', 'test-manifests.js');
const expectedFilepath = path.join(testDataDir, 'dist', 'test-expected.js');
const build = function() {
let manifests = 'export default {\n';
let expected = 'export default {\n';
const files = fs.readdirSync(manifestDir);
while (files.length > 0) {
const file = path.resolve(manifestDir, files.shift());
const extname = path.extname(file);
if (extname === '.m3u8') {
// translate this manifest
manifests += ' \'' + path.basename(file, '.m3u8') + '\': ';
manifests += fs.readFileSync(file, 'utf8')
.split(/\r\n|\n/)
// quote and concatenate
.map(function(line) {
return ' \'' + line + '\\n\' +\n';
}).join('')
// strip leading spaces and the trailing '+'
.slice(4, -3);
manifests += ',\n';
} else if (extname === '.json') {
// append the expected parse
expected += ' "' + path.basename(file, '.json') + '": ';
expected += fs.readFileSync(file, 'utf8');
expected += ',\n';
} else {
console.log('Unknown file ' + file + ' found in manifest dir ' + manifestDir);
}
}
// clean up and close the objects
manifests = manifests.slice(0, -2);
manifests += '\n};\n';
expected = expected.slice(0, -2);
expected += '\n};\n';
fs.writeFileSync(manifestFilepath, manifests);
fs.writeFileSync(expectedFilepath, expected);
console.log('Wrote test data file ' + manifestFilepath);
console.log('Wrote test data file ' + expectedFilepath);
};
const watch = function() {
build();
fs.watch(manifestDir, function(event, filename) {
console.log('files in manifest dir were changed rebuilding manifest data');
build();
});
};
const clean = function() {
try {
fs.unlinkSync(manifestFilepath);
} catch (e) {
console.log(e);
}
try {
fs.unlinkSync(expectedFilepath);
} catch (e) {
console.log(e);
}
};
module.exports = {
build,
watch,
clean
};

View File

@@ -1,12 +0,0 @@
const generate = require('videojs-generate-karma-config');
module.exports = function(config) {
// see https://github.com/videojs/videojs-generate-karma-config
// for options
const options = {};
config = generate(config, options);
// any other custom stuff not supported by options here!
};

View File

@@ -1,22 +0,0 @@
'use strict';
const m3u8 = require('./export-m3u8s.js');
const args = require('minimist')(process.argv.slice(2), {
boolean: ['watch', 'clean', 'build'],
default: {
build: true
},
alias: {
b: 'build',
c: 'clean',
w: 'watch'
}
});
if (args.w) {
m3u8.watch();
} else if (args.c) {
m3u8.clean();
} else if (args.b) {
m3u8.build();
}

View File

@@ -1,13 +0,0 @@
const generate = require('videojs-generate-rollup-config');
// see https://github.com/videojs/videojs-generate-rollup-config
// for options
const options = {
input: 'src/index.js'
};
const config = generate(options);
// Add additonal builds/customization here!
// export the builds to rollup
export default Object.values(config.builds);

View File

@@ -1,19 +0,0 @@
/**
* @file m3u8/index.js
*
* Utilities for parsing M3U8 files. If the entire manifest is available,
* `Parser` will create an object representation with enough detail for managing
* playback. `ParseStream` and `LineStream` are lower-level parsing primitives
* that do not assume the entirety of the manifest is ready and expose a
* ReadableStream-like interface.
*/
import LineStream from './line-stream';
import ParseStream from './parse-stream';
import Parser from './parser';
export {
LineStream,
ParseStream,
Parser
};

View File

@@ -1,35 +0,0 @@
/**
* @file m3u8/line-stream.js
*/
import Stream from './stream';
/**
* A stream that buffers string input and generates a `data` event for each
* line.
*
* @class LineStream
* @extends Stream
*/
export default class LineStream extends Stream {
constructor() {
super();
this.buffer = '';
}
/**
* Add new data to be parsed.
*
* @param {string} data the text to process
*/
push(data) {
let nextNewline;
this.buffer += data;
nextNewline = this.buffer.indexOf('\n');
for (; nextNewline > -1; nextNewline = this.buffer.indexOf('\n')) {
this.trigger('data', this.buffer.substring(0, nextNewline));
this.buffer = this.buffer.substring(nextNewline + 1);
}
}
}

View File

@@ -1,500 +0,0 @@
/**
* @file m3u8/parse-stream.js
*/
import Stream from './stream';
/**
* "forgiving" attribute list psuedo-grammar:
* attributes -> keyvalue (',' keyvalue)*
* keyvalue -> key '=' value
* key -> [^=]*
* value -> '"' [^"]* '"' | [^,]*
*/
const attributeSeparator = function() {
const key = '[^=]*';
const value = '"[^"]*"|[^,]*';
const keyvalue = '(?:' + key + ')=(?:' + value + ')';
return new RegExp('(?:^|,)(' + keyvalue + ')');
};
/**
* Parse attributes from a line given the separator
*
* @param {string} attributes the attribute line to parse
*/
const parseAttributes = function(attributes) {
// split the string using attributes as the separator
const attrs = attributes.split(attributeSeparator());
const result = {};
let i = attrs.length;
let attr;
while (i--) {
// filter out unmatched portions of the string
if (attrs[i] === '') {
continue;
}
// split the key and value
attr = (/([^=]*)=(.*)/).exec(attrs[i]).slice(1);
// trim whitespace and remove optional quotes around the value
attr[0] = attr[0].replace(/^\s+|\s+$/g, '');
attr[1] = attr[1].replace(/^\s+|\s+$/g, '');
attr[1] = attr[1].replace(/^['"](.*)['"]$/g, '$1');
result[attr[0]] = attr[1];
}
return result;
};
/**
* A line-level M3U8 parser event stream. It expects to receive input one
* line at a time and performs a context-free parse of its contents. A stream
* interpretation of a manifest can be useful if the manifest is expected to
* be too large to fit comfortably into memory or the entirety of the input
* is not immediately available. Otherwise, it's probably much easier to work
* with a regular `Parser` object.
*
* Produces `data` events with an object that captures the parser's
* interpretation of the input. That object has a property `tag` that is one
* of `uri`, `comment`, or `tag`. URIs only have a single additional
* property, `line`, which captures the entirety of the input without
* interpretation. Comments similarly have a single additional property
* `text` which is the input without the leading `#`.
*
* Tags always have a property `tagType` which is the lower-cased version of
* the M3U8 directive without the `#EXT` or `#EXT-X-` prefix. For instance,
* `#EXT-X-MEDIA-SEQUENCE` becomes `media-sequence` when parsed. Unrecognized
* tags are given the tag type `unknown` and a single additional property
* `data` with the remainder of the input.
*
* @class ParseStream
* @extends Stream
*/
export default class ParseStream extends Stream {
constructor() {
super();
this.customParsers = [];
this.tagMappers = [];
}
/**
* Parses an additional line of input.
*
* @param {string} line a single line of an M3U8 file to parse
*/
push(line) {
let match;
let event;
// strip whitespace
line = line.trim();
if (line.length === 0) {
// ignore empty lines
return;
}
// URIs
if (line[0] !== '#') {
this.trigger('data', {
type: 'uri',
uri: line
});
return;
}
// map tags
const newLines = this.tagMappers.reduce((acc, mapper) => {
const mappedLine = mapper(line);
// skip if unchanged
if (mappedLine === line) {
return acc;
}
return acc.concat([mappedLine]);
}, [line]);
newLines.forEach(newLine => {
for (let i = 0; i < this.customParsers.length; i++) {
if (this.customParsers[i].call(this, newLine)) {
return;
}
}
// Comments
if (newLine.indexOf('#EXT') !== 0) {
this.trigger('data', {
type: 'comment',
text: newLine.slice(1)
});
return;
}
// strip off any carriage returns here so the regex matching
// doesn't have to account for them.
newLine = newLine.replace('\r', '');
// Tags
match = (/^#EXTM3U/).exec(newLine);
if (match) {
this.trigger('data', {
type: 'tag',
tagType: 'm3u'
});
return;
}
match = (/^#EXTINF:?([0-9\.]*)?,?(.*)?$/).exec(newLine);
if (match) {
event = {
type: 'tag',
tagType: 'inf'
};
if (match[1]) {
event.duration = parseFloat(match[1]);
}
if (match[2]) {
event.title = match[2];
}
this.trigger('data', event);
return;
}
match = (/^#EXT-X-TARGETDURATION:?([0-9.]*)?/).exec(newLine);
if (match) {
event = {
type: 'tag',
tagType: 'targetduration'
};
if (match[1]) {
event.duration = parseInt(match[1], 10);
}
this.trigger('data', event);
return;
}
match = (/^#ZEN-TOTAL-DURATION:?([0-9.]*)?/).exec(newLine);
if (match) {
event = {
type: 'tag',
tagType: 'totalduration'
};
if (match[1]) {
event.duration = parseInt(match[1], 10);
}
this.trigger('data', event);
return;
}
match = (/^#EXT-X-VERSION:?([0-9.]*)?/).exec(newLine);
if (match) {
event = {
type: 'tag',
tagType: 'version'
};
if (match[1]) {
event.version = parseInt(match[1], 10);
}
this.trigger('data', event);
return;
}
match = (/^#EXT-X-MEDIA-SEQUENCE:?(\-?[0-9.]*)?/).exec(newLine);
if (match) {
event = {
type: 'tag',
tagType: 'media-sequence'
};
if (match[1]) {
event.number = parseInt(match[1], 10);
}
this.trigger('data', event);
return;
}
match = (/^#EXT-X-DISCONTINUITY-SEQUENCE:?(\-?[0-9.]*)?/).exec(newLine);
if (match) {
event = {
type: 'tag',
tagType: 'discontinuity-sequence'
};
if (match[1]) {
event.number = parseInt(match[1], 10);
}
this.trigger('data', event);
return;
}
match = (/^#EXT-X-PLAYLIST-TYPE:?(.*)?$/).exec(newLine);
if (match) {
event = {
type: 'tag',
tagType: 'playlist-type'
};
if (match[1]) {
event.playlistType = match[1];
}
this.trigger('data', event);
return;
}
match = (/^#EXT-X-BYTERANGE:?([0-9.]*)?@?([0-9.]*)?/).exec(newLine);
if (match) {
event = {
type: 'tag',
tagType: 'byterange'
};
if (match[1]) {
event.length = parseInt(match[1], 10);
}
if (match[2]) {
event.offset = parseInt(match[2], 10);
}
this.trigger('data', event);
return;
}
match = (/^#EXT-X-ALLOW-CACHE:?(YES|NO)?/).exec(newLine);
if (match) {
event = {
type: 'tag',
tagType: 'allow-cache'
};
if (match[1]) {
event.allowed = !(/NO/).test(match[1]);
}
this.trigger('data', event);
return;
}
match = (/^#EXT-X-MAP:?(.*)$/).exec(newLine);
if (match) {
event = {
type: 'tag',
tagType: 'map'
};
if (match[1]) {
const attributes = parseAttributes(match[1]);
if (attributes.URI) {
event.uri = attributes.URI;
}
if (attributes.BYTERANGE) {
const [length, offset] = attributes.BYTERANGE.split('@');
event.byterange = {};
if (length) {
event.byterange.length = parseInt(length, 10);
}
if (offset) {
event.byterange.offset = parseInt(offset, 10);
}
}
}
this.trigger('data', event);
return;
}
match = (/^#EXT-X-STREAM-INF:?(.*)$/).exec(newLine);
if (match) {
event = {
type: 'tag',
tagType: 'stream-inf'
};
if (match[1]) {
event.attributes = parseAttributes(match[1]);
if (event.attributes.RESOLUTION) {
const split = event.attributes.RESOLUTION.split('x');
const resolution = {};
if (split[0]) {
resolution.width = parseInt(split[0], 10);
}
if (split[1]) {
resolution.height = parseInt(split[1], 10);
}
event.attributes.RESOLUTION = resolution;
}
if (event.attributes.BANDWIDTH) {
event.attributes.BANDWIDTH = parseInt(event.attributes.BANDWIDTH, 10);
}
if (event.attributes['PROGRAM-ID']) {
event.attributes['PROGRAM-ID'] = parseInt(event.attributes['PROGRAM-ID'], 10);
}
}
this.trigger('data', event);
return;
}
match = (/^#EXT-X-MEDIA:?(.*)$/).exec(newLine);
if (match) {
event = {
type: 'tag',
tagType: 'media'
};
if (match[1]) {
event.attributes = parseAttributes(match[1]);
}
this.trigger('data', event);
return;
}
match = (/^#EXT-X-ENDLIST/).exec(newLine);
if (match) {
this.trigger('data', {
type: 'tag',
tagType: 'endlist'
});
return;
}
match = (/^#EXT-X-DISCONTINUITY/).exec(newLine);
if (match) {
this.trigger('data', {
type: 'tag',
tagType: 'discontinuity'
});
return;
}
match = (/^#EXT-X-PROGRAM-DATE-TIME:?(.*)$/).exec(newLine);
if (match) {
event = {
type: 'tag',
tagType: 'program-date-time'
};
if (match[1]) {
event.dateTimeString = match[1];
event.dateTimeObject = new Date(match[1]);
}
this.trigger('data', event);
return;
}
match = (/^#EXT-X-KEY:?(.*)$/).exec(newLine);
if (match) {
event = {
type: 'tag',
tagType: 'key'
};
if (match[1]) {
event.attributes = parseAttributes(match[1]);
// parse the IV string into a Uint32Array
if (event.attributes.IV) {
if (event.attributes.IV.substring(0, 2).toLowerCase() === '0x') {
event.attributes.IV = event.attributes.IV.substring(2);
}
event.attributes.IV = event.attributes.IV.match(/.{8}/g);
event.attributes.IV[0] = parseInt(event.attributes.IV[0], 16);
event.attributes.IV[1] = parseInt(event.attributes.IV[1], 16);
event.attributes.IV[2] = parseInt(event.attributes.IV[2], 16);
event.attributes.IV[3] = parseInt(event.attributes.IV[3], 16);
event.attributes.IV = new Uint32Array(event.attributes.IV);
}
}
this.trigger('data', event);
return;
}
match = (/^#EXT-X-START:?(.*)$/).exec(newLine);
if (match) {
event = {
type: 'tag',
tagType: 'start'
};
if (match[1]) {
event.attributes = parseAttributes(match[1]);
event.attributes['TIME-OFFSET'] = parseFloat(event.attributes['TIME-OFFSET']);
event.attributes.PRECISE = (/YES/).test(event.attributes.PRECISE);
}
this.trigger('data', event);
return;
}
match = (/^#EXT-X-CUE-OUT-CONT:?(.*)?$/).exec(newLine);
if (match) {
event = {
type: 'tag',
tagType: 'cue-out-cont'
};
if (match[1]) {
event.data = match[1];
} else {
event.data = '';
}
this.trigger('data', event);
return;
}
match = (/^#EXT-X-CUE-OUT:?(.*)?$/).exec(newLine);
if (match) {
event = {
type: 'tag',
tagType: 'cue-out'
};
if (match[1]) {
event.data = match[1];
} else {
event.data = '';
}
this.trigger('data', event);
return;
}
match = (/^#EXT-X-CUE-IN:?(.*)?$/).exec(newLine);
if (match) {
event = {
type: 'tag',
tagType: 'cue-in'
};
if (match[1]) {
event.data = match[1];
} else {
event.data = '';
}
this.trigger('data', event);
return;
}
// unknown tag type
this.trigger('data', {
type: 'tag',
data: newLine.slice(4)
});
});
}
/**
* Add a parser for custom headers
*
* @param {Object} options a map of options for the added parser
* @param {RegExp} options.expression a regular expression to match the custom header
* @param {string} options.customType the custom type to register to the output
* @param {Function} [options.dataParser] function to parse the line into an object
* @param {boolean} [options.segment] should tag data be attached to the segment object
*/
addParser({expression, customType, dataParser, segment}) {
if (typeof dataParser !== 'function') {
dataParser = (line) => line;
}
this.customParsers.push(line => {
const match = expression.exec(line);
if (match) {
this.trigger('data', {
type: 'custom',
data: dataParser(line),
customType,
segment
});
return true;
}
});
}
/**
* Add a custom header mapper
*
* @param {Object} options
* @param {RegExp} options.expression a regular expression to match the custom header
* @param {Function} options.map function to translate tag into a different tag
*/
addTagMapper({expression, map}) {
const mapFn = line => {
if (expression.test(line)) {
return map(line);
}
return line;
};
this.tagMappers.push(mapFn);
}
}

View File

@@ -1,459 +0,0 @@
/**
* @file m3u8/parser.js
*/
import Stream from './stream';
import LineStream from './line-stream';
import ParseStream from './parse-stream';
import decodeB64ToUint8Array from './utils/decode';
/**
* A parser for M3U8 files. The current interpretation of the input is
* exposed as a property `manifest` on parser objects. It's just two lines to
* create and parse a manifest once you have the contents available as a string:
*
* ```js
* var parser = new m3u8.Parser();
* parser.push(xhr.responseText);
* ```
*
* New input can later be applied to update the manifest object by calling
* `push` again.
*
* The parser attempts to create a usable manifest object even if the
* underlying input is somewhat nonsensical. It emits `info` and `warning`
* events during the parse if it encounters input that seems invalid or
* requires some property of the manifest object to be defaulted.
*
* @class Parser
* @extends Stream
*/
export default class Parser extends Stream {
constructor() {
super();
this.lineStream = new LineStream();
this.parseStream = new ParseStream();
this.lineStream.pipe(this.parseStream);
/* eslint-disable consistent-this */
const self = this;
/* eslint-enable consistent-this */
const uris = [];
let currentUri = {};
// if specified, the active EXT-X-MAP definition
let currentMap;
// if specified, the active decryption key
let key;
const noop = function() {};
const defaultMediaGroups = {
'AUDIO': {},
'VIDEO': {},
'CLOSED-CAPTIONS': {},
'SUBTITLES': {}
};
// This is the Widevine UUID from DASH IF IOP. The same exact string is
// used in MPDs with Widevine encrypted streams.
const widevineUuid = 'urn:uuid:edef8ba9-79d6-4ace-a3c8-27dcd51d21ed';
// group segments into numbered timelines delineated by discontinuities
let currentTimeline = 0;
// the manifest is empty until the parse stream begins delivering data
this.manifest = {
allowCache: true,
discontinuityStarts: [],
segments: []
};
// update the manifest with the m3u8 entry from the parse stream
this.parseStream.on('data', function(entry) {
let mediaGroup;
let rendition;
({
tag() {
// switch based on the tag type
(({
'allow-cache'() {
this.manifest.allowCache = entry.allowed;
if (!('allowed' in entry)) {
this.trigger('info', {
message: 'defaulting allowCache to YES'
});
this.manifest.allowCache = true;
}
},
byterange() {
const byterange = {};
if ('length' in entry) {
currentUri.byterange = byterange;
byterange.length = entry.length;
if (!('offset' in entry)) {
this.trigger('info', {
message: 'defaulting offset to zero'
});
entry.offset = 0;
}
}
if ('offset' in entry) {
currentUri.byterange = byterange;
byterange.offset = entry.offset;
}
},
endlist() {
this.manifest.endList = true;
},
inf() {
if (!('mediaSequence' in this.manifest)) {
this.manifest.mediaSequence = 0;
this.trigger('info', {
message: 'defaulting media sequence to zero'
});
}
if (!('discontinuitySequence' in this.manifest)) {
this.manifest.discontinuitySequence = 0;
this.trigger('info', {
message: 'defaulting discontinuity sequence to zero'
});
}
if (entry.duration > 0) {
currentUri.duration = entry.duration;
}
if (entry.duration === 0) {
currentUri.duration = 0.01;
this.trigger('info', {
message: 'updating zero segment duration to a small value'
});
}
this.manifest.segments = uris;
},
key() {
if (!entry.attributes) {
this.trigger('warn', {
message: 'ignoring key declaration without attribute list'
});
return;
}
// clear the active encryption key
if (entry.attributes.METHOD === 'NONE') {
key = null;
return;
}
if (!entry.attributes.URI) {
this.trigger('warn', {
message: 'ignoring key declaration without URI'
});
return;
}
// check if the content is encrypted for Widevine
// Widevine/HLS spec: https://storage.googleapis.com/wvdocs/Widevine_DRM_HLS.pdf
if (entry.attributes.KEYFORMAT === widevineUuid) {
const VALID_METHODS = ['SAMPLE-AES', 'SAMPLE-AES-CTR', 'SAMPLE-AES-CENC'];
if (VALID_METHODS.indexOf(entry.attributes.METHOD) === -1) {
this.trigger('warn', {
message: 'invalid key method provided for Widevine'
});
return;
}
if (entry.attributes.METHOD === 'SAMPLE-AES-CENC') {
this.trigger('warn', {
message: 'SAMPLE-AES-CENC is deprecated, please use SAMPLE-AES-CTR instead'
});
}
if (entry.attributes.URI.substring(0, 23) !== 'data:text/plain;base64,') {
this.trigger('warn', {
message: 'invalid key URI provided for Widevine'
});
return;
}
if (!(entry.attributes.KEYID && entry.attributes.KEYID.substring(0, 2) === '0x')) {
this.trigger('warn', {
message: 'invalid key ID provided for Widevine'
});
return;
}
// if Widevine key attributes are valid, store them as `contentProtection`
// on the manifest to emulate Widevine tag structure in a DASH mpd
this.manifest.contentProtection = {
'com.widevine.alpha': {
attributes: {
schemeIdUri: entry.attributes.KEYFORMAT,
// remove '0x' from the key id string
keyId: entry.attributes.KEYID.substring(2)
},
// decode the base64-encoded PSSH box
pssh: decodeB64ToUint8Array(entry.attributes.URI.split(',')[1])
}
};
return;
}
if (!entry.attributes.METHOD) {
this.trigger('warn', {
message: 'defaulting key method to AES-128'
});
}
// setup an encryption key for upcoming segments
key = {
method: entry.attributes.METHOD || 'AES-128',
uri: entry.attributes.URI
};
if (typeof entry.attributes.IV !== 'undefined') {
key.iv = entry.attributes.IV;
}
},
'media-sequence'() {
if (!isFinite(entry.number)) {
this.trigger('warn', {
message: 'ignoring invalid media sequence: ' + entry.number
});
return;
}
this.manifest.mediaSequence = entry.number;
},
'discontinuity-sequence'() {
if (!isFinite(entry.number)) {
this.trigger('warn', {
message: 'ignoring invalid discontinuity sequence: ' + entry.number
});
return;
}
this.manifest.discontinuitySequence = entry.number;
currentTimeline = entry.number;
},
'playlist-type'() {
if (!(/VOD|EVENT/).test(entry.playlistType)) {
this.trigger('warn', {
message: 'ignoring unknown playlist type: ' + entry.playlist
});
return;
}
this.manifest.playlistType = entry.playlistType;
},
map() {
currentMap = {};
if (entry.uri) {
currentMap.uri = entry.uri;
}
if (entry.byterange) {
currentMap.byterange = entry.byterange;
}
},
'stream-inf'() {
this.manifest.playlists = uris;
this.manifest.mediaGroups =
this.manifest.mediaGroups || defaultMediaGroups;
if (!entry.attributes) {
this.trigger('warn', {
message: 'ignoring empty stream-inf attributes'
});
return;
}
if (!currentUri.attributes) {
currentUri.attributes = {};
}
Object.assign(currentUri.attributes, entry.attributes);
},
media() {
this.manifest.mediaGroups =
this.manifest.mediaGroups || defaultMediaGroups;
if (!(entry.attributes &&
entry.attributes.TYPE &&
entry.attributes['GROUP-ID'] &&
entry.attributes.NAME)) {
this.trigger('warn', {
message: 'ignoring incomplete or missing media group'
});
return;
}
// find the media group, creating defaults as necessary
const mediaGroupType = this.manifest.mediaGroups[entry.attributes.TYPE];
mediaGroupType[entry.attributes['GROUP-ID']] =
mediaGroupType[entry.attributes['GROUP-ID']] || {};
mediaGroup = mediaGroupType[entry.attributes['GROUP-ID']];
// collect the rendition metadata
rendition = {
default: (/yes/i).test(entry.attributes.DEFAULT)
};
if (rendition.default) {
rendition.autoselect = true;
} else {
rendition.autoselect = (/yes/i).test(entry.attributes.AUTOSELECT);
}
if (entry.attributes.LANGUAGE) {
rendition.language = entry.attributes.LANGUAGE;
}
if (entry.attributes.URI) {
rendition.uri = entry.attributes.URI;
}
if (entry.attributes['INSTREAM-ID']) {
rendition.instreamId = entry.attributes['INSTREAM-ID'];
}
if (entry.attributes.CHARACTERISTICS) {
rendition.characteristics = entry.attributes.CHARACTERISTICS;
}
if (entry.attributes.FORCED) {
rendition.forced = (/yes/i).test(entry.attributes.FORCED);
}
// insert the new rendition
mediaGroup[entry.attributes.NAME] = rendition;
},
discontinuity() {
currentTimeline += 1;
currentUri.discontinuity = true;
this.manifest.discontinuityStarts.push(uris.length);
},
'program-date-time'() {
if (typeof this.manifest.dateTimeString === 'undefined') {
// PROGRAM-DATE-TIME is a media-segment tag, but for backwards
// compatibility, we add the first occurence of the PROGRAM-DATE-TIME tag
// to the manifest object
// TODO: Consider removing this in future major version
this.manifest.dateTimeString = entry.dateTimeString;
this.manifest.dateTimeObject = entry.dateTimeObject;
}
currentUri.dateTimeString = entry.dateTimeString;
currentUri.dateTimeObject = entry.dateTimeObject;
},
targetduration() {
if (!isFinite(entry.duration) || entry.duration < 0) {
this.trigger('warn', {
message: 'ignoring invalid target duration: ' + entry.duration
});
return;
}
this.manifest.targetDuration = entry.duration;
},
totalduration() {
if (!isFinite(entry.duration) || entry.duration < 0) {
this.trigger('warn', {
message: 'ignoring invalid total duration: ' + entry.duration
});
return;
}
this.manifest.totalDuration = entry.duration;
},
start() {
if (!entry.attributes || isNaN(entry.attributes['TIME-OFFSET'])) {
this.trigger('warn', {
message: 'ignoring start declaration without appropriate attribute list'
});
return;
}
this.manifest.start = {
timeOffset: entry.attributes['TIME-OFFSET'],
precise: entry.attributes.PRECISE
};
},
'cue-out'() {
currentUri.cueOut = entry.data;
},
'cue-out-cont'() {
currentUri.cueOutCont = entry.data;
},
'cue-in'() {
currentUri.cueIn = entry.data;
}
})[entry.tagType] || noop).call(self);
},
uri() {
currentUri.uri = entry.uri;
uris.push(currentUri);
// if no explicit duration was declared, use the target duration
if (this.manifest.targetDuration && !('duration' in currentUri)) {
this.trigger('warn', {
message: 'defaulting segment duration to the target duration'
});
currentUri.duration = this.manifest.targetDuration;
}
// annotate with encryption information, if necessary
if (key) {
currentUri.key = key;
}
currentUri.timeline = currentTimeline;
// annotate with initialization segment information, if necessary
if (currentMap) {
currentUri.map = currentMap;
}
// prepare for the next URI
currentUri = {};
},
comment() {
// comments are not important for playback
},
custom() {
// if this is segment-level data attach the output to the segment
if (entry.segment) {
currentUri.custom = currentUri.custom || {};
currentUri.custom[entry.customType] = entry.data;
// if this is manifest-level data attach to the top level manifest object
} else {
this.manifest.custom = this.manifest.custom || {};
this.manifest.custom[entry.customType] = entry.data;
}
}
})[entry.type].call(self);
});
}
/**
* Parse the input string and update the manifest object.
*
* @param {string} chunk a potentially incomplete portion of the manifest
*/
push(chunk) {
this.lineStream.push(chunk);
}
/**
* Flush any remaining input. This can be handy if the last line of an M3U8
* manifest did not contain a trailing newline but the file has been
* completely received.
*/
end() {
// flush any buffered input
this.lineStream.push('\n');
}
/**
* Add an additional parser for non-standard tags
*
* @param {Object} options a map of options for the added parser
* @param {RegExp} options.expression a regular expression to match the custom header
* @param {string} options.type the type to register to the output
* @param {Function} [options.dataParser] function to parse the line into an object
* @param {boolean} [options.segment] should tag data be attached to the segment object
*/
addParser(options) {
this.parseStream.addParser(options);
}
/**
* Add a custom header mapper
*
* @param {Object} options
* @param {RegExp} options.expression a regular expression to match the custom header
* @param {Function} options.map function to translate tag into a different tag
*/
addTagMapper(options) {
this.parseStream.addTagMapper(options);
}
}

View File

@@ -1,99 +0,0 @@
/**
* @file stream.js
*/
/**
* A lightweight readable stream implementation that handles event dispatching.
*
* @class Stream
*/
export default class Stream {
constructor() {
this.listeners = {};
}
/**
* Add a listener for a specified event type.
*
* @param {string} type the event name
* @param {Function} listener the callback to be invoked when an event of
* the specified type occurs
*/
on(type, listener) {
if (!this.listeners[type]) {
this.listeners[type] = [];
}
this.listeners[type].push(listener);
}
/**
* Remove a listener for a specified event type.
*
* @param {string} type the event name
* @param {Function} listener a function previously registered for this
* type of event through `on`
* @return {boolean} if we could turn it off or not
*/
off(type, listener) {
if (!this.listeners[type]) {
return false;
}
const index = this.listeners[type].indexOf(listener);
this.listeners[type].splice(index, 1);
return index > -1;
}
/**
* Trigger an event of the specified type on this stream. Any additional
* arguments to this function are passed as parameters to event listeners.
*
* @param {string} type the event name
*/
trigger(type) {
const callbacks = this.listeners[type];
let i;
let length;
let args;
if (!callbacks) {
return;
}
// Slicing the arguments on every invocation of this method
// can add a significant amount of overhead. Avoid the
// intermediate object creation for the common case of a
// single callback argument
if (arguments.length === 2) {
length = callbacks.length;
for (i = 0; i < length; ++i) {
callbacks[i].call(this, arguments[1]);
}
} else {
args = Array.prototype.slice.call(arguments, 1);
length = callbacks.length;
for (i = 0; i < length; ++i) {
callbacks[i].apply(this, args);
}
}
}
/**
* Destroys the stream and cleans up.
*/
dispose() {
this.listeners = {};
}
/**
* Forwards all `data` events on this stream to the destination stream. The
* destination stream should provide a method `push` to receive the data
* events as they arrive.
*
* @param {Stream} destination the stream that will receive all `data` events
* @see http://nodejs.org/api/stream.html#stream_readable_pipe_destination_options
*/
pipe(destination) {
this.on('data', function(data) {
destination.push(data);
});
}
}

View File

@@ -1,11 +0,0 @@
import window from 'global/window';
export default function decodeB64ToUint8Array(b64Text) {
const decodedString = window.atob(b64Text || '');
const array = new Uint8Array(decodedString.length);
for (let i = 0; i < decodedString.length; i++) {
array[i] = decodedString.charCodeAt(i);
}
return array;
}

View File

@@ -1,31 +0,0 @@
{
"allowCache": true,
"mediaSequence": 0,
"playlistType": "VOD",
"segments": [
{
"duration": 10,
"timeline": 0,
"uri": "http://example.com/00001.ts"
},
{
"duration": 10,
"timeline": 0,
"uri": "https://example.com/00002.ts"
},
{
"duration": 10,
"timeline": 0,
"uri": "//example.com/00003.ts"
},
{
"duration": 10,
"timeline": 0,
"uri": "http://example.com/00004.ts"
}
],
"targetDuration": 10,
"endList": true,
"discontinuitySequence": 0,
"discontinuityStarts": []
}

View File

@@ -1,13 +0,0 @@
#EXTM3U
#EXT-X-PLAYLIST-TYPE:VOD
#EXT-X-TARGETDURATION:10
#EXTINF:10,
http://example.com/00001.ts
#EXTINF:10,
https://example.com/00002.ts
#EXTINF:10,
//example.com/00003.ts
#EXTINF:10,
http://example.com/00004.ts
#ZEN-TOTAL-DURATION:57.9911
#EXT-X-ENDLIST

View File

@@ -1,164 +0,0 @@
{
"allowCache": true,
"mediaSequence": 0,
"playlistType": "VOD",
"segments": [
{
"byterange": {
"length": 522828,
"offset": 0
},
"duration": 10,
"timeline": 0,
"uri": "hls_450k_video.ts"
},
{
"byterange": {
"length": 587500,
"offset": 522828
},
"duration": 10,
"timeline": 0,
"uri": "hls_450k_video.ts"
},
{
"byterange": {
"length": 713084,
"offset": 1110328
},
"duration": 10,
"timeline": 0,
"uri": "hls_450k_video.ts"
},
{
"byterange": {
"length": 476580,
"offset": 1823412
},
"duration": 10,
"timeline": 0,
"uri": "hls_450k_video.ts"
},
{
"byterange": {
"length": 535612,
"offset": 2299992
},
"duration": 10,
"timeline": 0,
"uri": "hls_450k_video.ts"
},
{
"byterange": {
"length": 207176,
"offset": 2835604
},
"duration": 10,
"timeline": 0,
"uri": "hls_450k_video.ts"
},
{
"byterange": {
"length": 455900,
"offset": 3042780
},
"duration": 10,
"timeline": 0,
"uri": "hls_450k_video.ts"
},
{
"byterange": {
"length": 657248,
"offset": 3498680
},
"duration": 10,
"timeline": 0,
"uri": "hls_450k_video.ts"
},
{
"byterange": {
"length": 571708,
"offset": 4155928
},
"duration": 10,
"timeline": 0,
"uri": "hls_450k_video.ts"
},
{
"byterange": {
"length": 485040,
"offset": 4727636
},
"duration": 10,
"timeline": 0,
"uri": "hls_450k_video.ts"
},
{
"byterange": {
"length": 709136,
"offset": 5212676
},
"duration": 10,
"timeline": 0,
"uri": "hls_450k_video.ts"
},
{
"byterange": {
"length": 730004,
"offset": 5921812
},
"duration": 10,
"timeline": 0,
"uri": "hls_450k_video.ts"
},
{
"byterange": {
"length": 456276,
"offset": 6651816
},
"duration": 10,
"timeline": 0,
"uri": "hls_450k_video.ts"
},
{
"byterange": {
"length": 468684,
"offset": 7108092
},
"duration": 10,
"timeline": 0,
"uri": "hls_450k_video.ts"
},
{
"byterange": {
"length": 444996,
"offset": 7576776
},
"duration": 10,
"timeline": 0,
"uri": "hls_450k_video.ts"
},
{
"byterange": {
"length": 331444,
"offset": 8021772
},
"duration": 10,
"timeline": 0,
"uri": "hls_450k_video.ts"
},
{
"byterange": {
"length": 44556,
"offset": 8353216
},
"duration": 1.4167,
"timeline": 0,
"uri": "hls_450k_video.ts"
}
],
"targetDuration": 10,
"endList": true,
"discontinuitySequence": 0,
"discontinuityStarts": []
}

View File

@@ -1,58 +0,0 @@
#EXTM3U
#EXT-X-TARGETDURATION:10
#EXT-X-VERSION:4
#EXT-X-ALLOW-CACHE:YES
#EXT-X-MEDIA-SEQUENCE:0
#EXT-X-PLAYLIST-TYPE:VOD
#EXTINF:10,
#EXT-X-BYTERANGE:522828@0
hls_450k_video.ts
#EXTINF:10,
#EXT-X-BYTERANGE:587500@522828
hls_450k_video.ts
#EXTINF:10,
#EXT-X-BYTERANGE:713084@1110328
hls_450k_video.ts
#EXTINF:10,
#EXT-X-BYTERANGE:476580@1823412
hls_450k_video.ts
#EXTINF:10,
#EXT-X-BYTERANGE:535612@2299992
hls_450k_video.ts
#EXTINF:10,
#EXT-X-BYTERANGE:207176@2835604
hls_450k_video.ts
#EXTINF:10,
#EXT-X-BYTERANGE:455900@3042780
hls_450k_video.ts
#EXTINF:10,
#EXT-X-BYTERANGE:657248@3498680
hls_450k_video.ts
#EXTINF:10,
#EXT-X-BYTERANGE:571708@4155928
hls_450k_video.ts
#EXTINF:10,
#EXT-X-BYTERANGE:485040@4727636
hls_450k_video.ts
#EXTINF:10,
#EXT-X-BYTERANGE:709136@5212676
hls_450k_video.ts
#EXTINF:10,
#EXT-X-BYTERANGE:730004@5921812
hls_450k_video.ts
#EXTINF:10,
#EXT-X-BYTERANGE:456276@6651816
hls_450k_video.ts
#EXTINF:10,
#EXT-X-BYTERANGE:468684@7108092
hls_450k_video.ts
#EXTINF:10,
#EXT-X-BYTERANGE:444996@7576776
hls_450k_video.ts
#EXTINF:10,
#EXT-X-BYTERANGE:331444@8021772
hls_450k_video.ts
#EXTINF:1.4167,
#EXT-X-BYTERANGE:44556@8353216
hls_450k_video.ts
#EXT-X-ENDLIST

View File

@@ -1,20 +0,0 @@
{
"allowCache": true,
"mediaSequence": 0,
"playlistType": "VOD",
"segments": [
{
"byterange": {
"length": 522828,
"offset": 0
},
"duration": 10,
"timeline": 0,
"uri": "hls_450k_video.ts"
}
],
"targetDuration": 10,
"endList": true,
"discontinuitySequence": 0,
"discontinuityStarts": []
}

View File

@@ -1,10 +0,0 @@
#EXTM3U
#EXT-X-TARGETDURATION:10
#EXT-X-VERSION:4
#EXT-X-ALLOW-CACHE:0
#EXT-X-MEDIA-SEQUENCE:0
#EXT-X-PLAYLIST-TYPE:VOD
#EXTINF:10,
#EXT-X-BYTERANGE:522828@0
hls_450k_video.ts
#EXT-X-ENDLIST

View File

@@ -1,56 +0,0 @@
{
allowCache: true,
discontinuityStarts: [],
mediaGroups: {
// TYPE
AUDIO: {
// GROUP-ID
"audio": {
// NAME
"English": {
language: 'eng',
autoselect: true,
default: true,
uri: "eng/prog_index.m3u8"
},
// NAME
"Français": {
language: "fre",
autoselect: true,
default: false,
uri: "fre/prog_index.m3u8"
},
// NAME
"Espanol": {
language: "sp",
autoselect: true,
default: false,
uri: "sp/prog_index.m3u8"
}
}
},
VIDEO: {},
"CLOSED-CAPTIONS": {},
SUBTITLES: {}
},
playlists: [{
attributes: {
"PROGRAM-ID": 1,
BANDWIDTH: 195023,
CODECS: "avc1.42e00a,mp4a.40.2",
AUDIO: 'audio'
},
timeline: 0,
uri: "lo/prog_index.m3u8"
}, {
attributes: {
"PROGRAM-ID": 1,
BANDWIDTH: 591680,
CODECS: "avc1.42e01e,mp4a.40.2",
AUDIO: 'audio'
},
timeline: 0,
uri: "hi/prog_index.m3u8"
}],
segments: []
}

View File

@@ -1,9 +0,0 @@
#EXTM3U
#EXT-X-MEDIA:TYPE=AUDIO,GROUP-ID="audio",LANGUAGE="eng",NAME="English",AUTOSELECT=YES, DEFAULT=YES,URI="eng/prog_index.m3u8"
#EXT-X-MEDIA:TYPE=AUDIO,GROUP-ID="audio",LANGUAGE="fre",NAME="Français",AUTOSELECT=YES, DEFAULT=NO,URI="fre/prog_index.m3u8"
#EXT-X-MEDIA:TYPE=AUDIO,GROUP-ID="audio",LANGUAGE="sp",NAME="Espanol",AUTOSELECT=YES, DEFAULT=NO,URI="sp/prog_index.m3u8"
#EXT-X-STREAM-INF:PROGRAM-ID=1,BANDWIDTH=195023,CODECS="avc1.42e00a,mp4a.40.2",AUDIO="audio"
lo/prog_index.m3u8
#EXT-X-STREAM-INF:PROGRAM-ID=1,BANDWIDTH=591680,CODECS="avc1.42e01e,mp4a.40.2",AUDIO="audio"
hi/prog_index.m3u8

View File

@@ -1,48 +0,0 @@
{
allowCache: true,
discontinuityStarts: [],
mediaGroups: {
AUDIO: {
aac: {
English: {
autoselect: true,
default: true,
language: "eng",
uri: "eng/prog_index.m3u8"
}
}
},
VIDEO: {
"500kbs": {
Angle1: {
autoselect: true,
default: true
},
Angle2: {
autoselect: true,
default: false,
uri: "Angle2/500kbs/prog_index.m3u8"
},
Angle3: {
autoselect: true,
default: false,
uri: "Angle3/500kbs/prog_index.m3u8"
}
}
},
"CLOSED-CAPTIONS": {},
SUBTITLES: {}
},
playlists: [{
attributes: {
"PROGRAM-ID": 1,
BANDWIDTH: 754857,
CODECS: "mp4a.40.2,avc1.4d401e",
AUDIO: "aac",
VIDEO: "500kbs"
},
timeline: 0,
uri: "Angle1/500kbs/prog_index.m3u8"
}],
segments: []
}

View File

@@ -1,8 +0,0 @@
#EXTM3U
#EXT-X-MEDIA:TYPE=VIDEO,GROUP-ID="500kbs",NAME="Angle1",AUTOSELECT=YES,DEFAULT=YES
#EXT-X-MEDIA:TYPE=VIDEO,GROUP-ID="500kbs",NAME="Angle2",AUTOSELECT=YES,DEFAULT=NO,URI="Angle2/500kbs/prog_index.m3u8"
#EXT-X-MEDIA:TYPE=VIDEO,GROUP-ID="500kbs",NAME="Angle3",AUTOSELECT=YES,DEFAULT=NO,URI="Angle3/500kbs/prog_index.m3u8"
#EXT-X-MEDIA:TYPE=AUDIO,GROUP-ID="aac",LANGUAGE="eng",NAME="English",AUTOSELECT=YES,DEFAULT=YES,URI="eng/prog_index.m3u8"
#EXT-X-STREAM-INF:PROGRAM-ID=1,BANDWIDTH=754857,CODECS="mp4a.40.2,avc1.4d401e",VIDEO="500kbs",AUDIO="aac"
Angle1/500kbs/prog_index.m3u8

View File

@@ -1,57 +0,0 @@
{
"allowCache": true,
"playlists": [
{
"attributes": {
"PROGRAM-ID": 1,
"BANDWIDTH": 240000,
"RESOLUTION": {
"width": 396,
"height": 224
}
},
"timeline": 0,
"uri": "http://c.brightcove.com/services/mobile/streaming/index/rendition.m3u8?assetId=1824686811001&videoId=1824650741001"
},
{
"attributes": {
"PROGRAM-ID": 1,
"BANDWIDTH": 40000
},
"timeline": 0,
"uri": "http://c.brightcove.com/services/mobile/streaming/index/rendition.m3u8?assetId=1824683759001&videoId=1824650741001"
},
{
"attributes": {
"PROGRAM-ID": 1,
"BANDWIDTH": 440000,
"RESOLUTION": {
"width": 396,
"height": 224
}
},
"timeline": 0,
"uri": "http://c.brightcove.com/services/mobile/streaming/index/rendition.m3u8?assetId=1824686593001&videoId=1824650741001"
},
{
"attributes": {
"PROGRAM-ID": 1,
"BANDWIDTH": 1928000,
"RESOLUTION": {
"width": 960,
"height": 540
}
},
"timeline": 0,
"uri": "http://c.brightcove.com/services/mobile/streaming/index/rendition.m3u8?assetId=1824687660001&videoId=1824650741001"
}
],
"discontinuityStarts": [],
"mediaGroups": {
"VIDEO": {},
"AUDIO": {},
"CLOSED-CAPTIONS": {},
"SUBTITLES": {}
},
"segments": []
}

View File

@@ -1,9 +0,0 @@
#EXTM3U
#EXT-X-STREAM-INF:PROGRAM-ID=1,BANDWIDTH=240000,RESOLUTION=396x224
http://c.brightcove.com/services/mobile/streaming/index/rendition.m3u8?assetId=1824686811001&videoId=1824650741001
#EXT-X-STREAM-INF:PROGRAM-ID=1,BANDWIDTH=40000
http://c.brightcove.com/services/mobile/streaming/index/rendition.m3u8?assetId=1824683759001&videoId=1824650741001
#EXT-X-STREAM-INF:PROGRAM-ID=1,BANDWIDTH=440000,RESOLUTION=396x224
http://c.brightcove.com/services/mobile/streaming/index/rendition.m3u8?assetId=1824686593001&videoId=1824650741001
#EXT-X-STREAM-INF:PROGRAM-ID=1,BANDWIDTH=1928000,RESOLUTION=960x540
http://c.brightcove.com/services/mobile/streaming/index/rendition.m3u8?assetId=1824687660001&videoId=1824650741001

View File

@@ -1,160 +0,0 @@
{
"allowCache": true,
"mediaSequence": 0,
"playlistType": "VOD",
"segments": [
{
"duration": 10,
"timeline": 0,
"uri": "hls_450k_video.ts"
},
{
"byterange": {
"length": 587500,
"offset": 522828
},
"duration": 10,
"timeline": 0,
"uri": "hls_450k_video.ts"
},
{
"byterange": {
"length": 713084,
"offset": 0
},
"duration": 10,
"timeline": 0,
"uri": "hls_450k_video2.ts"
},
{
"byterange": {
"length": 476580,
"offset": 1823412
},
"duration": 10,
"timeline": 0,
"uri": "hls_450k_video.ts"
},
{
"byterange": {
"length": 535612,
"offset": 2299992
},
"duration": 10,
"timeline": 0,
"uri": "hls_450k_video.ts"
},
{
"byterange": {
"length": 207176,
"offset": 2835604
},
"duration": 10,
"timeline": 0,
"uri": "hls_450k_video.ts"
},
{
"byterange": {
"length": 455900,
"offset": 3042780
},
"duration": 10,
"timeline": 0,
"uri": "hls_450k_video.ts"
},
{
"byterange": {
"length": 657248,
"offset": 3498680
},
"duration": 10,
"timeline": 0,
"uri": "hls_450k_video.ts"
},
{
"byterange": {
"length": 571708,
"offset": 4155928
},
"duration": 10,
"timeline": 0,
"uri": "hls_450k_video.ts"
},
{
"byterange": {
"length": 485040,
"offset": 4727636
},
"duration": 10,
"timeline": 0,
"uri": "hls_450k_video.ts"
},
{
"byterange": {
"length": 709136,
"offset": 5212676
},
"duration": 10,
"timeline": 0,
"uri": "hls_450k_video.ts"
},
{
"byterange": {
"length": 730004,
"offset": 5921812
},
"duration": 10,
"timeline": 0,
"uri": "hls_450k_video.ts"
},
{
"byterange": {
"length": 456276,
"offset": 6651816
},
"duration": 10,
"timeline": 0,
"uri": "hls_450k_video.ts"
},
{
"byterange": {
"length": 468684,
"offset": 7108092
},
"duration": 10,
"timeline": 0,
"uri": "hls_450k_video.ts"
},
{
"byterange": {
"length": 444996,
"offset": 7576776
},
"duration": 10,
"timeline": 0,
"uri": "hls_450k_video.ts"
},
{
"byterange": {
"length": 331444,
"offset": 8021772
},
"duration": 10,
"timeline": 0,
"uri": "hls_450k_video.ts"
},
{
"byterange": {
"length": 44556,
"offset": 8353216
},
"duration": 1.4167,
"timeline": 0,
"uri": "hls_450k_video.ts"
}
],
"targetDuration": 10,
"endList": true,
"discontinuitySequence": 0,
"discontinuityStarts": []
}

View File

@@ -1,56 +0,0 @@
#EXTM3U
#EXT-X-TARGETDURATION:10
#EXT-X-VERSION:3
#EXT-X-MEDIA-SEQUENCE:0
#EXT-X-PLAYLIST-TYPE:VOD
#EXTINF:10,
hls_450k_video.ts
#EXTINF:10,
#EXT-X-BYTERANGE:587500@522828
hls_450k_video.ts
#EXTINF:10,
#EXT-X-BYTERANGE:713084
hls_450k_video2.ts
#EXTINF:10,
#EXT-X-BYTERANGE:476580@1823412
hls_450k_video.ts
#EXTINF:10,
#EXT-X-BYTERANGE:535612@2299992
hls_450k_video.ts
#EXTINF:10,
#EXT-X-BYTERANGE:207176@2835604
hls_450k_video.ts
#EXTINF:10,
#EXT-X-BYTERANGE:455900@3042780
hls_450k_video.ts
#EXTINF:10,
#EXT-X-BYTERANGE:657248@3498680
hls_450k_video.ts
#EXTINF:10,
#EXT-X-BYTERANGE:571708@4155928
hls_450k_video.ts
#EXTINF:10,
#EXT-X-BYTERANGE:485040@4727636
hls_450k_video.ts
#EXTINF:10,
#EXT-X-BYTERANGE:709136@5212676
hls_450k_video.ts
#EXTINF:10,
#EXT-X-BYTERANGE:730004@5921812
hls_450k_video.ts
#EXTINF:10,
#EXT-X-BYTERANGE:456276@6651816
hls_450k_video.ts
#EXTINF:10,
#EXT-X-BYTERANGE:468684@7108092
hls_450k_video.ts
#EXTINF:10,
#EXT-X-BYTERANGE:444996@7576776
hls_450k_video.ts
#EXTINF:10,
#EXT-X-BYTERANGE:331444@8021772
hls_450k_video.ts
#EXTINF:1.4167,
#EXT-X-BYTERANGE:44556@8353216
hls_450k_video.ts
#EXT-X-ENDLIST

View File

@@ -1,27 +0,0 @@
{
"allowCache": false,
"mediaSequence": 0,
"playlistType": "VOD",
"segments": [
{
"dateTimeString": "2016-06-22T09:20:16.166-04:00",
"dateTimeObject": new Date("2016-06-22T09:20:16.166-04:00"),
"duration": 10,
"timeline": 0,
"uri": "hls_450k_video.ts"
},
{
"dateTimeString": "2016-06-22T09:20:26.166-04:00",
"dateTimeObject": new Date("2016-06-22T09:20:26.166-04:00"),
"duration": 10,
"timeline": 0,
"uri": "hls_450k_video.ts"
}
],
"targetDuration": 10,
"endList": true,
"dateTimeString": "2016-06-22T09:20:16.166-04:00",
"dateTimeObject": new Date("2016-06-22T09:20:16.166-04:00"),
"discontinuitySequence": 0,
"discontinuityStarts": []
}

View File

@@ -1,12 +0,0 @@
#EXTM3U
#EXT-X-PLAYLIST-TYPE:VOD
#EXT-X-MEDIA-SEQUENCE:0
#EXT-X-ALLOW-CACHE:NO
#EXT-X-TARGETDURATION:10
#EXT-X-PROGRAM-DATE-TIME:2016-06-22T09:20:16.166-04:00
#EXTINF:10
hls_450k_video.ts
#EXT-X-PROGRAM-DATE-TIME:2016-06-22T09:20:26.166-04:00
#EXTINF:10
hls_450k_video.ts
#EXT-X-ENDLIST

View File

@@ -1,20 +0,0 @@
{
"allowCache": false,
"mediaSequence": 0,
"playlistType": "VOD",
"segments": [
{
"byterange": {
"length": 522828,
"offset": 0
},
"duration": 10,
"timeline": 0,
"uri": "hls_450k_video.ts"
}
],
"targetDuration": 10,
"endList": true,
"discontinuitySequence": 0,
"discontinuityStarts": []
}

View File

@@ -1,10 +0,0 @@
#EXTM3U
#EXT-X-TARGETDURATION:10
#EXT-X-VERSION:4
#EXT-X-ALLOW-CACHE:NO
#EXT-X-MEDIA-SEQUENCE:0
#EXT-X-PLAYLIST-TYPE:VOD
#EXTINF:10,
#EXT-X-BYTERANGE:522828@0
hls_450k_video.ts
#EXT-X-ENDLIST

View File

@@ -1,31 +0,0 @@
{
"allowCache": true,
"mediaSequence": 0,
"discontinuitySequence": 3,
"segments": [
{
"duration": 10,
"timeline": 3,
"uri": "001.ts"
},
{
"duration": 19,
"timeline": 3,
"uri": "002.ts"
},
{
"discontinuity": true,
"duration": 10,
"timeline": 4,
"uri": "003.ts"
},
{
"duration": 11,
"timeline": 4,
"uri": "004.ts"
}
],
"targetDuration": 19,
"endList": true,
"discontinuityStarts": [2]
}

Some files were not shown because too many files have changed in this diff Show More