@obipascal/player 1.0.6 → 1.0.8

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/README.md CHANGED
@@ -240,6 +240,7 @@ function VideoPlayer({ videoUrl }: VideoPlayerProps) {
240
240
 
241
241
  const s3config: S3Config = {
242
242
  cloudFrontDomains: [url.hostname],
243
+ withCredentials: true, // Enable cookies for CloudFront signed cookies
243
244
  signUrl: async (resourceUrl: string) => {
244
245
  try {
245
246
  const { data } = await refetch({
@@ -336,6 +337,7 @@ async function initializePlayer() {
336
337
  container: "#player",
337
338
  s3Config: {
338
339
  cloudFrontDomains: ["media.yourdomain.com"], // Your CloudFront domain
340
+ withCredentials: true, // Enable cookies for all HLS requests (required for CloudFront signed cookies)
339
341
  signUrl: async (url) => {
340
342
  // This function is called when player needs to access a video
341
343
  // Call your backend to refresh/set cookies if needed
@@ -734,9 +736,19 @@ interface WontumPlayerConfig {
734
736
  poster?: string // Poster image URL
735
737
  preload?: "none" | "metadata" | "auto" // Preload strategy
736
738
  theme?: PlayerTheme // Custom theme
737
- s3Config?: S3Config // S3 configuration
739
+ s3Config?: S3Config // S3/CloudFront configuration
738
740
  analytics?: AnalyticsConfig // Analytics configuration
739
741
  hlsConfig?: Partial<any> // HLS.js config override
742
+ subtitles?: SubtitleTrack[] // Subtitle tracks
743
+ stickyControls?: boolean // Keep controls always visible
744
+ }
745
+
746
+ interface S3Config {
747
+ signUrl?: (url: string) => Promise<string> // Sign URL and set cookies
748
+ cloudFrontDomains?: string[] // CloudFront domains (e.g., ['media.example.com'])
749
+ withCredentials?: boolean // Enable cookies for HLS requests (default: false, required for CloudFront signed cookies)
750
+ region?: string // S3 region
751
+ endpoint?: string // Custom S3 endpoint
740
752
  }
741
753
  ```
742
754
 
@@ -758,11 +770,17 @@ player.setPlaybackRate(rate: number): void // 0.5, 1, 1.5, 2, etc.
758
770
 
759
771
  // Quality control
760
772
  player.setQuality(qualityIndex: number): void
773
+ player.getQualities(): QualityLevel[]
761
774
 
762
775
  // Fullscreen
763
776
  player.enterFullscreen(): void
764
777
  player.exitFullscreen(): void
765
778
 
779
+ // Picture-in-Picture
780
+ player.enterPictureInPicture(): Promise<void>
781
+ player.exitPictureInPicture(): Promise<void>
782
+ player.togglePictureInPicture(): Promise<void>
783
+
766
784
  // State
767
785
  player.getState(): PlayerState
768
786
 
@@ -792,6 +810,8 @@ type PlayerEventType =
792
810
  | "error"
793
811
  | "qualitychange"
794
812
  | "fullscreenchange"
813
+ | "pictureinpictureenter"
814
+ | "pictureinpictureexit"
795
815
  ```
796
816
 
797
817
  ### React Components
@@ -994,6 +1014,15 @@ player.on("qualitychange", (event) => {
994
1014
  console.log("Quality changed to:", event.data.quality)
995
1015
  })
996
1016
 
1017
+ // Picture-in-Picture events
1018
+ player.on("pictureinpictureenter", () => {
1019
+ console.log("Entered Picture-in-Picture mode")
1020
+ })
1021
+
1022
+ player.on("pictureinpictureexit", () => {
1023
+ console.log("Exited Picture-in-Picture mode")
1024
+ })
1025
+
997
1026
  // Buffer events
998
1027
  player.on("waiting", () => console.log("Buffering..."))
999
1028
  player.on("canplay", () => console.log("Ready to play"))
@@ -1065,10 +1094,132 @@ player.setQuality(2) // Set to quality index 2
1065
1094
  player.enterFullscreen()
1066
1095
  player.exitFullscreen()
1067
1096
 
1097
+ // Picture-in-Picture
1098
+ await player.enterPictureInPicture()
1099
+ await player.exitPictureInPicture()
1100
+ await player.togglePictureInPicture()
1101
+
1068
1102
  // Cleanup
1069
1103
  player.destroy() // Remove player and clean up resources
1070
1104
  ```
1071
1105
 
1106
+ ### Picture-in-Picture Mode
1107
+
1108
+ Enable floating video that stays on top while users work in other apps:
1109
+
1110
+ ```typescript
1111
+ const player = new WontumPlayer({
1112
+ src: "https://example.com/video.m3u8",
1113
+ container: "#player",
1114
+ })
1115
+
1116
+ // Enter PiP mode
1117
+ await player.enterPictureInPicture()
1118
+
1119
+ // Listen for PiP events
1120
+ player.on("pictureinpictureenter", () => {
1121
+ console.log("Video is now floating!")
1122
+ })
1123
+
1124
+ player.on("pictureinpictureexit", () => {
1125
+ console.log("Back to normal mode")
1126
+ })
1127
+
1128
+ // Custom button to toggle PiP
1129
+ const pipButton = document.getElementById("pip-btn")
1130
+ pipButton.addEventListener("click", async () => {
1131
+ await player.togglePictureInPicture()
1132
+ })
1133
+ ```
1134
+
1135
+ **Note:** Picture-in-Picture is supported in most modern browsers. The player includes a built-in PiP button in the controls.
1136
+
1137
+ ### File Information Utility
1138
+
1139
+ The SDK includes a `WontumFileInfo` utility class to extract metadata from video files before uploading or processing them.
1140
+
1141
+ ```typescript
1142
+ import { WontumFileInfo } from "@obipascal/player"
1143
+
1144
+ // Example: File input handling
1145
+ const fileInput = document.querySelector<HTMLInputElement>("#video-upload")
1146
+
1147
+ fileInput.addEventListener("change", async (event) => {
1148
+ const file = event.target.files?.[0]
1149
+ if (!file) return
1150
+
1151
+ try {
1152
+ // Create instance (validates it's a video file)
1153
+ const videoInfo = new WontumFileInfo(file)
1154
+
1155
+ // Extract metadata
1156
+ await videoInfo.extract()
1157
+
1158
+ // Access properties
1159
+ console.log("Video Information:")
1160
+ console.log("- Width:", videoInfo.width) // e.g., 1920
1161
+ console.log("- Height:", videoInfo.height) // e.g., 1080
1162
+ console.log("- Aspect Ratio:", videoInfo.aspectRatio) // e.g., "16:9"
1163
+ console.log("- Quality:", videoInfo.quality) // e.g., "Full HD (1080p)"
1164
+ console.log("- Duration (raw):", videoInfo.durationInSeconds, "seconds") // e.g., 125.5
1165
+ console.log("- Formatted Duration:", videoInfo.durationFormatted) // e.g., "02:05"
1166
+ console.log("- File Size (raw):", videoInfo.sizeInBytes, "bytes") // e.g., 52428800
1167
+ console.log("- Formatted Size:", videoInfo.sizeFormatted) // e.g., "50 MB"
1168
+ console.log("- MIME Type:", videoInfo.mimeType) // e.g., "video/mp4"
1169
+ console.log("- File Name:", videoInfo.fileName) // e.g., "my-video.mp4"
1170
+ console.log("- Extension:", videoInfo.fileExtension) // e.g., ".mp4"
1171
+ console.log("- Bitrate:", videoInfo.bitrate, "kbps") // e.g., 3500
1172
+
1173
+ // Get all info as object
1174
+ const allInfo = videoInfo.getInfo()
1175
+ console.log(allInfo)
1176
+
1177
+ // Clean up when done
1178
+ videoInfo.destroy()
1179
+ } catch (error) {
1180
+ console.error("Error extracting video info:", error.message)
1181
+ // Throws error if file is not a video
1182
+ }
1183
+ })
1184
+ ```
1185
+
1186
+ #### WontumFileInfo API
1187
+
1188
+ **Constructor:**
1189
+
1190
+ ```typescript
1191
+ new WontumFileInfo(file: File)
1192
+ ```
1193
+
1194
+ Throws an error if the file is not a valid video file.
1195
+
1196
+ **Methods:**
1197
+
1198
+ - `extract(): Promise<VideoFileInfo>` - Extracts metadata from the video file
1199
+ - `getInfo(): VideoFileInfo | null` - Returns the extracted information object
1200
+ - `destroy(): void` - Cleans up resources
1201
+
1202
+ **Properties (available after calling `extract()`):**
1203
+
1204
+ - `width: number` - Video width in pixels
1205
+ - `height: number` - Video height in pixels
1206
+ - `aspectRatio: string` - Aspect ratio (e.g., "16:9", "4:3", "21:9")
1207
+ - `quality: string` - Quality description (e.g., "4K (2160p)", "Full HD (1080p)")
1208
+ - `size: number` - File size in bytes (raw value for computation)
1209
+ - `sizeInBytes: number` - Alias for size (raw value for computation)
1210
+ - `sizeFormatted: string` - Human-readable size (e.g., "50 MB")
1211
+ - `duration: number` - Duration in seconds (raw value for computation)
1212
+ - `durationInSeconds: number` - Alias for duration (raw value for computation)
1213
+ - `durationFormatted: string` - Formatted duration (e.g., "01:23:45")
1214
+ - `mimeType: string` - MIME type (e.g., "video/mp4")
1215
+ - `fileName: string` - Original file name
1216
+ - `fileExtension: string` - File extension (e.g., ".mp4")
1217
+ - `bitrate: number | undefined` - Estimated bitrate in kbps
1218
+
1219
+ **Supported Video Formats:**
1220
+
1221
+ `.mp4`, `.webm`, `.ogg`, `.mov`, `.avi`, `.mkv`, `.flv`, `.wmv`, `.m4v`, `.3gp`, `.ts`, `.m3u8`
1222
+
1072
1223
  ## 📋 Complete API Reference
1073
1224
 
1074
1225
  For detailed API documentation including all methods, events, types, and configuration options, see **[API-REFERENCE.md](./API-REFERENCE.md)**.
@@ -1083,6 +1234,7 @@ For detailed API documentation including all methods, events, types, and configu
1083
1234
  - **Quality:** `setQuality(index)`, `getQualities()`
1084
1235
  - **Playback Rate:** `setPlaybackRate(rate)`
1085
1236
  - **Fullscreen:** `enterFullscreen()`, `exitFullscreen()`
1237
+ - **Picture-in-Picture:** `enterPictureInPicture()`, `exitPictureInPicture()`, `togglePictureInPicture()`
1086
1238
  - **State:** `getState()`, `getCurrentTime()`, `getDuration()`
1087
1239
  - **Lifecycle:** `destroy()`
1088
1240
 
@@ -1129,9 +1281,9 @@ Contributions are welcome! Please follow these steps:
1129
1281
 
1130
1282
  ## 💬 Support
1131
1283
 
1132
- - **Issues:** [GitHub Issues](https://github.com/yourorg/wontum-player/issues)
1133
- - **Discussions:** [GitHub Discussions](https://github.com/yourorg/wontum-player/discussions)
1134
- - **Email:** support@wontum.com
1284
+ - **Issues:** [GitHub Issues](https://github.com/obipascal/wontum-player/issues)
1285
+ - **Discussions:** [GitHub Discussions](https://github.com/obipascal/wontum-player/discussions)
1286
+ - **Email:** pascalobi83@gmail.com
1135
1287
 
1136
1288
  ## 🙏 Acknowledgments
1137
1289
 
@@ -0,0 +1,78 @@
1
+ /**
2
+ * Video file information extractor
3
+ * Extracts metadata from video files (width, height, duration, size, etc.)
4
+ */
5
+ export interface VideoFileInfo {
6
+ width: number;
7
+ height: number;
8
+ aspectRatio: string;
9
+ size: number;
10
+ sizeInBytes: number;
11
+ sizeFormatted: string;
12
+ duration: number;
13
+ durationInSeconds: number;
14
+ durationFormatted: string;
15
+ mimeType: string;
16
+ fileName: string;
17
+ fileExtension: string;
18
+ bitrate?: number;
19
+ frameRate?: number;
20
+ videoCodec?: string;
21
+ audioCodec?: string;
22
+ }
23
+ export declare class WontumFileInfo {
24
+ private file;
25
+ private videoElement;
26
+ private info;
27
+ constructor(file: File);
28
+ /**
29
+ * Check if the file is a valid video file
30
+ */
31
+ private isVideoFile;
32
+ /**
33
+ * Extract video metadata
34
+ */
35
+ extract(): Promise<VideoFileInfo>;
36
+ /**
37
+ * Calculate aspect ratio (e.g., "16:9", "4:3")
38
+ */
39
+ private calculateAspectRatio;
40
+ /**
41
+ * Get Greatest Common Divisor
42
+ */
43
+ private getGCD;
44
+ /**
45
+ * Format bytes to human-readable size
46
+ */
47
+ private formatBytes;
48
+ /**
49
+ * Format duration to HH:MM:SS
50
+ */
51
+ private formatDuration;
52
+ /**
53
+ * Get file extension
54
+ */
55
+ private getFileExtension;
56
+ get width(): number;
57
+ get height(): number;
58
+ get aspectRatio(): string;
59
+ get size(): number;
60
+ get sizeInBytes(): number;
61
+ get sizeFormatted(): string;
62
+ get duration(): number;
63
+ get durationInSeconds(): number;
64
+ get durationFormatted(): string;
65
+ get mimeType(): string;
66
+ get fileName(): string;
67
+ get fileExtension(): string;
68
+ get bitrate(): number | undefined;
69
+ get quality(): string;
70
+ /**
71
+ * Get all information as object
72
+ */
73
+ getInfo(): VideoFileInfo | null;
74
+ /**
75
+ * Clean up resources
76
+ */
77
+ destroy(): void;
78
+ }
@@ -2,6 +2,8 @@ export { WontumPlayer } from './player';
2
2
  export { Analytics } from './analytics';
3
3
  export { S3Handler } from './s3-handler';
4
4
  export { UIController } from './ui-controller';
5
+ export { WontumFileInfo } from './file-info';
5
6
  export { WontumPlayerReact, useWontumPlayer, WontumPlayerProvider, useWontumPlayerContext } from './react';
6
7
  export type { WontumPlayerConfig, PlayerTheme, S3Config, AnalyticsConfig, PlayerState, PlayerEvent, PlayerEventType, AnalyticsEvent, QualityLevel } from './types';
8
+ export type { VideoFileInfo } from './file-info';
7
9
  export type { WontumPlayerReactProps } from './react';
@@ -36,6 +36,9 @@ export declare class WontumPlayer {
36
36
  getQualities(): QualityLevel[];
37
37
  enterFullscreen(): void;
38
38
  exitFullscreen(): void;
39
+ enterPictureInPicture(): Promise<void>;
40
+ exitPictureInPicture(): Promise<void>;
41
+ togglePictureInPicture(): Promise<void>;
39
42
  getState(): PlayerState;
40
43
  getVideoElement(): HTMLVideoElement;
41
44
  /**
@@ -45,6 +45,8 @@ export interface S3Config {
45
45
  getPresignedUrl?: (key: string) => Promise<string>;
46
46
  /** CloudFront domain patterns to match (e.g., ['media.domain.com']) */
47
47
  cloudFrontDomains?: string[];
48
+ /** Enable credentials (cookies) for HLS requests - required for CloudFront signed cookies */
49
+ withCredentials?: boolean;
48
50
  /** S3 bucket region */
49
51
  region?: string;
50
52
  /** Custom S3 endpoint */
@@ -82,7 +84,7 @@ export interface PlayerState {
82
84
  /**
83
85
  * Player events (compatible with Mux Player and HTML5 MediaElement events)
84
86
  */
85
- export type PlayerEventType = "play" | "pause" | "playing" | "ended" | "timeupdate" | "volumechange" | "ratechange" | "seeked" | "seeking" | "waiting" | "loadstart" | "loadeddata" | "loadedmetadata" | "canplay" | "canplaythrough" | "durationchange" | "progress" | "error" | "abort" | "emptied" | "stalled" | "suspend" | "qualitychange" | "fullscreenchange" | "resize";
87
+ export type PlayerEventType = "play" | "pause" | "playing" | "ended" | "timeupdate" | "volumechange" | "ratechange" | "seeked" | "seeking" | "waiting" | "loadstart" | "loadeddata" | "loadedmetadata" | "canplay" | "canplaythrough" | "durationchange" | "progress" | "error" | "abort" | "emptied" | "stalled" | "suspend" | "qualitychange" | "fullscreenchange" | "pictureinpictureenter" | "pictureinpictureexit" | "resize";
86
88
  export interface PlayerEvent {
87
89
  type: PlayerEventType;
88
90
  data?: any;
@@ -13,12 +13,15 @@ export declare class UIController {
13
13
  private skipBackwardButton;
14
14
  private skipForwardButton;
15
15
  private volumeButton;
16
+ private volumeContainer;
16
17
  private fullscreenButton;
18
+ private pipButton;
17
19
  private settingsButton;
18
20
  private volumeSlider;
19
21
  private progressInput;
20
22
  private hideControlsTimeout;
21
23
  private stickyControls;
24
+ private isVolumeSliderActive;
22
25
  constructor(container: HTMLElement, player: WontumPlayer);
23
26
  private injectStyles;
24
27
  private createProgressBar;
@@ -38,6 +41,7 @@ export declare class UIController {
38
41
  private getVolumeIcon;
39
42
  private getMutedIcon;
40
43
  private getFullscreenIcon;
44
+ private getPipIcon;
41
45
  private getSkipBackwardIcon;
42
46
  private getSkipForwardIcon;
43
47
  private getSettingsIcon;