{"id":28210728,"url":"https://github.com/xuset/aether-torrent","last_synced_at":"2025-06-11T00:31:53.571Z","repository":{"id":57173997,"uuid":"85006837","full_name":"xuset/aether-torrent","owner":"xuset","description":"A single WebTorrent client shared by all web pages and workers","archived":false,"fork":false,"pushed_at":"2022-08-19T12:12:41.000Z","size":3427,"stargazers_count":32,"open_issues_count":22,"forks_count":5,"subscribers_count":3,"default_branch":"master","last_synced_at":"2025-05-20T14:16:51.959Z","etag":null,"topics":[],"latest_commit_sha":null,"homepage":"","language":"JavaScript","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/xuset.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null}},"created_at":"2017-03-14T23:20:46.000Z","updated_at":"2024-08-31T06:18:45.000Z","dependencies_parsed_at":"2022-08-25T22:42:20.230Z","dependency_job_id":null,"html_url":"https://github.com/xuset/aether-torrent","commit_stats":null,"previous_names":["xuset/perma-torrent"],"tags_count":4,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/xuset%2Faether-torrent","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/xuset%2Faether-torrent/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/xuset%2Faether-torrent/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/xuset%2Faether-torrent/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/xuset","download_url":"https://codeload.github.com/xuset/aether-torrent/tar.gz/refs/heads/master","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/xuset%2Faether-torrent/sbom","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":259175405,"owners_count":22816985,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":[],"created_at":"2025-05-17T17:10:29.880Z","updated_at":"2025-06-11T00:31:53.561Z","avatar_url":"https://github.com/xuset.png","language":"JavaScript","funding_links":[],"categories":[],"sub_categories":[],"readme":"# aether-torrent [![Build Status](https://travis-ci.org/xuset/aether-torrent.svg?branch=master)](https://travis-ci.org/xuset/aether-torrent) [![npm](https://img.shields.io/npm/v/aether-torrent.svg)](https://npmjs.org/package/aether-torrent)\n\n#### A single [WebTorrent](https://webtorrent.io/) client shared by all web pages and workers\n\nEach AetherTorrent instance shares a single [WebTorrent](https://webtorrent.io/) client between all web pages and workers. So when a torrent is added in one context all other contexts are able to see that this torrent was added and can stream the downloading torrent. The benefit of this is that through behind-the-scene delegation only one web page does the actual downloading and seeding of the torrent instead of each web page. Additionally web workers are able to add and stream torrents just as web pages can. This shared client architecture also inherently persists it's state to IndexedDB so when a web page is reponed after the browser closed, it still has access to all the added torrents and their data.\n\nThis is a web-only module that can be used with bundlers like browserify or the `aethertorrent.min.js` script can be included which adds `AetherTorrent` to the global scope.\n\n## Usage\n\n#### Add a torrent then stream a file in a web page\n\n```js\nvar aether = new AetherTorrent()\n\naether.add('//foobar.torrent', function (err, torrent) {\n  if (err) throw err\n  var stream = torrent.files[0].getStream()\n})\n```\n\n#### Add a torrent then stream a file in a *web worker*\n\nThe exact same code above can be used in the web worker. The only caveat is that to download the torrent, there **must** be a web page that has instantiated AetherTorrent. This is because the actual torrent downloading must happen in a webpage since web workers do not have access to the WebRTC api.\n\nIn a web page:\n```js\n/* At least one web page has to have a AetherTorrent instance\n   so the download can be delegated to a web page */\nvar aether = new AetherTorrent()\n```\n\nIn a web worker:\n```js\n// Exact same code in the first example\nvar aether = new AetherTorrent()\n\naether.add('//foobar.torrent', function (err, torrent) {\n  if (err) throw err\n  // Returns NodeJS style stream\n  var stream = torrent.files[0].getStream()\n})\n```\n\n#### List all the torrents the shared client holds\n\n```js\nvar aether = new AetherTorrent()\n\naether.on('ready', function() {\n  console.log(aether.torrents)\n})\n```\n\n#### Get notified when a new torrent is added to the shared client\n\n```js\nvar aether = new AetherTorrent()\n\naether.on('torrent', function(torrent) {\n  console.log(torrent)\n  console.log(aether.torrents) // It is also added aether.torrents\n})\n```\n\n#### Optional promises are supported alongside callbacks\n```js\nvar aether = new AetherTorrent()\n\naether.add('//foobar.torrent')\n.then(torrent =\u003e torrent.files[0].getBlob())\n.then(blob =\u003e console.log(blob))\n```\n\n## API\n\nThe API uses NodeJS style callbacks but also supports promises in methods that accept a callback. If a callback is not given to one of these methods then the method will return a promise.\n\n### `var aether = new AetherTorrent([opts])`\n\nAll instances by default share the same underlying storage and client so adding a torrent to one instance adds it to all instances. To separate instances from one another define `opts.namespace`. The `opts` argument can take the following properties:\n\n * `opts.namespace` - Unique string used to insulate instances from each other. Defaults to 'aethertorrent'\n\n### `aether.add(torrentId, [opts], [function callback (err, torrent) {}])`\n\nAdds the given torrent to the instance and all other instances within the same namespace. `torrentId` must be a buffer of the '.torrent' file or a string url to the '.torrent' file. `torrent` is an instance of `Torrent` which is documented below.\n\n`opts` can have the following properties:\n\n* `opts.webseeds` - an array of webseed urls\n\n### `aether.torrents`\n\nThe list of `Torrent` instances that are shared between all web pages and workers. Listen for the 'ready' event to be notified when the list is fully populated.\n\n\n### `var torrent = aether.get(infoHash)`\n\nShorthand for iterating of the `aether.torrents` list and returning the torrent with the given `infoHash` or `undefined` if no torrent has that `infoHash`.\n\n### `aether.on('ready', function onready () {})`\n\n  `aether.torrents` is now fully populated with all the existing torrents\n\n### `aether.on('torrent', function ontorrent (torrent) {})`\n\n  Emitted when a AetherTorrent instance adds a new torrent\n\n### `aether.remove(infoHash, [function callback (err) {}])`\n\nRemoves the given torrent with the given `infoHash`\n\n### `aether.destroy()`\n\nFrees the internal resources of the instance without destroying the underlying torrent data.\n\n## API - Torrent\n\n### `torrent.infoHash`\n\nThe content based hash of the torrent that uniquely identifies it\n\n### `torrent.files`\n\nAn array of `File` instances that allow for the streaming of the file's data.\n\n### `var file = torrent.getFile(filePath)`\n\nReturns the `File` instance whose path in the torrent matches the given `filePath`. If no file is found then `undefined` is returned.\n\n## API - File\n\n### `file.name`\n\nThe file name\n\n### `file.path`\n\nThe path of the file within the torrent\n\n### `file.length`\n\nThe size of the file\n\n### `var stream = file.getStream([opts])`\n\nReturns a [NodeJS Readable stream](https://nodejs.org/api/stream.html#stream_readable_streams) for the file. The file can be streamed from any instance while it is being downloaded. `opts` can take the following properties:\n\n* `opts.start` - The byte offset to start streaming from within the file\n* `opts.end` - The byte offset to end the streaming\n\n### `var webStream = file.getWebStream([opts])`\n\nReturns a [WhatWG Readable stream](https://streams.spec.whatwg.org/) for the file. This type of stream is new and only available in a few browser; this method throws if it is called and the browser does not support this type of stream. `opts` can take the following properties:\n\n* `opts.start` - The byte offset to start streaming from within the file\n* `opts.end` - The byte offset to end the streaming\n\n### `file.getBlob([opts], [function callback (err, blob) {}]`\n\n  Returns a [Blob](https://developer.mozilla.org/en-US/docs/Web/API/Blob) of the file's data. `opts` can take the following properties:\n\n  * `opts.start` - The byte offset to start the blob from\n  * `opts.end` - The byte offset to end at\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fxuset%2Faether-torrent","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fxuset%2Faether-torrent","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fxuset%2Faether-torrent/lists"}