unified-video-framework 1.4.370 → 1.4.371

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.
@@ -361,16 +361,12 @@ export class ChapterManager {
361
361
  this.currentSegment.nextEpisodeUrl &&
362
362
  this.creditsButtonController.isUserWatchingCredits()) {
363
363
 
364
- console.log(`[ChapterManager] In credits segment, checking endTime. currentTime: ${currentTime}, endTime: ${this.currentSegment.endTime}`);
365
-
366
364
  // Check if we've reached or passed the credits endTime
367
365
  if (currentTime >= this.currentSegment.endTime) {
368
366
  // Capture URL before any state changes
369
367
  const redirectUrl = this.currentSegment.nextEpisodeUrl;
370
368
  const creditsSegment = this.currentSegment;
371
369
 
372
- console.log('[ChapterManager] Credits endTime reached! Redirecting to:', redirectUrl);
373
-
374
370
  this.emit('creditsFullyWatched', {
375
371
  segment: creditsSegment,
376
372
  nextEpisodeUrl: redirectUrl,
@@ -388,7 +384,6 @@ export class ChapterManager {
388
384
 
389
385
  // Check if segment changed
390
386
  if (newSegment !== this.currentSegment) {
391
- console.log(`[ChapterManager] Segment changed from ${this.currentSegment?.type || 'none'} to ${newSegment?.type || 'none'} at ${currentTime}s`);
392
387
 
393
388
  // Handle segment exit
394
389
  if (this.currentSegment) {
@@ -418,7 +413,6 @@ export class ChapterManager {
418
413
 
419
414
  // Handle segment entry
420
415
  if (this.currentSegment) {
421
- console.log(`[ChapterManager] Entered segment: ${this.currentSegment.type} (${this.currentSegment.title || 'no title'}) at ${currentTime}s`);
422
416
 
423
417
  this.emit('segmentEntered', {
424
418
  segment: this.currentSegment,
@@ -428,8 +422,6 @@ export class ChapterManager {
428
422
 
429
423
  // Check if this is a credits segment with next episode URL
430
424
  if (this.currentSegment.type === 'credits' && this.currentSegment.nextEpisodeUrl) {
431
- console.log('[ChapterManager] Credits segment with nextEpisodeUrl detected! Showing buttons...');
432
- console.log('[ChapterManager] nextEpisodeUrl:', this.currentSegment.nextEpisodeUrl);
433
425
  // Show credits buttons instead of skip button
434
426
  this.creditsButtonController.showCreditsButtons(this.currentSegment, currentTime);
435
427
  } else if (this.shouldShowSkipButton(this.currentSegment)) {
@@ -42,7 +42,6 @@ export class CreditsButtonController {
42
42
  public showCreditsButtons(segment: VideoSegment, currentTime: number): void {
43
43
  // Verify segment has nextEpisodeUrl
44
44
  if (!segment.nextEpisodeUrl) {
45
- console.warn('[CreditsButtonController] Segment does not have nextEpisodeUrl');
46
45
  return;
47
46
  }
48
47
 
@@ -129,24 +128,31 @@ export class CreditsButtonController {
129
128
  * Create the credits buttons DOM elements
130
129
  */
131
130
  private createCreditsButtons(): void {
131
+ const segment = this.currentSegment;
132
+ const style = segment?.creditsButtonStyle;
133
+ const layout = style?.layout || 'vertical';
134
+ const position = style?.position || 'bottom-right';
135
+
132
136
  // Create container
133
137
  this.buttonsContainer = document.createElement('div');
134
138
  this.buttonsContainer.className = 'uvf-credits-buttons';
135
139
  this.buttonsContainer.setAttribute('role', 'group');
136
140
  this.buttonsContainer.setAttribute('aria-label', 'Credits navigation');
137
141
 
138
- // Apply container styles
139
- Object.assign(this.buttonsContainer.style, {
142
+ // Apply container styles based on layout and position
143
+ const containerStyles: Partial<CSSStyleDeclaration> = {
140
144
  position: 'absolute',
141
- bottom: '100px',
142
- right: '30px',
143
145
  display: 'flex',
144
- flexDirection: 'column',
146
+ flexDirection: layout === 'horizontal' ? 'row' : 'column',
145
147
  gap: '10px',
146
148
  zIndex: '1000',
147
149
  opacity: '0',
148
150
  transition: 'opacity 0.3s ease-in-out'
149
- });
151
+ };
152
+
153
+ // Position the container
154
+ this.applyContainerPosition(containerStyles, position);
155
+ Object.assign(this.buttonsContainer.style, containerStyles);
150
156
 
151
157
  // Create "Watch Credits" button
152
158
  this.watchCreditsButton = document.createElement('button');
@@ -166,9 +172,9 @@ export class CreditsButtonController {
166
172
  // Add click handler for Next Episode
167
173
  this.nextEpisodeButton.addEventListener('click', () => this.handleNextEpisodeClick());
168
174
 
169
- // Apply button styles
170
- this.applyButtonStyles(this.watchCreditsButton, 'watch-credits');
171
- this.applyButtonStyles(this.nextEpisodeButton, 'next-episode');
175
+ // Apply button styles with custom colors
176
+ this.applyButtonStyles(this.watchCreditsButton, 'watch-credits', style);
177
+ this.applyButtonStyles(this.nextEpisodeButton, 'next-episode', style);
172
178
 
173
179
  // Append buttons to container
174
180
  this.buttonsContainer.appendChild(this.watchCreditsButton);
@@ -178,10 +184,36 @@ export class CreditsButtonController {
178
184
  this.playerContainer.appendChild(this.buttonsContainer);
179
185
  }
180
186
 
187
+ /**
188
+ * Apply position styles to container
189
+ */
190
+ private applyContainerPosition(styles: Partial<CSSStyleDeclaration>, position: string): void {
191
+ switch (position) {
192
+ case 'bottom-right':
193
+ Object.assign(styles, { bottom: '100px', right: '30px' });
194
+ break;
195
+ case 'bottom-left':
196
+ Object.assign(styles, { bottom: '100px', left: '30px' });
197
+ break;
198
+ case 'bottom-center':
199
+ Object.assign(styles, { bottom: '100px', left: '50%', transform: 'translateX(-50%)' });
200
+ break;
201
+ case 'top-right':
202
+ Object.assign(styles, { top: '30px', right: '30px' });
203
+ break;
204
+ case 'top-left':
205
+ Object.assign(styles, { top: '30px', left: '30px' });
206
+ break;
207
+ case 'top-center':
208
+ Object.assign(styles, { top: '30px', left: '50%', transform: 'translateX(-50%)' });
209
+ break;
210
+ }
211
+ }
212
+
181
213
  /**
182
214
  * Apply styles to buttons
183
215
  */
184
- private applyButtonStyles(button: HTMLElement, type: 'watch-credits' | 'next-episode'): void {
216
+ private applyButtonStyles(button: HTMLElement, type: 'watch-credits' | 'next-episode', customStyle?: any): void {
185
217
  const baseStyles: Partial<CSSStyleDeclaration> = {
186
218
  padding: '12px 24px',
187
219
  fontSize: '14px',
@@ -198,14 +230,14 @@ export class CreditsButtonController {
198
230
 
199
231
  if (type === 'watch-credits') {
200
232
  Object.assign(baseStyles, {
201
- backgroundColor: 'rgba(255, 255, 255, 0.15)',
202
- color: '#ffffff',
203
- border: '2px solid rgba(255, 255, 255, 0.3)'
233
+ backgroundColor: customStyle?.watchCreditsBgColor || 'rgba(255, 255, 255, 0.15)',
234
+ color: customStyle?.watchCreditsColor || '#ffffff',
235
+ border: `2px solid ${customStyle?.watchCreditsBgColor ? 'transparent' : 'rgba(255, 255, 255, 0.3)'}`
204
236
  });
205
237
  } else {
206
238
  Object.assign(baseStyles, {
207
- backgroundColor: '#e50914',
208
- color: '#ffffff',
239
+ backgroundColor: customStyle?.nextEpisodeBgColor || '#e50914',
240
+ color: customStyle?.nextEpisodeColor || '#ffffff',
209
241
  boxShadow: '0 2px 8px rgba(229, 9, 20, 0.4)'
210
242
  });
211
243
  }
@@ -215,25 +247,43 @@ export class CreditsButtonController {
215
247
  // Add hover effect
216
248
  button.addEventListener('mouseenter', () => {
217
249
  if (type === 'watch-credits') {
218
- button.style.backgroundColor = 'rgba(255, 255, 255, 0.25)';
219
- button.style.borderColor = 'rgba(255, 255, 255, 0.5)';
250
+ button.style.backgroundColor = customStyle?.watchCreditsBgColor
251
+ ? this.adjustBrightness(customStyle.watchCreditsBgColor, 20)
252
+ : 'rgba(255, 255, 255, 0.25)';
220
253
  } else {
221
- button.style.backgroundColor = '#f40612';
254
+ button.style.backgroundColor = customStyle?.nextEpisodeBgColor
255
+ ? this.adjustBrightness(customStyle.nextEpisodeBgColor, 20)
256
+ : '#f40612';
222
257
  button.style.transform = 'scale(1.03)';
223
258
  }
224
259
  });
225
260
 
226
261
  button.addEventListener('mouseleave', () => {
227
262
  if (type === 'watch-credits') {
228
- button.style.backgroundColor = 'rgba(255, 255, 255, 0.15)';
229
- button.style.borderColor = 'rgba(255, 255, 255, 0.3)';
263
+ button.style.backgroundColor = customStyle?.watchCreditsBgColor || 'rgba(255, 255, 255, 0.15)';
230
264
  } else {
231
- button.style.backgroundColor = '#e50914';
265
+ button.style.backgroundColor = customStyle?.nextEpisodeBgColor || '#e50914';
232
266
  button.style.transform = 'scale(1)';
233
267
  }
234
268
  });
235
269
  }
236
270
 
271
+ /**
272
+ * Adjust color brightness for hover effects
273
+ */
274
+ private adjustBrightness(color: string, percent: number): string {
275
+ // Simple brightness adjustment - works for hex and rgb
276
+ const num = parseInt(color.replace('#', ''), 16);
277
+ const amt = Math.round(2.55 * percent);
278
+ const R = (num >> 16) + amt;
279
+ const G = (num >> 8 & 0x00FF) + amt;
280
+ const B = (num & 0x0000FF) + amt;
281
+ return '#' + (0x1000000 + (R < 255 ? R < 1 ? 0 : R : 255) * 0x10000 +
282
+ (G < 255 ? G < 1 ? 0 : G : 255) * 0x100 +
283
+ (B < 255 ? B < 1 ? 0 : B : 255))
284
+ .toString(16).slice(1);
285
+ }
286
+
237
287
  /**
238
288
  * Update button labels based on segment configuration
239
289
  */
@@ -48,6 +48,27 @@ export interface VideoSegment {
48
48
 
49
49
  /** Custom label for "Next Episode/Play Next" button */
50
50
  nextEpisodeLabel?: string;
51
+
52
+ /** Styling options for credits buttons */
53
+ creditsButtonStyle?: {
54
+ /** Layout direction: 'vertical' (default) or 'horizontal' */
55
+ layout?: 'vertical' | 'horizontal';
56
+
57
+ /** Watch Credits button color */
58
+ watchCreditsColor?: string;
59
+
60
+ /** Watch Credits button background color */
61
+ watchCreditsBgColor?: string;
62
+
63
+ /** Next Episode button color */
64
+ nextEpisodeColor?: string;
65
+
66
+ /** Next Episode button background color */
67
+ nextEpisodeBgColor?: string;
68
+
69
+ /** Button position */
70
+ position?: 'bottom-right' | 'bottom-left' | 'top-right' | 'top-left' | 'bottom-center' | 'top-center';
71
+ };
51
72
  }
52
73
 
53
74
  /**