diff --git a/dredd/api-description.yml b/dredd/api-description.yml index d8546882424..8d6e4168a08 100644 --- a/dredd/api-description.yml +++ b/dredd/api-description.yml @@ -2565,11 +2565,12 @@ parameters: description: The configuration to retrieve type: string enum: - - main + - main # Keep main first, as the tests use it - consts - metadata - - search - notifiers + - search + - system log-level: name: level in: query diff --git a/medusa/helpers/__init__.py b/medusa/helpers/__init__.py index 583931cfc9b..c8907135aa9 100644 --- a/medusa/helpers/__init__.py +++ b/medusa/helpers/__init__.py @@ -65,6 +65,16 @@ except ImportError: reflink = None +try: + from psutil import Process + memory_usage_tool = 'psutil' +except ImportError: + try: + import resource # resource module is unix only + memory_usage_tool = 'resource' + except ImportError: + memory_usage_tool = None + def indent_xml(elem, level=0): """Do our pretty printing and make Matt very happy.""" @@ -1450,6 +1460,28 @@ def get_disk_space_usage(disk_path=None, pretty=True): return False +def memory_usage(pretty=True): + """ + Get the current memory usage (if possible). + + :param pretty: True for human readable size, False for bytes + + :return: Current memory usage + """ + usage = '' + if memory_usage_tool == 'resource': + usage = resource.getrusage(resource.RUSAGE_SELF).ru_maxrss + elif memory_usage_tool == 'psutil': + usage = Process(os.getpid()).memory_info().rss + else: + return '' + + if pretty: + usage = pretty_file_size(usage) + + return usage + + def get_tvdb_from_id(indexer_id, indexer): session = MedusaSafeSession() diff --git a/medusa/helpers/utils.py b/medusa/helpers/utils.py index 7fc2a204eb9..0ed598a08db 100644 --- a/medusa/helpers/utils.py +++ b/medusa/helpers/utils.py @@ -84,7 +84,8 @@ def strtobool(val): def to_timestamp(dt): - """Return POSIX timestamp corresponding to the datetime instance. + """ + Return POSIX timestamp corresponding to the datetime instance. :param dt: datetime (possibly aware) :return: seconds since epoch as float @@ -102,3 +103,18 @@ def to_camel_case(snake_str): """Convert a snake formatted string to camel case.""" components = snake_str.split('_') return components[0] + ''.join(x.title() for x in components[1:]) + + +def timedelta_in_milliseconds(td): + """ + Return the value of the timedelta object in milliseconds. + + :param td: timedelta + :type td: timedelta + :return: the value of the timedelta in milliseconds + :rtype: int + """ + if not td: + return 0 + + return int(td.total_seconds() * 1000) diff --git a/medusa/server/api/v2/config.py b/medusa/server/api/v2/config.py index ef10f418512..a33b84e39b0 100644 --- a/medusa/server/api/v2/config.py +++ b/medusa/server/api/v2/config.py @@ -15,6 +15,7 @@ common, config, db, + helpers, logger, ws, ) @@ -33,6 +34,10 @@ iter_nested_items, set_nested_value, ) +from medusa.system.schedulers import ( + generate_schedulers, + generate_show_queue, +) from six import iteritems, itervalues, text_type from six.moves import map @@ -914,6 +919,17 @@ def data_notifiers(): return section_data + @staticmethod + def data_system(): + """System information.""" + section_data = {} + + section_data['memoryUsage'] = helpers.memory_usage(pretty=True) + section_data['schedulers'] = generate_schedulers() + section_data['showQueue'] = generate_show_queue() + + return section_data + @staticmethod def data_clients(): """Notifications.""" diff --git a/medusa/server/api/v2/stats.py b/medusa/server/api/v2/stats.py index 1044909fedd..df3cc1347e3 100644 --- a/medusa/server/api/v2/stats.py +++ b/medusa/server/api/v2/stats.py @@ -18,6 +18,9 @@ WANTED ) from medusa.server.api.v2.base import BaseRequestHandler +from medusa.show.show import Show + +from six.moves import map class StatsHandler(BaseRequestHandler): @@ -28,93 +31,102 @@ class StatsHandler(BaseRequestHandler): #: identifier identifier = ('identifier', r'\w+') #: path param - path_param = ('path_param', r'\w+') + path_param = None #: allowed HTTP methods allowed_methods = ('GET', ) - def get(self, identifier, path_param=None): + def get(self, identifier): """Query statistics. - :param identifier: - :param path_param: - :type path_param: str + :param identifier: The type of statistics to query + :type identifier: str """ - pre_today = [SKIPPED, WANTED, FAILED] - snatched = [SNATCHED, SNATCHED_PROPER, SNATCHED_BEST] - downloaded = [DOWNLOADED, ARCHIVED] - - def query_in(items): - return '({0})'.format(','.join(map(str, items))) - - query = dedent("""\ - SELECT indexer AS indexerId, showid AS seriesId, - SUM( - season > 0 AND - episode > 0 AND - airdate > 1 AND - status IN {status_quality} - ) AS epSnatched, - SUM( - season > 0 AND - episode > 0 AND + if not identifier or identifier == 'overall': + data = overall_stats() + elif identifier == 'show': + data = per_show_stats() + else: + return self._not_found('Statistics not found') + + return self._ok(data=data) + + +def overall_stats(): + """Generate overall library statistics.""" + return Show.overall_stats() + + +def per_show_stats(): + """Generate per-show library statistics.""" + pre_today = [SKIPPED, WANTED, FAILED] + snatched = [SNATCHED, SNATCHED_PROPER, SNATCHED_BEST] + downloaded = [DOWNLOADED, ARCHIVED] + + def query_in(items): + return '({0})'.format(','.join(map(str, items))) + + query = dedent("""\ + SELECT indexer AS indexerId, showid AS seriesId, + SUM( + season > 0 AND + episode > 0 AND + airdate > 1 AND + status IN {status_quality} + ) AS epSnatched, + SUM( + season > 0 AND + episode > 0 AND + airdate > 1 AND + status IN {status_download} + ) AS epDownloaded, + SUM( + season > 0 AND + episode > 0 AND + airdate > 1 AND ( + (airdate <= {today} AND status IN {status_pre_today}) OR + status IN {status_both} + ) + ) AS epTotal, + (SELECT airdate FROM tv_episodes + WHERE showid=tv_eps.showid AND + indexer=tv_eps.indexer AND + airdate >= {today} AND + (status = {unaired} OR status = {wanted}) + ORDER BY airdate ASC + LIMIT 1 + ) AS epAirsNext, + (SELECT airdate FROM tv_episodes + WHERE showid=tv_eps.showid AND + indexer=tv_eps.indexer AND airdate > 1 AND - status IN {status_download} - ) AS epDownloaded, - SUM( - season > 0 AND - episode > 0 AND - airdate > 1 AND ( - (airdate <= {today} AND status IN {status_pre_today}) OR - status IN {status_both} - ) - ) AS epTotal, - (SELECT airdate FROM tv_episodes - WHERE showid=tv_eps.showid AND - indexer=tv_eps.indexer AND - airdate >= {today} AND - (status = {unaired} OR status = {wanted}) - ORDER BY airdate ASC - LIMIT 1 - ) AS epAirsNext, - (SELECT airdate FROM tv_episodes - WHERE showid=tv_eps.showid AND - indexer=tv_eps.indexer AND - airdate > 1 AND - status <> {unaired} - ORDER BY airdate DESC - LIMIT 1 - ) AS epAirsPrev, - SUM(file_size) AS seriesSize - FROM tv_episodes tv_eps - GROUP BY showid, indexer - """).format( - status_quality=query_in(snatched), - status_download=query_in(downloaded), - status_both=query_in(snatched + downloaded), - today=date.today().toordinal(), - status_pre_today=query_in(pre_today), - skipped=SKIPPED, - wanted=WANTED, - unaired=UNAIRED, - ) - - main_db_con = db.DBConnection() - sql_result = main_db_con.select(query) - - stats_data = {} - stats_data['seriesStat'] = list() - stats_data['maxDownloadCount'] = 1000 - for cur_result in sql_result: - stats_data['seriesStat'].append(dict(cur_result)) - if cur_result['epTotal'] > stats_data['maxDownloadCount']: - stats_data['maxDownloadCount'] = cur_result['epTotal'] - - stats_data['maxDownloadCount'] *= 100 - - if identifier is not None: - if identifier not in stats_data: - return self._bad_request('{key} is a invalid path'.format(key=identifier)) - - stats_data = stats_data[identifier] - - return self._ok(data=stats_data) + status <> {unaired} + ORDER BY airdate DESC + LIMIT 1 + ) AS epAirsPrev, + SUM(file_size) AS seriesSize + FROM tv_episodes tv_eps + GROUP BY showid, indexer + """).format( + status_quality=query_in(snatched), + status_download=query_in(downloaded), + status_both=query_in(snatched + downloaded), + today=date.today().toordinal(), + status_pre_today=query_in(pre_today), + skipped=SKIPPED, + wanted=WANTED, + unaired=UNAIRED, + ) + + main_db_con = db.DBConnection() + sql_result = main_db_con.select(query) + + stats_data = {} + stats_data['seriesStat'] = [] + stats_data['maxDownloadCount'] = 1000 + for cur_result in sql_result: + stats_data['seriesStat'].append(cur_result) + if cur_result['epTotal'] > stats_data['maxDownloadCount']: + stats_data['maxDownloadCount'] = cur_result['epTotal'] + + stats_data['maxDownloadCount'] *= 100 + return stats_data diff --git a/medusa/system/schedulers.py b/medusa/system/schedulers.py new file mode 100644 index 00000000000..5f4e9fe6116 --- /dev/null +++ b/medusa/system/schedulers.py @@ -0,0 +1,139 @@ +# coding=utf-8 +"""Helper functions to get info about running schedulers.""" +from __future__ import unicode_literals + +from medusa import app +from medusa.generic_queue import QueuePriorities +from medusa.helpers.utils import timedelta_in_milliseconds +from medusa.show_queue import ShowQueueActions + + +all_schedulers = [ + ('dailySearch', 'Daily Search', 'daily_search_scheduler'), + ('backlog', 'Backlog', 'backlog_search_scheduler'), + ('showUpdate', 'Show Update', 'show_update_scheduler'), + ('versionCheck', 'Version Check', 'version_check_scheduler'), + ('showQueue', 'Show Queue', 'show_queue_scheduler'), + ('searchQueue', 'Search Queue', 'search_queue_scheduler'), + ('properFinder', 'Proper Finder', 'proper_finder_scheduler'), + ('postProcess', 'Post Process', 'auto_post_processor_scheduler'), + ('subtitlesFinder', 'Subtitles Finder', 'subtitles_finder_scheduler'), + ('traktChecker', 'Trakt Checker', 'trakt_checker_scheduler'), + ('torrentChecker', 'Torrent Checker', 'torrent_checker_scheduler'), +] + + +def _is_enabled(key, scheduler): + if key == 'backlog' and app.search_queue_scheduler.action.is_backlog_paused(): + return 'Paused' + + return bool(scheduler.enable) + + +def _is_active(key, scheduler): + if key == 'backlog' and app.search_queue_scheduler.action.is_backlog_in_progress(): + return True + + try: + return bool(scheduler.action.amActive) + except AttributeError: + return None + + +def _scheduler_to_json(key, name, scheduler): + scheduler = getattr(app, scheduler) + if not scheduler: + # Not initialized + return { + 'key': key, + 'name': name, + } + + return { + 'key': key, + 'name': name, + 'isAlive': scheduler.is_alive(), + 'isEnabled': _is_enabled(key, scheduler), + 'isActive': _is_active(key, scheduler), + 'startTime': scheduler.start_time.isoformat() if scheduler.start_time else None, + 'cycleTime': timedelta_in_milliseconds(scheduler.cycleTime) or None, + 'nextRun': timedelta_in_milliseconds(scheduler.timeLeft()) if scheduler.enable else None, + 'lastRun': scheduler.lastRun.isoformat(), + 'isSilent': bool(scheduler.silent) + } + + +def _queued_show_to_json(item): + try: + show_slug = item.show.slug + except AttributeError: + show_slug = None + + try: + show_title = item.show.name + except AttributeError: + show_title = None + if item.action_id == ShowQueueActions.ADD: + show_dir = item.showDir + else: + show_dir = None + + if item.priority == QueuePriorities.LOW: + priority = 'low' + elif item.priority == QueuePriorities.NORMAL: + priority = 'normal' + elif item.priority == QueuePriorities.HIGH: + priority = 'high' + else: + priority = item.priority + + return { + 'showSlug': show_slug, + 'showTitle': show_title, + 'showDir': show_dir, + 'inProgress': bool(item.inProgress), + 'priority': priority, + 'added': item.added.isoformat(), + 'queueType': ShowQueueActions.names[item.action_id], + } + + +def generate_schedulers(): + """ + Generate a JSON-pickable list of scheduler dictionaries. + + :returns: list of scheduler dictionaries + """ + return [_scheduler_to_json(*scheduler) for scheduler in all_schedulers] + + +def scheduler_by_key(key): + """ + Get a JSON-pickable scheduler dictionary by its key. + + :param key: the key of the scheduler to get + :returns: a scheduler dictionary + :raises KeyError: if the scheduler could not be found + """ + try: + scheduler_tuple = next(item for item in all_schedulers if item[0] == key) + except StopIteration: + raise KeyError('Scheduler not found') + + return _scheduler_to_json(*scheduler_tuple) + + +def generate_show_queue(): + """ + Generate a JSON-pickable list of items in the show queue. + + :returns: list of show queue items + """ + if not app.show_queue_scheduler: + return [] + + queue = app.show_queue_scheduler.action.queue + if app.show_queue_scheduler.action.currentItem is not None: + queue.insert(0, app.show_queue_scheduler.action.currentItem) + + return [_queued_show_to_json(item) for item in queue] diff --git a/tests/apiv2/test_config.py b/tests/apiv2/test_config.py index e7e160f23cd..1a23b6e0c3a 100644 --- a/tests/apiv2/test_config.py +++ b/tests/apiv2/test_config.py @@ -7,8 +7,9 @@ import platform import sys -from medusa import app, classes, common, db, logger, metadata +from medusa import app, classes, common, db, helpers, logger, metadata from medusa.indexers.indexer_config import get_indexer_config +from medusa.system.schedulers import all_schedulers import pytest @@ -312,3 +313,32 @@ def test_config_get_metadata(http_client, create_url, auth_headers, config_metad # then assert response.code == 200 assert expected == json.loads(response.body) + + +@pytest.fixture +def config_system(monkeypatch, app_config): + def memory_usage_mock(*args, **kwargs): + return '124.86 MB' + monkeypatch.setattr(helpers, 'memory_usage', memory_usage_mock) + + section_data = {} + section_data['memoryUsage'] = memory_usage_mock() + section_data['schedulers'] = [{'key': scheduler[0], 'name': scheduler[1]} for scheduler in all_schedulers] + section_data['showQueue'] = [] + + return section_data + + +@pytest.mark.gen_test +def test_config_get_system(http_client, create_url, auth_headers, config_system): + # given + expected = config_system + + url = create_url('/config/system') + + # when + response = yield http_client.fetch(url, **auth_headers) + + # then + assert response.code == 200 + assert expected == json.loads(response.body) diff --git a/themes-default/slim/src/store/index.js b/themes-default/slim/src/store/index.js index 48c5d71fd25..ecdfaffde77 100644 --- a/themes-default/slim/src/store/index.js +++ b/themes-default/slim/src/store/index.js @@ -12,7 +12,9 @@ import { notifiers, search, shows, - socket + socket, + stats, + system } from './modules'; import { SOCKET_ONOPEN, @@ -37,7 +39,9 @@ const store = new Store({ notifiers, search, shows, - socket + socket, + stats, + system }, state: {}, mutations: {}, diff --git a/themes-default/slim/src/store/modules/index.js b/themes-default/slim/src/store/modules/index.js index 0640712f4bd..ba08c9f6778 100644 --- a/themes-default/slim/src/store/modules/index.js +++ b/themes-default/slim/src/store/modules/index.js @@ -9,3 +9,5 @@ export { default as notifiers } from './notifiers'; export { default as search } from './search'; export { default as shows } from './shows'; export { default as socket } from './socket'; +export { default as stats } from './stats'; +export { default as system } from './system'; diff --git a/themes-default/slim/src/store/modules/stats.js b/themes-default/slim/src/store/modules/stats.js new file mode 100644 index 00000000000..8a612effb58 --- /dev/null +++ b/themes-default/slim/src/store/modules/stats.js @@ -0,0 +1,44 @@ +import { api } from '../../api'; +import { ADD_STATS } from '../mutation-types'; + +const state = { + overall: { + episodes: { + downloaded: null, + snatched: null, + total: null + }, + shows: { + active: null, + total: null + } + } +}; + +const mutations = { + [ADD_STATS](state, payload) { + const { type, stats } = payload; + state[type] = Object.assign(state[type], stats); + } +}; + +const getters = {}; + +const actions = { + getStats(context, type) { + const { commit } = context; + return api.get('/stats/' + (type || '')).then(res => { + commit(ADD_STATS, { + type: (type || 'overall'), + stats: res.data + }); + }); + } +}; + +export default { + state, + mutations, + getters, + actions +}; diff --git a/themes-default/slim/src/store/modules/system.js b/themes-default/slim/src/store/modules/system.js new file mode 100644 index 00000000000..8871ac0e881 --- /dev/null +++ b/themes-default/slim/src/store/modules/system.js @@ -0,0 +1,31 @@ +import { ADD_CONFIG } from '../mutation-types'; + +const state = { + memoryUsage: null, + schedulers: [], + showQueue: [] +}; + +const mutations = { + [ADD_CONFIG](state, { section, config }) { + if (section === 'system') { + state = Object.assign(state, config); + } + } +}; + +const getters = { + // Get a scheduler object using a key + getScheduler: state => key => { + return state.schedulers.find(scheduler => key === scheduler.key); + } +}; + +const actions = {}; + +export default { + state, + mutations, + getters, + actions +}; diff --git a/themes-default/slim/src/store/mutation-types.js b/themes-default/slim/src/store/mutation-types.js index af9af520b6d..07f1fe79ada 100644 --- a/themes-default/slim/src/store/mutation-types.js +++ b/themes-default/slim/src/store/mutation-types.js @@ -14,6 +14,7 @@ const NOTIFICATIONS_ENABLED = '🔔 Notifications Enabled'; const NOTIFICATIONS_DISABLED = '🔔 Notifications Disabled'; const ADD_CONFIG = '⚙ī¸ Config added to store'; const ADD_SHOW = 'đŸ“ē Show added to store'; +const ADD_STATS = 'ℹī¸ Statistics added to store'; export { LOGIN_PENDING, @@ -31,5 +32,6 @@ export { NOTIFICATIONS_ENABLED, NOTIFICATIONS_DISABLED, ADD_CONFIG, - ADD_SHOW + ADD_SHOW, + ADD_STATS }; diff --git a/themes/dark/assets/js/medusa-runtime.js b/themes/dark/assets/js/medusa-runtime.js index 9ad0c0614b8..6952896a900 100644 --- a/themes/dark/assets/js/medusa-runtime.js +++ b/themes/dark/assets/js/medusa-runtime.js @@ -2884,7 +2884,7 @@ eval("__webpack_require__.r(__webpack_exports__);\n/* harmony import */ var vue_ /***/ (function(module, __webpack_exports__, __webpack_require__) { "use strict"; -eval("__webpack_require__.r(__webpack_exports__);\n/* harmony import */ var vue__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! vue */ \"./node_modules/vue/dist/vue.esm.js\");\n/* harmony import */ var vuex__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! vuex */ \"./node_modules/vuex/dist/vuex.esm.js\");\n/* harmony import */ var vue_native_websocket__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(/*! vue-native-websocket */ \"./node_modules/vue-native-websocket/dist/build.js\");\n/* harmony import */ var vue_native_websocket__WEBPACK_IMPORTED_MODULE_2___default = /*#__PURE__*/__webpack_require__.n(vue_native_websocket__WEBPACK_IMPORTED_MODULE_2__);\n/* harmony import */ var _modules__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(/*! ./modules */ \"./src/store/modules/index.js\");\n/* harmony import */ var _mutation_types__WEBPACK_IMPORTED_MODULE_4__ = __webpack_require__(/*! ./mutation-types */ \"./src/store/mutation-types.js\");\n\n\n\n\n\nvue__WEBPACK_IMPORTED_MODULE_0__[\"default\"].use(vuex__WEBPACK_IMPORTED_MODULE_1__[\"default\"]);\nconst store = new vuex__WEBPACK_IMPORTED_MODULE_1__[\"Store\"]({\n modules: {\n auth: _modules__WEBPACK_IMPORTED_MODULE_3__[\"auth\"],\n clients: _modules__WEBPACK_IMPORTED_MODULE_3__[\"clients\"],\n config: _modules__WEBPACK_IMPORTED_MODULE_3__[\"config\"],\n consts: _modules__WEBPACK_IMPORTED_MODULE_3__[\"consts\"],\n defaults: _modules__WEBPACK_IMPORTED_MODULE_3__[\"defaults\"],\n metadata: _modules__WEBPACK_IMPORTED_MODULE_3__[\"metadata\"],\n notifications: _modules__WEBPACK_IMPORTED_MODULE_3__[\"notifications\"],\n notifiers: _modules__WEBPACK_IMPORTED_MODULE_3__[\"notifiers\"],\n search: _modules__WEBPACK_IMPORTED_MODULE_3__[\"search\"],\n shows: _modules__WEBPACK_IMPORTED_MODULE_3__[\"shows\"],\n socket: _modules__WEBPACK_IMPORTED_MODULE_3__[\"socket\"]\n },\n state: {},\n mutations: {},\n getters: {},\n actions: {}\n}); // Keep as a non-arrow function for `this` context.\n\nconst passToStoreHandler = function passToStoreHandler(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 {\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 const webRoot = document.body.getAttribute('web-root');\n return \"\".concat(proto, \"//\").concat(host).concat(webRoot, \"/ws\").concat(WSMessageUrl);\n})();\n\nvue__WEBPACK_IMPORTED_MODULE_0__[\"default\"].use(vue_native_websocket__WEBPACK_IMPORTED_MODULE_2___default.a, websocketUrl, {\n store,\n format: 'json',\n reconnection: true,\n // (Boolean) whether to reconnect automatically (false)\n reconnectionAttempts: 2,\n // (Number) number of reconnection attempts before giving up (Infinity),\n reconnectionDelay: 1000,\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_4__[\"SOCKET_ONOPEN\"],\n SOCKET_ONCLOSE: _mutation_types__WEBPACK_IMPORTED_MODULE_4__[\"SOCKET_ONCLOSE\"],\n SOCKET_ONERROR: _mutation_types__WEBPACK_IMPORTED_MODULE_4__[\"SOCKET_ONERROR\"],\n SOCKET_ONMESSAGE: _mutation_types__WEBPACK_IMPORTED_MODULE_4__[\"SOCKET_ONMESSAGE\"],\n SOCKET_RECONNECT: _mutation_types__WEBPACK_IMPORTED_MODULE_4__[\"SOCKET_RECONNECT\"],\n SOCKET_RECONNECT_ERROR: _mutation_types__WEBPACK_IMPORTED_MODULE_4__[\"SOCKET_RECONNECT_ERROR\"]\n }\n});\n/* harmony default export */ __webpack_exports__[\"default\"] = (store);\n\n//# sourceURL=webpack:///./src/store/index.js?"); +eval("__webpack_require__.r(__webpack_exports__);\n/* harmony import */ var vue__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! vue */ \"./node_modules/vue/dist/vue.esm.js\");\n/* harmony import */ var vuex__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! vuex */ \"./node_modules/vuex/dist/vuex.esm.js\");\n/* harmony import */ var vue_native_websocket__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(/*! vue-native-websocket */ \"./node_modules/vue-native-websocket/dist/build.js\");\n/* harmony import */ var vue_native_websocket__WEBPACK_IMPORTED_MODULE_2___default = /*#__PURE__*/__webpack_require__.n(vue_native_websocket__WEBPACK_IMPORTED_MODULE_2__);\n/* harmony import */ var _modules__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(/*! ./modules */ \"./src/store/modules/index.js\");\n/* harmony import */ var _mutation_types__WEBPACK_IMPORTED_MODULE_4__ = __webpack_require__(/*! ./mutation-types */ \"./src/store/mutation-types.js\");\n\n\n\n\n\nvue__WEBPACK_IMPORTED_MODULE_0__[\"default\"].use(vuex__WEBPACK_IMPORTED_MODULE_1__[\"default\"]);\nconst store = new vuex__WEBPACK_IMPORTED_MODULE_1__[\"Store\"]({\n modules: {\n auth: _modules__WEBPACK_IMPORTED_MODULE_3__[\"auth\"],\n clients: _modules__WEBPACK_IMPORTED_MODULE_3__[\"clients\"],\n config: _modules__WEBPACK_IMPORTED_MODULE_3__[\"config\"],\n consts: _modules__WEBPACK_IMPORTED_MODULE_3__[\"consts\"],\n defaults: _modules__WEBPACK_IMPORTED_MODULE_3__[\"defaults\"],\n metadata: _modules__WEBPACK_IMPORTED_MODULE_3__[\"metadata\"],\n notifications: _modules__WEBPACK_IMPORTED_MODULE_3__[\"notifications\"],\n notifiers: _modules__WEBPACK_IMPORTED_MODULE_3__[\"notifiers\"],\n search: _modules__WEBPACK_IMPORTED_MODULE_3__[\"search\"],\n shows: _modules__WEBPACK_IMPORTED_MODULE_3__[\"shows\"],\n socket: _modules__WEBPACK_IMPORTED_MODULE_3__[\"socket\"],\n stats: _modules__WEBPACK_IMPORTED_MODULE_3__[\"stats\"],\n system: _modules__WEBPACK_IMPORTED_MODULE_3__[\"system\"]\n },\n state: {},\n mutations: {},\n getters: {},\n actions: {}\n}); // Keep as a non-arrow function for `this` context.\n\nconst passToStoreHandler = function passToStoreHandler(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 {\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 const webRoot = document.body.getAttribute('web-root');\n return \"\".concat(proto, \"//\").concat(host).concat(webRoot, \"/ws\").concat(WSMessageUrl);\n})();\n\nvue__WEBPACK_IMPORTED_MODULE_0__[\"default\"].use(vue_native_websocket__WEBPACK_IMPORTED_MODULE_2___default.a, websocketUrl, {\n store,\n format: 'json',\n reconnection: true,\n // (Boolean) whether to reconnect automatically (false)\n reconnectionAttempts: 2,\n // (Number) number of reconnection attempts before giving up (Infinity),\n reconnectionDelay: 1000,\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_4__[\"SOCKET_ONOPEN\"],\n SOCKET_ONCLOSE: _mutation_types__WEBPACK_IMPORTED_MODULE_4__[\"SOCKET_ONCLOSE\"],\n SOCKET_ONERROR: _mutation_types__WEBPACK_IMPORTED_MODULE_4__[\"SOCKET_ONERROR\"],\n SOCKET_ONMESSAGE: _mutation_types__WEBPACK_IMPORTED_MODULE_4__[\"SOCKET_ONMESSAGE\"],\n SOCKET_RECONNECT: _mutation_types__WEBPACK_IMPORTED_MODULE_4__[\"SOCKET_RECONNECT\"],\n SOCKET_RECONNECT_ERROR: _mutation_types__WEBPACK_IMPORTED_MODULE_4__[\"SOCKET_RECONNECT_ERROR\"]\n }\n});\n/* harmony default export */ __webpack_exports__[\"default\"] = (store);\n\n//# sourceURL=webpack:///./src/store/index.js?"); /***/ }), @@ -2952,11 +2952,11 @@ eval("__webpack_require__.r(__webpack_exports__);\nconst state = {\n show: {\n /*!************************************!*\ !*** ./src/store/modules/index.js ***! \************************************/ -/*! exports provided: auth, clients, config, consts, defaults, metadata, notifications, notifiers, search, shows, socket */ +/*! exports provided: auth, clients, config, consts, defaults, metadata, notifications, notifiers, search, shows, socket, stats, system */ /***/ (function(module, __webpack_exports__, __webpack_require__) { "use strict"; -eval("__webpack_require__.r(__webpack_exports__);\n/* harmony import */ var _auth__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! ./auth */ \"./src/store/modules/auth.js\");\n/* harmony reexport (safe) */ __webpack_require__.d(__webpack_exports__, \"auth\", function() { return _auth__WEBPACK_IMPORTED_MODULE_0__[\"default\"]; });\n\n/* harmony import */ var _clients__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! ./clients */ \"./src/store/modules/clients.js\");\n/* harmony reexport (safe) */ __webpack_require__.d(__webpack_exports__, \"clients\", function() { return _clients__WEBPACK_IMPORTED_MODULE_1__[\"default\"]; });\n\n/* harmony import */ var _config__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(/*! ./config */ \"./src/store/modules/config.js\");\n/* harmony reexport (safe) */ __webpack_require__.d(__webpack_exports__, \"config\", function() { return _config__WEBPACK_IMPORTED_MODULE_2__[\"default\"]; });\n\n/* harmony import */ var _consts__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(/*! ./consts */ \"./src/store/modules/consts.js\");\n/* harmony reexport (safe) */ __webpack_require__.d(__webpack_exports__, \"consts\", function() { return _consts__WEBPACK_IMPORTED_MODULE_3__[\"default\"]; });\n\n/* harmony import */ var _defaults__WEBPACK_IMPORTED_MODULE_4__ = __webpack_require__(/*! ./defaults */ \"./src/store/modules/defaults.js\");\n/* harmony reexport (safe) */ __webpack_require__.d(__webpack_exports__, \"defaults\", function() { return _defaults__WEBPACK_IMPORTED_MODULE_4__[\"default\"]; });\n\n/* harmony import */ var _metadata__WEBPACK_IMPORTED_MODULE_5__ = __webpack_require__(/*! ./metadata */ \"./src/store/modules/metadata.js\");\n/* harmony reexport (safe) */ __webpack_require__.d(__webpack_exports__, \"metadata\", function() { return _metadata__WEBPACK_IMPORTED_MODULE_5__[\"default\"]; });\n\n/* harmony import */ var _notifications__WEBPACK_IMPORTED_MODULE_6__ = __webpack_require__(/*! ./notifications */ \"./src/store/modules/notifications.js\");\n/* harmony reexport (safe) */ __webpack_require__.d(__webpack_exports__, \"notifications\", function() { return _notifications__WEBPACK_IMPORTED_MODULE_6__[\"default\"]; });\n\n/* harmony import */ var _notifiers__WEBPACK_IMPORTED_MODULE_7__ = __webpack_require__(/*! ./notifiers */ \"./src/store/modules/notifiers/index.js\");\n/* harmony reexport (safe) */ __webpack_require__.d(__webpack_exports__, \"notifiers\", function() { return _notifiers__WEBPACK_IMPORTED_MODULE_7__[\"default\"]; });\n\n/* harmony import */ var _search__WEBPACK_IMPORTED_MODULE_8__ = __webpack_require__(/*! ./search */ \"./src/store/modules/search.js\");\n/* harmony reexport (safe) */ __webpack_require__.d(__webpack_exports__, \"search\", function() { return _search__WEBPACK_IMPORTED_MODULE_8__[\"default\"]; });\n\n/* harmony import */ var _shows__WEBPACK_IMPORTED_MODULE_9__ = __webpack_require__(/*! ./shows */ \"./src/store/modules/shows.js\");\n/* harmony reexport (safe) */ __webpack_require__.d(__webpack_exports__, \"shows\", function() { return _shows__WEBPACK_IMPORTED_MODULE_9__[\"default\"]; });\n\n/* harmony import */ var _socket__WEBPACK_IMPORTED_MODULE_10__ = __webpack_require__(/*! ./socket */ \"./src/store/modules/socket.js\");\n/* harmony reexport (safe) */ __webpack_require__.d(__webpack_exports__, \"socket\", function() { return _socket__WEBPACK_IMPORTED_MODULE_10__[\"default\"]; });\n\n\n\n\n\n\n\n\n\n\n\n\n\n//# sourceURL=webpack:///./src/store/modules/index.js?"); +eval("__webpack_require__.r(__webpack_exports__);\n/* harmony import */ var _auth__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! ./auth */ \"./src/store/modules/auth.js\");\n/* harmony reexport (safe) */ __webpack_require__.d(__webpack_exports__, \"auth\", function() { return _auth__WEBPACK_IMPORTED_MODULE_0__[\"default\"]; });\n\n/* harmony import */ var _clients__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! ./clients */ \"./src/store/modules/clients.js\");\n/* harmony reexport (safe) */ __webpack_require__.d(__webpack_exports__, \"clients\", function() { return _clients__WEBPACK_IMPORTED_MODULE_1__[\"default\"]; });\n\n/* harmony import */ var _config__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(/*! ./config */ \"./src/store/modules/config.js\");\n/* harmony reexport (safe) */ __webpack_require__.d(__webpack_exports__, \"config\", function() { return _config__WEBPACK_IMPORTED_MODULE_2__[\"default\"]; });\n\n/* harmony import */ var _consts__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(/*! ./consts */ \"./src/store/modules/consts.js\");\n/* harmony reexport (safe) */ __webpack_require__.d(__webpack_exports__, \"consts\", function() { return _consts__WEBPACK_IMPORTED_MODULE_3__[\"default\"]; });\n\n/* harmony import */ var _defaults__WEBPACK_IMPORTED_MODULE_4__ = __webpack_require__(/*! ./defaults */ \"./src/store/modules/defaults.js\");\n/* harmony reexport (safe) */ __webpack_require__.d(__webpack_exports__, \"defaults\", function() { return _defaults__WEBPACK_IMPORTED_MODULE_4__[\"default\"]; });\n\n/* harmony import */ var _metadata__WEBPACK_IMPORTED_MODULE_5__ = __webpack_require__(/*! ./metadata */ \"./src/store/modules/metadata.js\");\n/* harmony reexport (safe) */ __webpack_require__.d(__webpack_exports__, \"metadata\", function() { return _metadata__WEBPACK_IMPORTED_MODULE_5__[\"default\"]; });\n\n/* harmony import */ var _notifications__WEBPACK_IMPORTED_MODULE_6__ = __webpack_require__(/*! ./notifications */ \"./src/store/modules/notifications.js\");\n/* harmony reexport (safe) */ __webpack_require__.d(__webpack_exports__, \"notifications\", function() { return _notifications__WEBPACK_IMPORTED_MODULE_6__[\"default\"]; });\n\n/* harmony import */ var _notifiers__WEBPACK_IMPORTED_MODULE_7__ = __webpack_require__(/*! ./notifiers */ \"./src/store/modules/notifiers/index.js\");\n/* harmony reexport (safe) */ __webpack_require__.d(__webpack_exports__, \"notifiers\", function() { return _notifiers__WEBPACK_IMPORTED_MODULE_7__[\"default\"]; });\n\n/* harmony import */ var _search__WEBPACK_IMPORTED_MODULE_8__ = __webpack_require__(/*! ./search */ \"./src/store/modules/search.js\");\n/* harmony reexport (safe) */ __webpack_require__.d(__webpack_exports__, \"search\", function() { return _search__WEBPACK_IMPORTED_MODULE_8__[\"default\"]; });\n\n/* harmony import */ var _shows__WEBPACK_IMPORTED_MODULE_9__ = __webpack_require__(/*! ./shows */ \"./src/store/modules/shows.js\");\n/* harmony reexport (safe) */ __webpack_require__.d(__webpack_exports__, \"shows\", function() { return _shows__WEBPACK_IMPORTED_MODULE_9__[\"default\"]; });\n\n/* harmony import */ var _socket__WEBPACK_IMPORTED_MODULE_10__ = __webpack_require__(/*! ./socket */ \"./src/store/modules/socket.js\");\n/* harmony reexport (safe) */ __webpack_require__.d(__webpack_exports__, \"socket\", function() { return _socket__WEBPACK_IMPORTED_MODULE_10__[\"default\"]; });\n\n/* harmony import */ var _stats__WEBPACK_IMPORTED_MODULE_11__ = __webpack_require__(/*! ./stats */ \"./src/store/modules/stats.js\");\n/* harmony reexport (safe) */ __webpack_require__.d(__webpack_exports__, \"stats\", function() { return _stats__WEBPACK_IMPORTED_MODULE_11__[\"default\"]; });\n\n/* harmony import */ var _system__WEBPACK_IMPORTED_MODULE_12__ = __webpack_require__(/*! ./system */ \"./src/store/modules/system.js\");\n/* harmony reexport (safe) */ __webpack_require__.d(__webpack_exports__, \"system\", function() { return _system__WEBPACK_IMPORTED_MODULE_12__[\"default\"]; });\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n//# sourceURL=webpack:///./src/store/modules/index.js?"); /***/ }), @@ -3284,15 +3284,39 @@ eval("__webpack_require__.r(__webpack_exports__);\n/* harmony import */ var _mut /***/ }), +/***/ "./src/store/modules/stats.js": +/*!************************************!*\ + !*** ./src/store/modules/stats.js ***! + \************************************/ +/*! exports provided: default */ +/***/ (function(module, __webpack_exports__, __webpack_require__) { + +"use strict"; +eval("__webpack_require__.r(__webpack_exports__);\n/* harmony import */ var _api__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! ../../api */ \"./src/api.js\");\n/* harmony import */ var _mutation_types__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! ../mutation-types */ \"./src/store/mutation-types.js\");\n\n\nconst state = {\n overall: {\n episodes: {\n downloaded: null,\n snatched: null,\n total: null\n },\n shows: {\n active: null,\n total: null\n }\n }\n};\nconst mutations = {\n [_mutation_types__WEBPACK_IMPORTED_MODULE_1__[\"ADD_STATS\"]](state, payload) {\n const {\n type,\n stats\n } = payload;\n state[type] = Object.assign(state[type], stats);\n }\n\n};\nconst getters = {};\nconst actions = {\n getStats(context, type) {\n const {\n commit\n } = context;\n return _api__WEBPACK_IMPORTED_MODULE_0__[\"api\"].get('/stats/' + (type || '')).then(res => {\n commit(_mutation_types__WEBPACK_IMPORTED_MODULE_1__[\"ADD_STATS\"], {\n type: type || 'overall',\n stats: res.data\n });\n });\n }\n\n};\n/* harmony default export */ __webpack_exports__[\"default\"] = ({\n state,\n mutations,\n getters,\n actions\n});\n\n//# sourceURL=webpack:///./src/store/modules/stats.js?"); + +/***/ }), + +/***/ "./src/store/modules/system.js": +/*!*************************************!*\ + !*** ./src/store/modules/system.js ***! + \*************************************/ +/*! exports provided: default */ +/***/ (function(module, __webpack_exports__, __webpack_require__) { + +"use strict"; +eval("__webpack_require__.r(__webpack_exports__);\n/* harmony import */ var _mutation_types__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! ../mutation-types */ \"./src/store/mutation-types.js\");\n\nconst state = {\n memoryUsage: null,\n schedulers: [],\n showQueue: []\n};\nconst mutations = {\n [_mutation_types__WEBPACK_IMPORTED_MODULE_0__[\"ADD_CONFIG\"]](state, {\n section,\n config\n }) {\n if (section === 'system') {\n state = Object.assign(state, config);\n }\n }\n\n};\nconst getters = {\n // Get a scheduler object using a key\n getScheduler: state => key => {\n return state.schedulers.find(scheduler => key === scheduler.key);\n }\n};\nconst actions = {};\n/* harmony default export */ __webpack_exports__[\"default\"] = ({\n state,\n mutations,\n getters,\n actions\n});\n\n//# sourceURL=webpack:///./src/store/modules/system.js?"); + +/***/ }), + /***/ "./src/store/mutation-types.js": /*!*************************************!*\ !*** ./src/store/mutation-types.js ***! \*************************************/ -/*! exports provided: LOGIN_PENDING, LOGIN_SUCCESS, LOGIN_FAILED, LOGOUT, REFRESH_TOKEN, REMOVE_AUTH_ERROR, SOCKET_ONOPEN, SOCKET_ONCLOSE, SOCKET_ONERROR, SOCKET_ONMESSAGE, SOCKET_RECONNECT, SOCKET_RECONNECT_ERROR, NOTIFICATIONS_ENABLED, NOTIFICATIONS_DISABLED, ADD_CONFIG, ADD_SHOW */ +/*! exports provided: LOGIN_PENDING, LOGIN_SUCCESS, LOGIN_FAILED, LOGOUT, REFRESH_TOKEN, REMOVE_AUTH_ERROR, SOCKET_ONOPEN, SOCKET_ONCLOSE, SOCKET_ONERROR, SOCKET_ONMESSAGE, SOCKET_RECONNECT, SOCKET_RECONNECT_ERROR, NOTIFICATIONS_ENABLED, NOTIFICATIONS_DISABLED, ADD_CONFIG, ADD_SHOW, ADD_STATS */ /***/ (function(module, __webpack_exports__, __webpack_require__) { "use strict"; -eval("__webpack_require__.r(__webpack_exports__);\n/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, \"LOGIN_PENDING\", function() { return LOGIN_PENDING; });\n/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, \"LOGIN_SUCCESS\", function() { return LOGIN_SUCCESS; });\n/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, \"LOGIN_FAILED\", function() { return LOGIN_FAILED; });\n/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, \"LOGOUT\", function() { return LOGOUT; });\n/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, \"REFRESH_TOKEN\", function() { return REFRESH_TOKEN; });\n/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, \"REMOVE_AUTH_ERROR\", function() { return REMOVE_AUTH_ERROR; });\n/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, \"SOCKET_ONOPEN\", function() { return SOCKET_ONOPEN; });\n/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, \"SOCKET_ONCLOSE\", function() { return SOCKET_ONCLOSE; });\n/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, \"SOCKET_ONERROR\", function() { return SOCKET_ONERROR; });\n/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, \"SOCKET_ONMESSAGE\", function() { return SOCKET_ONMESSAGE; });\n/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, \"SOCKET_RECONNECT\", function() { return SOCKET_RECONNECT; });\n/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, \"SOCKET_RECONNECT_ERROR\", function() { return SOCKET_RECONNECT_ERROR; });\n/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, \"NOTIFICATIONS_ENABLED\", function() { return NOTIFICATIONS_ENABLED; });\n/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, \"NOTIFICATIONS_DISABLED\", function() { return NOTIFICATIONS_DISABLED; });\n/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, \"ADD_CONFIG\", function() { return ADD_CONFIG; });\n/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, \"ADD_SHOW\", function() { return ADD_SHOW; });\nconst LOGIN_PENDING = '🔒 Logging in';\nconst LOGIN_SUCCESS = '🔒 ✅ Login Successful';\nconst LOGIN_FAILED = '🔒 ❌ Login Failed';\nconst LOGOUT = '🔒 Logout';\nconst REFRESH_TOKEN = '🔒 Refresh Token';\nconst REMOVE_AUTH_ERROR = '🔒 Remove Auth Error';\nconst SOCKET_ONOPEN = '🔗 ✅ WebSocket connected';\nconst SOCKET_ONCLOSE = '🔗 ❌ WebSocket disconnected';\nconst SOCKET_ONERROR = '🔗 ❌ WebSocket error';\nconst SOCKET_ONMESSAGE = '🔗 ✉ī¸ đŸ“Ĩ WebSocket message received';\nconst SOCKET_RECONNECT = '🔗 🔃 WebSocket reconnecting';\nconst SOCKET_RECONNECT_ERROR = '🔗 🔃 ❌ WebSocket reconnection attempt failed';\nconst NOTIFICATIONS_ENABLED = '🔔 Notifications Enabled';\nconst NOTIFICATIONS_DISABLED = '🔔 Notifications Disabled';\nconst ADD_CONFIG = '⚙ī¸ Config added to store';\nconst ADD_SHOW = 'đŸ“ē Show added to store';\n\n\n//# sourceURL=webpack:///./src/store/mutation-types.js?"); +eval("__webpack_require__.r(__webpack_exports__);\n/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, \"LOGIN_PENDING\", function() { return LOGIN_PENDING; });\n/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, \"LOGIN_SUCCESS\", function() { return LOGIN_SUCCESS; });\n/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, \"LOGIN_FAILED\", function() { return LOGIN_FAILED; });\n/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, \"LOGOUT\", function() { return LOGOUT; });\n/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, \"REFRESH_TOKEN\", function() { return REFRESH_TOKEN; });\n/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, \"REMOVE_AUTH_ERROR\", function() { return REMOVE_AUTH_ERROR; });\n/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, \"SOCKET_ONOPEN\", function() { return SOCKET_ONOPEN; });\n/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, \"SOCKET_ONCLOSE\", function() { return SOCKET_ONCLOSE; });\n/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, \"SOCKET_ONERROR\", function() { return SOCKET_ONERROR; });\n/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, \"SOCKET_ONMESSAGE\", function() { return SOCKET_ONMESSAGE; });\n/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, \"SOCKET_RECONNECT\", function() { return SOCKET_RECONNECT; });\n/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, \"SOCKET_RECONNECT_ERROR\", function() { return SOCKET_RECONNECT_ERROR; });\n/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, \"NOTIFICATIONS_ENABLED\", function() { return NOTIFICATIONS_ENABLED; });\n/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, \"NOTIFICATIONS_DISABLED\", function() { return NOTIFICATIONS_DISABLED; });\n/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, \"ADD_CONFIG\", function() { return ADD_CONFIG; });\n/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, \"ADD_SHOW\", function() { return ADD_SHOW; });\n/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, \"ADD_STATS\", function() { return ADD_STATS; });\nconst LOGIN_PENDING = '🔒 Logging in';\nconst LOGIN_SUCCESS = '🔒 ✅ Login Successful';\nconst LOGIN_FAILED = '🔒 ❌ Login Failed';\nconst LOGOUT = '🔒 Logout';\nconst REFRESH_TOKEN = '🔒 Refresh Token';\nconst REMOVE_AUTH_ERROR = '🔒 Remove Auth Error';\nconst SOCKET_ONOPEN = '🔗 ✅ WebSocket connected';\nconst SOCKET_ONCLOSE = '🔗 ❌ WebSocket disconnected';\nconst SOCKET_ONERROR = '🔗 ❌ WebSocket error';\nconst SOCKET_ONMESSAGE = '🔗 ✉ī¸ đŸ“Ĩ WebSocket message received';\nconst SOCKET_RECONNECT = '🔗 🔃 WebSocket reconnecting';\nconst SOCKET_RECONNECT_ERROR = '🔗 🔃 ❌ WebSocket reconnection attempt failed';\nconst NOTIFICATIONS_ENABLED = '🔔 Notifications Enabled';\nconst NOTIFICATIONS_DISABLED = '🔔 Notifications Disabled';\nconst ADD_CONFIG = '⚙ī¸ Config added to store';\nconst ADD_SHOW = 'đŸ“ē Show added to store';\nconst ADD_STATS = 'ℹī¸ Statistics added to store';\n\n\n//# sourceURL=webpack:///./src/store/mutation-types.js?"); /***/ }), diff --git a/themes/light/assets/js/medusa-runtime.js b/themes/light/assets/js/medusa-runtime.js index 9ad0c0614b8..6952896a900 100644 --- a/themes/light/assets/js/medusa-runtime.js +++ b/themes/light/assets/js/medusa-runtime.js @@ -2884,7 +2884,7 @@ eval("__webpack_require__.r(__webpack_exports__);\n/* harmony import */ var vue_ /***/ (function(module, __webpack_exports__, __webpack_require__) { "use strict"; -eval("__webpack_require__.r(__webpack_exports__);\n/* harmony import */ var vue__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! vue */ \"./node_modules/vue/dist/vue.esm.js\");\n/* harmony import */ var vuex__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! vuex */ \"./node_modules/vuex/dist/vuex.esm.js\");\n/* harmony import */ var vue_native_websocket__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(/*! vue-native-websocket */ \"./node_modules/vue-native-websocket/dist/build.js\");\n/* harmony import */ var vue_native_websocket__WEBPACK_IMPORTED_MODULE_2___default = /*#__PURE__*/__webpack_require__.n(vue_native_websocket__WEBPACK_IMPORTED_MODULE_2__);\n/* harmony import */ var _modules__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(/*! ./modules */ \"./src/store/modules/index.js\");\n/* harmony import */ var _mutation_types__WEBPACK_IMPORTED_MODULE_4__ = __webpack_require__(/*! ./mutation-types */ \"./src/store/mutation-types.js\");\n\n\n\n\n\nvue__WEBPACK_IMPORTED_MODULE_0__[\"default\"].use(vuex__WEBPACK_IMPORTED_MODULE_1__[\"default\"]);\nconst store = new vuex__WEBPACK_IMPORTED_MODULE_1__[\"Store\"]({\n modules: {\n auth: _modules__WEBPACK_IMPORTED_MODULE_3__[\"auth\"],\n clients: _modules__WEBPACK_IMPORTED_MODULE_3__[\"clients\"],\n config: _modules__WEBPACK_IMPORTED_MODULE_3__[\"config\"],\n consts: _modules__WEBPACK_IMPORTED_MODULE_3__[\"consts\"],\n defaults: _modules__WEBPACK_IMPORTED_MODULE_3__[\"defaults\"],\n metadata: _modules__WEBPACK_IMPORTED_MODULE_3__[\"metadata\"],\n notifications: _modules__WEBPACK_IMPORTED_MODULE_3__[\"notifications\"],\n notifiers: _modules__WEBPACK_IMPORTED_MODULE_3__[\"notifiers\"],\n search: _modules__WEBPACK_IMPORTED_MODULE_3__[\"search\"],\n shows: _modules__WEBPACK_IMPORTED_MODULE_3__[\"shows\"],\n socket: _modules__WEBPACK_IMPORTED_MODULE_3__[\"socket\"]\n },\n state: {},\n mutations: {},\n getters: {},\n actions: {}\n}); // Keep as a non-arrow function for `this` context.\n\nconst passToStoreHandler = function passToStoreHandler(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 {\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 const webRoot = document.body.getAttribute('web-root');\n return \"\".concat(proto, \"//\").concat(host).concat(webRoot, \"/ws\").concat(WSMessageUrl);\n})();\n\nvue__WEBPACK_IMPORTED_MODULE_0__[\"default\"].use(vue_native_websocket__WEBPACK_IMPORTED_MODULE_2___default.a, websocketUrl, {\n store,\n format: 'json',\n reconnection: true,\n // (Boolean) whether to reconnect automatically (false)\n reconnectionAttempts: 2,\n // (Number) number of reconnection attempts before giving up (Infinity),\n reconnectionDelay: 1000,\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_4__[\"SOCKET_ONOPEN\"],\n SOCKET_ONCLOSE: _mutation_types__WEBPACK_IMPORTED_MODULE_4__[\"SOCKET_ONCLOSE\"],\n SOCKET_ONERROR: _mutation_types__WEBPACK_IMPORTED_MODULE_4__[\"SOCKET_ONERROR\"],\n SOCKET_ONMESSAGE: _mutation_types__WEBPACK_IMPORTED_MODULE_4__[\"SOCKET_ONMESSAGE\"],\n SOCKET_RECONNECT: _mutation_types__WEBPACK_IMPORTED_MODULE_4__[\"SOCKET_RECONNECT\"],\n SOCKET_RECONNECT_ERROR: _mutation_types__WEBPACK_IMPORTED_MODULE_4__[\"SOCKET_RECONNECT_ERROR\"]\n }\n});\n/* harmony default export */ __webpack_exports__[\"default\"] = (store);\n\n//# sourceURL=webpack:///./src/store/index.js?"); +eval("__webpack_require__.r(__webpack_exports__);\n/* harmony import */ var vue__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! vue */ \"./node_modules/vue/dist/vue.esm.js\");\n/* harmony import */ var vuex__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! vuex */ \"./node_modules/vuex/dist/vuex.esm.js\");\n/* harmony import */ var vue_native_websocket__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(/*! vue-native-websocket */ \"./node_modules/vue-native-websocket/dist/build.js\");\n/* harmony import */ var vue_native_websocket__WEBPACK_IMPORTED_MODULE_2___default = /*#__PURE__*/__webpack_require__.n(vue_native_websocket__WEBPACK_IMPORTED_MODULE_2__);\n/* harmony import */ var _modules__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(/*! ./modules */ \"./src/store/modules/index.js\");\n/* harmony import */ var _mutation_types__WEBPACK_IMPORTED_MODULE_4__ = __webpack_require__(/*! ./mutation-types */ \"./src/store/mutation-types.js\");\n\n\n\n\n\nvue__WEBPACK_IMPORTED_MODULE_0__[\"default\"].use(vuex__WEBPACK_IMPORTED_MODULE_1__[\"default\"]);\nconst store = new vuex__WEBPACK_IMPORTED_MODULE_1__[\"Store\"]({\n modules: {\n auth: _modules__WEBPACK_IMPORTED_MODULE_3__[\"auth\"],\n clients: _modules__WEBPACK_IMPORTED_MODULE_3__[\"clients\"],\n config: _modules__WEBPACK_IMPORTED_MODULE_3__[\"config\"],\n consts: _modules__WEBPACK_IMPORTED_MODULE_3__[\"consts\"],\n defaults: _modules__WEBPACK_IMPORTED_MODULE_3__[\"defaults\"],\n metadata: _modules__WEBPACK_IMPORTED_MODULE_3__[\"metadata\"],\n notifications: _modules__WEBPACK_IMPORTED_MODULE_3__[\"notifications\"],\n notifiers: _modules__WEBPACK_IMPORTED_MODULE_3__[\"notifiers\"],\n search: _modules__WEBPACK_IMPORTED_MODULE_3__[\"search\"],\n shows: _modules__WEBPACK_IMPORTED_MODULE_3__[\"shows\"],\n socket: _modules__WEBPACK_IMPORTED_MODULE_3__[\"socket\"],\n stats: _modules__WEBPACK_IMPORTED_MODULE_3__[\"stats\"],\n system: _modules__WEBPACK_IMPORTED_MODULE_3__[\"system\"]\n },\n state: {},\n mutations: {},\n getters: {},\n actions: {}\n}); // Keep as a non-arrow function for `this` context.\n\nconst passToStoreHandler = function passToStoreHandler(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 {\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 const webRoot = document.body.getAttribute('web-root');\n return \"\".concat(proto, \"//\").concat(host).concat(webRoot, \"/ws\").concat(WSMessageUrl);\n})();\n\nvue__WEBPACK_IMPORTED_MODULE_0__[\"default\"].use(vue_native_websocket__WEBPACK_IMPORTED_MODULE_2___default.a, websocketUrl, {\n store,\n format: 'json',\n reconnection: true,\n // (Boolean) whether to reconnect automatically (false)\n reconnectionAttempts: 2,\n // (Number) number of reconnection attempts before giving up (Infinity),\n reconnectionDelay: 1000,\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_4__[\"SOCKET_ONOPEN\"],\n SOCKET_ONCLOSE: _mutation_types__WEBPACK_IMPORTED_MODULE_4__[\"SOCKET_ONCLOSE\"],\n SOCKET_ONERROR: _mutation_types__WEBPACK_IMPORTED_MODULE_4__[\"SOCKET_ONERROR\"],\n SOCKET_ONMESSAGE: _mutation_types__WEBPACK_IMPORTED_MODULE_4__[\"SOCKET_ONMESSAGE\"],\n SOCKET_RECONNECT: _mutation_types__WEBPACK_IMPORTED_MODULE_4__[\"SOCKET_RECONNECT\"],\n SOCKET_RECONNECT_ERROR: _mutation_types__WEBPACK_IMPORTED_MODULE_4__[\"SOCKET_RECONNECT_ERROR\"]\n }\n});\n/* harmony default export */ __webpack_exports__[\"default\"] = (store);\n\n//# sourceURL=webpack:///./src/store/index.js?"); /***/ }), @@ -2952,11 +2952,11 @@ eval("__webpack_require__.r(__webpack_exports__);\nconst state = {\n show: {\n /*!************************************!*\ !*** ./src/store/modules/index.js ***! \************************************/ -/*! exports provided: auth, clients, config, consts, defaults, metadata, notifications, notifiers, search, shows, socket */ +/*! exports provided: auth, clients, config, consts, defaults, metadata, notifications, notifiers, search, shows, socket, stats, system */ /***/ (function(module, __webpack_exports__, __webpack_require__) { "use strict"; -eval("__webpack_require__.r(__webpack_exports__);\n/* harmony import */ var _auth__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! ./auth */ \"./src/store/modules/auth.js\");\n/* harmony reexport (safe) */ __webpack_require__.d(__webpack_exports__, \"auth\", function() { return _auth__WEBPACK_IMPORTED_MODULE_0__[\"default\"]; });\n\n/* harmony import */ var _clients__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! ./clients */ \"./src/store/modules/clients.js\");\n/* harmony reexport (safe) */ __webpack_require__.d(__webpack_exports__, \"clients\", function() { return _clients__WEBPACK_IMPORTED_MODULE_1__[\"default\"]; });\n\n/* harmony import */ var _config__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(/*! ./config */ \"./src/store/modules/config.js\");\n/* harmony reexport (safe) */ __webpack_require__.d(__webpack_exports__, \"config\", function() { return _config__WEBPACK_IMPORTED_MODULE_2__[\"default\"]; });\n\n/* harmony import */ var _consts__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(/*! ./consts */ \"./src/store/modules/consts.js\");\n/* harmony reexport (safe) */ __webpack_require__.d(__webpack_exports__, \"consts\", function() { return _consts__WEBPACK_IMPORTED_MODULE_3__[\"default\"]; });\n\n/* harmony import */ var _defaults__WEBPACK_IMPORTED_MODULE_4__ = __webpack_require__(/*! ./defaults */ \"./src/store/modules/defaults.js\");\n/* harmony reexport (safe) */ __webpack_require__.d(__webpack_exports__, \"defaults\", function() { return _defaults__WEBPACK_IMPORTED_MODULE_4__[\"default\"]; });\n\n/* harmony import */ var _metadata__WEBPACK_IMPORTED_MODULE_5__ = __webpack_require__(/*! ./metadata */ \"./src/store/modules/metadata.js\");\n/* harmony reexport (safe) */ __webpack_require__.d(__webpack_exports__, \"metadata\", function() { return _metadata__WEBPACK_IMPORTED_MODULE_5__[\"default\"]; });\n\n/* harmony import */ var _notifications__WEBPACK_IMPORTED_MODULE_6__ = __webpack_require__(/*! ./notifications */ \"./src/store/modules/notifications.js\");\n/* harmony reexport (safe) */ __webpack_require__.d(__webpack_exports__, \"notifications\", function() { return _notifications__WEBPACK_IMPORTED_MODULE_6__[\"default\"]; });\n\n/* harmony import */ var _notifiers__WEBPACK_IMPORTED_MODULE_7__ = __webpack_require__(/*! ./notifiers */ \"./src/store/modules/notifiers/index.js\");\n/* harmony reexport (safe) */ __webpack_require__.d(__webpack_exports__, \"notifiers\", function() { return _notifiers__WEBPACK_IMPORTED_MODULE_7__[\"default\"]; });\n\n/* harmony import */ var _search__WEBPACK_IMPORTED_MODULE_8__ = __webpack_require__(/*! ./search */ \"./src/store/modules/search.js\");\n/* harmony reexport (safe) */ __webpack_require__.d(__webpack_exports__, \"search\", function() { return _search__WEBPACK_IMPORTED_MODULE_8__[\"default\"]; });\n\n/* harmony import */ var _shows__WEBPACK_IMPORTED_MODULE_9__ = __webpack_require__(/*! ./shows */ \"./src/store/modules/shows.js\");\n/* harmony reexport (safe) */ __webpack_require__.d(__webpack_exports__, \"shows\", function() { return _shows__WEBPACK_IMPORTED_MODULE_9__[\"default\"]; });\n\n/* harmony import */ var _socket__WEBPACK_IMPORTED_MODULE_10__ = __webpack_require__(/*! ./socket */ \"./src/store/modules/socket.js\");\n/* harmony reexport (safe) */ __webpack_require__.d(__webpack_exports__, \"socket\", function() { return _socket__WEBPACK_IMPORTED_MODULE_10__[\"default\"]; });\n\n\n\n\n\n\n\n\n\n\n\n\n\n//# sourceURL=webpack:///./src/store/modules/index.js?"); +eval("__webpack_require__.r(__webpack_exports__);\n/* harmony import */ var _auth__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! ./auth */ \"./src/store/modules/auth.js\");\n/* harmony reexport (safe) */ __webpack_require__.d(__webpack_exports__, \"auth\", function() { return _auth__WEBPACK_IMPORTED_MODULE_0__[\"default\"]; });\n\n/* harmony import */ var _clients__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! ./clients */ \"./src/store/modules/clients.js\");\n/* harmony reexport (safe) */ __webpack_require__.d(__webpack_exports__, \"clients\", function() { return _clients__WEBPACK_IMPORTED_MODULE_1__[\"default\"]; });\n\n/* harmony import */ var _config__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(/*! ./config */ \"./src/store/modules/config.js\");\n/* harmony reexport (safe) */ __webpack_require__.d(__webpack_exports__, \"config\", function() { return _config__WEBPACK_IMPORTED_MODULE_2__[\"default\"]; });\n\n/* harmony import */ var _consts__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(/*! ./consts */ \"./src/store/modules/consts.js\");\n/* harmony reexport (safe) */ __webpack_require__.d(__webpack_exports__, \"consts\", function() { return _consts__WEBPACK_IMPORTED_MODULE_3__[\"default\"]; });\n\n/* harmony import */ var _defaults__WEBPACK_IMPORTED_MODULE_4__ = __webpack_require__(/*! ./defaults */ \"./src/store/modules/defaults.js\");\n/* harmony reexport (safe) */ __webpack_require__.d(__webpack_exports__, \"defaults\", function() { return _defaults__WEBPACK_IMPORTED_MODULE_4__[\"default\"]; });\n\n/* harmony import */ var _metadata__WEBPACK_IMPORTED_MODULE_5__ = __webpack_require__(/*! ./metadata */ \"./src/store/modules/metadata.js\");\n/* harmony reexport (safe) */ __webpack_require__.d(__webpack_exports__, \"metadata\", function() { return _metadata__WEBPACK_IMPORTED_MODULE_5__[\"default\"]; });\n\n/* harmony import */ var _notifications__WEBPACK_IMPORTED_MODULE_6__ = __webpack_require__(/*! ./notifications */ \"./src/store/modules/notifications.js\");\n/* harmony reexport (safe) */ __webpack_require__.d(__webpack_exports__, \"notifications\", function() { return _notifications__WEBPACK_IMPORTED_MODULE_6__[\"default\"]; });\n\n/* harmony import */ var _notifiers__WEBPACK_IMPORTED_MODULE_7__ = __webpack_require__(/*! ./notifiers */ \"./src/store/modules/notifiers/index.js\");\n/* harmony reexport (safe) */ __webpack_require__.d(__webpack_exports__, \"notifiers\", function() { return _notifiers__WEBPACK_IMPORTED_MODULE_7__[\"default\"]; });\n\n/* harmony import */ var _search__WEBPACK_IMPORTED_MODULE_8__ = __webpack_require__(/*! ./search */ \"./src/store/modules/search.js\");\n/* harmony reexport (safe) */ __webpack_require__.d(__webpack_exports__, \"search\", function() { return _search__WEBPACK_IMPORTED_MODULE_8__[\"default\"]; });\n\n/* harmony import */ var _shows__WEBPACK_IMPORTED_MODULE_9__ = __webpack_require__(/*! ./shows */ \"./src/store/modules/shows.js\");\n/* harmony reexport (safe) */ __webpack_require__.d(__webpack_exports__, \"shows\", function() { return _shows__WEBPACK_IMPORTED_MODULE_9__[\"default\"]; });\n\n/* harmony import */ var _socket__WEBPACK_IMPORTED_MODULE_10__ = __webpack_require__(/*! ./socket */ \"./src/store/modules/socket.js\");\n/* harmony reexport (safe) */ __webpack_require__.d(__webpack_exports__, \"socket\", function() { return _socket__WEBPACK_IMPORTED_MODULE_10__[\"default\"]; });\n\n/* harmony import */ var _stats__WEBPACK_IMPORTED_MODULE_11__ = __webpack_require__(/*! ./stats */ \"./src/store/modules/stats.js\");\n/* harmony reexport (safe) */ __webpack_require__.d(__webpack_exports__, \"stats\", function() { return _stats__WEBPACK_IMPORTED_MODULE_11__[\"default\"]; });\n\n/* harmony import */ var _system__WEBPACK_IMPORTED_MODULE_12__ = __webpack_require__(/*! ./system */ \"./src/store/modules/system.js\");\n/* harmony reexport (safe) */ __webpack_require__.d(__webpack_exports__, \"system\", function() { return _system__WEBPACK_IMPORTED_MODULE_12__[\"default\"]; });\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n//# sourceURL=webpack:///./src/store/modules/index.js?"); /***/ }), @@ -3284,15 +3284,39 @@ eval("__webpack_require__.r(__webpack_exports__);\n/* harmony import */ var _mut /***/ }), +/***/ "./src/store/modules/stats.js": +/*!************************************!*\ + !*** ./src/store/modules/stats.js ***! + \************************************/ +/*! exports provided: default */ +/***/ (function(module, __webpack_exports__, __webpack_require__) { + +"use strict"; +eval("__webpack_require__.r(__webpack_exports__);\n/* harmony import */ var _api__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! ../../api */ \"./src/api.js\");\n/* harmony import */ var _mutation_types__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! ../mutation-types */ \"./src/store/mutation-types.js\");\n\n\nconst state = {\n overall: {\n episodes: {\n downloaded: null,\n snatched: null,\n total: null\n },\n shows: {\n active: null,\n total: null\n }\n }\n};\nconst mutations = {\n [_mutation_types__WEBPACK_IMPORTED_MODULE_1__[\"ADD_STATS\"]](state, payload) {\n const {\n type,\n stats\n } = payload;\n state[type] = Object.assign(state[type], stats);\n }\n\n};\nconst getters = {};\nconst actions = {\n getStats(context, type) {\n const {\n commit\n } = context;\n return _api__WEBPACK_IMPORTED_MODULE_0__[\"api\"].get('/stats/' + (type || '')).then(res => {\n commit(_mutation_types__WEBPACK_IMPORTED_MODULE_1__[\"ADD_STATS\"], {\n type: type || 'overall',\n stats: res.data\n });\n });\n }\n\n};\n/* harmony default export */ __webpack_exports__[\"default\"] = ({\n state,\n mutations,\n getters,\n actions\n});\n\n//# sourceURL=webpack:///./src/store/modules/stats.js?"); + +/***/ }), + +/***/ "./src/store/modules/system.js": +/*!*************************************!*\ + !*** ./src/store/modules/system.js ***! + \*************************************/ +/*! exports provided: default */ +/***/ (function(module, __webpack_exports__, __webpack_require__) { + +"use strict"; +eval("__webpack_require__.r(__webpack_exports__);\n/* harmony import */ var _mutation_types__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! ../mutation-types */ \"./src/store/mutation-types.js\");\n\nconst state = {\n memoryUsage: null,\n schedulers: [],\n showQueue: []\n};\nconst mutations = {\n [_mutation_types__WEBPACK_IMPORTED_MODULE_0__[\"ADD_CONFIG\"]](state, {\n section,\n config\n }) {\n if (section === 'system') {\n state = Object.assign(state, config);\n }\n }\n\n};\nconst getters = {\n // Get a scheduler object using a key\n getScheduler: state => key => {\n return state.schedulers.find(scheduler => key === scheduler.key);\n }\n};\nconst actions = {};\n/* harmony default export */ __webpack_exports__[\"default\"] = ({\n state,\n mutations,\n getters,\n actions\n});\n\n//# sourceURL=webpack:///./src/store/modules/system.js?"); + +/***/ }), + /***/ "./src/store/mutation-types.js": /*!*************************************!*\ !*** ./src/store/mutation-types.js ***! \*************************************/ -/*! exports provided: LOGIN_PENDING, LOGIN_SUCCESS, LOGIN_FAILED, LOGOUT, REFRESH_TOKEN, REMOVE_AUTH_ERROR, SOCKET_ONOPEN, SOCKET_ONCLOSE, SOCKET_ONERROR, SOCKET_ONMESSAGE, SOCKET_RECONNECT, SOCKET_RECONNECT_ERROR, NOTIFICATIONS_ENABLED, NOTIFICATIONS_DISABLED, ADD_CONFIG, ADD_SHOW */ +/*! exports provided: LOGIN_PENDING, LOGIN_SUCCESS, LOGIN_FAILED, LOGOUT, REFRESH_TOKEN, REMOVE_AUTH_ERROR, SOCKET_ONOPEN, SOCKET_ONCLOSE, SOCKET_ONERROR, SOCKET_ONMESSAGE, SOCKET_RECONNECT, SOCKET_RECONNECT_ERROR, NOTIFICATIONS_ENABLED, NOTIFICATIONS_DISABLED, ADD_CONFIG, ADD_SHOW, ADD_STATS */ /***/ (function(module, __webpack_exports__, __webpack_require__) { "use strict"; -eval("__webpack_require__.r(__webpack_exports__);\n/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, \"LOGIN_PENDING\", function() { return LOGIN_PENDING; });\n/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, \"LOGIN_SUCCESS\", function() { return LOGIN_SUCCESS; });\n/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, \"LOGIN_FAILED\", function() { return LOGIN_FAILED; });\n/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, \"LOGOUT\", function() { return LOGOUT; });\n/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, \"REFRESH_TOKEN\", function() { return REFRESH_TOKEN; });\n/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, \"REMOVE_AUTH_ERROR\", function() { return REMOVE_AUTH_ERROR; });\n/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, \"SOCKET_ONOPEN\", function() { return SOCKET_ONOPEN; });\n/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, \"SOCKET_ONCLOSE\", function() { return SOCKET_ONCLOSE; });\n/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, \"SOCKET_ONERROR\", function() { return SOCKET_ONERROR; });\n/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, \"SOCKET_ONMESSAGE\", function() { return SOCKET_ONMESSAGE; });\n/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, \"SOCKET_RECONNECT\", function() { return SOCKET_RECONNECT; });\n/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, \"SOCKET_RECONNECT_ERROR\", function() { return SOCKET_RECONNECT_ERROR; });\n/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, \"NOTIFICATIONS_ENABLED\", function() { return NOTIFICATIONS_ENABLED; });\n/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, \"NOTIFICATIONS_DISABLED\", function() { return NOTIFICATIONS_DISABLED; });\n/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, \"ADD_CONFIG\", function() { return ADD_CONFIG; });\n/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, \"ADD_SHOW\", function() { return ADD_SHOW; });\nconst LOGIN_PENDING = '🔒 Logging in';\nconst LOGIN_SUCCESS = '🔒 ✅ Login Successful';\nconst LOGIN_FAILED = '🔒 ❌ Login Failed';\nconst LOGOUT = '🔒 Logout';\nconst REFRESH_TOKEN = '🔒 Refresh Token';\nconst REMOVE_AUTH_ERROR = '🔒 Remove Auth Error';\nconst SOCKET_ONOPEN = '🔗 ✅ WebSocket connected';\nconst SOCKET_ONCLOSE = '🔗 ❌ WebSocket disconnected';\nconst SOCKET_ONERROR = '🔗 ❌ WebSocket error';\nconst SOCKET_ONMESSAGE = '🔗 ✉ī¸ đŸ“Ĩ WebSocket message received';\nconst SOCKET_RECONNECT = '🔗 🔃 WebSocket reconnecting';\nconst SOCKET_RECONNECT_ERROR = '🔗 🔃 ❌ WebSocket reconnection attempt failed';\nconst NOTIFICATIONS_ENABLED = '🔔 Notifications Enabled';\nconst NOTIFICATIONS_DISABLED = '🔔 Notifications Disabled';\nconst ADD_CONFIG = '⚙ī¸ Config added to store';\nconst ADD_SHOW = 'đŸ“ē Show added to store';\n\n\n//# sourceURL=webpack:///./src/store/mutation-types.js?"); +eval("__webpack_require__.r(__webpack_exports__);\n/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, \"LOGIN_PENDING\", function() { return LOGIN_PENDING; });\n/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, \"LOGIN_SUCCESS\", function() { return LOGIN_SUCCESS; });\n/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, \"LOGIN_FAILED\", function() { return LOGIN_FAILED; });\n/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, \"LOGOUT\", function() { return LOGOUT; });\n/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, \"REFRESH_TOKEN\", function() { return REFRESH_TOKEN; });\n/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, \"REMOVE_AUTH_ERROR\", function() { return REMOVE_AUTH_ERROR; });\n/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, \"SOCKET_ONOPEN\", function() { return SOCKET_ONOPEN; });\n/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, \"SOCKET_ONCLOSE\", function() { return SOCKET_ONCLOSE; });\n/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, \"SOCKET_ONERROR\", function() { return SOCKET_ONERROR; });\n/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, \"SOCKET_ONMESSAGE\", function() { return SOCKET_ONMESSAGE; });\n/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, \"SOCKET_RECONNECT\", function() { return SOCKET_RECONNECT; });\n/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, \"SOCKET_RECONNECT_ERROR\", function() { return SOCKET_RECONNECT_ERROR; });\n/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, \"NOTIFICATIONS_ENABLED\", function() { return NOTIFICATIONS_ENABLED; });\n/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, \"NOTIFICATIONS_DISABLED\", function() { return NOTIFICATIONS_DISABLED; });\n/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, \"ADD_CONFIG\", function() { return ADD_CONFIG; });\n/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, \"ADD_SHOW\", function() { return ADD_SHOW; });\n/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, \"ADD_STATS\", function() { return ADD_STATS; });\nconst LOGIN_PENDING = '🔒 Logging in';\nconst LOGIN_SUCCESS = '🔒 ✅ Login Successful';\nconst LOGIN_FAILED = '🔒 ❌ Login Failed';\nconst LOGOUT = '🔒 Logout';\nconst REFRESH_TOKEN = '🔒 Refresh Token';\nconst REMOVE_AUTH_ERROR = '🔒 Remove Auth Error';\nconst SOCKET_ONOPEN = '🔗 ✅ WebSocket connected';\nconst SOCKET_ONCLOSE = '🔗 ❌ WebSocket disconnected';\nconst SOCKET_ONERROR = '🔗 ❌ WebSocket error';\nconst SOCKET_ONMESSAGE = '🔗 ✉ī¸ đŸ“Ĩ WebSocket message received';\nconst SOCKET_RECONNECT = '🔗 🔃 WebSocket reconnecting';\nconst SOCKET_RECONNECT_ERROR = '🔗 🔃 ❌ WebSocket reconnection attempt failed';\nconst NOTIFICATIONS_ENABLED = '🔔 Notifications Enabled';\nconst NOTIFICATIONS_DISABLED = '🔔 Notifications Disabled';\nconst ADD_CONFIG = '⚙ī¸ Config added to store';\nconst ADD_SHOW = 'đŸ“ē Show added to store';\nconst ADD_STATS = 'ℹī¸ Statistics added to store';\n\n\n//# sourceURL=webpack:///./src/store/mutation-types.js?"); /***/ }),