-
Notifications
You must be signed in to change notification settings - Fork 1
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Showing
6 changed files
with
333 additions
and
2 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -59,3 +59,4 @@ typings/ | |
|
||
# next.js build output | ||
.next | ||
package-lock.json |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,2 @@ | ||
tag-version-prefix="" | ||
message="chore(release): %s :tada:" |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,2 +1,70 @@ | ||
# dat-shaka-plugin | ||
A plugin for 'shaka-player' to load 'dat://' URI | ||
dat-shaka-player-plugin | ||
================ | ||
|
||
A plugin for 'shaka-player' to load `dat://` URI schemes. | ||
|
||
## Installation | ||
|
||
```sh | ||
$ npm install dat-shaka-player-plugin | ||
``` | ||
|
||
## Usage | ||
|
||
```js | ||
const register = require('dat-shaka-player-plugin') | ||
const shaka = require('shaka-player') | ||
|
||
register(shaka) | ||
``` | ||
|
||
## API | ||
|
||
### `plugin = require('dat-shaka-player-plugin')(shaka, options)` | ||
|
||
A factory function to create and register the plugin with | ||
`shaka-player` to handle `dat://` URI requests for MPEG-DASH | ||
manifests (`*.mpd`) or HLS playlists (`*.m3u8`). `shaka` is the | ||
`shaka-player` module and `options` can be: | ||
|
||
```js | ||
{ | ||
archive: Object, // an optional 'hyperdrive' instance that represents a DAT archive. This will override the resolved archive from the DAT link. | ||
swarm: Object, // an optional 'discovery-swarm-web' or 'discovery-swarm' object to swarm for resources | ||
discovery: Object, // an optional object passed to the swarm constructor | ||
} | ||
``` | ||
|
||
#### `plugin.requests` | ||
|
||
A `Set` that represents the currently active requests being made by the | ||
`shaka-player` for resources stored in a DAT archive. | ||
|
||
#### `plugin.options` | ||
|
||
The options passed to the plugin factory. | ||
|
||
#### `plugin.swarms` | ||
|
||
A `Map` of swarms corresponding to a DAT link. | ||
|
||
#### `plugin.drives` | ||
|
||
A `Map` of hyperdrives corresponding to a DAT link. | ||
|
||
#### `plugin.destroyed` | ||
|
||
A boolean indicating that the plugin is destroyed. | ||
|
||
#### `plugin.unregister()` | ||
|
||
An alias to `plugin.destroy()` | ||
|
||
#### `plugin.destroy()` | ||
|
||
Destroy the plugin, close the underlying resources, and unregister as a | ||
scheme for `shaka-player`. | ||
|
||
## License | ||
|
||
MIT |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,38 @@ | ||
const register = require('./') | ||
const shaka = require('shaka-player') | ||
|
||
const BIG_BUCK_BUNNY_URI = 'dat://b2e7f16be8cf431310db322c2b8f8c97a39872de364295f251b76f40002f62bc/bunny.mpd' | ||
|
||
const video = document.createElement('video') | ||
const player = new shaka.Player(video) | ||
|
||
Object.assign(video, { | ||
crossOrigin: 'anonymous', | ||
autoplay: true, | ||
controls: true, | ||
preload: true, | ||
}) | ||
|
||
Object.assign(document.body.style, { | ||
background: '#151515', | ||
padding: 0, | ||
}) | ||
|
||
Object.assign(video.style, { | ||
display: 'block', | ||
position: 'relative', | ||
margin: '0 auto', | ||
width: '98%', | ||
}) | ||
|
||
const plugin = register(shaka, {}) | ||
const uri = window.location.hash.slice(1) || BIG_BUCK_BUNNY_URI | ||
|
||
player.load(uri) | ||
|
||
video.addEventListener('ended', () => { | ||
// you most likely never need to do this | ||
plugin.destroy() | ||
}) | ||
|
||
document.body.appendChild(video) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,192 @@ | ||
const resolveLink = require('dat-link-resolve') | ||
const parseRange = require('range-parser') | ||
const hyperdrive = require('hyperdrive') | ||
const Discovery = require('discovery-swarm-web') | ||
const collect = require('collect-stream') | ||
const debug = require('debug')('dat-shaka-plugin') | ||
const mime = require('mime') | ||
const ram = require('random-access-memory') | ||
const url = require('url') | ||
|
||
const SCHEME = 'dat' | ||
|
||
function createPlugin(shaka, options) { | ||
if (!options || 'object' !== typeof options) { | ||
options = {} | ||
} | ||
|
||
const requests = new Set() | ||
const swarms = new Map() | ||
const drives = new Map() | ||
|
||
let destroyed = false | ||
|
||
shaka.net.NetworkingEngine.registerScheme(SCHEME, onscheme) | ||
|
||
return { | ||
requests, | ||
options, | ||
swarms, | ||
drives, | ||
|
||
get destroyed() { | ||
return destroyed | ||
}, | ||
|
||
unregister() { | ||
return this.destroy() | ||
}, | ||
|
||
destroy() { | ||
for (const key of swarms.keys()) { | ||
swarms.get(key).close() | ||
swarms.delete(key) | ||
} | ||
|
||
for (const key of drives.keys()) { | ||
drives.get(key).close() | ||
drives.delete(key) | ||
} | ||
|
||
for (const request of requests.values()) { | ||
request.abort() | ||
requests.delete(request) | ||
} | ||
|
||
shaka.net.NetworkingEngine.unregisterScheme(SCHEME) | ||
}, | ||
} | ||
|
||
function onscheme(uri, req, type, onprogress) { | ||
if (destroyed) { | ||
throw new Error("'dat-shaka-plugin' is destroyed. Please unregister.") | ||
} | ||
|
||
let filename = null | ||
let drive = null | ||
let abort = null | ||
let key = null | ||
|
||
const request = new Promise((resolve, reject) => { | ||
abort = reject | ||
|
||
resolveLink(uri, onresolvelink) | ||
|
||
function onresolvelink(err, link) { | ||
if (err) { | ||
return reject(err) | ||
} | ||
|
||
key = Buffer.from(link, 'hex') | ||
drive = drives.get(link) || options.archive || options.drive | ||
swarm = swarms.get(link) || options.swarm | ||
|
||
if (!drive) { | ||
drive = hyperdrive(ram, key, Object.assign({}, options, { | ||
latest: true, | ||
sparse: true, | ||
})) | ||
} | ||
|
||
if (!swarm) { | ||
swarm = new Discovery(Object.assign({}, options.discovery, { | ||
stream: onstream | ||
})) | ||
} | ||
|
||
drives.set(link, drive) | ||
swarms.set(link, swarm) | ||
|
||
const { pathname } = url.parse(uri.replace(link, 'dat.local')) | ||
|
||
filename = pathname | ||
|
||
drive.ready(() => { | ||
swarm.join(drive.discoveryKey) | ||
drive.download(filename) | ||
drive.stat(filename, onstat) | ||
}) | ||
} | ||
|
||
function onread(err, buffer) { | ||
if (err) { | ||
return reject(err) | ||
} | ||
|
||
resolve(makeResponse(uri, buffer, type)) | ||
} | ||
|
||
function onstat(err, stats) { | ||
if (err) { | ||
return drive.once('update', () => { | ||
drive.stat(filename, onstat) | ||
}) | ||
} | ||
|
||
if ('HEAD' === req.method) { | ||
resolve(makeResponse(uri, stats, type)) | ||
} | ||
|
||
if ('GET' === req.method) { | ||
const { headers } = req | ||
const { size } = stats | ||
const range = headers.Range | ||
? parseRange(size, headers.Range)[0] | ||
: null | ||
|
||
collect(drive.createReadStream(filename, range), onread) | ||
} | ||
} | ||
}) | ||
|
||
const operation = new shaka.util.AbortableOperation(request, onabort) | ||
|
||
requests.add(request) | ||
request.then(ondone).catch(ondone) | ||
request.operation = operation | ||
request.abort = () => operation.abort() | ||
|
||
return operation | ||
|
||
function ondone(err) { | ||
if (err) { | ||
debug(err) | ||
} | ||
requests.delete(request) | ||
} | ||
|
||
function onabort() { | ||
requests.delete(request) | ||
return abort(new shaka.util.Error( | ||
shaka.util.Error.Severity.RECOVERABLE, | ||
shaka.util.Error.Category.NETWORK, | ||
shaka.util.Error.Code.OPERATION_ABORTED | ||
)) | ||
} | ||
|
||
function onstream() { | ||
return drive.replicate({ timeout: 0 }) | ||
} | ||
} | ||
|
||
function makeResponse(uri, file, type) { | ||
const contentType = mime.getType(uri) | ||
const headers = {} | ||
const status = 200 | ||
const data = file && file.buffer ? file.buffer : null | ||
|
||
headers['content-type'] = contentType | ||
|
||
if (file && file.size) { | ||
headers['content-length'] = file.size | ||
} else if (file && file.buffer) { | ||
headers['content-length'] = file.length | ||
} | ||
|
||
const response = { uri, data, status, headers, fromCache: false } | ||
|
||
return response | ||
} | ||
} | ||
|
||
module.exports = createPlugin |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,30 @@ | ||
{ | ||
"name": "dat-shaka-plugin", | ||
"version": "0.0.1", | ||
"description": "A plugin for 'shaka-player' to load 'dat://' URIs", | ||
"main": "index.js", | ||
"scripts": { | ||
"test": ":" | ||
}, | ||
"keywords": [ | ||
"dat", | ||
"shaka", | ||
"player", | ||
"plugin" | ||
], | ||
"author": "Joseph Werle <joseph.werle@gmail.com>", | ||
"license": "MIT", | ||
"devDependencies": { | ||
"discovery-swarm-web": "^1.0.6", | ||
"shaka-player": "^2.5.0-beta3" | ||
}, | ||
"dependencies": { | ||
"collect-stream": "^1.2.1", | ||
"dat-link-resolve": "^2.3.0", | ||
"debug": "^4.1.1", | ||
"hyperdrive": "^9.14.5", | ||
"mime": "^2.4.2", | ||
"random-access-memory": "^3.1.1", | ||
"range-parser": "^1.2.0" | ||
} | ||
} |