"use strict"; exports.id = 64564; exports.ids = [64564]; exports.modules = { /***/ 80701: /***/ ((__unused_webpack_module, __webpack_exports__, __webpack_require__) => { /* harmony export */ __webpack_require__.d(__webpack_exports__, { /* harmony export */ "Z": () => (__WEBPACK_DEFAULT_EXPORT__), /* harmony export */ "u": () => (/* binding */ getRandomCuratedStationId) /* harmony export */ }); /* harmony import */ var lodash_range__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(64042); /* harmony import */ var lodash_range__WEBPACK_IMPORTED_MODULE_0___default = /*#__PURE__*/__webpack_require__.n(lodash_range__WEBPACK_IMPORTED_MODULE_0__); /* harmony import */ var lodash_sample__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(47657); /* harmony import */ var lodash_sample__WEBPACK_IMPORTED_MODULE_1___default = /*#__PURE__*/__webpack_require__.n(lodash_sample__WEBPACK_IMPORTED_MODULE_1__); const QURAN_CHAPTERS_COUNT = 114; const popularRecitersId = [ "7", "3", "10", "4" ]; const generatePopularRecitersAudioTracks = ()=>{ return popularRecitersId.map((reciter)=>lodash_range__WEBPACK_IMPORTED_MODULE_0___default()(1, QURAN_CHAPTERS_COUNT).map((chapter)=>({ surah: chapter.toString(), reciterId: reciter.toString() }))).flat(); }; const JUZ_AMMA_FIRST_CHAPTER = 78; const generateJuzAmmaAudioTracks = ()=>{ return popularRecitersId.map((reciter)=>lodash_range__WEBPACK_IMPORTED_MODULE_0___default()(JUZ_AMMA_FIRST_CHAPTER, QURAN_CHAPTERS_COUNT).map((chapter)=>({ surah: chapter.toString(), reciterId: reciter.toString() }))).flat(); }; const generateSurahAlKahfAudioTracks = ()=>{ return popularRecitersId.map((reciterId)=>({ surah: "18", reciterId })); }; const curatedStations = { "1": { title: "popular-recitations.title", description: "popular-recitations.description", bannerImgSrc: "/images/stations/1.jpeg", audioTracks: generatePopularRecitersAudioTracks() }, "2": { title: "yaseen-alwaqiah-al-mulk.title", description: "yaseen-alwaqiah-al-mulk.description", bannerImgSrc: "/images/stations/2.jpg", audioTracks: [ { surah: "36", reciterId: "7" }, { surah: "96", reciterId: "7" }, { surah: "67", reciterId: "7" }, ] }, "3": { title: "surah-al-kahf.title", description: "surah-al-kahf.description", bannerImgSrc: "/images/stations/3.jpeg", audioTracks: generateSurahAlKahfAudioTracks() }, "4": { title: "juz-amma.title", description: "juz-amma.description", bannerImgSrc: "/images/stations/4.jpeg", audioTracks: generateJuzAmmaAudioTracks() } }; const getRandomCuratedStationId = ()=>{ return lodash_sample__WEBPACK_IMPORTED_MODULE_1___default()(Object.keys(curatedStations)); }; /* harmony default export */ const __WEBPACK_DEFAULT_EXPORT__ = (curatedStations); /***/ }), /***/ 16868: /***/ ((__unused_webpack_module, __webpack_exports__, __webpack_require__) => { /* harmony export */ __webpack_require__.d(__webpack_exports__, { /* harmony export */ "T": () => (/* binding */ StationType) /* harmony export */ }); var StationType; (function(StationType) { StationType["Curated"] = "curated"; StationType["Reciter"] = "reciter"; })(StationType || (StationType = {})); /***/ }), /***/ 64564: /***/ ((module, __webpack_exports__, __webpack_require__) => { __webpack_require__.a(module, async (__webpack_handle_async_dependencies__, __webpack_async_result__) => { try { /* harmony export */ __webpack_require__.d(__webpack_exports__, { /* harmony export */ "P": () => (/* binding */ AudioPlayerMachineProvider), /* harmony export */ "c": () => (/* binding */ AudioPlayerMachineContext) /* harmony export */ }); /* harmony import */ var react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(20997); /* harmony import */ var react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0___default = /*#__PURE__*/__webpack_require__.n(react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__); /* harmony import */ var react__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(16689); /* harmony import */ var react__WEBPACK_IMPORTED_MODULE_1___default = /*#__PURE__*/__webpack_require__.n(react__WEBPACK_IMPORTED_MODULE_1__); /* harmony import */ var _xstate_react__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(59456); /* harmony import */ var _xstate_react__WEBPACK_IMPORTED_MODULE_2___default = /*#__PURE__*/__webpack_require__.n(_xstate_react__WEBPACK_IMPORTED_MODULE_2__); /* harmony import */ var next_translate_useTranslation__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(60866); /* harmony import */ var next_translate_useTranslation__WEBPACK_IMPORTED_MODULE_3___default = /*#__PURE__*/__webpack_require__.n(next_translate_useTranslation__WEBPACK_IMPORTED_MODULE_3__); /* harmony import */ var _actors_audioPlayer_audioPlayerMachine__WEBPACK_IMPORTED_MODULE_4__ = __webpack_require__(43882); /* harmony import */ var _actors_audioPlayer_audioPlayerPersistHelper__WEBPACK_IMPORTED_MODULE_7__ = __webpack_require__(76133); /* harmony import */ var _dls_Toast_Toast__WEBPACK_IMPORTED_MODULE_5__ = __webpack_require__(79717); /* harmony import */ var _redux_defaultSettings_defaultSettings__WEBPACK_IMPORTED_MODULE_6__ = __webpack_require__(11854); var __webpack_async_dependencies__ = __webpack_handle_async_dependencies__([_dls_Toast_Toast__WEBPACK_IMPORTED_MODULE_5__]); _dls_Toast_Toast__WEBPACK_IMPORTED_MODULE_5__ = (__webpack_async_dependencies__.then ? (await __webpack_async_dependencies__)() : __webpack_async_dependencies__)[0]; /* eslint-disable import/prefer-default-export */ const AudioPlayerMachineContext = /*#__PURE__*/ (0,react__WEBPACK_IMPORTED_MODULE_1__.createContext)({}); const LOCAL_STORAGE_PERSISTENCE_EVENT_TRIGGER = [ "CHANGE_RECITER", "SET_PLAYBACK_SPEED", "UPDATE_VOLUME", ]; const AudioPlayerMachineProvider = ({ children })=>{ const toast = (0,_dls_Toast_Toast__WEBPACK_IMPORTED_MODULE_5__/* .useToast */ .pm)(); const { t } = next_translate_useTranslation__WEBPACK_IMPORTED_MODULE_3___default()("common"); const initialXstateContext = (0,_actors_audioPlayer_audioPlayerPersistHelper__WEBPACK_IMPORTED_MODULE_7__/* .getXstateStateFromLocalStorage */ .x)(); const defaultLocaleContext = { reciterId: _redux_defaultSettings_defaultSettings__WEBPACK_IMPORTED_MODULE_6__/* .DEFAULT_RECITER.id */ .YS.id }; const audioPlayerService = (0,_xstate_react__WEBPACK_IMPORTED_MODULE_2__.useInterpret)(_actors_audioPlayer_audioPlayerMachine__WEBPACK_IMPORTED_MODULE_4__/* .audioPlayerMachine */ .g, { context: { ..._actors_audioPlayer_audioPlayerMachine__WEBPACK_IMPORTED_MODULE_4__/* .audioPlayerMachine.initialState.context */ .g.initialState.context, ...defaultLocaleContext, ...initialXstateContext } }, (state)=>{ const { playbackRate , reciterId , volume } = state.context; if (state.matches("VISIBLE.FAILED")) { toast(t("error.general"), { status: _dls_Toast_Toast__WEBPACK_IMPORTED_MODULE_5__/* .ToastStatus.Error */ .YZ.Error }); } if (LOCAL_STORAGE_PERSISTENCE_EVENT_TRIGGER.includes(state.event.type)) { (0,_actors_audioPlayer_audioPlayerPersistHelper__WEBPACK_IMPORTED_MODULE_7__/* .persistXstateToLocalStorage */ .m)({ playbackRate, reciterId, volume }); } }); return /*#__PURE__*/ react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsx(AudioPlayerMachineContext.Provider, { value: audioPlayerService, children: children }); }; __webpack_async_result__(); } catch(e) { __webpack_async_result__(e); } }); /***/ }), /***/ 43882: /***/ ((__unused_webpack_module, __webpack_exports__, __webpack_require__) => { // EXPORTS __webpack_require__.d(__webpack_exports__, { "g": () => (/* binding */ audioPlayerMachine) }); // EXTERNAL MODULE: external "lodash/random" var random_ = __webpack_require__(35526); var random_default = /*#__PURE__*/__webpack_require__.n(random_); // EXTERNAL MODULE: external "xstate" var external_xstate_ = __webpack_require__(82522); // EXTERNAL MODULE: external "xstate/lib/actions" var actions_ = __webpack_require__(44549); // EXTERNAL MODULE: external "lodash/sample" var sample_ = __webpack_require__(47657); var sample_default = /*#__PURE__*/__webpack_require__.n(sample_); // EXTERNAL MODULE: ./src/components/Radio/curatedStations.ts var curatedStations = __webpack_require__(80701); // EXTERNAL MODULE: ./src/components/Radio/types.ts var types = __webpack_require__(16868); ;// CONCATENATED MODULE: ./src/xstate/actors/radio/radioMachine.ts /* eslint-disable react-func/max-lines-per-function */ /* eslint-disable import/prefer-default-export */ const createRadioMachine = ()=>{ return (0,external_xstate_.createMachine)({ tsTypes: {}, schema: { context: {}, events: {} }, id: "radioMachine", initial: "on", context: { type: types/* StationType.Curated */.T.Curated }, states: { on: { on: { PLAY_STATION: { actions: [ "setStation", "generateRadioAudioTrack" ] }, TRACK_ENDED: { actions: "generateNextAudioTrack" } } } } }, { actions: { setStation: (0,external_xstate_.assign)({ type: (context, event)=>event.stationType, id: (context, event)=>event.id }), generateNextAudioTrack: (0,actions_.sendParent)((context)=>{ const { type , id } = context; let randomAudioTrack; if (type === types/* StationType.Curated */.T.Curated) { const station = curatedStations/* default */.Z[id]; randomAudioTrack = sample_default()(station.audioTracks); } else { randomAudioTrack = { reciterId: id, surah: random_default()(1, 114).toString() }; } return { type: "PLAY_RADIO_TRACK", shouldPlayFromRandomTimeStamp: false, reciterId: Number(randomAudioTrack.reciterId), surah: Number(randomAudioTrack.surah) }; }), generateRadioAudioTrack: (0,actions_.sendParent)((context, event)=>{ const { stationType , id } = event; let randomAudioTrack; if (stationType === types/* StationType.Curated */.T.Curated) { const station = curatedStations/* default */.Z[id]; randomAudioTrack = sample_default()(station.audioTracks); } else { randomAudioTrack = { reciterId: id, surah: random_default()(1, 114).toString() }; } return { type: "PLAY_RADIO_TRACK", shouldPlayFromRandomTimeStamp: true, reciterId: Number(randomAudioTrack.reciterId), surah: Number(randomAudioTrack.surah) }; }) } }); }; ;// CONCATENATED MODULE: ./src/xstate/actors/verseCycle/verseCycleMachine.ts /* eslint-disable jsdoc/check-tag-names */ /* eslint-disable camelcase */ /* eslint-disable @typescript-eslint/naming-convention */ /* eslint-disable react-func/max-lines-per-function */ /* eslint-disable import/prefer-default-export */ const createVerseCycleMachine = ({ timestampFrom , timestampTo , totalVerseCycle })=>/** @xstate-layout N4IgpgJg5mDOIC5QDcwCdZgMIE8DGANmAIJ4AuA9mgHQCWAdgApoVRpywDEAqowCLEAKgFEA+oICSAWQkA5AOKJQABwqxaZWhXpKQAD0QBaAEwB2AJzULxgCznjAZgAMTgBxOLAGhA5EAVktzIKDXP2MARlsbJ3CAX1jvVAxsfCJSShokzGF6CEhOXVV1TW1dAwRwu2oANjdq8PqG41dmh29fBAdTcOpzU1C3G1dw8OdHeISQego8+CQQLJTCEnIqOiYWNg5CtQ0tHXnyw2qHG2obRwdRroHzNp9-B2o-Fxs32vDTCxtq+MT0TC4ZbpNaLHJ5CA7Yr7MqIYxuaiuIYudzhO7mEbtRDhJx+c6uaqmALdGxo0nmP4LAFLNKrGgAMwYtFgAAtIFC9qVDtiHK5eqY7Gi3F9og4-FiEPY+aYImZqh9zNU-KZKYsgbSMhySgdQEclXyLg4rkb+i87hLDGj8S8PFdXATusZfhMgA */ (0,external_xstate_.createMachine)({ context: { timestampFrom, timestampTo, totalVerseCycle, currentVerseCycle: 1 }, tsTypes: {}, id: "verseCycleActor", initial: "inProgress", states: { inProgress: { on: { UPDATE_VERSE_TIMING: { actions: "updateVerseTiming" }, TIMESTAMP_UPDATED: { cond: "verseEnded", target: "verseEnded" } } }, verseEnded: { always: [ { actions: "repeatSameAyah", description: "Inc context.currentVerseCycleNumber and sendParent(REPEAT_SAME_AYAH)", cond: "verseRepeatOnProgress", target: "inProgress" }, { description: "When repeat cycle is done, transition to finished state", target: "finished" }, ] }, finished: { entry: "sendVerseRepeatFinished", description: "Send VERSE_REPEAT_FINISHED event", type: "final" } } }, { guards: { verseEnded: (context, event)=>{ return event.timestamp >= context.timestampTo - 200 // 200ms is a buffer for the verse end time ; }, verseRepeatOnProgress: (context)=>{ return context.currentVerseCycle < context.totalVerseCycle; } }, actions: { updateVerseTiming: (0,actions_.pure)((context, event)=>{ return (0,external_xstate_.assign)({ timestampFrom: event.timestampFrom, timestampTo: event.timestampTo }); }), sendVerseRepeatFinished: (0,actions_.sendParent)(()=>{ return { type: "VERSE_REPEAT_FINISHED" }; }), repeatSameAyah: (0,actions_.pure)((context)=>{ return [ (0,external_xstate_.assign)({ currentVerseCycle: context.currentVerseCycle + 1 }), (0,actions_.sendParent)({ type: "REPEAT_SAME_AYAH" }), ]; }) } }); ;// CONCATENATED MODULE: ./src/xstate/actors/rangeCycle/rangeCycleMachine.ts /* eslint-disable max-lines */ /* eslint-disable @typescript-eslint/naming-convention */ /* eslint-disable jsdoc/check-tag-names */ /* eslint-disable react-func/max-lines-per-function */ /* eslint-disable import/prefer-default-export */ const createRangeCycleMachine = ({ totalRangeCycle , totalVerseCycle , verseTimings , fromVerseNumber , toVerseNumber , })=>/** @xstate-layout N4IgpgJg5mDOIC5QCcCGA7GBhAngYwBswBBPAFwHtkA6AS3QAVkKpk5YBiAFQEkBZAKIBlLsT4MA+gFUGAEWJcBsxKAAOFWLTK0K6FSAAeiAGwB2AIzUALACZTAVnMAOZ1fsAGYwBoQORI+pjAGYnKwBOELdw+2NjAF84nzRMMFxCEnIqOkZmVnYOACUBBgEFCSExAQliAE1iAAl9dU1tXX0jBCszajCnd3cnIKtPczDzUysfPwQAWnGransxoLD3GydTTatxhKSMbHwiUkoaeiYWNlhOIpKygDkBAA0uarrGpBBmrR09D46YsLUCY2MZhexDGz2KxOKaIWyWcxQjaOdzbIJBey7EDJA7pY5ZM65S7XYqlF4MIoANVeDSaGm+bT+-mMgOBoPBtiRsIQQVMQWoiOhDnMqPM6MxiWx+1ShwyJ2y5zyVw4lIEBSEVRuZIkADEeHceEJ6ko6S0fu1EDMbCyBcEgu4xZs7PZuXN3IFrWZwqZUT6nMYbFicTK8ZkaMGBOgIJAOKaGb9QB0hvyHGEbNb7FD3B5Jr44TbBciRWiMQlJegKNH4B9g2kjmGFUT2HHWgnDIh1gtzFYgnYwsZtmYzNzTE5Ar2QRYwtEVk4g9K63KshGo5AW+ambMMQswhFeQN+k5kdyzGPjODwTYMU4bOZ5ylF-iaAAzei0WAACzXHy+rYtW+zRZwhZUxgncXsb25MFLD6exIWCMUYicMJ71xesTnXRlE0tXkx13dE-UPY881mGwrFMRZQNCOw3HMMj1jLOIgA */ (0,external_xstate_.createMachine)({ context: { verseCycleActor: null, totalVerseCycle, totalRangeCycle, currentRangeCycle: 1, fromVerseNumber, toVerseNumber, currentVerseNumber: fromVerseNumber, verseTimings: verseTimings }, tsTypes: {}, id: "rangeCycleActor", initial: "inProgress", states: { inProgress: { entry: "spawnVerseCycleActor", on: { UPDATE_VERSE_TIMINGS: { actions: "updateVerseTimings" }, TIMESTAMP_UPDATED: { actions: "forwardtimestampToVerseActor", description: "Receive TIMESTAMP_UPDATED event from parent. Forward to verseCycleActor" }, REPEAT_SAME_AYAH: { actions: "repeatSameAyah", description: "Event from verseCycleActor. forward sendParent(REPEAT_SAME_AYAH)" }, REPEAT_NEXT_AYAH: { actions: "repeatNextAyah" }, REPEAT_PREV_AYAH: { actions: "repeatPreviousAyah" }, REPEAT_SELECTED_AYAH: { actions: "repeatSelectedAyah" }, VERSE_REPEAT_FINISHED: [ { cond: "rangeEnded", target: "rangeEnded" }, { actions: "spawnNextAyahActor" }, ] } }, rangeEnded: { description: "State where we reached the end of the range. Deciding whether to repeat or finish", always: [ { actions: "repeatCycle", description: "When range cycle is not finished yet. Inc context.currentRangeCycle, respawn verseCycleActor and sendPlayFromAyah", cond: "rangeCycleOnProgress", target: "inProgress" }, { description: "When range cycle is finished, transition to finished state", cond: "rangeCycleFinished", target: "finished" }, ] }, finished: { entry: "sendRangeRepeatFinished", description: "Send RANGE_REPEAT_FINISHED to parent", type: "final" } } }, { guards: { rangeEnded: (context)=>{ return context.currentVerseNumber === toVerseNumber; }, rangeCycleOnProgress: (context)=>{ return context.currentRangeCycle < context.totalRangeCycle; }, rangeCycleFinished: (context)=>{ return context.currentRangeCycle >= context.totalRangeCycle; } }, actions: { repeatSelectedAyah: (0,actions_.pure)((context, event)=>{ const { ayahNumber } = event; const selectedVerseTiming = context.verseTimings[ayahNumber - 1]; return [ (0,actions_.stop)(context.verseCycleActor.id), (0,actions_.assign)({ currentVerseNumber: ayahNumber, verseCycleActor: (0,external_xstate_.spawn)(createVerseCycleMachine({ timestampFrom: selectedVerseTiming.timestampFrom, timestampTo: selectedVerseTiming.timestampTo, totalVerseCycle: context.totalVerseCycle })) }), ]; }), // @ts-ignore updateVerseTimings: (0,actions_.pure)((context, event)=>{ const curentVerseTiming = event.verseTimings[context.currentVerseNumber - 1]; return [ (0,actions_.assign)({ verseTimings: event.verseTimings }), (0,actions_.send)({ type: "UPDATE_VERSE_TIMING", timestampFrom: curentVerseTiming.timestampFrom, timestampTo: curentVerseTiming.timestampTo }, { to: context.verseCycleActor.id }), ]; }), repeatNextAyah: (0,actions_.pure)((context)=>{ const currentIndex = context.currentVerseNumber - 1; const nextVerseTiming = context.verseTimings[currentIndex + 1]; const nextVerseNumber = context.currentVerseNumber + 1; if (nextVerseNumber > toVerseNumber) { return [ (0,actions_.stop)(context.verseCycleActor.id), (0,actions_.sendParent)({ type: "RANGE_REPEAT_FINISHED" }), ]; } return [ (0,actions_.stop)(context.verseCycleActor.id), (0,actions_.assign)({ currentVerseNumber: nextVerseNumber, verseCycleActor: (0,external_xstate_.spawn)(createVerseCycleMachine({ timestampFrom: nextVerseTiming.timestampFrom, timestampTo: nextVerseTiming.timestampTo, totalVerseCycle: context.totalVerseCycle })) }), ]; }), repeatPreviousAyah: (0,actions_.pure)((context)=>{ const currentIndex = context.currentVerseNumber - 1; const prevVerseTiming = context.verseTimings[currentIndex - 1]; const prevVerseNumber = context.currentVerseNumber - 1; return [ (0,actions_.stop)(context.verseCycleActor.id), (0,actions_.assign)({ currentVerseNumber: prevVerseNumber, verseCycleActor: (0,external_xstate_.spawn)(createVerseCycleMachine({ timestampFrom: prevVerseTiming.timestampFrom, timestampTo: prevVerseTiming.timestampTo, totalVerseCycle: context.totalVerseCycle })) }), ]; }), spawnNextAyahActor: (0,actions_.pure)((context)=>{ const currentIndex = context.currentVerseNumber - 1; const currentVerseTiming = context.verseTimings[currentIndex]; const nextVerseTiming = context.verseTimings[currentIndex + 1]; const nextVerseNumber = context.currentVerseNumber + 1; const previousVerseDuration = Math.abs(currentVerseTiming.duration); return [ (0,actions_.stop)(context.verseCycleActor.id), (0,actions_.sendParent)({ type: "REPEAT_AYAH", verseNumber: nextVerseNumber, verseDuration: previousVerseDuration }), (0,actions_.assign)({ verseCycleActor: (0,external_xstate_.spawn)(createVerseCycleMachine({ timestampFrom: nextVerseTiming.timestampFrom, timestampTo: nextVerseTiming.timestampTo, totalVerseCycle: context.totalVerseCycle })), currentVerseNumber: nextVerseNumber }), ]; }), /** * forward TIMESTAMP_UPDATED event to verseCycleActor */ forwardtimestampToVerseActor: (0,actions_.forwardTo)((context)=>{ return context.verseCycleActor; }), /** * Forward the event to parent */ repeatSameAyah: (0,actions_.sendParent)((context)=>{ const verseTiming = context.verseTimings[context.currentVerseNumber - 1]; const verseDuration = verseTiming.duration; return { type: "REPEAT_AYAH", verseNumber: context.currentVerseNumber, verseDuration }; }), /** * Repeat Cycle * - Increment currentRangeCycle * - respawn verseCycleActor * - send to parent PLAY_FROM_AYAH */ repeatCycle: (0,actions_.pure)((context)=>{ const verseTiming = context.verseTimings[fromVerseNumber - 1]; const verseDuration = verseTiming.duration; return [ (0,actions_.stop)(context.verseCycleActor.id), (0,actions_.assign)({ currentRangeCycle: context.currentRangeCycle + 1, verseCycleActor: (0,external_xstate_.spawn)(createVerseCycleMachine({ timestampFrom: verseTiming.timestampFrom, timestampTo: verseTiming.timestampTo, totalVerseCycle: context.totalVerseCycle })), currentVerseNumber: fromVerseNumber }), (0,actions_.sendParent)({ type: "REPEAT_AYAH", verseNumber: context.fromVerseNumber, verseDuration }), ]; }), sendRangeRepeatFinished: (0,actions_.pure)(()=>{ return (0,actions_.sendParent)({ type: "RANGE_REPEAT_FINISHED" }); }), /** * Spawn verseCycleActor, and assign it to context */ spawnVerseCycleActor: (0,actions_.assign)({ verseCycleActor: (context)=>{ const curentVerseTiming = context.verseTimings[context.currentVerseNumber - 1]; return (0,external_xstate_.spawn)(createVerseCycleMachine({ timestampFrom: curentVerseTiming.timestampFrom, timestampTo: curentVerseTiming.timestampTo, totalVerseCycle: context.totalVerseCycle })); } }) } }); ;// CONCATENATED MODULE: ./src/xstate/actors/repeatMachine/repeatMachine.ts /* eslint-disable jsdoc/check-tag-names */ /* eslint-disable react-func/max-lines-per-function */ /* eslint-disable import/prefer-default-export */ const createRepeatMachine = ({ totalRangeCycle , totalVerseCycle , verseTimings , fromVerseNumber , toVerseNumber , delayMultiplier , })=>/** @xstate-layout N4IgpgJg5mDOIC5QCcwAcwEMAuBZTAxgBYCWAdmAHTkAKyA9lKrLAMQT0XVkBu9A1lWSYyMAMIBPAgBsw+YuTCJQaerBLYSnZSAAeiACwGAzJQAcARgAMAVmMWzATmOOrZswBoQExNceVHdwB2CwsbCwMguwA2AF94rzJ6CDgdVAwceVIuWgYmOHgkEFV1TW0i-QQrLx8EaLjYr3SsPEJsqgAzchJYIkgdEo0tMh1Kg0cLSisAJgMbRyC3aKsgoLmaxGMzA0pohetZ6LszNZsEkGbMtsUBtSHy0EqAWlmNhCfogLMbOZsbbbszlm8XiQA */ (0,external_xstate_.createMachine)({ context: { verseTimings, fromVerseNumber, toVerseNumber, delayMultiplier, repeatSettings: { totalRangeCycle, totalVerseCycle }, rangeCycleActor: null }, tsTypes: {}, id: "repeatMachine", initial: "inProgress", states: { inProgress: { entry: "spawnRangeCycleActor", on: { UPDATE_VERSE_TIMINGS: { actions: "updateVerseTimings" }, TIMESTAMP_UPDATED: { actions: "forwardToRangeCycleActor" }, REPEAT_AYAH: { actions: "repeatAyah" }, RANGE_REPEAT_FINISHED: { target: "finished" }, REPEAT_NEXT_AYAH: { actions: "repeatNextAyah" }, REPEAT_PREV_AYAH: { actions: "repeatPreviousAyah" }, REPEAT_SELECTED_AYAH: [ { cond: "selectedAyahIsNotInRange", target: "finished" }, { actions: "repeatSelectedAyah" }, ] } }, finished: { type: "final", entry: "sendRepeatFinished" } } }, { guards: { selectedAyahIsNotInRange: (context, event)=>{ const { ayahNumber } = event; return ayahNumber < fromVerseNumber || ayahNumber > toVerseNumber; } }, actions: { repeatSelectedAyah: (0,actions_.pure)((context, event)=>{ return (0,actions_.send)({ type: "REPEAT_SELECTED_AYAH", ayahNumber: event.ayahNumber }, { to: context.rangeCycleActor.id }); }), repeatNextAyah: (0,actions_.pure)(()=>{ return (0,actions_.send)({ type: "REPEAT_NEXT_AYAH" }, { to: (context)=>context.rangeCycleActor }); }), repeatPreviousAyah: (0,actions_.pure)(()=>{ return (0,actions_.send)({ type: "REPEAT_PREV_AYAH" }, { to: (context)=>context.rangeCycleActor }); }), sendRepeatFinished: (0,actions_.sendParent)({ type: "REPEAT_FINISHED" }), repeatAyah: (0,actions_.pure)((context, event)=>{ const verseDelay = event.verseDuration * context.delayMultiplier; return (0,actions_.sendParent)({ type: "REPEAT_AYAH", ayahNumber: event.verseNumber, verseDelay }); }), forwardToRangeCycleActor: (0,actions_.forwardTo)((context)=>{ return context.rangeCycleActor; }), updateVerseTimings: (0,actions_.pure)((context, event)=>[ (0,external_xstate_.assign)({ verseTimings: event.verseTimings }), (0,actions_.send)({ type: "UPDATE_VERSE_TIMINGS", verseTimings: event.verseTimings }, { to: context.rangeCycleActor.id }), ]), spawnRangeCycleActor: (0,external_xstate_.assign)({ rangeCycleActor: (context)=>{ return (0,external_xstate_.spawn)(createRangeCycleMachine({ totalRangeCycle: context.repeatSettings.totalRangeCycle, totalVerseCycle: context.repeatSettings.totalVerseCycle, verseTimings: context.verseTimings, fromVerseNumber: context.fromVerseNumber, toVerseNumber: context.toVerseNumber })); } }) } }); // EXTERNAL MODULE: ./src/xstate/actors/audioPlayer/audioPlayerMachineHelper.ts + 1 modules var audioPlayerMachineHelper = __webpack_require__(93608); // EXTERNAL MODULE: ./src/utils/datetime.ts var datetime = __webpack_require__(76410); ;// CONCATENATED MODULE: ./src/xstate/actors/audioPlayer/audioPlayerMachine.ts /* eslint-disable no-param-reassign */ /* eslint-disable import/prefer-default-export */ /* eslint-disable no-restricted-syntax */ /* eslint-disable jsdoc/check-tag-names */ /* eslint-disable max-lines */ /** * Note on Safari `onWaiting` hack. * ---- * ISSUES * 1) Safari does not fire `onWaiting` event when audio is buffering. * It will just triggger `PAUSE` and immediately followed by `ENDED` state. * as the result, the audio player will enter the `ended` state. * * If we `.play()` the audio player again, it will start playing from the beginning. * * 2) If we set the currentTime to be, audioplayer.currentTime = context.elapsed - 000.1 * And then do `.play()` * - The audio player will continue playing the audio, the onTimeUpdate event will continue to be triggered * - But there will be no sound. Since the data is actually not yet available * - On the background, safari will attempt to continue fetch mp3 data. Once the data is available. PROGRESS event will be triggered * - and then the audio player will continue from the last played position (based on `context.elapsed`) * * Workaround we do right now * 1) When the audio PAUSE, is trigger, we enter PAUSED.ACTIVE state. * 2) Followed by an END state, we just trigger `continueFromLastTimestamp`. Which basically set the currentTime to be `context.elapsed` + `.play()` * 3) The audio will enter PLAYING.LOADING, (and then enter PLAYING.ACTIVE for a split second caused by SEEKED, and the enter PLAYING.LOADING again caused by WAITING event) * 4) The audioplayer will continue download progress in the background. And then CAN_PLAY will be triggered. -> The audio player will enter PLAYING.ACTIVE again * * Note * - CAN_PLAY and WAITING here. Are not natively triggered by the browser. It's artifial/simulated @see AudioPlayer.tsx onTimeUpdate for the implementation details * - continueFromLastTimestamp will not be called when the audio is `isAudioAlmostEnded`. Because in this case the safari behavior is correct. The audio is ended. * so no need to continue downloading and playing the audio * */ const audioPlayerMachine = /** @xstate-layout N4IgpgJg5mDOIC5QEMCuECWB7ACgG2QE8wAnAOgAkBJAERoFEA5AYhwBkBBATQH0AlDjSoB5RKAAOWWBgAu2AHZiQAD0QAOAJxkADJo0A2DWu0B2AIxqTAZgBMAGhCFEAVltkALBq-7DJ5140rAF8ghzRMXAJicmo6JlZOXgEhYR4AFQEAYQBpJUlpOSxFJBVEK20zMhNNGzV9GzN3bWcLBycEG2sPAM99E20GmytnELD0bHwiUkpaBhZ2bh5uDgo8qVkFJVUEcsrqjVr6xubWx0R3KzVur2H9Y2MbZ3dRkHCJqOnYuYTFgGUAVQEqxK+Q2RS2ZQqVRqdQaTRaajaiH0Zkqni87mM7gad2eoVe40iUxis3iv3oaR4Cy4ACEODkeL8cPR6DQ1gVNiVtmZtFYyGp-O4fEN9M41FYDEidmoruiNCYbF5nNptEKTC83kTojM4ixMhQOIwAOL0fj0TJUNL0PjssHFUDcixkMxWXH+ZV+Mz+KU2dzua4GEw3cVeDWEybagBqVF+VBpbHoZABQJ4AFkY6mOGl9cxMsJGAAxKh8VNUxJpjNZ-WsxmAla2wr20oIVGi508-qGMz6Wx1KUtCVVF0yqyuoXisMRCPTaOx+OJ5MrCu-TPZii5w2ZehsMuLdMrqsUGuL4ESdaNiEtizOdumbRdnuHKVex5kALmKx+J4KtST97EshZzjBMyA4f4Ul3LhrR4KhGEtKgs1ZMgcDA8kaFAzI0ioSN6GYNJhCNI0EwbTkHUhfRtDIRUFU8MwNG7FUTB9GUTCo45nBsQY+ncdV8U1adyCA+dQPAkRIOg2D4MQ9CUP+NCMKwnDmHJehchBc9SObR5zB0ao-B4lFDF9H0-T2F1+gefplTxMYpw+QSY2AxMwIg6kJLgrDpOQ1CkPpRTcN+NIODYNgSPBLlEG0ypTEsb9DIOdwfUMf0P3MDR3DMGxtA0Zo-y1GdHOElyxLcvgYI8hCrRknz0L87DcOpMKm22coKKo+VfXo+iKNMKVyi6BpLiMCpdDo4I+PDezAMKkDitSUryqkqrvLk3zMPq5gmDZdSOXCsidlVSjqM6uiGN6s4dkCG9UvFXozGqfQ8oE6a51m0T5sSdylqQ2T5LYYRBFgo1mEYegAA1KWWU8QFBC8Io6awbwFLK1B49xnCDEy7iHT9UYeTKnqmoS3tcz6yskzzlt+pD-sB41WD4ehIyWLh6x2u1L06YZ+Q43Q0YxjQfSy1iP1FTRVXS0dCYA4nnPe8TyYqrzqfQ2mhHpgsOCoUL2bh-b0fo517mcayeKGZ8Whvd9MRldLON-Ca7Jlma5dJ7gvspn6arINWgY3RhIKazmKJsMhXAMUVamol0fQlPkP00YwXVsIZpajF2RLdqDFe+9CGESP3QYhlm2bPXbmshYx2porqzqYi77pla4rMVQxmhsNOCte12SrJxbPbz7duD9nBGeZqGg-h8oq+O2jusYkzLDYiV-DUIYcod2z-3T7vM9792c4Hsh8+H+nlFgGRkBkMAyGQAAza+SAAChwvhyR4E+uAASmYfiiYzuaCt+6VSQp-IGk99qtSOh1OeddmKDkGrbE2wxVSdwcrvQBC0KYgJkgXY0CkNr4UIsRXWmkWqfi0CYC4qIYTUT6llLQg1rD3isNiAYaCXpOT3h9A+wDlZ4KNAQpSjNmRZhLtDWGZCygUKqNQiwBw17yj6tif0TDOjNB4mKXiW98roK4Zgvu2D+Gn0EXVJSKk1Jlw5lPUUlQJRGA0MqCUMV67tAaPeHmfQvCmGcD2DhstuFAKMVTARQiApBRChA5sroWhkHsZoJxOU9Kx38J4tQPIhT3m0QSJ2O99HyywUrEJJiwmbUYNtKxetmwZTaiiHK6U-BGAVElV8ApuJZJysg-xACCmGKKT9UJZjcL-BwDQRC6QqDpmNFElqQoUpyNoUoi6jwPG3B8LCRothHqO23l3fJWcPY4OQoM9aSlqYzOkUGWRVgaEKLoRdV0zRl4mFFC8u4SpukYN6bw4JAySm+3pkXSGrMJEaT2tE8U+hnTWE4sqIY90MY+k2W+LwVl6gDBRJ8-Z+9s58OKVwIGPsAbq2BqPJm4iLnSldNClOcKbl+FcYgCwa8UXyl8aqMUzRsl-2dl8g5h8jnUkJQC4GmttaUsyZUCwugTaqjNlYZ8tgrZeFRmKYYDDuWTV5dinhuLfm4P+cSv2mRDSB1IeClqdxQ51F0M0dlwxGUdGaFcNpDj7x0XYTs3RnCirfL1f09CW1WTKRZJYmGYKK4dFYVcAwBgZTZXSfdBVF0mgHBxmvAUHETYaCxb6-leKkJBpoD8LglLRxXKoTc+RUclntE-K4HG+h0amFYd+XNJMcWHK8kWktFLzWRuvFoVULzeydBNj2KUmJfTpruDKROm8cm7L0XmztAru3lODdSWsQJKWDp0AZUdX4J0psuNdYc9j62hi9c9AJBifkBrID2ohRF6ASuOGQOp2VNFNPsA3DirF0RBmsPUG5fjr3-z5augtgaN3Fq3ckMSGR6RhskRaplAoh0Hqjke5N7RXCqhnT4DJJhNW5L2Su3VXaqrMBEfQMRRY4K-CPBU8N5dObdi0J4WoK8m2OPuj6JJ-IDg9lMPKIw2ydE3p6fm-VINwbAtLqx6xkDWofvKIqV0jjXR+ClAcViAR5SjkMmvUjS6fUdso2u6jZLx4grLapkTGnDCuD6M4fsfhWWOO-KYGwYHJMQa4SKs0ForRlTGUFZgEAig3wwPIAAblgAA1jfO+YAZAAGMAAWfAwDpdkKQXdGH90juw+O3DTKfB8nfAOVuHZ22JiC4zEL0FwscGYKQEgWByDiAIDIO+XWAC2ZBUsZey7l-LJBCupOHY+EzZX+zKjMpcZtGNuL1aJXTI0ZpRGUla5F6LZBYsJeS8NtLWWcviDAFfGgV9kC7oqHyC4zqjAZU4ulfsFxPOpsCCRxx63Gv0B2x-LMbWOtdbID1q+-WSBDZG+dsAl3ru3fuy6Dw5QxQvcyoqRKKbuyecMA0vo5QbKLu9bLXM-1ySUqeNa+iVavF9EVFKTQnnqjpMuCR8a-ntXzhDZSakdIGRMhZCx1DkbOiBHap+HibPfPin7OKMyTRm3o14-V3MBpjSmia5aa0lLDJhweq89KfoXkfcMOmjiRwsnq-g4DVISGcj67xxjOoxu-QGX7MTwjKJh2mbJy7XtE9+2XgN67nwAsPdm4bncSovim3WBuba-3Unu69pPM7qF4f3em-0M+HilF48OrXsMQMtvywIdECH+GnRqhh19I8F0YpLC-rw1Qs9lxuINA+eB4kfOljy0ZgWSljfWIJJdIYWwnuLo9TPRlcwcu7gjF79EfvtGxHkjSFhaZ1f9qIobi81nmgXnSoMCEfE8gsAQDgEoHl2ovhMH1635EQwAxWpeYEBo62TzLlXPqSl8olEzKyovI5gPYdwFsJscSqKTwhmnEfo62d6-qucK08kQyI+FwMahgs6CaqI1gAm6Mzo2I46ji942IXOpOqeOqQSD6KsG2JKI+Lyqi8KXoicIBbmyy1gKULo9E94XgrciBfqVGXsq0ouEanMGU-osaOBRgeB5WTqRgOMTBPYziy+3OeSFGNBKBYCO+lSUiHQHG3Q3GjivGLQjqdEyo0BgYlwzQoGFBd+5GFmWhR8Qq+C6Bu+0Sng-oLQvgMSHq94SUUBtwQYmIHuhgghMmtBoSIqZadQ3hfoFEMog0TOyyqarKPELEdEf2K+jhPclm0GxyJiZafolElatyNa5hCooc1sc6ds9hWqGhThhSKB1AgUwgfApaHh2wDQVCRhIYvingZhFslwzchmIG3Y9RZGy6TRfSKBRaEq1COgvo1gMoxBMofUQYVwTCBsnEh0KeAWmhzRA8I+jQN4XG-Rph-GDcTQUKcovI2UmU1QHcOR0xiYYqCYYhbG8MQo8oukXUoon45QgsDcgJzoKqFQAop03Y-2RqxowWuuYWIOu6WaQ4DCKoEokceeF0rgqOCc1QpgQYX+Lx5mDWsJW26+u2SJXRL+ceRukeuek6GUnma87ywsOaxJss1Oaa2e9J0+biji+O34ngo47J6hBW1JOw8hUKKoMpspspjQ5+QQQAA */ (0,external_xstate_.createMachine)({ context: { audioPlayer: null, reciterId: 7, ayahNumber: 1, elapsed: 0, downloadProgress: 0, duration: 0, audioData: undefined, playbackRate: 1, shouldPlayFromRandomTimeStamp: false, surahVersesCount: 0, repeatActor: null, radioActor: null, verseDelay: 0, volume: 1 }, tsTypes: {}, schema: { context: {}, events: {}, services: {} }, id: "audioPlayer", initial: "HIDDEN", states: { HIDDEN: { description: "Audio player is hidden in the UI", on: { PLAY_RADIO: { actions: [ "stopRepeatActor", "forwardPlayToRadioMachine" ] }, CLOSE_RADIO: { actions: [ "pauseAudio", "exitRadio" ] }, PLAY_RADIO_TRACK: { actions: "setRadioStationDetails", description: "User opens the audio player to play radio of a certain station", target: "VISIBLE" }, PLAY_AYAH: [ { actions: [ "setSurahAndAyahNumbers", "exitRadio" ], description: "User opens the audio player to play an Ayah", cond: "isUsingCustomReciterId", target: "VISIBLE.LOADING_CUSTOM_RECITER_DATA" }, { actions: [ "setSurahAndAyahNumbers", "exitRadio" ], description: "User opens the audio player to play an Ayah", target: "VISIBLE" }, ], PLAY_SURAH: [ { actions: [ "setSurahAndResetAyahNumber", "exitRadio" ], cond: "isUsingCustomReciterId", target: "VISIBLE.LOADING_CUSTOM_RECITER_DATA" }, { actions: [ "setSurahAndResetAyahNumber", "exitRadio" ], description: "User opens the audio player to play a Surah", target: "VISIBLE" }, ], SET_PLAYBACK_SPEED: { actions: "setPlaybackRate", description: "User change the playback speed" }, CHANGE_RECITER: [ { actions: "setReciterId", description: "User changes the reciter" }, ] } }, VISIBLE: { description: "Audio player is visible in the UI", initial: "LOADING_RECITER_DATA", states: { AUDIO_PLAYER_INITIATED: { description: "File has been loaded and is ready to be played", initial: "PAUSED", invoke: { src: "initMediaSession" }, states: { PAUSED: { description: "Default state of the audio player", initial: "ACTIVE", states: { ACTIVE: { on: { TOGGLE: { actions: "setElapsedTime", description: "User either clicks on the play button or presses the space key", target: "#audioPlayer.VISIBLE.AUDIO_PLAYER_INITIATED.PLAYING.ACTIVE" }, SEEKING: { description: "When the mouse or keyboard keys are clicked to jump forward/backward 5 or 10 seconds or when the user wants to navigate to a specific time.", target: "LOADING" }, WAITING: { description: "Waiting for the buffer to be filled", target: "LOADING" }, PLAY: { description: "Play the audio again", target: "#audioPlayer.VISIBLE.AUDIO_PLAYER_INITIATED.PLAYING.ACTIVE" }, END: [ { cond: "isAudioAlmostEnded", actions: "forwardEndedToRadioMachine", description: "Current file ended playing", target: "#audioPlayer.VISIBLE.AUDIO_PLAYER_INITIATED.ENDED" }, { /** * This is a hack for safari. * In safari. The audio goes to ended state once the there's not enough data to play the audio. */ actions: "continueFromLastTimestamp", target: "#audioPlayer.VISIBLE.AUDIO_PLAYER_INITIATED.PLAYING.LOADING" }, ] } }, LOADING: { description: "Audio data is being fetched", tags: "loading", on: { NEXT_AYAH: [ { actions: "repeatNextAyah", cond: "canRepeatNextAyah" }, { actions: [ "incrementAyah", "setAudioPlayerCurrentTime" ], description: "User clicks the next ayah button and it's not the last ayah of the surah already", cond: "isNotLastVerse" }, ], PREV_AYAH: [ { actions: "repeatPreviousAyah", cond: "canRepeatPrevAyah" }, { actions: [ "decrementAyah", "setAudioPlayerCurrentTime" ], description: "User clicks the previous ayah button and it's not the first ayah of the surah already", cond: "isNotFirstVerse" }, ], FAIL: { description: "The audio file failed to load", target: "#audioPlayer.VISIBLE.FAILED" }, CAN_PLAY: { target: "ACTIVE" }, SEEKED: { target: "ACTIVE" }, END: { actions: "forwardEndedToRadioMachine", description: "Current file ended playing", target: "#audioPlayer.VISIBLE.AUDIO_PLAYER_INITIATED.ENDED" } } } } }, DELAYING: { after: { VERSE_DELAY: { target: "#audioPlayer.VISIBLE.AUDIO_PLAYER_INITIATED.PLAYING.ACTIVE" } }, on: { TOGGLE: { target: "#audioPlayer.VISIBLE.AUDIO_PLAYER_INITIATED.PLAYING.ACTIVE" }, NEXT_AYAH: [ { actions: "repeatNextAyah", cond: "canRepeatNextAyah", target: "#audioPlayer.VISIBLE.AUDIO_PLAYER_INITIATED.PLAYING.ACTIVE" }, { actions: [ "incrementAyah", "setAudioPlayerCurrentTime" ], description: "User clicks the next ayah button and it's not the last ayah of the surah already", cond: "isNotLastVerse" }, ], PREV_AYAH: [ { actions: "repeatPreviousAyah", cond: "canRepeatPrevAyah", target: "#audioPlayer.VISIBLE.AUDIO_PLAYER_INITIATED.PLAYING.ACTIVE" }, { actions: [ "decrementAyah", "setAudioPlayerCurrentTime" ], description: "User clicks the previous ayah button and it's not the first ayah of the surah already", cond: "isNotFirstVerse" }, ] } }, PLAYING: { invoke: { id: "playAudio", src: "playAudio", onError: { target: "#audioPlayer.VISIBLE.AUDIO_PLAYER_INITIATED.PAUSED.ACTIVE" } }, description: "The audio player is playing the audio", initial: "ACTIVE", on: { PLAY_AYAH: [ { actions: [ "setSurahAndAyahNumbers", "exitRadio", "stopRepeatActor" ], description: "When the user chooses to play an Ayah of another Surah", cond: "isDifferentSurahAndReciter", target: "#audioPlayer.VISIBLE.LOADING_CUSTOM_RECITER_DATA" }, { actions: [ "setSurahAndAyahNumbers", "exitRadio", "stopRepeatActor" ], description: "When the user chooses to play an Ayah of another Surah", cond: "isDifferentSurah", target: "#audioPlayer.VISIBLE.LOADING_RECITER_DATA" }, { actions: [ "setSurahAndAyahNumbers", "setAudioPlayerCurrentTime" ] }, ], CHANGE_RECITER: [ { actions: [ "pauseAudio", "setReciterId", "resetElapsedTime" ], description: "User changes the reciter while the audio player is visible and might be playing", target: "#audioPlayer.VISIBLE.LOADING_RECITER_DATA" }, ] }, states: { ACTIVE: { on: { TOGGLE: { actions: [ "setElapsedTime", "pauseAudio" ], description: "User either clicks on the pause button or presses the space key", target: "#audioPlayer.VISIBLE.AUDIO_PLAYER_INITIATED.PAUSED.ACTIVE" }, REPEAT_AYAH: { actions: [ (0,external_xstate_.assign)({ ayahNumber: (context, event)=>event.ayahNumber, verseDelay: (context, event)=>event.verseDelay }), "pauseAudio", "setAudioPlayerCurrentTime", ], description: "Repeat the current ayah", target: "#audioPlayer.VISIBLE.AUDIO_PLAYER_INITIATED.DELAYING" }, SEEKING: { description: "When the mouse or keyboard keys are clicked to jump forward/backward 5 or 10 seconds or when the user wants to navigate to a specific time.", target: "LOADING" }, WAITING: { description: "Waiting for the buffer to be filled", target: "LOADING" }, END: { actions: "forwardEndedToRadioMachine", description: "The audio finished played", target: "#audioPlayer.VISIBLE.AUDIO_PLAYER_INITIATED.ENDED" }, UPDATE_TIMING: { actions: "updateTiming", description: "Update the elapsed time " }, PAUSE: { description: "Pause the audio", target: "#audioPlayer.VISIBLE.AUDIO_PLAYER_INITIATED.PAUSED.ACTIVE" } } }, LOADING: { description: "Audio data is being fetched", tags: "loading", on: { NEXT_AYAH: [ { actions: "repeatNextAyah", cond: "canRepeatNextAyah" }, { actions: [ "incrementAyah", "setAudioPlayerCurrentTime" ], description: "User clicks the next ayah button and it's not the last ayah of the surah already", cond: "isNotLastVerse" }, ], PREV_AYAH: [ { actions: "repeatPreviousAyah", cond: "canRepeatPrevAyah" }, { actions: [ "decrementAyah", "setAudioPlayerCurrentTime" ], description: "User clicks the previous ayah button and it's not the first ayah of the surah already", cond: "isNotFirstVerse" }, ], FAIL: { description: "The audio file failed to load", target: "#audioPlayer.VISIBLE.FAILED" }, CAN_PLAY: { target: "ACTIVE" }, PAUSE: { description: "Pause the audio", target: "#audioPlayer.VISIBLE.AUDIO_PLAYER_INITIATED.PAUSED.ACTIVE" }, SEEKED: { target: "ACTIVE" } } } } }, HISTORY: { history: "shallow", type: "history" }, ENDED: { on: { SEEKING: { description: "When the mouse or keyboard keys are clicked to jump forward/backward 5 or 10 seconds or when the user wants to navigate to a specific time.", target: "PAUSED" }, PLAY: { description: "Play the audio again", target: "PLAYING" }, PLAY_AYAH: [ { actions: [ "setSurahAndAyahNumbers", "exitRadio", "stopRepeatActor" ], description: "When the user chooses to play an Ayah of another Surah", cond: "isDifferentSurahAndReciter", target: "#audioPlayer.VISIBLE.LOADING_CUSTOM_RECITER_DATA" }, { actions: [ "setSurahAndAyahNumbers", "exitRadio", "stopRepeatActor" ], description: "When the user chooses to play an Ayah of another Surah", cond: "isDifferentSurah", target: "#audioPlayer.VISIBLE.LOADING_RECITER_DATA" }, { actions: [ "setAyahNumber", "setAudioPlayerCurrentTime", "exitRadio", "updateRepeatAyah", ], description: "When the user chooses to play an Ayah of the same Surah. (can be the same Ayah being recited)", cond: "isSameSurahAndReciter", target: "PLAYING" }, ], PLAY_SURAH: [ { actions: [ "setSurahAndResetAyahNumber", "exitRadio", "stopRepeatActor" ], cond: "isUsingCustomReciterId", target: "#audioPlayer.VISIBLE.LOADING_CUSTOM_RECITER_DATA" }, { actions: [ "setSurahAndResetAyahNumber", "exitRadio", "stopRepeatActor" ], description: "When the user chooses to play another Surah", cond: "isDifferentSurah", target: "#audioPlayer.VISIBLE.LOADING_RECITER_DATA" }, { actions: [ "exitRadio" ], description: "When the user chooses to play an Ayah of the same Surah. (can be the same Ayah being recited)", cond: "isSameSurahAndReciter", target: "PLAYING" }, ], TOGGLE: { description: "User clicks on the play button or presses the space key", target: "PLAYING" }, PLAY_RADIO_TRACK: { actions: "setRadioStationDetails", description: "User opens the audio player to play radio of a certain station", target: "#audioPlayer.VISIBLE.LOADING_RECITER_DATA" } } } }, on: { PROGRESS: { actions: "updateDownloadProgress" }, REPEAT_FINISHED: { actions: [ "stopRepeatActor", "pauseAudio" ], target: ".PAUSED.ACTIVE" }, NEXT_AYAH: [ { actions: "repeatNextAyah", cond: "canRepeatNextAyah" }, { actions: [ "incrementAyah", "setAudioPlayerCurrentTime" ], description: "User clicks the next ayah button and it's not the last ayah of the surah already", cond: "isNotLastVerse" }, ], NEXT_AUDIO_TRACK: { actions: "nextAudioTrack" }, SEEK_TO: [ { cond: "isRepeatActive", actions: "seekToAndRepeat" }, { actions: "seekTo" }, ], PREV_AYAH: [ { actions: "repeatPreviousAyah", cond: "canRepeatPrevAyah" }, { actions: [ "decrementAyah", "setAudioPlayerCurrentTime" ], description: "User clicks the previous ayah button and it's not the first ayah of the surah already", cond: "isNotFirstVerse" }, ] } }, FAILED: { description: "Either the audio file failed to load or the API to fetch the reciter + Surah data failed", after: { 500: { target: "#audioPlayer.HIDDEN" } } }, LOADING_RECITER_DATA: { description: "The reciter + Surah data are being fetched", invoke: { src: "fetchReciter", id: "fetchReciter", onDone: [ { actions: [ "setAudioData", "setAudioPlayerSource", "setAudioPlayerCurrentTime", "updateRepeatVerseTimings", ], description: "The API call to get the selected chapter + Surah succeeded", target: "#audioPlayer.VISIBLE.AUDIO_PLAYER_INITIATED.PLAYING.LOADING" }, ], onError: [ { description: "The API call to get the selected chapter + Surah failed", target: "FAILED" }, ] }, tags: "loading" }, LOADING_RECITER_DATA_AND_PAUSE: { description: "The reciter + Surah data are being fetched", invoke: { src: "fetchReciter", id: "fetchReciter", onDone: [ { actions: [ "setAudioData", "setAudioPlayerSource", "setAudioPlayerCurrentTime", "updateRepeatVerseTimings", ], description: "The API call to get the selected chapter + Surah succeeded", target: "#audioPlayer.VISIBLE.AUDIO_PLAYER_INITIATED.PAUSED.LOADING" }, ], onError: [ { description: "The API call to get the selected chapter + Surah failed", target: "FAILED" }, ] }, tags: "loading" }, LOADING_CUSTOM_RECITER_DATA: { description: "The reciter + Surah data are being fetched", invoke: { src: "fetchCustomReciter", id: "fetchCustomReciter", onDone: [ { actions: [ "setAudioData", "setAudioPlayerSource", "setAudioPlayerCurrentTime", "updateRepeatVerseTimings", ], description: "The API call to get the selected chapter + Surah succeeded", target: "#audioPlayer.VISIBLE.AUDIO_PLAYER_INITIATED.PLAYING.LOADING" }, ], onError: [ { description: "The API call to get the selected chapter + Surah failed", target: "FAILED" }, ] }, tags: "loading" }, LOADING_REPEAT_DATA: { invoke: { src: "fetchRepeatData", id: "fetchRepeatData", onDone: [ { actions: [ "setAudioData", "setAudioPlayerSource", "setAudioPlayerCurrentTime", (0,external_xstate_.assign)({ surah: (context, event)=>event.data.surah, ayahNumber: (context, event)=>event.data.from, repeatActor: (context, event)=>{ return (0,external_xstate_.spawn)(createRepeatMachine({ fromVerseNumber: event.data.from, toVerseNumber: event.data.to, totalRangeCycle: event.data.repeatRange, totalVerseCycle: event.data.repeatEachVerse, verseTimings: context.audioData.verseTimings, delayMultiplier: event.data.delayMultiplier })); } }), ], description: "The API call to get the selected chapter + Surah succeeded", target: "#audioPlayer.VISIBLE.AUDIO_PLAYER_INITIATED.PLAYING.LOADING" }, ], onError: [ { description: "The API call to get the selected chapter + Surah failed", target: "FAILED" }, ] }, tags: "loading" } }, on: { CLOSE: { actions: [ "resetElapsedTime", "resetAyahNumber", "pauseAudio" ], description: "User closes the audio player", target: "HIDDEN" }, SET_PLAYBACK_SPEED: { actions: "setPlaybackRate", description: "User change the playback speed" }, CHANGE_RECITER: [ { cond: "isRadioActive", actions: "forwardChangeReciterToRadioMachine" }, { actions: [ "pauseAudio", "setReciterId", "resetElapsedTime" ], description: "User changes the reciter while the audio player is visible and might be playing", target: ".LOADING_RECITER_DATA_AND_PAUSE" }, ], PLAY_RADIO_TRACK: { actions: "setRadioStationDetails", description: "User opens the audio player to play radio of a certain station", target: ".LOADING_RECITER_DATA" }, PLAY_AYAH: [ { description: "When the user is clicking play ayah. On the currently playing ayah, resume it", cond: "isSameAyah", target: ".AUDIO_PLAYER_INITIATED.PLAYING.ACTIVE" }, { actions: [ "setSurahAndAyahNumbers", "exitRadio", "stopRepeatActor" ], description: "When the user chooses to play an Ayah of another Surah", cond: "isDifferentSurah", target: "VISIBLE.LOADING_RECITER_DATA" }, { actions: [ "setAyahNumber", "setAudioPlayerCurrentTime", "exitRadio", "updateRepeatAyah", ], description: "When the user chooses to play an Ayah of the same Surah. (can be the same Ayah being recited)", cond: "isSameSurahAndReciter", target: ".AUDIO_PLAYER_INITIATED.PLAYING.LOADING" }, ], PLAY_SURAH: [ { description: "When the users is playing the same surah. Just resume it", cond: "isSameSurahAndReciter", target: ".AUDIO_PLAYER_INITIATED.PLAYING.ACTIVE" }, { actions: [ "setSurahAndResetAyahNumber", "exitRadio", "stopRepeatActor" ], cond: "isUsingCustomReciterId", target: "VISIBLE.LOADING_CUSTOM_RECITER_DATA" }, { actions: [ "setSurahAndResetAyahNumber", "exitRadio", "stopRepeatActor" ], description: "When the user chooses to play another Surah", cond: "isDifferentSurah", target: "VISIBLE.LOADING_RECITER_DATA" }, ], PLAY_RADIO: { actions: [ "stopRepeatActor", "forwardPlayToRadioMachine" ] }, CLOSE_RADIO: { actions: [ "pauseAudio", "exitRadio" ], target: "HIDDEN" }, UPDATE_VOLUME: { actions: "updateVolume", description: "User updates the volume" } } } }, on: { SET_AUDIO_REF: { actions: "setAudioRef" }, SET_REPEAT_SETTING: { actions: [ "exitRadio" ], target: ".VISIBLE.LOADING_REPEAT_DATA" }, SET_INITIAL_CONTEXT: { actions: "setInitialContext" }, SET_RECITERS_LIST: { actions: "setRecitersList" } } }, { actions: { continueFromLastTimestamp: (context)=>{ /** * This is hack for safari where the audioplayer goes to ended, instead of waiting for the buffer data */ context.audioPlayer.currentTime = context.elapsed - 0.0001; context.audioPlayer.play(); }, setRecitersList: (0,external_xstate_.assign)({ recitersList: (context, event)=>event.recitersList }), setInitialContext: (0,external_xstate_.assign)({ reciterId: (context, event)=>event.reciterId, playbackRate: (context, event)=>event.playbackRate, volume: (context, event)=>event.volume }), updateRepeatAyah: (0,actions_.pure)((context, event)=>{ if (context.repeatActor) { return (0,external_xstate_.send)({ type: "REPEAT_SELECTED_AYAH", ayahNumber: event.ayahNumber }, { to: context.repeatActor.id }); } return []; }), exitRadio: (0,actions_.pure)((context)=>{ const { radioActor } = context; let actions = []; if (radioActor) { actions = [ // @ts-ignore (0,actions_.stop)(radioActor), (0,external_xstate_.assign)({ radioActor: ()=>null, shouldPlayFromRandomTimeStamp: ()=>false }), ]; } return actions; }), forwardEndedToRadioMachine: (0,actions_.pure)((context)=>{ let actions = []; const { radioActor } = context; if (radioActor) { actions = [ (0,external_xstate_.assign)({ ayahNumber: 1 }), (0,external_xstate_.send)({ type: "TRACK_ENDED" }, { // @ts-ignore to: radioActor }), ]; } return actions; }), setRadioStationDetails: (0,external_xstate_.assign)({ shouldPlayFromRandomTimeStamp: (context, event)=>event.shouldPlayFromRandomTimeStamp, reciterId: (context, event)=>event.reciterId, surah: (context, event)=>event.surah }), decrementAyah: (0,external_xstate_.assign)({ ayahNumber: (context)=>context.ayahNumber - 1 }), incrementAyah: (0,external_xstate_.assign)({ ayahNumber: (context)=>context.ayahNumber + 1 }), setSurahAndResetAyahNumber: (0,external_xstate_.assign)({ // eslint-disable-next-line @typescript-eslint/no-unused-vars surah: (context, event)=>event.surah, // eslint-disable-next-line @typescript-eslint/no-unused-vars ayahNumber: (context)=>1 }), setAyahNumber: (0,external_xstate_.assign)({ ayahNumber: (context, event)=>event.ayahNumber }), setSurahAndAyahNumbers: (0,external_xstate_.assign)({ surah: (context, event)=>event.surah, ayahNumber: (context, event)=>event.ayahNumber }), setAudioRef: (0,external_xstate_.assign)({ audioPlayer: (context, event)=>event.audioPlayerRef }), setAudioData: (0,external_xstate_.assign)({ duration: (context, event)=>{ return (0,datetime/* milliSecondsToSeconds */.Rp)(event.data.duration); }, audioData: (context, event)=>event.data, surahVersesCount: (context, event)=>event.data.verseTimings.length }), setAudioPlayerSource: (context)=>{ const { audioData: { audioUrl } , } = context; context.audioPlayer.src = audioUrl; }, setAudioPlayerCurrentTime: (context)=>{ const { ayahNumber , audioData: { verseTimings } , duration , shouldPlayFromRandomTimeStamp , } = context; if (shouldPlayFromRandomTimeStamp) { const randomTimestamp = random_default()(0, duration); context.audioPlayer.currentTime = randomTimestamp; } else { const ayahTimestamps = verseTimings[ayahNumber - 1]; const { timestampFrom } = ayahTimestamps; context.audioPlayer.currentTime = (0,datetime/* milliSecondsToSeconds */.Rp)(timestampFrom); } }, resetElapsedTime: (0,external_xstate_.assign)({ elapsed: 0 }), updateDownloadProgress: (0,external_xstate_.assign)({ downloadProgress: (context, event)=>event.timestamp }), // @ts-ignore setElapsedTime: (0,actions_.pure)((context)=>{ const activeVerseTiming = (0,audioPlayerMachineHelper/* getActiveVerseTiming */.yr)(context); const ayahNumber = (0,audioPlayerMachineHelper/* getActiveAyahNumber */.m9)(activeVerseTiming); const wordLocation = (0,audioPlayerMachineHelper/* getActiveWordLocation */.Mb)(activeVerseTiming, context.audioPlayer.currentTime * 1000); return (0,external_xstate_.assign)({ elapsed: context.audioPlayer.currentTime, ayahNumber, wordLocation }); }), setReciterId: (0,external_xstate_.assign)({ reciterId: (context, event)=>event.reciterId }), resetAyahNumber: (0,external_xstate_.assign)({ ayahNumber: 1 }), pauseAudio: (context)=>{ context.audioPlayer.pause(); }, setPlaybackRate: (0,actions_.pure)((context, event)=>{ const { playbackRate } = event; // eslint-disable-next-line no-param-reassign context.audioPlayer.playbackRate = playbackRate; return (0,external_xstate_.assign)({ playbackRate }); }), updateTiming: (0,actions_.pure)((context)=>{ const actions = []; actions.push("setElapsedTime"); if (context.repeatActor) { actions.push((0,external_xstate_.send)({ type: "TIMESTAMP_UPDATED", timestamp: context.audioPlayer.currentTime * 1000 }, { to: context.repeatActor.id })); } return actions; }), forwardPlayToRadioMachine: (0,actions_.pure)((context, event)=>{ const actions = []; let { radioActor } = context; // if the radioActor doesn't exist, spawn a new one if (!radioActor) { radioActor = (0,external_xstate_.spawn)(createRadioMachine()); actions.push((0,external_xstate_.assign)({ radioActor })); } actions.push((0,external_xstate_.send)({ type: "PLAY_STATION", stationType: event.stationType, id: event.stationId }, { to: radioActor.id })); return actions; }), forwardChangeReciterToRadioMachine: (0,actions_.pure)((context, event)=>{ const actions = []; let { radioActor } = context; // if the radioActor doesn't exist, spawn a new one if (!radioActor) { radioActor = (0,external_xstate_.spawn)(createRadioMachine()); actions.push((0,external_xstate_.assign)({ radioActor })); } actions.push((0,external_xstate_.send)({ type: "PLAY_STATION", stationType: types/* StationType.Reciter */.T.Reciter, id: event.reciterId }, { to: radioActor.id })); return actions; }), stopRepeatActor: (0,actions_.pure)((context)=>{ if (context.repeatActor) { return [ (0,actions_.stop)(context.repeatActor.id), (0,external_xstate_.assign)({ repeatActor: null }), ]; } return []; }), // @ts-ignore repeatNextAyah: (0,actions_.pure)((context)=>[ (0,external_xstate_.send)({ type: "REPEAT_NEXT_AYAH" }, { to: context.repeatActor.id }), "incrementAyah", "setAudioPlayerCurrentTime", ]), // @ts-ignore repeatPreviousAyah: (0,actions_.pure)((context)=>{ if (context.repeatActor) { return [ (0,external_xstate_.send)({ type: "REPEAT_PREV_AYAH" }, { to: context.repeatActor.id }), "decrementAyah", "setAudioPlayerCurrentTime", ]; } return []; }), updateRepeatVerseTimings: (0,actions_.pure)((context)=>{ const actions = []; if (context.repeatActor) { actions.push((0,external_xstate_.send)({ type: "UPDATE_VERSE_TIMINGS", verseTimings: context.audioData.verseTimings }, { to: context.repeatActor.id })); } return actions; }), nextAudioTrack: (0,actions_.pure)((context)=>{ if (context.radioActor) { return (0,external_xstate_.send)({ type: "TRACK_ENDED" }, { to: context.radioActor.id }); } return []; }), seekTo: (0,actions_.pure)((context, event)=>{ // eslint-disable-next-line no-param-reassign context.audioPlayer.currentTime = event.timestamp; return (0,external_xstate_.assign)({ elapsed: event.timestamp }); }), seekToAndRepeat: (0,actions_.pure)((context, event)=>{ const actions = []; const ayahNumber = (0,audioPlayerMachineHelper/* getAyahNumberByTimestamp */.SQ)(context.audioData.verseTimings, (0,datetime/* secondsToMilliSeconds */.pE)(event.timestamp)); if (context.repeatActor) { actions.push((0,external_xstate_.send)({ type: "REPEAT_SELECTED_AYAH", ayahNumber }, { to: context.repeatActor.id })); } actions.push("seekTo"); return actions; }), updateVolume: (0,actions_.pure)((context, { volume })=>{ context.audioPlayer.volume = volume; return (0,external_xstate_.assign)({ volume }); }) }, guards: { isRadioActive: (context)=>!!context.radioActor, isNotLastVerse: (context)=>context.ayahNumber < context.surahVersesCount, isNotFirstVerse: (context)=>context.ayahNumber !== 1, canRepeatPrevAyah: (context)=>context.ayahNumber !== 1 && !!context.repeatActor, canRepeatNextAyah: (context)=>context.ayahNumber < context.surahVersesCount && !!context.repeatActor, isDifferentSurah: (context, event)=>context.surah !== event.surah, isDifferentSurahAndReciter: (context, event)=>{ const reciterId = event.reciterId || context.reciterId; return context.surah !== event.surah && reciterId !== context.audioData?.reciterId; }, isSameAyah: (context, event)=>context.ayahNumber === event.ayahNumber && context.surah === event.surah, isSameSurahAndReciter: (context, event)=>{ // @ts-ignore const reciterId = event.reciterId || context.reciterId; return context.surah === event.surah && reciterId === context.audioData?.reciterId; }, isRepeatActive: (context)=>!!context.repeatActor, isUsingCustomReciterId: (context, event)=>!!event.reciterId, isAudioAlmostEnded: (context)=>{ const { currentTime } = context.audioPlayer; const duration = (0,datetime/* milliSecondsToSeconds */.Rp)(context.audioData.duration); const durationWithTolerancePeriod = duration - 3; return currentTime > durationWithTolerancePeriod; } }, services: { playAudio: (context)=>{ context.audioPlayer.playbackRate = context.playbackRate; context.audioPlayer.volume = context.volume; return context.audioPlayer.play(); }, fetchReciter: (context)=>(0,audioPlayerMachineHelper/* executeFetchReciter */.B2)(context), fetchCustomReciter: (context, event)=>{ // @ts-ignore return (0,audioPlayerMachineHelper/* executeFetchReciter */.B2)({ surah: event.surah, reciterId: event.reciterId }); }, fetchRepeatData: (context, event)=>(0,audioPlayerMachineHelper/* executeFetchReciterFromEvent */.aB)(context, event), // eslint-disable-next-line react-func/max-lines-per-function initMediaSession: (context)=>(callback)=>{ if ("mediaSession" in navigator) { (0,audioPlayerMachineHelper/* getRecitersList */.KA)(context).then((recitersList)=>{ callback({ type: "SET_RECITERS_LIST", recitersList }); (0,audioPlayerMachineHelper/* getMediaSessionMetaData */.Gq)(context, recitersList).then((metaData)=>{ navigator.mediaSession.metadata = metaData; }); }); } const actionHandlers = [ [ "play", ()=>callback("TOGGLE") ], [ "pause", ()=>callback("TOGGLE") ], [ "previoustrack", ()=>{ if (context.radioActor) { callback("NEXT_AUDIO_TRACK"); } callback("PREV_AYAH"); }, ], [ "nexttrack", ()=>{ if (context.radioActor) { callback("NEXT_AUDIO_TRACK"); } callback("NEXT_AYAH"); }, ], [ "stop", ()=>{ callback("END"); }, ], ]; for (const [action, handler] of actionHandlers){ try { navigator.mediaSession.setActionHandler(action, handler); } catch (error) { // eslint-disable-next-line no-console console.log(`The media session action "${action}" is not supported yet.`); } } } }, delays: { VERSE_DELAY: (context)=>{ return context.verseDelay; } } }); /***/ }), /***/ 93608: /***/ ((__unused_webpack_module, __webpack_exports__, __webpack_require__) => { // EXPORTS __webpack_require__.d(__webpack_exports__, { "B2": () => (/* binding */ executeFetchReciter), "aB": () => (/* binding */ executeFetchReciterFromEvent), "m9": () => (/* binding */ getActiveAyahNumber), "yr": () => (/* binding */ getActiveVerseTiming), "Mb": () => (/* binding */ getActiveWordLocation), "SQ": () => (/* binding */ getAyahNumberByTimestamp), "Gq": () => (/* binding */ getMediaSessionMetaData), "KA": () => (/* binding */ getRecitersList), "Po": () => (/* binding */ getWordTimeSegment) }); ;// CONCATENATED MODULE: ./src/components/AudioPlayer/hooks/isCurrentTimeInRange.ts /** * check if currentTime is within range timestampFrom and timestampTo * * example: * - timestampFrom = 10, timestampTo = 20, currentTime = 10 should return true * - timestampFrom = 10, timestampTo = 20, currentTime = 11 should return true * - timestampFrom = 10, timestampTo = 20, currentTime = 20 should return false * * @param {number} currentTime * @param {number} timestampFrom * @param {number} timestampTo * @returns {boolean} isWithinRange */ const isCurrentTimeInRange = (currentTime, timestampFrom, timestampTo)=>currentTime >= timestampFrom && currentTime < timestampTo; /* harmony default export */ const hooks_isCurrentTimeInRange = (isCurrentTimeInRange); // EXTERNAL MODULE: ./src/utils/verse.ts var verse = __webpack_require__(44519); // EXTERNAL MODULE: ./src/api.ts var api = __webpack_require__(92684); ;// CONCATENATED MODULE: ./src/xstate/actors/audioPlayer/audioPlayerMachineHelper.ts const getAyahNumberByTimestamp = (verseTimings, timestamp)=>{ const verseTiming = verseTimings.find((timing)=>timestamp >= timing.timestampFrom && timestamp <= timing.timestampTo); if (!verseTiming) return null; return (0,verse/* getVerseNumberFromKey */.tR)(verseTiming.verseKey); }; /** * There's an issue on mobile safari. Where the audio doesn't start from the correct timestamp. * For example * verse 1: timestamp : 0 - 1000ms; * verse 2: timestamp: 1000ms - 2000ms; * * When we seek to verse timestamp 1000ms, safari reports that the timestamp is 850ms. * And the UI highlights verse 1. Which is incorrect. Since the user intended to play verse 2 (timestamp 1000) * */ const TOLERANCE_PERIOD = 200; // ms const getActiveVerseTiming = (context)=>{ const { audioData: { verseTimings } , ayahNumber , } = context; const { currentTime } = context.audioPlayer; const currentTimeMS = currentTime * 1000; const lastAyahOfSurahTimestampTo = verseTimings[verseTimings.length - 1].timestampTo; // if the reported time exceeded the maximum timestamp of the Surah from BE, just return the current Ayah which should be the last if (currentTimeMS > lastAyahOfSurahTimestampTo - TOLERANCE_PERIOD) { return verseTimings[ayahNumber - 1]; } const activeVerseTiming = verseTimings.find((ayah)=>{ const isAyahBeingRecited = hooks_isCurrentTimeInRange(currentTimeMS, ayah.timestampFrom - TOLERANCE_PERIOD, ayah.timestampTo - TOLERANCE_PERIOD); return isAyahBeingRecited; }); return activeVerseTiming; }; const getActiveWordLocation = (activeVerseTiming, currentTime)=>{ const activeAudioSegment = activeVerseTiming.segments.find((segment)=>{ const [, timestampFrom, timestampTo] = segment; // the structure of the segment is: [wordLocation, timestampFrom, timestampTo] return hooks_isCurrentTimeInRange(currentTime, timestampFrom, timestampTo); }); const wordLocation = activeAudioSegment ? activeAudioSegment[0] : 0; return wordLocation; }; const getTimingSegment = (verseTiming, wordPosition)=>verseTiming.segments.find(([location])=>wordPosition === location); const getWordTimeSegment = (verseTimings, word)=>{ const verseTiming = verseTimings.find((timing)=>timing.verseKey === word.verseKey); if (!verseTiming) return null; const segment = getTimingSegment(verseTiming, word.position); if (segment) return [ segment[1], segment[2] ]; return null; }; const getActiveAyahNumber = (activeVerseTiming)=>{ const [, verseNumber] = activeVerseTiming.verseKey.split(":"); return Number(verseNumber); }; const executeFetchReciter = async (context)=>{ const { reciterId , surah } = context; return (0,api/* getChapterAudioData */.lt)(reciterId, surah, true); }; const executeFetchReciterFromEvent = async (context, event)=>{ const { surah } = event; const { reciterId } = context; // @ts-ignore const data = await executeFetchReciter({ reciterId, surah }); return { ...data, ...event }; }; const getMediaSessionMetaData = async (context, recitersList)=>{ const reciterName = recitersList.find((reciter)=>reciter.id === context.audioData.reciterId).name; return new MediaMetadata({ title: `Surah ${context.audioData.chapterId}`, artist: reciterName, album: "Quran.com", artwork: [ { src: "https://quran.com/images/logo/Logo@192x192.png", type: "image/png", sizes: "192x192" }, ] }); }; const getRecitersList = async (context)=>{ const { recitersList } = context; if (recitersList) return recitersList; // TODO: localize this return (0,api/* getAvailableReciters */.tS)("en").then((res)=>res.reciters); }; /***/ }), /***/ 76133: /***/ ((__unused_webpack_module, __webpack_exports__, __webpack_require__) => { /* harmony export */ __webpack_require__.d(__webpack_exports__, { /* harmony export */ "m": () => (/* binding */ persistXstateToLocalStorage), /* harmony export */ "x": () => (/* binding */ getXstateStateFromLocalStorage) /* harmony export */ }); const AUDIO_PLAYER_LOCAL_STORAGE_KEY = "audio-player-state"; const persistXstateToLocalStorage = (newState)=>{ try { const previousState = JSON.parse(localStorage.getItem(AUDIO_PLAYER_LOCAL_STORAGE_KEY)) || {}; const nextState = { ...previousState, ...newState }; localStorage.setItem(AUDIO_PLAYER_LOCAL_STORAGE_KEY, JSON.stringify(nextState)); } catch (error) { // TODO: log error } }; const getXstateStateFromLocalStorage = ()=>{ try { const stateString = localStorage.getItem(AUDIO_PLAYER_LOCAL_STORAGE_KEY); if (stateString) { return JSON.parse(stateString) || {}; } return {}; } catch (e) { // TODO: log error return {}; } }; /***/ }) }; ; //# sourceMappingURL=64564.js.map