Prettified Code!

This commit is contained in:
markspolakovs 2020-04-19 16:33:34 +00:00 committed by GitHub Action
parent d72e4ec4d4
commit bcfd4004d7
30 changed files with 308 additions and 321 deletions

View file

@ -25,8 +25,8 @@
display: flex;
flex-direction: column;
height: 100%;
margin-left: .5%;
margin-right: .5%;
margin-left: 0.5%;
margin-right: 0.5%;
}
.sp {
@ -42,16 +42,15 @@
.sp-col {
display: flex;
overflow-y: scroll;
margin-left: .2vw;
margin-right: .2vw;
padding: .2vw;
margin-left: 0.2vw;
margin-right: 0.2vw;
padding: 0.2vw;
flex-direction: column;
flex-wrap: nowrap;
flex-grow: 1;
}
.sp-main-col{
.sp-main-col {
display: flex;
flex: 1;
justify-content: flex-end;
@ -66,7 +65,6 @@
.sidebar-toggle {
flex-grow: 0;
width: auto;
}
.sidebar-toggle .btn {
writing-mode: vertical-rl;
@ -109,7 +107,7 @@
}
.sp-track .aux {
background-color: #07F;
background-color: #07f;
}
.sp-track .ghost {
@ -120,7 +118,9 @@
background-color: #10c998 !important;
}
html, body, #root {
html,
body,
#root {
padding: 0;
margin: 0;
width: 100%;
@ -142,10 +142,10 @@ html, body, #root {
cursor: not-allowed;
}
.mediaButtons button{
.mediaButtons button {
width: 32%;
border-style: none;
margin: .5%;
margin: 0.5%;
padding: 2%;
}
@ -161,11 +161,10 @@ html, body, #root {
background-color: #db2c2c;
}
button{
button {
background-color: rgb(199, 199, 199);
}
/*.player div {
overflow-x: hidden;
}*/
@ -219,19 +218,20 @@ button{
display: block;
z-index: 5;
/* padding: 1px; */
}
.waveform .current, .waveform .remaining, .waveform .length {
.waveform .current,
.waveform .remaining,
.waveform .length {
font-weight: 800;
}
.waveform .remaining, .waveform .outro {
.waveform .remaining,
.waveform .outro {
right: 0;
position: absolute;
}
.waveform .intro, .waveform .outro, .waveform .length {
.waveform .intro,
.waveform .outro,
.waveform .length {
bottom: 0;
position: absolute;
}
@ -252,7 +252,7 @@ button{
height: 6vh !important;
}
.waveform .loading {
background: #CCCCFF;
background: #ccccff;
}
.bypass-click {
@ -261,30 +261,42 @@ button{
/* Flash class and keyframe animation */
.sp-ending-soon {
-webkit-animation: green-flash steps(1) 0.5s infinite;
animation: green-flash steps(1) 0.5s infinite;
-webkit-animation: green-flash steps(1) 0.5s infinite;
animation: green-flash steps(1) 0.5s infinite;
}
@-webkit-keyframes green-flash {
0% { }
50% { background-color: rgb(199, 255, 199); }
0% {
}
50% {
background-color: rgb(199, 255, 199);
}
}
@keyframes green-flash {
0% { }
50% { background-color: rgb(199, 255, 199); }
0% {
}
50% {
background-color: rgb(199, 255, 199);
}
}
/* Flash class and keyframe animation */
.sp-muted-player {
-webkit-animation: red-flash steps(1) 0.5s infinite;
animation: red-flash steps(1) 0.5s infinite;
-webkit-animation: red-flash steps(1) 0.5s infinite;
animation: red-flash steps(1) 0.5s infinite;
}
@-webkit-keyframes red-flash {
0% { }
50% { background-color: rgb(255, 199, 199); }
0% {
}
50% {
background-color: rgb(255, 199, 199);
}
}
@keyframes red-flash {
0% { }
50% { background-color: rgb(255, 199, 199); }
0% {
}
50% {
background-color: rgb(255, 199, 199);
}
}
.ReactModal__Overlay {
@ -300,4 +312,4 @@ button{
z-index: 9000;
pointer-events: none;
box-shadow: inset 0 0 3px 6px red;
}
}

View file

@ -33,7 +33,7 @@ const App: React.FC = () => {
currentUser,
userLoading,
currentTimeslot,
timeslotLoading
timeslotLoading,
} = useSelector((state: RootState) => state.session);
if (
@ -60,8 +60,8 @@ const App: React.FC = () => {
type="text"
placeholder="enter a timeslot id"
value={inputVal}
onChange={e => setInputVal(e.target.value)}
onKeyPress={e => enterKeyCont(e.key)}
onChange={(e) => setInputVal(e.target.value)}
onKeyPress={(e) => enterKeyCont(e.key)}
autoFocus
/>
<button onClick={cont}>Continue</button>

View file

@ -15,7 +15,7 @@ export async function apiRequest(
let req = null;
if (method === "GET") {
req = fetch(url + qs.stringify(params, { addQueryPrefix: true }), {
credentials: need_auth ? "include" : "omit"
credentials: need_auth ? "include" : "omit",
});
} else {
const body = JSON.stringify(params);
@ -24,9 +24,9 @@ export async function apiRequest(
method,
body,
headers: {
"Content-Type": "application/json; charset=UTF-8"
"Content-Type": "application/json; charset=UTF-8",
},
credentials: need_auth ? "include" : "omit"
credentials: need_auth ? "include" : "omit",
});
}
return await req;
@ -123,8 +123,8 @@ export function getShowplan(showId: number): Promise<Showplan> {
`/timeslot/${showId.toString(10)}/showplan`,
"GET",
{}
).then(res => {
return Object.keys(res).map(x => res[x]);
).then((res) => {
return Object.keys(res).map((x) => res[x]);
});
}
@ -136,11 +136,11 @@ function wrapPromise<T, TArgs>(factory: (...args: TArgs[]) => Promise<T>) {
read(...args: TArgs[]) {
if (!(suspender instanceof Promise)) {
suspender = factory(...args).then(
r => {
(r) => {
status = "success";
result = r;
},
e => {
(e) => {
status = "error";
result = e;
}
@ -155,7 +155,7 @@ function wrapPromise<T, TArgs>(factory: (...args: TArgs[]) => Promise<T>) {
} else {
throw new Error("Can't happen.");
}
}
},
};
}
@ -181,7 +181,7 @@ export function searchForTracks(
artist,
title,
limit: 100,
digitised: true
digitised: true,
});
}
@ -206,8 +206,8 @@ export function getAuxPlaylists(): Promise<Array<ManagedPlaylist>> {
export function loadAuxLibrary(libraryId: string): Promise<AuxItem[]> {
return apiRequest(MYRADIO_NON_API_BASE + "/NIPSWeb/load_aux_lib", "GET", {
libraryid: libraryId
}).then(res => res.json());
libraryid: libraryId,
}).then((res) => res.json());
}
export type UpdateOp =
@ -242,7 +242,7 @@ export function updateShowplan(
ops: UpdateOp[]
): Promise<OpResult[]> {
return myradioApiRequest(`/timeslot/${timeslotid}/updateshowplan`, "PUT", {
set: ops
set: ops,
});
}
@ -255,7 +255,7 @@ export interface Timeslot {
export function getCurrentApiTimeslot(): Promise<Timeslot> {
return myradioApiRequest(`/timeslot/userselectedtimeslot`, "GET", {}).then(
res => {
(res) => {
return res;
}
);
@ -270,7 +270,7 @@ export interface User {
}
export function getCurrentApiUser(): Promise<User> {
return myradioApiRequest(`/user/currentuser`, "GET", {}).then(res => {
return myradioApiRequest(`/user/currentuser`, "GET", {}).then((res) => {
return res;
});
}

View file

@ -8,7 +8,7 @@ export class RecordingStreamer extends Streamer {
super();
this.recorder = new MediaRecorder(stream);
this.chunks = [];
this.recorder.ondataavailable = e => {
this.recorder.ondataavailable = (e) => {
this.chunks.push(e.data);
};
this.recorder.onstart = () => {
@ -17,7 +17,7 @@ export class RecordingStreamer extends Streamer {
this.recorder.onstop = () => {
this.onStateChange("NOT_CONNECTED");
const finalData = new Blob(this.chunks, {
type: "audio/ogg; codecs=opus"
type: "audio/ogg; codecs=opus",
});
const url = URL.createObjectURL(finalData);
@ -26,7 +26,7 @@ export class RecordingStreamer extends Streamer {
a.download = "recorded.ogg";
a.click();
};
this.recorder.onerror = e => {
this.recorder.onerror = (e) => {
console.error(e.error);
this.onStateChange("CONNECTION_LOST");
};

View file

@ -32,7 +32,7 @@ export class WebRTCStreamer extends Streamer {
this.pc = new RTCPeerConnection({
iceServers: [
{
urls: ["stun:eu-turn4.xirsys.com"]
urls: ["stun:eu-turn4.xirsys.com"],
},
{
username:
@ -44,12 +44,12 @@ export class WebRTCStreamer extends Streamer {
"turn:eu-turn4.xirsys.com:80?transport=tcp",
"turn:eu-turn4.xirsys.com:3478?transport=tcp",
"turns:eu-turn4.xirsys.com:443?transport=tcp",
"turns:eu-turn4.xirsys.com:5349?transport=tcp"
]
}
]
"turns:eu-turn4.xirsys.com:5349?transport=tcp",
],
},
],
});
this.pc.oniceconnectionstatechange = e => {
this.pc.oniceconnectionstatechange = (e) => {
if (!this.pc) {
throw new Error(
"Received ICEConnectionStateChange but PC was null?????"
@ -58,16 +58,13 @@ export class WebRTCStreamer extends Streamer {
console.log("ICE Connection state change: " + this.pc.iceConnectionState);
this.onStateChange(this.mapStateToConnectionState());
};
this.stream.getAudioTracks().forEach(track => this.pc!.addTrack(track));
this.stream.getAudioTracks().forEach((track) => this.pc!.addTrack(track));
this.addConnectionStateListener(state => {
this.addConnectionStateListener((state) => {
if (state === "CONNECTED") {
this.newsInterval = later.setInterval(
this.doTheNews,
later.parse
.recur()
.on(59)
.minute()
later.parse.recur().on(59).minute()
);
} else if (state === "CONNECTION_LOST" || state === "NOT_CONNECTED") {
this.newsInterval?.clear();
@ -76,11 +73,11 @@ export class WebRTCStreamer extends Streamer {
console.log("PC created");
this.ws = new WebSocket(process.env.REACT_APP_WS_URL!);
this.ws.onopen = e => {
this.ws.onopen = (e) => {
console.log("WS open");
this.onStateChange(this.mapStateToConnectionState());
};
this.ws.onclose = e => {
this.ws.onclose = (e) => {
console.log("WS close");
this.onStateChange(this.mapStateToConnectionState());
};
@ -110,30 +107,14 @@ export class WebRTCStreamer extends Streamer {
// Sanity check
const now = new Date();
if (now.getSeconds() < 45) {
later.setTimeout(
async () => {
await MixerState.playNewsIntro();
},
later.parse
.recur()
.on(59)
.minute()
.on(45)
.second()
);
later.setTimeout(async () => {
await MixerState.playNewsIntro();
}, later.parse.recur().on(59).minute().on(45).second());
}
if (now.getMinutes() <= 1 && now.getSeconds() < 55) {
later.setTimeout(
async () => {
await MixerState.playNewsEnd();
},
later.parse
.recur()
.on(1)
.minute()
.on(55)
.second()
);
later.setTimeout(async () => {
await MixerState.playNewsEnd();
}, later.parse.recur().on(1).minute().on(55).second());
}
}
}
@ -157,7 +138,7 @@ export class WebRTCStreamer extends Streamer {
// Do some fun SDP fuckery to get better quality
const parsed = SdpTransform.parse(offer.sdp!);
console.log("Old SDP", parsed);
parsed.media.forEach(track => {
parsed.media.forEach((track) => {
let opusIndex = 0;
for (let i = 0; i < track.rtp.length; i++) {
if (track.rtp[i].codec === "opus") {
@ -165,9 +146,9 @@ export class WebRTCStreamer extends Streamer {
}
// TODO: maybe delete non-Opus candidates?
}
track.fmtp[opusIndex].config += `; maxaveragebitrate=${192 *
2 *
1024}; stereo=1; sprop-stereo=1 ; cbr=1`;
track.fmtp[opusIndex].config += `; maxaveragebitrate=${
192 * 2 * 1024
}; stereo=1; sprop-stereo=1 ; cbr=1`;
});
offer.sdp = SdpTransform.write(parsed);
@ -179,7 +160,7 @@ export class WebRTCStreamer extends Streamer {
JSON.stringify({
kind: "OFFER",
type: this.pc.localDescription!.type,
sdp: this.pc.localDescription!.sdp
sdp: this.pc.localDescription!.sdp,
})
);
this.state = "OFFER";
@ -190,7 +171,7 @@ export class WebRTCStreamer extends Streamer {
}
const answer = new RTCSessionDescription({
type: data.type,
sdp: data.sdp
sdp: data.sdp,
});
await this.pc.setRemoteDescription(answer);
this.state = "ANSWER";
@ -226,7 +207,7 @@ export class WebRTCStreamer extends Streamer {
// TODO: supporting trickle ICE would be nICE
waitForIceCandidates() {
return new Promise(resolve => {
return new Promise((resolve) => {
if (!this.pc) {
throw new Error(
"Tried to gather ICE Candidates with a null PeerConnection!"

View file

@ -45,7 +45,7 @@ const broadcastState = createSlice({
autoNewsEnd: true,
liveForThePurposesOfTracklisting: false,
connectionState: "NOT_CONNECTED",
recordingState: "NOT_CONNECTED"
recordingState: "NOT_CONNECTED",
} as BroadcastState,
reducers: {
changeSetting<K extends keyof BroadcastState>(
@ -76,8 +76,8 @@ const broadcastState = createSlice({
},
setRecordingState(state, action: PayloadAction<ConnectionStateEnum>) {
state.recordingState = action.payload;
}
}
},
},
});
export default broadcastState.reducer;
@ -85,7 +85,7 @@ export default broadcastState.reducer;
export const {
toggleTracklisting,
setTracklisting,
setWsID
setWsID,
} = broadcastState.actions;
export interface TrackListItem {
@ -107,7 +107,7 @@ export const registerForShow = (): AppThunk => async (dispatch, getState) => {
NavbarState.showAlert({
color: "warning",
content: "You are not WebStudio Trained and cannot go live.",
closure: 7000
closure: 7000,
})
);
return;
@ -139,7 +139,7 @@ export const registerForShow = (): AppThunk => async (dispatch, getState) => {
NavbarState.showAlert({
content: e.message,
color: "danger",
closure: 10000
closure: 10000,
})
);
if (streamer) {
@ -168,7 +168,7 @@ export const cancelTimeslot = (): AppThunk => async (dispatch, getState) => {
NavbarState.showAlert({
content: e.message,
color: "danger",
closure: 10000
closure: 10000,
})
);
} else {
@ -203,7 +203,7 @@ export function sendBroadcastRegister(
memberid: memberid,
timeslotid: timeslotid,
sourceid: sourceid,
wsid: wsID
wsid: wsID,
} as any;
return broadcastApiRequest("/registerTimeslot", "POST", payload);
}
@ -211,7 +211,7 @@ export function sendBroadcastCancel(
connid: number | null
): Promise<string | null> {
return broadcastApiRequest("/cancelTimeslot", "POST", {
connid: connid
connid: connid,
});
}
@ -227,7 +227,7 @@ export function sendBroadcastChange(
sourceid: sourceid,
beginning: beginning,
middle: middle,
end: end
end: end,
});
}
@ -286,7 +286,7 @@ export function sendTracklistStart(trackid: number): Promise<TrackListItem> {
return myradioApiRequest("/tracklistItem", "POST", {
trackid: trackid,
sourceid: "w",
state: "c"
state: "c",
});
}
@ -296,14 +296,14 @@ export const goOnAir = (): AppThunk => async (dispatch, getState) => {
NavbarState.showAlert({
color: "warning",
content: "You are not WebStudio Trained and cannot go live.",
closure: 7000
closure: 7000,
})
);
return;
}
console.log("starting streamer.");
streamer = new WebRTCStreamer(MixerState.destination.stream, dispatch);
streamer.addConnectionStateListener(state => {
streamer.addConnectionStateListener((state) => {
dispatch(broadcastState.actions.setConnectionState(state));
if (state === "CONNECTION_LOST") {
// un-register if we drop, let the user manually reconnect
@ -316,7 +316,7 @@ export const goOnAir = (): AppThunk => async (dispatch, getState) => {
await streamer.start();
};
export const stopStreaming = (): AppThunk => async dispatch => {
export const stopStreaming = (): AppThunk => async (dispatch) => {
if (streamer) {
await streamer.stop();
streamer = null;
@ -327,15 +327,15 @@ export const stopStreaming = (): AppThunk => async dispatch => {
let recorder: RecordingStreamer;
export const startRecording = (): AppThunk => async dispatch => {
export const startRecording = (): AppThunk => async (dispatch) => {
recorder = new RecordingStreamer(MixerState.destination.stream);
recorder.addConnectionStateListener(state => {
recorder.addConnectionStateListener((state) => {
dispatch(broadcastState.actions.setRecordingState(state));
});
await recorder.start();
};
export const stopRecording = (): AppThunk => async dispatch => {
export const stopRecording = (): AppThunk => async (dispatch) => {
if (recorder) {
await recorder.stop();
} else {

View file

@ -20,6 +20,6 @@ export abstract class Streamer {
}
protected onStateChange(state: ConnectionStateEnum) {
this.csListeners.forEach(l => l(state));
this.csListeners.forEach((l) => l(state));
}
}

View file

@ -1,13 +1,13 @@
body {
margin: 0;
font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', 'Roboto', 'Oxygen',
'Ubuntu', 'Cantarell', 'Fira Sans', 'Droid Sans', 'Helvetica Neue',
font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", "Roboto", "Oxygen",
"Ubuntu", "Cantarell", "Fira Sans", "Droid Sans", "Helvetica Neue",
sans-serif;
-webkit-font-smoothing: antialiased;
-moz-osx-font-smoothing: grayscale;
}
code {
font-family: source-code-pro, Menlo, Monaco, Consolas, 'Courier New',
font-family: source-code-pro, Menlo, Monaco, Consolas, "Courier New",
monospace;
}

View file

@ -20,9 +20,9 @@ export async function createLoudnessMeasurement(
await input.context.audioWorklet.addModule(workletUrl);
const processor = new AudioWorkletNode(input.context, "loudness-processor", {
numberOfInputs: 1,
numberOfOutputs: 0
numberOfOutputs: 0,
});
processor.port.onmessage = evt => {
processor.port.onmessage = (evt) => {
callback(evt.data);
};
input.connect(processor);

View file

@ -34,7 +34,7 @@ class DBFSPeakProcessor extends AudioWorkletProcessor {
}
this.port.postMessage({
peak,
loudness: -Infinity // TODO
loudness: -Infinity, // TODO
});
return true;
}
@ -85,7 +85,7 @@ class PPMPeakProcessor extends AudioWorkletProcessor {
this.calcIntermediate(inputs[0]);
this.port.postMessage({
peak: this.convert(this.intermediateValue[0]),
loudness: this.intermediateValue[0]
loudness: this.intermediateValue[0],
});
return true;
}

View file

@ -2,7 +2,7 @@ import {
createSlice,
PayloadAction,
Dispatch,
Middleware
Middleware,
} from "@reduxjs/toolkit";
import fetchProgress, { FetchProgressData } from "fetch-progress";
import Between from "between.js";
@ -127,7 +127,7 @@ const mixerState = createSlice({
autoAdvance: true,
repeat: "none",
tracklistItemID: -1,
loadError: false
loadError: false,
},
{
loadedItem: null,
@ -144,7 +144,7 @@ const mixerState = createSlice({
autoAdvance: true,
repeat: "none",
tracklistItemID: -1,
loadError: false
loadError: false,
},
{
loadedItem: null,
@ -161,8 +161,8 @@ const mixerState = createSlice({
autoAdvance: true,
repeat: "none",
tracklistItemID: -1,
loadError: false
}
loadError: false,
},
],
mic: {
open: false,
@ -171,8 +171,8 @@ const mixerState = createSlice({
baseGain: 1,
openError: null,
id: "None",
calibration: false
}
calibration: false,
},
} as MixerState,
reducers: {
loadItem(
@ -254,7 +254,7 @@ const mixerState = createSlice({
state.players[action.payload.player].timeRemaining = timeRemaining;
},
updateTimeEndingAt(state) {
state.players.forEach(player => {
state.players.forEach((player) => {
let date = new Date();
date.setSeconds(date.getSeconds() + player.timeRemaining);
player.timeEndingAt = date.toLocaleString("en-GB").split(" ")[1];
@ -323,8 +323,8 @@ const mixerState = createSlice({
},
stopMicCalibration(state) {
state.mic.calibration = false;
}
}
},
},
});
export default mixerState.reducer;
@ -384,8 +384,8 @@ export const load = (
backend: "MediaElementWebAudio",
responsive: true,
xhr: {
credentials: "include"
} as any
credentials: "include",
} as any,
});
wavesurfer.on("ready", () => {
@ -393,13 +393,13 @@ export const load = (
dispatch(
mixerState.actions.setTimeLength({
player,
time: wavesurfer.getDuration()
time: wavesurfer.getDuration(),
})
);
dispatch(
mixerState.actions.setTimeCurrent({
player,
time: 0
time: 0,
})
);
dispatch(updateTimeEnding());
@ -415,7 +415,7 @@ export const load = (
dispatch(
mixerState.actions.setPlayerState({
player,
state: wavesurfer.getCurrentTime() === 0 ? "stopped" : "paused"
state: wavesurfer.getCurrentTime() === 0 ? "stopped" : "paused",
})
);
});
@ -423,7 +423,7 @@ export const load = (
dispatch(
mixerState.actions.setTimeCurrent({
player,
time: wavesurfer.getCurrentTime()
time: wavesurfer.getCurrentTime(),
})
);
});
@ -439,7 +439,7 @@ export const load = (
if ("channel" in item) {
// it's not in the CML/libraries "column"
const itsChannel = getState().showplan.plan!.filter(
x => x.channel === item.channel
(x) => x.channel === item.channel
);
const itsIndex = itsChannel.indexOf(item);
if (itsIndex === itsChannel.length - 1) {
@ -450,7 +450,7 @@ export const load = (
if ("channel" in item) {
// it's not in the CML/libraries "column"
const itsChannel = getState().showplan.plan!.filter(
x => x.channel === item.channel
(x) => x.channel === item.channel
);
const itsIndex = itsChannel.indexOf(item);
if (itsIndex > -1 && itsIndex !== itsChannel.length - 1) {
@ -469,7 +469,7 @@ export const load = (
dispatch(
mixerState.actions.setTimeCurrent({
player,
time: wavesurfer.getCurrentTime()
time: wavesurfer.getCurrentTime(),
})
);
}
@ -479,7 +479,7 @@ export const load = (
const signal = loadAbortControllers[player].signal; // hang on to the signal, even if its controller gets replaced
const result = await fetch(url, {
credentials: "include",
signal
signal,
}).then(
fetchProgress({
// implement onProgress method
@ -490,7 +490,7 @@ export const load = (
mixerState.actions.itemLoadPercentage({ player, percent })
);
}
}
},
})
);
const rawData = await result.arrayBuffer();
@ -524,17 +524,11 @@ export const load = (
}
};
export const updateTimeEnding = (): AppThunk => async dispatch => {
export const updateTimeEnding = (): AppThunk => async (dispatch) => {
if (!timerInterval) {
timerInterval = later.setInterval(
() => {
dispatch(mixerState.actions.updateTimeEndingAt());
},
later.parse
.recur()
.every(1)
.second()
);
timerInterval = later.setInterval(() => {
dispatch(mixerState.actions.updateTimeEndingAt());
}, later.parse.recur().every(1).second());
}
};
@ -606,11 +600,11 @@ export const stop = (player: number): AppThunk => (dispatch, getState) => {
export const {
toggleAutoAdvance,
togglePlayOnLoad,
toggleRepeat
toggleRepeat,
} = mixerState.actions;
export const redrawWavesurfers = (): AppThunk => () => {
wavesurfers.forEach(function(item) {
wavesurfers.forEach(function (item) {
item.drawBuffer();
});
};
@ -648,7 +642,7 @@ export const setVolume = (
// If we've just hit the button/key to go to the same value as that fade,
// stop it and immediately cut to the target value.
// Otherwise, stop id and start a new fade.
playerGainTweens[player].tweens.forEach(tween => tween.pause());
playerGainTweens[player].tweens.forEach((tween) => tween.pause());
if (playerGainTweens[player].target === level) {
delete playerGainTweens[player];
dispatch(mixerState.actions.setPlayerVolume({ player, volume: uiLevel }));
@ -682,7 +676,7 @@ export const setVolume = (
playerGainTweens[player] = {
target: level,
tweens: [volumeTween, gainTween]
tweens: [volumeTween, gainTween],
};
};
@ -712,8 +706,8 @@ export const openMicrophone = (micID: string): AppThunk => async (
echoCancellation: false,
autoGainControl: false,
noiseSuppression: false,
latency: 0.01
}
latency: 0.01,
},
});
} catch (e) {
if (e instanceof DOMException) {
@ -758,9 +752,9 @@ export const openMicrophone = (micID: string): AppThunk => async (
}
};
export const setMicVolume = (
level: MicVolumePresetEnum
): AppThunk => dispatch => {
export const setMicVolume = (level: MicVolumePresetEnum): AppThunk => (
dispatch
) => {
// no tween fuckery here, just cut the level
const levelVal = level === "full" ? 1 : 0;
// actually, that's a lie - if we're turning it off we delay it a little to compensate for
@ -832,11 +826,9 @@ export const stopMicCalibration = (): AppThunk => (dispatch, getState) => {
dispatch(mixerState.actions.stopMicCalibration());
};
export const mixerMiddleware: Middleware<
{},
RootState,
Dispatch<any>
> = store => next => action => {
export const mixerMiddleware: Middleware<{}, RootState, Dispatch<any>> = (
store
) => (next) => (action) => {
const oldState = store.getState().mixer;
const result = next(action);
const newState = store.getState().mixer;
@ -863,7 +855,7 @@ export const mixerKeyboardShortcutsMiddleware: Middleware<
{},
RootState,
Dispatch<any>
> = store => {
> = (store) => {
Keys("q", () => {
store.dispatch(play(0));
});
@ -925,5 +917,5 @@ export const mixerKeyboardShortcutsMiddleware: Middleware<
store.dispatch(setMicVolume(state.volume === 1 ? "off" : "full"));
});
return next => action => next(action);
return (next) => (action) => next(action);
};

View file

@ -2,44 +2,45 @@
* Taken from http://stackoverflow.com/a/36289507/995325 */
@media (max-width: 991px) {
.navbar-header {
float: none;
float: none;
}
.navbar-left, .navbar-right {
float: none !important;
.navbar-left,
.navbar-right {
float: none !important;
}
.navbar-toggle {
display: block;
display: block;
}
.navbar-collapse {
border-top: 1px solid transparent;
box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.1);
border-top: 1px solid transparent;
box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.1);
}
.navbar-fixed-top {
top: 0;
border-width: 0 0 1px;
top: 0;
border-width: 0 0 1px;
}
.navbar-collapse.collapse {
display: none !important;
display: none !important;
}
.navbar-nav {
float: none !important;
margin-top: 7.5px;
float: none !important;
margin-top: 7.5px;
}
.navbar-nav > li {
float: none;
float: none;
}
.navbar-nav > li > a {
padding-top: 10px;
padding-bottom: 10px;
padding-top: 10px;
padding-bottom: 10px;
}
.collapse.in {
display: block !important;
display: block !important;
}
}
/** MyRadio bootstrap navbar overides taken from http://work.smarchal.com/twbscolor/css/2D425F2D425Fffffffe1e1e11 **/
.navbar-ury {
background-color: #2D333C;
border-color: #2D425F;
background-color: #2d333c;
border-color: #2d425f;
border: none;
height: 60px;
max-height: 7vh;
@ -47,9 +48,8 @@
.navbar-ury .navbar-brand {
color: #ffffff;
padding: 10px 15px; /** added to center the logo **/
line-height: 30px; /** added to center the logo **/
line-height: 30px; /** added to center the logo **/
margin-right: 0;
}
.navbar-ury .navbar-brand img {
max-height: 100%;
@ -90,10 +90,10 @@
.navbar-ury .navbar-nav > li > a:hover,
.navbar-ury .navbar-nav > li > a:focus {
color: #e1e1e1;
background-color: #2D425F;
background-color: #2d425f;
}
.navbar-ury .navbar-nav > li > .dropdown-menu {
background-color: #2D333C;
background-color: #2d333c;
border-top: none;
}
.navbar-ury .navbar-nav > li > .dropdown-menu > a {
@ -102,35 +102,35 @@
.navbar-ury .navbar-nav > li > .dropdown-menu > a:hover,
.navbar-ury .navbar-nav > li > .dropdown-menu > a:focus {
color: #e1e1e1;
background-color: #2D425F;
background-color: #2d425f;
}
.navbar-ury .navbar-nav > li > .dropdown-menu > .divider {
background-color: #2D425F;
background-color: #2d425f;
}
.navbar-ury .navbar-nav .open .dropdown-menu > .active > a,
.navbar-ury .navbar-nav .open .dropdown-menu > .active > a:hover,
.navbar-ury .navbar-nav .open .dropdown-menu > .active > a:focus {
color: #e1e1e1;
background-color: #2D333C;
background-color: #2d333c;
}
.navbar-ury .navbar-nav > .active > a,
.navbar-ury .navbar-nav > .active > a:hover,
.navbar-ury .navbar-nav > .active > a:focus {
color: #e1e1e1;
background-color: #2D333C;
background-color: #2d333c;
}
.navbar-ury .navbar-nav > .open > a,
.navbar-ury .navbar-nav > .open > a:hover,
.navbar-ury .navbar-nav > .open > a:focus {
color: #e1e1e1;
background-color: #2D425F !important;
background-color: #2d425f !important;
}
.navbar-ury .navbar-toggle {
border-color: #2D425F;
border-color: #2d425f;
}
.navbar-ury .navbar-toggle:hover,
.navbar-ury .navbar-toggle:focus {
background-color: #2D425F;
background-color: #2d425f;
}
.navbar-ury .navbar-toggle .icon-bar {
background-color: #ffffff;
@ -147,7 +147,7 @@
}
.navbar-ury .navbar-brand:hover {
color: #e1e1e1;
background-color: #2D425F !important;
background-color: #2d425f !important;
}
@media (max-width: 767px) {
@ -162,22 +162,22 @@
.navbar-ury .navbar-nav .open .dropdown-menu > .active > a:hover,
.navbar-ury .navbar-nav .open .dropdown-menu > .active > a:focus {
color: #e1e1e1;
background-color: #2D425F;
background-color: #2d425f;
}
}
.alertbar {
position: fixed !important;
top: 0;
left: 0;
width: 100vw;
min-height: 38.5px;
z-index: 99999;
transform: translateY(-50px);
transition: 400ms transform;
&.visible {
transform: translateY(0);
}
position: fixed !important;
top: 0;
left: 0;
width: 100vw;
min-height: 38.5px;
z-index: 99999;
transform: translateY(-50px);
transition: 400ms transform;
&.visible {
transform: translateY(0);
}
}
#timelord {
@ -194,4 +194,4 @@
#timelord .time {
font-weight: bold;
font-size: 1.1em;
}
}

View file

@ -21,7 +21,7 @@ interface NavbarState {
const navbarState = createSlice({
name: "navbar",
initialState: {
currentAlert: null
currentAlert: null,
} as NavbarState,
reducers: {
showAlert(state, action: PayloadAction<Alert>) {
@ -29,8 +29,8 @@ const navbarState = createSlice({
},
closeAlert(state) {
state.currentAlert = null;
}
}
},
},
});
export default navbarState.reducer;

View file

@ -4,7 +4,7 @@ import logo from "../assets/images/webstudio.svg";
import {
MYRADIO_BASE_URL,
MYRADIO_NON_API_BASE,
BROADCAST_API_BASE_URL
BROADCAST_API_BASE_URL,
} from "../api";
export function AboutTab() {

View file

@ -22,7 +22,7 @@ export function AdvancedTab() {
className="form-control"
id="broadcastSourceSelect"
value={broadcastState.sourceID}
onChange={e =>
onChange={(e) =>
dispatch(
changeBroadcastSetting("sourceID", parseInt(e.target.value))
)
@ -39,7 +39,7 @@ export function AdvancedTab() {
className="form-check-input"
type="checkbox"
checked={broadcastState.autoNewsBeginning}
onChange={e =>
onChange={(e) =>
dispatch(
changeBroadcastSetting("autoNewsBeginning", e.target.checked)
)
@ -52,7 +52,7 @@ export function AdvancedTab() {
className="form-check-input"
type="checkbox"
checked={broadcastState.autoNewsMiddle}
onChange={e =>
onChange={(e) =>
dispatch(changeBroadcastSetting("autoNewsMiddle", e.target.checked))
}
/>
@ -65,7 +65,7 @@ export function AdvancedTab() {
className="form-check-input"
type="checkbox"
checked={broadcastState.autoNewsEnd}
onChange={e =>
onChange={(e) =>
dispatch(changeBroadcastSetting("autoNewsEnd", e.target.checked))
}
/>
@ -81,12 +81,12 @@ export function AdvancedTab() {
className="form-control"
id="broadcastSourceSelect"
value={settings.tracklist}
onChange={e =>
onChange={(e) =>
dispatch(
changeSetting({
key: "tracklist",
// @ts-ignore
val: e.target.value
val: e.target.value,
})
)
}
@ -101,11 +101,11 @@ export function AdvancedTab() {
className="form-check-input"
type="checkbox"
checked={settings.showDebugInfo}
onChange={e =>
onChange={(e) =>
dispatch(
changeSetting({
key: "showDebugInfo",
val: e.target.checked
val: e.target.checked,
})
)
}
@ -119,11 +119,11 @@ export function AdvancedTab() {
className="form-check-input"
type="checkbox"
checked={settings.enableRecording}
onChange={e =>
onChange={(e) =>
dispatch(
changeSetting({
key: "enableRecording",
val: e.target.checked
val: e.target.checked,
})
)
}

View file

@ -13,7 +13,7 @@ type MicErrorEnum =
function reduceToInputs(devices: MediaDeviceInfo[]) {
var temp: MediaDeviceInfo[] = [];
devices.forEach(device => {
devices.forEach((device) => {
if (device.kind === "audioinput") {
temp.push(device);
}
@ -91,11 +91,11 @@ export function MicTab() {
className="form-control"
style={{ width: "100%" }}
value={nextMicSource}
onChange={e => setMicSource(e.target.value)}
onChange={(e) => setMicSource(e.target.value)}
disabled={micList === null}
>
<option value={"$NONE"} disabled label="Choose a microphone" />
{(micList || []).map(function(e, i) {
{(micList || []).map(function (e, i) {
return (
<option value={e.deviceId} key={i}>
{e.label !== "" ? e.label : e.deviceId}
@ -138,7 +138,7 @@ export function MicTab() {
max={3}
step={0.05}
value={state.baseGain}
onChange={e =>
onChange={(e) =>
dispatch(MixerState.setMicBaseGain(parseFloat(e.target.value)))
}
/>

View file

@ -34,15 +34,15 @@ export function StatsTab() {
}
return (
<>
{Array.from(stats).map(stat => (
{Array.from(stats).map((stat) => (
<div key={stat[1].id}>
<h2>Report: {stat[1].type}</h2>
<div>
<strong>ID:</strong> {stat[1].id}
</div>
{Object.keys(stat[1])
.filter(x => x !== "id" && x !== "type" && x !== "timestamp")
.map(key => (
.filter((x) => x !== "id" && x !== "type" && x !== "timestamp")
.map((key) => (
<div key={key}>
<strong>{key}</strong>: {stat[1][key]}
</div>

View file

@ -11,7 +11,7 @@ const settingsState = createSlice({
initialState: {
showDebugInfo: false,
enableRecording: false,
tracklist: "while_live"
tracklist: "while_live",
} as Settings,
reducers: {
changeSetting<K extends keyof Settings>(
@ -19,8 +19,8 @@ const settingsState = createSlice({
action: PayloadAction<{ key: K; val: Settings[K] }>
) {
state[action.payload.key] = action.payload.val;
}
}
},
},
});
export default settingsState.reducer;

View file

@ -2,7 +2,7 @@ import {
createSlice,
PayloadAction,
Middleware,
Dispatch
Dispatch,
} from "@reduxjs/toolkit";
import { RootState } from "../rootReducer";
@ -14,7 +14,7 @@ const optionsMenuState = createSlice({
name: "optionsMenu",
initialState: {
open: false,
currentTab: "mic" as OptionsTabIDsEnum
currentTab: "mic" as OptionsTabIDsEnum,
},
reducers: {
open(state) {
@ -29,19 +29,17 @@ const optionsMenuState = createSlice({
},
changeTab(state, action: PayloadAction<OptionsTabIDsEnum>) {
state.currentTab = action.payload;
}
}
},
},
});
export default optionsMenuState.reducer;
export const { open, openToTab, close, changeTab } = optionsMenuState.actions;
export const tabSyncMiddleware: Middleware<
{},
RootState,
Dispatch
> = store => next => action => {
export const tabSyncMiddleware: Middleware<{}, RootState, Dispatch> = (
store
) => (next) => (action) => {
const oldState = store.getState();
const result = next(action);
const newState = store.getState();

View file

@ -19,7 +19,7 @@ const rootReducer = combineReducers({
session: sessionReducer,
navbar: NavbarReducer,
optionsMenu: OptionsMenuReducer,
settings: SettingsState
settings: SettingsState,
});
export type RootState = ReturnType<typeof rootReducer>;
@ -28,7 +28,7 @@ const persistenceConfig: PersistConfig<RootState> = {
key: "root",
storage: webStorage,
whitelist: ["settings"],
stateReconciler: autoMergeLevel2
stateReconciler: autoMergeLevel2,
};
const persistedReducer = persistReducer(persistenceConfig, rootReducer);

View file

@ -68,7 +68,7 @@ export function register(config?: Config) {
function registerValidSW(swUrl: string, config?: Config) {
navigator.serviceWorker
.register(swUrl)
.then(registration => {
.then((registration) => {
registration.onupdatefound = () => {
const installingWorker = registration.installing;
if (installingWorker == null) {
@ -85,7 +85,7 @@ function registerValidSW(swUrl: string, config?: Config) {
color: "info",
closure: 10000,
content:
"A new version of WebStudio is available! Please close and reopen all WebStudio tabs to use it."
"A new version of WebStudio is available! Please close and reopen all WebStudio tabs to use it.",
})
);
@ -108,7 +108,7 @@ function registerValidSW(swUrl: string, config?: Config) {
};
};
})
.catch(error => {
.catch((error) => {
console.error("Error during service worker registration:", error);
});
}
@ -116,7 +116,7 @@ function registerValidSW(swUrl: string, config?: Config) {
function checkValidServiceWorker(swUrl: string, config?: Config) {
// Check if the service worker can be found. If it can't reload the page.
fetch(swUrl)
.then(response => {
.then((response) => {
// Ensure service worker exists, and that we really are getting a JS file.
const contentType = response.headers.get("content-type");
if (
@ -124,7 +124,7 @@ function checkValidServiceWorker(swUrl: string, config?: Config) {
(contentType != null && contentType.indexOf("javascript") === -1)
) {
// No service worker found. Probably a different app. Reload the page.
navigator.serviceWorker.ready.then(registration => {
navigator.serviceWorker.ready.then((registration) => {
registration.unregister().then(() => {
window.location.reload();
});
@ -140,7 +140,7 @@ function checkValidServiceWorker(swUrl: string, config?: Config) {
color: "secondary",
closure: 5000,
content:
"No internet connection available. WebStudio is running in offline mode."
"No internet connection available. WebStudio is running in offline mode.",
})
);
});
@ -148,7 +148,7 @@ function checkValidServiceWorker(swUrl: string, config?: Config) {
export function unregister() {
if ("serviceWorker" in navigator) {
navigator.serviceWorker.ready.then(registration => {
navigator.serviceWorker.ready.then((registration) => {
registration.unregister();
});
}

View file

@ -5,7 +5,7 @@ import { MYRADIO_NON_API_BASE } from "../api";
import { useSelector, useDispatch } from "react-redux";
import { RootState } from "../rootReducer";
const SessionHandler: React.FC = function() {
const SessionHandler: React.FC = function () {
const dispatch = useDispatch();
useEffect(() => {
@ -38,7 +38,7 @@ const SessionHandler: React.FC = function() {
userLoading,
userLoadError,
timeslotLoading,
timeslotLoadError
timeslotLoadError,
} = useSelector((state: RootState) => state.session);
var redirect_url = encodeURIComponent(window.location.toString());

View file

@ -5,7 +5,7 @@ import {
getCurrentApiUser,
Timeslot,
getCurrentApiTimeslot,
doesCurrentUserHavePermission
doesCurrentUserHavePermission,
} from "../api";
import raygun from "raygun4js";
@ -31,7 +31,7 @@ const sessionState = createSlice({
userLoading: false,
userLoadError: null,
timeslotLoading: false,
timeslotLoadError: null
timeslotLoadError: null,
} as sessionState,
reducers: {
setCurrentUser(
@ -67,8 +67,8 @@ const sessionState = createSlice({
},
getState(state) {
return state;
}
}
},
},
});
export default sessionState.reducer;
@ -77,17 +77,17 @@ export const getCurrentUser = (): AppThunk => async (dispatch, getState) => {
return getState().session.currentUser;
};
export const getUser = (): AppThunk => async dispatch => {
export const getUser = (): AppThunk => async (dispatch) => {
dispatch(sessionState.actions.getUserStarting());
try {
const [user, canBroadcast] = await Promise.all([
getCurrentApiUser(),
doesCurrentUserHavePermission(BROADCAST_PERMISSION_ID)
doesCurrentUserHavePermission(BROADCAST_PERMISSION_ID),
]);
raygun("setUser", {
identifier: user.memberid.toString(10),
firstName: user.fname,
fullName: user.fname + " " + user.sname
fullName: user.fname + " " + user.sname,
});
dispatch(sessionState.actions.setCurrentUser({ user, canBroadcast }));
} catch (e) {
@ -96,7 +96,7 @@ export const getUser = (): AppThunk => async dispatch => {
}
};
export const getTimeslot = (): AppThunk => async dispatch => {
export const getTimeslot = (): AppThunk => async (dispatch) => {
dispatch(sessionState.actions.getTimeslotStarting());
try {
const timeslot = await getCurrentApiTimeslot();

View file

@ -13,7 +13,7 @@ export const TS_ITEM_MENU_ID = "SongMenu";
export const Item = memo(function Item({
item: x,
index,
column
column,
}: {
item: PlanItem | Track | AuxItem;
index: number;

View file

@ -5,7 +5,7 @@ import { Button } from "reactstrap";
export function PisModal({
close,
isOpen
isOpen,
}: {
close: () => any;
isOpen: boolean;

View file

@ -6,7 +6,7 @@ import {
FaRedo,
FaPlay,
FaPause,
FaStop
FaStop,
} from "react-icons/fa";
import { RootState } from "../rootReducer";
import * as MixerState from "../mixer/state";
@ -168,7 +168,7 @@ export function Player({ id }: { id: number }) {
style={
playerState.loading !== -1
? {
width: playerState.loading * 100 + "%"
width: playerState.loading * 100 + "%",
}
: {}
}
@ -190,7 +190,7 @@ export function Player({ id }: { id: number }) {
width:
(USE_REAL_GAIN_VALUE ? playerState.gain : playerState.volume) *
100 +
"%"
"%",
}}
></div>
<button onClick={() => dispatch(MixerState.setVolume(id, "off"))}>

View file

@ -9,7 +9,7 @@ import {
Droppable,
DragDropContext,
DropResult,
ResponderProvided
ResponderProvided,
} from "react-beautiful-dnd";
import { useSelector, useDispatch } from "react-redux";
@ -21,7 +21,7 @@ import {
moveItem,
addItem,
removeItem,
getPlaylists
getPlaylists,
} from "./state";
import * as MixerState from "../mixer/state";
@ -31,7 +31,7 @@ import {
CentralMusicLibrary,
CML_CACHE,
AuxLibrary,
AUX_CACHE
AUX_CACHE,
} from "./libraries";
import { Player } from "./Player";
@ -54,7 +54,7 @@ function Column({ id, data }: { id: number; data: PlanItem[] }) {
{typeof data[id] === "undefined"
? null
: data
.filter(x => x.channel === id)
.filter((x) => x.channel === id)
.sort((a, b) => a.weight - b.weight)
.map((x, index) => (
<Item
@ -91,20 +91,20 @@ function LibraryColumn() {
className="form-control"
style={{ width: "100%" }}
value={sauce}
onChange={e => setSauce(e.target.value)}
onChange={(e) => setSauce(e.target.value)}
>
<option value={"None"} disabled>
Choose a library
</option>
<option value={"CentralMusicLibrary"}>Central Music Library</option>
<option disabled>Personal Resources</option>
{userPlaylists.map(playlist => (
{userPlaylists.map((playlist) => (
<option key={playlist.managedid} value={playlist.managedid}>
{playlist.title}
</option>
))}
<option disabled>Shared Resources</option>
{auxPlaylists.map(playlist => (
{auxPlaylists.map((playlist) => (
<option
key={"aux-" + playlist.managedid}
value={"aux-" + playlist.managedid}
@ -140,7 +140,7 @@ function MicControl() {
<div
className="sp-mixer-buttons-backdrop"
style={{
width: state.volume * 100 + "%"
width: state.volume * 100 + "%",
}}
></div>
<button onClick={() => dispatch(MixerState.setMicVolume("off"))}>
@ -171,13 +171,15 @@ function incrReducer(state: number, action: any) {
return state + 1;
}
const Showplanner: React.FC<{ timeslotId: number }> = function({ timeslotId }) {
const Showplanner: React.FC<{ timeslotId: number }> = function ({
timeslotId,
}) {
const {
plan: showplan,
planLoadError,
planLoading,
planSaveError,
planSaving
planSaving,
} = useSelector((state: RootState) => state.showplan);
const session = useSelector((state: RootState) => state.session);
@ -189,7 +191,7 @@ const Showplanner: React.FC<{ timeslotId: number }> = function({ timeslotId }) {
const dispatch = useDispatch();
useBeforeunload(event => event.preventDefault());
useBeforeunload((event) => event.preventDefault());
useEffect(() => {
dispatch(getShowplan(timeslotId));
@ -200,7 +202,7 @@ const Showplanner: React.FC<{ timeslotId: number }> = function({ timeslotId }) {
if (element) {
element.classList.toggle("active");
}
setTimeout(function() {
setTimeout(function () {
dispatch(MixerState.redrawWavesurfers());
}, 500);
}
@ -224,7 +226,7 @@ const Showplanner: React.FC<{ timeslotId: number }> = function({ timeslotId }) {
timeslotitemid: "I" + insertIndex,
channel: parseInt(result.destination.droppableId, 10),
weight: result.destination.index,
...data
...data,
};
dispatch(addItem(timeslotId, newItem));
increment(null);
@ -238,7 +240,7 @@ const Showplanner: React.FC<{ timeslotId: number }> = function({ timeslotId }) {
channel: parseInt(result.destination.droppableId, 10),
weight: result.destination.index,
clean: true,
...data
...data,
} as any;
dispatch(addItem(timeslotId, newItem));
increment(null);
@ -247,7 +249,7 @@ const Showplanner: React.FC<{ timeslotId: number }> = function({ timeslotId }) {
dispatch(
moveItem(timeslotId, result.draggableId, [
parseInt(result.destination.droppableId, 10),
result.destination.index
result.destination.index,
])
);
}

View file

@ -29,13 +29,13 @@ export function CentralMusicLibrary() {
}
setItems([]);
setState("searching");
searchForTracks(artist, track).then(tracks => {
searchForTracks(artist, track).then((tracks) => {
if (tracks.length === 0) {
setState("no-results");
} else {
setState("results");
}
tracks.forEach(track => {
tracks.forEach((track) => {
const id = itemId(track);
if (!(id in CML_CACHE)) {
CML_CACHE[id] = track;
@ -51,14 +51,14 @@ export function CentralMusicLibrary() {
type="text"
placeholder="Filter by track..."
value={track}
onChange={e => setTrack(e.target.value)}
onChange={(e) => setTrack(e.target.value)}
/>
<input
className="form-control"
type="text"
placeholder="Filter by artist..."
value={artist}
onChange={e => setArtist(e.target.value)}
onChange={(e) => setArtist(e.target.value)}
/>
<span
className={
@ -100,7 +100,7 @@ export function AuxLibrary({ libraryId }: { libraryId: string }) {
useEffect(() => {
async function load() {
const libItems = await loadAuxLibrary(libraryId);
libItems.forEach(item => {
libItems.forEach((item) => {
const id = itemId(item);
if (!(id in AUX_CACHE)) {
AUX_CACHE[id] = item;
@ -117,14 +117,14 @@ export function AuxLibrary({ libraryId }: { libraryId: string }) {
type="text"
placeholder="Filter..."
value={title}
onChange={e => setTitle(e.target.value)}
onChange={(e) => setTitle(e.target.value)}
/>
<Droppable droppableId="$AUX">
{(provided, snapshot) => (
<div ref={provided.innerRef} {...provided.droppableProps}>
{items
.filter(
its =>
(its) =>
its.title
.toString()
.toLowerCase()

View file

@ -53,7 +53,7 @@ const initialState: ShowplanState = {
planSaving: false,
planSaveError: null,
auxPlaylists: [],
userPlaylists: []
userPlaylists: [],
};
const showplan = createSlice({
@ -84,11 +84,11 @@ const showplan = createSlice({
return;
}
console.log("Applying op sequence", action.payload);
action.payload.forEach(op => {
action.payload.forEach((op) => {
switch (op.op) {
case "MoveItem":
const item = state.plan!.find(
x => itemId(x) === op.timeslotitemid
(x) => itemId(x) === op.timeslotitemid
)!;
item.channel = op.channel;
item.weight = op.weight;
@ -98,7 +98,7 @@ const showplan = createSlice({
break;
case "RemoveItem":
const idx = state.plan!.findIndex(
x => itemId(x) === op.timeslotitemid
(x) => itemId(x) === op.timeslotitemid
);
if (idx < 0) {
throw new Error();
@ -121,7 +121,7 @@ const showplan = createSlice({
action: PayloadAction<{ ghostId: string; newItemData: TimeslotItem }>
) {
const idx = state.plan!.findIndex(
x => itemId(x) === action.payload.ghostId
(x) => itemId(x) === action.payload.ghostId
);
if (idx < 0) {
throw new Error();
@ -133,8 +133,8 @@ const showplan = createSlice({
},
addAuxPlaylists(state, action: PayloadAction<api.ManagedPlaylist[]>) {
state.auxPlaylists = state.auxPlaylists.concat(action.payload);
}
}
},
},
});
export default showplan.reducer;
@ -146,7 +146,7 @@ export const moveItem = (
): AppThunk => async (dispatch, getState) => {
// Make a copy of the plan, because we are about to engage in FUCKERY.
const plan = cloneDeep(getState().showplan.plan!);
const itemToMove = plan.find(x => itemId(x) === itemid)!;
const itemToMove = plan.find((x) => itemId(x) === itemid)!;
if (itemToMove.channel === to[0] && itemToMove.weight === to[1]) {
return;
}
@ -167,7 +167,7 @@ export const moveItem = (
if (oldChannel === newChannel) {
// Moving around in the same channel
const itemChan = plan
.filter(x => x.channel === oldChannel)
.filter((x) => x.channel === oldChannel)
.sort((a, b) => a.weight - b.weight);
if (oldWeight < newWeight) {
// moved the item down (incremented) - everything in between needs decrementing
@ -196,7 +196,7 @@ export const moveItem = (
// First, decrement everything between the old weight and the end of the old channel
// (inclusive of old weight, because we've removed the item)
const oldChannelData = plan
.filter(x => x.channel === oldChannel)
.filter((x) => x.channel === oldChannel)
.sort((a, b) => a.weight - b.weight);
for (let i = oldWeight; i < oldChannelData.length; i++) {
const movingItem = oldChannelData[i];
@ -207,7 +207,7 @@ export const moveItem = (
// Then, increment everything between the new weight and the end of the new channel
// (again, inclusive)
const newChannelData = plan
.filter(x => x.channel === newChannel)
.filter((x) => x.channel === newChannel)
.sort((a, b) => a.weight - b.weight);
for (let i = newWeight; i < newChannelData.length; i++) {
const movingItem = newChannelData[i];
@ -219,27 +219,27 @@ export const moveItem = (
const ops: api.UpdateOp[] = [];
console.log("Inc, dec:", inc, dec);
inc.forEach(id => {
const item = plan.find(x => itemId(x) === id)!;
inc.forEach((id) => {
const item = plan.find((x) => itemId(x) === id)!;
ops.push({
op: "MoveItem",
timeslotitemid: itemId(item),
oldchannel: item.channel,
oldweight: item.weight - 1,
channel: item.channel,
weight: item.weight
weight: item.weight,
});
});
dec.forEach(id => {
const item = plan.find(x => itemId(x) === id)!;
dec.forEach((id) => {
const item = plan.find((x) => itemId(x) === id)!;
ops.push({
op: "MoveItem",
timeslotitemid: itemId(item),
oldchannel: item.channel,
oldweight: item.weight + 1,
channel: item.channel,
weight: item.weight
weight: item.weight,
});
});
@ -250,7 +250,7 @@ export const moveItem = (
oldchannel: oldChannel,
oldweight: oldWeight,
channel: newChannel,
weight: newWeight
weight: newWeight,
});
dispatch(showplan.actions.applyOps(ops));
@ -272,7 +272,7 @@ export const addItem = (
// This is basically a simplified version of the second case above
// Before we add the new item to the plan, we increment everything below it
const planColumn = plan
.filter(x => x.channel === newItemData.channel)
.filter((x) => x.channel === newItemData.channel)
.sort((a, b) => a.weight - b.weight);
for (let i = newItemData.weight; i < planColumn.length; i++) {
const item = planColumn[i];
@ -282,7 +282,7 @@ export const addItem = (
oldchannel: item.channel,
oldweight: item.weight,
channel: item.channel,
weight: item.weight + 1
weight: item.weight + 1,
});
item.weight += 1;
}
@ -343,9 +343,9 @@ export const removeItem = (
): AppThunk => async (dispatch, getState) => {
// This is a simplified version of the second case of moveItem
const plan = cloneDeep(getState().showplan.plan!);
const item = plan.find(x => itemId(x) === itemid)!;
const item = plan.find((x) => itemId(x) === itemid)!;
const planColumn = plan
.filter(x => x.channel === item.channel)
.filter((x) => x.channel === item.channel)
.sort((a, b) => a.weight - b.weight);
const ops: api.UpdateOp[] = [];
@ -353,7 +353,7 @@ export const removeItem = (
op: "RemoveItem",
timeslotitemid: itemid,
channel: item.channel,
weight: item.weight
weight: item.weight,
});
planColumn.splice(planColumn.indexOf(item), 1);
for (let i = item.weight; i < planColumn.length; i++) {
@ -364,7 +364,7 @@ export const removeItem = (
oldchannel: movingItem.channel,
oldweight: movingItem.weight,
channel: movingItem.channel,
weight: movingItem.weight - 1
weight: movingItem.weight - 1,
});
movingItem.weight -= 1;
}
@ -377,7 +377,9 @@ export const removeItem = (
dispatch(showplan.actions.applyOps(ops));
};
export const getShowplan = (timeslotId: number): AppThunk => async dispatch => {
export const getShowplan = (timeslotId: number): AppThunk => async (
dispatch
) => {
dispatch(showplan.actions.getShowplanStarting());
try {
const plan = await api.getShowplan(timeslotId);
@ -405,7 +407,7 @@ export const getShowplan = (timeslotId: number): AppThunk => async dispatch => {
oldchannel: colIndex,
channel: colIndex,
oldweight: item.weight,
weight: itemIndex
weight: itemIndex,
});
plan[colIndex][itemIndex].weight = itemIndex;
}
@ -432,7 +434,7 @@ export const getShowplan = (timeslotId: number): AppThunk => async dispatch => {
}
};
export const getPlaylists = (): AppThunk => async dispatch => {
export const getPlaylists = (): AppThunk => async (dispatch) => {
try {
const userPlaylists = await api.getUserPlaylists();

View file

@ -3,7 +3,7 @@ import { configureStore, Action, getDefaultMiddleware } from "@reduxjs/toolkit";
import { ThunkAction } from "redux-thunk";
import {
mixerMiddleware,
mixerKeyboardShortcutsMiddleware
mixerKeyboardShortcutsMiddleware,
} from "./mixer/state";
import { tabSyncMiddleware } from "./optionsMenu/state";
import { persistStore } from "redux-persist";
@ -14,8 +14,8 @@ const store = configureStore({
mixerMiddleware,
mixerKeyboardShortcutsMiddleware,
tabSyncMiddleware,
...getDefaultMiddleware()
]
...getDefaultMiddleware(),
],
});
if (process.env.NODE_ENV === "development" && module.hot) {