diff --git a/README.md b/README.md index a334869..71f96b0 100644 --- a/README.md +++ b/README.md @@ -4,7 +4,7 @@ ```shell # install ffmpeg -npm install @ffmpeg/ffmpeg @ffmpeg/util +npm install @ffmpeg/ffmpeg ``` @@ -43,18 +43,29 @@ const hls2mp4 = new Hls2Mp4({ /** * the base url of ffmpeg */ - ffmpegBaseUrl = 'https://unpkg.com/@ffmpeg/core@0.12.2/dist/umd' -}, (type, progress) => { - // type = 0 => load FFmpeg - // type = 1 => parse m3u8 - // type = 2 => downloading ts - // type = 3 => merge ts -}, (error) => { - // has error + ffmpegBaseUrl = 'https://unpkg.com/@ffmpeg/core@0.12.2/dist/umd', + /** + * progress callback + */ + onProgress?: (type, progress) => { + // type = 0 => load FFmpeg + // type = 1 => parse m3u8 + // type = 2 => downloading ts + // type = 3 => merge ts + }; + /** + * error callback + */ + onError?: (error) => {}; }); const buffer = await hls2mp4.download('your m3u8 url') -hls2mp4.saveToFile(buffer, 'test.mp4') +if (buffer) { + hls2mp4.saveToFile(buffer, 'test.mp4') +} +else { + // download failed +} ``` #### as script diff --git a/dist/README.md b/dist/README.md index a334869..71f96b0 100644 --- a/dist/README.md +++ b/dist/README.md @@ -4,7 +4,7 @@ ```shell # install ffmpeg -npm install @ffmpeg/ffmpeg @ffmpeg/util +npm install @ffmpeg/ffmpeg ``` @@ -43,18 +43,29 @@ const hls2mp4 = new Hls2Mp4({ /** * the base url of ffmpeg */ - ffmpegBaseUrl = 'https://unpkg.com/@ffmpeg/core@0.12.2/dist/umd' -}, (type, progress) => { - // type = 0 => load FFmpeg - // type = 1 => parse m3u8 - // type = 2 => downloading ts - // type = 3 => merge ts -}, (error) => { - // has error + ffmpegBaseUrl = 'https://unpkg.com/@ffmpeg/core@0.12.2/dist/umd', + /** + * progress callback + */ + onProgress?: (type, progress) => { + // type = 0 => load FFmpeg + // type = 1 => parse m3u8 + // type = 2 => downloading ts + // type = 3 => merge ts + }; + /** + * error callback + */ + onError?: (error) => {}; }); const buffer = await hls2mp4.download('your m3u8 url') -hls2mp4.saveToFile(buffer, 'test.mp4') +if (buffer) { + hls2mp4.saveToFile(buffer, 'test.mp4') +} +else { + // download failed +} ``` #### as script diff --git a/dist/hls2mp4.cjs b/dist/hls2mp4.cjs index da4a2c0..6aafe01 100644 --- a/dist/hls2mp4.cjs +++ b/dist/hls2mp4.cjs @@ -3,7 +3,6 @@ Object.defineProperty(exports, '__esModule', { value: true }); var ffmpeg = require('@ffmpeg/ffmpeg'); -var util = require('@ffmpeg/util'); /****************************************************************************** Copyright (c) Microsoft Corporation. @@ -882,6 +881,35 @@ exports.TaskType = void 0; TaskType[TaskType["downloadTs"] = 2] = "downloadTs"; TaskType[TaskType["mergeTs"] = 3] = "mergeTs"; })(exports.TaskType || (exports.TaskType = {})); +function fetchFile(url) { + return __awaiter(this, void 0, void 0, function () { + var response, arrayBuffer; + return __generator(this, function (_a) { + switch (_a.label) { + case 0: return [4 /*yield*/, fetch(url)]; + case 1: + response = _a.sent(); + return [4 /*yield*/, response.arrayBuffer()]; + case 2: + arrayBuffer = _a.sent(); + return [2 /*return*/, new Uint8Array(arrayBuffer)]; + } + }); + }); +} +function toBlobURL(url, type) { + return __awaiter(this, void 0, void 0, function () { + var data; + return __generator(this, function (_a) { + switch (_a.label) { + case 0: return [4 /*yield*/, fetchFile(url)]; + case 1: + data = _a.sent(); + return [2 /*return*/, URL.createObjectURL(new Blob([data.buffer], { type: type }))]; + } + }); + }); +} function createFileUrlRegExp(ext, flags) { return new RegExp('(https?://)?[\\w:\\.\\-\\/]+?\\.' + ext, flags); } @@ -893,8 +921,18 @@ function parseUrl(url, path) { } var ffmpegDefaultBaseUrl = 'https://unpkg.com/@ffmpeg/core@0.12.2/dist/umd'; var Hls2Mp4 = /** @class */ (function () { - function Hls2Mp4(_a, onProgress, onError) { - var _b = _a.maxRetry, maxRetry = _b === void 0 ? 3 : _b, _c = _a.tsDownloadConcurrency, tsDownloadConcurrency = _c === void 0 ? 10 : _c, _d = _a.ffmpegBaseUrl, ffmpegBaseUrl = _d === void 0 ? ffmpegDefaultBaseUrl : _d; + function Hls2Mp4(_a, + /** + * @deprecated + * will be removed in the feature, please use options.onProgress instead + */ + _onProgress, + /** + * @deprecated + * will be removed in the feature, please use options.onError instead + */ + _onError) { + var _b = _a.maxRetry, maxRetry = _b === void 0 ? 3 : _b, _c = _a.tsDownloadConcurrency, tsDownloadConcurrency = _c === void 0 ? 10 : _c, _d = _a.ffmpegBaseUrl, ffmpegBaseUrl = _d === void 0 ? ffmpegDefaultBaseUrl : _d, onProgress = _a.onProgress, onError = _a.onError; this.loadRetryTime = 0; this.totalSegments = 0; this.savedSegments = 0; @@ -902,8 +940,8 @@ var Hls2Mp4 = /** @class */ (function () { this.maxRetry = maxRetry; this.tsDownloadConcurrency = tsDownloadConcurrency; this.ffmpegBaseUrl = ffmpegBaseUrl; - this.onProgress = onProgress; - this.onError = onError; + this.onProgress = onProgress !== null && onProgress !== void 0 ? onProgress : _onProgress; + this.onError = onError !== null && onError !== void 0 ? onError : _onError; } Hls2Mp4.prototype.transformBuffer = function (buffer) { if (buffer[0] === 0x47) { @@ -946,7 +984,7 @@ var Hls2Mp4 = /** @class */ (function () { case 1: playList = _d.sent(); return [3 /*break*/, 4]; - case 2: return [4 /*yield*/, util.fetchFile(url).then(function (data) { return aesjs.utils.utf8.fromBytes(data); })]; + case 2: return [4 /*yield*/, fetchFile(url).then(function (data) { return aesjs.utils.utf8.fromBytes(data); })]; case 3: playList = _d.sent(); _d.label = 4; @@ -1013,7 +1051,7 @@ var Hls2Mp4 = /** @class */ (function () { var _b, done, data, fileName; return __generator(this, function (_c) { switch (_c.label) { - case 0: return [4 /*yield*/, this.loopLoadFile(function () { return util.fetchFile(url); })]; + case 0: return [4 /*yield*/, this.loopLoadFile(function () { return fetchFile(url); })]; case 1: _b = _c.sent(), done = _b.done, data = _b.data; if (done) { @@ -1228,10 +1266,10 @@ var Hls2Mp4 = /** @class */ (function () { case 0: (_a = this.onProgress) === null || _a === void 0 ? void 0 : _a.call(this, exports.TaskType.loadFFmeg, 0); baseUrl = this.ffmpegBaseUrl; - return [4 /*yield*/, util.toBlobURL("".concat(baseUrl, "/ffmpeg-core.js"), 'text/javascript')]; + return [4 /*yield*/, toBlobURL("".concat(baseUrl, "/ffmpeg-core.js"), 'text/javascript')]; case 1: coreURL = _c.sent(); - return [4 /*yield*/, util.toBlobURL("".concat(baseUrl, "/ffmpeg-core.wasm"), 'application/wasm') + return [4 /*yield*/, toBlobURL("".concat(baseUrl, "/ffmpeg-core.wasm"), 'application/wasm') // workerURL = workerURL ?? await toBlobURL(`${baseUrl}/ffmpeg-core.worker.js`, 'text/javascript') ]; case 2: @@ -1295,7 +1333,10 @@ var Hls2Mp4 = /** @class */ (function () { anchor.click(); setTimeout(function () { return URL.revokeObjectURL(objectUrl); }, 100); }; - Hls2Mp4.version = '1.2.7'; + Hls2Mp4.prototype.destroy = function () { + this.ffmpeg.terminate(); + }; + Hls2Mp4.version = '1.2.8'; Hls2Mp4.TaskType = exports.TaskType; return Hls2Mp4; }()); diff --git a/dist/hls2mp4.js b/dist/hls2mp4.js index 4fb0020..5411daa 100644 --- a/dist/hls2mp4.js +++ b/dist/hls2mp4.js @@ -1,4 +1,4 @@ -var Hls2Mp4 = (function (exports, ffmpeg, util) { +var Hls2Mp4 = (function (exports, ffmpeg) { 'use strict'; /****************************************************************************** @@ -878,6 +878,35 @@ var Hls2Mp4 = (function (exports, ffmpeg, util) { TaskType[TaskType["downloadTs"] = 2] = "downloadTs"; TaskType[TaskType["mergeTs"] = 3] = "mergeTs"; })(exports.TaskType || (exports.TaskType = {})); + function fetchFile(url) { + return __awaiter(this, void 0, void 0, function () { + var response, arrayBuffer; + return __generator(this, function (_a) { + switch (_a.label) { + case 0: return [4 /*yield*/, fetch(url)]; + case 1: + response = _a.sent(); + return [4 /*yield*/, response.arrayBuffer()]; + case 2: + arrayBuffer = _a.sent(); + return [2 /*return*/, new Uint8Array(arrayBuffer)]; + } + }); + }); + } + function toBlobURL(url, type) { + return __awaiter(this, void 0, void 0, function () { + var data; + return __generator(this, function (_a) { + switch (_a.label) { + case 0: return [4 /*yield*/, fetchFile(url)]; + case 1: + data = _a.sent(); + return [2 /*return*/, URL.createObjectURL(new Blob([data.buffer], { type: type }))]; + } + }); + }); + } function createFileUrlRegExp(ext, flags) { return new RegExp('(https?://)?[\\w:\\.\\-\\/]+?\\.' + ext, flags); } @@ -889,8 +918,18 @@ var Hls2Mp4 = (function (exports, ffmpeg, util) { } var ffmpegDefaultBaseUrl = 'https://unpkg.com/@ffmpeg/core@0.12.2/dist/umd'; var Hls2Mp4 = /** @class */ (function () { - function Hls2Mp4(_a, onProgress, onError) { - var _b = _a.maxRetry, maxRetry = _b === void 0 ? 3 : _b, _c = _a.tsDownloadConcurrency, tsDownloadConcurrency = _c === void 0 ? 10 : _c, _d = _a.ffmpegBaseUrl, ffmpegBaseUrl = _d === void 0 ? ffmpegDefaultBaseUrl : _d; + function Hls2Mp4(_a, + /** + * @deprecated + * will be removed in the feature, please use options.onProgress instead + */ + _onProgress, + /** + * @deprecated + * will be removed in the feature, please use options.onError instead + */ + _onError) { + var _b = _a.maxRetry, maxRetry = _b === void 0 ? 3 : _b, _c = _a.tsDownloadConcurrency, tsDownloadConcurrency = _c === void 0 ? 10 : _c, _d = _a.ffmpegBaseUrl, ffmpegBaseUrl = _d === void 0 ? ffmpegDefaultBaseUrl : _d, onProgress = _a.onProgress, onError = _a.onError; this.loadRetryTime = 0; this.totalSegments = 0; this.savedSegments = 0; @@ -898,8 +937,8 @@ var Hls2Mp4 = (function (exports, ffmpeg, util) { this.maxRetry = maxRetry; this.tsDownloadConcurrency = tsDownloadConcurrency; this.ffmpegBaseUrl = ffmpegBaseUrl; - this.onProgress = onProgress; - this.onError = onError; + this.onProgress = onProgress !== null && onProgress !== void 0 ? onProgress : _onProgress; + this.onError = onError !== null && onError !== void 0 ? onError : _onError; } Hls2Mp4.prototype.transformBuffer = function (buffer) { if (buffer[0] === 0x47) { @@ -942,7 +981,7 @@ var Hls2Mp4 = (function (exports, ffmpeg, util) { case 1: playList = _d.sent(); return [3 /*break*/, 4]; - case 2: return [4 /*yield*/, util.fetchFile(url).then(function (data) { return aesjs.utils.utf8.fromBytes(data); })]; + case 2: return [4 /*yield*/, fetchFile(url).then(function (data) { return aesjs.utils.utf8.fromBytes(data); })]; case 3: playList = _d.sent(); _d.label = 4; @@ -1009,7 +1048,7 @@ var Hls2Mp4 = (function (exports, ffmpeg, util) { var _b, done, data, fileName; return __generator(this, function (_c) { switch (_c.label) { - case 0: return [4 /*yield*/, this.loopLoadFile(function () { return util.fetchFile(url); })]; + case 0: return [4 /*yield*/, this.loopLoadFile(function () { return fetchFile(url); })]; case 1: _b = _c.sent(), done = _b.done, data = _b.data; if (done) { @@ -1224,10 +1263,10 @@ var Hls2Mp4 = (function (exports, ffmpeg, util) { case 0: (_a = this.onProgress) === null || _a === void 0 ? void 0 : _a.call(this, exports.TaskType.loadFFmeg, 0); baseUrl = this.ffmpegBaseUrl; - return [4 /*yield*/, util.toBlobURL("".concat(baseUrl, "/ffmpeg-core.js"), 'text/javascript')]; + return [4 /*yield*/, toBlobURL("".concat(baseUrl, "/ffmpeg-core.js"), 'text/javascript')]; case 1: coreURL = _c.sent(); - return [4 /*yield*/, util.toBlobURL("".concat(baseUrl, "/ffmpeg-core.wasm"), 'application/wasm') + return [4 /*yield*/, toBlobURL("".concat(baseUrl, "/ffmpeg-core.wasm"), 'application/wasm') // workerURL = workerURL ?? await toBlobURL(`${baseUrl}/ffmpeg-core.worker.js`, 'text/javascript') ]; case 2: @@ -1291,7 +1330,10 @@ var Hls2Mp4 = (function (exports, ffmpeg, util) { anchor.click(); setTimeout(function () { return URL.revokeObjectURL(objectUrl); }, 100); }; - Hls2Mp4.version = '1.2.7'; + Hls2Mp4.prototype.destroy = function () { + this.ffmpeg.terminate(); + }; + Hls2Mp4.version = '1.2.8'; Hls2Mp4.TaskType = exports.TaskType; return Hls2Mp4; }()); @@ -1302,4 +1344,4 @@ var Hls2Mp4 = (function (exports, ffmpeg, util) { return exports; -})({}, FFmpeg, util); +})({}, FFmpeg); diff --git a/dist/hls2mp4.umd.js b/dist/hls2mp4.umd.js index 0f4bbbe..5307c6d 100644 --- a/dist/hls2mp4.umd.js +++ b/dist/hls2mp4.umd.js @@ -1,8 +1,8 @@ (function (global, factory) { - typeof exports === 'object' && typeof module !== 'undefined' ? factory(exports, require('@ffmpeg/ffmpeg'), require('@ffmpeg/util')) : - typeof define === 'function' && define.amd ? define(['exports', '@ffmpeg/ffmpeg', '@ffmpeg/util'], factory) : - (global = typeof globalThis !== 'undefined' ? globalThis : global || self, factory(global.Hls2Mp4 = {}, global.FFmpeg, global.util)); -})(this, (function (exports, ffmpeg, util) { 'use strict'; + typeof exports === 'object' && typeof module !== 'undefined' ? factory(exports, require('@ffmpeg/ffmpeg')) : + typeof define === 'function' && define.amd ? define(['exports', '@ffmpeg/ffmpeg'], factory) : + (global = typeof globalThis !== 'undefined' ? globalThis : global || self, factory(global.Hls2Mp4 = {}, global.FFmpeg)); +})(this, (function (exports, ffmpeg) { 'use strict'; /****************************************************************************** Copyright (c) Microsoft Corporation. @@ -881,6 +881,35 @@ TaskType[TaskType["downloadTs"] = 2] = "downloadTs"; TaskType[TaskType["mergeTs"] = 3] = "mergeTs"; })(exports.TaskType || (exports.TaskType = {})); + function fetchFile(url) { + return __awaiter(this, void 0, void 0, function () { + var response, arrayBuffer; + return __generator(this, function (_a) { + switch (_a.label) { + case 0: return [4 /*yield*/, fetch(url)]; + case 1: + response = _a.sent(); + return [4 /*yield*/, response.arrayBuffer()]; + case 2: + arrayBuffer = _a.sent(); + return [2 /*return*/, new Uint8Array(arrayBuffer)]; + } + }); + }); + } + function toBlobURL(url, type) { + return __awaiter(this, void 0, void 0, function () { + var data; + return __generator(this, function (_a) { + switch (_a.label) { + case 0: return [4 /*yield*/, fetchFile(url)]; + case 1: + data = _a.sent(); + return [2 /*return*/, URL.createObjectURL(new Blob([data.buffer], { type: type }))]; + } + }); + }); + } function createFileUrlRegExp(ext, flags) { return new RegExp('(https?://)?[\\w:\\.\\-\\/]+?\\.' + ext, flags); } @@ -892,8 +921,18 @@ } var ffmpegDefaultBaseUrl = 'https://unpkg.com/@ffmpeg/core@0.12.2/dist/umd'; var Hls2Mp4 = /** @class */ (function () { - function Hls2Mp4(_a, onProgress, onError) { - var _b = _a.maxRetry, maxRetry = _b === void 0 ? 3 : _b, _c = _a.tsDownloadConcurrency, tsDownloadConcurrency = _c === void 0 ? 10 : _c, _d = _a.ffmpegBaseUrl, ffmpegBaseUrl = _d === void 0 ? ffmpegDefaultBaseUrl : _d; + function Hls2Mp4(_a, + /** + * @deprecated + * will be removed in the feature, please use options.onProgress instead + */ + _onProgress, + /** + * @deprecated + * will be removed in the feature, please use options.onError instead + */ + _onError) { + var _b = _a.maxRetry, maxRetry = _b === void 0 ? 3 : _b, _c = _a.tsDownloadConcurrency, tsDownloadConcurrency = _c === void 0 ? 10 : _c, _d = _a.ffmpegBaseUrl, ffmpegBaseUrl = _d === void 0 ? ffmpegDefaultBaseUrl : _d, onProgress = _a.onProgress, onError = _a.onError; this.loadRetryTime = 0; this.totalSegments = 0; this.savedSegments = 0; @@ -901,8 +940,8 @@ this.maxRetry = maxRetry; this.tsDownloadConcurrency = tsDownloadConcurrency; this.ffmpegBaseUrl = ffmpegBaseUrl; - this.onProgress = onProgress; - this.onError = onError; + this.onProgress = onProgress !== null && onProgress !== void 0 ? onProgress : _onProgress; + this.onError = onError !== null && onError !== void 0 ? onError : _onError; } Hls2Mp4.prototype.transformBuffer = function (buffer) { if (buffer[0] === 0x47) { @@ -945,7 +984,7 @@ case 1: playList = _d.sent(); return [3 /*break*/, 4]; - case 2: return [4 /*yield*/, util.fetchFile(url).then(function (data) { return aesjs.utils.utf8.fromBytes(data); })]; + case 2: return [4 /*yield*/, fetchFile(url).then(function (data) { return aesjs.utils.utf8.fromBytes(data); })]; case 3: playList = _d.sent(); _d.label = 4; @@ -1012,7 +1051,7 @@ var _b, done, data, fileName; return __generator(this, function (_c) { switch (_c.label) { - case 0: return [4 /*yield*/, this.loopLoadFile(function () { return util.fetchFile(url); })]; + case 0: return [4 /*yield*/, this.loopLoadFile(function () { return fetchFile(url); })]; case 1: _b = _c.sent(), done = _b.done, data = _b.data; if (done) { @@ -1227,10 +1266,10 @@ case 0: (_a = this.onProgress) === null || _a === void 0 ? void 0 : _a.call(this, exports.TaskType.loadFFmeg, 0); baseUrl = this.ffmpegBaseUrl; - return [4 /*yield*/, util.toBlobURL("".concat(baseUrl, "/ffmpeg-core.js"), 'text/javascript')]; + return [4 /*yield*/, toBlobURL("".concat(baseUrl, "/ffmpeg-core.js"), 'text/javascript')]; case 1: coreURL = _c.sent(); - return [4 /*yield*/, util.toBlobURL("".concat(baseUrl, "/ffmpeg-core.wasm"), 'application/wasm') + return [4 /*yield*/, toBlobURL("".concat(baseUrl, "/ffmpeg-core.wasm"), 'application/wasm') // workerURL = workerURL ?? await toBlobURL(`${baseUrl}/ffmpeg-core.worker.js`, 'text/javascript') ]; case 2: @@ -1294,7 +1333,10 @@ anchor.click(); setTimeout(function () { return URL.revokeObjectURL(objectUrl); }, 100); }; - Hls2Mp4.version = '1.2.7'; + Hls2Mp4.prototype.destroy = function () { + this.ffmpeg.terminate(); + }; + Hls2Mp4.version = '1.2.8'; Hls2Mp4.TaskType = exports.TaskType; return Hls2Mp4; }()); diff --git a/dist/index.d.ts b/dist/index.d.ts index 0877caf..8404bd3 100644 --- a/dist/index.d.ts +++ b/dist/index.d.ts @@ -23,6 +23,14 @@ type Hls2Mp4Options = { * the base url of ffmpeg default: https://unpkg.com/@ffmpeg/core@0.12.2/dist/umd */ ffmpegBaseUrl?: string; + /** + * progress update callback + */ + onProgress?: ProgressCallback; + /** + * error callback + */ + onError?: ErrorCallback; }; export interface M3u8Parsed { url: string; @@ -40,7 +48,17 @@ declare class Hls2Mp4 { private savedSegments; static version: string; static TaskType: typeof TaskType; - constructor({ maxRetry, tsDownloadConcurrency, ffmpegBaseUrl }: Hls2Mp4Options, onProgress?: ProgressCallback, onError?: ErrorCallback); + constructor({ maxRetry, tsDownloadConcurrency, ffmpegBaseUrl, onProgress, onError }: Hls2Mp4Options, + /** + * @deprecated + * will be removed in the feature, please use options.onProgress instead + */ + _onProgress?: ProgressCallback, + /** + * @deprecated + * will be removed in the feature, please use options.onError instead + */ + _onError?: ErrorCallback); private transformBuffer; private hexToUint8Array; private aesDecrypt; @@ -53,5 +71,6 @@ declare class Hls2Mp4 { private loadFFmpeg; download(url: string): Promise; saveToFile(buffer: ArrayBuffer | string, filename: string): void; + destroy(): void; } export default Hls2Mp4; diff --git a/dist/index.js b/dist/index.js index 9a2930d..be96a2f 100644 --- a/dist/index.js +++ b/dist/index.js @@ -1,5 +1,4 @@ import { FFmpeg } from '@ffmpeg/ffmpeg'; -import { fetchFile, toBlobURL } from '@ffmpeg/util'; /****************************************************************************** Copyright (c) Microsoft Corporation. @@ -878,6 +877,35 @@ var TaskType; TaskType[TaskType["downloadTs"] = 2] = "downloadTs"; TaskType[TaskType["mergeTs"] = 3] = "mergeTs"; })(TaskType || (TaskType = {})); +function fetchFile(url) { + return __awaiter(this, void 0, void 0, function () { + var response, arrayBuffer; + return __generator(this, function (_a) { + switch (_a.label) { + case 0: return [4 /*yield*/, fetch(url)]; + case 1: + response = _a.sent(); + return [4 /*yield*/, response.arrayBuffer()]; + case 2: + arrayBuffer = _a.sent(); + return [2 /*return*/, new Uint8Array(arrayBuffer)]; + } + }); + }); +} +function toBlobURL(url, type) { + return __awaiter(this, void 0, void 0, function () { + var data; + return __generator(this, function (_a) { + switch (_a.label) { + case 0: return [4 /*yield*/, fetchFile(url)]; + case 1: + data = _a.sent(); + return [2 /*return*/, URL.createObjectURL(new Blob([data.buffer], { type: type }))]; + } + }); + }); +} function createFileUrlRegExp(ext, flags) { return new RegExp('(https?://)?[\\w:\\.\\-\\/]+?\\.' + ext, flags); } @@ -889,8 +917,18 @@ function parseUrl(url, path) { } var ffmpegDefaultBaseUrl = 'https://unpkg.com/@ffmpeg/core@0.12.2/dist/umd'; var Hls2Mp4 = /** @class */ (function () { - function Hls2Mp4(_a, onProgress, onError) { - var _b = _a.maxRetry, maxRetry = _b === void 0 ? 3 : _b, _c = _a.tsDownloadConcurrency, tsDownloadConcurrency = _c === void 0 ? 10 : _c, _d = _a.ffmpegBaseUrl, ffmpegBaseUrl = _d === void 0 ? ffmpegDefaultBaseUrl : _d; + function Hls2Mp4(_a, + /** + * @deprecated + * will be removed in the feature, please use options.onProgress instead + */ + _onProgress, + /** + * @deprecated + * will be removed in the feature, please use options.onError instead + */ + _onError) { + var _b = _a.maxRetry, maxRetry = _b === void 0 ? 3 : _b, _c = _a.tsDownloadConcurrency, tsDownloadConcurrency = _c === void 0 ? 10 : _c, _d = _a.ffmpegBaseUrl, ffmpegBaseUrl = _d === void 0 ? ffmpegDefaultBaseUrl : _d, onProgress = _a.onProgress, onError = _a.onError; this.loadRetryTime = 0; this.totalSegments = 0; this.savedSegments = 0; @@ -898,8 +936,8 @@ var Hls2Mp4 = /** @class */ (function () { this.maxRetry = maxRetry; this.tsDownloadConcurrency = tsDownloadConcurrency; this.ffmpegBaseUrl = ffmpegBaseUrl; - this.onProgress = onProgress; - this.onError = onError; + this.onProgress = onProgress !== null && onProgress !== void 0 ? onProgress : _onProgress; + this.onError = onError !== null && onError !== void 0 ? onError : _onError; } Hls2Mp4.prototype.transformBuffer = function (buffer) { if (buffer[0] === 0x47) { @@ -1291,7 +1329,10 @@ var Hls2Mp4 = /** @class */ (function () { anchor.click(); setTimeout(function () { return URL.revokeObjectURL(objectUrl); }, 100); }; - Hls2Mp4.version = '1.2.7'; + Hls2Mp4.prototype.destroy = function () { + this.ffmpeg.terminate(); + }; + Hls2Mp4.version = '1.2.8'; Hls2Mp4.TaskType = TaskType; return Hls2Mp4; }()); diff --git a/dist/package.json b/dist/package.json index 93a7af6..0764ce8 100644 --- a/dist/package.json +++ b/dist/package.json @@ -1,6 +1,6 @@ { "name": "hls2mp4", - "version": "1.2.7", + "version": "1.2.8", "description": "a tool for download hls/m3u8 to mp4", "main": "index.js", "types": "index.d.ts", diff --git a/package.json b/package.json index 0ebde33..1956992 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "hls2mp4", - "version": "1.2.7", + "version": "1.2.8", "description": "a tool for download hls/m3u8 to mp4", "main": "index.js", "types": "index.d.ts", @@ -20,7 +20,6 @@ }, "devDependencies": { "@ffmpeg/ffmpeg": "^0.12.6", - "@ffmpeg/util": "^0.12.1", "@rollup/plugin-commonjs": "^25.0.0", "@rollup/plugin-node-resolve": "^15.0.2", "@rollup/plugin-typescript": "^11.1.0", diff --git a/src/index.ts b/src/index.ts index 4198429..b2eb51d 100644 --- a/src/index.ts +++ b/src/index.ts @@ -1,5 +1,4 @@ import { FFmpeg } from '@ffmpeg/ffmpeg' -import { fetchFile, toBlobURL } from '@ffmpeg/util' import aesjs, { type ByteSource } from 'aes-js' export enum TaskType { @@ -36,6 +35,14 @@ type Hls2Mp4Options = { * the base url of ffmpeg default: https://unpkg.com/@ffmpeg/core@0.12.2/dist/umd */ ffmpegBaseUrl?: string; + /** + * progress update callback + */ + onProgress?: ProgressCallback; + /** + * error callback + */ + onError?: ErrorCallback; } type Segment = { @@ -55,6 +62,19 @@ type SegmentGroup = { segments: string[]; } +async function fetchFile(url: string): Promise { + const response = await fetch(url) + const arrayBuffer = await response.arrayBuffer() + return new Uint8Array(arrayBuffer) +} + +async function toBlobURL(url: string, type: string): Promise { + const data = await fetchFile(url) + return URL.createObjectURL( + new Blob([data.buffer], { type }) + ) +} + function createFileUrlRegExp(ext: string, flags?: string) { return new RegExp('(https?://)?[\\w:\\.\\-\\/]+?\\.' + ext, flags) } @@ -79,24 +99,34 @@ class Hls2Mp4 { private tsDownloadConcurrency: number; private totalSegments = 0; private savedSegments = 0; - public static version = '1.2.7'; + public static version = '1.2.8'; public static TaskType = TaskType; constructor( { maxRetry = 3, tsDownloadConcurrency = 10, - ffmpegBaseUrl = ffmpegDefaultBaseUrl + ffmpegBaseUrl = ffmpegDefaultBaseUrl, + onProgress, + onError }: Hls2Mp4Options, - onProgress?: ProgressCallback, - onError?: ErrorCallback + /** + * @deprecated + * will be removed in the feature, please use options.onProgress instead + */ + _onProgress?: ProgressCallback, + /** + * @deprecated + * will be removed in the feature, please use options.onError instead + */ + _onError?: ErrorCallback ) { this.ffmpeg = new FFmpeg(); this.maxRetry = maxRetry; this.tsDownloadConcurrency = tsDownloadConcurrency; this.ffmpegBaseUrl = ffmpegBaseUrl; - this.onProgress = onProgress; - this.onError = onError; + this.onProgress = onProgress ?? _onProgress; + this.onError = onError ?? _onError; } private transformBuffer(buffer: Uint8Array) { @@ -377,6 +407,10 @@ class Hls2Mp4 { anchor.click() setTimeout(() => URL.revokeObjectURL(objectUrl), 100) } + + public destroy() { + this.ffmpeg.terminate() + } } -export default Hls2Mp4 +export default Hls2Mp4 \ No newline at end of file diff --git a/yarn.lock b/yarn.lock index 85cb53f..bce7676 100644 --- a/yarn.lock +++ b/yarn.lock @@ -14,11 +14,6 @@ resolved "https://registry.yarnpkg.com/@ffmpeg/types/-/types-0.12.1.tgz#659e4eb51f3e01e145a6fe99e5b8e12a373aa59a" integrity sha512-n+v9yvxaBPi1Z/1wy2PvqMHvED3qV7LXBWnBmMBAAzybbs4KWp6wrhCTMxITORMHXpPZEEupsBH1iEoLuzYSUw== -"@ffmpeg/util@^0.12.1": - version "0.12.1" - resolved "https://registry.yarnpkg.com/@ffmpeg/util/-/util-0.12.1.tgz#98afa20d7b4c0821eebdb205ddcfa5d07b0a4f53" - integrity sha512-10jjfAKWaDyb8+nAkijcsi9wgz/y26LOc1NKJradNMyCIl6usQcBbhkjX5qhALrSBcOy6TOeksunTYa+a03qNQ== - "@jridgewell/sourcemap-codec@^1.4.13": version "1.4.15" resolved "https://registry.yarnpkg.com/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.4.15.tgz#d7c6e6755c78567a951e04ab52ef0fd26de59f32"