diff --git a/CHANGELOG.md b/CHANGELOG.md index 1b05c31abb..c929c1f5d3 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -5,6 +5,7 @@ #### Improvements - Added connection (lost) indicator on the Medusa log ([10774](https://github.com/pymedusa/Medusa/pull/10774)) - Extend subtitle file parsing to allow for titles with language name. ([10782](https://github.com/pymedusa/Medusa/pull/10782)) +- Auto change status episode to Wanted, when running a forced search for the episode. [10796](https://github.com/pymedusa/Medusa/pull/10796)) #### Fixes - Homepage: Fix loading shows from localCache ([10779](https://github.com/pymedusa/Medusa/pull/10779)) diff --git a/medusa/search/core.py b/medusa/search/core.py index c31f5f1563..9412b70786 100644 --- a/medusa/search/core.py +++ b/medusa/search/core.py @@ -21,6 +21,7 @@ name_cache, notifiers, ui, + ws ) from medusa.clients import torrent from medusa.clients.nzb import ( @@ -225,6 +226,9 @@ def snatch_result(result): sql_l.append(cur_ep_obj.get_sql()) + # Push an update with the updated episode to any open Web UIs through the WebSocket + ws.Message('episodeUpdated', cur_ep_obj.to_json()).push() + if cur_ep_obj.status != common.DOWNLOADED: notifiers.notify_snatch(cur_ep_obj, result) diff --git a/medusa/search/queue.py b/medusa/search/queue.py index c1b82f348e..007133f7e6 100644 --- a/medusa/search/queue.py +++ b/medusa/search/queue.py @@ -15,7 +15,7 @@ from builtins import str from medusa import app, common, db, failed_history, helpers, history, ui, ws -from medusa.common import DOWNLOADED, SNATCHED, SNATCHED_BEST, SNATCHED_PROPER, SUBTITLED +from medusa.common import DOWNLOADED, SNATCHED, SNATCHED_BEST, SNATCHED_PROPER, SUBTITLED, WANTED from medusa.helper.common import enabled_providers from medusa.helper.exceptions import AuthException, ex from medusa.helpers import pretty_file_size @@ -569,6 +569,18 @@ def run(self): # Push an update to any open Web UIs through the WebSocket ws.Message('QueueItemUpdate', self.to_json).push() + if self.segment: + # Make sure the episodes status has been changed to wanted, before starting the search. + ep_sql_l = [] + for episode in self.segment: + ep_sql = episode.mass_update_episode_status(WANTED) + if ep_sql: + ep_sql_l.append(ep_sql) + + if ep_sql_l: + main_db_con = db.DBConnection() + main_db_con.mass_action(ep_sql_l) + search_result = search_providers(self.show, self.segment) if search_result: diff --git a/medusa/tv/episode.py b/medusa/tv/episode.py index ac4edfe50b..a2d5bae0e9 100644 --- a/medusa/tv/episode.py +++ b/medusa/tv/episode.py @@ -23,6 +23,7 @@ notifiers, post_processor, subtitles, + ws ) from medusa.common import ( ARCHIVED, @@ -1096,6 +1097,7 @@ def to_json(self, detailed=True): data['identifier'] = self.identifier data['id'] = {self.indexer_name: self.indexerid} data['slug'] = self.slug + data['showSlug'] = self.series.slug data['season'] = self.season data['episode'] = self.episode @@ -1403,6 +1405,9 @@ def save_to_db(self): main_db_con = db.DBConnection() main_db_con.upsert('tv_episodes', new_value_dict, control_value_dict) + # Push an update with the updated episode to any open Web UIs through the WebSocket + ws.Message('episodeUpdated', self.to_json()).push() + self.reset_dirty() def full_path(self): @@ -2199,6 +2204,8 @@ def mass_update_episode_status(self, new_status): self.manually_searched = False self.status = new_status + # Push an update with the updated episode to any open Web UIs through the WebSocket + ws.Message('episodeUpdated', self.to_json()).push() # Make sure to run the collected sql through a mass action. return self.get_sql() diff --git a/themes-default/slim/src/store/index.js b/themes-default/slim/src/store/index.js index 05269fa138..832e755120 100644 --- a/themes-default/slim/src/store/index.js +++ b/themes-default/slim/src/store/index.js @@ -66,7 +66,7 @@ const passToStoreHandler = function(eventName, event, next) { } else if (event === 'showUpdated' || event === 'showAdded') { this.store.dispatch('updateShow', data); } else if (event === 'showRemoved') { - // We need this for the QueueItemChangeIndexer + // We need this for the QueueItemChangeIndexerstatus this.store.dispatch('removeShow', data); } else if (event === 'addManualSearchResult') { this.store.dispatch('addManualSearchResult', data); @@ -82,6 +82,8 @@ const passToStoreHandler = function(eventName, event, next) { } } else if (event === 'historyUpdate') { this.store.dispatch('updateHistory', data); + } else if (event === 'episodeUpdated') { + this.store.dispatch('updateEpisode', data); } else { window.displayNotification('info', event, data); } diff --git a/themes-default/slim/src/store/modules/shows.js b/themes-default/slim/src/store/modules/shows.js index 7e26e496f7..fc0175d35b 100644 --- a/themes-default/slim/src/store/modules/shows.js +++ b/themes-default/slim/src/store/modules/shows.js @@ -581,8 +581,11 @@ const actions = { initShowsFromLocalStorage({ rootState, commit }) { const namespace = rootState.config.system.webRoot ? `${rootState.config.system.webRoot}_` : ''; return commit('loadShowsFromStore', namespace); + }, + updateEpisode({ state, commit }, episode) { + const show = state.shows.find(({ id }) => id.slug === episode.showSlug); + commit(ADD_SHOW_EPISODE, { show, episodes: [episode] }); } - }; export default { diff --git a/themes/dark/assets/js/medusa-runtime.js b/themes/dark/assets/js/medusa-runtime.js index bc05e65f4e..09bc04c043 100644 --- a/themes/dark/assets/js/medusa-runtime.js +++ b/themes/dark/assets/js/medusa-runtime.js @@ -1379,7 +1379,7 @@ eval("__webpack_require__.r(__webpack_exports__);\n/* harmony export */ __webpac /***/ ((__unused_webpack_module, __webpack_exports__, __webpack_require__) => { "use strict"; -eval("__webpack_require__.r(__webpack_exports__);\n/* harmony export */ __webpack_require__.d(__webpack_exports__, {\n/* harmony export */ \"default\": () => (__WEBPACK_DEFAULT_EXPORT__)\n/* harmony export */ });\n/* harmony import */ var vue__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(/*! vue */ \"./node_modules/vue/dist/vue.esm.js\");\n/* harmony import */ var vuex__WEBPACK_IMPORTED_MODULE_4__ = __webpack_require__(/*! vuex */ \"./node_modules/vuex/dist/vuex.esm.js\");\n/* harmony import */ var vue_native_websocket__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! vue-native-websocket */ \"./node_modules/vue-native-websocket/dist/build.js\");\n/* harmony import */ var vue_native_websocket__WEBPACK_IMPORTED_MODULE_0___default = /*#__PURE__*/__webpack_require__.n(vue_native_websocket__WEBPACK_IMPORTED_MODULE_0__);\n/* harmony import */ var _modules__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! ./modules */ \"./src/store/modules/index.js\");\n/* harmony import */ var _mutation_types__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(/*! ./mutation-types */ \"./src/store/mutation-types.js\");\n\n\n\n\n\nvue__WEBPACK_IMPORTED_MODULE_3__[\"default\"].use(vuex__WEBPACK_IMPORTED_MODULE_4__[\"default\"]);\nconst store = new vuex__WEBPACK_IMPORTED_MODULE_4__.Store({\n modules: {\n auth: _modules__WEBPACK_IMPORTED_MODULE_1__.auth,\n config: _modules__WEBPACK_IMPORTED_MODULE_1__.config,\n defaults: _modules__WEBPACK_IMPORTED_MODULE_1__.defaults,\n history: _modules__WEBPACK_IMPORTED_MODULE_1__.history,\n notifications: _modules__WEBPACK_IMPORTED_MODULE_1__.notifications,\n provider: _modules__WEBPACK_IMPORTED_MODULE_1__.provider,\n recommended: _modules__WEBPACK_IMPORTED_MODULE_1__.recommended,\n schedule: _modules__WEBPACK_IMPORTED_MODULE_1__.schedule,\n shows: _modules__WEBPACK_IMPORTED_MODULE_1__.shows,\n socket: _modules__WEBPACK_IMPORTED_MODULE_1__.socket,\n stats: _modules__WEBPACK_IMPORTED_MODULE_1__.stats,\n queue: _modules__WEBPACK_IMPORTED_MODULE_1__.queue\n },\n state: {},\n mutations: {},\n getters: {},\n actions: {}\n}); // Keep as a non-arrow function for `this` context.\n\nconst passToStoreHandler = function (eventName, event, next) {\n const target = eventName.toUpperCase();\n const eventData = event.data;\n\n if (target === 'SOCKET_ONMESSAGE') {\n const message = JSON.parse(eventData);\n const {\n data,\n event\n } = message; // Show the notification to the user\n\n if (event === 'notification') {\n const {\n body,\n hash,\n type,\n title\n } = data;\n window.displayNotification(type, title, body, hash);\n } else if (event === 'configUpdated') {\n const {\n section,\n config\n } = data;\n this.store.dispatch('updateConfig', {\n section,\n config\n });\n } else if (event === 'showUpdated' || event === 'showAdded') {\n this.store.dispatch('updateShow', data);\n } else if (event === 'showRemoved') {\n // We need this for the QueueItemChangeIndexer\n this.store.dispatch('removeShow', data);\n } else if (event === 'addManualSearchResult') {\n this.store.dispatch('addManualSearchResult', data);\n } else if (event === 'QueueItemUpdate') {\n this.store.dispatch('updateQueueItem', data);\n } else if (event === 'QueueItemShow') {\n // Used as a generic showqueue item. If you want to know the specific action (update, refresh, remove, etc.)\n // Use queueItem.name. Like queueItem.name === 'REFRESH'.\n if (data.name === 'REMOVE-SHOW') {\n this.store.dispatch('removeShow', data.show);\n } else {\n this.store.dispatch('updateShowQueueItem', data);\n }\n } else if (event === 'historyUpdate') {\n this.store.dispatch('updateHistory', data);\n } else {\n window.displayNotification('info', event, data);\n }\n } // Resume normal 'passToStore' handling\n\n\n next(eventName, event);\n};\n\nconst websocketUrl = (() => {\n const {\n protocol,\n host\n } = window.location;\n const proto = protocol === 'https:' ? 'wss:' : 'ws:';\n const WSMessageUrl = '/ui';\n let webRoot = document.body.getAttribute('web-root');\n\n if (webRoot) {\n if (!webRoot.startsWith('/')) {\n webRoot = `/${webRoot}`;\n }\n }\n\n return `${proto}//${host}${webRoot}/ws${WSMessageUrl}`;\n})();\n\nvue__WEBPACK_IMPORTED_MODULE_3__[\"default\"].use((vue_native_websocket__WEBPACK_IMPORTED_MODULE_0___default()), websocketUrl, {\n store,\n format: 'json',\n reconnection: true,\n // (Boolean) whether to reconnect automatically (false)\n reconnectionAttempts: 25,\n // (Number) number of reconnection attempts before giving up (Infinity),\n reconnectionDelay: 2500,\n // (Number) how long to initially wait before attempting a new (1000)\n passToStoreHandler,\n // (Function|) Handler for events triggered by the WebSocket (false)\n mutations: {\n SOCKET_ONOPEN: _mutation_types__WEBPACK_IMPORTED_MODULE_2__.SOCKET_ONOPEN,\n SOCKET_ONCLOSE: _mutation_types__WEBPACK_IMPORTED_MODULE_2__.SOCKET_ONCLOSE,\n SOCKET_ONERROR: _mutation_types__WEBPACK_IMPORTED_MODULE_2__.SOCKET_ONERROR,\n SOCKET_ONMESSAGE: _mutation_types__WEBPACK_IMPORTED_MODULE_2__.SOCKET_ONMESSAGE,\n SOCKET_RECONNECT: _mutation_types__WEBPACK_IMPORTED_MODULE_2__.SOCKET_RECONNECT,\n SOCKET_RECONNECT_ERROR: _mutation_types__WEBPACK_IMPORTED_MODULE_2__.SOCKET_RECONNECT_ERROR\n }\n});\n/* harmony default export */ const __WEBPACK_DEFAULT_EXPORT__ = (store);\n\n//# sourceURL=webpack://slim/./src/store/index.js?"); +eval("__webpack_require__.r(__webpack_exports__);\n/* harmony export */ __webpack_require__.d(__webpack_exports__, {\n/* harmony export */ \"default\": () => (__WEBPACK_DEFAULT_EXPORT__)\n/* harmony export */ });\n/* harmony import */ var vue__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(/*! vue */ \"./node_modules/vue/dist/vue.esm.js\");\n/* harmony import */ var vuex__WEBPACK_IMPORTED_MODULE_4__ = __webpack_require__(/*! vuex */ \"./node_modules/vuex/dist/vuex.esm.js\");\n/* harmony import */ var vue_native_websocket__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! vue-native-websocket */ \"./node_modules/vue-native-websocket/dist/build.js\");\n/* harmony import */ var vue_native_websocket__WEBPACK_IMPORTED_MODULE_0___default = /*#__PURE__*/__webpack_require__.n(vue_native_websocket__WEBPACK_IMPORTED_MODULE_0__);\n/* harmony import */ var _modules__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! ./modules */ \"./src/store/modules/index.js\");\n/* harmony import */ var _mutation_types__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(/*! ./mutation-types */ \"./src/store/mutation-types.js\");\n\n\n\n\n\nvue__WEBPACK_IMPORTED_MODULE_3__[\"default\"].use(vuex__WEBPACK_IMPORTED_MODULE_4__[\"default\"]);\nconst store = new vuex__WEBPACK_IMPORTED_MODULE_4__.Store({\n modules: {\n auth: _modules__WEBPACK_IMPORTED_MODULE_1__.auth,\n config: _modules__WEBPACK_IMPORTED_MODULE_1__.config,\n defaults: _modules__WEBPACK_IMPORTED_MODULE_1__.defaults,\n history: _modules__WEBPACK_IMPORTED_MODULE_1__.history,\n notifications: _modules__WEBPACK_IMPORTED_MODULE_1__.notifications,\n provider: _modules__WEBPACK_IMPORTED_MODULE_1__.provider,\n recommended: _modules__WEBPACK_IMPORTED_MODULE_1__.recommended,\n schedule: _modules__WEBPACK_IMPORTED_MODULE_1__.schedule,\n shows: _modules__WEBPACK_IMPORTED_MODULE_1__.shows,\n socket: _modules__WEBPACK_IMPORTED_MODULE_1__.socket,\n stats: _modules__WEBPACK_IMPORTED_MODULE_1__.stats,\n queue: _modules__WEBPACK_IMPORTED_MODULE_1__.queue\n },\n state: {},\n mutations: {},\n getters: {},\n actions: {}\n}); // Keep as a non-arrow function for `this` context.\n\nconst passToStoreHandler = function (eventName, event, next) {\n const target = eventName.toUpperCase();\n const eventData = event.data;\n\n if (target === 'SOCKET_ONMESSAGE') {\n const message = JSON.parse(eventData);\n const {\n data,\n event\n } = message; // Show the notification to the user\n\n if (event === 'notification') {\n const {\n body,\n hash,\n type,\n title\n } = data;\n window.displayNotification(type, title, body, hash);\n } else if (event === 'configUpdated') {\n const {\n section,\n config\n } = data;\n this.store.dispatch('updateConfig', {\n section,\n config\n });\n } else if (event === 'showUpdated' || event === 'showAdded') {\n this.store.dispatch('updateShow', data);\n } else if (event === 'showRemoved') {\n // We need this for the QueueItemChangeIndexerstatus\n this.store.dispatch('removeShow', data);\n } else if (event === 'addManualSearchResult') {\n this.store.dispatch('addManualSearchResult', data);\n } else if (event === 'QueueItemUpdate') {\n this.store.dispatch('updateQueueItem', data);\n } else if (event === 'QueueItemShow') {\n // Used as a generic showqueue item. If you want to know the specific action (update, refresh, remove, etc.)\n // Use queueItem.name. Like queueItem.name === 'REFRESH'.\n if (data.name === 'REMOVE-SHOW') {\n this.store.dispatch('removeShow', data.show);\n } else {\n this.store.dispatch('updateShowQueueItem', data);\n }\n } else if (event === 'historyUpdate') {\n this.store.dispatch('updateHistory', data);\n } else if (event === 'episodeUpdated') {\n this.store.dispatch('updateEpisode', data);\n } else {\n window.displayNotification('info', event, data);\n }\n } // Resume normal 'passToStore' handling\n\n\n next(eventName, event);\n};\n\nconst websocketUrl = (() => {\n const {\n protocol,\n host\n } = window.location;\n const proto = protocol === 'https:' ? 'wss:' : 'ws:';\n const WSMessageUrl = '/ui';\n let webRoot = document.body.getAttribute('web-root');\n\n if (webRoot) {\n if (!webRoot.startsWith('/')) {\n webRoot = `/${webRoot}`;\n }\n }\n\n return `${proto}//${host}${webRoot}/ws${WSMessageUrl}`;\n})();\n\nvue__WEBPACK_IMPORTED_MODULE_3__[\"default\"].use((vue_native_websocket__WEBPACK_IMPORTED_MODULE_0___default()), websocketUrl, {\n store,\n format: 'json',\n reconnection: true,\n // (Boolean) whether to reconnect automatically (false)\n reconnectionAttempts: 25,\n // (Number) number of reconnection attempts before giving up (Infinity),\n reconnectionDelay: 2500,\n // (Number) how long to initially wait before attempting a new (1000)\n passToStoreHandler,\n // (Function|) Handler for events triggered by the WebSocket (false)\n mutations: {\n SOCKET_ONOPEN: _mutation_types__WEBPACK_IMPORTED_MODULE_2__.SOCKET_ONOPEN,\n SOCKET_ONCLOSE: _mutation_types__WEBPACK_IMPORTED_MODULE_2__.SOCKET_ONCLOSE,\n SOCKET_ONERROR: _mutation_types__WEBPACK_IMPORTED_MODULE_2__.SOCKET_ONERROR,\n SOCKET_ONMESSAGE: _mutation_types__WEBPACK_IMPORTED_MODULE_2__.SOCKET_ONMESSAGE,\n SOCKET_RECONNECT: _mutation_types__WEBPACK_IMPORTED_MODULE_2__.SOCKET_RECONNECT,\n SOCKET_RECONNECT_ERROR: _mutation_types__WEBPACK_IMPORTED_MODULE_2__.SOCKET_RECONNECT_ERROR\n }\n});\n/* harmony default export */ const __WEBPACK_DEFAULT_EXPORT__ = (store);\n\n//# sourceURL=webpack://slim/./src/store/index.js?"); /***/ }), @@ -1885,7 +1885,7 @@ eval("__webpack_require__.r(__webpack_exports__);\n/* harmony export */ __webpac /***/ ((__unused_webpack_module, __webpack_exports__, __webpack_require__) => { "use strict"; -eval("__webpack_require__.r(__webpack_exports__);\n/* harmony export */ __webpack_require__.d(__webpack_exports__, {\n/* harmony export */ \"default\": () => (__WEBPACK_DEFAULT_EXPORT__)\n/* harmony export */ });\n/* harmony import */ var vue__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! vue */ \"./node_modules/vue/dist/vue.esm.js\");\n/* harmony import */ var _mutation_types__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! ../mutation-types */ \"./src/store/mutation-types.js\");\n\n\n/**\n * @typedef {object} ShowIdentifier\n * @property {string} indexer The indexer name (e.g. `tvdb`)\n * @property {number} id The show ID on the indexer (e.g. `12345`)\n */\n\nconst state = {\n shows: [],\n currentShow: {\n showSlug: null\n },\n loading: {\n total: null,\n current: null,\n display: false,\n finished: false\n },\n queueitems: []\n};\nconst mutations = {\n [_mutation_types__WEBPACK_IMPORTED_MODULE_0__.ADD_SHOW](state, show) {\n const existingShow = state.shows.find(_ref => {\n let {\n id,\n indexer\n } = _ref;\n return Number(show.id[show.indexer]) === Number(id[indexer]);\n });\n\n if (!existingShow) {\n console.debug(`Adding ${show.title || show.indexer + String(show.id)} as it wasn't found in the shows array`, show);\n state.shows.push(show);\n return;\n } // Merge new show object over old one\n // this allows detailed queries to update the record\n // without the non-detailed removing the extra data\n\n\n console.debug(`Found ${show.title || show.indexer + String(show.id)} in shows array attempting merge`);\n const newShow = { ...existingShow,\n ...show\n }; // Repair the searchTemplates\n\n newShow.config.searchTemplates = show.config.searchTemplates ? show.config.searchTemplates : existingShow.config.searchTemplates; // Update state\n\n vue__WEBPACK_IMPORTED_MODULE_1__[\"default\"].set(state.shows, state.shows.indexOf(existingShow), newShow);\n console.debug(`Merged ${newShow.title || newShow.indexer + String(newShow.id)}`, newShow);\n },\n\n [_mutation_types__WEBPACK_IMPORTED_MODULE_0__.ADD_SHOWS](state, shows) {\n // If the show is already available, we only want to merge values\n const mergedShows = [];\n\n for (const newShow of shows) {\n const existing = state.shows.find(stateShow => stateShow.id.slug === newShow.id.slug);\n\n if (existing) {\n const {\n sceneAbsoluteNumbering,\n xemAbsoluteNumbering,\n sceneNumbering,\n ...showWithoutDetailed\n } = newShow; // Repair searchTemplates.\n\n const mergedShow = { ...existing,\n ...showWithoutDetailed\n };\n mergedShow.config.searchTemplates = showWithoutDetailed.config.searchTemplates ? showWithoutDetailed.config.searchTemplates : existing.config.searchTemplates;\n mergedShows.push(mergedShow);\n } else {\n mergedShows.push(newShow);\n }\n }\n\n state.shows = mergedShows;\n console.debug(`Added ${shows.length} shows to store`);\n },\n\n [_mutation_types__WEBPACK_IMPORTED_MODULE_0__.ADD_SHOW_CONFIG](state, _ref2) {\n let {\n show,\n config\n } = _ref2;\n const existingShow = state.shows.find(_ref3 => {\n let {\n id,\n indexer\n } = _ref3;\n return Number(show.id[show.indexer]) === Number(id[indexer]);\n });\n existingShow.config = { ...existingShow.config,\n ...config\n };\n },\n\n currentShow(state, showSlug) {\n state.currentShow.showSlug = showSlug;\n },\n\n setLoadingTotal(state, total) {\n state.loading.total = total;\n },\n\n setLoadingCurrent(state, current) {\n state.loading.current = current;\n },\n\n updateLoadingCurrent(state, current) {\n state.loading.current += current;\n },\n\n setLoadingDisplay(state, display) {\n state.loading.display = display;\n },\n\n setLoadingFinished(state, finished) {\n state.loading.finished = finished;\n },\n\n [_mutation_types__WEBPACK_IMPORTED_MODULE_0__.ADD_SHOW_EPISODE](state, _ref4) {\n let {\n show,\n episodes\n } = _ref4;\n // Creating a new show object (from the state one) as we want to trigger a store update\n const newShow = Object.assign({}, state.shows.find(_ref5 => {\n let {\n id,\n indexer\n } = _ref5;\n return Number(show.id[show.indexer]) === Number(id[indexer]);\n }));\n\n if (!newShow.seasons) {\n newShow.seasons = [];\n } // Recreate an Array with season objects, with each season having an episodes array.\n // This format is used by vue-good-table (displayShow).\n\n\n episodes.forEach(episode => {\n let existingSeason = newShow.seasons.find(season => season.season === episode.season);\n\n if (existingSeason) {\n // Shallow copy\n existingSeason = { ...existingSeason\n };\n const foundIndex = existingSeason.children.findIndex(element => element.slug === episode.slug);\n\n if (foundIndex === -1) {\n existingSeason.children.push(episode);\n } else {\n existingSeason.children.splice(foundIndex, 1, episode);\n }\n } else {\n const newSeason = {\n season: episode.season,\n children: [],\n html: false,\n mode: 'span',\n label: 1\n };\n newShow.seasons.push(newSeason);\n newSeason.children.push(episode);\n }\n }); // Update state\n\n const existingShow = state.shows.find(_ref6 => {\n let {\n id,\n indexer\n } = _ref6;\n return Number(show.id[show.indexer]) === Number(id[indexer]);\n });\n vue__WEBPACK_IMPORTED_MODULE_1__[\"default\"].set(state.shows, state.shows.indexOf(existingShow), newShow);\n console.log(`Storing episodes for show ${newShow.title} seasons: ${[...new Set(episodes.map(episode => episode.season))].join(', ')}`);\n },\n\n [_mutation_types__WEBPACK_IMPORTED_MODULE_0__.ADD_SHOW_SCENE_EXCEPTION](state, _ref7) {\n let {\n show,\n exception\n } = _ref7;\n // Get current show object\n const currentShow = Object.assign({}, state.shows.find(_ref8 => {\n let {\n id,\n indexer\n } = _ref8;\n return Number(show.id[show.indexer]) === Number(id[indexer]);\n }));\n\n if (currentShow.config.aliases.find(e => e.title === exception.title && e.season === exception.season)) {\n console.warn(`Can't add exception ${exception.title} with season ${exception.season} to show ${currentShow.title} as it already exists.`);\n return;\n }\n\n currentShow.config.aliases.push(exception);\n },\n\n [_mutation_types__WEBPACK_IMPORTED_MODULE_0__.REMOVE_SHOW_SCENE_EXCEPTION](state, _ref9) {\n let {\n show,\n exception\n } = _ref9;\n // Get current show object\n const currentShow = Object.assign({}, state.shows.find(_ref10 => {\n let {\n id,\n indexer\n } = _ref10;\n return Number(show.id[show.indexer]) === Number(id[indexer]);\n }));\n\n if (!currentShow.config.aliases.find(e => e.title === exception.title && e.season === exception.season)) {\n console.warn(`Can't remove exception ${exception.title} with season ${exception.season} to show ${currentShow.title} as it does not exist.`);\n return;\n }\n\n currentShow.config.aliases.splice(currentShow.config.aliases.indexOf(exception), 1);\n },\n\n [_mutation_types__WEBPACK_IMPORTED_MODULE_0__.ADD_SHOW_QUEUE_ITEM](state, queueItem) {\n const existingQueueItem = state.queueitems.find(item => item.identifier === queueItem.identifier);\n\n if (existingQueueItem) {\n vue__WEBPACK_IMPORTED_MODULE_1__[\"default\"].set(state.queueitems, state.queueitems.indexOf(existingQueueItem), { ...existingQueueItem,\n ...queueItem\n });\n } else {\n vue__WEBPACK_IMPORTED_MODULE_1__[\"default\"].set(state.queueitems, state.queueitems.length, queueItem);\n }\n },\n\n [_mutation_types__WEBPACK_IMPORTED_MODULE_0__.ADD_SHOW_CONFIG_TEMPLATE](state, _ref11) {\n let {\n show,\n template\n } = _ref11;\n // Get current show object\n const currentShow = Object.assign({}, state.shows.find(_ref12 => {\n let {\n id,\n indexer\n } = _ref12;\n return Number(show.id[show.indexer]) === Number(id[indexer]);\n }));\n\n if (currentShow.config.searchTemplates.find(t => t.template === template.pattern)) {\n console.warn(`Can't add template (${template.pattern} to show ${currentShow.title} as it already exists.`);\n return;\n }\n\n currentShow.config.searchTemplates.push(template);\n },\n\n [_mutation_types__WEBPACK_IMPORTED_MODULE_0__.REMOVE_SHOW_CONFIG_TEMPLATE](state, _ref13) {\n let {\n show,\n template\n } = _ref13;\n // Get current show object\n const currentShow = Object.assign({}, state.shows.find(_ref14 => {\n let {\n id,\n indexer\n } = _ref14;\n return Number(show.id[show.indexer]) === Number(id[indexer]);\n }));\n\n if (template.id) {\n currentShow.config.searchTemplates = currentShow.config.searchTemplates.filter(t => t.id !== template.id);\n return;\n }\n\n currentShow.config.searchTemplates = currentShow.config.searchTemplates.filter(t => !(t.title === template.title && t.season === template.season && t.template === template.template));\n },\n\n [_mutation_types__WEBPACK_IMPORTED_MODULE_0__.REMOVE_SHOW](state, removedShow) {\n state.shows = state.shows.filter(existingShow => removedShow.id.slug !== existingShow.id.slug);\n },\n\n loadShowsFromStore(state, namespace) {\n // Check if the ID exists\n // Update (namespaced) localStorage\n if (localStorage.getItem('shows')) {\n vue__WEBPACK_IMPORTED_MODULE_1__[\"default\"].set(state, 'shows', JSON.parse(localStorage.getItem(`${namespace}shows`)));\n }\n }\n\n};\nconst getters = {\n getShowById: state => {\n /**\n * Get a show from the loaded shows state, identified by show slug.\n *\n * @param {string} showSlug Show identifier.\n * @returns {object|undefined} Show object or undefined if not found.\n */\n const getShowById = showSlug => state.shows.find(show => show.id.slug === showSlug);\n\n return getShowById;\n },\n getShowByTitle: state => title => state.shows.find(show => show.title === title),\n getSeason: state => _ref15 => {\n let {\n showSlug,\n season\n } = _ref15;\n const show = state.shows.find(show => show.id.slug === showSlug);\n return show && show.seasons ? show.seasons[season] : undefined;\n },\n getEpisode: state => _ref16 => {\n let {\n showSlug,\n season,\n episode\n } = _ref16;\n const show = state.shows.find(show => show.id.slug === showSlug);\n return show && show.seasons && show.seasons.find(s => s.season === season) ? show.seasons.find(s => s.season === season).children.find(ep => ep.episode === episode) : undefined;\n },\n getCurrentShow: (state, _, rootState) => {\n return state.shows.find(show => show.id.slug === state.currentShow.showSlug) || rootState.defaults.show;\n },\n getShowIndexerUrl: (state, getters, rootState) => show => {\n const indexerConfig = rootState.config.indexers.indexers;\n\n if (!show.indexer || !indexerConfig[show.indexer]) {\n return;\n }\n\n const id = show.id[show.indexer];\n const indexerUrl = indexerConfig[show.indexer].showUrl;\n\n if (show.indexer === 'imdb') {\n return `${indexerUrl}${String(id).padStart(7, '0')}`;\n }\n\n return `${indexerUrl}${id}`;\n },\n showsWithStats: (state, getters, rootState) => {\n if (!state.shows) {\n return [];\n }\n\n return state.shows.map(show => {\n let showStats = rootState.stats.show.stats.find(stat => stat.indexerId === getters.indexerNameToId(show.indexer) && stat.seriesId === show.id[show.indexer]);\n const newLine = '\\u000D';\n let text = 'Unaired';\n let title = '';\n\n if (!showStats) {\n showStats = {\n epDownloaded: 0,\n epSnatched: 0,\n epTotal: 0,\n seriesSize: 0\n };\n }\n\n if (showStats.epTotal >= 1) {\n text = showStats.epDownloaded;\n title = `Downloaded: ${showStats.epDownloaded}`;\n\n if (showStats.epSnatched) {\n text += `+${showStats.epSnatched}`;\n title += `${newLine}Snatched: ${showStats.epSnatched}`;\n }\n\n text += ` / ${showStats.epTotal}`;\n title += `${newLine}Total: ${showStats.epTotal}`;\n }\n\n show.stats = {\n episodes: {\n total: showStats.epTotal,\n snatched: showStats.epSnatched,\n downloaded: showStats.epDownloaded,\n size: showStats.seriesSize\n },\n tooltip: {\n text,\n title,\n percentage: showStats.epDownloaded * 100 / (showStats.epTotal || 1)\n }\n };\n return show;\n });\n },\n showsInLists: (state, getters, rootState) => {\n const {\n layout,\n general\n } = rootState.config;\n const {\n show\n } = layout;\n const {\n showListOrder\n } = show;\n const {\n rootDirs\n } = general;\n const {\n selectedRootIndex,\n local\n } = layout;\n const {\n showFilterByName\n } = local;\n const {\n showsWithStats\n } = getters;\n let shows = null; // Filter root dirs\n\n shows = showsWithStats.filter(show => selectedRootIndex === -1 || show.config.location.includes(rootDirs.slice(1)[selectedRootIndex])); // Filter by text for the banner, simple and smallposter layouts.\n // The Poster layout uses vue-isotope and this does not respond well to changes to the `list` property.\n\n if (layout.home !== 'poster') {\n shows = shows.filter(show => show.title.toLowerCase().includes(showFilterByName.toLowerCase()));\n }\n\n const categorizedShows = showListOrder.filter(listTitle => shows.filter(show => show.config.showLists.map(list => list.toLowerCase()).includes(listTitle.toLowerCase())).length > 0).map(listTitle => ({\n listTitle,\n shows: shows.filter(show => show.config.showLists.map(list => list.toLowerCase()).includes(listTitle.toLowerCase()))\n })); // Check for shows that are not in any category anymore\n\n const uncategorizedShows = shows.filter(show => {\n return show.config.showLists.map(item => {\n return showListOrder.map(list => list.toLowerCase()).includes(item.toLowerCase());\n }).every(item => !item);\n });\n\n if (uncategorizedShows.length > 0) {\n categorizedShows.push({\n listTitle: 'uncategorized',\n shows: uncategorizedShows\n });\n }\n\n if (categorizedShows.length === 0 && uncategorizedShows.length === 0) {\n categorizedShows.push({\n listTitle: 'Series',\n shows: []\n });\n }\n\n return categorizedShows;\n }\n};\n/**\n * An object representing request parameters for getting a show from the API.\n *\n * @typedef {object} ShowGetParameters\n * @property {boolean} detailed Fetch detailed information? (e.g. scene/xem numbering)\n * @property {boolean} episodes Fetch seasons & episodes?\n */\n\nconst actions = {\n /**\n * Get show from API and commit it to the store.\n *\n * @param {*} context The store context.\n * @param {ShowIdentifier&ShowGetParameters} parameters Request parameters.\n * @returns {Promise} The API response.\n */\n getShow(_ref17, _ref18) {\n let {\n rootState,\n commit\n } = _ref17;\n let {\n showSlug,\n detailed,\n episodes\n } = _ref18;\n return new Promise((resolve, reject) => {\n const params = {};\n let timeout = 30000;\n\n if (detailed !== undefined) {\n params.detailed = detailed;\n timeout = 60000;\n timeout = 60000;\n }\n\n if (episodes !== undefined) {\n params.episodes = episodes;\n timeout = 60000;\n }\n\n rootState.auth.client.api.get(`/series/${showSlug}`, {\n params,\n timeout\n }).then(res => {\n commit(_mutation_types__WEBPACK_IMPORTED_MODULE_0__.ADD_SHOW, res.data);\n resolve(res.data);\n }).catch(error => {\n reject(error);\n });\n });\n },\n\n /**\n * Get episdoes for a specified show from API and commit it to the store.\n *\n * @param {*} context - The store context.\n * @param {ShowParameteres} parameters - Request parameters.\n * @returns {Promise} The API response.\n */\n getEpisodes(_ref19, _ref20) {\n let {\n rootState,\n commit,\n getters\n } = _ref19;\n let {\n showSlug,\n season\n } = _ref20;\n return new Promise((resolve, reject) => {\n const {\n getShowById\n } = getters;\n const show = getShowById(showSlug);\n const limit = 1000;\n const params = {\n limit\n };\n\n if (season !== undefined) {\n params.season = season;\n } // Get episodes\n\n\n rootState.auth.client.api.get(`/series/${showSlug}/episodes`, {\n params\n }).then(response => {\n commit(_mutation_types__WEBPACK_IMPORTED_MODULE_0__.ADD_SHOW_EPISODE, {\n show,\n episodes: response.data\n });\n resolve();\n }).catch(error => {\n console.log(`Could not retrieve a episodes for show ${showSlug}, error: ${error}`);\n reject(error);\n });\n });\n },\n\n /**\n * Get shows from API and commit them to the store.\n *\n * @param {*} context - The store context.\n * @param {(ShowIdentifier&ShowGetParameters)[]} shows Shows to get. If not provided, gets the first 1k shows.\n * @returns {undefined|Promise} undefined if `shows` was provided or the API response if not.\n */\n getShows(context, shows) {\n const {\n commit,\n dispatch,\n state,\n rootState\n } = context; // If no shows are provided get the first 1000\n\n if (shows) {\n // Return a specific show list. (not used afaik).\n return shows.forEach(show => dispatch('getShow', show));\n }\n\n return new Promise((resolve, _) => {\n // Loading new shows, commit show loading information to state.\n commit('setLoadingTotal', 0);\n commit('setLoadingCurrent', 0);\n commit('setLoadingDisplay', true);\n const limit = 1000;\n const page = 1;\n const params = {\n limit,\n page\n };\n const pageRequests = [];\n const newShows = []; // Get first page\n\n pageRequests.push(rootState.auth.client.api.get('/series', {\n params\n }).then(response => {\n commit('setLoadingTotal', Number(response.headers['x-pagination-count']));\n const totalPages = Number(response.headers['x-pagination-total']);\n newShows.push(...response.data);\n commit('updateLoadingCurrent', response.data.length); // Optionally get additional pages\n\n for (let page = 2; page <= totalPages; page++) {\n pageRequests.push(new Promise((resolve, reject) => {\n const newPage = {\n page\n };\n newPage.limit = params.limit;\n return rootState.auth.client.api.get('/series', {\n params: newPage\n }).then(response => {\n newShows.push(...response.data);\n commit('updateLoadingCurrent', response.data.length);\n resolve();\n }).catch(error => {\n reject(error);\n });\n }));\n }\n }).catch(() => {\n console.log('Could not retrieve a list of shows');\n }).finally(() => {\n Promise.all(pageRequests).then(() => {\n // Commit all the found shows to store.\n commit(_mutation_types__WEBPACK_IMPORTED_MODULE_0__.ADD_SHOWS, newShows); // Update (namespaced) localStorage\n\n const namespace = rootState.config.system.webRoot ? `${rootState.config.system.webRoot}_` : '';\n\n try {\n localStorage.setItem(`${namespace}shows`, JSON.stringify(state.shows));\n } catch (error) {\n console.warn(error);\n }\n\n resolve();\n });\n }));\n });\n },\n\n setShow(_ref21, _ref22) {\n let {\n rootState\n } = _ref21;\n let {\n showSlug,\n data\n } = _ref22;\n // Update show, updated show will arrive over a WebSocket message\n return rootState.auth.client.api.patch(`series/${showSlug}`, data);\n },\n\n updateShow(context, show) {\n // Update local store\n const {\n commit\n } = context;\n return commit(_mutation_types__WEBPACK_IMPORTED_MODULE_0__.ADD_SHOW, show);\n },\n\n addSceneException(context, _ref23) {\n let {\n show,\n exception\n } = _ref23;\n const {\n commit\n } = context;\n commit(_mutation_types__WEBPACK_IMPORTED_MODULE_0__.ADD_SHOW_SCENE_EXCEPTION, {\n show,\n exception\n });\n },\n\n removeSceneException(context, _ref24) {\n let {\n show,\n exception\n } = _ref24;\n const {\n commit\n } = context;\n commit(_mutation_types__WEBPACK_IMPORTED_MODULE_0__.REMOVE_SHOW_SCENE_EXCEPTION, {\n show,\n exception\n });\n },\n\n setCurrentShow(context, showSlug) {\n return new Promise(resolve => {\n // Set current show\n const {\n commit\n } = context;\n commit('currentShow', showSlug);\n resolve();\n });\n },\n\n setShowConfig(context, _ref25) {\n let {\n show,\n config\n } = _ref25;\n const {\n commit\n } = context;\n commit(_mutation_types__WEBPACK_IMPORTED_MODULE_0__.ADD_SHOW_CONFIG, {\n show,\n config\n });\n },\n\n removeShow(_ref26, show) {\n let {\n commit,\n rootState,\n state\n } = _ref26;\n // Remove the show from store and localStorage (provided through websocket)\n commit(_mutation_types__WEBPACK_IMPORTED_MODULE_0__.REMOVE_SHOW, show); // Update recentShows.\n\n rootState.config.general.recentShows = rootState.config.general.recentShows.filter(recentShow => recentShow.showSlug !== show.id.slug);\n const config = {\n recentShows: rootState.config.general.recentShows\n };\n rootState.auth.client.api.patch('config/main', config); // Update (namespaced) localStorage\n\n const namespace = rootState.config.system.webRoot ? `${rootState.config.system.webRoot}_` : '';\n localStorage.setItem(`${namespace}shows`, JSON.stringify(state.shows));\n },\n\n updateShowQueueItem(context, queueItem) {\n // Update store's search queue item. (provided through websocket)\n const {\n commit\n } = context;\n return commit(_mutation_types__WEBPACK_IMPORTED_MODULE_0__.ADD_SHOW_QUEUE_ITEM, queueItem);\n },\n\n addSearchTemplate(_ref27, _ref28) {\n let {\n rootState,\n getters,\n commit\n } = _ref27;\n let {\n show,\n template\n } = _ref28;\n commit(_mutation_types__WEBPACK_IMPORTED_MODULE_0__.ADD_SHOW_CONFIG_TEMPLATE, {\n show,\n template\n });\n const data = {\n config: {\n searchTemplates: getters.getCurrentShow.config.searchTemplates\n }\n };\n return rootState.auth.client.api.patch(`series/${show.indexer}${show.id[show.indexer]}`, data);\n },\n\n removeSearchTemplate(_ref29, _ref30) {\n let {\n rootState,\n getters,\n commit\n } = _ref29;\n let {\n show,\n template\n } = _ref30;\n commit(_mutation_types__WEBPACK_IMPORTED_MODULE_0__.REMOVE_SHOW_CONFIG_TEMPLATE, {\n show,\n template\n });\n const data = {\n config: {\n searchTemplates: getters.getCurrentShow.config.searchTemplates\n }\n };\n return rootState.auth.client.api.patch(`series/${show.indexer}${show.id[show.indexer]}`, data);\n },\n\n initShowsFromLocalStorage(_ref31) {\n let {\n rootState,\n commit\n } = _ref31;\n const namespace = rootState.config.system.webRoot ? `${rootState.config.system.webRoot}_` : '';\n return commit('loadShowsFromStore', namespace);\n }\n\n};\n/* harmony default export */ const __WEBPACK_DEFAULT_EXPORT__ = ({\n state,\n mutations,\n getters,\n actions\n});\n\n//# sourceURL=webpack://slim/./src/store/modules/shows.js?"); +eval("__webpack_require__.r(__webpack_exports__);\n/* harmony export */ __webpack_require__.d(__webpack_exports__, {\n/* harmony export */ \"default\": () => (__WEBPACK_DEFAULT_EXPORT__)\n/* harmony export */ });\n/* harmony import */ var vue__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! vue */ \"./node_modules/vue/dist/vue.esm.js\");\n/* harmony import */ var _mutation_types__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! ../mutation-types */ \"./src/store/mutation-types.js\");\n\n\n/**\n * @typedef {object} ShowIdentifier\n * @property {string} indexer The indexer name (e.g. `tvdb`)\n * @property {number} id The show ID on the indexer (e.g. `12345`)\n */\n\nconst state = {\n shows: [],\n currentShow: {\n showSlug: null\n },\n loading: {\n total: null,\n current: null,\n display: false,\n finished: false\n },\n queueitems: []\n};\nconst mutations = {\n [_mutation_types__WEBPACK_IMPORTED_MODULE_0__.ADD_SHOW](state, show) {\n const existingShow = state.shows.find(_ref => {\n let {\n id,\n indexer\n } = _ref;\n return Number(show.id[show.indexer]) === Number(id[indexer]);\n });\n\n if (!existingShow) {\n console.debug(`Adding ${show.title || show.indexer + String(show.id)} as it wasn't found in the shows array`, show);\n state.shows.push(show);\n return;\n } // Merge new show object over old one\n // this allows detailed queries to update the record\n // without the non-detailed removing the extra data\n\n\n console.debug(`Found ${show.title || show.indexer + String(show.id)} in shows array attempting merge`);\n const newShow = { ...existingShow,\n ...show\n }; // Repair the searchTemplates\n\n newShow.config.searchTemplates = show.config.searchTemplates ? show.config.searchTemplates : existingShow.config.searchTemplates; // Update state\n\n vue__WEBPACK_IMPORTED_MODULE_1__[\"default\"].set(state.shows, state.shows.indexOf(existingShow), newShow);\n console.debug(`Merged ${newShow.title || newShow.indexer + String(newShow.id)}`, newShow);\n },\n\n [_mutation_types__WEBPACK_IMPORTED_MODULE_0__.ADD_SHOWS](state, shows) {\n // If the show is already available, we only want to merge values\n const mergedShows = [];\n\n for (const newShow of shows) {\n const existing = state.shows.find(stateShow => stateShow.id.slug === newShow.id.slug);\n\n if (existing) {\n const {\n sceneAbsoluteNumbering,\n xemAbsoluteNumbering,\n sceneNumbering,\n ...showWithoutDetailed\n } = newShow; // Repair searchTemplates.\n\n const mergedShow = { ...existing,\n ...showWithoutDetailed\n };\n mergedShow.config.searchTemplates = showWithoutDetailed.config.searchTemplates ? showWithoutDetailed.config.searchTemplates : existing.config.searchTemplates;\n mergedShows.push(mergedShow);\n } else {\n mergedShows.push(newShow);\n }\n }\n\n state.shows = mergedShows;\n console.debug(`Added ${shows.length} shows to store`);\n },\n\n [_mutation_types__WEBPACK_IMPORTED_MODULE_0__.ADD_SHOW_CONFIG](state, _ref2) {\n let {\n show,\n config\n } = _ref2;\n const existingShow = state.shows.find(_ref3 => {\n let {\n id,\n indexer\n } = _ref3;\n return Number(show.id[show.indexer]) === Number(id[indexer]);\n });\n existingShow.config = { ...existingShow.config,\n ...config\n };\n },\n\n currentShow(state, showSlug) {\n state.currentShow.showSlug = showSlug;\n },\n\n setLoadingTotal(state, total) {\n state.loading.total = total;\n },\n\n setLoadingCurrent(state, current) {\n state.loading.current = current;\n },\n\n updateLoadingCurrent(state, current) {\n state.loading.current += current;\n },\n\n setLoadingDisplay(state, display) {\n state.loading.display = display;\n },\n\n setLoadingFinished(state, finished) {\n state.loading.finished = finished;\n },\n\n [_mutation_types__WEBPACK_IMPORTED_MODULE_0__.ADD_SHOW_EPISODE](state, _ref4) {\n let {\n show,\n episodes\n } = _ref4;\n // Creating a new show object (from the state one) as we want to trigger a store update\n const newShow = Object.assign({}, state.shows.find(_ref5 => {\n let {\n id,\n indexer\n } = _ref5;\n return Number(show.id[show.indexer]) === Number(id[indexer]);\n }));\n\n if (!newShow.seasons) {\n newShow.seasons = [];\n } // Recreate an Array with season objects, with each season having an episodes array.\n // This format is used by vue-good-table (displayShow).\n\n\n episodes.forEach(episode => {\n let existingSeason = newShow.seasons.find(season => season.season === episode.season);\n\n if (existingSeason) {\n // Shallow copy\n existingSeason = { ...existingSeason\n };\n const foundIndex = existingSeason.children.findIndex(element => element.slug === episode.slug);\n\n if (foundIndex === -1) {\n existingSeason.children.push(episode);\n } else {\n existingSeason.children.splice(foundIndex, 1, episode);\n }\n } else {\n const newSeason = {\n season: episode.season,\n children: [],\n html: false,\n mode: 'span',\n label: 1\n };\n newShow.seasons.push(newSeason);\n newSeason.children.push(episode);\n }\n }); // Update state\n\n const existingShow = state.shows.find(_ref6 => {\n let {\n id,\n indexer\n } = _ref6;\n return Number(show.id[show.indexer]) === Number(id[indexer]);\n });\n vue__WEBPACK_IMPORTED_MODULE_1__[\"default\"].set(state.shows, state.shows.indexOf(existingShow), newShow);\n console.log(`Storing episodes for show ${newShow.title} seasons: ${[...new Set(episodes.map(episode => episode.season))].join(', ')}`);\n },\n\n [_mutation_types__WEBPACK_IMPORTED_MODULE_0__.ADD_SHOW_SCENE_EXCEPTION](state, _ref7) {\n let {\n show,\n exception\n } = _ref7;\n // Get current show object\n const currentShow = Object.assign({}, state.shows.find(_ref8 => {\n let {\n id,\n indexer\n } = _ref8;\n return Number(show.id[show.indexer]) === Number(id[indexer]);\n }));\n\n if (currentShow.config.aliases.find(e => e.title === exception.title && e.season === exception.season)) {\n console.warn(`Can't add exception ${exception.title} with season ${exception.season} to show ${currentShow.title} as it already exists.`);\n return;\n }\n\n currentShow.config.aliases.push(exception);\n },\n\n [_mutation_types__WEBPACK_IMPORTED_MODULE_0__.REMOVE_SHOW_SCENE_EXCEPTION](state, _ref9) {\n let {\n show,\n exception\n } = _ref9;\n // Get current show object\n const currentShow = Object.assign({}, state.shows.find(_ref10 => {\n let {\n id,\n indexer\n } = _ref10;\n return Number(show.id[show.indexer]) === Number(id[indexer]);\n }));\n\n if (!currentShow.config.aliases.find(e => e.title === exception.title && e.season === exception.season)) {\n console.warn(`Can't remove exception ${exception.title} with season ${exception.season} to show ${currentShow.title} as it does not exist.`);\n return;\n }\n\n currentShow.config.aliases.splice(currentShow.config.aliases.indexOf(exception), 1);\n },\n\n [_mutation_types__WEBPACK_IMPORTED_MODULE_0__.ADD_SHOW_QUEUE_ITEM](state, queueItem) {\n const existingQueueItem = state.queueitems.find(item => item.identifier === queueItem.identifier);\n\n if (existingQueueItem) {\n vue__WEBPACK_IMPORTED_MODULE_1__[\"default\"].set(state.queueitems, state.queueitems.indexOf(existingQueueItem), { ...existingQueueItem,\n ...queueItem\n });\n } else {\n vue__WEBPACK_IMPORTED_MODULE_1__[\"default\"].set(state.queueitems, state.queueitems.length, queueItem);\n }\n },\n\n [_mutation_types__WEBPACK_IMPORTED_MODULE_0__.ADD_SHOW_CONFIG_TEMPLATE](state, _ref11) {\n let {\n show,\n template\n } = _ref11;\n // Get current show object\n const currentShow = Object.assign({}, state.shows.find(_ref12 => {\n let {\n id,\n indexer\n } = _ref12;\n return Number(show.id[show.indexer]) === Number(id[indexer]);\n }));\n\n if (currentShow.config.searchTemplates.find(t => t.template === template.pattern)) {\n console.warn(`Can't add template (${template.pattern} to show ${currentShow.title} as it already exists.`);\n return;\n }\n\n currentShow.config.searchTemplates.push(template);\n },\n\n [_mutation_types__WEBPACK_IMPORTED_MODULE_0__.REMOVE_SHOW_CONFIG_TEMPLATE](state, _ref13) {\n let {\n show,\n template\n } = _ref13;\n // Get current show object\n const currentShow = Object.assign({}, state.shows.find(_ref14 => {\n let {\n id,\n indexer\n } = _ref14;\n return Number(show.id[show.indexer]) === Number(id[indexer]);\n }));\n\n if (template.id) {\n currentShow.config.searchTemplates = currentShow.config.searchTemplates.filter(t => t.id !== template.id);\n return;\n }\n\n currentShow.config.searchTemplates = currentShow.config.searchTemplates.filter(t => !(t.title === template.title && t.season === template.season && t.template === template.template));\n },\n\n [_mutation_types__WEBPACK_IMPORTED_MODULE_0__.REMOVE_SHOW](state, removedShow) {\n state.shows = state.shows.filter(existingShow => removedShow.id.slug !== existingShow.id.slug);\n },\n\n loadShowsFromStore(state, namespace) {\n // Check if the ID exists\n // Update (namespaced) localStorage\n if (localStorage.getItem('shows')) {\n vue__WEBPACK_IMPORTED_MODULE_1__[\"default\"].set(state, 'shows', JSON.parse(localStorage.getItem(`${namespace}shows`)));\n }\n }\n\n};\nconst getters = {\n getShowById: state => {\n /**\n * Get a show from the loaded shows state, identified by show slug.\n *\n * @param {string} showSlug Show identifier.\n * @returns {object|undefined} Show object or undefined if not found.\n */\n const getShowById = showSlug => state.shows.find(show => show.id.slug === showSlug);\n\n return getShowById;\n },\n getShowByTitle: state => title => state.shows.find(show => show.title === title),\n getSeason: state => _ref15 => {\n let {\n showSlug,\n season\n } = _ref15;\n const show = state.shows.find(show => show.id.slug === showSlug);\n return show && show.seasons ? show.seasons[season] : undefined;\n },\n getEpisode: state => _ref16 => {\n let {\n showSlug,\n season,\n episode\n } = _ref16;\n const show = state.shows.find(show => show.id.slug === showSlug);\n return show && show.seasons && show.seasons.find(s => s.season === season) ? show.seasons.find(s => s.season === season).children.find(ep => ep.episode === episode) : undefined;\n },\n getCurrentShow: (state, _, rootState) => {\n return state.shows.find(show => show.id.slug === state.currentShow.showSlug) || rootState.defaults.show;\n },\n getShowIndexerUrl: (state, getters, rootState) => show => {\n const indexerConfig = rootState.config.indexers.indexers;\n\n if (!show.indexer || !indexerConfig[show.indexer]) {\n return;\n }\n\n const id = show.id[show.indexer];\n const indexerUrl = indexerConfig[show.indexer].showUrl;\n\n if (show.indexer === 'imdb') {\n return `${indexerUrl}${String(id).padStart(7, '0')}`;\n }\n\n return `${indexerUrl}${id}`;\n },\n showsWithStats: (state, getters, rootState) => {\n if (!state.shows) {\n return [];\n }\n\n return state.shows.map(show => {\n let showStats = rootState.stats.show.stats.find(stat => stat.indexerId === getters.indexerNameToId(show.indexer) && stat.seriesId === show.id[show.indexer]);\n const newLine = '\\u000D';\n let text = 'Unaired';\n let title = '';\n\n if (!showStats) {\n showStats = {\n epDownloaded: 0,\n epSnatched: 0,\n epTotal: 0,\n seriesSize: 0\n };\n }\n\n if (showStats.epTotal >= 1) {\n text = showStats.epDownloaded;\n title = `Downloaded: ${showStats.epDownloaded}`;\n\n if (showStats.epSnatched) {\n text += `+${showStats.epSnatched}`;\n title += `${newLine}Snatched: ${showStats.epSnatched}`;\n }\n\n text += ` / ${showStats.epTotal}`;\n title += `${newLine}Total: ${showStats.epTotal}`;\n }\n\n show.stats = {\n episodes: {\n total: showStats.epTotal,\n snatched: showStats.epSnatched,\n downloaded: showStats.epDownloaded,\n size: showStats.seriesSize\n },\n tooltip: {\n text,\n title,\n percentage: showStats.epDownloaded * 100 / (showStats.epTotal || 1)\n }\n };\n return show;\n });\n },\n showsInLists: (state, getters, rootState) => {\n const {\n layout,\n general\n } = rootState.config;\n const {\n show\n } = layout;\n const {\n showListOrder\n } = show;\n const {\n rootDirs\n } = general;\n const {\n selectedRootIndex,\n local\n } = layout;\n const {\n showFilterByName\n } = local;\n const {\n showsWithStats\n } = getters;\n let shows = null; // Filter root dirs\n\n shows = showsWithStats.filter(show => selectedRootIndex === -1 || show.config.location.includes(rootDirs.slice(1)[selectedRootIndex])); // Filter by text for the banner, simple and smallposter layouts.\n // The Poster layout uses vue-isotope and this does not respond well to changes to the `list` property.\n\n if (layout.home !== 'poster') {\n shows = shows.filter(show => show.title.toLowerCase().includes(showFilterByName.toLowerCase()));\n }\n\n const categorizedShows = showListOrder.filter(listTitle => shows.filter(show => show.config.showLists.map(list => list.toLowerCase()).includes(listTitle.toLowerCase())).length > 0).map(listTitle => ({\n listTitle,\n shows: shows.filter(show => show.config.showLists.map(list => list.toLowerCase()).includes(listTitle.toLowerCase()))\n })); // Check for shows that are not in any category anymore\n\n const uncategorizedShows = shows.filter(show => {\n return show.config.showLists.map(item => {\n return showListOrder.map(list => list.toLowerCase()).includes(item.toLowerCase());\n }).every(item => !item);\n });\n\n if (uncategorizedShows.length > 0) {\n categorizedShows.push({\n listTitle: 'uncategorized',\n shows: uncategorizedShows\n });\n }\n\n if (categorizedShows.length === 0 && uncategorizedShows.length === 0) {\n categorizedShows.push({\n listTitle: 'Series',\n shows: []\n });\n }\n\n return categorizedShows;\n }\n};\n/**\n * An object representing request parameters for getting a show from the API.\n *\n * @typedef {object} ShowGetParameters\n * @property {boolean} detailed Fetch detailed information? (e.g. scene/xem numbering)\n * @property {boolean} episodes Fetch seasons & episodes?\n */\n\nconst actions = {\n /**\n * Get show from API and commit it to the store.\n *\n * @param {*} context The store context.\n * @param {ShowIdentifier&ShowGetParameters} parameters Request parameters.\n * @returns {Promise} The API response.\n */\n getShow(_ref17, _ref18) {\n let {\n rootState,\n commit\n } = _ref17;\n let {\n showSlug,\n detailed,\n episodes\n } = _ref18;\n return new Promise((resolve, reject) => {\n const params = {};\n let timeout = 30000;\n\n if (detailed !== undefined) {\n params.detailed = detailed;\n timeout = 60000;\n timeout = 60000;\n }\n\n if (episodes !== undefined) {\n params.episodes = episodes;\n timeout = 60000;\n }\n\n rootState.auth.client.api.get(`/series/${showSlug}`, {\n params,\n timeout\n }).then(res => {\n commit(_mutation_types__WEBPACK_IMPORTED_MODULE_0__.ADD_SHOW, res.data);\n resolve(res.data);\n }).catch(error => {\n reject(error);\n });\n });\n },\n\n /**\n * Get episdoes for a specified show from API and commit it to the store.\n *\n * @param {*} context - The store context.\n * @param {ShowParameteres} parameters - Request parameters.\n * @returns {Promise} The API response.\n */\n getEpisodes(_ref19, _ref20) {\n let {\n rootState,\n commit,\n getters\n } = _ref19;\n let {\n showSlug,\n season\n } = _ref20;\n return new Promise((resolve, reject) => {\n const {\n getShowById\n } = getters;\n const show = getShowById(showSlug);\n const limit = 1000;\n const params = {\n limit\n };\n\n if (season !== undefined) {\n params.season = season;\n } // Get episodes\n\n\n rootState.auth.client.api.get(`/series/${showSlug}/episodes`, {\n params\n }).then(response => {\n commit(_mutation_types__WEBPACK_IMPORTED_MODULE_0__.ADD_SHOW_EPISODE, {\n show,\n episodes: response.data\n });\n resolve();\n }).catch(error => {\n console.log(`Could not retrieve a episodes for show ${showSlug}, error: ${error}`);\n reject(error);\n });\n });\n },\n\n /**\n * Get shows from API and commit them to the store.\n *\n * @param {*} context - The store context.\n * @param {(ShowIdentifier&ShowGetParameters)[]} shows Shows to get. If not provided, gets the first 1k shows.\n * @returns {undefined|Promise} undefined if `shows` was provided or the API response if not.\n */\n getShows(context, shows) {\n const {\n commit,\n dispatch,\n state,\n rootState\n } = context; // If no shows are provided get the first 1000\n\n if (shows) {\n // Return a specific show list. (not used afaik).\n return shows.forEach(show => dispatch('getShow', show));\n }\n\n return new Promise((resolve, _) => {\n // Loading new shows, commit show loading information to state.\n commit('setLoadingTotal', 0);\n commit('setLoadingCurrent', 0);\n commit('setLoadingDisplay', true);\n const limit = 1000;\n const page = 1;\n const params = {\n limit,\n page\n };\n const pageRequests = [];\n const newShows = []; // Get first page\n\n pageRequests.push(rootState.auth.client.api.get('/series', {\n params\n }).then(response => {\n commit('setLoadingTotal', Number(response.headers['x-pagination-count']));\n const totalPages = Number(response.headers['x-pagination-total']);\n newShows.push(...response.data);\n commit('updateLoadingCurrent', response.data.length); // Optionally get additional pages\n\n for (let page = 2; page <= totalPages; page++) {\n pageRequests.push(new Promise((resolve, reject) => {\n const newPage = {\n page\n };\n newPage.limit = params.limit;\n return rootState.auth.client.api.get('/series', {\n params: newPage\n }).then(response => {\n newShows.push(...response.data);\n commit('updateLoadingCurrent', response.data.length);\n resolve();\n }).catch(error => {\n reject(error);\n });\n }));\n }\n }).catch(() => {\n console.log('Could not retrieve a list of shows');\n }).finally(() => {\n Promise.all(pageRequests).then(() => {\n // Commit all the found shows to store.\n commit(_mutation_types__WEBPACK_IMPORTED_MODULE_0__.ADD_SHOWS, newShows); // Update (namespaced) localStorage\n\n const namespace = rootState.config.system.webRoot ? `${rootState.config.system.webRoot}_` : '';\n\n try {\n localStorage.setItem(`${namespace}shows`, JSON.stringify(state.shows));\n } catch (error) {\n console.warn(error);\n }\n\n resolve();\n });\n }));\n });\n },\n\n setShow(_ref21, _ref22) {\n let {\n rootState\n } = _ref21;\n let {\n showSlug,\n data\n } = _ref22;\n // Update show, updated show will arrive over a WebSocket message\n return rootState.auth.client.api.patch(`series/${showSlug}`, data);\n },\n\n updateShow(context, show) {\n // Update local store\n const {\n commit\n } = context;\n return commit(_mutation_types__WEBPACK_IMPORTED_MODULE_0__.ADD_SHOW, show);\n },\n\n addSceneException(context, _ref23) {\n let {\n show,\n exception\n } = _ref23;\n const {\n commit\n } = context;\n commit(_mutation_types__WEBPACK_IMPORTED_MODULE_0__.ADD_SHOW_SCENE_EXCEPTION, {\n show,\n exception\n });\n },\n\n removeSceneException(context, _ref24) {\n let {\n show,\n exception\n } = _ref24;\n const {\n commit\n } = context;\n commit(_mutation_types__WEBPACK_IMPORTED_MODULE_0__.REMOVE_SHOW_SCENE_EXCEPTION, {\n show,\n exception\n });\n },\n\n setCurrentShow(context, showSlug) {\n return new Promise(resolve => {\n // Set current show\n const {\n commit\n } = context;\n commit('currentShow', showSlug);\n resolve();\n });\n },\n\n setShowConfig(context, _ref25) {\n let {\n show,\n config\n } = _ref25;\n const {\n commit\n } = context;\n commit(_mutation_types__WEBPACK_IMPORTED_MODULE_0__.ADD_SHOW_CONFIG, {\n show,\n config\n });\n },\n\n removeShow(_ref26, show) {\n let {\n commit,\n rootState,\n state\n } = _ref26;\n // Remove the show from store and localStorage (provided through websocket)\n commit(_mutation_types__WEBPACK_IMPORTED_MODULE_0__.REMOVE_SHOW, show); // Update recentShows.\n\n rootState.config.general.recentShows = rootState.config.general.recentShows.filter(recentShow => recentShow.showSlug !== show.id.slug);\n const config = {\n recentShows: rootState.config.general.recentShows\n };\n rootState.auth.client.api.patch('config/main', config); // Update (namespaced) localStorage\n\n const namespace = rootState.config.system.webRoot ? `${rootState.config.system.webRoot}_` : '';\n localStorage.setItem(`${namespace}shows`, JSON.stringify(state.shows));\n },\n\n updateShowQueueItem(context, queueItem) {\n // Update store's search queue item. (provided through websocket)\n const {\n commit\n } = context;\n return commit(_mutation_types__WEBPACK_IMPORTED_MODULE_0__.ADD_SHOW_QUEUE_ITEM, queueItem);\n },\n\n addSearchTemplate(_ref27, _ref28) {\n let {\n rootState,\n getters,\n commit\n } = _ref27;\n let {\n show,\n template\n } = _ref28;\n commit(_mutation_types__WEBPACK_IMPORTED_MODULE_0__.ADD_SHOW_CONFIG_TEMPLATE, {\n show,\n template\n });\n const data = {\n config: {\n searchTemplates: getters.getCurrentShow.config.searchTemplates\n }\n };\n return rootState.auth.client.api.patch(`series/${show.indexer}${show.id[show.indexer]}`, data);\n },\n\n removeSearchTemplate(_ref29, _ref30) {\n let {\n rootState,\n getters,\n commit\n } = _ref29;\n let {\n show,\n template\n } = _ref30;\n commit(_mutation_types__WEBPACK_IMPORTED_MODULE_0__.REMOVE_SHOW_CONFIG_TEMPLATE, {\n show,\n template\n });\n const data = {\n config: {\n searchTemplates: getters.getCurrentShow.config.searchTemplates\n }\n };\n return rootState.auth.client.api.patch(`series/${show.indexer}${show.id[show.indexer]}`, data);\n },\n\n initShowsFromLocalStorage(_ref31) {\n let {\n rootState,\n commit\n } = _ref31;\n const namespace = rootState.config.system.webRoot ? `${rootState.config.system.webRoot}_` : '';\n return commit('loadShowsFromStore', namespace);\n },\n\n updateEpisode(_ref32, episode) {\n let {\n state,\n commit\n } = _ref32;\n const show = state.shows.find(_ref33 => {\n let {\n id\n } = _ref33;\n return id.slug === episode.showSlug;\n });\n commit(_mutation_types__WEBPACK_IMPORTED_MODULE_0__.ADD_SHOW_EPISODE, {\n show,\n episodes: [episode]\n });\n }\n\n};\n/* harmony default export */ const __WEBPACK_DEFAULT_EXPORT__ = ({\n state,\n mutations,\n getters,\n actions\n});\n\n//# sourceURL=webpack://slim/./src/store/modules/shows.js?"); /***/ }), diff --git a/themes/light/assets/js/medusa-runtime.js b/themes/light/assets/js/medusa-runtime.js index bc05e65f4e..09bc04c043 100644 --- a/themes/light/assets/js/medusa-runtime.js +++ b/themes/light/assets/js/medusa-runtime.js @@ -1379,7 +1379,7 @@ eval("__webpack_require__.r(__webpack_exports__);\n/* harmony export */ __webpac /***/ ((__unused_webpack_module, __webpack_exports__, __webpack_require__) => { "use strict"; -eval("__webpack_require__.r(__webpack_exports__);\n/* harmony export */ __webpack_require__.d(__webpack_exports__, {\n/* harmony export */ \"default\": () => (__WEBPACK_DEFAULT_EXPORT__)\n/* harmony export */ });\n/* harmony import */ var vue__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(/*! vue */ \"./node_modules/vue/dist/vue.esm.js\");\n/* harmony import */ var vuex__WEBPACK_IMPORTED_MODULE_4__ = __webpack_require__(/*! vuex */ \"./node_modules/vuex/dist/vuex.esm.js\");\n/* harmony import */ var vue_native_websocket__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! vue-native-websocket */ \"./node_modules/vue-native-websocket/dist/build.js\");\n/* harmony import */ var vue_native_websocket__WEBPACK_IMPORTED_MODULE_0___default = /*#__PURE__*/__webpack_require__.n(vue_native_websocket__WEBPACK_IMPORTED_MODULE_0__);\n/* harmony import */ var _modules__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! ./modules */ \"./src/store/modules/index.js\");\n/* harmony import */ var _mutation_types__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(/*! ./mutation-types */ \"./src/store/mutation-types.js\");\n\n\n\n\n\nvue__WEBPACK_IMPORTED_MODULE_3__[\"default\"].use(vuex__WEBPACK_IMPORTED_MODULE_4__[\"default\"]);\nconst store = new vuex__WEBPACK_IMPORTED_MODULE_4__.Store({\n modules: {\n auth: _modules__WEBPACK_IMPORTED_MODULE_1__.auth,\n config: _modules__WEBPACK_IMPORTED_MODULE_1__.config,\n defaults: _modules__WEBPACK_IMPORTED_MODULE_1__.defaults,\n history: _modules__WEBPACK_IMPORTED_MODULE_1__.history,\n notifications: _modules__WEBPACK_IMPORTED_MODULE_1__.notifications,\n provider: _modules__WEBPACK_IMPORTED_MODULE_1__.provider,\n recommended: _modules__WEBPACK_IMPORTED_MODULE_1__.recommended,\n schedule: _modules__WEBPACK_IMPORTED_MODULE_1__.schedule,\n shows: _modules__WEBPACK_IMPORTED_MODULE_1__.shows,\n socket: _modules__WEBPACK_IMPORTED_MODULE_1__.socket,\n stats: _modules__WEBPACK_IMPORTED_MODULE_1__.stats,\n queue: _modules__WEBPACK_IMPORTED_MODULE_1__.queue\n },\n state: {},\n mutations: {},\n getters: {},\n actions: {}\n}); // Keep as a non-arrow function for `this` context.\n\nconst passToStoreHandler = function (eventName, event, next) {\n const target = eventName.toUpperCase();\n const eventData = event.data;\n\n if (target === 'SOCKET_ONMESSAGE') {\n const message = JSON.parse(eventData);\n const {\n data,\n event\n } = message; // Show the notification to the user\n\n if (event === 'notification') {\n const {\n body,\n hash,\n type,\n title\n } = data;\n window.displayNotification(type, title, body, hash);\n } else if (event === 'configUpdated') {\n const {\n section,\n config\n } = data;\n this.store.dispatch('updateConfig', {\n section,\n config\n });\n } else if (event === 'showUpdated' || event === 'showAdded') {\n this.store.dispatch('updateShow', data);\n } else if (event === 'showRemoved') {\n // We need this for the QueueItemChangeIndexer\n this.store.dispatch('removeShow', data);\n } else if (event === 'addManualSearchResult') {\n this.store.dispatch('addManualSearchResult', data);\n } else if (event === 'QueueItemUpdate') {\n this.store.dispatch('updateQueueItem', data);\n } else if (event === 'QueueItemShow') {\n // Used as a generic showqueue item. If you want to know the specific action (update, refresh, remove, etc.)\n // Use queueItem.name. Like queueItem.name === 'REFRESH'.\n if (data.name === 'REMOVE-SHOW') {\n this.store.dispatch('removeShow', data.show);\n } else {\n this.store.dispatch('updateShowQueueItem', data);\n }\n } else if (event === 'historyUpdate') {\n this.store.dispatch('updateHistory', data);\n } else {\n window.displayNotification('info', event, data);\n }\n } // Resume normal 'passToStore' handling\n\n\n next(eventName, event);\n};\n\nconst websocketUrl = (() => {\n const {\n protocol,\n host\n } = window.location;\n const proto = protocol === 'https:' ? 'wss:' : 'ws:';\n const WSMessageUrl = '/ui';\n let webRoot = document.body.getAttribute('web-root');\n\n if (webRoot) {\n if (!webRoot.startsWith('/')) {\n webRoot = `/${webRoot}`;\n }\n }\n\n return `${proto}//${host}${webRoot}/ws${WSMessageUrl}`;\n})();\n\nvue__WEBPACK_IMPORTED_MODULE_3__[\"default\"].use((vue_native_websocket__WEBPACK_IMPORTED_MODULE_0___default()), websocketUrl, {\n store,\n format: 'json',\n reconnection: true,\n // (Boolean) whether to reconnect automatically (false)\n reconnectionAttempts: 25,\n // (Number) number of reconnection attempts before giving up (Infinity),\n reconnectionDelay: 2500,\n // (Number) how long to initially wait before attempting a new (1000)\n passToStoreHandler,\n // (Function|) Handler for events triggered by the WebSocket (false)\n mutations: {\n SOCKET_ONOPEN: _mutation_types__WEBPACK_IMPORTED_MODULE_2__.SOCKET_ONOPEN,\n SOCKET_ONCLOSE: _mutation_types__WEBPACK_IMPORTED_MODULE_2__.SOCKET_ONCLOSE,\n SOCKET_ONERROR: _mutation_types__WEBPACK_IMPORTED_MODULE_2__.SOCKET_ONERROR,\n SOCKET_ONMESSAGE: _mutation_types__WEBPACK_IMPORTED_MODULE_2__.SOCKET_ONMESSAGE,\n SOCKET_RECONNECT: _mutation_types__WEBPACK_IMPORTED_MODULE_2__.SOCKET_RECONNECT,\n SOCKET_RECONNECT_ERROR: _mutation_types__WEBPACK_IMPORTED_MODULE_2__.SOCKET_RECONNECT_ERROR\n }\n});\n/* harmony default export */ const __WEBPACK_DEFAULT_EXPORT__ = (store);\n\n//# sourceURL=webpack://slim/./src/store/index.js?"); +eval("__webpack_require__.r(__webpack_exports__);\n/* harmony export */ __webpack_require__.d(__webpack_exports__, {\n/* harmony export */ \"default\": () => (__WEBPACK_DEFAULT_EXPORT__)\n/* harmony export */ });\n/* harmony import */ var vue__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(/*! vue */ \"./node_modules/vue/dist/vue.esm.js\");\n/* harmony import */ var vuex__WEBPACK_IMPORTED_MODULE_4__ = __webpack_require__(/*! vuex */ \"./node_modules/vuex/dist/vuex.esm.js\");\n/* harmony import */ var vue_native_websocket__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! vue-native-websocket */ \"./node_modules/vue-native-websocket/dist/build.js\");\n/* harmony import */ var vue_native_websocket__WEBPACK_IMPORTED_MODULE_0___default = /*#__PURE__*/__webpack_require__.n(vue_native_websocket__WEBPACK_IMPORTED_MODULE_0__);\n/* harmony import */ var _modules__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! ./modules */ \"./src/store/modules/index.js\");\n/* harmony import */ var _mutation_types__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(/*! ./mutation-types */ \"./src/store/mutation-types.js\");\n\n\n\n\n\nvue__WEBPACK_IMPORTED_MODULE_3__[\"default\"].use(vuex__WEBPACK_IMPORTED_MODULE_4__[\"default\"]);\nconst store = new vuex__WEBPACK_IMPORTED_MODULE_4__.Store({\n modules: {\n auth: _modules__WEBPACK_IMPORTED_MODULE_1__.auth,\n config: _modules__WEBPACK_IMPORTED_MODULE_1__.config,\n defaults: _modules__WEBPACK_IMPORTED_MODULE_1__.defaults,\n history: _modules__WEBPACK_IMPORTED_MODULE_1__.history,\n notifications: _modules__WEBPACK_IMPORTED_MODULE_1__.notifications,\n provider: _modules__WEBPACK_IMPORTED_MODULE_1__.provider,\n recommended: _modules__WEBPACK_IMPORTED_MODULE_1__.recommended,\n schedule: _modules__WEBPACK_IMPORTED_MODULE_1__.schedule,\n shows: _modules__WEBPACK_IMPORTED_MODULE_1__.shows,\n socket: _modules__WEBPACK_IMPORTED_MODULE_1__.socket,\n stats: _modules__WEBPACK_IMPORTED_MODULE_1__.stats,\n queue: _modules__WEBPACK_IMPORTED_MODULE_1__.queue\n },\n state: {},\n mutations: {},\n getters: {},\n actions: {}\n}); // Keep as a non-arrow function for `this` context.\n\nconst passToStoreHandler = function (eventName, event, next) {\n const target = eventName.toUpperCase();\n const eventData = event.data;\n\n if (target === 'SOCKET_ONMESSAGE') {\n const message = JSON.parse(eventData);\n const {\n data,\n event\n } = message; // Show the notification to the user\n\n if (event === 'notification') {\n const {\n body,\n hash,\n type,\n title\n } = data;\n window.displayNotification(type, title, body, hash);\n } else if (event === 'configUpdated') {\n const {\n section,\n config\n } = data;\n this.store.dispatch('updateConfig', {\n section,\n config\n });\n } else if (event === 'showUpdated' || event === 'showAdded') {\n this.store.dispatch('updateShow', data);\n } else if (event === 'showRemoved') {\n // We need this for the QueueItemChangeIndexerstatus\n this.store.dispatch('removeShow', data);\n } else if (event === 'addManualSearchResult') {\n this.store.dispatch('addManualSearchResult', data);\n } else if (event === 'QueueItemUpdate') {\n this.store.dispatch('updateQueueItem', data);\n } else if (event === 'QueueItemShow') {\n // Used as a generic showqueue item. If you want to know the specific action (update, refresh, remove, etc.)\n // Use queueItem.name. Like queueItem.name === 'REFRESH'.\n if (data.name === 'REMOVE-SHOW') {\n this.store.dispatch('removeShow', data.show);\n } else {\n this.store.dispatch('updateShowQueueItem', data);\n }\n } else if (event === 'historyUpdate') {\n this.store.dispatch('updateHistory', data);\n } else if (event === 'episodeUpdated') {\n this.store.dispatch('updateEpisode', data);\n } else {\n window.displayNotification('info', event, data);\n }\n } // Resume normal 'passToStore' handling\n\n\n next(eventName, event);\n};\n\nconst websocketUrl = (() => {\n const {\n protocol,\n host\n } = window.location;\n const proto = protocol === 'https:' ? 'wss:' : 'ws:';\n const WSMessageUrl = '/ui';\n let webRoot = document.body.getAttribute('web-root');\n\n if (webRoot) {\n if (!webRoot.startsWith('/')) {\n webRoot = `/${webRoot}`;\n }\n }\n\n return `${proto}//${host}${webRoot}/ws${WSMessageUrl}`;\n})();\n\nvue__WEBPACK_IMPORTED_MODULE_3__[\"default\"].use((vue_native_websocket__WEBPACK_IMPORTED_MODULE_0___default()), websocketUrl, {\n store,\n format: 'json',\n reconnection: true,\n // (Boolean) whether to reconnect automatically (false)\n reconnectionAttempts: 25,\n // (Number) number of reconnection attempts before giving up (Infinity),\n reconnectionDelay: 2500,\n // (Number) how long to initially wait before attempting a new (1000)\n passToStoreHandler,\n // (Function|) Handler for events triggered by the WebSocket (false)\n mutations: {\n SOCKET_ONOPEN: _mutation_types__WEBPACK_IMPORTED_MODULE_2__.SOCKET_ONOPEN,\n SOCKET_ONCLOSE: _mutation_types__WEBPACK_IMPORTED_MODULE_2__.SOCKET_ONCLOSE,\n SOCKET_ONERROR: _mutation_types__WEBPACK_IMPORTED_MODULE_2__.SOCKET_ONERROR,\n SOCKET_ONMESSAGE: _mutation_types__WEBPACK_IMPORTED_MODULE_2__.SOCKET_ONMESSAGE,\n SOCKET_RECONNECT: _mutation_types__WEBPACK_IMPORTED_MODULE_2__.SOCKET_RECONNECT,\n SOCKET_RECONNECT_ERROR: _mutation_types__WEBPACK_IMPORTED_MODULE_2__.SOCKET_RECONNECT_ERROR\n }\n});\n/* harmony default export */ const __WEBPACK_DEFAULT_EXPORT__ = (store);\n\n//# sourceURL=webpack://slim/./src/store/index.js?"); /***/ }), @@ -1885,7 +1885,7 @@ eval("__webpack_require__.r(__webpack_exports__);\n/* harmony export */ __webpac /***/ ((__unused_webpack_module, __webpack_exports__, __webpack_require__) => { "use strict"; -eval("__webpack_require__.r(__webpack_exports__);\n/* harmony export */ __webpack_require__.d(__webpack_exports__, {\n/* harmony export */ \"default\": () => (__WEBPACK_DEFAULT_EXPORT__)\n/* harmony export */ });\n/* harmony import */ var vue__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! vue */ \"./node_modules/vue/dist/vue.esm.js\");\n/* harmony import */ var _mutation_types__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! ../mutation-types */ \"./src/store/mutation-types.js\");\n\n\n/**\n * @typedef {object} ShowIdentifier\n * @property {string} indexer The indexer name (e.g. `tvdb`)\n * @property {number} id The show ID on the indexer (e.g. `12345`)\n */\n\nconst state = {\n shows: [],\n currentShow: {\n showSlug: null\n },\n loading: {\n total: null,\n current: null,\n display: false,\n finished: false\n },\n queueitems: []\n};\nconst mutations = {\n [_mutation_types__WEBPACK_IMPORTED_MODULE_0__.ADD_SHOW](state, show) {\n const existingShow = state.shows.find(_ref => {\n let {\n id,\n indexer\n } = _ref;\n return Number(show.id[show.indexer]) === Number(id[indexer]);\n });\n\n if (!existingShow) {\n console.debug(`Adding ${show.title || show.indexer + String(show.id)} as it wasn't found in the shows array`, show);\n state.shows.push(show);\n return;\n } // Merge new show object over old one\n // this allows detailed queries to update the record\n // without the non-detailed removing the extra data\n\n\n console.debug(`Found ${show.title || show.indexer + String(show.id)} in shows array attempting merge`);\n const newShow = { ...existingShow,\n ...show\n }; // Repair the searchTemplates\n\n newShow.config.searchTemplates = show.config.searchTemplates ? show.config.searchTemplates : existingShow.config.searchTemplates; // Update state\n\n vue__WEBPACK_IMPORTED_MODULE_1__[\"default\"].set(state.shows, state.shows.indexOf(existingShow), newShow);\n console.debug(`Merged ${newShow.title || newShow.indexer + String(newShow.id)}`, newShow);\n },\n\n [_mutation_types__WEBPACK_IMPORTED_MODULE_0__.ADD_SHOWS](state, shows) {\n // If the show is already available, we only want to merge values\n const mergedShows = [];\n\n for (const newShow of shows) {\n const existing = state.shows.find(stateShow => stateShow.id.slug === newShow.id.slug);\n\n if (existing) {\n const {\n sceneAbsoluteNumbering,\n xemAbsoluteNumbering,\n sceneNumbering,\n ...showWithoutDetailed\n } = newShow; // Repair searchTemplates.\n\n const mergedShow = { ...existing,\n ...showWithoutDetailed\n };\n mergedShow.config.searchTemplates = showWithoutDetailed.config.searchTemplates ? showWithoutDetailed.config.searchTemplates : existing.config.searchTemplates;\n mergedShows.push(mergedShow);\n } else {\n mergedShows.push(newShow);\n }\n }\n\n state.shows = mergedShows;\n console.debug(`Added ${shows.length} shows to store`);\n },\n\n [_mutation_types__WEBPACK_IMPORTED_MODULE_0__.ADD_SHOW_CONFIG](state, _ref2) {\n let {\n show,\n config\n } = _ref2;\n const existingShow = state.shows.find(_ref3 => {\n let {\n id,\n indexer\n } = _ref3;\n return Number(show.id[show.indexer]) === Number(id[indexer]);\n });\n existingShow.config = { ...existingShow.config,\n ...config\n };\n },\n\n currentShow(state, showSlug) {\n state.currentShow.showSlug = showSlug;\n },\n\n setLoadingTotal(state, total) {\n state.loading.total = total;\n },\n\n setLoadingCurrent(state, current) {\n state.loading.current = current;\n },\n\n updateLoadingCurrent(state, current) {\n state.loading.current += current;\n },\n\n setLoadingDisplay(state, display) {\n state.loading.display = display;\n },\n\n setLoadingFinished(state, finished) {\n state.loading.finished = finished;\n },\n\n [_mutation_types__WEBPACK_IMPORTED_MODULE_0__.ADD_SHOW_EPISODE](state, _ref4) {\n let {\n show,\n episodes\n } = _ref4;\n // Creating a new show object (from the state one) as we want to trigger a store update\n const newShow = Object.assign({}, state.shows.find(_ref5 => {\n let {\n id,\n indexer\n } = _ref5;\n return Number(show.id[show.indexer]) === Number(id[indexer]);\n }));\n\n if (!newShow.seasons) {\n newShow.seasons = [];\n } // Recreate an Array with season objects, with each season having an episodes array.\n // This format is used by vue-good-table (displayShow).\n\n\n episodes.forEach(episode => {\n let existingSeason = newShow.seasons.find(season => season.season === episode.season);\n\n if (existingSeason) {\n // Shallow copy\n existingSeason = { ...existingSeason\n };\n const foundIndex = existingSeason.children.findIndex(element => element.slug === episode.slug);\n\n if (foundIndex === -1) {\n existingSeason.children.push(episode);\n } else {\n existingSeason.children.splice(foundIndex, 1, episode);\n }\n } else {\n const newSeason = {\n season: episode.season,\n children: [],\n html: false,\n mode: 'span',\n label: 1\n };\n newShow.seasons.push(newSeason);\n newSeason.children.push(episode);\n }\n }); // Update state\n\n const existingShow = state.shows.find(_ref6 => {\n let {\n id,\n indexer\n } = _ref6;\n return Number(show.id[show.indexer]) === Number(id[indexer]);\n });\n vue__WEBPACK_IMPORTED_MODULE_1__[\"default\"].set(state.shows, state.shows.indexOf(existingShow), newShow);\n console.log(`Storing episodes for show ${newShow.title} seasons: ${[...new Set(episodes.map(episode => episode.season))].join(', ')}`);\n },\n\n [_mutation_types__WEBPACK_IMPORTED_MODULE_0__.ADD_SHOW_SCENE_EXCEPTION](state, _ref7) {\n let {\n show,\n exception\n } = _ref7;\n // Get current show object\n const currentShow = Object.assign({}, state.shows.find(_ref8 => {\n let {\n id,\n indexer\n } = _ref8;\n return Number(show.id[show.indexer]) === Number(id[indexer]);\n }));\n\n if (currentShow.config.aliases.find(e => e.title === exception.title && e.season === exception.season)) {\n console.warn(`Can't add exception ${exception.title} with season ${exception.season} to show ${currentShow.title} as it already exists.`);\n return;\n }\n\n currentShow.config.aliases.push(exception);\n },\n\n [_mutation_types__WEBPACK_IMPORTED_MODULE_0__.REMOVE_SHOW_SCENE_EXCEPTION](state, _ref9) {\n let {\n show,\n exception\n } = _ref9;\n // Get current show object\n const currentShow = Object.assign({}, state.shows.find(_ref10 => {\n let {\n id,\n indexer\n } = _ref10;\n return Number(show.id[show.indexer]) === Number(id[indexer]);\n }));\n\n if (!currentShow.config.aliases.find(e => e.title === exception.title && e.season === exception.season)) {\n console.warn(`Can't remove exception ${exception.title} with season ${exception.season} to show ${currentShow.title} as it does not exist.`);\n return;\n }\n\n currentShow.config.aliases.splice(currentShow.config.aliases.indexOf(exception), 1);\n },\n\n [_mutation_types__WEBPACK_IMPORTED_MODULE_0__.ADD_SHOW_QUEUE_ITEM](state, queueItem) {\n const existingQueueItem = state.queueitems.find(item => item.identifier === queueItem.identifier);\n\n if (existingQueueItem) {\n vue__WEBPACK_IMPORTED_MODULE_1__[\"default\"].set(state.queueitems, state.queueitems.indexOf(existingQueueItem), { ...existingQueueItem,\n ...queueItem\n });\n } else {\n vue__WEBPACK_IMPORTED_MODULE_1__[\"default\"].set(state.queueitems, state.queueitems.length, queueItem);\n }\n },\n\n [_mutation_types__WEBPACK_IMPORTED_MODULE_0__.ADD_SHOW_CONFIG_TEMPLATE](state, _ref11) {\n let {\n show,\n template\n } = _ref11;\n // Get current show object\n const currentShow = Object.assign({}, state.shows.find(_ref12 => {\n let {\n id,\n indexer\n } = _ref12;\n return Number(show.id[show.indexer]) === Number(id[indexer]);\n }));\n\n if (currentShow.config.searchTemplates.find(t => t.template === template.pattern)) {\n console.warn(`Can't add template (${template.pattern} to show ${currentShow.title} as it already exists.`);\n return;\n }\n\n currentShow.config.searchTemplates.push(template);\n },\n\n [_mutation_types__WEBPACK_IMPORTED_MODULE_0__.REMOVE_SHOW_CONFIG_TEMPLATE](state, _ref13) {\n let {\n show,\n template\n } = _ref13;\n // Get current show object\n const currentShow = Object.assign({}, state.shows.find(_ref14 => {\n let {\n id,\n indexer\n } = _ref14;\n return Number(show.id[show.indexer]) === Number(id[indexer]);\n }));\n\n if (template.id) {\n currentShow.config.searchTemplates = currentShow.config.searchTemplates.filter(t => t.id !== template.id);\n return;\n }\n\n currentShow.config.searchTemplates = currentShow.config.searchTemplates.filter(t => !(t.title === template.title && t.season === template.season && t.template === template.template));\n },\n\n [_mutation_types__WEBPACK_IMPORTED_MODULE_0__.REMOVE_SHOW](state, removedShow) {\n state.shows = state.shows.filter(existingShow => removedShow.id.slug !== existingShow.id.slug);\n },\n\n loadShowsFromStore(state, namespace) {\n // Check if the ID exists\n // Update (namespaced) localStorage\n if (localStorage.getItem('shows')) {\n vue__WEBPACK_IMPORTED_MODULE_1__[\"default\"].set(state, 'shows', JSON.parse(localStorage.getItem(`${namespace}shows`)));\n }\n }\n\n};\nconst getters = {\n getShowById: state => {\n /**\n * Get a show from the loaded shows state, identified by show slug.\n *\n * @param {string} showSlug Show identifier.\n * @returns {object|undefined} Show object or undefined if not found.\n */\n const getShowById = showSlug => state.shows.find(show => show.id.slug === showSlug);\n\n return getShowById;\n },\n getShowByTitle: state => title => state.shows.find(show => show.title === title),\n getSeason: state => _ref15 => {\n let {\n showSlug,\n season\n } = _ref15;\n const show = state.shows.find(show => show.id.slug === showSlug);\n return show && show.seasons ? show.seasons[season] : undefined;\n },\n getEpisode: state => _ref16 => {\n let {\n showSlug,\n season,\n episode\n } = _ref16;\n const show = state.shows.find(show => show.id.slug === showSlug);\n return show && show.seasons && show.seasons.find(s => s.season === season) ? show.seasons.find(s => s.season === season).children.find(ep => ep.episode === episode) : undefined;\n },\n getCurrentShow: (state, _, rootState) => {\n return state.shows.find(show => show.id.slug === state.currentShow.showSlug) || rootState.defaults.show;\n },\n getShowIndexerUrl: (state, getters, rootState) => show => {\n const indexerConfig = rootState.config.indexers.indexers;\n\n if (!show.indexer || !indexerConfig[show.indexer]) {\n return;\n }\n\n const id = show.id[show.indexer];\n const indexerUrl = indexerConfig[show.indexer].showUrl;\n\n if (show.indexer === 'imdb') {\n return `${indexerUrl}${String(id).padStart(7, '0')}`;\n }\n\n return `${indexerUrl}${id}`;\n },\n showsWithStats: (state, getters, rootState) => {\n if (!state.shows) {\n return [];\n }\n\n return state.shows.map(show => {\n let showStats = rootState.stats.show.stats.find(stat => stat.indexerId === getters.indexerNameToId(show.indexer) && stat.seriesId === show.id[show.indexer]);\n const newLine = '\\u000D';\n let text = 'Unaired';\n let title = '';\n\n if (!showStats) {\n showStats = {\n epDownloaded: 0,\n epSnatched: 0,\n epTotal: 0,\n seriesSize: 0\n };\n }\n\n if (showStats.epTotal >= 1) {\n text = showStats.epDownloaded;\n title = `Downloaded: ${showStats.epDownloaded}`;\n\n if (showStats.epSnatched) {\n text += `+${showStats.epSnatched}`;\n title += `${newLine}Snatched: ${showStats.epSnatched}`;\n }\n\n text += ` / ${showStats.epTotal}`;\n title += `${newLine}Total: ${showStats.epTotal}`;\n }\n\n show.stats = {\n episodes: {\n total: showStats.epTotal,\n snatched: showStats.epSnatched,\n downloaded: showStats.epDownloaded,\n size: showStats.seriesSize\n },\n tooltip: {\n text,\n title,\n percentage: showStats.epDownloaded * 100 / (showStats.epTotal || 1)\n }\n };\n return show;\n });\n },\n showsInLists: (state, getters, rootState) => {\n const {\n layout,\n general\n } = rootState.config;\n const {\n show\n } = layout;\n const {\n showListOrder\n } = show;\n const {\n rootDirs\n } = general;\n const {\n selectedRootIndex,\n local\n } = layout;\n const {\n showFilterByName\n } = local;\n const {\n showsWithStats\n } = getters;\n let shows = null; // Filter root dirs\n\n shows = showsWithStats.filter(show => selectedRootIndex === -1 || show.config.location.includes(rootDirs.slice(1)[selectedRootIndex])); // Filter by text for the banner, simple and smallposter layouts.\n // The Poster layout uses vue-isotope and this does not respond well to changes to the `list` property.\n\n if (layout.home !== 'poster') {\n shows = shows.filter(show => show.title.toLowerCase().includes(showFilterByName.toLowerCase()));\n }\n\n const categorizedShows = showListOrder.filter(listTitle => shows.filter(show => show.config.showLists.map(list => list.toLowerCase()).includes(listTitle.toLowerCase())).length > 0).map(listTitle => ({\n listTitle,\n shows: shows.filter(show => show.config.showLists.map(list => list.toLowerCase()).includes(listTitle.toLowerCase()))\n })); // Check for shows that are not in any category anymore\n\n const uncategorizedShows = shows.filter(show => {\n return show.config.showLists.map(item => {\n return showListOrder.map(list => list.toLowerCase()).includes(item.toLowerCase());\n }).every(item => !item);\n });\n\n if (uncategorizedShows.length > 0) {\n categorizedShows.push({\n listTitle: 'uncategorized',\n shows: uncategorizedShows\n });\n }\n\n if (categorizedShows.length === 0 && uncategorizedShows.length === 0) {\n categorizedShows.push({\n listTitle: 'Series',\n shows: []\n });\n }\n\n return categorizedShows;\n }\n};\n/**\n * An object representing request parameters for getting a show from the API.\n *\n * @typedef {object} ShowGetParameters\n * @property {boolean} detailed Fetch detailed information? (e.g. scene/xem numbering)\n * @property {boolean} episodes Fetch seasons & episodes?\n */\n\nconst actions = {\n /**\n * Get show from API and commit it to the store.\n *\n * @param {*} context The store context.\n * @param {ShowIdentifier&ShowGetParameters} parameters Request parameters.\n * @returns {Promise} The API response.\n */\n getShow(_ref17, _ref18) {\n let {\n rootState,\n commit\n } = _ref17;\n let {\n showSlug,\n detailed,\n episodes\n } = _ref18;\n return new Promise((resolve, reject) => {\n const params = {};\n let timeout = 30000;\n\n if (detailed !== undefined) {\n params.detailed = detailed;\n timeout = 60000;\n timeout = 60000;\n }\n\n if (episodes !== undefined) {\n params.episodes = episodes;\n timeout = 60000;\n }\n\n rootState.auth.client.api.get(`/series/${showSlug}`, {\n params,\n timeout\n }).then(res => {\n commit(_mutation_types__WEBPACK_IMPORTED_MODULE_0__.ADD_SHOW, res.data);\n resolve(res.data);\n }).catch(error => {\n reject(error);\n });\n });\n },\n\n /**\n * Get episdoes for a specified show from API and commit it to the store.\n *\n * @param {*} context - The store context.\n * @param {ShowParameteres} parameters - Request parameters.\n * @returns {Promise} The API response.\n */\n getEpisodes(_ref19, _ref20) {\n let {\n rootState,\n commit,\n getters\n } = _ref19;\n let {\n showSlug,\n season\n } = _ref20;\n return new Promise((resolve, reject) => {\n const {\n getShowById\n } = getters;\n const show = getShowById(showSlug);\n const limit = 1000;\n const params = {\n limit\n };\n\n if (season !== undefined) {\n params.season = season;\n } // Get episodes\n\n\n rootState.auth.client.api.get(`/series/${showSlug}/episodes`, {\n params\n }).then(response => {\n commit(_mutation_types__WEBPACK_IMPORTED_MODULE_0__.ADD_SHOW_EPISODE, {\n show,\n episodes: response.data\n });\n resolve();\n }).catch(error => {\n console.log(`Could not retrieve a episodes for show ${showSlug}, error: ${error}`);\n reject(error);\n });\n });\n },\n\n /**\n * Get shows from API and commit them to the store.\n *\n * @param {*} context - The store context.\n * @param {(ShowIdentifier&ShowGetParameters)[]} shows Shows to get. If not provided, gets the first 1k shows.\n * @returns {undefined|Promise} undefined if `shows` was provided or the API response if not.\n */\n getShows(context, shows) {\n const {\n commit,\n dispatch,\n state,\n rootState\n } = context; // If no shows are provided get the first 1000\n\n if (shows) {\n // Return a specific show list. (not used afaik).\n return shows.forEach(show => dispatch('getShow', show));\n }\n\n return new Promise((resolve, _) => {\n // Loading new shows, commit show loading information to state.\n commit('setLoadingTotal', 0);\n commit('setLoadingCurrent', 0);\n commit('setLoadingDisplay', true);\n const limit = 1000;\n const page = 1;\n const params = {\n limit,\n page\n };\n const pageRequests = [];\n const newShows = []; // Get first page\n\n pageRequests.push(rootState.auth.client.api.get('/series', {\n params\n }).then(response => {\n commit('setLoadingTotal', Number(response.headers['x-pagination-count']));\n const totalPages = Number(response.headers['x-pagination-total']);\n newShows.push(...response.data);\n commit('updateLoadingCurrent', response.data.length); // Optionally get additional pages\n\n for (let page = 2; page <= totalPages; page++) {\n pageRequests.push(new Promise((resolve, reject) => {\n const newPage = {\n page\n };\n newPage.limit = params.limit;\n return rootState.auth.client.api.get('/series', {\n params: newPage\n }).then(response => {\n newShows.push(...response.data);\n commit('updateLoadingCurrent', response.data.length);\n resolve();\n }).catch(error => {\n reject(error);\n });\n }));\n }\n }).catch(() => {\n console.log('Could not retrieve a list of shows');\n }).finally(() => {\n Promise.all(pageRequests).then(() => {\n // Commit all the found shows to store.\n commit(_mutation_types__WEBPACK_IMPORTED_MODULE_0__.ADD_SHOWS, newShows); // Update (namespaced) localStorage\n\n const namespace = rootState.config.system.webRoot ? `${rootState.config.system.webRoot}_` : '';\n\n try {\n localStorage.setItem(`${namespace}shows`, JSON.stringify(state.shows));\n } catch (error) {\n console.warn(error);\n }\n\n resolve();\n });\n }));\n });\n },\n\n setShow(_ref21, _ref22) {\n let {\n rootState\n } = _ref21;\n let {\n showSlug,\n data\n } = _ref22;\n // Update show, updated show will arrive over a WebSocket message\n return rootState.auth.client.api.patch(`series/${showSlug}`, data);\n },\n\n updateShow(context, show) {\n // Update local store\n const {\n commit\n } = context;\n return commit(_mutation_types__WEBPACK_IMPORTED_MODULE_0__.ADD_SHOW, show);\n },\n\n addSceneException(context, _ref23) {\n let {\n show,\n exception\n } = _ref23;\n const {\n commit\n } = context;\n commit(_mutation_types__WEBPACK_IMPORTED_MODULE_0__.ADD_SHOW_SCENE_EXCEPTION, {\n show,\n exception\n });\n },\n\n removeSceneException(context, _ref24) {\n let {\n show,\n exception\n } = _ref24;\n const {\n commit\n } = context;\n commit(_mutation_types__WEBPACK_IMPORTED_MODULE_0__.REMOVE_SHOW_SCENE_EXCEPTION, {\n show,\n exception\n });\n },\n\n setCurrentShow(context, showSlug) {\n return new Promise(resolve => {\n // Set current show\n const {\n commit\n } = context;\n commit('currentShow', showSlug);\n resolve();\n });\n },\n\n setShowConfig(context, _ref25) {\n let {\n show,\n config\n } = _ref25;\n const {\n commit\n } = context;\n commit(_mutation_types__WEBPACK_IMPORTED_MODULE_0__.ADD_SHOW_CONFIG, {\n show,\n config\n });\n },\n\n removeShow(_ref26, show) {\n let {\n commit,\n rootState,\n state\n } = _ref26;\n // Remove the show from store and localStorage (provided through websocket)\n commit(_mutation_types__WEBPACK_IMPORTED_MODULE_0__.REMOVE_SHOW, show); // Update recentShows.\n\n rootState.config.general.recentShows = rootState.config.general.recentShows.filter(recentShow => recentShow.showSlug !== show.id.slug);\n const config = {\n recentShows: rootState.config.general.recentShows\n };\n rootState.auth.client.api.patch('config/main', config); // Update (namespaced) localStorage\n\n const namespace = rootState.config.system.webRoot ? `${rootState.config.system.webRoot}_` : '';\n localStorage.setItem(`${namespace}shows`, JSON.stringify(state.shows));\n },\n\n updateShowQueueItem(context, queueItem) {\n // Update store's search queue item. (provided through websocket)\n const {\n commit\n } = context;\n return commit(_mutation_types__WEBPACK_IMPORTED_MODULE_0__.ADD_SHOW_QUEUE_ITEM, queueItem);\n },\n\n addSearchTemplate(_ref27, _ref28) {\n let {\n rootState,\n getters,\n commit\n } = _ref27;\n let {\n show,\n template\n } = _ref28;\n commit(_mutation_types__WEBPACK_IMPORTED_MODULE_0__.ADD_SHOW_CONFIG_TEMPLATE, {\n show,\n template\n });\n const data = {\n config: {\n searchTemplates: getters.getCurrentShow.config.searchTemplates\n }\n };\n return rootState.auth.client.api.patch(`series/${show.indexer}${show.id[show.indexer]}`, data);\n },\n\n removeSearchTemplate(_ref29, _ref30) {\n let {\n rootState,\n getters,\n commit\n } = _ref29;\n let {\n show,\n template\n } = _ref30;\n commit(_mutation_types__WEBPACK_IMPORTED_MODULE_0__.REMOVE_SHOW_CONFIG_TEMPLATE, {\n show,\n template\n });\n const data = {\n config: {\n searchTemplates: getters.getCurrentShow.config.searchTemplates\n }\n };\n return rootState.auth.client.api.patch(`series/${show.indexer}${show.id[show.indexer]}`, data);\n },\n\n initShowsFromLocalStorage(_ref31) {\n let {\n rootState,\n commit\n } = _ref31;\n const namespace = rootState.config.system.webRoot ? `${rootState.config.system.webRoot}_` : '';\n return commit('loadShowsFromStore', namespace);\n }\n\n};\n/* harmony default export */ const __WEBPACK_DEFAULT_EXPORT__ = ({\n state,\n mutations,\n getters,\n actions\n});\n\n//# sourceURL=webpack://slim/./src/store/modules/shows.js?"); +eval("__webpack_require__.r(__webpack_exports__);\n/* harmony export */ __webpack_require__.d(__webpack_exports__, {\n/* harmony export */ \"default\": () => (__WEBPACK_DEFAULT_EXPORT__)\n/* harmony export */ });\n/* harmony import */ var vue__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! vue */ \"./node_modules/vue/dist/vue.esm.js\");\n/* harmony import */ var _mutation_types__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! ../mutation-types */ \"./src/store/mutation-types.js\");\n\n\n/**\n * @typedef {object} ShowIdentifier\n * @property {string} indexer The indexer name (e.g. `tvdb`)\n * @property {number} id The show ID on the indexer (e.g. `12345`)\n */\n\nconst state = {\n shows: [],\n currentShow: {\n showSlug: null\n },\n loading: {\n total: null,\n current: null,\n display: false,\n finished: false\n },\n queueitems: []\n};\nconst mutations = {\n [_mutation_types__WEBPACK_IMPORTED_MODULE_0__.ADD_SHOW](state, show) {\n const existingShow = state.shows.find(_ref => {\n let {\n id,\n indexer\n } = _ref;\n return Number(show.id[show.indexer]) === Number(id[indexer]);\n });\n\n if (!existingShow) {\n console.debug(`Adding ${show.title || show.indexer + String(show.id)} as it wasn't found in the shows array`, show);\n state.shows.push(show);\n return;\n } // Merge new show object over old one\n // this allows detailed queries to update the record\n // without the non-detailed removing the extra data\n\n\n console.debug(`Found ${show.title || show.indexer + String(show.id)} in shows array attempting merge`);\n const newShow = { ...existingShow,\n ...show\n }; // Repair the searchTemplates\n\n newShow.config.searchTemplates = show.config.searchTemplates ? show.config.searchTemplates : existingShow.config.searchTemplates; // Update state\n\n vue__WEBPACK_IMPORTED_MODULE_1__[\"default\"].set(state.shows, state.shows.indexOf(existingShow), newShow);\n console.debug(`Merged ${newShow.title || newShow.indexer + String(newShow.id)}`, newShow);\n },\n\n [_mutation_types__WEBPACK_IMPORTED_MODULE_0__.ADD_SHOWS](state, shows) {\n // If the show is already available, we only want to merge values\n const mergedShows = [];\n\n for (const newShow of shows) {\n const existing = state.shows.find(stateShow => stateShow.id.slug === newShow.id.slug);\n\n if (existing) {\n const {\n sceneAbsoluteNumbering,\n xemAbsoluteNumbering,\n sceneNumbering,\n ...showWithoutDetailed\n } = newShow; // Repair searchTemplates.\n\n const mergedShow = { ...existing,\n ...showWithoutDetailed\n };\n mergedShow.config.searchTemplates = showWithoutDetailed.config.searchTemplates ? showWithoutDetailed.config.searchTemplates : existing.config.searchTemplates;\n mergedShows.push(mergedShow);\n } else {\n mergedShows.push(newShow);\n }\n }\n\n state.shows = mergedShows;\n console.debug(`Added ${shows.length} shows to store`);\n },\n\n [_mutation_types__WEBPACK_IMPORTED_MODULE_0__.ADD_SHOW_CONFIG](state, _ref2) {\n let {\n show,\n config\n } = _ref2;\n const existingShow = state.shows.find(_ref3 => {\n let {\n id,\n indexer\n } = _ref3;\n return Number(show.id[show.indexer]) === Number(id[indexer]);\n });\n existingShow.config = { ...existingShow.config,\n ...config\n };\n },\n\n currentShow(state, showSlug) {\n state.currentShow.showSlug = showSlug;\n },\n\n setLoadingTotal(state, total) {\n state.loading.total = total;\n },\n\n setLoadingCurrent(state, current) {\n state.loading.current = current;\n },\n\n updateLoadingCurrent(state, current) {\n state.loading.current += current;\n },\n\n setLoadingDisplay(state, display) {\n state.loading.display = display;\n },\n\n setLoadingFinished(state, finished) {\n state.loading.finished = finished;\n },\n\n [_mutation_types__WEBPACK_IMPORTED_MODULE_0__.ADD_SHOW_EPISODE](state, _ref4) {\n let {\n show,\n episodes\n } = _ref4;\n // Creating a new show object (from the state one) as we want to trigger a store update\n const newShow = Object.assign({}, state.shows.find(_ref5 => {\n let {\n id,\n indexer\n } = _ref5;\n return Number(show.id[show.indexer]) === Number(id[indexer]);\n }));\n\n if (!newShow.seasons) {\n newShow.seasons = [];\n } // Recreate an Array with season objects, with each season having an episodes array.\n // This format is used by vue-good-table (displayShow).\n\n\n episodes.forEach(episode => {\n let existingSeason = newShow.seasons.find(season => season.season === episode.season);\n\n if (existingSeason) {\n // Shallow copy\n existingSeason = { ...existingSeason\n };\n const foundIndex = existingSeason.children.findIndex(element => element.slug === episode.slug);\n\n if (foundIndex === -1) {\n existingSeason.children.push(episode);\n } else {\n existingSeason.children.splice(foundIndex, 1, episode);\n }\n } else {\n const newSeason = {\n season: episode.season,\n children: [],\n html: false,\n mode: 'span',\n label: 1\n };\n newShow.seasons.push(newSeason);\n newSeason.children.push(episode);\n }\n }); // Update state\n\n const existingShow = state.shows.find(_ref6 => {\n let {\n id,\n indexer\n } = _ref6;\n return Number(show.id[show.indexer]) === Number(id[indexer]);\n });\n vue__WEBPACK_IMPORTED_MODULE_1__[\"default\"].set(state.shows, state.shows.indexOf(existingShow), newShow);\n console.log(`Storing episodes for show ${newShow.title} seasons: ${[...new Set(episodes.map(episode => episode.season))].join(', ')}`);\n },\n\n [_mutation_types__WEBPACK_IMPORTED_MODULE_0__.ADD_SHOW_SCENE_EXCEPTION](state, _ref7) {\n let {\n show,\n exception\n } = _ref7;\n // Get current show object\n const currentShow = Object.assign({}, state.shows.find(_ref8 => {\n let {\n id,\n indexer\n } = _ref8;\n return Number(show.id[show.indexer]) === Number(id[indexer]);\n }));\n\n if (currentShow.config.aliases.find(e => e.title === exception.title && e.season === exception.season)) {\n console.warn(`Can't add exception ${exception.title} with season ${exception.season} to show ${currentShow.title} as it already exists.`);\n return;\n }\n\n currentShow.config.aliases.push(exception);\n },\n\n [_mutation_types__WEBPACK_IMPORTED_MODULE_0__.REMOVE_SHOW_SCENE_EXCEPTION](state, _ref9) {\n let {\n show,\n exception\n } = _ref9;\n // Get current show object\n const currentShow = Object.assign({}, state.shows.find(_ref10 => {\n let {\n id,\n indexer\n } = _ref10;\n return Number(show.id[show.indexer]) === Number(id[indexer]);\n }));\n\n if (!currentShow.config.aliases.find(e => e.title === exception.title && e.season === exception.season)) {\n console.warn(`Can't remove exception ${exception.title} with season ${exception.season} to show ${currentShow.title} as it does not exist.`);\n return;\n }\n\n currentShow.config.aliases.splice(currentShow.config.aliases.indexOf(exception), 1);\n },\n\n [_mutation_types__WEBPACK_IMPORTED_MODULE_0__.ADD_SHOW_QUEUE_ITEM](state, queueItem) {\n const existingQueueItem = state.queueitems.find(item => item.identifier === queueItem.identifier);\n\n if (existingQueueItem) {\n vue__WEBPACK_IMPORTED_MODULE_1__[\"default\"].set(state.queueitems, state.queueitems.indexOf(existingQueueItem), { ...existingQueueItem,\n ...queueItem\n });\n } else {\n vue__WEBPACK_IMPORTED_MODULE_1__[\"default\"].set(state.queueitems, state.queueitems.length, queueItem);\n }\n },\n\n [_mutation_types__WEBPACK_IMPORTED_MODULE_0__.ADD_SHOW_CONFIG_TEMPLATE](state, _ref11) {\n let {\n show,\n template\n } = _ref11;\n // Get current show object\n const currentShow = Object.assign({}, state.shows.find(_ref12 => {\n let {\n id,\n indexer\n } = _ref12;\n return Number(show.id[show.indexer]) === Number(id[indexer]);\n }));\n\n if (currentShow.config.searchTemplates.find(t => t.template === template.pattern)) {\n console.warn(`Can't add template (${template.pattern} to show ${currentShow.title} as it already exists.`);\n return;\n }\n\n currentShow.config.searchTemplates.push(template);\n },\n\n [_mutation_types__WEBPACK_IMPORTED_MODULE_0__.REMOVE_SHOW_CONFIG_TEMPLATE](state, _ref13) {\n let {\n show,\n template\n } = _ref13;\n // Get current show object\n const currentShow = Object.assign({}, state.shows.find(_ref14 => {\n let {\n id,\n indexer\n } = _ref14;\n return Number(show.id[show.indexer]) === Number(id[indexer]);\n }));\n\n if (template.id) {\n currentShow.config.searchTemplates = currentShow.config.searchTemplates.filter(t => t.id !== template.id);\n return;\n }\n\n currentShow.config.searchTemplates = currentShow.config.searchTemplates.filter(t => !(t.title === template.title && t.season === template.season && t.template === template.template));\n },\n\n [_mutation_types__WEBPACK_IMPORTED_MODULE_0__.REMOVE_SHOW](state, removedShow) {\n state.shows = state.shows.filter(existingShow => removedShow.id.slug !== existingShow.id.slug);\n },\n\n loadShowsFromStore(state, namespace) {\n // Check if the ID exists\n // Update (namespaced) localStorage\n if (localStorage.getItem('shows')) {\n vue__WEBPACK_IMPORTED_MODULE_1__[\"default\"].set(state, 'shows', JSON.parse(localStorage.getItem(`${namespace}shows`)));\n }\n }\n\n};\nconst getters = {\n getShowById: state => {\n /**\n * Get a show from the loaded shows state, identified by show slug.\n *\n * @param {string} showSlug Show identifier.\n * @returns {object|undefined} Show object or undefined if not found.\n */\n const getShowById = showSlug => state.shows.find(show => show.id.slug === showSlug);\n\n return getShowById;\n },\n getShowByTitle: state => title => state.shows.find(show => show.title === title),\n getSeason: state => _ref15 => {\n let {\n showSlug,\n season\n } = _ref15;\n const show = state.shows.find(show => show.id.slug === showSlug);\n return show && show.seasons ? show.seasons[season] : undefined;\n },\n getEpisode: state => _ref16 => {\n let {\n showSlug,\n season,\n episode\n } = _ref16;\n const show = state.shows.find(show => show.id.slug === showSlug);\n return show && show.seasons && show.seasons.find(s => s.season === season) ? show.seasons.find(s => s.season === season).children.find(ep => ep.episode === episode) : undefined;\n },\n getCurrentShow: (state, _, rootState) => {\n return state.shows.find(show => show.id.slug === state.currentShow.showSlug) || rootState.defaults.show;\n },\n getShowIndexerUrl: (state, getters, rootState) => show => {\n const indexerConfig = rootState.config.indexers.indexers;\n\n if (!show.indexer || !indexerConfig[show.indexer]) {\n return;\n }\n\n const id = show.id[show.indexer];\n const indexerUrl = indexerConfig[show.indexer].showUrl;\n\n if (show.indexer === 'imdb') {\n return `${indexerUrl}${String(id).padStart(7, '0')}`;\n }\n\n return `${indexerUrl}${id}`;\n },\n showsWithStats: (state, getters, rootState) => {\n if (!state.shows) {\n return [];\n }\n\n return state.shows.map(show => {\n let showStats = rootState.stats.show.stats.find(stat => stat.indexerId === getters.indexerNameToId(show.indexer) && stat.seriesId === show.id[show.indexer]);\n const newLine = '\\u000D';\n let text = 'Unaired';\n let title = '';\n\n if (!showStats) {\n showStats = {\n epDownloaded: 0,\n epSnatched: 0,\n epTotal: 0,\n seriesSize: 0\n };\n }\n\n if (showStats.epTotal >= 1) {\n text = showStats.epDownloaded;\n title = `Downloaded: ${showStats.epDownloaded}`;\n\n if (showStats.epSnatched) {\n text += `+${showStats.epSnatched}`;\n title += `${newLine}Snatched: ${showStats.epSnatched}`;\n }\n\n text += ` / ${showStats.epTotal}`;\n title += `${newLine}Total: ${showStats.epTotal}`;\n }\n\n show.stats = {\n episodes: {\n total: showStats.epTotal,\n snatched: showStats.epSnatched,\n downloaded: showStats.epDownloaded,\n size: showStats.seriesSize\n },\n tooltip: {\n text,\n title,\n percentage: showStats.epDownloaded * 100 / (showStats.epTotal || 1)\n }\n };\n return show;\n });\n },\n showsInLists: (state, getters, rootState) => {\n const {\n layout,\n general\n } = rootState.config;\n const {\n show\n } = layout;\n const {\n showListOrder\n } = show;\n const {\n rootDirs\n } = general;\n const {\n selectedRootIndex,\n local\n } = layout;\n const {\n showFilterByName\n } = local;\n const {\n showsWithStats\n } = getters;\n let shows = null; // Filter root dirs\n\n shows = showsWithStats.filter(show => selectedRootIndex === -1 || show.config.location.includes(rootDirs.slice(1)[selectedRootIndex])); // Filter by text for the banner, simple and smallposter layouts.\n // The Poster layout uses vue-isotope and this does not respond well to changes to the `list` property.\n\n if (layout.home !== 'poster') {\n shows = shows.filter(show => show.title.toLowerCase().includes(showFilterByName.toLowerCase()));\n }\n\n const categorizedShows = showListOrder.filter(listTitle => shows.filter(show => show.config.showLists.map(list => list.toLowerCase()).includes(listTitle.toLowerCase())).length > 0).map(listTitle => ({\n listTitle,\n shows: shows.filter(show => show.config.showLists.map(list => list.toLowerCase()).includes(listTitle.toLowerCase()))\n })); // Check for shows that are not in any category anymore\n\n const uncategorizedShows = shows.filter(show => {\n return show.config.showLists.map(item => {\n return showListOrder.map(list => list.toLowerCase()).includes(item.toLowerCase());\n }).every(item => !item);\n });\n\n if (uncategorizedShows.length > 0) {\n categorizedShows.push({\n listTitle: 'uncategorized',\n shows: uncategorizedShows\n });\n }\n\n if (categorizedShows.length === 0 && uncategorizedShows.length === 0) {\n categorizedShows.push({\n listTitle: 'Series',\n shows: []\n });\n }\n\n return categorizedShows;\n }\n};\n/**\n * An object representing request parameters for getting a show from the API.\n *\n * @typedef {object} ShowGetParameters\n * @property {boolean} detailed Fetch detailed information? (e.g. scene/xem numbering)\n * @property {boolean} episodes Fetch seasons & episodes?\n */\n\nconst actions = {\n /**\n * Get show from API and commit it to the store.\n *\n * @param {*} context The store context.\n * @param {ShowIdentifier&ShowGetParameters} parameters Request parameters.\n * @returns {Promise} The API response.\n */\n getShow(_ref17, _ref18) {\n let {\n rootState,\n commit\n } = _ref17;\n let {\n showSlug,\n detailed,\n episodes\n } = _ref18;\n return new Promise((resolve, reject) => {\n const params = {};\n let timeout = 30000;\n\n if (detailed !== undefined) {\n params.detailed = detailed;\n timeout = 60000;\n timeout = 60000;\n }\n\n if (episodes !== undefined) {\n params.episodes = episodes;\n timeout = 60000;\n }\n\n rootState.auth.client.api.get(`/series/${showSlug}`, {\n params,\n timeout\n }).then(res => {\n commit(_mutation_types__WEBPACK_IMPORTED_MODULE_0__.ADD_SHOW, res.data);\n resolve(res.data);\n }).catch(error => {\n reject(error);\n });\n });\n },\n\n /**\n * Get episdoes for a specified show from API and commit it to the store.\n *\n * @param {*} context - The store context.\n * @param {ShowParameteres} parameters - Request parameters.\n * @returns {Promise} The API response.\n */\n getEpisodes(_ref19, _ref20) {\n let {\n rootState,\n commit,\n getters\n } = _ref19;\n let {\n showSlug,\n season\n } = _ref20;\n return new Promise((resolve, reject) => {\n const {\n getShowById\n } = getters;\n const show = getShowById(showSlug);\n const limit = 1000;\n const params = {\n limit\n };\n\n if (season !== undefined) {\n params.season = season;\n } // Get episodes\n\n\n rootState.auth.client.api.get(`/series/${showSlug}/episodes`, {\n params\n }).then(response => {\n commit(_mutation_types__WEBPACK_IMPORTED_MODULE_0__.ADD_SHOW_EPISODE, {\n show,\n episodes: response.data\n });\n resolve();\n }).catch(error => {\n console.log(`Could not retrieve a episodes for show ${showSlug}, error: ${error}`);\n reject(error);\n });\n });\n },\n\n /**\n * Get shows from API and commit them to the store.\n *\n * @param {*} context - The store context.\n * @param {(ShowIdentifier&ShowGetParameters)[]} shows Shows to get. If not provided, gets the first 1k shows.\n * @returns {undefined|Promise} undefined if `shows` was provided or the API response if not.\n */\n getShows(context, shows) {\n const {\n commit,\n dispatch,\n state,\n rootState\n } = context; // If no shows are provided get the first 1000\n\n if (shows) {\n // Return a specific show list. (not used afaik).\n return shows.forEach(show => dispatch('getShow', show));\n }\n\n return new Promise((resolve, _) => {\n // Loading new shows, commit show loading information to state.\n commit('setLoadingTotal', 0);\n commit('setLoadingCurrent', 0);\n commit('setLoadingDisplay', true);\n const limit = 1000;\n const page = 1;\n const params = {\n limit,\n page\n };\n const pageRequests = [];\n const newShows = []; // Get first page\n\n pageRequests.push(rootState.auth.client.api.get('/series', {\n params\n }).then(response => {\n commit('setLoadingTotal', Number(response.headers['x-pagination-count']));\n const totalPages = Number(response.headers['x-pagination-total']);\n newShows.push(...response.data);\n commit('updateLoadingCurrent', response.data.length); // Optionally get additional pages\n\n for (let page = 2; page <= totalPages; page++) {\n pageRequests.push(new Promise((resolve, reject) => {\n const newPage = {\n page\n };\n newPage.limit = params.limit;\n return rootState.auth.client.api.get('/series', {\n params: newPage\n }).then(response => {\n newShows.push(...response.data);\n commit('updateLoadingCurrent', response.data.length);\n resolve();\n }).catch(error => {\n reject(error);\n });\n }));\n }\n }).catch(() => {\n console.log('Could not retrieve a list of shows');\n }).finally(() => {\n Promise.all(pageRequests).then(() => {\n // Commit all the found shows to store.\n commit(_mutation_types__WEBPACK_IMPORTED_MODULE_0__.ADD_SHOWS, newShows); // Update (namespaced) localStorage\n\n const namespace = rootState.config.system.webRoot ? `${rootState.config.system.webRoot}_` : '';\n\n try {\n localStorage.setItem(`${namespace}shows`, JSON.stringify(state.shows));\n } catch (error) {\n console.warn(error);\n }\n\n resolve();\n });\n }));\n });\n },\n\n setShow(_ref21, _ref22) {\n let {\n rootState\n } = _ref21;\n let {\n showSlug,\n data\n } = _ref22;\n // Update show, updated show will arrive over a WebSocket message\n return rootState.auth.client.api.patch(`series/${showSlug}`, data);\n },\n\n updateShow(context, show) {\n // Update local store\n const {\n commit\n } = context;\n return commit(_mutation_types__WEBPACK_IMPORTED_MODULE_0__.ADD_SHOW, show);\n },\n\n addSceneException(context, _ref23) {\n let {\n show,\n exception\n } = _ref23;\n const {\n commit\n } = context;\n commit(_mutation_types__WEBPACK_IMPORTED_MODULE_0__.ADD_SHOW_SCENE_EXCEPTION, {\n show,\n exception\n });\n },\n\n removeSceneException(context, _ref24) {\n let {\n show,\n exception\n } = _ref24;\n const {\n commit\n } = context;\n commit(_mutation_types__WEBPACK_IMPORTED_MODULE_0__.REMOVE_SHOW_SCENE_EXCEPTION, {\n show,\n exception\n });\n },\n\n setCurrentShow(context, showSlug) {\n return new Promise(resolve => {\n // Set current show\n const {\n commit\n } = context;\n commit('currentShow', showSlug);\n resolve();\n });\n },\n\n setShowConfig(context, _ref25) {\n let {\n show,\n config\n } = _ref25;\n const {\n commit\n } = context;\n commit(_mutation_types__WEBPACK_IMPORTED_MODULE_0__.ADD_SHOW_CONFIG, {\n show,\n config\n });\n },\n\n removeShow(_ref26, show) {\n let {\n commit,\n rootState,\n state\n } = _ref26;\n // Remove the show from store and localStorage (provided through websocket)\n commit(_mutation_types__WEBPACK_IMPORTED_MODULE_0__.REMOVE_SHOW, show); // Update recentShows.\n\n rootState.config.general.recentShows = rootState.config.general.recentShows.filter(recentShow => recentShow.showSlug !== show.id.slug);\n const config = {\n recentShows: rootState.config.general.recentShows\n };\n rootState.auth.client.api.patch('config/main', config); // Update (namespaced) localStorage\n\n const namespace = rootState.config.system.webRoot ? `${rootState.config.system.webRoot}_` : '';\n localStorage.setItem(`${namespace}shows`, JSON.stringify(state.shows));\n },\n\n updateShowQueueItem(context, queueItem) {\n // Update store's search queue item. (provided through websocket)\n const {\n commit\n } = context;\n return commit(_mutation_types__WEBPACK_IMPORTED_MODULE_0__.ADD_SHOW_QUEUE_ITEM, queueItem);\n },\n\n addSearchTemplate(_ref27, _ref28) {\n let {\n rootState,\n getters,\n commit\n } = _ref27;\n let {\n show,\n template\n } = _ref28;\n commit(_mutation_types__WEBPACK_IMPORTED_MODULE_0__.ADD_SHOW_CONFIG_TEMPLATE, {\n show,\n template\n });\n const data = {\n config: {\n searchTemplates: getters.getCurrentShow.config.searchTemplates\n }\n };\n return rootState.auth.client.api.patch(`series/${show.indexer}${show.id[show.indexer]}`, data);\n },\n\n removeSearchTemplate(_ref29, _ref30) {\n let {\n rootState,\n getters,\n commit\n } = _ref29;\n let {\n show,\n template\n } = _ref30;\n commit(_mutation_types__WEBPACK_IMPORTED_MODULE_0__.REMOVE_SHOW_CONFIG_TEMPLATE, {\n show,\n template\n });\n const data = {\n config: {\n searchTemplates: getters.getCurrentShow.config.searchTemplates\n }\n };\n return rootState.auth.client.api.patch(`series/${show.indexer}${show.id[show.indexer]}`, data);\n },\n\n initShowsFromLocalStorage(_ref31) {\n let {\n rootState,\n commit\n } = _ref31;\n const namespace = rootState.config.system.webRoot ? `${rootState.config.system.webRoot}_` : '';\n return commit('loadShowsFromStore', namespace);\n },\n\n updateEpisode(_ref32, episode) {\n let {\n state,\n commit\n } = _ref32;\n const show = state.shows.find(_ref33 => {\n let {\n id\n } = _ref33;\n return id.slug === episode.showSlug;\n });\n commit(_mutation_types__WEBPACK_IMPORTED_MODULE_0__.ADD_SHOW_EPISODE, {\n show,\n episodes: [episode]\n });\n }\n\n};\n/* harmony default export */ const __WEBPACK_DEFAULT_EXPORT__ = ({\n state,\n mutations,\n getters,\n actions\n});\n\n//# sourceURL=webpack://slim/./src/store/modules/shows.js?"); /***/ }),