chrome-devtools-frontend 1.0.1681498 → 1.0.1682249

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.
Files changed (141) hide show
  1. package/eslint.config.mjs +8 -3
  2. package/front_end/core/sdk/ConsoleModel.ts +1 -1
  3. package/front_end/core/sdk/PreloadingModel.ts +44 -22
  4. package/front_end/core/sdk/RemoteObject.ts +4 -1
  5. package/front_end/core/sdk/RuntimeModel.ts +5 -5
  6. package/front_end/core/sdk/sdk.ts +2 -0
  7. package/front_end/entrypoints/formatter_worker/FormatterWorker.ts +1 -1
  8. package/front_end/entrypoints/inspector_main/InspectorMain.ts +3 -1
  9. package/front_end/entrypoints/inspector_main/inspector_main-meta.ts +1 -5
  10. package/front_end/entrypoints/main/MainImpl.ts +9 -10
  11. package/front_end/entrypoints/shell/shell.ts +0 -2
  12. package/front_end/entrypoints/trace_app/trace_app.ts +0 -2
  13. package/front_end/generated/InspectorBackendCommands.ts +2 -0
  14. package/front_end/generated/protocol-mapping.d.ts +16 -0
  15. package/front_end/generated/protocol-proxy-api.d.ts +12 -0
  16. package/front_end/generated/protocol.ts +12 -0
  17. package/front_end/models/ai_assistance/ExtensionScope.ts +11 -12
  18. package/front_end/models/ai_assistance/agents/AiAgent.ts +1 -1
  19. package/front_end/models/ai_assistance/agents/ContextSelectionAgent.ts +2 -1
  20. package/front_end/models/ai_assistance/agents/PerformanceAgent.snapshot.txt +1 -1
  21. package/front_end/models/ai_assistance/agents/PerformanceAgent.ts +2 -1
  22. package/front_end/models/ai_assistance/contexts/PerformanceTraceContext.ts +2 -1
  23. package/front_end/models/ai_assistance/data_formatters/PerformanceInsightFormatter.snapshot.txt +8 -8
  24. package/front_end/models/ai_assistance/data_formatters/PerformanceTraceFormatter.snapshot.txt +8 -8
  25. package/front_end/models/bindings/DebuggerLanguagePlugins.ts +1 -0
  26. package/front_end/models/formatter/ScriptFormatter.ts +1 -0
  27. package/front_end/models/javascript_metadata/NativeFunctions.js +5 -1
  28. package/front_end/models/live-metrics/web-vitals-injected/spec/spec.ts +4 -4
  29. package/front_end/models/logs/NetworkLog.ts +8 -1
  30. package/front_end/models/persistence/AutomaticFileSystemWorkspaceBinding.ts +4 -2
  31. package/front_end/models/stack_trace/StackTraceImpl.ts +1 -0
  32. package/front_end/models/trace/Name.ts +5 -5
  33. package/front_end/models/trace/Styles.ts +115 -115
  34. package/front_end/models/trace/extras/TraceTree.ts +2 -1
  35. package/front_end/models/trace/helpers/Network.ts +4 -1
  36. package/front_end/models/trace/insights/CLSCulprits.ts +4 -2
  37. package/front_end/models/trace/insights/CharacterSet.ts +3 -3
  38. package/front_end/models/trace/insights/DOMSize.ts +1 -1
  39. package/front_end/models/trace/insights/DuplicatedJavaScript.ts +6 -2
  40. package/front_end/models/trace/insights/FontDisplay.ts +9 -3
  41. package/front_end/models/trace/insights/ForcedReflow.ts +4 -4
  42. package/front_end/models/trace/insights/INPBreakdown.ts +3 -4
  43. package/front_end/models/trace/insights/ImageDelivery.ts +2 -2
  44. package/front_end/models/trace/insights/LCPBreakdown.ts +1 -1
  45. package/front_end/models/trace/insights/LCPDiscovery.ts +5 -5
  46. package/front_end/models/trace/insights/LegacyJavaScript.ts +7 -3
  47. package/front_end/models/trace/insights/ModernHTTP.ts +3 -3
  48. package/front_end/models/trace/insights/NetworkDependencyTree.ts +13 -9
  49. package/front_end/models/trace/insights/RenderBlocking.ts +1 -1
  50. package/front_end/models/trace/insights/SlowCSSSelector.ts +29 -25
  51. package/front_end/models/trace/insights/ThirdParties.ts +13 -5
  52. package/front_end/models/trace/insights/Viewport.ts +4 -2
  53. package/front_end/models/workspace/IgnoreListManager.ts +53 -17
  54. package/front_end/panels/accessibility/ARIAAttributesView.ts +11 -2
  55. package/front_end/panels/ai_assistance/components/ChatMessage.ts +67 -53
  56. package/front_end/panels/ai_assistance/components/ChatView.ts +2 -2
  57. package/front_end/panels/ai_assistance/components/StylingAgentMarkdownRenderer.ts +2 -2
  58. package/front_end/panels/ai_assistance/components/WalkthroughView.ts +5 -5
  59. package/front_end/panels/animation/AnimationTimeline.ts +2 -0
  60. package/front_end/panels/application/preloading/PreloadingView.ts +9 -3
  61. package/front_end/panels/application/preloading/components/components.ts +2 -0
  62. package/front_end/panels/browser_debugger/ObjectEventListenersSidebarPane.ts +10 -11
  63. package/front_end/panels/changes/CombinedDiffView.ts +1 -1
  64. package/front_end/panels/common/ExtensionServer.ts +9 -10
  65. package/front_end/panels/css_overview/CSSOverviewCompletedView.ts +9 -4
  66. package/front_end/panels/elements/ElementStatePaneWidget.ts +3 -0
  67. package/front_end/panels/elements/ElementsTreeElement.ts +7 -1
  68. package/front_end/panels/elements/EventListenersWidget.ts +10 -11
  69. package/front_end/panels/issues/IssueView.ts +5 -6
  70. package/front_end/panels/linear_memory_inspector/components/LinearMemoryViewer.ts +1 -1
  71. package/front_end/panels/media/PlayerPropertiesView.ts +309 -416
  72. package/front_end/panels/media/playerPropertiesView.css +1 -1
  73. package/front_end/panels/network/NetworkPanel.ts +2 -1
  74. package/front_end/panels/network/components/ResponseHeaderSection.ts +1 -2
  75. package/front_end/panels/network/network-meta.ts +6 -0
  76. package/front_end/panels/performance_monitor/PerformanceMonitor.ts +2 -1
  77. package/front_end/panels/recorder/RecordingView.ts +89 -73
  78. package/front_end/panels/recorder/ReplaySection.ts +59 -40
  79. package/front_end/panels/recorder/injected/injected.ts +4 -0
  80. package/front_end/panels/security/SecurityPanel.ts +5 -6
  81. package/front_end/panels/security/SecurityPanelSidebar.ts +244 -204
  82. package/front_end/panels/security/security.ts +0 -4
  83. package/front_end/panels/settings/EditFileSystemView.ts +8 -7
  84. package/front_end/panels/settings/FrameworkIgnoreListSettingsTab.ts +20 -14
  85. package/front_end/panels/snippets/ScriptSnippetFileSystem.ts +10 -11
  86. package/front_end/panels/sources/WatchExpressionsSidebarPane.ts +3 -3
  87. package/front_end/panels/timeline/TimelineFlameChartDataProvider.ts +5 -5
  88. package/front_end/panels/timeline/components/CWVMetrics.ts +1 -2
  89. package/front_end/panels/timeline/components/IgnoreListSetting.ts +5 -5
  90. package/front_end/panels/timeline/components/LayoutShiftDetails.ts +2 -3
  91. package/front_end/panels/timeline/components/LiveMetricsView.ts +2 -2
  92. package/front_end/panels/timeline/components/Sidebar.ts +3 -3
  93. package/front_end/panels/timeline/components/SidebarSingleInsightSet.ts +1 -2
  94. package/front_end/panels/timeline/components/insights/BaseInsightComponent.ts +3 -1
  95. package/front_end/panels/timeline/components/insights/CLSCulprits.ts +1 -2
  96. package/front_end/panels/timeline/components/insights/Cache.ts +1 -2
  97. package/front_end/panels/timeline/components/insights/CharacterSet.ts +1 -2
  98. package/front_end/panels/timeline/components/insights/DOMSize.ts +1 -2
  99. package/front_end/panels/timeline/components/insights/DocumentLatency.ts +2 -2
  100. package/front_end/panels/timeline/components/insights/DuplicatedJavaScript.ts +2 -2
  101. package/front_end/panels/timeline/components/insights/FontDisplay.ts +1 -2
  102. package/front_end/panels/timeline/components/insights/ForcedReflow.ts +1 -2
  103. package/front_end/panels/timeline/components/insights/INPBreakdown.ts +1 -2
  104. package/front_end/panels/timeline/components/insights/ImageDelivery.ts +1 -2
  105. package/front_end/panels/timeline/components/insights/LCPBreakdown.ts +13 -13
  106. package/front_end/panels/timeline/components/insights/LCPDiscovery.ts +1 -2
  107. package/front_end/panels/timeline/components/insights/LegacyJavaScript.ts +4 -4
  108. package/front_end/panels/timeline/components/insights/ModernHTTP.ts +1 -2
  109. package/front_end/panels/timeline/components/insights/NetworkDependencyTree.ts +10 -8
  110. package/front_end/panels/timeline/components/insights/RenderBlocking.ts +2 -2
  111. package/front_end/panels/timeline/components/insights/SidebarInsight.ts +3 -1
  112. package/front_end/panels/timeline/components/insights/SlowCSSSelector.ts +2 -2
  113. package/front_end/panels/timeline/components/insights/ThirdParties.ts +1 -2
  114. package/front_end/panels/timeline/components/insights/Viewport.ts +1 -2
  115. package/front_end/panels/timeline/overlays/OverlaysImpl.ts +1 -2
  116. package/front_end/panels/timeline/timeline.ts +0 -2
  117. package/front_end/panels/web_audio/WebAudioView.ts +7 -7
  118. package/front_end/panels/webauthn/WebauthnPane.ts +9 -9
  119. package/front_end/third_party/chromium/README.chromium +1 -1
  120. package/front_end/ui/components/diff_view/DiffView.ts +2 -1
  121. package/front_end/ui/components/report_view/ReportView.docs.ts +2 -2
  122. package/front_end/ui/components/text_editor/javascript.ts +12 -13
  123. package/front_end/ui/legacy/GlassPane.ts +38 -14
  124. package/front_end/ui/legacy/Treeoutline.ts +14 -3
  125. package/front_end/ui/legacy/components/object_ui/CustomPreviewComponent.ts +1 -1
  126. package/front_end/ui/legacy/components/object_ui/JavaScriptREPL.ts +1 -1
  127. package/front_end/ui/legacy/components/object_ui/ObjectPopoverHelper.ts +1 -1
  128. package/front_end/ui/legacy/components/object_ui/ObjectPropertiesSection.ts +21 -30
  129. package/front_end/ui/legacy/components/object_ui/RemoteObjectPreviewFormatter.ts +3 -8
  130. package/front_end/ui/legacy/components/utils/ImagePreview.ts +15 -16
  131. package/front_end/ui/legacy/components/utils/JSPresentationUtils.ts +4 -4
  132. package/front_end/ui/legacy/components/utils/Linkifier.ts +8 -10
  133. package/front_end/ui/settings/InspectorMainSettings.ts +12 -0
  134. package/front_end/ui/settings/settings.ts +2 -0
  135. package/front_end/ui/visual_logging/KnownContextValues.ts +21 -0
  136. package/mcp/mcp.ts +0 -6
  137. package/package.json +1 -1
  138. package/front_end/models/logs/logs-meta.ts +0 -24
  139. package/front_end/models/workspace/workspace-meta.ts +0 -40
  140. package/front_end/panels/security/OriginTreeElement.ts +0 -60
  141. package/front_end/panels/security/SecurityPanelSidebarTreeElement.ts +0 -30
