diff --git a/package.json b/package.json index 7e9792b..b2d25ea 100644 --- a/package.json +++ b/package.json @@ -9,6 +9,7 @@ "@types/dom-mediacapture-record": "^1.0.4", "@types/jest": "24.0.22", "@types/keymaster": "^1.6.28", + "@types/later": "^1.2.6", "@types/lodash": "^4.14.149", "@types/node": "^13.11.0", "@types/qs": "^6.9.0", @@ -35,7 +36,6 @@ "camelcase": "^5.2.0", "case-sensitive-paths-webpack-plugin": "2.2.0", "css-loader": "2.1.1", - "date-fns": "^2.12.0", "dotenv": "6.2.0", "dotenv-expand": "5.1.0", "eslint": "^6.1.0", @@ -57,6 +57,7 @@ "jest-resolve": "24.9.0", "jest-watch-typeahead": "0.4.0", "keymaster": "^1.6.2", + "later": "^1.2.0", "lodash": "^4.17.15", "mini-css-extract-plugin": "0.8.0", "optimize-css-assets-webpack-plugin": "5.0.3", diff --git a/src/api.ts b/src/api.ts index 672bb84..218d650 100644 --- a/src/api.ts +++ b/src/api.ts @@ -1,11 +1,8 @@ import qs from "qs"; -export const MYRADIO_NON_API_BASE = - process.env.REACT_APP_MYRADIO_NONAPI_BASE!; -export const MYRADIO_BASE_URL = - process.env.REACT_APP_MYRADIO_BASE!; -export const BROADCAST_API_BASE_URL = - process.env.REACT_APP_BROADCAST_API_BASE!; +export const MYRADIO_NON_API_BASE = process.env.REACT_APP_MYRADIO_NONAPI_BASE!; +export const MYRADIO_BASE_URL = process.env.REACT_APP_MYRADIO_BASE!; +export const BROADCAST_API_BASE_URL = process.env.REACT_APP_BROADCAST_API_BASE!; const MYRADIO_API_KEY = process.env.REACT_APP_MYRADIO_KEY!; export class ApiException extends Error {} @@ -19,7 +16,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); @@ -30,7 +27,7 @@ export async function apiRequest( headers: { "Content-Type": "application/json; charset=UTF-8" }, - credentials: (need_auth ? "include" : "omit") + credentials: need_auth ? "include" : "omit" }); } return await req; @@ -51,12 +48,17 @@ export async function myradioApiRequest( } } -export async function broadcastApiRequest( +export async function broadcastApiRequest( endpoint: string, method: "GET" | "POST" | "PUT", params: any -): Promise { - const res = await apiRequest(BROADCAST_API_BASE_URL + endpoint, method, params, false); +): Promise { + const res = await apiRequest( + BROADCAST_API_BASE_URL + endpoint, + method, + params, + false + ); const json = await res.json(); if (json.status === "OK") { return json.payload; @@ -184,7 +186,6 @@ export function searchForTracks( }); } - export interface ManagedPlaylist { type: "userPlaylist"; title: string; @@ -193,7 +194,11 @@ export interface ManagedPlaylist { } export function getUserPlaylists(): Promise> { - return myradioApiRequest("/nipswebUserPlaylist/allmanageduserplaylists", "GET", {}); + return myradioApiRequest( + "/nipswebUserPlaylist/allmanageduserplaylists", + "GET", + {} + ); } export function getAuxPlaylists(): Promise> { @@ -242,42 +247,34 @@ export function updateShowplan( }); } - - export interface Timeslot { - timeslot_id: number, - time: number, - start_time: string, - title: string + timeslot_id: number; + time: number; + start_time: string; + title: string; } - - export function getCurrentApiTimeslot(): Promise { - return myradioApiRequest(`/timeslot/userselectedtimeslot`, "GET", {} - ).then(res => { - return res; - }); -}; - - -export interface User { - memberid: number, - fname: string, - sname: string, - url: string, - photo: string + return myradioApiRequest(`/timeslot/userselectedtimeslot`, "GET", {}).then( + res => { + return res; + } + ); } - +export interface User { + memberid: number; + fname: string; + sname: string; + url: string; + photo: string; +} export function getCurrentApiUser(): Promise { - return myradioApiRequest(`/user/currentuser`, "GET", {} - ).then(res => { + return myradioApiRequest(`/user/currentuser`, "GET", {}).then(res => { return res; }); -}; - +} export function doesCurrentUserHavePermission(id: number): Promise { return myradioApiRequest("/auth/haspermission/" + id.toString(10), "GET", {}); diff --git a/src/broadcast/rtc_streamer.ts b/src/broadcast/rtc_streamer.ts index 1227c48..f6c283f 100644 --- a/src/broadcast/rtc_streamer.ts +++ b/src/broadcast/rtc_streamer.ts @@ -1,5 +1,5 @@ import SdpTransform from "sdp-transform"; -import * as DateFns from "date-fns"; +import * as later from "later"; import * as BroadcastState from "./state"; import * as MixerState from "../mixer/state"; @@ -10,6 +10,7 @@ import { ConnectionStateEnum } from "./streamer"; import { Dispatch } from "redux"; +import { broadcastApiRequest } from "../api"; type StreamerState = "HELLO" | "OFFER" | "ANSWER" | "CONNECTED"; @@ -22,9 +23,7 @@ export class WebRTCStreamer extends Streamer { dispatch: Dispatch; unexpectedDeath = false; - newsInTimeout?: number; - newsOutTimeout?: number; - newsInterval?: number; + newsInterval?: later.Timer; constructor(stream: MediaStream, dispatch: Dispatch) { super(); @@ -67,9 +66,15 @@ export class WebRTCStreamer extends Streamer { this.addConnectionStateListener(state => { if (state === "CONNECTED") { - this.newsInterval = window.setInterval(this.doTheNews, 1000 * 60); + this.newsInterval = later.setInterval( + this.doTheNews, + later.parse + .recur() + .on(59) + .minute() + ); } else if (state === "CONNECTION_LOST" || state === "NOT_CONNECTED") { - window.clearInterval(this.newsInterval); + this.newsInterval?.clear(); } }); @@ -99,41 +104,41 @@ export class WebRTCStreamer extends Streamer { this.unexpectedDeath = false; } - doTheNews() { - window.clearTimeout(this.newsInTimeout); - window.clearTimeout(this.newsOutTimeout); - const now = new Date(); - if ( - now.getMinutes() < 59 || - (now.getMinutes() === 59 && now.getSeconds() < 44) - ) { - const newsTime = DateFns.set(now, { - minutes: 59, - seconds: 45 - }); - console.log("news time", newsTime); - const delta = newsTime.valueOf() - now.valueOf(); - this.newsInTimeout = window.setTimeout(async () => { - await MixerState.playNewsIntro(); - }, delta); - } - if ( - now.getMinutes() < 1 || - now.getMinutes() >= 2 || - (now.getMinutes() === 1 && now.getSeconds() < 54) - ) { - let newsEndTime = DateFns.set(now, { - minutes: 1, - seconds: 55 - }); - if (now.getMinutes() > 2) { - newsEndTime = DateFns.add(newsEndTime, { hours: 1 }); + async doTheNews() { + const transition = await broadcastApiRequest<{ + autoNews: boolean; + selSource: number; + switchAudioAtMin: number; + }>("/nextTransition", "GET", {}); + if (transition.autoNews) { + // 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() + ); + } + if (now.getMinutes() <= 1 && now.getSeconds() < 55) { + later.setTimeout( + async () => { + await MixerState.playNewsEnd(); + }, + later.parse + .recur() + .on(1) + .minute() + .on(55) + .second() + ); } - console.log("end time", newsEndTime); - const delta = newsEndTime.valueOf() - now.valueOf(); - this.newsOutTimeout = window.setTimeout(async () => { - await MixerState.playNewsEnd(); - }, delta); } } diff --git a/yarn.lock b/yarn.lock index fcda2b0..6c92e04 100644 --- a/yarn.lock +++ b/yarn.lock @@ -1439,6 +1439,11 @@ resolved "https://registry.yarnpkg.com/@types/keymaster/-/keymaster-1.6.28.tgz#093fc6fe49deff4ee17d36935a49230edb1c935f" integrity sha1-CT/G/kne/07hfTaTWkkjDtsck18= +"@types/later@^1.2.6": + version "1.2.6" + resolved "https://registry.yarnpkg.com/@types/later/-/later-1.2.6.tgz#8ea70d292e5fb880039a7ed13da19a24c9e35a56" + integrity sha512-a+wmsrP4FJCOt3xq+bjMkNloUtk7O7MnjYGTa6HxANSHRRPxcfhougk5+pl5B9Qr/w7cC7a4Ku9LM8frizr2Lw== + "@types/lodash@^4.14.149": version "4.14.149" resolved "https://registry.yarnpkg.com/@types/lodash/-/lodash-4.14.149.tgz#1342d63d948c6062838fbf961012f74d4e638440" @@ -3530,11 +3535,6 @@ data-urls@^1.0.0, data-urls@^1.1.0: whatwg-mimetype "^2.2.0" whatwg-url "^7.0.0" -date-fns@^2.12.0: - version "2.12.0" - resolved "https://registry.yarnpkg.com/date-fns/-/date-fns-2.12.0.tgz#01754c8a2f3368fc1119cf4625c3dad8c1845ee6" - integrity sha512-qJgn99xxKnFgB1qL4jpxU7Q2t0LOn1p8KMIveef3UZD7kqjT3tpFNNdXJelEHhE+rUgffriXriw/sOSU+cS1Hw== - debug@2.6.9, debug@^2.2.0, debug@^2.3.3, debug@^2.6.0, debug@^2.6.9: version "2.6.9" resolved "https://registry.yarnpkg.com/debug/-/debug-2.6.9.tgz#5d128515df134ff327e90a4c93f4e077a536341f" @@ -6447,6 +6447,11 @@ last-call-webpack-plugin@^3.0.0: lodash "^4.17.5" webpack-sources "^1.1.0" +later@^1.2.0: + version "1.2.0" + resolved "https://registry.yarnpkg.com/later/-/later-1.2.0.tgz#f2cf6c4dd7956dd2f520adf0329836e9876bad0f" + integrity sha1-8s9sTdeVbdL1IK3wMpg26YdrrQ8= + lazy-cache@^0.2.3: version "0.2.7" resolved "https://registry.yarnpkg.com/lazy-cache/-/lazy-cache-0.2.7.tgz#7feddf2dcb6edb77d11ef1d117ab5ffdf0ab1b65"