Skip to content

Commit

Permalink
Merge pull request #77 from YouKnowBlom/migrate-commandhandler
Browse files Browse the repository at this point in the history
Migrate commandHandler to typescript
  • Loading branch information
YouKnowBlom authored Nov 28, 2020
2 parents ae604e9 + b6db4e1 commit f67b0c0
Show file tree
Hide file tree
Showing 3 changed files with 83 additions and 59 deletions.
3 changes: 2 additions & 1 deletion src/app.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
import { RepeatMode } from "./api/generated/models/repeat-mode";
import "./components/maincontroller";

const senders = cast.framework.CastReceiverContext.getInstance().getSenders();
Expand All @@ -13,7 +14,7 @@ window.mediaElement = document.getElementById('video-player');

window.playlist = [];
window.currentPlaylistIndex = -1;
window.repeatMode = "RepeatNone";
window.repeatMode = RepeatMode.RepeatNone;

// Global variable set by Webpack
if (!PRODUCTION) {
Expand Down
135 changes: 78 additions & 57 deletions src/components/commandHandler.js → src/components/commandHandler.ts
Original file line number Diff line number Diff line change
Expand Up @@ -15,101 +15,120 @@ import {
reportPlaybackProgress
} from "./jellyfinActions";

import { CastReceiverContext, PlayerManager } from "chromecast-caf-receiver/cast.framework";
import { playbackManager } from "./playbackManager";

export interface DataMessage {
//TODO: figure out a better type for data
[any: string]: any
}

interface SupportedCommands {
[command: string]: (data: DataMessage) => any
}

export class commandHandler {
constructor(castContext, playerManager, playbackManager) {
private castContext: CastReceiverContext;
private playerManager: PlayerManager;
private playbackManager: playbackManager;
private supportedCommands: SupportedCommands = {
PlayNext: this.playNextHandler,
PlayLast: this.playLastHandler,
Shuffle: this.shuffleHandler,
InstantMix: this.instantMixHandler,
DisplayContent: this.displayContentHandler,
NextTrack: this.nextTrackHandler,
PreviousTrack: this.previousTrackHandler,
SetAudioStreamIndex: this.setAudioStreamIndexHandler,
SetSubtitleStreamIndex: this.setSubtitleStreamIndexHandler,
VolumeUp: this.VolumeUpHandler,
VolumeDown: this.VolumeDownHandler,
ToggleMute: this.ToggleMuteHandler,
Identify: this.IdentifyHandler,
SetVolume: this.SetVolumeHandler,
Seek: this.SeekHandler,
Mute: this.MuteHandler,
Unmute: this.MuteHandler,
Stop: this.StopHandler,
PlayPause: this.PlayPauseHandler,
Pause: this.PauseHandler,
SetRepeatMode: this.SetRepeatModeHandler,
Unpause: this.UnpauseHandler
};

constructor(
castContext: CastReceiverContext,
playerManager: PlayerManager,
playbackManager: playbackManager
) {
this.castContext = castContext;
this.playerManager = playerManager;
this.playbackManager = playbackManager;
}

this.supportedCommands = {
PlayNext: this.playNextHandler,
PlayLast: this.playLastHandler,
Shuffle: this.shuffleHandler,
InstantMix: this.instantMixHandler,
DisplayContent: this.displayContentHandler,
NextTrack: this.nextTrackHandler,
PreviousTrack: this.previousTrackHandler,
SetAudioStreamIndex: this.setAudioStreamIndexHandler,
SetSubtitleStreamIndex: this.setSubtitleStreamIndexHandler,
VolumeUp: this.VolumeUpHandler,
VolumeDown: this.VolumeDownHandler,
ToggleMute: this.ToggleMuteHandler,
Identify: this.IdentifyHandler,
SetVolume: this.SetVolumeHandler,
Seek: this.SeekHandler,
Mute: this.MuteHandler,
Unmute: this.MuteHandler,
Stop: this.StopHandler,
PlayPause: this.PlayPauseHandler,
Pause: this.PauseHandler,
SetRepeatMode: this.SetRepeatModeHandler,
Unpause: this.UnpauseHandler
};
}

playNextHandler(data) {
playNextHandler(data: DataMessage): void {
translateItems(data, data.options, data.options.items, data.command);
}

playLastHandler(data) {
playLastHandler(data: DataMessage): void {
translateItems(data, data.options, data.options.items, data.command);
}

shuffleHandler(data) {
shuffleHandler(data: DataMessage): void {
shuffle(data, data.options, data.options.items[0]);
}

instantMixHandler(data) {
instantMixHandler(data: DataMessage): void {
instantMix(data, data.options, data.options.items[0]);
}

displayContentHandler(data) {
displayContentHandler(data: DataMessage): void {
if (!this.playbackManager.isPlaying()) {
displayItem($scope, data.serverAddress, data.accessToken, data.userId, data.options.ItemId);
}
}

nextTrackHandler() {
nextTrackHandler(): void {
if (window.playlist && window.currentPlaylistIndex < window.playlist.length - 1) {
this.playbackManager.playNextItem({}, true);
}
}

previousTrackHandler() {
previousTrackHandler(): void {
if (window.playlist && window.currentPlaylistIndex > 0) {
this.playbackManager.playPreviousItem({});
}
}

setAudioStreamIndexHandler(data) {
setAudioStreamIndexHandler(data: DataMessage): void {
setAudioStreamIndex($scope, data.options.index);
}

setSubtitleStreamIndexHandler(data) {
setSubtitleStreamIndexHandler(data: DataMessage): void {
setSubtitleStreamIndex($scope, data.options.index, data.serverAddress);
}

// VolumeUp, VolumeDown and ToggleMute commands seem to be handled on the sender in the current implementation.
// From what I can tell there's no convenient way for the receiver to get its own volume.
// We should probably remove these commands in the future.
VolumeUpHandler() {
VolumeUpHandler(): void {
console.log("VolumeUp handler not implemented");
}

VolumeDownHandler() {
VolumeDownHandler(): void {
console.log("VolumeDown handler not implemented");
}

ToggleMuteHandler() {
ToggleMuteHandler(): void {
console.log("ToggleMute handler not implemented");
}

SetVolumeHandler(data) {
// Scale 0-100
this.castContext.setSystemVolumeLevel(data.options.volume / 100);
SetVolumeHandler(data: DataMessage): void {
// This is now implemented on the sender
console.log("SetVolume handler not implemented");
}

IdentifyHandler(data) {
IdentifyHandler(data: DataMessage): void {
if (!this.playbackManager.isPlaying()) {
displayUserInfo($scope, data.serverAddress, data.accessToken, data.userId);
} else {
Expand All @@ -118,56 +137,58 @@ export class commandHandler {
}
}

SeekHandler(data) {
SeekHandler(data: DataMessage): void {
seek(data.options.position * 10000000);
}

MuteHandler() {
this.castContext.setSystemVolumeMuted(true);
MuteHandler(): void {
// This is now implemented on the sender
console.log("Mute handler not implemented");
}

UnmuteHandler() {
this.castContext.setSystemVolumeMuted(false);
UnmuteHandler(): void {
// This is now implemented on the sender
console.log("Unmute handler not implemented");
}

StopHandler() {
StopHandler(): void {
this.playerManager.stop();
}

PlayPauseHandler() {
PlayPauseHandler(): void {
if (this.playerManager.getPlayerState() === cast.framework.messages.PlayerState.PAUSED) {
this.playerManager.play();
} else {
this.playerManager.pause();
}
}

PauseHandler() {
PauseHandler(): void {
this.playerManager.pause();
}

SetRepeatModeHandler(data) {
SetRepeatModeHandler(data: DataMessage): void {
window.repeatMode = data.options.RepeatMode;
window.reportEventType = 'repeatmodechange';
}

UnpauseHandler() {
UnpauseHandler(): void {
this.playerManager.play();
}

// We should avoid using a defaulthandler that has a purpose other than informing the dev/user
// Currently all unhandled commands will be treated as play commands.
defaultHandler(data) {
defaultHandler(data: DataMessage): void {
translateItems(data, data.options, data.options.items, 'play');
}

processMessage(data, command) {
processMessage(data: DataMessage, command: string) {
const commandHandler = this.supportedCommands[command];
if (typeof commandHandler === "function") {
console.debug(`Command "${command}" received. Calling identified handler.`);
console.debug(`Command "${command}" received. Identified handler, calling identified handler.`);
(commandHandler.bind(this))(data);
} else {
console.debug(`Command "${command}" received. Calling default handler.`);
console.debug(`Command "${command}" received. Could not identify handler, calling default handler.`);
this.defaultHandler(data);
}
}
Expand Down
4 changes: 3 additions & 1 deletion src/types/global.d.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import { PlayerManager } from "chromecast-caf-receiver/cast.framework";
import { RepeatMode } from "../api/generated/models/repeat-mode";

export interface DeviceInfo {
deviceId: string | number,
Expand All @@ -20,7 +21,8 @@ declare global {
mediaManager: PlayerManager;
playlist: Array<any>;
currentPlaylistIndex: number;
repeatMode: "RepeatOne" | "RepeatAll" | "RepeatNone";
repeatMode: RepeatMode;
reportEventType: "repeatmodechange";
}
}

0 comments on commit f67b0c0

Please sign in to comment.