unified-video-framework 1.4.369 → 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.
- package/package.json +1 -1
- package/packages/web/dist/WebPlayer.d.ts.map +1 -1
- package/packages/web/dist/WebPlayer.js +2 -1
- package/packages/web/dist/WebPlayer.js.map +1 -1
- package/packages/web/dist/chapters/ChapterManager.d.ts.map +1 -1
- package/packages/web/dist/chapters/ChapterManager.js.map +1 -1
- package/packages/web/dist/chapters/CreditsButtonController.d.ts +2 -0
- package/packages/web/dist/chapters/CreditsButtonController.d.ts.map +1 -1
- package/packages/web/dist/chapters/CreditsButtonController.js +58 -20
- package/packages/web/dist/chapters/CreditsButtonController.js.map +1 -1
- package/packages/web/dist/chapters/types/ChapterTypes.d.ts +8 -0
- package/packages/web/dist/chapters/types/ChapterTypes.d.ts.map +1 -1
- package/packages/web/dist/chapters/types/ChapterTypes.js.map +1 -1
- package/packages/web/src/WebPlayer.ts +715 -714
- package/packages/web/src/chapters/ChapterManager.ts +2 -0
- package/packages/web/src/chapters/CreditsButtonController.ts +72 -22
- package/packages/web/src/chapters/types/ChapterTypes.ts +21 -0
|
@@ -384,6 +384,7 @@ export class ChapterManager {
|
|
|
384
384
|
|
|
385
385
|
// Check if segment changed
|
|
386
386
|
if (newSegment !== this.currentSegment) {
|
|
387
|
+
|
|
387
388
|
// Handle segment exit
|
|
388
389
|
if (this.currentSegment) {
|
|
389
390
|
this.emit('segmentExited', {
|
|
@@ -412,6 +413,7 @@ export class ChapterManager {
|
|
|
412
413
|
|
|
413
414
|
// Handle segment entry
|
|
414
415
|
if (this.currentSegment) {
|
|
416
|
+
|
|
415
417
|
this.emit('segmentEntered', {
|
|
416
418
|
segment: this.currentSegment,
|
|
417
419
|
currentTime,
|
|
@@ -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
|
-
|
|
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:
|
|
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 =
|
|
219
|
-
|
|
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 =
|
|
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
|
/**
|