hls-streamer 2.1.0 → 3.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (94) hide show
  1. package/README.md +189 -190
  2. package/dist/Interfaces/HlsStreamer.d.ts +20 -0
  3. package/dist/Interfaces/HlsStreamer.d.ts.map +1 -1
  4. package/dist/Libs/FileLib.d.ts +22 -1
  5. package/dist/Libs/FileLib.d.ts.map +1 -1
  6. package/dist/Libs/FileLib.js +273 -108
  7. package/dist/Libs/FileLib.js.map +1 -1
  8. package/dist/Libs/FormatDetector.d.ts +8 -0
  9. package/dist/Libs/FormatDetector.d.ts.map +1 -0
  10. package/dist/Libs/FormatDetector.js +63 -0
  11. package/dist/Libs/FormatDetector.js.map +1 -0
  12. package/dist/Parsers/AacParser.d.ts +15 -0
  13. package/dist/Parsers/AacParser.d.ts.map +1 -0
  14. package/dist/Parsers/AacParser.js +246 -0
  15. package/dist/Parsers/AacParser.js.map +1 -0
  16. package/dist/Parsers/FlacParser.d.ts +13 -0
  17. package/dist/Parsers/FlacParser.d.ts.map +1 -0
  18. package/dist/Parsers/FlacParser.js +200 -0
  19. package/dist/Parsers/FlacParser.js.map +1 -0
  20. package/dist/Parsers/IAudioParser.d.ts +31 -0
  21. package/dist/Parsers/IAudioParser.d.ts.map +1 -0
  22. package/dist/Parsers/IAudioParser.js +2 -0
  23. package/dist/Parsers/IAudioParser.js.map +1 -0
  24. package/dist/Parsers/Mp3Parser.d.ts +19 -0
  25. package/dist/Parsers/Mp3Parser.d.ts.map +1 -0
  26. package/dist/Parsers/Mp3Parser.js +270 -0
  27. package/dist/Parsers/Mp3Parser.js.map +1 -0
  28. package/dist/Parsers/OggParser.d.ts +11 -0
  29. package/dist/Parsers/OggParser.d.ts.map +1 -0
  30. package/dist/Parsers/OggParser.js +160 -0
  31. package/dist/Parsers/OggParser.js.map +1 -0
  32. package/dist/Parsers/ParserFactory.d.ts +10 -0
  33. package/dist/Parsers/ParserFactory.d.ts.map +1 -0
  34. package/dist/Parsers/ParserFactory.js +43 -0
  35. package/dist/Parsers/ParserFactory.js.map +1 -0
  36. package/dist/Parsers/WavParser.d.ts +9 -0
  37. package/dist/Parsers/WavParser.d.ts.map +1 -0
  38. package/dist/Parsers/WavParser.js +135 -0
  39. package/dist/Parsers/WavParser.js.map +1 -0
  40. package/dist/cjs/Interfaces/HlsStreamer.d.ts +20 -0
  41. package/dist/cjs/Interfaces/HlsStreamer.d.ts.map +1 -1
  42. package/dist/cjs/Libs/FileLib.d.ts +22 -1
  43. package/dist/cjs/Libs/FileLib.d.ts.map +1 -1
  44. package/dist/cjs/Libs/FileLib.js +276 -108
  45. package/dist/cjs/Libs/FileLib.js.map +1 -1
  46. package/dist/cjs/Libs/FormatDetector.d.ts +8 -0
  47. package/dist/cjs/Libs/FormatDetector.d.ts.map +1 -0
  48. package/dist/cjs/Libs/FormatDetector.js +67 -0
  49. package/dist/cjs/Libs/FormatDetector.js.map +1 -0
  50. package/dist/cjs/Parsers/AacParser.d.ts +15 -0
  51. package/dist/cjs/Parsers/AacParser.d.ts.map +1 -0
  52. package/dist/cjs/Parsers/AacParser.js +250 -0
  53. package/dist/cjs/Parsers/AacParser.js.map +1 -0
  54. package/dist/cjs/Parsers/FlacParser.d.ts +13 -0
  55. package/dist/cjs/Parsers/FlacParser.d.ts.map +1 -0
  56. package/dist/cjs/Parsers/FlacParser.js +204 -0
  57. package/dist/cjs/Parsers/FlacParser.js.map +1 -0
  58. package/dist/cjs/Parsers/IAudioParser.d.ts +31 -0
  59. package/dist/cjs/Parsers/IAudioParser.d.ts.map +1 -0
  60. package/dist/cjs/Parsers/IAudioParser.js +3 -0
  61. package/dist/cjs/Parsers/IAudioParser.js.map +1 -0
  62. package/dist/cjs/Parsers/Mp3Parser.d.ts +19 -0
  63. package/dist/cjs/Parsers/Mp3Parser.d.ts.map +1 -0
  64. package/dist/cjs/Parsers/Mp3Parser.js +274 -0
  65. package/dist/cjs/Parsers/Mp3Parser.js.map +1 -0
  66. package/dist/cjs/Parsers/OggParser.d.ts +11 -0
  67. package/dist/cjs/Parsers/OggParser.d.ts.map +1 -0
  68. package/dist/cjs/Parsers/OggParser.js +164 -0
  69. package/dist/cjs/Parsers/OggParser.js.map +1 -0
  70. package/dist/cjs/Parsers/ParserFactory.d.ts +10 -0
  71. package/dist/cjs/Parsers/ParserFactory.d.ts.map +1 -0
  72. package/dist/cjs/Parsers/ParserFactory.js +47 -0
  73. package/dist/cjs/Parsers/ParserFactory.js.map +1 -0
  74. package/dist/cjs/Parsers/WavParser.d.ts +9 -0
  75. package/dist/cjs/Parsers/WavParser.d.ts.map +1 -0
  76. package/dist/cjs/Parsers/WavParser.js +139 -0
  77. package/dist/cjs/Parsers/WavParser.js.map +1 -0
  78. package/dist/cjs/errors/HlsStreamerErrors.d.ts +3 -0
  79. package/dist/cjs/errors/HlsStreamerErrors.d.ts.map +1 -1
  80. package/dist/cjs/errors/HlsStreamerErrors.js +8 -1
  81. package/dist/cjs/errors/HlsStreamerErrors.js.map +1 -1
  82. package/dist/cjs/index.d.ts +6 -7
  83. package/dist/cjs/index.d.ts.map +1 -1
  84. package/dist/cjs/index.js +161 -138
  85. package/dist/cjs/index.js.map +1 -1
  86. package/dist/errors/HlsStreamerErrors.d.ts +3 -0
  87. package/dist/errors/HlsStreamerErrors.d.ts.map +1 -1
  88. package/dist/errors/HlsStreamerErrors.js +6 -0
  89. package/dist/errors/HlsStreamerErrors.js.map +1 -1
  90. package/dist/index.d.ts +6 -7
  91. package/dist/index.d.ts.map +1 -1
  92. package/dist/index.js +162 -139
  93. package/dist/index.js.map +1 -1
  94. package/package.json +10 -3
