first commit
This commit is contained in:
commit
934816dd37
|
|
@ -0,0 +1 @@
|
|||
BOT_TOKEN=MTQ3ODMyMzM4MDIwNDg2MzQ4OA.Gvw2pK.rug4g0AHl7lhkABbXGg94dms8ffnYecTv_OAuQ
|
||||
|
|
@ -0,0 +1,11 @@
|
|||
{
|
||||
"guildId": "1477770093537792000",
|
||||
"welcomeChannelId": "1477779103376478381",
|
||||
"ticketCreationChannelId": "1478321242086969354",
|
||||
"ticketForumChannelId": "1478321516469817494",
|
||||
"colors": {
|
||||
"main": "#ff5500",
|
||||
"success": "#00ff00",
|
||||
"error": "#ff0000"
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1 @@
|
|||
../acorn/bin/acorn
|
||||
|
|
@ -0,0 +1 @@
|
|||
../color-support/bin.js
|
||||
|
|
@ -0,0 +1 @@
|
|||
../esbuild/bin/esbuild
|
||||
|
|
@ -0,0 +1 @@
|
|||
../he/bin/he
|
||||
|
|
@ -0,0 +1 @@
|
|||
../mkdirp/bin/cmd.js
|
||||
|
|
@ -0,0 +1 @@
|
|||
../node-gyp/bin/node-gyp.js
|
||||
|
|
@ -0,0 +1 @@
|
|||
../which/bin/node-which
|
||||
|
|
@ -0,0 +1 @@
|
|||
../nopt/bin/nopt.js
|
||||
|
|
@ -0,0 +1 @@
|
|||
../prebuild-install/bin.js
|
||||
|
|
@ -0,0 +1 @@
|
|||
../rc/cli.js
|
||||
|
|
@ -0,0 +1 @@
|
|||
../rimraf/bin.js
|
||||
|
|
@ -0,0 +1 @@
|
|||
../rollup/dist/bin/rollup
|
||||
|
|
@ -0,0 +1 @@
|
|||
../semver/bin/semver.js
|
||||
|
|
@ -0,0 +1 @@
|
|||
../sucrase/bin/sucrase
|
||||
|
|
@ -0,0 +1 @@
|
|||
../sucrase/bin/sucrase-node
|
||||
|
|
@ -0,0 +1 @@
|
|||
../tree-kill/cli.js
|
||||
|
|
@ -0,0 +1 @@
|
|||
../typescript/bin/tsc
|
||||
|
|
@ -0,0 +1 @@
|
|||
../typescript/bin/tsserver
|
||||
|
|
@ -0,0 +1 @@
|
|||
../tsup/dist/cli-default.js
|
||||
|
|
@ -0,0 +1 @@
|
|||
../tsup/dist/cli-node.js
|
||||
File diff suppressed because it is too large
Load Diff
|
|
@ -0,0 +1,19 @@
|
|||
Copyright (c) 2022 Forbes Lindesay & Jannis R
|
||||
|
||||
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.
|
||||
|
|
@ -0,0 +1,101 @@
|
|||
# http-basic
|
||||
|
||||
**This is a temporary fork of [`ForbesLindesay/http-basic`](https://github.com/ForbesLindesay/http-basic).**
|
||||
|
||||
---
|
||||
|
||||
Simple wrapper arround http.request/https.request
|
||||
|
||||
[](https://travis-ci.org/ForbesLindesay/http-basic)
|
||||
[](https://david-dm.org/ForbesLindesay/http-basic)
|
||||
[](https://www.npmjs.org/package/http-basic)
|
||||
|
||||
## Installation
|
||||
|
||||
npm install http-basic
|
||||
|
||||
## Usage
|
||||
|
||||
```js
|
||||
var request = require('http-basic');
|
||||
|
||||
var options = {followRedirects: true, gzip: true, cache: 'memory'};
|
||||
|
||||
var req = request('GET', 'http://example.com', options, function (err, res) {
|
||||
if (err) throw err;
|
||||
console.dir(res.statusCode);
|
||||
res.body.resume();
|
||||
});
|
||||
req.end();
|
||||
```
|
||||
|
||||
**method:**
|
||||
|
||||
The http method (e.g. `GET`, `POST`, `PUT`, `DELETE` etc.)
|
||||
|
||||
**url:**
|
||||
|
||||
The url as a string (e.g. `http://example.com`). It must be fully qualified and either http or https.
|
||||
|
||||
**options:**
|
||||
|
||||
- `headers` - (default `{}`) http headers
|
||||
- `agent` - (default: `false`) controlls keep-alive (see http://nodejs.org/api/http.html#http_http_request_options_callback)
|
||||
- `duplex` - (default: `true` except for `GET`, `OPTIONS` and `HEAD` requests) allows you to explicitly set a body on a request that uses a method that normally would not have a body
|
||||
- `followRedirects` - (default: `false`) - if true, redirects are followed (note that this only affects the result in the callback)
|
||||
- `maxRedirects` - (default: `Infinity`) - limit the number of redirects allowed.
|
||||
- `allowRedirectHeaders` (default: `null`) - an array of headers allowed for redirects (none if `null`).
|
||||
- `gzip` (default: `false`) - automatically accept gzip and deflate encodings. This is kept completely transparent to the user.
|
||||
- `cache` - (default: `null`) - `'memory'` or `'file'` to use the default built in caches or you can pass your own cache implementation.
|
||||
- `timeout` (default: `false`) - times out if no response is returned within the given number of milliseconds.
|
||||
- `socketTimeout` (default: `false`) - calls `req.setTimeout` internally which causes the request to timeout if no new data is seen for the given number of milliseconds.
|
||||
- `retry` (default: `false`) - retry GET requests. Set this to `true` to retry when the request errors or returns a status code greater than or equal to 400 (can also be a function that takes `(err, req, attemptNo) => shouldRetry`)
|
||||
- `retryDelay` (default: `200`) - the delay between retries (can also be set to a function that takes `(err, res, attemptNo) => delay`)
|
||||
- `maxRetries` (default: `5`) - the number of times to retry before giving up.
|
||||
- `ignoreFailedInvalidation` (default: `false`) - whether the cache should swallow errors if there is a problem removing a cached response. Note that enabling this setting may result in incorrect, cached data being returned to the user.
|
||||
- `isMatch` - `(requestHeaders: Headers, cachedResponse: CachedResponse, defaultValue: boolean) => boolean` - override the default behaviour for testing whether a cached response matches a request.
|
||||
- `isExpired` - `(cachedResponse: CachedResponse, defaultValue: boolean) => boolean` - override the default behaviour for testing whether a cached response has expired
|
||||
- `canCache` - `(res: Response<NodeJS.ReadableStream>, defaultValue: boolean) => boolean` - override the default behaviour for testing whether a response can be cached
|
||||
|
||||
**callback:**
|
||||
|
||||
The callback is called with `err` as the first argument and `res` as the second argument. `res` is an [http-response-object](https://github.com/ForbesLindesay/http-response-object). It has the following properties:
|
||||
|
||||
- `statusCode` - a number representing the HTTP Status Code
|
||||
- `headers` - an object representing the HTTP headers
|
||||
- `body` - a readable stream respresenting the request body.
|
||||
- `url` - the URL that was requested (in the case of redirects, this is the final url that was requested)
|
||||
|
||||
**returns:**
|
||||
|
||||
If the method is `GET`, `DELETE` or `HEAD`, it returns `undefined`.
|
||||
|
||||
Otherwise, it returns a writable stream for the body of the request.
|
||||
|
||||
## Implementing a Cache
|
||||
|
||||
A `Cache` is an object with three methods:
|
||||
|
||||
- `getResponse(url, callback)` - retrieve a cached response object
|
||||
- `setResponse(url, response)` - cache a response object
|
||||
- `invalidateResponse(url, callback)` - remove a response which is no longer valid
|
||||
|
||||
A cached response object is an object with the following properties:
|
||||
|
||||
- `statusCode` - Number
|
||||
- `headers` - Object (key value pairs of strings)
|
||||
- `body` - Stream (a stream of binary data)
|
||||
- `requestHeaders` - Object (key value pairs of strings)
|
||||
- `requestTimestamp` - Number
|
||||
|
||||
`getResponse` should call the callback with an optional error and either `null` or a cached response object, depending on whether the url can be found in the cache. Only `GET`s are cached.
|
||||
|
||||
`setResponse` should just swallow any errors it has (or resport them using `console.warn`).
|
||||
|
||||
`invalidateResponse` should call the callback with an optional error if it is unable to invalidate a response.
|
||||
|
||||
A cache may also define any of the methods from `lib/cache-utils.js` to override behaviour for what gets cached. It is currently still only possible to cache "get" requests, although this could be changed.
|
||||
|
||||
## License
|
||||
|
||||
MIT
|
||||
|
|
@ -0,0 +1,10 @@
|
|||
/// <reference types="node" />
|
||||
import { Headers } from './Headers';
|
||||
interface CachedResponse {
|
||||
statusCode: number;
|
||||
headers: Headers;
|
||||
body: NodeJS.ReadableStream;
|
||||
requestHeaders: Headers;
|
||||
requestTimestamp: number;
|
||||
}
|
||||
export { CachedResponse };
|
||||
|
|
@ -0,0 +1,2 @@
|
|||
"use strict";
|
||||
exports.__esModule = true;
|
||||
|
|
@ -0,0 +1,14 @@
|
|||
// @flow
|
||||
// Generated using flowgen2
|
||||
|
||||
import type {Headers} from './Headers';
|
||||
|
||||
interface CachedResponse {
|
||||
statusCode: number;
|
||||
headers: Headers;
|
||||
body: stream$Readable;
|
||||
requestHeaders: Headers;
|
||||
requestTimestamp: number;
|
||||
}
|
||||
|
||||
export type {CachedResponse};
|
||||
|
|
@ -0,0 +1,4 @@
|
|||
/// <reference types="node" />
|
||||
import Response = require('http-response-object');
|
||||
declare type Callback = (err: NodeJS.ErrnoException | null, response?: Response<NodeJS.ReadableStream>) => void;
|
||||
export { Callback };
|
||||
|
|
@ -0,0 +1,2 @@
|
|||
"use strict";
|
||||
exports.__esModule = true;
|
||||
|
|
@ -0,0 +1,11 @@
|
|||
// @flow
|
||||
// Generated using flowgen2
|
||||
|
||||
const Response = require('http-response-object');
|
||||
|
||||
type Callback = (
|
||||
err: ErrnoError | null,
|
||||
response?: Response<stream$Readable>,
|
||||
) => void;
|
||||
|
||||
export type {Callback};
|
||||
|
|
@ -0,0 +1,12 @@
|
|||
/// <reference types="node" />
|
||||
import { ICache } from './ICache';
|
||||
import { CachedResponse } from './CachedResponse';
|
||||
export default class FileCache implements ICache {
|
||||
private readonly _location;
|
||||
constructor(location: string);
|
||||
getResponse(url: string, callback: (err: null | Error, response: null | CachedResponse) => void): void;
|
||||
setResponse(url: string, response: CachedResponse): void;
|
||||
updateResponseHeaders(url: string, response: Pick<CachedResponse, 'headers' | 'requestTimestamp'>): void;
|
||||
invalidateResponse(url: string, callback: (err: NodeJS.ErrnoException | null) => void): void;
|
||||
getCacheKey(url: string): string;
|
||||
}
|
||||
|
|
@ -0,0 +1,112 @@
|
|||
'use strict';
|
||||
exports.__esModule = true;
|
||||
var fs = require("fs");
|
||||
var path_1 = require("path");
|
||||
var crypto_1 = require("crypto");
|
||||
function jsonParse(data, cb) {
|
||||
var result = null;
|
||||
try {
|
||||
result = JSON.parse(data);
|
||||
}
|
||||
catch (ex) {
|
||||
if (ex instanceof Error) {
|
||||
return cb(ex);
|
||||
}
|
||||
return cb(new Error(ex + ''));
|
||||
}
|
||||
cb(null, result);
|
||||
}
|
||||
var FileCache = /** @class */ (function () {
|
||||
function FileCache(location) {
|
||||
this._location = location;
|
||||
}
|
||||
FileCache.prototype.getResponse = function (url, callback) {
|
||||
var key = (0, path_1.resolve)(this._location, this.getCacheKey(url));
|
||||
fs.readFile(key + '.json', 'utf8', function (err, data) {
|
||||
if (err && err.code === 'ENOENT')
|
||||
return callback(null, null);
|
||||
else if (err)
|
||||
return callback(err, null);
|
||||
jsonParse(data, function (err, response) {
|
||||
if (err) {
|
||||
return callback(err, null);
|
||||
}
|
||||
var body = fs.createReadStream(key + '.body');
|
||||
response.body = body;
|
||||
callback(null, response);
|
||||
});
|
||||
});
|
||||
};
|
||||
FileCache.prototype.setResponse = function (url, response) {
|
||||
var key = (0, path_1.resolve)(this._location, this.getCacheKey(url));
|
||||
var errored = false;
|
||||
fs.mkdir(this._location, { recursive: true }, function (err) {
|
||||
if (err && err.code !== 'EEXIST') {
|
||||
console.warn('Error creating cache: ' + err.message);
|
||||
return;
|
||||
}
|
||||
response.body.pipe(fs.createWriteStream(key + '.body')).on('error', function (err) {
|
||||
errored = true;
|
||||
console.warn('Error writing to cache: ' + err.message);
|
||||
}).on('close', function () {
|
||||
if (!errored) {
|
||||
fs.writeFile(key + '.json', JSON.stringify({
|
||||
statusCode: response.statusCode,
|
||||
headers: response.headers,
|
||||
requestHeaders: response.requestHeaders,
|
||||
requestTimestamp: response.requestTimestamp
|
||||
}, null, ' '), function (err) {
|
||||
if (err) {
|
||||
console.warn('Error writing to cache: ' + err.message);
|
||||
}
|
||||
});
|
||||
}
|
||||
});
|
||||
});
|
||||
};
|
||||
FileCache.prototype.updateResponseHeaders = function (url, response) {
|
||||
var key = (0, path_1.resolve)(this._location, this.getCacheKey(url));
|
||||
fs.readFile(key + '.json', 'utf8', function (err, data) {
|
||||
if (err) {
|
||||
console.warn('Error writing to cache: ' + err.message);
|
||||
return;
|
||||
}
|
||||
var parsed = null;
|
||||
try {
|
||||
parsed = JSON.parse(data);
|
||||
}
|
||||
catch (ex) {
|
||||
if (ex instanceof Error) {
|
||||
console.warn('Error writing to cache: ' + ex.message);
|
||||
}
|
||||
return;
|
||||
}
|
||||
fs.writeFile(key + '.json', JSON.stringify({
|
||||
statusCode: parsed.statusCode,
|
||||
headers: response.headers,
|
||||
requestHeaders: parsed.requestHeaders,
|
||||
requestTimestamp: response.requestTimestamp
|
||||
}, null, ' '), function (err) {
|
||||
if (err) {
|
||||
console.warn('Error writing to cache: ' + err.message);
|
||||
}
|
||||
});
|
||||
});
|
||||
};
|
||||
FileCache.prototype.invalidateResponse = function (url, callback) {
|
||||
var key = (0, path_1.resolve)(this._location, this.getCacheKey(url));
|
||||
fs.unlink(key + '.json', function (err) {
|
||||
if (err && err.code === 'ENOENT')
|
||||
return callback(null);
|
||||
else
|
||||
callback(err || null);
|
||||
});
|
||||
};
|
||||
FileCache.prototype.getCacheKey = function (url) {
|
||||
var hash = (0, crypto_1.createHash)('sha512');
|
||||
hash.update(url);
|
||||
return hash.digest('hex');
|
||||
};
|
||||
return FileCache;
|
||||
}());
|
||||
exports["default"] = FileCache;
|
||||
|
|
@ -0,0 +1,24 @@
|
|||
// @flow
|
||||
// Generated using flowgen2
|
||||
|
||||
import type {ICache} from './ICache';
|
||||
import type {CachedResponse} from './CachedResponse';
|
||||
|
||||
declare class FileCache {
|
||||
constructor(location: string): void;
|
||||
getResponse(
|
||||
url: string,
|
||||
callback: (err: null | Error, response: null | CachedResponse) => void,
|
||||
): void;
|
||||
setResponse(url: string, response: CachedResponse): void;
|
||||
updateResponseHeaders(
|
||||
url: string,
|
||||
response: {[key: 'headers' | 'requestTimestamp']: any},
|
||||
): void;
|
||||
invalidateResponse(
|
||||
url: string,
|
||||
callback: (err: ErrnoError | null) => void,
|
||||
): void;
|
||||
getCacheKey(url: string): string;
|
||||
}
|
||||
export default FileCache;
|
||||
|
|
@ -0,0 +1,3 @@
|
|||
/// <reference types="node" />
|
||||
import { IncomingHttpHeaders } from 'http';
|
||||
export declare type Headers = IncomingHttpHeaders;
|
||||
|
|
@ -0,0 +1,2 @@
|
|||
"use strict";
|
||||
exports.__esModule = true;
|
||||
|
|
@ -0,0 +1,7 @@
|
|||
// @flow
|
||||
// Generated using flowgen2
|
||||
|
||||
type IncomingHttpHeaders = Object;
|
||||
|
||||
type Headers = IncomingHttpHeaders;
|
||||
export type {Headers};
|
||||
|
|
@ -0,0 +1,2 @@
|
|||
declare type HttpVerb = ('GET' | 'HEAD' | 'POST' | 'PUT' | 'DELETE' | 'CONNECT' | 'OPTIONS' | 'TRACE' | 'PATCH');
|
||||
export { HttpVerb };
|
||||
|
|
@ -0,0 +1,2 @@
|
|||
"use strict";
|
||||
exports.__esModule = true;
|
||||
|
|
@ -0,0 +1,15 @@
|
|||
// @flow
|
||||
// Generated using flowgen2
|
||||
|
||||
type HttpVerb =
|
||||
| 'GET'
|
||||
| 'HEAD'
|
||||
| 'POST'
|
||||
| 'PUT'
|
||||
| 'DELETE'
|
||||
| 'CONNECT'
|
||||
| 'OPTIONS'
|
||||
| 'TRACE'
|
||||
| 'PATCH';
|
||||
|
||||
export type {HttpVerb};
|
||||
|
|
@ -0,0 +1,8 @@
|
|||
import { CachedResponse } from './CachedResponse';
|
||||
interface ICache {
|
||||
getResponse(url: string, cb: (err: Error | null, response: CachedResponse | null) => void): void;
|
||||
setResponse(url: string, response: CachedResponse | null): void;
|
||||
updateResponseHeaders?: (url: string, response: Pick<CachedResponse, 'headers' | 'requestTimestamp'>) => void;
|
||||
invalidateResponse(url: string, cb: (err: Error | null) => void): void;
|
||||
}
|
||||
export { ICache };
|
||||
|
|
@ -0,0 +1,2 @@
|
|||
"use strict";
|
||||
exports.__esModule = true;
|
||||
|
|
@ -0,0 +1,19 @@
|
|||
// @flow
|
||||
// Generated using flowgen2
|
||||
|
||||
import type {CachedResponse} from './CachedResponse';
|
||||
|
||||
interface ICache {
|
||||
getResponse(
|
||||
url: string,
|
||||
cb: (err: Error | null, response: CachedResponse | null) => void,
|
||||
): void;
|
||||
setResponse(url: string, response: CachedResponse | null): void;
|
||||
updateResponseHeaders?: (
|
||||
url: string,
|
||||
response: {[key: 'headers' | 'requestTimestamp']: any},
|
||||
) => void;
|
||||
invalidateResponse(url: string, cb: (err: Error | null) => void): void;
|
||||
}
|
||||
|
||||
export type {ICache};
|
||||
|
|
@ -0,0 +1,9 @@
|
|||
/// <reference types="node" />
|
||||
import { CachedResponse } from './CachedResponse';
|
||||
export default class MemoryCache {
|
||||
private readonly _cache;
|
||||
getResponse(url: string, callback: (err: null | Error, response: null | CachedResponse) => void): void;
|
||||
updateResponseHeaders(url: string, response: Pick<CachedResponse, 'headers' | 'requestTimestamp'>): void;
|
||||
setResponse(url: string, response: CachedResponse): void;
|
||||
invalidateResponse(url: string, callback: (err: NodeJS.ErrnoException | null) => void): void;
|
||||
}
|
||||
|
|
@ -0,0 +1,59 @@
|
|||
'use strict';
|
||||
var __assign = (this && this.__assign) || function () {
|
||||
__assign = Object.assign || function(t) {
|
||||
for (var s, i = 1, n = arguments.length; i < n; i++) {
|
||||
s = arguments[i];
|
||||
for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p))
|
||||
t[p] = s[p];
|
||||
}
|
||||
return t;
|
||||
};
|
||||
return __assign.apply(this, arguments);
|
||||
};
|
||||
exports.__esModule = true;
|
||||
var stream_1 = require("stream");
|
||||
var concat = require("concat-stream");
|
||||
var MemoryCache = /** @class */ (function () {
|
||||
function MemoryCache() {
|
||||
this._cache = {};
|
||||
}
|
||||
MemoryCache.prototype.getResponse = function (url, callback) {
|
||||
var cache = this._cache;
|
||||
if (cache[url]) {
|
||||
var body = new stream_1.PassThrough();
|
||||
body.end(cache[url].body);
|
||||
callback(null, {
|
||||
statusCode: cache[url].statusCode,
|
||||
headers: cache[url].headers,
|
||||
body: body,
|
||||
requestHeaders: cache[url].requestHeaders,
|
||||
requestTimestamp: cache[url].requestTimestamp
|
||||
});
|
||||
}
|
||||
else {
|
||||
callback(null, null);
|
||||
}
|
||||
};
|
||||
MemoryCache.prototype.updateResponseHeaders = function (url, response) {
|
||||
this._cache[url] = __assign(__assign({}, this._cache[url]), { headers: response.headers, requestTimestamp: response.requestTimestamp });
|
||||
};
|
||||
MemoryCache.prototype.setResponse = function (url, response) {
|
||||
var cache = this._cache;
|
||||
response.body.pipe(concat(function (body) {
|
||||
cache[url] = {
|
||||
statusCode: response.statusCode,
|
||||
headers: response.headers,
|
||||
body: body,
|
||||
requestHeaders: response.requestHeaders,
|
||||
requestTimestamp: response.requestTimestamp
|
||||
};
|
||||
}));
|
||||
};
|
||||
MemoryCache.prototype.invalidateResponse = function (url, callback) {
|
||||
var cache = this._cache;
|
||||
delete cache[url];
|
||||
callback(null);
|
||||
};
|
||||
return MemoryCache;
|
||||
}());
|
||||
exports["default"] = MemoryCache;
|
||||
|
|
@ -0,0 +1,21 @@
|
|||
// @flow
|
||||
// Generated using flowgen2
|
||||
|
||||
import type {CachedResponse} from './CachedResponse';
|
||||
|
||||
declare class MemoryCache {
|
||||
getResponse(
|
||||
url: string,
|
||||
callback: (err: null | Error, response: null | CachedResponse) => void,
|
||||
): void;
|
||||
updateResponseHeaders(
|
||||
url: string,
|
||||
response: {[key: 'headers' | 'requestTimestamp']: any},
|
||||
): void;
|
||||
setResponse(url: string, response: CachedResponse): void;
|
||||
invalidateResponse(
|
||||
url: string,
|
||||
callback: (err: ErrnoError | null) => void,
|
||||
): void;
|
||||
}
|
||||
export default MemoryCache;
|
||||
|
|
@ -0,0 +1,27 @@
|
|||
/// <reference types="node" />
|
||||
/// <reference types="node" />
|
||||
import { Agent } from 'http';
|
||||
import { Headers } from './Headers';
|
||||
import { ICache } from './ICache';
|
||||
import Response = require('http-response-object');
|
||||
import { CachedResponse } from './CachedResponse';
|
||||
interface Options {
|
||||
agent?: Agent | boolean;
|
||||
allowRedirectHeaders?: string[];
|
||||
cache?: 'file' | 'memory' | ICache;
|
||||
duplex?: boolean;
|
||||
followRedirects?: boolean;
|
||||
gzip?: boolean;
|
||||
headers?: Headers;
|
||||
ignoreFailedInvalidation?: boolean;
|
||||
maxRedirects?: number;
|
||||
maxRetries?: number;
|
||||
retry?: boolean | ((err: NodeJS.ErrnoException | null, res: Response<NodeJS.ReadableStream> | void, attemptNumber: number) => boolean);
|
||||
retryDelay?: number | ((err: NodeJS.ErrnoException | null, res: Response<NodeJS.ReadableStream> | void, attemptNumber: number) => number);
|
||||
socketTimeout?: number;
|
||||
timeout?: number;
|
||||
isMatch?: (requestHeaders: Headers, cachedResponse: CachedResponse, defaultValue: boolean) => boolean;
|
||||
isExpired?: (cachedResponse: CachedResponse, defaultValue: boolean) => boolean;
|
||||
canCache?: (res: Response<NodeJS.ReadableStream>, defaultValue: boolean) => boolean;
|
||||
}
|
||||
export { Options };
|
||||
|
|
@ -0,0 +1,2 @@
|
|||
"use strict";
|
||||
exports.__esModule = true;
|
||||
|
|
@ -0,0 +1,49 @@
|
|||
// @flow
|
||||
// Generated using flowgen2
|
||||
|
||||
import {Agent} from 'http';
|
||||
import type {Headers} from './Headers';
|
||||
import type {ICache} from './ICache';
|
||||
const Response = require('http-response-object');
|
||||
import type {CachedResponse} from './CachedResponse';
|
||||
|
||||
interface Options {
|
||||
agent?: Agent | boolean;
|
||||
allowRedirectHeaders?: Array<string>;
|
||||
cache?: 'file' | 'memory' | ICache;
|
||||
duplex?: boolean;
|
||||
followRedirects?: boolean;
|
||||
gzip?: boolean;
|
||||
headers?: Headers;
|
||||
ignoreFailedInvalidation?: boolean;
|
||||
maxRedirects?: number;
|
||||
maxRetries?: number;
|
||||
retry?:
|
||||
| boolean
|
||||
| ((
|
||||
err: ErrnoError | null,
|
||||
res: Response<stream$Readable> | void,
|
||||
attemptNumber: number,
|
||||
) => boolean);
|
||||
retryDelay?:
|
||||
| number
|
||||
| ((
|
||||
err: ErrnoError | null,
|
||||
res: Response<stream$Readable> | void,
|
||||
attemptNumber: number,
|
||||
) => number);
|
||||
socketTimeout?: number;
|
||||
timeout?: number;
|
||||
isMatch?: (
|
||||
requestHeaders: Headers,
|
||||
cachedResponse: CachedResponse,
|
||||
defaultValue: boolean,
|
||||
) => boolean;
|
||||
isExpired?: (
|
||||
cachedResponse: CachedResponse,
|
||||
defaultValue: boolean,
|
||||
) => boolean;
|
||||
canCache?: (res: Response<stream$Readable>, defaultValue: boolean) => boolean;
|
||||
}
|
||||
|
||||
export type {Options};
|
||||
|
|
@ -0,0 +1,14 @@
|
|||
import { CachedResponse } from './CachedResponse';
|
||||
import Response = require('http-response-object');
|
||||
export declare type Policy = {
|
||||
maxage: number | null;
|
||||
};
|
||||
/**
|
||||
* returns true if this response is cacheable (according to cache-control headers)
|
||||
*/
|
||||
export declare function isCacheable<T>(res: Response<T> | CachedResponse): boolean;
|
||||
/**
|
||||
* if the response is cacheable, returns an object detailing the maxage of the cache
|
||||
* otherwise returns null
|
||||
*/
|
||||
export declare function cachePolicy<T>(res: Response<T> | CachedResponse): Policy | null;
|
||||
|
|
@ -0,0 +1,54 @@
|
|||
"use strict";
|
||||
exports.__esModule = true;
|
||||
exports.cachePolicy = exports.isCacheable = void 0;
|
||||
var parseCacheControl = require('parse-cache-control');
|
||||
function parseCacheControlHeader(res) {
|
||||
var cacheControl = res.headers['cache-control'];
|
||||
var normalisedCacheControl = typeof cacheControl === 'string' ? cacheControl.trim() : ''; // must be normalised for parsing (e.g. parseCacheControl)
|
||||
if (!cacheControl) {
|
||||
return null;
|
||||
}
|
||||
return parseCacheControl(cacheControl);
|
||||
}
|
||||
// for the purposes of this library, we err on the side of caution and do not cache anything except public (or implicit public)
|
||||
var nonCaching = ['private', 'no-cache', 'no-store', 'no-transform', 'must-revalidate', 'proxy-revalidate'];
|
||||
function isCacheControlCacheable(parsedCacheControl) {
|
||||
if (!parsedCacheControl) {
|
||||
return false;
|
||||
}
|
||||
if (parsedCacheControl.public) {
|
||||
return true;
|
||||
}
|
||||
// note that the library does not currently support s-maxage
|
||||
if (parsedCacheControl["max-age"]) {
|
||||
// https://www.w3.org/Protocols/rfc2616/rfc2616-sec14.html#sec14.9.3
|
||||
// The max-age directive on a response implies that the response is cacheable (i.e., "public") unless some other, more restrictive cache directive is also present.
|
||||
for (var i = 0; i < nonCaching.length; i++) {
|
||||
if (parsedCacheControl[nonCaching[i]]) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
/**
|
||||
* returns true if this response is cacheable (according to cache-control headers)
|
||||
*/
|
||||
function isCacheable(res) {
|
||||
return isCacheControlCacheable(parseCacheControlHeader(res));
|
||||
}
|
||||
exports.isCacheable = isCacheable;
|
||||
function buildPolicy(parsedCacheControl) {
|
||||
// note that the library does not currently support s-maxage
|
||||
return { maxage: parsedCacheControl['max-age'] || null };
|
||||
}
|
||||
/**
|
||||
* if the response is cacheable, returns an object detailing the maxage of the cache
|
||||
* otherwise returns null
|
||||
*/
|
||||
function cachePolicy(res) {
|
||||
var parsed = parseCacheControlHeader(res);
|
||||
return parsed && isCacheControlCacheable(parsed) ? buildPolicy(parsed) : null;
|
||||
}
|
||||
exports.cachePolicy = cachePolicy;
|
||||
16
node_modules/@derhuerst/http-basic/lib/cache-control-utils.js.flow
generated
vendored
Normal file
16
node_modules/@derhuerst/http-basic/lib/cache-control-utils.js.flow
generated
vendored
Normal file
|
|
@ -0,0 +1,16 @@
|
|||
// @flow
|
||||
// Generated using flowgen2
|
||||
|
||||
import type {CachedResponse} from './CachedResponse';
|
||||
const Response = require('http-response-object');
|
||||
|
||||
type Policy = {maxage: number | null};
|
||||
export type {Policy};
|
||||
|
||||
declare function isCacheable<T>(res: Response<T> | CachedResponse): boolean;
|
||||
export {isCacheable};
|
||||
|
||||
declare function cachePolicy<T>(
|
||||
res: Response<T> | CachedResponse,
|
||||
): Policy | null;
|
||||
export {cachePolicy};
|
||||
|
|
@ -0,0 +1,6 @@
|
|||
import Response = require('http-response-object');
|
||||
import { Headers } from './Headers';
|
||||
import { CachedResponse } from './CachedResponse';
|
||||
export declare function isMatch(requestHeaders: Headers, cachedResponse: CachedResponse): boolean;
|
||||
export declare function isExpired(cachedResponse: CachedResponse): boolean;
|
||||
export declare function canCache<T>(res: Response<T>): boolean;
|
||||
|
|
@ -0,0 +1,45 @@
|
|||
"use strict";
|
||||
exports.__esModule = true;
|
||||
exports.canCache = exports.isExpired = exports.isMatch = void 0;
|
||||
var cache_control_utils_1 = require("./cache-control-utils");
|
||||
function isMatch(requestHeaders, cachedResponse) {
|
||||
var vary = cachedResponse.headers['vary'];
|
||||
if (vary && cachedResponse.requestHeaders) {
|
||||
vary = '' + vary;
|
||||
return vary.split(',').map(function (header) { return header.trim().toLowerCase(); }).every(function (header) {
|
||||
return requestHeaders[header] === cachedResponse.requestHeaders[header];
|
||||
});
|
||||
}
|
||||
else {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
exports.isMatch = isMatch;
|
||||
;
|
||||
function isExpired(cachedResponse) {
|
||||
var policy = (0, cache_control_utils_1.cachePolicy)(cachedResponse);
|
||||
if (policy) {
|
||||
var time = (Date.now() - cachedResponse.requestTimestamp) / 1000;
|
||||
if (policy.maxage !== null && policy.maxage > time) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
if (cachedResponse.statusCode === 301 || cachedResponse.statusCode === 308)
|
||||
return false;
|
||||
return true;
|
||||
}
|
||||
exports.isExpired = isExpired;
|
||||
;
|
||||
function canCache(res) {
|
||||
if (res.headers['etag'])
|
||||
return true;
|
||||
if (res.headers['last-modified'])
|
||||
return true;
|
||||
if ((0, cache_control_utils_1.isCacheable)(res))
|
||||
return true;
|
||||
if (res.statusCode === 301 || res.statusCode === 308)
|
||||
return true;
|
||||
return false;
|
||||
}
|
||||
exports.canCache = canCache;
|
||||
;
|
||||
|
|
@ -0,0 +1,18 @@
|
|||
// @flow
|
||||
// Generated using flowgen2
|
||||
|
||||
const Response = require('http-response-object');
|
||||
import type {Headers} from './Headers';
|
||||
import type {CachedResponse} from './CachedResponse';
|
||||
|
||||
declare function isMatch(
|
||||
requestHeaders: Headers,
|
||||
cachedResponse: CachedResponse,
|
||||
): boolean;
|
||||
export {isMatch};
|
||||
|
||||
declare function isExpired(cachedResponse: CachedResponse): boolean;
|
||||
export {isExpired};
|
||||
|
||||
declare function canCache<T>(res: Response<T>): boolean;
|
||||
export {canCache};
|
||||
|
|
@ -0,0 +1,22 @@
|
|||
/// <reference types="node" />
|
||||
/// <reference types="node" />
|
||||
import FileCache from './FileCache';
|
||||
import MemoryCache from './MemoryCache';
|
||||
import { Callback } from './Callback';
|
||||
import { CachedResponse } from './CachedResponse';
|
||||
import { HttpVerb } from './HttpVerb';
|
||||
import { ICache } from './ICache';
|
||||
import { Options } from './Options';
|
||||
import Response = require('http-response-object');
|
||||
import { URL } from 'url';
|
||||
declare function request(method: HttpVerb, url: string | URL, options: Options | null | void, callback: Callback): void | NodeJS.WritableStream;
|
||||
declare function request(method: HttpVerb, url: string | URL, callback: Callback): void | NodeJS.WritableStream;
|
||||
export default request;
|
||||
export { HttpVerb };
|
||||
export { Options };
|
||||
export { FileCache };
|
||||
export { MemoryCache };
|
||||
export { Callback };
|
||||
export { Response };
|
||||
export { CachedResponse };
|
||||
export { ICache };
|
||||
|
|
@ -0,0 +1,388 @@
|
|||
"use strict";
|
||||
var __assign = (this && this.__assign) || function () {
|
||||
__assign = Object.assign || function(t) {
|
||||
for (var s, i = 1, n = arguments.length; i < n; i++) {
|
||||
s = arguments[i];
|
||||
for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p))
|
||||
t[p] = s[p];
|
||||
}
|
||||
return t;
|
||||
};
|
||||
return __assign.apply(this, arguments);
|
||||
};
|
||||
exports.__esModule = true;
|
||||
exports.Response = exports.MemoryCache = exports.FileCache = void 0;
|
||||
var cacheUtils = require("./cache-utils");
|
||||
var FileCache_1 = require("./FileCache");
|
||||
exports.FileCache = FileCache_1["default"];
|
||||
var MemoryCache_1 = require("./MemoryCache");
|
||||
exports.MemoryCache = MemoryCache_1["default"];
|
||||
var http_1 = require("http");
|
||||
var zlib_1 = require("zlib");
|
||||
var url_1 = require("url");
|
||||
var stream_1 = require("stream");
|
||||
var https_1 = require("https");
|
||||
var Response = require("http-response-object");
|
||||
exports.Response = Response;
|
||||
var caseless = require('caseless');
|
||||
var fileCache = new FileCache_1["default"](__dirname + '/cache');
|
||||
var memoryCache = new MemoryCache_1["default"]();
|
||||
function requestProtocol(protocol, options, callback) {
|
||||
if (protocol === 'http') {
|
||||
return (0, http_1.request)(options, callback);
|
||||
}
|
||||
else if (protocol === 'https') {
|
||||
return (0, https_1.request)(options, callback);
|
||||
}
|
||||
throw new Error('Unsupported protocol ' + protocol);
|
||||
}
|
||||
function request(method, url, options, callback) {
|
||||
if (typeof options === 'function') {
|
||||
callback = options;
|
||||
options = null;
|
||||
}
|
||||
if (options === null || options === undefined) {
|
||||
options = {};
|
||||
}
|
||||
if (typeof options !== 'object') {
|
||||
throw new TypeError('options must be an object (or null)');
|
||||
}
|
||||
if (typeof callback !== 'function') {
|
||||
throw new TypeError('callback must be a function');
|
||||
}
|
||||
return _request(method, ((url && typeof url === 'object') ? url.href : url), options, callback);
|
||||
}
|
||||
function _request(method, url, options, callback) {
|
||||
var start = Date.now();
|
||||
if (typeof method !== 'string') {
|
||||
throw new TypeError('The method must be a string.');
|
||||
}
|
||||
if (typeof url !== 'string') {
|
||||
throw new TypeError('The URL/path must be a string or a URL object.');
|
||||
}
|
||||
method = method.toUpperCase();
|
||||
var urlObject = (0, url_1.parse)(url);
|
||||
var protocol = (urlObject.protocol || '').replace(/\:$/, '');
|
||||
if (protocol !== 'http' && protocol !== 'https') {
|
||||
throw new TypeError('The protocol "' + protocol + '" is not supported, cannot load "' + url + '"');
|
||||
}
|
||||
var rawHeaders = options.headers || {};
|
||||
var headers = caseless(rawHeaders);
|
||||
if (urlObject.auth) {
|
||||
headers.set('Authorization', 'Basic ' + (Buffer.from(urlObject.auth)).toString('base64'));
|
||||
}
|
||||
var agent = 'agent' in options ? options.agent : false;
|
||||
var cache = options.cache;
|
||||
if (typeof cache === 'string') {
|
||||
if (cache === 'file') {
|
||||
cache = fileCache;
|
||||
}
|
||||
else if (cache === 'memory') {
|
||||
cache = memoryCache;
|
||||
}
|
||||
}
|
||||
if (cache && !(typeof cache === 'object' && typeof cache.getResponse === 'function' && typeof cache.setResponse === 'function' && typeof cache.invalidateResponse === 'function')) {
|
||||
throw new TypeError(cache + ' is not a valid cache, caches must have `getResponse`, `setResponse` and `invalidateResponse` methods.');
|
||||
}
|
||||
var ignoreFailedInvalidation = options.ignoreFailedInvalidation;
|
||||
if (options.duplex !== undefined && typeof options.duplex !== 'boolean') {
|
||||
throw new Error('expected options.duplex to be a boolean if provided');
|
||||
}
|
||||
var duplex = options.duplex !== undefined ? options.duplex : !(method === 'GET' || method === 'DELETE' || method === 'HEAD');
|
||||
var unsafe = !(method === 'GET' || method === 'OPTIONS' || method === 'HEAD');
|
||||
if (options.gzip) {
|
||||
headers.set('Accept-Encoding', headers.has('Accept-Encoding') ? headers.get('Accept-Encoding') + ',gzip,deflate' : 'gzip,deflate');
|
||||
return _request(method, url, {
|
||||
allowRedirectHeaders: options.allowRedirectHeaders,
|
||||
duplex: duplex,
|
||||
headers: rawHeaders,
|
||||
agent: agent,
|
||||
followRedirects: options.followRedirects,
|
||||
retry: options.retry,
|
||||
retryDelay: options.retryDelay,
|
||||
maxRetries: options.maxRetries,
|
||||
cache: cache,
|
||||
timeout: options.timeout
|
||||
}, function (err, res) {
|
||||
if (err)
|
||||
return callback(err);
|
||||
if (!res)
|
||||
return callback(new Error('Response should not be undefined if there is no error.'));
|
||||
var newHeaders = __assign({}, res.headers);
|
||||
var newBody = res.body;
|
||||
switch (newHeaders['content-encoding']) {
|
||||
case 'gzip':
|
||||
delete newHeaders['content-encoding'];
|
||||
newBody = res.body.pipe((0, zlib_1.createGunzip)());
|
||||
break;
|
||||
case 'deflate':
|
||||
delete newHeaders['content-encoding'];
|
||||
newBody = res.body.pipe((0, zlib_1.createInflate)());
|
||||
break;
|
||||
}
|
||||
return callback(err, new Response(res.statusCode, newHeaders, newBody, res.url));
|
||||
});
|
||||
}
|
||||
if (options.followRedirects) {
|
||||
return _request(method, url, {
|
||||
allowRedirectHeaders: options.allowRedirectHeaders,
|
||||
duplex: duplex,
|
||||
headers: rawHeaders,
|
||||
agent: agent,
|
||||
retry: options.retry,
|
||||
retryDelay: options.retryDelay,
|
||||
maxRetries: options.maxRetries,
|
||||
cache: cache,
|
||||
timeout: options.timeout
|
||||
}, function (err, res) {
|
||||
if (err)
|
||||
return callback(err);
|
||||
if (!res)
|
||||
return callback(new Error('Response should not be undefined if there is no error.'));
|
||||
if (options.followRedirects && isRedirect(res.statusCode)) {
|
||||
// prevent leakage of file handles
|
||||
res.body.resume();
|
||||
if (method === 'DELETE' && res.statusCode === 303) {
|
||||
// 303 See Other should convert to GET for duplex
|
||||
// requests and for DELETE
|
||||
method = 'GET';
|
||||
}
|
||||
if (options.maxRedirects === 0) {
|
||||
var err_1 = new Error('Maximum number of redirects exceeded');
|
||||
err_1.res = res;
|
||||
return callback(err_1, res);
|
||||
}
|
||||
options = __assign(__assign({}, options), { duplex: false, maxRedirects: options.maxRedirects && options.maxRedirects !== Infinity ? options.maxRedirects - 1 : options.maxRedirects });
|
||||
// don't maintain headers through redirects
|
||||
// This fixes a problem where a POST to http://example.com
|
||||
// might result in a GET to http://example.co.uk that includes "content-length"
|
||||
// as a header
|
||||
var headers_1 = caseless(options.headers);
|
||||
var redirectHeaders = {};
|
||||
if (options.allowRedirectHeaders) {
|
||||
for (var i = 0; i < options.allowRedirectHeaders.length; i++) {
|
||||
var headerName = options.allowRedirectHeaders[i];
|
||||
var headerValue = headers_1.get(headerName);
|
||||
if (headerValue) {
|
||||
redirectHeaders[headerName] = headerValue;
|
||||
}
|
||||
}
|
||||
}
|
||||
options.headers = redirectHeaders;
|
||||
var location = res.headers.location;
|
||||
if (typeof location !== 'string') {
|
||||
return callback(new Error('Cannot redirect to non string location: ' + location));
|
||||
}
|
||||
return request(duplex ? 'GET' : method, (0, url_1.resolve)(url, location), options, callback);
|
||||
}
|
||||
else {
|
||||
return callback(null, res);
|
||||
}
|
||||
});
|
||||
}
|
||||
if (cache && method === 'GET' && !duplex) {
|
||||
var timestamp_1 = Date.now();
|
||||
return cache.getResponse(url, function (err, cachedResponse) {
|
||||
if (err) {
|
||||
console.warn('Error reading from cache: ' + err.message);
|
||||
}
|
||||
var isMatch = !!(cachedResponse && cacheUtils.isMatch(rawHeaders, cachedResponse));
|
||||
if (cachedResponse && (options.isMatch ? options.isMatch(rawHeaders, cachedResponse, isMatch) : isMatch)) {
|
||||
var isExpired = cacheUtils.isExpired(cachedResponse);
|
||||
if (!(options.isExpired ? options.isExpired(cachedResponse, isExpired) : isExpired)) {
|
||||
var res = new Response(cachedResponse.statusCode, cachedResponse.headers, cachedResponse.body, url);
|
||||
res.fromCache = true;
|
||||
res.fromNotModified = false;
|
||||
return callback(null, res);
|
||||
}
|
||||
else {
|
||||
if (cachedResponse.headers['etag']) {
|
||||
headers.set('If-None-Match', cachedResponse.headers['etag']);
|
||||
}
|
||||
if (cachedResponse.headers['last-modified']) {
|
||||
headers.set('If-Modified-Since', cachedResponse.headers['last-modified']);
|
||||
}
|
||||
}
|
||||
}
|
||||
request('GET', url, {
|
||||
allowRedirectHeaders: options.allowRedirectHeaders,
|
||||
headers: rawHeaders,
|
||||
retry: options.retry,
|
||||
retryDelay: options.retryDelay,
|
||||
maxRetries: options.maxRetries,
|
||||
agent: agent,
|
||||
timeout: options.timeout
|
||||
}, function (err, res) {
|
||||
if (err)
|
||||
return callback(err);
|
||||
if (!res)
|
||||
return callback(new Error('Response should not be undefined if there is no error.'));
|
||||
if (res.statusCode === 304 && cachedResponse) { // Not Modified
|
||||
// prevent leakage of file handles
|
||||
res.body.resume();
|
||||
var resultBody = cachedResponse.body;
|
||||
var c = cache;
|
||||
if (c.updateResponseHeaders) {
|
||||
c.updateResponseHeaders(url, {
|
||||
headers: res.headers,
|
||||
requestTimestamp: timestamp_1
|
||||
});
|
||||
}
|
||||
else {
|
||||
var cachedResponseBody_1 = new stream_1.PassThrough();
|
||||
var newResultBody_1 = new stream_1.PassThrough();
|
||||
resultBody.on('data', function (data) {
|
||||
cachedResponseBody_1.write(data);
|
||||
newResultBody_1.write(data);
|
||||
});
|
||||
resultBody.on('end', function () {
|
||||
cachedResponseBody_1.end();
|
||||
newResultBody_1.end();
|
||||
});
|
||||
resultBody = newResultBody_1;
|
||||
cache.setResponse(url, {
|
||||
statusCode: cachedResponse.statusCode,
|
||||
headers: res.headers,
|
||||
body: cachedResponseBody_1,
|
||||
requestHeaders: cachedResponse.requestHeaders,
|
||||
requestTimestamp: timestamp_1
|
||||
});
|
||||
}
|
||||
var response = new Response(cachedResponse.statusCode, cachedResponse.headers, resultBody, url);
|
||||
response.fromCache = true;
|
||||
response.fromNotModified = true;
|
||||
return callback(null, response);
|
||||
}
|
||||
// prevent leakage of file handles
|
||||
cachedResponse && cachedResponse.body.resume();
|
||||
var canCache = cacheUtils.canCache(res);
|
||||
if (options.canCache ? options.canCache(res, canCache) : canCache) {
|
||||
var cachedResponseBody_2 = new stream_1.PassThrough();
|
||||
var resultResponseBody_1 = new stream_1.PassThrough();
|
||||
res.body.on('data', function (data) {
|
||||
cachedResponseBody_2.write(data);
|
||||
resultResponseBody_1.write(data);
|
||||
});
|
||||
res.body.on('end', function () { cachedResponseBody_2.end(); resultResponseBody_1.end(); });
|
||||
var resultResponse = new Response(res.statusCode, res.headers, resultResponseBody_1, url);
|
||||
cache.setResponse(url, {
|
||||
statusCode: res.statusCode,
|
||||
headers: res.headers,
|
||||
body: cachedResponseBody_2,
|
||||
requestHeaders: rawHeaders,
|
||||
requestTimestamp: timestamp_1
|
||||
});
|
||||
return callback(null, resultResponse);
|
||||
}
|
||||
else {
|
||||
return callback(null, res);
|
||||
}
|
||||
});
|
||||
});
|
||||
}
|
||||
function attempt(n) {
|
||||
return _request(method, url, {
|
||||
allowRedirectHeaders: options.allowRedirectHeaders,
|
||||
headers: rawHeaders,
|
||||
agent: agent,
|
||||
timeout: options.timeout
|
||||
}, function (err, res) {
|
||||
var retry = err || !res || res.statusCode >= 400;
|
||||
if (typeof options.retry === 'function') {
|
||||
retry = options.retry(err, res, n + 1);
|
||||
}
|
||||
if (n >= (options.maxRetries || 5)) {
|
||||
retry = false;
|
||||
}
|
||||
if (retry) {
|
||||
var delay = options.retryDelay;
|
||||
if (typeof delay === 'function') {
|
||||
delay = delay(err, res, n + 1);
|
||||
}
|
||||
delay = delay || 200;
|
||||
setTimeout(function () {
|
||||
attempt(n + 1);
|
||||
}, delay);
|
||||
}
|
||||
else {
|
||||
callback(err, res);
|
||||
}
|
||||
});
|
||||
}
|
||||
if (options.retry && method === 'GET' && !duplex) {
|
||||
return attempt(0);
|
||||
}
|
||||
var responded = false;
|
||||
var timeout = null;
|
||||
var req = requestProtocol(protocol, {
|
||||
host: urlObject.hostname,
|
||||
port: urlObject.port == null ? undefined : +urlObject.port,
|
||||
path: urlObject.path,
|
||||
method: method,
|
||||
headers: rawHeaders,
|
||||
agent: agent
|
||||
}, function (res) {
|
||||
var end = Date.now();
|
||||
if (responded)
|
||||
return res.resume();
|
||||
responded = true;
|
||||
if (timeout !== null)
|
||||
clearTimeout(timeout);
|
||||
var result = new Response(res.statusCode || 0, res.headers, res, url);
|
||||
if (cache && unsafe && res.statusCode && res.statusCode < 400) {
|
||||
cache.invalidateResponse(url, function (err) {
|
||||
if (err && !ignoreFailedInvalidation) {
|
||||
callback(new Error('Error invalidating the cache for' + url + ': ' + err.message), result);
|
||||
}
|
||||
else {
|
||||
callback(null, result);
|
||||
}
|
||||
});
|
||||
}
|
||||
else {
|
||||
callback(null, result);
|
||||
}
|
||||
}).on('error', function (err) {
|
||||
if (responded)
|
||||
return;
|
||||
responded = true;
|
||||
if (timeout !== null)
|
||||
clearTimeout(timeout);
|
||||
callback(err);
|
||||
});
|
||||
function onTimeout() {
|
||||
if (responded)
|
||||
return;
|
||||
responded = true;
|
||||
if (timeout !== null)
|
||||
clearTimeout(timeout);
|
||||
req.abort();
|
||||
var duration = Date.now() - start;
|
||||
var err = new Error('Request timed out after ' + duration + 'ms');
|
||||
err.timeout = true;
|
||||
err.duration = duration;
|
||||
callback(err);
|
||||
}
|
||||
if (options.socketTimeout) {
|
||||
req.setTimeout(options.socketTimeout, onTimeout);
|
||||
}
|
||||
if (options.timeout) {
|
||||
timeout = setTimeout(onTimeout, options.timeout);
|
||||
}
|
||||
if (duplex) {
|
||||
return req;
|
||||
}
|
||||
else {
|
||||
req.end();
|
||||
}
|
||||
return undefined;
|
||||
}
|
||||
function isRedirect(statusCode) {
|
||||
return statusCode === 301 || statusCode === 302 || statusCode === 303 || statusCode === 307 || statusCode === 308;
|
||||
}
|
||||
exports["default"] = request;
|
||||
module.exports = request;
|
||||
module.exports["default"] = request;
|
||||
module.exports.FileCache = FileCache_1["default"];
|
||||
module.exports.MemoryCache = MemoryCache_1["default"];
|
||||
module.exports.Response = Response;
|
||||
|
|
@ -0,0 +1,35 @@
|
|||
// @flow
|
||||
// Generated using flowgen2
|
||||
|
||||
import FileCache from './FileCache';
|
||||
import MemoryCache from './MemoryCache';
|
||||
import type {Callback} from './Callback';
|
||||
import type {CachedResponse} from './CachedResponse';
|
||||
import type {HttpVerb} from './HttpVerb';
|
||||
import type {ICache} from './ICache';
|
||||
import type {Options} from './Options';
|
||||
const Response = require('http-response-object');
|
||||
import {URL} from 'url';
|
||||
|
||||
declare function request(
|
||||
method: HttpVerb,
|
||||
url: string | URL,
|
||||
options: Options | null | void,
|
||||
callback: Callback,
|
||||
): void | stream$Writable;
|
||||
|
||||
declare function request(
|
||||
method: HttpVerb,
|
||||
url: string | URL,
|
||||
callback: Callback,
|
||||
): void | stream$Writable;
|
||||
|
||||
export default request;
|
||||
export type {HttpVerb};
|
||||
export type {Options};
|
||||
export {FileCache};
|
||||
export {MemoryCache};
|
||||
export type {Callback};
|
||||
export {Response};
|
||||
export type {CachedResponse};
|
||||
export type {ICache};
|
||||
|
|
@ -0,0 +1,48 @@
|
|||
{
|
||||
"name": "@derhuerst/http-basic",
|
||||
"version": "8.2.4",
|
||||
"main": "lib/index.js",
|
||||
"types": "lib/index.d.ts",
|
||||
"files": [
|
||||
"lib"
|
||||
],
|
||||
"description": "Very low level wrapper arround http.request/https.request",
|
||||
"keywords": [
|
||||
"http",
|
||||
"https",
|
||||
"request",
|
||||
"fetch",
|
||||
"gzip",
|
||||
"deflate",
|
||||
"redirect",
|
||||
"cache",
|
||||
"etag",
|
||||
"cache-control"
|
||||
],
|
||||
"dependencies": {
|
||||
"caseless": "^0.12.0",
|
||||
"concat-stream": "^2.0.0",
|
||||
"http-response-object": "^3.0.1",
|
||||
"parse-cache-control": "^1.0.1"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@types/concat-stream": "^2.0.0",
|
||||
"@types/node": "^18.0.1",
|
||||
"flowgen2": "^2.2.1",
|
||||
"rimraf": "^3.0.2",
|
||||
"serve-static": "^1.11.1",
|
||||
"typescript": "^4.5.4"
|
||||
},
|
||||
"scripts": {
|
||||
"prepublishOnly": "npm run build",
|
||||
"build": "tsc && flowgen lib/**/*",
|
||||
"pretest": "npm run build",
|
||||
"test": "node test/index && node test/cache && node test/cache-invalidation && rimraf lib/cache"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=6.0.0"
|
||||
},
|
||||
"repository": "https://github.com/derhuerst/http-basic.git",
|
||||
"author": "ForbesLindesay",
|
||||
"license": "MIT"
|
||||
}
|
||||
|
|
@ -0,0 +1,21 @@
|
|||
MIT License
|
||||
|
||||
Copyright (c) 2023 Androz2091
|
||||
|
||||
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.
|
||||
|
|
@ -0,0 +1,74 @@
|
|||
# `@discord-player/equalizer`
|
||||
|
||||
This library implements Lavaplayer's 15 Band PCM Equalizer & biquad utilities.
|
||||
|
||||
## Installation
|
||||
|
||||
```sh
|
||||
$ yarn add @discord-player/equalizer
|
||||
```
|
||||
|
||||
## Example
|
||||
|
||||
#### Equalizer
|
||||
|
||||
```js
|
||||
import { EqualizerStream } from '@discord-player/equalizer';
|
||||
|
||||
// initialize 15 band equalizer stream
|
||||
const equalizer = new EqualizerStream();
|
||||
|
||||
// set equalizer bands, in this case add some bass
|
||||
equalizer.setEQ([
|
||||
{ band: 0, gain: 0.25 },
|
||||
{ band: 1, gain: 0.25 },
|
||||
{ band: 2, gain: 0.25 }
|
||||
]);
|
||||
|
||||
// input stream
|
||||
const input = getPCMAudioSomehow();
|
||||
|
||||
// pipe input stream to equalizer
|
||||
const output = input.pipe(equalizer);
|
||||
|
||||
// now do something with the output stream
|
||||
```
|
||||
|
||||
#### Biquad
|
||||
|
||||
```js
|
||||
import { BiquadStream, FilterType } from '@discord-player/equalizer';
|
||||
|
||||
// initialize biquad stream
|
||||
const biquad = new BiquadStream();
|
||||
|
||||
// initialize with filter
|
||||
const biquad = new BiquadStream({
|
||||
filter: FilterType.LowPass
|
||||
});
|
||||
|
||||
// set filter
|
||||
biquad.setFilter(FilterType.HighPass);
|
||||
|
||||
// set gain (Gain is only applicable to LowShelf, HighShelf and PeakingEQ)
|
||||
biquad.setGain(5);
|
||||
|
||||
// input stream
|
||||
const input = getPCMAudioSomehow();
|
||||
|
||||
// pipe input stream to biquad
|
||||
const output = input.pipe(biquad);
|
||||
```
|
||||
|
||||
#### Supported Biquad Filters
|
||||
|
||||
- SinglePoleLowPassApprox
|
||||
- SinglePoleLowPass
|
||||
- LowPass
|
||||
- HighPass
|
||||
- BandPass
|
||||
- Notch
|
||||
- AllPass
|
||||
- LowShelf
|
||||
- HighShelf
|
||||
- PeakingEQ
|
||||
|
|
@ -0,0 +1,482 @@
|
|||
import { TransformOptions, Transform, TransformCallback, Readable } from 'stream';
|
||||
import { EventEmitter } from 'events';
|
||||
|
||||
declare const FilterType: {
|
||||
readonly SinglePoleLowPassApprox: 0;
|
||||
readonly SinglePoleLowPass: 1;
|
||||
readonly LowPass: 2;
|
||||
readonly HighPass: 3;
|
||||
readonly BandPass: 4;
|
||||
readonly Notch: 5;
|
||||
readonly AllPass: 6;
|
||||
readonly LowShelf: 7;
|
||||
readonly HighShelf: 8;
|
||||
readonly PeakingEQ: 9;
|
||||
};
|
||||
type BiquadFilters = keyof typeof FilterType | (typeof FilterType)[keyof typeof FilterType];
|
||||
interface CoefficientsInit {
|
||||
a1: number;
|
||||
a2: number;
|
||||
b0: number;
|
||||
b1: number;
|
||||
b2: number;
|
||||
}
|
||||
declare const Q_BUTTERWORTH: number;
|
||||
declare class Coefficients {
|
||||
a1: number;
|
||||
a2: number;
|
||||
b0: number;
|
||||
b1: number;
|
||||
b2: number;
|
||||
constructor(data?: CoefficientsInit);
|
||||
static from(filter: BiquadFilters, samplingFreq: number, cutoffFreq: number, Q: number, dbGain?: number): Coefficients;
|
||||
}
|
||||
|
||||
interface BiquadSetFilterProps {
|
||||
f0: number;
|
||||
fs: number;
|
||||
Q: number;
|
||||
gain?: number;
|
||||
}
|
||||
declare class BiquadFilter {
|
||||
coefficients: Coefficients;
|
||||
x1: number;
|
||||
x2: number;
|
||||
y1: number;
|
||||
y2: number;
|
||||
s1: number;
|
||||
s2: number;
|
||||
constructor(coefficients: Coefficients);
|
||||
setFilter(filter: BiquadFilters, options: BiquadSetFilterProps): void;
|
||||
update(coefficients: Coefficients): void;
|
||||
replace(coefficients: Coefficients): void;
|
||||
reset(): void;
|
||||
run(input: number): number;
|
||||
runTransposed(input: number): number;
|
||||
}
|
||||
|
||||
declare class Frequency {
|
||||
private __val;
|
||||
constructor(__val: number);
|
||||
khz(): number;
|
||||
mhz(): number;
|
||||
hz(): number;
|
||||
dt(): number;
|
||||
valueOf(): number;
|
||||
toString(): string;
|
||||
toJSON(): string;
|
||||
}
|
||||
|
||||
type PCMType = `s${16 | 32}${'l' | 'b'}e`;
|
||||
interface PCMTransformerOptions extends TransformOptions {
|
||||
type?: PCMType;
|
||||
disabled?: boolean;
|
||||
sampleRate?: number;
|
||||
}
|
||||
declare class PCMTransformer extends Transform {
|
||||
readonly type: PCMType;
|
||||
bits: number;
|
||||
bytes: number;
|
||||
extremum: number;
|
||||
disabled: boolean;
|
||||
sampleRate: number;
|
||||
onUpdate: () => void;
|
||||
constructor(options?: PCMTransformerOptions);
|
||||
disable(): void;
|
||||
enable(): void;
|
||||
toggle(): boolean;
|
||||
_readInt(buffer: Buffer, index: number): number;
|
||||
_writeInt(buffer: Buffer, int: number, index: number): number;
|
||||
clamp(val: number, max?: number, min?: number): number;
|
||||
setSampleRate(rate: number): void;
|
||||
}
|
||||
|
||||
interface BiquadStreamOptions extends PCMTransformerOptions {
|
||||
filter?: BiquadFilters;
|
||||
Q?: number;
|
||||
cutoff?: number;
|
||||
gain?: number;
|
||||
}
|
||||
interface BiquadFilterUpdateData {
|
||||
filter?: BiquadFilters;
|
||||
Q?: number;
|
||||
cutoff?: number;
|
||||
gain?: number;
|
||||
}
|
||||
declare class BiquadStream extends PCMTransformer {
|
||||
biquad: BiquadFilter;
|
||||
cutoff: number;
|
||||
gain: number;
|
||||
biquadFilter: BiquadFilters;
|
||||
Q: number;
|
||||
constructor(options?: BiquadStreamOptions);
|
||||
get filters(): BiquadFilters;
|
||||
set filters(f: BiquadFilters);
|
||||
getFilterName(): BiquadFilters | null;
|
||||
update(options: BiquadFilterUpdateData): void;
|
||||
setFilter(filter: BiquadFilters): void;
|
||||
setQ(Q: number): void;
|
||||
setCutoff(f0: number): void;
|
||||
setGain(dB: number): void;
|
||||
_transform(chunk: Buffer, encoding: BufferEncoding, callback: TransformCallback): void;
|
||||
}
|
||||
|
||||
type ReadIntCallback = (buffer: Buffer, index: number) => number;
|
||||
type WriteIntCallback = (buffer: Buffer, int: number, index: number) => number;
|
||||
declare class ChannelProcessor {
|
||||
history: number[];
|
||||
bandMultipliers: number[];
|
||||
current: number;
|
||||
m1: number;
|
||||
m2: number;
|
||||
constructor(bandMultipliers: number[]);
|
||||
processInt(int: number): number;
|
||||
process(samples: Buffer, extremum?: number, bytes?: number, readInt?: ReadIntCallback, writeInt?: WriteIntCallback): Buffer;
|
||||
step(): void;
|
||||
reset(): void;
|
||||
}
|
||||
|
||||
declare class EqualizerCoefficients {
|
||||
beta: number;
|
||||
alpha: number;
|
||||
gamma: number;
|
||||
constructor(beta: number, alpha: number, gamma: number);
|
||||
setBeta(v: number): void;
|
||||
setAlpha(v: number): void;
|
||||
setGamma(v: number): void;
|
||||
toJSON(): {
|
||||
alpha: number;
|
||||
beta: number;
|
||||
gamma: number;
|
||||
};
|
||||
}
|
||||
|
||||
declare class EqualizerConfiguration {
|
||||
bandMultipliers: number[];
|
||||
constructor(bandMultipliers: number[]);
|
||||
setGain(band: number, value: number): void;
|
||||
getGain(band: number): number;
|
||||
isValidBand(band: number): boolean;
|
||||
}
|
||||
|
||||
interface ChannelProcessorInput {
|
||||
data: Buffer;
|
||||
readInt?: ReadIntCallback;
|
||||
writeInt?: WriteIntCallback;
|
||||
extremum?: number;
|
||||
bytes?: number;
|
||||
}
|
||||
declare class Equalizer extends EqualizerConfiguration {
|
||||
static BAND_COUNT: 15;
|
||||
static SAMPLE_RATE: 48000;
|
||||
static Coefficients48000: EqualizerCoefficients[];
|
||||
channels: ChannelProcessor[];
|
||||
channelCount: number;
|
||||
constructor(channelCount: number, bandMultipliers: number[]);
|
||||
createChannelProcessor(): ChannelProcessor[];
|
||||
process(input: ChannelProcessorInput[]): Buffer[];
|
||||
}
|
||||
|
||||
interface EqualizerStreamOptions extends PCMTransformerOptions {
|
||||
bandMultiplier?: EqualizerBand[];
|
||||
channels?: number;
|
||||
}
|
||||
interface EqualizerBand {
|
||||
band: number;
|
||||
gain: number;
|
||||
}
|
||||
declare class EqualizerStream extends PCMTransformer {
|
||||
bandMultipliers: number[];
|
||||
equalizer: Equalizer;
|
||||
constructor(options?: EqualizerStreamOptions);
|
||||
_processBands(multiplier: EqualizerBand[]): void;
|
||||
_transform(chunk: Buffer, encoding: BufferEncoding, callback: TransformCallback): void;
|
||||
getEQ(): EqualizerBand[];
|
||||
setEQ(bands: EqualizerBand[]): void;
|
||||
resetEQ(): void;
|
||||
}
|
||||
|
||||
type MSTStrategy = 'm2s' | 's2m';
|
||||
interface MonoStereoTransformerOptions extends PCMTransformerOptions {
|
||||
strategy: MSTStrategy;
|
||||
}
|
||||
declare class MonoStereoTransformer extends PCMTransformer {
|
||||
strategy: MSTStrategy;
|
||||
constructor(options?: MonoStereoTransformerOptions);
|
||||
setStrategy(strategy: MSTStrategy): void;
|
||||
_transform(chunk: Buffer, encoding: BufferEncoding, callback: TransformCallback): void;
|
||||
toStereo(sample: Buffer, len: number): Buffer;
|
||||
toMono(sample: Buffer, len: number): Buffer;
|
||||
}
|
||||
|
||||
interface AFBiquadConfig {
|
||||
biquad: BiquadFilter;
|
||||
sample: number;
|
||||
cutoff: number;
|
||||
gain: number;
|
||||
filter: BiquadFilters;
|
||||
coefficient: Coefficients;
|
||||
Q: number;
|
||||
}
|
||||
declare function applyBiquad(filterer: BiquadFilter, int: number): number;
|
||||
|
||||
interface AFPulsatorConfig {
|
||||
hz: number;
|
||||
x: number;
|
||||
dI: number;
|
||||
}
|
||||
interface AFTremoloConfig {
|
||||
phase: number;
|
||||
depth: number;
|
||||
frequency: number;
|
||||
}
|
||||
type AFVibratoConfig = AFTremoloConfig;
|
||||
type LR = 0 | 1;
|
||||
declare function applyPulsator(config: AFPulsatorConfig, int: number, channel: LR): number;
|
||||
declare function applyTremolo(config: AFTremoloConfig, int: number, sampleRate: number): number;
|
||||
declare function applyVibrato(config: AFVibratoConfig, int: number, sampleRate: number): number;
|
||||
declare function applyVolume(vol: number, int: number): number;
|
||||
|
||||
declare function applyEqualization(eq: Equalizer, int: number): number;
|
||||
|
||||
type index_AFBiquadConfig = AFBiquadConfig;
|
||||
type index_AFPulsatorConfig = AFPulsatorConfig;
|
||||
type index_AFTremoloConfig = AFTremoloConfig;
|
||||
type index_AFVibratoConfig = AFVibratoConfig;
|
||||
type index_LR = LR;
|
||||
declare const index_applyBiquad: typeof applyBiquad;
|
||||
declare const index_applyEqualization: typeof applyEqualization;
|
||||
declare const index_applyPulsator: typeof applyPulsator;
|
||||
declare const index_applyTremolo: typeof applyTremolo;
|
||||
declare const index_applyVibrato: typeof applyVibrato;
|
||||
declare const index_applyVolume: typeof applyVolume;
|
||||
declare namespace index {
|
||||
export { type index_AFBiquadConfig as AFBiquadConfig, type index_AFPulsatorConfig as AFPulsatorConfig, type index_AFTremoloConfig as AFTremoloConfig, type index_AFVibratoConfig as AFVibratoConfig, type index_LR as LR, index_applyBiquad as applyBiquad, index_applyEqualization as applyEqualization, index_applyPulsator as applyPulsator, index_applyTremolo as applyTremolo, index_applyVibrato as applyVibrato, index_applyVolume as applyVolume };
|
||||
}
|
||||
|
||||
declare const AudioFilters: {
|
||||
readonly '8D': "8D";
|
||||
readonly Tremolo: "Tremolo";
|
||||
readonly Vibrato: "Vibrato";
|
||||
};
|
||||
type PCMFilters = keyof typeof AudioFilters;
|
||||
interface PCMFiltererOptions extends PCMTransformerOptions {
|
||||
filters?: PCMFilters[];
|
||||
}
|
||||
declare const AF_NIGHTCORE_RATE: 1.3;
|
||||
declare const AF_VAPORWAVE_RATE: 0.8;
|
||||
declare const BASS_EQ_BANDS: EqualizerBand[];
|
||||
declare class AudioFilter extends PCMTransformer {
|
||||
filters: PCMFilters[];
|
||||
targetSampleRate: number;
|
||||
pulsatorConfig: AFPulsatorConfig;
|
||||
tremoloConfig: AFTremoloConfig;
|
||||
vibratoConfig: AFVibratoConfig;
|
||||
constructor(options?: PCMFiltererOptions);
|
||||
setTargetSampleRate(rate: number): void;
|
||||
setPulsator(hz: number): void;
|
||||
get pulsator(): number;
|
||||
setTremolo({ depth, frequency, phase, }: Partial<AFTremoloConfig>): void;
|
||||
setVibrato({ depth, frequency, phase, }: Partial<AFVibratoConfig>): void;
|
||||
get tremolo(): AFTremoloConfig;
|
||||
setFilters(filters: PCMFilters[]): boolean;
|
||||
_transform(chunk: Buffer, encoding: BufferEncoding, callback: TransformCallback): void;
|
||||
get currentSampleRate(): number;
|
||||
applyFilters(byte: number, channel: LR): number;
|
||||
}
|
||||
|
||||
interface PCMResamplerOptions extends PCMTransformerOptions {
|
||||
inputSampleRate: number;
|
||||
targetSampleRate: number;
|
||||
channels?: number;
|
||||
}
|
||||
interface ResampleParameters {
|
||||
currentFilter: CommonResamplerFilterPreset | null;
|
||||
inputSampleRate: number;
|
||||
channels: number;
|
||||
sampleRate: number;
|
||||
}
|
||||
type CommonResamplerFilterPreset = 'nightcore' | 'vaporwave';
|
||||
declare class PCMResampler extends PCMTransformer {
|
||||
private readonly inputSampleRate;
|
||||
private readonly channels;
|
||||
private buffer;
|
||||
currentFilter: CommonResamplerFilterPreset | null;
|
||||
constructor(options?: PCMResamplerOptions);
|
||||
setFilter(filter: CommonResamplerFilterPreset | null): void;
|
||||
getParameters(): ResampleParameters;
|
||||
toggleFilter(filter: CommonResamplerFilterPreset): boolean;
|
||||
getRatio(): number;
|
||||
private resample;
|
||||
_transform(chunk: Buffer, encoding: BufferEncoding, callback: (error?: Error | null, data?: Buffer) => void): void;
|
||||
_flush(callback: (error?: Error | null, data?: Buffer) => void): void;
|
||||
setSampleRate(rate: number): void;
|
||||
}
|
||||
|
||||
interface VolumeTransformerOptions extends PCMTransformerOptions {
|
||||
volume?: number;
|
||||
}
|
||||
declare class VolumeTransformer extends PCMTransformer {
|
||||
private _volume;
|
||||
constructor(options?: VolumeTransformerOptions);
|
||||
get volumeApprox(): number;
|
||||
get volume(): number;
|
||||
set volume(volume: number);
|
||||
setVolume(volume: number): boolean;
|
||||
_transform(chunk: Buffer, encoding: BufferEncoding, callback: TransformCallback): void;
|
||||
toString(): string;
|
||||
}
|
||||
|
||||
interface CompressorOptions extends PCMTransformerOptions {
|
||||
threshold?: number;
|
||||
ratio?: number;
|
||||
attack?: number;
|
||||
release?: number;
|
||||
makeupGain?: number;
|
||||
kneeWidth?: number;
|
||||
}
|
||||
interface CompressorParameters {
|
||||
threshold: number;
|
||||
ratio: number;
|
||||
attack: number;
|
||||
release: number;
|
||||
makeupGain: number;
|
||||
kneeWidth: number;
|
||||
}
|
||||
declare class CompressorTransformer extends PCMTransformer {
|
||||
private threshold;
|
||||
private ratio;
|
||||
private attack;
|
||||
private release;
|
||||
private makeupGain;
|
||||
private kneeWidth;
|
||||
private envelope;
|
||||
private gainReduction;
|
||||
private previousGainReduction;
|
||||
constructor(options?: CompressorOptions);
|
||||
private linearToDb;
|
||||
private dbToLinear;
|
||||
setThreshold(db: number): void;
|
||||
setRatio(ratio: number): void;
|
||||
setAttack(ms: number): void;
|
||||
setRelease(ms: number): void;
|
||||
setMakeupGain(db: number): void;
|
||||
setKneeWidth(db: number): void;
|
||||
setCompressor(options: Partial<CompressorParameters>): CompressorParameters;
|
||||
getParameters(): CompressorParameters;
|
||||
private computeGainReduction;
|
||||
private processSample;
|
||||
_transform(chunk: Buffer, encoding: BufferEncoding, callback: (error?: Error | null, data?: Buffer) => void): void;
|
||||
}
|
||||
|
||||
interface PCMSeekerOptions extends PCMTransformerOptions {
|
||||
totalDuration: number;
|
||||
channels: number;
|
||||
seekTarget?: number | null;
|
||||
}
|
||||
interface SeekerParameters {
|
||||
currentPosition: number;
|
||||
seekTarget: number | null;
|
||||
totalDuration: number;
|
||||
}
|
||||
interface SeekEvent {
|
||||
position: number;
|
||||
sample: number;
|
||||
bytePosition: number;
|
||||
}
|
||||
declare class PCMSeekerTransformer extends PCMTransformer {
|
||||
private totalDuration;
|
||||
private readonly channels;
|
||||
private bytesPerFrame;
|
||||
private currentPosition;
|
||||
private seekTarget;
|
||||
private buffer;
|
||||
readonly events: EventEmitter<[never]>;
|
||||
constructor(options?: PCMSeekerOptions);
|
||||
getParameters(): SeekerParameters;
|
||||
private updateDependentValues;
|
||||
/**
|
||||
* Calculate byte position from sample position
|
||||
* @param samplePosition Position in samples
|
||||
* @returns Position in bytes
|
||||
*/
|
||||
private sampleToBytePosition;
|
||||
setTotalDuration(duration: number): void;
|
||||
setSampleRate(rate: number): void;
|
||||
/**
|
||||
* Seek to a specific position in milliseconds
|
||||
* @param ms Position in milliseconds (negative values seek from end)
|
||||
* @returns Actual position in milliseconds after seeking
|
||||
*/
|
||||
seek(ms: number): number;
|
||||
getPosition(): number;
|
||||
private handleSeek;
|
||||
_transform(chunk: Buffer, encoding: BufferEncoding, callback: (error?: Error | null, data?: Buffer) => void): void;
|
||||
_flush(callback: (error?: Error | null, data?: Buffer) => void): void;
|
||||
}
|
||||
|
||||
interface ReverbOptions extends PCMTransformerOptions {
|
||||
roomSize?: number;
|
||||
damping?: number;
|
||||
wetLevel?: number;
|
||||
dryLevel?: number;
|
||||
}
|
||||
interface ReverbParameters {
|
||||
roomSize: number;
|
||||
damping: number;
|
||||
wetLevel: number;
|
||||
dryLevel: number;
|
||||
}
|
||||
declare class ReverbTransformer extends PCMTransformer {
|
||||
private roomSize;
|
||||
private damping;
|
||||
private wetLevel;
|
||||
private dryLevel;
|
||||
private readonly delayLines;
|
||||
private readonly delayLineLength;
|
||||
private delayIndices;
|
||||
private readonly numDelayLines;
|
||||
private readonly feedback;
|
||||
constructor(options?: ReverbOptions);
|
||||
setRoomSize(size: number): void;
|
||||
setDamping(damping: number): void;
|
||||
setWetLevel(level: number): void;
|
||||
setDryLevel(level: number): void;
|
||||
setReverb(options: Partial<ReverbParameters>): ReverbParameters;
|
||||
getParameters(): ReverbParameters;
|
||||
private processSample;
|
||||
_transform(chunk: Buffer, encoding: BufferEncoding, callback: (error?: Error | null, data?: Buffer) => void): void;
|
||||
}
|
||||
|
||||
interface DSPFiltersPreset {
|
||||
equalizer?: EqualizerStreamOptions;
|
||||
dsp?: PCMFiltererOptions;
|
||||
biquad?: BiquadStreamOptions;
|
||||
volume?: VolumeTransformerOptions;
|
||||
resampler?: PCMResamplerOptions;
|
||||
compressor?: CompressorOptions;
|
||||
seeker?: PCMSeekerOptions;
|
||||
reverb?: ReverbOptions;
|
||||
}
|
||||
declare class FiltersChain {
|
||||
presets: DSPFiltersPreset;
|
||||
equalizer: EqualizerStream | null;
|
||||
filters: AudioFilter | null;
|
||||
biquad: BiquadStream | null;
|
||||
volume: VolumeTransformer | null;
|
||||
resampler: PCMResampler | null;
|
||||
compressor: CompressorTransformer | null;
|
||||
seeker: PCMSeekerTransformer | null;
|
||||
reverb: ReverbTransformer | null;
|
||||
destination: Readable | null;
|
||||
source: Readable | null;
|
||||
onUpdate: () => unknown;
|
||||
onError: (err: Error) => unknown;
|
||||
constructor(presets?: DSPFiltersPreset);
|
||||
create(src: Readable, presets?: DSPFiltersPreset): Readable;
|
||||
destroy(): void;
|
||||
}
|
||||
|
||||
declare const version: string;
|
||||
|
||||
export { AF_NIGHTCORE_RATE, AF_VAPORWAVE_RATE, AudioFilter, AudioFilters, BASS_EQ_BANDS, BiquadFilter, type BiquadFilterUpdateData, type BiquadFilters, type BiquadSetFilterProps, BiquadStream, type BiquadStreamOptions, ChannelProcessor, type ChannelProcessorInput, Coefficients, type CommonResamplerFilterPreset, type CompressorOptions, type CompressorParameters, CompressorTransformer, type DSPFiltersPreset, Equalizer, type EqualizerBand, EqualizerCoefficients, EqualizerConfiguration, EqualizerStream, type EqualizerStreamOptions, FilterType, FiltersChain, Frequency, type MSTStrategy, MonoStereoTransformer, type MonoStereoTransformerOptions, index as PCMAudioTransformer, type PCMFiltererOptions, type PCMFilters, PCMResampler, type PCMResamplerOptions, type PCMSeekerOptions, PCMSeekerTransformer, PCMTransformer, type PCMTransformerOptions, type PCMType, Q_BUTTERWORTH, type ReadIntCallback, type ResampleParameters, type ReverbOptions, type ReverbParameters, ReverbTransformer, type SeekEvent, type SeekerParameters, VolumeTransformer, type VolumeTransformerOptions, type WriteIntCallback, version };
|
||||
|
|
@ -0,0 +1,482 @@
|
|||
import { TransformOptions, Transform, TransformCallback, Readable } from 'stream';
|
||||
import { EventEmitter } from 'events';
|
||||
|
||||
declare const FilterType: {
|
||||
readonly SinglePoleLowPassApprox: 0;
|
||||
readonly SinglePoleLowPass: 1;
|
||||
readonly LowPass: 2;
|
||||
readonly HighPass: 3;
|
||||
readonly BandPass: 4;
|
||||
readonly Notch: 5;
|
||||
readonly AllPass: 6;
|
||||
readonly LowShelf: 7;
|
||||
readonly HighShelf: 8;
|
||||
readonly PeakingEQ: 9;
|
||||
};
|
||||
type BiquadFilters = keyof typeof FilterType | (typeof FilterType)[keyof typeof FilterType];
|
||||
interface CoefficientsInit {
|
||||
a1: number;
|
||||
a2: number;
|
||||
b0: number;
|
||||
b1: number;
|
||||
b2: number;
|
||||
}
|
||||
declare const Q_BUTTERWORTH: number;
|
||||
declare class Coefficients {
|
||||
a1: number;
|
||||
a2: number;
|
||||
b0: number;
|
||||
b1: number;
|
||||
b2: number;
|
||||
constructor(data?: CoefficientsInit);
|
||||
static from(filter: BiquadFilters, samplingFreq: number, cutoffFreq: number, Q: number, dbGain?: number): Coefficients;
|
||||
}
|
||||
|
||||
interface BiquadSetFilterProps {
|
||||
f0: number;
|
||||
fs: number;
|
||||
Q: number;
|
||||
gain?: number;
|
||||
}
|
||||
declare class BiquadFilter {
|
||||
coefficients: Coefficients;
|
||||
x1: number;
|
||||
x2: number;
|
||||
y1: number;
|
||||
y2: number;
|
||||
s1: number;
|
||||
s2: number;
|
||||
constructor(coefficients: Coefficients);
|
||||
setFilter(filter: BiquadFilters, options: BiquadSetFilterProps): void;
|
||||
update(coefficients: Coefficients): void;
|
||||
replace(coefficients: Coefficients): void;
|
||||
reset(): void;
|
||||
run(input: number): number;
|
||||
runTransposed(input: number): number;
|
||||
}
|
||||
|
||||
declare class Frequency {
|
||||
private __val;
|
||||
constructor(__val: number);
|
||||
khz(): number;
|
||||
mhz(): number;
|
||||
hz(): number;
|
||||
dt(): number;
|
||||
valueOf(): number;
|
||||
toString(): string;
|
||||
toJSON(): string;
|
||||
}
|
||||
|
||||
type PCMType = `s${16 | 32}${'l' | 'b'}e`;
|
||||
interface PCMTransformerOptions extends TransformOptions {
|
||||
type?: PCMType;
|
||||
disabled?: boolean;
|
||||
sampleRate?: number;
|
||||
}
|
||||
declare class PCMTransformer extends Transform {
|
||||
readonly type: PCMType;
|
||||
bits: number;
|
||||
bytes: number;
|
||||
extremum: number;
|
||||
disabled: boolean;
|
||||
sampleRate: number;
|
||||
onUpdate: () => void;
|
||||
constructor(options?: PCMTransformerOptions);
|
||||
disable(): void;
|
||||
enable(): void;
|
||||
toggle(): boolean;
|
||||
_readInt(buffer: Buffer, index: number): number;
|
||||
_writeInt(buffer: Buffer, int: number, index: number): number;
|
||||
clamp(val: number, max?: number, min?: number): number;
|
||||
setSampleRate(rate: number): void;
|
||||
}
|
||||
|
||||
interface BiquadStreamOptions extends PCMTransformerOptions {
|
||||
filter?: BiquadFilters;
|
||||
Q?: number;
|
||||
cutoff?: number;
|
||||
gain?: number;
|
||||
}
|
||||
interface BiquadFilterUpdateData {
|
||||
filter?: BiquadFilters;
|
||||
Q?: number;
|
||||
cutoff?: number;
|
||||
gain?: number;
|
||||
}
|
||||
declare class BiquadStream extends PCMTransformer {
|
||||
biquad: BiquadFilter;
|
||||
cutoff: number;
|
||||
gain: number;
|
||||
biquadFilter: BiquadFilters;
|
||||
Q: number;
|
||||
constructor(options?: BiquadStreamOptions);
|
||||
get filters(): BiquadFilters;
|
||||
set filters(f: BiquadFilters);
|
||||
getFilterName(): BiquadFilters | null;
|
||||
update(options: BiquadFilterUpdateData): void;
|
||||
setFilter(filter: BiquadFilters): void;
|
||||
setQ(Q: number): void;
|
||||
setCutoff(f0: number): void;
|
||||
setGain(dB: number): void;
|
||||
_transform(chunk: Buffer, encoding: BufferEncoding, callback: TransformCallback): void;
|
||||
}
|
||||
|
||||
type ReadIntCallback = (buffer: Buffer, index: number) => number;
|
||||
type WriteIntCallback = (buffer: Buffer, int: number, index: number) => number;
|
||||
declare class ChannelProcessor {
|
||||
history: number[];
|
||||
bandMultipliers: number[];
|
||||
current: number;
|
||||
m1: number;
|
||||
m2: number;
|
||||
constructor(bandMultipliers: number[]);
|
||||
processInt(int: number): number;
|
||||
process(samples: Buffer, extremum?: number, bytes?: number, readInt?: ReadIntCallback, writeInt?: WriteIntCallback): Buffer;
|
||||
step(): void;
|
||||
reset(): void;
|
||||
}
|
||||
|
||||
declare class EqualizerCoefficients {
|
||||
beta: number;
|
||||
alpha: number;
|
||||
gamma: number;
|
||||
constructor(beta: number, alpha: number, gamma: number);
|
||||
setBeta(v: number): void;
|
||||
setAlpha(v: number): void;
|
||||
setGamma(v: number): void;
|
||||
toJSON(): {
|
||||
alpha: number;
|
||||
beta: number;
|
||||
gamma: number;
|
||||
};
|
||||
}
|
||||
|
||||
declare class EqualizerConfiguration {
|
||||
bandMultipliers: number[];
|
||||
constructor(bandMultipliers: number[]);
|
||||
setGain(band: number, value: number): void;
|
||||
getGain(band: number): number;
|
||||
isValidBand(band: number): boolean;
|
||||
}
|
||||
|
||||
interface ChannelProcessorInput {
|
||||
data: Buffer;
|
||||
readInt?: ReadIntCallback;
|
||||
writeInt?: WriteIntCallback;
|
||||
extremum?: number;
|
||||
bytes?: number;
|
||||
}
|
||||
declare class Equalizer extends EqualizerConfiguration {
|
||||
static BAND_COUNT: 15;
|
||||
static SAMPLE_RATE: 48000;
|
||||
static Coefficients48000: EqualizerCoefficients[];
|
||||
channels: ChannelProcessor[];
|
||||
channelCount: number;
|
||||
constructor(channelCount: number, bandMultipliers: number[]);
|
||||
createChannelProcessor(): ChannelProcessor[];
|
||||
process(input: ChannelProcessorInput[]): Buffer[];
|
||||
}
|
||||
|
||||
interface EqualizerStreamOptions extends PCMTransformerOptions {
|
||||
bandMultiplier?: EqualizerBand[];
|
||||
channels?: number;
|
||||
}
|
||||
interface EqualizerBand {
|
||||
band: number;
|
||||
gain: number;
|
||||
}
|
||||
declare class EqualizerStream extends PCMTransformer {
|
||||
bandMultipliers: number[];
|
||||
equalizer: Equalizer;
|
||||
constructor(options?: EqualizerStreamOptions);
|
||||
_processBands(multiplier: EqualizerBand[]): void;
|
||||
_transform(chunk: Buffer, encoding: BufferEncoding, callback: TransformCallback): void;
|
||||
getEQ(): EqualizerBand[];
|
||||
setEQ(bands: EqualizerBand[]): void;
|
||||
resetEQ(): void;
|
||||
}
|
||||
|
||||
type MSTStrategy = 'm2s' | 's2m';
|
||||
interface MonoStereoTransformerOptions extends PCMTransformerOptions {
|
||||
strategy: MSTStrategy;
|
||||
}
|
||||
declare class MonoStereoTransformer extends PCMTransformer {
|
||||
strategy: MSTStrategy;
|
||||
constructor(options?: MonoStereoTransformerOptions);
|
||||
setStrategy(strategy: MSTStrategy): void;
|
||||
_transform(chunk: Buffer, encoding: BufferEncoding, callback: TransformCallback): void;
|
||||
toStereo(sample: Buffer, len: number): Buffer;
|
||||
toMono(sample: Buffer, len: number): Buffer;
|
||||
}
|
||||
|
||||
interface AFBiquadConfig {
|
||||
biquad: BiquadFilter;
|
||||
sample: number;
|
||||
cutoff: number;
|
||||
gain: number;
|
||||
filter: BiquadFilters;
|
||||
coefficient: Coefficients;
|
||||
Q: number;
|
||||
}
|
||||
declare function applyBiquad(filterer: BiquadFilter, int: number): number;
|
||||
|
||||
interface AFPulsatorConfig {
|
||||
hz: number;
|
||||
x: number;
|
||||
dI: number;
|
||||
}
|
||||
interface AFTremoloConfig {
|
||||
phase: number;
|
||||
depth: number;
|
||||
frequency: number;
|
||||
}
|
||||
type AFVibratoConfig = AFTremoloConfig;
|
||||
type LR = 0 | 1;
|
||||
declare function applyPulsator(config: AFPulsatorConfig, int: number, channel: LR): number;
|
||||
declare function applyTremolo(config: AFTremoloConfig, int: number, sampleRate: number): number;
|
||||
declare function applyVibrato(config: AFVibratoConfig, int: number, sampleRate: number): number;
|
||||
declare function applyVolume(vol: number, int: number): number;
|
||||
|
||||
declare function applyEqualization(eq: Equalizer, int: number): number;
|
||||
|
||||
type index_AFBiquadConfig = AFBiquadConfig;
|
||||
type index_AFPulsatorConfig = AFPulsatorConfig;
|
||||
type index_AFTremoloConfig = AFTremoloConfig;
|
||||
type index_AFVibratoConfig = AFVibratoConfig;
|
||||
type index_LR = LR;
|
||||
declare const index_applyBiquad: typeof applyBiquad;
|
||||
declare const index_applyEqualization: typeof applyEqualization;
|
||||
declare const index_applyPulsator: typeof applyPulsator;
|
||||
declare const index_applyTremolo: typeof applyTremolo;
|
||||
declare const index_applyVibrato: typeof applyVibrato;
|
||||
declare const index_applyVolume: typeof applyVolume;
|
||||
declare namespace index {
|
||||
export { type index_AFBiquadConfig as AFBiquadConfig, type index_AFPulsatorConfig as AFPulsatorConfig, type index_AFTremoloConfig as AFTremoloConfig, type index_AFVibratoConfig as AFVibratoConfig, type index_LR as LR, index_applyBiquad as applyBiquad, index_applyEqualization as applyEqualization, index_applyPulsator as applyPulsator, index_applyTremolo as applyTremolo, index_applyVibrato as applyVibrato, index_applyVolume as applyVolume };
|
||||
}
|
||||
|
||||
declare const AudioFilters: {
|
||||
readonly '8D': "8D";
|
||||
readonly Tremolo: "Tremolo";
|
||||
readonly Vibrato: "Vibrato";
|
||||
};
|
||||
type PCMFilters = keyof typeof AudioFilters;
|
||||
interface PCMFiltererOptions extends PCMTransformerOptions {
|
||||
filters?: PCMFilters[];
|
||||
}
|
||||
declare const AF_NIGHTCORE_RATE: 1.3;
|
||||
declare const AF_VAPORWAVE_RATE: 0.8;
|
||||
declare const BASS_EQ_BANDS: EqualizerBand[];
|
||||
declare class AudioFilter extends PCMTransformer {
|
||||
filters: PCMFilters[];
|
||||
targetSampleRate: number;
|
||||
pulsatorConfig: AFPulsatorConfig;
|
||||
tremoloConfig: AFTremoloConfig;
|
||||
vibratoConfig: AFVibratoConfig;
|
||||
constructor(options?: PCMFiltererOptions);
|
||||
setTargetSampleRate(rate: number): void;
|
||||
setPulsator(hz: number): void;
|
||||
get pulsator(): number;
|
||||
setTremolo({ depth, frequency, phase, }: Partial<AFTremoloConfig>): void;
|
||||
setVibrato({ depth, frequency, phase, }: Partial<AFVibratoConfig>): void;
|
||||
get tremolo(): AFTremoloConfig;
|
||||
setFilters(filters: PCMFilters[]): boolean;
|
||||
_transform(chunk: Buffer, encoding: BufferEncoding, callback: TransformCallback): void;
|
||||
get currentSampleRate(): number;
|
||||
applyFilters(byte: number, channel: LR): number;
|
||||
}
|
||||
|
||||
interface PCMResamplerOptions extends PCMTransformerOptions {
|
||||
inputSampleRate: number;
|
||||
targetSampleRate: number;
|
||||
channels?: number;
|
||||
}
|
||||
interface ResampleParameters {
|
||||
currentFilter: CommonResamplerFilterPreset | null;
|
||||
inputSampleRate: number;
|
||||
channels: number;
|
||||
sampleRate: number;
|
||||
}
|
||||
type CommonResamplerFilterPreset = 'nightcore' | 'vaporwave';
|
||||
declare class PCMResampler extends PCMTransformer {
|
||||
private readonly inputSampleRate;
|
||||
private readonly channels;
|
||||
private buffer;
|
||||
currentFilter: CommonResamplerFilterPreset | null;
|
||||
constructor(options?: PCMResamplerOptions);
|
||||
setFilter(filter: CommonResamplerFilterPreset | null): void;
|
||||
getParameters(): ResampleParameters;
|
||||
toggleFilter(filter: CommonResamplerFilterPreset): boolean;
|
||||
getRatio(): number;
|
||||
private resample;
|
||||
_transform(chunk: Buffer, encoding: BufferEncoding, callback: (error?: Error | null, data?: Buffer) => void): void;
|
||||
_flush(callback: (error?: Error | null, data?: Buffer) => void): void;
|
||||
setSampleRate(rate: number): void;
|
||||
}
|
||||
|
||||
interface VolumeTransformerOptions extends PCMTransformerOptions {
|
||||
volume?: number;
|
||||
}
|
||||
declare class VolumeTransformer extends PCMTransformer {
|
||||
private _volume;
|
||||
constructor(options?: VolumeTransformerOptions);
|
||||
get volumeApprox(): number;
|
||||
get volume(): number;
|
||||
set volume(volume: number);
|
||||
setVolume(volume: number): boolean;
|
||||
_transform(chunk: Buffer, encoding: BufferEncoding, callback: TransformCallback): void;
|
||||
toString(): string;
|
||||
}
|
||||
|
||||
interface CompressorOptions extends PCMTransformerOptions {
|
||||
threshold?: number;
|
||||
ratio?: number;
|
||||
attack?: number;
|
||||
release?: number;
|
||||
makeupGain?: number;
|
||||
kneeWidth?: number;
|
||||
}
|
||||
interface CompressorParameters {
|
||||
threshold: number;
|
||||
ratio: number;
|
||||
attack: number;
|
||||
release: number;
|
||||
makeupGain: number;
|
||||
kneeWidth: number;
|
||||
}
|
||||
declare class CompressorTransformer extends PCMTransformer {
|
||||
private threshold;
|
||||
private ratio;
|
||||
private attack;
|
||||
private release;
|
||||
private makeupGain;
|
||||
private kneeWidth;
|
||||
private envelope;
|
||||
private gainReduction;
|
||||
private previousGainReduction;
|
||||
constructor(options?: CompressorOptions);
|
||||
private linearToDb;
|
||||
private dbToLinear;
|
||||
setThreshold(db: number): void;
|
||||
setRatio(ratio: number): void;
|
||||
setAttack(ms: number): void;
|
||||
setRelease(ms: number): void;
|
||||
setMakeupGain(db: number): void;
|
||||
setKneeWidth(db: number): void;
|
||||
setCompressor(options: Partial<CompressorParameters>): CompressorParameters;
|
||||
getParameters(): CompressorParameters;
|
||||
private computeGainReduction;
|
||||
private processSample;
|
||||
_transform(chunk: Buffer, encoding: BufferEncoding, callback: (error?: Error | null, data?: Buffer) => void): void;
|
||||
}
|
||||
|
||||
interface PCMSeekerOptions extends PCMTransformerOptions {
|
||||
totalDuration: number;
|
||||
channels: number;
|
||||
seekTarget?: number | null;
|
||||
}
|
||||
interface SeekerParameters {
|
||||
currentPosition: number;
|
||||
seekTarget: number | null;
|
||||
totalDuration: number;
|
||||
}
|
||||
interface SeekEvent {
|
||||
position: number;
|
||||
sample: number;
|
||||
bytePosition: number;
|
||||
}
|
||||
declare class PCMSeekerTransformer extends PCMTransformer {
|
||||
private totalDuration;
|
||||
private readonly channels;
|
||||
private bytesPerFrame;
|
||||
private currentPosition;
|
||||
private seekTarget;
|
||||
private buffer;
|
||||
readonly events: EventEmitter<[never]>;
|
||||
constructor(options?: PCMSeekerOptions);
|
||||
getParameters(): SeekerParameters;
|
||||
private updateDependentValues;
|
||||
/**
|
||||
* Calculate byte position from sample position
|
||||
* @param samplePosition Position in samples
|
||||
* @returns Position in bytes
|
||||
*/
|
||||
private sampleToBytePosition;
|
||||
setTotalDuration(duration: number): void;
|
||||
setSampleRate(rate: number): void;
|
||||
/**
|
||||
* Seek to a specific position in milliseconds
|
||||
* @param ms Position in milliseconds (negative values seek from end)
|
||||
* @returns Actual position in milliseconds after seeking
|
||||
*/
|
||||
seek(ms: number): number;
|
||||
getPosition(): number;
|
||||
private handleSeek;
|
||||
_transform(chunk: Buffer, encoding: BufferEncoding, callback: (error?: Error | null, data?: Buffer) => void): void;
|
||||
_flush(callback: (error?: Error | null, data?: Buffer) => void): void;
|
||||
}
|
||||
|
||||
interface ReverbOptions extends PCMTransformerOptions {
|
||||
roomSize?: number;
|
||||
damping?: number;
|
||||
wetLevel?: number;
|
||||
dryLevel?: number;
|
||||
}
|
||||
interface ReverbParameters {
|
||||
roomSize: number;
|
||||
damping: number;
|
||||
wetLevel: number;
|
||||
dryLevel: number;
|
||||
}
|
||||
declare class ReverbTransformer extends PCMTransformer {
|
||||
private roomSize;
|
||||
private damping;
|
||||
private wetLevel;
|
||||
private dryLevel;
|
||||
private readonly delayLines;
|
||||
private readonly delayLineLength;
|
||||
private delayIndices;
|
||||
private readonly numDelayLines;
|
||||
private readonly feedback;
|
||||
constructor(options?: ReverbOptions);
|
||||
setRoomSize(size: number): void;
|
||||
setDamping(damping: number): void;
|
||||
setWetLevel(level: number): void;
|
||||
setDryLevel(level: number): void;
|
||||
setReverb(options: Partial<ReverbParameters>): ReverbParameters;
|
||||
getParameters(): ReverbParameters;
|
||||
private processSample;
|
||||
_transform(chunk: Buffer, encoding: BufferEncoding, callback: (error?: Error | null, data?: Buffer) => void): void;
|
||||
}
|
||||
|
||||
interface DSPFiltersPreset {
|
||||
equalizer?: EqualizerStreamOptions;
|
||||
dsp?: PCMFiltererOptions;
|
||||
biquad?: BiquadStreamOptions;
|
||||
volume?: VolumeTransformerOptions;
|
||||
resampler?: PCMResamplerOptions;
|
||||
compressor?: CompressorOptions;
|
||||
seeker?: PCMSeekerOptions;
|
||||
reverb?: ReverbOptions;
|
||||
}
|
||||
declare class FiltersChain {
|
||||
presets: DSPFiltersPreset;
|
||||
equalizer: EqualizerStream | null;
|
||||
filters: AudioFilter | null;
|
||||
biquad: BiquadStream | null;
|
||||
volume: VolumeTransformer | null;
|
||||
resampler: PCMResampler | null;
|
||||
compressor: CompressorTransformer | null;
|
||||
seeker: PCMSeekerTransformer | null;
|
||||
reverb: ReverbTransformer | null;
|
||||
destination: Readable | null;
|
||||
source: Readable | null;
|
||||
onUpdate: () => unknown;
|
||||
onError: (err: Error) => unknown;
|
||||
constructor(presets?: DSPFiltersPreset);
|
||||
create(src: Readable, presets?: DSPFiltersPreset): Readable;
|
||||
destroy(): void;
|
||||
}
|
||||
|
||||
declare const version: string;
|
||||
|
||||
export { AF_NIGHTCORE_RATE, AF_VAPORWAVE_RATE, AudioFilter, AudioFilters, BASS_EQ_BANDS, BiquadFilter, type BiquadFilterUpdateData, type BiquadFilters, type BiquadSetFilterProps, BiquadStream, type BiquadStreamOptions, ChannelProcessor, type ChannelProcessorInput, Coefficients, type CommonResamplerFilterPreset, type CompressorOptions, type CompressorParameters, CompressorTransformer, type DSPFiltersPreset, Equalizer, type EqualizerBand, EqualizerCoefficients, EqualizerConfiguration, EqualizerStream, type EqualizerStreamOptions, FilterType, FiltersChain, Frequency, type MSTStrategy, MonoStereoTransformer, type MonoStereoTransformerOptions, index as PCMAudioTransformer, type PCMFiltererOptions, type PCMFilters, PCMResampler, type PCMResamplerOptions, type PCMSeekerOptions, PCMSeekerTransformer, PCMTransformer, type PCMTransformerOptions, type PCMType, Q_BUTTERWORTH, type ReadIntCallback, type ResampleParameters, type ReverbOptions, type ReverbParameters, ReverbTransformer, type SeekEvent, type SeekerParameters, VolumeTransformer, type VolumeTransformerOptions, type WriteIntCallback, version };
|
||||
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
|
|
@ -0,0 +1,59 @@
|
|||
{
|
||||
"name": "@discord-player/equalizer",
|
||||
"version": "7.2.0",
|
||||
"description": "PCM Equalizer implementation for Discord Player",
|
||||
"keywords": [
|
||||
"discord-player",
|
||||
"pcm",
|
||||
"equalizer",
|
||||
"music",
|
||||
"bot",
|
||||
"discord.js",
|
||||
"javascript",
|
||||
"voip",
|
||||
"lavalink",
|
||||
"lavaplayer"
|
||||
],
|
||||
"author": "Twilight <hello@twlite.dev>",
|
||||
"homepage": "https://discord-player.js.org",
|
||||
"license": "MIT",
|
||||
"main": "dist/index.js",
|
||||
"module": "dist/index.mjs",
|
||||
"types": "dist/index.d.ts",
|
||||
"publishConfig": {
|
||||
"access": "public"
|
||||
},
|
||||
"directories": {
|
||||
"dist": "dist",
|
||||
"src": "src"
|
||||
},
|
||||
"files": [
|
||||
"dist"
|
||||
],
|
||||
"repository": {
|
||||
"type": "git",
|
||||
"url": "git+https://github.com/Androz2091/discord-player.git"
|
||||
},
|
||||
"scripts": {
|
||||
"build": "tsup",
|
||||
"build:check": "tsc --noEmit",
|
||||
"test": "vitest",
|
||||
"coverage": "vitest run --coverage"
|
||||
},
|
||||
"bugs": {
|
||||
"url": "https://github.com/Androz2091/discord-player/issues"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@discord-player/tsconfig": "^7.2.0",
|
||||
"tsup": "^8.3.5",
|
||||
"typescript": "^5.2.2",
|
||||
"vitest": "^0.34.6"
|
||||
},
|
||||
"typedoc": {
|
||||
"entryPoint": "./src/index.ts",
|
||||
"readmeFile": "./README.md",
|
||||
"tsconfig": "./tsconfig.json",
|
||||
"excludeExternals": true,
|
||||
"excludePrivate": true
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,21 @@
|
|||
MIT License
|
||||
|
||||
Copyright (c) 2020 Androz2091
|
||||
|
||||
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.
|
||||
|
|
@ -0,0 +1,22 @@
|
|||
# Extractors
|
||||
|
||||
Extractors for `discord-player`.
|
||||
|
||||
# Example
|
||||
|
||||
```js
|
||||
const { SoundCloudExtractor } = require('@discord-player/extractor');
|
||||
const player = useMainPlayer();
|
||||
|
||||
// enables soundcloud extractor
|
||||
player.extractors.register(SoundCloudExtractor);
|
||||
```
|
||||
|
||||
# Available Extractors
|
||||
|
||||
- Attachment (Remote, Local)
|
||||
- Reverbnation
|
||||
- SoundCloud
|
||||
- Vimeo
|
||||
- Spotify
|
||||
- Apple Music
|
||||
|
|
@ -0,0 +1,277 @@
|
|||
import { BaseExtractor, SearchQueryType, Track, GuildQueueHistory, ExtractorInfo, ExtractorSearchContext, ExtractorStreamable } from 'discord-player';
|
||||
import * as SoundCloud from 'soundcloud.ts';
|
||||
import * as fs from 'fs';
|
||||
import { Readable } from 'stream';
|
||||
import { HTMLElement } from 'node-html-parser';
|
||||
import { RequestOptions } from 'http';
|
||||
|
||||
interface SoundCloudExtractorInit {
|
||||
clientId?: string;
|
||||
oauthToken?: string;
|
||||
proxy?: string;
|
||||
}
|
||||
declare class SoundCloudExtractor extends BaseExtractor<SoundCloudExtractorInit> {
|
||||
static identifier: "com.discord-player.soundcloudextractor";
|
||||
static instance: SoundCloudExtractor | null;
|
||||
internal: SoundCloud.Soundcloud;
|
||||
activate(): Promise<void>;
|
||||
deactivate(): Promise<void>;
|
||||
validate(query: string, type?: SearchQueryType | null | undefined): Promise<boolean>;
|
||||
getRelatedTracks(track: Track, history: GuildQueueHistory): Promise<ExtractorInfo>;
|
||||
handle(query: string, context: ExtractorSearchContext): Promise<ExtractorInfo>;
|
||||
emptyResponse(): ExtractorInfo;
|
||||
stream(info: Track): Promise<string>;
|
||||
bridge(track: Track, sourceExtractor: BaseExtractor | null): Promise<ExtractorStreamable | null>;
|
||||
}
|
||||
|
||||
declare function lyricsExtractor(): void;
|
||||
|
||||
declare class VimeoExtractor extends BaseExtractor {
|
||||
static identifier: "com.discord-player.vimeoextractor";
|
||||
validate(query: string, type?: SearchQueryType | null | undefined): Promise<boolean>;
|
||||
getRelatedTracks(track: Track): Promise<ExtractorInfo>;
|
||||
handle(query: string, context: ExtractorSearchContext): Promise<ExtractorInfo>;
|
||||
emptyResponse(): ExtractorInfo;
|
||||
stream(info: Track): Promise<string>;
|
||||
}
|
||||
|
||||
declare class ReverbnationExtractor extends BaseExtractor {
|
||||
static identifier: "com.discord-player.reverbnationextractor";
|
||||
validate(query: string, type?: SearchQueryType | null | undefined): Promise<boolean>;
|
||||
getRelatedTracks(track: Track): Promise<ExtractorInfo>;
|
||||
handle(query: string, context: ExtractorSearchContext): Promise<ExtractorInfo>;
|
||||
emptyResponse(): ExtractorInfo;
|
||||
stream(info: Track): Promise<string>;
|
||||
}
|
||||
|
||||
declare class AttachmentExtractor extends BaseExtractor {
|
||||
static identifier: "com.discord-player.attachmentextractor";
|
||||
priority: number;
|
||||
validate(query: string, type?: SearchQueryType | null | undefined): Promise<boolean>;
|
||||
getRelatedTracks(track: Track): Promise<ExtractorInfo>;
|
||||
handle(query: string, context: ExtractorSearchContext): Promise<ExtractorInfo>;
|
||||
emptyResponse(): ExtractorInfo;
|
||||
stream(info: Track): Promise<string | {
|
||||
stream: fs.ReadStream;
|
||||
$fmt: string;
|
||||
}>;
|
||||
}
|
||||
|
||||
interface AppleMusicExtractorInit {
|
||||
createStream?: (ext: AppleMusicExtractor, url: string, track: Track) => Promise<Readable | string>;
|
||||
}
|
||||
declare class AppleMusicExtractor extends BaseExtractor<AppleMusicExtractorInit> {
|
||||
static identifier: "com.discord-player.applemusicextractor";
|
||||
private _stream;
|
||||
activate(): Promise<void>;
|
||||
deactivate(): Promise<void>;
|
||||
validate(query: string, type?: SearchQueryType | null | undefined): Promise<boolean>;
|
||||
getRelatedTracks(track: Track, history: GuildQueueHistory): Promise<ExtractorInfo>;
|
||||
handle(query: string, context: ExtractorSearchContext): Promise<ExtractorInfo>;
|
||||
stream(info: Track): Promise<ExtractorStreamable>;
|
||||
}
|
||||
|
||||
declare class AppleMusic {
|
||||
constructor();
|
||||
static search(query: string): Promise<any>;
|
||||
static getSongInfoFallback(res: HTMLElement, name: string, id: string, link: string): Promise<{
|
||||
id: string;
|
||||
duration: string;
|
||||
title: string;
|
||||
url: string;
|
||||
thumbnail: string;
|
||||
artist: {
|
||||
name: string;
|
||||
};
|
||||
} | null>;
|
||||
static getSongInfo(link: string): Promise<{
|
||||
id: any;
|
||||
duration: any;
|
||||
title: any;
|
||||
url: any;
|
||||
thumbnail: string;
|
||||
artist: {
|
||||
name: any;
|
||||
};
|
||||
} | null>;
|
||||
static getPlaylistInfo(link: string): Promise<{
|
||||
id: any;
|
||||
title: any;
|
||||
thumbnail: string;
|
||||
artist: {
|
||||
name: any;
|
||||
};
|
||||
url: any;
|
||||
tracks: any;
|
||||
} | null>;
|
||||
static getAlbumInfo(link: string): Promise<{
|
||||
id: any;
|
||||
title: any;
|
||||
thumbnail: string;
|
||||
artist: {
|
||||
name: any;
|
||||
};
|
||||
url: any;
|
||||
tracks: any;
|
||||
} | null>;
|
||||
}
|
||||
|
||||
declare class Vimeo {
|
||||
constructor();
|
||||
/**
|
||||
* @typedef {Readable} Readable
|
||||
*/
|
||||
/**
|
||||
* Downloads from vimeo
|
||||
* @param {number} id Vimeo video id
|
||||
* @returns {Promise<Readable>}
|
||||
*/
|
||||
static download(id: number | string): Promise<Readable>;
|
||||
/**
|
||||
* Returns video info
|
||||
* @param {number} id Video id
|
||||
*/
|
||||
static getInfo(id: number | string): Promise<VimeoInfo | null>;
|
||||
}
|
||||
interface VimeoInfo {
|
||||
id: number;
|
||||
duration: number;
|
||||
title: string;
|
||||
url: string;
|
||||
thumbnail: string;
|
||||
stream: string;
|
||||
author: {
|
||||
id: number;
|
||||
name: string;
|
||||
url: string;
|
||||
avatar: string;
|
||||
};
|
||||
}
|
||||
|
||||
declare function downloadStream(url: string, opts?: RequestOptions): Promise<Readable>;
|
||||
|
||||
interface SP_ACCESS_TOKEN {
|
||||
token: string;
|
||||
expiresAfter: number;
|
||||
type: 'Bearer';
|
||||
}
|
||||
declare class SpotifyAPI {
|
||||
credentials: {
|
||||
clientId: string | null;
|
||||
clientSecret: string | null;
|
||||
};
|
||||
accessToken: SP_ACCESS_TOKEN | null;
|
||||
constructor(credentials?: {
|
||||
clientId: string | null;
|
||||
clientSecret: string | null;
|
||||
});
|
||||
get authorizationKey(): string | null;
|
||||
requestToken(): Promise<{
|
||||
token: string;
|
||||
expiresAfter: number;
|
||||
type: "Bearer";
|
||||
} | null>;
|
||||
requestAnonymousToken(): Promise<{
|
||||
token: string;
|
||||
expiresAfter: number;
|
||||
type: "Bearer";
|
||||
} | null>;
|
||||
isTokenExpired(): boolean;
|
||||
search(query: string): Promise<{
|
||||
title: string;
|
||||
duration: number;
|
||||
artist: string;
|
||||
url: string;
|
||||
thumbnail: string | null;
|
||||
}[] | null>;
|
||||
getPlaylist(id: string): Promise<{
|
||||
name: string;
|
||||
author: string;
|
||||
thumbnail: string | null;
|
||||
id: string;
|
||||
url: string;
|
||||
tracks: {
|
||||
title: string;
|
||||
duration: number;
|
||||
artist: string;
|
||||
url: string;
|
||||
thumbnail: string | null;
|
||||
}[];
|
||||
} | null>;
|
||||
getAlbum(id: string): Promise<{
|
||||
name: string;
|
||||
author: string;
|
||||
thumbnail: string | null;
|
||||
id: string;
|
||||
url: string;
|
||||
tracks: {
|
||||
title: string;
|
||||
duration: number;
|
||||
artist: string;
|
||||
url: string;
|
||||
thumbnail: string | null;
|
||||
}[];
|
||||
} | null>;
|
||||
}
|
||||
interface SpotifyTrack {
|
||||
album: {
|
||||
images: {
|
||||
height: number;
|
||||
url: string;
|
||||
width: number;
|
||||
}[];
|
||||
};
|
||||
artists: {
|
||||
id: string;
|
||||
name: string;
|
||||
}[];
|
||||
duration_ms: number;
|
||||
explicit: boolean;
|
||||
external_urls: {
|
||||
spotify: string;
|
||||
};
|
||||
id: string;
|
||||
name: string;
|
||||
}
|
||||
|
||||
type index_AppleMusic = AppleMusic;
|
||||
declare const index_AppleMusic: typeof AppleMusic;
|
||||
type index_SpotifyAPI = SpotifyAPI;
|
||||
declare const index_SpotifyAPI: typeof SpotifyAPI;
|
||||
type index_SpotifyTrack = SpotifyTrack;
|
||||
type index_Vimeo = Vimeo;
|
||||
declare const index_Vimeo: typeof Vimeo;
|
||||
type index_VimeoInfo = VimeoInfo;
|
||||
declare const index_downloadStream: typeof downloadStream;
|
||||
declare namespace index {
|
||||
export { index_AppleMusic as AppleMusic, index_SpotifyAPI as SpotifyAPI, type index_SpotifyTrack as SpotifyTrack, index_Vimeo as Vimeo, type index_VimeoInfo as VimeoInfo, index_downloadStream as downloadStream };
|
||||
}
|
||||
|
||||
interface SpotifyExtractorInit {
|
||||
clientId?: string | null;
|
||||
clientSecret?: string | null;
|
||||
createStream?: (ext: SpotifyExtractor, url: string) => Promise<Readable | string>;
|
||||
}
|
||||
declare class SpotifyExtractor extends BaseExtractor<SpotifyExtractorInit> {
|
||||
static identifier: "com.discord-player.spotifyextractor";
|
||||
private _stream;
|
||||
private _lib;
|
||||
private _credentials;
|
||||
internal: SpotifyAPI;
|
||||
activate(): Promise<void>;
|
||||
deactivate(): Promise<void>;
|
||||
validate(query: string, type?: SearchQueryType | null | undefined): Promise<boolean>;
|
||||
getRelatedTracks(track: Track): Promise<ExtractorInfo>;
|
||||
handle(query: string, context: ExtractorSearchContext): Promise<ExtractorInfo>;
|
||||
stream(info: Track): Promise<ExtractorStreamable>;
|
||||
parse(q: string): {
|
||||
queryType: string;
|
||||
id: string;
|
||||
};
|
||||
}
|
||||
|
||||
declare const version: string;
|
||||
|
||||
declare const DefaultExtractors: (typeof SoundCloudExtractor | typeof AttachmentExtractor | typeof VimeoExtractor | typeof ReverbnationExtractor | typeof AppleMusicExtractor | typeof SpotifyExtractor)[];
|
||||
|
||||
export { AppleMusicExtractor, type AppleMusicExtractorInit, AttachmentExtractor, DefaultExtractors, index as Internal, ReverbnationExtractor, SoundCloudExtractor, type SoundCloudExtractorInit, SpotifyExtractor, type SpotifyExtractorInit, VimeoExtractor, lyricsExtractor, version };
|
||||
|
|
@ -0,0 +1,277 @@
|
|||
import { BaseExtractor, SearchQueryType, Track, GuildQueueHistory, ExtractorInfo, ExtractorSearchContext, ExtractorStreamable } from 'discord-player';
|
||||
import * as SoundCloud from 'soundcloud.ts';
|
||||
import * as fs from 'fs';
|
||||
import { Readable } from 'stream';
|
||||
import { HTMLElement } from 'node-html-parser';
|
||||
import { RequestOptions } from 'http';
|
||||
|
||||
interface SoundCloudExtractorInit {
|
||||
clientId?: string;
|
||||
oauthToken?: string;
|
||||
proxy?: string;
|
||||
}
|
||||
declare class SoundCloudExtractor extends BaseExtractor<SoundCloudExtractorInit> {
|
||||
static identifier: "com.discord-player.soundcloudextractor";
|
||||
static instance: SoundCloudExtractor | null;
|
||||
internal: SoundCloud.Soundcloud;
|
||||
activate(): Promise<void>;
|
||||
deactivate(): Promise<void>;
|
||||
validate(query: string, type?: SearchQueryType | null | undefined): Promise<boolean>;
|
||||
getRelatedTracks(track: Track, history: GuildQueueHistory): Promise<ExtractorInfo>;
|
||||
handle(query: string, context: ExtractorSearchContext): Promise<ExtractorInfo>;
|
||||
emptyResponse(): ExtractorInfo;
|
||||
stream(info: Track): Promise<string>;
|
||||
bridge(track: Track, sourceExtractor: BaseExtractor | null): Promise<ExtractorStreamable | null>;
|
||||
}
|
||||
|
||||
declare function lyricsExtractor(): void;
|
||||
|
||||
declare class VimeoExtractor extends BaseExtractor {
|
||||
static identifier: "com.discord-player.vimeoextractor";
|
||||
validate(query: string, type?: SearchQueryType | null | undefined): Promise<boolean>;
|
||||
getRelatedTracks(track: Track): Promise<ExtractorInfo>;
|
||||
handle(query: string, context: ExtractorSearchContext): Promise<ExtractorInfo>;
|
||||
emptyResponse(): ExtractorInfo;
|
||||
stream(info: Track): Promise<string>;
|
||||
}
|
||||
|
||||
declare class ReverbnationExtractor extends BaseExtractor {
|
||||
static identifier: "com.discord-player.reverbnationextractor";
|
||||
validate(query: string, type?: SearchQueryType | null | undefined): Promise<boolean>;
|
||||
getRelatedTracks(track: Track): Promise<ExtractorInfo>;
|
||||
handle(query: string, context: ExtractorSearchContext): Promise<ExtractorInfo>;
|
||||
emptyResponse(): ExtractorInfo;
|
||||
stream(info: Track): Promise<string>;
|
||||
}
|
||||
|
||||
declare class AttachmentExtractor extends BaseExtractor {
|
||||
static identifier: "com.discord-player.attachmentextractor";
|
||||
priority: number;
|
||||
validate(query: string, type?: SearchQueryType | null | undefined): Promise<boolean>;
|
||||
getRelatedTracks(track: Track): Promise<ExtractorInfo>;
|
||||
handle(query: string, context: ExtractorSearchContext): Promise<ExtractorInfo>;
|
||||
emptyResponse(): ExtractorInfo;
|
||||
stream(info: Track): Promise<string | {
|
||||
stream: fs.ReadStream;
|
||||
$fmt: string;
|
||||
}>;
|
||||
}
|
||||
|
||||
interface AppleMusicExtractorInit {
|
||||
createStream?: (ext: AppleMusicExtractor, url: string, track: Track) => Promise<Readable | string>;
|
||||
}
|
||||
declare class AppleMusicExtractor extends BaseExtractor<AppleMusicExtractorInit> {
|
||||
static identifier: "com.discord-player.applemusicextractor";
|
||||
private _stream;
|
||||
activate(): Promise<void>;
|
||||
deactivate(): Promise<void>;
|
||||
validate(query: string, type?: SearchQueryType | null | undefined): Promise<boolean>;
|
||||
getRelatedTracks(track: Track, history: GuildQueueHistory): Promise<ExtractorInfo>;
|
||||
handle(query: string, context: ExtractorSearchContext): Promise<ExtractorInfo>;
|
||||
stream(info: Track): Promise<ExtractorStreamable>;
|
||||
}
|
||||
|
||||
declare class AppleMusic {
|
||||
constructor();
|
||||
static search(query: string): Promise<any>;
|
||||
static getSongInfoFallback(res: HTMLElement, name: string, id: string, link: string): Promise<{
|
||||
id: string;
|
||||
duration: string;
|
||||
title: string;
|
||||
url: string;
|
||||
thumbnail: string;
|
||||
artist: {
|
||||
name: string;
|
||||
};
|
||||
} | null>;
|
||||
static getSongInfo(link: string): Promise<{
|
||||
id: any;
|
||||
duration: any;
|
||||
title: any;
|
||||
url: any;
|
||||
thumbnail: string;
|
||||
artist: {
|
||||
name: any;
|
||||
};
|
||||
} | null>;
|
||||
static getPlaylistInfo(link: string): Promise<{
|
||||
id: any;
|
||||
title: any;
|
||||
thumbnail: string;
|
||||
artist: {
|
||||
name: any;
|
||||
};
|
||||
url: any;
|
||||
tracks: any;
|
||||
} | null>;
|
||||
static getAlbumInfo(link: string): Promise<{
|
||||
id: any;
|
||||
title: any;
|
||||
thumbnail: string;
|
||||
artist: {
|
||||
name: any;
|
||||
};
|
||||
url: any;
|
||||
tracks: any;
|
||||
} | null>;
|
||||
}
|
||||
|
||||
declare class Vimeo {
|
||||
constructor();
|
||||
/**
|
||||
* @typedef {Readable} Readable
|
||||
*/
|
||||
/**
|
||||
* Downloads from vimeo
|
||||
* @param {number} id Vimeo video id
|
||||
* @returns {Promise<Readable>}
|
||||
*/
|
||||
static download(id: number | string): Promise<Readable>;
|
||||
/**
|
||||
* Returns video info
|
||||
* @param {number} id Video id
|
||||
*/
|
||||
static getInfo(id: number | string): Promise<VimeoInfo | null>;
|
||||
}
|
||||
interface VimeoInfo {
|
||||
id: number;
|
||||
duration: number;
|
||||
title: string;
|
||||
url: string;
|
||||
thumbnail: string;
|
||||
stream: string;
|
||||
author: {
|
||||
id: number;
|
||||
name: string;
|
||||
url: string;
|
||||
avatar: string;
|
||||
};
|
||||
}
|
||||
|
||||
declare function downloadStream(url: string, opts?: RequestOptions): Promise<Readable>;
|
||||
|
||||
interface SP_ACCESS_TOKEN {
|
||||
token: string;
|
||||
expiresAfter: number;
|
||||
type: 'Bearer';
|
||||
}
|
||||
declare class SpotifyAPI {
|
||||
credentials: {
|
||||
clientId: string | null;
|
||||
clientSecret: string | null;
|
||||
};
|
||||
accessToken: SP_ACCESS_TOKEN | null;
|
||||
constructor(credentials?: {
|
||||
clientId: string | null;
|
||||
clientSecret: string | null;
|
||||
});
|
||||
get authorizationKey(): string | null;
|
||||
requestToken(): Promise<{
|
||||
token: string;
|
||||
expiresAfter: number;
|
||||
type: "Bearer";
|
||||
} | null>;
|
||||
requestAnonymousToken(): Promise<{
|
||||
token: string;
|
||||
expiresAfter: number;
|
||||
type: "Bearer";
|
||||
} | null>;
|
||||
isTokenExpired(): boolean;
|
||||
search(query: string): Promise<{
|
||||
title: string;
|
||||
duration: number;
|
||||
artist: string;
|
||||
url: string;
|
||||
thumbnail: string | null;
|
||||
}[] | null>;
|
||||
getPlaylist(id: string): Promise<{
|
||||
name: string;
|
||||
author: string;
|
||||
thumbnail: string | null;
|
||||
id: string;
|
||||
url: string;
|
||||
tracks: {
|
||||
title: string;
|
||||
duration: number;
|
||||
artist: string;
|
||||
url: string;
|
||||
thumbnail: string | null;
|
||||
}[];
|
||||
} | null>;
|
||||
getAlbum(id: string): Promise<{
|
||||
name: string;
|
||||
author: string;
|
||||
thumbnail: string | null;
|
||||
id: string;
|
||||
url: string;
|
||||
tracks: {
|
||||
title: string;
|
||||
duration: number;
|
||||
artist: string;
|
||||
url: string;
|
||||
thumbnail: string | null;
|
||||
}[];
|
||||
} | null>;
|
||||
}
|
||||
interface SpotifyTrack {
|
||||
album: {
|
||||
images: {
|
||||
height: number;
|
||||
url: string;
|
||||
width: number;
|
||||
}[];
|
||||
};
|
||||
artists: {
|
||||
id: string;
|
||||
name: string;
|
||||
}[];
|
||||
duration_ms: number;
|
||||
explicit: boolean;
|
||||
external_urls: {
|
||||
spotify: string;
|
||||
};
|
||||
id: string;
|
||||
name: string;
|
||||
}
|
||||
|
||||
type index_AppleMusic = AppleMusic;
|
||||
declare const index_AppleMusic: typeof AppleMusic;
|
||||
type index_SpotifyAPI = SpotifyAPI;
|
||||
declare const index_SpotifyAPI: typeof SpotifyAPI;
|
||||
type index_SpotifyTrack = SpotifyTrack;
|
||||
type index_Vimeo = Vimeo;
|
||||
declare const index_Vimeo: typeof Vimeo;
|
||||
type index_VimeoInfo = VimeoInfo;
|
||||
declare const index_downloadStream: typeof downloadStream;
|
||||
declare namespace index {
|
||||
export { index_AppleMusic as AppleMusic, index_SpotifyAPI as SpotifyAPI, type index_SpotifyTrack as SpotifyTrack, index_Vimeo as Vimeo, type index_VimeoInfo as VimeoInfo, index_downloadStream as downloadStream };
|
||||
}
|
||||
|
||||
interface SpotifyExtractorInit {
|
||||
clientId?: string | null;
|
||||
clientSecret?: string | null;
|
||||
createStream?: (ext: SpotifyExtractor, url: string) => Promise<Readable | string>;
|
||||
}
|
||||
declare class SpotifyExtractor extends BaseExtractor<SpotifyExtractorInit> {
|
||||
static identifier: "com.discord-player.spotifyextractor";
|
||||
private _stream;
|
||||
private _lib;
|
||||
private _credentials;
|
||||
internal: SpotifyAPI;
|
||||
activate(): Promise<void>;
|
||||
deactivate(): Promise<void>;
|
||||
validate(query: string, type?: SearchQueryType | null | undefined): Promise<boolean>;
|
||||
getRelatedTracks(track: Track): Promise<ExtractorInfo>;
|
||||
handle(query: string, context: ExtractorSearchContext): Promise<ExtractorInfo>;
|
||||
stream(info: Track): Promise<ExtractorStreamable>;
|
||||
parse(q: string): {
|
||||
queryType: string;
|
||||
id: string;
|
||||
};
|
||||
}
|
||||
|
||||
declare const version: string;
|
||||
|
||||
declare const DefaultExtractors: (typeof SoundCloudExtractor | typeof AttachmentExtractor | typeof VimeoExtractor | typeof ReverbnationExtractor | typeof AppleMusicExtractor | typeof SpotifyExtractor)[];
|
||||
|
||||
export { AppleMusicExtractor, type AppleMusicExtractorInit, AttachmentExtractor, DefaultExtractors, index as Internal, ReverbnationExtractor, SoundCloudExtractor, type SoundCloudExtractorInit, SpotifyExtractor, type SpotifyExtractorInit, VimeoExtractor, lyricsExtractor, version };
|
||||
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
|
|
@ -0,0 +1,63 @@
|
|||
{
|
||||
"name": "@discord-player/extractor",
|
||||
"version": "7.2.0",
|
||||
"description": "Extractors for discord-player",
|
||||
"keywords": [
|
||||
"discord-player",
|
||||
"music",
|
||||
"bot",
|
||||
"discord.js",
|
||||
"javascript",
|
||||
"voip",
|
||||
"lavalink",
|
||||
"lavaplayer"
|
||||
],
|
||||
"author": "Twilight <hello@twlite.dev>",
|
||||
"homepage": "https://discord-player.js.org",
|
||||
"license": "MIT",
|
||||
"main": "dist/index.js",
|
||||
"module": "dist/index.mjs",
|
||||
"types": "dist/index.d.ts",
|
||||
"publishConfig": {
|
||||
"access": "public"
|
||||
},
|
||||
"files": [
|
||||
"dist"
|
||||
],
|
||||
"repository": {
|
||||
"type": "git",
|
||||
"url": "git+https://github.com/Androz2091/discord-player.git"
|
||||
},
|
||||
"scripts": {
|
||||
"build": "tsup",
|
||||
"build:check": "tsc --noEmit",
|
||||
"lint": "eslint src --ext .ts --fix"
|
||||
},
|
||||
"bugs": {
|
||||
"url": "https://github.com/Androz2091/discord-player/issues"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@discord-player/tsconfig": "^7.2.0",
|
||||
"@types/node": "^22.10.7",
|
||||
"discord-player": "^7.2.0",
|
||||
"mediaplex": "^1.0.0",
|
||||
"tsup": "^8.3.5",
|
||||
"typescript": "^5.2.2",
|
||||
"vitest": "^0.34.6"
|
||||
},
|
||||
"dependencies": {
|
||||
"file-type": "^16.5.4",
|
||||
"isomorphic-unfetch": "^4.0.2",
|
||||
"node-html-parser": "^7.0.2",
|
||||
"reverbnation-scraper": "^2.0.0",
|
||||
"soundcloud.ts": "^0.5.5",
|
||||
"spotify-url-info": "^3.2.6"
|
||||
},
|
||||
"typedoc": {
|
||||
"entryPoint": "./src/index.ts",
|
||||
"readmeFile": "./README.md",
|
||||
"tsconfig": "./tsconfig.json",
|
||||
"excludeExternals": true,
|
||||
"excludePrivate": true
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,21 @@
|
|||
MIT License
|
||||
|
||||
Copyright (c) 2020 Androz2091
|
||||
|
||||
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.
|
||||
|
|
@ -0,0 +1,42 @@
|
|||
# `@discord-player/ffmpeg`
|
||||
|
||||
FFmpeg stream abstraction for Discord Player.
|
||||
|
||||
## Installation
|
||||
|
||||
```sh
|
||||
$ yarn add @discord-player/ffmpeg
|
||||
```
|
||||
|
||||
## Supported FFmpeg Locations
|
||||
|
||||
- `process.env.FFMPEG_PATH`
|
||||
- command `ffmpeg`
|
||||
- command `avconv`
|
||||
- command `./ffmpeg` (`./ffmpeg.exe` on windows)
|
||||
- command `./avconv` (`./avconv.exe` on windows)
|
||||
- npm package [@ffmpeg-installer/ffmpeg](https://npm.im/@ffmpeg-installer/ffmpeg)
|
||||
- npm package [ffmpeg-static](https://npm.im/ffmpeg-static)
|
||||
- npm package [@node-ffmpeg/node-ffmpeg-installer](@node-ffmpeg/node-ffmpeg-installer)
|
||||
- npm package [ffmpeg-binaries](https://npm.im/ffmpeg-binaries)
|
||||
|
||||
## Example
|
||||
|
||||
<!-- prettier-ignore -->
|
||||
```js
|
||||
import { FFmpeg } from '@discord-player/ffmpeg';
|
||||
|
||||
const transcoder = new FFmpeg({
|
||||
args: [
|
||||
'-analyzeduration', '0',
|
||||
'-loglevel', '0',
|
||||
'-f', 's16le',
|
||||
'-ar', '48000',
|
||||
'-ac', '2',
|
||||
'-af', 'bass=g=15,acompressor'
|
||||
]
|
||||
});
|
||||
|
||||
const stream = getAudioStreamSomehow();
|
||||
const transcoded = stream.pipe(transcoder);
|
||||
```
|
||||
|
|
@ -0,0 +1,121 @@
|
|||
import * as stream from 'stream';
|
||||
import { ChildProcessWithoutNullStreams } from 'node:child_process';
|
||||
import { DuplexOptions, Duplex } from 'node:stream';
|
||||
|
||||
type FFmpegLib = 'ffmpeg' | './ffmpeg' | 'avconv' | './avconv' | 'ffmpeg-static' | '@ffmpeg-installer/ffmpeg' | '@node-ffmpeg/node-ffmpeg-installer' | 'ffmpeg-binaries';
|
||||
type FFmpegCallback<Args extends Array<unknown>> = (...args: Args) => unknown;
|
||||
/**
|
||||
* FFmpeg source configuration
|
||||
*/
|
||||
interface FFmpegSource {
|
||||
/** Name or path of the FFmpeg executable */
|
||||
name: FFmpegLib;
|
||||
/** Whether this source is a Node.js module */
|
||||
module: boolean;
|
||||
}
|
||||
interface ResolvedFFmpegSource extends FFmpegSource {
|
||||
path: string;
|
||||
version: string;
|
||||
command: string;
|
||||
result: string;
|
||||
}
|
||||
/**
|
||||
* Compares and updates FFmpeg flags as needed
|
||||
* @param oldFlags The old flags
|
||||
* @param newFlags The new flags
|
||||
* @returns The updated flags
|
||||
*/
|
||||
declare function changeFFmpegFlags(oldFlags: string[], newFlags: string[]): string[];
|
||||
|
||||
interface FFmpegOptions extends DuplexOptions {
|
||||
args?: string[];
|
||||
shell?: boolean;
|
||||
}
|
||||
declare class FFmpeg extends Duplex {
|
||||
/**
|
||||
* Cached FFmpeg source.
|
||||
*/
|
||||
private static cached;
|
||||
/**
|
||||
* Supported FFmpeg sources.
|
||||
*/
|
||||
static sources: FFmpegSource[];
|
||||
/**
|
||||
* Checks if FFmpeg is loaded.
|
||||
*/
|
||||
static isLoaded(): boolean;
|
||||
/**
|
||||
* Adds a new FFmpeg source.
|
||||
* @param source FFmpeg source
|
||||
*/
|
||||
static addSource(source: FFmpegSource): boolean;
|
||||
/**
|
||||
* Removes a FFmpeg source.
|
||||
* @param source FFmpeg source
|
||||
*/
|
||||
static removeSource(source: FFmpegSource): boolean;
|
||||
/**
|
||||
* Resolves FFmpeg path. Throws an error if it fails to resolve.
|
||||
* @param force if it should relocate the command
|
||||
*/
|
||||
static resolve(force?: boolean): ResolvedFFmpegSource;
|
||||
/**
|
||||
* Resolves FFmpeg path safely. Returns null if it fails to resolve.
|
||||
* @param force if it should relocate the command
|
||||
*/
|
||||
static resolveSafe(force?: boolean): ResolvedFFmpegSource | null;
|
||||
/**
|
||||
* Spawns ffmpeg process
|
||||
* @param options Spawn options
|
||||
*/
|
||||
static spawn({ args, shell }?: {
|
||||
args?: string[] | undefined;
|
||||
shell?: boolean | undefined;
|
||||
}): ChildProcessWithoutNullStreams;
|
||||
/**
|
||||
* Current FFmpeg process
|
||||
*/
|
||||
process: ChildProcessWithoutNullStreams;
|
||||
/**
|
||||
* Create FFmpeg duplex stream
|
||||
* @param options Options to initialize ffmpeg
|
||||
* @example ```typescript
|
||||
* const ffmpeg = new FFmpeg({
|
||||
* args: [
|
||||
* '-analyzeduration', '0',
|
||||
* '-loglevel', '0',
|
||||
* '-f', 's16le',
|
||||
* '-ar', '48000',
|
||||
* '-ac', '2',
|
||||
* '-af', 'bass=g=10,acompressor'
|
||||
* ]
|
||||
* });
|
||||
*
|
||||
* const pcm = input.pipe(ffmpeg);
|
||||
*
|
||||
* pcm.pipe(fs.createWriteStream('./audio.pcm'));
|
||||
* ```
|
||||
*/
|
||||
constructor(options?: FFmpegOptions);
|
||||
get _reader(): stream.Readable;
|
||||
get _writer(): stream.Writable;
|
||||
private _copy;
|
||||
_destroy(err: Error | null, cb: FFmpegCallback<[Error | null]>): unknown;
|
||||
_final(cb: FFmpegCallback<[]>): void;
|
||||
private _cleanup;
|
||||
}
|
||||
|
||||
declare const version: string;
|
||||
|
||||
type ArgPrimitive = string | number | null;
|
||||
/**
|
||||
* Create FFmpeg arguments from an object.
|
||||
* @param input The input object.
|
||||
* @param post Additional arguments to append.
|
||||
* @returns The FFmpeg arguments.
|
||||
* @example createFFmpegArgs({ i: 'input.mp3', af: ['bass=g=10','acompressor'] }, './out.mp3');
|
||||
* // => ['-i', 'input.mp3', '-af', 'bass=g=10,acompressor', './out.mp3']
|
||||
*/
|
||||
declare const createFFmpegArgs: (input: Record<string, ArgPrimitive | ArgPrimitive[]>, post?: string | string[]) => string[];
|
||||
|
||||
export { type ArgPrimitive, FFmpeg, type FFmpegCallback, type FFmpegLib, type FFmpegOptions, type FFmpegSource, type ResolvedFFmpegSource, changeFFmpegFlags, createFFmpegArgs, version };
|
||||
File diff suppressed because one or more lines are too long
|
|
@ -0,0 +1,15 @@
|
|||
import DiscordPlayerFFmpeg from './index.js';
|
||||
|
||||
const {
|
||||
FFmpeg,
|
||||
changeFFmpegFlags,
|
||||
createFFmpegArgs,
|
||||
version
|
||||
} = DiscordPlayerFFmpeg;
|
||||
|
||||
export {
|
||||
FFmpeg,
|
||||
changeFFmpegFlags,
|
||||
createFFmpegArgs,
|
||||
version
|
||||
};
|
||||
|
|
@ -0,0 +1,53 @@
|
|||
{
|
||||
"name": "@discord-player/ffmpeg",
|
||||
"version": "7.2.0",
|
||||
"description": "FFmpeg stream abstraction for discord-player",
|
||||
"keywords": [
|
||||
"discord-player",
|
||||
"music",
|
||||
"bot",
|
||||
"discord.js",
|
||||
"javascript",
|
||||
"voip",
|
||||
"lavalink",
|
||||
"lavaplayer"
|
||||
],
|
||||
"author": "Twilight <hello@twlite.dev>",
|
||||
"homepage": "https://discord-player.js.org",
|
||||
"license": "MIT",
|
||||
"main": "dist/index.js",
|
||||
"module": "dist/index.mjs",
|
||||
"types": "dist/index.d.ts",
|
||||
"publishConfig": {
|
||||
"access": "public"
|
||||
},
|
||||
"files": [
|
||||
"dist"
|
||||
],
|
||||
"repository": {
|
||||
"type": "git",
|
||||
"url": "git+https://github.com/Androz2091/discord-player.git"
|
||||
},
|
||||
"scripts": {
|
||||
"build": "tsup && node ./scripts/esm-shim.cjs",
|
||||
"build:check": "tsc --noEmit",
|
||||
"lint": "eslint src --ext .ts --fix"
|
||||
},
|
||||
"bugs": {
|
||||
"url": "https://github.com/Androz2091/discord-player/issues"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@discord-player/tsconfig": "^7.2.0",
|
||||
"@types/node": "^22.10.7",
|
||||
"tsup": "^8.3.5",
|
||||
"typescript": "^5.2.2",
|
||||
"vitest": "^0.34.6"
|
||||
},
|
||||
"typedoc": {
|
||||
"entryPoint": "./src/index.ts",
|
||||
"readmeFile": "./README.md",
|
||||
"tsconfig": "./tsconfig.json",
|
||||
"excludeExternals": true,
|
||||
"excludePrivate": true
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,21 @@
|
|||
MIT License
|
||||
|
||||
Copyright (c) 2020 Androz2091
|
||||
|
||||
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.
|
||||
|
|
@ -0,0 +1,41 @@
|
|||
# `@discord-player/opus`
|
||||
|
||||
Streamable Opus encoder and decoder for Discord Player.
|
||||
|
||||
## Installation
|
||||
|
||||
```sh
|
||||
$ yarn add @discord-player/opus
|
||||
```
|
||||
|
||||
Additionally, install one of the following opus libraries:
|
||||
|
||||
- `mediaplex`
|
||||
- `@discordjs/opus`
|
||||
- `opusscript`
|
||||
- `@evan/opus`
|
||||
- `node-opus`
|
||||
|
||||
If one does not work, feel free to switch to another.
|
||||
|
||||
## Adding custom opus library
|
||||
|
||||
```js
|
||||
import { OPUS_MOD_REGISTRY } from '@discord-player/opus';
|
||||
|
||||
OPUS_MOD_REGISTRY.unshift(['my-opus-package-name', (mod) => ({ Encoder: mod.OpusEncoder })]);
|
||||
```
|
||||
|
||||
Make sure to use this code before using any of the opus classes.
|
||||
|
||||
## Example
|
||||
|
||||
```js
|
||||
import { OpusEncoder, OpusDecoder } from '@discord-player/opus';
|
||||
|
||||
// encode
|
||||
const opusStream = getPcmStreamSomehow().pipe(new OpusEncoder({ rate: 48000, channels: 2, frameSize: 960 }));
|
||||
|
||||
// decode
|
||||
const pcmStream = getOpusStreamSomehow().pipe(new OpusDecoder({ rate: 48000, channels: 2, frameSize: 960 }));
|
||||
```
|
||||
|
|
@ -0,0 +1,267 @@
|
|||
import { Transform, TransformCallback } from 'node:stream';
|
||||
|
||||
/**
|
||||
* Demuxes an Ogg stream (containing Opus audio) to output an Opus stream.
|
||||
*/
|
||||
declare class OggDemuxer extends Transform {
|
||||
private _remainder;
|
||||
private _head;
|
||||
private _bitstream;
|
||||
/**
|
||||
* Creates a new OggOpus demuxer.
|
||||
* @param {Object} [options] options that you would pass to a regular Transform stream.
|
||||
* @memberof opus
|
||||
*/
|
||||
constructor(options?: {});
|
||||
_transform(chunk: Buffer, encoding: BufferEncoding, done: TransformCallback): void;
|
||||
/**
|
||||
* Reads a page from a buffer
|
||||
* @private
|
||||
* @param {Buffer} chunk the chunk containing the page
|
||||
* @returns {boolean|Buffer} if a buffer, it will be a slice of the excess data of the original, otherwise it will be
|
||||
* false and would indicate that there is not enough data to go ahead with reading this page.
|
||||
*/
|
||||
_readPage(chunk: Buffer): false | Buffer;
|
||||
_destroy(err: Error, cb: (error: Error | null) => void): void;
|
||||
_final(cb: TransformCallback): void;
|
||||
/**
|
||||
* Cleans up the demuxer when it is no longer required.
|
||||
* @private
|
||||
*/
|
||||
_cleanup(): void;
|
||||
}
|
||||
|
||||
type IEncoder = {
|
||||
new (rate: number, channels: number, application: number): {
|
||||
encode(buffer: Buffer): Buffer;
|
||||
encode(buffer: Buffer, frameSize: number): Buffer;
|
||||
encode(buffer: Buffer, frameSize?: number): Buffer;
|
||||
decode(buffer: Buffer): Buffer;
|
||||
decode(buffer: Buffer, frameSize: number): Buffer;
|
||||
decode(buffer: Buffer, frameSize?: number): Buffer;
|
||||
applyEncoderCTL?(ctl: number, value: number): void;
|
||||
encoderCTL?(ctl: number, value: number): void;
|
||||
delete?(): void;
|
||||
};
|
||||
Application?: any;
|
||||
};
|
||||
type IMod = [
|
||||
string,
|
||||
(mod: any) => {
|
||||
Encoder: IEncoder;
|
||||
}
|
||||
];
|
||||
declare const CTL: {
|
||||
readonly BITRATE: 4002;
|
||||
readonly FEC: 4012;
|
||||
readonly PLP: 4014;
|
||||
};
|
||||
/**
|
||||
* Add a new Opus provider to the registry. This will be tried to load in order at runtime.
|
||||
* @param provider - The provider to add
|
||||
*/
|
||||
declare const addLibopusProvider: (provider: IMod) => void;
|
||||
/**
|
||||
* Remove an Opus provider from the registry.
|
||||
* @param name - The name of the provider to remove
|
||||
*/
|
||||
declare const removeLibopusProvider: (name: string) => boolean;
|
||||
/**
|
||||
* Set the Opus provider to use. This will override the automatic provider selection.
|
||||
* @param provider - The provider to use
|
||||
*/
|
||||
declare const setLibopusProvider: (provider: IEncoder, name: string) => void;
|
||||
interface IOpusStreamInit {
|
||||
frameSize: number;
|
||||
channels: number;
|
||||
rate: number;
|
||||
application?: number;
|
||||
}
|
||||
/**
|
||||
* Takes a stream of Opus data and outputs a stream of PCM data, or the inverse.
|
||||
* **You shouldn't directly instantiate this class, see opus.Encoder and opus.Decoder instead!**
|
||||
* @memberof opus
|
||||
* @extends TransformStream
|
||||
* @protected
|
||||
*/
|
||||
declare class OpusStream extends Transform {
|
||||
encoder: InstanceType<IEncoder> | null;
|
||||
_options: IOpusStreamInit;
|
||||
_required: number;
|
||||
/**
|
||||
* Creates a new Opus transformer.
|
||||
* @private
|
||||
* @memberof opus
|
||||
* @param {Object} [options] options that you would pass to a regular Transform stream
|
||||
*/
|
||||
constructor(options?: IOpusStreamInit);
|
||||
_encode(buffer: Buffer): Buffer;
|
||||
_decode(buffer: Buffer): Buffer;
|
||||
/**
|
||||
* Returns the Opus module being used - `mediaplex`, `opusscript`, `node-opus`, or `@discordjs/opus`.
|
||||
* @type {string}
|
||||
* @readonly
|
||||
* @example
|
||||
* console.log(`Using Opus module ${OpusEncoder.type}`);
|
||||
*/
|
||||
static get type(): string | undefined;
|
||||
/**
|
||||
* Sets the bitrate of the stream.
|
||||
* @param {number} bitrate the bitrate to use use, e.g. 48000
|
||||
* @public
|
||||
*/
|
||||
setBitrate(bitrate: number): void;
|
||||
/**
|
||||
* Enables or disables forward error correction.
|
||||
* @param {boolean} enabled whether or not to enable FEC.
|
||||
* @public
|
||||
*/
|
||||
setFEC(enabled: boolean): void;
|
||||
/**
|
||||
* Sets the expected packet loss over network transmission.
|
||||
* @param {number} [percentage] a percentage (represented between 0 and 1)
|
||||
*/
|
||||
setPLP(percentage: number): void;
|
||||
_final(cb: () => void): void;
|
||||
_destroy(err: Error | null, cb: (err: Error | null) => void): void;
|
||||
/**
|
||||
* Cleans up the Opus stream when it is no longer needed
|
||||
* @private
|
||||
*/
|
||||
_cleanup(): void;
|
||||
}
|
||||
/**
|
||||
* An Opus encoder stream.
|
||||
*
|
||||
* Outputs opus packets in [object mode.](https://nodejs.org/api/stream.html#stream_object_mode)
|
||||
* @extends opus.OpusStream
|
||||
* @memberof opus
|
||||
* @example
|
||||
* const encoder = new prism.opus.Encoder({ frameSize: 960, channels: 2, rate: 48000 });
|
||||
* pcmAudio.pipe(encoder);
|
||||
* // encoder will now output Opus-encoded audio packets
|
||||
*/
|
||||
declare class OpusEncoder extends OpusStream {
|
||||
_buffer: Buffer;
|
||||
/**
|
||||
* Creates a new Opus encoder stream.
|
||||
* @memberof opus
|
||||
* @param {Object} options options that you would pass to a regular OpusStream, plus a few more:
|
||||
* @param {number} options.frameSize the frame size in bytes to use (e.g. 960 for stereo audio at 48KHz with a frame
|
||||
* duration of 20ms)
|
||||
* @param {number} options.channels the number of channels to use
|
||||
* @param {number} options.rate the sampling rate in Hz
|
||||
*/
|
||||
constructor(options?: IOpusStreamInit);
|
||||
_transform(newChunk: Buffer, encoding: BufferEncoding, done: TransformCallback): void;
|
||||
_destroy(err: Error, cb: (err: Error | null) => void): void;
|
||||
}
|
||||
/**
|
||||
* An Opus decoder stream.
|
||||
*
|
||||
* Note that any stream you pipe into this must be in
|
||||
* [object mode](https://nodejs.org/api/stream.html#stream_object_mode) and should output Opus packets.
|
||||
* @extends opus.OpusStream
|
||||
* @memberof opus
|
||||
* @example
|
||||
* const decoder = new OpusDecoder({ frameSize: 960, channels: 2, rate: 48000 });
|
||||
* input.pipe(decoder);
|
||||
* // decoder will now output PCM audio
|
||||
*/
|
||||
declare class OpusDecoder extends OpusStream {
|
||||
_transform(chunk: Buffer, encoding: BufferEncoding, done: (e?: Error | null, chunk?: Buffer) => void): void;
|
||||
}
|
||||
|
||||
declare class WebmBaseDemuxer extends Transform {
|
||||
static readonly TAGS: {
|
||||
'1a45dfa3': boolean;
|
||||
'18538067': boolean;
|
||||
'1f43b675': boolean;
|
||||
'1654ae6b': boolean;
|
||||
ae: boolean;
|
||||
d7: boolean;
|
||||
'83': boolean;
|
||||
a3: boolean;
|
||||
'63a2': boolean;
|
||||
};
|
||||
static readonly TOO_SHORT: unique symbol;
|
||||
private _remainder;
|
||||
private _length;
|
||||
private _count;
|
||||
private _skipUntil;
|
||||
private _track;
|
||||
private _incompleteTrack;
|
||||
private _ebmlFound;
|
||||
/**
|
||||
* Creates a new Webm demuxer.
|
||||
* @param {Object} [options] options that you would pass to a regular Transform stream.
|
||||
*/
|
||||
constructor(options?: {});
|
||||
_checkHead(data: Buffer): void;
|
||||
_transform(chunk: Buffer, encoding: BufferEncoding, done: TransformCallback): void;
|
||||
/**
|
||||
* Reads an EBML ID from a buffer.
|
||||
* @private
|
||||
* @param {Buffer} chunk the buffer to read from.
|
||||
* @param {number} offset the offset in the buffer.
|
||||
* @returns {Object|Symbol} contains an `id` property (buffer) and the new `offset` (number).
|
||||
* Returns the TOO_SHORT symbol if the data wasn't big enough to facilitate the request.
|
||||
*/
|
||||
_readEBMLId(chunk: Buffer, offset: number): typeof WebmBaseDemuxer.TOO_SHORT | {
|
||||
id: Buffer;
|
||||
offset: number;
|
||||
};
|
||||
/**
|
||||
* Reads a size variable-integer to calculate the length of the data of a tag.
|
||||
* @private
|
||||
* @param {Buffer} chunk the buffer to read from.
|
||||
* @param {number} offset the offset in the buffer.
|
||||
* @returns {Object|Symbol} contains property `offset` (number), `dataLength` (number) and `sizeLength` (number).
|
||||
* Returns the TOO_SHORT symbol if the data wasn't big enough to facilitate the request.
|
||||
*/
|
||||
_readTagDataSize(chunk: Buffer, offset: number): typeof WebmBaseDemuxer.TOO_SHORT | {
|
||||
offset: number;
|
||||
dataLength: number | symbol;
|
||||
sizeLength: number;
|
||||
};
|
||||
/**
|
||||
* Takes a buffer and attempts to read and process a tag.
|
||||
* @private
|
||||
* @param {Buffer} chunk the buffer to read from.
|
||||
* @param {number} offset the offset in the buffer.
|
||||
* @returns {Object|Symbol} contains the new `offset` (number) and optionally the `_skipUntil` property,
|
||||
* indicating that the stream should ignore any data until a certain length is reached.
|
||||
* Returns the TOO_SHORT symbol if the data wasn't big enough to facilitate the request.
|
||||
*/
|
||||
_readTag(chunk: Buffer, offset: number): typeof WebmBaseDemuxer.TOO_SHORT | {
|
||||
offset: number;
|
||||
_skipUntil?: undefined;
|
||||
} | {
|
||||
offset: number;
|
||||
_skipUntil: number;
|
||||
};
|
||||
_destroy(err: Error, cb: (error: Error | null) => void): void;
|
||||
_final(cb: TransformCallback): void;
|
||||
/**
|
||||
* Cleans up the demuxer when it is no longer required.
|
||||
* @private
|
||||
*/
|
||||
_cleanup(): void;
|
||||
}
|
||||
|
||||
/**
|
||||
* Demuxes a Webm stream (containing Opus audio) to output an Opus stream.
|
||||
* @example
|
||||
* const fs = require('fs');
|
||||
* const file = fs.createReadStream('./audio.webm');
|
||||
* const demuxer = new WebmDemuxer();
|
||||
* const opus = file.pipe(demuxer);
|
||||
* // opus is now a ReadableStream in object mode outputting Opus packets
|
||||
*/
|
||||
declare class WebmDemuxer extends WebmBaseDemuxer {
|
||||
_checkHead(data: Buffer): void;
|
||||
}
|
||||
|
||||
declare const version: string;
|
||||
|
||||
export { CTL, type IEncoder, type IOpusStreamInit, OggDemuxer, OpusDecoder, OpusEncoder, OpusStream, WebmDemuxer, addLibopusProvider, removeLibopusProvider, setLibopusProvider, version };
|
||||
File diff suppressed because one or more lines are too long
|
|
@ -0,0 +1,27 @@
|
|||
import DiscordPlayerOpus from './index.js';
|
||||
|
||||
const {
|
||||
CTL,
|
||||
OggDemuxer,
|
||||
OpusDecoder,
|
||||
OpusEncoder,
|
||||
OpusStream,
|
||||
WebmDemuxer,
|
||||
addLibopusProvider,
|
||||
removeLibopusProvider,
|
||||
setLibopusProvider,
|
||||
version
|
||||
} = DiscordPlayerOpus;
|
||||
|
||||
export {
|
||||
CTL,
|
||||
OggDemuxer,
|
||||
OpusDecoder,
|
||||
OpusEncoder,
|
||||
OpusStream,
|
||||
WebmDemuxer,
|
||||
addLibopusProvider,
|
||||
removeLibopusProvider,
|
||||
setLibopusProvider,
|
||||
version
|
||||
};
|
||||
|
|
@ -0,0 +1,55 @@
|
|||
{
|
||||
"name": "@discord-player/opus",
|
||||
"version": "7.2.0",
|
||||
"description": "A complete framework to simplify the implementation of music commands for Discord bots",
|
||||
"keywords": [
|
||||
"discord-player",
|
||||
"music",
|
||||
"bot",
|
||||
"discord.js",
|
||||
"javascript",
|
||||
"voip",
|
||||
"lavalink",
|
||||
"lavaplayer"
|
||||
],
|
||||
"publishConfig": {
|
||||
"access": "public"
|
||||
},
|
||||
"author": "Twilight <hello@twlite.dev>",
|
||||
"homepage": "https://discord-player.js.org",
|
||||
"license": "MIT",
|
||||
"main": "dist/index.js",
|
||||
"module": "dist/index.mjs",
|
||||
"types": "dist/index.d.ts",
|
||||
"files": [
|
||||
"dist"
|
||||
],
|
||||
"repository": {
|
||||
"type": "git",
|
||||
"url": "git+https://github.com/Androz2091/discord-player.git"
|
||||
},
|
||||
"scripts": {
|
||||
"build": "tsup && node ./scripts/esm-shim.cjs",
|
||||
"build:check": "tsc --noEmit",
|
||||
"lint": "eslint src --ext .ts --fix",
|
||||
"test": "vitest",
|
||||
"coverage": "vitest run --coverage"
|
||||
},
|
||||
"bugs": {
|
||||
"url": "https://github.com/Androz2091/discord-player/issues"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@discord-player/tsconfig": "^7.2.0",
|
||||
"@evan/opus": "^1.0.2",
|
||||
"tsup": "^8.3.5",
|
||||
"typescript": "^5.2.2",
|
||||
"vitest": "^0.34.6"
|
||||
},
|
||||
"typedoc": {
|
||||
"entryPoint": "./src/index.ts",
|
||||
"readmeFile": "./README.md",
|
||||
"tsconfig": "./tsconfig.json",
|
||||
"excludeExternals": true,
|
||||
"excludePrivate": true
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,21 @@
|
|||
MIT License
|
||||
|
||||
Copyright (c) 2020 Androz2091
|
||||
|
||||
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.
|
||||
|
|
@ -0,0 +1,74 @@
|
|||
# `@discord-player/utils`
|
||||
|
||||
Discord Player utilities
|
||||
|
||||
## Installation
|
||||
|
||||
```sh
|
||||
$ yarn add @discord-player/utils
|
||||
```
|
||||
|
||||
## Example
|
||||
|
||||
### Queue
|
||||
|
||||
```js
|
||||
import { Queue } from "@discord-player/utils";
|
||||
|
||||
// initialize queue with last-in-first-out strategy
|
||||
const lifo = new Queue<number>("LIFO");
|
||||
// initialize queue with first-in-first-out strategy
|
||||
const fifo = new Queue<number>("FIFO");
|
||||
|
||||
// add some data to the queue
|
||||
lifo.add([1, 2, 3, 4]);
|
||||
fifo.add([1, 2, 3, 4]);
|
||||
|
||||
// dispatches last inserted item from the queue
|
||||
console.log(lifo.dispatch()); // 4
|
||||
|
||||
// dispatches first inserted item from the queue
|
||||
console.log(fifo.dispatch()); // 1
|
||||
|
||||
console.log(lifo.at(0)); // 3
|
||||
console.log(fifo.at(0)); // 2
|
||||
```
|
||||
|
||||
### Collection
|
||||
|
||||
```ts
|
||||
import { Collection } from "@discord-player/utils";
|
||||
|
||||
// utility data structure based on Map
|
||||
const store = new Collection<string, number>();
|
||||
|
||||
store.set("foo", 1);
|
||||
|
||||
console.log(store.get("foo")); // 1
|
||||
store.delete("foo"); // true
|
||||
console.log(store.get("foo")); // undefined
|
||||
store.delete("foo"); // false
|
||||
```
|
||||
|
||||
### Key Mirror
|
||||
|
||||
```ts
|
||||
import { keyMirror } from "@discord-player/utils";
|
||||
|
||||
// creates read-only object with same value as the key
|
||||
const enums = keyMirror([
|
||||
"SUNDAY",
|
||||
"MONDAY",
|
||||
"TUESDAY"
|
||||
]);
|
||||
|
||||
console.log(enums);
|
||||
|
||||
/*
|
||||
{
|
||||
"SUNDAY": "SUNDAY",
|
||||
"MONDAY": "MONDAY",
|
||||
"TUESDAY": "TUESDAY"
|
||||
}
|
||||
*/
|
||||
```
|
||||
|
|
@ -0,0 +1,81 @@
|
|||
import { Collection as Collection$1 } from '@discordjs/collection';
|
||||
import { inspect } from 'util';
|
||||
|
||||
declare class Collection<K = unknown, V = unknown> extends Collection$1<K, V> {
|
||||
#private;
|
||||
/**
|
||||
* @returns {Array<V>} Array of this collection
|
||||
*/
|
||||
array(): V[];
|
||||
set(key: K, value: V): this;
|
||||
delete(key: K): boolean;
|
||||
}
|
||||
|
||||
type QueueStrategy = 'LIFO' | 'FIFO';
|
||||
type QueueItemFilter<T, R = boolean> = (value: T, idx: number, array: T[]) => R;
|
||||
declare class Queue<T = unknown> {
|
||||
strategy: QueueStrategy;
|
||||
store: T[];
|
||||
constructor(strategy?: QueueStrategy, initializer?: T[]);
|
||||
get data(): T[];
|
||||
static from<T>(data: T[], strategy?: QueueStrategy): Queue<T>;
|
||||
isFIFO(): boolean;
|
||||
isLIFO(): boolean;
|
||||
add(item: T | T[]): void;
|
||||
clear(): void;
|
||||
shuffle(): void;
|
||||
remove(itemFilter: QueueItemFilter<T>): void;
|
||||
removeOne(itemFilter: QueueItemFilter<T>): void;
|
||||
find(itemFilter: QueueItemFilter<T>): T | undefined;
|
||||
filter(itemFilter: QueueItemFilter<T>): T[];
|
||||
some(itemFilter: QueueItemFilter<T>): boolean;
|
||||
every(itemFilter: QueueItemFilter<T>): boolean;
|
||||
map<R = T>(itemFilter: QueueItemFilter<T, R>): R[];
|
||||
at(idx: number): T | undefined;
|
||||
dispatch(): T | undefined;
|
||||
clone(): Queue<T>;
|
||||
get size(): number;
|
||||
toString(): string;
|
||||
toArray(): T[];
|
||||
toJSON(): T[];
|
||||
[inspect.custom](): string;
|
||||
}
|
||||
|
||||
declare class EventEmitter<L extends ListenerSignature<L> = DefaultListener> {
|
||||
public static defaultMaxListeners: number;
|
||||
public constructor(options?: { captureRejections?: boolean });
|
||||
public addListener<U extends keyof L>(event: U, listener: L[U]): this;
|
||||
public prependListener<U extends keyof L>(event: U, listener: L[U]): this;
|
||||
public prependOnceListener<U extends keyof L>(event: U, listener: L[U]): this;
|
||||
public removeListener<U extends keyof L>(event: U, listener: L[U]): this;
|
||||
public removeAllListeners(event?: keyof L): this;
|
||||
public once<U extends keyof L>(event: U, listener: L[U]): this;
|
||||
public on<U extends keyof L>(event: U, listener: L[U]): this;
|
||||
public off<U extends keyof L>(event: U, listener: L[U]): this;
|
||||
public emit<U extends keyof L>(event: U, ...args: Parameters<L[U]>): boolean;
|
||||
public eventNames<U extends keyof L>(): U[];
|
||||
public listenerCount(type: keyof L): number;
|
||||
public listeners<U extends keyof L>(type: U): L[U][];
|
||||
public rawListeners<U extends keyof L>(type: U): L[U][];
|
||||
public getMaxListeners(): number;
|
||||
public setMaxListeners(n: number): this;
|
||||
}
|
||||
|
||||
type ListenerSignature<L> = {
|
||||
[E in keyof L]: (...args: any[]) => any;
|
||||
};
|
||||
|
||||
type DefaultListener = {
|
||||
[k: string]: (...args: any[]) => any;
|
||||
};
|
||||
|
||||
declare function createEnum<K extends string | number | symbol>(data: K[]): Readonly<Record<K, K>>;
|
||||
|
||||
type PlayerExceptionMessage = string | Record<string, unknown>;
|
||||
declare class PlayerException extends Error {
|
||||
constructor(message: PlayerExceptionMessage);
|
||||
}
|
||||
|
||||
declare const version: string;
|
||||
|
||||
export { Collection, type DefaultListener, EventEmitter, type ListenerSignature, PlayerException, type PlayerExceptionMessage, Queue, type QueueItemFilter, type QueueStrategy, createEnum, createEnum as keyMirror, version };
|
||||
|
|
@ -0,0 +1,81 @@
|
|||
import { Collection as Collection$1 } from '@discordjs/collection';
|
||||
import { inspect } from 'util';
|
||||
|
||||
declare class Collection<K = unknown, V = unknown> extends Collection$1<K, V> {
|
||||
#private;
|
||||
/**
|
||||
* @returns {Array<V>} Array of this collection
|
||||
*/
|
||||
array(): V[];
|
||||
set(key: K, value: V): this;
|
||||
delete(key: K): boolean;
|
||||
}
|
||||
|
||||
type QueueStrategy = 'LIFO' | 'FIFO';
|
||||
type QueueItemFilter<T, R = boolean> = (value: T, idx: number, array: T[]) => R;
|
||||
declare class Queue<T = unknown> {
|
||||
strategy: QueueStrategy;
|
||||
store: T[];
|
||||
constructor(strategy?: QueueStrategy, initializer?: T[]);
|
||||
get data(): T[];
|
||||
static from<T>(data: T[], strategy?: QueueStrategy): Queue<T>;
|
||||
isFIFO(): boolean;
|
||||
isLIFO(): boolean;
|
||||
add(item: T | T[]): void;
|
||||
clear(): void;
|
||||
shuffle(): void;
|
||||
remove(itemFilter: QueueItemFilter<T>): void;
|
||||
removeOne(itemFilter: QueueItemFilter<T>): void;
|
||||
find(itemFilter: QueueItemFilter<T>): T | undefined;
|
||||
filter(itemFilter: QueueItemFilter<T>): T[];
|
||||
some(itemFilter: QueueItemFilter<T>): boolean;
|
||||
every(itemFilter: QueueItemFilter<T>): boolean;
|
||||
map<R = T>(itemFilter: QueueItemFilter<T, R>): R[];
|
||||
at(idx: number): T | undefined;
|
||||
dispatch(): T | undefined;
|
||||
clone(): Queue<T>;
|
||||
get size(): number;
|
||||
toString(): string;
|
||||
toArray(): T[];
|
||||
toJSON(): T[];
|
||||
[inspect.custom](): string;
|
||||
}
|
||||
|
||||
declare class EventEmitter<L extends ListenerSignature<L> = DefaultListener> {
|
||||
public static defaultMaxListeners: number;
|
||||
public constructor(options?: { captureRejections?: boolean });
|
||||
public addListener<U extends keyof L>(event: U, listener: L[U]): this;
|
||||
public prependListener<U extends keyof L>(event: U, listener: L[U]): this;
|
||||
public prependOnceListener<U extends keyof L>(event: U, listener: L[U]): this;
|
||||
public removeListener<U extends keyof L>(event: U, listener: L[U]): this;
|
||||
public removeAllListeners(event?: keyof L): this;
|
||||
public once<U extends keyof L>(event: U, listener: L[U]): this;
|
||||
public on<U extends keyof L>(event: U, listener: L[U]): this;
|
||||
public off<U extends keyof L>(event: U, listener: L[U]): this;
|
||||
public emit<U extends keyof L>(event: U, ...args: Parameters<L[U]>): boolean;
|
||||
public eventNames<U extends keyof L>(): U[];
|
||||
public listenerCount(type: keyof L): number;
|
||||
public listeners<U extends keyof L>(type: U): L[U][];
|
||||
public rawListeners<U extends keyof L>(type: U): L[U][];
|
||||
public getMaxListeners(): number;
|
||||
public setMaxListeners(n: number): this;
|
||||
}
|
||||
|
||||
type ListenerSignature<L> = {
|
||||
[E in keyof L]: (...args: any[]) => any;
|
||||
};
|
||||
|
||||
type DefaultListener = {
|
||||
[k: string]: (...args: any[]) => any;
|
||||
};
|
||||
|
||||
declare function createEnum<K extends string | number | symbol>(data: K[]): Readonly<Record<K, K>>;
|
||||
|
||||
type PlayerExceptionMessage = string | Record<string, unknown>;
|
||||
declare class PlayerException extends Error {
|
||||
constructor(message: PlayerExceptionMessage);
|
||||
}
|
||||
|
||||
declare const version: string;
|
||||
|
||||
export { Collection, type DefaultListener, EventEmitter, type ListenerSignature, PlayerException, type PlayerExceptionMessage, Queue, type QueueItemFilter, type QueueStrategy, createEnum, createEnum as keyMirror, version };
|
||||
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
|
|
@ -0,0 +1,52 @@
|
|||
{
|
||||
"name": "@discord-player/utils",
|
||||
"version": "7.2.0",
|
||||
"description": "Discord Player Utilities",
|
||||
"keywords": [
|
||||
"discord-player"
|
||||
],
|
||||
"author": "Twilight <hello@twlite.dev>",
|
||||
"homepage": "https://discord-player.js.org",
|
||||
"license": "MIT",
|
||||
"main": "dist/index.js",
|
||||
"types": "dist/index.d.ts",
|
||||
"module": "dist/index.mjs",
|
||||
"publishConfig": {
|
||||
"access": "public"
|
||||
},
|
||||
"directories": {
|
||||
"src": "src"
|
||||
},
|
||||
"files": [
|
||||
"dist"
|
||||
],
|
||||
"repository": {
|
||||
"type": "git",
|
||||
"url": "git+https://github.com/Androz2091/discord-player.git"
|
||||
},
|
||||
"scripts": {
|
||||
"build:check": "tsc --noEmit",
|
||||
"build": "tsup",
|
||||
"test": "vitest",
|
||||
"coverage": "vitest run --coverage"
|
||||
},
|
||||
"bugs": {
|
||||
"url": "https://github.com/Androz2091/discord-player/issues"
|
||||
},
|
||||
"dependencies": {
|
||||
"@discordjs/collection": "^1.1.0"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@discord-player/tsconfig": "^7.2.0",
|
||||
"tsup": "^8.3.5",
|
||||
"typescript": "^5.2.2",
|
||||
"vitest": "^0.34.6"
|
||||
},
|
||||
"typedoc": {
|
||||
"entryPoint": "./src/index.ts",
|
||||
"readmeFile": "./README.md",
|
||||
"tsconfig": "./tsconfig.json",
|
||||
"excludeExternals": true,
|
||||
"excludePrivate": true
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,191 @@
|
|||
Apache License
|
||||
Version 2.0, January 2004
|
||||
http://www.apache.org/licenses/
|
||||
|
||||
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
|
||||
|
||||
1. Definitions.
|
||||
|
||||
"License" shall mean the terms and conditions for use, reproduction,
|
||||
and distribution as defined by Sections 1 through 9 of this document.
|
||||
|
||||
"Licensor" shall mean the copyright owner or entity authorized by
|
||||
the copyright owner that is granting the License.
|
||||
|
||||
"Legal Entity" shall mean the union of the acting entity and all
|
||||
other entities that control, are controlled by, or are under common
|
||||
control with that entity. For the purposes of this definition,
|
||||
"control" means (i) the power, direct or indirect, to cause the
|
||||
direction or management of such entity, whether by contract or
|
||||
otherwise, or (ii) ownership of fifty percent (50%) or more of the
|
||||
outstanding shares, or (iii) beneficial ownership of such entity.
|
||||
|
||||
"You" (or "Your") shall mean an individual or Legal Entity
|
||||
exercising permissions granted by this License.
|
||||
|
||||
"Source" form shall mean the preferred form for making modifications,
|
||||
including but not limited to software source code, documentation
|
||||
source, and configuration files.
|
||||
|
||||
"Object" form shall mean any form resulting from mechanical
|
||||
transformation or translation of a Source form, including but
|
||||
not limited to compiled object code, generated documentation,
|
||||
and conversions to other media types.
|
||||
|
||||
"Work" shall mean the work of authorship, whether in Source or
|
||||
Object form, made available under the License, as indicated by a
|
||||
copyright notice that is included in or attached to the work
|
||||
(an example is provided in the Appendix below).
|
||||
|
||||
"Derivative Works" shall mean any work, whether in Source or Object
|
||||
form, that is based on (or derived from) the Work and for which the
|
||||
editorial revisions, annotations, elaborations, or other modifications
|
||||
represent, as a whole, an original work of authorship. For the purposes
|
||||
of this License, Derivative Works shall not include works that remain
|
||||
separable from, or merely link (or bind by name) to the interfaces of,
|
||||
the Work and Derivative Works thereof.
|
||||
|
||||
"Contribution" shall mean any work of authorship, including
|
||||
the original version of the Work and any modifications or additions
|
||||
to that Work or Derivative Works thereof, that is intentionally
|
||||
submitted to Licensor for inclusion in the Work by the copyright owner
|
||||
or by an individual or Legal Entity authorized to submit on behalf of
|
||||
the copyright owner. For the purposes of this definition, "submitted"
|
||||
means any form of electronic, verbal, or written communication sent
|
||||
to the Licensor or its representatives, including but not limited to
|
||||
communication on electronic mailing lists, source code control systems,
|
||||
and issue tracking systems that are managed by, or on behalf of, the
|
||||
Licensor for the purpose of discussing and improving the Work, but
|
||||
excluding communication that is conspicuously marked or otherwise
|
||||
designated in writing by the copyright owner as "Not a Contribution."
|
||||
|
||||
"Contributor" shall mean Licensor and any individual or Legal Entity
|
||||
on behalf of whom a Contribution has been received by Licensor and
|
||||
subsequently incorporated within the Work.
|
||||
|
||||
2. Grant of Copyright License. Subject to the terms and conditions of
|
||||
this License, each Contributor hereby grants to You a perpetual,
|
||||
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
||||
copyright license to reproduce, prepare Derivative Works of,
|
||||
publicly display, publicly perform, sublicense, and distribute the
|
||||
Work and such Derivative Works in Source or Object form.
|
||||
|
||||
3. Grant of Patent License. Subject to the terms and conditions of
|
||||
this License, each Contributor hereby grants to You a perpetual,
|
||||
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
||||
(except as stated in this section) patent license to make, have made,
|
||||
use, offer to sell, sell, import, and otherwise transfer the Work,
|
||||
where such license applies only to those patent claims licensable
|
||||
by such Contributor that are necessarily infringed by their
|
||||
Contribution(s) alone or by combination of their Contribution(s)
|
||||
with the Work to which such Contribution(s) was submitted. If You
|
||||
institute patent litigation against any entity (including a
|
||||
cross-claim or counterclaim in a lawsuit) alleging that the Work
|
||||
or a Contribution incorporated within the Work constitutes direct
|
||||
or contributory patent infringement, then any patent licenses
|
||||
granted to You under this License for that Work shall terminate
|
||||
as of the date such litigation is filed.
|
||||
|
||||
4. Redistribution. You may reproduce and distribute copies of the
|
||||
Work or Derivative Works thereof in any medium, with or without
|
||||
modifications, and in Source or Object form, provided that You
|
||||
meet the following conditions:
|
||||
|
||||
(a) You must give any other recipients of the Work or
|
||||
Derivative Works a copy of this License; and
|
||||
|
||||
(b) You must cause any modified files to carry prominent notices
|
||||
stating that You changed the files; and
|
||||
|
||||
(c) You must retain, in the Source form of any Derivative Works
|
||||
that You distribute, all copyright, patent, trademark, and
|
||||
attribution notices from the Source form of the Work,
|
||||
excluding those notices that do not pertain to any part of
|
||||
the Derivative Works; and
|
||||
|
||||
(d) If the Work includes a "NOTICE" text file as part of its
|
||||
distribution, then any Derivative Works that You distribute must
|
||||
include a readable copy of the attribution notices contained
|
||||
within such NOTICE file, excluding those notices that do not
|
||||
pertain to any part of the Derivative Works, in at least one
|
||||
of the following places: within a NOTICE text file distributed
|
||||
as part of the Derivative Works; within the Source form or
|
||||
documentation, if provided along with the Derivative Works; or,
|
||||
within a display generated by the Derivative Works, if and
|
||||
wherever such third-party notices normally appear. The contents
|
||||
of the NOTICE file are for informational purposes only and
|
||||
do not modify the License. You may add Your own attribution
|
||||
notices within Derivative Works that You distribute, alongside
|
||||
or as an addendum to the NOTICE text from the Work, provided
|
||||
that such additional attribution notices cannot be construed
|
||||
as modifying the License.
|
||||
|
||||
You may add Your own copyright statement to Your modifications and
|
||||
may provide additional or different license terms and conditions
|
||||
for use, reproduction, or distribution of Your modifications, or
|
||||
for any such Derivative Works as a whole, provided Your use,
|
||||
reproduction, and distribution of the Work otherwise complies with
|
||||
the conditions stated in this License.
|
||||
|
||||
5. Submission of Contributions. Unless You explicitly state otherwise,
|
||||
any Contribution intentionally submitted for inclusion in the Work
|
||||
by You to the Licensor shall be under the terms and conditions of
|
||||
this License, without any additional terms or conditions.
|
||||
Notwithstanding the above, nothing herein shall supersede or modify
|
||||
the terms of any separate license agreement you may have executed
|
||||
with Licensor regarding such Contributions.
|
||||
|
||||
6. Trademarks. This License does not grant permission to use the trade
|
||||
names, trademarks, service marks, or product names of the Licensor,
|
||||
except as required for reasonable and customary use in describing the
|
||||
origin of the Work and reproducing the content of the NOTICE file.
|
||||
|
||||
7. Disclaimer of Warranty. Unless required by applicable law or
|
||||
agreed to in writing, Licensor provides the Work (and each
|
||||
Contributor provides its Contributions) on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
|
||||
implied, including, without limitation, any warranties or conditions
|
||||
of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
|
||||
PARTICULAR PURPOSE. You are solely responsible for determining the
|
||||
appropriateness of using or redistributing the Work and assume any
|
||||
risks associated with Your exercise of permissions under this License.
|
||||
|
||||
8. Limitation of Liability. In no event and under no legal theory,
|
||||
whether in tort (including negligence), contract, or otherwise,
|
||||
unless required by applicable law (such as deliberate and grossly
|
||||
negligent acts) or agreed to in writing, shall any Contributor be
|
||||
liable to You for damages, including any direct, indirect, special,
|
||||
incidental, or consequential damages of any character arising as a
|
||||
result of this License or out of the use or inability to use the
|
||||
Work (including but not limited to damages for loss of goodwill,
|
||||
work stoppage, computer failure or malfunction, or any and all
|
||||
other commercial damages or losses), even if such Contributor
|
||||
has been advised of the possibility of such damages.
|
||||
|
||||
9. Accepting Warranty or Additional Liability. While redistributing
|
||||
the Work or Derivative Works thereof, You may choose to offer,
|
||||
and charge a fee for, acceptance of support, warranty, indemnity,
|
||||
or other liability obligations and/or rights consistent with this
|
||||
License. However, in accepting such obligations, You may act only
|
||||
on Your own behalf and on Your sole responsibility, not on behalf
|
||||
of any other Contributor, and only if You agree to indemnify,
|
||||
defend, and hold each Contributor harmless for any liability
|
||||
incurred by, or claims asserted against, such Contributor by reason
|
||||
of your accepting any such warranty or additional liability.
|
||||
|
||||
END OF TERMS AND CONDITIONS
|
||||
|
||||
Copyright 2021 Noel Buechler
|
||||
Copyright 2021 Vlad Frangu
|
||||
|
||||
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.
|
||||
|
|
@ -0,0 +1,73 @@
|
|||
<div align="center">
|
||||
<br />
|
||||
<p>
|
||||
<a href="https://discord.js.org"><img src="https://discord.js.org/static/logo.svg" width="546" alt="discord.js" /></a>
|
||||
</p>
|
||||
<br />
|
||||
<p>
|
||||
<a href="https://discord.gg/djs"><img src="https://img.shields.io/discord/222078108977594368?color=5865F2&logo=discord&logoColor=white" alt="Discord server" /></a>
|
||||
<a href="https://www.npmjs.com/package/@discordjs/builders"><img src="https://img.shields.io/npm/v/@discordjs/builders.svg?maxAge=3600" alt="npm version" /></a>
|
||||
<a href="https://www.npmjs.com/package/@discordjs/builders"><img src="https://img.shields.io/npm/dt/@discordjs/builders.svg?maxAge=3600" alt="npm downloads" /></a>
|
||||
<a href="https://github.com/discordjs/discord.js/actions"><img src="https://github.com/discordjs/discord.js/actions/workflows/test.yml/badge.svg" alt="Build status" /></a>
|
||||
<a href="https://github.com/discordjs/discord.js/commits/main/packages/builders"><img alt="Last commit." src="https://img.shields.io/github/last-commit/discordjs/discord.js?logo=github&logoColor=ffffff&path=packages%2Fbuilders"></a>
|
||||
<a href="https://codecov.io/gh/discordjs/discord.js"><img src="https://codecov.io/gh/discordjs/discord.js/branch/main/graph/badge.svg?precision=2&flag=builders" alt="Code coverage" /></a>
|
||||
</p>
|
||||
<p>
|
||||
<a href="https://vercel.com/?utm_source=discordjs&utm_campaign=oss"><img src="https://raw.githubusercontent.com/discordjs/discord.js/main/.github/powered-by-vercel.svg" alt="Vercel" /></a>
|
||||
<a href="https://www.cloudflare.com"><img src="https://raw.githubusercontent.com/discordjs/discord.js/main/.github/powered-by-workers.png" alt="Cloudflare Workers" height="44" /></a>
|
||||
</p>
|
||||
</div>
|
||||
|
||||
## About
|
||||
|
||||
`@discordjs/builders` is a utility package for easily building Discord API payloads.
|
||||
|
||||
## Installation
|
||||
|
||||
**Node.js 16.11.0 or newer is required.**
|
||||
|
||||
```sh
|
||||
npm install @discordjs/builders
|
||||
yarn add @discordjs/builders
|
||||
pnpm add @discordjs/builders
|
||||
```
|
||||
|
||||
## Examples
|
||||
|
||||
You can find examples of how to use the builders in the [Slash Command Builders][example] examples.
|
||||
|
||||
## Links
|
||||
|
||||
- [Website][website] ([source][website-source])
|
||||
- [Documentation][documentation]
|
||||
- [Guide][guide] ([source][guide-source])
|
||||
Also see the v13 to v14 [Update Guide][guide-update], which includes updated and removed items from the library.
|
||||
- [discord.js Discord server][discord]
|
||||
- [Discord API Discord server][discord-api]
|
||||
- [GitHub][source]
|
||||
- [npm][npm]
|
||||
- [Related libraries][related-libs]
|
||||
|
||||
## Contributing
|
||||
|
||||
Before creating an issue, please ensure that it hasn't already been reported/suggested, and double-check the
|
||||
[documentation][documentation].
|
||||
See [the contribution guide][contributing] if you'd like to submit a PR.
|
||||
|
||||
## Help
|
||||
|
||||
If you don't understand something in the documentation, you are experiencing problems, or you just need a gentle nudge in the right direction, please don't hesitate to join our official [discord.js Server][discord].
|
||||
|
||||
[example]: https://github.com/discordjs/discord.js/blob/main/packages/builders/docs/examples/Slash%20Command%20Builders.md
|
||||
[website]: https://discord.js.org
|
||||
[website-source]: https://github.com/discordjs/discord.js/tree/main/apps/website
|
||||
[documentation]: https://discord.js.org/docs/packages/builders/stable
|
||||
[guide]: https://discordjs.guide/
|
||||
[guide-source]: https://github.com/discordjs/guide
|
||||
[guide-update]: https://discordjs.guide/additional-info/changes-in-v14.html
|
||||
[discord]: https://discord.gg/djs
|
||||
[discord-api]: https://discord.gg/discord-api
|
||||
[source]: https://github.com/discordjs/discord.js/tree/main/packages/builders
|
||||
[npm]: https://www.npmjs.com/package/@discordjs/builders
|
||||
[related-libs]: https://discord.com/developers/docs/topics/community-resources#libraries
|
||||
[contributing]: https://github.com/discordjs/discord.js/blob/main/.github/CONTRIBUTING.md
|
||||
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because one or more lines are too long
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue