From a5cada585507b524f976d029ca9cc53afbb3e2c6 Mon Sep 17 00:00:00 2001 From: Adeeb Shihadeh Date: Mon, 8 Apr 2024 18:23:44 -0700 Subject: [PATCH 1/5] log id url --- src/actions/history.js | 10 ++++++-- src/actions/index.js | 30 +++++++++++++--------- src/actions/types.js | 1 - src/components/Dashboard/DriveListItem.jsx | 4 +-- src/components/DriveVideo/index.jsx | 5 ---- src/components/DriveView/index.jsx | 4 +-- src/components/Timeline/index.jsx | 4 ++- src/initialState.js | 3 ++- src/reducers/globalState.js | 13 +++++++++- src/reducers/index.js | 4 +-- src/timeline/index.js | 19 +------------- src/timeline/segments.js | 25 ------------------ src/url.js | 15 +++++++++++ 13 files changed, 64 insertions(+), 73 deletions(-) diff --git a/src/actions/history.js b/src/actions/history.js index 61c7db120..6a7bc0c4d 100644 --- a/src/actions/history.js +++ b/src/actions/history.js @@ -1,5 +1,5 @@ import { LOCATION_CHANGE } from 'connected-react-router'; -import { getDongleID, getZoom, getPrimeNav } from '../url'; +import { getDongleID, getZoom, getSegmentRange, getPrimeNav } from '../url'; import { primeNav, selectDevice, pushTimelineRange } from './index'; export const onHistoryMiddleware = ({ dispatch, getState }) => (next) => (action) => { @@ -17,9 +17,15 @@ export const onHistoryMiddleware = ({ dispatch, getState }) => (next) => (action dispatch(selectDevice(pathDongleId, false)); } + // TODO: this should redirect to a log id const pathZoom = getZoom(action.payload.location.pathname); if (pathZoom !== state.zoom) { - dispatch(pushTimelineRange(pathZoom?.start, pathZoom?.end, false)); + //dispatch(pushTimelineRange(pathZoom?.start, pathZoom?.end, false)); + } + + const pathSegmentRange = getSegmentRange(action.payload.location.pathname); + if (pathSegmentRange != state.segmentRange) { + dispatch(pushTimelineRange(pathSegmentRange?.log_id, pathSegmentRange?.start, pathSegmentRange?.end, true)); } const pathPrimeNav = getPrimeNav(action.payload.location.pathname); diff --git a/src/actions/index.js b/src/actions/index.js index 9ac4a1cc3..aad6fdf74 100644 --- a/src/actions/index.js +++ b/src/actions/index.js @@ -11,7 +11,7 @@ import { getDeviceFromState, deviceVersionAtLeast } from '../utils'; let routesRequest = null; -function updateTimeline(state, dispatch, start, end, allowPathChange) { +function updateTimeline(state, dispatch, log_id, start, end, allowPathChange) { dispatch(checkRoutesData()); if (!state.loop || !state.loop.startTime || !state.loop.duration || state.loop.startTime < start @@ -20,8 +20,9 @@ function updateTimeline(state, dispatch, start, end, allowPathChange) { dispatch(selectLoop(start, end)); } + // TODO: fix this up if (allowPathChange) { - const desiredPath = urlForState(state.dongleId, start, end, false); + const desiredPath = urlForState(state.dongleId, log_id, start, end, false); if (window.location.pathname !== desiredPath) { dispatch(push(desiredPath)); } @@ -37,23 +38,24 @@ export function popTimelineRange(allowPathChange = true) { }); const { start, end } = state.zoom.previous; - updateTimeline(state, dispatch, start, end, allowPathChange); + updateTimeline(state, dispatch, state.currentRoute?.log_id, start, end, allowPathChange); } }; } -export function pushTimelineRange(start, end, allowPathChange = true) { +export function pushTimelineRange(log_id, start, end, allowPathChange = true) { return (dispatch, getState) => { const state = getState(); if (state.zoom?.start !== start || state.zoom?.end !== end) { dispatch({ type: Types.TIMELINE_PUSH_SELECTION, + log_id, start, end, }); } - updateTimeline(state, dispatch, start, end, allowPathChange); + updateTimeline(state, dispatch, log_id, start, end, allowPathChange); }; } @@ -73,7 +75,7 @@ export function selectDevice(dongleId, allowPathChange = true) { dongleId, }); - dispatch(pushTimelineRange(null, null, false)); + dispatch(pushTimelineRange(null, null, null, false)); if ((device && !device.shared) || state.profile?.superuser) { dispatch(primeFetchSubscription(dongleId, device)); dispatch(fetchDeviceOnline(dongleId)); @@ -82,7 +84,7 @@ export function selectDevice(dongleId, allowPathChange = true) { dispatch(checkRoutesData()); if (allowPathChange) { - const desiredPath = urlForState(dongleId, null, null, null); + const desiredPath = urlForState(dongleId, null, null, null, null); if (window.location.pathname !== desiredPath) { dispatch(push(desiredPath)); } @@ -141,7 +143,7 @@ export function primeNav(nav, allowPathChange = true) { if (allowPathChange) { const curPath = document.location.pathname; - const desiredPath = urlForState(state.dongleId, null, null, nav); + const desiredPath = urlForState(state.dongleId, null, null, null, nav); if (curPath !== desiredPath) { dispatch(push(desiredPath)); } @@ -302,6 +304,7 @@ export function checkRoutesData() { return { ...r, url: r.url.replace('chffrprivate.blob.core.windows.net', 'chffrprivate.azureedge.net'), + log_id: r.fullname.split('|')[1], offset: Math.round(startTime) - state.filter.start, duration: endTime - startTime, start_time_utc_millis: startTime, @@ -361,12 +364,15 @@ export function primeGetSubscription(dongleId, subscription) { }; } -export function urlForState(dongleId, start, end, prime) { +export function urlForState(dongleId, log_id, start, end, prime) { const path = [dongleId]; - if (start && end) { - path.push(start); - path.push(end); + if (log_id) { + path.push(log_id); + if (start && end) { + path.push(start); + path.push(end); + } } else if (prime) { path.push('prime'); } diff --git a/src/actions/types.js b/src/actions/types.js index d6a6a686d..96d88adac 100644 --- a/src/actions/types.js +++ b/src/actions/types.js @@ -28,7 +28,6 @@ export const ACTION_BUFFER_VIDEO = 'action_buffer_video'; export const ACTION_RESET = 'action_reset'; // segments -export const ACTION_UPDATE_SEGMENTS = 'update_segments'; export const ACTION_ROUTES_METADATA = 'routes_metadata'; // files diff --git a/src/components/Dashboard/DriveListItem.jsx b/src/components/Dashboard/DriveListItem.jsx index bfa5b64ed..57fc643d6 100644 --- a/src/components/Dashboard/DriveListItem.jsx +++ b/src/components/Dashboard/DriveListItem.jsx @@ -84,7 +84,7 @@ const DriveListItem = (props) => { }, [drive, dispatch, isVisible, el]); const onClick = filterRegularClick( - () => dispatch(pushTimelineRange(drive.start_time_utc_millis, drive.end_time_utc_millis)), + () => dispatch(pushTimelineRange(drive.log_id, drive.start_time_utc_millis, drive.end_time_utc_millis, true)), ); const small = windowWidth < 580; @@ -117,7 +117,7 @@ const DriveListItem = (props) => { key={drive.fullname} className={`${classes.drive} DriveEntry`} ref={el} - href={`/${drive.dongle_id}/${drive.start_time_utc_millis}/${drive.end_time_utc_millis}`} + //href={`/${drive.dongle_id}/${drive.log_id}`} onClick={onClick} >
diff --git a/src/components/DriveVideo/index.jsx b/src/components/DriveVideo/index.jsx index 7952db38e..aa82011c5 100644 --- a/src/components/DriveVideo/index.jsx +++ b/src/components/DriveVideo/index.jsx @@ -12,7 +12,6 @@ import Colors from '../../colors'; import { ErrorOutline } from '../../icons'; import { currentOffset } from '../../timeline'; import { seek, bufferVideo } from '../../timeline/playback'; -import { updateSegments } from '../../timeline/segments'; const VideoOverlay = ({ loading, error }) => { let content; @@ -203,10 +202,6 @@ class DriveVideo extends Component { syncVideo() { const { dispatch, isBufferingVideo, currentRoute } = this.props; if (!currentRoute) { - dispatch(updateSegments()); - if (currentRoute && isBufferingVideo) { - dispatch(bufferVideo(false)); - } return; } diff --git a/src/components/DriveView/index.jsx b/src/components/DriveView/index.jsx index b64d04bf6..69c123ff0 100644 --- a/src/components/DriveView/index.jsx +++ b/src/components/DriveView/index.jsx @@ -23,13 +23,13 @@ class DriveView extends Component { this.props.dispatch(popTimelineRange()); } else if (currentRoute) { this.props.dispatch( - pushTimelineRange(currentRoute.start_time_utc_millis, currentRoute.end_time_utc_millis), + pushTimelineRange(currentRoute.log_id, currentRoute.start_time_utc_millis, currentRoute.end_time_utc_millis), ); } } close() { - this.props.dispatch(pushTimelineRange(null, null)); + this.props.dispatch(pushTimelineRange(null, null, null)); } render() { diff --git a/src/components/Timeline/index.jsx b/src/components/Timeline/index.jsx index a89816c29..71f338839 100644 --- a/src/components/Timeline/index.jsx +++ b/src/components/Timeline/index.jsx @@ -233,6 +233,8 @@ class Timeline extends Component { } handlePointerUp(ev) { + const { route } = this.props; + // prevent preventDefault for back(3) and forward(4) mouse buttons if (ev.button !== 3 && ev.button !== 4) { ev.preventDefault(); @@ -261,7 +263,7 @@ class Timeline extends Component { const startTime = startOffset + filter.start; const endTime = endOffset + filter.start; - dispatch(pushTimelineRange(startTime, endTime)); + dispatch(pushTimelineRange(route.log_id, startTime, endTime, true)); } else if (ev.currentTarget !== document) { this.handleClick(ev); } diff --git a/src/initialState.js b/src/initialState.js index ff6b7ac11..fc65ee61c 100644 --- a/src/initialState.js +++ b/src/initialState.js @@ -1,4 +1,4 @@ -import { getDongleID, getZoom, getPrimeNav } from './url'; +import { getDongleID, getZoom, getPrimeNav, getSegmentRange } from './url'; import * as Demo from './demo'; export function getDefaultFilter() { @@ -65,4 +65,5 @@ export default { filter: getDefaultFilter(), zoom: getZoom(window.location.pathname), loop: getDefaultLoop(window.location.pathname), + segmentRange: getSegmentRange(window.location.pathname), }; diff --git a/src/reducers/globalState.js b/src/reducers/globalState.js index aee087e87..be59fbd63 100644 --- a/src/reducers/globalState.js +++ b/src/reducers/globalState.js @@ -273,11 +273,13 @@ export default function reducer(_state, action) { end: action.end, previous: state.zoom, }; + state.currentRoute = state.routes?.find((route) => route.log_id === action.log_id); } else { state.zoom = null; state.loop = null; + state.currentRoute = null; } - break; + break; case Types.ACTION_FILES_URLS: state.files = { ...(state.files !== null ? { ...state.files } : {}), @@ -323,6 +325,15 @@ export default function reducer(_state, action) { start: action.start, end: action.end, }; + + if (!state.currentRoute && state.segmentRange) { + const r = state.routes?.find((route) => route.log_id === state.segmentRange.log_id); + if (r) { + state.currentRoute = { + ...r, + }; + } + } break; default: return state; diff --git a/src/reducers/index.js b/src/reducers/index.js index 10f491a6b..6a7d8d6d6 100644 --- a/src/reducers/index.js +++ b/src/reducers/index.js @@ -1,11 +1,9 @@ import { reducer as playbackReducer } from '../timeline/playback'; -import { reducer as segmentsReducers } from '../timeline/segments'; import globalState from './globalState'; const reducers = [ globalState, playbackReducer, - segmentsReducers, ]; -export default reducers; +export default reducers; \ No newline at end of file diff --git a/src/timeline/index.js b/src/timeline/index.js index f16743293..e1f1300eb 100644 --- a/src/timeline/index.js +++ b/src/timeline/index.js @@ -31,21 +31,4 @@ export function currentOffset(state = null) { } return offset; -} - -/** - * Get current route - * - * @param {object} state - * @param {number} [offset] - * @returns {*|null} - */ -export function getCurrentRoute(state, offset) { - if (!state.routes) return null; - - offset = offset || currentOffset(state); - if (offset === null) return null; - - return state.routes - .find((route) => offset >= route.offset && offset <= route.offset + route.duration); -} +} \ No newline at end of file diff --git a/src/timeline/segments.js b/src/timeline/segments.js index 410f8a430..b59cd935c 100644 --- a/src/timeline/segments.js +++ b/src/timeline/segments.js @@ -1,29 +1,4 @@ import * as Types from '../actions/types'; -import { getCurrentRoute } from '.'; - -export function reducer(_state, action) { - let state = { ..._state }; - switch (action.type) { - case Types.ACTION_UPDATE_SEGMENTS: - state = { - ...state, - }; - break; - default: - break; - } - - const currentRoute = getCurrentRoute(state); - state.currentRoute = currentRoute ? { ...currentRoute } : null; - - return state; -} - -export function updateSegments() { - return { - type: Types.ACTION_UPDATE_SEGMENTS, - }; -} export function getSegmentFetchRange(state) { if (!state.zoom) { diff --git a/src/url.js b/src/url.js index 5bd604804..645833b23 100644 --- a/src/url.js +++ b/src/url.js @@ -1,4 +1,5 @@ const dongleIdRegex = /[a-f0-9]{16}/; +const logIdRegex = /[a-f0-9-]{20}/; export function getDongleID(pathname) { let parts = pathname.split('/'); @@ -24,6 +25,20 @@ export function getZoom(pathname) { return null; } +export function getSegmentRange(pathname) { + let parts = pathname.split('/'); + parts = parts.filter((m) => m.length); + + if (parts.length >= 2 && logIdRegex.test(parts[1])) { + return { + log_id: parts[1], + start: Number(parts[2]), + end: Number(parts[3]), + }; + } + return null; +} + export function getPrimeNav(pathname) { let parts = pathname.split('/'); parts = parts.filter((m) => m.length); From a5342742cf7b2169b9330e9949af5325192a29ad Mon Sep 17 00:00:00 2001 From: Adeeb Shihadeh Date: Mon, 8 Apr 2024 21:15:48 -0700 Subject: [PATCH 2/5] some stuff kinda works --- README.md | 8 ----- src/actions/index.js | 7 +++-- src/components/AppHeader/index.jsx | 4 +-- src/components/Dashboard/DriveListItem.jsx | 8 ++--- src/components/DriveVideo/index.jsx | 1 - src/components/DriveView/index.jsx | 16 +++++----- src/components/Timeline/index.jsx | 35 ++++++++-------------- src/components/Timeline/thumbnails.jsx | 6 ++-- src/components/explorer.jsx | 9 ++++-- src/initialState.js | 6 ++-- src/reducers/globalState.js | 4 +++ src/timeline/index.js | 6 ++-- src/timeline/playback.js | 6 ++-- src/utils/index.js | 11 +++++-- 14 files changed, 61 insertions(+), 66 deletions(-) diff --git a/README.md b/README.md index 774afc843..dede906a3 100644 --- a/README.md +++ b/README.md @@ -17,14 +17,6 @@ There's a ton of them, but these are worth mentioning because they sort of affec * `@material-ui` - Lots of fully featured highly customizable components for building the UIs with. Theming system with global and per-component overrides of any CSS values. * `react-router-redux` - the newer one, 5.x.... Mindlessly simple routing with convenient global access due to redux -## How things works -The current playback is tracked not by storing the current offset, but instead storing the local time that the player began, the offset it began at, and the playback rate. Any time any of these values change, it rebases them all back to the current time. It means that at any arbitrary moment you can calculate the current offset with... -```js -(Date.now() - state.startTime) * state.playSpeed + state.offset -``` - -With this central authority on current offset time, it becomes much easier to have each data source keep themselves in sync instead of trying to manage synchronizing all of them. - ## Development `pnpm start` diff --git a/src/actions/index.js b/src/actions/index.js index aad6fdf74..fd0d24533 100644 --- a/src/actions/index.js +++ b/src/actions/index.js @@ -305,11 +305,12 @@ export function checkRoutesData() { ...r, url: r.url.replace('chffrprivate.blob.core.windows.net', 'chffrprivate.azureedge.net'), log_id: r.fullname.split('|')[1], - offset: Math.round(startTime) - state.filter.start, + //offset: Math.round(startTime), duration: endTime - startTime, start_time_utc_millis: startTime, end_time_utc_millis: endTime, - segment_offsets: r.segment_start_times.map((x) => x - state.filter.start), + // TODO: get this from the API, this isn't correct for segments with a time jump + segment_durations: r.segment_start_times.map((x, i) => r.segment_end_times[i] - x), }; }); @@ -369,7 +370,7 @@ export function urlForState(dongleId, log_id, start, end, prime) { if (log_id) { path.push(log_id); - if (start && end) { + if (start && end && start > 0 && start > end) { path.push(start); path.push(end); } diff --git a/src/components/AppHeader/index.jsx b/src/components/AppHeader/index.jsx index ebee8d761..0d69a7359 100644 --- a/src/components/AppHeader/index.jsx +++ b/src/components/AppHeader/index.jsx @@ -58,7 +58,7 @@ const styles = () => ({ }); const AppHeader = ({ - profile, classes, dispatch, drawerIsOpen, annotating, showDrawerButton, + profile, classes, dispatch, drawerIsOpen, viewingRoute, showDrawerButton, forwardRef, handleDrawerStateChanged, primeNav, dongleId, }) => { const [anchorEl, setAnchorEl] = useState(null); @@ -112,7 +112,7 @@ const AppHeader = ({
- {Boolean(!primeNav && !annotating && dongleId) && } + {Boolean(!primeNav && !viewingRoute && dongleId) && }
diff --git a/src/components/Dashboard/DriveListItem.jsx b/src/components/Dashboard/DriveListItem.jsx index 57fc643d6..998b6f32f 100644 --- a/src/components/Dashboard/DriveListItem.jsx +++ b/src/components/Dashboard/DriveListItem.jsx @@ -84,7 +84,7 @@ const DriveListItem = (props) => { }, [drive, dispatch, isVisible, el]); const onClick = filterRegularClick( - () => dispatch(pushTimelineRange(drive.log_id, drive.start_time_utc_millis, drive.end_time_utc_millis, true)), + () => dispatch(pushTimelineRange(drive.log_id, null, null, true)), ); const small = windowWidth < 580; @@ -117,8 +117,8 @@ const DriveListItem = (props) => { key={drive.fullname} className={`${classes.drive} DriveEntry`} ref={el} - //href={`/${drive.dongle_id}/${drive.log_id}`} - onClick={onClick} + href={`/${drive.dongle_id}/${drive.log_id}`} + //onClick={onClick} >
@@ -148,7 +148,7 @@ const DriveListItem = (props) => { ); diff --git a/src/components/DriveVideo/index.jsx b/src/components/DriveVideo/index.jsx index aa82011c5..3f7e63702 100644 --- a/src/components/DriveVideo/index.jsx +++ b/src/components/DriveVideo/index.jsx @@ -264,7 +264,6 @@ class DriveVideo extends Component { if (!currentRoute) { return 0; } - offset -= currentRoute.offset; if (currentRoute.videoStartOffset) { offset -= currentRoute.videoStartOffset; diff --git a/src/components/DriveView/index.jsx b/src/components/DriveView/index.jsx index 69c123ff0..fde9c2a80 100644 --- a/src/components/DriveView/index.jsx +++ b/src/components/DriveView/index.jsx @@ -23,7 +23,7 @@ class DriveView extends Component { this.props.dispatch(popTimelineRange()); } else if (currentRoute) { this.props.dispatch( - pushTimelineRange(currentRoute.log_id, currentRoute.start_time_utc_millis, currentRoute.end_time_utc_millis), + pushTimelineRange(currentRoute.log_id, null, null), ); } } @@ -33,15 +33,17 @@ class DriveView extends Component { } render() { - const { dongleId, zoom, routes, currentRoute } = this.props; + const { dongleId, zoom, currentRoute, routes } = this.props; - const currentRouteBoundsSelected = currentRoute?.start_time_utc_millis === zoom.start && currentRoute?.end_time_utc_millis === zoom.end; - const backButtonDisabled = !zoom.previousZoom && currentRouteBoundsSelected; + // TODO: fix this + //const currentRouteBoundsSelected = currentRoute?.start_time_utc_millis === zoom.start && currentRoute?.end_time_utc_millis === zoom.end; + const currentRouteBoundsSelected = false; + const backButtonDisabled = !zoom?.previousZoom && currentRouteBoundsSelected; // FIXME: end time not always same day as start time - const startDay = dayjs(zoom.start).format('dddd'); - const startTime = dayjs(zoom.start).format('MMM D @ HH:mm'); - const endTime = dayjs(zoom.end).format('HH:mm'); + const startDay = dayjs(currentRoute.start_time_utc_millis).format('dddd'); + const startTime = dayjs(currentRoute.start_time_utc_millis).format('MMM D @ HH:mm'); + const endTime = dayjs(currentRoute.end_time_utc_millis).format('HH:mm'); return (
diff --git a/src/components/Timeline/index.jsx b/src/components/Timeline/index.jsx index 71f338839..4aa1f620e 100644 --- a/src/components/Timeline/index.jsx +++ b/src/components/Timeline/index.jsx @@ -259,9 +259,9 @@ class Timeline extends Component { if (offset < startOffset || offset > endOffset) { this.props.dispatch(seek(startOffset)); } - const { filter, dispatch } = this.props; - const startTime = startOffset + filter.start; - const endTime = endOffset + filter.start; + const { dispatch } = this.props; + const startTime = startOffset; + const endTime = endOffset; dispatch(pushTimelineRange(route.log_id, startTime, endTime, true)); } else if (ev.currentTarget !== document) { @@ -299,14 +299,12 @@ class Timeline extends Component { percentToOffset(perc) { const { zoom } = this.state; - const { filter } = this.props; - return perc * (zoom.end - zoom.start) + (zoom.start - filter.start); + return perc * (zoom.end - zoom.start) + zoom.start; } offsetToPercent(offset) { const { zoom } = this.state; - const { filter } = this.props; - return (offset - (zoom.start - filter.start)) / (zoom.end - zoom.start); + return (offset - zoom.start) / (zoom.end - zoom.start); } segmentNum(offset) { @@ -318,27 +316,19 @@ class Timeline extends Component { } renderRoute() { - const { classes, route, filter } = this.props; + const { classes, route } = this.props; const { zoom } = this.state; if (!route.events) { return null; } - const range = filter.start - filter.end; - let startPerc = (100 * route.offset) / range; + const range = route.duration; + let startPerc = (100 * 0) / range; let widthPerc = (100 * route.duration) / range; - const startOffset = zoom.start - filter.start; - const endOffset = zoom.end - filter.start; - const zoomDuration = endOffset - startOffset; - if (route.offset > endOffset) { - return []; - } - if (route.offset + route.duration < startOffset) { - return []; - } - startPerc = (100 * (route.offset - startOffset)) / zoomDuration; + const zoomDuration = zoom.end - zoom.start; + startPerc = (100 * (route.offset - zoom.start)) / zoomDuration; widthPerc = (100 * route.duration) / zoomDuration; const style = { @@ -378,7 +368,7 @@ class Timeline extends Component { } render() { - const { classes, hasRuler, filter, className, route, thumbnailsVisible } = this.props; + const { classes, hasRuler, className, route, thumbnailsVisible } = this.props; const { thumbnail, hoverX, dragging } = this.state; const hasRulerCls = hasRuler ? 'hasRuler' : ''; @@ -394,7 +384,7 @@ class Timeline extends Component { const hoverOffset = this.percentToOffset((hoverX - rulerBounds.x) / rulerBounds.width); hoverStyle = { left: Math.max(-10, Math.min(rulerBounds.width - 70, hoverX - rulerBounds.x - 40)) }; if (!Number.isNaN(hoverOffset)) { - hoverString = dayjs(filter.start + hoverOffset).format('HH:mm:ss'); + hoverString = dayjs(route.start_time_utc_millis + hoverOffset).format('HH:mm:ss'); const segNum = this.segmentNum(hoverOffset); if (segNum !== null) { hoverString = `${segNum}, ${hoverString}`; @@ -463,7 +453,6 @@ class Timeline extends Component { const stateToProps = Obstruction({ zoom: 'zoom', loop: 'loop', - filter: 'filter', }); export default connect(stateToProps)(withStyles(styles)(Timeline)); diff --git a/src/components/Timeline/thumbnails.jsx b/src/components/Timeline/thumbnails.jsx index 08f1233f0..4424591ed 100644 --- a/src/components/Timeline/thumbnails.jsx +++ b/src/components/Timeline/thumbnails.jsx @@ -33,7 +33,7 @@ export default function Thumbnails(props) { currSegment.length += 1; } else { // 12 per file, 5s each - const seconds = Math.floor((offset - route.offset) / 1000); + const seconds = Math.floor(offset / 1000); const imageIndex = Math.max(0, Math.min(Math.floor(seconds / 5), 11)); const segmentNum = getSegmentNumber(route, offset); const url = `${route.url}/${segmentNum}/sprite.jpg`; @@ -75,7 +75,7 @@ export default function Thumbnails(props) { return imgArr.map((data, i) => (data.blank ? (
this.setState({ windowWidth: ww }) } /> { noDevicesUpsell ? - : (zoom ? : )} + : (currentRoute ? : )}
@@ -249,6 +251,7 @@ const stateToProps = Obstruction({ pathname: 'router.location.pathname', dongleId: 'dongleId', devices: 'devices', + currentRoute: 'currentRoute', }); export default connect(stateToProps)(withStyles(styles)(ExplorerApp)); diff --git a/src/initialState.js b/src/initialState.js index fc65ee61c..6e55942b4 100644 --- a/src/initialState.js +++ b/src/initialState.js @@ -35,10 +35,10 @@ function getDefaultLoop(pathname) { export default { dongleId: getDongleID(window.location.pathname), - desiredPlaySpeed: 1, // speed set by user + desiredPlaySpeed: 1, // speed set by user isBufferingVideo: true, // if we're currently buffering for more data - offset: null, // in miliseconds, relative to `state.filter.start` - startTime: Date.now(), // millisecond timestamp in which play began + offset: null, // in miliseconds, relative to state.zoom.start + startTime: Date.now(), // millisecond timestamp in which play began routes: null, routesMeta: { diff --git a/src/reducers/globalState.js b/src/reducers/globalState.js index be59fbd63..9198db4b7 100644 --- a/src/reducers/globalState.js +++ b/src/reducers/globalState.js @@ -332,6 +332,10 @@ export default function reducer(_state, action) { state.currentRoute = { ...r, }; + state.zoom = { + start: 0, + end: state.currentRoute.duration, + }; } } break; diff --git a/src/timeline/index.js b/src/timeline/index.js index e1f1300eb..13e797a08 100644 --- a/src/timeline/index.js +++ b/src/timeline/index.js @@ -1,7 +1,7 @@ import store from '../store'; /** - * Get current playback offset, relative to `state.filter.start` + * Get current playback offset * * @param {object} state * @returns {number} @@ -14,7 +14,7 @@ export function currentOffset(state = null) { /** @type {number} */ let offset; if (state.offset === null && state.loop?.startTime) { - offset = state.loop.startTime - state.filter.start; + offset = state.loop.startTime; } else { const playSpeed = state.isBufferingVideo ? 0 : state.desiredPlaySpeed; offset = state.offset + ((Date.now() - state.startTime) * playSpeed); @@ -22,7 +22,7 @@ export function currentOffset(state = null) { if (offset !== null && state.loop?.startTime) { // respect the loop - const loopOffset = state.loop.startTime - state.filter.start; + const loopOffset = state.loop.startTime; if (offset < loopOffset) { offset = loopOffset; } else if (offset > loopOffset + state.loop.duration) { diff --git a/src/timeline/playback.js b/src/timeline/playback.js index da803029f..12ea4b9a5 100644 --- a/src/timeline/playback.js +++ b/src/timeline/playback.js @@ -7,7 +7,7 @@ export function reducer(_state, action) { let state = { ..._state }; let loopOffset = null; if (state.loop && state.loop.startTime !== null) { - loopOffset = state.loop.startTime - state.filter.start; + loopOffset = state.loop.startTime; } switch (action.type) { case Types.ACTION_SEEK: @@ -75,7 +75,7 @@ export function reducer(_state, action) { } if (state.currentRoute && state.currentRoute.videoStartOffset && state.loop && state.zoom && state.filter - && state.loop.startTime === state.zoom.start && state.filter.start + state.currentRoute.offset === state.zoom.start) { + && state.loop.startTime === state.zoom.start && state.zoom.start === 0) { const loopRouteOffset = state.loop.startTime - state.zoom.start; if (state.currentRoute.videoStartOffset > loopRouteOffset) { state.loop = { @@ -89,7 +89,7 @@ export function reducer(_state, action) { if (state.offset !== null && state.loop?.startTime) { const playSpeed = state.isBufferingVideo ? 0 : state.desiredPlaySpeed; const offset = state.offset + (Date.now() - state.startTime) * playSpeed; - loopOffset = state.loop.startTime - state.filter.start; + loopOffset = state.loop.startTime; // has loop, trap offset within the loop if (offset < loopOffset) { state.startTime = Date.now(); diff --git a/src/utils/index.js b/src/utils/index.js index d529a1fa9..a5c61b731 100644 --- a/src/utils/index.js +++ b/src/utils/index.js @@ -187,11 +187,16 @@ export function getSegmentNumber(route, offset) { if (offset === undefined) { offset = currentOffset(); } - for (let i = 0; i < route.segment_offsets.length; i++) { - if (offset >= route.segment_offsets[i] - && (i === route.segment_offsets.length - 1 || offset < route.segment_offsets[i + 1])) { + + return Math.floor(offset / (60*1000)); + + /* + for (let i = 0; i < route.segment_durations.length; i++) { + console.log(offset, route.segment_durations.slice(0, i+1).reduce((acc, val) => acc + val, 0)) + if (offset >= route.segment_durations.slice(0, i+1).reduce((acc, val) => acc + val, 0)) { return route.segment_numbers[i]; } } return null; + */ } From c043170319d6695572012f8ffaa0c868ffa3eb9c Mon Sep 17 00:00:00 2001 From: Adeeb Shihadeh Date: Tue, 9 Apr 2024 11:20:02 -0700 Subject: [PATCH 3/5] works a lil more --- src/actions/index.js | 2 +- src/components/Dashboard/DriveListItem.jsx | 4 ++-- src/components/DriveView/index.jsx | 4 +--- src/components/explorer.jsx | 2 +- src/reducers/globalState.js | 23 +++++++++++++++------- src/timeline/segments.js | 3 +++ 6 files changed, 24 insertions(+), 14 deletions(-) diff --git a/src/actions/index.js b/src/actions/index.js index fd0d24533..623f0735e 100644 --- a/src/actions/index.js +++ b/src/actions/index.js @@ -370,7 +370,7 @@ export function urlForState(dongleId, log_id, start, end, prime) { if (log_id) { path.push(log_id); - if (start && end && start > 0 && start > end) { + if (start && end && start > 0) { path.push(start); path.push(end); } diff --git a/src/components/Dashboard/DriveListItem.jsx b/src/components/Dashboard/DriveListItem.jsx index 998b6f32f..cdb7c892b 100644 --- a/src/components/Dashboard/DriveListItem.jsx +++ b/src/components/Dashboard/DriveListItem.jsx @@ -84,7 +84,7 @@ const DriveListItem = (props) => { }, [drive, dispatch, isVisible, el]); const onClick = filterRegularClick( - () => dispatch(pushTimelineRange(drive.log_id, null, null, true)), + () => dispatch(pushTimelineRange(drive.log_id, 0, drive.duration, true)), ); const small = windowWidth < 580; @@ -118,7 +118,7 @@ const DriveListItem = (props) => { className={`${classes.drive} DriveEntry`} ref={el} href={`/${drive.dongle_id}/${drive.log_id}`} - //onClick={onClick} + onClick={onClick} >
diff --git a/src/components/DriveView/index.jsx b/src/components/DriveView/index.jsx index fde9c2a80..da0377c32 100644 --- a/src/components/DriveView/index.jsx +++ b/src/components/DriveView/index.jsx @@ -35,9 +35,7 @@ class DriveView extends Component { render() { const { dongleId, zoom, currentRoute, routes } = this.props; - // TODO: fix this - //const currentRouteBoundsSelected = currentRoute?.start_time_utc_millis === zoom.start && currentRoute?.end_time_utc_millis === zoom.end; - const currentRouteBoundsSelected = false; + const currentRouteBoundsSelected = zoom.start === 0 && zoom.end === currentRoute?.duration; const backButtonDisabled = !zoom?.previousZoom && currentRouteBoundsSelected; // FIXME: end time not always same day as start time diff --git a/src/components/explorer.jsx b/src/components/explorer.jsx index 756180894..35f825137 100644 --- a/src/components/explorer.jsx +++ b/src/components/explorer.jsx @@ -197,7 +197,7 @@ class ExplorerApp extends Component { minHeight: `calc(100vh - ${headerHeight}px)`, }; - console.log("zoom here", zoom) + console.log("current route", currentRoute, zoom) return (
diff --git a/src/reducers/globalState.js b/src/reducers/globalState.js index 9198db4b7..902936330 100644 --- a/src/reducers/globalState.js +++ b/src/reducers/globalState.js @@ -267,13 +267,22 @@ export default function reducer(_state, action) { if (!state.zoom || !action.start || !action.end || action.start < state.zoom.start || action.end > state.zoom.end) { state.files = null; } - if (action.start && action.end) { - state.zoom = { - start: action.start, - end: action.end, - previous: state.zoom, - }; - state.currentRoute = state.routes?.find((route) => route.log_id === action.log_id); + const r = state.routes?.find((route) => route.log_id === action.log_id); + if (action.log_id && r) { + state.currentRoute = r; + if (!action.start) { + state.zoom = { + start: 0, + end: state.currentRoute.duration, + previous: state.zoom, + } + } else { + state.zoom = { + start: action.start, + end: action.end, + previous: state.zoom, + }; + } } else { state.zoom = null; state.loop = null; diff --git a/src/timeline/segments.js b/src/timeline/segments.js index b59cd935c..54784f5dc 100644 --- a/src/timeline/segments.js +++ b/src/timeline/segments.js @@ -1,6 +1,9 @@ import * as Types from '../actions/types'; export function getSegmentFetchRange(state) { + // TODO: fix this for relative routes + return state.filter; + if (!state.zoom) { return state.filter; } From 1885658760666d98db2727f5cd2b8a57ed66b467 Mon Sep 17 00:00:00 2001 From: Adeeb Shihadeh Date: Tue, 9 Apr 2024 11:41:06 -0700 Subject: [PATCH 4/5] all relative --- src/components/DriveView/index.jsx | 7 ++++--- src/components/TimeDisplay/index.jsx | 2 +- src/components/Timeline/index.jsx | 8 ++------ src/initialState.js | 18 ++---------------- src/reducers/globalState.js | 15 +++++++++++---- 5 files changed, 20 insertions(+), 30 deletions(-) diff --git a/src/components/DriveView/index.jsx b/src/components/DriveView/index.jsx index da0377c32..859268a69 100644 --- a/src/components/DriveView/index.jsx +++ b/src/components/DriveView/index.jsx @@ -39,9 +39,10 @@ class DriveView extends Component { const backButtonDisabled = !zoom?.previousZoom && currentRouteBoundsSelected; // FIXME: end time not always same day as start time - const startDay = dayjs(currentRoute.start_time_utc_millis).format('dddd'); - const startTime = dayjs(currentRoute.start_time_utc_millis).format('MMM D @ HH:mm'); - const endTime = dayjs(currentRoute.end_time_utc_millis).format('HH:mm'); + const start = currentRoute.start_time_utc_millis + zoom.start; + const startDay = dayjs(start).format('dddd'); + const startTime = dayjs(start).format('MMM D @ HH:mm'); + const endTime = dayjs(start + (zoom.end - zoom.start)).format('HH:mm'); return (
diff --git a/src/components/TimeDisplay/index.jsx b/src/components/TimeDisplay/index.jsx index caf22b636..409292dea 100644 --- a/src/components/TimeDisplay/index.jsx +++ b/src/components/TimeDisplay/index.jsx @@ -137,7 +137,7 @@ class TimeDisplay extends Component { getDisplayTime() { const offset = currentOffset(); const { filter, currentRoute } = this.props; - const now = new Date(offset + filter.start); + const now = new Date(offset + currentRoute.start_time_utc_millis); if (Number.isNaN(now.getTime())) { return '...'; } diff --git a/src/components/Timeline/index.jsx b/src/components/Timeline/index.jsx index 4aa1f620e..3f25f01fd 100644 --- a/src/components/Timeline/index.jsx +++ b/src/components/Timeline/index.jsx @@ -323,13 +323,9 @@ class Timeline extends Component { return null; } - const range = route.duration; - let startPerc = (100 * 0) / range; - let widthPerc = (100 * route.duration) / range; - const zoomDuration = zoom.end - zoom.start; - startPerc = (100 * (route.offset - zoom.start)) / zoomDuration; - widthPerc = (100 * route.duration) / zoomDuration; + const startPerc = (100 * (-zoom.start)) / zoomDuration; + const widthPerc = (100 * route.duration) / zoomDuration; const style = { width: `${widthPerc}%`, diff --git a/src/initialState.js b/src/initialState.js index 6e55942b4..3a9b7c669 100644 --- a/src/initialState.js +++ b/src/initialState.js @@ -18,20 +18,6 @@ export function getDefaultFilter() { }; } -function getDefaultLoop(pathname) { - // in time instead of offset - // this makes it so that the timespan can change without this changing - // thats helpful to shared links and other things probably... - const zoom = getZoom(pathname); - if (zoom) { - return { - startTime: zoom.start, - duration: zoom.end - zoom.start, - }; - } - return null; -} - export default { dongleId: getDongleID(window.location.pathname), @@ -63,7 +49,7 @@ export default { }, filter: getDefaultFilter(), - zoom: getZoom(window.location.pathname), - loop: getDefaultLoop(window.location.pathname), + zoom: null, + loop: null, segmentRange: getSegmentRange(window.location.pathname), }; diff --git a/src/reducers/globalState.js b/src/reducers/globalState.js index 902936330..77541f172 100644 --- a/src/reducers/globalState.js +++ b/src/reducers/globalState.js @@ -341,10 +341,17 @@ export default function reducer(_state, action) { state.currentRoute = { ...r, }; - state.zoom = { - start: 0, - end: state.currentRoute.duration, - }; + if (state.segmentRange.start && state.segmentRange.end) { + state.zoom = { + start: state.segmentRange.start, + end: state.segmentRange.end, + }; + } else { + state.zoom = { + start: 0, + end: state.currentRoute.duration, + }; + } } } break; From dc086af891f933075767a9fdb347670a773cd51c Mon Sep 17 00:00:00 2001 From: Adeeb Shihadeh Date: Tue, 9 Apr 2024 13:15:35 -0700 Subject: [PATCH 5/5] update tests --- src/actions/history.js | 6 +-- src/actions/history.test.js | 7 ++- src/actions/index.js | 1 - src/actions/index.test.js | 4 +- src/components/TimeDisplay/index.jsx | 3 +- src/initialState.js | 2 +- src/reducers/globalState.js | 6 +-- src/timeline/playback.js | 2 +- src/timeline/playback.test.js | 22 ++++----- src/timeline/segments.js | 2 - src/timeline/segments.test.js | 69 ---------------------------- src/url.js | 2 +- 12 files changed, 24 insertions(+), 102 deletions(-) diff --git a/src/actions/history.js b/src/actions/history.js index 6a7bc0c4d..a44a7758d 100644 --- a/src/actions/history.js +++ b/src/actions/history.js @@ -17,15 +17,15 @@ export const onHistoryMiddleware = ({ dispatch, getState }) => (next) => (action dispatch(selectDevice(pathDongleId, false)); } - // TODO: this should redirect to a log id const pathZoom = getZoom(action.payload.location.pathname); if (pathZoom !== state.zoom) { + console.debug("TODO: this should redirect to a log id") //dispatch(pushTimelineRange(pathZoom?.start, pathZoom?.end, false)); } const pathSegmentRange = getSegmentRange(action.payload.location.pathname); - if (pathSegmentRange != state.segmentRange) { - dispatch(pushTimelineRange(pathSegmentRange?.log_id, pathSegmentRange?.start, pathSegmentRange?.end, true)); + if (pathSegmentRange !== state.segmentRange) { + dispatch(pushTimelineRange(pathSegmentRange?.log_id, pathSegmentRange?.start, pathSegmentRange?.end, false)); } const pathPrimeNav = getPrimeNav(action.payload.location.pathname); diff --git a/src/actions/history.test.js b/src/actions/history.test.js index 47ccc7196..b802f11f4 100644 --- a/src/actions/history.test.js +++ b/src/actions/history.test.js @@ -77,7 +77,6 @@ describe('history middleware', () => { }; invoke(action); expect(next).toHaveBeenCalledWith(action); - expect(store.dispatch).toHaveBeenCalledTimes(1); expect(store.dispatch).toHaveBeenCalledWith(fakeInner); expect(actionsIndex.selectDevice).toHaveBeenCalledWith('0000aaaa0000aaaa', false); }); @@ -96,14 +95,14 @@ describe('history middleware', () => { type: LOCATION_CHANGE, payload: { action: 'POP', - location: { pathname: '0000aaaa0000aaaa/1230/1234' }, + location: { pathname: '0000aaaa0000aaaa/00000014--55a0b1280e/1230/1234' }, }, }; invoke(action); expect(next).toHaveBeenCalledWith(action); expect(store.dispatch).toHaveBeenCalledTimes(1); expect(store.dispatch).toHaveBeenCalledWith(fakeInner); - expect(actionsIndex.pushTimelineRange).toHaveBeenCalledWith(1230, 1234, false); + expect(actionsIndex.pushTimelineRange).toHaveBeenCalledWith('00000014--55a0b1280e', 1230, 1234, false); }); it('should call prime nav with history', async () => { @@ -130,7 +129,7 @@ describe('history middleware', () => { expect(store.dispatch).toHaveBeenCalledTimes(2); expect(store.dispatch).toHaveBeenCalledWith(fakeInner); expect(store.dispatch).toHaveBeenCalledWith(fakeInner2); - expect(actionsIndex.pushTimelineRange).toHaveBeenCalledWith(undefined, undefined, false); + expect(actionsIndex.pushTimelineRange).toHaveBeenCalledWith(undefined, undefined, undefined, false); expect(actionsIndex.primeNav).toHaveBeenCalledWith(true); }); }); diff --git a/src/actions/index.js b/src/actions/index.js index 623f0735e..a21bf4de8 100644 --- a/src/actions/index.js +++ b/src/actions/index.js @@ -305,7 +305,6 @@ export function checkRoutesData() { ...r, url: r.url.replace('chffrprivate.blob.core.windows.net', 'chffrprivate.azureedge.net'), log_id: r.fullname.split('|')[1], - //offset: Math.round(startTime), duration: endTime - startTime, start_time_utc_millis: startTime, end_time_utc_millis: endTime, diff --git a/src/actions/index.test.js b/src/actions/index.test.js index 90449a0f2..f45871236 100644 --- a/src/actions/index.test.js +++ b/src/actions/index.test.js @@ -15,7 +15,7 @@ describe('timeline actions', () => { it('should push history state when editing zoom', () => { const dispatch = jest.fn(); const getState = jest.fn(); - const actionThunk = pushTimelineRange(123, 1234); + const actionThunk = pushTimelineRange("log_id", 123, 1234); getState.mockImplementationOnce(() => ({ dongleId: 'statedongle', @@ -23,6 +23,6 @@ describe('timeline actions', () => { zoom: {}, })); actionThunk(dispatch, getState); - expect(push).toBeCalledWith('/statedongle/123/1234'); + expect(push).toBeCalledWith('/statedongle/log_id/123/1234'); }); }); diff --git a/src/components/TimeDisplay/index.jsx b/src/components/TimeDisplay/index.jsx index 409292dea..56720138e 100644 --- a/src/components/TimeDisplay/index.jsx +++ b/src/components/TimeDisplay/index.jsx @@ -136,7 +136,7 @@ class TimeDisplay extends Component { getDisplayTime() { const offset = currentOffset(); - const { filter, currentRoute } = this.props; + const { currentRoute } = this.props; const now = new Date(offset + currentRoute.start_time_utc_millis); if (Number.isNaN(now.getTime())) { return '...'; @@ -299,7 +299,6 @@ const stateToProps = Obstruction({ currentRoute: 'currentRoute', zoom: 'zoom', desiredPlaySpeed: 'desiredPlaySpeed', - filter: 'filter', }); export default connect(stateToProps)(withStyles(styles)(TimeDisplay)); diff --git a/src/initialState.js b/src/initialState.js index 3a9b7c669..18ef0d315 100644 --- a/src/initialState.js +++ b/src/initialState.js @@ -1,4 +1,4 @@ -import { getDongleID, getZoom, getPrimeNav, getSegmentRange } from './url'; +import { getDongleID, getPrimeNav, getSegmentRange } from './url'; import * as Demo from './demo'; export function getDefaultFilter() { diff --git a/src/reducers/globalState.js b/src/reducers/globalState.js index 77541f172..d86ce267e 100644 --- a/src/reducers/globalState.js +++ b/src/reducers/globalState.js @@ -336,10 +336,10 @@ export default function reducer(_state, action) { }; if (!state.currentRoute && state.segmentRange) { - const r = state.routes?.find((route) => route.log_id === state.segmentRange.log_id); - if (r) { + const curr = state.routes?.find((route) => route.log_id === state.segmentRange.log_id); + if (curr) { state.currentRoute = { - ...r, + ...curr, }; if (state.segmentRange.start && state.segmentRange.end) { state.zoom = { diff --git a/src/timeline/playback.js b/src/timeline/playback.js index 12ea4b9a5..3c1a4c039 100644 --- a/src/timeline/playback.js +++ b/src/timeline/playback.js @@ -74,7 +74,7 @@ export function reducer(_state, action) { break; } - if (state.currentRoute && state.currentRoute.videoStartOffset && state.loop && state.zoom && state.filter + if (state.currentRoute && state.currentRoute.videoStartOffset && state.loop && state.zoom && state.loop.startTime === state.zoom.start && state.zoom.start === 0) { const loopRouteOffset = state.loop.startTime - state.zoom.start; if (state.currentRoute.videoStartOffset > loopRouteOffset) { diff --git a/src/timeline/playback.test.js b/src/timeline/playback.test.js index 5d56cbbc4..54e02546c 100644 --- a/src/timeline/playback.test.js +++ b/src/timeline/playback.test.js @@ -5,11 +5,7 @@ import { bufferVideo, pause, play, reducer, seek, selectLoop } from './playback' const makeDefaultStruct = function makeDefaultStruct() { return { - filter: { - start: Date.now(), - end: Date.now() + 100000, - }, - desiredPlaySpeed: 1, // 0 = stopped, 1 = playing, 2 = 2x speed... multiplier on speed + desiredPlaySpeed: 1, // 0 = stopped, 1 = playing, 2 = 2x speed offset: 0, // in miliseconds from the start startTime: Date.now(), // millisecond timestamp in which play began @@ -81,14 +77,14 @@ describe('playback', () => { // set up loop state = reducer(state, play()); state = reducer(state, selectLoop( - state.filter.start + 1000, - state.filter.start + 2000, + 1000, + 2000, )); - expect(state.loop.startTime).toEqual(state.filter.start + 1000); + expect(state.loop.startTime).toEqual(1000); // seek past loop end boundary a state = reducer(state, seek(3000)); - expect(state.loop.startTime).toEqual(state.filter.start + 1000); + expect(state.loop.startTime).toEqual(1000); expect(state.offset).toEqual(2000); }); @@ -99,14 +95,14 @@ describe('playback', () => { // set up loop state = reducer(state, play()); state = reducer(state, selectLoop( - state.filter.start + 1000, - state.filter.start + 2000, + 1000, + 2000, )); - expect(state.loop.startTime).toEqual(state.filter.start + 1000); + expect(state.loop.startTime).toEqual(1000); // seek past loop end boundary a state = reducer(state, seek(0)); - expect(state.loop.startTime).toEqual(state.filter.start + 1000); + expect(state.loop.startTime).toEqual(1000); expect(state.offset).toEqual(1000); }); diff --git a/src/timeline/segments.js b/src/timeline/segments.js index 54784f5dc..413f3e526 100644 --- a/src/timeline/segments.js +++ b/src/timeline/segments.js @@ -1,5 +1,3 @@ -import * as Types from '../actions/types'; - export function getSegmentFetchRange(state) { // TODO: fix this for relative routes return state.filter; diff --git a/src/timeline/segments.test.js b/src/timeline/segments.test.js index 34f98410b..592c5c67f 100644 --- a/src/timeline/segments.test.js +++ b/src/timeline/segments.test.js @@ -1,78 +1,9 @@ /* eslint-env jest */ -import { getCurrentRoute } from '.'; import { hasRoutesData } from './segments'; -import { getSegmentNumber } from '../utils'; export const SEGMENT_LENGTH = 1000 * 60; -const routes = [{ - fullname: '99c94dc769b5d96e|2018-04-09--10-10-00', - offset: 36600000, - duration: 2558000, - segment_numbers: Array.from(Array(43).keys()), - segment_offsets: Array.from(Array(43).keys()).map((i) => i * SEGMENT_LENGTH + 36600000), - events: [{ - time: 36600123, - type: 'event', - }], -}, { - fullname: '99c94dc769b5d96e|2018-04-09--11-29-08', - offset: 41348000, - duration: 214000, - segment_numbers: Array.from(Array(4).keys()), - segment_offsets: Array.from(Array(4).keys()).map((i) => i * SEGMENT_LENGTH + 41348000), - events: [{ - time: 41348123, - type: 'event', - }], -}]; - describe('segments', () => { - it('finds current segment', async () => { - const [route] = routes; - let r = getCurrentRoute({ - routes, - offset: route.offset, - desiredPlaySpeed: 1, - startTime: Date.now(), - }); - expect(r.fullname).toBe(route.fullname); - expect(getSegmentNumber(r, route.offset)).toBe(0); - - r = getCurrentRoute({ - routes, - offset: route.offset + SEGMENT_LENGTH * 1.1, - desiredPlaySpeed: 1, - startTime: Date.now(), - }); - expect(getSegmentNumber(r, route.offset + SEGMENT_LENGTH * 1.1)).toBe(1); - }); - - it('finds last segment of a route', async () => { - const [route] = routes; - const offset = route.offset + SEGMENT_LENGTH * (route.segment_offsets.length - 1) + 1000; - const r = getCurrentRoute({ - routes, - offset, - desiredPlaySpeed: 1, - startTime: Date.now(), - }); - expect(r.fullname).toBe(route.fullname); - expect(getSegmentNumber(r, offset)).toBe(route.segment_offsets.length - 1); - }); - - it('ends last segment of a route', async () => { - const [route] = routes; - const offset = route.offset + route.duration - 10; - const r = getCurrentRoute({ - routes, - offset, - desiredPlaySpeed: 1, - startTime: Date.now() - 50, - }); - expect(getSegmentNumber(r, offset)).toBe(null); - }); - it('can check if it has segment metadata', () => { expect(hasRoutesData()).toBe(false); expect(hasRoutesData({})).toBe(false); diff --git a/src/url.js b/src/url.js index 645833b23..7c3771a3e 100644 --- a/src/url.js +++ b/src/url.js @@ -43,7 +43,7 @@ export function getPrimeNav(pathname) { let parts = pathname.split('/'); parts = parts.filter((m) => m.length); - if (parts.length === 2 && parts[0] !== 'auth' && parts[1] === 'prime') { + if (parts.length === 2 && dongleIdRegex.test(parts[0]) && parts[1] === 'prime') { return true; } return false;