@better-media/plugin-video-streaming 0.6.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.
- package/LICENSE +21 -0
- package/dist/index.d.mts +138 -0
- package/dist/index.d.ts +138 -0
- package/dist/index.js +619 -0
- package/dist/index.js.map +1 -0
- package/dist/index.mjs +606 -0
- package/dist/index.mjs.map +1 -0
- package/package.json +61 -0
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 abenezeratnafu
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS
|
|
20
|
+
ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THE
|
|
21
|
+
SOFTWARE.
|
package/dist/index.d.mts
ADDED
|
@@ -0,0 +1,138 @@
|
|
|
1
|
+
import { PipelineContext, DatabaseAdapter, StorageAdapter, PipelinePlugin } from '@better-media/core';
|
|
2
|
+
|
|
3
|
+
type StreamingFormat = "hls" | "dash";
|
|
4
|
+
interface StreamingProgressEvent {
|
|
5
|
+
/** Which streaming format is being transcoded. */
|
|
6
|
+
format: StreamingFormat;
|
|
7
|
+
/** For HLS: the preset currently being transcoded (one pass per preset). Absent for DASH. */
|
|
8
|
+
preset?: string;
|
|
9
|
+
/** Estimated completion percentage (0–100). */
|
|
10
|
+
percent?: number;
|
|
11
|
+
/** How far into the source video ffmpeg has processed, in seconds. */
|
|
12
|
+
currentTimeSecs?: number;
|
|
13
|
+
}
|
|
14
|
+
interface StreamingPreset {
|
|
15
|
+
/** Used in storage path, e.g. "360p", "720p". Must be stable for idempotent keys. */
|
|
16
|
+
name: string;
|
|
17
|
+
/** Output width (px). Aspect ratio preserved if only height is set. */
|
|
18
|
+
width?: number;
|
|
19
|
+
/** Output height (px). Aspect ratio preserved if only width is set. */
|
|
20
|
+
height?: number;
|
|
21
|
+
/** Video bitrate, e.g. "1000k". */
|
|
22
|
+
videoBitrate?: string;
|
|
23
|
+
/** Audio bitrate, e.g. "128k". */
|
|
24
|
+
audioBitrate?: string;
|
|
25
|
+
/** Video codec. Default: "libx264". */
|
|
26
|
+
videoCodec?: string;
|
|
27
|
+
/** Audio codec. Default: "aac". */
|
|
28
|
+
audioCodec?: string;
|
|
29
|
+
}
|
|
30
|
+
interface VideoStreamingPluginOptions {
|
|
31
|
+
/**
|
|
32
|
+
* Streaming formats to generate. Default: ["hls"].
|
|
33
|
+
* Add "dash" to also produce a DASH manifest.
|
|
34
|
+
*/
|
|
35
|
+
formats?: StreamingFormat[];
|
|
36
|
+
/** Quality presets to transcode. Default: 360p / 720p / 1080p. */
|
|
37
|
+
presets?: StreamingPreset[];
|
|
38
|
+
/**
|
|
39
|
+
* Adjust each preset at runtime from context.metadata (e.g. restrict max quality
|
|
40
|
+
* based on subscription tier).
|
|
41
|
+
*/
|
|
42
|
+
resolvePreset?: (context: PipelineContext, preset: StreamingPreset, index: number) => StreamingPreset | Promise<StreamingPreset>;
|
|
43
|
+
/** Only process files whose mimeType is in this list. Default: common video types. */
|
|
44
|
+
allowedMimeTypes?: string[];
|
|
45
|
+
/** Prefix for streaming storage keys. Default: "streaming". */
|
|
46
|
+
derivativePrefix?: string;
|
|
47
|
+
/** HLS/DASH segment duration in seconds. Default: 6. */
|
|
48
|
+
segmentDuration?: number;
|
|
49
|
+
/**
|
|
50
|
+
* Insert rows into media_versions for master playlists and variant playlists.
|
|
51
|
+
* Individual segments are never persisted. Default: true.
|
|
52
|
+
*/
|
|
53
|
+
persistMediaVersions?: boolean;
|
|
54
|
+
/**
|
|
55
|
+
* Skip transcoding if the master playlist already exists in storage. Default: true.
|
|
56
|
+
*/
|
|
57
|
+
skipExistingDerivatives?: boolean;
|
|
58
|
+
/** Timeout for the full transcoding pass (ms). Default: 600_000 (10 min). */
|
|
59
|
+
timeoutMs?: number;
|
|
60
|
+
/**
|
|
61
|
+
* Called periodically during transcoding with ffmpeg progress information.
|
|
62
|
+
* For HLS each preset runs as a separate pass, so events include the preset name.
|
|
63
|
+
* For DASH all presets run in a single pass, so `preset` is absent.
|
|
64
|
+
*/
|
|
65
|
+
onProgress?: (event: StreamingProgressEvent) => void;
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
declare const DEFAULT_STREAMING_PRESETS: StreamingPreset[];
|
|
69
|
+
declare const DEFAULT_VIDEO_MIME_TYPES: string[];
|
|
70
|
+
|
|
71
|
+
interface StreamingUrlResult {
|
|
72
|
+
/** Master HLS playlist URL, if HLS was generated for this record. */
|
|
73
|
+
hls?: string;
|
|
74
|
+
/** Master DASH manifest URL, if DASH was generated for this record. */
|
|
75
|
+
dash?: string;
|
|
76
|
+
}
|
|
77
|
+
interface ResolveStreamingUrlsOptions {
|
|
78
|
+
database: DatabaseAdapter;
|
|
79
|
+
storage: StorageAdapter;
|
|
80
|
+
/** When set, generates a signed URL expiring in this many seconds. */
|
|
81
|
+
expiresIn?: number;
|
|
82
|
+
/** Storage key prefix used at transcode time. Default: "streaming". */
|
|
83
|
+
derivativePrefix?: string;
|
|
84
|
+
}
|
|
85
|
+
declare function resolveStreamingUrls(recordId: string, options: ResolveStreamingUrlsOptions): Promise<StreamingUrlResult>;
|
|
86
|
+
|
|
87
|
+
interface StreamingStatus {
|
|
88
|
+
/** Whether the HLS master playlist is ready in storage. */
|
|
89
|
+
hls: boolean;
|
|
90
|
+
/** Whether the DASH master manifest is ready in storage. */
|
|
91
|
+
dash: boolean;
|
|
92
|
+
/** True when at least one format is ready for playback. */
|
|
93
|
+
ready: boolean;
|
|
94
|
+
}
|
|
95
|
+
interface ResolveStreamingStatusOptions {
|
|
96
|
+
storage: StorageAdapter;
|
|
97
|
+
/** Storage key prefix used at transcode time. Default: "streaming". */
|
|
98
|
+
derivativePrefix?: string;
|
|
99
|
+
}
|
|
100
|
+
declare function resolveStreamingStatus(recordId: string, options: ResolveStreamingStatusOptions): Promise<StreamingStatus>;
|
|
101
|
+
|
|
102
|
+
interface StreamingProxyOptions {
|
|
103
|
+
storage: StorageAdapter;
|
|
104
|
+
authenticate?: (req: unknown, context: {
|
|
105
|
+
recordId: string;
|
|
106
|
+
storageKey: string;
|
|
107
|
+
}) => Promise<void>;
|
|
108
|
+
cacheControl?: {
|
|
109
|
+
playlist?: string;
|
|
110
|
+
segment?: string;
|
|
111
|
+
};
|
|
112
|
+
/** CORS origin to allow. Default: "*". */
|
|
113
|
+
corsOrigin?: string;
|
|
114
|
+
/** Storage key prefix used at transcode time. Default: "streaming". */
|
|
115
|
+
derivativePrefix?: string;
|
|
116
|
+
}
|
|
117
|
+
interface ProxyHandleOptions {
|
|
118
|
+
recordId: string;
|
|
119
|
+
/** Relative path within the record, e.g. "hls/master.m3u8" or "hls/720p/seg001.ts". */
|
|
120
|
+
filePath: string;
|
|
121
|
+
/** Original request object — passed through to authenticate if provided. */
|
|
122
|
+
req?: unknown;
|
|
123
|
+
/** HTTP method. Default: "GET". HEAD returns headers only (no body). */
|
|
124
|
+
method?: string;
|
|
125
|
+
}
|
|
126
|
+
interface StreamingProxy {
|
|
127
|
+
handle(options: ProxyHandleOptions): Promise<Response>;
|
|
128
|
+
}
|
|
129
|
+
declare function createStreamingProxy(options: StreamingProxyOptions): StreamingProxy;
|
|
130
|
+
|
|
131
|
+
/**
|
|
132
|
+
* Video streaming plugin: adaptive-bitrate HLS (and optionally DASH) transcoding via ffmpeg.
|
|
133
|
+
*
|
|
134
|
+
* Requires `fluent-ffmpeg` peer dependency and the `ffmpeg` binary in PATH.
|
|
135
|
+
*/
|
|
136
|
+
declare function videoStreamingPlugin(opts?: VideoStreamingPluginOptions): PipelinePlugin;
|
|
137
|
+
|
|
138
|
+
export { DEFAULT_STREAMING_PRESETS, DEFAULT_VIDEO_MIME_TYPES, type ProxyHandleOptions, type ResolveStreamingStatusOptions, type ResolveStreamingUrlsOptions, type StreamingFormat, type StreamingPreset, type StreamingProgressEvent, type StreamingProxy, type StreamingProxyOptions, type StreamingStatus, type StreamingUrlResult, type VideoStreamingPluginOptions, createStreamingProxy, resolveStreamingStatus, resolveStreamingUrls, videoStreamingPlugin };
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,138 @@
|
|
|
1
|
+
import { PipelineContext, DatabaseAdapter, StorageAdapter, PipelinePlugin } from '@better-media/core';
|
|
2
|
+
|
|
3
|
+
type StreamingFormat = "hls" | "dash";
|
|
4
|
+
interface StreamingProgressEvent {
|
|
5
|
+
/** Which streaming format is being transcoded. */
|
|
6
|
+
format: StreamingFormat;
|
|
7
|
+
/** For HLS: the preset currently being transcoded (one pass per preset). Absent for DASH. */
|
|
8
|
+
preset?: string;
|
|
9
|
+
/** Estimated completion percentage (0–100). */
|
|
10
|
+
percent?: number;
|
|
11
|
+
/** How far into the source video ffmpeg has processed, in seconds. */
|
|
12
|
+
currentTimeSecs?: number;
|
|
13
|
+
}
|
|
14
|
+
interface StreamingPreset {
|
|
15
|
+
/** Used in storage path, e.g. "360p", "720p". Must be stable for idempotent keys. */
|
|
16
|
+
name: string;
|
|
17
|
+
/** Output width (px). Aspect ratio preserved if only height is set. */
|
|
18
|
+
width?: number;
|
|
19
|
+
/** Output height (px). Aspect ratio preserved if only width is set. */
|
|
20
|
+
height?: number;
|
|
21
|
+
/** Video bitrate, e.g. "1000k". */
|
|
22
|
+
videoBitrate?: string;
|
|
23
|
+
/** Audio bitrate, e.g. "128k". */
|
|
24
|
+
audioBitrate?: string;
|
|
25
|
+
/** Video codec. Default: "libx264". */
|
|
26
|
+
videoCodec?: string;
|
|
27
|
+
/** Audio codec. Default: "aac". */
|
|
28
|
+
audioCodec?: string;
|
|
29
|
+
}
|
|
30
|
+
interface VideoStreamingPluginOptions {
|
|
31
|
+
/**
|
|
32
|
+
* Streaming formats to generate. Default: ["hls"].
|
|
33
|
+
* Add "dash" to also produce a DASH manifest.
|
|
34
|
+
*/
|
|
35
|
+
formats?: StreamingFormat[];
|
|
36
|
+
/** Quality presets to transcode. Default: 360p / 720p / 1080p. */
|
|
37
|
+
presets?: StreamingPreset[];
|
|
38
|
+
/**
|
|
39
|
+
* Adjust each preset at runtime from context.metadata (e.g. restrict max quality
|
|
40
|
+
* based on subscription tier).
|
|
41
|
+
*/
|
|
42
|
+
resolvePreset?: (context: PipelineContext, preset: StreamingPreset, index: number) => StreamingPreset | Promise<StreamingPreset>;
|
|
43
|
+
/** Only process files whose mimeType is in this list. Default: common video types. */
|
|
44
|
+
allowedMimeTypes?: string[];
|
|
45
|
+
/** Prefix for streaming storage keys. Default: "streaming". */
|
|
46
|
+
derivativePrefix?: string;
|
|
47
|
+
/** HLS/DASH segment duration in seconds. Default: 6. */
|
|
48
|
+
segmentDuration?: number;
|
|
49
|
+
/**
|
|
50
|
+
* Insert rows into media_versions for master playlists and variant playlists.
|
|
51
|
+
* Individual segments are never persisted. Default: true.
|
|
52
|
+
*/
|
|
53
|
+
persistMediaVersions?: boolean;
|
|
54
|
+
/**
|
|
55
|
+
* Skip transcoding if the master playlist already exists in storage. Default: true.
|
|
56
|
+
*/
|
|
57
|
+
skipExistingDerivatives?: boolean;
|
|
58
|
+
/** Timeout for the full transcoding pass (ms). Default: 600_000 (10 min). */
|
|
59
|
+
timeoutMs?: number;
|
|
60
|
+
/**
|
|
61
|
+
* Called periodically during transcoding with ffmpeg progress information.
|
|
62
|
+
* For HLS each preset runs as a separate pass, so events include the preset name.
|
|
63
|
+
* For DASH all presets run in a single pass, so `preset` is absent.
|
|
64
|
+
*/
|
|
65
|
+
onProgress?: (event: StreamingProgressEvent) => void;
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
declare const DEFAULT_STREAMING_PRESETS: StreamingPreset[];
|
|
69
|
+
declare const DEFAULT_VIDEO_MIME_TYPES: string[];
|
|
70
|
+
|
|
71
|
+
interface StreamingUrlResult {
|
|
72
|
+
/** Master HLS playlist URL, if HLS was generated for this record. */
|
|
73
|
+
hls?: string;
|
|
74
|
+
/** Master DASH manifest URL, if DASH was generated for this record. */
|
|
75
|
+
dash?: string;
|
|
76
|
+
}
|
|
77
|
+
interface ResolveStreamingUrlsOptions {
|
|
78
|
+
database: DatabaseAdapter;
|
|
79
|
+
storage: StorageAdapter;
|
|
80
|
+
/** When set, generates a signed URL expiring in this many seconds. */
|
|
81
|
+
expiresIn?: number;
|
|
82
|
+
/** Storage key prefix used at transcode time. Default: "streaming". */
|
|
83
|
+
derivativePrefix?: string;
|
|
84
|
+
}
|
|
85
|
+
declare function resolveStreamingUrls(recordId: string, options: ResolveStreamingUrlsOptions): Promise<StreamingUrlResult>;
|
|
86
|
+
|
|
87
|
+
interface StreamingStatus {
|
|
88
|
+
/** Whether the HLS master playlist is ready in storage. */
|
|
89
|
+
hls: boolean;
|
|
90
|
+
/** Whether the DASH master manifest is ready in storage. */
|
|
91
|
+
dash: boolean;
|
|
92
|
+
/** True when at least one format is ready for playback. */
|
|
93
|
+
ready: boolean;
|
|
94
|
+
}
|
|
95
|
+
interface ResolveStreamingStatusOptions {
|
|
96
|
+
storage: StorageAdapter;
|
|
97
|
+
/** Storage key prefix used at transcode time. Default: "streaming". */
|
|
98
|
+
derivativePrefix?: string;
|
|
99
|
+
}
|
|
100
|
+
declare function resolveStreamingStatus(recordId: string, options: ResolveStreamingStatusOptions): Promise<StreamingStatus>;
|
|
101
|
+
|
|
102
|
+
interface StreamingProxyOptions {
|
|
103
|
+
storage: StorageAdapter;
|
|
104
|
+
authenticate?: (req: unknown, context: {
|
|
105
|
+
recordId: string;
|
|
106
|
+
storageKey: string;
|
|
107
|
+
}) => Promise<void>;
|
|
108
|
+
cacheControl?: {
|
|
109
|
+
playlist?: string;
|
|
110
|
+
segment?: string;
|
|
111
|
+
};
|
|
112
|
+
/** CORS origin to allow. Default: "*". */
|
|
113
|
+
corsOrigin?: string;
|
|
114
|
+
/** Storage key prefix used at transcode time. Default: "streaming". */
|
|
115
|
+
derivativePrefix?: string;
|
|
116
|
+
}
|
|
117
|
+
interface ProxyHandleOptions {
|
|
118
|
+
recordId: string;
|
|
119
|
+
/** Relative path within the record, e.g. "hls/master.m3u8" or "hls/720p/seg001.ts". */
|
|
120
|
+
filePath: string;
|
|
121
|
+
/** Original request object — passed through to authenticate if provided. */
|
|
122
|
+
req?: unknown;
|
|
123
|
+
/** HTTP method. Default: "GET". HEAD returns headers only (no body). */
|
|
124
|
+
method?: string;
|
|
125
|
+
}
|
|
126
|
+
interface StreamingProxy {
|
|
127
|
+
handle(options: ProxyHandleOptions): Promise<Response>;
|
|
128
|
+
}
|
|
129
|
+
declare function createStreamingProxy(options: StreamingProxyOptions): StreamingProxy;
|
|
130
|
+
|
|
131
|
+
/**
|
|
132
|
+
* Video streaming plugin: adaptive-bitrate HLS (and optionally DASH) transcoding via ffmpeg.
|
|
133
|
+
*
|
|
134
|
+
* Requires `fluent-ffmpeg` peer dependency and the `ffmpeg` binary in PATH.
|
|
135
|
+
*/
|
|
136
|
+
declare function videoStreamingPlugin(opts?: VideoStreamingPluginOptions): PipelinePlugin;
|
|
137
|
+
|
|
138
|
+
export { DEFAULT_STREAMING_PRESETS, DEFAULT_VIDEO_MIME_TYPES, type ProxyHandleOptions, type ResolveStreamingStatusOptions, type ResolveStreamingUrlsOptions, type StreamingFormat, type StreamingPreset, type StreamingProgressEvent, type StreamingProxy, type StreamingProxyOptions, type StreamingStatus, type StreamingUrlResult, type VideoStreamingPluginOptions, createStreamingProxy, resolveStreamingStatus, resolveStreamingUrls, videoStreamingPlugin };
|