From cff7466046daa02ae50b5f4a20a231c80b79baa4 Mon Sep 17 00:00:00 2001 From: hensm Date: Tue, 27 Apr 2021 06:15:55 +0100 Subject: [PATCH] Implement partial queue support and other cast.media.Media improvements --- ext/src/senders/media/index.ts | 5 +- ext/src/shim/cast/media/classes/Media.ts | 297 ++++++++++++++---- .../cast/media/classes/QueueJumpRequest.ts | 15 + ext/src/ui/popup/styles/index.css | 3 +- 4 files changed, 247 insertions(+), 73 deletions(-) create mode 100644 ext/src/shim/cast/media/classes/QueueJumpRequest.ts diff --git a/ext/src/senders/media/index.ts b/ext/src/senders/media/index.ts index 35c6af6..8bb2adf 100644 --- a/ext/src/senders/media/index.ts +++ b/ext/src/senders/media/index.ts @@ -270,9 +270,8 @@ async function registerMediaElementListeners() { }); mediaElement.addEventListener("ratechange", () => { - currentMedia._sendMediaMessage({ - type: "SET_PLAYBACK_RATE" - , playbackRate: mediaElement.playbackRate + currentMedia._sendMediaMessage("SET_PLAYBACK_RATE", { + playbackRate: mediaElement.playbackRate }); }); diff --git a/ext/src/shim/cast/media/classes/Media.ts b/ext/src/shim/cast/media/classes/Media.ts index 7e98017..5631fab 100644 --- a/ext/src/shim/cast/media/classes/Media.ts +++ b/ext/src/shim/cast/media/classes/Media.ts @@ -12,8 +12,11 @@ import MediaInfo from "./MediaInfo"; import PauseRequest from "./PauseRequest"; import PlayRequest from "./PlayRequest"; import QueueData from "./QueueData"; +import QueueJumpRequest from "./QueueJumpRequest"; import QueueInsertItemsRequest from "./QueueInsertItemsRequest"; import QueueItem from "./QueueItem"; +import QueueSetPropertiesRequest from "./QueueSetPropertiesRequest"; +import QueueRemoveItemsRequest from "./QueueRemoveItemsRequest"; import QueueReorderItemsRequest from "./QueueReorderItemsRequest"; import QueueUpdateItemsRequest from "./QueueUpdateItemsRequest"; import SeekRequest from "./SeekRequest"; @@ -37,6 +40,38 @@ import { Callbacks , UpdateListener } from "../../../types"; +type MediaRequest = + EditTracksInfoRequest + | GetStatusRequest + | PauseRequest + | PlayRequest + | QueueInsertItemsRequest + | QueueJumpRequest + | QueueRemoveItemsRequest + | QueueReorderItemsRequest + | QueueUpdateItemsRequest + | SeekRequest + | StopRequest + | VolumeRequest; + + +enum MediaMessageType { + Play = "PLAY" + , Load = "LOAD" + , Pause = "PAUSE" + , Seek = "SEEK" + , StopMedia = "STOP_MEDIA" + , MediaSetVolume = "MEDIA_SET_VOLUME" + , MediaGetStatus = "MEDIA_GET_STATUS" + , EditTracksInfo = "EDIT_TRACKS_INFO" + , QueueLoad = "QUEUE_LOAD" + , QueueInsert = "QUEUE_INSERT" + , QueueUpdate = "QUEUE_UPDATE" + , QueueRemove = "QUEUE_REMOVE" + , QueueReorder = "QUEUE_REORDER" +} + + export default class Media { #id = uuid(); #isActive = true; @@ -140,11 +175,14 @@ export default class Media { } public editTracksInfo( - _editTracksInfoRequest: EditTracksInfoRequest - , _successCallback?: SuccessCallback - , _errorCallback?: ErrorCallback): void { + editTracksInfoRequest: EditTracksInfoRequest + , successCallback?: SuccessCallback + , errorCallback?: ErrorCallback): void { - logger.info("STUB :: Media#editTracksInfo"); + this._sendMediaMessage( + MediaMessageType.EditTracksInfo + , editTracksInfoRequest + , successCallback, errorCallback); } public getEstimatedBreakClipTime() { @@ -167,99 +205,214 @@ export default class Media { } public getStatus( - _getStatusRequest?: GetStatusRequest + getStatusRequest?: GetStatusRequest , successCallback?: SuccessCallback , errorCallback?: ErrorCallback): void { - - this._sendMediaMessage({ type: "MEDIA_GET_STATUS" } + + if (!getStatusRequest) { + getStatusRequest = new GetStatusRequest(); + } + + this._sendMediaMessage( + MediaMessageType.MediaGetStatus + , getStatusRequest , successCallback, errorCallback); } public pause( - _pauseRequest?: PauseRequest + pauseRequest?: PauseRequest , successCallback?: SuccessCallback , errorCallback?: ErrorCallback): void { - this._sendMediaMessage({ type: "PAUSE" } + if (!pauseRequest) { + pauseRequest = new PauseRequest(); + } + + this._sendMediaMessage( + MediaMessageType.Pause + , pauseRequest , successCallback, errorCallback); } public play( - _playRequest?: PlayRequest + playRequest?: PlayRequest , successCallback?: SuccessCallback , errorCallback?: ErrorCallback): void { - this._sendMediaMessage({ type: "PLAY" } + if (!playRequest) { + playRequest = new PlayRequest(); + } + + this._sendMediaMessage( + MediaMessageType.Play + , playRequest , successCallback, errorCallback); } public queueAppendItem( - _item: QueueItem - , _successCallback?: SuccessCallback - , _errorCallback?: ErrorCallback): void { - logger.info("STUB :: Media#queueAppendItem"); + item: QueueItem + , successCallback?: SuccessCallback + , errorCallback?: ErrorCallback): void { + + this._sendMediaMessage( + MediaMessageType.QueueInsert + , new QueueInsertItemsRequest([ item ]) + , successCallback, errorCallback); } public queueInsertItems( - _queueInsertItemsRequest: QueueInsertItemsRequest - , _successCallback?: SuccessCallback - , _errorCallback?: ErrorCallback): void { - logger.info("STUB :: Media#queueInsertItems"); + queueInsertItemsRequest: QueueInsertItemsRequest + , successCallback?: SuccessCallback + , errorCallback?: ErrorCallback): void { + + this._sendMediaMessage( + MediaMessageType.QueueInsert + , queueInsertItemsRequest + , successCallback, errorCallback); } public queueJumpToItem( - _itemId: number - , _successCallback?: SuccessCallback - , _errorCallback?: ErrorCallback): void { - logger.info("STUB :: Media#queueJumpToItem"); + itemId: number + , successCallback?: SuccessCallback + , errorCallback?: ErrorCallback): void { + + if (this.items?.find(item => item.itemId === itemId)) { + const jumpRequest = new QueueJumpRequest(); + jumpRequest.currentItemId = itemId; + + this._sendMediaMessage( + MediaMessageType.QueueUpdate + , jumpRequest + , successCallback, errorCallback); + } } public queueMoveItemToNewIndex( - _itemId: number - , _newIndex: number - , _successCallback?: SuccessCallback - , _errorCallback?: ErrorCallback): void { - logger.info("STUB :: Media#queueMoveItemToNewIndex"); + itemId: number + , newIndex: number + , successCallback?: SuccessCallback + , errorCallback?: ErrorCallback): void { + + if (!this.items) { + return; + } + + const itemIndex = this.items.findIndex(item => item.itemId === itemId); + + if (itemIndex !== -1) { + // New index must not be negative + if (newIndex < 0) { + if (errorCallback) { + errorCallback(new _Error(ErrorCode.INVALID_PARAMETER)); + } + } else if (newIndex == itemIndex) { + if (successCallback) { successCallback(); } + } + } else { + if (newIndex > itemIndex) { + newIndex++; + } + + const reorderItemsRequest = + new QueueReorderItemsRequest([ itemId ]); + if (newIndex < this.items.length) { + const existingItem = this.items[newIndex]; + reorderItemsRequest.insertBefore = existingItem.itemId; + } + + this._sendMediaMessage( + MediaMessageType.QueueReorder + , reorderItemsRequest + , successCallback, errorCallback); + } } public queueNext( - _successCallback?: SuccessCallback - , _errorCallback?: ErrorCallback): void { - logger.info("STUB :: Media#queueNext"); + successCallback?: SuccessCallback + , errorCallback?: ErrorCallback): void { + + const jumpRequest = new QueueJumpRequest(); + jumpRequest.jump = 1; + + this._sendMediaMessage( + MediaMessageType.QueueUpdate + , jumpRequest + , successCallback, errorCallback); } public queuePrev( - _successCallback?: SuccessCallback - , _errorCallback?: ErrorCallback): void { - logger.info("STUB :: Media#queuePrev"); + successCallback?: SuccessCallback + , errorCallback?: ErrorCallback): void { + + const jumpRequest = new QueueJumpRequest(); + jumpRequest.jump = -1; + + this._sendMediaMessage( + MediaMessageType.QueueUpdate + , jumpRequest + , successCallback, errorCallback); } public queueRemoveItem( - _itemId: number - , _successCallback?: SuccessCallback - , _errorCallback?: ErrorCallback): void { - logger.info("STUB :: Media#queueRemoveItem"); + itemId: number + , successCallback?: SuccessCallback + , errorCallback?: ErrorCallback): void { + + const item = this.items?.find(item => item.itemId === itemId); + if (item) { + const removeItemsRequest = new QueueRemoveItemsRequest([ itemId ]); + this._sendMediaMessage( + MediaMessageType.QueueRemove + , removeItemsRequest + , successCallback, errorCallback); + } + } + + public queueRemoveItems( + queueRemoveItemsRequest: QueueRemoveItemsRequest + , successCallback?: SuccessCallback + , errorCallback?: ErrorCallback): void { + + this._sendMediaMessage( + MediaMessageType.QueueRemove + , queueRemoveItemsRequest + , successCallback, errorCallback); } public queueReorderItems( - _queueReorderItemsRequest: QueueReorderItemsRequest - , _successCallback?: SuccessCallback - , _errorCallback?: ErrorCallback): void { - logger.info("STUB :: Media#queueReorderItems"); + queueReorderItemsRequest: QueueReorderItemsRequest + , successCallback?: SuccessCallback + , errorCallback?: ErrorCallback): void { + + this._sendMediaMessage( + MediaMessageType.QueueReorder + , queueReorderItemsRequest + , successCallback, errorCallback); } public queueSetRepeatMode( - _repeatMode: string - , _successCallback?: SuccessCallback - , _errorCallback?: ErrorCallback): void { - logger.info("STUB :: Media#queueSetRepeatMode"); + repeatMode: string + , successCallback?: SuccessCallback + , errorCallback?: ErrorCallback): void { + + const setPropertiesRequest = new QueueSetPropertiesRequest(); + setPropertiesRequest.repeatMode = repeatMode; + + this._sendMediaMessage( + MediaMessageType.QueueUpdate + , setPropertiesRequest + , successCallback, errorCallback); } public queueUpdateItems( - _queueUpdateItemsRequest: QueueUpdateItemsRequest - , _successCallback?: SuccessCallback - , _errorCallback?: ErrorCallback): void { - logger.info("STUB :: Media#queueUpdateItems"); + queueUpdateItemsRequest: QueueUpdateItemsRequest + , successCallback?: SuccessCallback + , errorCallback?: ErrorCallback): void { + + this._sendMediaMessage( + MediaMessageType.QueueUpdate + , queueUpdateItemsRequest + , successCallback, errorCallback); } public removeUpdateListener(listener: UpdateListener) { @@ -271,30 +424,33 @@ export default class Media { , successCallback?: SuccessCallback , errorCallback?: ErrorCallback): void { - this._sendMediaMessage({ - type: "SEEK" - , currentTime: seekRequest.currentTime - }, successCallback, errorCallback); + + this._sendMediaMessage( + MediaMessageType.Seek + , seekRequest + , successCallback, errorCallback); } public setVolume( volumeRequest: VolumeRequest , successCallback?: SuccessCallback , errorCallback?: ErrorCallback): void { - - this._sendMediaMessage({ - type: "SET_VOLUME" - , volume: volumeRequest.volume - }, successCallback, errorCallback); + + + this._sendMediaMessage( + MediaMessageType.MediaSetVolume + , volumeRequest + , successCallback, errorCallback); } public stop( - _stopRequest: StopRequest + stopRequest: StopRequest , successCallback?: SuccessCallback , errorCallback?: ErrorCallback): void { this._sendMediaMessage( - { type: "STOP" } + MediaMessageType.StopMedia + , stopRequest , () => { this.#isActive = false; this.#listener.disconnect(); @@ -306,14 +462,14 @@ export default class Media { , errorCallback); } - public supportsCommand(_command: string): boolean { - logger.info("STUB :: Media#supportsCommand"); - return true; + public supportsCommand(command: string): boolean { + return this.supportedMediaCommands.includes(command); } public _sendMediaMessage( - message: any + messageType: string + , message: MediaRequest , successCallback?: SuccessCallback , errorCallback?: ErrorCallback) { @@ -331,10 +487,13 @@ export default class Media { return; } - message.mediaSessionId = this.mediaSessionId; - message.requestId = 0; - message.sessionId = this.sessionId; - message.customData = null; + // TODO: Fix this + (message as any).type = messageType; + + (message as any).mediaSessionId = this.mediaSessionId; + (message as any).requestId = 0; + (message as any).sessionId = this.sessionId; + (message as any).customData = null; const messageId = uuid(); diff --git a/ext/src/shim/cast/media/classes/QueueJumpRequest.ts b/ext/src/shim/cast/media/classes/QueueJumpRequest.ts new file mode 100644 index 0000000..24ed194 --- /dev/null +++ b/ext/src/shim/cast/media/classes/QueueJumpRequest.ts @@ -0,0 +1,15 @@ +"use strict"; + +import QueueItem from "./QueueItem"; + +import { RepeatMode } from "../enums"; + + +export default class QueueJumpRequest { + public jump: (number | null) = null; + public currentItemId: (number | null) = null; + public sessionId: (number | null) = null; + public requestId: (number | null) = null; + + public type = "QUEUE_UPDATE"; +} diff --git a/ext/src/ui/popup/styles/index.css b/ext/src/ui/popup/styles/index.css index 4372b27..e0a73b2 100755 --- a/ext/src/ui/popup/styles/index.css +++ b/ext/src/ui/popup/styles/index.css @@ -11,7 +11,8 @@ body { background: var(--grey-80) !important; color: white !important; } - .media-select { + .media-select, + .receiver:not(:last-child) { border-bottom-color: var(--grey-50) !important; } .receiver__address {