@@ -1,38 +1,36 @@
1
1
  // Copyright 2019 The Chromium Authors
2
2
  // Use of this source code is governed by a BSD-style license that can be
3
3
  // found in the LICENSE file.
4
- /* eslint-disable @devtools/no-imperative-dom-api */
5
4
 
6
5
  import * as i18n from '../../core/i18n/i18n.js';
7
6
  import * as Platform from '../../core/platform/platform.js';
8
7
  import type * as Protocol from '../../generated/protocol.js';
9
8
  import * as SourceFrame from '../../ui/legacy/components/source_frame/source_frame.js';
10
9
  import * as UI from '../../ui/legacy/legacy.js';
10
+ import {Directives, html, type LitTemplate, nothing, render} from '../../ui/lit/lit.js';
11
11
  import * as VisualLogging from '../../ui/visual_logging/visual_logging.js';
12
12
 
13
13
  import playerPropertiesViewStyles from './playerPropertiesView.css.js';
14
14
 
15
15
  const UIStrings = {
16
- /**
17
- * @description The type of media, for example - video, audio, or text. Capitalized.
18
- */
19
- video: 'Video',
20
- /**
21
- * @description The type of media, for example - video, audio, or text. Capitalized.
22
- */
23
- audio: 'Audio',
24
16
  /**
25
17
  * @description A video or audio stream - but capitalized.
26
18
  */
27
19
  track: 'Track',
28
20
  /**
29
- * @description A device that converts media files into playable streams of audio or video.
21
+ * @description Title of the video decoder tab in the media player properties view.
30
22
  */
31
- decoder: 'Decoder',
23
+ videoDecoderProperties: 'Video Decoder Properties',
32
24
  /**
33
- * @description Title of the 'Properties' tool in the sidebar of the Elements tool.
25
+ * @description Title of the audio decoder tab in the media player properties view.
34
26
  */
35
- properties: 'Properties',
27
+ audioDecoderProperties: 'Audio Decoder Properties',
28
+ /**
29
+ * @description Menu label for media tracks, it is followed by a number, like 'Track #1'.
30
+ * @example {Track} PH1
31
+ * @example {1} PH2
32
+ */
33
+ trackNumber: '{PH1} #{PH2}',
36
34
  /**
37
35
  * @description Menu label for text tracks, it is followed by a number, like 'Text track #1'.
38
36
  */
@@ -139,7 +137,6 @@ const UIStrings = {
139
137
 
140
138
  const str_ = i18n.i18n.registerUIStrings('panels/media/PlayerPropertiesView.ts', UIStrings);
141
139
  const i18nString = i18n.i18n.getLocalizedString.bind(undefined, str_);
142
- const i18nLazyString = i18n.i18n.getLazilyComputedLocalizedString.bind(undefined, str_);
143
140
 
144
141
  type TabData = Record<string, string|object>;
145
142
 
@@ -150,7 +147,8 @@ export const enum PlayerPropertyKeys {
150
147
  BITRATE = 'kBitrate',
151
148
  MAX_DURATION = 'kMaxDuration',
152
149
  START_TIME = 'kStartTime',
153
- IS_CDM_ATTACHED = 'kIsCdmAttached',
150
+ // Not observed
151
+ // IS_CDM_ATTACHED = 'kIsCdmAttached',
154
152
  IS_STREAMING = 'kIsStreaming',
155
153
  FRAME_URL = 'kFrameUrl',
156
154
  FRAME_TITLE = 'kFrameTitle',
@@ -174,479 +172,374 @@ export const enum PlayerPropertyKeys {
174
172
  HLS_BUFFERED_RANGES = 'kHlsBufferedRanges',
175
173
  }
176
174
 
177
- export class PropertyRenderer extends UI.Widget.VBox {
178
- private readonly contents: HTMLElement;
179
- private value: string|null;
180
- private pseudoColorProtectionElement: HTMLDivElement|null;
181
-
182
- constructor(title: Platform.UIString.LocalizedString) {
183
- super();
184
- this.contentElement.classList.add('media-property-renderer');
185
- const titleElement = this.contentElement.createChild('span', 'media-property-renderer-title');
186
- this.contents = this.contentElement.createChild('div', 'media-property-renderer-contents');
187
- UI.UIUtils.createTextChild(titleElement, title);
188
- this.value = null;
189
- this.pseudoColorProtectionElement = null;
190
- this.contentElement.classList.add('media-property-renderer-hidden');
191
- }
192
-
193
- updateData(propvalue: string): void {
194
- // convert all empty possibilities into nulls for easier handling.
195
- if (propvalue === '' || propvalue === null) {
196
- this.changeContents(null);
197
- } else if (this.value === propvalue) {
198
- return; // Don't rebuild element!
199
- } else {
200
- this.value = propvalue;
201
- this.updateDataInternal(propvalue);
202
- }
175
+ class Property {
176
+ protected dataInternal: string|null = null;
177
+ constructor(readonly type: PlayerPropertyKeys) {
203
178
  }
204
179
 
205
- updateDataInternal(propvalue: string): void {
180
+ protected parse<T>(val: string): T {
206
181
  try {
207
- const parsed = JSON.parse(propvalue) as string;
208
- this.changeContents(parsed);
182
+ return JSON.parse(val) as T;
209
183
  } catch {
210
- // Some properties are just raw strings.
211
- this.changeContents(propvalue);
184
+ return val as T;
212
185
  }
213
186
  }
214
187
 
215
- protected unsetNestedContents(): void {
216
- this.contentElement.classList.add('media-property-renderer-hidden');
217
- if (this.pseudoColorProtectionElement === null) {
218
- this.pseudoColorProtectionElement = document.createElement('div');
219
- this.pseudoColorProtectionElement.classList.add('media-property-renderer');
220
- this.pseudoColorProtectionElement.classList.add('media-property-renderer-hidden');
221
- (this.contentElement.parentNode as HTMLElement)
222
- .insertBefore(this.pseudoColorProtectionElement, this.contentElement);
223
- }
188
+ get data(): string|null {
189
+ return this.dataInternal;
224
190
  }
225
191
 
226
- changeNestedContents(value: object): void {
227
- if (value === null || Object.keys(value).length === 0) {
228
- this.unsetNestedContents();
229
- } else {
230
- if (this.pseudoColorProtectionElement !== null) {
231
- this.pseudoColorProtectionElement.remove();
232
- this.pseudoColorProtectionElement = null;
233
- }
234
- this.contentElement.classList.remove('media-property-renderer-hidden');
235
- this.contents.removeChildren();
236
- const jsonWrapperElement =
237
- new SourceFrame.JSONView.JSONView(new SourceFrame.JSONView.ParsedJSON(value, '', ''), true);
238
- jsonWrapperElement.show(this.contents);
239
- }
240
- }
241
-
242
- changeContents(value: string|null): void {
243
- if (value === null) {
244
- this.unsetNestedContents();
245
- } else {
246
- if (this.pseudoColorProtectionElement !== null) {
247
- this.pseudoColorProtectionElement.remove();
248
- this.pseudoColorProtectionElement = null;
249
- }
250
- this.contentElement.classList.remove('media-property-renderer-hidden');
251
- this.contents.removeChildren();
252
- const spanElement = document.createElement('span');
253
- spanElement.textContent = value;
254
- this.contents.appendChild(spanElement);
192
+ set data(val: string|null) {
193
+ if (!val) {
194
+ this.dataInternal = null;
195
+ return;
255
196
  }
197
+ // Some properties are just raw strings.
198
+ this.dataInternal = String(this.parse<string>(val));
256
199
  }
257
200
  }
258
201
 
259
- export class FormattedPropertyRenderer<DataType> extends PropertyRenderer {
260
- private readonly formatfunction: (arg0: DataType) => string;
261
- constructor(title: Platform.UIString.LocalizedString, formatfunction: (arg0: DataType) => string) {
262
- super(title);
263
- this.formatfunction = formatfunction;
264
- }
265
-
266
- override updateDataInternal(propvalue: string): void {
267
- try {
268
- const parsed: DataType = JSON.parse(propvalue) as DataType;
269
- this.changeContents(this.formatfunction(parsed));
270
- } catch {
271
- const unparsed = propvalue as DataType;
272
- this.changeContents(this.formatfunction(unparsed));
273
- }
202
+ class TotalBytesProperty extends Property {
203
+ constructor() {
204
+ super(PlayerPropertyKeys.TOTAL_BYTES);
274
205
  }
275
- }
276
206
 
277
- export class DefaultPropertyRenderer extends PropertyRenderer {
278
- constructor(title: Platform.UIString.LocalizedString, defaultText: string) {
279
- super(title);
280
- this.changeContents(defaultText);
207
+ override get data(): string|null {
208
+ return this.dataInternal;
281
209
  }
282
- }
283
210
 
284
- export class NestedPropertyRenderer extends PropertyRenderer {
285
- constructor(title: Platform.UIString.LocalizedString, content: object) {
286
- super(title);
287
- this.changeNestedContents(content);
211
+ override set data(val: string|null) {
212
+ this.dataInternal = val === null ? null : TotalBytesProperty.formatFileSize(this.parse<string|number>(val));
288
213
  }
289
- }
290
214
 
291
- export class AttributesView extends UI.Widget.VBox {
292
- private readonly contentHash: number;
293
-
294
- constructor(elements: UI.Widget.Widget[]) {
295
- super();
296
- this.contentHash = 0;
297
- this.contentElement.classList.add('media-attributes-view');
298
- for (const element of elements) {
299
- element.show(this.contentElement);
300
- // We just need a really simple way to compare the topical equality
301
- // of the attributes views in order to avoid deleting and recreating
302
- // a node containing exactly the same data.
303
- const content = this.contentElement.textContent;
304
- if (content !== null) {
305
- this.contentHash += Platform.StringUtilities.hashCode(content);
306
- }
215
+ static formatFileSize(bytes: string|number): string {
216
+ if (bytes === '') {
217
+ return '0 bytes';
307
218
  }
308
- }
309
-
310
- getContentHash(): number {
311
- return this.contentHash;
219
+ const actualBytes = Number(bytes);
220
+ if (actualBytes < 1000) {
221
+ return `${bytes} bytes`;
222
+ }
223
+ const power = Math.floor(Math.log10(actualBytes) / 3);
224
+ const suffix = ['bytes', 'kB', 'MB', 'GB', 'TB'][power];
225
+ const bytesDecimal = (actualBytes / Math.pow(1000, power)).toFixed(2);
226
+ return `${bytesDecimal} ${suffix}`;
312
227
  }
313
228
  }
314
229
 
315
- export class TrackManager {
316
- private readonly type: string;
317
- private readonly view: PlayerPropertiesView;
318
-
319
- constructor(propertiesView: PlayerPropertiesView, type: string) {
320
- this.type = type;
321
- this.view = propertiesView;
230
+ class BitRateProperty extends Property {
231
+ constructor() {
232
+ super(PlayerPropertyKeys.BITRATE);
322
233
  }
323
234
 
324
- updateData(value: string): void {
325
- const tabs = this.view.getTabs(this.type);
326
-
327
- const newTabs = JSON.parse(value) as TabData[];
328
- let enumerate = 1;
329
- for (const tabData of newTabs) {
330
- this.addNewTab(tabs, tabData, enumerate);
331
- enumerate++;
332
- }
235
+ override get data(): string|null {
236
+ return this.dataInternal;
333
237
  }
334
238
 
335
- addNewTab(tabs: GenericTrackMenu|NoTracksPlaceholderMenu, tabData: TabData, tabNumber: number): void {
336
- const tabElements = [];
337
- for (const [name, data] of Object.entries(tabData)) {
338
- if (typeof data === 'object') {
339
- tabElements.push(new NestedPropertyRenderer(i18n.i18n.lockedString(name), data));
340
- } else {
341
- tabElements.push(new DefaultPropertyRenderer(i18n.i18n.lockedString(name), data));
342
- }
343
- }
344
- const newTab = new AttributesView(tabElements);
345
-
346
- tabs.addNewTab(tabNumber, newTab);
239
+ override set data(val: string|null) {
240
+ this.dataInternal = val === null ? null : BitRateProperty.formatKbps(this.parse<string|number>(val));
347
241
  }
348
- }
349
242
 
350
- export class VideoTrackManager extends TrackManager {
351
- constructor(propertiesView: PlayerPropertiesView) {
352
- super(propertiesView, 'video');
243
+ static formatKbps(bitsPerSecond: string|number): string {
244
+ if (bitsPerSecond === '') {
245
+ return '0 kbps';
246
+ }
247
+ const kbps = Math.floor(Number(bitsPerSecond) / 1000);
248
+ return `${kbps} kbps`;
353
249
  }
354
250
  }
355
251
 
356
- export class TextTrackManager extends TrackManager {
357
- constructor(propertiesView: PlayerPropertiesView) {
358
- super(propertiesView, 'text');
252
+ class MaxDurationProperty extends Property {
253
+ constructor() {
254
+ super(PlayerPropertyKeys.MAX_DURATION);
359
255
  }
360
- }
361
256
 
362
- export class AudioTrackManager extends TrackManager {
363
- constructor(propertiesView: PlayerPropertiesView) {
364
- super(propertiesView, 'audio');
257
+ override get data(): string|null {
258
+ return this.dataInternal;
365
259
  }
366
- }
367
-
368
- const TrackTypeLocalized = {
369
- Video: i18nLazyString(UIStrings.video),
370
- Audio: i18nLazyString(UIStrings.audio),
371
- };
372
-
373
- class GenericTrackMenu extends UI.TabbedPane.TabbedPane {
374
- private readonly decoderName: string;
375
- private readonly trackName: string;
376
260
 
377
- constructor(decoderName: string, trackName: string = i18nString(UIStrings.track)) {
378
- super();
379
- this.decoderName = decoderName;
380
- this.trackName = trackName;
261
+ override set data(val: string|null) {
262
+ this.dataInternal = val === null ? null : MaxDurationProperty.formatTime(this.parse<string|number>(val));
381
263
  }
382
264
 
383
- addNewTab(trackNumber: number, element: AttributesView): void {
384
- const localizedTrackLower = i18nString(UIStrings.track);
385
- const tabId = `track-${trackNumber}` as Lowercase<string>;
386
- if (this.hasTab(tabId)) {
387
- const tabElement = this.tabView(tabId);
388
- if (tabElement === null) {
389
- return;
390
- }
391
- if ((tabElement as AttributesView).getContentHash() === element.getContentHash()) {
392
- return;
393
- }
394
- this.closeTab(tabId, /* userGesture=*/ false);
265
+ static formatTime(seconds: string|number): string {
266
+ if (seconds === '') {
267
+ return '0:00';
395
268
  }
396
- this.appendTab(
397
- tabId, // No need for localizing, internal ID.
398
- `${this.trackName} #${trackNumber}`, element, `${this.decoderName} ${localizedTrackLower} #${trackNumber}`);
269
+ const date = new Date(0);
270
+ date.setSeconds(Number(seconds));
271
+ return date.toISOString().substring(11, 19);
399
272
  }
400
273
  }
401
274
 
402
- class DecoderTrackMenu extends GenericTrackMenu {
403
- constructor(decoderName: string, informationalElement: UI.Widget.Widget) {
404
- super(decoderName);
405
-
406
- const decoderLocalized = i18nString(UIStrings.decoder);
407
- const title = `${decoderName} ${decoderLocalized}`;
408
- const propertiesLocalized = i18nString(UIStrings.properties);
409
- const hoverText = `${title} ${propertiesLocalized}`;
410
- this.appendTab('decoder-properties', title, informationalElement, hoverText);
275
+ class HlsBufferedRangesProperty extends Property {
276
+ constructor() {
277
+ super(PlayerPropertyKeys.HLS_BUFFERED_RANGES);
411
278
  }
412
- }
413
-
414
- class NoTracksPlaceholderMenu extends UI.Widget.VBox {
415
- private isPlaceholder: boolean;
416
- private readonly wrapping: GenericTrackMenu;
417
279
 
418
- constructor(wrapping: GenericTrackMenu, placeholderText: string) {
419
- super();
420
- this.isPlaceholder = true;
421
- this.wrapping = wrapping;
422
- this.wrapping.appendTab('_placeholder', placeholderText, new UI.Widget.VBox(), placeholderText);
423
- this.wrapping.show(this.contentElement);
280
+ override get data(): string|null {
281
+ return this.dataInternal;
424
282
  }
425
283
 
426
- addNewTab(trackNumber: number, element: AttributesView): void {
427
- if (this.isPlaceholder) {
428
- this.wrapping.closeTab('_placeholder');
429
- this.isPlaceholder = false;
430
- }
431
- this.wrapping.addNewTab(trackNumber, element);
284
+ override set data(val: string|null) {
285
+ this.dataInternal =
286
+ val === null ? null : HlsBufferedRangesProperty.formatBufferedRanges(this.parse<Array<[number, number]>>(val));
432
287
  }
433
- }
434
-
435
- export class PlayerPropertiesView extends UI.Widget.VBox {
436
- private readonly mediaElements: PropertyRenderer[];
437
- private readonly videoDecoderElements: PropertyRenderer[];
438
- private readonly audioDecoderElements: PropertyRenderer[];
439
- private readonly attributeMap: Map<string, PropertyRenderer|TrackManager>;
440
- private readonly videoProperties: AttributesView;
441
- private readonly videoDecoderProperties: AttributesView;
442
- private readonly audioDecoderProperties: AttributesView;
443
- private readonly videoDecoderTabs: DecoderTrackMenu;
444
- private readonly audioDecoderTabs: DecoderTrackMenu;
445
- private textTracksTabs: GenericTrackMenu|NoTracksPlaceholderMenu|null;
446
-
447
- constructor() {
448
- super({jslog: `${VisualLogging.pane('properties')}`});
449
- this.registerRequiredCSS(playerPropertiesViewStyles);
450
-
451
- this.contentElement.classList.add('media-properties-frame');
452
-
453
- this.mediaElements = [];
454
- this.videoDecoderElements = [];
455
- this.audioDecoderElements = [];
456
- this.attributeMap = new Map();
457
-
458
- this.populateAttributesAndElements();
459
- this.videoProperties = new AttributesView(this.mediaElements);
460
- this.videoDecoderProperties = new AttributesView(this.videoDecoderElements);
461
- this.audioDecoderProperties = new AttributesView(this.audioDecoderElements);
462
-
463
- this.videoProperties.show(this.contentElement);
464
- this.videoDecoderTabs = new DecoderTrackMenu(TrackTypeLocalized.Video(), this.videoDecoderProperties);
465
- this.videoDecoderTabs.show(this.contentElement);
466
- this.audioDecoderTabs = new DecoderTrackMenu(TrackTypeLocalized.Audio(), this.audioDecoderProperties);
467
- this.audioDecoderTabs.show(this.contentElement);
468
288
 
469
- this.textTracksTabs = null;
289
+ static formatBufferedRanges(ranges: Array<[number, number]>): string {
290
+ // ranges is an array of `Range`, where a `Range` is a tuple-array of start/end floating point numbers.
291
+ return ranges
292
+ .map(range => {
293
+ return '[' + range[0] + ' → ' + range[1] + ']';
294
+ })
295
+ .join(', ');
470
296
  }
297
+ }
471
298
 
472
- private lazyCreateTrackTabs(): GenericTrackMenu|NoTracksPlaceholderMenu {
473
- let textTracksTabs = this.textTracksTabs;
474
- if (textTracksTabs === null) {
475
- const textTracks = new GenericTrackMenu(i18nString(UIStrings.textTrack));
476
- textTracksTabs = new NoTracksPlaceholderMenu(textTracks, i18nString(UIStrings.noTextTracks));
477
- textTracksTabs.show(this.contentElement);
478
- this.textTracksTabs = textTracksTabs;
479
- }
480
- return textTracksTabs;
299
+ class TrackProperty extends Property {
300
+ #entries: TabData[]|null = null;
301
+ // eslint-disable-next-line @typescript-eslint/no-useless-constructor
302
+ constructor(type: PlayerPropertyKeys.VIDEO_TRACKS|PlayerPropertyKeys.AUDIO_TRACKS|PlayerPropertyKeys.TEXT_TRACKS) {
303
+ super(type);
481
304
  }
482
305
 
483
- getTabs(type: string): GenericTrackMenu|NoTracksPlaceholderMenu {
484
- if (type === 'audio') {
485
- return this.audioDecoderTabs;
486
- }
487
- if (type === 'video') {
488
- return this.videoDecoderTabs;
489
- }
490
- if (type === 'text') {
491
- return this.lazyCreateTrackTabs();
492
- }
493
- // There should be no other type allowed.
494
- throw new Error('Unreachable');
306
+ get entries(): TabData[]|null {
307
+ return this.#entries;
495
308
  }
496
309
 
497
- onProperty(property: Protocol.Media.PlayerProperty): void {
498
- const renderer = this.attributeMap.get(property.name);
499
- if (!renderer) {
500
- throw new Error(`Player property "${property.name}" not supported.`);
501
- }
502
- renderer.updateData(property.value);
310
+ override get data(): never {
311
+ throw new Error('Cannot access raw data');
503
312
  }
504
313
 
505
- formatKbps(bitsPerSecond: string|number): string {
506
- if (bitsPerSecond === '') {
507
- return '0 kbps';
314
+ override set data(val: string|null) {
315
+ if (val === null) {
316
+ this.#entries = null;
317
+ return;
508
318
  }
509
- const kbps = Math.floor(Number(bitsPerSecond) / 1000);
510
- return `${kbps} kbps`;
319
+ const parsed = this.parse<TabData[]>(val);
320
+ this.#entries = Array.isArray(parsed) ? parsed : [];
511
321
  }
512
-
513
- formatTime(seconds: string|number): string {
514
- if (seconds === '') {
515
- return '0:00';
322
+ }
323
+ const {classMap} = Directives;
324
+ const {widget} = UI.Widget;
325
+ interface ViewInput {
326
+ properties: Record<PlayerPropertyKeys, Property>;
327
+ }
328
+ type View = (input: ViewInput, output: object, target: HTMLElement) => void;
329
+ export const DEFAULT_VIEW: View = (input, output, target) => {
330
+ function propertyTitle(type: PlayerPropertyKeys): Platform.UIString.LocalizedString {
331
+ switch (type) {
332
+ case PlayerPropertyKeys.RESOLUTION:
333
+ return i18nString(UIStrings.resolution);
334
+ case PlayerPropertyKeys.TOTAL_BYTES:
335
+ return i18nString(UIStrings.fileSize);
336
+ case PlayerPropertyKeys.BITRATE:
337
+ return i18nString(UIStrings.bitrate);
338
+ case PlayerPropertyKeys.MAX_DURATION:
339
+ return i18nString(UIStrings.duration);
340
+ case PlayerPropertyKeys.START_TIME:
341
+ return i18nString(UIStrings.startTime);
342
+ case PlayerPropertyKeys.IS_STREAMING:
343
+ return i18nString(UIStrings.streaming);
344
+ case PlayerPropertyKeys.FRAME_URL:
345
+ return i18nString(UIStrings.playbackFrameUrl);
346
+ case PlayerPropertyKeys.FRAME_TITLE:
347
+ return i18nString(UIStrings.playbackFrameTitle);
348
+ case PlayerPropertyKeys.IS_SINGLE_ORIGIN:
349
+ return i18nString(UIStrings.singleoriginPlayback);
350
+ case PlayerPropertyKeys.IS_RANGE_HEADER_SUPPORTED:
351
+ return i18nString(UIStrings.rangeHeaderSupport);
352
+ case PlayerPropertyKeys.FRAMERATE:
353
+ return i18nString(UIStrings.frameRate);
354
+ case PlayerPropertyKeys.VIDEO_PLAYBACK_ROUGHNESS:
355
+ return i18nString(UIStrings.videoPlaybackRoughness);
356
+ case PlayerPropertyKeys.VIDEO_PLAYBACK_FREEZING:
357
+ return i18nString(UIStrings.videoFreezingScore);
358
+ case PlayerPropertyKeys.RENDERER_NAME:
359
+ return i18nString(UIStrings.rendererName);
360
+ case PlayerPropertyKeys.HLS_BUFFERED_RANGES:
361
+ return i18nString(UIStrings.hlsBufferedRanges);
362
+ case PlayerPropertyKeys.VIDEO_DECODER_NAME:
363
+ return i18nString(UIStrings.decoderName);
364
+ case PlayerPropertyKeys.IS_PLATFORM_VIDEO_DECODER:
365
+ return i18nString(UIStrings.hardwareDecoder);
366
+ case PlayerPropertyKeys.VIDEO_ENCODER_NAME:
367
+ return i18nString(UIStrings.encoderName);
368
+ case PlayerPropertyKeys.IS_PLATFORM_VIDEO_ENCODER:
369
+ return i18nString(UIStrings.hardwareEncoder);
370
+ case PlayerPropertyKeys.IS_VIDEO_DECRYPTION_DEMUXER_STREAM:
371
+ return i18nString(UIStrings.decryptingDemuxer);
372
+ case PlayerPropertyKeys.AUDIO_DECODER_NAME:
373
+ return i18nString(UIStrings.decoderName);
374
+ case PlayerPropertyKeys.IS_PLATFORM_AUDIO_DECODER:
375
+ return i18nString(UIStrings.hardwareDecoder);
376
+ case PlayerPropertyKeys.IS_AUDIO_DECRYPTING_DEMUXER_STREAM:
377
+ return i18nString(UIStrings.decryptingDemuxer);
378
+ default:
379
+ return Platform.UIString.LocalizedEmptyString;
516
380
  }
517
- const date = new Date();
518
- date.setSeconds(Number(seconds));
519
- return date.toISOString().substr(11, 8);
520
381
  }
521
382
 
522
- formatFileSize(bytes: string): string {
523
- if (bytes === '') {
524
- return '0 bytes';
383
+ const renderAttribute = (data: string|null|LitTemplate, title: string): LitTemplate => {
384
+ return html`<div class=${classMap({
385
+ widget: true,
386
+ vbox: true,
387
+ 'media-property-renderer': true,
388
+ 'media-property-renderer-hidden': data === null,
389
+ })}>
390
+ <span class=media-property-renderer-title>${title}</span>
391
+ <div class=media-property-renderer-contents>${data}</div>
392
+ </div>`;
393
+ };
394
+
395
+ const renderProperty = (property: Property): LitTemplate => {
396
+ let fallback: string|null = null;
397
+ if (property.type === PlayerPropertyKeys.VIDEO_DECODER_NAME ||
398
+ property.type === PlayerPropertyKeys.AUDIO_DECODER_NAME) {
399
+ fallback = i18nString(UIStrings.noDecoder);
400
+ } else if (property.type === PlayerPropertyKeys.VIDEO_ENCODER_NAME) {
401
+ fallback = i18nString(UIStrings.noEncoder);
525
402
  }
526
- const actualBytes = Number(bytes);
527
- if (actualBytes < 1000) {
528
- return `${bytes} bytes`;
529
- }
530
- const power = Math.floor(Math.log10(actualBytes) / 3);
531
- const suffix = ['bytes', 'kB', 'MB', 'GB', 'TB'][power];
532
- const bytesDecimal = (actualBytes / Math.pow(1000, power)).toFixed(2);
533
- return `${bytesDecimal} ${suffix}`;
534
- }
403
+ return renderAttribute(property.data ?? fallback, propertyTitle(property.type));
404
+ };
405
+
406
+ const renderTracks =
407
+ (property: Property, trackName: Platform.UIString.LocalizedString, idPrefix: string): LitTemplate[] =>
408
+ property instanceof TrackProperty && property.entries !== null ?
409
+ property.entries.map(
410
+ // clang-format off
411
+ (track, i) => html`
412
+ <div id=track-${idPrefix}-${i} title=${i18nString(UIStrings.trackNumber, {PH1: trackName, PH2: i + 1})}>
413
+ <div class="widget vbox media-attributes-view">
414
+ ${Object.entries(track).map(([name, data]) => renderAttribute(typeof data === 'object' ? html`${
415
+ widget(e => new SourceFrame.JSONView.JSONView(
416
+ new SourceFrame.JSONView.ParsedJSON(data, '', ''), true, e))}` :
417
+ String(data),
418
+ name))}
419
+ </div>
420
+ </div>`)
421
+ : [nothing];
422
+ // clang-format on
423
+
424
+ render(
425
+ // clang-format off
426
+ html`
427
+ <style>${playerPropertiesViewStyles}</style>
428
+ <div class="widget vbox media-attributes-view">
429
+ ${renderProperty(input.properties[PlayerPropertyKeys.RESOLUTION])}
430
+ ${renderProperty(input.properties[PlayerPropertyKeys.TOTAL_BYTES])}
431
+ ${renderProperty(input.properties[PlayerPropertyKeys.BITRATE])}
432
+ ${renderProperty(input.properties[PlayerPropertyKeys.MAX_DURATION])}
433
+ ${renderProperty(input.properties[PlayerPropertyKeys.START_TIME])}
434
+ ${renderProperty(input.properties[PlayerPropertyKeys.IS_STREAMING])}
435
+ ${renderProperty(input.properties[PlayerPropertyKeys.FRAME_URL])}
436
+ ${renderProperty(input.properties[PlayerPropertyKeys.FRAME_TITLE])}
437
+ ${renderProperty(input.properties[PlayerPropertyKeys.IS_SINGLE_ORIGIN])}
438
+ ${renderProperty(input.properties[PlayerPropertyKeys.IS_RANGE_HEADER_SUPPORTED])}
439
+ ${renderProperty(input.properties[PlayerPropertyKeys.FRAMERATE])}
440
+ ${renderProperty(input.properties[PlayerPropertyKeys.VIDEO_PLAYBACK_ROUGHNESS])}
441
+ ${renderProperty(input.properties[PlayerPropertyKeys.VIDEO_PLAYBACK_FREEZING])}
442
+ ${renderProperty(input.properties[PlayerPropertyKeys.RENDERER_NAME])}
443
+ ${renderProperty(input.properties[PlayerPropertyKeys.HLS_BUFFERED_RANGES])}
444
+ </div>
445
+ <devtools-tabbed-pane>
446
+ <div id=decoder-properties title=${i18nString(UIStrings.videoDecoderProperties)}>
447
+ <div class="widget vbox media-attributes-view">
448
+ ${renderProperty(input.properties[PlayerPropertyKeys.VIDEO_DECODER_NAME])}
449
+ ${renderProperty(input.properties[PlayerPropertyKeys.IS_PLATFORM_VIDEO_DECODER])}
450
+ ${renderProperty(input.properties[PlayerPropertyKeys.VIDEO_ENCODER_NAME])}
451
+ ${renderProperty(input.properties[PlayerPropertyKeys.IS_PLATFORM_VIDEO_ENCODER])}
452
+ ${renderProperty(input.properties[PlayerPropertyKeys.IS_VIDEO_DECRYPTION_DEMUXER_STREAM])}
453
+ </div>
454
+ </div>
455
+ ${renderTracks(input.properties[PlayerPropertyKeys.VIDEO_TRACKS], i18nString(UIStrings.track), 'video')}
456
+ </devtools-tabbed-pane>
457
+ <devtools-tabbed-pane>
458
+ <div id=decoder-properties title=${i18nString(UIStrings.audioDecoderProperties)}>
459
+ <div class="widget vbox media-attributes-view">
460
+ ${renderProperty(input.properties[PlayerPropertyKeys.AUDIO_DECODER_NAME])}
461
+ ${renderProperty(input.properties[PlayerPropertyKeys.IS_PLATFORM_AUDIO_DECODER])}
462
+ ${renderProperty(input.properties[PlayerPropertyKeys.IS_AUDIO_DECRYPTING_DEMUXER_STREAM])}
463
+ </div>
464
+ </div>
465
+ ${renderTracks(input.properties[PlayerPropertyKeys.AUDIO_TRACKS], i18nString(UIStrings.track), 'audio')}
466
+ </devtools-tabbed-pane>
467
+ ${input.properties[PlayerPropertyKeys.TEXT_TRACKS] instanceof TrackProperty &&
468
+ input.properties[PlayerPropertyKeys.TEXT_TRACKS].entries !== null ? html`
469
+ <devtools-tabbed-pane>
470
+ ${input.properties[PlayerPropertyKeys.TEXT_TRACKS].entries.length === 0 ?
471
+ html`<div id=_placeholder title=${i18nString(UIStrings.noTextTracks)}></div>` :
472
+ renderTracks(input.properties[PlayerPropertyKeys.TEXT_TRACKS], i18nString(UIStrings.textTrack), 'text')}
473
+ </devtools-tabbed-pane>`
474
+ : nothing}
475
+ `,
476
+ // clang-format on
477
+ target,
478
+ {container: {attributes: {jslog: `${VisualLogging.pane('properties')}`}, classes: ['media-properties-frame']}});
479
+ };
535
480
 
536
- formatBufferedRanges(ranges: string[]): string {
537
- // ranges is an array of `Range`, where a `Range` is a tuple-array of start/end floating point numbers.
538
- return ranges
539
- .map(range => {
540
- return '[' + range[0] + ' → ' + range[1] + ']';
541
- })
542
- .join(', ');
543
- }
481
+ export class PlayerPropertiesView extends UI.Widget.VBox {
482
+ readonly #view: View;
544
483
 
545
- populateAttributesAndElements(): void {
484
+ #properties: Record<PlayerPropertyKeys, Property> = {
546
485
  /* Media properties */
547
- const resolution = new PropertyRenderer(i18nString(UIStrings.resolution));
548
- this.mediaElements.push(resolution);
549
- this.attributeMap.set(PlayerPropertyKeys.RESOLUTION, resolution);
550
-
551
- const fileSize = new FormattedPropertyRenderer(i18nString(UIStrings.fileSize), this.formatFileSize);
552
- this.mediaElements.push(fileSize);
553
- this.attributeMap.set(PlayerPropertyKeys.TOTAL_BYTES, fileSize);
554
-
555
- const bitrate = new FormattedPropertyRenderer(i18nString(UIStrings.bitrate), this.formatKbps);
556
- this.mediaElements.push(bitrate);
557
- this.attributeMap.set(PlayerPropertyKeys.BITRATE, bitrate);
558
-
559
- const duration = new FormattedPropertyRenderer(i18nString(UIStrings.duration), this.formatTime);
560
- this.mediaElements.push(duration);
561
- this.attributeMap.set(PlayerPropertyKeys.MAX_DURATION, duration);
562
-
563
- const startTime = new PropertyRenderer(i18nString(UIStrings.startTime));
564
- this.mediaElements.push(startTime);
565
- this.attributeMap.set(PlayerPropertyKeys.START_TIME, startTime);
566
-
567
- const streaming = new PropertyRenderer(i18nString(UIStrings.streaming));
568
- this.mediaElements.push(streaming);
569
- this.attributeMap.set(PlayerPropertyKeys.IS_STREAMING, streaming);
570
-
571
- const frameUrl = new PropertyRenderer(i18nString(UIStrings.playbackFrameUrl));
572
- this.mediaElements.push(frameUrl);
573
- this.attributeMap.set(PlayerPropertyKeys.FRAME_URL, frameUrl);
574
-
575
- const frameTitle = new PropertyRenderer(i18nString(UIStrings.playbackFrameTitle));
576
- this.mediaElements.push(frameTitle);
577
- this.attributeMap.set(PlayerPropertyKeys.FRAME_TITLE, frameTitle);
578
-
579
- const singleOrigin = new PropertyRenderer(i18nString(UIStrings.singleoriginPlayback));
580
- this.mediaElements.push(singleOrigin);
581
- this.attributeMap.set(PlayerPropertyKeys.IS_SINGLE_ORIGIN, singleOrigin);
582
-
583
- const rangeHeaders = new PropertyRenderer(i18nString(UIStrings.rangeHeaderSupport));
584
- this.mediaElements.push(rangeHeaders);
585
- this.attributeMap.set(PlayerPropertyKeys.IS_RANGE_HEADER_SUPPORTED, rangeHeaders);
586
-
587
- const frameRate = new PropertyRenderer(i18nString(UIStrings.frameRate));
588
- this.mediaElements.push(frameRate);
589
- this.attributeMap.set(PlayerPropertyKeys.FRAMERATE, frameRate);
590
-
591
- const roughness = new PropertyRenderer(i18nString(UIStrings.videoPlaybackRoughness));
592
- this.mediaElements.push(roughness);
593
- this.attributeMap.set(PlayerPropertyKeys.VIDEO_PLAYBACK_ROUGHNESS, roughness);
594
-
595
- const freezingScore = new PropertyRenderer(i18nString(UIStrings.videoFreezingScore));
596
- this.mediaElements.push(freezingScore);
597
- this.attributeMap.set(PlayerPropertyKeys.VIDEO_PLAYBACK_FREEZING, freezingScore);
598
-
599
- const rendererName = new PropertyRenderer(i18nString(UIStrings.rendererName));
600
- this.mediaElements.push(rendererName);
601
- this.attributeMap.set(PlayerPropertyKeys.RENDERER_NAME, rendererName);
602
-
603
- const hlsBufferedRanges =
604
- new FormattedPropertyRenderer(i18nString(UIStrings.hlsBufferedRanges), this.formatBufferedRanges);
605
- this.mediaElements.push(hlsBufferedRanges);
606
- this.attributeMap.set(PlayerPropertyKeys.HLS_BUFFERED_RANGES, hlsBufferedRanges);
486
+ [PlayerPropertyKeys.RESOLUTION]: new Property(PlayerPropertyKeys.RESOLUTION),
487
+ [PlayerPropertyKeys.TOTAL_BYTES]: new TotalBytesProperty(),
488
+ [PlayerPropertyKeys.BITRATE]: new BitRateProperty(),
489
+ [PlayerPropertyKeys.MAX_DURATION]: new MaxDurationProperty(),
490
+ [PlayerPropertyKeys.START_TIME]: new Property(PlayerPropertyKeys.START_TIME),
491
+ [PlayerPropertyKeys.IS_STREAMING]: new Property(PlayerPropertyKeys.IS_STREAMING),
492
+ [PlayerPropertyKeys.FRAME_URL]: new Property(PlayerPropertyKeys.FRAME_URL),
493
+ [PlayerPropertyKeys.FRAME_TITLE]: new Property(PlayerPropertyKeys.FRAME_TITLE),
494
+ [PlayerPropertyKeys.IS_SINGLE_ORIGIN]: new Property(PlayerPropertyKeys.IS_SINGLE_ORIGIN),
495
+ [PlayerPropertyKeys.IS_RANGE_HEADER_SUPPORTED]: new Property(PlayerPropertyKeys.IS_RANGE_HEADER_SUPPORTED),
496
+ [PlayerPropertyKeys.FRAMERATE]: new Property(PlayerPropertyKeys.FRAMERATE),
497
+ [PlayerPropertyKeys.VIDEO_PLAYBACK_ROUGHNESS]: new Property(PlayerPropertyKeys.VIDEO_PLAYBACK_ROUGHNESS),
498
+ [PlayerPropertyKeys.VIDEO_PLAYBACK_FREEZING]: new Property(PlayerPropertyKeys.VIDEO_PLAYBACK_FREEZING),
499
+ [PlayerPropertyKeys.RENDERER_NAME]: new Property(PlayerPropertyKeys.RENDERER_NAME),
500
+ [PlayerPropertyKeys.HLS_BUFFERED_RANGES]: new HlsBufferedRangesProperty(),
607
501
 
608
502
  /* Video Decoder Properties */
609
- const decoderName = new DefaultPropertyRenderer(i18nString(UIStrings.decoderName), i18nString(UIStrings.noDecoder));
610
- this.videoDecoderElements.push(decoderName);
611
- this.attributeMap.set(PlayerPropertyKeys.VIDEO_DECODER_NAME, decoderName);
612
-
613
- const videoPlatformDecoder = new PropertyRenderer(i18nString(UIStrings.hardwareDecoder));
614
- this.videoDecoderElements.push(videoPlatformDecoder);
615
- this.attributeMap.set(PlayerPropertyKeys.IS_PLATFORM_VIDEO_DECODER, videoPlatformDecoder);
616
-
617
- const encoderName = new DefaultPropertyRenderer(i18nString(UIStrings.encoderName), i18nString(UIStrings.noEncoder));
618
- this.videoDecoderElements.push(encoderName);
619
- this.attributeMap.set(PlayerPropertyKeys.VIDEO_ENCODER_NAME, encoderName);
620
-
621
- const videoPlatformEncoder = new PropertyRenderer(i18nString(UIStrings.hardwareEncoder));
622
- this.videoDecoderElements.push(videoPlatformEncoder);
623
- this.attributeMap.set(PlayerPropertyKeys.IS_PLATFORM_VIDEO_ENCODER, videoPlatformEncoder);
624
-
625
- const videoDDS = new PropertyRenderer(i18nString(UIStrings.decryptingDemuxer));
626
- this.videoDecoderElements.push(videoDDS);
627
- this.attributeMap.set(PlayerPropertyKeys.IS_VIDEO_DECRYPTION_DEMUXER_STREAM, videoDDS);
628
-
629
- const videoTrackManager = new VideoTrackManager(this);
630
- this.attributeMap.set(PlayerPropertyKeys.VIDEO_TRACKS, videoTrackManager);
503
+ [PlayerPropertyKeys.VIDEO_DECODER_NAME]: new Property(PlayerPropertyKeys.VIDEO_DECODER_NAME),
504
+ [PlayerPropertyKeys.IS_PLATFORM_VIDEO_DECODER]: new Property(PlayerPropertyKeys.IS_PLATFORM_VIDEO_DECODER),
505
+ [PlayerPropertyKeys.VIDEO_ENCODER_NAME]: new Property(PlayerPropertyKeys.VIDEO_ENCODER_NAME),
506
+ [PlayerPropertyKeys.IS_PLATFORM_VIDEO_ENCODER]: new Property(PlayerPropertyKeys.IS_PLATFORM_VIDEO_ENCODER),
507
+ [PlayerPropertyKeys.IS_VIDEO_DECRYPTION_DEMUXER_STREAM]:
508
+ new Property(PlayerPropertyKeys.IS_VIDEO_DECRYPTION_DEMUXER_STREAM),
509
+ [PlayerPropertyKeys.VIDEO_TRACKS]: new TrackProperty(PlayerPropertyKeys.VIDEO_TRACKS),
631
510
 
632
511
  /* Audio Decoder Properties */
633
- const audioDecoder =
634
- new DefaultPropertyRenderer(i18nString(UIStrings.decoderName), i18nString(UIStrings.noDecoder));
635
- this.audioDecoderElements.push(audioDecoder);
636
- this.attributeMap.set(PlayerPropertyKeys.AUDIO_DECODER_NAME, audioDecoder);
512
+ [PlayerPropertyKeys.AUDIO_DECODER_NAME]: new Property(PlayerPropertyKeys.AUDIO_DECODER_NAME),
513
+ [PlayerPropertyKeys.IS_PLATFORM_AUDIO_DECODER]: new Property(PlayerPropertyKeys.IS_PLATFORM_AUDIO_DECODER),
514
+ [PlayerPropertyKeys.IS_AUDIO_DECRYPTING_DEMUXER_STREAM]:
515
+ new Property(PlayerPropertyKeys.IS_AUDIO_DECRYPTING_DEMUXER_STREAM),
516
+ [PlayerPropertyKeys.AUDIO_TRACKS]: new TrackProperty(PlayerPropertyKeys.AUDIO_TRACKS),
517
+ [PlayerPropertyKeys.TEXT_TRACKS]: new TrackProperty(PlayerPropertyKeys.TEXT_TRACKS),
518
+ };
519
+
520
+ constructor(target?: HTMLElement, view = DEFAULT_VIEW) {
521
+ super(target);
522
+ this.#view = view;
523
+ }
637
524
 
638
- const audioPlatformDecoder = new PropertyRenderer(i18nString(UIStrings.hardwareDecoder));
639
- this.audioDecoderElements.push(audioPlatformDecoder);
640
- this.attributeMap.set(PlayerPropertyKeys.IS_PLATFORM_AUDIO_DECODER, audioPlatformDecoder);
525
+ get properties(): Record<PlayerPropertyKeys, Property> {
526
+ return this.#properties;
527
+ }
641
528
 
642
- const audioDDS = new PropertyRenderer(i18nString(UIStrings.decryptingDemuxer));
643
- this.audioDecoderElements.push(audioDDS);
644
- this.attributeMap.set(PlayerPropertyKeys.IS_AUDIO_DECRYPTING_DEMUXER_STREAM, audioDDS);
529
+ onProperty(property: Protocol.Media.PlayerProperty): void {
530
+ if (!(property.name in this.#properties)) {
531
+ throw new Error(`Player property '${property.name}' not supported.`);
532
+ }
533
+ this.#properties[property.name as PlayerPropertyKeys].data = property.value;
534
+ this.requestUpdate();
535
+ }
645
536
 
646
- const audioTrackManager = new AudioTrackManager(this);
647
- this.attributeMap.set(PlayerPropertyKeys.AUDIO_TRACKS, audioTrackManager);
537
+ override wasShown(): void {
538
+ super.wasShown();
539
+ this.requestUpdate();
540
+ }
648
541
 
649
- const textTrackManager = new TextTrackManager(this);
650
- this.attributeMap.set(PlayerPropertyKeys.TEXT_TRACKS, textTrackManager);
542
+ override performUpdate(): void {
543
+ this.#view(this, {}, this.contentElement);
651
544
  }
652
545
  }