blob: 6ceae44981e4e1286cc1c13daa02fd1eab12972a [file] [log] [blame]
Ted Meyer79b022f2019-10-08 18:24:301// Copyright 2019 The Chromium Authors. All rights reserved.
2// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
Tim van der Lippec02a97c2020-02-14 14:39:275import * as Common from '../common/common.js'; // eslint-disable-line no-unused-vars
Ted Meyer6a973ea2020-03-16 01:48:516import * as SDK from '../sdk/sdk.js';
Ted Meyer0aab7462020-02-27 20:16:137import * as UI from '../ui/ui.js';
Tim van der Lippe0c7b4d22020-03-10 16:48:598
Ted Meyer9a7ea8c2020-04-28 23:37:099import {MediaModel, PlayerEvent, ProtocolTriggers} from './MediaModel.js'; // eslint-disable-line no-unused-vars
Tim van der Lippe0c7b4d22020-03-10 16:48:5910import {PlayerDetailView} from './PlayerDetailView.js';
11import {PlayerListView} from './PlayerListView.js';
Tim van der Lippec02a97c2020-02-14 14:39:2712
Ted Meyer9a7ea8c2020-04-28 23:37:0913/** @interface */
14export class TriggerHandler {
15 /** @param {!Protocol.Media.PlayerProperty} property */
16 onProperty(property) {
17 }
18
19 /** @param {!Protocol.Media.PlayerError} error */
20 onError(error) {
21 }
22
23 /** @param {!Protocol.Media.PlayerMessage} message */
24 onMessage(message) {
25 }
26
27 /** @param {!PlayerEvent} event */
28 onEvent(event) {
29 }
30}
31
32/** @interface */
33export class TriggerDispatcher {
34 /**
35 * @param {string} playerID
36 * @param {!Protocol.Media.PlayerProperty} property
37 */
38 onProperty(playerID, property) {
39 }
40
41 /**
42 * @param {string} playerID
43 * @param {!Protocol.Media.PlayerError} error
44 */
45 onError(playerID, error) {
46 }
47
48 /**
49 * @param {string} playerID
50 * @param {!Protocol.Media.PlayerMessage} message
51 */
52 onMessage(playerID, message) {
53 }
54
55 /**
56 * @param {string} playerID
57 * @param {!PlayerEvent} event
58 */
59 onEvent(playerID, event) {
60 }
61}
62
Ted Meyer79b022f2019-10-08 18:24:3063/**
Ted Meyer8eec09f2020-07-31 21:45:5764 * @implements TriggerHandler
65 */
66class PlayerDataCollection {
67 constructor() {
Paul Lewis8d314a42020-10-09 13:42:4068 /** @type {!Map<string, string>} */
69 this._properties = new Map();
Ted Meyer8eec09f2020-07-31 21:45:5770
Paul Lewis8d314a42020-10-09 13:42:4071 /** @type {!Array<!Protocol.Media.PlayerMessage>} */
Ted Meyer8eec09f2020-07-31 21:45:5772 this._messages = [];
Paul Lewis8d314a42020-10-09 13:42:4073
74 /** @type {!Array<!PlayerEvent>} */
Ted Meyer8eec09f2020-07-31 21:45:5775 this._events = [];
Paul Lewis8d314a42020-10-09 13:42:4076
77 /** @type {!Array<!Protocol.Media.PlayerError>} */
Ted Meyer8eec09f2020-07-31 21:45:5778 this._errors = [];
79 }
80
81 /**
82 * @override
83 * @param {!Protocol.Media.PlayerProperty} property
84 */
85 onProperty(property) {
Paul Lewis8d314a42020-10-09 13:42:4086 this._properties.set(property.name, property.value);
Ted Meyer8eec09f2020-07-31 21:45:5787 }
88
89 /**
90 * @override
91 * @param {!Protocol.Media.PlayerError} error */
92 onError(error) {
93 this._errors.push(error);
94 }
95
96 /**
97 * @override
98 * @param {!Protocol.Media.PlayerMessage} message
99 */
100 onMessage(message) {
101 this._messages.push(message);
102 }
103
104 /**
105 * @override
106 * @param {!PlayerEvent} event
107 */
108 onEvent(event) {
109 this._events.push(event);
110 }
111
112 export() {
113 return {'properties': this._properties, 'messages': this._messages, 'events': this._events, 'errors': this._errors};
114 }
115}
116
117/**
118 * @implements TriggerDispatcher
119 */
120class PlayerDataDownloadManager {
121 constructor() {
Paul Lewis8d314a42020-10-09 13:42:40122 /**
123 * @type {!Map<string, !PlayerDataCollection>}
124 */
Ted Meyer8eec09f2020-07-31 21:45:57125 this._playerDataCollection = new Map();
126 }
127
Paul Lewis8d314a42020-10-09 13:42:40128 /**
129 * @param {string} playerID
130 */
Ted Meyer8eec09f2020-07-31 21:45:57131 addPlayer(playerID) {
132 this._playerDataCollection.set(playerID, new PlayerDataCollection());
133 }
134
135 /**
136 * @override
137 * @param {string} playerID
138 * @param {!Protocol.Media.PlayerProperty} property
139 */
140 onProperty(playerID, property) {
Paul Lewis8d314a42020-10-09 13:42:40141 const playerProperty = this._playerDataCollection.get(playerID);
142 if (!playerProperty) {
143 return;
144 }
145
146 playerProperty.onProperty(property);
Ted Meyer8eec09f2020-07-31 21:45:57147 }
148
149 /**
150 * @override
151 * @param {string} playerID
152 * @param {!Protocol.Media.PlayerError} error
153 */
154 onError(playerID, error) {
Paul Lewis8d314a42020-10-09 13:42:40155 const playerProperty = this._playerDataCollection.get(playerID);
156 if (!playerProperty) {
157 return;
158 }
159
160 playerProperty.onError(error);
Ted Meyer8eec09f2020-07-31 21:45:57161 }
162
163 /**
164 * @override
165 * @param {string} playerID
166 * @param {!Protocol.Media.PlayerMessage} message
167 */
168 onMessage(playerID, message) {
Paul Lewis8d314a42020-10-09 13:42:40169 const playerProperty = this._playerDataCollection.get(playerID);
170 if (!playerProperty) {
171 return;
172 }
173
174 playerProperty.onMessage(message);
Ted Meyer8eec09f2020-07-31 21:45:57175 }
176
177 /**
178 * @override
179 * @param {string} playerID
180 * @param {!PlayerEvent} event
181 */
182 onEvent(playerID, event) {
Paul Lewis8d314a42020-10-09 13:42:40183 const playerProperty = this._playerDataCollection.get(playerID);
184 if (!playerProperty) {
185 return;
186 }
187
188 playerProperty.onEvent(event);
Ted Meyer8eec09f2020-07-31 21:45:57189 }
190
Paul Lewis8d314a42020-10-09 13:42:40191 /**
192 * @param {string} playerID
193 */
Ted Meyer8eec09f2020-07-31 21:45:57194 exportPlayerData(playerID) {
Paul Lewis8d314a42020-10-09 13:42:40195 const playerProperty = this._playerDataCollection.get(playerID);
196 if (!playerProperty) {
197 throw new Error('Unable to find player');
198 }
199
200 return playerProperty.export();
Ted Meyer8eec09f2020-07-31 21:45:57201 }
202
Paul Lewis8d314a42020-10-09 13:42:40203 /**
204 * @param {string} playerID
205 */
Ted Meyer8eec09f2020-07-31 21:45:57206 deletePlayer(playerID) {
207 this._playerDataCollection.delete(playerID);
208 }
209}
210
211/**
Paul Lewis8d314a42020-10-09 13:42:40212 * @implements {SDK.SDKModel.SDKModelObserver<!MediaModel>}
Ted Meyer79b022f2019-10-08 18:24:30213 */
Ted Meyer0aab7462020-02-27 20:16:13214export class MainView extends UI.Panel.PanelWithSidebar {
Ted Meyer79b022f2019-10-08 18:24:30215 constructor() {
216 super('Media');
Jack Franklin71519f82020-11-03 12:08:59217 this.registerRequiredCSS('media/mediaView.css', {enableLegacyPatching: true});
Ted Meyer79b022f2019-10-08 18:24:30218
Tim van der Lippe0c7b4d22020-03-10 16:48:59219 // Map<PlayerDetailView>
Ted Meyer79b022f2019-10-08 18:24:30220 this._detailPanels = new Map();
221
222 // Map<string>
223 this._deletedPlayers = new Set();
224
Ted Meyer8eec09f2020-07-31 21:45:57225 this._downloadStore = new PlayerDataDownloadManager();
226
Tim van der Lippe0c7b4d22020-03-10 16:48:59227 this._sidebar = new PlayerListView(this);
Ted Meyer79b022f2019-10-08 18:24:30228 this._sidebar.show(this.panelSidebarElement());
229
Tim van der Lippe0c7b4d22020-03-10 16:48:59230 SDK.SDKModel.TargetManager.instance().observeModels(MediaModel, this);
Ted Meyer79b022f2019-10-08 18:24:30231 }
232
233 /**
234 * @param {string} playerID
Ted Meyer79b022f2019-10-08 18:24:30235 */
236 renderMainPanel(playerID) {
237 if (!this._detailPanels.has(playerID)) {
238 return;
239 }
Paul Lewis8d314a42020-10-09 13:42:40240 const mainWidget = this.splitWidget().mainWidget();
241 if (mainWidget) {
242 mainWidget.detachChildWidgets();
243 }
Ted Meyer79b022f2019-10-08 18:24:30244 this._detailPanels.get(playerID).show(this.mainElement());
245 }
246
247 /**
Ted Meyer79b022f2019-10-08 18:24:30248 * @override
249 */
250 wasShown() {
251 super.wasShown();
Tim van der Lippe0c7b4d22020-03-10 16:48:59252 for (const model of SDK.SDKModel.TargetManager.instance().models(MediaModel)) {
Ted Meyer79b022f2019-10-08 18:24:30253 this._addEventListeners(model);
254 }
255 }
256
257 /**
258 * @override
259 */
260 willHide() {
Tim van der Lippe0c7b4d22020-03-10 16:48:59261 for (const model of SDK.SDKModel.TargetManager.instance().models(MediaModel)) {
Ted Meyer79b022f2019-10-08 18:24:30262 this._removeEventListeners(model);
263 }
264 }
265
266 /**
267 * @override
Paul Lewis8d314a42020-10-09 13:42:40268 * @param {!MediaModel} model
Ted Meyer79b022f2019-10-08 18:24:30269 */
Paul Lewis8d314a42020-10-09 13:42:40270 modelAdded(model) {
Ted Meyer79b022f2019-10-08 18:24:30271 if (this.isShowing()) {
Paul Lewis8d314a42020-10-09 13:42:40272 this._addEventListeners(model);
Ted Meyer79b022f2019-10-08 18:24:30273 }
274 }
275
276 /**
277 * @override
Paul Lewis8d314a42020-10-09 13:42:40278 * @param {!MediaModel} model
Ted Meyer79b022f2019-10-08 18:24:30279 */
Paul Lewis8d314a42020-10-09 13:42:40280 modelRemoved(model) {
281 this._removeEventListeners(model);
Ted Meyer79b022f2019-10-08 18:24:30282 }
283
284 /**
Paul Lewis8d314a42020-10-09 13:42:40285 * @param {!MediaModel} mediaModel
Ted Meyer79b022f2019-10-08 18:24:30286 */
287 _addEventListeners(mediaModel) {
288 mediaModel.ensureEnabled();
Ted Meyer9a7ea8c2020-04-28 23:37:09289 mediaModel.addEventListener(ProtocolTriggers.PlayerPropertiesChanged, this._propertiesChanged, this);
290 mediaModel.addEventListener(ProtocolTriggers.PlayerEventsAdded, this._eventsAdded, this);
291 mediaModel.addEventListener(ProtocolTriggers.PlayerMessagesLogged, this._messagesLogged, this);
292 mediaModel.addEventListener(ProtocolTriggers.PlayerErrorsRaised, this._errorsRaised, this);
293 mediaModel.addEventListener(ProtocolTriggers.PlayersCreated, this._playersCreated, this);
Ted Meyer79b022f2019-10-08 18:24:30294 }
295
296 /**
Paul Lewis8d314a42020-10-09 13:42:40297 * @param {!MediaModel} mediaModel
Ted Meyer79b022f2019-10-08 18:24:30298 */
299 _removeEventListeners(mediaModel) {
Ted Meyer9a7ea8c2020-04-28 23:37:09300 mediaModel.removeEventListener(ProtocolTriggers.PlayerPropertiesChanged, this._propertiesChanged, this);
301 mediaModel.removeEventListener(ProtocolTriggers.PlayerEventsAdded, this._eventsAdded, this);
302 mediaModel.removeEventListener(ProtocolTriggers.PlayerMessagesLogged, this._messagesLogged, this);
303 mediaModel.removeEventListener(ProtocolTriggers.PlayerErrorsRaised, this._errorsRaised, this);
304 mediaModel.removeEventListener(ProtocolTriggers.PlayersCreated, this._playersCreated, this);
305 }
306
307 /**
308 * @param {string} playerID
309 */
310 _onPlayerCreated(playerID) {
311 this._sidebar.addMediaElementItem(playerID);
312 this._detailPanels.set(playerID, new PlayerDetailView());
Ted Meyer8eec09f2020-07-31 21:45:57313 this._downloadStore.addPlayer(playerID);
Ted Meyer79b022f2019-10-08 18:24:30314 }
315
316 /**
Tim van der Lippec02a97c2020-02-14 14:39:27317 * @param {!Common.EventTarget.EventTargetEvent} event
Ted Meyer79b022f2019-10-08 18:24:30318 */
319 _propertiesChanged(event) {
Ted Meyer9a7ea8c2020-04-28 23:37:09320 for (const property of event.data.properties) {
321 this.onProperty(event.data.playerId, property);
322 }
Ted Meyer79b022f2019-10-08 18:24:30323 }
324
325 /**
Tim van der Lippec02a97c2020-02-14 14:39:27326 * @param {!Common.EventTarget.EventTargetEvent} event
Ted Meyer79b022f2019-10-08 18:24:30327 */
328 _eventsAdded(event) {
Ted Meyer9a7ea8c2020-04-28 23:37:09329 for (const ev of event.data.events) {
330 this.onEvent(event.data.playerId, ev);
331 }
332 }
333
334 /**
335 * @param {!Common.EventTarget.EventTargetEvent} event
336 */
337 _messagesLogged(event) {
338 for (const message of event.data.messages) {
339 this.onMessage(event.data.playerId, message);
340 }
341 }
342
343 /**
344 * @param {!Common.EventTarget.EventTargetEvent} event
345 */
346 _errorsRaised(event) {
347 for (const error of event.data.errors) {
348 this.onError(event.data.playerId, error);
349 }
350 }
351
352 /**
353 * @param {string} playerID
354 * @return {boolean}
355 */
356 _shouldPropagate(playerID) {
357 return !this._deletedPlayers.has(playerID) && this._detailPanels.has(playerID);
358 }
359
360 /**
Ted Meyer9a7ea8c2020-04-28 23:37:09361 * @param {string} playerID
362 * @param {!Protocol.Media.PlayerProperty} property
363 */
364 onProperty(playerID, property) {
365 if (!this._shouldPropagate(playerID)) {
366 return;
367 }
368 this._sidebar.onProperty(playerID, property);
Ted Meyer8eec09f2020-07-31 21:45:57369 this._downloadStore.onProperty(playerID, property);
Ted Meyer9a7ea8c2020-04-28 23:37:09370 this._detailPanels.get(playerID).onProperty(property);
371 }
372
373 /**
Ted Meyer9a7ea8c2020-04-28 23:37:09374 * @param {string} playerID
375 * @param {!Protocol.Media.PlayerError} error
376 */
377 onError(playerID, error) {
378 if (!this._shouldPropagate(playerID)) {
379 return;
380 }
381 this._sidebar.onError(playerID, error);
Ted Meyer8eec09f2020-07-31 21:45:57382 this._downloadStore.onError(playerID, error);
Ted Meyer9a7ea8c2020-04-28 23:37:09383 this._detailPanels.get(playerID).onError(error);
384 }
385
386 /**
Ted Meyer9a7ea8c2020-04-28 23:37:09387 * @param {string} playerID
388 * @param {!Protocol.Media.PlayerMessage} message
389 */
390 onMessage(playerID, message) {
391 if (!this._shouldPropagate(playerID)) {
392 return;
393 }
394 this._sidebar.onMessage(playerID, message);
Ted Meyer8eec09f2020-07-31 21:45:57395 this._downloadStore.onMessage(playerID, message);
Ted Meyer9a7ea8c2020-04-28 23:37:09396 this._detailPanels.get(playerID).onMessage(message);
397 }
398
399 /**
Ted Meyer9a7ea8c2020-04-28 23:37:09400 * @param {string} playerID
401 * @param {!PlayerEvent} event
402 */
403 onEvent(playerID, event) {
404 if (!this._shouldPropagate(playerID)) {
405 return;
406 }
407 this._sidebar.onEvent(playerID, event);
Ted Meyer8eec09f2020-07-31 21:45:57408 this._downloadStore.onEvent(playerID, event);
Ted Meyer9a7ea8c2020-04-28 23:37:09409 this._detailPanels.get(playerID).onEvent(event);
Ted Meyer79b022f2019-10-08 18:24:30410 }
411
412 /**
Tim van der Lippec02a97c2020-02-14 14:39:27413 * @param {!Common.EventTarget.EventTargetEvent} event
Ted Meyer79b022f2019-10-08 18:24:30414 */
415 _playersCreated(event) {
416 const playerlist = /** @type {!Iterable.<string>} */ (event.data);
417 for (const playerID of playerlist) {
418 this._onPlayerCreated(playerID);
419 }
420 }
Ted Meyerc69e9072020-07-21 00:02:11421
422 /**
423 * @param {string} playerID
424 */
425 markPlayerForDeletion(playerID) {
426 // TODO(tmathmeyer): send this to chromium to save the storage space there too.
427 this._deletedPlayers.add(playerID);
428 this._detailPanels.delete(playerID);
429 this._sidebar.deletePlayer(playerID);
Ted Meyer8eec09f2020-07-31 21:45:57430 this._downloadStore.deletePlayer(playerID);
431 }
432
Paul Lewis8d314a42020-10-09 13:42:40433 /**
434 * @param {string} playerID
435 */
Ted Meyera1d72d52020-08-04 23:17:25436 markOtherPlayersForDeletion(playerID) {
437 for (const keyID of this._detailPanels.keys()) {
438 if (keyID !== playerID) {
439 this.markPlayerForDeletion(keyID);
440 }
441 }
442 }
443
Paul Lewis8d314a42020-10-09 13:42:40444 /**
445 * @param {string} playerID
446 */
Ted Meyer8eec09f2020-07-31 21:45:57447 exportPlayerData(playerID) {
448 const dump = this._downloadStore.exportPlayerData(playerID);
449 const uriContent = 'data:application/octet-stream,' + encodeURIComponent(JSON.stringify(dump, null, 2));
450 const anchor = document.createElement('a');
451 anchor.href = uriContent;
452 anchor.download = playerID + '.json';
453 anchor.click();
Ted Meyerc69e9072020-07-21 00:02:11454 }
Ted Meyer0aab7462020-02-27 20:16:13455}