package/README.md CHANGED
@@ -2,254 +2,253 @@
2
2
 
3
3
  [![npm version](https://badge.fury.io/js/hls-streamer.svg)](https://badge.fury.io/js/hls-streamer)
4
4
  [![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](https://opensource.org/licenses/MIT)
5
- [![TypeScript](https://img.shields.io/badge/%3C%2F%3E-TypeScript-%230074c1.svg)](http://www.typescriptlang.org/)
5
+ [![TypeScript](https://img.shields.io/badge/%3C%2F%3E-TypeScript-%230074c1.svg)](https://www.typescriptlang.org/)
6
6
 
7
- **HLS Streamer** is a lightweight npm package that creates and streams HLS (HTTP Live Streaming) from MP3 files on demand, without storing temporary files or requiring ffmpeg.
7
+ HLS Streamer turns any audio file (MP3, AAC, M4A, OGG Vorbis, FLAC, WAV) into an HTTP Live Streaming (HLS) playlist on the fly. It analyses the source audio in-memory, builds frame-aligned byte ranges, and streams them without temporary files, native bindings, or external binaries like ffmpeg.
8
8
 
9
- ## ✨ Features
10
-
11
- - 🚀 **True Zero Dependencies** - No external dependencies, no ffmpeg, no native binaries
12
- - 🎵 **Built-in MP3 Parser** - Custom MP3 duration parsing without external libraries
13
- - 🔄 **Frame-Aligned Segments** - Ensures all MP3 segments start at valid frame boundaries for seamless playback
14
- - 💾 **No Temporary Files** - Stream directly from source
15
- - ⚡ **Fast Startup** - Optional smaller initial segments for quick playback start
16
- - 🎯 **TypeScript Support** - Full type definitions included
17
- - 🔧 **Configurable** - Customizable segment sizes and naming
18
- - 📱 **Memory Efficient** - Byte-range streaming with minimal memory footprint
9
+ ---
19
10
 
20
- ## 📦 Installation
11
+ - [Why HLS Streamer?](#why-hls-streamer)
12
+ - [How It Works](#how-it-works)
13
+ - [Quick Start](#quick-start)
14
+ - [Serving Over HTTP](#serving-over-http)
15
+ - [Configuration Reference](#configuration-reference)
16
+ - [Playlist Anatomy](#playlist-anatomy)
17
+ - [Operational Tips](#operational-tips)
18
+ - [Development](#development)
19
+ - [Support](#support)
20
+
21
+ ## Why HLS Streamer?
22
+
23
+ - **Multi-format support** – handles MP3, AAC, M4A, OGG Vorbis, FLAC, and WAV with automatic format detection.
24
+ - **Zero dependencies** – no shared libraries, no ffmpeg, no native compilation. Pure TypeScript parsers for all formats. Drop it into Docker, serverless, or edge runtimes.
25
+ - **Accurate segments** – real audio frame/packet parsing provides true durations, `#EXTINF` metadata, and target durations that match playback.
26
+ - **Frame-aligned byte ranges** – every segment begins and ends on verified frame/packet boundaries, preventing pops and clipped audio.
27
+ - **No temp files** – streams straight from the source audio file using byte-range reads.
28
+ - **Fast-start aware** – optional smaller first segments improve startup latency for constrained networks.
29
+ - **TypeScript first** – authored in TypeScript with full type definitions for your tooling and IDEs.
30
+
31
+ ## How It Works
32
+
33
+ 1. **Format detection** – automatically detects audio format from file content (magic bytes) or extension, with optional manual override.
34
+ 2. **Metadata analysis** – format-specific parsers extract metadata (ID3/Vorbis comments/etc.), parse frame/packet headers, and produce a frame table with offsets, durations, and bitrates.
35
+ 3. **Segment planning** – segment boundaries are calculated from the frame table so each segment contains whole frames/packets while matching your target sizes.
36
+ 4. **Playlist generation** – `createM3U8()` emits an `#EXTM3U` playlist with accurate `#EXTINF` entries and `#EXT-X-TARGETDURATION` derived from the longest segment.
37
+ 5. **On-demand byte ranges** – `getFileBuffer(start, end)` streams the exact bytes for a segment without reading the entire file into memory.
21
38
 
22
- ```bash
23
- npm install hls-streamer
24
39
  ```
25
-
26
- ```bash
27
- yarn add hls-streamer
28
- ```
29
-
30
- ```bash
31
- pnpm add hls-streamer
40
+ ┌──────────────┐ ┌─────────────────┐ ┌─────────────────┐ ┌──────────────────────┐
41
+ │ Audio Source │ ──▶ │ Format Detector │ ──▶ │ Format Parser │ ──▶ │ Segment Planner │
42
+ (any format) │ │ (magic bytes) │ │ (MP3/AAC/etc.) │ │ (frame-aligned) │
43
+ └──────────────┘ └─────────────────┘ └─────────────────┘ └──────────┬───────────┘
44
+
45
+
46
+ ┌──────────────────────┐
47
+ │ HLS Playlist & Bytes │
48
+ └──────────────────────┘
32
49
  ```
33
50
 
34
- ## 🎯 Zero Dependencies
35
-
36
- This package is **truly zero-dependency**, meaning:
37
-
38
- - ✅ **No ffmpeg** - No external binary dependencies
39
- - ✅ **No native modules** - Pure JavaScript/TypeScript implementation
40
- - ✅ **No runtime dependencies** - Check `package.json` - completely empty dependencies
41
- - ✅ **Custom MP3 parser** - Built-in MP3 header parsing and duration calculation
42
- - ✅ **Frame-perfect segmentation** - MP3 segments start at valid frame boundaries
43
- - ✅ **Cross-platform** - Works on any platform that supports Node.js
44
-
45
- Perfect for:
46
- - 🐳 **Docker containers** - No need to install ffmpeg
47
- - 🌐 **Serverless functions** - Minimal package size and cold start time
48
- - 📱 **Edge computing** - Lightweight deployment
49
- - 🔒 **Security-conscious environments** - No external binaries to audit
51
+ ## Quick Start
50
52
 
51
- ## 🚀 Quick Start
52
-
53
- ### Basic Usage
54
-
55
- ```typescript
53
+ ```ts
56
54
  import { HlsStreamer } from 'hls-streamer';
57
55
 
58
- const hls = new HlsStreamer({
59
- filePath: 'path/to/audio.mp3',
56
+ // Works with any supported format - auto-detected!
57
+ const streamer = new HlsStreamer({
58
+ filePath: '/media/library/song.mp3', // or .aac, .m4a, .ogg, .flac, .wav
60
59
  segmentSizeKB: 512,
61
- fileName: 'segment',
62
- baseUrl: 'segments/session-123',
63
- enableFastStart: true
60
+ fileName: 'track',
61
+ baseUrl: 'audio/stream/session-42',
62
+ enableFastStart: true,
63
+ // format: 'mp3' // optional: override auto-detection
64
64
  });
65
65
 
66
- // Generate M3U8 playlist
67
- const playlist = await hls.createM3U8();
66
+ const playlist = await streamer.createM3U8();
67
+ console.log(playlist);
68
68
 
69
- // Get file buffer for specific byte range
70
- const buffer = await hls.getFileBuffer(startByte, endByte);
69
+ const firstSegmentBuffer = await streamer.getFileBuffer(0, 512 * 1024);
71
70
  ```
72
71
 
73
- ### Express.js Integration
72
+ ## Serving Over HTTP
74
73
 
75
- ```typescript
74
+ Create playlists and segment endpoints with any HTTP framework. The example below shows an Express setup:
75
+
76
+ ```ts
76
77
  import express from 'express';
77
78
  import { HlsStreamer } from 'hls-streamer';
78
79
 
79
80
  const app = express();
80
81
 
81
- // Serve M3U8 playlist
82
- app.get('/stream/:sessionId/playlist.m3u8', async (req, res) => {
83
- const hls = new HlsStreamer({
84
- filePath: getFilePath(req.params.sessionId),
85
- baseUrl: `stream/${req.params.sessionId}`,
86
- enableFastStart: true
87
- });
82
+ app.get('/streams/:id/playlist.m3u8', async (req, res, next) => {
83
+ try {
84
+ const streamer = new HlsStreamer({
85
+ filePath: resolveAudioPath(req.params.id),
86
+ baseUrl: `streams/${req.params.id}`,
87
+ enableFastStart: true,
88
+ });
88
89
 
89
- res.setHeader('Content-Type', 'application/vnd.apple.mpegurl');
90
- res.send(await hls.createM3U8());
90
+ res.type('application/vnd.apple.mpegurl');
91
+ res.send(await streamer.createM3U8());
92
+ } catch (error) {
93
+ next(error);
94
+ }
91
95
  });
92
96
 
93
- // Serve segment files
94
- app.get('/stream/:sessionId/:start/:end/:filename', async (req, res) => {
95
- const hls = new HlsStreamer({
96
- filePath: getFilePath(req.params.sessionId),
97
- baseUrl: `stream/${req.params.sessionId}`
98
- });
97
+ app.get('/streams/:id/:start/:end/:filename', async (req, res, next) => {
98
+ try {
99
+ const streamer = new HlsStreamer({
100
+ filePath: resolveAudioPath(req.params.id),
101
+ baseUrl: `streams/${req.params.id}`,
102
+ });
99
103
 
100
- const start = parseInt(req.params.start);
101
- const end = parseInt(req.params.end);
104
+ const start = Number(req.params.start);
105
+ const end = Number(req.params.end);
102
106
 
103
- res.setHeader('Content-Type', 'audio/mpeg');
104
- res.setHeader('Accept-Ranges', 'bytes');
105
- res.send(await hls.getFileBuffer(start, end));
107
+ res.type('audio/mpeg');
108
+ res.set('Accept-Ranges', 'bytes');
109
+ res.send(await streamer.getFileBuffer(start, end));
110
+ } catch (error) {
111
+ next(error);
112
+ }
106
113
  });
107
114
  ```
108
115
 
109
- ## 🛠️ API Reference
110
-
111
- ### HlsStreamer
116
+ ### Segment URL Contract
112
117
 
113
- #### Constructor Options
118
+ Generated playlists follow the pattern below:
114
119
 
115
- ```typescript
116
- interface HlsStreamerOptions {
117
- /** Path to the MP3 file */
118
- filePath: string;
119
- /** Segment size in KB (default: 512) */
120
- segmentSizeKB?: number;
121
- /** Base filename for segments (default: "file") */
122
- fileName?: string;
123
- /** Base URL path for segment URLs */
124
- baseUrl?: string;
125
- /** Enable smaller initial segments for faster startup */
126
- enableFastStart?: boolean;
127
- }
120
+ ```
121
+ /{baseUrl}/{startByte}/{endByte}/{fileName}{index}.mp3
128
122
  ```
129
123
 
130
- #### Methods
131
-
132
- ##### `createM3U8(): Promise<string>`
133
- Generates an HLS M3U8 playlist file content.
134
-
135
- **Returns:** M3U8 playlist as a string
124
+ - `startByte` is inclusive, `endByte` is exclusive.
125
+ - `index` is zero-padded to three digits (`000`, `001`, ...).
126
+ - Use the provided byte range as-is when serving `audio/mpeg` responses.
127
+
128
+ ## Configuration Reference
129
+
130
+ | Option | Type | Default | Description |
131
+ | ------------------- | --------- | ------- | ----------- |
132
+ | `filePath` | `string` | — | Absolute or relative path to the audio file. Supports: MP3, AAC, M4A, OGG, FLAC, WAV. |
133
+ | `segmentSizeKB` | `number` | `512` | Target segment size in kilobytes. Fast-start mode splits the first two segments into quarters/halves of this value. |
134
+ | `fileName` | `string` | `"file"` | Base name used in generated segment URLs (the index is appended automatically). |
135
+ | `baseUrl` | `string` | `""` | URL prefix inserted before each segment path. Useful when mounting under a route or CDN prefix. |
136
+ | `enableFastStart` | `boolean` | `false` | When true, the first two segments are smaller to reduce initial buffering time. |
137
+ | `format` | `AudioFormat` | auto-detect | Optional format override ('mp3', 'aac', 'm4a', 'ogg', 'flac', 'wav'). Auto-detected from file if not specified. |
138
+
139
+ ### API Surface
140
+
141
+ - `createM3U8(): Promise<string>` – Returns a full playlist with frame-accurate durations.
142
+ - `getFileBuffer(start: number, end: number): Promise<Buffer>` – Streams a byte range from the audio file.
143
+ - `getSegmentDuration(index: number): Promise<number>` – Reads the cached segment table to return the duration of a segment in seconds.
144
+
145
+ Custom error classes are exported to help with error handling: `FileNotFoundError`, `InvalidFileError`, `InvalidRangeError`, `InvalidParameterError`, and `UnsupportedFormatError`.
146
+
147
+ ### Supported Formats
148
+
149
+ | Format | Extensions | Container | Codec | Frame Parsing |
150
+ |--------|-----------|-----------|-------|---------------|
151
+ | **MP3** | `.mp3` | — | MPEG-1/2 Layer III | ✅ Full frame table |
152
+ | **AAC** | `.aac` | ADTS | AAC | ✅ ADTS frames |
153
+ | **M4A** | `.m4a`, `.m4b` | MP4 | AAC | ✅ MP4 box structure |
154
+ | **OGG** | `.ogg`, `.oga` | OGG | Vorbis | ✅ OGG pages |
155
+ | **FLAC** | `.flac` | — | FLAC | ✅ FLAC frames |
156
+ | **WAV** | `.wav` | RIFF | PCM | ⚠️ Synthetic 1-second frames |
157
+
158
+ ## Playlist Anatomy
159
+
160
+ ```m3u8
161
+ #EXTM3U
162
+ #EXT-X-VERSION:6
163
+ #EXT-X-PLAYLIST-TYPE:VOD
164
+ #EXT-X-TARGETDURATION:6
165
+ #EXT-X-MEDIA-SEQUENCE:0
166
+ #EXTINF:5.973,
167
+ /audio/session/0/260736/track000.mp3
168
+ #EXTINF:5.994,
169
+ /audio/session/260736/521472/track001.mp3
170
+ ...
171
+ #EXT-X-ENDLIST
172
+ ```
136
173
 
137
- ##### `getFileBuffer(startByte: number, endByte: number): Promise<Buffer>`
138
- Retrieves a specific byte range from the MP3 file.
174
+ - `#EXT-X-TARGETDURATION` is rounded up from the longest real segment duration.
175
+ - `#EXTINF` entries retain millisecond precision for smooth playback on strict clients.
176
+ - Segment paths directly encode the byte ranges your route must return.
139
177
 
140
- **Parameters:**
141
- - `startByte` - Starting byte position (inclusive)
142
- - `endByte` - Ending byte position (exclusive)
178
+ ## Operational Tips
143
179
 
144
- **Returns:** Buffer containing the requested byte range
180
+ - **Caching** Construct the streamer once per unique audio file and reuse it. Segment planning caches the metadata, so repeated calls to `createM3U8()` or `getSegmentDuration()` are cheap.
181
+ - **CDN friendliness** – Because segment URLs are deterministic byte ranges, edge caches can serve them efficiently. Configure consistent caching headers (e.g. `Cache-Control: public, max-age=86400`).
182
+ - **Serverless** – The zero-dependency design works well in Lambda/Cloud Functions. For large files, prefer streaming reads (`getFileBuffer`) instead of loading entire files into memory.
183
+ - **Monitoring** – Log segment `start`/`end` pairs and durations to correlate playback issues with specific byte ranges or frame parsing warnings.
184
+ - **Troubleshooting** – For corrupted files, inspect `FileLib.analyzeAudioFile()` to review parsing warnings and format-specific metadata.
185
+ - **Format selection** – All formats work seamlessly with HLS, but consider:
186
+ - **MP3/AAC/M4A**: Best compatibility with HLS players
187
+ - **FLAC**: Lossless quality but larger segments
188
+ - **OGG**: Open-source, good compression
189
+ - **WAV**: Uncompressed, very large segments (consider smaller `segmentSizeKB`)
145
190
 
146
- ##### `getSegmentDuration(segmentIndex: number): Promise<number>`
147
- Gets the accurate duration of a specific segment.
191
+ ## Development
148
192
 
149
- **Parameters:**
150
- - `segmentIndex` - Zero-based segment index
193
+ Clone the repo, install dependencies, and run the usual scripts:
151
194
 
152
- **Returns:** Duration in seconds
195
+ ```bash
196
+ npm install
197
+ npm test -- --runInBand --watchman=false
198
+ npm run build
199
+ ```
153
200
 
154
- ### Error Handling
201
+ The Jest flag `--watchman=false` avoids macOS sandbox issues when running in restricted environments.
155
202
 
156
- The package includes custom error types for better error handling:
203
+ To explore the example playlist generator, see `example/test-hls-generation.js` and the bundled `example/sample.mp3` fixture.
157
204
 
158
- ```typescript
159
- import {
160
- FileNotFoundError,
161
- InvalidFileError,
162
- InvalidRangeError,
163
- InvalidParameterError
164
- } from 'hls-streamer';
205
+ ## Support
165
206
 
166
- try {
167
- const hls = new HlsStreamer({ filePath: 'nonexistent.mp3' });
168
- } catch (error) {
169
- if (error instanceof FileNotFoundError) {
170
- console.error('File not found:', error.message);
171
- }
172
- }
173
- ```
207
+ - 🐛 Bug reports: [GitHub Issues](https://github.com/LordVersA/hls-streamer/issues)
208
+ - 💬 Questions & ideas: [GitHub Discussions](https://github.com/LordVersA/hls-streamer/discussions)
209
+ - 📦 npm registry: [hls-streamer](https://www.npmjs.com/package/hls-streamer)
174
210
 
175
- ## 📋 Configuration Options
211
+ ## Contributing
176
212
 
177
- | Option | Type | Default | Description |
178
- |--------|------|---------|-------------|
179
- | `filePath` | `string` | **required** | Path to the MP3 file |
180
- | `segmentSizeKB` | `number` | `512` | Size of each segment in KB |
181
- | `fileName` | `string` | `"file"` | Base name for segment files |
182
- | `baseUrl` | `string` | `""` | Base URL path for segment URLs |
183
- | `enableFastStart` | `boolean` | `false` | Use smaller initial segments for faster startup |
213
+ Contributions are welcome! Please open an issue to discuss substantial changes before submitting a pull request. Make sure `npm test -- --runInBand --watchman=false` and `npm run build` pass prior to filing the PR.
184
214
 
185
- ## 🎯 Use Cases
215
+ ---
186
216
 
187
- - **Audio Streaming Services** - Stream music without pre-processing
188
- - **Podcast Platforms** - On-demand episode streaming
189
- - **Educational Platforms** - Stream lecture recordings
190
- - **Voice Message Systems** - Real-time audio message playback
191
- - **Audio Books** - Chapter-based streaming
217
+ ## Version 3.0.0 Breaking Changes
192
218
 
193
- ## 🔧 Advanced Examples
219
+ This major release adds multi-format support with pure TypeScript parsers. While most code remains backward compatible, please note:
194
220
 
195
- ### Custom Segment Sizing
221
+ ### What Changed
222
+ - **New formats**: Added AAC, M4A, OGG Vorbis, FLAC, and WAV support
223
+ - **Format detection**: Files are now validated against all supported formats, not just MP3
224
+ - **Error types**: `InvalidFileError` for non-MP3 files is now `UnsupportedFormatError` for unsupported formats
225
+ - **Internal architecture**: MP3 parsing refactored into modular `Parsers/` directory
196
226
 
227
+ ### Migration Guide
197
228
  ```typescript
198
- const hls = new HlsStreamer({
199
- filePath: 'large-audio-file.mp3',
200
- segmentSizeKB: 1024, // 1MB segments for better quality
201
- enableFastStart: true // First segments will be 256KB and 512KB
202
- });
203
- ```
229
+ // v2.x - Only MP3 supported
230
+ const streamer = new HlsStreamer({ filePath: 'song.mp3' });
204
231
 
205
- ### Dynamic File Paths
232
+ // v3.x - All formats work the same way!
233
+ const streamer = new HlsStreamer({ filePath: 'song.mp3' }); // ✅ Still works
234
+ const streamer = new HlsStreamer({ filePath: 'song.ogg' }); // ✅ Now supported
235
+ const streamer = new HlsStreamer({ filePath: 'song.flac' }); // ✅ Now supported
206
236
 
207
- ```typescript
208
- class AudioStreamer {
209
- async streamAudio(userId: string, audioId: string) {
210
- const filePath = await this.getAudioPath(userId, audioId);
211
-
212
- const hls = new HlsStreamer({
213
- filePath,
214
- baseUrl: `audio/${userId}/${audioId}`,
215
- fileName: `audio-${audioId}`,
216
- segmentSizeKB: 256 // Smaller segments for mobile
217
- });
218
-
219
- return hls.createM3U8();
220
- }
237
+ // Error handling update
238
+ try {
239
+ new HlsStreamer({ filePath: 'document.pdf' });
240
+ } catch (err) {
241
+ // v2.x: InvalidFileError
242
+ // v3.x: UnsupportedFormatError
221
243
  }
222
244
  ```
223
245
 
224
- ## 🧪 Testing
225
-
226
- ```bash
227
- npm test
228
- npm run test:watch
229
- npm run test:coverage
230
- ```
231
-
232
- ## 🏗️ Building
233
-
234
- ```bash
235
- npm run build # Build both ESM and CJS
236
- npm run build:esm # Build ES modules
237
- npm run build:cjs # Build CommonJS
238
- ```
239
-
240
- ## 📄 License
241
-
242
- MIT License - see [LICENSE](LICENSE) file for details.
243
-
244
- ## 🤝 Contributing
245
-
246
- Contributions are welcome! Please feel free to submit a Pull Request. For major changes, please open an issue first to discuss what you would like to change.
247
-
248
- ## 📞 Support
246
+ ### Deprecated APIs
247
+ - `Mp3FileInfo` → Use `AudioFileInfo` (backward compatible, but deprecated)
248
+ - `Mp3FrameInfo` → Use `AudioFrameInfo` (backward compatible, but deprecated)
249
+ - `FileLib.analyzeMP3File()` → Use `FileLib.analyzeAudioFile()` (old method still works)
249
250
 
250
- - 🐛 **Bug Reports:** [GitHub Issues](https://github.com/LordVersA/hls-streamer/issues)
251
- - 💬 **Questions:** [GitHub Discussions](https://github.com/LordVersA/hls-streamer/discussions)
252
- - 📦 **NPM:** [hls-streamer](https://www.npmjs.com/package/hls-streamer)
251
+ All deprecated APIs remain functional for backward compatibility but will be removed in v4.0.0.
253
252
 
254
253
  ---
255
254
 
@@ -1,17 +1,37 @@
1
+ import { AudioFormat } from '../Parsers/IAudioParser';
1
2
  export interface HlsStreamerOptions {
2
3
  filePath: string;
3
4
  segmentSizeKB?: number;
4
5
  fileName?: string;
5
6
  baseUrl?: string;
6
7
  enableFastStart?: boolean;
8
+ format?: AudioFormat;
7
9
  }
8
10
  export interface SegmentInfo {
9
11
  start: number;
10
12
  end: number;
11
13
  duration: number;
12
14
  }
15
+ export type { AudioFormat, AudioFrameInfo, AudioFileInfo } from '../Parsers/IAudioParser';
16
+ export interface Mp3FrameInfo {
17
+ index: number;
18
+ offset: number;
19
+ length: number;
20
+ duration: number;
21
+ samples: number;
22
+ sampleRate: number;
23
+ bitrate: number;
24
+ padding?: 0 | 1;
25
+ }
13
26
  export interface Mp3FileInfo {
14
27
  size: number;
15
28
  duration: number;
29
+ audioDataSize: number;
30
+ sampleRate?: number;
31
+ averageBitrate?: number;
32
+ id3v2Size?: number;
33
+ id3v1Size?: number;
34
+ frames: Mp3FrameInfo[];
35
+ warnings?: string[];
16
36
  }
17
37
  //# sourceMappingURL=HlsStreamer.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"HlsStreamer.d.ts","sourceRoot":"","sources":["../../src/Interfaces/HlsStreamer.ts"],"names":[],"mappings":"AAGA,MAAM,WAAW,kBAAkB;IAEjC,QAAQ,EAAE,MAAM,CAAC;IAEjB,aAAa,CAAC,EAAE,MAAM,CAAC;IAEvB,QAAQ,CAAC,EAAE,MAAM,CAAC;IAElB,OAAO,CAAC,EAAE,MAAM,CAAC;IAEjB,eAAe,CAAC,EAAE,OAAO,CAAC;CAC3B;AAKD,MAAM,WAAW,WAAW;IAE1B,KAAK,EAAE,MAAM,CAAC;IAEd,GAAG,EAAE,MAAM,CAAC;IAEZ,QAAQ,EAAE,MAAM,CAAC;CAClB;AAKD,MAAM,WAAW,WAAW;IAE1B,IAAI,EAAE,MAAM,CAAC;IAEb,QAAQ,EAAE,MAAM,CAAC;CAClB"}
1
+ {"version":3,"file":"HlsStreamer.d.ts","sourceRoot":"","sources":["../../src/Interfaces/HlsStreamer.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,WAAW,EAAE,MAAM,yBAAyB,CAAC;AAKtD,MAAM,WAAW,kBAAkB;IAEjC,QAAQ,EAAE,MAAM,CAAC;IAEjB,aAAa,CAAC,EAAE,MAAM,CAAC;IAEvB,QAAQ,CAAC,EAAE,MAAM,CAAC;IAElB,OAAO,CAAC,EAAE,MAAM,CAAC;IAEjB,eAAe,CAAC,EAAE,OAAO,CAAC;IAE1B,MAAM,CAAC,EAAE,WAAW,CAAC;CACtB;AAKD,MAAM,WAAW,WAAW;IAE1B,KAAK,EAAE,MAAM,CAAC;IAEd,GAAG,EAAE,MAAM,CAAC;IAEZ,QAAQ,EAAE,MAAM,CAAC;CAClB;AAGD,YAAY,EAAE,WAAW,EAAE,cAAc,EAAE,aAAa,EAAE,MAAM,yBAAyB,CAAC;AAM1F,MAAM,WAAW,YAAY;IAI3B,KAAK,EAAE,MAAM,CAAC;IAEd,MAAM,EAAE,MAAM,CAAC;IAEf,MAAM,EAAE,MAAM,CAAC;IAEf,QAAQ,EAAE,MAAM,CAAC;IAEjB,OAAO,EAAE,MAAM,CAAC;IAEhB,UAAU,EAAE,MAAM,CAAC;IAEnB,OAAO,EAAE,MAAM,CAAC;IAEhB,OAAO,CAAC,EAAE,CAAC,GAAG,CAAC,CAAC;CACjB;AAMD,MAAM,WAAW,WAAW;IAE1B,IAAI,EAAE,MAAM,CAAC;IAEb,QAAQ,EAAE,MAAM,CAAC;IAEjB,aAAa,EAAE,MAAM,CAAC;IAEtB,UAAU,CAAC,EAAE,MAAM,CAAC;IAEpB,cAAc,CAAC,EAAE,MAAM,CAAC;IAExB,SAAS,CAAC,EAAE,MAAM,CAAC;IAEnB,SAAS,CAAC,EAAE,MAAM,CAAC;IAEnB,MAAM,EAAE,YAAY,EAAE,CAAC;IAEvB,QAAQ,CAAC,EAAE,MAAM,EAAE,CAAC;CACrB"}
@@ -1,6 +1,27 @@
1
+ import { Mp3FileInfo, AudioFileInfo } from '../Interfaces/HlsStreamer';
2
+ import { AudioFormat } from '../Parsers/IAudioParser';
1
3
  export declare class FileLib {
4
+ private static readonly BITRATE_INDEX;
5
+ private static readonly SAMPLE_RATE_INDEX;
2
6
  static getFileSizeInBytes(buffer: Buffer): number;
3
7
  static getMP3DurationFromBuffer(mp3Buffer: Buffer): Promise<number>;
4
- private static parseMP3Duration;
8
+ static analyzeMP3Buffer(buffer: Buffer, opts?: {
9
+ fileSize?: number;
10
+ }): Mp3FileInfo;
11
+ static analyzeMP3File(filePath: string): Promise<Mp3FileInfo>;
12
+ static analyzeAudioFile(filePath: string, format?: AudioFormat): Promise<AudioFileInfo>;
13
+ static analyzeAudioBuffer(buffer: Buffer, opts?: {
14
+ fileSize?: number;
15
+ filePath?: string;
16
+ format?: AudioFormat;
17
+ }): AudioFileInfo;
18
+ private static calculateFrameLength;
19
+ private static getId3Offsets;
20
+ private static syncSafeInteger;
21
+ private static isFrameSync;
22
+ private static parseFrameHeader;
23
+ private static decodeVersion;
24
+ private static decodeLayer;
25
+ private static getSamplesPerFrame;
5
26
  }
6
27
  //# sourceMappingURL=FileLib.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"FileLib.d.ts","sourceRoot":"","sources":["../../src/Libs/FileLib.ts"],"names":[],"mappings":"AAGA,qBAAa,OAAO;IAIlB,MAAM,CAAC,kBAAkB,CAAC,MAAM,EAAE,MAAM,GAAG,MAAM;IAWjD,MAAM,CAAC,wBAAwB,CAAC,SAAS,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC;IAcnE,OAAO,CAAC,MAAM,CAAC,gBAAgB;CAqIhC"}
1
+ {"version":3,"file":"FileLib.d.ts","sourceRoot":"","sources":["../../src/Libs/FileLib.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,WAAW,EAAgB,aAAa,EAAE,MAAM,2BAA2B,CAAC;AAGrF,OAAO,EAAE,WAAW,EAAE,MAAM,yBAAyB,CAAC;AAqBtD,qBAAa,OAAO;IAClB,OAAO,CAAC,MAAM,CAAC,QAAQ,CAAC,aAAa,CAgBnC;IAEF,OAAO,CAAC,MAAM,CAAC,QAAQ,CAAC,iBAAiB,CAIvC;IAKF,MAAM,CAAC,kBAAkB,CAAC,MAAM,EAAE,MAAM,GAAG,MAAM;WAWpC,wBAAwB,CAAC,SAAS,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC;IAQzE,MAAM,CAAC,gBAAgB,CAAC,MAAM,EAAE,MAAM,EAAE,IAAI,GAAE;QAAE,QAAQ,CAAC,EAAE,MAAM,CAAA;KAAO,GAAG,WAAW;WA8HzE,cAAc,CAAC,QAAQ,EAAE,MAAM,GAAG,OAAO,CAAC,WAAW,CAAC;WAetD,gBAAgB,CAAC,QAAQ,EAAE,MAAM,EAAE,MAAM,CAAC,EAAE,WAAW,GAAG,OAAO,CAAC,aAAa,CAAC;IAwB7F,MAAM,CAAC,kBAAkB,CACvB,MAAM,EAAE,MAAM,EACd,IAAI,GAAE;QAAE,QAAQ,CAAC,EAAE,MAAM,CAAC;QAAC,QAAQ,CAAC,EAAE,MAAM,CAAC;QAAC,MAAM,CAAC,EAAE,WAAW,CAAA;KAAO,GACxE,aAAa;IA6BhB,OAAO,CAAC,MAAM,CAAC,oBAAoB;IASnC,OAAO,CAAC,MAAM,CAAC,aAAa;IA8B5B,OAAO,CAAC,MAAM,CAAC,eAAe;IAO9B,OAAO,CAAC,MAAM,CAAC,WAAW;IAW1B,OAAO,CAAC,MAAM,CAAC,gBAAgB;IAqC/B,OAAO,CAAC,MAAM,CAAC,aAAa;IAa5B,OAAO,CAAC,MAAM,CAAC,WAAW;IAa1B,OAAO,CAAC,MAAM,CAAC,kBAAkB;CAWlC"}