@nomercy-entertainment/nomercy-video-player 0.3.2 → 0.3.4

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/dist/index.d.ts CHANGED
@@ -151,10 +151,10 @@ declare class NMPlayer<T> extends Base<T> {
151
151
  createBaseStyles(): void;
152
152
  createSubtitleFontFamily(): void;
153
153
  createSubtitleOverlay(): void;
154
- setSubtitleStyle(style: SubtitleStyle): void;
154
+ setSubtitleStyle(style: Partial<SubtitleStyle>): void;
155
155
  getSubtitleStyle(): SubtitleStyle;
156
156
  private applySubtitleStyle;
157
- computeSubtitlePosition: (cue: Cue, videoElement: HTMLVideoElement, subtitleSafeZone: HTMLElement, subtitleArea: HTMLElement, subtitleText: HTMLElement) => void;
157
+ computeSubtitlePosition: (cue: Cue, videoElement: HTMLVideoElement, subtitleArea: HTMLElement, subtitleText: HTMLElement) => void;
158
158
  /**
159
159
  * This method is called every time event of the video element.
160
160
  * It will generate the content of the subtitle overlay.
package/dist/index.js CHANGED
@@ -122,28 +122,24 @@ class NMPlayer extends base_1.Base {
122
122
  console.error('Failed to fetch file contents', reason);
123
123
  });
124
124
  };
125
- this.computeSubtitlePosition = (cue, videoElement, subtitleSafeZone, subtitleArea, subtitleText) => {
126
- if (!videoElement || !subtitleSafeZone || !subtitleArea || !subtitleText) {
125
+ this.computeSubtitlePosition = (cue, videoElement, subtitleArea, subtitleText) => {
126
+ if (!videoElement || !subtitleArea || !subtitleText) {
127
127
  return;
128
128
  }
129
129
  const videoHeight = videoElement.clientHeight;
130
- const safeZoneHeight = subtitleSafeZone.clientHeight;
131
130
  const subtitleHeight = subtitleArea.clientHeight;
132
- let insetTop = videoHeight;
131
+ // Handle vertical positioning
133
132
  if (typeof cue.linePosition === "number") {
134
- if (cue.linePosition === 50) {
135
- // Calculate the exact offset for centering.
136
- insetTop = videoHeight / 2 - subtitleHeight / 2;
137
- }
138
- else {
139
- insetTop = (videoHeight * (cue.linePosition / 100)) - (subtitleHeight * (cue.linePosition / 100));
140
- }
133
+ const verticalPos = cue.linePosition === 50
134
+ ? `${50 - (subtitleHeight / videoHeight * 50)}%` // Center
135
+ : `${cue.linePosition}%`; // Specified position
136
+ subtitleArea.style.bottom = '';
137
+ subtitleArea.style.top = verticalPos;
138
+ }
139
+ else {
140
+ subtitleArea.style.top = '';
141
+ subtitleArea.style.bottom = '3%';
141
142
  }
142
- const safeZoneTop = subtitleSafeZone.getBoundingClientRect().top - videoElement.getBoundingClientRect().top;
143
- const safeZoneBottom = safeZoneTop + safeZoneHeight;
144
- const buffer = 10;
145
- insetTop = Math.max(safeZoneTop + buffer, Math.min(insetTop, safeZoneBottom - subtitleHeight - buffer));
146
- subtitleArea.style.inset = `${insetTop}px 0px 0px`;
147
143
  // Handle alignment
148
144
  subtitleArea.classList.remove("aligned-start", "aligned-center", "aligned-end");
149
145
  if (cue.alignment === "start" || cue.alignment === "left") {
@@ -155,16 +151,16 @@ class NMPlayer extends base_1.Base {
155
151
  else if (cue.alignment === "end" || cue.alignment === "right") {
156
152
  subtitleArea.classList.add("aligned-end");
157
153
  }
158
- // Handle size (width percentage)
154
+ // Handle width
159
155
  if (cue.size >= 0 && cue.size <= 100) {
160
- subtitleArea.classList.add("sized");
161
- subtitleArea.style.width = `${cue.size}%`;
162
- subtitleArea.style.left = `${(100 - cue.size) / 2}%`;
156
+ subtitleArea.style.width = `calc(${cue.size}% - 6%)`;
157
+ subtitleArea.style.left = `calc(${(100 - cue.size) / 2}% + 3%)`;
158
+ subtitleArea.style.right = `calc(${(100 - cue.size) / 2}% + 3%)`;
163
159
  }
164
160
  else {
165
- subtitleArea.classList.remove("sized");
166
- subtitleArea.style.width = `100%`;
167
- subtitleArea.style.left = `0%`;
161
+ subtitleArea.style.width = '100%';
162
+ subtitleArea.style.left = '3%';
163
+ subtitleArea.style.right = '3%';
168
164
  }
169
165
  };
170
166
  this.inactivityTimeout = null;
@@ -497,11 +493,16 @@ class NMPlayer extends base_1.Base {
497
493
  writing-mode: horizontal-tb;
498
494
  unicode-bidi: plaintext;
499
495
  white-space: pre-line;
496
+ padding: 0.5rem 0;
500
497
  position: absolute;
501
498
  height: fit-content;
502
499
  font-size: 28px;
503
500
  }
504
501
 
502
+ .nomercyplayer:has(.subtitle-text:empty) .subtitle-overlay .subtitle-area {
503
+ display: none;
504
+ }
505
+
505
506
  .nomercyplayer .subtitle-overlay .subtitle-area.aligned-start {
506
507
  text-align: left;
507
508
  }
@@ -526,11 +527,17 @@ class NMPlayer extends base_1.Base {
526
527
 
527
528
  .nomercyplayer .subtitle-overlay .subtitle-text {
528
529
  white-space: pre-line;
529
- display: inline;
530
+ padding: 0 0.5rem;
531
+ display: inline-flex;
532
+ line-height: 1.2;
530
533
  writing-mode: horizontal-tb;
531
534
  unicode-bidi: plaintext;
532
535
  }
533
536
 
537
+ .nomercyplayer .subtitle-overlay .subtitle-text:empty {
538
+ display: none;
539
+ }
540
+
534
541
  .nomercyplayer .subtitle-text,
535
542
  .nomercyplayer .subtitle-text[data-language="eng"] {
536
543
  font-family: 'ReithSans', sans-serif;
@@ -642,21 +649,16 @@ class NMPlayer extends base_1.Base {
642
649
  this.subtitleOverlay = this.createElement('div', `${this.playerId}-subtitle-overlay`, true)
643
650
  .addClasses(['subtitle-overlay'])
644
651
  .appendTo(this.container);
645
- this.subtitleSafeZone = this.createElement('div', `${this.playerId}-subtitle-safezone`, true)
646
- .addClasses(['subtitle-safezone'])
647
- .appendTo(this.subtitleOverlay);
648
652
  this.subtitleArea = this.createElement('div', `${this.playerId}-subtitle-area`, true)
649
653
  .addClasses(['subtitle-area'])
650
- .appendTo(this.subtitleSafeZone);
654
+ .appendTo(this.subtitleOverlay);
651
655
  this.subtitleText = this.createElement('span', `${this.playerId}-subtitle-text`, true)
652
656
  .addClasses(['subtitle-text'])
653
657
  .appendTo(this.subtitleArea);
654
658
  this.on('time', this.checkSubtitles.bind(this));
655
- this.updateDisplayOverlay();
656
659
  this.storage.get('subtitle-style', helpers_1.defaultSubtitleStyles)
657
660
  .then((val) => {
658
661
  this.subtitleStyle = val;
659
- this.updateDisplayOverlay();
660
662
  this.applySubtitleStyle();
661
663
  });
662
664
  }
@@ -669,6 +671,12 @@ class NMPlayer extends base_1.Base {
669
671
  }
670
672
  applySubtitleStyle() {
671
673
  this.storage.set('subtitle-style', this.subtitleStyle).then();
674
+ Object.entries(this.subtitleStyle).forEach(([key, value]) => {
675
+ this.emit('set-subtitle-style', {
676
+ property: key,
677
+ value: value,
678
+ });
679
+ });
672
680
  const { fontSize, fontFamily, textColor, textOpacity, backgroundColor, backgroundOpacity, edgeStyle, areaColor, windowOpacity } = this.subtitleStyle;
673
681
  const areaElement = this.subtitleArea.style;
674
682
  const textElement = this.subtitleText.style;
@@ -721,7 +729,7 @@ class NMPlayer extends base_1.Base {
721
729
  this.subtitleText.appendChild(fragment);
722
730
  this.subtitleText.setAttribute('data-language', this.getCaptionLanguage());
723
731
  requestAnimationFrame(() => {
724
- this.computeSubtitlePosition(subtitleCue, this.videoElement, this.subtitleSafeZone, this.subtitleArea, this.subtitleText);
732
+ this.computeSubtitlePosition(subtitleCue, this.videoElement, this.subtitleArea, this.subtitleText);
725
733
  });
726
734
  }
727
735
  this.subtitleOverlay.style.display = 'block';
package/dist/types.d.ts CHANGED
@@ -345,7 +345,7 @@ export interface NMPlayer<Conf extends Partial<PlayerConfig> = {}> {
345
345
  usePlugin(id: string): void;
346
346
  volumeDown(): void;
347
347
  volumeUp(): void;
348
- setSubtitleStyle(style: SubtitleStyle): void;
348
+ setSubtitleStyle(style: Partial<SubtitleStyle>): void;
349
349
  getSubtitleStyle(): SubtitleStyle;
350
350
  emit(event: 'all', data?: any): void;
351
351
  emit(event: 'ready', data?: any): void;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@nomercy-entertainment/nomercy-video-player",
3
- "version": "0.3.2",
3
+ "version": "0.3.4",
4
4
  "description": "Full event-driven video player without a UI.",
5
5
  "type": "commonjs",
6
6
  "main": "./dist/index.js",
@@ -0,0 +1,245 @@
1
+ {
2
+ "off": "Uit",
3
+ "und": "Onbekend",
4
+ "zxx": "Geen",
5
+ "contain": "Bevatten",
6
+ "cover": "Bedekken",
7
+ "fill": "Vullen",
8
+
9
+ "aar": "Afar",
10
+ "abk": "Abchazisch",
11
+ "afr": "Afrikaans",
12
+ "aka": "Akan",
13
+ "alb": "Albanees",
14
+ "amh": "Amhaars",
15
+ "ara": "Arabisch",
16
+ "arg": "Aragonees",
17
+ "arm": "Armeens",
18
+ "asm": "Assamees",
19
+ "ava": "Avarisch",
20
+ "ave": "Avestisch",
21
+ "aym": "Aymara",
22
+ "aze": "Azerbeidzjaans",
23
+ "bak": "Basjkiers",
24
+ "bam": "Bambara",
25
+ "baq": "Baskisch",
26
+ "bel": "Wit-Russisch",
27
+ "ben": "Bengaals",
28
+ "bih": "Bihari",
29
+ "bis": "Bislama",
30
+ "bos": "Bosnisch",
31
+ "bra": "Braziliaans",
32
+ "bre": "Bretons",
33
+ "bul": "Bulgaars",
34
+ "bur": "Birmees",
35
+ "cat": "Catalaans",
36
+ "cha": "Chamorro",
37
+ "che": "Tsjetsjeens",
38
+ "chi": "Chinees",
39
+ "chu": "Oudkerkslavisch",
40
+ "chv": "Tsjoevasjisch",
41
+ "cor": "Cornisch",
42
+ "cro": "Kroatisch",
43
+ "cos": "Corsicaans",
44
+ "cre": "Cree",
45
+ "cze": "Tsjechisch",
46
+ "dan": "Deens",
47
+ "div": "Divehi, Maldivisch",
48
+ "dut": "Nederlands",
49
+ "dzo": "Dzongkha",
50
+ "eng": "Engels",
51
+ "epo": "Esperanto",
52
+ "est": "Ests",
53
+ "ewe": "Ewe",
54
+ "fao": "Faeröers",
55
+ "fij": "Fijisch",
56
+ "fil": "Filipijns",
57
+ "fin": "Fins",
58
+ "fre": "Frans",
59
+ "fry": "West-Fries",
60
+ "ful": "Fulah",
61
+ "geo": "Georgisch",
62
+ "ger": "Duits",
63
+ "gla": "Schots-Gaelisch",
64
+ "gle": "Iers",
65
+ "glg": "Galicisch",
66
+ "glv": "Manx",
67
+ "gre": "Grieks",
68
+ "grn": "Guaraní",
69
+ "gsw": "Zwitserduits",
70
+ "guj": "Gujarati",
71
+ "hat": "Haïtiaans",
72
+ "hau": "Hausa",
73
+ "haw": "Hawaïaans",
74
+ "heb": "Hebreeuws",
75
+ "her": "Herero",
76
+ "hin": "Hindi",
77
+ "hmo": "Hiri Motu",
78
+ "hrv": "Kroatisch",
79
+ "hun": "Hongaars",
80
+ "ibo": "Igbo",
81
+ "ice": "IJslands",
82
+ "ido": "Ido",
83
+ "iii": "Sichuan Yi",
84
+ "iku": "Inuktitut",
85
+ "ile": "Interlingue",
86
+ "ina": "Interlingua",
87
+ "ind": "Indonesisch",
88
+ "ipk": "Inupiaq",
89
+ "ita": "Italiaans",
90
+ "jav": "Javaans",
91
+ "jpn": "Japans",
92
+ "kan": "Kannada",
93
+ "kas": "Kasjmiri",
94
+ "kau": "Kanuri",
95
+ "kaz": "Kazachs",
96
+ "khm": "Khmer",
97
+ "kik": "Kikuyu",
98
+ "kin": "Kinyarwanda",
99
+ "kir": "Kirgizisch",
100
+ "kom": "Komi",
101
+ "kon": "Kongo",
102
+ "kor": "Koreaans",
103
+ "kua": "Kwanyama",
104
+ "kur": "Koerdisch",
105
+ "lao": "Lao",
106
+ "lat": "Latijn",
107
+ "lav": "Lets",
108
+ "lim": "Limburgs",
109
+ "lin": "Lingala",
110
+ "lit": "Litouws",
111
+ "ltz": "Luxemburgs",
112
+ "lub": "Luba-Katanga",
113
+ "lug": "Ganda",
114
+ "mac": "Macedonisch",
115
+ "mah": "Marshallees",
116
+ "mal": "Malayalam",
117
+ "mao": "Maori",
118
+ "mar": "Marathi",
119
+ "may": "Maleis",
120
+ "mlg": "Malagassisch",
121
+ "mlt": "Maltees",
122
+ "mon": "Mongools",
123
+ "nau": "Nauruaans",
124
+ "nav": "Navajo",
125
+ "nbl": "Zuid-Ndebele",
126
+ "nde": "Noord-Ndebele",
127
+ "ndo": "Ndonga",
128
+ "nep": "Nepalees",
129
+ "nno": "Noors Nynorsk",
130
+ "nob": "Noors Bokmål",
131
+ "nor": "Noors",
132
+ "nya": "Chichewa",
133
+ "oci": "Occitaans",
134
+ "oji": "Ojibwe",
135
+ "ori": "Oriya",
136
+ "orm": "Oromo",
137
+ "oss": "Ossetisch",
138
+ "pan": "Punjabi",
139
+ "per": "Perzisch",
140
+ "pli": "Pali",
141
+ "pob": "Braziliaans Portugees",
142
+ "pol": "Pools",
143
+ "por": "Portugees",
144
+ "pus": "Pasjtoe",
145
+ "que": "Quechua",
146
+ "roh": "Reto-Romaans",
147
+ "rum": "Roemeens",
148
+ "run": "Kirundi",
149
+ "rus": "Russisch",
150
+ "sag": "Sango",
151
+ "san": "Sanskriet",
152
+ "sin": "Singalees",
153
+ "slo": "Slowaaks",
154
+ "slv": "Sloveens",
155
+ "sme": "Noord-Sami",
156
+ "smo": "Samoaans",
157
+ "sna": "Shona",
158
+ "snd": "Sindhi",
159
+ "som": "Somalisch",
160
+ "sot": "Zuid-Sotho",
161
+ "spa": "Spaans",
162
+ "srd": "Sardijns",
163
+ "srp": "Servisch",
164
+ "ssw": "Swazi",
165
+ "sun": "Soendanees",
166
+ "swa": "Swahili",
167
+ "swe": "Zweeds",
168
+ "tah": "Tahitiaans",
169
+ "tam": "Tamil",
170
+ "tat": "Tataars",
171
+ "tel": "Telugu",
172
+ "tgk": "Tadzjieks",
173
+ "tgl": "Tagalog",
174
+ "tha": "Thais",
175
+ "tib": "Tibetaans",
176
+ "tir": "Tigrinya",
177
+ "ton": "Tongaans",
178
+ "tsn": "Tswana",
179
+ "tso": "Tsonga",
180
+ "tuk": "Turkmeens",
181
+ "tur": "Turks",
182
+ "twi": "Twi",
183
+ "uig": "Oeigoers",
184
+ "ukr": "Oekraïens",
185
+ "urd": "Urdu",
186
+ "uzb": "Oezbeeks",
187
+ "ven": "Venda",
188
+ "vie": "Vietnamees",
189
+ "vol": "Volapük",
190
+ "wel": "Welsh",
191
+ "wln": "Waals",
192
+ "wol": "Wolof",
193
+ "xho": "Xhosa",
194
+ "yid": "Jiddisch",
195
+ "yor": "Yoruba",
196
+ "zha": "Zhuang",
197
+ "zul": "Zulu",
198
+
199
+ "none": "geen",
200
+ "Audio and subtitles": "Audio en ondertiteling",
201
+ "Audio": "Audio",
202
+ "AudioTracks": "Audio Sporen",
203
+ "Back": "Terug",
204
+ "Backward": "Achteruit",
205
+ "Buffering": "Bufferen",
206
+ "E": "A",
207
+ "Episode": "Aflevering",
208
+ "episodes": "afleveringen",
209
+ "Episodes": "Afleveringen",
210
+ "ExitFullscreen": "Verlaat Volledig Scherm",
211
+ "Forward": "Vooruit",
212
+ "Fullscreen": "Volledig Scherm",
213
+ "Language": "Taal",
214
+ "Loading playlist item": "Afspeellijst item laden",
215
+ "Loading playlist": "Afspeellijst laden",
216
+ "Muted": "Gedempt",
217
+ "Mute": "Dempen",
218
+ "Next Episode": "Volgende Aflevering",
219
+ "Next": "Volgende",
220
+ "Normal": "Normaal",
221
+ "Off": "Uit",
222
+ "Pause": "Pauze",
223
+ "Play from beginning": "Speel vanaf het begin",
224
+ "Play": "Afspelen",
225
+ "Playlist": "Afspeellijst",
226
+ "Previous Episode": "Vorige Aflevering",
227
+ "Previous": "Vorige",
228
+ "Quality": "Kwaliteit",
229
+ "Resume playback": "Afspelen hervatten",
230
+ "S": "S",
231
+ "seconds": "seconden",
232
+ "Seconds": "Seconden",
233
+ "Seek backward": "Achteruit zoeken",
234
+ "Seek forward": "Vooruit zoeken",
235
+ "Settings": "Instellingen",
236
+ "Something went wrong trying to play this item": "Er is iets misgegaan bij het afspelen van dit item",
237
+ "SPACE": "SPATIE",
238
+ "Speed": "Snelheid",
239
+ "Stop": "Stop",
240
+ "styled": "gestyled",
241
+ "Subtitle": "Ondertiteling",
242
+ "Subtitles": "Ondertiteling",
243
+ "Video": "Video",
244
+ "Watch credits": "Bekijk credits"
245
+ }
package/src/index.ts CHANGED
@@ -8,7 +8,7 @@ import type Plugin from './plugin';
8
8
 
9
9
  import { defaultSubtitleStyles, getEdgeStyle, humanTime, pad, parseColorToHex, unique } from './helpers';
10
10
  import {
11
- PlaylistItem, PreviewTime, PlayerConfig, Stretching,
11
+ PlaylistItem, PreviewTime, PlayerConfig, Stretching,
12
12
  TimeData, Track, TypeMappings, Chapter, Level, SubtitleStyle,
13
13
  } from './types';
14
14
 
@@ -419,7 +419,7 @@ class NMPlayer<T> extends Base<T> {
419
419
  this.videoElement.controls = this.options.controls ?? false;
420
420
  this.videoElement.preload = this.options.preload ?? 'auto';
421
421
  this.storage.get('muted', this.options.muted).then((val) => {
422
- this.videoElement.muted = val == true;
422
+ this.videoElement.muted = val == true;
423
423
  });
424
424
  this.storage.get('volume', 100).then((val) => {
425
425
  this.videoElement.volume = val ? val / 100 : 1;
@@ -510,11 +510,16 @@ class NMPlayer<T> extends Base<T> {
510
510
  writing-mode: horizontal-tb;
511
511
  unicode-bidi: plaintext;
512
512
  white-space: pre-line;
513
+ padding: 0.5rem 0;
513
514
  position: absolute;
514
515
  height: fit-content;
515
516
  font-size: 28px;
516
517
  }
517
518
 
519
+ .nomercyplayer:has(.subtitle-text:empty) .subtitle-overlay .subtitle-area {
520
+ display: none;
521
+ }
522
+
518
523
  .nomercyplayer .subtitle-overlay .subtitle-area.aligned-start {
519
524
  text-align: left;
520
525
  }
@@ -539,11 +544,17 @@ class NMPlayer<T> extends Base<T> {
539
544
 
540
545
  .nomercyplayer .subtitle-overlay .subtitle-text {
541
546
  white-space: pre-line;
542
- display: inline;
547
+ padding: 0 0.5rem;
548
+ display: inline-flex;
549
+ line-height: 1.2;
543
550
  writing-mode: horizontal-tb;
544
551
  unicode-bidi: plaintext;
545
552
  }
546
553
 
554
+ .nomercyplayer .subtitle-overlay .subtitle-text:empty {
555
+ display: none;
556
+ }
557
+
547
558
  .nomercyplayer .subtitle-text,
548
559
  .nomercyplayer .subtitle-text[data-language="eng"] {
549
560
  font-family: 'ReithSans', sans-serif;
@@ -656,18 +667,13 @@ class NMPlayer<T> extends Base<T> {
656
667
 
657
668
  createSubtitleOverlay(): void {
658
669
 
659
- this.subtitleOverlay = this.createElement('div', `${this.playerId}-subtitle-overlay`, true)
670
+ this.subtitleOverlay = this.createElement('div', `${this.playerId}-subtitle-overlay`, true)
660
671
  .addClasses(['subtitle-overlay'])
661
672
  .appendTo(this.container);
662
673
 
663
- this.subtitleSafeZone = this.createElement('div', `${this.playerId}-subtitle-safezone`, true)
664
- .addClasses(['subtitle-safezone'])
665
- .appendTo(this.subtitleOverlay);
666
-
667
-
668
674
  this.subtitleArea = this.createElement('div', `${this.playerId}-subtitle-area`, true)
669
675
  .addClasses(['subtitle-area'])
670
- .appendTo(this.subtitleSafeZone);
676
+ .appendTo(this.subtitleOverlay);
671
677
 
672
678
  this.subtitleText = this.createElement('span', `${this.playerId}-subtitle-text`, true)
673
679
  .addClasses(['subtitle-text'])
@@ -675,19 +681,15 @@ class NMPlayer<T> extends Base<T> {
675
681
 
676
682
  this.on('time', this.checkSubtitles.bind(this));
677
683
 
678
-
679
- this.updateDisplayOverlay();
680
-
681
684
  this.storage.get<SubtitleStyle>('subtitle-style', defaultSubtitleStyles)
682
685
  .then((val) => {
683
- this.subtitleStyle = val;
684
- this.updateDisplayOverlay();
686
+ this.subtitleStyle = val;
685
687
  this.applySubtitleStyle();
686
688
  });
687
689
  }
688
690
 
689
691
 
690
- setSubtitleStyle(style: SubtitleStyle): void {
692
+ setSubtitleStyle(style: Partial<SubtitleStyle>): void {
691
693
  this.subtitleStyle = { ...this.subtitleStyle, ...style };
692
694
  this.applySubtitleStyle();
693
695
  }
@@ -700,6 +702,13 @@ class NMPlayer<T> extends Base<T> {
700
702
  private applySubtitleStyle(): void {
701
703
  this.storage.set('subtitle-style', this.subtitleStyle).then();
702
704
 
705
+ Object.entries(this.subtitleStyle).forEach(([key, value]) => {
706
+ this.emit('set-subtitle-style', {
707
+ property: key,
708
+ value: value,
709
+ });
710
+ });
711
+
703
712
  const { fontSize, fontFamily, textColor,
704
713
  textOpacity, backgroundColor, backgroundOpacity,
705
714
  edgeStyle, areaColor, windowOpacity
@@ -724,33 +733,26 @@ class NMPlayer<T> extends Base<T> {
724
733
  }
725
734
  }
726
735
 
727
- computeSubtitlePosition = (cue: Cue, videoElement: HTMLVideoElement, subtitleSafeZone: HTMLElement, subtitleArea: HTMLElement, subtitleText: HTMLElement) => {
728
- if (!videoElement || !subtitleSafeZone || !subtitleArea || !subtitleText) {
736
+ computeSubtitlePosition = (cue: Cue, videoElement: HTMLVideoElement, subtitleArea: HTMLElement, subtitleText: HTMLElement) => {
737
+ if (!videoElement || !subtitleArea || !subtitleText) {
729
738
  return;
730
739
  }
731
740
 
732
741
  const videoHeight = videoElement.clientHeight;
733
- const safeZoneHeight = subtitleSafeZone.clientHeight;
734
742
  const subtitleHeight = subtitleArea.clientHeight;
735
743
 
736
- let insetTop: number = videoHeight;
737
-
744
+ // Handle vertical positioning
738
745
  if (typeof cue.linePosition === "number") {
739
- if (cue.linePosition === 50) {
740
- // Calculate the exact offset for centering.
741
- insetTop = videoHeight / 2 - subtitleHeight / 2;
742
- } else {
743
- insetTop = (videoHeight * (cue.linePosition / 100)) - (subtitleHeight * (cue.linePosition / 100));
744
- }
745
- }
746
-
747
- const safeZoneTop = subtitleSafeZone.getBoundingClientRect().top - videoElement.getBoundingClientRect().top;
748
- const safeZoneBottom = safeZoneTop + safeZoneHeight;
749
- const buffer = 10;
750
-
751
- insetTop = Math.max(safeZoneTop + buffer, Math.min(insetTop, safeZoneBottom - subtitleHeight - buffer));
746
+ const verticalPos = cue.linePosition === 50
747
+ ? `${50 - (subtitleHeight / videoHeight * 50)}%` // Center
748
+ : `${cue.linePosition}%`; // Specified position
752
749
 
753
- subtitleArea.style.inset = `${insetTop}px 0px 0px`;
750
+ subtitleArea.style.bottom = '';
751
+ subtitleArea.style.top = verticalPos;
752
+ } else {
753
+ subtitleArea.style.top = '';
754
+ subtitleArea.style.bottom = '3%';
755
+ }
754
756
 
755
757
  // Handle alignment
756
758
  subtitleArea.classList.remove("aligned-start", "aligned-center", "aligned-end");
@@ -762,15 +764,15 @@ class NMPlayer<T> extends Base<T> {
762
764
  subtitleArea.classList.add("aligned-end");
763
765
  }
764
766
 
765
- // Handle size (width percentage)
767
+ // Handle width
766
768
  if (cue.size >= 0 && cue.size <= 100) {
767
- subtitleArea.classList.add("sized");
768
- subtitleArea.style.width = `${cue.size}%`;
769
- subtitleArea.style.left = `${(100 - cue.size) / 2}%`;
769
+ subtitleArea.style.width = `calc(${cue.size}% - 6%)`;
770
+ subtitleArea.style.left = `calc(${(100 - cue.size) / 2}% + 3%)`;
771
+ subtitleArea.style.right = `calc(${(100 - cue.size) / 2}% + 3%)`;
770
772
  } else {
771
- subtitleArea.classList.remove("sized");
772
- subtitleArea.style.width = `100%`;
773
- subtitleArea.style.left = `0%`;
773
+ subtitleArea.style.width = '100%';
774
+ subtitleArea.style.left = '3%';
775
+ subtitleArea.style.right = '3%';
774
776
  }
775
777
  };
776
778
 
@@ -811,7 +813,7 @@ class NMPlayer<T> extends Base<T> {
811
813
  this.subtitleText.appendChild(fragment);
812
814
  this.subtitleText.setAttribute('data-language', this.getCaptionLanguage());
813
815
  requestAnimationFrame(() => {
814
- this.computeSubtitlePosition(subtitleCue, this.videoElement, this.subtitleSafeZone, this.subtitleArea, this.subtitleText);
816
+ this.computeSubtitlePosition(subtitleCue, this.videoElement, this.subtitleArea, this.subtitleText);
815
817
  });
816
818
  }
817
819
 
@@ -1092,7 +1094,7 @@ class NMPlayer<T> extends Base<T> {
1092
1094
  }
1093
1095
 
1094
1096
  videoPlayer_loadedmetadataEvent(e: Event): void {
1095
- const _e = e as Event & {target: HTMLVideoElement};
1097
+ const _e = e as Event & { target: HTMLVideoElement };
1096
1098
  this.emit('loadedmetadata', this.videoElement);
1097
1099
  this.emit('duration', this.videoPlayer_getTimeData(_e));
1098
1100
  }
@@ -1102,14 +1104,14 @@ class NMPlayer<T> extends Base<T> {
1102
1104
  }
1103
1105
 
1104
1106
  videoPlayer_timeupdateEvent(e: Event): void {
1105
- const _e = e as Event & {target: HTMLVideoElement};
1107
+ const _e = e as Event & { target: HTMLVideoElement };
1106
1108
  if (Number.isNaN(_e.target.duration) || Number.isNaN(_e.target.currentTime)) return;
1107
1109
 
1108
1110
  this.emit('time', this.videoPlayer_getTimeData(_e));
1109
1111
  }
1110
1112
 
1111
1113
  videoPlayer_durationchangeEvent(e: Event): void {
1112
- const _e = e as Event & {target: HTMLVideoElement};
1114
+ const _e = e as Event & { target: HTMLVideoElement };
1113
1115
  this.emit('duration', this.videoPlayer_getTimeData(_e));
1114
1116
 
1115
1117
  this.emit('ready');
@@ -1134,7 +1136,7 @@ class NMPlayer<T> extends Base<T> {
1134
1136
  this.volume = Math.round(this.videoElement.volume * 100);
1135
1137
  }
1136
1138
 
1137
- videoPlayer_getTimeData(_e: {target: HTMLVideoElement}): TimeData {
1139
+ videoPlayer_getTimeData(_e: { target: HTMLVideoElement }): TimeData {
1138
1140
  return {
1139
1141
  currentTime: _e.target.currentTime,
1140
1142
  duration: _e.target.duration,
@@ -1438,7 +1440,7 @@ class NMPlayer<T> extends Base<T> {
1438
1440
 
1439
1441
  const playlistItem = progressItem
1440
1442
  .filter(i => i.progress)
1441
- .sort((a,b) => new Date(b.progress!.date).getTime() - new Date(a.progress!.date).getTime())
1443
+ .sort((a, b) => new Date(b.progress!.date).getTime() - new Date(a.progress!.date).getTime())
1442
1444
  .at(0);
1443
1445
 
1444
1446
  if (!playlistItem?.progress) {
@@ -1540,7 +1542,7 @@ class NMPlayer<T> extends Base<T> {
1540
1542
 
1541
1543
  }
1542
1544
 
1543
- getParameterByName<T extends number|string>(name: string, url = window.location.href): T|null {
1545
+ getParameterByName<T extends number | string>(name: string, url = window.location.href): T | null {
1544
1546
  name = name.replace(/[[\]]/gu, '\\$&');
1545
1547
 
1546
1548
  const regex = new RegExp(`[?&]${name}(=([^&#]*)|&|#|$)`, 'u');
@@ -1803,7 +1805,7 @@ class NMPlayer<T> extends Base<T> {
1803
1805
  this.translations[key] = value;
1804
1806
  }
1805
1807
 
1806
- addTranslations(translations: {key: string, value: string}[]): void {
1808
+ addTranslations(translations: { key: string, value: string }[]): void {
1807
1809
  if (!this.translations) {
1808
1810
  this.translations = {};
1809
1811
  }
package/src/types.ts CHANGED
@@ -368,7 +368,7 @@ export interface NMPlayer<Conf extends Partial<PlayerConfig> = {}> {
368
368
  volumeDown(): void;
369
369
  volumeUp(): void;
370
370
 
371
- setSubtitleStyle(style: SubtitleStyle): void;
371
+ setSubtitleStyle(style: Partial<SubtitleStyle>): void;
372
372
  getSubtitleStyle(): SubtitleStyle;
373
373
 
374
374
  emit(event: 'all', data?: any): void;