mirror of
https://github.com/hensm/fx_cast.git
synced 2026-06-11 18:19:58 +00:00
Implement partial queue support and other cast.media.Media improvements
This commit is contained in:
@@ -270,9 +270,8 @@ async function registerMediaElementListeners() {
|
|||||||
});
|
});
|
||||||
|
|
||||||
mediaElement.addEventListener("ratechange", () => {
|
mediaElement.addEventListener("ratechange", () => {
|
||||||
currentMedia._sendMediaMessage({
|
currentMedia._sendMediaMessage("SET_PLAYBACK_RATE", {
|
||||||
type: "SET_PLAYBACK_RATE"
|
playbackRate: mediaElement.playbackRate
|
||||||
, playbackRate: mediaElement.playbackRate
|
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|||||||
@@ -12,8 +12,11 @@ import MediaInfo from "./MediaInfo";
|
|||||||
import PauseRequest from "./PauseRequest";
|
import PauseRequest from "./PauseRequest";
|
||||||
import PlayRequest from "./PlayRequest";
|
import PlayRequest from "./PlayRequest";
|
||||||
import QueueData from "./QueueData";
|
import QueueData from "./QueueData";
|
||||||
|
import QueueJumpRequest from "./QueueJumpRequest";
|
||||||
import QueueInsertItemsRequest from "./QueueInsertItemsRequest";
|
import QueueInsertItemsRequest from "./QueueInsertItemsRequest";
|
||||||
import QueueItem from "./QueueItem";
|
import QueueItem from "./QueueItem";
|
||||||
|
import QueueSetPropertiesRequest from "./QueueSetPropertiesRequest";
|
||||||
|
import QueueRemoveItemsRequest from "./QueueRemoveItemsRequest";
|
||||||
import QueueReorderItemsRequest from "./QueueReorderItemsRequest";
|
import QueueReorderItemsRequest from "./QueueReorderItemsRequest";
|
||||||
import QueueUpdateItemsRequest from "./QueueUpdateItemsRequest";
|
import QueueUpdateItemsRequest from "./QueueUpdateItemsRequest";
|
||||||
import SeekRequest from "./SeekRequest";
|
import SeekRequest from "./SeekRequest";
|
||||||
@@ -37,6 +40,38 @@ import { Callbacks
|
|||||||
, UpdateListener } from "../../../types";
|
, 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 {
|
export default class Media {
|
||||||
#id = uuid();
|
#id = uuid();
|
||||||
#isActive = true;
|
#isActive = true;
|
||||||
@@ -140,11 +175,14 @@ export default class Media {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public editTracksInfo(
|
public editTracksInfo(
|
||||||
_editTracksInfoRequest: EditTracksInfoRequest
|
editTracksInfoRequest: EditTracksInfoRequest
|
||||||
, _successCallback?: SuccessCallback
|
, successCallback?: SuccessCallback
|
||||||
, _errorCallback?: ErrorCallback): void {
|
, errorCallback?: ErrorCallback): void {
|
||||||
|
|
||||||
logger.info("STUB :: Media#editTracksInfo");
|
this._sendMediaMessage(
|
||||||
|
MediaMessageType.EditTracksInfo
|
||||||
|
, editTracksInfoRequest
|
||||||
|
, successCallback, errorCallback);
|
||||||
}
|
}
|
||||||
|
|
||||||
public getEstimatedBreakClipTime() {
|
public getEstimatedBreakClipTime() {
|
||||||
@@ -167,99 +205,214 @@ export default class Media {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public getStatus(
|
public getStatus(
|
||||||
_getStatusRequest?: GetStatusRequest
|
getStatusRequest?: GetStatusRequest
|
||||||
, successCallback?: SuccessCallback
|
, successCallback?: SuccessCallback
|
||||||
, errorCallback?: ErrorCallback): void {
|
, errorCallback?: ErrorCallback): void {
|
||||||
|
|
||||||
this._sendMediaMessage({ type: "MEDIA_GET_STATUS" }
|
if (!getStatusRequest) {
|
||||||
|
getStatusRequest = new GetStatusRequest();
|
||||||
|
}
|
||||||
|
|
||||||
|
this._sendMediaMessage(
|
||||||
|
MediaMessageType.MediaGetStatus
|
||||||
|
, getStatusRequest
|
||||||
, successCallback, errorCallback);
|
, successCallback, errorCallback);
|
||||||
}
|
}
|
||||||
|
|
||||||
public pause(
|
public pause(
|
||||||
_pauseRequest?: PauseRequest
|
pauseRequest?: PauseRequest
|
||||||
, successCallback?: SuccessCallback
|
, successCallback?: SuccessCallback
|
||||||
, errorCallback?: ErrorCallback): void {
|
, errorCallback?: ErrorCallback): void {
|
||||||
|
|
||||||
this._sendMediaMessage({ type: "PAUSE" }
|
if (!pauseRequest) {
|
||||||
|
pauseRequest = new PauseRequest();
|
||||||
|
}
|
||||||
|
|
||||||
|
this._sendMediaMessage(
|
||||||
|
MediaMessageType.Pause
|
||||||
|
, pauseRequest
|
||||||
, successCallback, errorCallback);
|
, successCallback, errorCallback);
|
||||||
}
|
}
|
||||||
|
|
||||||
public play(
|
public play(
|
||||||
_playRequest?: PlayRequest
|
playRequest?: PlayRequest
|
||||||
, successCallback?: SuccessCallback
|
, successCallback?: SuccessCallback
|
||||||
, errorCallback?: ErrorCallback): void {
|
, errorCallback?: ErrorCallback): void {
|
||||||
|
|
||||||
this._sendMediaMessage({ type: "PLAY" }
|
if (!playRequest) {
|
||||||
|
playRequest = new PlayRequest();
|
||||||
|
}
|
||||||
|
|
||||||
|
this._sendMediaMessage(
|
||||||
|
MediaMessageType.Play
|
||||||
|
, playRequest
|
||||||
, successCallback, errorCallback);
|
, successCallback, errorCallback);
|
||||||
}
|
}
|
||||||
|
|
||||||
public queueAppendItem(
|
public queueAppendItem(
|
||||||
_item: QueueItem
|
item: QueueItem
|
||||||
, _successCallback?: SuccessCallback
|
, successCallback?: SuccessCallback
|
||||||
, _errorCallback?: ErrorCallback): void {
|
, errorCallback?: ErrorCallback): void {
|
||||||
logger.info("STUB :: Media#queueAppendItem");
|
|
||||||
|
this._sendMediaMessage(
|
||||||
|
MediaMessageType.QueueInsert
|
||||||
|
, new QueueInsertItemsRequest([ item ])
|
||||||
|
, successCallback, errorCallback);
|
||||||
}
|
}
|
||||||
|
|
||||||
public queueInsertItems(
|
public queueInsertItems(
|
||||||
_queueInsertItemsRequest: QueueInsertItemsRequest
|
queueInsertItemsRequest: QueueInsertItemsRequest
|
||||||
, _successCallback?: SuccessCallback
|
, successCallback?: SuccessCallback
|
||||||
, _errorCallback?: ErrorCallback): void {
|
, errorCallback?: ErrorCallback): void {
|
||||||
logger.info("STUB :: Media#queueInsertItems");
|
|
||||||
|
this._sendMediaMessage(
|
||||||
|
MediaMessageType.QueueInsert
|
||||||
|
, queueInsertItemsRequest
|
||||||
|
, successCallback, errorCallback);
|
||||||
}
|
}
|
||||||
|
|
||||||
public queueJumpToItem(
|
public queueJumpToItem(
|
||||||
_itemId: number
|
itemId: number
|
||||||
, _successCallback?: SuccessCallback
|
, successCallback?: SuccessCallback
|
||||||
, _errorCallback?: ErrorCallback): void {
|
, errorCallback?: ErrorCallback): void {
|
||||||
logger.info("STUB :: Media#queueJumpToItem");
|
|
||||||
|
if (this.items?.find(item => item.itemId === itemId)) {
|
||||||
|
const jumpRequest = new QueueJumpRequest();
|
||||||
|
jumpRequest.currentItemId = itemId;
|
||||||
|
|
||||||
|
this._sendMediaMessage(
|
||||||
|
MediaMessageType.QueueUpdate
|
||||||
|
, jumpRequest
|
||||||
|
, successCallback, errorCallback);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public queueMoveItemToNewIndex(
|
public queueMoveItemToNewIndex(
|
||||||
_itemId: number
|
itemId: number
|
||||||
, _newIndex: number
|
, newIndex: number
|
||||||
, _successCallback?: SuccessCallback
|
, successCallback?: SuccessCallback
|
||||||
, _errorCallback?: ErrorCallback): void {
|
, errorCallback?: ErrorCallback): void {
|
||||||
logger.info("STUB :: Media#queueMoveItemToNewIndex");
|
|
||||||
|
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(
|
public queueNext(
|
||||||
_successCallback?: SuccessCallback
|
successCallback?: SuccessCallback
|
||||||
, _errorCallback?: ErrorCallback): void {
|
, errorCallback?: ErrorCallback): void {
|
||||||
logger.info("STUB :: Media#queueNext");
|
|
||||||
|
const jumpRequest = new QueueJumpRequest();
|
||||||
|
jumpRequest.jump = 1;
|
||||||
|
|
||||||
|
this._sendMediaMessage(
|
||||||
|
MediaMessageType.QueueUpdate
|
||||||
|
, jumpRequest
|
||||||
|
, successCallback, errorCallback);
|
||||||
}
|
}
|
||||||
|
|
||||||
public queuePrev(
|
public queuePrev(
|
||||||
_successCallback?: SuccessCallback
|
successCallback?: SuccessCallback
|
||||||
, _errorCallback?: ErrorCallback): void {
|
, errorCallback?: ErrorCallback): void {
|
||||||
logger.info("STUB :: Media#queuePrev");
|
|
||||||
|
const jumpRequest = new QueueJumpRequest();
|
||||||
|
jumpRequest.jump = -1;
|
||||||
|
|
||||||
|
this._sendMediaMessage(
|
||||||
|
MediaMessageType.QueueUpdate
|
||||||
|
, jumpRequest
|
||||||
|
, successCallback, errorCallback);
|
||||||
}
|
}
|
||||||
|
|
||||||
public queueRemoveItem(
|
public queueRemoveItem(
|
||||||
_itemId: number
|
itemId: number
|
||||||
, _successCallback?: SuccessCallback
|
, successCallback?: SuccessCallback
|
||||||
, _errorCallback?: ErrorCallback): void {
|
, errorCallback?: ErrorCallback): void {
|
||||||
logger.info("STUB :: Media#queueRemoveItem");
|
|
||||||
|
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(
|
public queueReorderItems(
|
||||||
_queueReorderItemsRequest: QueueReorderItemsRequest
|
queueReorderItemsRequest: QueueReorderItemsRequest
|
||||||
, _successCallback?: SuccessCallback
|
, successCallback?: SuccessCallback
|
||||||
, _errorCallback?: ErrorCallback): void {
|
, errorCallback?: ErrorCallback): void {
|
||||||
logger.info("STUB :: Media#queueReorderItems");
|
|
||||||
|
this._sendMediaMessage(
|
||||||
|
MediaMessageType.QueueReorder
|
||||||
|
, queueReorderItemsRequest
|
||||||
|
, successCallback, errorCallback);
|
||||||
}
|
}
|
||||||
|
|
||||||
public queueSetRepeatMode(
|
public queueSetRepeatMode(
|
||||||
_repeatMode: string
|
repeatMode: string
|
||||||
, _successCallback?: SuccessCallback
|
, successCallback?: SuccessCallback
|
||||||
, _errorCallback?: ErrorCallback): void {
|
, errorCallback?: ErrorCallback): void {
|
||||||
logger.info("STUB :: Media#queueSetRepeatMode");
|
|
||||||
|
const setPropertiesRequest = new QueueSetPropertiesRequest();
|
||||||
|
setPropertiesRequest.repeatMode = repeatMode;
|
||||||
|
|
||||||
|
this._sendMediaMessage(
|
||||||
|
MediaMessageType.QueueUpdate
|
||||||
|
, setPropertiesRequest
|
||||||
|
, successCallback, errorCallback);
|
||||||
}
|
}
|
||||||
|
|
||||||
public queueUpdateItems(
|
public queueUpdateItems(
|
||||||
_queueUpdateItemsRequest: QueueUpdateItemsRequest
|
queueUpdateItemsRequest: QueueUpdateItemsRequest
|
||||||
, _successCallback?: SuccessCallback
|
, successCallback?: SuccessCallback
|
||||||
, _errorCallback?: ErrorCallback): void {
|
, errorCallback?: ErrorCallback): void {
|
||||||
logger.info("STUB :: Media#queueUpdateItems");
|
|
||||||
|
this._sendMediaMessage(
|
||||||
|
MediaMessageType.QueueUpdate
|
||||||
|
, queueUpdateItemsRequest
|
||||||
|
, successCallback, errorCallback);
|
||||||
}
|
}
|
||||||
|
|
||||||
public removeUpdateListener(listener: UpdateListener) {
|
public removeUpdateListener(listener: UpdateListener) {
|
||||||
@@ -271,30 +424,33 @@ export default class Media {
|
|||||||
, successCallback?: SuccessCallback
|
, successCallback?: SuccessCallback
|
||||||
, errorCallback?: ErrorCallback): void {
|
, errorCallback?: ErrorCallback): void {
|
||||||
|
|
||||||
this._sendMediaMessage({
|
|
||||||
type: "SEEK"
|
this._sendMediaMessage(
|
||||||
, currentTime: seekRequest.currentTime
|
MediaMessageType.Seek
|
||||||
}, successCallback, errorCallback);
|
, seekRequest
|
||||||
|
, successCallback, errorCallback);
|
||||||
}
|
}
|
||||||
|
|
||||||
public setVolume(
|
public setVolume(
|
||||||
volumeRequest: VolumeRequest
|
volumeRequest: VolumeRequest
|
||||||
, successCallback?: SuccessCallback
|
, successCallback?: SuccessCallback
|
||||||
, errorCallback?: ErrorCallback): void {
|
, errorCallback?: ErrorCallback): void {
|
||||||
|
|
||||||
this._sendMediaMessage({
|
|
||||||
type: "SET_VOLUME"
|
this._sendMediaMessage(
|
||||||
, volume: volumeRequest.volume
|
MediaMessageType.MediaSetVolume
|
||||||
}, successCallback, errorCallback);
|
, volumeRequest
|
||||||
|
, successCallback, errorCallback);
|
||||||
}
|
}
|
||||||
|
|
||||||
public stop(
|
public stop(
|
||||||
_stopRequest: StopRequest
|
stopRequest: StopRequest
|
||||||
, successCallback?: SuccessCallback
|
, successCallback?: SuccessCallback
|
||||||
, errorCallback?: ErrorCallback): void {
|
, errorCallback?: ErrorCallback): void {
|
||||||
|
|
||||||
this._sendMediaMessage(
|
this._sendMediaMessage(
|
||||||
{ type: "STOP" }
|
MediaMessageType.StopMedia
|
||||||
|
, stopRequest
|
||||||
, () => {
|
, () => {
|
||||||
this.#isActive = false;
|
this.#isActive = false;
|
||||||
this.#listener.disconnect();
|
this.#listener.disconnect();
|
||||||
@@ -306,14 +462,14 @@ export default class Media {
|
|||||||
, errorCallback);
|
, errorCallback);
|
||||||
}
|
}
|
||||||
|
|
||||||
public supportsCommand(_command: string): boolean {
|
public supportsCommand(command: string): boolean {
|
||||||
logger.info("STUB :: Media#supportsCommand");
|
return this.supportedMediaCommands.includes(command);
|
||||||
return true;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
public _sendMediaMessage(
|
public _sendMediaMessage(
|
||||||
message: any
|
messageType: string
|
||||||
|
, message: MediaRequest
|
||||||
, successCallback?: SuccessCallback
|
, successCallback?: SuccessCallback
|
||||||
, errorCallback?: ErrorCallback) {
|
, errorCallback?: ErrorCallback) {
|
||||||
|
|
||||||
@@ -331,10 +487,13 @@ export default class Media {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
message.mediaSessionId = this.mediaSessionId;
|
// TODO: Fix this
|
||||||
message.requestId = 0;
|
(message as any).type = messageType;
|
||||||
message.sessionId = this.sessionId;
|
|
||||||
message.customData = null;
|
(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();
|
const messageId = uuid();
|
||||||
|
|
||||||
|
|||||||
15
ext/src/shim/cast/media/classes/QueueJumpRequest.ts
Normal file
15
ext/src/shim/cast/media/classes/QueueJumpRequest.ts
Normal file
@@ -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";
|
||||||
|
}
|
||||||
@@ -11,7 +11,8 @@ body {
|
|||||||
background: var(--grey-80) !important;
|
background: var(--grey-80) !important;
|
||||||
color: white !important;
|
color: white !important;
|
||||||
}
|
}
|
||||||
.media-select {
|
.media-select,
|
||||||
|
.receiver:not(:last-child) {
|
||||||
border-bottom-color: var(--grey-50) !important;
|
border-bottom-color: var(--grey-50) !important;
|
||||||
}
|
}
|
||||||
.receiver__address {
|
.receiver__address {
|
||||||
|
|||||||
Reference in New Issue
Block a user